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