Bug 1811634 Part 1: Deal with spurious wakeups in WinCompositorWindowThread::ShutDown...
[gecko.git] / tools / power / mach_commands.py
blob956dcdf440eaa1420ad54f762ce938c52109704b
1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 from distutils.version import StrictVersion
7 from mach.decorators import Command, CommandArgument
10 def is_osx_10_10_or_greater(cls):
11 import platform
13 release = platform.mac_ver()[0]
14 return release and StrictVersion(release) >= StrictVersion("10.10")
17 # Get system power consumption and related measurements.
18 @Command(
19 "power",
20 category="misc",
21 conditions=[is_osx_10_10_or_greater],
22 description="Get system power consumption and related measurements for "
23 "all running browsers. Available only on Mac OS X 10.10 and above. "
24 "Requires root access.",
26 @CommandArgument(
27 "-i",
28 "--interval",
29 type=int,
30 default=30000,
31 help="The sample period, measured in milliseconds. Defaults to 30000.",
33 def power(command_context, interval):
34 """
35 Get system power consumption and related measurements.
36 """
37 import os
38 import re
39 import subprocess
41 rapl = os.path.join(command_context.topobjdir, "dist", "bin", "rapl")
43 interval = str(interval)
45 # Run a trivial command with |sudo| to gain temporary root privileges
46 # before |rapl| and |powermetrics| are called. This ensures that |rapl|
47 # doesn't start measuring while |powermetrics| is waiting for the root
48 # password to be entered.
49 try:
50 subprocess.check_call(["sudo", "true"])
51 except Exception:
52 print("\nsudo failed; aborting")
53 return 1
55 # This runs rapl in the background because nothing in this script
56 # depends on the output. This is good because we want |rapl| and
57 # |powermetrics| to run at the same time.
58 subprocess.Popen([rapl, "-n", "1", "-i", interval])
60 lines = subprocess.check_output(
62 "sudo",
63 "powermetrics",
64 "--samplers",
65 "tasks",
66 "--show-process-coalition",
67 "--show-process-gpu",
68 "-n",
69 "1",
70 "-i",
71 interval,
73 universal_newlines=True,
76 # When run with --show-process-coalition, |powermetrics| groups outputs
77 # into process coalitions, each of which has a leader.
79 # For example, when Firefox runs from the dock, its coalition looks
80 # like this:
82 # org.mozilla.firefox
83 # firefox
84 # plugin-container
86 # When Safari runs from the dock:
88 # com.apple.Safari
89 # Safari
90 # com.apple.WebKit.Networking
91 # com.apple.WebKit.WebContent
92 # com.apple.WebKit.WebContent
94 # When Chrome runs from the dock:
96 # com.google.Chrome
97 # Google Chrome
98 # Google Chrome Helper
99 # Google Chrome Helper
101 # In these cases, we want to print the whole coalition.
103 # Also, when you run any of them from the command line, things are the
104 # same except that the leader is com.apple.Terminal and there may be
105 # non-browser processes in the coalition, e.g.:
107 # com.apple.Terminal
108 # firefox
109 # plugin-container
110 # <and possibly other, non-browser processes>
112 # Also, the WindowServer and kernel coalitions and processes are often
113 # relevant.
115 # We want to print all these but omit uninteresting coalitions. We
116 # could do this by properly parsing powermetrics output, but it's
117 # simpler and more robust to just grep for a handful of identifying
118 # strings.
120 print() # blank line between |rapl| output and |powermetrics| output
122 for line in lines.splitlines():
123 # Search for the following things.
125 # - '^Name' is for the columns headings line.
127 # - 'firefox' and 'plugin-container' are for Firefox
129 # - 'Safari\b' and 'WebKit' are for Safari. The '\b' excludes
130 # SafariCloudHistoryPush, which is a process that always
131 # runs, even when Safari isn't open.
133 # - 'Chrome' is for Chrome.
135 # - 'Terminal' is for the terminal. If no browser is running from
136 # within the terminal, it will show up unnecessarily. This is a
137 # minor disadvantage of this very simple parsing strategy.
139 # - 'WindowServer' is for the WindowServer.
141 # - 'kernel' is for the kernel.
143 if re.search(
144 r"(^Name|firefox|plugin-container|Safari\b|WebKit|Chrome|Terminal|WindowServer|kernel)", # NOQA: E501
145 line,
147 print(line)
149 return 0