Add perf_events based counting/sampling profilers to autotest

Counting profiler:

Counts cycles, instructions and computes CPI

Sampling profiler:

Depends on a patch that enables sampling per cpu and reporting via 

--sort cpu,...

which will be mailed upstream soon.

Signed-off-by: Arun Sharma <[email protected]>

--- /dev/null   2009-12-17 12:29:38.000000000 -0800
+++ autotest/client/profilers/cpistat/control   2010-04-30 16:50:45.000000000 
-0700
@@ -0,0 +1,3 @@
+job.profilers.add('cpistat')
+job.run_test('sleeptest', seconds=10)
+job.profilers.delete('cpistat')
--- /dev/null   2009-12-17 12:29:38.000000000 -0800
+++ autotest/client/profilers/cpistat/cpistat   2010-04-30 16:50:45.000000000 
-0700
@@ -0,0 +1,103 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2010 Google, Inc.
+# Contributed by Arun Sharma <[email protected]>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+#
+# Run as: ./cpistat -c cpulist -e eventlist
+#
+# Depends on libpfm4: http://perfmon2.sf.net/
+#
+# git://perfmon2.git.sourceforge.net/gitroot/perfmon2/libpfm4
+
+import sys
+import os
+import optparse
+import time
+import struct
+import perfmon
+
+if __name__ == '__main__':
+    parser = optparse.OptionParser()
+    parser.add_option("-e", "--events", help="Events to use",
+                       action="store", dest="events")
+    parser.add_option("-c", "--cpulist", help="CPUs to monitor",
+                       action="store", dest="cpulist")
+    
parser.set_defaults(events="PERF_COUNT_HW_CPU_CYCLES,PERF_COUNT_HW_INSTRUCTIONS")
+    (options, args) = parser.parse_args()
+
+    show_per_cpu = False
+    if not options.cpulist:
+        ncpus = os.sysconf('SC_NPROCESSORS_ONLN')
+        cpus = range(0, ncpus)
+    else:
+        cpus = options.cpulist.split(',')
+        cpus = [ int(c) for c in cpus ]
+        show_per_cpu = True
+
+    if options.events:
+        events = options.events.split(",")
+    else:
+        raise "You need to specify events to monitor"
+
+    s = perfmon.SystemWideSession(cpus, events)
+
+    s.start()
+    # Measuring loop
+    interval = 1
+    iters = -1
+    infinite = True
+    if len(args) == 2:
+        interval = int(args[0])
+        iters = int(args[1])
+        infinite = False
+
+    delta = {}
+    last = {}
+    sum = {}
+    for e in events:
+        delta[e] = {}
+        last[e] = {}
+        sum[e] = {}
+        for c in cpus:
+            delta[e][c] = 0
+            last[e][c] = 0
+
+    while infinite or iters:
+        for i in range(0, len(events)):
+          e = events[i]
+          sum[e] = 0
+          for c in cpus:
+              count = struct.unpack("L", s.read(c, i))[0]
+              delta[e][c] = count - last[e][c]
+              last[e][c] = count
+              if show_per_cpu:
+                  print """CPU%d: %s\t%lu""" % (c, e, delta[e][c])
+              sum[e] += delta[e][c]
+
+        cycles = sum["PERF_COUNT_HW_CPU_CYCLES"]
+        instructions = sum["PERF_COUNT_HW_INSTRUCTIONS"]
+        CPI = cycles * 1.0/instructions
+        print "cycles: %12lu, instructions: %12lu, CPI: %2.4f" \
+               % (cycles, instructions, CPI)
+        sys.stdout.flush()
+        time.sleep(interval)
+        iters = iters - 1
--- /dev/null   2009-12-17 12:29:38.000000000 -0800
+++ autotest/client/profilers/cpistat/cpistat.py        2010-04-30 
16:50:45.000000000 -0700
@@ -0,0 +1,28 @@
+"""
+Uses perf_events to count cycles and instructions
+
+Defaults options:
+job.profilers.add('cpistat', interval=1)
+"""
+import time, os, subprocess
+from autotest_lib.client.bin import profiler
+
+class cpistat(profiler.profiler):
+    version = 1
+
+    def initialize(self, interval = 1):
+        self.interval = interval
+
+
+    def start(self, test):
+        cmd = os.path.join(self.bindir, 'site_cpistat')
+        if not os.path.exists(cmd):
+           cmd = os.path.join(self.bindir, 'cpistat')
+        logfile = open(os.path.join(test.profdir, "cpistat"), 'w')
+        p = subprocess.Popen(cmd, stdout=logfile, \
+                             stderr=subprocess.STDOUT)
+        self.pid = p.pid
+
+
+    def stop(self, test):
+        os.kill(self.pid, 15)
--- /dev/null   2009-12-17 12:29:38.000000000 -0800
+++ autotest/client/profilers/perf/control      2010-04-30 16:50:45.000000000 
-0700
@@ -0,0 +1,3 @@
+job.profilers.add('perf')
+job.run_test('sleeptest', seconds=10)
+job.profilers.delete('perf')
--- /dev/null   2009-12-17 12:29:38.000000000 -0800
+++ autotest/client/profilers/perf/perf.py      2010-04-30 16:50:45.000000000 
-0700
@@ -0,0 +1,42 @@
+"""
+perf is a tool included in the linux kernel tree that
+supports functionality similar to oprofile and more.
+
+More Info: http://lwn.net/Articles/310260/
+"""
+
+import time, os, subprocess, signal
+from autotest_lib.client.bin import profiler
+
+class perf(profiler.profiler):
+    version = 1
+
+    def initialize(self, events="cycles,instructions"):
+        self.events = events
+
+
+    def start(self, test):
+        self.logfile = os.path.join(test.profdir, "perf")
+        cmd = "/usr/bin/perf record -a -o %s -e %s" % \
+              (self.logfile, self.events)
+        self._process = subprocess.Popen(cmd, shell=True, 
stderr=subprocess.STDOUT)
+
+
+    def stop(self, test):
+        os.kill(self._process.pid, signal.SIGINT)
+        self._process.wait()
+
+
+    def report(self, test):
+        self.reportfile_comm = os.path.join(test.profdir, 'perf.comm')
+        cmd = "/usr/bin/perf report -i %s --sort comm,dso" % self.logfile
+        outfile = open(self.reportfile_comm, 'w')
+        p1 = subprocess.Popen(cmd, shell=True, stdout=outfile,
+                              stderr=subprocess.STDOUT)
+        p1.wait()
+        self.reportfile_cpu = os.path.join(test.profdir, 'perf.cpu')
+        cmd = "/usr/bin/perf report -i %s --sort cpu,dso" % self.logfile
+        outfile = open(self.reportfile_cpu, 'w')
+        p2 = subprocess.Popen(cmd, shell=True, stdout=outfile,
+                              stderr=subprocess.STDOUT)
+        p2.wait()
_______________________________________________
Autotest mailing list
[email protected]
http://test.kernel.org/cgi-bin/mailman/listinfo/autotest

Reply via email to