profile.h

00001 /*
00002  * $Id$
00003  * 
00004  * Copyright (C) 2007 iptelorg GmbH
00005  *
00006  * Permission to use, copy, modify, and distribute this software for any
00007  * purpose with or without fee is hereby granted, provided that the above
00008  * copyright notice and this permission notice appear in all copies.
00009  *
00010  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00011  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00012  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00013  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00014  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00015  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00016  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00017  */
00018 /*
00019  * Basic profile using the cpu cycle counter
00020  *
00021  * cycles_t - an unsigned interger type used for storing the cpu cycles
00022  *            (unsigned long long for now)
00023  *
00024  * cycles_t get_cpu_cycles() - returns the current cpu cycles counter
00025  *
00026  * void     get_cpu_cycles_uint(unsigned* u1, unsigned* u2) 
00027  *                            - sets u1 and u2 to the least significant, 
00028  *                              respective most significant 32 bit word of
00029  *                              the cpu cycles counter
00030  * struct profile_data;            - holds all the profile results
00031  *                               (last call cycles, max cycles, total cycles,
00032  *                                no. of profile_start calls, no. of 
00033  *                                profile_end calls, name use in profile_init)
00034  * void     profile_init(pd, name) - intialize a profile structure
00035  * void     profile_start(pd)      - starts profiling (call before calling
00036  *                               the target function)
00037  * void     profile_end(pd)        - stops profiling (call after the target
00038  *                               function returns)
00039  * 
00040  */
00041  /*
00042  * Config defines:   CC_GCC_LIKE_ASM  - the compiler support gcc style
00043  *                     inline asm,
00044  *                  __CPU_x86, __CPU_x86_64, __CPU_sparc64
00045  */
00046 /* 
00047  * History:
00048  * --------
00049  *  2007-06-23  created by andrei
00050  */
00051 
00052 
00053 
00054 
00055 #ifndef _profile_h
00056 #define _profile_h
00057 
00058 #include <string.h>
00059 
00060 /*
00061  * cycles_t - an unsigned interger type used for storing the cpu cycles
00062  *            (unsigned long long for now)
00063  *
00064  * cycles_t get_cpu_cycles() - returns the current cpu cycles counter
00065  * void     get_cpu_cycles_uint(unsigned* u1, unsigned* u2) 
00066  *                            - sets u1 and u2 to the least significant, 
00067  *                              respective most significant 32 bit word of
00068  *                              the cpu cycles counter
00069  */
00070 
00071 #if defined __CPU_i386 && ! defined __CPU_x86
00072 #define __CPU_x86
00073 #endif
00074 
00075 #ifdef __CPU_x86
00076 typedef unsigned long long cycles_t;
00077 
00078 inline static cycles_t get_cpu_cycles()
00079 {
00080         cycles_t r;
00081         asm volatile( "rdtsc \n\t" : "=A"(r));
00082         return r;
00083 }
00084 
00085 #define get_cpu_cycles_uint(u1, u2) \
00086         do{ \
00087                 /* result in edx:eax */ \
00088                 asm volatile( "rdtsc \n\t" : "=a"(*(u1)), "=d"(*(u2))); \
00089         }while(0)
00090 
00091 #elif defined __CPU_x86_64
00092 typedef unsigned long long cycles_t;
00093 
00094 inline static cycles_t get_cpu_cycles()
00095 {
00096         unsigned int u1, u2;
00097         asm volatile( "rdtsc \n\t" : "=a"(u1), "=d"(u2));
00098         return ((cycles_t)u2<<32ULL)|u1;
00099 }
00100 
00101 
00102 #define get_cpu_cycles_uint(u1, u2) \
00103         do{ \
00104                 /* result in edx:eax */ \
00105                 asm volatile( "rdtsc \n\t" : "=a"(*(u1)), "=d"(*(u2))); \
00106         }while(0)
00107 
00108 #elif defined __CPU_sparc64
00109 
00110 typedef unsigned long long cycles_t;
00111 
00112 inline static cycles_t get_cpu_cycles()
00113 {
00114 #if ! defined(_LP64)
00115 #warning "ilp32 mode "
00116         struct uint_64{
00117                 unsigned int u2;
00118                 unsigned int u1;
00119         };
00120         union{
00121                 cycles_t c;
00122                 struct uint_64 u;
00123         }r;
00124         
00125         asm volatile("rd %%tick, %0 \n\t"
00126                                  "srlx %0, 32, %1 \n\t"
00127                                 : "=r"(r.u.u1), "=r"(r.u.u2));
00128         return r.c;
00129 #else
00130         cycles_t r;
00131         /* normal 64 bit mode (e.g. gcc -m64) */
00132         asm volatile("rd %%tick, %0" : "=r"(r));
00133         return r;
00134 #endif
00135 }
00136 inline static void  get_cpu_cycles_uint(unsigned int* u1, unsigned int* u2)
00137 {
00138         cycles_t r;
00139         asm volatile("rd %%tick, %0" : "=r"(r));
00140         *u1=(unsigned int)r;
00141         *u2=(unsigned int)(r>>32);
00142 }
00143 
00144 #else /* __CPU_xxx */
00145 #error "no get_cycles support for this CPU"
00146 #endif /* __CPU_xxx */
00147 
00148 
00149 union profile_cycles{
00150         cycles_t c;
00151         struct{
00152                 unsigned int u1;
00153                 unsigned int u2;
00154         }uint;
00155 };
00156 
00157 struct profile_data{
00158         cycles_t cycles;  /* last call */
00159         cycles_t total_cycles;
00160         cycles_t max_cycles;
00161         unsigned long entries; /* no. profile_start calls */
00162         unsigned long exits;   /* no. profile_end calls */
00163         char * name;
00164         
00165         /* private stuff */
00166         union profile_cycles init_rdtsc;
00167 };
00168 
00169 inline static void profile_init(struct profile_data* pd, char *name)
00170 {
00171         memset(pd, 0, sizeof(*pd));
00172         pd->name=name;
00173 }
00174 
00175 
00176 inline static void profile_start(struct profile_data* pd)
00177 {
00178         pd->entries++;
00179         pd->init_rdtsc.c=get_cpu_cycles();
00180 }
00181 
00182 
00183 inline static void profile_end(struct profile_data* pd)
00184 {
00185         pd->cycles=get_cpu_cycles()-pd->init_rdtsc.c;
00186         if (pd->max_cycles<pd->cycles) pd->max_cycles=pd->cycles;
00187         pd->total_cycles+=pd->cycles;
00188         pd->exits++;
00189 }
00190 
00191 
00192 #endif