test suite reviews and discussions
 help / color / mirror / Atom feed
* [dts] [PATCH V1 0/2] tests/power_empty_poll: python3 support and script optimize
@ 2020-04-20  1:20 yufengmx
  2020-04-20  1:20 ` [dts] [PATCH V1 1/2] " yufengmx
  2020-04-20  1:20 ` [dts] [PATCH V1 2/2] tests/power_empty_poll: update test plan yufengmx
  0 siblings, 2 replies; 5+ messages in thread
From: yufengmx @ 2020-04-20  1:20 UTC (permalink / raw)
  To: dts, lei.a.yao; +Cc: yufengmx


. python3 support. 

. use pktgen new callback function to take the place of shell script query. 

. 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. 

. update test plan. 

yufengmx (2):
  tests/power_empty_poll: python3 support and script optimize
  tests/power_empty_poll: update test plan

 test_plans/power_empty_poll_test_plan.rst |  16 +-
 tests/TestSuite_power_empty_poll.py       | 258 ++++++++++++++--------
 2 files changed, 183 insertions(+), 91 deletions(-)

-- 
2.21.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [dts] [PATCH V1 1/2] tests/power_empty_poll: python3 support and script optimize
  2020-04-20  1:20 [dts] [PATCH V1 0/2] tests/power_empty_poll: python3 support and script optimize yufengmx
