All of lore.kernel.org
 help / color / mirror / Atom feed
* [Powertop] [PATCH] devfreq: add devfreq devices stats support
@ 2014-08-25  6:58 Sanjay Singh Rawat
  0 siblings, 0 replies; 13+ messages in thread
From: Sanjay Singh Rawat @ 2014-08-25  6:58 UTC (permalink / raw)
  To: powertop

[-- Attachment #1: Type: text/plain, Size: 14235 bytes --]

add window to show frequency stats for devfreq devices

Signed-off-by: Rajagopal Venkat <rajagopal.venkat(a)gmail.com>
Signed-off-by: Sanjay Singh Rawat <sanjay.rawat(a)linaro.org>
---
 src/Makefile.am           |   2 +-
 src/devices/devfreq.cpp   | 351 ++++++++++++++++++++++++++++++++++++++++++++++
 src/devices/devfreq.h     |  75 ++++++++++
 src/main.cpp              |   9 ++
 src/report/report-maker.h |   1 +
 5 files changed, 437 insertions(+), 1 deletion(-)
 create mode 100644 src/devices/devfreq.cpp
 create mode 100644 src/devices/devfreq.h

diff --git a/src/Makefile.am b/src/Makefile.am
index 6886388..fee1ffa 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -32,7 +32,7 @@ powertop_SOURCES = parameters/persistent.cpp parameters/learn.cpp parameters/par
 		report/report-formatter-csv.cpp report/report-formatter-csv.h \
 		report/report-formatter-html.cpp report/report-formatter-html.h \
 		report/report-data-html.cpp report/report-data-html.h \
-		main.cpp css.h powertop.css cpu/intel_gpu.cpp \
+		main.cpp css.h powertop.css cpu/intel_gpu.cpp devices/devfreq.cpp \
 		cpu/rapl/rapl_interface.cpp cpu/cpu_rapl_device.cpp cpu/rapl/rapl_interface.h\
 		cpu/dram_rapl_device.cpp devices/gpu_rapl_device.cpp cpu/cpu_rapl_device.h \
 		cpu/dram_rapl_device.h devices/gpu_rapl_device.h
diff --git a/src/devices/devfreq.cpp b/src/devices/devfreq.cpp
new file mode 100644
index 0000000..29d7790
--- /dev/null
+++ b/src/devices/devfreq.cpp
@@ -0,0 +1,351 @@
+/*
+ * Copyright 2012, Linaro
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *	Rajagopal Venkat <rajagopal.venkat(a)linaro.org>
+ */
+
+#include <iostream>
+#include <fstream>
+
+#include <dirent.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "device.h"
+#include "devfreq.h"
+#include "../display.h"
+#include "../cpu/cpu.h"
+#include "../report/report.h"
+#include "../report/report-maker.h"
+
+static bool is_enabled = true;
+
+static vector<class devfreq *> all_devfreq;
+
+devfreq::devfreq(const char* dpath): device()
+{
+	strncpy(dir_name, dpath, sizeof(dir_name));
+}
+
+uint64_t devfreq::parse_freq_time(char* pchr)
+{
+	char *cptr, *pptr = pchr;
+	uint64_t ctime;
+
+	cptr = strtok(pchr, " :");
+	while (cptr != NULL) {
+		cptr = strtok(NULL, " :");
+		if (cptr )
+			pptr = cptr;
+	}
+
+	ctime = strtoull(pptr, NULL, 10);
+	return ctime;
+}
+
+void devfreq::process_time_stamps()
+{
+	unsigned int i;
+	uint64_t active_time = 0;
+
+	sample_time = (1000000.0 * (stamp_after.tv_sec - stamp_before.tv_sec))
+			+ ((stamp_after.tv_usec - stamp_before.tv_usec) );
+
+	for (i=0; i < dstates.size()-1; i++) {
+		struct frequency *state = dstates[i];
+		state->time_after = 1000 * (state->time_after - state->time_before);
+		active_time += state->time_after;
+	}
+	/* Compute idle time for the device */
+	dstates[i]->time_after = sample_time - active_time;
+}
+
+void devfreq::add_devfreq_freq_state(uint64_t freq, uint64_t time)
+{
+	struct frequency *state;
+
+	state = new(std::nothrow) struct frequency;
+	if (!state)
+		return;
+
+	memset(state, 0, sizeof(*state));
+	dstates.push_back(state);
+
+	state->freq = freq;
+	if (freq == 0)
+		strcpy(state->human_name, "Idle");
+	else
+		hz_to_human(freq, state->human_name);
+	state->time_before = time;
+}
+
+void devfreq::update_devfreq_freq_state(uint64_t freq, uint64_t time)
+{
+	unsigned int i;
+	struct frequency *state = NULL;
+
+	for(i=0; i < dstates.size(); i++) {
+		if (freq == dstates[i]->freq)
+			state = dstates[i];
+	}
+
+	if (state == NULL) {
+		add_devfreq_freq_state(freq, time);
+		return;
+	}
+
+	state->time_after = time;
+}
+
+void devfreq::parse_devfreq_trans_stat(char *dname)
+{
+	ifstream file;
+	char filename[256];
+
+	sprintf(filename, "/sys/class/devfreq/%s/trans_stat", dir_name);
+	file.open(filename);
+
+	if (!file)
+		return;
+
+	char line[1024];
+	char *c;
+
+	while (file) {
+		uint64_t freq;
+		uint64_t time;
+		char *pchr;
+
+		memset(line, 0, sizeof(line));
+		file.getline(line, sizeof(line));
+
+		pchr = strchr(line, '*');
+		pchr = (pchr != NULL) ? pchr+1 : line;
+
+		freq = strtoull(pchr, &c, 10);
+		if (!freq)
+			continue;
+
+		time = parse_freq_time(pchr);
+		update_devfreq_freq_state(freq, time);
+	}
+	file.close();
+}
+
+void devfreq::start_measurement(void)
+{
+	unsigned int i;
+	ifstream file;
+
+	for (i=0; i < dstates.size(); i++)
+		delete dstates[i];
+	dstates.resize(0);
+	sample_time = 0;
+
+	gettimeofday(&stamp_before, NULL);
+	parse_devfreq_trans_stat(dir_name);
+	/* add device idle state */
+	update_devfreq_freq_state(0, 0);
+}
+
+void devfreq::end_measurement(void)
+{
+	parse_devfreq_trans_stat(dir_name);
+	gettimeofday(&stamp_after, NULL);
+	process_time_stamps();
+}
+
+double devfreq::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+	return 0;
+}
+
+double devfreq::utilization(void)
+{
+	return 0;
+}
+
+void devfreq::fill_freq_utilization(unsigned int idx, char *buf)
+{
+	buf[0] = 0;
+
+	if (idx < dstates.size() && dstates[idx]) {
+		struct frequency *state = dstates[idx];
+		sprintf(buf, " %5.1f%% ", percentage(1.0 * state->time_after / sample_time));
+	}
+}
+
+void devfreq::fill_freq_name(unsigned int idx, char *buf)
+{
+	buf[0] = 0;
+
+	if (idx < dstates.size() && dstates[idx]) {
+		sprintf(buf, "%-15s", dstates[idx]->human_name);
+	}
+}
+
+void start_devfreq_measurement(void)
+{
+	unsigned int i;
+
+	for (i=0; i<all_devfreq.size(); i++)
+		all_devfreq[i]->start_measurement();
+}
+
+void end_devfreq_measurement(void)
+{
+	unsigned int i;
+
+	for (i=0; i<all_devfreq.size(); i++)
+		all_devfreq[i]->end_measurement();
+}
+
+static void devfreq_dev_callback(const char *d_name)
+{
+	devfreq *df = new(std::nothrow) class devfreq(d_name);
+	if (df)
+		all_devfreq.push_back(df);
+}
+
+void create_all_devfreq_devices(void)
+{
+	DIR *dir;
+	std::string p = "/sys/class/devfreq/";
+	dir = opendir(p.c_str());
+	if (dir == NULL) {
+		fprintf(stderr, "Devfreq not enabled\n");
+		is_enabled = false;
+		return;
+	}
+
+	callback fn = &devfreq_dev_callback;
+	process_directory(p.c_str(), fn);
+}
+
+void initialize_devfreq(void)
+{
+	if (is_enabled)
+		create_tab("Device Freq stats", _("Device Freq stats"));
+}
+
+void display_devfreq_devices(void)
+{
+	unsigned int i, j;
+	WINDOW *win;
+	char fline[1024];
+	char buf[128];
+
+	win = get_ncurses_win("Device Freq stats");
+        if (!win)
+                return;
+
+        wclear(win);
+        wmove(win, 2,0);
+
+	if (!is_enabled) {
+		wprintw(win, _(" Devfreq is not enabled"));
+		return;
+	}
+
+	if (!all_devfreq.size()) {
+		wprintw(win, _(" No devfreq devices available"));
+		return;
+	}
+
+	for (i=0; i<all_devfreq.size(); i++) {
+
+		class devfreq *df = all_devfreq[i];
+		wprintw(win, "\n%s\n", df->device_name());
+
+		for(j=0; j < df->dstates.size(); j++) {
+			memset(fline, 0, sizeof(fline));
+			strcpy(fline, "\t");
+			df->fill_freq_name(j, buf);
+			strcat(fline, buf);
+			df->fill_freq_utilization(j, buf);
+			strcat(fline, buf);
+			strcat(fline, "\n");
+			wprintw(win, fline);
+		}
+		wprintw(win, "\n");
+	}
+}
+
+void report_devfreq_devices(void)
+{
+	if (!is_enabled) {
+		return;
+	}
+
+/* todo: adapt to new report format */
+#if 0
+	char buffer[512];
+	unsigned int i, j;
+
+	report.begin_section(SECTION_DEVFREQ);
+	report.add_header("Device Frequency Report");
+
+	report.begin_table(TABLE_WIDE);
+	if (!all_devfreq.size()) {
+		report.begin_row();
+		report.add(" No devfreq devices available");
+		return;
+	}
+
+	for (i = 0; i < all_devfreq.size(); i++) {
+		buffer[0] = 0;
+		class devfreq *df = all_devfreq[i];
+
+		report.begin_row();
+		report.begin_cell(CELL_CPU_PSTATE_HEADER);
+		report.addf("%s", df->device_name());
+
+		for (j = 0; j < df->dstates.size(); j++) {
+			report.begin_row();
+			report.begin_cell(CELL_CPU_STATE_VALUE);
+			df->fill_freq_name(j, buffer);
+			report.add(buffer);
+			report.begin_cell(CELL_CPU_STATE_VALUE);
+			df->fill_freq_utilization(j, buffer);
+			report.add(buffer);
+		}
+	}
+#endif
+
+}
+
+void clear_all_devfreq()
+{
+	unsigned int i, j;
+
+	for (i=0; i < all_devfreq.size(); i++) {
+		class devfreq *df = all_devfreq[i];
+
+		for(j=0; j < df->dstates.size(); j++)
+			delete df->dstates[j];
+
+		df->dstates.resize(0);
+		delete df;
+	}
+	all_devfreq.clear();
+}
diff --git a/src/devices/devfreq.h b/src/devices/devfreq.h
new file mode 100644
index 0000000..8ab5705
--- /dev/null
+++ b/src/devices/devfreq.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2012, Linaro
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *	Rajagopal Venkat <rajagopal.venkat(a)linaro.org>
+ */
+#ifndef _INCLUDE_GUARD_DEVFREQ_H
+#define _INCLUDE_GUARD_DEVFREQ_H
+
+#include "device.h"
+#include "../parameters/parameters.h"
+
+struct frequency;
+
+class devfreq: public device {
+	char dir_name[4096];
+	struct timeval  stamp_before, stamp_after;
+	double sample_time;
+
+	uint64_t parse_freq_time(char *ptr);
+	void add_devfreq_freq_state(uint64_t freq, uint64_t time);
+	void update_devfreq_freq_state(uint64_t freq, uint64_t time);
+	void parse_devfreq_trans_stat(char *dname);
+	void process_time_stamps();
+
+public:
+
+	vector<struct frequency *> dstates;
+
+	devfreq(const char *c);
+	void fill_freq_utilization(unsigned int idx, char *buf);
+	void fill_freq_name(unsigned int idx, char *buf);
+
+	virtual void start_measurement(void);
+	virtual void end_measurement(void);
+
+	virtual double	utilization(void); /* percentage */
+
+	virtual const char * class_name(void) { return "devfreq";};
+
+	virtual const char * device_name(void) { return dir_name;};
+	virtual const char * human_name(void) { return "devfreq";};
+	virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+	virtual const char * util_units(void) { return " rpm"; };
+	virtual int power_valid(void) { return 0; /*utilization_power_valid(r_index);*/};
+	virtual int grouping_prio(void) { return 1; };
+};
+
+extern void create_all_devfreq_devices(void);
+extern void clear_all_devfreq(void);
+extern void display_devfreq_devices(void);
+extern void report_devfreq_devices(void);
+extern void initialize_devfreq(void);
+extern void start_devfreq_measurement(void);
+extern void end_devfreq_measurement(void);
+
+#endif
diff --git a/src/main.cpp b/src/main.cpp
index cf4e547..d33eaed 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -48,6 +48,7 @@
 
 
 #include "devices/device.h"
+#include "devices/devfreq.h"
 #include "devices/usb.h"
 #include "devices/ahci.h"
 #include "measurement/measurement.h"
@@ -194,6 +195,7 @@ void one_measurement(int seconds, char *workload)
 	create_all_usb_devices();
 	start_power_measurement();
 	devices_start_measurement();
+	start_devfreq_measurement();
 	start_process_measurement();
 	start_cpu_measurement();
 
@@ -206,6 +208,7 @@ void one_measurement(int seconds, char *workload)
 	end_cpu_measurement();
 	end_process_measurement();
 	collect_open_devices();
+	end_devfreq_measurement();
 	devices_end_measurement();
 	end_power_measurement();
 
@@ -233,6 +236,9 @@ void one_measurement(int seconds, char *workload)
 	report_show_open_devices();
 
 	report_devices();
+	display_devfreq_devices();
+	report_devfreq_devices();
+
 	ahci_create_device_stats_table();
 	store_results(measurement_time);
 	end_cpu_data();
@@ -344,6 +350,7 @@ static void powertop_init(void)
 
 	enumerate_cpus();
 	create_all_devices();
+	create_all_devfreq_devices();
 	detect_power_meters();
 
 	register_parameter("base power", 100, 0.5);
@@ -457,6 +464,7 @@ int main(int argc, char **argv)
 		exit(0);
 	}
 	init_display();
+	initialize_devfreq();
 	initialize_tuning();
 	/* first one is short to not let the user wait too long */
 	one_measurement(1, NULL);
@@ -491,6 +499,7 @@ int main(int argc, char **argv)
 
 	clean_open_devices();
 	clear_all_devices();
+	clear_all_devfreq();
 	clear_all_cpus();
 
 	return 0;
