Add support for devfreq device freq stats

Add new window to display devfreq device frequency statistics.

Signed-off-by: Rajagopal Venkat <rajagopal.venkat@linaro.org>
diff --git a/Android.mk b/Android.mk
index 11c69dc..9489407 100644
--- a/Android.mk
+++ b/Android.mk
@@ -90,6 +90,7 @@
 	src/devices/backlight.cpp \
 	src/devices/network.cpp \
 	src/devices/device.cpp \
+	src/devices/devfreq.cpp \
 	src/devlist.cpp \
 	src/calibrate/calibrate.cpp \
 	src/lib.cpp \
diff --git a/src/Makefile.am b/src/Makefile.am
index f60426a..96cdfc6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -34,7 +34,7 @@
 		report/report-formatter-base.cpp report/report-formatter-base.h \
 		report/report-formatter-csv.cpp report/report-formatter-csv.h \
 		report/report-formatter-html.cpp report/report-formatter-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
 
 
 powertop_CXXFLAGS = -fno-omit-frame-pointer -fstack-protector -Wall -Wshadow -Wformat $(NCURSES_CFLAGS) $(PCIUTILS_CFLAGS) $(LIBNL_CFLAGS) $(GLIB2_CFLAGS)
diff --git a/src/devices/devfreq.cpp b/src/devices/devfreq.cpp
new file mode 100644
index 0000000..e16951c
--- /dev/null
+++ b/src/devices/devfreq.cpp
@@ -0,0 +1,346 @@
+/*
+ * 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 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) {
+		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) {
+		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)
+{
+
+	char buffer[512];
+	unsigned int i, j;
+
+	if (!is_enabled) {
+		return;
+	}
+
+	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);
+		}
+	}
+}
+
+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@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/devices/device.cpp b/src/devices/device.cpp
index 00ec5e6..6ff3a22 100644
--- a/src/devices/device.cpp
+++ b/src/devices/device.cpp
@@ -289,6 +289,7 @@
 		report.begin_cell();
 		report.add(all_devices[i]->human_name());
 	}
+
 }
 
 
diff --git a/src/display.h b/src/display.h
index b450f8b..b84717d 100644
--- a/src/display.h
+++ b/src/display.h
@@ -74,6 +74,12 @@
 		delwin(win);
 		win = NULL;
 	}
+
+	tab_window(void)
+	{
+		xpad_pos = 0;
+		ypad_pos = 0;
+	}
 };
 
 extern map<string, class tab_window *> tab_windows;
diff --git a/src/main.cpp b/src/main.cpp
index 2395e83..6e79714 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 "measurement/measurement.h"
 #include "parameters/parameters.h"
@@ -55,6 +56,7 @@
 
 
 #include "tuning/tuning.h"
+#include "devices/devfreq.h"
 
 #include "display.h"
 #include "devlist.h"
@@ -189,6 +191,7 @@
 	create_all_usb_devices();
 	start_power_measurement();
 	devices_start_measurement();
+	start_devfreq_measurement();
 	start_process_measurement();
 	start_cpu_measurement();
 
@@ -201,6 +204,7 @@
 	end_cpu_measurement();
 	end_process_measurement();
 	collect_open_devices();
+	end_devfreq_measurement();
 	devices_end_measurement();
 	end_power_measurement();
 
@@ -227,6 +231,8 @@
 	report_show_open_devices();
 
 	report_devices();
+	display_devfreq_devices();
+	report_devfreq_devices();
 
 	store_results(measurement_time);
 	end_cpu_data();
@@ -319,6 +325,7 @@
 
 	enumerate_cpus();
 	create_all_devices();
+	create_all_devfreq_devices();
 	detect_power_meters();
 
 	register_parameter("base power", 100, 0.5);
@@ -438,6 +445,7 @@
 
 	/* first one is short to not let the user wait too long */
 	init_display();
+	initialize_devfreq();
 	one_measurement(1, NULL);
 	initialize_tuning();
 	tuning_update_display();
@@ -465,6 +473,7 @@
 	reset_display();
 
 	clear_all_devices();
+	clear_all_devfreq();
 	clear_all_cpus();
 
 	return 0;
diff --git a/src/powertop.css b/src/powertop.css
index c73d3e2..c09bb43 100644
--- a/src/powertop.css
+++ b/src/powertop.css
@@ -18,6 +18,8 @@
 	$('#device h2').addClass('hide');
 	$('#device table').addClass('hide');
 	$('#device p').addClass('hide');