@ 2020-04-20  1:20 ` yufengmx
  2020-04-21  5:51   ` Tu, Lijuan
  2020-04-20  1:20 ` [dts] [PATCH V1 2/2] tests/power_empty_poll: update test plan yufengmx
  1 sibling, 1 reply; 5+ messages in thread
From: yufengmx @ 2020-04-20  1:20 UTC (permalink / raw)
  To: dts, lei.a.yao; +Cc: yufengmx


#. python3 support.
#. use pktgen new callback function to take the place of shell script query.
#. 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.

Signed-off-by: yufengmx <yufengx.mo@intel.com>
---
 tests/TestSuite_power_empty_poll.py | 258 ++++++++++++++++++----------
 1 file changed, 172 insertions(+), 86 deletions(-)

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 @@
 
 """
 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
 
 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
 
 
-class TestPowerEmptPoll(TestCase):
+class TestPowerEmptyPoll(TestCase):
     TRAIN = 'train'
     NOTRAIN = 'no-train'
     MED = 'med_threshold'
     HIGH = 'high_threshold'
-    query_min_freq = '/tmp/cpu_min.log'
-    query_max_freq = '/tmp/cpu_max.log'
-    output_path = '/tmp'
 
     @property
     def target_dir(self):
@@ -63,6 +61,12 @@ class TestPowerEmptPoll(TestCase):
                      self.dut.base_dir
         return target_dir
 
+    @property
+    def is_use_trex(self):
+        return (hasattr(self.tester, 'is_pktgen') and
+                self.tester.is_pktgen and
+                self.tester.pktgen.pktgen_type == PKTGEN_TREX)
+
     def d_con(self, cmd):
         _cmd = [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)
 
-    def set_pktgen_stream(self, txport, rxport, send_pkts, option):
+    def add_stream_to_pktgen(self, txport, rxport, send_pkts, option):
         stream_ids = []
         cnt = 0
         for pkt in send_pkts:
@@ -108,29 +112,36 @@ class TestPowerEmptPoll(TestCase):
         rate_percent = option.get('rate', float(100))
         duration = option.get('duration', 10)
         send_pkts = self.set_stream(stm_type)
+        # clear streams before add new streams
+        self.tester.pktgen.clear_streams()
         # set stream into pktgen
-        option = {
+        s_option = {
             'stream_config': {
                 'txmode': {},
                 'transmit_mode': TRANSMIT_CONT,
                 'rate': rate_percent, }
         }
-        stream_ids = self.set_pktgen_stream(txport, rxport, send_pkts, option)
+        stream_ids = self.add_stream_to_pktgen(txport, rxport, send_pkts, s_option)
         # run traffic options
-        traffic_opt = {
-            'method': 'throughput',
-            'duration': duration, }
+        traffic_opt = option.get('traffic_opt')
         # run pktgen(ixia/trex) traffic
         result = self.tester.pktgen.measure(stream_ids, traffic_opt)
 
         return result
 
+    def get_pkt_len(self, pkt_type, frame_size):
+        headers_size = sum([HEADER_SIZE[x] for x in ['eth', 'ip', pkt_type]])
+        pktlen = frame_size - headers_size
+        return pktlen
+
     def set_stream(self, stm_names=None):
         # set streams for traffic
         pkt_configs = {
             '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=1024)}}},
         }
         # create packet instance for send
         streams = []
@@ -150,7 +161,7 @@ class TestPowerEmptPoll(TestCase):
     @property
     def empty_poll_options(self):
         table = {
-            'train': '1,0,0,',
+            'train': '1,0,0',
             'no-train': '0,350000,500000', }
         return table
 
@@ -159,58 +170,60 @@ class TestPowerEmptPoll(TestCase):
 
     def start_l3fwd_power(self, core):
         train_mode = self.empty_poll_options.get(self.train_mode)
-        option = (' '
+        option = ('-v '
                   '-c {core_mask} '
                   '-n {mem_channel} '
                   '-- '
-                  '-p 0x1 '
+                  '-p 0x3 '
                   '-P '
-                  '--config="(0,0,2)" '
-                  '-l 10 -m 6 -h 1'
+                  '--config="(0,0,{core}),(1,0,{core})" '
+                  '-l 10 -m 6 -h 1 '
                   '--empty-poll="{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 = 'L3FWD_POWER: entering main loop on lcore'
-        cmd = [' '.join([self.l3fwd_power, option]), prompt, 60]
+        prompts = {
+            self.NOTRAIN: 'POWER: Bring up the Timer',
+            self.TRAIN: 'POWER: Training is Complete'}
+        prompt = prompts.get(self.train_mode)
+        cmd = [' '.join([self.l3fwd_power, option]), prompt, 120]
         self.d_con(cmd)
+        self.is_l3fwd_on = True
 
     def close_l3fwd_power(self):
-        cmd = 'killall l3fwd-power'
-        self.d_a_con(cmd)
+        if not self.is_l3fwd_on:
+            return
+        cmd = "^C"
+        self.d_con(cmd)
 
-    def init_query_script(self):
-        script_content = 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_freq >> {0}
-                cat /sys/devices/system/cpu/cpu$1/cpufreq/scaling_max_freq >> {1}
-            done
-        """).format(self.query_min_freq, self.query_max_freq)
-        fileName = 'vm_power_core.sh'
-        query_script = 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 = ';'.join([
-            'cd {}'.format(self.target_dir),
-            'chmod 777 {}'.format(fileName),
-            './' + fileName])
-
-    def start_query(self, core):
-        cmd = self.query_tool + ' {0} > /dev/null 2>&1 &'.format(core)
-        self.d_a_con(cmd)
+    def is_hyper_threading(self):
+        cpu_index = list(self.cpu_info.keys())[-1]
+        core_num = self.cpu_info[cpu_index].get('core')
+        return (cpu_index + 1) / 2 == (core_num + 1)
 
-    def stop_query(self):
-        cmd = 'pkill {}'.format(os.path.basename(self.query_tool))
+    def is_support_pbf(self):
+        # check if cpu support bpf feature
+        cpu_attr = r'/sys/devices/system/cpu/cpu0/cpufreq/base_frequency'
+        cmd = "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 = "echo $?"
+        output = self.d_a_con(cmd)
+        ret = True if output == "0" else False
+        return ret
+
+    def query_cpu_freq(self):
+        cmd = (
+            "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 = self.d_a_con(cmd)
+        if not output:
+            self.scaling_min_freq, self.scaling_max_freq = 0, 0
+        else:
+            values = [int(item) for item in output.splitlines()]
+            self.scaling_min_freq, self.scaling_max_freq = values
 
     def get_sys_power_driver(self):
         drv_file = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_driver"
@@ -221,8 +234,61 @@ class TestPowerEmptPoll(TestCase):
         drv_name = output.splitlines()[0].strip()
         return drv_name
 
-    def get_no_turbo_max(self):
-        cmd = 'rdmsr -p 1 0x0CE -f 15:8 -d'
+    def get_all_cpu_attrs(self):
+        ''' get all cpus' base_frequency value '''
+        key_values = ['base_frequency',
+                      'cpuinfo_max_freq',
+                      'cpuinfo_min_freq']
+        freq = '/sys/devices/system/cpu/cpu{0}/cpufreq/{1}'.format
+        # use dut alt session to get dut platform cpu base frequency attribute
+        cpu_topos = self.dut.get_all_cores()
+        cpu_info = {}
+        for cpu_topo in cpu_topos:
+            cpu_id = int(cpu_topo['thread'])
+            cpu_info[cpu_id] = {}
+            cpu_info[cpu_id]['socket'] = cpu_topo['socket']
+            cpu_info[cpu_id]['core'] = cpu_topo['core']
+
+        for key_value in key_values:
+            cmds = []
+            for cpu_id in sorted(cpu_info.keys()):
+                cmds.append('cat {0}'.format(freq(cpu_id, key_value)))
+            output = self.d_a_con(';'.join(cmds))
+            freqs = [int(item) for item in output.splitlines()] \
+                if key_value != 'scaling_available_frequencies' else \
+                    [item for item in output.splitlines()]
+            for index, cpu_id in enumerate(sorted(cpu_info.keys())):
+                if key_value == 'scaling_available_frequencies':
+                    cpu_info[cpu_id][key_value] = \
+                        [int(item) for item in sorted(freqs[index].split())]
+                else:
+                    cpu_info[cpu_id][key_value] = freqs[index]
+
+        # get high priority core and normal core
+        base_freqs_info = {}
+        for core_index, value in list(cpu_info.items()):
+            base_frequency = value.get('base_frequency')
+            base_freqs_info.setdefault(base_frequency, []).append(core_index)
+        base_freqs = list(base_freqs_info.keys())
+        # cpu should have high priority core and normal core
+        # high priority core frequency is higher than normal core frequency
+        if len(base_freqs) <= 1 or \
+           not all([len(value) for value in list(base_freqs_info.values())]):
+            msg = '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 = min(self.base_freqs_info.keys())
+        cores_index = self.base_freqs_info[normal_freq][1:number] \
+            if self.base_freqs_info[normal_freq][0] == 0 else \
+            self.base_freqs_info[normal_freq][:number]
+        return cores_index
+
+    def get_no_turbo_max(self, core):
+        cmd = 'rdmsr -p {} 0x0CE -f 15:8 -d'.format(core)
         output = self.d_a_con(cmd)
         freq = 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=cur_max=no_turbo_max
         '''
-        self.stop_query()
-        freq = self.get_no_turbo_max()
-        expected_freq = str(freq if mode == self.HIGH else (freq - 500000))
-        query_max_freq = os.path.join(
-            self.output_path, os.path.basename(self.query_max_freq))
-        with open(query_max_freq, 'rb') as fp:
-            content = fp.read()
-        msg = 'max freq are not the same as highest frequency <{0}>'
-        self.verify(expected_freq in content, msg.format(expected_freq))
-        query_min_freq = os.path.join(
-            self.output_path, os.path.basename(self.query_min_freq))
-        with open(query_min_freq, 'rb') as fp:
-            content = fp.read()
-        msg = 'min freq are not the same as highest frequency <{0}>'
-        self.verify(expected_freq in content, msg.format(expected_freq))
+        freq = self.get_no_turbo_max(core_index)
+        expected_freq = freq if mode == self.HIGH else (freq - 500000)
+        msg = 'max freq is failed to get.'
+        self.verify(self.scaling_max_freq, msg)
+        msg = 'max freq is not the same as highest frequency <{0}>'
+        self.verify(expected_freq == self.scaling_max_freq,
+                    msg.format(expected_freq))
+        msg = 'min freq is failed to get.'
+        self.verify(self.scaling_min_freq, msg)
+        msg = 'min freq is not the same as highest frequency <{0}>'
+        self.verify(expected_freq == self.scaling_min_freq,
+                    msg.format(expected_freq))
         msg = 'core <{0}>: max freq/min_freq/expected freq<{1}> are the same'
         self.logger.info(msg.format(core_index, expected_freq))
 
@@ -255,6 +318,19 @@ class TestPowerEmptPoll(TestCase):
         msg = 'training steps should not be executed'
         self.verify('POWER: Training is Complete' not in output, msg)
 
+    @property
+    def train_mode_check_item(self):
+        # Injected Rate:
+        #      10G -> 0.1G -> 10G -> 0.1G -> 10G -> 0.1G
+        check_item = [
+            [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 = None
         # begin run vm power policy testing
@@ -263,26 +339,22 @@ class TestPowerEmptPoll(TestCase):
             if self.train_mode == self.NOTRAIN:
                 self.check_no_train()
             else:
-                # Injected Rate(64B, dst_ip=1.1.1.1):
-                #      10G -> 0.1G -> 10G -> 0.1G -> 10G -> 0.1G
-                check_item = [
-                    [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 = '{0} begin test mode <{1}> with traffic rate percent {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, rate))
-                    self.start_query(self.check_core[1])
+                    duration = 20 if self.is_use_trex else 10
                     info = {
+                        '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):
 
         # check verify result
         if except_content:
-            raise Exception(except_content)
+            raise VerifyFailure(except_content)
         else:
             msg = "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 == expected_drv, msg)
 
+    def verify_hyper_threading(self):
+        msg = "{} 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 = "dut cpu doesn't support priority base frequency feature"
+        raise VerifyFailure(msg)
+
     def preset_test_environment(self):
-        self.check_core = [1, 2]
+        self.is_l3fwd_on = None
+        self.cpu_info, self.base_freqs_info = self.get_all_cpu_attrs()
+        self.check_core = 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 = self.dut.get_ports(self.nic)
         self.verify(len(self.dut_ports) >= 2, "Not enough ports")
         # prepare testing environment
-- 
2.21.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [dts] [PATCH V1 2/2] tests/power_empty_poll: update test plan
  2020-04-20  1:20 [dts] [PATCH V1 0/2] tests/power_empty_poll: python3 support and script optimize yufengmx
  2020-04-20  1:20 ` [dts] [PATCH V1 1/2] " yufengmx
