diff options
| author | Tor Aamodt <[email protected]> | 2010-07-15 18:09:46 -0800 |
|---|---|---|
| committer | Tor Aamodt <[email protected]> | 2010-07-15 18:09:46 -0800 |
| commit | 69f2911e04ffb1b19eef1fafb8c040af271f656e (patch) | |
| tree | 231d3b6bdc3a202f7c255bfcf7bf2c36e32cee9e /benchmarks/CUDA/CP/common | |
creating branch for adding support for CUDA 3.x and Fermi
[git-p4: depot-paths = "//depot/gpgpu_sim_research/fermi/distribution/": change = 6829]
Diffstat (limited to 'benchmarks/CUDA/CP/common')
| -rw-r--r-- | benchmarks/CUDA/CP/common/include/parboil.h | 132 | ||||
| -rw-r--r-- | benchmarks/CUDA/CP/common/lib/.dummy.txt | 1 | ||||
| -rw-r--r-- | benchmarks/CUDA/CP/common/mk/common.mk | 51 | ||||
| -rw-r--r-- | benchmarks/CUDA/CP/common/mk/cuda.mk | 17 | ||||
| -rw-r--r-- | benchmarks/CUDA/CP/common/mk/cuda_rules.mk | 30 | ||||
| -rw-r--r-- | benchmarks/CUDA/CP/common/mk/rules.mk | 48 | ||||
| -rw-r--r-- | benchmarks/CUDA/CP/common/python/binaryfilecompare.py | 50 | ||||
| -rw-r--r-- | benchmarks/CUDA/CP/common/python/filecompare.py | 154 | ||||
| -rw-r--r-- | benchmarks/CUDA/CP/common/python/textfilecompare.py | 27 | ||||
| -rw-r--r-- | benchmarks/CUDA/CP/common/src/Makefile | 23 | ||||
| -rw-r--r-- | benchmarks/CUDA/CP/common/src/parboil.c | 349 |
11 files changed, 882 insertions, 0 deletions
diff --git a/benchmarks/CUDA/CP/common/include/parboil.h b/benchmarks/CUDA/CP/common/include/parboil.h new file mode 100644 index 0000000..9885c9d --- /dev/null +++ b/benchmarks/CUDA/CP/common/include/parboil.h @@ -0,0 +1,132 @@ +/* + * (c) 2007 The Board of Trustees of the University of Illinois. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <unistd.h> + +/* Command line parameters for benchmarks */ +struct pb_Parameters { + char *outFile; /* If not NULL, the raw output of the + * computation should be saved to this + * file. The string is owned. */ + char **inpFiles; /* A NULL-terminated array of strings + * holding the input file(s) for the + * computation. The array and strings + * are owned. */ + int synchronizeGpu; /* Controls behavior of CUDA benchmarks. + * If nonzero, a CUDA runtime + * synchronization call should happen + * after each data transfer to the GPU + * and after each kernel call. This + * is necessary for accurate timing + * measurement. */ +}; + +/* Read command-line parameters. + * + * The argc and argv parameters to main are read, and any parameters + * interpreted by this function are removed from the argument list. + * + * A new instance of struct pb_Parameters is returned. + * If there is an error, then an error message is printed on stderr + * and NULL is returned. + */ +struct pb_Parameters * +pb_ReadParameters(int *_argc, char **argv); + +/* Free an instance of struct pb_Parameters. + */ +void +pb_FreeParameters(struct pb_Parameters *p); + +/* Count the number of input files in a pb_Parameters instance. + */ +int +pb_Parameters_CountInputs(struct pb_Parameters *p); + +/* A time or duration. */ +#if _POSIX_VERSION >= 200112L +typedef unsigned long long pb_Timestamp; /* time in microseconds */ +#else +# error "Timestamps not implemented" +#endif + +enum pb_TimerState { + pb_Timer_STOPPED, + pb_Timer_RUNNING, +}; + +struct pb_Timer { + enum pb_TimerState state; + pb_Timestamp elapsed; /* Amount of time elapsed so far */ + pb_Timestamp init; /* Beginning of the current time interval, + * if state is RUNNING. Undefined + * otherwise. */ +}; + +/* Reset a timer. + * Use this to initialize a timer or to clear + * its elapsed time. The reset timer is stopped. + */ +void +pb_ResetTimer(struct pb_Timer *timer); + +/* Start a timer. The timer is set to RUNNING mode and + * time elapsed while the timer is running is added to + * the timer. + * The timer should not already be running. + */ +void +pb_StartTimer(struct pb_Timer *timer); + +/* Stop a timer. + * This stops adding elapsed time to the timer. + * The timer should not already be stopped. + */ +void +pb_StopTimer(struct pb_Timer *timer); + +/* Get the elapsed time in seconds. */ +double +pb_GetElapsedTime(struct pb_Timer *timer); + +/* Execution time is assigned to one of these categories. */ +enum pb_TimerID { + pb_TimerID_NONE = 0, + pb_TimerID_IO, /* Time spent in input/output */ + pb_TimerID_GPU, /* Time spent computing on the GPU */ + pb_TimerID_COPY, /* Time spent moving data to/from GPU and + * allocating/freeing memory on the GPU */ + pb_TimerID_COMPUTE, /* Time for all program execution other + * than parsing command line arguments, + * I/O, GPU, and copy */ + pb_TimerID_LAST /* Number of timer IDs */ +}; + +/* A set of timers for recording execution times. */ +struct pb_TimerSet { + enum pb_TimerID current; + struct pb_Timer timers[pb_TimerID_LAST]; +}; + +/* Reset all timers in the set. */ +void +pb_InitializeTimerSet(struct pb_TimerSet *timers); + +/* Select which timer the next interval of time should be accounted + * to. The selected timer is started and other timers are stopped. + * Using pb_TimerID_NONE stops all timers. */ +void +pb_SwitchToTimer(struct pb_TimerSet *timers, enum pb_TimerID timer); + +/* Print timer values to standard output. */ +void +pb_PrintTimerSet(struct pb_TimerSet *timers); + +#ifdef __cplusplus +} +#endif diff --git a/benchmarks/CUDA/CP/common/lib/.dummy.txt b/benchmarks/CUDA/CP/common/lib/.dummy.txt new file mode 100644 index 0000000..241e4bb --- /dev/null +++ b/benchmarks/CUDA/CP/common/lib/.dummy.txt @@ -0,0 +1 @@ +A dummy file so that perforce creates the empty lib directory. diff --git a/benchmarks/CUDA/CP/common/mk/common.mk b/benchmarks/CUDA/CP/common/mk/common.mk new file mode 100644 index 0000000..93c76c0 --- /dev/null +++ b/benchmarks/CUDA/CP/common/mk/common.mk @@ -0,0 +1,51 @@ +# (c) 2007 The Board of Trustees of the University of Illinois. + +# Definitions common to all makefiles + +######################################## +# Environment variable check +# +# The environment variables BUILDDIR, SRCDIR, and PARBOIL_ROOT +# should be set on the command line to `make'. +######################################## + +ifeq ("$(SRCDIR)", "") +$(error $$SRCDIR is not set) +endif + +ifeq ("$(PARBOIL_ROOT)", "") +$(error $$PARBOIL_ROOT is not set) +endif + +######################################## +# Variables +######################################## + +# Programs +CC=gcc +CXX=g++ +AR=ar +RANLIB=ranlib + +# Command line options +INCLUDEFLAGS=-I$(CUDAHOME)/include -I$(PARBOIL_ROOT)/common/include +CFLAGS=$(GCCSTD) $(INCLUDEFLAGS) -g $(EXTRA_CFLAGS) +CXXFLAGS=$(INCLUDEFLAGS) -g $(EXTRA_CXXFLAGS) +LDFLAGS=-L$(PARBOIL_ROOT)/common/lib $(EXTRA_LDFLAGS) +LIBS=-lparboil $(EXTRA_LIBS) + +# Pass an extra source language option to GCC +ifeq ("$(CC)","gcc") +GCCSTD=-std=gnu99 +endif + + +######################################## +# Functions +######################################## + +# Add BUILDDIR as a prefix to each element of $1 +INBUILDDIR=$(addprefix $(BUILDDIR)/,$(1)) + +# Add SRCDIR as a prefix to each element of $1 +INSRCDIR=$(addprefix $(SRCDIR)/,$(1)) diff --git a/benchmarks/CUDA/CP/common/mk/cuda.mk b/benchmarks/CUDA/CP/common/mk/cuda.mk new file mode 100644 index 0000000..38f0ba2 --- /dev/null +++ b/benchmarks/CUDA/CP/common/mk/cuda.mk @@ -0,0 +1,17 @@ +# (c) 2007 The Board of Trustees of the University of Illinois. + +# Cuda-related definitions common to all benchmarks + +######################################## +# Variables +######################################## + +# Programs +CUDACC=nvcc +# Paths +# Flags +CUDACFLAGS=$(INCLUDEFLAGS) -g -Xcompiler "-m32" $(EXTRA_CUDACFLAGS) +CUDALDFLAGS=$(LDFLAGS) -Xcompiler "-m32" \ + -L$(GPGPUSIM_ROOT)/lib/ \ + -L$(PARBOIL_ROOT)/common/src $(EXTRA_CUDALDFLAGS) +CUDALIBS=-lcudart $(LIBS) -lm -lz -lGL diff --git a/benchmarks/CUDA/CP/common/mk/cuda_rules.mk b/benchmarks/CUDA/CP/common/mk/cuda_rules.mk new file mode 100644 index 0000000..ce2f5da --- /dev/null +++ b/benchmarks/CUDA/CP/common/mk/cuda_rules.mk @@ -0,0 +1,30 @@ +# (c) 2007 The Board of Trustees of the University of Illinois. + +# Cuda-related rules common to all benchmarks + +######################################## +# Derived variables +######################################## + +CUDAOBJS = $(call INBUILDDIR,$(SRCDIR_CUDAOBJS)) + +######################################## +# Rules +######################################## + +ifeq ("$(LINK_MODE)", "CUDA") +$(BIN) : $(OBJS) $(CUDAOBJS) + $(CUDACC) $(CUDALDFLAGS) $^ -o $@ $(CUDALIBS) +endif + +$(BUILDDIR)/%.o : $(SRCDIR)/%.cu + mkdir -p $(BUILDDIR) + $(CUDACC) $(CUDACFLAGS) -c $< -o $@ + +$(BUILDDIR)/%.ptx : $(SRCDIR)/%.cu + mkdir -p $(BUILDDIR) + $(CUDACC) $(CUDACFLAGS) -ptx $< -o $@ + +$(BUILDDIR)/%.cubin : $(SRCDIR)/%.cu + mkdir -p $(BUILDDIR) + $(CUDACC) $(CUDACFLAGS) -cubin $< -o $@ diff --git a/benchmarks/CUDA/CP/common/mk/rules.mk b/benchmarks/CUDA/CP/common/mk/rules.mk new file mode 100644 index 0000000..0e6304d --- /dev/null +++ b/benchmarks/CUDA/CP/common/mk/rules.mk @@ -0,0 +1,48 @@ +# (c) 2007 The Board of Trustees of the University of Illinois. + +# Rules common to all makefiles + +######################################## +# Environment variable check +######################################## + +# The second-last directory in the $(BUILDDIR) path +# must have the name "build". This reduces the risk of terrible +# accidents if paths are not set up correctly. +ifeq ("$(notdir $(BUILDDIR))", "") +$(error $$BUILDDIR is not set correctly) +endif + +ifneq ("$(notdir $(patsubst %/,%,$(dir $(BUILDDIR))))", "build") +$(error $$BUILDDIR is not set correctly) +endif + +######################################## +# Derived variables +######################################## + +OBJS = $(call INBUILDDIR,$(SRCDIR_OBJS)) + +######################################## +# Rules +######################################## + +clean : + rm -f $(BUILDDIR)/* + if [ -d $(BUILDDIR) ]; then rmdir $(BUILDDIR); fi + +ifeq ("$(LINK_MODE)","C") +$(BIN) : $(OBJS) + $(CC) $(LDFLAGS) $^ -o $@ $(LIBS) +endif + +$(BUILDDIR) : + mkdir $(BUILDDIR) + +$(BUILDDIR)/%.o : $(SRCDIR)/%.c + mkdir -p $(BUILDDIR) + $(CC) $(CFLAGS) -c $< -o $@ + +$(BUILDDIR)/%.o : $(SRCDIR)/%.cc + mkdir -p $(BUILDDIR) + $(CXX) $(CXXFLAGS) -c $< -o $@ diff --git a/benchmarks/CUDA/CP/common/python/binaryfilecompare.py b/benchmarks/CUDA/CP/common/python/binaryfilecompare.py new file mode 100644 index 0000000..b143b68 --- /dev/null +++ b/benchmarks/CUDA/CP/common/python/binaryfilecompare.py @@ -0,0 +1,50 @@ +# (c) Copyright 2007 The Board of Trustees of the University of Illinois. + +import struct + +def uint16(f): + """Read a 16-bit unsigned integer from f.""" + [c, c2] = f.read(2) + return ord(c) + (ord(c2) << 8) + +def uint32(f): + """Read a 32-bit unsigned integer from f.""" + [c, c2, c3, c4] = f.read(4) + return ord(c) + (ord(c2) << 8) + (ord(c3) << 16) + (ord(c4) << 24) + +def float(f): + """Read a floating-point number from f.""" + s = f.read(4) + (n,) = struct.unpack("<f", s) + return n + +def many(reader, count): + """Create a reader function that reads a fixed-size sequence of + values from f.""" + return lambda f: [reader(f) for n in range(count)] + +def many_uint16(count): + """Create a reader function that reads a fixed-size sequence of + 16-bit unsigned integers from f.""" + def read(f): + s = f.read(2*count) + ns = struct.unpack("<%dH" % count, s) + return ns + return read + +def many_float(count): + """Create a reader function that reads a fixed-size sequence of + floats from f.""" + def read(f): + s = f.read(4*count) + floats = struct.unpack("<%df" % count, s) + return floats + return read + +def eof(f): + """Read the end of file 'f'. A ValueError is raised if anything + other than EOF is read from the file.""" + if f.readline() == "": return None + else: raise ValueError, "Expecting end of file" + + diff --git a/benchmarks/CUDA/CP/common/python/filecompare.py b/benchmarks/CUDA/CP/common/python/filecompare.py new file mode 100644 index 0000000..a9a5c57 --- /dev/null +++ b/benchmarks/CUDA/CP/common/python/filecompare.py @@ -0,0 +1,154 @@ +# (c) Copyright 2007 The Board of Trustees of the University of Illinois. + +import sys + +# A monad for comparing two files. Comparing proceeds until the first +# mismatch occurs, at which point comparison stops and the error is +# reported. +class CompareMonad(object): + def checkType(x): + if not isinstance(x, CompareMonad): + raise TypeError, "Not a CompareMonad instance" + checkType = staticmethod(checkType) + + def run(self, ref_file, out_file): + raise NotImplementedError + +# The >>= operator. Executes 'fst', then executes 'snd' with the result +# of 'fst'. +class Bind(CompareMonad): + + def __init__(self, fst, snd): + CompareMonad.checkType(fst) + self.fst = fst + self.snd = snd + + def run(self, ref_file, out_file): + (ok, value) = self.fst.run(ref_file, out_file) + if ok: + sndMonad = self.snd(value) + CompareMonad.checkType(sndMonad) + return sndMonad.run(ref_file, out_file) + return (False, None) + +# The >> operator. Executes 'fst', then executes 'snd'. +class Then(CompareMonad): + def __init__(self, fst, snd): + CompareMonad.checkType(fst) + CompareMonad.checkType(snd) + self.fst = fst + self.snd = snd + + def run(self, ref_file, out_file): + (ok, value) = self.fst.run(ref_file, out_file) + if ok: + return self.snd.run(ref_file, out_file) + return (False, None) + +# The 'return' operator. Returns a value that is accessible +# within the monad. +class Return(CompareMonad): + def __init__(self, value): + self.value = value + + def run(self, ref_file, out_file): + return (True, self.value) + +# Run a list of monad instances and return their results as +# a list. +class Sequence(CompareMonad): + def __init__(self, ms): + self.ms = ms + + def run(self, ref_file, out_file): + values = [] + for m in self.ms: + CompareMonad.checkType(m) + (ok, value) = m.run(ref_file, out_file) + if not ok: return (False, None) + values.append(value) + + return (True, values) + +# Run a list of monad instances, ignoring their results. +class Sequence_(CompareMonad): + def __init__(self, ms): + self.ms = ms + + def run(self, ref_file, out_file): + for m in self.ms: + CompareMonad.checkType(m) + (ok, value) = m.run(ref_file, out_file) + if not ok: return (False, None) + + return (True, None) + +# The basic CompareMonad routine. This reads a value from both input +# files, compares the result, and, if the comparison was successful, +# returns the value. +class Compare(CompareMonad): + """Read an item from both input files and compare it.""" + + def __init__(self, + read = file.read, + equal = lambda x, y: x == y, + message = "Output does not match the expected output"): + self.read = read + self.equal = equal + self.message = message + + def run(self, ref_file, out_file): + try: + x = self.read(ref_file) + except ValueError, e: + sys.stderr.write("Malformed reference file!\n") + return (False, None) + except EOFError: + sys.stderr.write("Unexpected end of reference file!\n") + return (False, None) + try: + y = self.read(out_file) + except ValueError, e: + sys.stderr.write("Malformed output file;\n") + sys.stderr.write(str(e)) + sys.stderr.write('\n') + return (False, None) + except EOFError: + sys.stderr.write("Unexpected end of output file\n") + return (False, None) + + # Compare reference data to result data + if self.equal(x, y): + return (True, x) + else: + sys.stderr.write(self.message) + sys.stderr.write('\n') + return (False, None) + +def open_or_abort(filename): + try: f = file(filename, "r") + except: + sys.stderr.write("Cannot open file '" + filename + "'\n") + sys.exit(-1) + return f + + +def default_main(comparison_routine): + """Default main() routine. Read file names from sys.argv + and compare the files.""" + + if len(sys.argv) != 3: + sys.stderr.write("Usage: compare-output <from-file> <to-file>\n") + sys.exit(-1) + + ref = open_or_abort(sys.argv[1]) + out = open_or_abort(sys.argv[2]) + + (ok, _) = comparison_routine.run(ref, out) + if ok: + sys.stdout.write("Pass\n") + sys.exit(0) + else: + sys.stdout.write("Mismatch\n") + sys.exit(-1) + diff --git a/benchmarks/CUDA/CP/common/python/textfilecompare.py b/benchmarks/CUDA/CP/common/python/textfilecompare.py new file mode 100644 index 0000000..2f6ef68 --- /dev/null +++ b/benchmarks/CUDA/CP/common/python/textfilecompare.py @@ -0,0 +1,27 @@ +# (c) Copyright 2007 The Board of Trustees of the University of Illinois. + +from binaryfilecompare import eof, many + +# Rename the builtin 'float' variable to avoid name conflicts +builtin_float = float + +def verbatim(f): + """Read a line of text from file 'f'.""" + line = f.readline() + return line + +def float(f): + """Read a line of text from file 'f' as a single floating-point + number.""" + words = f.readline().split() + if len(words) != 1: + raise ValueError, "Expecting line to contain a single number" + return builtin_float(words[0]) + +def floats(f): + """Read a line of text from file 'f' as a list of floating-point + numbers.""" + words = f.readline().split() + return [builtin_float(x) for x in words] + + diff --git a/benchmarks/CUDA/CP/common/src/Makefile b/benchmarks/CUDA/CP/common/src/Makefile new file mode 100644 index 0000000..74822e2 --- /dev/null +++ b/benchmarks/CUDA/CP/common/src/Makefile @@ -0,0 +1,23 @@ +# (c) 2007 The Board of Trustees of the University of Illinois. + +SRCDIR=$(shell pwd) +BUILDDIR=$(shell pwd)/../lib + +include $(PARBOIL_ROOT)/common/mk/common.mk +include $(PARBOIL_ROOT)/common/mk/cuda.mk + +OBJS=$(BUILDDIR)/parboil.o +TARGET=$(BUILDDIR)/libparboil.a + +all : $(TARGET) + +clean: + rm -f $(OBJS) $(TARGET) + +$(BUILDDIR)/%.o : $(SRCDIR)/%.c + $(CC) -c $(CFLAGS) $^ -o $@ + +$(TARGET) : $(OBJS) + $(AR) rc $@ $? + $(RANLIB) $@ + diff --git a/benchmarks/CUDA/CP/common/src/parboil.c b/benchmarks/CUDA/CP/common/src/parboil.c new file mode 100644 index 0000000..f5ddfc6 --- /dev/null +++ b/benchmarks/CUDA/CP/common/src/parboil.c @@ -0,0 +1,349 @@ +/* + * (c) 2007 The Board of Trustees of the University of Illinois. + */ + +#include <parboil.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#if _POSIX_VERSION >= 200112L +# include <sys/time.h> +#endif + +/* Free an array of owned strings. */ +static void +free_string_array(char **string_array) +{ + char **p; + + if (!string_array) return; + for (p = string_array; *p; p++) free(*p); + free(string_array); +} + +/* Parse a comma-delimited list of strings into an + * array of strings. */ +static char ** +read_string_array(char *in) +{ + char **ret; + int i; + int count; /* Number of items in the input */ + char *substring; /* Current substring within 'in' */ + + /* Count the number of items in the string */ + count = 1; + for (i = 0; in[i]; i++) if (in[i] == ',') count++; + + /* Allocate storage */ + ret = malloc((count + 1) * sizeof(char *)); + + /* Create copies of the strings from the list */ + substring = in; + for (i = 0; i < count; i++) { + char *substring_end; + int substring_length; + + /* Find length of substring */ + for (substring_end = substring; + (*substring_end != ',') && (*substring_end != 0); + substring_end++); + + substring_length = substring_end - substring; + + /* Allocate memory and copy the substring */ + ret[i] = malloc(substring_length + 1); + memcpy(ret[i], substring, substring_length); + ret[i][substring_length] = 0; + + /* go to next substring */ + substring = substring_end + 1; + } + ret[i] = NULL; /* Write the sentinel value */ + + return ret; +} + +struct argparse { + int argc; /* Number of arguments. Mutable. */ + char **argv; /* Argument values. Immutable. */ + + int argn; /* Current argument number. */ + char **argv_get; /* Argument value being read. */ + char **argv_put; /* Argument value being written. + * argv_put <= argv_get. */ +}; + +static void +initialize_argparse(struct argparse *ap, int argc, char **argv) +{ + ap->argc = argc; + ap->argn = 0; + ap->argv_get = ap->argv_put = ap->argv = argv; +} + +static void +finalize_argparse(struct argparse *ap) +{ + /* Move the remaining arguments */ + for(; ap->argn < ap->argc; ap->argn++) + *ap->argv_put++ = *ap->argv_get++; +} + +/* Delete the current argument. */ +static void +delete_argument(struct argparse *ap) +{ + if (ap->argn >= ap->argc) { + fprintf(stderr, "delete_argument\n"); + } + ap->argc--; + ap->argv_get++; +} + +/* Go to the next argument. Also, move the current argument to its + * final location in argv. */ +static void +next_argument(struct argparse *ap) +{ + if (ap->argn >= ap->argc) { + fprintf(stderr, "next_argument\n"); + } + /* Move argument to its new location. */ + *ap->argv_put++ = *ap->argv_get++; + ap->argn++; +} + +static int +is_end_of_arguments(struct argparse *ap) +{ + return ap->argn == ap->argc; +} + +static char * +get_argument(struct argparse *ap) +{ + return *ap->argv_get; +} + +static char * +consume_argument(struct argparse *ap) +{ + char *ret = get_argument(ap); + delete_argument(ap); + return ret; +} + +struct pb_Parameters * +pb_ReadParameters(int *_argc, char **argv) +{ + char *err_message; + struct argparse ap; + struct pb_Parameters *ret = malloc(sizeof(struct pb_Parameters)); + + /* Initialize the parameters structure */ + ret->outFile = NULL; + ret->inpFiles = malloc(sizeof(char *)); + ret->inpFiles[0] = NULL; + ret->synchronizeGpu = 0; + + /* Each argument */ + initialize_argparse(&ap, *_argc, argv); + while(!is_end_of_arguments(&ap)) { + char *arg = get_argument(&ap); + + /* Single-character flag */ + if ((arg[0] == '-') && (arg[1] != 0) && (arg[2] == 0)) { + delete_argument(&ap); /* This argument is consumed here */ + + switch(arg[1]) { + case 'o': /* Output file name */ + if (is_end_of_arguments(&ap)) + { + err_message = "Expecting file name after '-o'\n"; + goto error; + } + free(ret->outFile); + ret->outFile = strdup(consume_argument(&ap)); + break; + case 'i': /* Input file name */ + if (is_end_of_arguments(&ap)) + { + err_message = "Expecting file name after '-i'\n"; + goto error; + } + ret->inpFiles = read_string_array(consume_argument(&ap)); + break; + case 'S': /* Synchronize */ + ret->synchronizeGpu = 1; + break; + case '-': /* End of options */ + goto end_of_options; + default: + err_message = "Unexpected command-line parameter\n"; + goto error; + } + } + else { + /* Other parameters are ignored */ + next_argument(&ap); + } + } /* end for each argument */ + + end_of_options: + *_argc = ap.argc; /* Save the modified argc value */ + finalize_argparse(&ap); + + return ret; + + error: + fputs(err_message, stderr); + pb_FreeParameters(ret); + return NULL; +} + +void +pb_FreeParameters(struct pb_Parameters *p) +{ + char **cpp; + + free(p->outFile); + free_string_array(p->inpFiles); + free(p); +} + +int +pb_Parameters_CountInputs(struct pb_Parameters *p) +{ + int n; + + for (n = 0; p->inpFiles[n]; n++); + return n; +} + +/*****************************************************************************/ +/* Timer routines */ + +static void +accumulate_time(pb_Timestamp *accum, + pb_Timestamp start, + pb_Timestamp end) +{ +#if _POSIX_VERSION >= 200112L + *accum += end - start; +#else +# error "Timestamps not implemented for this system" +#endif +} + +void +pb_ResetTimer(struct pb_Timer *timer) +{ + timer->state = pb_Timer_STOPPED; + +#if _POSIX_VERSION >= 200112L + timer->elapsed = 0; +#else +# error "pb_ResetTimer: not implemented for this system" +#endif +} + +void +pb_StartTimer(struct pb_Timer *timer) +{ + if (timer->state != pb_Timer_STOPPED) { + fputs("Ignoring attempt to start a running timer\n", stderr); + return; + } + + timer->state = pb_Timer_RUNNING; + +#if _POSIX_VERSION >= 200112L + { + struct timeval tv; + gettimeofday(&tv, NULL); + timer->init = tv.tv_sec * 1000000LL + tv.tv_usec; + } +#else +# error "pb_StartTimer: not implemented for this system" +#endif +} + +void +pb_StopTimer(struct pb_Timer *timer) +{ + pb_Timestamp fini; + + if (timer->state != pb_Timer_RUNNING) { + fputs("Ignoring attempt to stop a stopped timer\n", stderr); + return; + } + + timer->state = pb_Timer_STOPPED; + +#if _POSIX_VERSION >= 200112L + { + struct timeval tv; + gettimeofday(&tv, NULL); + fini = tv.tv_sec * 1000000LL + tv.tv_usec; + } +#else +# error "pb_StopTimer: not implemented for this system" +#endif + + accumulate_time(&timer->elapsed, timer->init, fini); +} + +/* Get the elapsed time in seconds. */ +double +pb_GetElapsedTime(struct pb_Timer *timer) +{ + double ret; + + if (timer->state != pb_Timer_STOPPED) { + fputs("Elapsed time from a running timer is inaccurate\n", stderr); + } + +#if _POSIX_VERSION >= 200112L + ret = timer->elapsed / 1e6; +#else +# error "pb_GetElapsedTime: not implemented for this system" +#endif + return ret; +} + +void +pb_InitializeTimerSet(struct pb_TimerSet *timers) +{ + int n; + + timers->current = pb_TimerID_NONE; + + for (n = 0; n < pb_TimerID_LAST; n++) + pb_ResetTimer(&timers->timers[n]); +} + +void +pb_SwitchToTimer(struct pb_TimerSet *timers, enum pb_TimerID timer) +{ + /* Stop the currently running timer */ + if (timers->current != pb_TimerID_NONE) + pb_StopTimer(&timers->timers[timers->current]); + + timers->current = timer; + + /* Start the new timer */ + if (timer != pb_TimerID_NONE) + pb_StartTimer(&timers->timers[timer]); +} + +void +pb_PrintTimerSet(struct pb_TimerSet *timers) +{ + struct pb_Timer *t = timers->timers; + printf("IO: %f\n", pb_GetElapsedTime(&t[pb_TimerID_IO])); + printf("GPU: %f\n", pb_GetElapsedTime(&t[pb_TimerID_GPU])); + printf("Copy: %f\n", pb_GetElapsedTime(&t[pb_TimerID_COPY])); + printf("Compute: %f\n", pb_GetElapsedTime(&t[pb_TimerID_COMPUTE])); +} |
