* 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 <dlfcn.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <string.h>
#include "framework/executor_c/ge_log.h"
#include "ge/ge_error_codes.h"
#include "json_parser.h"
#include "profiling.h"
#include "toolchain/prof_api.h"
typedef uint32_t (*CAC_MSPROF_INIT_FUNC)(uint32_t dataType, void *data, uint32_t dataLen);
typedef int32_t (*ProfCommandHandle)(uint32_t type, void *data, uint32_t len);
typedef uint32_t (*CAC_MSPROF_REGISTER_CALLBACK_FUNC)(uint32_t moduleId, ProfCommandHandle handle);
typedef uint64_t (*CAC_MSPROF_GETHASHID_FUNC)(const char *hashInfo, size_t length);
typedef uint64_t (*CAC_MSPROF_GETTIME_FUNC)(void);
typedef uint32_t (*CAC_MSPROF_REPORT_DATA_FUNC)(uint32_t agingFlag, const void *data, uint32_t length);
typedef int32_t (*CAC_MSPROF_DEINIT_FUNC)(void);
typedef int32_t (*CAC_MSPROF_NOTIFY_SET_DEVICE_FUNC)(uint32_t chipId, uint32_t deviceId, bool isOpen);
typedef struct {
CAC_MSPROF_INIT_FUNC cac_msprof_init_func;
CAC_MSPROF_REGISTER_CALLBACK_FUNC cac_msprof_register_callback_func;
CAC_MSPROF_GETHASHID_FUNC cac_msprof_hashid_func;
CAC_MSPROF_GETTIME_FUNC cac_msprof_gettime_func;
CAC_MSPROF_REPORT_DATA_FUNC cac_msprof_report_data_func;
CAC_MSPROF_DEINIT_FUNC cac_msprof_deinit_func;
CAC_MSPROF_NOTIFY_SET_DEVICE_FUNC cac_msprof_notify_set_device_func;
} ProfFuncs;
const char *DBG_PROFILING = "profiler";
static void *gProfHandle = NULL;
static ProfFuncs gProfFuncs = {0};
static bool gMsprofEnable = false;
static Status LoadProfSo(void) {
const char *soName = "libprofapi.so";
gProfHandle = dlopen(soName, RTLD_NOW);
if (gProfHandle == NULL) {
GELOGE(ACL_ERROR_GE_PARAM_INVALID, "call dlopen failed, so path[%s]. err message: %s", soName, dlerror());
return ACL_ERROR_GE_PARAM_INVALID;
}
return SUCCESS;
}
static Status DataDlopenProf(void) {
if (LoadProfSo() != SUCCESS) {
return ACL_ERROR_GE_PARAM_INVALID;
}
gProfFuncs.cac_msprof_init_func = (CAC_MSPROF_INIT_FUNC)dlsym(gProfHandle, "MsprofInit");
if (gProfFuncs.cac_msprof_init_func == NULL) {
return ACL_ERROR_GE_PARAM_INVALID;
}
gProfFuncs.cac_msprof_register_callback_func =
(CAC_MSPROF_REGISTER_CALLBACK_FUNC)dlsym(gProfHandle, "MsprofRegisterCallback");
if (gProfFuncs.cac_msprof_register_callback_func == NULL) {
return ACL_ERROR_GE_PARAM_INVALID;
}
gProfFuncs.cac_msprof_hashid_func = (CAC_MSPROF_GETHASHID_FUNC)dlsym(gProfHandle, "MsprofGetHashId");
if (gProfFuncs.cac_msprof_hashid_func == NULL) {
return ACL_ERROR_GE_PARAM_INVALID;
}
gProfFuncs.cac_msprof_gettime_func = (CAC_MSPROF_GETTIME_FUNC)dlsym(gProfHandle, "MsprofSysCycleTime");
if (gProfFuncs.cac_msprof_gettime_func == NULL) {
return ACL_ERROR_GE_PARAM_INVALID;
}
gProfFuncs.cac_msprof_report_data_func =
(CAC_MSPROF_REPORT_DATA_FUNC)dlsym(gProfHandle, "MsprofReportAdditionalInfo");
if (gProfFuncs.cac_msprof_report_data_func == NULL) {
return ACL_ERROR_GE_PARAM_INVALID;
}
gProfFuncs.cac_msprof_deinit_func = (CAC_MSPROF_DEINIT_FUNC)dlsym(gProfHandle, "MsprofFinalize");
if (gProfFuncs.cac_msprof_deinit_func == NULL) {
return ACL_ERROR_GE_PARAM_INVALID;
}
gProfFuncs.cac_msprof_notify_set_device_func =
(CAC_MSPROF_NOTIFY_SET_DEVICE_FUNC)dlsym(gProfHandle, "MsprofNotifySetDevice");
if (gProfFuncs.cac_msprof_notify_set_device_func == NULL) {
return ACL_ERROR_GE_PARAM_INVALID;
}
return SUCCESS;
}
void SetMsprofEnable(bool flag) {
gMsprofEnable = flag;
}
bool DbgGetprofEnable(void) {
return gMsprofEnable;
}
static Status ProcessProfData(void *const data, const uint32_t len) {
const uint32_t commandLen = sizeof(struct MsprofCommandHandle);
if (len != commandLen) {
GELOGE(ACL_ERROR_GE_PARAM_INVALID, "[Check][Len]len[%u] is invalid, it should be %u", len, commandLen);
return ACL_ERROR_GE_PARAM_INVALID;
}
struct MsprofCommandHandle *const profilingCfg = (struct MsprofCommandHandle *)(data);
SetMsprofEnable(((profilingCfg->profSwitch) & MSPROF_TASK_TIME_L0));
return SUCCESS;
}
int32_t MsprofCtrlHandleFunc(uint32_t dataType, void *data, uint32_t dataLen) {
if (data == NULL) {
GELOGE(ACL_ERROR_GE_PARAM_INVALID, "input data is null");
return (int32_t)ACL_ERROR_GE_PARAM_INVALID;
}
if (dataType == PROF_CTRL_SWITCH) {
const int32_t ret = (int32_t)ProcessProfData(data, dataLen);
if (ret != SUCCESS) {
GELOGE(ACL_ERROR_GE_PARAM_INVALID, "[Process][ProfSwitch]failed to call ProcessProfData, result is %u", ret);
return ret;
}
} else {
GELOGI("get unsupported dataType %u while processing profiling data", dataType);
}
return SUCCESS;
}
static void FreeProfHandle(void) {
gProfFuncs.cac_msprof_init_func = NULL;
gProfFuncs.cac_msprof_register_callback_func = NULL;
gProfFuncs.cac_msprof_hashid_func = NULL;
gProfFuncs.cac_msprof_gettime_func = NULL;
gProfFuncs.cac_msprof_report_data_func = NULL;
gProfFuncs.cac_msprof_deinit_func = NULL;
gProfFuncs.cac_msprof_notify_set_device_func = NULL;
dlclose(gProfHandle);
gProfHandle = NULL;
}
Status DbgProfInit(const char *cfg) {
char *strCfg = CJsonFileParseKey(cfg, DBG_PROFILING);
if (strCfg == NULL) {
GELOGI("profiling config is off");
return SUCCESS;
}
int32_t ret = (int32_t)DataDlopenProf();
if (ret != SUCCESS) {
mmFree(strCfg);
if (gProfHandle != NULL) {
FreeProfHandle();
}
return ACL_ERROR_GE_PARAM_INVALID;
}
do {
ret = (int32_t)gProfFuncs.cac_msprof_register_callback_func(GE_MODULE_NAME, MsprofCtrlHandleFunc);
if (ret != SUCCESS) {
GELOGE(ACL_ERROR_GE_PARAM_INVALID, "prof RegisterCallback failed");
break;
}
uint32_t len = (uint32_t)strlen(strCfg);
ret = (int32_t)gProfFuncs.cac_msprof_init_func(MSPROF_CTRL_INIT_ACL_JSON, strCfg, len);
if (ret != SUCCESS) {
GELOGE(ACL_ERROR_GE_PARAM_INVALID, "prof Init failed");
break;
}
} while (0);
mmFree(strCfg);
return ret == SUCCESS ? SUCCESS : ACL_ERROR_GE_PARAM_INVALID;
}
static void InitMsprofAdditionalInfo(uint32_t modelId, char *om_name, struct MsprofAdditionalInfo *profData) {
profData->magicNumber = MSPROF_REPORT_DATA_MAGIC_NUM;
profData->level = MSPROF_REPORT_MODEL_LEVEL;
profData->type = MSPROF_REPORT_MODEL_EXEOM_TYPE;
profData->threadId = (uint32_t)syscall(SYS_gettid);
profData->timeStamp = gProfFuncs.cac_msprof_gettime_func();
profData->dataLen = sizeof(struct MsprofExeomLoadInfo);
struct MsprofExeomLoadInfo *modelLoadTag = (struct MsprofExeomLoadInfo *)profData->data;
modelLoadTag->modelId = modelId;
modelLoadTag->modelName = gProfFuncs.cac_msprof_hashid_func(om_name, strlen(om_name));
}
Status DbgProfReportDataProcess(uint32_t modelId, char *om) {
if (!DbgGetprofEnable()) {
return SUCCESS;
}
struct MsprofAdditionalInfo profData = {0};
InitMsprofAdditionalInfo(modelId, om, &profData);
uint32_t length = sizeof(profData);
int32_t ret = (int32_t)gProfFuncs.cac_msprof_report_data_func(false, &profData, length);
if (ret != SUCCESS) {
GELOGE(ACL_ERROR_GE_PARAM_INVALID, "prof Report AdditionalInfo failed, phy_model_id[%d], omName[%s]", modelId, om);
return ACL_ERROR_GE_PARAM_INVALID;
}
return SUCCESS;
}
Status DbgProfDeInit(void) {
if (gProfFuncs.cac_msprof_deinit_func == NULL) {
return SUCCESS;
}
SetMsprofEnable(false);
int32_t ret = gProfFuncs.cac_msprof_deinit_func();
if (gProfHandle != NULL) {
FreeProfHandle();
}
if (ret != SUCCESS) {
GELOGE(ACL_ERROR_GE_PARAM_INVALID, "prof Finalize failed");
return ACL_ERROR_GE_PARAM_INVALID;
}
return SUCCESS;
}
Status DbgNotifySetDevice(uint32_t chipId, uint32_t deviceId) {
if (gProfFuncs.cac_msprof_notify_set_device_func == NULL) {
return SUCCESS;
}
int32_t ret = gProfFuncs.cac_msprof_notify_set_device_func(chipId, deviceId, true);
if (ret != SUCCESS) {
GELOGE(ACL_ERROR_GE_PARAM_INVALID, "prof Notify SetDevice failed");
return ACL_ERROR_GE_PARAM_INVALID;
}
return SUCCESS;
}