]> rtime.felk.cvut.cz Git - linux-conf-perf.git/commitdiff
Add boot timeout
authorKarel Kočí <cynerd@email.cz>
Mon, 24 Aug 2015 12:39:16 +0000 (14:39 +0200)
committerKarel Kočí <cynerd@email.cz>
Mon, 24 Aug 2015 14:18:39 +0000 (16:18 +0200)
Boot process should timeout after selected number of seconds if no
output is generated. This allows resolving some problems with possible
boot stuck.

conf.py
scripts/boot.py
scripts/database.py
scripts/databaseinit.sql
scripts/exceptions.py
scripts/utils.py
targets/ryuglab/boot/boot

diff --git a/conf.py b/conf.py
index 9efc975e05db3e1d32f79e8d299b9a3377ea4523..b8204cbef8ed05a90f7ebac33374ccd63f197e12 100644 (file)
--- a/conf.py
+++ b/conf.py
@@ -18,6 +18,9 @@ build_command = ['make']
 # boot_command
 # Command executed for booting. Output of this command is saved to output folder.
 boot_command = ['echo', 'bootit']
+# boot_timeout
+# Set timeout of boot process if no output is generated for selected seconds
+boot_timeout = 120
 
 # parse_command
 # Command to parse double value from boot output
index af39b300ebbfa7759f0d2c1198b0e401a780edb3..31328a1216160452d51a1fe079cc84625c254948 100644 (file)
@@ -3,16 +3,28 @@ import sys
 import subprocess
 import shutil
 import importlib
+import traceback
 
 import utils
 import initialize
 from conf import conf
 from conf import sf
-from exceptions import MissingFile
+import exceptions
 import database
 
 def boot(config, to_database = True):
-       out = utils.callsubprocess('boot', conf.boot_command, conf.boot_output, True)
+       try:
+               out = utils.callsubprocess('boot', conf.boot_command, conf.boot_output, \
+                               True, timeout = conf.boot_timeout)
+               result = 'nominal'
+       except exceptions.ProcessFailed as e:
+               result = 'failed'
+               out = e.output
+               traceback.print_exc()
+       except exceptions.ProcessTimeout as e:
+               result = 'timeout'
+               out = e.output
+               traceback.print_exc()
 
        value = None
        try:
@@ -27,4 +39,4 @@ def boot(config, to_database = True):
                        txt = ''
                        for ln in out:
                                txt += ln + '\n'
-                       dtb.add_measure(txt, config.id, value)
+                       dtb.add_measure(txt, result, config.id, value)
index 866439395af4c9c74c3658c87f290aae74c34e4f..27c6a92cec6fd7c72cf0d71b18626b338c1bf88a 100644 (file)
@@ -99,17 +99,18 @@ class database:
                        rtn.append(Config(dt[0], hash, dt[1].split('\n')))
                return rtn
 
-       def add_measure(self, output, conf_id, value = None):
+       def add_measure(self, output, result, conf_id, value = None):
                "Add measurement."
                ps = self.db.prepare("""INSERT INTO measure
-                                                               (conf, output, value, mtime, toolgit, linuxgit, measurement)
+                                                               (conf, output, value, mtime, toolgit,
+                                                               linuxgit, measurement, result)
                                                                VALUES
-                                                               ($1, $2, $3, $4, $5, $6, $7);
+                                                               ($1, $2, $3, $4, $5, $6, $7, $8);
                                                                """)
                gt = self.check_toolsgit()
                lgt = self.check_linuxgit()
                tm = datetime.datetime.now()
-               ps(conf_id, output, value, tm, gt, lgt, conf.measure_identifier)
+               ps(conf_id, output, value, tm, gt, lgt, conf.measure_identifier, result)
 
        def update_measure(self, measure_id, value):
                "Update measured value"
