Title: [137714] trunk/Tools
Revision
137714
Author
[email protected]
Date
2012-12-13 22:41:24 -0800 (Thu, 13 Dec 2012)

Log Message

Add --profiler=PROFILER option to run-perf-tests to allow specifying which profiler to use on platforms with many
https://bugs.webkit.org/show_bug.cgi?id=104891

Reviewed by Ryosuke Niwa.

I also implemented a very simple "Sample" Profiler using
Mac OS X's /usr/bin/sample command line tool.

The real reason for this abstraction is to make it easy
to support both perf and pprof on linux which seem to
be about equally popular among those I ask in the Chrome team.

* Scripts/webkitpy/common/system/profiler.py:
(ProfilerFactory.create_profiler):
(ProfilerFactory):
(ProfilerFactory.available_profilers_by_name):
(ProfilerFactory.default_profiler_name):
(Sample):
(Sample.__init__):
(Sample.attach_to_pid):
(Sample.profile_after_exit):
(IProfiler.attach_to_pid):
* Scripts/webkitpy/layout_tests/port/driver.py:
(Driver.__init__):
* Scripts/webkitpy/performance_tests/perftestsrunner.py:
(PerfTestsRunner._parse_args):

Modified Paths

Diff

Modified: trunk/Tools/ChangeLog (137713 => 137714)


--- trunk/Tools/ChangeLog	2012-12-14 05:43:03 UTC (rev 137713)
+++ trunk/Tools/ChangeLog	2012-12-14 06:41:24 UTC (rev 137714)
@@ -1,5 +1,34 @@
 2012-12-13  Eric Seidel  <[email protected]>
 
+        Add --profiler=PROFILER option to run-perf-tests to allow specifying which profiler to use on platforms with many
+        https://bugs.webkit.org/show_bug.cgi?id=104891
+
+        Reviewed by Ryosuke Niwa.
+
+        I also implemented a very simple "Sample" Profiler using
+        Mac OS X's /usr/bin/sample command line tool.
+
+        The real reason for this abstraction is to make it easy
+        to support both perf and pprof on linux which seem to
+        be about equally popular among those I ask in the Chrome team.
+
+        * Scripts/webkitpy/common/system/profiler.py:
+        (ProfilerFactory.create_profiler):
+        (ProfilerFactory):
+        (ProfilerFactory.available_profilers_by_name):
+        (ProfilerFactory.default_profiler_name):
+        (Sample):
+        (Sample.__init__):
+        (Sample.attach_to_pid):
+        (Sample.profile_after_exit):
+        (IProfiler.attach_to_pid):
+        * Scripts/webkitpy/layout_tests/port/driver.py:
+        (Driver.__init__):
+        * Scripts/webkitpy/performance_tests/perftestsrunner.py:
+        (PerfTestsRunner._parse_args):
+
+2012-12-13  Eric Seidel  <[email protected]>
+
         Unreviewed, fixing typo in python unittest.
 
         I changed the default profiler on linux from pprof to perf in

Modified: trunk/Tools/Scripts/webkitpy/common/system/profiler.py (137713 => 137714)


--- trunk/Tools/Scripts/webkitpy/common/system/profiler.py	2012-12-14 05:43:03 UTC (rev 137713)
+++ trunk/Tools/Scripts/webkitpy/common/system/profiler.py	2012-12-14 06:41:24 UTC (rev 137714)
@@ -28,19 +28,44 @@
 
 import logging
 import re
+import itertools
 
 _log = logging.getLogger(__name__)
 
 
 class ProfilerFactory(object):
     @classmethod
-    def create_profiler(cls, host, executable_path, output_dir, identifier=None):
-        if host.platform.is_mac():
-            return IProfiler(host, executable_path, output_dir, identifier)
-        return Perf(host, executable_path, output_dir, identifier)
+    def create_profiler(cls, host, executable_path, output_dir, profiler_name=None, identifier=None):
+        profilers = cls.profilers_for_platform(host.platform)
+        if not profilers:
+            return None
+        profiler_name = profiler_name or cls.default_profiler_name(host.platform)
+        profiler_class = next(itertools.ifilter(lambda profiler: profiler.name == profiler_name, profilers), None)
+        if not profiler_class:
+            return None
+        return profilers[0](host, executable_path, output_dir, identifier)
 
+    @classmethod
+    def default_profiler_name(cls, platform):
+        profilers = cls.profilers_for_platform(platform)
+        return profilers[0].name if profilers else None
 
+    @classmethod
+    def profilers_for_platform(cls, platform):
+        # GooglePProf requires TCMalloc/google-perftools, but is available everywhere.
+        profilers_by_os_name = {
+            'mac': [IProfiler, Sample, GooglePProf],
+            'linux': [Perf, GooglePProf],
+            # Note: freebsd, win32 have no profilers defined yet, thus --profile will be ignored
+            # by default, but a profiler can be selected with --profiler=PROFILER explicitly.
+        }
+        return profilers_by_os_name.get(platform.os_name, [])
+
+
 class Profiler(object):
+    # Used by ProfilerFactory to lookup a profiler from the --profiler=NAME option.
+    name = None
+
     def __init__(self, host, executable_path, output_dir, identifier=None):
         self._host = host
         self._executable_path = executable_path
@@ -65,6 +90,8 @@
 
 
 class GooglePProf(SingleFileOutputProfiler):
+    name = 'pprof'
+
     def __init__(self, host, executable_path, output_dir, identifier=None):
         super(GooglePProf, self).__init__(host, executable_path, output_dir, "pprof", identifier)
 
@@ -98,6 +125,8 @@
 
 
 class Perf(SingleFileOutputProfiler):
