test suite reviews and discussions
 help / color / mirror / Atom feed
* [dts] [PATCH V1 0/3] vm_pw_mgmt_policy: upload test plan and automation script
@ 2018-06-06  5:35 yufengx.mo
  2018-06-06  5:35 ` [dts] [PATCH V1 1/3] vm_pw_mgmt_policy: upload test plan yufengx.mo
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: yufengx.mo @ 2018-06-06  5:35 UTC (permalink / raw)
  To: dts; +Cc: yufengmx

From: yufengmx <yufengx.mo@intel.com>

*. extend ixia to send continuous stream 
*. vm_pw_mgmt_policy test plan 
*. vm_pw_mgmt_policy automation script 

yufengmx (3):
  vm_pw_mgmt_policy: upload test plan
  vm_pw_mgmt_policy: upload automation script
  vm_pw_mgmt_policy: framework etgen/ixia

 conf/vm_pw_mgmt_policy.cfg                 |  39 ++
 framework/etgen.py                         | 184 +++++-
 framework/tester.py                        |  54 +-
 test_plans/vm_pw_mgmt_policy_test_plan.rst | 266 +++++++++
 tests/TestSuite_vm_pw_mgmt_policy.py       | 884 +++++++++++++++++++++++++++++
 5 files changed, 1421 insertions(+), 6 deletions(-)
 create mode 100644 conf/vm_pw_mgmt_policy.cfg
 mode change 100755 => 100644 framework/tester.py
 create mode 100644 test_plans/vm_pw_mgmt_policy_test_plan.rst
 create mode 100644 tests/TestSuite_vm_pw_mgmt_policy.py

-- 
1.9.3

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

* [dts] [PATCH V1 1/3] vm_pw_mgmt_policy: upload test plan
  2018-06-06  5:35 [dts] [PATCH V1 0/3] vm_pw_mgmt_policy: upload test plan and automation script yufengx.mo
@ 2018-06-06  5:35 ` yufengx.mo
  2018-06-06  5:35 ` [dts] [PATCH V1 2/3] vm_pw_mgmt_policy: upload automation script yufengx.mo
  2018-06-06  5:35 ` [dts] [PATCH V1 3/3] vm_pw_mgmt_policy: framework etgen/ixia yufengx.mo
  2 siblings, 0 replies; 4+ messages in thread
From: yufengx.mo @ 2018-06-06  5:35 UTC (permalink / raw)
  To: dts; +Cc: yufengmx

From: yufengmx <yufengx.mo@intel.com>


This test plan is for vm power mgmt policy feature.

The DPDK Power Management feature allows users space applications to save power
by dynamically adjusting CPU frequency or entering into different C-States.

*   Adjusting the CPU frequency dynamically according to the utilization of RX
    queue.

*   Entering into different deeper C-States according to the adaptive algorithms
    to speculate brief periods of time suspending the application if no packets
    are received.

This feauture are realized through example/vm_power_manager

Signed-off-by: yufengmx <yufengx.mo@intel.com>
---
 test_plans/vm_pw_mgmt_policy_test_plan.rst | 266 +++++++++++++++++++++++++++++
 1 file changed, 266 insertions(+)
 create mode 100644 test_plans/vm_pw_mgmt_policy_test_plan.rst

diff --git a/test_plans/vm_pw_mgmt_policy_test_plan.rst b/test_plans/vm_pw_mgmt_policy_test_plan.rst
new file mode 100644
index 0000000..627aad1
--- /dev/null
+++ b/test_plans/vm_pw_mgmt_policy_test_plan.rst
@@ -0,0 +1,266 @@
+.. Copyright (c) <2010-2018>, Intel Corporation
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+
+   - Neither the name of Intel Corporation nor the names of its
+     contributors may be used to endorse or promote products derived
+     from this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+   COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+   OF THE POSSIBILITY OF SUCH DAMAGE.
+
+========================================
+VM Power Management Tests (Policy/Turbo)
+========================================
+
+Inband Policy Control
+=====================
+
+a feature allows workload to deliver policy to the host to manage Power controls 
+such as p-states Extends the thinking of the current scheme moving away 
+from  direct controls to policy controls to avoid latency & jitter 
+penalities. Also provides the ability to react faster. 
+
+VM Power Manager would use a hint based mechanism by which a VM can
+communicate to a host based governor about its current processing
+requirements. By mapping VMs virtual CPUs to physical CPUs the Power Manager
+can then make decisions according to some policy as to what power state the
+physical CPUs can transition to.
+
+VM Agent shall have the ability to send the following policy to host:
+- traffic policy
+- timer policy
+- workload policy(no expose to user to run)
+
+turbo
+=====
+a new feature extend the library to enable 'per-core' turbo among other APIs.
+
+VM Power Manager would use a hint based mechanism by which a VM can
+communicate to a host based governor about its current processing
+requirements. By mapping VMs virtual CPUs to physical CPUs the Power Manager
+can then make decisions according to some policy as to what power state the
+physical CPUs can transition to.
+
+VM Agent shall have the ability to send the following hints to host:
+- core disable turbo
+- core enable turbo
+
+The power manager will manage the file handles for each core(<n>) below:
+
+- ``/dev/cpu/%d/msr``
+
+note: DPDK technical document refer to ``doc/guides/prog_guide/power_man.rst``
+
+Prerequisites
+=============
+*. Hardware:
+
+    - Platform: SuperMicro 1U Xeon D Broadwell SoC uServer
+    - NIC: i40e series('Ethernet Controller X710 for 10GbE SFP+ 1572')
+    - Per-core turbo is supported only on recent atchitectures. 
+        Haswell, Broadwell, Skylake, etc
+
+*. BIOS:
+
+    - Disable Intel(R) Hyper-Threading Tech
+    - Enable VT-d and VT-x
+    - Enable Enhanced Intel SpeedStep(R) Tech
+    - Enable Intel(R) Turbo Boost Technology
+    - Enable Processor C3
+    - Enable Processor C6
+
+*. OS and Kernel:
+
+    - Fedora 22
+    - Enable Kernel features Huge page, UIO, IOMMU, KVM
+
+    /boot/grub2/grub.cfg
+    - Enable Kernel features IOMMU
+        iommu=pt
+    - Enable Intel IOMMU
+        intel_iommu=on 
+    - Disable intel_pstate 
+        intel_pstate=disable
+
+*. Virtualization:
+
+    - QEMU emulator version >= 2.3.1
+    - libvirtd (libvirt) >= 1.2.13.2
+      libvirt configuration refer to 
+        dpdk/doc/guides/howto/pvp_reference_benchmark.rst ``Libvirt way`` chapter
+    - Add virio-serial port
+
+*. IXIA Traffic Generator Configuration LPM table used for packet routing is:
+
+        +---------+------------------------+----+
+        | Entry # | LPM prefix (IP/length) |    |
+        +---------+------------------------+----+
+        | 0       | 1.1.1.0/24             | P0 |
+        +---------+------------------------+----+
+        | 1       | 2.1.1.0/24             | P1 |
+        +---------+------------------------+----+
+
+
+    The flows should be configured and started by the traffic generator.
+
+        +------+---------+------------+---------+------+-------+--------+
+        | Flow | Traffic | IPv4       | IPv4    | Port | Port  | L4     |
+        |      | Gen.    | Src.       | Dst.    | Src. | Dest. | Proto. |
+        |      | Port    | Address    | Address |      |       |        |
+        +------+---------+------------+---------+------+-------+--------+
+        | 1    | TG0     | 0.0.0.0    | 2.1.1.0 | any  | any   | UDP    |
+        +------+---------+------------+---------+------+-------+--------+
+        | 2    | TG1     | 0.0.0.0    | 1.1.1.0 | any  | any   | UDP    |
+        +------+---------+------------+---------+------+-------+--------+
+
+
+Boot up vm using libvirt
+========================
+*. Configure VM XML to pin VCPUs/CPUs:
+
+   .. code-block:: xml
+
+        <vcpu placement='static'>5</vcpu>
+          <cputune>
+          <vcpupin vcpu='0' cpuset='1'/>
+          <vcpupin vcpu='1' cpuset='2'/>
+          <vcpupin vcpu='2' cpuset='3'/>
+          <vcpupin vcpu='3' cpuset='4'/>
+          <vcpupin vcpu='4' cpuset='5'/>
+        </cputune>
+
+*. Configure VM XML to set up virtio serial ports
+
+    Create temporary folder for vm_power socket.
+
+        mkdir /tmp/powermonitor
+
+    Setup one serial port for every one vcpu in VM.
+
+    .. code-block:: xml
+
+        <channel type='unix'>
+        <source mode='bind' path='/tmp/powermonitor/<vm_name>.<channel_num>'/>
+        <target type='virtio' name='virtio.serial.port.poweragent.<channel_num>'/>
+        <address type='virtio-serial' controller='0' bus='0' port='4'/>
+        </channel>
+
+*. Run power-manager in Host:
+        ./build/vm_power_mgr -c 0x3 -n 4
+
+*. Startup VM and run guest_vm_power_mgr:
+        guest_vm_power_mgr -c 0x1f -n 4 -- -i
+
+*. Add vm in host and check vm_power_mgr can get frequency normally:
+        vmpower> add_vm <vm_name>
+        vmpower> add_channels <vm_name> all
+
+
+Test Case : time policy
+=======================
+*. when clock is turn to 03:00 04:00 05:00, put vcore to max freq
+*. when clock is turn to 11:00 12:00 13:00, put vcore to min freq
+
+step:
+*. Connect two physical ports to IXIA
+
+*. set up testing environment refer to ``Boot up vm using libvirt``
+
+*. set DUT system time to desired time
+
+*. activate policy on vm DUT
+    vmpower(guest)> send_policy now
+
+*. Check DUT platform core frequency
+
+Test Case : traffic policy
+==========================
+*. use pkt generator to send a stream with a rate bigger 2000000, 
+   vcpus' frequence will runn at max frequence
+*. use pkt generator to send a stream with a rate between 2000000~1800000, 
+   vcpus' frequence will run at med frequence
+*. use pkt generator to send a stream with a rate less than 1800000, 
+   vcpus' frequence will run at min frequence
+
+steps:
+*. Connect two physical ports to IXIA
+
+*. set up testing environment refer to ``Boot up vm using libvirt``
+
+*. Configure packet flow in IxiaNetwork, set ixia to send desired bit rate stream
+
+*. activate policy on vm DUT
+    vmpower(guest)> send_policy now
+
+*. Check DUT platform core frequency
+
+Test Case : VM disable CPU turbo
+================================
+check a custom cpu turbo status can be disable
+
+steps:
+*. bind two ports
+
+    ./usertools/dpdk-devbind.py --bind=igb_uio <pci address 1> <pci address 2>
+
+*. set up testing environment refer to ``Boot up vm using libvirt``
+
+*. set cpu turbo disable on vm DUT
+
+    vmpower(guest)> set_cpu_freq <core_num> disable_turbo
+
+*. Verify the DUT physical CPU's turbo has been disable correctly, using linux
+   tool ``cpupower`` to query
+
+    cpupower -c <cpu core> frequency-info
+
+    boost state support:
+      Supported: yes
+      Active: no
+
+Test Case : VM enable CPU turbo
+===============================
+check a custom cpu turbo status can be enable
+
+steps:
+*. bind two ports
+
+    ./usertools/dpdk-devbind.py --bind=igb_uio <pci address 1> <pci address 2>
+
+*. set up testing environment refer to ``Boot up vm using libvirt`` steps
+
+*. set cpu turbo disable on vm DUT
+
+    vmpower(guest)> set_cpu_freq <vm_core_num> enable_turbo
+
+*. Verify the DUT physical CPU's turbo has been disable correctly, using linux
+   tool ``cpupower`` to query
+
+    cpupower -c <cpu core> frequency-info
+
+    boost state support:
+      Supported: yes
+      Active: yes
+
-- 
1.9.3

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

