Hi everyone,
Sorry for 2 posts in one day. I have edited my code since the last post
to make it easy to add options once I get some direction about using the
options and creating a parameter file. I have attached the patch. All
the configurable options are now set in set_spc1_options, which can be
modified to read a parameter file.
All advice, comments, suggestions and help welcome.
Kind regards, Mike O'S
From 73d246dd4dcd7ae18c1c6e0ba16737fcd67bad3c Mon Sep 17 00:00:00 2001
From: unknown <mosu001@.(none)>
Date: Wed, 10 Feb 2010 11:06:38 +1300
Subject: [PATCH] Initial integration of open SPC-1 code into fio
---
spc1_wrapper.c | 660 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
spc1_wrapper.h | 93 ++++++++
2 files changed, 753 insertions(+), 0 deletions(-)
create mode 100644 spc1_wrapper.c
create mode 100644 spc1_wrapper.h
diff --git a/spc1_wrapper.c b/spc1_wrapper.c
new file mode 100644
index 0000000..3c59de5
--- /dev/null
+++ b/spc1_wrapper.c
@@ -0,0 +1,660 @@
+/*
+ * spc1_wrapper.c
+ *
+ * Created on: 23/12/2009
+ * Author: Michael
+ */
+
+#ifdef _USE_SPC1
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef _SPC1_H
+#define _SPC1_H
+#include "spc1.h"
+#endif
+
+#include "fio.h"
+
+#include "spc1_wrapper.h"
+
+short use_spc1;
+
+struct spc1_io_s *** iostore;
+
+unsigned ** iocount;
+
+void spc1_io_debug_info(const char *pre, struct spc1_io_s *spc1_io_s_addr) {
+ printf("%s", pre);
+ printf(": address = %d, ASU = %d, R/W = %d, length = %d, bsu stream = %d, bsu = %d, pos = %d, time = %d\n",
+ spc1_io_s_addr,
+ spc1_io_s_addr->asu,
+ spc1_io_s_addr->dir,
+ spc1_io_s_addr->len,
+ spc1_io_s_addr->stream,
+ spc1_io_s_addr->bsu,
+ spc1_io_s_addr->pos,
+ spc1_io_s_addr->when); // .when in 0.1 milliseconds
+ printf("pid = %d\n", getpid());
+ fflush(stdout);
+}
+void fio_io_debug_info(const char *pre, struct io_u *io_u_addr) {
+ printf("%s", pre);
+ printf(": address = %d, R/W = %d, offset = %lld, length = %ld, file %d, ",
+ io_u_addr,
+ io_u_addr->ddir,
+ io_u_addr->offset,
+ io_u_addr->buflen,
+ io_u_addr->file);
+ printf("pid = %d\n", getpid());
+ fflush(stdout);
+}
+
+unsigned spc1_context_from_bsu(unsigned bsu) {
+ int retcode;
+
+ retcode = (bsu + 1) / 100;
+
+ return retcode;
+}
+
+int gen_spc1_ios() {
+ int numContexts = (BSU + 1) / 100;
+ char vbuf[BUFLEN];
+ char pname[] = PNAME;
+
+ struct spc1_io_s nextio;
+ int retcode;
+ unsigned int i, j, bsu, stream, totalio, iops;
+ unsigned long long whenMillis, finalMillis = TOTAL_RUNTIME_MILLIS;
+ char message[BUFLEN];
+ unsigned numStarted, numFinished;
+ int status[BSU][STREAMS];
+
+ printf("Generating SPC-1 workload, num contexts = %d...\n", numContexts);
+
+ printf("Initialising data structures...\n");
+
+ assert( (BEGIN_CONTEXT >= 0) && (BEGIN_CONTEXT <= END_CONTEXT) && (END_CONTEXT <= numContexts) );
+
+ iostore = (struct spc1_io_s ***)malloc(BSU * sizeof(struct spc1_io_s **));
+ iocount = (unsigned **)malloc(BSU * sizeof(unsigned *));
+ for (i=0; i<BSU; i++) {
+ if ( (spc1_context_from_bsu(i) >= BEGIN_CONTEXT) &&
+ (spc1_context_from_bsu(i) <= END_CONTEXT) ) {
+ iostore[i] = (struct spc1_io_s **)malloc(STREAMS * sizeof(struct spc_io_u *));
+ iocount[i] = (unsigned *)malloc(STREAMS * sizeof(unsigned));
+ for (j=0; j<STREAMS; j++) {
+ iostore[i][j] = (struct spc1_io_s *)malloc(AVG_IOPS*TOTAL_RUNTIME_SECS * sizeof(struct spc1_io_s));
+ iocount[i][j] = 0;
+ }
+ }
+ }
+ memset(status, 0, BSU * STREAMS* sizeof(int)); /* Flags to see if stream started/finished */
+
+
+#ifdef _SPC1_DEBUG
+ printf("SPC-1 checking value of iocount, pid = %d\n", getpid());
+ for (i=0; i<BSU; i++)
+ if ( (spc1_context_from_bsu(i) >= BEGIN_CONTEXT) &&
+ (spc1_context_from_bsu(i) <= END_CONTEXT) )
+ for (j=0; j<STREAMS; j++)
+ printf("iocount[%d][%d] = %d\n", i, j, iocount[i][j]);
+ fflush(stdout);
+#endif
+
+ printf("Initialising SPC-1 benchmark generator...\n");
+
+ retcode = spc1_init(pname, // char *m Name of the program. Used for error messages.
+ BSU, // int b Number of BSUs.
+ GB_TO_BLOCK(ASU1_SIZE_GB), // unsigned int a1 Size of ASU 1 in 4K blocks.
+ GB_TO_BLOCK(ASU2_SIZE_GB), // unsigned int a2 Size of ASU 2 in 4K blocks.
+ GB_TO_BLOCK(ASU3_SIZE_GB), // unsigned int a3 Size of ASU 3 in 4K blocks.
+ numContexts, // int n_contexts The number of context blocks to allocate
+ vbuf, // version An output buffer where a version string may be written. If NULL, no version is written.
+ BUFLEN); // len The length of the output buffer.
+
+ if (retcode != SPC1_ENOERR) {
+ printf("Error initialising SPC-1 workload, errcode = %d\n", retcode);
+ return 1;
+ }
+
+ numStarted = numFinished = 0; /* No stream from any BSU has started/finished generating load */
+
+ printf("Initialisation complete!\n");
+
+ /* Generate SPC-1 IOs until the set time has elapsed */
+ printf("Creating SPC-1 workload...\n");
+
+ iops = 0;
+ do {
+ retcode = spc1_next_op_any(&nextio);
+ iops++;
+
+ if (retcode == SPC1_ENOERR) {
+#ifdef _SPC1_DEBUG
+ if ( (iops % IOPS_INFO == 0) || (iops >= IOPS_ALL) ) {
+ sprintf(message, "IOP #%d, context = %d", iops, spc1_context_from_bsu(nextio.bsu));
+ spc1_io_debug_info(message, &nextio);
+ }
+#endif
+ if ( (spc1_context_from_bsu(nextio.bsu) < BEGIN_CONTEXT) ||
+ (spc1_context_from_bsu(nextio.bsu) > END_CONTEXT) )
+ continue; /* This bsu is outside the contexts considered */
+
+ bsu = nextio.bsu;
+ stream = nextio.stream;
+ whenMillis = nextio.when / 10;
+
+ if (status[bsu][stream] == -1)
+ continue; /* Nothing to do for this (bsu, stream), go to next IO */
+ else {
+ if (status[bsu][stream] == 0) { /* (bsu, stream) not started yet */
+ status[bsu][stream] = 1; /* Start (bsu, stream) */
+ numStarted++; /* One more (bsu, steam) started */
+ }
+
+#ifdef _SPC1_DEBUG
+ if ( (iops % IOPS_INFO == 0) || (iops >= IOPS_ALL) ) {
+ printf("current = %lld, max = %lld\n", whenMillis, finalMillis);
+ fflush(stdout);
+ }
+#endif
+ if (whenMillis > finalMillis) { /* IO happens after time limit */
+ status[bsu][stream] = -1; /* Stop generating for this (bsu, stream) */
+ numFinished++; /* One more (bsu, steam) finished */
+ } else {
+#ifdef _SPC1_DEBUG
+ if ( (iops % IOPS_INFO == 0) || (iops >= IOPS_ALL) ) {
+ printf("Adding SPC-1 IO\n");
+ fflush(stdout);
+ }
+#endif
+ iostore[bsu][stream][iocount[bsu][stream]] = nextio; /* Store IO for (bsu, stream) */
+ iocount[bsu][stream]++; /* One more IO for (bsu, stream) */
+ }
+ }
+
+#ifdef _SPC1_DEBUG
+ if ( (iops % IOPS_INFO == 0) || (iops >= IOPS_ALL) ) {
+ printf("started = %d, finished = %d\n", numStarted, numFinished);
+ fflush(stdout);
+ }
+#endif
+ } else {
+ printf("Problem creating workload.");
+ return 1;
+ }
+
+ } while ( (numStarted > numFinished) || (iops <= MIN_IOPS_GENERATED) );
+
+ totalio = 0;
+ for (i=0; i<BSU; i++)
+ if ( (spc1_context_from_bsu(i) >= BEGIN_CONTEXT) &&
+ (spc1_context_from_bsu(i) <= END_CONTEXT) )
+ for (j=0; j<STREAMS;j++) {
+ totalio += iocount[i][j];
+#ifdef _SPC1_DEBUG
+ printf("iocount[%d][%d] = %d\n", i, j, iocount[i][j]);
+ fflush(stdout);
+#endif
+ }
+ printf("totalio = %d, totaltime = %d, average = %g\n",
+ totalio, TOTAL_RUNTIME_SECS, (double)totalio / TOTAL_RUNTIME_SECS / BSU);
+
+ printf("Workload created!\n");
+
+ return 0;
+}
+
+extern char* gen_spc1_file(char *string, unsigned int *global_addr,
+ unsigned int *line_addr, int *bsu_addr, int *str_addr) {
+
+ if (*global_addr) {
+#ifdef _SPC1_DEBUG
+ printf("SPC-1, global section, line = %d\n", *line_addr);
+#endif
+ switch (*line_addr) {
+ case 0:
+ sprintf(string, "[global]");
+ (*line_addr)++;
+ break;
+ case 1:
+ sprintf(string, "rw=randrw");
+ *global_addr = 0;
+ *line_addr = 0;
+#ifdef SINGLE
+ *bsu_addr = BSU_ID_FOR_SINGLE;
+#else
+ *bsu_addr = 0;
+#endif
+ *str_addr = 0;
+ break;
+ }
+
+ } else {
+
+ if (*bsu_addr == BSU_ID_FOR_SINGLE) {
+
+ switch (*line_addr) {
+ case 0:
+ sprintf(string, "[spc_all]");
+ (*line_addr)++;
+ break;
+ case 1:
+ sprintf(string, "write_bw_log=spc_all");
+ (*line_addr)++;
+ break;
+ case 2:
+ sprintf(string, "write_lat_log=spc_all");
+ *str_addr = STREAMS;
+ *bsu_addr = BSU;
+ *line_addr = 0;
+ break;
+ }
+
+ } else if (*bsu_addr == BSU) {
+#ifdef _SPC1_DEBUG
+ printf("SPC-1 generate null string\n");
+#endif
+ return NULL;
+ } else if (iocount[*bsu_addr][*str_addr] > 0) {
+#ifdef _SPC1_DEBUG
+ printf("SPC-1, bsu%d_str%d section, line = %d\n", *bsu_addr, *str_addr, *line_addr);
+#endif
+ switch (*line_addr) {
+ case 0:
+ sprintf(string, "[bsu%d_str%d]", *bsu_addr, *str_addr);
+ (*line_addr)++;
+ break;
+ case 1:
+ sprintf(string, "write_bw_log=spc_bsu%d", *bsu_addr);
+ (*line_addr)++;
+ break;
+ case 2:
+ sprintf(string, "write_lat_log=spc_bsu%d", *bsu_addr);
+ (*str_addr)++;
+ if (*str_addr == STREAMS) {
+ (*bsu_addr)++;
+ *str_addr = 0;
+ }
+ *line_addr = 0;
+ break;
+ }
+ } else {
+ (*str_addr)++;
+ if (*str_addr == STREAMS) {
+ (*bsu_addr)++;
+ *str_addr = 0;
+ }
+ *line_addr = 0;
+ }
+ }
+
+#ifdef _SPC1_DEBUG
+ printf("SPC-1 generate string %s\n", string);
+#endif
+ return string;
+}
+
+int init_spc1_io(struct thread_data *td) {
+ int i, j, k;
+ int fileno;
+
+ if ( (td->bsu >= BSU) || (td->str >= STREAMS) ) return 1;
+#ifdef SINGLE
+#ifdef _SPC1_DEBUG
+ printf("Initialising max_bs...\n");
+#endif
+ td->single_iopos = (unsigned **) malloc(BSU * sizeof(unsigned *));
+ for (i=0; i<BSU; i++)
+ if ( (spc1_context_from_bsu(i) >= BEGIN_CONTEXT) &&
+ (spc1_context_from_bsu(i) <= END_CONTEXT) ) {
+ td->single_iopos[i] = (unsigned *) malloc(STREAMS * sizeof(unsigned));
+ for (j=0; j<STREAMS; j++) {
+#ifdef _SPC1_DEBUG
+ printf("Initialising position, bsu = %d, str = %d\n", i, j);
+ fflush(stdout);
+#endif
+ td->single_iopos[i][j] = 0;
+ if (td->single_iocount[i][j] < 0) return 1;
+#ifdef _SPC1_DEBUG
+ printf("Checking max size, bsu = %d, str = %d\n", i, j);
+ fflush(stdout);
+// printf("for %d positions\n", td->single_iocount[i][j]);
+// fflush(stdout);
+#endif
+ for (k=0; k<td->single_iocount[i][j]; k++) {
+ int rw = td->single_iostore[i][j][k].dir;
+ int bytes = BLOCK_TO_B(td->single_iostore[i][j][k].len);
+
+#ifdef _SPC1_DEBUG
+ printf("IO from bsu = %d, str = %d, pos = %d has size %d\n", i, j, k, bytes);
+#endif
+ if (bytes > td->o.max_bs[rw])
+ td->o.max_bs[rw] = bytes;
+ }
+ }
+ }
+
+#ifdef _SPC1_DEBUG
+ printf("Adding ASU1 file...\n");
+#endif
+ fileno = get_fileno(td, ASU1);
+ if (fileno == -1) {
+ td->o.nr_files++;
+ fileno = add_file(td, ASU1);
+ }
+ if (fileno == -1) {
+#ifdef _SPC1_DEBUG
+ printf("ASU1 file could not be added...\n");
+#endif
+ return 1;
+ }
+ if (td_io_open_file(td, td->files[fileno])) {
+#ifdef _SPC1_DEBUG
+ printf("ASU1 file could not be opened...\n");
+#endif
+ return 1;
+ }
+#ifdef _SPC1_DEBUG
+ printf("Adding ASU2 file...\n");
+#endif
+ fileno = get_fileno(td, ASU2);
+ if (fileno == -1) {
+ td->o.nr_files++;
+ fileno = add_file(td, ASU2);
+ }
+ if (fileno == -1) {
+#ifdef _SPC1_DEBUG
+ printf("ASU2 file could not be added...\n");
+#endif
+ return 1;
+ }
+ if (td_io_open_file(td, td->files[fileno])) {
+#ifdef _SPC1_DEBUG
+ printf("ASU2 file could not be opened...\n");
+#endif
+ return 1;
+ }
+#ifdef _SPC1_DEBUG
+ printf("Adding ASU3 file...\n");
+#endif
+ fileno = get_fileno(td, ASU3);
+ if (fileno == -1) {
+ td->o.nr_files++;
+ fileno = add_file(td, ASU3);
+ }
+ if (fileno == -1) {
+#ifdef _SPC1_DEBUG
+ printf("ASU3 file could not be added...\n");
+#endif
+ return 1;
+ }
+ if (td_io_open_file(td, td->files[fileno])) {
+#ifdef _SPC1_DEBUG
+ printf("ASU3 file could not be opened...\n");
+#endif
+ return 1;
+ }
+
+#else
+ if (td->iocount <= 0) return 1;
+
+ td->iopos = 0;
+ // Find the maximum block size for creating buffers
+ for (i=0; i<td->iocount; i++) {
+ int rw = td->iostore[i].dir;
+ int bytes = BLOCK_TO_B(td->iostore[i].len);
+
+ if (bytes > td->o.max_bs[rw])
+ td->o.max_bs[rw] = bytes;
+ }
+#endif
+
+#ifdef _SPC1_DEBUG
+ printf("Initialisation finished for bsu = %d, str = %d, pid = %d\n", td->bsu, td->str, getpid());
+ fflush(stdout);
+#endif
+
+ return 0;
+}
+
+int fin_spc1_io(struct thread_data *td) {
+ int fileno;
+
+ if ( (td->bsu >= BSU) || (td->str >= STREAMS) ) return 1;
+#ifdef SINGLE
+
+ fileno = get_fileno(td, ASU1);
+ if (fileno == -1) {
+#ifdef _SPC1_DEBUG
+ printf("ASU1 file not open when closing...\n");
+#endif
+ return 1;
+ }
+ td_io_close_file(td, td->files[fileno]);
+ fileno = get_fileno(td, ASU2);
+ if (fileno == -1) {
+#ifdef _SPC1_DEBUG
+ printf("ASU2 file not open when closing...\n");
+#endif
+ return 1;
+ }
+ td_io_close_file(td, td->files[fileno]);
+ fileno = get_fileno(td, ASU3);
+ if (fileno == -1) {
+#ifdef _SPC1_DEBUG
+ printf("ASU3 file not open when closing...\n");
+#endif
+ return 1;
+ }
+ td_io_close_file(td, td->files[fileno]);
+
+#else
+ if (td->iocount <= 0) return 1;
+#endif
+
+#ifdef _SPC1_DEBUG
+ printf("Finalisation finished for bsu = %d, str = %d, pid = %d\n", td->bsu, td->str, getpid());
+ fflush(stdout);
+#endif
+ return 0;
+}
+
+int get_spc1_io(struct thread_data *td, struct io_u *io_u_addr) {
+
+ struct spc1_io_s spc1_io;
+ int i, j, bsu, str, pos, fileno;
+ unsigned long elapsed, whenMillis, least;
+ unsigned short found;
+
+#ifdef _SPC1_DEBUG
+ printf("Reading from SPC-1 IOs, pid = %d\n", getpid());
+ fflush(stdout);
+#endif
+
+#ifdef SINGLE
+ least = TOTAL_RUNTIME_MILLIS;
+ found = 0;
+ for (i=0; i<BSU; i++)
+ if ( (spc1_context_from_bsu(i) >= BEGIN_CONTEXT) &&
+ (spc1_context_from_bsu(i) <= END_CONTEXT) ) {
+ for (j=0; j<STREAMS; j++) {
+#ifdef _SPC1_DEBUG
+ printf("single_iocount[%d][%d] = %d, single_iopos[%d][%d] = %d\n",
+ i, j, td->single_iocount[i][j],
+ i, j, td->single_iopos[i][j]
+ );
+#endif
+ if (td->single_iopos[i][j] < td->single_iocount[i][j])
+ if (td->single_iostore[i][j][td->single_iopos[i][j]].when / 10 < least) {
+ bsu = i;
+ str = j;
+ pos = td->single_iopos[i][j];
+#ifdef _SPC1_DEBUG
+ printf("Earlier SPC-1 IOs, bsu = %d, str = %d, pos = %d, pid = %d\n", bsu, str, pos, getpid());
+ fflush(stdout);
+#endif
+ least = td->single_iostore[bsu][str][pos].when / 10;
+ found = 1;
+ }
+ }
+ }
+ if (!found) {
+ td->done = 1;
+ return 1;
+ }
+ spc1_io = td->single_iostore[bsu][str][pos];
+
+#else
+ bsu = td->bsu;
+ str = td->str;
+
+ pos = td->iopos;
+
+ if (pos == td->iocount) {
+ printf("IOs exhausted... bsu = %d, str = %d, pid = %d\n", bsu, str, getpid());
+ /* No more IOs from this (bsu, stream) */
+ td->done = 1;
+ return 1;
+ }
+
+#ifdef _SPC1_DEBUG
+ printf("IO # %d from bsu = %d, str = %d, pid = %d\n", pos, bsu, str, getpid());
+#endif
+ fflush(stdout);
+ spc1_io = td->iostore[pos];
+#endif
+
+#ifdef _SPC1_DEBUG
+ spc1_io_debug_info("SPC-1 IOP", &spc1_io);
+ fflush(stdout);
+#endif
+
+ elapsed = mtime_since_genesis();
+ whenMillis = spc1_io.when / 10;
+#ifdef _SPC1_DEBUG
+ printf("SPC-1 IO: elapsed = %ld, when = %ld, pid = %d\n", elapsed, whenMillis, getpid());
+ fflush(stdout);
+#endif
+ if (whenMillis > elapsed) {
+ usec_sleep(td, (whenMillis - elapsed) * 1000);
+ }
+
+#ifdef _SPC1_DEBUG
+ printf("SPC-1 IO: wait over\n");
+ fflush(stdout);
+#endif
+
+ io_u_addr->ddir = spc1_io.dir;
+ io_u_addr->offset = spc1_io.pos;
+// io_u_addr->offset = BLOCK_TO_B(spc1_io.pos);
+ io_u_addr->buflen = BLOCK_TO_B(spc1_io.len);
+
+#ifdef _SPC1_DEBUG
+ printf("IO # %d from bsu = %d, str = %d, pid = %d, identifying file...\n", pos, bsu, str, getpid());
+ fflush(stdout);
+#endif
+ /* Get file to read from/write to */
+ switch (td->str) {
+ case 0: case 1: case 2: case 3:
+ fileno = get_fileno(td, ASU1);
+ if (fileno == -1) {
+ td->o.nr_files++;
+ fileno = add_file(td, ASU1);
+ }
+ break;
+ case 4: case 5: case 6:
+ fileno = get_fileno(td, ASU2);
+ if (fileno == -1) {
+ td->o.nr_files++;
+ fileno = add_file(td, ASU2);
+ }
+ break;
+ default: /* case 7: */
+ fileno = get_fileno(td, ASU3);
+ if (fileno == -1) {
+ td->o.nr_files++;
+ fileno = add_file(td, ASU3);
+ }
+ break;
+ }
+ if (fileno == -1) {
+#ifdef _SPC1_DEBUG
+ printf("IO file has not been added... bsu = %d, str = %d, pid = %d\n", bsu, str, getpid());
+#endif
+ return 1;
+ }
+
+ io_u_addr->file = td->files[fileno];
+
+#ifndef SINGLE
+
+ if (pos == 0) {
+#ifdef _SPC1_DEBUG
+ printf("IO # %d from bsu = %d, str = %d, pid = %d, opening file # %d...\n", pos, bsu, str, getpid(), fileno);
+#endif
+ if (td_io_open_file(td, io_u_addr->file)) {
+#ifdef _SPC1_DEBUG
+ printf("IO file could not be opened... bsu = %d, str = %d, pid = %d\n", bsu, str, getpid());
+#endif
+ return 1;
+ }
+ }
+
+ if (pos == td->iocount) {
+#ifdef _SPC1_DEBUG
+ printf("IO # %d from bsu = %d, str = %d, pid = %d, closing file # %d...\n", pos, bsu, str, getpid(), fileno);
+#endif
+ td_io_close_file(td, io_u_addr->file);
+ }
+
+#endif
+
+#ifdef _SPC1_DEBUG
+ printf("IO # %d from bsu = %d, str = %d, pid = %d, getting file %d...\n", pos, bsu, str, getpid(), io_u_addr->file);
+ fflush(stdout);
+#endif
+ get_file(io_u_addr->file);
+
+#ifdef _SPC1_DEBUG
+ fio_io_debug_info("SPC-1 io_u", io_u_addr);
+ fflush(stdout);
+#endif
+
+#ifdef SINGLE
+ td->single_iopos[bsu][str]++;
+#else
+ td->iopos++;
+#endif
+
+#ifdef _SPC1_DEBUG
+ printf("Finished reading IO # %d from bsu = %d, str = %d, pid = %d\n", pos, bsu, str, getpid());
+ fflush(stdout);
+#endif
+
+ return 0;
+}
+
+unsigned short spc1_ios_left(struct thread_data *td) {
+ unsigned short left = 0;
+ int i, j;
+
+ for (i=0; i<BSU; i++)
+ if ( (spc1_context_from_bsu(i) >= BEGIN_CONTEXT) &&
+ (spc1_context_from_bsu(i) <= END_CONTEXT) ) {
+ for (j=0; j<STREAMS; j++)
+ if (td->single_iopos[i][j] < td->single_iocount[i][j]) {
+ left = 1;
+ break;
+ }
+ if (left) break;
+ }
+
+ return left;
+}
+
+#endif
diff --git a/spc1_wrapper.h b/spc1_wrapper.h
new file mode 100644
index 0000000..9d30dde
--- /dev/null
+++ b/spc1_wrapper.h
@@ -0,0 +1,93 @@
+#ifndef SPC1_WRAPPER_H_
+#define SPC1_WRAPPER_H_
+
+/* Can change these parameters */
+#define SINGLE
+//#define PROCS
+//#define THREADS
+
+#define BSU 198 // # Max working with PROCS = 25, with SINGLE = 400
+#define BEGIN_CONTEXT 0 /* This limits the BSUs to be those running on context = 0 */
+#define END_CONTEXT 0 /* and context = 0 */
+
+//#define BSU 99 // # Max working with PROCS = 25, with SINGLE = 400
+//#define BEGIN_CONTEXT 0 /* This limits the BSUs to be those running on context = 0 */
+//#define END_CONTEXT 0 /* and context = 1 */
+
+#define MIN_IOPS_GENERATED 100
+
+#define RUNTIME_HRS 0
+#define RUNTIME_MINS 30
+#define RUNTIME_SECS 0
+
+#define ASU1 "/dev/mapper/test-asu1"
+#define ASU2 "/dev/mapper/test-asu2"
+#define ASU3 "/dev/mapper/test-asu3"
+
+#define ASU1_SIZE_GB 20
+#define ASU2_SIZE_GB 20
+#define ASU3_SIZE_GB 20
+
+#define BLOCK_SIZE_KB 4
+
+#define PNAME "fio (v1.36)"
+
+#define GIGABYTE 1073741824
+#define MEGABYTE 1048576
+#define KILOBYTE 1024
+
+#define GB_TO_BLOCK( g ) ( (g)*(GIGABYTE/KILOBYTE)*BLOCK_SIZE_KB )
+#define BLOCK_TO_B( b ) ( (b)*BLOCK_SIZE_KB*KILOBYTE )
+
+#define BUFLEN 1000
+
+#define IOPS_INFO 100000
+#define IOPS_ALL 27900000
+
+/* No more changes required below here */
+#define BSU_ID_FOR_SINGLE -1
+#define STR_ID_FOR_SINGLE -1
+
+#define ASU 3
+
+#define STREAMS 8
+
+#define AVG_IOPS 50
+
+#define TOTAL_TIME_SECS( h, m, s ) ( 60*60*(h) + 60*(m) + (s) )
+#define IN_MILLIS( s ) ( 1000*(s) )
+
+#define TOTAL_RUNTIME_SECS TOTAL_TIME_SECS(RUNTIME_HRS, RUNTIME_MINS, RUNTIME_SECS)
+#define TOTAL_RUNTIME_MILLIS IN_MILLIS(TOTAL_RUNTIME_SECS)
+
+#ifndef _SPC1_H
+#define _SPC1_H
+#include "spc1.h"
+#endif
+
+#include "fio.h"
+
+extern short use_spc1;
+
+extern struct spc1_io_s *** iostore;
+
+extern unsigned ** iocount;
+
+extern unsigned spc1_context_from_bsu(unsigned bsu);
+
+extern int gen_spc1_ios();
+
+extern char* gen_spc1_file(char *string, unsigned int *global_addr,
+ unsigned int *line_addr, int *bsu_addr, int *str_addr);
+
+extern int init_spc1_io(struct thread_data *td);
+extern int fin_spc1_io(struct thread_data *td);
+
+extern int get_spc1_io(struct thread_data *td, struct io_u *io_u_addr);
+
+extern void spc1_io_debug_info(const char *pre, struct spc1_io_s *spc1_io_s_addr);
+extern void fio_io_debug_info(const char *pre, struct io_u *io_u_addr);
+
+extern unsigned short spc1_ios_left(struct thread_data *td);
+
+#endif /*SPC1_WRAPPER_H_*/
--
1.6.5.1.1367.gcd48