Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 51 additions & 46 deletions cpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ def __init__(self, package_id):
# The average percentage of CPU used by the device.
self._mean_device_usage = None

# The error message.
self.error = ''

# TODO(danduri@): Validate whether the "top" command is valid for
# different android versions.
# "adb shell top -bn1" output:
Expand Down Expand Up @@ -145,6 +148,7 @@ def __init__(self, package_id):
except subprocess.CalledProcessError:
logging.error("Please check your ADB connection.")
sys.exit(1)
logging.error('Test init CPUED')

def _web_gather_cpu_usage(self):
"""Stores the percentage of CPU used by the application and the
Expand All @@ -158,42 +162,22 @@ def _web_gather_cpu_usage(self):
_app_values
_device_values
"""

top_output = subprocess.check_output(
_ADB_SHELL_TOP.split()).strip().decode()

app_matches = self._re_app.search(top_output)
if not app_matches:
return (f"\nRegex: Match for {self._package_name}"
" not found in top output")

app_cpu = app_matches.group("cpu")
if not app_cpu:
return "Application CPU usage values are not recorded."

self._app_usage = float(app_cpu)

# Captures regex group(line) containing the CPU idle usage info.
cpu_matches = self._re_cpu.search(top_output)
if not cpu_matches:
return ("\nRegex: Match for (percentage)idle cpu usage not "
"found in top output")

idle_cpu = float(cpu_matches.group("idle"))
self._max_cpu = float(cpu_matches.group("cpu"))

if not idle_cpu:
return "CPU idle values are not recorded."
if not self._max_cpu:
return "CPU max value is not recorded."
self._device_usage = self._max_cpu - idle_cpu
usages = {
"app": self._app_usage,
"device": self._device_usage
stats = {
"app": 0,
"device": 0
}
return usages

def _gather_cpu_usage(self) -> None:

if self._gather_cpu_usage():
stats['app'] = self._app_values[-1]
stats['device'] = self._device_values[-1]
return stats

def get_error(self):
msg = self.error
self.error = ""
return msg

def _gather_cpu_usage(self, cmdLine=True) -> None:
"""Stores the percentage of CPU used by the application and the
device.

Expand All @@ -211,31 +195,52 @@ def _gather_cpu_usage(self) -> None:

app_matches = self._re_app.search(top_output)
if not app_matches:
logging.error(f"\nRegex: Match for {self._package_name}"
msg = (f"\nRegex: Match for {self._package_name}"
" not found in top output")
sys.exit(1)
self.error = msg
logging.error(msg)
if cmdLine:
sys.exit(1)
return False

app_cpu = app_matches.group("cpu")
assert app_cpu, "Application CPU usage values are not recorded."
self._app_usage = float(app_cpu)

if not app_cpu:
self.error = "Application CPU usage values are not recorded."
logging.error("Application CPU usage values are not recorded.")
if cmdLine:
sys.exit(1)
return False

# Captures regex group(line) containing the CPU idle usage info.
cpu_matches = self._re_cpu.search(top_output)
if not cpu_matches:
logging.error("\nRegex: Match for (percentage)idle cpu usage not "
msg = ("\nRegex: Match for (percentage)idle cpu usage not "
"found in top output")
sys.exit(1)
self.error = msg
logging.error(msg)
if cmdLine:
sys.exit(1)
return False

idle_cpu = float(cpu_matches.group("idle"))
self._max_cpu = float(cpu_matches.group("cpu"))
max_cpu = float(cpu_matches.group("cpu"))

if not idle_cpu or not max_cpu:
self.error = "CPU idle/ max values are not recorded."
logging.error("CPU idle/ max values are not recorded.")
sys.exit(1)
return False

assert idle_cpu, "CPU idle values are not recorded."
assert self._max_cpu, "CPU max value is not recorded."
self._device_usage = self._max_cpu - idle_cpu
# Only update values if both app and device were captured.
self._max_cpu = max_cpu
self._device_usage = max_cpu - idle_cpu
self._app_usage = float(app_cpu)

# Stores app and device usage for later calculations.
self._app_values.append(self._app_usage)
self._device_values.append(self._device_usage)
return True


def _update_cpu_calculations(self) -> None:
"""Updates the mean of the application and device CPU usage recorded
Expand Down
42 changes: 33 additions & 9 deletions fps.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,29 +320,53 @@ def _get_recent_frames(self):
Frame(draw=entries[0], vsync=entries[1], submit=entries[2]))
return frames

def print_stats(self, frames: List[Frame]) -> None:
"""
Prints the stats of the list of Frames.

def get_stats(self, frames: List[Frame], frameless=False) -> dict:
''' Calculates FPS stats.
Args:
frames: List of latest 127 frames.
"""

frameless: A bool to indicate if frames are provided or not.
Returns:
dict: A dict storing the fps stats calculated.
'''
# It might be possible that 'frames' is almost empty (e.g. SF stats were
# recently cleared). When that's the case, don't print anything.
# Three is the minimum required to generate two values needed for stdev.
if frameless:
frames = self._get_recent_frames()

if len(frames) < 3:
return
return {
'avg': 0,
'total': 0,
'dt': 0,
'latencies': []
}

total = len(frames) - 1
dt = (frames[-1].vsync - frames[0].vsync) / 1000000000
avg = total / dt
return {
'avg': avg,
'total': total,
'dt': dt,
'latencies': [(f.submit-f.draw) / 1000000 for f in frames]
}

def print_stats(self, frames: List[Frame]) -> None:
"""
Prints the stats of the list of Frames.

Args:
frames: List of latest 127 frames.
"""

# Line overwrites itself with '\r'.
stats = self.get_stats(frames)
avg = stats['avg']
fps_avg = f'\r- FPS avg={avg:.2f} '
latency_str = ''
if self._print_latency:
# Store latencies in milliseconds.
latencies = [(f.submit-f.draw) / 1000000 for f in frames]
latencies = stats['latencies']
latency_str = ('/ LATENCY (ms) '
f'mean={statistics.mean(latencies):.2f}, '
f'stdev={statistics.stdev(latencies):.2f}, '
Expand Down
18 changes: 9 additions & 9 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,11 @@ def hello():
@app.route('/fps/<package_name>', methods=['GET', 'POST'])
def getfps(package_name):
fps = FPS(package_name=package_name, duration=60, dumpfile="text",
print_latency=False, require_full_name=True)
frames = fps._get_recent_frames()
print_latency=False, require_full_name=False)

stats = fps.get_stats([], True) # Frameless, no frames given, possible error when getting frames
if not fps.error:
if len(frames) < 3:
return
total = len(frames) - 1
dt = (frames[-1].vsync - frames[0].vsync) / 1000000000
avg = total / dt
avg = stats['avg']
return jsonify(str(avg))
else:
return fps.error
Expand All @@ -36,8 +33,11 @@ def getfps(package_name):
@app.route('/cpu/<package_name>', methods=['GET', 'POST'])
def getcpu(package_name):
cpu = CPU(package_id=package_name)
output = cpu._web_gather_cpu_usage()
return output
stats = cpu._web_gather_cpu_usage()
if cpu.error:
error = cpu.get_error()
return {'error': error}
return stats


@app.route('/mem/<package_name>', methods=['GET', 'POST'])
Expand Down