* [dts] [PATCH V1 2/3] vm_pw_mgmt_policy: upload automation script
  2018-06-06  5:35 [dts] [PATCH V1 0/3] vm_pw_mgmt_policy: upload test plan and automation script yufengx.mo
  2018-06-06  5:35 ` [dts] [PATCH V1 1/3] vm_pw_mgmt_policy: upload test plan yufengx.mo
@ 2018-06-06  5:35 ` yufengx.mo
  2018-06-06  5:35 ` [dts] [PATCH V1 3/3] vm_pw_mgmt_policy: framework etgen/ixia yufengx.mo
  2 siblings, 0 replies; 4+ messages in thread
From: yufengx.mo @ 2018-06-06  5:35 UTC (permalink / raw)
  To: dts; +Cc: yufengmx

From: yufengmx <yufengx.mo@intel.com>


This automation script is is for vm power mgmt policy feature.

The DPDK Power Management feature allows users space applications to save power
by dynamically adjusting CPU frequency or entering into different C-States.

*   Adjusting the CPU frequency dynamically according to the utilization of RX
    queue.

*   Entering into different deeper C-States according to the adaptive algorithms
    to speculate brief periods of time suspending the application if no packets
    are received.

This feauture are realized through example/vm_power_manager

Signed-off-by: yufengmx <yufengx.mo@intel.com>
---
 tests/TestSuite_vm_pw_mgmt_policy.py | 884 +++++++++++++++++++++++++++++++++++
 1 file changed, 884 insertions(+)
 create mode 100644 tests/TestSuite_vm_pw_mgmt_policy.py

diff --git a/tests/TestSuite_vm_pw_mgmt_policy.py b/tests/TestSuite_vm_pw_mgmt_policy.py
new file mode 100644
index 0000000..7cfd9ec
--- /dev/null
+++ b/tests/TestSuite_vm_pw_mgmt_policy.py
@@ -0,0 +1,884 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2018 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#   * Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+#   * Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in
+#     the documentation and/or other materials provided with the
+#     distribution.
+#   * Neither the name of Intel Corporation nor the names of its
+#     contributors may be used to endorse or promote products derived
+#     from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""
+DPDK Test suite.
+VM power manager test suite.
+"""
+import os
+import re
+import utils
+import time
+import random
+from datetime import datetime, timedelta
+
+# for deubg
+from functools import wraps
+from pprint import pformat, pprint
+import inspect
+import traceback
+
+from serializer import Serializer
+from test_case import TestCase
+from settings import HEADER_SIZE
+from qemu_libvirt import LibvirtKvm
+from exception import TimeoutException, VerifyFailure
+
+from packet import Packet, NVGRE, IPPROTO_NVGRE
+from scapy.sendrecv import sendp
+from scapy.utils import wrpcap, rdpcap, hexstr
+
+class TestVmPwMgmtPolicy(TestCase):
+
+    #---------------------------------------------------------
+    # execute ssh session command 
+    #---------------------------------------------------------
+    def d_console(self, cmds):
+        return self.execute_cmds(cmds, con_name='dut')
+
+    def d_a_console(self, cmds):
+        return self.execute_cmds(cmds, con_name='dut_alt')
+
+    def t_console(self, cmds):
+        return self.execute_cmds(cmds, con_name='tester')
+
+    def vm_console(self, cmds):
+        return self.execute_cmds(cmds, con_name='vm_dut')
+
+    def get_console(self, name):
+        if name == 'tester':
+            console = self.tester.send_expect
+            msg_pipe = self.tester.get_session_output
+        elif name == 'dut':
+            console = self.dut.send_expect
+            msg_pipe = self.dut.get_session_output
+        elif name == 'dut_alt':
+            console = self.dut.alt_session.send_expect
+            msg_pipe = self.dut.alt_session.session.get_output_all
+        elif name == 'vm_dut':
+            console = self.vm_dut.send_expect
+            msg_pipe = self.vm_dut.get_session_output
+        return console, msg_pipe
+
+    def execute_cmds(self, cmds, con_name='dut'):
+        console, msg_pipe = self.get_console(con_name)
+        if len(cmds) == 0:
+            return
+        if not isinstance(cmds[0], list):
+            cmds = [cmds]
+        if len(cmds) > 1:
+            outputs = []
+        else:
+            outputs = ''
+        for item in cmds:
+            expected_items = item[1]
+            if expected_items and isinstance(expected_items, (list, tuple)):
+                check_output = True
+                expected_str = expected_items[0] or '# '
+            else:
+                check_output = False
+                expected_str = expected_items or '# '
+
+            try:
+                if len(item) == 3:
+                    timeout = int(item[2])
+                    output = console(item[0], expected_str, timeout)
+                    output = msg_pipe(timeout) if not output else output
+                else:
+                    output = console(item[0], expected_str)
+                    output = msg_pipe() if not output else output
+            except TimeoutException:
+                #self.check_process_status()
+                msg = "execute '{0}' timeout".format(item[0])
+                raise TimeoutException(msg)
+            finally:
+                pass
+            # when execute "port start", LSC event will cause next command 
+            # execution fail. So wait 10s here
+            time.sleep(1)
+            if len(cmds) > 1:
+                outputs.append(output)
+            else:
+                outputs = output
+            if check_output and len(expected_items) >= 2:
+                self.logger.info(output)
+                expected_output = expected_items[1]
+                check_type = True if len(expected_items) == 2 \
+                                  else expected_items[2]
+                if check_type and expected_output in output:
+                    msg = "expected '{0}' is in output".format(expected_output)
+                    self.logger.info(msg)
+                elif not check_type and expected_output not in output:
+                    msg = "unexpected '{0}' is not in output".format(
+                                                            expected_output)
+                    self.logger.info(msg)
+                else:
+                    status = "isn't in" if check_type else "is in"
+                    msg = "[{0}] {1} output".format(expected_output, status)
+                    self.logger.error(msg)
+                    raise VerifyFailure(msg)
+
+        time.sleep(2)
+        return outputs
+
+    def get_host_reponse(self):
+        output = self.dut.get_session_output(timeout=2)
+        return output
+
+    def get_guest_reponse(self):
+        output = self.vm_dut.get_session_output(timeout=2)
+        return output
+
+    #---------------------------------------------------------
+    # traffic method of ixia/scapy or others
+    #---------------------------------------------------------
+    def get_pkt_len(self, pkt_type):
+        # packet size
+        frame_size = 64
+        headers_size = sum(map(lambda x: HEADER_SIZE[x],
+                               ['eth', 'ip', pkt_type]))
+        pktlen = frame_size - headers_size
+        return pktlen
+
+    def set_stream(self, stm_names=None):
+        dmac = self.dut.get_mac_address(self.dut_ports[0])
+        #----------------------------------------------------------------------
+        # set streams for traffic
+        pkt_configs = {
+            'UDP_1': {
+            'type': 'UDP',
+            'pkt_layers': {
+                #'ether': {'src': srcmac, 'dst': nutmac},
+                'ipv4': {'src': '0.0.0.0', 'dst': '2.1.1.0'},
+                'udp': {'src': 32, 'dst': 33},
+                'ether': {'dst': dmac},
+                'raw': {'payload': ['58'] * self.get_pkt_len('udp')}}},
+            'UDP_2': {
+            'type': 'UDP',
+            'pkt_layers': {
+                #'ether': {'src': srcmac, 'dst': nutmac},
+                'ipv4': {'src': '0.0.0.0', 'dst': '1.1.1.0'},
+                'udp': {'src': 32, 'dst': 33},
+                'ether': {'dst': dmac},
+                'raw': {'payload': ['58'] * self.get_pkt_len('udp')}}}
+        }
+
+        # create packet for send
+        streams = []
+        for stm_name in stm_names:
+            if stm_name not in pkt_configs.keys():
+                continue
+            values = pkt_configs[stm_name]
+            savePath = os.sep.join([self.target_source,
+                                    "pkt_{0}.pcap".format(stm_name)])
+            pkt_type = values.get('type')
+            pkt_layers = values.get('pkt_layers')
+            pkt = Packet(pkt_type=pkt_type)
+            for layer in pkt_layers.keys():
+                pkt.config_layer(layer, pkt_layers[layer])
+            pkt.pktgen.write_pcap(savePath)
+            streams.append(pkt.pktgen.pkt)
+
+        return streams
+
+    def get_rate_percent(self, expect_pps):
+        frame_size = 64
+        full_pps = self.wirespeed(self.nic, frame_size, 1) * 1000000.0
+        rate_percent = round((100*float(expect_pps)/float(full_pps)), 2)
+        return rate_percent
+
+    def send_packets_by_ixia(self, **kwargs):
+        tester_port = kwargs.get('tx_intf')
+        count = kwargs.get('count', 1)
+        traffic_type = kwargs.get('traffic_type', 'normal')
+        rate_percent = kwargs.get('rate_percent', float(100))
+        expected_pps = kwargs.get('pps', 0)
+        traffic_time = kwargs.get('traffic_time', 0)
+        rate_percent = self.get_rate_percent(expected_pps)
+        msg = "expected_pps is {0}, rate percent is {1}".format(
+                                                        expected_pps,
+                                                        rate_percent)
+        self.logger.info(msg)
+        #---------------------------------------------------------------
+        self.tgen_input = []
+        tgen_input = self.tgen_input
+        send_pkts = kwargs.get('stream') or []
+        pcap = self.target_source + os.sep + 'ixia.pcap'
+        wrpcap(pcap, send_pkts)
+        #----------------------------------------------------------------
+        tgen_input.append((tester_port, 
+                           tester_port, 
+                           pcap))
+        # run latency stat statistics
+        self.rate_percent = rate_percent
+        self.pktgen_status = 'running'
+        #if traffic_type == 'burst':
+        stream_configs = kwargs.get('stream configs', None)
+        if not stream_configs:
+            raise VerifyFailure("no stream configs set")
+        traffic = self.tester.loop_traffic_generator_throughput
+        #rx_bps, rx_pps = 
+        traffic(tgen_input, rate_percent)
+        # move stop method in packet thread
+        if traffic_time:
+            time.sleep(traffic_time)
+
+        return True
+
+    def stop_ixia(self, data_types='packets'):
+        cur_data = {}
+        cur_data['ixia statistics'] = []
+        append = cur_data['ixia statistics'].append
+        # get ixia statistics
+        if self.pktgen_status != 'running':
+            return cur_data
+        try:
+            line_rate = self.tester.get_port_line_rate()
+            stop_traffic = self.tester.stop_traffic_generator_throughput_loop
+            rx_bps, rx_pps = stop_traffic(self.tgen_input)
+            output = self.tester.traffic_get_port_stats(self.tgen_input)
+            append('send packets: {0}'.format(output[0]))
+            append('line_rate: {0}'.format(line_rate[0]))
+            append('rate_percent: {0}%'.format(self.rate_percent))
+        except Exception as e:
+            msg = traceback.format_exc()
+            self.logger.error(msg)
+        finally:
+            self.pktgen_status = 'stop'
+        return cur_data
+
+    def get_time_unit(self, unit):
+        #
+        unit = unit or 'gapSeconds'
+        time_unit = {'gapNanoSeconds': 1/10e8,
+                     'gapMicroSeconds': 1/10e5,
+                     'gapMilliSeconds': 1/10e2,
+                     'gapSeconds': 1,}
+        return time_unit[unit]
+
+    def send_packets_by_scapy(self, **kwargs):
+        tester_port = kwargs.get('tx_intf')
+        send_pkts = kwargs.get('stream') or []
+        stream_configs = kwargs.get('stream configs', None)
+        rate_limit = kwargs.get('traffic_type') or 0
+        if not stream_configs:
+            raise VerifyFailure("no stream configs set")
+        count = stream_configs.get('count') or 1
+        frameConfigs = stream_configs.get('frameType') or None
+        if rate_limit:
+            interval = 1/count
+        else:
+            interval = 0.01
+        #---------------------------------------------------------------
+        self.pktgen_status = 'running'
+        self.logger.info("begin transmission ...")
+        sendp(send_pkts, iface=tester_port, count=count, 
+              inter=interval, verbose=False)
+        self.logger.info("complete transmission")
+        self.pktgen_status = 'stop'
+
+    def traffic(self, ports_topo):
+        """
+        stream transmission on specified link topology
+        """
+        time.sleep(2)
+        if self.pktgen_name == 'ixia':
+            result = self.send_packets_by_ixia(**ports_topo)
+        elif self.pktgen_name == 'scapy':
+            result = self.send_packets_by_scapy(**ports_topo)
+        else:
+            self.logger.error("set wrong pkt generator")
+            return
+
+        # end traffic
+        self.logger.info("complete transmission")
+
+        return result
+
+    def run_traffic(self, **kwargs):
+        #-----------------------------------------
+        # set traffic topology
+        # for lack ixia port, one of ixia port use normal link peer 
+        # so there set a hard code for temporarily usage
+        port = 0
+        tester_port_id = self.tester.get_local_port(self.dut_ports[port])
+        stm_type = kwargs.get('stm_types')
+        packets = kwargs.get('packets')
+        if self.pktgen_name == 'ixia':
+            expected_pps = kwargs.get('pps')
+            traffic_time = kwargs.get('traffic_time', None) or 30
+            tx_port = tester_port_id
+            ports_topo = {'tx_intf': tx_port,
+                          'rx_intf': 0,
+                          'stream': self.set_stream(stm_type),
+                          'stream configs': {
+                                'count': packets,
+                                'frameType': {
+                                    # gapNanoSeconds gapMilliSeconds gapSeconds
+                                    'gapUnit': 'gapMilliSeconds'},
+                                'stream_type': 'burst'
+                                },
+                          # send bursts of 32 packets
+                          'traffic_type': 'normal',
+                          'pps': expected_pps,
+                          # 0 means stop after one round traffic
+                          # xx value means stop after traffic_time time
+                          'traffic_time': traffic_time,}
+        else:
+            tx_port = self.tester.get_interface(tester_port_id)
+            ports_topo = {'tx_intf': tx_port,
+                          'rx_intf': 0,
+                          'stream': self.set_stream(stm_type),
+                          'stream configs': {
+                                'count': packets
+                                },
+                          'traffic_type': 'rate_limit',
+                          }
+
+        # begin traffic checking
+        result = self.traffic(ports_topo)
+
+        return result
+    
+    @property
+    def is_perf(self):
+        return self._enable_perf
+
+    def set_up_all(self):
+        """
+        Run at the start of each test suite.
+        """
+        self.skip_compile = self.dut.skip_setup
+        self.dut_ports = self.dut.get_ports(self.nic)
+        self.verify(len(self.dut_ports) >= 2,
+                    "Not enough ports for " + self.nic)
+        self.target_source = self.dut.base_dir
+        self.debug = self._enable_debug
+        # rename hard code of vm name in dpdk code
+        self.replace_vm_name()
+        # boot up vm
+        self.vm = None
+        self.vm_dut = None
+        self.set_up_vm()
+
+        #------------------------------------------------------------------
+        # initialize ixia session
+        self.pktgen_status = 'stop'
+        #------------------------------------------------------------------
+        # initialize packet generator
+        self.pktgen_name = 'ixia' if self.is_perf else 'scapy'
+
+    def set_up(self):
+        """
+        Run before each test case.
+        """
+        pass
+
+    def tear_down(self):
+        """
+        Run after each test case.
+        """
+        if self.vm_dut:
+            self.vm_dut.send_expect("quit", "# ")
+        pass
+
+    def tear_down_all(self):
+        """
+        Run after each test suite.
+        """
+        self.dut.send_expect("quit", "# ")
+        if self.vm:
+            self.vm.stop()
+        self.dut.virt_exit()
+        pass
+
+    def replace_vm_name(self):
+        '''
+        till 18.02 rc0, developer use hard code to set vm name.
+        '''
+        console = self.d_a_console
+        old_word = "ubuntu2"
+        new_word = "vm0"
+        sed_file = os.sep.join([self.target_source, 
+                   "examples/vm_power_manager/guest_cli/vm_power_cli_guest.c"])
+        cmds = [["sed -i -e 's/{0}/{1}/' {2}".format(old_word, new_word,
+                                                    sed_file), "# "]]
+        console(cmds)
+
+    def set_up_vm(self):
+        # map between host vcpu and guest vcpu
+        try:
+            self.vcpu_map = []
+            # start vm
+            self.vm_name = "vm0"
+            self.vm = LibvirtKvm(self.dut, self.vm_name, self.suite_name)
+            base_path = '/tmp/powermonitor'
+            #-----------------------
+            # create temporary folder for power monitor
+            cmd = "mkdir -p {0}".format(base_path)
+            self.dut.send_expect(cmd, "# ")
+            cmd = "chmod 777 {0}".format(base_path)
+            self.dut.send_expect(cmd, "# ")
+            #-----------------------
+            ch_name = 'virtio.serial.port.poweragent.{0}'
+            vm_path = base_path + os.sep + '{0}.{1}'
+            channels = []
+            max_ch = 4
+            for cnt in range(max_ch):
+                channel = {
+                        'path': vm_path.format(self.vm_name, cnt), 
+                        'name': ch_name.format(cnt)}
+                self.vm.add_vm_virtio_serial_channel(**channel)
+            # boot up vm
+            self.vm_dut = self.vm.start()
+            if not self.vm_dut:
+                raise VerifyFailure("create vm_dut fail !")
+
+            # ping cpus
+            cpus = self.vm.get_vm_cpu()
+            self.vcpu_map = cpus[:]
+            self.core_num = len(cpus)
+            # build guest cli
+            if not self.skip_compile:
+                out = self.vm_dut.build_dpdk_apps(
+                    "examples/vm_power_manager/guest_cli")
+                self.verify("Error" not in out, "Compilation error")
+                self.verify("No such" not in out, "Compilation error")
+
+            # compile vm power manager
+            if not self.skip_compile:
+                out = self.dut.build_dpdk_apps("./examples/vm_power_manager")
+                self.verify("Error" not in out, "Compilation error")
+                self.verify("No such" not in out, "Compilation error")
+            bin_dir = os.sep.join([self.target_source, 
+                                   "examples/vm_power_manager"])
+            cmd = "guest_cli/build/guest_vm_power_mgr -c 0xf -n 4 -- -i"
+            self.guest_cli = os.sep.join([bin_dir, cmd])
+            #----------------------------------------------------------------
+            try:
+                cmd = "build/vm_power_mgr -c 0x3 -n 4"
+                self.mgr = os.sep.join([bin_dir, cmd])
+                self.dut.send_expect(self.mgr, "vmpower>", )
+                cmds = [[self.mgr, 'vmpower>', 120],
+                        ["add_vm %s" % self.vm_name, 'vmpower>'],
+                        ["add_channels %s all" % self.vm_name, 'vmpower>'],
+                        ["show_vm %s" % self.vm_name, 'vmpower>']]
+                pprint(cmds)
+                self.d_console(cmds)
+            except Exception as e:
+                pass
+            finally:
+                pass
+        except Exception as e:
+            msg = traceback.format_exc()
+            self.logger.error(msg)
+        finally:
+            pass
+
+    def set_cpu_full_load(self, cpu_id):
+        cmd = "taskset -c {0} dd if=/dev/zero of=/dev/null".format(cpu_id)
+
+    def check_guest_cli(self):
+        process_name = 'guest_vm_power_mgr'
+        cmd = "ps aux | grep -i %s | grep -v grep | awk {'print $2'}"%(
+                                                                process_name)
+        out = self.vm_dut.send_expect(cmd, "# ", 10)
+        if out != "":
+            process_pid = out.splitlines()[0]
+            cmd = 'kill -9 {0}'.format(process_pid)
+            self.vm_dut.send_expect(cmd, ">", 10)
+
+    def convert_to_values(self, output):
+        pdata_s = "^\d+$"
+        ret = re.match(pdata_s, output)
+        if ret:
+            return int(output)
+        pdata_m = "(\d+ )+" 
+        ret = re.match(pdata_m, output)
+        if ret:
+            return [int(item) for item in output.split()]
+        pdata_m = "^\w+$"
+        ret = re.match(pdata_m, output)
+        if ret:
+            return output
+        pdata_m = "(\w+ )+"
+        ret = re.match(pdata_m, output)
+        if ret:
+            return [item for item in output.split()]
+
+    def linux_get_cpu_attrs(self, core_num, name="cpuinfo_cur_freq"):
+        fmt = "/sys/devices/system/cpu/cpu{0}/cpufreq/{1}"
+        freq_path = fmt.format(core_num, name)
+        console = self.d_a_console
+        console(["ll %s"%freq_path, "# "])
+        if console(["echo $?", "# "]) != "0":
+            msg = "cpu attribute <{0}> isn't existed".format(name)
+            raise VerifyFailure(msg)
+            return
+        output = console(["cat %s"%freq_path, "# "])
+        return self.convert_to_values(output)
+
+    def linux_set_core_freq(self, core_num, attr, value):
+        fmt = "/sys/devices/system/cpu/cpu{0}/cpufreq/{1}"
+        freq_path = fmt.format(core_num, attr)
+        console = self.d_a_console
+        console(["echo {0} > {1}".format(value ,freq_path), "# "])
+        if console(["echo $?", "# "]) != "0":
+            msg = "cpu attribute <{0}> isn't existed".format(name)
+            raise VerifyFailure(msg)
+
+    def linux_preset_core_freq(self, core_num, value):
+        attr = 'scaling_setspeed'
+        self.linux_set_core_freq(core_num, attr, value)
+        cur_value = self.get_cur_freq(core_num)
+        if value != cur_value:
+            msg = "failed to set core {0} to {1}".format(core_num, value)
+            self.logger.error(msg)
+
+    def get_cur_freq(self, core_num):
+        name = 'cpuinfo_cur_freq'
+        freq = self.linux_get_cpu_attrs(core_num, name)
+        return freq
+
+    def get_preset_freq(self, available_freqs, check_reqs):
+        # set cores to one frequency not in min/max/medium frequency
+        # if available frequencys are not enough, use core's default frequency
+        available = set(available_freqs)
+        check = set(check_reqs)
+        for_use = list(available.difference(check))
+        index = random.randint(0, len(for_use)-1)
+        _freq = for_use[index]
+        return _freq
+
+    def preset_policy_freqs(self):
+        freqs = { 'max': 'scaling_max_freq',
+                  'medium': 'scaling_available_frequencies',
+                  'min': 'scaling_min_freq'}
+        freqs_for_check = {}
+        # note: till 17.11 rc4, developer only realize policy on first two core
+        # using hard code.
+        for vcpu in range(len(self.vcpu_map[:2])):
+            core_num = int(self.vcpu_map[vcpu])
+            freqs_for_check[core_num] = {}
+            sub_core_freq = freqs_for_check[core_num]
+            for name, attr in freqs.iteritems():
+                value = self.linux_get_cpu_attrs(core_num, attr)
+                if name == 'medium':
+                    available_freqs = sorted(value)
+                    index = len(value)/2
+                    sub_core_freq[name] = available_freqs[index]
+                else:
+                    sub_core_freq[name] = value
+            set_freq = self.get_preset_freq(available_freqs, 
+                                            sub_core_freq.values())
+            self.linux_preset_core_freq(core_num, set_freq)
+        return freqs_for_check
+
+    def get_vm_turbo_status(self, core_num):
+        pass
+
+    def save_system_time(self):
+        self.bak_sys_time = datetime.now()
+        msg = "system original time is {0}".format(self.bak_sys_time)
+        self.logger.info(msg)
+
+    def restore_system_time(self, interval):
+        console = self.d_a_console
+        timestamp = self.bak_sys_time + timedelta(seconds=interval)
+        FMT = '%Y-%m-%d %H:%M:%S'
+        date_tool = "date"
+        clock_cmd = "clock -w"
+        real_time = timestamp.strftime(FMT)
+        cmds = [[date_tool, '', 5],
+                ["{0} -s '{1}' &".format(date_tool, real_time), '', 20],
+                [clock_cmd, '', 5],
+                [date_tool, '', 5]]
+        console(cmds)
+
+    def set_desired_time(self, timestamp):
+        console = self.d_a_console
+        date_tool = "date"
+        clock_cmd = "clock -w"
+        cmds = [[date_tool, '', 5],
+                ["{0} -s '{1}' &".format(date_tool, timestamp), '', 20],
+                [clock_cmd, '', 5]]
+        console(cmds)
+        cmds = ["{0} '+%H:00'".format(date_tool), '', 5]
+        output = console(cmds)
+        if output.strip() != timestamp:
+            msg = "desired time fails to set"
+        else:
+            msg = "desired time set successful"
+        self.logger.info(msg)
+
+    def set_vm_turbo_status(self, vcpu, status):
+        output = self.vm_dut.send_expect(
+                    "set_cpu_freq %d %s" % (vcpu, status), 
+                    "vmpower\(guest\)>", 120)
+        vm_status = self.get_vm_turbo_status(vcpu)
+
+    def start_guest_mgr(self):
+        self.check_guest_cli()
+        guest_cmd = self.guest_cli
+        out = self.vm_dut.send_expect(guest_cmd, "vmpower\(guest\)>", 120)
+
+    def guest_console(self, cmd):
+        out = self.vm_dut.send_expect(cmd, "# ", 120)
+        self.get_guest_reponse()
+
+    def close_guest_mgr(self):
+        self.vm_dut.send_expect("quit", "# ")
+
+    def set_single_core_turbo(self, vcpu, status):
+        '''
+        status: enable_turbo | disable_turbo
+        '''
+        dut_core_num = self.vcpu_map[vcpu]
+        self.set_vm_turbo_status(vcpu, status)
+        dut_cpupower_cmd = "cpupower -c {0} frequency-info | grep Active"
+        out = self.dut.alt_session.send_expect(
+                        dut_cpupower_cmd.format(dut_core_num), "# ")
+        dut_status = out.split(': ')[1]
+        self.get_host_reponse()
+        return dut_status, dut_core_num
+
+    def check_single_core_turbo_enable(self, vcpu):
+        dut_status, dut_core_num = self.set_single_core_turbo(vcpu, 
+                                                              'enable_turbo')
+        if dut_status.lower() != 'yes': 
+              msg = "core <{0}> turbo status not correct".format(dut_core_num)
+              raise VerifyFailure(msg)
+        self.logger.info( 
+            "core <{0}> turbo status set successful".format(dut_core_num))
+        return True
+
+    def check_single_core_turbo_disable(self, vcpu):
+        dut_status, dut_core_num = self.set_single_core_turbo(vcpu, 
+                                                              'disable_turbo')
+        if dut_status.lower() != 'no':
+            msg = "core <{0}> turbo status not correct".format(dut_core_num)
+            raise VerifyFailure(msg)
+        self.logger.info( 
+            "core <{0}> turbo status clear successful".format(dut_core_num))
+        return True
+
+    def check_turbo_by_core_mask(self, option):
+        self.logger.error("set frequency by core mask is not supported now")
+        return True
+
+    def run_test_pre(self):
+        ref_freqs = self.preset_policy_freqs()
+        #------------------------------------
+        # prepare testing environment
+        #self.result_table_create(latency_header)
+        # note: till 17.11 rc4, developer only realize 'TIME' policy 
+        # using hard code
+        self.start_guest_mgr()
+        #----------------------------
+        # set work load for vm power testing
+        policy = 'now'
+        cmd = "send_policy {0}".format(policy)
+        self.logger.info("get_host_reponse before send policy")
+        self.get_host_reponse()
+        output = self.vm_dut.send_expect(cmd, "vmpower\(guest\)>")
+        self.logger.info("get_host_reponse before traffic")
+        self.get_host_reponse()
+        self.logger.info("get_guest_reponse before traffic")
+        self.get_guest_reponse()
+        return ref_freqs
+
+    def run_test_post(self):
+        pass
+
+    def check_cpus_status(self, check_item, ref_freqs):
+        erro_logs = [] 
+        msg = "check content {0}".format(check_item)
+        self.logger.info(msg)
+        for core_num, value in ref_freqs.iteritems():
+            ref_req = value[check_item]
+            
+            freq = self.get_cur_freq(core_num)
+            msg = "core {0} expected freq is {1}" + \
+                  "  current freq is {2}"
+            log = msg.format(core_num, ref_req, freq)
+            if ref_req != freq:
+                self.logger.error(log)
+                erro_logs.append(log)
+            else:
+                self.logger.info(log)
+
+        if erro_logs:
+            raise VerifyFailure("cpu freqency is wrong")
+
+    def run_policy(self, name, content):
+        """
+        Measure cpu frequency fluctuate with work load
+        """
+        try:
+            ref_freqs = self.run_test_pre()
+            #------------------
+            # run traffic
+            if name == 'TRAFFIC':
+                expected_pps = content['pps']
+                if isinstance(expected_pps, list):
+                    test_pps = random.randint(expected_pps[0],
+                                              expected_pps[1]-1)
+                else:
+                    test_pps = expected_pps
+                msg = "set pps {0}".format(test_pps)
+                self.logger.info(msg)
+                info = {}
+                # note: till 17.11 rc4, developer using NO.0 binded port to 
+                # send policy pkts by default
+                info['stm_types'] = ['UDP_1']
+                info['packets'] = 25
+                info['pps'] = expected_pps
+                # run traffic
+                self.run_traffic(**info)
+                self.logger.info("get_host_reponse after traffic")
+                self.get_host_reponse()
+                self.logger.info("get_guest_reponse after traffic")
+                self.get_guest_reponse()
+                check_flg = True
+            time.sleep(10)
+            # check cpu core status
+            check_item = content['check']
+            self.check_cpus_status(check_item, ref_freqs)
+        except Exception as e:
+            pass
+        finally:
+            pass
+
+        if self.pktgen_name == "ixia" and name == 'TRAFFIC':
+            result = self.stop_ixia()
+        #------------------------------------
+        # clear testing environment
+        self.close_guest_mgr()
+
+    def get_policy_test_content(self, name):
+        # note: till 17.11 rc4, developer only use hard code to expose   
+        # 'TIME/TRAFFIC' policy to user to run testing
+        policys = {'TRAFFIC': [
+                        {"time stage": ['08:00', '10:00'],
+                         "pps":  97000,#[96000, 1800000], 
+                         "check": "min"},
+                        {"time stage": ['08:00', '10:00'],
+                         "pps": 1900000,#[1800000, 2000000], 
+                         "check": "medium"},
+                        {"time stage": ['08:00', '10:00'],
+                         "pps": 2200000,
+                         "check": "max"},
+                        ],
+                    'TIME': [
+                        {'time stage': ['11:00', '12:00', '13:00'],
+                         "check": 'min'},
+                        {"time stage": ['03:00', '04:00', '05:00'],
+                        "check": 'max'},
+                        ],
+                    'WORKLOAD':None
+                }
+        if not self.is_perf and name == 'TRAFFIC':
+            return policys[name][:1]
+
+        return policys[name]
+
+    def check_policy(self, policy_name):
+        check_results = []
+        test_contents = self.get_policy_test_content(policy_name)
+        msg = "begin test policy <{0}>".format(policy_name)
+        self.logger.info(msg)
+        for content in test_contents:
+            #----------------------------
+            # set system time
+            time_stage = content['time stage']
+            random_index = random.randint(0, len(time_stage)-1)
+            timestamp = time_stage[random_index]
+            msg = "set timestamp {0}".format(timestamp)
+            self.logger.info(msg)
+            #------------------------------------------------
+            # set system time to a desired tiem
+            self.save_system_time()
+            self.set_desired_time(timestamp)
+            pre_time = datetime.now()
+            # run policy testing
+            try: 
+                self.run_policy(policy_name, content)
+            except Exception as e:
+                check_results.append(e)
+            finally:
+                pass
+            #------------------------------------------------
+            # restore system time
+            post_time = datetime.now()
+            interval = (post_time - pre_time).seconds
+            self.restore_system_time(interval)
+        msg = "complete test policy <{0}>".format(policy_name)
+        self.logger.warning(msg)
+
+        if check_results:
+            for e in check_results:
+                self.logger.error(e)
+            raise VerifyFailure('check_policy is failed')
+
+    def test_turbo_enable_by_core_num(self):
+        self.start_guest_mgr()
+        self.check_single_core_turbo_enable(vcpu)
+        self.close_guest_mgr()
+
+    def test_turbo_disable_by_core_num(self):
+        self.start_guest_mgr()
+        for vcpu in range(self.core_num):
+            self.check_single_core_turbo_disable(vcpu)
+        self.close_guest_mgr()
+
+    def test_policy_traffic(self):
+        """
+        Measure cpu frequency fluctuate with work load(traffic policy)
+        """
+        self.check_policy("TRAFFIC")
+
+    def test_policy_time(self):
+        """
+        Measure cpu frequency fluctuate with work load(time policy)
+        """
+        self.check_policy("TIME")
+
+    def test_perf_policy_traffic(self):
+        """
+        Measure cpu frequency fluctuate with work load(traffic policy)
+        """
+        self.check_policy("TRAFFIC")
+
+    def test_perf_policy_time(self):
+        """
+        Measure cpu frequency fluctuate with work load(time policy)
+        """
+        self.check_policy("TIME")
\ No newline at end of file
-- 
1.9.3

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

* [dts] [PATCH V1 3/3] vm_pw_mgmt_policy: framework etgen/ixia
  2018-06-06  5:35 [dts] [PATCH V1 0/3] vm_pw_mgmt_policy: upload test plan and automation script yufengx.mo
  2018-06-06  5:35 ` [dts] [PATCH V1 1/3] vm_pw_mgmt_policy: upload test plan yufengx.mo
  2018-06-06  5:35 ` [dts] [PATCH V1 2/3] vm_pw_mgmt_policy: upload automation script yufengx.mo
@ 2018-06-06  5:35 ` yufengx.mo
  2 siblings, 0 replies; 4+ messages in thread
