blob: 6f7e1ab1e9e6b5e94c3a7cd95a46b6dd4a4d1a10 [file] [log] [blame]
/*
* 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);