mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-13 00:00:00 -04:00
soc: qcom: mem-offline: log additional time stats
With active-mode memory offlining, it would be helpful to track the
total Online and Offline times of each blocks and determine percentage
of time they have been in that state.
This patch adds the below additional stats:
- current state of each blocks.
- total Online and Offline time of each blocks.
- percentage of total system runtime that blocks were in Online
and Offline state.
- total overall percentage of time all blocks were in Online
and Offline state.
Also, change the sysfs node from 'perf_stats' to 'stats'.
Change-Id: Ie18ad68194df8c7702dc496821c4f680d15486ce
Signed-off-by: Sudarshan Rajagopalan <sudaraja@codeaurora.org>
This commit is contained in:
parent
19a5a7fa3b
commit
e44f87c449
1 changed files with 172 additions and 43 deletions
|
|
@ -29,7 +29,6 @@ static struct kobject *kobj;
|
|||
static unsigned int sections_per_block;
|
||||
static u32 offline_granule;
|
||||
#define MODULE_CLASS_NAME "mem-offline"
|
||||
#define BUF_LEN 100
|
||||
|
||||
struct section_stat {
|
||||
unsigned long success_count;
|
||||
|
|
@ -39,6 +38,8 @@ struct section_stat {
|
|||
unsigned long worst_time;
|
||||
unsigned long total_time;
|
||||
unsigned long last_recorded_time;
|
||||
ktime_t resident_time;
|
||||
ktime_t resident_since;
|
||||
};
|
||||
|
||||
enum memory_states {
|
||||
|
|
@ -115,6 +116,7 @@ static void record_stat(unsigned long sec, ktime_t delay, int mode)
|
|||
unsigned int total_sec = end_section_nr - start_section_nr + 1;
|
||||
unsigned int blk_nr = (sec - start_section_nr + mode * total_sec) /
|
||||
sections_per_block;
|
||||
ktime_t now, delta;
|
||||
|
||||
if (sec > end_section_nr)
|
||||
return;
|
||||
|
|
@ -135,6 +137,18 @@ static void record_stat(unsigned long sec, ktime_t delay, int mode)
|
|||
mem_info[blk_nr].total_time / mem_info[blk_nr].success_count;
|
||||
|
||||
mem_info[blk_nr].last_recorded_time = delay;
|
||||
|
||||
now = ktime_get();
|
||||
mem_info[blk_nr].resident_since = now;
|
||||
|
||||
/* since other state has gone inactive, update the stats */
|
||||
mode = mode ? MEMORY_ONLINE : MEMORY_OFFLINE;
|
||||
blk_nr = (sec - start_section_nr + mode * total_sec) /
|
||||
sections_per_block;
|
||||
delta = ktime_sub(now, mem_info[blk_nr].resident_since);
|
||||
mem_info[blk_nr].resident_time =
|
||||
ktime_add(mem_info[blk_nr].resident_time, delta);
|
||||
mem_info[blk_nr].resident_since = 0;
|
||||
}
|
||||
|
||||
static int aop_send_msg(unsigned long addr, bool online)
|
||||
|
|
@ -434,75 +448,184 @@ static int mem_online_remaining_blocks(void)
|
|||
static ssize_t show_mem_offline_granule(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
return snprintf(buf, BUF_LEN, "%lu\n", (unsigned long)offline_granule *
|
||||
SZ_1M);
|
||||
return scnprintf(buf, PAGE_SIZE, "%lu\n",
|
||||
(unsigned long)offline_granule * SZ_1M);
|
||||
}
|
||||
|
||||
static ssize_t show_mem_perf_stats(struct kobject *kobj,
|
||||
|
||||
static unsigned int print_blk_residency_percentage(char *buf, size_t sz,
|
||||
unsigned int tot_blks, ktime_t *total_time,
|
||||
enum memory_states mode)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int c = 0;
|
||||
int percent;
|
||||
unsigned int idx = tot_blks + 1;
|
||||
|
||||
for (i = 0; i <= tot_blks; i++) {
|
||||
percent = (int)ktime_divns(total_time[i + mode * idx] * 100,
|
||||
ktime_add(total_time[i + MEMORY_ONLINE * idx],
|
||||
total_time[i + MEMORY_OFFLINE * idx]));
|
||||
|
||||
c += scnprintf(buf + c, sz - c, "%d%%\t\t", percent);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
static unsigned int print_blk_residency_times(char *buf, size_t sz,
|
||||
unsigned int tot_blks, ktime_t *total_time,
|
||||
enum memory_states mode)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int c = 0;
|
||||
ktime_t now, delta;
|
||||
unsigned int idx = tot_blks + 1;
|
||||
|
||||
now = ktime_get();
|
||||
for (i = 0; i <= tot_blks; i++) {
|
||||
if (mem_sec_state[i] == mode)
|
||||
delta = ktime_sub(now,
|
||||
mem_info[i + mode * idx].resident_since);
|
||||
else
|
||||
delta = 0;
|
||||
delta = ktime_add(delta,
|
||||
mem_info[i + mode * idx].resident_time);
|
||||
c += scnprintf(buf + c, sz - c, "%lus\t\t",
|
||||
ktime_to_ms(delta) / MSEC_PER_SEC);
|
||||
total_time[i + mode * idx] = delta;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static ssize_t show_mem_stats(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
|
||||
unsigned int blk_start = start_section_nr / sections_per_block;
|
||||
unsigned int blk_end = end_section_nr / sections_per_block;
|
||||
unsigned int idx = blk_end - blk_start + 1;
|
||||
unsigned int char_count = 0;
|
||||
unsigned int tot_blks = blk_end - blk_start;
|
||||
ktime_t *total_time;
|
||||
unsigned int idx = tot_blks + 1;
|
||||
unsigned int c = 0;
|
||||
unsigned int i, j;
|
||||
|
||||
size_t sz = PAGE_SIZE;
|
||||
ktime_t total = 0, total_online = 0, total_offline = 0;
|
||||
|
||||
total_time = kcalloc(idx * MAX_STATE, sizeof(*total_time), GFP_KERNEL);
|
||||
|
||||
if (!total_time)
|
||||
return -ENOMEM;
|
||||
|
||||
for (j = 0; j < MAX_STATE; j++) {
|
||||
char_count += snprintf(buf + char_count, BUF_LEN,
|
||||
c += scnprintf(buf + c, sz - c,
|
||||
"\n\t%s\n\t\t\t", j == 0 ? "ONLINE" : "OFFLINE");
|
||||
for (i = blk_start; i <= blk_end; i++)
|
||||
char_count += snprintf(buf + char_count, BUF_LEN,
|
||||
c += scnprintf(buf + c, sz - c,
|
||||
"%s%d\t\t", "mem", i);
|
||||
char_count += snprintf(buf + char_count, BUF_LEN, "\n");
|
||||
char_count += snprintf(buf + char_count, BUF_LEN,
|
||||
c += scnprintf(buf + c, sz - c, "\n");
|
||||
c += scnprintf(buf + c, sz - c,
|
||||
"\tLast recd time:\t");
|
||||
for (i = 0; i <= blk_end - blk_start; i++)
|
||||
char_count += snprintf(buf + char_count, BUF_LEN,
|
||||
"%lums\t\t", mem_info[i+j*idx].last_recorded_time);
|
||||
char_count += snprintf(buf + char_count, BUF_LEN, "\n");
|
||||
char_count += snprintf(buf + char_count, BUF_LEN,
|
||||
for (i = 0; i <= tot_blks; i++)
|
||||
c += scnprintf(buf + c, sz - c, "%lums\t\t",
|
||||
mem_info[i + j * idx].last_recorded_time);
|
||||
c += scnprintf(buf + c, sz - c, "\n");
|
||||
c += scnprintf(buf + c, sz - c,
|
||||
"\tAvg time:\t");
|
||||
for (i = 0; i <= blk_end - blk_start; i++)
|
||||
char_count += snprintf(buf + char_count, BUF_LEN,
|
||||
"%lums\t\t", mem_info[i+j*idx].avg_time);
|
||||
char_count += snprintf(buf + char_count, BUF_LEN, "\n");
|
||||
char_count += snprintf(buf + char_count, BUF_LEN,
|
||||
for (i = 0; i <= tot_blks; i++)
|
||||
c += scnprintf(buf + c, sz - c,
|
||||
"%lums\t\t", mem_info[i + j * idx].avg_time);
|
||||
c += scnprintf(buf + c, sz - c, "\n");
|
||||
c += scnprintf(buf + c, sz - c,
|
||||
"\tBest time:\t");
|
||||
for (i = 0; i <= blk_end - blk_start; i++)
|
||||
char_count += snprintf(buf + char_count, BUF_LEN,
|
||||
"%lums\t\t", mem_info[i+j*idx].best_time);
|
||||
char_count += snprintf(buf + char_count, BUF_LEN, "\n");
|
||||
char_count += snprintf(buf + char_count, BUF_LEN,
|
||||
for (i = 0; i <= tot_blks; i++)
|
||||
c += scnprintf(buf + c, sz - c,
|
||||
"%lums\t\t", mem_info[i + j * idx].best_time);
|
||||
c += scnprintf(buf + c, sz - c, "\n");
|
||||
c += scnprintf(buf + c, sz - c,
|
||||
"\tWorst time:\t");
|
||||
for (i = 0; i <= blk_end - blk_start; i++)
|
||||
char_count += snprintf(buf + char_count, BUF_LEN,
|
||||
"%lums\t\t", mem_info[i+j*idx].worst_time);
|
||||
char_count += snprintf(buf + char_count, BUF_LEN, "\n");
|
||||
char_count += snprintf(buf + char_count, BUF_LEN,
|
||||
for (i = 0; i <= tot_blks; i++)
|
||||
c += scnprintf(buf + c, sz - c,
|
||||
"%lums\t\t", mem_info[i + j * idx].worst_time);
|
||||
c += scnprintf(buf + c, sz - c, "\n");
|
||||
c += scnprintf(buf + c, sz - c,
|
||||
"\tSuccess count:\t");
|
||||
for (i = 0; i <= blk_end - blk_start; i++)
|
||||
char_count += snprintf(buf + char_count, BUF_LEN,
|
||||
"%lu\t\t", mem_info[i+j*idx].success_count);
|
||||
char_count += snprintf(buf + char_count, BUF_LEN, "\n");
|
||||
char_count += snprintf(buf + char_count, BUF_LEN,
|
||||
for (i = 0; i <= tot_blks; i++)
|
||||
c += scnprintf(buf + c, sz - c,
|
||||
"%lu\t\t", mem_info[i + j * idx].success_count);
|
||||
c += scnprintf(buf + c, sz - c, "\n");
|
||||
c += scnprintf(buf + c, sz - c,
|
||||
"\tFail count:\t");
|
||||
for (i = 0; i <= blk_end - blk_start; i++)
|
||||
char_count += snprintf(buf + char_count, BUF_LEN,
|
||||
"%lu\t\t", mem_info[i+j*idx].fail_count);
|
||||
char_count += snprintf(buf + char_count, BUF_LEN, "\n");
|
||||
for (i = 0; i <= tot_blks; i++)
|
||||
c += scnprintf(buf + c, sz - c,
|
||||
"%lu\t\t", mem_info[i + j * idx].fail_count);
|
||||
c += scnprintf(buf + c, sz - c, "\n");
|
||||
}
|
||||
return char_count;
|
||||
|
||||
c += scnprintf(buf + c, sz - c, "\n");
|
||||
c += scnprintf(buf + c, sz - c, "\tState:\t\t");
|
||||
for (i = 0; i <= tot_blks; i++) {
|
||||
c += scnprintf(buf + c, sz - c, "%s\t\t",
|
||||
mem_sec_state[i] == MEMORY_ONLINE ?
|
||||
"Online" : "Offline");
|
||||
}
|
||||
c += scnprintf(buf + c, sz - c, "\n");
|
||||
|
||||
c += scnprintf(buf + c, sz - c, "\n");
|
||||
c += scnprintf(buf + c, sz - c, "\tOnline time:\t");
|
||||
c += print_blk_residency_times(buf + c, sz - c,
|
||||
tot_blks, total_time, MEMORY_ONLINE);
|
||||
|
||||
|
||||
c += scnprintf(buf + c, sz - c, "\n");
|
||||
c += scnprintf(buf + c, sz - c, "\tOffline time:\t");
|
||||
c += print_blk_residency_times(buf + c, sz - c,
|
||||
tot_blks, total_time, MEMORY_OFFLINE);
|
||||
|
||||
c += scnprintf(buf + c, sz, "\n");
|
||||
|
||||
c += scnprintf(buf + c, sz, "\n");
|
||||
c += scnprintf(buf + c, sz, "\tOnline %%:\t");
|
||||
c += print_blk_residency_percentage(buf + c, sz - c,
|
||||
tot_blks, total_time, MEMORY_ONLINE);
|
||||
|
||||
c += scnprintf(buf + c, sz, "\n");
|
||||
c += scnprintf(buf + c, sz, "\tOffline %%:\t");
|
||||
c += print_blk_residency_percentage(buf + c, sz - c,
|
||||
tot_blks, total_time, MEMORY_OFFLINE);
|
||||
c += scnprintf(buf + c, sz, "\n");
|
||||
c += scnprintf(buf + c, sz, "\n");
|
||||
|
||||
for (i = 0; i <= tot_blks; i++)
|
||||
total = ktime_add(total,
|
||||
ktime_add(total_time[i + MEMORY_ONLINE * idx],
|
||||
total_time[i + MEMORY_OFFLINE * idx]));
|
||||
|
||||
for (i = 0; i <= tot_blks; i++)
|
||||
total_online = ktime_add(total_online,
|
||||
total_time[i + MEMORY_ONLINE * idx]);
|
||||
|
||||
total_offline = ktime_sub(total, total_online);
|
||||
|
||||
c += scnprintf(buf + c, sz,
|
||||
"\tAvg Online %%:\t%d%%\n",
|
||||
((int)total_online * 100) / total);
|
||||
c += scnprintf(buf + c, sz,
|
||||
"\tAvg Offline %%:\t%d%%\n",
|
||||
((int)total_offline * 100) / total);
|
||||
|
||||
c += scnprintf(buf + c, sz, "\n");
|
||||
kfree(total_time);
|
||||
return c;
|
||||
}
|
||||
|
||||
static struct kobj_attribute perf_stats_attr =
|
||||
__ATTR(perf_stats, 0444, show_mem_perf_stats, NULL);
|
||||
static struct kobj_attribute stats_attr =
|
||||
__ATTR(stats, 0444, show_mem_stats, NULL);
|
||||
|
||||
static struct kobj_attribute offline_granule_attr =
|
||||
__ATTR(offline_granule, 0444, show_mem_offline_granule, NULL);
|
||||
|
||||
static struct attribute *mem_root_attrs[] = {
|
||||
&perf_stats_attr.attr,
|
||||
&stats_attr.attr,
|
||||
&offline_granule_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
|
@ -573,6 +696,7 @@ static int mem_offline_driver_probe(struct platform_device *pdev)
|
|||
{
|
||||
unsigned int total_blks;
|
||||
int ret, i;
|
||||
ktime_t now;
|
||||
|
||||
ret = mem_parse_dt(pdev);
|
||||
if (ret)
|
||||
|
|
@ -592,6 +716,11 @@ static int mem_offline_driver_probe(struct platform_device *pdev)
|
|||
if (!mem_info)
|
||||
return -ENOMEM;
|
||||
|
||||
/* record time of online for all blocks */
|
||||
now = ktime_get();
|
||||
for (i = 0; i < total_blks; i++)
|
||||
mem_info[i].resident_since = now;
|
||||
|
||||
mem_sec_state = kcalloc(total_blks, sizeof(*mem_sec_state), GFP_KERNEL);
|
||||
if (!mem_sec_state) {
|
||||
ret = -ENOMEM;
|
||||
|
|
|
|||
Loading…
Reference in a new issue