/*-----------------------------------------------------------------------------*/ /* Include Header Files */ /*-----------------------------------------------------------------------------*/ #include #include #include #include //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 #include #include #include #include #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);