# HG changeset patch # User Merten Sach # Date 1323717988 -3600 # Node ID ef2b8d975a9943c354114fb8ee27ba9396855f80 # Parent 8323aae8c303d0a0692e6e6434d52f5fb0fc9399 exec time vs task size data generation and calculation splited in two scripts diff -r 8323aae8c303 -r ef2b8d975a99 scripts/overhead_data_generation.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/overhead_data_generation.py Mon Dec 12 20:26:28 2011 +0100 @@ -0,0 +1,111 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +import sys +from re import match, search +from pprint import pformat +from datetime import datetime +from subprocess import call,Popen,PIPE + +""" +This script generates a graph that represents the overhead + +involved in synchronisation operations +This script generates results for 5 runs per threads and iteration in +TOTAL_THREADS_TABLE and ITER_PER_TASK_TABLE +""" + +usage=""" + This runs the exec time vs task size in three levels of loop nest. The outer most iterates through + a selection of numbers-of-thread. For each of those, the next lever iterates over a number of work-loops-per-task + values. The innermost repeats several times and chooses the best. + Finally, it generates an output file for each value of number-of-threads that give the number of all runs. + It is expected that the output directory's path is meaningful, such as machine-name, date, and so on + Usage: + %s [executable binary] [path to output dir] +""" % sys.argv[0] + +NUM_CORES = 4 #Number of Cores the code was compiled for +ITERS_PER_TASK_TABLE = [2, 5, 10, 20, 40, 80, 160, 320, 640] #Number of iterations of inner loop +TASKS_PER_THREAD = 30000 #Number of interations of outer loop +TOTAL_THREADS_TABLE = [8, 32, 128, 512] + +def getNumber(line): + match_obj = search("(\d+\.?\d*)", line) + if match_obj != None: + return match_obj.groups()[0] + else: + raise ValueError + +if len(sys.argv) != 3: + print usage + sys.exit(0) + +cmd=sys.argv[1] +try: + f = open(cmd) +except IOError: + print "Please provide a valid executable." + f.close() + sys.exit(1) +finally: + f.close() + +output_dir_path = sys.argv[2] + +#=================================================================== +# Done with parsing cmd line inputs, start doing the runs +# + +for totalThreads in TOTAL_THREADS_TABLE: + print "\nDoing run with %d threads" % totalThreads + output = "%s/%d_thds__o%d__perfCtrs.meas" % (output_dir_path, totalThreads, TASKS_PER_THREAD) + print "output file: %s" % output + threadsPerCore = totalThreads/NUM_CORES + array_of_results = {} + for workload_iterations_in_task in ITERS_PER_TASK_TABLE: + print "Run for %s workload iterations in a task" % workload_iterations_in_task + results = [] + for run in range(5): + print "Run %d" % run, + program_output = Popen("%s -t %d -i %d -o %d" % (cmd, + totalThreads, + workload_iterations_in_task, + TASKS_PER_THREAD), + stdout=PIPE, stderr=None, shell=True).stdout.read() + #parse arguments for + for line in program_output.split("\n"): + if match("^Sum across threads of work cycles:", line) != None: + total_workcycles = int(getNumber(line)) + if match("^Total Execution Cycles:", line) != None: + total_exe_cycles = int(getNumber(line)) + if match("^ExeCycles/WorkCycles Ratio", line) != None: + exeCycles_workCycles_ratio = float(getNumber(line)) + results.append({"total_workcycles" : total_workcycles, + "total_exe_cycles" : total_exe_cycles, + "exeCycles_workCycles_ratio" : exeCycles_workCycles_ratio}) + print "ratio %f" % exeCycles_workCycles_ratio + array_of_results[workload_iterations_in_task] = results + + #open file to output data + try: + data_output = open(output,"w") + except IOError: + print "Cannot open output file %s" % output + sys.exit(1) + + #output relevant data to file + data_output.write(";\n".join(["# This is a output of the overhead_data_generation.py script, run the overhead_result_calc.py script to get the calculated results", + "data_filename = " + pformat(output), + "NUM_CORES = " + pformat(NUM_CORES), + "ITERS_PER_TASK_TABLE = " + pformat(ITERS_PER_TASK_TABLE), + "TASKS_PER_THREAD = " + pformat(TASKS_PER_THREAD), + "date_of_run = " + pformat(datetime.now()), + "threads_per_core = " + pformat(threadsPerCore), + "totalThreads = " + pformat(totalThreads), + "# array_of_results: hash key is the number of iterations per task(inner iterations)", + "array_of_results = " + pformat(array_of_results)])) + + + data_output.close() + diff -r 8323aae8c303 -r ef2b8d975a99 scripts/overhead_result_calc.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/overhead_result_calc.py Mon Dec 12 20:26:28 2011 +0100 @@ -0,0 +1,111 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +import sys +from re import search +import datetime +from os.path import basename + +""" +This script generates a graph that represents the overhead +involved in synchronisation operations +""" + +usage=""" + This generates an output file for each value of number-of-threads that give the number of all runs. + As an input it expects a result file which is generated by the overhead_result_calc.py script. + The file extension of the result file has to be ".meas". + It is expected that the output directory's path is meaningful, such as machine-name, date, and so on + Usage: + %s [result files] [path to output dir] +""" % sys.argv[0] + +if len(sys.argv) < 3: + print usage + sys.exit(0) + +result_filenames = sys.argv[1:-1] +output_dir_path = sys.argv[-1] + +for result_filename in result_filenames: + #open input file + try: + result_file = open(result_filename,"r") + except: + print "Cannot open result file %s" % result_filename + sys.exit(1) + + #parse(evaluate) result file + try: + exec(result_file.read()) + except: + print "Cannot parse result file: %s" % result_filename + result_file.close() + sys.exit(1) + result_file.close() + + #check for file extension + result_filename = basename(result_filename) + if search("\.meas$",result_filename) == None: + print "Wrong file extension! Has to be '.meas'" + sys.exit(1) + + output = output_dir_path + "/" + result_filename.replace(".meas",".result") + #open gnuplot output + try: + gnuplot_output = open(output,"w") + except IOError: + print "Cannot open output file %s" % output + result_file.close() + sys.exit(1) + + table_header = "# %20s\t%20s\t%20s\t%20s\t%20s\t%20s\t%20s\t%20s\n" % ( + "", + "", + "", + "", + "", + "", + "", + "") + + #write header to file + gnuplot_output.writelines(["# Output file name: %s\n" % data_filename, + "# Date of Run: %s\n" % date_of_run, + "# Number of Cores: %d\n" % NUM_CORES, + "# Number of Threads: %f per Core, %d total\n" % (threads_per_core, totalThreads), + table_header, + "# " + (len(table_header)-3)*"-" + "\n"]) + + #Now print the results out + for workload_iterations_in_task in ITERS_PER_TASK_TABLE: + results = array_of_results[workload_iterations_in_task] + + #take shortest run + results.sort(lambda x,y: cmp(x["total_exe_cycles"],y["total_exe_cycles"])) + total_workcycles = results[0]["total_workcycles"] + total_exe_cycles = results[0]["total_exe_cycles"] + #exeCycles_workCycles_ratio = results[0]["exeCycles_workCycles_ratio"] + + #Calculate numbers + overhead = total_exe_cycles - total_workcycles + total_syncs = totalThreads * TASKS_PER_THREAD * 2 + overhead_per_sync = float(overhead) / float(total_syncs) + cycles_of_task = float(total_workcycles) / float(TASKS_PER_THREAD * totalThreads) + overhead_per_core = float(overhead) / NUM_CORES + workcycles_per_core = total_workcycles / NUM_CORES + + # The 2 is in there because we have two sync operations in one per outer iteration + exeCycles_workCycles_ratio = float(total_workcycles+float(overhead)/2)/float(total_workcycles) + + gnuplot_output.write("%20d\t%20d\t%20d\t%20f\t%20d\t%20d\t%20f\t%20f\n" % ( + workload_iterations_in_task, + total_exe_cycles, + total_workcycles, + cycles_of_task, + overhead, + total_syncs, + overhead_per_sync, + exeCycles_workCycles_ratio)) + + gnuplot_output.close();