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