summaryrefslogtreecommitdiff
path: root/benchmarks/CUDA/CP/common
diff options
context:
space:
mode:
Diffstat (limited to 'benchmarks/CUDA/CP/common')
-rw-r--r--benchmarks/CUDA/CP/common/include/parboil.h132
-rw-r--r--benchmarks/CUDA/CP/common/lib/.dummy.txt1
-rw-r--r--benchmarks/CUDA/CP/common/mk/common.mk51
-rw-r--r--benchmarks/CUDA/CP/common/mk/cuda.mk17
-rw-r--r--benchmarks/CUDA/CP/common/mk/cuda_rules.mk30
-rw-r--r--benchmarks/CUDA/CP/common/mk/rules.mk48
-rw-r--r--benchmarks/CUDA/CP/common/python/binaryfilecompare.py50
-rw-r--r--benchmarks/CUDA/CP/common/python/filecompare.py154
-rw-r--r--benchmarks/CUDA/CP/common/python/textfilecompare.py27
-rw-r--r--benchmarks/CUDA/CP/common/src/Makefile23
-rw-r--r--benchmarks/CUDA/CP/common/src/parboil.c349
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]));
+}