summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/include/ipxe/profile.h
blob: b6d2b19e03483f2a90adf411b86df077bc7ebfa0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#ifndef _IPXE_PROFILE_H
#define _IPXE_PROFILE_H

/** @file
 *
 * Profiling
 *
 */

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );

#include <bits/profile.h>
#include <ipxe/tables.h>

#ifdef NDEBUG
#define PROFILING 0
#else
#define PROFILING 1
#endif

/**
 * A data structure for storing profiling information
 */
struct profiler {
	/** Name */
	const char *name;
	/** Start timestamp */
	unsigned long started;
	/** Stop timestamp */
	unsigned long stopped;
	/** Number of samples */
	unsigned int count;
	/** Mean sample value (scaled) */
	unsigned long mean;
	/** Mean sample value MSB
	 *
	 * This is the highest bit set in the raw (unscaled) value
	 * (i.e. one less than would be returned by flsl(raw_mean)).
	 */
	unsigned int mean_msb;
	/** Accumulated variance (scaled) */
	unsigned long long accvar;
	/** Accumulated variance MSB
	 *
	 * This is the highest bit set in the raw (unscaled) value
	 * (i.e. one less than would be returned by flsll(raw_accvar)).
	 */
	unsigned int accvar_msb;
};

/** Profiler table */
#define PROFILERS __table ( struct profiler, "profilers" )

/** Declare a profiler */
#if PROFILING
#define __profiler __table_entry ( PROFILERS, 01 )
#else
#define __profiler
#endif

extern unsigned long profile_excluded;

extern void profile_update ( struct profiler *profiler, unsigned long sample );
extern unsigned long profile_mean ( struct profiler *profiler );
extern unsigned long profile_variance ( struct profiler *profiler );
extern unsigned long profile_stddev ( struct profiler *profiler );

/**
 * Get start time
 *
 * @v profiler		Profiler
 * @ret started		Start time
 */
static inline __attribute__ (( always_inline )) unsigned long
profile_started ( struct profiler *profiler ) {

	/* If profiling is active then return start time */
	if ( PROFILING ) {
		return ( profiler->started + profile_excluded );
	} else {
		return 0;
	}
}

/**
 * Get stop time
 *
 * @v profiler		Profiler
 * @ret stopped		Stop time
 */
static inline __attribute__ (( always_inline )) unsigned long
profile_stopped ( struct profiler *profiler ) {

	/* If profiling is active then return start time */
	if ( PROFILING ) {
		return ( profiler->stopped + profile_excluded );
	} else {
		return 0;
	}
}

/**
 * Get elapsed time
 *
 * @v profiler		Profiler
 * @ret elapsed		Elapsed time
 */
static inline __attribute__ (( always_inline )) unsigned long
profile_elapsed ( struct profiler *profiler ) {

	/* If profiling is active then return elapsed time */
	if ( PROFILING ) {
		return ( profile_stopped ( profiler ) -
			 profile_started ( profiler ) );
	} else {
		return 0;
	}
}

/**
 * Start profiling
 *
 * @v profiler		Profiler
 * @v started		Start timestamp
 */
static inline __attribute__ (( always_inline )) void
profile_start_at ( struct profiler *profiler, unsigned long started ) {

	/* If profiling is active then record start timestamp */
	if ( PROFILING )
		profiler->started = ( started - profile_excluded );
}

/**
 * Stop profiling
 *
 * @v profiler		Profiler
 * @v stopped		Stop timestamp
 */
static inline __attribute__ (( always_inline )) void
profile_stop_at ( struct profiler *profiler, unsigned long stopped ) {

	/* If profiling is active then record end timestamp and update stats */
	if ( PROFILING ) {
		profiler->stopped = ( stopped - profile_excluded );
		profile_update ( profiler, profile_elapsed ( profiler ) );
	}
}

/**
 * Start profiling
 *
 * @v profiler		Profiler
 */
static inline __attribute__ (( always_inline )) void
profile_start ( struct profiler *profiler ) {

	/* If profiling is active then record start timestamp */
	if ( PROFILING )
		profile_start_at ( profiler, profile_timestamp() );
}

/**
 * Stop profiling
 *
 * @v profiler		Profiler
 */
static inline __attribute__ (( always_inline )) void
profile_stop ( struct profiler *profiler ) {

	/* If profiling is active then record end timestamp and update stats */
	if ( PROFILING )
		profile_stop_at ( profiler, profile_timestamp() );
}

/**
 * Exclude time from other ongoing profiling results
 *
 * @v profiler		Profiler
 */
static inline __attribute__ (( always_inline )) void
profile_exclude ( struct profiler *profiler ) {

	/* If profiling is active then update accumulated excluded time */
	if ( PROFILING )
		profile_excluded += profile_elapsed ( profiler );
}

/**
 * Record profiling sample in custom units
 *
 * @v profiler		Profiler
 * @v sample		Profiling sample
 */
static inline __attribute__ (( always_inline )) void
profile_custom ( struct profiler *profiler, unsigned long sample ) {

	/* If profiling is active then update stats */
	if ( PROFILING )
		profile_update ( profiler, sample );
}

#endif /* _IPXE_PROFILE_H */