blob: 55ed301f2b0a0b7106093481e5c02b88a09af34d [file] [log] [blame]
#include <linux/io.h>
#include <linux/rtc.h>
#include <linux/time.h>
#include <linux/tick.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/pm_wakeup.h>
#include <linux/kernel_stat.h>
#include <mach/devices_dtb.h>
#include <mach/htc_util.h>
#include <linux/irq.h>
#include "pm.h"
#include "rpm_stats.h"
#include "htc_cpu_usage_stats.h"
#define USE_STATISTICS_STRATEGY_CONTINUOUS_3 0
#define SEND_KOBJECT_UEVENT_ENV_ENABLED 0
#define NUM_BUSY_THREAD_CHECK 5
#define HTC_KERNEL_TOP_CPU_USAGE_THRESHOLD 30
#define BUFFER_WARN_LEN 64
#define BUFFER_TEMP_LEN 32
struct process_monitor_statistic {
unsigned int pid;
char *ppid_name;
unsigned int cnt;
unsigned char set_warn;
unsigned char is_found;
#if SEND_KOBJECT_UEVENT_ENV_ENABLED
unsigned char sent_uevent;
#endif
};
static int pm_monitor_enabled = 0;
static struct workqueue_struct *htc_pm_monitor_wq = NULL;
static struct workqueue_struct *htc_kernel_top_monitor_wq = NULL;
#define MAX_PID 32768
#define NUM_BUSY_THREAD_CHECK 5
struct _htc_kernel_top {
struct delayed_work dwork;
unsigned int *prev_proc_stat;
int *curr_proc_delta;
int *curr_proc_pid;
struct task_struct **task_ptr_array;
struct kernel_cpustat curr_cpustat;
struct kernel_cpustat prev_cpustat;
unsigned long cpustat_time;
int top_loading_pid[NUM_BUSY_THREAD_CHECK];
spinlock_t lock;
};
struct st_htc_idle_statistic {
u32 count;
u32 time;
};
struct st_htc_idle_statistic htc_idle_stat[CONFIG_NR_CPUS][3];
static int msm_htc_util_delay_time = 10000;
module_param_named(kmonitor_delay, msm_htc_util_delay_time, int, S_IRUGO | S_IWUSR | S_IWGRP);
static int msm_htc_util_top_delay_time = 60000;
module_param_named(ktop_delay, msm_htc_util_top_delay_time, int, S_IRUGO | S_IWUSR | S_IWGRP);
enum {
KERNEL_TOP,
KERNEL_TOP_ACCU,
};
#if USE_STATISTICS_STRATEGY_CONTINUOUS_3
#define MAX_CONSECUTIVE_THRES_TIMES 3
#define SIZE_OF_CURR_PID_FOUND_ARRAY ARRAY_SIZE(current_pid_found_array)
#define SIZE_OF_PROCESS_MONITOR_CONTINUOUS_3_ARRAY ARRAY_SIZE(process_monitor_continuous_3_array)
struct current_pid_found {
unsigned char pid_found;
unsigned char need_to_add;
};
static struct current_pid_found current_pid_found_array[NUM_BUSY_THREAD_CHECK];
static struct process_monitor_statistic process_monitor_continuous_3_array[NUM_BUSY_THREAD_CHECK];
#else
#define MAX_OVER_THRES_TIMES 5
#define HTC_KERNEL_TOP_MONITOR_PERIOD 10
#define MAX_PROCESS_MONITOR_ARRAY_FIELDS (HTC_KERNEL_TOP_MONITOR_PERIOD * NUM_BUSY_THREAD_CHECK)
#define PROCESS_MONITOR_ARRAY_5_IN_10_SIZE MAX_PROCESS_MONITOR_ARRAY_FIELDS
#define BUFFER_WARN_5_IN_10_SIZE HTC_KERNEL_TOP_MONITOR_PERIOD
#define SIZE_OF_PROCESS_MONITOR_5_IN_10_ARRAY ARRAY_SIZE(process_monitor_5_in_10_array)
static int statistic_monitor_period = 1;
static struct process_monitor_statistic process_monitor_5_in_10_array[PROCESS_MONITOR_ARRAY_5_IN_10_SIZE];
#endif
static void clear_process_monitor_array(struct process_monitor_statistic *pArray, int array_size)
{
int j;
for (j = 0; j < array_size; j++) {
(pArray + j)->pid = 0;
(pArray + j)->ppid_name = NULL;
(pArray + j)->cnt = 0;
(pArray + j)->set_warn = 0;
(pArray + j)->is_found = 0;
#if SEND_KOBJECT_UEVENT_ENV_ENABLED
(pArray + j)->sent_uevent = 0;
#endif
}
}
#if USE_STATISTICS_STRATEGY_CONTINUOUS_3
static void clear_current_pid_found_array(void)
{
int i;
for (i = 0; i < SIZE_OF_CURR_PID_FOUND_ARRAY; i++) {
current_pid_found_array[i].pid_found = 0;
current_pid_found_array[i].need_to_add = 0;
}
}
static int htc_kernel_top_statistics_continuous_3(struct _htc_kernel_top *ktop)
{
int rtn = 0;
int i, j, cpu_usage;
#if SEND_KOBJECT_UEVENT_ENV_ENABLED
int ok_to_send_uevent = 0;
char buf_warn[SIZE_OF_PROCESS_MONITOR_CONTINUOUS_3_ARRAY * BUFFER_WARN_LEN];
char buf_temp[BUFFER_TEMP_LEN];
#endif
unsigned long delta_time = ktop->cpustat_time;
int *ptr_top_loading = ktop->top_loading_pid;
for (i = 0 ; i < SIZE_OF_CURR_PID_FOUND_ARRAY ; i++) {
cpu_usage = ktop->curr_proc_delta[*(ptr_top_loading + i)] * 100 / delta_time;
if (cpu_usage >= HTC_KERNEL_TOP_CPU_USAGE_THRESHOLD) {
for (j = 0; j < SIZE_OF_PROCESS_MONITOR_CONTINUOUS_3_ARRAY; j++) {
if (process_monitor_continuous_3_array[j].pid == *(ptr_top_loading + i)) {
process_monitor_continuous_3_array[j].cnt++;
process_monitor_continuous_3_array[j].is_found = 1;
current_pid_found_array[i].pid_found = 1;
if ((process_monitor_continuous_3_array[j].cnt >= MAX_CONSECUTIVE_THRES_TIMES) &&
(!process_monitor_continuous_3_array[j].set_warn)) {
process_monitor_continuous_3_array[j].set_warn = 1;
pr_err("[K] CPU_Sniffer: PID=[%d], name=[%s], over-cpu-usage-threshold.\n",
process_monitor_continuous_3_array[j].pid, process_monitor_continuous_3_array[j].ppid_name);
}
break;
}
}
if (!current_pid_found_array[i].pid_found) {
current_pid_found_array[i].need_to_add = 1;
}
}
}
#if SEND_KOBJECT_UEVENT_ENV_ENABLED
memset(buf_warn, 0x0, sizeof(buf_warn));
strcpy(buf_warn, "");
for (j = 0; j < SIZE_OF_PROCESS_MONITOR_CONTINUOUS_3_ARRAY; j++) {
if ((process_monitor_continuous_3_array[j].set_warn == 1) &&
(process_monitor_continuous_3_array[j].sent_uevent == 0)) {
strcat(buf_warn, "PID=");
sprintf(buf_temp, "%d", process_monitor_continuous_3_array[j].pid);
strcat(buf_warn, buf_temp);
strcat(buf_warn, ",0,0,0;");
process_monitor_continuous_3_array[j].sent_uevent = 1;
ok_to_send_uevent++;
}
}
if (ok_to_send_uevent) {
strcat(buf_warn, "PID=0,0,0,0;");
strcat(buf_warn, "#");
send_cpu_usage_stats_kobject_uevent(&buf_warn[0]);
}
#endif
for (j = 0; j < SIZE_OF_PROCESS_MONITOR_CONTINUOUS_3_ARRAY; j++) {
if (!process_monitor_continuous_3_array[j].is_found) {
process_monitor_continuous_3_array[j].pid = 0;
process_monitor_continuous_3_array[j].ppid_name = NULL;
process_monitor_continuous_3_array[j].cnt = 0;
process_monitor_continuous_3_array[j].set_warn = 0;
#if SEND_KOBJECT_UEVENT_ENV_ENABLED
process_monitor_continuous_3_array[j].sent_uevent = 0;
#endif
}
process_monitor_continuous_3_array[j].is_found = 0;
}
for (i = 0 ; i < SIZE_OF_CURR_PID_FOUND_ARRAY ; i++) {
for (j = 0; j < SIZE_OF_PROCESS_MONITOR_CONTINUOUS_3_ARRAY; j++) {
if (current_pid_found_array[i].need_to_add && !process_monitor_continuous_3_array[j].pid) {
process_monitor_continuous_3_array[j].pid = *(ptr_top_loading + i);
process_monitor_continuous_3_array[j].ppid_name = ktop->task_ptr_array[*(ptr_top_loading + i)]->comm;
process_monitor_continuous_3_array[j].cnt++;
current_pid_found_array[i].need_to_add = 0;
break;
}
}
}
clear_current_pid_found_array();
return rtn;
}
#else
static int htc_kernel_top_statistics_5_in_10(struct _htc_kernel_top *ktop)
{
int rtn = 0;
int i, j, cpu_usage;
#if SEND_KOBJECT_UEVENT_ENV_ENABLED
int ok_to_send_uevent = 0;
char buf_warn[BUFFER_WARN_5_IN_10_SIZE * BUFFER_WARN_LEN];
char buf_temp[BUFFER_TEMP_LEN];
#endif
unsigned long delta_time = ktop->cpustat_time;
int *ptr_top_loading = ktop->top_loading_pid;
for (i = 0 ; i < NUM_BUSY_THREAD_CHECK ; i++) {
cpu_usage = ktop->curr_proc_delta[*(ptr_top_loading + i)] * 100 / delta_time;
if (cpu_usage >= HTC_KERNEL_TOP_CPU_USAGE_THRESHOLD) {
for (j = 0; j < SIZE_OF_PROCESS_MONITOR_5_IN_10_ARRAY; j++) {
if (process_monitor_5_in_10_array[j].pid == *(ptr_top_loading + i)) {
process_monitor_5_in_10_array[j].cnt++;
if ((process_monitor_5_in_10_array[j].cnt >= MAX_OVER_THRES_TIMES) &&
(process_monitor_5_in_10_array[j].set_warn == 0)) {
process_monitor_5_in_10_array[j].set_warn = 1;
process_monitor_5_in_10_array[j].ppid_name =
ktop->task_ptr_array[*(ptr_top_loading + i)]->comm;
}
break;
}
else if (process_monitor_5_in_10_array[j].pid == 0) {
process_monitor_5_in_10_array[j].pid = *(ptr_top_loading + i);
process_monitor_5_in_10_array[j].cnt++;
break;
}
}
}
}
if (statistic_monitor_period < HTC_KERNEL_TOP_MONITOR_PERIOD) {
statistic_monitor_period++;
} else {
#if SEND_KOBJECT_UEVENT_ENV_ENABLED
memset(buf_warn, 0x0, sizeof(buf_warn));
strcpy(buf_warn, "");
#endif
for (j = 0; j < SIZE_OF_PROCESS_MONITOR_5_IN_10_ARRAY; j++) {
if (process_monitor_5_in_10_array[j].set_warn == 1) {
#if SEND_KOBJECT_UEVENT_ENV_ENABLED
strcat(buf_warn, "PID=");
sprintf(buf_temp, "%d", process_monitor_5_in_10_array[j].pid);
strcat(buf_warn, buf_temp);
strcat(buf_warn, ",0,0,0;");
#endif
pr_err("[K] CPU_Sniffer: PID=[%d], name=[%s], over-cpu-usage-threshold.\n",
process_monitor_5_in_10_array[j].pid, process_monitor_5_in_10_array[j].ppid_name);
#if SEND_KOBJECT_UEVENT_ENV_ENABLED
process_monitor_5_in_10_array[j].sent_uevent = 1;
ok_to_send_uevent++;
#endif
rtn = 1;
}
}
#if SEND_KOBJECT_UEVENT_ENV_ENABLED
if (ok_to_send_uevent) {
strcat(buf_warn, "PID=0,0,0,0;");
strcat(buf_warn, "#");
send_cpu_usage_stats_kobject_uevent(&buf_warn[0]);
}
#endif
if (pm_monitor_enabled)
pr_debug("[K] [KTOP] Reach the number of statistics monitor period.\n");
statistic_monitor_period = 1;
clear_process_monitor_array(&process_monitor_5_in_10_array[0], SIZE_OF_PROCESS_MONITOR_5_IN_10_ARRAY);
}
return rtn;
}
#endif
void htc_idle_stat_add(int sleep_mode, u32 time)
{
int cpu = smp_processor_id();
if (cpu < CONFIG_NR_CPUS) {
switch (sleep_mode) {
case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
htc_idle_stat[cpu][0].count++;
htc_idle_stat[cpu][0].time += time;
break;
case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
htc_idle_stat[cpu][1].count++;
htc_idle_stat[cpu][1].time += time;
break;
case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
htc_idle_stat[cpu][2].count++;
htc_idle_stat[cpu][2].time += time;
break;
default:
break;
}
}
}
static void htc_idle_stat_clear(void)
{
memset(htc_idle_stat, 0, sizeof(htc_idle_stat));
}
static void htc_xo_vddmin_stat_show(void)
{
uint32_t xo_count = 0, vddmin_count = 0;
uint64_t xo_time = 0, vddmin_time = 0;
static uint32_t prev_xo_count = 0, prev_vddmin_count = 0;
static uint64_t prev_xo_time = 0, prev_vddmin_time = 0;
if (htc_get_xo_vddmin_info(&xo_count, &xo_time, &vddmin_count, &vddmin_time)) {
if (xo_count > prev_xo_count) {
pr_info("[K] XO: %u, %llums\n", xo_count - prev_xo_count,
xo_time - prev_xo_time);
prev_xo_count = xo_count;
prev_xo_time = xo_time;
}
if (vddmin_count > prev_vddmin_count) {
pr_info("[K] Vdd-min: %u, %llums\n", vddmin_count - prev_vddmin_count,
vddmin_time - prev_vddmin_time);
prev_vddmin_count = vddmin_count;
prev_vddmin_time = vddmin_time;
}
}
}
static void htc_idle_stat_show(void)
{
int i = 0, cpu = 0;
pr_info("[K] cpu_id\tcpu_state\tidle_count\tidle_time\n");
for (cpu = 0; cpu < CONFIG_NR_CPUS; cpu++) {
for (i = 0; i < 3; i++) {
if (htc_idle_stat[cpu][i].count) {
pr_info("[K]\t%d\tC%d\t\t%d\t\t%dms\n", cpu, i,
htc_idle_stat[cpu][i].count, htc_idle_stat[cpu][i].time / 1000);
}
}
}
htc_xo_vddmin_stat_show();
msm_rpm_dump_stat();
}
#ifdef arch_idle_time
static cputime64_t get_idle_time(int cpu)
{
cputime64_t idle;
idle = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE];
if (cpu_online(cpu) && !nr_iowait_cpu(cpu))
idle += arch_idle_time(cpu);
return idle;
}
static cputime64_t get_iowait_time(int cpu)
{
cputime64_t iowait;
iowait = kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT];
if (cpu_online(cpu) && nr_iowait_cpu(cpu))
iowait += arch_idle_time(cpu);
return iowait;
}
#else
static u64 get_idle_time(int cpu)
{
u64 idle, idle_time = get_cpu_idle_time_us(cpu, NULL);
if (idle_time == -1ULL)
idle = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE];
else
idle = usecs_to_cputime64(idle_time);
return idle;
}
static u64 get_iowait_time(int cpu)
{
u64 iowait, iowait_time = get_cpu_iowait_time_us(cpu, NULL);
if (iowait_time == -1ULL)
iowait = kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT];
else
iowait = usecs_to_cputime64(iowait_time);
return iowait;
}
#endif
static void get_all_cpustat(struct kernel_cpustat *cpu_stat)
{
int cpu;
if (!cpu_stat)
return;
memset(cpu_stat, 0, sizeof(struct kernel_cpustat));
for_each_possible_cpu(cpu) {
cpu_stat->cpustat[CPUTIME_USER] += kcpustat_cpu(cpu).cpustat[CPUTIME_USER];
cpu_stat->cpustat[CPUTIME_NICE] += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE];
cpu_stat->cpustat[CPUTIME_SYSTEM] += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM];
cpu_stat->cpustat[CPUTIME_IDLE] += get_idle_time(cpu);
cpu_stat->cpustat[CPUTIME_IOWAIT] += get_iowait_time(cpu);
cpu_stat->cpustat[CPUTIME_IRQ] += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ];
cpu_stat->cpustat[CPUTIME_SOFTIRQ] += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ];
cpu_stat->cpustat[CPUTIME_STEAL] += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL];
cpu_stat->cpustat[CPUTIME_GUEST] += kcpustat_cpu(cpu).cpustat[CPUTIME_GUEST];
cpu_stat->cpustat[CPUTIME_GUEST_NICE] += kcpustat_cpu(cpu).cpustat[CPUTIME_GUEST_NICE];
}
}
static void sort_cputime_by_pid(int *source, int *pid_pos, int pid_cnt, int *result)
{
int i = 0, j = 0, k = 0, l = 0;
int pid_found = 0;
for (i = 0; i < NUM_BUSY_THREAD_CHECK; i++) {
result[i] = 0;
if (i == 0) {
for (j = 0; j < pid_cnt; j++) {
k = pid_pos[j];
if(source[result[i]] < source[k]) {
result[i] = k;
}
}
} else {
for (j = 0; j < pid_cnt; j++) {
k = pid_pos[j];
for (l = 0; l < i; l++) {
if (result[l] == k) {
pid_found = 1;
break;
}
}
if (pid_found) {
pid_found = 0;
continue;
}
if(source[result[i]] < source[k]) {
result[i] = k;
}
}
}
}
}
static unsigned long htc_calculate_cpustat_time(struct kernel_cpustat curr_cpustat,
struct kernel_cpustat prev_cpustat)
{
unsigned long user_time = 0, system_time = 0, io_time = 0;
unsigned long irq_time = 0, idle_time = 0;
user_time = (unsigned long) ((curr_cpustat.cpustat[CPUTIME_USER] +
curr_cpustat.cpustat[CPUTIME_NICE]) -
(prev_cpustat.cpustat[CPUTIME_USER] +
prev_cpustat.cpustat[CPUTIME_NICE]));
system_time = (unsigned long) (curr_cpustat.cpustat[CPUTIME_SYSTEM] -
prev_cpustat.cpustat[CPUTIME_SYSTEM]);
io_time = (unsigned long) (curr_cpustat.cpustat[CPUTIME_IOWAIT] -
prev_cpustat.cpustat[CPUTIME_IOWAIT]);
irq_time = (unsigned long) ((curr_cpustat.cpustat[CPUTIME_IRQ] +
curr_cpustat.cpustat[CPUTIME_SOFTIRQ]) -
(prev_cpustat.cpustat[CPUTIME_IRQ] +
prev_cpustat.cpustat[CPUTIME_SOFTIRQ]));
idle_time = (unsigned long) ((curr_cpustat.cpustat[CPUTIME_IDLE] > prev_cpustat.cpustat[CPUTIME_IDLE]) ?
curr_cpustat.cpustat[CPUTIME_IDLE] - prev_cpustat.cpustat[CPUTIME_IDLE] : 0);
idle_time += (unsigned long) ((curr_cpustat.cpustat[CPUTIME_STEAL] +
curr_cpustat.cpustat[CPUTIME_GUEST]) -
(prev_cpustat.cpustat[CPUTIME_STEAL] +
prev_cpustat.cpustat[CPUTIME_GUEST]));
return (user_time + system_time + io_time + irq_time + idle_time);
}
static void htc_kernel_top_cal(struct _htc_kernel_top *ktop, int type)
{
int pid_cnt = 0;
struct task_struct *process;
struct task_cputime cputime;
ulong flags;
if (ktop->task_ptr_array == NULL ||
ktop->curr_proc_delta == NULL ||
ktop->curr_proc_pid == NULL ||
ktop->prev_proc_stat == NULL)
return;
spin_lock_irqsave(&ktop->lock, flags);
for_each_process(process) {
thread_group_cputime(process, &cputime);
if (process->pid < MAX_PID) {
ktop->curr_proc_delta[process->pid] =
(cputime.utime + cputime.stime) - ktop->prev_proc_stat[process->pid];
ktop->task_ptr_array[process->pid] = process;
if (ktop->curr_proc_delta[process->pid] > 0) {
ktop->curr_proc_pid[pid_cnt] = process->pid;
pid_cnt++;
}
}
}
sort_cputime_by_pid(ktop->curr_proc_delta, ktop->curr_proc_pid, pid_cnt, ktop->top_loading_pid);
get_all_cpustat(&ktop->curr_cpustat);
ktop->cpustat_time = htc_calculate_cpustat_time(ktop->curr_cpustat, ktop->prev_cpustat);
if (type == KERNEL_TOP_ACCU) {
#if USE_STATISTICS_STRATEGY_CONTINUOUS_3
htc_kernel_top_statistics_continuous_3(ktop);
#else
htc_kernel_top_statistics_5_in_10(ktop);
#endif
}
for_each_process(process) {
if (process->pid < MAX_PID) {
thread_group_cputime(process, &cputime);
ktop->prev_proc_stat[process->pid] = cputime.stime + cputime.utime;
}
}
memcpy(&ktop->prev_cpustat, &ktop->curr_cpustat, sizeof(struct kernel_cpustat));
spin_unlock_irqrestore(&ktop->lock, flags);
}
static void htc_kernel_top_show(struct _htc_kernel_top *ktop, int type)
{
int top_n_pid = 0, i;
pr_info("[K]%sCPU Usage\t\tPID\t\tName\n", type == KERNEL_TOP_ACCU ? "[KTOP]" : " ");
for (i = 0; i < NUM_BUSY_THREAD_CHECK; i++) {
top_n_pid = ktop->top_loading_pid[i];
pr_info("[K]%s%8lu%%\t\t%d\t\t%s\t\t%d\n", type == KERNEL_TOP_ACCU ? "[KTOP]" : " ",
ktop->curr_proc_delta[top_n_pid] * 100 / ktop->cpustat_time,
top_n_pid,
ktop->task_ptr_array[top_n_pid]->comm,
ktop->curr_proc_delta[top_n_pid]);
}
memset(ktop->curr_proc_delta, 0, sizeof(int) * MAX_PID);
memset(ktop->task_ptr_array, 0, sizeof(int) * MAX_PID);
memset(ktop->curr_proc_pid, 0, sizeof(int) * MAX_PID);
}
static void htc_pm_monitor_work_func(struct work_struct *work)
{
struct _htc_kernel_top *ktop = container_of(work, struct _htc_kernel_top,
dwork.work);
struct timespec ts;
struct rtc_time tm;
if (!htc_pm_monitor_wq) {
pr_info("[K] htc_pm_monitor_wq is unavaliable.\n");
return;
}
getnstimeofday(&ts);
rtc_time_to_tm(ts.tv_sec - (sys_tz.tz_minuteswest * 60), &tm);
pr_info("[K][PM] hTC PM Statistic start (%02d-%02d %02d:%02d:%02d)\n",
tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
htc_show_interrupts();
htc_idle_stat_show();
htc_idle_stat_clear();
htc_timer_stats_onoff('0');
htc_timer_stats_show(300);
htc_timer_stats_onoff('1');
htc_print_active_wakeup_sources();
queue_delayed_work(htc_pm_monitor_wq, &ktop->dwork, msecs_to_jiffies(msm_htc_util_delay_time));
htc_kernel_top_cal(ktop, KERNEL_TOP);
htc_kernel_top_show(ktop, KERNEL_TOP);
pr_info("[K][PM] hTC PM Statistic done\n");
}
static void htc_kernel_top_accumulation_monitor_work_func(struct work_struct *work)
{
struct _htc_kernel_top *ktop = container_of(work, struct _htc_kernel_top,
dwork.work);
struct timespec ts;
struct rtc_time tm;
if (htc_kernel_top_monitor_wq == NULL){
if (pm_monitor_enabled)
printk(KERN_INFO "[K] hTc Kernel Top statistic is NULL.\n");
return;
}
getnstimeofday(&ts);
rtc_time_to_tm(ts.tv_sec - (sys_tz.tz_minuteswest * 60), &tm);
if (pm_monitor_enabled)
printk("[K][KTOP] hTC Kernel Top Statistic start (%02d-%02d %02d:%02d:%02d) \n",
tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
queue_delayed_work(htc_kernel_top_monitor_wq, &ktop->dwork, msecs_to_jiffies(msm_htc_util_top_delay_time));
htc_kernel_top_cal(ktop, KERNEL_TOP_ACCU);
htc_kernel_top_show(ktop, KERNEL_TOP_ACCU);
if (pm_monitor_enabled)
printk("[K][KTOP] hTC Kernel Top Statistic done\n");
}
void htc_monitor_init(void)
{
struct _htc_kernel_top *htc_kernel_top;
struct _htc_kernel_top *htc_kernel_top_accu;
if ((get_kernel_flag() & KERNEL_FLAG_PM_MONITOR) ||
!(get_kernel_flag() & KERNEL_FLAG_TEST_PWR_SUPPLY)) {
pm_monitor_enabled = 1;
} else
pm_monitor_enabled = 0;
if (pm_monitor_enabled) {
if (htc_pm_monitor_wq == NULL)
htc_pm_monitor_wq = create_workqueue("htc_pm_monitor_wq");
if (!htc_pm_monitor_wq)
return;
pr_info("[K] Success to create htc_pm_monitor_wq (0x%x).\n",
(unsigned int) htc_pm_monitor_wq);
htc_kernel_top = vmalloc(sizeof(*htc_kernel_top));
spin_lock_init(&htc_kernel_top->lock);
htc_kernel_top->prev_proc_stat = vmalloc(sizeof(int) * MAX_PID);
htc_kernel_top->curr_proc_delta = vmalloc(sizeof(int) * MAX_PID);
htc_kernel_top->task_ptr_array = vmalloc(sizeof(int) * MAX_PID);
htc_kernel_top->curr_proc_pid = vmalloc(sizeof(int) * MAX_PID);
memset(htc_kernel_top->prev_proc_stat, 0, sizeof(int) * MAX_PID);
memset(htc_kernel_top->curr_proc_delta, 0, sizeof(int) * MAX_PID);
memset(htc_kernel_top->task_ptr_array, 0, sizeof(int) * MAX_PID);
memset(htc_kernel_top->curr_proc_pid, 0, sizeof(int) * MAX_PID);
get_all_cpustat(&htc_kernel_top->curr_cpustat);
get_all_cpustat(&htc_kernel_top->prev_cpustat);
INIT_DELAYED_WORK(&htc_kernel_top->dwork, htc_pm_monitor_work_func);
queue_delayed_work(htc_pm_monitor_wq, &htc_kernel_top->dwork,
msecs_to_jiffies(msm_htc_util_delay_time));
}
if (htc_kernel_top_monitor_wq == NULL) {
htc_kernel_top_monitor_wq = create_workqueue("htc_kernel_top_monitor_wq");
printk(KERN_INFO "[K][KTOP] Create HTC private workqueue(0x%x)...\n",
(unsigned int)htc_kernel_top_monitor_wq);
}
if (!htc_kernel_top_monitor_wq)
return;
printk(KERN_INFO "[K][KTOP] Success to create htc_kernel_top_monitor_wq (0x%x).\n",
(unsigned int)htc_kernel_top_monitor_wq);
#if USE_STATISTICS_STRATEGY_CONTINUOUS_3
clear_current_pid_found_array();
clear_process_monitor_array(&process_monitor_continuous_3_array[0],
SIZE_OF_PROCESS_MONITOR_CONTINUOUS_3_ARRAY);
#else
clear_process_monitor_array(&process_monitor_5_in_10_array[0],
SIZE_OF_PROCESS_MONITOR_5_IN_10_ARRAY);
#endif
htc_kernel_top_accu = vmalloc(sizeof(*htc_kernel_top_accu));
spin_lock_init(&htc_kernel_top_accu->lock);
htc_kernel_top_accu->prev_proc_stat = vmalloc(sizeof(int) * MAX_PID);
htc_kernel_top_accu->curr_proc_delta = vmalloc(sizeof(int) * MAX_PID);
htc_kernel_top_accu->task_ptr_array = vmalloc(sizeof(int) * MAX_PID);
htc_kernel_top_accu->curr_proc_pid = vmalloc(sizeof(int) * MAX_PID);
memset(htc_kernel_top_accu->prev_proc_stat, 0, sizeof(int) * MAX_PID);
memset(htc_kernel_top_accu->curr_proc_delta, 0, sizeof(int) * MAX_PID);
memset(htc_kernel_top_accu->task_ptr_array, 0, sizeof(int) * MAX_PID);
memset(htc_kernel_top_accu->curr_proc_pid, 0, sizeof(int) * MAX_PID);
get_all_cpustat(&htc_kernel_top_accu->curr_cpustat);
get_all_cpustat(&htc_kernel_top_accu->prev_cpustat);
INIT_DELAYED_WORK(&htc_kernel_top_accu->dwork,
htc_kernel_top_accumulation_monitor_work_func);
queue_delayed_work(htc_kernel_top_monitor_wq, &htc_kernel_top_accu->dwork,
msecs_to_jiffies(msm_htc_util_top_delay_time));
}