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.registerController(android_device)[0] 53 self.dut.shell.InvokeTerminal("one") 54 self._cpu_freq = cpu_frequency_scaling.CpuFrequencyScalingController(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.one.Execute([ 85 "chmod 755 %s" % binary, "LD_LIBRARY_PATH=/data/local/tmp/%s:" 86 "$LD_LIBRARY_PATH %s&" % (bits, binary) 87 ]) 88 asserts.assertEqual(len(results[const.STDOUT]), 2) 89 asserts.assertFalse(any(results[const.EXIT_CODE]), 90 "Failed to start the benchmark service.") 91 92 # Runs the benchmark. 93 logging.info("Start to run the benchmark (%s bit mode)", bits) 94 binary = "/data/local/tmp/%s/mq_benchmark_client%s" % (bits, bits) 95 96 results = self.dut.shell.one.Execute([ 97 "chmod 755 %s" % binary, "LD_LIBRARY_PATH=/data/local/tmp/%s:" 98 "$LD_LIBRARY_PATH %s" % (bits, binary) 99 ]) 100 101 # Stop the benchmark service. 102 self.dut.shell.one.Execute("kill -9 `pidof mq_benchmark_service%s`" % bits) 103 104 # Parses the result. 105 asserts.assertEqual(len(results[const.STDOUT]), 2) 106 asserts.assertFalse(any(results[const.EXIT_CODE]), 107 "FmqPerformanceTest failed.") 108 read_label = [] 109 read_latency = [] 110 write_label = [] 111 write_latency = [] 112 stdout_lines = results[const.STDOUT][1].split("\n") 113 for line in stdout_lines: 114 if line.startswith("Average time to read"): 115 read_result = line.replace( 116 "Average time to read", "").replace( 117 "bytes", "").replace("ns", "") 118 (label, value) = read_result.split(": ") 119 read_label.append(label) 120 read_latency.append(int(value)) 121 if line.startswith("Average time to write"): 122 write_result = line.replace( 123 "Average time to write ", "").replace( 124 "bytes", "").replace("ns", "") 125 (label, value) = write_result.split(": ") 126 write_label.append(label) 127 write_latency.append(int(value)) 128 129 # To upload to the web DB. 130 self.web.AddProfilingDataLabeledVector( 131 "fmq_read_latency_benchmark_%sbits" % bits, 132 read_label, 133 read_latency, 134 x_axis_label="Message Size (Bytes)", 135 y_axis_label="Average Latency (nanoseconds)") 136 137 self.web.AddProfilingDataLabeledVector( 138 "fmq_write_latency_benchmark_%sbits" % bits, 139 write_label, 140 write_latency, 141 x_axis_label="Message Size (Bytes)", 142 y_axis_label="Average Latency (nanoseconds)") 143 144 # Assertions to check the performance requirements 145 for label, value in zip(read_label, read_latency): 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 for label, value in zip(write_label, write_latency): 153 if label in self.THRESHOLD[bits]: 154 asserts.assertLess( 155 value, self.THRESHOLD[bits][label], 156 "%s ns for %s is longer than the threshold %s ns" % ( 157 value, label, self.THRESHOLD[bits][label])) 158 159if __name__ == "__main__": 160 test_runner.main() 161