From: yufengx.mo @ 2018-06-06  5:35 UTC (permalink / raw)
  To: dts; +Cc: yufengmx

From: yufengmx <yufengx.mo@intel.com>


extend ixia class to support continuous sending stream, app will stop it after
app complete sample statistics data.

Signed-off-by: yufengmx <yufengx.mo@intel.com>
---
 conf/vm_pw_mgmt_policy.cfg |  39 ++++++++++
 framework/etgen.py         | 184 +++++++++++++++++++++++++++++++++++++++++++--
 framework/tester.py        |  54 ++++++++++++-
 3 files changed, 271 insertions(+), 6 deletions(-)
 create mode 100644 conf/vm_pw_mgmt_policy.cfg
 mode change 100755 => 100644 framework/tester.py

diff --git a/conf/vm_pw_mgmt_policy.cfg b/conf/vm_pw_mgmt_policy.cfg
new file mode 100644
index 0000000..86ed1fb
--- /dev/null
+++ b/conf/vm_pw_mgmt_policy.cfg
@@ -0,0 +1,39 @@
+# libvirtd options:
+# [VM name] section value is the name for VM
+# cpu       # hard code type to host-passthrough
+#   number: number of vcpus
+#   cpupin: host cpu list
+# mem
+#   size: 4096
+# disk
+#   file: absolute path to disk image
+#   type: disk image format
+# login
+#   user: user name to login into VM
+#   password: passwork to login into VM
+# device
+#   pf_idx: pass-through device index of DUT ports
+#   guestpci: hardcode value of guest pci address
+# virtio_serial_channel
+#   path: virtio unix socket absolute path
+#   name: virtio serial name in VM
+
+# vm configuration for vm power management case
+[vm0]
+cpu =
+    number=4,cpupin=4 5 6 7;
+mem =
+    size=8196;
+disk =
+    file=/home/image/sriov-fc20-pw-1.img,type=raw;
+login =
+    user=root,password=tester;
+[vm1]
+cpu =
+    number=2,cpupin=7 8;
+mem =
+    size=2048;
+disk =
+    file=/home/image/sriov-fc20-pw-2.img,type=raw;
+login =
+    user=root,password=tester;
diff --git a/framework/etgen.py b/framework/etgen.py
index 2856a28..296d416 100644
--- a/framework/etgen.py
+++ b/framework/etgen.py
@@ -1,6 +1,6 @@
 # BSD LICENSE
 #
-# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# Copyright(c) 2010-2018 Intel Corporation. All rights reserved.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -168,6 +168,8 @@ class IxiaPacketGenerator(SSHConnection):
     """
 
     def __init__(self, tester):
+        self.bpsRate, self.oversize, self.rate = 0, 0, 0
+        self.rxPortlist, self.txPortlist = None, None
         self.tester = tester
         self.NAME = 'ixia'
         self.logger = getLogger(self.NAME)
@@ -227,6 +229,12 @@ class IxiaPacketGenerator(SSHConnection):
         Add one tcl command into command list.
         """
         self.tcl_cmds.append(cmd)
+        
+    def add_tcl_cmds(self, cmds):
+        """
+        Add multiple tcl commands into command list.
+        """
+        self.tcl_cmds += cmds
 
     def clean(self):
         """
@@ -393,7 +401,62 @@ class IxiaPacketGenerator(SSHConnection):
             self.add_tcl_cmd("stream set %d %d %d %d" %
                              (self.chasId, txport['card'], txport['port'], stream_id))
 
-    def config_ixia_stream(self, rate_percent, flows, latency):
+    def config_burst_stream(self, fpcap, txport, rate_percent, stream_id=1, 
+                            latency=False, **kwargs):
+        """
+        Configure IXIA stream and enable mutliple flows.
+        """
+        flows = self.parse_pcap(fpcap)
+        
+        self.add_tcl_cmd("ixGlobalSetDefault")
+
+        dma = kwargs.get('flow_type', 'stopStream')
+        frameType = kwargs.get('frameType', None)
+        gapUnit = frameType.get('type', 'gapMilliSeconds')
+        isg = frameType.get('isg', 100)
+        ifg = frameType.get('ifg', 100)
+        ibg = frameType.get('ibg', 100)
+        pkt = kwargs.get('count', 100)
+        frame_cmds = [
+                "stream config -numBursts {0}".format(pkt),
+                "stream config -gapUnit {0}".format(gapUnit),
+                "stream config -rateMode useGap",
+                "stream config -ifg {0}".format(ifg),
+                "stream config -ifgType gapFixed",
+                "stream config -enableIbg true",
+                "stream config -ibg {0}".format(ibg),
+                "stream config -enableIsg true",
+                "stream config -isg {0}".format(isg),]
+
+        self.config_ixia_stream(rate_percent, flows, latency)
+
+        pat = re.compile(r"(\w+)\((.*)\)")
+        for flow in flows:
+            for header in flow.split('/'):
+                match = pat.match(header)
+                params = eval('dict(%s)' % match.group(2))
+                method_name = match.group(1)
+                if method_name == 'Vxlan':
+                    method = getattr(self, method_name.lower())
+                    method(txport, **params)
+                    break
+                if method_name in SCAPY2IXIA:
+                    method = getattr(self, method_name.lower())
+                    method(txport, **params)
+            cmds =["stream config -name {0}".format(stream_id), 
+                   "stream set %d %d %d %d" % (self.chasId, txport['card'], 
+                                              txport['port'], stream_id)]
+            self.add_tcl_cmds(frame_cmds + cmds)
+            stream_id += 1
+
+        stream_id -= 1
+        cmds = ["stream config -dma {0}".format(dma),
+                "stream set %d %d %d %d" %
+                 (self.chasId, txport['card'], txport['port'], stream_id),
+                ]
+        self.add_tcl_cmds(cmds)
+
+    def config_ixia_stream(self, rate_percent, flows, latency, dma=None):
         """
         Configure IXIA stream with rate and latency.
         Override this method if you want to add custom stream configuration.
