From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id D0BFDA0561; Tue, 21 Apr 2020 07:51:43 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id A02EA1D6CC; Tue, 21 Apr 2020 07:51:43 +0200 (CEST) Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by dpdk.org (Postfix) with ESMTP id EA4EE1D6C3 for ; Tue, 21 Apr 2020 07:51:40 +0200 (CEST) IronPort-SDR: u+6j/RiHO+DGrh3PLysl8kDtCc8JmS08xllp+96HKDEGRPJFyvrQn2J2Ja7t/nf6vAFYGSk1DY eqzjFkwheWJw== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Apr 2020 22:51:40 -0700 IronPort-SDR: 3ZmFXu42bj3nse9YXep9pLjKXuQVyPOGs5ETAHFP95jXdwUOSooKgcOYNYkQ8VxT+ObRB2WL9O sGSrEcJphUcA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.72,409,1580803200"; d="scan'208";a="455966349" Received: from fmsmsx108.amr.corp.intel.com ([10.18.124.206]) by fmsmga005.fm.intel.com with ESMTP; 20 Apr 2020 22:51:40 -0700 Received: from FMSMSX110.amr.corp.intel.com (10.18.116.10) by FMSMSX108.amr.corp.intel.com (10.18.124.206) with Microsoft SMTP Server (TLS) id 14.3.439.0; Mon, 20 Apr 2020 22:51:39 -0700 Received: from shsmsx103.ccr.corp.intel.com (10.239.4.69) by fmsmsx110.amr.corp.intel.com (10.18.116.10) with Microsoft SMTP Server (TLS) id 14.3.439.0; Mon, 20 Apr 2020 22:51:38 -0700 Received: from shsmsx101.ccr.corp.intel.com ([169.254.1.129]) by SHSMSX103.ccr.corp.intel.com ([169.254.4.146]) with mapi id 14.03.0439.000; Tue, 21 Apr 2020 13:51:37 +0800 From: "Tu, Lijuan" To: "Mo, YufengX" , "dts@dpdk.org" , "Yao, Lei A" CC: "Mo, YufengX" Thread-Topic: [dts] [PATCH V1 1/2] tests/power_empty_poll: python3 support and script optimize Thread-Index: AQHWFrGclkMEKT8vNECU+bvxFOcvcqiDFGqQ Date: Tue, 21 Apr 2020 05:51:36 +0000 Message-ID: <8CE3E05A3F976642AAB0F4675D0AD20E0BC0E034@SHSMSX101.ccr.corp.intel.com> References: <20200420012036.3630-1-yufengx.mo@intel.com> <20200420012036.3630-2-yufengx.mo@intel.com> In-Reply-To: <20200420012036.3630-2-yufengx.mo@intel.com> Accept-Language: zh-CN, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: dlp-product: dlpe-windows dlp-version: 11.2.0.6 dlp-reaction: no-action x-originating-ip: [10.239.127.40] Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Subject: Re: [dts] [PATCH V1 1/2] tests/power_empty_poll: python3 support and script optimize X-BeenThere: dts@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: test suite reviews and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dts-bounces@dpdk.org Sender: "dts" Applied, thanks > -----Original Message----- > From: dts [mailto:dts-bounces@dpdk.org] On Behalf Of yufengmx > Sent: Monday, April 20, 2020 9:21 AM > To: dts@dpdk.org; Yao, Lei A > Cc: Mo, YufengX > Subject: [dts] [PATCH V1 1/2] tests/power_empty_poll: python3 support and > script optimize >=20 >=20 > #. python3 support. > #. use pktgen new callback function to take the place of shell script que= ry. > #. change stream frame size to avoid nic perf limitation. > #. update prompt setting. > #. use ^C to take the place of killall. > #. select normal core for priority base frequency cpu. > #. add hyper threading check method. > #. add base frequency cpu type check method. > #. use dts VerifyFailure. > #. display dpdk version. >=20 > Signed-off-by: yufengmx > --- > tests/TestSuite_power_empty_poll.py | 258 ++++++++++++++++++---------- > 1 file changed, 172 insertions(+), 86 deletions(-) >=20 > diff --git a/tests/TestSuite_power_empty_poll.py > b/tests/TestSuite_power_empty_poll.py > index 3be5146..7b35b9d 100644 > --- a/tests/TestSuite_power_empty_poll.py > +++ b/tests/TestSuite_power_empty_poll.py > @@ -1,6 +1,6 @@ > # BSD LICENSE > # > -# Copyright(c) 2010-2019 Intel Corporation. All rights reserved. > +# Copyright(c) 2010-2020 Intel Corporation. All rights reserved. > # All rights reserved. > # > # Redistribution and use in source and binary forms, with or without @@ = - > 31,29 +31,27 @@ >=20 > """ > DPDK Test suite. > -l3fwd-power power management test suite. > +power empty poll test suite. > """ > import os > import time > -import textwrap > import traceback > from copy import deepcopy > +from pprint import pformat >=20 > from utils import create_mask as dts_create_mask > +from exception import VerifyFailure > from test_case import TestCase > - > +from settings import HEADER_SIZE, PKTGEN_TREX > from packet import Packet > from pktgen import TRANSMIT_CONT >=20 >=20 > -class TestPowerEmptPoll(TestCase): > +class TestPowerEmptyPoll(TestCase): > TRAIN =3D 'train' > NOTRAIN =3D 'no-train' > MED =3D 'med_threshold' > HIGH =3D 'high_threshold' > - query_min_freq =3D '/tmp/cpu_min.log' > - query_max_freq =3D '/tmp/cpu_max.log' > - output_path =3D '/tmp' >=20 > @property > def target_dir(self): > @@ -63,6 +61,12 @@ class TestPowerEmptPoll(TestCase): > self.dut.base_dir > return target_dir >=20 > + @property > + def is_use_trex(self): > + return (hasattr(self.tester, 'is_pktgen') and > + self.tester.is_pktgen and > + self.tester.pktgen.pktgen_type =3D=3D PKTGEN_TREX) > + > def d_con(self, cmd): > _cmd =3D [cmd, '# ', 10] if isinstance(cmd, str) else cmd > return self.dut.send_expect(*_cmd) @@ -85,7 +89,7 @@ class > TestPowerEmptPoll(TestCase): > def get_cores_mask(self, cores_list): > return dts_create_mask(cores_list) >=20 > - def set_pktgen_stream(self, txport, rxport, send_pkts, option): > + def add_stream_to_pktgen(self, txport, rxport, send_pkts, option): > stream_ids =3D [] > cnt =3D 0 > for pkt in send_pkts: > @@ -108,29 +112,36 @@ class TestPowerEmptPoll(TestCase): > rate_percent =3D option.get('rate', float(100)) > duration =3D option.get('duration', 10) > send_pkts =3D self.set_stream(stm_type) > + # clear streams before add new streams > + self.tester.pktgen.clear_streams() > # set stream into pktgen > - option =3D { > + s_option =3D { > 'stream_config': { > 'txmode': {}, > 'transmit_mode': TRANSMIT_CONT, > 'rate': rate_percent, } > } > - stream_ids =3D self.set_pktgen_stream(txport, rxport, send_pkts,= option) > + stream_ids =3D self.add_stream_to_pktgen(txport, rxport, > + send_pkts, s_option) > # run traffic options > - traffic_opt =3D { > - 'method': 'throughput', > - 'duration': duration, } > + traffic_opt =3D option.get('traffic_opt') > # run pktgen(ixia/trex) traffic > result =3D self.tester.pktgen.measure(stream_ids, traffic_opt) >=20 > return result >=20 > + def get_pkt_len(self, pkt_type, frame_size): > + headers_size =3D sum([HEADER_SIZE[x] for x in ['eth', 'ip', pkt_= type]]) > + pktlen =3D frame_size - headers_size > + return pktlen > + > def set_stream(self, stm_names=3DNone): > # set streams for traffic > pkt_configs =3D { > 'UDP_1': { > 'type': 'UDP', > - 'pkt_layers': {'ipv4': {'dst': '1.1.1.1'}, }}, > + 'pkt_layers': { > + 'ipv4': {'dst': '1.1.1.1'}, > + 'raw': {'payload': ['58'] * self.get_pkt_len('udp', > + frame_size=3D1024)}}}, > } > # create packet instance for send > streams =3D [] > @@ -150,7 +161,7 @@ class TestPowerEmptPoll(TestCase): > @property > def empty_poll_options(self): > table =3D { > - 'train': '1,0,0,', > + 'train': '1,0,0', > 'no-train': '0,350000,500000', } > return table >=20 > @@ -159,58 +170,60 @@ class TestPowerEmptPoll(TestCase): >=20 > def start_l3fwd_power(self, core): > train_mode =3D self.empty_poll_options.get(self.train_mode) > - option =3D (' ' > + option =3D ('-v ' > '-c {core_mask} ' > '-n {mem_channel} ' > '-- ' > - '-p 0x1 ' > + '-p 0x3 ' > '-P ' > - '--config=3D"(0,0,2)" ' > - '-l 10 -m 6 -h 1' > + '--config=3D"(0,0,{core}),(1,0,{core})" ' > + '-l 10 -m 6 -h 1 ' > '--empty-poll=3D"{empty-poll}" ' > ).format(**{ > + 'core': core[-1], > 'core_mask': self.get_cores_mask(core), > 'mem_channel': self.dut.get_memory_channels(), > 'empty-poll': train_mode, }) > - prompt =3D 'L3FWD_POWER: entering main loop on lcore' > - cmd =3D [' '.join([self.l3fwd_power, option]), prompt, 60] > + prompts =3D { > + self.NOTRAIN: 'POWER: Bring up the Timer', > + self.TRAIN: 'POWER: Training is Complete'} > + prompt =3D prompts.get(self.train_mode) > + cmd =3D [' '.join([self.l3fwd_power, option]), prompt, 120] > self.d_con(cmd) > + self.is_l3fwd_on =3D True >=20 > def close_l3fwd_power(self): > - cmd =3D 'killall l3fwd-power' > - self.d_a_con(cmd) > + if not self.is_l3fwd_on: > + return > + cmd =3D "^C" > + self.d_con(cmd) >=20 > - def init_query_script(self): > - script_content =3D textwrap.dedent(""" > - # $1: delay time before traffic start > - # $2: core number > - sleep 5 > - while : > - do > - sleep 1 > - cat /sys/devices/system/cpu/cpu$1/cpufreq/scaling_min_fr= eq >> > {0} > - cat /sys/devices/system/cpu/cpu$1/cpufreq/scaling_max_fr= eq >> > {1} > - done > - """).format(self.query_min_freq, self.query_max_freq) > - fileName =3D 'vm_power_core.sh' > - query_script =3D os.path.join(self.output_path, fileName) > - with open(query_script, 'wb') as fp: > - fp.write('#! /bin/sh' + os.linesep + script_content) > - self.dut.session.copy_file_to(query_script, self.target_dir) > - self.query_tool =3D ';'.join([ > - 'cd {}'.format(self.target_dir), > - 'chmod 777 {}'.format(fileName), > - './' + fileName]) > - > - def start_query(self, core): > - cmd =3D self.query_tool + ' {0} > /dev/null 2>&1 &'.format(core) > - self.d_a_con(cmd) > + def is_hyper_threading(self): > + cpu_index =3D list(self.cpu_info.keys())[-1] > + core_num =3D self.cpu_info[cpu_index].get('core') > + return (cpu_index + 1) / 2 =3D=3D (core_num + 1) >=20 > - def stop_query(self): > - cmd =3D 'pkill {}'.format(os.path.basename(self.query_tool)) > + def is_support_pbf(self): > + # check if cpu support bpf feature > + cpu_attr =3D r'/sys/devices/system/cpu/cpu0/cpufreq/base_frequen= cy' > + cmd =3D "ls {0}".format(cpu_attr) > self.d_a_con(cmd) > - self.dut.session.copy_file_from(self.query_min_freq, self.output= _path) > - self.dut.session.copy_file_from(self.query_max_freq, self.output= _path) > + cmd =3D "echo $?" > + output =3D self.d_a_con(cmd) > + ret =3D True if output =3D=3D "0" else False > + return ret > + > + def query_cpu_freq(self): > + cmd =3D ( > + "cat /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_min_freq= ;" > + "cat /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_max_freq= ;" > + ).format(self.check_core[1]) > + output =3D self.d_a_con(cmd) > + if not output: > + self.scaling_min_freq, self.scaling_max_freq =3D 0, 0 > + else: > + values =3D [int(item) for item in output.splitlines()] > + self.scaling_min_freq, self.scaling_max_freq =3D values >=20 > def get_sys_power_driver(self): > drv_file =3D "/sys/devices/system/cpu/cpu0/cpufreq/scaling_drive= r" > @@ -221,8 +234,61 @@ class TestPowerEmptPoll(TestCase): > drv_name =3D output.splitlines()[0].strip() > return drv_name >=20 > - def get_no_turbo_max(self): > - cmd =3D 'rdmsr -p 1 0x0CE -f 15:8 -d' > + def get_all_cpu_attrs(self): > + ''' get all cpus' base_frequency value ''' > + key_values =3D ['base_frequency', > + 'cpuinfo_max_freq', > + 'cpuinfo_min_freq'] > + freq =3D '/sys/devices/system/cpu/cpu{0}/cpufreq/{1}'.format > + # use dut alt session to get dut platform cpu base frequency att= ribute > + cpu_topos =3D self.dut.get_all_cores() > + cpu_info =3D {} > + for cpu_topo in cpu_topos: > + cpu_id =3D int(cpu_topo['thread']) > + cpu_info[cpu_id] =3D {} > + cpu_info[cpu_id]['socket'] =3D cpu_topo['socket'] > + cpu_info[cpu_id]['core'] =3D cpu_topo['core'] > + > + for key_value in key_values: > + cmds =3D [] > + for cpu_id in sorted(cpu_info.keys()): > + cmds.append('cat {0}'.format(freq(cpu_id, key_value))) > + output =3D self.d_a_con(';'.join(cmds)) > + freqs =3D [int(item) for item in output.splitlines()] \ > + if key_value !=3D 'scaling_available_frequencies' else \ > + [item for item in output.splitlines()] > + for index, cpu_id in enumerate(sorted(cpu_info.keys())): > + if key_value =3D=3D 'scaling_available_frequencies': > + cpu_info[cpu_id][key_value] =3D \ > + [int(item) for item in sorted(freqs[index].split= ())] > + else: > + cpu_info[cpu_id][key_value] =3D freqs[index] > + > + # get high priority core and normal core > + base_freqs_info =3D {} > + for core_index, value in list(cpu_info.items()): > + base_frequency =3D value.get('base_frequency') > + base_freqs_info.setdefault(base_frequency, []).append(core_i= ndex) > + base_freqs =3D list(base_freqs_info.keys()) > + # cpu should have high priority core and normal core > + # high priority core frequency is higher than normal core freque= ncy > + if len(base_freqs) <=3D 1 or \ > + not all([len(value) for value in list(base_freqs_info.values(= ))]): > + msg =3D 'current cpu has no high priority core' > + raise VerifyFailure(msg) > + self.logger.debug(pformat(base_freqs_info)) > + > + return cpu_info, base_freqs_info > + > + def get_normal_cores_index(self, number): > + normal_freq =3D min(self.base_freqs_info.keys()) > + cores_index =3D self.base_freqs_info[normal_freq][1:number] \ > + if self.base_freqs_info[normal_freq][0] =3D=3D 0 else \ > + self.base_freqs_info[normal_freq][:number] > + return cores_index > + > + def get_no_turbo_max(self, core): > + cmd =3D 'rdmsr -p {} 0x0CE -f 15:8 -d'.format(core) > output =3D self.d_a_con(cmd) > freq =3D output.strip() + '00000' > return int(freq) > @@ -232,21 +298,18 @@ class TestPowerEmptPoll(TestCase): > check the cores frequency when running traffic > highest frequency[no_turbo_max]: > cur_min=3Dcur_max=3Dno_turbo_max > ''' > - self.stop_query() > - freq =3D self.get_no_turbo_max() > - expected_freq =3D str(freq if mode =3D=3D self.HIGH else (freq -= 500000)) > - query_max_freq =3D os.path.join( > - self.output_path, os.path.basename(self.query_max_freq)) > - with open(query_max_freq, 'rb') as fp: > - content =3D fp.read() > - msg =3D 'max freq are not the same as highest frequency <{0}>' > - self.verify(expected_freq in content, msg.format(expected_freq)) > - query_min_freq =3D os.path.join( > - self.output_path, os.path.basename(self.query_min_freq)) > - with open(query_min_freq, 'rb') as fp: > - content =3D fp.read() > - msg =3D 'min freq are not the same as highest frequency <{0}>' > - self.verify(expected_freq in content, msg.format(expected_freq)) > + freq =3D self.get_no_turbo_max(core_index) > + expected_freq =3D freq if mode =3D=3D self.HIGH else (freq - 500= 000) > + msg =3D 'max freq is failed to get.' > + self.verify(self.scaling_max_freq, msg) > + msg =3D 'max freq is not the same as highest frequency <{0}>' > + self.verify(expected_freq =3D=3D self.scaling_max_freq, > + msg.format(expected_freq)) > + msg =3D 'min freq is failed to get.' > + self.verify(self.scaling_min_freq, msg) > + msg =3D 'min freq is not the same as highest frequency <{0}>' > + self.verify(expected_freq =3D=3D self.scaling_min_freq, > + msg.format(expected_freq)) > msg =3D 'core <{0}>: max freq/min_freq/expected freq<{1}> are th= e same' > self.logger.info(msg.format(core_index, expected_freq)) >=20 > @@ -255,6 +318,19 @@ class TestPowerEmptPoll(TestCase): > msg =3D 'training steps should not be executed' > self.verify('POWER: Training is Complete' not in output, msg) >=20 > + @property > + def train_mode_check_item(self): > + # Injected Rate: > + # 10G -> 0.1G -> 10G -> 0.1G -> 10G -> 0.1G > + check_item =3D [ > + [100, self.HIGH], > + [1, self.MED], > + [100, self.HIGH], > + [1, self.MED], > + [100, self.HIGH], > + [1, self.MED], ] > + return check_item > + > def verify_train_mode(self): > except_content =3D None > # begin run vm power policy testing @@ -263,26 +339,22 @@ class > TestPowerEmptPoll(TestCase): > if self.train_mode =3D=3D self.NOTRAIN: > self.check_no_train() > else: > - # Injected Rate(64B, dst_ip=3D1.1.1.1): > - # 10G -> 0.1G -> 10G -> 0.1G -> 10G -> 0.1G > - check_item =3D [ > - [100, self.HIGH], > - [1, self.MED], > - [100, self.HIGH], > - [1, self.MED], > - [100, self.HIGH], > - [1, self.MED], ] > + time.sleep(10) # wait some time for stable training > msg =3D '{0} begin test mode <{1}> with traffic rate per= cent {2}%' > - for rate, mode in check_item: > + for rate, mode in self.train_mode_check_item: > self.logger.info(msg.format(self.train_mode, mode, r= ate)) > - self.start_query(self.check_core[1]) > + duration =3D 20 if self.is_use_trex else 10 > info =3D { > + 'traffic_opt': { > + 'method': 'throughput', > + 'interval': duration - 2, > + 'duration': duration, > + 'callback': self.query_cpu_freq}, > 'stm_types': ['UDP_1'], > 'rate': rate} > # run traffic > self.run_traffic(info) > - time.sleep(2) > - self.stop_query() > + time.sleep(15 if self.is_use_trex else 2) > # check test result > self.check_core_freq_in_traffic(self.check_core[1], = mode) > except Exception as e: > @@ -293,7 +365,7 @@ class TestPowerEmptPoll(TestCase): >=20 > # check verify result > if except_content: > - raise Exception(except_content) > + raise VerifyFailure(except_content) > else: > msg =3D "test <{0}> successful !!!".format(self.train_mode) > self.logger.info(msg) > @@ -305,13 +377,25 @@ class TestPowerEmptPoll(TestCase): > self.suite_name, expected_drv) > self.verify(power_drv =3D=3D expected_drv, msg) >=20 > + def verify_hyper_threading(self): > + msg =3D "{} should work under hyper threading close status" > + self.verify(not self.is_hyper_threading(), > + msg.format(self.suite_name)) > + > + def verify_pbf_supported(self): > + if self.is_support_pbf(): > + return > + msg =3D "dut cpu doesn't support priority base frequency feature= " > + raise VerifyFailure(msg) > + > def preset_test_environment(self): > - self.check_core =3D [1, 2] > + self.is_l3fwd_on =3D None > + self.cpu_info, self.base_freqs_info =3D self.get_all_cpu_attrs() > + self.check_core =3D self.get_normal_cores_index(2) > + self.verify_hyper_threading() > # modprobe msr module to let the application can get the CPU HW = info > self.d_a_con('modprobe msr') > # init binary > self.init_l3fwd_power() > - self.init_query_script() > # > # Test cases. > # > @@ -321,6 +405,8 @@ class TestPowerEmptPoll(TestCase): > Run at the start of each test suite. > """ > self.verify_power_driver() > + # check if cpu support bpf feature > + self.verify_pbf_supported() > self.dut_ports =3D self.dut.get_ports(self.nic) > self.verify(len(self.dut_ports) >=3D 2, "Not enough ports") > # prepare testing environment > -- > 2.21.0