* Removed all Id tags.
[cacao.git] / src / vm / cycles-stats.c
index 0734f1e54203b4b7d58eb2762f47662fb5c8c876..87d2c5101524138960ddfe7d541efd110dcc062e 100644 (file)
 
    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"
 
@@ -54,29 +55,109 @@ static struct cycles_stats_percentile cycles_stats_percentile_defs[] = {
        {  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;
 
@@ -87,7 +168,7 @@ void cycles_stats_print(FILE *file,
                                /* { invariant: `cumul` samples are < `p` } */
 
                                /* check if percentile lies exactly at the bin boundary */
-                               
+
                                if (floor == cumul && floor == ceiling) {
                                        percentile = p;
                                        break;
@@ -99,13 +180,15 @@ void cycles_stats_print(FILE *file,
                                        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) {
@@ -113,26 +196,43 @@ void cycles_stats_print(FILE *file,
                        }
 
                        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]);