+    name = 'perf'
+
     def __init__(self, host, executable_path, output_dir, identifier=None):
         super(Perf, self).__init__(host, executable_path, output_dir, "data", identifier)
         self._perf_process = None
@@ -111,7 +140,6 @@
         assert(not self._perf_process and not self._pid_being_profiled)
         self._pid_being_profiled = pid
         cmd = [self._perf_path(), "record", "-g", "-p", pid, "-o", self._output_path]
-        cmd = map(unicode, cmd)
         self._perf_process = self._host.executive.popen(cmd)
 
     def _first_ten_lines_of_profile(self, perf_output):
@@ -140,7 +168,24 @@
         print ' '.join([self._perf_path(), 'report', '-i', self._output_path])
 
 
+class Sample(SingleFileOutputProfiler):
+    name = 'sample'
+
+    def __init__(self, host, executable_path, output_dir, identifier=None):
+        super(Sample, self).__init__(host, executable_path, output_dir, "txt", identifier)
+        self._profiler_process = None
+
+    def attach_to_pid(self, pid):
+        cmd = ["sample", pid, "-mayDie", "-file", self._output_path]
+        self._profiler_process = self._host.executive.popen(cmd)
+
+    def profile_after_exit(self):
+        self._profiler_process.wait()
+
+
 class IProfiler(SingleFileOutputProfiler):
+    name = 'iprofiler'
+
     def __init__(self, host, executable_path, output_dir, identifier=None):
         super(IProfiler, self).__init__(host, executable_path, output_dir, "dtps", identifier)
         self._profiler_process = None
@@ -151,7 +196,6 @@
         fs = self._host.filesystem
         cmd = ["iprofiler", "-timeprofiler", "-a", pid,
                 "-d", fs.dirname(self._output_path), "-o", fs.splitext(fs.basename(self._output_path))[0]]
-        cmd = map(unicode, cmd)
         # FIXME: Consider capturing instead of letting instruments spam to stderr directly.
         self._profiler_process = self._host.executive.popen(cmd)
 

Modified: trunk/Tools/Scripts/webkitpy/common/system/profiler_unittest.py (137713 => 137714)


--- trunk/Tools/Scripts/webkitpy/common/system/profiler_unittest.py	2012-12-14 05:43:03 UTC (rev 137713)
+++ trunk/Tools/Scripts/webkitpy/common/system/profiler_unittest.py	2012-12-14 06:41:24 UTC (rev 137714)
@@ -28,23 +28,39 @@
 
 import unittest
 
+from webkitpy.common.system.platforminfo_mock import MockPlatformInfo
 from webkitpy.common.system.systemhost_mock import MockSystemHost
 
 from .profiler import ProfilerFactory, GooglePProf
 
 
 class ProfilerFactoryTest(unittest.TestCase):
-    def test_basic(self):
+    def _assert_default_profiler_name(self, os_name, expected_profiler_name):
+        profiler_name = ProfilerFactory.default_profiler_name(MockPlatformInfo(os_name))
+        self.assertEquals(profiler_name, expected_profiler_name)
+
+    def test_default_profilers(self):
+        self._assert_default_profiler_name('mac', 'iprofiler')
+        self._assert_default_profiler_name('linux', 'perf')
+        self._assert_default_profiler_name('win32', None)
+        self._assert_default_profiler_name('freebsd', None)
+
+    def test_default_profiler_output(self):
         host = MockSystemHost()
         self.assertFalse(host.filesystem.exists("/tmp/output"))
+
+        # Default mocks are Mac, so iprofile should be default.
         profiler = ProfilerFactory.create_profiler(host, '/bin/executable', '/tmp/output')
         self.assertTrue(host.filesystem.exists("/tmp/output"))
         self.assertEquals(profiler._output_path, "/tmp/output/test.dtps")
 
+        # Linux defaults to perf.
         host.platform.os_name = 'linux'
         profiler = ProfilerFactory.create_profiler(host, '/bin/executable', '/tmp/output')
         self.assertEquals(profiler._output_path, "/tmp/output/test.data")
 
+
+class GooglePProfTest(unittest.TestCase):
     def test_pprof_output_regexp(self):
         pprof_output = """
 sometimes

Modified: trunk/Tools/Scripts/webkitpy/layout_tests/port/driver.py (137713 => 137714)


--- trunk/Tools/Scripts/webkitpy/layout_tests/port/driver.py	2012-12-14 05:43:03 UTC (rev 137713)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/port/driver.py	2012-12-14 06:41:24 UTC (rev 137714)
@@ -143,7 +143,9 @@
 
         self._measurements = {}
         if self._port.get_option("profile"):
-            self._profiler = ProfilerFactory.create_profiler(self._port.host, self._port._path_to_driver(), self._port.results_directory())
+            profiler_name = self._port.get_option("profiler")
+            self._profiler = ProfilerFactory.create_profiler(self._port.host,
+                self._port._path_to_driver(), self._port.results_directory(), profiler_name)
         else:
             self._profiler = None
 

Modified: trunk/Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py (137713 => 137714)


--- trunk/Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py	2012-12-14 05:43:03 UTC (rev 137713)
+++ trunk/Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py	2012-12-14 06:41:24 UTC (rev 137714)
@@ -122,6 +122,8 @@
                 help="Run all tests, including the ones in the Skipped list."),
             optparse.make_option("--profile", action=""
                 help="Output per-test profile information."),
+            optparse.make_option("--profiler", action=""
+                help="Output per-test profile information, using the specified profiler."),
             ]
         return optparse.OptionParser(option_list=(perf_option_list)).parse_args(args)
 
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to