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