* [KVM-autotest] virtio_console test
@ 2010-08-20 13:40 Lukas Doktor
2010-08-20 13:40 ` [PATCH] NEW " Lukas Doktor
2010-08-20 14:12 ` [KVM-autotest] " Lukáš Doktor
0 siblings, 2 replies; 6+ messages in thread
From: Lukas Doktor @ 2010-08-20 13:40 UTC (permalink / raw)
To: ldoktor, jzupka, autotest, kvm, akong
Hi,
This patch adds new test for virtio_console. It supports booth, serialport and console, virtio_console types and it contains three tests:
1) smoke
2) loopback
3) perf
Before any tests are executed it starts the machine with required number of virtio_consoles. Than it allows user to run all three tests. Using the parameters user can control which tests are executed and what setting is used. All tests supports multiple run using ';' separated list of settings. Most of the settings are optional only. The mandatory ones are written in CAPITALS.
ad1) virtio_console_smoke format:
$VIRTIO_CONSOLE_TYPE:$custom_data
It creates a loopback via $VIRTIO_CONSOLE_TYPE console and sends $custom_data. If the received data match the original test pass
ad2) virtio_console_loopback format:
$SOURCE_CONSOLE_TYPE@$buffer_length:$DESTINATION_CONSOLE1_TYPE@$buffer_length:...:$DESTINATION_CONSOLEx_TYPE@$buffer_length:$loopback_buffer_length
Creates loopback between the $SOURCE_CONSOLE_TYPE console and all following $DESTINATION_CONSOLEn_TYPE consoles. Than it sends data by $buffer_length to the source port. The loopback resends the data by $loopback_buffer_length to all destination consoles. The test listens on the destination consoles and controls the received data.
NOTE: in the debug mode you can see the send/received data's buffers in every second during the test.
ad3) virtio_console_perf format:
$VIRTIO_CONSOLE_TYPE@$buffer_size:$test_duration
First it sends the prepared data in a loop over $VIRTIO_CONSOLE_TYPE console from host to guest. Guest only reads all the data and throw them away. This part runs $test_duration seconds.
Second it does the same from guest to host.
For booth runs it provides information of minimum/median/maximum throughput and guest/host average loads.
Best regards,
Lukas Doktor
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH] NEW virtio_console test
2010-08-20 13:40 [KVM-autotest] virtio_console test Lukas Doktor
@ 2010-08-20 13:40 ` Lukas Doktor
2010-08-20 14:12 ` [KVM-autotest] " Lukáš Doktor
1 sibling, 0 replies; 6+ messages in thread
From: Lukas Doktor @ 2010-08-20 13:40 UTC (permalink / raw)
To: ldoktor, jzupka, autotest, kvm, akong
Signed-off-by: Lukas Doktor <ldoktor@redhat.com>
---
client/tests/kvm/scripts/consoleSwitch.py | 217 +++++++++
client/tests/kvm/tests/virtio_console.py | 730 +++++++++++++++++++++++++++++
client/tests/kvm/tests_base.cfg.sample | 7 +
3 files changed, 954 insertions(+), 0 deletions(-)
create mode 100644 client/tests/kvm/scripts/consoleSwitch.py
create mode 100644 client/tests/kvm/tests/virtio_console.py
diff --git a/client/tests/kvm/scripts/consoleSwitch.py b/client/tests/kvm/scripts/consoleSwitch.py
new file mode 100644
index 0000000..814388f
--- /dev/null
+++ b/client/tests/kvm/scripts/consoleSwitch.py
@@ -0,0 +1,217 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+"""
+Auxiliary script used to send data betwen ports on guests.
+
+@copyright: 2008-2009 Red Hat Inc.
+@author: Jiri Zupka (jzupka@redhat.com)
+@author: Lukas Doktor (ldoktor@redhat.com)
+"""
+
+
+import threading
+from threading import Thread
+import os,time,select,re,random,sys,array
+
+
+files = dict()
+ev = threading.Event()
+threads = []
+
+DEBUGPATH="/sys/kernel/debug"
+
+
+
+class switch(Thread):
+ """
+ Class create thread which send data between ports
+ """
+ def __init__ (self,exitevent,in_files,out_files,cachesize=1):
+ """
+ @param exitevent: event to end switch
+ @param in_files: array of input files
+ @param out_files: array of output files
+ @param cachesize: block to receive and send
+ """
+ Thread.__init__(self)
+
+ self.in_files = in_files
+ self.out_files = out_files
+
+ self.cachesize = cachesize
+ self.exitevent = exitevent
+
+
+ def run(self):
+ while not self.exitevent.isSet():
+ #TODO: Why select causes trouble? :-(
+ #ret = select.select(self.in_files,[],[],1.0)
+ data = ""
+ #if not ret[0] == []:
+ for desc in self.in_files:
+ data += os.read(desc,self.cachesize)
+ for desc in self.out_files:
+ os.write(desc,data)
+
+class sender(Thread):
+ """
+ Class creates thread which sends random block of data to the destination
+ port
+ """
+ def __init__(self, port, length):
+ """
+ @param port: destination port
+ @param length: length of the random data block
+ """
+ Thread.__init__(self)
+ self.port = port
+ self.data = array.array('L')
+ for i in range(max(length / self.data.itemsize,1)):
+ self.data.append(random.randrange(sys.maxint))
+
+ def run(self):
+ while True:
+ os.write(self.port, self.data)
+ del threads[:]
+
+def getPortStatus():
+ """
+ Function get info about ports from kernel debugfs.
+
+ @return: ports dictionary of port properties
+ """
+ ports = dict()
+
+ if (not os.path.ismount(DEBUGPATH)):
+ os.system('mount -t debugfs none %s' % (DEBUGPATH))
+ try:
+ if not os.path.isdir('%s/virtio-ports' % (DEBUGPATH)):
+ print "FAIL: Not exist virtio-ports in debug fs"
+ except:
+ print "FAIL: virtio-ports not exist"
+ else:
+ viop_names = os.listdir('%s/virtio-ports' % (DEBUGPATH))
+ for name in viop_names:
+ f = open("%s/virtio-ports/%s" % (DEBUGPATH,name),'r')
+ port = dict()
+ for line in iter(f):
+ m = re.match("(\S+): (\S+)",line)
+ port[m.group(1)] = m.group(2)
+
+ if (port['is_console'] == "yes"):
+ port["path"] = "/dev/hvc%s" % (port["console_vtermno"])
+ #Console work like serialport
+ else:
+ port["path"] = "/dev/%s" % (name)
+ ports[port['name']] = port
+ f.close()
+
+ return ports
+
+
+def opendevice(in_files,ports):
+ """
+ Open devices and return array of descriptors
+
+ @param in_files: files array
+ @return: array of descriptor
+ """
+
+ f = []
+
+ for item in in_files:
+ name = ports[item[0]]["path"]
+ if (not item[1] == ports[item[0]]["is_console"]):
+ print ports
+ print "FAIL: Host console is not like console on guest side\n"
+
+ if (name in files):
+ f.append(files[name])
+ else:
+ try:
+ files[name] = os.open(name, os.O_RDWR)
+ if (ports[item[0]]["is_console"] == "yes"):
+ print os.system("stty -F %s raw -echo" % (ports[item[0]]["path"]))
+ print os.system("stty -F %s -a" % (ports[item[0]]["path"]))
+ f.append(files[name])
+ except Exception as inst:
+ print "FAIL: Failed open file %s" % (name)
+ raise inst
+ return f
+
+
+def startswitch(in_files,out_files,cachesize=1):
+ """
+ Function starts switch thread (because there is problem with multiple open
+ of one files).
+
+ @param in_files: array of input files
+ @param out_files: array of output files
+ @param cachesize: cachesize
+ """
+
+
+ ports = getPortStatus()
+
+ in_f = opendevice(in_files,ports)
+ out_f = opendevice(out_files,ports)
+
+
+ s = switch(ev,in_f,out_f,cachesize)
+ s.start()
+ threads.append(s)
+ print "PASS: Start switch"
+
+def endswitchs():
+ """
+ Function end all running data switch.
+ """
+ ev.set()
+ for th in threads:
+ print "join"
+ th.join(3.0)
+ ev.clear()
+
+ del threads[:]
+ print "PASS: End switch"
+
+def die():
+ """
+ Quit consoleswitch.
+ """
+ for desc in files.itervalues():
+ os.close(desc)
+ exit(0)
+
+def senderprepare(port, length):
+ """
+ Prepares the sender thread. Requires clean thread structure.
+ """
+ del threads[:]
+ ports = getPortStatus()
+ in_f = opendevice([port],ports)
+
+ threads.append(sender(in_f[0], length))
+ print "PASS: Sender prepare"
+
+def senderstart():
+ """
+ Start sender data transfer. Requires senderprepare run firs.
+ """
+ threads[0].start()
+ print "PASS: Sender start"
+
+def main():
+ """
+ Main (infinite) loop of consoleswitch.
+ """
+ print "PASS: Start"
+ end = False
+ while not end:
+ str = raw_input()
+ exec str
+
+
+
+if __name__ == "__main__":
+ main()
diff --git a/client/tests/kvm/tests/virtio_console.py b/client/tests/kvm/tests/virtio_console.py
new file mode 100644
index 0000000..f05500d
--- /dev/null
+++ b/client/tests/kvm/tests/virtio_console.py
@@ -0,0 +1,730 @@
+import logging, time
+from autotest_lib.client.common_lib import error
+import kvm_subprocess, kvm_test_utils, kvm_utils, kvm_preprocessing
+import socket, random, array, sys, os, tempfile, shutil, threading, select
+from threading import Thread
+from collections import deque
+import re
+
+
+def run_virtio_console(test, params, env):
+ """
+ KVM virtio_console test
+
+ @param test: kvm test object
+ @param params: Dictionary with the test parameters
+ @param env: Dictionary with test environment
+ """
+ class th_send(Thread):
+ """
+ Random data sender thread
+ """
+ def __init__(self, port, length, buffers, blocklen=32):
+ """
+ @param port: destination port
+ @param length: amount of data we want to send
+ @param buffers: buffers for the control data (FIFOs)
+ @param blocklen: block length
+ """
+ Thread.__init__(self)
+ self.ExitState = True
+ self.port = port[0]
+ self.length = length
+ self.buffers = buffers
+ self.blocklen = blocklen
+ def run(self):
+ logging.debug("th_send %s: run" % self.getName())
+ idx = 0
+ while idx < self.length:
+ ret = select.select([], [self.port], [], 1.0)
+ if ret:
+ # Generate blocklen of random data add them to the FIFO
+ # and send tham over virtio_console
+ buf = ""
+ for i in range(min(self.blocklen, self.length-idx)):
+ ch = "%c" % random.randrange(255)
+ buf += ch
+ for buffer in self.buffers:
+ buffer.append(ch)
+ idx += len(buf)
+ self.port.sendall(buf)
+ logging.debug("th_send %s: exit(%d)" % (self.getName(), idx))
+ if idx >= self.length:
+ self.ExitState = False
+ class th_send_loop(Thread):
+ """
+ Send data in the loop until the exit event is set
+ """
+ def __init__(self, port, data, event):
+ """
+ @param port: destination port
+ @param data: the data intend to be send in a loop
+ @param event: exit event
+ """
+ Thread.__init__(self)
+ self.port = port
+ self.data = data
+ self.exitevent = event
+ self.idx = 0
+ def run(self):
+ logging.debug("th_send_loop %s: run" % self.getName())
+ while not self.exitevent.isSet():
+ self.idx += self.port.send(self.data)
+ logging.debug("th_send_loop %s: exit(%d)" % (self.getName(), \
+ self.idx))
+
+ class th_recv(Thread):
+ """
+ Random data reciever/checker thread
+ """
+ def __init__(self, port, buffer, length, blocklen=32):
+ """
+ @param port: source port
+ @param buffer: control data buffer (FIFO)
+ @param length: amount of data we want to receive
+ @param blocklen: block length
+ """
+ Thread.__init__(self)
+ self.ExitState = True
+ self.port = port[0]
+ self.buffer = buffer
+ self.length = length
+ self.blocklen = blocklen
+ def run(self):
+ logging.debug("th_recv %s: run" % self.getName())
+ idx = 0
+ while idx < self.length:
+ ret = select.select([self.port], [], [], 1.0)
+ if ret:
+ buf = self.port.recv(self.blocklen)
+ if buf:
+ # Compare the recvd data with the control data
+ for ch in buf:
+ if not ch == self.buffer.popleft():
+ error.TestFail("th_recv: incorrect data")
+ idx += len(buf)
+ logging.debug("th_recv %s: exit(%d)" % (self.getName(), idx))
+ if (idx >= self.length) and (len(self.buffer) == 0):
+ self.ExitState = False
+
+ class th_recv_null(Thread):
+ """
+ Recieves data and throw them away
+ """
+ def __init__(self, port, event, blocklen=32):
+ """
+ @param port: data source port
+ @param event: exit event
+ @param blocklen: block length
+ """
+ Thread.__init__(self)
+ self.port = port[0]
+ self._port_timeout = self.port.gettimeout()
+ self.port.settimeout(0.1)
+ self.exitevent = event
+ self.blocklen = blocklen
+ self.idx = 0
+ def run(self):
+ logging.debug("th_recv_null %s: run" % self.getName())
+ while not self.exitevent.isSet():
+ # Workaround, it didn't work with select :-/
+ try:
+ self.idx += len(self.port.recv(self.blocklen))
+ except socket.timeout:
+ pass
+ self.port.settimeout(self._port_timeout)
+ logging.debug("th_recv_null %s: exit(%d)" % (self.getName(), \
+ self.idx))
+
+ seqTest = threading.Lock();
+
+ class averageCpuLoad():
+ """
+ Get average cpu load between start and getLoad
+ """
+ def __init__ (self):
+ self.old_load = [0,0,0,0,0,0,0,0,0,0]
+ self.startTime = 0;
+ self.endTime = 0;
+
+ def _get_cpu_load(self):
+ # Let's try if we can calc system load.
+ try:
+ f = open("/proc/stat", "r")
+ tmp = f.readlines(200)
+ f.close()
+ except:
+ self.log_entry(severity['CRIT'], "Something went terribly" \
+ "wrong when trying to open /proc/stat")
+ error.TestFail("averageCpuLoad: Error reading /proc/stat")
+ # 200 bytes should be enough because the information we need
+ # ist typically stored in the first line
+
+ # Info about individual processors (not yet supported) is in
+ # the second (third, ...?) line
+ for line in tmp:
+ if line[0:4] == "cpu ":
+ reg = re.compile('[0-9]+')
+ load_values = reg.findall(line)
+ # extract values from /proc/stat
+ load = [0,0,0,0,0,0,0,0,0,0]
+ for i in range(8):
+ load[i] = int(load_values[i])-self.old_load[i]
+
+ for i in range(8):
+ self.old_load[i] = int(load_values[i])
+ return load
+
+
+ def start ( self ):
+ """
+ Start CPU usage measurement
+ """
+ self.startTime = time.time();
+ self._get_cpu_load()
+
+ def getLoad(self):
+ """
+ Get and reset CPU usage
+ @return: return group cpu (user[%],system[%],sum[%],testTime[s])
+ """
+ self.endTime = time.time()
+ testTime = self.endTime-self.startTime
+ load = self._get_cpu_load()
+
+ user = load[0]/testTime
+ system = load[2]/testTime
+ sum = user + system
+
+ return (user,system,sum,testTime)
+
+
+ class averageProcessCpuLoad():
+ """
+ Get average process cpu load between start and getLoad
+ """
+ def __init__ (self, pid, name):
+ self.old_load = [0,0]
+ self.startTime = 0;
+ self.endTime = 0;
+ self.pid = pid
+ self.name = name
+
+ def _get_cpu_load(self,pid):
+ # Let's try if we can calc system load.
+ try:
+ f = open("/proc/%d/stat" % (pid), "r")
+ line = f.readline()
+ f.close()
+ except:
+ self.log_entry(severity['CRIT'],\
+ "Something went terribly wrong when" + \
+ "trying to open /proc/%d/stat" % (pid))
+ error.TestFail("averageProcessCpuLoad: Error reading " \
+ "/proc/stat")
+ else:
+ reg = re.compile('[0-9]+')
+ load_values = reg.findall(line)
+ del load_values[0:11]
+ # extract values from /proc/stat
+ load = [0,0]
+ for i in range(2):
+ load[i] = int(load_values[i])-self.old_load[i]
+
+ for i in range(2):
+ self.old_load[i] = int(load_values[i])
+ return load
+
+ def start ( self ):
+ """
+ Start CPU usage measurement
+ """
+ self.startTime = time.time();
+ self._get_cpu_load(self.pid)
+
+ def getLoad(self):
+ """
+ Get and reset CPU usage
+ @return: return group cpu (pid,user[%],system[%],sum[%],testTime[s])
+ """
+ self.endTime = time.time()
+ testTime = self.endTime-self.startTime
+ load = self._get_cpu_load(self.pid)
+
+ user = load[0]/testTime
+ system = load[1]/testTime
+ sum = user+system
+
+ return (self.name, self.pid,user,system,sum,testTime)
+
+ def print_load(process,system):
+ """
+ Print load in tabular mode
+
+ @param process: list of process statistic tuples
+ @param system: tuple of system cpu usage
+ """
+
+ logging.info("%-10s %6s %5s %5s %5s %11s" \
+ % ("NAME", "PID","USER","SYS","SUM","TIME"))
+ for pr in process:
+ logging.info("%-10s %6d %4.0f%% %4.0f%% %4.0f%% %10.3fs" % pr)
+ logging.info("TOTAL: ------ %4.0f%% %4.0f%% %4.0f%% %10.3fs" \
+ % system)
+
+ def process_stats(stats, scale=1.0):
+ """
+ Process and print the statistic
+
+ @param stats: list of measured data
+ """
+ if not stats:
+ return None
+ for i in range((len(stats)-1),0,-1):
+ stats[i] = stats[i] - stats[i-1]
+ stats[i] /= scale
+ stats[0] /= scale
+ stats = sorted(stats)
+ return stats
+
+ def _start_consoleSwitch(vm, timeout=2):
+ """
+ Execute consoleSwitch.py on guest; wait until it is initialized.
+
+ @param vm: Informations about the guest.
+ @param timeout: Timeout that will be used to verify if the script
+ started properly.
+ """
+ logging.debug("Starting consoleSwitch.py on guest %s", vm[0].name)
+ vm[1].sendline("python /tmp/consoleSwitch.py")
+ (match, data) = vm[1].read_until_last_line_matches(["PASS:", "FAIL:"],
+ timeout)
+ if match == 1 or match is None:
+ raise error.TestFail("Command consoleSwitch.py on guest %s failed."\
+ "\nreturn code: %s\n output:\n%s" \
+ % (vm[0].name, match, data))
+
+ def _execute_consoleSwitch(command, vm, timeout=2):
+ """
+ Execute given command inside the script's main loop, indicating the vm
+ the command was executed on.
+
+ @param command: Command that will be executed.
+ @param vm: Informations about the guest
+ @param timeout: Timeout used to verify expected output.
+
+ @return: Tuple (match index, data)
+ """
+ logging.debug("Executing '%s' on consoleSwitch.py loop, vm: %s," +
+ "timeout: %s", command, vm[0].name, timeout)
+ vm[1].sendline(command)
+ (match, data) = vm[1].read_until_last_line_matches(["PASS:","FAIL:"],
+ timeout)
+ if match == 1 or match is None:
+ raise error.TestFail("Failed to execute '%s' on consoleSwitch.py, "
+ "vm: %s, output:\n%s" %
+ (command, vm[0].name, data))
+ return (match, data)
+
+ def socket_readall(sock,read_timeout,mesagesize):
+ """
+ Read everything from the socket
+
+ @param sock: socket
+ @param read_timeout: read timeout
+ @param mesagesize: size of message
+ """
+ sock_decriptor = sock.fileno()
+ sock.settimeout(read_timeout)
+ message = ""
+ try:
+ while (len(message) < mesagesize):
+ message += sock.recv(mesagesize)
+ except Exception as inst:
+ if (inst.args[0] == "timed out"):
+ logging.debug("Reading timeout")
+ else:
+ logging.debug(inst)
+ sock.setblocking(1)
+ return message
+
+ def _vm_create(no_console=3,no_serialport=3):
+ """
+ Creates the VM and connects the specified number of consoles and serial
+ ports
+
+ @param no_console: number of desired virtconsoles
+ @param no_serialport: number of desired virtserialports
+ @return tupple with (guest information, consoles information)
+ guest informations = [vm, session, tmp_dir]
+ consoles informations = [consoles[], serialports[]]
+ """
+ consoles = []
+ serialports = []
+ tmp_dir = tempfile.mkdtemp(prefix="virtio-console-", dir="/tmp/")
+ if not params.get('extra_params'):
+ params['extra_params'] = ''
+ params['extra_params'] += " -device virtio-serial"
+
+ for i in range(0, no_console):
+ params['extra_params'] +=\
+ " -chardev socket,path=%s/%d,id=%d,server,nowait"\
+ % (tmp_dir, i, i)
+ params['extra_params'] += " -device virtconsole,chardev=%d,"\
+ "name=org.fedoraproject.console.%d,id=c%d"\
+ % (i,i,i)
+
+ for i in range(no_console, no_console + no_serialport):
+ params['extra_params'] +=\
+ " -chardev socket,path=%s/%d,id=%d,server,nowait"\
+ % (tmp_dir, i, i)
+ params['extra_params'] += " -device virtserialport,chardev=%d,"\
+ "name=org.fedoraproject.data.%d,id=p%d"\
+ % (i,i,i)
+
+
+ logging.debug("Booting first guest %s", params.get("main_vm"))
+ kvm_preprocessing.preprocess_vm(test, params, env,
+ params.get("main_vm"))
+
+
+ vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
+
+ session = kvm_test_utils.wait_for_login(vm, 0,
+ float(params.get("boot_timeout", 240)),
+ 0, 2)
+
+ # connect the sockets
+ for i in range(0, no_console):
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ sock.connect("%s/%d" % (tmp_dir, i))
+ consoles.append([sock, \
+ "org.fedoraproject.console.%d" % i, \
+ "yes"])
+ for i in range(no_console, no_console + no_serialport):
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ sock.connect("%s/%d" % (tmp_dir, i))
+ serialports.append([sock, \
+ "org.fedoraproject.data.%d" %i, \
+ "no"])
+
+ return [vm, session, tmp_dir], [consoles, serialports]
+
+ def test_smoke(vm, consoles, params):
+ """
+ Creates loopback on the vm machine between providen ports[>=2] and
+ sends the data
+
+ @param vm: target virtual machine [vm, session, tmp_dir]
+ @param consoles: a field of virtio ports with the minimum of 2 items
+ @param params: test parameters '$console_type:$data;...'
+ """
+ # PREPARE
+ for param in params.split(';'):
+ if not param:
+ continue
+ logging.info("test_smoke: PARAMS: %s" % param)
+ param = param.split(':')
+ if len(param) > 1:
+ data = param[1]
+ else:
+ data = "Smoke test data"
+ param = (param[0]=='serialport')
+ send_pt = consoles[param][0]
+ recv_pt = consoles[param][1]
+ _start_consoleSwitch(vm, 10.0)
+
+ # TEST
+ _execute_consoleSwitch('startswitch([%s], [%s])' % (
+ str(send_pt[1:3]),
+ str(recv_pt[1:3])
+ ), vm, 2.0)
+
+ send_pt[0].sendall(data)
+ d = socket_readall(recv_pt[0], 1.0, len(data))
+ if data != d:
+ raise error.TestFail("test_smoke: Error, recieved data"\
+ " doesn't match the original")
+ else:
+ logging.info("test_smoke: data = %s" % d)
+
+
+ vm[1].sendline("die()")
+
+ def test_loopback(vm, consoles, params):
+ """
+ Creates loopback on the vm machine between send_pt and recv_pts
+ ports and sends length amount of data through this connection.
+ It validates the correctness of those data
+
+ @param vm: target virtual machine [vm, session, tmp_dir]
+ @param consoles: a field of virtio ports with the minimum of 2 items
+ @param params: test parameters, multiple recievers allowed.
+ '$source_console_type@buffer_length:
+ $destination_console_type1@buffer_length:...:
+ $loopback_buffer_length;...'
+ """
+ # PREPARE
+ for param in params.split(';'):
+ if not param:
+ continue
+ logging.info("test_loopback: PARAMS: %s" % param)
+ param = param.split(':')
+ idx_serialport = 0
+ idx_console = 0
+ buf_len = []
+ if (param[0].startswith('console')):
+ send_pt = consoles[0][idx_console]
+ idx_console += 1
+ else:
+ send_pt = consoles[1][idx_serialport]
+ idx_serialport += 1
+ if (len(param[0].split('@')) == 2):
+ buf_len.append(int(param[0].split('@')[1]))
+ else:
+ buf_len.append(32)
+ recv_pts = []
+ for parm in param[1:]:
+ if (parm.isdigit()):
+ buf_len.append(int(parm))
+ break # buf_len is the last portion of param
+ if (parm.startswith('console')):
+ recv_pts.append(consoles[0][idx_console])
+ idx_console += 1
+ else:
+ recv_pts.append(consoles[1][idx_serialport])
+ idx_serialport += 1
+ if (len(parm[0].split('@')) == 2):
+ buf_len.append(int(parm[0].split('@')[1]))
+ else:
+ buf_len.append(32)
+ # There must be sum(idx_*) consoles + last item as loopback buf_len
+ if len(buf_len) == (idx_console + idx_serialport):
+ buf_len.append(32)
+
+ if len(recv_pts) == 0:
+ raise error.TestFail("test_loopback: incorrect recv consoles"
+ "definition")
+ threads = []
+ buffers = []
+ for i in range(0, len(recv_pts)):
+ buffers.append(deque())
+
+ _start_consoleSwitch(vm, 10.0)
+ tmp = str(recv_pts[0][1:3])
+ for recv_pt in recv_pts[1:]:
+ tmp += ", " + str(recv_pt[1:3])
+ _execute_consoleSwitch('startswitch([%s], [%s], %d)' % (
+ str(send_pt[1:3]), tmp, buf_len[-1]
+ ), vm, 2.0)
+
+ # TEST
+ thread = th_send(send_pt, 1048576, buffers, buf_len[0])
+ thread.start()
+ threads.append(thread)
+
+ for i in range(len(recv_pts)):
+ thread = th_recv(recv_pts[i], buffers[i], 1048576,
+ buf_len[i+1])
+ thread.start()
+ threads.append(thread)
+
+ death = False
+ # Send+recv threads, DL 60s
+ for i in range(60):
+ for thread in threads:
+ if not thread.is_alive():
+ if thread.ExitState:
+ error.TestFail("test_loopback send/recv thread" \
+ " failed")
+ death = True
+ if death:
+ break
+ tmp = ""
+ for buf in buffers:
+ tmp += str(len(buf)) + ", "
+ logging.debug("test_loopback: buffer length (%s)" % (tmp[:-2]))
+ time.sleep(1)
+
+ if not death:
+ raise error.TestFail("test_loopback send/recv timeout")
+ # at this point at least one thread died. It should be the send one.
+
+ # Wait for recv threads to finish their's work
+ for i in range(60):
+ death = True
+ for thread in threads:
+ if thread.is_alive():
+ death = False
+ # There are no living threads
+ if death:
+ break
+ tmp = ""
+ for buf in buffers:
+ tmp += str(len(buf)) + ", "
+ logging.debug("test_loopback: buffer length (%s)" % (tmp[:-2]))
+ time.sleep(1)
+
+ for thread in threads:
+ if thread.ExitState:
+ error.TestFail("test_loopback recv thread failed")
+
+ # At least one thread is still alive
+ if not death:
+ raise error.TestFail("test_loopback recv timeout")
+
+ vm[1].sendline("die()")
+
+ def test_perf(vm, consoles, params):
+ """
+ Tests performance of the virtio_console tunel. First it sends the data
+ from host to guest and than back. It provides informations about
+ computer utilisation and statistic informations about the troughput.
+
+ @param vm: target virtual machine [vm, session, tmp_dir]
+ @param consoles: a field of virtio ports with the minimum of 2 items
+ @param params: test parameters:
+ '$console_type@buffer_length:$test_duration;...'
+ """
+ # PREPARE
+ for param in params.split(';'):
+ if not param:
+ continue
+ logging.info("test_perf: PARAMS:%s" % param)
+ param = param.split(':')
+ if len(param) > 1 and param[1].isdigit():
+ duration = float(param[1])
+ else:
+ duration = 30.0
+ param = param[0].split('@')
+ if len(param) > 1 and param[1].isdigit():
+ buf_len = int(param[1])
+ else:
+ buf_len = 32
+ if param[0] == "serialport":
+ port = consoles[1][0]
+ else:
+ port = consoles[0][0]
+ data = array.array("L")
+ for i in range(max((buf_len / data.itemsize), 1)):
+ data.append(random.randrange(sys.maxint))
+
+ ev = threading.Event()
+ thread = th_send_loop(port[0], data.tostring(), ev)
+
+ _start_consoleSwitch(vm, 10.0)
+
+ _execute_consoleSwitch('startswitch([%s], [], %d)' % (
+ str(port[1:3]),
+ buf_len,
+ ), vm, 2.0)
+
+ # TEST
+ # Host -> Guest
+ load = []
+ stats = array.array('f', [])
+ slice = float(duration)/100
+ load.append(averageCpuLoad())
+ load.append(averageProcessCpuLoad(os.getpid(), 'autotest'))
+ load.append(averageProcessCpuLoad(vm[0].get_pid(), 'VM'))
+ for ld in load:
+ ld.start()
+ _time = time.time()
+ thread.start()
+ for i in range(100):
+ stats.append(thread.idx)
+ time.sleep(slice)
+ _time = time.time() - _time - duration
+ print_load([load[1].getLoad(), load[2].getLoad()], \
+ load[0].getLoad())
+ ev.set()
+ thread.join()
+ if (_time > slice):
+ logging.error(
+ "Test ran %fs longer which is more than one slice" % _time)
+ else:
+ logging.debug("Test ran %fs longer" % _time)
+ stats = process_stats(stats[1:], slice*1024*1024)
+ logging.info("Host->Guest [mb/s] min/med/max = %.3f/%.3f/%.3f" \
+ % (stats[0], stats[len(stats)/2], stats[-1]))
+ time.sleep(5)
+ vm[1].sendline("die()")
+
+ # Guest -> Host
+ _start_consoleSwitch(vm, 10.0)
+ _execute_consoleSwitch('senderprepare(%s, %d)' % (
+ str(port[1:3]),
+ buf_len,
+ ), vm, 10)
+ stats = array.array('f', [])
+ ev.clear()
+ thread = th_recv_null(port, ev, buf_len)
+ thread.start()
+ # reset load measures
+ for ld in load:
+ ld.getLoad()
+ _execute_consoleSwitch('senderstart()', vm, 2)
+ _time = time.time()
+ for i in range(100):
+ stats.append(thread.idx)
+ time.sleep(slice)
+ _time = time.time() - _time - duration
+ print_load([load[1].getLoad(), load[2].getLoad()], \
+ load[0].getLoad())
+ vm[1].sendline("die()")
+ time.sleep(5)
+ ev.set()
+ thread.join()
+ if (_time > slice): # Deviation is higher than 1 slice
+ logging.error(
+ "Test ran %fs longer which is more than one slice" % _time)
+ else:
+ logging.debug("Test ran %fs longer" % _time)
+ stats = process_stats(stats[1:], slice*1024*1024)
+ logging.info("Guest->Host [mb/s] min/med/max = %.3f/%.3f/%.3f" \
+ % (stats[0], stats[len(stats)/2], stats[-1]))
+ for ld in load:
+ del(ld)
+
+
+ # INITIALIZE
+ test_smoke_params = params.get('virtio_console_smoke', '')
+ test_loopback_params = params.get('virtio_console_loopback', '')
+ test_perf_params = params.get('virtio_console_perf', '')
+
+ no_serialports = 0
+ no_consoles = 0
+ # consoles required for Smoke test
+ if (test_smoke_params.count('serialport')):
+ no_serialports = max(2, no_serialports)
+ if (test_smoke_params.count('console')):
+ no_consoles = max(2, no_consoles)
+ # consoles required for Loopback test
+ for param in test_loopback_params.split(';'):
+ no_serialports = max(no_serialports, param.count('serialport'))
+ no_consoles = max(no_consoles, param.count('console'))
+ # consoles required for Performance test
+ if (test_perf_params.count('serialport')):
+ no_serialports = max(1, no_serialports)
+ if (test_perf_params.count('console')):
+ no_consoles = max(1, no_consoles)
+
+ vm, consoles = _vm_create(no_consoles, no_serialports)
+
+ # Copy allocator.py into guests
+ pwd = os.path.join(os.environ['AUTODIR'],'tests/kvm')
+ vksmd_src = os.path.join(pwd, "scripts/consoleSwitch.py")
+ dst_dir = "/tmp"
+ if not vm[0].copy_files_to(vksmd_src, dst_dir):
+ raise error.TestFail("copy_files_to failed %s" % vm[0].name)
+
+ # ACTUAL TESTING
+ test_smoke(vm, consoles, test_smoke_params)
+ test_loopback(vm, consoles, test_loopback_params)
+ test_perf(vm, consoles, test_perf_params)
+
+
+ # CLEANUP
+ vm[1].close()
+ vm[0].destroy(gracefully = False)
+ shutil.rmtree(vm[2])
diff --git a/client/tests/kvm/tests_base.cfg.sample b/client/tests/kvm/tests_base.cfg.sample
index cb727c4..2773ea2 100644
--- a/client/tests/kvm/tests_base.cfg.sample
+++ b/client/tests/kvm/tests_base.cfg.sample
@@ -380,6 +380,13 @@ variants:
ksm_mode = "parallel"
- iofuzz:
type = iofuzz
+
+ - virtio_console:
+ vms = ''
+ type = virtio_console
+ virtio_console_smoke = "serialport;console:Custom data"
+ virtio_console_loopback = "serialport:serialport;serialport@1024:serialport@32:console@1024:console@8:16"
+ virtio_console_perf = "serialport;serialport@1000000:120;console@1024:60"
# This unit test module is for older branches of KVM that use the
# kvmctl test harness (such as the code shipped with RHEL 5.x)
--
1.7.2.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [KVM-autotest] virtio_console test
2010-08-20 13:40 [KVM-autotest] virtio_console test Lukas Doktor
2010-08-20 13:40 ` [PATCH] NEW " Lukas Doktor
@ 2010-08-20 14:12 ` Lukáš Doktor
2010-08-23 7:53 ` Amit Shah
1 sibling, 1 reply; 6+ messages in thread
From: Lukáš Doktor @ 2010-08-20 14:12 UTC (permalink / raw)
To: Lukas Doktor; +Cc: jzupka, autotest, kvm, akong
Dne 20.8.2010 15:40, Lukas Doktor napsal(a):
> Hi,
>
> This patch adds new test for virtio_console. It supports booth, serialport and console, virtio_console types and it contains three tests:
> 1) smoke
> 2) loopback
> 3) perf
>
>
> Before any tests are executed it starts the machine with required number of virtio_consoles. Than it allows user to run all three tests. Using the parameters user can control which tests are executed and what setting is used. All tests supports multiple run using ';' separated list of settings. Most of the settings are optional only. The mandatory ones are written in CAPITALS.
>
> ad1) virtio_console_smoke format:
> $VIRTIO_CONSOLE_TYPE:$custom_data
>
> It creates a loopback via $VIRTIO_CONSOLE_TYPE console and sends $custom_data. If the received data match the original test pass
>
> ad2) virtio_console_loopback format:
> $SOURCE_CONSOLE_TYPE@$buffer_length:$DESTINATION_CONSOLE1_TYPE@$buffer_length:...:$DESTINATION_CONSOLEx_TYPE@$buffer_length:$loopback_buffer_length
>
> Creates loopback between the $SOURCE_CONSOLE_TYPE console and all following $DESTINATION_CONSOLEn_TYPE consoles. Than it sends data by $buffer_length to the source port. The loopback resends the data by $loopback_buffer_length to all destination consoles. The test listens on the destination consoles and controls the received data.
>
> NOTE: in the debug mode you can see the send/received data's buffers in every second during the test.
>
> ad3) virtio_console_perf format:
> $VIRTIO_CONSOLE_TYPE@$buffer_size:$test_duration
>
> First it sends the prepared data in a loop over $VIRTIO_CONSOLE_TYPE console from host to guest. Guest only reads all the data and throw them away. This part runs $test_duration seconds.
> Second it does the same from guest to host.
>
> For booth runs it provides information of minimum/median/maximum throughput and guest/host average loads.
>
>
> Best regards,
> Lukas Doktor
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
Just a note about kernels:
serialport works great but console have big issues. Use kernels >=
2.6.35 for testing.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [KVM-autotest] virtio_console test
2010-08-20 14:12 ` [KVM-autotest] " Lukáš Doktor
@ 2010-08-23 7:53 ` Amit Shah
2010-08-23 13:20 ` Lukáš Doktor
0 siblings, 1 reply; 6+ messages in thread
From: Amit Shah @ 2010-08-23 7:53 UTC (permalink / raw)
To: Lukáš Doktor; +Cc: jzupka, autotest, kvm, akong
On (Fri) Aug 20 2010 [16:12:51], Lukáš Doktor wrote:
> Dne 20.8.2010 15:40, Lukas Doktor napsal(a):
> >Hi,
> >
> >This patch adds new test for virtio_console. It supports booth, serialport and console, virtio_console types and it contains three tests:
> >1) smoke
> >2) loopback
> >3) perf
This is great, thanks for the tests.
I was working with Lucas at the KVM Forum to get my virtio-console tests
integrated upstream. I have a few micro tests that test correctness of
various bits in the virtio_console code:
http://fedorapeople.org/gitweb?p=amitshah/public_git/test-virtserial.git
It would be great to sync up with Lucas and add those tests to autotest
as well.
Eventually, I'd also like to adapt the C code to python so that it
integrates with KVM-autotest.
> Just a note about kernels:
> serialport works great but console have big issues. Use kernels >=
> 2.6.35 for testing.
Can you tell me what the issues are? I test console io in the testsuite
mentioned above and it's been passing fine.
Amit
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [KVM-autotest] virtio_console test
2010-08-23 7:53 ` Amit Shah
@ 2010-08-23 13:20 ` Lukáš Doktor
2010-08-23 13:42 ` Amit Shah
0 siblings, 1 reply; 6+ messages in thread
From: Lukáš Doktor @ 2010-08-23 13:20 UTC (permalink / raw)
To: Amit Shah; +Cc: jzupka, autotest, kvm, akong
Hi Amit,
Dne 23.8.2010 09:53, Amit Shah napsal(a):
> On (Fri) Aug 20 2010 [16:12:51], Lukáš Doktor wrote:
>> Dne 20.8.2010 15:40, Lukas Doktor napsal(a):
>>> Hi,
>>>
>>> This patch adds new test for virtio_console. It supports booth, serialport and console, virtio_console types and it contains three tests:
>>> 1) smoke
>>> 2) loopback
>>> 3) perf
>
> This is great, thanks for the tests.
>
> I was working with Lucas at the KVM Forum to get my virtio-console tests
> integrated upstream. I have a few micro tests that test correctness of
> various bits in the virtio_console code:
>
> http://fedorapeople.org/gitweb?p=amitshah/public_git/test-virtserial.git
yes, I'm aware of your tests and the fedora page about virtio-console. I
took an inspiration from them ;-) (thanks)
>
> It would be great to sync up with Lucas and add those tests to autotest
> as well.
I went through the code trying to find tests missing in our autotest
virtio_console.py test. Correct me if I'm wrong, but the missing tests are:
* variations on opening/writing/reading host/guest closed/open consoles
and check the right handling
* guest caching (if necessarily)
>
> Eventually, I'd also like to adapt the C code to python so that it
> integrates with KVM-autotest.
>
Yes, either you or I can do that. I would just need the
test-requirement-list.
>> Just a note about kernels:
>> serialport works great but console have big issues. Use kernels>=
>> 2.6.35 for testing.
>
> Can you tell me what the issues are? I test console io in the testsuite
> mentioned above and it's been passing fine.
>
Sometimes on F13 there were Oops while booting guests with virtconsoles.
Also the sysfs informations about virtconsoles were sometimes
mismatched. With vanilla kernel 2.6.35 it worked better with occasional
Oops while booting the guest.
My colleague was working on that part so when he's back from holiday he
can provide more information.
With virtserialport it always worked correctly.
> Amit
Lukáš
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [KVM-autotest] virtio_console test
2010-08-23 13:20 ` Lukáš Doktor
@ 2010-08-23 13:42 ` Amit Shah
0 siblings, 0 replies; 6+ messages in thread
From: Amit Shah @ 2010-08-23 13:42 UTC (permalink / raw)
To: Lukáš Doktor; +Cc: jzupka, autotest, kvm, akong
On (Mon) Aug 23 2010 [15:20:17], Lukáš Doktor wrote:
> Hi Amit,
>
> Dne 23.8.2010 09:53, Amit Shah napsal(a):
> >On (Fri) Aug 20 2010 [16:12:51], Lukáš Doktor wrote:
> >>Dne 20.8.2010 15:40, Lukas Doktor napsal(a):
> >>>Hi,
> >>>
> >>>This patch adds new test for virtio_console. It supports booth, serialport and console, virtio_console types and it contains three tests:
> >>>1) smoke
> >>>2) loopback
> >>>3) perf
> >
> >This is great, thanks for the tests.
> >
> >I was working with Lucas at the KVM Forum to get my virtio-console tests
> >integrated upstream. I have a few micro tests that test correctness of
> >various bits in the virtio_console code:
> >
> >http://fedorapeople.org/gitweb?p=amitshah/public_git/test-virtserial.git
>
> yes, I'm aware of your tests and the fedora page about
> virtio-console. I took an inspiration from them ;-) (thanks)
> >
> >It would be great to sync up with Lucas and add those tests to autotest
> >as well.
>
> I went through the code trying to find tests missing in our autotest
> virtio_console.py test. Correct me if I'm wrong, but the missing
> tests are:
>
> * variations on opening/writing/reading host/guest closed/open
> consoles and check the right handling
Mostly checking for the open/read/write/close semantics, poll(), a new
test that I added today for checking of blocking calls (read) in one
thread while doing write in another.
I actually want to add a lot more (and even convert existing ones) to
threads, since currently I can't guarantee that the guest commands are
processed before any subsequent host commands (this means threading in
the host, obviously).
> * guest caching (if necessarily)
Yes, guest caching isn't needed in the current code (they're kept around
from the previous code where we had such a thing).
> >Eventually, I'd also like to adapt the C code to python so that it
> >integrates with KVM-autotest.
>
> Yes, either you or I can do that. I would just need the
> test-requirement-list.
I'd much prefer someone else did it, as I'm not familiar with python
(yet).
I'll be willing to help you or whoever picks it up.
> >>Just a note about kernels:
> >>serialport works great but console have big issues. Use kernels>=
> >>2.6.35 for testing.
> >
> >Can you tell me what the issues are? I test console io in the testsuite
> >mentioned above and it's been passing fine.
>
> Sometimes on F13 there were Oops while booting guests with
> virtconsoles. Also the sysfs informations about virtconsoles were
> sometimes mismatched. With vanilla kernel 2.6.35 it worked better
> with occasional Oops while booting the guest.
I see. Can you give me any logs / oops messages / traces?
2.6.35 is the first kernel version to officially support the new
features and is complete barring a few fixes which I haven't pushed out
yet.
There's a chance that the F13 kernel doesn't have some fixes, but I did
backport all of them AFAIR.
> My colleague was working on that part so when he's back from holiday
> he can provide more information.
OK, let me know if you get more info.
Thanks,
Amit
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2010-08-23 13:42 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-08-20 13:40 [KVM-autotest] virtio_console test Lukas Doktor
2010-08-20 13:40 ` [PATCH] NEW " Lukas Doktor
2010-08-20 14:12 ` [KVM-autotest] " Lukáš Doktor
2010-08-23 7:53 ` Amit Shah
2010-08-23 13:20 ` Lukáš Doktor
2010-08-23 13:42 ` Amit Shah
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).