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