* 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 <iostream>
#include <fstream>
#include "gtest/gtest.h"
#include "mockcpp/mockcpp.hpp"
#include "mmpa_api.h"
#include "osal/osal.h"
#include "osal/osal_mem.h"
#include "errno/error_code.h"
#include "hal/hal_prof.h"
#include "hal/hal_dsmi.h"
#include "platform.h"
#include "platform_define.h"
#include "platform_table.h"
#include "platform_interface.h"
#include "platform_feature.h"
#include "chip/chip_nano_v1.h"
#include "json/json_parser.h"
#include "json/json_generator.h"
#include "securec.h"
#include "prof_api.h"
#include "thread_pool.h"
#include "channel_manager.h"
#include "param/profile_param.h"
#include "transport/uploader.h"
#include "flash_transport.h"
static const char C_RM_RF[] = "rm -rf ./acljsonCstest_workspace";
static const char C_MKDIR[] = "mkdir ./acljsonCstest_workspace";
static const char C_OUTPUT_DIR[] = "./acljsonCstest_workspace/output";
class BasicCStest: public testing::Test {
protected:
virtual void SetUp()
{
}
virtual void TearDown()
{
GlobalMockObject::verify();
GlobalMockObject::reset();
}
};
TEST_F(BasicCStest, PlatformBase)
{
MOCKER(HalGetChipVersion)
.stubs()
.will(returnValue(uint32_t(PlatformType::CHIP_NANO_V1)));
MOCKER(HalGetHostFreq)
.stubs()
.will(returnValue((uint64_t)10000));
uint32_t count = 0;
int32_t ret = PlatformInitialize(&count);
EXPECT_EQ(ret, PROFILING_SUCCESS);
MOCKER(HalGetDeviceFreq)
.stubs()
.will(returnValue((uint64_t)50000))
.then(returnValue((uint64_t)0));
EXPECT_EQ(PlatformGetDefaultDevFreq(), (uint64_t)NANO_HWTS_DEFAULT_FREQ);
EXPECT_EQ(PlatformGetDevFreq(0), 50);
EXPECT_EQ(PlatformGetDevFreq(0), 50);
EXPECT_EQ(PlatformGetHostFreq(), 10);
EXPECT_EQ(IsSupportBit(PROF_AICORE_METRICS), true);
EXPECT_EQ(IsSupportBit(PROF_AICPU_TRACE), false);
const char *versionInfo = PlatformGetVersionInfo();
EXPECT_EQ(strcmp(versionInfo, "1.0"), 0);
char* metrics = PlatformGetDefaultMetrics();
EXPECT_EQ(strcmp(metrics, "PipeUtilization"), 0);
PlatformFinalize(&count);
EXPECT_EQ(IsSupportBit(PROF_AICORE_METRICS), false);
EXPECT_EQ(PlatformGetHostFreq(), 0);
EXPECT_EQ(PlatformGetDevFreq(0), 0);
EXPECT_EQ(PlatformGetDefaultDevFreq(), 0);
char* metrics2 = PlatformGetDefaultMetrics();
EXPECT_EQ((metrics2 == NULL), true);
}
TEST_F(BasicCStest, MsprofSysCycleTimeBase)
{
MOCKER(HalGetChipVersion)
.stubs()
.will(returnValue(uint32_t(PlatformType::CHIP_NANO_V1)));
MOCKER(HalGetHostFreq)
.stubs()
.will(returnValue((uint32_t)10000));
uint32_t count = 0;
int32_t ret = PlatformInitialize(&count);
EXPECT_EQ(ret, PROFILING_SUCCESS);
EXPECT_EQ(PlatformHostFreqIsEnable(), true);
MOCKER(PlatformHostFreqIsEnable)
.stubs()
.will(returnValue(true))
.then(returnValue(false));
uint64_t cycleTime = MsprofSysCycleTime();
EXPECT_EQ((cycleTime > 0), true);
cycleTime = MsprofSysCycleTime();
EXPECT_EQ((cycleTime > 0), true);
}
void* MallocStubC(int size)
{
return malloc(size);
}
int32_t g_mallocCCnt = 0;
void* MallocTestC(int size)
{
void* ret = nullptr;
if (g_mallocCCnt != 0) {
ret = MallocStubC(size);
}
g_mallocCCnt--;
return ret;
}
TEST_F(BasicCStest, ThreadPoolBase)
{
GlobalMockObject::verify();
int32_t ret = ProfThreadPoolInit(1000, 5, 20);
EXPECT_EQ(ret, PROFILING_SUCCESS);
ProfThreadPoolFinalize();
MOCKER(OsalMalloc)
.stubs()
.will(invoke(MallocTestC));
int32_t successCnt = 0;
g_mallocCCnt = successCnt++;
ret = ProfThreadPoolInit(1000, 5, 20);
EXPECT_EQ(ret, PROFILING_FAILED);
g_mallocCCnt = successCnt++;
ret = ProfThreadPoolInit(1000, 5, 20);
EXPECT_EQ(ret, PROFILING_FAILED);
g_mallocCCnt = successCnt++;
ret = ProfThreadPoolInit(1000, 5, 20);
EXPECT_EQ(ret, PROFILING_FAILED);
ProfThreadPoolFinalize();
}
TEST_F(BasicCStest, ChannelMgrFlushUnInit)
{
GlobalMockObject::verify();
EXPECT_EQ(GetChannelIdByIndex(0, 0), 0);
}
extern "C" {
typedef struct ICollectionJob {
int32_t channelId;
int32_t devId;
int32_t jobId;
const ProfileParam *params;
int32_t (*Init)(struct ICollectionJob*);
int32_t (*Process)(struct ICollectionJob*);
int32_t (*Uninit)(struct ICollectionJob*);
} ICollectionJob;
typedef struct {
bool isStart;
bool quit;
uint32_t deviceId;
const ProfileParam *params;
ICollectionJob* collectionJobs[PROF_CHANNEL_MAX];
} JobManagerAttribute;
#define NANO_PMU_EVENT_MAX_NUM 10
typedef struct {
uint32_t tag;
uint32_t eventNum;
uint16_t event[NANO_PMU_EVENT_MAX_NUM];
} TagNanoStarsProfileConfig;
typedef struct {
ICollectionJob baseJob;
} NanoStarsJobAttribute;
ICollectionJob* FactoryCreateJob(int32_t channelId);
int32_t JobManagerStart(JobManagerAttribute *attr);
int32_t JobManagerStop(JobManagerAttribute *attr);
int32_t NanoJobInit(ICollectionJob *attr);
int32_t NanoJobProcess(ICollectionJob *attr);
int32_t NanoJobUninit(ICollectionJob *attr);
}
TEST_F(BasicCStest, FactoryCreateJobError)
{
GlobalMockObject::verify();
bool ret = false;
if (FactoryCreateJob(0) == nullptr) {
ret = true;
}
EXPECT_TRUE(ret);
}
TEST_F(BasicCStest, SliceBase)
{
GlobalMockObject::verify();
char* numStr = Slice("200MB", 3, 4);
bool ret = false;
if (numStr == nullptr) {
ret = true;
}
EXPECT_EQ(ret, false);
OSAL_MEM_FREE(numStr);
}
TEST_F(BasicCStest, CheckDataTypeBase)
{
GlobalMockObject::verify();
ProfileParam ut_profileParam = { 0 };
uint32_t errorType = 100;
const int32_t DEFSIZE = 4096;
char data[DEFSIZE] = "{\"aic_metrics\":\"PipeStallCycle\",\"output\":\"./output_dir\",\"switch\":\"on\",\"task_trace\":\"off\"}";
EXPECT_EQ(GenProfileParam(MSPROF_CTRL_INIT_ACL_JSON, data, sizeof(data), &ut_profileParam), PROFILING_SUCCESS);
EXPECT_EQ(GenProfileParam(MSPROF_CTRL_INIT_GE_OPTIONS, data, sizeof(data), &ut_profileParam), PROFILING_SUCCESS);
EXPECT_EQ(GenProfileParam(MSPROF_CTRL_INIT_HELPER, data, sizeof(data), &ut_profileParam), PROFILING_SUCCESS);
EXPECT_EQ(GenProfileParam(MSPROF_CTRL_INIT_PURE_CPU, data, sizeof(data), &ut_profileParam), PROFILING_SUCCESS);
EXPECT_EQ(GenProfileParam(UINT32_MAX, data, sizeof(data), &ut_profileParam), PROFILING_FAILED);
}
TEST_F(BasicCStest, StorageLimitBase)
{
GlobalMockObject::verify();
ProfileParam ut_profileParam = { 0 };
uint32_t errorType = 100;
const int32_t DEFSIZE = 4096;
char data[DEFSIZE] = "{\"aic_metrics\":\"PipeUtilization\",\"output\":\"./output_dir\",\"switch\":\"on\",\"task_trace\":\"on\",\"storage_limit\":\"200MB\"}";
EXPECT_EQ(GenProfileParam(MSPROF_CTRL_INIT_ACL_JSON, data, sizeof(data), &ut_profileParam), PROFILING_FAILED);
MOCKER(IsSupportSwitch)
.stubs()
.will(returnValue(true));
EXPECT_EQ(GenProfileParam(MSPROF_CTRL_INIT_ACL_JSON, data, sizeof(data), &ut_profileParam), PROFILING_SUCCESS);
}
TEST_F(BasicCStest, HalGetChipVersionBase)
{
int64_t info = -1;
MOCKER(halGetDeviceInfo)
.stubs()
.with(any(), any(), any(), outBoundP(&info, sizeof(info)))
.will(returnValue(DRV_ERROR_INVALID_VALUE));
EXPECT_EQ(0, HalGetChipVersion());
}
TEST_F(BasicCStest, HalGetHostFreqBase)
{
int64_t info = 1;
MOCKER(HalGetDeviceInfo)
.stubs()
.with(any(), any(), outBoundP(&info, sizeof(info)))
.will(returnValue(PROFILING_SUCCESS));
EXPECT_EQ(1, HalGetHostFreq());
}
TEST_F(BasicCStest, HalGetDeviceFreqBase)
{
int64_t info = 1;
MOCKER(HalGetDeviceInfo)
.stubs()
.with(any(), any(), outBoundP(&info, sizeof(info)))
.will(returnValue(PROFILING_SUCCESS));
EXPECT_EQ(1, HalGetDeviceFreq(0));
}
ProfFileChunk * CreateChunk(uint8_t deviceId, uint32_t chunkSize, FileChunkType type)
{
ProfFileChunk *chunk = (ProfFileChunk *)OsalMalloc(sizeof(ProfFileChunk));
chunk->deviceId = deviceId;
chunk->chunkSize = chunkSize;
chunk->chunkType = type;
chunk->isLastChunk = false;
chunk->offset = -1;
chunk->chunk = (uint8_t*)OsalMalloc(MAX_READER_BUFFER_SIZE);
(void)memset_s(chunk->fileName, sizeof(chunk->fileName), 0, sizeof(chunk->fileName));
(void)sprintf_s(chunk->fileName, sizeof(chunk->fileName), "%s", "nano_stars_profile.data");
return chunk;
}
TEST_F(BasicCStest, FlashSendBufferTest)
{
const char* dir = "./";
ProfFileChunk *chunk = CreateChunk(0, 1, PROF_DEVICE_DATA);
EXPECT_EQ(FlashSendBuffer(chunk, dir), PROFILING_SUCCESS);
ProfFileChunk *chunk2 = CreateChunk(64, 1, PROF_HOST_DATA);
EXPECT_EQ(FlashSendBuffer(chunk2, dir), PROFILING_SUCCESS);
ProfFileChunk *chunk3 = CreateChunk(64, 1, PROF_CTRL_DATA);
EXPECT_EQ(FlashSendBuffer(chunk3, dir), PROFILING_SUCCESS);
}
TEST_F(BasicCStest, GetSelfPathTest)
{
MOCKER(readlink)
.stubs()
.will(returnValue(-1))
.then(returnValue(4097));
MOCKER(strcpy_s)
.stubs()
.will(returnValue(0));
EXPECT_EQ(false, GetSelfPath("./"));
}
TEST_F(BasicCStest, TestJsonMakeString)
{
JsonObj *emptyObj = JsonInit();
char *emptyStr = JsonToString(emptyObj);
EXPECT_EQ(0, strcmp("null", emptyStr));
JsonFree(emptyObj);
free(emptyStr);
JsonObj *subObj = JsonInit();
subObj->SetValueByKey(subObj, "1", {"1", CJSON_STRING})
->SetValueByKey(subObj, "2", {"2", CJSON_STRING})
->SetValueByKey(subObj, "3", {"3", CJSON_STRING});
JsonObj *arr = JsonInit();
arr->AddArrayItem(arr, {{.intValue = 1}, .type = CJSON_INT})
->AddArrayItem(arr, {{.intValue = 2}, .type = CJSON_INT})
->AddArrayItem(arr, {{.intValue = 3}, .type = CJSON_INT});
JsonObj *obj = JsonInit();
obj->SetValueByKey(obj, "s", {"abc", CJSON_STRING})
->SetValueByKey(obj, "t", {{.boolValue = true}, .type = CJSON_BOOL})
->SetValueByKey(obj, "f", {{.boolValue = false}, .type = CJSON_BOOL})
->SetValueByKey(obj, "i", {{.intValue = 123}, .type = CJSON_INT})
->SetValueByKey(obj, "d", {{.doubleValue = 1.5}, .type = CJSON_DOUBLE})
->SetValueByKey(obj, "a", *arr)
->SetValueByKey(obj, "o", *subObj);
JsonObj *objPtr = obj;
objPtr->TravelByKey(&objPtr, "o")->SetValueByKey(objPtr, "1", {{.intValue = 111}, .type = CJSON_INT});
EXPECT_EQ(CJSON_OBJ, objPtr->type);
char *json3 = JsonToString(obj);
char *expectJson = "{\"a\":[1,2,3],\"d\":1.5,\"f\":false,\"i\":123,\"o\":{\"1\":111,\"2\":\"2\",\"3\":\"3\"},\"s\":"
"\"abc\",\"t\":true}";
EXPECT_EQ(0, strcmp(expectJson, json3));
EXPECT_EQ(true, obj->Contains(obj, "s"));
EXPECT_EQ(false, obj->Contains(obj, "not_exist"));
void *notExist = obj->GetValueByKey(obj, "not_exist");
EXPECT_EQ(NULL, notExist);
const char *gotStr = obj->GetValueByKey(obj, "s")->stringValue;
EXPECT_EQ(0, strcmp("abc", gotStr));
int64_t gotInt = obj->GetValueByKey(obj, "i")->intValue;
EXPECT_EQ(123, gotInt);
bool gotTrue = obj->GetValueByKey(obj, "t")->boolValue;
EXPECT_EQ(true, gotTrue);
double gotDouble = obj->GetValueByKey(obj, "d")->doubleValue;
EXPECT_EQ(1.5, gotDouble);
free(json3);
JsonFree(subObj);
JsonFree(arr);
JsonFree(obj);
}