Apply consistent code formatting across the repo. Add clang-format and pre-commit hooks.

This commit is contained in:
Rob Armstrong
2025-03-27 10:30:07 -07:00
parent 2cd58fbc9a
commit ceab6e8bcc
782 changed files with 107230 additions and 106548 deletions

View File

@@ -31,20 +31,20 @@
* See supplied whitepaper for more explanations.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <cuda_runtime.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// includes, project
#include <helper_functions.h> // Helper functions (utilities, parsing, timing)
#include <helper_cuda.h> // helper functions (cuda error checking and initialization)
#include <helper_cuda.h> // helper functions (cuda error checking and initialization)
#include <helper_functions.h> // Helper functions (utilities, parsing, timing)
#include <multithreading.h>
#include "MonteCarlo_common.h"
int *pArgc = NULL;
int *pArgc = NULL;
char **pArgv = NULL;
#ifdef WIN32
@@ -54,42 +54,43 @@ char **pArgv = NULL;
////////////////////////////////////////////////////////////////////////////////
// Common functions
////////////////////////////////////////////////////////////////////////////////
float randFloat(float low, float high) {
float t = (float)rand() / (float)RAND_MAX;
return (1.0f - t) * low + t * high;
float randFloat(float low, float high)
{
float t = (float)rand() / (float)RAND_MAX;
return (1.0f - t) * low + t * high;
}
/// Utility function to tweak problem size for small GPUs
int adjustProblemSize(int GPU_N, int default_nOptions) {
int nOptions = default_nOptions;
int adjustProblemSize(int GPU_N, int default_nOptions)
{
int nOptions = default_nOptions;
// select problem size
for (int i = 0; i < GPU_N; i++) {
cudaDeviceProp deviceProp;
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, i));
int cudaCores = _ConvertSMVer2Cores(deviceProp.major, deviceProp.minor) *
deviceProp.multiProcessorCount;
// select problem size
for (int i = 0; i < GPU_N; i++) {
cudaDeviceProp deviceProp;
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, i));
int cudaCores = _ConvertSMVer2Cores(deviceProp.major, deviceProp.minor) * deviceProp.multiProcessorCount;
if (cudaCores <= 32) {
nOptions = (nOptions < cudaCores / 2 ? nOptions : cudaCores / 2);
if (cudaCores <= 32) {
nOptions = (nOptions < cudaCores / 2 ? nOptions : cudaCores / 2);
}
}
}
return nOptions;
return nOptions;
}
int adjustGridSize(int GPUIndex, int defaultGridSize) {
cudaDeviceProp deviceProp;
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, GPUIndex));
int maxGridSize = deviceProp.multiProcessorCount * 40;
return ((defaultGridSize > maxGridSize) ? maxGridSize : defaultGridSize);
int adjustGridSize(int GPUIndex, int defaultGridSize)
{
cudaDeviceProp deviceProp;
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, GPUIndex));
int maxGridSize = deviceProp.multiProcessorCount * 40;
return ((defaultGridSize > maxGridSize) ? maxGridSize : defaultGridSize);
}
///////////////////////////////////////////////////////////////////////////////
// CPU reference functions
///////////////////////////////////////////////////////////////////////////////
extern "C" void MonteCarloCPU(TOptionValue &callValue, TOptionData optionData,
float *h_Random, int pathN);
extern "C" void MonteCarloCPU(TOptionValue &callValue, TOptionData optionData, float *h_Random, int pathN);
// Black-Scholes formula for call options
extern "C" void BlackScholesCall(float &CallResult, TOptionData optionData);
@@ -100,98 +101,99 @@ extern "C" void BlackScholesCall(float &CallResult, TOptionData optionData);
// Timer
StopWatchInterface **hTimer = NULL;
static CUT_THREADPROC solverThread(TOptionPlan *plan) {
// Init GPU
checkCudaErrors(cudaSetDevice(plan->device));
cudaDeviceProp deviceProp;
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, plan->device));
// Start the timer
sdkStartTimer(&hTimer[plan->device]);
// Allocate intermediate memory for MC integrator and initialize
// RNG states
initMonteCarloGPU(plan);
// Main computation
MonteCarloGPU(plan);
checkCudaErrors(cudaDeviceSynchronize());
// Stop the timer
sdkStopTimer(&hTimer[plan->device]);
// Shut down this GPU
closeMonteCarloGPU(plan);
cudaStreamSynchronize(0);
printf("solverThread() finished - GPU Device %d: %s\n", plan->device,
deviceProp.name);
CUT_THREADEND;
}
static void multiSolver(TOptionPlan *plan, int nPlans) {
// allocate and initialize an array of stream handles
cudaStream_t *streams = (cudaStream_t *)malloc(nPlans * sizeof(cudaStream_t));
cudaEvent_t *events = (cudaEvent_t *)malloc(nPlans * sizeof(cudaEvent_t));
for (int i = 0; i < nPlans; i++) {
checkCudaErrors(cudaSetDevice(plan[i].device));
checkCudaErrors(cudaStreamCreate(&(streams[i])));
checkCudaErrors(cudaEventCreate(&(events[i])));
}
// Init Each GPU
// In CUDA 4.0 we can call cudaSetDevice multiple times to target each device
// Set the device desired, then perform initializations on that device
for (int i = 0; i < nPlans; i++) {
// set the target device to perform initialization on
checkCudaErrors(cudaSetDevice(plan[i].device));
static CUT_THREADPROC solverThread(TOptionPlan *plan)
{
// Init GPU
checkCudaErrors(cudaSetDevice(plan->device));
cudaDeviceProp deviceProp;
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, plan[i].device));
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, plan->device));
// Allocate intermediate memory for MC integrator
// and initialize RNG state
initMonteCarloGPU(&plan[i]);
}
// Start the timer
sdkStartTimer(&hTimer[plan->device]);
// Allocate intermediate memory for MC integrator and initialize
// RNG states
initMonteCarloGPU(plan);
// Main computation
MonteCarloGPU(plan);
for (int i = 0; i < nPlans; i++) {
checkCudaErrors(cudaSetDevice(plan[i].device));
checkCudaErrors(cudaDeviceSynchronize());
}
// Start the timer
sdkResetTimer(&hTimer[0]);
sdkStartTimer(&hTimer[0]);
// Stop the timer
sdkStopTimer(&hTimer[plan->device]);
for (int i = 0; i < nPlans; i++) {
checkCudaErrors(cudaSetDevice(plan[i].device));
// Shut down this GPU
closeMonteCarloGPU(plan);
// Main computations
MonteCarloGPU(&plan[i], streams[i]);
cudaStreamSynchronize(0);
checkCudaErrors(cudaEventRecord(events[i], streams[i]));
}
printf("solverThread() finished - GPU Device %d: %s\n", plan->device, deviceProp.name);
for (int i = 0; i < nPlans; i++) {
checkCudaErrors(cudaSetDevice(plan[i].device));
cudaEventSynchronize(events[i]);
}
CUT_THREADEND;
}
// Stop the timer
sdkStopTimer(&hTimer[0]);
static void multiSolver(TOptionPlan *plan, int nPlans)
{
// allocate and initialize an array of stream handles
cudaStream_t *streams = (cudaStream_t *)malloc(nPlans * sizeof(cudaStream_t));
cudaEvent_t *events = (cudaEvent_t *)malloc(nPlans * sizeof(cudaEvent_t));
for (int i = 0; i < nPlans; i++) {
checkCudaErrors(cudaSetDevice(plan[i].device));
closeMonteCarloGPU(&plan[i]);
checkCudaErrors(cudaStreamDestroy(streams[i]));
checkCudaErrors(cudaEventDestroy(events[i]));
}
for (int i = 0; i < nPlans; i++) {
checkCudaErrors(cudaSetDevice(plan[i].device));
checkCudaErrors(cudaStreamCreate(&(streams[i])));
checkCudaErrors(cudaEventCreate(&(events[i])));
}
// Init Each GPU
// In CUDA 4.0 we can call cudaSetDevice multiple times to target each device
// Set the device desired, then perform initializations on that device
for (int i = 0; i < nPlans; i++) {
// set the target device to perform initialization on
checkCudaErrors(cudaSetDevice(plan[i].device));
cudaDeviceProp deviceProp;
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, plan[i].device));
// Allocate intermediate memory for MC integrator
// and initialize RNG state
initMonteCarloGPU(&plan[i]);
}
for (int i = 0; i < nPlans; i++) {
checkCudaErrors(cudaSetDevice(plan[i].device));
checkCudaErrors(cudaDeviceSynchronize());
}
// Start the timer
sdkResetTimer(&hTimer[0]);
sdkStartTimer(&hTimer[0]);
for (int i = 0; i < nPlans; i++) {
checkCudaErrors(cudaSetDevice(plan[i].device));
// Main computations
MonteCarloGPU(&plan[i], streams[i]);
checkCudaErrors(cudaEventRecord(events[i], streams[i]));
}
for (int i = 0; i < nPlans; i++) {
checkCudaErrors(cudaSetDevice(plan[i].device));
cudaEventSynchronize(events[i]);
}
// Stop the timer
sdkStopTimer(&hTimer[0]);
for (int i = 0; i < nPlans; i++) {
checkCudaErrors(cudaSetDevice(plan[i].device));
closeMonteCarloGPU(&plan[i]);
checkCudaErrors(cudaStreamDestroy(streams[i]));
checkCudaErrors(cudaEventDestroy(events[i]));
}
}
///////////////////////////////////////////////////////////////////////////////
@@ -203,285 +205,279 @@ static void multiSolver(TOptionPlan *plan, int nPlans) {
#define PRINT_RESULTS
#undef PRINT_RESULTS
void usage() {
printf("--method=[threaded,streamed] --scaling=[strong,weak] [--help]\n");
printf("Method=threaded: 1 CPU thread for each GPU [default]\n");
printf(
" streamed: 1 CPU thread handles all GPUs (requires CUDA 4.0 or "
"newer)\n");
printf("Scaling=strong : constant problem size\n");
printf(
" weak : problem size scales with number of available GPUs "
"[default]\n");
void usage()
{
printf("--method=[threaded,streamed] --scaling=[strong,weak] [--help]\n");
printf("Method=threaded: 1 CPU thread for each GPU [default]\n");
printf(" streamed: 1 CPU thread handles all GPUs (requires CUDA 4.0 or "
"newer)\n");
printf("Scaling=strong : constant problem size\n");
printf(" weak : problem size scales with number of available GPUs "
"[default]\n");
}
int main(int argc, char **argv) {
char *multiMethodChoice = NULL;
char *scalingChoice = NULL;
bool use_threads = true;
bool bqatest = false;
bool strongScaling = false;
int main(int argc, char **argv)
{
char *multiMethodChoice = NULL;
char *scalingChoice = NULL;
bool use_threads = true;
bool bqatest = false;
bool strongScaling = false;
pArgc = &argc;
pArgv = argv;
pArgc = &argc;
pArgv = argv;
printf("%s Starting...\n\n", argv[0]);
printf("%s Starting...\n\n", argv[0]);
if (checkCmdLineFlag(argc, (const char **)argv, "qatest")) {
bqatest = true;
}
getCmdLineArgumentString(argc, (const char **)argv, "method",
&multiMethodChoice);
getCmdLineArgumentString(argc, (const char **)argv, "scaling",
&scalingChoice);
if (checkCmdLineFlag(argc, (const char **)argv, "h") ||
checkCmdLineFlag(argc, (const char **)argv, "help")) {
usage();
exit(EXIT_SUCCESS);
}
if (multiMethodChoice == NULL) {
use_threads = false;
} else {
if (!strcasecmp(multiMethodChoice, "threaded")) {
use_threads = true;
} else {
use_threads = false;
}
}
if (use_threads == false) {
printf("Using single CPU thread for multiple GPUs\n");
}
if (scalingChoice == NULL) {
strongScaling = false;
} else {
if (!strcasecmp(scalingChoice, "strong")) {
strongScaling = true;
} else {
strongScaling = false;
}
}
// GPU number present in the system
int GPU_N;
checkCudaErrors(cudaGetDeviceCount(&GPU_N));
int nOptions = 8 * 1024;
nOptions = adjustProblemSize(GPU_N, nOptions);
// select problem size
int scale = (strongScaling) ? 1 : GPU_N;
int OPT_N = nOptions * scale;
int PATH_N = 262144;
// initialize the timers
hTimer = new StopWatchInterface *[GPU_N];
for (int i = 0; i < GPU_N; i++) {
sdkCreateTimer(&hTimer[i]);
sdkResetTimer(&hTimer[i]);
}
// Input data array
TOptionData *optionData = new TOptionData[OPT_N];
// Final GPU MC results
TOptionValue *callValueGPU = new TOptionValue[OPT_N];
//"Theoretical" call values by Black-Scholes formula
float *callValueBS = new float[OPT_N];
// Solver config
TOptionPlan *optionSolver = new TOptionPlan[GPU_N];
// OS thread ID
CUTThread *threadID = new CUTThread[GPU_N];
int gpuBase, gpuIndex;
int i;
float time;
double delta, ref, sumDelta, sumRef, sumReserve;
printf("MonteCarloMultiGPU\n");
printf("==================\n");
printf("Parallelization method = %s\n",
use_threads ? "threaded" : "streamed");
printf("Problem scaling = %s\n", strongScaling ? "strong" : "weak");
printf("Number of GPUs = %d\n", GPU_N);
printf("Total number of options = %d\n", OPT_N);
printf("Number of paths = %d\n", PATH_N);
printf("main(): generating input data...\n");
srand(123);
for (i = 0; i < OPT_N; i++) {
optionData[i].S = randFloat(5.0f, 50.0f);
optionData[i].X = randFloat(10.0f, 25.0f);
optionData[i].T = randFloat(1.0f, 5.0f);
optionData[i].R = 0.06f;
optionData[i].V = 0.10f;
callValueGPU[i].Expected = -1.0f;
callValueGPU[i].Confidence = -1.0f;
}
printf("main(): starting %i host threads...\n", GPU_N);
// Get option count for each GPU
for (i = 0; i < GPU_N; i++) {
optionSolver[i].optionCount = OPT_N / GPU_N;
}
// Take into account cases with "odd" option counts
for (i = 0; i < (OPT_N % GPU_N); i++) {
optionSolver[i].optionCount++;
}
// Assign GPU option ranges
gpuBase = 0;
for (i = 0; i < GPU_N; i++) {
optionSolver[i].device = i;
optionSolver[i].optionData = optionData + gpuBase;
optionSolver[i].callValue = callValueGPU + gpuBase;
optionSolver[i].pathN = PATH_N;
optionSolver[i].gridSize =
adjustGridSize(optionSolver[i].device, optionSolver[i].optionCount);
gpuBase += optionSolver[i].optionCount;
}
if (use_threads || bqatest) {
// Start CPU thread for each GPU
for (gpuIndex = 0; gpuIndex < GPU_N; gpuIndex++) {
threadID[gpuIndex] = cutStartThread((CUT_THREADROUTINE)solverThread,
&optionSolver[gpuIndex]);
if (checkCmdLineFlag(argc, (const char **)argv, "qatest")) {
bqatest = true;
}
printf("main(): waiting for GPU results...\n");
cutWaitForThreads(threadID, GPU_N);
getCmdLineArgumentString(argc, (const char **)argv, "method", &multiMethodChoice);
getCmdLineArgumentString(argc, (const char **)argv, "scaling", &scalingChoice);
printf("main(): GPU statistics, threaded\n");
for (i = 0; i < GPU_N; i++) {
cudaDeviceProp deviceProp;
checkCudaErrors(
cudaGetDeviceProperties(&deviceProp, optionSolver[i].device));
printf("GPU Device #%i: %s\n", optionSolver[i].device, deviceProp.name);
printf("Options : %i\n", optionSolver[i].optionCount);
printf("Simulation paths: %i\n", optionSolver[i].pathN);
time = sdkGetTimerValue(&hTimer[i]);
printf("Total time (ms.): %f\n", time);
printf("Options per sec.: %f\n", OPT_N / (time * 0.001));
if (checkCmdLineFlag(argc, (const char **)argv, "h") || checkCmdLineFlag(argc, (const char **)argv, "help")) {
usage();
exit(EXIT_SUCCESS);
}
printf("main(): comparing Monte Carlo and Black-Scholes results...\n");
sumDelta = 0;
sumRef = 0;
sumReserve = 0;
if (multiMethodChoice == NULL) {
use_threads = false;
}
else {
if (!strcasecmp(multiMethodChoice, "threaded")) {
use_threads = true;
}
else {
use_threads = false;
}
}
if (use_threads == false) {
printf("Using single CPU thread for multiple GPUs\n");
}
if (scalingChoice == NULL) {
strongScaling = false;
}
else {
if (!strcasecmp(scalingChoice, "strong")) {
strongScaling = true;
}
else {
strongScaling = false;
}
}
// GPU number present in the system
int GPU_N;
checkCudaErrors(cudaGetDeviceCount(&GPU_N));
int nOptions = 8 * 1024;
nOptions = adjustProblemSize(GPU_N, nOptions);
// select problem size
int scale = (strongScaling) ? 1 : GPU_N;
int OPT_N = nOptions * scale;
int PATH_N = 262144;
// initialize the timers
hTimer = new StopWatchInterface *[GPU_N];
for (int i = 0; i < GPU_N; i++) {
sdkCreateTimer(&hTimer[i]);
sdkResetTimer(&hTimer[i]);
}
// Input data array
TOptionData *optionData = new TOptionData[OPT_N];
// Final GPU MC results
TOptionValue *callValueGPU = new TOptionValue[OPT_N];
//"Theoretical" call values by Black-Scholes formula
float *callValueBS = new float[OPT_N];
// Solver config
TOptionPlan *optionSolver = new TOptionPlan[GPU_N];
// OS thread ID
CUTThread *threadID = new CUTThread[GPU_N];
int gpuBase, gpuIndex;
int i;
float time;
double delta, ref, sumDelta, sumRef, sumReserve;
printf("MonteCarloMultiGPU\n");
printf("==================\n");
printf("Parallelization method = %s\n", use_threads ? "threaded" : "streamed");
printf("Problem scaling = %s\n", strongScaling ? "strong" : "weak");
printf("Number of GPUs = %d\n", GPU_N);
printf("Total number of options = %d\n", OPT_N);
printf("Number of paths = %d\n", PATH_N);
printf("main(): generating input data...\n");
srand(123);
for (i = 0; i < OPT_N; i++) {
BlackScholesCall(callValueBS[i], optionData[i]);
delta = fabs(callValueBS[i] - callValueGPU[i].Expected);
ref = callValueBS[i];
sumDelta += delta;
sumRef += fabs(ref);
if (delta > 1e-6) {
sumReserve += callValueGPU[i].Confidence / delta;
}
#ifdef PRINT_RESULTS
printf("BS: %f; delta: %E\n", callValueBS[i], delta);
#endif
optionData[i].S = randFloat(5.0f, 50.0f);
optionData[i].X = randFloat(10.0f, 25.0f);
optionData[i].T = randFloat(1.0f, 5.0f);
optionData[i].R = 0.06f;
optionData[i].V = 0.10f;
callValueGPU[i].Expected = -1.0f;
callValueGPU[i].Confidence = -1.0f;
}
sumReserve /= OPT_N;
}
printf("main(): starting %i host threads...\n", GPU_N);
if (!use_threads || bqatest) {
multiSolver(optionSolver, GPU_N);
// Get option count for each GPU
for (i = 0; i < GPU_N; i++) {
optionSolver[i].optionCount = OPT_N / GPU_N;
}
printf("main(): GPU statistics, streamed\n");
// Take into account cases with "odd" option counts
for (i = 0; i < (OPT_N % GPU_N); i++) {
optionSolver[i].optionCount++;
}
// Assign GPU option ranges
gpuBase = 0;
for (i = 0; i < GPU_N; i++) {
cudaDeviceProp deviceProp;
checkCudaErrors(
cudaGetDeviceProperties(&deviceProp, optionSolver[i].device));
printf("GPU Device #%i: %s\n", optionSolver[i].device, deviceProp.name);
printf("Options : %i\n", optionSolver[i].optionCount);
printf("Simulation paths: %i\n", optionSolver[i].pathN);
optionSolver[i].device = i;
optionSolver[i].optionData = optionData + gpuBase;
optionSolver[i].callValue = callValueGPU + gpuBase;
optionSolver[i].pathN = PATH_N;
optionSolver[i].gridSize = adjustGridSize(optionSolver[i].device, optionSolver[i].optionCount);
gpuBase += optionSolver[i].optionCount;
}
time = sdkGetTimerValue(&hTimer[0]);
printf("\nTotal time (ms.): %f\n", time);
printf("\tNote: This is elapsed time for all to compute.\n");
printf("Options per sec.: %f\n", OPT_N / (time * 0.001));
if (use_threads || bqatest) {
// Start CPU thread for each GPU
for (gpuIndex = 0; gpuIndex < GPU_N; gpuIndex++) {
threadID[gpuIndex] = cutStartThread((CUT_THREADROUTINE)solverThread, &optionSolver[gpuIndex]);
}
printf("main(): comparing Monte Carlo and Black-Scholes results...\n");
sumDelta = 0;
sumRef = 0;
sumReserve = 0;
printf("main(): waiting for GPU results...\n");
cutWaitForThreads(threadID, GPU_N);
for (i = 0; i < OPT_N; i++) {
BlackScholesCall(callValueBS[i], optionData[i]);
delta = fabs(callValueBS[i] - callValueGPU[i].Expected);
ref = callValueBS[i];
sumDelta += delta;
sumRef += fabs(ref);
printf("main(): GPU statistics, threaded\n");
if (delta > 1e-6) {
sumReserve += callValueGPU[i].Confidence / delta;
}
for (i = 0; i < GPU_N; i++) {
cudaDeviceProp deviceProp;
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, optionSolver[i].device));
printf("GPU Device #%i: %s\n", optionSolver[i].device, deviceProp.name);
printf("Options : %i\n", optionSolver[i].optionCount);
printf("Simulation paths: %i\n", optionSolver[i].pathN);
time = sdkGetTimerValue(&hTimer[i]);
printf("Total time (ms.): %f\n", time);
printf("Options per sec.: %f\n", OPT_N / (time * 0.001));
}
printf("main(): comparing Monte Carlo and Black-Scholes results...\n");
sumDelta = 0;
sumRef = 0;
sumReserve = 0;
for (i = 0; i < OPT_N; i++) {
BlackScholesCall(callValueBS[i], optionData[i]);
delta = fabs(callValueBS[i] - callValueGPU[i].Expected);
ref = callValueBS[i];
sumDelta += delta;
sumRef += fabs(ref);
if (delta > 1e-6) {
sumReserve += callValueGPU[i].Confidence / delta;
}
#ifdef PRINT_RESULTS
printf("BS: %f; delta: %E\n", callValueBS[i], delta);
printf("BS: %f; delta: %E\n", callValueBS[i], delta);
#endif
}
sumReserve /= OPT_N;
}
sumReserve /= OPT_N;
}
if (!use_threads || bqatest) {
multiSolver(optionSolver, GPU_N);
printf("main(): GPU statistics, streamed\n");
for (i = 0; i < GPU_N; i++) {
cudaDeviceProp deviceProp;
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, optionSolver[i].device));
printf("GPU Device #%i: %s\n", optionSolver[i].device, deviceProp.name);
printf("Options : %i\n", optionSolver[i].optionCount);
printf("Simulation paths: %i\n", optionSolver[i].pathN);
}
time = sdkGetTimerValue(&hTimer[0]);
printf("\nTotal time (ms.): %f\n", time);
printf("\tNote: This is elapsed time for all to compute.\n");
printf("Options per sec.: %f\n", OPT_N / (time * 0.001));
printf("main(): comparing Monte Carlo and Black-Scholes results...\n");
sumDelta = 0;
sumRef = 0;
sumReserve = 0;
for (i = 0; i < OPT_N; i++) {
BlackScholesCall(callValueBS[i], optionData[i]);
delta = fabs(callValueBS[i] - callValueGPU[i].Expected);
ref = callValueBS[i];
sumDelta += delta;
sumRef += fabs(ref);
if (delta > 1e-6) {
sumReserve += callValueGPU[i].Confidence / delta;
}
#ifdef PRINT_RESULTS
printf("BS: %f; delta: %E\n", callValueBS[i], delta);
#endif
}
sumReserve /= OPT_N;
}
#ifdef DO_CPU
printf("main(): running CPU MonteCarlo...\n");
TOptionValue callValueCPU;
sumDelta = 0;
sumRef = 0;
printf("main(): running CPU MonteCarlo...\n");
TOptionValue callValueCPU;
sumDelta = 0;
sumRef = 0;
for (i = 0; i < OPT_N; i++) {
MonteCarloCPU(callValueCPU, optionData[i], NULL, PATH_N);
delta = fabs(callValueCPU.Expected - callValueGPU[i].Expected);
ref = callValueCPU.Expected;
sumDelta += delta;
sumRef += fabs(ref);
printf("Exp : %f | %f\t", callValueCPU.Expected, callValueGPU[i].Expected);
printf("Conf: %f | %f\n", callValueCPU.Confidence,
callValueGPU[i].Confidence);
}
for (i = 0; i < OPT_N; i++) {
MonteCarloCPU(callValueCPU, optionData[i], NULL, PATH_N);
delta = fabs(callValueCPU.Expected - callValueGPU[i].Expected);
ref = callValueCPU.Expected;
sumDelta += delta;
sumRef += fabs(ref);
printf("Exp : %f | %f\t", callValueCPU.Expected, callValueGPU[i].Expected);
printf("Conf: %f | %f\n", callValueCPU.Confidence, callValueGPU[i].Confidence);
}
printf("L1 norm: %E\n", sumDelta / sumRef);
printf("L1 norm: %E\n", sumDelta / sumRef);
#endif
printf("Shutting down...\n");
printf("Shutting down...\n");
for (int i = 0; i < GPU_N; i++) {
sdkStartTimer(&hTimer[i]);
checkCudaErrors(cudaSetDevice(i));
}
for (int i = 0; i < GPU_N; i++) {
sdkStartTimer(&hTimer[i]);
checkCudaErrors(cudaSetDevice(i));
}
delete[] optionSolver;
delete[] callValueBS;
delete[] callValueGPU;
delete[] optionData;
delete[] threadID;
delete[] hTimer;
delete[] optionSolver;
delete[] callValueBS;
delete[] callValueGPU;
delete[] optionData;
delete[] threadID;
delete[] hTimer;
printf("Test Summary...\n");
printf("L1 norm : %E\n", sumDelta / sumRef);
printf("Average reserve: %f\n", sumReserve);
printf(
"\nNOTE: The CUDA Samples are not meant for performance measurements. "
"Results may vary when GPU Boost is enabled.\n\n");
printf(sumReserve > 1.0f ? "Test passed\n" : "Test failed!\n");
exit(sumReserve > 1.0f ? EXIT_SUCCESS : EXIT_FAILURE);
printf("Test Summary...\n");
printf("L1 norm : %E\n", sumDelta / sumRef);
printf("Average reserve: %f\n", sumReserve);
printf("\nNOTE: The CUDA Samples are not meant for performance measurements. "
"Results may vary when GPU Boost is enabled.\n\n");
printf(sumReserve > 1.0f ? "Test passed\n" : "Test failed!\n");
exit(sumReserve > 1.0f ? EXIT_SUCCESS : EXIT_FAILURE);
}

View File

@@ -27,68 +27,71 @@
#ifndef MONTECARLO_COMMON_H
#define MONTECARLO_COMMON_H
#include "realtype.h"
#include "curand_kernel.h"
#include "realtype.h"
////////////////////////////////////////////////////////////////////////////////
// Global types
////////////////////////////////////////////////////////////////////////////////
typedef struct {
float S;
float X;
float T;
float R;
float V;
typedef struct
{
float S;
float X;
float T;
float R;
float V;
} TOptionData;
typedef struct
//#ifdef __CUDACC__
//__align__(8)
//#endif
{
float Expected;
float Confidence;
// #ifdef __CUDACC__
//__align__(8)
// #endif
{
float Expected;
float Confidence;
} TOptionValue;
// GPU outputs before CPU postprocessing
typedef struct {
real Expected;
real Confidence;
typedef struct
{
real Expected;
real Confidence;
} __TOptionValue;
typedef struct {
// Device ID for multi-GPU version
int device;
// Option count for this plan
int optionCount;
typedef struct
{
// Device ID for multi-GPU version
int device;
// Option count for this plan
int optionCount;
// Host-side data source and result destination
TOptionData *optionData;
TOptionValue *callValue;
// Host-side data source and result destination
TOptionData *optionData;
TOptionValue *callValue;
// Temporary Host-side pinned memory for async + faster data transfers
__TOptionValue *h_CallValue;
// Temporary Host-side pinned memory for async + faster data transfers
__TOptionValue *h_CallValue;
// Device- and host-side option data
void *d_OptionData;
void *h_OptionData;
// Device- and host-side option data
void *d_OptionData;
void *h_OptionData;
// Device-side option values
void *d_CallValue;
// Device-side option values
void *d_CallValue;
// Intermediate device-side buffers
void *d_Buffer;
// Intermediate device-side buffers
void *d_Buffer;
// random number generator states
curandState *rngStates;
// random number generator states
curandState *rngStates;
// Pseudorandom samples count
int pathN;
// Pseudorandom samples count
int pathN;
// Time stamp
float time;
// Time stamp
float time;
int gridSize;
int gridSize;
} TOptionPlan;
extern "C" void initMonteCarloGPU(TOptionPlan *plan);

View File

@@ -25,13 +25,12 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <curand.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <curand.h>
//#include "curand_kernel.h"
// #include "curand_kernel.h"
#include "helper_cuda.h"
////////////////////////////////////////////////////////////////////////////////
@@ -42,99 +41,101 @@
////////////////////////////////////////////////////////////////////////////////
// Black-Scholes formula for Monte Carlo results validation
////////////////////////////////////////////////////////////////////////////////
#define A1 0.31938153
#define A2 -0.356563782
#define A3 1.781477937
#define A4 -1.821255978
#define A5 1.330274429
#define A1 0.31938153
#define A2 -0.356563782
#define A3 1.781477937
#define A4 -1.821255978
#define A5 1.330274429
#define RSQRT2PI 0.39894228040143267793994605993438
// Polynomial approximation of
// cumulative normal distribution function
double CND(double d) {
double K = 1.0 / (1.0 + 0.2316419 * fabs(d));
double CND(double d)
{
double K = 1.0 / (1.0 + 0.2316419 * fabs(d));
double cnd = RSQRT2PI * exp(-0.5 * d * d) *
(K * (A1 + K * (A2 + K * (A3 + K * (A4 + K * A5)))));
double cnd = RSQRT2PI * exp(-0.5 * d * d) * (K * (A1 + K * (A2 + K * (A3 + K * (A4 + K * A5)))));
if (d > 0) cnd = 1.0 - cnd;
if (d > 0)
cnd = 1.0 - cnd;
return cnd;
return cnd;
}
// Black-Scholes formula for call value
extern "C" void BlackScholesCall(float &callValue, TOptionData optionData) {
double S = optionData.S;
double X = optionData.X;
double T = optionData.T;
double R = optionData.R;
double V = optionData.V;
extern "C" void BlackScholesCall(float &callValue, TOptionData optionData)
{
double S = optionData.S;
double X = optionData.X;
double T = optionData.T;
double R = optionData.R;
double V = optionData.V;
double sqrtT = sqrt(T);
double d1 = (log(S / X) + (R + 0.5 * V * V) * T) / (V * sqrtT);
double d2 = d1 - V * sqrtT;
double CNDD1 = CND(d1);
double CNDD2 = CND(d2);
double expRT = exp(-R * T);
double sqrtT = sqrt(T);
double d1 = (log(S / X) + (R + 0.5 * V * V) * T) / (V * sqrtT);
double d2 = d1 - V * sqrtT;
double CNDD1 = CND(d1);
double CNDD2 = CND(d2);
double expRT = exp(-R * T);
callValue = (float)(S * CNDD1 - X * expRT * CNDD2);
callValue = (float)(S * CNDD1 - X * expRT * CNDD2);
}
////////////////////////////////////////////////////////////////////////////////
// CPU Monte Carlo
////////////////////////////////////////////////////////////////////////////////
static double endCallValue(double S, double X, double r, double MuByT,
double VBySqrtT) {
double callValue = S * exp(MuByT + VBySqrtT * r) - X;
return (callValue > 0) ? callValue : 0;
static double endCallValue(double S, double X, double r, double MuByT, double VBySqrtT)
{
double callValue = S * exp(MuByT + VBySqrtT * r) - X;
return (callValue > 0) ? callValue : 0;
}
extern "C" void MonteCarloCPU(TOptionValue &callValue, TOptionData optionData,
float *h_Samples, int pathN) {
const double S = optionData.S;
const double X = optionData.X;
const double T = optionData.T;
const double R = optionData.R;
const double V = optionData.V;
const double MuByT = (R - 0.5 * V * V) * T;
const double VBySqrtT = V * sqrt(T);
extern "C" void MonteCarloCPU(TOptionValue &callValue, TOptionData optionData, float *h_Samples, int pathN)
{
const double S = optionData.S;
const double X = optionData.X;
const double T = optionData.T;
const double R = optionData.R;
const double V = optionData.V;
const double MuByT = (R - 0.5 * V * V) * T;
const double VBySqrtT = V * sqrt(T);
float *samples;
curandGenerator_t gen;
float *samples;
curandGenerator_t gen;
checkCudaErrors(curandCreateGeneratorHost(&gen, CURAND_RNG_PSEUDO_DEFAULT));
unsigned long long seed = 1234ULL;
checkCudaErrors(curandSetPseudoRandomGeneratorSeed(gen, seed));
checkCudaErrors(curandCreateGeneratorHost(&gen, CURAND_RNG_PSEUDO_DEFAULT));
unsigned long long seed = 1234ULL;
checkCudaErrors(curandSetPseudoRandomGeneratorSeed(gen, seed));
if (h_Samples != NULL) {
samples = h_Samples;
} else {
samples = (float *)malloc(pathN * sizeof(float));
checkCudaErrors(curandGenerateNormal(gen, samples, pathN, 0.0, 1.0));
}
if (h_Samples != NULL) {
samples = h_Samples;
}
else {
samples = (float *)malloc(pathN * sizeof(float));
checkCudaErrors(curandGenerateNormal(gen, samples, pathN, 0.0, 1.0));
}
// for(int i=0; i<10; i++) printf("CPU sample = %f\n", samples[i]);
// for(int i=0; i<10; i++) printf("CPU sample = %f\n", samples[i]);
double sum = 0, sum2 = 0;
double sum = 0, sum2 = 0;
for (int pos = 0; pos < pathN; pos++) {
double sample = samples[pos];
double callValue = endCallValue(S, X, sample, MuByT, VBySqrtT);
sum += callValue;
sum2 += callValue * callValue;
}
for (int pos = 0; pos < pathN; pos++) {
double sample = samples[pos];
double callValue = endCallValue(S, X, sample, MuByT, VBySqrtT);
sum += callValue;
sum2 += callValue * callValue;
}
if (h_Samples == NULL) free(samples);
if (h_Samples == NULL)
free(samples);
checkCudaErrors(curandDestroyGenerator(gen));
checkCudaErrors(curandDestroyGenerator(gen));
// Derive average from the total sum and discount by riskfree rate
callValue.Expected = (float)(exp(-R * T) * sum / (double)pathN);
// Standard deviation
double stdDev = sqrt(((double)pathN * sum2 - sum * sum) /
((double)pathN * (double)(pathN - 1)));
// Confidence width; in 95% of all cases theoretical value lies within these
// borders
callValue.Confidence =
(float)(exp(-R * T) * 1.96 * stdDev / sqrt((double)pathN));
// Derive average from the total sum and discount by riskfree rate
callValue.Expected = (float)(exp(-R * T) * sum / (double)pathN);
// Standard deviation
double stdDev = sqrt(((double)pathN * sum2 - sum * sum) / ((double)pathN * (double)(pathN - 1)));
// Confidence width; in 95% of all cases theoretical value lies within these
// borders
callValue.Confidence = (float)(exp(-R * T) * 1.96 * stdDev / sqrt((double)pathN));
}

View File

@@ -28,13 +28,14 @@
////////////////////////////////////////////////////////////////////////////////
// Global types
////////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <stdio.h>
#include <cooperative_groups.h>
#include <stdio.h>
#include <stdlib.h>
namespace cg = cooperative_groups;
#include <helper_cuda.h>
#include <curand_kernel.h>
#include <helper_cuda.h>
#include "MonteCarlo_common.h"
////////////////////////////////////////////////////////////////////////////////
@@ -49,26 +50,27 @@ namespace cg = cooperative_groups;
#define MAX_OPTIONS (1024 * 1024)
// Preprocessed input option data
typedef struct {
real S;
real X;
real MuByT;
real VBySqrtT;
typedef struct
{
real S;
real X;
real MuByT;
real VBySqrtT;
} __TOptionData;
////////////////////////////////////////////////////////////////////////////////
// Overloaded shortcut payoff functions for different precision modes
////////////////////////////////////////////////////////////////////////////////
__device__ inline float endCallValue(float S, float X, float r, float MuByT,
float VBySqrtT) {
float callValue = S * __expf(MuByT + VBySqrtT * r) - X;
return (callValue > 0.0F) ? callValue : 0.0F;
__device__ inline float endCallValue(float S, float X, float r, float MuByT, float VBySqrtT)
{
float callValue = S * __expf(MuByT + VBySqrtT * r) - X;
return (callValue > 0.0F) ? callValue : 0.0F;
}
__device__ inline double endCallValue(double S, double X, double r,
double MuByT, double VBySqrtT) {
double callValue = S * exp(MuByT + VBySqrtT * r) - X;
return (callValue > 0.0) ? callValue : 0.0;
__device__ inline double endCallValue(double S, double X, double r, double MuByT, double VBySqrtT)
{
double callValue = S * exp(MuByT + VBySqrtT * r) - X;
return (callValue > 0.0) ? callValue : 0.0;
}
#define THREAD_N 256
@@ -78,149 +80,145 @@ __device__ inline double endCallValue(double S, double X, double r,
// per option. It is fastest when the number of thread blocks times the work per
// block is high enough to keep the GPU busy.
////////////////////////////////////////////////////////////////////////////////
static __global__ void MonteCarloOneBlockPerOption(
curandState *__restrict rngStates,
const __TOptionData *__restrict d_OptionData,
__TOptionValue *__restrict d_CallValue, int pathN, int optionN) {
// Handle to thread block group
cg::thread_block cta = cg::this_thread_block();
cg::thread_block_tile<32> tile32 = cg::tiled_partition<32>(cta);
static __global__ void MonteCarloOneBlockPerOption(curandState *__restrict rngStates,
const __TOptionData *__restrict d_OptionData,
__TOptionValue *__restrict d_CallValue,
int pathN,
int optionN)
{
// Handle to thread block group
cg::thread_block cta = cg::this_thread_block();
cg::thread_block_tile<32> tile32 = cg::tiled_partition<32>(cta);
const int SUM_N = THREAD_N;
__shared__ real s_SumCall[SUM_N];
__shared__ real s_Sum2Call[SUM_N];
const int SUM_N = THREAD_N;
__shared__ real s_SumCall[SUM_N];
__shared__ real s_Sum2Call[SUM_N];
// determine global thread id
int tid = threadIdx.x + blockIdx.x * blockDim.x;
// determine global thread id
int tid = threadIdx.x + blockIdx.x * blockDim.x;
// Copy random number state to local memory for efficiency
curandState localState = rngStates[tid];
for (int optionIndex = blockIdx.x; optionIndex < optionN;
optionIndex += gridDim.x) {
const real S = d_OptionData[optionIndex].S;
const real X = d_OptionData[optionIndex].X;
const real MuByT = d_OptionData[optionIndex].MuByT;
const real VBySqrtT = d_OptionData[optionIndex].VBySqrtT;
// Copy random number state to local memory for efficiency
curandState localState = rngStates[tid];
for (int optionIndex = blockIdx.x; optionIndex < optionN; optionIndex += gridDim.x) {
const real S = d_OptionData[optionIndex].S;
const real X = d_OptionData[optionIndex].X;
const real MuByT = d_OptionData[optionIndex].MuByT;
const real VBySqrtT = d_OptionData[optionIndex].VBySqrtT;
// Cycle through the entire samples array:
// derive end stock price for each path
// accumulate partial integrals into intermediate shared memory buffer
for (int iSum = threadIdx.x; iSum < SUM_N; iSum += blockDim.x) {
__TOptionValue sumCall = {0, 0};
// Cycle through the entire samples array:
// derive end stock price for each path
// accumulate partial integrals into intermediate shared memory buffer
for (int iSum = threadIdx.x; iSum < SUM_N; iSum += blockDim.x) {
__TOptionValue sumCall = {0, 0};
#pragma unroll 8
for (int i = iSum; i < pathN; i += SUM_N) {
real r = curand_normal(&localState);
real callValue = endCallValue(S, X, r, MuByT, VBySqrtT);
sumCall.Expected += callValue;
sumCall.Confidence += callValue * callValue;
}
for (int i = iSum; i < pathN; i += SUM_N) {
real r = curand_normal(&localState);
real callValue = endCallValue(S, X, r, MuByT, VBySqrtT);
sumCall.Expected += callValue;
sumCall.Confidence += callValue * callValue;
}
s_SumCall[iSum] = sumCall.Expected;
s_Sum2Call[iSum] = sumCall.Confidence;
s_SumCall[iSum] = sumCall.Expected;
s_Sum2Call[iSum] = sumCall.Confidence;
}
// Reduce shared memory accumulators
// and write final result to global memory
cg::sync(cta);
sumReduce<real, SUM_N, THREAD_N>(s_SumCall, s_Sum2Call, cta, tile32, &d_CallValue[optionIndex]);
}
// Reduce shared memory accumulators
// and write final result to global memory
cg::sync(cta);
sumReduce<real, SUM_N, THREAD_N>(s_SumCall, s_Sum2Call, cta, tile32,
&d_CallValue[optionIndex]);
}
}
static __global__ void rngSetupStates(curandState *rngState, int device_id) {
// determine global thread id
int tid = threadIdx.x + blockIdx.x * blockDim.x;
// Each threadblock gets different seed,
// Threads within a threadblock get different sequence numbers
curand_init(blockIdx.x + gridDim.x * device_id, threadIdx.x, 0,
&rngState[tid]);
static __global__ void rngSetupStates(curandState *rngState, int device_id)
{
// determine global thread id
int tid = threadIdx.x + blockIdx.x * blockDim.x;
// Each threadblock gets different seed,
// Threads within a threadblock get different sequence numbers
curand_init(blockIdx.x + gridDim.x * device_id, threadIdx.x, 0, &rngState[tid]);
}
////////////////////////////////////////////////////////////////////////////////
// Host-side interface to GPU Monte Carlo
////////////////////////////////////////////////////////////////////////////////
extern "C" void initMonteCarloGPU(TOptionPlan *plan) {
checkCudaErrors(cudaMalloc(&plan->d_OptionData,
sizeof(__TOptionData) * (plan->optionCount)));
checkCudaErrors(cudaMalloc(&plan->d_CallValue,
sizeof(__TOptionValue) * (plan->optionCount)));
checkCudaErrors(cudaMallocHost(&plan->h_OptionData,
sizeof(__TOptionData) * (plan->optionCount)));
// Allocate internal device memory
checkCudaErrors(cudaMallocHost(&plan->h_CallValue,
sizeof(__TOptionValue) * (plan->optionCount)));
// Allocate states for pseudo random number generators
checkCudaErrors(cudaMalloc((void **)&plan->rngStates,
plan->gridSize * THREAD_N * sizeof(curandState)));
checkCudaErrors(cudaMemset(plan->rngStates, 0,
plan->gridSize * THREAD_N * sizeof(curandState)));
extern "C" void initMonteCarloGPU(TOptionPlan *plan)
{
checkCudaErrors(cudaMalloc(&plan->d_OptionData, sizeof(__TOptionData) * (plan->optionCount)));
checkCudaErrors(cudaMalloc(&plan->d_CallValue, sizeof(__TOptionValue) * (plan->optionCount)));
checkCudaErrors(cudaMallocHost(&plan->h_OptionData, sizeof(__TOptionData) * (plan->optionCount)));
// Allocate internal device memory
checkCudaErrors(cudaMallocHost(&plan->h_CallValue, sizeof(__TOptionValue) * (plan->optionCount)));
// Allocate states for pseudo random number generators
checkCudaErrors(cudaMalloc((void **)&plan->rngStates, plan->gridSize * THREAD_N * sizeof(curandState)));
checkCudaErrors(cudaMemset(plan->rngStates, 0, plan->gridSize * THREAD_N * sizeof(curandState)));
// place each device pathN random numbers apart on the random number sequence
rngSetupStates<<<plan->gridSize, THREAD_N>>>(plan->rngStates, plan->device);
getLastCudaError("rngSetupStates kernel failed.\n");
// place each device pathN random numbers apart on the random number sequence
rngSetupStates<<<plan->gridSize, THREAD_N>>>(plan->rngStates, plan->device);
getLastCudaError("rngSetupStates kernel failed.\n");
}
// Compute statistics and deallocate internal device memory
extern "C" void closeMonteCarloGPU(TOptionPlan *plan) {
for (int i = 0; i < plan->optionCount; i++) {
const double RT = plan->optionData[i].R * plan->optionData[i].T;
const double sum = plan->h_CallValue[i].Expected;
const double sum2 = plan->h_CallValue[i].Confidence;
const double pathN = plan->pathN;
// Derive average from the total sum and discount by riskfree rate
plan->callValue[i].Expected = (float)(exp(-RT) * sum / pathN);
// Standard deviation
double stdDev = sqrt((pathN * sum2 - sum * sum) / (pathN * (pathN - 1)));
// Confidence width; in 95% of all cases theoretical value lies within these
// borders
plan->callValue[i].Confidence =
(float)(exp(-RT) * 1.96 * stdDev / sqrt(pathN));
}
extern "C" void closeMonteCarloGPU(TOptionPlan *plan)
{
for (int i = 0; i < plan->optionCount; i++) {
const double RT = plan->optionData[i].R * plan->optionData[i].T;
const double sum = plan->h_CallValue[i].Expected;
const double sum2 = plan->h_CallValue[i].Confidence;
const double pathN = plan->pathN;
// Derive average from the total sum and discount by riskfree rate
plan->callValue[i].Expected = (float)(exp(-RT) * sum / pathN);
// Standard deviation
double stdDev = sqrt((pathN * sum2 - sum * sum) / (pathN * (pathN - 1)));
// Confidence width; in 95% of all cases theoretical value lies within these
// borders
plan->callValue[i].Confidence = (float)(exp(-RT) * 1.96 * stdDev / sqrt(pathN));
}
checkCudaErrors(cudaFree(plan->rngStates));
checkCudaErrors(cudaFreeHost(plan->h_CallValue));
checkCudaErrors(cudaFreeHost(plan->h_OptionData));
checkCudaErrors(cudaFree(plan->d_CallValue));
checkCudaErrors(cudaFree(plan->d_OptionData));
checkCudaErrors(cudaFree(plan->rngStates));
checkCudaErrors(cudaFreeHost(plan->h_CallValue));
checkCudaErrors(cudaFreeHost(plan->h_OptionData));
checkCudaErrors(cudaFree(plan->d_CallValue));
checkCudaErrors(cudaFree(plan->d_OptionData));
}
// Main computations
extern "C" void MonteCarloGPU(TOptionPlan *plan, cudaStream_t stream) {
__TOptionValue *h_CallValue = plan->h_CallValue;
extern "C" void MonteCarloGPU(TOptionPlan *plan, cudaStream_t stream)
{
__TOptionValue *h_CallValue = plan->h_CallValue;
if (plan->optionCount <= 0 || plan->optionCount > MAX_OPTIONS) {
printf("MonteCarloGPU(): bad option count.\n");
return;
}
if (plan->optionCount <= 0 || plan->optionCount > MAX_OPTIONS) {
printf("MonteCarloGPU(): bad option count.\n");
return;
}
__TOptionData *h_OptionData = (__TOptionData *)plan->h_OptionData;
__TOptionData *h_OptionData = (__TOptionData *)plan->h_OptionData;
for (int i = 0; i < plan->optionCount; i++) {
const double T = plan->optionData[i].T;
const double R = plan->optionData[i].R;
const double V = plan->optionData[i].V;
const double MuByT = (R - 0.5 * V * V) * T;
const double VBySqrtT = V * sqrt(T);
h_OptionData[i].S = (real)plan->optionData[i].S;
h_OptionData[i].X = (real)plan->optionData[i].X;
h_OptionData[i].MuByT = (real)MuByT;
h_OptionData[i].VBySqrtT = (real)VBySqrtT;
}
for (int i = 0; i < plan->optionCount; i++) {
const double T = plan->optionData[i].T;
const double R = plan->optionData[i].R;
const double V = plan->optionData[i].V;
const double MuByT = (R - 0.5 * V * V) * T;
const double VBySqrtT = V * sqrt(T);
h_OptionData[i].S = (real)plan->optionData[i].S;
h_OptionData[i].X = (real)plan->optionData[i].X;
h_OptionData[i].MuByT = (real)MuByT;
h_OptionData[i].VBySqrtT = (real)VBySqrtT;
}
checkCudaErrors(cudaMemcpyAsync(plan->d_OptionData, h_OptionData,
plan->optionCount * sizeof(__TOptionData),
cudaMemcpyHostToDevice, stream));
checkCudaErrors(cudaMemcpyAsync(
plan->d_OptionData, h_OptionData, plan->optionCount * sizeof(__TOptionData), cudaMemcpyHostToDevice, stream));
MonteCarloOneBlockPerOption<<<plan->gridSize, THREAD_N, 0, stream>>>(
plan->rngStates, (__TOptionData *)(plan->d_OptionData),
(__TOptionValue *)(plan->d_CallValue), plan->pathN, plan->optionCount);
getLastCudaError("MonteCarloOneBlockPerOption() execution failed\n");
MonteCarloOneBlockPerOption<<<plan->gridSize, THREAD_N, 0, stream>>>(plan->rngStates,
(__TOptionData *)(plan->d_OptionData),
(__TOptionValue *)(plan->d_CallValue),
plan->pathN,
plan->optionCount);
getLastCudaError("MonteCarloOneBlockPerOption() execution failed\n");
checkCudaErrors(cudaMemcpyAsync(h_CallValue, plan->d_CallValue,
plan->optionCount * sizeof(__TOptionValue),
cudaMemcpyDeviceToHost, stream));
checkCudaErrors(cudaMemcpyAsync(
h_CallValue, plan->d_CallValue, plan->optionCount * sizeof(__TOptionValue), cudaMemcpyDeviceToHost, stream));
// cudaDeviceSynchronize();
// cudaDeviceSynchronize();
}

View File

@@ -40,40 +40,40 @@ namespace cg = cooperative_groups;
////////////////////////////////////////////////////////////////////////////////
template <class T, int SUM_N, int blockSize>
__device__ void sumReduce(T *sum, T *sum2, cg::thread_block &cta,
cg::thread_block_tile<32> &tile32,
__TOptionValue *d_CallValue) {
const int VEC = 32;
const int tid = cta.thread_rank();
__device__ void
sumReduce(T *sum, T *sum2, cg::thread_block &cta, cg::thread_block_tile<32> &tile32, __TOptionValue *d_CallValue)
{
const int VEC = 32;
const int tid = cta.thread_rank();
T beta = sum[tid];
T beta2 = sum2[tid];
T temp, temp2;
T beta = sum[tid];
T beta2 = sum2[tid];
T temp, temp2;
for (int i = VEC / 2; i > 0; i >>= 1) {
if (tile32.thread_rank() < i) {
temp = sum[tid + i];
temp2 = sum2[tid + i];
beta += temp;
beta2 += temp2;
sum[tid] = beta;
sum2[tid] = beta2;
for (int i = VEC / 2; i > 0; i >>= 1) {
if (tile32.thread_rank() < i) {
temp = sum[tid + i];
temp2 = sum2[tid + i];
beta += temp;
beta2 += temp2;
sum[tid] = beta;
sum2[tid] = beta2;
}
cg::sync(tile32);
}
cg::sync(tile32);
}
cg::sync(cta);
cg::sync(cta);
if (tid == 0) {
beta = 0;
beta2 = 0;
for (int i = 0; i < blockDim.x; i += VEC) {
beta += sum[i];
beta2 += sum2[i];
if (tid == 0) {
beta = 0;
beta2 = 0;
for (int i = 0; i < blockDim.x; i += VEC) {
beta += sum[i];
beta2 += sum2[i];
}
__TOptionValue t = {beta, beta2};
*d_CallValue = t;
}
__TOptionValue t = {beta, beta2};
*d_CallValue = t;
}
cg::sync(cta);
cg::sync(cta);
}
#endif

View File

@@ -29,41 +29,46 @@
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
// Create thread
CUTThread cutStartThread(CUT_THREADROUTINE func, void *data) {
return CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, data, 0, NULL);
CUTThread cutStartThread(CUT_THREADROUTINE func, void *data)
{
return CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, data, 0, NULL);
}
// Wait for thread to finish
void cutEndThread(CUTThread thread) {
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
void cutEndThread(CUTThread thread)
{
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
}
// Wait for multiple threads
void cutWaitForThreads(const CUTThread *threads, int num) {
WaitForMultipleObjects(num, threads, true, INFINITE);
void cutWaitForThreads(const CUTThread *threads, int num)
{
WaitForMultipleObjects(num, threads, true, INFINITE);
for (int i = 0; i < num; i++) {
CloseHandle(threads[i]);
}
for (int i = 0; i < num; i++) {
CloseHandle(threads[i]);
}
}
#else
// Create thread
CUTThread cutStartThread(CUT_THREADROUTINE func, void *data) {
pthread_t thread;
pthread_create(&thread, NULL, func, data);
return thread;
CUTThread cutStartThread(CUT_THREADROUTINE func, void *data)
{
pthread_t thread;
pthread_create(&thread, NULL, func, data);
return thread;
}
// Wait for thread to finish
void cutEndThread(CUTThread thread) { pthread_join(thread, NULL); }
// Wait for multiple threads
void cutWaitForThreads(const CUTThread *threads, int num) {
for (int i = 0; i < num; i++) {
cutEndThread(threads[i]);
}
void cutWaitForThreads(const CUTThread *threads, int num)
{
for (int i = 0; i < num; i++) {
cutEndThread(threads[i]);
}
}
#endif

View File

@@ -38,7 +38,7 @@ typedef HANDLE CUTThread;
typedef unsigned(WINAPI *CUT_THREADROUTINE)(void *);
#define CUT_THREADPROC unsigned WINAPI
#define CUT_THREADEND return 0
#define CUT_THREADEND return 0
#else
// POSIX threads.
@@ -52,20 +52,21 @@ typedef void *(*CUT_THREADROUTINE)(void *);
#endif
#ifdef __cplusplus
extern "C" {
extern "C"
{
#endif
// Create thread.
CUTThread cutStartThread(CUT_THREADROUTINE, void *data);
// Create thread.
CUTThread cutStartThread(CUT_THREADROUTINE, void *data);
// Wait for thread to finish.
void cutEndThread(CUTThread thread);
// Wait for thread to finish.
void cutEndThread(CUTThread thread);
// Wait for multiple threads.
void cutWaitForThreads(const CUTThread *threads, int num);
// Wait for multiple threads.
void cutWaitForThreads(const CUTThread *threads, int num);
#ifdef __cplusplus
} // extern "C"
} // extern "C"
#endif
#endif // MULTITHREADING_H
#endif // MULTITHREADING_H

View File

@@ -28,7 +28,7 @@
#ifndef REALTYPE_H
#define REALTYPE_H
//#define DOUBLE_PRECISION
// #define DOUBLE_PRECISION
#ifndef DOUBLE_PRECISION
typedef float real;