/**
 * Copyright 2022-2025 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.
 *
 */

////////////////////////////////////////////////////////////////////////////////

#ifndef HELPER_CUPTI_ACTIVITY_RECORDS_H_
#define HELPER_CUPTI_ACTIVITY_RECORDS_H_

#pragma once

// System headers
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

// CUPTI headers
#include <cupti_activity.h>
#include <helper_cupti.h>
#include <helper_cupti_activity_enums.h>

#include <helper_cupti_activity_user_defined_records.h>

static const char *
GetName(
    const char *pName)
{
    if (pName == NULL)
    {
        return "<null>";
    }

    return pName;
}

static const char *
GetDomainName(
    const char *pName)
{
    if (pName == NULL)
    {
        return "<default domain>";
    }

    return pName;
}

static uint32_t
GetActivityObjectKindId(
    CUpti_ActivityObjectKind objectKind,
    CUpti_ActivityObjectKindId *pObjectKindId)
{
    switch (objectKind)
    {
        case CUPTI_ACTIVITY_OBJECT_UNKNOWN:
            return 0xffffffff;
        case CUPTI_ACTIVITY_OBJECT_PROCESS:
            return pObjectKindId->pt.processId;
        case CUPTI_ACTIVITY_OBJECT_THREAD:
            return pObjectKindId->pt.threadId;
        case CUPTI_ACTIVITY_OBJECT_DEVICE:
            return pObjectKindId->dcs.deviceId;
        case CUPTI_ACTIVITY_OBJECT_CONTEXT:
            return pObjectKindId->dcs.contextId;
        case CUPTI_ACTIVITY_OBJECT_STREAM:
            return pObjectKindId->dcs.streamId;
        default:
            return 0xffffffff;
    }
}

static uint32_t
GetCorrelationId(
    CUpti_Activity *pRecord)
{
    switch (pRecord->kind)
    {
        case CUPTI_ACTIVITY_KIND_MEMCPY:
            return ((CUpti_ActivityMemcpy6 *)pRecord)->correlationId;
        case CUPTI_ACTIVITY_KIND_MEMSET:
            return ((CUpti_ActivityMemset4 *)pRecord)->correlationId;
        case CUPTI_ACTIVITY_KIND_KERNEL:
        case CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL:
            return ((CUpti_ActivityKernel11 *)pRecord)->correlationId;
        case CUPTI_ACTIVITY_KIND_DRIVER:
        case CUPTI_ACTIVITY_KIND_RUNTIME:
            return ((CUpti_ActivityAPI *)pRecord)->correlationId;
        case CUPTI_ACTIVITY_KIND_CDP_KERNEL:
            return ((CUpti_ActivityCdpKernel *)pRecord)->correlationId;
        case CUPTI_ACTIVITY_KIND_MEMCPY2:
            return ((CUpti_ActivityMemcpyPtoP4 *)pRecord)->correlationId;
        default:
            return 0;
    }
}

static void
PrintOpenaccCommon(
    FILE *pFileHandle,
    CUpti_ActivityOpenAcc *pOpenAcc)
{
    fprintf(pFileHandle, "%s [ %llu, %llu ] duration %llu, eventKind %u, parentConstruct %s, version %u, implicit %u, deviceType %u, deviceNumber %u, threadId %u,\n"
            "  async %llu, asyncMap %llu, lineNo %u, endLineNo %u, funcLineNo %u, endFuncLineNo %u,\n"
            "  cuDeviceId %u, cuContextId %u, cuStreamId %u, cuProcessId %u, cuThreadId %u, externalId %llu",
            GetActivityKindString(pOpenAcc->kind),
            (unsigned long long)pOpenAcc->start,
            (unsigned long long)pOpenAcc->end,
            (unsigned long long)(pOpenAcc->end - pOpenAcc->start),
            pOpenAcc->eventKind,
            GetOpenAccConstructKindString((CUpti_OpenAccConstructKind)pOpenAcc->parentConstruct),
            pOpenAcc->version,
            pOpenAcc->implicit,
            pOpenAcc->deviceType,
            pOpenAcc->deviceNumber,
            pOpenAcc->threadId,
            (unsigned long long)pOpenAcc->async,
            (unsigned long long)pOpenAcc->asyncMap,
            pOpenAcc->lineNo,
            pOpenAcc->endLineNo,
            pOpenAcc->funcLineNo,
            pOpenAcc->funcEndLineNo,
            pOpenAcc->cuDeviceId,
            pOpenAcc->cuContextId,
            pOpenAcc->cuStreamId,
            pOpenAcc->cuProcessId,
            pOpenAcc->cuThreadId,
            (unsigned long long)pOpenAcc->externalId);

    fprintf(pFileHandle, ", srcFile %s", pOpenAcc->srcFile ? pOpenAcc->srcFile : "?");
    fprintf(pFileHandle, ", funcName %s", pOpenAcc->funcName ? pOpenAcc->funcName : "?");

}

