1 /*!
2  * \file  mfront/src/BehaviourProfiler.cxx
3  * \brief
4  * \author Thomas Helfer
5  * \brief 15 mai 2014
6  * \copyright Copyright (C) 2006-2018 CEA/DEN, EDF R&D. All rights
7  * reserved.
8  * This project is publicly released under either the GNU GPL Licence
9  * or the CECILL-A licence. A copy of thoses licences are delivered
10  * with the sources of TFEL. CEA or EDF may also distribute this
11  * project under specific licensing conditions.
12  */
13 
14 #include<ctime>
15 #include<string>
16 #include<iterator>
17 #include <iomanip>
18 #include<iostream>
19 #include<algorithm>
20 #include<stdexcept>
21 #include "TFEL/Raise.hxx"
22 #include "MFront/BehaviourProfiler.hxx"
23 
24 namespace mfront
25 {
26 
27 #if !(defined _WIN32 || defined _WIN64)
28   /*!
29    * add a new measure
30    * t     : measure to which the new measure is added
31    * start : start of the measure
32    * end   : end of the measure
33    */
add_measure(std::atomic<intmax_t> & t,const timespec & start,const timespec & end)34   static inline void add_measure(std::atomic<intmax_t>& t,
35                                  const timespec& start,
36                                  const timespec& end) {
37     /* http://www.guyrutenberg.com/2007/09/22/profiling-code-using-clock_gettime */
38     timespec temp;
39     if ((end.tv_nsec-start.tv_nsec)<0) {
40       temp.tv_sec = end.tv_sec-start.tv_sec-1;
41       temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
42     } else {
43       temp.tv_sec = end.tv_sec-start.tv_sec;
44       temp.tv_nsec = end.tv_nsec-start.tv_nsec;
45     }
46     t += 1000000000*temp.tv_sec+temp.tv_nsec;
47   }  // end of add_measure
48 #endif
49 
50   /*!
51    * print a time to the specified stream
52    */
print_time(std::ostream & os,const intmax_t time)53   static void print_time(std::ostream& os, const intmax_t time) {
54     constexpr intmax_t musec_d = 1000;
55     constexpr intmax_t msec_d  = 1000*musec_d;
56     constexpr intmax_t sec_d   = msec_d*1000;
57     constexpr intmax_t min_d   = sec_d*60;
58     constexpr intmax_t hour_d  = min_d*60;
59     constexpr intmax_t days_d  = hour_d*24;
60     intmax_t t = time;
61     const intmax_t ndays  = t/days_d;
62     t -= ndays*days_d;
63     const intmax_t nhours = t/hour_d;
64     t -= nhours*hour_d;
65     const intmax_t nmins  = t/min_d;
66     t -= nmins*min_d;
67     const intmax_t nsecs   = t/sec_d;
68     t -= nsecs*sec_d;
69     const intmax_t nmsecs   = t/msec_d;
70     t -= nmsecs*msec_d;
71     const intmax_t nmusecs   = t/musec_d;
72     t -= nmusecs*musec_d;
73     if(ndays>0){
74       os << ndays << "days ";
75     }
76     if(nhours>0){
77       os << nhours << "hours ";
78     }
79     if(nmins>0){
80       os << nmins << "mins ";
81     }
82     if(nsecs>0){
83       os << nsecs << "secs ";
84     }
85     if(nmsecs>0){
86       os << nmsecs << "msecs ";
87     }
88     if(nmusecs>0){
89       os << nmusecs << "musecs ";
90     }
91     os << t << "nsecs";
92   } // end pf print
93 
getCodeBlockName(const unsigned int c)94   static std::string getCodeBlockName(const unsigned int c) {
95     auto n = std::string{};
96     switch(c){
97     case BehaviourProfiler::FLOWRULE:
98       n = "FlowRule";
99       break;
100     case BehaviourProfiler::BEFOREINITIALIZELOCALVARIABLES:
101       n = "Init::BeforeInitializeLocalVariables";
102       break;
103     case BehaviourProfiler::INITIALIZELOCALVARIABLES:
104       n = "Init::InitializeLocalVariables";
105       break;
106     case BehaviourProfiler::AFTERINITIALIZELOCALVARIABLES:
107       n = "Init::AfterInitializeLocalVariables";
108       break;
109     case BehaviourProfiler::COMPUTEPREDICTOR:
110       n = "Init::ComputePredictor";
111       break;
112     case BehaviourProfiler::INITIALIZEJACOBIAN:
113       n = "Init::InitializeJacobian";
114       break;
115     case BehaviourProfiler::COMPUTEPREDICTIONOPERATOR:
116       n = "ComputePredictionOperator";
117       break;
118     case BehaviourProfiler::INTEGRATOR:
119       n = "Integrator";
120       break;
121     case BehaviourProfiler::COMPUTETHERMODYNAMICFORCES:
122       n = "Integrator::ComputeThermodynamicForces";
123       break;
124     case BehaviourProfiler::ADDITIONALCONVERGENCECHECKS:
125       n = "Integrator::AdditionalConvergenceChecks";
126       break;
127     case BehaviourProfiler::COMPUTEDERIVATIVE:
128       n = "Integrator::ComputeDerivative";
129       break;
130     case BehaviourProfiler::COMPUTEFDF:
131       n = "Integrator::ComputeFdF";
132       break;
133     case BehaviourProfiler::TINYMATRIXSOLVE:
134       n = "Integrator::TinyMatrixSolve";
135       break;
136     case BehaviourProfiler::COMPUTEFINALTHERMODYNAMICFORCES:
137       n = "ComputeFinalThermodynamicForces";
138       break;
139     case BehaviourProfiler::COMPUTETANGENTOPERATOR:
140       n = "ComputeTangentOperator";
141       break;
142     case BehaviourProfiler::APRIORITIMESTEPSCALINGFACTOR:
143       n = "APrioriTimeStepScalingFactor";
144       break;
145     case BehaviourProfiler::APOSTERIORITIMESTEPSCALINGFACTOR:
146       n = "APosterioriTimeStepScalingFactor";
147       break;
148     case BehaviourProfiler::UPDATEAUXILIARYSTATEVARIABLES:
149       n = "UpdateAuxiliaryStateVariables";
150       break;
151     case BehaviourProfiler::FINITESTRAINPREPROCESSING:
152       n = "FiniteStrainPreProcessing";
153       break;
154     case BehaviourProfiler::FINITESTRAINPOSTPROCESSING:
155       n = "FiniteStrainPostProcessing";
156       break;
157     case BehaviourProfiler::USERDEFINEDCODE1:
158       n = "UserDefinedCode-1";
159       break;
160     case BehaviourProfiler::USERDEFINEDCODE2:
161       n = "UserDefinedCode-2";
162       break;
163     case BehaviourProfiler::TOTALTIME:
164       n = "TotalTime";
165       break;
166     default:
167       tfel::raise("getCodeBlockName : no name associated "
168 		  "with the given code block");
169     }
170     return n;
171   }
172 
Timer(BehaviourProfiler & t,const unsigned short cn)173   BehaviourProfiler::Timer::Timer(BehaviourProfiler& t, const unsigned short cn)
174       : gtimer(t), c(cn) {
175 #if !(defined _WIN32 || defined _WIN64)
176     ::clock_gettime(CLOCK_THREAD_CPUTIME_ID,&(this->start));
177 #endif
178   }  // end of BehaviourProfiler::Timer
179 
~Timer()180   BehaviourProfiler::Timer::~Timer() {
181 #if !(defined _WIN32 || defined _WIN64)
182     ::clock_gettime(CLOCK_THREAD_CPUTIME_ID,&(this->end));
183     add_measure(this->gtimer.measures[this->c],this->start,this->end);
184 #endif
185   }  // end of BehaviourProfiler::~Timer
186 
BehaviourProfiler(const std::string & n)187   BehaviourProfiler::BehaviourProfiler(const std::string& n) : name(n) {
188     std::fill(begin(measures),end(measures),0);
189   }  // end of BehaviourProfiler::BehaviourProfiler
190 
~BehaviourProfiler()191   BehaviourProfiler::~BehaviourProfiler() {
192     using size_type = std::array<std::atomic<std::intmax_t>, 23>::size_type;
193     std::cout << "\nResults of " << this->name << " profiling : ";
194     print_time(std::cout,measures.back());
195     std::cout << '\n';
196     std::string::size_type w{0};
197     for(size_type i=0;i+1!=measures.size();++i){
198       if(measures[i]!=0){
199         w = std::max(w, getCodeBlockName(i).size());
200       }
201     }
202     for(size_type i=0;i+1!=measures.size();++i){
203       if(measures[i]!=0){
204         std::cout << "- " << std::setw(w) << std::left << getCodeBlockName(i)
205                   << " : ";
206         print_time(std::cout,measures[i]);
207         std::cout << " (" << measures[i] << " ns)\n";
208       }
209     }
210     std::cout << std::endl;
211   }  // end of BehaviourProfiler::~BehaviourProfiler
212 
213 } // end of namespace mfront
214