Add disk usage monitoring to tests. This triggers a WARN if, during
the running of a test the rate of disk space usage on / exceeds a
fixed threshold.
The monitoring defaults to off, but you can turn it on for
subsequent tests by calling job.monitor_disk_usage.
Signed-off-by: John Admanski <[email protected]>
git-svn-id: http://test.kernel.org/svn/autotest/trunk@1487 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/client/bin/autotest_utils.py b/client/bin/autotest_utils.py
index 89139c0..8b2df8d 100755
--- a/client/bin/autotest_utils.py
+++ b/client/bin/autotest_utils.py
@@ -533,9 +533,14 @@
def freespace(path):
- # Find free space available in bytes
+ """Return the disk free space, in bytes"""
s = os.statvfs(path)
- return s[statvfs.F_BAVAIL] * long(s[statvfs.F_BSIZE])
+ return s.f_bavail * s.f_bsize
+
+
+def disk_block_size(path):
+ """Return the disk block size, in bytes"""
+ return os.statvfs(path).f_bsize
def get_cpu_family():
diff --git a/client/bin/job.py b/client/bin/job.py
index 4bcbd79..62f6093 100755
--- a/client/bin/job.py
+++ b/client/bin/job.py
@@ -150,6 +150,25 @@
if use_external_logging:
self.enable_external_logging()
+ # load the max disk usage rate - default to no monitoring
+ self.max_disk_usage_rate = self.get_state('__monitor_disk',
+ default=0.0)
+
+
+ def monitor_disk_usage(self, max_rate):
+ """\
+ Signal that the job should monitor disk space usage on /
+ and generate a warning if a test uses up disk space at a
+ rate exceeding 'max_rate'.
+
+ Parameters:
+ max_rate - the maximium allowed rate of disk consumption
+ during a test, in MB/hour, or 0 to indicate
+ no limit.
+ """
+ self.set_state('__monitor_disk', max_rate)
+ self.max_disk_usage_rate = max_rate
+
def relative_path(self, path):
"""\
@@ -285,6 +304,10 @@
root=root, name=cname)
# We are running in a container now...
+ def log_warning(reason):
+ self.record("WARN", subdir, testname, reason)
+ @disk_usage_monitor.watch(log_warning, "/",
+ self.max_disk_usage_rate)
def group_func():
try:
self.__runtest(url, tag, args, dargs)
@@ -299,6 +322,7 @@
else:
self.record('GOOD', subdir, testname,
'completed successfully')
+
result, exc_info = self.__rungroup(subdir, group_func)
if container:
self.release_container()
@@ -747,6 +771,61 @@
open(status_file, "a").write(msg + "\n")
+class disk_usage_monitor:
+ def __init__(self, logging_func, device, max_mb_per_hour):
+ self.func = logging_func
+ self.device = device
+ self.max_mb_per_hour = max_mb_per_hour
+
+
+ def start(self):
+ self.initial_space = autotest_utils.freespace(self.device)
+ self.start_time = time.time()
+
+
+ def stop(self):
+ # if no maximum usage rate was set, we don't need to
+ # generate any warnings
+ if not self.max_mb_per_hour:
+ return
+
+ final_space = autotest_utils.freespace(self.device)
+ used_space = self.initial_space - final_space
+ stop_time = time.time()
+ total_time = stop_time - self.start_time
+ # round up the time to one minute, to keep extremely short
+ # tests from generating false positives due to short, badly
+ # timed bursts of activity
+ total_time = max(total_time, 60.0)
+
+ # determine the usage rate
+ bytes_per_sec = used_space / total_time
+ mb_per_sec = bytes_per_sec / 1024**2
+ mb_per_hour = mb_per_sec * 60 * 60
+
+ if mb_per_hour > self.max_mb_per_hour:
+ msg = ("disk space on %s was consumed at a rate of "
+ "%.2f MB/hour")
+ msg %= (self.device, mb_per_hour)
+ self.func(msg)
+
+
+ @classmethod
+ def watch(cls, *monitor_args, **monitor_dargs):
+ """ Generic decorator to wrap a function call with the
+ standard create-monitor -> start -> call -> stop idiom."""
+ def decorator(func):
+ def watched_func(*args, **dargs):
+ monitor = cls(*monitor_args, **monitor_dargs)
+ monitor.start()
+ try:
+ func(*args, **dargs)
+ finally:
+ monitor.stop()
+ return watched_func
+ return decorator
+
+
def runjob(control, cont = False, tag = "default", harness_type = '',
use_external_logging = False):
"""The main interface to this module