From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by dpdk.org (Postfix) with ESMTP id DE3325AA0 for ; Thu, 9 Jul 2015 05:36:32 +0200 (CEST) Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga103.fm.intel.com with ESMTP; 08 Jul 2015 20:36:34 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.15,436,1432623600"; d="scan'208";a="725462095" Received: from shvmail01.sh.intel.com ([10.239.29.42]) by orsmga001.jf.intel.com with ESMTP; 08 Jul 2015 20:36:31 -0700 Received: from shecgisg003.sh.intel.com (shecgisg003.sh.intel.com [10.239.29.90]) by shvmail01.sh.intel.com with ESMTP id t693aUt6026110; Thu, 9 Jul 2015 11:36:30 +0800 Received: from shecgisg003.sh.intel.com (localhost [127.0.0.1]) by shecgisg003.sh.intel.com (8.13.6/8.13.6/SuSE Linux 0.8) with ESMTP id t693aRVg030978; Thu, 9 Jul 2015 11:36:29 +0800 Received: (from yliu84x@localhost) by shecgisg003.sh.intel.com (8.13.6/8.13.6/Submit) id t693aRET030974; Thu, 9 Jul 2015 11:36:27 +0800 From: Yong Liu To: dts@dpdk.org Date: Thu, 9 Jul 2015 11:36:19 +0800 Message-Id: <1436412979-30921-4-git-send-email-yong.liu@intel.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1436412979-30921-1-git-send-email-yong.liu@intel.com> References: <1436412979-30921-1-git-send-email-yong.liu@intel.com> Subject: [dts] [PATCH 3/3] Add test suite for vm power management feature X-BeenThere: dts@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: test suite reviews and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 09 Jul 2015 03:36:33 -0000 From: Marvin Liu Signed-off-by: Marvin Liu diff --git a/tests/TestSuite_vm_power_manager.py b/tests/TestSuite_vm_power_manager.py new file mode 100644 index 0000000..f06d245 --- /dev/null +++ b/tests/TestSuite_vm_power_manager.py @@ -0,0 +1,430 @@ +# BSD LICENSE +# +# Copyright(c) 2010-2015 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 re +import dts +from test_case import TestCase +from etgen import IxiaPacketGenerator +from settings import HEADER_SIZE +from qemu_libvirt import LibvirtKvm + + +class TestVmPowerManager(TestCase, IxiaPacketGenerator): + + def set_up_all(self): + """ + Run at the start of each test suite. + """ + self.dut_ports = self.dut.get_ports(self.nic) + self.verify(len(self.dut_ports) >= 2, + "Not enough ports for " + self.nic) + + # create temporary folder for power monitor + self.dut.send_expect("mkdir -p /tmp/powermonitor", "# ") + self.dut.send_expect("chmod 777 /tmp/powermonitor", "# ") + # compile vm power manager + 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") + + # map between host vcpu and guest vcpu + self.vcpu_map = [] + # start vm + self.vm_name = "vm0" + self.vm = LibvirtKvm(self.dut, self.vm_name, self.suite) + channels = [ + {'path': '/tmp/powermonitor/%s.0' % + self.vm_name, 'name': 'virtio.serial.port.poweragent.0'}, + {'path': '/tmp/powermonitor/%s.1' % + self.vm_name, 'name': 'virtio.serial.port.poweragent.1'}, + {'path': '/tmp/powermonitor/%s.2' % + self.vm_name, 'name': 'virtio.serial.port.poweragent.2'}, + {'path': '/tmp/powermonitor/%s.3' % + self.vm_name, 'name': 'virtio.serial.port.poweragent.3'} + ] + for channel in channels: + self.vm.add_vm_virtio_serial_channel(**channel) + + self.vm_dut = self.vm.start() + + # ping cpus + cpus = self.vm.get_vm_cpu() + self.vcpu_map = cpus[:] + self.core_num = len(cpus) + + # build guest cli + 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") + + self.vm_power_dir = "./examples/vm_power_manager/" + mgr_cmd = self.vm_power_dir + "build/vm_power_mgr -c 0x3 -n 4" + out = self.dut.send_expect(mgr_cmd, "vmpower>", 120) + self.verify("Initialized successfully" in out, + "Power manager failed to initialized") + self.dut.send_expect("add_vm %s" % self.vm_name, "vmpower>") + self.dut.send_expect("add_channels %s all" % self.vm_name, "vmpower>") + vm_info = self.dut.send_expect("show_vm %s" % self.vm_name, "vmpower>") + + # performance measure + self.frame_sizes = [128] + self.perf_rates = [0, 20, 40, 60, 80, 100] + self.def_framesize = 64 + + def set_up(self): + """ + Run before each test case. + """ + pass + + def test_managment_channel(self): + """ + Check power monitor channel connection + """ + # check Channels and vcpus + guest_cmd = self.vm_power_dir + \ + "guest_cli/build/guest_vm_power_mgr -c 0xf -n 4 -- -i" + out = self.vm_dut.send_expect(guest_cmd, "vmpower\(guest\)>", 120) + self.verify("now connected" in out, + "Power manager guest failed to connect") + self.vm_dut.send_expect("quit", "# ") + + def get_cpu_frequency(self, core_id): + cpu_regex = ".*\nCore (\d+) frequency: (\d+)" + out = self.dut.send_expect("show_cpu_freq %s" % core_id, "vmpower>") + m = re.match(cpu_regex, out) + freq = -1 + if m: + freq = int(m.group(2)) + + return freq + + def test_vm_power_managment_freqdown(self): + """ + Check host cpu frequency can scale down in VM + """ + guest_cmd = self.vm_power_dir + \ + "guest_cli/build/guest_vm_power_mgr -c 0xf -n 4 -- -i" + out = self.vm_dut.send_expect(guest_cmd, "vmpower\(guest\)>", 120) + self.verify("now connected" in out, + "Power manager guest failed to connect") + + for vcpu in range(self.core_num): + self.vm_dut.send_expect( + "set_cpu_freq %d max" % vcpu, "vmpower\(guest\)>") + + for vcpu in range(self.core_num): + # map between host cpu and guest cpu + ori_freq = self.get_cpu_frequency(self.vcpu_map[vcpu]) + # get cpu frequencies range + freqs = self.get_cpu_freqs(vcpu) + + for loop in range(len(freqs)-1): + # connect vm power host and guest + self.vm_dut.send_expect( + "set_cpu_freq %d down" % vcpu, "vmpower\(guest\)>") + cur_freq = self.get_cpu_frequency(self.vcpu_map[vcpu]) + print dts.GREEN("After freqency down, freq is %d\n" % cur_freq) + self.verify( + ori_freq > cur_freq, "Cpu freqenecy can not scale down") + ori_freq = cur_freq + + self.vm_dut.send_expect("quit", "# ") + + def test_vm_power_managment_frequp(self): + """ + Check host cpu frequency can scale up in VM + """ + guest_cmd = self.vm_power_dir + \ + "guest_cli/build/guest_vm_power_mgr -c 0xf -n 4 -- -i" + out = self.vm_dut.send_expect(guest_cmd, "vmpower\(guest\)>", 120) + self.verify("now connected" in out, + "Power manager guest failed to connect") + + for vcpu in range(self.core_num): + self.vm_dut.send_expect( + "set_cpu_freq %d min" % vcpu, "vmpower\(guest\)>") + + for vcpu in range(self.core_num): + ori_freq = self.get_cpu_frequency(self.vcpu_map[vcpu]) + # get cpu frequencies range + freqs = self.get_cpu_freqs(vcpu) + for loop in range(len(freqs)-1): + self.vm_dut.send_expect( + "set_cpu_freq %d up" % vcpu, "vmpower\(guest\)>") + cur_freq = self.get_cpu_frequency(self.vcpu_map[vcpu]) + print dts.GREEN("After freqency up, freq is %d\n" % cur_freq) + self.verify( + cur_freq > ori_freq, "Cpu freqenecy can not scale up") + ori_freq = cur_freq + + self.vm_dut.send_expect("quit", "# ") + + def test_vm_power_managment_freqmax(self): + """ + Check host cpu frequency can scale to max in VM + """ + guest_cmd = self.vm_power_dir + \ + "guest_cli/build/guest_vm_power_mgr -c 0xf -n 4 -- -i" + out = self.vm_dut.send_expect(guest_cmd, "vmpower\(guest\)>", 120) + self.verify("now connected" in out, + "Power manager guest failed to connect") + + max_freq_path = "cat /sys/devices/system/cpu/cpu%s/cpufreq/" + \ + "cpuinfo_max_freq" + for vcpu in range(self.core_num): + self.vm_dut.send_expect( + "set_cpu_freq %d max" % vcpu, "vmpower\(guest\)>") + freq = self.get_cpu_frequency(self.vcpu_map[vcpu]) + + out = self.dut.alt_session.send_expect( + max_freq_path % self.vcpu_map[vcpu], "# ") + max_freq = int(out) + + self.verify(freq == max_freq, "Cpu max frequency not correct") + print dts.GREEN("After freqency max, freq is %d\n" % max_freq) + self.vm_dut.send_expect("quit", "# ") + + def test_vm_power_managment_freqmin(self): + """ + Check host cpu frequency can scale to min in VM + """ + guest_cmd = self.vm_power_dir + \ + "guest_cli/build/guest_vm_power_mgr -c 0xf -n 4 -- -i" + out = self.vm_dut.send_expect(guest_cmd, "vmpower\(guest\)>", 120) + self.verify("now connected" in out, + "Power manager guest failed to connect") + + min_freq_path = "cat /sys/devices/system/cpu/cpu%s/cpufreq/" + \ + "cpuinfo_min_freq" + for vcpu in range(self.core_num): + self.vm_dut.send_expect( + "set_cpu_freq %d min" % vcpu, "vmpower\(guest\)>") + freq = self.get_cpu_frequency(self.vcpu_map[vcpu]) + + out = self.dut.alt_session.send_expect( + min_freq_path % self.vcpu_map[vcpu], "# ") + min_freq = int(out) + + self.verify(freq == min_freq, "Cpu min frequency not correct") + print dts.GREEN("After freqency min, freq is %d\n" % min_freq) + self.vm_dut.send_expect("quit", "# ") + + def test_vm_power_multivms(self): + """ + Check power management channel connected in multiple VMs + """ + vm_name = "vm1" + vm2 = LibvirtKvm(self.dut, vm_name, self.suite) + channels = [ + {'path': '/tmp/powermonitor/%s.0' % + vm_name, 'name': 'virtio.serial.port.poweragent.0'}, + {'path': '/tmp/powermonitor/%s.1' % + vm_name, 'name': 'virtio.serial.port.poweragent.1'}, + {'path': '/tmp/powermonitor/%s.2' % + vm_name, 'name': 'virtio.serial.port.poweragent.2'}, + {'path': '/tmp/powermonitor/%s.3' % + vm_name, 'name': 'virtio.serial.port.poweragent.3'} + ] + for channel in channels: + vm2.add_vm_virtio_serial_channel(**channel) + vm2_dut = vm2.start() + + self.dut.send_expect("add_vm %s" % vm_name, "vmpower>") + self.dut.send_expect("add_channels %s all" % vm_name, "vmpower>") + vm_info = self.dut.send_expect("show_vm %s" % vm_name, "vmpower>") + + out = vm2_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") + + guest_cmd = self.vm_power_dir + \ + "guest_cli/build/guest_vm_power_mgr -c 0xf -n 4 -- -i" + out = vm2_dut.send_expect(guest_cmd, "vmpower\(guest\)>", 120) + self.verify("now connected" in out, + "Power manager guest failed to connect") + vm2_dut.send_expect("quit", "# ") + vm2.stop() + + def test_perf_vmpower_latency(self): + """ + Measure packet latency in VM + """ + latency_header = ['Frame Size', 'Max latency', 'Min lantecy', + 'Avg latency'] + + dts.results_table_add_header(latency_header) + + rx_port = self.dut_ports[0] + tx_port = self.dut_ports[1] + + # build l3fwd-power + out = self.vm_dut.send_expect("make -C examples/l3fwd-power", "# ") + self.verify("Error" not in out, "compilation error 1") + self.verify("No such file" not in out, "compilation error 2") + # start l3fwd-power + l3fwd_app = "./examples/l3fwd-power/build/l3fwd-power" + + cmd = l3fwd_app + " -c 6 -n 4 -- -p 0x3 --config " + \ + "'(0,0,1),(1,0,2)'" + + self.vm_dut.send_expect(cmd, "L3FWD_POWER: entering main loop") + + for frame_size in self.frame_sizes: + # Prepare traffic flow + payload_size = frame_size - HEADER_SIZE['udp'] - \ + HEADER_SIZE['ip'] - HEADER_SIZE['eth'] + dmac = self.dut.get_mac_address(self.dut_ports[0]) + flow = 'Ether(dst="%s")/IP(dst="2.1.1.0")/UDP()' % dmac + \ + '/Raw("X"*%d)' % payload_size + self.tester.scapy_append('wrpcap("vmpower.pcap", [%s])' % flow) + self.tester.scapy_execute() + + tgen_input = [] + tgen_input.append((self.tester.get_local_port(rx_port), + self.tester.get_local_port(tx_port), + "vmpower.pcap")) + # run traffic generator + [latency] = self.tester.traffic_generator_latency(tgen_input) + print latency + table_row = [frame_size, latency['max'], latency['min'], + latency['average']] + dts.results_table_add_row(table_row) + + dts.results_table_print() + + self.vm_dut.kill_all() + + def test_perf_vmpower_frequency(self): + """ + Measure cpu frequency fluctuate with work load + """ + latency_header = ['Tx linerate%', 'Rx linerate%', 'Cpu freq'] + + dts.results_table_add_header(latency_header) + + rx_port = self.dut_ports[0] + tx_port = self.dut_ports[1] + + # build l3fwd-power + out = self.vm_dut.send_expect("make -C examples/l3fwd-power", "# ") + self.verify("Error" not in out, "compilation error 1") + self.verify("No such file" not in out, "compilation error 2") + # start l3fwd-power + l3fwd_app = "./examples/l3fwd-power/build/l3fwd-power" + + cmd = l3fwd_app + " -c 6 -n 4 -- -p 0x3 --config " + \ + "'(0,0,1),(1,0,2)'" + + self.vm_dut.send_expect(cmd, "L3FWD_POWER: entering main loop") + + for rate in self.perf_rates: + # Prepare traffic flow + payload_size = self.def_framesize - HEADER_SIZE['udp'] - \ + HEADER_SIZE['ip'] - HEADER_SIZE['eth'] + dmac = self.dut.get_mac_address(self.dut_ports[0]) + flow = 'Ether(dst="%s")/IP(dst="2.1.1.0")/UDP()' % dmac + \ + '/Raw("X"*%d)' % payload_size + self.tester.scapy_append('wrpcap("vmpower.pcap", [%s])' % flow) + self.tester.scapy_execute() + + tgen_input = [] + tgen_input.append((self.tester.get_local_port(rx_port), + self.tester.get_local_port(tx_port), + "vmpower.pcap")) + + # register hook function for current cpu frequency + self.hook_transmissoin_func = self.get_freq_in_transmission + self.tester.extend_external_packet_generator(TestVmPowerManager, + self) + # run traffic generator, run 20 seconds for frequency stable + _, pps = self.tester.traffic_generator_throughput(tgen_input, + rate, + delay=20) + pps /= 1000000.0 + freq = self.cur_freq / 1000000.0 + wirespeed = self.wirespeed(self.nic, self.def_framesize, 1) + pct = pps * 100 / wirespeed + table_row = [rate, pct, freq] + dts.results_table_add_row(table_row) + + dts.results_table_print() + + self.vm_dut.kill_all() + + def get_freq_in_transmission(self): + self.cur_freq = self.get_cpu_frequency(self.vcpu_map[1]) + print dts.GREEN("Current cpu frequency %d" % self.cur_freq) + + def get_max_freq(self, core_num): + freq_path = "cat /sys/devices/system/cpu/cpu%d/cpufreq/" + \ + "cpuinfo_max_freq" + + out = self.dut.alt_session.send_expect(freq_path % core_num, "# ") + freq = int(out) + return freq + + def get_min_freq(self, core_num): + freq_path = "cat /sys/devices/system/cpu/cpu%d/cpufreq/" + \ + "cpuinfo_min_freq" + + out = self.dut.alt_session.send_expect(freq_path % core_num, "# ") + freq = int(out) + return freq + + def get_cpu_freqs(self, core_num): + freq_path = "cat /sys/devices/system/cpu/cpu%d/cpufreq/" + \ + "scaling_available_frequencies" + + out = self.dut.alt_session.send_expect(freq_path % core_num, "# ") + freqs = out.split() + return freqs + + def tear_down(self): + """ + Run after each test case. + """ + self.vm_dut.send_expect("quit", "# ") + pass + + def tear_down_all(self): + """ + Run after each test suite. + """ + self.dut.send_expect("quit", "# ") + self.vm.stop() + pass -- 1.9.3