|
|
1.1 root 1: #!/usr/bin/env python
2: #
3: # Copyright (C) 2013 by Eero Tamminen
4: #
5: # This program is free software; you can redistribute it and/or modify
6: # it under the terms of the GNU General Public License as published by
7: # the Free Software Foundation; either version 2 of the License, or
8: # (at your option) any later version.
9: #
10: # This program is distributed in the hope that it will be useful,
11: # but WITHOUT ANY WARRANTY; without even the implied warranty of
12: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13: # GNU General Public License for more details.
14: """
15: Usage: hatari_spinloop.py <filename>
16:
17: Script for post-processing Hatari profiler looping information
18: produced by "profile loops <filename>" command, after profiling is
19: enabled with either "profile on" and/or "dspprofile on".
20:
21: That Hatari command saves spinloop data for any CPU and DSP code inner
22: loop that spins for more than once.
23:
24: This script gives counts on how many times loops were executed, how
25: many times they spinned at minimum and maximum, at which VBL those
26: happened, and what was the standard deviation of that.
27:
28: Note: in some cases Hatari can list different sized spinloops for the
29: same loop (start) address. This can be because code changed, or outer
30: loop was sometimes repeated several times in succession without
31: repeating the inner loop.
32: """
33:
34: import os, sys, math
35:
36:
37: class LoopItem:
38: def __init__(self, addr, size):
39: self.addr = addr
40: self.size = size
41: self.loops = []
42:
43: def add(self, count, vbl):
44: self.loops.append((count, vbl))
45:
46: def stats(self):
47: "return max + its VBL, min + its VBL, count of separate loops, stddev for them, loop addr & size"
48: self.loops.sort()
49: count = len(self.loops)
50: if count > 1:
51: mean = sum([x for x,y in self.loops]) / float(count)
52: mean2 = sum([(x-mean)**2 for x,y in self.loops]) / float(count-1)
53: else:
54: mean2 = 0.0
55: return (self.loops[-1][0], self.loops[-1][1],
56: self.loops[0][0], self.loops[0][1],
57: count, math.sqrt(mean2), self.addr, self.size)
58:
59:
60: def output(processors, write):
61: for name, data in processors.items():
62: write("\n%s loop statistics\n" % name)
63: sorted = []
64: for item in data.values():
65: sorted.append(item.stats())
66: sorted.sort()
67: sorted.reverse()
68: write(" max:\tat VBL:\t min:\tat VBL:\ttimes:\tstddev:\taddr:\tsize:\n")
69: for item in sorted:
70: write("%7d\t%7d\t" % (item[0], item[1]))
71: write("%7d\t%7d\t" % (item[2], item[3]))
72: write("%7d\t%7.1f\t" % (item[4], item[5]))
73: write(" %06x\t%6d\n" % (item[6], item[7]))
74:
75:
76: def parse(fname):
77: "parse looping information from given file object"
78: processors = {}
79: for line in open(fname).readlines():
80: if line[0] == '#':
81: continue
82: name, vbl, addr, size, count = line.split()
83: if name not in processors:
84: processors[name] = {}
85: items = processors[name]
86: addr = int(addr, 16)
87: size = int(size)
88: ident = (addr, size)
89: if ident not in items:
90: items[ident] = LoopItem(addr, size)
91: items[ident].add(int(count), int(vbl))
92: return processors
93:
94:
95: if __name__ == "__main__":
96: if len(sys.argv) != 2 or not os.path.exists(sys.argv[1]):
97: print __doc__
98: sys.exit(1)
99: data = parse(sys.argv[1])
100: output(data, sys.stdout.write)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.