iPXE
profile.c File Reference

Profiling. More...

#include <stdint.h>
#include <stdio.h>
#include <strings.h>
#include <limits.h>
#include <assert.h>
#include <ipxe/isqrt.h>
#include <ipxe/profile.h>

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
 FILE_SECBOOT (PERMITTED)
static const char * profile_hex_fraction (signed long long value, unsigned int shift)
 Format a hex fraction (for debugging)
static unsigned int profile_mean_shift (struct profiler *profiler)
 Calculate bit shift for mean sample value.
static unsigned int profile_accvar_shift (struct profiler *profiler)
 Calculate bit shift for accumulated variance value.
void profile_update (struct profiler *profiler, unsigned long sample)
 Update profiler with a new sample.
unsigned long profile_mean (struct profiler *profiler)
 Get mean sample value.
unsigned long profile_variance (struct profiler *profiler)
 Get sample variance.
unsigned long profile_stddev (struct profiler *profiler)
 Get sample standard deviation.

Variables

unsigned long profile_excluded
 Accumulated time excluded from profiling.

Detailed Description

Profiling.

The profiler computes basic statistics (mean, variance, and standard deviation) for the samples which it records. Note that these statistics need not be completely accurate; it is sufficient to give a rough approximation.

The algorithm for updating the mean and variance estimators is from The Art of Computer Programming (via Wikipedia), with adjustments to avoid the use of floating-point instructions.

Definition in file profile.c.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )

◆ FILE_SECBOOT()

FILE_SECBOOT ( PERMITTED )

◆ profile_hex_fraction()

const char * profile_hex_fraction ( signed long long value,
unsigned int shift )
static

Format a hex fraction (for debugging)

Parameters
valueValue
shiftBit shift
Return values
stringFormatted hex fraction

Definition at line 59 of file profile.c.

60 {
61 static char buf[23] = "-"; /* -0xXXXXXXXXXXXXXXXX.XX + NUL */
62 unsigned long long int_part;
63 uint8_t frac_part;
64 char *ptr;
65
66 if ( value < 0 ) {
67 value = -value;
68 ptr = &buf[0];
69 } else {
70 ptr = &buf[1];
71 }
72 int_part = ( value >> shift );
73 frac_part = ( value >> ( shift - ( 8 * sizeof ( frac_part ) ) ) );
74 snprintf ( &buf[1], ( sizeof ( buf ) - 1 ), "%#llx.%02x",
75 int_part, frac_part );
76 return ptr;
77}
pseudo_bit_t value[0x00020]
Definition arbel.h:2
unsigned char uint8_t
Definition stdint.h:10
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition vsprintf.c:383

References snprintf(), and value.

Referenced by profile_update().

◆ profile_mean_shift()

unsigned int profile_mean_shift ( struct profiler * profiler)
inlinestatic

Calculate bit shift for mean sample value.

Parameters
profilerProfiler
Return values
shiftBit shift

Definition at line 85 of file profile.c.

85 {
86
87 return ( ( ( 8 * sizeof ( profiler->mean ) ) - 1 ) /* MSB */
88 - 1 /* Leave sign bit unused */
89 - profiler->mean_msb );
90}
A data structure for storing profiling information.
Definition profile.h:27
unsigned long mean
Mean sample value (scaled)
Definition profile.h:37
unsigned int mean_msb
Mean sample value MSB.
Definition profile.h:43

References profiler::mean, and profiler::mean_msb.

Referenced by profile_mean(), and profile_update().

◆ profile_accvar_shift()

unsigned int profile_accvar_shift ( struct profiler * profiler)
inlinestatic

Calculate bit shift for accumulated variance value.

Parameters
profilerProfiler
Return values
shiftBit shift

Definition at line 98 of file profile.c.

98 {
99
100 return ( ( ( 8 * sizeof ( profiler->accvar ) ) - 1 ) /* MSB */
101 - 1 /* Leave top bit unused */
102 - profiler->accvar_msb );
103}
unsigned long long accvar
Accumulated variance (scaled)
Definition profile.h:45
unsigned int accvar_msb
Accumulated variance MSB.
Definition profile.h:51

References profiler::accvar, and profiler::accvar_msb.

Referenced by profile_update(), and profile_variance().

◆ profile_update()

void profile_update ( struct profiler * profiler,
unsigned long sample )

