blob: a5bdd3a45b4a21858c1be29482f0b2d95e88d14c [file] [log] [blame]
#ifndef _GPXE_PROFILE_H
#define _GPXE_PROFILE_H
/** @file
*
* Profiling
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
/**
* A data structure for storing profiling information
*/
union profiler {
/** Timestamp (in CPU-specific "ticks") */
uint64_t timestamp;
/** Registers returned by rdtsc.
*
* This part should really be architecture-specific code.
*/
struct {
uint32_t eax;
uint32_t edx;
} rdtsc;
};
/**
* Static per-object profiler, for use with simple_profile()
*/
static union profiler simple_profiler;
/**
* Perform 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
*/
static inline __attribute__ (( always_inline )) unsigned long
profile ( union profiler *profiler ) {
uint64_t last_timestamp = profiler->timestamp;
__asm__ __volatile__ ( "rdtsc" :
"=a" ( profiler->rdtsc.eax ),
"=d" ( profiler->rdtsc.edx ) );
return ( profiler->timestamp - last_timestamp );
}
/**
* Perform profiling
*
* @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.
*/
static inline __attribute__ (( always_inline )) unsigned long
simple_profile ( void ) {
return profile ( &simple_profiler );
}
#endif /* _GPXE_PROFILE_H */