mbgtools-lx  4.2.8
mbgpccyc.h
Go to the documentation of this file.
1 
2 /**************************************************************************
3  *
4  * $Id: mbgpccyc.h 1.8 2019/03/18 08:58:39 martin REL_M $
5  *
6  * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
7  *
8  * Description:
9  * Portable macros to get a machine's current cycle count.
10  *
11  * -----------------------------------------------------------------------
12  * $Log: mbgpccyc.h $
13  * Revision 1.8 2019/03/18 08:58:39 martin
14  * Cleanup and comments.
15  * Revision 1.7 2017/05/10 15:21:41 martin
16  * Tiny cleanup.
17  * Revision 1.6 2016/08/09 16:01:10 martin
18  * Syntax fix.
19  * Revision 1.5 2016/02/17 16:04:18 martin
20  * Include header file missing for FreeBSD.
21  * Revision 1.4 2015/10/19 09:16:45 martin
22  * Fixed some spelling.
23  * Revision 1.3 2014/10/08 13:10:14 martin
24  * Check for MBG_TGT_POSIX instead of MBG_TGT_UNIX.
25  * Revision 1.2 2012/03/12 13:45:57 martin
26  * Added cycles support for Linux/IA64, FreeBSD and NetBSD
27  * in kernel space.
28  * Use get_cycles() in Linux kernel mode if no special cycles support
29  * is provided for the given hardware platform.
30  * Revision 1.1 2011/06/23 15:36:07 martin
31  * Initial revision.
32  *
33  **************************************************************************/
34 
35 #ifndef _MBGPCCYC_H
36 #define _MBGPCCYC_H
37 
38 
39 /* Other headers to be included */
40 
41 #include <mbg_tgt.h>
42 #include <words.h>
43 
44 #if defined( MBG_TGT_NETBSD )
45  #if defined( MBG_TGT_KERNEL )
46  #include <machine/cpu.h>
47  #include <machine/cpu_counter.h> // for cycle counter abstraction
48  #endif
49 #endif
50 
51 #if defined( MBG_TGT_FREEBSD )
52  #if defined( MBG_TGT_KERNEL )
53  #if defined( MBG_ARCH_X86 )
54  #include <sys/time.h>
55  #include <machine/clock.h> // for symbol 'tsc_freq'
56  #endif
57  #endif
58 #endif
59 
60 #if defined( MBG_TGT_LINUX )
61  #if defined( MBG_ARCH_IA64 ) && defined( MBG_TGT_KERNEL )
62  #include <asm/ia64regs.h>
63  #endif
64 #endif
65 
66 
67 #ifdef _MBGPCCYC
68  #define _ext
69  #define _DO_INIT
70 #else
71  #define _ext extern
72 #endif
73 
74 
75 /* Start of header body */
76 
77 #ifdef __cplusplus
78 extern "C" {
79 #endif
80 
87 #if defined( MBG_TGT_WIN32 )
88 
89  // On Windows, QPC() is commonly used to retrieve a cycles count
90  // as LARGE_INTEGER union which has a LONGLONG QuadPart field,
91  // which in fact is a signed 64 bit integer.
92  typedef int64_t MBG_PC_CYCLES;
94 
95 #elif defined( MBG_TGT_POSIX )
96 
99 
100 #else
101 
102  typedef uint32_t MBG_PC_CYCLES;
103  typedef uint32_t MBG_PC_CYCLES_FREQUENCY;
104 
105 #endif
106 
107 
108 // MBG_PC_CYCLES and MBG_PC_CYCLES_FREQUENCY are always read in native
109 // machine endianess, so no endianess conversion is required.
110 
111 #define _mbg_swab_mbg_pc_cycles( _p ) \
112  _nop_macro_fnc()
113 
114 #define _mbg_swab_mbg_pc_cycles_frequency( _p ) \
115  _nop_macro_fnc()
116 
117 
118 
119 #if ( defined( MBG_TGT_LINUX ) || defined( MBG_TGT_BSD ) ) && defined( MBG_ARCH_X86 )
120 
121  static __mbg_inline unsigned long long int mbg_rdtscll( void )
122  {
123  // The code below is a hack to get around issues with
124  // different versions of gcc.
125  //
126  // Normally the inline asm code could look similar to:
127  //
128  // __asm__ volatile ( "rdtsc" : "=A" (x) )
129  //
130  // which would copy the output regs edx:eax as a 64 bit
131  // number to a variable x.
132  //
133  // The "=A" expression should implicitly tell the compiler
134  // the edx and eax registers have been clobbered. However,
135  // this does not seem to work properly at least with gcc 4.1.2
136  // shipped with Centos 5.
137  //
138  // If optimization level 1 or higher is used then function
139  // parameters are also passed in registers. If the inline
140  // code above is used inside a function then the edx register
141  // is clobbered but the gcc 4.1.2 is not aware of this and
142  // assumes edx is unchanged, which may yield faulty results
143  // or even lead to segmentation faults.
144  //
145  // A possible workaround could be to mark edx explicitly as
146  // being clobbered in the asm inline code, but unfortunately
147  // other gcc versions report an error if a register which is
148  // implicitly (by "=A") known to be clobbered is also listed
149  // explicitly to be clobbered.
150  //
151  // So the code below is a workaround which tells the compiler
152  // implicitly that the eax ("=a") and edx ("=d") registers
153  // are being used and thus clobbered.
154 
155  union
156  {
157  struct
158  {
159  uint32_t lo;
160  uint32_t hi;
161  } u32;
162 
163  uint64_t u64;
164 
165  } tsc_val;
166 
167  __asm__ __volatile__( "rdtsc" : "=a" (tsc_val.u32.lo), "=d" (tsc_val.u32.hi) );
168 
169  return tsc_val.u64;
170 
171  } // mbg_rdtscll
172 
173 #endif
174 
175 
176 
177 static __mbg_inline
178 void mbg_get_pc_cycles( MBG_PC_CYCLES *p )
179 {
180  #if !defined( OMIT_PC_CYCLES_SUPPORT )
181 
182  #if defined( MBG_TGT_WIN32 )
183 
184  #if defined( MBG_TGT_KERNEL ) // kernel space
185  *p = (MBG_PC_CYCLES) KeQueryPerformanceCounter( NULL ).QuadPart;
186  #else // user space
187  // Please note QPC() *may* fail if p points to a variable
188  // that is *not* at least 4-byte-aligned.
189  QueryPerformanceCounter( (LARGE_INTEGER *) p );
190  #endif
191 
192  #define MBG_PC_CYCLES_SUPPORTED 1
193 
194  #elif defined( MBG_TGT_LINUX ) && defined( MBG_ARCH_X86 )
195 
196  *p = mbg_rdtscll();
197  #define MBG_PC_CYCLES_SUPPORTED 1
198 
199  #elif defined( MBG_TGT_LINUX ) && defined( MBG_ARCH_IA64 ) && defined( MBG_TGT_KERNEL )
200 
201  unsigned long result = ia64_getreg( _IA64_REG_AR_ITC );
202  ia64_barrier();
203 
204  #ifdef CONFIG_ITANIUM
205  while (unlikely((__s32) result == -1))
206  {
207  result = ia64_getreg(_IA64_REG_AR_ITC);
208  ia64_barrier();
209  }
210  #endif
211 
212  *p = result;
213 
214  #define MBG_PC_CYCLES_SUPPORTED 1
215 
216  #elif defined( MBG_TGT_LINUX ) && defined( MBG_TGT_KERNEL )
217 
218  *p = get_cycles();
219  #define MBG_PC_CYCLES_SUPPORTED 1
220 
221  #elif defined( MBG_TGT_FREEBSD ) && defined( MBG_ARCH_X86 )
222 
223  *p = mbg_rdtscll();
224 
225  #define MBG_PC_CYCLES_SUPPORTED 1
226 
227  #elif defined( MBG_TGT_NETBSD ) && defined( MBG_TGT_KERNEL )
228 
229  *p = cpu_counter(); // TODO or cpu_counter_serializing()?
230 
231  #define MBG_PC_CYCLES_SUPPORTED 1
232 
233  #endif
234 
235  #endif
236 
237 
238  #if !defined( MBG_PC_CYCLES_SUPPORTED )
239 
240  *p = 0;
241  #define MBG_PC_CYCLES_SUPPORTED 0
242 
243  #endif
244 
245 } // mbg_get_pc_cycles
246 
247 
248 
249 static __mbg_inline
250 void mbg_get_pc_cycles_frequency( MBG_PC_CYCLES_FREQUENCY *p )
251 {
252  #if defined( MBG_TGT_WIN32 )
253  LARGE_INTEGER li;
254 
255  #if defined( MBG_TGT_KERNEL ) // kernel space
256  KeQueryPerformanceCounter( &li );
257  #else // user space
258  QueryPerformanceFrequency( &li );
259  #endif
260 
261  *p = li.QuadPart;
262 
263  #elif defined( MBG_TGT_LINUX ) && defined( MBG_ARCH_X86 ) && defined( MBG_TGT_KERNEL )
264 
265  *p = ( cpu_khz * 1000 );
266 
267  #elif defined( MBG_TGT_LINUX ) && defined( MBG_ARCH_IA64 )
268 
269  // TODO we probably can use:
270  //
271  // ia64_sal_freq_base(unsigned long which, unsigned long *ticks_per_second,
272  // unsigned long *drift_info)
273  // However, this is not tested.
274 
275  *p = 0;
276 
277  #elif defined( MBG_TGT_FREEBSD ) && defined( MBG_ARCH_X86 ) && defined( MBG_TGT_KERNEL )
278 
279  *p = tsc_freq;
280 
281  #elif defined( MBG_TGT_NETBSD ) && defined( MBG_TGT_KERNEL )
282 
283  *p = cpu_frequency( curcpu() );
284 
285  #else
286 
287  *p = 0;
288 
289  #endif
290 
291 } // mbg_get_pc_cycles_frequency
292 
293 
294 
295 static __mbg_inline
296 MBG_PC_CYCLES mbg_delta_pc_cycles( const MBG_PC_CYCLES *p1, const MBG_PC_CYCLES *p2 )
297 {
298  return *p1 - *p2;
299 
300 } // mbg_delta_pc_cycles
301 
302 
303 
304 /* ----- function prototypes begin ----- */
305 
306 /* This section was generated automatically */
307 /* by MAKEHDR, do not remove the comments. */
308 
309 /* (no header definitions found) */
310 
311 /* ----- function prototypes end ----- */
312 
313 #ifdef __cplusplus
314 }
315 #endif
316 
317 /* End of header body */
318 
319 #undef _ext
320 #undef _DO_INIT
321 
322 #endif /* _MBGPCCYC */
static __mbg_inline void mbg_get_pc_cycles(MBG_PC_CYCLES *p)
Definition: mbgpccyc.h:178
uint64_t u64
Definition: lan_util.c:101
__int64 int64_t
Definition: words.h:249
uint64_t MBG_PC_CYCLES_FREQUENCY
Definition: mbgpccyc.h:98
static __mbg_inline MBG_PC_CYCLES mbg_delta_pc_cycles(const MBG_PC_CYCLES *p1, const MBG_PC_CYCLES *p2)
Definition: mbgpccyc.h:296
unsigned __int64 uint64_t
Definition: words.h:250
int64_t MBG_PC_CYCLES
Generic types to hold PC cycle counter values.
Definition: mbgpccyc.h:97
static __mbg_inline void mbg_get_pc_cycles_frequency(MBG_PC_CYCLES_FREQUENCY *p)
Definition: mbgpccyc.h:250
uint32_t u32
Definition: lan_util.c:100