Skip to content

Profiling

CVEDIA-RT allows profiling the instances, gathering information about timings in realtime.

Profiling Window

CVEDIA-RT's gathered data can be viewed on the Profiler Window, when this window is open the profiling system is enabled and CVEDIA-RT starts gathering data. Otherwise the system is not active, so that it doesn't affect performance.

cvediart-profiler-window

Profiling Counters

System Counters

Multiple modules and CVEDIART internal functionalities have profiling counters already defined, when the profiling system is activated this will start collecting data, for example the inference system collects timings on how long does an inference operation takes in ms.

User Defined Counters

CVEDIART scripting system allows creating and accessing custom profiling counters with specific Lua functions:

rt:writePerformanceCounter : Write a value to a PerformanceCounter (This will show up on the Profiling Window)

rt:writePerformanceCounter("counter_name", counter_value_float)

rt:getAllPerformanceCounters : Get a table will all PerformanceCounters (Including Global ones)

rt:getAllPerformanceCounters()

rt:getInstancePerformanceCounters : Get a table will the Instance PerformanceCounters

rt:getAllPerformanceCounters()

getAllPerformanceCounters Table Structure

{
  lua = {}, // Lua related counters
  rt = {  // Instance counters
    ["InputManaged::readFrame"] = { 7.0, 0.0, 7.8000001907349, 0.0, 8.7538461685181, 4226.0, 9.3751249313354, 67.0, 0.0 },
    [counter_name] = { Latest Value, Avg50 , Avg10, Avg100, AvgTotal, Total Samples count, Total Avg Since Start, Max Since Start }
  }
}

rt Lua variable

In this case, the rt Lua variable presented represents the instance variable returned from rt = api.thread.getCurrentInstance()


Demo - Output Profiling Data with sinks

This Demo showcases how its possible to output profiling data using the sink and Output handler system from CVEDIA-RT

Instance Json - ProfilerDemo.json

This json configures an instance with a Video File input and a Json Output thats attached to the profiler sink, it also uses the assets/scripts/profiler_output.lua to process the data that is fed to the output

{
    "Input": {
        "config": {
            "media_type": "Video File",
            "uri": [
                "ffmpeg:///assets/videos/demo.mp4"
            ]
        }
    },
    "Output": {
        "handlers": [
            {
                "sink": "profiler",
                "uri": "json:///output/detector_outputs.json",
                "config": {
                    "script": "assets/scripts/profiler_output.lua"
                }
            }
        ]
    }
}

Instance Code - index.lua

The Lua code for the instance will be based on a simple detector but will define a new sink called profiler, which will receive the data from the profiler counters, then, because we have an Output Handler attached to the profiler sink, we can output that data to a json file, passing it first through the profiler_output.lua script.

dofile(luaroot .. "/api/api.lua")
dofile(luaroot .. "/profiler.lua")

-- Declare and initialize global instances and modules
---@class rt_instance
rt = api.thread.getCurrentInstance()
---@class inferencemanaged
detectInst = api:loadInference("PVADetector","Detector")
---@class inputmanaged
input = api:loadInput("Input")
---@class outputmanaged
output = api:loadOutput("Output")

function onStartInstance(name, config)
    rt:registerSink("Output")
    rt:registerSink("profiler")
    rt:createWorker("myworker1", "onInit", "onRun")
end

function onInit()
    -- Load Input source from configuration on the system
    input:setSource()
    -- Load Output source from configuration on the system
    output:setSource()

    -- Load Detector model on the system
    detectInst = sapi.createBackend("auto://pva_det/rgb/small/220204", "PVADetector", 1)

    Profiler.Init(sapi)
    Profiler.Enable()

    -- Start performance counter system (Otherwise its only enabled when we open the Profiler window)
    rt:setPerformanceCounterState(true)
    return true
end

function onRun(currentTime)

    -- Get next frame, if the instance is paused we must ignore the skip_frame functionality
    local inputimg = input:readFrame(rt:isPaused())
    if inputimg ~= nil and inputimg:is_valid() then

        local outputimg = inputimg:copy()

        -- Start measuring performance couter
        Profiler.TraceStart("detection_time")

        -- Run detector
        local detections = detectInst:runInference({ x=0, y=0, width=1.0, height=1.0, relative=true, source=inputimg })

        -- Write performance counter with detection time interval (Calls rt:writePerformanceCounter("detection_time",value) internally)
        Profiler.TraceInterval("detection_time")

        if detections ~= nil then
            for _, d in pairs(detections) do
                outputimg:drawBoundingBox(d.x, d.y, d.width, d.height, string.format("%s (%.2f)", d.label, d.confidence), {0, 255, 0}, 1)
            end
        end

        rt:writeToSink("Output", {image = outputimg, meta=detections})

        -- Write performance counter data to the profiler sink
        rt:writeToSink("profiler", {meta=rt:getAllPerformanceCounters()})

        rt:stepThread()
    end

    return true
end

Script Code - assets/scripts/profiler_output.lua

The Output Handler will look for a script in assets/scripts/profiler_output.lua to process the data. This script will simply take the metadata provided and output the detection_time field that we created manually, as well as an endline char.

function outputHandlerProcess(metadata)
    if metadata == nil then
        return {}
    end
    local last_value_column_index = 1
    return metadata.rt["detection_time"][last_value_column_index] .. "\n";
end

outputHandlerProcess

All the scripts defined in the Output Handler section will look for a function called outputHandlerProcess in the file, only this function will be run.