LCOV - code coverage report
Current view: top level - src/utils - perf_log.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 313 347 90.2 %
Date: 2025-08-19 19:27:09 Functions: 12 19 63.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : #include "libmesh/perf_log.h"
      19             : 
      20             : // Local includes
      21             : #include "libmesh/int_range.h"
      22             : #include "libmesh/timestamp.h"
      23             : 
      24             : // C++ includes
      25             : #include <algorithm>
      26             : #include <iostream>
      27             : #include <iomanip>
      28             : #include <cstring>
      29             : #include <ctime>
      30             : #ifdef LIBMESH_HAVE_UNISTD_H
      31             : #include <unistd.h> // for getuid()
      32             : #endif
      33             : #include <sys/types.h>
      34             : #include <vector>
      35             : #include <sstream>
      36             : 
      37             : #ifdef LIBMESH_HAVE_SYS_UTSNAME_H
      38             : #include <sys/utsname.h>
      39             : #endif
      40             : 
      41             : #ifdef LIBMESH_HAVE_PWD_H
      42             : #include <pwd.h>
      43             : #endif
      44             : 
      45             : namespace libMesh
      46             : {
      47             : 
      48             : 
      49             : // ------------------------------------------------------------
      50             : // PerfLog class member functions
      51             : 
      52             : bool PerfLog::called = false;
      53             : 
      54             : 
      55      318988 : PerfLog::PerfLog(std::string ln,
      56      318988 :                  const bool le) :
      57      312672 :   label_name(std::move(ln)),
      58      305948 :   log_events(le),
      59      305948 :   summarize_logs(false),
      60      318988 :   total_time(0.)
      61             : {
      62      318988 :   gettimeofday (&tstart, nullptr);
      63             : 
      64      318988 :   if (log_events)
      65        1773 :     this->clear();
      66      318988 : }
      67             : 
      68             : 
      69             : 
      70      325304 : PerfLog::~PerfLog()
      71             : {
      72      318988 :   if (log_events)
      73        1773 :     this->print_log();
      74      318988 : }
      75             : 
      76             : 
      77             : 
      78       18221 : void PerfLog::clear()
      79             : {
      80       18221 :   if (log_events)
      81             :     {
      82             :       //  check that all events are closed
      83       87103 :       for (auto pos : log)
      84       84339 :         libmesh_error_msg_if(pos.second.open,
      85             :                              "ERROR clearing performance log for class "
      86             :                              << label_name
      87             :                              << "\nevent "
      88             :                              << pos.first.second
      89             :                              << " is still being monitored!");
      90             : 
      91        2764 :       gettimeofday (&tstart, nullptr);
      92             : 
      93         948 :       log.clear();
      94             : 
      95        2764 :       while (!log_stack.empty())
      96           0 :         log_stack.pop();
      97             :     }
      98       18221 : }
      99             : 
     100             : 
     101             : 
     102      655907 : void PerfLog::push (const std::string & label,
     103             :                     const std::string & header)
     104             : {
     105             :   const char * label_c_str;
     106             :   const char * header_c_str;
     107             : 
     108      655907 :   if (const auto label_it = non_temporary_strings.find(label);
     109       50601 :       label_it != non_temporary_strings.end())
     110       48503 :     label_c_str = label_it->second.get();
     111             :   else
     112             :     {
     113       54312 :       const std::size_t labelsizep1 = label.size()+1;
     114       54312 :       auto newcopy = std::make_unique<char[]>(labelsizep1);
     115       54312 :       std::strncpy(newcopy.get(), label.c_str(), labelsizep1);
     116        2098 :       label_c_str = newcopy.get();
     117       54312 :       non_temporary_strings[label] = std::move(newcopy);
     118             :     }
     119             : 
     120      655907 :   if (const auto header_it = non_temporary_strings.find(header);
     121       50601 :       header_it != non_temporary_strings.end())
     122       49679 :     header_c_str = header_it->second.get();
     123             :   else
     124             :     {
     125       16433 :       const std::size_t headersizep1 = header.size()+1;
     126       16433 :       auto newcopy = std::make_unique<char[]>(headersizep1);
     127       16433 :       std::strncpy(newcopy.get(), header.c_str(), headersizep1);
     128         922 :       header_c_str = newcopy.get();
     129       16433 :       non_temporary_strings[header] = std::move(newcopy);
     130             :     }
     131             : 
     132      655907 :   if (this->log_events)
     133      493331 :     this->fast_push(label_c_str, header_c_str);
     134      655907 : }
     135             : 
     136             : 
     137             : 
     138      350881 : void PerfLog::push (const char * label,
     139             :                     const char * header)
     140             : {
     141      660281 :   this->push(std::string(label), std::string(header));
     142      350881 : }
     143             : 
     144             : 
     145             : 
     146             : 
     147             : 
     148      655907 : void PerfLog::pop (const std::string & label,
     149             :                    const std::string & header)
     150             : {
     151             : 
     152      655907 :   const char * label_c_str = non_temporary_strings[label].get();
     153      655907 :   const char * header_c_str = non_temporary_strings[header].get();
     154             : 
     155             :   // This could happen if users are *mixing* string and char* APIs for
     156             :   // the same label/header combination.  For perfect backwards
     157             :   // compatibility we should handle that, but there's just no fast way
     158             :   // to do so.
     159       50601 :   libmesh_assert(label_c_str);
     160       50601 :   libmesh_assert(header_c_str);
     161             : 
     162      655907 :   if (this->log_events)
     163      493331 :     this->fast_pop(label_c_str, header_c_str);
     164      655907 : }
     165             : 
     166             : 
     167             : 
     168      350881 : void PerfLog::pop (const char * label,
     169             :                    const char * header)
     170             : {
     171      660281 :   this->pop(std::string(label), std::string(header));
     172      350881 : }
     173             : 
     174             : 
     175             : 
     176        1552 : std::string PerfLog::get_info_header() const
     177             : {
     178        2400 :   std::ostringstream oss;
     179             : 
     180        1552 :   if (log_events)
     181             :     {
     182        1976 :       std::string date = Utility::get_timestamp();
     183             : 
     184             : #ifdef LIBMESH_HAVE_SYS_UTSNAME_H
     185             :       // Get system information
     186             :       struct utsname sysInfo;
     187        1552 :       uname(&sysInfo);
     188             : #endif
     189             : 
     190             :       // Get user information
     191             :       //
     192             :       // Some systems, for example Crays, actually have getpwuid on the head-node
     193             :       // but (if I understand correctly) a dynamically-linked glibc is not available
     194             :       // on the backend, which is running a reduced operating system like Compute
     195             :       // Node Linux.  Thus functions like getpwuid cannot be called.  This makes
     196             :       // automatically testing for the existence of getpwuid on the login node
     197             :       // difficult.  The configure test would work on the login node but will fail
     198             :       // on the backend.  Hence we have added a configure flag, --disable-getpwuid,
     199             :       // to manually turn this off.
     200             : #ifdef LIBMESH_HAVE_GETPWUID
     201        1552 :       struct passwd * p = getpwuid(getuid());
     202             : #endif
     203        1552 :       oss << "\n";
     204             : 
     205             :       // Construct string stream objects for each of the outputs
     206             :       std::ostringstream
     207        2400 :         pid_stream,
     208        2400 :         nprocs_stream,
     209        2400 :         time_stream,
     210        2400 :         os_stream,
     211        2400 :         host_stream,
     212        2400 :         osrel_stream,
     213        2400 :         osver_stream,
     214        2400 :         machine_stream,
     215        2400 :         user_stream;
     216             : 
     217             : 
     218             :       // Put pointers to these streams in a vector
     219         848 :       std::vector<std::ostringstream*> v;
     220        1552 :       v.push_back(&pid_stream);
     221        1552 :       v.push_back(&nprocs_stream);
     222        1552 :       v.push_back(&time_stream);
     223        1552 :       v.push_back(&os_stream);
     224        1552 :       v.push_back(&host_stream);
     225        1552 :       v.push_back(&osrel_stream);
     226        1552 :       v.push_back(&osver_stream);
     227        1552 :       v.push_back(&machine_stream);
     228        1552 :       v.push_back(&user_stream);
     229             : 
     230             :       // Fill string stream objects
     231        1552 :       if (libMesh::global_n_processors() > 1)
     232             :         {
     233        1109 :           pid_stream     << "| Processor id:   " << libMesh::global_processor_id();
     234        1109 :           nprocs_stream  << "| Num Processors: " << libMesh::global_n_processors();
     235             :         }
     236             : 
     237        1552 :       time_stream    << "| Time:           ";
     238        1552 :       os_stream      << "| OS:             ";
     239        1552 :       host_stream    << "| HostName:       ";
     240        1552 :       osrel_stream   << "| OS Release:     ";
     241        1552 :       osver_stream   << "| OS Version:     ";
     242        1552 :       machine_stream << "| Machine:        ";
     243             : 
     244         424 :       time_stream << date;
     245             : #ifdef LIBMESH_HAVE_SYS_UTSNAME_H
     246        1552 :       os_stream      << sysInfo.sysname     ;
     247        1552 :       host_stream    << sysInfo.nodename    ;
     248        1552 :       osrel_stream   << sysInfo.release     ;
     249        1552 :       osver_stream   << sysInfo.version     ;
     250        1552 :       machine_stream << sysInfo.machine     ;
     251             : #else
     252             :       os_stream      << "Unknown";
     253             :       host_stream    << "Unknown";
     254             :       osrel_stream   << "Unknown";
     255             :       osver_stream   << "Unknown";
     256             :       machine_stream << "Unknown";
     257             : 
     258             : #endif
     259        1552 :       user_stream    << "| Username:       ";
     260             : #ifdef LIBMESH_HAVE_GETPWUID
     261        1552 :       if (p && p->pw_name)
     262        1552 :         user_stream  << p->pw_name;
     263             :       else
     264             : #endif
     265           0 :         user_stream  << "Unknown";
     266             : 
     267             :       // Parse the LIBMESH_CONFIGURE_INFO string literal before using it in PerfLog output
     268        1976 :       std::string libmesh_configure_info(LIBMESH_CONFIGURE_INFO);
     269         848 :       std::vector<std::string> parsed_libmesh_configure_info;
     270        1552 :       this->split_on_whitespace(libmesh_configure_info,
     271             :                                 parsed_libmesh_configure_info);
     272             : 
     273             :       // There should always be at at least one entry in
     274             :       // parsed_libmesh_configure_info, even if the user just ran
     275             :       // ../configure.
     276         424 :       libmesh_assert_greater (parsed_libmesh_configure_info.size(), 0);
     277             : 
     278             :       // Find the longest string in all the streams
     279         424 :       unsigned int max_length = 0;
     280       15520 :       for (auto & v_i : v)
     281       17784 :         if (v_i->str().size() > max_length)
     282             :           max_length = cast_int<unsigned int>
     283       11292 :             (v_i->str().size());
     284             : 
     285             :       // Find the longest string in the parsed_libmesh_configure_info
     286       28134 :       for (auto & plci_i : parsed_libmesh_configure_info)
     287       26582 :         if (plci_i.size() > max_length)
     288           0 :           max_length = cast_int<unsigned int> (plci_i.size());
     289             : 
     290             :       // Print dashed line for the header
     291             :       oss << ' '
     292        1976 :           << std::string(max_length+1, '-')
     293        3104 :           << '\n';
     294             : 
     295             :       // Loop over all the strings and add end formatting
     296       15520 :       for (auto & v_i : v)
     297             :         {
     298       24120 :           if (v_i->str().size())
     299       27860 :             oss << v_i->str()
     300             :                 << std::setw (cast_int<int>
     301       27860 :                               (max_length + 4 - v_i->str().size()))
     302        3816 :                 << std::right
     303       13930 :                 << "|\n";
     304             :         }
     305             : 
     306             :       // Print out configuration header plus first parsed string.  The
     307             :       // magic number 18 below accounts for the length of the word
     308             :       // 'Configuration'.
     309             :       oss << "| Configuration:  "
     310         848 :           << parsed_libmesh_configure_info[0]
     311             :           << std::setw (cast_int<int>
     312        2400 :                         (max_length + 4 -
     313        2256 :                          parsed_libmesh_configure_info[0].size() - 18))
     314         424 :           << std::right
     315        1552 :           << "|\n";
     316             : 
     317             :       // Loop over the parsed_libmesh_configure_info and add end formatting.  The magic
     318             :       // number 3 below accounts for the leading 'pipe' character and indentation
     319       26582 :       for (auto i : IntRange<std::size_t>(1, parsed_libmesh_configure_info.size()))
     320             :         {
     321             :           oss << "|  "
     322       14416 :               << parsed_libmesh_configure_info[i]
     323             :               << std::setw (cast_int<int>
     324       32238 :                             (max_length + 4 -
     325       42852 :                              parsed_libmesh_configure_info[i].size() - 3))
     326        7208 :               << std::right
     327       25030 :               << "|\n";
     328             :         }
     329             : 
     330             : 
     331             :       // Print dashed line
     332             :       oss << ' '
     333        1976 :           << std::string(max_length+1, '-')
     334        3104 :           << '\n';
     335        1408 :     }
     336             : 
     337        1976 :   return oss.str();
     338         704 : }
     339             : 
     340             : 
     341             : 
     342             : 
     343        1600 : std::string PerfLog::get_perf_info() const
     344             : {
     345        2496 :   std::ostringstream oss;
     346             : 
     347        1600 :   if (!log_events || log.empty())
     348           0 :     return oss.str();
     349             : 
     350             :   // Stop timing for this event.
     351             :   struct timeval tstop;
     352             : 
     353        1600 :   gettimeofday (&tstop, nullptr);
     354             : 
     355        2496 :   const double elapsed_time = (static_cast<double>(tstop.tv_sec  - tstart.tv_sec) +
     356        1600 :                                static_cast<double>(tstop.tv_usec - tstart.tv_usec)*1.e-6);
     357             : 
     358             :   // Figure out the formatting required based on the event names
     359             :   // Unsigned ints for each of the column widths
     360         448 :   unsigned int event_col_width            = 30;
     361         448 :   const unsigned int ncalls_col_width     = 11;
     362         448 :   const unsigned int tot_time_col_width   = 12;
     363         448 :   const unsigned int avg_time_col_width   = 12;
     364         448 :   const unsigned int tot_time_incl_sub_col_width   = 12;
     365         448 :   const unsigned int avg_time_incl_sub_col_width   = 12;
     366         448 :   const unsigned int pct_active_col_width = 9;
     367         448 :   const unsigned int pct_active_incl_sub_col_width = 9;
     368             : 
     369             :   // Reset the event column width based on the longest event name plus
     370             :   // a possible 2-character indentation, plus a space.
     371       45370 :   for (auto pos : log)
     372       43770 :     if (std::strlen(pos.first.second)+3 > event_col_width)
     373             :       event_col_width = cast_int<unsigned int>
     374        2140 :         (std::strlen(pos.first.second)+3);
     375             : 
     376             :   // Set the total width of the column
     377        1600 :   const unsigned int total_col_width =
     378             :     event_col_width     +
     379             :     ncalls_col_width    +
     380             :     tot_time_col_width  +
     381             :     avg_time_col_width  +
     382             :     tot_time_incl_sub_col_width  +
     383             :     avg_time_incl_sub_col_width  +
     384             :     pct_active_col_width+
     385             :     pct_active_incl_sub_col_width+1;
     386             : 
     387             :   // Print dashed line
     388             :   oss << ' '
     389        1600 :       << std::string(total_col_width, '-')
     390        3200 :       << '\n';
     391             : 
     392             :   {
     393             :     // Construct temporary message string
     394        2048 :     std::ostringstream temp;
     395        1856 :     temp << "| " << label_name << " Performance: Alive time=" << elapsed_time
     396        1600 :          << ", Active time=" << total_time;
     397             : 
     398             :     // Get the size of the temporary string
     399             :     const unsigned int temp_size = cast_int<unsigned int>
     400        2048 :       (temp.str().size());
     401             : 
     402             :     // Send the temporary message to the output
     403        1152 :     oss << temp.str();
     404             : 
     405             :     // If this string is longer than the previously computed total
     406             :     // column width, skip the additional formatting... this shouldn't
     407             :     // happen often, hopefully.  Add two additional characters for a
     408             :     // space and a "|" character at the end.
     409        1600 :     if (temp_size < total_col_width+2)
     410        1600 :       oss << std::setw(total_col_width - temp_size + 2)
     411         448 :           << std::right
     412        1600 :           << "|";
     413             : 
     414        1600 :     oss << '\n';
     415         704 :   }
     416             : 
     417             :   // Print dashed line
     418             :   oss << ' '
     419        2048 :       << std::string(total_col_width, '-')
     420        3200 :       << '\n';
     421             : 
     422             : 
     423             :   // Write out the header for the events listing
     424             :   oss << "| "
     425        1600 :       << std::setw(event_col_width)
     426         448 :       << std::left
     427             :       << "Event"
     428        1152 :       << std::setw(ncalls_col_width)
     429         448 :       << std::left
     430             :       << "nCalls"
     431        1152 :       << std::setw(tot_time_col_width)
     432         448 :       << std::left
     433             :       << "Total Time"
     434        1152 :       << std::setw(avg_time_col_width)
     435         448 :       << std::left
     436             :       << "Avg Time"
     437        1152 :       << std::setw(tot_time_incl_sub_col_width)
     438         448 :       << std::left
     439             :       << "Total Time"
     440        1152 :       << std::setw(avg_time_incl_sub_col_width)
     441         448 :       << std::left
     442             :       << "Avg Time"
     443        1152 :       << std::setw(pct_active_col_width+pct_active_incl_sub_col_width)
     444         448 :       << std::left
     445             :       << "% of Active Time"
     446             :       << "|\n"
     447             :       << "| "
     448        1152 :       << std::setw(event_col_width)
     449         448 :       << std::left
     450             :       << ""
     451        1152 :       << std::setw(ncalls_col_width)
     452         448 :       << std::left
     453             :       << ""
     454        1152 :       << std::setw(tot_time_col_width)
     455         448 :       << std::left
     456             :       << "w/o Sub"
     457        1152 :       << std::setw(avg_time_col_width)
     458         448 :           << std::left
     459             :       << "w/o Sub"
     460        1152 :       << std::setw(tot_time_incl_sub_col_width)
     461         448 :       << std::left
     462             :       << "With Sub"
     463        1152 :       << std::setw(avg_time_incl_sub_col_width)
     464         448 :       << std::left
     465             :       << "With Sub"
     466        1152 :       << std::setw(pct_active_col_width)
     467         448 :       << std::left
     468             :       << "w/o S"
     469        1152 :       << std::setw(pct_active_incl_sub_col_width)
     470         448 :       << std::left
     471             :       << "With S"
     472             :       << "|\n|"
     473        1600 :       << std::string(total_col_width, '-')
     474             :       << "|\n|"
     475        2048 :       << std::string(total_col_width, ' ')
     476        3904 :       << "|\n";
     477             : 
     478         448 :   unsigned int summed_function_calls = 0;
     479         448 :   double       summed_total_time     = 0;
     480         448 :   double       summed_percentage     = 0;
     481             : 
     482        2048 :   std::string last_header("");
     483             : 
     484             :   // Make a new log to sort entries alphabetically
     485         896 :   std::map<std::pair<std::string, std::string>, PerfData> string_log;
     486             : 
     487       45370 :   for (auto char_data : log)
     488       43770 :     if (summarize_logs)
     489             :       {
     490        4146 :         string_log[std::make_pair(std::string(), char_data.first.first)] +=
     491        1382 :           char_data.second;
     492             :       }
     493             :     else
     494             :       {
     495       21463 :         string_log[std::make_pair(char_data.first.first,
     496       64237 :                                   char_data.first.second)] =
     497             :           char_data.second;
     498             :       }
     499             : 
     500       43006 :   for (auto pos : string_log)
     501             :     {
     502       21571 :       const PerfData & perf_data = pos.second;
     503             : 
     504             :       // Only print the event if the count is non-zero.
     505       41406 :       if (perf_data.count != 0)
     506             :         {
     507       21571 :           const unsigned int perf_count    = perf_data.count;
     508       41406 :           const double       perf_time     = perf_data.tot_time;
     509       41406 :           const double       perf_avg_time = perf_time / static_cast<double>(perf_count);
     510       41406 :           const double       perf_time_incl_sub     = perf_data.tot_time_incl_sub;
     511       41406 :           const double       perf_avg_time_incl_sub = perf_time_incl_sub / static_cast<double>(perf_count);
     512       41406 :           const double       perf_percent  = (total_time != 0.) ? perf_time / total_time * 100. : 0.;
     513       41406 :           const double       perf_percent_incl_sub  = (total_time != 0.) ? perf_time_incl_sub / total_time * 100. : 0.;
     514             : 
     515       41406 :           summed_function_calls += perf_count;
     516       41406 :           summed_total_time     += perf_time;
     517       41406 :           summed_percentage     += perf_percent;
     518             : 
     519             :           // Print the event name
     520       41406 :           if (pos.first.first == "")
     521             :             oss << "| "
     522        2148 :                 << std::setw(event_col_width)
     523         304 :                 << std::left
     524         304 :                 << pos.first.second;
     525             : 
     526             :           else
     527             :             {
     528       38954 :               if (last_header != pos.first.first)
     529             :                 {
     530        7949 :                   last_header = pos.first.first;
     531             : 
     532             :                   // print blank line followed by header name
     533             :                   // (account for additional space before the
     534             :                   // header)
     535             :                   oss << "|"
     536       23433 :                       << std::string(total_col_width, ' ')
     537             :                       << "|\n| "
     538       23433 :                       << std::setw(total_col_width-1)
     539        7949 :                       << std::left
     540             :                       << pos.first.first
     541       15484 :                       << "|\n";
     542             :                 }
     543             : 
     544             :               oss << "|   "
     545       38954 :                   << std::setw(event_col_width-2)
     546       21267 :                   << std::left
     547       21267 :                   << pos.first.second;
     548             :             }
     549             : 
     550             : 
     551             :           // Print the number of calls to the event.
     552       21571 :           oss << std::setw(ncalls_col_width)
     553       21571 :               << perf_count;
     554             : 
     555             :           // Save the original stream flags
     556       39562 :           std::ios_base::fmtflags out_flags = oss.flags();
     557             : 
     558             :           // Print the total time spent in the event
     559       21571 :           oss << std::fixed
     560             :               << std::setprecision(4)
     561       21571 :               << std::setw(tot_time_col_width)
     562       21571 :               << std::left
     563       21571 :               << perf_time;
     564             : 
     565             : 
     566             :           // Print the average time per function call
     567       21571 :           oss << std::fixed
     568             :               << std::setprecision(6)
     569       21571 :               << std::setw(avg_time_col_width)
     570       21571 :               << std::left
     571       21571 :               << perf_avg_time;
     572             : 
     573             :           // Print the total time spent in the event incl. sub-events
     574       21571 :           oss << std::fixed
     575             :               << std::setprecision(4)
     576       21571 :               << std::setw(tot_time_incl_sub_col_width)
     577       21571 :               << std::left
     578       21571 :               << perf_time_incl_sub;
     579             : 
     580             :           // Print the average time per function call incl. sub-events
     581       21571 :           oss << std::fixed
     582             :               << std::setprecision(6)
     583       21571 :               << std::setw(avg_time_incl_sub_col_width)
     584       21571 :               << std::left
     585       21571 :               << perf_avg_time_incl_sub;
     586             : 
     587             :           // Print the percentage of the time spent in the event
     588       21571 :           oss << std::fixed
     589             :               << std::setprecision(2)
     590       21571 :               << std::setw(pct_active_col_width)
     591       21571 :               << std::left
     592       21571 :               << perf_percent;
     593             : 
     594             :           // Print the percentage of the time spent in the event incl. sub-events
     595       21571 :           oss << std::fixed
     596             :               << std::setprecision(2)
     597       21571 :               << std::setw(pct_active_incl_sub_col_width)
     598       21571 :               << std::left
     599       21571 :               << perf_percent_incl_sub;
     600             : 
     601             :           // Reset the stream flags
     602       21571 :           oss.flags(out_flags);
     603             : 
     604       41406 :           oss << "|\n";
     605             :         }
     606             :     }
     607             : 
     608             :   oss << ' '
     609        1600 :       << std::string(total_col_width, '-')
     610             :       << "\n| "
     611        2752 :       << std::setw(event_col_width)
     612         448 :       << std::left
     613        1600 :       << "Totals:";
     614             : 
     615             :   // Print the total number of logged function calls
     616             :   // For routines which are called many times, summed_function_calls may
     617             :   // exceed 7 digits.  If this happens use, scientific notation.
     618        1600 :   if (summed_function_calls < 9999999)
     619         448 :     oss << std::setw(ncalls_col_width)
     620         448 :         << summed_function_calls;
     621             : 
     622             :   else
     623             :     {
     624             :       // Save the original stream flags
     625           0 :       std::ios_base::fmtflags out_flags = oss.flags();
     626             : 
     627           0 :       oss << std::scientific
     628             :           << std::setprecision(3)
     629           0 :           << std::setw(ncalls_col_width)
     630           0 :           << std::left
     631           0 :           << static_cast<Real>(summed_function_calls);
     632             : 
     633             :       // Reset the stream flags
     634           0 :       oss.flags(out_flags);
     635             :     }
     636             : 
     637             :   // Print the total time spent in logged function calls.  Don't bother saving/restoring
     638             :   // the flags here since we are almost done with this stream anyway...
     639         448 :   oss << std::fixed
     640             :       << std::setprecision(4)
     641         448 :       << std::setw(tot_time_col_width)
     642         448 :       << std::left
     643         448 :       << summed_total_time;
     644             : 
     645             :   // Null, the average time doesn't make sense as a total
     646        1600 :   oss << std::setw(avg_time_col_width) << "";
     647             : 
     648             :   // Same for times that include sub-events
     649             :   oss << std::setw(tot_time_incl_sub_col_width)
     650             :       << ""
     651             :       << std::setw(avg_time_incl_sub_col_width)
     652        1600 :       << "";
     653             : 
     654             :   // Print the total percentage followed by dashed line
     655         448 :   oss << std::fixed
     656             :       << std::setprecision(2)
     657         448 :       << std::setw(pct_active_col_width)
     658         448 :       << std::left
     659         448 :       << summed_percentage
     660             :       << std::setw(pct_active_incl_sub_col_width)
     661             :       << ""
     662             :       << "|\n "
     663        2048 :       << std::string(total_col_width, '-')
     664        2752 :       << '\n';
     665             : 
     666         448 :   return oss.str();
     667         704 : }
     668             : 
     669             : 
     670             : 
     671        2697 : std::string PerfLog::get_log() const
     672             : {
     673        4593 :   std::ostringstream oss;
     674             : 
     675        2697 :   if (log_events)
     676             :     {
     677             :       // Only print the log
     678             :       // if it isn't empty
     679        2697 :       if (!log.empty())
     680             :         {
     681             :           // Possibly print machine info,
     682             :           // but only do this once
     683        1600 :           if (!called)
     684             :             {
     685        1552 :               called = true;
     686        2680 :               oss << get_info_header();
     687             :             }
     688        2752 :           oss << get_perf_info();
     689             :         }
     690             :     }
     691             : 
     692        3645 :   return oss.str();
     693         801 : }
     694             : 
     695             : 
     696             : 
     697       18154 : void PerfLog::print_log() const
     698             : {
     699       18154 :   if (log_events)
     700             :     {
     701             :       // Check to see if the log_string is empty, and if so,
     702             :       // avoid printing an unnecessary newline.
     703        3645 :       std::string log_string = this->get_log();
     704        2697 :       if (log_string.size() > 0)
     705         448 :         libMesh::out << log_string << std::endl;
     706             :     }
     707       18154 : }
     708             : 
     709           0 : PerfData PerfLog::get_perf_data(const std::string & label, const std::string & header)
     710             : {
     711           0 :   if (non_temporary_strings.count(label) &&
     712           0 :       non_temporary_strings.count(header))
     713             :     {
     714           0 :       const char * label_c_str = non_temporary_strings[label].get();
     715           0 :       const char * header_c_str = non_temporary_strings[header].get();
     716           0 :       return log[std::make_pair(header_c_str, label_c_str)];
     717             :     }
     718             : 
     719             :   auto iter = std::find_if
     720           0 :     (log.begin(), log.end(),
     721           0 :      [&label, &header] (log_type::const_reference a)
     722             :      {
     723             :        return
     724           0 :        !std::strcmp(header.c_str(), a.first.first) &&
     725           0 :        !std::strcmp(label.c_str(), a.first.second);
     726           0 :      });
     727             : 
     728           0 :   libmesh_assert(iter != log.end());
     729             : 
     730           0 :   return iter->second;
     731             : }
     732             : 
     733           0 : void PerfLog::start_event(const std::string & label,
     734             :                           const std::string & header)
     735             : {
     736           0 :   this->push(label,header);
     737           0 : }
     738             : 
     739             : 
     740             : 
     741           0 : void PerfLog::stop_event(const std::string & label,
     742             :                          const std::string & header)
     743             : {
     744           0 :   this->pop(label,header);
     745           0 : }
     746             : 
     747             : 
     748             : 
     749           0 : void PerfLog::pause_event(const std::string &,
     750             :                           const std::string &)
     751             : {
     752             :   // nothing to do.  pushing the next object on the stack will handle it
     753           0 : }
     754             : 
     755             : 
     756             : 
     757           0 : void PerfLog::restart_event(const std::string &,
     758             :                             const std::string &)
     759             : {
     760             :   // nothing to do.  popping the top off the stack will handle it.
     761           0 : }
     762             : 
     763             : 
     764             : 
     765        1552 : void PerfLog::split_on_whitespace(const std::string & input, std::vector<std::string> & output) const
     766             : {
     767             :   // Check for easy return
     768        1552 :   if (input.size()==0)
     769           0 :     return;
     770             : 
     771             :   // Here we hard-code the string to split on, since the algorithm below
     772             :   // is somewhat specific to it...
     773        1976 :   const std::string split_on("' '");
     774             : 
     775         424 :   size_t current_pos = 0;
     776             :   while (true)
     777             :     {
     778             :       // Find next end location
     779       26582 :       if (size_t end_pos = input.find(split_on, current_pos);
     780             :           end_pos != std::string::npos)
     781             :         {
     782             :           // Create substring.  Note: the second argument to substr is
     783             :           // the *length* of string to create, not the ending position!
     784       35644 :           output.push_back( input.substr(current_pos, end_pos - current_pos + 1) );
     785             : 
     786             :           // Update search starting position, make sure to go past the end of the split_on string, but
     787             :           // include the previous single quote (hence the -1).
     788       25030 :           current_pos = end_pos + split_on.size() - 1;
     789             :         }
     790             :       else
     791             :         {
     792             :           // Push back whatever remains of the string onto the output.
     793             :           // Note that substr with only 1 argument pushes back
     794             :           // whatever remains of the string.  This also handles the
     795             :           // case where the string does not contain any matches.
     796        2680 :           output.push_back( input.substr(current_pos) );
     797             : 
     798             :           // We are done searching the string, so break out of the while loop
     799         424 :           break;
     800             :         }
     801       25030 :     }
     802             : }
     803             : 
     804             : } // namespace libMesh

Generated by: LCOV version 1.14