mirror of
https://github.com/NVIDIA/cuda-samples.git
synced 2026-10-13 00:08:26 +08:00
CUDA 13.2 samples update (#432)
- Added Python samples for CUDA Python 1.0 release - Renamed top-level `Samples` directory to `cpp` to accommodate Python samples.
This commit is contained in:
18
cpp/5_Domain_Specific/MonteCarloMultiGPU/.vscode/c_cpp_properties.json
vendored
Normal file
18
cpp/5_Domain_Specific/MonteCarloMultiGPU/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/../../../Common"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/local/cuda/bin/nvcc",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "gnu++14",
|
||||
"intelliSenseMode": "linux-gcc-x64",
|
||||
"configurationProvider": "ms-vscode.makefile-tools"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
7
cpp/5_Domain_Specific/MonteCarloMultiGPU/.vscode/extensions.json
vendored
Normal file
7
cpp/5_Domain_Specific/MonteCarloMultiGPU/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"nvidia.nsight-vscode-edition",
|
||||
"ms-vscode.cpptools",
|
||||
"ms-vscode.makefile-tools"
|
||||
]
|
||||
}
|
||||
42
cpp/5_Domain_Specific/MonteCarloMultiGPU/CMakeLists.txt
Normal file
42
cpp/5_Domain_Specific/MonteCarloMultiGPU/CMakeLists.txt
Normal file
@@ -0,0 +1,42 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/Modules")
|
||||
|
||||
project(MonteCarloMultiGPU LANGUAGES C CXX CUDA)
|
||||
|
||||
find_package(CUDAToolkit REQUIRED)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(CMAKE_CUDA_ARCHITECTURES 75 80 86 87 89 90 100 110 120)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Wno-deprecated-gpu-targets")
|
||||
if(ENABLE_CUDA_DEBUG)
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -G") # enable cuda-gdb (may significantly affect performance on some targets)
|
||||
else()
|
||||
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo") # add line information to all builds for debug tools (exclusive to -G option)
|
||||
endif()
|
||||
|
||||
# Include directories and libraries
|
||||
include_directories(../../../Common)
|
||||
|
||||
# Source file
|
||||
# Add target for MonteCarloMultiGPU
|
||||
add_executable(MonteCarloMultiGPU MonteCarlo_gold.cpp MonteCarlo_kernel.cu multithreading.cpp MonteCarloMultiGPU.cpp)
|
||||
|
||||
target_compile_options(MonteCarloMultiGPU PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--extended-lambda>)
|
||||
|
||||
target_compile_features(MonteCarloMultiGPU PRIVATE cxx_std_17 cuda_std_17)
|
||||
|
||||
set_target_properties(MonteCarloMultiGPU PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
|
||||
|
||||
target_include_directories(MonteCarloMultiGPU PRIVATE
|
||||
${CUDAToolkit_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(MonteCarloMultiGPU PRIVATE
|
||||
CUDA::curand
|
||||
)
|
||||
|
||||
# Include installation configuration
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/InstallSamples.cmake)
|
||||
setup_samples_install()
|
||||
483
cpp/5_Domain_Specific/MonteCarloMultiGPU/MonteCarloMultiGPU.cpp
Normal file
483
cpp/5_Domain_Specific/MonteCarloMultiGPU/MonteCarloMultiGPU.cpp
Normal file
@@ -0,0 +1,483 @@
|
||||
/* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This sample evaluates fair call price for a
|
||||
* given set of European options using Monte Carlo approach.
|
||||
* See supplied whitepaper for more explanations.
|
||||
*/
|
||||
|
||||
#include <cuda_runtime.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// includes, project
|
||||
#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;
|
||||
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 < 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);
|
||||
}
|
||||
}
|
||||
|
||||
return nOptions;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// 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 < 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]));
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Main program
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define DO_CPU
|
||||
#undef DO_CPU
|
||||
|
||||
#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");
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
printf("main(): waiting for GPU results...\n");
|
||||
cutWaitForThreads(threadID, GPU_N);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 < GPU_N; i++) {
|
||||
sdkStartTimer(&hTimer[i]);
|
||||
checkCudaErrors(cudaSetDevice(i));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
101
cpp/5_Domain_Specific/MonteCarloMultiGPU/MonteCarlo_common.h
Normal file
101
cpp/5_Domain_Specific/MonteCarloMultiGPU/MonteCarlo_common.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef MONTECARLO_COMMON_H
|
||||
#define MONTECARLO_COMMON_H
|
||||
#include "curand_kernel.h"
|
||||
#include "realtype.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Global types
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
typedef struct
|
||||
{
|
||||
float S;
|
||||
float X;
|
||||
float T;
|
||||
float R;
|
||||
float V;
|
||||
} TOptionData;
|
||||
|
||||
typedef struct
|
||||
// #ifdef __CUDACC__
|
||||
//__align__(8)
|
||||
// #endif
|
||||
{
|
||||
float Expected;
|
||||
float Confidence;
|
||||
} TOptionValue;
|
||||
|
||||
// GPU outputs before CPU postprocessing
|
||||
typedef struct
|
||||
{
|
||||
real Expected;
|
||||
real Confidence;
|
||||
} __TOptionValue;
|
||||
|
||||
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;
|
||||
|
||||
// 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-side option values
|
||||
void *d_CallValue;
|
||||
|
||||
// Intermediate device-side buffers
|
||||
void *d_Buffer;
|
||||
|
||||
// random number generator states
|
||||
curandState *rngStates;
|
||||
|
||||
// Pseudorandom samples count
|
||||
int pathN;
|
||||
|
||||
// Time stamp
|
||||
float time;
|
||||
|
||||
int gridSize;
|
||||
} TOptionPlan;
|
||||
|
||||
extern "C" void initMonteCarloGPU(TOptionPlan *plan);
|
||||
extern "C" void MonteCarloGPU(TOptionPlan *plan, cudaStream_t stream = 0);
|
||||
extern "C" void closeMonteCarloGPU(TOptionPlan *plan);
|
||||
|
||||
#endif
|
||||
141
cpp/5_Domain_Specific/MonteCarloMultiGPU/MonteCarlo_gold.cpp
Normal file
141
cpp/5_Domain_Specific/MonteCarloMultiGPU/MonteCarlo_gold.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
/* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* 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 "curand_kernel.h"
|
||||
#include "helper_cuda.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Common types
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include "MonteCarlo_common.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 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 = RSQRT2PI * exp(-0.5 * d * d) * (K * (A1 + K * (A2 + K * (A3 + K * (A4 + K * A5)))));
|
||||
|
||||
if (d > 0)
|
||||
cnd = 1.0 - 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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
// for(int i=0; i<10; i++) printf("CPU sample = %f\n", samples[i]);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (h_Samples == NULL)
|
||||
free(samples);
|
||||
|
||||
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));
|
||||
}
|
||||
224
cpp/5_Domain_Specific/MonteCarloMultiGPU/MonteCarlo_kernel.cu
Normal file
224
cpp/5_Domain_Specific/MonteCarloMultiGPU/MonteCarlo_kernel.cu
Normal file
@@ -0,0 +1,224 @@
|
||||
/* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Global types
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include <cooperative_groups.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace cg = cooperative_groups;
|
||||
#include <curand_kernel.h>
|
||||
#include <helper_cuda.h>
|
||||
|
||||
#include "MonteCarlo_common.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Helper reduction template
|
||||
// Please see the "reduction" CUDA Sample for more information
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include "MonteCarlo_reduction.cuh"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Internal GPU-side data structures
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define MAX_OPTIONS (1024 * 1024)
|
||||
|
||||
// Preprocessed input option data
|
||||
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 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
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// This kernel computes the integral over all paths using a single thread block
|
||||
// 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);
|
||||
|
||||
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;
|
||||
|
||||
// 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};
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
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)));
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (plan->optionCount <= 0 || plan->optionCount > MAX_OPTIONS) {
|
||||
printf("MonteCarloGPU(): bad option count.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
__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;
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
checkCudaErrors(cudaMemcpyAsync(
|
||||
h_CallValue, plan->d_CallValue, plan->optionCount * sizeof(__TOptionValue), cudaMemcpyDeviceToHost, stream));
|
||||
|
||||
// cudaDeviceSynchronize();
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef MONTECARLO_REDUCTION_CUH
|
||||
#define MONTECARLO_REDUCTION_CUH
|
||||
|
||||
#include <cooperative_groups.h>
|
||||
|
||||
namespace cg = cooperative_groups;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// This function calculates total sum for each of the two input arrays.
|
||||
// SUM_N must be power of two
|
||||
// Unrolling provides a bit of a performance improvement for small
|
||||
// to medium path counts.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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();
|
||||
|
||||
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;
|
||||
}
|
||||
cg::sync(tile32);
|
||||
}
|
||||
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];
|
||||
}
|
||||
__TOptionValue t = {beta, beta2};
|
||||
*d_CallValue = t;
|
||||
}
|
||||
cg::sync(cta);
|
||||
}
|
||||
|
||||
#endif
|
||||
38
cpp/5_Domain_Specific/MonteCarloMultiGPU/README.md
Normal file
38
cpp/5_Domain_Specific/MonteCarloMultiGPU/README.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# MonteCarloMultiGPU - Monte Carlo Option Pricing with Multi-GPU support
|
||||
|
||||
## Description
|
||||
|
||||
This sample evaluates fair call price for a given set of European options using the Monte Carlo approach, taking advantage of all CUDA-capable GPUs installed in the system. This sample use double precision hardware if a GTX 200 class GPU is present. The sample also takes advantage of CUDA 4.0 capability to supporting using a single CPU thread to control multiple GPUs
|
||||
|
||||
## Key Concepts
|
||||
|
||||
Random Number Generator, Computational Finance, CURAND Library
|
||||
|
||||
## Supported SM Architectures
|
||||
|
||||
[SM 5.0 ](https://developer.nvidia.com/cuda-gpus) [SM 5.2 ](https://developer.nvidia.com/cuda-gpus) [SM 5.3 ](https://developer.nvidia.com/cuda-gpus) [SM 6.0 ](https://developer.nvidia.com/cuda-gpus) [SM 6.1 ](https://developer.nvidia.com/cuda-gpus) [SM 7.0 ](https://developer.nvidia.com/cuda-gpus) [SM 7.2 ](https://developer.nvidia.com/cuda-gpus) [SM 7.5 ](https://developer.nvidia.com/cuda-gpus) [SM 8.0 ](https://developer.nvidia.com/cuda-gpus) [SM 8.6 ](https://developer.nvidia.com/cuda-gpus) [SM 8.7 ](https://developer.nvidia.com/cuda-gpus) [SM 8.9 ](https://developer.nvidia.com/cuda-gpus) [SM 9.0 ](https://developer.nvidia.com/cuda-gpus)
|
||||
|
||||
## Supported OSes
|
||||
|
||||
Linux, Windows
|
||||
|
||||
## Supported CPU Architecture
|
||||
|
||||
x86_64, armv7l
|
||||
|
||||
## CUDA APIs involved
|
||||
|
||||
### [CUDA Runtime API](http://docs.nvidia.com/cuda/cuda-runtime-api/index.html)
|
||||
cudaStreamDestroy, cudaMalloc, cudaFree, cudaMallocHost, cudaSetDevice, cudaEventSynchronize, cudaGetDeviceProperties, cudaDeviceSynchronize, cudaEventRecord, cudaFreeHost, cudaMemset, cudaStreamSynchronize, cudaEventDestroy, cudaMemcpyAsync, cudaStreamCreate, cudaGetDeviceCount, cudaEventCreate
|
||||
|
||||
## Dependencies needed to build/run
|
||||
[CURAND](../../../README.md#curand)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Download and install the [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
|
||||
Make sure the dependencies mentioned in [Dependencies]() section above are installed.
|
||||
|
||||
## References (for more details)
|
||||
|
||||
[whitepaper](./doc/MonteCarlo.pdf)
|
||||
BIN
cpp/5_Domain_Specific/MonteCarloMultiGPU/doc/MonteCarlo.doc
Normal file
BIN
cpp/5_Domain_Specific/MonteCarloMultiGPU/doc/MonteCarlo.doc
Normal file
Binary file not shown.
BIN
cpp/5_Domain_Specific/MonteCarloMultiGPU/doc/MonteCarlo.pdf
Normal file
BIN
cpp/5_Domain_Specific/MonteCarloMultiGPU/doc/MonteCarlo.pdf
Normal file
Binary file not shown.
74
cpp/5_Domain_Specific/MonteCarloMultiGPU/multithreading.cpp
Normal file
74
cpp/5_Domain_Specific/MonteCarloMultiGPU/multithreading.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <multithreading.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
// Wait for thread to finish
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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]);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
72
cpp/5_Domain_Specific/MonteCarloMultiGPU/multithreading.h
Normal file
72
cpp/5_Domain_Specific/MonteCarloMultiGPU/multithreading.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef MULTITHREADING_H
|
||||
#define MULTITHREADING_H
|
||||
|
||||
// Simple portable thread library.
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
|
||||
// Windows threads.
|
||||
#include <windows.h>
|
||||
|
||||
typedef HANDLE CUTThread;
|
||||
typedef unsigned(WINAPI *CUT_THREADROUTINE)(void *);
|
||||
|
||||
#define CUT_THREADPROC unsigned WINAPI
|
||||
#define CUT_THREADEND return 0
|
||||
|
||||
#else
|
||||
// POSIX threads.
|
||||
#include <pthread.h>
|
||||
|
||||
typedef pthread_t CUTThread;
|
||||
typedef void *(*CUT_THREADROUTINE)(void *);
|
||||
|
||||
#define CUT_THREADPROC void
|
||||
#define CUT_THREADEND
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
// Create thread.
|
||||
CUTThread cutStartThread(CUT_THREADROUTINE, void *data);
|
||||
|
||||
// Wait for thread to finish.
|
||||
void cutEndThread(CUTThread thread);
|
||||
|
||||
// Wait for multiple threads.
|
||||
void cutWaitForThreads(const CUTThread *threads, int num);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // MULTITHREADING_H
|
||||
39
cpp/5_Domain_Specific/MonteCarloMultiGPU/realtype.h
Normal file
39
cpp/5_Domain_Specific/MonteCarloMultiGPU/realtype.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef REALTYPE_H
|
||||
#define REALTYPE_H
|
||||
|
||||
// #define DOUBLE_PRECISION
|
||||
|
||||
#ifndef DOUBLE_PRECISION
|
||||
typedef float real;
|
||||
#else
|
||||
typedef double real;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user