1#ifndef _GPXE_PROFILE_H 2#define _GPXE_PROFILE_H 3 4/** @file 5 * 6 * Profiling 7 * 8 */ 9 10FILE_LICENCE ( GPL2_OR_LATER ); 11 12#include <stdint.h> 13 14/** 15 * A data structure for storing profiling information 16 */ 17union profiler { 18 /** Timestamp (in CPU-specific "ticks") */ 19 uint64_t timestamp; 20 /** Registers returned by rdtsc. 21 * 22 * This part should really be architecture-specific code. 23 */ 24 struct { 25 uint32_t eax; 26 uint32_t edx; 27 } rdtsc; 28}; 29 30/** 31 * Static per-object profiler, for use with simple_profile() 32 */ 33static union profiler simple_profiler; 34 35/** 36 * Perform profiling 37 * 38 * @v profiler Profiler data structure 39 * @ret delta Elapsed ticks since last call to profile(). 40 * 41 * Call profile() both before and after the code you wish to measure. 42 * The "after" call will return the measurement. For example: 43 * 44 * @code 45 * 46 * profile ( &profiler ); 47 * ... do something here ... 48 * printf ( "It took %ld ticks to execute\n", profile ( &profiler ) ); 49 * 50 * @endcode 51 */ 52static inline __attribute__ (( always_inline )) unsigned long 53profile ( union profiler *profiler ) { 54 uint64_t last_timestamp = profiler->timestamp; 55 56 __asm__ __volatile__ ( "rdtsc" : 57 "=a" ( profiler->rdtsc.eax ), 58 "=d" ( profiler->rdtsc.edx ) ); 59 return ( profiler->timestamp - last_timestamp ); 60} 61 62/** 63 * Perform profiling 64 * 65 * @ret delta Elapsed ticks since last call to profile(). 66 * 67 * When you only need one profiler, you can avoid the hassle of 68 * creating your own @c profiler data structure by using 69 * simple_profile() instead. 70 * 71 * simple_profile() is equivalent to profile(&simple_profiler), where 72 * @c simple_profiler is a @c profiler data structure that is static 73 * to each object which includes @c profile.h. 74 */ 75static inline __attribute__ (( always_inline )) unsigned long 76simple_profile ( void ) { 77 return profile ( &simple_profiler ); 78} 79 80#endif /* _GPXE_PROFILE_H */ 81