Generalize AndroidDeviceInfo to DeviceInfo. (#8615)
* Generalize AndroidDeviceInfo to DeviceInfo.
diff --git a/build_tools/benchmarks/common/android_device_utils.py b/build_tools/benchmarks/common/android_device_utils.py
new file mode 100644
index 0000000..2a697c1
--- /dev/null
+++ b/build_tools/benchmarks/common/android_device_utils.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+# Copyright 2021 The IREE Authors
+#
+# Licensed under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+"""Utils for accessing Android devices."""
+
+import json
+import re
+
+from typing import Sequence
+from .benchmark_definition import (execute_cmd_and_get_output, DeviceInfo,
+ PlatformType)
+
+
+def get_android_device_model(verbose: bool = False) -> str:
+ """Returns the Android device model."""
+ model = execute_cmd_and_get_output(
+ ["adb", "shell", "getprop", "ro.product.model"], verbose=verbose)
+ model = re.sub(r"\W+", "-", model)
+ return model
+
+
+def get_android_cpu_abi(verbose: bool = False) -> str:
+ """Returns the CPU ABI for the Android device."""
+ return execute_cmd_and_get_output(
+ ["adb", "shell", "getprop", "ro.product.cpu.abi"], verbose=verbose)
+
+
+def get_android_cpu_features(verbose: bool = False) -> Sequence[str]:
+ """Returns the CPU features for the Android device."""
+ cpuinfo = execute_cmd_and_get_output(["adb", "shell", "cat", "/proc/cpuinfo"],
+ verbose=verbose)
+ features = []
+ for line in cpuinfo.splitlines():
+ if line.startswith("Features"):
+ _, features = line.split(":")
+ return features.strip().split()
+ return features
+
+
+def get_android_gpu_name(verbose: bool = False) -> str:
+ """Returns the GPU name for the Android device."""
+ vkjson = execute_cmd_and_get_output(["adb", "shell", "cmd", "gpu", "vkjson"],
+ verbose=verbose)
+ vkjson = json.loads(vkjson)
+ name = vkjson["devices"][0]["properties"]["deviceName"]
+
+ # Perform some canonicalization:
+
+ # - Adreno GPUs have raw names like "Adreno (TM) 650".
+ name = name.replace("(TM)", "")
+
+ # Replace all consecutive non-word characters with a single hypen.
+ name = re.sub(r"\W+", "-", name)
+
+ return name
+
+
+def get_android_device_info(verbose: bool = False) -> DeviceInfo:
+ """Returns device info for the Android device."""
+ return DeviceInfo(PlatformType.ANDROID, get_android_device_model(verbose),
+ get_android_cpu_abi(verbose),
+ get_android_cpu_features(verbose),
+ get_android_gpu_name(verbose))
diff --git a/build_tools/benchmarks/common/benchmark_definition.py b/build_tools/benchmarks/common/benchmark_definition.py
index ee3b4a0..7bb85a3 100644
--- a/build_tools/benchmarks/common/benchmark_definition.py
+++ b/build_tools/benchmarks/common/benchmark_definition.py
@@ -11,30 +11,39 @@
"""
import json
-import re
import subprocess
from dataclasses import dataclass
+from enum import Enum
from typing import Any, Dict, Sequence
-__all__ = [
- "AndroidDeviceInfo", "BenchmarkInfo", "BenchmarkResults", "BenchmarkRun",
- "execute_cmd_and_get_output", "execute_cmd"
-]
+
+@dataclass
+class DriverInfo:
+ """An object describing a IREE HAL driver.
+
+ It includes the following characteristics:
+ - pretty_name: the pretty name, e.g., 'IREE-DyLib'
+ - device_type: the targeted device type, e.g., 'CPU'
+ """
+
+ pretty_name: str
+ device_type: str
+
# A map for IREE driver names. This allows us to normalize driver names like
# mapping to more friendly ones and detach to keep driver names used in
# benchmark presentation stable.
-IREE_DRIVERS_TO_PRETTY_NAMES = {
- "iree-dylib": "IREE-Dylib",
- "iree-dylib-sync": "IREE-Dylib-Sync",
- "iree-vmvx": "IREE-VMVX",
- "iree-vmvx-sync": "IREE-VMVX-Sync",
- "iree-vulkan": "IREE-Vulkan",
+IREE_DRIVERS_INFOS = {
+ "iree-dylib": DriverInfo("IREE-Dylib", "CPU"),
+ "iree-dylib-sync": DriverInfo("IREE-Dylib-Sync", "CPU"),
+ "iree-vmvx": DriverInfo("IREE-VMVX", "CPU"),
+ "iree-vmvx-sync": DriverInfo("IREE-VMVX-Sync", "CPU"),
+ "iree-vulkan": DriverInfo("IREE-Vulkan", "GPU"),
}
IREE_PRETTY_NAMES_TO_DRIVERS = {
- v: k for k, v in IREE_DRIVERS_TO_PRETTY_NAMES.items()
+ v.pretty_name: k for k, v in IREE_DRIVERS_INFOS.items()
}
@@ -75,61 +84,23 @@
**kwargs).stdout.strip()
-def get_android_device_model(verbose: bool = False) -> str:
- """Returns the Android device model."""
- model = execute_cmd_and_get_output(
- ["adb", "shell", "getprop", "ro.product.model"], verbose=verbose)
- model = re.sub(r"\W+", "-", model)
- return model
-
-
-def get_android_cpu_abi(verbose: bool = False) -> str:
- """Returns the CPU ABI for the Android device."""
- return execute_cmd_and_get_output(
- ["adb", "shell", "getprop", "ro.product.cpu.abi"], verbose=verbose)
-
-
-def get_android_cpu_features(verbose: bool = False) -> Sequence[str]:
- """Returns the CPU features for the Android device."""
- cpuinfo = execute_cmd_and_get_output(["adb", "shell", "cat", "/proc/cpuinfo"],
- verbose=verbose)
- features = []
- for line in cpuinfo.splitlines():
- if line.startswith("Features"):
- _, features = line.split(":")
- return features.strip().split()
- return features
-
-
-def get_android_gpu_name(verbose: bool = False) -> str:
- """Returns the GPU name for the Android device."""
- vkjson = execute_cmd_and_get_output(["adb", "shell", "cmd", "gpu", "vkjson"],
- verbose=verbose)
- vkjson = json.loads(vkjson)
- name = vkjson["devices"][0]["properties"]["deviceName"]
-
- # Perform some canonicalization:
-
- # - Adreno GPUs have raw names like "Adreno (TM) 650".
- name = name.replace("(TM)", "")
-
- # Replace all consecutive non-word characters with a single hypen.
- name = re.sub(r"\W+", "-", name)
-
- return name
+class PlatformType(Enum):
+ ANDROID = "Android"
@dataclass
-class AndroidDeviceInfo:
- """An object describing the current Android Device.
+class DeviceInfo:
+ """An object describing a device.
- It includes the following phone characteristics:
+ It includes the following characteristics:
+ - platform_type: the OS platform, e.g., 'Android'
- model: the product model, e.g., 'Pixel-4'
- cpu_abi: the CPU ABI, e.g., 'arm64-v8a'
- cpu_features: the detailed CPU features, e.g., ['fphp', 'sve']
- gpu_name: the GPU name, e.g., 'Mali-G77'
"""
+ platform_type: PlatformType
model: str
cpu_abi: str
cpu_features: Sequence[str]
@@ -144,12 +115,30 @@
f"cpu_features=[{features}]",
]
params = ", ".join(params)
- return f"Android device <{params}>"
+ return f"{self.platform_type.value} device <{params}>"
- def get_arm_arch_revision(self) -> str:
+ def get_cpu_arch_revision(self) -> str:
+ if self.cpu_abi == "arm64-v8a":
+ return self.__get_arm_cpu_arch_revision()
+ raise ValueError("Unrecognized CPU ABI; need to update the list")
+
+ def to_json_object(self) -> Dict[str, Any]:
+ return {
+ "platform_type": self.platform_type.value,
+ "model": self.model,
+ "cpu_abi": self.cpu_abi,
+ "cpu_features": self.cpu_features,
+ "gpu_name": self.gpu_name,
+ }
+
+ @staticmethod
+ def from_json_object(json_object: Dict[str, Any]):
+ return DeviceInfo(PlatformType(json_object["platform_type"]),
+ json_object["model"], json_object["cpu_abi"],
+ json_object["cpu_features"], json_object["gpu_name"])
+
+ def __get_arm_cpu_arch_revision(self) -> str:
"""Returns the ARM architecture revision."""
- if self.cpu_abi != "arm64-v8a":
- raise ValueError("Unrecognized ARM CPU ABI; need to update the list")
# CPU features for ARMv8 revisions.
# From https://en.wikichip.org/wiki/arm/armv8#ARMv8_Extensions_and_Processor_Features
@@ -165,27 +154,6 @@
rev = "ARMv8.2-A"
return rev
- def to_json_object(self) -> Dict[str, Any]:
- return {
- "model": self.model,
- "cpu_abi": self.cpu_abi,
- "cpu_features": self.cpu_features,
- "gpu_name": self.gpu_name,
- }
-
- @staticmethod
- def from_json_object(json_object: Dict[str, Any]):
- return AndroidDeviceInfo(json_object["model"], json_object["cpu_abi"],
- json_object["cpu_features"],
- json_object["gpu_name"])
-
- @staticmethod
- def from_adb(verbose: bool = False):
- return AndroidDeviceInfo(get_android_device_model(verbose),
- get_android_cpu_abi(verbose),
- get_android_cpu_features(verbose),
- get_android_gpu_name(verbose))
-
@dataclass
class BenchmarkInfo:
@@ -199,8 +167,7 @@
- bench_mode: a list of tags for benchmark mode,
e.g., ['1-thread', 'big-core', 'full-inference']
- runner: which runner is used for benchmarking, e.g., 'iree_vulkan', 'tflite'
- - device_info: an AndroidDeviceInfo object describing the phone where
- benchmarks run
+ - device_info: an DeviceInfo object describing the device where benchmarks run
"""
model_name: str
@@ -208,35 +175,37 @@
model_source: str
bench_mode: Sequence[str]
runner: str
- device_info: AndroidDeviceInfo
+ device_info: DeviceInfo
def __str__(self):
# Get the target architecture and better driver name depending on the runner.
- target_arch = ""
- driver = ""
- if self.runner == "iree-vulkan":
- target_arch = "GPU-" + self.device_info.gpu_name
- driver = IREE_DRIVERS_TO_PRETTY_NAMES[self.runner]
- elif (self.runner == "iree-dylib" or self.runner == "iree-dylib-sync" or
- self.runner == "iree-vmvx" or self.runner == "iree-vmvx-sync"):
- target_arch = "CPU-" + self.device_info.get_arm_arch_revision()
- driver = IREE_DRIVERS_TO_PRETTY_NAMES[self.runner]
- else:
+ driver_info = IREE_DRIVERS_INFOS.get(self.runner)
+ if not driver_info:
raise ValueError(
f"Unrecognized runner '{self.runner}'; need to update the list")
+ target_arch = None
+ if driver_info.device_type == 'GPU':
+ target_arch = "GPU-" + self.device_info.gpu_name
+ elif driver_info.device_type == 'CPU':
+ target_arch = "CPU-" + self.device_info.get_cpu_arch_revision()
+ else:
+ raise ValueError(
+ f"Unrecognized device type '{driver_info.device_type}' of the runner '{self.runner}'"
+ )
+
if self.model_tags:
tags = ",".join(self.model_tags)
model_part = f"{self.model_name} [{tags}] ({self.model_source})"
else:
model_part = f"{self.model_name} ({self.model_source})"
- phone_part = f"{self.device_info.model} ({target_arch})"
+ device_part = f"{self.device_info.model} ({target_arch})"
mode = ",".join(self.bench_mode)
- return f"{model_part} {mode} with {driver} @ {phone_part}"
+ return f"{model_part} {mode} with {driver_info.pretty_name} @ {device_part}"
@staticmethod
- def from_device_info_and_name(device_info: AndroidDeviceInfo, name: str):
+ def from_device_info_and_name(device_info: DeviceInfo, name: str):
(
model_name,
model_tags,
@@ -283,7 +252,7 @@
model_source=json_object["model_source"],
bench_mode=json_object["bench_mode"],
runner=json_object["runner"],
- device_info=AndroidDeviceInfo.from_json_object(
+ device_info=DeviceInfo.from_json_object(
json_object["device_info"]))
diff --git a/build_tools/benchmarks/common/benchmark_suite.py b/build_tools/benchmarks/common/benchmark_suite.py
index 3e09831..bd72617 100644
--- a/build_tools/benchmarks/common/benchmark_suite.py
+++ b/build_tools/benchmarks/common/benchmark_suite.py
@@ -34,17 +34,17 @@
from typing import List, Optional, Sequence
-from .benchmark_definition import AndroidDeviceInfo, BenchmarkInfo
+from .benchmark_definition import DeviceInfo, BenchmarkInfo
# All benchmarks' relative path against root build directory.
BENCHMARK_SUITE_REL_PATH = "benchmark_suites"
-def compose_info_object(device_info: AndroidDeviceInfo,
- benchmark_category_dir: str,
+
+def compose_info_object(device_info: DeviceInfo, benchmark_category_dir: str,
benchmark_case_dir: str) -> BenchmarkInfo:
"""Creates an BenchmarkInfo object to describe the benchmark.
Args:
- device_info: an AndroidDeviceInfo object.
+ device_info: an DeviceInfo object.
benchmark_category_dir: the directory to a specific benchmark category.
benchmark_case_dir: a directory containing the benchmark case.
Returns:
diff --git a/build_tools/benchmarks/run_benchmarks_on_android.py b/build_tools/benchmarks/run_benchmarks_on_android.py
index 7763cf2..a86b7e2 100755
--- a/build_tools/benchmarks/run_benchmarks_on_android.py
+++ b/build_tools/benchmarks/run_benchmarks_on_android.py
@@ -40,15 +40,18 @@
import shutil
import sys
-from typing import Any, Dict, List, Optional, Sequence, Tuple, TextIO, Set
+from typing import List, Optional, Sequence, Tuple, Set
-from common.benchmark_definition import (
- AndroidDeviceInfo, BenchmarkInfo, BenchmarkResults, BenchmarkRun,
- execute_cmd, execute_cmd_and_get_output, get_android_device_model,
- get_android_gpu_name, IREE_PRETTY_NAMES_TO_DRIVERS)
+from common.benchmark_definition import (DeviceInfo, BenchmarkInfo,
+ BenchmarkResults, BenchmarkRun,
+ execute_cmd,
+ execute_cmd_and_get_output)
from common.benchmark_suite import (BENCHMARK_SUITE_REL_PATH,
compose_info_object,
filter_benchmarks_for_category)
+from common.android_device_utils import (get_android_device_model,
+ get_android_device_info,
+ get_android_gpu_name)
# The flagfile/toolfile's filename for compiled benchmark artifacts.
MODEL_FLAGFILE_NAME = "flagfile"
@@ -223,7 +226,7 @@
def run_benchmarks_for_category(
- device_info: AndroidDeviceInfo,
+ device_info: DeviceInfo,
root_benchmark_dir: str,
benchmark_category_dir: str,
benchmark_case_dirs: Sequence[str],
@@ -241,7 +244,7 @@
"""Runs all benchmarks on the Android device and reports results and captures.
Args:
- device_info: an AndroidDeviceInfo object.
+ device_info: an DeviceInfo object.
root_benchmark_dir: path to the benchmark suite within the root build dir
benchmark_category_dir: the directory to a specific benchmark category.
benchmark_case_dirs: a list of benchmark case directories.
@@ -449,7 +452,7 @@
def filter_and_run_benchmarks(
- device_info: AndroidDeviceInfo,
+ device_info: DeviceInfo,
root_build_dir: str,
driver_filter: Optional[str],
model_name_filter: Optional[str],
@@ -467,7 +470,7 @@
"""Filters and runs benchmarks in all categories for the given device.
Args:
- device_info: an AndroidDeviceInfo object.
+ device_info: an DeviceInfo object.
root_build_dir: the root build directory containing the built benchmark
suites.
driver_filter: filter benchmarks to those whose driver matches this regex
@@ -695,7 +698,7 @@
def main(args):
- device_info = AndroidDeviceInfo.from_adb()
+ device_info = get_android_device_info()
if args.verbose:
print(device_info)