提交 6e0a3f10 编写于 作者: L LiteOS2021

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: NLiteOS2021 <dinglu@huawei.com>
Change-Id: Ieb9b7483c85d1495df7c55bc0027f4309dff9814
上级 92f33ab9
......@@ -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
# 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" ]
}
# 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)
/*
* 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 */
/*
* 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 */
/*
* 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 */
/*
* 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 */
/*
* 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 */
/*
* 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;
}
/*
* 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;
}
\ No newline at end of file
/*
* 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;
}
\ No newline at end of file
/*
* 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");
}
/*
* 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);
}
/*
* 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)
/*
* 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)
......
/*
* 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(&regs, sizeof(PerfRegs), 0, sizeof(PerfRegs));
OsPerfFetchIrqRegs(&regs);
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, &regs);
}
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
}
......
/*
* 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"
# 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" ]
}
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.
# 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)
/*
* 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
/*
* 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"
\ No newline at end of file
# 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 = [ "." ]
}
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
\ No newline at end of file
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)
/*
* 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);
/*
* 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 */
/*
* 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;
}
/*
* 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 */
/*
* 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;
}
/*
* 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 */
/*
* 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;
}
/*
* 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(&regs, 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(&regs);
OsPerfHandleOverFlow(event, &regs);
}
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);
}
/*
* 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(&regs, sizeof(PerfRegs), 0, sizeof(PerfRegs));
OsPerfFetchIrqRegs(&regs);
for (index = 0; index < eventNum; index++) {
Event *event = &(events->per[index]);
OsPerfUpdateEventCount(event, 1); /* eventCount += 1 every once */
OsPerfHandleOverFlow(event, &regs);
}
}
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
}
......
/*
* 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)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册