diff --git a/src/report/report-maker.h b/src/report/report-maker.h
index 423568a..bda4cef 100644
--- a/src/report/report-maker.h
+++ b/src/report/report-maker.h
@@ -89,6 +89,7 @@ enum section_type {
 	SECTION_SYSINFO,
 	SECTION_CPUIDLE,
 	SECTION_CPUFREQ,
+	SECTION_DEVFREQ,
 	SECTION_DEVPOWER,
 	SECTION_SOFTWARE,
 	SECTION_SUMMARY,
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [Powertop] [PATCH] devfreq: add devfreq devices stats support
@ 2014-10-10  9:43 Sanjay Singh Rawat
  0 siblings, 0 replies; 13+ messages in thread
From: Sanjay Singh Rawat @ 2014-10-10  9:43 UTC (permalink / raw)
  To: powertop

[-- Attachment #1: Type: text/plain, Size: 2541 bytes --]


On Thursday 02 October 2014 01:52 AM, Magnus Fromreide wrote:
> On Tue, Sep 30, 2014 at 12:04:54PM +0530, Sanjay Singh Rawat wrote:
>> add window to show frequency stats for devfreq devices
>>
>> Signed-off-by: Rajagopal Venkat <rajagopal.venkat(a)gmail.com>
>> Signed-off-by: Sanjay Singh Rawat <sanjay.rawat(a)linaro.org>
>> ---
>>
>> v2 - Show devfreq window on support basis. Check for empty devfreq
>>       directory.
>>     - Free the open dirp while exiting.
>> ---
>>   src/Makefile.am           |   1 +
>>   src/devices/devfreq.cpp   | 367 ++++++++++++++++++++++++++++++++++++++++++++++
>>   src/devices/devfreq.h     |  75 ++++++++++
>>   src/main.cpp              |   9 ++
>>   src/report/report-maker.h |   1 +
>>   5 files changed, 453 insertions(+)
>>   create mode 100644 src/devices/devfreq.cpp
>>   create mode 100644 src/devices/devfreq.h
>>
>> diff --git a/src/Makefile.am b/src/Makefile.am
>> index 311b75e..d2f1da7 100644
>> --- a/src/Makefile.am
>> +++ b/src/Makefile.am
>> @@ -39,6 +39,7 @@ powertop_SOURCES = \
>>   	devices/alsa.h \
>>   	devices/backlight.cpp \
>>   	devices/backlight.h \
>> +	devices/devfreq.cpp \
>>   	devices/device.cpp \
>>   	devices/device.h \
>>   	devices/gpu_rapl_device.cpp \
>> diff --git a/src/devices/devfreq.cpp b/src/devices/devfreq.cpp
>> new file mode 100644
>> index 0000000..3eb63e5
>> --- /dev/null
>> +++ b/src/devices/devfreq.cpp
>> @@ -0,0 +1,367 @@
> ...
>> +/* todo: adapt to new report format */
>> +#if 0
> Do it, or at least do not commit big #if 0-blocks.

ack
>
>> +	char buffer[512];
>> +	unsigned int i, j;
>> +
>> +	report.begin_section(SECTION_DEVFREQ);
>> +	report.add_header("Device Frequency Report");
>> +
>> +	report.begin_table(TABLE_WIDE);
>> +	if (!all_devfreq.size()) {
>> +		report.begin_row();
>> +		report.add(" No devfreq devices available");
>> +		return;
>> +	}
>> +
>> +	for (i = 0; i < all_devfreq.size(); i++) {
>> +		buffer[0] = 0;
>> +		class devfreq *df = all_devfreq[i];
>> +
>> +		report.begin_row();
>> +		report.begin_cell(CELL_CPU_PSTATE_HEADER);
>> +		report.addf("%s", df->device_name());
>> +
>> +		for (j = 0; j < df->dstates.size(); j++) {
>> +			report.begin_row();
>> +			report.begin_cell(CELL_CPU_STATE_VALUE);
>> +			df->fill_freq_name(j, buffer);
>> +			report.add(buffer);
>> +			report.begin_cell(CELL_CPU_STATE_VALUE);
>> +			df->fill_freq_utilization(j, buffer);
>> +			report.add(buffer);
>> +		}
>> +	}
>> +#endif
> /MF

-- 
sanjay


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Powertop] [PATCH] devfreq: add devfreq devices stats support
@ 2014-10-10  9:42 Sanjay Singh Rawat
  0 siblings, 0 replies; 13+ messages in thread
From: Sanjay Singh Rawat @ 2014-10-10  9:42 UTC (permalink / raw)
  To: powertop

[-- Attachment #1: Type: text/plain, Size: 1876 bytes --]

thanks for the review Sergey

On Wednesday 01 October 2014 08:42 PM, Sergey Senozhatsky wrote:
> On (09/30/14 12:04), Sanjay Singh Rawat wrote:
>> add window to show frequency stats for devfreq devices
>>
>> Signed-off-by: Rajagopal Venkat <rajagopal.venkat(a)gmail.com>
>> Signed-off-by: Sanjay Singh Rawat <sanjay.rawat(a)linaro.org>
>> ---
>>
>> v2 - Show devfreq window on support basis. Check for empty devfreq
>>       directory.
>>     - Free the open dirp while exiting.
>> ---
>>   src/Makefile.am           |   1 +
>>   src/devices/devfreq.cpp   | 367 ++++++++++++++++++++++++++++++++++++++++++++++
>>   src/devices/devfreq.h     |  75 ++++++++++
>>   src/main.cpp              |   9 ++
[...]
>> +	file.close();
>> +}
>> +
>> +void devfreq::start_measurement(void)
>> +{
>> +	unsigned int i;
>> +	ifstream file;
> not needed.

ack
>
[...]
>> +		is_enabled = false;
>> +		closedir(dir);
>> +		return;
>> +	}
> who close the dir if `num != 2'?

the dir is closed in the clear_all_devfreq() function while exiting
>
>> +	callback fn = &devfreq_dev_callback;
>> +	process_directory(p.c_str(), fn);
>> +}
>> +
>> +void initialize_devfreq(void)
[...]
>> +
>> +void clear_all_devfreq()
>> +{
>> +	unsigned int i, j;
>> +
>> +	for (i=0; i < all_devfreq.size(); i++) {
>> +		class devfreq *df = all_devfreq[i];
>> +
>> +		for(j=0; j < df->dstates.size(); j++)
>> +			delete df->dstates[j];
>> +
>> +		df->dstates.resize(0);
> resize not needed, I think

ack
>
>> +		delete df;
>> +	}
>> +	all_devfreq.clear();
>> +	/* close /sys/class/devfreq */
[...]
>> +
>> +class devfreq: public device {
>> +	char dir_name[4096];
> hm. so this is 2 pages for each class instance.
> can you

will resize to 128 bytes
> 	const char *dir_name;
> 	
> and then
> 	dir_name = strdup(dname); ?
>
>

-- 
sanjay


[-- Attachment #2: attachment.html --]
[-- Type: text/html, Size: 3818 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Powertop] [PATCH] devfreq: add devfreq devices stats support
@ 2014-10-01 20:22 Magnus Fromreide
  0 siblings, 0 replies; 13+ messages in thread
From: Magnus Fromreide @ 2014-10-01 20:22 UTC (permalink / raw)
  To: powertop

[-- Attachment #1: Type: text/plain, Size: 2363 bytes --]

On Tue, Sep 30, 2014 at 12:04:54PM +0530, Sanjay Singh Rawat wrote:
> add window to show frequency stats for devfreq devices
> 
> Signed-off-by: Rajagopal Venkat <rajagopal.venkat(a)gmail.com>
> Signed-off-by: Sanjay Singh Rawat <sanjay.rawat(a)linaro.org>
> ---
> 
> v2 - Show devfreq window on support basis. Check for empty devfreq
>      directory.
>    - Free the open dirp while exiting.
> ---
>  src/Makefile.am           |   1 +
>  src/devices/devfreq.cpp   | 367 ++++++++++++++++++++++++++++++++++++++++++++++
>  src/devices/devfreq.h     |  75 ++++++++++
>  src/main.cpp              |   9 ++
>  src/report/report-maker.h |   1 +
>  5 files changed, 453 insertions(+)
>  create mode 100644 src/devices/devfreq.cpp
>  create mode 100644 src/devices/devfreq.h
> 
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 311b75e..d2f1da7 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -39,6 +39,7 @@ powertop_SOURCES = \
>  	devices/alsa.h \
>  	devices/backlight.cpp \
>  	devices/backlight.h \
> +	devices/devfreq.cpp \
>  	devices/device.cpp \
>  	devices/device.h \
>  	devices/gpu_rapl_device.cpp \
> diff --git a/src/devices/devfreq.cpp b/src/devices/devfreq.cpp
> new file mode 100644
> index 0000000..3eb63e5
> --- /dev/null
> +++ b/src/devices/devfreq.cpp
> @@ -0,0 +1,367 @@
...
> +/* todo: adapt to new report format */
> +#if 0

Do it, or at least do not commit big #if 0-blocks.

> +	char buffer[512];
> +	unsigned int i, j;
> +
> +	report.begin_section(SECTION_DEVFREQ);
> +	report.add_header("Device Frequency Report");
> +
> +	report.begin_table(TABLE_WIDE);
> +	if (!all_devfreq.size()) {
> +		report.begin_row();
> +		report.add(" No devfreq devices available");
> +		return;
> +	}
> +
> +	for (i = 0; i < all_devfreq.size(); i++) {
> +		buffer[0] = 0;
> +		class devfreq *df = all_devfreq[i];
> +
> +		report.begin_row();
> +		report.begin_cell(CELL_CPU_PSTATE_HEADER);
> +		report.addf("%s", df->device_name());
> +
> +		for (j = 0; j < df->dstates.size(); j++) {
> +			report.begin_row();
> +			report.begin_cell(CELL_CPU_STATE_VALUE);
> +			df->fill_freq_name(j, buffer);
> +			report.add(buffer);
> +			report.begin_cell(CELL_CPU_STATE_VALUE);
> +			df->fill_freq_utilization(j, buffer);
> +			report.add(buffer);
> +		}
> +	}
> +#endif

/MF

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Powertop] [PATCH] devfreq: add devfreq devices stats support
@ 2014-10-01 15:12 Sergey Senozhatsky
  0 siblings, 0 replies; 13+ messages in thread
From: Sergey Senozhatsky @ 2014-10-01 15:12 UTC (permalink / raw)
  To: powertop

[-- Attachment #1: Type: text/plain, Size: 15633 bytes --]

On (09/30/14 12:04), Sanjay Singh Rawat wrote:
> add window to show frequency stats for devfreq devices
> 
> Signed-off-by: Rajagopal Venkat <rajagopal.venkat(a)gmail.com>
> Signed-off-by: Sanjay Singh Rawat <sanjay.rawat(a)linaro.org>
> ---
> 
> v2 - Show devfreq window on support basis. Check for empty devfreq
>      directory.
>    - Free the open dirp while exiting.
> ---
>  src/Makefile.am           |   1 +
>  src/devices/devfreq.cpp   | 367 ++++++++++++++++++++++++++++++++++++++++++++++
>  src/devices/devfreq.h     |  75 ++++++++++
>  src/main.cpp              |   9 ++
>  src/report/report-maker.h |   1 +
>  5 files changed, 453 insertions(+)
>  create mode 100644 src/devices/devfreq.cpp
>  create mode 100644 src/devices/devfreq.h
> 
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 311b75e..d2f1da7 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -39,6 +39,7 @@ powertop_SOURCES = \
>  	devices/alsa.h \
>  	devices/backlight.cpp \
>  	devices/backlight.h \
> +	devices/devfreq.cpp \
>  	devices/device.cpp \
>  	devices/device.h \
>  	devices/gpu_rapl_device.cpp \
> diff --git a/src/devices/devfreq.cpp b/src/devices/devfreq.cpp
> new file mode 100644
> index 0000000..3eb63e5
> --- /dev/null
> +++ b/src/devices/devfreq.cpp
> @@ -0,0 +1,367 @@
> +/*
> + * Copyright 2012, Linaro
> + *
> + * This file is part of PowerTOP
> + *
> + * This program file is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> + * for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program in a file named COPYING; if not, write to the
> + * Free Software Foundation, Inc,
> + * 51 Franklin Street, Fifth Floor,
> + * Boston, MA 02110-1301 USA
> + * or just google for it.
> + *
> + * Authors:
> + *	Rajagopal Venkat <rajagopal.venkat(a)linaro.org>
> + */
> +
> +#include <iostream>
> +#include <fstream>
> +
> +#include <dirent.h>
> +#include <stdlib.h>
> +#include <time.h>
> +#include <unistd.h>
> +
> +#include "device.h"
> +#include "devfreq.h"
> +#include "../display.h"
> +#include "../cpu/cpu.h"
> +#include "../report/report.h"
> +#include "../report/report-maker.h"
> +
> +static bool is_enabled = true;
> +static DIR *dir = NULL;
> +
> +static vector<class devfreq *> all_devfreq;
> +
> +devfreq::devfreq(const char* dpath): device()
> +{
> +	strncpy(dir_name, dpath, sizeof(dir_name));
>
>
>
> +}
> +
> +uint64_t devfreq::parse_freq_time(char* pchr)
> +{
> +	char *cptr, *pptr = pchr;
> +	uint64_t ctime;
> +
> +	cptr = strtok(pchr, " :");
> +	while (cptr != NULL) {
> +		cptr = strtok(NULL, " :");
> +		if (cptr )
> +			pptr = cptr;
> +	}
> +
> +	ctime = strtoull(pptr, NULL, 10);
> +	return ctime;
> +}
> +
> +void devfreq::process_time_stamps()
> +{
> +	unsigned int i;
> +	uint64_t active_time = 0;
> +
> +	sample_time = (1000000.0 * (stamp_after.tv_sec - stamp_before.tv_sec))
> +			+ ((stamp_after.tv_usec - stamp_before.tv_usec) );
> +
> +	for (i=0; i < dstates.size()-1; i++) {
> +		struct frequency *state = dstates[i];
> +		state->time_after = 1000 * (state->time_after - state->time_before);
> +		active_time += state->time_after;
> +	}
> +	/* Compute idle time for the device */
> +	dstates[i]->time_after = sample_time - active_time;
> +}
> +
> +void devfreq::add_devfreq_freq_state(uint64_t freq, uint64_t time)
> +{
> +	struct frequency *state;
> +
> +	state = new(std::nothrow) struct frequency;
> +	if (!state)
> +		return;
> +
> +	memset(state, 0, sizeof(*state));
> +	dstates.push_back(state);
> +
> +	state->freq = freq;
> +	if (freq == 0)
> +		strcpy(state->human_name, "Idle");
> +	else
> +		hz_to_human(freq, state->human_name);
> +	state->time_before = time;
> +}
> +
> +void devfreq::update_devfreq_freq_state(uint64_t freq, uint64_t time)
> +{
> +	unsigned int i;
> +	struct frequency *state = NULL;
> +
> +	for(i=0; i < dstates.size(); i++) {
> +		if (freq == dstates[i]->freq)
> +			state = dstates[i];
> +	}
> +
> +	if (state == NULL) {
> +		add_devfreq_freq_state(freq, time);
> +		return;
> +	}
> +
> +	state->time_after = time;
> +}
> +
> +void devfreq::parse_devfreq_trans_stat(char *dname)
> +{
> +	ifstream file;
> +	char filename[256];
> +
> +	sprintf(filename, "/sys/class/devfreq/%s/trans_stat", dir_name);
> +	file.open(filename);
> +
> +	if (!file)
> +		return;
> +
> +	char line[1024];
> +	char *c;
> +
> +	while (file) {
> +		uint64_t freq;
> +		uint64_t time;
> +		char *pchr;
> +
> +		memset(line, 0, sizeof(line));
> +		file.getline(line, sizeof(line));
> +
> +		pchr = strchr(line, '*');
> +		pchr = (pchr != NULL) ? pchr+1 : line;
> +
> +		freq = strtoull(pchr, &c, 10);
> +		if (!freq)
> +			continue;
> +
> +		time = parse_freq_time(pchr);
> +		update_devfreq_freq_state(freq, time);
> +	}
> +	file.close();
> +}
> +
> +void devfreq::start_measurement(void)
> +{
> +	unsigned int i;
> +	ifstream file;

not needed.

> +	for (i=0; i < dstates.size(); i++)
> +		delete dstates[i];
> +	dstates.resize(0);
> +	sample_time = 0;
> +
> +	gettimeofday(&stamp_before, NULL);
> +	parse_devfreq_trans_stat(dir_name);
> +	/* add device idle state */
> +	update_devfreq_freq_state(0, 0);
> +}
> +
> +void devfreq::end_measurement(void)
> +{
> +	parse_devfreq_trans_stat(dir_name);
> +	gettimeofday(&stamp_after, NULL);
> +	process_time_stamps();
> +}
> +
> +double devfreq::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
> +{
> +	return 0;
> +}
> +
> +double devfreq::utilization(void)
> +{
> +	return 0;
> +}
> +
> +void devfreq::fill_freq_utilization(unsigned int idx, char *buf)
> +{
> +	buf[0] = 0;
> +
> +	if (idx < dstates.size() && dstates[idx]) {
> +		struct frequency *state = dstates[idx];
> +		sprintf(buf, " %5.1f%% ", percentage(1.0 * state->time_after / sample_time));
> +	}
> +}
> +
> +void devfreq::fill_freq_name(unsigned int idx, char *buf)
> +{
> +	buf[0] = 0;
> +
> +	if (idx < dstates.size() && dstates[idx]) {
> +		sprintf(buf, "%-15s", dstates[idx]->human_name);
> +	}
> +}
> +
> +void start_devfreq_measurement(void)
> +{
> +	unsigned int i;
> +
> +	for (i=0; i<all_devfreq.size(); i++)
> +		all_devfreq[i]->start_measurement();
> +}
> +
> +void end_devfreq_measurement(void)
> +{
> +	unsigned int i;
> +
> +	for (i=0; i<all_devfreq.size(); i++)
> +		all_devfreq[i]->end_measurement();
> +}
> +
> +static void devfreq_dev_callback(const char *d_name)
> +{
> +	devfreq *df = new(std::nothrow) class devfreq(d_name);
> +	if (df)
> +		all_devfreq.push_back(df);
> +}
> +
> +void create_all_devfreq_devices(void)
> +{
> +	struct dirent *entry;
> +	int num = 0;
> +
> +	std::string p = "/sys/class/devfreq/";
> +	dir = opendir(p.c_str());
> +	if (dir == NULL) {
> +		fprintf(stderr, "Devfreq not enabled\n");
> +		is_enabled = false;
> +		return;
> +	}
> +
> +	while((entry = readdir(dir)) != NULL)
> +		num++;
> +
> +	if (num == 2) {
> +		fprintf(stderr, "Devfreq not enabled\n");
> +		is_enabled = false;
> +		closedir(dir);
> +		return;
> +	}

who close the dir if `num != 2'?

> +	callback fn = &devfreq_dev_callback;
> +	process_directory(p.c_str(), fn);
> +}
> +
> +void initialize_devfreq(void)
> +{
> +	if (is_enabled)
> +		create_tab("Device Freq stats", _("Device Freq stats"));
> +}
> +
> +void display_devfreq_devices(void)
> +{
> +	unsigned int i, j;
> +	WINDOW *win;
> +	char fline[1024];
> +	char buf[128];
> +
> +	win = get_ncurses_win("Device Freq stats");
> +        if (!win)
> +                return;
> +
> +        wclear(win);
> +        wmove(win, 2,0);
> +
> +	if (!is_enabled) {
> +		wprintw(win, _(" Devfreq is not enabled"));
> +		return;
> +	}
> +
> +	if (!all_devfreq.size()) {
> +		wprintw(win, _(" No devfreq devices available"));
> +		return;
> +	}
> +
> +	for (i=0; i<all_devfreq.size(); i++) {
> +
> +		class devfreq *df = all_devfreq[i];
> +		wprintw(win, "\n%s\n", df->device_name());
> +
> +		for(j=0; j < df->dstates.size(); j++) {
> +			memset(fline, 0, sizeof(fline));
> +			strcpy(fline, "\t");
> +			df->fill_freq_name(j, buf);
> +			strcat(fline, buf);
> +			df->fill_freq_utilization(j, buf);
> +			strcat(fline, buf);
> +			strcat(fline, "\n");
> +			wprintw(win, fline);
> +		}
> +		wprintw(win, "\n");
> +	}
> +}
> +
> +void report_devfreq_devices(void)
> +{
> +	if (!is_enabled) {
> +		return;
> +	}
> +
> +/* todo: adapt to new report format */
> +#if 0
> +	char buffer[512];
> +	unsigned int i, j;
> +
> +	report.begin_section(SECTION_DEVFREQ);
> +	report.add_header("Device Frequency Report");
> +
> +	report.begin_table(TABLE_WIDE);
> +	if (!all_devfreq.size()) {
> +		report.begin_row();
> +		report.add(" No devfreq devices available");
> +		return;
> +	}
> +
> +	for (i = 0; i < all_devfreq.size(); i++) {
> +		buffer[0] = 0;
> +		class devfreq *df = all_devfreq[i];
> +
> +		report.begin_row();
> +		report.begin_cell(CELL_CPU_PSTATE_HEADER);
> +		report.addf("%s", df->device_name());
> +
> +		for (j = 0; j < df->dstates.size(); j++) {
> +			report.begin_row();
> +			report.begin_cell(CELL_CPU_STATE_VALUE);
> +			df->fill_freq_name(j, buffer);
> +			report.add(buffer);
> +			report.begin_cell(CELL_CPU_STATE_VALUE);
> +			df->fill_freq_utilization(j, buffer);
> +			report.add(buffer);
> +		}
> +	}
> +#endif
> +
> +}
> +
> +void clear_all_devfreq()
> +{
> +	unsigned int i, j;
> +
> +	for (i=0; i < all_devfreq.size(); i++) {
> +		class devfreq *df = all_devfreq[i];
> +
> +		for(j=0; j < df->dstates.size(); j++)
> +			delete df->dstates[j];
> +
> +		df->dstates.resize(0);
resize not needed, I think

> +		delete df;
> +	}
> +	all_devfreq.clear();
> +	/* close /sys/class/devfreq */
> +	if (dir != NULL)
> +		closedir(dir);
> +}
> diff --git a/src/devices/devfreq.h b/src/devices/devfreq.h
> new file mode 100644
> index 0000000..8ab5705
> --- /dev/null
> +++ b/src/devices/devfreq.h
> @@ -0,0 +1,75 @@
> +/*
> + * Copyright 2012, Linaro
> + *
> + * This file is part of PowerTOP
> + *
> + * This program file is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> + * for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program in a file named COPYING; if not, write to the
> + * Free Software Foundation, Inc,
> + * 51 Franklin Street, Fifth Floor,
> + * Boston, MA 02110-1301 USA
> + * or just google for it.
> + *
> + * Authors:
> + *	Rajagopal Venkat <rajagopal.venkat(a)linaro.org>
> + */
> +#ifndef _INCLUDE_GUARD_DEVFREQ_H
> +#define _INCLUDE_GUARD_DEVFREQ_H
> +
> +#include "device.h"
> +#include "../parameters/parameters.h"
> +
> +struct frequency;
> +
> +class devfreq: public device {
> +	char dir_name[4096];

hm. so this is 2 pages for each class instance.
can you
	const char *dir_name;
	
and then
	dir_name = strdup(dname); ?

> +	struct timeval  stamp_before, stamp_after;
> +	double sample_time;
> +
> +	uint64_t parse_freq_time(char *ptr);
> +	void add_devfreq_freq_state(uint64_t freq, uint64_t time);
> +	void update_devfreq_freq_state(uint64_t freq, uint64_t time);
> +	void parse_devfreq_trans_stat(char *dname);
> +	void process_time_stamps();
> +
> +public:
> +
> +	vector<struct frequency *> dstates;
> +
> +	devfreq(const char *c);
> +	void fill_freq_utilization(unsigned int idx, char *buf);
> +	void fill_freq_name(unsigned int idx, char *buf);
> +
> +	virtual void start_measurement(void);
> +	virtual void end_measurement(void);
> +
> +	virtual double	utilization(void); /* percentage */
> +
> +	virtual const char * class_name(void) { return "devfreq";};
> +
> +	virtual const char * device_name(void) { return dir_name;};
> +	virtual const char * human_name(void) { return "devfreq";};
> +	virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
> +	virtual const char * util_units(void) { return " rpm"; };
> +	virtual int power_valid(void) { return 0; /*utilization_power_valid(r_index);*/};
> +	virtual int grouping_prio(void) { return 1; };
> +};
> +
> +extern void create_all_devfreq_devices(void);
> +extern void clear_all_devfreq(void);
> +extern void display_devfreq_devices(void);
> +extern void report_devfreq_devices(void);
> +extern void initialize_devfreq(void);
> +extern void start_devfreq_measurement(void);
> +extern void end_devfreq_measurement(void);
> +
> +#endif
> diff --git a/src/main.cpp b/src/main.cpp
> index d3963ed..2162004 100644
> --- a/src/main.cpp
> +++ b/src/main.cpp
> @@ -48,6 +48,7 @@
>  
>  
>  #include "devices/device.h"
> +#include "devices/devfreq.h"
>  #include "devices/usb.h"
>  #include "devices/ahci.h"
>  #include "measurement/measurement.h"
> @@ -201,6 +202,7 @@ void one_measurement(int seconds, char *workload)
>  	create_all_usb_devices();
>  	start_power_measurement();
>  	devices_start_measurement();
> +	start_devfreq_measurement();
>  	start_process_measurement();
>  	start_cpu_measurement();
>  
> @@ -213,6 +215,7 @@ void one_measurement(int seconds, char *workload)
>  	end_cpu_measurement();
>  	end_process_measurement();
>  	collect_open_devices();
> +	end_devfreq_measurement();
>  	devices_end_measurement();
>  	end_power_measurement();
>  
> @@ -240,6 +243,8 @@ void one_measurement(int seconds, char *workload)
>  	report_show_open_devices();
>  
>  	report_devices();
> +	display_devfreq_devices();
> +	report_devfreq_devices();
>  	ahci_create_device_stats_table();
>  	store_results(measurement_time);
>  	end_cpu_data();
> @@ -353,6 +358,7 @@ static void powertop_init(void)
>  
>  	enumerate_cpus();
>  	create_all_devices();
> +	create_all_devfreq_devices();
>  	detect_power_meters();
>  
>  	register_parameter("base power", 100, 0.5);
> @@ -464,6 +470,8 @@ int main(int argc, char **argv)
>  	}
>  	if (!auto_tune)
>  		init_display();
> +
> +	initialize_devfreq();
>  	initialize_tuning();
>  	/* first one is short to not let the user wait too long */
>  	one_measurement(1, NULL);
> @@ -500,6 +508,7 @@ int main(int argc, char **argv)
>  
>  	clean_open_devices();
>  	clear_all_devices();
> +	clear_all_devfreq();
>  	clear_all_cpus();
>  
>  	return 0;
> diff --git a/src/report/report-maker.h b/src/report/report-maker.h
> index 423568a..bda4cef 100644
> --- a/src/report/report-maker.h
> +++ b/src/report/report-maker.h
> @@ -89,6 +89,7 @@ enum section_type {
>  	SECTION_SYSINFO,
>  	SECTION_CPUIDLE,
>  	SECTION_CPUFREQ,
> +	SECTION_DEVFREQ,
>  	SECTION_DEVPOWER,
>  	SECTION_SOFTWARE,
>  	SECTION_SUMMARY,
> -- 
> 1.8.3.2
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Powertop] [PATCH] devfreq: add devfreq devices stats support
@ 2014-10-01 14:52 Sergey Senozhatsky
  0 siblings, 0 replies; 13+ messages in thread
