rocJPEG API Tracing (#73)
* rocDecode API Tracing support * Test bin file added to rocdecode. Need to add validate python methods * Added option to not make rocDecode tests * Added rocdecode and rocprofv3 tests * Added csv test * Address PR comments. Changed tests to use built-in rocstreambit decoder to remove ffmpeg dependancy. Changed cmake option to disbale tests rather than not build them. Tests work locally, but will fail until rocDecode is built with tracing enabled on CI * Add option to avoid building rocdecode tests * Added option to avoid building rocdecode bin file * Support for rocJPEG API Trace * Added newline to rocjpeg_version.h * json-tool code added, initial test/bin commit * Formatting * Resolved rocjpeg bin test compilation errors * Tests implemented. Perfetto module currently resulting in errors, so need to retest whenever it is fixed * Formatting and compilation errors * Minor fixes * Copyright year update and minor fixes * Doc update fix * Added rocjpeg csv file in data * Addresses review comments: Updated fixed Findroc.. and uses root directory as a hint, fixed documentation error, changed tables to use _CORE, minor style fixes * Added rocdecode and rocjpeg to CI * Removed rocdecode and rocjpeg from CI and added back build tests option * Updated Cmake Files * Added rocDecode and rocJPEG to CI * Remove cmake line added in error * Temporarily modified tests to pass if rocdecode or rocjpeg tracing are not supported for CI, cmake changes * Added find_package for test * Added back use of system rocDecode and rocJPEG, modifies system files to include prefix path * Updated no-link to include INCLUDE_DIR/roc(decode|jpeg), added comments for tests * Resolve merge conflicts and formatting * Added regex find and replace instead of include for CI * VAAPI package causing errors on Vega20 * Removed system rocjpeg and rocdecode use temporarily until cmake issues resolved * Removed workflows regex * Formatting and minor test modification * Modified test for vega20 * Update rocDecode and rocJPEG cmake and tests * Changelog * Fix merge conflict * Added back if-statements around add-tests since cmake-generator-expressions are resulting in errors when the packages are missing * Removed if found statements, replaced with TARGET:EXISTS * Skip json file for rocjpeg and rocdecode tests if not supported * Add os import --------- Co-authored-by: Kandula, Venkateshwar reddy <Venkateshwarreddy.Kandula@amd.com> Co-authored-by: Jonathan R. Madsen <jonathanrmadsen@gmail.com>
This commit is contained in:
@@ -68,10 +68,9 @@ add_subdirectory(thread-trace)
|
||||
add_subdirectory(pc_sampling)
|
||||
add_subdirectory(hip-graph-tracing)
|
||||
add_subdirectory(counter-collection)
|
||||
add_subdirectory(rocdecode)
|
||||
add_subdirectory(rocjpeg)
|
||||
add_subdirectory(conversion-script)
|
||||
if(ROCPROFILER_BUILD_ROCDECODE_TESTS)
|
||||
add_subdirectory(rocdecode)
|
||||
endif()
|
||||
|
||||
if(ROCPROFILER_BUILD_OPENMP_TESTS)
|
||||
add_subdirectory(openmp-tools)
|
||||
|
||||
@@ -9,6 +9,10 @@ set(CMAKE_BUILD_RPATH
|
||||
"\$ORIGIN:\$ORIGIN/../lib:$<TARGET_FILE_DIR:rocprofiler-sdk-roctx::rocprofiler-sdk-roctx-shared-library>"
|
||||
)
|
||||
|
||||
# Find rocDecode and rocJPEG packages for testing
|
||||
find_package(rocDecode)
|
||||
find_package(rocJPEG)
|
||||
|
||||
# applications used by integration tests which DO link to rocprofiler-sdk-roctx
|
||||
add_subdirectory(reproducible-runtime)
|
||||
add_subdirectory(transpose)
|
||||
@@ -29,7 +33,10 @@ add_subdirectory(hsa-queue-dependency)
|
||||
add_subdirectory(hip-graph)
|
||||
add_subdirectory(hsa-memory-allocation)
|
||||
add_subdirectory(pc-sampling)
|
||||
if(ROCPROFILER_BUILD_ROCDECODE_TESTS)
|
||||
if(rocDecode_FOUND AND rocDecode_VERSION VERSION_GREATER 0.8.0)
|
||||
add_subdirectory(rocdecode)
|
||||
endif()
|
||||
if(rocJPEG_FOUND AND rocJPEG_VERSION VERSION_GREATER 0.6.0)
|
||||
add_subdirectory(rocjpeg)
|
||||
endif()
|
||||
add_subdirectory(hsa-code-object)
|
||||
|
||||
@@ -33,11 +33,12 @@ set(CMAKE_HIP_EXTENSIONS OFF)
|
||||
set(CMAKE_HIP_STANDARD_REQUIRED ON)
|
||||
|
||||
set_source_files_properties(rocdecode.cpp roc_video_dec.cpp PROPERTIES LANGUAGE HIP)
|
||||
add_executable(rocdecode)
|
||||
target_sources(rocdecode PRIVATE rocdecode.cpp roc_video_dec.cpp)
|
||||
add_executable(rocdecode-demo)
|
||||
target_sources(rocdecode-demo PRIVATE rocdecode.cpp roc_video_dec.cpp)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(rocDecode REQUIRED)
|
||||
target_link_libraries(
|
||||
rocdecode PRIVATE rocprofiler-sdk::tests-build-flags Threads::Threads hsa-runtime64
|
||||
rocprofiler-sdk::tests-common-library rocDecode::rocDecode)
|
||||
rocdecode-demo
|
||||
PRIVATE rocprofiler-sdk::tests-build-flags Threads::Threads hsa-runtime64
|
||||
rocprofiler-sdk::tests-common-library rocDecode::rocDecode)
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
cmake_minimum_required(VERSION 3.21.0 FATAL_ERROR)
|
||||
|
||||
if(NOT CMAKE_HIP_COMPILER)
|
||||
find_program(
|
||||
amdclangpp_EXECUTABLE
|
||||
NAMES amdclang++
|
||||
HINTS ${ROCM_PATH} ENV ROCM_PATH /opt/rocm
|
||||
PATHS ${ROCM_PATH} ENV ROCM_PATH /opt/rocm
|
||||
PATH_SUFFIXES bin llvm/bin NO_CACHE)
|
||||
mark_as_advanced(amdclangpp_EXECUTABLE)
|
||||
|
||||
if(amdclangpp_EXECUTABLE)
|
||||
set(CMAKE_HIP_COMPILER "${amdclangpp_EXECUTABLE}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
project(rocprofiler-tool-test-app-rocjpeg LANGUAGES CXX HIP)
|
||||
|
||||
foreach(_TYPE DEBUG MINSIZEREL RELEASE RELWITHDEBINFO)
|
||||
if("${CMAKE_HIP_FLAGS_${_TYPE}}" STREQUAL "")
|
||||
set(CMAKE_HIP_FLAGS_${_TYPE} "${CMAKE_CXX_FLAGS_${_TYPE}}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
find_path(
|
||||
ROCJPEG_SHARE_DIR
|
||||
NAMES images
|
||||
PATHS ${ROCM_PATH}/share/rocjpeg/)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_HIP_STANDARD 17)
|
||||
set(CMAKE_HIP_EXTENSIONS OFF)
|
||||
set(CMAKE_HIP_STANDARD_REQUIRED ON)
|
||||
|
||||
set_source_files_properties(rocjpeg.cpp PROPERTIES LANGUAGE HIP)
|
||||
add_executable(rocjpeg-demo)
|
||||
target_sources(rocjpeg-demo PRIVATE rocjpeg.cpp)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(rocJPEG REQUIRED)
|
||||
target_link_libraries(
|
||||
rocjpeg-demo
|
||||
PRIVATE Threads::Threads hsa-runtime64 rocprofiler-sdk::tests-common-library
|
||||
rocprofiler-sdk::tests-build-flags rocJPEG::rocJPEG)
|
||||
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <rocjpeg/rocjpeg.h>
|
||||
#include "rocjpeg_samples_utils.h"
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
int device_id = 0;
|
||||
bool save_images = false;
|
||||
uint8_t num_components;
|
||||
uint32_t widths[ROCJPEG_MAX_COMPONENT] = {};
|
||||
uint32_t heights[ROCJPEG_MAX_COMPONENT] = {};
|
||||
uint32_t channel_sizes[ROCJPEG_MAX_COMPONENT] = {};
|
||||
uint32_t prior_channel_sizes[ROCJPEG_MAX_COMPONENT] = {};
|
||||
uint32_t num_channels = 0;
|
||||
int total_images = 0;
|
||||
double time_per_image_all = 0;
|
||||
std::string chroma_sub_sampling = "";
|
||||
std::string input_path, output_file_path;
|
||||
std::vector<std::string> file_paths = {};
|
||||
bool is_dir = false;
|
||||
bool is_file = false;
|
||||
RocJpegChromaSubsampling subsampling;
|
||||
RocJpegBackend rocjpeg_backend = ROCJPEG_BACKEND_HARDWARE;
|
||||
RocJpegHandle rocjpeg_handle = nullptr;
|
||||
RocJpegStreamHandle rocjpeg_stream_handle = nullptr;
|
||||
RocJpegImage output_image = {};
|
||||
RocJpegDecodeParams decode_params = {};
|
||||
RocJpegUtils rocjpeg_utils;
|
||||
uint64_t num_bad_jpegs = 0;
|
||||
uint64_t num_jpegs_with_411_subsampling = 0;
|
||||
uint64_t num_jpegs_with_unknown_subsampling = 0;
|
||||
uint64_t num_jpegs_with_unsupported_resolution = 0;
|
||||
|
||||
RocJpegUtils::ParseCommandLine(input_path,
|
||||
output_file_path,
|
||||
save_images,
|
||||
device_id,
|
||||
rocjpeg_backend,
|
||||
decode_params,
|
||||
nullptr,
|
||||
nullptr,
|
||||
argc,
|
||||
argv);
|
||||
|
||||
bool is_roi_valid = false;
|
||||
uint32_t roi_width;
|
||||
uint32_t roi_height;
|
||||
roi_width = decode_params.crop_rectangle.right - decode_params.crop_rectangle.left;
|
||||
roi_height = decode_params.crop_rectangle.bottom - decode_params.crop_rectangle.top;
|
||||
|
||||
if(!RocJpegUtils::GetFilePaths(input_path, file_paths, is_dir, is_file))
|
||||
{
|
||||
std::cerr << "ERROR: Failed to get input file paths!" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if(!RocJpegUtils::InitHipDevice(device_id))
|
||||
{
|
||||
std::cerr << "ERROR: Failed to initialize HIP!" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// CHECK_ROCJPEG(rocJpegCreate(rocjpeg_backend, device_id, &rocjpeg_handle));
|
||||
if(rocJpegCreate(rocjpeg_backend, device_id, &rocjpeg_handle) != ROCJPEG_STATUS_SUCCESS)
|
||||
{
|
||||
std::cerr << "rocJPEG tests not supported" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
CHECK_ROCJPEG(rocJpegStreamCreate(&rocjpeg_stream_handle));
|
||||
std::vector<char> file_data;
|
||||
for(auto file_path : file_paths)
|
||||
{
|
||||
std::string base_file_name = file_path.substr(file_path.find_last_of("/\\") + 1);
|
||||
int image_count = 0;
|
||||
|
||||
// Read an image from disk.
|
||||
std::ifstream input(file_path.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
|
||||
if(!(input.is_open()))
|
||||
{
|
||||
std::cerr << "ERROR: Cannot open image: " << file_path << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
// Get the size
|
||||
std::streamsize file_size = input.tellg();
|
||||
input.seekg(0, std::ios::beg);
|
||||
// resize if buffer is too small
|
||||
if(file_data.size() < static_cast<size_t>(file_size))
|
||||
{
|
||||
file_data.resize(file_size);
|
||||
}
|
||||
if(!input.read(file_data.data(), file_size))
|
||||
{
|
||||
std::cerr << "ERROR: Cannot read from file: " << file_path << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
RocJpegStatus rocjpeg_status = rocJpegStreamParse(
|
||||
reinterpret_cast<uint8_t*>(file_data.data()), file_size, rocjpeg_stream_handle);
|
||||
if(rocjpeg_status != ROCJPEG_STATUS_SUCCESS)
|
||||
{
|
||||
if(is_dir)
|
||||
{
|
||||
num_bad_jpegs++;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: Failed to parse the input jpeg stream with "
|
||||
<< rocJpegGetErrorName(rocjpeg_status) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_ROCJPEG(rocJpegGetImageInfo(
|
||||
rocjpeg_handle, rocjpeg_stream_handle, &num_components, &subsampling, widths, heights));
|
||||
|
||||
if(roi_width > 0 && roi_height > 0 && roi_width <= widths[0] && roi_height <= heights[0])
|
||||
{
|
||||
is_roi_valid = true;
|
||||
}
|
||||
rocjpeg_utils.GetChromaSubsamplingStr(subsampling, chroma_sub_sampling);
|
||||
if(widths[0] < 64 || heights[0] < 64)
|
||||
{
|
||||
std::cerr << "The image resolution is not supported by VCN Hardware" << std::endl;
|
||||
if(is_dir)
|
||||
{
|
||||
num_jpegs_with_unsupported_resolution++;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if(subsampling == ROCJPEG_CSS_411 || subsampling == ROCJPEG_CSS_UNKNOWN)
|
||||
{
|
||||
std::cerr << "The chroma sub-sampling is not supported by VCN Hardware" << std::endl;
|
||||
if(is_dir)
|
||||
{
|
||||
if(subsampling == ROCJPEG_CSS_411) num_jpegs_with_411_subsampling++;
|
||||
if(subsampling == ROCJPEG_CSS_UNKNOWN) num_jpegs_with_unknown_subsampling++;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(rocjpeg_utils.GetChannelPitchAndSizes(decode_params,
|
||||
subsampling,
|
||||
widths,
|
||||
heights,
|
||||
num_channels,
|
||||
output_image,
|
||||
channel_sizes))
|
||||
{
|
||||
std::cerr << "ERROR: Failed to get the channel pitch and sizes" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// allocate memory for each channel and reuse them if the sizes remain unchanged for a new
|
||||
// image.
|
||||
for(uint32_t i = 0; i < num_channels; i++)
|
||||
{
|
||||
if(prior_channel_sizes[i] != channel_sizes[i])
|
||||
{
|
||||
if(output_image.channel[i] != nullptr)
|
||||
{
|
||||
CHECK_HIP(hipFree((void*) output_image.channel[i]));
|
||||
output_image.channel[i] = nullptr;
|
||||
}
|
||||
CHECK_HIP(hipMalloc(&output_image.channel[i], channel_sizes[i]));
|
||||
}
|
||||
}
|
||||
|
||||
if(is_roi_valid)
|
||||
{}
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
CHECK_ROCJPEG(
|
||||
rocJpegDecode(rocjpeg_handle, rocjpeg_stream_handle, &decode_params, &output_image));
|
||||
auto end_time = std::chrono::high_resolution_clock::now();
|
||||
double time_per_image_in_milli_sec =
|
||||
std::chrono::duration<double, std::milli>(end_time - start_time).count();
|
||||
image_count++;
|
||||
|
||||
if(save_images)
|
||||
{
|
||||
std::string image_save_path = output_file_path;
|
||||
// if ROI is present, need to pass roi_width and roi_height
|
||||
uint32_t width = is_roi_valid ? roi_width : widths[0];
|
||||
uint32_t height = is_roi_valid ? roi_height : heights[0];
|
||||
if(is_dir)
|
||||
{
|
||||
rocjpeg_utils.GetOutputFileExt(decode_params.output_format,
|
||||
base_file_name,
|
||||
width,
|
||||
height,
|
||||
subsampling,
|
||||
image_save_path);
|
||||
}
|
||||
rocjpeg_utils.SaveImage(image_save_path,
|
||||
&output_image,
|
||||
width,
|
||||
height,
|
||||
subsampling,
|
||||
decode_params.output_format);
|
||||
}
|
||||
|
||||
if(is_dir)
|
||||
{
|
||||
total_images += image_count;
|
||||
time_per_image_all += time_per_image_in_milli_sec;
|
||||
}
|
||||
for(int i = 0; i < ROCJPEG_MAX_COMPONENT; i++)
|
||||
{
|
||||
prior_channel_sizes[i] = channel_sizes[i];
|
||||
}
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < num_channels; i++)
|
||||
{
|
||||
if(output_image.channel[i] != nullptr)
|
||||
{
|
||||
CHECK_HIP(hipFree((void*) output_image.channel[i]));
|
||||
output_image.channel[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if(is_dir)
|
||||
{
|
||||
time_per_image_all = time_per_image_all / total_images;
|
||||
if(num_bad_jpegs || num_jpegs_with_411_subsampling || num_jpegs_with_unknown_subsampling ||
|
||||
num_jpegs_with_unsupported_resolution)
|
||||
{
|
||||
if(num_bad_jpegs)
|
||||
{
|
||||
std::cout << " ,total images that cannot be parsed: " << num_bad_jpegs;
|
||||
}
|
||||
if(num_jpegs_with_411_subsampling)
|
||||
{
|
||||
std::cout << " ,total images with YUV 4:1:1 chroam subsampling: "
|
||||
<< num_jpegs_with_411_subsampling;
|
||||
}
|
||||
if(num_jpegs_with_unknown_subsampling)
|
||||
{
|
||||
std::cout << " ,total images with unknwon chroam subsampling: "
|
||||
<< num_jpegs_with_unknown_subsampling;
|
||||
}
|
||||
if(num_jpegs_with_unsupported_resolution)
|
||||
{
|
||||
std::cout << " ,total images with unsupported_resolution: "
|
||||
<< num_jpegs_with_unsupported_resolution;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_ROCJPEG(rocJpegDestroy(rocjpeg_handle));
|
||||
CHECK_ROCJPEG(rocJpegStreamDestroy(rocjpeg_stream_handle));
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,875 @@
|
||||
/*
|
||||
Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
#ifndef ROC_JPEG_SAMPLES_COMMON
|
||||
#define ROC_JPEG_SAMPLES_COMMON
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <condition_variable>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#if __cplusplus >= 201703L && __has_include(<filesystem>)
|
||||
# include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
#else
|
||||
# include <experimental/filesystem>
|
||||
namespace fs = std::experimental::filesystem;
|
||||
#endif
|
||||
#include <rocjpeg/rocjpeg.h>
|
||||
#include <chrono>
|
||||
|
||||
#define CHECK_ROCJPEG(call) \
|
||||
{ \
|
||||
RocJpegStatus _rocjpeg_status = (call); \
|
||||
if(_rocjpeg_status != ROCJPEG_STATUS_SUCCESS) \
|
||||
{ \
|
||||
std::cerr << #call << " returned " << rocJpegGetErrorName(_rocjpeg_status) << " at " \
|
||||
<< __FILE__ << ":" << __LINE__ << std::endl; \
|
||||
exit(1); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CHECK_HIP(call) \
|
||||
{ \
|
||||
hipError_t _hip_status = (call); \
|
||||
if(_hip_status != hipSuccess) \
|
||||
{ \
|
||||
std::cout << "rocJPEG failure: '#" << _hip_status << "' at " << __FILE__ << ":" \
|
||||
<< __LINE__ << std::endl; \
|
||||
exit(1); \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* @class RocJpegUtils
|
||||
* @brief Utility class for rocJPEG samples.
|
||||
*
|
||||
* This class provides utility functions for rocJPEG samples, such as parsing command line
|
||||
* arguments, getting file paths, initializing HIP device, getting chroma subsampling string,
|
||||
* getting channel pitch and sizes, getting output file extension, and saving images.
|
||||
*/
|
||||
class RocJpegUtils
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Parses the command line arguments.
|
||||
*
|
||||
* This function parses the command line arguments and sets the corresponding variables.
|
||||
*
|
||||
* @param input_path The input path.
|
||||
* @param output_file_path The output file path.
|
||||
* @param save_images Flag indicating whether to save images.
|
||||
* @param device_id The device ID.
|
||||
* @param rocjpeg_backend The rocJPEG backend.
|
||||
* @param decode_params The rocJPEG decode parameters.
|
||||
* @param num_threads The number of threads.
|
||||
* @param crop The crop rectangle.
|
||||
* @param argc The number of command line arguments.
|
||||
* @param argv The command line arguments.
|
||||
*/
|
||||
static void ParseCommandLine(std::string& input_path,
|
||||
std::string& output_file_path,
|
||||
bool& save_images,
|
||||
int& device_id,
|
||||
RocJpegBackend& rocjpeg_backend,
|
||||
RocJpegDecodeParams& decode_params,
|
||||
int* num_threads,
|
||||
int* batch_size,
|
||||
int argc,
|
||||
char* argv[])
|
||||
{
|
||||
if(argc <= 1)
|
||||
{
|
||||
ShowHelpAndExit("", num_threads != nullptr, batch_size != nullptr);
|
||||
}
|
||||
for(int i = 1; i < argc; i++)
|
||||
{
|
||||
if(!strcmp(argv[i], "-h"))
|
||||
{
|
||||
ShowHelpAndExit("", num_threads != nullptr, batch_size != nullptr);
|
||||
}
|
||||
if(!strcmp(argv[i], "-i"))
|
||||
{
|
||||
if(++i == argc)
|
||||
{
|
||||
ShowHelpAndExit("-i", num_threads != nullptr, batch_size != nullptr);
|
||||
}
|
||||
input_path = argv[i];
|
||||
continue;
|
||||
}
|
||||
if(!strcmp(argv[i], "-o"))
|
||||
{
|
||||
if(++i == argc)
|
||||
{
|
||||
ShowHelpAndExit("-o", num_threads != nullptr, batch_size != nullptr);
|
||||
}
|
||||
output_file_path = argv[i];
|
||||
save_images = true;
|
||||
continue;
|
||||
}
|
||||
if(!strcmp(argv[i], "-d"))
|
||||
{
|
||||
if(++i == argc)
|
||||
{
|
||||
ShowHelpAndExit("-d", num_threads != nullptr, batch_size != nullptr);
|
||||
}
|
||||
device_id = atoi(argv[i]);
|
||||
continue;
|
||||
}
|
||||
if(!strcmp(argv[i], "-be"))
|
||||
{
|
||||
if(++i == argc)
|
||||
{
|
||||
ShowHelpAndExit("-be", num_threads != nullptr, batch_size != nullptr);
|
||||
}
|
||||
rocjpeg_backend = static_cast<RocJpegBackend>(atoi(argv[i]));
|
||||
continue;
|
||||
}
|
||||
if(!strcmp(argv[i], "-fmt"))
|
||||
{
|
||||
if(++i == argc)
|
||||
{
|
||||
ShowHelpAndExit("-fmt", num_threads != nullptr, batch_size != nullptr);
|
||||
}
|
||||
std::string selected_output_format = argv[i];
|
||||
if(selected_output_format == "native")
|
||||
{
|
||||
decode_params.output_format = ROCJPEG_OUTPUT_NATIVE;
|
||||
}
|
||||
else if(selected_output_format == "yuv_planar")
|
||||
{
|
||||
decode_params.output_format = ROCJPEG_OUTPUT_YUV_PLANAR;
|
||||
}
|
||||
else if(selected_output_format == "y")
|
||||
{
|
||||
decode_params.output_format = ROCJPEG_OUTPUT_Y;
|
||||
}
|
||||
else if(selected_output_format == "rgb")
|
||||
{
|
||||
decode_params.output_format = ROCJPEG_OUTPUT_RGB;
|
||||
}
|
||||
else if(selected_output_format == "rgb_planar")
|
||||
{
|
||||
decode_params.output_format = ROCJPEG_OUTPUT_RGB_PLANAR;
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowHelpAndExit(argv[i], num_threads != nullptr);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(!strcmp(argv[i], "-t"))
|
||||
{
|
||||
if(++i == argc)
|
||||
{
|
||||
ShowHelpAndExit("-t", num_threads != nullptr, batch_size != nullptr);
|
||||
}
|
||||
if(num_threads != nullptr)
|
||||
{
|
||||
*num_threads = atoi(argv[i]);
|
||||
if(*num_threads <= 0 || *num_threads > 32)
|
||||
{
|
||||
ShowHelpAndExit(argv[i], num_threads != nullptr, batch_size != nullptr);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(!strcmp(argv[i], "-b"))
|
||||
{
|
||||
if(++i == argc)
|
||||
{
|
||||
ShowHelpAndExit("-b", num_threads != nullptr, batch_size != nullptr);
|
||||
}
|
||||
if(batch_size != nullptr) *batch_size = atoi(argv[i]);
|
||||
continue;
|
||||
}
|
||||
if(!strcmp(argv[i], "-crop"))
|
||||
{
|
||||
if(++i == argc || 4 != sscanf(argv[i],
|
||||
"%hd,%hd,%hd,%hd",
|
||||
&decode_params.crop_rectangle.left,
|
||||
&decode_params.crop_rectangle.top,
|
||||
&decode_params.crop_rectangle.right,
|
||||
&decode_params.crop_rectangle.bottom))
|
||||
{
|
||||
ShowHelpAndExit("-crop");
|
||||
}
|
||||
if((&decode_params.crop_rectangle.right - &decode_params.crop_rectangle.left) % 2 ==
|
||||
1 ||
|
||||
(&decode_params.crop_rectangle.bottom - &decode_params.crop_rectangle.top) % 2 ==
|
||||
1)
|
||||
{
|
||||
std::cout << "output crop rectangle must have width and height of even numbers"
|
||||
<< std::endl;
|
||||
exit(1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
ShowHelpAndExit(argv[i], num_threads != nullptr, batch_size != nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a file is a JPEG file.
|
||||
*
|
||||
* @param filePath The path to the file to be checked.
|
||||
* @return True if the file is a JPEG file, false otherwise.
|
||||
*/
|
||||
static bool IsJPEG(const std::string& filePath)
|
||||
{
|
||||
std::ifstream file(filePath, std::ios::binary);
|
||||
if(!file.is_open())
|
||||
{
|
||||
std::cerr << "Failed to open file: " << filePath << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char buffer[2];
|
||||
file.read(reinterpret_cast<char*>(buffer), 2);
|
||||
file.close();
|
||||
|
||||
// The first two bytes of every JPEG stream are always 0xFFD8, which represents the Start of
|
||||
// Image (SOI) marker.
|
||||
return buffer[0] == 0xFF && buffer[1] == 0xD8;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the file paths.
|
||||
*
|
||||
* This function gets the file paths based on the input path and sets the corresponding
|
||||
* variables.
|
||||
*
|
||||
* @param input_path The input path.
|
||||
* @param file_paths The vector to store the file paths.
|
||||
* @param is_dir Flag indicating whether the input path is a directory.
|
||||
* @param is_file Flag indicating whether the input path is a file.
|
||||
* @return True if successful, false otherwise.
|
||||
*/
|
||||
static bool GetFilePaths(std::string& input_path,
|
||||
std::vector<std::string>& file_paths,
|
||||
bool& is_dir,
|
||||
bool& is_file)
|
||||
{
|
||||
if(!fs::exists(input_path))
|
||||
{
|
||||
std::cerr << "ERROR: the input path does not exist!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
is_dir = fs::is_directory(input_path);
|
||||
is_file = fs::is_regular_file(input_path);
|
||||
if(is_dir)
|
||||
{
|
||||
for(const auto& entry : fs::recursive_directory_iterator(input_path))
|
||||
{
|
||||
if(fs::is_regular_file(entry) && IsJPEG(entry.path().string()))
|
||||
{
|
||||
file_paths.push_back(entry.path().string());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(is_file && IsJPEG(input_path))
|
||||
{
|
||||
file_paths.push_back(input_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: the input path does not contain JPEG files!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes the HIP device.
|
||||
*
|
||||
* This function initializes the HIP device with the specified device ID.
|
||||
*
|
||||
* @param device_id The device ID.
|
||||
* @return True if successful, false otherwise.
|
||||
*/
|
||||
static bool InitHipDevice(int device_id)
|
||||
{
|
||||
int num_devices;
|
||||
hipDeviceProp_t hip_dev_prop;
|
||||
CHECK_HIP(hipGetDeviceCount(&num_devices));
|
||||
if(num_devices < 1)
|
||||
{
|
||||
std::cerr << "ERROR: didn't find any GPU!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
if(device_id >= num_devices)
|
||||
{
|
||||
std::cerr << "ERROR: the requested device_id is not found!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
CHECK_HIP(hipSetDevice(device_id));
|
||||
CHECK_HIP(hipGetDeviceProperties(&hip_dev_prop, device_id));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the chroma subsampling string.
|
||||
*
|
||||
* This function gets the chroma subsampling string based on the specified subsampling value.
|
||||
*
|
||||
* @param subsampling The chroma subsampling value.
|
||||
* @param chroma_sub_sampling The string to store the chroma subsampling.
|
||||
*/
|
||||
void GetChromaSubsamplingStr(RocJpegChromaSubsampling subsampling,
|
||||
std::string& chroma_sub_sampling)
|
||||
{
|
||||
switch(subsampling)
|
||||
{
|
||||
case ROCJPEG_CSS_444: chroma_sub_sampling = "YUV 4:4:4"; break;
|
||||
case ROCJPEG_CSS_440: chroma_sub_sampling = "YUV 4:4:0"; break;
|
||||
case ROCJPEG_CSS_422: chroma_sub_sampling = "YUV 4:2:2"; break;
|
||||
case ROCJPEG_CSS_420: chroma_sub_sampling = "YUV 4:2:0"; break;
|
||||
case ROCJPEG_CSS_411: chroma_sub_sampling = "YUV 4:1:1"; break;
|
||||
case ROCJPEG_CSS_400: chroma_sub_sampling = "YUV 4:0:0"; break;
|
||||
case ROCJPEG_CSS_UNKNOWN: chroma_sub_sampling = "UNKNOWN"; break;
|
||||
default: chroma_sub_sampling = ""; break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the channel pitch and sizes.
|
||||
*
|
||||
* This function gets the channel pitch and sizes based on the specified output format, chroma
|
||||
* subsampling, output image, and channel sizes.
|
||||
*
|
||||
* @param decode_params The decode parameters that specify the output format and crop rectangle.
|
||||
* @param subsampling The chroma subsampling.
|
||||
* @param widths The array to store the channel widths.
|
||||
* @param heights The array to store the channel heights.
|
||||
* @param num_channels The number of channels.
|
||||
* @param output_image The output image.
|
||||
* @param channel_sizes The array to store the channel sizes.
|
||||
* @return The channel pitch.
|
||||
*/
|
||||
int GetChannelPitchAndSizes(RocJpegDecodeParams decode_params,
|
||||
RocJpegChromaSubsampling subsampling,
|
||||
uint32_t* widths,
|
||||
uint32_t* heights,
|
||||
uint32_t& num_channels,
|
||||
RocJpegImage& output_image,
|
||||
uint32_t* channel_sizes)
|
||||
{
|
||||
bool is_roi_valid = false;
|
||||
uint32_t roi_width;
|
||||
uint32_t roi_height;
|
||||
roi_width = decode_params.crop_rectangle.right - decode_params.crop_rectangle.left;
|
||||
roi_height = decode_params.crop_rectangle.bottom - decode_params.crop_rectangle.top;
|
||||
if(roi_width > 0 && roi_height > 0 && roi_width <= widths[0] && roi_height <= heights[0])
|
||||
{
|
||||
is_roi_valid = true;
|
||||
}
|
||||
switch(decode_params.output_format)
|
||||
{
|
||||
case ROCJPEG_OUTPUT_NATIVE:
|
||||
switch(subsampling)
|
||||
{
|
||||
case ROCJPEG_CSS_444:
|
||||
num_channels = 3;
|
||||
output_image.pitch[2] = output_image.pitch[1] = output_image.pitch[0] =
|
||||
is_roi_valid ? roi_width : widths[0];
|
||||
channel_sizes[2] = channel_sizes[1] = channel_sizes[0] =
|
||||
align(output_image.pitch[0] * (is_roi_valid ? roi_height : heights[0]),
|
||||
mem_alignment);
|
||||
break;
|
||||
case ROCJPEG_CSS_440:
|
||||
num_channels = 3;
|
||||
output_image.pitch[2] = output_image.pitch[1] = output_image.pitch[0] =
|
||||
is_roi_valid ? roi_width : widths[0];
|
||||
channel_sizes[0] =
|
||||
align(output_image.pitch[0] * (is_roi_valid ? roi_height : heights[0]),
|
||||
mem_alignment);
|
||||
channel_sizes[2] = channel_sizes[1] = align(
|
||||
output_image.pitch[0] * ((is_roi_valid ? roi_height : heights[0]) >> 1),
|
||||
mem_alignment);
|
||||
break;
|
||||
case ROCJPEG_CSS_422:
|
||||
num_channels = 1;
|
||||
output_image.pitch[0] = (is_roi_valid ? roi_width : widths[0]) * 2;
|
||||
channel_sizes[0] =
|
||||
align(output_image.pitch[0] * (is_roi_valid ? roi_height : heights[0]),
|
||||
mem_alignment);
|
||||
break;
|
||||
case ROCJPEG_CSS_420:
|
||||
num_channels = 2;
|
||||
output_image.pitch[1] = output_image.pitch[0] =
|
||||
is_roi_valid ? roi_width : widths[0];
|
||||
channel_sizes[0] =
|
||||
align(output_image.pitch[0] * (is_roi_valid ? roi_height : heights[0]),
|
||||
mem_alignment);
|
||||
channel_sizes[1] = align(
|
||||
output_image.pitch[1] * ((is_roi_valid ? roi_height : heights[0]) >> 1),
|
||||
mem_alignment);
|
||||
break;
|
||||
case ROCJPEG_CSS_400:
|
||||
num_channels = 1;
|
||||
output_image.pitch[0] = is_roi_valid ? roi_width : widths[0];
|
||||
channel_sizes[0] =
|
||||
align(output_image.pitch[0] * (is_roi_valid ? roi_height : heights[0]),
|
||||
mem_alignment);
|
||||
break;
|
||||
default:
|
||||
std::cout << "Unknown chroma subsampling!" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
break;
|
||||
case ROCJPEG_OUTPUT_YUV_PLANAR:
|
||||
if(subsampling == ROCJPEG_CSS_400)
|
||||
{
|
||||
num_channels = 1;
|
||||
output_image.pitch[0] = is_roi_valid ? roi_width : widths[0];
|
||||
channel_sizes[0] =
|
||||
align(output_image.pitch[0] * (is_roi_valid ? roi_height : heights[0]),
|
||||
mem_alignment);
|
||||
}
|
||||
else
|
||||
{
|
||||
num_channels = 3;
|
||||
output_image.pitch[0] = is_roi_valid ? roi_width : widths[0];
|
||||
output_image.pitch[1] = is_roi_valid ? roi_width : widths[1];
|
||||
output_image.pitch[2] = is_roi_valid ? roi_width : widths[2];
|
||||
channel_sizes[0] =
|
||||
align(output_image.pitch[0] * (is_roi_valid ? roi_height : heights[0]),
|
||||
mem_alignment);
|
||||
channel_sizes[1] =
|
||||
align(output_image.pitch[1] * (is_roi_valid ? roi_height : heights[1]),
|
||||
mem_alignment);
|
||||
channel_sizes[2] =
|
||||
align(output_image.pitch[2] * (is_roi_valid ? roi_height : heights[2]),
|
||||
mem_alignment);
|
||||
}
|
||||
break;
|
||||
case ROCJPEG_OUTPUT_Y:
|
||||
num_channels = 1;
|
||||
output_image.pitch[0] = is_roi_valid ? roi_width : widths[0];
|
||||
channel_sizes[0] =
|
||||
align(output_image.pitch[0] * (is_roi_valid ? roi_height : heights[0]),
|
||||
mem_alignment);
|
||||
break;
|
||||
case ROCJPEG_OUTPUT_RGB:
|
||||
num_channels = 1;
|
||||
output_image.pitch[0] = (is_roi_valid ? roi_width : widths[0]) * 3;
|
||||
channel_sizes[0] =
|
||||
align(output_image.pitch[0] * (is_roi_valid ? roi_height : heights[0]),
|
||||
mem_alignment);
|
||||
break;
|
||||
case ROCJPEG_OUTPUT_RGB_PLANAR:
|
||||
num_channels = 3;
|
||||
output_image.pitch[2] = output_image.pitch[1] = output_image.pitch[0] =
|
||||
is_roi_valid ? roi_width : widths[0];
|
||||
channel_sizes[2] = channel_sizes[1] = channel_sizes[0] =
|
||||
align(output_image.pitch[0] * (is_roi_valid ? roi_height : heights[0]),
|
||||
mem_alignment);
|
||||
break;
|
||||
default: std::cout << "Unknown output format!" << std::endl; return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the output file extension.
|
||||
*
|
||||
* This function gets the output file extension based on the specified output format, base file
|
||||
* name, image width, image height, and file name for saving.
|
||||
*
|
||||
* @param output_format The output format.
|
||||
* @param base_file_name The base file name.
|
||||
* @param image_width The image width.
|
||||
* @param image_height The image height.
|
||||
* @param file_name_for_saving The string to store the file name for saving.
|
||||
*/
|
||||
void GetOutputFileExt(RocJpegOutputFormat output_format,
|
||||
std::string& base_file_name,
|
||||
uint32_t image_width,
|
||||
uint32_t image_height,
|
||||
RocJpegChromaSubsampling subsampling,
|
||||
std::string& file_name_for_saving)
|
||||
{
|
||||
std::string file_extension;
|
||||
std::string::size_type const p(base_file_name.find_last_of('.'));
|
||||
std::string file_name_no_ext = base_file_name.substr(0, p);
|
||||
std::string format_description = "";
|
||||
switch(output_format)
|
||||
{
|
||||
case ROCJPEG_OUTPUT_NATIVE:
|
||||
file_extension = "yuv";
|
||||
switch(subsampling)
|
||||
{
|
||||
case ROCJPEG_CSS_444: format_description = "444"; break;
|
||||
case ROCJPEG_CSS_440: format_description = "440"; break;
|
||||
case ROCJPEG_CSS_422: format_description = "422_yuyv"; break;
|
||||
case ROCJPEG_CSS_420: format_description = "nv12"; break;
|
||||
case ROCJPEG_CSS_400: format_description = "400"; break;
|
||||
default: std::cout << "Unknown chroma subsampling!" << std::endl; return;
|
||||
}
|
||||
break;
|
||||
case ROCJPEG_OUTPUT_YUV_PLANAR:
|
||||
file_extension = "yuv";
|
||||
format_description = "planar";
|
||||
break;
|
||||
case ROCJPEG_OUTPUT_Y:
|
||||
file_extension = "yuv";
|
||||
format_description = "400";
|
||||
break;
|
||||
case ROCJPEG_OUTPUT_RGB:
|
||||
file_extension = "rgb";
|
||||
format_description = "packed";
|
||||
break;
|
||||
case ROCJPEG_OUTPUT_RGB_PLANAR:
|
||||
file_extension = "rgb";
|
||||
format_description = "planar";
|
||||
break;
|
||||
default: file_extension = ""; break;
|
||||
}
|
||||
file_name_for_saving += "//" + file_name_no_ext + "_" + std::to_string(image_width) + "x" +
|
||||
std::to_string(image_height) + "_" + format_description + "." +
|
||||
file_extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Saves the image.
|
||||
*
|
||||
* This function saves the image to the specified output file name based on the output image,
|
||||
* image width, image height, chroma subsampling, and output format.
|
||||
*
|
||||
* @param output_file_name The output file name.
|
||||
* @param output_image The output image.
|
||||
* @param img_width The image width.
|
||||
* @param img_height The image height.
|
||||
* @param subsampling The chroma subsampling.
|
||||
* @param output_format The output format.
|
||||
*/
|
||||
void SaveImage(std::string output_file_name,
|
||||
RocJpegImage* output_image,
|
||||
uint32_t img_width,
|
||||
uint32_t img_height,
|
||||
RocJpegChromaSubsampling subsampling,
|
||||
RocJpegOutputFormat output_format)
|
||||
{
|
||||
uint8_t* hst_ptr = nullptr;
|
||||
FILE* fp;
|
||||
|
||||
if(output_image == nullptr || output_image->channel[0] == nullptr ||
|
||||
output_image->pitch[0] == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t widths[ROCJPEG_MAX_COMPONENT] = {};
|
||||
uint32_t heights[ROCJPEG_MAX_COMPONENT] = {};
|
||||
|
||||
switch(output_format)
|
||||
{
|
||||
case ROCJPEG_OUTPUT_NATIVE:
|
||||
switch(subsampling)
|
||||
{
|
||||
case ROCJPEG_CSS_444:
|
||||
widths[2] = widths[1] = widths[0] = img_width;
|
||||
heights[2] = heights[1] = heights[0] = img_height;
|
||||
break;
|
||||
case ROCJPEG_CSS_440:
|
||||
widths[2] = widths[1] = widths[0] = img_width;
|
||||
heights[0] = img_height;
|
||||
heights[2] = heights[1] = img_height >> 1;
|
||||
break;
|
||||
case ROCJPEG_CSS_422:
|
||||
widths[0] = img_width * 2;
|
||||
heights[0] = img_height;
|
||||
break;
|
||||
case ROCJPEG_CSS_420:
|
||||
widths[1] = widths[0] = img_width;
|
||||
heights[0] = img_height;
|
||||
heights[1] = img_height >> 1;
|
||||
break;
|
||||
case ROCJPEG_CSS_400:
|
||||
widths[0] = img_width;
|
||||
heights[0] = img_height;
|
||||
break;
|
||||
default: std::cout << "Unknown chroma subsampling!" << std::endl; return;
|
||||
}
|
||||
break;
|
||||
case ROCJPEG_OUTPUT_YUV_PLANAR:
|
||||
switch(subsampling)
|
||||
{
|
||||
case ROCJPEG_CSS_444:
|
||||
widths[2] = widths[1] = widths[0] = img_width;
|
||||
heights[2] = heights[1] = heights[0] = img_height;
|
||||
break;
|
||||
case ROCJPEG_CSS_440:
|
||||
widths[2] = widths[1] = widths[0] = img_width;
|
||||
heights[0] = img_height;
|
||||
heights[2] = heights[1] = img_height >> 1;
|
||||
break;
|
||||
case ROCJPEG_CSS_422:
|
||||
widths[0] = img_width;
|
||||
widths[2] = widths[1] = widths[0] >> 1;
|
||||
heights[2] = heights[1] = heights[0] = img_height;
|
||||
break;
|
||||
case ROCJPEG_CSS_420:
|
||||
widths[0] = img_width;
|
||||
widths[2] = widths[1] = widths[0] >> 1;
|
||||
heights[0] = img_height;
|
||||
heights[2] = heights[1] = img_height >> 1;
|
||||
break;
|
||||
case ROCJPEG_CSS_400:
|
||||
widths[0] = img_width;
|
||||
heights[0] = img_height;
|
||||
break;
|
||||
default: std::cout << "Unknown chroma subsampling!" << std::endl; return;
|
||||
}
|
||||
break;
|
||||
case ROCJPEG_OUTPUT_Y:
|
||||
widths[0] = img_width;
|
||||
heights[0] = img_height;
|
||||
break;
|
||||
case ROCJPEG_OUTPUT_RGB:
|
||||
widths[0] = img_width * 3;
|
||||
heights[0] = img_height;
|
||||
break;
|
||||
case ROCJPEG_OUTPUT_RGB_PLANAR:
|
||||
widths[2] = widths[1] = widths[0] = img_width;
|
||||
heights[2] = heights[1] = heights[0] = img_height;
|
||||
break;
|
||||
default: std::cout << "Unknown output format!" << std::endl; return;
|
||||
}
|
||||
|
||||
uint32_t channel0_size = output_image->pitch[0] * heights[0];
|
||||
uint32_t channel1_size = output_image->pitch[1] * heights[1];
|
||||
uint32_t channel2_size = output_image->pitch[2] * heights[2];
|
||||
|
||||
uint32_t output_image_size = channel0_size + channel1_size + channel2_size;
|
||||
|
||||
if(hst_ptr == nullptr)
|
||||
{
|
||||
hst_ptr = new uint8_t[output_image_size];
|
||||
}
|
||||
|
||||
CHECK_HIP(hipMemcpyDtoH((void*) hst_ptr, output_image->channel[0], channel0_size));
|
||||
|
||||
uint8_t* tmp_hst_ptr = hst_ptr;
|
||||
fp = fopen(output_file_name.c_str(), "wb");
|
||||
if(fp)
|
||||
{
|
||||
// write channel0
|
||||
if(widths[0] == output_image->pitch[0])
|
||||
{
|
||||
fwrite(hst_ptr, 1, channel0_size, fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(uint32_t i = 0; i < heights[0]; i++)
|
||||
{
|
||||
fwrite(tmp_hst_ptr, 1, widths[0], fp);
|
||||
tmp_hst_ptr += output_image->pitch[0];
|
||||
}
|
||||
}
|
||||
// write channel1
|
||||
if(channel1_size != 0 && output_image->channel[1] != nullptr)
|
||||
{
|
||||
uint8_t* channel1_hst_ptr = hst_ptr + channel0_size;
|
||||
CHECK_HIP(hipMemcpyDtoH(
|
||||
(void*) channel1_hst_ptr, output_image->channel[1], channel1_size));
|
||||
if(widths[1] == output_image->pitch[1])
|
||||
{
|
||||
fwrite(channel1_hst_ptr, 1, channel1_size, fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(uint32_t i = 0; i < heights[1]; i++)
|
||||
{
|
||||
fwrite(channel1_hst_ptr, 1, widths[1], fp);
|
||||
channel1_hst_ptr += output_image->pitch[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
// write channel2
|
||||
if(channel2_size != 0 && output_image->channel[2] != nullptr)
|
||||
{
|
||||
uint8_t* channel2_hst_ptr = hst_ptr + channel0_size + channel1_size;
|
||||
CHECK_HIP(hipMemcpyDtoH(
|
||||
(void*) channel2_hst_ptr, output_image->channel[2], channel2_size));
|
||||
if(widths[2] == output_image->pitch[2])
|
||||
{
|
||||
fwrite(channel2_hst_ptr, 1, channel2_size, fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(uint32_t i = 0; i < heights[2]; i++)
|
||||
{
|
||||
fwrite(channel2_hst_ptr, 1, widths[2], fp);
|
||||
channel2_hst_ptr += output_image->pitch[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if(hst_ptr != nullptr)
|
||||
{
|
||||
delete[] hst_ptr;
|
||||
hst_ptr = nullptr;
|
||||
tmp_hst_ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static const int mem_alignment = 4 * 1024 * 1024;
|
||||
/**
|
||||
* @brief Shows the help message and exits.
|
||||
*
|
||||
* This function shows the help message and exits the program.
|
||||
*
|
||||
* @param option The option to display in the help message (optional).
|
||||
* @param show_threads Flag indicating whether to show the number of threads in the help
|
||||
* message.
|
||||
*/
|
||||
static void ShowHelpAndExit(const char* option = nullptr,
|
||||
bool show_threads = false,
|
||||
bool show_batch_size = false)
|
||||
{
|
||||
(void) option;
|
||||
std::cout
|
||||
<< "Options:\n"
|
||||
"-i [input path] - input path to a single JPEG image or a directory containing "
|
||||
"JPEG images - [required]\n"
|
||||
"-be [backend] - select rocJPEG backend (0 for hardware-accelerated JPEG "
|
||||
"decoding using VCN,\n"
|
||||
" 1 for hybrid JPEG decoding using CPU "
|
||||
"and GPU HIP kernels (currently not supported)) [optional - default: 0]\n"
|
||||
"-fmt [output format] - select rocJPEG output format for decoding, one of the "
|
||||
"[native, yuv_planar, y, rgb, rgb_planar] - [optional - default: native]\n"
|
||||
"-o [output path] - path to an output file or a path to an existing directory - "
|
||||
"write decoded images to a file or an existing directory based on selected output "
|
||||
"format - [optional]\n"
|
||||
"-crop [crop rectangle] - crop rectangle for output in a comma-separated format: "
|
||||
"left,top,right,bottom - [optional]\n"
|
||||
"-d [device id] - specify the GPU device id for the desired device (use 0 for "
|
||||
"the first device, 1 for the second device, and so on) [optional - default: 0]\n";
|
||||
if(show_threads)
|
||||
{
|
||||
std::cout << "-t [threads] - number of threads (<= 32) for parallel JPEG decoding "
|
||||
"- [optional - default: 1]\n";
|
||||
}
|
||||
if(show_batch_size)
|
||||
{
|
||||
std::cout << "-b [batch_size] - decode images from input by batches of a specified "
|
||||
"size - [optional - default: 1]\n";
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
/**
|
||||
* @brief Aligns a value to a specified alignment.
|
||||
*
|
||||
* This function takes a value and aligns it to the specified alignment. It returns the aligned
|
||||
* value.
|
||||
*
|
||||
* @param value The value to be aligned.
|
||||
* @param alignment The alignment value.
|
||||
* @return The aligned value.
|
||||
*/
|
||||
static inline int align(int value, int alignment)
|
||||
{
|
||||
return (value + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
};
|
||||
|
||||
class ThreadPool
|
||||
{
|
||||
public:
|
||||
ThreadPool(int nthreads)
|
||||
: shutdown_(false)
|
||||
{
|
||||
// Create the specified number of threads
|
||||
threads_.reserve(nthreads);
|
||||
for(int i = 0; i < nthreads; ++i)
|
||||
threads_.emplace_back(std::bind(&ThreadPool::ThreadEntry, this, i));
|
||||
}
|
||||
|
||||
~ThreadPool() {}
|
||||
|
||||
void JoinThreads()
|
||||
{
|
||||
{
|
||||
// Unblock any threads and tell them to stop
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
shutdown_ = true;
|
||||
cond_var_.notify_all();
|
||||
}
|
||||
|
||||
// Wait for all threads to stop
|
||||
for(auto& thread : threads_)
|
||||
thread.join();
|
||||
}
|
||||
|
||||
void ExecuteJob(std::function<void()> func)
|
||||
{
|
||||
// Place a job on the queue and unblock a thread
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
decode_jobs_queue_.emplace(std::move(func));
|
||||
cond_var_.notify_one();
|
||||
}
|
||||
|
||||
protected:
|
||||
void ThreadEntry(int i)
|
||||
{
|
||||
(void) i;
|
||||
std::function<void()> execute_decode_job;
|
||||
|
||||
while(true)
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
cond_var_.wait(lock, [&] { return shutdown_ || !decode_jobs_queue_.empty(); });
|
||||
if(decode_jobs_queue_.empty())
|
||||
{
|
||||
// No jobs to do; shutting down
|
||||
return;
|
||||
}
|
||||
|
||||
execute_decode_job = std::move(decode_jobs_queue_.front());
|
||||
decode_jobs_queue_.pop();
|
||||
}
|
||||
|
||||
// Execute the decode job without holding any locks
|
||||
execute_decode_job();
|
||||
}
|
||||
}
|
||||
|
||||
std::mutex mutex_;
|
||||
std::condition_variable cond_var_;
|
||||
bool shutdown_;
|
||||
std::queue<std::function<void()>> decode_jobs_queue_;
|
||||
std::vector<std::thread> threads_;
|
||||
};
|
||||
#endif // ROC_JPEG_SAMPLES_COMMON
|
||||
@@ -34,6 +34,7 @@ def test_perfetto_data(
|
||||
"memory_copy",
|
||||
"memory_allocation",
|
||||
"rocdecode_api",
|
||||
"rocjpeg_api",
|
||||
),
|
||||
):
|
||||
|
||||
@@ -45,6 +46,7 @@ def test_perfetto_data(
|
||||
"memory_copy": ("memory_copy", "memory_copy"),
|
||||
"memory_allocation": ("memory_allocation", "memory_allocation"),
|
||||
"rocdecode_api": ("rocdecode_api", "rocdecode_api"),
|
||||
"rocjpeg_api": ("rocjpeg_api", "rocjpeg_api"),
|
||||
}
|
||||
|
||||
# make sure they specified valid categories
|
||||
@@ -83,6 +85,7 @@ def test_otf2_data(
|
||||
"memory_copy": ("memory_copy", "memory_copy"),
|
||||
"memory_allocation": ("memory_allocation", "memory_allocation"),
|
||||
"rocdecode_api": ("rocdecode_api", "rocdecode_api"),
|
||||
"rocjpeg_api": ("rocjpeg_api", "rocjpeg_api"),
|
||||
}
|
||||
|
||||
# make sure they specified valid categories
|
||||
|
||||
@@ -9,6 +9,7 @@ project(
|
||||
VERSION 0.0.0)
|
||||
|
||||
find_package(rocprofiler-sdk REQUIRED)
|
||||
find_package(rocDecode)
|
||||
|
||||
if(ROCPROFILER_MEMCHECK_PRELOAD_ENV)
|
||||
set(PRELOAD_ENV
|
||||
@@ -18,14 +19,18 @@ else()
|
||||
endif()
|
||||
|
||||
set(ROCDECODE_VIDEO_FILE
|
||||
"${ROCM_PATH}/share/rocdecode/video/AMD_driving_virtual_20-H265.265")
|
||||
if(NOT EXISTS "${ROCDECODE_VIDEO_FILE}")
|
||||
"${rocDecode_ROOT_DIR}/share/rocdecode/video/AMD_driving_virtual_20-H265.265")
|
||||
if(TARGET rocdecode-demo AND NOT EXISTS "${ROCDECODE_VIDEO_FILE}")
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Unable to find video file for rocdecode tests: ${ROCDECODE_VIDEO_FILE}")
|
||||
endif()
|
||||
add_test(NAME test-rocdecode-tracing-execute COMMAND $<TARGET_FILE:rocdecode> -i
|
||||
${ROCDECODE_VIDEO_FILE})
|
||||
|
||||
add_test(
|
||||
NAME test-rocdecode-tracing-execute
|
||||
COMMAND
|
||||
$<IF:$<TARGET_EXISTS:rocdecode-demo>,$<$<TARGET_EXISTS:rocdecode-demo>:$<TARGET_FILE:rocdecode-demo>>,${CMAKE_COMMAND}>
|
||||
-i ${ROCDECODE_VIDEO_FILE})
|
||||
|
||||
set(rocdecode-tracing-env
|
||||
"${PRELOAD_ENV}"
|
||||
@@ -35,9 +40,16 @@ set(rocdecode-tracing-env
|
||||
|
||||
set_tests_properties(
|
||||
test-rocdecode-tracing-execute
|
||||
PROPERTIES TIMEOUT 45 LABELS "integration-tests" ENVIRONMENT
|
||||
"${rocdecode-tracing-env}" FAIL_REGULAR_EXPRESSION
|
||||
"${ROCPROFILER_DEFAULT_FAIL_REGEX}")
|
||||
PROPERTIES TIMEOUT
|
||||
45
|
||||
LABELS
|
||||
"integration-tests"
|
||||
ENVIRONMENT
|
||||
"${rocdecode-tracing-env}"
|
||||
FAIL_REGULAR_EXPRESSION
|
||||
"${ROCPROFILER_DEFAULT_FAIL_REGEX}"
|
||||
DISABLED
|
||||
$<NOT:$<TARGET_EXISTS:rocdecode-demo>>)
|
||||
|
||||
# copy to binary directory
|
||||
rocprofiler_configure_pytest_files(COPY validate.py conftest.py CONFIG pytest.ini)
|
||||
@@ -48,6 +60,13 @@ add_test(NAME test-rocdecode-tracing-validate
|
||||
|
||||
set_tests_properties(
|
||||
test-rocdecode-tracing-validate
|
||||
PROPERTIES TIMEOUT 45 LABELS "integration-tests" DEPENDS
|
||||
test-rocdecode-tracing-execute FAIL_REGULAR_EXPRESSION
|
||||
"${ROCPROFILER_DEFAULT_FAIL_REGEX}")
|
||||
PROPERTIES TIMEOUT
|
||||
45
|
||||
LABELS
|
||||
"integration-tests"
|
||||
DEPENDS
|
||||
test-rocdecode-tracing-execute
|
||||
FAIL_REGULAR_EXPRESSION
|
||||
"${ROCPROFILER_DEFAULT_FAIL_REGEX}"
|
||||
DISABLED
|
||||
$<NOT:$<TARGET_EXISTS:rocdecode-demo>>)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import json
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from rocprofiler_sdk.pytest_utils.dotdict import dotdict
|
||||
@@ -18,5 +19,7 @@ def pytest_addoption(parser):
|
||||
@pytest.fixture
|
||||
def input_data(request):
|
||||
filename = request.config.getoption("--input")
|
||||
if not os.path.isfile(filename):
|
||||
return pytest.skip("rocdecode tracing unavailable")
|
||||
with open(filename, "r") as inp:
|
||||
return dotdict(json.load(inp))
|
||||
|
||||
@@ -32,16 +32,12 @@ def test_data_structure(input_data):
|
||||
node_exists("buffer_records", sdk_data)
|
||||
|
||||
node_exists("names", sdk_data["callback_records"])
|
||||
node_exists("hsa_api_traces", sdk_data["callback_records"])
|
||||
node_exists("hip_api_traces", sdk_data["callback_records"])
|
||||
node_exists("memory_allocations", sdk_data["callback_records"])
|
||||
node_exists("rocdecode_api_traces", sdk_data["callback_records"])
|
||||
# Uncomment when rocprofiler register mainline supports rocdecode
|
||||
# node_exists("rocdecode_api_traces", sdk_data["callback_records"])
|
||||
|
||||
node_exists("names", sdk_data["buffer_records"])
|
||||
node_exists("hsa_api_traces", sdk_data["buffer_records"])
|
||||
node_exists("hip_api_traces", sdk_data["buffer_records"])
|
||||
node_exists("memory_allocations", sdk_data["buffer_records"])
|
||||
node_exists("rocdecode_api_traces", sdk_data["buffer_records"])
|
||||
# Uncomment when rocprofiler register mainline supports rocdecode
|
||||
# node_exists("rocdecode_api_traces", sdk_data["buffer_records"])
|
||||
|
||||
|
||||
def test_size_entries(input_data):
|
||||
@@ -77,7 +73,7 @@ def test_timestamps(input_data):
|
||||
|
||||
cb_start = {}
|
||||
cb_end = {}
|
||||
for titr in ["hsa_api_traces", "hip_api_traces", "rocdecode_api_traces"]:
|
||||
for titr in ["rocdecode_api_traces"]:
|
||||
for itr in sdk_data["callback_records"][titr]:
|
||||
cid = itr["correlation_id"]["internal"]
|
||||
phase = itr["phase"]
|
||||
@@ -92,29 +88,6 @@ def test_timestamps(input_data):
|
||||
for itr in sdk_data["buffer_records"][titr]:
|
||||
assert itr["start_timestamp"] <= itr["end_timestamp"]
|
||||
|
||||
for titr in ["memory_allocations"]:
|
||||
for itr in sdk_data["buffer_records"][titr]:
|
||||
assert itr["start_timestamp"] < itr["end_timestamp"], f"[{titr}] {itr}"
|
||||
assert itr["correlation_id"]["internal"] > 0, f"[{titr}] {itr}"
|
||||
assert itr["correlation_id"]["external"] > 0, f"[{titr}] {itr}"
|
||||
assert (
|
||||
sdk_data["metadata"]["init_time"] < itr["start_timestamp"]
|
||||
), f"[{titr}] {itr}"
|
||||
assert (
|
||||
sdk_data["metadata"]["init_time"] < itr["end_timestamp"]
|
||||
), f"[{titr}] {itr}"
|
||||
assert (
|
||||
sdk_data["metadata"]["fini_time"] > itr["start_timestamp"]
|
||||
), f"[{titr}] {itr}"
|
||||
assert (
|
||||
sdk_data["metadata"]["fini_time"] > itr["end_timestamp"]
|
||||
), f"[{titr}] {itr}"
|
||||
|
||||
api_start = cb_start[itr["correlation_id"]["internal"]]
|
||||
# api_end = cb_end[itr["correlation_id"]["internal"]]
|
||||
assert api_start < itr["start_timestamp"], f"[{titr}] {itr}"
|
||||
# assert api_end <= itr["end_timestamp"], f"[{titr}] {itr}"
|
||||
|
||||
|
||||
def test_internal_correlation_ids(input_data):
|
||||
"""Assure correlation ids are unique"""
|
||||
@@ -140,37 +113,6 @@ def test_internal_correlation_ids(input_data):
|
||||
assert max(api_corr_ids_sorted) == len_corr_id_unq
|
||||
|
||||
|
||||
def test_external_correlation_ids(input_data):
|
||||
data = input_data
|
||||
sdk_data = data["rocprofiler-sdk-json-tool"]
|
||||
|
||||
extern_corr_ids = []
|
||||
for titr in ["hsa_api_traces", "hip_api_traces", "rocdecode_api_traces"]:
|
||||
for itr in sdk_data["callback_records"][titr]:
|
||||
assert itr["correlation_id"]["external"] > 0
|
||||
assert itr["thread_id"] == itr["correlation_id"]["external"]
|
||||
extern_corr_ids.append(itr["correlation_id"]["external"])
|
||||
|
||||
extern_corr_ids = list(set(sorted(extern_corr_ids)))
|
||||
for titr in ["hsa_api_traces", "hip_api_traces", "rocdecode_api_traces"]:
|
||||
for itr in sdk_data["buffer_records"][titr]:
|
||||
assert itr["correlation_id"]["external"] > 0, f"[{titr}] {itr}"
|
||||
assert (
|
||||
itr["thread_id"] == itr["correlation_id"]["external"]
|
||||
), f"[{titr}] {itr}"
|
||||
assert itr["thread_id"] in extern_corr_ids, f"[{titr}] {itr}"
|
||||
assert itr["correlation_id"]["external"] in extern_corr_ids, f"[{titr}] {itr}"
|
||||
|
||||
for titr in ["memory_allocations"]:
|
||||
for itr in sdk_data["buffer_records"][titr]:
|
||||
assert itr["correlation_id"]["external"] > 0, f"[{titr}] {itr}"
|
||||
assert itr["correlation_id"]["external"] in extern_corr_ids, f"[{titr}] {itr}"
|
||||
|
||||
for itr in sdk_data["callback_records"][titr]:
|
||||
assert itr["correlation_id"]["external"] > 0, f"[{titr}] {itr}"
|
||||
assert itr["correlation_id"]["external"] in extern_corr_ids, f"[{titr}] {itr}"
|
||||
|
||||
|
||||
def get_operation(record, kind_name, op_name=None):
|
||||
for idx, itr in enumerate(record["names"]):
|
||||
if kind_name == itr["kind"]:
|
||||
@@ -196,7 +138,9 @@ def test_rocdecode_traces(input_data):
|
||||
|
||||
rocdecode_cb_traces = sdk_data["callback_records"]["rocdecode_api_traces"]
|
||||
rocdecode_api_cb_ops = get_operation(callback_records, "ROCDECODE_API")
|
||||
|
||||
# If rocDecode tracing is not supported, end early
|
||||
if len(rocdecode_bf_traces) == 0:
|
||||
return pytest.skip("rocdecode tracing unavailable")
|
||||
assert (
|
||||
rocdecode_api_bf_ops[1] == rocdecode_api_cb_ops[1]
|
||||
and len(rocdecode_api_cb_ops[1]) == 16
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
cmake_minimum_required(VERSION 3.21.0 FATAL_ERROR)
|
||||
|
||||
project(
|
||||
rocprofiler-tests-rocjpeg-tracing
|
||||
LANGUAGES CXX
|
||||
VERSION 0.0.0)
|
||||
|
||||
find_package(rocprofiler-sdk REQUIRED)
|
||||
find_package(rocJPEG)
|
||||
|
||||
string(REPLACE "LD_PRELOAD=" "ROCPROF_PRELOAD=" PRELOAD_ENV
|
||||
"${ROCPROFILER_MEMCHECK_PRELOAD_ENV}")
|
||||
set(rocjpeg-tracing-env "${PRELOAD_ENV}")
|
||||
|
||||
set(rocJPEG_IMAGE_DIR "${rocJPEG_ROOT_DIR}/share/rocjpeg/images")
|
||||
if(TARGET rocjpeg-demo AND NOT EXISTS "${rocJPEG_IMAGE_DIR}")
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Unable to find image directory for rocjpeg tests: ${rocJPEG_IMAGE_DIR}")
|
||||
endif()
|
||||
|
||||
add_test(
|
||||
NAME test-rocjpeg-tracing-execute
|
||||
COMMAND
|
||||
$<IF:$<TARGET_EXISTS:rocjpeg-demo>,$<$<TARGET_EXISTS:rocjpeg-demo>:$<TARGET_FILE:rocjpeg-demo>>,${CMAKE_COMMAND}>
|
||||
-i ${rocJPEG_IMAGE_DIR})
|
||||
|
||||
set(rocjpeg-tracing-env
|
||||
"${PRELOAD_ENV}"
|
||||
"ROCPROFILER_TOOL_OUTPUT_FILE=rocjpeg-tracing-test.json"
|
||||
"LD_LIBRARY_PATH=$<TARGET_FILE_DIR:rocprofiler-sdk::rocprofiler-sdk-shared-library>:$ENV{LD_LIBRARY_PATH}"
|
||||
)
|
||||
|
||||
set_tests_properties(
|
||||
test-rocjpeg-tracing-execute
|
||||
PROPERTIES TIMEOUT
|
||||
45
|
||||
LABELS
|
||||
"integration-tests"
|
||||
ENVIRONMENT
|
||||
"${rocjpeg-tracing-env}"
|
||||
FAIL_REGULAR_EXPRESSION
|
||||
"${ROCPROFILER_DEFAULT_FAIL_REGEX}"
|
||||
DISABLED
|
||||
$<NOT:$<TARGET_EXISTS:rocjpeg-demo>>)
|
||||
|
||||
# copy to binary directory
|
||||
rocprofiler_configure_pytest_files(COPY validate.py conftest.py CONFIG pytest.ini)
|
||||
|
||||
add_test(NAME test-rocjpeg-tracing-validate
|
||||
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/validate.py --input
|
||||
${CMAKE_CURRENT_BINARY_DIR}/rocjpeg-tracing-test.json)
|
||||
|
||||
set_tests_properties(
|
||||
test-rocjpeg-tracing-validate
|
||||
PROPERTIES TIMEOUT
|
||||
45
|
||||
LABELS
|
||||
"integration-tests"
|
||||
DEPENDS
|
||||
test-rocjpeg-tracing-execute
|
||||
FAIL_REGULAR_EXPRESSION
|
||||
"${ROCPROFILER_DEFAULT_FAIL_REGEX}"
|
||||
DISABLED
|
||||
$<NOT:$<TARGET_EXISTS:rocjpeg-demo>>)
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import json
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from rocprofiler_sdk.pytest_utils.dotdict import dotdict
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption(
|
||||
"--input",
|
||||
action="store",
|
||||
default="rocjpeg-tracing-test.json",
|
||||
help="Input JSON",
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def input_data(request):
|
||||
filename = request.config.getoption("--input")
|
||||
if not os.path.isfile(filename):
|
||||
return pytest.skip("rocjpeg tracing unavailable")
|
||||
with open(filename, "r") as inp:
|
||||
return dotdict(json.load(inp))
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
[pytest]
|
||||
addopts = --durations=20 -rA -s -vv
|
||||
testpaths = validate.py
|
||||
pythonpath = @ROCPROFILER_SDK_TESTS_BINARY_DIR@/pytest-packages
|
||||
@@ -0,0 +1,250 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
|
||||
# helper function
|
||||
def node_exists(name, data, min_len=1):
|
||||
assert name in data
|
||||
assert data[name] is not None
|
||||
if isinstance(data[name], (list, tuple, dict, set)):
|
||||
assert len(data[name]) >= min_len, f"{name}:\n{data}"
|
||||
|
||||
|
||||
def test_data_structure(input_data):
|
||||
"""verify minimum amount of expected data is present"""
|
||||
data = input_data
|
||||
|
||||
node_exists("rocprofiler-sdk-json-tool", data)
|
||||
|
||||
sdk_data = data["rocprofiler-sdk-json-tool"]
|
||||
|
||||
node_exists("metadata", sdk_data)
|
||||
node_exists("pid", sdk_data["metadata"])
|
||||
node_exists("main_tid", sdk_data["metadata"])
|
||||
node_exists("init_time", sdk_data["metadata"])
|
||||
node_exists("fini_time", sdk_data["metadata"])
|
||||
|
||||
node_exists("agents", sdk_data)
|
||||
node_exists("call_stack", sdk_data)
|
||||
node_exists("callback_records", sdk_data)
|
||||
node_exists("buffer_records", sdk_data)
|
||||
|
||||
node_exists("names", sdk_data["callback_records"])
|
||||
# Uncomment once mainline rocprofiler register supports rocJPEG
|
||||
# node_exists("rocjpeg_api_traces", sdk_data["callback_records"])
|
||||
|
||||
node_exists("names", sdk_data["buffer_records"])
|
||||
# Uncomment once mainline rocprofiler register supports rocJPEG
|
||||
# node_exists("rocjpeg_api_traces", sdk_data["buffer_records"])
|
||||
|
||||
|
||||
def test_size_entries(input_data):
|
||||
# check that size fields are > 0 but account for function arguments
|
||||
# which are named "size"
|
||||
def check_size(data, bt):
|
||||
if "size" in data.keys():
|
||||
if isinstance(data["size"], str) and bt.endswith('["args"]'):
|
||||
pass
|
||||
else:
|
||||
assert data["size"] > 0, f"origin: {bt}"
|
||||
|
||||
# recursively check the entire data structure
|
||||
def iterate_data(data, bt):
|
||||
if isinstance(data, (list, tuple)):
|
||||
for i, itr in enumerate(data):
|
||||
if isinstance(itr, dict):
|
||||
check_size(itr, f"{bt}[{i}]")
|
||||
iterate_data(itr, f"{bt}[{i}]")
|
||||
elif isinstance(data, dict):
|
||||
check_size(data, f"{bt}")
|
||||
for key, itr in data.items():
|
||||
iterate_data(itr, f'{bt}["{key}"]')
|
||||
|
||||
# start recursive check over entire JSON dict
|
||||
iterate_data(input_data, "input_data")
|
||||
|
||||
|
||||
def test_timestamps(input_data):
|
||||
"""Verify starting timestamps are less than ending timestamps"""
|
||||
data = input_data
|
||||
sdk_data = data["rocprofiler-sdk-json-tool"]
|
||||
|
||||
cb_start = {}
|
||||
cb_end = {}
|
||||
for titr in ["rocjpeg_api_traces"]:
|
||||
for itr in sdk_data["callback_records"][titr]:
|
||||
cid = itr["correlation_id"]["internal"]
|
||||
phase = itr["phase"]
|
||||
if phase == 1:
|
||||
cb_start[cid] = itr["timestamp"]
|
||||
elif phase == 2:
|
||||
cb_end[cid] = itr["timestamp"]
|
||||
assert cb_start[cid] <= itr["timestamp"]
|
||||
else:
|
||||
assert phase == 1 or phase == 2
|
||||
|
||||
for itr in sdk_data["buffer_records"][titr]:
|
||||
assert itr["start_timestamp"] <= itr["end_timestamp"]
|
||||
|
||||
|
||||
def test_internal_correlation_ids(input_data):
|
||||
"""Assure correlation ids are unique"""
|
||||
data = input_data
|
||||
sdk_data = data["rocprofiler-sdk-json-tool"]
|
||||
|
||||
api_corr_ids = []
|
||||
for titr in ["hsa_api_traces", "hip_api_traces", "rocjpeg_api_traces"]:
|
||||
for itr in sdk_data["callback_records"][titr]:
|
||||
api_corr_ids.append(itr["correlation_id"]["internal"])
|
||||
|
||||
for itr in sdk_data["buffer_records"][titr]:
|
||||
api_corr_ids.append(itr["correlation_id"]["internal"])
|
||||
|
||||
api_corr_ids_sorted = sorted(api_corr_ids)
|
||||
api_corr_ids_unique = list(set(api_corr_ids))
|
||||
|
||||
for itr in sdk_data["buffer_records"]["memory_allocations"]:
|
||||
assert itr["correlation_id"]["internal"] in api_corr_ids_unique
|
||||
|
||||
len_corr_id_unq = len(api_corr_ids_unique)
|
||||
assert len(api_corr_ids) != len_corr_id_unq
|
||||
assert max(api_corr_ids_sorted) == len_corr_id_unq
|
||||
|
||||
|
||||
def test_external_correlation_ids(input_data):
|
||||
data = input_data
|
||||
sdk_data = data["rocprofiler-sdk-json-tool"]
|
||||
|
||||
extern_corr_ids = []
|
||||
for titr in ["rocjpeg_api_traces"]:
|
||||
for itr in sdk_data["callback_records"][titr]:
|
||||
assert itr["correlation_id"]["external"] > 0
|
||||
assert itr["thread_id"] == itr["correlation_id"]["external"]
|
||||
extern_corr_ids.append(itr["correlation_id"]["external"])
|
||||
|
||||
extern_corr_ids = list(set(sorted(extern_corr_ids)))
|
||||
for titr in ["rocjpeg_api_traces"]:
|
||||
for itr in sdk_data["buffer_records"][titr]:
|
||||
assert itr["correlation_id"]["external"] > 0, f"[{titr}] {itr}"
|
||||
assert (
|
||||
itr["thread_id"] == itr["correlation_id"]["external"]
|
||||
), f"[{titr}] {itr}"
|
||||
assert itr["thread_id"] in extern_corr_ids, f"[{titr}] {itr}"
|
||||
assert itr["correlation_id"]["external"] in extern_corr_ids, f"[{titr}] {itr}"
|
||||
|
||||
for itr in sdk_data["callback_records"][titr]:
|
||||
assert itr["correlation_id"]["external"] > 0, f"[{titr}] {itr}"
|
||||
assert itr["correlation_id"]["external"] in extern_corr_ids, f"[{titr}] {itr}"
|
||||
|
||||
|
||||
def get_operation(record, kind_name, op_name=None):
|
||||
for idx, itr in enumerate(record["names"]):
|
||||
if kind_name == itr["kind"]:
|
||||
if op_name is None:
|
||||
return idx, itr["operations"]
|
||||
else:
|
||||
for oidx, oname in enumerate(itr["operations"]):
|
||||
if op_name == oname:
|
||||
return oidx
|
||||
return None
|
||||
|
||||
|
||||
def test_rocjpeg_traces(input_data):
|
||||
data = input_data
|
||||
sdk_data = data["rocprofiler-sdk-json-tool"]
|
||||
|
||||
callback_records = sdk_data["callback_records"]
|
||||
buffer_records = sdk_data["buffer_records"]
|
||||
|
||||
rocjpeg_bf_traces = sdk_data["buffer_records"]["rocjpeg_api_traces"]
|
||||
rocjpeg_api_bf_ops = get_operation(buffer_records, "ROCJPEG_API")
|
||||
assert len(rocjpeg_api_bf_ops[1]) == 9
|
||||
|
||||
rocjpeg_cb_traces = sdk_data["callback_records"]["rocjpeg_api_traces"]
|
||||
rocjpeg_api_cb_ops = get_operation(callback_records, "ROCJPEG_API")
|
||||
|
||||
# If rocJPEG tracing is not supported, end early
|
||||
if len(rocjpeg_bf_traces) <= 2:
|
||||
return pytest.skip("rocdecode tracing unavailable")
|
||||
assert (
|
||||
rocjpeg_api_bf_ops[1] == rocjpeg_api_cb_ops[1] and len(rocjpeg_api_cb_ops[1]) == 9
|
||||
)
|
||||
|
||||
# check that buffer and callback records agree
|
||||
phase_enter_count = 0
|
||||
phase_end_count = 0
|
||||
|
||||
api_calls = []
|
||||
|
||||
for api_call in rocjpeg_cb_traces:
|
||||
if api_call["phase"] == 1:
|
||||
phase_enter_count += 1
|
||||
api_calls.append(rocjpeg_api_cb_ops[1][api_call["operation"]])
|
||||
if api_call["phase"] == 2:
|
||||
phase_end_count += 1
|
||||
|
||||
assert phase_enter_count == phase_end_count == len(rocjpeg_bf_traces)
|
||||
|
||||
for call in [
|
||||
"rocJpegCreate",
|
||||
"rocJpegStreamCreate",
|
||||
"rocJpegStreamParse",
|
||||
"rocJpegGetImageInfo",
|
||||
"rocJpegDecode",
|
||||
"rocJpegDestroy",
|
||||
"rocJpegStreamDestroy",
|
||||
]:
|
||||
assert call in api_calls
|
||||
|
||||
|
||||
def test_retired_correlation_ids(input_data):
|
||||
data = input_data
|
||||
sdk_data = data["rocprofiler-sdk-json-tool"]
|
||||
|
||||
def _sort_dict(inp):
|
||||
return dict(sorted(inp.items()))
|
||||
|
||||
api_corr_ids = {}
|
||||
for titr in ["hsa_api_traces", "hip_api_traces", "rocjpeg_api_traces"]:
|
||||
for itr in sdk_data["buffer_records"][titr]:
|
||||
corr_id = itr["correlation_id"]["internal"]
|
||||
assert corr_id not in api_corr_ids.keys()
|
||||
api_corr_ids[corr_id] = itr
|
||||
|
||||
alloc_corr_ids = {}
|
||||
for titr in ["memory_allocations"]:
|
||||
for itr in sdk_data["buffer_records"][titr]:
|
||||
corr_id = itr["correlation_id"]["internal"]
|
||||
assert corr_id not in alloc_corr_ids.keys()
|
||||
alloc_corr_ids[corr_id] = itr
|
||||
|
||||
retired_corr_ids = {}
|
||||
for itr in sdk_data["buffer_records"]["retired_correlation_ids"]:
|
||||
corr_id = itr["internal_correlation_id"]
|
||||
assert corr_id not in retired_corr_ids.keys()
|
||||
retired_corr_ids[corr_id] = itr
|
||||
|
||||
api_corr_ids = _sort_dict(api_corr_ids)
|
||||
alloc_corr_ids = _sort_dict(alloc_corr_ids)
|
||||
retired_corr_ids = _sort_dict(retired_corr_ids)
|
||||
|
||||
for cid, itr in alloc_corr_ids.items():
|
||||
assert cid in retired_corr_ids.keys()
|
||||
retired_ts = retired_corr_ids[cid]["timestamp"]
|
||||
end_ts = itr["end_timestamp"]
|
||||
assert (retired_ts - end_ts) > 0, f"correlation-id: {cid}, data: {itr}"
|
||||
|
||||
for cid, itr in api_corr_ids.items():
|
||||
assert cid in retired_corr_ids.keys()
|
||||
retired_ts = retired_corr_ids[cid]["timestamp"]
|
||||
end_ts = itr["end_timestamp"]
|
||||
assert (retired_ts - end_ts) > 0, f"correlation-id: {cid}, data: {itr}"
|
||||
|
||||
assert len(api_corr_ids.keys()) == (len(retired_corr_ids.keys()))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit_code = pytest.main(["-x", __file__] + sys.argv[1:])
|
||||
sys.exit(exit_code)
|
||||
@@ -36,9 +36,8 @@ add_subdirectory(roctracer-roctx)
|
||||
add_subdirectory(scratch-memory)
|
||||
add_subdirectory(pc-sampling)
|
||||
add_subdirectory(collection-period)
|
||||
if(ROCPROFILER_BUILD_ROCDECODE_TESTS)
|
||||
add_subdirectory(rocdecode-trace)
|
||||
endif()
|
||||
add_subdirectory(rocdecode-trace)
|
||||
add_subdirectory(rocjpeg-trace)
|
||||
if(TARGET att_decoder_testing)
|
||||
add_subdirectory(advanced-thread-trace)
|
||||
endif()
|
||||
|
||||
@@ -9,6 +9,7 @@ project(
|
||||
VERSION 0.0.0)
|
||||
|
||||
find_package(rocprofiler-sdk REQUIRED)
|
||||
find_package(rocDecode)
|
||||
|
||||
rocprofiler_configure_pytest_files(CONFIG pytest.ini COPY validate.py conftest.py)
|
||||
|
||||
@@ -18,23 +19,34 @@ string(REPLACE "LD_PRELOAD=" "ROCPROF_PRELOAD=" PRELOAD_ENV
|
||||
set(rocdecode-tracing-env "${PRELOAD_ENV}")
|
||||
|
||||
set(ROCDECODE_VIDEO_FILE
|
||||
"${ROCM_PATH}/share/rocdecode/video/AMD_driving_virtual_20-H265.265")
|
||||
if(NOT EXISTS "${ROCDECODE_VIDEO_FILE}")
|
||||
"${rocDecode_ROOT_DIR}/share/rocdecode/video/AMD_driving_virtual_20-H265.265")
|
||||
if(TARGET rocdecode-demo AND NOT EXISTS "${ROCDECODE_VIDEO_FILE}")
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Unable to find video file for rocdecode tests: ${ROCDECODE_VIDEO_FILE}")
|
||||
endif()
|
||||
|
||||
add_test(
|
||||
NAME rocprofv3-test-rocdecode-tracing-execute
|
||||
COMMAND
|
||||
$<TARGET_FILE:rocprofiler-sdk::rocprofv3> --rocdecode-trace -d
|
||||
${CMAKE_CURRENT_BINARY_DIR}/%tag%-trace -o out --output-format json otf2 pftrace
|
||||
csv --log-level env -- $<TARGET_FILE:rocdecode> -i ${ROCDECODE_VIDEO_FILE})
|
||||
${CMAKE_CURRENT_BINARY_DIR}/%tag%-trace -o out --output-format json csv
|
||||
--log-level env --
|
||||
$<IF:$<TARGET_EXISTS:rocdecode-demo>,$<$<TARGET_EXISTS:rocdecode-demo>:$<TARGET_FILE:rocdecode-demo>>,rocdecode-demo>
|
||||
-i ${ROCDECODE_VIDEO_FILE})
|
||||
|
||||
set_tests_properties(
|
||||
rocprofv3-test-rocdecode-tracing-execute
|
||||
PROPERTIES TIMEOUT 45 LABELS "integration-tests" ENVIRONMENT
|
||||
"${rocdecode-tracing-env}" FAIL_REGULAR_EXPRESSION "threw an exception")
|
||||
PROPERTIES TIMEOUT
|
||||
45
|
||||
LABELS
|
||||
"integration-tests"
|
||||
ENVIRONMENT
|
||||
"${rocdecode-tracing-env}"
|
||||
FAIL_REGULAR_EXPRESSION
|
||||
"threw an exception"
|
||||
DISABLED
|
||||
$<NOT:$<TARGET_EXISTS:rocdecode-demo>>)
|
||||
|
||||
add_test(
|
||||
NAME rocprofv3-test-rocdecode-tracing-validate
|
||||
@@ -47,6 +59,13 @@ add_test(
|
||||
|
||||
set_tests_properties(
|
||||
rocprofv3-test-rocdecode-tracing-validate
|
||||
PROPERTIES TIMEOUT 45 LABELS "integration-tests" DEPENDS
|
||||
rocprofv3-test-rocdecode-tracing-execute FAIL_REGULAR_EXPRESSION
|
||||
"AssertionError")
|
||||
PROPERTIES TIMEOUT
|
||||
45
|
||||
LABELS
|
||||
"integration-tests"
|
||||
DEPENDS
|
||||
rocprofv3-test-rocdecode-tracing-execute
|
||||
FAIL_REGULAR_EXPRESSION
|
||||
"AssertionError"
|
||||
DISABLED
|
||||
$<NOT:$<TARGET_EXISTS:rocdecode-demo>>)
|
||||
|
||||
@@ -41,6 +41,8 @@ def pytest_addoption(parser):
|
||||
@pytest.fixture
|
||||
def json_data(request):
|
||||
filename = request.config.getoption("--json-input")
|
||||
if not os.path.isfile(filename):
|
||||
return pytest.skip("rocdecode tracing unavailable")
|
||||
with open(filename, "r") as inp:
|
||||
return dotdict(collapse_dict_list(json.load(inp)))
|
||||
|
||||
@@ -49,23 +51,30 @@ def json_data(request):
|
||||
def csv_data(request):
|
||||
filename = request.config.getoption("--csv-input")
|
||||
data = []
|
||||
with open(filename, "r") as inp:
|
||||
reader = csv.DictReader(inp)
|
||||
for row in reader:
|
||||
data.append(row)
|
||||
|
||||
if not os.path.isfile(filename):
|
||||
# The CSV file is not generated, because the dependency test
|
||||
# responsible to generate this file was skipped or failed.
|
||||
# Thus emit the message to skip this test as well.
|
||||
return pytest.skip("rocdecode tracing unavailable")
|
||||
else:
|
||||
with open(filename, "r") as inp:
|
||||
reader = csv.DictReader(inp)
|
||||
for row in reader:
|
||||
data.append(row)
|
||||
return data
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def otf2_data(request):
|
||||
filename = request.config.getoption("--otf2-input")
|
||||
if not os.path.exists(filename):
|
||||
raise FileExistsError(f"{filename} does not exist")
|
||||
if not os.path.isfile(filename):
|
||||
return pytest.skip("rocdecode tracing unavailable")
|
||||
return OTF2Reader(filename).read()[0]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def pftrace_data(request):
|
||||
filename = request.config.getoption("--pftrace-input")
|
||||
if not os.path.isfile(filename):
|
||||
return pytest.skip("rocdecode tracing unavailable")
|
||||
return PerfettoReader(filename).read()[0]
|
||||
|
||||
@@ -32,6 +32,9 @@ def test_rocdeocde(json_data):
|
||||
buffer_records = data["buffer_records"]
|
||||
|
||||
rocdecode_data = buffer_records["rocdecode_api"]
|
||||
# If rocDecode tracing is not supported, end early
|
||||
if len(rocdecode_data) == 0:
|
||||
return pytest.skip("rocdecode tracing unavailable")
|
||||
|
||||
_, bf_op_names = get_operation(data, "ROCDECODE_API")
|
||||
|
||||
@@ -62,6 +65,9 @@ def test_rocdeocde(json_data):
|
||||
|
||||
|
||||
def test_csv_data(csv_data):
|
||||
# If rocDecode tracing is not supported, end early
|
||||
if len(csv_data) == 0:
|
||||
return pytest.skip("rocdecode tracing unavailable")
|
||||
assert len(csv_data) > 0, "Expected non-empty csv data"
|
||||
|
||||
api_calls = []
|
||||
@@ -116,20 +122,34 @@ def test_csv_data(csv_data):
|
||||
def test_perfetto_data(pftrace_data, json_data):
|
||||
import rocprofiler_sdk.tests.rocprofv3 as rocprofv3
|
||||
|
||||
# If rocDecode tracing is not supported, end early
|
||||
if (
|
||||
pftrace_data == None
|
||||
or len(json_data["rocprofiler-sdk-tool"]["buffer_records"]["rocdecode_api"]) == 0
|
||||
):
|
||||
return pytest.skip("rocdecode tracing unavailable")
|
||||
|
||||
rocprofv3.test_perfetto_data(
|
||||
pftrace_data,
|
||||
json_data,
|
||||
("hip", "hsa", "memory_allocation", "rocdecode_api"),
|
||||
("rocdecode_api",),
|
||||
)
|
||||
|
||||
|
||||
def test_otf2_data(otf2_data, json_data):
|
||||
import rocprofiler_sdk.tests.rocprofv3 as rocprofv3
|
||||
|
||||
# If rocDecode tracing is not supported, end early
|
||||
if (
|
||||
otf2_data == None
|
||||
or len(json_data["rocprofiler-sdk-tool"]["buffer_records"]["rocdecode_api"]) == 0
|
||||
):
|
||||
return pytest.skip("rocdecode tracing unavailable")
|
||||
|
||||
rocprofv3.test_otf2_data(
|
||||
otf2_data,
|
||||
json_data,
|
||||
("hip", "hsa", "memory_allocation", "rocdecode_api"),
|
||||
("rocdecode_api",),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
cmake_minimum_required(VERSION 3.21.0 FATAL_ERROR)
|
||||
|
||||
project(
|
||||
rocprofiler-tests-rocprofv3-rocjpeg-tracing
|
||||
LANGUAGES CXX
|
||||
VERSION 0.0.0)
|
||||
|
||||
find_package(rocprofiler-sdk REQUIRED)
|
||||
find_package(rocJPEG)
|
||||
|
||||
rocprofiler_configure_pytest_files(CONFIG pytest.ini COPY validate.py conftest.py)
|
||||
|
||||
string(REPLACE "LD_PRELOAD=" "ROCPROF_PRELOAD=" PRELOAD_ENV
|
||||
"${ROCPROFILER_MEMCHECK_PRELOAD_ENV}")
|
||||
|
||||
set(rocjpeg-tracing-env "${PRELOAD_ENV}")
|
||||
|
||||
set(ROCJPEG_IMAGE_DIR "${ROCM_PATH}/share/rocjpeg/images")
|
||||
if(TARGET rocjpeg-demo AND NOT EXISTS "${ROCJPEG_IMAGE_DIR}")
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Unable to find image directory for rocjpeg tests: ${ROCJPEG_IMAGE_DIR}")
|
||||
endif()
|
||||
|
||||
# CI Sanitizer run gives the following error: No target "rocjpeg-demo" Adding if-statement
|
||||
# to avoid tests for now to stop error
|
||||
add_test(
|
||||
NAME rocprofv3-test-rocjpeg-tracing-execute
|
||||
COMMAND
|
||||
$<TARGET_FILE:rocprofiler-sdk::rocprofv3> --rocjpeg-trace -d
|
||||
${CMAKE_CURRENT_BINARY_DIR}/%tag%-trace -o out --output-format json csv
|
||||
--log-level env --
|
||||
$<IF:$<TARGET_EXISTS:rocjpeg-demo>,$<$<TARGET_EXISTS:rocjpeg-demo>:$<TARGET_FILE:rocjpeg-demo>>,rocjpeg-demo>
|
||||
-i ${ROCJPEG_IMAGE_DIR})
|
||||
|
||||
set_tests_properties(
|
||||
rocprofv3-test-rocjpeg-tracing-execute
|
||||
PROPERTIES TIMEOUT
|
||||
45
|
||||
LABELS
|
||||
"integration-tests"
|
||||
ENVIRONMENT
|
||||
"${rocjpeg-tracing-env}"
|
||||
FAIL_REGULAR_EXPRESSION
|
||||
"threw an exception"
|
||||
DISABLED
|
||||
$<NOT:$<TARGET_EXISTS:rocjpeg-demo>>)
|
||||
|
||||
add_test(
|
||||
NAME rocprofv3-test-rocjpeg-tracing-validate
|
||||
COMMAND
|
||||
${Python3_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/validate.py --json-input
|
||||
${CMAKE_CURRENT_BINARY_DIR}/rocjpeg-trace/out_results.json --otf2-input
|
||||
${CMAKE_CURRENT_BINARY_DIR}/rocjpeg-trace/out_results.otf2 --pftrace-input
|
||||
${CMAKE_CURRENT_BINARY_DIR}/rocjpeg-trace/out_results.pftrace --csv-input
|
||||
${CMAKE_CURRENT_BINARY_DIR}/rocjpeg-trace/out_rocjpeg_api_trace.csv)
|
||||
|
||||
set_tests_properties(
|
||||
rocprofv3-test-rocjpeg-tracing-validate
|
||||
PROPERTIES TIMEOUT
|
||||
45
|
||||
LABELS
|
||||
"integration-tests"
|
||||
DEPENDS
|
||||
rocprofv3-test-rocjpeg-tracing-execute
|
||||
FAIL_REGULAR_EXPRESSION
|
||||
"AssertionError"
|
||||
DISABLED
|
||||
$<NOT:$<TARGET_EXISTS:rocjpeg-demo>>)
|
||||
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import csv
|
||||
import json
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from rocprofiler_sdk.pytest_utils.dotdict import dotdict
|
||||
from rocprofiler_sdk.pytest_utils import collapse_dict_list
|
||||
from rocprofiler_sdk.pytest_utils.perfetto_reader import PerfettoReader
|
||||
from rocprofiler_sdk.pytest_utils.otf2_reader import OTF2Reader
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption(
|
||||
"--json-input",
|
||||
action="store",
|
||||
default="rocjpeg-tracing/out_results.json",
|
||||
help="Input JSON",
|
||||
)
|
||||
parser.addoption(
|
||||
"--otf2-input",
|
||||
action="store",
|
||||
default="rocjpeg-tracing/out_results.otf2",
|
||||
help="Input OTF2",
|
||||
)
|
||||
parser.addoption(
|
||||
"--pftrace-input",
|
||||
action="store",
|
||||
default="rocjpeg-tracing/out_results.pftrace",
|
||||
help="Input pftrace file",
|
||||
)
|
||||
parser.addoption(
|
||||
"--csv-input",
|
||||
action="store",
|
||||
default="rocjpeg-tracing/out_rocjpeg_api_trace.csv",
|
||||
help="Input CSV",
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def json_data(request):
|
||||
filename = request.config.getoption("--json-input")
|
||||
if not os.path.isfile(filename):
|
||||
return pytest.skip("rocjpeg tracing unavailable")
|
||||
with open(filename, "r") as inp:
|
||||
return dotdict(collapse_dict_list(json.load(inp)))
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def csv_data(request):
|
||||
filename = request.config.getoption("--csv-input")
|
||||
data = []
|
||||
if not os.path.isfile(filename):
|
||||
# The CSV file is not generated, because the dependency test
|
||||
# responsible to generate this file was skipped or failed.
|
||||
# Thus emit the message to skip this test as well.
|
||||
return pytest.skip("rocjpeg tracing unavailable")
|
||||
else:
|
||||
with open(filename, "r") as inp:
|
||||
reader = csv.DictReader(inp)
|
||||
for row in reader:
|
||||
data.append(row)
|
||||
return data
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def otf2_data(request):
|
||||
filename = request.config.getoption("--otf2-input")
|
||||
if not os.path.isfile(filename):
|
||||
return pytest.skip("rocjpeg tracing unavailable")
|
||||
return OTF2Reader(filename).read()[0]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def pftrace_data(request):
|
||||
filename = request.config.getoption("--pftrace-input")
|
||||
if not os.path.isfile(filename):
|
||||
return pytest.skip("rocjpeg tracing unavailable")
|
||||
return PerfettoReader(filename).read()[0]
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
[pytest]
|
||||
addopts = --durations=20 -rA -s -vv
|
||||
testpaths = validate.py
|
||||
pythonpath = @ROCPROFILER_SDK_TESTS_BINARY_DIR@/pytest-packages
|
||||
Executable
+153
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import pytest
|
||||
import json
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
# helper function
|
||||
def node_exists(name, data, min_len=1):
|
||||
assert name in data
|
||||
assert data[name] is not None
|
||||
if isinstance(data[name], (list, tuple, dict, set)):
|
||||
assert len(data[name]) >= min_len
|
||||
|
||||
|
||||
def get_operation(record, kind_name, op_name=None):
|
||||
for idx, itr in enumerate(record["strings"]["buffer_records"]):
|
||||
if kind_name == itr["kind"]:
|
||||
if op_name is None:
|
||||
return idx, itr["operations"]
|
||||
else:
|
||||
for oidx, oname in enumerate(itr["operations"]):
|
||||
if op_name == oname:
|
||||
return oidx
|
||||
return None
|
||||
|
||||
|
||||
def test_rocjpeg(json_data):
|
||||
data = json_data["rocprofiler-sdk-tool"]
|
||||
buffer_records = data["buffer_records"]
|
||||
|
||||
rocjpeg_data = buffer_records["rocjpeg_api"]
|
||||
# If rocJPEG tracing is not supported, end early
|
||||
if len(rocjpeg_data) == 0:
|
||||
return pytest.skip("rocjpeg tracing unavailable")
|
||||
|
||||
_, bf_op_names = get_operation(data, "ROCJPEG_API")
|
||||
|
||||
assert len(bf_op_names) == 9
|
||||
|
||||
rocjpeg_reported_agent_ids = set()
|
||||
# check buffering data
|
||||
for node in rocjpeg_data:
|
||||
assert "size" in node
|
||||
assert "kind" in node
|
||||
assert "operation" in node
|
||||
assert "correlation_id" in node
|
||||
assert "end_timestamp" in node
|
||||
assert "start_timestamp" in node
|
||||
assert "thread_id" in node
|
||||
|
||||
assert node.size > 0
|
||||
assert node.thread_id > 0
|
||||
assert node.start_timestamp > 0
|
||||
assert node.end_timestamp > 0
|
||||
assert node.start_timestamp < node.end_timestamp
|
||||
|
||||
assert data.strings.buffer_records[node.kind].kind == "ROCJPEG_API"
|
||||
assert (
|
||||
data.strings.buffer_records[node.kind].operations[node.operation]
|
||||
in bf_op_names
|
||||
)
|
||||
|
||||
|
||||
def test_csv_data(csv_data):
|
||||
# If rocJPEG tracing is not supported, end early
|
||||
if len(csv_data) <= 2:
|
||||
return pytest.skip("rocjpeg tracing unavailable")
|
||||
assert len(csv_data) > 0, "Expected non-empty csv data"
|
||||
|
||||
api_calls = []
|
||||
|
||||
for row in csv_data:
|
||||
assert "Domain" in row, "'Domain' was not present in csv data for rocjpeg-trace"
|
||||
assert (
|
||||
"Function" in row
|
||||
), "'Function' was not present in csv data for rocjpeg-trace"
|
||||
assert (
|
||||
"Process_Id" in row
|
||||
), "'Process_Id' was not present in csv data for rocjpeg-trace"
|
||||
assert (
|
||||
"Thread_Id" in row
|
||||
), "'Thread_Id' was not present in csv data for rocjpeg-trace"
|
||||
assert (
|
||||
"Correlation_Id" in row
|
||||
), "'Correlation_Id' was not present in csv data for rocjpeg-trace"
|
||||
assert (
|
||||
"Start_Timestamp" in row
|
||||
), "'Start_Timestamp' was not present in csv data for rocjpeg-trace"
|
||||
assert (
|
||||
"End_Timestamp" in row
|
||||
), "'End_Timestamp' was not present in csv data for rocjpeg-trace"
|
||||
|
||||
api_calls.append(row["Function"])
|
||||
|
||||
assert row["Domain"] == "ROCJPEG_API"
|
||||
assert int(row["Process_Id"]) > 0
|
||||
assert int(row["Thread_Id"]) > 0
|
||||
assert int(row["Start_Timestamp"]) > 0
|
||||
assert int(row["End_Timestamp"]) > 0
|
||||
assert int(row["Start_Timestamp"]) < int(row["End_Timestamp"])
|
||||
|
||||
for call in [
|
||||
"rocJpegCreate",
|
||||
"rocJpegStreamCreate",
|
||||
"rocJpegStreamParse",
|
||||
"rocJpegGetImageInfo",
|
||||
"rocJpegDecode",
|
||||
"rocJpegDestroy",
|
||||
"rocJpegStreamDestroy",
|
||||
]:
|
||||
assert call in api_calls
|
||||
|
||||
|
||||
def test_perfetto_data(pftrace_data, json_data):
|
||||
import rocprofiler_sdk.tests.rocprofv3 as rocprofv3
|
||||
|
||||
# If rocJPEG tracing is not supported, end early
|
||||
if (
|
||||
pftrace_data == None
|
||||
or len(json_data["rocprofiler-sdk-tool"]["buffer_records"]["rocjpeg_api"]) == 0
|
||||
):
|
||||
return pytest.skip("rocjpeg tracing unavailable")
|
||||
|
||||
rocprofv3.test_perfetto_data(
|
||||
pftrace_data,
|
||||
json_data,
|
||||
("rocjpeg_api",),
|
||||
)
|
||||
|
||||
|
||||
def test_otf2_data(otf2_data, json_data):
|
||||
import rocprofiler_sdk.tests.rocprofv3 as rocprofv3
|
||||
|
||||
# If rocJPEG tracing is not supported, end early
|
||||
if (
|
||||
otf2_data == None
|
||||
or len(json_data["rocprofiler-sdk-tool"]["buffer_records"]["rocjpeg_api"]) == 0
|
||||
):
|
||||
return pytest.skip("rocjpeg tracing unavailable")
|
||||
|
||||
rocprofv3.test_otf2_data(
|
||||
otf2_data,
|
||||
json_data,
|
||||
("rocjpeg_api",),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit_code = pytest.main(["-x", __file__] + sys.argv[1:])
|
||||
sys.exit(exit_code)
|
||||
+121
-3
@@ -414,6 +414,23 @@ struct rocdecode_api_callback_record_t
|
||||
}
|
||||
};
|
||||
|
||||
struct rocjpeg_api_callback_record_t
|
||||
{
|
||||
uint64_t timestamp = 0;
|
||||
rocprofiler_callback_tracing_record_t record = {};
|
||||
rocprofiler_callback_tracing_rocjpeg_api_data_t payload = {};
|
||||
callback_arg_array_t args = {};
|
||||
|
||||
template <typename ArchiveT>
|
||||
void save(ArchiveT& ar) const
|
||||
{
|
||||
ar(cereal::make_nvp("timestamp", timestamp));
|
||||
cereal::save(ar, record);
|
||||
ar(cereal::make_nvp("payload", payload));
|
||||
serialize_args(ar, args);
|
||||
}
|
||||
};
|
||||
|
||||
struct ompt_callback_record_t
|
||||
{
|
||||
uint64_t timestamp = 0;
|
||||
@@ -573,6 +590,7 @@ auto memory_copy_cb_records = std::deque<memory_copy_callback_record_t>{}
|
||||
auto memory_allocation_cb_records = std::deque<memory_allocation_callback_record_t>{};
|
||||
auto rccl_api_cb_records = std::deque<rccl_api_callback_record_t>{};
|
||||
auto rocdecode_api_cb_records = std::deque<rocdecode_api_callback_record_t>{};
|
||||
auto rocjpeg_api_cb_records = std::deque<rocjpeg_api_callback_record_t>{};
|
||||
auto ompt_cb_records = std::deque<ompt_callback_record_t>{};
|
||||
|
||||
int
|
||||
@@ -856,6 +874,19 @@ tool_tracing_callback(rocprofiler_callback_tracing_record_t record,
|
||||
rocdecode_api_cb_records.emplace_back(
|
||||
rocdecode_api_callback_record_t{ts, record, *data, std::move(args)});
|
||||
}
|
||||
else if(record.kind == ROCPROFILER_CALLBACK_TRACING_ROCJPEG_API)
|
||||
{
|
||||
auto* data = static_cast<rocprofiler_callback_tracing_rocjpeg_api_data_t*>(record.payload);
|
||||
auto args = callback_arg_array_t{};
|
||||
if(record.phase == ROCPROFILER_CALLBACK_PHASE_EXIT)
|
||||
rocprofiler_iterate_callback_tracing_kind_operation_args(
|
||||
record, save_args, record.phase, &args);
|
||||
|
||||
static auto _mutex = std::mutex{};
|
||||
auto _lk = std::unique_lock<std::mutex>{_mutex};
|
||||
rocjpeg_api_cb_records.emplace_back(
|
||||
rocjpeg_api_callback_record_t{ts, record, *data, std::move(args)});
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error{"unsupported callback kind"};
|
||||
@@ -877,6 +908,7 @@ auto corr_id_retire_records =
|
||||
std::deque<rocprofiler_buffer_tracing_correlation_id_retirement_record_t>{};
|
||||
auto rccl_api_bf_records = std::deque<rocprofiler_buffer_tracing_rccl_api_record_t>{};
|
||||
auto rocdecode_api_bf_records = std::deque<rocprofiler_buffer_tracing_rocdecode_api_record_t>{};
|
||||
auto rocjpeg_api_bf_records = std::deque<rocprofiler_buffer_tracing_rocjpeg_api_record_t>{};
|
||||
auto ompt_bf_records = std::deque<rocprofiler_buffer_tracing_ompt_record_t>{};
|
||||
|
||||
void
|
||||
@@ -1011,6 +1043,13 @@ tool_tracing_buffered(rocprofiler_context_id_t /*context*/,
|
||||
|
||||
rocdecode_api_bf_records.emplace_back(*record);
|
||||
}
|
||||
else if(header->kind == ROCPROFILER_BUFFER_TRACING_ROCJPEG_API)
|
||||
{
|
||||
auto* record =
|
||||
static_cast<rocprofiler_buffer_tracing_rocjpeg_api_record_t*>(header->payload);
|
||||
|
||||
rocjpeg_api_bf_records.emplace_back(*record);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error{
|
||||
@@ -1111,6 +1150,8 @@ rocprofiler_context_id_t runtime_init_callback_ctx = {};
|
||||
rocprofiler_context_id_t runtime_init_buffered_ctx = {};
|
||||
rocprofiler_context_id_t rocdecode_api_callback_ctx = {0};
|
||||
rocprofiler_context_id_t rocdecode_api_buffered_ctx = {0};
|
||||
rocprofiler_context_id_t rocjpeg_api_callback_ctx = {0};
|
||||
rocprofiler_context_id_t rocjpeg_api_buffered_ctx = {0};
|
||||
|
||||
// buffers
|
||||
rocprofiler_buffer_id_t runtime_init_buffered_buffer = {};
|
||||
@@ -1126,6 +1167,7 @@ rocprofiler_buffer_id_t scratch_memory_buffer = {};
|
||||
rocprofiler_buffer_id_t corr_id_retire_buffer = {};
|
||||
rocprofiler_buffer_id_t rccl_api_buffered_buffer = {};
|
||||
rocprofiler_buffer_id_t rocdecode_api_buffer = {};
|
||||
rocprofiler_buffer_id_t rocjpeg_api_buffer = {};
|
||||
rocprofiler_buffer_id_t ompt_buffered_buffer = {};
|
||||
|
||||
auto contexts = std::unordered_map<std::string_view, rocprofiler_context_id_t*>{
|
||||
@@ -1153,10 +1195,12 @@ auto contexts = std::unordered_map<std::string_view, rocprofiler_context_id_t*>{
|
||||
{"RCCL_API_BUFFERED", &rccl_api_buffered_ctx},
|
||||
{"ROCDECODE_API_CALLBACK", &rocdecode_api_callback_ctx},
|
||||
{"ROCDECODE_API_BUFFERED", &rocdecode_api_buffered_ctx},
|
||||
{"ROCJPEG_API_CALLBACK", &rocjpeg_api_callback_ctx},
|
||||
{"ROCJPEG_API_BUFFERED", &rocjpeg_api_buffered_ctx},
|
||||
{"OMPT_BUFFERED", &ompt_buffered_ctx},
|
||||
};
|
||||
|
||||
auto buffers = std::array<rocprofiler_buffer_id_t*, 14>{&runtime_init_buffered_buffer,
|
||||
auto buffers = std::array<rocprofiler_buffer_id_t*, 15>{&runtime_init_buffered_buffer,
|
||||
&hsa_api_buffered_buffer,
|
||||
&hip_api_buffered_buffer,
|
||||
&marker_api_buffered_buffer,
|
||||
@@ -1169,7 +1213,8 @@ auto buffers = std::array<rocprofiler_buffer_id_t*, 14>{&runtime_init_buffered_b
|
||||
&corr_id_retire_buffer,
|
||||
&rccl_api_buffered_buffer,
|
||||
&ompt_buffered_buffer,
|
||||
&rocdecode_api_buffer};
|
||||
&rocdecode_api_buffer,
|
||||
&rocjpeg_api_buffer};
|
||||
|
||||
auto agents = std::vector<rocprofiler_agent_t>{};
|
||||
auto agents_map = std::unordered_map<rocprofiler_agent_id_t, rocprofiler_agent_t>{};
|
||||
@@ -1344,6 +1389,15 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
|
||||
nullptr),
|
||||
"rocdecode api callback tracing service configure");
|
||||
|
||||
ROCPROFILER_CALL(
|
||||
rocprofiler_configure_callback_tracing_service(rocjpeg_api_callback_ctx,
|
||||
ROCPROFILER_CALLBACK_TRACING_ROCJPEG_API,
|
||||
nullptr,
|
||||
0,
|
||||
tool_tracing_callback,
|
||||
nullptr),
|
||||
"rocjpeg api callback tracing service configure");
|
||||
|
||||
ROCPROFILER_CALL(
|
||||
rocprofiler_configure_callback_tracing_service(ompt_callback_ctx,
|
||||
ROCPROFILER_CALLBACK_TRACING_OMPT,
|
||||
@@ -1473,6 +1527,15 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
|
||||
&rocdecode_api_buffer),
|
||||
"buffer creation");
|
||||
|
||||
ROCPROFILER_CALL(rocprofiler_create_buffer(rocjpeg_api_buffered_ctx,
|
||||
buffer_size,
|
||||
watermark,
|
||||
ROCPROFILER_BUFFER_POLICY_LOSSLESS,
|
||||
tool_tracing_buffered,
|
||||
tool_data,
|
||||
&rocjpeg_api_buffer),
|
||||
"buffer creation");
|
||||
|
||||
ROCPROFILER_CALL(rocprofiler_create_buffer(ompt_buffered_ctx,
|
||||
buffer_size,
|
||||
watermark,
|
||||
@@ -1605,6 +1668,14 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
|
||||
rocdecode_api_buffer),
|
||||
"buffer tracing service for rocdecode api configure");
|
||||
|
||||
ROCPROFILER_CALL(
|
||||
rocprofiler_configure_buffer_tracing_service(rocjpeg_api_buffered_ctx,
|
||||
ROCPROFILER_BUFFER_TRACING_ROCJPEG_API,
|
||||
nullptr,
|
||||
0,
|
||||
rocjpeg_api_buffer),
|
||||
"buffer tracing service for rocjpeg api configure");
|
||||
|
||||
ROCPROFILER_CALL(
|
||||
rocprofiler_configure_buffer_tracing_service(
|
||||
ompt_buffered_ctx, ROCPROFILER_BUFFER_TRACING_OMPT, nullptr, 0, ompt_buffered_buffer),
|
||||
@@ -1775,7 +1846,9 @@ tool_fini(void* tool_data)
|
||||
<< ", ompt_bf_records=" << ompt_bf_records.size()
|
||||
<< ", counter_collection_value_records=" << counter_collection_bf_records.size()
|
||||
<< ", rocdecode_api_callback_records=" << rocdecode_api_cb_records.size()
|
||||
<< ", rocdecode_api_bf_records=" << rocdecode_api_bf_records.size() << "...\n"
|
||||
<< ", rocdecode_api_bf_records=" << rocdecode_api_bf_records.size()
|
||||
<< ", rocjpeg_api_callback_records=" << rocjpeg_api_cb_records.size()
|
||||
<< ", rocjpeg_api_bf_records=" << rocjpeg_api_bf_records.size() << "...\n"
|
||||
<< std::flush;
|
||||
|
||||
auto* _call_stack = static_cast<call_stack_t*>(tool_data);
|
||||
@@ -1872,6 +1945,7 @@ write_json(call_stack_t* _call_stack)
|
||||
json_ar(cereal::make_nvp("memory_copies", memory_copy_cb_records));
|
||||
json_ar(cereal::make_nvp("memory_allocations", memory_allocation_cb_records));
|
||||
json_ar(cereal::make_nvp("rocdecode_api_traces", rocdecode_api_cb_records));
|
||||
json_ar(cereal::make_nvp("rocjpeg_api_traces", rocjpeg_api_cb_records));
|
||||
} catch(std::exception& e)
|
||||
{
|
||||
std::cerr << "[" << getpid() << "][" << __FUNCTION__
|
||||
@@ -1899,6 +1973,7 @@ write_json(call_stack_t* _call_stack)
|
||||
json_ar(cereal::make_nvp("retired_correlation_ids", corr_id_retire_records));
|
||||
json_ar(cereal::make_nvp("counter_collection", counter_collection_bf_records));
|
||||
json_ar(cereal::make_nvp("rocdecode_api_traces", rocdecode_api_bf_records));
|
||||
json_ar(cereal::make_nvp("rocjpeg_api_traces", rocjpeg_api_bf_records));
|
||||
} catch(std::exception& e)
|
||||
{
|
||||
std::cerr << "[" << getpid() << "][" << __FUNCTION__
|
||||
@@ -1972,6 +2047,8 @@ write_perfetto()
|
||||
tids.emplace(itr.thread_id);
|
||||
for(auto itr : rocdecode_api_bf_records)
|
||||
tids.emplace(itr.thread_id);
|
||||
for(auto itr : rocjpeg_api_bf_records)
|
||||
tids.emplace(itr.thread_id);
|
||||
|
||||
for(auto itr : memory_copy_bf_records)
|
||||
{
|
||||
@@ -2266,6 +2343,47 @@ write_perfetto()
|
||||
itr.end_timestamp);
|
||||
}
|
||||
|
||||
for(auto itr : rocjpeg_api_bf_records)
|
||||
{
|
||||
auto name = buffer_names.at(itr.kind, itr.operation);
|
||||
auto& track = thread_tracks.at(itr.thread_id);
|
||||
|
||||
auto _args = callback_arg_array_t{};
|
||||
auto ritr = std::find_if(
|
||||
rocjpeg_api_cb_records.begin(),
|
||||
rocjpeg_api_cb_records.end(),
|
||||
[&itr](const auto& citr) {
|
||||
return (citr.record.correlation_id.internal == itr.correlation_id.internal &&
|
||||
!citr.args.empty());
|
||||
});
|
||||
if(ritr != rocjpeg_api_cb_records.end()) _args = ritr->args;
|
||||
|
||||
TRACE_EVENT_BEGIN(sdk::perfetto_category<sdk::category::rocjpeg_api>::name,
|
||||
::perfetto::StaticString(name.data()),
|
||||
track,
|
||||
itr.start_timestamp,
|
||||
::perfetto::Flow::ProcessScoped(itr.correlation_id.internal),
|
||||
"begin_ns",
|
||||
itr.start_timestamp,
|
||||
"tid",
|
||||
itr.thread_id,
|
||||
"kind",
|
||||
itr.kind,
|
||||
"operation",
|
||||
itr.operation,
|
||||
"corr_id",
|
||||
itr.correlation_id.internal,
|
||||
[&](::perfetto::EventContext ctx) {
|
||||
for(const auto& aitr : _args)
|
||||
sdk::add_perfetto_annotation(ctx, aitr.first, aitr.second);
|
||||
});
|
||||
TRACE_EVENT_END(sdk::perfetto_category<sdk::category::rocjpeg_api>::name,
|
||||
track,
|
||||
itr.end_timestamp,
|
||||
"end_ns",
|
||||
itr.end_timestamp);
|
||||
}
|
||||
|
||||
for(auto itr : ompt_bf_records)
|
||||
{
|
||||
auto name = buffer_names.at(itr.kind, itr.operation);
|
||||
|
||||
Reference in New Issue
Block a user