Loading drivers/soc/qcom/mem-offline.c +172 −43 Original line number Original line Diff line number Diff line Loading @@ -29,7 +29,6 @@ static struct kobject *kobj; static unsigned int sections_per_block; static unsigned int sections_per_block; static u32 offline_granule; static u32 offline_granule; #define MODULE_CLASS_NAME "mem-offline" #define MODULE_CLASS_NAME "mem-offline" #define BUF_LEN 100 struct section_stat { struct section_stat { unsigned long success_count; unsigned long success_count; Loading @@ -39,6 +38,8 @@ struct section_stat { unsigned long worst_time; unsigned long worst_time; unsigned long total_time; unsigned long total_time; unsigned long last_recorded_time; unsigned long last_recorded_time; ktime_t resident_time; ktime_t resident_since; }; }; enum memory_states { enum memory_states { Loading Loading @@ -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 total_sec = end_section_nr - start_section_nr + 1; unsigned int blk_nr = (sec - start_section_nr + mode * total_sec) / unsigned int blk_nr = (sec - start_section_nr + mode * total_sec) / sections_per_block; sections_per_block; ktime_t now, delta; if (sec > end_section_nr) if (sec > end_section_nr) return; return; Loading @@ -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].total_time / mem_info[blk_nr].success_count; mem_info[blk_nr].last_recorded_time = delay; 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) static int aop_send_msg(unsigned long addr, bool online) Loading Loading @@ -434,75 +448,184 @@ static int mem_online_remaining_blocks(void) static ssize_t show_mem_offline_granule(struct kobject *kobj, static ssize_t show_mem_offline_granule(struct kobject *kobj, struct kobj_attribute *attr, char *buf) struct kobj_attribute *attr, char *buf) { { return snprintf(buf, BUF_LEN, "%lu\n", (unsigned long)offline_granule * return scnprintf(buf, PAGE_SIZE, "%lu\n", SZ_1M); (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) struct kobj_attribute *attr, char *buf) { { unsigned int blk_start = start_section_nr / sections_per_block; unsigned int blk_start = start_section_nr / sections_per_block; unsigned int blk_end = end_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 tot_blks = blk_end - blk_start; unsigned int char_count = 0; ktime_t *total_time; unsigned int idx = tot_blks + 1; unsigned int c = 0; unsigned int i, j; 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++) { 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"); "\n\t%s\n\t\t\t", j == 0 ? "ONLINE" : "OFFLINE"); for (i = blk_start; i <= blk_end; i++) 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); "%s%d\t\t", "mem", i); char_count += snprintf(buf + char_count, BUF_LEN, "\n"); c += scnprintf(buf + c, sz - c, "\n"); char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "\tLast recd time:\t"); "\tLast recd time:\t"); for (i = 0; i <= blk_end - blk_start; i++) for (i = 0; i <= tot_blks; i++) char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "%lums\t\t", "%lums\t\t", mem_info[i+j*idx].last_recorded_time); mem_info[i + j * idx].last_recorded_time); char_count += snprintf(buf + char_count, BUF_LEN, "\n"); c += scnprintf(buf + c, sz - c, "\n"); char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "\tAvg time:\t"); "\tAvg time:\t"); for (i = 0; i <= blk_end - blk_start; i++) for (i = 0; i <= tot_blks; i++) char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "%lums\t\t", mem_info[i + j * idx].avg_time); "%lums\t\t", mem_info[i + j * idx].avg_time); char_count += snprintf(buf + char_count, BUF_LEN, "\n"); c += scnprintf(buf + c, sz - c, "\n"); char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "\tBest time:\t"); "\tBest time:\t"); for (i = 0; i <= blk_end - blk_start; i++) for (i = 0; i <= tot_blks; i++) char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "%lums\t\t", mem_info[i + j * idx].best_time); "%lums\t\t", mem_info[i + j * idx].best_time); char_count += snprintf(buf + char_count, BUF_LEN, "\n"); c += scnprintf(buf + c, sz - c, "\n"); char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "\tWorst time:\t"); "\tWorst time:\t"); for (i = 0; i <= blk_end - blk_start; i++) for (i = 0; i <= tot_blks; i++) char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "%lums\t\t", mem_info[i + j * idx].worst_time); "%lums\t\t", mem_info[i + j * idx].worst_time); char_count += snprintf(buf + char_count, BUF_LEN, "\n"); c += scnprintf(buf + c, sz - c, "\n"); char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "\tSuccess count:\t"); "\tSuccess count:\t"); for (i = 0; i <= blk_end - blk_start; i++) for (i = 0; i <= tot_blks; i++) char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "%lu\t\t", mem_info[i + j * idx].success_count); "%lu\t\t", mem_info[i + j * idx].success_count); char_count += snprintf(buf + char_count, BUF_LEN, "\n"); c += scnprintf(buf + c, sz - c, "\n"); char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "\tFail count:\t"); "\tFail count:\t"); for (i = 0; i <= blk_end - blk_start; i++) for (i = 0; i <= tot_blks; i++) char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "%lu\t\t", mem_info[i + j * idx].fail_count); "%lu\t\t", mem_info[i + j * idx].fail_count); char_count += snprintf(buf + char_count, BUF_LEN, "\n"); c += scnprintf(buf + c, sz - c, "\n"); } 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"); } } return char_count; 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 = static struct kobj_attribute stats_attr = __ATTR(perf_stats, 0444, show_mem_perf_stats, NULL); __ATTR(stats, 0444, show_mem_stats, NULL); static struct kobj_attribute offline_granule_attr = static struct kobj_attribute offline_granule_attr = __ATTR(offline_granule, 0444, show_mem_offline_granule, NULL); __ATTR(offline_granule, 0444, show_mem_offline_granule, NULL); static struct attribute *mem_root_attrs[] = { static struct attribute *mem_root_attrs[] = { &perf_stats_attr.attr, &stats_attr.attr, &offline_granule_attr.attr, &offline_granule_attr.attr, NULL, NULL, }; }; Loading Loading @@ -573,6 +696,7 @@ static int mem_offline_driver_probe(struct platform_device *pdev) { { unsigned int total_blks; unsigned int total_blks; int ret, i; int ret, i; ktime_t now; ret = mem_parse_dt(pdev); ret = mem_parse_dt(pdev); if (ret) if (ret) Loading @@ -592,6 +716,11 @@ static int mem_offline_driver_probe(struct platform_device *pdev) if (!mem_info) if (!mem_info) return -ENOMEM; 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); mem_sec_state = kcalloc(total_blks, sizeof(*mem_sec_state), GFP_KERNEL); if (!mem_sec_state) { if (!mem_sec_state) { ret = -ENOMEM; ret = -ENOMEM; Loading Loading
drivers/soc/qcom/mem-offline.c +172 −43 Original line number Original line Diff line number Diff line Loading @@ -29,7 +29,6 @@ static struct kobject *kobj; static unsigned int sections_per_block; static unsigned int sections_per_block; static u32 offline_granule; static u32 offline_granule; #define MODULE_CLASS_NAME "mem-offline" #define MODULE_CLASS_NAME "mem-offline" #define BUF_LEN 100 struct section_stat { struct section_stat { unsigned long success_count; unsigned long success_count; Loading @@ -39,6 +38,8 @@ struct section_stat { unsigned long worst_time; unsigned long worst_time; unsigned long total_time; unsigned long total_time; unsigned long last_recorded_time; unsigned long last_recorded_time; ktime_t resident_time; ktime_t resident_since; }; }; enum memory_states { enum memory_states { Loading Loading @@ -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 total_sec = end_section_nr - start_section_nr + 1; unsigned int blk_nr = (sec - start_section_nr + mode * total_sec) / unsigned int blk_nr = (sec - start_section_nr + mode * total_sec) / sections_per_block; sections_per_block; ktime_t now, delta; if (sec > end_section_nr) if (sec > end_section_nr) return; return; Loading @@ -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].total_time / mem_info[blk_nr].success_count; mem_info[blk_nr].last_recorded_time = delay; 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) static int aop_send_msg(unsigned long addr, bool online) Loading Loading @@ -434,75 +448,184 @@ static int mem_online_remaining_blocks(void) static ssize_t show_mem_offline_granule(struct kobject *kobj, static ssize_t show_mem_offline_granule(struct kobject *kobj, struct kobj_attribute *attr, char *buf) struct kobj_attribute *attr, char *buf) { { return snprintf(buf, BUF_LEN, "%lu\n", (unsigned long)offline_granule * return scnprintf(buf, PAGE_SIZE, "%lu\n", SZ_1M); (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) struct kobj_attribute *attr, char *buf) { { unsigned int blk_start = start_section_nr / sections_per_block; unsigned int blk_start = start_section_nr / sections_per_block; unsigned int blk_end = end_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 tot_blks = blk_end - blk_start; unsigned int char_count = 0; ktime_t *total_time; unsigned int idx = tot_blks + 1; unsigned int c = 0; unsigned int i, j; 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++) { 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"); "\n\t%s\n\t\t\t", j == 0 ? "ONLINE" : "OFFLINE"); for (i = blk_start; i <= blk_end; i++) 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); "%s%d\t\t", "mem", i); char_count += snprintf(buf + char_count, BUF_LEN, "\n"); c += scnprintf(buf + c, sz - c, "\n"); char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "\tLast recd time:\t"); "\tLast recd time:\t"); for (i = 0; i <= blk_end - blk_start; i++) for (i = 0; i <= tot_blks; i++) char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "%lums\t\t", "%lums\t\t", mem_info[i+j*idx].last_recorded_time); mem_info[i + j * idx].last_recorded_time); char_count += snprintf(buf + char_count, BUF_LEN, "\n"); c += scnprintf(buf + c, sz - c, "\n"); char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "\tAvg time:\t"); "\tAvg time:\t"); for (i = 0; i <= blk_end - blk_start; i++) for (i = 0; i <= tot_blks; i++) char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "%lums\t\t", mem_info[i + j * idx].avg_time); "%lums\t\t", mem_info[i + j * idx].avg_time); char_count += snprintf(buf + char_count, BUF_LEN, "\n"); c += scnprintf(buf + c, sz - c, "\n"); char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "\tBest time:\t"); "\tBest time:\t"); for (i = 0; i <= blk_end - blk_start; i++) for (i = 0; i <= tot_blks; i++) char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "%lums\t\t", mem_info[i + j * idx].best_time); "%lums\t\t", mem_info[i + j * idx].best_time); char_count += snprintf(buf + char_count, BUF_LEN, "\n"); c += scnprintf(buf + c, sz - c, "\n"); char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "\tWorst time:\t"); "\tWorst time:\t"); for (i = 0; i <= blk_end - blk_start; i++) for (i = 0; i <= tot_blks; i++) char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "%lums\t\t", mem_info[i + j * idx].worst_time); "%lums\t\t", mem_info[i + j * idx].worst_time); char_count += snprintf(buf + char_count, BUF_LEN, "\n"); c += scnprintf(buf + c, sz - c, "\n"); char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "\tSuccess count:\t"); "\tSuccess count:\t"); for (i = 0; i <= blk_end - blk_start; i++) for (i = 0; i <= tot_blks; i++) char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "%lu\t\t", mem_info[i + j * idx].success_count); "%lu\t\t", mem_info[i + j * idx].success_count); char_count += snprintf(buf + char_count, BUF_LEN, "\n"); c += scnprintf(buf + c, sz - c, "\n"); char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "\tFail count:\t"); "\tFail count:\t"); for (i = 0; i <= blk_end - blk_start; i++) for (i = 0; i <= tot_blks; i++) char_count += snprintf(buf + char_count, BUF_LEN, c += scnprintf(buf + c, sz - c, "%lu\t\t", mem_info[i + j * idx].fail_count); "%lu\t\t", mem_info[i + j * idx].fail_count); char_count += snprintf(buf + char_count, BUF_LEN, "\n"); c += scnprintf(buf + c, sz - c, "\n"); } 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"); } } return char_count; 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 = static struct kobj_attribute stats_attr = __ATTR(perf_stats, 0444, show_mem_perf_stats, NULL); __ATTR(stats, 0444, show_mem_stats, NULL); static struct kobj_attribute offline_granule_attr = static struct kobj_attribute offline_granule_attr = __ATTR(offline_granule, 0444, show_mem_offline_granule, NULL); __ATTR(offline_granule, 0444, show_mem_offline_granule, NULL); static struct attribute *mem_root_attrs[] = { static struct attribute *mem_root_attrs[] = { &perf_stats_attr.attr, &stats_attr.attr, &offline_granule_attr.attr, &offline_granule_attr.attr, NULL, NULL, }; }; Loading Loading @@ -573,6 +696,7 @@ static int mem_offline_driver_probe(struct platform_device *pdev) { { unsigned int total_blks; unsigned int total_blks; int ret, i; int ret, i; ktime_t now; ret = mem_parse_dt(pdev); ret = mem_parse_dt(pdev); if (ret) if (ret) Loading @@ -592,6 +716,11 @@ static int mem_offline_driver_probe(struct platform_device *pdev) if (!mem_info) if (!mem_info) return -ENOMEM; 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); mem_sec_state = kcalloc(total_blks, sizeof(*mem_sec_state), GFP_KERNEL); if (!mem_sec_state) { if (!mem_sec_state) { ret = -ENOMEM; ret = -ENOMEM; Loading