/* 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. */ /////////////////////////////////////////////////////////////////////////////// // Monte Carlo: Estimate Pi // ======================== // // This sample demonstrates a very simple Monte Carlo estimation for Pi. // // This file, main.cpp, contains the setup information to run the test, for // example parsing the command line and integrating this sample with the // samples framework. As such it is perhaps less interesting than the guts of // the sample. Readers wishing to skip the clutter are advised to skip straight // to Test.operator() in test.cpp. /////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include "../inc/test.h" // SDK information static const char *printfFile = "MonteCarloEstimatePiInlineP.txt"; // Forward declarations void showHelp(const int argc, const char **argv); template void runTest(int argc, const char **argv); int main(int argc, char **argv) { using std::invalid_argument; using std::string; // Open the log file printf("Monte Carlo Estimate Pi (with inline PRNG)\n"); printf("==========================================\n\n"); // If help flag is set, display help and exit immediately if (checkCmdLineFlag(argc, (const char **)argv, "help")) { printf("Displaying help on console\n"); showHelp(argc, (const char **)argv); exit(EXIT_SUCCESS); } // Check the precision (checked against the device capability later) try { char *value; if (getCmdLineArgumentString(argc, (const char **)argv, "precision", &value)) { // Check requested precision is valid string prec(value); if (prec.compare("single") == 0 || prec.compare("\"single\"") == 0) { runTest(argc, (const char **)argv); } else if (prec.compare("double") == 0 || prec.compare("\"double\"") == 0) { runTest(argc, (const char **)argv); } else { printf( "specified precision (%s) is invalid, must be \"single\" or " "\"double\".\n", value); throw invalid_argument("precision"); } } else { runTest(argc, (const char **)argv); } } catch (invalid_argument &e) { printf("invalid command line argument (%s)\n", e.what()); exit(EXIT_FAILURE); } // Finish exit(EXIT_SUCCESS); } template void runTest(int argc, const char **argv) { using std::invalid_argument; using std::runtime_error; try { Test test; int deviceCount = 0; cudaError_t cudaResult = cudaSuccess; // by default specify GPU Device == 0 test.device = 0; // Get number of available devices cudaResult = cudaGetDeviceCount(&deviceCount); if (cudaResult != cudaSuccess) { printf("could not get device count (%s).\n", cudaGetErrorString(cudaResult)); throw runtime_error("cudaGetDeviceCount"); } // (default parameters) test.numSims = k_sims_qa; test.threadBlockSize = k_bsize_qa; test.seed = k_seed_def; { char *value = 0; if (getCmdLineArgumentString(argc, argv, "device", &value)) { test.device = (int)atoi(value); if (test.device >= deviceCount) { printf( "invalid target device specified on command line (device %d does " "not exist).\n", test.device); throw invalid_argument("device"); } } else { test.device = gpuGetMaxGflopsDeviceId(); } if (getCmdLineArgumentString(argc, argv, "sims", &value)) { test.numSims = (unsigned int)atoi(value); printf("number of simulations = %d\n", test.numSims); if (test.numSims < k_sims_min || test.numSims > k_sims_max) { printf( "specified number of simulations (%d) is invalid, must be " "between %d and %d.\n", test.numSims, k_sims_min, k_sims_max); throw invalid_argument("sims"); } } else { test.numSims = k_sims_def; } if (getCmdLineArgumentString(argc, argv, "block-size", &value)) { // Determine max threads per block cudaDeviceProp deviceProperties; cudaResult = cudaGetDeviceProperties(&deviceProperties, test.device); if (cudaResult != cudaSuccess) { printf("unable to get device properties for device %d.\n", test.device); throw runtime_error("cudaGetDeviceProperties"); } // Check requested size is valid test.threadBlockSize = (unsigned int)atoi(value); printf("block size = %d\n", test.threadBlockSize); if (test.threadBlockSize < k_bsize_min || test.threadBlockSize > static_cast( deviceProperties.maxThreadsPerBlock)) { printf( "specified block size (%d) is invalid, must be between %d and %d " "for device %d.\n", test.threadBlockSize, k_bsize_min, deviceProperties.maxThreadsPerBlock, test.device); throw invalid_argument("block-size"); } if (test.threadBlockSize & test.threadBlockSize - 1) { printf( "specified block size (%d) is invalid, must be a power of two " "(see reduction function).\n", test.threadBlockSize); throw invalid_argument("block-size"); } } else { test.threadBlockSize = k_bsize_def; } if (getCmdLineArgumentString(argc, argv, "seed", &value)) { // Check requested seed is valid test.seed = (unsigned int)atoi(value); printf("seed = %d\n", test.seed); if (test.seed == 0) { printf("specified seed (%d) is invalid, must be non-zero.\n", test.seed); throw invalid_argument("seed"); } } else { test.seed = k_seed_def; } } // Execute test(); } catch (invalid_argument &e) { printf("invalid command line argument (%s)\n", e.what()); exit(EXIT_FAILURE); } catch (runtime_error &e) { printf("runtime error (%s)\n", e.what()); exit(EXIT_FAILURE); } } void showHelp(int argc, const char **argv) { using std::cout; using std::endl; using std::left; using std::setw; if (argc > 0) { cout << endl << argv[0] << endl; } cout << endl << "Syntax:" << endl; cout << left; cout << " " << setw(20) << "--device=" << "Specify device to use for execution" << endl; cout << " " << setw(20) << "--sims=" << "Specify number of Monte Carlo simulations" << endl; cout << " " << setw(20) << "--block-size=" << "Specify number of threads per block" << endl; cout << " " << setw(20) << "--seed=" << "Specify the seed to use for the random number generator" << endl; cout << " " << setw(20) << "--precision=

" << "Specify the precision (\"single\" or \"double\")" << endl; cout << endl; cout << " " << setw(20) << "--noprompt" << "Skip prompt before exit" << endl; cout << endl; }