From: Sergey Senozhatsky @ 2014-10-01 14:52 UTC (permalink / raw)
  To: powertop

[-- Attachment #1: Type: text/plain, Size: 18021 bytes --]

Hello,

Alexandra, sorry, no ARM devices around at this moment.

	-ss

On (09/29/14 16:04), Alexandra Yates wrote:
> >
> >> add window to show frequency stats for devfreq devices
> >>
> >> Signed-off-by: Rajagopal Venkat <rajagopal.venkat(a)gmail.com>
> >> Signed-off-by: Sanjay Singh Rawat <sanjay.rawat(a)linaro.org>
> >> ---
> >>  src/Makefile.am           |   2 +-
> >>  src/devices/devfreq.cpp   | 351
> >> ++++++++++++++++++++++++++++++++++++++++++++++
> >>  src/devices/devfreq.h     |  75 ++++++++++
> >>  src/main.cpp              |   9 ++
> >>  src/report/report-maker.h |   1 +
> >>  5 files changed, 437 insertions(+), 1 deletion(-)
> >>  create mode 100644 src/devices/devfreq.cpp
> >>  create mode 100644 src/devices/devfreq.h
> >>
> >> diff --git a/src/Makefile.am b/src/Makefile.am
> >> index 6886388..fee1ffa 100644
> >> --- a/src/Makefile.am
> >> +++ b/src/Makefile.am
> >> @@ -32,7 +32,7 @@ powertop_SOURCES = parameters/persistent.cpp
> >> parameters/learn.cpp parameters/par
> >>  		report/report-formatter-csv.cpp report/report-formatter-csv.h \
> >>  		report/report-formatter-html.cpp report/report-formatter-html.h \
> >>  		report/report-data-html.cpp report/report-data-html.h \
> >> -		main.cpp css.h powertop.css cpu/intel_gpu.cpp \
> >> +		main.cpp css.h powertop.css cpu/intel_gpu.cpp devices/devfreq.cpp \
> >>  		cpu/rapl/rapl_interface.cpp cpu/cpu_rapl_device.cpp
> >> cpu/rapl/rapl_interface.h\
> >>  		cpu/dram_rapl_device.cpp devices/gpu_rapl_device.cpp
> >> cpu/cpu_rapl_device.h \
> >>  		cpu/dram_rapl_device.h devices/gpu_rapl_device.h
> >> diff --git a/src/devices/devfreq.cpp b/src/devices/devfreq.cpp
> >> new file mode 100644
> >> index 0000000..29d7790
> >> --- /dev/null
> >> +++ b/src/devices/devfreq.cpp
> >> @@ -0,0 +1,351 @@
> >> +/*
> >> + * Copyright 2012, Linaro
> >> + *
> >> + * This file is part of PowerTOP
> >> + *
> >> + * This program file is free software; you can redistribute it and/or
> >> modify it
> >> + * under the terms of the GNU General Public License as published by
> >> the
> >> + * Free Software Foundation; version 2 of the License.
> >> + *
> >> + * This program is distributed in the hope that it will be useful, but
> >> WITHOUT
> >> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> >> or
> >> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> >> License
> >> + * for more details.
> >> + *
> >> + * You should have received a copy of the GNU General Public License
> >> + * along with this program in a file named COPYING; if not, write to
> >> the
> >> + * Free Software Foundation, Inc,
> >> + * 51 Franklin Street, Fifth Floor,
> >> + * Boston, MA 02110-1301 USA
> >> + * or just google for it.
> >> + *
> >> + * Authors:
> >> + *	Rajagopal Venkat <rajagopal.venkat(a)linaro.org>
> >> + */
> >> +
> >> +#include <iostream>
> >> +#include <fstream>
> >> +
> >> +#include <dirent.h>
> >> +#include <stdlib.h>
> >> +#include <time.h>
> >> +#include <unistd.h>
> >> +
> >> +#include "device.h"
> >> +#include "devfreq.h"
> >> +#include "../display.h"
> >> +#include "../cpu/cpu.h"
> >> +#include "../report/report.h"
> >> +#include "../report/report-maker.h"
> >> +
> >> +static bool is_enabled = true;
> >> +
> >> +static vector<class devfreq *> all_devfreq;
> >> +
> >> +devfreq::devfreq(const char* dpath): device()
> >> +{
> >> +	strncpy(dir_name, dpath, sizeof(dir_name));
> >> +}
> >> +
> >> +uint64_t devfreq::parse_freq_time(char* pchr)
> >> +{
> >> +	char *cptr, *pptr = pchr;
> >> +	uint64_t ctime;
> >> +
> >> +	cptr = strtok(pchr, " :");
> >> +	while (cptr != NULL) {
> >> +		cptr = strtok(NULL, " :");
> >> +		if (cptr )
> >> +			pptr = cptr;
> >> +	}
> >> +
> >> +	ctime = strtoull(pptr, NULL, 10);
> >> +	return ctime;
> >> +}
> >> +
> >> +void devfreq::process_time_stamps()
> >> +{
> >> +	unsigned int i;
> >> +	uint64_t active_time = 0;
> >> +
> >> +	sample_time = (1000000.0 * (stamp_after.tv_sec - stamp_before.tv_sec))
> >> +			+ ((stamp_after.tv_usec - stamp_before.tv_usec) );
> >> +
> >> +	for (i=0; i < dstates.size()-1; i++) {
> >> +		struct frequency *state = dstates[i];
> >> +		state->time_after = 1000 * (state->time_after - state->time_before);
> >> +		active_time += state->time_after;
> >> +	}
> >> +	/* Compute idle time for the device */
> >> +	dstates[i]->time_after = sample_time - active_time;
> >> +}
> >> +
> >> +void devfreq::add_devfreq_freq_state(uint64_t freq, uint64_t time)
> >> +{
> >> +	struct frequency *state;
> >> +
> >> +	state = new(std::nothrow) struct frequency;
> >> +	if (!state)
> >> +		return;
> >> +
> >> +	memset(state, 0, sizeof(*state));
> >> +	dstates.push_back(state);
> >> +
> >> +	state->freq = freq;
> >> +	if (freq == 0)
> >> +		strcpy(state->human_name, "Idle");
> >> +	else
> >> +		hz_to_human(freq, state->human_name);
> >> +	state->time_before = time;
> >> +}
> >> +
> >> +void devfreq::update_devfreq_freq_state(uint64_t freq, uint64_t time)
> >> +{
> >> +	unsigned int i;
> >> +	struct frequency *state = NULL;
> >> +
> >> +	for(i=0; i < dstates.size(); i++) {
> >> +		if (freq == dstates[i]->freq)
> >> +			state = dstates[i];
> >> +	}
> >> +
> >> +	if (state == NULL) {
> >> +		add_devfreq_freq_state(freq, time);
> >> +		return;
> >> +	}
> >> +
> >> +	state->time_after = time;
> >> +}
> >> +
> >> +void devfreq::parse_devfreq_trans_stat(char *dname)
> >> +{
> >> +	ifstream file;
> >> +	char filename[256];
> >> +
> >> +	sprintf(filename, "/sys/class/devfreq/%s/trans_stat", dir_name);
> >> +	file.open(filename);
> >> +
> >> +	if (!file)
> >> +		return;
> >> +
> >> +	char line[1024];
> >> +	char *c;
> >> +
> >> +	while (file) {
> >> +		uint64_t freq;
> >> +		uint64_t time;
> >> +		char *pchr;
> >> +
> >> +		memset(line, 0, sizeof(line));
> >> +		file.getline(line, sizeof(line));
> >> +
> >> +		pchr = strchr(line, '*');
> >> +		pchr = (pchr != NULL) ? pchr+1 : line;
> >> +
> >> +		freq = strtoull(pchr, &c, 10);
> >> +		if (!freq)
> >> +			continue;
> >> +
> >> +		time = parse_freq_time(pchr);
> >> +		update_devfreq_freq_state(freq, time);
> >> +	}
> >> +	file.close();
> >> +}
> >> +
> >> +void devfreq::start_measurement(void)
> >> +{
> >> +	unsigned int i;
> >> +	ifstream file;
> >> +
> >> +	for (i=0; i < dstates.size(); i++)
> >> +		delete dstates[i];
> >> +	dstates.resize(0);
> >> +	sample_time = 0;
> >> +
> >> +	gettimeofday(&stamp_before, NULL);
> >> +	parse_devfreq_trans_stat(dir_name);
> >> +	/* add device idle state */
> >> +	update_devfreq_freq_state(0, 0);
> >> +}
> >> +
> >> +void devfreq::end_measurement(void)
> >> +{
> >> +	parse_devfreq_trans_stat(dir_name);
> >> +	gettimeofday(&stamp_after, NULL);
> >> +	process_time_stamps();
> >> +}
> >> +
> >> +double devfreq::power_usage(struct result_bundle *result, struct
> >> parameter_bundle *bundle)
> >> +{
> >> +	return 0;
> >> +}
> >> +
> >> +double devfreq::utilization(void)
> >> +{
> >> +	return 0;
> >> +}
> >> +
> >> +void devfreq::fill_freq_utilization(unsigned int idx, char *buf)
> >> +{
> >> +	buf[0] = 0;
> >> +
> >> +	if (idx < dstates.size() && dstates[idx]) {
> >> +		struct frequency *state = dstates[idx];
> >> +		sprintf(buf, " %5.1f%% ", percentage(1.0 * state->time_after /
> >> sample_time));
> >> +	}
> >> +}
> >> +
> >> +void devfreq::fill_freq_name(unsigned int idx, char *buf)
> >> +{
> >> +	buf[0] = 0;
> >> +
> >> +	if (idx < dstates.size() && dstates[idx]) {
> >> +		sprintf(buf, "%-15s", dstates[idx]->human_name);
> >> +	}
> >> +}
> >> +
> >> +void start_devfreq_measurement(void)
> >> +{
> >> +	unsigned int i;
> >> +
> >> +	for (i=0; i<all_devfreq.size(); i++)
> >> +		all_devfreq[i]->start_measurement();
> >> +}
> >> +
> >> +void end_devfreq_measurement(void)
> >> +{
> >> +	unsigned int i;
> >> +
> >> +	for (i=0; i<all_devfreq.size(); i++)
> >> +		all_devfreq[i]->end_measurement();
> >> +}
> >> +
> >> +static void devfreq_dev_callback(const char *d_name)
> >> +{
> >> +	devfreq *df = new(std::nothrow) class devfreq(d_name);
> >> +	if (df)
> >> +		all_devfreq.push_back(df);
> >> +}
> >> +
> >> +void create_all_devfreq_devices(void)
> >> +{
> >> +	DIR *dir;
> >> +	std::string p = "/sys/class/devfreq/";
> >> +	dir = opendir(p.c_str());
> >> +	if (dir == NULL) {
> >> +		fprintf(stderr, "Devfreq not enabled\n");
> >> +		is_enabled = false;
> >> +		return;
> >> +	}
> >> +
> >> +	callback fn = &devfreq_dev_callback;
> >> +	process_directory(p.c_str(), fn);
> >> +}
> >> +
> >> +void initialize_devfreq(void)
> >> +{
> >> +	if (is_enabled)
> >> +		create_tab("Device Freq stats", _("Device Freq stats"));
> >> +}
> >> +
> >> +void display_devfreq_devices(void)
> >> +{
> >> +	unsigned int i, j;
> >> +	WINDOW *win;
> >> +	char fline[1024];
> >> +	char buf[128];
> >> +
> >> +	win = get_ncurses_win("Device Freq stats");
> >> +        if (!win)
> >> +                return;
> >> +
> >> +        wclear(win);
> >> +        wmove(win, 2,0);
> >> +
> >> +	if (!is_enabled) {
> >> +		wprintw(win, _(" Devfreq is not enabled"));
> >> +		return;
> >> +	}
> >> +
> >> +	if (!all_devfreq.size()) {
> >> +		wprintw(win, _(" No devfreq devices available"));
> >> +		return;
> >> +	}
> >> +
> >> +	for (i=0; i<all_devfreq.size(); i++) {
> >> +
> >> +		class devfreq *df = all_devfreq[i];
> >> +		wprintw(win, "\n%s\n", df->device_name());
> >> +
> >> +		for(j=0; j < df->dstates.size(); j++) {
> >> +			memset(fline, 0, sizeof(fline));
> >> +			strcpy(fline, "\t");
> >> +			df->fill_freq_name(j, buf);
> >> +			strcat(fline, buf);
> >> +			df->fill_freq_utilization(j, buf);
> >> +			strcat(fline, buf);
> >> +			strcat(fline, "\n");
> >> +			wprintw(win, fline);
> >> +		}
> >> +		wprintw(win, "\n");
> >> +	}
> >> +}
> >> +
> >> +void report_devfreq_devices(void)
> >> +{
> >> +	if (!is_enabled) {
> >> +		return;
> >> +	}
> >> +
> >> +/* todo: adapt to new report format */
> >> +#if 0
> >> +	char buffer[512];
> >> +	unsigned int i, j;
> >> +
> >> +	report.begin_section(SECTION_DEVFREQ);
> >> +	report.add_header("Device Frequency Report");
> >> +
> >> +	report.begin_table(TABLE_WIDE);
> >> +	if (!all_devfreq.size()) {
> >> +		report.begin_row();
> >> +		report.add(" No devfreq devices available");
> >> +		return;
> >> +	}
> >> +
> >> +	for (i = 0; i < all_devfreq.size(); i++) {
> >> +		buffer[0] = 0;
> >> +		class devfreq *df = all_devfreq[i];
> >> +
> >> +		report.begin_row();
> >> +		report.begin_cell(CELL_CPU_PSTATE_HEADER);
> >> +		report.addf("%s", df->device_name());
> >> +
> >> +		for (j = 0; j < df->dstates.size(); j++) {
> >> +			report.begin_row();
> >> +			report.begin_cell(CELL_CPU_STATE_VALUE);
> >> +			df->fill_freq_name(j, buffer);
> >> +			report.add(buffer);
> >> +			report.begin_cell(CELL_CPU_STATE_VALUE);
> >> +			df->fill_freq_utilization(j, buffer);
> >> +			report.add(buffer);
> >> +		}
> >> +	}
> >> +#endif
> >> +
> >> +}
> >> +
> >> +void clear_all_devfreq()
> >> +{
> >> +	unsigned int i, j;
> >> +
> >> +	for (i=0; i < all_devfreq.size(); i++) {
> >> +		class devfreq *df = all_devfreq[i];
> >> +
> >> +		for(j=0; j < df->dstates.size(); j++)
> >> +			delete df->dstates[j];
> >> +
> >> +		df->dstates.resize(0);
> >> +		delete df;
> >> +	}
> >> +	all_devfreq.clear();
> >> +}
> >> diff --git a/src/devices/devfreq.h b/src/devices/devfreq.h
> >> new file mode 100644
> >> index 0000000..8ab5705
> >> --- /dev/null
> >> +++ b/src/devices/devfreq.h
> >> @@ -0,0 +1,75 @@
> >> +/*
> >> + * Copyright 2012, Linaro
> >> + *
> >> + * This file is part of PowerTOP
> >> + *
> >> + * This program file is free software; you can redistribute it and/or
> >> modify it
> >> + * under the terms of the GNU General Public License as published by
> >> the
> >> + * Free Software Foundation; version 2 of the License.
> >> + *
> >> + * This program is distributed in the hope that it will be useful, but
> >> WITHOUT
> >> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> >> or
> >> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
> >> License
> >> + * for more details.
> >> + *
> >> + * You should have received a copy of the GNU General Public License
> >> + * along with this program in a file named COPYING; if not, write to
> >> the
> >> + * Free Software Foundation, Inc,
> >> + * 51 Franklin Street, Fifth Floor,
> >> + * Boston, MA 02110-1301 USA
> >> + * or just google for it.
> >> + *
> >> + * Authors:
> >> + *	Rajagopal Venkat <rajagopal.venkat(a)linaro.org>
> >> + */
> >> +#ifndef _INCLUDE_GUARD_DEVFREQ_H
> >> +#define _INCLUDE_GUARD_DEVFREQ_H
> >> +
> >> +#include "device.h"
> >> +#include "../parameters/parameters.h"
> >> +
> >> +struct frequency;
> >> +
> >> +class devfreq: public device {
> >> +	char dir_name[4096];
> >> +	struct timeval  stamp_before, stamp_after;
> >> +	double sample_time;
> >> +
> >> +	uint64_t parse_freq_time(char *ptr);
> >> +	void add_devfreq_freq_state(uint64_t freq, uint64_t time);
> >> +	void update_devfreq_freq_state(uint64_t freq, uint64_t time);
> >> +	void parse_devfreq_trans_stat(char *dname);
> >> +	void process_time_stamps();
> >> +
> >> +public:
> >> +
> >> +	vector<struct frequency *> dstates;
> >> +
> >> +	devfreq(const char *c);
> >> +	void fill_freq_utilization(unsigned int idx, char *buf);
> >> +	void fill_freq_name(unsigned int idx, char *buf);
> >> +
> >> +	virtual void start_measurement(void);
> >> +	virtual void end_measurement(void);
> >> +
> >> +	virtual double	utilization(void); /* percentage */
> >> +
> >> +	virtual const char * class_name(void) { return "devfreq";};
> >> +
> >> +	virtual const char * device_name(void) { return dir_name;};
> >> +	virtual const char * human_name(void) { return "devfreq";};
> >> +	virtual double power_usage(struct result_bundle *result, struct
> >> parameter_bundle *bundle);
> >> +	virtual const char * util_units(void) { return " rpm"; };
> >> +	virtual int power_valid(void) { return 0;
> >> /*utilization_power_valid(r_index);*/};
> >> +	virtual int grouping_prio(void) { return 1; };
> >> +};
> >> +
> >> +extern void create_all_devfreq_devices(void);
> >> +extern void clear_all_devfreq(void);
> >> +extern void display_devfreq_devices(void);
> >> +extern void report_devfreq_devices(void);
> >> +extern void initialize_devfreq(void);
> >> +extern void start_devfreq_measurement(void);
> >> +extern void end_devfreq_measurement(void);
> >> +
> >> +#endif
> >> diff --git a/src/main.cpp b/src/main.cpp
> >> index cf4e547..d33eaed 100644
> >> --- a/src/main.cpp
> >> +++ b/src/main.cpp
> >> @@ -48,6 +48,7 @@
> >>
> >>
> >>  #include "devices/device.h"
> >> +#include "devices/devfreq.h"
> >>  #include "devices/usb.h"
> >>  #include "devices/ahci.h"
> >>  #include "measurement/measurement.h"
> >> @@ -194,6 +195,7 @@ void one_measurement(int seconds, char *workload)
> >>  	create_all_usb_devices();
> >>  	start_power_measurement();
> >>  	devices_start_measurement();
> >> +	start_devfreq_measurement();
> >>  	start_process_measurement();
> >>  	start_cpu_measurement();
> >>
> >> @@ -206,6 +208,7 @@ void one_measurement(int seconds, char *workload)
> >>  	end_cpu_measurement();
> >>  	end_process_measurement();
> >>  	collect_open_devices();
> >> +	end_devfreq_measurement();
> >>  	devices_end_measurement();
> >>  	end_power_measurement();
> >>
> >> @@ -233,6 +236,9 @@ void one_measurement(int seconds, char *workload)
> >>  	report_show_open_devices();
> >>
> >>  	report_devices();
> >> +	display_devfreq_devices();
> >> +	report_devfreq_devices();
> >> +
> >>  	ahci_create_device_stats_table();
> >>  	store_results(measurement_time);
> >>  	end_cpu_data();
> >> @@ -344,6 +350,7 @@ static void powertop_init(void)
> >>
> >>  	enumerate_cpus();
> >>  	create_all_devices();
> >> +	create_all_devfreq_devices();
> >>  	detect_power_meters();
> >>
> >>  	register_parameter("base power", 100, 0.5);
> >> @@ -457,6 +464,7 @@ int main(int argc, char **argv)
> >>  		exit(0);
> >>  	}
> >>  	init_display();
> >> +	initialize_devfreq();
> >>  	initialize_tuning();
> >>  	/* first one is short to not let the user wait too long */
> >>  	one_measurement(1, NULL);
> >> @@ -491,6 +499,7 @@ int main(int argc, char **argv)
> >>
> >>  	clean_open_devices();
> >>  	clear_all_devices();
> >> +	clear_all_devfreq();
> >>  	clear_all_cpus();
> >>
> >>  	return 0;
> >> diff --git a/src/report/report-maker.h b/src/report/report-maker.h
> >> index 423568a..bda4cef 100644
> >> --- a/src/report/report-maker.h
> >> +++ b/src/report/report-maker.h
> >> @@ -89,6 +89,7 @@ enum section_type {
> >>  	SECTION_SYSINFO,
> >>  	SECTION_CPUIDLE,
> >>  	SECTION_CPUFREQ,
> >> +	SECTION_DEVFREQ,
> >>  	SECTION_DEVPOWER,
> >>  	SECTION_SOFTWARE,
> >>  	SECTION_SUMMARY,
> >> --
> >> 1.8.3.2
> >>
> >> _______________________________________________
> >> PowerTop mailing list
> >> PowerTop(a)lists.01.org
> >> https://lists.01.org/mailman/listinfo/powertop
> >>
> >
> > Hi Sanjay,
> >
> > It would be better that Device Frequency Stats appears only when
> > /sys/class/devfewq is present on the system.  That will simplify code
> > execution at runtime and remove the blank window with "No devfreq devices
> > available".
> >
> > Thank you,
> > Alexandra.
> > _______________________________________________
> > PowerTop mailing list
> > PowerTop(a)lists.01.org
> > https://lists.01.org/mailman/listinfo/powertop
> >
> 
> I'm testing the code doesn't break Intel support.  Please Sergey
> Senozhatsky and any one else in the community can you help me test this
> patch on ARM platforms.
> 
> Thank you,
> Alexandra.
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Powertop] [PATCH] devfreq: add devfreq devices stats support
@ 2014-09-30  6:34 Sanjay Singh Rawat
  0 siblings, 0 replies; 13+ messages in thread
