1 /** @file kmp_stats_timing.cpp
2  * Timing functions
3  */
4 
5 
6 //===----------------------------------------------------------------------===//
7 //
8 //                     The LLVM Compiler Infrastructure
9 //
10 // This file is dual licensed under the MIT and the University of Illinois Open
11 // Source Licenses. See LICENSE.txt for details.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 
16 #include <stdlib.h>
17 #include <unistd.h>
18 
19 #include <iostream>
20 #include <iomanip>
21 #include <sstream>
22 
23 #include "kmp_stats_timing.h"
24 
25 using namespace std;
26 
27 #if KMP_OS_LINUX
28 # if KMP_MIC
29 double tsc_tick_count::tick_time()
30 {
31     // pretty bad assumption of 1GHz clock for MIC
32     return 1/((double)1000*1.e6);
33 }
34 # else
35 #  include <string.h>
36 // Extract the value from the CPUID information
37 double tsc_tick_count::tick_time()
38 {
39     static double result = 0.0;
40 
41     if (result == 0.0)
42     {
43         int cpuinfo[4];
44         char brand[256];
45 
46         __cpuid(cpuinfo, 0x80000000);
47         memset(brand, 0, sizeof(brand));
48         int ids = cpuinfo[0];
49 
50         for (unsigned int i=2; i<(ids^0x80000000)+2; i++)
51             __cpuid(brand+(i-2)*sizeof(cpuinfo), i | 0x80000000);
52 
53         char * start = &brand[0];
54         for (;*start == ' '; start++)
55             ;
56 
57         char * end = brand + KMP_STRLEN(brand) - 3;
58         uint64_t multiplier;
59 
60         if (*end == 'M') multiplier = 1000LL*1000LL;
61         else if (*end == 'G') multiplier = 1000LL*1000LL*1000LL;
62         else if (*end == 'T') multiplier = 1000LL*1000LL*1000LL*1000LL;
63         else
64         {
65             cout << "Error determining multiplier '" << *end << "'\n";
66             exit (-1);
67         }
68         *end = 0;
69         while (*end != ' ') end--;
70         end++;
71 
72         double freq = strtod(end, &start);
73         if (freq == 0.0)
74         {
75             cout << "Error calculating frequency " <<  end << "\n";
76             exit (-1);
77         }
78 
79         result = ((double)1.0)/(freq * multiplier);
80     }
81     return result;
82 }
83 # endif
84 #endif
85 
86 static bool useSI = true;
87 
88 // Return a formatted string after normalising the value into
89 // engineering style and using a suitable unit prefix (e.g. ms, us, ns).
90 std::string formatSI(double interval, int width, char unit)
91 {
92     std::stringstream os;
93 
94     if (useSI)
95     {
96         // Preserve accuracy for small numbers, since we only multiply and the positive powers
97         // of ten are precisely representable.
98         static struct { double scale; char prefix; } ranges[] = {
99             {1.e12,'f'},
100             {1.e9, 'p'},
101             {1.e6, 'n'},
102             {1.e3, 'u'},
103             {1.0,  'm'},
104             {1.e-3,' '},
105             {1.e-6,'k'},
106             {1.e-9,'M'},
107             {1.e-12,'G'},
108             {1.e-15,'T'},
109             {1.e-18,'P'},
110             {1.e-21,'E'},
111             {1.e-24,'Z'},
112             {1.e-27,'Y'}
113         };
114 
115         if (interval == 0.0)
116         {
117             os << std::setw(width-3) << std::right << "0.00" << std::setw(3) << unit;
118             return os.str();
119         }
120 
121         bool negative = false;
122         if (interval < 0.0)
123         {
124             negative = true;
125             interval = -interval;
126         }
127 
128         for (int i=0; i<(int)(sizeof(ranges)/sizeof(ranges[0])); i++)
129         {
130             if (interval*ranges[i].scale < 1.e0)
131             {
132                 interval = interval * 1000.e0 * ranges[i].scale;
133                 os << std::fixed << std::setprecision(2) << std::setw(width-3) << std::right <<
134                     (negative ? -interval : interval) << std::setw(2) << ranges[i].prefix << std::setw(1) << unit;
135 
136                 return os.str();
137             }
138         }
139     }
140     os << std::setprecision(2) << std::fixed << std::right << std::setw(width-3) << interval << std::setw(3) << unit;
141 
142     return os.str();
143 }
144 
145 tsc_tick_count::tsc_interval_t computeLastInLastOutInterval(timePair * times, int nTimes)
146 {
147     timePair lastTimes = times[0];
148     tsc_tick_count * startp = lastTimes.get_startp();
149     tsc_tick_count * endp   = lastTimes.get_endp();
150 
151     for (int i=1; i<nTimes; i++)
152     {
153        (*startp) = startp->later(times[i].get_start());
154        (*endp)   = endp->later  (times[i].get_end());
155     }
156 
157     return lastTimes.duration();
158 }
159 
160 std::string timePair::format() const
161 {
162     std::ostringstream oss;
163 
164     oss << start.getValue() << ":" << end.getValue() << " = " << (end-start).getValue();
165 
166     return oss.str();
167 }
168