#ifndef _GPXE_PROFILE_H #define _GPXE_PROFILE_H /** @file * * Profiling * */ FILE_LICENCE ( GPL2_OR_LATER ); #include /** * 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 */