* [PATCH v2 0/3] devfreq: improve devfreq statistics counting
[not found] <CGME20191204150032eucas1p1c10713b3308e45e086dd66099057e2b6@eucas1p1.samsung.com>
@ 2019-12-04 15:00 ` Kamil Konieczny
[not found] ` <CGME20191204150033eucas1p1bf11d36a89c89e3eb55c37a1a204e988@eucas1p1.samsung.com>
` (2 more replies)
0 siblings, 3 replies; 12+ messages in thread
From: Kamil Konieczny @ 2019-12-04 15:00 UTC (permalink / raw)
To: k.konieczny
Cc: Bartlomiej Zolnierkiewicz, Chanwoo Choi, Krzysztof Kozlowski,
Kyungmin Park, linux-kernel, linux-pm, Marek Szyprowski,
MyungJoo Ham
Hi,
this patch series tries to improve devfreq statistics:
- do conversion to use 64-bit jiffies for storing elapsed time and prevent
counters overflow,
- add ability to reset statistics using sysfs,
- move statistics data to separate structure for improved code
readability and maintenance.
Changes in v2:
- added Acked-by to first patch
- dropped spinlock patch, there is mutex used for protecting stats data
- rewrite clearing statistics, suggested by Chanwoo Choi: reuse
trans_stats sysfs file, any write to it will clear devfreq stats
- dropped change var name last_stat_updated
- squashed three last patches into one, as it turned out that freq_table
from devfreq_profile is used by other drivers
- rebased on linux-next
Kamil Konieczny (3):
devfreq: change time stats to 64-bit
devfreq: add clearing transitions stats
devfreq: move statistics to separate struct
drivers/devfreq/devfreq.c | 86 +++++++++++++++++++++++++++------------
include/linux/devfreq.h | 31 ++++++++++----
2 files changed, 81 insertions(+), 36 deletions(-)
--
2.24.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v2 1/3] devfreq: change time stats to 64-bit
[not found] ` <CGME20191204150033eucas1p1bf11d36a89c89e3eb55c37a1a204e988@eucas1p1.samsung.com>
@ 2019-12-04 15:00 ` Kamil Konieczny
2019-12-05 0:27 ` Chanwoo Choi
0 siblings, 1 reply; 12+ messages in thread
From: Kamil Konieczny @ 2019-12-04 15:00 UTC (permalink / raw)
To: k.konieczny
Cc: Bartlomiej Zolnierkiewicz, Chanwoo Choi, Krzysztof Kozlowski,
Kyungmin Park, linux-kernel, linux-pm, Marek Szyprowski,
MyungJoo Ham
Change time stats counting to bigger type by using 64-bit jiffies.
This will make devfreq stats code look similar to cpufreq stats and
prevents overflow (for HZ = 1000 after 49.7 days).
Signed-off-by: Kamil Konieczny <k.konieczny@samsung.com>
Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
---
Changes in v2:
added Acked-by, rebased on linux-next
drivers/devfreq/devfreq.c | 14 +++++++-------
include/linux/devfreq.h | 4 ++--
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index bdeb4189c978..0e2030403e4a 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -199,10 +199,10 @@ static int set_freq_table(struct devfreq *devfreq)
int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
{
int lev, prev_lev, ret = 0;
- unsigned long cur_time;
+ unsigned long long cur_time;
lockdep_assert_held(&devfreq->lock);
- cur_time = jiffies;
+ cur_time = get_jiffies_64();
/* Immediately exit if previous_freq is not initialized yet. */
if (!devfreq->previous_freq)
@@ -525,7 +525,7 @@ void devfreq_monitor_resume(struct devfreq *devfreq)
msecs_to_jiffies(devfreq->profile->polling_ms));
out_update:
- devfreq->last_stat_updated = jiffies;
+ devfreq->last_stat_updated = get_jiffies_64();
devfreq->stop_polling = false;
if (devfreq->profile->get_cur_freq &&
@@ -748,7 +748,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
devfreq->time_in_state = devm_kcalloc(&devfreq->dev,
devfreq->profile->max_state,
- sizeof(unsigned long),
+ sizeof(*devfreq->time_in_state),
GFP_KERNEL);
if (!devfreq->time_in_state) {
mutex_unlock(&devfreq->lock);
@@ -756,7 +756,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
goto err_devfreq;
}
- devfreq->last_stat_updated = jiffies;
+ devfreq->last_stat_updated = get_jiffies_64();
srcu_init_notifier_head(&devfreq->transition_notifier_list);
@@ -1470,8 +1470,8 @@ static ssize_t trans_stat_show(struct device *dev,
for (j = 0; j < max_state; j++)
len += sprintf(buf + len, "%10u",
devfreq->trans_table[(i * max_state) + j]);
- len += sprintf(buf + len, "%10u\n",
- jiffies_to_msecs(devfreq->time_in_state[i]));
+ len += sprintf(buf + len, "%10llu\n", (u64)
+ jiffies64_to_msecs(devfreq->time_in_state[i]));
}
len += sprintf(buf + len, "Total transition : %u\n",
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index 2bae9ed3c783..b81a86e47fb9 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -174,8 +174,8 @@ struct devfreq {
/* information for device frequency transition */
unsigned int total_trans;
unsigned int *trans_table;
- unsigned long *time_in_state;
- unsigned long last_stat_updated;
+ u64 *time_in_state;
+ unsigned long long last_stat_updated;
struct srcu_notifier_head transition_notifier_list;
};
--
2.24.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 2/3] devfreq: add clearing transitions stats
[not found] ` <CGME20191204150033eucas1p164374e7f15cb9a74b7432ca1a822dc10@eucas1p1.samsung.com>
@ 2019-12-04 15:00 ` Kamil Konieczny
2019-12-05 0:38 ` Chanwoo Choi
0 siblings, 1 reply; 12+ messages in thread
From: Kamil Konieczny @ 2019-12-04 15:00 UTC (permalink / raw)
To: k.konieczny
Cc: Bartlomiej Zolnierkiewicz, Chanwoo Choi, Krzysztof Kozlowski,
Kyungmin Park, linux-kernel, linux-pm, Marek Szyprowski,
MyungJoo Ham
Add clearing transition table and time in states devfreq statistics
by writing to trans_stat file in devfreq sysfs.
Signed-off-by: Kamil Konieczny <k.konieczny@samsung.com>
---
Changes in v2:
instead of creating new sysfs file, add new functionality to trans_stat
and clear stats when anything is writen to it
drivers/devfreq/devfreq.c | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 0e2030403e4a..901af3b66a76 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -1478,7 +1478,27 @@ static ssize_t trans_stat_show(struct device *dev,
devfreq->total_trans);
return len;
}
-static DEVICE_ATTR_RO(trans_stat);
+
+static ssize_t trans_stat_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct devfreq *df = to_devfreq(dev);
+ unsigned int cnt = df->profile->max_state;
+
+ if (cnt == 0)
+ return count;
+
+ mutex_lock(&df->lock);
+ memset(df->time_in_state, 0, cnt * sizeof(u64));
+ memset(df->trans_table, 0, cnt * cnt * sizeof(int));
+ df->last_stat_updated = get_jiffies_64();
+ df->total_trans = 0;
+ mutex_unlock(&df->lock);
+
+ return count;
+}
+static DEVICE_ATTR_RW(trans_stat);
static struct attribute *devfreq_attrs[] = {
&dev_attr_name.attr,
--
2.24.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 3/3] devfreq: move statistics to separate struct
[not found] ` <CGME20191204150034eucas1p1b6e7f43a6be59ed2e0a4e55ccdefc750@eucas1p1.samsung.com>
@ 2019-12-04 15:00 ` Kamil Konieczny
2019-12-05 0:28 ` Matthias Kaehlcke
2019-12-05 1:46 ` Chanwoo Choi
0 siblings, 2 replies; 12+ messages in thread
From: Kamil Konieczny @ 2019-12-04 15:00 UTC (permalink / raw)
To: k.konieczny
Cc: Bartlomiej Zolnierkiewicz, Chanwoo Choi, Krzysztof Kozlowski,
Kyungmin Park, linux-kernel, linux-pm, Marek Szyprowski,
MyungJoo Ham
Count time and transitions between devfreq frequencies in separate struct
for improved code readability and maintenance.
Signed-off-by: Kamil Konieczny <k.konieczny@samsung.com>
---
Changes in v2:
squash three patches into one, do not modify devfreq_profile and separate stats
into devfreq_stats
drivers/devfreq/devfreq.c | 68 +++++++++++++++++++++++----------------
include/linux/devfreq.h | 31 ++++++++++++------
2 files changed, 62 insertions(+), 37 deletions(-)
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 901af3b66a76..4d50c8f10bd2 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -198,6 +198,7 @@ static int set_freq_table(struct devfreq *devfreq)
*/
int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
{
+ struct devfreq_stats *stats = devfreq->stats;
int lev, prev_lev, ret = 0;
unsigned long long cur_time;
@@ -214,8 +215,8 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
goto out;
}
- devfreq->time_in_state[prev_lev] +=
- cur_time - devfreq->last_stat_updated;
+ stats->time_in_state[prev_lev] +=
+ cur_time - stats->last_stat_updated;
lev = devfreq_get_freq_level(devfreq, freq);
if (lev < 0) {
@@ -224,13 +225,12 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
}
if (lev != prev_lev) {
- devfreq->trans_table[(prev_lev *
- devfreq->profile->max_state) + lev]++;
- devfreq->total_trans++;
+ stats->trans_table[(prev_lev * stats->max_state) + lev]++;
+ stats->total_trans++;
}
out:
- devfreq->last_stat_updated = cur_time;
+ stats->last_stat_updated = cur_time;
return ret;
}
EXPORT_SYMBOL(devfreq_update_status);
@@ -525,7 +525,7 @@ void devfreq_monitor_resume(struct devfreq *devfreq)
msecs_to_jiffies(devfreq->profile->polling_ms));
out_update:
- devfreq->last_stat_updated = get_jiffies_64();
+ devfreq->stats->last_stat_updated = get_jiffies_64();
devfreq->stop_polling = false;
if (devfreq->profile->get_cur_freq &&
@@ -735,28 +735,38 @@ struct devfreq *devfreq_add_device(struct device *dev,
goto err_out;
}
- devfreq->trans_table = devm_kzalloc(&devfreq->dev,
+ devfreq->stats = devm_kzalloc(&devfreq->dev, sizeof(*devfreq->stats),
+ GFP_KERNEL);
+ if (!devfreq->stats) {
+ mutex_unlock(&devfreq->lock);
+ err = -ENOMEM;
+ goto err_devfreq;
+ }
+
+ devfreq->stats->freq_table = devfreq->profile->freq_table;
+ devfreq->stats->max_state = devfreq->profile->max_state;
+ devfreq->stats->trans_table = devm_kzalloc(&devfreq->dev,
array3_size(sizeof(unsigned int),
- devfreq->profile->max_state,
- devfreq->profile->max_state),
+ devfreq->stats->max_state,
+ devfreq->stats->max_state),
GFP_KERNEL);
- if (!devfreq->trans_table) {
+ if (!devfreq->stats->trans_table) {
mutex_unlock(&devfreq->lock);
err = -ENOMEM;
goto err_devfreq;
}
- devfreq->time_in_state = devm_kcalloc(&devfreq->dev,
- devfreq->profile->max_state,
- sizeof(*devfreq->time_in_state),
+ devfreq->stats->time_in_state = devm_kcalloc(&devfreq->dev,
+ devfreq->stats->max_state,
+ sizeof(*devfreq->stats->time_in_state),
GFP_KERNEL);
- if (!devfreq->time_in_state) {
+ if (!devfreq->stats->time_in_state) {
mutex_unlock(&devfreq->lock);
err = -ENOMEM;
goto err_devfreq;
}
- devfreq->last_stat_updated = get_jiffies_64();
+ devfreq->stats->last_stat_updated = get_jiffies_64();
srcu_init_notifier_head(&devfreq->transition_notifier_list);
@@ -1435,9 +1445,10 @@ static ssize_t trans_stat_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct devfreq *devfreq = to_devfreq(dev);
+ struct devfreq_stats *stats = devfreq->stats;
+ unsigned int max_state = stats->max_state;
ssize_t len;
int i, j;
- unsigned int max_state = devfreq->profile->max_state;
if (max_state == 0)
return sprintf(buf, "Not Supported.\n");
@@ -1454,28 +1465,28 @@ static ssize_t trans_stat_show(struct device *dev,
len += sprintf(buf + len, " :");
for (i = 0; i < max_state; i++)
len += sprintf(buf + len, "%10lu",
- devfreq->profile->freq_table[i]);
+ stats->freq_table[i]);
len += sprintf(buf + len, " time(ms)\n");
for (i = 0; i < max_state; i++) {
- if (devfreq->profile->freq_table[i]
+ if (stats->freq_table[i]
== devfreq->previous_freq) {
len += sprintf(buf + len, "*");
} else {
len += sprintf(buf + len, " ");
}
len += sprintf(buf + len, "%10lu:",
- devfreq->profile->freq_table[i]);
+ stats->freq_table[i]);
for (j = 0; j < max_state; j++)
len += sprintf(buf + len, "%10u",
- devfreq->trans_table[(i * max_state) + j]);
+ stats->trans_table[(i * max_state) + j]);
len += sprintf(buf + len, "%10llu\n", (u64)
- jiffies64_to_msecs(devfreq->time_in_state[i]));
+ jiffies64_to_msecs(stats->time_in_state[i]));
}
len += sprintf(buf + len, "Total transition : %u\n",
- devfreq->total_trans);
+ stats->total_trans);
return len;
}
@@ -1484,16 +1495,17 @@ static ssize_t trans_stat_store(struct device *dev,
const char *buf, size_t count)
{
struct devfreq *df = to_devfreq(dev);
- unsigned int cnt = df->profile->max_state;
+ struct devfreq_stats *stats = df->stats;
+ unsigned int cnt = stats->max_state;
if (cnt == 0)
return count;
mutex_lock(&df->lock);
- memset(df->time_in_state, 0, cnt * sizeof(u64));
- memset(df->trans_table, 0, cnt * cnt * sizeof(int));
- df->last_stat_updated = get_jiffies_64();
- df->total_trans = 0;
+ memset(stats->time_in_state, 0, cnt * sizeof(u64));
+ memset(stats->trans_table, 0, cnt * cnt * sizeof(int));
+ stats->last_stat_updated = get_jiffies_64();
+ stats->total_trans = 0;
mutex_unlock(&df->lock);
return count;
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index b81a86e47fb9..2715719924e7 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -106,6 +106,25 @@ struct devfreq_dev_profile {
unsigned int max_state;
};
+/**
+ * struct devfreq_stats - Devfreq's transitions stats counters
+ * @freq_table: List of frequencies in ascending order.
+ * @max_state: The size of freq_table.
+ * @total_trans: Number of devfreq transitions.
+ * @trans_table: Statistics of devfreq transitions.
+ * @time_in_state: Statistics of devfreq states.
+ * @last_stat_updated: The last time stats were updated.
+ */
+struct devfreq_stats {
+ unsigned long *freq_table;
+ unsigned int max_state;
+
+ unsigned int total_trans;
+ unsigned int *trans_table;
+ u64 *time_in_state;
+ unsigned long long last_stat_updated;
+};
+
/**
* struct devfreq - Device devfreq structure
* @node: list node - contains the devices with devfreq that have been
@@ -131,10 +150,7 @@ struct devfreq_dev_profile {
* @suspend_freq: frequency of a device set during suspend phase.
* @resume_freq: frequency of a device set in resume phase.
* @suspend_count: suspend requests counter for a device.
- * @total_trans: Number of devfreq transitions
- * @trans_table: Statistics of devfreq transitions
- * @time_in_state: Statistics of devfreq states
- * @last_stat_updated: The last time stat updated
+ * @stats: Statistics of devfreq transitions and states times
* @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
*
* This structure stores the devfreq information for a give device.
@@ -171,11 +187,8 @@ struct devfreq {
unsigned long resume_freq;
atomic_t suspend_count;
- /* information for device frequency transition */
- unsigned int total_trans;
- unsigned int *trans_table;
- u64 *time_in_state;
- unsigned long long last_stat_updated;
+ /* information for device frequency transitions */
+ struct devfreq_stats *stats;
struct srcu_notifier_head transition_notifier_list;
};
--
2.24.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v2 1/3] devfreq: change time stats to 64-bit
2019-12-04 15:00 ` [PATCH v2 1/3] devfreq: change time stats to 64-bit Kamil Konieczny
@ 2019-12-05 0:27 ` Chanwoo Choi
2019-12-05 9:58 ` Kamil Konieczny
0 siblings, 1 reply; 12+ messages in thread
From: Chanwoo Choi @ 2019-12-05 0:27 UTC (permalink / raw)
To: Kamil Konieczny
Cc: Bartlomiej Zolnierkiewicz, Krzysztof Kozlowski, Kyungmin Park,
linux-kernel, linux-pm, Marek Szyprowski, MyungJoo Ham
On 12/5/19 12:00 AM, Kamil Konieczny wrote:
> Change time stats counting to bigger type by using 64-bit jiffies.
> This will make devfreq stats code look similar to cpufreq stats and
> prevents overflow (for HZ = 1000 after 49.7 days).
>
> Signed-off-by: Kamil Konieczny <k.konieczny@samsung.com>
> Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
> ---
> Changes in v2:
> added Acked-by, rebased on linux-next
>
> drivers/devfreq/devfreq.c | 14 +++++++-------
> include/linux/devfreq.h | 4 ++--
> 2 files changed, 9 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index bdeb4189c978..0e2030403e4a 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -199,10 +199,10 @@ static int set_freq_table(struct devfreq *devfreq)
> int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
> {
> int lev, prev_lev, ret = 0;
> - unsigned long cur_time;
> + unsigned long long cur_time;
It looks better to use 'u64' instead of 'unsigned long long'.
Because get_jiffies_u64 has 'u64' return type.
>
> lockdep_assert_held(&devfreq->lock);
> - cur_time = jiffies;
> + cur_time = get_jiffies_64();
>
> /* Immediately exit if previous_freq is not initialized yet. */
> if (!devfreq->previous_freq)
> @@ -525,7 +525,7 @@ void devfreq_monitor_resume(struct devfreq *devfreq)
> msecs_to_jiffies(devfreq->profile->polling_ms));
>
> out_update:
> - devfreq->last_stat_updated = jiffies;
> + devfreq->last_stat_updated = get_jiffies_64();
> devfreq->stop_polling = false;
>
> if (devfreq->profile->get_cur_freq &&
> @@ -748,7 +748,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
>
> devfreq->time_in_state = devm_kcalloc(&devfreq->dev,
> devfreq->profile->max_state,
> - sizeof(unsigned long),
> + sizeof(*devfreq->time_in_state),
> GFP_KERNEL);
> if (!devfreq->time_in_state) {
> mutex_unlock(&devfreq->lock);
> @@ -756,7 +756,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
> goto err_devfreq;
> }
>
> - devfreq->last_stat_updated = jiffies;
> + devfreq->last_stat_updated = get_jiffies_64();
>
> srcu_init_notifier_head(&devfreq->transition_notifier_list);
>
> @@ -1470,8 +1470,8 @@ static ssize_t trans_stat_show(struct device *dev,
> for (j = 0; j < max_state; j++)
> len += sprintf(buf + len, "%10u",
> devfreq->trans_table[(i * max_state) + j]);
> - len += sprintf(buf + len, "%10u\n",
> - jiffies_to_msecs(devfreq->time_in_state[i]));
> + len += sprintf(buf + len, "%10llu\n", (u64)
> + jiffies64_to_msecs(devfreq->time_in_state[i]));
> }
>
> len += sprintf(buf + len, "Total transition : %u\n",
> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
> index 2bae9ed3c783..b81a86e47fb9 100644
> --- a/include/linux/devfreq.h
> +++ b/include/linux/devfreq.h
> @@ -174,8 +174,8 @@ struct devfreq {
> /* information for device frequency transition */
> unsigned int total_trans;
> unsigned int *trans_table;
> - unsigned long *time_in_state;
> - unsigned long last_stat_updated;
> + u64 *time_in_state;
> + unsigned long long last_stat_updated;
ditto. 'unsigned long long' -> 'u64'.
>
> struct srcu_notifier_head transition_notifier_list;
> };
>
--
Best Regards,
Chanwoo Choi
Samsung Electronics
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 3/3] devfreq: move statistics to separate struct
2019-12-04 15:00 ` [PATCH v2 3/3] devfreq: move statistics to separate struct Kamil Konieczny
@ 2019-12-05 0:28 ` Matthias Kaehlcke
2019-12-05 14:18 ` Kamil Konieczny
2019-12-05 1:46 ` Chanwoo Choi
1 sibling, 1 reply; 12+ messages in thread
From: Matthias Kaehlcke @ 2019-12-05 0:28 UTC (permalink / raw)
To: Kamil Konieczny
Cc: Bartlomiej Zolnierkiewicz, Chanwoo Choi, Krzysztof Kozlowski,
Kyungmin Park, linux-kernel, linux-pm, Marek Szyprowski,
MyungJoo Ham
Hi,
On Wed, Dec 04, 2019 at 04:00:18PM +0100, Kamil Konieczny wrote:
> Count time and transitions between devfreq frequencies in separate struct
> for improved code readability and maintenance.
>
> Signed-off-by: Kamil Konieczny <k.konieczny@samsung.com>
> ---
> Changes in v2:
> squash three patches into one, do not modify devfreq_profile and separate stats
> into devfreq_stats
>
> drivers/devfreq/devfreq.c | 68 +++++++++++++++++++++++----------------
> include/linux/devfreq.h | 31 ++++++++++++------
> 2 files changed, 62 insertions(+), 37 deletions(-)
>
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index 901af3b66a76..4d50c8f10bd2 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -198,6 +198,7 @@ static int set_freq_table(struct devfreq *devfreq)
> */
> int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
> {
> + struct devfreq_stats *stats = devfreq->stats;
> int lev, prev_lev, ret = 0;
> unsigned long long cur_time;
>
> @@ -214,8 +215,8 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
> goto out;
> }
>
> - devfreq->time_in_state[prev_lev] +=
> - cur_time - devfreq->last_stat_updated;
> + stats->time_in_state[prev_lev] +=
> + cur_time - stats->last_stat_updated;
>
> lev = devfreq_get_freq_level(devfreq, freq);
> if (lev < 0) {
> @@ -224,13 +225,12 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
> }
>
> if (lev != prev_lev) {
> - devfreq->trans_table[(prev_lev *
> - devfreq->profile->max_state) + lev]++;
> - devfreq->total_trans++;
> + stats->trans_table[(prev_lev * stats->max_state) + lev]++;
> + stats->total_trans++;
> }
>
> out:
> - devfreq->last_stat_updated = cur_time;
> + stats->last_stat_updated = cur_time;
> return ret;
> }
> EXPORT_SYMBOL(devfreq_update_status);
> @@ -525,7 +525,7 @@ void devfreq_monitor_resume(struct devfreq *devfreq)
> msecs_to_jiffies(devfreq->profile->polling_ms));
>
> out_update:
> - devfreq->last_stat_updated = get_jiffies_64();
> + devfreq->stats->last_stat_updated = get_jiffies_64();
> devfreq->stop_polling = false;
>
> if (devfreq->profile->get_cur_freq &&
> @@ -735,28 +735,38 @@ struct devfreq *devfreq_add_device(struct device *dev,
> goto err_out;
> }
>
> - devfreq->trans_table = devm_kzalloc(&devfreq->dev,
> + devfreq->stats = devm_kzalloc(&devfreq->dev, sizeof(*devfreq->stats),
> + GFP_KERNEL);
> + if (!devfreq->stats) {
> + mutex_unlock(&devfreq->lock);
> + err = -ENOMEM;
> + goto err_devfreq;
> + }
> +
> + devfreq->stats->freq_table = devfreq->profile->freq_table;
> + devfreq->stats->max_state = devfreq->profile->max_state;
> + devfreq->stats->trans_table = devm_kzalloc(&devfreq->dev,
> array3_size(sizeof(unsigned int),
> - devfreq->profile->max_state,
> - devfreq->profile->max_state),
> + devfreq->stats->max_state,
> + devfreq->stats->max_state),
> GFP_KERNEL);
> - if (!devfreq->trans_table) {
> + if (!devfreq->stats->trans_table) {
> mutex_unlock(&devfreq->lock);
> err = -ENOMEM;
> goto err_devfreq;
> }
>
> - devfreq->time_in_state = devm_kcalloc(&devfreq->dev,
> - devfreq->profile->max_state,
> - sizeof(*devfreq->time_in_state),
> + devfreq->stats->time_in_state = devm_kcalloc(&devfreq->dev,
> + devfreq->stats->max_state,
> + sizeof(*devfreq->stats->time_in_state),
> GFP_KERNEL);
> - if (!devfreq->time_in_state) {
> + if (!devfreq->stats->time_in_state) {
> mutex_unlock(&devfreq->lock);
> err = -ENOMEM;
> goto err_devfreq;
> }
>
> - devfreq->last_stat_updated = get_jiffies_64();
> + devfreq->stats->last_stat_updated = get_jiffies_64();
>
> srcu_init_notifier_head(&devfreq->transition_notifier_list);
>
> @@ -1435,9 +1445,10 @@ static ssize_t trans_stat_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> struct devfreq *devfreq = to_devfreq(dev);
> + struct devfreq_stats *stats = devfreq->stats;
> + unsigned int max_state = stats->max_state;
> ssize_t len;
> int i, j;
> - unsigned int max_state = devfreq->profile->max_state;
>
> if (max_state == 0)
> return sprintf(buf, "Not Supported.\n");
> @@ -1454,28 +1465,28 @@ static ssize_t trans_stat_show(struct device *dev,
> len += sprintf(buf + len, " :");
> for (i = 0; i < max_state; i++)
> len += sprintf(buf + len, "%10lu",
> - devfreq->profile->freq_table[i]);
> + stats->freq_table[i]);
>
> len += sprintf(buf + len, " time(ms)\n");
>
> for (i = 0; i < max_state; i++) {
> - if (devfreq->profile->freq_table[i]
> + if (stats->freq_table[i]
> == devfreq->previous_freq) {
> len += sprintf(buf + len, "*");
> } else {
> len += sprintf(buf + len, " ");
> }
> len += sprintf(buf + len, "%10lu:",
> - devfreq->profile->freq_table[i]);
> + stats->freq_table[i]);
> for (j = 0; j < max_state; j++)
> len += sprintf(buf + len, "%10u",
> - devfreq->trans_table[(i * max_state) + j]);
> + stats->trans_table[(i * max_state) + j]);
> len += sprintf(buf + len, "%10llu\n", (u64)
> - jiffies64_to_msecs(devfreq->time_in_state[i]));
> + jiffies64_to_msecs(stats->time_in_state[i]));
> }
>
> len += sprintf(buf + len, "Total transition : %u\n",
> - devfreq->total_trans);
> + stats->total_trans);
> return len;
> }
>
> @@ -1484,16 +1495,17 @@ static ssize_t trans_stat_store(struct device *dev,
> const char *buf, size_t count)
> {
> struct devfreq *df = to_devfreq(dev);
> - unsigned int cnt = df->profile->max_state;
> + struct devfreq_stats *stats = df->stats;
> + unsigned int cnt = stats->max_state;
>
> if (cnt == 0)
> return count;
>
> mutex_lock(&df->lock);
> - memset(df->time_in_state, 0, cnt * sizeof(u64));
> - memset(df->trans_table, 0, cnt * cnt * sizeof(int));
> - df->last_stat_updated = get_jiffies_64();
> - df->total_trans = 0;
> + memset(stats->time_in_state, 0, cnt * sizeof(u64));
> + memset(stats->trans_table, 0, cnt * cnt * sizeof(int));
> + stats->last_stat_updated = get_jiffies_64();
> + stats->total_trans = 0;
> mutex_unlock(&df->lock);
>
> return count;
> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
> index b81a86e47fb9..2715719924e7 100644
> --- a/include/linux/devfreq.h
> +++ b/include/linux/devfreq.h
> @@ -106,6 +106,25 @@ struct devfreq_dev_profile {
> unsigned int max_state;
> };
>
> +/**
> + * struct devfreq_stats - Devfreq's transitions stats counters
> + * @freq_table: List of frequencies in ascending order.
> + * @max_state: The size of freq_table.
> + * @total_trans: Number of devfreq transitions.
> + * @trans_table: Statistics of devfreq transitions.
> + * @time_in_state: Statistics of devfreq states.
> + * @last_stat_updated: The last time stats were updated.
> + */
> +struct devfreq_stats {
> + unsigned long *freq_table;
nit: trans_stat_show() is the only place where 'freq_table' is
used. Instead of 'duplicating' it (I know, it's just a pointer)
you could use a local pointer 'freq_table' in trans_stat_show().
> + unsigned int max_state;
nit: max_state is also a bit of a corner case. It's not really a 'stat' and
it is already available in struct devfreq_dev_profile, it doesn't seem a
huge inconvenient to take it from there.
> +
> + unsigned int total_trans;
> + unsigned int *trans_table;
> + u64 *time_in_state;
> + unsigned long long last_stat_updated;
nit: the name 'last_stat_updated' is somewhat redundant, since the
field is part of a struct called 'devfreq_stats'. 'last_updated' or
'last_update' would be concise enough IMO.
> +};
> +
> /**
> * struct devfreq - Device devfreq structure
> * @node: list node - contains the devices with devfreq that have been
> @@ -131,10 +150,7 @@ struct devfreq_dev_profile {
> * @suspend_freq: frequency of a device set during suspend phase.
> * @resume_freq: frequency of a device set in resume phase.
> * @suspend_count: suspend requests counter for a device.
> - * @total_trans: Number of devfreq transitions
> - * @trans_table: Statistics of devfreq transitions
> - * @time_in_state: Statistics of devfreq states
> - * @last_stat_updated: The last time stat updated
> + * @stats: Statistics of devfreq transitions and states times
> * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
> *
> * This structure stores the devfreq information for a give device.
> @@ -171,11 +187,8 @@ struct devfreq {
> unsigned long resume_freq;
> atomic_t suspend_count;
>
> - /* information for device frequency transition */
> - unsigned int total_trans;
> - unsigned int *trans_table;
> - u64 *time_in_state;
> - unsigned long long last_stat_updated;
> + /* information for device frequency transitions */
> + struct devfreq_stats *stats;
>
> struct srcu_notifier_head transition_notifier_list;
> };
My comments above are just suggestions:
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 2/3] devfreq: add clearing transitions stats
2019-12-04 15:00 ` [PATCH v2 2/3] devfreq: add clearing transitions stats Kamil Konieczny
@ 2019-12-05 0:38 ` Chanwoo Choi
2019-12-05 10:33 ` Kamil Konieczny
0 siblings, 1 reply; 12+ messages in thread
From: Chanwoo Choi @ 2019-12-05 0:38 UTC (permalink / raw)
To: Kamil Konieczny
Cc: Bartlomiej Zolnierkiewicz, Krzysztof Kozlowski, Kyungmin Park,
linux-kernel, linux-pm, Marek Szyprowski, MyungJoo Ham
On 12/5/19 12:00 AM, Kamil Konieczny wrote:
> Add clearing transition table and time in states devfreq statistics
> by writing to trans_stat file in devfreq sysfs.
Have to add command example how to reset the trans_stat via sysfs
on patch description.
And, have to add how to do it on documentation file as following:
On next version, please contain the following modification with this patch.
diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq
index 75897e2fde43..c172ff838643 100644
--- a/Documentation/ABI/testing/sysfs-class-devfreq
+++ b/Documentation/ABI/testing/sysfs-class-devfreq
@@ -60,7 +60,10 @@ Description:
the number of transitions between states.
In order to activate this ABI, the devfreq target device
driver should provide the list of available frequencies
- with its profile.
+ with its profile. If need to reset the statistics of devfreq
+ behavior on a specific device, enter 0(zero) to 'trans_stat'
+ as following:
+ echo 0 > /sys/class/devfreq/.../trans_stat
What: /sys/class/devfreq/.../userspace/set_freq
Date: September 2011
>
> Signed-off-by: Kamil Konieczny <k.konieczny@samsung.com>
> ---
> Changes in v2:
> instead of creating new sysfs file, add new functionality to trans_stat
> and clear stats when anything is writen to it
>
> drivers/devfreq/devfreq.c | 22 +++++++++++++++++++++-
> 1 file changed, 21 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index 0e2030403e4a..901af3b66a76 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -1478,7 +1478,27 @@ static ssize_t trans_stat_show(struct device *dev,
> devfreq->total_trans);
> return len;
> }
> -static DEVICE_ATTR_RO(trans_stat);
> +
> +static ssize_t trans_stat_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct devfreq *df = to_devfreq(dev);
> + unsigned int cnt = df->profile->max_state;
> +
Why don't you check the input value is whether value is 0(zero) or not?
If user enter the any value to 'trans_stat', devfreq core
reset the statistics data. I want to decide the fixed value
for the reset as following:
echo 0 > /sys/class/devfreq/devfreqX/trans_stat
> + if (cnt == 0)
> + return count;
> +
> + mutex_lock(&df->lock);
> + memset(df->time_in_state, 0, cnt * sizeof(u64));
> + memset(df->trans_table, 0, cnt * cnt * sizeof(int));
> + df->last_stat_updated = get_jiffies_64();
> + df->total_trans = 0;
> + mutex_unlock(&df->lock);
> +
> + return count;
> +}
> +static DEVICE_ATTR_RW(trans_stat);
>
> static struct attribute *devfreq_attrs[] = {
> &dev_attr_name.attr,
>
--
Best Regards,
Chanwoo Choi
Samsung Electronics
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v2 3/3] devfreq: move statistics to separate struct
2019-12-04 15:00 ` [PATCH v2 3/3] devfreq: move statistics to separate struct Kamil Konieczny
2019-12-05 0:28 ` Matthias Kaehlcke
@ 2019-12-05 1:46 ` Chanwoo Choi
2019-12-05 14:30 ` Kamil Konieczny
1 sibling, 1 reply; 12+ messages in thread
From: Chanwoo Choi @ 2019-12-05 1:46 UTC (permalink / raw)
To: Kamil Konieczny
Cc: Bartlomiej Zolnierkiewicz, Krzysztof Kozlowski, Kyungmin Park,
linux-kernel, linux-pm, Marek Szyprowski, MyungJoo Ham
On 12/5/19 12:00 AM, Kamil Konieczny wrote:
> Count time and transitions between devfreq frequencies in separate struct
> for improved code readability and maintenance.
>
> Signed-off-by: Kamil Konieczny <k.konieczny@samsung.com>
> ---
> Changes in v2:
> squash three patches into one, do not modify devfreq_profile and separate stats
> into devfreq_stats
>
> drivers/devfreq/devfreq.c | 68 +++++++++++++++++++++++----------------
> include/linux/devfreq.h | 31 ++++++++++++------
> 2 files changed, 62 insertions(+), 37 deletions(-)
>
> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
> index 901af3b66a76..4d50c8f10bd2 100644
> --- a/drivers/devfreq/devfreq.c
> +++ b/drivers/devfreq/devfreq.c
> @@ -198,6 +198,7 @@ static int set_freq_table(struct devfreq *devfreq)
> */
> int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
> {
> + struct devfreq_stats *stats = devfreq->stats;
> int lev, prev_lev, ret = 0;
> unsigned long long cur_time;
>
> @@ -214,8 +215,8 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
> goto out;
> }
>
> - devfreq->time_in_state[prev_lev] +=
> - cur_time - devfreq->last_stat_updated;
> + stats->time_in_state[prev_lev] +=
> + cur_time - stats->last_stat_updated;
>
> lev = devfreq_get_freq_level(devfreq, freq);
> if (lev < 0) {
> @@ -224,13 +225,12 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
> }
>
> if (lev != prev_lev) {
> - devfreq->trans_table[(prev_lev *
> - devfreq->profile->max_state) + lev]++;
> - devfreq->total_trans++;
> + stats->trans_table[(prev_lev * stats->max_state) + lev]++;
> + stats->total_trans++;
> }
>
> out:
> - devfreq->last_stat_updated = cur_time;
> + stats->last_stat_updated = cur_time;
> return ret;
> }
> EXPORT_SYMBOL(devfreq_update_status);
> @@ -525,7 +525,7 @@ void devfreq_monitor_resume(struct devfreq *devfreq)
> msecs_to_jiffies(devfreq->profile->polling_ms));
>
> out_update:
> - devfreq->last_stat_updated = get_jiffies_64();
> + devfreq->stats->last_stat_updated = get_jiffies_64();
> devfreq->stop_polling = false;
>
> if (devfreq->profile->get_cur_freq &&
> @@ -735,28 +735,38 @@ struct devfreq *devfreq_add_device(struct device *dev,
> goto err_out;
> }
>
> - devfreq->trans_table = devm_kzalloc(&devfreq->dev,
> + devfreq->stats = devm_kzalloc(&devfreq->dev, sizeof(*devfreq->stats),
> + GFP_KERNEL);
Each devfreq has only one stats structure always. Don't need to define
it with pointer type. It is enough to define as following without pointer type:
struct devfreq_stats stats;
> + if (!devfreq->stats) {
> + mutex_unlock(&devfreq->lock);
> + err = -ENOMEM;
> + goto err_devfreq;
> + }
> +
> + devfreq->stats->freq_table = devfreq->profile->freq_table;
> + devfreq->stats->max_state = devfreq->profile->max_state;
> + devfreq->stats->trans_table = devm_kzalloc(&devfreq->dev,
> array3_size(sizeof(unsigned int),
> - devfreq->profile->max_state,
> - devfreq->profile->max_state),
> + devfreq->stats->max_state,
> + devfreq->stats->max_state),
> GFP_KERNEL);
> - if (!devfreq->trans_table) {
> + if (!devfreq->stats->trans_table) {
> mutex_unlock(&devfreq->lock);
> err = -ENOMEM;
> goto err_devfreq;
> }
>
> - devfreq->time_in_state = devm_kcalloc(&devfreq->dev,
> - devfreq->profile->max_state,
> - sizeof(*devfreq->time_in_state),
> + devfreq->stats->time_in_state = devm_kcalloc(&devfreq->dev,
> + devfreq->stats->max_state,
> + sizeof(*devfreq->stats->time_in_state),
> GFP_KERNEL);
Actually, this patch will be conflict with patch[1].
[1] https://www.spinics.net/lists/arm-kernel/msg768822.html
First of all, I have to merge patches[1][2] for the devfreq pm-qos
during v5.5-rc period. It requires the linux-pm's maintainer.
[2] https://www.spinics.net/lists/arm-kernel/msg769761.html
After finishing the job[1][2], I'll merge this patch
if finished the review of this patch. Just share the possible merge
conflict to you.
> - if (!devfreq->time_in_state) {
> + if (!devfreq->stats->time_in_state) {
> mutex_unlock(&devfreq->lock);
> err = -ENOMEM;
> goto err_devfreq;
> }
>
> - devfreq->last_stat_updated = get_jiffies_64();
> + devfreq->stats->last_stat_updated = get_jiffies_64();
>
> srcu_init_notifier_head(&devfreq->transition_notifier_list);
>
> @@ -1435,9 +1445,10 @@ static ssize_t trans_stat_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> struct devfreq *devfreq = to_devfreq(dev);
> + struct devfreq_stats *stats = devfreq->stats;
> + unsigned int max_state = stats->max_state;
> ssize_t len;
> int i, j;
> - unsigned int max_state = devfreq->profile->max_state;
>
> if (max_state == 0)
> return sprintf(buf, "Not Supported.\n");
> @@ -1454,28 +1465,28 @@ static ssize_t trans_stat_show(struct device *dev,
> len += sprintf(buf + len, " :");
> for (i = 0; i < max_state; i++)
> len += sprintf(buf + len, "%10lu",
> - devfreq->profile->freq_table[i]);
> + stats->freq_table[i]);
>
> len += sprintf(buf + len, " time(ms)\n");
>
> for (i = 0; i < max_state; i++) {
> - if (devfreq->profile->freq_table[i]
> + if (stats->freq_table[i]
> == devfreq->previous_freq) {
> len += sprintf(buf + len, "*");
> } else {
> len += sprintf(buf + len, " ");
> }
> len += sprintf(buf + len, "%10lu:",
> - devfreq->profile->freq_table[i]);
> + stats->freq_table[i]);
> for (j = 0; j < max_state; j++)
> len += sprintf(buf + len, "%10u",
> - devfreq->trans_table[(i * max_state) + j]);
> + stats->trans_table[(i * max_state) + j]);
> len += sprintf(buf + len, "%10llu\n", (u64)
> - jiffies64_to_msecs(devfreq->time_in_state[i]));
> + jiffies64_to_msecs(stats->time_in_state[i]));
> }
>
> len += sprintf(buf + len, "Total transition : %u\n",
> - devfreq->total_trans);
> + stats->total_trans);
> return len;
> }
>
> @@ -1484,16 +1495,17 @@ static ssize_t trans_stat_store(struct device *dev,
> const char *buf, size_t count)
> {
> struct devfreq *df = to_devfreq(dev);
> - unsigned int cnt = df->profile->max_state;
> + struct devfreq_stats *stats = df->stats;
> + unsigned int cnt = stats->max_state;
>
> if (cnt == 0)
> return count;
>
> mutex_lock(&df->lock);
> - memset(df->time_in_state, 0, cnt * sizeof(u64));
> - memset(df->trans_table, 0, cnt * cnt * sizeof(int));
> - df->last_stat_updated = get_jiffies_64();
> - df->total_trans = 0;
> + memset(stats->time_in_state, 0, cnt * sizeof(u64));
> + memset(stats->trans_table, 0, cnt * cnt * sizeof(int));
> + stats->last_stat_updated = get_jiffies_64();
> + stats->total_trans = 0;
> mutex_unlock(&df->lock);
>
> return count;
> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
> index b81a86e47fb9..2715719924e7 100644
> --- a/include/linux/devfreq.h
> +++ b/include/linux/devfreq.h
> @@ -106,6 +106,25 @@ struct devfreq_dev_profile {
> unsigned int max_state;
> };
>
> +/**
> + * struct devfreq_stats - Devfreq's transitions stats counters
Devfreq's transitions stats counters -> Statistics of devfreq device behavior
> + * @freq_table: List of frequencies in ascending order.
> + * @max_state: The size of freq_table.
> + * @total_trans: Number of devfreq transitions.
> + * @trans_table: Statistics of devfreq transitions.
> + * @time_in_state: Statistics of devfreq states.
> + * @last_stat_updated: The last time stats were updated.
> + */
> +struct devfreq_stats {
> + unsigned long *freq_table;
> + unsigned int max_state;
Acutally, I'm sorry I has not yet completely agreed to move
'freq_table and 'max_state' from struct devfreq to struct devfreq_stats.
It has not any critical benefit and any problem.
So, don't move 'freq_table' and 'max_state'.
> +
> + unsigned int total_trans;
> + unsigned int *trans_table;
> + u64 *time_in_state;
> + unsigned long long last_stat_updated;
> +};
> +
> /**
> * struct devfreq - Device devfreq structure
> * @node: list node - contains the devices with devfreq that have been
> @@ -131,10 +150,7 @@ struct devfreq_dev_profile {
> * @suspend_freq: frequency of a device set during suspend phase.
> * @resume_freq: frequency of a device set in resume phase.
> * @suspend_count: suspend requests counter for a device.
> - * @total_trans: Number of devfreq transitions
> - * @trans_table: Statistics of devfreq transitions
> - * @time_in_state: Statistics of devfreq states
> - * @last_stat_updated: The last time stat updated
> + * @stats: Statistics of devfreq transitions and states times
Statistics of devfreq transitions and states times
-> Statistics of devfreq device behavior
> * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
> *
> * This structure stores the devfreq information for a give device.
> @@ -171,11 +187,8 @@ struct devfreq {
> unsigned long resume_freq;
> atomic_t suspend_count;
>
> - /* information for device frequency transition */
> - unsigned int total_trans;
> - unsigned int *trans_table;
> - u64 *time_in_state;
> - unsigned long long last_stat_updated;
> + /* information for device frequency transitions */
> + struct devfreq_stats *stats;
Each devfreq has only one stats structure always. Don't need to define
it with pointer type. It is enough to define as following without pointer type:
struct devfreq_stats stats;
>
> struct srcu_notifier_head transition_notifier_list;
> };
>
--
Best Regards,
Chanwoo Choi
Samsung Electronics
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 1/3] devfreq: change time stats to 64-bit
2019-12-05 0:27 ` Chanwoo Choi
@ 2019-12-05 9:58 ` Kamil Konieczny
0 siblings, 0 replies; 12+ messages in thread
From: Kamil Konieczny @ 2019-12-05 9:58 UTC (permalink / raw)
To: Chanwoo Choi
Cc: Bartlomiej Zolnierkiewicz, Krzysztof Kozlowski, Kyungmin Park,
linux-kernel, linux-pm, Marek Szyprowski, MyungJoo Ham
Hi,
On 05.12.2019 01:27, Chanwoo Choi wrote:
> On 12/5/19 12:00 AM, Kamil Konieczny wrote:
>> Change time stats counting to bigger type by using 64-bit jiffies.
>> This will make devfreq stats code look similar to cpufreq stats and
>> prevents overflow (for HZ = 1000 after 49.7 days).
>>
>> Signed-off-by: Kamil Konieczny <k.konieczny@samsung.com>
>> Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
>> ---
>> Changes in v2:
>> added Acked-by, rebased on linux-next
>>
>> drivers/devfreq/devfreq.c | 14 +++++++-------
>> include/linux/devfreq.h | 4 ++--
>> 2 files changed, 9 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>> index bdeb4189c978..0e2030403e4a 100644
>> --- a/drivers/devfreq/devfreq.c
>> +++ b/drivers/devfreq/devfreq.c
>> @@ -199,10 +199,10 @@ static int set_freq_table(struct devfreq *devfreq)
>> int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
>> {
>> int lev, prev_lev, ret = 0;
>> - unsigned long cur_time;
>> + unsigned long long cur_time;
>
> It looks better to use 'u64' instead of 'unsigned long long'.
> Because get_jiffies_u64 has 'u64' return type.
You are right, I will change this and send v3.
>>
>> lockdep_assert_held(&devfreq->lock);
>> - cur_time = jiffies;
>> + cur_time = get_jiffies_64();
>>
>> /* Immediately exit if previous_freq is not initialized yet. */
>> if (!devfreq->previous_freq)
>> @@ -525,7 +525,7 @@ void devfreq_monitor_resume(struct devfreq *devfreq)
>> msecs_to_jiffies(devfreq->profile->polling_ms));
>>
>> out_update:
>> - devfreq->last_stat_updated = jiffies;
>> + devfreq->last_stat_updated = get_jiffies_64();
>> devfreq->stop_polling = false;
>>
>> if (devfreq->profile->get_cur_freq &&
>> @@ -748,7 +748,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
>>
>> devfreq->time_in_state = devm_kcalloc(&devfreq->dev,
>> devfreq->profile->max_state,
>> - sizeof(unsigned long),
>> + sizeof(*devfreq->time_in_state),
>> GFP_KERNEL);
>> if (!devfreq->time_in_state) {
>> mutex_unlock(&devfreq->lock);
>> @@ -756,7 +756,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
>> goto err_devfreq;
>> }
>>
>> - devfreq->last_stat_updated = jiffies;
>> + devfreq->last_stat_updated = get_jiffies_64();
>>
>> srcu_init_notifier_head(&devfreq->transition_notifier_list);
>>
>> @@ -1470,8 +1470,8 @@ static ssize_t trans_stat_show(struct device *dev,
>> for (j = 0; j < max_state; j++)
>> len += sprintf(buf + len, "%10u",
>> devfreq->trans_table[(i * max_state) + j]);
>> - len += sprintf(buf + len, "%10u\n",
>> - jiffies_to_msecs(devfreq->time_in_state[i]));
>> + len += sprintf(buf + len, "%10llu\n", (u64)
>> + jiffies64_to_msecs(devfreq->time_in_state[i]));
>> }
>>
>> len += sprintf(buf + len, "Total transition : %u\n",
>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>> index 2bae9ed3c783..b81a86e47fb9 100644
>> --- a/include/linux/devfreq.h
>> +++ b/include/linux/devfreq.h
>> @@ -174,8 +174,8 @@ struct devfreq {
>> /* information for device frequency transition */
>> unsigned int total_trans;
>> unsigned int *trans_table;
>> - unsigned long *time_in_state;
>> - unsigned long last_stat_updated;
>> + u64 *time_in_state;
>> + unsigned long long last_stat_updated;
>
> ditto. 'unsigned long long' -> 'u64'.
Yes, will change this too.
>> struct srcu_notifier_head transition_notifier_list;
>> };
>>
--
Best regards,
Kamil Konieczny
Samsung R&D Institute Poland
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 2/3] devfreq: add clearing transitions stats
2019-12-05 0:38 ` Chanwoo Choi
@ 2019-12-05 10:33 ` Kamil Konieczny
0 siblings, 0 replies; 12+ messages in thread
From: Kamil Konieczny @ 2019-12-05 10:33 UTC (permalink / raw)
To: Chanwoo Choi
Cc: Bartlomiej Zolnierkiewicz, Krzysztof Kozlowski, Kyungmin Park,
linux-kernel, linux-pm, Marek Szyprowski, MyungJoo Ham
Hi Chanwoo,
On 05.12.2019 01:38, Chanwoo Choi wrote:
> On 12/5/19 12:00 AM, Kamil Konieczny wrote:
>> Add clearing transition table and time in states devfreq statistics
>> by writing to trans_stat file in devfreq sysfs.
>
> Have to add command example how to reset the trans_stat via sysfs
> on patch description.
>
> And, have to add how to do it on documentation file as following:
> On next version, please contain the following modification with this patch.
>
> diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq
> index 75897e2fde43..c172ff838643 100644
> --- a/Documentation/ABI/testing/sysfs-class-devfreq
> +++ b/Documentation/ABI/testing/sysfs-class-devfreq
> @@ -60,7 +60,10 @@ Description:
> the number of transitions between states.
> In order to activate this ABI, the devfreq target device
> driver should provide the list of available frequencies
> - with its profile.
> + with its profile. If need to reset the statistics of devfreq
> + behavior on a specific device, enter 0(zero) to 'trans_stat'
> + as following:
> + echo 0 > /sys/class/devfreq/.../trans_stat
>
> What: /sys/class/devfreq/.../userspace/set_freq
> Date: September 2011
Thank you for spotting this and giving patch, I will include it with v3.
>>
>> Signed-off-by: Kamil Konieczny <k.konieczny@samsung.com>
>> ---
>> Changes in v2:
>> instead of creating new sysfs file, add new functionality to trans_stat
>> and clear stats when anything is writen to it
>>
>> drivers/devfreq/devfreq.c | 22 +++++++++++++++++++++-
>> 1 file changed, 21 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>> index 0e2030403e4a..901af3b66a76 100644
>> --- a/drivers/devfreq/devfreq.c
>> +++ b/drivers/devfreq/devfreq.c
>> @@ -1478,7 +1478,27 @@ static ssize_t trans_stat_show(struct device *dev,
>> devfreq->total_trans);
>> return len;
>> }
>> -static DEVICE_ATTR_RO(trans_stat);
>> +
>> +static ssize_t trans_stat_store(struct device *dev,
>> + struct device_attribute *attr,
>> + const char *buf, size_t count)
>> +{
>> + struct devfreq *df = to_devfreq(dev);
>> + unsigned int cnt = df->profile->max_state;
>> +
> Why don't you check the input value is whether value is 0(zero) or not?
I will follow your suggestion as this will help to avoid misuse
> If user enter the any value to 'trans_stat', devfreq core
> reset the statistics data. I want to decide the fixed value
> for the reset as following:
>
> echo 0 > /sys/class/devfreq/devfreqX/trans_stat
>
Thank you, I will add it to commit description.
>> + if (cnt == 0)
>> + return count;
>> +
>> + mutex_lock(&df->lock);
>> + memset(df->time_in_state, 0, cnt * sizeof(u64));
>> + memset(df->trans_table, 0, cnt * cnt * sizeof(int));
>> + df->last_stat_updated = get_jiffies_64();
>> + df->total_trans = 0;
>> + mutex_unlock(&df->lock);
>> +
>> + return count;
>> +}
>> +static DEVICE_ATTR_RW(trans_stat);
>>
>> static struct attribute *devfreq_attrs[] = {
>> &dev_attr_name.attr,
--
Best regards,
Kamil Konieczny
Samsung R&D Institute Poland
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 3/3] devfreq: move statistics to separate struct
2019-12-05 0:28 ` Matthias Kaehlcke
@ 2019-12-05 14:18 ` Kamil Konieczny
0 siblings, 0 replies; 12+ messages in thread
From: Kamil Konieczny @ 2019-12-05 14:18 UTC (permalink / raw)
To: Matthias Kaehlcke
Cc: Bartlomiej Zolnierkiewicz, Chanwoo Choi, Krzysztof Kozlowski,
Kyungmin Park, linux-kernel, linux-pm, Marek Szyprowski,
MyungJoo Ham
Hi,
thank you for review, I will follow you suggestions in v3.
On 05.12.2019 01:28, Matthias Kaehlcke wrote:
> Hi,
>
> On Wed, Dec 04, 2019 at 04:00:18PM +0100, Kamil Konieczny wrote:
>> Count time and transitions between devfreq frequencies in separate struct
>> for improved code readability and maintenance.
>>
>> Signed-off-by: Kamil Konieczny <k.konieczny@samsung.com>
>> ---
>> Changes in v2:
>> squash three patches into one, do not modify devfreq_profile and separate stats
>> into devfreq_stats
>>
>> drivers/devfreq/devfreq.c | 68 +++++++++++++++++++++++----------------
>> include/linux/devfreq.h | 31 ++++++++++++------
>> 2 files changed, 62 insertions(+), 37 deletions(-)
>>
>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>> index 901af3b66a76..4d50c8f10bd2 100644
>> --- a/drivers/devfreq/devfreq.c
>> +++ b/drivers/devfreq/devfreq.c
>> @@ -198,6 +198,7 @@ static int set_freq_table(struct devfreq *devfreq)
>> */
>> int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
>> {
>> + struct devfreq_stats *stats = devfreq->stats;
>> int lev, prev_lev, ret = 0;
>> unsigned long long cur_time;
>>
>> @@ -214,8 +215,8 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
>> goto out;
>> }
>>
>> - devfreq->time_in_state[prev_lev] +=
>> - cur_time - devfreq->last_stat_updated;
>> + stats->time_in_state[prev_lev] +=
>> + cur_time - stats->last_stat_updated;
>>
>> lev = devfreq_get_freq_level(devfreq, freq);
>> if (lev < 0) {
>> @@ -224,13 +225,12 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
>> }
>>
>> if (lev != prev_lev) {
>> - devfreq->trans_table[(prev_lev *
>> - devfreq->profile->max_state) + lev]++;
>> - devfreq->total_trans++;
>> + stats->trans_table[(prev_lev * stats->max_state) + lev]++;
>> + stats->total_trans++;
>> }
>>
>> out:
>> - devfreq->last_stat_updated = cur_time;
>> + stats->last_stat_updated = cur_time;
>> return ret;
>> }
>> EXPORT_SYMBOL(devfreq_update_status);
>> @@ -525,7 +525,7 @@ void devfreq_monitor_resume(struct devfreq *devfreq)
>> msecs_to_jiffies(devfreq->profile->polling_ms));
>>
>> out_update:
>> - devfreq->last_stat_updated = get_jiffies_64();
>> + devfreq->stats->last_stat_updated = get_jiffies_64();
>> devfreq->stop_polling = false;
>>
>> if (devfreq->profile->get_cur_freq &&
>> @@ -735,28 +735,38 @@ struct devfreq *devfreq_add_device(struct device *dev,
>> goto err_out;
>> }
>>
>> - devfreq->trans_table = devm_kzalloc(&devfreq->dev,
>> + devfreq->stats = devm_kzalloc(&devfreq->dev, sizeof(*devfreq->stats),
>> + GFP_KERNEL);
>> + if (!devfreq->stats) {
>> + mutex_unlock(&devfreq->lock);
>> + err = -ENOMEM;
>> + goto err_devfreq;
>> + }
>> +
>> + devfreq->stats->freq_table = devfreq->profile->freq_table;
>> + devfreq->stats->max_state = devfreq->profile->max_state;
>> + devfreq->stats->trans_table = devm_kzalloc(&devfreq->dev,
>> array3_size(sizeof(unsigned int),
>> - devfreq->profile->max_state,
>> - devfreq->profile->max_state),
>> + devfreq->stats->max_state,
>> + devfreq->stats->max_state),
>> GFP_KERNEL);
>> - if (!devfreq->trans_table) {
>> + if (!devfreq->stats->trans_table) {
>> mutex_unlock(&devfreq->lock);
>> err = -ENOMEM;
>> goto err_devfreq;
>> }
>>
>> - devfreq->time_in_state = devm_kcalloc(&devfreq->dev,
>> - devfreq->profile->max_state,
>> - sizeof(*devfreq->time_in_state),
>> + devfreq->stats->time_in_state = devm_kcalloc(&devfreq->dev,
>> + devfreq->stats->max_state,
>> + sizeof(*devfreq->stats->time_in_state),
>> GFP_KERNEL);
>> - if (!devfreq->time_in_state) {
>> + if (!devfreq->stats->time_in_state) {
>> mutex_unlock(&devfreq->lock);
>> err = -ENOMEM;
>> goto err_devfreq;
>> }
>>
>> - devfreq->last_stat_updated = get_jiffies_64();
>> + devfreq->stats->last_stat_updated = get_jiffies_64();
>>
>> srcu_init_notifier_head(&devfreq->transition_notifier_list);
>>
>> @@ -1435,9 +1445,10 @@ static ssize_t trans_stat_show(struct device *dev,
>> struct device_attribute *attr, char *buf)
>> {
>> struct devfreq *devfreq = to_devfreq(dev);
>> + struct devfreq_stats *stats = devfreq->stats;
>> + unsigned int max_state = stats->max_state;
>> ssize_t len;
>> int i, j;
>> - unsigned int max_state = devfreq->profile->max_state;
>>
>> if (max_state == 0)
>> return sprintf(buf, "Not Supported.\n");
>> @@ -1454,28 +1465,28 @@ static ssize_t trans_stat_show(struct device *dev,
>> len += sprintf(buf + len, " :");
>> for (i = 0; i < max_state; i++)
>> len += sprintf(buf + len, "%10lu",
>> - devfreq->profile->freq_table[i]);
>> + stats->freq_table[i]);
>>
>> len += sprintf(buf + len, " time(ms)\n");
>>
>> for (i = 0; i < max_state; i++) {
>> - if (devfreq->profile->freq_table[i]
>> + if (stats->freq_table[i]
>> == devfreq->previous_freq) {
>> len += sprintf(buf + len, "*");
>> } else {
>> len += sprintf(buf + len, " ");
>> }
>> len += sprintf(buf + len, "%10lu:",
>> - devfreq->profile->freq_table[i]);
>> + stats->freq_table[i]);
>> for (j = 0; j < max_state; j++)
>> len += sprintf(buf + len, "%10u",
>> - devfreq->trans_table[(i * max_state) + j]);
>> + stats->trans_table[(i * max_state) + j]);
>> len += sprintf(buf + len, "%10llu\n", (u64)
>> - jiffies64_to_msecs(devfreq->time_in_state[i]));
>> + jiffies64_to_msecs(stats->time_in_state[i]));
>> }
>>
>> len += sprintf(buf + len, "Total transition : %u\n",
>> - devfreq->total_trans);
>> + stats->total_trans);
>> return len;
>> }
>>
>> @@ -1484,16 +1495,17 @@ static ssize_t trans_stat_store(struct device *dev,
>> const char *buf, size_t count)
>> {
>> struct devfreq *df = to_devfreq(dev);
>> - unsigned int cnt = df->profile->max_state;
>> + struct devfreq_stats *stats = df->stats;
>> + unsigned int cnt = stats->max_state;
>>
>> if (cnt == 0)
>> return count;
>>
>> mutex_lock(&df->lock);
>> - memset(df->time_in_state, 0, cnt * sizeof(u64));
>> - memset(df->trans_table, 0, cnt * cnt * sizeof(int));
>> - df->last_stat_updated = get_jiffies_64();
>> - df->total_trans = 0;
>> + memset(stats->time_in_state, 0, cnt * sizeof(u64));
>> + memset(stats->trans_table, 0, cnt * cnt * sizeof(int));
>> + stats->last_stat_updated = get_jiffies_64();
>> + stats->total_trans = 0;
>> mutex_unlock(&df->lock);
>>
>> return count;
>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>> index b81a86e47fb9..2715719924e7 100644
>> --- a/include/linux/devfreq.h
>> +++ b/include/linux/devfreq.h
>> @@ -106,6 +106,25 @@ struct devfreq_dev_profile {
>> unsigned int max_state;
>> };
>>
>> +/**
>> + * struct devfreq_stats - Devfreq's transitions stats counters
>> + * @freq_table: List of frequencies in ascending order.
>> + * @max_state: The size of freq_table.
>> + * @total_trans: Number of devfreq transitions.
>> + * @trans_table: Statistics of devfreq transitions.
>> + * @time_in_state: Statistics of devfreq states.
>> + * @last_stat_updated: The last time stats were updated.
>> + */
>> +struct devfreq_stats {
>> + unsigned long *freq_table;
>
> nit: trans_stat_show() is the only place where 'freq_table' is
> used. Instead of 'duplicating' it (I know, it's just a pointer)
> you could use a local pointer 'freq_table' in trans_stat_show().
>
>> + unsigned int max_state;
>
> nit: max_state is also a bit of a corner case. It's not really a 'stat' and
> it is already available in struct devfreq_dev_profile, it doesn't seem a
> huge inconvenient to take it from there.
Good hints, I will change this.
>> +
>> + unsigned int total_trans;
>> + unsigned int *trans_table;
>> + u64 *time_in_state;
>> + unsigned long long last_stat_updated;
>
> nit: the name 'last_stat_updated' is somewhat redundant, since the
> field is part of a struct called 'devfreq_stats'. 'last_updated' or
> 'last_update' would be concise enough IMO.
This is also good hint.
>> +};
>> +
>> /**
>> * struct devfreq - Device devfreq structure
>> * @node: list node - contains the devices with devfreq that have been
>> @@ -131,10 +150,7 @@ struct devfreq_dev_profile {
>> * @suspend_freq: frequency of a device set during suspend phase.
>> * @resume_freq: frequency of a device set in resume phase.
>> * @suspend_count: suspend requests counter for a device.
>> - * @total_trans: Number of devfreq transitions
>> - * @trans_table: Statistics of devfreq transitions
>> - * @time_in_state: Statistics of devfreq states
>> - * @last_stat_updated: The last time stat updated
>> + * @stats: Statistics of devfreq transitions and states times
>> * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>> *
>> * This structure stores the devfreq information for a give device.
>> @@ -171,11 +187,8 @@ struct devfreq {
>> unsigned long resume_freq;
>> atomic_t suspend_count;
>>
>> - /* information for device frequency transition */
>> - unsigned int total_trans;
>> - unsigned int *trans_table;
>> - u64 *time_in_state;
>> - unsigned long long last_stat_updated;
>> + /* information for device frequency transitions */
>> + struct devfreq_stats *stats;
>>
>> struct srcu_notifier_head transition_notifier_list;
>> };
>
> My comments above are just suggestions:
>
> Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
--
Best regards,
Kamil Konieczny
Samsung R&D Institute Poland
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 3/3] devfreq: move statistics to separate struct
2019-12-05 1:46 ` Chanwoo Choi
@ 2019-12-05 14:30 ` Kamil Konieczny
0 siblings, 0 replies; 12+ messages in thread
From: Kamil Konieczny @ 2019-12-05 14:30 UTC (permalink / raw)
To: Chanwoo Choi
Cc: Bartlomiej Zolnierkiewicz, Krzysztof Kozlowski, Kyungmin Park,
linux-kernel, linux-pm, Marek Szyprowski, MyungJoo Ham
Hi Chanwoo,
On 05.12.2019 02:46, Chanwoo Choi wrote:
> On 12/5/19 12:00 AM, Kamil Konieczny wrote:
>> Count time and transitions between devfreq frequencies in separate struct
>> for improved code readability and maintenance.
>>
>> Signed-off-by: Kamil Konieczny <k.konieczny@samsung.com>
>> ---
>> Changes in v2:
>> squash three patches into one, do not modify devfreq_profile and separate stats
>> into devfreq_stats
>>
>> drivers/devfreq/devfreq.c | 68 +++++++++++++++++++++++----------------
>> include/linux/devfreq.h | 31 ++++++++++++------
>> 2 files changed, 62 insertions(+), 37 deletions(-)
>>
>> diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
>> index 901af3b66a76..4d50c8f10bd2 100644
>> --- a/drivers/devfreq/devfreq.c
>> +++ b/drivers/devfreq/devfreq.c
>> @@ -198,6 +198,7 @@ static int set_freq_table(struct devfreq *devfreq)
>> */
>> int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
>> {
>> + struct devfreq_stats *stats = devfreq->stats;
>> int lev, prev_lev, ret = 0;
>> unsigned long long cur_time;
>>
>> @@ -214,8 +215,8 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
>> goto out;
>> }
>>
>> - devfreq->time_in_state[prev_lev] +=
>> - cur_time - devfreq->last_stat_updated;
>> + stats->time_in_state[prev_lev] +=
>> + cur_time - stats->last_stat_updated;
>>
>> lev = devfreq_get_freq_level(devfreq, freq);
>> if (lev < 0) {
>> @@ -224,13 +225,12 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
>> }
>>
>> if (lev != prev_lev) {
>> - devfreq->trans_table[(prev_lev *
>> - devfreq->profile->max_state) + lev]++;
>> - devfreq->total_trans++;
>> + stats->trans_table[(prev_lev * stats->max_state) + lev]++;
>> + stats->total_trans++;
>> }
>>
>> out:
>> - devfreq->last_stat_updated = cur_time;
>> + stats->last_stat_updated = cur_time;
>> return ret;
>> }
>> EXPORT_SYMBOL(devfreq_update_status);
>> @@ -525,7 +525,7 @@ void devfreq_monitor_resume(struct devfreq *devfreq)
>> msecs_to_jiffies(devfreq->profile->polling_ms));
>>
>> out_update:
>> - devfreq->last_stat_updated = get_jiffies_64();
>> + devfreq->stats->last_stat_updated = get_jiffies_64();
>> devfreq->stop_polling = false;
>>
>> if (devfreq->profile->get_cur_freq &&
>> @@ -735,28 +735,38 @@ struct devfreq *devfreq_add_device(struct device *dev,
>> goto err_out;
>> }
>>
>> - devfreq->trans_table = devm_kzalloc(&devfreq->dev,
>> + devfreq->stats = devm_kzalloc(&devfreq->dev, sizeof(*devfreq->stats),
>> + GFP_KERNEL);
>
> Each devfreq has only one stats structure always. Don't need to define
> it with pointer type. It is enough to define as following without pointer type:
>
> struct devfreq_stats stats;
>
Good point, I will change this.
>> + if (!devfreq->stats) {
>> + mutex_unlock(&devfreq->lock);
>> + err = -ENOMEM;
>> + goto err_devfreq;
>> + }
>> +
>> + devfreq->stats->freq_table = devfreq->profile->freq_table;
>> + devfreq->stats->max_state = devfreq->profile->max_state;
>> + devfreq->stats->trans_table = devm_kzalloc(&devfreq->dev,
>> array3_size(sizeof(unsigned int),
>> - devfreq->profile->max_state,
>> - devfreq->profile->max_state),
>> + devfreq->stats->max_state,
>> + devfreq->stats->max_state),
>> GFP_KERNEL);
>> - if (!devfreq->trans_table) {
>> + if (!devfreq->stats->trans_table) {
>> mutex_unlock(&devfreq->lock);
>> err = -ENOMEM;
>> goto err_devfreq;
>> }
>>
>> - devfreq->time_in_state = devm_kcalloc(&devfreq->dev,
>> - devfreq->profile->max_state,
>> - sizeof(*devfreq->time_in_state),
>> + devfreq->stats->time_in_state = devm_kcalloc(&devfreq->dev,
>> + devfreq->stats->max_state,
>> + sizeof(*devfreq->stats->time_in_state),
>> GFP_KERNEL);
>
> Actually, this patch will be conflict with patch[1].
> [1] https://www.spinics.net/lists/arm-kernel/msg768822.html
>
> First of all, I have to merge patches[1][2] for the devfreq pm-qos
> during v5.5-rc period. It requires the linux-pm's maintainer.
> [2] https://www.spinics.net/lists/arm-kernel/msg769761.html
>
> After finishing the job[1][2], I'll merge this patch
> if finished the review of this patch. Just share the possible merge
> conflict to you.
>
Ok, I will rebase and send when you will need this,
please remind me when it happens.
>
>> - if (!devfreq->time_in_state) {
>> + if (!devfreq->stats->time_in_state) {
>> mutex_unlock(&devfreq->lock);
>> err = -ENOMEM;
>> goto err_devfreq;
>> }
>>
>> - devfreq->last_stat_updated = get_jiffies_64();
>> + devfreq->stats->last_stat_updated = get_jiffies_64();
>>
>> srcu_init_notifier_head(&devfreq->transition_notifier_list);
>>
>> @@ -1435,9 +1445,10 @@ static ssize_t trans_stat_show(struct device *dev,
>> struct device_attribute *attr, char *buf)
>> {
>> struct devfreq *devfreq = to_devfreq(dev);
>> + struct devfreq_stats *stats = devfreq->stats;
>> + unsigned int max_state = stats->max_state;
>> ssize_t len;
>> int i, j;
>> - unsigned int max_state = devfreq->profile->max_state;
>>
>> if (max_state == 0)
>> return sprintf(buf, "Not Supported.\n");
>> @@ -1454,28 +1465,28 @@ static ssize_t trans_stat_show(struct device *dev,
>> len += sprintf(buf + len, " :");
>> for (i = 0; i < max_state; i++)
>> len += sprintf(buf + len, "%10lu",
>> - devfreq->profile->freq_table[i]);
>> + stats->freq_table[i]);
>>
>> len += sprintf(buf + len, " time(ms)\n");
>>
>> for (i = 0; i < max_state; i++) {
>> - if (devfreq->profile->freq_table[i]
>> + if (stats->freq_table[i]
>> == devfreq->previous_freq) {
>> len += sprintf(buf + len, "*");
>> } else {
>> len += sprintf(buf + len, " ");
>> }
>> len += sprintf(buf + len, "%10lu:",
>> - devfreq->profile->freq_table[i]);
>> + stats->freq_table[i]);
>> for (j = 0; j < max_state; j++)
>> len += sprintf(buf + len, "%10u",
>> - devfreq->trans_table[(i * max_state) + j]);
>> + stats->trans_table[(i * max_state) + j]);
>> len += sprintf(buf + len, "%10llu\n", (u64)
>> - jiffies64_to_msecs(devfreq->time_in_state[i]));
>> + jiffies64_to_msecs(stats->time_in_state[i]));
>> }
>>
>> len += sprintf(buf + len, "Total transition : %u\n",
>> - devfreq->total_trans);
>> + stats->total_trans);
>> return len;
>> }
>>
>> @@ -1484,16 +1495,17 @@ static ssize_t trans_stat_store(struct device *dev,
>> const char *buf, size_t count)
>> {
>> struct devfreq *df = to_devfreq(dev);
>> - unsigned int cnt = df->profile->max_state;
>> + struct devfreq_stats *stats = df->stats;
>> + unsigned int cnt = stats->max_state;
>>
>> if (cnt == 0)
>> return count;
>>
>> mutex_lock(&df->lock);
>> - memset(df->time_in_state, 0, cnt * sizeof(u64));
>> - memset(df->trans_table, 0, cnt * cnt * sizeof(int));
>> - df->last_stat_updated = get_jiffies_64();
>> - df->total_trans = 0;
>> + memset(stats->time_in_state, 0, cnt * sizeof(u64));
>> + memset(stats->trans_table, 0, cnt * cnt * sizeof(int));
>> + stats->last_stat_updated = get_jiffies_64();
>> + stats->total_trans = 0;
>> mutex_unlock(&df->lock);
>>
>> return count;
>> diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
>> index b81a86e47fb9..2715719924e7 100644
>> --- a/include/linux/devfreq.h
>> +++ b/include/linux/devfreq.h
>> @@ -106,6 +106,25 @@ struct devfreq_dev_profile {
>> unsigned int max_state;
>> };
>>
>> +/**
>> + * struct devfreq_stats - Devfreq's transitions stats counters
>
> Devfreq's transitions stats counters -> Statistics of devfreq device behavior
Thanks, changed.
>> + * @freq_table: List of frequencies in ascending order.
>> + * @max_state: The size of freq_table.
>> + * @total_trans: Number of devfreq transitions.
>> + * @trans_table: Statistics of devfreq transitions.
>> + * @time_in_state: Statistics of devfreq states.
>> + * @last_stat_updated: The last time stats were updated.
>> + */
>> +struct devfreq_stats {
>> + unsigned long *freq_table;
>> + unsigned int max_state;
>
> Acutally, I'm sorry I has not yet completely agreed to move
> 'freq_table and 'max_state' from struct devfreq to struct devfreq_stats.
> It has not any critical benefit and any problem.
> So, don't move 'freq_table' and 'max_state'.
I removed these two from devfreq_stats and use devfreq->profile as in original
devfreq code.
>
>> +
>> + unsigned int total_trans;
>> + unsigned int *trans_table;
>> + u64 *time_in_state;
>> + unsigned long long last_stat_updated;
>> +};
>> +
>> /**
>> * struct devfreq - Device devfreq structure
>> * @node: list node - contains the devices with devfreq that have been
>> @@ -131,10 +150,7 @@ struct devfreq_dev_profile {
>> * @suspend_freq: frequency of a device set during suspend phase.
>> * @resume_freq: frequency of a device set in resume phase.
>> * @suspend_count: suspend requests counter for a device.
>> - * @total_trans: Number of devfreq transitions
>> - * @trans_table: Statistics of devfreq transitions
>> - * @time_in_state: Statistics of devfreq states
>> - * @last_stat_updated: The last time stat updated
>> + * @stats: Statistics of devfreq transitions and states times
>
> Statistics of devfreq transitions and states times
> -> Statistics of devfreq device behavior
>
Ok.
>> * @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
>> *
>> * This structure stores the devfreq information for a give device.
>> @@ -171,11 +187,8 @@ struct devfreq {
>> unsigned long resume_freq;
>> atomic_t suspend_count;
>>
>> - /* information for device frequency transition */
>> - unsigned int total_trans;
>> - unsigned int *trans_table;
>> - u64 *time_in_state;
>> - unsigned long long last_stat_updated;
>> + /* information for device frequency transitions */
>> + struct devfreq_stats *stats;
>
> Each devfreq has only one stats structure always. Don't need to define
> it with pointer type. It is enough to define as following without pointer type:
>
> struct devfreq_stats stats;
>
>>
>> struct srcu_notifier_head transition_notifier_list;
>> };
>>
--
Best regards,
Kamil Konieczny
Samsung R&D Institute Poland
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2019-12-05 14:31 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <CGME20191204150032eucas1p1c10713b3308e45e086dd66099057e2b6@eucas1p1.samsung.com>
2019-12-04 15:00 ` [PATCH v2 0/3] devfreq: improve devfreq statistics counting Kamil Konieczny
[not found] ` <CGME20191204150033eucas1p1bf11d36a89c89e3eb55c37a1a204e988@eucas1p1.samsung.com>
2019-12-04 15:00 ` [PATCH v2 1/3] devfreq: change time stats to 64-bit Kamil Konieczny
2019-12-05 0:27 ` Chanwoo Choi
2019-12-05 9:58 ` Kamil Konieczny
[not found] ` <CGME20191204150033eucas1p164374e7f15cb9a74b7432ca1a822dc10@eucas1p1.samsung.com>
2019-12-04 15:00 ` [PATCH v2 2/3] devfreq: add clearing transitions stats Kamil Konieczny
2019-12-05 0:38 ` Chanwoo Choi
2019-12-05 10:33 ` Kamil Konieczny
[not found] ` <CGME20191204150034eucas1p1b6e7f43a6be59ed2e0a4e55ccdefc750@eucas1p1.samsung.com>
2019-12-04 15:00 ` [PATCH v2 3/3] devfreq: move statistics to separate struct Kamil Konieczny
2019-12-05 0:28 ` Matthias Kaehlcke
2019-12-05 14:18 ` Kamil Konieczny
2019-12-05 1:46 ` Chanwoo Choi
2019-12-05 14:30 ` Kamil Konieczny
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).