source: trunk/lib/perflib/BOM_Profiler.h @ 476

Last change on this file since 476 was 476, checked in by ksherdy, 9 years ago

Add method destroy_BOM_timer.

File size: 6.2 KB
Line 
1/*
2    BOM_Profiler.h - Binary Order of Magnitude Execution Time Profiler
3    Copyright (C) 2010  Robert D. Cameron and Dan Lin
4    Version 0.4
5    Licensed to the general public under Academic Free License version 3.0
6
7BOM_Profiler provides a lightweight multiplatform execution time profiling
8utility based on processor cycle counters.  It uses a binary logarithmic
9histogram technique that is useful in both highlighting patterns of
10cycle time distributions as well as identifing outliers in timing events
11due to interruptions for operating system services.
12
13In essence, BOM profiler is designed to collect statistics over a number
14of repetitions of particular timed events.  Statistics are gathered in the
15form of a logarithmic histogram of cycle times for processing a fixed number
16of elements between calls to start_BOM_interval and end_BOM_interval. 
17For example, an interval may correspond to processing 1024 single-byte
18elements by a particular routine.
19
20A timer t is created and initialized by a call to t = init_BOM_timer(). 
21Given a timer t, start_BOM_interval(t) initiates an interval measurement
22which completes with end_BOM_interval(t, n), where n is the number of
23elements processed. 
24
25dump_BOM_table(t) prints out a rudimentary histogram of the recorded
26intervals for a particular timer. 
27
28Although the basic concept of BOM_Profiler is architecture independent,
29processor-dependent routines for accessing time-stamp counters and
30determining the binary order of magnitude are included through external
31files.
32
33
34*/
35
36#ifndef BOM_Profiler_H
37#define BOM_Profiler_H
38
39#include <iostream>
40
41using namespace std;
42
43#include "i386_timer.h"
44
45#define BIT_COUNT 64
46#define MAX_TIMER_ENTRIES (1<<18)
47#define TIMER_SCALE_FACTOR 1000
48
49struct BOM_Table {
50  // current timing interval information
51  int timer_on;
52  int full;
53  timestamp_t interval_start[MAX_TIMER_ENTRIES];
54  timestamp_t interval_end[MAX_TIMER_ENTRIES];
55  unsigned int interval_elems[MAX_TIMER_ENTRIES]; 
56  unsigned int current_entry;
57};
58
59typedef struct BOM_Table BOM_Table;
60
61BOM_Table * init_BOM_timer () {
62  BOM_Table * timer_table = (BOM_Table *) malloc(sizeof(BOM_Table));
63  if (!timer_table) {
64    printf("Couldn't initialize BOM timer.\n");
65    exit(-1);
66  }
67  timer_table -> current_entry = 0;
68  timer_table -> full = 0;
69  timer_table -> timer_on = 0;
70  return timer_table;
71}
72
73
74static inline void start_BOM_interval(BOM_Table * timer_table) {
75  timer_table->timer_on = 1;
76  timer_table->interval_start[timer_table->current_entry] = read_cycle_counter();
77}
78
79static inline void end_BOM_interval(BOM_Table * timer_table, unsigned int elems) {
80  if (timer_table->timer_on) {
81    timer_table->interval_end[timer_table->current_entry] = read_cycle_counter();
82    timer_table->interval_elems[timer_table->current_entry] = elems;
83    timer_table->current_entry++;
84    if(timer_table->current_entry >= MAX_TIMER_ENTRIES) {
85      timer_table->full=1;
86      timer_table->current_entry=0;
87    }
88    timer_table->timer_on = 0;
89  }
90  else
91        fprintf(stderr,"Time interval end without a start!\n"); 
92}
93
94#define SEQ_TIMESTAMP_COUNT 8
95
96void dump_BOM_table(BOM_Table * timer_table) {
97  // an array of counts and timings per binary order of magnitude
98  int BOM_count[BIT_COUNT];
99  unsigned int BOM_elems[BIT_COUNT]; 
100  timestamp_t BOM_total_time[BIT_COUNT];
101  int i, BOM, b;
102  int this_count;
103  int cum_count = 0;
104  unsigned int entry = 0;
105  unsigned int total_entries;
106  unsigned int this_elems = 0;
107  unsigned int cum_elems = 0;
108  timestamp_t this_time;
109  timestamp_t cum_time = 0ULL;
110  timestamp_t this_avg;
111  timestamp_t cum_avg;
112  timestamp_t accumulated_cycles; 
113  timestamp_t sequential_stamps[SEQ_TIMESTAMP_COUNT];
114  timestamp_t timestamp_overhead;
115
116/*  Calculate minimum overhead of timestamps.  */
117
118  sequential_stamps[0] = read_cycle_counter();
119  sequential_stamps[1] = read_cycle_counter();
120  sequential_stamps[2] = read_cycle_counter();
121  sequential_stamps[3] = read_cycle_counter();
122  sequential_stamps[4] = read_cycle_counter();
123  sequential_stamps[5] = read_cycle_counter();
124  sequential_stamps[6] = read_cycle_counter();
125  sequential_stamps[7] = read_cycle_counter();
126  timestamp_overhead = sequential_stamps[1] - sequential_stamps[0];
127  for (i = 2; i < SEQ_TIMESTAMP_COUNT; i++) {
128    if (sequential_stamps[i] - sequential_stamps[i-1] < timestamp_overhead)
129         timestamp_overhead = sequential_stamps[i] - sequential_stamps[i-1];
130  }
131//  fprintf(stderr, "timestamp_overhead = %i\n", timestamp_overhead);
132
133
134  for (b = 0; b < BIT_COUNT; b++) {
135        BOM_count[b] = 0;
136        BOM_elems[b] = 0;
137        BOM_total_time[b] = 0;
138  }
139
140
141  total_entries = timer_table->full ? MAX_TIMER_ENTRIES : timer_table->current_entry;
142  for(entry = 0; entry < total_entries; entry++){
143        accumulated_cycles = timer_table->interval_end[entry] - timer_table->interval_start[entry] - timestamp_overhead;
144        if (accumulated_cycles > 0ULL) {
145//        cout << "accumulated_cycles =" << accumulated_cycles << "; elems = " << timer_table->interval_elems[entry] << endl;
146            BOM = binary_order_of_magnitude(accumulated_cycles*TIMER_SCALE_FACTOR/timer_table->interval_elems[entry]);
147            BOM_count[BOM]++;
148            BOM_elems[BOM] += timer_table->interval_elems[entry];
149            BOM_total_time[BOM] += accumulated_cycles;
150        }
151  }
152 
153  printf("Binary Order of Magnitude Profile\n");
154  for (b = 0; b < BIT_COUNT; b++) {
155    this_count = BOM_count[b];
156    cum_count += this_count;
157    this_time = BOM_total_time[b];
158    cum_time += this_time;
159    this_elems = BOM_elems[b];
160    cum_elems += this_elems;
161    if (this_count == 0) this_avg = 0ULL;
162    else this_avg = (TIMER_SCALE_FACTOR*this_time)/(this_elems);
163    if (cum_count == 0) cum_avg = 0ULL;
164    else cum_avg = (TIMER_SCALE_FACTOR*cum_time)/(cum_elems);
165    if (this_count > 0) {  // Only report intervals with nonzero counts.
166      printf("BOM %i: %i ", b, this_count);
167      printf("(avg time: %i %s/kElem) ", (int) this_avg, cycle_counter_units);
168      printf("Cumulative: %i ", cum_count);
169      printf("(avg: %i %s/kElem)\n", (int) cum_avg, cycle_counter_units);
170    }
171  }           
172}
173
174void destroy_BOM_timer(BOM_Table * timer_table) {
175        if(timer_table) {
176                delete timer_table;
177        }
178       
179}
180
181#endif
Note: See TracBrowser for help on using the repository browser.