Teuchos Package Browser (Single Doxygen Collection) Version of the Day
Loading...
Searching...
No Matches
Teuchos_StackedTimer.cpp
Go to the documentation of this file.
1// @HEADER
2// ***********************************************************************
3//
4// Teuchos: Common Tools Package
5// Copyright (2004) Sandia Corporation
6//
7// Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8// license for use of this work by or on behalf of the U.S. Government.
9//
10// Redistribution and use in source and binary forms, with or without
11// modification, are permitted provided that the following conditions are
12// met:
13//
14// 1. Redistributions of source code must retain the above copyright
15// notice, this list of conditions and the following disclaimer.
16//
17// 2. Redistributions in binary form must reproduce the above copyright
18// notice, this list of conditions and the following disclaimer in the
19// documentation and/or other materials provided with the distribution.
20//
21// 3. Neither the name of the Corporation nor the names of the
22// contributors may be used to endorse or promote products derived from
23// this software without specific prior written permission.
24//
25// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36//
37// ***********************************************************************
38// @HEADER
39
41#include <limits>
42#include <ctime>
43#include <cctype>
44#include <algorithm>
45#include <fstream>
46#include <sstream>
47
48namespace Teuchos {
49
50
52 level_(std::numeric_limits<unsigned>::max()),name_("INVALID"),parent_(nullptr)
53{}
54
55void error_out(const std::string& msg, const bool)
56{
57 TEUCHOS_TEST_FOR_EXCEPTION(true,std::runtime_error,msg);
58}
59
60
61void
63 for (unsigned i=0; i<level_; ++i)
64 os << " ";
65 os << name_<<":"<<accumulatedTime()<< " [" << count_started_<<"] ("<< count_updates_ <<")"<<std::endl;
66 double t_total = 0;
67 for (size_t i=0; i<sub_timers_.size(); ++i) {
68 t_total += sub_timers_[i].accumulatedTime();
69 sub_timers_[i].report(os);
70 }
71 if ( sub_timers_.size() == 0 )
72 return;
73 for (unsigned i=0; i<=level_; ++i)
74 os << " ";
75 os << "Remainder: " << accumulatedTime() - t_total<<std::endl;
76
77}
78
79const BaseTimer*
80StackedTimer::LevelTimer::findBaseTimer(const std::string &name) const {
81 const BaseTimer* t = nullptr;
82 if (get_full_name() == name) {
83 return this;
84 }
85 else {
86 for (unsigned i=0;i<sub_timers_.size(); ++i){
87 t = sub_timers_[i].findBaseTimer(name);
88 if (t != nullptr)
89 return t;
90 }
91 }
92 return t;
93}
94
96StackedTimer::LevelTimer::findTimer(const std::string &name, bool& found) {
98 auto full_name = get_full_name();
99 if (full_name.size() > name.size())
100 return t;
101 if ( strncmp(full_name.c_str(), name.c_str(), full_name.size()))
102 return t;
103 if (get_full_name() == name) {
104 t = BaseTimer::TimeInfo(this);
105 found = true;
106 }
107 else {
108 for (unsigned i=0;i<sub_timers_.size(); ++i){
109 t = sub_timers_[i].findTimer(name,found);
110 if (found)
111 return t;
112 }
113 }
114 return t;
115}
116
117void
124
125void
131
132void
134 // allocate everything
135 int num_names = flat_names_.size();
140
141 if (options.output_minmax || options.output_histogram || options.output_proc_minmax) {
144 if ( options.output_minmax )
146 else
147 sum_sq_.resize(0);
148 } else {
149 min_.resize(0);
150 max_.resize(0);
151 sum_sq_.resize(0);
152 }
153
154 if (options.output_proc_minmax) {
157 }
158
159
160 if (options.output_histogram ) {
161 hist_.resize(options.num_histogram);
162 for (int i=0;i<options.num_histogram ; ++i)
163 hist_[i].resize(num_names);
164 }
165
166 // Temp data
170 if (options.output_total_updates)
171 updates.resize(num_names);
174
175 if (options.output_histogram)
176 bins.resize(num_names);
177
178 // set initial values
179 for (int i=0;i<num_names; ++i) {
180 bool found = false; // ignore result here
182 time[i] = t.time;
183 count[i] = t.count;
184 used[i] = t.count==0? 0:1;
185 if (options.output_total_updates)
186 updates[i] = t.updates;
187 }
188
189 // Now reduce the data
190 reduce<int, double>(time.getRawPtr(), sum_.getRawPtr(), num_names, REDUCE_SUM, 0, *comm);
191 reduce(count.getRawPtr(), count_.getRawPtr(), num_names, REDUCE_SUM, 0, *comm);
192 reduce(used.getRawPtr(), active_.getRawPtr(), num_names, REDUCE_SUM, 0, *comm);
193
194 if (min_.size()) {
195 reduceAll(*comm, REDUCE_MAX, num_names, time.getRawPtr(), max_.getRawPtr());
196 for (int i=0;i<num_names;++i)
197 if (!used[i])
198 time[i] = max_[i];
199 reduceAll(*comm, REDUCE_MIN, num_names, time.getRawPtr(), min_.getRawPtr());
200 for (int i=0;i<num_names;++i)
201 if (!used[i])
202 time[i] = 0.;
203 if (procmin_.size()) {
206 int commRank = comm->getRank();
207 for (int i=0;i<num_names; ++i) {
208 if (used[i] && (min_[i]==time[i]))
209 procmin[i] = commRank;
210 else
211 procmin[i] = -1;
212 if (used[i] && (max_[i]==time[i]))
213 procmax[i] = commRank;
214 else
215 procmax[i] = -1;
216 }
217 reduceAll(*comm, REDUCE_MAX, num_names, procmin.getRawPtr(), procmin_.getRawPtr());
218 reduceAll(*comm, REDUCE_MAX, num_names, procmax.getRawPtr(), procmax_.getRawPtr());
219 }
220 }
221
222 if (options.output_histogram) {
223 for (int i=0;i<num_names; ++i) {
224
225 double dh = (max_[i]-min_[i])/options.num_histogram;
226 if (dh==0) // Put everything into bin 1
227 dh=1;
228 if (used[i]) {
229 int bin=(time[i]- min_[i])/dh;
230 bins[i] = std::max(std::min(bin,options.num_histogram-1) , 0);
231 } else
232 bins[i] = -1;
233 }
234 // Recycle the used array for the temp bin array
235 for (int j=0; j<options.num_histogram; ++j){
236 for (int i=0;i<num_names; ++i) {
237 if (bins[i] == j )
238 used[i]=1;
239 else
240 used[i]=0;
241 }
242 reduce(used.getRawPtr(), hist_[j].getRawPtr(), num_names, REDUCE_SUM, 0, *comm);
243 }
244 }
245
246 if (sum_sq_.size()) {
247 for (int i=0;i<num_names; ++i)
248 time[i] *= time[i];
249 reduce(time.getRawPtr(), sum_sq_.getRawPtr(), num_names, REDUCE_SUM, 0, *comm);
250 }
251
252}
253
254std::pair<std::string, std::string> getPrefix(const std::string &name) {
255 for (std::size_t i=name.size()-1; i>0; --i)
256 if (name[i] == '@') {
257 return std::pair<std::string, std::string>(name.substr(0,i), name.substr(i+1));
258 }
259 return std::pair<std::string, std::string>(std::string(""), name);
260}
261
262double
264 int print_level,
265 std::vector<bool> &printed,
266 double parent_time,
267 const OutputOptions &options)
268{
269 // This replicates printLevel but counts column width instead of
270 // printing to ostream. This must be kept in sync with printLevel()
271 double total_time = 0.0;
272
273 for (int i=0; i<flat_names_.size(); ++i ) {
274 if (sum_[i]/active_[i] <= options.drop_time)
275 continue;
276 if (printed[i])
277 continue;
278 int level = std::count(flat_names_[i].begin(), flat_names_[i].end(), '@');
279 if ( (level != print_level) || (level >= options.max_levels) )
280 continue;
282 if ( prefix != split_names.first)
283 continue;
284
285 // Output the indentation level and timer name
286 {
287 std::ostringstream os;
288 for (int l=0; l<level; ++l)
289 os << "| ";
290 // Output the timer name
291 os << split_names.second << ": ";
292 alignments_.timer_names_= std::max(alignments_.timer_names_,os.str().size());
293 }
294
295 // output averge time
296 {
297 std::ostringstream os;
298 os << sum_[i]/active_[i];
299 alignments_.average_time_ = std::max(alignments_.average_time_,os.str().size());
300 }
301
302 // output percentage
303 if ( options.output_fraction && parent_time>0) {
304 std::ostringstream os;
305 os << " - "<<sum_[i]/active_[i]/parent_time*100<<"%";
306 alignments_.fraction_ = std::max(alignments_.fraction_,os.str().size());
307 }
308
309 // output count
310 {
311 std::ostringstream os;
312 os << " ["<<count_[i]/active_[i]<<"]";
313 alignments_.count_ = std::max(alignments_.count_,os.str().size());
314 }
315
316 // output total counts
317 if ( options.output_total_updates) {
318 std::ostringstream os;
319 os << " ("<<updates_[i]/active_[i]<<")";
320 alignments_.total_updates_ = std::max(alignments_.total_updates_,os.str().size());
321 }
322
323 // Output min and maxs
324 if ( options.output_minmax && active_[i]>1) {
325 {
326 std::ostringstream os;
327 os << " {min=" << min_[i];
328 alignments_.min_ = std::max(alignments_.min_,os.str().size());
329 }
330 {
331 std::ostringstream os;
332 os << ", max=" << max_[i];
333 if (active_[i] <= 1)
334 os << "}";
335 alignments_.max_ = std::max(alignments_.max_,os.str().size());
336 }
337 if (procmin_.size()) {
338 std::ostringstream os;
339 os << ", proc min=" << procmin_[i];
340 if (active_[i] <= 1)
341 os << "}";
342 alignments_.procmin_ = std::min(alignments_.procmin_,os.str().size());
343 }
344 if (procmax_.size()) {
345 std::ostringstream os;
346 os << ", proc max=" << procmax_[i];
347 if (active_[i] <= 1)
348 os << "}";
349 alignments_.procmax_ = std::max(alignments_.procmax_,os.str().size());
350 }
351 if (active_[i]>1) {
352 std::ostringstream os;
353 os << ", std dev=" << sqrt(std::max<double>(sum_sq_[i]-sum_[i]*sum_[i]/active_[i],0.0)/(active_[i]-1));
354 os << "}";
355 alignments_.stddev_ = std::max(alignments_.stddev_,os.str().size());
356 }
357 }
358 // Output histogram
359 if ( options.output_histogram && active_[i] >1 ) {
360 std::ostringstream os;
361 os << " <";
362 for (int h=0;h<options.num_histogram; ++h) {
363 if (h)
364 os <<", "<<hist_[h][i];
365 else
366 os << hist_[h][i];
367 }
368 os << ">";
369 alignments_.histogram_ = std::max(alignments_.histogram_,os.str().size());
370 }
371
372 printed[i] = true;
374
375 // Print Remainder
376 if (sub_time > 0 ) {
377 if (options.print_names_before_values) {
378 std::ostringstream tmp;
379 for (int l=0; l<=level; ++l)
380 tmp << "| ";
381 tmp << "Remainder: ";
382 alignments_.timer_names_ = std::max(alignments_.timer_names_,tmp.str().size());
383 }
384 {
385 std::ostringstream tmp;
386 tmp << sum_[i]/active_[i]- sub_time;
387 alignments_.average_time_ = std::max(alignments_.average_time_,tmp.str().size());
388 }
389 if ( options.output_fraction && (sum_[i]/active_[i] > 0.) ) {
390 std::ostringstream tmp;
391 tmp << " - "<< (sum_[i]/active_[i]- sub_time)/(sum_[i]/active_[i])*100 << "%";
392 alignments_.fraction_ = std::max(alignments_.fraction_,tmp.str().size());
393 }
394 }
395
397 }
398 return total_time;
399}
400
401double
402StackedTimer::printLevel (std::string prefix, int print_level, std::ostream &os, std::vector<bool> &printed, double parent_time, const OutputOptions &options)
403{
404 // NOTE: If you change the outputting format or logic in this
405 // function, you must make a corresponding change to the function
406 // computeColumnWidthsForAlignment() or the alignments will be
407 // incorrect if the user requests aligned output!
408
409 double total_time = 0.0;
410
411 for (int i=0; i<flat_names_.size(); ++i ) {
412 if (sum_[i]/active_[i] <= options.drop_time) {
413 continue;
414 }
415 if (printed[i])
416 continue;
417 int level = std::count(flat_names_[i].begin(), flat_names_[i].end(), '@');
418 if ( (level != print_level) || (level >= options.max_levels) )
419 continue;
421 if ( prefix != split_names.first)
422 continue;
423
424 // Output the indentation level
425 if (options.print_names_before_values) {
426 std::ostringstream tmp;
427 for (int l=0; l<level; ++l) {
428 tmp << "| ";
429 }
430 // Output the timer name
431 tmp << split_names.second << ": ";
432 if (options.align_columns)
433 os << std::left << std::setw(alignments_.timer_names_);
434 os << tmp.str();
435 }
436 // output averge time
437 {
438 std::ostringstream tmp;
439 tmp << sum_[i]/active_[i];
440 if (options.align_columns)
441 os << std::left << std::setw(alignments_.average_time_);
442 os << tmp.str();
443 }
444 // output percentage
445 if ( options.output_fraction && parent_time>0) {
446 std::ostringstream tmp;
447 tmp << " - "<<sum_[i]/active_[i]/parent_time*100<<"%";
448 if (options.align_columns)
449 os << std::left << std::setw(alignments_.fraction_);
450 os << tmp.str();
451 }
452 // to keep alignment for later columns if requested
453 else if (options.output_fraction) {
454 if (options.align_columns)
455 os << std::setw(alignments_.fraction_) << " ";
456 }
457 // output count
458 {
459 std::ostringstream tmp;
460 tmp << " ["<<count_[i]/active_[i]<<"]";
461 if (options.align_columns)
462 os << std::left << std::setw(alignments_.count_);
463 os << tmp.str();
464 }
465 // output total counts
466 if ( options.output_total_updates ) {
467 std::ostringstream tmp;
468 tmp << " ("<<updates_[i]/active_[i]<<")";
469 if (options.align_columns)
470 os << std::left << std::setw(alignments_.total_updates_);
471 os << tmp.str();
472 }
473 // Output min and maxs
474 if ( options.output_minmax && active_[i]>1) {
475 {
476 std::ostringstream tmp;
477 tmp << " {min="<<min_[i];
478 if (options.align_columns)
479 os << std::left << std::setw(alignments_.min_);
480 os << tmp.str();
481 }
482 {
483 std::ostringstream tmp;
484 tmp <<", max="<<max_[i];
485 if (active_[i] <= 1)
486 tmp << "}";
487 if (options.align_columns)
488 os << std::left << std::setw(alignments_.max_);
489 os << tmp.str();
490 }
491 if (procmin_.size()) {
492 std::ostringstream tmp;
493 tmp <<", proc min="<<procmin_[i];
494 if (active_[i] <= 1)
495 tmp << "}";
496 if (options.align_columns)
497 os << std::left << std::setw(alignments_.procmin_);
498 os << tmp.str();
499 }
500 if (procmax_.size()) {
501 std::ostringstream tmp;
502 tmp <<", proc max="<<procmax_[i];
503 if (active_[i] <= 1)
504 tmp << "}";
505 if (options.align_columns)
506 os << std::left << std::setw(alignments_.procmax_);
507 os << tmp.str();
508 }
509 if (active_[i]>1) {
510 std::ostringstream tmp;
511 tmp << ", std dev="<<sqrt(std::max<double>(sum_sq_[i]-sum_[i]*sum_[i]/active_[i],0.0)/(active_[i]-1));
512 tmp << "}";
513 if (options.align_columns)
514 os << std::left << std::setw(alignments_.stddev_);
515 os << tmp.str();
516 }
517 }
518 else if ( options.output_minmax) {
519 // this block keeps alignment for single rank timers
520 size_t offset = alignments_.min_ + alignments_.max_ + alignments_.stddev_;
521 for (size_t j=0; j < offset; ++j)
522 os << " ";
523 }
524
525 // Output histogram
526 if ( options.output_histogram && active_[i] >1 ) {
527 std::ostringstream tmp;
528 tmp << " <";
529 for (int h=0;h<options.num_histogram; ++h) {
530 if (h)
531 tmp <<", "<<hist_[h][i];
532 else
533 tmp << hist_[h][i];
534 }
535 tmp << ">";
536 if (options.align_columns)
537 os << std::left << std::setw(alignments_.histogram_);
538 os << tmp.str();
539 }
540 else if ( options.output_histogram) {
541 // this block keeps alignment for single rank timers
542 for (size_t j=0; j < alignments_.histogram_; ++j)
543 os << " ";
544 }
545
546 if (! options.print_names_before_values) {
547 std::ostringstream tmp;
548 tmp << " ";
549 for (int l=0; l<level; ++l) {
550 tmp << "| ";
551 }
552 // Output the timer name
553 tmp << split_names.second << ": ";
554 os << tmp.str();
555 }
556
557 os << std::endl;
558 printed[i] = true;
559 double sub_time = printLevel(flat_names_[i], level+1, os, printed, sum_[i]/active_[i], options);
560
561 // Print Remainder
562 if (sub_time > 0 ) {
563 if (options.print_names_before_values) {
564 std::ostringstream tmp;
565 for (int l=0; l<=level; ++l)
566 tmp << "| ";
567 tmp << "Remainder: ";
568 if (options.align_columns)
569 os << std::left << std::setw(alignments_.timer_names_);
570 os << tmp.str();
571 }
572 {
573 std::ostringstream tmp;
574 tmp << sum_[i]/active_[i]- sub_time;
575 if (options.align_columns)
576 os << std::left << std::setw(alignments_.average_time_);
577 os << tmp.str();
578 }
579 if ( options.output_fraction && (sum_[i]/active_[i] > 0.) ) {
580 if (options.align_columns)
581 os << std::left << std::setw(alignments_.fraction_);
582 std::ostringstream tmp;
583 tmp << " - "<< (sum_[i]/active_[i]- sub_time)/(sum_[i]/active_[i])*100 << "%";
584 os << tmp.str();
585 }
586 if (! options.print_names_before_values) {
587 {
588 size_t offset = 0;
589 offset += alignments_.count_;
590 if (options.output_total_updates)
591 offset += alignments_.total_updates_;
592 if (options.output_minmax)
593 offset += alignments_.min_ + alignments_.max_ + alignments_.stddev_;
594 if (options.output_histogram)
595 offset += alignments_.histogram_;
596 for (size_t j=0; j < offset; ++j)
597 os << " ";
598 }
599 std::ostringstream tmp;
600 tmp << " ";
601 for (int l=0; l<=level; ++l)
602 tmp << "| ";
603 tmp << "Remainder: ";
604 if (options.align_columns)
605 os << std::left << std::setw(alignments_.timer_names_);
606 os << tmp.str();
607 }
608 os << std::endl;
609 }
611 }
612 return total_time;
613}
614
615static void printXMLEscapedString(std::ostream& os, const std::string& str)
616{
617 for(char c : str)
618 {
619 switch(c)
620 {
621 case '<':
622 os << "&lt;";
623 break;
624 case '>':
625 os << "&gt;";
626 break;
627 case '\'':
628 os << "&apos;";
629 break;
630 case '"':
631 os << "&quot;";
632 break;
633 case '&':
634 os << "&amp;";
635 break;
636 //NOTE: unescaped curly braces {} are valid in XML,
637 //however Watchr has a bug with parsing them
638 case '{':
639 os << '(';
640 break;
641 case '}':
642 os << ')';
643 break;
644 default:
645 os << c;
646 }
647 }
648}
649
650double
651StackedTimer::printLevelXML (std::string prefix, int print_level, std::ostream& os, std::vector<bool> &printed, double parent_time, const std::string& rootName)
652{
653 constexpr int indSpaces = 2;
654 int indent = indSpaces * print_level;
655
656 double total_time = 0.0;
657
658 for (int i=0; i<flat_names_.size(); ++i) {
659 if (printed[i])
660 continue;
661 int level = std::count(flat_names_[i].begin(), flat_names_[i].end(), '@');
662 if ( level != print_level)
663 continue;
665 if ( prefix != split_names.first)
666 continue;
667 // Output the indentation level
668 for (int j = 0; j < indent; j++)
669 os << " ";
670 os << "<timing name=\"";
671 if(level == 0 && rootName.length())
673 else
675 os << "\" value=\"" << sum_[i]/active_[i] << "\"";
676 printed[i] = true;
677 //note: don't need to pass in prependRoot, since the recursive calls don't apply to the root level
678 //Print the children to a temporary string. If it's empty, can close the current XML element on the same line.
679 std::ostringstream osInner;
681 std::string innerContents = osInner.str();
682 if(innerContents.length())
683 {
684 os << ">\n";
685 os << innerContents;
686 // Print Remainder
687 if (sub_time > 0 ) {
688 for (int j = 0; j < indent + indSpaces; j++)
689 os << " ";
690 os << "<timing name=\"Remainder\" value=\"" << (sum_[i]/active_[i] - sub_time) << "\"/>\n";
691 }
692 //having printed child nodes, close the XML element on its own line
693 for (int j = 0; j < indent; j++)
694 os << " ";
695 os << "</timing>\n";
696 }
697 else
698 {
699 //Just a leaf node.
700 os << "/>\n";
701 }
703 }
704 return total_time;
705}
706
707void
709 flatten();
710 merge(comm);
712 if (rank(*comm) == 0 ) {
713 if (options.print_warnings) {
714 os << "*** Teuchos::StackedTimer::report() - Remainder for a level will be ***"
715 << "\n*** incorrect if a timer in the level does not exist on every rank ***"
716 << "\n*** of the MPI Communicator. ***"
717 << std::endl;
718 }
719 if ( (options.max_levels != INT_MAX) && options.print_warnings) {
720 os << "Teuchos::StackedTimer::report() - max_levels manually set to " << options.max_levels
721 << ". \nTo print more levels, increase value of OutputOptions::max_levels." << std::endl;
722 }
723 if ( (! options.print_names_before_values) && (! options.align_columns)) {
724 options.align_columns = true;
725 if (options.print_warnings)
726 os << "Teuchos::StackedTimer::report() - option print_names_before_values=false "
727 << "\nrequires that the option align_columns=true too. Setting the value for "
728 << "\nalign_column to true."
729 << std::endl;
730 }
731 if (options.align_columns) {
732 std::vector<bool> printed(flat_names_.size(), false);
734 }
735
736 std::vector<bool> printed(flat_names_.size(), false);
737 printLevel("", 0, os, printed, 0., options);
738 }
739}
740
741void
742StackedTimer::reportXML(std::ostream &os, const std::string& datestamp, const std::string& timestamp, Teuchos::RCP<const Teuchos::Comm<int> > comm)
743{
744 flatten();
745 merge(comm);
748 if (rank(*comm) == 0 ) {
749 std::vector<bool> printed(flat_names_.size(), false);
750 os << "<?xml version=\"1.0\"?>\n";
751 os << "<performance-report date=\"" << timestamp << "\" name=\"nightly_run_" << datestamp << "\" time-units=\"seconds\">\n";
752 printLevelXML("", 0, os, printed, 0.0);
753 os << "</performance-report>\n";
754 }
755}
756
757std::string
759 const char* rawWatchrDir = getenv("WATCHR_PERF_DIR");
760 const char* rawBuildName = getenv("WATCHR_BUILD_NAME");
761 const char* rawGitSHA = getenv("TRILINOS_GIT_SHA");
762 const char* rawBuildDateOverride = getenv("WATCHR_BUILD_DATE");
763 //WATCHR_PERF_DIR is required (will also check nonempty below)
764 if(!rawWatchrDir)
765 return "";
766 std::string watchrDir = rawWatchrDir;
767 if(!watchrDir.length())
768 {
769 //Output directory has not been set, so don't produce output.
770 return "";
771 }
772 //But the build name is optional (may be empty)
773 std::string buildName = rawBuildName ? rawBuildName : "";
774 std::string datestamp;
775 std::string timestamp;
776 {
777 char buf[256];
778 time_t t;
779 struct tm* tstruct;
780 time(&t);
781 tstruct = gmtime(&t);
783 {
784 //Parse the year, month, day
785 int year = 0, month = 0, day = 0;
786 sscanf(rawBuildDateOverride, "%d_%d_%d", &year, &month, &day);
787 //Sanity check the values
789 throw std::invalid_argument("$WATCHR_BUILD_DATE has invalid year or is not in YYYY_MM_DD format.");
791 throw std::invalid_argument("$WATCHR_BUILD_DATE has invalid month or is not in YYYY_MM_DD format.");
792 if(day < 1 || day > 31)
793 throw std::invalid_argument("$WATCHR_BUILD_DATE has invalid day or is not in YYYY_MM_DD format.");
794 snprintf(buf, 256, "%04d_%02d_%02d", year, month, day);
795 datestamp = buf;
796 strftime(buf, 256, "T%H:%M:%S", tstruct);
797 std::string justTime = buf;
798 snprintf(buf, 256, "%04d-%02d-%02d", year, month, day);
799 timestamp = std::string(buf) + justTime;
800 }
801 else
802 {
803 strftime(buf, 256, "%Y_%m_%d", tstruct);
804 datestamp = buf;
805 strftime(buf, 256, "%FT%H:%M:%S", tstruct);
806 timestamp = buf;
807 }
808 }
809 flatten();
810 merge(comm);
813 std::string fullFile;
814 //only open the file on rank 0
815 if(rank(*comm) == 0) {
816 std::string nameNoSpaces = name;
817 for(char& c : nameNoSpaces)
818 {
819 if(isspace(c))
820 c = '_';
821 }
822 if(buildName.length())
823 {
824 //In filename, replace all whitespace with underscores
825 std::string buildNameNoSpaces = buildName;
826 for(char& c : buildNameNoSpaces)
827 {
828 if(isspace(c))
829 c = '_';
830 }
831 fullFile = watchrDir + '/' + buildNameNoSpaces + "-" + nameNoSpaces + '_' + datestamp + ".xml";
832 }
833 else
834 fullFile = watchrDir + '/' + nameNoSpaces + '_' + datestamp + ".xml";
835 std::ofstream os(fullFile);
836 std::vector<bool> printed(flat_names_.size(), false);
837 os << "<?xml version=\"1.0\"?>\n";
838 os << "<performance-report date=\"" << timestamp << "\" name=\"nightly_run_" << datestamp << "\" time-units=\"seconds\">\n";
839 if(rawGitSHA)
840 {
841 std::string gitSHA(rawGitSHA);
842 //Output the first 10 (hex) characters
843 if(gitSHA.length() > 10)
844 gitSHA = gitSHA.substr(0, 10);
845 os << " <metadata key=\"Trilinos Version\" value=\"" << gitSHA << "\"/>\n";
846 }
847 printLevelXML("", 0, os, printed, 0.0, buildName + ": " + name);
848 os << "</performance-report>\n";
849 }
850 return fullFile;
851}
852
855
858
861
864
867
868} //namespace Teuchos
T * getRawPtr()
Return a raw pointer to beginning of array or NULL if unsized.
size_type size() const
void resize(size_type new_size, const value_type &x=value_type())
the basic timer used elsewhere, uses MPI_Wtime for time
int size(const Comm< Ordinal > &comm)
Get the number of processes in the communicator.
Smart reference counting pointer class for automatic garbage collection.
Concrete serial communicator subclass.
void addTimerNames(Array< std::string > &names, unsigned &pos)
BaseTimer::TimeInfo findTimer(const std::string &name, bool &found)
const BaseTimer * findBaseTimer(const std::string &name) const
LevelTimer()
Default constructor, shouldn't be used but needed for std::vector.
struct Teuchos::StackedTimer::AlignmentWidths alignments_
double computeColumnWidthsForAligment(std::string prefix, int print_level, std::vector< bool > &printed, double parent_time, const OutputOptions &options)
void collectRemoteData(Teuchos::RCP< const Teuchos::Comm< int > > comm, const OutputOptions &options)
Array< Array< int > > hist_
Teuchos::RCP< std::ostream > verbose_ostream_
For debugging, this is the ostream used for printing.
double printLevelXML(std::string prefix, int level, std::ostream &os, std::vector< bool > &printed, double parent_time, const std::string &rootName="")
Array< unsigned long long > updates_
void report(std::ostream &os)
void enableVerboseTimestamps(const unsigned levels)
Enable timestamps in verbose mode for the number of levels specified.
Array< std::string > flat_names_
void setVerboseOstream(const Teuchos::RCP< std::ostream > &os)
Set the ostream for verbose mode(defaults to std::cout).
bool enable_timers_
Used to disable timers for asynchronous work.
Array< unsigned long > count_
unsigned verbose_timestamp_levels_
If set to a value greater than 0, verbose mode will print that many levels of timers with timestamps....
double accumulatedTime(const std::string &name="")
LevelTimer timer_
Base timer.
bool enable_verbose_
If set to true, prints to the debug ostream. At construction, default value is set from environment v...
void merge(Teuchos::RCP< const Teuchos::Comm< int > > comm)
double printLevel(std::string prefix, int level, std::ostream &os, std::vector< bool > &printed, double parent_time, const OutputOptions &options)
void enableVerbose(const bool enable_verbose)
If set to true, print timer start/stop to verbose ostream.
std::string reportWatchrXML(const std::string &name, Teuchos::RCP< const Teuchos::Comm< int > > comm)
void reportXML(std::ostream &os, const std::string &datestamp, const std::string &timestamp, Teuchos::RCP< const Teuchos::Comm< int > > comm)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
static void printXMLEscapedString(std::ostream &os, const std::string &str)
std::pair< std::string, std::string > getPrefix(const std::string &name)
void mergeCounterNames(const Comm< int > &comm, const Array< std::string > &localNames, Array< std::string > &globalNames, const ECounterSetOp setOp)
Merge counter names over all processors.
void reduce< int, double >(const double sendBuf[], double recvBuf[], const int count, const EReductionType reductType, const int root, const Comm< int > &comm)
void error_out(const std::string &msg, const bool)
Error reporting function for stacked timer.