From: Sanjay Singh Rawat @ 2014-09-30  6:34 UTC (permalink / raw)
  To: powertop

[-- Attachment #1: Type: text/plain, Size: 14248 bytes --]

add window to show frequency stats for devfreq devices

Signed-off-by: Rajagopal Venkat <rajagopal.venkat(a)gmail.com>
Signed-off-by: Sanjay Singh Rawat <sanjay.rawat(a)linaro.org>
---

v2 - Show devfreq window on support basis. Check for empty devfreq
     directory.
   - Free the open dirp while exiting.
---
 src/Makefile.am           |   1 +
 src/devices/devfreq.cpp   | 367 ++++++++++++++++++++++++++++++++++++++++++++++
 src/devices/devfreq.h     |  75 ++++++++++
 src/main.cpp              |   9 ++
 src/report/report-maker.h |   1 +
 5 files changed, 453 insertions(+)
 create mode 100644 src/devices/devfreq.cpp
 create mode 100644 src/devices/devfreq.h

diff --git a/src/Makefile.am b/src/Makefile.am
index 311b75e..d2f1da7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -39,6 +39,7 @@ powertop_SOURCES = \
 	devices/alsa.h \
 	devices/backlight.cpp \
 	devices/backlight.h \
+	devices/devfreq.cpp \
 	devices/device.cpp \
 	devices/device.h \
 	devices/gpu_rapl_device.cpp \
diff --git a/src/devices/devfreq.cpp b/src/devices/devfreq.cpp
new file mode 100644
index 0000000..3eb63e5
--- /dev/null
+++ b/src/devices/devfreq.cpp
@@ -0,0 +1,367 @@
+/*
+ * Copyright 2012, Linaro
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *	Rajagopal Venkat <rajagopal.venkat(a)linaro.org>
+ */
+
+#include <iostream>
+#include <fstream>
+
+#include <dirent.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "device.h"
+#include "devfreq.h"
+#include "../display.h"
+#include "../cpu/cpu.h"
+#include "../report/report.h"
+#include "../report/report-maker.h"
+
+static bool is_enabled = true;
+static DIR *dir = NULL;
+
+static vector<class devfreq *> all_devfreq;
+
+devfreq::devfreq(const char* dpath): device()
+{
+	strncpy(dir_name, dpath, sizeof(dir_name));
+}
+
+uint64_t devfreq::parse_freq_time(char* pchr)
+{
+	char *cptr, *pptr = pchr;
+	uint64_t ctime;
+
+	cptr = strtok(pchr, " :");
+	while (cptr != NULL) {
+		cptr = strtok(NULL, " :");
+		if (cptr )
+			pptr = cptr;
+	}
+
+	ctime = strtoull(pptr, NULL, 10);
+	return ctime;
+}
+
+void devfreq::process_time_stamps()
+{
+	unsigned int i;
+	uint64_t active_time = 0;
+
+	sample_time = (1000000.0 * (stamp_after.tv_sec - stamp_before.tv_sec))
+			+ ((stamp_after.tv_usec - stamp_before.tv_usec) );
+
+	for (i=0; i < dstates.size()-1; i++) {
+		struct frequency *state = dstates[i];
+		state->time_after = 1000 * (state->time_after - state->time_before);
+		active_time += state->time_after;
+	}
+	/* Compute idle time for the device */
+	dstates[i]->time_after = sample_time - active_time;
+}
+
+void devfreq::add_devfreq_freq_state(uint64_t freq, uint64_t time)
+{
+	struct frequency *state;
+
+	state = new(std::nothrow) struct frequency;
+	if (!state)
+		return;
+
+	memset(state, 0, sizeof(*state));
+	dstates.push_back(state);
+
+	state->freq = freq;
+	if (freq == 0)
+		strcpy(state->human_name, "Idle");
+	else
+		hz_to_human(freq, state->human_name);
+	state->time_before = time;
+}
+
+void devfreq::update_devfreq_freq_state(uint64_t freq, uint64_t time)
+{
+	unsigned int i;
+	struct frequency *state = NULL;
+
+	for(i=0; i < dstates.size(); i++) {
+		if (freq == dstates[i]->freq)
+			state = dstates[i];
+	}
+
+	if (state == NULL) {
+		add_devfreq_freq_state(freq, time);
+		return;
+	}
+
+	state->time_after = time;
+}
+
+void devfreq::parse_devfreq_trans_stat(char *dname)
+{
+	ifstream file;
+	char filename[256];
+
+	sprintf(filename, "/sys/class/devfreq/%s/trans_stat", dir_name);
+	file.open(filename);
+
+	if (!file)
+		return;
+
+	char line[1024];
+	char *c;
+
+	while (file) {
+		uint64_t freq;
+		uint64_t time;
+		char *pchr;
+
+		memset(line, 0, sizeof(line));
+		file.getline(line, sizeof(line));
+
+		pchr = strchr(line, '*');
+		pchr = (pchr != NULL) ? pchr+1 : line;
+
+		freq = strtoull(pchr, &c, 10);
+		if (!freq)
+			continue;
+
+		time = parse_freq_time(pchr);
+		update_devfreq_freq_state(freq, time);
+	}
+	file.close();
+}
+
+void devfreq::start_measurement(void)
+{
+	unsigned int i;
+	ifstream file;
+
+	for (i=0; i < dstates.size(); i++)
+		delete dstates[i];
+	dstates.resize(0);
+	sample_time = 0;
+
+	gettimeofday(&stamp_before, NULL);
+	parse_devfreq_trans_stat(dir_name);
+	/* add device idle state */
+	update_devfreq_freq_state(0, 0);
+}
+
+void devfreq::end_measurement(void)
+{
+	parse_devfreq_trans_stat(dir_name);
+	gettimeofday(&stamp_after, NULL);
+	process_time_stamps();
+}
+
+double devfreq::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+	return 0;
+}
+
+double devfreq::utilization(void)
+{
+	return 0;
+}
+
+void devfreq::fill_freq_utilization(unsigned int idx, char *buf)
+{
+	buf[0] = 0;
+
+	if (idx < dstates.size() && dstates[idx]) {
+		struct frequency *state = dstates[idx];
+		sprintf(buf, " %5.1f%% ", percentage(1.0 * state->time_after / sample_time));
+	}
+}
+
+void devfreq::fill_freq_name(unsigned int idx, char *buf)
+{
+	buf[0] = 0;
+
+	if (idx < dstates.size() && dstates[idx]) {
+		sprintf(buf, "%-15s", dstates[idx]->human_name);
+	}
+}
+
+void start_devfreq_measurement(void)
+{
+	unsigned int i;
+
+	for (i=0; i<all_devfreq.size(); i++)
+		all_devfreq[i]->start_measurement();
+}
+
+void end_devfreq_measurement(void)
+{
+	unsigned int i;
+
+	for (i=0; i<all_devfreq.size(); i++)
+		all_devfreq[i]->end_measurement();
+}
+
+static void devfreq_dev_callback(const char *d_name)
+{
+	devfreq *df = new(std::nothrow) class devfreq(d_name);
+	if (df)
+		all_devfreq.push_back(df);
+}
+
+void create_all_devfreq_devices(void)
+{
+	struct dirent *entry;
+	int num = 0;
+
+	std::string p = "/sys/class/devfreq/";
+	dir = opendir(p.c_str());
+	if (dir == NULL) {
+		fprintf(stderr, "Devfreq not enabled\n");
+		is_enabled = false;
+		return;
+	}
+
+	while((entry = readdir(dir)) != NULL)
+		num++;
+
+	if (num == 2) {
+		fprintf(stderr, "Devfreq not enabled\n");
+		is_enabled = false;
+		closedir(dir);
+		return;
+	}
+
+	callback fn = &devfreq_dev_callback;
+	process_directory(p.c_str(), fn);
+}
+
+void initialize_devfreq(void)
+{
+	if (is_enabled)
+		create_tab("Device Freq stats", _("Device Freq stats"));
+}
+
+void display_devfreq_devices(void)
+{
+	unsigned int i, j;
+	WINDOW *win;
+	char fline[1024];
+	char buf[128];
+
+	win = get_ncurses_win("Device Freq stats");
+        if (!win)
+                return;
+
+        wclear(win);
+        wmove(win, 2,0);
+
+	if (!is_enabled) {
+		wprintw(win, _(" Devfreq is not enabled"));
+		return;
+	}
+
+	if (!all_devfreq.size()) {
+		wprintw(win, _(" No devfreq devices available"));
+		return;
+	}
+
+	for (i=0; i<all_devfreq.size(); i++) {
+
+		class devfreq *df = all_devfreq[i];
+		wprintw(win, "\n%s\n", df->device_name());
+
+		for(j=0; j < df->dstates.size(); j++) {
+			memset(fline, 0, sizeof(fline));
+			strcpy(fline, "\t");
+			df->fill_freq_name(j, buf);
+			strcat(fline, buf);
+			df->fill_freq_utilization(j, buf);
+			strcat(fline, buf);
+			strcat(fline, "\n");
+			wprintw(win, fline);
+		}
+		wprintw(win, "\n");
+	}
+}
+
+void report_devfreq_devices(void)
+{
+	if (!is_enabled) {
+		return;
+	}
+
+/* todo: adapt to new report format */
+#if 0
+	char buffer[512];
+	unsigned int i, j;
+
+	report.begin_section(SECTION_DEVFREQ);
+	report.add_header("Device Frequency Report");
+
+	report.begin_table(TABLE_WIDE);
+	if (!all_devfreq.size()) {
+		report.begin_row();
+		report.add(" No devfreq devices available");
+		return;
+	}
+
+	for (i = 0; i < all_devfreq.size(); i++) {
+		buffer[0] = 0;
+		class devfreq *df = all_devfreq[i];
+
+		report.begin_row();
+		report.begin_cell(CELL_CPU_PSTATE_HEADER);
+		report.addf("%s", df->device_name());
+
+		for (j = 0; j < df->dstates.size(); j++) {
+			report.begin_row();
+			report.begin_cell(CELL_CPU_STATE_VALUE);
+			df->fill_freq_name(j, buffer);
+			report.add(buffer);
+			report.begin_cell(CELL_CPU_STATE_VALUE);
+			df->fill_freq_utilization(j, buffer);
+			report.add(buffer);
+		}
+	}
+#endif
+
+}
+
+void clear_all_devfreq()
+{
+	unsigned int i, j;
+
+	for (i=0; i < all_devfreq.size(); i++) {
+		class devfreq *df = all_devfreq[i];
+
+		for(j=0; j < df->dstates.size(); j++)
+			delete df->dstates[j];
+
+		df->dstates.resize(0);
+		delete df;
+	}
+	all_devfreq.clear();
+	/* close /sys/class/devfreq */
+	if (dir != NULL)
+		closedir(dir);
+}
diff --git a/src/devices/devfreq.h b/src/devices/devfreq.h
new file mode 100644
index 0000000..8ab5705
--- /dev/null
+++ b/src/devices/devfreq.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2012, Linaro
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *	Rajagopal Venkat <rajagopal.venkat(a)linaro.org>
+ */
+#ifndef _INCLUDE_GUARD_DEVFREQ_H
+#define _INCLUDE_GUARD_DEVFREQ_H
+
+#include "device.h"
+#include "../parameters/parameters.h"
+
+struct frequency;
+
+class devfreq: public device {
+	char dir_name[4096];
+	struct timeval  stamp_before, stamp_after;
+	double sample_time;
+
+	uint64_t parse_freq_time(char *ptr);
+	void add_devfreq_freq_state(uint64_t freq, uint64_t time);
+	void update_devfreq_freq_state(uint64_t freq, uint64_t time);
+	void parse_devfreq_trans_stat(char *dname);
+	void process_time_stamps();
+
+public:
+
+	vector<struct frequency *> dstates;
+
+	devfreq(const char *c);
+	void fill_freq_utilization(unsigned int idx, char *buf);
+	void fill_freq_name(unsigned int idx, char *buf);
+
+	virtual void start_measurement(void);
+	virtual void end_measurement(void);
+
+	virtual double	utilization(void); /* percentage */
+
+	virtual const char * class_name(void) { return "devfreq";};
+
+	virtual const char * device_name(void) { return dir_name;};
+	virtual const char * human_name(void) { return "devfreq";};
+	virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+	virtual const char * util_units(void) { return " rpm"; };
+	virtual int power_valid(void) { return 0; /*utilization_power_valid(r_index);*/};
+	virtual int grouping_prio(void) { return 1; };
+};
+
+extern void create_all_devfreq_devices(void);
+extern void clear_all_devfreq(void);
+extern void display_devfreq_devices(void);
+extern void report_devfreq_devices(void);
+extern void initialize_devfreq(void);
+extern void start_devfreq_measurement(void);
+extern void end_devfreq_measurement(void);
+
+#endif
diff --git a/src/main.cpp b/src/main.cpp
index d3963ed..2162004 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -48,6 +48,7 @@
 
 
 #include "devices/device.h"
