/* * Copyright 2010-2019 NVIDIA Corporation. All rights reserved * * Sample CUPTI app to query domains and events supported by device * */ // System headers #include #include // CUDA headers #include // CUPTI headers #include "helper_cupti.h" #include // Global variables static unsigned int s_OptionsFlag = 0; // Macros #define NAME_SHORT 64 #define NAME_LONG 128 #define DESC_SHORT 512 #define DESC_LONG 2048 #define CATEGORY_LENGTH sizeof(CUpti_EventCategory) #define SetOptionsFlag(bit) (s_OptionsFlag |= (1< -getdomains : Displays supported domains for specified device.\n"); printf(" -device -getmetrics : Displays supported metrics for specified device.\n"); printf(" -device -domain -getevents : Displays supported events for specified domain and device.\n"); printf("Note: Default device is 0 and default domain is first domain for device.\n"); } // Add a null terminator to the end of a string if the string. // Length equals the maximum length. // (As in that case there was no room to write the null terminator.) static void CheckNullTerminator( char *pString, size_t length, size_t maxLength) { if (length >= maxLength) { pString[maxLength - 1] = '\0'; } } int EnumEventDomains( CUdevice dev) { CUptiResult cuptiResult = CUPTI_SUCCESS; CUpti_EventDomainID *pDomainId = NULL; DomainData domainData; uint32_t maxDomains = 0, i = 0; size_t size = 0; CUPTI_API_CALL(cuptiDeviceGetNumEventDomains(dev, &maxDomains)); if (maxDomains == 0) { printf("Error: No domain is exposed by dev = %d\n", dev); cuptiResult = CUPTI_ERROR_UNKNOWN; goto Exit; } size = sizeof(CUpti_EventDomainID) * maxDomains; pDomainId = (CUpti_EventDomainID *)malloc(size); MEMORY_ALLOCATION_CALL(pDomainId); memset(pDomainId, 0, size); CUPTI_API_CALL(cuptiDeviceEnumEventDomains(dev, &size, pDomainId)); // Enum domains. for (i = 0; i < maxDomains; i++) { domainData.domainId = pDomainId[i]; // Query domain name. size = NAME_SHORT; CUPTI_API_CALL(cuptiEventDomainGetAttribute(domainData.domainId, CUPTI_EVENT_DOMAIN_ATTR_NAME, &size, (void*)domainData.domainName)); CheckNullTerminator(domainData.domainName, size, NAME_SHORT); // Query number of profiled instances in the domain. size = sizeof(domainData.profiledInstanceCnt); CUPTI_API_CALL(cuptiDeviceGetEventDomainAttribute(dev, domainData.domainId, CUPTI_EVENT_DOMAIN_ATTR_INSTANCE_COUNT, &size, (void *)&domainData.profiledInstanceCnt)); // Query total instances in the domain. size = sizeof(domainData.totalInstanceCnt); CUPTI_API_CALL(cuptiDeviceGetEventDomainAttribute(dev, domainData.domainId, CUPTI_EVENT_DOMAIN_ATTR_TOTAL_INSTANCE_COUNT, &size, (void *)&domainData.totalInstanceCnt)); size = sizeof(CUpti_EventCollectionMethod); CUPTI_API_CALL(cuptiEventDomainGetAttribute(domainData.domainId, CUPTI_EVENT_DOMAIN_ATTR_COLLECTION_METHOD, &size, (void *)&domainData.eventCollectionMethod)); printf ("Domain# %u\n", i+1); printf ("Id = %d\n", domainData.domainId); printf ("Name = %s\n", domainData.domainName); printf ("Profiled instance count = %u\n", domainData.profiledInstanceCnt); printf ("Total instance count = %u\n", domainData.totalInstanceCnt); printf ("Event collection method = "); switch (domainData.eventCollectionMethod) { case CUPTI_EVENT_COLLECTION_METHOD_PM: printf("CUPTI_EVENT_COLLECTION_METHOD_PM\n"); break; case CUPTI_EVENT_COLLECTION_METHOD_SM: printf("CUPTI_EVENT_COLLECTION_METHOD_SM\n"); break; case CUPTI_EVENT_COLLECTION_METHOD_INSTRUMENTED: printf("CUPTI_EVENT_COLLECTION_METHOD_INSTRUMENTED\n"); break; case CUPTI_EVENT_COLLECTION_METHOD_NVLINK_TC: printf("CUPTI_EVENT_COLLECTION_METHOD_NVLINK_TC\n"); break; default: printf("\nError: Invalid event collection method!\n"); return -1; } } Exit: if (pDomainId) { free(pDomainId); } if (cuptiResult == CUPTI_SUCCESS) { return 0; } else { return -1; } } int EnumEvents( CUpti_EventDomainID domainId) { EventData eventData; CUptiResult cuptiResult = CUPTI_SUCCESS; CUpti_EventID *pEventId = NULL; uint32_t maxEvents = 0; uint32_t i = 0; size_t size = 0; // Query number of events available in the domain. CUPTI_API_CALL(cuptiEventDomainGetNumEvents(domainId, &maxEvents)); size = sizeof(CUpti_EventID) * maxEvents; pEventId = (CUpti_EventID *)malloc(size); MEMORY_ALLOCATION_CALL(pEventId); memset(pEventId, 0, size); CUPTI_API_CALL(cuptiEventDomainEnumEvents(domainId, &size, pEventId)); // Query event information. for (i = 0; i < maxEvents; i++) { eventData.Id.eventId = pEventId[i]; size = NAME_SHORT; CUPTI_API_CALL(cuptiEventGetAttribute(eventData.Id.eventId, CUPTI_EVENT_ATTR_NAME, &size, (uint8_t *)eventData.eventName)); CheckNullTerminator(eventData.eventName, size, NAME_SHORT); size = DESC_SHORT; CUPTI_API_CALL(cuptiEventGetAttribute(eventData.Id.eventId, CUPTI_EVENT_ATTR_SHORT_DESCRIPTION, &size, (uint8_t *)eventData.shortDesc)); CheckNullTerminator(eventData.shortDesc, size, DESC_SHORT); size = DESC_LONG; CUPTI_API_CALL(cuptiEventGetAttribute(eventData.Id.eventId, CUPTI_EVENT_ATTR_LONG_DESCRIPTION, &size, (uint8_t *)eventData.longDesc)); CheckNullTerminator(eventData.longDesc, size, DESC_LONG); size = CATEGORY_LENGTH; CUPTI_API_CALL(cuptiEventGetAttribute(eventData.Id.eventId, CUPTI_EVENT_ATTR_CATEGORY, &size, &eventData.category)); printf("Event# %u\n", i+1); printf("Id = %d\n", eventData.Id.eventId); printf("Name = %s\n", eventData.eventName); printf("Shortdesc = %s\n", eventData.shortDesc); printf("Longdesc = %s\n", eventData.longDesc); switch (eventData.category) { case CUPTI_EVENT_CATEGORY_INSTRUCTION: printf("Category = CUPTI_EVENT_CATEGORY_INSTRUCTION\n\n"); break; case CUPTI_EVENT_CATEGORY_MEMORY: printf("Category = CUPTI_EVENT_CATEGORY_MEMORY\n\n"); break; case CUPTI_EVENT_CATEGORY_CACHE: printf("Category = CUPTI_EVENT_CATEGORY_CACHE\n\n"); break; case CUPTI_EVENT_CATEGORY_PROFILE_TRIGGER: printf("Category = CUPTI_EVENT_CATEGORY_PROFILE_TRIGGER\n\n"); break; case CUPTI_EVENT_CATEGORY_SYSTEM: printf("Category = CUPTI_EVENT_CATEGORY_SYSTEM\n\n"); break; default: printf("\nInvalid category!\n"); } } if (pEventId) { free(pEventId); } if (cuptiResult == CUPTI_SUCCESS) { return 0; } else { return -1; } } int EnumMetrics( CUdevice dev) { EventData metricData; CUptiResult cuptiResult = CUPTI_SUCCESS; CUpti_MetricID *pMetricId = NULL; uint32_t maxMetrics = 0; uint32_t i = 0; size_t size = 0; CUPTI_API_CALL(cuptiDeviceGetNumMetrics(dev, &maxMetrics)); size = sizeof(CUpti_EventID) * maxMetrics; pMetricId = (CUpti_MetricID *)malloc(size); MEMORY_ALLOCATION_CALL(pMetricId); memset(pMetricId, 0, size); CUPTI_API_CALL(cuptiDeviceEnumMetrics(dev, &size, pMetricId)); // query metric info for (i = 0; i < maxMetrics; i++) { metricData.Id.metricId = pMetricId[i]; size = NAME_SHORT; CUPTI_API_CALL(cuptiMetricGetAttribute(metricData.Id.metricId, CUPTI_METRIC_ATTR_NAME, &size, (uint8_t *)metricData.eventName)); CheckNullTerminator(metricData.eventName, size, NAME_SHORT); size = DESC_SHORT; CUPTI_API_CALL(cuptiMetricGetAttribute(metricData.Id.metricId, CUPTI_METRIC_ATTR_SHORT_DESCRIPTION, &size, (uint8_t *)metricData.shortDesc)); CheckNullTerminator(metricData.shortDesc, size, DESC_SHORT); size = DESC_LONG; CUPTI_API_CALL(cuptiMetricGetAttribute(metricData.Id.metricId, CUPTI_METRIC_ATTR_LONG_DESCRIPTION, &size, (uint8_t *)metricData.longDesc)); CheckNullTerminator(metricData.longDesc, size, DESC_LONG); printf("Metric# %u\n", i + 1); printf("Id = %d\n", metricData.Id.metricId); printf("Name = %s\n", metricData.eventName); printf("Shortdesc = %s\n", metricData.shortDesc); printf("Longdesc = %s\n\n", metricData.longDesc); } if (pMetricId) { free(pMetricId); } if (cuptiResult == CUPTI_SUCCESS) { return 0; } else { return -1; } } void ParseCommandLineArgs(int argc, char *argv[], int &deviceId, CUpti_EventDomainID &domainId) { for (int k = 1; k < argc; k++) { if ((k + 1 < argc) && stricmp(argv[k], "-device") == 0) { deviceId = atoi(argv[k+1]); SetOptionsFlag(FLAG_DEVICE_ID); k++; } else if ((k+1 < argc) && stricmp(argv[k], "-domain") == 0) { domainId = (CUpti_EventDomainID)atoi(argv[k + 1]); SetOptionsFlag(FLAG_DOMAIN_ID); k++; } else if ((k < argc) && stricmp(argv[k], "-getdomains") == 0) { SetOptionsFlag(FLAG_GET_DOMAINS); } else if (stricmp(argv[k], "-getevents") == 0) { SetOptionsFlag(FLAG_GET_EVENTS); } else if (stricmp(argv[k], "-getmetrics") == 0) { SetOptionsFlag(FLAG_GET_METRICS); } else if ((stricmp(argv[k], "--help") == 0) || (stricmp(argv[k], "-help") == 0) || (stricmp(argv[k], "-h") == 0)) { PrintUsage(); exit(EXIT_SUCCESS); } else { printf("Warning: Invalid/Incomplete option %s.\n", argv[k]); } } } int main( int argc, char *argv[]) { CUdevice dev; CUptiResult cuptiResult = CUPTI_SUCCESS; int ret = 0; int deviceId = 0; int deviceCount = 0; int computeCapabilityMajor = 0, computeCapabilityMinor = 0; char deviceName[256]; CUpti_EventDomainID domainId = 0; size_t size = 0; DRIVER_API_CALL(cuInit(0)); DRIVER_API_CALL(cuDeviceGetCount(&deviceCount)); if (deviceCount == 0) { printf("Warning: There is no device supporting CUDA.\n"); ret = -2; goto Exit; } // Parse command line arguments. ParseCommandLineArgs(argc, argv, deviceId, domainId); if (!IsOptionsFlagSet(FLAG_DEVICE_ID)) { // Default is device 0. printf("Assuming default device id 0\n"); deviceId = 0; } // Show events if no explicit flag is set. if (!IsOptionsFlagSet(FLAG_GET_DOMAINS) && !IsOptionsFlagSet(FLAG_GET_EVENTS) && !IsOptionsFlagSet(FLAG_GET_METRICS)) { SetOptionsFlag(FLAG_GET_EVENTS); } DRIVER_API_CALL(cuDeviceGet(&dev, deviceId)); DRIVER_API_CALL(cuDeviceGetName(deviceName, 256, dev)); printf("CUDA Device Id : %d\n", deviceId); printf("CUDA Device Name: %s\n\n", deviceName); DRIVER_API_CALL(cuDeviceGetAttribute(&computeCapabilityMajor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, dev)); DRIVER_API_CALL(cuDeviceGetAttribute(&computeCapabilityMinor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, dev)); if (IsOptionsFlagSet(FLAG_GET_DOMAINS)) { if (EnumEventDomains(dev)) { printf("Error: EnumEventDomains failed.\n"); ret = -1; goto Exit; } } else if (IsOptionsFlagSet(FLAG_GET_EVENTS)) { if (!IsOptionsFlagSet(FLAG_DOMAIN_ID)) { // Query first domain on the device. size = sizeof(CUpti_EventDomainID); CUPTI_API_CALL(cuptiDeviceEnumEventDomains(dev, &size, (CUpti_EventDomainID *)&domainId)); printf("Assuming default domain id %d.\n", domainId); } else { // Validate the domain on the device. CUpti_EventDomainID *pDomainIdArray = NULL; uint32_t maxDomains = 0, i = 0; CUPTI_API_CALL(cuptiDeviceGetNumEventDomains(dev, &maxDomains)); if (maxDomains == 0) { printf("Warning: No domain is exposed by dev = %d\n", dev); cuptiResult = CUPTI_ERROR_UNKNOWN; ret = -2; goto Exit; } size = sizeof(CUpti_EventDomainID) * maxDomains; pDomainIdArray = (CUpti_EventDomainID *)malloc(size); MEMORY_ALLOCATION_CALL(pDomainIdArray); memset(pDomainIdArray, 0, size); // Enum domains. CUPTI_API_CALL(cuptiDeviceEnumEventDomains(dev, &size, pDomainIdArray)); for (i = 0; i < maxDomains; i++) { if (pDomainIdArray[i] == domainId) { break; } } free(pDomainIdArray); if (i == maxDomains) { printf("Warning: Domain Id %d is not supported by device.\n", domainId); ret = -2; goto Exit; } } if (EnumEvents(domainId)) { printf("Error: EnumEvents failed.\n"); ret = -1; goto Exit; } } else if (IsOptionsFlagSet(FLAG_GET_METRICS)) { if(EnumMetrics(dev)) { printf("Error: EnumMetrics() failed.\n"); ret = -1; goto Exit; } } Exit: RUNTIME_API_CALL(cudaDeviceSynchronize()); if(ret == -1) { exit(EXIT_FAILURE); } else if (ret == -2) { exit(EXIT_WAIVED); } else { exit(EXIT_SUCCESS); } }