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);
506 Action* action = m_main_action.findSubActionRecursive(
"Loop");
508 _dumpStats(ostr, m_main_action, tt, 1, 3, nb);
510 _dumpStats(ostr, *action, tt, 1, 3, nb);
520 bool use_elapsed_time)
522 _computeCumulativeTimes();
523 ostr <<
"Execution statistics (current execution)\n";
527 ostr <<
"\nExecution statistics (cumulative)\n";
529 cumul_series.dumpStats(ostr, is_verbose, nb, name, use_elapsed_time,
"(cumulative execution)");
539 Action* action = m_main_action->findSubActionRecursive(action_name);
542 _computeCumulativeTimes();
545 action->dumpCurrentStats(ostr(), 1, unit);
546 info() <<
"-- Execution statistics: Action=" << action->name()
555resetStats(
const String& action_name)
557 Action* action = m_main_action->findSubActionRecursive(action_name);
561 m_need_compute_elapsed_time =
true;
570 _writeValue(std::ostream& ostr, Real value, Real unit)
573 Real v2 = value * unit;
585 _printIndentedName(std::ostream& ostr,
const String& name,
int level)
587 StringBuilder indent_str;
588 StringBuilder after_str;
589 for (
int i = 0; i < level; ++i)
590 indent_str.append(
" ");
593 int alen =
static_cast<int>(name.utf8().size());
595 for (
int i = 0; i < 50 - alen; ++i)
604 _printPercentage(std::ostream& ostr,
Real value,
Real cumulative_value)
613 Real z_cumulative_value = cumulative_value;
614 if (z_cumulative_value != 0.0 && !math::isNearlyZero(z_cumulative_value)) {
615 percent = value / z_cumulative_value;
620 ostr << (n_percent / 10) <<
'.' << (n_percent % 10);
627void TimeStats::Action::
628dumpCurrentStats(std::ostream& ostr,
int level,
Real unit)
631 _printIndentedName(ostr, action.name(), level);
632 _writeValue(ostr, action.m_phases[TP_Computation].m_time[TT_Real][TC_Cumulative], unit);
633 _writeValue(ostr, action.m_phases[TP_Communication].m_time[TT_Real][TC_Cumulative], unit);
637 a->dumpCurrentStats(ostr, level + 1, unit);
645_computeCumulativeTimes()
647 if (!m_need_compute_elapsed_time)
649 m_main_action->computeCumulativeTimes();
650 m_need_compute_elapsed_time =
false;
656void TimeStats::ActionSeries::
657_dumpStats(std::ostream& ostr,
Action& action, eTimeType tt,
int level,
int max_level,
Real nb)
659 PhaseValue& pv = action.m_phases[TP_Computation];
660 _printIndentedName(ostr, action.name(), level);
662 if (pv.m_time[TT_Real][TC_Cumulative] != 0.0 || pv.m_time[TT_Virtual][TC_Cumulative] != 0.0) {
663 _dumpAllPhases(ostr, action, tt, TC_Cumulative, nb);
666 if (max_level == 0 || level < max_level) {
669 _dumpStats(ostr, *a, tt, level + 1, max_level, nb);
678_dumpCumulativeTime(std::ostream& ostr,
Action& action,
eTimePhase tp, eTimeType tt)
680 Real current_time = action.m_phases[tp].m_time[tt][TC_Local];
681 Real cumulative_time = action.m_phases[tp].m_time[tt][TC_Cumulative];
684 ostr << current_time <<
' ';
686 ostr << cumulative_time <<
' ';
688 _printPercentage(ostr, current_time, m_main_action->m_phases[tp].m_time[tt][TC_Cumulative]);
689 _printPercentage(ostr, cumulative_time, m_main_action->m_phases[tp].m_time[tt][TC_Cumulative]);
691 Action* parent_action = action.parent();
692 Real parent_time = cumulative_time;
694 parent_time = parent_action->m_phases[tp].m_time[tt][TC_Cumulative];
695 _printPercentage(ostr, cumulative_time, parent_time);
702void TimeStats::ActionSeries::
703_dumpAllPhases(std::ostream& ostr,
Action& action, eTimeType tt,
int tc,
Real nb)
705 Real all_phase_time = action.m_total_time.m_time[tt][tc];
708 ostr << Trace::Width(11) << String::fromNumber(all_phase_time, 3);
716 nb_called = (
Real)action.nbCalled();
718 Real r = all_phase_time * 1.0e6;
719 Real r_nb_called =
static_cast<Real>(nb_called);
721 ct_by_call = r / (r_nb_called + 1.0e-10);
723 ostr << Trace::Width(11) << String::fromNumber(ct_by_call, 3);
728 ostr << action.nbCalled() <<
' ';
730 _printPercentage(ostr, all_phase_time, m_main_action.m_total_time.m_time[tt][tc]);
733 Action* parent_action = action.parent();
734 Real parent_time = all_phase_time;
736 parent_time = parent_action->m_total_time.m_time[tt][tc];
737 _printPercentage(ostr, all_phase_time, parent_time);
742 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase) {
743 _printPercentage(ostr, action.m_phases[phase].m_time[tt][tc], all_phase_time);
744 if ((phase + 1) != NB_TIME_PHASE)
753void TimeStats::Action::
754computeCumulativeTimes()
758 action.m_total_time.m_time[tt][TC_Local] = 0.;
759 action.m_total_time.m_time[tt][TC_Cumulative] = 0.;
760 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase) {
761 Real r = action.m_phases[phase].m_time[tt][TC_Local];
762 action.m_phases[phase].m_time[tt][TC_Cumulative] = r;
763 action.m_total_time.m_time[tt][TC_Cumulative] += r;
764 action.m_total_time.m_time[tt][TC_Local] += r;
770 a->computeCumulativeTimes();
771 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase) {
773 Real r = a->m_phases[phase].m_time[tt][TC_Cumulative];
774 action.m_phases[phase].m_time[tt][TC_Cumulative] += r;
775 action.m_total_time.m_time[tt][TC_Cumulative] += r;
784TimeStats::Action* TimeStats::
787 if (!m_current_action)
788 m_current_action = m_main_action;
789 return m_current_action;
795TimeStats::PhaseValue TimeStats::
798 Real real_time = m_timer_mng->getTime(m_real_timer);
799 Real virtual_time = m_timer_mng->getTime(m_virtual_timer);
801 Real diff_real_time = real_time - m_current_phase.m_time[TT_Real][TC_Local];
802 Real diff_virtual_time = virtual_time - m_current_phase.m_time[TT_Virtual][TC_Local];
803 if (diff_real_time < 0.0 || diff_virtual_time < 0.0)
804 info() <<
"BAD_CURRENT_PHASE_VALUE " << diff_real_time <<
" " << diff_virtual_time
805 <<
" phase=" << m_current_phase.
m_type;
806 m_current_phase.m_time[TT_Real][TC_Local] = real_time;
807 m_current_phase.m_time[TT_Virtual][TC_Local] = virtual_time;
809 m_full_stats_str <<
"<time"
810 <<
" phase='" << m_current_phase.m_type <<
"'"
811 <<
" real_time='" << real_time <<
"'"
813 return PhaseValue(m_current_phase.m_type, diff_real_time, diff_virtual_time);
823 ARCANE_FATAL(
"TimeStats::beginGatherStats() not called");
824 if (!m_current_action)
834 bool is_gather = m_is_gathering && m_current_action;
853 _computeCumulativeTimes();
854 writer.write(
"Version", (
Int64)1);
856 writer.writeKey(
"Current");
857 writer.beginObject();
858 m_main_action->dumpJSON(writer, TT_Real);
864 writer.writeKey(
"Cumulative");
865 writer.beginObject();
866 cumul_series.mainAction()->dumpJSON(writer, TT_Real);
874void TimeStats::Action::
877 Action& action = *
this;
878 writer.writeKey(action.name());
879 writer.beginObject();
881 Real values[NB_TIME_PHASE];
882 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase)
883 values[phase] = action.m_phases[phase].m_time[tt][TC_Local];
885 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase)
886 values[phase] = action.m_phases[phase].m_time[tt][TC_Cumulative];
887 writer.write(
"Cumulative",
RealArrayView(NB_TIME_PHASE, values));
889 if (!action.m_sub_actions.empty()) {
890 writer.writeKey(
"SubActions");
894 a->dumpJSON(writer, tt);
911 m_sub_actions.each(Deleter());
929void TimeStats::Action::
932 m_phases[new_pv.m_type].add(new_pv);
938void TimeStats::Action::
939save(AllActionsInfo& save_info)
const
941 save_info.m_name_list.add(m_name);
942 save_info.m_nb_call_list.add(m_nb_called);
943 save_info.m_nb_child.add(m_sub_actions.count());
944 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase)
946 save_info.m_time_list.add(m_phases[phase].m_time[i][TC_Local]);
947 for (Action* s : m_sub_actions)
954void TimeStats::Action::
955merge(AllActionsInfo& save_info,
Integer* index_ptr)
958 String saved_name = save_info.m_name_list[index];
959 if (saved_name != m_name)
960 ARCANE_FATAL(
"Bad merge name={0} saved={1}", m_name, saved_name);
962 Integer nb_child = save_info.m_nb_child[index];
963 m_nb_called += save_info.m_nb_call_list[index];
966 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase)
968 m_phases[phase].m_time[i][TC_Local] += save_info.m_time_list[pos];
972 for (
Integer i = 0; i < nb_child; ++i) {
973 String next_name = save_info.m_name_list[*index_ptr];
974 Action* a = findOrCreateSubAction(next_name);
975 a->merge(save_info, index_ptr);
989 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase)
991 m_phases[phase].m_time[i][TC_Local] = 0.0;
1006 return m_metric_collector;
1015 info(4) <<
"Saving TimeStats values";
1016 Action::AllActionsInfo action_save_info;
1018 cumulative_series.save(action_save_info);
1019 const bool is_verbose =
false;
1021 info() <<
"Saved " << action_save_info;
1024 p->
set(
"Version", 1);
1025 p->
set(
"NbIterationLoop", action_save_info.m_nb_iteration_loop);
1026 p->
set(
"Names", action_save_info.m_name_list);
1027 p->
set(
"NbCalls", action_save_info.m_nb_call_list);
1028 p->
set(
"NbChildren", action_save_info.m_nb_child);
1029 p->
set(
"TimeList", action_save_info.m_time_list);
1036mergeTimeValues(Properties* p)
1038 info(4) <<
"Merging TimeStats values";
1042 Int32 v = p->getInt32WithDefault(
"Version", 0);
1047 info() <<
"Warning: can not merge time stats values because checkpoint version is not compatible";
1051 action_save_info.m_nb_iteration_loop = p->getInt64(
"NbIterationLoop");
1052 p->get(
"Names", action_save_info.m_name_list);
1053 p->get(
"NbCalls", action_save_info.m_nb_call_list);
1054 p->get(
"NbChildren", action_save_info.m_nb_child);
1055 p->get(
"TimeList", action_save_info.m_time_list);
1057 const bool is_verbose =
false;
1059 info() <<
"MergedSeries=" << action_save_info;
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
Various mathematical functions.
void clear()
Removes the elements from the array.
Interface of the parallelism manager for a subdomain.
Interface managing statistics on execution.
Interface managing execution time statistics.
Interface of a timer manager.
ListEnumeratorT< Action * > Enumerator
Utility class for comparing an instance's name.
Output stream linked to a String.
void set(const String &name, bool value)
Sets a boolean property of name name and value value.
Unicode character string constructor.
Unicode character string.
const char * localstr() const
Returns the conversion of the instance into UTF-8 encoding.
ActionSeries(const ActionSeries &s1, const ActionSeries &s2)
Creates a series that accumulates the times of the two previous series passed as arguments.
Information to save/reconstruct an action tree.
String m_name
Action name.
Action * m_parent
Parent action.
Action * subAction(const String &name)
Child action with name name. nullptr if none with this name.
ActionList m_sub_actions
Child actions.
Int64 m_nb_called
Number of times the action has been called.
void reset()
Resets the statistics of the action and its children.
Statistics on execution times.
Real elapsedTime(eTimePhase phase) override
Real elapsed time for phase phase.
void dumpStats(std::ostream &ostr, bool is_verbose, Real nb, const String &name, bool use_elapsed_time) override
Displays execution time statistics.
void endGatherStats() override
Stops time collection.
void dumpCurrentStats(const String &action) override
Displays statistics for an action.
ActionSeries * m_previous_action_series
Statistics on previous executions.
bool isGathering() const override
Indicates if statistics are active.
void dumpStatsJSON(JSONWriter &writer) override
Serializes the temporal statistics into the writer writer.
ITimeMetricCollector * metricCollector() override
Associated collection interface.
void notifyNewIterationLoop() override
Notifies that a new iteration of the calculation loop begins.
static const Integer NB_TIME_TYPE
Number of eTimeType values.
void beginGatherStats() override
Starts time collection.
ActionSeries * m_current_action_series
Statistics on current execution.
void dumpTimeAndMemoryUsage(IParallelMng *pm) override
Displays the current date and memory consumption.
@ TimerReal
Timer using real time.
@ TimerVirtual
Timer using CPU time (obsolete).
TraceMessage info() const
Flow for an information message.
ITraceMng * traceMng() const
Trace manager.
Trace::eMessageType m_type
Message type.
1D data vector with value semantics (STL style).
Integer toInteger(Real r)
Converts a Real to Integer.
void dumpDateAndMemoryUsage(IParallelMng *pm, ITraceMng *tm)
Writes the date and memory consumed into tm.
bool isZero(const BuiltInProxy< _Type > &a)
Tests if a value is exactly equal to zero.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
Integer arcaneCallFunctionAndCatchException(std::function< void()> function)
Calls the function function while catching potential exceptions.
double Real
Type representing a real number.
eTimePhase
Phase of a temporal action.
ArrayView< Real > RealArrayView
C equivalent of a 1D array of reals.
std::int32_t Int32
Signed integer type of 32 bits.