34 #include <sys/param.h>
38 #include <boost/format.hpp>
89 Timer::Timer(
const CodePoint &cp,
int parent)
96 hash_idx_(cp.hash_idx_),
101 for(
unsigned int i=0; i< max_n_childs ;i++) child_timers[i]=-1;
114 Timer::TimeData Timer::get_time() {
120 double Timer::cumulative_time()
const
122 return 1000.0 * double(cumul_time) / CLOCKS_PER_SEC;
127 void Timer::start() {
128 if (start_count == 0) start_time = get_time();
135 void Timer::update() {
136 TimeData time = get_time();
137 cumul_time += time - start_time;
142 bool Timer::stop(
bool forced) {
144 if (forced) start_count=1;
146 if (start_count == 1) {
147 TimeData time = get_time();
148 cumul_time += time - start_time;
159 void Timer::add_child(
int child_index,
const Timer &child)
161 unsigned int idx = child.hash_idx_;
162 if (child_timers[idx] >0) {
165 i=( i < max_n_childs ? i+1 : 0);
166 }
while (i!=idx && child_timers[i] >0);
167 ASSERT(i!=idx,
"Too many children of the timer with tag '%s'\n", tag() );
170 child_timers[idx] = child_index;
175 string Timer::code_point_str()
const {
176 return boost::str( boost::format(
"%s:%d, %s()") % code_point_->file_ % code_point_->line_ % code_point_->func_ );
190 CodePoint Profiler::null_code_point = CodePoint(
"__no_tag__",
"__no_file__",
"__no_func__", 0);
208 start_time( time(NULL) )
211 #ifdef DEBUG_PROFILER
212 static CONSTEXPR_ CodePoint main_cp = CODE_POINT(
"Whole Program");
213 timers_.push_back( Timer(main_cp, 0) );
222 task_description_ = description;
229 flow_name_ = program_name;
230 flow_version_ = program_version;
231 flow_branch_ = branch;
232 flow_revision_ = revision;
238 int Profiler::start_timer(
const CodePoint &cp) {
240 int child_idx = find_child(cp);
243 child_idx=timers_.size();
244 timers_.push_back( Timer(cp, actual_node) );
245 timers_[actual_node].add_child(child_idx , timers_.back() );
248 timers_[child_idx].start();
249 actual_node=child_idx;
256 int Profiler::find_child(
const CodePoint &cp) {
257 Timer &timer =timers_[actual_node];
258 int idx = cp.hash_idx_;
261 child_idx=timer.child_timers[idx];
263 if (child_idx < 0)
break;
266 if (timers_[child_idx].full_hash_ == cp.hash_)
return child_idx;
267 idx = ( (
unsigned int)(idx)==Timer::max_n_childs ? 0 : idx+1 );
268 }
while ( (
unsigned int)(idx) != cp.hash_idx_ );
274 void Profiler::stop_timer(
const CodePoint &cp) {
275 #ifdef Flow123d_DEBUG
277 Timer &timer=timers_[actual_node];
278 for(
unsigned int i=0; i < Timer::max_n_childs; i++)
279 if (timer.child_timers[i] >0)
280 ASSERT( ! timers_[timer.child_timers[i]].running() ,
"Child timer '%s' running while closing timer '%s'.\n", timers_[timer.child_timers[i]].tag(), timer.tag() );
282 if ( cp.hash_ != timers_[actual_node].full_hash_) {
284 for(
unsigned int node=actual_node; node != 0; node=timers_[node].parent_timer) {
285 if ( cp.hash_ == timers_[node].full_hash_) {
287 for(; (
unsigned int)(actual_node) != node; actual_node=timers_[actual_node].parent_timer) {
288 xprintf(
Warn,
"Timer to close '%s' do not match actual timer '%s'. Force closing actual.\n", cp.tag_, timers_[actual_node].tag());
289 timers_[actual_node].stop(
true);
292 timers_[actual_node].stop(
false);
293 actual_node=timers_[actual_node].parent_timer;
301 timers_[actual_node].stop(
false);
302 actual_node=timers_[actual_node].parent_timer;
307 void Profiler::stop_timer(
int timer_index) {
308 if (timer_index <0) timer_index=actual_node;
311 if (! timers_[timer_index].running() )
return;
313 if ( timer_index != actual_node ) {
315 for(
unsigned int node=actual_node; node != 0; node=timers_[node].parent_timer)
316 if ( (
unsigned int)(timer_index) == node) {
318 for(; (
unsigned int)(actual_node) != node; actual_node=timers_[actual_node].parent_timer) {
319 xprintf(
Warn,
"Timer to close '%s' do not match actual timer '%s'. Force closing actual.\n", timers_[timer_index].tag(), timers_[actual_node].tag());
320 timers_[actual_node].stop(
true);
323 timers_[actual_node].stop(
false);
324 actual_node=timers_[actual_node].parent_timer;
332 timers_[actual_node].stop(
false);
333 actual_node=timers_[actual_node].parent_timer;
338 void Profiler::add_calls(
unsigned int n_calls) {
339 timers_[actual_node].call_count += n_calls-1;
345 timers_[actual_node].total_allocated_ += size;
351 timers_[actual_node].total_deallocated_ += size;
361 Timer &timer = timers_[timer_idx];
363 ASSERT( timer_idx >=0,
"Wrong timer index %d.\n", timer_idx);
364 ASSERT( timer.parent_timer >=0 ,
"Inconsistent tree.\n");
369 int call_count = timer.call_count;
374 double cumul_time = timer.cumulative_time() / 1000;
379 if (timer_idx == 0) parent_time = cumul_time_sum;
382 double percent = parent_time > 1.0e-10 ? cumul_time_sum / parent_time * 100.0 : 0.0;
383 string tree_info = string(2*indent,
' ') +
384 boost::str( boost::format(
"[%.1f] ") % percent )+
386 info.push_back( tree_info );
388 info.push_back( boost::str(boost::format(
"%i%s") % call_count % (call_count_min != call_count_max ?
"*" :
" ")) );
389 info.push_back( boost::str( boost::format(
"%.2f") % (cumul_time_max) ) );
390 info.push_back( boost::str(boost::format(
"%.2f") % (cumul_time_min > 1.0e-10 ? cumul_time_max / cumul_time_min : 1)) );
391 info.push_back( boost::str( boost::format(
"%.2f") % (cumul_time_sum / call_count_sum) ) );
392 info.push_back( boost::str( boost::format(
"%.2f") % (cumul_time_sum) ) );
393 info.push_back( timer.code_point_str() );
395 timers_info.push_back(info);
397 for (
unsigned int i = 0; i < Timer::max_n_childs; i++)
398 if (timer.child_timers[i] > 0)
399 add_timer_info(comm, timers_info, timer.child_timers[i], indent + 1, cumul_time_sum);
404 void Profiler::update_running_timers() {
405 for(
int node=actual_node; node !=0; node = timers_[node].parent_timer)
406 timers_[node].update();
414 const int column_space = 3;
418 update_running_timers();
422 ASSERT(ierr == 0,
"Error in MPI test of rank.");
427 timers_info[0].push_back(
"tag tree");
428 timers_info[0].push_back(
"calls");
429 timers_info[0].push_back(
"Tmax");
430 timers_info[0].push_back(
"max/min");
431 timers_info[0].push_back(
"T/calls");
432 timers_info[0].push_back(
"Ttotal");
433 timers_info[0].push_back(
"code_point");
435 add_timer_info(comm, timers_info, 0, 0, 0.0);
442 for (
unsigned int i = 0; i < timers_info.size(); i++)
443 for (
unsigned int j = 0; j < timers_info[i].size(); j++) width[j] = max( width[j] , (
unsigned int)timers_info[i][j].size() );
445 unsigned int common_length=timers_info[1].back().size();
446 for (
unsigned int i = 2; i < timers_info.size(); i++) {
447 common_length = min( common_length, (
unsigned int) timers_info[i].back().size() );
448 for (
unsigned int j = 0; j < common_length; j++ ) {
449 if (timers_info[1].back().at(j) != timers_info[i].back().at(j)) {
456 for (
unsigned int i = 1; i < timers_info.size(); i++) timers_info[i].back().erase(0, common_length);
462 time_t end_time = time(NULL);
464 const char format[] =
"%x %X";
465 char start_time_string[BUFSIZ] = {0};
466 strftime(start_time_string,
sizeof (start_time_string) - 1, format, localtime(&start_time));
468 char end_time_string[BUFSIZ] = {0};
469 strftime(end_time_string,
sizeof (end_time_string) - 1, format, localtime(&end_time));
473 os <<
"Program name: " << flow_name_ << endl
474 <<
"Program version: " << flow_version_ << endl
475 <<
"Program branch: " << flow_branch_ << endl
476 <<
"Program revision: " << flow_revision_ << endl
477 <<
"Program build: " << flow_build_ << endl << endl;
480 os <<
"Task description: " << task_description_ << endl
481 <<
"Task size: " << task_size_ << endl << endl;
484 os <<
"Run processes count: " << mpi_size << endl;
485 os <<
"Run started at: " << start_time_string << endl;
486 os <<
"Run finished at: " << end_time_string << endl;
488 os << setfill (
'-') << setw (80) <<
"" << endl;
492 for(
unsigned int j=0; j< timers_info[0].size(); j++)
493 os << left << setw(width[j]) << timers_info[0][j] << setw(column_space) <<
"";
496 os << setfill (
'-') << setw (80) <<
"" << endl;
499 for (
unsigned int i = 1; i < timers_info.size(); i++) {
500 for(
unsigned int j=0; j< timers_info[i].size(); j++) {
502 if (j==0 || j==timers_info[i].size()-1 ) os << left;
else os<<
right;
503 os << setw(width[j]) << timers_info[i][j] << setw(column_space) <<
"";
515 char filename[PATH_MAX];
516 strftime(filename,
sizeof (filename) - 1,
"profiler_info_%y.%m.%d_%H-%M-%S.log", localtime(&start_time));
520 ofstream os(full_fname.c_str());
530 ASSERT(
_instance->actual_node==0 ,
"Forbidden to uninitialize the Profiler when actual timer is not zero (but '%s').\n",
538 #else // def DEBUG_PROFILER
540 Profiler* Profiler::_instance = NULL;
554 #endif // def DEBUG_PROFILER