base: Move Stats::Info functions to its own source file
[gem5.git] / src / base / statistics.cc
1 /*
2 * Copyright (c) 2019-2020 Arm Limited
3 * All rights reserved.
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2003-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 */
40
41 #include "base/statistics.hh"
42
43 #include <cassert>
44 #include <list>
45 #include <map>
46 #include <string>
47 #include <utility>
48
49 #include "base/callback.hh"
50 #include "base/logging.hh"
51 #include "sim/root.hh"
52
53 namespace Stats {
54
55 // We wrap these in a function to make sure they're built in time.
56 std::list<Info *> &
57 statsList()
58 {
59 static std::list<Info *> the_list;
60 return the_list;
61 }
62
63 MapType &
64 statsMap()
65 {
66 static MapType the_map;
67 return the_map;
68 }
69
70 void
71 InfoAccess::setInfo(Group *parent, Info *info)
72 {
73 panic_if(statsMap().find(this) != statsMap().end() ||
74 _info != nullptr,
75 "shouldn't register stat twice!");
76
77 // New-style stats are reachable through the hierarchy and
78 // shouldn't be added to the global lists.
79 if (parent) {
80 _info = info;
81 return;
82 }
83
84 statsList().push_back(info);
85
86 #ifndef NDEBUG
87 std::pair<MapType::iterator, bool> result =
88 #endif
89 statsMap().insert(std::make_pair(this, info));
90 assert(result.second && "this should never fail");
91 assert(statsMap().find(this) != statsMap().end());
92 }
93
94 void
95 InfoAccess::setParams(const StorageParams *params)
96 {
97 info()->storageParams = params;
98 }
99
100 void
101 InfoAccess::setInit()
102 {
103 info()->flags.set(init);
104 }
105
106 Info *
107 InfoAccess::info()
108 {
109 if (_info) {
110 // New-style stats
111 return _info;
112 } else {
113 // Legacy stats
114 MapType::const_iterator i = statsMap().find(this);
115 assert(i != statsMap().end());
116 return (*i).second;
117 }
118 }
119
120 const Info *
121 InfoAccess::info() const
122 {
123 if (_info) {
124 // New-style stats
125 return _info;
126 } else {
127 // Legacy stats
128 MapType::const_iterator i = statsMap().find(this);
129 assert(i != statsMap().end());
130 return (*i).second;
131 }
132 }
133
134 StorageParams::~StorageParams()
135 {
136 }
137
138 void
139 HistStor::grow_out()
140 {
141 int size = cvec.size();
142 int zero = size / 2; // round down!
143 int top_half = zero + (size - zero + 1) / 2; // round up!
144 int bottom_half = (size - zero) / 2; // round down!
145
146 // grow down
147 int low_pair = zero - 1;
148 for (int i = zero - 1; i >= bottom_half; i--) {
149 cvec[i] = cvec[low_pair];
150 if (low_pair - 1 >= 0)
151 cvec[i] += cvec[low_pair - 1];
152 low_pair -= 2;
153 }
154 assert(low_pair == 0 || low_pair == -1 || low_pair == -2);
155
156 for (int i = bottom_half - 1; i >= 0; i--)
157 cvec[i] = Counter();
158
159 // grow up
160 int high_pair = zero;
161 for (int i = zero; i < top_half; i++) {
162 cvec[i] = cvec[high_pair];
163 if (high_pair + 1 < size)
164 cvec[i] += cvec[high_pair + 1];
165 high_pair += 2;
166 }
167 assert(high_pair == size || high_pair == size + 1);
168
169 for (int i = top_half; i < size; i++)
170 cvec[i] = Counter();
171
172 max_bucket *= 2;
173 min_bucket *= 2;
174 bucket_size *= 2;
175 }
176
177 void
178 HistStor::grow_convert()
179 {
180 int size = cvec.size();
181 int half = (size + 1) / 2; // round up!
182 //bool even = (size & 1) == 0;
183
184 int pair = size - 1;
185 for (int i = size - 1; i >= half; --i) {
186 cvec[i] = cvec[pair];
187 if (pair - 1 >= 0)
188 cvec[i] += cvec[pair - 1];
189 pair -= 2;
190 }
191
192 for (int i = half - 1; i >= 0; i--)
193 cvec[i] = Counter();
194
195 min_bucket = -max_bucket;// - (even ? bucket_size : 0);
196 bucket_size *= 2;
197 }
198
199 void
200 HistStor::grow_up()
201 {
202 int size = cvec.size();
203 int half = (size + 1) / 2; // round up!
204
205 int pair = 0;
206 for (int i = 0; i < half; i++) {
207 cvec[i] = cvec[pair];
208 if (pair + 1 < size)
209 cvec[i] += cvec[pair + 1];
210 pair += 2;
211 }
212 assert(pair == size || pair == size + 1);
213
214 for (int i = half; i < size; i++)
215 cvec[i] = Counter();
216
217 max_bucket *= 2;
218 bucket_size *= 2;
219 }
220
221 void
222 HistStor::add(HistStor *hs)
223 {
224 int b_size = hs->size();
225 assert(size() == b_size);
226 assert(min_bucket == hs->min_bucket);
227
228 sum += hs->sum;
229 logs += hs->logs;
230 squares += hs->squares;
231 samples += hs->samples;
232
233 while (bucket_size > hs->bucket_size)
234 hs->grow_up();
235 while (bucket_size < hs->bucket_size)
236 grow_up();
237
238 for (uint32_t i = 0; i < b_size; i++)
239 cvec[i] += hs->cvec[i];
240 }
241
242 Formula::Formula(Group *parent, const char *name, const char *desc)
243 : DataWrapVec<Formula, FormulaInfoProxy>(parent, name, desc)
244
245 {
246 }
247
248
249
250 Formula::Formula(Group *parent, const char *name, const char *desc,
251 const Temp &r)
252 : DataWrapVec<Formula, FormulaInfoProxy>(parent, name, desc)
253 {
254 *this = r;
255 }
256
257 const Formula &
258 Formula::operator=(const Temp &r)
259 {
260 assert(!root && "Can't change formulas");
261 root = r.getNodePtr();
262 setInit();
263 assert(size());
264 return *this;
265 }
266
267 const Formula &
268 Formula::operator+=(Temp r)
269 {
270 if (root)
271 root = NodePtr(new BinaryNode<std::plus<Result> >(root, r));
272 else {
273 root = r.getNodePtr();
274 setInit();
275 }
276
277 assert(size());
278 return *this;
279 }
280
281 const Formula &
282 Formula::operator/=(Temp r)
283 {
284 assert (root);
285 root = NodePtr(new BinaryNode<std::divides<Result> >(root, r));
286
287 assert(size());
288 return *this;
289 }
290
291
292 void
293 Formula::result(VResult &vec) const
294 {
295 if (root)
296 vec = root->result();
297 }
298
299 Result
300 Formula::total() const
301 {
302 return root ? root->total() : 0.0;
303 }
304
305 size_type
306 Formula::size() const
307 {
308 if (!root)
309 return 0;
310 else
311 return root->size();
312 }
313
314 void
315 Formula::reset()
316 {
317 }
318
319 bool
320 Formula::zero() const
321 {
322 VResult vec;
323 result(vec);
324 for (VResult::size_type i = 0; i < vec.size(); ++i)
325 if (vec[i] != 0.0)
326 return false;
327 return true;
328 }
329
330 std::string
331 Formula::str() const
332 {
333 return root ? root->str() : "";
334 }
335
336 Handler resetHandler = NULL;
337 Handler dumpHandler = NULL;
338
339 void
340 registerHandlers(Handler reset_handler, Handler dump_handler)
341 {
342 resetHandler = reset_handler;
343 dumpHandler = dump_handler;
344 }
345
346 CallbackQueue dumpQueue;
347 CallbackQueue resetQueue;
348
349 void
350 processResetQueue()
351 {
352 resetQueue.process();
353 }
354
355 void
356 processDumpQueue()
357 {
358 dumpQueue.process();
359 }
360
361 void
362 registerResetCallback(const std::function<void()> &callback)
363 {
364 resetQueue.push_back(callback);
365 }
366
367 bool _enabled = false;
368
369 bool
370 enabled()
371 {
372 return _enabled;
373 }
374
375 void
376 enable()
377 {
378 if (_enabled)
379 fatal("Stats are already enabled");
380
381 _enabled = true;
382 }
383
384 void
385 dump()
386 {
387 if (dumpHandler)
388 dumpHandler();
389 else
390 fatal("No registered Stats::dump handler");
391 }
392
393 void
394 reset()
395 {
396 if (resetHandler)
397 resetHandler();
398 else
399 fatal("No registered Stats::reset handler");
400 }
401
402 const Info *
403 resolve(const std::string &name)
404 {
405 const auto &it = nameMap().find(name);
406 if (it != nameMap().cend()) {
407 return it->second;
408 } else {
409 return Root::root()->resolveStat(name);
410 }
411 }
412
413 void
414 registerDumpCallback(const std::function<void()> &callback)
415 {
416 dumpQueue.push_back(callback);
417 }
418
419 } // namespace Stats
420
421 void
422 debugDumpStats()
423 {
424 Stats::dump();
425 }