nt9856x/code/vos/drivers/source/kwrap/linux/rtos_os_perf.c
2023-03-28 15:07:53 +08:00

307 lines
8.1 KiB
C
Executable File

/*-----------------------------------------------------------------------------*/
/* Include Header Files */
/*-----------------------------------------------------------------------------*/
#include <linux/module.h>
#include <asm/io.h>
#include <linux/uaccess.h>
#include <plat/hardware.h> //for NVT_TIMER_BASE_VIRT
#define __MODULE__ rtos_perf
#define __DBGLVL__ 8 // 0=FATAL, 1=ERR, 2=WRN, 3=UNIT, 4=FUNC, 5=IND, 6=MSG, 7=VALUE, 8=USER
#define __DBGFLT__ "*"
#include <kwrap/debug.h>
#include <kwrap/cpu.h>
#include <kwrap/dev.h>
#include <kwrap/perf.h>
#include <kwrap/spinlock.h>
#include "vos_ioctl.h"
/*-----------------------------------------------------------------------------*/
/* Local Types Declarations */
/*-----------------------------------------------------------------------------*/
#define RTOS_PERF_INITED_TAG MAKEFOURCC('R', 'P', 'E', 'R') ///< a key value
#ifndef NVT_TIMER_OFS_TM0_CNT
#if defined(_BSP_NA51055_)
#define NVT_TIMER_OFS_TM0_CNT 0x108
#elif defined(_BSP_NA51000_)
#define NVT_TIMER_OFS_TM0_CNT 0x108
#elif defined(_BSP_NA51068_)
#define NVT_TIMER_OFS_TM0_CNT 0x108
#elif defined(_BSP_NA51089_)
#define NVT_TIMER_OFS_TM0_CNT 0x108
#elif defined(_BSP_NA51090_)
#define NVT_TIMER_OFS_TM0_CNT 0x108
#else
#error NVT_TIMER_OFS_TM0_CNT not defined
#endif
#endif
#ifndef NVT_TIMER_BASE_VIRT
#define VOS_GET_TIMER_REG(ofs) 0 //should be fixed
#else
#define VOS_GET_TIMER_REG(ofs) readl((volatile void __iomem *)(NVT_TIMER_BASE_VIRT+(ofs)))
#endif
#define VOS_PERF_LIST_NUM 32
#define VOS_PERF_LIST_NAME_SIZE 32
#define VOS_GET_TM0_CNT() (VOS_TICK)VOS_GET_TIMER_REG(NVT_TIMER_OFS_TM0_CNT)
#define VOS_STRCPY(dst, src, dst_size) do { \
strncpy(dst, src, (dst_size)-1); \
dst[(dst_size)-1] = '\0'; \
} while(0)
typedef struct _VOS_PERF_LIST_ITEM {
CHAR name[VOS_PERF_LIST_NAME_SIZE];
VOS_TICK tick;
UINT32 line_no;
UINT32 cus_val;
UINT32 diff_time; //diff time to the first same name
INT column;
} VOS_PERF_LIST_ITEM;
/*-----------------------------------------------------------------------------*/
/* Local Global Variables */
/*-----------------------------------------------------------------------------*/
unsigned int rtos_perf_debug_level = NVT_DBG_WRN;
static VK_DEFINE_SPINLOCK(g_perf_lock);
static VOS_PERF_LIST_ITEM g_perf_list[VOS_PERF_LIST_NUM] = {0};
static UINT32 g_perf_list_idx = 0;
static UINT32 g_perf_list_skip_count = 0;
module_param_named(rtos_perf_debug_level, rtos_perf_debug_level, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(rtos_perf_debug_level, "Debug message level");
/*-----------------------------------------------------------------------------*/
/* Interface Functions */
/*-----------------------------------------------------------------------------*/
void vos_perf_init(void *param)
{
}
void vos_perf_exit(void)
{
}
void vos_perf_mark(VOS_TICK *p_tick)
{
if (NULL == p_tick) {
DBG_ERR("p_tick is NULL\r\n");
return;
}
*p_tick = VOS_GET_TM0_CNT();
}
VOS_TICK vos_perf_duration(VOS_TICK t_begin, VOS_TICK t_end)
{
return (t_end - t_begin);
}
void vos_perf_list_reset(void)
{
unsigned long flags;
vk_spin_lock_irqsave(&g_perf_lock, flags);
g_perf_list_idx = 0;
g_perf_list_skip_count = 0;
vk_spin_unlock_irqrestore(&g_perf_lock, flags);
}
void vos_perf_list_mark(const CHAR *p_name, UINT32 line_no, UINT32 cus_val)
{
unsigned long flags;
vk_spin_lock_irqsave(&g_perf_lock, flags);
if (g_perf_list_idx < VOS_PERF_LIST_NUM) {
VOS_STRCPY(g_perf_list[g_perf_list_idx].name, p_name, sizeof(g_perf_list[g_perf_list_idx].name));
g_perf_list[g_perf_list_idx].tick = VOS_GET_TM0_CNT();
g_perf_list[g_perf_list_idx].line_no = line_no;
g_perf_list[g_perf_list_idx].cus_val = cus_val;
g_perf_list_idx++;
} else {
g_perf_list_skip_count++;
}
vk_spin_unlock_irqrestore(&g_perf_lock, flags);
}
static void vos_perf_list_dump_by_idx(void)
{
INT list_idx;
INT max_idx;
DBG_DUMP("\r\n===== %s =====\r\n", __func__);
max_idx = g_perf_list_idx;
for(list_idx = 0; list_idx < max_idx; list_idx++) {
DBG_DUMP("[%02d] %s() ln %d ts %d df %d cus %d\r\n",
list_idx,
g_perf_list[list_idx].name,
(UINT)g_perf_list[list_idx].line_no,
(UINT)g_perf_list[list_idx].tick,
(list_idx < 1) ? 0 : (UINT)vos_perf_duration(g_perf_list[list_idx-1].tick, g_perf_list[list_idx].tick),
(UINT)g_perf_list[list_idx].cus_val);
}
}
static void vos_perf_list_dump_by_name(void)
{
INT item_idx, item_idx2;
INT column_cur, column_max;
INT row_idx;
INT max_idx;
pr_cont("\r\n===== %s =====\r\n", __func__);
max_idx = g_perf_list_idx;
//reset the column to recount the newest column
for (item_idx = 0; item_idx < max_idx; item_idx++) {
g_perf_list[item_idx].column = 0;
}
//setup the column of each item
column_cur = 0;
for (item_idx = 0; item_idx < max_idx; item_idx++) {
if (0 != g_perf_list[item_idx].column) {
continue;
}
column_cur++;
g_perf_list[item_idx].column = column_cur;
g_perf_list[item_idx].diff_time = 0;
for (item_idx2 = item_idx + 1; item_idx2 < max_idx; item_idx2++) {
if (!strcmp(g_perf_list[item_idx2].name, g_perf_list[item_idx].name)) {
g_perf_list[item_idx2].column = column_cur;
g_perf_list[item_idx2].diff_time = g_perf_list[item_idx2].tick - g_perf_list[item_idx].tick;
}
}
}
column_max = column_cur;
#if 0 //for debug
DBG_DUMP("max_idx %d, column_max %d\r\n", max_idx, column_max);
for (item_idx = 0; item_idx < max_idx; item_idx++) {
DBG_DUMP("item[%d], column %d, df %u, %u, %s\r\n",
item_idx,
g_perf_list[item_idx].column,
g_perf_list[item_idx].tick,
g_perf_list[item_idx].diff_time,
g_perf_list[item_idx].name);
}
#endif
//print column name
pr_cont("Name");
for (column_cur = 1; column_cur <= column_max; column_cur++) {
for (item_idx = 0; item_idx < max_idx; item_idx++) {
if (column_cur == g_perf_list[item_idx].column) {
pr_cont(" %10s", g_perf_list[item_idx].name);
break;
}
}
}
pr_cont("\n");
//print item data by column
for (row_idx = 0; row_idx < max_idx; row_idx++) {
pr_cont("[%02d]", row_idx);
for (column_cur = 1; column_cur <= column_max; column_cur++) {
if (column_cur == g_perf_list[row_idx].column) {
pr_cont(" %10u", g_perf_list[row_idx].tick);
} else {
pr_cont(" %10c", '-');
}
}
pr_cont("\n");
}
//print diff time
pr_cont("-----------------------------------------------\n");
pr_cont("Diff");
for (column_cur = 1; column_cur <= column_max; column_cur++) {
for (item_idx = (max_idx-1); item_idx >= 0; item_idx--) {
if (column_cur == g_perf_list[item_idx].column) {
pr_cont(" %10u", g_perf_list[item_idx].diff_time);
break;
}
}
}
pr_cont("\n");
}
void vos_perf_list_dump(void)
{
unsigned long flags;
vk_spin_lock_irqsave(&g_perf_lock, flags);
vos_perf_list_dump_by_idx();
vos_perf_list_dump_by_name();
if (g_perf_list_skip_count) {
DBG_WRN("skip count %d\r\n", (UINT)g_perf_list_skip_count);
}
vk_spin_unlock_irqrestore(&g_perf_lock, flags);
}
int _IOFUNC_PERF_IOCMD_MARK(unsigned long arg)
{
VOS_PERF_IOARG ioarg = {0};
VOS_TICK tmp_tick;
//-------------------
//skip copy_from_user
//-------------------
vos_perf_mark(&tmp_tick);
ioarg.tick = tmp_tick;
if (copy_to_user((void *)arg, (void *)&ioarg, sizeof(VOS_PERF_IOARG))) {
DBG_ERR("copy_to_user failed\n");
return -EFAULT;
}
return 0;
}
int _IOFUNC_PERF_IOCMD_LIST_MARK(unsigned long arg)
{
VOS_PERF_IOARG ioarg = {0};
if (copy_from_user((void *)&ioarg, (void *)arg, sizeof(VOS_PERF_IOARG))) {
DBG_ERR("copy_from_user failed\n");
return -EFAULT;
}
vos_perf_list_mark(ioarg.name, ioarg.line_no, ioarg.cus_val);
return 0;
}
int _IOFUNC_PERF_IOCMD_LIST_DUMP(unsigned long arg)
{
vos_perf_list_dump();
return 0;
}
int _IOFUNC_PERF_IOCMD_LIST_RESET(unsigned long arg)
{
vos_perf_list_reset();
return 0;
}
EXPORT_SYMBOL(vos_perf_mark);
EXPORT_SYMBOL(vos_perf_duration);
EXPORT_SYMBOL(vos_perf_list_reset);
EXPORT_SYMBOL(vos_perf_list_mark);
EXPORT_SYMBOL(vos_perf_list_dump);