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