CACAO
cycles-stats.cpp
Go to the documentation of this file.
1 /* src/vm/cycles-stats.c - functions for cycle count statistics
2 
3  Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4  C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5  E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6  J. Wenninger, Institut f. Computersprachen - TU Wien
7 
8  This file is part of CACAO.
9 
10  This program is free software; you can redistribute it and/or
11  modify it under the terms of the GNU General Public License as
12  published by the Free Software Foundation; either version 2, or (at
13  your option) any later version.
14 
15  This program is distributed in the hope that it will be useful, but
16  WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with this program; if not, write to the Free Software
22  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23  02110-1301, USA.
24 
25  Contact: cacao@cacaojvm.org
26 
27  Authors: Edwin Steiner
28 
29  Changes:
30 
31 */
32 
33 #include "config.h"
34 #include "vm/types.hpp"
35 #include "vm/global.hpp"
36 
37 #if defined(ENABLE_CYCLES_STATS)
38 
39 #include <stdio.h>
40 #include <errno.h>
41 #include <string.h>
42 #include <assert.h>
43 #include "vm/cycles-stats.hpp"
44 
45 #include "toolbox/logging.hpp"
46 
47 struct cycles_stats_percentile {
48  int pct;
49  const char *name;
50 };
51 
52 static struct cycles_stats_percentile cycles_stats_percentile_defs[] = {
53  { 10, "10%-percentile" },
54  { 50, "median" },
55  { 90, "90%-percentile" },
56  { 99, "99%-percentile" },
57  { 0, NULL } /* sentinel */
58 };
59 
60 static double cycles_stats_cpu_MHz = 0.0;
61 
62 #define CYCLES_STATS_MAXLINE 100
63 
64 static double cycles_stats_get_cpu_MHz(void)
65 {
66  FILE *info;
67  char line[CYCLES_STATS_MAXLINE + 1];
68 
69  if (cycles_stats_cpu_MHz != 0.0)
70  return cycles_stats_cpu_MHz;
71 
72  info = fopen("/proc/cpuinfo","r");
73  if (!info) {
74  fprintf(log_get_logfile(),"error: could not open /proc/cpuinfo: %s\n",strerror(errno));
75  goto got_no_cpuinfo;
76  }
77 
78  while (!feof(info) && !ferror(info)) {
79  if (fgets(line,CYCLES_STATS_MAXLINE,info)
80  && sscanf(line,"cpu MHz : %lf",&cycles_stats_cpu_MHz) == 1)
81  {
82  fclose(info);
83  fprintf(log_get_logfile(),"CPU frequency used for statistics: %f MHz\n",
84  cycles_stats_cpu_MHz);
85  return cycles_stats_cpu_MHz;
86  }
87  }
88 
89  if (ferror(info)) {
90  fprintf(log_get_logfile(),"error reading /proc/cpuinfo: %s\n",strerror(errno));
91  }
92 
93  fclose(info);
94 
95 got_no_cpuinfo:
96  fprintf(log_get_logfile(),"warning: falling back to default CPU frequency for statistics\n");
97  cycles_stats_cpu_MHz = 1800.0;
98  return cycles_stats_cpu_MHz;
99 }
100 
101 u8 cycles_stats_measurement_overhead = 0;
102 
103 static void cycles_stats_print_percentile(FILE *file, const char *name,
104  double percentile, u8 count,
105  u8 cumul, double cumulcycles,
106  bool isoverhead, bool printforall)
107 {
108  u8 forall;
109  double cpuMHz = cycles_stats_get_cpu_MHz();
110  u8 cycles_per_ms = cpuMHz * 1000;
111 
112  if (isoverhead) {
113  fprintf(file,"\t\t%14s = %6.1f\n", name, percentile);
114  }
115  else {
116  percentile -= cycles_stats_measurement_overhead;
117 
118  fprintf(file,"\t\t%14s = %14.1f (+%llu)",
119  name, percentile,
120  (unsigned long long)cycles_stats_measurement_overhead);
121  if (printforall) {
122  forall = cumulcycles - cumul * cycles_stats_measurement_overhead
123  + percentile * (count - cumul);
124  fprintf(file," (%-23s: %15llu cycles = %6lu msec)",
125  (count == cumul) ? "total" : "capped here & extrapol.",
126  (unsigned long long)forall,
127  (unsigned long)(forall / cycles_per_ms));
128  }
129  fprintf(file,"\n");
130  }
131 }
132 
133 void cycles_stats_print(FILE *file,
134  const char *name, int nbins, int div,
135  u4 *bins, u8 count, u8 total, u8 min, u8 max,
136  int overhead)
137 {
138  s4 i;
139  struct cycles_stats_percentile *pcd;
140  u8 floor, ceiling;
141  u8 p;
142  u8 cumul;
143  double cumulcycles;
144  double percentile;
145  double cpuMHz = cycles_stats_get_cpu_MHz();
146  u8 cycles_per_ms = cpuMHz * 1000;
147 
148  fprintf(file,"\t%s: %llu calls\n",
149  (overhead) ? "measurement overhead determined by" : name,
150  (unsigned long long)count);
151 
152  fprintf(file,"\t%s cycles distribution:\n",
153  (overhead) ? "measurement overhead" : name);
154 
155  cycles_stats_print_percentile(file, "min", min, count, 0, 0, overhead, true);
156 
157  pcd = cycles_stats_percentile_defs;
158  for (; pcd->name; pcd++) {
159  floor = (count * pcd->pct) / 100;
160  ceiling = (count * pcd->pct + 99) / 100;
161  cumul = 0;
162  cumulcycles = 0;
163  p = 0;
164  percentile = -1.0;
165 
166  assert( ceiling <= floor + 1 );
167 
168  for (i=0; i<nbins; ++i) {
169 
170  /* { invariant: `cumul` samples are < `p` } */
171 
172  /* check if percentile lies exactly at the bin boundary */
173 
174  if (floor == cumul && floor == ceiling) {
175  percentile = p;
176  break;
177  }
178 
179  /* check if percentile lies within this bin */
180 
181  if (cumul <= floor && ceiling <= cumul + bins[i]) {
182  percentile = p + (double)div/2.0;
183  break;
184  }
185 
186  cumul += bins[i];
187  p += div;
188 
189  cumulcycles += bins[i] * (p - (double)div/2.0);
190 
191  /* { invariant: `cumul` samples are < `p` } */
192  }
193 
194  /* check if percentile lies exactly at the bin boundary */
195 
196  if (floor == cumul && floor == ceiling) {
197  percentile = p;
198  }
199 
200  if (percentile >= 0) {
201  if (overhead && pcd->pct == 50) {
202  cycles_stats_measurement_overhead = percentile;
203  }
204  cycles_stats_print_percentile(file, pcd->name, percentile,
205  count, cumul, cumulcycles,
206  overhead, true);
207  }
208  else {
209  if (!overhead)
210  p -= cycles_stats_measurement_overhead;
211  fprintf(file,"\t\t%14s = unknown (> %llu)\n", pcd->name, (unsigned long long)p);
212  }
213  }
214 
215  cycles_stats_print_percentile(file, "max", max, count, count,
216  total, overhead, true);
217 
218  if (!overhead) {
219  fprintf(file,"\t\t(assuming %llu cycles per ms)\n",
220  (unsigned long long)cycles_per_ms);
221  fprintf(file,"\t\t(assuming %llu cycles measurement overhead)\n",
222  (unsigned long long)cycles_stats_measurement_overhead);
223  }
224 
225  fprintf(file,"\n");
226 
227  cumul = 0;
228  for (i=0; i<nbins; ++i) {
229  cumul += bins[i];
230  fprintf(file,"\t\t< %8d: %10lu (%3d%%) %10lu\n",
231  (int)((i+1) * div),
232  (unsigned long) cumul,
233  (count) ? (int)((cumul * 100) / count) : 0,
234  (unsigned long) bins[i]);
235  }
236 
237  fprintf(file,"\t\t>= %8d: %10s (----) %10lu\n",
238  (int)(nbins * div),
239  "OVER",
240  (unsigned long) bins[nbins]);
241 }
242 
243 #endif /* defined(ENABLE_CYCLES_STATS) */
244 
245 /*
246  * These are local overrides for various environment variables in Emacs.
247  * Please do not remove this and leave it at the end of the file, where
248  * Emacs will automagically detect them.
249  * ---------------------------------------------------------------------
250  * Local variables:
251  * mode: c++
252  * indent-tabs-mode: t
253  * c-basic-offset: 4
254  * tab-width: 4
255  * End:
256  * vim:noexpandtab:sw=4:ts=4:
257  */
#define max(a, b)
Definition: lsra.hpp:80
FILE * log_get_logfile()
Definition: logging.cpp:90
JNIEnv jclass jobject const char * name
Definition: jvmti.h:312
#define min(a, b)
Definition: lsra.hpp:79
uint64_t u8
Definition: types.hpp:49
MIIterator i
int32_t s4
Definition: types.hpp:45
uint32_t u4
Definition: types.hpp:46