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