14#include "arcane/utils/ArrayView.h"
15#include "arcane/utils/Deleter.h"
16#include "arcane/utils/FatalErrorException.h"
17#include "arcane/utils/NameComparer.h"
18#include "arcane/utils/OStringStream.h"
19#include "arcane/utils/PlatformUtils.h"
20#include "arcane/utils/StringBuilder.h"
21#include "arcane/utils/TraceInfo.h"
22#include "arcane/utils/JSONWriter.h"
23#include "arcane/utils/Exception.h"
25#include "arcane/Timer.h"
26#include "arcane/IParallelMng.h"
27#include "arcane/ITimerMng.h"
28#include "arcane/MathUtils.h"
29#include "arcane/Properties.h"
31#include "arcane/impl/TimeStats.h"
33#include "arccore/trace/ITimeMetricCollector.h"
34#include "arccore/trace/TimeMetric.h"
47extern "C++" ITimeStats*
48arcaneCreateTimeStats(ITimerMng* timer_mng, ITraceMng* trace_mng,
const String& name)
50 return new TimeStats(timer_mng, trace_mng, name);
72 auto name = handle.name();
74 m_time_stats->beginAction(name);
75 int phase = handle.phase();
77 m_time_stats->beginPhase(
static_cast<eTimePhase>(phase));
83 int phase = action.phase();
85 m_time_stats->endPhase(
static_cast<eTimePhase>(phase));
86 auto name = action.name();
88 m_time_stats->endAction(name,
false);
93 std::atomic<Int64> m_id;
114 Int64 m_nb_iteration_loop = 0;
118 o <<
"NbLoop=" << x.m_nb_iteration_loop <<
"\n";
119 o <<
"Name=" << x.m_name_list <<
"\n";
120 o <<
"NbCall=" << x.m_nb_call_list <<
"\n";
121 o <<
"NbChild=" << x.m_nb_child <<
"\n";
122 o <<
"Time=" << x.m_time_list <<
"\n";
128 m_nb_iteration_loop = 0;
131 m_nb_call_list.clear();
143 Action* parent()
const {
return m_parent; }
145 Action* findOrCreateSubAction(
const String& name);
146 void addPhaseValue(
const PhaseValue& new_pv);
148 Action* findSubActionRecursive(
const String& action_name)
const;
149 void save(AllActionsInfo& save_info)
const;
150 void merge(AllActionsInfo& save_info,Integer* index);
151 void dumpJSON(JSONWriter& writer,eTimeType tt);
152 void computeCumulativeTimes();
153 void dumpCurrentStats(std::ostream& ostr,
int level,
Real unit);
181 : m_main_action(
nullptr,
"Main")
186 : m_main_action(
nullptr,
"Main")
198 Action* mainAction() {
return &m_main_action; }
199 Int64 nbIterationLoop()
const {
return m_nb_iteration_loop; }
200 void save(AllActionsInfo& all_actions_info)
const
202 all_actions_info.clear();
203 m_main_action.save(all_actions_info);
204 all_actions_info.m_nb_iteration_loop = m_nb_iteration_loop;
206 void merge(AllActionsInfo& all_actions_info)
208 m_nb_iteration_loop += all_actions_info.m_nb_iteration_loop;
210 m_main_action.merge(all_actions_info,&index);
211 m_main_action.computeCumulativeTimes();
213 void dumpStats(std::ostream& ostr,
bool is_verbose,
Real nb,
const String& name,
214 bool use_elapsed_time,
const String& message);
217 Action m_main_action;
218 Int64 m_nb_iteration_loop = 0;
221 void _dumpStats(std::ostream& ostr,Action& action,eTimeType tt,
int level,
int max_level,
Real nb);
222 void _dumpAllPhases(std::ostream& ostr,Action& action,eTimeType tt,
int tc,
Real nb);
223 void _dumpCurrentStats(std::ostream& ostr,Action& action,
int level,
Real unit);
233TimeStats(ITimerMng* timer_mng, ITraceMng* trace_mng,
const String& name)
234: TraceAccessor(trace_mng)
235, m_timer_mng(timer_mng)
236, m_virtual_timer(nullptr)
237, m_real_timer(nullptr)
238, m_is_gathering(false)
239, m_current_action_series(new ActionSeries())
240, m_previous_action_series(new ActionSeries())
241, m_main_action(m_current_action_series->mainAction())
242, m_current_action(m_main_action)
243, m_need_compute_elapsed_time(true)
246, m_metric_collector(new MetricCollector(this))
248 m_phases_type.push(TP_Computation);
249 if (platform::getEnvironmentVariable(
"ARCANE_FULLSTATS") ==
"TRUE")
259 delete m_metric_collector;
262 delete m_virtual_timer;
277 if (!m_virtual_timer)
282 m_is_gathering =
true;
286 m_virtual_timer->
start();
287 m_real_timer->
start();
288 m_full_stats_str <<
"<? xml version='1.0'?>\n";
289 m_full_stats_str <<
"<stats>\n";
298 m_virtual_timer->
stop();
299 m_real_timer->
stop();
301 m_is_gathering =
false;
303 m_full_stats_str <<
"</stats>\n";
309 ofile << m_full_stats_str.str();
317findOrCreateSubAction(
const String& name)
319 Action*
sa = subAction(name);
321 sa =
new Action(
this,name);
331beginAction(
const String& action_name)
334 Action* current_action = _currentAction();
335 current_action->addPhaseValue(_currentPhaseValue());
336 Action* sa = current_action->findOrCreateSubAction(action_name);
338 m_full_stats_str <<
"<action name='" << sa->name() <<
"'"
340 m_current_action = sa;
347endAction(
const String& action_name,
bool print_time)
349 ARCANE_UNUSED(action_name);
351 m_need_compute_elapsed_time =
true;
352 TimeStats::PhaseValue pv = _currentPhaseValue();
353 m_current_action->addPhaseValue(pv);
354 m_current_action->addNbCalled();
356 elapsedTime(TP_Computation,m_current_action->name());
357 elapsedTime(TP_Communication,m_current_action->name());
360 m_full_stats_str <<
"</action><!-- " << m_current_action->name() <<
" -->\n";
361 m_current_action = m_current_action->parent();
371 TimeStats::PhaseValue pv = _currentPhaseValue();
372 m_current_action->addPhaseValue(pv);
373 m_current_phase.m_type = phase_type;
374 m_phases_type.push(pv.m_type);
383 ARCANE_UNUSED(phase_type);
385 m_need_compute_elapsed_time =
true;
386 TimeStats::PhaseValue pv = _currentPhaseValue();
387 m_current_action->addPhaseValue(pv);
388 if (m_phases_type.empty())
390 eTimePhase old_phase_type = m_phases_type.top();
392 m_current_phase.m_type = old_phase_type;
401 _computeCumulativeTimes();
402 return m_main_action->m_phases[phase].m_time[TT_Real][TC_Cumulative];
411 _computeCumulativeTimes();
416 <<
" local_Real=" << action->m_phases[phase].m_time[TT_Real][TC_Local]
417 <<
" total_Real=" << action->m_phases[phase].m_time[TT_Real][TC_Cumulative]
418 <<
" local_Virt=" << action->m_phases[phase].m_time[TT_Virtual][TC_Local]
419 <<
" total_Virt=" << action->m_phases[phase].m_time[TT_Virtual][TC_Cumulative];
420 return action->m_phases[phase].m_time[TT_Real][TC_Cumulative];
443void TimeStats::ActionSeries::
444dumpStats(std::ostream& ostr,
bool is_verbose,
Real nb,
const String& name,
445 bool use_elapsed_time,
const String& message)
447 Int64 nb_iteration_loop = this->nbIterationLoop();
448 if (nb_iteration_loop!=0)
449 nb = nb * ((
Real)nb_iteration_loop);
450 eTimeType tt = TT_Virtual;
451 if (use_elapsed_time)
453 ostr <<
"-- Execution statistics " << message
454 <<
" (divide=" << nb <<
", nb_loop=" << nb_iteration_loop <<
")";
456 ostr <<
" (clock time)";
457 else if (tt==TT_Virtual)
458 ostr <<
" (CPU time)";
460 std::ios_base::fmtflags f = ostr.flags(std::ios::right);
473 _dumpStats(ostr,m_main_action,tt,1,0,nb);
478 Action* action = m_main_action.findSubActionRecursive(
"Loop");
480 _dumpStats(ostr,m_main_action,tt,1,3,nb);
482 _dumpStats(ostr,*action,tt,1,3,nb);
494 _computeCumulativeTimes();
495 ostr <<
"Execution statistics (current execution)\n";
499 ostr <<
"\nExecution statistics (cumulative)\n";
514 _computeCumulativeTimes();
517 action->dumpCurrentStats(
ostr(),1,
unit);
518 info() <<
"-- Execution statistics: Action=" << action->name()
529 Action* action = m_main_action->findSubActionRecursive(
action_name);
533 m_need_compute_elapsed_time =
true;
542_writeValue(std::ostream& ostr,
Real value,
Real unit)
545 Real v2 = value * unit;
557_printIndentedName(std::ostream& ostr,
const String& name,
int level)
559 StringBuilder indent_str;
560 StringBuilder after_str;
561 for(
int i=0; i<level; ++i )
562 indent_str.append(
" ");
565 int alen =
static_cast<int>(name.utf8().size());
567 for(
int i=0; i<50-alen; ++i )
576_printPercentage(std::ostream& ostr,
Real value,
Real cumulative_value)
585 Real z_cumulative_value = cumulative_value;
586 if (z_cumulative_value!=0.0 && !math::isNearlyZero(z_cumulative_value)){
587 percent = value / z_cumulative_value;
592 ostr << (n_percent / 10) <<
'.' << (n_percent % 10);
599void TimeStats::Action::
600dumpCurrentStats(std::ostream& ostr,
int level,
Real unit)
602 Action& action = *
this;
603 _printIndentedName(ostr,action.name(),level);
604 _writeValue(ostr,action.m_phases[TP_Computation].m_time[TT_Real][TC_Cumulative],unit);
605 _writeValue(ostr,action.m_phases[TP_Communication].m_time[TT_Real][TC_Cumulative],unit);
609 a->dumpCurrentStats(ostr,level+1,unit);
617_computeCumulativeTimes()
619 if (!m_need_compute_elapsed_time)
621 m_main_action->computeCumulativeTimes();
622 m_need_compute_elapsed_time =
false;
628void TimeStats::ActionSeries::
629_dumpStats(std::ostream& ostr,Action& action,eTimeType tt,
int level,
int max_level,
Real nb)
631 PhaseValue& pv = action.m_phases[TP_Computation];
632 _printIndentedName(ostr,action.name(),level);
634 if (pv.m_time[TT_Real][TC_Cumulative]!=0.0 || pv.m_time[TT_Virtual][TC_Cumulative]!=0.0){
635 _dumpAllPhases(ostr,action,tt,TC_Cumulative,nb);
638 if (max_level==0 || level<max_level){
641 _dumpStats(ostr,*a,tt,level+1,max_level,nb);
650_dumpCumulativeTime(std::ostream& ostr,Action& action,
eTimePhase tp,eTimeType tt)
652 Real current_time = action.m_phases[tp].m_time[tt][TC_Local];
653 Real cumulative_time = action.m_phases[tp].m_time[tt][TC_Cumulative];
656 ostr << current_time <<
' ';
658 ostr << cumulative_time <<
' ';
660 _printPercentage(ostr,current_time,m_main_action->m_phases[tp].m_time[tt][TC_Cumulative]);
661 _printPercentage(ostr,cumulative_time,m_main_action->m_phases[tp].m_time[tt][TC_Cumulative]);
663 Action* parent_action = action.parent();
664 Real parent_time = cumulative_time;
666 parent_time = parent_action->m_phases[tp].m_time[tt][TC_Cumulative];
667 _printPercentage(ostr,cumulative_time,parent_time);
674void TimeStats::ActionSeries::
675_dumpAllPhases(std::ostream& ostr,Action& action,eTimeType tt,
int tc,
Real nb)
677 Real all_phase_time = action.m_total_time.m_time[tt][tc];
680 ostr <<
Trace::Width(11) << String::fromNumber(all_phase_time,3);
688 nb_called = (
Real)action.nbCalled();
690 Real r = all_phase_time * 1.0e6;
691 Real r_nb_called =
static_cast<Real>(nb_called);
693 ct_by_call = r / (r_nb_called + 1.0e-10);
695 ostr <<
Trace::Width(11) << String::fromNumber(ct_by_call,3);
700 ostr << action.nbCalled() <<
' ';
702 _printPercentage(ostr,all_phase_time,m_main_action.m_total_time.m_time[tt][tc]);
705 Action* parent_action = action.parent();
706 Real parent_time = all_phase_time;
708 parent_time = parent_action->m_total_time.m_time[tt][tc];
709 _printPercentage(ostr,all_phase_time,parent_time);
714 for( Integer phase=0; phase<NB_TIME_PHASE; ++phase ){
715 _printPercentage(ostr,action.m_phases[phase].m_time[tt][tc],all_phase_time);
716 if ((phase+1)!=NB_TIME_PHASE)
725void TimeStats::Action::
726computeCumulativeTimes()
728 Action& action = *
this;
730 action.m_total_time.m_time[tt][TC_Local] = 0.;
731 action.m_total_time.m_time[tt][TC_Cumulative] = 0.;
732 for( Integer phase=0; phase<NB_TIME_PHASE; ++phase ){
733 Real r = action.m_phases[phase].m_time[tt][TC_Local];
734 action.m_phases[phase].m_time[tt][TC_Cumulative] = r;
735 action.m_total_time.m_time[tt][TC_Cumulative] += r;
736 action.m_total_time.m_time[tt][TC_Local] += r;
742 a->computeCumulativeTimes();
743 for( Integer phase=0; phase<NB_TIME_PHASE; ++phase ){
745 Real r = a->m_phases[phase].m_time[tt][TC_Cumulative];
746 action.m_phases[phase].m_time[tt][TC_Cumulative] += r;
747 action.m_total_time.m_time[tt][TC_Cumulative] += r;
756TimeStats::Action* TimeStats::
759 if (!m_current_action)
760 m_current_action = m_main_action;
761 return m_current_action;
767TimeStats::PhaseValue TimeStats::
770 Real real_time = m_timer_mng->
getTime(m_real_timer);
771 Real virtual_time = m_timer_mng->
getTime(m_virtual_timer);
773 Real diff_real_time = real_time - m_current_phase.m_time[TT_Real][TC_Local];
774 Real diff_virtual_time = virtual_time - m_current_phase.m_time[TT_Virtual][TC_Local];
775 if (diff_real_time<0.0 || diff_virtual_time<0.0)
776 info() <<
"BAD_CURRENT_PHASE_VALUE " << diff_real_time <<
" " << diff_virtual_time
777 <<
" phase=" << m_current_phase.m_type;
778 m_current_phase.m_time[TT_Real][TC_Local] = real_time;
779 m_current_phase.m_time[TT_Virtual][TC_Local] = virtual_time;
781 m_full_stats_str <<
"<time"
782 <<
" phase='" << m_current_phase.m_type <<
"'"
783 <<
" real_time='" << real_time <<
"'"
785 return PhaseValue(m_current_phase.m_type,diff_real_time,diff_virtual_time);
795 ARCANE_FATAL(
"TimeStats::beginGatherStats() not called");
796 if (!m_current_action)
806 bool is_gather = m_is_gathering && m_current_action;
825 _computeCumulativeTimes();
826 writer.write(
"Version",(Int64)1);
828 writer.writeKey(
"Current");
830 m_main_action->dumpJSON(
writer,TT_Real);
836 writer.writeKey(
"Cumulative");
846void TimeStats::Action::
849 Action& action = *
this;
850 writer.writeKey(action.name());
853 Real values[NB_TIME_PHASE];
854 for( Integer phase=0; phase<NB_TIME_PHASE; ++phase )
855 values[phase] = action.m_phases[phase].m_time[
tt][TC_Local];
857 for( Integer phase=0; phase<NB_TIME_PHASE; ++phase )
858 values[phase] = action.m_phases[phase].m_time[
tt][TC_Cumulative];
861 if (!action.m_sub_actions.empty()){
862 writer.writeKey(
"SubActions");
883 m_sub_actions.each(Deleter());
892 ActionList::iterator i = m_sub_actions.find_if(
NameComparer(name));
893 if (i!=m_sub_actions.end())
901void TimeStats::Action::
910void TimeStats::Action::
914 save_info.m_nb_call_list.add(m_nb_called);
915 save_info.m_nb_child.add(m_sub_actions.count());
916 for( Integer phase=0; phase<NB_TIME_PHASE; ++phase )
918 save_info.m_time_list.add(m_phases[phase].m_time[i][TC_Local]);
919 for( Action* s : m_sub_actions )
926void TimeStats::Action::
927merge(AllActionsInfo& save_info,Integer* index_ptr)
929 Integer index = *index_ptr;
930 String saved_name = save_info.m_name_list[index];
931 if (saved_name!=m_name)
932 ARCANE_FATAL(
"Bad merge name={0} saved={1}",m_name,saved_name);
934 Integer nb_child = save_info.m_nb_child[index];
935 m_nb_called += save_info.m_nb_call_list[index];
938 for (Integer phase = 0; phase < NB_TIME_PHASE; ++phase)
940 m_phases[phase].m_time[i][TC_Local] += save_info.m_time_list[pos];
944 for( Integer i=0; i<nb_child; ++i ) {
945 String next_name = save_info.m_name_list[*index_ptr];
946 Action* a = findOrCreateSubAction(next_name);
947 a->merge(save_info,index_ptr);
960 for( Integer phase=0; phase<NB_TIME_PHASE; ++phase )
962 m_phases[phase].m_time[i][TC_Local] = 0.0;
964 for(
Action* s : m_sub_actions )
977 return m_metric_collector;
986 info(4) <<
"Saving TimeStats values";
990 const bool is_verbose =
false;
996 p->
set(
"NbIterationLoop",action_save_info.m_nb_iteration_loop);
997 p->
set(
"Names",action_save_info.m_name_list);
998 p->
set(
"NbCalls",action_save_info.m_nb_call_list);
999 p->
set(
"NbChildren",action_save_info.m_nb_child);
1000 p->
set(
"TimeList",action_save_info.m_time_list);
1007mergeTimeValues(Properties* p)
1009 info(4) <<
"Merging TimeStats values";
1011 Action::AllActionsInfo action_save_info;
1013 Int32 v = p->getInt32WithDefault(
"Version",0);
1018 info() <<
"Warning: can not merge time stats values because checkpoint version is not compatible";
1022 action_save_info.m_nb_iteration_loop = p->getInt64(
"NbIterationLoop");
1023 p->get(
"Names",action_save_info.m_name_list);
1024 p->get(
"NbCalls",action_save_info.m_nb_call_list);
1025 p->get(
"NbChildren",action_save_info.m_nb_child);
1026 p->get(
"TimeList",action_save_info.m_time_list);
1028 const bool is_verbose =
false;
1030 info() <<
"MergedSeries=" << action_save_info;
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Interface du gestionnaire de parallélisme pour un sous-domaine.
Interface gérant les statistiques sur les temps d'exécution.
virtual Real getTime(Timer *timer)=0
Temps écoulé depuis le dernier appel à beginTimer().
Lecteur des fichiers de maillage via la bibliothèque LIMA.
ListEnumeratorT< Action * > Enumerator
Type d'un itérateur constant sur tout le tableau.
Classe utilitaire pour comparer le nom d'une instance.
Flot de sortie lié à une String.
void set(const String &name, bool value)
Positionne une propriété de type bool de nom name et de valeur value.
ActionSeries(const ActionSeries &s1, const ActionSeries &s2)
Créé une série qui cumule les temps des deux séries passées en argument.
Informations pour sauver/reconstruire une arborescence d'action.
String m_name
Nom de l'action.
Action * m_parent
Action parente.
Action * subAction(const String &name)
Action fille de nom name. nullptr si aucune avec ce nom.
ActionList m_sub_actions
Actions filles.
Int64 m_nb_called
Nombre de fois que l'action a été appelée.
void reset()
Remet à zéro les statistiques de l'action et de ces filles.
Real elapsedTime(eTimePhase phase) override
Temps réel écoulé pour la phase phase.
void dumpStats(std::ostream &ostr, bool is_verbose, Real nb, const String &name, bool use_elapsed_time) override
Affiche les statistiques sur les temps d'exécution.
void endGatherStats() override
Arrête la collection des temps.
void dumpCurrentStats(const String &action) override
Affiche les statistiques d'une action.
ActionSeries * m_previous_action_series
Statistiques sur les exécutions précédentes.
bool isGathering() const override
Indique si les statistiques sont actives.
void dumpStatsJSON(JSONWriter &writer) override
Sérialise dans l'écrivain writer les statistiques temporelles.
ITimeMetricCollector * metricCollector() override
Interface de collection associée.
void notifyNewIterationLoop() override
Notifie qu'on commence une nouvelle itération de la boucle de calcul.
static const Integer NB_TIME_TYPE
Nombre de valeurs de eTimeType.
void beginGatherStats() override
Démarre la collection des temps.
ActionSeries * m_current_action_series
Statistiques sur l'exécution en cours.
void dumpTimeAndMemoryUsage(IParallelMng *pm) override
Affiche la date actuelle et la mémoire consommée.
Real stop()
Désactive le timer.
@ TimerReal
Timer utilisant le temps réel.
@ TimerVirtual
Timer utilisant le temps CPU (obsolète).
void start()
Active le timer.
Interface gérant les statistiques sur l'exécution.
Constructeur de chaîne de caractère unicode.
Chaîne de caractères unicode.
const char * localstr() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
ITraceMng * traceMng() const
Gestionnaire de trace.
TraceMessage info() const
Flot pour un message d'information.
Formattage du flot en longueur.
Integer toInteger(Real r)
Converti un Real en Integer.
void dumpDateAndMemoryUsage(IParallelMng *pm, ITraceMng *tm)
Écrit dans tm la date et la mémoire consommée.
bool isZero(const BuiltInProxy< _Type > &a)
Teste si une valeur est exactement égale à zéro.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
Integer arcaneCallFunctionAndCatchException(std::function< void()> function)
eTimePhase
Phase d'une action temporelle.
ArrayView< Real > RealArrayView
Equivalent C d'un tableau à une dimension de réels.
Int32 Integer
Type représentant un entier.