+	$('#devfreq h2').addClass('hide');
+	$('#devfreq table').addClass('hide');
 	$('#tuning h2').addClass('hide');
 	$('#tuning table').addClass('hide');
 
@@ -27,6 +29,7 @@
 	$('#top').append('<div class=\"CpufreqButton\"  onclick=\"toggleCpufreq()\">CPU Frequency</div>');
 	$('#top').append('<div class=\"SoftwareButton\" onclick=\"toggleSoftware()\">Software info</div>');
 	$('#top').append('<div class=\"DeviceButton\"   onclick=\"toggleDevice()\">Device Info</div>');
+	$('#top').append('<div class=\"DevfreqButton\"  onclick=\"toggleDevfreq()\">Device Freq</div>');
 	$('#top').append('<div class=\"TuningButton\"   onclick=\"toggleTuning()\">Tuning</div>');
 	$('#top').append('<div class=\"AllButton\"      onclick=\"toggleAll()\">All</div>');
 	$('#top .SummaryButton').toggleClass('pressed');
@@ -48,6 +51,8 @@
 		$('#device table').toggleClass('hide', true);
 		$('#device h2').toggleClass('hide', true);
 		$('#device p').toggleClass('hide', true);
+		$('#devfreq table').toggleClass('hide', true);
+		$('#devfreq h2').toggleClass('hide', true);
 		$('#tuning table').toggleClass('hide', true);
 		$('#tuning h2').toggleClass('hide', true);
 		$('#top .SystemButton').toggleClass('pressed', false);
@@ -56,6 +61,7 @@
 		$('#top .CpufreqButton').toggleClass('pressed', false);
 		$('#top .SoftwareButton').toggleClass('pressed', false);
 		$('#top .DeviceButton').toggleClass('pressed', false);
+		$('#top .DevfreqButton').toggleClass('pressed', false);
 		$('#top .TuningButton').toggleClass('pressed', false);
 		$('#top .AllButton').toggleClass('pressed', false);
 }
@@ -74,6 +80,8 @@
 		$('#device table').toggleClass('hide', true);
 		$('#device h2').toggleClass('hide', true);
 		$('#device p').toggleClass('hide', true);
+		$('#devfreq table').toggleClass('hide', true);
+		$('#devfreq h2').toggleClass('hide', true);
 		$('#tuning table').toggleClass('hide', true);
 		$('#tuning h2').toggleClass('hide', true);
 		$('#top .SystemButton').toggleClass('pressed', true);
@@ -82,6 +90,7 @@
 		$('#top .CpufreqButton').toggleClass('pressed', false);
 		$('#top .SoftwareButton').toggleClass('pressed', false);
 		$('#top .DeviceButton').toggleClass('pressed', false);
+		$('#top .DevfreqButton').toggleClass('pressed', false);
 		$('#top .TuningButton').toggleClass('pressed', false);
 		$('#top .AllButton').toggleClass('pressed', false);
 }
@@ -100,6 +109,8 @@
 		$('#device table').toggleClass('hide', true);
 		$('#device h2').toggleClass('hide', true);
 		$('#device p').toggleClass('hide', true);
+		$('#devfreq table').toggleClass('hide', true);
+		$('#devfreq h2').toggleClass('hide', true);
 		$('#tuning table').toggleClass('hide', true);
 		$('#tuning h2').toggleClass('hide', true);
 		$('#top .SystemButton').toggleClass('pressed', false);
@@ -108,6 +119,7 @@
 		$('#top .CpufreqButton').toggleClass('pressed', false);
 		$('#top .SoftwareButton').toggleClass('pressed', false);
 		$('#top .DeviceButton').toggleClass('pressed', false);
+		$('#top .DevfreqButton').toggleClass('pressed', false);
 		$('#top .TuningButton').toggleClass('pressed', false);
 		$('#top .AllButton').toggleClass('pressed', false);
 }
@@ -126,6 +138,8 @@
 		$('#device table').toggleClass('hide', true);
 		$('#device h2').toggleClass('hide', true);
 		$('#device p').toggleClass('hide', true);
+		$('#devfreq table').toggleClass('hide', true);
+		$('#devfreq h2').toggleClass('hide', true);
 		$('#tuning table').toggleClass('hide', true);
 		$('#tuning h2').toggleClass('hide', true);
 		$('#top .SystemButton').toggleClass('pressed', false);
