1 /*
2  * Orc - Oil Runtime Compiler
3  * Copyright (c) 2003,2004 David A. Schleef <ds@schleef.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 #include <orc-test/orcprofile.h>
33 #include <orc/orcdebug.h>
34 
35 #ifdef HAVE_SYS_TIME_H
36 #include <sys/time.h>
37 #endif
38 #include <time.h>
39 #include <string.h>
40 #include <math.h>
41 
42 /* not used because it requires a kernel patch */
43 /* #undef USE_CORTEX_A8_COUNTER */
44 
45 /**
46  * SECTION:orcprofile
47  * @title:OrcProfile
48  * @short_description:
49  * Measuring the length of time needed to execute Orc functions.
50  *
51  */
52 
53 /**
54  * orc_profile_init:
55  * @prof: the OrcProfile structure
56  *
57  * Initializes a profiling structure.
58  */
59 void
orc_profile_init(OrcProfile * prof)60 orc_profile_init (OrcProfile *prof)
61 {
62 #if defined(__GNUC__) && defined(HAVE_ARM) && defined(USE_CORTEX_A8_COUNTER)
63   unsigned int flags;
64 
65   __asm__ volatile ("mrc p15, 0, %0, c9, c12, 0" : "=r" (flags));
66   flags |= 1;
67   __asm__ volatile ("mcr p15, 0, %0, c9, c12, 0" :: "r" (flags));
68 
69   __asm__ volatile ("mcr p15, 0, %0, c9, c12, 2" :: "r"(1<<31));
70   __asm__ __volatile__("  mcr p15, 0, %0, c9, c13, 0" :: "r" (0));
71 
72   __asm__ volatile ("mcr p15, 0, %0, c9, c12, 1" :: "r"(1<<31));
73 #endif
74   memset(prof, 0, sizeof(OrcProfile));
75 
76   prof->min = -1;
77 
78 }
79 
80 /**
81  * orc_profile_stop_handle:
82  * @prof: the OrcProfile structure
83  *
84  * Handles post-processing of a single profiling run.
85  *
86  * FIXME: need more info
87  */
88 void
orc_profile_stop_handle(OrcProfile * prof)89 orc_profile_stop_handle (OrcProfile *prof)
90 {
91   int i;
92 
93   prof->last = prof->stop - prof->start;
94 
95   prof->total += prof->last;
96   prof->n++;
97 
98   if (prof->last < prof->min) prof->min = prof->last;
99 
100   for(i=0;i<prof->hist_n;i++) {
101     if (prof->last == prof->hist_time[i]) {
102       prof->hist_count[i]++;
103       break;
104     }
105   }
106   if (i == prof->hist_n && prof->hist_n < ORC_PROFILE_HIST_LENGTH) {
107     prof->hist_time[prof->hist_n] = prof->last;
108     prof->hist_count[prof->hist_n] = 1;
109     prof->hist_n++;
110   }
111 }
112 
113 /**
114  * orc_profile_get_ave_std:
115  * @prof: the OrcProfile structure
116  * @ave_p: pointer to average
117  * @std_p: pointer to standard deviation
118  *
119  * Calculates the average and standard deviation of a number of
120  * profiling runs, and places the results in the locations
121  * provided by @ave_p and @std_p.  Either @ave_p and @std_p may
122  * be NULL, in which case the values will not be written.
123  */
124 void
orc_profile_get_ave_std(OrcProfile * prof,double * ave_p,double * std_p)125 orc_profile_get_ave_std (OrcProfile *prof, double *ave_p, double *std_p)
126 {
127   double ave;
128   double std;
129   int max_i;
130   double off;
131   double s;
132   double s2;
133   int i;
134   int n;
135   double x;
136 
137   do {
138     s = s2 = 0;
139     n = 0;
140     max_i = -1;
141     for(i=0;i<10;i++){
142       x = prof->hist_time[i];
143       s2 += x * x * prof->hist_count[i];
144       s += x * prof->hist_count[i];
145       n += prof->hist_count[i];
146       if (prof->hist_count[i] > 0) {
147         if (max_i == -1 || prof->hist_time[i] > prof->hist_time[max_i]) {
148           max_i = i;
149         }
150       }
151     }
152 
153     ave = s / n;
154     std = sqrt (s2 - s * s / n + n*n) / (n-1);
155     off = (prof->hist_time[max_i] - ave)/std;
156 
157     if (off > 4.0) {
158       prof->hist_count[max_i] = 0;
159     }
160   } while (off > 4.0);
161 
162   if (ave_p) *ave_p = ave;
163   if (std_p) *std_p = std;
164 }
165 
166 
167 static unsigned long
oil_profile_stamp_default(void)168 oil_profile_stamp_default (void)
169 {
170 #if defined(__GNUC__) && (defined(HAVE_I386) || defined(HAVE_AMD64))
171   unsigned long ts;
172   __asm__ __volatile__("rdtsc\n" : "=a" (ts) : : "edx");
173   return ts;
174 #elif defined(__GNUC__) && defined(HAVE_ARM) && defined(USE_CORTEX_A8_COUNTER)
175   unsigned int ts;
176   /* __asm__ __volatile__("  mrc p14, 0, %0, c1, c0, 0 \n" : "=r" (ts)); */
177   __asm__ __volatile__("  mrc p15, 0, %0, c9, c13, 0 \n" : "=r" (ts));
178   return ts;
179 #elif defined(_MSC_VER) && defined(HAVE_I386)
180   unsigned long ts;
181   __asm push edx
182   __asm __emit 0fh __asm __emit 031h
183   __asm mov ts, eax
184   __asm pop edx
185 #elif defined(HAVE_CLOCK_GETTIME) && defined(HAVE_MONOTONIC_CLOCK)
186   struct timespec ts;
187   clock_gettime (CLOCK_MONOTONIC, &ts);
188   return 1000000000*ts.tv_sec + ts.tv_nsec;
189 #elif defined(HAVE_GETTIMEOFDAY)
190   struct timeval tv;
191   gettimeofday(&tv,NULL);
192   return 1000000*(unsigned long)tv.tv_sec + (unsigned long)tv.tv_usec;
193 #else
194   return 0;
195 #endif
196 }
197 
198 static unsigned long (*_orc_profile_stamp)(void) = oil_profile_stamp_default;
199 
200 /**
201  * orc_profile_stamp:
202  *
203  * Creates a timestamp based on a CPU-specific high-frequency
204  * counter, if available.
205  *
206  * Returns: a timestamp
207  */
208 unsigned long
orc_profile_stamp(void)209 orc_profile_stamp (void)
210 {
211   return _orc_profile_stamp();
212 }
213 
214 void
_orc_profile_init(void)215 _orc_profile_init (void)
216 {
217 
218 }
219 
220