Arcane  v3.14.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
TimeLoopMng.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/* TimeLoopMng.cc (C) 2000-2024 */
9/* */
10/* Gestionnaire de la boucle en temps. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/Iterator.h"
15#include "arcane/utils/List.h"
16#include "arcane/utils/ScopedPtr.h"
17#include "arcane/utils/PlatformUtils.h"
18#include "arcane/utils/StringBuilder.h"
19#include "arcane/utils/IMemoryInfo.h"
20#include "arcane/utils/ITraceMng.h"
21#include "arcane/utils/IProfilingService.h"
22#include "arcane/utils/IMessagePassingProfilingService.h"
23#include "arcane/utils/ValueConvert.h"
24#include "arcane/utils/TimeoutException.h"
25#include "arcane/utils/GoBackwardException.h"
26#include "arcane/utils/OStringStream.h"
27#include "arcane/utils/FloatingPointExceptionSentry.h"
28#include "arcane/utils/JSONWriter.h"
29
30#include "arcane/core/IApplication.h"
31#include "arcane/core/IServiceLoader.h"
32#include "arcane/core/ISubDomain.h"
33#include "arcane/core/CommonVariables.h"
34#include "arcane/core/IVariableMng.h"
35#include "arcane/core/IEntryPoint.h"
36#include "arcane/core/IEntryPointMng.h"
37#include "arcane/core/IMesh.h"
38#include "arcane/core/IMeshSubMeshTransition.h"
39#include "arcane/core/IModule.h"
40#include "arcane/core/Directory.h"
41#include "arcane/core/IModuleMng.h"
42#include "arcane/core/Timer.h"
43#include "arcane/core/ITimeLoop.h"
44#include "arcane/core/ITimeLoopMng.h"
45#include "arcane/core/TimeLoopEntryPointInfo.h"
46#include "arcane/core/TimeLoopSingletonServiceInfo.h"
47#include "arcane/core/IParallelMng.h"
48#include "arcane/core/IMainFactory.h"
49#include "arcane/core/ICaseMng.h"
50#include "arcane/core/ICaseFunction.h"
51#include "arcane/core/IServiceFactory.h"
52#include "arcane/core/IModuleFactory.h"
53#include "arcane/core/ServiceBuilder.h"
54#include "arcane/core/ServiceInfo.h"
55#include "arcane/core/ServiceUtils.h"
56#include "arcane/core/CaseOptions.h"
57#include "arcane/core/ICaseDocument.h"
58#include "arcane/core/IVerifierService.h"
59#include "arcane/core/IMeshPartitioner.h"
60#include "arcane/core/IVariableFilter.h"
61#include "arcane/core/ITimeStats.h"
62#include "arcane/core/XmlNodeIterator.h"
63#include "arcane/core/ServiceFinder2.h"
64#include "arcane/core/VariableCollection.h"
65#include "arcane/core/Observable.h"
66#include "arcane/core/IParallelReplication.h"
67#include "arcane/core/IItemFamily.h"
68#include "arcane/core/IConfiguration.h"
69#include "arcane/core/IMeshUtilities.h"
70#include "arcane/core/IVariableUtilities.h"
71#include "arcane/core/IItemEnumeratorTracer.h"
72#include "arcane/core/ObservablePool.h"
73#include "arcane/core/parallel/IStat.h"
74#include "arcane/core/IVariableSynchronizer.h"
75#include "arcane/core/IVariableSynchronizerMng.h"
76
77#include "arcane/accelerator/core/IAcceleratorMng.h"
78#include "arcane/accelerator/core/Runner.h"
79
80#include "arcane/impl/DefaultBackwardMng.h"
81
82#include <algorithm>
83#include <map>
84
85/*---------------------------------------------------------------------------*/
86/*---------------------------------------------------------------------------*/
87
88namespace Arcane
89{
90
91/*---------------------------------------------------------------------------*/
92/*---------------------------------------------------------------------------*/
97: public TraceAccessor
98, public ITimeLoopMng
99{
100 public:
101
103 {
104 ModuleState(bool is_optional, const String & alias)
105 : m_is_active(false), m_is_optional(is_optional), m_alias(alias) { }
106
107 bool m_is_active;
108 bool m_is_optional;
109 String m_alias;
110 };
119
121 typedef std::map<String,ModuleState> ModuleStateMap;
123 typedef std::map<String,ITimeLoop*> TimeLoopMap;
125 typedef std::map<String,IModuleFactoryInfo*> ModuleFactoryMap;
126
127 public:
128
129 explicit TimeLoopMng(ISubDomain* sd);
130 ~TimeLoopMng() override;
131
132 public:
133
134 void build() override;
135
136 ISubDomain* subDomain() const override { return m_sub_domain; }
137
138 void execExitEntryPoints() override;
139 void execBuildEntryPoints() override;
140 void execInitEntryPoints(bool is_continue) override;
141 void stopComputeLoop(bool is_final_time,bool has_error) override;
142 bool finalTimeReached() const override { return m_final_time_reached; }
143 Real cpuTimeUsed() const override;
144
147
148 void registerTimeLoop(ITimeLoop* timeloop) override;
149 void setUsedTimeLoop(const String& name) override;
150
151 ITimeLoop* usedTimeLoop() const override { return m_used_time_loop; }
152
153 void doExecNextEntryPoint(bool & is_last) override;
154 IEntryPoint* nextEntryPoint() override;
155
157
158 int doOneIteration() override;
159
160 void setBackwardMng(IBackwardMng* backward_mng) override;
161 // Attention, peut renvoyer NULL
162 IBackwardMng* getBackwardMng() const override { return m_backward_mng;}
163
164 void goBackward() override;
165 bool isDoingBackward() override;
166 void setBackwardSavePeriod(Integer n) override
167 {
168 if (!m_backward_mng)
169 _createOwnDefaultBackwardMng();
170 m_backward_mng->setSavePeriod(n);
171 }
172
173 void setVerificationActive(bool is_active) override { m_verification_active = is_active; }
174 void doVerification(const String& name) override;
175
176 void registerActionMeshPartition(IMeshPartitionerBase* mesh_partitioner) override;
177
178 void timeLoopsName(StringCollection & names) const override;
179 void timeLoops(TimeLoopCollection & time_loops) const override;
180 ITimeLoop * createTimeLoop(const String & name) override;
181
182 int doComputeLoop(Integer max_loop) override;
183 Integer nbLoop() const override { return m_nb_loop; }
184
186 eTimeLoopStopReason stopReason() const override { return m_stop_reason; }
187
188 public:
189
190 void execRestoreEntryPoints();
191 void execOnMeshChangedEntryPoints() override;
192 void execOnMeshRefinementEntryPoints() override;
193
194 ITraceMng* traceMng() { return m_sub_domain->traceMng(); }
195
196 IObservable* observable(eTimeLoopEventType type) override
197 {
198 return m_observables[type];
199 }
200
201 protected:
202
206 bool _createModule(const String & module_name);
208
211 const char* where);
217
224
225 private:
226
229
232
235
238
241
244
247
250
253
256
259
262
264
266
268
269 bool m_stop_time_loop;
270 bool m_stop_has_error;
271 bool m_final_time_reached;
272
274
276 bool m_verif_same_parallel;
278 bool m_verification_active;
281 bool m_verification_only_at_exit = false;
282
284 bool m_my_own_backward_mng;
285
286 ModuleStateMap m_module_state_list;
287
290
292 UniqueArray<IMeshPartitionerBase*> m_mesh_partitioner;
293 String m_message_class_name;
294 Integer m_alarm_timer_value;
295 Integer m_nb_loop;
296
298
299 eTimeLoopStopReason m_stop_reason;
300
301 // Service de message passing profiling
302 Ref<IMessagePassingProfilingService> m_msg_pass_prof_srv;
303
306
307 private:
308
309 void _execOneEntryPoint(IEntryPoint* ic, Integer index_value = 0, bool do_verif = false);
310 void _dumpTimeInfos(JSONWriter& json_writer);
311 void _resetTimer() const;
312 void _checkVerif(const String& entry_point_name,Integer index,bool do_verif);
313 void _checkVerifSameOnAllReplica(const String& entry_point_name);
314 void _createOwnDefaultBackwardMng();
315 void _doMeshPartition();
317 void _createSingletonServices(IServiceLoader* service_loader);
318 void _callSpecificEntryPoint();
319};
320
321/*---------------------------------------------------------------------------*/
322/*---------------------------------------------------------------------------*/
323
324extern "C++" ITimeLoopMng*
325arcaneCreateTimeLoopMng(ISubDomain * mng)
326{
327 auto* tm = new TimeLoopMng(mng);
328 return tm;
329}
330
331/*---------------------------------------------------------------------------*/
332/*---------------------------------------------------------------------------*/
333
334TimeLoopMng::
335TimeLoopMng(ISubDomain* sd)
336: TraceAccessor(sd->traceMng())
337, m_sub_domain(sd)
338, m_entry_point_mng(m_sub_domain->entryPointMng())
339, m_default_time_loop(nullptr)
340, m_used_time_loop(nullptr)
341, m_current_entry_point_ptr(nullptr)
342, m_stop_time_loop(false)
343, m_stop_has_error(false)
344, m_final_time_reached(false)
345, m_current_entry_point(0)
346, m_verif_type(VerifNone)
347, m_verif_same_parallel(false)
348, m_verif_path(".")
349, m_verification_active(false)
350, m_verification_at_entry_point(false)
351, m_backward_mng(nullptr)
352, m_my_own_backward_mng(false)
353, m_message_class_name("TimeLoopMng")
354, m_alarm_timer_value(0)
355, m_nb_loop(0)
356, m_stop_reason(eTimeLoopStopReason::NoStop)
357{
358 {
359 String s = platform::getEnvironmentVariable("ARCANE_LISTENER_TIMEOUT");
360 if (!s.null()){
361 Integer v = 0;
362 if (!builtInGetValue(v,s))
363 if (v>0)
364 m_alarm_timer_value = v;
365 }
366 }
367 {
368 String s = platform::getEnvironmentVariable("ARCANE_VERIF_PARALLEL");
369 if (!s.null())
370 m_verif_same_parallel = true;
371 }
372
373 m_observables.add(eTimeLoopEventType::BeginEntryPoint);
374 m_observables.add(eTimeLoopEventType::EndEntryPoint);
375 m_observables.add(eTimeLoopEventType::BeginIteration);
376 m_observables.add(eTimeLoopEventType::EndIteration);
377}
378
379/*---------------------------------------------------------------------------*/
380/*---------------------------------------------------------------------------*/
381
382TimeLoopMng::
383~TimeLoopMng()
384{
385 for( ConstIterT<TimeLoopMap> i(m_time_loop_list); i(); ++i){
386 ITimeLoop * tm = i->second;
387 delete tm;
388 }
389
390 if (m_my_own_backward_mng)
391 delete m_backward_mng;
392}
393
394/*---------------------------------------------------------------------------*/
395/*---------------------------------------------------------------------------*/
396
397void TimeLoopMng::
398build()
399{
400 // Créé en enregistre une boucle par défaut.
401 ITimeLoop * tm = createTimeLoop(String("ArcaneEmptyLoop"));
404
405 {
406 String verif_env = platform::getEnvironmentVariable("STDENV_VERIF");
407 if (verif_env=="READ"){
409 info() << "Checking in read mode";
410 }
411 if (verif_env=="WRITE"){
413 info() << "Checking in write mode";
414 }
415 if (verif_env=="CHECKSYNC"){
416 m_verif_type = VerifSync;
417 info() << "Checking synchronizations";
418 }
419 if (verif_env=="CHECKREPLICA"){
421 info() << "Checking variables values between replica";
422 }
424 m_verification_active = true;
425 }
426 {
427 String s = platform::getEnvironmentVariable("STDENV_VERIF_ENTRYPOINT");
428 if (!s.null()){
430 info() << "Do verification at each entry point";
431 }
432 }
433 {
434 String s = platform::getEnvironmentVariable("STDENV_VERIF_ONLY_AT_EXIT");
435 if (s=="1" || s=="true" || s=="TRUE"){
436 m_verification_only_at_exit = true;
437 info() << "Do verification only at exit";
438 }
439 }
440 // Regarde si on n'exécute qu'un seul point d'entrée au lieu de la boucle
441 // en temps. Cela est utilisé uniquement pour des tests
442 {
443 String s = platform::getEnvironmentVariable("ARCANE_CALL_SPECIFIC_ENTRY_POINT");
444 if (!s.null()){
446 info() << "Use specific entry point: " << s;
447 }
448 }
449
450 //
451 if (m_verification_active){
452 m_verif_path = platform::getEnvironmentVariable("STDENV_VERIF_PATH");
453 if (m_verif_path.null()){
454 String user_name = subDomain()->application()->userName();
455 m_verif_path = "/tmp/" + user_name + "/verif";
456 //m_verif_path += user_name;
457 //m_verif_path += "/verif";
458 }
459 }
461 if (subDomain()->parallelMng()->isMasterIO()){
462 info() << "Creating directory '"<< m_verif_path << "' for checking";
463 platform::recursiveCreateDirectory(m_verif_path);
464 }
465 }
466
467 // Creation du service de "message passing profiling" le cas echeant
468 {
469 String msg_pass_prof_str = platform::getEnvironmentVariable("ARCANE_MESSAGE_PASSING_PROFILING");
470 if (!msg_pass_prof_str.null()) {
471 String service_name;
472 // TODO: ne pas faire de if mais utiliser directement le nom spécifié par la
473 // variable d'environnement.
474 if (msg_pass_prof_str == "JSON") {
475 service_name = "JsonMessagePassingProfiling";
476 } else if (msg_pass_prof_str == "OTF2") {
477 service_name = "Otf2MessagePassingProfiling";
478 }
479 ServiceBuilder<IMessagePassingProfilingService> srv(this->subDomain());
480 m_msg_pass_prof_srv = srv.createReference(service_name ,SB_AllowNull);
481 }
482 }
483}
484
485/*---------------------------------------------------------------------------*/
486/*---------------------------------------------------------------------------*/
487
488void TimeLoopMng::
489_createOwnDefaultBackwardMng()
490{
491 m_backward_mng = new DefaultBackwardMng(traceMng(),subDomain());
493 m_my_own_backward_mng = true;
494}
495
496/*---------------------------------------------------------------------------*/
497/*---------------------------------------------------------------------------*/
498
499void TimeLoopMng::
500setBackwardMng(IBackwardMng* backward_mng)
501{
502 ARCANE_ASSERT((backward_mng),("IBackwardMng pointer null"));
503
504 if (m_backward_mng){
505 // Détruit l'ancien gestionnaire si c'est nous qui l'avons créé.
506 if (m_my_own_backward_mng)
507 delete m_backward_mng;
508 ARCANE_FATAL("Backward manager already set");
509 }
510
511 m_backward_mng = backward_mng;
512 m_my_own_backward_mng = false;
513}
514
515/*---------------------------------------------------------------------------*/
516/*---------------------------------------------------------------------------*/
517
520{
521 Timer::Action ts_action(m_sub_domain,"InitEntryPoints");
522 info() << "-- Executing init entry points";
523
525
527 IEntryPoint * ic = * i;
528 if (ic->where() == IEntryPoint::WInit || ic->where() == where)
529 _execOneEntryPoint(ic);
530 }
531}
532
533/*---------------------------------------------------------------------------*/
534/*---------------------------------------------------------------------------*/
535
538{
539 Timer::Action ts_action(m_sub_domain,"BuildtEntryPoints");
540 info() << "-- Executing build entry points";
541
543 IEntryPoint* ic = *i;
544 if (ic->where()==IEntryPoint::WBuild)
545 _execOneEntryPoint(ic);
546 }
547}
548
549/*---------------------------------------------------------------------------*/
550/*---------------------------------------------------------------------------*/
551
552void TimeLoopMng::
553execRestoreEntryPoints()
554{
555 Timer::Action ts_action(m_sub_domain,"RestoreEntryPoints");
556 info() << "-- Executing restore entry points";
557
559 IEntryPoint * ic = * i;
560 _execOneEntryPoint(ic);
561 }
562}
563
564/*---------------------------------------------------------------------------*/
565/*---------------------------------------------------------------------------*/
566
569{
570 Timer::Action ts_action(m_sub_domain,"OnMeshChangedEntryPoints");
571 info() << "-- Executing entry points after mesh change";
572
574 IEntryPoint * ic = * i;
575 info() << "Execute: " << ic->name();
576 _execOneEntryPoint(ic);
577 }
578}
579
580/*---------------------------------------------------------------------------*/
581/*---------------------------------------------------------------------------*/
582
585{
586 Timer::Action ts_action(m_sub_domain,"OnMeshRefinementEntryPoints");
587 info() << "-- Executing entry points after mesh refinement";
588
590 IEntryPoint * ic = * i;
591 info() << "Execute: " << ic->name();
592 _execOneEntryPoint(ic);
593 }
594}
595
596/*---------------------------------------------------------------------------*/
597/*---------------------------------------------------------------------------*/
598
601{
602 Timer::Action ts_action(m_sub_domain,"ExitEntryPoints");
603 info() << "-- Executing terminal entry points";
604
606 IEntryPoint * ic = * i;
607 _execOneEntryPoint(ic);
608 }
609
610 // Affiche les statistiques d'exécution
611 {
612 JSONWriter json_writer(JSONWriter::FormatFlags::None);
613 json_writer.beginObject();
614 _dumpTimeInfos(json_writer);
615 json_writer.endObject();
616 traceMng()->plog() << "TimeStats:" << json_writer.getBuffer();
617 traceMng()->flush();
618 }
619
620 // Affiche le profiling de message passing dans un fichier pour les traces JSON
621 if (m_msg_pass_prof_srv.get() && m_msg_pass_prof_srv->implName() == "JsonMessagePassingProfiling") {
622 String fullname(subDomain()->listingDirectory().file("message_passing_logs.")
623 + String(std::to_string(subDomain()->subDomainId()))
624 + String(".json"));
625 std::ofstream file(fullname.localstr());
626 m_msg_pass_prof_srv->printInfos(file);
627 }
628}
629
630/*---------------------------------------------------------------------------*/
631/*---------------------------------------------------------------------------*/
632
633void TimeLoopMng::
634_execOneEntryPoint(IEntryPoint * ic, Integer index, bool do_verif)
635{
637 m_observables[eTimeLoopEventType::BeginEntryPoint]->notifyAllObservers();
638 ic->executeEntryPoint();
639 m_observables[eTimeLoopEventType::EndEntryPoint]->notifyAllObservers();
641 if (m_verification_at_entry_point && !m_verification_only_at_exit)
642 _checkVerif(ic->name(),index,do_verif);
643}
644
645/*---------------------------------------------------------------------------*/
646/*---------------------------------------------------------------------------*/
647
649doVerification(const String& name)
650{
651 _checkVerif(name,0,true);
652}
653
654/*---------------------------------------------------------------------------*/
655/*---------------------------------------------------------------------------*/
656
657void TimeLoopMng::
658_checkVerif(const String& entry_point_name,Integer index,bool do_verif)
659{
661
663 IApplication* app = sd->application();
664
665
667 String service_name1 = platform::getEnvironmentVariable("STDENV_VERIF_SERVICE");
668 if (service_name1.empty())
669 service_name1 = "ArcaneBasicVerifier2";
670
672 m_verifier_service = sf.createReference(service_name1);
673 if (!m_verifier_service.get()){
674 warning() << "No verification service is available."
675 << " No verification will be performed";
677 }
678 if (m_verifier_service.get()){
679 info() << "Use the service <" << service_name1
680 << "> for verification";
681 }
682 }
683
684 if (pm->isParallel()){
685 if (m_verif_type == VerifSync){
686 Integer nb_error = 0;
687 VariableCollection variables(subDomain()->variableMng()->usedVariables());
688 for( VariableCollection::Enumerator i(variables); ++i; ){
689 IVariable* var = *i;
690 if (var->property() & IVariable::PNoNeedSync)
691 continue;
692 if (var->isPartial())
693 continue;
694 nb_error += var->checkIfSync(5);
695 }
696 if (nb_error!=0)
697 info() << "Error in synchronization nb_error=" << nb_error
698 << " entry_point=" << entry_point_name;
699 }
700 }
701
702 if (m_verif_type == VerifSameReplica && pm->replication()->hasReplication()){
703 _checkVerifSameOnAllReplica(entry_point_name);
704 }
705
706 if ((m_verif_type == VerifRead || m_verif_type == VerifWrite) && do_verif){
707 Integer current_iter = subDomain()->commonVariables().globalIteration();
708 if (current_iter>=0){
709 {
710 StringBuilder path = Directory(m_verif_path).file("verif_file");
711 if (m_verif_same_parallel){
712 path += "_";
713 path += pm->commRank();
714 }
715
716 StringBuilder sub_dir;
717 sub_dir += "iter";
718 sub_dir += current_iter;
719 sub_dir += "/";
720 sub_dir += entry_point_name;
721 sub_dir += index;
722
723 m_verifier_service->setFileName(path.toString());
724 m_verifier_service->setSubDir(sub_dir.toString());
725 }
726 bool parallel_sequential = pm->isParallel();
727 if (m_verif_same_parallel)
728 parallel_sequential = false;
730
731 // Activer cette partie si on souhaite sauver les valeurs actuelles
732#if 0
733 {
734 ServiceFinder2T<IVerifierService,ISubDomain> sf(app,sd);
735 ScopedPtrT<IVerifierService> current_save(sf.find(service_name1));
736 if (current_save.get()){
737 current_save->setFileName(m_verifier_service->fileName()+"_current");
738 current_save->setSubDir(m_verifier_service->subDir());
739 current_save->writeReferenceFile();
740 }
741 }
742#endif
743
744 // En lecture, désactive les exceptions flottantes pour éviter
745 // des erreurs lorsqu'on compare des variables non initialisées
746 {
747 FloatingPointExceptionSentry fpes(false);
748 m_verifier_service->doVerifFromReferenceFile(parallel_sequential,
749 platform::getEnvironmentVariable("STDENV_VERIF_SKIP_GHOSTS").null());
750 }
751 }
753 m_verifier_service->writeReferenceFile();
754 }
755 }
756}
757
758/*---------------------------------------------------------------------------*/
759/*---------------------------------------------------------------------------*/
760
761void TimeLoopMng::
762_checkVerifSameOnAllReplica(const String& entry_point_name)
763{
764 info() << "CHECK: comparing variables values on all replica"
765 << " entry_point_name=" << entry_point_name;
766 ISubDomain* sd = subDomain();
767 IParallelMng* replica_pm = sd->parallelMng()->replication()->replicaParallelMng();
768 IVariableMng* vm = sd->variableMng();
769 VariableCollection variables(vm->usedVariables());
770 VariableList vars_to_check;
771 for( VariableCollection::Enumerator i(variables); ++i; ){
772 IVariable* var = *i;
773 if (var->property() & IVariable::PNoReplicaSync)
774 continue;
775 if (var->isPartial())
776 continue;
777 // Pour l'instant on ne supporte pas la comparaison entre réplica
778 // des variables de type 'String'.
779 if (var->dataType()==DT_String)
780 continue;
781 vars_to_check.add(var);
782 }
783 VariableCollection common_vars = vm->utilities()->filterCommonVariables(replica_pm,vars_to_check,true);
784
785 Integer nb_error = 0;
786 {
787 FloatingPointExceptionSentry fpes(false);
788 for( VariableCollection::Enumerator ivar(common_vars); ++ivar; ){
789 IVariable* var = *ivar;
790 nb_error += var->checkIfSameOnAllReplica(10);
791 }
792 }
793
794 if (nb_error!=0)
795 info() << "Errors in comparing values between replica nb_error=" << nb_error
796 << " entry_point=" << entry_point_name;
797}
798
799/*---------------------------------------------------------------------------*/
800/*---------------------------------------------------------------------------*/
806{
807 if (!m_used_time_loop)
808 ARCANE_FATAL("No time loop");
809
810 is_last = true;
811
813
814 if (cl.empty())
815 return;
816
817 if (m_current_entry_point >= cl.count())
819
820 _execOneEntryPoint(cl[m_current_entry_point]);
821
823
824 is_last = (m_current_entry_point >= cl.count());
825}
826
827/*---------------------------------------------------------------------------*/
828/*---------------------------------------------------------------------------*/
834{
835 //return m_loop_entry_points->EntryPointList()[m_current_entry_point];
837 if (m_current_entry_point >= cl.count())
838 return nullptr;
840}
841
842/*---------------------------------------------------------------------------*/
843/*---------------------------------------------------------------------------*/
844
847{
848 ITraceMng * msg = traceMng();
850 Trace::Setter mci(msg,m_message_class_name);
851
852 if (!m_used_time_loop)
853 ARCANE_FATAL("No time loop");
854
855 Integer current_iteration = sd->commonVariables().globalIteration();
856 // Le numéro d'itération 0 correspond à l'initialisation. La première
857 // itération de la boucle en temps porte le numéro 1.
858 if (current_iteration==0){
859 VariableScalarInteger global_iteration(sd->commonVariables().m_global_iteration);
860 global_iteration = 1;
862 }
863
864 _resetTimer();
865
866 if (m_stop_time_loop){
867 if (m_stop_has_error)
868 return (-1);
869 return (+1);
870 }
871
873
874 // Action de restauration
876
877 execRestoreEntryPoints();
878
879 // Repartitionnement inutile si retour-arrière
880 m_mesh_partitioner.clear();
881 }
882
883 // Repartionnement demandé
884 bool mesh_partition_done = false;
885 if (!m_mesh_partitioner.empty()) {
887 mesh_partition_done = true;
888 }
889
890 // Action de sauvegarde
892
894
895 {
896 // Regarde les modules inactifs au cours du temps
897 Real global_time = sd->commonVariables().globalTime();
898 CaseOptionsCollection blocks(sd->caseMng()->blocks());
899 for( CaseOptionsCollection::Enumerator i(blocks); ++i; ){
900 ICaseOptions * opt = * i;
901 IModule * mod = opt->caseModule();
902 ICaseFunction * f = opt->activateFunction();
903 if (mod && f){
904 bool is_active = true;
905 f->value(global_time, is_active);
906 bool mod_disabled = mod->disabled();
910 info() << "The module " << mod->name() << " is desactivated";
911 else
912 info() << "The module " << mod->name() << " is activated";
913 mod->setDisabled(mod_new_disabled);
914 }
915 }
916 }
917 }
918
919 m_observables[eTimeLoopEventType::BeginIteration]->notifyAllObservers();
920
921 // Exécute chaque point d'entrée de l'itération
922 {
923 Integer index =0;
924 sd->timeStats()->notifyNewIterationLoop();
925 Timer::Action ts_action(sd,"LoopEntryPoints");
926 for( EntryPointList::Enumerator i(m_loop_entry_points); ++i; ++index ){
927 IEntryPoint* ep = *i;
928 IModule* mod = ep->module();
929 if (mod && mod->disabled()){
930 continue;
931 //warning() << "MODULE " << mod->name() << " is disabled";
932 }
933 try{
934 _execOneEntryPoint(*i, index, true);
935 } catch(const GoBackwardException&){
937 } catch(...){ // On remonte toute autre exception
938 throw;
939 }
941 break;
942 }
943 }
944 if (!m_verification_at_entry_point && !m_verification_only_at_exit)
945 _checkVerif("_EndLoop",0,true);
946 }
947 m_observables[eTimeLoopEventType::EndIteration]->notifyAllObservers();
948
949 {
950 bool force_prepare_dump = false;
951 if (m_verification_active && m_verif_type==VerifWrite){
952 if (!m_verif_same_parallel)
953 force_prepare_dump = true;
954 }
955 else{
956 String force_prepare_dump_str = platform::getEnvironmentVariable("ARCANE_FORCE_PREPARE_DUMP");
958 force_prepare_dump = true;
959 }
961 info() << "TimeLoopMng::doOneIteration(): Force prepareDump()";
962 // TODO: vérifier si nécessaire et si oui le faire pour tous les sous-domaines.
963 sd->defaultMesh()->prepareForDump();
964 }
965 }
966
967 if (m_stop_time_loop){
968 if (m_stop_has_error)
969 return (-1);
970 return (+1);
971 }
972 return 0;
973}
974
975/*---------------------------------------------------------------------------*/
976/*---------------------------------------------------------------------------*/
982{
984
985 // Détruit le gestionnaire de retour-arrière pour économiser de la mémoire.
986 // Il sera reconstruit après le partitionnement.
988
989 Timer timer(sd,"TimeLoopMng::partitionMesh",Timer::TimerReal);
990 Timer::Action ts_action(sd, "MeshesLoadBalance", true);
991
992 for (IMeshPartitionerBase* mesh_partitioner : m_mesh_partitioner) {
993 IMesh* mesh = mesh_partitioner->primaryMesh();
994 Timer::Action ts_action2(sd, mesh->name(), true);
995 {
997 mesh->utilities()->partitionAndExchangeMeshWithReplication(mesh_partitioner, false);
998 }
999 info() << "Time spent to repartition the mesh (unit: second): "
1000 << timer.lastActivationTime();
1001
1002 // Écrit dans les logs dans les infos sur la distribution du voisinage
1003 // TODO: pouvoir configurer cela et éventuellement ajouter des informations
1004 {
1006 IVariableSynchronizer* sync_info = cell_family->allItemsSynchronizer();
1007 auto communicating_ranks = sync_info->communicatingRanks();
1008 Int64 current_iteration = subDomain()->commonVariables().globalIteration();
1009 {
1010 JSONWriter json_writer(JSONWriter::FormatFlags::None);
1011 json_writer.beginObject();
1012 json_writer.write("Mesh", mesh->name());
1013 json_writer.write("Iteration", current_iteration);
1014 json_writer.write("CommunicatingRanks", communicating_ranks);
1015 json_writer.endObject();
1016 plog() << "MeshPartitionCommunicatingInfos:" << json_writer.getBuffer();
1017 }
1018 }
1019 }
1020
1021 {
1022 Timer::Action ts_action1(sd, "OnMeshChangeEntryPoints", true);
1024 }
1025
1026 m_mesh_partitioner.clear();
1027
1028 // Affiche les statistiques d'exécution
1029 sd->timeStats()->dumpCurrentStats("MeshesLoadBalance");
1030}
1031
1032/*---------------------------------------------------------------------------*/
1033/*---------------------------------------------------------------------------*/
1034
1035void TimeLoopMng::
1036_callSpecificEntryPoint()
1037{
1039 info() << "Calling specific entry point: " << m_specific_entry_point_name;
1040 if (!ep)
1041 ARCANE_FATAL("No entry point named '{0}' found",m_specific_entry_point_name);
1042 ep->executeEntryPoint();
1043}
1044
1045/*---------------------------------------------------------------------------*/
1046/*---------------------------------------------------------------------------*/
1047
1049registerTimeLoop(ITimeLoop * timeloop)
1050{
1051 ITraceMng* msg = traceMng();
1052 Trace::Setter mci(msg,m_message_class_name);
1053
1054 const String& name = timeloop->name();
1055
1056 log() << "Registering the time loop " << name;
1057
1058 auto tl = m_time_loop_list.find(name);
1059 if (tl != m_time_loop_list.end())
1060 ARCANE_FATAL("The time loop '{0}' is defined twice",name);
1061
1062 m_time_loop_list.insert(TimeLoopMap::value_type(name, timeloop));
1063}
1064
1065/*---------------------------------------------------------------------------*/
1066/*---------------------------------------------------------------------------*/
1067
1069setUsedTimeLoop(const String& name)
1070{
1071 ITraceMng * msg = traceMng();
1072 Trace::Setter mci(msg,m_message_class_name);
1073
1074 m_used_time_loop = nullptr;
1075 if (name.null())
1077 else{
1078 auto tl = m_time_loop_list.find(name);
1079 if (tl != m_time_loop_list.end())
1080 m_used_time_loop = tl->second;
1081 }
1082
1083 if (!m_used_time_loop){
1084 info() << "Available time loops: ";
1085 for( const auto& tl : m_time_loop_list ){
1086 info() << "Time loop <" << tl.second->name() << ">";
1087 }
1088 ARCANE_FATAL("Unknown time loop '{0}'",name);
1089 }
1090
1091 logdate() << "Using time loop " << name;
1092
1094 // Fusionne la configuration du sous-domaine avec celle de la boucle en temps.
1095 sd->configuration()->merge(m_used_time_loop->configuration());
1096
1097 ScopedPtrT<IServiceLoader> service_loader(sd->mainFactory()->createServiceLoader());
1098
1099 service_loader->loadModules(sd,false);
1100
1102
1103 // Chargement des modules de la boucle en temps
1105
1106 for( const auto& it : m_module_state_list ){
1107 const ModuleState & module_state = it.second;
1108
1109 if (!module_state.m_is_optional || module_state.m_is_active){
1110 // creation du module
1111 if (!_createModule(module_state.m_alias))
1112 ARCANE_FATAL("The module \"{0}\" was not created.",module_state.m_alias);
1113 }
1114 else{
1115 info() << "The entry points of the module \""
1116 << module_state.m_alias << "\" won't be executed (inactive module).";
1117 }
1118 }
1119
1120 _createSingletonServices(service_loader.get());
1121
1123
1124 // Parcours des points d'entrée explicitement référencés dans la boucle en temps
1125 // (m_used_time_loop) pour rechercher ceux qui correspondent aux points d'entrée
1126 // enregistrés dans les modules
1127 // Les points d'entrée non auto-load non référencés ne sont donc pas pris en charge.
1128 // Attention: dans la boucle en temps les points d'entrée sont référencés
1129 // par nom_module.nom_point_entrée alors que dans le fichier de données
1130 // ils sont référencés par alias_module.nom_point_entrée
1153
1154 // Ajoute les autoload au début.
1157 IEntryPoint* ic = * i;
1158 if (ic->property() & IEntryPoint::PAutoLoadBegin)
1160 }
1161
1162 // Ajoute les points d'entrées de la boucle de calcul.
1165
1166 { // Ajoute les autoload à la fin dans le sens inverse de leur déclaration
1169 IEntryPoint* ic = *i;
1170 if (ic->property() & IEntryPoint::PAutoLoadEnd){
1171 auto_load_ends.add(ic);
1172 }
1173 }
1174 for( Integer i=0, s=auto_load_ends.count(); i<s; ++i){
1175 IEntryPoint * ic = auto_load_ends[s - 1 - i];
1177 }
1178 }
1179}
1180
1181/*---------------------------------------------------------------------------*/
1182/*---------------------------------------------------------------------------*/
1183
1184void TimeLoopMng::
1185_createSingletonServices(IServiceLoader* service_loader)
1186{
1189 const TimeLoopSingletonServiceInfo& ti = *i;
1190 String name = ti.name();
1191 bool is_found = service_loader->loadSingletonService(sd,name);
1192 if (!is_found){
1193 if (ti.isRequired())
1194 ARCANE_FATAL("Unable to find a singleton service named '{0}'",name);
1195 info() << "The optional singleton service named '" << name << "' was not found";
1196 }
1197 info() << "Loading singleton service '" << name << "'";
1198 }
1199
1200 // Lecture des services spécifiés dans le jeu de données.
1201 ICaseMng* cm = m_sub_domain->caseMng();
1202 ICaseDocument* doc = cm->caseDocument();
1203 if (doc){
1204 XmlNode services_element = doc->servicesElement();
1205 String ustr_name("name");
1206 String ustr_active("active");
1207 XmlNodeList services = services_element.children("service");
1208 for( XmlNode x : services ) {
1209 String name = x.attrValue(ustr_name);
1210 XmlNode active_node = x.attr(ustr_active);
1211 bool is_active = true;
1212 if (!active_node.null())
1213 is_active = active_node.valueAsBoolean(true);
1214 if (is_active)
1215 service_loader->loadSingletonService(sd,name);
1216 }
1217 }
1218}
1219
1220/*---------------------------------------------------------------------------*/
1221/*---------------------------------------------------------------------------*/
1222
1226 const char* where)
1227{
1228 //TODO: Verifier que le nom du module spécifié dans la liste des modules à activer existe bien.
1235
1236 auto it = m_module_state_list.find(module_name);
1237 if (it == m_module_state_list.end())
1238 ARCANE_FATAL("No module named '{0}' is referenced",module_name);
1239
1240 const ModuleState & module_state = it->second;
1241 if (!module_state.m_is_optional || module_state.m_is_active){
1242 if (!module_state.m_alias.null())
1243 module_name = module_state.m_alias;
1245 call_alias += ".";
1247
1249 log() << "Looking for entry point '" << call_alias << "'";
1250 if (!entry_point)
1251 ARCANE_FATAL("No entry point named '{0}' is referenced",call_alias);
1252
1253 // il faut verifier que la propriete "where" du point d'entree est
1254 // compatible avec l'attribut "where" donne dans la boucle en temps
1255 String ep_where = entry_point->where();
1257 msg() << "The entry point '" << call_alias << "' declared \"" << ep_where
1258 << "\" can't be in the entry point list \""
1259 << where << "\" of the time loop";
1260
1262 ARCANE_FATAL(msg.str());
1264 ARCANE_FATAL(msg.str());
1265 if (ep_where==IEntryPoint::WExit && where!=ITimeLoop::WExit)
1266 ARCANE_FATAL(msg.str());
1270 && where != ITimeLoop::WInit)
1271 ARCANE_FATAL(msg.str());
1272
1274 }
1275 }
1276}
1277
1278/*---------------------------------------------------------------------------*/
1279/*---------------------------------------------------------------------------*/
1280
1283{
1284 // Analyse des infos de la boucle en temps
1285 // 1. liste des modules obligatoires
1286 for( StringCollection::Enumerator i(time_loop->requiredModulesName()); ++i; ){
1287 const String& module_name = *i;
1288 ModuleState ms(false, module_name);
1289 m_module_state_list.insert(ModuleStateMap::value_type(module_name, ms));
1290 }
1291
1292 // 2. liste des modules optionnels
1293 for( StringCollection::Enumerator i(time_loop->optionalModulesName()); ++i; ){
1294 const String& module_name = *i;
1295 ModuleState ms(true, module_name);
1296 m_module_state_list.insert(ModuleStateMap::value_type(module_name,ms));
1297 }
1298
1300 // Remplissage de la liste d'état des modules à partir
1301 // des infos du fichier de données s'il existe
1302 // (Il n'y a pas de jeu de données par exemple lorsqu'on génére les infos
1303 // internes du code via l'option 'arcane_all_internal').
1304 ICaseDocument* doc = cm->caseDocument();
1305 if (!doc)
1306 return;
1307
1308 XmlNode modules_node = doc->modulesElement();
1309 String ustr_module("module");
1310 String ustr_false("false");
1311 String ustr_name("name");
1312 String ustr_alias("alias");
1313 String ustr_active("active");
1314 for (XmlNode::const_iter i(modules_node); i(); ++i){
1315 if (i->name() != ustr_module)
1316 continue;
1317 XmlNode module_node = *i;
1318 String name = module_node.attrValue(ustr_name);
1319 String alias = module_node.attrValue(ustr_alias);
1320
1321 // Regarde si le module est actif.
1323 bool active = true;
1324 if (!active_node.null())
1325 active = active_node.valueAsBoolean(true);
1326
1327 // Complète les infos de la liste d'état
1328
1329 // Regarde d'abord si 'name' correspond à un nom de module
1330 // dans la langue du JDD.
1331 auto ilang = m_lang_module_factory_map.find(name);
1333 name = ilang->second->moduleName();
1334
1335 auto it = m_module_state_list.find(name);
1336 if (it == m_module_state_list.end())
1337 // Lève une exception si le nom du module spécifié dans le JDD
1338 // ne correspond à aucun module enregistré.
1339 ARCANE_FATAL("Error in configuring active modules: no module named '{0}' is registered.",
1340 name);
1341
1342 ModuleState& ms = it->second;
1343 ms.m_is_active = active;
1344 if (!alias.null())
1345 ms.m_alias = alias;
1346
1347 if (!ms.m_is_optional && !ms.m_is_active) {
1348 pwarning() << "The module \"" << ms.m_alias
1349 << "\" can't be declared mandatory in the time loop"
1350 << " while being inactive in the input data."
1351 << " It's activity is therefore forced. ";
1352 ms.m_is_active = true;
1353 }
1354 }
1355}
1356
1357/*---------------------------------------------------------------------------*/
1358/*---------------------------------------------------------------------------*/
1359
1364{
1365 std::string std_timeloop_call_name(timeloop_call_name.localstr());
1366 size_t index = std_timeloop_call_name.find_first_of('.');
1367 if (index==std::string::npos){
1368 ARCANE_FATAL("The string '{0}' is not a valid reference to an entry point (has to be of type "
1369 "'module_name.entry_point_name)",timeloop_call_name);
1370 }
1371 std::string std_module_name = std_timeloop_call_name.substr(0, index);
1372 std::string std_entry_point_name = std_timeloop_call_name.substr(index+1);
1375}
1376
1377/*---------------------------------------------------------------------------*/
1378/*---------------------------------------------------------------------------*/
1384{
1385 String lang;
1386 ICaseDocumentFragment* doc = m_sub_domain->caseMng()->caseDocumentFragment();
1387 if (doc)
1388 lang = doc->language();
1389 ModuleFactoryInfoCollection module_factories(subDomain()->application()->moduleFactoryInfos());
1390 m_module_factory_map.clear();
1393 IModuleFactoryInfo* mfi = *i;
1394
1395 const String& module_name = mfi->moduleName();
1397 ARCANE_FATAL("Two modules with same name '{0}'",module_name);
1398 m_module_factory_map.insert(std::make_pair(module_name,mfi));
1399 info(5) << "Registering module in factory map name=" << module_name;
1400
1401 if (!lang.null()){
1402 const IServiceInfo* si = mfi->serviceInfo();
1403 String translated_name = si->tagName(lang);
1405 // Envoie juste un avertissement car cela ne posera pas forcément problème.
1406 warning() << "Two modules with same translated name=" << translated_name
1407 << " ignoring name=" << module_name;
1408 }
1409 else{
1410 m_lang_module_factory_map.insert(std::make_pair(translated_name,mfi));
1411 info(5) << "Registering module in lang factory map name=" << translated_name;
1412 }
1413 }
1414 }
1415}
1416
1417/*---------------------------------------------------------------------------*/
1418/*---------------------------------------------------------------------------*/
1419
1422{
1423 auto x = m_module_factory_map.find(module_name);
1424 if (x!=m_module_factory_map.end()){
1425 IModuleFactoryInfo* mfi = x->second;
1426 Ref<IModule> module = mfi->createModule(m_sub_domain,m_sub_domain->defaultMeshHandle());
1427 if (module.get()){
1428 info() << "Loading module " << module->name()
1429 << " (Version " << module->versionInfo() << ")";
1430 return true;
1431 }
1432 }
1433 return false;
1434}
1435
1436/*---------------------------------------------------------------------------*/
1437/*---------------------------------------------------------------------------*/
1443{
1444 log() << "Adding the entry point `" << entry_point->module()->name() << "::" << entry_point->name() << "' to the execution";
1445
1446 String where = entry_point->where();
1449 }
1450 else if (where==IEntryPoint::WBuild){
1452 }
1453 else if (where==IEntryPoint::WExit){
1455 }
1456 else if (where == IEntryPoint::WRestore){
1458 }
1459 else if (where == IEntryPoint::WOnMeshChanged){
1461 }
1462 else if (where == IEntryPoint::WOnMeshRefinement){
1464 }
1465 else if (IEntryPoint::WComputeLoop){
1468 }
1470
1471 // Puisque le module a un point d'entrée utilisé, il est activé.
1472 IModule* c = entry_point->module();
1473 c->setUsed(true);
1474 {
1475 if (std::find(m_list_execute_module.begin(),m_list_execute_module.end(),c)==m_list_execute_module.end()){
1476 debug() << "Adding the module `" << c->name() << "' to the execution";
1478 }
1479 }
1480}
1481
1482/*---------------------------------------------------------------------------*/
1483/*---------------------------------------------------------------------------*/
1484
1485void TimeLoopMng::
1486_dumpTimeInfos(JSONWriter& json_writer)
1487{
1489
1491
1493
1494 {
1495 Real total_real_time = 0.0;
1496 Real compute_real_time = 0.0;
1497 json_writer.writeKey("EntryPoints");
1498 json_writer.beginArray();
1500 IEntryPoint* ep = *i;
1501 Real s2 = ep->totalElapsedTime();
1502 {
1504 json_writer.write("Name",ep->name());
1505 json_writer.write("TotalCpuTime",s2);
1506 json_writer.write("TotalElapsedTime",s2);
1507 json_writer.write("NbCall",(Int64)ep->nbCall());
1508 json_writer.write("Where",ep->where());
1509 }
1510 info(5) << "CPU_TIME where=" << ep->where() << " name=" << ep->name() << " S=" << s2;
1511 total_real_time += s2;
1512 if (ep->where()==IEntryPoint::WComputeLoop){
1513 compute_real_time += s2;
1514 }
1515 }
1516 json_writer.endArray();
1517 info(4) << "TOTAL_REAL_TIME COMPUTE=" << compute_real_time << " TOTAL=" << total_real_time;
1518 }
1519
1520
1521 const CommonVariables& scv = subDomain()->commonVariables();
1522 info() << "Information on the execution time";
1523 {
1524 Accelerator::IAcceleratorMng* acc_mng = m_sub_domain->acceleratorMng();
1525 if (acc_mng->isInitialized()){
1526 Accelerator::Runner* runner = acc_mng->defaultRunner();
1527 info() << " TotalRunner (" << runner->executionPolicy() << ") = "
1528 << runner->cumulativeCommandTime() << " seconds";
1529 }
1530 }
1531 info() << " TotalElapsed = " << total_exec_time << " seconds";
1532 info() << " CumulativeElapsed = " << scv.globalElapsedTime()
1533 << " seconds (" << platform::timeToHourMinuteSecond(scv.globalElapsedTime()) << ")";
1534 info() << " T = Total time spent in the function or in the module (s)";
1535 info() << " TC = Total time spend per call (ms)";
1536 info() << " TCC = Total time spent per call and per cell (ns)";
1537 info() << " N = Number of time the function was called";
1538
1539 info() << " Use the clock time (elapsed) for the statistics";
1540
1541 std::ostringstream o;
1542 std::ios_base::fmtflags f = o.flags(std::ios::right);
1543 Integer nb_cell = 0;
1544 IMesh * mesh = subDomain()->defaultMesh();
1545 if (mesh)
1546 nb_cell = mesh->nbCell();
1547 if (nb_cell == 0)
1548 nb_cell = 1;
1549
1550 o << "\n Name T TC TCC % N\n";
1551
1552 for (ModuleCollection::Enumerator j(module_mng->modules()); ++j; ){
1553 IModule * module = * j;
1554 Real total_time_module = 0.;
1555 Real total_time_module_entry_point = 0.;
1556 for (EntryPointCollection::Enumerator i(entry_points); ++i; ){
1557 IEntryPoint * ic = * i;
1558 if (ic->module()!=module)
1559 continue;
1560 Integer nb_call = ic->nbCall();
1561 if (nb_call==0)
1562 continue;
1563 Real total_time = ic->totalElapsedTime();
1564 //if (math::isZero(total_time))
1565 //continue;
1566 const String& ep_name = ic->name();
1567 {
1568 Int64 l = ep_name.length();
1569 if (l > 36){
1570 o.write(ep_name.localstr(), 34);
1571 o << "...";
1572 }
1573 else{
1574 o.width(37);
1575 o << ep_name;
1576 }
1577 }
1578 o.width(10);
1579 Int64 z = Convert::toInt64(total_time);
1580 o << z;
1581 Real r = (1e3 * total_time) / nb_call;
1582 if (ic->where() == IEntryPoint::WComputeLoop){
1583 total_time_module += r;
1584 total_time_module_entry_point += total_time;
1585 }
1586 z = Convert::toInt64(r);
1587 o.width(10);
1588 o << z;
1589 r = (r * 1e6) / nb_cell;
1590 z = Convert::toInt64(r);
1591 o.width(10);
1592 o << z;
1593 //Probleme sur certaine machine : total_exec_time = 0
1594 if (total_exec_time>0)
1595 z = Convert::toInt64((100.0 * total_time) / total_exec_time);
1596 else
1597 z = Convert::toInt64((100.0 * total_time)) ;
1598 o.width(5);
1599 o << z;
1600 o.width(12);
1601 o << nb_call;
1602 o << '\n';
1603 }
1604 o << "--";
1605 o.width(33);
1606 o << module->name();
1607 o << "--";
1608 o.width(10);
1609 Int64 z = Convert::toInt64(total_time_module_entry_point * 1e-3);
1610 o << z;
1611 o.width(10);
1612 z = Convert::toInt64(total_time_module);
1613 o << z;
1614 Real r = (total_time_module * 1e6) / nb_cell;
1615 z = Convert::toInt64(r);
1616 o.width(10);
1617 o << z;
1618 o << '\n';
1619 }
1620 o.flags(f);
1621
1622 info() << o.str();
1623
1624 {
1625 IParallelMng* pm = m_sub_domain->parallelMng();
1626 if (pm->isParallel()){
1627 JSONWriter::Object jo(json_writer,"MessagePassingStats");
1628 Parallel::IStat* s = pm->stat();
1629 if (s){
1630 s->printCollective(pm);
1631 s->dumpJSON(json_writer);
1632 }
1633 }
1634 }
1635 {
1636 JSONWriter::Object jo(json_writer,"VariablesStats");
1637 m_sub_domain->variableMng()->dumpStatsJSON(json_writer);
1638 }
1639 {
1640 JSONWriter::Object jo(json_writer,"TimeStats");
1641 m_sub_domain->timeStats()->dumpStatsJSON(json_writer);
1642 }
1643 {
1644 IProfilingService* ps = platform::getProfilingService();
1645 if (ps){
1646 JSONWriter::Object jo(json_writer,"Profiling");
1647 ps->dumpJSON(json_writer);
1648 }
1649 }
1650
1651 Item::dumpStats(traceMng());
1652}
1653
1654/*---------------------------------------------------------------------------*/
1655/*---------------------------------------------------------------------------*/
1656
1658cpuTimeUsed() const
1659{
1661 Real total_elapsed_time = 0.0;
1663 Real s1 = (*i)->totalElapsedTime();
1665 }
1666 return total_elapsed_time;
1667}
1668
1669/*---------------------------------------------------------------------------*/
1670/*---------------------------------------------------------------------------*/
1671
1674{
1675 if (!m_backward_mng)
1676 _createOwnDefaultBackwardMng();
1677 return m_backward_mng->isLocked();
1678}
1679
1680/*---------------------------------------------------------------------------*/
1681/*---------------------------------------------------------------------------*/
1682
1684goBackward()
1685{
1686 ITraceMng * msg = traceMng();
1687 Trace::Setter mci(msg,m_message_class_name);
1688
1689 if (!m_backward_mng)
1690 _createOwnDefaultBackwardMng();
1691
1693}
1694
1695/*---------------------------------------------------------------------------*/
1696/*---------------------------------------------------------------------------*/
1697
1700{
1701 for( ConstIterT<TimeLoopMap> i(m_time_loop_list); i(); ++i)
1702 names.add(i->first);
1703}
1704
1705/*---------------------------------------------------------------------------*/
1706/*---------------------------------------------------------------------------*/
1707
1710{
1711 for( ConstIterT<TimeLoopMap> i(m_time_loop_list); i(); ++i)
1712 time_loops.add(i->second);
1713}
1714
1715/*---------------------------------------------------------------------------*/
1716/*---------------------------------------------------------------------------*/
1717
1719createTimeLoop(const String& name)
1720{
1722 return sm->mainFactory()->createTimeLoop(sm, name);
1723}
1724
1725/*---------------------------------------------------------------------------*/
1726/*---------------------------------------------------------------------------*/
1727
1730{
1731 m_stop_reason = reason;
1732}
1733
1734/*---------------------------------------------------------------------------*/
1735/*---------------------------------------------------------------------------*/
1736
1739{
1740 m_stop_time_loop = true;
1741 m_stop_has_error = has_error;
1742 if (is_final_time)
1743 m_final_time_reached = true;
1744 if (has_error)
1745 m_stop_reason = eTimeLoopStopReason::Error;
1746 else if (is_final_time)
1748 // Si \a m_stop_reason n'est pas encore spécifié, indique qu'il n'y a pas
1749 // de raison spéciale
1750 if (m_stop_reason==eTimeLoopStopReason::NoStop)
1751 m_stop_reason = eTimeLoopStopReason::NoReason;
1752}
1753
1754/*---------------------------------------------------------------------------*/
1755/*---------------------------------------------------------------------------*/
1756
1759{
1760 if (!m_backward_mng)
1761 _createOwnDefaultBackwardMng();
1762
1764 info() << "Repartioning required but inactive due to a backward process active";
1765 return;
1766 }
1767 m_mesh_partitioner.add(mesh_partitioner);
1768}
1769
1770/*---------------------------------------------------------------------------*/
1771/*---------------------------------------------------------------------------*/
1772
1774doComputeLoop(Integer max_loop)
1775{
1776 m_nb_loop = 0;
1777 bool is_end = false;
1778 bool is_end_by_max_loop = false;
1779 int ret_val = 0;
1780 //m_alarm_timer_value = 0;
1781 //pwarning() << "Force le alarm_timer_value a zéro";
1782 if (m_alarm_timer_value>0){
1783 info() << "Set the timeout before alarm at " << m_alarm_timer_value << " seconds";
1784 }
1785
1786 // Allocation d'un gestionnaire de retour-arrière par défaut
1787 if (!m_backward_mng)
1788 _createOwnDefaultBackwardMng();
1789
1791 bool want_specific_profiling = false;
1792 // Regarde si on demande un profiling spécifique. Dans ce cas,
1793 // les modules et services gèrent eux même le profiling et donc
1794 // on ne démarre pas automatiquement le profiling au début de la
1795 // boucle de calcul
1796 if (!platform::getEnvironmentVariable("ARCANE_SPECIFIC_PROFILING").null()){
1797 info() << "Specific profiling activated";
1799 }
1800
1801 {
1802 // NOTE: arcaneGlobalMemoryInfo() peut changer au cours du calcul
1803 // donc il faut le récupérer à chaque fois qu'on en a besoin.
1804 IMemoryInfo* mem_info = arcaneGlobalMemoryInfo();
1805 String s = platform::getEnvironmentVariable("ARCANE_CHECK_MEMORY_BLOCK_SIZE_ITERATION");
1806 if (!s.null()){
1807 Int64 block_size = 0;
1808 bool is_bad = builtInGetValue(block_size,s);
1809 if (!is_bad && block_size>2){
1810 info() << "Set Memory StackTraceMinAllocSize to " << block_size;
1811 mem_info->setStackTraceMinAllocSize(block_size);
1812 }
1813 }
1814 }
1815
1816 // Demarrage du profiling de message passing le cas echeant
1817 if (m_msg_pass_prof_srv.get())
1818 m_msg_pass_prof_srv->startProfiling();
1819
1820 try{
1821 if (ps){
1822 if (!ps->isInitialized())
1823 ps->initialize();
1824 ps->reset();
1825 }
1826 Item::resetStats();
1827 // Désactive le profiling si demande spécifique
1829 ps = nullptr;
1832 _callSpecificEntryPoint();
1833 is_end = true;
1834 }
1835 while (!is_end){
1836 if (max_loop!=0 && m_nb_loop>=max_loop){
1837 info()<<"===================================================";
1838 info()<<"====== MAXIMUM NUMBER OF ITERATION REACHED =======";
1839 info()<<"===================================================";
1840 is_end_by_max_loop = true;
1842 stopComputeLoop(false,false);
1843 break;
1844 }
1845 // Indique qu'on va s'arrêter par nombre max d'itération
1846 if (max_loop!=0 && (1+m_nb_loop)>=max_loop){
1848 }
1850 IMemoryInfo* mem_info = arcaneGlobalMemoryInfo();
1851 if (mem_info && mem_info->isCollecting()){
1852 mem_info->endCollect();
1853 Integer iteration = subDomain()->commonVariables().globalIteration();
1854 mem_info->setIteration(iteration);
1855
1856 std::ostringstream ostr;
1857 if (iteration>0)
1858 mem_info->printAllocatedMemory(ostr,iteration-1);
1859 if (iteration>1)
1860 mem_info->printAllocatedMemory(ostr,iteration-2);
1861 if (iteration>4)
1862 mem_info->printAllocatedMemory(ostr,iteration-5);
1863 info() << "ITERATION_MemoryInfo: " << ostr.str();
1864 mem_info->beginCollect();
1865 }
1866 subDomain()->variableMng()->synchronizerMng()->flushPendingStats();
1867 if (ret_val!=0)
1868 is_end = true;
1869 ++m_nb_loop;
1870 }
1871 }
1872 catch (const TimeoutException& ex){
1873 if (m_msg_pass_prof_srv.get())
1874 m_msg_pass_prof_srv->stopProfiling();
1876 pinfo() << "TIMEOUT " << Trace::Width(8) << pm->commRank() << "_RANK Infos:"<<ex.additionalInfo();
1877 traceMng()->flush();
1878 // Attend que tous les processeurs envoient le signal et affichent le
1879 // message précédent
1880 platform::sleep(40);
1881 throw;
1882 }
1883 if (m_verification_only_at_exit){
1884 info() << "Doing verification at exit";
1885 doVerification("AtExit");
1886 }
1887 {
1889 if (ps2)
1890 ps2->printInfos(true);
1891 }
1892 if (m_msg_pass_prof_srv.get())
1893 m_msg_pass_prof_srv->stopProfiling();
1894 if (IItemEnumeratorTracer::singleton())
1895 IItemEnumeratorTracer::singleton()->dumpStats();
1896 info() << "End of compute loop: reason=" << (int)m_stop_reason;
1898 return 2;
1899 if (m_final_time_reached)
1900 return 1;
1901 if (ret_val<0){
1902 return ret_val;
1903 }
1904 return 0;
1905}
1906
1907/*---------------------------------------------------------------------------*/
1908/*---------------------------------------------------------------------------*/
1909
1910void TimeLoopMng::
1911_resetTimer() const
1912{
1913 if (m_alarm_timer_value>0)
1914 platform::resetAlarmTimer(m_alarm_timer_value);
1915}
1916
1917/*---------------------------------------------------------------------------*/
1918/*---------------------------------------------------------------------------*/
1919
1920} // End namespace Arcane
1921
1922/*---------------------------------------------------------------------------*/
1923/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
void clear()
Supprime tous les éléments de la collection.
Definition Collection.h:68
Integer count() const
Nombre d'éléments de la collection.
Definition Collection.h:70
EnumeratorT< IModule * > Enumerator
Type d'un itérateur sur toute la collection.
Definition Collection.h:129
Exception pour demander un retour-arrière de la boucle en temps.
Interface de l'application.
Interface gérant les stratégies de retour-arrière.
virtual void init()=0
Initialisation du manager de retour en arrière.
virtual void clear()=0
Supprime les ressources associées au retour-arrière.
virtual bool checkAndApplySave(bool is_forced)=0
Vérifie et applique la sauvegarde des variables si nécessaire. Si is_forced est vrai,...
virtual void endAction()=0
Indique que les actions de sauvegarde/restauration sont terminées.
virtual void goBackward()=0
Signale qu'on souhaite effectué un retour arrière.
virtual bool isLocked() const =0
Indique si les sauvegardes de retour-arrière sont vérouillées.
virtual bool isBackwardEnabled() const =0
Indique si un retour-arrière est programmé.
virtual void beginAction()=0
Indique qu'on commence les actions de sauvegarde/restauration sont terminées.
virtual bool checkAndApplyRestore()=0
Vérifie et applique la restauration si nécessaire.
virtual ITraceMng * traceMng() const =0
Gestionnaire de traces.
Interface d'une partie d'un jeu de données.
Interface d'une classe gérant un document XML du jeu de données.
Interface d'une fonction du jeu de données.
virtual void value(Real param, Real &v) const =0
Valeur v de l'option pour le paramètre param.
Interface du gestionnaire de cas.
Definition ICaseMng.h:56
Interface d'une liste d'options du jeu de données.
Interface du gestionnaire de point d'entrée.
virtual IEntryPoint * findEntryPoint(const String &s)=0
Point d'entrée de nom s.
virtual EntryPointCollection entryPoints()=0
Liste des points d'entrées.
Interface d'un point d'entrée d'un module.
Definition IEntryPoint.h:34
static const char *const WComputeLoop
appelé pendant la boucle de calcul
Definition IEntryPoint.h:42
static const char *const WBuild
appelé pour la construction du module
Definition IEntryPoint.h:44
@ PAutoLoadEnd
Chargé automatiquement à la fin. Cela signifie qu'un module possédant un point d'entrée avec cette pr...
Definition IEntryPoint.h:80
@ PAutoLoadBegin
Chargé automatiquement au début. Cela signifie qu'un module possédant un point d'entrée avec cette pr...
Definition IEntryPoint.h:73
static const char *const WStartInit
appelé pendant l'initialisation d'un nouveau cas
Definition IEntryPoint.h:50
static const char *const WRestore
appelé pour restaurer les variables lors d'un retour arrière
Definition IEntryPoint.h:52
static const char *const WOnMeshRefinement
appelé après un raffinement de maillage
Definition IEntryPoint.h:56
static const char *const WOnMeshChanged
appelé après un changement de maillage
Definition IEntryPoint.h:54
static const char *const WContinueInit
appelé pendant l'initialisation d'une reprise
Definition IEntryPoint.h:48
virtual String where() const =0
Retourne l'endroit ou est appelé le point d'entrée.
static const char *const WInit
appelé pendant l'initialisation
Definition IEntryPoint.h:46
virtual String name() const =0
Retourne le nom du point d'entrée.
Interface d'une famille d'entités.
Interface d'un collecteur d'informations sur l'usage mémoire.
Definition IMemoryInfo.h:60
virtual String name() const =0
Nom du maillage.
virtual IItemFamily * cellFamily()=0
Retourne la famille des mailles.
Interface d'un partitionneur de maillage.
virtual IMeshUtilities * utilities()=0
Interface des fonctions utilitaires associée.
Informations sur la fabrique d'un module.
Interface du gestionnaire de modules.
Definition IModuleMng.h:39
virtual ModuleCollection modules() const =0
Liste des modules.
Interface d'un module.
Definition IModule.h:39
Interface d'un observable.
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual Int32 commRank() const =0
Rang de cette instance dans le communicateur.
virtual IParallelReplication * replication() const =0
Informations sur la réplication.
virtual IStat * stat()=0
Gestionnaire des statistiques.
virtual bool isParallel() const =0
Retourne true si l'exécution est parallèle.
Interface d'un service de profiling.
Interface des informations d'un service ou d'un module.
Interface de chargement des services.
virtual bool loadSingletonService(ISubDomain *sd, const String &name)=0
Charge le service singleton de sous-domaine de nom name.
Interface du gestionnaire d'un sous-domaine.
Definition ISubDomain.h:74
virtual IModuleMng * moduleMng()=0
Retourne le gestionnaire de modules.
virtual const CommonVariables & commonVariables() const =0
Informations sur les variables standards.
virtual IMesh * defaultMesh()=0
Maillage par défaut.
virtual ITimeStats * timeStats() const =0
Statistiques des temps d'exécution.
virtual IApplication * application()=0
Application.
virtual IParallelMng * parallelMng()=0
Retourne le gestionnaire de parallélisme.
virtual IVariableMng * variableMng()=0
Retourne le gestionnaire de variables.
virtual ICaseMng * caseMng()=0
Retourne le gestionnaire du jeu de données.
virtual IAcceleratorMng * acceleratorMng()=0
Gestionnaire de l'accélérateur associé
Interface du gestionnaire de la boucle en temps.
Interface d'une boucle en temps.
Definition ITimeLoop.h:41
static const char * WRestore
appelé pour restaurer les variables lors d'un retour arrière
Definition ITimeLoop.h:54
virtual TimeLoopEntryPointInfoCollection entryPoints(const String &where) const =0
Liste des noms des points d'entrée pour le point d'appel where.
static const char * WOnMeshChanged
appelé après un changement de maillage
Definition ITimeLoop.h:56
static const char * WExit
appelé lors de la terminaison du code.
Definition ITimeLoop.h:60
virtual IConfiguration * configuration()=0
Options de configuration.
virtual TimeLoopSingletonServiceInfoCollection singletonServices() const =0
Liste services singletons.
static const char * WOnMeshRefinement
appelé après un raffinement de maillage
Definition ITimeLoop.h:58
static const char * WBuild
appelé lors de la lecture du jeu de données
Definition ITimeLoop.h:50
static const char * WComputeLoop
appelé pendant la boucle de calcul
Definition ITimeLoop.h:48
static const char * WInit
appelé pendant l'initialisation, l'initialisation d'une reprise ou d'un nouveau cas
Definition ITimeLoop.h:52
virtual String name() const =0
Nom de la boucle en temps.
Interface d'un service de synchronisation de variable.
@ PNoReplicaSync
Indique que la variable n'a pas forcément la même valeur entre les réplicas.
Definition IVariable.h:159
@ PNoNeedSync
Indique que la variable n'est pas nécessairement synchronisée.
Definition IVariable.h:80
Ecrivain au format JSON.
Definition JSONWriter.h:33
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
Flot de sortie lié à une String.
Classe permettant de démarrer et arrêter automatiquement un service.
Infos d'un point d'entrée d'une boucle en temps.
Gestionnaire de la boucle en temps.
bool finalTimeReached() const override
Retourne true si le temps final est atteint.
IObservable * observable(eTimeLoopEventType type) override
Observable sur l'instance.
ModuleFactoryMap m_module_factory_map
Etat de tous les modules référencés.
std::map< String, ITimeLoop * > TimeLoopMap
Liste de boucles en temps.
TimeLoopMap m_time_loop_list
Liste des boucles en temps.
void registerActionMeshPartition(IMeshPartitionerBase *mesh_partitioner) override
Programme un repartitionnement du maillage avec l'outil de partition mesh_partitioner.
EntryPointCollection usedTimeLoopEntryPoints() override
Liste de tous les points d'entrée pour la boucle en temps actuelle.
void _processEntryPoints(EntryPointList &entry_points, const TimeLoopEntryPointInfoCollection &entry_points_info, const char *where)
Ajoute à la liste entry_points les points d'entrée proposés dans entry_points_info.
@ VerifSameReplica
Vérifie que les variables sont synchronisées.
@ VerifWrite
Indique qu'on génère des valeurs pour vérifier.
@ VerifNone
Indique qu'on ne fait pas de vérifications.
@ VerifRead
Indique qu'on relit et vérifie des valeurs.
ITimeLoop * createTimeLoop(const String &name) override
Crée une boucle en temps de nom name.
EntryPointList m_exit_entry_points
Liste des points d'entrée à exécuter à la terminaison.
EntryPointCollection loopEntryPoints() override
Retourne la liste des points d'entrée de type 'ComputeLoop' de la boucle en temps.
ITimeLoop * usedTimeLoop() const override
Retourne la boucle en temps utilisée.
EntryPointList m_on_mesh_changed_entry_points
Liste des points d'entrée à exécuter après un changement de maillage.
std::map< String, ModuleState > ModuleStateMap
Liste des états des modules.
ITimeLoop * m_default_time_loop
Boucle en temps par défaut.
void doVerification(const String &name) override
Effectue une vérification.
void stopComputeLoop(bool is_final_time, bool has_error) override
Indique que la boucle de calcul doit s'interrompre.
void execInitEntryPoints(bool is_continue) override
Exécute les points d'entrée d'initialisation.
IEntryPoint * nextEntryPoint() override
Retourne la fonction suivante à appeler.
bool _createModule(const String &module_name)
Crée un module à partir de son nom.
eTimeLoopStopReason stopReason() const override
Raison pour laquelle on arrête le code.
void doExecNextEntryPoint(bool &is_last) override
void execExitEntryPoints() override
Exécute les points d'entrée de terminaison.
static void _extractModuleAndEntryPointName(const String &timeloop_call_name, String &module_name, String &entry_point_name)
EntryPointList m_build_entry_points
Liste des points d'entrée à exécuter lors de la construction.
EntryPointList m_used_time_loop_entry_points
Liste de tous les points d'entrée de la boucle en temps utilisée.
Integer m_current_entry_point
Prochain point d'entrée à exécuter.
int doOneIteration() override
Lance l'exécution d'une itération de la boucle de calcul.
void execOnMeshRefinementEntryPoints() override
Exécute les points d'entrée après raffinement.
ISubDomain * subDomain() const override
< Retourne le gestionnaire du sous-domaine
bool m_verification_at_entry_point
Si vrai, effectue vérifications à chaque point d'entrée, sinon uniquement en fin d'itération.
void timeLoops(TimeLoopCollection &time_loops) const override
Retourne dans time_loops la liste des boucles en temps.
EntryPointList m_restore_entry_points
Liste des points d'entrée à exécuter lors d'un retour arrière.
EntryPointList m_on_mesh_refinement_entry_points
Liste des points d'entrée à exécuter après un raffinement.
ISubDomain * m_sub_domain
Gestionnaire du sous-domaine.
ModuleFactoryMap m_lang_module_factory_map
Liste des fabriques des modules.
Integer nbLoop() const override
Nombre de boucles de calcul (ComputeLoop) effectuées.
bool isDoingBackward() override
Vrai si on est actuellement dans un retour-arrière.
int doComputeLoop(Integer max_loop) override
Exécute la boucle de calcul.
void timeLoopsName(StringCollection &names) const override
Retourne dans names la liste des noms des boucles en temps.
void goBackward() override
Effectue un retour arrière.
void setStopReason(eTimeLoopStopReason reason) override
Positionne la raison pour laquelle on arrête le code.
EntryPointList m_loop_entry_points
Liste des points d'entrée à exécuter.
IEntryPointMng * m_entry_point_mng
Gestionnaire de points d'entrée.
EntryPointList m_init_entry_points
Liste des points d'entrée à exécuter à l'initialisation.
String m_specific_entry_point_name
Pour test, point d'entrée spécifique à appeler.
ModuleList m_list_execute_module
Liste des modules à éxécuter.
Real cpuTimeUsed() const override
Retourne le temps CPU utilisé en secondes.
void execBuildEntryPoints() override
Exécute les points d'entrée de construction.
void setBackwardSavePeriod(Integer n) override
Positionne la période entre deux sauvegarde pour le retour arrière. Si cette valeur est nulle,...
IEntryPoint * m_current_entry_point_ptr
Point d'entrée en cours d'exécution.
IBackwardMng * m_backward_mng
Gestionnaire du retour-arrière;.
ITimeLoop * m_used_time_loop
Boucle en temps utilisée.
void setUsedTimeLoop(const String &name) override
Positionne la boucle en temps à exécuter. Sélectionne la boucle en temps de nom name comme celle qui ...
eVerifType m_verif_type
Type de vérifications.
void _fillModuleStateMap(ITimeLoop *time_loop)
void _doMeshPartition()
Effectue un repartitionnement des maillages.
std::map< String, IModuleFactoryInfo * > ModuleFactoryMap
Liste des fabriques des modules indéxés par leur nom.
void execOnMeshChangedEntryPoints() override
Exécute les points d'entrée après rééquilibrage.
void _addExecuteEntryPoint(IEntryPoint *)
Ajoute un point d'entrée à exécuter.
IEntryPoint * currentEntryPoint() override
Retourne le point d'entrée en cours d'exécution ou 0 s'il n'y en a pas.
void _fillModuleFactoryMap()
Remplit m_module_factory_map avec la liste des fabriques disponibles.
void registerTimeLoop(ITimeLoop *timeloop) override
Enregistrement et choix de la boucle en temps.
Ref< IVerifierService > m_verifier_service
Liste des fabriques des modules dans la langue du JDD.
String m_verif_path
Répertoire de sauvegarde/lecture des verifs.
void setVerificationActive(bool is_active) override
Positionne l'état du mode de vérification.
Infos d'un service singleton d'une boucle en temps.
Postionne le nom de l'action en cours d'exécution.
Definition Timer.h:110
Sentinelle pour le timer. La sentinelle associée à un timer permet de déclancher celui-ci au moment d...
Definition Timer.h:89
Gestion d'un timer.
Definition Timer.h:62
@ TimerReal
Timer utilisant le temps réel.
Definition Timer.h:76
Noeud d'un arbre DOM.
Definition XmlNode.h:51
Interface du gestionnaire de traces.
virtual void flush()=0
Flush tous les flots.
virtual TraceMessage plog()=0
Flot pour un message de log parallèle.
Constructeur de chaîne de caractère unicode.
Chaîne de caractères unicode.
bool null() const
Retourne true si la chaîne est nulle.
Definition String.cc:304
TraceMessage pwarning() const
TraceMessage log() const
Flot pour un message de log.
TraceMessage pinfo() const
Flot pour un message d'information en parallèle.
TraceMessage plog() const
Flot pour un message de log.
TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium) const
Flot pour un message de debug.
TraceMessage warning() const
Flot pour un message d'avertissement.
TraceMessage info() const
Flot pour un message d'information.
TraceMessage logdate() const
Flot pour un message de log précédé de la date.
Positionne une classe de message.
Formattage du flot en longueur.
Int64 toInt64(Real r)
Converti un Real en Int64.
Definition Convert.h:62
IProfilingService * getProfilingService()
Service utilisé pour obtenir pour obtenir des informations de profiling.
void resetAlarmTimer(Integer nb_second)
Remet à timer d'alarme à nb_second.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
@ SB_AllowNull
Autorise l'absence du service.
eTimeLoopStopReason
Raison pour laquelle on arrête le code.
@ MaxIterationReached
Arrêt car nombre d'itération maximal spécifié atteint.
@ NoStop
Indique qu'on n'est pas encore en mode d'arrête du code.
@ FinalTimeReached
Arrêt car temps final atteint.
@ NoReason
Pas de raison spécifique.
@ Error
Arrêt sur une erreur.
@ DT_String
Donnée de type chaîne de caractère UTF-8.
Definition DataTypes.h:45
Int32 Integer
Type représentant un entier.