@@ -26,6 +26,13 @@ config KERNEL_SMP_TASK_SYNC
|
||||
help
|
||||
This option will enable task synchronized operate task across cores.
|
||||
|
||||
config KERNEL_SMP_CALL
|
||||
bool "Enable Function call cross Multi-core"
|
||||
default n
|
||||
depends on KERNEL_SMP
|
||||
help
|
||||
This option will enable function call on multi-core.
|
||||
|
||||
config KERNEL_SCHED_STATISTICS
|
||||
bool "Enable Scheduler statistics"
|
||||
default n
|
||||
|
||||
@@ -69,6 +69,9 @@ typedef struct {
|
||||
UINT32 schedFlag; /* pending scheduler flag */
|
||||
#ifdef LOSCFG_KERNEL_SMP
|
||||
UINT32 excFlag; /* cpu halt or exc flag */
|
||||
#ifdef LOSCFG_KERNEL_SMP_CALL
|
||||
LOS_DL_LIST funcLink; /* mp function call link */
|
||||
#endif
|
||||
#endif
|
||||
} Percpu;
|
||||
|
||||
|
||||
@@ -371,6 +371,10 @@ typedef struct {
|
||||
LOS_DL_LIST msgListHead;
|
||||
BOOL accessMap[LOSCFG_BASE_CORE_TSK_LIMIT];
|
||||
#endif
|
||||
#ifdef LOSCFG_KERNEL_PERF
|
||||
UINTPTR pc;
|
||||
UINTPTR fp;
|
||||
#endif
|
||||
} LosTaskCB;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -38,6 +38,12 @@
|
||||
|
||||
#ifdef LOSCFG_KERNEL_SMP
|
||||
|
||||
#ifdef LOSCFG_KERNEL_SMP_CALL
|
||||
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_mpCallSpin);
|
||||
#define MP_CALL_LOCK(state) LOS_SpinLockSave(&g_mpCallSpin, &(state))
|
||||
#define MP_CALL_UNLOCK(state) LOS_SpinUnlockRestore(&g_mpCallSpin, (state))
|
||||
#endif
|
||||
|
||||
VOID LOS_MpSchedule(UINT32 target)
|
||||
{
|
||||
UINT32 cpuid = ArchCurrCpuid();
|
||||
@@ -94,6 +100,70 @@ VOID OsMpCollectTasks(VOID)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LOSCFG_KERNEL_SMP_CALL
|
||||
VOID OsMpFuncCall(UINT32 target, SMP_FUNC_CALL func, VOID *args)
|
||||
{
|
||||
UINT32 index;
|
||||
UINT32 intSave;
|
||||
|
||||
if (func == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(target & OS_MP_CPU_ALL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {
|
||||
if (CPUID_TO_AFFI_MASK(index) & target) {
|
||||
MpCallFunc *mpCallFunc = (MpCallFunc *)LOS_MemAlloc(m_aucSysMem0, sizeof(MpCallFunc));
|
||||
if (mpCallFunc == NULL) {
|
||||
PRINT_ERR("smp func call malloc failed\n");
|
||||
return;
|
||||
}
|
||||
mpCallFunc->func = func;
|
||||
mpCallFunc->args = args;
|
||||
|
||||
MP_CALL_LOCK(intSave);
|
||||
LOS_ListAdd(&g_percpu[index].funcLink, &(mpCallFunc->node));
|
||||
MP_CALL_UNLOCK(intSave);
|
||||
}
|
||||
}
|
||||
HalIrqSendIpi(target, LOS_MP_IPI_FUNC_CALL);
|
||||
}
|
||||
|
||||
VOID OsMpFuncCallHandler(VOID)
|
||||
{
|
||||
UINT32 intSave;
|
||||
UINT32 cpuid = ArchCurrCpuid();
|
||||
LOS_DL_LIST *list = NULL;
|
||||
MpCallFunc *mpCallFunc = NULL;
|
||||
|
||||
MP_CALL_LOCK(intSave);
|
||||
while (!LOS_ListEmpty(&g_percpu[cpuid].funcLink)) {
|
||||
list = LOS_DL_LIST_FIRST(&g_percpu[cpuid].funcLink);
|
||||
LOS_ListDelete(list);
|
||||
MP_CALL_UNLOCK(intSave);
|
||||
|
||||
mpCallFunc = LOS_DL_LIST_ENTRY(list, MpCallFunc, node);
|
||||
mpCallFunc->func(mpCallFunc->args);
|
||||
(VOID)LOS_MemFree(m_aucSysMem0, mpCallFunc);
|
||||
|
||||
MP_CALL_LOCK(intSave);
|
||||
}
|
||||
MP_CALL_UNLOCK(intSave);
|
||||
}
|
||||
|
||||
VOID OsMpFuncCallInit(VOID)
|
||||
{
|
||||
UINT32 index;
|
||||
/* init funclink for each core */
|
||||
for (index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {
|
||||
LOS_ListInit(&g_percpu[index].funcLink);
|
||||
}
|
||||
}
|
||||
#endif /* LOSCFG_KERNEL_SMP_CALL */
|
||||
|
||||
UINT32 OsMpInit(VOID)
|
||||
{
|
||||
UINT16 swtmrId;
|
||||
@@ -101,7 +171,9 @@ UINT32 OsMpInit(VOID)
|
||||
(VOID)LOS_SwtmrCreate(OS_MP_GC_PERIOD, LOS_SWTMR_MODE_PERIOD,
|
||||
(SWTMR_PROC_FUNC)OsMpCollectTasks, &swtmrId, 0);
|
||||
(VOID)LOS_SwtmrStart(swtmrId);
|
||||
|
||||
#ifdef LOSCFG_KERNEL_SMP_CALL
|
||||
OsMpFuncCallInit();
|
||||
#endif
|
||||
return LOS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ group("extended") {
|
||||
"hilog",
|
||||
"hook",
|
||||
"liteipc",
|
||||
"perf",
|
||||
"pipes",
|
||||
"power",
|
||||
"trace",
|
||||
@@ -57,5 +58,6 @@ config("public") {
|
||||
"liteipc:public",
|
||||
"pipes:public",
|
||||
"vdso:public",
|
||||
"perf:public",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -96,3 +96,6 @@ source "kernel/extended/blackbox/Kconfig"
|
||||
|
||||
######################### config options of hidumper #########################
|
||||
source "kernel/extended/hidumper/Kconfig"
|
||||
|
||||
######################### config options of perf #########################
|
||||
source "kernel/extended/perf/Kconfig"
|
||||
56
kernel/extended/perf/BUILD.gn
Normal file
56
kernel/extended/perf/BUILD.gn
Normal file
@@ -0,0 +1,56 @@
|
||||
# Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
|
||||
# Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import("//kernel/liteos_a/liteos.gni")
|
||||
|
||||
module_switch = defined(LOSCFG_KERNEL_PERF)
|
||||
module_name = get_path_info(rebase_path("."), "name")
|
||||
kernel_module(module_name) {
|
||||
sources = [
|
||||
"los_perf.c",
|
||||
"perf_output.c",
|
||||
"perf_pmu.c",
|
||||
]
|
||||
|
||||
if (defined(LOSCFG_PERF_HW_PMU)) {
|
||||
sources += [ "pmu/perf_hw_pmu.c" ]
|
||||
}
|
||||
|
||||
if (defined(LOSCFG_PERF_TIMED_PMU)) {
|
||||
sources += [ "pmu/perf_timed_pmu.c" ]
|
||||
}
|
||||
|
||||
if (defined(LOSCFG_PERF_SW_PMU)) {
|
||||
sources += [ "pmu/perf_sw_pmu.c" ]
|
||||
}
|
||||
}
|
||||
|
||||
config("public") {
|
||||
include_dirs = [ "." ]
|
||||
}
|
||||
38
kernel/extended/perf/Kconfig
Normal file
38
kernel/extended/perf/Kconfig
Normal file
@@ -0,0 +1,38 @@
|
||||
config KERNEL_PERF
|
||||
bool "Enable Perf Feature"
|
||||
default n
|
||||
depends on KERNEL_EXTKERNEL
|
||||
select KERNEL_SMP_CALL if KERNEL_SMP
|
||||
help
|
||||
If you wish to build LiteOS with support for perf.
|
||||
|
||||
choice
|
||||
prompt "Time-consuming Calc Methods"
|
||||
depends on KERNEL_PERF
|
||||
|
||||
config PERF_CALC_TIME_BY_TICK
|
||||
bool "By Tick"
|
||||
|
||||
config PERF_CALC_TIME_BY_CYCLE
|
||||
bool "By Cpu Cycle"
|
||||
endchoice
|
||||
|
||||
config PERF_BUFFER_SIZE
|
||||
int "Perf Sampling Buffer Size"
|
||||
default 20480
|
||||
depends on KERNEL_PERF
|
||||
|
||||
config PERF_HW_PMU
|
||||
bool "Enable Hardware Pmu Events for Sampling"
|
||||
default n
|
||||
depends on KERNEL_PERF
|
||||
|
||||
config PERF_TIMED_PMU
|
||||
bool "Enable Hrtimer Period Events for Sampling"
|
||||
default n
|
||||
depends on KERNEL_PERF && HRTIMER_ENABLE
|
||||
|
||||
config PERF_SW_PMU
|
||||
bool "Enable Software Events for Sampling"
|
||||
default y
|
||||
depends on KERNEL_PERF && KERNEL_HOOK
|
||||
22
kernel/extended/perf/Makefile
Normal file
22
kernel/extended/perf/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
include $(LITEOSTOPDIR)/config.mk
|
||||
|
||||
MODULE_NAME := $(notdir $(shell pwd))
|
||||
|
||||
LOCAL_SRCS := $(wildcard *.c)
|
||||
|
||||
ifeq ($(LOSCFG_PERF_HW_PMU), y)
|
||||
LOCAL_SRCS += $(wildcard pmu/perf_hw_pmu.c)
|
||||
endif
|
||||
|
||||
ifeq ($(LOSCFG_PERF_TIMED_PMU), y)
|
||||
LOCAL_SRCS += $(wildcard pmu/perf_timed_pmu.c)
|
||||
endif
|
||||
|
||||
ifeq ($(LOSCFG_PERF_SW_PMU), y)
|
||||
LOCAL_SRCS += $(wildcard pmu/perf_sw_pmu.c)
|
||||
endif
|
||||
|
||||
LOCAL_FLAGS := $(LOCAL_INCLUDE)
|
||||
|
||||
include $(MODULE)
|
||||
|
||||
544
kernel/extended/perf/los_perf.c
Normal file
544
kernel/extended/perf/los_perf.c
Normal file
@@ -0,0 +1,544 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
|
||||
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
|
||||
*
|
||||
* 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"
|
||||
#include "los_init.h"
|
||||
#include "los_process.h"
|
||||
#include "los_tick.h"
|
||||
#include "los_sys.h"
|
||||
#include "los_spinlock.h"
|
||||
|
||||
STATIC Pmu *g_pmu = NULL;
|
||||
STATIC PerfCB g_perfCb = {0};
|
||||
|
||||
LITE_OS_SEC_BSS SPIN_LOCK_INIT(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)\n", time);
|
||||
}
|
||||
|
||||
STATIC VOID OsPerfStart(VOID)
|
||||
{
|
||||
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 INLINE UINT32 OsPerfSaveIpInfo(CHAR *buf, IpInfo *info)
|
||||
{
|
||||
UINT32 size = 0;
|
||||
#ifdef LOSCFG_KERNEL_VM
|
||||
UINT32 len = ALIGN(info->len, sizeof(size_t));
|
||||
|
||||
*(UINTPTR *)buf = info->ip; /* save ip */
|
||||
size += sizeof(UINTPTR);
|
||||
|
||||
*(UINT32 *)(buf + size) = len; /* save f_path length */
|
||||
size += sizeof(UINT32);
|
||||
|
||||
if (strncpy_s(buf + size, REGION_PATH_MAX, info->f_path, info->len) != EOK) { /* save f_path */
|
||||
PRINT_ERR("copy f_path failed, %s\n", info->f_path);
|
||||
}
|
||||
size += len;
|
||||
#else
|
||||
*(UINTPTR *)buf = info->ip; /* save ip */
|
||||
size += sizeof(UINTPTR);
|
||||
#endif
|
||||
return size;
|
||||
}
|
||||
|
||||
STATIC UINT32 OsPerfBackTrace(PerfBackTrace *callChain, UINT32 maxDepth, PerfRegs *regs)
|
||||
{
|
||||
UINT32 count = BackTraceGet(regs->fp, (IpInfo *)(callChain->ip), maxDepth);
|
||||
PRINT_DEBUG("backtrace depth = %u, fp = 0x%x\n", count, regs->fp);
|
||||
return count;
|
||||
}
|
||||
|
||||
STATIC INLINE UINT32 OsPerfSaveBackTrace(CHAR *buf, PerfBackTrace *callChain, UINT32 count)
|
||||
{
|
||||
UINT32 i;
|
||||
*(UINT32 *)buf = count;
|
||||
UINT32 size = sizeof(UINT32);
|
||||
for (i = 0; i < count; i++) {
|
||||
size += OsPerfSaveIpInfo(buf + size, &(callChain->ip[i]));
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
STATIC UINT32 OsPerfCollectData(Event *event, PerfSampleData *data, PerfRegs *regs)
|
||||
{
|
||||
UINT32 size = 0;
|
||||
UINT32 depth;
|
||||
IpInfo pc = {0};
|
||||
PerfBackTrace callChain = {0};
|
||||
UINT32 sampleType = g_perfCb.sampleType;
|
||||
CHAR *p = (CHAR *)data;
|
||||
|
||||
if (sampleType & PERF_RECORD_CPU) {
|
||||
*(UINT32 *)(p + size) = ArchCurrCpuid();
|
||||
size += sizeof(data->cpuid);
|
||||
}
|
||||
|
||||
if (sampleType & PERF_RECORD_TID) {
|
||||
*(UINT32 *)(p + size) = LOS_CurTaskIDGet();
|
||||
size += sizeof(data->taskId);
|
||||
}
|
||||
|
||||
if (sampleType & PERF_RECORD_PID) {
|
||||
*(UINT32 *)(p + size) = LOS_GetCurrProcessID();
|
||||
size += sizeof(data->processId);
|
||||
}
|
||||
|
||||
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();
|
||||
size += sizeof(data->time);
|
||||
}
|
||||
|
||||
if (sampleType & PERF_RECORD_IP) {
|
||||
OsGetUsrIpInfo(regs->pc, &pc);
|
||||
size += OsPerfSaveIpInfo(p + size, &pc);
|
||||
}
|
||||
|
||||
if (sampleType & PERF_RECORD_CALLCHAIN) {
|
||||
depth = OsPerfBackTrace(&callChain, PERF_MAX_CALLCHAIN_DEPTH, regs);
|
||||
size += OsPerfSaveBackTrace(p + size, &callChain, depth);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
* return TRUE if the taskId in the task filter list, return FALSE otherwise;
|
||||
* return TRUE if user haven't specified any taskId(which is supposed
|
||||
* to instrument the whole system)
|
||||
*/
|
||||
STATIC INLINE BOOL OsFilterId(UINT32 id, UINT32 *ids, UINT8 idsNr)
|
||||
{
|
||||
UINT32 i;
|
||||
if (!idsNr) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
for (i = 0; i < idsNr; i++) {
|
||||
if (ids[i] == id) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
STATIC INLINE BOOL OsPerfFilter(UINT32 taskId, UINT32 processId)
|
||||
{
|
||||
return OsFilterId(taskId, g_perfCb.taskIds, g_perfCb.taskIdsNr) &&
|
||||
OsFilterId(processId, g_perfCb.processIds, g_perfCb.processIdsNr);
|
||||
}
|
||||
|
||||
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) && OsPerfFilter(LOS_CurTaskIDGet(), LOS_GetCurrProcessID())) {
|
||||
len = OsPerfCollectData(event, &data, regs);
|
||||
OsPerfOutputWrite((CHAR *)&data, len);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC UINT32 OsPerfInit(VOID)
|
||||
{
|
||||
UINT32 ret;
|
||||
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(NULL, LOSCFG_PERF_BUFFER_SIZE);
|
||||
if (ret != LOS_OK) {
|
||||
ret = LOS_ERRNO_PERF_BUF_ERROR;
|
||||
goto PERF_INIT_ERROR;
|
||||
}
|
||||
g_perfCb.status = PERF_STOPPED;
|
||||
PERF_INIT_ERROR:
|
||||
return ret;
|
||||
}
|
||||
|
||||
STATIC VOID PerfInfoDump(VOID)
|
||||
{
|
||||
UINT32 i;
|
||||
if (g_pmu != NULL) {
|
||||
PRINTK("type: %d\n", g_pmu->type);
|
||||
for (i = 0; i < g_pmu->events.nr; i++) {
|
||||
PRINTK("events[%d]: %d, 0x%x\n", i, g_pmu->events.per[i].eventId, g_pmu->events.per[i].period);
|
||||
}
|
||||
PRINTK("predivided: %d\n", g_pmu->events.cntDivided);
|
||||
} else {
|
||||
PRINTK("pmu is NULL\n");
|
||||
}
|
||||
|
||||
PRINTK("sampleType: 0x%x\n", g_perfCb.sampleType);
|
||||
for (i = 0; i < g_perfCb.taskIdsNr; i++) {
|
||||
PRINTK("filter taskIds[%d]: %d\n", i, g_perfCb.taskIds[i]);
|
||||
}
|
||||
for (i = 0; i < g_perfCb.processIdsNr; i++) {
|
||||
PRINTK("filter processIds[%d]: %d\n", i, g_perfCb.processIds[i]);
|
||||
}
|
||||
PRINTK("needSample: %d\n", g_perfCb.needSample);
|
||||
}
|
||||
|
||||
STATIC INLINE VOID OsPerfSetFilterIds(UINT32 *dstIds, UINT8 *dstIdsNr, UINT32 *ids, UINT32 idsNr)
|
||||
{
|
||||
errno_t ret;
|
||||
if (idsNr) {
|
||||
ret = memcpy_s(dstIds, PERF_MAX_FILTER_TSKS * sizeof(UINT32), ids, idsNr * sizeof(UINT32));
|
||||
if (ret != EOK) {
|
||||
PRINT_ERR("In %s At line:%d execute memcpy_s error\n", __FUNCTION__, __LINE__);
|
||||
*dstIdsNr = 0;
|
||||
return;
|
||||
}
|
||||
*dstIdsNr = MIN(idsNr, PERF_MAX_FILTER_TSKS);
|
||||
} else {
|
||||
*dstIdsNr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
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_STOPPED) {
|
||||
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;
|
||||
|
||||
g_perfCb.needSample = attr->needSample;
|
||||
g_perfCb.sampleType = attr->sampleType;
|
||||
|
||||
OsPerfSetFilterIds(g_perfCb.taskIds, &g_perfCb.taskIdsNr, attr->taskIds, attr->taskIdsNr);
|
||||
OsPerfSetFilterIds(g_perfCb.processIds, &g_perfCb.processIdsNr, attr->processIds, attr->processIdsNr);
|
||||
|
||||
ret = OsPerfConfig(&attr->eventsCfg);
|
||||
PerfInfoDump();
|
||||
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_STOPPED) {
|
||||
PRINT_ERR("perf start status error : 0x%x\n", g_perfCb.status);
|
||||
goto PERF_START_ERROR;
|
||||
}
|
||||
|
||||
if (!OsPerfParamValid()) {
|
||||
PRINT_ERR("forgot call `LOS_PerfConfig(...)` before perf start?\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); /* send to all cpu to start pmu */
|
||||
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_STOPPED;
|
||||
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)
|
||||
{
|
||||
UINT32 intSave;
|
||||
|
||||
PERF_LOCK(intSave);
|
||||
OsPerfNotifyHookReg(func);
|
||||
PERF_UNLOCK(intSave);
|
||||
}
|
||||
|
||||
VOID LOS_PerfFlushHookReg(const PERF_BUF_FLUSH_HOOK func)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
LOS_MODULE_INIT(OsPerfInit, LOS_INIT_LEVEL_KMOD_EXTENDED);
|
||||
158
kernel/extended/perf/los_perf_pri.h
Normal file
158
kernel/extended/perf/los_perf_pri.h
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
|
||||
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _LOS_PERF_PRI_H
|
||||
#define _LOS_PERF_PRI_H
|
||||
|
||||
#include "los_perf.h"
|
||||
#include "perf.h"
|
||||
#include "los_mp.h"
|
||||
#include "los_task_pri.h"
|
||||
#include "los_exc_pri.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define PERF_EVENT_TO_CODE 0
|
||||
#define PERF_CODE_TO_EVENT 1
|
||||
#define PERF_DATA_MAGIC_WORD 0xEFEFEF00
|
||||
|
||||
#define SMP_CALL_PERF_FUNC(func) OsMpFuncCall(OS_MP_CPU_ALL, (SMP_FUNC_CALL)func, NULL)
|
||||
|
||||
enum PmuStatus {
|
||||
PERF_PMU_STOPED,
|
||||
PERF_PMU_STARTED,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
UINTPTR pc;
|
||||
UINTPTR fp;
|
||||
} PerfRegs;
|
||||
|
||||
typedef struct {
|
||||
UINT32 ipNr;
|
||||
IpInfo ip[PERF_MAX_CALLCHAIN_DEPTH];
|
||||
} PerfBackTrace;
|
||||
|
||||
typedef struct {
|
||||
UINT32 cpuid; /* cpu id */
|
||||
UINT32 taskId; /* task id */
|
||||
UINT32 processId; /* process id */
|
||||
UINT32 eventId; /* record type */
|
||||
UINT32 period; /* record period */
|
||||
UINT64 time; /* record time */
|
||||
IpInfo pc; /* instruction pointer */
|
||||
PerfBackTrace callChain; /* number of callChain ips */
|
||||
} PerfSampleData;
|
||||
|
||||
typedef struct {
|
||||
UINT32 magic; /* magic number */
|
||||
UINT32 eventType; /* enum PerfEventType */
|
||||
UINT32 len; /* sample data file length */
|
||||
UINT32 sampleType; /* IP | TID | TIMESTAMP... */
|
||||
UINT32 sectionId; /* section id */
|
||||
} PerfDataHdr;
|
||||
|
||||
typedef struct {
|
||||
UINT32 counter;
|
||||
UINT32 eventId;
|
||||
UINT32 period;
|
||||
UINT64 count[LOSCFG_KERNEL_CORE_NUM];
|
||||
} Event;
|
||||
|
||||
typedef struct {
|
||||
Event per[PERF_MAX_EVENT];
|
||||
UINT8 nr;
|
||||
UINT8 cntDivided;
|
||||
} PerfEvent;
|
||||
|
||||
typedef struct {
|
||||
enum PerfEventType type;
|
||||
PerfEvent events;
|
||||
UINT32 (*config)(VOID);
|
||||
UINT32 (*start)(VOID);
|
||||
UINT32 (*stop)(VOID);
|
||||
CHAR *(*getName)(Event *event);
|
||||
} Pmu;
|
||||
|
||||
typedef struct {
|
||||
/* time info */
|
||||
UINT64 startTime;
|
||||
UINT64 endTime;
|
||||
|
||||
/* instrumentation status */
|
||||
enum PerfStatus status;
|
||||
enum PmuStatus pmuStatusPerCpu[LOSCFG_KERNEL_CORE_NUM];
|
||||
|
||||
/* configuration info */
|
||||
UINT32 sampleType;
|
||||
UINT32 taskIds[PERF_MAX_FILTER_TSKS];
|
||||
UINT8 taskIdsNr;
|
||||
UINT32 processIds[PERF_MAX_FILTER_TSKS];
|
||||
UINT8 processIdsNr;
|
||||
UINT8 needSample;
|
||||
} PerfCB;
|
||||
|
||||
#ifndef OsPerfArchFetchIrqRegs
|
||||
STATIC INLINE VOID OsPerfArchFetchIrqRegs(PerfRegs *regs, LosTaskCB *curTask) {}
|
||||
#endif
|
||||
|
||||
STATIC INLINE VOID OsPerfFetchIrqRegs(PerfRegs *regs)
|
||||
{
|
||||
LosTaskCB *curTask = OsCurrTaskGet();
|
||||
OsPerfArchFetchIrqRegs(regs, curTask);
|
||||
PRINT_DEBUG("pc = 0x%x, fp = 0x%x\n", regs->pc, regs->fp);
|
||||
}
|
||||
|
||||
#ifndef OsPerfArchFetchCallerRegs
|
||||
STATIC INLINE VOID OsPerfArchFetchCallerRegs(PerfRegs *regs) {}
|
||||
#endif
|
||||
|
||||
STATIC INLINE VOID OsPerfFetchCallerRegs(PerfRegs *regs)
|
||||
{
|
||||
OsPerfArchFetchCallerRegs(regs);
|
||||
PRINT_DEBUG("pc = 0x%x, fp = 0x%x\n", regs->pc, regs->fp);
|
||||
}
|
||||
|
||||
extern VOID OsPerfSetIrqRegs(UINTPTR pc, UINTPTR fp);
|
||||
extern VOID OsPerfUpdateEventCount(Event *event, UINT32 value);
|
||||
extern VOID OsPerfHandleOverFlow(Event *event, PerfRegs *regs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* _LOS_PERF_PRI_H */
|
||||
126
kernel/extended/perf/perf_output.c
Normal file
126
kernel/extended/perf/perf_output.c
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
|
||||
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
|
||||
*
|
||||
* 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 "perf_output_pri.h"
|
||||
|
||||
STATIC PERF_BUF_NOTIFY_HOOK g_perfBufNotifyHook = NULL;
|
||||
STATIC PERF_BUF_FLUSH_HOOK g_perfBufFlushHook = NULL;
|
||||
STATIC PerfOutputCB g_perfOutputCb;
|
||||
|
||||
STATIC VOID OsPerfDefaultNotify(VOID)
|
||||
{
|
||||
PRINT_INFO("perf buf waterline notify!\n");
|
||||
}
|
||||
|
||||
UINT32 OsPerfOutputInit(VOID *buf, UINT32 size)
|
||||
{
|
||||
UINT32 ret;
|
||||
BOOL releaseFlag = FALSE;
|
||||
if (buf == NULL) {
|
||||
buf = LOS_MemAlloc(m_aucSysMem1, size);
|
||||
if (buf == NULL) {
|
||||
return LOS_NOK;
|
||||
} else {
|
||||
releaseFlag = TRUE;
|
||||
}
|
||||
}
|
||||
ret = LOS_CirBufInit(&g_perfOutputCb.ringbuf, buf, size);
|
||||
if (ret != LOS_OK) {
|
||||
goto RELEASE;
|
||||
}
|
||||
g_perfOutputCb.waterMark = size / PERF_BUFFER_WATERMARK_ONE_N;
|
||||
g_perfBufNotifyHook = OsPerfDefaultNotify;
|
||||
return ret;
|
||||
RELEASE:
|
||||
if (releaseFlag) {
|
||||
(VOID)LOS_MemFree(m_aucSysMem1, buf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
VOID OsPerfOutputFlush(VOID)
|
||||
{
|
||||
if (g_perfBufFlushHook != NULL) {
|
||||
g_perfBufFlushHook(g_perfOutputCb.ringbuf.fifo, g_perfOutputCb.ringbuf.size);
|
||||
}
|
||||
}
|
||||
|
||||
UINT32 OsPerfOutputRead(CHAR *dest, UINT32 size)
|
||||
{
|
||||
OsPerfOutputFlush();
|
||||
return LOS_CirBufRead(&g_perfOutputCb.ringbuf, dest, size);
|
||||
}
|
||||
|
||||
STATIC BOOL OsPerfOutputBegin(UINT32 size)
|
||||
{
|
||||
if (g_perfOutputCb.ringbuf.remain < size) {
|
||||
PRINT_INFO("perf buf has no enough space for 0x%x\n", size);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
STATIC VOID OsPerfOutputEnd(VOID)
|
||||
{
|
||||
OsPerfOutputFlush();
|
||||
if (LOS_CirBufUsedSize(&g_perfOutputCb.ringbuf) >= g_perfOutputCb.waterMark) {
|
||||
if (g_perfBufNotifyHook != NULL) {
|
||||
g_perfBufNotifyHook();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UINT32 OsPerfOutputWrite(CHAR *data, UINT32 size)
|
||||
{
|
||||
if (!OsPerfOutputBegin(size)) {
|
||||
return LOS_NOK;
|
||||
}
|
||||
|
||||
LOS_CirBufWrite(&g_perfOutputCb.ringbuf, data, size);
|
||||
|
||||
OsPerfOutputEnd();
|
||||
return LOS_OK;
|
||||
}
|
||||
|
||||
VOID OsPerfOutputInfo(VOID)
|
||||
{
|
||||
PRINT_EMG("dump perf data, addr: %p length: %#x\n", g_perfOutputCb.ringbuf.fifo, g_perfOutputCb.ringbuf.size);
|
||||
}
|
||||
|
||||
VOID OsPerfNotifyHookReg(const PERF_BUF_NOTIFY_HOOK func)
|
||||
{
|
||||
g_perfBufNotifyHook = func;
|
||||
}
|
||||
|
||||
VOID OsPerfFlushHookReg(const PERF_BUF_FLUSH_HOOK func)
|
||||
{
|
||||
g_perfBufFlushHook = func;
|
||||
}
|
||||
63
kernel/extended/perf/perf_output_pri.h
Normal file
63
kernel/extended/perf/perf_output_pri.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
|
||||
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _PERF_OUTPUT_PRI_H
|
||||
#define _PERF_OUTPUT_PRI_H
|
||||
|
||||
#include "los_perf_pri.h"
|
||||
#include "los_cir_buf.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct {
|
||||
CirBuf ringbuf; /* ring buffer */
|
||||
UINT32 waterMark; /* notify water mark */
|
||||
} PerfOutputCB;
|
||||
|
||||
extern UINT32 OsPerfOutputInit(VOID *buf, UINT32 size);
|
||||
extern UINT32 OsPerfOutputRead(CHAR *dest, UINT32 size);
|
||||
extern UINT32 OsPerfOutputWrite(CHAR *data, UINT32 size);
|
||||
extern VOID OsPerfOutputInfo(VOID);
|
||||
extern VOID OsPerfOutputFlush(VOID);
|
||||
extern VOID OsPerfNotifyHookReg(const PERF_BUF_NOTIFY_HOOK func);
|
||||
extern VOID OsPerfFlushHookReg(const PERF_BUF_FLUSH_HOOK func);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* _PERF_OUTPUT_PRI_H */
|
||||
70
kernel/extended/perf/perf_pmu.c
Normal file
70
kernel/extended/perf/perf_pmu.c
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
|
||||
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
|
||||
*
|
||||
* 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 "perf_pmu_pri.h"
|
||||
|
||||
STATIC Pmu *g_pmuMgr[PERF_EVENT_TYPE_MAX] = { NULL };
|
||||
|
||||
UINT32 OsPerfPmuRegister(Pmu *pmu)
|
||||
{
|
||||
UINT32 type;
|
||||
|
||||
if ((pmu == NULL) || (pmu->type >= PERF_EVENT_TYPE_MAX)) {
|
||||
return LOS_NOK;
|
||||
}
|
||||
|
||||
type = pmu->type;
|
||||
if (g_pmuMgr[type] == NULL) {
|
||||
g_pmuMgr[type] = pmu;
|
||||
return LOS_OK;
|
||||
}
|
||||
return LOS_NOK;
|
||||
}
|
||||
|
||||
Pmu *OsPerfPmuGet(UINT32 type)
|
||||
{
|
||||
if (type >= PERF_EVENT_TYPE_MAX) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (type == PERF_EVENT_TYPE_RAW) { /* process hardware raw events with hard pmu */
|
||||
type = PERF_EVENT_TYPE_HW;
|
||||
}
|
||||
return g_pmuMgr[type];
|
||||
}
|
||||
|
||||
VOID OsPerfPmuRm(UINT32 type)
|
||||
{
|
||||
if (type >= PERF_EVENT_TYPE_MAX) {
|
||||
return;
|
||||
}
|
||||
g_pmuMgr[type] = NULL;
|
||||
}
|
||||
130
kernel/extended/perf/perf_pmu_pri.h
Normal file
130
kernel/extended/perf/perf_pmu_pri.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
|
||||
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _PERF_PMU_PRI_H
|
||||
#define _PERF_PMU_PRI_H
|
||||
|
||||
#include "los_perf_pri.h"
|
||||
|
||||
#ifdef LOSCFG_HRTIMER_ENABLE
|
||||
#include "linux/hrtimer.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct {
|
||||
Pmu pmu;
|
||||
BOOL canDivided;
|
||||
UINT32 cntDivided;
|
||||
VOID (*enable)(Event *event);
|
||||
VOID (*disable)(Event *event);
|
||||
VOID (*start)(VOID);
|
||||
VOID (*stop)(VOID);
|
||||
VOID (*clear)(VOID);
|
||||
VOID (*setPeriod)(Event *event);
|
||||
UINTPTR (*readCnt)(Event *event);
|
||||
UINT32 (*mapEvent)(UINT32 eventType, BOOL reverse);
|
||||
} HwPmu;
|
||||
|
||||
typedef struct {
|
||||
Pmu pmu;
|
||||
union {
|
||||
struct { /* trace event */
|
||||
BOOL enable;
|
||||
};
|
||||
#ifdef LOSCFG_HRTIMER_ENABLE
|
||||
struct { /* timer event */
|
||||
struct hrtimer hrtimer;
|
||||
union ktime time;
|
||||
union ktime cfgTime;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
} SwPmu;
|
||||
|
||||
#define GET_HW_PMU(item) LOS_DL_LIST_ENTRY(item, HwPmu, pmu)
|
||||
|
||||
#define TIMER_PERIOD_LOWER_BOUND_US 100
|
||||
|
||||
#define CCNT_FULL 0xFFFFFFFF
|
||||
#define CCNT_PERIOD_LOWER_BOUND 0x00000000
|
||||
#define CCNT_PERIOD_UPPER_BOUND 0xFFFFFF00
|
||||
#define PERIOD_CALC(p) (CCNT_FULL - (p))
|
||||
#define VALID_PERIOD(p) ((PERIOD_CALC(p) > CCNT_PERIOD_LOWER_BOUND) \
|
||||
&& (PERIOD_CALC(p) < CCNT_PERIOD_UPPER_BOUND))
|
||||
|
||||
#define PERF_HW_INVALID_EVENT_TYPE 0xFFFFFFFF
|
||||
|
||||
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
|
||||
|
||||
#define PMU_LABEL_INT_1 \
|
||||
NUM_HAL_INTERRUPT_PMU_0,
|
||||
#define PMU_LABEL_INT_2 \
|
||||
PMU_LABEL_INT_1 \
|
||||
NUM_HAL_INTERRUPT_PMU_1,
|
||||
#define PMU_LABEL_INT_3 \
|
||||
PMU_LABEL_INT_2 \
|
||||
NUM_HAL_INTERRUPT_PMU_2,
|
||||
#define PMU_LABEL_INT_4 \
|
||||
PMU_LABEL_INT_3 \
|
||||
NUM_HAL_INTERRUPT_PMU_3,
|
||||
|
||||
#define PMU_INT(_num) PMU_LABEL_INT_##_num
|
||||
|
||||
#define OS_PMU_INTS(_num, _list) \
|
||||
STATIC UINT32 _list [_num] = { \
|
||||
PMU_INT(_num) \
|
||||
}
|
||||
|
||||
extern UINT32 OsPerfPmuRegister(Pmu *pmu);
|
||||
extern VOID OsPerfPmuRm(UINT32 type);
|
||||
extern Pmu *OsPerfPmuGet(UINT32 type);
|
||||
|
||||
extern UINT32 OsHwPmuInit(VOID);
|
||||
extern UINT32 OsSwPmuInit(VOID);
|
||||
extern UINT32 OsTimedPmuInit(VOID);
|
||||
|
||||
extern UINT32 OsGetPmuCounter0(VOID);
|
||||
extern UINT32 OsGetPmuMaxCounter(VOID);
|
||||
extern UINT32 OsGetPmuCycleCounter(VOID);
|
||||
extern UINT32 OsPerfHwInit(HwPmu *hwPmu);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* _PERF_PMU_PRI_H */
|
||||
187
kernel/extended/perf/pmu/perf_hw_pmu.c
Normal file
187
kernel/extended/perf/pmu/perf_hw_pmu.c
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
|
||||
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
|
||||
*
|
||||
* 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 "perf_pmu_pri.h"
|
||||
|
||||
STATIC Pmu *g_perfHw = NULL;
|
||||
|
||||
STATIC CHAR *g_eventName[PERF_COUNT_HW_MAX] = {
|
||||
[PERF_COUNT_HW_CPU_CYCLES] = "cycles",
|
||||
[PERF_COUNT_HW_INSTRUCTIONS] = "instructions",
|
||||
[PERF_COUNT_HW_ICACHE_REFERENCES] = "icache",
|
||||
[PERF_COUNT_HW_ICACHE_MISSES] = "icache-misses",
|
||||
[PERF_COUNT_HW_DCACHE_REFERENCES] = "dcache",
|
||||
[PERF_COUNT_HW_DCACHE_MISSES] = "dcache-misses",
|
||||
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = "branches",
|
||||
[PERF_COUNT_HW_BRANCH_MISSES] = "branches-misses",
|
||||
};
|
||||
|
||||
/**
|
||||
* 1.If config event is PERF_EVENT_TYPE_HW, then map it to the real eventId first, otherwise use the configured
|
||||
* eventId directly.
|
||||
* 2.Find available counter for each event.
|
||||
* 3.Decide whether this hardware pmu need prescaler (once every 64 cycle counts).
|
||||
*/
|
||||
STATIC UINT32 OsPerfHwConfig(VOID)
|
||||
{
|
||||
UINT32 i;
|
||||
HwPmu *armPmu = GET_HW_PMU(g_perfHw);
|
||||
|
||||
UINT32 maxCounter = OsGetPmuMaxCounter();
|
||||
UINT32 counter = OsGetPmuCounter0();
|
||||
UINT32 cycleCounter = OsGetPmuCycleCounter();
|
||||
UINT32 cycleCode = armPmu->mapEvent(PERF_COUNT_HW_CPU_CYCLES, PERF_EVENT_TO_CODE);
|
||||
if (cycleCode == PERF_HW_INVALID_EVENT_TYPE) {
|
||||
return LOS_NOK;
|
||||
}
|
||||
|
||||
PerfEvent *events = &g_perfHw->events;
|
||||
UINT32 eventNum = events->nr;
|
||||
|
||||
for (i = 0; i < eventNum; i++) {
|
||||
Event *event = &(events->per[i]);
|
||||
|
||||
if (!VALID_PERIOD(event->period)) {
|
||||
PRINT_ERR("Config period: 0x%x invalid, should be in (%#x, %#x)\n", event->period,
|
||||
PERIOD_CALC(CCNT_PERIOD_UPPER_BOUND), PERIOD_CALC(CCNT_PERIOD_LOWER_BOUND));
|
||||
return LOS_NOK;
|
||||
}
|
||||
|
||||
if (g_perfHw->type == PERF_EVENT_TYPE_HW) { /* do map */
|
||||
UINT32 eventId = armPmu->mapEvent(event->eventId, PERF_EVENT_TO_CODE);
|
||||
if (eventId == PERF_HW_INVALID_EVENT_TYPE) {
|
||||
return LOS_NOK;
|
||||
}
|
||||
event->eventId = eventId;
|
||||
}
|
||||
|
||||
if (event->eventId == cycleCode) {
|
||||
event->counter = cycleCounter;
|
||||
} else {
|
||||
event->counter = counter;
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (counter >= maxCounter) {
|
||||
PRINT_ERR("max events: %u excluding cycle event\n", maxCounter - 1);
|
||||
return LOS_NOK;
|
||||
}
|
||||
|
||||
PRINT_DEBUG("Perf Config %u eventId = 0x%x, counter = 0x%x, period = 0x%x\n", i, event->eventId, event->counter,
|
||||
event->period);
|
||||
}
|
||||
|
||||
armPmu->cntDivided = events->cntDivided & armPmu->canDivided;
|
||||
return LOS_OK;
|
||||
}
|
||||
|
||||
STATIC UINT32 OsPerfHwStart(VOID)
|
||||
{
|
||||
UINT32 i;
|
||||
UINT32 cpuid = ArchCurrCpuid();
|
||||
HwPmu *armPmu = GET_HW_PMU(g_perfHw);
|
||||
|
||||
PerfEvent *events = &g_perfHw->events;
|
||||
UINT32 eventNum = events->nr;
|
||||
|
||||
armPmu->clear();
|
||||
|
||||
for (i = 0; i < eventNum; i++) {
|
||||
Event *event = &(events->per[i]);
|
||||
armPmu->setPeriod(event);
|
||||
armPmu->enable(event);
|
||||
event->count[cpuid] = 0;
|
||||
}
|
||||
|
||||
armPmu->start();
|
||||
return LOS_OK;
|
||||
}
|
||||
|
||||
STATIC UINT32 OsPerfHwStop(VOID)
|
||||
{
|
||||
UINT32 i;
|
||||
UINT32 cpuid = ArchCurrCpuid();
|
||||
HwPmu *armPmu = GET_HW_PMU(g_perfHw);
|
||||
|
||||
PerfEvent *events = &g_perfHw->events;
|
||||
UINT32 eventNum = events->nr;
|
||||
|
||||
armPmu->stop();
|
||||
|
||||
for (i = 0; i < eventNum; i++) {
|
||||
Event *event = &(events->per[i]);
|
||||
UINTPTR value = armPmu->readCnt(event);
|
||||
PRINT_DEBUG("perf stop readCnt value = 0x%x\n", value);
|
||||
event->count[cpuid] += value;
|
||||
|
||||
/* multiplier of cycle counter */
|
||||
UINT32 eventId = armPmu->mapEvent(event->eventId, PERF_CODE_TO_EVENT);
|
||||
if ((eventId == PERF_COUNT_HW_CPU_CYCLES) && (armPmu->cntDivided != 0)) {
|
||||
PRINT_DEBUG("perf stop is cycle\n");
|
||||
event->count[cpuid] = event->count[cpuid] << 6; /* CCNT counts every 64th cpu cycle */
|
||||
}
|
||||
PRINT_DEBUG("perf stop eventCount[0x%x] : [%s] = %llu\n", event->eventId, g_eventName[eventId],
|
||||
event->count[cpuid]);
|
||||
}
|
||||
return LOS_OK;
|
||||
}
|
||||
|
||||
STATIC CHAR *OsPerfGetEventName(Event *event)
|
||||
{
|
||||
UINT32 eventId;
|
||||
HwPmu *armPmu = GET_HW_PMU(g_perfHw);
|
||||
eventId = armPmu->mapEvent(event->eventId, PERF_CODE_TO_EVENT);
|
||||
if (eventId < PERF_COUNT_HW_MAX) {
|
||||
return g_eventName[eventId];
|
||||
} else {
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
UINT32 OsPerfHwInit(HwPmu *hwPmu)
|
||||
{
|
||||
UINT32 ret;
|
||||
if (hwPmu == NULL) {
|
||||
return LOS_NOK;
|
||||
}
|
||||
|
||||
hwPmu->pmu.type = PERF_EVENT_TYPE_HW;
|
||||
hwPmu->pmu.config = OsPerfHwConfig;
|
||||
hwPmu->pmu.start = OsPerfHwStart;
|
||||
hwPmu->pmu.stop = OsPerfHwStop;
|
||||
hwPmu->pmu.getName = OsPerfGetEventName;
|
||||
|
||||
(VOID)memset_s(&hwPmu->pmu.events, sizeof(PerfEvent), 0, sizeof(PerfEvent));
|
||||
ret = OsPerfPmuRegister(&hwPmu->pmu);
|
||||
|
||||
g_perfHw = OsPerfPmuGet(PERF_EVENT_TYPE_HW);
|
||||
return ret;
|
||||
}
|
||||
169
kernel/extended/perf/pmu/perf_sw_pmu.c
Normal file
169
kernel/extended/perf/pmu/perf_sw_pmu.c
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
|
||||
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
|
||||
*
|
||||
* 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 "perf_pmu_pri.h"
|
||||
#include "los_hook.h"
|
||||
|
||||
STATIC SwPmu g_perfSw;
|
||||
STATIC CHAR *g_eventName[PERF_COUNT_SW_MAX] = {
|
||||
[PERF_COUNT_SW_TASK_SWITCH] = "task switch",
|
||||
[PERF_COUNT_SW_IRQ_RESPONSE] = "irq response",
|
||||
[PERF_COUNT_SW_MEM_ALLOC] = "mem alloc",
|
||||
[PERF_COUNT_SW_MUX_PEND] = "mux pend",
|
||||
};
|
||||
|
||||
STATIC UINT32 g_traceEventMap[PERF_COUNT_SW_MAX] = {
|
||||
[PERF_COUNT_SW_TASK_SWITCH] = LOS_HOOK_TYPE_TASK_SWITCHEDIN,
|
||||
[PERF_COUNT_SW_IRQ_RESPONSE] = LOS_HOOK_TYPE_ISR_ENTER,
|
||||
[PERF_COUNT_SW_MEM_ALLOC] = LOS_HOOK_TYPE_MEM_ALLOC,
|
||||
[PERF_COUNT_SW_MUX_PEND] = LOS_HOOK_TYPE_MUX_PEND,
|
||||
};
|
||||
|
||||
VOID OsPerfHook(UINT32 eventType)
|
||||
{
|
||||
if (!g_perfSw.enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
PerfEvent *events = &g_perfSw.pmu.events;
|
||||
UINT32 eventNum = events->nr;
|
||||
|
||||
UINT32 i;
|
||||
PerfRegs regs;
|
||||
|
||||
(VOID)memset_s(®s, sizeof(PerfRegs), 0, sizeof(PerfRegs));
|
||||
|
||||
for (i = 0; i < eventNum; i++) {
|
||||
Event *event = &(events->per[i]);
|
||||
if (event->counter == eventType) {
|
||||
OsPerfUpdateEventCount(event, 1);
|
||||
if (event->count[ArchCurrCpuid()] % event->period == 0) {
|
||||
OsPerfFetchCallerRegs(®s);
|
||||
OsPerfHandleOverFlow(event, ®s);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC VOID LOS_PerfMemAlloc(VOID *pool, VOID *ptr, UINT32 size)
|
||||
{
|
||||
OsPerfHook(LOS_HOOK_TYPE_MEM_ALLOC);
|
||||
}
|
||||
|
||||
STATIC VOID LOS_PerfMuxPend(const LosMux *muxCB, UINT32 timeout)
|
||||
{
|
||||
OsPerfHook(LOS_HOOK_TYPE_MUX_PEND);
|
||||
}
|
||||
|
||||
STATIC VOID LOS_PerfIsrEnter(UINT32 hwiNum)
|
||||
{
|
||||
OsPerfHook(LOS_HOOK_TYPE_ISR_ENTER);
|
||||
}
|
||||
|
||||
STATIC VOID LOS_PerfTaskSwitchedIn(const LosTaskCB *newTask, const LosTaskCB *runTask)
|
||||
{
|
||||
OsPerfHook(LOS_HOOK_TYPE_TASK_SWITCHEDIN);
|
||||
}
|
||||
|
||||
STATIC VOID OsPerfCnvInit(VOID)
|
||||
{
|
||||
LOS_HookReg(LOS_HOOK_TYPE_MEM_ALLOC, LOS_PerfMemAlloc);
|
||||
LOS_HookReg(LOS_HOOK_TYPE_MUX_PEND, LOS_PerfMuxPend);
|
||||
LOS_HookReg(LOS_HOOK_TYPE_ISR_ENTER, LOS_PerfIsrEnter);
|
||||
LOS_HookReg(LOS_HOOK_TYPE_TASK_SWITCHEDIN, LOS_PerfTaskSwitchedIn);
|
||||
}
|
||||
|
||||
STATIC UINT32 OsPerfSwConfig(VOID)
|
||||
{
|
||||
UINT32 i;
|
||||
PerfEvent *events = &g_perfSw.pmu.events;
|
||||
UINT32 eventNum = events->nr;
|
||||
|
||||
for (i = 0; i < eventNum; i++) {
|
||||
Event *event = &(events->per[i]);
|
||||
if ((event->eventId < PERF_COUNT_SW_TASK_SWITCH) || (event->eventId >= PERF_COUNT_SW_MAX) ||
|
||||
(event->period == 0)) {
|
||||
return LOS_NOK;
|
||||
}
|
||||
event->counter = g_traceEventMap[event->eventId];
|
||||
}
|
||||
return LOS_OK;
|
||||
}
|
||||
|
||||
STATIC UINT32 OsPerfSwStart(VOID)
|
||||
{
|
||||
UINT32 i;
|
||||
UINT32 cpuid = ArchCurrCpuid();
|
||||
PerfEvent *events = &g_perfSw.pmu.events;
|
||||
UINT32 eventNum = events->nr;
|
||||
|
||||
for (i = 0; i < eventNum; i++) {
|
||||
Event *event = &(events->per[i]);
|
||||
event->count[cpuid] = 0;
|
||||
}
|
||||
|
||||
g_perfSw.enable = TRUE;
|
||||
return LOS_OK;
|
||||
}
|
||||
|
||||
STATIC UINT32 OsPerfSwStop(VOID)
|
||||
{
|
||||
g_perfSw.enable = FALSE;
|
||||
return LOS_OK;
|
||||
}
|
||||
|
||||
STATIC CHAR *OsPerfGetEventName(Event *event)
|
||||
{
|
||||
UINT32 eventId = event->eventId;
|
||||
if (eventId < PERF_COUNT_SW_MAX) {
|
||||
return g_eventName[eventId];
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
UINT32 OsSwPmuInit(VOID)
|
||||
{
|
||||
g_perfSw.pmu = (Pmu) {
|
||||
.type = PERF_EVENT_TYPE_SW,
|
||||
.config = OsPerfSwConfig,
|
||||
.start = OsPerfSwStart,
|
||||
.stop = OsPerfSwStop,
|
||||
.getName = OsPerfGetEventName,
|
||||
};
|
||||
|
||||
g_perfSw.enable = FALSE;
|
||||
|
||||
OsPerfCnvInit();
|
||||
|
||||
(VOID)memset_s(&g_perfSw.pmu.events, sizeof(PerfEvent), 0, sizeof(PerfEvent));
|
||||
return OsPerfPmuRegister(&g_perfSw.pmu);
|
||||
}
|
||||
177
kernel/extended/perf/pmu/perf_timed_pmu.c
Normal file
177
kernel/extended/perf/pmu/perf_timed_pmu.c
Normal file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
|
||||
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
|
||||
*
|
||||
* 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 "perf_pmu_pri.h"
|
||||
|
||||
#define US_PER_SECOND 1000000
|
||||
#define HRTIMER_DEFAULT_PERIOD_US 1000
|
||||
|
||||
STATIC SwPmu g_perfTimed;
|
||||
|
||||
STATIC BOOL OsPerfTimedPeriodValid(UINT32 period)
|
||||
{
|
||||
return period >= TIMER_PERIOD_LOWER_BOUND_US;
|
||||
}
|
||||
|
||||
STATIC UINT32 OsPerfTimedStart(VOID)
|
||||
{
|
||||
UINT32 i;
|
||||
UINT32 cpuid = ArchCurrCpuid();
|
||||
PerfEvent *events = &g_perfTimed.pmu.events;
|
||||
UINT32 eventNum = events->nr;
|
||||
|
||||
for (i = 0; i < eventNum; i++) {
|
||||
Event *event = &(events->per[i]);
|
||||
event->count[cpuid] = 0;
|
||||
}
|
||||
|
||||
if (cpuid != 0) { /* only need start on one core */
|
||||
return LOS_OK;
|
||||
}
|
||||
|
||||
if (hrtimer_start(&g_perfTimed.hrtimer, g_perfTimed.time, HRTIMER_MODE_REL) != 0) {
|
||||
PRINT_ERR("Hrtimer start failed\n");
|
||||
return LOS_NOK;
|
||||
}
|
||||
|
||||
if (hrtimer_forward(&g_perfTimed.hrtimer, g_perfTimed.cfgTime) == 0) {
|
||||
PRINT_ERR("Hrtimer forward failed\n");
|
||||
return LOS_NOK;
|
||||
}
|
||||
|
||||
g_perfTimed.time = g_perfTimed.cfgTime;
|
||||
return LOS_OK;
|
||||
}
|
||||
|
||||
STATIC UINT32 OsPerfTimedConfig(VOID)
|
||||
{
|
||||
UINT32 i;
|
||||
PerfEvent *events = &g_perfTimed.pmu.events;
|
||||
UINT32 eventNum = events->nr;
|
||||
|
||||
for (i = 0; i < eventNum; i++) {
|
||||
Event *event = &(events->per[i]);
|
||||
UINT32 period = event->period;
|
||||
if (event->eventId == PERF_COUNT_CPU_CLOCK) {
|
||||
if (!OsPerfTimedPeriodValid(period)) {
|
||||
period = TIMER_PERIOD_LOWER_BOUND_US;
|
||||
PRINT_ERR("config period invalid, should be >= 100, use default period:%u us\n", period);
|
||||
}
|
||||
|
||||
g_perfTimed.cfgTime = (union ktime) {
|
||||
.tv.sec = period / US_PER_SECOND,
|
||||
.tv.usec = period % US_PER_SECOND
|
||||
};
|
||||
PRINT_INFO("hrtimer config period - sec:%d, usec:%d\n", g_perfTimed.cfgTime.tv.sec,
|
||||
g_perfTimed.cfgTime.tv.usec);
|
||||
return LOS_OK;
|
||||
}
|
||||
}
|
||||
return LOS_NOK;
|
||||
}
|
||||
|
||||
STATIC UINT32 OsPerfTimedStop(VOID)
|
||||
{
|
||||
UINT32 ret;
|
||||
|
||||
if (ArchCurrCpuid() != 0) { /* only need stop on one core */
|
||||
return LOS_OK;
|
||||
}
|
||||
|
||||
ret = hrtimer_cancel(&g_perfTimed.hrtimer);
|
||||
if (ret != 1) {
|
||||
PRINT_ERR("Hrtimer stop failed!, 0x%x\n", ret);
|
||||
return LOS_NOK;
|
||||
}
|
||||
return LOS_OK;
|
||||
}
|
||||
|
||||
STATIC VOID OsPerfTimedHandle(VOID)
|
||||
{
|
||||
UINT32 index;
|
||||
PerfRegs regs;
|
||||
|
||||
PerfEvent *events = &g_perfTimed.pmu.events;
|
||||
UINT32 eventNum = events->nr;
|
||||
|
||||
(VOID)memset_s(®s, sizeof(PerfRegs), 0, sizeof(PerfRegs));
|
||||
OsPerfFetchIrqRegs(®s);
|
||||
|
||||
for (index = 0; index < eventNum; index++) {
|
||||
Event *event = &(events->per[index]);
|
||||
OsPerfUpdateEventCount(event, 1); /* eventCount += 1 every once */
|
||||
OsPerfHandleOverFlow(event, ®s);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC enum hrtimer_restart OsPerfHrtimer(struct hrtimer *hrtimer)
|
||||
{
|
||||
SMP_CALL_PERF_FUNC(OsPerfTimedHandle); /* send to all cpu to collect data */
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
|
||||
STATIC CHAR *OsPerfGetEventName(Event *event)
|
||||
{
|
||||
if (event->eventId == PERF_COUNT_CPU_CLOCK) {
|
||||
return "timed";
|
||||
} else {
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
UINT32 OsTimedPmuInit(VOID)
|
||||
{
|
||||
UINT32 ret;
|
||||
|
||||
g_perfTimed.time = (union ktime) {
|
||||
.tv.sec = 0,
|
||||
.tv.usec = HRTIMER_DEFAULT_PERIOD_US,
|
||||
};
|
||||
|
||||
hrtimer_init(&g_perfTimed.hrtimer, 1, HRTIMER_MODE_REL);
|
||||
|
||||
ret = hrtimer_create(&g_perfTimed.hrtimer, g_perfTimed.time, OsPerfHrtimer);
|
||||
if (ret != LOS_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
g_perfTimed.pmu = (Pmu) {
|
||||
.type = PERF_EVENT_TYPE_TIMED,
|
||||
.config = OsPerfTimedConfig,
|
||||
.start = OsPerfTimedStart,
|
||||
.stop = OsPerfTimedStop,
|
||||
.getName = OsPerfGetEventName,
|
||||
};
|
||||
|
||||
(VOID)memset_s(&g_perfTimed.pmu.events, sizeof(PerfEvent), 0, sizeof(PerfEvent));
|
||||
ret = OsPerfPmuRegister(&g_perfTimed.pmu);
|
||||
return ret;
|
||||
}
|
||||
@@ -143,6 +143,7 @@ enum LOS_MOUDLE_ID {
|
||||
LOS_MOD_MUX = 0X1d,
|
||||
LOS_MOD_CPUP = 0x1e,
|
||||
LOS_MOD_HOOK = 0x1f,
|
||||
LOS_MOD_PERF = 0x20,
|
||||
LOS_MOD_SHELL = 0x31,
|
||||
LOS_MOD_DRIVER = 0x41,
|
||||
LOS_MOD_BUTT
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#define _LOS_MP_H
|
||||
|
||||
#include "los_config.h"
|
||||
#include "los_list.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
@@ -48,8 +49,13 @@ typedef enum {
|
||||
LOS_MP_IPI_WAKEUP,
|
||||
LOS_MP_IPI_SCHEDULE,
|
||||
LOS_MP_IPI_HALT,
|
||||
#ifdef LOSCFG_KERNEL_SMP_CALL
|
||||
LOS_MP_IPI_FUNC_CALL,
|
||||
#endif
|
||||
} MP_IPI_TYPE;
|
||||
|
||||
typedef VOID (*SMP_FUNC_CALL)(VOID *args);
|
||||
|
||||
#ifdef LOSCFG_KERNEL_SMP
|
||||
extern VOID LOS_MpSchedule(UINT32 target);
|
||||
extern VOID OsMpWakeHandler(VOID);
|
||||
@@ -63,6 +69,28 @@ STATIC INLINE VOID LOS_MpSchedule(UINT32 target)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LOSCFG_KERNEL_SMP_CALL
|
||||
typedef struct {
|
||||
LOS_DL_LIST node;
|
||||
SMP_FUNC_CALL func;
|
||||
VOID *args;
|
||||
} MpCallFunc;
|
||||
|
||||
/**
|
||||
* It is used to call function on target cpus by sending ipi, and the first param is target cpu mask value.
|
||||
*/
|
||||
extern VOID OsMpFuncCall(UINT32 target, SMP_FUNC_CALL func, VOID *args);
|
||||
extern VOID OsMpFuncCallHandler(VOID);
|
||||
#else
|
||||
INLINE VOID OsMpFuncCall(UINT32 target, SMP_FUNC_CALL func, VOID *args)
|
||||
{
|
||||
(VOID)target;
|
||||
if (func != NULL) {
|
||||
func(args);
|
||||
}
|
||||
}
|
||||
#endif /* LOSCFG_KERNEL_SMP_CALL */
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
|
||||
439
kernel/include/los_perf.h
Normal file
439
kernel/include/los_perf.h
Normal file
@@ -0,0 +1,439 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
|
||||
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup los_perf Perf
|
||||
* @ingroup kernel
|
||||
*/
|
||||
|
||||
#ifndef _LOS_PERF_H
|
||||
#define _LOS_PERF_H
|
||||
|
||||
#include "los_typedef.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* Perf max sample filter task number.
|
||||
*/
|
||||
#define PERF_MAX_FILTER_TSKS 32
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* Perf max sample event counter's number.
|
||||
*/
|
||||
#define PERF_MAX_EVENT 7
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* Perf max backtrace depth.
|
||||
*/
|
||||
#define PERF_MAX_CALLCHAIN_DEPTH 10
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* Perf sample data buffer's water mark 1/N.
|
||||
*/
|
||||
#define PERF_BUFFER_WATERMARK_ONE_N 2
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* Perf status.
|
||||
*/
|
||||
enum PerfStatus {
|
||||
PERF_UNINIT, /* perf isn't inited */
|
||||
PERF_STARTED, /* perf is started */
|
||||
PERF_STOPPED, /* perf is stopped */
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* Define the type of the perf sample data buffer water mark hook function.
|
||||
*
|
||||
*/
|
||||
typedef VOID (*PERF_BUF_NOTIFY_HOOK)(VOID);
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* Define the type of the perf sample data buffer flush hook function.
|
||||
*
|
||||
*/
|
||||
typedef VOID (*PERF_BUF_FLUSH_HOOK)(VOID *addr, UINT32 size);
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* Perf error code: Bad status.
|
||||
*
|
||||
* Value: 0x02002000
|
||||
*
|
||||
* Solution: Follow the perf state machine.
|
||||
*/
|
||||
#define LOS_ERRNO_PERF_STATUS_INVALID LOS_ERRNO_OS_ERROR(LOS_MOD_PERF, 0x00)
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* Perf error code: Hardware pmu init failed.
|
||||
*
|
||||
* Value: 0x02002001
|
||||
*
|
||||
* Solution: Check the pmu hwi irq.
|
||||
*/
|
||||
#define LOS_ERRNO_PERF_HW_INIT_ERROR LOS_ERRNO_OS_ERROR(LOS_MOD_PERF, 0x01)
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* Perf error code: Hrtimer init failed for hrtimer timed pmu init.
|
||||
*
|
||||
* Value: 0x02002002
|
||||
*
|
||||
* Solution: Check the Hrtimer init.
|
||||
*/
|
||||
#define LOS_ERRNO_PERF_TIMED_INIT_ERROR LOS_ERRNO_OS_ERROR(LOS_MOD_PERF, 0x02)
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* Perf error code: Software pmu init failed.
|
||||
*
|
||||
* Value: 0x02002003
|
||||
*
|
||||
* Solution: Check the Perf software events init.
|
||||
*/
|
||||
#define LOS_ERRNO_PERF_SW_INIT_ERROR LOS_ERRNO_OS_ERROR(LOS_MOD_PERF, 0x03)
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* Perf error code: Perf buffer init failed.
|
||||
*
|
||||
* Value: 0x02002004
|
||||
*
|
||||
* Solution: Check the buffer init size.
|
||||
*/
|
||||
#define LOS_ERRNO_PERF_BUF_ERROR LOS_ERRNO_OS_ERROR(LOS_MOD_PERF, 0x04)
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* Perf error code: Perf pmu type error.
|
||||
*
|
||||
* Value: 0x02002005
|
||||
*
|
||||
* Solution: Check whether the corresponding pmu is enabled in the menuconfig.
|
||||
*/
|
||||
#define LOS_ERRNO_PERF_INVALID_PMU LOS_ERRNO_OS_ERROR(LOS_MOD_PERF, 0x05)
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* Perf error code: Perf pmu config error.
|
||||
*
|
||||
* Value: 0x02002006
|
||||
*
|
||||
* Solution: Check the config attr of event id and event period.
|
||||
*/
|
||||
#define LOS_ERRNO_PERF_PMU_CONFIG_ERROR LOS_ERRNO_OS_ERROR(LOS_MOD_PERF, 0x06)
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* Perf error code: Perf pmu config attr is NULL.
|
||||
*
|
||||
* Value: 0x02002007
|
||||
*
|
||||
* Solution: Check if the input params of attr is NULL.
|
||||
*/
|
||||
#define LOS_ERRNO_PERF_CONFIG_NULL LOS_ERRNO_OS_ERROR(LOS_MOD_PERF, 0x07)
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* Perf types
|
||||
*/
|
||||
enum PerfEventType {
|
||||
PERF_EVENT_TYPE_HW, /* boards common hw events */
|
||||
PERF_EVENT_TYPE_TIMED, /* hrtimer timed events */
|
||||
PERF_EVENT_TYPE_SW, /* software trace events */
|
||||
PERF_EVENT_TYPE_RAW, /* boards special hw events, see enum PmuEventType in corresponding arch headfile */
|
||||
|
||||
PERF_EVENT_TYPE_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* Common hardware pmu events
|
||||
*/
|
||||
enum PmuHwId {
|
||||
PERF_COUNT_HW_CPU_CYCLES = 0, /* cpu cycle event */
|
||||
PERF_COUNT_HW_INSTRUCTIONS, /* instruction event */
|
||||
PERF_COUNT_HW_DCACHE_REFERENCES, /* dcache access event */
|
||||
PERF_COUNT_HW_DCACHE_MISSES, /* dcache miss event */
|
||||
PERF_COUNT_HW_ICACHE_REFERENCES, /* icache access event */
|
||||
PERF_COUNT_HW_ICACHE_MISSES, /* icache miss event */
|
||||
PERF_COUNT_HW_BRANCH_INSTRUCTIONS, /* software change of pc event */
|
||||
PERF_COUNT_HW_BRANCH_MISSES, /* branch miss event */
|
||||
|
||||
PERF_COUNT_HW_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* Common hrtimer timed events
|
||||
*/
|
||||
enum PmuTimedId {
|
||||
PERF_COUNT_CPU_CLOCK = 0, /* hrtimer timed event */
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* Common software pmu events
|
||||
*/
|
||||
enum PmuSwId {
|
||||
PERF_COUNT_SW_TASK_SWITCH = 1, /* task switch event */
|
||||
PERF_COUNT_SW_IRQ_RESPONSE, /* irq response event */
|
||||
PERF_COUNT_SW_MEM_ALLOC, /* memory alloc event */
|
||||
PERF_COUNT_SW_MUX_PEND, /* mutex pend event */
|
||||
|
||||
PERF_COUNT_SW_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* perf sample data types
|
||||
* Config it through PerfConfigAttr->sampleType.
|
||||
*/
|
||||
enum PerfSampleType {
|
||||
PERF_RECORD_CPU = 1U << 0, /* record current cpuid */
|
||||
PERF_RECORD_TID = 1U << 1, /* record current task id */
|
||||
PERF_RECORD_TYPE = 1U << 2, /* record event type */
|
||||
PERF_RECORD_PERIOD = 1U << 3, /* record event period */
|
||||
PERF_RECORD_TIMESTAMP = 1U << 4, /* record timestamp */
|
||||
PERF_RECORD_IP = 1U << 5, /* record instruction pointer */
|
||||
PERF_RECORD_CALLCHAIN = 1U << 6, /* record backtrace */
|
||||
PERF_RECORD_PID = 1U << 7, /* record current process id */
|
||||
};
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* perf configuration sub event information
|
||||
*
|
||||
* This structure is used to config specific events attributes.
|
||||
*/
|
||||
typedef struct {
|
||||
UINT32 type; /* enum PerfEventType */
|
||||
struct {
|
||||
UINT32 eventId; /* the specific event corresponds to the PerfEventType */
|
||||
UINT32 period; /* event period, for every "period"th occurrence of the event a
|
||||
sample will be recorded */
|
||||
} events[PERF_MAX_EVENT]; /* perf event list */
|
||||
UINT32 eventsNr; /* total perf event number */
|
||||
BOOL predivided; /* whether to prescaler (once every 64 counts),
|
||||
which only take effect on cpu cycle hardware event */
|
||||
} PerfEventConfig;
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* perf configuration main information
|
||||
*
|
||||
* This structure is used to set perf sampling attributes, including events, tasks and other information.
|
||||
*/
|
||||
typedef struct {
|
||||
PerfEventConfig eventsCfg; /* perf event config */
|
||||
UINT32 taskIds[PERF_MAX_FILTER_TSKS]; /* perf task filter list (allowlist) */
|
||||
UINT32 taskIdsNr; /* task numbers of task filter allowlist,
|
||||
if set 0 perf will sample all tasks */
|
||||
UINT32 processIds[PERF_MAX_FILTER_TSKS]; /* perf process filter list (allowlist) */
|
||||
UINT32 processIdsNr; /* process numbers of process filter allowlist,
|
||||
if set 0 perf will sample all processes */
|
||||
UINT32 sampleType; /* type of data to sample defined in PerfSampleType */
|
||||
BOOL needSample; /* whether to sample data */
|
||||
} PerfConfigAttr;
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* @brief Init perf.
|
||||
*
|
||||
* @par Description:
|
||||
* <ul>
|
||||
* <li>Used to initialize the perf module, including initializing the PMU, allocating memory,
|
||||
* etc.,which is called during the phase of system initialization.</li>
|
||||
* </ul>
|
||||
* @attention
|
||||
* <ul>
|
||||
* <li>If buf is not NULL, user must ensure size is not bigger than buf's length.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param buf [IN] Pointer of sample data buffer;Use the dynamically allocated memory if the pointer is NULL.
|
||||
* @param size [IN] Length of sample data buffer.
|
||||
*
|
||||
* @retval #LOS_ERRNO_PERF_STATUS_INVALID Perf in a wrong status.
|
||||
* @retval #LOS_ERRNO_PERF_HW_INIT_ERROR Perf hardware pmu init fail.
|
||||
* @retval #LOS_ERRNO_PERF_TIMED_INIT_ERROR Perf timed pmu init fail.
|
||||
* @retval #LOS_ERRNO_PERF_SW_INIT_ERROR Perf software pmu init fail.
|
||||
* @retval #LOS_ERRNO_PERF_BUF_ERROR Perf buffer init fail.
|
||||
* @retval #LOS_OK Perf init success.
|
||||
* @par Dependency:
|
||||
* <ul>
|
||||
* <li>los_perf.h: the header file that contains the API declaration.</li>
|
||||
* </ul>
|
||||
*/
|
||||
UINT32 LOS_PerfInit(VOID *buf, UINT32 size);
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* @brief Start perf sampling.
|
||||
*
|
||||
* @par Description
|
||||
* Start perf sampling.
|
||||
* @attention
|
||||
* None.
|
||||
*
|
||||
* @param sectionId [IN] Set the section id for marking this piece of data in the perf sample data buffer.
|
||||
* @retval None.
|
||||
* @par Dependency:
|
||||
* <ul>
|
||||
* <li>los_perf.h: the header file that contains the API declaration.</li>
|
||||
* </ul>
|
||||
*/
|
||||
VOID LOS_PerfStart(UINT32 sectionId);
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* @brief Stop perf sampling.
|
||||
*
|
||||
* @par Description
|
||||
* Stop perf sampling.
|
||||
* @attention
|
||||
* None.
|
||||
*
|
||||
* @param None.
|
||||
*
|
||||
* @retval None.
|
||||
* @par Dependency:
|
||||
* <ul>
|
||||
* <li>los_perf.h: the header file that contains the API declaration.</li>
|
||||
* </ul>
|
||||
*/
|
||||
VOID LOS_PerfStop(VOID);
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* @brief Config perf parameters.
|
||||
*
|
||||
* @par Description
|
||||
* Config perf parameters before sample, for example, sample event, sample task, etc. This interface need to be called
|
||||
* before LOS_PerfStart.
|
||||
* @attention
|
||||
* None.
|
||||
*
|
||||
* @param attr [IN] Address of a perf event attr struct.
|
||||
*
|
||||
* @retval #LOS_ERRNO_PERF_STATUS_INVALID Perf in a wrong status.
|
||||
* @retval #LOS_ERRNO_PERF_CONFIG_NULL Attr is NULL.
|
||||
* @retval #LOS_ERRNO_PERF_INVALID_PMU Config perf pmu with error type.
|
||||
* @retval #LOS_ERRNO_PERF_PMU_CONFIG_ERROR Config perf events fail with invalid event id or event period.
|
||||
* @retval #LOS_OK Config success.
|
||||
* @par Dependency:
|
||||
* <ul>
|
||||
* <li>los_perf.h: the header file that contains the API declaration.</li>
|
||||
* </ul>
|
||||
*/
|
||||
UINT32 LOS_PerfConfig(PerfConfigAttr *attr);
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* @brief Read data from perf sample data buffer.
|
||||
*
|
||||
* @par Description
|
||||
* Because perf sample data buffer is a ringbuffer, the data may be covered after user read ringbuffer.
|
||||
* @attention
|
||||
* None.
|
||||
*
|
||||
* @param dest [IN] The destination address.
|
||||
* @param size [IN] Read size.
|
||||
* @retval #UINT32 The really read bytes.
|
||||
* @par Dependency:
|
||||
* <ul>
|
||||
* <li>los_perf.h: the header file that contains the API declaration.</li>
|
||||
* </ul>
|
||||
*/
|
||||
UINT32 LOS_PerfDataRead(CHAR *dest, UINT32 size);
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* @brief Register perf sample data buffer water mark hook function.
|
||||
*
|
||||
* @par Description
|
||||
* <ul>
|
||||
* <li> Register perf sample data buffer water mark hook function.</li>
|
||||
* <li> The registered hook will be called when buffer reaches the water mark./li>
|
||||
* </ul>
|
||||
* @attention
|
||||
* None.
|
||||
*
|
||||
* @param func [IN] Buffer water mark hook function.
|
||||
*
|
||||
* @retval None.
|
||||
* @par Dependency:
|
||||
* <ul>
|
||||
* <li>los_perf.h: the header file that contains the API declaration.</li>
|
||||
* </ul>
|
||||
*/
|
||||
VOID LOS_PerfNotifyHookReg(const PERF_BUF_NOTIFY_HOOK func);
|
||||
|
||||
/**
|
||||
* @ingroup los_perf
|
||||
* @brief Register perf sample data buffer flush hook function.
|
||||
*
|
||||
* @par Description
|
||||
* <ul>
|
||||
* <li> Register perf sample data buffer flush hook function.</li>
|
||||
* <li> The flush hook will be called when the buffer be read or written.</li>
|
||||
* </ul>
|
||||
* @attention
|
||||
* None.
|
||||
*
|
||||
* @param func [IN] Buffer flush hook function.
|
||||
*
|
||||
* @retval None.
|
||||
* @par Dependency:
|
||||
* <ul>
|
||||
* <li>los_perf.h: the header file that contains the API declaration.</li>
|
||||
* </ul>
|
||||
*/
|
||||
VOID LOS_PerfFlushHookReg(const PERF_BUF_FLUSH_HOOK func);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* _LOS_PERF_H */
|
||||
Reference in New Issue
Block a user