// Copyright (C) 2023-2026 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

/*
  VERSION HISTORY

 - version 2.3
     Adds DMATask fields:
       tensorShapeInfo, tensorStrideInfo, gatherIndices, dynamicStridesInput, dynamicStridesOutput

 - version 2.2
     Adds DPU fields:
       tensorInfo, variantInfo
     Adds ActShave field:
       tensorInfo

 - version 2.1
     Adds DMATask fields:
       portId, channelType, sourceMemoryType, destinationMemoryType

 - version 2.0 (initial version)

*/

namespace ProfilingFB;

enum MemoryKind : byte { DDR, CMX }

enum DMAChannelType : byte { DDR, CMX }

table ShapeInfo {
    dimensions: [uint];
    elemType: string;
}

table TensorInfo {
    inputs: [ShapeInfo] (native_inline);
    outputs: [ShapeInfo] (native_inline);
}

// The current implementation assumes that each of the arrays in DPUVariantInfo has length of 3.
table DPUVariantInfo {
    inStart: [uint];
    inEnd: [uint];
    outStart: [uint];
    outEnd: [uint];
}

// Each task represent individual task, which can be executed and so be profiled.
// DMATask - DMA transaction, DPUTask - DPU invariant, SWTask - single kernel invocation,
// M2ITask - M2I Task invocation.
// Some fields are common, like name(consist of original layer name, which come from IR location)
// and wait/update barriers, which represent dependencies. Other fields specific to engine

table DMATask {
    name: string;
    waitBarriers: [uint];
    updateBarriers: [uint];
    hwpId: ushort;          // DMA hardware profiling ID
    dataIndex: uint;        // The position in the profiling output binary
    isProfBegin: bool;      // Marker of profBeginDma
    portId: ushort = null;
    channelType: DMAChannelType = null;
    sourceMemoryKind: MemoryKind = null;
    destinationMemoryKind: MemoryKind = null;
    tensorShapeInfo: TensorInfo;
    tensorStrideInfo: TensorInfo;
    gatherIndices: ushort; // Number of indices passed to GatherDMA, 0 means task isn't a GatherDMA
    dynamicStridesInput: bool;
    dynamicStridesOutput: bool;
}

// DPU tasks are special, because of memory layout, which may be distributed across multiple clusters.
// Each DPU invariant may consist of variable number of variants(numVariants field), which can be different from
// other invariants of the same task(before unrolling). Profiling buffer is allocated before the task is split into invariants,
// and memory distribution is assumed to be the same for all clusters, so knowledge of maxVariants is needed to skip empty regions for cluster,
// which don't use all allocated memory. bufferId and taskId is needed to know order of tasks and for debugging purpose

table DPUTask {
    name: string;
    bufferId: ushort;               // id of buffer(single DPU profiling buffer in CMX)
    clusterId: ushort;              // id of cluster
    taskId: ushort;                 // id of task(global, not in current buffer)
    numVariants: ushort;            // count of variants(or count of **used** profiling timestamps)
    maxVariants: ushort;            // max. count of variants in any invariant, which was grouped before unrolling(or size of **allocated** memory for profiling timestamps)
    waitBarriers: [uint];
    updateBarriers: [uint];
    workloadIds: [uint];            // DPU hardware profiling ID, for validation purpose. Quantity should be the same as numVariants
    tensorInfo: TensorInfo;         // DPU invariant-level tensor info
    variantInfo: [DPUVariantInfo] (native_inline);  // DPU variant offsets
}

table SWTask {
    name: string;
    waitBarriers: [uint];
    updateBarriers: [uint];
    taskType: string;       // name of the kernel or layer type
    bufferId: ushort;       // id of buffer(single SW profiling buffer in CMX)
    bufferOffset: uint;     // offset to start of current buffer from beginning of master buffer(in tasks)
    clusterSize: uint;      // size of buffer(in tasks)
    dataIndex: uint;        // index of current task
    tileId: uint;
    clusterId: uint;
    tensorInfo: TensorInfo;
}

table M2ITask {
    name: string;
    waitBarriers: [uint];
    updateBarriers: [uint];
}

table ProfilingSection {
    type: uint;
    offset: uint;
    size: uint;
    typeLabel: string;
}

table ProfilingBuffer {
    sections: [ProfilingSection];
    size: uint;
}

table Platform {
    device: byte;
}

// High level container over others
table ProfilingMeta {
    majorVersion: uint;
    minorVersion: uint;
    platform: Platform;
    profilingBuffer: ProfilingBuffer;
    dmaTasks: [DMATask];
    dpuTasks: [DPUTask];
    swTasks: [SWTask];
    m2iTasks: [M2ITask];
}

root_type ProfilingMeta;
