Geekbench4 is an app offering several benchmarks to run on android smartphones. The one used in this notebook is the 'CPU' benchmark, which runs several workloads that follow the lines of what is commonly run by smartphones (AES, JPEG codec, FFT, and so on). The benchmark runs all the tests in 'Single-Core' mode as well as in 'Multi-Core' in order to compare the single-thread and multi-thread performances of the device.
Do note that the benchmark will attempt to upload its results, which includes some hardware information
In [1]:
from conf import LisaLogging
LisaLogging.setup()
In [2]:
%pylab inline
import json
import os
# Support to access the remote target
import devlib
from env import TestEnv
# Import support for Android devices
from android import Screen, Workload
# Support for trace events analysis
from trace import Trace
# Suport for FTrace events parsing and visualization
import trappy
import pandas as pd
This function helps us run our experiments:
In [3]:
def experiment():
# Configure governor
target.cpufreq.set_all_governors('sched')
# Get workload
wload = Workload.getInstance(te, 'Geekbench')
# Run Geekbench workload
wload.run(te.res_dir, test_name='CPU', collect='ftrace')
# Dump platform descriptor
te.platform_dump(te.res_dir)
devlib requires the ANDROID_HOME environment variable configured to point to your local installation of the Android SDK. If you have not this variable configured in the shell used to start the notebook server, you need to run a cell to define where your Android SDK is installed or specify the ANDROID_HOME in your target configuration.
In case more than one Android device are conencted to the host, you must specify the ID of the device you want to target in my_target_conf. Run adb devices on your host to get the ID.
In [4]:
# Setup target configuration
my_conf = {
# Target platform and board
"platform" : 'android',
"board" : 'pixel',
# Device
"device" : "0123456789ABCDEF",
# Android home
"ANDROID_HOME" : "/home/vagrant/lisa/tools/android-sdk-linux/",
# Folder where all the results will be collected
"results_dir" : datetime.datetime.now()\
.strftime("Geekbench_example_" + '%Y%m%d_%H%M%S'),
# Define devlib modules to load
"modules" : [
'cpufreq' # enable CPUFreq support
],
# FTrace events to collect for all the tests configuration which have
# the "ftrace" flag enabled
"ftrace" : {
"events" : [
"sched_switch",
"sched_wakeup",
"sched_wakeup_new",
"sched_overutilized",
"sched_load_avg_cpu",
"sched_load_avg_task",
"cpu_capacity",
"cpu_frequency",
],
"buffsize" : 100 * 1024,
},
# Tools required by the experiments
"tools" : [ 'trace-cmd', 'taskset'],
}
In [5]:
# Initialize a test environment using:
te = TestEnv(my_conf, wipe=False)
target = te.target
In [6]:
# Initialize Workloads for this test environment
results = experiment()
Geekbench4 uses a baseline score of 4000, which is the benchmark score of an Intel Core i7-6600U. Higher scores are better, with double the score indicating double the performance. You can have a look at the results for several android phones here https://browser.primatelabs.com/android-benchmarks
In [7]:
class Geekbench(object):
"""
Geekbench json results parsing class
"""
def __init__(self, filepath):
with open(filepath) as fd:
self.__json = json.loads(fd.read())
self.benchmarks = {}
for section in self.__json["sections"]:
self.benchmarks[section["name"]] = section
for workload in section["workloads"]:
self.benchmarks[section["name"]][workload["name"]] = workload
def name(self):
"""Get a human-readable name for the geekbench run
"""
gov = ""
build = ""
for metric in self.__json["metrics"]:
if metric["name"] == "Governor":
gov = metric["value"]
elif metric["name"] == "Build":
build = metric["value"]
return "[build]=\"{}\" [governor]=\"{}\"".format(build, gov)
def benchmarks_names(self):
"""Get a list of benchmarks (e.g. Single-Core, Multi-Core) found in the run results
"""
return [section["name"] for section in self.__json["sections"]]
def workloads_names(self):
"""Get a list of unique workloads (e.g. EAS, Dijkstra) found in the run results
"""
return [workload["name"] for workload in self.benchmarks.values()[0]["workloads"]]
def global_scores(self):
"""Get the overall scores of each benchmark
"""
data = {}
for benchmark in self.benchmarks_names():
data[benchmark] = self.benchmarks[benchmark]["score"]
return data
def detailed_scores(self):
"""Get the detailed workload scores of each benchmark
"""
benchmark_fields = ["score", "runtime_mean", "rate_string"]
benches = {}
benchmarks = self.benchmarks_names()
workloads = self.workloads_names()
for benchmark in benchmarks:
data = {}
for workload in workloads:
data[workload] = {}
for field in benchmark_fields:
data[workload][field] = self.benchmarks[benchmark][workload][field]
benches[benchmark] = data
return benches
In [8]:
def display_bench_results(geekbench, detailed=False):
print "===== Global results ====="
scores = geekbench.global_scores()
# Build dataframe for display
row = []
for bench_type, score in scores.iteritems():
row.append(score)
df = pd.DataFrame(data=row, index=scores.keys(), columns=["Global score"])
display(df)
if not detailed:
return
print "===== Detailed results ====="
scores = geekbench.detailed_scores()
for benchmark, results in geekbench.detailed_scores().iteritems():
print "----- {} benchmark -----".format(benchmark)
# Build dataframe for display
data = []
idx = []
columns = results.values()[0].keys()
for workload, fields in results.iteritems():
data.append(tuple(fields.values()))
idx.append(workload)
display (pd.DataFrame(data=data, index=idx, columns=columns))
In [9]:
for f in os.listdir(te.res_dir):
if f.endswith(".gb4"):
geekbench = Geekbench(te.res_dir + "/" + f)
print "Analysing geekbench {}".format(geekbench.name())
display_bench_results(geekbench, True)
It can be interesting to compare Geekbench results with different parameters (kernel, drivers) and even different devices to gauge the impact of these parameters. As Geekbench results can vary a bit from one run to another, having a set of repeated runs is preferable.
The following section will grab the results of all the Geekbench_exemple_* results found in the LISA results directory
In [10]:
import glob
def fetch_results():
results_path = os.path.join(te.LISA_HOME, "results")
results_dirs = [results_path + "/" + d for d in os.listdir(results_path) if d.startswith("Geekbench_example_")]
res = []
for d in results_dirs:
bench_file = glob.glob("{}/*.gb4".format(d))[0]
res.append(Geekbench(bench_file))
return res
def compare_runs():
geekbenches = fetch_results()
# Pick one run to build a baseline template
benchmarks = geekbenches[0].benchmarks_names()
workloads = geekbenches[0].workloads_names()
stats = ["avg", "min", "max"]
count = len(geekbenches)
print "Parsing {} runs".format(count)
# Initialize stats
results = {benchmark :
{"min" : sys.maxint, "max" : 0, "avg" : 0}
for benchmark in benchmarks}
# Get all the data
for benchmark in results.iterkeys():
for bench in geekbenches:
score = bench.global_scores()[benchmark]
if score > results[benchmark]["max"]:
results[benchmark]["max"] = score
if score < results[benchmark]["min"]:
results[benchmark]["min"] = score
results[benchmark]["avg"] += score
results[benchmark]["avg"] /= count
# Convert data to Dataframe
data = []
for benchmark in results.iterkeys():
row = []
for stat in stats:
row.append(results[benchmark][stat])
data.append(tuple(row))
df = pd.DataFrame(data, index=results.iterkeys(), columns=stats)
return df
In [11]:
display(compare_runs())