@ 2020-04-20  1:20 ` yufengmx
  2020-04-20  5:24   ` Tu, Lijuan
  1 sibling, 1 reply; 5+ messages in thread
From: yufengmx @ 2020-04-20  1:20 UTC (permalink / raw)
  To: dts, lei.a.yao; +Cc: yufengmx


#. add missing hyper threading setting.
#. update traffic framesize usage.

Signed-off-by: yufengmx <yufengx.mo@intel.com>
---
 test_plans/power_empty_poll_test_plan.rst | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/test_plans/power_empty_poll_test_plan.rst b/test_plans/power_empty_poll_test_plan.rst
index 61c698c..4472830 100644
--- a/test_plans/power_empty_poll_test_plan.rst
+++ b/test_plans/power_empty_poll_test_plan.rst
@@ -101,10 +101,16 @@ state. If this is not supplied, the application will apply the default value of
 
 Preparation Work for Settings
 =============================
-1. Turn on Speedstep option in BIOS
-2. Turn on Turbo in BIOS
-3. Use intel_pstate driver for CPU frequency control
-4. modprobe msr
+BIOS setting::
+
+    1. Turn on Speedstep option in BIOS
+    2. Turn on Turbo in BIOS
+    3. Turn off Hyper Threading
+
+Linux setting::
+
+    1. Use intel_pstate driver for CPU frequency control
+    2. modprobe msr
 
 sys_min=/sys/devices/system/cpu/cpu{}/cpufreq/cpuinfo_min_freq
 sys_max=/sys/devices/system/cpu/cpu{}/cpufreq/cpuinfo_max_freq
