blob: 0b5e76b2741bbaeea8a5b74c75f76b01ab616100 [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/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 <mach/iomap.h>
#ifndef CONFIG_SYSTEM_CAP
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/seq_file.h>
#endif
/*******************************************************************************
* ºê¶¨Òå *
*******************************************************************************/
#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 (8)
#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
#ifndef CONFIG_SYSTEM_CAP
#define KERNEL_L1W_IRAM_LOG_DROP (IRAM_BASE_ADDR_LOG_DROP_TRACE)
#define KERNEL_L1l_IRAM_LOG_DROP (KERNEL_L1W_IRAM_LOG_DROP + sizeof(T_LogIram_Record))
#endif
/*******************************************************************************
* Êý¾Ý½á¹¹¶¨Òå *
*******************************************************************************/
typedef volatile struct {
unsigned int enable;
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;
#ifndef CONFIG_SYSTEM_CAP
typedef struct
{
unsigned int no_lock;
unsigned int no_mem;
}T_LogIram_Record;
#endif
/*******************************************************************************
* È«¾Ö±äÁ¿ *
*******************************************************************************/
#if defined(_OS_LINUX)
static char *g_zxic_trace_apcpu_addr;
#endif
static int g_os_statistic_enable;
static unsigned int g_os_statistic_cnt;
static t_os_iram_thread_statistic *g_os_iram_swapin_statistic;
static t_os_iram_statistic *g_os_iram_irq_start_statistic;
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)
static t_os_iram_statistic *g_os_iram_softirq_start_statistic;
static t_os_iram_statistic *g_os_iram_softirq_end_statistic;
static t_os_iram_statistic *g_os_iram_timer_start_statistic;
static t_os_iram_statistic *g_os_iram_timer_end_statistic;
#endif
static t_os_ddr_statistic *g_os_ddr_swapin_statistic;
static t_os_ddr_statistic *g_os_ddr_irq_start_statistic;
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)
static t_os_ddr_statistic *g_os_ddr_softirq_start_statistic;
static t_os_ddr_statistic *g_os_ddr_softirq_end_statistic;
static t_os_ddr_statistic *g_os_ddr_timer_start_statistic;
static t_os_ddr_statistic *g_os_ddr_timer_end_statistic;
#endif
#ifndef CONFIG_SYSTEM_CAP
T_LogIram_Record *gL1w_LogMissPoint = (T_LogIram_Record *)KERNEL_L1W_IRAM_LOG_DROP;
T_LogIram_Record *gL11_LogMissPoint = (T_LogIram_Record *)KERNEL_L1l_IRAM_LOG_DROP;
#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;
msleep(10000);
sec++;
}
os_statistic_enable();
return 0;
}
/*******************************************************************************
* È«¾Öº¯ÊýʵÏÖ *
*******************************************************************************/
/*******************************************************************************
* ¹¦ÄÜÃèÊö: ¹ì¼£Í³¼Æ³õʼ»¯
* ²ÎÊý˵Ã÷:
* (´«Èë²ÎÊý) void
* (´«³ö²ÎÊý) void
* ·µ »Ø Öµ: void
* ÆäËü˵Ã÷: psºËµ÷ÓÃ
*******************************************************************************/
void os_statistic_init(void)
{
memset((void *)IRAM_BASE_ADDR_LINUX_STATISTIC, 0x0, IRAM_BASE_LEN_LINUX_STATISTIC);
}
EXPORT_SYMBOL(os_statistic_init);
/*******************************************************************************
* ¹¦ÄÜÃèÊö: ʹÄܹ켣ͳ¼Æ¹¦ÄÜ
* ²ÎÊý˵Ã÷:
* (´«Èë²ÎÊý) 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
g_os_statistic_enable = 1;
}
EXPORT_SYMBOL(os_statistic_enable);
/*******************************************************************************
* ¹¦ÄÜÃèÊö: ¹ì¼£Í³¼ÆÊ¹ÄÜ֪ͨ
* ²ÎÊý˵Ã÷:
* (´«Èë²ÎÊý) void
* (´«³ö²ÎÊý) void
* ·µ »Ø Öµ: void
* ÆäËü˵Ã÷: psºËµ÷ÓÃ
*******************************************************************************/
void os_statistic_enable_notify(void)
{
*(volatile unsigned long *)IRAM_BASE_ADDR_LINUX_STATISTIC_PSCPU = 1;
*(volatile unsigned long *)IRAM_BASE_ADDR_LINUX_STATISTIC_PHYCPU = 1;
*(volatile unsigned long *)IRAM_BASE_ADDR_LINUX_STATISTIC_APCPU = 1;
}
EXPORT_SYMBOL(os_statistic_enable_notify);
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();
}
#ifndef CONFIG_SYSTEM_CAP
/**
* kernel_log_miss_point_show - show the log miss cnt
* @m: proc file structure
* @v:
*
* Returns -errno, or 0 for success.
*/
static int kernel_log_miss_point_show(struct seq_file *m, void *v)
{
int index = 0;
T_LogIram_Record *iram = NULL;
iram = (T_LogIram_Record *)gL1w_LogMissPoint;
if (iram)
printk("kernel_log_miss_point_show iram = %x\n",iram);
else
{
printk("iram is NULL\n");
return -1;
}
seq_printf(m,"L1W phy: log miss point count is:\n");
for (; index < 2; index++)
{
if (index == 1)
seq_printf(m,"L1l phy: log miss point count is:\n");
if (iram != NULL)
{
seq_printf(m,"1. Due to allocMem fail count: %u\n", iram->no_mem);
seq_printf(m,"2. Due to multi thread conflict count: %u\n", iram->no_lock);
}
iram = (T_LogIram_Record *)gL11_LogMissPoint;
}
seq_printf(m,"done\n");
return 0;
}
/**
* cpumask_parse_user - open funution
* @inode: file inode
* @file: file descriptor
*
* Returns -errno, or 0 for success.
*/
static int kernel_log_tracker_open(struct inode *inode, struct file *file)
{
return single_open(file, kernel_log_miss_point_show, NULL);
}
/**
* kernel_log_tracker_proc_fops - proc file ops
* @open: open the registed proc file.
* @read: read the registed proc file.
* @write: write to the registed proc file.
*
* Returns -errno, or 0 for success.
*/
static const struct file_operations kernel_log_tracker_proc_fops = {
.open = kernel_log_tracker_open,
.read = seq_read,
.write = NULL
};
#endif
/*******************************************************************************
* ¹¦ÄÜÃèÊö: ¹ì¼£Í³¼Æµ½DDR
* ²ÎÊý˵Ã÷:
* (´«Èë²ÎÊý) iram_addr: µØÖ·
data: ʼþÏî
time: ʱ¼ä
* (´«³ö²ÎÊý) void
* ·µ »Ø Öµ: void
* ÆäËü˵Ã÷: ÎÞ
*******************************************************************************/
int __init zxic_enable_trace(void)
{
struct timer_list timer;
struct task_struct *task;
#ifdef IRAM_BASE_ADDR_VA
g_zxic_trace_apcpu_addr = IRAM_BASE_ADDR_LINUX_STATISTIC_APCPU;
#else
g_zxic_trace_apcpu_addr = ioremap(IRAM_BASE_ADDR_LINUX_STATISTIC_APCPU, IRAM_BASE_LEN_LINUX_STATISTIC_APCPU);
#endif
#ifndef CONFIG_SYSTEM_CAP
proc_create("kernel_log_tracker", 0, NULL, &kernel_log_tracker_proc_fops);
#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);
return 0x0;
}
module_init(zxic_enable_trace);