@@ -134,6 +148,7 @@
 		$('#top .CpufreqButton').toggleClass('pressed', false);
 		$('#top .SoftwareButton').toggleClass('pressed', false);
 		$('#top .DeviceButton').toggleClass('pressed', false);
+		$('#top .DevfreqButton').toggleClass('pressed', false);
 		$('#top .TuningButton').toggleClass('pressed', false);
 		$('#top .AllButton').toggleClass('pressed', false);
 
@@ -153,6 +168,8 @@
 		$('#device table').toggleClass('hide', true);
 		$('#device h2').toggleClass('hide', true);
 		$('#device p').toggleClass('hide', true);
+		$('#devfreq table').toggleClass('hide', true);
+		$('#devfreq h2').toggleClass('hide', true);
 		$('#tuning table').toggleClass('hide', true);
 		$('#tuning h2').toggleClass('hide', true);
 		$('#top .SystemButton').toggleClass('pressed', false);
@@ -161,6 +178,7 @@
 		$('#top .CpufreqButton').toggleClass('pressed', true);
 		$('#top .SoftwareButton').toggleClass('pressed', false);
 		$('#top .DeviceButton').toggleClass('pressed', false);
+		$('#top .DevfreqButton').toggleClass('pressed', false);
 		$('#top .TuningButton').toggleClass('pressed', false);
 		$('#top .AllButton').toggleClass('pressed', false);
 }
@@ -180,6 +198,8 @@
 		$('#device table').toggleClass('hide', true);
 		$('#device h2').toggleClass('hide', true);
 		$('#device p').toggleClass('hide', true);
+		$('#devfreq table').toggleClass('hide', true);
+		$('#devfreq h2').toggleClass('hide', true);
 		$('#tuning table').toggleClass('hide', true);
 		$('#tuning h2').toggleClass('hide', true);
 		$('#top .SystemButton').toggleClass('pressed', false);
@@ -188,6 +208,7 @@
 		$('#top .CpufreqButton').toggleClass('pressed', false);
 		$('#top .SoftwareButton').toggleClass('pressed', true);
 		$('#top .DeviceButton').toggleClass('pressed', false);
+		$('#top .DevfreqButton').toggleClass('pressed', false);
 		$('#top .TuningButton').toggleClass('pressed', false);
 		$('#top .AllButton').toggleClass('pressed', false);
 }
@@ -207,6 +228,8 @@
 		$('#device table').toggleClass('hide', false);
 		$('#device h2').toggleClass('hide', false);
 		$('#device p').toggleClass('hide', false);
+		$('#devfreq table').toggleClass('hide', true);
+		$('#devfreq h2').toggleClass('hide', true);
 		$('#tuning table').toggleClass('hide', true);
 		$('#tuning h2').toggleClass('hide', true);
 		$('#top .SystemButton').toggleClass('pressed', false);
@@ -215,6 +238,37 @@
 		$('#top .CpufreqButton').toggleClass('pressed', false);
 		$('#top .SoftwareButton').toggleClass('pressed', false);
 		$('#top .DeviceButton').toggleClass('pressed', true);
+		$('#top .DevfreqButton').toggleClass('pressed', false);
+		$('#top .TuningButton').toggleClass('pressed', false);
+		$('#top .AllButton').toggleClass('pressed', false);
+}
+
+function toggleDevfreq() {
+		$('#system table').toggleClass('hide', true);
+		$('#system h2').toggleClass('hide', true);
+		$('#summary table').toggleClass('hide', true);
+		$('#summary h2').toggleClass('hide', true);
+		$('#summary p').toggleClass('hide', true);
+		$('#cpuidle table').toggleClass('hide', true);
+		$('#cpuidle h2').toggleClass('hide', true);
+		$('#cpufreq table').toggleClass('hide', true);
+		$('#cpufreq h2').toggleClass('hide', true);
+		$('#software table').toggleClass('hide', true);
+		$('#software h2').toggleClass('hide', true);
+		$('#device table').toggleClass('hide', true);
+		$('#device h2').toggleClass('hide', true);
+		$('#device p').toggleClass('hide', true);
+		$('#devfreq table').toggleClass('hide', false);
+		$('#devfreq h2').toggleClass('hide', false);
+		$('#tuning table').toggleClass('hide', true);
+		$('#tuning h2').toggleClass('hide', true);
+		$('#top .SystemButton').toggleClass('pressed', false);
+		$('#top .SummaryButton').toggleClass('pressed', false);
+		$('#top .CpuidleButton').toggleClass('pressed', false);
+		$('#top .CpufreqButton').toggleClass('pressed', false);
+		$('#top .SoftwareButton').toggleClass('pressed', false);
+		$('#top .DeviceButton').toggleClass('pressed', false);
+		$('#top .DevfreqButton').toggleClass('pressed', true);
 		$('#top .TuningButton').toggleClass('pressed', false);
 		$('#top .AllButton').toggleClass('pressed', false);
 }
