1 /*========================== begin_copyright_notice ============================
2
3 Copyright (C) 2019-2021 Intel Corporation
4
5 SPDX-License-Identifier: MIT
6
7 ============================= end_copyright_notice ===========================*/
8
9 #pragma once
10
11 #if defined( _INTERNAL) || defined( _DEBUG )
12 #define COMPILER_STATS_ENABLE 1
13 #endif
14
15 #include <cassert>
16 #include <unordered_map>
17 #include <map>
18 #include <sstream>
19 #include <memory>
20
21 class CompilerStats {
22 // Internal class for storing data. Every statistic knows its type and keeps values for
23 // each simd size (potenatially wastes memory but improves execution time).
24 struct Statistic
25 {
26 // Supported data types:
27 enum Type
28 {
29 type_bool,
30 type_int64,
31 type_double
32 };
33
34 // Supported simd sizes:
35 enum SimdType
36 {
37 SIMD_GENERIC = 0,
38 SIMD_8 = 1,
39 SIMD_16 = 2,
40 SIMD_32 = 3,
41 NUM_SIMD_TYPES
42 };
43
44 // Store every type as 64-bit value.
45 union Value
46 {
47 uint64_t value = 0;
48 bool bool_value;
49 int64_t int64_value;
50 double double_value;
51 };
52
53 // Helper function to convert from SimdType enum to integer represenation (8/16/32). Returns 0 for generic simd.
54 inline static int type_to_simd(SimdType simd_type);
55
56 // Helper function to convert from integer;
57 inline static SimdType simd_to_type(int simd);
58
59 // Get stat value for simd size expressed as integer. Pass 0 to access generic.
60 inline Value& operator[](int simd);
61 inline const Value& operator[](int simd) const;
62
63 // Members:
64 Type type;
65 Value values[NUM_SIMD_TYPES];
66 };
67
68 // Create empty statistic if does not exist, return existing if it does.
69 inline Statistic& PrivateInit(const std::string& name, Statistic::Type type, int simd);
70
71 // Returns true if the statistic name exists in the map.
72 inline bool PrivateFind(const std::string& name);
73
74 // Try to find statistic. Return empty one if it does not exist.
75 inline const Statistic& PrivateGet(const std::string& name, int simd) const;
76
IsEnabled()77 inline bool IsEnabled() const { return m_pState != nullptr; }
78
79 struct State {
80 std::unordered_map<std::string, Statistic> m_Stats;
81 bool m_CollectOnlyInitialized = true;
82 };
83
84 std::shared_ptr<State> m_pState;
85 Statistic m_ZeroStat;
86
87 public:
88 static constexpr Statistic::Type type_bool = Statistic::Type::type_bool;
89 static constexpr Statistic::Type type_int64 = Statistic::Type::type_int64;
90 static constexpr Statistic::Type type_double = Statistic::Type::type_double;
91
numSendStr()92 static constexpr const char* numSendStr() { return "NumSendInst"; };
numGRFSpillStr()93 static constexpr const char* numGRFSpillStr() { return "NumGRFSpill"; };
numGRFFillStr()94 static constexpr const char* numGRFFillStr() { return "NumGRFFill"; };
numCyclesStr()95 static constexpr const char* numCyclesStr() { return "NumCycles"; };
96
97
98 // Statistic collection is disabled by default.
99 inline void Enable(bool collectOnlyInitialized);
100
101 // Link statistics to the one from the provided object.
102 inline void Link(CompilerStats& sharedData);
103
104 // Merge the given Compiler Stats
105 inline void MergeStats(CompilerStats& from, int simd);
106
107 // Create statistic with value set to zero/false.
108 inline void Init(const std::string& name, Statistic::Type type, int simd=0);
109
110 // Set value to zero/false.
111 inline void Reset(const std::string& name, int simd = 0);
112
113 // Return true if the statistic name exists.
114 inline bool Find(const std::string& name);
115
116 // Set flag statistic to true.
117 inline void SetFlag(const std::string& name, int simd=0);
118
119 // Set value of integer statistic.
120 inline void SetI64(const std::string& name, int64_t value, int simd=0);
121
122 // Set value of floating point statistic.
123 inline void SetF64(const std::string& name, double value, int simd=0);
124
125 // Increase value of integer statistic.
126 inline void IncreaseI64(const std::string& name, int64_t value, int simd=0);
127
128 // Increase value of floating point statistic.
129 inline void IncreaseF64(const std::string& name, double value, int simd=0);
130
131 // Get value of a flag. Returns false if not found.
132 inline bool GetFlag(const std::string& name, int simd=0) const;
133
134 // Get value of an integer. Returns 0 if not found.
135 inline int64_t GetI64(const std::string& name, int simd=0) const;
136
137 // Get value of a floating point. Returns 0.0 if not found.
138 inline double GetF64(const std::string& name, int simd=0) const;
139
140 // Dump stats to csv format string.
141 inline std::string ToCsv() const;
142 };
143
144 // Enable collection of statistics.
145 // collectOnlyInitialized - if true, statistic initialization is required, otherwise statistic update will be ignored
Enable(bool collectOnlyInitialized)146 void CompilerStats::Enable(bool collectOnlyInitialized)
147 {
148 if (!IsEnabled())
149 {
150 m_pState = std::make_shared<State>();
151 m_pState->m_CollectOnlyInitialized = collectOnlyInitialized;
152 }
153 }
154
155 // Link statistics to the one from the provided object.
Link(CompilerStats & sharedData)156 void CompilerStats::Link(CompilerStats& sharedData)
157 {
158 if (m_pState != nullptr)
159 {
160 m_pState.reset();
161 }
162 m_pState = sharedData.m_pState;
163 }
164
MergeStats(CompilerStats & from,int simd)165 void CompilerStats::MergeStats(CompilerStats& from, int simd)
166 {
167 for (auto elem : from.m_pState->m_Stats)
168 {
169 auto name = elem.first;
170 auto type = elem.second.type;
171 auto f = m_pState->m_Stats.find(name);
172 if (f == m_pState->m_Stats.end())
173 {
174 Statistic& s = PrivateInit(name, type, simd);
175 s[simd].value = elem.second[simd].value;
176 }
177 else
178 {
179 assert(type == f->second.type);
180 // If flag, do OR rather than overwrite. This is because we want
181 // to preserve the bool stats from an earlier try at this simd.
182 if (type == Statistic::type_bool)
183 {
184 f->second[simd].value |= elem.second[simd].value;
185 }
186 else
187 {
188 f->second[simd].value = elem.second[simd].value;
189 }
190 }
191 }
192 }
193
194 // Create statistic with value set to zero/false.
Init(const std::string & name,Statistic::Type type,int simd)195 void CompilerStats::Init(const std::string& name, Statistic::Type type, int simd)
196 {
197 if (IsEnabled())
198 {
199 auto f = m_pState->m_Stats.find(name);
200 if(f == m_pState->m_Stats.end())
201 {
202 PrivateInit(name, type, simd);
203 }
204 }
205 }
206
207 // Set value to zero/false.
Reset(const std::string & name,int simd)208 void CompilerStats::Reset(const std::string& name, int simd)
209 {
210 if (IsEnabled())
211 {
212 auto f = m_pState->m_Stats.find(name);
213 if(f != m_pState->m_Stats.end())
214 {
215 f->second[simd].value = 0;
216 }
217 }
218 }
219
220 // Return true if the statistic name exists.
Find(const std::string & name)221 bool CompilerStats::Find(const std::string& name)
222 {
223 return PrivateFind(name);
224 }
225
226 // Set flag statistic to true.
227 // If statistic does not exist, create new one.
SetFlag(const std::string & name,int simd)228 void CompilerStats::SetFlag(const std::string& name, int simd)
229 {
230 if (IsEnabled())
231 {
232 auto f = m_pState->m_Stats.find(name);
233 if (f == m_pState->m_Stats.end())
234 {
235 if (!m_pState->m_CollectOnlyInitialized)
236 {
237 Statistic& s = PrivateInit(name, Statistic::type_bool, simd);
238 s[simd].bool_value = true;
239 }
240 }
241 else
242 {
243 Statistic& s = f->second;
244 assert(s.type == Statistic::type_bool);
245 s[simd].bool_value = true;
246 }
247 }
248 }
249
250 // Set value of integer statistic.
251 // If statistic does not exist, create new one.
SetI64(const std::string & name,int64_t value,int simd)252 void CompilerStats::SetI64(const std::string& name, int64_t value, int simd)
253 {
254 if (IsEnabled())
255 {
256 auto f = m_pState->m_Stats.find(name);
257 if (f == m_pState->m_Stats.end())
258 {
259 if (!m_pState->m_CollectOnlyInitialized)
260 {
261 Statistic& s = PrivateInit(name, Statistic::type_int64, simd);
262 s[simd].int64_value = value;
263 }
264 }
265 else
266 {
267 Statistic& s = f->second;
268 assert(s.type == Statistic::type_int64);
269 s[simd].int64_value = value;
270 }
271 }
272 }
273
274 // Set value of floating point statistic.
275 // If statistic does not exist, create new one.
SetF64(const std::string & name,double value,int simd)276 void CompilerStats::SetF64(const std::string& name, double value, int simd)
277 {
278 if (IsEnabled())
279 {
280 auto f = m_pState->m_Stats.find(name);
281 if (f == m_pState->m_Stats.end())
282 {
283 if (!m_pState->m_CollectOnlyInitialized)
284 {
285 Statistic& s = PrivateInit(name, Statistic::type_double, simd);
286 s[simd].double_value = value;
287 }
288 }
289 else
290 {
291 Statistic& s = f->second;
292 assert(s.type == Statistic::type_double);
293 s[simd].double_value = value;
294 }
295 }
296 }
297
298 // Increase value of integer statistic.
299 // If statistic does not exist, create new one.
IncreaseI64(const std::string & name,int64_t value,int simd)300 void CompilerStats::IncreaseI64(const std::string& name, int64_t value, int simd)
301 {
302 if (IsEnabled())
303 {
304 auto f = m_pState->m_Stats.find(name);
305 if (f == m_pState->m_Stats.end())
306 {
307 if (!m_pState->m_CollectOnlyInitialized)
308 {
309 Statistic& s = PrivateInit(name, Statistic::type_int64, simd);
310 s[simd].int64_value += value;
311 }
312 }
313 else
314 {
315 Statistic& s = f->second;
316 assert(s.type == Statistic::type_int64);
317 s[simd].int64_value += value;
318 }
319 }
320 }
321
322 // Increase value of floating point statistic.
323 // If statistic does not exist, create new one.
IncreaseF64(const std::string & name,double value,int simd)324 void CompilerStats::IncreaseF64(const std::string& name, double value, int simd)
325 {
326 if (IsEnabled())
327 {
328 auto f = m_pState->m_Stats.find(name);
329 if (f == m_pState->m_Stats.end())
330 {
331 if (!m_pState->m_CollectOnlyInitialized)
332 {
333 Statistic& s = PrivateInit(name, Statistic::type_double, simd);
334 s[simd].double_value += value;
335 }
336 }
337 else
338 {
339 Statistic& s = f->second;
340 assert(s.type == Statistic::type_double);
341 s[simd].double_value += value;
342 }
343 }
344 }
345
346 // Get value of a flag. Returns false if not found.
GetFlag(const std::string & name,int simd)347 bool CompilerStats::GetFlag(const std::string& name, int simd) const
348 {
349 return PrivateGet(name, simd)[simd].bool_value;
350 }
351
352 // Get value of an integer. Returns 0 if not found.
GetI64(const std::string & name,int simd)353 int64_t CompilerStats::GetI64(const std::string& name, int simd) const
354 {
355 return PrivateGet(name, simd)[simd].int64_value;
356 }
357
358 // Get value of a floating point. Returns 0.0 if not found.
GetF64(const std::string & name,int simd)359 double CompilerStats::GetF64(const std::string& name, int simd) const
360 {
361 return PrivateGet(name, simd)[simd].double_value;
362 }
363
364 // Dump stats to csv format string.
ToCsv()365 std::string CompilerStats::ToCsv() const
366 {
367 if (IsEnabled() == false)
368 return "";
369
370 std::stringstream ss;
371 ss << "Name,Generic,Simd8,Simd16,Simd32,\n";
372 std::map<std::string, Statistic> ordered(m_pState->m_Stats.begin(), m_pState->m_Stats.end());
373 for (auto elem : ordered)
374 {
375 ss << elem.first << ",";
376 for(int simd_type = 0; simd_type < Statistic::SimdType::NUM_SIMD_TYPES; simd_type++)
377 {
378 switch (elem.second.type)
379 {
380 case Statistic::Type::type_bool:
381 ss << elem.second.values[simd_type].bool_value << ",";
382 break;
383 case Statistic::Type::type_int64:
384 ss << elem.second.values[simd_type].int64_value << ",";
385 break;
386 case Statistic::Type::type_double:
387 ss << elem.second.values[simd_type].double_value << ",";
388 break;
389 }
390 }
391 ss << "\n";
392 }
393 return ss.str();
394 }
395
396 // Create empty statistic if does not exist, return existing if it does.
PrivateInit(const std::string & name,Statistic::Type type,int simd)397 CompilerStats::Statistic& CompilerStats::PrivateInit(const std::string& name, Statistic::Type type, int simd)
398 {
399 Statistic s;
400 s.type = type;
401 m_pState->m_Stats[name] = s;
402 return m_pState->m_Stats[name];
403 }
404
405 // Checks if the statistic name exists in the map
PrivateFind(const std::string & name)406 bool CompilerStats::PrivateFind(const std::string& name)
407 {
408 if (IsEnabled())
409 {
410 return m_pState->m_Stats.find(name) != m_pState->m_Stats.end();
411 }
412 return false;
413 }
414
415 // Try to find statistic. Return empty one if it does not exist.
PrivateGet(const std::string & name,int simd)416 const CompilerStats::Statistic& CompilerStats::PrivateGet(const std::string& name, int simd) const
417 {
418 auto f = m_pState->m_Stats.find(name);
419 if(f != m_pState->m_Stats.end())
420 {
421 return f->second;
422 }
423 return m_ZeroStat;
424 }
425
426
427 // Helper function to convert from SimdType enum to integer represenation (8/16/32). Returns 0 for generic simd.
type_to_simd(CompilerStats::Statistic::SimdType simd_type)428 int CompilerStats::Statistic::type_to_simd(CompilerStats::Statistic::SimdType simd_type)
429 {
430 switch (simd_type)
431 {
432 case SIMD_8: return 8;
433 case SIMD_16: return 16;
434 case SIMD_32: return 32;
435 case SIMD_GENERIC: return 0;
436 default: return 0;
437 }
438 }
439
440 // Helper function to convert from integer represenation (8/16/32) to SimdType enum. Returns SIMD_GENERIC for unexpected values.
simd_to_type(int simd)441 CompilerStats::Statistic::SimdType CompilerStats::Statistic::simd_to_type(int simd)
442 {
443 switch (simd)
444 {
445 case 8: return SIMD_8;
446 case 16: return SIMD_16;
447 case 32: return SIMD_32;
448 case 0: return SIMD_GENERIC;
449 default: return SIMD_GENERIC;
450 }
451 }
452
453 // Get stat value for simd size expressed as integer. Pass 0 to access generic.
454 CompilerStats::Statistic::Value& CompilerStats::Statistic::operator[](int simd)
455 {
456 const SimdType simd_type = simd_to_type(simd);
457 return values[simd_type];
458 }
459
460 // Get stat value for simd size expressed as integer. Pass 0 to access generic.
461 const CompilerStats::Statistic::Value& CompilerStats::Statistic::operator[](int simd) const
462 {
463 const SimdType simd_type = simd_to_type(simd);
464 return values[simd_type];
465 }
466
467