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.android_devices[0]
78        self.dut.shell.Execute("stop")
79        self.dut.shell.Execute("setprop sys.boot_completed 0")
80        self._cpu_freq = cpu_frequency_scaling.CpuFrequencyScalingController(self.dut)
81        self._cpu_freq.DisableCpuScaling()
82
83    def setUp(self):
84        self._cpu_freq.SkipIfThermalThrottling(retry_delay_secs=30)
85
86    def tearDown(self):
87        self._cpu_freq.SkipIfThermalThrottling()
88
89    def tearDownClass(self):
90        self._cpu_freq.EnableCpuScaling()
91        self.dut.shell.Execute("start")
92        self.dut.waitForBootCompletion()
93
94    def testRunBenchmark32Bit(self):
95        """A testcase which runs the 32-bit benchmark."""
96        self.RunBenchmark(32)
97
98    def testRunBenchmark64Bit(self):
99        """A testcase which runs the 64-bit benchmark."""
100        self.RunBenchmark(64)
101
102    def RunBenchmark(self, bits):
103        """Runs the native binary and parses its result.
104
105        Args:
106            bits: integer (32 or 64), the number of bits in a word chosen
107                  at the compile time (e.g., 32- vs. 64-bit library).
108        """
109        # Runs the benchmark.
110        logging.info(
111            "Start to run the benchmark with HIDL mode %s (%s bit mode)",
112            self.hidl_hal_mode, bits)
113        binary = "/data/local/tmp/%s/libhwbinder_benchmark%s" % (bits, bits)
114
115        results = self.dut.shell.Execute([
116            "chmod 755 %s" % binary,
117            "VTS_ROOT_PATH=/data/local/tmp " \
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        table_name = "hwbinder_vector_roundtrip_latency_benchmark_%sbits" % bits
136        self.addTableToResult(table_name, parser.ToTable())
137
138        # To upload to the web DB.
139        self.web.AddProfilingDataLabeledVector(
140            table_name,
141            label_result,
142            value_result,
143            x_axis_label="Message Size (Bytes)",
144            y_axis_label="Roundtrip HwBinder RPC Latency (naonseconds)")
145
146        # Assertions to check the performance requirements
147        for label, value in zip(label_result, value_result):
148            if label in self.THRESHOLD[bits]:
149                asserts.assertLess(
150                    value, self.THRESHOLD[bits][label],
151                    "%s ns for %s is longer than the threshold %s ns" % (
152                        value, label, self.THRESHOLD[bits][label]))
153
154
155if __name__ == "__main__":
156    test_runner.main()
157