Updated options pricing example to have a tasking-based path as well.

This commit is contained in:
Matt Pharr
2011-12-05 13:24:34 -08:00
parent 6181ce59ae
commit 9dd498718b
5 changed files with 196 additions and 69 deletions

View File

@@ -1,4 +1,9 @@
TASK_CXX=../tasksys.cpp
TASK_LIB=-lpthread
TASK_OBJ=$(addprefix objs/, $(subst ../,, $(TASK_CXX:.cpp=.o)))
CXX=g++ -m64 CXX=g++ -m64
CXXFLAGS=-Iobjs/ -g -Wall CXXFLAGS=-Iobjs/ -g -Wall
ISPC=ispc ISPC=ispc
@@ -6,7 +11,7 @@ ISPCFLAGS=-O2 --target=sse2,sse4-x2,avx-x2 --arch=x86-64
OBJS=objs/options.o objs/options_serial.o objs/options_ispc.o \ OBJS=objs/options.o objs/options_serial.o objs/options_ispc.o \
objs/options_ispc_sse2.o objs/options_ispc_sse4.o \ objs/options_ispc_sse2.o objs/options_ispc_sse4.o \
objs/options_ispc_avx.o objs/options_ispc_avx.o $(TASK_OBJ)
default: options default: options
@@ -19,11 +24,14 @@ clean:
/bin/rm -rf objs *~ options /bin/rm -rf objs *~ options
options: dirs $(OBJS) options: dirs $(OBJS)
$(CXX) $(CXXFLAGS) -o $@ $(OBJS) -lm $(CXX) $(CXXFLAGS) -o $@ $(OBJS) -lm $(TASK_LIB)
objs/%.o: %.cpp objs/%.o: %.cpp
$(CXX) $< $(CXXFLAGS) -c -o $@ $(CXX) $< $(CXXFLAGS) -c -o $@
objs/%.o: ../%.cpp
$(CXX) $< $(CXXFLAGS) -c -o $@
objs/options.o: objs/options_ispc.h options_defs.h objs/options.o: objs/options_ispc.h options_defs.h
objs/%_ispc.h objs/%_ispc.o objs/%_ispc_sse2.o objs/%_ispc_sse4.o objs/%_ispc_avx.o: %.ispc options_defs.h objs/%_ispc.h objs/%_ispc.o objs/%_ispc_sse2.o objs/%_ispc_sse4.o objs/%_ispc_avx.o: %.ispc options_defs.h

View File

