VPI - Vision Programming Interface

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:

  • Creating and destroying a VPI stream.
  • Creating a VPI-managed 2D images.
  • Create a GaussianFilter and Rescale algorithms and submit them.
  • Creation of VPI events.
  • Use events to record the state of a VPI stream.
  • Measure elapsed time between events.
  • Simple stream 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.

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: 6.043959 ms
Gaussian pyramid elapsed time: 5.397499 ms
Total elapsed time: 11.441458 ms

CUDA Backend

Input size: 1920 x 1080
Blurring elapsed time: 1.674752 ms
Gaussian pyramid elapsed time: 4.395520 ms
Total elapsed time: 6.070272 ms

Source Code

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

1 /*
2 * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of NVIDIA CORPORATION nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #include <vpi/Event.h>
30 #include <vpi/Image.h>
31 #include <vpi/Pyramid.h>
32 #include <vpi/Status.h>
33 #include <vpi/Stream.h>
36 
37 #include <cstdio>
38 #include <iostream>
39 #include <sstream>
40 
41 #define CHECK_STATUS(STMT) \
42  do \
43  { \
44  VPIStatus status = (STMT); \
45  if (status != VPI_SUCCESS) \
46  { \
47  char buffer[VPI_MAX_STATUS_MESSAGE_LENGTH]; \
48  vpiGetLastStatusMessage(buffer, sizeof(buffer)); \
49  std::ostringstream ss; \
50  ss << vpiStatusGetName(status) << ": " << buffer; \
51  throw std::runtime_error(ss.str()); \
52  } \
53  } while (0);
54 
55 int main(int argc, char *argv[])
56 {
57  VPIImage image = NULL;
58  VPIImage blurred = NULL;
59  VPIPyramid output = NULL;
60  VPIStream stream = NULL;
61 
62  VPIEvent evStart = NULL;
63  VPIEvent evBlur = NULL;
64  VPIEvent evPyramid = NULL;
65 
66  int retval = 0;
67 
68  try
69  {
70  // 1. Initialization stage ----------------------
71 
72  if (argc != 2)
73  {
74  throw std::runtime_error(std::string("Usage: ") + argv[0] + " <cpu|pva|cuda>");
75  }
76 
77  std::string strBackend = argv[1];
78 
79  // Parse the backend
80  VPIBackend backendType;
81 
82  if (strBackend == "cpu")
83  {
84  backendType = VPI_BACKEND_CPU;
85  }
86  else if (strBackend == "cuda")
87  {
88  backendType = VPI_BACKEND_CUDA;
89  }
90  else if (strBackend == "pva")
91  {
92  backendType = VPI_BACKEND_PVA;
93  }
94  else
95  {
96  throw std::runtime_error("Backend '" + strBackend +
97  "' not recognized, it must be either cpu, cuda or pva.");
98  }
99 
100  // Create the stream for the given backend.
101  CHECK_STATUS(vpiStreamCreate(backendType, &stream));
102 
103  int width = 1920, height = 1080;
105 
106  std::cout << "Input size: " << width << " x " << height << '\n';
107 
108  // Create image with zero content
109  CHECK_STATUS(vpiImageCreate(width, height, imgFormat, 0, &image));
110 
111  // Now create the output image
112  CHECK_STATUS(vpiPyramidCreate(width, height, imgFormat, 3, 0.5, 0, &output));
113 
114  // Create a temporary image convolved with a low-pass filter.
115  CHECK_STATUS(vpiImageCreate(width, height, imgFormat, 0, &blurred));
116 
117  // Create the events we'll need to get timing info
118  CHECK_STATUS(vpiEventCreate(0, &evStart));
119  CHECK_STATUS(vpiEventCreate(0, &evBlur));
120  CHECK_STATUS(vpiEventCreate(0, &evPyramid));
121 
122  // 2. Processing ----------------------
123 
124  // Record stream queue when we start processing
125  CHECK_STATUS(vpiEventRecord(evStart, stream));
126 
127  // First we apply a low-pass filter using gaussian to avoid aliasing
128  CHECK_STATUS(vpiSubmitGaussianFilter(stream, backendType, image, blurred, 5, 5, 1, 1, VPI_BORDER_ZERO));
129 
130  // Record stream queue just after blurring
131  CHECK_STATUS(vpiEventRecord(evBlur, stream));
132 
133  // Now we create a gaussian pyramid out of it.
134  CHECK_STATUS(vpiSubmitGaussianPyramidGenerator(stream, backendType, blurred, output));
135 
136  // Record stream queue just after pyramid generation, thus capturing the whole processing
137  CHECK_STATUS(vpiEventRecord(evPyramid, stream));
138 
139  // Wait until the gaussian pyramid finishes processing
140  CHECK_STATUS(vpiEventSync(evPyramid));
141 
142  // 3. Timing analysis ----------------------
143 
144  float elapsedBlurMS, elapsedPyramidMS, elapsedTotalMS;
145  CHECK_STATUS(vpiEventElapsedTimeMillis(evStart, evBlur, &elapsedBlurMS));
146  CHECK_STATUS(vpiEventElapsedTimeMillis(evBlur, evPyramid, &elapsedPyramidMS));
147  CHECK_STATUS(vpiEventElapsedTimeMillis(evStart, evPyramid, &elapsedTotalMS));
148 
149  printf("Blurring elapsed time: %f ms\n", elapsedBlurMS);
150  printf("Gaussian pyramid elapsed time: %f ms\n", elapsedPyramidMS);
151  printf("Total elapsed time: %f ms\n", elapsedTotalMS);
152  }
153  catch (std::exception &e)
154  {
155  std::cerr << e.what() << std::endl;
156  retval = 1;
157  }
158 
159  // 4. Clean up -----------------------------------
160 
161  // Make sure stream is synchronized before destroying the objects
162  // that might still be in use.
163  if (stream != NULL)
164  {
165  vpiStreamSync(stream);
166  }
167 
168  vpiImageDestroy(image);
169  vpiPyramidDestroy(output);
170  vpiImageDestroy(blurred);
171  vpiEventDestroy(evStart);
172  vpiEventDestroy(evBlur);
173  vpiEventDestroy(evPyramid);
174  vpiStreamDestroy(stream);
175 
176  return retval;
177 }
Functions and structures for dealing with VPI events.
Declares functions that implement the Gaussian Filter algorithm.
Declares functions that handle gaussian pyramids.
Functions and structures for dealing with VPI images.
Functions and structures for dealing with VPI pyramids.
Declaration of VPI status codes handling functions.
Declares functions dealing with VPI streams.
struct VPIEventImpl * VPIEvent
A handle to an event.
Definition: Types.h:185
VPIStatus vpiEventElapsedTimeMillis(VPIEvent start, VPIEvent end, float *msec)
Computes the elapsed time in (msec) between two completed events.
VPIStatus vpiEventRecord(VPIEvent event, VPIStream stream)
Captures in the event the contents of the stream command queue at the time of this call.
VPIStatus vpiEventSync(VPIEvent event)
Blocks the calling thread until the event is signaled.
VPIStatus vpiEventCreate(uint32_t flags, VPIEvent *event)
Create an event instance with the specified flags.
void vpiEventDestroy(VPIEvent event)
Destroy an event instance as well as all resources it owns.
VPIStatus vpiSubmitGaussianFilter(VPIStream stream, uint32_t backend, VPIImage input, VPIImage output, int32_t kernelSizeX, int32_t kernelSizeY, float sigmaX, float sigmaY, VPIBorderExtension border)
Runs a 2D Gaussian filter over an image.
VPIStatus vpiSubmitGaussianPyramidGenerator(VPIStream stream, uint32_t backend, VPIImage input, VPIPyramid output)
Computes the Gaussian pyramid from the input image.
VPIImageFormat
Pre-defined image formats.
Definition: ImageFormat.h:99
@ VPI_IMAGE_FORMAT_U16
Single plane with one 16-bit unsigned integer channel.
Definition: ImageFormat.h:110
void vpiImageDestroy(VPIImage img)
Destroy an image instance.
struct VPIImageImpl * VPIImage
A handle to an image.
Definition: Types.h:197
VPIStatus vpiImageCreate(int32_t width, int32_t height, VPIImageFormat fmt, uint32_t flags, VPIImage *img)
Create an empty image instance with the specified flags.
struct VPIPyramidImpl * VPIPyramid
A handle to an image pyramid.
Definition: Types.h:203
VPIStatus vpiPyramidCreate(int32_t width, int32_t height, VPIImageFormat fmt, int32_t numLevels, float scale, uint32_t flags, VPIPyramid *pyr)
Create an empty image pyramid instance with the specified flags.
void vpiPyramidDestroy(VPIPyramid pyr)
Destroy an image pyramid instance as well as all resources it owns.
struct VPIStreamImpl * VPIStream
A handle to a stream.
Definition: Types.h:191
VPIStatus vpiStreamSync(VPIStream stream)
Blocks the calling thread until all submitted commands in this stream queue are done (queue is empty)...
VPIBackend
VPI Backend types.
Definition: Types.h:90
void vpiStreamDestroy(VPIStream stream)
Destroy a stream instance and deallocate all HW resources.
VPIStatus vpiStreamCreate(uint32_t flags, VPIStream *stream)
Create a stream instance.
@ VPI_BACKEND_CUDA
CUDA backend.
Definition: Types.h:92
@ VPI_BACKEND_PVA
PVA backend.
Definition: Types.h:93
@ VPI_BACKEND_CPU
CPU backend.
Definition: Types.h:91
@ VPI_BORDER_ZERO
All pixels outside the image are considered to be zero.
Definition: Types.h:219