@@ -234,6 +288,8 @@
 		$('#device table').toggleClass('hide', true);
 		$('#device h2').toggleClass('hide', true);
 		$('#device p').toggleClass('hide', true);
+		$('#devfreq table').toggleClass('hide', true);
+		$('#devfreq h2').toggleClass('hide', true);
 		$('#tuning table').toggleClass('hide', false);
 		$('#tuning h2').toggleClass('hide', false);
 		$('#top .SystemButton').toggleClass('pressed', false);
@@ -242,6 +298,7 @@
 		$('#top .CpufreqButton').toggleClass('pressed', false);
 		$('#top .SoftwareButton').toggleClass('pressed', false);
 		$('#top .DeviceButton').toggleClass('pressed', false);
+		$('#top .DevfreqButton').toggleClass('pressed', false);
 		$('#top .TuningButton').toggleClass('pressed', true);
 		$('#top .AllButton').toggleClass('pressed', false);
 }
@@ -260,6 +317,8 @@
 		$('#device table').toggleClass('hide', false);
 		$('#device h2').toggleClass('hide', false);
 		$('#device p').toggleClass('hide', false);
+		$('#devfreq table').toggleClass('hide', false);
+		$('#devfreq h2').toggleClass('hide', false);
 		$('#tuning table').toggleClass('hide', false);
 		$('#tuning h2').toggleClass('hide', false);
 		$('#top .SystemButton').toggleClass('pressed', false);
@@ -268,6 +327,7 @@
 		$('#top .CpufreqButton').toggleClass('pressed', false);
 		$('#top .SoftwareButton').toggleClass('pressed', false);
 		$('#top .DeviceButton').toggleClass('pressed', false);
+		$('#top .DevfreqButton').toggleClass('pressed', false);
 		$('#top .TuningButton').toggleClass('pressed', false);
 		$('#top .AllButton').toggleClass('pressed', true);
 }
@@ -491,32 +551,37 @@
 #top div.SummaryButton {
 	position: absolute;
 	top: 7px;
-	left: 160px;
+	left: 140px;
 }
 #top div.CpuidleButton {
 	position: absolute;
 	top: 7px;
-	left: 320px;
+	left: 280px;
 }
 #top div.CpufreqButton {
 	position: absolute;
 	top: 7px;
-	left: 480px;
+	left: 420px;
 }
 #top div.SoftwareButton {
 	position: absolute;
 	top: 7px;
-	left: 640px;
+	left: 560px;
 }
 #top div.DeviceButton {
 	position: absolute;
 	top: 7px;
-	left: 800px;
+	left: 700px;
+}
+#top div.DevfreqButton {
+	position: absolute;
+	top: 7px;
+	left: 840px;
 }
 #top div.TuningButton {
 	position: absolute;
 	top: 7px;
-	left: 960px;
+	left: 980px;
 }
 #top div.AllButton {
 	position: absolute;
diff --git a/src/report/report-formatter-html.cpp b/src/report/report-formatter-html.cpp
index 5851575..34a79f3 100644
--- a/src/report/report-formatter-html.cpp
+++ b/src/report/report-formatter-html.cpp
@@ -68,6 +68,7 @@
 	set_section(SECTION_DEVPOWER,	"device");
 	set_section(SECTION_SOFTWARE,	"software");
 	set_section(SECTION_SUMMARY,	"summary");
+	set_section(SECTION_DEVFREQ,	"devfreq");
 	set_section(SECTION_TUNING,	"tuning");
 
 	/*	  ttype		 width */
diff --git a/src/report/report-maker.h b/src/report/report-maker.h
index 75e0d06..1e2f3ac 100644
--- a/src/report/report-maker.h
+++ b/src/report/report-maker.h
@@ -97,6 +97,7 @@
 	SECTION_SYSINFO,
 	SECTION_CPUIDLE,
 	SECTION_CPUFREQ,
+	SECTION_DEVFREQ,
 	SECTION_DEVPOWER,
 	SECTION_SOFTWARE,
 	SECTION_SUMMARY,