Arcane  v3.16.0.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
ArcaneBasicVerifierService.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2024 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* ArcaneBasicVerifierService.cc (C) 2000-2024 */
9/* */
10/* Service de comparaison des variables. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/ITraceMng.h"
15#include "arcane/utils/FatalErrorException.h"
16#include "arcane/utils/PlatformUtils.h"
17#include "arcane/utils/StringBuilder.h"
18#include "arcane/utils/ValueConvert.h"
19
20#include "arcane/core/IParallelMng.h"
21#include "arcane/core/VariableCollection.h"
22#include "arcane/core/IVariableUtilities.h"
23#include "arcane/core/VerifierService.h"
24#include "arcane/core/ItemGroup.h"
25#include "arcane/core/IVariableMng.h"
26#include "arcane/core/IVariable.h"
27#include "arcane/core/ISubDomain.h"
29#include "arcane/core/IData.h"
30#include "arcane/core/internal/IVariableInternal.h"
31
32#include "arcane/std/internal/BasicReader.h"
33#include "arcane/std/internal/BasicWriter.h"
34
35/*---------------------------------------------------------------------------*/
36/*---------------------------------------------------------------------------*/
37
38namespace Arcane
39{
40using namespace Arcane::impl;
41
42/*---------------------------------------------------------------------------*/
43/*---------------------------------------------------------------------------*/
44
45class ArcaneBasicVerifierService
46: public VerifierService
47{
48 class GroupFinder
50 {
51 public:
52
53 GroupFinder(IVariableMng* vm)
54 : m_variable_mng(vm)
55 {}
56 ItemGroup getWantedGroup(VariableMetaData* vmd) override
57 {
58 String full_name = vmd->fullName();
59 IVariable* var = m_variable_mng->findVariableFullyQualified(full_name);
60 if (!var)
61 ARCANE_FATAL("Variable '{0}' not found");
62 return var->itemGroup();
63 }
64
65 private:
66
67 IVariableMng* m_variable_mng;
68 };
69
70 public:
71
72 explicit ArcaneBasicVerifierService(const ServiceBuildInfo& sbi)
73 : VerifierService(sbi)
74 {
75 }
76
77 public:
78
79 void build() override {}
80 void writeReferenceFile() override;
81 void doVerifFromReferenceFile(bool parallel_sequential, bool compare_ghost) override;
82
83 protected:
84
85 void _setFormatVersion(Int32 v)
86 {
87 m_wanted_format_version = v;
88 }
89
90 private:
91
92 String m_full_file_name;
93 Int32 m_wanted_format_version = 1;
94
95 private:
96
97 void _computeFullFileName(bool is_read)
98 {
99 ARCANE_UNUSED(is_read);
101 //m_full_file_name = fileName();
102 const String& sub_dir = subDir();
103 if (!sub_dir.empty()) {
104 s += "/";
105 s += sub_dir;
106 }
107 m_full_file_name = s;
108 }
109 void _doVerifHash(BasicReader* reader, const VariableCollection& variables);
110 void _writeReferenceFile(const String& file_name);
111};
112
113/*---------------------------------------------------------------------------*/
114/*---------------------------------------------------------------------------*/
115
116void ArcaneBasicVerifierService::
117_writeReferenceFile(const String& file_name)
118{
119 ISubDomain* sd = subDomain();
120 IParallelMng* pm = sd->parallelMng();
121 IVariableMng* vm = sd->variableMng();
122 auto open_mode = BasicReaderWriterCommon::OpenModeTruncate;
123 // Pour l'instant utilise la version 1
124 // A partir de janvier 2019, il est possible d'utiliser la version 2 ou 3
125 // car le comparateur C# supporte cette version.
126 Int32 version = m_wanted_format_version;
127 bool want_parallel = pm->isParallel();
128 ScopedPtrT<BasicWriter> verif(new BasicWriter(sd->application(), pm, file_name,
129 open_mode, version, want_parallel));
130 if (compareMode() == eCompareMode::HashOnly)
131 verif->setSaveValues(false);
132
133 verif->initialize();
134
135 // En parallèle, comme l'écriture nécessite des communications entre les sous-domaines,
136 // il est indispensable que tous les PE aient les mêmes variables. On les filtre pour
137 // garantir cela.
138 VariableCollection used_variables = vm->usedVariables();
139 if (pm->isParallel()) {
140 bool dump_not_common = true;
141 VariableCollection filtered_variables = vm->utilities()->filterCommonVariables(pm, used_variables, dump_not_common);
142 vm->writeVariables(verif.get(), filtered_variables);
143 }
144 else {
145 vm->writeVariables(verif.get(), used_variables);
146 }
147}
148
149/*---------------------------------------------------------------------------*/
150/*---------------------------------------------------------------------------*/
151
154{
155 _computeFullFileName(false);
156 String dir_name = platform::getFileDirName(m_full_file_name);
157 platform::recursiveCreateDirectory(m_full_file_name);
158 _writeReferenceFile(m_full_file_name);
159}
160
161/*---------------------------------------------------------------------------*/
162/*---------------------------------------------------------------------------*/
163
165doVerifFromReferenceFile(bool parallel_sequential, bool compare_ghost)
166{
167 ISubDomain* sd = subDomain();
168 IParallelMng* pm = sd->parallelMng();
169 IVariableMng* vm = subDomain()->variableMng();
170 ITraceMng* tm = sd->traceMng();
171 _computeFullFileName(true);
172 bool want_parallel = pm->isParallel();
173 Ref<BasicReader> reader = makeRef(new BasicReader(sd->application(), pm, A_NULL_RANK, m_full_file_name, want_parallel));
174 reader->initialize();
175 GroupFinder group_finder(vm);
176 reader->setItemGroupFinder(&group_finder);
177
178 VariableList read_variables;
179 _getVariables(read_variables, parallel_sequential);
180
181 // En parallèle, comme la lecture nécessite des communications entre les sous-domaines,
182 // il est indispensable que tous les PE aient les mêmes variables. On les filtre pour
183 // garantir cela.
184 if (pm->isParallel()) {
185 IVariableMng* vm = sd->variableMng();
186 bool dump_not_common = true;
187 VariableCollection filtered_variables = vm->utilities()->filterCommonVariables(pm, read_variables, dump_not_common);
188 read_variables = filtered_variables;
189 }
190
191 tm->info() << "Checking (" << m_full_file_name << ")";
192 reader->beginRead(read_variables);
193 if (compareMode() == eCompareMode::Values)
194 _doVerif(reader.get(), read_variables, compare_ghost);
195 if (compareMode() == eCompareMode::HashOnly)
196 _doVerifHash(reader.get(), read_variables);
197 reader->endRead();
198}
199
200/*---------------------------------------------------------------------------*/
201/*---------------------------------------------------------------------------*/
202namespace
203{
204 String
205 _getHashValueOrNull(const std::map<String, String>& comparison_hash_map, const String& name)
206 {
207 auto x = comparison_hash_map.find(name);
208 if (x != comparison_hash_map.end())
209 return x->second;
210 return {};
211 }
212} // namespace
213
214void ArcaneBasicVerifierService::
215_doVerifHash(BasicReader* ref_reader, const VariableCollection& variables)
216{
217 ISubDomain* sd = subDomain();
218 IParallelMng* pm = sd->parallelMng();
219 bool is_master = pm->isMasterIO();
220 const bool want_parallel = pm->isParallel();
221
222 info() << "Check Verif Hash";
223 // Récupère l'algorithm de calcul du hash
224 IHashAlgorithm* ref_compare_hash_algo = ref_reader->comparisonHashAlgorithm();
225 if (!ref_compare_hash_algo)
226 // TODO: regarder s'il faut ne rien faire ou s'il faut signaler une erreur.
227 return;
228
229 // Calcul les hash des valeurs courantes des variables
230 std::map<String, String> current_comparison_hash_map;
231 ParallelDataWriterList parallel_data_writers;
232 info() << "DoVerifHash";
233 for (VariableCollection::Enumerator ivar(variables); ++ivar;) {
234 IVariable* var = *ivar;
235 Ref<IData> allocated_data;
236 IData* data = var->data();
237 // En parallèle, trie les entités par uniqueId() croissant.
238 // En séquentiel c'est toujours le cas.
239 // NOTE: pour l'instant on utilise le IParallelMng global mais il faudrait
240 // vérifier s'il ne faut pas utiliser celui associé au maillage de la
241 // variable courante \a var.
242 if (want_parallel) {
243 // En parallèle, ne compare que les variables sur les entités
244 ItemGroup group = var->itemGroup();
245 if (group.null())
246 continue;
247 Ref<ParallelDataWriter> writer = parallel_data_writers.getOrCreateWriter(group);
248 allocated_data = writer->getSortedValues(data);
249 data = allocated_data.get();
250 }
251 String hash_string = var->_internalApi()->computeComparisonHashCollective(ref_compare_hash_algo, data);
252 if (!hash_string.empty())
253 current_comparison_hash_map.try_emplace(var->fullName(), hash_string);
254 }
255
256 std::map<String, String> ref_comparison_hash_map;
257 ref_reader->fillComparisonHash(ref_comparison_hash_map);
258 if (is_master) {
259 Int32 nb_variable = 0;
260 Int32 nb_compared = 0;
261 Int32 nb_different = 0;
262 for (VariableCollection::Enumerator ivar(variables); ++ivar;) {
263 IVariable* var = *ivar;
264 String var_full_name = var->fullName();
265 ++nb_variable;
266 String ref_hash = _getHashValueOrNull(ref_comparison_hash_map, var_full_name);
267 String current_hash = _getHashValueOrNull(current_comparison_hash_map, var_full_name);
268 if (!ref_hash.empty() && !current_hash.empty()) {
269 ++nb_compared;
270 if (ref_hash != current_hash) {
271 info() << "Different hash ref_hash=" << ref_hash << " current=" << current_hash
272 << " var=" << var_full_name;
273 ++nb_different;
274 }
275 else
276 info(4) << "Found Hash hash=" << ref_hash << " var=" << var_full_name;
277 }
278 }
279 info() << "NbVariable=" << nb_variable << " nb_compared=" << nb_compared << " nb_different=" << nb_different;
280 }
281}
282
283/*---------------------------------------------------------------------------*/
284/*---------------------------------------------------------------------------*/
285
286/*---------------------------------------------------------------------------*/
287/*---------------------------------------------------------------------------*/
288
289class ArcaneBasicVerifierService2
290: public ArcaneBasicVerifierService
291{
292 public:
293
294 explicit ArcaneBasicVerifierService2(const ServiceBuildInfo& sbi)
295 : ArcaneBasicVerifierService(sbi)
296 {
297 }
298};
299
300/*---------------------------------------------------------------------------*/
301/*---------------------------------------------------------------------------*/
302
303class ArcaneBasicVerifierServiceV3
304: public ArcaneBasicVerifierService
305{
306 public:
307
308 explicit ArcaneBasicVerifierServiceV3(const ServiceBuildInfo& sbi)
309 : ArcaneBasicVerifierService(sbi)
310 {
311 _setFormatVersion(3);
312 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_VERIF_HASHONLY", true)) {
313 bool use_hash = (v.value() != 0);
314 info() << "ArcaneBasicVerifierServiceV3: using hash?=" << use_hash;
316 }
317 }
318};
319
320/*---------------------------------------------------------------------------*/
321/*---------------------------------------------------------------------------*/
322
324 ServiceProperty("ArcaneBasicVerifier2", ST_SubDomain),
326
328 ServiceProperty("ArcaneBasicVerifier3", ST_SubDomain),
330
331/*---------------------------------------------------------------------------*/
332/*---------------------------------------------------------------------------*/
333
334/*---------------------------------------------------------------------------*/
335/*---------------------------------------------------------------------------*/
336
337} // End namespace Arcane
338
339/*---------------------------------------------------------------------------*/
340/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Ce fichier contient les différentes fabriques de services et macro pour enregistrer les services.
#define ARCANE_SERVICE_INTERFACE(ainterface)
Macro pour déclarer une interface lors de l'enregistrement d'un service.
void build() override
Construction de niveau build du service.
void doVerifFromReferenceFile(bool parallel_sequential, bool compare_ghost) override
Effectue la vérification à partir du fichier référence.
void writeReferenceFile() override
Ecrit le fichier référence.
virtual ITraceMng * traceMng() const =0
Gestionnaire de traces.
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual bool isMasterIO() const =0
true si l'instance est un gestionnaire maître des entrées/sorties.
virtual bool isParallel() const =0
Retourne true si l'exécution est parallèle.
Interface du gestionnaire d'un sous-domaine.
Definition ISubDomain.h:74
virtual IApplication * application()=0
Application.
virtual IParallelMng * parallelMng()=0
Retourne le gestionnaire de parallélisme.
virtual IVariableMng * variableMng()=0
Retourne le gestionnaire de variables.
Interface du gestionnaire de traces.
virtual TraceMessage info()=0
Flot pour un message d'information.
virtual String computeComparisonHashCollective(IHashAlgorithm *hash_algo, IData *sorted_data)=0
Calcule de Hash de comparaison pour la variable.
Interface du gestionnaire de variables.
virtual IVariableUtilities * utilities() const =0
Interface des fonctions utilitaires associées.
virtual VariableCollection usedVariables()=0
Liste des variables utilisées.
virtual void writeVariables(IDataWriter *writer, IVariableFilter *filter=0)=0
Ecrit les variables.
virtual VariableCollection filterCommonVariables(IParallelMng *pm, const VariableCollection input_variables, bool dump_not_common)=0
Filtre les variables communes entre plusieurs rangs.
Interface d'une variable.
Definition IVariable.h:56
virtual String fullName() const =0
Nom complet de la variable (avec le préfixe de la famille)
virtual IData * data()=0
Données associées à la variable.
virtual ItemGroup itemGroup() const =0
Groupe du maillage associé.
virtual IVariableInternal * _internalApi()=0
API interne à Arcane.
Interface du service de vérification des données entre deux exécutions.
@ Values
Compare toutes les valeurs.
@ HashOnly
Compare uniquement les hash des valeurs.
Groupe d'entités de maillage.
Definition ItemGroup.h:49
bool null() const
true is le groupe est le groupe nul
Definition ItemGroup.h:70
Référence à une instance.
InstanceType * get() const
Instance associée ou nullptr si aucune.
Structure contenant les informations pour créer un service.
Propriétés de création d'un service.
Constructeur de chaîne de caractère unicode.
Chaîne de caractères unicode.
bool empty() const
Vrai si la chaîne est vide (nulle ou "")
Definition String.cc:315
TraceMessage info() const
Flot pour un message d'information.
Collection de variables.
Meta-données sur une variable.
String fullName() const
Nom complet de la variable.
String fileName() const override
Nom du fichier contenant les valeurs de référence.
virtual void _getVariables(VariableList variables, bool parallel_sequential)
Remplit dans variables la liste des variables devant être relues.
void setCompareMode(eCompareMode v) override
Type de comparaison souhaité
String subDir() const override
Nom du fichier contenant les valeurs de référence.
Interface pour retrouver le groupe associée à une variable à partir de ces meta-données.
Definition BasicReader.h:45
void fillComparisonHash(std::map< String, String > &comparison_hash_map)
Remplit l'argument avec des couples (nom_de_variable,valeur du hash).
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro pour enregistrer un service.
ARCCORE_BASE_EXPORT String getFileDirName(const String &file_name)
Retourne le nom du répertoire d'un fichier.
ARCCORE_BASE_EXPORT bool recursiveCreateDirectory(const String &dir_name)
Créé un répertoire.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
@ ST_SubDomain
Le service s'utilise au niveau du sous-domaine.
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Créé une référence sur un pointeur.
std::int32_t Int32
Type entier signé sur 32 bits.