|
|
/*----------------------------------------------------------------------------
|
|
|
* Copyright (c) Huawei Technologies Co., Ltd. 2017-2020. All rights reserved.
|
|
|
* Description: LiteOS Performance Monitor Module Implementation
|
|
|
* Author: Huawei LiteOS Team
|
|
|
* Create: 2017-01-01
|
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
|
* are permitted provided that the following conditions are met:
|
|
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
|
|
* conditions and the following disclaimer.
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
|
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
|
|
* provided with the distribution.
|
|
|
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
|
|
|
* to endorse or promote products derived from this software without specific prior written
|
|
|
* permission.
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
|
|
#include "los_perf_pri.h"
|
|
|
#include "perf_pmu_pri.h"
|
|
|
#include "perf_output_pri.h"
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
#if __cplusplus
|
|
|
extern "C" {
|
|
|
#endif /* __cplusplus */
|
|
|
#endif /* __cplusplus */
|
|
|
|
|
|
#ifdef LOSCFG_KERNEL_PERF
|
|
|
STATIC Pmu *g_pmu = NULL;//用于保存当前系统中所使用的硬件性能计数器
|
|
|
STATIC PerfCB g_perfCb = {0};//保存了性能测量回调函数和一些测量结果数据
|
|
|
|
|
|
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_perfSpin);
|
|
|
//定义了一个自旋锁 g_perfSpin,用于保护性能测量模块在多线程环境下的并发访问
|
|
|
#define PERF_LOCK(state) LOS_SpinLockSave(&g_perfSpin, &(state))
|
|
|
#define PERF_UNLOCK(state) LOS_SpinUnlockRestore(&g_perfSpin, (state))
|
|
|
|
|
|
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
|
|
|
|
|
STATIC INLINE UINT64 OsPerfGetCurrTime(VOID)
|
|
|
{
|
|
|
#ifdef LOSCFG_PERF_CALC_TIME_BY_TICK
|
|
|
return LOS_TickCountGet();
|
|
|
#else
|
|
|
return HalClockGetCycles();
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
STATIC UINT32 OsPmuInit(VOID)//初始化性能计数器
|
|
|
{
|
|
|
//判断是否开启了计数器
|
|
|
#ifdef LOSCFG_PERF_HW_PMU
|
|
|
if (OsHwPmuInit() != LOS_OK) {
|
|
|
return LOS_ERRNO_PERF_HW_INIT_ERROR;
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
#ifdef LOSCFG_PERF_TIMED_PMU
|
|
|
if (OsTimedPmuInit() != LOS_OK) {
|
|
|
return LOS_ERRNO_PERF_TIMED_INIT_ERROR;
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
#ifdef LOSCFG_PERF_SW_PMU
|
|
|
if (OsSwPmuInit() != LOS_OK) {
|
|
|
return LOS_ERRNO_PERF_SW_INIT_ERROR;
|
|
|
}
|
|
|
#endif
|
|
|
return LOS_OK;
|
|
|
}
|
|
|
|
|
|
STATIC UINT32 OsPerfConfig(PerfEventConfig *eventsCfg)//配置性能计数器
|
|
|
{
|
|
|
UINT32 i;
|
|
|
UINT32 ret;
|
|
|
|
|
|
g_pmu = OsPerfPmuGet(eventsCfg->type);
|
|
|
if (g_pmu == NULL) {//根据配置的类型获取对应的性能计数器对象
|
|
|
PRINT_ERR("perf config type error %u!\n", eventsCfg->type);
|
|
|
return LOS_ERRNO_PERF_INVALID_PMU;
|
|
|
}
|
|
|
|
|
|
UINT32 eventNum = MIN(eventsCfg->eventsNr, PERF_MAX_EVENT);
|
|
|
|
|
|
(VOID)memset_s(&g_pmu->events, sizeof(PerfEvent), 0, sizeof(PerfEvent));
|
|
|
|
|
|
//根据配置信息设置各性能事件的参数,调用性能计数器对象的配置函数进行配置
|
|
|
for (i = 0; i < eventNum; i++) {
|
|
|
g_pmu->events.per[i].eventId = eventsCfg->events[i].eventId;
|
|
|
g_pmu->events.per[i].period = eventsCfg->events[i].period;
|
|
|
}
|
|
|
g_pmu->events.nr = i;
|
|
|
g_pmu->events.cntDivided = eventsCfg->predivided;
|
|
|
g_pmu->type = eventsCfg->type;
|
|
|
|
|
|
ret = g_pmu->config();
|
|
|
if (ret != LOS_OK) {
|
|
|
PRINT_ERR("perf config failed!\n");
|
|
|
(VOID)memset_s(&g_pmu->events, sizeof(PerfEvent), 0, sizeof(PerfEvent));
|
|
|
return LOS_ERRNO_PERF_PMU_CONFIG_ERROR;
|
|
|
}
|
|
|
return LOS_OK;
|
|
|
}
|
|
|
|
|
|
STATIC VOID OsPerfPrintCount(VOID)//用于打印性能计数器的统计信息
|
|
|
{
|
|
|
UINT32 index;
|
|
|
UINT32 intSave;
|
|
|
UINT32 cpuid = ArchCurrCpuid();
|
|
|
|
|
|
PerfEvent *events = &g_pmu->events;//获取性能计数器对象的性能时间数组和事件数量
|
|
|
UINT32 eventNum = events->nr;
|
|
|
|
|
|
PERF_LOCK(intSave);
|
|
|
for (index = 0; index < eventNum; index++) {
|
|
|
Event *event = &(events->per[index]);
|
|
|
|
|
|
/* filter out event counter with no event binded. */
|
|
|
if (event->period == 0) { //事件周期
|
|
|
continue;
|
|
|
}
|
|
|
PRINT_EMG("[%s] eventType: 0x%x [core %u]: %llu\n", g_pmu->getName(event), event->eventId, cpuid,
|
|
|
event->count[cpuid]);
|
|
|
}
|
|
|
PERF_UNLOCK(intSave);
|
|
|
}
|
|
|
|
|
|
STATIC INLINE VOID OsPerfPrintTs(VOID)//打印时间信息
|
|
|
{
|
|
|
#ifdef LOSCFG_PERF_CALC_TIME_BY_TICK
|
|
|
DOUBLE time = (g_perfCb.endTime - g_perfCb.startTime) * 1.0 / LOSCFG_BASE_CORE_TICK_PER_SECOND;
|
|
|
#else
|
|
|
DOUBLE time = (g_perfCb.endTime - g_perfCb.startTime) * 1.0 / OS_SYS_CLOCK;
|
|
|
#endif
|
|
|
PRINT_EMG("time used: %.6f(s)\r\n", time);
|
|
|
}
|
|
|
|
|
|
STATIC VOID OsPerfStart(VOID)//启动及更新CPU和计数器状态
|
|
|
{
|
|
|
UINT32 cpuid = ArchCurrCpuid();
|
|
|
|
|
|
if (g_pmu == NULL) {
|
|
|
PRINT_ERR("pmu not registered!\n");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (g_perfCb.pmuStatusPerCpu[cpuid] != PERF_PMU_STARTED) {
|
|
|
UINT32 ret = g_pmu->start();//若计数器未启动则启动
|
|
|
if (ret != LOS_OK) {
|
|
|
PRINT_ERR("perf start on core:%u failed, ret = 0x%x\n", cpuid, ret);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
g_perfCb.pmuStatusPerCpu[cpuid] = PERF_PMU_STARTED;
|
|
|
} else {
|
|
|
PRINT_ERR("percpu status err %d\n", g_perfCb.pmuStatusPerCpu[cpuid]);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
STATIC VOID OsPerfStop(VOID)//停止性能计数器
|
|
|
{
|
|
|
UINT32 cpuid = ArchCurrCpuid();
|
|
|
|
|
|
if (g_pmu == NULL) {
|
|
|
PRINT_ERR("pmu not registered!\n");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (g_perfCb.pmuStatusPerCpu[cpuid] != PERF_PMU_STOPED) {
|
|
|
UINT32 ret = g_pmu->stop();
|
|
|
if (ret != LOS_OK) {
|
|
|
PRINT_ERR("perf stop on core:%u failed, ret = 0x%x\n", cpuid, ret);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (!g_perfCb.needSample) {
|
|
|
OsPerfPrintCount();
|
|
|
}
|
|
|
|
|
|
g_perfCb.pmuStatusPerCpu[cpuid] = PERF_PMU_STOPED;
|
|
|
} else {
|
|
|
PRINT_ERR("percpu status err %d\n", g_perfCb.pmuStatusPerCpu[cpuid]);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
STATIC UINT32 OsPerfBackTrace(UINTPTR *callChain, UINT32 maxDepth, PerfRegs *regs)
|
|
|
//获取当前函数调用链的信息,并将结果存储在 callChain 数组中
|
|
|
{
|
|
|
UINT32 i;
|
|
|
|
|
|
UINT32 count = ArchBackTraceGet(regs->fp, callChain, maxDepth);//获取当前状态的帧指针值
|
|
|
PRINT_DEBUG("backtrace depth = %u, fp = 0x%x\n", count, regs->fp);
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
PRINT_DEBUG("ip[%u]: 0x%x\n", i, callChain[i]);//打印调用链中每个函数的指令地址
|
|
|
}
|
|
|
return count;//返回用链的深度
|
|
|
}
|
|
|
|
|
|
STATIC UINT32 OsPerfCollectData(Event *event, PerfSampleData *data, PerfRegs *regs)
|
|
|
//收集性能计数器的数据,并将其存储在 data 结构体中
|
|
|
{
|
|
|
UINT32 size = 0;
|
|
|
UINT32 depth;
|
|
|
UINT32 sampleType = g_perfCb.sampleType;
|
|
|
CHAR *p = (CHAR *)data;
|
|
|
|
|
|
if (sampleType & PERF_RECORD_CPU) {
|
|
|
*(UINT32 *)(p + size) = ArchCurrCpuid();//函数获取当前CPU的ID,并存储在 data->cpuid 字段中
|
|
|
size += sizeof(data->cpuid);
|
|
|
}
|
|
|
|
|
|
if (sampleType & PERF_RECORD_TID) {
|
|
|
*(UINT32 *)(p + size) = LOS_CurTaskIDGet();// 函数获取当前任务的ID,并存储在 data->taskId 字段中
|
|
|
size += sizeof(data->taskId);
|
|
|
}
|
|
|
|
|
|
if (sampleType & PERF_RECORD_TYPE) {
|
|
|
*(UINT32 *)(p + size) = event->eventId;
|
|
|
size += sizeof(data->eventId);
|
|
|
}
|
|
|
|
|
|
if (sampleType & PERF_RECORD_PERIOD) {
|
|
|
*(UINT32 *)(p + size) = event->period;
|
|
|
size += sizeof(data->period);
|
|
|
}
|
|
|
|
|
|
if (sampleType & PERF_RECORD_TIMESTAMP) {
|
|
|
*(UINT64 *)(p + size) = OsPerfGetCurrTime();//获取当前时间戳,并存储在 data->time 字段中
|
|
|
size += sizeof(data->time);
|
|
|
}
|
|
|
|
|
|
if (sampleType & PERF_RECORD_IP) {
|
|
|
*(UINTPTR *)(p + size) = regs->pc;
|
|
|
size += sizeof(data->pc);
|
|
|
}
|
|
|
|
|
|
if (sampleType & PERF_RECORD_CALLCHAIN) {
|
|
|
depth = OsPerfBackTrace((UINTPTR *)(p + size + sizeof(data->callChain.ipNr)), PERF_MAX_CALLCHAIN_DEPTH, regs);
|
|
|
*(UINT32 *)(p + size) = depth;
|
|
|
size += sizeof(data->callChain.ipNr) + depth * sizeof(data->callChain.ip[0]);
|
|
|
}
|
|
|
|
|
|
return size;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* return TRUE if the taskId in the taskId list, return FALSE otherwise;
|
|
|
* return TRUE if user haven't specified any taskId(which is supposed
|
|
|
* to instrument the whole system)
|
|
|
*/
|
|
|
STATIC BOOL OsPerfTaskFilter(UINT32 taskId)//过滤任务ID,判断一个给定的任务ID是否需要进行性能优化
|
|
|
{
|
|
|
UINT32 i;
|
|
|
|
|
|
if (!g_perfCb.taskIdsNr) {
|
|
|
return TRUE;
|
|
|
}
|
|
|
|
|
|
for (i = 0; i < g_perfCb.taskIdsNr; i++) { //储存允许过滤任务ID的列表
|
|
|
if (g_perfCb.taskIds[i] == taskId) {
|
|
|
return TRUE;
|
|
|
}
|
|
|
}
|
|
|
return FALSE;
|
|
|
}
|
|
|
|
|
|
STATIC INLINE UINT32 OsPerfParamValid(VOID)//检查性能函数的有效性
|
|
|
{
|
|
|
UINT32 index;
|
|
|
UINT32 res = 0;
|
|
|
|
|
|
if (g_pmu == NULL) {
|
|
|
return 0;
|
|
|
}
|
|
|
PerfEvent *events = &g_pmu->events;
|
|
|
UINT32 eventNum = events->nr;
|
|
|
|
|
|
for (index = 0; index < eventNum; index++) {
|
|
|
res |= events->per[index].period;
|
|
|
}
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
STATIC UINT32 OsPerfHdrInit(UINT32 id)//初始化性能数据的头部信息
|
|
|
{
|
|
|
PerfDataHdr head = {
|
|
|
.magic = PERF_DATA_MAGIC_WORD,
|
|
|
.sampleType = g_perfCb.sampleType,
|
|
|
.sectionId = id,
|
|
|
.eventType = g_pmu->type,
|
|
|
.len = sizeof(PerfDataHdr),
|
|
|
};
|
|
|
return OsPerfOutPutWrite((CHAR *)&head, head.len);
|
|
|
}
|
|
|
|
|
|
VOID OsPerfUpdateEventCount(Event *event, UINT32 value)//更新上传事件的技术
|
|
|
{
|
|
|
if (event == NULL) {
|
|
|
return;
|
|
|
}
|
|
|
event->count[ArchCurrCpuid()] += (value & 0xFFFFFFFF); /* event->count is UINT64 */
|
|
|
}
|
|
|
|
|
|
VOID OsPerfHandleOverFlow(Event *event, PerfRegs *regs)//处理性能计数器溢出的情况
|
|
|
{
|
|
|
PerfSampleData data;
|
|
|
UINT32 len;
|
|
|
|
|
|
(VOID)memset_s(&data, sizeof(PerfSampleData), 0, sizeof(PerfSampleData));
|
|
|
if ((g_perfCb.needSample) && OsPerfTaskFilter(LOS_CurTaskIDGet())) {//判断是否优化
|
|
|
len = OsPerfCollectData(event, &data, regs);
|
|
|
OsPerfOutPutWrite((CHAR *)&data, len);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
UINT32 LOS_PerfInit(VOID *buf, UINT32 size)//初始化性能统计模块
|
|
|
{
|
|
|
UINT32 ret;
|
|
|
UINT32 intSave;
|
|
|
|
|
|
PERF_LOCK(intSave);//保存中断状态
|
|
|
if (g_perfCb.status != PERF_UNINIT) {
|
|
|
ret = LOS_ERRNO_PERF_STATUS_INVALID;
|
|
|
goto PERF_INIT_ERROR;
|
|
|
}
|
|
|
|
|
|
ret = OsPmuInit();//函数性能计数器初始化
|
|
|
if (ret != LOS_OK) {
|
|
|
goto PERF_INIT_ERROR;
|
|
|
}
|
|
|
|
|
|
ret = OsPerfOutPutInit(buf, size);//性能输出缓冲区进行初始化
|
|
|
if (ret != LOS_OK) {
|
|
|
ret = LOS_ERRNO_PERF_BUF_ERROR;
|
|
|
goto PERF_INIT_ERROR;
|
|
|
}
|
|
|
g_perfCb.status = PERF_STOPED;
|
|
|
PERF_INIT_ERROR:
|
|
|
PERF_UNLOCK(intSave);//解锁中断处理
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
UINT32 LOS_PerfConfig(PerfConfigAttr *attr)//配置性能统计模块的属性
|
|
|
{
|
|
|
UINT32 ret;
|
|
|
UINT32 intSave;
|
|
|
|
|
|
if (attr == NULL) {
|
|
|
return LOS_ERRNO_PERF_CONFIG_NULL;
|
|
|
}
|
|
|
|
|
|
PERF_LOCK(intSave);//保存中断状态
|
|
|
if (g_perfCb.status != PERF_STOPED) {
|
|
|
ret = LOS_ERRNO_PERF_STATUS_INVALID;
|
|
|
PRINT_ERR("perf config status error : 0x%x\n", g_perfCb.status);
|
|
|
goto PERF_CONFIG_ERROR;
|
|
|
}
|
|
|
|
|
|
g_pmu = NULL;//将全局标量PMU计数器置零
|
|
|
|
|
|
g_perfCb.needSample = attr->needSample;
|
|
|
g_perfCb.taskFilterEnable = attr->taskFilterEnable;
|
|
|
g_perfCb.sampleType = attr->sampleType;
|
|
|
|
|
|
if (attr->taskFilterEnable) {//开启任务过滤功能
|
|
|
ret = memcpy_s(g_perfCb.taskIds, PERF_MAX_FILTER_TSKS * sizeof(UINT32), attr->taskIds,
|
|
|
g_perfCb.taskIdsNr * sizeof(UINT32));
|
|
|
if (ret != EOK) {
|
|
|
PRINT_ERR("In %s At line:%d execute memcpy_s error\n", __FUNCTION__, __LINE__);
|
|
|
goto PERF_CONFIG_ERROR;
|
|
|
}
|
|
|
g_perfCb.taskIdsNr = MIN(attr->taskIdsNr, PERF_MAX_FILTER_TSKS);
|
|
|
}
|
|
|
ret = OsPerfConfig(&attr->eventsCfg);//对事件配置进行处理
|
|
|
PERF_CONFIG_ERROR:
|
|
|
PERF_UNLOCK(intSave);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
VOID LOS_PerfStart(UINT32 sectionId)//启动性能统计模块
|
|
|
{
|
|
|
UINT32 intSave;
|
|
|
UINT32 ret;
|
|
|
|
|
|
PERF_LOCK(intSave);
|
|
|
if (g_perfCb.status != PERF_STOPED) {//判断统计模块是否打开
|
|
|
PRINT_ERR("perf start status error : 0x%x\n", g_perfCb.status);
|
|
|
goto PERF_START_ERROR;
|
|
|
}
|
|
|
|
|
|
if (!OsPerfParamValid()) {//检车行呢个统计模块的参数是否有效
|
|
|
PRINT_ERR("forgot call `LOS_Config(...)` before instrumenting?\n");
|
|
|
goto PERF_START_ERROR;
|
|
|
}
|
|
|
|
|
|
if (g_perfCb.needSample) {//判断是否需要抽样
|
|
|
ret = OsPerfHdrInit(sectionId); /* section header init */
|
|
|
if (ret != LOS_OK) {
|
|
|
PRINT_ERR("perf hdr init error 0x%x\n", ret);
|
|
|
goto PERF_START_ERROR;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
SMP_CALL_PERF_FUNC(OsPerfStart); /* 所有CPU开始PMU计数器,启动性能统计模块i奥 */
|
|
|
g_perfCb.status = PERF_STARTED;
|
|
|
g_perfCb.startTime = OsPerfGetCurrTime();
|
|
|
PERF_START_ERROR:
|
|
|
PERF_UNLOCK(intSave);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
VOID LOS_PerfStop(VOID)//停止性能统计模块的运行,进行一些清理操作
|
|
|
{
|
|
|
UINT32 intSave;
|
|
|
|
|
|
PERF_LOCK(intSave);
|
|
|
if (g_perfCb.status != PERF_STARTED) {
|
|
|
PRINT_ERR("perf stop status error : 0x%x\n", g_perfCb.status);
|
|
|
goto PERF_STOP_ERROR;
|
|
|
}
|
|
|
|
|
|
SMP_CALL_PERF_FUNC(OsPerfStop); /* send to all cpu to stop pmu */
|
|
|
|
|
|
OsPerfOutPutFlush();//刷新输出操作
|
|
|
|
|
|
if (g_perfCb.needSample) {
|
|
|
OsPerfOutPutInfo();
|
|
|
}
|
|
|
//更新了两个全局变量的值,表示性能统计模块已经在状态上和时间上停止了
|
|
|
g_perfCb.status = PERF_STOPED;
|
|
|
g_perfCb.endTime = OsPerfGetCurrTime();
|
|
|
|
|
|
OsPerfPrintTs();
|
|
|
PERF_STOP_ERROR:
|
|
|
PERF_UNLOCK(intSave);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
UINT32 LOS_PerfDataRead(CHAR *dest, UINT32 size)//从性能统计门票快的输出缓冲区中读取数据到指定的内存
|
|
|
{
|
|
|
return OsPerfOutPutRead(dest, size);
|
|
|
}
|
|
|
|
|
|
VOID LOS_PerfNotifyHookReg(const PERF_BUF_NOTIFY_HOOK func)//注册型那个统计模块的通知hook函数
|
|
|
{
|
|
|
UINT32 intSave;
|
|
|
//保存中断状态,恢复中断状态
|
|
|
PERF_LOCK(intSave);
|
|
|
OsPerfNotifyHookReg(func);
|
|
|
PERF_UNLOCK(intSave);
|
|
|
}
|
|
|
|
|
|
VOID LOS_PerfFlushHookReg(const PERF_BUF_FLUSH_HOOK func)//刷新hook
|
|
|
{
|
|
|
UINT32 intSave;
|
|
|
|
|
|
PERF_LOCK(intSave);
|
|
|
OsPerfFlushHookReg(func);
|
|
|
PERF_UNLOCK(intSave);
|
|
|
}
|
|
|
|
|
|
VOID OsPerfSetIrqRegs(UINTPTR pc, UINTPTR fp)//设置中断相关的寄存器,用于中断时的性能统计
|
|
|
{
|
|
|
LosTaskCB *runTask = (LosTaskCB *)ArchCurrTaskGet();
|
|
|
runTask->pc = pc;
|
|
|
runTask->fp = fp;
|
|
|
}
|
|
|
|
|
|
#endif /* LOSCFG_KERNEL_PERF == YES */
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
#if __cplusplus
|
|
|
}
|
|
|
#endif /* __cplusplus */
|
|
|
#endif /* __cplusplus */
|