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 BinderPerformanceTest(base_test.BaseTestClass):
30    """A testcase for the Binder 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": 150000,
40            "8": 150000,
41            "16": 150000,
42            "32": 150000,
43            "64": 150000,
44            "128": 150000,
45            "256": 150000,
46            "512": 150000,
47            "1024": 150000,
48            "2k": 200000,
49            "4k": 300000,
50            "8k": 400000,
51            "16k": 600000,
52            "32k": 800000,
53            "64k": 1000000,
54        },
55        64: {
56            "4": 150000,
57            "8": 150000,
58            "16": 150000,
59            "32": 150000,
60            "64": 150000,
61            "128": 150000,
62            "256": 150000,
63            "512": 150000,
64            "1024": 150000,
65            "2k": 200000,
66            "4k": 300000,
67            "8k": 400000,
68            "16k": 600000,
69            "32k": 800000,
70            "64k": 1000000,
71        }
72    }
73
74    def setUpClass(self):
75        self.dut = self.android_devices[0]
76        self.dut.shell.Execute("stop")
77        self.dut.shell.Execute("setprop sys.boot_completed 0")
78        self._cpu_freq = cpu_frequency_scaling.CpuFrequencyScalingController(self.dut)
79        self._cpu_freq.DisableCpuScaling()
80
81    def setUp(self):
82        self._cpu_freq.SkipIfThermalThrottling(retry_delay_secs=30)
83
84    def tearDown(self):
85        self._cpu_freq.SkipIfThermalThrottling()
86
87    def tearDownClass(self):
88        self._cpu_freq.EnableCpuScaling()
89        self.dut.shell.Execute("start")
90        self.dut.waitForBootCompletion()
91
92    def testRunBenchmark32Bit(self):
93        """A testcase which runs the 32-bit benchmark."""
94        self.RunBenchmark(32)
95
96    def testRunBenchmark64Bit(self):
97        """A testcase which runs the 64-bit benchmark."""
98        self.RunBenchmark(64)
99
100    def RunBenchmark(self, bits):
101        """Runs the native binary and parses its result.
102
103        Args:
104            bits: integer (32 or 64), the number of bits in a word chosen
105                  at the compile time (e.g., 32- vs. 64-bit library).
106        """
107        # Runs the benchmark.
108        logging.info("Start to run the benchmark (%s bit mode)", bits)
109        binary = "/data/local/tmp/%s/libbinder_benchmark%s" % (bits, bits)
110
111        results = self.dut.shell.Execute([
112            "chmod 755 %s" % binary, "LD_LIBRARY_PATH=/data/local/tmp/%s/hw:"
113            "/data/local/tmp/%s:$LD_LIBRARY_PATH "
114            "%s --benchmark_format=json" % (bits, bits, binary)
115        ])
116
117        # Parses the result.
118        asserts.assertEqual(len(results[const.STDOUT]), 2)
119        logging.info("stderr: %s", results[const.STDERR][1])
120        logging.info("stdout: %s", results[const.STDOUT][1])
121        asserts.assertFalse(
122            any(results[const.EXIT_CODE]),
123            "BinderPerformanceTest failed.")
124        parser = benchmark_parser.GoogleBenchmarkJsonParser(
125            results[const.STDOUT][1])
126        label_result = parser.GetArguments()
127        value_result = parser.GetRealTime()
128        table_name = "binder_vector_roundtrip_latency_benchmark_%sbits" % bits
129        self.addTableToResult(table_name, parser.ToTable())
130
131        # To upload to the web DB.
132        self.web.AddProfilingDataLabeledVector(
133            table_name,
134            label_result,
135            value_result,
136            x_axis_label="Message Size (Bytes)",
137            y_axis_label="Roundtrip Binder RPC Latency (nanoseconds)")
138
139        # Assertions to check the performance requirements
140        for label, value in zip(label_result, value_result):
141            if label in self.THRESHOLD[bits]:
142                asserts.assertLess(
143                    value, self.THRESHOLD[bits][label],
144                    "%s ns for %s is longer than the threshold %s ns" % (
145                        value, label, self.THRESHOLD[bits][label]))
146
147
148if __name__ == "__main__":
149    test_runner.main()
150