@@ -402,7 +465,7 @@ class IxiaPacketGenerator(SSHConnection):
         self.add_tcl_cmd("stream config -percentPacketRate %s" % rate_percent)
         self.add_tcl_cmd("stream config -numFrames 1")
         if len(flows) == 1:
-            self.add_tcl_cmd("stream config -dma contPacket")
+            self.add_tcl_cmd("stream config -dma {0}".format(dma or 'contPacket'))
         else:
             self.add_tcl_cmd("stream config -dma advance")
         # request by packet Group
@@ -527,6 +590,43 @@ class IxiaPacketGenerator(SSHConnection):
 
         return {'card': int(m.group(1)), 'port': int(m.group(2))}
 
+    def get_port_stats(self, rxPortlist, txPortlist, delay=5):
+        """
+        Get RX/TX packet statistics and calculate loss rate.
+        """
+        time.sleep(delay)
+
+        #self.send_expect("ixStopTransmit portList", "%", 10)
+        time.sleep(2)
+        sendNumber = 0
+        for port in txPortlist:
+            self.stat_get_stat_all_stats(port)
+            sendNumber += self.get_frames_sent()
+            time.sleep(0.5)
+
+        self.logger.info("send :%f" % sendNumber)
+
+        assert sendNumber != 0
+
+        revNumber = 0
+        for port in rxPortlist:
+            self.stat_get_stat_all_stats(port)
+            revNumber += self.get_frames_received()
+        self.logger.info("rev  :%f" % revNumber)
+
+        return sendNumber, revNumber
+
+    def port_stats(self, portList, ratePercent, delay=5):
+        rxPortlist, txPortlist = self.rxPortlist, self.txPortlist
+        return self.get_port_stats(rxPortlist, txPortlist, delay)
+
+    def port_line_rate(self):
+        chasId = '1'
+        port_line_rate = []
+        for port in self.ports:
+            port_line_rate.append(self.get_line_rate(chasId, port))
+        return port_line_rate
+
     def loss(self, portList, ratePercent, delay=5):
         """
         Run loss performance test and return loss rate.
@@ -589,6 +689,41 @@ class IxiaPacketGenerator(SSHConnection):
         """
         rxPortlist, txPortlist = self._configure_everything(port_list, rate_percent)
         return self.get_transmission_results(rxPortlist, txPortlist, delay)