static void
PrintActivity(
    CUpti_Activity *pRecord,
    FILE *pFileHandle)
{
  CUpti_ActivityKind activityKind = pRecord->kind;

    switch (activityKind)
    {
        case CUPTI_ACTIVITY_KIND_MEMCPY:
        {
            CUpti_ActivityMemcpy6 *pMemcpyRecord = (CUpti_ActivityMemcpy6 *)pRecord;

            fprintf(pFileHandle, "%s \"%s\" [ %llu, %llu ] duration %llu, size %llu, copyCount %llu, srcKind %s, dstKind %s, correlationId %u\n"
                    "\tdeviceId %u, contextId %u, streamId %u, graphId %u, graphNodeId %llu, channelId %u, channelType %s\n",
                    GetActivityKindString(pMemcpyRecord->kind),
                    GetActivityMemcpyKindString((CUpti_ActivityMemcpyKind)pMemcpyRecord->copyKind),
                    (unsigned long long)pMemcpyRecord->start,
                    (unsigned long long)pMemcpyRecord->end,
                    (unsigned long long)(pMemcpyRecord->end - pMemcpyRecord->start),
                    (unsigned long long)pMemcpyRecord->bytes,
                    (unsigned long long)pMemcpyRecord->copyCount,
                    GetActivityMemoryKindString((CUpti_ActivityMemoryKind)pMemcpyRecord->srcKind),
                    GetActivityMemoryKindString((CUpti_ActivityMemoryKind)pMemcpyRecord->dstKind),
                    pMemcpyRecord->correlationId,
                    pMemcpyRecord->deviceId,
                    pMemcpyRecord->contextId,
                    pMemcpyRecord->streamId,
                    pMemcpyRecord->graphId,
                    (unsigned long long)pMemcpyRecord->graphNodeId,
                    pMemcpyRecord->channelID,
                    GetChannelTypeString(pMemcpyRecord->channelType));

            break;
        }
        case CUPTI_ACTIVITY_KIND_MEMSET:
        {
            CUpti_ActivityMemset4 *pMemsetRecord = (CUpti_ActivityMemset4 *)pRecord;

            fprintf(pFileHandle, "%s [ %llu, %llu ] duration %llu, value %u, size %llu, correlationId %u\n"
                    "\tdeviceId %u, contextId %u, streamId %u, graphId %u, graphNodeId %llu, channelId %u, channelType %s\n",
                    GetActivityKindString(pMemsetRecord->kind),
                    (unsigned long long)pMemsetRecord->start,
                    (unsigned long long)pMemsetRecord->end,
                    (unsigned long long)(pMemsetRecord->end - pMemsetRecord->start),
                    pMemsetRecord->value,
                    (unsigned long long)pMemsetRecord->bytes,
                    pMemsetRecord->correlationId,
                    pMemsetRecord->deviceId,
                    pMemsetRecord->contextId,
                    pMemsetRecord->streamId,
                    pMemsetRecord->graphId,
                    (unsigned long long)pMemsetRecord->graphNodeId,
                    pMemsetRecord->channelID,
                    GetChannelTypeString(pMemsetRecord->channelType));

            break;
        }
        case CUPTI_ACTIVITY_KIND_KERNEL:
        case CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL:
        {
            CUpti_ActivityKernel11 *pKernelRecord = (CUpti_ActivityKernel11 *)pRecord;

            fprintf(pFileHandle, "%s [ %llu, %llu ] duration %llu, \"%s\", correlationId %u, cacheConfigRequested %d, cacheConfigExecuted %d\n"
                    "\tgrid [ %u, %u, %u ], block [ %u, %u, %u ], cluster [ %u, %u, %u ], sharedMemory (static %u, dynamic %u)\n"
                    "\tdeviceId %u, contextId %u, streamId %u, graphId %u, graphNodeId %llu, channelId %u, channelType %s, priority %u\n",
                    GetActivityKindString(pKernelRecord->kind),
                    (unsigned long long)pKernelRecord->start,
                    (unsigned long long)pKernelRecord->end,
                    (unsigned long long)(pKernelRecord->end - pKernelRecord->start),
                    GetName(pKernelRecord->name),
                    pKernelRecord->correlationId,
                    pKernelRecord->cacheConfig.config.requested,
                    pKernelRecord->cacheConfig.config.executed,
                    pKernelRecord->gridX,
                    pKernelRecord->gridY,
                    pKernelRecord->gridZ,
                    pKernelRecord->blockX,
                    pKernelRecord->blockY,
                    pKernelRecord->blockZ,
                    pKernelRecord->clusterX,
                    pKernelRecord->clusterY,
                    pKernelRecord->clusterZ,
                    pKernelRecord->staticSharedMemory,
                    pKernelRecord->dynamicSharedMemory,
                    pKernelRecord->deviceId,
                    pKernelRecord->contextId,
                    pKernelRecord->streamId,
                    pKernelRecord->graphId,
                    (unsigned long long)pKernelRecord->graphNodeId,
                    pKernelRecord->channelID,
                    GetChannelTypeString(pKernelRecord->channelType),
                    pKernelRecord->priority);

            break;
        }
        case CUPTI_ACTIVITY_KIND_DRIVER:
        case CUPTI_ACTIVITY_KIND_RUNTIME:
        case CUPTI_ACTIVITY_KIND_INTERNAL_LAUNCH_API:
        {
            CUpti_ActivityAPI *pApiRecord = (CUpti_ActivityAPI *)pRecord;
            const char* pName = NULL;

            if (pApiRecord->kind == CUPTI_ACTIVITY_KIND_DRIVER)
            {
                cuptiGetCallbackName(CUPTI_CB_DOMAIN_DRIVER_API, pApiRecord->cbid, &pName);
            }
            else if (pApiRecord->kind == CUPTI_ACTIVITY_KIND_RUNTIME)
            {
                cuptiGetCallbackName(CUPTI_CB_DOMAIN_RUNTIME_API, pApiRecord->cbid, &pName);
            }

            fprintf(pFileHandle, "%s [ %llu, %llu ] duration %llu, \"%s\", cbid %u, processId %u, threadId %u, correlationId %u\n",
                    GetActivityKindString(pApiRecord->kind),
                    (unsigned long long)pApiRecord->start,
                    (unsigned long long)pApiRecord->end,
                    (unsigned long long)(pApiRecord->end - pApiRecord->start),
                    GetName(pName),
                    pApiRecord->cbid,
                    pApiRecord->processId,
                    pApiRecord->threadId,
                    pApiRecord->correlationId);

            break;
        }
        case CUPTI_ACTIVITY_KIND_DEVICE:
        {
            CUpti_ActivityDevice6 *pDeviceRecord = (CUpti_ActivityDevice6 *)pRecord;

            fprintf(pFileHandle, "%s %s [ %u ]\n",
                    GetActivityKindString(pDeviceRecord->kind),
                    GetName(pDeviceRecord->name),
                    pDeviceRecord->id);

            break;
        }
        case CUPTI_ACTIVITY_KIND_CONTEXT:
        {
            CUpti_ActivityContext4 *pContextRecord = (CUpti_ActivityContext4 *)pRecord;

            fprintf(pFileHandle, "%s computeApiKind %s, contextId %u, deviceId %u, nullStreamId %d, CIG mode %d, processId %llu\n",
                    GetActivityKindString(pContextRecord->kind),
                    GetActivityComputeApiKindString((CUpti_ActivityComputeApiKind) pContextRecord->computeApiKind),
                    pContextRecord->contextId,
                    pContextRecord->deviceId,
                    (int)pContextRecord->nullStreamId,
                    pContextRecord->cigMode,
                    (unsigned long long)pContextRecord->processId);

            break;
        }
        case CUPTI_ACTIVITY_KIND_NAME:
        {
            CUpti_ActivityName *pNameRecord = (CUpti_ActivityName *)pRecord;

            switch(pNameRecord->objectKind)
            {
                case CUPTI_ACTIVITY_OBJECT_CONTEXT:
                {
                    fprintf(pFileHandle, "%s %s %u %s id %u, name %s\n",
                            GetActivityKindString(pNameRecord->kind),
                            GetActivityObjectKindString(pNameRecord->objectKind),
                            GetActivityObjectKindId(pNameRecord->objectKind, &pNameRecord->objectId),
                            GetActivityObjectKindString(CUPTI_ACTIVITY_OBJECT_DEVICE),
                            GetActivityObjectKindId(CUPTI_ACTIVITY_OBJECT_DEVICE, &pNameRecord->objectId),
                            GetName(pNameRecord->name));

                    break;
                }
                case CUPTI_ACTIVITY_OBJECT_STREAM:
                {
                    fprintf(pFileHandle, "%s %s %u %s %u %s id %u, name %s\n",
                            GetActivityKindString(pNameRecord->kind),
                            GetActivityObjectKindString(pNameRecord->objectKind),
                            GetActivityObjectKindId(pNameRecord->objectKind, &pNameRecord->objectId),
                            GetActivityObjectKindString(CUPTI_ACTIVITY_OBJECT_CONTEXT),
                            GetActivityObjectKindId(CUPTI_ACTIVITY_OBJECT_CONTEXT, &pNameRecord->objectId),
                            GetActivityObjectKindString(CUPTI_ACTIVITY_OBJECT_DEVICE),
                            GetActivityObjectKindId(CUPTI_ACTIVITY_OBJECT_DEVICE, &pNameRecord->objectId),
                            GetName(pNameRecord->name));

                    break;
                }
                default:
                {
                    fprintf(pFileHandle, "%s %s id %u, name %s\n",
                            GetActivityKindString(pNameRecord->kind),
                            GetActivityObjectKindString(pNameRecord->objectKind),
                            GetActivityObjectKindId(pNameRecord->objectKind, &pNameRecord->objectId),
                            GetName(pNameRecord->name));
                    break;
                }
            }

            break;
        }
        case CUPTI_ACTIVITY_KIND_MARKER:
        {
            CUpti_ActivityMarker2 *pMarkerRecord = (CUpti_ActivityMarker2 *)pRecord;

            fprintf(pFileHandle, "%s [ %llu ] id %u, domain %s, name %s\n",
                    GetActivityKindString(pMarkerRecord->kind),
                    (unsigned long long)pMarkerRecord->timestamp,
                    pMarkerRecord->id,
                    GetDomainName(pMarkerRecord->domain),
                    GetName(pMarkerRecord->name));

            break;
        }
        case CUPTI_ACTIVITY_KIND_MARKER_DATA:
        {
            CUpti_ActivityMarkerData *pMarkerDataRecord = (CUpti_ActivityMarkerData *)pRecord;

            fprintf(pFileHandle, "%s id %u, color 0x%x, category %u, payload %llu/%f\n",
                    GetActivityKindString(pMarkerDataRecord->kind),
                    pMarkerDataRecord->id,
                    pMarkerDataRecord->color,
                    pMarkerDataRecord->category,
                    (unsigned long long)pMarkerDataRecord->payload.metricValueUint64,
                    pMarkerDataRecord->payload.metricValueDouble);

            break;
        }
        case CUPTI_ACTIVITY_KIND_OVERHEAD:
        {
            CUpti_ActivityOverhead3 *pOverheadRecord = (CUpti_ActivityOverhead3 *)pRecord;

            fprintf(pFileHandle, "%s %s [ %llu, %llu ] duration %llu, %s, id %u, correlation id %lu\n",
                    GetActivityKindString(pOverheadRecord->kind),
                    GetActivityOverheadKindString(pOverheadRecord->overheadKind),
                    (unsigned long long)pOverheadRecord->start,
                    (unsigned long long)pOverheadRecord->end,
                    (unsigned long long)(pOverheadRecord->end - pOverheadRecord->start),
                    GetActivityObjectKindString(pOverheadRecord->objectKind),
                    GetActivityObjectKindId(pOverheadRecord->objectKind, &pOverheadRecord->objectId),
                    (unsigned long)pOverheadRecord->correlationId);
            if (pOverheadRecord->overheadData)
            {
                switch (pOverheadRecord->overheadKind)
                {
                    case CUPTI_ACTIVITY_OVERHEAD_COMMAND_BUFFER_FULL:
                    {
                        CUpti_ActivityOverheadCommandBufferFullData* pCommandBufferData = (CUpti_ActivityOverheadCommandBufferFullData*)pOverheadRecord->overheadData;
                        fprintf(pFileHandle, "CUpti_ActivityOverheadCommandBufferFullData : commandBufferLength %d channelID %d channelType %d\n",
                        pCommandBufferData->commandBufferLength,
                        pCommandBufferData->channelID,
                        pCommandBufferData->channelType);
                        break;
                    }
                    default:
                    {
                        break;
                    }
                }

            }

            break;
        }
        case CUPTI_ACTIVITY_KIND_CDP_KERNEL:
        {
            CUpti_ActivityCdpKernel *pCdpKernelRecord = (CUpti_ActivityCdpKernel *)pRecord;

            fprintf(pFileHandle, "%s [ %llu, %llu ] duration %llu, \"%s\", deviceId %u, contextId %u, streamId %u, gridId %lld, correlationId %u,\n"
                    "\tgrid [ %u, %u, %u ], block [ %u, %u, %u ], registersPerThread %u, sharedMemory (static %u, dynamic %u), parentGridId %lld, parentBlockId [ %u, %u, %u ]\n",
                    GetActivityKindString(pCdpKernelRecord->kind),
                    (unsigned long long)pCdpKernelRecord->start,
                    (unsigned long long)pCdpKernelRecord->end,
                    (unsigned long long)(pCdpKernelRecord->end - pCdpKernelRecord->start),
                    GetName(pCdpKernelRecord->name),
                    pCdpKernelRecord->deviceId,
                    pCdpKernelRecord->contextId,
                    pCdpKernelRecord->streamId,
                    (long long)pCdpKernelRecord->gridId,
                    pCdpKernelRecord->correlationId,
                    pCdpKernelRecord->gridX,
                    pCdpKernelRecord->gridY,
                    pCdpKernelRecord->gridZ,
                    pCdpKernelRecord->blockX,
                    pCdpKernelRecord->blockY,
                    pCdpKernelRecord->blockZ,
                    pCdpKernelRecord->registersPerThread,
                    pCdpKernelRecord->staticSharedMemory,
                    pCdpKernelRecord->dynamicSharedMemory,
                    (long long)pCdpKernelRecord->parentGridId,
                    pCdpKernelRecord->parentBlockX,
                    pCdpKernelRecord->parentBlockY,
                    pCdpKernelRecord->parentBlockZ);

            break;
        }
        case CUPTI_ACTIVITY_KIND_PREEMPTION:
        {
            CUpti_ActivityPreemption *pPreemptionRecord = (CUpti_ActivityPreemption *)pRecord;

            fprintf(pFileHandle, "%s preemptionKind %s [ %llu ] gridId %lld, block [ %u, %u, %u ]\n",
                    GetActivityKindString(pPreemptionRecord->kind),
                    GetActivityPreemptionKindString(pPreemptionRecord->preemptionKind),
                    (unsigned long long)pPreemptionRecord->timestamp,
                    (long long)pPreemptionRecord->gridId,
                    pPreemptionRecord->blockX,
                    pPreemptionRecord->blockY,
                    pPreemptionRecord->blockZ);

            break;
        }
        case CUPTI_ACTIVITY_KIND_ENVIRONMENT:
        {
            CUpti_ActivityEnvironment *pEnvironmentRecord = (CUpti_ActivityEnvironment *)pRecord;

            switch (pEnvironmentRecord->environmentKind)
            {
                case CUPTI_ACTIVITY_ENVIRONMENT_SPEED:
                {
                    fprintf(pFileHandle, "%s: kind=SPEED, deviceId %u, timestamp %llu, memoryClock %u, smClock %u, pcieLinkGen %u, pcieLinkWidth %u, clocksThrottleReasons %u\n",
                            GetActivityKindString(pEnvironmentRecord->kind),
                            pEnvironmentRecord->deviceId,
                            (unsigned long long)pEnvironmentRecord->timestamp,
                            pEnvironmentRecord->data.speed.memoryClock,
                            pEnvironmentRecord->data.speed.smClock,
                            pEnvironmentRecord->data.speed.pcieLinkGen,
                            pEnvironmentRecord->data.speed.pcieLinkWidth,
                            pEnvironmentRecord->data.speed.clocksThrottleReasons);

                    break;
                }
                case CUPTI_ACTIVITY_ENVIRONMENT_TEMPERATURE:
                {
                    fprintf(pFileHandle, "%s: kind=TEMPERATURE, deviceId %u, timestamp %llu, gpuTemperature %u\n",
                            GetActivityKindString(pEnvironmentRecord->kind),
                            pEnvironmentRecord->deviceId,
                            (unsigned long long)pEnvironmentRecord->timestamp,
                            pEnvironmentRecord->data.temperature.gpuTemperature);

                    break;
                }
                case CUPTI_ACTIVITY_ENVIRONMENT_POWER:
                {
                    fprintf(pFileHandle, "%s: kind=POWER, deviceId %u, timestamp %llu, power %u, powerLimit %u\n",
                            GetActivityKindString(pEnvironmentRecord->kind),
                            pEnvironmentRecord->deviceId,
                            (unsigned long long)pEnvironmentRecord->timestamp,
                            pEnvironmentRecord->data.power.power,
                            pEnvironmentRecord->data.power.powerLimit);

                    break;
                }
                case CUPTI_ACTIVITY_ENVIRONMENT_COOLING:
                {
                    fprintf(pFileHandle, "%s: kind=COOLING, deviceId %u, timestamp %llu, fanSpeed %u\n",
                            GetActivityKindString(pEnvironmentRecord->kind),
                            pEnvironmentRecord->deviceId,
                            (unsigned long long)pEnvironmentRecord->timestamp,
                            pEnvironmentRecord->data.cooling.fanSpeed);

                    break;
                }
                default:
                    break;
            }

            break;
        }
        case CUPTI_ACTIVITY_KIND_MEMCPY2:
        {
            CUpti_ActivityMemcpyPtoP4 *pMemcpyPtoPRecord = (CUpti_ActivityMemcpyPtoP4 *)pRecord;

            fprintf(pFileHandle, "%s \"%s\" [ %llu, %llu ] duration %llu, size %llu, srcKind %s, dstKind %s, correlationId %u,\n"
                    "\tdeviceId %u, contextId %u, streamId %u, graphId %u, graphNodeId %llu, channelId %u, channelType %s\n"
                    "\tsrcDeviceId %u, srcContextId %u, dstDeviceId %u, dstContextId %u\n",
                    GetActivityKindString(pMemcpyPtoPRecord->kind),
                    GetActivityMemcpyKindString((CUpti_ActivityMemcpyKind)pMemcpyPtoPRecord->copyKind),
                    (unsigned long long)pMemcpyPtoPRecord->start,
                    (unsigned long long)pMemcpyPtoPRecord->end,
                    (unsigned long long)(pMemcpyPtoPRecord->end - pMemcpyPtoPRecord->start),
                    (unsigned long long)pMemcpyPtoPRecord->bytes,
                    GetActivityMemoryKindString((CUpti_ActivityMemoryKind)pMemcpyPtoPRecord->srcKind),
                    GetActivityMemoryKindString((CUpti_ActivityMemoryKind)pMemcpyPtoPRecord->dstKind),
                    pMemcpyPtoPRecord->correlationId,
                    pMemcpyPtoPRecord->deviceId,
                    pMemcpyPtoPRecord->contextId,
                    pMemcpyPtoPRecord->streamId,
                    pMemcpyPtoPRecord->graphId,
                    (unsigned long long)pMemcpyPtoPRecord->graphNodeId,
                    pMemcpyPtoPRecord->channelID,
                    GetChannelTypeString(pMemcpyPtoPRecord->channelType),
                    pMemcpyPtoPRecord->srcDeviceId,
                    pMemcpyPtoPRecord->srcContextId,
                    pMemcpyPtoPRecord->dstDeviceId,
                    pMemcpyPtoPRecord->dstContextId);

            break;
        }
        case CUPTI_ACTIVITY_KIND_UNIFIED_MEMORY_COUNTER:
        {
            CUpti_ActivityUnifiedMemoryCounter2 *pUnifiedMemoryCounterRecord = (CUpti_ActivityUnifiedMemoryCounter2 *)pRecord;

            fprintf(pFileHandle, "%s [ %llu, %llu ] duration %llu, counterKind %s, value %llu, address %llx, srcId %u, dstId %u, processId %u\n",
                    GetActivityKindString(pUnifiedMemoryCounterRecord->kind),
                    (unsigned long long)pUnifiedMemoryCounterRecord->start,
                    (unsigned long long)pUnifiedMemoryCounterRecord->end,
                    (unsigned long long)(pUnifiedMemoryCounterRecord->end - pUnifiedMemoryCounterRecord->start),
                    GetActivityUnifiedMemoryCounterKindString(pUnifiedMemoryCounterRecord->counterKind),
                    (unsigned long long)pUnifiedMemoryCounterRecord->value,
                    (unsigned long long)pUnifiedMemoryCounterRecord->address,
                    pUnifiedMemoryCounterRecord->srcId,
                    pUnifiedMemoryCounterRecord->dstId,
                    pUnifiedMemoryCounterRecord->processId);

            break;
        }
        case CUPTI_ACTIVITY_KIND_FUNCTION:
        {
            CUpti_ActivityFunction *pFunctionRecord = (CUpti_ActivityFunction *)pRecord;

            fprintf(pFileHandle, "%s id %u, contextId %u, moduleId %u, functionIndex %u, name %s\n",
                    GetActivityKindString(pFunctionRecord->kind),
                    pFunctionRecord->id,
                    pFunctionRecord->contextId,
                    pFunctionRecord->moduleId,
                    pFunctionRecord->functionIndex,
                    GetName(pFunctionRecord->name));

            break;
        }
        case CUPTI_ACTIVITY_KIND_MODULE:
        {
            CUpti_ActivityModule *pModuleRecord = (CUpti_ActivityModule *)pRecord;

            fprintf(pFileHandle, "%s contextId %u, id %d, cubinSize %d\n",
                    GetActivityKindString(pModuleRecord->kind),
                    pModuleRecord->contextId,
                    pModuleRecord->id,
                    pModuleRecord->cubinSize);

            break;
        }
        case CUPTI_ACTIVITY_KIND_DEVICE_ATTRIBUTE:
        {
            CUpti_ActivityDeviceAttribute *pDeviceAttributeRecord = (CUpti_ActivityDeviceAttribute *)pRecord;

            fprintf(pFileHandle, "%s %u, deviceId %u, value 0x%llx\n",
                    GetActivityKindString(pDeviceAttributeRecord->kind),
                    pDeviceAttributeRecord->attribute.cupti,
                    pDeviceAttributeRecord->deviceId,
                    (unsigned long long)pDeviceAttributeRecord->value.vUint64);

            break;
        }
        case CUPTI_ACTIVITY_KIND_OPENACC_DATA:
        {
            CUpti_ActivityOpenAccData *pOpenaccDataRecord = (CUpti_ActivityOpenAccData *)pRecord;

            PrintOpenaccCommon(pFileHandle, (CUpti_ActivityOpenAcc*)pOpenaccDataRecord);

            fprintf(pFileHandle, ", bytes %llu, varName %s\n",
                    (long long unsigned)pOpenaccDataRecord->bytes,
                    pOpenaccDataRecord->varName ? pOpenaccDataRecord->varName : "?");

            break;
        }
        case CUPTI_ACTIVITY_KIND_OPENACC_LAUNCH:
        {
            CUpti_ActivityOpenAccLaunch *pOpenaccLaunchRecord = (CUpti_ActivityOpenAccLaunch *)pRecord;

            PrintOpenaccCommon(pFileHandle, (CUpti_ActivityOpenAcc*)pOpenaccLaunchRecord);

            fprintf(pFileHandle, ", numGangs %llu, numWorkers %llu, vectorLength %llu, kernelName %s\n",
                    (long long unsigned)pOpenaccLaunchRecord->numGangs,
                    (long long unsigned)pOpenaccLaunchRecord->numWorkers,
                    (long long unsigned)pOpenaccLaunchRecord->vectorLength,
                    pOpenaccLaunchRecord->kernelName ? pOpenaccLaunchRecord->kernelName : "?");

            break;
        }
        case CUPTI_ACTIVITY_KIND_OPENACC_OTHER:
        {
            CUpti_ActivityOpenAccOther *pOpenaccOtherRecord = (CUpti_ActivityOpenAccOther *)pRecord;

            PrintOpenaccCommon(pFileHandle, (CUpti_ActivityOpenAcc*)pOpenaccOtherRecord);
            printf("\n");

            break;
        }
        case CUPTI_ACTIVITY_KIND_CUDA_EVENT:
        {
            CUpti_ActivityCudaEvent2 *pCudaEventRecord = (CUpti_ActivityCudaEvent2 *)pRecord;

            fprintf(pFileHandle, "%s [ %llu ] contextId %u, streamId %u, correlationId %u, eventId %u, cudaEventSyncId %llu\n",
                    GetActivityKindString(pCudaEventRecord->kind),
                    (long long unsigned)pCudaEventRecord->deviceTimestamp,
                    pCudaEventRecord->contextId,
                    pCudaEventRecord->streamId,
                    pCudaEventRecord->correlationId,
                    pCudaEventRecord->eventId,
                    (long long unsigned)pCudaEventRecord->cudaEventSyncId);

            break;
        }
        case CUPTI_ACTIVITY_KIND_STREAM:
        {
            CUpti_ActivityStream *pStreamRecord = (CUpti_ActivityStream *)pRecord;

            fprintf(pFileHandle, "%s type %s, priority %u, contextId %u, streamId %u, correlationId %u\n",
                    GetActivityKindString(pStreamRecord->kind),
                    GetActivityStreamFlagString(pStreamRecord->flag),
                    pStreamRecord->priority,
                    pStreamRecord->contextId,
                    pStreamRecord->streamId,
                    pStreamRecord->correlationId);
            break;
        }
        case CUPTI_ACTIVITY_KIND_SYNCHRONIZATION:
        {
            CUpti_ActivitySynchronization2 *pSynchronizationRecord = (CUpti_ActivitySynchronization2 *)pRecord;

            fprintf(pFileHandle, "%s [ %llu, %llu ] duration %llu, type %s, contextId %u, streamId %d, correlationId %u, eventId %d, cudaEventSyncId %llu\n",
                    GetActivityKindString(pSynchronizationRecord->kind),
                    (unsigned long long)pSynchronizationRecord->start,
                    (unsigned long long)pSynchronizationRecord->end,
                    (unsigned long long)(pSynchronizationRecord->end - pSynchronizationRecord->start),
                    GetActivitySynchronizationTypeString(pSynchronizationRecord->type),
                    pSynchronizationRecord->contextId,
                    (int32_t)pSynchronizationRecord->streamId,
                    pSynchronizationRecord->correlationId,
                    (int32_t)pSynchronizationRecord->cudaEventId,
                    (long long unsigned)pSynchronizationRecord->cudaEventSyncId);

            break;
        }
        case CUPTI_ACTIVITY_KIND_EXTERNAL_CORRELATION:
        {
            CUpti_ActivityExternalCorrelation *pExternalCorrelationRecord = (CUpti_ActivityExternalCorrelation *)pRecord;

            fprintf(pFileHandle, "%s externalKind %s, correlationId %llu, externalId %llu\n",
                    GetActivityKindString(pExternalCorrelationRecord->kind),
                    GetExternalCorrelationKindString(pExternalCorrelationRecord->externalKind),
                    (long long unsigned)pExternalCorrelationRecord->correlationId,
                    (long long unsigned)pExternalCorrelationRecord->externalId);

            break;
        }
        case CUPTI_ACTIVITY_KIND_NVLINK:
        {
            CUpti_ActivityNvLink5 *pNvLinkRecord = (CUpti_ActivityNvLink5 *)pRecord;
            unsigned int i = 0;

            fprintf(pFileHandle, "%s typeDev0 %s, typeDev1 %s, sysmem %d, peer %d, physicalNvLinkCount %d, ",
                    GetActivityKindString(pNvLinkRecord->kind),
                    GetDevTypeString(pNvLinkRecord->typeDev0),
                    GetDevTypeString(pNvLinkRecord->typeDev1),
                    ((pNvLinkRecord->flag & CUPTI_LINK_FLAG_SYSMEM_ACCESS) ? 1 : 0),
                    ((pNvLinkRecord->flag & CUPTI_LINK_FLAG_PEER_ACCESS) ? 1 : 0),
                    pNvLinkRecord->physicalNvLinkCount);

            fprintf(pFileHandle, "portDev0 ");
            for (i = 0 ; i < pNvLinkRecord->physicalNvLinkCount ; i++ )
            {
                fprintf(pFileHandle, "%d, ", pNvLinkRecord->portDev0[i]);
            }


            fprintf(pFileHandle, "portDev1 ");
            for (i = 0 ; i < pNvLinkRecord->physicalNvLinkCount ; i++ )
            {
                fprintf(pFileHandle, "%d, ", pNvLinkRecord->portDev1[i]);
            }

            fprintf(pFileHandle, "bandwidth %llu\n", (long long unsigned int)pNvLinkRecord->bandwidth);

            break;
        }
        case CUPTI_ACTIVITY_KIND_MEMORY:
        {
            CUpti_ActivityMemory *pMemoryRecord = (CUpti_ActivityMemory *)(void *)pRecord;

            fprintf(pFileHandle, "%s [ %llu, %llu ] duration %llu, size %llu bytes, address %llu, memoryKind %s, deviceId %u, contextId %u, processId %u\n",
                    GetActivityKindString(pMemoryRecord->kind),
                    (unsigned long long)pMemoryRecord->start,
                    (unsigned long long)pMemoryRecord->end,
                    (unsigned long long)(pMemoryRecord->end - pMemoryRecord->start),
                    (unsigned long long)pMemoryRecord->bytes,
                    (unsigned long long)pMemoryRecord->address,
                    GetActivityMemoryKindString(pMemoryRecord->memoryKind),
                    pMemoryRecord->deviceId,
                    pMemoryRecord->contextId,
                    pMemoryRecord->processId);

            break;
        }
        case CUPTI_ACTIVITY_KIND_PCIE:
        {
            CUpti_ActivityPcie *pPcieRecord = (CUpti_ActivityPcie *)pRecord;

            if (pPcieRecord->type == CUPTI_PCIE_DEVICE_TYPE_GPU)
            {
                fprintf(pFileHandle, "%s GPU %u, domain %u, upstreamBus %u, link rate %u GT/s, link width %u bits.\n",
                        GetActivityKindString(pPcieRecord->kind),
                        pPcieRecord->id.devId,
                        pPcieRecord->domain,
                        pPcieRecord->upstreamBus,
                        pPcieRecord->linkRate,
                        pPcieRecord->linkWidth);
            }
            else if (pPcieRecord->type == CUPTI_PCIE_DEVICE_TYPE_BRIDGE)
            {
                fprintf(pFileHandle, "%s bridgeId %u, domain %u, upstream Bus %u, downstream Bus %u, link rate %u GT/s, link width %u bits.\n",
                        GetActivityKindString(pPcieRecord->kind),
                        pPcieRecord->id.bridgeId,
                        pPcieRecord->domain,
                        pPcieRecord->upstreamBus,
                        pPcieRecord->attr.bridgeAttr.secondaryBus,
                        pPcieRecord->linkRate,
                        pPcieRecord->linkWidth);
            }

            break;
        }
        case CUPTI_ACTIVITY_KIND_OPENMP:
        {
            CUpti_ActivityOpenMp *pOpenMpRecord = (CUpti_ActivityOpenMp *)pRecord;

            fprintf(pFileHandle, "%s [ %llu, %llu ] duration %llu, eventKind %u, cuProcessId %u, cuThreadId %u\n",
                    GetActivityKindString(pOpenMpRecord->kind),
                    (unsigned long long)pOpenMpRecord->start,
                    (unsigned long long)pOpenMpRecord->end,
                    (unsigned long long)(pOpenMpRecord->end - pOpenMpRecord->start),
                    pOpenMpRecord->eventKind,
                    pOpenMpRecord->cuProcessId,
                    pOpenMpRecord->cuThreadId);

            break;
        }
        case CUPTI_ACTIVITY_KIND_MEMORY2:
        {
            CUpti_ActivityMemory4 *pMemory2Record = (CUpti_ActivityMemory4 *)(void *)pRecord;

            fprintf(pFileHandle, "%s [ %llu ] memoryOperationType %s, memoryKind %s, size %llu, address %llu, pc %llu,\n"
                    "  deviceId %u, contextId %u, streamId %u, processId %u, correlationId %u, isAsync %u,\n"
                    "  memoryPool %s, memoryPoolAddress %llu,  memoryPoolThreshold %llu\n"
                    ,
                    GetActivityKindString(pMemory2Record->kind),
                    (unsigned long long)pMemory2Record->timestamp,
                    GetActivityMemoryOperationTypeString(pMemory2Record->memoryOperationType),
                    GetActivityMemoryKindString(pMemory2Record->memoryKind),
                    (unsigned long long)pMemory2Record->bytes,
                    (unsigned long long)pMemory2Record->address,
                    (unsigned long long)pMemory2Record->PC,
                    pMemory2Record->deviceId,
                    pMemory2Record->contextId,
                    pMemory2Record->streamId,
                    pMemory2Record->processId,
                    pMemory2Record->correlationId,
                    pMemory2Record->isAsync,
                    GetActivityMemoryPoolTypeString(pMemory2Record->memoryPoolConfig.memoryPoolType),
                    (unsigned long long)pMemory2Record->memoryPoolConfig.address,
                    (unsigned long long)pMemory2Record->memoryPoolConfig.releaseThreshold
                    );

            if (pMemory2Record->memoryPoolConfig.memoryPoolType == CUPTI_ACTIVITY_MEMORY_POOL_TYPE_LOCAL)
            {
                fprintf(pFileHandle, ", memoryPoolSize: %llu, memoryPoolUtilizedSize: %llu",
                        (unsigned long long)pMemory2Record->memoryPoolConfig.pool.size,
                        (unsigned long long)pMemory2Record->memoryPoolConfig.utilizedSize);
            }
            else if (pMemory2Record->memoryPoolConfig.memoryPoolType == CUPTI_ACTIVITY_MEMORY_POOL_TYPE_IMPORTED)
            {
                fprintf(pFileHandle, ", memoryPoolProcessId: %llu",
                        (unsigned long long)pMemory2Record->memoryPoolConfig.pool.processId);
            }

            fprintf(pFileHandle, "\n");

            break;
        }
        case CUPTI_ACTIVITY_KIND_MEMORY_POOL:
        {
            CUpti_ActivityMemoryPool3 *pMemoryPoolRecord = (CUpti_ActivityMemoryPool3 *)(void *)pRecord;

            fprintf(pFileHandle, "%s [ %llu ] memoryPoolOperation %s, memoryPool %s, address %llu, size %llu, utilizedSize %llu, %d isManagedPool, releaseThreshold %llu,\n"
                    "  deviceId %u, processId %u, correlationId %u\n",
                    GetActivityKindString(pMemoryPoolRecord->kind),
                    (unsigned long long)pMemoryPoolRecord->timestamp,
                    GetActivityMemoryPoolOperationTypeString(pMemoryPoolRecord->memoryPoolOperationType),
                    GetActivityMemoryPoolTypeString(pMemoryPoolRecord->memoryPoolType),
                    (unsigned long long)pMemoryPoolRecord->address,
                    (unsigned long long)pMemoryPoolRecord->size,
                    (unsigned long long)pMemoryPoolRecord->utilizedSize,
                    pMemoryPoolRecord->isManagedPool,
                    (unsigned long long)pMemoryPoolRecord->releaseThreshold,
                    pMemoryPoolRecord->deviceId,
                    pMemoryPoolRecord->processId,
                    pMemoryPoolRecord->correlationId);

            break;
        }
        case CUPTI_ACTIVITY_KIND_GRAPH_TRACE:
        {
            CUpti_ActivityGraphTrace2 *pGraphTraceRecord = (CUpti_ActivityGraphTrace2 *)pRecord;

            fprintf(pFileHandle, "%s [ %llu, %llu ] duration %llu, correlationId %u\n deviceId %u, contextId %u, streamId %u, graphId %u\n",
                    GetActivityKindString(pGraphTraceRecord->kind),
                    (unsigned long long)pGraphTraceRecord->start,
                    (unsigned long long)pGraphTraceRecord->end,
                    (unsigned long long)(pGraphTraceRecord->end - pGraphTraceRecord->start),
                    pGraphTraceRecord->correlationId,
                    pGraphTraceRecord->deviceId,
                    pGraphTraceRecord->contextId,
                    pGraphTraceRecord->streamId,
                    pGraphTraceRecord->graphId);

            break;
        }
        case CUPTI_ACTIVITY_KIND_JIT:
        {
            CUpti_ActivityJit2 *pJitRecord = (CUpti_ActivityJit2 *)pRecord;

            fprintf(pFileHandle, "%s [ %llu, %llu ] duration %llu, deviceId %u, correlationId %u, processId %u, threadId %u\n"
                    "jitEntryType %s, jitOperationType %s, jitOperationCorrelationId %llu\n cacheSize %llu, cachePath %s\n",
                    GetActivityKindString(pJitRecord->kind),
                    (unsigned long long)pJitRecord->start,
                    (unsigned long long)pJitRecord->end,
                    (unsigned long long)(pJitRecord->end - pJitRecord->start),
                    pJitRecord->deviceId,
                    pJitRecord->correlationId,
                    pJitRecord->processId,
                    pJitRecord->threadId,
                    GetActivityJitEntryTypeString(pJitRecord->jitEntryType),
                    GetActivityJitOperationTypeString(pJitRecord->jitOperationType),
                    (unsigned long long)pJitRecord->jitOperationCorrelationId,
                    (unsigned long long)pJitRecord->cacheSize,
                    GetName(pJitRecord->cachePath));

            break;
        }
        case CUPTI_ACTIVITY_KIND_MEM_DECOMPRESS:
        {
            CUpti_ActivityMemDecompress *pMemDecompress = (CUpti_ActivityMemDecompress *)pRecord;

            fprintf(pFileHandle, "%s [ %llu, %llu ] duration %llu, deviceId %u, contextId %u, streamId %u, correlationId %u\n"
                    "channelId %u, channelType %s, numberOfOperations %u, sourceBytes %llu\n",
                    GetActivityKindString(pMemDecompress->kind),
                    (unsigned long long)pMemDecompress->start,
                    (unsigned long long)pMemDecompress->end,
                    (unsigned long long)(pMemDecompress->end - pMemDecompress->start),
                    pMemDecompress->deviceId,
                    pMemDecompress->contextId,
                    pMemDecompress->streamId,
                    pMemDecompress->correlationId,
                    pMemDecompress->channelID,
                    GetChannelTypeString(pMemDecompress->channelType),
                    pMemDecompress->numberOfOperations,
                    (unsigned long long)pMemDecompress->sourceBytes);

            break;
        }
        case CUPTI_ACTIVITY_KIND_GRAPH_HOST_NODE:
        {
            CUpti_ActivityGraphHostNode *pGraphHostNodeRecord = (CUpti_ActivityGraphHostNode *)pRecord;

            fprintf(pFileHandle, "%s [ %llu, %llu ] duration %llu, deviceId %u, contextId %u, streamId %u, correlationId %u, graphId %u, nodeId %llu\n",
                    GetActivityKindString(pGraphHostNodeRecord->kind),
                    (unsigned long long)pGraphHostNodeRecord->start,
                    (unsigned long long)pGraphHostNodeRecord->end,
                    (unsigned long long)(pGraphHostNodeRecord->end - pGraphHostNodeRecord->start),
                    pGraphHostNodeRecord->deviceId,
                    pGraphHostNodeRecord->contextId,
                    pGraphHostNodeRecord->streamId,
                    pGraphHostNodeRecord->correlationId,
                    pGraphHostNodeRecord->graphId,
                    (unsigned long long)pGraphHostNodeRecord->graphNodeId);
            break;
        }
        case CUPTI_ACTIVITY_KIND_HOST_LAUNCH:
        {
            CUpti_ActivityHostLaunch *pHostLaunchRecord = (CUpti_ActivityHostLaunch *)pRecord;

            fprintf(pFileHandle, "%s [ %llu, %llu ] duration %llu, deviceId %u, contextId %u, streamId %u, correlationId %u\n",
                    GetActivityKindString(pHostLaunchRecord->kind),
                    (unsigned long long)pHostLaunchRecord->start,
                    (unsigned long long)pHostLaunchRecord->end,
                    (unsigned long long)(pHostLaunchRecord->end - pHostLaunchRecord->start),
                    pHostLaunchRecord->deviceId,
                    pHostLaunchRecord->contextId,
                    pHostLaunchRecord->streamId,
                    pHostLaunchRecord->correlationId);
            break;
        }
        case CUPTI_ACTIVITY_KIND_COMPUTE_ENGINE_CTX_SWITCH:
        {
            CUpti_ActivityComputeEngineCtxSwitch *pComputeEngineCtxSwitchRecord = (CUpti_ActivityComputeEngineCtxSwitch *)pRecord;

            fprintf(pFileHandle, "%s contextId %u, timestamp %llu, operationType %d\n",
                    GetActivityKindString(pComputeEngineCtxSwitchRecord->kind),
                    pComputeEngineCtxSwitchRecord->contextId,
                    (unsigned long long)pComputeEngineCtxSwitchRecord->timestamp,
                    (int)pComputeEngineCtxSwitchRecord->operationType);

            break;
        }
        case CUPTI_ACTIVITY_KIND_GREEN_CONTEXT:
        {
            CUpti_ActivityGreenContext2 *pGreenContextRecord = (CUpti_ActivityGreenContext2 *)pRecord;

            fprintf(pFileHandle, "%s contextId %u, parentContextId %u, deviceId %u, numMultiprocessors %u, numTpcs %u\n"
                    "\tlogicalTpcMaskSize %u, workqueueResourceId %llu, workqueueConcurrencyLimit %u, workqueueSharingScope %u\n",
                    GetActivityKindString(pGreenContextRecord->kind),
                    pGreenContextRecord->contextId,
                    pGreenContextRecord->parentContextId,
                    pGreenContextRecord->deviceId,
                    pGreenContextRecord->numMultiprocessors,
                    pGreenContextRecord->numTpcs,
                    pGreenContextRecord->logicalTpcMaskSize,
                    (unsigned long long)pGreenContextRecord->workqueueResourceId,
                    pGreenContextRecord->workqueueConcurrencyLimit,
                    pGreenContextRecord->workqueueSharingScope);

            break;
        }
        default:
            fprintf(pFileHandle, "%s: Print support is not added for this kind.\n", GetActivityKindString(pRecord->kind));
            break;
    }
}

#endif // HELPER_CUPTI_ACTIVITY_RECORDS_H_
