deleted file mode 100644
@@ -1,219 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-"""
-Auxiliary script used to send data between 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 = {}
-ev = threading.Event()
-threads = []
-
-DEBUGPATH="/sys/kernel/debug"
-
-
-class Switch(Thread):
- """
- Create a thread which sends 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):
- """
- Creates thread which sends random blocks 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 get_port_status():
- """
- Get info about ports from kernel debugfs.
-
- @return: ports dictionary of port properties
- """
- ports = {}
-
- not_present_msg = "FAIL: There's no virtio-ports dir in debugfs"
- 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 not_present_msg
- except:
- print not_present_msg
- else:
- viop_names = os.listdir('%s/virtio-ports' % DEBUGPATH)
- for name in viop_names:
- f = open("%s/virtio-ports/%s" % (DEBUGPATH, name), 'r')
- port = {}
- 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 works like a serialport
- else:
- port["path"] = "/dev/%s" % name
- ports[port['name']] = port
- f.close()
-
- return ports
-
-
-def open_device(in_files, ports):
- """
- Open devices and return an array of descriptors.
-
- @param in_files: files array
- @return: array of descriptors
- """
- 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 to open file %s" % name
- raise inst
- return f
-
-
-def start_switch(in_files,out_files,cachesize=1):
- """
- Start a switch thread
- (because there is a problem with opening one file multiple times).
-
- @param in_files: array of input files
- @param out_files: array of output files
- @param cachesize: cachesize
- """
- ports = get_port_status()
-
- in_f = open_device(in_files, ports)
- out_f = open_device(out_files, ports)
-
- s = Switch(ev, in_f, out_f, cachesize)
- s.start()
- threads.append(s)
-
- print "PASS: Start switch"
-
-
-def end_switches():
- """
- End all running data switches.
- """
- 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)
- current_pid = os.getpid()
- os.kill(current_pid, 15)
-
-
-def sender_prepare(port, length):
- """
- Prepares the sender thread. Requires a clean thread structure.
- """
- del threads[:]
- ports = get_port_status()
- in_f = open_device([port], ports)
-
- threads.append(Sender(in_f[0], length))
- print "PASS: Sender prepare"
-
-
-def sender_start():
- """
- Start sender data transfer. Requires sender_prepare to run first.
- """
- threads[0].start()
- print "PASS: Sender start"
-
-
-def main():
- """
- Main (infinite) loop of console_switch.
- """
- print "PASS: Start"
- end = False
- while not end:
- str = raw_input()
- exec str
-
-
-if __name__ == "__main__":
- main()
new file mode 100644
@@ -0,0 +1,571 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+"""
+Auxiliary script used to send data between ports on guests.
+
+@copyright: 2008-2009 Red Hat Inc.
+@author: Jiri Zupka (jzupka@redhat.com)
+@author: Lukas Doktor (ldoktor@redhat.com)
+"""
+#from _pydev_SimpleXMLRPCServer import fcntl
+
+"""
+TODO:
+virt.init([consoles]) # sysfs, udev, OK
+virt.open(name)
+virt.close(name)
+virt.poll(name, eventmask, timeout) # poll.register(), poll.poll(),
+return event
+virt.send(name, length) # host disconnected
+virt.recv(name, length) # host disconnected
+virt.blocking(name, true) # true = blocking, false = nonblocking
+virt.loopback(in_names, out_names, type="None") # use select/poll
+"""
+
+import threading
+from threading import Thread
+import os, time, select, re, random, sys, array, fcntl, array, subprocess
+
+DEBUGPATH = "/sys/kernel/debug"
+SYSFSPATH = "/sys/class/virtio-ports/"
+
+
+class virtio_guest():
+
+ LOOP_NONE = 0
+ LOOP_POLL = 1
+ LOOP_SELECT = 2
+
+ def __init__(self):
+ self.files = {}
+ self.exit_thread = threading.Event()
+ self.threads = []
+ self.ports = {}
+
+ def _readfile(self, name):
+ """
+ Read file and return content as string
+
+ @param name: Name of file
+ @return: Content of file as string
+ """
+ out = ""
+ try:
+ f = open(name, "r")
+ out = f.read()
+ f.close()
+ except:
+ print "FAIL: Cannot open file %s" % (name)
+
+ return out
+
+ def _get_port_status(self):
+ """
+ Get info about ports from kernel debugfs.
+
+ @return: Ports dictionary of port properties
+ """
+ ports = {}
+ not_present_msg = "FAIL: There's no virtio-ports dir in debugfs"
+ 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 not_present_msg
+ except:
+ print not_present_msg
+ else:
+ viop_names = os.listdir('%s/virtio-ports' % (DEBUGPATH))
+ for name in viop_names:
+ f = open("%s/virtio-ports/%s" % (DEBUGPATH, name), 'r')
+ port = {}
+ 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 works like a serialport
+ else:
+ port["path"] = "/dev/%s" % name
+
+ if (not os.path.exists(port['path'])):
+ print "FAIL: %s not exist" % port['path']
+
+ sysfspath = SYSFSPATH + name
+ if (not os.path.isdir(sysfspath)):
+ print "FAIL: %s not exist" % (sysfspath)
+
+ info_name = sysfspath + "/name"
+ port_name = self._readfile(info_name).strip()
+ if (port_name != port["name"]):
+ print "FAIL: Port info not match \n%s - %s\n%s - %s" \
+ % (info_name , port_name, \
+ "%s/virtio-ports/%s" % (DEBUGPATH, name), port["name"])
+
+ ports[port['name']] = port
+ f.close()
+
+ return ports
+
+ def init(self, in_files):
+ """
+ Init and check port properties
+ """
+ self.ports = self._get_port_status()
+
+ for item in in_files:
+ if (item[1] != self.ports[item[0]]["is_console"]):
+ print self.ports
+ print "FAIL: Host console is not like console on guest side\n"
+ print "PASS: Init and check virtioconsole files in system."
+
+ class switch(Thread):
+ """
+ Create a thread which sends data between ports.
+ """
+ def __init__ (self, in_files, out_files, event, \
+ cachesize=1024, method=0):
+ """
+ @param in_files: Array of input files
+ @param out_files: Array of output files
+ @param method: Method of read/write access
+ @param cachesize: Block to receive and send
+ """
+ Thread.__init__(self)
+
+ self.in_files = in_files
+ self.out_files = out_files
+ self.exit_thread = event
+ self.method = method
+
+ self.cachesize = cachesize
+
+ def _none_mode(self):
+ """
+ Read and write to device in blocking mode
+ """
+ data = ""
+ while not self.exit_thread.isSet():
+ data = ""
+ for desc in self.in_files:
+ data += os.read(desc, self.cachesize)
+ if data != "":
+ for desc in self.out_files:
+ os.write(desc, data)
+
+ def _poll_mode(self):
+ """
+ Read and write to device in polling mode
+ """
+
+ pi = select.poll()
+ po = select.poll()
+
+ for fd in self.in_files:
+ pi.register(fd, select.POLLIN)
+
+ for fd in self.out_files:
+ po.register(fd, select.POLLOUT)
+ readyf = []
+ data = ""#array.array('B')
+ while not self.exit_thread.isSet():
+ data = ""
+ t_out = self.out_files
+
+ readyf = pi.poll(1.0)
+ for i in readyf:
+ try:
+ data += os.read(desc, self.cachesize)
+ except EOFError:
+ pass
+
+ if data.count(x):
+ readyf = []
+ while (len(t_out) != len(readyf)) and \
+ not self.exit_thread.isSet():
+ readyf = po.poll(1.0)
+ for desc in t_out:
+ os.write(desc, data)
+
+
+
+ def _select_mode(self):
+ """
+ Read and write to device in selecting mode
+ """
+ data = ""
+ ret = []
+ while not self.exit_thread.isSet():
+ #TODO: Why select causes trouble? :-(
+ ret = select.select(self.in_files, [], [], 1.0)
+ data = ""
+ if ret[0] != []:
+ for desc in ret[0]:
+ data += os.read(desc, self.cachesize)
+ if data != "":
+ ret = select.select([], self.out_files, [], 1.0)
+ while (len(self.out_files) != len(ret[1])) and \
+ not self.exit_thread.isSet():
+ ret = select.select([], self.out_files, [], 1.0)
+ for desc in ret[1]:
+ os.write(desc, data)
+
+ def run(self):
+ if (self.method == virtio_guest.LOOP_POLL):
+ self._poll_mode()
+ elif (self.method == virtio_guest.LOOP_SELECT):
+ self._select_mode()
+ else:
+ self._none_mode()
+
+ def _poll_mode(self):
+ """
+ Read and write to device in polling mode
+ """
+
+ pi = select.poll()
+ po = select.poll()
+
+ for fd in self.in_files:
+ pi.register(fd, select.POLLIN)
+
+ for fd in self.out_files:
+ po.register(fd, select.POLLOUT)
+
+ while not self.exit_thread.isSet():
+ data = ""
+ t_out = self.out_files
+
+ readyf = pi.poll(1.0)
+ for i in readyf:
+ data += os.read(i[0], self.cachesize)
+
+ if data != "":
+ while (len(t_out) != len(readyf)) and \
+ not self.exit_thread.isSet():
+ readyf = po.poll(1.0)
+ for desc in t_out:
+ os.write(desc, data)
+
+
+
+ def _select_mode(self):
+ """
+ Read and write to device in selecting mode
+ """
+ while not self.exit_thread.isSet():
+ #TODO: Why select causes trouble? :-(
+ ret = select.select(self.in_files, [], [], 1.0)
+ data = ""
+ if ret[0] != []:
+ for desc in ret[0]:
+ data += os.read(desc, self.cachesize)
+ if data != "":
+ ret = select.select([], self.out_files, [], 1.0)
+ while (len(self.out_files) != len(ret[1])) and \
+ not self.exit_thread.isSet():
+ ret = select.select([], self.out_files, [], 1.0)
+ for desc in ret[1]:
+ os.write(desc, data)
+
+ def run(self):
+ if (self.method == virtio_guest.LOOP_POLL):
+ self._poll_mode()
+ elif (self.method == virtio_guest.LOOP_SELECT):
+ self._select_mode()
+ else:
+ self._none_mode()
+
+ class sender(Thread):
+ """
+ Creates thread which sends random blocks of data to the destination
+ port.
+ """
+ def __init__(self, port, event, length):
+ """
+ @param port: Destination port
+ @param length: Length of the random data block
+ """
+ Thread.__init__(self)
+ self.port = port
+ self.exit_thread = event
+ 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 not self.exit_thread.isSet():
+ os.write(self.port, self.data)
+
+
+ def _open(self, in_files):
+ """
+ Open devices and return array of descriptors
+
+ @param in_files: Files array
+ @return: Array of descriptor
+ """
+
+ f = []
+
+ for item in in_files:
+ name = self.ports[item]["path"]
+ if (name in self.files):
+ f.append(self.files[name])
+ else:
+ try:
+ self.files[name] = os.open(name, os.O_RDWR)
+ if (self.ports[item]["is_console"] == "yes"):
+ print os.system("stty -F %s raw -echo" % (name))
+ print os.system("stty -F %s -a" % (name))
+ f.append(self.files[name])
+ except Exception as inst:
+ print "FAIL: Failed to open file %s" % (name)
+ raise inst
+ return f
+
+
+ def poll(self, port, expected, timeout=500):
+ """
+ Pool event from device and print event like text
+
+ @param file: Device
+ """
+
+ in_f = self._open([port])
+
+ p = select.poll()
+ p.register(in_f[0])
+
+ mask = p.poll(timeout)
+
+ str = ""
+ if (mask[0][1] & select.POLLIN):
+ str += "IN "
+ if (mask[0][1] & select.POLLPRI):
+ str += "PRI IN "
+ if (mask[0][1] & select.POLLOUT):
+ str += "OUT "
+ if (mask[0][1] & select.POLLERR):
+ str += "ERR "
+ if (mask[0][1] & select.POLLHUP):
+ str += "HUP "
+ if (mask[0][1] & select.POLLMSG):
+ str += "MSG "
+
+ if (mask[0][1] & expected) == expected:
+ print "PASS: Events: " + str
+ else:
+ print "FAIL: Events: " + str
+
+
+ def blocking(self, port, mode=False):
+ """
+ Set port function mode blocking/nonblocking
+
+ @param port: port to set mode
+ @param mode: False to set nonblock mode, True for block mode
+ """
+ path = self.ports[port]["path"]
+ fd = self.files[path]
+
+ try:
+ fl = fcntl.fcntl(fd, fcntl.F_GETFL)
+ if not mode:
+ fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
+ else:
+ fcntl.fcntl(fd, fcntl.F_SETFL, fl & ~os.O_NONBLOCK)
+
+ except Exception as inst:
+ print "FAIL: Setting (non)blocking mode: " + str(inst)
+ return
+
+ print "PASS: set blocking mode to %s mode" % \
+ ("blocking" if mode else "nonblocking")
+
+
+ def close(self, file):
+ """
+ Close open port
+
+ @param file: file to close
+ """
+ descriptor = None
+ path = self.ports[file]["path"]
+ if path != None:
+ if path in self.files.keys():
+ descriptor = self.files[path]
+ del self.files[path]
+ try:
+ os.close(descriptor)
+ except Exception as inst:
+ print "FAIL: Closing the file: " + str(inst)
+ return
+ print "PASS: Close"
+
+ def open(self, in_files):
+ """
+ Direct open devices.
+
+ @param in_files: Files array
+ @return: Array of descriptor
+ """
+
+ name = self.ports[in_files]["path"]
+ try:
+ self.files[name] = os.open(name, os.O_RDWR)
+ print "PASS: Open all filles correctly."
+ except Exception as inst:
+ print "%s\nFAIL: Failed open file %s" % (str(inst), name)
+
+
+ def loopback(self, in_files, out_files, cachesize=1024, mode=LOOP_NONE):
+ """
+ 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
+ """
+
+
+ self.ports = self._get_port_status()
+
+ in_f = self._open(in_files)
+ out_f = self._open(out_files)
+
+ s = self.switch(in_f, out_f, self.exit_thread, cachesize, mode)
+ s.start()
+ self.threads.append(s)
+ print "PASS: Start switch"
+
+ def exit_threads(self):
+ """
+ Function end all running data switch.
+ """
+ self.exit_thread.set()
+ for th in self.threads:
+ print "join"
+ th.join()
+ self.exit_thread.clear()
+
+ del self.threads[:]
+ for desc in self.files.itervalues():
+ os.close(desc)
+ self.files.clear()
+ print "PASS: All threads finished."
+
+ def die(self):
+ """
+ Quit consoleswitch.
+ """
+ self.exit_threads()
+ exit()
+
+
+ def send_loop_init(self, port, length):
+ """
+ Prepares the sender thread. Requires clean thread structure.
+ """
+ self.ports = self._get_port_status()
+ in_f = self._open([port])
+
+ self.threads.append(self.sender(in_f[0], self.exit_thread, length))
+ print "PASS: Sender prepare"
+
+
+ def send_loop(self):
+ """
+ Start sender data transfer. Requires senderprepare run firs.
+ """
+ self.threads[0].start()
+ print "PASS: Sender start"
+
+
+ def send(self, port, length=1, mode=True):
+ """
+ Send a data of some length
+
+ @param port: Port to write data
+ @param length: Length of data
+ @param mode: True = loop mode, False = one shoot mode
+ """
+ in_f = self._open([port])
+
+ data = ""
+ while len(data) < length:
+ data += "%c" % random.randrange(255)
+ try:
+ writes = os.write(in_f[0], data)
+ except Exception as inst:
+ print inst
+ if not writes:
+ writes = 0
+ if mode:
+ while (writes < length):
+ try:
+ writes += os.write(in_f[0], data)
+ except Exception as inst:
+ print inst
+ if writes >= length:
+ print "PASS: Send data length %d" % writes
+ else:
+ print "FAIL: Partial send: desired %d, transfered %d" \
+ % (length, writes)
+
+
+ def recv(self, port, length=1, buffer=1024, mode=True):
+ """
+ Recv a data of some length
+
+ @param port: Port to write data
+ @param length: Length of data
+ @param mode: True = loop mode, False = one shoot mode
+ """
+ in_f = self._open([port])
+
+ recvs = ""
+ try:
+ recvs = os.read(in_f[0], buffer)
+ except Exception as inst:
+ print inst
+ if mode:
+ while (len(recvs) < length):
+ try:
+ recvs += os.read(in_f[0], buffer)
+ except Exception as inst:
+ print inst
+ if len(recvs) >= length:
+ print "PASS: Recv data length %d" % len(recvs)
+ else:
+ print "FAIL: Partial recv: desired %d, transfered %d" \
+ % (length, len(recvs))
+
+def compile():
+ """
+ Compile virtio_guest.py to speed up.
+ """
+ import py_compile
+ py_compile.compile(sys.path[0] + "/virtio_guest.py")
+ print "PASS: compile"
+ exit(0)
+
+def main():
+ """
+ Main (infinite) loop of virtio_guest.
+ """
+ if (len(sys.argv) > 1) and (sys.argv[1] == "-c"):
+ compile()
+
+ virt = virtio_guest()
+ print "PASS: Start"
+
+ while True:
+ str = raw_input()
+ exec str
+
+
+if __name__ == "__main__":
+ main()
@@ -1,10 +1,10 @@
-import socket, random, array, sys, os, tempfile, shutil, threading, select, re
-import logging, time
-from threading import Thread
+import array, logging, os, random, re, select, shutil, socket, sys, tempfile
+import threading, time
from collections import deque
-from autotest_lib.client.common_lib import error
-import kvm_subprocess, kvm_test_utils, kvm_utils, kvm_preprocessing
+from threading import Thread
+import kvm_subprocess, kvm_test_utils, kvm_utils, kvm_preprocessing
+from autotest_lib.client.common_lib import error
def run_virtio_console(test, params, env):
"""
@@ -28,139 +28,162 @@ def run_virtio_console(test, params, env):
"""
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
+ @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
+ # FIXME: socket.send(data>>127998) without read blocks thread
+ if len(data) > 102400:
+ data = data[0:102400]
+ logging.error("Data are too long, using only first %d bytes",
+ len(data))
self.data = data
self.exitevent = event
self.idx = 0
-
-
def run(self):
- logging.debug("th_send_loop %s: run", self.getName())
+ logging.debug("th_send %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(),
+ logging.debug("th_send %s: exit(%d)", self.getName(),
self.idx)
-
- class th_recv(Thread):
+ class th_send_check(Thread):
"""
- Random data reciever/checker thread
+ Random data sender thread
"""
- def __init__(self, port, buffer, length, blocklen=32):
+ def __init__(self, port, event, queues, blocklen=1024):
"""
- @param port: source port
- @param buffer: control data buffer (FIFO)
- @param length: amount of data we want to receive
- @param blocklen: block length
+ @param port: Destination port
+ @param event: Exit event
+ @param queues: Queues for the control data (FIFOs)
+ @param blocklen: Block length
"""
Thread.__init__(self)
- self.ExitState = True
- self.port = port[0]
- self.buffer = buffer
- self.length = length
+ self.port = port
+ self.queues = queues
+ # FIXME: socket.send(data>>127998) without read blocks thread
+ if blocklen > 102400:
+ blocklen = 102400
+ logging.error("Data are too long, using blocklen = %d",
+ blocklen)
self.blocklen = blocklen
-
+ self.exitevent = event
+ self.idx = 0
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
+ logging.debug("th_send_check %s: run", self.getName())
+ too_much_data = False
+ while not self.exitevent.isSet():
+ # FIXME: workaround the problem with qemu-kvm stall when too
+ # much data send without receiving
+ for queue in self.queues:
+ while not self.exitevent.isSet() and len(queue) > 1048576:
+ too_much_data = True
+ time.sleep(0.1)
+ ret = select.select([], [self.port], [], 1.0)
+ if ret[1]:
+ # Generate blocklen of random data add them to the FIFO
+ # and send them over virtio_console
+ buf = ""
+ for i in range(self.blocklen):
+ ch = "%c" % random.randrange(255)
+ buf += ch
+ for queue in self.queues:
+ queue.append(ch)
+ target = self.idx + self.blocklen
+ while not self.exitevent.isSet() and self.idx < target:
+ idx = self.port.send(buf)
+ buf = buf[idx:]
+ self.idx += idx
+ logging.debug("th_send_check %s: exit(%d)", self.getName(),
+ self.idx)
+ if too_much_data:
+ logging.error("th_send_check: workaround the 'too_much_data'"
+ "bug")
- class th_recv_null(Thread):
+ class th_recv(Thread):
"""
- Receives data and throws it away.
+ Recieves data and throw them away
"""
- def __init__(self, port, event, blocklen=32):
+ def __init__(self, port, event, blocklen=1024):
"""
@param port: Data source port.
@param event: Exit event.
@param blocklen: Block length.
"""
Thread.__init__(self)
- self.port = port[0]
+ self.port = port
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())
+ logging.debug("th_recv %s: run", self.getName())
while not self.exitevent.isSet():
- # Workaround, it didn't work with select :-/
+ # TODO: 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(),
+ logging.debug("th_recv %s: exit(%d)", self.getName(), self.idx)
+
+
+ class th_recv_check(Thread):
+ """
+ Random data reciever/checker thread
+ """
+ def __init__(self, port, buffer, event, blocklen=1024):
+ """
+ @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.port = port
+ self.buffer = buffer
+ self.exitevent = event
+ self.blocklen = blocklen
+ self.idx = 0
+ def run(self):
+ logging.debug("th_recv_check %s: run", self.getName())
+ while not self.exitevent.isSet():
+ ret = select.select([self.port], [], [], 1.0)
+ if ret and (not self.exitevent.isSet()):
+ buf = self.port.recv(self.blocklen)
+ if buf:
+ # Compare the recvd data with the control data
+ for ch in buf:
+ ch_ = self.buffer.popleft()
+ if not ch == ch_:
+ self.exitevent.set()
+ logging.error("Failed to recv %dth character",
+ self.idx)
+ logging.error("%s != %s", repr(ch), repr(ch_))
+ logging.error("Recv = %s", repr(buf))
+ # sender might change the buffer :-(
+ time.sleep(1)
+ ch_ = ""
+ for buf in self.buffer:
+ ch_ += buf
+ logging.error("Queue = %s", repr(ch_))
+ raise error.TestFail("th_recv_check: incorrect "
+ "data")
+ self.idx += len(buf)
+ logging.debug("th_recv_check %s: exit(%d)", self.getName(),
self.idx)
seqTest = threading.Lock();
- class average_cpu_load():
+ class cpu_load():
"""
Get average cpu load between start and get_load
"""
@@ -198,10 +221,11 @@ def run_virtio_console(test, params, env):
return load
- def start ( self ):
+ def start (self):
"""
Start CPU usage measurement
"""
+ self.old_load = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
self.startTime = time.time();
self._get_cpu_load()
@@ -209,10 +233,11 @@ def run_virtio_console(test, params, env):
def get_load(self):
"""
Get and reset CPU usage
+
@return: return group cpu (user[%], system[%], sum[%], testTime[s])
"""
self.endTime = time.time()
- testTime = self.endTime-self.startTime
+ testTime = self.endTime - self.startTime
load = self._get_cpu_load()
user = load[0] / testTime
@@ -222,7 +247,7 @@ def run_virtio_console(test, params, env):
return (user, system, sum, testTime)
- class average_process_cpu_load():
+ class pid_load():
"""
Get average process cpu load between start and get_load
"""
@@ -234,7 +259,7 @@ def run_virtio_console(test, params, env):
self.name = name
- def _get_cpu_load(self,pid):
+ def _get_cpu_load(self, pid):
# Let's see if we can calc system load.
try:
f = open("/proc/%d/stat" % (pid), "r")
@@ -249,19 +274,19 @@ def run_virtio_console(test, params, env):
load_values = reg.findall(line)
del load_values[0:11]
# extract values from /proc/stat
- load = [0,0]
+ load = [0, 0]
for i in range(2):
- load[i] = int(load_values[i])-self.old_load[i]
+ 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 ):
+ def start (self):
"""
Start CPU usage measurement
"""
+ self.old_load = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
self.startTime = time.time();
self._get_cpu_load(self.pid)
@@ -274,7 +299,7 @@ def run_virtio_console(test, params, env):
(pid, user[%], system[%], sum[%], testTime[s])
"""
self.endTime = time.time()
- testTime = self.endTime - self.startTime
+ testTime = self.endTime - self.startTime
load = self._get_cpu_load(self.pid)
user = load[0] / testTime
@@ -288,12 +313,12 @@ def run_virtio_console(test, params, env):
"""
Print load in tabular mode.
- @param process: list of process statistic tuples
- @param system: tuple of system cpu usage
+ @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")
+ "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" %
@@ -302,64 +327,96 @@ def run_virtio_console(test, params, env):
def process_stats(stats, scale=1.0):
"""
- Process and print the stats.
+ 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]
+ 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_console_switch(vm, timeout=2):
+ def init_guest(vm, timeout=2):
"""
- Execute console_switch.py on guest, wait until it is initialized.
+ Execute virtio_guest.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 console_switch.py on guest %s", vm[0].name)
- vm[1].sendline("python /tmp/console_switch.py")
+ logging.debug("compile virtio_guest.py on guest %s", vm[0].name)
+ vm[1].sendline("python -OO /tmp/virtio_guest.py -c &&"
+ "echo -n 'PASS: Compile virtio_guest finished' ||"
+ "echo -n 'FAIL: Compile virtio_guest failed'")
(match, data) = vm[1].read_until_last_line_matches(["PASS:", "FAIL:"],
timeout)
if match == 1 or match is None:
raise error.TestFail("Command console_switch.py on guest %s failed."
"\nreturn code: %s\n output:\n%s" %
(vm[0].name, match, data))
+ logging.debug("Starting virtio_guest.py on guest %s", vm[0].name)
+ vm[1].sendline("python /tmp/virtio_guest.pyo &&"
+ "echo -n 'PASS: virtio_guest finished' ||"
+ "echo -n 'FAIL: virtio_guest failed'")
+ (match, data) = vm[1].read_until_last_line_matches(["PASS:", "FAIL:"],
+ timeout)
+ if match == 1 or match is None:
+ raise error.TestFail("Command console_switch.py on guest %s failed."
+ "\nreturn code: %s\n output:\n%s" %
+ (vm[0].name, match, data))
+ # Let the system rest
+ time.sleep(2)
- def _execute_console_switch(command, vm, timeout=2):
+ def _on_guest(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 vm: Informations about the guest.
@param timeout: Timeout used to verify expected output.
@return: Tuple (match index, data)
"""
- logging.debug("Executing '%s' on console_switch.py loop, vm: %s,"
+ logging.debug("Executing '%s' on virtio_guest.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)
+ (match, data) = vm[1].read_until_last_line_matches(["PASS:", "FAIL:" \
+ "[Failed to execute]"], \
+ timeout)
+ return (match, data)
+
+
+ def on_guest(command, vm, timeout=2):
+ """
+ Wrapper around the _on_guest command which executes the command on
+ guest. Unlike _on_guest command when the command fails it raises the
+ test error.
+
+ @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)
+ """
+ match, data = _on_guest(command, vm, timeout)
if match == 1 or match is None:
- raise error.TestFail("Failed to execute '%s' on console_switch.py, "
+ raise error.TestFail("Failed to execute '%s' on virtio_guest.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.
+ Read everything from the socket
@param sock: socket
@param read_timeout: read timeout
@@ -380,14 +437,44 @@ def run_virtio_console(test, params, env):
return message
+ def _guest_exit_threads(vm, send_pts, recv_pts):
+ """
+ Safely executes on_guest("virt.exit_threads()") using workaround of
+ the stucked thread in loopback in mode=virt.LOOP_NONE .
+
+ @param vm: Informations about the guest.
+ @param send_pts: list of possible send sockets we need to work around
+ @param recv_pts: list of possible recv sockets we need to read-out
+ """
+ # in LOOP_NONE mode it might stuck in read/write
+ match, tmp = _on_guest("virt.exit_threads()", vm, 10)
+ if match == None:
+ logging.debug("Workaround the stucked thread on Guest")
+ # Thread is stucked in read/write
+ for send_pt in send_pts:
+ send_pt[0].sendall(".")
+ elif match != 0:
+ # Something else
+ raise error.TestFail("Unexpected fail\nMatch: %s\nData:\n"
+ % (match, tmp))
+
+ # Read-out all remaining data
+ for recv_pt in recv_pts:
+ while select.select([recv_pt[0]], [], [], 0.1)[0]:
+ recv_pt[0].recv(1024)
+
+ # This will cause fail in case anything went wrong.
+ on_guest("print 'PASS: nothing'", vm, 10)
+
+
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 tuple with (guest information, consoles information)
+ @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[]]
"""
@@ -398,24 +485,24 @@ def run_virtio_console(test, params, env):
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=c%d,"
+ 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=c%d,"
- "name=org.fedoraproject.console.%d,"
- "id=c%d" % (i, i, i))
+ params['extra_params'] += (" -device virtconsole,chardev=%d,"
+ "name=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=p%d,"
+ params['extra_params'] += (" -chardev socket,path=%s/%d,id=%d,"
"server,nowait" % (tmp_dir, i, i))
- params['extra_params'] += (" -device virtserialport,chardev=p%d,"
- "name=org.fedoraproject.data.%d,id=p%d" %
- (i, i, i))
+ params['extra_params'] += (" -device virtserialport,chardev=%d,"
+ "name=serialport-%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,
@@ -426,12 +513,11 @@ def run_virtio_console(test, params, env):
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"])
-
+ consoles.append([sock, "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"])
+ serialports.append([sock, "serialport-%d" % i, "no"])
return [vm, session, tmp_dir], [consoles, serialports]
@@ -440,15 +526,15 @@ def run_virtio_console(test, params, env):
"""
Virtio console smoke test.
- Creates loopback on the vm machine between the ports[>=2] provided and
- sends the data
+ Tests the basic functionalities (poll, read/write with and without
+ connected host, etc.
@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;...'
"""
- logging.info("Smoke test: Send data on the sender port, "
- "verify data integrity on the receiving port")
+ logging.info("Smoke test: Tests the basic capabilities of "
+ "virtio_consoles.")
# PREPARE
for param in params.split(';'):
if not param:
@@ -462,23 +548,118 @@ def run_virtio_console(test, params, env):
param = (param[0] == 'serialport')
send_pt = consoles[param][0]
recv_pt = consoles[param][1]
- _start_console_switch(vm, 10.0)
# TEST
- _execute_console_switch('start_switch([%s], [%s])' %
- (str(send_pt[1:3]), str(recv_pt[1:3])),
- vm, 2.0)
-
+ # Poll (OUT)
+ on_guest("virt.poll('%s', %s)" % (send_pt[1], select.POLLOUT), vm,
+ 2)
+
+ # Poll (IN, OUT)
+ send_pt[0].sendall("test")
+ for test in [select.POLLIN, select.POLLOUT]:
+ on_guest("virt.poll('%s', %s)" % (send_pt[1], test), vm, 2)
+
+ # Poll (IN HUP)
+ # I store the socket informations and close the socket
+ sock = send_pt[0]
+ send_pt[0] = sock.getpeername()
+ sock.shutdown(2)
+ sock.close()
+ del sock
+ for test in [select.POLLIN, select.POLLHUP]:
+ on_guest("virt.poll('%s', %s)" % (send_pt[1], test), vm, 2)
+
+ # Poll (HUP)
+ on_guest("virt.recv('%s', 4, 1024, False)" % (send_pt[1]), vm, 2)
+ on_guest("virt.poll('%s', %s)" % (send_pt[1], select.POLLHUP), vm,
+ 2)
+
+ # Reconnect the socket
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ sock.connect(send_pt[0])
+ send_pt[0] = sock
+ # Redefine socket in consoles
+ consoles[param][0] = send_pt
+ on_guest("virt.poll('%s', %s)" % (send_pt[1], select.POLLOUT), vm,
+ 2)
+
+ # Read/write without host connected
+ # I store the socket informations and close the socket
+ sock = send_pt[0]
+ send_pt[0] = sock.getpeername()
+ sock.shutdown(2)
+ sock.close()
+ del sock
+ # Read should pass
+ on_guest("virt.recv('%s', 0, 1024, False)" % send_pt[1], vm, 2)
+ # Write should timed-out
+ match, tmp = _on_guest("virt.send('%s', 10, False)"
+ % send_pt[1], vm, 2)
+ if match != None:
+ raise error.TestFail("Read on guest while host disconnected "
+ "didn't timed out.\nOutput:\n%s"
+ % tmp)
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ sock.connect(send_pt[0])
+ send_pt[0] = sock
+ # Redefine socket in consoles
+ consoles[param][0] = send_pt
+ if (send_pt[0].recv(1024) < 10):
+ raise error.TestFail("Didn't received data from guest")
+ # Now the _on_guest("virt.send('%s'... command should be finished
+ on_guest("print 'PASS: nothing'", vm, 2)
+
+ # Non-blocking mode
+ on_guest("virt.blocking('%s', False)" % send_pt[1], vm, 2)
+ # Recv should return FAIL with 0 received data
+ match, tmp = _on_guest("virt.recv('%s', 10, 1024, False)"
+ % send_pt[1], vm, 2)
+ if match == 0:
+ raise error.TestFail("Received data even when non were sent\n"
+ "Data:\n%s" % tmp)
+ elif match == None:
+ raise error.TestFail("Timed out, probably in blocking mode\n"
+ "Data:\n%s" % tmp)
+ elif match != 1:
+ raise error.TestFail("Unexpected fail\nMatch: %s\nData:\n"
+ % (match, tmp))
+ send_pt[0].sendall("1234567890")
+ on_guest("virt.recv('%s', 10, 1024, False)" % send_pt[1], vm, 2)
+
+ # Blocking mode
+ on_guest("virt.blocking('%s', True)" % send_pt[1], vm, 2)
+ # Recv should timed out
+ match, tmp = _on_guest("virt.recv('%s', 10, 1024, False)"
+ % send_pt[1], vm, 2)
+ if match == 0:
+ raise error.TestFail("Received data even when non were sent\n"
+ "Data:\n%s" % tmp)
+ elif match != None:
+ raise error.TestFail("Unexpected fail\nMatch: %s\nData:\n"
+ % (match, tmp))
+ send_pt[0].sendall("1234567890")
+ # Now guest received the data end escaped from the recv()
+ on_guest("print 'PASS: nothing'", vm, 2)
+
+ # Basic loopback test
+ on_guest("virt.loopback(['%s'], ['%s'], 1024, virt.LOOP_NONE)"
+ % (send_pt[1], recv_pt[1]), vm, 2)
send_pt[0].sendall(data)
- d = socket_readall(recv_pt[0], 1.0, len(data))
- if data != d:
- raise error.TestFail("test_smoke: received data on port %s "
- "does not match data sent through "
- "port %s" % (recv_pt, send_pt))
-
- vm[1].sendline('die()')
+ tmp = ""
+ i = 0
+ while i <= 10:
+ i += 1
+ ret = select.select([recv_pt[0]], [], [], 1.0)
+ if ret:
+ tmp += recv_pt[0].recv(1024)
+ if len(tmp) >= len(data):
+ break
+ if tmp != data:
+ raise error.TestFail("Incorrect data: '%s' != '%s'",
+ data, tmp)
+ _guest_exit_threads(vm, [send_pt], [recv_pt])
- logging.info("test_smoke: PASS")
+ return consoles
def test_loopback(vm, consoles, params):
@@ -492,9 +673,9 @@ def run_virtio_console(test, params, env):
@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;...'
+ '$source_console_type@buffer_length:
+ $destination_console_type1@$buffer_length:...:
+ $loopback_buffer_length;...'
"""
logging.info("Loopback test: Creates a loopback between sender port "
"and receiving port, send data through this connection, "
@@ -517,7 +698,7 @@ def run_virtio_console(test, params, env):
if (len(param[0].split('@')) == 2):
buf_len.append(int(param[0].split('@')[1]))
else:
- buf_len.append(32)
+ buf_len.append(1024)
recv_pts = []
for parm in param[1:]:
if (parm.isdigit()):
@@ -532,201 +713,170 @@ def run_virtio_console(test, params, env):
if (len(parm[0].split('@')) == 2):
buf_len.append(int(parm[0].split('@')[1]))
else:
- buf_len.append(32)
+ buf_len.append(1024)
# There must be sum(idx_*) consoles + last item as loopback buf_len
if len(buf_len) == (idx_console + idx_serialport):
- buf_len.append(32)
+ buf_len.append(1024)
if len(recv_pts) == 0:
raise error.TestFail("test_loopback: incorrect recv consoles"
"definition")
+
threads = []
- buffers = []
+ queues = []
for i in range(0, len(recv_pts)):
- buffers.append(deque())
+ queues.append(deque())
- _start_console_switch(vm, 10.0)
- tmp = str(recv_pts[0][1:3])
+ tmp = "'%s'" % recv_pts[0][1]
for recv_pt in recv_pts[1:]:
- tmp += ", " + str(recv_pt[1:3])
- _execute_console_switch('start_switch([%s], [%s], %d)' %
- (str(send_pt[1:3]), tmp, buf_len[-1]),
- vm, 2.0)
+ tmp += ", '%s'" % (recv_pt[1])
+ on_guest("virt.loopback(['%s'], [%s], %d, virt.LOOP_POLL)"
+ % (send_pt[1], tmp, buf_len[-1]), vm, 2)
+
+ exit_event = threading.Event()
# TEST
- thread = th_send(send_pt, 1048576, buffers, buf_len[0])
+ thread = th_send_check(send_pt[0], exit_event, queues, 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 = th_recv_check(recv_pts[i][0], queues[i], exit_event,
+ buf_len[i + 1])
thread.start()
threads.append(thread)
- dead_threads = False
- # Send + recv threads, DL 60s
- for i in range(60):
- for t in threads:
- if not t.is_alive():
- if t.ExitState:
- error.TestFail("test_loopback: send/recv thread "
- "failed")
- dead_threads = True
- if dead_threads:
- break
- tmp = ""
- for buf in buffers:
- tmp += str(len(buf)) + ", "
- logging.debug("test_loopback: buffer length (%s)", tmp[:-2])
- time.sleep(1)
-
- if not dead_threads:
- 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):
- dead_threads = True
- for t in threads:
- if t.is_alive():
- dead_threads = False
- # There are no living threads
- if dead_threads:
- break
- tmp = ""
- for buf in buffers:
- tmp += str(len(buf)) + ", "
- logging.debug("test_loopback: buffer length (%s)", tmp[:-2])
- time.sleep(1)
+ time.sleep(60)
+ exit_event.set()
+ threads[0].join()
+ tmp = "%d data sent; " % threads[0].idx
+ for thread in threads[1:]:
+ thread.join()
+ tmp += "%d, " % thread.idx
+ logging.info("test_loopback: %s data received and verified",
+ tmp[:-2])
- for t in threads:
- if t.ExitState:
- raise error.TestFail("test_loopback: recv thread failed")
+ # Read-out all remaining data
+ for recv_pt in recv_pts:
+ while select.select([recv_pt[0]], [], [], 0.1)[0]:
+ recv_pt[0].recv(1024)
- # At least one thread is still alive
- if not dead_threads:
- raise error.TestFail("test_loopback: recv timeout")
+ _guest_exit_threads(vm, [send_pt], recv_pts)
- vm[1].sendline("die()")
-
- logging.info("test_loopback: PASS")
+ del exit_event
+ del threads[:]
def test_perf(vm, consoles, params):
"""
- Virtio console performance test.
-
Tests performance of the virtio_console tunel. First it sends the data
- from host to guest and then back. It provides informations about
- computer utilization and statistic information about the throughput.
+ 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;...'
+ '$console_type@$buffer_length:$test_duration;...'
"""
logging.info("Performance test: Measure performance for the "
- "virtio console tunnel")
- # PREPARE
+ "virtio console tunnel")
for param in params.split(';'):
if not param:
continue
- logging.info("test_perf: params: %s", param)
+ print "test_perf: params: %s" % param
param = param.split(':')
- if len(param) > 1 and param[1].isdigit():
- duration = float(param[1])
- else:
- duration = 30.0
+ duration = 60.0
+ if len(param) > 1:
+ try:
+ duration = float(param[1])
+ except:
+ pass
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)
+ buf_len = 1024
+ param = (param[0] == 'serialport')
+ port = consoles[param][0]
- _start_console_switch(vm, 10.0)
+ data = ""
+ for i in range(buf_len):
+ data += "%c" % random.randrange(255)
- _execute_console_switch('start_switch([%s], [], %d)' %
- (str(port[1:3]), buf_len), vm, 2.0)
+ exit_event = threading.Event()
+ slice = float(duration)/100
- # TEST
- # Host -> Guest
- load = []
+ # HOST->GUEST
+ on_guest('virt.loopback(["%s"], [], %d, virt.LOOP_NONE)' % (
+ port[1], buf_len), vm, 2)
+ thread = th_send(port[0], data, exit_event)
stats = array.array('f', [])
- slice = float(duration)/100
- load.append(average_cpu_load())
- load.append(average_process_cpu_load(os.getpid(), 'autotest'))
- load.append(average_process_cpu_load(vm[0].get_pid(), 'VM'))
- for ld in load:
- ld.start()
+ loads = []
+ loads.append(cpu_load())
+ loads.append(pid_load(os.getpid(), 'autotest'))
+ loads.append(pid_load(vm[0].get_pid(), 'VM'))
+
+ for load in loads:
+ load.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].get_load(), load[2].get_load()],
- load[0].get_load())
- ev.set()
+ print_load([loads[1].get_load(), loads[2].get_load()],
+ loads[0].get_load())
+ exit_event.set()
thread.join()
+
+ _guest_exit_threads(vm, [port], [])
+
if (_time > slice):
- logging.error("test_perf: test ran %fs longer "
- "(more than 1 slice)", _time)
+ logging.error(
+ "Test ran %fs longer which is more than one slice", _time)
else:
- logging.debug("test_perf: test ran %fs longer "
- "(less than 1 slice)", _time)
- stats = process_stats(stats[1:], slice*1024*1024)
- logging.info("Host -> Guest [MB/s] min/med/max = %.3f/%.3f/%.3f",
+ logging.debug("Test ran %fs longer", _time)
+ stats = process_stats(stats[1:], slice*1048576)
+ logging.debug("Stats = %s", stats)
+ 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_console_switch(vm, 10.0)
- _execute_console_switch('sender_prepare(%s, %d)' %
- (str(port[1:3]), buf_len), vm, 10)
+ del thread
+
+ # GUEST->HOST
+ exit_event.clear()
stats = array.array('f', [])
- ev.clear()
- thread = th_recv_null(port, ev, buf_len)
+ on_guest("virt.send_loop_init('%s', %d)" % (port[1], buf_len),
+ vm, 30)
+ thread = th_recv(port[0], exit_event, buf_len)
thread.start()
- # reset load measures
- for ld in load:
- ld.get_load()
- _execute_console_switch('sender_start()', vm, 2)
+ for load in loads:
+ load.start()
+ on_guest("virt.send_loop()", 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].get_load(), load[2].get_load()],
- load[0].get_load())
- vm[1].sendline("die()")
- time.sleep(5)
- ev.set()
+ print_load([loads[1].get_load(), loads[2].get_load()],
+ loads[0].get_load())
+ on_guest("virt.exit_threads()", vm, 2)
+ exit_event.set()
thread.join()
if (_time > slice): # Deviation is higher than 1 slice
- logging.error("test_perf: test ran %fs longer "
- "(more than 1 slice)", _time)
+ logging.error(
+ "Test ran %fs longer which is more than one slice", _time)
else:
- logging.debug("test_perf: test ran %fs longer "
- "(less than 1 slice)", _time)
- stats = process_stats(stats[1:], slice*1024*1024)
- logging.info("Guest -> Host [MB/s] min/med/max = %.3f/%.3f/%.3f",
+ logging.debug("Test ran %fs longer" % _time)
+ stats = process_stats(stats[1:], slice*1048576)
+ logging.debug("Stats = %s", stats)
+ 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)
- logging.info("test_perf: PASS")
+ del thread
+
+ del exit_event
+ del loads[:]
# INITIALIZE
@@ -736,35 +886,44 @@ def run_virtio_console(test, params, env):
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)
+ if (no_serialports + no_consoles) == 0:
+ raise error.TestFail("No tests defined, probably incorrect "
+ "configuration in tests_base.cfg")
+
vm, consoles = _vm_create(no_consoles, no_serialports)
- # Copy console_switch.py into guests
+ # Copy allocator.py into guests
pwd = os.path.join(os.environ['AUTODIR'], 'tests/kvm')
- vksmd_src = os.path.join(pwd, "scripts/console_switch.py")
+ vksmd_src = os.path.join(pwd, "scripts/virtio_guest.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)
+ # Defines all available consoles; tests udev and sysfs
+ conss = []
+ for mode in consoles:
+ for cons in mode:
+ conss.append(cons[1:3])
+ init_guest(vm, 10)
+ on_guest("virt.init(%s)" % (conss), vm, 10)
+
+ consoles = test_smoke(vm, consoles, test_smoke_params)
test_loopback(vm, consoles, test_loopback_params)
test_perf(vm, consoles, test_perf_params)
@@ -772,3 +931,4 @@ def run_virtio_console(test, params, env):
vm[1].close()
vm[0].destroy(gracefully=False)
shutil.rmtree(vm[2])
+
@@ -502,11 +502,15 @@ variants:
vms = ''
type = virtio_console
# smoke params - $console_type:data_string
- virtio_console_smoke = "serialport;console:Custom data"
+ # FIXME: test_smoke doesn't work with console yet (virtio_console bug)
+ # "serialport;console:Custom data"
+ virtio_console_smoke = "serialport"
# loopback params - '$source_console_type@buffer_length:$destination_console_type1@buffer_length:...:$loopback_buffer_length;...'
virtio_console_loopback = "serialport:serialport;serialport@1024:serialport@32:console@1024:console@8:16"
# perf params - $console_type@buffer_length:$test_duration
- virtio_console_perf = "serialport;serialport@1000000:120;console@1024:60"
+ # FIXME: test_perf doesn't work with console yet (virtio_console bug)
+ # virtio_console_perf = "serialport;serialport@1000000:120;console@1024:60"
+ virtio_console_perf = "serialport;serialport@1000000:120"
# 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)