Changes:
- $Id$
-
*/
#include "config.h"
#include "vm/types.h"
+#include "vm/global.h"
#if defined(ENABLE_CYCLES_STATS)
#include <stdio.h>
+#include <errno.h>
+#include <string.h>
#include <assert.h>
#include "vm/cycles-stats.h"
{ 0, NULL } /* sentinel */
};
+static double cycles_stats_cpu_MHz = 0.0;
+
+#define CYCLES_STATS_MAXLINE 100
+
+static double cycles_stats_get_cpu_MHz(void)
+{
+ FILE *info;
+ char line[CYCLES_STATS_MAXLINE + 1];
+
+ if (cycles_stats_cpu_MHz != 0.0)
+ return cycles_stats_cpu_MHz;
+
+ info = fopen("/proc/cpuinfo","r");
+ if (!info) {
+ fprintf(stderr,"error: could not open /proc/cpuinfo: %s\n",strerror(errno));
+ goto got_no_cpuinfo;
+ }
+
+ while (!feof(info) && !ferror(info)) {
+ if (fgets(line,CYCLES_STATS_MAXLINE,info)
+ && sscanf(line,"cpu MHz : %lf",&cycles_stats_cpu_MHz) == 1)
+ {
+ fclose(info);
+ fprintf(stderr,"CPU frequency used for statistics: %f MHz\n",
+ cycles_stats_cpu_MHz);
+ return cycles_stats_cpu_MHz;
+ }
+ }
+
+ if (ferror(info)) {
+ fprintf(stderr,"error reading /proc/cpuinfo: %s\n",strerror(errno));
+ }
+
+ fclose(info);
+
+got_no_cpuinfo:
+ fprintf(stderr,"warning: falling back to default CPU frequency for statistics\n");
+ cycles_stats_cpu_MHz = 1800.0;
+ return cycles_stats_cpu_MHz;
+}
+
+u8 cycles_stats_measurement_overhead = 0;
+
+static void cycles_stats_print_percentile(FILE *file, const char *name,
+ double percentile, u8 count,
+ u8 cumul, double cumulcycles,
+ bool isoverhead, bool printforall)
+{
+ u8 forall;
+ double cpuMHz = cycles_stats_get_cpu_MHz();
+ u8 cycles_per_ms = cpuMHz * 1000;
+
+ if (isoverhead) {
+ fprintf(file,"\t\t%14s = %6.1f\n", name, percentile);
+ }
+ else {
+ percentile -= cycles_stats_measurement_overhead;
+
+ fprintf(file,"\t\t%14s = %14.1f (+%llu)",
+ name, percentile,
+ (unsigned long long)cycles_stats_measurement_overhead);
+ if (printforall) {
+ forall = cumulcycles - cumul * cycles_stats_measurement_overhead
+ + percentile * (count - cumul);
+ fprintf(file," (%-23s: %15llu cycles = %6lu msec)",
+ (count == cumul) ? "total" : "capped here & extrapol.",
+ (unsigned long long)forall,
+ (unsigned long)(forall / cycles_per_ms));
+ }
+ fprintf(file,"\n");
+ }
+}
+
void cycles_stats_print(FILE *file,
const char *name, int nbins, int div,
- u4 *bins, u8 count, u8 min, u8 max)
+ u4 *bins, u8 count, u8 total, u8 min, u8 max,
+ int overhead)
{
s4 i;
struct cycles_stats_percentile *pcd;
u8 floor, ceiling;
u8 p;
u8 cumul;
+ double cumulcycles;
double percentile;
+ double cpuMHz = cycles_stats_get_cpu_MHz();
+ u8 cycles_per_ms = cpuMHz * 1000;
+
+ fprintf(file,"\t%s: %llu calls\n",
+ (overhead) ? "measurement overhead determined by" : name,
+ (unsigned long long)count);
- fprintf(file,"\t%s: %u calls\n",
- name, count);
-
- fprintf(file,"\t%s cycles distribution:\n", name);
-
- fprintf(file,"\t\t%20s = %llu\n", "min", (unsigned long long)min);
+ fprintf(file,"\t%s cycles distribution:\n",
+ (overhead) ? "measurement overhead" : name);
+
+ cycles_stats_print_percentile(file, "min", min, count, 0, 0, overhead, true);
pcd = cycles_stats_percentile_defs;
for (; pcd->name; pcd++) {
floor = (count * pcd->pct) / 100;
ceiling = (count * pcd->pct + 99) / 100;
cumul = 0;
+ cumulcycles = 0;
p = 0;
percentile = -1.0;
/* { invariant: `cumul` samples are < `p` } */
/* check if percentile lies exactly at the bin boundary */
-
+
if (floor == cumul && floor == ceiling) {
percentile = p;
break;
percentile = p + (double)div/2.0;
break;
}
-
+
cumul += bins[i];
p += div;
+ cumulcycles += bins[i] * (p - (double)div/2.0);
+
/* { invariant: `cumul` samples are < `p` } */
}
-
+
/* check if percentile lies exactly at the bin boundary */
if (floor == cumul && floor == ceiling) {
}
if (percentile >= 0) {
- fprintf(file,"\t\t%20s = %.1f\n", pcd->name, percentile);
+ if (overhead && pcd->pct == 50) {
+ cycles_stats_measurement_overhead = percentile;
+ }
+ cycles_stats_print_percentile(file, pcd->name, percentile,
+ count, cumul, cumulcycles,
+ overhead, true);
}
else {
- fprintf(file,"\t\t%20s = unknown (> %llu)\n", pcd->name, (unsigned long long)p);
+ if (!overhead)
+ p -= cycles_stats_measurement_overhead;
+ fprintf(file,"\t\t%14s = unknown (> %llu)\n", pcd->name, (unsigned long long)p);
}
}
-
- fprintf(file,"\t\t%20s = %llu\n", "max", (unsigned long long)max);
-
+
+ cycles_stats_print_percentile(file, "max", max, count, count,
+ total, overhead, true);
+
+ if (!overhead) {
+ fprintf(file,"\t\t(assuming %llu cycles per ms)\n",
+ (unsigned long long)cycles_per_ms);
+ fprintf(file,"\t\t(assuming %llu cycles measurement overhead)\n",
+ (unsigned long long)cycles_stats_measurement_overhead);
+ }
+
+ fprintf(file,"\n");
+
cumul = 0;
for (i=0; i<nbins; ++i) {
cumul += bins[i];
- fprintf(file,"\t\t< %5d: %10lu (%3d%%) %10lu\n",
+ fprintf(file,"\t\t< %8d: %10lu (%3d%%) %10lu\n",
(int)((i+1) * div),
(unsigned long) cumul,
- (int)((cumul * 100) / count),
+ (count) ? (int)((cumul * 100) / count) : 0,
(unsigned long) bins[i]);
}
-
- fprintf(file,"\t\t>= %5d: %10s (----) %10lu\n",
+
+ fprintf(file,"\t\t>= %8d: %10s (----) %10lu\n",
(int)(nbins * div),
"OVER",
(unsigned long) bins[nbins]);