From: Stefan Raspl <raspl@xxxxxxxxxx> Allow to specify logfile size using a timeframe as specified by option '-T'. Since .csv files have varying record lengths, the estimate might be off, especially in case only a subset of (pathological) fields is chosen via '-f'. But we try to over- rather than understimate the required space to make up for it. Signed-off-by: Stefan Raspl <raspl@xxxxxxxxxxxxx> --- tools/kvm/kvm_stat/kvm_stat | 73 ++++++++++++++++++++++++++++++++- tools/kvm/kvm_stat/kvm_stat.txt | 6 +++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index 2275ab1b070b..d402ef97bf10 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat @@ -1509,6 +1509,10 @@ class StdFormat(object): res += ' %9d' % s[key].delta return res + def get_statline_len(self, keys, stats): + # Note: 19 chars for timestamp plus one for linefeed + return 20 + len(self.get_statline(keys, stats.get())) + class CSVFormat(object): def __init__(self, keys): @@ -1524,6 +1528,12 @@ class CSVFormat(object): return reduce(lambda res, key: "{},{!s}".format(res, s[key].delta), keys, '') + def get_statline_len(self, keys, stats): + # csv statlines are of variable length - need to + # apply horrible heuristics to get a projection + # Note: 19 chars for timestamp plus one for linefeed + return 20 + len(keys) * 5 + def log(stats, opts, frmt, keys): """Prints statistics as reiterating key block, multiple value blocks.""" @@ -1543,6 +1553,14 @@ def log(stats, opts, frmt, keys): def rotating_log(stats, opts, frmt, keys): """Prints statistics to file in csv format.""" + def convert_to_si(val): + if val / 1000000000000. > 1: + return "%.2fTB" % (val / 1000000000000.) + elif val / 1000000000. > 1: + return "%.2fGB" % (val / 1000000000.) + else: + return "%.2fMB" % (val / 1000000.) + def init(opts, frmt): # Regular RotatingFileHandler doesn't add a header to each file, # so we create our own version @@ -1580,6 +1598,18 @@ def rotating_log(stats, opts, frmt, keys): except: sys.exit("Error setting up csv log with file '%s'" % opts.rotating_log) + + def determine_logsize(opts, keys, stats): + if opts.time_frame != '': + opts.size = LOGCOUNT_DEFAULT * (len(frmt.get_banner()) + 1) + \ + opts.time_frame / opts.set_delay * \ + frmt.get_statline_len(keys, stats) + # Account for the current file being reset when we roll over + opts.size = opts.size / (LOGCOUNT_DEFAULT-1) * LOGCOUNT_DEFAULT + print("Estimated required total logfile size: %s" % + convert_to_si(opts.size)) + + determine_logsize(opts, keys, stats) formatter = MyFormatter('%(asctime)s%(message)s', '%Y-%m-%d %H:%M:%S') hdl.setFormatter(formatter) @@ -1645,6 +1675,32 @@ Press any other key to refresh statistics immediately. """ % (PATH_DEBUGFS_KVM, PATH_DEBUGFS_TRACING) def convert_from_si(opts): + if opts.time_frame != '': + try: + num = int(opts.time_frame.rstrip(string.ascii_letters)) + unit = opts.time_frame.lstrip(string.digits) + except ValueError: + sys.exit("Error: Invalid argument to -T/--time-frame: '%s'" + % opts.size) + if num <= 0: + sys.exit("Error: Argument to -S/--size must be >0") + factor = 3600 + if unit != '': + if unit in ['h', 'H']: + factor = 3600 + elif unit in ['d', 'D']: + factor = 24*3600 + elif unit in ['w', 'W']: + factor = 7*24*3600 + elif unit in ['m', 'M']: + factor = 30*24*3600 + elif unit in ['y', 'Y']: + factor = 365*24*3600 + else: + sys.exit("Error: Unsupported unit suffix '%s' for " + "-T/--time-frame" % unit) + opts.time_frame = int(num * factor) + try: factor = 1000000 num = int(opts.size.rstrip(string.ascii_letters)) @@ -1749,6 +1805,13 @@ default: %s''' % SIZE_DEFAULT, default=False, help='retrieve statistics from tracepoints', ) + argparser.add_argument('-T', '--time-frame', + type=str, + default='', + help='''determine total logfile size by minimum \ +time it should hold +supported suffixes: hdwmy (hours (default), days, weeks, months, years)''', + ) options = argparser.parse_args() if options.csv and not options.log and not options.rotating_log: sys.exit('Error: Option -c/--csv requires one of -l/--log or ' @@ -1756,9 +1819,17 @@ default: %s''' % SIZE_DEFAULT, if options.rotating_log: if options.log: sys.exit('Error: Cannot mix -l/--log and -r/--rotating-log') - if not options.size: + if options.size: + if options.time_frame: + sys.exit('Error: Cannot specify -S/--size and -T/--time-frame ' + 'together') + else: options.size = SIZE_DEFAULT convert_from_si(options) + else: + if options.size or options.time_frame: + sys.exit('Error: Options -S/--size and -T/--time-frame only valid ' + 'with -r/--rotating-log') try: # verify that we were passed a valid regex up front re.compile(options.fields) diff --git a/tools/kvm/kvm_stat/kvm_stat.txt b/tools/kvm/kvm_stat/kvm_stat.txt index 35df0b1261a2..2531c3bf56eb 100644 --- a/tools/kvm/kvm_stat/kvm_stat.txt +++ b/tools/kvm/kvm_stat/kvm_stat.txt @@ -115,6 +115,12 @@ OPTIONS --tracepoints:: retrieve statistics from tracepoints +-T:: +--time-frame:: + determine total logfile size by minimum time it should hold. + Supported suffixes: hd (hours (default), days, weeks, months, + years). Might be inaccurate for .csv format. + SEE ALSO -------- 'perf'(1), 'trace-cmd'(1) -- 2.17.1