+#include "devices/devfreq.h"
 #include "devices/usb.h"
 #include "devices/ahci.h"
 #include "measurement/measurement.h"
@@ -201,6 +202,7 @@ void one_measurement(int seconds, char *workload)
 	create_all_usb_devices();
 	start_power_measurement();
 	devices_start_measurement();
+	start_devfreq_measurement();
 	start_process_measurement();
 	start_cpu_measurement();
 
@@ -213,6 +215,7 @@ void one_measurement(int seconds, char *workload)
 	end_cpu_measurement();
 	end_process_measurement();
 	collect_open_devices();
+	end_devfreq_measurement();
 	devices_end_measurement();
 	end_power_measurement();
 
@@ -240,6 +243,8 @@ void one_measurement(int seconds, char *workload)
 	report_show_open_devices();
 
 	report_devices();
+	display_devfreq_devices();
+	report_devfreq_devices();
 	ahci_create_device_stats_table();
 	store_results(measurement_time);
 	end_cpu_data();
@@ -353,6 +358,7 @@ static void powertop_init(void)
 
 	enumerate_cpus();
 	create_all_devices();
+	create_all_devfreq_devices();
 	detect_power_meters();
 
 	register_parameter("base power", 100, 0.5);
@@ -464,6 +470,8 @@ int main(int argc, char **argv)
 	}
 	if (!auto_tune)
 		init_display();
+
+	initialize_devfreq();
 	initialize_tuning();
 	/* first one is short to not let the user wait too long */
 	one_measurement(1, NULL);
@@ -500,6 +508,7 @@ int main(int argc, char **argv)
 
 	clean_open_devices();
 	clear_all_devices();
+	clear_all_devfreq();
 	clear_all_cpus();
 
 	return 0;