+    
+    def loop_throughput(self, port_list, rate_percent=100, delay=5):
+        """
+        Run throughput performance test and return throughput statistics.
+        """
+        rxPortlist, txPortlist = self._configure_everything(port_list, rate_percent)
+        self.rxPortlist, self.txPortlist = rxPortlist, txPortlist
+
+    def stop_loop_throughput(self, port_list, rate_percent=100, delay=5):
+        """
+        Run throughput performance test and return throughput statistics.
+        """
+        
+        return self.stop_loop_transmission(self.rxPortlist, self.txPortlist, delay)
+        return True
+
+    def burst_throughput(self, port_list, rate_percent=100, delay=5, **kwargs):
+        """
+        Run burst performance test and return throughput statistics.
+        """
+        rxPortlist, txPortlist = self._configure_burst(port_list, rate_percent, **kwargs)
+        self.rxPortlist, self.txPortlist = rxPortlist, txPortlist
+        return True
+
+    def _configure_burst(self, port_list, rate_percent, latency=False, **kwargs):
+        """
+        Prepare and configure IXIA ports for performance test.
+        """
+        rxPortlist, txPortlist = self.prepare_port_list(port_list, rate_percent, 
+                                                        latency , **kwargs)
+        self.prepare_ixia_for_transmission(txPortlist, rxPortlist)
+        self.configure_transmission()
+        self.start_transmission()
+        self.clear_tcl_commands()
+        return rxPortlist, txPortlist
 
     """
     This function could be used to check the packets' order whether same as the receive sequence.
@@ -644,12 +779,14 @@ class IxiaPacketGenerator(SSHConnection):
         """
         self.add_tcl_cmd("ixStartTransmit portList")
 
