diff --git a/ilp-measurement.scm b/ilp-measurement.scm index 2c452e20f7541d208d0c01678056bed19496d3b6..47ecca66f385f6523d9556fa25fe6a3f6fa3e903 100644 --- a/ilp-measurement.scm +++ b/ilp-measurement.scm @@ -354,15 +354,16 @@ "No valid arguments found, use 'all', 'dirs', 'prefix', 'suffix' or a number of ids.")) (define (measurement-cli-call command-line) - (let ([first (if (= 0 (length command-line)) #f (car command-line))]) - (cond - [(= 0 (length command-line)) (print-usage)] - [(string=? "all" first) (for-each run-test (map car params) (map cdr params))] - [(string=? "dirs" first) (for-each (lambda (entry) (display (car entry)) (display " ")) params)] - [(string=? "prefix" first) - (let ([param_subset (filter (lambda (p) (string-prefix? (cadr command-line) (car p))) params)]) - (for-each run-test (map car param_subset) (map cdr param_subset)))] - [(string=? "suffix" first) - (let ([param_subset (filter (lambda (p) (string-suffix? (cadr command-line) (car p))) params)]) - (for-each run-test (map car param_subset) (map cdr param_subset)))] - [else (for-each run-test command-line (map (lambda (id) (cdr (assoc id params))) command-line))])))) + (if (= 0 (length command-line)) (print-usage) + (let ([first (car command-line)]) + (sleep preesleep) + (cond + [(string=? "all" first) (for-each run-test (map car params) (map cdr params))] + [(string=? "dirs" first) (for-each (lambda (entry) (display (car entry)) (display " ")) params)] + [(string=? "prefix" first) + (let ([param_subset (filter (lambda (p) (string-prefix? (cadr command-line) (car p))) params)]) + (for-each run-test (map car param_subset) (map cdr param_subset)))] + [(string=? "suffix" first) + (let ([param_subset (filter (lambda (p) (string-suffix? (cadr command-line) (car p))) params)]) + (for-each run-test (map car param_subset) (map cdr param_subset)))] + [else (for-each run-test command-line (map (lambda (id) (cdr (assoc id params))) command-line))]))))) diff --git a/ilp_measurement.py b/ilp_measurement.py index 801fc3e58c8457aa5f1992b0ab91fba4f3617e2b..8f02a7eea858297bb062cbfdfe006d720e71387a 100644 --- a/ilp_measurement.py +++ b/ilp_measurement.py @@ -1,14 +1,14 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -import sys, re, os, csv, timeit, shutil, json +import sys, re, os, csv, timeit, shutil, json, threading, time from datetime import datetime from glob import glob, iglob -from subprocess import Popen +from subprocess import Popen, check_output, CalledProcessError try: from fabric.api import task, lcd, hosts, cd, run, get, execute from fabric.colors import red, green - from fabric.contrib.console import confirm +# from fabric.contrib.console import confirm except ImportError: from fabric_workaround import task, red, lcd, green import utils, properties @@ -82,18 +82,57 @@ def larceny(*dirs): """ Measure larceny once. """ do_gen(call_larceny, 1, dirs) +class MemoryMeasurement(threading.Thread): + def __init__(self, logfile_id, prog_name): + threading.Thread.__init__(self) + self.logfile_id = logfile_id + self.prog_name = prog_name + self.running = True + self.pid = None + self.daemon = True + + def run(self): + # find pid of prog + while self.running: + try: + self.pid = int(check_output(['pidof', '-s', self.prog_name])) + break + except CalledProcessError: + time.sleep(0.5) + # start thread periodically reading from /proc/$pid/status | grep VmSize + with open(self.logfile_id, 'w') as out_fd: + writer = csv.writer(out_fd) + writer.writerow(['time','vmsize']) + try: + while self.running: + time.sleep(1) + with open('/proc/{}/status'.format(self.pid)) as proc_fd: + lines = proc_fd.readlines() + size = next((l.split(':')[1].strip() for l in lines if l.startswith('VmSize')), None) + writer.writerow([datetime.today().isoformat(), size]) + except IOError: + self.running = False + + def abort(self): + self.running = False + +def start_memory_measurement(logfile_id, prog_name): + thr = MemoryMeasurement(logfile_id, prog_name) + thr.start() + return thr + def do_gen(call_impl, number, dirs, memory = False): cmd = 'measure' with timed(): setup_profiling_dirs(call_impl, cmd) for _ in xrange(int(number)): if memory: - FNULL = open(os.devnull, 'w') - dstat_cmds = ['dstat', '-tclmdC', 'total,0,1,2,3', '--output']#, logfile_id] for d in dirs: - process = Popen(dstat_cmds + [dstat_log(d)], stdout = FNULL) + thr = start_memory_measurement(memory_log(d), \ + 'racket' if call_impl == call_racket else 'larceny') call_impl('cli.scm', cmd, d, capture = False) - process.kill() + thr.abort() + thr.join() else: call_impl('cli.scm', cmd, 'all' if dirs == () else ' '.join(dirs), capture = False) # call_impl('larceny_profiling.scm', 'measure', 'all' if dirs == () else ' '.join(dirs), capture = False) @@ -101,6 +140,7 @@ def do_gen(call_impl, number, dirs, memory = False): # conflate_results(skip_sol = True) def dstat_log(directory): return 'profiling/{}/dstat.log'.format(directory) +def memory_log(directory): return 'profiling/{}/memory.csv'.format(directory) def dirname(d): return os.path.split(os.path.dirname(d))[-1] @@ -427,12 +467,13 @@ def check(): with open('dependencies.txt') as fd: if 'ilp-noncached\n' in fd: noncached_scm = True - print 'Evaluation is set to:\n- {0}, {1}\n- {2}\n- {3}\n- {4}'.format( + print 'Evaluation is set to:\n'+'\n- '.join(( red('non-cached') if properties.noncached.value else 'cached', red('flushed') if properties.flushed.value else 'unflushed', (green('Yes: ') if properties.timing.value else 'No ') + 'measurement of execution times', (green('Yes: ') if properties.profiling.value else 'No ') + 'profiling of attribute metrics', - (green('Yes: ') if properties.lp_write.value else 'No ') + 'write of LP files',) + (green('Yes: ') if properties.lp_write.value else 'No ') + 'write of LP files', + 'Wait {0} second(s) before each experiment'.format(properties.preesleep.value))) if noncached_scm != properties.noncached.value: print 'Attention: Compiled ilp ({}) differs from properties file setting ({}).'.format( nc_tostring(noncached_scm), nc_tostring(properties.noncached.value)) @@ -453,6 +494,19 @@ def help(): print '4. (Mandatory) Execute distinction-of-changes, to create splitted csv files' print '5. (Optional) Rerun notebook to update diagrams' +def confirm(question, default_val = False): + prompt = question + if isinstance(default_val, bool): + prompt += ' [{0}]'.format('Y/n' if default_val else 'y/N') + answer = raw_input(prompt + ' ') + if answer == '': + answer = default_val + if isinstance(default_val, bool): + return answer in ('y','Y','yes','Yes',True) + if isinstance(default_val,int): + return int(answer) + return answer + @task def setup(name = None, to_default = False): """ diff --git a/properties.py b/properties.py index 90990dce9e0cc1c6f63ef99d623652b523eb9309..a68bf1724065b3f0af0854833cbabfd04b1f3b9d 100644 --- a/properties.py +++ b/properties.py @@ -5,25 +5,27 @@ properties_fname = 'scheme.properties' def int_to_bool(i): return i in ('1', 1, True) +def bool_to_int(b): + return 1 if b else 0 + class PItem(object): - def __init__(self, name, question, default, key, conv = int_to_bool): + def __init__(self, name, question, default, key, conv_read = int_to_bool, conv_write = bool_to_int): self.name = name self.question = question self.default = default self.key = key - self.conv = conv + self.conv_r = conv_read + self.conv_w = conv_write self._value = default @property def value(self): return self._value @value.setter def value(self, new_value): - self._value = self.conv(new_value) + self._value = self.conv_r(new_value) def write_value(self): - def v(value): - return 1 if value else 0 local_quiet(r'sed -i "s/{0}\(\s*\)= {1}/{0}\1= {2}/" {3}'.format( - self.key, v(not self.value), v(self.value), properties_fname)) + self.key, self.conv_w(not self.value), self.conv_w(self.value), properties_fname)) timing = PItem('timing', 'Measure runtimes?', False, 'timing') log_info = PItem('info', 'Log INFO messages?', True, 'log.info') @@ -32,8 +34,10 @@ lp_write = PItem('lp', 'Write out ILP files?', False, 'measure.lp.write') profiling = PItem('profiling', 'Profile attribute metrics?', True, 'measure.profiling') flushed = PItem('flushed', 'Use strategy "flushed"?', False, 'measure.flush') noncached = PItem('noncached', 'Use strategy "noncached"?', False, 'measure.non-cached') +preesleep = PItem('presleep', 'Seconds to wait before running complete run?', 0.0, 'measure.presleep', + conv_read = float, conv_write = lambda x : x if x else '.*' ) -items = [timing, log_info, log_debug, lp_write, profiling, flushed, noncached] +items = [timing, log_info, log_debug, lp_write, profiling, flushed, noncached, preesleep] #class Properties(object): # def __init__(self, f): diff --git a/properties.scm b/properties.scm index ebfba94f02099d1a0ef84cffe1325479c3ddfcd3..53b07f82edb506a38e2bada98b8f1b10d25dd3fa 100644 --- a/properties.scm +++ b/properties.scm @@ -2,7 +2,7 @@ (library (mquat properties) - (export timing? profiling? log.debug? log.info? log.warn? write-ilp? measure-flush? measure-non-cached?) + (export timing? profiling? log.debug? log.info? log.warn? write-ilp? measure-flush? measure-non-cached? preesleep) (import (rnrs) (only (srfi :13) string-tokenize string-index string-trim-both) (srfi :14)) (define (file->char_list path) @@ -43,4 +43,5 @@ (define log.warn? (get-value "log.warn" #t)) (define write-ilp? (get-value "measure.lp.write" #f)) (define measure-flush? (get-value "measure.flush" #f)) - (define measure-non-cached? (get-value "measure.non-cached" #f))) + (define measure-non-cached? (get-value "measure.non-cached" #f)) + (define preesleep (get-value "measure.preesleep" 0.0))) diff --git a/scheme.properties b/scheme.properties index adbaed5e86a67bc7ec9eac4ea003bea5d9d46fae..23f04c9e4567d80ee97a622d772c5332f7f4f285 100644 --- a/scheme.properties +++ b/scheme.properties @@ -8,3 +8,4 @@ measure.lp.write = 0 measure.profiling = 1 measure.flush = 0 measure.non-cached = 0 +measure.presleep = 2.0