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.registerController(android_device)[0]
76        self.dut.shell.InvokeTerminal("one")
77        self.dut.shell.one.Execute("stop")
78        self.dut.shell.one.Execute("setprop sys.boot_completed 0")
79        self._cpu_freq = cpu_frequency_scaling.CpuFrequencyScalingController(self.dut)
80        self._cpu_freq.DisableCpuScaling()
81
82    def setUp(self):
83        self._cpu_freq.SkipIfThermalThrottling(retry_delay_secs=30)
84
85    def tearDown(self):
86        self._cpu_freq.SkipIfThermalThrottling()
87
88    def tearDownClass(self):
89        self._cpu_freq.EnableCpuScaling()
90        self.dut.shell.one.Execute("start")
91        self.dut.waitForBootCompletion()
92
93    def testRunBenchmark32Bit(self):
94        """A testcase which runs the 32-bit benchmark."""
95        self.RunBenchmark(32)
96
97    def testRunBenchmark64Bit(self):
98        """A testcase which runs the 64-bit benchmark."""
99        self.RunBenchmark(64)
100
101    def RunBenchmark(self, bits):
102        """Runs the native binary and parses its result.
103
104        Args:
105            bits: integer (32 or 64), the number of bits in a word chosen
106                  at the compile time (e.g., 32- vs. 64-bit library).
107        """
108        # Runs the benchmark.
109        logging.info("Start to run the benchmark (%s bit mode)", bits)
110        binary = "/data/local/tmp/%s/libbinder_benchmark%s" % (bits, bits)
111
112        results = self.dut.shell.one.Execute([
113            "chmod 755 %s" % binary, "LD_LIBRARY_PATH=/data/local/tmp/%s/hw:"
114            "/data/local/tmp/%s:$LD_LIBRARY_PATH "
115            "%s --benchmark_format=json" % (bits, bits, binary)
116        ])
117
118        # Parses the result.
119        asserts.assertEqual(len(results[const.STDOUT]), 2)
120        logging.info("stderr: %s", results[const.STDERR][1])
121        logging.info("stdout: %s", results[const.STDOUT][1])
122        asserts.assertFalse(
123            any(results[const.EXIT_CODE]),
124            "BinderPerformanceTest failed.")
125        parser = benchmark_parser.GoogleBenchmarkJsonParser(
126            results[const.STDOUT][1])
127        label_result = parser.getArguments()
128        value_result = parser.getRealTime()
129
130        # To upload to the web DB.
131        self.web.AddProfilingDataLabeledVector(
132            "binder_vector_roundtrip_latency_benchmark_%sbits" % bits,
133            label_result,
134            value_result,
135            x_axis_label="Message Size (Bytes)",
136            y_axis_label="Roundtrip Binder RPC Latency (nanoseconds)")
137
138        # Assertions to check the performance requirements
139        for label, value in zip(label_result, value_result):
140            if label in self.THRESHOLD[bits]:
141                asserts.assertLess(
142                    value, self.THRESHOLD[bits][label],
143                    "%s ns for %s is longer than the threshold %s ns" % (
144                        value, label, self.THRESHOLD[bits][label]))
145
146
147if __name__ == "__main__":
148    test_runner.main()
149