@@ -53,15 +53,32 @@ extern void binomial_put_serial(float Sa[], float Xa[], float Ta[],
float ra[], float va[], float ra[], float va[],
float result[], int count); float result[], int count);
int main() { static void usage() {
float *S = new float[N_OPTIONS]; printf("usage: options [--count=<num options>]\n");
float *X = new float[N_OPTIONS]; }
float *T = new float[N_OPTIONS];
float *r = new float[N_OPTIONS];
float *v = new float[N_OPTIONS];
float *result = new float[N_OPTIONS];
for (int i = 0; i < N_OPTIONS; ++i) {
int main(int argc, char *argv[]) {
int nOptions = 128*1024;
for (int i = 1; i < argc; ++i) {
if (strncmp(argv[i], "--count=", 8) == 0) {
nOptions = atoi(argv[i] + 8);
if (nOptions <= 0) {
usage();
exit(1);
}
}
}
float *S = new float[nOptions];
float *X = new float[nOptions];
float *T = new float[nOptions];
float *r = new float[nOptions];
float *v = new float[nOptions];
float *result = new float[nOptions];
for (int i = 0; i < nOptions; ++i) {
S[i] = 100; // stock price S[i] = 100; // stock price
X[i] = 98; // option strike price X[i] = 98; // option strike price
T[i] = 2; // time (years) T[i] = 2; // time (years)
@@ -69,61 +86,109 @@ int main() {
v[i] = 5; // volatility v[i] = 5; // volatility
} }
double sum;
// //
// Binomial options pricing model, ispc implementation // Binomial options pricing model, ispc implementation
// //
reset_and_start_timer(); double binomial_ispc = 1e30;
binomial_put_ispc(S, X, T, r, v, result, N_OPTIONS); for (int i = 0; i < 3; ++i) {
double binomial_ispc = get_elapsed_mcycles(); reset_and_start_timer();
float sum = 0.f; binomial_put_ispc(S, X, T, r, v, result, nOptions);
for (int i = 0; i < N_OPTIONS; ++i) double dt = get_elapsed_mcycles();
sum += result[i]; sum = 0.;
printf("[binomial ispc]:\t\t[%.3f] million cycles (avg %f)\n", for (int i = 0; i < nOptions; ++i)
binomial_ispc, sum / N_OPTIONS); sum += result[i];
binomial_ispc = std::min(binomial_ispc, dt);
}
printf("[binomial ispc, 1 thread]:\t[%.3f] million cycles (avg %f)\n",
binomial_ispc, sum / nOptions);
//
// Binomial options pricing model, ispc implementation, tasks
//
double binomial_tasks = 1e30;
for (int i = 0; i < 3; ++i) {
reset_and_start_timer();
binomial_put_ispc_tasks(S, X, T, r, v, result, nOptions);
double dt = get_elapsed_mcycles();
sum = 0.;
for (int i = 0; i < nOptions; ++i)
sum += result[i];
binomial_tasks = std::min(binomial_tasks, dt);
}
printf("[binomial ispc, tasks]:\t\t[%.3f] million cycles (avg %f)\n",
binomial_tasks, sum / nOptions);
// //
// Binomial options, serial implementation // Binomial options, serial implementation
// //
reset_and_start_timer(); double binomial_serial = 1e30;
binomial_put_serial(S, X, T, r, v, result, N_OPTIONS); for (int i = 0; i < 3; ++i) {
double binomial_serial = get_elapsed_mcycles(); reset_and_start_timer();
sum = 0.f; binomial_put_serial(S, X, T, r, v, result, nOptions);
for (int i = 0; i < N_OPTIONS; ++i) double dt = get_elapsed_mcycles();
sum += result[i]; sum = 0.;
printf("[binomial serial]:\t\t[%.3f] million cycles (avg %f)\n", for (int i = 0; i < nOptions; ++i)
binomial_serial, sum / N_OPTIONS);
printf("\t\t\t\t(%.2fx speedup from ISPC)\n", binomial_serial / binomial_ispc);
//
// Black-Scholes options pricing model, ispc implementation
//
sum = 0.f;
reset_and_start_timer();
for (int a = 0; a < N_BLACK_SCHOLES_ROUNDS; ++a) {
black_scholes_ispc(S, X, T, r, v, result, N_OPTIONS);
for (int i = 0; i < N_OPTIONS; ++i)
sum += result[i]; sum += result[i];
binomial_serial = std::min(binomial_serial, dt);
} }
double bs_ispc = get_elapsed_mcycles(); printf("[binomial serial]:\t\t[%.3f] million cycles (avg %f)\n",
printf("[black-scholes ispc]:\t\t[%.3f] million cycles (avg %f)\n", binomial_serial, sum / nOptions);
bs_ispc, sum / (N_BLACK_SCHOLES_ROUNDS * N_OPTIONS));
printf("\t\t\t\t(%.2fx speedup from ISPC, %.2fx speedup from ISPC + tasks)\n",
binomial_serial / binomial_ispc, binomial_serial / binomial_tasks);
//
// Black-Scholes options pricing model, ispc implementation, 1 thread
//
double bs_ispc = 1e30;
for (int i = 0; i < 3; ++i) {
reset_and_start_timer();
black_scholes_ispc(S, X, T, r, v, result, nOptions);
double dt = get_elapsed_mcycles();
sum = 0.;
for (int i = 0; i < nOptions; ++i)
sum += result[i];
bs_ispc = std::min(bs_ispc, dt);
}
printf("[black-scholes ispc, 1 thread]:\t[%.3f] million cycles (avg %f)\n",
bs_ispc, sum / nOptions);
//
// Black-Scholes options pricing model, ispc implementation, tasks
//
double bs_ispc_tasks = 1e30;
for (int i = 0; i < 3; ++i) {
reset_and_start_timer();
black_scholes_ispc_tasks(S, X, T, r, v, result, nOptions);
double dt = get_elapsed_mcycles();
sum = 0.;
for (int i = 0; i < nOptions; ++i)
sum += result[i];
bs_ispc_tasks = std::min(bs_ispc_tasks, dt);
}
printf("[black-scholes ispc, tasks]:\t[%.3f] million cycles (avg %f)\n",
bs_ispc_tasks, sum / nOptions);
// //
// Black-Scholes options pricing model, serial implementation // Black-Scholes options pricing model, serial implementation
// //
sum = 0.f; double bs_serial = 1e30;
reset_and_start_timer(); for (int i = 0; i < 3; ++i) {
for (int a = 0; a < N_BLACK_SCHOLES_ROUNDS; ++a) { reset_and_start_timer();
black_scholes_serial(S, X, T, r, v, result, N_OPTIONS); black_scholes_serial(S, X, T, r, v, result, nOptions);
for (int i = 0; i < N_OPTIONS; ++i) double dt = get_elapsed_mcycles();
sum = 0.;
for (int i = 0; i < nOptions; ++i)
sum += result[i]; sum += result[i];
bs_serial = std::min(bs_serial, dt);
} }
double bs_serial = get_elapsed_mcycles();
printf("[black-scholes serial]:\t\t[%.3f] million cycles (avg %f)\n", bs_serial, printf("[black-scholes serial]:\t\t[%.3f] million cycles (avg %f)\n", bs_serial,
sum / (N_BLACK_SCHOLES_ROUNDS * N_OPTIONS)); sum / nOptions);
printf("\t\t\t\t(%.2fx speedup from ISPC)\n", bs_serial / bs_ispc); printf("\t\t\t\t(%.2fx speedup from ISPC, %.2fx speedup from ISPC + tasks)\n",
bs_serial / bs_ispc, bs_serial / bs_ispc_tasks);
return 0; return 0;
} }

View File

@@ -55,6 +55,32 @@ CND(float X) {
return w; return w;
} }
task void
bs_task(uniform float Sa[], uniform float Xa[], uniform float Ta[],
uniform float ra[], uniform float va[],
uniform float result[], uniform int count) {
uniform int first = taskIndex * (count/taskCount);
uniform int last = min(count, (int)((taskIndex+1) * (count/taskCount)));
foreach (i = first ... last) {
float S = Sa[i], X = Xa[i], T = Ta[i], r = ra[i], v = va[i];
float d1 = (log(S/X) + (r + v * v * .5f) * T) / (v * sqrt(T));
float d2 = d1 - v * sqrt(T);
result[i] = S * CND(d1) - X * exp(-r * T) * CND(d2);
}
}
export void
black_scholes_ispc_tasks(uniform float Sa[], uniform float Xa[], uniform float Ta[],
uniform float ra[], uniform float va[],
uniform float result[], uniform int count) {
uniform int nTasks = max((int)1, (int)count/1024);
launch[nTasks] < bs_task(Sa, Xa, Ta, ra, va, result, count) >;
}
export void export void
black_scholes_ispc(uniform float Sa[], uniform float Xa[], uniform float Ta[], black_scholes_ispc(uniform float Sa[], uniform float Xa[], uniform float Ta[],
uniform float ra[], uniform float va[], uniform float ra[], uniform float va[],
@@ -70,30 +96,59 @@ black_scholes_ispc(uniform float Sa[], uniform float Xa[], uniform float Ta[],
} }
static inline float
binomial_put(float S, float X, float T, float r, float v) {
float V[BINOMIAL_NUM];
float dt = T / BINOMIAL_NUM;
float u = exp(v * sqrt(dt));
float d = 1. / u;
float disc = exp(r * dt);
float Pu = (disc - d) / (u - d);
for (uniform int j = 0; j < BINOMIAL_NUM; ++j) {
float upow = pow(u, (float)(2*j-BINOMIAL_NUM));
V[j] = max(0., X - S * upow);
}
for (uniform int j = BINOMIAL_NUM-1; j >= 0; --j)
for (uniform int k = 0; k < j; ++k)
V[k] = ((1 - Pu) * V[k] + Pu * V[k + 1]) / disc;
return V[0];
}
export void export void
binomial_put_ispc(uniform float Sa[], uniform float Xa[], uniform float Ta[], binomial_put_ispc(uniform float Sa[], uniform float Xa[], uniform float Ta[],
uniform float ra[], uniform float va[], uniform float ra[], uniform float va[],
uniform float result[], uniform int count) { uniform float result[], uniform int count) {
float V[BINOMIAL_NUM];
foreach (i = 0 ... count) { foreach (i = 0 ... count) {
float S = Sa[i], X = Xa[i], T = Ta[i], r = ra[i], v = va[i]; float S = Sa[i], X = Xa[i], T = Ta[i], r = ra[i], v = va[i];
result[i] = binomial_put(S, X, T, r, v);
float dt = T / BINOMIAL_NUM;
float u = exp(v * sqrt(dt));
float d = 1. / u;
float disc = exp(r * dt);
float Pu = (disc - d) / (u - d);
for (uniform int j = 0; j < BINOMIAL_NUM; ++j) {
float upow = pow(u, (float)(2*j-BINOMIAL_NUM));
V[j] = max(0., X - S * upow);
}
for (uniform int j = BINOMIAL_NUM-1; j >= 0; --j)
for (uniform int k = 0; k < j; ++k)
V[k] = ((1 - Pu) * V[k] + Pu * V[k + 1]) / disc;
result[i] = V[0];
} }
} }
task void
binomial_task(uniform float Sa[], uniform float Xa[],
uniform float Ta[], uniform float ra[],
uniform float va[], uniform float result[],
uniform int count) {
uniform int first = taskIndex * (count/taskCount);
uniform int last = min(count, (int)((taskIndex+1) * (count/taskCount)));
foreach (i = first ... last) {
float S = Sa[i], X = Xa[i], T = Ta[i], r = ra[i], v = va[i];
result[i] = binomial_put(S, X, T, r, v);
}
}
export void
binomial_put_ispc_tasks(uniform float Sa[], uniform float Xa[],
uniform float Ta[], uniform float ra[],
uniform float va[], uniform float result[],
uniform int count) {
uniform int nTasks = max((int)1, (int)count/1024);
launch[nTasks] < binomial_task(Sa, Xa, Ta, ra, va, result, count) >;
}

View File

@@ -155,6 +155,7 @@
<ItemGroup> <ItemGroup>
<ClCompile Include="options.cpp" /> <ClCompile Include="options.cpp" />
<ClCompile Include="options_serial.cpp" /> <ClCompile Include="options_serial.cpp" />
<ClCompile Include="../tasksys.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="options.ispc"> <CustomBuild Include="options.ispc">

View File

@@ -35,8 +35,6 @@
#define OPTIONS_DEFS_H 1 #define OPTIONS_DEFS_H 1
#define BINOMIAL_NUM 64 #define BINOMIAL_NUM 64
#define N_OPTIONS 65536
#define N_BLACK_SCHOLES_ROUNDS 20
#endif // OPTIONS_DEFS_H #endif // OPTIONS_DEFS_H