update graph generating code
[gem5.git] / util / stats / info.py
1 from __future__ import division
2 import operator, re, types
3
4 source = None
5 display_run = 0
6
7 def issequence(t):
8 return isinstance(t, types.TupleType) or isinstance(t, types.ListType)
9
10 def total(f):
11 if isinstance(f, FormulaStat):
12 v = f.value
13 else:
14 v = f
15
16 f = FormulaStat()
17 if issequence(v):
18 f.value = reduce(operator.add, v)
19 else:
20 f.value = v
21
22 return f
23
24 def unaryop(op, f):
25 if isinstance(f, FormulaStat):
26 v = f.value
27 else:
28 v = f
29
30 if issequence(v):
31 return map(op, v)
32 else:
33 return op(v)
34
35 def zerodiv(lv, rv):
36 if rv == 0.0:
37 return 0.0
38 else:
39 return operator.truediv(lv, rv)
40
41 def wrapop(op, lv, rv):
42 if isinstance(lv, str):
43 return lv
44
45 if isinstance(rv, str):
46 return rv
47
48 return op(lv, rv)
49
50 def same(lv, rv):
51 for lrun,rrun in zip(lv.keys(),rv.keys()):
52 if lrun != rrun:
53 print 'lrun != rrun'
54 print lrun, rrun
55 print lv.keys()
56 print rv.keys()
57 return False
58 for lx,rx in zip(lv[lrun].keys(),rv[rrun].keys()):
59 if lx != rx:
60 print 'lx != rx'
61 print lx, rx
62 print lv[lrun].keys()
63 print rv[rrun].keys()
64 return False
65 for ly,ry in zip(lv[lrun][lx].keys(),rv[rrun][rx].keys()):
66 if ly != ry:
67 print 'ly != ry'
68 print ly, ry
69 print lv[lrun][lx].keys()
70 print rv[rrun][rx].keys()
71 return False
72 return True
73
74
75 def binaryop(op, lf, rf):
76 result = {}
77
78 if isinstance(lf, FormulaStat) and isinstance(rf, FormulaStat):
79 lv = lf.value
80 rv = rf.value
81
82 if not same(lv, rv):
83 raise AttributeError, "run,x,y not identical"
84
85 for run in lv.keys():
86 result[run] = {}
87 for x in lv[run].keys():
88 result[run][x] = {}
89 for y in lv[run][x].keys():
90 result[run][x][y] = wrapop(op, lv[run][x][y],
91 rv[run][x][y])
92 elif isinstance(lf, FormulaStat):
93 lv = lf.value
94 for run in lv.keys():
95 result[run] = {}
96 for x in lv[run].keys():
97 result[run][x] = {}
98 for y in lv[run][x].keys():
99 result[run][x][y] = wrapop(op, lv[run][x][y], rf)
100 elif isinstance(rf, FormulaStat):
101 rv = rf.value
102 for run in rv.keys():
103 result[run] = {}
104 for x in rv[run].keys():
105 result[run][x] = {}
106 for y in rv[run][x].keys():
107 result[run][x][y] = wrapop(op, lf, rv[run][x][y])
108
109 return result
110
111 def sums(x, y):
112 if issequence(x):
113 return map(lambda x, y: x + y, x, y)
114 else:
115 return x + y
116
117 def alltrue(list):
118 return reduce(lambda x, y: x and y, list)
119
120 def allfalse(list):
121 return not reduce(lambda x, y: x or y, list)
122
123 def enumerate(list):
124 return map(None, range(len(list)), list)
125
126 def cmp(a, b):
127 if a < b:
128 return -1
129 elif a == b:
130 return 0
131 else:
132 return 1
133
134 class Statistic(object):
135 def __init__(self, data):
136 self.__dict__.update(data.__dict__)
137 if not self.__dict__.has_key('value'):
138 self.__dict__['value'] = None
139 if not self.__dict__.has_key('bins'):
140 self.__dict__['bins'] = None
141 if not self.__dict__.has_key('ticks'):
142 self.__dict__['ticks'] = None
143
144 def __getattribute__(self, attr):
145 if attr == 'value':
146 if self.__dict__['value'] == None:
147 self.__dict__['value'] = self.getValue()
148 return self.__dict__['value']
149 else:
150 return super(Statistic, self).__getattribute__(attr)
151
152 def __setattr__(self, attr, value):
153 if attr == 'bins' or attr == 'ticks':
154 if attr == 'bins':
155 global db
156 if value is not None:
157 value = db.getBin(value)
158 elif attr == 'samples' and type(value) is str:
159 value = [ int(x) for x in value.split() ]
160
161 self.__dict__[attr] = value
162 self.__dict__['value'] = None
163 else:
164 super(Statistic, self).__setattr__(attr, value)
165
166 def getValue(self):
167 raise AttributeError, 'getValue() must be defined'
168
169 def zero(self):
170 return False
171
172 def __ne__(self, other):
173 return not (self == other)
174
175 def __str__(self):
176 return '%f' % (float(self))
177
178 class FormulaStat(object):
179 def __add__(self, other):
180 f = FormulaStat()
181 f.value = binaryop(operator.add, self, other)
182 return f
183 def __sub__(self, other):
184 f = FormulaStat()
185 f.value = binaryop(operator.sub, self, other)
186 return f
187 def __mul__(self, other):
188 f = FormulaStat()
189 f.value = binaryop(operator.mul, self, other)
190 return f
191 def __truediv__(self, other):
192 f = FormulaStat()
193 f.value = binaryop(zerodiv, self, other)
194 return f
195 def __mod__(self, other):
196 f = FormulaStat()
197 f.value = binaryop(operator.mod, self, other)
198 return f
199 def __radd__(self, other):
200 f = FormulaStat()
201 f.value = binaryop(operator.add, other, self)
202 return f
203 def __rsub__(self, other):
204 f = FormulaStat()
205 f.value = binaryop(operator.sub, other, self)
206 return f
207 def __rmul__(self, other):
208 f = FormulaStat()
209 f.value = binaryop(operator.mul, other, self)
210 return f
211 def __rtruediv__(self, other):
212 f = FormulaStat()
213 f.value = binaryop(zerodiv, other, self)
214 return f
215 def __rmod__(self, other):
216 f = FormulaStat()
217 f.value = binaryop(operator.mod, other, self)
218 return f
219 def __neg__(self):
220 f = FormulaStat()
221 f.value = unaryop(operator.neg, self)
222 return f
223 def __getitem__(self, idx):
224 f = FormulaStat()
225 f.value = {}
226 for key in self.value.keys():
227 f.value[key] = {}
228 f.value[key][0] = {}
229 f.value[key][0][0] = self.value[key][idx][0]
230 return f
231
232 def __float__(self):
233 if isinstance(self.value, FormulaStat):
234 return float(self.value)
235 if not self.value.has_key(display_run):
236 return (1e300*1e300)
237 if len(self.value[display_run]) == 1:
238 return self.value[display_run][0][0]
239 else:
240 #print self.value[display_run]
241 return self.value[display_run][4][0]
242 #raise ValueError
243
244 def display(self):
245 import display
246 d = display.VectorDisplay()
247 d.flags = 0
248 d.precision = 1
249 d.name = 'formula'
250 d.desc = 'formula'
251 val = self.value[display_run]
252 d.value = [ val[x][0] for x in val.keys() ]
253 d.display()
254
255
256 class Scalar(Statistic,FormulaStat):
257 def getValue(self):
258 return source.data(self, self.bins)
259
260 def display(self):
261 import display
262 p = display.Print()
263 p.name = self.name
264 p.desc = self.desc
265 p.value = float(self)
266 p.flags = self.flags
267 p.precision = self.precision
268 if display.all or (self.flags & flags.printable):
269 p.display()
270
271 def comparable(self, other):
272 return self.name == other.name
273
274 def __eq__(self, other):
275 return self.value == other.value
276
277 def __isub__(self, other):
278 self.value -= other.value
279 return self
280
281 def __iadd__(self, other):
282 self.value += other.value
283 return self
284
285 def __itruediv__(self, other):
286 if not other:
287 return self
288 self.value /= other
289 return self
290
291 class Vector(Statistic,FormulaStat):
292 def getValue(self):
293 return source.data(self, self.bins);
294
295 def display(self):
296 import display
297 if not display.all and not (self.flags & flags.printable):
298 return
299
300 d = display.VectorDisplay()
301 d.__dict__.update(self.__dict__)
302 d.display()
303
304 def comparable(self, other):
305 return self.name == other.name and \
306 len(self.value) == len(other.value)
307
308 def __eq__(self, other):
309 if issequence(self.value) != issequence(other.value):
310 return false
311
312 if issequence(self.value):
313 if len(self.value) != len(other.value):
314 return False
315 else:
316 for v1,v2 in zip(self.value, other.value):
317 if v1 != v2:
318 return False
319 return True
320 else:
321 return self.value == other.value
322
323 def __isub__(self, other):
324 self.value = binaryop(operator.sub, self.value, other.value)
325 return self
326
327 def __iadd__(self, other):
328 self.value = binaryop(operator.add, self.value, other.value)
329 return self
330
331 def __itruediv__(self, other):
332 if not other:
333 return self
334 if issequence(self.value):
335 for i in xrange(len(self.value)):
336 self.value[i] /= other
337 else:
338 self.value /= other
339 return self
340
341 class Formula(Vector):
342 def getValue(self):
343 formula = re.sub(':', '__', self.formula)
344 x = eval(formula, source.stattop)
345 return x.value
346
347 def comparable(self, other):
348 return self.name == other.name and \
349 compare(self.dist, other.dist)
350
351 def __eq__(self, other):
352 return self.value == other.value
353
354 def __isub__(self, other):
355 return self
356
357 def __iadd__(self, other):
358 return self
359
360 def __itruediv__(self, other):
361 if not other:
362 return self
363 return self
364
365 class SimpleDist(object):
366 def __init__(self, sums, squares, samples):
367 self.sums = sums
368 self.squares = squares
369 self.samples = samples
370
371 def getValue(self):
372 return 0.0
373
374 def display(self, name, desc, flags, precision):
375 import display
376 p = display.Print()
377 p.flags = flags
378 p.precision = precision
379
380 if self.samples > 0:
381 p.name = name + ".mean"
382 p.value = self.sums / self.samples
383 p.display()
384
385 p.name = name + ".stdev"
386 if self.samples > 1:
387 var = (self.samples * self.squares - self.sums ** 2) \
388 / (self.samples * (self.samples - 1))
389 if var >= 0:
390 p.value = math.sqrt(var)
391 else:
392 p.value = 'NaN'
393 else:
394 p.value = 0.0
395 p.display()
396
397 p.name = name + ".samples"
398 p.value = self.samples
399 p.display()
400
401 def comparable(self, other):
402 return True
403
404 def __eq__(self, other):
405 return self.sums == other.sums and self.squares == other.squares and \
406 self.samples == other.samples
407
408 def __isub__(self, other):
409 self.sums -= other.sums
410 self.squares -= other.squares
411 self.samples -= other.samples
412 return self
413
414 def __iadd__(self, other):
415 self.sums += other.sums
416 self.squares += other.squares
417 self.samples += other.samples
418 return self
419
420 def __itruediv__(self, other):
421 if not other:
422 return self
423 self.sums /= other
424 self.squares /= other
425 self.samples /= other
426 return self
427
428 class FullDist(SimpleDist):
429 def __init__(self, sums, squares, samples, minval, maxval,
430 under, vec, over, min, max, bsize, size):
431 self.sums = sums
432 self.squares = squares
433 self.samples = samples
434 self.minval = minval
435 self.maxval = maxval
436 self.under = under
437 self.vec = vec
438 self.over = over
439 self.min = min
440 self.max = max
441 self.bsize = bsize
442 self.size = size
443
444 def getValue(self):
445 return 0.0
446
447 def display(self, name, desc, flags, precision):
448 import display
449 p = display.Print()
450 p.flags = flags
451 p.precision = precision
452
453 p.name = name + '.min_val'
454 p.value = self.minval
455 p.display()
456
457 p.name = name + '.max_val'
458 p.value = self.maxval
459 p.display()
460
461 p.name = name + '.underflow'
462 p.value = self.under
463 p.display()
464
465 i = self.min
466 for val in self.vec[:-1]:
467 p.name = name + '[%d:%d]' % (i, i + self.bsize - 1)
468 p.value = val
469 p.display()
470 i += self.bsize
471
472 p.name = name + '[%d:%d]' % (i, self.max)
473 p.value = self.vec[-1]
474 p.display()
475
476
477 p.name = name + '.overflow'
478 p.value = self.over
479 p.display()
480
481 SimpleDist.display(self, name, desc, flags, precision)
482
483 def comparable(self, other):
484 return self.min == other.min and self.max == other.max and \
485 self.bsize == other.bsize and self.size == other.size
486
487 def __eq__(self, other):
488 return self.sums == other.sums and self.squares == other.squares and \
489 self.samples == other.samples
490
491 def __isub__(self, other):
492 self.sums -= other.sums
493 self.squares -= other.squares
494 self.samples -= other.samples
495
496 if other.samples:
497 self.minval = min(self.minval, other.minval)
498 self.maxval = max(self.maxval, other.maxval)
499 self.under -= under
500 self.vec = map(lambda x,y: x - y, self.vec, other.vec)
501 self.over -= over
502 return self
503
504 def __iadd__(self, other):
505 if not self.samples and other.samples:
506 self = other
507 return self
508
509 self.sums += other.sums
510 self.squares += other.squares
511 self.samples += other.samples
512
513 if other.samples:
514 self.minval = min(self.minval, other.minval)
515 self.maxval = max(self.maxval, other.maxval)
516 self.under += other.under
517 self.vec = map(lambda x,y: x + y, self.vec, other.vec)
518 self.over += other.over
519 return self
520
521 def __itruediv__(self, other):
522 if not other:
523 return self
524 self.sums /= other
525 self.squares /= other
526 self.samples /= other
527
528 if self.samples:
529 self.under /= other
530 for i in xrange(len(self.vec)):
531 self.vec[i] /= other
532 self.over /= other
533 return self
534
535 class Dist(Statistic):
536 def getValue(self):
537 return 0.0
538
539 def display(self):
540 import display
541 if not display.all and not (self.flags & flags.printable):
542 return
543
544 self.dist.display(self.name, self.desc, self.flags, self.precision)
545
546 def comparable(self, other):
547 return self.name == other.name and \
548 self.dist.compareable(other.dist)
549
550 def __eq__(self, other):
551 return self.dist == other.dist
552
553 def __isub__(self, other):
554 self.dist -= other.dist
555 return self
556
557 def __iadd__(self, other):
558 self.dist += other.dist
559 return self
560
561 def __itruediv__(self, other):
562 if not other:
563 return self
564 self.dist /= other
565 return self
566
567 class VectorDist(Statistic):
568 def getValue(self):
569 return 0.0
570
571 def display(self):
572 import display
573 if not display.all and not (self.flags & flags.printable):
574 return
575
576 if isinstance(self.dist, SimpleDist):
577 return
578
579 for dist,sn,sd,i in map(None, self.dist, self.subnames, self.subdescs,
580 range(len(self.dist))):
581 if len(sn) > 0:
582 name = '%s.%s' % (self.name, sn)
583 else:
584 name = '%s[%d]' % (self.name, i)
585
586 if len(sd) > 0:
587 desc = sd
588 else:
589 desc = self.desc
590
591 dist.display(name, desc, self.flags, self.precision)
592
593 if (self.flags & flags.total) or 1:
594 if isinstance(self.dist[0], SimpleDist):
595 disttotal = SimpleDist( \
596 reduce(sums, [d.sums for d in self.dist]),
597 reduce(sums, [d.squares for d in self.dist]),
598 reduce(sums, [d.samples for d in self.dist]))
599 else:
600 disttotal = FullDist( \
601 reduce(sums, [d.sums for d in self.dist]),
602 reduce(sums, [d.squares for d in self.dist]),
603 reduce(sums, [d.samples for d in self.dist]),
604 min([d.minval for d in self.dist]),
605 max([d.maxval for d in self.dist]),
606 reduce(sums, [d.under for d in self.dist]),
607 reduce(sums, [d.vec for d in self.dist]),
608 reduce(sums, [d.over for d in self.dist]),
609 dist[0].min,
610 dist[0].max,
611 dist[0].bsize,
612 dist[0].size)
613
614 name = '%s.total' % (self.name)
615 desc = self.desc
616 disttotal.display(name, desc, self.flags, self.precision)
617
618 def comparable(self, other):
619 return self.name == other.name and \
620 alltrue(map(lambda x, y : x.comparable(y),
621 self.dist,
622 other.dist))
623
624 def __eq__(self, other):
625 return alltrue(map(lambda x, y : x == y, self.dist, other.dist))
626
627 def __isub__(self, other):
628 if issequence(self.dist) and issequence(other.dist):
629 for sd,od in zip(self.dist, other.dist):
630 sd -= od
631 else:
632 self.dist -= other.dist
633 return self
634
635 def __iadd__(self, other):
636 if issequence(self.dist) and issequence(other.dist):
637 for sd,od in zip(self.dist, other.dist):
638 sd += od
639 else:
640 self.dist += other.dist
641 return self
642
643 def __itruediv__(self, other):
644 if not other:
645 return self
646 if issequence(self.dist):
647 for dist in self.dist:
648 dist /= other
649 else:
650 self.dist /= other
651 return self
652
653 class Vector2d(Statistic):
654 def getValue(self):
655 return 0.0
656
657 def display(self):
658 import display
659 if not display.all and not (self.flags & flags.printable):
660 return
661
662 d = display.VectorDisplay()
663 d.__dict__.update(self.__dict__)
664
665 if self.__dict__.has_key('ysubnames'):
666 ysubnames = list(self.ysubnames)
667 slack = self.x - len(ysubnames)
668 if slack > 0:
669 ysubnames.extend(['']*slack)
670 else:
671 ysubnames = range(self.x)
672
673 for x,sname in enumerate(ysubnames):
674 o = x * self.y
675 d.value = self.value[o:o+self.y]
676 d.name = '%s[%s]' % (self.name, sname)
677 d.display()
678
679 if self.flags & flags.total:
680 d.value = []
681 for y in range(self.y):
682 xtot = 0.0
683 for x in range(self.x):
684 xtot += self.value[y + x * self.x]
685 d.value.append(xtot)
686
687 d.name = self.name + '.total'
688 d.display()
689
690 def comparable(self, other):
691 return self.name == other.name and self.x == other.x and \
692 self.y == other.y
693
694 def __eq__(self, other):
695 return True
696
697 def __isub__(self, other):
698 return self
699
700 def __iadd__(self, other):
701 return self
702
703 def __itruediv__(self, other):
704 if not other:
705 return self
706 return self
707
708 def NewStat(data):
709 stat = None
710 if data.type == 'SCALAR':
711 stat = Scalar(data)
712 elif data.type == 'VECTOR':
713 stat = Vector(data)
714 elif data.type == 'DIST':
715 stat = Dist(data)
716 elif data.type == 'VECTORDIST':
717 stat = VectorDist(data)
718 elif data.type == 'VECTOR2D':
719 stat = Vector2d(data)
720 elif data.type == 'FORMULA':
721 stat = Formula(data)
722
723 return stat
724