Files
TheRock/rocm-libraries/projects/miopen/test/gtest/log.cpp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

459 lines
15 KiB
C++

/*******************************************************************************
*
* MIT License
*
* Copyright (c) 2022 Advanced Micro Devices, Inc.
*
* 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 <cstdio>
#include <cstdlib>
#include "log.hpp"
#include "tensor_util.hpp"
#include "get_handle.hpp"
#include "../lib_env_var.hpp"
#include <gtest/gtest_common.hpp>
#include <miopen/config.h>
#include <miopen/fusion_plan.hpp>
#include <miopen/logger.hpp>
#include "../random.hpp"
#ifdef _WIN32
#define MDEXE "MIOpenDriver.exe"
#else
#define MDEXE "./bin/MIOpenDriver"
#endif
const std::string logConv =
"MIOpen: Command [LogCmdConvolution] " MDEXE " conv -n 128 -c 3 -H 32 -W 32 -k "
"64 -y 3 -x 3 -p 1 -q 1 -u 1 -v 1 -l 1 -j 1 -m conv -g 1 -F 1 -t 1";
const std::string logFindConv =
"MIOpen: Command [LogCmdFindConvolution] " MDEXE " conv -n 128 -c 3 -H 32 -W 32 "
"-k 64 -y 3 -x 3 -p 1 -q 1 -u 1 -v 1 -l 1 -j 1 -m conv -g 1 -F 1 -t 1";
const std::string logFusionConvBiasActiv =
"MIOpen: Command [LogCmdFusion] " MDEXE " CBAInfer -J 4 -n 128 -c 3 -H 32 "
"-W 32 -k 64 -y 3 -x 3 -p 1 -q 1 -u 1 -v 1 -l 1 -j 1";
const std::string logBnormActiv =
"MIOpen: Command [LogCmdFusion] " MDEXE " CBAInfer -J 2 -n 64 -c 64 -H 56 -W 56 -m 1";
// Captures the std::cerr buffer and store it to a string.
struct CerrRedirect
{
public:
CerrRedirect()
{
// Store the current stream buffer object and set
// stringstream as a new stream buffer.
old_stream_buf = std::cerr.rdbuf(str_buffer.rdbuf());
EXPECT_TRUE(old_stream_buf != nullptr);
}
std::string getString() { return str_buffer.str(); }
~CerrRedirect()
{
// reset the old stream buffer back
std::cerr.rdbuf(old_stream_buf);
}
private:
std::streambuf* old_stream_buf;
std::stringstream str_buffer;
};
struct Tensor
{
miopenTensorDescriptor_t desc{};
size_t data_size;
void* data;
Tensor(int n, int c, int h, int w)
{
EXPECT_EQ(miopenCreateTensorDescriptor(&desc), 0);
EXPECT_EQ(miopenSet4dTensorDescriptor(desc, miopenFloat, n, c, h, w), 0);
data_size = n * c * h * w * sizeof(float);
// ASSERT_* cannot be used in constructors (generates illegal
// return-void). Use hard abort on allocation failure instead.
auto err = hipMalloc(&data, data_size);
if(err != hipSuccess)
{
fprintf(stderr,
"hipMalloc failed: %s at %s:%d\n",
hipGetErrorString(err),
__FILE__,
__LINE__);
abort();
}
}
~Tensor()
{
miopenDestroyTensorDescriptor(desc);
(void)hipFree(data);
}
};
struct Conv
{
Tensor input;
Tensor output;
Tensor weights;
Tensor bias;
miopenConvolutionDescriptor_t convDesc;
Conv()
: input(128, 3, 32, 32), output(128, 64, 32, 32), weights(64, 3, 3, 3), bias(64, 1, 32, 1)
{
EXPECT_EQ(miopenCreateConvolutionDescriptor(&convDesc), 0);
EXPECT_EQ(miopenInitConvolutionDescriptor(convDesc, miopenConvolution, 1, 1, 1, 1, 1, 1),
0);
}
~Conv() { miopenDestroyConvolutionDescriptor(convDesc); }
};
struct CreateCBAFusionPlan
{
miopenFusionPlanDescriptor_t fusePlanDesc = nullptr;
miopen::OperatorArgs op_args;
~CreateCBAFusionPlan()
{
if(fusePlanDesc != nullptr)
{
miopenDestroyFusionPlan(fusePlanDesc);
}
}
void CBAPlan()
{
Conv conv_obj;
miopenCreateFusionPlan(&fusePlanDesc, miopenVerticalFusion, conv_obj.input.desc);
auto convoOp = std::make_shared<miopen::ConvForwardOpDescriptor>(
miopen::deref(conv_obj.convDesc), miopen::deref(conv_obj.weights.desc));
auto biasOp =
std::make_shared<miopen::BiasFusionOpDescriptor>(miopen::deref(conv_obj.weights.desc));
auto activOp = std::make_shared<miopen::ActivFwdFusionOpDescriptor>(miopenActivationRELU);
miopen::deref(fusePlanDesc).AddOp(convoOp);
miopen::deref(fusePlanDesc).AddOp(biasOp);
miopen::deref(fusePlanDesc).AddOp(activOp);
}
};
template <typename T>
struct CreateBNormFusionPlan
{
miopenFusionPlanDescriptor_t fusePlanDesc = nullptr;
miopen::OperatorArgs op_args;
~CreateBNormFusionPlan()
{
if(fusePlanDesc != nullptr)
{
miopenDestroyFusionPlan(fusePlanDesc);
}
}
miopen::TensorDescriptor bn_desc;
miopen::ActivationDescriptor activ_desc;
miopenBatchNormMode_t bn_mode = miopenBNSpatial;
tensor<T> input;
tensor<T> output;
tensor<T> scale;
tensor<T> shift;
tensor<T> estMean;
tensor<T> estVariance;
miopen::Allocator::ManageDataPtr in_dev;
miopen::Allocator::ManageDataPtr out_dev;
miopen::Allocator::ManageDataPtr scale_dev;
miopen::Allocator::ManageDataPtr shift_dev;
miopen::Allocator::ManageDataPtr estMean_dev;
miopen::Allocator::ManageDataPtr estVariance_dev;
miopenActivationMode_t activ_mode = miopenActivationRELU;
const float alpha{1.0f};
const float beta{0.0f};
const float activ_alpha{0.5f};
const float activ_beta{0.5f};
const float activ_gamma{0.5f};
double epsilon{1.0e-5};
std::vector<int> input_lens = {64, 64, 56, 56};
void Init()
{
input = tensor<T>{input_lens};
auto derivedBnDesc = miopen::TensorDescriptor{};
miopenDeriveBNTensorDescriptor(&derivedBnDesc, &input.desc, bn_mode);
scale = tensor<T>{input_lens};
shift = tensor<T>{input_lens};
estMean = tensor<T>{input_lens};
estVariance = tensor<T>{input_lens};
auto gen_value = [](auto...) { return prng::gen_descreet_uniform_sign<T>(1e-2, 100); };
input.generate(gen_value);
scale.generate(gen_value);
shift.generate(gen_value);
estMean.generate(gen_value);
auto gen_var = [](auto...) { return static_cast<T>(1e-2 * (prng::gen_0_to_B(100) + 1)); };
estVariance.generate(gen_var);
activ_desc = {activ_mode, activ_alpha, activ_beta, activ_gamma};
output = tensor<T>{input_lens};
auto&& handle = get_handle();
std::fill(output.begin(), output.end(), std::numeric_limits<T>::quiet_NaN());
in_dev = handle.Write(input.data);
scale_dev = handle.Write(scale.data);
shift_dev = handle.Write(shift.data);
estMean_dev = handle.Write(estMean.data);
estVariance_dev = handle.Write(estVariance.data);
out_dev = handle.Write(output.data);
}
void BNormActivation()
{
Init();
miopenCreateFusionPlan(&fusePlanDesc, miopenVerticalFusion, &input.desc);
activ_desc = {activ_mode, activ_alpha, activ_beta, activ_gamma};
auto bnOp =
std::make_shared<miopen::BatchNormInferenceFusionOpDescriptor>(bn_mode, bn_desc);
EXPECT_EQ(miopen::deref(fusePlanDesc).AddOp(bnOp), miopenStatusSuccess);
bnOp->SetArgs(op_args,
&alpha,
&beta,
scale_dev.get(),
shift_dev.get(),
estMean_dev.get(),
estVariance_dev.get(),
epsilon);
auto activOp = std::make_shared<miopen::ActivFwdFusionOpDescriptor>(activ_desc.GetMode());
EXPECT_EQ(miopen::deref(fusePlanDesc).AddOp(activOp), miopenStatusSuccess);
activOp->SetArgs(op_args, &alpha, &beta, activ_alpha, activ_beta, activ_gamma);
}
};
static bool isSubStr(const std::string& str, const std::string& sub_str)
{
return str.find(sub_str) != std::string::npos;
}
MIOPEN_LIB_ENV_VAR(MIOPEN_ENABLE_LOGGING_CMD)
void TestLogFun(std::function<void(const miopenTensorDescriptor_t&,
const miopenTensorDescriptor_t&,
const miopenConvolutionDescriptor_t&,
const miopenTensorDescriptor_t&,
const miopen::debug::ConvDirection&,
bool)> const& func,
std::string sub_str,
bool set_env)
{
CerrRedirect capture_cerr;
Conv test_conv_log;
if(set_env)
lib_env::update(MIOPEN_ENABLE_LOGGING_CMD, true);
else
lib_env::clear(MIOPEN_ENABLE_LOGGING_CMD);
func(test_conv_log.input.desc,
test_conv_log.weights.desc,
test_conv_log.convDesc,
test_conv_log.output.desc,
miopen::debug::ConvDirection::Fwd,
false);
std::string str = capture_cerr.getString();
if(set_env)
ASSERT_TRUE(isSubStr(str, sub_str)) << "str : " << str << "str_sub : " << sub_str;
else
ASSERT_FALSE(isSubStr(str, sub_str)) << "str : " << str << "str_sub : " << sub_str;
}
void TestLogCmdCBAFusion(std::function<void(const miopenFusionPlanDescriptor_t)> const& func,
std::string sub_str,
bool set_env)
{
CerrRedirect capture_cerr;
if(set_env)
lib_env::update(MIOPEN_ENABLE_LOGGING_CMD, true);
else
lib_env::clear(MIOPEN_ENABLE_LOGGING_CMD);
CreateCBAFusionPlan fp_cba_create;
fp_cba_create.CBAPlan();
func(fp_cba_create.fusePlanDesc);
std::string str = capture_cerr.getString();
if(set_env)
ASSERT_TRUE(isSubStr(str, sub_str)) << "str : " << str << "str_sub : " << sub_str;
else
ASSERT_FALSE(isSubStr(str, sub_str)) << "str : " << str << "str_sub : " << sub_str;
}
void TestLogCmdBNormFusion(std::function<void(const miopenFusionPlanDescriptor_t)> const& func,
std::string sub_str,
bool set_env)
{
CerrRedirect capture_cerr;
if(set_env)
lib_env::update(MIOPEN_ENABLE_LOGGING_CMD, true);
else
lib_env::clear(MIOPEN_ENABLE_LOGGING_CMD);
CreateBNormFusionPlan<float> fp_bnorm_create;
fp_bnorm_create.BNormActivation();
func(fp_bnorm_create.fusePlanDesc);
std::string str = capture_cerr.getString();
if(set_env)
ASSERT_TRUE(isSubStr(str, sub_str)) << "str : " << str << "str_sub : " << sub_str;
else
ASSERT_FALSE(isSubStr(str, sub_str)) << "str : " << str << "str_sub : " << sub_str;
}
void TestLogBufferEnvEnabled()
{
auto filename =
fs::temp_directory_path() / ("miopen_error_" + std::to_string(getpid()) + ".log");
size_t line_i = 0;
std::string line;
fs::remove(filename);
ScopedEnvironment<std::string> log_level_env(MIOPEN_LOG_LEVEL,
"5"); // miopen::LoggingLevel::Info
ScopedEnvironment<std::string> log_buffer_on_env(MIOPEN_LOG_BUFFER_SIZE,
"128"); // enable logging
// test log dump after error
miopen::ClearLogBuffer();
MIOPEN_LOG_W("warn");
MIOPEN_LOG_I("info");
MIOPEN_LOG_I2("info2");
MIOPEN_LOG_T("trace");
MIOPEN_LOG_E("error");
ASSERT_TRUE(fs::exists(filename));
{
auto log_file = std::ifstream{filename};
while(std::getline(log_file, line))
{
switch(line_i)
{
case 0: ASSERT_TRUE(isSubStr(line, "warn")); break;
case 1: ASSERT_TRUE(isSubStr(line, "info")); break;
case 2: ASSERT_TRUE(isSubStr(line, "info2")); break;
case 3: ASSERT_TRUE(isSubStr(line, "error")); break;
case 4: ASSERT_TRUE(isSubStr(line, "")); break;
}
line_i++;
}
}
// test log dump after 2nd error
MIOPEN_LOG_W("warn 2nd");
MIOPEN_LOG_I("info 2nd");
MIOPEN_LOG_I2("info2 2nd");
MIOPEN_LOG_T("trace 2nd");
MIOPEN_LOG_E("error 2nd");
EXPECT_TRUE(fs::exists(filename));
{
auto log_file = std::ifstream{filename};
line_i = 0;
while(std::getline(log_file, line))
{
switch(line_i)
{
case 0: ASSERT_TRUE(isSubStr(line, "warn")); break;
case 1: ASSERT_TRUE(isSubStr(line, "info")); break;
case 2: ASSERT_TRUE(isSubStr(line, "info2")); break;
case 3: ASSERT_TRUE(isSubStr(line, "error")); break;
case 4: ASSERT_TRUE(isSubStr(line, "")); break;
case 5: ASSERT_TRUE(isSubStr(line, "warn 2nd")); break;
case 6: ASSERT_TRUE(isSubStr(line, "info 2nd")); break;
case 7: ASSERT_TRUE(isSubStr(line, "info2 2nd")); break;
case 8: ASSERT_TRUE(isSubStr(line, "error 2nd")); break;
case 9: ASSERT_TRUE(isSubStr(line, "")); break;
}
line_i++;
}
ASSERT_TRUE(line_i == 10);
}
fs::remove(filename);
EXPECT_ANY_THROW({ MIOPEN_THROW("throw"); });
ASSERT_FALSE(fs::exists(filename));
}
void TestLogBufferOff()
{
auto filename =
fs::temp_directory_path() / ("miopen_error_" + std::to_string(getpid()) + ".log");
fs::remove(filename);
ScopedEnvironment<std::string> log_level_env(MIOPEN_LOG_LEVEL,
"5"); // miopen::LoggingLevel::Info
miopen::ClearLogBuffer();
// log messages
MIOPEN_LOG_W("warn");
MIOPEN_LOG_I("info");
MIOPEN_LOG_I2("info2");
MIOPEN_LOG_T("trace");
// test log dump after error
MIOPEN_LOG_E("error");
ASSERT_FALSE(fs::exists(filename));
}
void TestLogBufferOffAtHighLevel()
{
auto filename =
fs::temp_directory_path() / ("miopen_error_" + std::to_string(getpid()) + ".log");
fs::remove(filename);
ScopedEnvironment<std::string> log_level_env(MIOPEN_LOG_LEVEL,
"6"); // miopen::LoggingLevel::Info2
ScopedEnvironment<std::string> log_buffer_on_env(MIOPEN_LOG_BUFFER_SIZE,
"128"); // enable logging
miopen::ClearLogBuffer();
// log messages
MIOPEN_LOG_W("warn");
MIOPEN_LOG_I("info");
MIOPEN_LOG_I2("info2");
MIOPEN_LOG_T("trace");
// test log dump after error
MIOPEN_LOG_E("error");
ASSERT_FALSE(fs::exists(filename));
}