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/core/Timer.h"
26#include "arcane/core/IParallelMng.h"
27#include "arcane/core/ITimerMng.h"
29#include "arcane/core/Properties.h"
31#include "arcane/impl/TimeStats.h"
33#include "arccore/trace/internal/ITimeMetricCollector.h"
34#include "arccore/trace/internal/TimeMetric.h"
50 return new TimeStats(timer_mng, trace_mng, name);
74 auto name = handle.name();
76 m_time_stats->beginAction(name);
77 int phase = handle.phase();
79 m_time_stats->beginPhase(
static_cast<eTimePhase>(phase));
85 int phase = action.phase();
87 m_time_stats->endPhase(
static_cast<eTimePhase>(phase));
88 auto name = action.name();
90 m_time_stats->endAction(name,
false);
96 std::atomic<Int64> m_id;
119 Int64 m_nb_iteration_loop = 0;
123 friend std::ostream& operator<<(std::ostream& o,
const AllActionsInfo& x)
125 o <<
"NbLoop=" << x.m_nb_iteration_loop <<
"\n";
126 o <<
"Name=" << x.m_name_list <<
"\n";
127 o <<
"NbCall=" << x.m_nb_call_list <<
"\n";
128 o <<
"NbChild=" << x.m_nb_child <<
"\n";
129 o <<
"Time=" << x.m_time_list <<
"\n";
137 m_nb_iteration_loop = 0;
140 m_nb_call_list.clear();
147 Action(Action* parent,
const String& name)
158 const String& name()
const {
return m_name; }
159 Action* parent()
const {
return m_parent; }
161 Action* findOrCreateSubAction(
const String& name);
162 void addPhaseValue(
const PhaseValue& new_pv);
164 Action* findSubActionRecursive(
const String& action_name)
const;
167 void dumpJSON(JSONWriter& writer, eTimeType tt);
168 void computeCumulativeTimes();
169 void dumpCurrentStats(std::ostream& ostr,
int level,
Real unit);
205 : m_main_action(
nullptr,
"Main")
210 : m_main_action(nullptr,
"Main")
213 s1.save(action_info);
214 this->merge(action_info);
215 s2.save(action_info);
216 this->merge(action_info);
224 Action* mainAction() {
return &m_main_action; }
225 Int64 nbIterationLoop()
const {
return m_nb_iteration_loop; }
226 void save(AllActionsInfo& all_actions_info)
const
228 all_actions_info.clear();
229 m_main_action.save(all_actions_info);
230 all_actions_info.m_nb_iteration_loop = m_nb_iteration_loop;
232 void merge(AllActionsInfo& all_actions_info)
234 m_nb_iteration_loop += all_actions_info.m_nb_iteration_loop;
236 m_main_action.merge(all_actions_info, &index);
237 m_main_action.computeCumulativeTimes();
239 void dumpStats(std::ostream& ostr,
bool is_verbose,
Real nb,
const String& name,
240 bool use_elapsed_time,
const String& message);
244 Action m_main_action;
245 Int64 m_nb_iteration_loop = 0;
249 void _dumpStats(std::ostream& ostr, Action& action, eTimeType tt,
int level,
int max_level,
Real nb);
250 void _dumpAllPhases(std::ostream& ostr, Action& action, eTimeType tt,
int tc,
Real nb);
251 void _dumpCurrentStats(std::ostream& ostr, Action& action,
int level,
Real unit);
263, m_timer_mng(timer_mng)
264, m_virtual_timer(nullptr)
265, m_real_timer(nullptr)
266, m_is_gathering(false)
267, m_current_action_series(new ActionSeries())
268, m_previous_action_series(new ActionSeries())
269, m_main_action(m_current_action_series->mainAction())
270, m_current_action(m_main_action)
271, m_need_compute_elapsed_time(true)
274, m_metric_collector(new MetricCollector(this))
276 m_phases_type.push(TP_Computation);
287 delete m_metric_collector;
290 delete m_virtual_timer;
305 if (!m_virtual_timer)
310 m_is_gathering =
true;
314 m_virtual_timer->start();
315 m_real_timer->start();
316 m_full_stats_str <<
"<? xml version='1.0'?>\n";
317 m_full_stats_str <<
"<stats>\n";
326 m_virtual_timer->stop();
327 m_real_timer->stop();
329 m_is_gathering =
false;
331 m_full_stats_str <<
"</stats>\n";
337 ofile << m_full_stats_str.str();
345findOrCreateSubAction(
const String& name)
347 Action* sa = subAction(name);
349 sa =
new Action(
this, name);
359beginAction(
const String& action_name)
362 Action* current_action = _currentAction();
363 current_action->addPhaseValue(_currentPhaseValue());
364 Action* sa = current_action->findOrCreateSubAction(action_name);
366 m_full_stats_str <<
"<action name='" << sa->name() <<
"'"
368 m_current_action = sa;
375endAction(
const String& action_name,
bool print_time)
377 ARCANE_UNUSED(action_name);
379 m_need_compute_elapsed_time =
true;
380 TimeStats::PhaseValue pv = _currentPhaseValue();
381 m_current_action->addPhaseValue(pv);
382 m_current_action->addNbCalled();
384 elapsedTime(TP_Computation, m_current_action->name());
385 elapsedTime(TP_Communication, m_current_action->name());
388 m_full_stats_str <<
"</action><!-- " << m_current_action->name() <<
" -->\n";
389 m_current_action = m_current_action->parent();
399 TimeStats::PhaseValue pv = _currentPhaseValue();
400 m_current_action->addPhaseValue(pv);
401 m_current_phase.m_type = phase_type;
402 m_phases_type.push(pv.m_type);
411 ARCANE_UNUSED(phase_type);
413 m_need_compute_elapsed_time =
true;
414 TimeStats::PhaseValue pv = _currentPhaseValue();
415 m_current_action->addPhaseValue(pv);
416 if (m_phases_type.empty())
418 eTimePhase old_phase_type = m_phases_type.top();
420 m_current_phase.m_type = old_phase_type;
429 _computeCumulativeTimes();
430 return m_main_action->m_phases[phase].m_time[TT_Real][TC_Cumulative];
439 _computeCumulativeTimes();
440 Action* action = m_main_action->findSubActionRecursive(action_name);
443 info() <<
"TimeStat: type=" << phase <<
" action=" << action_name
444 <<
" local_Real=" << action->m_phases[phase].m_time[TT_Real][TC_Local]
445 <<
" total_Real=" << action->m_phases[phase].m_time[TT_Real][TC_Cumulative]
446 <<
" local_Virt=" << action->m_phases[phase].m_time[TT_Virtual][TC_Local]
447 <<
" total_Virt=" << action->m_phases[phase].m_time[TT_Virtual][TC_Cumulative];
448 return action->m_phases[phase].m_time[TT_Real][TC_Cumulative];
455findSubActionRecursive(
const String& action_name)
const
459 if (action->name() == action_name)
461 Action* find_action = action->findSubActionRecursive(action_name);
471void TimeStats::ActionSeries::
472dumpStats(std::ostream& ostr,
bool is_verbose,
Real nb,
const String& name,
473 bool use_elapsed_time,
const String& message)
475 Int64 nb_iteration_loop = this->nbIterationLoop();
476 if (nb_iteration_loop != 0)
477 nb = nb * ((
Real)nb_iteration_loop);
478 eTimeType tt = TT_Virtual;
479 if (use_elapsed_time)
481 ostr <<
"-- Execution statistics " << message
482 <<
" (divide=" << nb <<
", nb_loop=" << nb_iteration_loop <<
")";
484 ostr <<
" (clock time)";
485 else if (tt == TT_Virtual)
486 ostr <<
" (CPU time)";
488 std::ios_base::fmtflags f = ostr.flags(std::ios::right);
490 ostr << Trace::Width(50) <<
" Action "
491 << Trace::Width(11) <<
" Time "
492 << Trace::Width(11) <<
" Time "
493 << Trace::Width(8) <<
"N"
495 ostr << Trace::Width(50) <<
" "
496 << Trace::Width(11) <<
"Total(s)"
497 << Trace::Width(11) << (String(
"/") + name +
"(us)")
501 _dumpStats(ostr, m_main_action, tt, 1, 0, nb);
505 Action* action = m_main_action.findSubActionRecursive(
"Loop");
507 _dumpStats(ostr, m_main_action, tt, 1, 3, nb);
509 _dumpStats(ostr, *action, tt, 1, 3, nb);
519 bool use_elapsed_time)
521 _computeCumulativeTimes();
522 ostr <<
"Execution statistics (current execution)\n";
526 ostr <<
"\nExecution statistics (cumulative)\n";
528 cumul_series.dumpStats(ostr, is_verbose, nb, name, use_elapsed_time,
"(cumulative execution)");
538 Action* action = m_main_action->findSubActionRecursive(action_name);
541 _computeCumulativeTimes();
544 action->dumpCurrentStats(ostr(), 1, unit);
545 info() <<
"-- Execution statistics: Action=" << action->name()
554resetStats(
const String& action_name)
556 Action* action = m_main_action->findSubActionRecursive(action_name);
560 m_need_compute_elapsed_time =
true;
569 _writeValue(std::ostream& ostr, Real value, Real unit)
572 Real v2 = value * unit;
584 _printIndentedName(std::ostream& ostr,
const String& name,
int level)
586 StringBuilder indent_str;
587 StringBuilder after_str;
588 for (
int i = 0; i < level; ++i)
589 indent_str.append(
" ");
592 int alen =
static_cast<int>(name.utf8().size());
594 for (
int i = 0; i < 50 - alen; ++i)
603 _printPercentage(std::ostream& ostr,
Real value,
Real cumulative_value)
612 Real z_cumulative_value = cumulative_value;
613 if (z_cumulative_value != 0.0 && !math::isNearlyZero(z_cumulative_value)) {
614 percent = value / z_cumulative_value;
619 ostr << (n_percent / 10) <<
'.' << (n_percent % 10);
626void TimeStats::Action::
627dumpCurrentStats(std::ostream& ostr,
int level,
Real unit)
630 _printIndentedName(ostr, action.name(), level);
631 _writeValue(ostr, action.m_phases[TP_Computation].m_time[TT_Real][TC_Cumulative], unit);
632 _writeValue(ostr, action.m_phases[TP_Communication].m_time[TT_Real][TC_Cumulative], unit);
636 a->dumpCurrentStats(ostr, level + 1, unit);
644_computeCumulativeTimes()
646 if (!m_need_compute_elapsed_time)
648 m_main_action->computeCumulativeTimes();
649 m_need_compute_elapsed_time =
false;
655void TimeStats::ActionSeries::
656_dumpStats(std::ostream& ostr,
Action& action, eTimeType tt,
int level,
int max_level,
Real nb)
658 PhaseValue& pv = action.m_phases[TP_Computation];
659 _printIndentedName(ostr, action.name(), level);
661 if (pv.m_time[TT_Real][TC_Cumulative] != 0.0 || pv.m_time[TT_Virtual][TC_Cumulative] != 0.0) {
662 _dumpAllPhases(ostr, action, tt, TC_Cumulative, nb);
665 if (max_level == 0 || level < max_level) {
668 _dumpStats(ostr, *a, tt, level + 1, max_level, nb);
677_dumpCumulativeTime(std::ostream& ostr,
Action& action,
eTimePhase tp, eTimeType tt)
679 Real current_time = action.m_phases[tp].m_time[tt][TC_Local];
680 Real cumulative_time = action.m_phases[tp].m_time[tt][TC_Cumulative];
683 ostr << current_time <<
' ';
685 ostr << cumulative_time <<
' ';
687 _printPercentage(ostr, current_time, m_main_action->m_phases[tp].m_time[tt][TC_Cumulative]);
688 _printPercentage(ostr, cumulative_time, m_main_action->m_phases[tp].m_time[tt][TC_Cumulative]);
690 Action* parent_action = action.parent();
691 Real parent_time = cumulative_time;
693 parent_time = parent_action->m_phases[tp].m_time[tt][TC_Cumulative];
694 _printPercentage(ostr, cumulative_time, parent_time);
701void TimeStats::ActionSeries::
702_dumpAllPhases(std::ostream& ostr,
Action& action, eTimeType tt,
int tc,
Real nb)
704 Real all_phase_time = action.m_total_time.m_time[tt][tc];
707 ostr << Trace::Width(11) << String::fromNumber(all_phase_time, 3);
715 nb_called = (
Real)action.nbCalled();
717 Real r = all_phase_time * 1.0e6;
718 Real r_nb_called =
static_cast<Real>(nb_called);
720 ct_by_call = r / (r_nb_called + 1.0e-10);
722 ostr << Trace::Width(11) << String::fromNumber(ct_by_call, 3);
727 ostr << action.nbCalled() <<
' ';
729 _printPercentage(ostr, all_phase_time, m_main_action.m_total_time.m_time[tt][tc]);
732 Action* parent_action = action.parent();
733 Real parent_time = all_phase_time;
735 parent_time = parent_action->m_total_time.m_time[tt][tc];
736 _printPercentage(ostr, all_phase_time, parent_time);
741 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase) {
742 _printPercentage(ostr, action.m_phases[phase].m_time[tt][tc], all_phase_time);
743 if ((phase + 1) != NB_TIME_PHASE)
752void TimeStats::Action::
753computeCumulativeTimes()
757 action.m_total_time.m_time[tt][TC_Local] = 0.;
758 action.m_total_time.m_time[tt][TC_Cumulative] = 0.;
759 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase) {
760 Real r = action.m_phases[phase].m_time[tt][TC_Local];
761 action.m_phases[phase].m_time[tt][TC_Cumulative] = r;
762 action.m_total_time.m_time[tt][TC_Cumulative] += r;
763 action.m_total_time.m_time[tt][TC_Local] += r;
769 a->computeCumulativeTimes();
770 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase) {
772 Real r = a->m_phases[phase].m_time[tt][TC_Cumulative];
773 action.m_phases[phase].m_time[tt][TC_Cumulative] += r;
774 action.m_total_time.m_time[tt][TC_Cumulative] += r;
783TimeStats::Action* TimeStats::
786 if (!m_current_action)
787 m_current_action = m_main_action;
788 return m_current_action;
794TimeStats::PhaseValue TimeStats::
797 Real real_time = m_timer_mng->getTime(m_real_timer);
798 Real virtual_time = m_timer_mng->getTime(m_virtual_timer);
800 Real diff_real_time = real_time - m_current_phase.m_time[TT_Real][TC_Local];
801 Real diff_virtual_time = virtual_time - m_current_phase.m_time[TT_Virtual][TC_Local];
802 if (diff_real_time < 0.0 || diff_virtual_time < 0.0)
803 info() <<
"BAD_CURRENT_PHASE_VALUE " << diff_real_time <<
" " << diff_virtual_time
804 <<
" phase=" << m_current_phase.
m_type;
805 m_current_phase.m_time[TT_Real][TC_Local] = real_time;
806 m_current_phase.m_time[TT_Virtual][TC_Local] = virtual_time;
808 m_full_stats_str <<
"<time"
809 <<
" phase='" << m_current_phase.m_type <<
"'"
810 <<
" real_time='" << real_time <<
"'"
812 return PhaseValue(m_current_phase.m_type, diff_real_time, diff_virtual_time);
822 ARCANE_FATAL(
"TimeStats::beginGatherStats() not called");
823 if (!m_current_action)
833 bool is_gather = m_is_gathering && m_current_action;
852 _computeCumulativeTimes();
853 writer.write(
"Version", (
Int64)1);
855 writer.writeKey(
"Current");
856 writer.beginObject();
857 m_main_action->dumpJSON(writer, TT_Real);
863 writer.writeKey(
"Cumulative");
864 writer.beginObject();
865 cumul_series.mainAction()->dumpJSON(writer, TT_Real);
873void TimeStats::Action::
876 Action& action = *
this;
877 writer.writeKey(action.name());
878 writer.beginObject();
880 Real values[NB_TIME_PHASE];
881 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase)
882 values[phase] = action.m_phases[phase].m_time[tt][TC_Local];
884 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase)
885 values[phase] = action.m_phases[phase].m_time[tt][TC_Cumulative];
886 writer.write(
"Cumulative",
RealArrayView(NB_TIME_PHASE, values));
888 if (!action.m_sub_actions.empty()) {
889 writer.writeKey(
"SubActions");
893 a->dumpJSON(writer, tt);
910 m_sub_actions.each(Deleter());
928void TimeStats::Action::
931 m_phases[new_pv.m_type].add(new_pv);
937void TimeStats::Action::
938save(AllActionsInfo& save_info)
const
940 save_info.m_name_list.add(m_name);
941 save_info.m_nb_call_list.add(m_nb_called);
942 save_info.m_nb_child.add(m_sub_actions.count());
943 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase)
945 save_info.m_time_list.add(m_phases[phase].m_time[i][TC_Local]);
946 for (Action* s : m_sub_actions)
953void TimeStats::Action::
954merge(AllActionsInfo& save_info,
Integer* index_ptr)
957 String saved_name = save_info.m_name_list[index];
958 if (saved_name != m_name)
959 ARCANE_FATAL(
"Bad merge name={0} saved={1}", m_name, saved_name);
961 Integer nb_child = save_info.m_nb_child[index];
962 m_nb_called += save_info.m_nb_call_list[index];
965 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase)
967 m_phases[phase].m_time[i][TC_Local] += save_info.m_time_list[pos];
971 for (
Integer i = 0; i < nb_child; ++i) {
972 String next_name = save_info.m_name_list[*index_ptr];
973 Action* a = findOrCreateSubAction(next_name);
974 a->merge(save_info, index_ptr);
988 for (
Integer phase = 0; phase < NB_TIME_PHASE; ++phase)
990 m_phases[phase].m_time[i][TC_Local] = 0.0;
1005 return m_metric_collector;
1014 info(4) <<
"Saving TimeStats values";
1015 Action::AllActionsInfo action_save_info;
1017 cumulative_series.save(action_save_info);
1018 const bool is_verbose =
false;
1020 info() <<
"Saved " << action_save_info;
1023 p->
set(
"Version", 1);
1024 p->
set(
"NbIterationLoop", action_save_info.m_nb_iteration_loop);
1025 p->
set(
"Names", action_save_info.m_name_list);
1026 p->
set(
"NbCalls", action_save_info.m_nb_call_list);
1027 p->
set(
"NbChildren", action_save_info.m_nb_child);
1028 p->
set(
"TimeList", action_save_info.m_time_list);
1035mergeTimeValues(Properties* p)
1037 info(4) <<
"Merging TimeStats values";
1041 Int32 v = p->getInt32WithDefault(
"Version", 0);
1046 info() <<
"Warning: can not merge time stats values because checkpoint version is not compatible";
1050 action_save_info.m_nb_iteration_loop = p->getInt64(
"NbIterationLoop");
1051 p->get(
"Names", action_save_info.m_name_list);
1052 p->get(
"NbCalls", action_save_info.m_nb_call_list);
1053 p->get(
"NbChildren", action_save_info.m_nb_child);
1054 p->get(
"TimeList", action_save_info.m_time_list);
1056 const bool is_verbose =
false;
1058 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.