@@ -122,7 +128,7 @@ Step 1. Bind One NIC to DPDK driver, launch l3fwd-power with empty-poll enabled
 
 Step 2. Check the log also when changing the inject packet rate as following:
 
-    Injected Rate(64B, dst_ip=1.1.1.1): 10G -> 0.1G -> 10G -> 0.1G -> 10G ->
+    Injected Rate(1024B, dst_ip=1.1.1.1): 10G -> 0.1G -> 10G -> 0.1G -> 10G ->
     0.1G The frequency will be set to MED when we inject 0.1G and return to HGH
     when inject 10G Rate, check the frequency of the forwarding core(core 2)
     When traffic is 10G:  cur_min=cur_max=no_turbo_max
-- 
2.21.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [dts] [PATCH V1 2/2] tests/power_empty_poll: update test plan
  2020-04-20  1:20 ` [dts] [PATCH V1 2/2] tests/power_empty_poll: update test plan yufengmx
@ 2020-04-20  5:24   ` Tu, Lijuan
  0 siblings, 0 replies; 5+ messages in thread
From: Tu, Lijuan @ 2020-04-20  5:24 UTC (permalink / raw)
  To: Mo, YufengX, dts, Yao, Lei A; +Cc: Mo, YufengX

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 <lei.a.yao@intel.com>
> Cc: Mo, YufengX <yufengx.mo@intel.com>
> Subject: [dts] [PATCH V1 2/2] tests/power_empty_poll: update test plan
> 
> 
> #. add missing hyper threading setting.
> #. update traffic framesize usage.
> 
> Signed-off-by: yufengmx <yufengx.mo@intel.com>
> ---
>  test_plans/power_empty_poll_test_plan.rst | 16 +++++++++++-----
>  1 file changed, 11 insertions(+), 5 deletions(-)
> 
> diff --git a/test_plans/power_empty_poll_test_plan.rst
> b/test_plans/power_empty_poll_test_plan.rst
> index 61c698c..4472830 100644
> --- a/test_plans/power_empty_poll_test_plan.rst
> +++ b/test_plans/power_empty_poll_test_plan.rst
> @@ -101,10 +101,16 @@ state. If this is not supplied, the application will
> apply the default value of
> 
>  Preparation Work for Settings
>  =============================
> -1. Turn on Speedstep option in BIOS
> -2. Turn on Turbo in BIOS
> -3. Use intel_pstate driver for CPU frequency control -4. modprobe msr
> +BIOS setting::
> +
> +    1. Turn on Speedstep option in BIOS
> +    2. Turn on Turbo in BIOS
> +    3. Turn off Hyper Threading
> +
> +Linux setting::
> +
> +    1. Use intel_pstate driver for CPU frequency control
> +    2. modprobe msr
> 
>  sys_min=/sys/devices/system/cpu/cpu{}/cpufreq/cpuinfo_min_freq
>  sys_max=/sys/devices/system/cpu/cpu{}/cpufreq/cpuinfo_max_freq
> @@ -122,7 +128,7 @@ Step 1. Bind One NIC to DPDK driver, launch l3fwd-
> power with empty-poll enabled
> 
>  Step 2. Check the log also when changing the inject packet rate as following:
> 
> -    Injected Rate(64B, dst_ip=1.1.1.1): 10G -> 0.1G -> 10G -> 0.1G -> 10G ->
> +    Injected Rate(1024B, dst_ip=1.1.1.1): 10G -> 0.1G -> 10G -> 0.1G ->
> + 10G ->
>      0.1G The frequency will be set to MED when we inject 0.1G and return to
> HGH
>      when inject 10G Rate, check the frequency of the forwarding core(core 2)
>      When traffic is 10G:  cur_min=cur_max=no_turbo_max
> --
> 2.21.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [dts] [PATCH V1 1/2] tests/power_empty_poll: python3 support and script optimize
  2020-04-20  1:20 ` [dts] [PATCH V1 1/2] " yufengmx
@ 2020-04-21  5:51   ` Tu, Lijuan
  0 siblings, 0 replies; 5+ messages in thread
