]> git.lyx.org Git - lyx.git/blob - src/support/pmprof.h
RefChanger
[lyx.git] / src / support / pmprof.h
1 // -*- C++ -*-
2 /* \file pmprof.h
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Jean-Marc Lasgouttes
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 /** How to use this trivial profiler:
12  *
13  * * at the beginning of the interesting block, just add:
14  *   PROFILE_THIS_BLOCK(some_identifier)
15  *
16  *   A trailing semicolon can be added at your discretion.
17  *
18  * * when the program ends, statistics will be sent to standard error, like:
19  *
20  *   ##### some_identifier: 6.48475usec, count=25405
21  *
22  * The code measured by the profiler corresponds to the lifetime of a
23  * local variable declared by the PROFILE_THIS_BLOCK macro.
24  *
25  * Some examples of profiling scope: In the snippets below, c1, c2...
26  * designate code chunks, and the identifiers of profiling blocks are
27  * chosen to reflect what they count.
28  *
29  * {
30  *   c1
31  *   PROFILE_THIS_BLOCK(c2)
32  *   c2
33  * }
34  *
35  *
36  * {
37  *   PROFILE_THIS_BLOCK(c1_c2)
38  *   c1
39  *   PROFILE_THIS_BLOCK(c2)
40  *   c2
41  * }
42  *
43  *
44  * {
45  *   {
46  *     PROFILE_THIS_BLOCK(c1)
47  *     c1
48  *   }
49  *   PROFILE_THIS_BLOCK(c2)
50  *   c2
51  * }
52  *
53  *
54  * {
55  *   PROFILE_THIS_BLOCK(c1_c2_c3)
56  *   c1
57  *   {
58  *     PROFILE_THIS_BLOCK(c2)
59  *     c2
60  *   }
61  *   c3
62  * }
63  *
64  * Influence of identifier names: they are mainly used for display
65  * purpose, but the same name should not be used twice in the same
66  * scope.
67  *
68  * {
69  *   PROFILE_THIS_BLOCK(foo)
70  *   c1
71  *   PROFILE_THIS_BLOCK(foo) // error: identifier clash
72  *   c2
73  * }
74  *
75  * In the example below, c1+c2 and c2 are counted separately, but in
76  * the output, both are confusingly labelled `foo'.
77  *
78  * {
79  *   PROFILE_THIS_BLOCK(foo)
80  *   c1
81  *   {
82  *     PROFILE_THIS_BLOCK(foo) // error: identifier clash
83  *     c2
84  *   }
85  * }
86
87  */
88
89 #ifndef PMPROF_H
90 #define PMPROF_H
91
92 #ifdef _WIN32
93 #include <windows.h>
94 #else
95 #include <sys/time.h>
96 #endif
97
98 #include <iomanip>
99 #include <iostream>
100
101
102 #if defined(__GNUG__) && defined(_GLIBCXX_DEBUG)
103 #error Profiling is not usable when run-time debugging is in effect
104 #endif
105
106 #ifdef _WIN32
107 /* This function does not really returns the "time of day",
108  * but it will suffice to evaluate elapsed times.
109  */
110 int gettimeofday(struct timeval * tv, struct timezone * /*tz*/)
111 {
112         LARGE_INTEGER frequency, t;
113         QueryPerformanceFrequency(&frequency);
114         QueryPerformanceCounter(&t);
115
116         tv->tv_sec = long(t.QuadPart / frequency.QuadPart);
117         tv->tv_usec = long((1000000.0 * (t.QuadPart % frequency.QuadPart)) / frequency.QuadPart);
118         return 0;
119 }
120
121 #endif // _WIN32
122
123 /* Helper class for gathering data. Instantiate this as a static
124  * variable, so that its destructor will be executed when the program
125  * ends.
126  */
127
128 class PMProfStat {
129 public:
130         PMProfStat(char const * name)
131           : name_(name), sec_(0), usec_(0), count_(0) {}
132
133         ~PMProfStat() {
134                 if (count_>0) {
135                         double total = 0.001 * (sec_ * 1000000 + usec_);
136                         std::cerr << std::fixed << std::setprecision(2) 
137                                 << "#pmprof# " << name_ << ": "
138                                 << total / count_
139                                 << "msec, count=" << count_
140                                 << ", total=" << total << "msec"
141                                 << std::endl;
142                 }
143         }
144
145         void add(const long long s, const long long u) {
146                 sec_ += s;
147                 usec_ += u;
148                 count_++;
149         }
150
151 private:
152         char const * name_;
153         long long sec_, usec_;
154         unsigned long long count_;
155 };
156
157
158 /* Helper class which gathers data at the end of the scope. One
159  * instance of this one should be created at each execution of the
160  * block. At the end of the block, it sends statistics to the static
161  * PMProfStat object.
162  */
163 class PMProfInstance {
164 public:
165         PMProfInstance(PMProfStat * stat) : stat_(stat)
166         {
167                 gettimeofday(&before_, 0);
168         }
169
170         ~PMProfInstance() {
171                 gettimeofday(&after_, 0);
172                 stat_->add(after_.tv_sec - before_.tv_sec,
173                            after_.tv_usec - before_.tv_usec);
174         }
175
176 private:
177         timeval before_, after_;
178         PMProfStat * stat_;
179 };
180
181
182 #define PROFILE_THIS_BLOCK(a) \
183         static PMProfStat PMPS_##a(#a);\
184         PMProfInstance PMPI_##a(&PMPS_##a);
185
186
187 #endif