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"
24#include "arcane/utils/Convert.h"
26#include "arcane/core/Timer.h"
27#include "arcane/core/IParallelMng.h"
28#include "arcane/core/ITimerMng.h"
30#include "arcane/core/Properties.h"
32#include "arcane/impl/TimeStats.h"
34#include "arccore/trace/internal/ITimeMetricCollector.h"
35#include "arccore/trace/internal/TimeMetric.h"
51 return new TimeStats(timer_mng, trace_mng, name);
75 auto name = handle.name();
77 m_time_stats->beginAction(name);
78 int phase = handle.phase();
80 m_time_stats->beginPhase(
static_cast<eTimePhase>(phase));
86 int phase = action.phase();
88 m_time_stats->endPhase(
static_cast<eTimePhase>(phase));
89 auto name = action.name();
91 m_time_stats->endAction(name,
false);
97 std::atomic<Int64> m_id;
120 Int64 m_nb_iteration_loop = 0;
124 friend std::ostream& operator<<(std::ostream& o,
const AllActionsInfo& x)
126 o <<
"NbLoop=" << x.m_nb_iteration_loop <<
"\n";
127 o <<
"Name=" << x.m_name_list <<
"\n";
128 o <<
"NbCall=" << x.m_nb_call_list <<
"\n";
129 o <<
"NbChild=" << x.m_nb_child <<
"\n";
130 o <<
"Time=" << x.m_time_list <<
"\n";
138 m_nb_iteration_loop = 0;
141 m_nb_call_list.clear();
148 Action(Action* parent,
const String& name)
159 const String& name()
const {
return m_name; }
160 Action* parent()
const {
return m_parent; }
162 Action* findOrCreateSubAction(
const String& name);
163 void addPhaseValue(
const PhaseValue& new_pv);
165 Action* findSubActionRecursive(
const String& action_name)
const;
168 void dumpJSON(JSONWriter& writer, eTimeType tt);
169 void computeCumulativeTimes();
170 void dumpCurrentStats(std::ostream& ostr,
int level,
Real unit);
206 : m_main_action(
nullptr,
"Main")
211 : m_main_action(nullptr,
"Main")
214 s1.save(action_info);
215 this->merge(action_info);
216 s2.save(action_info);
217 this->merge(action_info);
225 Action* mainAction() {
return &m_main_action; }
226 Int64 nbIterationLoop()
const {
return m_nb_iteration_loop; }
227 void save(AllActionsInfo& all_actions_info)
const
229 all_actions_info.clear();
230 m_main_action.save(all_actions_info);
231 all_actions_info.m_nb_iteration_loop = m_nb_iteration_loop;
233 void merge(AllActionsInfo& all_actions_info)
235 m_nb_iteration_loop += all_actions_info.m_nb_iteration_loop;
237 m_main_action.merge(all_actions_info, &index);
238 m_main_action.computeCumulativeTimes();
240 void dumpStats(std::ostream& ostr,
bool is_verbose,
Real nb,
const String& name,
241 bool use_elapsed_time,
const String& message);
245 Action m_main_action;
246 Int64 m_nb_iteration_loop = 0;
250 void _dumpStats(std::ostream& ostr, Action& action, eTimeType tt,
int level,
int max_level,
Real nb);
251 void _dumpAllPhases(std::ostream& ostr, Action& action, eTimeType tt,
int tc,
Real nb);
252 void _dumpCurrentStats(std::ostream& ostr, Action& action,
int level,
Real unit);
264, m_timer_mng(timer_mng)
265, m_virtual_timer(nullptr)
266, m_real_timer(nullptr)
267, m_is_gathering(false)
268, m_current_action_series(new ActionSeries())
269, m_previous_action_series(new ActionSeries())
270, m_main_action(m_current_action_series->mainAction())
271, m_current_action(m_main_action)
272, m_need_compute_elapsed_time(true)
275, m_metric_collector(new MetricCollector(this))
277 m_phases_type.push(TP_Computation);
288 delete m_metric_collector;
291 delete m_virtual_timer;
306 if (!m_virtual_timer)
311 m_is_gathering =
true;
315 m_virtual_timer->start();
316 m_real_timer->start();
317 m_full_stats_str <<
"<? xml version='1.0'?>\n";
318 m_full_stats_str <<
"<stats>\n";
327 m_virtual_timer->stop();
328 m_real_timer->stop();
330 m_is_gathering =
false;
332 m_full_stats_str <<
"</stats>\n";
338 ofile << m_full_stats_str.str();
346findOrCreateSubAction(
const String& name)
348 Action* sa = subAction(name);
350 sa =
new Action(
this, name);
360beginAction(
const String& action_name)
363 Action* current_action = _currentAction();
364 current_action->addPhaseValue(_currentPhaseValue());
365 Action* sa = current_action->findOrCreateSubAction(action_name);
367 m_full_stats_str <<
"<action name='" << sa->name() <<
"'"
369 m_current_action = sa;
376endAction(
const String& action_name,
bool print_time)
378 ARCANE_UNUSED(action_name);
380 m_need_compute_elapsed_time =
true;
381 TimeStats::PhaseValue pv = _currentPhaseValue();
382 m_current_action->addPhaseValue(pv);
383 m_current_action->addNbCalled();
385 elapsedTime(TP_Computation, m_current_action->name());
386 elapsedTime(TP_Communication, m_current_action->name());
389 m_full_stats_str <<
"</action><!-- " << m_current_action->name() <<
" -->\n";
390 m_current_action = m_current_action->parent();
400 TimeStats::PhaseValue pv = _currentPhaseValue();
401 m_current_action->addPhaseValue(pv);
402 m_current_phase.m_type = phase_type;
403 m_phases_type.push(pv.m_type);
412 ARCANE_UNUSED(phase_type);
414 m_need_compute_elapsed_time =
true;
415 TimeStats::PhaseValue pv = _currentPhaseValue();
416 m_current_action->addPhaseValue(pv);
417 if (m_phases_type.empty())
419 eTimePhase old_phase_type = m_phases_type.top();
421 m_current_phase.m_type = old_phase_type;
430 _computeCumulativeTimes();
431 return m_main_action->m_phases[phase].m_time[TT_Real][TC_Cumulative];
440 _computeCumulativeTimes();
441 Action* action = m_main_action->findSubActionRecursive(action_name);
444 info() <<
"TimeStat: type=" << phase <<
" action=" << action_name
445 <<
" local_Real=" << action->m_phases[phase].m_time[TT_Real][TC_Local]
446 <<
" total_Real=" << action->m_phases[phase].m_time[TT_Real][TC_Cumulative]
447 <<
" local_Virt=" << action->m_phases[phase].m_time[TT_Virtual][TC_Local]
448 <<
" total_Virt=" << action->m_phases[phase].m_time[TT_Virtual][TC_Cumulative];
449 return action->m_phases[phase].m_time[TT_Real][TC_Cumulative];
456findSubActionRecursive(
const String& action_name)
const
460 if (action->name() == action_name)
462 Action* find_action = action->findSubActionRecursive(action_name);
472void TimeStats::ActionSeries::
473dumpStats(std::ostream& ostr,
bool is_verbose,
Real nb,
const String& name,
474 bool use_elapsed_time,
const String& message)
476 Int64 nb_iteration_loop = this->nbIterationLoop();
477 if (nb_iteration_loop != 0)
478 nb = nb * ((
Real)nb_iteration_loop);
479 eTimeType tt = TT_Virtual;
480 if (use_elapsed_time)
482 ostr <<
"-- Execution statistics " << message
483 <<
" (divide=" << nb <<
", nb_loop=" << nb_iteration_loop <<
")";
485 ostr <<
" (clock time)";
486 else if (tt == TT_Virtual)
487 ostr <<
" (CPU time)";
489 std::ios_base::fmtflags f = ostr.flags(std::ios::right);
491 ostr << Trace::Width(50) <<
" Action "
492 << Trace::Width(11) <<
" Time "
493 << Trace::Width(11) <<
" Time "
494 << Trace::Width(8) <<
"N"
496 ostr << Trace::Width(50) <<
" "
497 << Trace::Width(11) <<
"Total(s)"
498 << Trace::Width(11) << (String(
"/") + name +
"(us)")
502 _dumpStats(ostr, m_main_action, tt, 1, 0, nb);
507 Action* action = m_main_action.findSubActionRecursive(
"Loop");
509 _dumpStats(ostr, m_main_action, tt, 1, 3, nb);
511 _dumpStats(ostr, *action, tt, 1, 3, nb);
521 bool use_elapsed_time)
523 _computeCumulativeTimes();
524 ostr <<
"Execution statistics (current execution)\n";
528 ostr <<
"\nExecution statistics (cumulative)\n";
530 cumul_series.dumpStats(ostr, is_verbose, nb, name, use_elapsed_time,
"(cumulative execution)");
540 Action* action = m_main_action->findSubActionRecursive(action_name);
543 _computeCumulativeTimes();
546 action->dumpCurrentStats(ostr(), 1, unit);
547 info() <<
"-- Execution statistics: Action=" << action->name()
556resetStats(
const String& action_name)
558 Action* action = m_main_action->findSubActionRecursive(action_name);
562 m_need_compute_elapsed_time =
true;
571 _writeValue(std::ostream& ostr, Real value, Real unit)
574 Real v2 = value * unit;
586 _printIndentedName(std::ostream& ostr,
const String& name,
int level)
588 StringBuilder indent_str;
589 StringBuilder after_str;
590 for (
int i = 0; i < level; ++i)
591 indent_str.append(
" ");
594 int alen =
static_cast<int>(name.utf8().size());
596 for (
int i = 0; i < 50 - alen; ++i)
605 _printPercentage(std::ostream& ostr,
Real value,
Real cumulative_value)
614 Real z_cumulative_value = cumulative_value;
615 if (z_cumulative_value != 0.0 && !math::isNearlyZero(z_cumulative_value)) {
616 percent = value / z_cumulative_value;
621 ostr << (n_percent / 10) <<
'.' << (n_percent % 10);
628void TimeStats::Action::
629dumpCurrentStats(std::ostream& ostr,
int level,
Real unit)
632 _printIndentedName(ostr, action.name(), level);
633 _writeValue(ostr, action.m_phases[TP_Computation].m_time[TT_Real][TC_Cumulative], unit);
634 _writeValue(ostr, action.m_phases[TP_Communication].m_time[TT_Real][TC_Cumulative], unit);
638 a->dumpCurrentStats(ostr, level + 1, unit);
646_computeCumulativeTimes()
648 if (!m_need_compute_elapsed_time)
650 m_main_action->computeCumulativeTimes();
651 m_need_compute_elapsed_time =
false;
657void TimeStats::ActionSeries::
658_dumpStats(std::ostream& ostr,
Action& action, eTimeType tt,
int level,
int max_level,
Real nb)
660 PhaseValue& pv = action.m_phases[TP_Computation];
661 _printIndentedName(ostr, action.name(), level);
663 if (pv.m_time[TT_Real][TC_Cumulative] != 0.0 || pv.m_time[TT_Virtual][TC_Cumulative] != 0.0) {
664 _dumpAllPhases(ostr, action, tt, TC_Cumulative, nb);
667 if (max_level == 0 || level < max_level) {
670 _dumpStats(ostr, *a, tt, level + 1, max_level, nb);
679_dumpCumulativeTime(std::ostream& ostr,
Action& action,
eTimePhase tp, eTimeType tt)
681 Real current_time = action.m_phases[tp].m_time[tt][TC_Local];
682 Real cumulative_time = action.m_phases[tp].m_time[tt][TC_Cumulative];
685 ostr << current_time <<
' ';
687 ostr << cumulative_time <<
' ';
689 _printPercentage(ostr, current_time, m_main_action->m_phases[tp].m_time[tt][TC_Cumulative]);
690 _printPercentage(ostr, cumulative_time, m_main_action->m_phases[tp].m_time[tt][TC_Cumulative]);
692 Action* parent_action = action.parent();
693 Real parent_time = cumulative_time;
695 parent_time = parent_action->m_phases[tp].m_time[tt][TC_Cumulative];
696 _printPercentage(ostr, cumulative_time, parent_time);
703void TimeStats::ActionSeries::
704_dumpAllPhases(std::ostream& ostr,
Action& action, eTimeType tt,
int tc,
Real nb)
706 Real all_phase_time = action.m_total_time.m_time[tt][tc];
709 ostr << Trace::Width(11) << String::fromNumber(all_phase_time, 3);
717 nb_called = (
Real)action.nbCalled();
719 Real r = all_phase_time * 1.0e6;
720 Real r_nb_called =
static_cast<Real>(nb_called);
722 ct_by_call = r / (r_nb_called + 1.0e-10);
724 ostr << Trace::Width(11) << String::fromNumber(ct_by_call, 3);
729 ostr << action.nbCalled() <<
' ';
731 _printPercentage(ostr, all_phase_time, m_main_action.m_total_time.m_time[tt][tc]);
734 Action* parent_action = action.parent();
735 Real parent_time = all_phase_time;
737 parent_time = parent_action->m_total_time.m_time[tt][tc];
738 _printPercentage(ostr, all_phase_time, parent_time);
743 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase) {
744 _printPercentage(ostr, action.m_phases[phase].m_time[tt][tc], all_phase_time);
745 if ((phase + 1) != NB_TIME_PHASE)
754void TimeStats::Action::
755computeCumulativeTimes()
759 action.m_total_time.m_time[tt][TC_Local] = 0.;
760 action.m_total_time.m_time[tt][TC_Cumulative] = 0.;
761 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase) {
762 Real r = action.m_phases[phase].m_time[tt][TC_Local];
763 action.m_phases[phase].m_time[tt][TC_Cumulative] = r;
764 action.m_total_time.m_time[tt][TC_Cumulative] += r;
765 action.m_total_time.m_time[tt][TC_Local] += r;
771 a->computeCumulativeTimes();
772 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase) {
774 Real r = a->m_phases[phase].m_time[tt][TC_Cumulative];
775 action.m_phases[phase].m_time[tt][TC_Cumulative] += r;
776 action.m_total_time.m_time[tt][TC_Cumulative] += r;
785TimeStats::Action* TimeStats::
788 if (!m_current_action)
789 m_current_action = m_main_action;
790 return m_current_action;
796TimeStats::PhaseValue TimeStats::
799 Real real_time = m_timer_mng->getTime(m_real_timer);
800 Real virtual_time = m_timer_mng->getTime(m_virtual_timer);
802 Real diff_real_time = real_time - m_current_phase.m_time[TT_Real][TC_Local];
803 Real diff_virtual_time = virtual_time - m_current_phase.m_time[TT_Virtual][TC_Local];
804 if (diff_real_time < 0.0 || diff_virtual_time < 0.0)
805 info() <<
"BAD_CURRENT_PHASE_VALUE " << diff_real_time <<
" " << diff_virtual_time
806 <<
" phase=" << m_current_phase.
m_type;
807 m_current_phase.m_time[TT_Real][TC_Local] = real_time;
808 m_current_phase.m_time[TT_Virtual][TC_Local] = virtual_time;
810 m_full_stats_str <<
"<time"
811 <<
" phase='" << m_current_phase.m_type <<
"'"
812 <<
" real_time='" << real_time <<
"'"
814 return PhaseValue(m_current_phase.m_type, diff_real_time, diff_virtual_time);
824 ARCANE_FATAL(
"TimeStats::beginGatherStats() not called");
825 if (!m_current_action)
835 bool is_gather = m_is_gathering && m_current_action;
854 _computeCumulativeTimes();
855 writer.write(
"Version", (
Int64)1);
857 writer.writeKey(
"Current");
858 writer.beginObject();
859 m_main_action->dumpJSON(writer, TT_Real);
865 writer.writeKey(
"Cumulative");
866 writer.beginObject();
867 cumul_series.mainAction()->dumpJSON(writer, TT_Real);
875void TimeStats::Action::
878 Action& action = *
this;
879 writer.writeKey(action.name());
880 writer.beginObject();
882 Real values[NB_TIME_PHASE];
883 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase)
884 values[phase] = action.m_phases[phase].m_time[tt][TC_Local];
886 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase)
887 values[phase] = action.m_phases[phase].m_time[tt][TC_Cumulative];
888 writer.write(
"Cumulative",
RealArrayView(NB_TIME_PHASE, values));
890 if (!action.m_sub_actions.empty()) {
891 writer.writeKey(
"SubActions");
895 a->dumpJSON(writer, tt);
912 m_sub_actions.each(Deleter());
930void TimeStats::Action::
933 m_phases[new_pv.m_type].add(new_pv);
939void TimeStats::Action::
940save(AllActionsInfo& save_info)
const
942 save_info.m_name_list.add(m_name);
943 save_info.m_nb_call_list.add(m_nb_called);
944 save_info.m_nb_child.add(m_sub_actions.count());
945 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase)
947 save_info.m_time_list.add(m_phases[phase].m_time[i][TC_Local]);
948 for (Action* s : m_sub_actions)
955void TimeStats::Action::
956merge(AllActionsInfo& save_info,
Integer* index_ptr)
959 String saved_name = save_info.m_name_list[index];
960 if (saved_name != m_name)
961 ARCANE_FATAL(
"Bad merge name={0} saved={1}", m_name, saved_name);
963 Integer nb_child = save_info.m_nb_child[index];
964 m_nb_called += save_info.m_nb_call_list[index];
967 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase)
969 m_phases[phase].m_time[i][TC_Local] += save_info.m_time_list[pos];
973 for (
Integer i = 0; i < nb_child; ++i) {
974 String next_name = save_info.m_name_list[*index_ptr];
975 Action* a = findOrCreateSubAction(next_name);
976 a->merge(save_info, index_ptr);
990 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase)
992 m_phases[phase].m_time[i][TC_Local] = 0.0;
1007 return m_metric_collector;
1016 info(4) <<
"Sauvegarde des valeurs TimeStats";
1017 Action::AllActionsInfo action_save_info;
1019 cumulative_series.save(action_save_info);
1020 const bool is_verbose =
false;
1022 info() <<
"Sauvegardé " << action_save_info;
1025 p->
set(
"Version", 1);
1026 p->
set(
"NbIterationLoop", action_save_info.m_nb_iteration_loop);
1027 p->
set(
"Names", action_save_info.m_name_list);
1028 p->
set(
"NbCalls", action_save_info.m_nb_call_list);
1029 p->
set(
"NbChildren", action_save_info.m_nb_child);
1030 p->
set(
"TimeList", action_save_info.m_time_list);
1037mergeTimeValues(Properties* p)
1039 info(4) <<
"Fusion des valeurs TimeStats";
1043 Int32 v = p->getInt32WithDefault(
"Version", 0);
1048 info() <<
"Avertissement : impossible de fusionner les valeurs de statistiques de temps car la version du point de contrôle n'est pas compatible";
1052 action_save_info.m_nb_iteration_loop = p->getInt64(
"NbIterationLoop");
1053 p->get(
"Names", action_save_info.m_name_list);
1054 p->get(
"NbCalls", action_save_info.m_nb_call_list);
1055 p->get(
"NbChildren", action_save_info.m_nb_child);
1056 p->get(
"TimeList", action_save_info.m_time_list);
1058 const bool is_verbose =
false;
1060 info() <<
"MergedSeries=" << action_save_info;
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Fonctions mathématiques diverses.
void clear()
Supprime les éléments du tableau.
Interface du gestionnaire de parallélisme pour un sous-domaine.
Interface gérant les statistiques sur l'exécution.
Interface gérant les statistiques sur les temps d'exécution.
Interface d'un gestionnaire de timer.
Interface du gestionnaire de traces.
ListEnumeratorT< Action * > Enumerator
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.
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.
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.
Statistiques sur les temps d'exécution.
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.
@ TimerReal
Timer utilisant le temps réel.
@ TimerVirtual
Timer utilisant le temps CPU (obsolète).
Classe d'accès aux traces.
TraceMessage info() const
Flot pour un message d'information.
ITraceMng * traceMng() const
Gestionnaire de trace.
Trace::eMessageType m_type
Type de message.
Vecteur 1D de données avec sémantique par valeur (style STL).
Integer toInteger(Real r)
Convertit 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 --
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
Integer arcaneCallFunctionAndCatchException(std::function< void()> function)
double Real
Type représentant un réel.
eTimePhase
Phase d'une action temporelle.
ArrayView< Real > RealArrayView
Equivalent C d'un tableau à une dimension de réels.
std::int32_t Int32
Type entier signé sur 32 bits.