Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e44f87c4 authored by Sudarshan Rajagopalan's avatar Sudarshan Rajagopalan
Browse files

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: default avatarSudarshan Rajagopalan <sudaraja@codeaurora.org>
parent 19a5a7fa
Loading
Loading
Loading
Loading
+172 −43
Original line number Diff line number Diff line
@@ -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,
		for (i = 0; i <= tot_blks; i++)
			c += scnprintf(buf + c, sz - c,
				"%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,
		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,
		for (i = 0; i <= tot_blks; i++)
			c += scnprintf(buf + c, sz - c,
				"%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,
		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,
		for (i = 0; i <= tot_blks; i++)
			c += scnprintf(buf + c, sz - c,
				"%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,
		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,
		for (i = 0; i <= tot_blks; i++)
			c += scnprintf(buf + c, sz - c,
				"%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,
		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,
		for (i = 0; i <= tot_blks; i++)
			c += scnprintf(buf + c, sz - c,
				"%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 =
		__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;