1#!/usr/bin/env python
2#
3# Copyright (C) 2016 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18import logging
19
20from vts.runners.host import asserts
21from vts.runners.host import base_test
22from vts.runners.host import const
23from vts.runners.host import test_runner
24from vts.utils.python.controllers import android_device
25from vts.utils.python.cpu import cpu_frequency_scaling
26from vts.utils.python.performance import benchmark_parser
27
28
29class HwBinderPerformanceTest(base_test.BaseTestClass):
30    """A test case for the HWBinder performance benchmarking.
31
32    Attributes:
33        dut: the target DUT (device under test) instance.
34        _cpu_freq: CpuFrequencyScalingController instance of self.dut.
35    """
36
37    THRESHOLD = {
38        32: {
39            "4": 100000,
40            "8": 100000,
41            "16": 100000,
42            "32": 100000,
43            "64": 100000,
44            "128": 100000,
45            "256": 100000,
46            "512": 100000,
47            "1024": 100000,
48            "2k": 100000,
49            "4k": 100000,
50            "8k": 110000,
51            "16k": 120000,
52            "32k": 140000,
53            "64k": 170000,
54        },
55        64: {
56            "4": 100000,
57            "8": 100000,
58            "16": 100000,
59            "32": 100000,
60            "64": 100000,
61            "128": 100000,
62            "256": 100000,
63            "512": 100000,
64            "1024": 100000,
65            "2k": 100000,
66            "4k": 100000,
67            "8k": 110000,
68            "16k": 120000,
69            "32k": 150000,
70            "64k": 200000,
71        }
72    }
73
74    def setUpClass(self):
75        required_params = ["hidl_hal_mode"]
76        self.getUserParams(required_params)
77        self.dut = self.registerController(android_device)[0]
78        self.dut.shell.InvokeTerminal("one")
79        self.dut.shell.one.Execute("stop")
80        self.dut.shell.one.Execute("setprop sys.boot_completed 0")
81        self._cpu_freq = cpu_frequency_scaling.CpuFrequencyScalingController(self.dut)
82        self._cpu_freq.DisableCpuScaling()
83
84    def setUp(self):
85        self._cpu_freq.SkipIfThermalThrottling(retry_delay_secs=30)
86
87    def tearDown(self):
88        self._cpu_freq.SkipIfThermalThrottling()
89
90    def tearDownClass(self):
91        self._cpu_freq.EnableCpuScaling()
92        self.dut.shell.one.Execute("start")
93        self.dut.waitForBootCompletion()
94
95    def testRunBenchmark32Bit(self):
96        """A testcase which runs the 32-bit benchmark."""
97        self.RunBenchmark(32)
98
99    def testRunBenchmark64Bit(self):
100        """A testcase which runs the 64-bit benchmark."""
101        self.RunBenchmark(64)
102
103    def RunBenchmark(self, bits):
104        """Runs the native binary and parses its result.
105
106        Args:
107            bits: integer (32 or 64), the number of bits in a word chosen
108                  at the compile time (e.g., 32- vs. 64-bit library).
109        """
110        # Runs the benchmark.
111        logging.info(
112            "Start to run the benchmark with HIDL mode %s (%s bit mode)",
113            self.hidl_hal_mode, bits)
114        binary = "/data/local/tmp/%s/libhwbinder_benchmark%s" % (bits, bits)
115
116        results = self.dut.shell.one.Execute([
117            "chmod 755 %s" % binary,
118            "LD_LIBRARY_PATH=/system/lib%s:/data/local/tmp/%s/hw:"
119            "/data/local/tmp/%s:$LD_LIBRARY_PATH "
120            "%s -m %s --benchmark_format=json" %
121            (bits, bits, bits, binary, self.hidl_hal_mode.encode("utf-8"))
122        ])
123
124        # Parses the result.
125        asserts.assertEqual(len(results[const.STDOUT]), 2)
126        logging.info("stderr: %s", results[const.STDERR][1])
127        logging.info("stdout: %s", results[const.STDOUT][1])
128        asserts.assertFalse(
129            any(results[const.EXIT_CODE]),
130            "HwBinderPerformanceTest failed.")
131        parser = benchmark_parser.GoogleBenchmarkJsonParser(
132            results[const.STDOUT][1])
133        label_result = parser.getArguments()
134        value_result = parser.getRealTime()
135
136        # To upload to the web DB.
137        self.web.AddProfilingDataLabeledVector(
138            "hwbinder_vector_roundtrip_latency_benchmark_%sbits" % bits,
139            label_result,
140            value_result,
141            x_axis_label="Message Size (Bytes)",
142            y_axis_label="Roundtrip HwBinder RPC Latency (naonseconds)")
143
144        # Assertions to check the performance requirements
145        for label, value in zip(label_result, value_result):
146            if label in self.THRESHOLD[bits]:
147                asserts.assertLess(
148                    value, self.THRESHOLD[bits][label],
149                    "%s ns for %s is longer than the threshold %s ns" % (
150                        value, label, self.THRESHOLD[bits][label]))
151
152
153if __name__ == "__main__":
154    test_runner.main()
155