index 0ca9b5a1434bc9af3baae3ce967e71cd74e529c3..c74640c1dccc56b28ce1dbc0e43d8121178cba32 100644 (file)
@@ -29,6 +29,7 @@ CREATE TABLE measure (
        conf BIGINT REFERENCES configurations (id), -- Reference to configuration
        measurement TEXT NOT NULL, -- Text identifivator of measuring tool
        output TEXT NOT NULL, -- Output of boot
+       result TEXT NOT NULL, -- Result of boot script, if exited normally
        value DOUBLE PRECISION DEFAULT null, -- Measured data value
        mtime timestamp NOT NULL, -- Time and date of measurement
        linuxgit BIGINT REFERENCES linuxgit (id), -- Reference to git version of Linux
index 649c235fd5a876784279f433c1984eff53683ff2..889dbe60b302c384b8cfdfd17267ddbab9940937 100644 (file)
@@ -32,13 +32,21 @@ class NoApplicableConfiguration(Exception):
                return "No applicable configuration find. All generated configurations were already applied."
 
 class ProcessFailed(Exception):
-       def __init__(self, process, returncode):
+       def __init__(self, process, returncode, output):
                self.process = process
                self.returncode = returncode
+               self.output = output
        def __str__(self):
                return "Process failed: " + str(self.process) + \
                        " with return code: " + str(self.returncode)
 
+class ProcessTimeout(Exception):
+       def __init__(self, process, output):
+               self.process = process
+               self.output = output
+       def __str__(self):
+               return "Process timeout: " + str(self.process)
+
 class DatabaseUninitialized(Exception):
        def __str__(self):
                return "Database seems to be uninitialized."
index 4260cc9badfdb3a6697fe170af1c9ff4dfafd267..f6a4720e2f15d25b152ff7d8a411ff89f106547a 100644 (file)
@@ -3,7 +3,9 @@ import sys
 import subprocess
 import time
 import hashlib
+import signal
 import re
+from threading import Thread
 from conf import conf
 from conf import sf
 import exceptions
@@ -27,13 +29,37 @@ def build_symbol_map():
                                w = lnn.rstrip().split(sep=':')
                                smap[int(w[0])] = w[1]
 
+class __subprocess_timer__(Thread):
+       def __init__(self, sprc, timeout):
+               Thread.__init__(self, name='subprocess_timer')
+               self.sprc = sprc
+               self.last = time.time()
+               self.exitit = False
+               self.timeout = timeout
+               self.timeouted = False
+               if timeout > 0:
+                       self.start()
+       def output(self):
+               self.last = time.time()
+       def exit(self):
+               self.exitit = True
+               return self.timeouted
+       def run(self):
+               while not self.exitit:
+                       now = time.time()
+                       if (now - self.last) >= self.timeout:
+                               self.timeouted = True
+                               os.kill(self.sprc.pid, signal.SIGTERM)
+                               return
+                       time.sleep(1)
 
 def callsubprocess(process_name, process, show_output = True,
                return_output = False, env=os.environ, allowed_exit_codes = [0],
-               allow_all_exit_codes = False, stdin = None):
+               allow_all_exit_codes = False, stdin = None, timeout = -1):
        sprc = subprocess.Popen(process, stdout = subprocess.PIPE,
                        stderr = subprocess.STDOUT, stdin = subprocess.PIPE, env = env)
 
+
        try:
                os.mkdir(os.path.join(sf(conf.log_folder), process_name))
        except OSError:
@@ -46,21 +72,24 @@ def callsubprocess(process_name, process, show_output = True,
                sprc.stdin.close()
 
        rtn = []
+       timerout = __subprocess_timer__(sprc, timeout)
        with open(os.path.join(sf(conf.log_folder),
                        process_name, time.strftime("%y-%m-%d-%H-%M-%S") + ".log"),
                        "a") as f:
                f.write('::' + time.strftime("%y-%m-%d-%H-%M-%S-%f") + '::\n')
                for linen in sprc.stdout:
+                       timerout.output()
                        line = linen.decode(sys.getdefaultencoding())
                        f.write(line)
                        if show_output:
                                print(line, end="")
                        if return_output:
                                rtn.append(line.rstrip())
-
+       if timerout.exit():
+               raise exceptions.ProcessTimeout(process_name, rtn)
        rtncode = sprc.wait()
        if rtncode not in allowed_exit_codes and not allow_all_exit_codes:
-               raise exceptions.ProcessFailed(process, rtncode)
+               raise exceptions.ProcessFailed(process, rtncode, rtn)
        return rtn
 
 def get_kernel_env():
index 331d9dca4a9118442b40c33321fbadd80d76dc45..3f88f6ec27ce478e75de21ba2abe6069554520df 100755 (executable)
@@ -9,4 +9,5 @@ cd `dirname $0`
 ln -sf ../../../jobfiles/linuxImage uImage
 ln -sf ../../../tests/cyclictest/root/images/rootfs.cpio.uboot rootfs.cpio.uboot
 
-novaboot nbscripts --exiton="NOVABOOT EXIT LINUX-CONF-PERF"
+novaboot nbscripts --exiton="NOVABOOT EXIT LINUX-CONF-PERF" --exiton-timeout=120 \
+       --exiton="Kernel panic"