/** * Copyright 1993-2015 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ /* * This sample evaluates fair call price for a * given set of European options using Monte Carlo approach. * See supplied whitepaper for more explanations. */ #include #include #include #include #include // includes, project #include // Helper functions (utilities, parsing, timing) #include // helper functions (cuda error checking and initialization) #include #include "MonteCarlo_common.h" int *pArgc = NULL; char **pArgv = NULL; #ifdef WIN32 #define strcasecmp _strcmpi #endif //////////////////////////////////////////////////////////////////////////////// // Common functions //////////////////////////////////////////////////////////////////////////////// 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; // select problem size for (int i=0; i maxGridSize) ? maxGridSize : defaultGridSize); } /////////////////////////////////////////////////////////////////////////////// // CPU reference functions /////////////////////////////////////////////////////////////////////////////// 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 ); //////////////////////////////////////////////////////////////////////////////// // GPU-driving host thread //////////////////////////////////////////////////////////////////////////////// //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 1e-6) { sumReserve += callValueGPU[i].Confidence / delta; } #ifdef PRINT_RESULTS printf("BS: %f; delta: %E\n", callValueBS[i], delta); #endif } 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; 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); #endif printf("Shutting down...\n"); for (int i=0; i 1.0f ? "Test passed\n" : "Test failed!\n"); exit(sumReserve > 1.0f ? EXIT_SUCCESS : EXIT_FAILURE); }