add window to show frequency stats for devfreq devices
Signed-off-by: Rajagopal Venkat rajagopal.venkat@gmail.com Signed-off-by: Sanjay Singh Rawat sanjay.rawat@linaro.org ---
v4 - remove resizing before freeing the vector
v3 - remove unused variables, reduce array size to suitable value - replace the inactive code block in the report function with TODO comment
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 | 332 ++++++++++++++++++++++++++++++++++++++++++++++ src/devices/devfreq.h | 75 +++++++++++ src/main.cpp | 9 ++ src/report/report-maker.h | 1 + 5 files changed, 418 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..d2e56e3 --- /dev/null +++ b/src/devices/devfreq.cpp @@ -0,0 +1,332 @@ +/* + * 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@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; + + 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 */ + +} + +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]; + + 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..16a60fb --- /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@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[128]; + 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,
add window to show frequency stats for devfreq devices
Signed-off-by: Rajagopal Venkat rajagopal.venkat@gmail.com Signed-off-by: Sanjay Singh Rawat sanjay.rawat@linaro.org
v4 - remove resizing before freeing the vector
v3 - remove unused variables, reduce array size to suitable value
- replace the inactive code block in the report function with TODO comment
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 | 332 ++++++++++++++++++++++++++++++++++++++++++++++ src/devices/devfreq.h | 75 +++++++++++ src/main.cpp | 9 ++ src/report/report-maker.h | 1 + 5 files changed, 418 insertions(+) create mode 100644 src/devices/devfreq.cpp create mode 100644 src/devices/devfreq.h
I think I don't have any serious/outstanding objections.
-ss
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..d2e56e3 --- /dev/null +++ b/src/devices/devfreq.cpp @@ -0,0 +1,332 @@ +/*
- 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@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;
- 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 */
+}
+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];
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..16a60fb --- /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@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[128];
- 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
add window to show frequency stats for devfreq devices
Signed-off-by: Rajagopal Venkat rajagopal.venkat@gmail.com Signed-off-by: Sanjay Singh Rawat sanjay.rawat@linaro.org
v4 - remove resizing before freeing the vector
v3 - remove unused variables, reduce array size to suitable value
- replace the inactive code block in the report function with TODO comment
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 | 332 ++++++++++++++++++++++++++++++++++++++++++++++ src/devices/devfreq.h | 75 +++++++++++ src/main.cpp | 9 ++ src/report/report-maker.h | 1 + 5 files changed, 418 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..d2e56e3 --- /dev/null +++ b/src/devices/devfreq.cpp @@ -0,0 +1,332 @@ +/*
- 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@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;
- 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 */
+}
+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];
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..16a60fb --- /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@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[128];
- 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
Your patch was added today.
Thank you, Alexandra.