|
|
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.