1 #ifndef _IPXE_PROFILE_H
2 #define _IPXE_PROFILE_H
3
4 /** @file
5 *
6 * Profiling
7 *
8 */
9
10 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11
12 #include <bits/profile.h>
13 #include <ipxe/tables.h>
14
15 #ifndef PROFILING
16 #ifdef NDEBUG
17 #define PROFILING 0
18 #else
19 #define PROFILING 1
20 #endif
21 #endif
22
23 /**
24 * A data structure for storing profiling information
25 */
26 struct profiler {
27 /** Name */
28 const char *name;
29 /** Start timestamp */
30 unsigned long started;
31 /** Stop timestamp */
32 unsigned long stopped;
33 /** Number of samples */
34 unsigned int count;
35 /** Mean sample value (scaled) */
36 unsigned long mean;
37 /** Mean sample value MSB
38 *
39 * This is the highest bit set in the raw (unscaled) value
40 * (i.e. one less than would be returned by flsl(raw_mean)).
41 */
42 unsigned int mean_msb;
43 /** Accumulated variance (scaled) */
44 unsigned long long accvar;
45 /** Accumulated variance MSB
46 *
47 * This is the highest bit set in the raw (unscaled) value
48 * (i.e. one less than would be returned by flsll(raw_accvar)).
49 */
50 unsigned int accvar_msb;
51 };
52
53 /** Profiler table */
54 #define PROFILERS __table ( struct profiler, "profilers" )
55
56 /** Declare a profiler */
57 #if PROFILING
58 #define __profiler __table_entry ( PROFILERS, 01 )
59 #else
60 #define __profiler
61 #endif
62
63 extern unsigned long profile_excluded;
64
65 extern void profile_update ( struct profiler *profiler, unsigned long sample );
66 extern unsigned long profile_mean ( struct profiler *profiler );
67 extern unsigned long profile_variance ( struct profiler *profiler );
68 extern unsigned long profile_stddev ( struct profiler *profiler );
69
70 /**
71 * Get start time
72 *
73 * @v profiler Profiler
74 * @ret started Start time
75 */
76 static inline __attribute__ (( always_inline )) unsigned long
profile_started(struct profiler * profiler)77 profile_started ( struct profiler *profiler ) {
78
79 /* If profiling is active then return start time */
80 if ( PROFILING ) {
81 return ( profiler->started + profile_excluded );
82 } else {
83 return 0;
84 }
85 }
86
87 /**
88 * Get stop time
89 *
90 * @v profiler Profiler
91 * @ret stopped Stop time
92 */
93 static inline __attribute__ (( always_inline )) unsigned long
profile_stopped(struct profiler * profiler)94 profile_stopped ( struct profiler *profiler ) {
95
96 /* If profiling is active then return start time */
97 if ( PROFILING ) {
98 return ( profiler->stopped + profile_excluded );
99 } else {
100 return 0;
101 }
102 }
103
104 /**
105 * Get elapsed time
106 *
107 * @v profiler Profiler
108 * @ret elapsed Elapsed time
109 */
110 static inline __attribute__ (( always_inline )) unsigned long
profile_elapsed(struct profiler * profiler)111 profile_elapsed ( struct profiler *profiler ) {
112
113 /* If profiling is active then return elapsed time */
114 if ( PROFILING ) {
115 return ( profile_stopped ( profiler ) -
116 profile_started ( profiler ) );
117 } else {
118 return 0;
119 }
120 }
121
122 /**
123 * Start profiling
124 *
125 * @v profiler Profiler
126 * @v started Start timestamp
127 */
128 static inline __attribute__ (( always_inline )) void
profile_start_at(struct profiler * profiler,unsigned long started)129 profile_start_at ( struct profiler *profiler, unsigned long started ) {
130
131 /* If profiling is active then record start timestamp */
132 if ( PROFILING )
133 profiler->started = ( started - profile_excluded );
134 }
135
136 /**
137 * Stop profiling
138 *
139 * @v profiler Profiler
140 * @v stopped Stop timestamp
141 */
142 static inline __attribute__ (( always_inline )) void
profile_stop_at(struct profiler * profiler,unsigned long stopped)143 profile_stop_at ( struct profiler *profiler, unsigned long stopped ) {
144
145 /* If profiling is active then record end timestamp and update stats */
146 if ( PROFILING ) {
147 profiler->stopped = ( stopped - profile_excluded );
148 profile_update ( profiler, profile_elapsed ( profiler ) );
149 }
150 }
151
152 /**
153 * Start profiling
154 *
155 * @v profiler Profiler
156 */
157 static inline __attribute__ (( always_inline )) void
profile_start(struct profiler * profiler)158 profile_start ( struct profiler *profiler ) {
159
160 /* If profiling is active then record start timestamp */
161 if ( PROFILING )
162 profile_start_at ( profiler, profile_timestamp() );
163 }
164
165 /**
166 * Stop profiling
167 *
168 * @v profiler Profiler
169 */
170 static inline __attribute__ (( always_inline )) void
profile_stop(struct profiler * profiler)171 profile_stop ( struct profiler *profiler ) {
172
173 /* If profiling is active then record end timestamp and update stats */
174 if ( PROFILING )
175 profile_stop_at ( profiler, profile_timestamp() );
176 }
177
178 /**
179 * Exclude time from other ongoing profiling results
180 *
181 * @v profiler Profiler
182 */
183 static inline __attribute__ (( always_inline )) void
profile_exclude(struct profiler * profiler)184 profile_exclude ( struct profiler *profiler ) {
185
186 /* If profiling is active then update accumulated excluded time */
187 if ( PROFILING )
188 profile_excluded += profile_elapsed ( profiler );
189 }
190
191 /**
192 * Record profiling sample in custom units
193 *
194 * @v profiler Profiler
195 * @v sample Profiling sample
196 */
197 static inline __attribute__ (( always_inline )) void
profile_custom(struct profiler * profiler,unsigned long sample)198 profile_custom ( struct profiler *profiler, unsigned long sample ) {
199
200 /* If profiling is active then update stats */
201 if ( PROFILING )
202 profile_update ( profiler, sample );
203 }
204
205 #endif /* _IPXE_PROFILE_H */
206