1#!/usr/bin/env python 2# 3# Copyright (C) 2017 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 26 27 28class FmqPerformanceTest(base_test.BaseTestClass): 29 """A testcase for the Fast Message Queue(fmq) Performance Benchmarking. 30 31 Attributes: 32 dut: the target DUT (device under test) instance. 33 _cpu_freq: CpuFrequencyScalingController instance of self.dut. 34 """ 35 # Latency threshold for the benchmark, unit: nanoseconds. 36 THRESHOLD = { 37 32: { 38 "64": 300, 39 "128": 300, 40 "256": 300, 41 "512": 350, 42 }, 43 64: { 44 "64": 150, 45 "128": 150, 46 "256": 150, 47 "512": 150, 48 } 49 } 50 51 def setUpClass(self): 52 self.dut = self.android_devices[0] 53 self._cpu_freq = cpu_frequency_scaling.CpuFrequencyScalingController( 54 self.dut) 55 self._cpu_freq.DisableCpuScaling() 56 57 def tearDownClass(self): 58 self._cpu_freq.EnableCpuScaling() 59 60 def setUp(self): 61 self._cpu_freq.SkipIfThermalThrottling(retry_delay_secs=30) 62 63 def tearDown(self): 64 self._cpu_freq.SkipIfThermalThrottling() 65 66 def testRunBenchmark32Bit(self): 67 """A testcase which runs the 32-bit benchmark.""" 68 self.RunBenchmark(32) 69 70 def testRunBenchmark64Bit(self): 71 """A testcase which runs the 64-bit benchmark.""" 72 self.RunBenchmark(64) 73 74 def RunBenchmark(self, bits): 75 """Runs the native binary and parses its result. 76 77 Args: 78 bits: integer (32 or 64), the number of bits in a word chosen 79 at the compile time (e.g., 32- vs. 64-bit library). 80 """ 81 # Start the benchmark service. 82 logging.info("Start the benchmark service(%s bit mode)", bits) 83 binary = "/data/local/tmp/%s/mq_benchmark_service%s" % (bits, bits) 84 results = self.dut.shell.Execute([ 85 "chmod 755 %s" % binary, 86 "VTS_ROOT_PATH=/data/local/tmp TREBLE_TESTING_OVERRIDE=true " \ 87 "LD_LIBRARY_PATH=/data/local/tmp/%s:" 88 "$LD_LIBRARY_PATH %s&" % (bits, binary) 89 ]) 90 asserts.assertEqual(len(results[const.STDOUT]), 2) 91 asserts.assertFalse( 92 any(results[const.EXIT_CODE]), 93 "Failed to start the benchmark service.") 94 95 # Runs the benchmark. 96 logging.info("Start to run the benchmark (%s bit mode)", bits) 97 binary = "/data/local/tmp/%s/mq_benchmark_client%s" % (bits, bits) 98 99 results = self.dut.shell.Execute([ 100 "chmod 755 %s" % binary, 101 "TREBLE_TESTING_OVERRIDE=true LD_LIBRARY_PATH=/data/local/tmp/%s:" 102 "$LD_LIBRARY_PATH %s" % (bits, binary) 103 ]) 104 105 # Stop the benchmark service. 106 self.dut.shell.Execute("kill -9 `pidof mq_benchmark_service%s`" % 107 bits) 108 109 # Parses the result. 110 asserts.assertEqual(len(results[const.STDOUT]), 2) 111 asserts.assertFalse( 112 any(results[const.EXIT_CODE]), "FmqPerformanceTest failed.") 113 read_label = [] 114 read_latency = [] 115 write_label = [] 116 write_latency = [] 117 stdout_lines = results[const.STDOUT][1].split("\n") 118 for line in stdout_lines: 119 if line.startswith("Average time to read"): 120 read_result = line.replace("Average time to read", "").replace( 121 "bytes", "").replace("ns", "") 122 (label, value) = read_result.split(": ") 123 read_label.append(label) 124 read_latency.append(int(value)) 125 if line.startswith("Average time to write"): 126 write_result = line.replace("Average time to write ", 127 "").replace("bytes", 128 "").replace("ns", "") 129 (label, value) = write_result.split(": ") 130 write_label.append(label) 131 write_latency.append(int(value)) 132 133 # To upload to the web DB. 134 self.web.AddProfilingDataLabeledVector( 135 "fmq_read_latency_benchmark_%sbits" % bits, 136 read_label, 137 read_latency, 138 x_axis_label="Message Size (Bytes)", 139 y_axis_label="Average Latency (nanoseconds)") 140 141 self.web.AddProfilingDataLabeledVector( 142 "fmq_write_latency_benchmark_%sbits" % bits, 143 write_label, 144 write_latency, 145 x_axis_label="Message Size (Bytes)", 146 y_axis_label="Average Latency (nanoseconds)") 147 148 # Assertions to check the performance requirements 149 for label, value in zip(read_label, read_latency): 150 if label in self.THRESHOLD[bits]: 151 asserts.assertLess( 152 value, self.THRESHOLD[bits][label], 153 "%s ns for %s is longer than the threshold %s ns" % ( 154 value, label, self.THRESHOLD[bits][label])) 155 156 for label, value in zip(write_label, write_latency): 157 if label in self.THRESHOLD[bits]: 158 asserts.assertLess( 159 value, self.THRESHOLD[bits][label], 160 "%s ns for %s is longer than the threshold %s ns" % ( 161 value, label, self.THRESHOLD[bits][label])) 162 163 164if __name__ == "__main__": 165 test_runner.main() 166