/* Copyright (c) 2019, 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 #include #include "commonDefs.hpp" #define CU_INIT_UUID #include #define UNITS_Time "ms" #define UNITS_BW "MB/s" #define KB_str "KB" #define MB_str "MB" struct resultsData { char resultsName[64]; struct testResults *results; // this has MEMALLOC_TYPE_COUNT * results->numSizesToTest * // results->numMeasurements elements double **runTimesInMs[MEMALLOC_TYPE_COUNT]; double *averageRunTimesInMs[MEMALLOC_TYPE_COUNT]; double *stdDevRunTimesInMs[MEMALLOC_TYPE_COUNT]; double *stdDevBandwidthInMBps[MEMALLOC_TYPE_COUNT]; bool printOnlyInVerbose; bool reportAsBandwidth; struct resultsData *next; }; struct testResults { char testName[64]; unsigned int numMeasurements; unsigned long *sizesToTest; unsigned int numSizesToTest; struct resultsData *resultsDataHead; struct resultsData *resultsDataTail; }; unsigned int findNumSizesToTest(unsigned int minSize, unsigned int maxSize, unsigned int multiplier) { unsigned int numSizesToTest = 0; while (minSize <= maxSize) { numSizesToTest++; minSize *= multiplier; } return numSizesToTest; } int compareDoubles(const void *ptr1, const void *ptr2) { return (*(double *)ptr1 > *(double *)ptr2) ? 1 : -1; } static inline double getTimeOrBandwidth(double runTimeInMs, unsigned long size, bool getBandwidth) { return (getBandwidth) ? (1000 * (size / runTimeInMs)) / ONE_MB : runTimeInMs; } void createAndInitTestResults(struct testResults **ptrResults, const char *testName, unsigned int numMeasurements, unsigned int numSizesToTest) { unsigned int i; struct testResults *results; results = (struct testResults *)malloc(sizeof(struct testResults)); memset(results, 0, sizeof(struct testResults)); strcpy(results->testName, testName); results->numMeasurements = numMeasurements; results->numSizesToTest = numSizesToTest; results->sizesToTest = (unsigned long *)malloc(numSizesToTest * sizeof(unsigned long)); results->resultsDataHead = NULL; results->resultsDataTail = NULL; *ptrResults = results; } unsigned long *getPtrSizesToTest(struct testResults *results) { return results->sizesToTest; } void createResultDataAndAddToTestResults(struct resultsData **ptrData, struct testResults *results, const char *resultsName, bool printOnlyInVerbose, bool reportAsBandwidth) { unsigned int i, j; struct resultsData *data; data = (struct resultsData *)malloc(sizeof(struct resultsData)); memset(data, 0, sizeof(struct resultsData)); strcpy(data->resultsName, resultsName); data->results = results; for (i = 0; i < MEMALLOC_TYPE_COUNT; i++) { data->runTimesInMs[i] = (double **)malloc(results->numSizesToTest * sizeof(double *)); for (j = 0; j < results->numSizesToTest; j++) { data->runTimesInMs[i][j] = (double *)malloc(results->numMeasurements * sizeof(double)); } data->averageRunTimesInMs[i] = (double *)malloc(results->numSizesToTest * sizeof(double)); data->stdDevRunTimesInMs[i] = (double *)malloc(results->numSizesToTest * sizeof(double)); data->stdDevBandwidthInMBps[i] = (double *)malloc(results->numSizesToTest * sizeof(double)); } data->printOnlyInVerbose = printOnlyInVerbose; data->reportAsBandwidth = reportAsBandwidth; data->next = NULL; *ptrData = data; if (results->resultsDataHead == NULL) { results->resultsDataHead = data; results->resultsDataTail = data; } else { results->resultsDataTail->next = data; results->resultsDataTail = data; } } double *getPtrRunTimesInMs(struct resultsData *data, int allocType, int sizeIndex) { return data->runTimesInMs[allocType][sizeIndex]; } void freeTestResultsAndAllResultsData(struct testResults *results) { struct resultsData *data, *dataToFree; unsigned int i, j; for (data = results->resultsDataHead; data != NULL;) { for (i = 0; i < MEMALLOC_TYPE_COUNT; i++) { for (j = 0; j < results->numSizesToTest; j++) { free(data->runTimesInMs[i][j]); } free(data->runTimesInMs[i]); free(data->averageRunTimesInMs[i]); free(data->stdDevRunTimesInMs[i]); free(data->stdDevBandwidthInMBps[i]); } dataToFree = data; data = data->next; free(dataToFree); } free(results->sizesToTest); free(results); } void calculateAverageAndStdDev(double *pAverage, double *pStdDev, double *allResults, unsigned int count) { unsigned int i; double average = 0.0; double stdDev = 0.0; for (i = 0; i < count; i++) { average += allResults[i]; } average /= count; for (i = 0; i < count; i++) { stdDev += (allResults[i] - average) * (allResults[i] - average); } stdDev /= count; stdDev = sqrt(stdDev); *pAverage = average; *pStdDev = (average == 0.0) ? 0.0 : ((100.0 * stdDev) / average); } void calculateStdDevBandwidth(double *pStdDev, double *allResults, unsigned int count, unsigned long size) { unsigned int i; double bandwidth; double average = 0.0; double stdDev = 0.0; for (i = 0; i < count; i++) { bandwidth = (1000 * (size / allResults[i])) / ONE_MB; average += bandwidth; } average /= count; for (i = 0; i < count; i++) { bandwidth = (1000 * (size / allResults[i])) / ONE_MB; stdDev += (bandwidth - average) * (bandwidth - average); } stdDev /= count; stdDev = sqrt(stdDev); *pStdDev = (average == 0.0) ? 0.0 : ((100.0 * stdDev) / average); } void printTimesInTableFormat(struct testResults *results, struct resultsData *data, bool printAverage, bool printStdDev) { unsigned int i, j; bool printStdDevBandwidth = printStdDev && data->reportAsBandwidth; printf("Size_KB"); for (i = 0; i < MEMALLOC_TYPE_COUNT; i++) { printf("\t%7s", memAllocTypeShortStr[i]); } printf("\n"); for (j = 0; j < results->numSizesToTest; j++) { printf("%lu", results->sizesToTest[j] / ONE_KB); for (i = 0; i < MEMALLOC_TYPE_COUNT; i++) { printf(data->reportAsBandwidth ? "\t%7.2lf" : "\t%7.3lf", printStdDevBandwidth ? data->stdDevBandwidthInMBps[i][j] : getTimeOrBandwidth( printAverage ? data->averageRunTimesInMs[i][j] : data->stdDevRunTimesInMs[i][j], results->sizesToTest[j], data->reportAsBandwidth)); } printf("\n"); } } void printAllResultsInVerboseMode(struct testResults *results, struct resultsData *data) { unsigned int i, j, k; for (i = 0; i < MEMALLOC_TYPE_COUNT; i++) { printf("Verbose mode, printing all results for %s\n", memAllocTypeStr[i]); printf("Instance"); for (j = 0; j < results->numSizesToTest; j++) { printf("\t%lu", results->sizesToTest[j] / ONE_KB); } printf("\n"); for (k = 0; k < results->numMeasurements; k++) { printf("%u", k); for (j = 0; j < results->numSizesToTest; j++) { printf(data->reportAsBandwidth ? "\t%7.2lf" : "\t%7.3lf", getTimeOrBandwidth(data->runTimesInMs[i][j][k], results->sizesToTest[j], data->reportAsBandwidth)); } printf("\n"); } } } void printResults(struct testResults *results, bool print_launch_transfer_results, bool print_std_deviation) { char vulcanPrint[256]; char resultNameNoSpaces[64]; unsigned int i, j, k; struct resultsData *resultsIter; bool sizeGreaterThan1MB; for (resultsIter = results->resultsDataHead; resultsIter != NULL; resultsIter = resultsIter->next) { if (!verboseResults && resultsIter->printOnlyInVerbose) { continue; } if (!print_launch_transfer_results) { if (!(strcmp(resultsIter->resultsName, "Overall Time") == 0)) { continue; } } // regular print printf("\n%s For %s ", resultsIter->resultsName, results->testName); printf("\n"); for (j = 0; j < results->numSizesToTest; j++) { for (i = 0; i < MEMALLOC_TYPE_COUNT; i++) { calculateAverageAndStdDev(&resultsIter->averageRunTimesInMs[i][j], &resultsIter->stdDevRunTimesInMs[i][j], resultsIter->runTimesInMs[i][j], results->numMeasurements); if (resultsIter->reportAsBandwidth) { calculateStdDevBandwidth(&resultsIter->stdDevBandwidthInMBps[i][j], resultsIter->runTimesInMs[i][j], results->numMeasurements, results->sizesToTest[j]); } } } printf("\nPrinting Average of %u measurements in (%s)\n", results->numMeasurements, resultsIter->reportAsBandwidth ? UNITS_BW : UNITS_Time); printTimesInTableFormat(results, resultsIter, true, false); if (print_std_deviation) { printf( "\nPrinting Standard Deviation as %% of average of %u measurements\n", results->numMeasurements); printTimesInTableFormat(results, resultsIter, false, true); } if (verboseResults) { printAllResultsInVerboseMode(results, resultsIter); } } }