diff --git a/src/report/report-maker.h b/src/report/report-maker.h
index 423568a..bda4cef 100644
--- a/src/report/report-maker.h
+++ b/src/report/report-maker.h
@@ -89,6 +89,7 @@ enum section_type {
 	SECTION_SYSINFO,
 	SECTION_CPUIDLE,
 	SECTION_CPUFREQ,
+	SECTION_DEVFREQ,
 	SECTION_DEVPOWER,
 	SECTION_SOFTWARE,
 	SECTION_SUMMARY,
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [Powertop] [PATCH] devfreq: add devfreq devices stats support
@ 2014-09-30  4:21 Sanjay Singh Rawat
  0 siblings, 0 replies; 13+ messages in thread
From: Sanjay Singh Rawat @ 2014-09-30  4:21 UTC (permalink / raw)
  To: powertop

[-- Attachment #1: Type: text/plain, Size: 452 bytes --]


On Tuesday 30 September 2014 04:16 AM, Alexandra Yates wrote:
>
> Hi Sanjay,
>
> It would be better that Device Frequency Stats appears only when
> /sys/class/devfewq is present on the system.  That will simplify code
> execution at runtime and remove the blank window with "No devfreq devices
> available".

ack, thanks for the review Alexandra

will update the patch as per your comment.
>
> Thank you,
> Alexandra.

-- 
sanjay


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Powertop] [PATCH] devfreq: add devfreq devices stats support
@ 2014-09-29 23:04 Alexandra Yates
  0 siblings, 0 replies; 13+ messages in thread
From: Alexandra Yates @ 2014-09-29 23:04 UTC (permalink / raw)
  To: powertop

[-- Attachment #1: Type: text/plain, Size: 16717 bytes --]


>
>> add window to show frequency stats for devfreq devices
>>
>> Signed-off-by: Rajagopal Venkat <rajagopal.venkat(a)gmail.com>
>> Signed-off-by: Sanjay Singh Rawat <sanjay.rawat(a)linaro.org>
>> ---
>>  src/Makefile.am           |   2 +-
>>  src/devices/devfreq.cpp   | 351
>> ++++++++++++++++++++++++++++++++++++++++++++++
>>  src/devices/devfreq.h     |  75 ++++++++++
>>  src/main.cpp              |   9 ++
>>  src/report/report-maker.h |   1 +
>>  5 files changed, 437 insertions(+), 1 deletion(-)
>>  create mode 100644 src/devices/devfreq.cpp
>>  create mode 100644 src/devices/devfreq.h
>>
>> diff --git a/src/Makefile.am b/src/Makefile.am
>> index 6886388..fee1ffa 100644
>> --- a/src/Makefile.am
>> +++ b/src/Makefile.am
>> @@ -32,7 +32,7 @@ powertop_SOURCES = parameters/persistent.cpp
>> parameters/learn.cpp parameters/par
>>  		report/report-formatter-csv.cpp report/report-formatter-csv.h \
>>  		report/report-formatter-html.cpp report/report-formatter-html.h \
>>  		report/report-data-html.cpp report/report-data-html.h \
>> -		main.cpp css.h powertop.css cpu/intel_gpu.cpp \
>> +		main.cpp css.h powertop.css cpu/intel_gpu.cpp devices/devfreq.cpp \
>>  		cpu/rapl/rapl_interface.cpp cpu/cpu_rapl_device.cpp
>> cpu/rapl/rapl_interface.h\
>>  		cpu/dram_rapl_device.cpp devices/gpu_rapl_device.cpp
>> cpu/cpu_rapl_device.h \
>>  		cpu/dram_rapl_device.h devices/gpu_rapl_device.h
>> diff --git a/src/devices/devfreq.cpp b/src/devices/devfreq.cpp
>> new file mode 100644
>> index 0000000..29d7790
>> --- /dev/null
>> +++ b/src/devices/devfreq.cpp
>> @@ -0,0 +1,351 @@
>> +/*
>> + * Copyright 2012, Linaro
>> + *
>> + * This file is part of PowerTOP
>> + *
>> + * This program file is free software; you can redistribute it and/or
>> modify it
>> + * under the terms of the GNU General Public License as published by
>> the
>> + * Free Software Foundation; version 2 of the License.
>> + *
>> + * This program is distributed in the hope that it will be useful, but
>> WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
>> or
>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
>> License
>> + * for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program in a file named COPYING; if not, write to
>> the
>> + * Free Software Foundation, Inc,
>> + * 51 Franklin Street, Fifth Floor,
>> + * Boston, MA 02110-1301 USA
>> + * or just google for it.
>> + *
>> + * Authors:
>> + *	Rajagopal Venkat <rajagopal.venkat(a)linaro.org>
>> + */
>> +
>> +#include <iostream>
>> +#include <fstream>
>> +
>> +#include <dirent.h>
>> +#include <stdlib.h>
>> +#include <time.h>
>> +#include <unistd.h>
>> +
>> +#include "device.h"
>> +#include "devfreq.h"
>> +#include "../display.h"
>> +#include "../cpu/cpu.h"
>> +#include "../report/report.h"
>> +#include "../report/report-maker.h"
>> +
>> +static bool is_enabled = true;
>> +
>> +static vector<class devfreq *> all_devfreq;
>> +
>> +devfreq::devfreq(const char* dpath): device()
>> +{
>> +	strncpy(dir_name, dpath, sizeof(dir_name));
>> +}
>> +
>> +uint64_t devfreq::parse_freq_time(char* pchr)
>> +{
>> +	char *cptr, *pptr = pchr;
>> +	uint64_t ctime;
>> +
>> +	cptr = strtok(pchr, " :");
>> +	while (cptr != NULL) {
>> +		cptr = strtok(NULL, " :");
>> +		if (cptr )
>> +			pptr = cptr;
>> +	}
>> +
>> +	ctime = strtoull(pptr, NULL, 10);
>> +	return ctime;
>> +}
>> +
>> +void devfreq::process_time_stamps()
>> +{
>> +	unsigned int i;
>> +	uint64_t active_time = 0;
>> +
>> +	sample_time = (1000000.0 * (stamp_after.tv_sec - stamp_before.tv_sec))
>> +			+ ((stamp_after.tv_usec - stamp_before.tv_usec) );
>> +
>> +	for (i=0; i < dstates.size()-1; i++) {
>> +		struct frequency *state = dstates[i];
>> +		state->time_after = 1000 * (state->time_after - state->time_before);
>> +		active_time += state->time_after;
>> +	}
>> +	/* Compute idle time for the device */
>> +	dstates[i]->time_after = sample_time - active_time;
>> +}
>> +
>> +void devfreq::add_devfreq_freq_state(uint64_t freq, uint64_t time)
>> +{
>> +	struct frequency *state;
>> +
>> +	state = new(std::nothrow) struct frequency;
>> +	if (!state)
>> +		return;
>> +
>> +	memset(state, 0, sizeof(*state));
>> +	dstates.push_back(state);
>> +
>> +	state->freq = freq;
>> +	if (freq == 0)
>> +		strcpy(state->human_name, "Idle");
>> +	else
>> +		hz_to_human(freq, state->human_name);
>> +	state->time_before = time;
>> +}
>> +
>> +void devfreq::update_devfreq_freq_state(uint64_t freq, uint64_t time)
>> +{
>> +	unsigned int i;
>> +	struct frequency *state = NULL;
>> +
>> +	for(i=0; i < dstates.size(); i++) {
>> +		if (freq == dstates[i]->freq)
>> +			state = dstates[i];
>> +	}
>> +
>> +	if (state == NULL) {
>> +		add_devfreq_freq_state(freq, time);
>> +		return;
>> +	}
>> +
>> +	state->time_after = time;
>> +}
>> +
>> +void devfreq::parse_devfreq_trans_stat(char *dname)
>> +{
>> +	ifstream file;
>> +	char filename[256];
>> +
>> +	sprintf(filename, "/sys/class/devfreq/%s/trans_stat", dir_name);
>> +	file.open(filename);
>> +
>> +	if (!file)
>> +		return;
>> +
>> +	char line[1024];
>> +	char *c;
>> +
>> +	while (file) {
>> +		uint64_t freq;
>> +		uint64_t time;
>> +		char *pchr;
>> +
>> +		memset(line, 0, sizeof(line));
>> +		file.getline(line, sizeof(line));
>> +
>> +		pchr = strchr(line, '*');
>> +		pchr = (pchr != NULL) ? pchr+1 : line;
>> +
>> +		freq = strtoull(pchr, &c, 10);
>> +		if (!freq)
>> +			continue;
>> +
>> +		time = parse_freq_time(pchr);
>> +		update_devfreq_freq_state(freq, time);
>> +	}
>> +	file.close();
>> +}
>> +
>> +void devfreq::start_measurement(void)
>> +{
>> +	unsigned int i;
>> +	ifstream file;
>> +
>> +	for (i=0; i < dstates.size(); i++)
>> +		delete dstates[i];
>> +	dstates.resize(0);
>> +	sample_time = 0;
>> +
>> +	gettimeofday(&stamp_before, NULL);
>> +	parse_devfreq_trans_stat(dir_name);
>> +	/* add device idle state */
>> +	update_devfreq_freq_state(0, 0);
>> +}
>> +
>> +void devfreq::end_measurement(void)
>> +{
>> +	parse_devfreq_trans_stat(dir_name);
>> +	gettimeofday(&stamp_after, NULL);
>> +	process_time_stamps();
>> +}
>> +
>> +double devfreq::power_usage(struct result_bundle *result, struct
>> parameter_bundle *bundle)
>> +{
>> +	return 0;
>> +}
>> +
>> +double devfreq::utilization(void)
>> +{
>> +	return 0;
>> +}
>> +
>> +void devfreq::fill_freq_utilization(unsigned int idx, char *buf)
>> +{
>> +	buf[0] = 0;
>> +
>> +	if (idx < dstates.size() && dstates[idx]) {
>> +		struct frequency *state = dstates[idx];
>> +		sprintf(buf, " %5.1f%% ", percentage(1.0 * state->time_after /
>> sample_time));
>> +	}
>> +}
>> +
>> +void devfreq::fill_freq_name(unsigned int idx, char *buf)
>> +{
>> +	buf[0] = 0;
>> +
>> +	if (idx < dstates.size() && dstates[idx]) {
>> +		sprintf(buf, "%-15s", dstates[idx]->human_name);
>> +	}
>> +}
>> +
>> +void start_devfreq_measurement(void)
>> +{
>> +	unsigned int i;
>> +
>> +	for (i=0; i<all_devfreq.size(); i++)
>> +		all_devfreq[i]->start_measurement();
>> +}
>> +
>> +void end_devfreq_measurement(void)
>> +{
>> +	unsigned int i;
>> +
>> +	for (i=0; i<all_devfreq.size(); i++)
>> +		all_devfreq[i]->end_measurement();
>> +}
>> +
>> +static void devfreq_dev_callback(const char *d_name)
>> +{
>> +	devfreq *df = new(std::nothrow) class devfreq(d_name);
>> +	if (df)
>> +		all_devfreq.push_back(df);
>> +}
>> +
>> +void create_all_devfreq_devices(void)
>> +{
>> +	DIR *dir;
>> +	std::string p = "/sys/class/devfreq/";
>> +	dir = opendir(p.c_str());
>> +	if (dir == NULL) {
>> +		fprintf(stderr, "Devfreq not enabled\n");
>> +		is_enabled = false;
>> +		return;
>> +	}
>> +
>> +	callback fn = &devfreq_dev_callback;
>> +	process_directory(p.c_str(), fn);
>> +}
>> +
>> +void initialize_devfreq(void)
>> +{
>> +	if (is_enabled)
>> +		create_tab("Device Freq stats", _("Device Freq stats"));
>> +}
>> +
>> +void display_devfreq_devices(void)
>> +{
>> +	unsigned int i, j;
>> +	WINDOW *win;
>> +	char fline[1024];
>> +	char buf[128];
>> +
>> +	win = get_ncurses_win("Device Freq stats");
>> +        if (!win)
>> +                return;
>> +
>> +        wclear(win);
>> +        wmove(win, 2,0);
>> +
>> +	if (!is_enabled) {
>> +		wprintw(win, _(" Devfreq is not enabled"));
>> +		return;
>> +	}
>> +
>> +	if (!all_devfreq.size()) {
>> +		wprintw(win, _(" No devfreq devices available"));
>> +		return;
>> +	}
>> +
>> +	for (i=0; i<all_devfreq.size(); i++) {
>> +
>> +		class devfreq *df = all_devfreq[i];
>> +		wprintw(win, "\n%s\n", df->device_name());
>> +
>> +		for(j=0; j < df->dstates.size(); j++) {
>> +			memset(fline, 0, sizeof(fline));
>> +			strcpy(fline, "\t");
>> +			df->fill_freq_name(j, buf);
>> +			strcat(fline, buf);
>> +			df->fill_freq_utilization(j, buf);
>> +			strcat(fline, buf);
>> +			strcat(fline, "\n");
>> +			wprintw(win, fline);
>> +		}
>> +		wprintw(win, "\n");
>> +	}
>> +}
>> +
>> +void report_devfreq_devices(void)
>> +{
>> +	if (!is_enabled) {
>> +		return;
>> +	}
>> +
>> +/* todo: adapt to new report format */
>> +#if 0
>> +	char buffer[512];
>> +	unsigned int i, j;
>> +
>> +	report.begin_section(SECTION_DEVFREQ);
>> +	report.add_header("Device Frequency Report");
>> +
>> +	report.begin_table(TABLE_WIDE);
>> +	if (!all_devfreq.size()) {
>> +		report.begin_row();
>> +		report.add(" No devfreq devices available");
>> +		return;
>> +	}
>> +
>> +	for (i = 0; i < all_devfreq.size(); i++) {
>> +		buffer[0] = 0;
>> +		class devfreq *df = all_devfreq[i];
>> +
>> +		report.begin_row();
>> +		report.begin_cell(CELL_CPU_PSTATE_HEADER);
>> +		report.addf("%s", df->device_name());
>> +
>> +		for (j = 0; j < df->dstates.size(); j++) {
>> +			report.begin_row();
>> +			report.begin_cell(CELL_CPU_STATE_VALUE);
>> +			df->fill_freq_name(j, buffer);
>> +			report.add(buffer);
>> +			report.begin_cell(CELL_CPU_STATE_VALUE);
>> +			df->fill_freq_utilization(j, buffer);
>> +			report.add(buffer);
>> +		}
>> +	}
>> +#endif
>> +
>> +}
>> +
>> +void clear_all_devfreq()
>> +{
>> +	unsigned int i, j;
>> +
>> +	for (i=0; i < all_devfreq.size(); i++) {
>> +		class devfreq *df = all_devfreq[i];
>> +
>> +		for(j=0; j < df->dstates.size(); j++)
>> +			delete df->dstates[j];
>> +
>> +		df->dstates.resize(0);
>> +		delete df;
>> +	}
>> +	all_devfreq.clear();
>> +}
>> diff --git a/src/devices/devfreq.h b/src/devices/devfreq.h
>> new file mode 100644
>> index 0000000..8ab5705
>> --- /dev/null
>> +++ b/src/devices/devfreq.h
>> @@ -0,0 +1,75 @@
>> +/*
>> + * Copyright 2012, Linaro
>> + *
>> + * This file is part of PowerTOP
>> + *
>> + * This program file is free software; you can redistribute it and/or
>> modify it
>> + * under the terms of the GNU General Public License as published by
>> the
>> + * Free Software Foundation; version 2 of the License.
>> + *
>> + * This program is distributed in the hope that it will be useful, but
>> WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
>> or
>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
>> License
>> + * for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program in a file named COPYING; if not, write to
>> the
>> + * Free Software Foundation, Inc,
>> + * 51 Franklin Street, Fifth Floor,
>> + * Boston, MA 02110-1301 USA
>> + * or just google for it.
>> + *
>> + * Authors:
>> + *	Rajagopal Venkat <rajagopal.venkat(a)linaro.org>
>> + */
>> +#ifndef _INCLUDE_GUARD_DEVFREQ_H
>> +#define _INCLUDE_GUARD_DEVFREQ_H
>> +
>> +#include "device.h"
>> +#include "../parameters/parameters.h"
>> +
>> +struct frequency;
>> +
>> +class devfreq: public device {
>> +	char dir_name[4096];
>> +	struct timeval  stamp_before, stamp_after;
>> +	double sample_time;
>> +
>> +	uint64_t parse_freq_time(char *ptr);
>> +	void add_devfreq_freq_state(uint64_t freq, uint64_t time);
>> +	void update_devfreq_freq_state(uint64_t freq, uint64_t time);
>> +	void parse_devfreq_trans_stat(char *dname);
>> +	void process_time_stamps();
>> +
>> +public:
>> +
>> +	vector<struct frequency *> dstates;
>> +
>> +	devfreq(const char *c);
>> +	void fill_freq_utilization(unsigned int idx, char *buf);
>> +	void fill_freq_name(unsigned int idx, char *buf);
>> +
>> +	virtual void start_measurement(void);
>> +	virtual void end_measurement(void);
>> +
>> +	virtual double	utilization(void); /* percentage */
>> +
>> +	virtual const char * class_name(void) { return "devfreq";};
>> +
>> +	virtual const char * device_name(void) { return dir_name;};
>> +	virtual const char * human_name(void) { return "devfreq";};
>> +	virtual double power_usage(struct result_bundle *result, struct
>> parameter_bundle *bundle);
>> +	virtual const char * util_units(void) { return " rpm"; };
>> +	virtual int power_valid(void) { return 0;
>> /*utilization_power_valid(r_index);*/};
>> +	virtual int grouping_prio(void) { return 1; };
>> +};
>> +
>> +extern void create_all_devfreq_devices(void);
>> +extern void clear_all_devfreq(void);
>> +extern void display_devfreq_devices(void);
>> +extern void report_devfreq_devices(void);
>> +extern void initialize_devfreq(void);
>> +extern void start_devfreq_measurement(void);
>> +extern void end_devfreq_measurement(void);
>> +
>> +#endif
>> diff --git a/src/main.cpp b/src/main.cpp
>> index cf4e547..d33eaed 100644
>> --- a/src/main.cpp
>> +++ b/src/main.cpp
>> @@ -48,6 +48,7 @@
>>
>>
>>  #include "devices/device.h"
>> +#include "devices/devfreq.h"
>>  #include "devices/usb.h"
>>  #include "devices/ahci.h"
>>  #include "measurement/measurement.h"
>> @@ -194,6 +195,7 @@ void one_measurement(int seconds, char *workload)
>>  	create_all_usb_devices();
>>  	start_power_measurement();
>>  	devices_start_measurement();
>> +	start_devfreq_measurement();
>>  	start_process_measurement();
>>  	start_cpu_measurement();
>>
>> @@ -206,6 +208,7 @@ void one_measurement(int seconds, char *workload)
>>  	end_cpu_measurement();
>>  	end_process_measurement();
>>  	collect_open_devices();
>> +	end_devfreq_measurement();
>>  	devices_end_measurement();
>>  	end_power_measurement();
>>
>> @@ -233,6 +236,9 @@ void one_measurement(int seconds, char *workload)
>>  	report_show_open_devices();
>>
>>  	report_devices();
>> +	display_devfreq_devices();
>> +	report_devfreq_devices();
>> +
>>  	ahci_create_device_stats_table();
>>  	store_results(measurement_time);
>>  	end_cpu_data();
>> @@ -344,6 +350,7 @@ static void powertop_init(void)
>>
>>  	enumerate_cpus();
>>  	create_all_devices();
>> +	create_all_devfreq_devices();
>>  	detect_power_meters();
>>
>>  	register_parameter("base power", 100, 0.5);
>> @@ -457,6 +464,7 @@ int main(int argc, char **argv)
>>  		exit(0);
>>  	}
>>  	init_display();
>> +	initialize_devfreq();
>>  	initialize_tuning();
>>  	/* first one is short to not let the user wait too long */
>>  	one_measurement(1, NULL);
>> @@ -491,6 +499,7 @@ int main(int argc, char **argv)
>>
>>  	clean_open_devices();
>>  	clear_all_devices();
>> +	clear_all_devfreq();
>>  	clear_all_cpus();
>>
>>  	return 0;
>> diff --git a/src/report/report-maker.h b/src/report/report-maker.h
>> index 423568a..bda4cef 100644
>> --- a/src/report/report-maker.h
>> +++ b/src/report/report-maker.h
>> @@ -89,6 +89,7 @@ enum section_type {
>>  	SECTION_SYSINFO,
>>  	SECTION_CPUIDLE,
>>  	SECTION_CPUFREQ,
>> +	SECTION_DEVFREQ,
>>  	SECTION_DEVPOWER,
>>  	SECTION_SOFTWARE,
>>  	SECTION_SUMMARY,
>> --
>> 1.8.3.2
>>
>> _______________________________________________
>> PowerTop mailing list
>> PowerTop(a)lists.01.org
>> https://lists.01.org/mailman/listinfo/powertop
>>
>
> Hi Sanjay,
>
> It would be better that Device Frequency Stats appears only when
> /sys/class/devfewq is present on the system.  That will simplify code
> execution at runtime and remove the blank window with "No devfreq devices
> available".
>
> Thank you,
> Alexandra.
> _______________________________________________
> PowerTop mailing list
> PowerTop(a)lists.01.org
> https://lists.01.org/mailman/listinfo/powertop
>

I'm testing the code doesn't break Intel support.  Please Sergey
Senozhatsky and any one else in the community can you help me test this
patch on ARM platforms.

Thank you,
Alexandra.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Powertop] [PATCH] devfreq: add devfreq devices stats support
@ 2014-09-29 22:46 Alexandra Yates
  0 siblings, 0 replies; 13+ messages in thread
From: Alexandra Yates @ 2014-09-29 22:46 UTC (permalink / raw)
  To: powertop

[-- Attachment #1: Type: text/plain, Size: 15758 bytes --]


> add window to show frequency stats for devfreq devices
>
> Signed-off-by: Rajagopal Venkat <rajagopal.venkat(a)gmail.com>
> Signed-off-by: Sanjay Singh Rawat <sanjay.rawat(a)linaro.org>
> ---
>  src/Makefile.am           |   2 +-
>  src/devices/devfreq.cpp   | 351
> ++++++++++++++++++++++++++++++++++++++++++++++
>  src/devices/devfreq.h     |  75 ++++++++++
>  src/main.cpp              |   9 ++
>  src/report/report-maker.h |   1 +
>  5 files changed, 437 insertions(+), 1 deletion(-)
>  create mode 100644 src/devices/devfreq.cpp
>  create mode 100644 src/devices/devfreq.h
>
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 6886388..fee1ffa 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -32,7 +32,7 @@ powertop_SOURCES = parameters/persistent.cpp
> parameters/learn.cpp parameters/par
>  		report/report-formatter-csv.cpp report/report-formatter-csv.h \
>  		report/report-formatter-html.cpp report/report-formatter-html.h \
>  		report/report-data-html.cpp report/report-data-html.h \
> -		main.cpp css.h powertop.css cpu/intel_gpu.cpp \
> +		main.cpp css.h powertop.css cpu/intel_gpu.cpp devices/devfreq.cpp \
>  		cpu/rapl/rapl_interface.cpp cpu/cpu_rapl_device.cpp
> cpu/rapl/rapl_interface.h\
>  		cpu/dram_rapl_device.cpp devices/gpu_rapl_device.cpp
> cpu/cpu_rapl_device.h \
>  		cpu/dram_rapl_device.h devices/gpu_rapl_device.h
> diff --git a/src/devices/devfreq.cpp b/src/devices/devfreq.cpp
> new file mode 100644
> index 0000000..29d7790
> --- /dev/null
> +++ b/src/devices/devfreq.cpp
> @@ -0,0 +1,351 @@
> +/*
> + * Copyright 2012, Linaro
> + *
> + * This file is part of PowerTOP
> + *
> + * This program file is free software; you can redistribute it and/or
> modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but
> WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> + * for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program in a file named COPYING; if not, write to the
> + * Free Software Foundation, Inc,
> + * 51 Franklin Street, Fifth Floor,
> + * Boston, MA 02110-1301 USA
> + * or just google for it.
> + *
> + * Authors:
> + *	Rajagopal Venkat <rajagopal.venkat(a)linaro.org>
> + */
> +
> +#include <iostream>
> +#include <fstream>
> +
> +#include <dirent.h>
> +#include <stdlib.h>
> +#include <time.h>
> +#include <unistd.h>
> +
> +#include "device.h"
> +#include "devfreq.h"
> +#include "../display.h"
> +#include "../cpu/cpu.h"
> +#include "../report/report.h"
> +#include "../report/report-maker.h"
> +
> +static bool is_enabled = true;
> +
> +static vector<class devfreq *> all_devfreq;
> +
> +devfreq::devfreq(const char* dpath): device()
> +{
> +	strncpy(dir_name, dpath, sizeof(dir_name));
> +}
> +
> +uint64_t devfreq::parse_freq_time(char* pchr)
> +{
> +	char *cptr, *pptr = pchr;
> +	uint64_t ctime;
> +
> +	cptr = strtok(pchr, " :");
> +	while (cptr != NULL) {
> +		cptr = strtok(NULL, " :");
> +		if (cptr )
> +			pptr = cptr;
> +	}
> +
> +	ctime = strtoull(pptr, NULL, 10);
> +	return ctime;
> +}
> +
> +void devfreq::process_time_stamps()
> +{
> +	unsigned int i;
> +	uint64_t active_time = 0;
> +
> +	sample_time = (1000000.0 * (stamp_after.tv_sec - stamp_before.tv_sec))
> +			+ ((stamp_after.tv_usec - stamp_before.tv_usec) );
> +
> +	for (i=0; i < dstates.size()-1; i++) {
> +		struct frequency *state = dstates[i];
> +		state->time_after = 1000 * (state->time_after - state->time_before);
> +		active_time += state->time_after;
> +	}
> +	/* Compute idle time for the device */
> +	dstates[i]->time_after = sample_time - active_time;
> +}
> +
> +void devfreq::add_devfreq_freq_state(uint64_t freq, uint64_t time)
> +{
> +	struct frequency *state;
> +
> +	state = new(std::nothrow) struct frequency;
> +	if (!state)
> +		return;
> +
> +	memset(state, 0, sizeof(*state));
> +	dstates.push_back(state);
> +
> +	state->freq = freq;
> +	if (freq == 0)
> +		strcpy(state->human_name, "Idle");
> +	else
> +		hz_to_human(freq, state->human_name);
> +	state->time_before = time;
> +}
> +
> +void devfreq::update_devfreq_freq_state(uint64_t freq, uint64_t time)
> +{
> +	unsigned int i;
> +	struct frequency *state = NULL;
> +
> +	for(i=0; i < dstates.size(); i++) {
> +		if (freq == dstates[i]->freq)
> +			state = dstates[i];
> +	}
> +
> +	if (state == NULL) {
> +		add_devfreq_freq_state(freq, time);
> +		return;
> +	}
> +
> +	state->time_after = time;
> +}
> +
> +void devfreq::parse_devfreq_trans_stat(char *dname)
> +{
> +	ifstream file;
> +	char filename[256];
> +
> +	sprintf(filename, "/sys/class/devfreq/%s/trans_stat", dir_name);
> +	file.open(filename);
> +
> +	if (!file)
> +		return;
> +
> +	char line[1024];
> +	char *c;
> +
> +	while (file) {
> +		uint64_t freq;
> +		uint64_t time;
> +		char *pchr;
> +
> +		memset(line, 0, sizeof(line));
> +		file.getline(line, sizeof(line));
> +
> +		pchr = strchr(line, '*');
> +		pchr = (pchr != NULL) ? pchr+1 : line;
> +
> +		freq = strtoull(pchr, &c, 10);
> +		if (!freq)
> +			continue;
> +
> +		time = parse_freq_time(pchr);
> +		update_devfreq_freq_state(freq, time);
> +	}
> +	file.close();
> +}
> +
> +void devfreq::start_measurement(void)
> +{
> +	unsigned int i;
> +	ifstream file;
> +
> +	for (i=0; i < dstates.size(); i++)
> +		delete dstates[i];
> +	dstates.resize(0);
> +	sample_time = 0;
> +
> +	gettimeofday(&stamp_before, NULL);
> +	parse_devfreq_trans_stat(dir_name);
> +	/* add device idle state */
> +	update_devfreq_freq_state(0, 0);
> +}
> +
> +void devfreq::end_measurement(void)
> +{
> +	parse_devfreq_trans_stat(dir_name);
> +	gettimeofday(&stamp_after, NULL);
> +	process_time_stamps();
> +}
> +
> +double devfreq::power_usage(struct result_bundle *result, struct
> parameter_bundle *bundle)
> +{
> +	return 0;
> +}
> +
> +double devfreq::utilization(void)
> +{
> +	return 0;
> +}
> +
> +void devfreq::fill_freq_utilization(unsigned int idx, char *buf)
> +{
> +	buf[0] = 0;
> +
> +	if (idx < dstates.size() && dstates[idx]) {
> +		struct frequency *state = dstates[idx];
> +		sprintf(buf, " %5.1f%% ", percentage(1.0 * state->time_after /
> sample_time));
> +	}
> +}
> +
> +void devfreq::fill_freq_name(unsigned int idx, char *buf)
> +{
> +	buf[0] = 0;
> +
> +	if (idx < dstates.size() && dstates[idx]) {
> +		sprintf(buf, "%-15s", dstates[idx]->human_name);
> +	}
> +}
> +
> +void start_devfreq_measurement(void)
> +{
> +	unsigned int i;
> +
> +	for (i=0; i<all_devfreq.size(); i++)
> +		all_devfreq[i]->start_measurement();
> +}
> +
> +void end_devfreq_measurement(void)
> +{
> +	unsigned int i;
> +
> +	for (i=0; i<all_devfreq.size(); i++)
> +		all_devfreq[i]->end_measurement();
> +}
> +
> +static void devfreq_dev_callback(const char *d_name)
> +{
> +	devfreq *df = new(std::nothrow) class devfreq(d_name);
> +	if (df)
> +		all_devfreq.push_back(df);
> +}
> +
> +void create_all_devfreq_devices(void)
> +{
> +	DIR *dir;
> +	std::string p = "/sys/class/devfreq/";
> +	dir = opendir(p.c_str());
> +	if (dir == NULL) {
> +		fprintf(stderr, "Devfreq not enabled\n");
> +		is_enabled = false;
> +		return;
> +	}
> +
> +	callback fn = &devfreq_dev_callback;
> +	process_directory(p.c_str(), fn);
> +}
> +
> +void initialize_devfreq(void)
> +{
> +	if (is_enabled)
> +		create_tab("Device Freq stats", _("Device Freq stats"));
> +}
> +
> +void display_devfreq_devices(void)
> +{
> +	unsigned int i, j;
> +	WINDOW *win;
> +	char fline[1024];
> +	char buf[128];
> +
> +	win = get_ncurses_win("Device Freq stats");
> +        if (!win)
> +                return;
> +
> +        wclear(win);
> +        wmove(win, 2,0);
> +
> +	if (!is_enabled) {
> +		wprintw(win, _(" Devfreq is not enabled"));
> +		return;
> +	}
> +
> +	if (!all_devfreq.size()) {
> +		wprintw(win, _(" No devfreq devices available"));
> +		return;
> +	}
> +
> +	for (i=0; i<all_devfreq.size(); i++) {
> +
> +		class devfreq *df = all_devfreq[i];
> +		wprintw(win, "\n%s\n", df->device_name());
> +
> +		for(j=0; j < df->dstates.size(); j++) {
> +			memset(fline, 0, sizeof(fline));
> +			strcpy(fline, "\t");
> +			df->fill_freq_name(j, buf);
> +			strcat(fline, buf);
> +			df->fill_freq_utilization(j, buf);
> +			strcat(fline, buf);
> +			strcat(fline, "\n");
> +			wprintw(win, fline);
> +		}
> +		wprintw(win, "\n");
> +	}
> +}
> +
> +void report_devfreq_devices(void)
> +{
> +	if (!is_enabled) {
> +		return;
> +	}
> +
> +/* todo: adapt to new report format */
> +#if 0
> +	char buffer[512];
> +	unsigned int i, j;
> +
> +	report.begin_section(SECTION_DEVFREQ);
> +	report.add_header("Device Frequency Report");
> +
> +	report.begin_table(TABLE_WIDE);
> +	if (!all_devfreq.size()) {
> +		report.begin_row();
> +		report.add(" No devfreq devices available");
> +		return;
> +	}
> +
> +	for (i = 0; i < all_devfreq.size(); i++) {
> +		buffer[0] = 0;
> +		class devfreq *df = all_devfreq[i];
> +
> +		report.begin_row();
> +		report.begin_cell(CELL_CPU_PSTATE_HEADER);
> +		report.addf("%s", df->device_name());
> +
> +		for (j = 0; j < df->dstates.size(); j++) {
> +			report.begin_row();
> +			report.begin_cell(CELL_CPU_STATE_VALUE);
> +			df->fill_freq_name(j, buffer);
> +			report.add(buffer);
> +			report.begin_cell(CELL_CPU_STATE_VALUE);
> +			df->fill_freq_utilization(j, buffer);
> +			report.add(buffer);
> +		}
> +	}
> +#endif
> +
> +}
> +
> +void clear_all_devfreq()
> +{
> +	unsigned int i, j;
> +
> +	for (i=0; i < all_devfreq.size(); i++) {
> +		class devfreq *df = all_devfreq[i];
> +
> +		for(j=0; j < df->dstates.size(); j++)
> +			delete df->dstates[j];
> +
> +		df->dstates.resize(0);
> +		delete df;
> +	}
> +	all_devfreq.clear();
> +}
> diff --git a/src/devices/devfreq.h b/src/devices/devfreq.h
> new file mode 100644
> index 0000000..8ab5705
> --- /dev/null
> +++ b/src/devices/devfreq.h
> @@ -0,0 +1,75 @@
> +/*
> + * Copyright 2012, Linaro
> + *
> + * This file is part of PowerTOP
> + *
> + * This program file is free software; you can redistribute it and/or
> modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but
> WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> + * for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program in a file named COPYING; if not, write to the
> + * Free Software Foundation, Inc,
> + * 51 Franklin Street, Fifth Floor,
> + * Boston, MA 02110-1301 USA
> + * or just google for it.
> + *
> + * Authors:
> + *	Rajagopal Venkat <rajagopal.venkat(a)linaro.org>
> + */
> +#ifndef _INCLUDE_GUARD_DEVFREQ_H
> +#define _INCLUDE_GUARD_DEVFREQ_H
> +
> +#include "device.h"
> +#include "../parameters/parameters.h"
> +
> +struct frequency;
> +
> +class devfreq: public device {
> +	char dir_name[4096];
> +	struct timeval  stamp_before, stamp_after;
> +	double sample_time;
> +
> +	uint64_t parse_freq_time(char *ptr);
> +	void add_devfreq_freq_state(uint64_t freq, uint64_t time);
> +	void update_devfreq_freq_state(uint64_t freq, uint64_t time);
> +	void parse_devfreq_trans_stat(char *dname);
> +	void process_time_stamps();
> +
> +public:
> +
> +	vector<struct frequency *> dstates;
> +
> +	devfreq(const char *c);
> +	void fill_freq_utilization(unsigned int idx, char *buf);
> +	void fill_freq_name(unsigned int idx, char *buf);
> +
> +	virtual void start_measurement(void);
> +	virtual void end_measurement(void);
> +
> +	virtual double	utilization(void); /* percentage */
> +
> +	virtual const char * class_name(void) { return "devfreq";};
> +
> +	virtual const char * device_name(void) { return dir_name;};
> +	virtual const char * human_name(void) { return "devfreq";};
> +	virtual double power_usage(struct result_bundle *result, struct
> parameter_bundle *bundle);
> +	virtual const char * util_units(void) { return " rpm"; };
> +	virtual int power_valid(void) { return 0;
> /*utilization_power_valid(r_index);*/};
> +	virtual int grouping_prio(void) { return 1; };
> +};
> +
> +extern void create_all_devfreq_devices(void);
> +extern void clear_all_devfreq(void);
> +extern void display_devfreq_devices(void);
> +extern void report_devfreq_devices(void);
> +extern void initialize_devfreq(void);
> +extern void start_devfreq_measurement(void);
> +extern void end_devfreq_measurement(void);
> +
> +#endif
> diff --git a/src/main.cpp b/src/main.cpp
> index cf4e547..d33eaed 100644
> --- a/src/main.cpp
> +++ b/src/main.cpp
> @@ -48,6 +48,7 @@
>
>
>  #include "devices/device.h"
> +#include "devices/devfreq.h"
>  #include "devices/usb.h"
>  #include "devices/ahci.h"
>  #include "measurement/measurement.h"
> @@ -194,6 +195,7 @@ void one_measurement(int seconds, char *workload)
>  	create_all_usb_devices();
>  	start_power_measurement();
>  	devices_start_measurement();
> +	start_devfreq_measurement();
>  	start_process_measurement();
>  	start_cpu_measurement();
>
> @@ -206,6 +208,7 @@ void one_measurement(int seconds, char *workload)
>  	end_cpu_measurement();
>  	end_process_measurement();
>  	collect_open_devices();
> +	end_devfreq_measurement();
>  	devices_end_measurement();
>  	end_power_measurement();
>
> @@ -233,6 +236,9 @@ void one_measurement(int seconds, char *workload)
>  	report_show_open_devices();
>
>  	report_devices();
> +	display_devfreq_devices();
> +	report_devfreq_devices();
> +
>  	ahci_create_device_stats_table();
>  	store_results(measurement_time);
>  	end_cpu_data();
> @@ -344,6 +350,7 @@ static void powertop_init(void)
>
>  	enumerate_cpus();
>  	create_all_devices();
> +	create_all_devfreq_devices();
>  	detect_power_meters();
>
>  	register_parameter("base power", 100, 0.5);
> @@ -457,6 +464,7 @@ int main(int argc, char **argv)
>  		exit(0);
>  	}
>  	init_display();
> +	initialize_devfreq();
>  	initialize_tuning();
>  	/* first one is short to not let the user wait too long */
>  	one_measurement(1, NULL);
> @@ -491,6 +499,7 @@ int main(int argc, char **argv)
>
>  	clean_open_devices();
>  	clear_all_devices();
> +	clear_all_devfreq();
>  	clear_all_cpus();
>
>  	return 0;
> diff --git a/src/report/report-maker.h b/src/report/report-maker.h
> index 423568a..bda4cef 100644
> --- a/src/report/report-maker.h
> +++ b/src/report/report-maker.h
> @@ -89,6 +89,7 @@ enum section_type {
>  	SECTION_SYSINFO,
>  	SECTION_CPUIDLE,
>  	SECTION_CPUFREQ,
> +	SECTION_DEVFREQ,
>  	SECTION_DEVPOWER,
>  	SECTION_SOFTWARE,
>  	SECTION_SUMMARY,
> --
> 1.8.3.2
>
> _______________________________________________
> PowerTop mailing list
> PowerTop(a)lists.01.org
> https://lists.01.org/mailman/listinfo/powertop
>

Hi Sanjay,

It would be better that Device Frequency Stats appears only when
/sys/class/devfewq is present on the system.  That will simplify code
execution at runtime and remove the blank window with "No devfreq devices
available".

Thank you,
Alexandra.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Powertop] [PATCH] devfreq: add devfreq devices stats support
@ 2014-09-17  4:16 Sanjay Singh Rawat
  0 siblings, 0 replies; 13+ messages in thread
From: Sanjay Singh Rawat @ 2014-09-17  4:16 UTC (permalink / raw)
  To: powertop

[-- Attachment #1: Type: text/plain, Size: 15535 bytes --]

hello Alexandra,

Can you please review the patch and share your comments?

thanks,
sanjay

On Monday 25 August 2014 12:28 PM, Sanjay Singh Rawat wrote:
> add window to show frequency stats for devfreq devices
>
> Signed-off-by: Rajagopal Venkat <rajagopal.venkat(a)gmail.com>
> Signed-off-by: Sanjay Singh Rawat <sanjay.rawat(a)linaro.org>
> ---
>   src/Makefile.am           |   2 +-
>   src/devices/devfreq.cpp   | 351 ++++++++++++++++++++++++++++++++++++++++++++++
>   src/devices/devfreq.h     |  75 ++++++++++
>   src/main.cpp              |   9 ++
>   src/report/report-maker.h |   1 +
>   5 files changed, 437 insertions(+), 1 deletion(-)
>   create mode 100644 src/devices/devfreq.cpp
>   create mode 100644 src/devices/devfreq.h
>
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 6886388..fee1ffa 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -32,7 +32,7 @@ powertop_SOURCES = parameters/persistent.cpp parameters/learn.cpp parameters/par
>   		report/report-formatter-csv.cpp report/report-formatter-csv.h \
>   		report/report-formatter-html.cpp report/report-formatter-html.h \
>   		report/report-data-html.cpp report/report-data-html.h \
> -		main.cpp css.h powertop.css cpu/intel_gpu.cpp \
> +		main.cpp css.h powertop.css cpu/intel_gpu.cpp devices/devfreq.cpp \
>   		cpu/rapl/rapl_interface.cpp cpu/cpu_rapl_device.cpp cpu/rapl/rapl_interface.h\
>   		cpu/dram_rapl_device.cpp devices/gpu_rapl_device.cpp cpu/cpu_rapl_device.h \
>   		cpu/dram_rapl_device.h devices/gpu_rapl_device.h
> diff --git a/src/devices/devfreq.cpp b/src/devices/devfreq.cpp
> new file mode 100644
> index 0000000..29d7790
> --- /dev/null
> +++ b/src/devices/devfreq.cpp
> @@ -0,0 +1,351 @@
> +/*
> + * Copyright 2012, Linaro
> + *
> + * This file is part of PowerTOP
> + *
> + * This program file is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> + * for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program in a file named COPYING; if not, write to the
> + * Free Software Foundation, Inc,
> + * 51 Franklin Street, Fifth Floor,
> + * Boston, MA 02110-1301 USA
> + * or just google for it.
> + *
> + * Authors:
> + *	Rajagopal Venkat <rajagopal.venkat(a)linaro.org>
> + */
> +
> +#include <iostream>
> +#include <fstream>
> +
> +#include <dirent.h>
> +#include <stdlib.h>
> +#include <time.h>
> +#include <unistd.h>
> +
> +#include "device.h"
> +#include "devfreq.h"
> +#include "../display.h"
> +#include "../cpu/cpu.h"
> +#include "../report/report.h"
> +#include "../report/report-maker.h"
> +
> +static bool is_enabled = true;
> +
> +static vector<class devfreq *> all_devfreq;
> +
> +devfreq::devfreq(const char* dpath): device()
> +{
> +	strncpy(dir_name, dpath, sizeof(dir_name));
> +}
> +
> +uint64_t devfreq::parse_freq_time(char* pchr)
> +{
> +	char *cptr, *pptr = pchr;
> +	uint64_t ctime;
> +
> +	cptr = strtok(pchr, " :");
> +	while (cptr != NULL) {
> +		cptr = strtok(NULL, " :");
> +		if (cptr )
> +			pptr = cptr;
> +	}
> +
> +	ctime = strtoull(pptr, NULL, 10);
> +	return ctime;
> +}
> +
> +void devfreq::process_time_stamps()
> +{
> +	unsigned int i;
> +	uint64_t active_time = 0;
> +
> +	sample_time = (1000000.0 * (stamp_after.tv_sec - stamp_before.tv_sec))
> +			+ ((stamp_after.tv_usec - stamp_before.tv_usec) );
> +
> +	for (i=0; i < dstates.size()-1; i++) {
> +		struct frequency *state = dstates[i];
> +		state->time_after = 1000 * (state->time_after - state->time_before);
> +		active_time += state->time_after;
> +	}
> +	/* Compute idle time for the device */
> +	dstates[i]->time_after = sample_time - active_time;
> +}
> +
> +void devfreq::add_devfreq_freq_state(uint64_t freq, uint64_t time)
> +{
> +	struct frequency *state;
> +
> +	state = new(std::nothrow) struct frequency;
> +	if (!state)
> +		return;
> +
> +	memset(state, 0, sizeof(*state));
> +	dstates.push_back(state);
> +
> +	state->freq = freq;
> +	if (freq == 0)
> +		strcpy(state->human_name, "Idle");
> +	else
> +		hz_to_human(freq, state->human_name);
> +	state->time_before = time;
> +}
> +
> +void devfreq::update_devfreq_freq_state(uint64_t freq, uint64_t time)
> +{
> +	unsigned int i;
> +	struct frequency *state = NULL;
> +
> +	for(i=0; i < dstates.size(); i++) {
> +		if (freq == dstates[i]->freq)
> +			state = dstates[i];
> +	}
> +
> +	if (state == NULL) {
> +		add_devfreq_freq_state(freq, time);
> +		return;
> +	}
> +
> +	state->time_after = time;
> +}
> +
> +void devfreq::parse_devfreq_trans_stat(char *dname)
> +{
> +	ifstream file;
> +	char filename[256];
> +
> +	sprintf(filename, "/sys/class/devfreq/%s/trans_stat", dir_name);
> +	file.open(filename);
> +
> +	if (!file)
> +		return;
> +
> +	char line[1024];
> +	char *c;
> +
> +	while (file) {
> +		uint64_t freq;
> +		uint64_t time;
> +		char *pchr;
> +
> +		memset(line, 0, sizeof(line));
> +		file.getline(line, sizeof(line));
> +
> +		pchr = strchr(line, '*');
> +		pchr = (pchr != NULL) ? pchr+1 : line;
> +
> +		freq = strtoull(pchr, &c, 10);
> +		if (!freq)
> +			continue;
> +
> +		time = parse_freq_time(pchr);
> +		update_devfreq_freq_state(freq, time);
> +	}
> +	file.close();
> +}
> +
> +void devfreq::start_measurement(void)
> +{
> +	unsigned int i;
> +	ifstream file;
> +
> +	for (i=0; i < dstates.size(); i++)
> +		delete dstates[i];
> +	dstates.resize(0);
> +	sample_time = 0;
> +
> +	gettimeofday(&stamp_before, NULL);
> +	parse_devfreq_trans_stat(dir_name);
> +	/* add device idle state */
> +	update_devfreq_freq_state(0, 0);
> +}
> +
> +void devfreq::end_measurement(void)
> +{
> +	parse_devfreq_trans_stat(dir_name);
> +	gettimeofday(&stamp_after, NULL);
> +	process_time_stamps();
> +}
> +
> +double devfreq::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
> +{
> +	return 0;
> +}
> +
> +double devfreq::utilization(void)
> +{
> +	return 0;
> +}
> +
> +void devfreq::fill_freq_utilization(unsigned int idx, char *buf)
> +{
> +	buf[0] = 0;
> +
> +	if (idx < dstates.size() && dstates[idx]) {
> +		struct frequency *state = dstates[idx];
> +		sprintf(buf, " %5.1f%% ", percentage(1.0 * state->time_after / sample_time));
> +	}
> +}
> +
> +void devfreq::fill_freq_name(unsigned int idx, char *buf)
> +{
> +	buf[0] = 0;
> +
> +	if (idx < dstates.size() && dstates[idx]) {
> +		sprintf(buf, "%-15s", dstates[idx]->human_name);
> +	}
> +}
> +
> +void start_devfreq_measurement(void)
> +{
> +	unsigned int i;
> +
> +	for (i=0; i<all_devfreq.size(); i++)
> +		all_devfreq[i]->start_measurement();
> +}
> +
> +void end_devfreq_measurement(void)
> +{
> +	unsigned int i;
> +
> +	for (i=0; i<all_devfreq.size(); i++)
> +		all_devfreq[i]->end_measurement();
> +}
> +
> +static void devfreq_dev_callback(const char *d_name)
> +{
> +	devfreq *df = new(std::nothrow) class devfreq(d_name);
> +	if (df)
> +		all_devfreq.push_back(df);
> +}
> +
> +void create_all_devfreq_devices(void)
> +{
> +	DIR *dir;
> +	std::string p = "/sys/class/devfreq/";
> +	dir = opendir(p.c_str());
> +	if (dir == NULL) {
> +		fprintf(stderr, "Devfreq not enabled\n");
> +		is_enabled = false;
> +		return;
> +	}
> +
> +	callback fn = &devfreq_dev_callback;
> +	process_directory(p.c_str(), fn);
> +}
> +
> +void initialize_devfreq(void)
> +{
> +	if (is_enabled)
> +		create_tab("Device Freq stats", _("Device Freq stats"));
> +}
> +
> +void display_devfreq_devices(void)
> +{
> +	unsigned int i, j;
> +	WINDOW *win;
> +	char fline[1024];
> +	char buf[128];
> +
> +	win = get_ncurses_win("Device Freq stats");
> +        if (!win)
> +                return;
> +
> +        wclear(win);
> +        wmove(win, 2,0);
> +
> +	if (!is_enabled) {
> +		wprintw(win, _(" Devfreq is not enabled"));
> +		return;
> +	}
> +
> +	if (!all_devfreq.size()) {
> +		wprintw(win, _(" No devfreq devices available"));
> +		return;
> +	}
> +
> +	for (i=0; i<all_devfreq.size(); i++) {
> +
> +		class devfreq *df = all_devfreq[i];
> +		wprintw(win, "\n%s\n", df->device_name());
> +
> +		for(j=0; j < df->dstates.size(); j++) {
> +			memset(fline, 0, sizeof(fline));
> +			strcpy(fline, "\t");
> +			df->fill_freq_name(j, buf);
> +			strcat(fline, buf);
> +			df->fill_freq_utilization(j, buf);
> +			strcat(fline, buf);
> +			strcat(fline, "\n");
> +			wprintw(win, fline);
> +		}
> +		wprintw(win, "\n");
> +	}
> +}
> +
> +void report_devfreq_devices(void)
> +{
> +	if (!is_enabled) {
> +		return;
> +	}
> +
> +/* todo: adapt to new report format */
> +#if 0
> +	char buffer[512];
> +	unsigned int i, j;
> +
> +	report.begin_section(SECTION_DEVFREQ);
> +	report.add_header("Device Frequency Report");
> +
> +	report.begin_table(TABLE_WIDE);
> +	if (!all_devfreq.size()) {
> +		report.begin_row();
> +		report.add(" No devfreq devices available");
> +		return;
> +	}
> +
> +	for (i = 0; i < all_devfreq.size(); i++) {
> +		buffer[0] = 0;
> +		class devfreq *df = all_devfreq[i];
> +
> +		report.begin_row();
> +		report.begin_cell(CELL_CPU_PSTATE_HEADER);
> +		report.addf("%s", df->device_name());
> +
> +		for (j = 0; j < df->dstates.size(); j++) {
> +			report.begin_row();
> +			report.begin_cell(CELL_CPU_STATE_VALUE);
> +			df->fill_freq_name(j, buffer);
> +			report.add(buffer);
> +			report.begin_cell(CELL_CPU_STATE_VALUE);
> +			df->fill_freq_utilization(j, buffer);
> +			report.add(buffer);
> +		}
> +	}
> +#endif
> +
> +}
> +
> +void clear_all_devfreq()
> +{
> +	unsigned int i, j;
> +
> +	for (i=0; i < all_devfreq.size(); i++) {
> +		class devfreq *df = all_devfreq[i];
> +
> +		for(j=0; j < df->dstates.size(); j++)
> +			delete df->dstates[j];
> +
> +		df->dstates.resize(0);
> +		delete df;
> +	}
> +	all_devfreq.clear();
> +}
> diff --git a/src/devices/devfreq.h b/src/devices/devfreq.h
> new file mode 100644
> index 0000000..8ab5705
> --- /dev/null
> +++ b/src/devices/devfreq.h
> @@ -0,0 +1,75 @@
> +/*
> + * Copyright 2012, Linaro
> + *
> + * This file is part of PowerTOP
> + *
> + * This program file is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> + * for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program in a file named COPYING; if not, write to the
> + * Free Software Foundation, Inc,
> + * 51 Franklin Street, Fifth Floor,
> + * Boston, MA 02110-1301 USA
> + * or just google for it.
> + *
> + * Authors:
> + *	Rajagopal Venkat <rajagopal.venkat(a)linaro.org>
> + */
> +#ifndef _INCLUDE_GUARD_DEVFREQ_H
> +#define _INCLUDE_GUARD_DEVFREQ_H
> +
> +#include "device.h"
> +#include "../parameters/parameters.h"
> +
> +struct frequency;
> +
> +class devfreq: public device {
> +	char dir_name[4096];
> +	struct timeval  stamp_before, stamp_after;
> +	double sample_time;
> +
> +	uint64_t parse_freq_time(char *ptr);
> +	void add_devfreq_freq_state(uint64_t freq, uint64_t time);
> +	void update_devfreq_freq_state(uint64_t freq, uint64_t time);
> +	void parse_devfreq_trans_stat(char *dname);
> +	void process_time_stamps();
> +
> +public:
> +
> +	vector<struct frequency *> dstates;
> +
> +	devfreq(const char *c);
> +	void fill_freq_utilization(unsigned int idx, char *buf);
> +	void fill_freq_name(unsigned int idx, char *buf);
> +
> +	virtual void start_measurement(void);
> +	virtual void end_measurement(void);
> +
> +	virtual double	utilization(void); /* percentage */
> +
> +	virtual const char * class_name(void) { return "devfreq";};
> +
> +	virtual const char * device_name(void) { return dir_name;};
> +	virtual const char * human_name(void) { return "devfreq";};
> +	virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
> +	virtual const char * util_units(void) { return " rpm"; };
> +	virtual int power_valid(void) { return 0; /*utilization_power_valid(r_index);*/};
> +	virtual int grouping_prio(void) { return 1; };
> +};
> +
> +extern void create_all_devfreq_devices(void);
> +extern void clear_all_devfreq(void);
> +extern void display_devfreq_devices(void);
> +extern void report_devfreq_devices(void);
> +extern void initialize_devfreq(void);
> +extern void start_devfreq_measurement(void);
> +extern void end_devfreq_measurement(void);
> +
> +#endif
> diff --git a/src/main.cpp b/src/main.cpp
> index cf4e547..d33eaed 100644
> --- a/src/main.cpp
> +++ b/src/main.cpp
> @@ -48,6 +48,7 @@
>   
>   
>   #include "devices/device.h"
> +#include "devices/devfreq.h"
>   #include "devices/usb.h"
>   #include "devices/ahci.h"
>   #include "measurement/measurement.h"
> @@ -194,6 +195,7 @@ void one_measurement(int seconds, char *workload)
>   	create_all_usb_devices();
>   	start_power_measurement();
>   	devices_start_measurement();
> +	start_devfreq_measurement();
>   	start_process_measurement();
>   	start_cpu_measurement();
>   
> @@ -206,6 +208,7 @@ void one_measurement(int seconds, char *workload)
>   	end_cpu_measurement();
>   	end_process_measurement();
>   	collect_open_devices();
> +	end_devfreq_measurement();
>   	devices_end_measurement();
>   	end_power_measurement();
>   
> @@ -233,6 +236,9 @@ void one_measurement(int seconds, char *workload)
>   	report_show_open_devices();
>   
>   	report_devices();
> +	display_devfreq_devices();
> +	report_devfreq_devices();
> +
>   	ahci_create_device_stats_table();
>   	store_results(measurement_time);
>   	end_cpu_data();
> @@ -344,6 +350,7 @@ static void powertop_init(void)
>   
>   	enumerate_cpus();
>   	create_all_devices();
> +	create_all_devfreq_devices();
>   	detect_power_meters();
>   
>   	register_parameter("base power", 100, 0.5);
> @@ -457,6 +464,7 @@ int main(int argc, char **argv)
>   		exit(0);
>   	}
>   	init_display();
> +	initialize_devfreq();
>   	initialize_tuning();
>   	/* first one is short to not let the user wait too long */
>   	one_measurement(1, NULL);
> @@ -491,6 +499,7 @@ int main(int argc, char **argv)
>   
>   	clean_open_devices();
>   	clear_all_devices();
> +	clear_all_devfreq();
>   	clear_all_cpus();
>   
>   	return 0;
> diff --git a/src/report/report-maker.h b/src/report/report-maker.h
> index 423568a..bda4cef 100644
> --- a/src/report/report-maker.h
> +++ b/src/report/report-maker.h
> @@ -89,6 +89,7 @@ enum section_type {
>   	SECTION_SYSINFO,
>   	SECTION_CPUIDLE,
>   	SECTION_CPUFREQ,
> +	SECTION_DEVFREQ,
>   	SECTION_DEVPOWER,
>   	SECTION_SOFTWARE,
>   	SECTION_SUMMARY,

-- 
sanjay


[-- Attachment #2: attachment.html --]
[-- Type: text/html, Size: 14880 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Powertop] [PATCH] devfreq: add devfreq devices stats support
@ 2014-08-25  6:55 Sanjay Singh Rawat
  0 siblings, 0 replies; 13+ messages in thread
From: Sanjay Singh Rawat @ 2014-08-25  6:55 UTC (permalink / raw)
  To: powertop

[-- Attachment #1: Type: text/plain, Size: 216 bytes --]

Sorry, Rajagopal's id is not valid. Will resend the patch with correct id.

thanks,

On Monday 25 August 2014 11:54 AM, Sanjay Singh Rawat wrote:
> add window to show frequency stats for devfreq devices
[...]

[-- Attachment #2: attachment.html --]
[-- Type: text/html, Size: 647 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Powertop] [PATCH] devfreq: add devfreq devices stats support
@ 2014-08-25  6:24 Sanjay Singh Rawat
  0 siblings, 0 replies; 13+ messages in thread
From: Sanjay Singh Rawat @ 2014-08-25  6:24 UTC (permalink / raw)
  To: powertop

[-- Attachment #1: Type: text/plain, Size: 14236 bytes --]

add window to show frequency stats for devfreq devices

Signed-off-by: Rajagopal Venkat <rajagopal.venkat(a)linaro.org>
Signed-off-by: Sanjay Singh Rawat <sanjay.rawat(a)linaro.org>
---
 src/Makefile.am           |   2 +-
 src/devices/devfreq.cpp   | 351 ++++++++++++++++++++++++++++++++++++++++++++++
 src/devices/devfreq.h     |  75 ++++++++++
 src/main.cpp              |   9 ++
 src/report/report-maker.h |   1 +
 5 files changed, 437 insertions(+), 1 deletion(-)
 create mode 100644 src/devices/devfreq.cpp
 create mode 100644 src/devices/devfreq.h

diff --git a/src/Makefile.am b/src/Makefile.am
index 6886388..fee1ffa 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -32,7 +32,7 @@ powertop_SOURCES = parameters/persistent.cpp parameters/learn.cpp parameters/par
 		report/report-formatter-csv.cpp report/report-formatter-csv.h \
 		report/report-formatter-html.cpp report/report-formatter-html.h \
 		report/report-data-html.cpp report/report-data-html.h \
-		main.cpp css.h powertop.css cpu/intel_gpu.cpp \
+		main.cpp css.h powertop.css cpu/intel_gpu.cpp devices/devfreq.cpp \
 		cpu/rapl/rapl_interface.cpp cpu/cpu_rapl_device.cpp cpu/rapl/rapl_interface.h\
 		cpu/dram_rapl_device.cpp devices/gpu_rapl_device.cpp cpu/cpu_rapl_device.h \
 		cpu/dram_rapl_device.h devices/gpu_rapl_device.h
diff --git a/src/devices/devfreq.cpp b/src/devices/devfreq.cpp
new file mode 100644
index 0000000..29d7790
--- /dev/null
+++ b/src/devices/devfreq.cpp
@@ -0,0 +1,351 @@
+/*
+ * Copyright 2012, Linaro
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *	Rajagopal Venkat <rajagopal.venkat(a)linaro.org>
+ */
+
+#include <iostream>
+#include <fstream>
+
+#include <dirent.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "device.h"
+#include "devfreq.h"
+#include "../display.h"
+#include "../cpu/cpu.h"
+#include "../report/report.h"
+#include "../report/report-maker.h"
+
+static bool is_enabled = true;
+
+static vector<class devfreq *> all_devfreq;
+
+devfreq::devfreq(const char* dpath): device()
+{
+	strncpy(dir_name, dpath, sizeof(dir_name));
+}
+
+uint64_t devfreq::parse_freq_time(char* pchr)
+{
+	char *cptr, *pptr = pchr;
+	uint64_t ctime;
+
+	cptr = strtok(pchr, " :");
+	while (cptr != NULL) {
+		cptr = strtok(NULL, " :");
+		if (cptr )
+			pptr = cptr;
+	}
+
+	ctime = strtoull(pptr, NULL, 10);
+	return ctime;
+}
+
+void devfreq::process_time_stamps()
+{
+	unsigned int i;
+	uint64_t active_time = 0;
+
+	sample_time = (1000000.0 * (stamp_after.tv_sec - stamp_before.tv_sec))
+			+ ((stamp_after.tv_usec - stamp_before.tv_usec) );
+
+	for (i=0; i < dstates.size()-1; i++) {
+		struct frequency *state = dstates[i];
+		state->time_after = 1000 * (state->time_after - state->time_before);
+		active_time += state->time_after;
+	}
+	/* Compute idle time for the device */
+	dstates[i]->time_after = sample_time - active_time;
+}
+
+void devfreq::add_devfreq_freq_state(uint64_t freq, uint64_t time)
+{
+	struct frequency *state;
+
+	state = new(std::nothrow) struct frequency;
+	if (!state)
+		return;
+
+	memset(state, 0, sizeof(*state));
+	dstates.push_back(state);
+
+	state->freq = freq;
+	if (freq == 0)
+		strcpy(state->human_name, "Idle");
+	else
+		hz_to_human(freq, state->human_name);
+	state->time_before = time;
+}
+
+void devfreq::update_devfreq_freq_state(uint64_t freq, uint64_t time)
+{
+	unsigned int i;
+	struct frequency *state = NULL;
+
+	for(i=0; i < dstates.size(); i++) {
+		if (freq == dstates[i]->freq)
+			state = dstates[i];
+	}
+
+	if (state == NULL) {
+		add_devfreq_freq_state(freq, time);
+		return;
+	}
+
+	state->time_after = time;
+}
+
+void devfreq::parse_devfreq_trans_stat(char *dname)
+{
+	ifstream file;
+	char filename[256];
+
+	sprintf(filename, "/sys/class/devfreq/%s/trans_stat", dir_name);
+	file.open(filename);
+
+	if (!file)
+		return;
+
+	char line[1024];
+	char *c;
+
+	while (file) {
+		uint64_t freq;
+		uint64_t time;
+		char *pchr;
+
+		memset(line, 0, sizeof(line));
+		file.getline(line, sizeof(line));
+
+		pchr = strchr(line, '*');
+		pchr = (pchr != NULL) ? pchr+1 : line;
+
+		freq = strtoull(pchr, &c, 10);
+		if (!freq)
+			continue;
+
+		time = parse_freq_time(pchr);
+		update_devfreq_freq_state(freq, time);
+	}
+	file.close();
+}
+
+void devfreq::start_measurement(void)
+{
+	unsigned int i;
+	ifstream file;
+
+	for (i=0; i < dstates.size(); i++)
+		delete dstates[i];
+	dstates.resize(0);
+	sample_time = 0;
+
+	gettimeofday(&stamp_before, NULL);
+	parse_devfreq_trans_stat(dir_name);
+	/* add device idle state */
+	update_devfreq_freq_state(0, 0);
+}
+
+void devfreq::end_measurement(void)
+{
+	parse_devfreq_trans_stat(dir_name);
+	gettimeofday(&stamp_after, NULL);
+	process_time_stamps();
+}
+
+double devfreq::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+	return 0;
+}
+
+double devfreq::utilization(void)
+{
+	return 0;
+}
+
+void devfreq::fill_freq_utilization(unsigned int idx, char *buf)
+{
+	buf[0] = 0;
+
+	if (idx < dstates.size() && dstates[idx]) {
+		struct frequency *state = dstates[idx];
+		sprintf(buf, " %5.1f%% ", percentage(1.0 * state->time_after / sample_time));
+	}
+}
+
+void devfreq::fill_freq_name(unsigned int idx, char *buf)
+{
+	buf[0] = 0;
+
+	if (idx < dstates.size() && dstates[idx]) {
+		sprintf(buf, "%-15s", dstates[idx]->human_name);
+	}
+}
+
+void start_devfreq_measurement(void)
+{
+	unsigned int i;
+
+	for (i=0; i<all_devfreq.size(); i++)
+		all_devfreq[i]->start_measurement();
+}
+
+void end_devfreq_measurement(void)
+{
+	unsigned int i;
+
+	for (i=0; i<all_devfreq.size(); i++)
+		all_devfreq[i]->end_measurement();
+}
+
+static void devfreq_dev_callback(const char *d_name)
+{
+	devfreq *df = new(std::nothrow) class devfreq(d_name);
+	if (df)
+		all_devfreq.push_back(df);
+}
+
+void create_all_devfreq_devices(void)
+{
+	DIR *dir;
+	std::string p = "/sys/class/devfreq/";
+	dir = opendir(p.c_str());
+	if (dir == NULL) {
+		fprintf(stderr, "Devfreq not enabled\n");
+		is_enabled = false;
+		return;
+	}
+
+	callback fn = &devfreq_dev_callback;
+	process_directory(p.c_str(), fn);
+}
+
+void initialize_devfreq(void)
+{
+	if (is_enabled)
+		create_tab("Device Freq stats", _("Device Freq stats"));
+}
+
+void display_devfreq_devices(void)
+{
+	unsigned int i, j;
+	WINDOW *win;
+	char fline[1024];
+	char buf[128];
+
+	win = get_ncurses_win("Device Freq stats");
+        if (!win)
+                return;
+
+        wclear(win);
+        wmove(win, 2,0);
+
+	if (!is_enabled) {
+		wprintw(win, _(" Devfreq is not enabled"));
+		return;
+	}
+
+	if (!all_devfreq.size()) {
+		wprintw(win, _(" No devfreq devices available"));
+		return;
+	}
+
+	for (i=0; i<all_devfreq.size(); i++) {
+
+		class devfreq *df = all_devfreq[i];
+		wprintw(win, "\n%s\n", df->device_name());
+
+		for(j=0; j < df->dstates.size(); j++) {
+			memset(fline, 0, sizeof(fline));
+			strcpy(fline, "\t");
+			df->fill_freq_name(j, buf);
+			strcat(fline, buf);
+			df->fill_freq_utilization(j, buf);
+			strcat(fline, buf);
+			strcat(fline, "\n");
+			wprintw(win, fline);
+		}
+		wprintw(win, "\n");
+	}
+}
+
+void report_devfreq_devices(void)
+{
+	if (!is_enabled) {
+		return;
+	}
+
+/* todo: adapt to new report format */
+#if 0
+	char buffer[512];
+	unsigned int i, j;
+
+	report.begin_section(SECTION_DEVFREQ);
+	report.add_header("Device Frequency Report");
+
+	report.begin_table(TABLE_WIDE);
+	if (!all_devfreq.size()) {
+		report.begin_row();
+		report.add(" No devfreq devices available");
+		return;
+	}
+
+	for (i = 0; i < all_devfreq.size(); i++) {
+		buffer[0] = 0;
+		class devfreq *df = all_devfreq[i];
+
+		report.begin_row();
+		report.begin_cell(CELL_CPU_PSTATE_HEADER);
+		report.addf("%s", df->device_name());
+
+		for (j = 0; j < df->dstates.size(); j++) {
+			report.begin_row();
+			report.begin_cell(CELL_CPU_STATE_VALUE);
+			df->fill_freq_name(j, buffer);
+			report.add(buffer);
+			report.begin_cell(CELL_CPU_STATE_VALUE);
+			df->fill_freq_utilization(j, buffer);
+			report.add(buffer);
+		}
+	}
+#endif
+
+}
+
+void clear_all_devfreq()
+{
+	unsigned int i, j;
+
+	for (i=0; i < all_devfreq.size(); i++) {
+		class devfreq *df = all_devfreq[i];
+
+		for(j=0; j < df->dstates.size(); j++)
+			delete df->dstates[j];
+
+		df->dstates.resize(0);
+		delete df;
+	}
+	all_devfreq.clear();
+}
diff --git a/src/devices/devfreq.h b/src/devices/devfreq.h
new file mode 100644
index 0000000..8ab5705
--- /dev/null
+++ b/src/devices/devfreq.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2012, Linaro
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ *	Rajagopal Venkat <rajagopal.venkat(a)linaro.org>
+ */
+#ifndef _INCLUDE_GUARD_DEVFREQ_H
+#define _INCLUDE_GUARD_DEVFREQ_H
+
+#include "device.h"
+#include "../parameters/parameters.h"
+
+struct frequency;
+
+class devfreq: public device {
+	char dir_name[4096];
+	struct timeval  stamp_before, stamp_after;
+	double sample_time;
+
+	uint64_t parse_freq_time(char *ptr);
+	void add_devfreq_freq_state(uint64_t freq, uint64_t time);
+	void update_devfreq_freq_state(uint64_t freq, uint64_t time);
+	void parse_devfreq_trans_stat(char *dname);
+	void process_time_stamps();
+
+public:
+
+	vector<struct frequency *> dstates;
+
+	devfreq(const char *c);
+	void fill_freq_utilization(unsigned int idx, char *buf);
+	void fill_freq_name(unsigned int idx, char *buf);
+
+	virtual void start_measurement(void);
+	virtual void end_measurement(void);
+
+	virtual double	utilization(void); /* percentage */
+
+	virtual const char * class_name(void) { return "devfreq";};
+
+	virtual const char * device_name(void) { return dir_name;};
+	virtual const char * human_name(void) { return "devfreq";};
+	virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+	virtual const char * util_units(void) { return " rpm"; };
+	virtual int power_valid(void) { return 0; /*utilization_power_valid(r_index);*/};
+	virtual int grouping_prio(void) { return 1; };
+};
+
+extern void create_all_devfreq_devices(void);
+extern void clear_all_devfreq(void);
+extern void display_devfreq_devices(void);
+extern void report_devfreq_devices(void);
+extern void initialize_devfreq(void);
+extern void start_devfreq_measurement(void);
+extern void end_devfreq_measurement(void);
+
+#endif
diff --git a/src/main.cpp b/src/main.cpp
index cf4e547..d33eaed 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -48,6 +48,7 @@
 
 
 #include "devices/device.h"
+#include "devices/devfreq.h"
 #include "devices/usb.h"
 #include "devices/ahci.h"
 #include "measurement/measurement.h"
@@ -194,6 +195,7 @@ void one_measurement(int seconds, char *workload)
 	create_all_usb_devices();
 	start_power_measurement();
 	devices_start_measurement();
+	start_devfreq_measurement();
 	start_process_measurement();
 	start_cpu_measurement();
 
@@ -206,6 +208,7 @@ void one_measurement(int seconds, char *workload)
 	end_cpu_measurement();
 	end_process_measurement();
 	collect_open_devices();
+	end_devfreq_measurement();
 	devices_end_measurement();
 	end_power_measurement();
 
@@ -233,6 +236,9 @@ void one_measurement(int seconds, char *workload)
 	report_show_open_devices();
 
 	report_devices();
+	display_devfreq_devices();
+	report_devfreq_devices();
+
 	ahci_create_device_stats_table();
 	store_results(measurement_time);
 	end_cpu_data();
@@ -344,6 +350,7 @@ static void powertop_init(void)
 
 	enumerate_cpus();
 	create_all_devices();
+	create_all_devfreq_devices();
 	detect_power_meters();
 
 	register_parameter("base power", 100, 0.5);
@@ -457,6 +464,7 @@ int main(int argc, char **argv)
 		exit(0);
 	}
 	init_display();
+	initialize_devfreq();
 	initialize_tuning();
 	/* first one is short to not let the user wait too long */
 	one_measurement(1, NULL);
@@ -491,6 +499,7 @@ int main(int argc, char **argv)
 
 	clean_open_devices();
 	clear_all_devices();
+	clear_all_devfreq();
 	clear_all_cpus();
 
 	return 0;
diff --git a/src/report/report-maker.h b/src/report/report-maker.h
index 423568a..bda4cef 100644
--- a/src/report/report-maker.h
+++ b/src/report/report-maker.h
@@ -89,6 +89,7 @@ enum section_type {
 	SECTION_SYSINFO,
 	SECTION_CPUIDLE,
 	SECTION_CPUFREQ,
+	SECTION_DEVFREQ,
 	SECTION_DEVPOWER,
 	SECTION_SOFTWARE,
 	SECTION_SUMMARY,
-- 
1.8.3.2


^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2014-10-10  9:43 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-25  6:58 [Powertop] [PATCH] devfreq: add devfreq devices stats support Sanjay Singh Rawat
  -- strict thread matches above, loose matches on Subject: below --
2014-10-10  9:43 Sanjay Singh Rawat
2014-10-10  9:42 Sanjay Singh Rawat
2014-10-01 20:22 Magnus Fromreide
2014-10-01 15:12 Sergey Senozhatsky
2014-10-01 14:52 Sergey Senozhatsky
2014-09-30  6:34 Sanjay Singh Rawat
2014-09-30  4:21 Sanjay Singh Rawat
2014-09-29 23:04 Alexandra Yates
2014-09-29 22:46 Alexandra Yates
2014-09-17  4:16 Sanjay Singh Rawat
2014-08-25  6:55 Sanjay Singh Rawat
2014-08-25  6:24 Sanjay Singh Rawat

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.