[pypy-svn] r58279 - in pypy/build/benchmem: . benchmark testing

hpk at codespeak.net hpk at codespeak.net
Sat Sep 20 18:57:38 CEST 2008


Author: hpk
Date: Sat Sep 20 18:57:37 2008
New Revision: 58279

Modified:
   pypy/build/benchmem/benchmark/create_recursive_tuples.py
   pypy/build/benchmem/benchtool.py
   pypy/build/benchmem/smaps.py
   pypy/build/benchmem/testing/test_benchtool.py
Log:
always append benchmark results to a file, use denser format 


Modified: pypy/build/benchmem/benchmark/create_recursive_tuples.py
==============================================================================
--- pypy/build/benchmem/benchmark/create_recursive_tuples.py	(original)
+++ pypy/build/benchmem/benchmark/create_recursive_tuples.py	Sat Sep 20 18:57:37 2008
@@ -5,4 +5,11 @@
         checkpoint()
         for j in range(iter2):
             x = (x,)
+            x = (x,)
+            x = (x,)
+            x = (x,)
+            x = (x,)
+            x = (x,)
+            x = (x,)
+            x = (x,)
 

Modified: pypy/build/benchmem/benchtool.py
==============================================================================
--- pypy/build/benchmem/benchtool.py	(original)
+++ pypy/build/benchmem/benchtool.py	Sat Sep 20 18:57:37 2008
@@ -1,5 +1,6 @@
+#!/usr/bin/env python
 """
-  benchtool.py [--benchlog=logfile] [--executable=path1] [benchname1.py] [benchname2.py]
+  benchtool.py [options] [benchname1.py] [benchname2.py]
 
   record memory usage for given benchmarks (or all if none specified). 
 
@@ -13,8 +14,11 @@
 
  
 class BenchRunner(object):
+    SEPBENCH = "=" * 80
+
     def __init__(self, executable, benchlog):
-        self.benchlog = py.path.local(benchlog)
+        self.benchlogpath = py.path.local(benchlog)
+        self.logstream = self.benchlogpath.open("a")
         self.executable = executable
         self.tmpdir = py.path.local.make_numbered_dir(prefix="bench")
    
@@ -31,31 +35,33 @@
             
         arglist = ",".join(map(str, args))
         source = py.code.Source(path.read(), """
+
+            def write(c):
+                sys.stdout.write(c)
+                sys.stdout.flush()
+
             def checkpoint():
-                sys.stdout.write("c")
+                write("c")
                 sys.stdin.read(1)
             if __name__ == "__main__":
                 import os, sys
                 pid = os.getpid()
-                sys.stdout.write(str(pid))
-                sys.stdout.write("\\n")
+                write(str(pid) + "\\n")
                 checkpoint()
                 %s(checkpoint, %s)
                 checkpoint()
