diff --git a/benchmarking/degrade/degrade_base.py b/benchmarking/degrade/degrade_base.py new file mode 100644 index 00000000..291838c2 --- /dev/null +++ b/benchmarking/degrade/degrade_base.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python + +############################################################################## +# Copyright 2021-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. +############################################################################## + +from typing import TypedDict + + +class DegradeBase(object): + """Base class for platform-specific "degrade" tools to be used to apply cpu or memory device constraints to a benchmark run. + + The implementation-specific constraints are specified by a dictionary containing a "cpu" and / or "memory" dictionary entry. + + For example: + { + "cpu": { + count: "4", + }, + "memory": { + limit: "2000000KB", + } + } + + This class also acts as a default no-op implementation in the case that no implementation is registered for a given platform. + """ + + def __init__(self, platform_util, constraints=None): + """Specify a dictionary containing "cpu" or "memory" options to a degrade tool to apply device constraints to the benchmark run + + Args: + platform_util: (object) Platform-specific Device identifier object, such as adb + constraints (dict): Dictionary containing a "cpu" and / or "memory" dictionary of platform / implementation-specific device contraint options. + + Notes: + The args value may also be passed to setArgs() directly if desired. + + """ + self.util = platform_util + if constraints is not None: + self.specifyConstraints(constraints) + + def __enter__(self): + self.applyConstraints() + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.resetConstraints() + + def specifyConstraints(self, constraints): + """Specify a dictionary containing "cpu" or "memory" options to a degrade tool to apply device constraints to the benchmark run + + Args: + constraints (dict): Dictionary containing a "cpu" and / or "memory" dictionary of platform / implementation-specific device contraint options. + + Notes: + The args value may also be passed to the constructor instead of to setArgs() if desired. + """ + pass + + def applyConstraints(self): + """Apply any cpu / memory constraints set previously""" + pass + + def resetConstraints(self): + """Reset device to defaults (remove any constraints applied previously).""" + pass + + def logConstraints(self): + pass + + +class DegradeEntries(TypedDict): + platform: str + degrade: DegradeBase + + +default_degrade = DegradeBase + +degrade_table: DegradeEntries = {} + + +def registerDegrade(platform: str, degrade: DegradeBase): + """Register a platform-specific DegradeBase implementation. + + Args: + platform (str): Name of the plaform (eg. "android", "ios"). + degrade (DegradeBase): Implementaton drived from DegradeBase. + """ + global degrade_table + degrade_table[platform] = degrade + + +def getDegrade(platform: str) -> DegradeBase: + """Lookup and return a registered platform-specific implementation of DegradeBase. + + Args: + platform (str): Name of the plaform (eg. "android", "ios"). + + Returns: + A matching DegradeBase implementation or the default implementation if none. + """ + global degrade_table + global default_degrade + if platform in degrade_table: + return degrade_table[platform] + + return default_degrade diff --git a/benchmarking/platforms/android/android_platform.py b/benchmarking/platforms/android/android_platform.py index 11bba629..9bdec7df 100644 --- a/benchmarking/platforms/android/android_platform.py +++ b/benchmarking/platforms/android/android_platform.py @@ -15,6 +15,7 @@ import shutil import time +from degrade.degrade_base import DegradeBase, getDegrade from platforms.platform_base import PlatformBase from profilers.profilers import getProfilerByUsage from six import string_types @@ -55,6 +56,8 @@ def __init__(self, tempdir, adb, args, usb_controller=None): self.usb_controller = usb_controller self._setLogCatSize() self.app = None + self.degrade_constraints = None + self.degrade: DegradeBase = getDegrade(self.type) if self.args.set_freq: self.util.setFrequency(self.args.set_freq) @@ -112,6 +115,8 @@ def preprocess(self, *args, **kwargs): if "app" in benchmark["model"]: self.app = benchmark["model"]["app"] + self.degrade_constraints = benchmark["tests"][0].get("degrade") + if not self.app: if "intent.txt" in programs: # temporary to rename the program with adb suffix @@ -152,16 +157,17 @@ def runBenchmark(self, cmd, *args, **kwargs): # that is not the output of the command meta = {} - # We know this command may fail. Avoid propogating this - # failure to the upstream - success = getRunStatus() - self.util.logcat("-b", "all", "-c") - setRunStatus(success, overwrite=True) - if self.app: - log, meta = self.runAppBenchmark(cmd, *args, **kwargs) - else: - log, meta = self.runBinaryBenchmark(cmd, *args, **kwargs) - return log, meta + with self.degrade(self.util, self.degrade_constraints): + # We know this command may fail. Avoid propogating this + # failure to the upstream + success = getRunStatus() + self.util.logcat("-b", "all", "-c") + setRunStatus(success, overwrite=True) + if self.app: + log, meta = self.runAppBenchmark(cmd, *args, **kwargs) + else: + log, meta = self.runBinaryBenchmark(cmd, *args, **kwargs) + return log, meta def runAppBenchmark(self, cmd, *args, **kwargs): arguments = self.getPairedArguments(cmd)