-    def prepare_port_list(self, portList, rate_percent=100, latency=False):
+    def prepare_port_list(self, portList, rate_percent=100, latency=False, 
+                          **kwargs):
         """
         Configure stream and flow on every IXIA ports.
         """
         txPortlist = set()
         rxPortlist = set()
+        stream_type= kwargs.get('stream_type') or 'normal'
 
         for (txPort, rxPort, pcapFile) in portList:
             txPortlist.add(txPort)
@@ -661,7 +798,15 @@ class IxiaPacketGenerator(SSHConnection):
 
         # stream/flow setting
         for (txPort, rxPort, pcapFile) in portList:
-            self.config_stream(pcapFile, self.pci_to_port(self.tester.get_pci(txPort)), rate_percent, 1, latency)
+            if stream_type != 'normal':
+                config_stream = getattr(self, 'config_{0}_stream'.format(stream_type))
+                config_stream(pcapFile, 
+                              self.pci_to_port(self.tester.get_pci(txPort)), 
+                              rate_percent, 1, latency, **kwargs)
+            else:
+                self.config_stream(pcapFile, 
+                                   self.pci_to_port(self.tester.get_pci(txPort)), 
+                                   rate_percent, 1, latency)
 
         # config stream before packetGroup
         if latency is not False:
@@ -686,6 +831,35 @@ class IxiaPacketGenerator(SSHConnection):
     def hook_transmission_func(self):
         pass
 