-                sys.stdout.write("F")
-                sys.stdout.close()
+                write("F")
+                sys.stdin.close()
         """ %(name, arglist))
         p = self.tmpdir.join(path.basename)
         p.write(source)
         return p
 
-    def writeexecinfo(self, benchname):
-        f = self.benchlog.open("a")
-        print >>f, "=" * 80
-        print >>f, "#executable=%r" %(str(self.executable ),)
-        print >>f, "#benchname=%r" %(benchname,)
-        f.close()
-        # xxx add more
+    def writeexecinfo(self, benchname, args):
+        print >>self.logstream, self.SEPBENCH 
+        print >>self.logstream, "#executable=%r" %(str(self.executable ),)
+        print >>self.logstream, "#benchname=%r" %(benchname,)
+        print >>self.logstream, "#benchargs=%r" %(args,)
 
     def run_checkpointed_bench(self, filename, args):
         benchpyfile = self._preparebench(filename, args)
@@ -65,39 +71,94 @@
         stdout, stdin = os.popen2(cmd)
         pid = int(stdin.readline())
         
-        self.writeexecinfo(benchpyfile.basename)
-        rec = smaps.SmapsRecorder(pid, self.benchlog)
-        stdout.write(".")
-        stdout.flush()
+        self.writeexecinfo(benchpyfile.basename, args)
+        rec = smaps.SmapsRecorder(pid, self.logstream)
+        self.interact_with_child_checkpoints(rec, stdout, stdin)
+
+    def interact_with_child_checkpoints(self, rec, stdout, stdin):
+        def write(c):
+            stdout.write(c)
+            stdout.flush()
         while not stdin.closed:
             c = stdin.read(1)
             if c == "F":
+                stdin.close()
+                stdout.close()
                 break
             rec.snapshot()
             stdout.write(".")
             stdout.flush()
             #sys.stdout.write(".")
             #sys.stdout.flush()
-        rec.finish()
-        self.log("finished", cmd)
 
-class BenchResult:
-    pass
-    
-class BenchlogReader(object):
-    def __init__(self, logpath):
-        self.logpath = logpath
-
-    def getname2results(self):
-        name2results = {}
-        for result in self.readresults():
-            l = name2results.setdefault(result.benchname, [])
-            l.append(result)
-        return name2results
+#
+# ================ reading a benchmark log file =======================
+#
 
-    def readresults(self):
-        xxx
+class Benchresults(object):
+    def __init__(self):
+        self.name2results = {}
+
+    def parse_logfile(self, logpath):
+        f = logpath.open()
+        for result in BenchmarkResult.parse(f):
+            #print "parsed", result
+            l = self.name2results.setdefault(result.benchname, [])
+            l.append(result)
+        f.close()
         
+class BenchmarkResult:
+    def __init__(self, snapshots, executable, benchname, benchargs):
+        assert snapshots
+        self.snapshots = snapshots
+        self.executable = executable
+        self.benchname = benchname
+        self.benchargs = benchargs
+
+    @classmethod
+    def parse(cls, f):
+        while not f.closed:
+            line = f.readline()
+            if not line.strip():
+                break
+            if not line.startswith("#executable"):
+                print "ignoring", line
+                continue
+            executable = eval(line.split("=", 1)[1])
+            benchname = eval(f.readline().split("=", 1)[1])
+            benchargs = eval(f.readline().split("=", 1)[1])
+
+            snapshots = []
+            line = f.readline()
+            while 1:
+                mappings = []
+                while line != smaps.SmapsRecorder.SEPSNAPSHOT:
+                    mappings.append(smaps.Mapping(line))
+                    line = f.readline()
+                    #print "reading", line.strip()
+                snapshots.append(Snapshot(mappings))
+                line = f.readline()
+                if not line or line == BenchRunner.SEPBENCH:
+                    break 
+            yield BenchmarkResult(snapshots, executable=executable, 
+                benchname=benchname, benchargs=benchargs)
+
+    def _verify_integrity(self):
+        for snap in self.snapshots:
+            for mapping in snap.mappings:
+                clean = mapping.shared_clean + mapping.private_clean 
+                dirty = mapping.private_dirty + mapping.shared_dirty 
+                assert mapping.rss == dirty + clean
+
+class Snapshot(object):
+    def __init__(self, mappings):
+        assert mappings
+        self.mappings = mappings
+        for name in smaps.Mapping._attrnames:
+            setattr(self, name, sum([getattr(x, name) for x in mappings]))
+
+    def memusage(self):
+        return "privdirty: %d, shadirty: %d" %(self.private_dirty, self.shared_dirty)
 
 #
 # ==============================================================================
@@ -146,3 +207,4 @@
     runner = BenchRunner(executable, benchlog)
     for name in names:
         runner.run_checkpointed_bench(name, (100, 100))
+    print "bench results append to -->>>", benchlog

Modified: pypy/build/benchmem/smaps.py
==============================================================================
--- pypy/build/benchmem/smaps.py	(original)
+++ pypy/build/benchmem/smaps.py	Sat Sep 20 18:57:37 2008
@@ -2,99 +2,55 @@
 import py
 
 class SmapsRecorder:
-    SEPLINE = "-"*80 + "\n"
+    SEPSNAPSHOT = "-"*80 + "\n"
 
-    def __init__(self, pid, logpath):
-        self.logpath = py.path.local(logpath)
-        self._file = self.logpath.open("a")
+    def __init__(self, pid, stream):
+        self.stream = stream 
         self.pid = pid
         self.smapspath = py.path.local("/proc/%d/smaps" %(pid,))
         assert self.smapspath.check()
 
     def snapshot(self):
-        s = self.smapspath.read()
-        self._file.write(s)
-        self._file.write(self.SEPLINE)
-        self._file.flush()
-
-    def finish(self):
-        self._file.close()
-
-class SmapsReader:
-    def __init__(self, snapshots):
-        self.snapshots = snapshots
-
-    @classmethod
-    def parse(cls, path):
-        """ parse a file previously recorded through SmapsRecorder. """
-        s = path.read()
-        parts = filter(None, map(str.strip, s.split(SmapsRecorder.SEPLINE)))
-        snapshots = [SmapsSnapshot.parse(s) for s in parts]
-        return cls(snapshots)
-
-    def _verify_integrity(self):
-        for snap in self.snapshots:
-            for mapping in snap.mappings:
-                clean = mapping.shared_clean + mapping.private_clean 
-                dirty = mapping.private_dirty + mapping.shared_dirty 
-                assert mapping.rss == dirty + clean
-        
-
-class SmapsMapping:
-    def __init__(self, headvars, bodyvars):
-        self.__dict__.update(headvars)
-        self.__dict__.update(bodyvars)
+        f = self.smapspath.open()
+        headline = f.readline()
+        while not f.closed:
+            attrs = []
+            while not f.closed:
+                sizeline = f.readline()
+                if not sizeline: # EOF 
+                    break 
+                parts = sizeline.split()
+                if len(parts) != 3:
+                    headline = sizeline
+                    break 
+                value = int(parts[1])
+                attrs.append(value)
+            attrs = attrs[:6] # not interested in "Referenced"
+            sizes = ",".join(map(str, attrs))
+            assert sizes
+            self.stream.write("%-24s %s" %(sizes, headline))
+            if not sizeline:
+                break 
+        f.close()
+        self.stream.write(self.SEPSNAPSHOT)
+        self.stream.flush()
+
+
+#
+# objects gained from reading of the logfile 
+#
+class Mapping: 
+    _attrnames = ("size rss shared_clean shared_dirty "
+                  "private_clean private_dirty".split())
+    # example '402c1000-402c2000 rw-p 00011000 1f:04 1110 /lib/libnsl-2.5.so'
+    _headattrnames = "virtualaddress mode page dev inode filename".split()
+
+    def __init__(self, line):
+        parts = line.split()
+        attrs = parts.pop(0)
+        for name, value in zip(self._attrnames, map(int, attrs.split(","))):
+            setattr(self, name, value)
+        for name, value in zip(self._headattrnames, parts):
+            setattr(self, name, value)
         self.inode = int(self.inode)
     
-class SmapsSnapshot(object):
-    # example '402c1000-402c2000 rw-p 00011000 1f:04 1110 /lib/libnsl-2.5.so'
-    headrex = re.compile(r"""
-          (?P<virtualaddress>\w+-\w+)\s+
-          (?P<mode>[rwxps-]+)\s+
-          (?P<page>\w+)\s+
-          (?P<dev>\w\w:\w\w)\s+
-          (?P<inode>\w+)\s+
-          (?P<filename>\S*)""",
-          re.VERBOSE)
-    # example 'Size:              4648 kB'
-    linerex = re.compile(r"(\S+):\s+(\d+)\skB")
-
-    def __init__(self, mappings):
-        self.mappings = mappings
-        self.UNIT = "kB"
-        for name in ("size rss shared_clean shared_dirty "
-                     "private_clean private_dirty".split()):
-            setattr(self, name, sum([getattr(x, name) for x in mappings]))
-
-    def memusage(self):
-        return "privdirty: %d, shadirty: %d" %(self.private_dirty, self.shared_dirty)
-
-    @classmethod
-    def parse(cls, string):
-        lines = string.split("\n")
-        mappings = []
-        while lines:
-            line = lines.pop(0)
-            if not line.strip():
-                continue
-            m = cls.headrex.match(line)
-            if m is None:
-                print "ignoring", line
-                continue
-            headvars = m.groupdict()
-            bodyvars = {}
-            while lines:
-                line = lines.pop(0)
-                m = cls.linerex.match(line)
-                if m is None:
-                    lines.insert(0, line)
-                    mappings.append(SmapsMapping(headvars, bodyvars))
-                    break
-                name, num = m.groups()
-                name = name.lower()
-                num = int(num) 
-                assert name not in bodyvars
-                bodyvars[name] = num
-            else:
-                mappings.append(SmapsMapping(headvars, bodyvars))
-        return cls(mappings)

Modified: pypy/build/benchmem/testing/test_benchtool.py
==============================================================================
--- pypy/build/benchmem/testing/test_benchtool.py	(original)
+++ pypy/build/benchmem/testing/test_benchtool.py	Sat Sep 20 18:57:37 2008
@@ -12,155 +12,85 @@
     tmpdir = py.test.ensuretemp("smapsrecorder")
     logpath = tmpdir.join("logfile")
     pid = os.getpid()
-    rec = smaps.SmapsRecorder(pid=pid, logpath=logpath)
+    f = logpath.open("w")
+    rec = smaps.SmapsRecorder(pid=pid, stream=f)
     s = logpath.read()
-    assert s.count(smaps.SmapsRecorder.SEPLINE) == 0
+    assert s.count(smaps.SmapsRecorder.SEPSNAPSHOT) == 0
     rec.snapshot()
     rec.snapshot()
     del rec
     s = logpath.read()
-    assert s.count(smaps.SmapsRecorder.SEPLINE) == 2
+    assert s.count(smaps.SmapsRecorder.SEPSNAPSHOT) == 2
 
 def test_benchrunner_functional():
     tmpdir = py.test.ensuretemp("benchrunner")
     log=tmpdir.join("log")
-    runner = benchtool.BenchRunner(executable="python2.5", benchlog=log)
     def checker(path, *args):
         if log.check():
             log.remove()
+        runner = benchtool.BenchRunner(executable="python2.5", benchlog=log)
         runner.run_checkpointed_bench(path, args)
         assert log.check()
-        reader = smaps.SmapsReader.parse(log)
+        benchresult = benchtool.Benchresults()
+        benchresult.parse_logfile(log)
         #assert reader.executable
         #assert reader.executable
-        assert len(reader.snapshots) == 10 + 2
-        reader._verify_integrity()
+        assert len(benchresult.name2results) == 1
+        results = benchresult.name2results.values()[0]
+        assert len(results) == 1
+        assert len(results[0].snapshots) == 10 + 2
 
     for path in benchtool.benchmarkdir.listdir("*.py"):
         if path.basename[0] != "_": 
             yield checker, path, 10, 10
 
-class TestSmapsSnapshot:
-    def setup_class(cls):
-        cls.s = py.std.textwrap.dedent("""\
-            08048000-0813f000 r-xp 00000000 fd:00 75457      sometext
-            Size:                988 kB
-            Rss:                 796 kB
-            Shared_Clean:          0 kB
-            Shared_Dirty:          0 kB
-            Private_Clean:       796 kB
-            Private_Dirty:         0 kB
-            402c2000-402c4000 rw-p 402c2000 00:00 0 
-            Size:                 16 kB
-            Rss:                  8 kB
-            Shared_Clean:         0 kB
-            Shared_Dirty:         0 kB
-            Private_Clean:        0 kB
-            Private_Dirty:        8 kB""")
-
-    def test_parse_mappings(self):
-        smapsreader = smaps.SmapsSnapshot.parse(self.s)
-        mappings = smapsreader.mappings
-        assert len(mappings) == 2
-        mapping = mappings[0]
-        assert mapping.virtualaddress == "08048000-0813f000"
-        assert mapping.mode == "r-xp"
-        assert mapping.dev == "fd:00"
-        assert mapping.inode == 75457
-        assert mapping.filename == "sometext"
-        assert mapping.size == 988 
-        assert mapping.rss == 796 
-        assert mapping.shared_clean == 0
-        assert mapping.shared_dirty == 0
-        assert mapping.private_clean == 796 
-        assert mapping.private_dirty == 0
-        #assert mapping.referenced is None
-
-        mapping = mappings[1]
-        assert mapping.virtualaddress == "402c2000-402c4000"
-        assert mapping.mode == "rw-p"
-        assert mapping.dev == "00:00"
-        assert mapping.inode == 0
-        assert not mapping.filename
-        assert mapping.size == 16 
-        assert mapping.rss == 8 
-        assert mapping.shared_clean == 0
-        assert mapping.shared_dirty == 0
-        assert mapping.private_clean == 0
-        assert mapping.private_dirty == 8 
-        #assert mapping.referenced == 12 
-
-    def test_summing(self):
-        snap = smaps.SmapsSnapshot.parse(self.s)
-        for name in ('size rss shared_clean shared_dirty '
-                     'private_clean private_dirty').split():
-            sumval = getattr(snap, name)
-            val1 = getattr(snap.mappings[0], name)
-            val2 = getattr(snap.mappings[1], name)
-            assert sumval == val1 + val2
-
-example_data2 = '''
-08048000-0813f000 r-xp 00000000 fd:00 75457      /usr/bin/python2.5
-Size:                988 kB
-Rss:                 796 kB
-Shared_Clean:          0 kB
-Shared_Dirty:          0 kB
-Private_Clean:       796 kB
-Private_Dirty:         0 kB
-0813f000-08164000 rw-p 000f6000 fd:00 75457      /usr/bin/python2.5
-Size:                148 kB
-Rss:                 120 kB
-Shared_Clean:          0 kB
-Shared_Dirty:          0 kB
-Private_Clean:        12 kB
-Private_Dirty:       108 kB
-08164000-0825c000 rw-p 08164000 00:00 0          [heap]
-Size:                992 kB
-Rss:                 924 kB
-Shared_Clean:          0 kB
-Shared_Dirty:          0 kB
-Private_Clean:         0 kB
-Private_Dirty:       924 kB
-b7baf000-b7beb000 r-xp 00000000 08:01 218        /lib/libncurses.so.5.6
-Size:                240 kB
-Rss:                  60 kB
-Shared_Clean:         60 kB
-Shared_Dirty:          0 kB
-Private_Clean:         0 kB
-Private_Dirty:         0 kB
-'''
-
-example_data = '''
-08048000-0813f000 r-xp 00000000 fd:00 75457      /usr/bin/python2.5
-Size:                988 kB
-Rss:                 796 kB
-Shared_Clean:          0 kB
-Shared_Dirty:          0 kB
-Private_Clean:       796 kB
-Private_Dirty:         0 kB
-Referenced:          796 kB
-0813f000-08164000 rw-p 000f6000 fd:00 75457      /usr/bin/python2.5
-Size:                148 kB
-Rss:                 120 kB
-Shared_Clean:          0 kB
-Shared_Dirty:          0 kB
-Private_Clean:        12 kB
-Private_Dirty:       108 kB
-Referenced:          120 kB
-08164000-0825c000 rw-p 08164000 00:00 0          [heap]
-Size:                992 kB
-Rss:                 924 kB
-Shared_Clean:          0 kB
-Shared_Dirty:          0 kB
-Private_Clean:         0 kB
-Private_Dirty:       924 kB
-Referenced:          924 kB
-b7baf000-b7beb000 r-xp 00000000 08:01 218        /lib/libncurses.so.5.6
-Size:                240 kB
-Rss:                  60 kB
-Shared_Clean:         60 kB
-Shared_Dirty:          0 kB
-Private_Clean:         0 kB
-Private_Dirty:         0 kB
-Referenced:           60 kB
-'''
+def test_log_mapping():
+    s = py.std.textwrap.dedent("""\
+        402c2000-402c4000 rw-p 402c2000 00:00 0 
+        Size:                 16 kB
+        Rss:                  8 kB
+        Shared_Clean:         0 kB
+        Shared_Dirty:         0 kB
+        Private_Clean:        0 kB
+        Private_Dirty:        8 kB""")
+    basedir = py.test.ensuretemp("log_mapping")
+    p = basedir.join("smaps.example")
+    p.write(s)
+
+    io = py.std.StringIO.StringIO()
+    rec = smaps.SmapsRecorder(os.getpid(), io)
+    rec.smapspath = p
+    rec.snapshot()
+    result = io.getvalue()
+    lines = result.split("\n")
+    l0 = " ".join(lines[0].split())
+    assert l0 == "16,8,0,0,0,8 402c2000-402c4000 rw-p 402c2000 00:00 0"
+    assert lines[1] == smaps.SmapsRecorder.SEPSNAPSHOT.strip() 
+
+def test_parse_mapping():
+    line = ("988,796,0,0,796,0 08048000-0813f000 "
+            "r-xp 00000000 fd:00 75457      sometext")
+    mapping = smaps.Mapping(line)
+    assert mapping.virtualaddress == "08048000-0813f000"
+    assert mapping.mode == "r-xp"
+    assert mapping.dev == "fd:00"
+    assert mapping.inode == 75457
+    assert mapping.filename == "sometext"
+    assert mapping.size == 988 
+    assert mapping.rss == 796 
+    assert mapping.shared_clean == 0
+    assert mapping.shared_dirty == 0
+    assert mapping.private_clean == 796 
+    assert mapping.private_dirty == 0
+
+def test_summing():
+    line = ("988,796,0,0,796,0 08048000-0813f000 "
+            "r-xp 00000000 fd:00 75457      sometext")
+    snap = benchtool.Snapshot([smaps.Mapping(line), smaps.Mapping(line)])
+    for name in ('size rss shared_clean shared_dirty '
+                 'private_clean private_dirty').split():
+        sumval = getattr(snap, name)
+        val1 = getattr(snap.mappings[0], name)
+        val2 = getattr(snap.mappings[1], name)
+        assert sumval == val1 + val2
+    



More information about the Pypy-commit mailing list