Update profiler with a new sample.

Parameters
profilerProfiler
sampleSample value

Definition at line 111 of file profile.c.

111 {
112 unsigned int sample_msb;
113 unsigned int mean_shift;
114 unsigned int delta_shift;
115 signed long pre_delta;
116 signed long post_delta;
117 signed long long accvar_delta;
118 unsigned int accvar_delta_shift;
119 unsigned int accvar_delta_msb;
120 unsigned int accvar_shift;
121
122 /* Our scaling logic assumes that sample values never overflow
123 * a signed long (i.e. that the high bit is always zero).
124 */
125 assert ( ( ( signed ) sample ) >= 0 );
126
127 /* Update sample count, limiting to avoid signed overflow */
128 if ( profiler->count < INT_MAX )
129 profiler->count++;
130
131 /* Adjust mean sample value scale if necessary. Skip if
132 * sample is zero (in which case flsl(sample)-1 would
133 * underflow): in the case of a zero sample we have no need to
134 * adjust the scale anyway.
135 */
136 if ( sample ) {
137 sample_msb = ( flsl ( sample ) - 1 );
138 if ( profiler->mean_msb < sample_msb ) {
139 profiler->mean >>= ( sample_msb - profiler->mean_msb );
140 profiler->mean_msb = sample_msb;
141 }
142 }
143
144 /* Scale sample to internal units */
145 mean_shift = profile_mean_shift ( profiler );
146 sample <<= mean_shift;
147
148 /* Update mean */
149 pre_delta = ( sample - profiler->mean );
150 profiler->mean += ( pre_delta / ( ( signed ) profiler->count ) );
151 post_delta = ( sample - profiler->mean );
152 delta_shift = mean_shift;
153 DBGC ( profiler, "PROFILER %p sample %#lx mean %s", profiler,
154 ( sample >> mean_shift ),
155 profile_hex_fraction ( profiler->mean, mean_shift ) );
156 DBGC ( profiler, " pre %s",
157 profile_hex_fraction ( pre_delta, delta_shift ) );
158 DBGC ( profiler, " post %s\n",
159 profile_hex_fraction ( post_delta, delta_shift ) );
160
161 /* Scale both deltas to fit in half of an unsigned long long
162 * to avoid potential overflow on multiplication. Note that
163 * shifting a signed quantity is "implementation-defined"
164 * behaviour in the C standard, but gcc documents that it will
165 * always perform sign extension.
166 */
167 if ( sizeof ( pre_delta ) > ( sizeof ( accvar_delta ) / 2 ) ) {
168 unsigned int shift = ( 8 * ( sizeof ( pre_delta ) -
169 ( sizeof ( accvar_delta ) / 2 ) ));
170 pre_delta >>= shift;
171 post_delta >>= shift;
172 delta_shift -= shift;
173 }
174
175 /* Update variance, if applicable. Skip if either delta is
176 * zero (in which case flsl(delta)-1 would underflow): in the
177 * case of a zero delta there is no change to the accumulated
178 * variance anyway.
179 */
180 if ( pre_delta && post_delta ) {
181
182 /* Calculate variance delta */
183 accvar_delta = ( ( ( signed long long ) pre_delta ) *
184 ( ( signed long long ) post_delta ) );
185 accvar_delta_shift = ( 2 * delta_shift );
186 assert ( accvar_delta > 0 );
187
188 /* Calculate variance delta MSB, using flsl() on each
189 * delta individually to provide an upper bound rather
190 * than requiring the existence of flsll().
191 */
192 accvar_delta_msb = ( flsll ( accvar_delta ) - 1 );
193 if ( accvar_delta_msb > accvar_delta_shift ) {
194 accvar_delta_msb -= accvar_delta_shift;
195 } else {
196 accvar_delta_msb = 0;
197 }
198
199 /* Adjust scales as necessary */
200 if ( profiler->accvar_msb < accvar_delta_msb ) {
201 /* Rescale accumulated variance */
202 profiler->accvar >>= ( accvar_delta_msb -
204 profiler->accvar_msb = accvar_delta_msb;
205 } else {
206 /* Rescale variance delta */
207 accvar_delta >>= ( profiler->accvar_msb -
208 accvar_delta_msb );
209 accvar_delta_shift -= ( profiler->accvar_msb -
210 accvar_delta_msb );
211 }
212
213 /* Scale delta to internal units */
214 accvar_shift = profile_accvar_shift ( profiler );
215 accvar_delta <<= ( accvar_shift - accvar_delta_shift );
216
217 /* Accumulate variance */
218 profiler->accvar += accvar_delta;
219
220 /* Adjust scale if necessary */
221 if ( profiler->accvar &
222 ( 1ULL << ( ( 8 * sizeof ( profiler->accvar ) ) - 1 ) ) ) {
223 profiler->accvar >>= 1;
225 accvar_delta >>= 1;
226 accvar_shift--;
227 }
228
229 DBGC ( profiler, "PROFILER %p accvar %s", profiler,
230 profile_hex_fraction ( profiler->accvar, accvar_shift ));
231 DBGC ( profiler, " delta %s\n",
232 profile_hex_fraction ( accvar_delta, accvar_shift ) );
233 }
234}
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
#define DBGC(...)
Definition compiler.h:505
#define flsll(x)
Find last (i.e.
Definition strings.h:149
#define flsl(x)
Find last (i.e.
Definition strings.h:158
#define INT_MAX
Definition limits.h:30
static unsigned int profile_accvar_shift(struct profiler *profiler)
Calculate bit shift for accumulated variance value.
Definition profile.c:98
static const char * profile_hex_fraction(signed long long value, unsigned int shift)
Format a hex fraction (for debugging)
Definition profile.c:59
static unsigned int profile_mean_shift(struct profiler *profiler)
Calculate bit shift for mean sample value.
Definition profile.c:85
unsigned int count
Number of samples.
Definition profile.h:35

References profiler::accvar, profiler::accvar_msb, assert, profiler::count, DBGC, flsl, flsll, INT_MAX, profiler::mean, profiler::mean_msb, profile_accvar_shift(), profile_hex_fraction(), and profile_mean_shift().

Referenced by profile_custom(), profile_okx(), and profile_stop_at().

◆ profile_mean()

unsigned long profile_mean ( struct profiler * profiler)

Get mean sample value.

Parameters
profilerProfiler
Return values
meanMean sample value

Definition at line 242 of file profile.c.

242 {
243 unsigned int mean_shift = profile_mean_shift ( profiler );
244
245 /* Round to nearest and scale down to original units */
246 return ( ( profiler->mean + ( 1UL << ( mean_shift - 1 ) ) )
247 >> mean_shift );
248}

References profiler::mean, and profile_mean_shift().

Referenced by cipher_cost(), digest_cost(), memcpy_test_speed(), profile_okx(), profstat(), and tcpip_random_okx().

◆ profile_variance()

unsigned long profile_variance ( struct profiler * profiler)

Get sample variance.

Parameters
profilerProfiler
Return values
varianceSample variance

Definition at line 256 of file profile.c.

256 {
257 unsigned int accvar_shift = profile_accvar_shift ( profiler );
258
259 /* Variance is zero if fewer than two samples exist (avoiding
260 * division by zero error).
261 */
262 if ( profiler->count < 2 )
263 return 0;
264
265 /* Calculate variance, round to nearest, and scale to original units */
266 return ( ( ( profiler->accvar / ( profiler->count - 1 ) )
267 + ( 1ULL << ( accvar_shift - 1 ) ) ) >> accvar_shift );
268}

References profiler::accvar, profiler::count, and profile_accvar_shift().

Referenced by profile_stddev().

◆ profile_stddev()

unsigned long profile_stddev ( struct profiler * profiler)

Get sample standard deviation.

Parameters
profilerProfiler
Return values
stddevSample standard deviation

Definition at line 276 of file profile.c.

276 {
277
278 return isqrt ( profile_variance ( profiler ) );
279}
unsigned long isqrt(unsigned long value)
Find integer square root.
Definition isqrt.c:41
unsigned long profile_variance(struct profiler *profiler)
Get sample variance.
Definition profile.c:256

References isqrt(), and profile_variance().

Referenced by memcpy_test_speed(), profile_okx(), profstat(), and tcpip_random_okx().

Variable Documentation

◆ profile_excluded

unsigned long profile_excluded

Accumulated time excluded from profiling.

Definition at line 50 of file profile.c.

Referenced by profile_exclude(), profile_start_at(), profile_started(), profile_stop_at(), profile_stopped(), and profile_timestamp().