* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#include "mockcpp/mockcpp.hpp"
#include "gtest/gtest.h"
#include "prof_cann_plugin.h"
#include "prof_runtime_plugin.h"
#include "msprof_dlog.h"
#include "errno/error_code.h"
using namespace ProfAPI;
using namespace analysis::dvvp::common::error;
namespace {
int g_atlsReportApi = 0;
int g_atlsReportEvent = 0;
int g_atlsReportCompact = 0;
int g_atlsReportAdditional = 0;
int g_atlsReportRegType = 0;
int g_atlsHashIdCalled = 0;
int g_atlsHostFreqCalled = 0;
int g_atlsSetDeviceCalled = 0;
int32_t StubAtlsReportApi(uint32_t, const MsprofApi*) { ++g_atlsReportApi; return 0; }
int32_t StubAtlsReportEvent(uint32_t, const MsprofEvent*) { ++g_atlsReportEvent; return 0; }
int32_t StubAtlsReportCompact(uint32_t, const VOID_PTR, uint32_t) { ++g_atlsReportCompact; return 0; }
int32_t StubAtlsReportAdditional(uint32_t, const VOID_PTR, uint32_t) { ++g_atlsReportAdditional; return 0; }
int32_t StubAtlsReportRegType(uint16_t, uint32_t, const char*, size_t) { ++g_atlsReportRegType; return 0; }
uint64_t StubAtlsGetHashId(const char*, size_t) { ++g_atlsHashIdCalled; return 0xABCDEF12U; }
int8_t StubAtlsHostFreq() { ++g_atlsHostFreqCalled; return 1; }
int32_t StubAtlsSetDevice(VOID_PTR, uint32_t) { ++g_atlsSetDeviceCalled; return 0; }
int32_t StubProfReportRegDataFormat(uint16_t, uint32_t, const std::string&) { return 7; }
std::string StubProfReportGetHashInfo(uint64_t) { return "stub-hash-info"; }
std::string StubProfGetPath() { return "/var/tmp/prof"; }
bool StubProfHostFreqIsEnable() { return true; }
int32_t StubProfGetFeatureIsOn(uint64_t) { return 1; }
int32_t StubProfSubscribeRawData(MsprofRawDataCallback) { return 0; }
int32_t StubProfUnSubscribeRawData() { return 0; }
int32_t StubProfSetCommand(VOID_PTR, uint32_t) { return 0; }
int32_t StubProfNotifySetDevice(uint32_t, uint32_t, bool) { return 0; }
void* StubProfBatchAddBufPop(const ProfBatchAddBufPopCallback) { return nullptr; }
void StubProfBatchAddBufIndexShift(const ProfBatchAddBufIndexShiftCallBack) {}
void ResetAtlsCounters()
{
g_atlsReportApi = 0;
g_atlsReportEvent = 0;
g_atlsReportCompact = 0;
g_atlsReportAdditional = 0;
g_atlsReportRegType = 0;
g_atlsHashIdCalled = 0;
g_atlsHostFreqCalled = 0;
g_atlsSetDeviceCalled = 0;
}
void ClearAtlsHooks()
{
auto plugin = ProfCannPlugin::instance();
plugin->atlsReportApi_ = nullptr;
plugin->atlsReportEvent_ = nullptr;
plugin->atlsReportCompactInfo_ = nullptr;
plugin->atlsReportAdditionalInfo_ = nullptr;
plugin->atlsReportRegTypeInfo_ = nullptr;
plugin->atlsReportGetHashId_ = nullptr;
plugin->atlsHostFreqIsEnable_ = nullptr;
plugin->atlsSetDevice_ = nullptr;
}
void ClearProfHooks()
{
auto plugin = ProfCannPlugin::instance();
plugin->profReportRegDataFormat_ = nullptr;
plugin->profReportGetHashInfo_ = nullptr;
plugin->profGetPath_ = nullptr;
plugin->profHostFreqIsEnable_ = nullptr;
plugin->profGetFeatureIsOn_ = nullptr;
plugin->profSubscribeRawData_ = nullptr;
plugin->profUnSubscribeRawData_ = nullptr;
plugin->profSetProfCommand_ = nullptr;
plugin->profNotifySetDevice_ = nullptr;
plugin->profBatchAddBufPop_ = nullptr;
plugin->profBatchAddBufIndexShift_ = nullptr;
}
}
class PROF_CANN_PLUGIN_UTEST : public testing::Test {
protected:
virtual void SetUp()
{
ResetAtlsCounters();
ClearAtlsHooks();
ClearProfHooks();
}
virtual void TearDown()
{
ClearAtlsHooks();
ClearProfHooks();
GlobalMockObject::verify();
}
};
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfReportRegDataFormat_Variants)
{
auto plugin = ProfCannPlugin::instance();
EXPECT_EQ(0, plugin->ProfReportRegDataFormat(0, 1, "fmt", 3));
plugin->profReportRegDataFormat_ = StubProfReportRegDataFormat;
EXPECT_EQ(7, plugin->ProfReportRegDataFormat(0, 1, "fmt", 3));
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfReportGetHashInfo_Variants)
{
auto plugin = ProfCannPlugin::instance();
char *p = plugin->ProfReportGetHashInfo(123);
EXPECT_NE(nullptr, p);
plugin->profReportGetHashInfo_ = StubProfReportGetHashInfo;
p = plugin->ProfReportGetHashInfo(456);
EXPECT_STREQ("stub-hash-info", p);
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfGetPath_Variants)
{
auto plugin = ProfCannPlugin::instance();
char *p = plugin->profGetPath();
EXPECT_NE(nullptr, p);
plugin->profGetPath_ = StubProfGetPath;
p = plugin->profGetPath();
EXPECT_STREQ("/var/tmp/prof", p);
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfHostFreqIsEnable_Branches)
{
auto plugin = ProfCannPlugin::instance();
EXPECT_FALSE(plugin->ProfHostFreqIsEnable());
plugin->profHostFreqIsEnable_ = StubProfHostFreqIsEnable;
EXPECT_TRUE(plugin->ProfHostFreqIsEnable());
plugin->atlsHostFreqIsEnable_ = StubAtlsHostFreq;
EXPECT_TRUE(plugin->ProfHostFreqIsEnable());
EXPECT_GE(g_atlsHostFreqCalled, 1);
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfReportGetHashId_AtlsAndCb)
{
auto plugin = ProfCannPlugin::instance();
plugin->atlsReportGetHashId_ = StubAtlsGetHashId;
EXPECT_EQ(0xABCDEF12ULL, plugin->ProfReportGetHashId("aa", 2));
EXPECT_GE(g_atlsHashIdCalled, 1);
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfReportApi_AtlsHook)
{
auto plugin = ProfCannPlugin::instance();
plugin->atlsReportApi_ = StubAtlsReportApi;
MsprofApi api{};
EXPECT_EQ(0, plugin->ProfReportApi(0, &api));
EXPECT_EQ(1, g_atlsReportApi);
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfReportEvent_AtlsHook)
{
auto plugin = ProfCannPlugin::instance();
plugin->atlsReportEvent_ = StubAtlsReportEvent;
MsprofEvent ev{};
EXPECT_EQ(0, plugin->ProfReportEvent(0, &ev));
EXPECT_EQ(1, g_atlsReportEvent);
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfReportCompactInfo_AtlsHook)
{
auto plugin = ProfCannPlugin::instance();
plugin->atlsReportCompactInfo_ = StubAtlsReportCompact;
MsprofCompactInfo info{};
EXPECT_EQ(0, plugin->ProfReportCompactInfo(0, &info, sizeof(info)));
EXPECT_EQ(1, g_atlsReportCompact);
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfReportAdditionalInfo_AtlsHook)
{
auto plugin = ProfCannPlugin::instance();
plugin->atlsReportAdditionalInfo_ = StubAtlsReportAdditional;
MsprofAdditionalInfo info{};
EXPECT_EQ(0, plugin->ProfReportAdditionalInfo(0, &info, sizeof(info)));
EXPECT_EQ(1, g_atlsReportAdditional);
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfReportAdditionalInfo_LengthBoundary)
{
auto plugin = ProfCannPlugin::instance();
char buf[STANDARD_ADDITIONAL_INFO_LENGTH + 16] = {0};
EXPECT_EQ(PROFILING_FAILED, plugin->ProfReportAdditionalInfo(0, buf, MAX_VARIABLE_DATA_LENGTH + 1));
plugin->variableAdditionalBuffer_.Init("variable");
EXPECT_EQ(0, plugin->ProfReportAdditionalInfo(0, buf, STANDARD_ADDITIONAL_INFO_LENGTH + 16));
plugin->variableAdditionalBuffer_.UnInit();
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfReportRegTypeInfo_AtlsHook)
{
auto plugin = ProfCannPlugin::instance();
plugin->atlsReportRegTypeInfo_ = StubAtlsReportRegType;
EXPECT_EQ(0, plugin->ProfReportRegTypeInfo(0, 1, "type", 4));
EXPECT_EQ(1, g_atlsReportRegType);
}
TEST_F(PROF_CANN_PLUGIN_UTEST, RegisterProfileCallback_AtlsTypes)
{
auto plugin = ProfCannPlugin::instance();
EXPECT_EQ(PROFILING_SUCCESS, plugin->RegisterProfileCallback(PROFILE_CTRL_CALLBACK, nullptr, 0));
EXPECT_EQ(PROFILING_SUCCESS, plugin->RegisterProfileCallback(PROFILE_DEVICE_STATE_CALLBACK, nullptr, 0));
EXPECT_EQ(PROFILING_SUCCESS, plugin->RegisterProfileCallback(PROFILE_REPORT_API_CALLBACK, nullptr, 0));
EXPECT_EQ(PROFILING_SUCCESS, plugin->RegisterProfileCallback(PROFILE_REPORT_EVENT_CALLBACK, nullptr, 0));
EXPECT_EQ(PROFILING_SUCCESS, plugin->RegisterProfileCallback(PROFILE_REPORT_REG_TYPE_INFO_CALLBACK, nullptr, 0));
EXPECT_EQ(PROFILING_SUCCESS, plugin->RegisterProfileCallback(PROFILE_REPORT_REG_DATA_FORMAT_CALLBACK, nullptr, 0));
EXPECT_EQ(PROFILING_SUCCESS, plugin->RegisterProfileCallback(PROFILE_REPORT_GET_HASH_ID_CALLBACK, nullptr, 0));
EXPECT_EQ(PROFILING_SUCCESS, plugin->RegisterProfileCallback(PROFILE_HOST_FREQ_IS_ENABLE_CALLBACK, nullptr, 0));
EXPECT_EQ(PROFILING_SUCCESS, plugin->RegisterProfileCallback(PROFILE_REPORT_COMPACT_CALLBACK,
reinterpret_cast<VOID_PTR>(StubAtlsReportCompact), 0));
EXPECT_EQ(PROFILING_SUCCESS, plugin->RegisterProfileCallback(PROFILE_REPORT_ADDITIONAL_CALLBACK,
reinterpret_cast<VOID_PTR>(StubAtlsReportAdditional), 0));
}
TEST_F(PROF_CANN_PLUGIN_UTEST, RegisterProfileCallback_AtlsForkCases)
{
auto plugin = ProfCannPlugin::instance();
EXPECT_EQ(PROFILING_SUCCESS, plugin->RegisterProfileCallback(PROFILE_REPORT_API_C_CALLBACK,
reinterpret_cast<VOID_PTR>(StubAtlsReportApi), 0));
EXPECT_EQ(PROFILING_SUCCESS, plugin->RegisterProfileCallback(PROFILE_REPORT_EVENT_C_CALLBACK,
reinterpret_cast<VOID_PTR>(StubAtlsReportEvent), 0));
EXPECT_EQ(PROFILING_SUCCESS, plugin->RegisterProfileCallback(PROFILE_REPORT_REG_TYPE_INFO_C_CALLBACK,
reinterpret_cast<VOID_PTR>(StubAtlsReportRegType), 0));
EXPECT_EQ(PROFILING_SUCCESS, plugin->RegisterProfileCallback(PROFILE_REPORT_REG_DATA_FORMAT_C_CALLBACK,
nullptr, 0));
EXPECT_EQ(PROFILING_SUCCESS, plugin->RegisterProfileCallback(PROFILE_REPORT_GET_HASH_ID_C_CALLBACK,
reinterpret_cast<VOID_PTR>(StubAtlsGetHashId), 0));
EXPECT_EQ(PROFILING_SUCCESS, plugin->RegisterProfileCallback(PROFILE_HOST_FREQ_IS_ENABLE_C_CALLBACK,
reinterpret_cast<VOID_PTR>(StubAtlsHostFreq), 0));
EXPECT_EQ(PROFILING_SUCCESS, plugin->RegisterProfileCallback(PROFILE_DEVICE_STATE_C_CALLBACK,
reinterpret_cast<VOID_PTR>(StubAtlsSetDevice), 0));
EXPECT_EQ(PROFILING_FAILED, plugin->RegisterProfileCallback(0xFFFF, nullptr, 0));
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfNotifyCachedDevice_WithSetDevice)
{
auto plugin = ProfCannPlugin::instance();
plugin->ProfNotifySetDevice(1, 2, true);
plugin->atlsSetDevice_ = StubAtlsSetDevice;
plugin->ProfNotifyCachedDevice();
EXPECT_GE(g_atlsSetDeviceCalled, 1);
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfNotifyCachedDevice_NullCallback)
{
auto plugin = ProfCannPlugin::instance();
plugin->atlsSetDevice_ = nullptr;
plugin->ProfNotifyCachedDevice();
EXPECT_EQ(0, g_atlsSetDeviceCalled);
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfNotifySetDevice_AtlsBranch)
{
auto plugin = ProfCannPlugin::instance();
plugin->atlsSetDevice_ = StubAtlsSetDevice;
EXPECT_EQ(0, plugin->ProfNotifySetDevice(3, 4, true));
EXPECT_GE(g_atlsSetDeviceCalled, 1);
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfNotifySetDevice_NotifyCallback)
{
auto plugin = ProfCannPlugin::instance();
plugin->profNotifySetDevice_ = StubProfNotifySetDevice;
EXPECT_EQ(0, plugin->ProfNotifySetDevice(5, 6, false));
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfSetStepInfo_RuntimeInitFail)
{
auto plugin = ProfCannPlugin::instance();
MOCKER_CPP(&ProfRuntimePlugin::RuntimeApiInit).stubs().will(returnValue((int32_t)PROFILING_FAILED));
EXPECT_EQ(PROFILING_FAILED, plugin->ProfSetStepInfo(1, 2, nullptr));
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfSetStepInfo_MarkExFail)
{
auto plugin = ProfCannPlugin::instance();
MOCKER_CPP(&ProfRuntimePlugin::RuntimeApiInit).stubs().will(returnValue((int32_t)PROFILING_SUCCESS));
MOCKER_CPP(&ProfRuntimePlugin::ProfMarkEx).stubs().will(returnValue((int32_t)1));
EXPECT_EQ(1, plugin->ProfSetStepInfo(1, 2, nullptr));
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfSetStepInfo_Success)
{
auto plugin = ProfCannPlugin::instance();
MOCKER_CPP(&ProfRuntimePlugin::RuntimeApiInit).stubs().will(returnValue((int32_t)PROFILING_SUCCESS));
MOCKER_CPP(&ProfRuntimePlugin::ProfMarkEx).stubs().will(returnValue((int32_t)RT_ERROR_NONE));
EXPECT_EQ(PROFILING_SUCCESS, plugin->ProfSetStepInfo(1, 2, nullptr));
}
TEST_F(PROF_CANN_PLUGIN_UTEST, BuildApiInfo_FillsFields)
{
auto plugin = ProfCannPlugin::instance();
MsprofApi api{};
plugin->BuildApiInfo({100ULL, 200ULL}, 99, 7ULL, api);
EXPECT_EQ(7ULL, api.itemId);
EXPECT_EQ(100ULL, api.beginTime);
EXPECT_EQ(200ULL, api.endTime);
EXPECT_EQ(99u, api.type);
EXPECT_EQ(MSPROF_REPORT_NODE_LEVEL, api.level);
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ReportApiInfo_Path)
{
auto plugin = ProfCannPlugin::instance();
plugin->ProfInitReportBuf(MSPROF_CTRL_INIT_ACL_ENV);
EXPECT_EQ(PROFILING_SUCCESS, plugin->ReportApiInfo(1, 2, 3, 4));
plugin->ProfUnInitReportBuf();
}
TEST_F(PROF_CANN_PLUGIN_UTEST, AdprofFeature_And_RawData)
{
auto plugin = ProfCannPlugin::instance();
EXPECT_EQ(0, plugin->ProfAdprofCheckFeatureIsOn(1));
plugin->profGetFeatureIsOn_ = StubProfGetFeatureIsOn;
EXPECT_EQ(1, plugin->ProfAdprofCheckFeatureIsOn(1));
EXPECT_EQ(0, plugin->ProfSubscribeRawData(nullptr));
plugin->profSubscribeRawData_ = StubProfSubscribeRawData;
EXPECT_EQ(0, plugin->ProfSubscribeRawData(nullptr));
EXPECT_EQ(0, plugin->ProfUnSubscribeRawData());
plugin->profUnSubscribeRawData_ = StubProfUnSubscribeRawData;
EXPECT_EQ(0, plugin->ProfUnSubscribeRawData());
}
TEST_F(PROF_CANN_PLUGIN_UTEST, BatchReport_PopAndIndexShift)
{
auto plugin = ProfCannPlugin::instance();
plugin->ProfInitDevReportBuf();
MsprofAdditionalInfo info{};
EXPECT_EQ(0, plugin->ProfReportBatchAdditionalInfo(0, &info, sizeof(info)));
EXPECT_EQ(static_cast<size_t>(131072), plugin->ProfGetBatchReportMaxSize(MSPROF_BATCH_ADDITIONAL_INFO));
EXPECT_EQ(static_cast<size_t>(0), plugin->ProfGetBatchReportMaxSize(0xFFFF));
size_t popSize = 0;
void *ptr = TryPopAdprofBuf(popSize, true);
if (ptr != nullptr) {
TryIndexShiftAdprofBuf(ptr, popSize);
}
plugin->profBatchAddBufPop_ = StubProfBatchAddBufPop;
plugin->profBatchAddBufIndexShift_ = StubProfBatchAddBufIndexShift;
plugin->ProfRegisterFunc(REPORT_ADPROF_POP, reinterpret_cast<VOID_PTR>(TryPopAdprofBuf));
plugin->ProfRegisterFunc(REPORT_ADPROF_INDEX_SHIFT, reinterpret_cast<VOID_PTR>(TryIndexShiftAdprofBuf));
}
TEST_F(PROF_CANN_PLUGIN_UTEST, VariableAdditional_PopAndIndexShift)
{
auto plugin = ProfCannPlugin::instance();
plugin->ProfInitReportBuf(MSPROF_CTRL_INIT_ACL_ENV);
size_t popSize = 0;
void *ptr = TryPopVariableAdditionalBuf(popSize);
if (ptr != nullptr) {
TryIndexShiftVariableAddBuf(ptr, popSize);
}
plugin->ProfUnInitReportBuf();
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfRegisterFunc_AllBranches)
{
auto plugin = ProfCannPlugin::instance();
plugin->ProfRegisterFunc(0xDEADBEEF, nullptr);
plugin->ProfRegisterFunc(REPORT_VARIABLE_ADDITIONAL_POP,
reinterpret_cast<VOID_PTR>(TryPopVariableAdditionalBuf));
plugin->ProfRegisterFunc(REPORT_VARIABLE_ADDITIONAL_INDEX_SHIFT,
reinterpret_cast<VOID_PTR>(TryIndexShiftVariableAddBuf));
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfSetProfCommand_NullAndCb)
{
auto plugin = ProfCannPlugin::instance();
EXPECT_EQ(PROFILING_FAILED, plugin->ProfSetProfCommand(nullptr, 0));
plugin->profSetProfCommand_ = StubProfSetCommand;
EXPECT_EQ(0, plugin->ProfSetProfCommand(nullptr, 0));
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfCheckCommandLine_NoEnv)
{
auto plugin = ProfCannPlugin::instance();
(void)plugin->ProfCheckCommandLine();
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfGetModuleName_KnownAndUnknown)
{
EXPECT_STREQ("HCCL", ProfGetModuleName(3));
EXPECT_STREQ("RUNTIME", ProfGetModuleName(7));
EXPECT_STREQ("GE", ProfGetModuleName(45));
EXPECT_STREQ("ASCENDCL", ProfGetModuleName(48));
EXPECT_STREQ("UNKNOWN", ProfGetModuleName(9999));
}
TEST_F(PROF_CANN_PLUGIN_UTEST, ProfGetCommandTypeName_KnownAndUnknown)
{
EXPECT_STREQ("INIT", ProfGetCommandTypeName(0));
EXPECT_STREQ("START", ProfGetCommandTypeName(1));
EXPECT_STREQ("STOP", ProfGetCommandTypeName(2));
EXPECT_STREQ("FINALIZE", ProfGetCommandTypeName(3));
EXPECT_STREQ("UNKNOWN", ProfGetCommandTypeName(9999));
}