+    def loop_get_transmission_results(self, rx_port_list, tx_port_list, delay=5):
+        """
+        Override this method if you want to change the way of getting results
+        back from IXIA.
+        """
+        time.sleep(delay)
+        bpsRate = self.bpsRate
+        rate = self.rate
+        oversize = self.oversize
+        for port in rx_port_list:
+            self.stat_get_rate_stat_all_stats(port)
+            out = self.send_expect("stat cget -framesReceived", '%', 10)
+            rate += int(out.strip())
+            out = self.send_expect("stat cget -bitsReceived", '% ', 10)
+            self.logger.debug("port %d bits rate:" % (port) + out)
+            bpsRate += int(out.strip())
+            out = self.send_expect("stat cget -oversize", '%', 10)
+            oversize += int(out.strip())
+
+        self.logger.info("Rate: %f Mpps" % (rate * 1.0 / 1000000))
+        self.logger.info("Mbps rate: %f Mbps" % (bpsRate * 1.0 / 1000000))
+        self.hook_transmissoin_func()
+
+        return True
+
+    def stop_loop_transmission(self, rx_port_list, tx_port_list, delay=5):
+        return self.get_transmission_results(self.rxPortlist, self.txPortlist, 
+                                             delay)
+
     def get_transmission_results(self, rx_port_list, tx_port_list, delay=5):
         """
         Override this method if you want to change the way of getting results
diff --git a/framework/tester.py b/framework/tester.py
old mode 100755
new mode 100644
index a775f68..043c6fc
--- a/framework/tester.py
+++ b/framework/tester.py
@@ -1,6 +1,6 @@
 # BSD LICENSE
 #
-# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# Copyright(c) 2010-2018 Intel Corporation. All rights reserved.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -502,6 +502,42 @@ class Tester(Crb):
             return None
         return self.packet_gen.throughput(portList, rate_percent)
 
+    def loop_traffic_generator_throughput(self, portList, rate_percent=100, 
+                                          delay=5):
+        """
+        Run throughput performance test on specified ports.
+        """
+        print rate_percent
+        if self.check_port_list(portList, 'ixia'):
+            return self.ixia_packet_gen.loop_throughput(portList, rate_percent, 
+                                                        delay)
+        if not self.check_port_list(portList):
+            self.logger.warning("exception by mixed port types")
+            return None
+        result = self.packet_gen.loop_throughput(portList, rate_percent)
+        return result
+
+    def stop_traffic_generator_throughput_loop(self, portList, 
+                                               rate_percent=100, delay=5):
+        """
+        Run throughput performance test on specified ports.
+        """
+        return self.ixia_packet_gen.stop_loop_throughput(portList, 
+                                                         rate_percent, delay)
+
+    def burst_traffic_generator_throughput(self, portList, rate_percent=100, 
+                                           delay=5, **kwargs):
+        """
+        Run throughput performance test on specified ports.
+        """
+        if self.check_port_list(portList, 'ixia'):
+            return self.ixia_packet_gen.burst_throughput(portList, rate_percent, 
+                                                         delay, **kwargs)
+        if not self.check_port_list(portList):
+            self.logger.warning("exception by mixed port types")
+            return None
+        return result
+
     def verify_packet_order(self, portList, delay):
         if self.check_port_list(portList, 'ixia'):
             return self.ixia_packet_gen.is_packet_ordered(portList, delay)
@@ -536,6 +572,22 @@ class Tester(Crb):
             return None
         return self.packet_gen.loss(portList, ratePercent, delay)
 
+    def traffic_get_port_stats(self, portList, delay=60):
+        """
+        Run loss performance test on specified ports.
+        """
+        ratePercent = float(100)
+        if self.check_port_list(portList, 'ixia'):
+            return self.ixia_packet_gen.port_stats(portList, ratePercent, delay)
+        elif not self.check_port_list(portList):
+            self.logger.warning("exception by mixed port types")
+            return None
+        else:
+            return None
+
+    def get_port_line_rate(self):
+        return self.ixia_packet_gen.port_line_rate()
+
     def traffic_generator_latency(self, portList, ratePercent=100, delay=5):
         """
         Run latency performance test on specified ports.
-- 
1.9.3

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

end of thread, other threads:[~2018-06-06  5:35 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-06  5:35 [dts] [PATCH V1 0/3] vm_pw_mgmt_policy: upload test plan and automation script yufengx.mo
2018-06-06  5:35 ` [dts] [PATCH V1 1/3] vm_pw_mgmt_policy: upload test plan yufengx.mo
2018-06-06  5:35 ` [dts] [PATCH V1 2/3] vm_pw_mgmt_policy: upload automation script yufengx.mo
2018-06-06  5:35 ` [dts] [PATCH V1 3/3] vm_pw_mgmt_policy: framework etgen/ixia yufengx.mo

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