VPI - Vision Programming Interface

0.1.0 Release

Timing With Events

Overview

This application shows how to use events to measure the time taken to process VPI tasks. It does an image downsampling composed of two tasks: image blurring to avoid aliasing, followed by actual downsampling. Using a 1920x1080, 8bpp single channel input image, it record events before and after processing it, and also in between the tasks. At the end it shows the time taken for each task and the total time.

This sample shows the following VPI features:

  • Creating and destroying a VPI device.
  • Creating a VPI-managed 2D images.
  • Create a GaussianFilter and Resample algorithms and submit them.
  • Creation of VPI events.
  • Use events to record the state of a VPI device.
  • Measure elapsed time between events.
  • Simple device synchronization.
  • Error handling.
  • Environment clean up.

Instructions

The usage is:

./vpi_sample_05_timing <backend>

where

  • backend: either cpu, cuda or pva; it defines the backend that will perform the processing.

Here's one example:

./vpi_sample_05_timing cuda

This is using the CUDA backend. Try other backends to see how the processing time differs between them.

Source code

For convenience, here's the code that is also installed in the samples directory.

/*
* 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 <vpi/Event.h>
#include <vpi/Image.h>
#include <vpi/Pyramid.h>
#include <vpi/Stream.h>
#include <iostream>
#define CHECK_STATUS(STMT) \
do \
{ \
VPIStatus status = (STMT); \
if (status != VPI_SUCCESS) \
{ \
throw std::runtime_error(vpiStatusGetName(status)); \
} \
} while (0);
int main(int argc, char *argv[])
{
VPIImage image = nullptr;
VPIImage blurred = nullptr;
VPIPyramid output = nullptr;
VPIStream stream = nullptr;
VPIEvent evStart = nullptr;
VPIEvent evBlur = nullptr;
VPIEvent evPyramid = nullptr;
int retval = 0;
try
{
// 1. Initialization stage ----------------------
if (argc != 2)
{
throw std::runtime_error(std::string("Usage: ") + argv[0] + " <cpu|pva|cuda>");
}
std::string strDevType = argv[1];
// Process the device type
VPIDeviceType devType;
if (strDevType == "cpu")
{
}
else if (strDevType == "cuda")
{
}
else if (strDevType == "pva")
{
}
else
{
throw std::runtime_error("Backend '" + strDevType +
"' not recognized, it must be either cpu, cuda or pva.");
}
// Create the stream for the given backend.
CHECK_STATUS(vpiStreamCreate(devType, &stream));
int width = 1920, height = 1080;
std::cout << "Input size: " << width << " x " << height << '\n';
// Create image with zero content
CHECK_STATUS(vpiImageCreate(width, height, imgType, 0, &image));
// Now create the output image
CHECK_STATUS(vpiPyramidCreate(width, height, imgType, 3, 0.5, 0, &output));
// Create a temporary image convolved with a low-pass filter.
CHECK_STATUS(vpiImageCreate(width, height, imgType, 0, &blurred));
// Create the events we'll need to get timing info
CHECK_STATUS(vpiEventCreate(0, &evStart));
CHECK_STATUS(vpiEventCreate(0, &evBlur));
CHECK_STATUS(vpiEventCreate(0, &evPyramid));
// 2. Processing ----------------------
// Record stream queue when we start processing
CHECK_STATUS(vpiEventRecord(evStart, stream));
// First we apply a low-pass filter using gaussian to avoid aliasing
CHECK_STATUS(vpiSubmitGaussianImageFilter(stream, image, blurred, 5, 5, 1, 1, VPI_BOUNDARY_COND_ZERO));
// Record stream queue just after blurring
CHECK_STATUS(vpiEventRecord(evBlur, stream));
// Now we create a gaussian pyramid out of it.
CHECK_STATUS(vpiSubmitGaussianPyramidGenerator(stream, blurred, output));
// Record stream queue just after pyramid generation, thus capturing the whole processing
CHECK_STATUS(vpiEventRecord(evPyramid, stream));
// Wait until the gaussian pyramid finishes processing
CHECK_STATUS(vpiEventSync(evPyramid));
// 3. Timing analysis ----------------------
float elapsedBlurMS, elapsedPyramidMS, elapsedTotalMS;
CHECK_STATUS(vpiEventElapsedTime(evStart, evBlur, &elapsedBlurMS));
CHECK_STATUS(vpiEventElapsedTime(evBlur, evPyramid, &elapsedPyramidMS));
CHECK_STATUS(vpiEventElapsedTime(evStart, evPyramid, &elapsedTotalMS));
printf("Blurring elapsed time: %f ms\n", elapsedBlurMS);
printf("Gaussian pyramid elapsed time: %f ms\n", elapsedPyramidMS);
printf("Total elapsed time: %f ms\n", elapsedTotalMS);
}
catch (std::exception &e)
{
std::cerr << e.what() << std::endl;
retval = 1;
}
// 4. Clean up -----------------------------------
vpiImageDestroy(blurred);
vpiEventDestroy(evStart);
vpiEventDestroy(evBlur);
vpiEventDestroy(evPyramid);
return retval;
}

Results

The input image is 1920x1080, 8bpp single channel. Image downsample currently isn't supported on PVA, so no data for this backend.

Note
You should not interpret these elapsed times as a performance benchmark. For this reason, we're not specifying here the hardware used to measure them.

CPU Backend

Input size: 1920 x 1080
Blurring elapsed time: 703.280823 ms
Gaussian pyramid elapsed time: 97.995987 ms
Total elapsed time: 801.276855 ms

CUDA Backend

Input size: 1920 x 1080
Blurring elapsed time: 0.531488 ms
Gaussian pyramid elapsed time: 0.313856 ms
Total elapsed time: 0.845344 ms
vpiEventElapsedTime
VPIStatus vpiEventElapsedTime(VPIEvent start, VPIEvent end, float *msec)
Computes the elapsed time in (msec) between two completed events.
vpiEventCreate
VPIStatus vpiEventCreate(uint32_t flags, VPIEvent *event)
Create an event instance with the specified flags.
VPIDeviceType
VPIDeviceType
Device types.
Definition: Types.h:431
vpiSubmitGaussianPyramidGenerator
VPIStatus vpiSubmitGaussianPyramidGenerator(VPIStream stream, VPIImage input, VPIPyramid output)
Computes the Gaussian pyramid from the input image.
vpiPyramidCreate
VPIStatus vpiPyramidCreate(uint32_t width, uint32_t height, VPIImageType fmt, uint32_t numLevels, float scale, uint32_t flags, VPIPyramid *pyr)
Create an empty image pyramid instance with the specified flags.
vpiEventSync
VPIStatus vpiEventSync(VPIEvent event)
Blocks the calling thread until the event is completed.
VPIImageType
VPIImageType
Image formats.
Definition: Types.h:172
GaussianImageFilter.h
vpiEventRecord
VPIStatus vpiEventRecord(VPIEvent event, VPIStream stream)
Captures in the event the contents of the stream command queue at the time of this call.
vpiStreamCreate
VPIStatus vpiStreamCreate(VPIDeviceType devType, VPIStream *stream)
Create a stream instance.
vpiStreamDestroy
void vpiStreamDestroy(VPIStream stream)
Destroy a stream instance and deallocate all HW resources.
GaussianPyramidGenerator.h
vpiImageDestroy
void vpiImageDestroy(VPIImage img)
Destroy an image instance as well as all resources it owns.
Image.h
Event.h
VPIEvent
struct VPIEventImpl * VPIEvent
Definition: Types.h:141
VPI_IMAGE_TYPE_Y16
unsigned 16-bit grayscale/luma.
Definition: Types.h:176
VPIImage
struct VPIImageImpl * VPIImage
Definition: Types.h:153
Pyramid.h
vpiImageCreate
VPIStatus vpiImageCreate(uint32_t width, uint32_t height, VPIImageType type, uint32_t flags, VPIImage *img)
Create an empty image instance with the specified flags.
VPI_BOUNDARY_COND_ZERO
All pixels outside the image are considered to be zero.
Definition: Types.h:204
VPI_DEVICE_TYPE_PVA
PVA backend.
Definition: Types.h:435
Stream.h
vpiPyramidDestroy
void vpiPyramidDestroy(VPIPyramid pyr)
Destroy an image pyramid instance as well as all resources it owns.
VPIStream
struct VPIStreamImpl * VPIStream
Definition: Types.h:147
vpiEventDestroy
void vpiEventDestroy(VPIEvent event)
Destroy an event instance as well as all resources it owns.
VPIPyramid
struct VPIPyramidImpl * VPIPyramid
Definition: Types.h:159
VPI_DEVICE_TYPE_CUDA
CUDA backend.
Definition: Types.h:434
vpiSubmitGaussianImageFilter
VPIStatus vpiSubmitGaussianImageFilter(VPIStream stream, VPIImage input, VPIImage output, uint32_t kernelSizeX, uint32_t kernelSizeY, float sigmaX, float sigmaY, VPIBoundaryCond boundary)
Runs a 2D Gaussian filter over an image.
VPI_DEVICE_TYPE_CPU
CPU backend.
Definition: Types.h:433