[PATCH v2] thermal/core: Make trans_table tunnable to avoid some needless zero output

Junwen Wu posted 1 patch 1 week, 2 days ago
drivers/thermal/thermal_sysfs.c | 111 +++++++++++++++++++++++++-------
1 file changed, 86 insertions(+), 25 deletions(-)
[PATCH v2] thermal/core: Make trans_table tunnable to avoid some needless zero output
Posted by Junwen Wu 1 week, 2 days ago
Very high cooling device max state value make trans_table node
prompt File too large. We introduce show_state node, tunnable
by user,thus trans_table only show show_state'th trans count to
the max trans count, in this way trans_table_show's buffer is
always less than PAGE_SIZE and shows the important changes.

Signed-off-by: Junwen Wu <wudaemon@163.com>
---
 drivers/thermal/thermal_sysfs.c | 111 +++++++++++++++++++++++++-------
 1 file changed, 86 insertions(+), 25 deletions(-)

diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
index f154bada2906..bb8627aa49b7 100644
--- a/drivers/thermal/thermal_sysfs.c
+++ b/drivers/thermal/thermal_sysfs.c
@@ -656,6 +656,7 @@ struct cooling_dev_stats {
 	spinlock_t lock;
 	unsigned int total_trans;
 	unsigned long state;
+	unsigned long show_state;
 	unsigned long max_states;
 	ktime_t last_time;
 	ktime_t *time_in_state;
@@ -752,38 +753,93 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf,
 	return count;
 }
 
-static ssize_t trans_table_show(struct device *dev,
-				struct device_attribute *attr, char *buf)
+static ssize_t
+show_state_store(struct device *dev, struct device_attribute *attr, const char *buf,
+		size_t count)
 {
 	struct thermal_cooling_device *cdev = to_cooling_device(dev);
 	struct cooling_dev_stats *stats = cdev->stats;
-	ssize_t len = 0;
-	int i, j;
+	unsigned long state;
+	ssize_t ret;
 
-	len += snprintf(buf + len, PAGE_SIZE - len, " From  :    To\n");
-	len += snprintf(buf + len, PAGE_SIZE - len, "       : ");
-	for (i = 0; i < stats->max_states; i++) {
-		if (len >= PAGE_SIZE)
-			break;
-		len += snprintf(buf + len, PAGE_SIZE - len, "state%2u  ", i);
-	}
-	if (len >= PAGE_SIZE)
-		return PAGE_SIZE;
+	spin_lock(&stats->lock);
+
+	ret = kstrtoul(buf, 10, &state);
+	if (ret || (state > stats->max_states))
+		goto unlock;
 
-	len += snprintf(buf + len, PAGE_SIZE - len, "\n");
+	stats->show_state = state;
+unlock:
+	spin_unlock(&stats->lock);
 
-	for (i = 0; i < stats->max_states; i++) {
-		if (len >= PAGE_SIZE)
-			break;
+	return count;
+}
+
+static ssize_t
+show_state_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct thermal_cooling_device *cdev = to_cooling_device(dev);
+	struct cooling_dev_stats *stats = cdev->stats;
+
+	return sprintf(buf, "%lu\n", stats->show_state);
+}
 
-		len += snprintf(buf + len, PAGE_SIZE - len, "state%2u:", i);
+/* find the kth largest in nums array*/
+static int find_show_state(int *nums, int numsSize, int k, unsigned int *max_value)
+{
+	int i, l, r, mid, cnt = 0, min = INT_MAX, max = 0;
 
-		for (j = 0; j < stats->max_states; j++) {
-			if (len >= PAGE_SIZE)
-				break;
-			len += snprintf(buf + len, PAGE_SIZE - len, "%8u ",
-				stats->trans_table[i * stats->max_states + j]);
+	for (i = 0; i < numsSize; i++) {
+		min = nums[i] < min ? nums[i] : min;
+		max = nums[i] > max ? nums[i] : max;
+	}
+	l = min;
+	r = max;
+	while (l < r) {
+		mid = r - (r - l) / 2;
+		for (i = 0; i < numsSize; i++) {
+			if (nums[i] >= mid)
+				cnt++;
+		}
+		if (cnt < k) {
+			r = mid - 1;
+			cnt = 0;
+		} else {
+			l = mid;
+			cnt = 0;
 		}
+	}
+
+	*max_value = max;
+
+	return l;
+}
+
+
+
+static ssize_t trans_table_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct thermal_cooling_device *cdev = to_cooling_device(dev);
+	struct cooling_dev_stats *stats = cdev->stats;
+	unsigned int show_state_value = 0;
+	unsigned int max_state_value = 0;
+	ssize_t len = 0;
+	int i, j;
+
+	len += snprintf(buf + len, PAGE_SIZE - len, " From  :    Index_change\n");
+	for (i = 0; i < stats->max_states; i++) {
+		show_state_value = find_show_state(&stats->trans_table[i * stats->max_states],
+				stats->max_states, stats->show_state, &max_state_value);
+		if (max_state_value)
+			len += snprintf(buf + len, PAGE_SIZE - len, "state%2u:", i);
+		else
+			continue;
+		for (j = 0; j < stats->max_states; j++)
+			if (stats->trans_table[i * stats->max_states + j] && (show_state_value <=
+						stats->trans_table[i * stats->max_states + j]))
+				len += snprintf(buf + len, PAGE_SIZE - len, "     ->%u(%u)", j,
+						stats->trans_table[i * stats->max_states + j]);
 		if (len >= PAGE_SIZE)
 			break;
 		len += snprintf(buf + len, PAGE_SIZE - len, "\n");
@@ -793,6 +849,7 @@ static ssize_t trans_table_show(struct device *dev,
 		pr_warn_once("Thermal transition table exceeds PAGE_SIZE. Disabling\n");
 		return -EFBIG;
 	}
+
 	return len;
 }
 
@@ -800,12 +857,14 @@ static DEVICE_ATTR_RO(total_trans);
 static DEVICE_ATTR_RO(time_in_state_ms);
 static DEVICE_ATTR_WO(reset);
 static DEVICE_ATTR_RO(trans_table);
+static DEVICE_ATTR_RW(show_state);
 
 static struct attribute *cooling_device_stats_attrs[] = {
 	&dev_attr_total_trans.attr,
 	&dev_attr_time_in_state_ms.attr,
 	&dev_attr_reset.attr,
 	&dev_attr_trans_table.attr,
+	&dev_attr_show_state.attr,
 	NULL
 };
 
@@ -829,7 +888,7 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
 	var += sizeof(*stats->time_in_state) * states;
 	var += sizeof(*stats->trans_table) * states * states;
 
-	stats = kzalloc(var, GFP_KERNEL);
+	stats = kvzalloc(var, GFP_KERNEL);
 	if (!stats)
 		return;
 
@@ -838,6 +897,8 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
 	cdev->stats = stats;
 	stats->last_time = ktime_get();
 	stats->max_states = states;
+	/* default set show_state = max_states/2 */
+	stats->show_state = states / 2;
 
 	spin_lock_init(&stats->lock);
 
@@ -848,7 +909,7 @@ static void cooling_device_stats_setup(struct thermal_cooling_device *cdev)
 
 static void cooling_device_stats_destroy(struct thermal_cooling_device *cdev)
 {
-	kfree(cdev->stats);
+	kvfree(cdev->stats);
 	cdev->stats = NULL;
 }
 
-- 
2.25.1