From: Tu, Lijuan @ 2020-04-21  5:51 UTC (permalink / raw)
  To: Mo, YufengX, dts, Yao, Lei A; +Cc: Mo, YufengX

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 <lei.a.yao@intel.com>
> Cc: Mo, YufengX <yufengx.mo@intel.com>
> Subject: [dts] [PATCH V1 1/2] tests/power_empty_poll: python3 support and
> script optimize
> 
> 
> #. python3 support.
> #. use pktgen new callback function to take the place of shell script query.
> #. 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.
> 
> Signed-off-by: yufengmx <yufengx.mo@intel.com>
> ---
>  tests/TestSuite_power_empty_poll.py | 258 ++++++++++++++++++----------
>  1 file changed, 172 insertions(+), 86 deletions(-)
> 
> 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 @@
> 
>  """
>  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
> 
>  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
> 
> 
> -class TestPowerEmptPoll(TestCase):
> +class TestPowerEmptyPoll(TestCase):
>      TRAIN = 'train'
>      NOTRAIN = 'no-train'
>      MED = 'med_threshold'
>      HIGH = 'high_threshold'
> -    query_min_freq = '/tmp/cpu_min.log'
> -    query_max_freq = '/tmp/cpu_max.log'
> -    output_path = '/tmp'
> 
>      @property
>      def target_dir(self):
> @@ -63,6 +61,12 @@ class TestPowerEmptPoll(TestCase):
>                       self.dut.base_dir
>          return target_dir
> 
> +    @property
> +    def is_use_trex(self):
> +        return (hasattr(self.tester, 'is_pktgen') and
> +                self.tester.is_pktgen and
> +                self.tester.pktgen.pktgen_type == PKTGEN_TREX)
> +
>      def d_con(self, cmd):
>          _cmd = [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)
> 
> -    def set_pktgen_stream(self, txport, rxport, send_pkts, option):
> +    def add_stream_to_pktgen(self, txport, rxport, send_pkts, option):
>          stream_ids = []
>          cnt = 0
>          for pkt in send_pkts:
> @@ -108,29 +112,36 @@ class TestPowerEmptPoll(TestCase):
>          rate_percent = option.get('rate', float(100))
>          duration = option.get('duration', 10)
>          send_pkts = self.set_stream(stm_type)
> +        # clear streams before add new streams
> +        self.tester.pktgen.clear_streams()
>          # set stream into pktgen
> -        option = {
> +        s_option = {
>              'stream_config': {
>                  'txmode': {},
>                  'transmit_mode': TRANSMIT_CONT,
>                  'rate': rate_percent, }
>          }
> -        stream_ids = self.set_pktgen_stream(txport, rxport, send_pkts, option)
> +        stream_ids = self.add_stream_to_pktgen(txport, rxport,
> + send_pkts, s_option)
>          # run traffic options
> -        traffic_opt = {
> -            'method': 'throughput',
> -            'duration': duration, }
> +        traffic_opt = option.get('traffic_opt')
>          # run pktgen(ixia/trex) traffic
>          result = self.tester.pktgen.measure(stream_ids, traffic_opt)
> 
>          return result
> 
> +    def get_pkt_len(self, pkt_type, frame_size):
> +        headers_size = sum([HEADER_SIZE[x] for x in ['eth', 'ip', pkt_type]])
> +        pktlen = frame_size - headers_size
> +        return pktlen
> +
>      def set_stream(self, stm_names=None):
>          # set streams for traffic
>          pkt_configs = {
>              '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=1024)}}},
>          }
>          # create packet instance for send
>          streams = []
> @@ -150,7 +161,7 @@ class TestPowerEmptPoll(TestCase):
>      @property
>      def empty_poll_options(self):
>          table = {
> -            'train': '1,0,0,',
> +            'train': '1,0,0',
>              'no-train': '0,350000,500000', }
>          return table
> 
> @@ -159,58 +170,60 @@ class TestPowerEmptPoll(TestCase):
> 
>      def start_l3fwd_power(self, core):
>          train_mode = self.empty_poll_options.get(self.train_mode)
> -        option = (' '
> +        option = ('-v '
>                    '-c {core_mask} '
>                    '-n {mem_channel} '
>                    '-- '
> -                  '-p 0x1 '
> +                  '-p 0x3 '
>                    '-P '
> -                  '--config="(0,0,2)" '
> -                  '-l 10 -m 6 -h 1'
> +                  '--config="(0,0,{core}),(1,0,{core})" '
> +                  '-l 10 -m 6 -h 1 '
>                    '--empty-poll="{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 = 'L3FWD_POWER: entering main loop on lcore'
> -        cmd = [' '.join([self.l3fwd_power, option]), prompt, 60]
> +        prompts = {
> +            self.NOTRAIN: 'POWER: Bring up the Timer',
> +            self.TRAIN: 'POWER: Training is Complete'}
> +        prompt = prompts.get(self.train_mode)
> +        cmd = [' '.join([self.l3fwd_power, option]), prompt, 120]
>          self.d_con(cmd)
> +        self.is_l3fwd_on = True
> 
>      def close_l3fwd_power(self):
> -        cmd = 'killall l3fwd-power'
> -        self.d_a_con(cmd)
> +        if not self.is_l3fwd_on:
> +            return
> +        cmd = "^C"
> +        self.d_con(cmd)
> 
> -    def init_query_script(self):
> -        script_content = 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_freq >>
> {0}
> -                cat /sys/devices/system/cpu/cpu$1/cpufreq/scaling_max_freq >>
> {1}
> -            done
> -        """).format(self.query_min_freq, self.query_max_freq)
> -        fileName = 'vm_power_core.sh'
> -        query_script = 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 = ';'.join([
> -            'cd {}'.format(self.target_dir),
> -            'chmod 777 {}'.format(fileName),
> -            './' + fileName])
> -
> -    def start_query(self, core):
> -        cmd = self.query_tool + ' {0} > /dev/null 2>&1 &'.format(core)
> -        self.d_a_con(cmd)
> +    def is_hyper_threading(self):
> +        cpu_index = list(self.cpu_info.keys())[-1]
> +        core_num = self.cpu_info[cpu_index].get('core')
> +        return (cpu_index + 1) / 2 == (core_num + 1)
> 
> -    def stop_query(self):
> -        cmd = 'pkill {}'.format(os.path.basename(self.query_tool))
> +    def is_support_pbf(self):
> +        # check if cpu support bpf feature
> +        cpu_attr = r'/sys/devices/system/cpu/cpu0/cpufreq/base_frequency'
> +        cmd = "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 = "echo $?"
> +        output = self.d_a_con(cmd)
> +        ret = True if output == "0" else False
> +        return ret
> +
> +    def query_cpu_freq(self):
> +        cmd = (
> +            "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 = self.d_a_con(cmd)
> +        if not output:
> +            self.scaling_min_freq, self.scaling_max_freq = 0, 0
> +        else:
> +            values = [int(item) for item in output.splitlines()]
> +            self.scaling_min_freq, self.scaling_max_freq = values
> 
>      def get_sys_power_driver(self):
>          drv_file = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_driver"
> @@ -221,8 +234,61 @@ class TestPowerEmptPoll(TestCase):
>          drv_name = output.splitlines()[0].strip()
>          return drv_name
> 
> -    def get_no_turbo_max(self):
> -        cmd = 'rdmsr -p 1 0x0CE -f 15:8 -d'
> +    def get_all_cpu_attrs(self):
> +        ''' get all cpus' base_frequency value '''
> +        key_values = ['base_frequency',
> +                      'cpuinfo_max_freq',
> +                      'cpuinfo_min_freq']
> +        freq = '/sys/devices/system/cpu/cpu{0}/cpufreq/{1}'.format
> +        # use dut alt session to get dut platform cpu base frequency attribute
> +        cpu_topos = self.dut.get_all_cores()
> +        cpu_info = {}
> +        for cpu_topo in cpu_topos:
> +            cpu_id = int(cpu_topo['thread'])
> +            cpu_info[cpu_id] = {}
> +            cpu_info[cpu_id]['socket'] = cpu_topo['socket']
> +            cpu_info[cpu_id]['core'] = cpu_topo['core']
> +
> +        for key_value in key_values:
> +            cmds = []
> +            for cpu_id in sorted(cpu_info.keys()):
> +                cmds.append('cat {0}'.format(freq(cpu_id, key_value)))
> +            output = self.d_a_con(';'.join(cmds))
> +            freqs = [int(item) for item in output.splitlines()] \
> +                if key_value != 'scaling_available_frequencies' else \
> +                    [item for item in output.splitlines()]
> +            for index, cpu_id in enumerate(sorted(cpu_info.keys())):
> +                if key_value == 'scaling_available_frequencies':
> +                    cpu_info[cpu_id][key_value] = \
> +                        [int(item) for item in sorted(freqs[index].split())]
> +                else:
> +                    cpu_info[cpu_id][key_value] = freqs[index]
> +
> +        # get high priority core and normal core
> +        base_freqs_info = {}
> +        for core_index, value in list(cpu_info.items()):
> +            base_frequency = value.get('base_frequency')
> +            base_freqs_info.setdefault(base_frequency, []).append(core_index)
> +        base_freqs = list(base_freqs_info.keys())
> +        # cpu should have high priority core and normal core
> +        # high priority core frequency is higher than normal core frequency
> +        if len(base_freqs) <= 1 or \
> +           not all([len(value) for value in list(base_freqs_info.values())]):
> +            msg = '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 = min(self.base_freqs_info.keys())
> +        cores_index = self.base_freqs_info[normal_freq][1:number] \
> +            if self.base_freqs_info[normal_freq][0] == 0 else \
> +            self.base_freqs_info[normal_freq][:number]
> +        return cores_index
> +
> +    def get_no_turbo_max(self, core):
> +        cmd = 'rdmsr -p {} 0x0CE -f 15:8 -d'.format(core)
>          output = self.d_a_con(cmd)
>          freq = 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=cur_max=no_turbo_max
>          '''
> -        self.stop_query()
> -        freq = self.get_no_turbo_max()
> -        expected_freq = str(freq if mode == self.HIGH else (freq - 500000))
> -        query_max_freq = os.path.join(
> -            self.output_path, os.path.basename(self.query_max_freq))
> -        with open(query_max_freq, 'rb') as fp:
> -            content = fp.read()
> -        msg = 'max freq are not the same as highest frequency <{0}>'
> -        self.verify(expected_freq in content, msg.format(expected_freq))
> -        query_min_freq = os.path.join(
> -            self.output_path, os.path.basename(self.query_min_freq))
> -        with open(query_min_freq, 'rb') as fp:
> -            content = fp.read()
> -        msg = 'min freq are not the same as highest frequency <{0}>'
> -        self.verify(expected_freq in content, msg.format(expected_freq))
> +        freq = self.get_no_turbo_max(core_index)
> +        expected_freq = freq if mode == self.HIGH else (freq - 500000)
> +        msg = 'max freq is failed to get.'
> +        self.verify(self.scaling_max_freq, msg)
> +        msg = 'max freq is not the same as highest frequency <{0}>'
> +        self.verify(expected_freq == self.scaling_max_freq,
> +                    msg.format(expected_freq))
> +        msg = 'min freq is failed to get.'
> +        self.verify(self.scaling_min_freq, msg)
> +        msg = 'min freq is not the same as highest frequency <{0}>'
> +        self.verify(expected_freq == self.scaling_min_freq,
> +                    msg.format(expected_freq))
>          msg = 'core <{0}>: max freq/min_freq/expected freq<{1}> are the same'
>          self.logger.info(msg.format(core_index, expected_freq))
> 
> @@ -255,6 +318,19 @@ class TestPowerEmptPoll(TestCase):
>          msg = 'training steps should not be executed'
>          self.verify('POWER: Training is Complete' not in output, msg)
> 
> +    @property
> +    def train_mode_check_item(self):
> +        # Injected Rate:
> +        #      10G -> 0.1G -> 10G -> 0.1G -> 10G -> 0.1G
> +        check_item = [
> +            [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 = None
>          # begin run vm power policy testing @@ -263,26 +339,22 @@ class
> TestPowerEmptPoll(TestCase):
>              if self.train_mode == self.NOTRAIN:
>                  self.check_no_train()
>              else:
> -                # Injected Rate(64B, dst_ip=1.1.1.1):
> -                #      10G -> 0.1G -> 10G -> 0.1G -> 10G -> 0.1G
> -                check_item = [
> -                    [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 = '{0} begin test mode <{1}> with traffic rate percent {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, rate))
> -                    self.start_query(self.check_core[1])
> +                    duration = 20 if self.is_use_trex else 10
>                      info = {
> +                        '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):
> 
>          # check verify result
>          if except_content:
> -            raise Exception(except_content)
> +            raise VerifyFailure(except_content)
>          else:
>              msg = "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 == expected_drv, msg)
> 
> +    def verify_hyper_threading(self):
> +        msg = "{} 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 = "dut cpu doesn't support priority base frequency feature"
> +        raise VerifyFailure(msg)
> +
>      def preset_test_environment(self):
> -        self.check_core = [1, 2]
> +        self.is_l3fwd_on = None
> +        self.cpu_info, self.base_freqs_info = self.get_all_cpu_attrs()
> +        self.check_core = 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 = self.dut.get_ports(self.nic)
>          self.verify(len(self.dut_ports) >= 2, "Not enough ports")
>          # prepare testing environment
> --
> 2.21.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2020-04-21  5:51 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-20  1:20 [dts] [PATCH V1 0/2] tests/power_empty_poll: python3 support and script optimize yufengmx
2020-04-20  1:20 ` [dts] [PATCH V1 1/2] " yufengmx
2020-04-21  5:51   ` Tu, Lijuan
2020-04-20  1:20 ` [dts] [PATCH V1 2/2] tests/power_empty_poll: update test plan yufengmx
2020-04-20  5:24   ` Tu, Lijuan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).