| /* |
| * tracker.c - System accounting over taskstats interface |
| * |
| * Copyright (C) Jay Lan, <jlan@sgi.com> |
| * |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| */ |
| #include <linux/io.h> |
| #include <linux/module.h> |
| #include <linux/kernel.h> |
| #include <linux/sched.h> |
| #include <linux/jiffies.h> |
| #include <linux/slab.h> |
| #include <linux/timer.h> |
| #include <linux/delay.h> |
| #include <linux/kthread.h> |
| #include <linux/timer.h> |
| #include <linux/uaccess.h> |
| #include <linux/export.h> |
| #include <linux/sched/clock.h> |
| #include "ram_config.h" |
| |
| /******************************************************************************* |
| * ºê¶¨Òå * |
| *******************************************************************************/ |
| #define _OS_LINUX 1 |
| |
| #if defined(_OS_TOS) |
| # define OS_STATISTIC_IRAM_BASE (IRAM_BASE_ADDR_OS_STATISTIC_PSCPU) |
| # define OS_STATISTIC_TIME zDrvTimer_Stamp() |
| #elif defined(_OS_LINUX) |
| # define OS_STATISTIC_IRAM_BASE g_zxic_trace_apcpu_addr //(IRAM_BASE_ADDR_OS_STATISTIC_APCPU) |
| # define OS_STATISTIC_TIME (cpu_clock(0)>>10) |
| #else |
| # error "unknown os" |
| #endif |
| |
| |
| |
| #define OS_IRAM_STATISTIC_CNT (5) |
| #define OS_IRAM_STATISTIC_NAME_LEN (16) |
| #define OS_DDR_STATISTIC_CNT (1000) |
| |
| #define OS_IRAM_THREAD_SWAPIN (OS_STATISTIC_IRAM_BASE) |
| #define OS_IRAM_IRQ_START (OS_IRAM_THREAD_SWAPIN + sizeof(t_os_iram_thread_statistic)) |
| #define OS_IRAM_IRQ_END (OS_IRAM_IRQ_START + sizeof(t_os_iram_statistic)) |
| |
| #if defined(_OS_TOS) |
| #define OS_IRAM_DSR_START (OS_IRAM_IRQ_END + sizeof(t_os_iram_statistic)) |
| #define OS_IRAM_DSR_END (OS_IRAM_DSR_START + sizeof(t_os_iram_statistic)) |
| #elif defined(_OS_LINUX) |
| #define OS_IRAM_SOFTIRQ_START (OS_IRAM_IRQ_END + sizeof(t_os_iram_statistic)) |
| #define OS_IRAM_SOFTIRQ_END (OS_IRAM_SOFTIRQ_START + sizeof(t_os_iram_statistic)) |
| #define OS_IRAM_TIMER_START (OS_IRAM_SOFTIRQ_END + sizeof(t_os_iram_statistic)) |
| #define OS_IRAM_TIMER_END (OS_IRAM_TIMER_START + sizeof(t_os_iram_statistic)) |
| #endif |
| |
| #define os_statistic_check() *((volatile unsigned long *)OS_STATISTIC_IRAM_BASE) |
| #define os_statistic_enabled() g_os_statistic_enable |
| |
| /******************************************************************************* |
| * Êý¾Ý½á¹¹¶¨Òå * |
| *******************************************************************************/ |
| typedef volatile struct { |
| unsigned int cnt; |
| unsigned int index; |
| struct { |
| unsigned char name[OS_IRAM_STATISTIC_NAME_LEN]; |
| unsigned int data2; |
| } statistics[OS_IRAM_STATISTIC_CNT]; |
| }t_os_iram_thread_statistic; |
| |
| typedef volatile struct { |
| unsigned int cnt; |
| unsigned int index; |
| struct { |
| unsigned int data1; |
| unsigned int data2; |
| } statistics[OS_IRAM_STATISTIC_CNT]; |
| }t_os_iram_statistic; |
| |
| typedef struct { |
| unsigned int cnt; |
| unsigned int index; |
| struct { |
| unsigned int data1; |
| unsigned int data2; |
| } statistics[OS_DDR_STATISTIC_CNT]; |
| }t_os_ddr_statistic; |
| |
| /******************************************************************************* |
| * È«¾Ö±äÁ¿ * |
| *******************************************************************************/ |
| #if defined(_OS_LINUX) |
| volatile static char *g_zxic_trace_apcpu_addr; |
| #endif |
| |
| volatile static int g_os_statistic_enable; |
| volatile static unsigned int g_os_statistic_cnt; |
| |
| volatile static t_os_iram_thread_statistic *g_os_iram_swapin_statistic; |
| volatile static t_os_iram_statistic *g_os_iram_irq_start_statistic; |
| volatile static t_os_iram_statistic *g_os_iram_irq_end_statistic; |
| |
| #if defined(_OS_TOS) |
| static t_os_iram_statistic *g_os_iram_dsr_start_statistic; |
| static t_os_iram_statistic *g_os_iram_dsr_end_statistic; |
| #elif defined(_OS_LINUX) |
| volatile static t_os_iram_statistic *g_os_iram_softirq_start_statistic; |
| volatile static t_os_iram_statistic *g_os_iram_softirq_end_statistic; |
| volatile static t_os_iram_statistic *g_os_iram_timer_start_statistic; |
| volatile static t_os_iram_statistic *g_os_iram_timer_end_statistic; |
| #endif |
| |
| volatile static t_os_ddr_statistic *g_os_ddr_swapin_statistic; |
| volatile static t_os_ddr_statistic *g_os_ddr_irq_start_statistic; |
| volatile static t_os_ddr_statistic *g_os_ddr_irq_end_statistic; |
| |
| #if defined(_OS_TOS) |
| static t_os_ddr_statistic *g_os_ddr_dsr_start_statistic; |
| static t_os_ddr_statistic *g_os_ddr_dsr_end_statistic; |
| #elif defined(_OS_LINUX) |
| volatile static t_os_ddr_statistic *g_os_ddr_softirq_start_statistic; |
| volatile static t_os_ddr_statistic *g_os_ddr_softirq_end_statistic; |
| volatile static t_os_ddr_statistic *g_os_ddr_timer_start_statistic; |
| volatile static t_os_ddr_statistic *g_os_ddr_timer_end_statistic; |
| #endif |
| |
| /******************************************************************************* |
| * È«¾Öº¯ÊýÉùÃ÷ * |
| *******************************************************************************/ |
| void os_statistic_enable(void); |
| /******************************************************************************* |
| * ¾Ö²¿º¯Êý * |
| *******************************************************************************/ |
| /******************************************************************************* |
| * ¹¦ÄÜÃèÊö: ¹ì¼£Í³¼Æµ½IRAM |
| * ²ÎÊý˵Ã÷: |
| * (´«Èë²ÎÊý) iram_addr: µØÖ· |
| data: ʼþÏî |
| time: ʱ¼ä |
| * (´«³ö²ÎÊý) void |
| * ·µ »Ø Öµ: void |
| * ÆäËü˵Ã÷: ÎÞ |
| *******************************************************************************/ |
| static inline void os_statistic_in_iram(volatile void *iram_addr, void *data, unsigned long time) |
| { |
| unsigned long index; |
| t_os_iram_statistic *iram; |
| |
| iram = (t_os_iram_statistic *)iram_addr; |
| |
| index = iram->index; |
| if(index >= OS_IRAM_STATISTIC_CNT) |
| { |
| index = 0; |
| } |
| |
| iram->statistics[index].data1 = (unsigned int)data; |
| iram->statistics[index].data2 = time; |
| index++; |
| |
| iram->index = index; |
| iram->cnt = g_os_statistic_cnt; |
| } |
| |
| /******************************************************************************* |
| * ¹¦ÄÜÃèÊö: Ï̹߳켣ͳ¼Æµ½IRAM |
| * ²ÎÊý˵Ã÷: |
| * (´«Èë²ÎÊý) iram_addr: µØÖ· |
| data: ʼþÏî |
| time: ʱ¼ä |
| * (´«³ö²ÎÊý) void |
| * ·µ »Ø Öµ: void |
| * ÆäËü˵Ã÷: ÎÞ |
| *******************************************************************************/ |
| static inline void os_statistic_thread_in_iram(volatile void *iram_addr, void *data, unsigned long time) |
| { |
| unsigned long index; |
| t_os_iram_thread_statistic *iram; |
| |
| iram = (t_os_iram_thread_statistic *)iram_addr; |
| |
| index = iram->index; |
| if(index >= OS_IRAM_STATISTIC_CNT) |
| { |
| index = 0; |
| } |
| |
| #if defined(_OS_TOS) |
| strncpy((char *)(iram->statistics[index].name), cyg_thread_get_name((cyg_handle_t)data), OS_IRAM_STATISTIC_NAME_LEN - 1); |
| #elif defined(_OS_LINUX) |
| strncpy((char *)(iram->statistics[index].name), ((struct task_struct *)data)->comm, OS_IRAM_STATISTIC_NAME_LEN - 1); |
| #else |
| # error "unkown os" |
| #endif |
| iram->statistics[index].name[OS_IRAM_STATISTIC_NAME_LEN - 1] = 0; |
| iram->statistics[index].data2 = time; |
| index++; |
| |
| iram->index = index; |
| iram->cnt = g_os_statistic_cnt; |
| } |
| |
| /******************************************************************************* |
| * ¹¦ÄÜÃèÊö: ¹ì¼£Í³¼Æµ½DDR |
| * ²ÎÊý˵Ã÷: |
| * (´«Èë²ÎÊý) iram_addr: µØÖ· |
| data: ʼþÏî |
| time: ʱ¼ä |
| * (´«³ö²ÎÊý) void |
| * ·µ »Ø Öµ: void |
| * ÆäËü˵Ã÷: ÎÞ |
| *******************************************************************************/ |
| static inline void os_statistic_in_ddr(void *ddr_addr, void *data, unsigned long time) |
| { |
| unsigned long index; |
| t_os_ddr_statistic *ddr; |
| |
| ddr = (t_os_ddr_statistic *)ddr_addr; |
| |
| index = ddr->index; |
| if (index >= OS_DDR_STATISTIC_CNT) |
| { |
| index = 0; |
| } |
| ddr->statistics[index].data1 = (unsigned int)data; |
| ddr->statistics[index].data2 = time; |
| index++; |
| |
| ddr->index = index; |
| ddr->cnt = g_os_statistic_cnt; |
| } |
| |
| /******************************************************************************* |
| * ¹¦ÄÜÃèÊö: ¹ì¼£Í³¼Æµ½DDR |
| * ²ÎÊý˵Ã÷: |
| * (´«Èë²ÎÊý) iram_addr: µØÖ· |
| data: ʼþÏî |
| time: ʱ¼ä |
| * (´«³ö²ÎÊý) void |
| * ·µ »Ø Öµ: void |
| * ÆäËü˵Ã÷: ÎÞ |
| *******************************************************************************/ |
| static inline void os_statistic_info_update(void) |
| { |
| g_os_statistic_cnt++; |
| } |
| |
| /******************************************************************************* |
| * ¹¦ÄÜÃèÊö: ¶¨Ê±Æ÷»Øµ÷¹³×Ó |
| * ²ÎÊý˵Ã÷: |
| * (´«Èë²ÎÊý) |
| * (´«³ö²ÎÊý) void |
| * ·µ »Ø Öµ: void |
| * ÆäËü˵Ã÷: ÎÞ |
| *******************************************************************************/ |
| static int os_statistic_delayed_work_timer_fn(unsigned long data) |
| { |
| int sec = 0; |
| msleep(20000); |
| while(!os_statistic_check()) |
| { |
| //³¬¹ý40s£¬Ö±½ÓÍ˳ö |
| if(sec >= 4) |
| return 0; |
| msleep(10000); |
| sec++; |
| } |
| os_statistic_enable(); |
| return 0; |
| } |
| |
| /******************************************************************************* |
| * È«¾Öº¯ÊýʵÏÖ * |
| *******************************************************************************/ |
| /******************************************************************************* |
| * ¹¦ÄÜÃèÊö: ʹÄܹ켣ͳ¼Æ¹¦ÄÜ |
| * ²ÎÊý˵Ã÷: |
| * (´«Èë²ÎÊý) address: ¼Ç¼µ½IRAMÖеĵØÖ· |
| size: IRAM¿Õ¼ä´óС |
| * (´«³ö²ÎÊý) void |
| * ·µ »Ø Öµ: void |
| * ÆäËü˵Ã÷: ÎÞ |
| *******************************************************************************/ |
| void os_statistic_enable(void) |
| { |
| #if defined(_OS_TOS) |
| g_os_iram_swapin_statistic = (t_os_iram_thread_statistic *)OS_IRAM_THREAD_SWAPIN; |
| g_os_iram_irq_start_statistic = (t_os_iram_statistic *)OS_IRAM_IRQ_START; |
| g_os_iram_irq_end_statistic = (t_os_iram_statistic *)OS_IRAM_IRQ_END; |
| g_os_iram_dsr_start_statistic = (t_os_iram_statistic *)OS_IRAM_DSR_START; |
| g_os_iram_dsr_end_statistic = (t_os_iram_statistic *)OS_IRAM_DSR_END; |
| |
| g_os_ddr_swapin_statistic = (t_os_ddr_statistic *)zOss_Malloc(sizeof(t_os_ddr_statistic)); |
| g_os_ddr_irq_start_statistic = (t_os_ddr_statistic *)zOss_Malloc(sizeof(t_os_ddr_statistic)); |
| g_os_ddr_irq_end_statistic = (t_os_ddr_statistic *)zOss_Malloc(sizeof(t_os_ddr_statistic)); |
| g_os_ddr_dsr_start_statistic = (t_os_ddr_statistic *)zOss_Malloc(sizeof(t_os_ddr_statistic)); |
| g_os_ddr_dsr_end_statistic = (t_os_ddr_statistic *)zOss_Malloc(sizeof(t_os_ddr_statistic)); |
| #elif defined(_OS_LINUX) |
| g_os_iram_swapin_statistic = (t_os_iram_thread_statistic *)OS_IRAM_THREAD_SWAPIN; |
| g_os_iram_irq_start_statistic = (t_os_iram_statistic *)OS_IRAM_IRQ_START; |
| g_os_iram_irq_end_statistic = (t_os_iram_statistic *)OS_IRAM_IRQ_END; |
| g_os_iram_softirq_start_statistic = (t_os_iram_statistic *)OS_IRAM_SOFTIRQ_START; |
| g_os_iram_softirq_end_statistic = (t_os_iram_statistic *)OS_IRAM_SOFTIRQ_END; |
| g_os_iram_timer_start_statistic = (t_os_iram_statistic *)OS_IRAM_TIMER_START; |
| g_os_iram_timer_end_statistic = (t_os_iram_statistic *)OS_IRAM_TIMER_END; |
| |
| g_os_ddr_swapin_statistic = (t_os_ddr_statistic *)kmalloc(sizeof(t_os_ddr_statistic), GFP_KERNEL); |
| g_os_ddr_irq_start_statistic = (t_os_ddr_statistic *)kmalloc(sizeof(t_os_ddr_statistic), GFP_KERNEL); |
| g_os_ddr_irq_end_statistic = (t_os_ddr_statistic *)kmalloc(sizeof(t_os_ddr_statistic), GFP_KERNEL); |
| g_os_ddr_softirq_start_statistic = (t_os_ddr_statistic *)kmalloc(sizeof(t_os_ddr_statistic), GFP_KERNEL); |
| g_os_ddr_softirq_end_statistic = (t_os_ddr_statistic *)kmalloc(sizeof(t_os_ddr_statistic), GFP_KERNEL); |
| g_os_ddr_timer_start_statistic = (t_os_ddr_statistic *)kmalloc(sizeof(t_os_ddr_statistic), GFP_KERNEL); |
| g_os_ddr_timer_end_statistic = (t_os_ddr_statistic *)kmalloc(sizeof(t_os_ddr_statistic), GFP_KERNEL); |
| |
| #else |
| # error "unkown os" |
| #endif |
| if ((unsigned int )g_os_iram_timer_end_statistic - (unsigned int )g_os_iram_swapin_statistic > (unsigned int )IRAM_BASE_LEN_OS_STATISTIC_PSCPU ) |
| { |
| BUG(); |
| } |
| g_os_statistic_enable = 1; |
| } |
| EXPORT_SYMBOL(os_statistic_enable); |
| |
| void zxic_trace_task_switch(struct task_struct *next) |
| { |
| unsigned long time; |
| if (!g_os_statistic_enable) |
| return ; |
| |
| time = OS_STATISTIC_TIME; |
| os_statistic_thread_in_iram(g_os_iram_swapin_statistic, next, time); |
| os_statistic_in_ddr(g_os_ddr_swapin_statistic, next, time); |
| os_statistic_info_update(); |
| } |
| |
| void zxic_trace_irq_enter(u32 irq) |
| { |
| unsigned long time; |
| if (!g_os_statistic_enable) |
| return ; |
| |
| time = OS_STATISTIC_TIME; |
| os_statistic_in_iram(g_os_iram_irq_start_statistic, irq, time); |
| os_statistic_in_ddr(g_os_ddr_irq_start_statistic, irq, time); |
| os_statistic_info_update(); |
| } |
| |
| void zxic_trace_irq_exit(u32 irq) |
| { |
| unsigned long time; |
| if (!g_os_statistic_enable) |
| return ; |
| |
| time = OS_STATISTIC_TIME; |
| os_statistic_in_iram(g_os_iram_irq_end_statistic, irq, time); |
| os_statistic_in_ddr(g_os_ddr_irq_end_statistic, irq, time); |
| os_statistic_info_update(); |
| } |
| |
| void zxic_trace_softirq_enter(u32 vec_nr) |
| { |
| unsigned long time; |
| if (!g_os_statistic_enable) |
| return ; |
| |
| time = OS_STATISTIC_TIME; |
| os_statistic_in_iram(g_os_iram_softirq_start_statistic, vec_nr, time); |
| os_statistic_in_ddr(g_os_ddr_softirq_start_statistic, vec_nr, time); |
| os_statistic_info_update(); |
| } |
| |
| void zxic_trace_softirq_exit(u32 vec_nr) |
| { |
| unsigned long time; |
| if (!g_os_statistic_enable) |
| return ; |
| |
| time = OS_STATISTIC_TIME; |
| os_statistic_in_iram(g_os_iram_softirq_end_statistic, vec_nr, time); |
| os_statistic_in_ddr(g_os_ddr_softirq_end_statistic, vec_nr, time); |
| os_statistic_info_update(); |
| } |
| |
| void zxic_trace_timer_enter(void *func) |
| { |
| unsigned long time; |
| if (!g_os_statistic_enable) |
| return ; |
| |
| time = OS_STATISTIC_TIME; |
| os_statistic_in_iram(g_os_iram_timer_start_statistic, func, time); |
| os_statistic_in_ddr(g_os_ddr_timer_start_statistic, func, time); |
| os_statistic_info_update(); |
| } |
| |
| void zxic_trace_timer_exit(void *func) |
| { |
| unsigned long time; |
| if (!g_os_statistic_enable) |
| return ; |
| |
| time = OS_STATISTIC_TIME; |
| os_statistic_in_iram(g_os_iram_timer_end_statistic, func, time); |
| os_statistic_in_ddr(g_os_ddr_timer_end_statistic, func, time); |
| os_statistic_info_update(); |
| } |
| |
| |
| /******************************************************************************* |
| * ¹¦ÄÜÃèÊö: ¹ì¼£Í³¼Æµ½DDR |
| * ²ÎÊý˵Ã÷: |
| * (´«Èë²ÎÊý) iram_addr: µØÖ· |
| data: ʼþÏî |
| time: ʱ¼ä |
| * (´«³ö²ÎÊý) void |
| * ·µ »Ø Öµ: void |
| * ÆäËü˵Ã÷: ÎÞ |
| *******************************************************************************/ |
| int __init zxic_enable_tracer(void) |
| { |
| struct timer_list timer; |
| struct task_struct *task; |
| |
| #ifdef IRAM_BASE_ADDR_VA |
| g_zxic_trace_apcpu_addr = IRAM_BASE_ADDR_OS_STATISTIC_PSCPU; |
| #else |
| g_zxic_trace_apcpu_addr = ioremap(IRAM_BASE_ADDR_OS_STATISTIC_PSCPU, IRAM_BASE_LEN_OS_STATISTIC_PSCPU); |
| #endif |
| |
| /* |
| init_timer(&timer); |
| timer.expires = jiffies + 40*HZ;//msecs_to_jiffies(40*1000);//ÑÓ³Ù40Ãë |
| timer.data = 0; |
| timer.function = os_statistic_delayed_work_timer_fn; |
| setup_timer(&timer, os_statistic_delayed_work_timer_fn, 0); |
| add_timer(&timer); |
| */ |
| //task = kthread_create(os_statistic_delayed_work_timer_fn, 0, "g_zxic_trace_sync_thread", 0); |
| //wake_up_process(task); |
| os_statistic_enable(); |
| return 0x0; |
| } |
| module_init(zxic_enable_tracer); |
| |
| |