feat: L0-L1 支持Perf
1.【需求描述】: L0-L1 支持Perf,提供2种模式的配置, 及3大类型的事件配置: 2种模式:计数模式(仅统计事件发生次数)、采样模式(收集上下文如任务ID、pc、backtrace等)。 3种事件类型:CPU硬件事件(cycle、branch、icache、dcache等)、OS软件事件(task switch、mux pend、irq等)、高精度周期事件(cpu clock)。 2.【方案描述】: L0: 基于事件采样原理,以性能事件为基础,当事件发生时,相应的事件计数器溢出发生中断,在中断处理函数中记录事件信息,包括当前的pc、当前运 行的任务ID以及调用栈等信息。 L1: 新增perf字符设备,位于“dev/perf”,通过对设备节点的read\ioctl,实现用户态perf BREAKING CHANGE: 1.新增一系列perf的对外API,位于los_perf.h中. LOS_PerfInit配置采样数据缓冲区 LOS_PerfStart开启Perf采样 LOS_PerfStop停止Perf采样 LOS_PerfConfig配置Perf采样事件 LOS_PerfDataRead读取采样数据 LOS_PerfNotifyHookReg 注册采样数据缓冲区的钩子函数 LOS_PerfFlushHookReg 注册缓冲区刷cache的钩子 2. 用户态新增perf命令 【Usage】: ./perf [start] /[start id] Start perf. ./perf [stop] Stop perf. ./perf [read nBytes] Read nBytes raw data from perf buffer and print out. ./perf [list] List events to be used in -e. ./perf [stat] or [record] <option> <command> -e, event selector. use './perf list' to list available events. -p, event period. -o, perf data output filename. -t, taskId filter(whiltelist), if not set perf will sample all tasks. -s, type of data to sample defined in PerfSampleType los_perf.h. -P, processId filter(whiltelist), if not set perf will sample all processes. -d, whether to prescaler (once every 64 counts), which only take effect on cpu cycle hardware event. Close #I47I9A Signed-off-by: LiteOS2021 <dinglu@huawei.com> Change-Id: Ieb9b7483c85d1495df7c55bc0027f4309dff9814
This commit is contained in:
parent
92f33ab9c4
commit
6e0a3f10bb
|
@ -34,8 +34,8 @@ group("apps") {
|
|||
|
||||
if (defined(LOSCFG_SHELL)) {
|
||||
deps += [
|
||||
"shell",
|
||||
"mksh",
|
||||
"shell",
|
||||
"toybox",
|
||||
]
|
||||
}
|
||||
|
@ -51,4 +51,8 @@ group("apps") {
|
|||
if (defined(LOSCFG_DRIVERS_TRACE)) {
|
||||
deps += [ "trace" ]
|
||||
}
|
||||
|
||||
if (defined(LOSCFG_DRIVERS_PERF)) {
|
||||
deps += [ "perf" ]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,3 +69,7 @@ endif
|
|||
ifeq ($(LOSCFG_DRIVERS_TRACE), y)
|
||||
APP_SUBDIRS += trace
|
||||
endif
|
||||
|
||||
ifeq ($(LOSCFG_DRIVERS_PERF), y)
|
||||
APP_SUBDIRS += perf
|
||||
endif
|
||||
|
|
|
@ -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.
|
||||
|
||||
import("//kernel/liteos_a/liteos.gni")
|
||||
|
||||
executable("perf") {
|
||||
sources = [
|
||||
"src/main.c",
|
||||
"src/option.c",
|
||||
"src/perf.c",
|
||||
"src/perf_list.c",
|
||||
"src/perf_record.c",
|
||||
"src/perf_stat.c",
|
||||
]
|
||||
include_dirs = [ "include" ]
|
||||
defines = []
|
||||
|
||||
if (defined(LOSCFG_PERF_HW_PMU)) {
|
||||
defines += [ "LOSCFG_PERF_HW_PMU" ]
|
||||
}
|
||||
|
||||
if (defined(LOSCFG_PERF_TIMED_PMU)) {
|
||||
defines += [ "LOSCFG_PERF_TIMED_PMU" ]
|
||||
}
|
||||
|
||||
if (defined(LOSCFG_PERF_SW_PMU)) {
|
||||
defines += [ "LOSCFG_PERF_SW_PMU" ]
|
||||
}
|
||||
|
||||
if (defined(LOSCFG_FS_VFS)) {
|
||||
defines += [ "LOSCFG_FS_VFS" ]
|
||||
}
|
||||
|
||||
defines += [ "LOSCFG_PERF_BUFFER_SIZE=$LOSCFG_PERF_BUFFER_SIZE" ]
|
||||
|
||||
deps = [ "$LITEOSTHIRDPARTY/bounds_checking_function:libsec_static" ]
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
# 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 $(APPSTOPDIR)/config.mk
|
||||
|
||||
APP_NAME := $(notdir $(shell pwd))
|
||||
|
||||
SECUREC_DIR := $(LITEOSTHIRDPARTY)/bounds_checking_function
|
||||
|
||||
LOCAL_SRCS = $(wildcard src/*.c)
|
||||
LOCAL_SRCS += $(wildcard $(SECUREC_DIR)/src/*.c)
|
||||
|
||||
LOCAL_INCLUDE := \
|
||||
-I include \
|
||||
-I $(SECUREC_DIR)/include
|
||||
|
||||
LOCAL_FLAGS += $(LOCAL_INCLUDE)
|
||||
|
||||
ifeq ($(LOSCFG_PERF_HW_PMU), y)
|
||||
CFLAGS += -DLOSCFG_PERF_HW_PMU
|
||||
endif
|
||||
|
||||
ifeq ($(LOSCFG_PERF_TIMED_PMU), y)
|
||||
CFLAGS += -DLOSCFG_PERF_TIMED_PMU
|
||||
endif
|
||||
|
||||
ifeq ($(LOSCFG_PERF_SW_PMU), y)
|
||||
CFLAGS += -DLOSCFG_PERF_SW_PMU
|
||||
endif
|
||||
|
||||
ifeq ($(LOSCFG_FS_VFS), y)
|
||||
CFLAGS += -DLOSCFG_FS_VFS
|
||||
endif
|
||||
|
||||
CFLAGS += -DLOSCFG_PERF_BUFFER_SIZE=$(LOSCFG_PERF_BUFFER_SIZE)
|
||||
include $(APP)
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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 _OPTION_H
|
||||
#define _OPTION_H
|
||||
|
||||
#include "perf.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define CMD_MAX_PARAMS 10
|
||||
typedef int (*CALL_BACK)(const char *argv);
|
||||
|
||||
enum OptionType {
|
||||
OPTION_TYPE_UINT,
|
||||
OPTION_TYPE_STRING,
|
||||
OPTION_TYPE_CALLBACK,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
const char *name;
|
||||
const char **str;
|
||||
unsigned int *value;
|
||||
CALL_BACK cb;
|
||||
} PerfOption;
|
||||
|
||||
typedef struct {
|
||||
const char *path;
|
||||
char *params[CMD_MAX_PARAMS];
|
||||
} SubCmd;
|
||||
|
||||
#define OPTION_END() {.name = ""}
|
||||
#define OPTION_UINT(n, v) {.type = OPTION_TYPE_UINT, .name = (n), .value = (v)}
|
||||
#define OPTION_STRING(n, s) {.type = OPTION_TYPE_STRING, .name = (n), .str = (s)}
|
||||
#define OPTION_CALLBACK(n, c) {.type = OPTION_TYPE_CALLBACK, .name = (n), .cb = (c)}
|
||||
|
||||
int ParseOptions(int argc, char **argv, PerfOption *opt, SubCmd *cmd);
|
||||
int ParseEvents(const char *argv, PerfEventConfig *eventsCfg, unsigned int *len);
|
||||
int ParseIds(const char *argv, int *arr, unsigned int *len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* _OPTION_H */
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* 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_H
|
||||
#define _PERF_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define PERF_MAX_EVENT 7
|
||||
#define PERF_MAX_FILTER_TSKS 32
|
||||
|
||||
#ifdef PERF_DEBUG
|
||||
#define printf_debug(fmt, ...) printf(fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define printf_debug(fmt, ...)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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
|
||||
};
|
||||
|
||||
/*
|
||||
* 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,
|
||||
};
|
||||
|
||||
/*
|
||||
* Common hrtimer timed events
|
||||
*/
|
||||
enum PmuTimedId {
|
||||
PERF_COUNT_CPU_CLOCK = 0, /* hrtimer timed event */
|
||||
};
|
||||
|
||||
/*
|
||||
* 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,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
};
|
||||
|
||||
/*
|
||||
* perf configuration sub event information
|
||||
*
|
||||
* This structure is used to config specific events attributes.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int type; /* enum PerfEventType */
|
||||
struct {
|
||||
unsigned int eventId; /* the specific event corresponds to the PerfEventType */
|
||||
unsigned int period; /* event period, for every "period"th occurrence of the event a
|
||||
sample will be recorded */
|
||||
} events[PERF_MAX_EVENT]; /* perf event list */
|
||||
unsigned int eventsNr; /* total perf event number */
|
||||
size_t predivided; /* whether to prescaler (once every 64 counts),
|
||||
which only take effect on cpu cycle hardware event */
|
||||
} PerfEventConfig;
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
unsigned int taskIds[PERF_MAX_FILTER_TSKS]; /* perf task filter list (allowlist) */
|
||||
unsigned int taskIdsNr; /* task numbers of task filter allowlist,
|
||||
if set 0 perf will sample all tasks */
|
||||
unsigned int processIds[PERF_MAX_FILTER_TSKS]; /* perf process filter list (allowlist) */
|
||||
unsigned int processIdsNr; /* process numbers of process filter allowlist,
|
||||
if set 0 perf will sample all processes */
|
||||
unsigned int sampleType; /* type of data to sample defined in PerfSampleType */
|
||||
size_t needSample; /* whether to sample data */
|
||||
} PerfConfigAttr;
|
||||
|
||||
void PerfUsage(void);
|
||||
void PerfDumpAttr(PerfConfigAttr *attr);
|
||||
int PerfConfig(int fd, PerfConfigAttr *attr);
|
||||
void PerfStart(int fd, size_t sectionId);
|
||||
void PerfStop(int fd);
|
||||
ssize_t PerfRead(int fd, char *buf, size_t size);
|
||||
void PerfPrintBuffer(const char *buf, ssize_t num);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* _PERF_H */
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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_LIST_H
|
||||
#define _PERF_LIST_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
int event;
|
||||
int type;
|
||||
} PerfEvent;
|
||||
|
||||
extern const PerfEvent g_events[];
|
||||
void PerfList(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* _PERF_LIST_H */
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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_RECORD_H
|
||||
#define _PERF_RECORD_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void PerfRecord(int fd, int argc, char **argv);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* _PERF_RECORD_H */
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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_STAT_H
|
||||
#define _PERF_STAT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void PerfStat(int fd, int argc, char **argv);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* _PERF_STAT_H */
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include "perf.h"
|
||||
#include "perf_list.h"
|
||||
#include "perf_stat.h"
|
||||
#include "perf_record.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#define TWO_ARGS 2
|
||||
#define THREE_ARGS 3
|
||||
int fd = open("/dev/perf", O_RDWR);
|
||||
if (fd == -1) {
|
||||
printf("Perf open failed.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (argc == 1) {
|
||||
PerfUsage();
|
||||
} else if ((argc == TWO_ARGS) && strcmp(argv[1], "start") == 0) {
|
||||
PerfStart(fd, 0);
|
||||
} else if ((argc == THREE_ARGS) && strcmp(argv[1], "start") == 0) {
|
||||
size_t id = strtoul(argv[THREE_ARGS - 1], NULL, 0);
|
||||
PerfStart(fd, id);
|
||||
} else if ((argc == TWO_ARGS) && strcmp(argv[1], "stop") == 0) {
|
||||
PerfStop(fd);
|
||||
} else if ((argc == THREE_ARGS) && strcmp(argv[1], "read") == 0) {
|
||||
size_t size = strtoul(argv[THREE_ARGS - 1], NULL, 0);
|
||||
char *buf = (char *)malloc(size);
|
||||
int len = PerfRead(fd, buf, size);
|
||||
PerfPrintBuffer(buf, len);
|
||||
free(buf);
|
||||
} else if ((argc == TWO_ARGS) && strcmp(argv[1], "list") == 0) {
|
||||
PerfList();
|
||||
} else if ((argc >= THREE_ARGS) && strcmp(argv[1], "stat") == 0) {
|
||||
PerfStat(fd, argc, argv);
|
||||
} else if ((argc >= THREE_ARGS) && strcmp(argv[1], "record") == 0) {
|
||||
PerfRecord(fd, argc, argv);
|
||||
} else {
|
||||
printf("Unsupported perf command.\n");
|
||||
PerfUsage();
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include "option.h"
|
||||
#include "perf_list.h"
|
||||
|
||||
static int ParseOption(char **argv, int *index, PerfOption *opts)
|
||||
{
|
||||
int ret = 0;
|
||||
const char *str = NULL;
|
||||
|
||||
while ((opts->name != NULL) && (*opts->name != 0)) {
|
||||
if (strcmp(argv[*index], opts->name) == 0) {
|
||||
switch (opts->type) {
|
||||
case OPTION_TYPE_UINT:
|
||||
*opts->value = strtoul(argv[++(*index)], NULL, 0);
|
||||
break;
|
||||
case OPTION_TYPE_STRING:
|
||||
*opts->str = argv[++(*index)];
|
||||
break;
|
||||
case OPTION_TYPE_CALLBACK:
|
||||
str = argv[++(*index)];
|
||||
if ((*opts->cb)(str) != 0) {
|
||||
printf("parse error\n");
|
||||
ret = -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("invalid option\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
opts++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ParseOptions(int argc, char **argv, PerfOption *opts, SubCmd *cmd)
|
||||
{
|
||||
int i;
|
||||
int index = 0;
|
||||
|
||||
while ((index < argc) && (argv[index] != NULL) && (*argv[index] == '-')) {
|
||||
if (ParseOption(argv, &index, opts) != 0) {
|
||||
return -1;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
if ((index < argc) && (argv[index] != NULL)) {
|
||||
cmd->path = argv[index];
|
||||
cmd->params[0] = argv[index];
|
||||
index++;
|
||||
} else {
|
||||
printf("no subcmd to execute\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 1; (index < argc) && (i < CMD_MAX_PARAMS); index++, i++) {
|
||||
cmd->params[i] = argv[index];
|
||||
}
|
||||
printf_debug("subcmd = %s\n", cmd->path);
|
||||
for (int j = 0; j < i; j++) {
|
||||
printf_debug("paras[%d]:%s\n", j, cmd->params[j]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ParseIds(const char *argv, int *arr, unsigned int *len)
|
||||
{
|
||||
int res, ret;
|
||||
unsigned int index = 0;
|
||||
char *sp = NULL;
|
||||
char *this = NULL;
|
||||
char *list = strdup(argv);
|
||||
|
||||
if (list == NULL) {
|
||||
printf("no memory for ParseIds\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sp = strtok_r(list, ",", &this);
|
||||
while (sp) {
|
||||
res = strtoul(sp, NULL, 0);
|
||||
if (res < 0) {
|
||||
ret = -1;
|
||||
goto EXIT;
|
||||
}
|
||||
arr[index++] = res;
|
||||
sp = strtok_r(NULL, ",", &this);
|
||||
}
|
||||
*len = index;
|
||||
ret = 0;
|
||||
EXIT:
|
||||
free(list);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline const PerfEvent *StrToEvent(const char *str)
|
||||
{
|
||||
const PerfEvent *evt = &g_events[0];
|
||||
|
||||
for (; evt->event != -1; evt++) {
|
||||
if (strcmp(str, evt->name) == 0) {
|
||||
return evt;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ParseEvents(const char *argv, PerfEventConfig *eventsCfg, unsigned int *len)
|
||||
{
|
||||
int ret;
|
||||
unsigned int index = 0;
|
||||
const PerfEvent *event = NULL;
|
||||
char *sp = NULL;
|
||||
char *this = NULL;
|
||||
char *list = strdup(argv);
|
||||
|
||||
if (list == NULL) {
|
||||
printf("no memory for ParseEvents\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sp = strtok_r(list, ",", &this);
|
||||
while (sp) {
|
||||
event = StrToEvent(sp);
|
||||
if (event == NULL) {
|
||||
ret = -1;
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
if (index == 0) {
|
||||
eventsCfg->type = event->type;
|
||||
} else if (eventsCfg->type != event->type) {
|
||||
printf("events type must be same\n");
|
||||
ret = -1;
|
||||
goto EXIT;
|
||||
}
|
||||
eventsCfg->events[index].eventId = event->event;
|
||||
sp = strtok_r(NULL, ",", &this);
|
||||
index++;
|
||||
}
|
||||
*len = index;
|
||||
ret = 0;
|
||||
EXIT:
|
||||
free(list);
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include "perf.h"
|
||||
|
||||
#define PERF_IOC_MAGIC 'T'
|
||||
#define PERF_START _IO(PERF_IOC_MAGIC, 1)
|
||||
#define PERF_STOP _IO(PERF_IOC_MAGIC, 2)
|
||||
|
||||
void PerfUsage(void)
|
||||
{
|
||||
printf("\nUsage: ./perf start [id]. Start perf.\n");
|
||||
printf("\nUsage: ./perf stop. Stop perf.\n");
|
||||
printf("\nUsage: ./perf read <nBytes>. Read nBytes raw data from perf buffer and print out.\n");
|
||||
printf("\nUsage: ./perf list. List events to be used in -e.\n");
|
||||
printf("\nUsage: ./perf stat/record [option] <command>. \n"
|
||||
"-e, event selector. use './perf list' to list available events.\n"
|
||||
"-p, event period.\n"
|
||||
"-o, perf data output filename.\n"
|
||||
"-t, taskId filter(allowlist), if not set perf will sample all tasks.\n"
|
||||
"-s, type of data to sample defined in PerfSampleType los_perf.h.\n"
|
||||
"-P, processId filter(allowlist), if not set perf will sample all processes.\n"
|
||||
"-d, whether to prescaler (once every 64 counts),"
|
||||
"which only take effect on cpu cycle hardware event.\n"
|
||||
);
|
||||
}
|
||||
|
||||
static void PerfSetPeriod(PerfConfigAttr *attr)
|
||||
{
|
||||
int i;
|
||||
for (i = 1; i < attr->eventsCfg.eventsNr; i++) {
|
||||
attr->eventsCfg.events[i].period = attr->eventsCfg.events[0].period;
|
||||
}
|
||||
}
|
||||
|
||||
void PerfPrintBuffer(const char *buf, ssize_t num)
|
||||
{
|
||||
#define BYTES_PER_LINE 4
|
||||
ssize_t i = 0;
|
||||
for (i = 0; i < num; i++) {
|
||||
printf(" %02x", (unsigned char)buf[i]);
|
||||
if (((i + 1) % BYTES_PER_LINE) == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void PerfDumpAttr(PerfConfigAttr *attr)
|
||||
{
|
||||
int i;
|
||||
printf_debug("attr->type: %d\n", attr->eventsCfg.type);
|
||||
for (i = 0; i < attr->eventsCfg.eventsNr; i++) {
|
||||
printf_debug("attr->events[%d]: %d, 0x%x\n", i, attr->eventsCfg.events[i].eventId,
|
||||
attr->eventsCfg.events[i].period);
|
||||
}
|
||||
printf_debug("attr->predivided: %d\n", attr->eventsCfg.predivided);
|
||||
printf_debug("attr->sampleType: 0x%x\n", attr->sampleType);
|
||||
|
||||
for (i = 0; i < attr->taskIdsNr; i++) {
|
||||
printf_debug("attr->taskIds[%d]: %d\n", i, attr->taskIds[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < attr->processIdsNr; i++) {
|
||||
printf_debug("attr->processIds[%d]: %d\n", i, attr->processIds[i]);
|
||||
}
|
||||
|
||||
printf_debug("attr->needSample: %d\n", attr->needSample);
|
||||
}
|
||||
|
||||
|
||||
void PerfStart(int fd, size_t sectionId)
|
||||
{
|
||||
(void)ioctl(fd, PERF_START, sectionId);
|
||||
}
|
||||
|
||||
void PerfStop(int fd)
|
||||
{
|
||||
(void)ioctl(fd, PERF_STOP, NULL);
|
||||
}
|
||||
|
||||
int PerfConfig(int fd, PerfConfigAttr *attr)
|
||||
{
|
||||
if (attr == NULL) {
|
||||
return -1;
|
||||
}
|
||||
PerfSetPeriod(attr);
|
||||
PerfDumpAttr(attr);
|
||||
return write(fd, attr, sizeof(PerfConfigAttr));
|
||||
}
|
||||
|
||||
ssize_t PerfRead(int fd, char *buf, size_t size)
|
||||
{
|
||||
ssize_t len;
|
||||
if (buf == NULL) {
|
||||
printf("Read buffer is null.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = read(fd, buf, size);
|
||||
return len;
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* 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 <stdio.h>
|
||||
#include "perf.h"
|
||||
#include "perf_list.h"
|
||||
|
||||
static const char *g_eventTypeStr[] = {
|
||||
"[Hardware event]",
|
||||
"[Timed event]",
|
||||
"[Software event]",
|
||||
};
|
||||
|
||||
const PerfEvent g_events[] = {
|
||||
#ifdef LOSCFG_PERF_HW_PMU
|
||||
{
|
||||
.name = "cycles",
|
||||
.event = PERF_COUNT_HW_CPU_CYCLES,
|
||||
.type = PERF_EVENT_TYPE_HW,
|
||||
},
|
||||
{
|
||||
.name = "instruction",
|
||||
.event = PERF_COUNT_HW_INSTRUCTIONS,
|
||||
.type = PERF_EVENT_TYPE_HW,
|
||||
},
|
||||
{
|
||||
.name = "dcache",
|
||||
.event = PERF_COUNT_HW_DCACHE_REFERENCES,
|
||||
.type = PERF_EVENT_TYPE_HW,
|
||||
},
|
||||
{
|
||||
.name = "dcache-miss",
|
||||
.event = PERF_COUNT_HW_DCACHE_MISSES,
|
||||
.type = PERF_EVENT_TYPE_HW,
|
||||
},
|
||||
{
|
||||
.name = "icache",
|
||||
.event = PERF_COUNT_HW_ICACHE_REFERENCES,
|
||||
.type = PERF_EVENT_TYPE_HW,
|
||||
},
|
||||
{
|
||||
.name = "icache-miss",
|
||||
.event = PERF_COUNT_HW_ICACHE_MISSES,
|
||||
.type = PERF_EVENT_TYPE_HW,
|
||||
},
|
||||
{
|
||||
.name = "branch",
|
||||
.event = PERF_COUNT_HW_BRANCH_INSTRUCTIONS,
|
||||
.type = PERF_EVENT_TYPE_HW,
|
||||
},
|
||||
{
|
||||
.name = "branch-miss",
|
||||
.event = PERF_COUNT_HW_BRANCH_MISSES,
|
||||
.type = PERF_EVENT_TYPE_HW,
|
||||
},
|
||||
#endif
|
||||
#ifdef LOSCFG_PERF_TIMED_PMU
|
||||
{
|
||||
.name = "clock",
|
||||
.event = PERF_COUNT_CPU_CLOCK,
|
||||
.type = PERF_EVENT_TYPE_TIMED,
|
||||
},
|
||||
#endif
|
||||
#ifdef LOSCFG_PERF_SW_PMU
|
||||
{
|
||||
.name = "task-switch",
|
||||
.event = PERF_COUNT_SW_TASK_SWITCH,
|
||||
.type = PERF_EVENT_TYPE_SW,
|
||||
},
|
||||
{
|
||||
.name = "irq-in",
|
||||
.event = PERF_COUNT_SW_IRQ_RESPONSE,
|
||||
.type = PERF_EVENT_TYPE_SW,
|
||||
},
|
||||
{
|
||||
.name = "mem-alloc",
|
||||
.event = PERF_COUNT_SW_MEM_ALLOC,
|
||||
.type = PERF_EVENT_TYPE_SW,
|
||||
},
|
||||
{
|
||||
.name = "mux-pend",
|
||||
.event = PERF_COUNT_SW_MUX_PEND,
|
||||
.type = PERF_EVENT_TYPE_SW,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.name = "",
|
||||
.event = -1,
|
||||
.type = PERF_EVENT_TYPE_MAX,
|
||||
}
|
||||
};
|
||||
|
||||
void PerfList(void)
|
||||
{
|
||||
const PerfEvent *evt = &g_events[0];
|
||||
printf("\n");
|
||||
for (; evt->event != -1; evt++) {
|
||||
printf("\t %-25s%30s\n", evt->name, g_eventTypeStr[evt->type]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* 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 <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <securec.h>
|
||||
|
||||
#ifdef LOSCFG_FS_VFS
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "perf.h"
|
||||
#include "option.h"
|
||||
#include "perf_record.h"
|
||||
|
||||
#define PERF_FILE_MODE 0644
|
||||
static PerfConfigAttr g_recordAttr;
|
||||
static const char *g_savePath = "/storage/data/perf.data";
|
||||
|
||||
static inline int GetEvents(const char *argv)
|
||||
{
|
||||
return ParseEvents(argv, &g_recordAttr.eventsCfg, &g_recordAttr.eventsCfg.eventsNr);
|
||||
}
|
||||
|
||||
static inline int GetTids(const char *argv)
|
||||
{
|
||||
return ParseIds(argv, (int *)g_recordAttr.taskIds, &g_recordAttr.taskIdsNr);
|
||||
}
|
||||
|
||||
static inline int GetPids(const char *argv)
|
||||
{
|
||||
return ParseIds(argv, (int *)g_recordAttr.processIds, &g_recordAttr.processIdsNr);
|
||||
}
|
||||
|
||||
static PerfOption g_recordOpts[] = {
|
||||
OPTION_CALLBACK("-e", GetEvents),
|
||||
OPTION_CALLBACK("-t", GetTids),
|
||||
OPTION_CALLBACK("-P", GetPids),
|
||||
OPTION_STRING("-o", &g_savePath),
|
||||
OPTION_UINT("-p", &g_recordAttr.eventsCfg.events[0].period),
|
||||
OPTION_UINT("-s", &g_recordAttr.sampleType),
|
||||
OPTION_UINT("-d", &g_recordAttr.eventsCfg.predivided),
|
||||
};
|
||||
|
||||
static int PerfRecordAttrInit(void)
|
||||
{
|
||||
PerfConfigAttr attr = {
|
||||
.eventsCfg = {
|
||||
#ifdef LOSCFG_PERF_HW_PMU
|
||||
.type = PERF_EVENT_TYPE_HW,
|
||||
.events = {
|
||||
[0] = {PERF_COUNT_HW_CPU_CYCLES, 0xFFFF},
|
||||
},
|
||||
#elif defined LOSCFG_PERF_TIMED_PMU
|
||||
.type = PERF_EVENT_TYPE_TIMED,
|
||||
.events = {
|
||||
[0] = {PERF_COUNT_CPU_CLOCK, 100},
|
||||
},
|
||||
#elif defined LOSCFG_PERF_SW_PMU
|
||||
.type = PERF_EVENT_TYPE_SW,
|
||||
.events = {
|
||||
[0] = {PERF_COUNT_SW_TASK_SWITCH, 1},
|
||||
},
|
||||
#endif
|
||||
.eventsNr = 1, /* 1 event */
|
||||
.predivided = 0,
|
||||
},
|
||||
.taskIds = {0},
|
||||
.taskIdsNr = 0,
|
||||
.processIds = {0},
|
||||
.processIdsNr = 0,
|
||||
.needSample = 1,
|
||||
.sampleType = PERF_RECORD_IP | PERF_RECORD_CALLCHAIN,
|
||||
};
|
||||
|
||||
return memcpy_s(&g_recordAttr, sizeof(PerfConfigAttr), &attr, sizeof(PerfConfigAttr)) != EOK ? -1 : 0;
|
||||
}
|
||||
|
||||
ssize_t PerfWriteFile(const char *filePath, const char *buf, ssize_t bufSize)
|
||||
{
|
||||
#ifdef LOSCFG_FS_VFS
|
||||
int fd = -1;
|
||||
ssize_t totalToWrite = bufSize;
|
||||
ssize_t totalWrite = 0;
|
||||
|
||||
if (filePath == NULL || buf == NULL || bufSize == 0) {
|
||||
printf("filePath: %p, buf: %p, bufSize: %u!\n", filePath, buf, bufSize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = open(filePath, O_CREAT | O_RDWR | O_TRUNC, PERF_FILE_MODE);
|
||||
if (fd < 0) {
|
||||
printf("create file [%s] failed, fd: %d, %s!\n", filePath, fd, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
while (totalToWrite > 0) {
|
||||
ssize_t writeThisTime = write(fd, buf, totalToWrite);
|
||||
if (writeThisTime < 0) {
|
||||
printf("failed to write file [%s], %s!\n", filePath, strerror(errno));
|
||||
(void)close(fd);
|
||||
return -1;
|
||||
}
|
||||
buf += writeThisTime;
|
||||
totalToWrite -= writeThisTime;
|
||||
totalWrite += writeThisTime;
|
||||
}
|
||||
(void)fsync(fd);
|
||||
(void)close(fd);
|
||||
|
||||
return (totalWrite == bufSize) ? 0 : -1;
|
||||
#else
|
||||
(void)filePath;
|
||||
PerfPrintBuffer(buf, bufSize);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PerfRecord(int fd, int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
int child;
|
||||
char *buf;
|
||||
ssize_t len;
|
||||
SubCmd cmd = {0};
|
||||
|
||||
if (argc < 3) { /* perf record argc is at least 3 */
|
||||
return;
|
||||
}
|
||||
|
||||
ret = PerfRecordAttrInit();
|
||||
if (ret != 0) {
|
||||
printf("perf record attr init failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = ParseOptions(argc - 2, &argv[2], g_recordOpts, &cmd); /* parse option and cmd begin at index 2 */
|
||||
if (ret != 0) {
|
||||
printf("parse error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = PerfConfig(fd, &g_recordAttr);
|
||||
if (ret != 0) {
|
||||
printf("perf config failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
PerfStart(fd, 0);
|
||||
child = fork();
|
||||
if (child < 0) {
|
||||
printf("fork error\n");
|
||||
PerfStop(fd);
|
||||
return;
|
||||
} else if (child == 0) {
|
||||
(void)execve(cmd.path, cmd.params, NULL);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
waitpid(child, 0, 0);
|
||||
PerfStop(fd);
|
||||
|
||||
buf = (char *)malloc(LOSCFG_PERF_BUFFER_SIZE);
|
||||
if (buf == NULL) {
|
||||
printf("no memory for read perf 0x%x\n", LOSCFG_PERF_BUFFER_SIZE);
|
||||
return;
|
||||
}
|
||||
len = PerfRead(fd, buf, LOSCFG_PERF_BUFFER_SIZE);
|
||||
ret = PerfWriteFile(g_savePath, buf, len);
|
||||
if (ret == 0) {
|
||||
printf("save perf data success at %s\n", g_savePath);
|
||||
} else {
|
||||
printf("save perf data failed at %s\n", g_savePath);
|
||||
}
|
||||
free(buf);
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* 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 <unistd.h>
|
||||
#include <securec.h>
|
||||
#include <sys/wait.h>
|
||||
#include "perf.h"
|
||||
#include "option.h"
|
||||
#include "perf_stat.h"
|
||||
|
||||
static PerfConfigAttr g_statAttr;
|
||||
|
||||
static inline int GetEvents(const char *argv)
|
||||
{
|
||||
return ParseEvents(argv, &g_statAttr.eventsCfg, &g_statAttr.eventsCfg.eventsNr);
|
||||
}
|
||||
|
||||
static inline int GetTids(const char *argv)
|
||||
{
|
||||
return ParseIds(argv, (int *)g_statAttr.taskIds, &g_statAttr.taskIdsNr);
|
||||
}
|
||||
|
||||
static inline int GetPids(const char *argv)
|
||||
{
|
||||
return ParseIds(argv, (int *)g_statAttr.processIds, &g_statAttr.processIdsNr);
|
||||
}
|
||||
|
||||
static PerfOption g_statOpts[] = {
|
||||
OPTION_CALLBACK("-e", GetEvents),
|
||||
OPTION_CALLBACK("-t", GetTids),
|
||||
OPTION_CALLBACK("-P", GetPids),
|
||||
OPTION_UINT("-p", &g_statAttr.eventsCfg.events[0].period),
|
||||
OPTION_UINT("-s", &g_statAttr.sampleType),
|
||||
OPTION_UINT("-d", &g_statAttr.eventsCfg.predivided),
|
||||
};
|
||||
|
||||
static int PerfStatAttrInit(void)
|
||||
{
|
||||
PerfConfigAttr attr = {
|
||||
.eventsCfg = {
|
||||
#ifdef LOSCFG_PERF_HW_PMU
|
||||
.type = PERF_EVENT_TYPE_HW,
|
||||
.events = {
|
||||
[0] = {PERF_COUNT_HW_CPU_CYCLES, 0xFFFF},
|
||||
[1] = {PERF_COUNT_HW_INSTRUCTIONS, 0xFFFFFF00},
|
||||
[2] = {PERF_COUNT_HW_ICACHE_REFERENCES, 0xFFFF},
|
||||
[3] = {PERF_COUNT_HW_DCACHE_REFERENCES, 0xFFFF},
|
||||
},
|
||||
.eventsNr = 4, /* 4 events */
|
||||
#elif defined LOSCFG_PERF_TIMED_PMU
|
||||
.type = PERF_EVENT_TYPE_TIMED,
|
||||
.events = {
|
||||
[0] = {PERF_COUNT_CPU_CLOCK, 100},
|
||||
},
|
||||
.eventsNr = 1, /* 1 event */
|
||||
#elif defined LOSCFG_PERF_SW_PMU
|
||||
.type = PERF_EVENT_TYPE_SW,
|
||||
.events = {
|
||||
[0] = {PERF_COUNT_SW_TASK_SWITCH, 1},
|
||||
[1] = {PERF_COUNT_SW_IRQ_RESPONSE, 1},
|
||||
[2] = {PERF_COUNT_SW_MEM_ALLOC, 1},
|
||||
[3] = {PERF_COUNT_SW_MUX_PEND, 1},
|
||||
},
|
||||
.eventsNr = 4, /* 4 events */
|
||||
#endif
|
||||
.predivided = 0,
|
||||
},
|
||||
.taskIds = {0},
|
||||
.taskIdsNr = 0,
|
||||
.processIds = {0},
|
||||
.processIdsNr = 0,
|
||||
.needSample = 0,
|
||||
.sampleType = 0,
|
||||
};
|
||||
|
||||
return memcpy_s(&g_statAttr, sizeof(PerfConfigAttr), &attr, sizeof(PerfConfigAttr)) != EOK ? -1 : 0;
|
||||
}
|
||||
|
||||
void PerfStat(int fd, int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
int child;
|
||||
SubCmd cmd = {0};
|
||||
|
||||
if (argc < 3) { /* perf stat argc is at least 3 */
|
||||
return;
|
||||
}
|
||||
|
||||
ret = PerfStatAttrInit();
|
||||
if (ret != 0) {
|
||||
printf("perf stat attr init failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = ParseOptions(argc - 2, &argv[2], g_statOpts, &cmd); /* parse option and cmd begin at index 2 */
|
||||
if (ret != 0) {
|
||||
printf("parse error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = PerfConfig(fd, &g_statAttr);
|
||||
if (ret != 0) {
|
||||
printf("perf config failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
PerfStart(fd, 0);
|
||||
child = fork();
|
||||
if (child < 0) {
|
||||
printf("fork error\n");
|
||||
goto EXIT;
|
||||
} else if (child == 0) {
|
||||
(void)execve(cmd.path, cmd.params, NULL);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
(void)waitpid(child, 0, 0);
|
||||
EXIT:
|
||||
PerfStop(fd);
|
||||
}
|
||||
|
|
@ -46,10 +46,10 @@ kernel_module(module_name) {
|
|||
"src/los_hw_runstop.S",
|
||||
"src/los_hw_tick.c",
|
||||
"src/los_hwi.c",
|
||||
"src/smp.c",
|
||||
"src/strncpy_from_user.c",
|
||||
"src/strnlen_user.c",
|
||||
"src/user_copy.c",
|
||||
"src/smp.c",
|
||||
]
|
||||
|
||||
if (LOSCFG_ARCH_ARM_VER == "armv7-a") {
|
||||
|
@ -64,6 +64,10 @@ kernel_module(module_name) {
|
|||
|
||||
include_dirs = [ "src/include" ]
|
||||
|
||||
if (defined(LOSCFG_PERF_HW_PMU)) {
|
||||
sources += [ "src/pmu/armv7_pmu.c" ]
|
||||
}
|
||||
|
||||
if (defined(LOSCFG_GDB)) {
|
||||
configs += [ ":as_objs_libc_flags" ]
|
||||
}
|
||||
|
@ -82,9 +86,11 @@ config("as_objs_libc_flags") {
|
|||
defines = [ "__ASSEMBLY__" ]
|
||||
|
||||
# linux style macros
|
||||
if (defined(LOSCFG_ARCH_ARM_V7A) || defined(LOSCFG_ARCH_ARM_V7R) || defined(LOSCFG_ARCH_ARM_V7M)) {
|
||||
if (defined(LOSCFG_ARCH_ARM_V7A) || defined(LOSCFG_ARCH_ARM_V7R) ||
|
||||
defined(LOSCFG_ARCH_ARM_V7M)) {
|
||||
defines += [ "__LINUX_ARM_ARCH__=7" ]
|
||||
} else if (defined(LOSCFG_ARCH_ARM_V8A) || defined(LOSCFG_ARCH_ARM_V8R) || defined(LOSCFG_ARCH_ARM_V8M)) {
|
||||
} else if (defined(LOSCFG_ARCH_ARM_V8A) || defined(LOSCFG_ARCH_ARM_V8R) ||
|
||||
defined(LOSCFG_ARCH_ARM_V8M)) {
|
||||
defines += [ "__LINUX_ARM_ARCH__=8" ]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,12 @@ else
|
|||
LOCAL_SRCS += src/startup/reset_vector_up.S
|
||||
endif
|
||||
|
||||
ifeq ($(LOSCFG_PERF_HW_PMU), y)
|
||||
LOCAL_SRCS += src/pmu/armv7_pmu.c
|
||||
endif
|
||||
|
||||
LOCAL_FLAGS := $(LOCAL_INCLUDE)
|
||||
|
||||
AS_OBJS_LIBC_FLAGS = -D__ASSEMBLY__
|
||||
# linux style macros
|
||||
LINUX_ARCH_$(LOSCFG_ARCH_ARM_V7A) = -D__LINUX_ARM_ARCH__=7
|
||||
|
@ -54,6 +60,6 @@ LINUX_ARCH_$(LOSCFG_ARCH_ARM_V8M) = -D__LINUX_ARM_ARCH__=8
|
|||
AS_OBJS_LIBC_FLAGS += $(LINUX_ARCH_y)
|
||||
|
||||
ifeq ($(LOSCFG_GDB), y)
|
||||
LOCAL_FLAGS := $(AS_OBJS_LIBC_FLAGS)
|
||||
LOCAL_FLAGS += $(AS_OBJS_LIBC_FLAGS)
|
||||
endif
|
||||
include $(MODULE)
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* 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 _ARMV7_PMU_PRI_H
|
||||
#define _ARMV7_PMU_PRI_H
|
||||
|
||||
#include "los_typedef.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* counters overflow flag status reg */
|
||||
#define ARMV7_FLAG_MASK 0xffffffff /* Mask for writable bits */
|
||||
#define ARMV7_OVERFLOWED_MASK ARMV7_FLAG_MASK /* Mask for pmu overflowed */
|
||||
|
||||
/* pmnc config reg */
|
||||
#define ARMV7_PMNC_E (1U << 0) /* Enable all counters */
|
||||
#define ARMV7_PMNC_P (1U << 1) /* Reset all counters */
|
||||
#define ARMV7_PMNC_C (1U << 2) /* Cycle counter reset */
|
||||
#define ARMV7_PMNC_D (1U << 3) /* CCNT counts every 64th cpu cycle */
|
||||
#define ARMV7_PMNC_X (1U << 4) /* Export to ETM */
|
||||
#define ARMV7_PMNC_DP (1U << 5) /* Disable CCNT if non-invasive debug */
|
||||
#define ARMV7_PMNC_MASK 0x3f /* Mask for writable bits */
|
||||
|
||||
/* pmxevtyper event selection reg */
|
||||
#define ARMV7_EVTYPE_MASK 0xc80000ff /* Mask for writable bits */
|
||||
|
||||
/* armv7 counters index */
|
||||
#define ARMV7_IDX_COUNTER0 1
|
||||
#define ARMV7_IDX_CYCLE_COUNTER 0
|
||||
#define ARMV7_IDX_MAX_COUNTER 9
|
||||
|
||||
#define ARMV7_MAX_COUNTERS 32
|
||||
#define ARMV7_IDX_COUNTER_LAST (ARMV7_IDX_CYCLE_COUNTER + ARMV7_MAX_COUNTERS - 1)
|
||||
#define ARMV7_COUNTER_MASK (ARMV7_MAX_COUNTERS - 1)
|
||||
|
||||
/* armv7 event counter index mapping */
|
||||
#define ARMV7_CNT2BIT(x) (1UL << (x))
|
||||
#define ARMV7_IDX2CNT(x) (((x) - ARMV7_IDX_COUNTER0) & ARMV7_COUNTER_MASK)
|
||||
|
||||
enum PmuEventType {
|
||||
ARMV7_PERF_HW_CYCLES = 0xFF, /* cycles */
|
||||
ARMV7_PERF_HW_INSTRUCTIONS = 0x08, /* instructions */
|
||||
ARMV7_PERF_HW_DCACHES = 0x04, /* dcache */
|
||||
ARMV7_PERF_HW_DCACHE_MISSES = 0x03, /* dcache-misses */
|
||||
ARMV7_PERF_HW_ICACHES = 0x14, /* icache */
|
||||
ARMV7_PERF_HW_ICACHE_MISSES = 0x01, /* icache-misses */
|
||||
ARMV7_PERF_HW_BRANCHES = 0x0C, /* software change of pc */
|
||||
ARMV7_PERF_HW_BRANCE_MISSES = 0x10, /* branch-misses */
|
||||
ARMV7_PERF_HW_PRED_BRANCH = 0x12, /* predictable branches */
|
||||
ARMV7_PERF_HW_NUM_CYC_IRQ = 0x50, /* number of cycles Irqs are interrupted */
|
||||
ARMV7_PERF_HW_EXC_TAKEN = 0x09, /* exception_taken */
|
||||
ARMV7_PERF_HW_DATA_READ = 0x06, /* data read */
|
||||
ARMV7_PERF_HW_DATA_WRITE = 0x07, /* data write */
|
||||
ARMV7_PERF_HW_STREX_PASSED = 0x80, /* strex passed */
|
||||
ARMV7_PERF_HW_STREX_FAILED = 0x81, /* strex failed */
|
||||
ARMV7_PERF_HW_LP_IN_TCM = 0x82, /* literal pool in TCM region */
|
||||
ARMV7_PERF_HW_DMB_STALL = 0x90, /* DMB stall */
|
||||
ARMV7_PERF_HW_ITCM_ACCESS = 0x91, /* ITCM access */
|
||||
ARMV7_PERF_HW_DTCM_ACCESS = 0x92, /* DTCM access */
|
||||
ARMV7_PERF_HW_DATA_EVICTION = 0x93, /* data eviction */
|
||||
ARMV7_PERF_HW_SCU = 0x94, /* SCU coherency operation */
|
||||
ARMV7_PERF_HW_INSCACHE_DEP_DW = 0x95, /* instruction cache dependent stall */
|
||||
ARMV7_PERF_HW_DATA_CACHE_DEP_STALL = 0x96, /* data cache dependent stall */
|
||||
ARMV7_PERF_HW_NOCACHE_NO_PER_DEP_STALL = 0x97, /* non-cacheable no peripheral dependent stall */
|
||||
ARMV7_PERF_HW_NOCACHE_PER_DEP_STALL = 0x98, /* non-Cacheable peripheral dependent stall */
|
||||
ARMV7_PERF_HW_DATA_CACHE_HP_DEP_STALL = 0x99, /* data cache high priority dependent stall */
|
||||
ARMV7_PERF_HW_AXI_FAST_PERIPHERAL = 0x9A, /* Accesses_to_AXI_fast_peripheral_port(reads_and_writes) */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* _ARMV7_PMU_PRI_H */
|
|
@ -44,10 +44,24 @@ extern "C" {
|
|||
#define OS_SYSTEM_EXC_CURR_CPU 1
|
||||
#define OS_SYSTEM_EXC_OTHER_CPU 2
|
||||
|
||||
#define REGION_PATH_MAX 32
|
||||
|
||||
typedef struct {
|
||||
#ifdef LOSCFG_KERNEL_VM
|
||||
UINTPTR ip;
|
||||
UINT32 len; /* f_path length */
|
||||
CHAR f_path[REGION_PATH_MAX];
|
||||
#else
|
||||
UINTPTR ip;
|
||||
#endif
|
||||
} IpInfo;
|
||||
|
||||
extern UINT32 OsGetSystemStatus(VOID);
|
||||
extern VOID BackTraceSub(UINTPTR regFP);
|
||||
extern VOID OsExcInit(VOID);
|
||||
extern BOOL OsSystemExcIsReset(VOID);
|
||||
extern UINT32 BackTraceGet(UINTPTR regFP, IpInfo *callChain, UINT32 maxDepth);
|
||||
extern BOOL OsGetUsrIpInfo(UINTPTR ip, IpInfo *info);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
|
|
|
@ -147,6 +147,14 @@ OsIrqHandler:
|
|||
/* disable irq, switch to svc mode */
|
||||
CPSID i, #0x13
|
||||
|
||||
#ifdef LOSCFG_KERNEL_PERF
|
||||
PUSH {R0-R3, R12, LR}
|
||||
MOV R0, LR
|
||||
MOV R1, FP
|
||||
BL OsPerfSetIrqRegs
|
||||
POP {R0-R3, R12, LR}
|
||||
#endif
|
||||
|
||||
STMFD SP!, {R0-R3, R12, LR}
|
||||
STMFD SP, {R13, R14}^
|
||||
SUB SP, SP, #(4 * 4)
|
||||
|
|
|
@ -690,20 +690,66 @@ FOUND:
|
|||
return found;
|
||||
}
|
||||
|
||||
VOID BackTraceSub(UINTPTR regFP)
|
||||
BOOL OsGetUsrIpInfo(UINTPTR ip, IpInfo *info)
|
||||
{
|
||||
if (info == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
#ifdef LOSCFG_KERNEL_VM
|
||||
BOOL ret = FALSE;
|
||||
const CHAR *name = NULL;
|
||||
LosVmMapRegion *region = NULL;
|
||||
LosProcessCB *runProcess = OsCurrProcessGet();
|
||||
|
||||
if (LOS_IsUserAddress((VADDR_T)ip) == FALSE) {
|
||||
info->ip = ip;
|
||||
name = "kernel";
|
||||
ret = FALSE;
|
||||
goto END;
|
||||
}
|
||||
|
||||
region = LOS_RegionFind(runProcess->vmSpace, (VADDR_T)ip);
|
||||
if (region == NULL) {
|
||||
info->ip = ip;
|
||||
name = "invalid";
|
||||
ret = FALSE;
|
||||
goto END;
|
||||
}
|
||||
|
||||
info->ip = ip - OsGetTextRegionBase(region, runProcess);
|
||||
name = OsGetRegionNameOrFilePath(region);
|
||||
ret = TRUE;
|
||||
if (strcmp(name, "/lib/libc.so") != 0) {
|
||||
PRINT_ERR("ip = 0x%x, %s\n", info->ip, name);
|
||||
}
|
||||
END:
|
||||
info->len = strlen(name);
|
||||
if (strncpy_s(info->f_path, REGION_PATH_MAX, name, REGION_PATH_MAX - 1) != EOK) {
|
||||
info->f_path[0] = '\0';
|
||||
info->len = 0;
|
||||
PRINT_ERR("copy f_path failed, %s\n", name);
|
||||
}
|
||||
return ret;
|
||||
#else
|
||||
info->ip = ip;
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
UINT32 BackTraceGet(UINTPTR regFP, IpInfo *callChain, UINT32 maxDepth)
|
||||
{
|
||||
UINTPTR tmpFP, backLR;
|
||||
UINTPTR stackStart, stackEnd;
|
||||
UINTPTR backFP = regFP;
|
||||
UINT32 count = 0;
|
||||
BOOL ret;
|
||||
VADDR_T kvaddr;
|
||||
#ifdef LOSCFG_KERNEL_VM
|
||||
LosProcessCB *runProcess = OsCurrProcessGet();
|
||||
#endif
|
||||
|
||||
if (FindSuitableStack(regFP, &stackStart, &stackEnd, &kvaddr) == FALSE) {
|
||||
PrintExcInfo("traceback error fp = 0x%x\n", regFP);
|
||||
return;
|
||||
if (callChain == NULL) {
|
||||
PrintExcInfo("traceback error fp = 0x%x\n", regFP);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -715,7 +761,9 @@ VOID BackTraceSub(UINTPTR regFP)
|
|||
tmpFP = *(UINTPTR *)(UINTPTR)kvaddr;
|
||||
if (IsValidFP(tmpFP, stackStart, stackEnd, NULL) == TRUE) {
|
||||
backFP = tmpFP;
|
||||
PrintExcInfo("traceback fp fixed, trace using fp = 0x%x\n", backFP);
|
||||
if (callChain == NULL) {
|
||||
PrintExcInfo("traceback fp fixed, trace using fp = 0x%x\n", backFP);
|
||||
}
|
||||
}
|
||||
|
||||
while (IsValidFP(backFP, stackStart, stackEnd, &kvaddr) == TRUE) {
|
||||
|
@ -723,38 +771,49 @@ VOID BackTraceSub(UINTPTR regFP)
|
|||
#ifdef LOSCFG_COMPILER_CLANG_LLVM
|
||||
backFP = *(UINTPTR *)(UINTPTR)kvaddr;
|
||||
if (IsValidFP(tmpFP + POINTER_SIZE, stackStart, stackEnd, &kvaddr) == FALSE) {
|
||||
PrintExcInfo("traceback backLR check failed, backLP: 0x%x\n", tmpFP + POINTER_SIZE);
|
||||
return;
|
||||
if (callChain == NULL) {
|
||||
PrintExcInfo("traceback backLR check failed, backLP: 0x%x\n", tmpFP + POINTER_SIZE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
backLR = *(UINTPTR *)(UINTPTR)kvaddr;
|
||||
#else
|
||||
backLR = *(UINTPTR *)(UINTPTR)kvaddr;
|
||||
if (IsValidFP(tmpFP - POINTER_SIZE, stackStart, stackEnd, &kvaddr) == FALSE) {
|
||||
PrintExcInfo("traceback backFP check failed, backFP: 0x%x\n", tmpFP - POINTER_SIZE);
|
||||
return;
|
||||
if (callChain == NULL) {
|
||||
PrintExcInfo("traceback backFP check failed, backFP: 0x%x\n", tmpFP - POINTER_SIZE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
backFP = *(UINTPTR *)(UINTPTR)kvaddr;
|
||||
#endif
|
||||
IpInfo info = {0};
|
||||
ret = OsGetUsrIpInfo((VADDR_T)backLR, &info);
|
||||
if (callChain == NULL) {
|
||||
PrintExcInfo("traceback %u -- lr = 0x%x fp = 0x%x ", count, backLR, backFP);
|
||||
if (ret) {
|
||||
#ifdef LOSCFG_KERNEL_VM
|
||||
LosVmMapRegion *region = NULL;
|
||||
if (LOS_IsUserAddress((VADDR_T)backLR) == TRUE) {
|
||||
region = LOS_RegionFind(runProcess->vmSpace, (VADDR_T)backLR);
|
||||
}
|
||||
if (region != NULL) {
|
||||
PrintExcInfo("traceback %u -- lr = 0x%x fp = 0x%x lr in %s --> 0x%x\n", count, backLR, backFP,
|
||||
OsGetRegionNameOrFilePath(region),
|
||||
backLR - OsGetTextRegionBase(region, runProcess));
|
||||
region = NULL;
|
||||
} else
|
||||
PrintExcInfo("lr in %s --> 0x%x\n", info.f_path, info.ip);
|
||||
#else
|
||||
PrintExcInfo("\n");
|
||||
#endif
|
||||
{
|
||||
PrintExcInfo("traceback %u -- lr = 0x%x fp = 0x%x\n", count, backLR, backFP);
|
||||
} else {
|
||||
PrintExcInfo("\n");
|
||||
}
|
||||
} else {
|
||||
(VOID)memcpy_s(&callChain[count], sizeof(IpInfo), &info, sizeof(IpInfo));
|
||||
}
|
||||
count++;
|
||||
if ((count == OS_MAX_BACKTRACE) || (backFP == tmpFP)) {
|
||||
if ((count == maxDepth) || (backFP == tmpFP)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
VOID BackTraceSub(UINTPTR regFP)
|
||||
{
|
||||
(VOID)BackTraceGet(regFP, NULL, OS_MAX_BACKTRACE);
|
||||
}
|
||||
|
||||
VOID BackTrace(UINT32 regFP)
|
||||
|
|
|
@ -0,0 +1,373 @@
|
|||
/*
|
||||
* 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 "armv7_pmu_pri.h"
|
||||
#include "perf_pmu_pri.h"
|
||||
#include "los_hw_cpu.h"
|
||||
#include "asm/platform.h"
|
||||
|
||||
OS_PMU_INTS(LOSCFG_KERNEL_CORE_NUM, g_pmuIrqNr);
|
||||
STATIC HwPmu g_armv7Pmu;
|
||||
|
||||
STATIC INLINE UINT32 Armv7PmncRead(VOID)
|
||||
{
|
||||
UINT32 value = 0;
|
||||
__asm__ volatile("mrc p15, 0, %0, c9, c12, 0" : "=r"(value));
|
||||
return value;
|
||||
}
|
||||
|
||||
STATIC INLINE VOID Armv7PmncWrite(UINT32 value)
|
||||
{
|
||||
value &= ARMV7_PMNC_MASK;
|
||||
__asm__ volatile("mcr p15, 0, %0, c9, c12, 0" : : "r"(value));
|
||||
ISB;
|
||||
}
|
||||
|
||||
STATIC INLINE UINT32 Armv7PmuOverflowed(UINT32 pmnc)
|
||||
{
|
||||
return pmnc & ARMV7_OVERFLOWED_MASK;
|
||||
}
|
||||
|
||||
STATIC INLINE UINT32 Armv7PmuCntOverflowed(UINT32 pmnc, UINT32 index)
|
||||
{
|
||||
return pmnc & ARMV7_CNT2BIT(ARMV7_IDX2CNT(index));
|
||||
}
|
||||
|
||||
STATIC INLINE UINT32 Armv7CntValid(UINT32 index)
|
||||
{
|
||||
return index <= ARMV7_IDX_COUNTER_LAST;
|
||||
}
|
||||
|
||||
STATIC INLINE VOID Armv7PmuSelCnt(UINT32 index)
|
||||
{
|
||||
UINT32 counter = ARMV7_IDX2CNT(index);
|
||||
__asm__ volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (counter));
|
||||
ISB;
|
||||
}
|
||||
|
||||
STATIC INLINE VOID Armv7PmuSetCntPeriod(UINT32 index, UINT32 period)
|
||||
{
|
||||
if (!Armv7CntValid(index)) {
|
||||
PRINT_ERR("CPU writing wrong counter %u\n", index);
|
||||
} else if (index == ARMV7_IDX_CYCLE_COUNTER) {
|
||||
__asm__ volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (period));
|
||||
} else {
|
||||
Armv7PmuSelCnt(index);
|
||||
__asm__ volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (period));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC INLINE VOID Armv7BindEvt2Cnt(UINT32 index, UINT32 value)
|
||||
{
|
||||
PRINT_DEBUG("bind event: %u to counter: %u\n", value, index);
|
||||
Armv7PmuSelCnt(index);
|
||||
value &= ARMV7_EVTYPE_MASK;
|
||||
__asm__ volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (value));
|
||||
}
|
||||
|
||||
STATIC INLINE VOID Armv7EnableCnt(UINT32 index)
|
||||
{
|
||||
UINT32 counter = ARMV7_IDX2CNT(index);
|
||||
PRINT_DEBUG("index : %u, counter: %u\n", index, counter);
|
||||
__asm__ volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (ARMV7_CNT2BIT(counter)));
|
||||
}
|
||||
|
||||
STATIC INLINE VOID Armv7DisableCnt(UINT32 index)
|
||||
{
|
||||
UINT32 counter = ARMV7_IDX2CNT(index);
|
||||
PRINT_DEBUG("index : %u, counter: %u\n", index, counter);
|
||||
__asm__ volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (ARMV7_CNT2BIT(counter)));
|
||||
}
|
||||
|
||||
STATIC INLINE VOID Armv7EnableCntInterrupt(UINT32 index)
|
||||
{
|
||||
UINT32 counter = ARMV7_IDX2CNT(index);
|
||||
__asm__ volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (ARMV7_CNT2BIT(counter)));
|
||||
ISB;
|
||||
}
|
||||
|
||||
STATIC INLINE VOID Armv7DisableCntInterrupt(UINT32 index)
|
||||
{
|
||||
UINT32 counter = ARMV7_IDX2CNT(index);
|
||||
__asm__ volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (ARMV7_CNT2BIT(counter)));
|
||||
/* Clear the overflow flag in case an interrupt is pending. */
|
||||
__asm__ volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (ARMV7_CNT2BIT(counter)));
|
||||
ISB;
|
||||
}
|
||||
|
||||
STATIC INLINE UINT32 Armv7PmuGetOverflowStatus(VOID)
|
||||
{
|
||||
UINT32 value;
|
||||
|
||||
__asm__ volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (value));
|
||||
value &= ARMV7_FLAG_MASK;
|
||||
__asm__ volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (value));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
STATIC VOID Armv7EnableEvent(Event *event)
|
||||
{
|
||||
UINT32 cnt = event->counter;
|
||||
|
||||
if (!Armv7CntValid(cnt)) {
|
||||
PRINT_ERR("CPU enabling wrong PMNC counter IRQ enable %u\n", cnt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->period == 0) {
|
||||
PRINT_INFO("event period value not valid, counter: %u\n", cnt);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Enable counter and interrupt, and set the counter to count
|
||||
* the event that we're interested in.
|
||||
*/
|
||||
UINT32 intSave = LOS_IntLock();
|
||||
|
||||
Armv7DisableCnt(cnt);
|
||||
|
||||
/*
|
||||
* Set event (if destined for PMNx counters)
|
||||
* We only need to set the event for the cycle counter if we
|
||||
* have the ability to perform event filtering.
|
||||
*/
|
||||
if (cnt != ARMV7_IDX_CYCLE_COUNTER) {
|
||||
Armv7BindEvt2Cnt(cnt, event->eventId);
|
||||
}
|
||||
|
||||
/* Enable interrupt for this counter */
|
||||
Armv7EnableCntInterrupt(cnt);
|
||||
Armv7EnableCnt(cnt);
|
||||
LOS_IntRestore(intSave);
|
||||
|
||||
PRINT_DEBUG("enabled event: %u cnt: %u\n", event->eventId, cnt);
|
||||
}
|
||||
|
||||
STATIC VOID Armv7DisableEvent(Event *event)
|
||||
{
|
||||
UINT32 cnt = event->counter;
|
||||
|
||||
if (!Armv7CntValid(cnt)) {
|
||||
PRINT_ERR("CPU enabling wrong PMNC counter IRQ enable %u\n", cnt);
|
||||
return;
|
||||
}
|
||||
|
||||
UINT32 intSave = LOS_IntLock();
|
||||
Armv7DisableCnt(cnt);
|
||||
Armv7DisableCntInterrupt(cnt);
|
||||
LOS_IntRestore(intSave);
|
||||
}
|
||||
|
||||
|
||||
STATIC VOID Armv7StartAllCnt(VOID)
|
||||
{
|
||||
PRINT_DEBUG("starting pmu...\n");
|
||||
|
||||
/* Enable all counters */
|
||||
UINT32 reg = Armv7PmncRead() | ARMV7_PMNC_E;
|
||||
if (g_armv7Pmu.cntDivided) {
|
||||
reg |= ARMV7_PMNC_D;
|
||||
} else {
|
||||
reg &= ~ARMV7_PMNC_D;
|
||||
}
|
||||
|
||||
Armv7PmncWrite(reg);
|
||||
HalIrqUnmask(g_pmuIrqNr[ArchCurrCpuid()]);
|
||||
}
|
||||
|
||||
STATIC VOID Armv7StopAllCnt(VOID)
|
||||
{
|
||||
PRINT_DEBUG("stopping pmu...\n");
|
||||
/* Disable all counters */
|
||||
Armv7PmncWrite(Armv7PmncRead() & ~ARMV7_PMNC_E);
|
||||
|
||||
HalIrqMask(g_pmuIrqNr[ArchCurrCpuid()]);
|
||||
}
|
||||
|
||||
STATIC VOID Armv7ResetAllCnt(VOID)
|
||||
{
|
||||
UINT32 index;
|
||||
|
||||
/* The counter and interrupt enable registers are unknown at reset. */
|
||||
for (index = ARMV7_IDX_CYCLE_COUNTER; index < ARMV7_IDX_MAX_COUNTER; index++) {
|
||||
Armv7DisableCnt(index);
|
||||
Armv7DisableCntInterrupt(index);
|
||||
}
|
||||
|
||||
/* Initialize & Reset PMNC: C and P bits and D bits */
|
||||
UINT32 reg = ARMV7_PMNC_P | ARMV7_PMNC_C | (g_armv7Pmu.cntDivided ? ARMV7_PMNC_D : 0);
|
||||
Armv7PmncWrite(reg);
|
||||
}
|
||||
|
||||
STATIC VOID Armv7SetEventPeriod(Event *event)
|
||||
{
|
||||
if (event->period != 0) {
|
||||
PRINT_INFO("counter: %u, period: 0x%x\n", event->counter, event->period);
|
||||
Armv7PmuSetCntPeriod(event->counter, PERIOD_CALC(event->period));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC UINTPTR Armv7ReadEventCnt(Event *event)
|
||||
{
|
||||
UINT32 value = 0;
|
||||
UINT32 index = event->counter;
|
||||
|
||||
if (!Armv7CntValid(index)) {
|
||||
PRINT_ERR("CPU reading wrong counter %u\n", index);
|
||||
} else if (index == ARMV7_IDX_CYCLE_COUNTER) {
|
||||
__asm__ volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (value));
|
||||
} else {
|
||||
Armv7PmuSelCnt(index);
|
||||
__asm__ volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (value));
|
||||
}
|
||||
|
||||
if (value < PERIOD_CALC(event->period)) {
|
||||
if (Armv7PmuCntOverflowed(Armv7PmuGetOverflowStatus(), event->counter)) {
|
||||
value += event->period;
|
||||
}
|
||||
} else {
|
||||
value -= PERIOD_CALC(event->period);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
STATIC const UINT32 g_armv7Map[] = {
|
||||
[PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERF_HW_CYCLES,
|
||||
[PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERF_HW_INSTRUCTIONS,
|
||||
[PERF_COUNT_HW_DCACHE_REFERENCES] = ARMV7_PERF_HW_DCACHES,
|
||||
[PERF_COUNT_HW_DCACHE_MISSES] = ARMV7_PERF_HW_DCACHE_MISSES,
|
||||
[PERF_COUNT_HW_ICACHE_REFERENCES] = ARMV7_PERF_HW_ICACHES,
|
||||
[PERF_COUNT_HW_ICACHE_MISSES] = ARMV7_PERF_HW_ICACHE_MISSES,
|
||||
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERF_HW_BRANCHES,
|
||||
[PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERF_HW_BRANCE_MISSES,
|
||||
};
|
||||
|
||||
UINT32 Armv7PmuMapEvent(UINT32 eventType, BOOL reverse)
|
||||
{
|
||||
if (!reverse) { /* Common event to armv7 real event */
|
||||
if (eventType < ARRAY_SIZE(g_armv7Map)) {
|
||||
return g_armv7Map[eventType];
|
||||
}
|
||||
return eventType;
|
||||
} else { /* Armv7 real event to common event */
|
||||
UINT32 i;
|
||||
for (i = 0; i < ARRAY_SIZE(g_armv7Map); i++) {
|
||||
if (g_armv7Map[i] == eventType) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return PERF_HW_INVALID_EVENT_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC VOID Armv7PmuIrqHandler(VOID)
|
||||
{
|
||||
UINT32 index;
|
||||
PerfRegs regs;
|
||||
|
||||
PerfEvent *events = &(g_armv7Pmu.pmu.events);
|
||||
UINT32 eventNum = events->nr;
|
||||
|
||||
/* Get and reset the IRQ flags */
|
||||
UINT32 pmnc = Armv7PmuGetOverflowStatus();
|
||||
if (!Armv7PmuOverflowed(pmnc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
(VOID)memset_s(®s, sizeof(PerfRegs), 0, sizeof(PerfRegs));
|
||||
OsPerfFetchIrqRegs(®s);
|
||||
|
||||
Armv7StopAllCnt();
|
||||
|
||||
for (index = 0; index < eventNum; index++) {
|
||||
Event *event = &(events->per[index]);
|
||||
/*
|
||||
* We have a single interrupt for all counters. Check that
|
||||
* each counter has overflowed before we process it.
|
||||
*/
|
||||
if (!Armv7PmuCntOverflowed(pmnc, event->counter) || (event->period == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Armv7PmuSetCntPeriod(event->counter, PERIOD_CALC(event->period));
|
||||
|
||||
OsPerfUpdateEventCount(event, event->period);
|
||||
OsPerfHandleOverFlow(event, ®s);
|
||||
}
|
||||
Armv7StartAllCnt();
|
||||
}
|
||||
|
||||
UINT32 OsGetPmuMaxCounter(VOID)
|
||||
{
|
||||
return ARMV7_IDX_MAX_COUNTER;
|
||||
}
|
||||
|
||||
UINT32 OsGetPmuCycleCounter(VOID)
|
||||
{
|
||||
return ARMV7_IDX_CYCLE_COUNTER;
|
||||
}
|
||||
|
||||
UINT32 OsGetPmuCounter0(VOID)
|
||||
{
|
||||
return ARMV7_IDX_COUNTER0;
|
||||
}
|
||||
|
||||
STATIC HwPmu g_armv7Pmu = {
|
||||
.canDivided = TRUE,
|
||||
.enable = Armv7EnableEvent,
|
||||
.disable = Armv7DisableEvent,
|
||||
.start = Armv7StartAllCnt,
|
||||
.stop = Armv7StopAllCnt,
|
||||
.clear = Armv7ResetAllCnt,
|
||||
.setPeriod = Armv7SetEventPeriod,
|
||||
.readCnt = Armv7ReadEventCnt,
|
||||
.mapEvent = Armv7PmuMapEvent,
|
||||
};
|
||||
|
||||
UINT32 OsHwPmuInit(VOID)
|
||||
{
|
||||
UINT32 ret;
|
||||
UINT32 index;
|
||||
|
||||
for (index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {
|
||||
ret = LOS_HwiCreate(g_pmuIrqNr[index], 0, 0, Armv7PmuIrqHandler, 0);
|
||||
if (ret != LOS_OK) {
|
||||
PRINT_ERR("pmu %u irq handler register failed\n", g_pmuIrqNr[index]);
|
||||
return ret;
|
||||
}
|
||||
#ifdef LOSCFG_KERNEL_SMP
|
||||
HalIrqSetAffinity(g_pmuIrqNr[index], CPUID_TO_AFFI_MASK(index));
|
||||
#endif
|
||||
}
|
||||
ret = OsPerfHwInit(&g_armv7Pmu);
|
||||
return ret;
|
||||
}
|
|
@ -149,6 +149,9 @@ VOID HalIrqInit(VOID)
|
|||
(VOID)LOS_HwiCreate(LOS_MP_IPI_WAKEUP, 0xa0, 0, OsMpWakeHandler, 0);
|
||||
(VOID)LOS_HwiCreate(LOS_MP_IPI_SCHEDULE, 0xa0, 0, OsMpScheduleHandler, 0);
|
||||
(VOID)LOS_HwiCreate(LOS_MP_IPI_HALT, 0xa0, 0, OsMpHaltHandler, 0);
|
||||
#ifdef LOSCFG_KERNEL_SMP_CALL
|
||||
(VOID)LOS_HwiCreate(LOS_MP_IPI_FUNC_CALL, 0xa0, 0, OsMpFuncCallHandler, 0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -401,9 +401,12 @@ VOID HalIrqInit(VOID)
|
|||
|
||||
#ifdef LOSCFG_KERNEL_SMP
|
||||
/* register inter-processor interrupt */
|
||||
LOS_HwiCreate(LOS_MP_IPI_WAKEUP, 0xa0, 0, OsMpWakeHandler, 0);
|
||||
LOS_HwiCreate(LOS_MP_IPI_SCHEDULE, 0xa0, 0, OsMpScheduleHandler, 0);
|
||||
LOS_HwiCreate(LOS_MP_IPI_HALT, 0xa0, 0, OsMpScheduleHandler, 0);
|
||||
(VOID)LOS_HwiCreate(LOS_MP_IPI_WAKEUP, 0xa0, 0, OsMpWakeHandler, 0);
|
||||
(VOID)LOS_HwiCreate(LOS_MP_IPI_SCHEDULE, 0xa0, 0, OsMpScheduleHandler, 0);
|
||||
(VOID)LOS_HwiCreate(LOS_MP_IPI_HALT, 0xa0, 0, OsMpScheduleHandler, 0);
|
||||
#ifdef LOSCFG_KERNEL_SMP_CALL
|
||||
(VOID)LOS_HwiCreate(LOS_MP_IPI_FUNC_CALL, 0xa0, 0, OsMpFuncCallHandler, 0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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_H
|
||||
#define _PERF_H
|
||||
|
||||
#include "los_typedef.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define OsPerfArchFetchCallerRegs(regs) \
|
||||
do { \
|
||||
(regs)->pc = (UINTPTR)__builtin_return_address(0); \
|
||||
(regs)->fp = (UINTPTR)__builtin_frame_address(0); \
|
||||
} while (0)
|
||||
|
||||
#define OsPerfArchFetchIrqRegs(regs, tcb) \
|
||||
do { \
|
||||
(regs)->pc = (tcb)->pc; \
|
||||
(regs)->fp = (tcb)->fp; \
|
||||
} while (0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* _PERF_H */
|
|
@ -34,6 +34,7 @@ group("drivers") {
|
|||
"block/disk",
|
||||
"char/bch",
|
||||
"char/mem",
|
||||
"char/perf",
|
||||
"char/quickstart",
|
||||
"char/random",
|
||||
"char/trace",
|
||||
|
|
|
@ -15,6 +15,7 @@ source "drivers/char/quickstart/Kconfig"
|
|||
source "drivers/char/random/Kconfig"
|
||||
source "drivers/char/video/Kconfig"
|
||||
source "drivers/char/trace/Kconfig"
|
||||
source "drivers/char/perf/Kconfig"
|
||||
|
||||
source "../../drivers/liteos/tzdriver/Kconfig"
|
||||
source "../../drivers/liteos/hievent/Kconfig"
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
# 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_DRIVERS_PERF)
|
||||
module_name = "perf_dev"
|
||||
kernel_module(module_name) {
|
||||
sources = [ "src/perf.c" ]
|
||||
|
||||
public_configs = [ ":public" ]
|
||||
}
|
||||
|
||||
config("public") {
|
||||
include_dirs = [ "include" ]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
config DRIVERS_PERF
|
||||
bool "Enable PERF DRIVER"
|
||||
default y
|
||||
depends on DRIVERS && FS_VFS && KERNEL_PERF
|
||||
help
|
||||
Answer Y to enable LiteOS support perf in userspace.
|
|
@ -0,0 +1,36 @@
|
|||
# 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 $(LITEOSTOPDIR)/config.mk
|
||||
|
||||
MODULE_NAME := perf_dev
|
||||
|
||||
LOCAL_SRCS := $(wildcard src/*.c)
|
||||
|
||||
include $(MODULE)
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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_DEV_PERF_H__
|
||||
#define __LOS_DEV_PERF_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int DevPerfRegister(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* 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 "fcntl.h"
|
||||
#include "user_copy.h"
|
||||
#include "sys/ioctl.h"
|
||||
#include "fs/driver.h"
|
||||
#include "los_dev_perf.h"
|
||||
#include "los_perf.h"
|
||||
#include "los_init.h"
|
||||
|
||||
#define PERF_DRIVER "/dev/perf"
|
||||
#define PERF_DRIVER_MODE 0666
|
||||
|
||||
/* perf ioctl */
|
||||
#define PERF_IOC_MAGIC 'T'
|
||||
#define PERF_START _IO(PERF_IOC_MAGIC, 1)
|
||||
#define PERF_STOP _IO(PERF_IOC_MAGIC, 2)
|
||||
|
||||
static int PerfOpen(struct file *filep)
|
||||
{
|
||||
(void)filep;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int PerfClose(struct file *filep)
|
||||
{
|
||||
(void)filep;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t PerfRead(struct file *filep, char *buffer, size_t buflen)
|
||||
{
|
||||
/* perf record buffer read */
|
||||
(void)filep;
|
||||
int ret;
|
||||
int realLen;
|
||||
|
||||
char *records = LOS_MemAlloc(m_aucSysMem0, buflen);
|
||||
if (records == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
realLen = LOS_PerfDataRead(records, buflen); /* get sample data */
|
||||
if (realLen == 0) {
|
||||
PRINT_ERR("Perf read failed, check whether perf is configured to sample mode.\n");
|
||||
ret = -EINVAL;
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
ret = LOS_CopyFromKernel((void *)buffer, buflen, (void *)records, realLen);
|
||||
if (ret != 0) {
|
||||
ret = -EINVAL;
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
ret = realLen;
|
||||
EXIT:
|
||||
LOS_MemFree(m_aucSysMem0, records);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t PerfConfig(struct file *filep, const char *buffer, size_t buflen)
|
||||
{
|
||||
(void)filep;
|
||||
int ret;
|
||||
PerfConfigAttr attr = {0};
|
||||
int attrlen = sizeof(PerfConfigAttr);
|
||||
|
||||
if (buflen != attrlen) {
|
||||
PRINT_ERR("PerfConfigAttr is %d bytes not %d\n", attrlen, buflen);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = LOS_CopyToKernel(&attr, attrlen, buffer, buflen);
|
||||
if (ret != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = LOS_PerfConfig(&attr);
|
||||
if (ret != LOS_OK) {
|
||||
PRINT_ERR("perf config error %u\n", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int PerfIoctl(struct file *filep, int cmd, unsigned long arg)
|
||||
{
|
||||
(void)filep;
|
||||
switch (cmd) {
|
||||
case PERF_START:
|
||||
LOS_PerfStart((UINT32)arg);
|
||||
break;
|
||||
case PERF_STOP:
|
||||
LOS_PerfStop();
|
||||
break;
|
||||
default:
|
||||
PRINT_ERR("Unknown perf ioctl cmd:%d\n", cmd);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations_vfs g_perfDevOps = {
|
||||
PerfOpen, /* open */
|
||||
PerfClose, /* close */
|
||||
PerfRead, /* read */
|
||||
PerfConfig, /* write */
|
||||
NULL, /* seek */
|
||||
PerfIoctl, /* ioctl */
|
||||
NULL, /* mmap */
|
||||
#ifndef CONFIG_DISABLE_POLL
|
||||
NULL, /* poll */
|
||||
#endif
|
||||
NULL, /* unlink */
|
||||
};
|
||||
|
||||
int DevPerfRegister(void)
|
||||
{
|
||||
return register_driver(PERF_DRIVER, &g_perfDevOps, PERF_DRIVER_MODE, 0); /* 0666: file mode */
|
||||
}
|
||||
|
||||
LOS_MODULE_INIT(DevPerfRegister, LOS_INIT_LEVEL_KMOD_EXTENDED);
|
|
@ -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"
|
|
@ -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 = [ "." ]
|
||||
}
|
|
@ -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
|
|
@ -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)
|
||||
|
|
@ -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);
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 */
|
|
@ -157,6 +157,12 @@ ifeq ($(LOSCFG_KERNEL_HOOK), y)
|
|||
LITEOS_HOOK_INCLUDE += -I $(LITEOSTOPDIR)/kernel/extended/hook/include
|
||||
endif
|
||||
|
||||
ifeq ($(LOSCFG_KERNEL_PERF), y)
|
||||
LITEOS_BASELIB += -lperf
|
||||
LIB_SUBDIRS += kernel/extended/perf
|
||||
LITEOS_PERF_INCLUDE += -I $(LITEOSTOPDIR)/kernel/extended/perf
|
||||
endif
|
||||
|
||||
ifeq ($(LOSCFG_KERNEL_LITEIPC), y)
|
||||
LITEOS_BASELIB += -lliteipc
|
||||
LIB_SUBDIRS += kernel/extended/liteipc
|
||||
|
@ -366,6 +372,12 @@ ifeq ($(LOSCFG_DRIVERS_TRACE), y)
|
|||
LIB_SUBDIRS += $(LITEOSTOPDIR)/drivers/char/trace
|
||||
endif
|
||||
|
||||
ifeq ($(LOSCFG_DRIVERS_PERF), y)
|
||||
LITEOS_BASELIB += -lperf_dev
|
||||
LIB_SUBDIRS += $(LITEOSTOPDIR)/drivers/char/perf
|
||||
LITEOS_DEV_PERF_INCLUDE += -I $(LITEOSTOPDIR)/drivers/char/perf/include
|
||||
endif
|
||||
|
||||
ifeq ($(LOSCFG_DRIVERS_QUICKSTART), y)
|
||||
LITEOS_BASELIB += -lquickstart
|
||||
LIB_SUBDIRS += $(LITEOSTOPDIR)/drivers/char/quickstart
|
||||
|
@ -494,7 +506,8 @@ endif
|
|||
LITEOS_EXTKERNEL_INCLUDE := $(LITEOS_CPPSUPPORT_INCLUDE) $(LITEOS_DYNLOAD_INCLUDE) \
|
||||
$(LITEOS_TICKLESS_INCLUDE) $(LITEOS_HOOK_INCLUDE)\
|
||||
$(LITEOS_VDSO_INCLUDE) $(LITEOS_LITEIPC_INCLUDE) \
|
||||
$(LITEOS_PIPE_INCLUDE) $(LITEOS_CPUP_INCLUDE)
|
||||
$(LITEOS_PIPE_INCLUDE) $(LITEOS_CPUP_INCLUDE) \
|
||||
$(LITEOS_PERF_INCLUDE)
|
||||
LITEOS_COMPAT_INCLUDE := $(LITEOS_POSIX_INCLUDE) $(LITEOS_LINUX_INCLUDE) \
|
||||
$(LITEOS_BSD_INCLUDE)
|
||||
LITEOS_FS_INCLUDE := $(LITEOS_VFS_INCLUDE) $(LITEOS_FAT_CACHE_INCLUDE) \
|
||||
|
@ -516,7 +529,7 @@ LITEOS_DRIVERS_INCLUDE := $(LITEOS_CELLWISE_INCLUDE) $(LITEOS_GPIO_INCLUDE
|
|||
$(LITEOS_REGULATOR_INCLUDE) $(LITEOS_VIDEO_INCLUDE) \
|
||||
$(LITEOS_DRIVERS_HDF_INCLUDE) $(LITEOS_TZDRIVER_INCLUDE) \
|
||||
$(LITEOS_HIEVENT_INCLUDE) $(LITEOS_DEV_MEM_INCLUDE) \
|
||||
$(LITEOS_DEV_QUICKSTART_INCLUDE)
|
||||
$(LITEOS_DEV_QUICKSTART_INCLUDE) $(LITEOS_DEV_PERF_INCLUDE)
|
||||
LITEOS_DFX_INCLUDE := $(LITEOS_HILOG_INCLUDE) \
|
||||
$(LITEOS_BLACKBOX_INCLUDE) \
|
||||
$(LITEOS_HIDUMPER_INCLUDE)
|
||||
|
|
Loading…
Reference in New Issue