From a0e4b9fe9d7fab9a50a626cfeda3c614a9a6af5d Mon Sep 17 00:00:00 2001 From: Jonathan Herman Date: Wed, 17 Apr 2013 10:43:53 -0400 Subject: Created infrastructure for calculating scaling factors. --- parse/sched.py | 133 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 108 insertions(+), 25 deletions(-) (limited to 'parse') diff --git a/parse/sched.py b/parse/sched.py index 1213f0d..1f07751 100644 --- a/parse/sched.py +++ b/parse/sched.py @@ -2,8 +2,8 @@ import config.config as conf import os import re import struct -import sys import subprocess +import sys from collections import defaultdict,namedtuple from common import recordtype @@ -33,8 +33,9 @@ class TimeTracker: self.job = record.job # Data stored for each task -TaskParams = namedtuple('TaskParams', ['wcet', 'period', 'cpu']) -TaskData = recordtype('TaskData', ['params', 'jobs', 'blocks', 'misses']) +TaskParams = namedtuple('TaskParams', ['wcet', 'period', 'cpu', 'level']) +TaskData = recordtype('TaskData', ['params', 'jobs', 'loads', + 'blocks', 'misses', 'execs']) # Map of event ids to corresponding class, binary format, and processing methods RecordInfo = namedtuple('RecordInfo', ['clazz', 'fmt', 'method']) @@ -124,6 +125,7 @@ def read_data(task_dict, fnames): def process_completion(task_dict, record): task_dict[record.pid].misses.store_time(record) + task_dict[record.pid].loads += [record.load] def process_release(task_dict, record): data = task_dict[record.pid] @@ -131,7 +133,9 @@ def process_release(task_dict, record): data.misses.start_time(record) def process_param(task_dict, record): - params = TaskParams(record.wcet, record.period, record.partition) + level = chr(97 + record.level) + params = TaskParams(record.wcet, record.period, + record.partition, level) task_dict[record.pid].params = params def process_block(task_dict, record): @@ -140,14 +144,27 @@ def process_block(task_dict, record): def process_resume(task_dict, record): task_dict[record.pid].blocks.store_time(record) +def process_switch_to(task_dict, record): + task_dict[record.pid].execs.start_time(record) + +def process_switch_away(task_dict, record): + task_dict[record.pid].execs.store_time(record) + register_record('ResumeRecord', 9, process_resume, 'Q8x', ['when']) register_record('BlockRecord', 8, process_block, 'Q8x', ['when']) -register_record('CompletionRecord', 7, process_completion, 'Q8x', ['when']) +register_record('CompletionRecord', 7, process_completion, 'QQ', ['when', 'load']) register_record('ReleaseRecord', 3, process_release, 'QQ', ['release', 'when']) -register_record('ParamRecord', 2, process_param, 'IIIcc2x', - ['wcet','period','phase','partition', 'task_class']) +register_record('SwitchToRecord', 5, process_switch_to, 'Q8x', ['when']) +register_record('SwitchAwayRecord', 6, process_switch_away, 'Q8x', ['when']) +register_record('ParamRecord', 2, process_param, 'IIIcccx', + ['wcet','period','phase','partition', 'task_class', 'level']) + +saved_stats = [] +def get_task_data(data_dir, work_dir = None): + '''Parse sched trace files''' + if data_dir in saved_stats: + return data_dir -def extract_sched_data(result, data_dir, work_dir): bin_files = conf.FILES['sched_data'].format(".*") output_file = "%s/out-st" % work_dir @@ -157,24 +174,46 @@ def extract_sched_data(result, data_dir, work_dir): # Save an in-english version of the data for debugging # This is optional and will only be done if 'st_show' is in PATH - if conf.BINS['st_show']: + if work_dir and conf.BINS['st_show']: cmd_arr = [conf.BINS['st_show']] cmd_arr.extend(bins) with open(output_file, "w") as f: print("calling %s" % cmd_arr) subprocess.call(cmd_arr, cwd=data_dir, stdout=f) - task_dict = defaultdict(lambda : - TaskData(0, 0, TimeTracker(), TimeTracker())) + task_dict = defaultdict(lambda :TaskData(0, 0, 0, [], TimeTracker(), + TimeTracker(), TimeTracker())) # Gather per-task values read_data(task_dict, bins) - stat_data = {"avg-tard" : [], "max-tard" : [], - "avg-block" : [], "max-block" : [], - "miss-ratio" : []} + saved_stats[data_dir] = task_dict + return task_dict + +class LeveledArray(object): + """Groups statistics by the level of the task to which they apply""" + def __init__(self): + self.name = name + self.vals = defaultdict(lambda: defaultdict(lambda:[])) + + def add(self, name, level, value): + if type(value) != type([]): + value = [value] + self.vals[name][task.config.level] += value - # Group per-task values + def write_measurements(self, result): + for stat_name, stat_data in self.vals.iteritems(): + for level, values in stat_data.iteritems(): + if not values: + continue + + name = "%s%s" % ("%s-" % level if level else "", stat_name) + result[name] = Measurement(name).from_array(arr) + +def extract_sched_data(result, data_dir, work_dir): + task_dict = get_task_data(data_dir, work_dir) + + stat_data = LeveledArray() for tdata in task_dict.itervalues(): if not tdata.params: # Currently unknown where these invalid tasks come from... @@ -184,15 +223,59 @@ def extract_sched_data(result, data_dir, work_dir): # Scale average down to account for jobs with 0 tardiness avg_tard = tdata.misses.avg * miss_ratio - stat_data["miss-ratio"].append(miss_ratio) - stat_data["avg-tard" ].append(avg_tard / tdata.params.wcet) - stat_data["max-tard" ].append(tdata.misses.max / tdata.params.wcet) - stat_data["avg-block" ].append(tdata.blocks.avg / NSEC_PER_MSEC) - stat_data["max-block" ].append(tdata.blocks.max / NSEC_PER_MSEC) - - # Summarize value groups - for name, data in stat_data.iteritems(): - if not data: + level = tdata.params.level + stat_data.add("miss-ratio", level, miss_ratio) + stat_data.add("avg-tard", level, avg_tard / tdata.params.wcet) + stat_data.add("max-tard", level, tdata.misses.max / tdata.params.wcet) + stat_data.add("avg-block", level, tdata.blocks.avg / NSEC_PER_MSEC) + stat_data.add("max-block", level, tdata.blocks.max / NSEC_PER_MSEC) + + stat_data.write_measurements(result) + +ScaleData = namedtuple('ScaleData', ['reg_tasks', 'base_tasks']) +def extract_mc_data(result, data_dir, base_dir): + task_dict = get_task_data(data_dir) + base_dict = get_task_data(base_dir) + + stat_data = LeveledArray() + + # Only level B loads are measured + for tdata in filter(task_dict.iteritems(), lambda x: x.level == 'b'): + stat_data.add('load', tdata.config.level, tdata.loads) + + tasks_by_config = defaultdict(lambda: ScaleData([], [])) + + # Add tasks in order of pid to tasks_by_config + # Tasks must be ordered by pid or we can't make 1 to 1 comparisons + # when multiple tasks have the same config in each task set + for tasks, field in ((task_dict, 'reg_tasks'), (base_dict, 'base_tasks')): + for pid in sorted(tasks.keys()): + tdata = tasks[pid] + tlist = getattr(tasks_by_config[tdata.params], field) + tlist += [tdata.execs] + + # Write scaling factors + for config, scale_data in tasks_by_config: + if len(scale_data.reg_tasks) != len(scale_data.base_tasks): + # Can't make comparison if different numbers of tasks! continue - result[name] = Measurement(str(name)).from_array(data) + all_pairs = zip(scale_data.reg_tasks, scale_data.base_tasks) + for reg_execs, base_execs in all_pairs: + if not reg_execs.max or not reg_execs.avg or\ + not base_execs.max or not base_execs.avg: + # This was an issue at some point, not sure if it still is + continue + + max_scale = float(base_execs.max) / reg_execs.max + avg_scale = float(base_execs.avg) / reg_execs.avg + + if (avg_scale < 1 or max_scale < 1) and config.level == "b": + sys.stderr.write("Task in {} with config {} has <1.0 scale!" + .format(data_dir, config) + continue + + stat_data.add('max-scale', config.level, max_scale) + stat_data.add('avg-scale', config.level, avg_scale) + + stat_data.write_measurements(result) -- cgit v1.2.2