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