diff options
author | Michael Brown | 2014-04-23 18:43:18 +0200 |
---|---|---|
committer | Michael Brown | 2014-04-28 00:14:43 +0200 |
commit | e5f6a9be384f6adc2b50ffdb8781e81327b790aa (patch) | |
tree | 42efc59b490b68891abd81a5cc11ac938c3848c2 /src/include/ipxe | |
parent | [libc] Add flsll() (diff) | |
download | ipxe-e5f6a9be384f6adc2b50ffdb8781e81327b790aa.tar.gz ipxe-e5f6a9be384f6adc2b50ffdb8781e81327b790aa.tar.xz ipxe-e5f6a9be384f6adc2b50ffdb8781e81327b790aa.zip |
[profile] Add generic profiling infrastructure
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/include/ipxe')
-rw-r--r-- | src/include/ipxe/profile.h | 108 |
1 files changed, 61 insertions, 47 deletions
diff --git a/src/include/ipxe/profile.h b/src/include/ipxe/profile.h index 60dd53a3..0b15fe54 100644 --- a/src/include/ipxe/profile.h +++ b/src/include/ipxe/profile.h @@ -10,71 +10,85 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdint.h> +#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 */ -union profiler { - /** Timestamp (in CPU-specific "ticks") */ - uint64_t timestamp; - /** Registers returned by rdtsc. +struct profiler { + /** Name */ + const char *name; + /** Start timestamp */ + uint64_t started; + /** 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 part should really be architecture-specific code. + * This is the highest bit set in the raw (unscaled) value + * (i.e. one less than would be returned by flsll(raw_accvar)). */ - struct { - uint32_t eax; - uint32_t edx; - } rdtsc; + unsigned int accvar_msb; }; -/** - * Static per-object profiler, for use with simple_profile() - */ -static union profiler simple_profiler; +/** Profiler table */ +#define PROFILERS __table ( struct profiler, "profilers" ) + +/** Declare a profiler */ +#if PROFILING +#define __profiler __table_entry ( PROFILERS, 01 ) +#else +#define __profiler +#endif + +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 ); /** - * Perform profiling + * Start profiling * - * @v profiler Profiler data structure - * @ret delta Elapsed ticks since last call to profile(). - * - * Call profile() both before and after the code you wish to measure. - * The "after" call will return the measurement. For example: - * - * @code - * - * profile ( &profiler ); - * ... do something here ... - * printf ( "It took %ld ticks to execute\n", profile ( &profiler ) ); - * - * @endcode + * @v profiler Profiler */ -static inline __attribute__ (( always_inline )) unsigned long -profile ( union profiler *profiler ) { - uint64_t last_timestamp = profiler->timestamp; +static inline __attribute__ (( always_inline )) void +profile_start ( struct profiler *profiler ) { - __asm__ __volatile__ ( "rdtsc" : - "=a" ( profiler->rdtsc.eax ), - "=d" ( profiler->rdtsc.edx ) ); - return ( profiler->timestamp - last_timestamp ); + /* If profiling is active then record start timestamp */ + if ( PROFILING ) + profiler->started = profile_timestamp(); } /** - * Perform profiling + * Record profiling result * - * @ret delta Elapsed ticks since last call to profile(). - * - * When you only need one profiler, you can avoid the hassle of - * creating your own @c profiler data structure by using - * simple_profile() instead. - * - * simple_profile() is equivalent to profile(&simple_profiler), where - * @c simple_profiler is a @c profiler data structure that is static - * to each object which includes @c profile.h. + * @v profiler Profiler */ -static inline __attribute__ (( always_inline )) unsigned long -simple_profile ( void ) { - return profile ( &simple_profiler ); +static inline __attribute__ (( always_inline )) void +profile_stop ( struct profiler *profiler ) { + uint64_t ended; + + /* If profiling is active then record end timestamp and update stats */ + if ( PROFILING ) { + ended = profile_timestamp(); + profile_update ( profiler, ( ended - profiler->started ) ); + } } #endif /* _IPXE_PROFILE_H */ |