summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am176
-rw-r--r--src/calibrate/calibrate.cpp435
-rw-r--r--src/calibrate/calibrate.h32
-rw-r--r--src/cpu/abstract_cpu.cpp535
-rw-r--r--src/cpu/cpu.cpp1075
-rw-r--r--src/cpu/cpu.h234
-rw-r--r--src/cpu/cpu_core.cpp100
-rw-r--r--src/cpu/cpu_linux.cpp350
-rw-r--r--src/cpu/cpu_package.cpp113
-rw-r--r--src/cpu/cpu_rapl_device.cpp74
-rw-r--r--src/cpu/cpu_rapl_device.h57
-rw-r--r--src/cpu/cpudevice.cpp86
-rw-r--r--src/cpu/cpudevice.h63
-rw-r--r--src/cpu/dram_rapl_device.cpp75
-rw-r--r--src/cpu/dram_rapl_device.h57
-rw-r--r--src/cpu/intel_cpus.cpp757
-rw-r--r--src/cpu/intel_cpus.h180
-rw-r--r--src/cpu/intel_gpu.cpp122
-rw-r--r--src/cpu/rapl/rapl_interface.cpp699
-rw-r--r--src/cpu/rapl/rapl_interface.h91
-rwxr-xr-xsrc/csstoh.sh50
-rw-r--r--src/devices/ahci.cpp428
-rw-r--r--src/devices/ahci.h72
-rw-r--r--src/devices/alsa.cpp207
-rw-r--r--src/devices/alsa.h67
-rw-r--r--src/devices/backlight.cpp225
-rw-r--r--src/devices/backlight.h59
-rw-r--r--src/devices/devfreq.cpp334
-rw-r--r--src/devices/devfreq.h76
-rw-r--r--src/devices/device.cpp345
-rw-r--r--src/devices/device.h85
-rw-r--r--src/devices/gpu_rapl_device.cpp70
-rw-r--r--src/devices/gpu_rapl_device.h57
-rw-r--r--src/devices/i915-gpu.cpp121
-rw-r--r--src/devices/i915-gpu.h58
-rw-r--r--src/devices/network.cpp441
-rw-r--r--src/devices/network.h85
-rw-r--r--src/devices/rfkill.cpp177
-rw-r--r--src/devices/rfkill.h62
-rw-r--r--src/devices/runtime_pm.cpp257
-rw-r--r--src/devices/runtime_pm.h66
-rw-r--r--src/devices/thinkpad-fan.cpp124
-rw-r--r--src/devices/thinkpad-fan.h58
-rw-r--r--src/devices/thinkpad-light.cpp113
-rw-r--r--src/devices/thinkpad-light.h58
-rw-r--r--src/devices/usb.cpp254
-rw-r--r--src/devices/usb.h67
-rw-r--r--src/devlist.cpp351
-rw-r--r--src/devlist.h27
-rw-r--r--src/display.cpp342
-rw-r--r--src/display.h99
-rw-r--r--src/lib.cpp597
-rw-r--r--src/lib.h95
-rw-r--r--src/main.cpp578
-rw-r--r--src/measurement/acpi.cpp213
-rw-r--r--src/measurement/acpi.h46
-rw-r--r--src/measurement/extech.cpp354
-rw-r--r--src/measurement/extech.h51
-rw-r--r--src/measurement/measurement.cpp188
-rw-r--r--src/measurement/measurement.h71
-rw-r--r--src/measurement/opal-sensors.cpp48
-rw-r--r--src/measurement/opal-sensors.h42
-rw-r--r--src/measurement/sysfs.cpp160
-rw-r--r--src/measurement/sysfs.h55
-rw-r--r--src/parameters/learn.cpp282
-rw-r--r--src/parameters/parameters.cpp462
-rw-r--r--src/parameters/parameters.h123
-rw-r--r--src/parameters/persistent.cpp202
-rw-r--r--src/perf/perf.cpp266
-rw-r--r--src/perf/perf.h76
-rw-r--r--src/perf/perf_bundle.cpp348
-rw-r--r--src/perf/perf_bundle.h59
-rw-r--r--src/perf/perf_event.h910
-rw-r--r--src/powertop.css263
-rw-r--r--src/process/do_process.cpp1230
-rw-r--r--src/process/interrupt.cpp131
-rw-r--r--src/process/interrupt.h62
-rw-r--r--src/process/powerconsumer.cpp100
-rw-r--r--src/process/powerconsumer.h79
-rw-r--r--src/process/process.cpp246
-rw-r--r--src/process/process.h96
-rw-r--r--src/process/processdevice.cpp99
-rw-r--r--src/process/processdevice.h55
-rw-r--r--src/process/timer.cpp159
-rw-r--r--src/process/timer.h64
-rw-r--r--src/process/work.cpp130
-rw-r--r--src/process/work.h57
-rw-r--r--src/report/report-data-html.cpp128
-rw-r--r--src/report/report-data-html.h76
-rw-r--r--src/report/report-formatter-base.cpp114
-rw-r--r--src/report/report-formatter-base.h52
-rw-r--r--src/report/report-formatter-csv.cpp163
-rw-r--r--src/report/report-formatter-csv.h73
-rw-r--r--src/report/report-formatter-html.cpp376
-rw-r--r--src/report/report-formatter-html.h73
-rw-r--r--src/report/report-formatter.h57
-rw-r--r--src/report/report-maker.cpp187
-rw-r--r--src/report/report-maker.h139
-rw-r--r--src/report/report.cpp217
-rw-r--r--src/report/report.h47
-rw-r--r--src/tuning/bluetooth.cpp228
-rw-r--r--src/tuning/bluetooth.h49
-rw-r--r--src/tuning/ethernet.cpp157
-rw-r--r--src/tuning/ethernet.h49
-rw-r--r--src/tuning/iw.c303
-rw-r--r--src/tuning/iw.h69
-rw-r--r--src/tuning/nl80211.h1897
-rw-r--r--src/tuning/runtime.cpp202
-rw-r--r--src/tuning/runtime.h50
-rw-r--r--src/tuning/tunable.cpp52
-rw-r--r--src/tuning/tunable.h81
-rw-r--r--src/tuning/tuning.cpp332
-rw-r--r--src/tuning/tuning.h33
-rw-r--r--src/tuning/tuningi2c.cpp129
-rw-r--r--src/tuning/tuningi2c.h46
-rw-r--r--src/tuning/tuningsysfs.cpp130
-rw-r--r--src/tuning/tuningsysfs.h53
-rw-r--r--src/tuning/tuningusb.cpp157
-rw-r--r--src/tuning/tuningusb.h51
-rw-r--r--src/tuning/wifi.cpp112
-rw-r--r--src/tuning/wifi.h50
-rw-r--r--src/wakeup/waketab.cpp195
-rw-r--r--src/wakeup/wakeup.cpp52
-rw-r--r--src/wakeup/wakeup.h81
-rw-r--r--src/wakeup/wakeup_ethernet.cpp111
-rw-r--r--src/wakeup/wakeup_ethernet.h50
-rw-r--r--src/wakeup/wakeup_usb.cpp111
-rw-r--r--src/wakeup/wakeup_usb.h50
128 files changed, 24725 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..6b523f6
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,176 @@
+AUTOMAKE_OPTIONS = subdir-objects
+
+sbin_PROGRAMS = powertop
+nodist_powertop_SOURCES = css.h
+
+powertop_SOURCES = \
+ css.h \
+ devlist.cpp \
+ devlist.h \
+ display.cpp \
+ display.h \
+ lib.cpp \
+ lib.h \
+ main.cpp \
+ powertop.css \
+ \
+ calibrate/calibrate.cpp \
+ calibrate/calibrate.h \
+ cpu/abstract_cpu.cpp \
+ cpu/cpu.cpp \
+ cpu/cpu.h \
+ cpu/cpu_core.cpp \
+ cpu/cpu_linux.cpp \
+ cpu/cpu_package.cpp \
+ cpu/cpu_rapl_device.cpp \
+ cpu/cpu_rapl_device.h \
+ cpu/cpudevice.cpp \
+ cpu/cpudevice.h \
+ cpu/dram_rapl_device.cpp \
+ cpu/dram_rapl_device.h \
+ cpu/intel_cpus.cpp \
+ cpu/intel_cpus.h \
+ cpu/intel_gpu.cpp \
+ cpu/rapl/rapl_interface.cpp \
+ cpu/rapl/rapl_interface.h \
+ devices/ahci.cpp \
+ devices/ahci.h \
+ devices/alsa.cpp \
+ devices/alsa.h \
+ devices/backlight.cpp \
+ devices/backlight.h \
+ devices/devfreq.cpp \
+ devices/devfreq.h \
+ devices/device.cpp \
+ devices/device.h \
+ devices/gpu_rapl_device.cpp \
+ devices/gpu_rapl_device.h \
+ devices/i915-gpu.cpp \
+ devices/i915-gpu.h \
+ devices/network.cpp \
+ devices/network.h \
+ devices/rfkill.cpp \
+ devices/rfkill.h \
+ devices/runtime_pm.cpp \
+ devices/runtime_pm.h \
+ devices/thinkpad-fan.cpp \
+ devices/thinkpad-fan.h \
+ devices/thinkpad-light.cpp \
+ devices/thinkpad-light.h \
+ devices/usb.cpp \
+ devices/usb.h \
+ measurement/acpi.cpp \
+ measurement/acpi.h \
+ measurement/extech.cpp \
+ measurement/extech.h \
+ measurement/measurement.cpp \
+ measurement/measurement.h \
+ measurement/sysfs.cpp \
+ measurement/sysfs.h \
+ measurement/opal-sensors.cpp \
+ measurement/opal-sensors.h \
+ parameters/learn.cpp \
+ parameters/parameters.cpp \
+ parameters/parameters.h \
+ parameters/persistent.cpp \
+ perf/perf.cpp \
+ perf/perf.h \
+ perf/perf_bundle.cpp \
+ perf/perf_bundle.h \
+ perf/perf_event.h \
+ process/do_process.cpp \
+ process/interrupt.cpp \
+ process/interrupt.h \
+ process/powerconsumer.cpp \
+ process/powerconsumer.h \
+ process/process.cpp \
+ process/process.h \
+ process/processdevice.cpp \
+ process/processdevice.h \
+ process/timer.cpp \
+ process/timer.h \
+ process/work.cpp \
+ process/work.h \
+ report/report-data-html.cpp \
+ report/report-data-html.h \
+ 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 \
+ report/report-formatter.h \
+ report/report-maker.cpp \
+ report/report-maker.h \
+ report/report.cpp \
+ report/report.h \
+ tuning/bluetooth.cpp \
+ tuning/bluetooth.h \
+ tuning/ethernet.cpp \
+ tuning/ethernet.h \
+ tuning/iw.c \
+ tuning/iw.h \
+ tuning/nl80211.h \
+ tuning/runtime.cpp \
+ tuning/runtime.h \
+ tuning/tunable.cpp \
+ tuning/tunable.h \
+ tuning/tuning.cpp \
+ tuning/tuning.h \
+ tuning/tuningsysfs.cpp \
+ tuning/tuningsysfs.h \
+ tuning/tuningusb.cpp \
+ tuning/tuningusb.h \
+ tuning/tuningi2c.cpp \
+ tuning/tuningi2c.h \
+ tuning/wifi.cpp \
+ tuning/wifi.h \
+ wakeup/wakeup.cpp \
+ wakeup/waketab.cpp \
+ wakeup/wakeup_ethernet.cpp \
+ wakeup/wakeup_usb.cpp \
+ wakeup/wakeup_usb.h \
+ wakeup/wakeup.h \
+ wakeup/wakeup_ethernet.h
+
+powertop_CXXFLAGS = \
+ -Wall \
+ -Wformat \
+ -Wshadow \
+ -fno-omit-frame-pointer \
+ -fstack-protector \
+ $(GLIB2_CFLAGS) \
+ $(LIBNL_CFLAGS) \
+ $(NCURSES_CFLAGS) \
+ $(PCIUTILS_CFLAGS) \
+ $(PTHREAD_CFLAGS)
+
+
+powertop_CPPFLAGS = \
+ -DLOCALEDIR=\"$(localedir)\" \
+ $(GLIB2_CFLAGS) \
+ $(LIBNL_CFLAGS) \
+ $(LIBZ_CFLAGS) \
+ $(NCURSES_CFLAGS) \
+ $(PCIUTILS_CFLAGS) \
+ $(PTHREAD_CFLAGS)
+
+powertop_LDADD = \
+ ../traceevent/libtraceevnet.la
+
+AM_LDFLAGS = \
+ $(LIBNL_LIBS) \
+ $(LIBS) \
+ $(LIBZ_LIBS) \
+ $(NCURSES_LIBS) \
+ $(PCIUTILS_LIBS) \
+ $(PTHREAD_LIBS) \
+ $(RESOLV_LIBS)
+
+BUILT_SOURCES = css.h
+CLEANFILES = css.h
+
+css.h: powertop.css
+ $(SHELL) ${srcdir}/csstoh.sh ${srcdir}/powertop.css css.h
+
+EXTRA_DIST = ${srcdir}/csstoh.sh
diff --git a/src/calibrate/calibrate.cpp b/src/calibrate/calibrate.cpp
new file mode 100644
index 0000000..745d544
--- /dev/null
+++ b/src/calibrate/calibrate.cpp
@@ -0,0 +1,435 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+#include <algorithm>
+
+#include "calibrate.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <math.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <limits.h>
+
+#include "../parameters/parameters.h"
+extern "C" {
+#include "../tuning/iw.h"
+}
+
+#include <map>
+#include <vector>
+#include <string>
+
+using namespace std;
+
+
+static vector<string> usb_devices;
+static vector<string> rfkill_devices;
+static vector<string> backlight_devices;
+static vector<string> scsi_link_devices;
+static int blmax;
+
+static map<string, string> saved_sysfs;
+
+
+static volatile int stop_measurement;
+
+static int wireless_PS;
+
+
+static void save_sysfs(const char *filename)
+{
+ char line[4096];
+ ifstream file;
+
+ file.open(filename, ios::in);
+ if (!file)
+ return;
+ file.getline(line, 4096);
+ file.close();
+
+ saved_sysfs[filename] = line;
+}
+
+static void restore_all_sysfs(void)
+{
+ map<string, string>::iterator it;
+
+ for (it = saved_sysfs.begin(); it != saved_sysfs.end(); it++)
+ write_sysfs(it->first, it->second);
+
+ set_wifi_power_saving("wlan0", wireless_PS);
+}
+
+static void find_all_usb_callback(const char *d_name)
+{
+ char filename[PATH_MAX];
+ ifstream file;
+
+ snprintf(filename, sizeof(filename), "/sys/bus/usb/devices/%s/power/active_duration", d_name);
+ if (access(filename, R_OK) != 0)
+ return;
+
+ snprintf(filename, sizeof(filename), "/sys/bus/usb/devices/%s/power/idVendor", d_name);
+ file.open(filename, ios::in);
+ if (file) {
+ file.getline(filename, sizeof(filename));
+ file.close();
+ if (strcmp(filename, "1d6b") == 0)
+ return;
+ }
+
+ snprintf(filename, sizeof(filename), "/sys/bus/usb/devices/%s/power/control", d_name);
+ save_sysfs(filename);
+ usb_devices.push_back(filename);
+}
+
+static void find_all_usb(void)
+{
+ process_directory("/sys/bus/usb/devices/", find_all_usb_callback);
+}
+
+static void suspend_all_usb_devices(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < usb_devices.size(); i++)
+ write_sysfs(usb_devices[i], "auto\n");
+}
+
+static void find_all_rfkill_callback(const char *d_name)
+{
+ char filename[PATH_MAX];
+ snprintf(filename, sizeof(filename), "/sys/class/rfkill/%s/soft", d_name);
+ if (access(filename, R_OK) != 0)
+ return;
+ save_sysfs(filename);
+ rfkill_devices.push_back(filename);
+}
+
+static void find_all_rfkill(void)
+{
+ process_directory("/sys/class/rfkill/", find_all_rfkill_callback);
+}
+
+static void rfkill_all_radios(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < rfkill_devices.size(); i++)
+ write_sysfs(rfkill_devices[i], "1\n");
+}
+static void unrfkill_all_radios(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < rfkill_devices.size(); i++)
+ write_sysfs(rfkill_devices[i], "0\n");
+}
+
+static void find_backlight_callback(const char *d_name)
+{
+ char filename[PATH_MAX];
+ snprintf(filename, sizeof(filename), "/sys/class/backlight/%s/brightness", d_name);
+ if (access(filename, R_OK) != 0)
+ return;
+
+ save_sysfs(filename);
+ backlight_devices.push_back(filename);
+ snprintf(filename, sizeof(filename), "/sys/class/backlight/%s/max_brightness", d_name);
+ blmax = read_sysfs(filename);
+}
+
+static void find_backlight(void)
+{
+ process_directory("/sys/class/backlight/", find_backlight_callback);
+}
+
+static void lower_backlight(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < backlight_devices.size(); i++)
+ write_sysfs(backlight_devices[i], "0\n");
+}
+
+static void find_scsi_link_callback(const char *d_name)
+{
+ char filename[PATH_MAX];
+ snprintf(filename, sizeof(filename), "/sys/class/scsi_host/%s/link_power_management_policy", d_name);
+ if (access(filename, R_OK)!=0)
+ return;
+
+ save_sysfs(filename);
+ scsi_link_devices.push_back(filename);
+}
+
+static void find_scsi_link(void)
+{
+ process_directory("/sys/class/scsi_host/", find_scsi_link_callback);
+}
+
+static void set_scsi_link(const char *state)
+{
+ unsigned int i;
+
+ for (i = 0; i < scsi_link_devices.size(); i++)
+ write_sysfs(scsi_link_devices[i], state);
+}
+
+
+static void *burn_cpu(void *dummy)
+{
+ volatile double d = 1.1;
+
+ while (!stop_measurement) {
+ d = pow(d, 1.0001);
+ }
+ return NULL;
+}
+
+static void *burn_cpu_wakeups(void *dummy)
+{
+ struct timespec tm;
+
+ while (!stop_measurement) {
+ tm.tv_sec = 0;
+ tm.tv_nsec = (unsigned long)dummy;
+ nanosleep(&tm, NULL);
+ }
+ return NULL;
+}
+
+static void *burn_disk(void *dummy)
+{
+ int fd;
+ char buffer[64*1024];
+ char filename[256];
+
+ strcpy(filename ,"/tmp/powertop.XXXXXX");
+ fd = mkstemp(filename);
+
+ if (fd < 0) {
+ printf(_("Cannot create temp file\n"));
+ return NULL;
+ }
+
+ while (!stop_measurement) {
+ lseek(fd, 0, SEEK_SET);
+ if(write(fd, buffer, 64*1024) == -1)
+ printf("Error: %s\n", strerror(errno));
+ fdatasync(fd);
+ }
+ unlink(filename);
+ return NULL;
+}
+
+
+static void cpu_calibration(int threads)
+{
+ int i;
+ pthread_t thr;
+
+ printf(_("Calibrating: CPU usage on %i threads\n"), threads);
+
+ stop_measurement = 0;
+ for (i = 0; i < threads; i++)
+ pthread_create(&thr, NULL, burn_cpu, NULL);
+
+ one_measurement(15, 15, NULL);
+ stop_measurement = 1;
+ sleep(1);
+}
+
+static void wakeup_calibration(unsigned long interval)
+{
+ pthread_t thr;
+
+ printf(_("Calibrating: CPU wakeup power consumption\n"));
+
+ stop_measurement = 0;
+
+ pthread_create(&thr, NULL, burn_cpu_wakeups, (void *)interval);
+
+ one_measurement(15, 15, NULL);
+ stop_measurement = 1;
+ sleep(1);
+}
+
+static void usb_calibration(void)
+{
+ unsigned int i;
+
+ /* chances are one of the USB devices is bluetooth; unrfkill first */
+ unrfkill_all_radios();
+ printf(_("Calibrating USB devices\n"));
+ for (i = 0; i < usb_devices.size(); i++) {
+ printf(_(".... device %s \n"), usb_devices[i].c_str());
+ suspend_all_usb_devices();
+ write_sysfs(usb_devices[i], "on\n");
+ one_measurement(15, 15, NULL);
+ suspend_all_usb_devices();
+ sleep(3);
+ }
+ rfkill_all_radios();
+ sleep(4);
+}
+
+static void rfkill_calibration(void)
+{
+ unsigned int i;
+
+ printf(_("Calibrating radio devices\n"));
+ for (i = 0; i < rfkill_devices.size(); i++) {
+ printf(_(".... device %s \n"), rfkill_devices[i].c_str());
+ rfkill_all_radios();
+ write_sysfs(rfkill_devices[i], "0\n");
+ one_measurement(15, 15, NULL);
+ rfkill_all_radios();
+ sleep(3);
+ }
+ for (i = 0; i < rfkill_devices.size(); i++) {
+ printf(_(".... device %s \n"), rfkill_devices[i].c_str());
+ unrfkill_all_radios();
+ write_sysfs(rfkill_devices[i], "1\n");
+ one_measurement(15, 15, NULL);
+ unrfkill_all_radios();
+ sleep(3);
+ }
+ rfkill_all_radios();
+}
+
+static void backlight_calibration(void)
+{
+ unsigned int i;
+
+ printf(_("Calibrating backlight\n"));
+ for (i = 0; i < backlight_devices.size(); i++) {
+ char str[4096];
+ printf(_(".... device %s \n"), backlight_devices[i].c_str());
+ lower_backlight();
+ one_measurement(15, 15, NULL);
+ sprintf(str, "%i\n", blmax / 4);
+ write_sysfs(backlight_devices[i], str);
+ one_measurement(15, 15, NULL);
+
+ sprintf(str, "%i\n", blmax / 2);
+ write_sysfs(backlight_devices[i], str);
+ one_measurement(15, 15, NULL);
+
+ sprintf(str, "%i\n", 3 * blmax / 4 );
+ write_sysfs(backlight_devices[i], str);
+ one_measurement(15, 15, NULL);
+
+ sprintf(str, "%i\n", blmax);
+ write_sysfs(backlight_devices[i], str);
+ one_measurement(15, 15, NULL);
+ lower_backlight();
+ sleep(1);
+ }
+ printf(_("Calibrating idle\n"));
+ if(!system("DISPLAY=:0 /usr/bin/xset dpms force off"))
+ printf("System is not available\n");
+ one_measurement(15, 15, NULL);
+ if(!system("DISPLAY=:0 /usr/bin/xset dpms force on"))
+ printf("System is not available\n");
+}
+
+static void idle_calibration(void)
+{
+ printf(_("Calibrating idle\n"));
+ if(!system("DISPLAY=:0 /usr/bin/xset dpms force off"))
+ printf("System is not available\n");
+ one_measurement(15, 15, NULL);
+ if(!system("DISPLAY=:0 /usr/bin/xset dpms force on"))
+ printf("System is not available\n");
+}
+
+
+static void disk_calibration(void)
+{
+ pthread_t thr;
+
+ printf(_("Calibrating: disk usage \n"));
+
+ set_scsi_link("min_power");
+
+ stop_measurement = 0;
+ pthread_create(&thr, NULL, burn_disk, NULL);
+
+ one_measurement(15, 15, NULL);
+ stop_measurement = 1;
+ sleep(1);
+
+
+}
+
+
+void calibrate(void)
+{
+ find_all_usb();
+ find_all_rfkill();
+ find_backlight();
+ find_scsi_link();
+ wireless_PS = get_wifi_power_saving("wlan0");
+
+ save_sysfs("/sys/module/snd_hda_intel/parameters/power_save");
+
+ cout << _("Starting PowerTOP power estimate calibration \n");
+ suspend_all_usb_devices();
+ rfkill_all_radios();
+ lower_backlight();
+ set_wifi_power_saving("wlan0", 1);
+
+ sleep(4);
+
+
+ idle_calibration();
+ disk_calibration();
+ backlight_calibration();
+
+ write_sysfs("/sys/module/snd_hda_intel/parameters/power_save", "1\n");
+ cpu_calibration(1);
+ cpu_calibration(4);
+ wakeup_calibration(10000);
+ wakeup_calibration(100000);
+ wakeup_calibration(1000000);
+ set_wifi_power_saving("wlan0", 0);
+ usb_calibration();
+ rfkill_calibration();
+
+ cout << _("Finishing PowerTOP power estimate calibration \n");
+
+ restore_all_sysfs();
+ learn_parameters(300, 1);
+ printf(_("Parameters after calibration:\n"));
+ dump_parameter_bundle();
+ save_parameters("saved_parameters.powertop");
+ save_all_results("saved_results.powertop");
+
+}
diff --git a/src/calibrate/calibrate.h b/src/calibrate/calibrate.h
new file mode 100644
index 0000000..de71938
--- /dev/null
+++ b/src/calibrate/calibrate.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef __INCLUDE_GUARD_CALIBRATE_H
+#define __INCLUDE_GUARD_CALIBRATE_H
+
+extern void one_measurement(int seconds, int sample_interval, char *workload);
+extern void calibrate(void);
+
+
+#endif
diff --git a/src/cpu/abstract_cpu.cpp b/src/cpu/abstract_cpu.cpp
new file mode 100644
index 0000000..066891d
--- /dev/null
+++ b/src/cpu/abstract_cpu.cpp
@@ -0,0 +1,535 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "cpu.h"
+#include "../lib.h"
+
+abstract_cpu::~abstract_cpu()
+{
+ unsigned int i=0;
+ for (i=0; i < cstates.size(); i++){
+ delete cstates[i];
+ }
+ cstates.clear();
+
+ for (i=0; i < pstates.size(); i++){
+ delete pstates[i];
+ }
+ pstates.clear();
+}
+
+void abstract_cpu::account_freq(uint64_t freq, uint64_t duration)
+{
+ struct frequency *state = NULL;
+ unsigned int i;
+
+ for (i = 0; i < pstates.size(); i++) {
+ if (freq == pstates[i]->freq) {
+ state = pstates[i];
+ break;
+ }
+ }
+
+
+ if (!state) {
+ state = new(std::nothrow) struct frequency;
+
+ if (!state)
+ return;
+
+ memset(state, 0, sizeof(*state));
+
+ pstates.push_back(state);
+
+ state->freq = freq;
+ hz_to_human(freq, state->human_name);
+ if (freq == 0)
+ pt_strcpy(state->human_name, _("Idle"));
+ if (is_turbo(freq, max_frequency, max_minus_one_frequency))
+ pt_strcpy(state->human_name, _("Turbo Mode"));
+
+ state->after_count = 1;
+ }
+
+
+ state->time_after += duration;
+
+
+}
+
+void abstract_cpu::freq_updated(uint64_t time)
+{
+ if(parent)
+ parent->calculate_freq(time);
+ old_idle = idle;
+}
+
+void abstract_cpu::measurement_start(void)
+{
+ unsigned int i;
+ ifstream file;
+ char filename[4096];
+
+ last_stamp = 0;
+
+ for (i = 0; i < cstates.size(); i++)
+ delete cstates[i];
+ cstates.resize(0);
+
+ for (i = 0; i < pstates.size(); i++)
+ delete pstates[i];
+ pstates.resize(0);
+
+ current_frequency = 0;
+ idle = false;
+ old_idle = true;
+
+
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpufreq/scaling_available_frequencies", number);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> max_frequency;
+ file >> max_minus_one_frequency;
+ file.close();
+ }
+
+ for (i = 0; i < children.size(); i++)
+ if (children[i])
+ children[i]->measurement_start();
+
+ gettimeofday(&stamp_before, NULL);
+
+ last_stamp = 0;
+
+ for (i = 0; i < children.size(); i++)
+ if (children[i])
+ children[i]->wiggle();
+
+}
+
+void abstract_cpu::measurement_end(void)
+{
+ unsigned int i, j;
+
+ total_stamp = 0;
+ gettimeofday(&stamp_after, NULL);
+ for (i = 0; i < children.size(); i++)
+ if (children[i])
+ children[i]->wiggle();
+
+ time_factor = 1000000.0 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+
+ for (i = 0; i < children.size(); i++)
+ if (children[i])
+ children[i]->measurement_end();
+
+ for (i = 0; i < children.size(); i++)
+ if (children[i]) {
+ for (j = 0; j < children[i]->cstates.size(); j++) {
+ struct idle_state *state;
+ state = children[i]->cstates[j];
+ if (!state)
+ continue;
+
+ update_cstate( state->linux_name, state->human_name, state->usage_before, state->duration_before, state->before_count);
+ finalize_cstate(state->linux_name, state->usage_after, state->duration_after, state->after_count);
+ }
+ for (j = 0; j < children[i]->pstates.size(); j++) {
+ struct frequency *state;
+ state = children[i]->pstates[j];
+ if (!state)
+ continue;
+
+ update_pstate( state->freq, state->human_name, state->time_before, state->before_count);
+ finalize_pstate(state->freq, state->time_after, state->after_count);
+ }
+ }
+
+ for (i = 0; i < cstates.size(); i++) {
+ struct idle_state *state = cstates[i];
+
+ if (state->after_count == 0)
+ continue;
+
+ if (state->after_count != state->before_count)
+ continue;
+
+ state->usage_delta = (state->usage_after - state->usage_before) / state->after_count;
+ state->duration_delta = (state->duration_after - state->duration_before) / state->after_count;
+ }
+}
+
+void abstract_cpu::insert_cstate(const char *linux_name, const char *human_name, uint64_t usage, uint64_t duration, int count, int level)
+{
+ struct idle_state *state;
+ const char *c;
+
+ state = new(std::nothrow) struct idle_state;
+
+ if (!state)
+ return;
+
+ memset(state, 0, sizeof(*state));
+
+ cstates.push_back(state);
+
+ pt_strcpy(state->linux_name, linux_name);
+ pt_strcpy(state->human_name, human_name);
+
+ state->line_level = -1;
+
+ c = human_name;
+ while (*c) {
+ if (strcmp(linux_name, "active")==0) {
+ state->line_level = LEVEL_C0;
+ break;
+ }
+ if (*c >= '0' && *c <='9') {
+ state->line_level = strtoull(c, NULL, 10);
+ if(*(c+1) != '-'){
+ int greater_line_level = strtoull(c, NULL, 10);
+ for(unsigned int pos = 0; pos < cstates.size(); pos++){
+ if(*c == cstates[pos]->human_name[1]){
+ if(*(c+1) != cstates[pos]->human_name[2]){
+ greater_line_level = max(greater_line_level, cstates[pos]->line_level);
+ state->line_level = greater_line_level + 1;
+ }
+ }
+ }
+ }
+ break;
+ }
+ c++;
+ }
+
+ /* some architectures (ARM) don't have good numbers in their human name.. fall back to the linux name for those */
+ c = linux_name;
+ while (*c && state->line_level < 0) {
+ if (*c >= '0' && *c <='9') {
+ state->line_level = strtoull(c, NULL, 10);
+ break;
+ }
+ c++;
+ }
+
+ if (level >= 0)
+ state->line_level = level;
+
+ state->usage_before = usage;
+ state->duration_before = duration;
+ state->before_count = count;
+}
+
+void abstract_cpu::finalize_cstate(const char *linux_name, uint64_t usage, uint64_t duration, int count)
+{
+ unsigned int i;
+ struct idle_state *state = NULL;
+
+ for (i = 0; i < cstates.size(); i++) {
+ if (strcmp(linux_name, cstates[i]->linux_name) == 0) {
+ state = cstates[i];
+ break;
+ }
+ }
+
+ if (!state) {
+ cout << "Invalid C state finalize " << linux_name << " \n";
+ return;
+ }
+
+ state->usage_after += usage;
+ state->duration_after += duration;
+ state->after_count += count;
+}
+
+void abstract_cpu::update_cstate(const char *linux_name, const char *human_name, uint64_t usage, uint64_t duration, int count, int level)
+{
+ unsigned int i;
+ struct idle_state *state = NULL;
+
+ for (i = 0; i < cstates.size(); i++) {
+ if (strcmp(linux_name, cstates[i]->linux_name) == 0) {
+ state = cstates[i];
+ break;
+ }
+ }
+
+ if (!state) {
+ insert_cstate(linux_name, human_name, usage, duration, count, level);
+ return;
+ }
+
+ state->usage_before += usage;
+ state->duration_before += duration;
+ state->before_count += count;
+
+}
+
+int abstract_cpu::has_cstate_level(int level)
+{
+ unsigned int i;
+
+ if (level == LEVEL_HEADER)
+ return 1;
+
+ for (i = 0; i < cstates.size(); i++)
+ if (cstates[i]->line_level == level)
+ return 1;
+
+ for (i = 0; i < children.size(); i++)
+ if (children[i])
+ if (children[i]->has_cstate_level(level))
+ return 1;
+ return 0;
+}
+
+int abstract_cpu::has_pstate_level(int level)
+{
+ unsigned int i;
+
+ if (level == LEVEL_HEADER)
+ return 1;
+
+ if (level >= 0 && level < (int)pstates.size())
+ return 1;
+
+ for (i = 0; i < children.size(); i++)
+ if (children[i])
+ if (children[i]->has_pstate_level(level))
+ return 1;
+ return 0;
+}
+
+
+
+void abstract_cpu::insert_pstate(uint64_t freq, const char *human_name, uint64_t duration, int count)
+{
+ struct frequency *state;
+
+ state = new(std::nothrow) struct frequency;
+
+ if (!state)
+ return;
+
+ memset(state, 0, sizeof(*state));
+
+ pstates.push_back(state);
+
+ state->freq = freq;
+ pt_strcpy(state->human_name, human_name);
+
+
+ state->time_before = duration;
+ state->before_count = count;
+}
+
+void abstract_cpu::finalize_pstate(uint64_t freq, uint64_t duration, int count)
+{
+ unsigned int i;
+ struct frequency *state = NULL;
+
+ for (i = 0; i < pstates.size(); i++) {
+ if (freq == pstates[i]->freq) {
+ state = pstates[i];
+ break;
+ }
+ }
+
+ if (!state) {
+ cout << "Invalid P state finalize " << freq << " \n";
+ return;
+ }
+ state->time_after += duration;
+ state->after_count += count;
+
+}
+
+void abstract_cpu::update_pstate(uint64_t freq, const char *human_name, uint64_t duration, int count)
+{
+ unsigned int i;
+ struct frequency *state = NULL;
+
+ for (i = 0; i < pstates.size(); i++) {
+ if (freq == pstates[i]->freq) {
+ state = pstates[i];
+ break;
+ }
+ }
+
+ if (!state) {
+ insert_pstate(freq, human_name, duration, count);
+ return;
+ }
+
+ state->time_before += duration;
+ state->before_count += count;
+}
+
+
+void abstract_cpu::calculate_freq(uint64_t time)
+{
+ uint64_t freq = 0;
+ bool is_idle = true;
+ unsigned int i;
+
+ /* calculate the maximum frequency of all children */
+ for (i = 0; i < children.size(); i++)
+ if (children[i] && children[i]->has_pstates()) {
+ uint64_t f = 0;
+ if (!children[i]->idle) {
+ f = children[i]->current_frequency;
+ is_idle = false;
+ }
+ if (f > freq)
+ freq = f;
+ }
+
+ current_frequency = freq;
+ idle = is_idle;
+ freq_updated(time);
+}
+
+void abstract_cpu::change_effective_frequency(uint64_t time, uint64_t frequency)
+{
+ unsigned int i;
+ uint64_t time_delta, fr;
+
+ if (last_stamp)
+ time_delta = time - last_stamp;
+ else
+ time_delta = 1;
+
+ fr = effective_frequency;
+ if (old_idle)
+ fr = 0;
+
+ account_freq(fr, time_delta);
+
+ effective_frequency = frequency;
+ last_stamp = time;
+
+ /* propagate to all children */
+ for (i = 0; i < children.size(); i++)
+ if (children[i]) {
+ children[i]->change_effective_frequency(time, frequency);
+ }
+}
+
+
+void abstract_cpu::wiggle(void)
+{
+ char filename[PATH_MAX];
+ ifstream ifile;
+ ofstream ofile;
+ uint64_t minf,maxf;
+ uint64_t setspeed = 0;
+
+ /* wiggle a CPU so that we have a record of it at the start and end of the perf trace */
+
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpufreq/scaling_max_freq", first_cpu);
+ ifile.open(filename, ios::in);
+ ifile >> maxf;
+ ifile.close();
+
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpufreq/scaling_min_freq", first_cpu);
+ ifile.open(filename, ios::in);
+ ifile >> minf;
+ ifile.close();
+
+ /* In case of the userspace governor, remember the old setspeed setting, it will be affected by wiggle */
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpufreq/scaling_setspeed", first_cpu);
+ ifile.open(filename, ios::in);
+ /* Note that non-userspace governors report "<unsupported>". In that case ifile will fail and setspeed remains 0 */
+ ifile >> setspeed;
+ ifile.close();
+
+ ofile.open(filename, ios::out);
+ ofile << maxf;
+ ofile.close();
+ ofile.open(filename, ios::out);
+ ofile << minf;
+ ofile.close();
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpufreq/scaling_max_freq", first_cpu);
+ ofile.open(filename, ios::out);
+ ofile << minf;
+ ofile.close();
+ ofile.open(filename, ios::out);
+ ofile << maxf;
+ ofile.close();
+
+ if (setspeed != 0) {
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpufreq/scaling_setspeed", first_cpu);
+ ofile.open(filename, ios::out);
+ ofile << setspeed;
+ ofile.close();
+ }
+}
+uint64_t abstract_cpu::total_pstate_time(void)
+{
+ unsigned int i;
+ uint64_t stamp = 0;
+
+ for (i = 0; i < pstates.size(); i++)
+ stamp += pstates[i]->time_after;
+
+ return stamp;
+}
+
+
+void abstract_cpu::validate(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < children.size(); i++) {
+ if (children[i])
+ children[i]->validate();
+ }
+}
+
+void abstract_cpu::reset_pstate_data(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < pstates.size(); i++) {
+ pstates[i]->time_before = 0;
+ pstates[i]->time_after = 0;
+ }
+ for (i = 0; i < cstates.size(); i++) {
+ cstates[i]->duration_before = 0;
+ cstates[i]->duration_after = 0;
+ cstates[i]->before_count = 0;
+ cstates[i]->after_count = 0;
+ }
+
+ for (i = 0; i < children.size(); i++)
+ if (children[i])
+ children[i]->reset_pstate_data();
+}
diff --git a/src/cpu/cpu.cpp b/src/cpu/cpu.cpp
new file mode 100644
index 0000000..1c12765
--- /dev/null
+++ b/src/cpu/cpu.cpp
@@ -0,0 +1,1075 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <string.h>
+#include <stdlib.h>
+#include <ncurses.h>
+#include <unistd.h>
+#include "cpu.h"
+#include "cpudevice.h"
+#include "cpu_rapl_device.h"
+#include "dram_rapl_device.h"
+#include "intel_cpus.h"
+#include "../parameters/parameters.h"
+
+#include "../perf/perf_bundle.h"
+#include "../lib.h"
+#include "../display.h"
+#include "../report/report.h"
+#include "../report/report-maker.h"
+#include "../report/report-data-html.h"
+
+static class abstract_cpu system_level;
+
+vector<class abstract_cpu *> all_cpus;
+
+static class perf_bundle * perf_events;
+
+
+
+class perf_power_bundle: public perf_bundle
+{
+ virtual void handle_trace_point(void *trace, int cpu, uint64_t time);
+
+};
+
+
+static class abstract_cpu * new_package(int package, int cpu, char * vendor, int family, int model)
+{
+ class abstract_cpu *ret = NULL;
+ class cpudevice *cpudev;
+ class cpu_rapl_device *cpu_rapl_dev;
+ class dram_rapl_device *dram_rapl_dev;
+
+ char packagename[128];
+ if (strcmp(vendor, "GenuineIntel") == 0)
+ if (family == 6)
+ if (is_supported_intel_cpu(model, cpu)) {
+ ret = new class nhm_package(model);
+ ret->set_intel_MSR(true);
+ }
+
+ if (!ret) {
+ ret = new class cpu_package;
+ ret->set_intel_MSR(false);
+ }
+
+ ret->set_number(package, cpu);
+ ret->set_type("Package");
+ ret->childcount = 0;
+
+ snprintf(packagename, sizeof(packagename), _("cpu package %i"), cpu);
+ cpudev = new class cpudevice(_("cpu package"), packagename, ret);
+ all_devices.push_back(cpudev);
+
+ snprintf(packagename, sizeof(packagename), _("package-%i"), cpu);
+ cpu_rapl_dev = new class cpu_rapl_device(cpudev, _("cpu rapl package"), packagename, ret);
+ if (cpu_rapl_dev->device_present())
+ all_devices.push_back(cpu_rapl_dev);
+ else
+ delete cpu_rapl_dev;
+
+ snprintf(packagename, sizeof(packagename), _("package-%i"), cpu);
+ dram_rapl_dev = new class dram_rapl_device(cpudev, _("dram rapl package"), packagename, ret);
+ if (dram_rapl_dev->device_present())
+ all_devices.push_back(dram_rapl_dev);
+ else
+ delete dram_rapl_dev;
+
+ return ret;
+}
+
+static class abstract_cpu * new_core(int core, int cpu, char * vendor, int family, int model)
+{
+ class abstract_cpu *ret = NULL;
+
+ if (strcmp(vendor, "GenuineIntel") == 0)
+ if (family == 6)
+ if (is_supported_intel_cpu(model, cpu)) {
+ ret = new class nhm_core(model);
+ ret->set_intel_MSR(true);
+ }
+
+ if (!ret) {
+ ret = new class cpu_core;
+ ret->set_intel_MSR(false);
+ }
+
+ ret->set_number(core, cpu);
+ ret->childcount = 0;
+ ret->set_type("Core");
+
+ return ret;
+}
+
+static class abstract_cpu * new_i965_gpu(void)
+{
+ class abstract_cpu *ret = NULL;
+
+ ret = new class i965_core;
+ ret->childcount = 0;
+ ret->set_type("GPU");
+
+ return ret;
+}
+
+static class abstract_cpu * new_cpu(int number, char * vendor, int family, int model)
+{
+ class abstract_cpu * ret = NULL;
+
+ if (strcmp(vendor, "GenuineIntel") == 0)
+ if (family == 6)
+ if (is_supported_intel_cpu(model, number)) {
+ ret = new class nhm_cpu;
+ ret->set_intel_MSR(true);
+ }
+
+ if (!ret) {
+ ret = new class cpu_linux;
+ ret->set_intel_MSR(false);
+ }
+ ret->set_number(number, number);
+ ret->set_type("CPU");
+ ret->childcount = 0;
+
+ return ret;
+}
+
+
+
+
+static void handle_one_cpu(unsigned int number, char *vendor, int family, int model)
+{
+ char filename[PATH_MAX];
+ ifstream file;
+ unsigned int package_number = 0;
+ unsigned int core_number = 0;
+ class abstract_cpu *package, *core, *cpu;
+
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/topology/core_id", number);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> core_number;
+ file.close();
+ }
+
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/topology/physical_package_id", number);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> package_number;
+ if (package_number == (unsigned int) -1)
+ package_number = 0;
+ file.close();
+ }
+
+
+ if (system_level.children.size() <= package_number)
+ system_level.children.resize(package_number + 1, NULL);
+
+ if (!system_level.children[package_number]) {
+ system_level.children[package_number] = new_package(package_number, number, vendor, family, model);
+ system_level.childcount++;
+ }
+
+ package = system_level.children[package_number];
+ package->parent = &system_level;
+
+ if (package->children.size() <= core_number)
+ package->children.resize(core_number + 1, NULL);
+
+ if (!package->children[core_number]) {
+ package->children[core_number] = new_core(core_number, number, vendor, family, model);
+ package->childcount++;
+ }
+
+ core = package->children[core_number];
+ core->parent = package;
+
+ if (core->children.size() <= number)
+ core->children.resize(number + 1, NULL);
+ if (!core->children[number]) {
+ core->children[number] = new_cpu(number, vendor, family, model);
+ core->childcount++;
+ }
+
+ cpu = core->children[number];
+ cpu->parent = core;
+
+ if (number >= all_cpus.size())
+ all_cpus.resize(number + 1, NULL);
+ all_cpus[number] = cpu;
+}
+
+static void handle_i965_gpu(void)
+{
+ unsigned int core_number = 0;
+ class abstract_cpu *package;
+
+
+ package = system_level.children[0];
+
+ core_number = package->children.size();
+
+ if (package->children.size() <= core_number)
+ package->children.resize(core_number + 1, NULL);
+
+ if (!package->children[core_number]) {
+ package->children[core_number] = new_i965_gpu();
+ package->childcount++;
+ }
+}
+
+
+void enumerate_cpus(void)
+{
+ ifstream file;
+ char line[4096];
+
+ int number = -1;
+ char vendor[128];
+ int family = 0;
+ int model = 0;
+
+ file.open("/proc/cpuinfo", ios::in);
+
+ if (!file)
+ return;
+ /* Not all /proc/cpuinfo include "vendor_id\t". */
+ vendor[0] = '\0';
+
+ while (file) {
+
+ file.getline(line, sizeof(line));
+ if (strncmp(line, "vendor_id\t",10) == 0) {
+ char *c;
+ c = strchr(line, ':');
+ if (c) {
+ c++;
+ if (*c == ' ')
+ c++;
+ pt_strcpy(vendor, c);
+ }
+ }
+ if (strncmp(line, "processor\t",10) == 0) {
+ char *c;
+ c = strchr(line, ':');
+ if (c) {
+ c++;
+ number = strtoull(c, NULL, 10);
+ }
+ }
+ if (strncmp(line, "cpu family\t",11) == 0) {
+ char *c;
+ c = strchr(line, ':');
+ if (c) {
+ c++;
+ family = strtoull(c, NULL, 10);
+ }
+ }
+ if (strncmp(line, "model\t",6) == 0) {
+ char *c;
+ c = strchr(line, ':');
+ if (c) {
+ c++;
+ model = strtoull(c, NULL, 10);
+ }
+ }
+ /* on x86 and others 'bogomips' is last
+ * on ARM it *can* be bogomips, or 'CPU revision'
+ * on POWER, it's revision
+ */
+ if (strncasecmp(line, "bogomips\t", 9) == 0
+ || strncasecmp(line, "CPU revision\t", 13) == 0
+ || strncmp(line, "revision", 8) == 0) {
+ if (number == -1) {
+ /* Not all /proc/cpuinfo include "processor\t". */
+ number = 0;
+ }
+ if (number >= 0) {
+ handle_one_cpu(number, vendor, family, model);
+ set_max_cpu(number);
+ number = -2;
+ }
+ }
+ }
+
+
+ file.close();
+
+ if (access("/sys/class/drm/card0/power/rc6_residency_ms", R_OK) == 0)
+ handle_i965_gpu();
+
+ perf_events = new perf_power_bundle();
+
+ if (!perf_events->add_event("power:cpu_idle")){
+ perf_events->add_event("power:power_start");
+ perf_events->add_event("power:power_end");
+ }
+ if (!perf_events->add_event("power:cpu_frequency"))
+ perf_events->add_event("power:power_frequency");
+
+}
+
+void start_cpu_measurement(void)
+{
+ perf_events->start();
+ system_level.measurement_start();
+}
+
+void end_cpu_measurement(void)
+{
+ system_level.measurement_end();
+ perf_events->stop();
+}
+
+static void expand_string(char *string, unsigned int newlen)
+{
+ while (strlen(string) < newlen)
+ strcat(string, " ");
+}
+
+static int has_state_level(class abstract_cpu *acpu, int state, int line)
+{
+ switch (state) {
+ case PSTATE:
+ return acpu->has_pstate_level(line);
+ break;
+ case CSTATE:
+ return acpu->has_cstate_level(line);
+ break;
+ }
+ return 0;
+}
+
+static const char * fill_state_name(class abstract_cpu *acpu, int state, int line, char *buf)
+{
+ switch (state) {
+ case PSTATE:
+ return acpu->fill_pstate_name(line, buf);
+ break;
+ case CSTATE:
+ return acpu->fill_cstate_name(line, buf);
+ break;
+ }
+ return "-EINVAL";
+}
+
+static const char * fill_state_line(class abstract_cpu *acpu, int state, int line,
+ char *buf, const char *sep = "")
+{
+ switch (state) {
+ case PSTATE:
+ return acpu->fill_pstate_line(line, buf);
+ break;
+ case CSTATE:
+ return acpu->fill_cstate_line(line, buf, sep);
+ break;
+ }
+ return "-EINVAL";
+}
+
+static int get_cstates_num(void)
+{
+ unsigned int package, core, cpu;
+ class abstract_cpu *_package, * _core, * _cpu;
+ unsigned int i;
+ int cstates_num;
+
+ for (package = 0, cstates_num = 0;
+ package < system_level.children.size(); package++) {
+ _package = system_level.children[package];
+ if (_package == NULL)
+ continue;
+
+ /* walk package cstates and get largest cstates number */
+ for (i = 0; i < _package->cstates.size(); i++)
+ cstates_num = std::max(cstates_num,
+ (_package->cstates[i])->line_level);
+
+ /*
+ * for each core in this package, walk core cstates and get
+ * largest cstates number
+ */
+ for (core = 0; core < _package->children.size(); core++) {
+ _core = _package->children[core];
+ if (_core == NULL)
+ continue;
+
+ for (i = 0; i < _core->cstates.size(); i++)
+ cstates_num = std::max(cstates_num,
+ (_core->cstates[i])->line_level);
+
+ /*
+ * for each core, walk the logical cpus in case
+ * there is are more linux cstates than hw cstates
+ */
+ for (cpu = 0; cpu < _core->children.size(); cpu++) {
+ _cpu = _core->children[cpu];
+ if (_cpu == NULL)
+ continue;
+
+ for (i = 0; i < _cpu->cstates.size(); i++)
+ cstates_num = std::max(cstates_num,
+ (_cpu->cstates[i])->line_level);
+ }
+ }
+ }
+
+ return cstates_num;
+}
+
+void report_display_cpu_cstates(void)
+{
+ char buffer[512], buffer2[512], tmp_num[50];
+ unsigned int package, core, cpu;
+ int line, cstates_num, title=0, core_num=0;
+ class abstract_cpu *_package, *_core = NULL, * _cpu;
+ const char* core_type = NULL;
+
+ cstates_num = get_cstates_num();
+ /* div attr css_class and css_id */
+ tag_attr div_attr;
+ init_div(&div_attr, "clear_block", "cpuidle");
+
+ /* Set Table attributes, rows, and cols */
+ table_attributes std_table_css;
+ table_size pkg_tbl_size;
+ table_size core_tbl_size;
+ table_size cpu_tbl_size;
+
+
+ /* Set Title attributes */
+ tag_attr title_attr;
+ init_title_attr(&title_attr);
+
+ /* Report add section */
+ report.add_div(&div_attr);
+ report.add_title(&title_attr, __("Processor Idle State Report"));
+
+ /* Set array of data in row Major order */
+ int idx1, idx2, idx3;
+ string tmp_str;
+
+ for (package = 0; package < system_level.children.size(); package++) {
+ bool first_core = true;
+ idx1=0;
+ idx2=0;
+ idx3=0;
+
+ _package = system_level.children[package];
+ if (!_package)
+ continue;
+ /* Tables for PKG, CORE, CPU */
+ pkg_tbl_size.cols=2;
+ pkg_tbl_size.rows= ((cstates_num+1)-LEVEL_HEADER)+1;
+ string *pkg_data = new string[pkg_tbl_size.cols * pkg_tbl_size.rows];
+
+ core_tbl_size.cols=2;
+ core_tbl_size.rows=(cstates_num *_package->children.size())
+ + _package->children.size();
+ string *core_data = new string[core_tbl_size.cols * core_tbl_size.rows];
+ int num_cpus=0, num_cores=0;
+
+ for (core = 0; core < _package->children.size(); core++) {
+ _core = _package->children[core];
+ if (!_core)
+ continue;
+ core_type = _core->get_type();
+ if (core_type != NULL)
+ if (strcmp(core_type, "Core") == 0 )
+ num_cores+=1;
+
+ for (cpu = 0; cpu < _core->children.size(); cpu++) {
+ _cpu = _core->children[cpu];
+ if (!_cpu)
+ continue;
+ num_cpus+=1;
+ }
+ }
+ cpu_tbl_size.cols=(2 * (num_cpus / num_cores)) + 1;
+ cpu_tbl_size.rows = ((cstates_num+1-LEVEL_HEADER) * _package->children.size())
+ + _package->children.size();
+ string *cpu_data = new string[cpu_tbl_size.cols * cpu_tbl_size.rows];
+
+ for (core = 0; core < _package->children.size(); core++) {
+ cpu_data[idx3]="&nbsp;";
+ idx3+=1;
+ _core = _package->children[core];
+
+ if (!_core)
+ continue;
+
+ /* *** PKG STARTS *** */
+ for (line = LEVEL_HEADER; line <= cstates_num; line++) {
+ bool first_cpu = true;
+ if (!_package->has_cstate_level(line))
+ continue;
+ buffer[0] = 0;
+ buffer2[0] = 0;
+ if (line == LEVEL_HEADER) {
+ if (first_core) {
+ pkg_data[idx1]=__("Package");
+ idx1+=1;
+ sprintf(tmp_num,"%d", _package->get_number());
+ pkg_data[idx1]= string(tmp_num);
+ idx1+=1;
+ }
+ } else if (first_core) {
+ tmp_str=string(_package->fill_cstate_name(line, buffer));
+ pkg_data[idx1]=(tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx1+=1;
+ tmp_str=string(_package->fill_cstate_line(line, buffer2));
+ pkg_data[idx1]=(tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx1+=1;
+ }
+
+ /* *** CORE STARTS *** */
+ if (!_core->can_collapse()) {
+ buffer[0] = 0;
+ buffer2[0] = 0;
+
+ /*
+ * Patch for compatibility with Ryzen processors
+ * See https://github.com/fenrus75/powertop/issues/64
+ */
+ if(idx2 >= core_tbl_size.cols * core_tbl_size.rows) break;
+
+ if (line == LEVEL_HEADER) {
+ /* Here we need to check for which core type we
+ * are using. Do not use the core type for the
+ * report.addf as it breaks an important macro use
+ * for translation decision making for the reports.
+ * */
+ core_type = _core->get_type();
+ if (core_type != NULL) {
+ if (strcmp(core_type, "Core") == 0 ) {
+ core_data[idx2]="";
+ idx2+=1;
+ snprintf(tmp_num, sizeof(tmp_num), __("Core %d"), _core->get_number());
+ core_data[idx2]=string(tmp_num);
+ idx2+=1;
+ core_num+=1;
+ } else {
+ core_data[idx2]="";
+ idx2+=1;
+ snprintf(tmp_num, sizeof(tmp_num), __("GPU %d"), _core->get_number());
+ core_data[idx2]=string(tmp_num);
+ idx2+=1;
+ }
+ }
+ } else {
+
+
+ tmp_str=string(_core->fill_cstate_name(line, buffer));
+ core_data[idx2]=(tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx2+=1;
+ tmp_str=string(_core->fill_cstate_line(line, buffer2));
+ core_data[idx2]=(tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx2+=1;
+ }
+ }
+ // *** CPU STARTS ***
+ for (cpu = 0; cpu < _core->children.size(); cpu++) {
+ _cpu = _core->children[cpu];
+
+ if (!_cpu)
+ continue;
+ if (line == LEVEL_HEADER) {
+ cpu_data[idx3] = __("CPU");
+ idx3+=1;
+ sprintf(tmp_num,"%d",_cpu->get_number());
+ cpu_data[idx3]=string(tmp_num);
+ idx3+=1;
+ continue;
+ }
+
+ if (first_cpu) {
+ title+=1;
+ cpu_data[idx3]=(string(_cpu->fill_cstate_name(line, buffer)));
+ idx3+=1;
+ first_cpu = false;
+ }
+
+ buffer[0] = 0;
+ tmp_str=string(_cpu->fill_cstate_percentage(line, buffer));
+ cpu_data[idx3]=(tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx3+=1;
+
+ if (line != LEVEL_C0){
+ tmp_str=string(_cpu->fill_cstate_time(line, buffer));
+ cpu_data[idx3]=(tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx3+=1;
+ } else {
+ cpu_data[idx3]="&nbsp;";
+ idx3+=1;
+ }
+ }
+ }
+ first_core = false;
+ }
+
+ /* Report Output */
+ if(core_num > 0)
+ title=title/core_num;
+ else if(_core && _core->children.size() > 0)
+ title=title/_core->children.size();
+
+ init_pkg_table_attr(&std_table_css, pkg_tbl_size.rows, pkg_tbl_size.cols);
+ report.add_table(pkg_data, &std_table_css);
+ if (!_core->can_collapse()){
+ init_core_table_attr(&std_table_css, title+1, core_tbl_size.rows,
+ core_tbl_size.cols);
+ report.add_table(core_data, &std_table_css);
+ }
+ init_cpu_table_attr(&std_table_css, title+1, cpu_tbl_size.rows,
+ cpu_tbl_size.cols);
+ report.add_table(cpu_data, &std_table_css);
+ delete [] pkg_data;
+ delete [] core_data;
+ delete [] cpu_data;
+ }
+ report.end_div();
+}
+
+void report_display_cpu_pstates(void)
+{
+ char buffer[512], buffer2[512], tmp_num[50];
+ unsigned int package, core, cpu;
+ int line, title=0;
+ class abstract_cpu *_package, *_core = NULL, * _cpu;
+ unsigned int i, pstates_num;
+ const char* core_type = NULL;
+
+ /* div attr css_class and css_id */
+ tag_attr div_attr;
+ init_div(&div_attr, "clear_block", "cpufreq");
+
+ /* Set Table attributes, rows, and cols */
+ table_attributes std_table_css;
+ table_size pkg_tbl_size;
+ table_size core_tbl_size;
+ table_size cpu_tbl_size;
+
+
+ /* Set Title attributes */
+ tag_attr title_attr;
+ init_title_attr(&title_attr);
+
+ /* Report add section */
+ report.add_div(&div_attr);
+ report.add_title(&title_attr, __("Processor Frequency Report"));
+
+ /* Set array of data in row Major order */
+ int idx1, idx2, idx3, num_cpus=0, num_cores=0;
+ string tmp_str;
+
+ for (i = 0, pstates_num = 0; i < all_cpus.size(); i++) {
+ if (all_cpus[i])
+ pstates_num = std::max<unsigned int>(pstates_num,
+ all_cpus[i]->pstates.size());
+ }
+
+ for (package = 0; package < system_level.children.size(); package++) {
+ bool first_core = true;
+ idx1=0;
+ idx2=0;
+ idx3=0;
+
+ _package = system_level.children[package];
+ if (!_package)
+ continue;
+
+ /* Tables for PKG, CORE, CPU */
+ pkg_tbl_size.cols=2;
+ pkg_tbl_size.rows=((pstates_num+1)-LEVEL_HEADER)+2;
+ string *pkg_data = new string[pkg_tbl_size.cols * pkg_tbl_size.rows];
+
+ core_tbl_size.cols=2;
+ core_tbl_size.rows=((pstates_num+2) *_package->children.size());
+ string *core_data = new string[core_tbl_size.cols * core_tbl_size.rows];
+
+ /* PKG */
+ num_cpus=0;
+ num_cores=0;
+ for (core = 0; core < _package->children.size(); core++) {
+ _core = _package->children[core];
+ if (!_core)
+ continue;
+
+ core_type = _core->get_type();
+ if (core_type != NULL)
+ if (strcmp(core_type, "Core") == 0 )
+ num_cores+=1;
+
+ for (cpu = 0; cpu < _core->children.size(); cpu++) {
+ _cpu = _core->children[cpu];
+ if (!_cpu)
+ continue;
+ num_cpus+=1;
+ }
+ }
+ cpu_tbl_size.cols= (num_cpus/ num_cores) + 1;
+ cpu_tbl_size.rows= (pstates_num+2) * _package->children.size()
+ + _package->children.size();
+ string *cpu_data = new string[cpu_tbl_size.cols * cpu_tbl_size.rows];
+
+ /* Core */
+ for (core = 0; core < _package->children.size(); core++) {
+ cpu_data[idx3]="&nbsp;";
+ idx3+=1;
+ _core = _package->children[core];
+ if (!_core)
+ continue;
+
+ if (!_core->has_pstates())
+ continue;
+
+ for (line = LEVEL_HEADER; line < (int)pstates_num; line++) {
+ bool first_cpu = true;
+
+ if (!_package->has_pstate_level(line))
+ continue;
+
+ buffer[0] = 0;
+ buffer2[0] = 0;
+ if (first_core) {
+ if (line == LEVEL_HEADER) {
+ pkg_data[idx1]=__("Package");
+ idx1+=1;
+ sprintf(tmp_num,"%d", _package->get_number());
+ pkg_data[idx1]= string(tmp_num);
+ idx1+=1;
+ } else {
+ tmp_str=string(_package->fill_pstate_name(line, buffer));
+ pkg_data[idx1]=(tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx1+=1;
+ tmp_str=string(_package->fill_pstate_line(line, buffer2));
+ pkg_data[idx1]=(tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx1+=1;
+ }
+ }
+
+
+ if (!_core->can_collapse()) {
+ buffer[0] = 0;
+ buffer2[0] = 0;
+ if (line == LEVEL_HEADER) {
+ core_data[idx2]="";
+ idx2+=1;
+ snprintf(tmp_num, sizeof(tmp_num), __("Core %d"), _core->get_number());
+ core_data[idx2]=string(tmp_num);
+ idx2+=1;
+ } else {
+ tmp_str=string(_core->fill_pstate_name(line, buffer));
+ core_data[idx2]= (tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx2+=1;
+ tmp_str=string(_core->fill_pstate_line(line, buffer2));
+ core_data[idx2]= (tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx2+=1;
+ }
+ }
+
+ /* CPU */
+ for (cpu = 0; cpu < _core->children.size(); cpu++) {
+ buffer[0] = 0;
+ _cpu = _core->children[cpu];
+ if (!_cpu)
+ continue;
+
+ if (line == LEVEL_HEADER) {
+ snprintf(tmp_num, sizeof(tmp_num), __("CPU %d"), _cpu->get_number());
+ cpu_data[idx3] = string(tmp_num);
+ idx3+=1;
+ continue;
+ }
+
+ if (first_cpu) {
+ tmp_str=string(_cpu->fill_pstate_name(line, buffer));
+ cpu_data[idx3]=(tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx3+=1;
+ first_cpu = false;
+ }
+
+ buffer[0] = 0;
+ tmp_str=string(_cpu->fill_pstate_line(line, buffer));
+ cpu_data[idx3]=(tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx3+=1;
+ }
+ }
+ first_core = false;
+ }
+ init_pkg_table_attr(&std_table_css, pkg_tbl_size.rows, pkg_tbl_size.cols);
+ report.add_table(pkg_data, &std_table_css);
+ if(_core && !_core->can_collapse()){
+ title=pstates_num+2;
+ init_core_table_attr(&std_table_css, title,
+ core_tbl_size.rows, core_tbl_size.cols);
+ report.add_table(core_data, &std_table_css);
+ } else {
+ title=pstates_num+1;
+ }
+
+ init_cpu_table_attr(&std_table_css, title,
+ cpu_tbl_size.rows, cpu_tbl_size.cols);
+ report.add_table(cpu_data, &std_table_css);
+ delete [] pkg_data;
+ delete [] core_data;
+ delete [] cpu_data;
+ }
+ report.end_div();
+}
+
+void impl_w_display_cpu_states(int state)
+{
+ WINDOW *win;
+ char buffer[128];
+ char linebuf[1024];
+ unsigned int package, core, cpu;
+ int line, loop, cstates_num, pstates_num;
+ class abstract_cpu *_package, * _core, * _cpu;
+ int ctr = 0;
+ unsigned int i;
+
+ cstates_num = get_cstates_num();
+
+ for (i = 0, pstates_num = 0; i < all_cpus.size(); i++) {
+ if (!all_cpus[i])
+ continue;
+
+ pstates_num = std::max<int>(pstates_num, all_cpus[i]->pstates.size());
+ }
+
+ if (state == PSTATE) {
+ win = get_ncurses_win("Frequency stats");
+ loop = pstates_num;
+ } else {
+ win = get_ncurses_win("Idle stats");
+ loop = cstates_num;
+ }
+
+ if (!win)
+ return;
+
+ wclear(win);
+ wmove(win, 2,0);
+
+ for (package = 0; package < system_level.children.size(); package++) {
+ int first_pkg = 0;
+ _package = system_level.children[package];
+ if (!_package)
+ continue;
+
+ for (core = 0; core < _package->children.size(); core++) {
+ _core = _package->children[core];
+ if (!_core)
+ continue;
+ if (!_core->has_pstates() && state == PSTATE)
+ continue;
+
+ for (line = LEVEL_HEADER; line <= loop; line++) {
+ int first = 1;
+ ctr = 0;
+ linebuf[0] = 0;
+
+ if (!has_state_level(_package, state, line))
+ continue;
+
+ buffer[0] = 0;
+ if (first_pkg == 0) {
+ strcat(linebuf, fill_state_name(_package, state, line, buffer));
+ expand_string(linebuf, ctr + 10);
+ strcat(linebuf, fill_state_line(_package, state, line, buffer));
+ }
+ ctr += 20;
+ expand_string(linebuf, ctr);
+
+ strcat(linebuf, "| ");
+ ctr += strlen("| ");
+
+ if (!_core->can_collapse()) {
+ buffer[0] = 0;
+ strcat(linebuf, fill_state_name(_core, state, line, buffer));
+ expand_string(linebuf, ctr + 10);
+ strcat(linebuf, fill_state_line(_core, state, line, buffer));
+ ctr += 20;
+ expand_string(linebuf, ctr);
+
+ strcat(linebuf, "| ");
+ ctr += strlen("| ");
+ }
+
+ for (cpu = 0; cpu < _core->children.size(); cpu++) {
+ _cpu = _core->children[cpu];
+ if (!_cpu)
+ continue;
+
+ if (first == 1) {
+ strcat(linebuf, fill_state_name(_cpu, state, line, buffer));
+ expand_string(linebuf, ctr + 10);
+ first = 0;
+ ctr += 12;
+ }
+ buffer[0] = 0;
+ strcat(linebuf, fill_state_line(_cpu, state, line, buffer));
+ ctr += 10;
+ expand_string(linebuf, ctr);
+
+ }
+ strcat(linebuf, "\n");
+ wprintw(win, "%s", linebuf);
+ }
+ wprintw(win, "\n");
+ first_pkg++;
+ }
+ }
+}
+
+void w_display_cpu_pstates(void)
+{
+ impl_w_display_cpu_states(PSTATE);
+}
+
+void w_display_cpu_cstates(void)
+{
+ impl_w_display_cpu_states(CSTATE);
+}
+
+struct power_entry {
+#ifndef __i386__
+ int dummy;
+#endif
+ int64_t type;
+ int64_t value;
+} __attribute__((packed));
+
+
+void perf_power_bundle::handle_trace_point(void *trace, int cpunr, uint64_t time)
+{
+ struct event_format *event;
+ struct pevent_record rec; /* holder */
+ class abstract_cpu *cpu;
+ int type;
+
+ rec.data = trace;
+
+ type = pevent_data_type(perf_event::pevent, &rec);
+ event = pevent_find_event(perf_event::pevent, type);
+
+ if (!event)
+ return;
+
+ if (cpunr >= (int)all_cpus.size()) {
+ cout << "INVALID cpu nr in handle_trace_point\n";
+ return;
+ }
+
+ cpu = all_cpus[cpunr];
+
+#if 0
+ unsigned int i;
+ printf("Time is %llu \n", time);
+ for (i = 0; i < system_level.children.size(); i++)
+ if (system_level.children[i])
+ system_level.children[i]->validate();
+#endif
+ unsigned long long val;
+ int ret;
+ if (strcmp(event->name, "cpu_idle")==0) {
+
+ ret = pevent_get_field_val(NULL, event, "state", &rec, &val, 0);
+ if (ret < 0) {
+ fprintf(stderr, _("cpu_idle event returned no state?\n"));
+ exit(-1);
+ }
+
+ if (val == (unsigned int)-1)
+ cpu->go_unidle(time);
+ else
+ cpu->go_idle(time);
+ }
+
+ if (strcmp(event->name, "power_frequency") == 0
+ || strcmp(event->name, "cpu_frequency") == 0){
+
+ ret = pevent_get_field_val(NULL, event, "state", &rec, &val, 0);
+ if (ret < 0) {
+ fprintf(stderr, _("power or cpu_frequency event returned no state?\n"));
+ exit(-1);
+ }
+
+ cpu->change_freq(time, val);
+ }
+
+ if (strcmp(event->name, "power_start")==0)
+ cpu->go_idle(time);
+ if (strcmp(event->name, "power_end")==0)
+ cpu->go_unidle(time);
+
+#if 0
+ unsigned int i;
+ for (i = 0; i < system_level.children.size(); i++)
+ if (system_level.children[i])
+ system_level.children[i]->validate();
+#endif
+}
+
+void process_cpu_data(void)
+{
+ unsigned int i;
+ system_level.reset_pstate_data();
+
+ perf_events->process();
+
+ for (i = 0; i < system_level.children.size(); i++)
+ if (system_level.children[i])
+ system_level.children[i]->validate();
+
+}
+
+void end_cpu_data(void)
+{
+ system_level.reset_pstate_data();
+
+ perf_events->clear();
+}
+
+void clear_cpu_data(void)
+{
+ if (perf_events)
+ perf_events->release();
+ delete perf_events;
+}
+
+
+void clear_all_cpus(void)
+{
+ unsigned int i;
+ for (i = 0; i < all_cpus.size(); i++) {
+ delete all_cpus[i];
+ }
+ all_cpus.clear();
+}
diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h
new file mode 100644
index 0000000..9114764
--- /dev/null
+++ b/src/cpu/cpu.h
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#ifndef __INCLUDE_GUARD_CPUDEV_H
+#define __INCLUDE_GUARD_CPUDEV_H
+
+#include <iostream>
+#include <vector>
+#include <string>
+#include <stdint.h>
+#include <sys/time.h>
+
+using namespace std;
+
+class abstract_cpu;
+
+#define LEVEL_C0 -1
+#define LEVEL_HEADER -2
+
+#define PSTATE 1
+#define CSTATE 2
+
+struct idle_state {
+ char linux_name[16]; /* state0 etc.. cpuidle name */
+ char human_name[32];
+
+ uint64_t usage_before;
+ uint64_t usage_after;
+ uint64_t usage_delta;
+
+ uint64_t duration_before;
+ uint64_t duration_after;
+ uint64_t duration_delta;
+
+ int before_count;
+ int after_count;
+
+ int line_level;
+};
+
+struct frequency {
+ char human_name[32];
+ int line_level;
+
+ uint64_t freq;
+
+ uint64_t time_after;
+ uint64_t time_before;
+
+ int before_count;
+ int after_count;
+
+ double display_value;
+};
+
+class abstract_cpu
+{
+protected:
+ int first_cpu;
+ struct timeval stamp_before, stamp_after;
+ double time_factor;
+ uint64_t max_frequency = 0;
+ uint64_t max_minus_one_frequency = 0;
+
+ virtual void account_freq(uint64_t frequency, uint64_t duration);
+ virtual void freq_updated(uint64_t time);
+
+public:
+ uint64_t last_stamp;
+ uint64_t total_stamp;
+ int number;
+ int childcount;
+ const char* name;
+ bool idle, old_idle, has_intel_MSR;
+ uint64_t current_frequency;
+ uint64_t effective_frequency;
+
+ vector<class abstract_cpu *> children;
+ vector<struct idle_state *> cstates;
+ vector<struct frequency *> pstates;
+
+ virtual ~abstract_cpu();
+
+ class abstract_cpu *parent;
+
+
+ int get_first_cpu() { return first_cpu; }
+ void set_number(int _number, int cpu) {this->number = _number; this->first_cpu = cpu;};
+ void set_intel_MSR(bool _bool_value) {this->has_intel_MSR = _bool_value;};
+ void set_type(const char* _name) {this->name = _name;};
+ int get_number(void) { return number; };
+ const char* get_type(void) { return name; };
+
+ virtual void measurement_start(void);
+ virtual void measurement_end(void);
+
+ virtual int can_collapse(void) { return 0;};
+
+
+ /* C state related methods */
+
+ void insert_cstate(const char *linux_name, const char *human_name, uint64_t usage, uint64_t duration, int count, int level = -1);
+ void update_cstate(const char *linux_name, const char *human_name, uint64_t usage, uint64_t duration, int count, int level = -1);
+ void finalize_cstate(const char *linux_name, uint64_t usage, uint64_t duration, int count);
+
+ virtual int has_cstate_level(int level);
+
+ virtual char * fill_cstate_line(int line_nr, char *buffer, const char *separator="") { return buffer;};
+ virtual char * fill_cstate_percentage(int line_nr, char *buffer) { return buffer; };
+ virtual char * fill_cstate_time(int line_nr, char *buffer) { return buffer; };
+ virtual char * fill_cstate_name(int line_nr, char *buffer) { return buffer;};
+
+
+ /* P state related methods */
+ void insert_pstate(uint64_t freq, const char *human_name, uint64_t duration, int count);
+ void update_pstate(uint64_t freq, const char *human_name, uint64_t duration, int count);
+ void finalize_pstate(uint64_t freq, uint64_t duration, int count);
+
+
+ virtual char * fill_pstate_line(int line_nr, char *buffer) { return buffer;};
+ virtual char * fill_pstate_name(int line_nr, char *buffer) { return buffer;};
+ virtual int has_pstate_level(int level);
+ virtual int has_pstates(void) { return 1; };
+
+ /* Frequency micro accounting methods */
+ virtual void calculate_freq(uint64_t time);
+ virtual void go_idle(uint64_t time) { idle = true; freq_updated(time); }
+ virtual void go_unidle(uint64_t time) { idle = false; freq_updated(time); }
+ virtual void change_freq(uint64_t time, int freq) { current_frequency = freq; freq_updated(time); }
+
+ virtual void change_effective_frequency(uint64_t time, uint64_t freq);
+
+ virtual void wiggle(void);
+
+ virtual uint64_t total_pstate_time(void);
+
+ virtual void validate(void);
+ virtual void reset_pstate_data(void);
+};
+
+extern vector<class abstract_cpu *> all_cpus;
+
+class cpu_linux: public abstract_cpu
+{
+ void parse_pstates_start(void);
+ void parse_cstates_start(void);
+ void parse_pstates_end(void);
+ void parse_cstates_end(void);
+
+public:
+ virtual void measurement_start(void);
+ virtual void measurement_end(void);
+
+ virtual char * fill_cstate_line(int line_nr, char *buffer, const char *separator="");
+ virtual char * fill_cstate_name(int line_nr, char *buffer);
+ virtual char * fill_cstate_percentage(int line_nr, char *buffer);
+ virtual char * fill_cstate_time(int line_nr, char *buffer);
+
+ virtual char * fill_pstate_line(int line_nr, char *buffer);
+ virtual char * fill_pstate_name(int line_nr, char *buffer);
+};
+
+class cpu_core: public abstract_cpu
+{
+public:
+ virtual char * fill_cstate_line(int line_nr, char *buffer, const char *separator="");
+ virtual char * fill_cstate_name(int line_nr, char *buffer);
+
+ virtual char * fill_pstate_line(int line_nr, char *buffer);
+ virtual char * fill_pstate_name(int line_nr, char *buffer);
+
+ virtual int can_collapse(void) { return childcount == 1;};
+};
+
+class cpu_package: public abstract_cpu
+{
+protected:
+ virtual void freq_updated(uint64_t time);
+public:
+ virtual char * fill_cstate_line(int line_nr, char *buffer, const char *separator="");
+ virtual char * fill_cstate_name(int line_nr, char *buffer);
+
+ virtual char * fill_pstate_line(int line_nr, char *buffer);
+ virtual char * fill_pstate_name(int line_nr, char *buffer);
+ virtual int can_collapse(void) { return childcount == 1;};
+};
+
+extern void enumerate_cpus(void);
+
+extern void report_display_cpu_pstates(void);
+extern void report_display_cpu_cstates(void);
+
+
+
+extern void display_cpu_cstates(const char *start= "",
+ const char *end = "",
+ const char *linestart = "",
+ const char *separator = "| ",
+ const char *lineend = "\n");
+
+extern void w_display_cpu_cstates(void);
+extern void w_display_cpu_pstates(void);
+
+
+extern void start_cpu_measurement(void);
+extern void end_cpu_measurement(void);
+extern void process_cpu_data(void);
+extern void end_cpu_data(void);
+extern void clear_cpu_data(void);
+extern void clear_all_cpus(void);
+
+#endif
diff --git a/src/cpu/cpu_core.cpp b/src/cpu/cpu_core.cpp
new file mode 100644
index 0000000..e1372f7
--- /dev/null
+++ b/src/cpu/cpu_core.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <stdio.h>
+#include "cpu.h"
+#include "../lib.h"
+
+#include "../parameters/parameters.h"
+
+char * cpu_core::fill_cstate_line(int line_nr, char *buffer, const char *separator)
+{
+ unsigned int i;
+ buffer[0] = 0;
+
+ if (line_nr == LEVEL_HEADER)
+ sprintf(buffer, this->has_intel_MSR ? _(" Core(HW)"): _(" Core(OS)"));
+
+ for (i = 0; i < cstates.size(); i++) {
+ if (cstates[i]->line_level != line_nr)
+ continue;
+ sprintf(buffer,"%5.1f%%", percentage(cstates[i]->duration_delta / time_factor));
+ }
+
+ return buffer;
+}
+
+
+char * cpu_core::fill_cstate_name(int line_nr, char *buffer)
+{
+ unsigned int i;
+ buffer[0] = 0;
+
+ for (i = 0; i < cstates.size(); i++) {
+ if (cstates[i]->line_level != line_nr)
+ continue;
+
+ sprintf(buffer,"%s", cstates[i]->human_name);
+ }
+
+ return buffer;
+}
+
+
+
+char * cpu_core::fill_pstate_name(int line_nr, char *buffer)
+{
+ buffer[0] = 0;
+
+ if (line_nr >= (int)pstates.size() || line_nr < 0)
+ return buffer;
+
+ sprintf(buffer,"%s", pstates[line_nr]->human_name);
+
+ return buffer;
+}
+
+char * cpu_core::fill_pstate_line(int line_nr, char *buffer)
+{
+ buffer[0] = 0;
+ unsigned int i;
+
+ if (total_stamp ==0) {
+ for (i = 0; i < pstates.size(); i++)
+ total_stamp += pstates[i]->time_after;
+ if (total_stamp == 0)
+ total_stamp = 1;
+ }
+
+ if (line_nr == LEVEL_HEADER) {
+ sprintf(buffer,_(" Core"));
+ return buffer;
+ }
+
+ if (line_nr >= (int)pstates.size() || line_nr < 0)
+ return buffer;
+
+ sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after) / total_stamp));
+ return buffer;
+}
diff --git a/src/cpu/cpu_linux.cpp b/src/cpu/cpu_linux.cpp
new file mode 100644
index 0000000..d7ce93d
--- /dev/null
+++ b/src/cpu/cpu_linux.cpp
@@ -0,0 +1,350 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+
+#include "cpu.h"
+#include "../lib.h"
+
+#include <stdlib.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+void cpu_linux::parse_cstates_start(void)
+{
+ ifstream file;
+ DIR *dir;
+ struct dirent *entry;
+ char filename[256];
+ int len;
+
+ len = snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpuidle", number);
+
+ dir = opendir(filename);
+ if (!dir)
+ return;
+
+ /* For each C-state, there is a stateX directory which
+ * contains a 'usage' and a 'time' (duration) file */
+ while ((entry = readdir(dir))) {
+ char linux_name[64];
+ char human_name[64];
+ uint64_t usage = 0;
+ uint64_t duration = 0;
+
+
+ if (strlen(entry->d_name) < 3)
+ continue;
+
+ pt_strcpy(linux_name, entry->d_name);
+ pt_strcpy(human_name, linux_name);
+
+ snprintf(filename + len, sizeof(filename) - len, "/%s/name", entry->d_name);
+
+ file.open(filename, ios::in);
+ if (file) {
+ file.getline(human_name, sizeof(human_name));
+ file.close();
+ }
+
+ if (strcmp(human_name, "C0")==0)
+ pt_strcpy(human_name, _("C0 polling"));
+
+ snprintf(filename + len, sizeof(filename) - len, "/%s/usage", entry->d_name);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> usage;
+ file.close();
+ } else
+ continue;
+
+ snprintf(filename + len, sizeof(filename) - len, "/%s/time", entry->d_name);
+
+ file.open(filename, ios::in);
+ if (file) {
+ file >> duration;
+ file.close();
+ }
+
+
+ update_cstate(linux_name, human_name, usage, duration, 1);
+
+ }
+ closedir(dir);
+}
+
+
+void cpu_linux::parse_pstates_start(void)
+{
+ ifstream file;
+ char filename[256];
+ unsigned int i;
+
+ last_stamp = 0;
+ for (i = 0; i < children.size(); i++)
+ if (children[i])
+ children[i]->wiggle();
+
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpufreq/stats/time_in_state", first_cpu);
+
+ file.open(filename, ios::in);
+
+ if (file) {
+ char line[1024];
+
+ while (file) {
+ uint64_t f;
+ file.getline(line, sizeof(line));
+ f = strtoull(line, NULL, 10);
+ account_freq(f, 0);
+ }
+ file.close();
+ }
+ account_freq(0, 0);
+}
+
+void cpu_linux::measurement_start(void)
+{
+ abstract_cpu::measurement_start();
+ parse_cstates_start();
+ parse_pstates_start();
+}
+
+void cpu_linux::parse_cstates_end(void)
+{
+ DIR *dir;
+ struct dirent *entry;
+ char filename[256];
+ ifstream file;
+ int len;
+
+ len = snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpuidle", number);
+
+ dir = opendir(filename);
+ if (!dir)
+ return;
+
+ /* For each C-state, there is a stateX directory which
+ * contains a 'usage' and a 'time' (duration) file */
+ while ((entry = readdir(dir))) {
+ char linux_name[64];
+ char human_name[64];
+ uint64_t usage = 0;
+ uint64_t duration = 0;
+
+
+ if (strlen(entry->d_name) < 3)
+ continue;
+
+ pt_strcpy(linux_name, entry->d_name);
+ pt_strcpy(human_name, linux_name);
+
+
+ snprintf(filename + len, sizeof(filename) - len, "/%s/usage", entry->d_name);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> usage;
+ file.close();
+ } else
+ continue;
+
+ snprintf(filename + len, sizeof(filename) - len, "/%s/time", entry->d_name);
+
+ file.open(filename, ios::in);
+ if (file) {
+ file >> duration;
+ file.close();
+ }
+
+
+ finalize_cstate(linux_name, usage, duration, 1);
+
+ }
+ closedir(dir);
+}
+
+void cpu_linux::parse_pstates_end(void)
+{
+ char filename[256];
+ ifstream file;
+
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpufreq/stats/time_in_state", number);
+
+ file.open(filename, ios::in);
+
+ if (file) {
+ char line[1024];
+
+ while (file) {
+ uint64_t f,count;
+ char *c;
+
+ memset(line, 0, sizeof(line));
+
+ file.getline(line, sizeof(line));
+
+ f = strtoull(line, &c, 10);
+ if (!c)
+ break;
+
+ count = strtoull(c, NULL, 10);
+
+ if (f > 0)
+ finalize_pstate(f, count, 1);
+
+
+ }
+ file.close();
+ }
+}
+
+void cpu_linux::measurement_end(void)
+{
+ parse_cstates_end();
+ parse_pstates_end();
+ abstract_cpu::measurement_end();
+}
+
+char * cpu_linux::fill_cstate_line(int line_nr, char *buffer, const char *separator)
+{
+ unsigned int i;
+ buffer[0] = 0;
+
+ if (line_nr == LEVEL_HEADER) {
+ sprintf(buffer,_(" CPU(OS) %i"), number);
+ return buffer;
+ }
+
+ for (i = 0; i < cstates.size(); i++) {
+ if (cstates[i]->line_level != line_nr)
+ continue;
+
+ if (line_nr == LEVEL_C0)
+ sprintf(buffer,"%5.1f%%", percentage(cstates[i]->duration_delta / time_factor));
+ else
+ sprintf(buffer,"%5.1f%%%s %6.1f ms",
+ percentage(cstates[i]->duration_delta / time_factor),
+ separator,
+ 1.0 * cstates[i]->duration_delta / (1 + cstates[i]->usage_delta) / 1000);
+ }
+
+ return buffer;
+}
+
+char * cpu_linux::fill_cstate_percentage(int line_nr, char *buffer)
+{
+ unsigned int i;
+ buffer[0] = 0;
+
+ for (i = 0; i < cstates.size(); i++) {
+ if (cstates[i]->line_level != line_nr)
+ continue;
+
+ sprintf(buffer,"%5.1f%%",
+ percentage(cstates[i]->duration_delta / time_factor));
+ break;
+ }
+
+ return buffer;
+}
+
+char * cpu_linux::fill_cstate_time(int line_nr, char *buffer)
+{
+ unsigned int i;
+ buffer[0] = 0;
+
+ if (line_nr == LEVEL_C0)
+ return buffer;
+
+ for (i = 0; i < cstates.size(); i++) {
+ if (cstates[i]->line_level != line_nr)
+ continue;
+
+ sprintf(buffer,"%6.1f ms",
+ 1.0 * cstates[i]->duration_delta /
+ (1 + cstates[i]->usage_delta) / 1000);
+ break;
+ }
+
+ return buffer;
+}
+
+char * cpu_linux::fill_cstate_name(int line_nr, char *buffer)
+{
+ unsigned int i;
+ buffer[0] = 0;
+
+ for (i = 0; i < cstates.size(); i++) {
+ if (cstates[i]->line_level != line_nr)
+ continue;
+
+ sprintf(buffer,"%s", cstates[i]->human_name);
+ }
+
+ return buffer;
+}
+
+
+char * cpu_linux::fill_pstate_name(int line_nr, char *buffer)
+{
+ buffer[0] = 0;
+
+ if (line_nr >= (int)pstates.size() || line_nr < 0)
+ return buffer;
+
+ sprintf(buffer,"%s", pstates[line_nr]->human_name);
+
+ return buffer;
+}
+
+char * cpu_linux::fill_pstate_line(int line_nr, char *buffer)
+{
+ buffer[0] = 0;
+
+ if (total_stamp ==0) {
+ unsigned int i;
+ for (i = 0; i < pstates.size(); i++)
+ total_stamp += pstates[i]->time_after;
+ if (total_stamp == 0)
+ total_stamp = 1;
+ }
+
+ if (line_nr == LEVEL_HEADER) {
+ sprintf(buffer,_(" CPU %i"), number);
+ return buffer;
+ }
+
+ if (line_nr >= (int)pstates.size() || line_nr < 0)
+ return buffer;
+
+ sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after) / total_stamp));
+ return buffer;
+}
diff --git a/src/cpu/cpu_package.cpp b/src/cpu/cpu_package.cpp
new file mode 100644
index 0000000..926a484
--- /dev/null
+++ b/src/cpu/cpu_package.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <stdio.h>
+#include "cpu.h"
+#include "../lib.h"
+#include "../parameters/parameters.h"
+
+void cpu_package::freq_updated(uint64_t time)
+{
+ if (parent)
+ parent->calculate_freq(time);
+ /*
+ * Make the frequency changes to propagate to all cores in a package.
+ */
+ change_effective_frequency(time, current_frequency);
+ old_idle = idle;
+}
+
+char * cpu_package::fill_cstate_line(int line_nr, char *buffer, const char *separator)
+{
+ unsigned int i;
+ buffer[0] = 0;
+
+ if (line_nr == LEVEL_HEADER) {
+ sprintf(buffer, this->has_intel_MSR ? _(" Pkg(HW)"): _(" Pkg(OS)"));
+ }
+
+ for (i = 0; i < cstates.size(); i++) {
+ if (cstates[i]->line_level != line_nr)
+ continue;
+
+ sprintf(buffer,"%5.1f%%", percentage(cstates[i]->duration_delta / time_factor));
+ }
+
+ return buffer;
+}
+
+
+char * cpu_package::fill_cstate_name(int line_nr, char *buffer)
+{
+ unsigned int i;
+ buffer[0] = 0;
+
+ for (i = 0; i < cstates.size(); i++) {
+ if (cstates[i]->line_level != line_nr)
+ continue;
+
+ sprintf(buffer,"%s", cstates[i]->human_name);
+ }
+
+ return buffer;
+}
+
+
+
+char * cpu_package::fill_pstate_name(int line_nr, char *buffer)
+{
+ buffer[0] = 0;
+
+ if (line_nr >= (int)pstates.size() || line_nr < 0)
+ return buffer;
+
+ sprintf(buffer,"%s", pstates[line_nr]->human_name);
+
+ return buffer;
+}
+
+char * cpu_package::fill_pstate_line(int line_nr, char *buffer)
+{
+ buffer[0] = 0;
+ unsigned int i;
+
+ if (total_stamp ==0) {
+ for (i = 0; i < pstates.size(); i++)
+ total_stamp += pstates[i]->time_after;
+ if (total_stamp == 0)
+ total_stamp = 1;
+ }
+
+
+ if (line_nr == LEVEL_HEADER) {
+ sprintf(buffer,_(" Package"));
+ return buffer;
+ }
+
+ if (line_nr >= (int)pstates.size() || line_nr < 0)
+ return buffer;
+
+ sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after) / total_stamp));
+ return buffer;
+}
diff --git a/src/cpu/cpu_rapl_device.cpp b/src/cpu/cpu_rapl_device.cpp
new file mode 100644
index 0000000..357a1c8
--- /dev/null
+++ b/src/cpu/cpu_rapl_device.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Srinivas Pandruvada<Srinivas.Pandruvada@linux.intel.com>
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "../parameters/parameters.h"
+#include "cpu_rapl_device.h"
+
+cpu_rapl_device::cpu_rapl_device(cpudevice *parent, const char *classname, const char *dev_name, class abstract_cpu *_cpu)
+ : cpudevice(classname, dev_name, _cpu),
+ device_valid(false)
+{
+ if (_cpu)
+ rapl = new c_rapl_interface(dev_name, cpu->get_first_cpu());
+ else
+ rapl = new c_rapl_interface();
+ last_time = time(NULL);
+ if (rapl->pp0_domain_present()) {
+ device_valid = true;
+ parent->add_child(this);
+ rapl->get_pp0_energy_status(&last_energy);
+ }
+}
+
+void cpu_rapl_device::start_measurement(void)
+{
+ last_time = time(NULL);
+
+ rapl->get_pp0_energy_status(&last_energy);
+}
+
+void cpu_rapl_device::end_measurement(void)
+{
+ time_t curr_time = time(NULL);
+ double energy;
+
+ consumed_power = 0.0;
+ if ((curr_time - last_time) > 0) {
+ rapl->get_pp0_energy_status(&energy);
+ consumed_power = (energy-last_energy)/(curr_time-last_time);
+ last_energy = energy;
+ last_time = curr_time;
+ }
+}
+
+double cpu_rapl_device::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+ if (rapl->pp0_domain_present())
+ return consumed_power;
+ else
+ return 0.0;
+}
diff --git a/src/cpu/cpu_rapl_device.h b/src/cpu/cpu_rapl_device.h
new file mode 100644
index 0000000..407f2da
--- /dev/null
+++ b/src/cpu/cpu_rapl_device.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Srinivas Pandruvada <Srinivas.Pandruvada@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_CPU_RAPL_DEVICE_H
+#define _INCLUDE_GUARD_CPU_RAPL_DEVICE_H
+
+#include <vector>
+#include <string>
+
+using namespace std;
+
+#include <sys/time.h>
+#include "cpudevice.h"
+#include "rapl/rapl_interface.h"
+
+class cpu_rapl_device: public cpudevice {
+
+ c_rapl_interface *rapl;
+ time_t last_time;
+ double last_energy;
+ double consumed_power;
+ bool device_valid;
+
+public:
+ cpu_rapl_device(cpudevice *parent, const char *classname = "cpu_core", const char *device_name = "cpu_core", class abstract_cpu *_cpu = NULL);
+ ~cpu_rapl_device() { delete rapl; }
+ virtual const char * device_name(void) {return "CPU core";};
+ bool device_present() { return device_valid;}
+ virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+ virtual void start_measurement(void);
+ virtual void end_measurement(void);
+
+};
+
+
+#endif
diff --git a/src/cpu/cpudevice.cpp b/src/cpu/cpudevice.cpp
new file mode 100644
index 0000000..4c7ca7b
--- /dev/null
+++ b/src/cpu/cpudevice.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "cpudevice.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "../lib.h"
+#include "../parameters/parameters.h"
+
+
+cpudevice::cpudevice(const char *classname, const char *dev_name, class abstract_cpu *_cpu)
+{
+ pt_strcpy(_class, classname);
+ pt_strcpy(_cpuname, dev_name);
+ cpu = _cpu;
+ wake_index = get_param_index("cpu-wakeups");;
+ consumption_index = get_param_index("cpu-consumption");;
+ r_wake_index = get_result_index("cpu-wakeups");;
+ r_consumption_index = get_result_index("cpu-consumption");;
+}
+
+const char * cpudevice::device_name(void)
+{
+ if (child_devices.size())
+ return "CPU misc";
+ else
+ return "CPU use";
+}
+
+double cpudevice::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+ double power;
+ double factor;
+ double _utilization;
+ double child_power;
+
+ power = 0;
+ factor = get_parameter_value(wake_index, bundle);
+ _utilization = get_result_value(r_wake_index, result);
+
+ power += _utilization * factor / 10000.0;
+
+ factor = get_parameter_value(consumption_index, bundle);
+ _utilization = get_result_value(r_consumption_index, result);
+
+ power += _utilization * factor;
+
+ for (unsigned int i = 0; i < child_devices.size(); ++i) {
+ child_power = child_devices[i]->power_usage(result, bundle);
+ if ((power - child_power) > 0.0)
+ power -= child_power;
+ }
+
+ return power;
+}
+
+double cpudevice::utilization(void)
+{
+ double _utilization;
+ _utilization = get_result_value(r_consumption_index);
+
+ return _utilization * 100;
+
+}
diff --git a/src/cpu/cpudevice.h b/src/cpu/cpudevice.h
new file mode 100644
index 0000000..841a101
--- /dev/null
+++ b/src/cpu/cpudevice.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_CPUDEVICE_H
+#define _INCLUDE_GUARD_CPUDEVICE_H
+
+#include <vector>
+#include <string>
+
+using namespace std;
+
+#include "../devices/device.h"
+#include "cpu.h"
+
+class cpudevice: public device {
+protected:
+ char _class[128];
+ char _cpuname[128];
+
+ vector<string> params;
+ class abstract_cpu *cpu;
+ int wake_index;
+ int consumption_index;
+ int r_wake_index;
+ int r_consumption_index;
+
+ vector<device *>child_devices;
+
+public:
+ cpudevice(const char *classname = "cpu", const char *device_name = "cpu0", class abstract_cpu *_cpu = NULL);
+ virtual const char * class_name(void) { return _class;};
+
+ virtual const char * device_name(void);
+
+ virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+ virtual bool show_in_list(void) {return false;};
+ virtual double utilization(void); /* percentage */
+ void add_child(device *dev_ptr) { child_devices.push_back(dev_ptr);}
+};
+
+
+#endif \ No newline at end of file
diff --git a/src/cpu/dram_rapl_device.cpp b/src/cpu/dram_rapl_device.cpp
new file mode 100644
index 0000000..36d47a2
--- /dev/null
+++ b/src/cpu/dram_rapl_device.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Srinivas Pandruvada <Srinivas.Pandruvada@linux.intel.com>
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "../parameters/parameters.h"
+#include "dram_rapl_device.h"
+
+
+dram_rapl_device::dram_rapl_device(cpudevice *parent, const char *classname, const char *dev_name, class abstract_cpu *_cpu)
+ : cpudevice(classname, dev_name, _cpu),
+ device_valid(false)
+{
+ if (_cpu)
+ rapl = new c_rapl_interface(dev_name, cpu->get_first_cpu());
+ else
+ rapl = new c_rapl_interface();
+ last_time = time(NULL);
+ if (rapl->dram_domain_present()) {
+ device_valid = true;
+ parent->add_child(this);
+ rapl->get_dram_energy_status(&last_energy);
+ }
+}
+
+void dram_rapl_device::start_measurement(void)
+{
+ last_time = time(NULL);
+
+ rapl->get_dram_energy_status(&last_energy);
+}
+
+void dram_rapl_device::end_measurement(void)
+{
+ time_t curr_time = time(NULL);
+ double energy;
+
+ consumed_power = 0.0;
+ if ((curr_time - last_time) > 0) {
+ rapl->get_dram_energy_status(&energy);
+ consumed_power = (energy-last_energy)/(curr_time-last_time);
+ last_energy = energy;
+ last_time = curr_time;
+ }
+}
+
+double dram_rapl_device::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+ if (rapl->dram_domain_present())
+ return consumed_power;
+ else
+ return 0.0;
+}
diff --git a/src/cpu/dram_rapl_device.h b/src/cpu/dram_rapl_device.h
new file mode 100644
index 0000000..dc53094
--- /dev/null
+++ b/src/cpu/dram_rapl_device.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Srinivas Pandruvada <Srinivas.Pandruvada@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_DRAM_RAPL_DEVICE_H
+#define _INCLUDE_GUARD_DRAM_RAPL_DEVICE_H
+
+#include <vector>
+#include <string>
+
+using namespace std;
+
+#include <sys/time.h>
+#include "cpudevice.h"
+#include "rapl/rapl_interface.h"
+
+class dram_rapl_device: public cpudevice {
+
+ c_rapl_interface *rapl;
+ time_t last_time;
+ double last_energy;
+ double consumed_power;
+ bool device_valid;
+
+public:
+ dram_rapl_device(cpudevice *parent, const char *classname = "dram_core", const char *device_name = "dram_core", class abstract_cpu *_cpu = NULL);
+ ~dram_rapl_device() { delete rapl; }
+ virtual const char * device_name(void) {return "DRAM";};
+ bool device_present() { return device_valid;}
+ virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+ void start_measurement(void);
+ void end_measurement(void);
+
+};
+
+
+#endif
diff --git a/src/cpu/intel_cpus.cpp b/src/cpu/intel_cpus.cpp
new file mode 100644
index 0000000..a7145d7
--- /dev/null
+++ b/src/cpu/intel_cpus.cpp
@@ -0,0 +1,757 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "intel_cpus.h"
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "../lib.h"
+#include "../parameters/parameters.h"
+#include "../display.h"
+
+static int intel_cpu_models[] = {
+ 0x1A, /* Core i7, Xeon 5500 series */
+ 0x1E, /* Core i7 and i5 Processor - Lynnfield Jasper Forest */
+ 0x1F, /* Core i7 and i5 Processor - Nehalem */
+ 0x25, /* Westmere */
+ 0x27, /* Medfield Atom */
+ 0x2A, /* SNB */
+ 0x2C, /* Westmere */
+ 0x2D, /* SNB Xeon */
+ 0x2E, /* Nehalem-EX Xeon */
+ 0x2F, /* Westmere-EX Xeon */
+ 0x37, /* BYT-M */
+ 0x3A, /* IVB */
+ 0x3C, /* HSW */
+ 0x3D, /* BDW */
+ 0x3E, /* IVB Xeon */
+ 0x3F, /* HSX */
+ 0x45, /* HSW-ULT */
+ 0x46, /* HSW-G */
+ 0x47, /* BDW-H */
+ 0x4C, /* BSW */
+ 0x4D, /* AVN */
+ 0x4F, /* BDX */
+ 0x4E, /* SKY */
+ 0x55, /* SKY-X */
+ 0x56, /* BDX-DE */
+ 0x5C, /* BXT-P */
+ 0x5E, /* SKY */
+ 0x5F, /* DNV */
+ 0x66, /* CNL-U/Y */
+ 0x6A, /* ICL_X*/
+ 0x7A, /* GLK */
+ 0x7D, /* ICL_DESKTOP */
+ 0x7E, /* ICL_MOBILE */
+ 0x8A, /* LKF */
+ 0x8C, /* TGL_MOBILE */
+ 0x8D, /* TGL_DESKTOP */
+ 0x8E, /* KBL_MOBILE */
+ 0X8F, /* SAPPHIRERAPIDS_X */
+ 0x96, /* EHL */
+ 0x97, /* ADL_DESKTOP */
+ 0x9A, /* ADL_MOBILE */
+ 0x9C, /* JSL */
+ 0x9D, /* ICL_NNPI */
+ 0x9E, /* KBL_DESKTOP */
+ 0xA5, /* CML_DESKTOP */
+ 0xA6, /* CML_MOBILE */
+ 0xA7, /* RKL_DESKTOP */
+ 0xAA, /* MTL_MOBILE */
+ 0xAC, /* MTL_DESKTOP */
+ 0xB7, /* RPL_DESKTOP */
+ 0xBA, /* RPL_P */
+ 0xBE, /* ADL_N */
+ 0xBF, /* RPL_S */
+ 0 /* last entry must be zero */
+};
+
+static int intel_pstate_driver_loaded = -1;
+
+int is_supported_intel_cpu(int model, int cpu)
+{
+ int i;
+ uint64_t msr;
+
+ for (i = 0; intel_cpu_models[i] != 0; i++)
+ if (model == intel_cpu_models[i])
+ if (cpu < 0 || read_msr(cpu, MSR_APERF, &msr) >= 0)
+ return 1;
+
+ return 0;
+}
+
+int is_intel_pstate_driver_loaded()
+{
+ const char *filename = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_driver";
+ const string intel_pstate("intel_pstate");
+ char line[32] = { '\0' };
+ ifstream file;
+
+ if (intel_pstate_driver_loaded > -1)
+ return intel_pstate_driver_loaded;
+
+ file.open(filename, ios::in);
+
+ if (!file)
+ return -1;
+
+ file.getline(line, sizeof(line)-1);
+ file.close();
+
+ const string scaling_driver(line);
+ if (scaling_driver == intel_pstate) {
+ intel_pstate_driver_loaded = 1;
+ } else {
+ intel_pstate_driver_loaded = 0;
+ }
+
+ return intel_pstate_driver_loaded;
+}
+
+static uint64_t get_msr(int cpu, uint64_t offset)
+{
+ ssize_t retval;
+ uint64_t msr;
+
+ retval = read_msr(cpu, offset, &msr);
+ if (retval < 0) {
+ reset_display();
+ fprintf(stderr, _("read_msr cpu%d 0x%llx : "), cpu, (unsigned long long)offset);
+ fprintf(stderr, "%s\n", strerror(errno));
+ exit(-2);
+ }
+
+ return msr;
+}
+
+intel_util::intel_util()
+{
+ byt_ahci_support=0;
+}
+
+void intel_util::byt_has_ahci()
+{
+ dir = opendir("/sys/bus/pci/devices/0000:00:13.0");
+ if (!dir)
+ byt_ahci_support=0;
+ else {
+ byt_ahci_support=1;
+ closedir(dir);
+ }
+}
+
+int intel_util::get_byt_ahci_support()
+{
+ return byt_ahci_support;
+}
+
+nhm_core::nhm_core(int model)
+{
+ has_c7_res = 0;
+
+ switch(model) {
+ case 0x2A: /* SNB */
+ case 0x2D: /* SNB Xeon */
+ case 0x3A: /* IVB */
+ case 0x3C: /* HSW */
+ case 0x3D: /* BDW */
+ case 0x3E: /* IVB Xeon */
+ case 0x45: /* HSW-ULT */
+ case 0x4E: /* SKY */
+ case 0x55: /* SKY-X */
+ case 0x5E: /* SKY */
+ case 0x5F: /* DNV */
+ case 0x5C: /* BXT-P */
+ case 0x66: /* CNL-U/Y */
+ case 0x6A: /* ICL_X*/
+ case 0x7A: /* GLK */
+ case 0x7D: /* ICL_DESKTOP */
+ case 0x7E: /* ICL_MOBILE */
+ case 0x8A: /* LKF */
+ case 0x8C: /* TGL_MOBILE */
+ case 0x8D: /* TGL_DESKTOP */
+ case 0x8E: /* KBL_MOBILE */
+ case 0x8F: /* SAPPHIRERAPIDS_X */
+ case 0x96: /* EHL */
+ case 0x97: /* ADL_DESKTOP */
+ case 0x9A: /* ADL_MOBILE */
+ case 0x9C: /* JSL */
+ case 0x9D: /* ICL_NNPI */
+ case 0x9E: /* KBL_DESKTOP */
+ case 0xA5: /* CML_DESKTOP */
+ case 0xA6: /* CML_MOBILE */
+ case 0xA7: /* RKL_DESKTOP */
+ case 0xAA: /* MTL_MOBILE */
+ case 0xAC: /* MTL_DESKTOP */
+ case 0xB7: /* RPL_DESKTOP */
+ case 0xBA: /* RPL_P */
+ case 0xBE: /* ADL_N */
+ case 0xBF: /* RPL_S */
+ has_c7_res = 1;
+ }
+
+ has_c3_res = 1;
+ has_c1_res = 0;
+
+ switch (model) {
+ case 0x37: /* BYT-M does not support C3/C4 */
+ case 0x4C: /* BSW does not support C3 */
+ has_c3_res = 0;
+ has_c1_res = 1;
+ }
+
+}
+
+void nhm_core::measurement_start(void)
+{
+ ifstream file;
+ char filename[PATH_MAX];
+
+ /* the abstract function needs to be first since it clears all state */
+ abstract_cpu::measurement_start();
+
+ last_stamp = 0;
+
+ if (this->has_c1_res)
+ c1_before = get_msr(first_cpu, MSR_CORE_C1_RESIDENCY);
+ if (this->has_c3_res)
+ c3_before = get_msr(first_cpu, MSR_CORE_C3_RESIDENCY);
+ c6_before = get_msr(first_cpu, MSR_CORE_C6_RESIDENCY);
+ if (this->has_c7_res)
+ c7_before = get_msr(first_cpu, MSR_CORE_C7_RESIDENCY);
+ tsc_before = get_msr(first_cpu, MSR_TSC);
+
+ if (this->has_c1_res)
+ insert_cstate("core c1", "C1 (cc1)", 0, c1_before, 1);
+ if (this->has_c3_res)
+ insert_cstate("core c3", "C3 (cc3)", 0, c3_before, 1);
+ insert_cstate("core c6", "C6 (cc6)", 0, c6_before, 1);
+ if (this->has_c7_res) {
+ insert_cstate("core c7", "C7 (cc7)", 0, c7_before, 1);
+ }
+
+
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpufreq/stats/time_in_state", first_cpu);
+
+ file.open(filename, ios::in);
+
+ if (file) {
+ char line[1024];
+
+ while (file) {
+ uint64_t f;
+ file.getline(line, 1024);
+ f = strtoull(line, NULL, 10);
+ account_freq(f, 0);
+ }
+ file.close();
+ }
+ account_freq(0, 0);
+
+}
+
+void nhm_core::measurement_end(void)
+{
+ unsigned int i;
+ uint64_t time_delta;
+ double ratio;
+
+ if (this->has_c1_res)
+ c1_after = get_msr(first_cpu, MSR_CORE_C1_RESIDENCY);
+ if (this->has_c3_res)
+ c3_after = get_msr(first_cpu, MSR_CORE_C3_RESIDENCY);
+ c6_after = get_msr(first_cpu, MSR_CORE_C6_RESIDENCY);
+ if (this->has_c7_res)
+ c7_after = get_msr(first_cpu, MSR_CORE_C7_RESIDENCY);
+ tsc_after = get_msr(first_cpu, MSR_TSC);
+
+ if (this->has_c1_res)
+ finalize_cstate("core c1", 0, c1_after, 1);
+ if (this->has_c3_res)
+ finalize_cstate("core c3", 0, c3_after, 1);
+ finalize_cstate("core c6", 0, c6_after, 1);
+ if (this->has_c7_res)
+ finalize_cstate("core c7", 0, c7_after, 1);
+
+ gettimeofday(&stamp_after, NULL);
+
+ time_factor = 1000000.0 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+ for (i = 0; i < children.size(); i++)
+ if (children[i]) {
+ children[i]->measurement_end();
+ children[i]->wiggle();
+ }
+
+ time_delta = 1000000 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+ ratio = 1.0 * time_delta / (tsc_after - tsc_before);
+
+ for (i = 0; i < cstates.size(); i++) {
+ struct idle_state *state = cstates[i];
+
+ if (state->after_count == 0)
+ continue;
+
+ if (state->after_count != state->before_count)
+ continue;
+
+ state->usage_delta = ratio * (state->usage_after - state->usage_before) / state->after_count;
+ state->duration_delta = ratio * (state->duration_after - state->duration_before) / state->after_count;
+ }
+
+#if 0
+ for (i = 0; i < children.size(); i++)
+ if (children[i]) {
+ for (j = 0; j < children[i]->pstates.size(); j++) {
+ struct frequency *state;
+ state = children[i]->pstates[j];
+ if (!state)
+ continue;
+
+ update_pstate( state->freq, state->human_name, state->time_before, state->before_count);
+ finalize_pstate(state->freq, state->time_after, state->after_count);
+ }
+ }
+#endif
+ total_stamp = 0;
+}
+
+char * nhm_core::fill_pstate_line(int line_nr, char *buffer)
+{
+ const int intel_pstate = is_intel_pstate_driver_loaded();
+ buffer[0] = 0;
+ unsigned int i;
+
+ if (!intel_pstate && total_stamp ==0) {
+ for (i = 0; i < pstates.size(); i++)
+ total_stamp += pstates[i]->time_after;
+ if (total_stamp == 0)
+ total_stamp = 1;
+ }
+
+ if (line_nr == LEVEL_HEADER) {
+ sprintf(buffer,_(" Core"));
+ return buffer;
+ }
+
+ if (intel_pstate > 0 || line_nr >= (int)pstates.size() || line_nr < 0)
+ return buffer;
+
+ sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after) / total_stamp));
+
+ return buffer;
+}
+
+nhm_package::nhm_package(int model)
+{
+ has_c8c9c10_res = 0;
+ has_c2c6_res = 0;
+ has_c7_res = 0;
+ has_c6c_res = 0;
+
+ switch(model) {
+ case 0x2A: /* SNB */
+ case 0x2D: /* SNB Xeon */
+ case 0x3A: /* IVB */
+ case 0x3C: /* HSW */
+ case 0x3D: /* BDW */
+ case 0x3E: /* IVB Xeon */
+ case 0x45: /* HSW-ULT */
+ case 0x4E: /* SKY */
+ case 0x55: /* SKY-X */
+ case 0x5C: /* BXT-P */
+ case 0x5E: /* SKY */
+ case 0x5F: /* DNV */
+ case 0x66: /* CNL-U/Y */
+ case 0x6A: /* ICL_X*/
+ case 0x7A: /* GLK */
+ case 0x7D: /* ICL_DESKTOP */
+ case 0x7E: /* ICL_MOBILE */
+ case 0x8A: /* LKF */
+ case 0x8C: /* TGL_MOBILE */
+ case 0x8D: /* TGL_DESKTOP */
+ case 0x8E: /* KBL_MOBILE */
+ case 0x8F: /* SAPPHIRERAPIDS_X */
+ case 0x96: /* EHL */
+ case 0x97: /* ADL_DESKTOP */
+ case 0X9A: /* ADL_MOBILE */
+ case 0x9C: /* JSL */
+ case 0x9D: /* ICL_NNPI */
+ case 0x9E: /* KBL_DESKTOP */
+ case 0xA5: /* CML_DESKTOP */
+ case 0xA6: /* CML_MOBILE */
+ case 0xA7: /* RKL_DESKTOP */
+ case 0xAA: /* MTL_MOBILE */
+ case 0xAC: /* MTL_DESKTOP */
+ case 0xB7: /* RPL_DESKTOP */
+ case 0xBA: /* RPL_P */
+ case 0xBE: /* ADL_N */
+ case 0xBF: /* RPL_S */
+ has_c2c6_res=1;
+ has_c7_res = 1;
+ }
+
+ has_c3_res = 1;
+
+ switch(model) {
+ /* BYT-M doesn't have C3 or C7 */
+ /* BYT-T doesn't have C3 but it has C7 */
+ case 0x37:
+ has_c2c6_res=1;
+ this->byt_has_ahci();
+ if ((this->get_byt_ahci_support()) == 0)
+ has_c7_res = 1;/*BYT-T PC7 <- S0iX*/
+ else
+ has_c7_res = 0;
+ break;
+ case 0x4C: /* BSW doesn't have C3 */
+ has_c3_res = 0;
+ has_c6c_res = 1; /* BSW only exposes package C6 */
+ break;
+ }
+
+ /*Has C8/9/10*/
+ switch(model) {
+ case 0x3D: /* BDW */
+ case 0x45: /* HSW */
+ case 0x4E: /* SKY */
+ case 0x5C: /* BXT-P */
+ case 0x5E: /* SKY */
+ case 0x5F: /* DNV */
+ case 0x66: /* CNL-U/Y */
+ case 0x7A: /* GLK */
+ case 0x7D: /* ICL_DESKTOP */
+ case 0x7E: /* ICL_MOBILE */
+ case 0x8A: /* LKF */
+ case 0x8C: /* TGL_MOBILE */
+ case 0x8D: /* TGL_DESKTOP */
+ case 0x8E: /* KBL_MOBILE */
+ case 0x96: /* EHL */
+ case 0x97: /* ADL_DESKTOP */
+ case 0x9A: /* ADL_MOBILE */
+ case 0x9C: /* JSL */
+ case 0x9D: /* ICL_NNPI */
+ case 0x9E: /* KBL_DESKTOP */
+ case 0xA5: /* CML_DESKTOP */
+ case 0xA6: /* CML_MOBILE */
+ case 0xA7: /* RKL_DESKTOP */
+ case 0xAA: /* MTL_MOBILE */
+ case 0xAC: /* MTL_DESKTOP */
+ case 0xB7: /* RPL_DESKTOP */
+ case 0xBA: /* RPL_P */
+ case 0xBE: /* ADL_N */
+ case 0xBF: /* RPL_S */
+ has_c8c9c10_res = 1;
+ break;
+ }
+}
+
+char * nhm_package::fill_pstate_line(int line_nr, char *buffer)
+{
+ const int intel_pstate = is_intel_pstate_driver_loaded();
+ buffer[0] = 0;
+ unsigned int i;
+
+ if (!intel_pstate && total_stamp ==0) {
+ for (i = 0; i < pstates.size(); i++)
+ total_stamp += pstates[i]->time_after;
+ if (total_stamp == 0)
+ total_stamp = 1;
+ }
+
+
+ if (line_nr == LEVEL_HEADER) {
+ sprintf(buffer,_(" Package"));
+ return buffer;
+ }
+
+ if (intel_pstate > 0 || line_nr >= (int)pstates.size() || line_nr < 0)
+ return buffer;
+
+ sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after) / total_stamp));
+
+ return buffer;
+}
+
+
+
+void nhm_package::measurement_start(void)
+{
+ abstract_cpu::measurement_start();
+
+ last_stamp = 0;
+
+ if (this->has_c2c6_res)
+ c2_before = get_msr(number, MSR_PKG_C2_RESIDENCY);
+
+ if (this->has_c3_res)
+ c3_before = get_msr(number, MSR_PKG_C3_RESIDENCY);
+
+ /*
+ * Hack for Braswell where C7 MSR is actually BSW C6
+ */
+ if (this->has_c6c_res)
+ c6_before = get_msr(number, MSR_PKG_C7_RESIDENCY);
+ else
+ c6_before = get_msr(number, MSR_PKG_C6_RESIDENCY);
+
+ if (this->has_c7_res)
+ c7_before = get_msr(number, MSR_PKG_C7_RESIDENCY);
+ if (this->has_c8c9c10_res) {
+ c8_before = get_msr(number, MSR_PKG_C8_RESIDENCY);
+ c9_before = get_msr(number, MSR_PKG_C9_RESIDENCY);
+ c10_before = get_msr(number, MSR_PKG_C10_RESIDENCY);
+ }
+ tsc_before = get_msr(first_cpu, MSR_TSC);
+
+ if (this->has_c2c6_res)
+ insert_cstate("pkg c2", "C2 (pc2)", 0, c2_before, 1);
+
+ if (this->has_c3_res)
+ insert_cstate("pkg c3", "C3 (pc3)", 0, c3_before, 1);
+ insert_cstate("pkg c6", "C6 (pc6)", 0, c6_before, 1);
+ if (this->has_c7_res)
+ insert_cstate("pkg c7", "C7 (pc7)", 0, c7_before, 1);
+ if (this->has_c8c9c10_res) {
+ insert_cstate("pkg c8", "C8 (pc8)", 0, c8_before, 1);
+ insert_cstate("pkg c9", "C9 (pc9)", 0, c9_before, 1);
+ insert_cstate("pkg c10", "C10 (pc10)", 0, c10_before, 1);
+ }
+}
+
+void nhm_package::measurement_end(void)
+{
+ uint64_t time_delta;
+ double ratio;
+ unsigned int i, j;
+
+ for (i = 0; i < children.size(); i++)
+ if (children[i])
+ children[i]->wiggle();
+
+
+ if (this->has_c2c6_res)
+ c2_after = get_msr(number, MSR_PKG_C2_RESIDENCY);
+
+ if (this->has_c3_res)
+ c3_after = get_msr(number, MSR_PKG_C3_RESIDENCY);
+
+ if (this->has_c6c_res)
+ c6_after = get_msr(number, MSR_PKG_C7_RESIDENCY);
+ else
+ c6_after = get_msr(number, MSR_PKG_C6_RESIDENCY);
+
+ if (this->has_c7_res)
+ c7_after = get_msr(number, MSR_PKG_C7_RESIDENCY);
+ if (has_c8c9c10_res) {
+ c8_after = get_msr(number, MSR_PKG_C8_RESIDENCY);
+ c9_after = get_msr(number, MSR_PKG_C9_RESIDENCY);
+ c10_after = get_msr(number, MSR_PKG_C10_RESIDENCY);
+ }
+ tsc_after = get_msr(first_cpu, MSR_TSC);
+
+ gettimeofday(&stamp_after, NULL);
+
+ time_factor = 1000000.0 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+
+ if (this->has_c2c6_res)
+ finalize_cstate("pkg c2", 0, c2_after, 1);
+
+ if (this->has_c3_res)
+ finalize_cstate("pkg c3", 0, c3_after, 1);
+ finalize_cstate("pkg c6", 0, c6_after, 1);
+ if (this->has_c7_res)
+ finalize_cstate("pkg c7", 0, c7_after, 1);
+ if (has_c8c9c10_res) {
+ finalize_cstate("pkg c8", 0, c8_after, 1);
+ finalize_cstate("pkg c9", 0, c9_after, 1);
+ finalize_cstate("pkg c10", 0, c10_after, 1);
+ }
+
+ for (i = 0; i < children.size(); i++)
+ if (children[i])
+ children[i]->measurement_end();
+
+ time_delta = 1000000 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+ ratio = 1.0 * time_delta / (tsc_after - tsc_before);
+
+
+ for (i = 0; i < cstates.size(); i++) {
+ struct idle_state *state = cstates[i];
+
+ if (state->after_count == 0)
+ continue;
+
+ if (state->after_count != state->before_count)
+ continue;
+
+ state->usage_delta = ratio * (state->usage_after - state->usage_before) / state->after_count;
+ state->duration_delta = ratio * (state->duration_after - state->duration_before) / state->after_count;
+ }
+ for (i = 0; i < children.size(); i++)
+ if (children[i]) {
+ for (j = 0; j < children[i]->pstates.size(); j++) {
+ struct frequency *state;
+ state = children[i]->pstates[j];
+ if (!state)
+ continue;
+
+ update_pstate( state->freq, state->human_name, state->time_before, state->before_count);
+ finalize_pstate(state->freq, state->time_after, state->after_count);
+ }
+ }
+ total_stamp = 0;
+
+}
+
+void nhm_cpu::measurement_start(void)
+{
+ ifstream file;
+ char filename[PATH_MAX];
+
+ cpu_linux::measurement_start();
+
+ last_stamp = 0;
+
+ aperf_before = get_msr(number, MSR_APERF);
+ mperf_before = get_msr(number, MSR_MPERF);
+ tsc_before = get_msr(number, MSR_TSC);
+
+ insert_cstate("active", _("C0 active"), 0, aperf_before, 1);
+
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpufreq/stats/time_in_state", first_cpu);
+
+ file.open(filename, ios::in);
+
+ if (file) {
+ char line[1024];
+
+ while (file) {
+ uint64_t f;
+ file.getline(line, sizeof(line));
+ f = strtoull(line, NULL, 10);
+ account_freq(f, 0);
+ }
+ file.close();
+ }
+ account_freq(0, 0);
+}
+
+void nhm_cpu::measurement_end(void)
+{
+ uint64_t time_delta;
+ double ratio;
+ unsigned int i;
+
+ aperf_after = get_msr(number, MSR_APERF);
+ mperf_after = get_msr(number, MSR_MPERF);
+ tsc_after = get_msr(number, MSR_TSC);
+
+
+
+ finalize_cstate("active", 0, aperf_after, 1);
+
+
+ cpu_linux::measurement_end();
+
+ time_delta = 1000000 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+ ratio = 1.0 * time_delta / (tsc_after - tsc_before);
+
+
+ for (i = 0; i < cstates.size(); i++) {
+ struct idle_state *state = cstates[i];
+ if (state->line_level != LEVEL_C0)
+ continue;
+
+ state->usage_delta = ratio * (state->usage_after - state->usage_before) / state->after_count;
+ state->duration_delta = ratio * (state->duration_after - state->duration_before) / state->after_count;
+ }
+
+ total_stamp = 0;
+
+}
+
+char * nhm_cpu::fill_pstate_name(int line_nr, char *buffer)
+{
+ if (line_nr == LEVEL_C0) {
+ sprintf(buffer, _("Average"));
+ return buffer;
+ }
+ return cpu_linux::fill_pstate_name(line_nr, buffer);
+}
+
+char * nhm_cpu::fill_pstate_line(int line_nr, char *buffer)
+{
+ const int intel_pstate = is_intel_pstate_driver_loaded();
+
+ if (!intel_pstate && total_stamp ==0) {
+ unsigned int i;
+ for (i = 0; i < pstates.size(); i++)
+ total_stamp += pstates[i]->time_after;
+ if (total_stamp == 0)
+ total_stamp = 1;
+ }
+
+ if (line_nr == LEVEL_HEADER) {
+ sprintf(buffer,_(" CPU %i"), number);
+ return buffer;
+ }
+
+ if (line_nr == LEVEL_C0) {
+ double F;
+ F = 1.0 * (tsc_after - tsc_before) * (aperf_after - aperf_before) / (mperf_after - mperf_before) / time_factor * 1000;
+ hz_to_human(F, buffer, 1);
+ return buffer;
+ }
+ if (intel_pstate > 0 || line_nr >= (int)pstates.size() || line_nr < 0)
+ return buffer;
+
+ sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after) / total_stamp));
+
+ return buffer;
+}
+
+
+int nhm_cpu::has_pstate_level(int level)
+{
+ if (level == LEVEL_C0)
+ return 1;
+ return cpu_linux::has_pstate_level(level);
+}
diff --git a/src/cpu/intel_cpus.h b/src/cpu/intel_cpus.h
new file mode 100644
index 0000000..79afb98
--- /dev/null
+++ b/src/cpu/intel_cpus.h
@@ -0,0 +1,180 @@
+#ifndef PowerTop_INTEL_CPUS_H_84F09FB4F519470FA914AA9B02453221
+#define PowerTop_INTEL_CPUS_H_84F09FB4F519470FA914AA9B02453221
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <stdint.h>
+#include <sys/time.h>
+#include <dirent.h>
+
+#include "cpu.h"
+
+
+#define MSR_TSC 0x10
+#define MSR_NEHALEM_PLATFORM_INFO 0xCE
+#define MSR_NEHALEM_TURBO_RATIO_LIMIT 0x1AD
+#define MSR_APERF 0xE8
+#define MSR_MPERF 0xE7
+#define MSR_PKG_C2_RESIDENCY 0x60D
+#define MSR_PKG_C3_RESIDENCY 0x3F8
+#define MSR_PKG_C6_RESIDENCY 0x3F9
+#define MSR_PKG_C7_RESIDENCY 0x3FA
+#define MSR_PKG_C8_RESIDENCY 0x630
+#define MSR_PKG_C9_RESIDENCY 0x631
+#define MSR_PKG_C10_RESIDENCY 0x632
+#define MSR_CORE_C1_RESIDENCY 0x660
+#define MSR_CORE_C3_RESIDENCY 0x3FC
+#define MSR_CORE_C6_RESIDENCY 0x3FD
+#define MSR_CORE_C7_RESIDENCY 0x3FE
+
+class intel_util
+{
+protected:
+ int byt_ahci_support;
+ DIR *dir;
+public:
+ intel_util();
+ virtual void byt_has_ahci();
+ virtual int get_byt_ahci_support();
+};
+
+class nhm_package: public cpu_package, public intel_util
+{
+private:
+ uint64_t c2_before, c2_after;
+ uint64_t c3_before, c3_after;
+ uint64_t c6_before, c6_after;
+ uint64_t c7_before, c7_after;
+ uint64_t c8_before, c8_after;
+ uint64_t c9_before, c9_after;
+ uint64_t c10_before, c10_after;
+ uint64_t tsc_before, tsc_after;
+
+ uint64_t last_stamp;
+ uint64_t total_stamp;
+public:
+ int has_c7_res;
+ int has_c2c6_res;
+ int has_c3_res;
+ int has_c6c_res; /* BSW */
+ int has_c8c9c10_res;
+ nhm_package(int model);
+ virtual void measurement_start(void);
+ virtual void measurement_end(void);
+ virtual int can_collapse(void) { return 0;};
+
+ virtual char * fill_pstate_line(int line_nr, char *buffer);
+};
+
+class nhm_core: public cpu_core, public intel_util
+{
+private:
+ uint64_t c1_before, c1_after;
+ uint64_t c3_before, c3_after;
+ uint64_t c6_before, c6_after;
+ uint64_t c7_before, c7_after;
+ uint64_t tsc_before, tsc_after;
+
+ uint64_t last_stamp;
+ uint64_t total_stamp;
+public:
+ int has_c1_res;
+ int has_c7_res;
+ int has_c3_res;
+ nhm_core(int model);
+ virtual void measurement_start(void);
+ virtual void measurement_end(void);
+ virtual int can_collapse(void) { return 0;};
+
+ virtual char * fill_pstate_line(int line_nr, char *buffer);
+};
+
+class nhm_cpu: public cpu_linux, public intel_util
+{
+private:
+ uint64_t aperf_before;
+ uint64_t aperf_after;
+ uint64_t mperf_before;
+ uint64_t mperf_after;
+ uint64_t tsc_before, tsc_after;
+
+ uint64_t last_stamp;
+ uint64_t total_stamp;
+public:
+ virtual void measurement_start(void);
+ virtual void measurement_end(void);
+ virtual int can_collapse(void) { return 0;};
+
+ virtual char * fill_pstate_name(int line_nr, char *buffer);
+ virtual char * fill_pstate_line(int line_nr, char *buffer);
+ virtual int has_pstate_level(int level);
+};
+
+class atom_package: public cpu_package
+{
+public:
+ virtual void measurement_start(void);
+ virtual void measurement_end(void);
+
+};
+
+class atom_core: public cpu_core
+{
+public:
+ virtual void measurement_start(void);
+ virtual void measurement_end(void);
+
+};
+
+
+class i965_core: public cpu_core
+{
+private:
+ uint64_t rc6_before, rc6_after;
+ uint64_t rc6p_before, rc6p_after;
+ uint64_t rc6pp_before, rc6pp_after;
+
+ struct timeval before;
+ struct timeval after;
+
+public:
+ virtual void measurement_start(void);
+ virtual void measurement_end(void);
+ virtual int can_collapse(void) { return 0;};
+
+ virtual char * fill_pstate_line(int line_nr, char *buffer);
+ virtual char * fill_pstate_name(int line_nr, char *buffer);
+ virtual char * fill_cstate_line(int line_nr, char *buffer, const char *separator);
+ virtual int has_pstate_level(int level) { return 0; };
+ virtual int has_pstates(void) { return 0; };
+ virtual void wiggle(void) { };
+
+};
+
+int is_supported_intel_cpu(int model, int cpu);
+int byt_has_ahci();
+
+int is_intel_pstate_driver_loaded();
+
+#endif
diff --git a/src/cpu/intel_gpu.cpp b/src/cpu/intel_gpu.cpp
new file mode 100644
index 0000000..e0f4ac2
--- /dev/null
+++ b/src/cpu/intel_gpu.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2012, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "intel_cpus.h"
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "../lib.h"
+#include "../parameters/parameters.h"
+#include "../display.h"
+
+void i965_core::measurement_start(void)
+{
+ ifstream file;
+
+ gettimeofday(&before, NULL);
+ rc6_before = read_sysfs("/sys/class/drm/card0/power/rc6_residency_ms", NULL);
+ rc6p_before = read_sysfs("/sys/class/drm/card0/power/rc6p_residency_ms", NULL);
+ rc6pp_before = read_sysfs("/sys/class/drm/card0/power/rc6pp_residency_ms", NULL);
+
+ update_cstate("gpu c0", "Powered On", 0, 0, 1, 0);
+ update_cstate("gpu rc6", "RC6", 0, rc6_before, 1, 1);
+ update_cstate("gpu rc6p", "RC6p", 0, rc6p_before, 1, 2);
+ update_cstate("gpu rc6pp", "RC6pp", 0, rc6pp_before, 1, 3);
+}
+
+char * i965_core::fill_cstate_line(int line_nr, char *buffer, const char *separator)
+{
+ buffer[0] = 0;
+ double ratio, d = -1.0, time_delta;
+
+ if (line_nr == LEVEL_HEADER) {
+ sprintf(buffer,_(" GPU "));
+ return buffer;
+ }
+
+ buffer[0] = 0;
+
+ time_delta = 1000000 * (after.tv_sec - before.tv_sec) + after.tv_usec - before.tv_usec;
+ ratio = 100000.0/time_delta;
+
+ switch (line_nr) {
+ case 0:
+ d = 100.0 - ratio * (rc6_after + rc6p_after + rc6pp_after - rc6_before - rc6p_before - rc6pp_before);
+ break;
+ case 1:
+ d = ratio * (rc6_after - rc6_before);
+ break;
+ case 2:
+ d = ratio * (rc6p_after - rc6p_before);
+ break;
+ case 3:
+ d = ratio * (rc6pp_after - rc6pp_before);
+ break;
+ default:
+ return buffer;
+ }
+
+ /* cope with rounding errors due to the measurement interval */
+ if (d < 0.0)
+ d = 0.0;
+ if (d > 100.0)
+ d = 100.0;
+
+ sprintf(buffer,"%5.1f%%", d);
+
+ return buffer;
+}
+
+
+void i965_core::measurement_end(void)
+{
+ gettimeofday(&after, NULL);
+
+ rc6_after = read_sysfs("/sys/class/drm/card0/power/rc6_residency_ms", NULL);
+ rc6p_after = read_sysfs("/sys/class/drm/card0/power/rc6p_residency_ms", NULL);
+ rc6pp_after = read_sysfs("/sys/class/drm/card0/power/rc6pp_residency_ms", NULL);
+}
+
+char * i965_core::fill_pstate_line(int line_nr, char *buffer)
+{
+ buffer[0] = 0;
+ return buffer;
+}
+
+char * i965_core::fill_pstate_name(int line_nr, char *buffer)
+{
+ buffer[0] = 0;
+ return buffer;
+}
+
diff --git a/src/cpu/rapl/rapl_interface.cpp b/src/cpu/rapl/rapl_interface.cpp
new file mode 100644
index 0000000..d6bd4c8
--- /dev/null
+++ b/src/cpu/rapl/rapl_interface.cpp
@@ -0,0 +1,699 @@
+/* rapl_interface.cpp: rapl interface for power top implementation
+ *
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * Author Name <Srinivas.Pandruvada@linux.intel.com>
+ *
+ */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <math.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include "lib.h"
+#include "rapl_interface.h"
+
+#ifdef DEBUG
+#define RAPL_DBG_PRINT printf
+#define RAPL_ERROR_PRINT printf
+#else
+#define RAPL_DBG_PRINT(...) ((void) 0)
+#define RAPL_ERROR_PRINT(...) ((void) 0)
+#endif
+#define RAPL_INFO_PRINT(format, m) fprintf(stderr, format, m)
+
+#define MAX_TEMP_STR_SIZE 20
+
+// RAPL interface
+#define MSR_RAPL_POWER_UNIT 0x606
+#define MSR_PKG_POWER_LIMIT 0x610
+
+#define MSR_PKG_ENERY_STATUS 0x611
+#define MSR_PKG_POWER_INFO 0x614
+#define MSR_PKG_PERF_STATUS 0x613
+
+#define MSR_DRAM_POWER_LIMIT 0x618
+#define MSR_DRAM_ENERY_STATUS 0x619
+#define MSR_DRAM_PERF_STATUS 0x61B
+#define MSR_DRAM_POWER_INFO 0x61c
+
+#define MSR_PP0_POWER_LIMIT 0x638
+#define MSR_PP0_ENERY_STATUS 0x639
+#define MSR_PP0_POLICY 0x63A
+#define MSR_PP0_PERF_STATUS 0x63B
+
+#define MSR_PP1_POWER_LIMIT 0x640
+#define MSR_PP1_ENERY_STATUS 0x641
+#define MSR_PP1_POLICY 0x642
+
+#define PKG_DOMAIN_PRESENT 0x01
+#define DRAM_DOMAIN_PRESENT 0x02
+#define PP0_DOMAIN_PRESENT 0x04
+#define PP1_DOMAIN_PRESENT 0x08
+
+c_rapl_interface::c_rapl_interface(const char *dev_name, int cpu) :
+ powercap_sysfs_present(false),
+ powercap_core_path(),
+ powercap_uncore_path(),
+ powercap_dram_path(),
+ first_cpu(cpu),
+ measurment_interval(def_sampling_interval),
+ last_pkg_energy_status(0.0),
+ last_dram_energy_status(0.0),
+ last_pp0_energy_status(0.0),
+ last_pp1_energy_status(0.0)
+{
+ uint64_t value;
+ int ret;
+ string package_path;
+ DIR *dir;
+ struct dirent *entry;
+
+ RAPL_INFO_PRINT("RAPL device for cpu %d\n", cpu);
+
+ rapl_domains = 0;
+
+ if (dev_name) {
+ string base_path = "/sys/class/powercap/intel-rapl/";
+ if ((dir = opendir(base_path.c_str())) != NULL) {
+ while ((entry = readdir(dir)) != NULL) {
+ string path = base_path + entry->d_name + "/name";
+ string str = read_sysfs_string(path);
+ if (str.length() > 0) {
+ if (str == dev_name) {
+ package_path = base_path + entry->d_name + "/";
+ powercap_sysfs_present = true;
+ rapl_domains |= PKG_DOMAIN_PRESENT;
+ break;
+ }
+ }
+ }
+ closedir(dir);
+ }
+ }
+
+ if (powercap_sysfs_present) {
+ if ((dir = opendir(package_path.c_str())) != NULL) {
+ while ((entry = readdir(dir)) != NULL) {
+ string path = package_path + entry->d_name;
+ string str = read_sysfs_string(path + "/name");
+ if (str.length() > 0) {
+ if (str == "core") {
+ rapl_domains |= PP0_DOMAIN_PRESENT;
+ powercap_core_path = path + "/";
+ }
+ else if (str == "dram") {
+ rapl_domains |= DRAM_DOMAIN_PRESENT;
+ powercap_dram_path = path + "/";
+ }
+ else if (str == "uncore") {
+ rapl_domains |= PP1_DOMAIN_PRESENT;
+ powercap_uncore_path = path + "/";
+ }
+ }
+ }
+ closedir(dir);
+ }
+
+ RAPL_INFO_PRINT("RAPL Using PowerCap Sysfs : Domain Mask %x\n", rapl_domains);
+ return;
+ }
+
+ // Fallback to using MSRs
+
+ // presence of each domain
+ // Check presence of PKG domain
+ ret = read_msr(first_cpu, MSR_PKG_ENERY_STATUS, &value);
+ if (ret > 0) {
+ rapl_domains |= PKG_DOMAIN_PRESENT;
+ RAPL_DBG_PRINT("Domain : PKG present\n");
+ } else {
+ RAPL_DBG_PRINT("Domain : PKG Not present\n");
+ }
+
+ // Check presence of DRAM domain
+ ret = read_msr(first_cpu, MSR_DRAM_ENERY_STATUS, &value);
+ if (ret > 0) {
+ rapl_domains |= DRAM_DOMAIN_PRESENT;
+ RAPL_DBG_PRINT("Domain : DRAM present\n");
+ } else {
+ RAPL_DBG_PRINT("Domain : DRAM Not present\n");
+ }
+
+ // Check presence of PP0 domain
+ ret = read_msr(first_cpu, MSR_PP0_ENERY_STATUS, &value);
+ if (ret > 0) {
+ rapl_domains |= PP0_DOMAIN_PRESENT;
+ RAPL_DBG_PRINT("Domain : PP0 present\n");
+ } else {
+ RAPL_DBG_PRINT("Domain : PP0 Not present\n");
+ }
+
+ // Check presence of PP1 domain
+ ret = read_msr(first_cpu, MSR_PP1_ENERY_STATUS, &value);
+ if (ret > 0) {
+ rapl_domains |= PP1_DOMAIN_PRESENT;
+ RAPL_DBG_PRINT("Domain : PP1 present\n");
+ } else {
+ RAPL_DBG_PRINT("Domain : PP1 Not present\n");
+ }
+
+ power_units = get_power_unit();
+ energy_status_units = get_energy_status_unit();
+ time_units = get_time_unit();
+
+ RAPL_DBG_PRINT("RAPL Domain mask: %x\n", rapl_domains);
+}
+
+bool c_rapl_interface::pkg_domain_present()
+{
+ if ((rapl_domains & PKG_DOMAIN_PRESENT)) {
+ return true;
+ }
+
+ return false;
+}
+
+bool c_rapl_interface::dram_domain_present()
+{
+ if ((rapl_domains & DRAM_DOMAIN_PRESENT)) {
+ return true;
+ }
+
+ return false;
+}
+
+bool c_rapl_interface::pp0_domain_present()
+{
+ if ((rapl_domains & PP0_DOMAIN_PRESENT)) {
+ return true;
+ }
+
+ return false;
+}
+
+bool c_rapl_interface::pp1_domain_present()
+{
+ if ((rapl_domains & PP1_DOMAIN_PRESENT)) {
+ return true;
+ }
+
+ return false;
+}
+
+int c_rapl_interface::read_msr(int cpu, unsigned int idx, uint64_t *val)
+{
+ return ::read_msr(cpu, idx, val);
+}
+
+int c_rapl_interface::write_msr(int cpu, unsigned int idx, uint64_t val)
+{
+ return ::write_msr(cpu, idx, val);
+}
+
+int c_rapl_interface::get_rapl_power_unit(uint64_t *value)
+{
+ int ret;
+
+ ret = read_msr(first_cpu, MSR_RAPL_POWER_UNIT, value);
+
+ return ret;
+}
+
+double c_rapl_interface::get_power_unit()
+{
+ int ret;
+ uint64_t value;
+
+ ret = get_rapl_power_unit(&value);
+ if(ret < 0)
+ {
+ return ret;
+ }
+
+ return (double) 1/pow((double)2, (double)(value & 0xf));
+}
+
+double c_rapl_interface::get_energy_status_unit()
+{
+ int ret;
+ uint64_t value;
+
+ ret = get_rapl_power_unit(&value);
+ if(ret < 0)
+ {
+ return ret;
+ }
+
+ return (double)1/ pow((double)2, (double)((value & 0x1f00) >> 8));
+}
+
+double c_rapl_interface::get_time_unit()
+{
+ int ret;
+ uint64_t value;
+
+ ret = get_rapl_power_unit(&value);
+ if(ret < 0)
+ {
+ return ret;
+ }
+
+ return (double)1 / pow((double)2, (double)((value & 0xf0000) >> 16));
+}
+
+int c_rapl_interface::get_pkg_energy_status(double *status)
+{
+ int ret;
+ uint64_t value;
+
+ if (!pkg_domain_present()) {
+ return -1;
+ }
+
+ ret = read_msr(first_cpu, MSR_PKG_ENERY_STATUS, &value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_pkg_energy_status failed\n");
+ return ret;
+ }
+
+ *status = (double) (value & 0xffffffff) * get_energy_status_unit();
+
+ return ret;
+}
+
+int c_rapl_interface::get_pkg_power_info(double *thermal_spec_power,
+ double *max_power, double *min_power, double *max_time_window)
+{
+ int ret;
+ uint64_t value;
+
+ if (!pkg_domain_present()) {
+ return -1;
+ }
+ ret = read_msr(first_cpu, MSR_PKG_POWER_INFO, &value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_pkg_power_info failed\n");
+ return ret;
+ }
+ *thermal_spec_power = (value & 0x7FFF) * power_units;
+ *min_power = ((value & 0x7FFF0000) >> 16) * power_units;
+ *max_power = ((value & 0x7FFF00000000) >> 32) * power_units;
+ *max_time_window = ((value & 0x3f000000000000)>>48) * time_units;
+
+ return ret;
+}
+
+int c_rapl_interface::get_pkg_power_limit(uint64_t *value)
+{
+ int ret;
+
+ if (!pkg_domain_present()) {
+ return -1;
+ }
+
+ ret = read_msr(first_cpu, MSR_PKG_POWER_LIMIT, value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_pkg_power_limit failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+int c_rapl_interface::set_pkg_power_limit(uint64_t value)
+{
+ int ret;
+
+ if (!pkg_domain_present()) {
+ return -1;
+ }
+
+ ret = write_msr(first_cpu, MSR_PKG_POWER_LIMIT, value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("set_pkg_power_limit failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+int c_rapl_interface::get_dram_energy_status(double *status)
+{
+ int ret;
+ uint64_t value;
+
+ if (!dram_domain_present()) {
+ return -1;
+ }
+
+ if (powercap_sysfs_present) {
+ string str = read_sysfs_string(powercap_dram_path + "energy_uj");
+ if (str.length() > 0) {
+ *status = atof(str.c_str()) / 1000000; // uj to Js
+ return 0;
+ }
+
+ return -EINVAL;
+ }
+
+ ret = read_msr(first_cpu, MSR_DRAM_ENERY_STATUS, &value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_dram_energy_status failed\n");
+ return ret;
+ }
+
+ *status = (double) (value & 0xffffffff) * get_energy_status_unit();
+
+ return ret;
+}
+
+int c_rapl_interface::get_dram_power_info(double *thermal_spec_power,
+ double *max_power, double *min_power, double *max_time_window)
+{
+ int ret;
+ uint64_t value;
+
+ if (!dram_domain_present()) {
+ return -1;
+ }
+ ret = read_msr(first_cpu, MSR_DRAM_POWER_INFO, &value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_dram_power_info failed\n");
+ return ret;
+ }
+
+ *thermal_spec_power = (value & 0x7FFF) * power_units;
+ *min_power = ((value & 0x7FFF0000) >> 16) * power_units;
+ *max_power = ((value & 0x7FFF00000000) >> 32) * power_units;
+ *max_time_window = ((value & 0x3f000000000000)>>48) * time_units;
+
+ return ret;
+}
+
+int c_rapl_interface::get_dram_power_limit(uint64_t *value)
+{
+ int ret;
+
+ if (!dram_domain_present()) {
+ return -1;
+ }
+
+ ret = read_msr(first_cpu, MSR_DRAM_POWER_LIMIT, value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_dram_power_limit failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+int c_rapl_interface::set_dram_power_limit(uint64_t value)
+{
+ int ret;
+
+ if (!dram_domain_present()) {
+ return -1;
+ }
+
+ ret = write_msr(first_cpu, MSR_DRAM_POWER_LIMIT, value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("set_dram_power_limit failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+int c_rapl_interface::get_pp0_energy_status(double *status)
+{
+ int ret;
+ uint64_t value;
+
+ if (!pp0_domain_present()) {
+ return -1;
+ }
+
+ if (powercap_sysfs_present) {
+ string str = read_sysfs_string(powercap_core_path + "energy_uj");
+ if (str.length() > 0) {
+ *status = atof(str.c_str()) / 1000000; // uj to Js
+ return 0;
+ }
+
+ return -EINVAL;
+ }
+
+ ret = read_msr(first_cpu, MSR_PP0_ENERY_STATUS, &value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_pp0_energy_status failed\n");
+ return ret;
+ }
+
+ *status = (double) (value & 0xffffffff) * get_energy_status_unit();
+
+ return ret;
+}
+
+int c_rapl_interface::get_pp0_power_limit(uint64_t *value)
+{
+ int ret;
+
+ if (!pp0_domain_present()) {
+ return -1;
+ }
+
+ ret = read_msr(first_cpu, MSR_PP0_POWER_LIMIT, value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_pp0_power_limit failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+int c_rapl_interface::set_pp0_power_limit(uint64_t value)
+{
+ int ret;
+
+ if (!pp0_domain_present()) {
+ return -1;
+ }
+
+ ret = write_msr(first_cpu, MSR_PP0_POWER_LIMIT, value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("set_pp0_power_limit failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+int c_rapl_interface::get_pp0_power_policy(unsigned int *pp0_power_policy)
+{
+ int ret;
+ uint64_t value;
+
+ if (!pp0_domain_present()) {
+ return -1;
+ }
+
+ ret = read_msr(first_cpu, MSR_PP0_POLICY, &value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_pp0_power_policy failed\n");
+ return ret;
+ }
+
+ *pp0_power_policy = value & 0x0f;
+
+ return ret;
+}
+
+int c_rapl_interface::get_pp1_energy_status(double *status)
+{
+ int ret;
+ uint64_t value;
+
+ if (!pp1_domain_present()) {
+ return -1;
+ }
+
+ if (powercap_sysfs_present) {
+ string str = read_sysfs_string(powercap_uncore_path + "energy_uj");
+ if (str.length() > 0) {
+ *status = atof(str.c_str()) / 1000000; // uj to Js
+ return 0;
+ }
+
+ return -EINVAL;
+ }
+
+ ret = read_msr(first_cpu, MSR_PP1_ENERY_STATUS, &value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_pp1_energy_status failed\n");
+ return ret;
+ }
+
+ *status = (double) (value & 0xffffffff) * get_energy_status_unit();
+
+ return ret;
+}
+
+int c_rapl_interface::get_pp1_power_limit(uint64_t *value)
+{
+ int ret;
+
+ if (!pp1_domain_present()) {
+ return -1;
+ }
+
+ ret = read_msr(first_cpu, MSR_PP1_POWER_LIMIT, value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_pp1_power_info failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+int c_rapl_interface::set_pp1_power_limit(uint64_t value)
+{
+ int ret;
+
+ if (!pp1_domain_present()) {
+ return -1;
+ }
+
+ ret = write_msr(first_cpu, MSR_PP1_POWER_LIMIT, value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("set_pp1_power_limit failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+int c_rapl_interface::get_pp1_power_policy(unsigned int *pp1_power_policy)
+{
+ int ret;
+ uint64_t value;
+
+ if (!pp1_domain_present()) {
+ return -1;
+ }
+
+ ret = read_msr(first_cpu, MSR_PP1_POLICY, &value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_pp1_power_policy failed\n");
+ return ret;
+ }
+
+ *pp1_power_policy = value & 0x0f;
+
+ return ret;
+}
+
+void c_rapl_interface::rapl_measure_energy()
+{
+#ifdef RAPL_TEST_MODE
+ int ret;
+ double energy_status;
+ double thermal_spec_power;
+ double max_power;
+ double min_power;
+ double max_time_window;
+ double pkg_watts = 0;
+ double dram_watts = 0;
+ double pp0_watts = 0;
+ double pp1_watts = 0;
+ double pkg_joules = 0;
+ double dram_joules = 0;
+ double pp0_joules = 0;
+ double pp1_joules = 0;
+
+ get_pkg_power_info(&thermal_spec_power, &max_power, &min_power, &max_time_window);
+ RAPL_DBG_PRINT("Pkg Power Info: Thermal spec %f watts, max %f watts, min %f watts, max time window %f seconds\n", thermal_spec_power, max_power, min_power, max_time_window);
+ get_dram_power_info(&thermal_spec_power, &max_power, &min_power, &max_time_window);
+ RAPL_DBG_PRINT("DRAM Power Info: Thermal spec %f watts, max %f watts, min %f watts, max time window %f seconds\n", thermal_spec_power, max_power, min_power, max_time_window);
+
+ for (;;) {
+ if (pkg_domain_present()) {
+ ret = get_pkg_energy_status(&energy_status);
+ if (last_pkg_energy_status == 0)
+ last_pkg_energy_status = energy_status;
+ if (ret > 0) {
+ pkg_joules = energy_status;
+ pkg_watts = (energy_status-last_pkg_energy_status)/measurment_interval;
+ }
+ last_pkg_energy_status = energy_status;
+ }
+ if (dram_domain_present()) {
+ ret = get_dram_energy_status(&energy_status);
+ if (last_dram_energy_status == 0)
+ last_dram_energy_status = energy_status;
+ if (ret > 0){
+ dram_joules = energy_status;
+ dram_watts = (energy_status-last_dram_energy_status)/measurment_interval;
+ }
+ last_dram_energy_status = energy_status;
+ }
+ if (pp0_domain_present()) {
+ ret = get_pp0_energy_status(&energy_status);
+ if (last_pp0_energy_status == 0)
+ last_pp0_energy_status = energy_status;
+ if (ret > 0){
+ pp0_joules = energy_status;
+ pp0_watts = (energy_status-last_pp0_energy_status)/measurment_interval;
+ }
+ last_pp0_energy_status = energy_status;
+ }
+ if (pp1_domain_present()) {
+ ret = get_pp1_energy_status(&energy_status);
+ if (last_pp1_energy_status == 0)
+ last_pp1_energy_status = energy_status;
+ if (ret > 0){
+ pp1_joules = energy_status;
+ pp1_watts = (energy_status-last_pp1_energy_status)/measurment_interval;
+ }
+ last_pp1_energy_status = energy_status;
+ }
+ RAPL_DBG_PRINT("%f, %f, %f, %f\n", pkg_watts, dram_watts, pp0_watts, pp1_watts);
+ sleep(measurment_interval);
+ }
+#endif
+}
diff --git a/src/cpu/rapl/rapl_interface.h b/src/cpu/rapl/rapl_interface.h
new file mode 100644
index 0000000..c8e9683
--- /dev/null
+++ b/src/cpu/rapl/rapl_interface.h
@@ -0,0 +1,91 @@
+/* rapl_interface.h: rapl interface for power top
+ *
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * Author Name <Srinivas.Pandruvada@linux.intel.com>
+ *
+ */
+
+#ifndef RAPL_INTERFACE_H
+#define RAPL_INTERFACE_H
+
+class c_rapl_interface
+{
+private:
+ static const int def_sampling_interval = 1; //In seconds
+ bool powercap_sysfs_present;
+ string powercap_core_path;
+ string powercap_uncore_path;
+ string powercap_dram_path;
+
+ unsigned char rapl_domains;
+ int first_cpu;
+
+ double power_units;
+ double energy_status_units;
+ double time_units;
+
+ int read_msr(int cpu, unsigned int idx, uint64_t *val);
+ int write_msr(int cpu, unsigned int idx, uint64_t val);
+
+protected:
+ int measurment_interval;
+ double last_pkg_energy_status;
+ double last_dram_energy_status;
+ double last_pp0_energy_status;
+ double last_pp1_energy_status;
+
+public:
+ c_rapl_interface(const char *dev_name = "package-0", int cpu = 0);
+
+ int get_rapl_power_unit(uint64_t *value);
+ double get_power_unit();
+ double get_energy_status_unit();
+ double get_time_unit();
+
+ int get_pkg_energy_status(double *status);
+ int get_pkg_power_info(double *thermal_spec_power,
+ double *max_power, double *min_power, double *max_time_window);
+ int get_pkg_power_limit(uint64_t *value);
+ int set_pkg_power_limit(uint64_t value);
+
+ int get_dram_energy_status(double *status);
+ int get_dram_power_info(double *thermal_spec_power,
+ double *max_power, double *min_power, double *max_time_window);
+ int get_dram_power_limit(uint64_t *value);
+ int set_dram_power_limit(uint64_t value);
+
+ int get_pp0_energy_status(double *status);
+ int get_pp0_power_limit(uint64_t *value);
+ int set_pp0_power_limit(uint64_t value);
+ int get_pp0_power_policy(unsigned int *pp0_power_policy);
+
+ int get_pp1_energy_status(double *status);
+ int get_pp1_power_limit(uint64_t *value);
+ int set_pp1_power_limit(uint64_t value);
+ int get_pp1_power_policy(unsigned int *pp1_power_policy);
+
+ bool pkg_domain_present();
+ bool dram_domain_present();
+ bool pp0_domain_present();
+ bool pp1_domain_present();
+
+ void rapl_measure_energy();
+};
+
+#endif
diff --git a/src/csstoh.sh b/src/csstoh.sh
new file mode 100755
index 0000000..681e6a5
--- /dev/null
+++ b/src/csstoh.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+#
+# 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.
+#
+# Written by Igor Zhbanov <i.zhbanov at samsung.com>
+
+if [ $# -ne 2 ]; then
+ echo "Usage: csstoh.sh cssfile header.h" >&2
+ exit 1
+fi
+if [ ! -f "$1" ]; then
+ echo "$1: no such file or directory" >&2
+ exit 1
+fi
+# redirect stdout to a file
+exec 1> "$2" || exit $?
+
+# header
+cat <<HERE || exit $?
+#ifndef __INCLUDE_GUARD_CCS_H
+#define __INCLUDE_GUARD_CCS_H
+
+const char css[] =
+HERE
+# body
+sed -r 's/^[ \t]*//; s/^(.*)$/\t\"\1\\n\"/' "$1" || exit $?
+# footer
+cat <<HERE || exit $?
+;
+#endif
+HERE
+
+# close output file
+exec 1>&-
+# return status of output file write
+exit $?
diff --git a/src/devices/ahci.cpp b/src/devices/ahci.cpp
new file mode 100644
index 0000000..efa66b3
--- /dev/null
+++ b/src/devices/ahci.cpp
@@ -0,0 +1,428 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <limits.h>
+
+
+using namespace std;
+
+#include "device.h"
+#include "report/report.h"
+#include "report/report-maker.h"
+#include "ahci.h"
+#include "../parameters/parameters.h"
+#include "report/report-data-html.h"
+#include <string.h>
+
+vector <class ahci *> links;
+
+static string disk_name(char *path, char *target, char *shortname)
+{
+
+ DIR *dir;
+ struct dirent *dirent;
+ char pathname[PATH_MAX];
+ string diskname = "";
+
+ snprintf(pathname, sizeof(pathname), "%s/%s", path, target);
+ dir = opendir(pathname);
+ if (!dir)
+ return diskname;
+
+ while ((dirent = readdir(dir))) {
+ char line[4096], *c;
+ FILE *file;
+ if (dirent->d_name[0]=='.')
+ continue;
+
+ if (!strchr(dirent->d_name, ':'))
+ continue;
+
+ snprintf(line, sizeof(line), "%s/%s/model", pathname, dirent->d_name);
+ file = fopen(line, "r");
+ if (file) {
+ if (fgets(line, sizeof(line), file) == NULL) {
+ fclose(file);
+ break;
+ }
+ fclose(file);
+ c = strchr(line, '\n');
+ if (c)
+ *c = 0;
+ diskname = line;
+ break;
+ }
+ }
+ closedir(dir);
+
+ return diskname;
+}
+
+static string model_name(char *path, char *shortname)
+{
+
+ DIR *dir;
+ struct dirent *dirent;
+ char pathname[PATH_MAX];
+
+ snprintf(pathname, sizeof(pathname), "%s/device", path);
+
+ dir = opendir(pathname);
+ if (!dir)
+ return strdup(shortname);
+
+ while ((dirent = readdir(dir))) {
+ if (dirent->d_name[0]=='.')
+ continue;
+
+ if (!strchr(dirent->d_name, ':'))
+ continue;
+ if (!strstr(dirent->d_name, "target"))
+ continue;
+ return disk_name(pathname, dirent->d_name, shortname);
+ }
+ closedir(dir);
+
+ return "";
+}
+
+ahci::ahci(char *_name, char *path): device()
+{
+ char buffer[4096];
+ char devname[128];
+ string diskname;
+
+ end_active = 0;
+ end_slumber = 0;
+ end_devslp = 0;
+ end_partial = 0;
+ start_active = 0;
+ start_slumber = 0;
+ start_devslp = 0;
+ start_partial = 0;
+ pt_strcpy(sysfs_path, path);
+
+ register_sysfs_path(sysfs_path);
+
+ snprintf(devname, sizeof(devname), "ahci:%s", _name);
+ pt_strcpy(name, devname);
+ active_index = get_param_index("ahci-link-power-active");
+ partial_index = get_param_index("ahci-link-power-partial");
+
+ snprintf(buffer, sizeof(buffer), "%s-active", name);
+ active_rindex = get_result_index(buffer);
+
+ snprintf(buffer, sizeof(buffer), "%s-partial", name);
+ partial_rindex = get_result_index(buffer);
+
+ snprintf(buffer, sizeof(buffer), "%s-slumber", name);
+ slumber_rindex = get_result_index(buffer);
+
+ snprintf(buffer, sizeof(buffer), "%s-devslp", name);
+ devslp_rindex = get_result_index(buffer);
+
+ diskname = model_name(path, _name);
+
+ if (strlen(diskname.c_str()) == 0)
+ snprintf(humanname, sizeof(humanname), _("SATA link: %s"), _name);
+ else
+ snprintf(humanname, sizeof(humanname), _("SATA disk: %s"), diskname.c_str());
+}
+
+void ahci::start_measurement(void)
+{
+ char filename[PATH_MAX];
+ ifstream file;
+
+ snprintf(filename, sizeof(filename), "%s/ahci_alpm_active", sysfs_path);
+ try {
+ file.open(filename, ios::in);
+ if (file) {
+ file >> start_active;
+ }
+ file.close();
+ snprintf(filename, sizeof(filename), "%s/ahci_alpm_partial", sysfs_path);
+ file.open(filename, ios::in);
+
+ if (file) {
+ file >> start_partial;
+ }
+ file.close();
+ snprintf(filename, sizeof(filename), "%s/ahci_alpm_slumber", sysfs_path);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> start_slumber;
+ }
+ file.close();
+ snprintf(filename, sizeof(filename), "%s/ahci_alpm_devslp", sysfs_path);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> start_devslp;
+ }
+ file.close();
+ }
+ catch (std::ios_base::failure &c) {
+ fprintf(stderr, "%s\n", c.what());
+ }
+
+}
+
+void ahci::end_measurement(void)
+{
+ char filename[PATH_MAX];
+ char powername[4096];
+ ifstream file;
+ double p;
+ double total;
+
+ try {
+ snprintf(filename, sizeof(filename), "%s/ahci_alpm_active", sysfs_path);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> end_active;
+ }
+ file.close();
+ snprintf(filename, sizeof(filename), "%s/ahci_alpm_partial", sysfs_path);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> end_partial;
+ }
+ file.close();
+ snprintf(filename, sizeof(filename), "%s/ahci_alpm_slumber", sysfs_path);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> end_slumber;
+ }
+ file.close();
+ snprintf(filename, sizeof(filename), "%s/ahci_alpm_devslp", sysfs_path);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> end_devslp;
+ }
+ file.close();
+ }
+ catch (std::ios_base::failure &c) {
+ fprintf(stderr, "%s\n", c.what());
+ }
+ if (end_active < start_active)
+ end_active = start_active;
+ if (end_partial < start_partial)
+ end_partial = start_partial;
+ if (end_slumber < start_slumber)
+ end_slumber = start_slumber;
+
+ total = 0.001 + end_active + end_partial + end_slumber + end_devslp -
+ start_active - start_partial - start_slumber - start_devslp;
+
+ /* percent in active */
+ p = (end_active - start_active) / total * 100.0;
+ if (p < 0)
+ p = 0;
+ snprintf(powername, sizeof(powername), "%s-active", name);
+ report_utilization(powername, p);
+
+ /* percent in partial */
+ p = (end_partial - start_partial) / total * 100.0;
+ if (p < 0)
+ p = 0;
+ snprintf(powername, sizeof(powername), "%s-partial", name);
+ report_utilization(powername, p);
+
+ /* percent in slumber */
+ p = (end_slumber - start_slumber) / total * 100.0;
+ if (p < 0)
+ p = 0;
+ snprintf(powername, sizeof(powername), "%s-slumber", name);
+ report_utilization(powername, p);
+
+ /* percent in devslp */
+ p = (end_devslp - start_devslp) / total * 100.0;
+ if (p < 0)
+ p = 0;
+ snprintf(powername, sizeof(powername), "%s-devslp", name);
+ report_utilization(powername, p);
+}
+
+
+double ahci::utilization(void)
+{
+ double p;
+
+ p = (end_partial - start_partial + end_active - start_active) / (0.001 + end_active + end_partial + end_slumber + end_devslp - start_active - start_partial - start_slumber - start_devslp) * 100.0;
+
+ if (p < 0)
+ p = 0;
+
+ return p;
+}
+
+const char * ahci::device_name(void)
+{
+ return name;
+}
+
+void create_all_ahcis(void)
+{
+ struct dirent *entry;
+ DIR *dir;
+ char filename[PATH_MAX];
+
+ dir = opendir("/sys/class/scsi_host/");
+ if (!dir)
+ return;
+ while (1) {
+ class ahci *bl;
+ ofstream file;
+ ifstream check_file;
+ entry = readdir(dir);
+ if (!entry)
+ break;
+ if (entry->d_name[0] == '.')
+ continue;
+ snprintf(filename, sizeof(filename), "/sys/class/scsi_host/%s/ahci_alpm_accounting", entry->d_name);
+
+ check_file.open(filename, ios::in);
+ check_file.get();
+ check_file.close();
+ if (check_file.bad())
+ continue;
+
+ file.open(filename, ios::in);
+ if (!file)
+ continue;
+ file << 1 ;
+ file.close();
+ snprintf(filename, sizeof(filename), "/sys/class/scsi_host/%s", entry->d_name);
+
+ bl = new class ahci(entry->d_name, filename);
+ all_devices.push_back(bl);
+ register_parameter("ahci-link-power-active", 0.6); /* active sata link takes about 0.6 W */
+ register_parameter("ahci-link-power-partial");
+ links.push_back(bl);
+ }
+ closedir(dir);
+
+}
+
+
+
+double ahci::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+ double power;
+ double factor;
+ double util;
+
+ power = 0;
+
+ factor = get_parameter_value(active_index, bundle);
+ util = get_result_value(active_rindex, result);
+ power += util * factor / 100.0;
+
+
+ factor = get_parameter_value(partial_index, bundle);
+ util = get_result_value(partial_rindex, result);
+ power += util * factor / 100.0;
+
+ return power;
+}
+
+void ahci_create_device_stats_table(void)
+{
+ unsigned int i;
+ int cols=0;
+ int rows=0;
+
+ /* div attr css_class and css_id */
+ tag_attr div_attr;
+ init_div(&div_attr, "clear_block", "ahci");
+
+ /* Set Title attributes */
+ tag_attr title_attr;
+ init_title_attr(&title_attr);
+
+ /* Add section */
+ report.add_div(&div_attr);
+
+ if (links.size() == 0) {
+ report.add_title(&title_attr, __("AHCI ALPM Residency Statistics - Not supported on this macine"));
+ report.end_div();
+ return;
+ }
+
+ /* Set Table attributes, rows, and cols */
+ table_attributes std_table_css;
+ cols=5;
+ rows=links.size()+1;
+ init_std_side_table_attr(&std_table_css, rows, cols);
+
+
+
+ /* Set array of data in row Major order */
+ string *ahci_data = new string[cols * rows];
+ ahci_data[0]=__("Link");
+ ahci_data[1]=__("Active");
+ ahci_data[2]=__("Partial");
+ ahci_data[3]=__("Slumber");
+ ahci_data[4]=__("Devslp");
+
+ /* traverse list of all devices and put their residency in the table */
+ for (i = 0; i < links.size(); i++){
+ links[i]->report_device_stats(ahci_data, i);
+ }
+ report.add_title(&title_attr, __("AHCI ALPM Residency Statistics"));
+ report.add_table(ahci_data, &std_table_css);
+ report.end_div();
+ delete [] ahci_data;
+}
+
+void ahci::report_device_stats(string *ahci_data, int idx)
+{
+ int offset=(idx*5+5);
+ char util[128];
+ double active_util = get_result_value(active_rindex, &all_results);
+ double partial_util = get_result_value(partial_rindex, &all_results);
+ double slumber_util = get_result_value(slumber_rindex, &all_results);
+ double devslp_util = get_result_value(devslp_rindex, &all_results);
+
+ snprintf(util, sizeof(util), "%5.1f", active_util);
+ ahci_data[offset]= util;
+ offset +=1;
+
+ snprintf(util, sizeof(util), "%5.1f", partial_util);
+ ahci_data[offset]= util;
+ offset +=1;
+
+ snprintf(util, sizeof(util), "%5.1f", slumber_util);
+ ahci_data[offset]= util;
+ offset +=1;
+
+ snprintf(util, sizeof(util), "%5.1f", devslp_util);
+ ahci_data[offset]= util;
+}
diff --git a/src/devices/ahci.h b/src/devices/ahci.h
new file mode 100644
index 0000000..7431fb5
--- /dev/null
+++ b/src/devices/ahci.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_AHCI_H
+#define _INCLUDE_GUARD_AHCI_H
+
+
+#include <string>
+#include <limits.h>
+#include "device.h"
+#include "../parameters/parameters.h"
+#include <stdint.h>
+
+class ahci: public device {
+ uint64_t start_active, end_active;
+ uint64_t start_partial, end_partial;
+ uint64_t start_slumber, end_slumber;
+ uint64_t start_devslp, end_devslp;
+ char sysfs_path[PATH_MAX];
+ char name[4096];
+ int partial_rindex;
+ int active_rindex;
+ int slumber_rindex;
+ int devslp_rindex;
+ int partial_index;
+ int active_index;
+ char humanname[4096];
+public:
+
+ ahci(char *_name, char *path);
+
+ virtual void start_measurement(void);
+ virtual void end_measurement(void);
+
+ virtual double utilization(void); /* percentage */
+
+ virtual const char * class_name(void) { return "ahci";};
+
+ virtual const char * device_name(void);
+ virtual const char * human_name(void) { return humanname;};
+ virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+ virtual int power_valid(void) { return utilization_power_valid(partial_rindex) + utilization_power_valid(active_rindex);};
+ virtual int grouping_prio(void) { return 1; };
+ virtual void report_device_stats(string *ahci_data, int idx);
+};
+
+extern void create_all_ahcis(void);
+extern void ahci_create_device_stats_table(void);
+
+
+#endif
diff --git a/src/devices/alsa.cpp b/src/devices/alsa.cpp
new file mode 100644
index 0000000..7e22975
--- /dev/null
+++ b/src/devices/alsa.cpp
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+using namespace std;
+
+#include "device.h"
+#include "alsa.h"
+#include "../parameters/parameters.h"
+
+#include "../devlist.h"
+
+#include <string.h>
+#include <unistd.h>
+
+alsa::alsa(const char *_name, const char *path): device()
+{
+ ifstream file;
+
+ char devname[4096];
+ char model[4096];
+ char vendor[4096];
+ end_active = 0;
+ start_active = 0;
+ end_inactive = 0;
+ start_inactive = 0;
+ pt_strcpy(sysfs_path, path);
+
+ snprintf(devname, sizeof(devname), "alsa:%s", _name);
+ snprintf(humanname, sizeof(humanname), "alsa:%s", _name);
+ pt_strcpy(name, devname);
+ rindex = get_result_index(name);
+
+ guilty[0] = 0;
+ model[0] = 0;
+ vendor[0] = 0;
+ snprintf(devname, sizeof(devname), "%s/modelname", path);
+ file.open(devname);
+ if (file) {
+ file.getline(model, sizeof(model));
+ file.close();
+ }
+ snprintf(devname, sizeof(devname), "%s/vendor_name", path);
+ file.open(devname);
+ if (file) {
+ file.getline(vendor, sizeof(vendor));
+ file.close();
+ }
+ if (strlen(model) && strlen(vendor))
+ snprintf(humanname, sizeof(humanname), _("Audio codec %s: %s (%s)"), name, model, vendor);
+ else if (strlen(model))
+ snprintf(humanname, sizeof(humanname), _("Audio codec %s: %s"), _name, model);
+ else if (strlen(vendor))
+ snprintf(humanname, sizeof(humanname), _("Audio codec %s: %s"), _name, vendor);
+}
+
+void alsa::start_measurement(void)
+{
+ char filename[PATH_MAX];
+ ifstream file;
+
+ snprintf(filename, sizeof(filename), "%s/power_off_acct", sysfs_path);
+ try {
+ file.open(filename, ios::in);
+ if (file) {
+ file >> start_inactive;
+ }
+ file.close();
+ snprintf(filename, sizeof(filename), "%s/power_on_acct", sysfs_path);
+ file.open(filename, ios::in);
+
+ if (file) {
+ file >> start_active;
+ }
+ file.close();
+ }
+ catch (std::ios_base::failure &c) {
+ fprintf(stderr, "%s\n", c.what());
+ }
+}
+
+void alsa::end_measurement(void)
+{
+ char filename[PATH_MAX];
+ ifstream file;
+ double p;
+
+ snprintf(filename, sizeof(filename), "%s/power_off_acct", sysfs_path);
+ try {
+ file.open(filename, ios::in);
+ if (file) {
+ file >> end_inactive;
+ }
+ file.close();
+ snprintf(filename, sizeof(filename), "%s/power_on_acct", sysfs_path);
+ file.open(filename, ios::in);
+
+ if (file) {
+ file >> end_active;
+ }
+ file.close();
+ }
+ catch (std::ios_base::failure &c) {
+ fprintf(stderr, "%s\n", c.what());
+ }
+
+ p = (end_active - start_active) / (0.001 + end_active + end_inactive - start_active - start_inactive) * 100.0;
+ report_utilization(name, p);
+}
+
+
+double alsa::utilization(void)
+{
+ double p;
+
+ p = (end_active - start_active) / (0.001 + end_active - start_active + end_inactive - start_inactive) * 100.0;
+
+ return p;
+}
+
+const char * alsa::device_name(void)
+{
+ return name;
+}
+
+static void create_all_alsa_callback(const char *d_name)
+{
+ char filename[PATH_MAX];
+ class alsa *bl;
+
+ if (strncmp(d_name, "hwC", 3) != 0)
+ return;
+
+ snprintf(filename, sizeof(filename), "/sys/class/sound/%s/power_on_acct", d_name);
+ if (access(filename, R_OK) != 0)
+ return;
+
+ snprintf(filename, sizeof(filename), "/sys/class/sound/%s", d_name);
+ bl = new class alsa(d_name, filename);
+ all_devices.push_back(bl);
+ register_parameter("alsa-codec-power", 0.5);
+}
+
+void create_all_alsa(void)
+{
+ process_directory("/sys/class/sound/", create_all_alsa_callback);
+}
+
+double alsa::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+ double power;
+ double factor;
+ double util;
+ static int index = 0;
+
+ power = 0;
+ if (!index)
+ index = get_param_index("alsa-codec-power");
+
+ factor = get_parameter_value(index, bundle);
+
+ util = get_result_value(rindex, result);
+
+ power += util * factor / 100.0;
+
+ return power;
+}
+
+void alsa::register_power_with_devlist(struct result_bundle *results, struct parameter_bundle *bundle)
+{
+ register_devpower(&name[7], power_usage(results, bundle), this);
+}
+
+const char * alsa::human_name(void)
+{
+ pt_strcpy(temp_buf, humanname);
+ if (strlen(guilty) > 0)
+ snprintf(temp_buf, sizeof(temp_buf), "%s (%s)", humanname, guilty);
+ return temp_buf;
+}
diff --git a/src/devices/alsa.h b/src/devices/alsa.h
new file mode 100644
index 0000000..b68203f
--- /dev/null
+++ b/src/devices/alsa.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_ALSA_H
+#define _INCLUDE_GUARD_ALSA_H
+
+
+#include "device.h"
+#include "../parameters/parameters.h"
+
+#include <stdint.h>
+#include <limits.h>
+
+class alsa: public device {
+ uint64_t start_active, end_active;
+ uint64_t start_inactive, end_inactive;
+ char sysfs_path[PATH_MAX];
+ char name[4096];
+ char humanname[4096];
+ char temp_buf[4096];
+ int rindex;
+public:
+
+ alsa(const char *_name, const char *path);
+
+ virtual void start_measurement(void);
+ virtual void end_measurement(void);
+
+ virtual double utilization(void); /* percentage */
+
+ virtual const char * class_name(void) { return "alsa";};
+
+ virtual const char * device_name(void);
+ virtual const char * human_name(void);
+ virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+ virtual int power_valid(void) { return utilization_power_valid(rindex);};
+
+ virtual void register_power_with_devlist(struct result_bundle *results, struct parameter_bundle *bundle);
+ virtual int grouping_prio(void) { return 0; };
+
+};
+
+extern void create_all_alsa(void);
+
+
+#endif
diff --git a/src/devices/backlight.cpp b/src/devices/backlight.cpp
new file mode 100644
index 0000000..c73e4c9
--- /dev/null
+++ b/src/devices/backlight.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <limits.h>
+
+
+using namespace std;
+
+#include "device.h"
+#include "backlight.h"
+#include "../parameters/parameters.h"
+
+#include <string.h>
+
+
+backlight::backlight(const char *_name, const char *path): device()
+{
+ min_level = 0;
+ max_level = 0;
+ start_level = 0;
+ end_level = 0;
+ pt_strcpy(sysfs_path, path);
+ register_sysfs_path(sysfs_path);
+ snprintf(name, sizeof(name) - 1, "backlight:%s", _name);
+ r_index = get_result_index(name);
+ r_index_power = 0;
+}
+
+void backlight::start_measurement(void)
+{
+ char filename[PATH_MAX];
+ ifstream file;
+
+ snprintf(filename, sizeof(filename), "%s/max_brightness", sysfs_path);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> max_level;
+ }
+ file.close();
+
+ snprintf(filename, sizeof(filename), "%s/actual_brightness", sysfs_path);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> start_level;
+ file.close();
+ }
+}
+
+static int dpms_screen_on(void)
+{
+ DIR *dir;
+ struct dirent *entry;
+ char filename[PATH_MAX];
+ char line[4096];
+ ifstream file;
+
+ dir = opendir("/sys/class/drm/card0");
+ if (!dir)
+ return 1;
+ while (1) {
+ entry = readdir(dir);
+ if (!entry)
+ break;
+
+ if (strncmp(entry->d_name, "card", 4) != 0)
+ continue;
+ snprintf(filename, sizeof(filename), "/sys/class/drm/card0/%s/enabled", entry->d_name);
+ file.open(filename, ios::in);
+ if (!file)
+ continue;
+ file.getline(line, sizeof(line));
+ file.close();
+ if (strcmp(line, "enabled") != 0)
+ continue;
+ snprintf(filename, sizeof(filename), "/sys/class/drm/card0/%s/dpms", entry->d_name);
+ file.open(filename, ios::in);
+ if (!file)
+ continue;
+ file.getline(line, sizeof(line));
+ file.close();
+ if (strcmp(line, "On") == 0) {
+ closedir(dir);
+ return 1;
+ }
+ }
+ closedir(dir);
+ return 0;
+}
+
+void backlight::end_measurement(void)
+{
+ char filename[PATH_MAX];
+ char powername[4096];
+ ifstream file;
+ double p;
+ int _backlight = 0;
+
+ snprintf(filename, sizeof(filename), "%s/actual_brightness", sysfs_path);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> end_level;
+ }
+ file.close();
+
+ if (dpms_screen_on()) {
+ p = 100.0 * (end_level + start_level) / 2 / max_level;
+ _backlight = 100;
+ } else {
+ p = 0;
+ }
+
+ report_utilization(name, p);
+ snprintf(powername, sizeof(powername), "%s-power", name);
+ report_utilization(powername, _backlight);
+}
+
+
+double backlight::utilization(void)
+{
+ double p;
+
+ p = 100.0 * (end_level + start_level) / 2 / max_level;
+ return p;
+}
+
+const char * backlight::device_name(void)
+{
+ return name;
+}
+
+static void create_all_backlights_callback(const char *d_name)
+{
+ class backlight *bl;
+ char filename[PATH_MAX];
+ snprintf(filename, sizeof(filename), "/sys/class/backlight/%s", d_name);
+ bl = new class backlight(d_name, filename);
+ all_devices.push_back(bl);
+}
+
+void create_all_backlights(void)
+{
+ process_directory("/sys/class/backlight/", create_all_backlights_callback);
+ register_parameter("backlight");
+ register_parameter("backlight-power");
+ register_parameter("backlight-boost-40", 0, 0.5);
+ register_parameter("backlight-boost-80", 0, 0.5);
+ register_parameter("backlight-boost-100", 0, 0.5);
+}
+
+double backlight::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+ double power;
+ double factor;
+ double _utilization;
+ char powername[4096];
+ static int bl_index = 0, blp_index = 0, bl_boost_index40 = 0, bl_boost_index80, bl_boost_index100;
+
+ if (!bl_index)
+ bl_index = get_param_index("backlight");
+ if (!blp_index)
+ blp_index = get_param_index("backlight-power");
+ if (!bl_boost_index40)
+ bl_boost_index40 = get_param_index("backlight-boost-40");
+ if (!bl_boost_index80)
+ bl_boost_index80 = get_param_index("backlight-boost-80");
+ if (!bl_boost_index100)
+ bl_boost_index100 = get_param_index("backlight-boost-100");
+
+ power = 0;
+ factor = get_parameter_value(bl_index, bundle);
+ _utilization = get_result_value(r_index, result);
+
+ power += _utilization * factor / 100.0;
+
+ /*
+ * most machines have a non-linear backlight scale. to compensate, add a fixed value
+ * once the brightness hits 40% and 80%
+ */
+
+ if (_utilization >=99)
+ power += get_parameter_value(bl_boost_index100, bundle);
+ else if (_utilization >=80)
+ power += get_parameter_value(bl_boost_index80, bundle);
+ else if (_utilization >=40)
+ power += get_parameter_value(bl_boost_index40, bundle);
+
+ factor = get_parameter_value(blp_index, bundle);
+
+ if (!r_index_power) {
+ sprintf(powername, "%s-power", name);
+ r_index_power = get_result_index(powername);
+ }
+ _utilization = get_result_value(r_index_power, result);
+
+ power += _utilization * factor / 100.0;
+
+ return power;
+}
diff --git a/src/devices/backlight.h b/src/devices/backlight.h
new file mode 100644
index 0000000..1dac778
--- /dev/null
+++ b/src/devices/backlight.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_BACKLIGHT_H
+#define _INCLUDE_GUARD_BACKLIGHT_H
+
+#include <limits.h>
+
+#include "device.h"
+
+class backlight: public device {
+ int min_level, max_level;
+ int start_level, end_level;
+ char sysfs_path[PATH_MAX];
+ char name[4096];
+ int r_index;
+ int r_index_power;
+public:
+
+ backlight(const char *_name, const char *path);
+
+ virtual void start_measurement(void);
+ virtual void end_measurement(void);
+
+ virtual double utilization(void); /* percentage */
+
+ virtual const char * class_name(void) { return "backlight";};
+
+ virtual const char * device_name(void);
+ virtual const char * human_name(void) { return "Display backlight";};
+ virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+ virtual int grouping_prio(void) { return 10; };
+};
+
+extern void create_all_backlights(void);
+
+
+#endif
diff --git a/src/devices/devfreq.cpp b/src/devices/devfreq.cpp
new file mode 100644
index 0000000..b194ac4
--- /dev/null
+++ b/src/devices/devfreq.cpp
@@ -0,0 +1,334 @@
+/*
+ * 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()
+{
+ pt_strcpy(dir_name, dpath);
+}
+
+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];
+
+ snprintf(filename, sizeof(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)
+{
+ 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(readdir(dir) != NULL)
+ num++;
+
+ if (num == 2) {
+ fprintf(stderr, "Devfreq not enabled\n");
+ is_enabled = false;
+ closedir(dir);
+ dir = NULL;
+ 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, "%s", 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);
+ dir = NULL;
+ }
+}
diff --git a/src/devices/devfreq.h b/src/devices/devfreq.h
new file mode 100644
index 0000000..4a8983b
--- /dev/null
+++ b/src/devices/devfreq.h
@@ -0,0 +1,76 @@
+/*
+ * 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"
+#include <sys/time.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/devices/device.cpp b/src/devices/device.cpp
new file mode 100644
index 0000000..f191072
--- /dev/null
+++ b/src/devices/device.cpp
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "device.h"
+#include <vector>
+#include <algorithm>
+#include <stdio.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+using namespace std;
+
+#include "backlight.h"
+#include "usb.h"
+#include "ahci.h"
+#include "alsa.h"
+#include "rfkill.h"
+#include "i915-gpu.h"
+#include "thinkpad-fan.h"
+#include "thinkpad-light.h"
+#include "network.h"
+#include "runtime_pm.h"
+
+#include "../parameters/parameters.h"
+#include "../display.h"
+#include "../lib.h"
+#include "../report/report.h"
+#include "../report/report-maker.h"
+#include "../report/report-data-html.h"
+#include "../measurement/measurement.h"
+#include "../devlist.h"
+#include <unistd.h>
+
+device::device(void)
+{
+ cached_valid = 0;
+ hide = 0;
+
+ memset(guilty, 0, sizeof(guilty));
+ memset(real_path, 0, sizeof(real_path));
+}
+
+
+void device::register_sysfs_path(const char *path)
+{
+ char current_path[PATH_MAX + 1];
+ int iter = 0;
+ pt_strcpy(current_path, path);
+
+ while (iter++ < 10) {
+ char test_path[PATH_MAX + 1];
+ snprintf(test_path, sizeof(test_path), "%s/device", current_path);
+ if (access(test_path, R_OK) == 0)
+ strcpy(current_path, test_path);
+ else
+ break;
+ }
+
+ if (!realpath(current_path, real_path))
+ real_path[0] = 0;
+}
+
+void device::start_measurement(void)
+{
+ hide = false;
+}
+
+void device::end_measurement(void)
+{
+}
+
+double device::utilization(void)
+{
+ return 0.0;
+}
+
+
+
+vector<class device *> all_devices;
+
+
+void devices_start_measurement(void)
+{
+ unsigned int i;
+ for (i = 0; i < all_devices.size(); i++)
+ all_devices[i]->start_measurement();
+}
+
+void devices_end_measurement(void)
+{
+ unsigned int i;
+ for (i = 0; i < all_devices.size(); i++)
+ all_devices[i]->end_measurement();
+
+ clear_devpower();
+
+ for (i = 0; i < all_devices.size(); i++) {
+ all_devices[i]->hide = false;
+ all_devices[i]->register_power_with_devlist(&all_results, &all_parameters);
+ }
+}
+
+static bool power_device_sort(class device * i, class device * j)
+{
+ double pI, pJ;
+ pI = i->power_usage(&all_results, &all_parameters);
+ pJ = j->power_usage(&all_results, &all_parameters);
+
+ if (equals(pI, pJ)) {
+ int vI, vJ;
+ vI = i->power_valid();
+ vJ = j->power_valid();
+
+ if (vI != vJ)
+ return vI > vJ;
+
+ return i->utilization() > j->utilization();
+ }
+ return pI > pJ;
+}
+
+
+void report_devices(void)
+{
+ WINDOW *win;
+ unsigned int i;
+ int show_power;
+ double pw;
+
+ char util[128];
+ char power[128];
+
+ win = get_ncurses_win("Device stats");
+ if (!win)
+ return;
+
+ show_power = global_power_valid();
+
+ wclear(win);
+ wmove(win, 2,0);
+
+ sort(all_devices.begin(), all_devices.end(), power_device_sort);
+
+
+
+ pw = global_power();
+ if (pw > 0.0001) {
+ char buf[32];
+ wprintw(win, _("The battery reports a discharge rate of %sW\n"),
+ fmt_prefix(pw, buf));
+ wprintw(win, _("The energy consumed was %sJ\n"),
+ fmt_prefix(global_joules(), buf));
+ }
+
+ if (show_power) {
+ char buf[32];
+ wprintw(win, _("System baseline power is estimated at %sW\n"),
+ fmt_prefix(get_parameter_value("base power"), buf));
+ }
+
+ if (pw > 0.0001 || show_power)
+ wprintw(win, "\n");
+ if (show_power)
+ wprintw(win, _("Power est. Usage Device name\n"));
+ else
+ wprintw(win, _(" Usage Device name\n"));
+
+ for (i = 0; i < all_devices.size(); i++) {
+ double P;
+
+ util[0] = 0;
+
+ if (all_devices[i]->util_units()) {
+ if (all_devices[i]->utilization() < 1000)
+ sprintf(util, "%5.1f%s", all_devices[i]->utilization(), all_devices[i]->util_units());
+ else
+ sprintf(util, "%5i%s", (int)all_devices[i]->utilization(), all_devices[i]->util_units());
+ }
+ while (strlen(util) < 13) strcat(util, " ");
+
+ P = all_devices[i]->power_usage(&all_results, &all_parameters);
+
+ format_watts(P, power, 11);
+
+ if (!show_power || !all_devices[i]->power_valid())
+ strcpy(power, " ");
+
+
+ wprintw(win, "%s %s %s\n",
+ power,
+ util,
+ all_devices[i]->human_name()
+ );
+ }
+}
+
+void show_report_devices(void)
+{
+ unsigned int i;
+ int show_power, cols, rows, idx;
+ double pw;
+
+ show_power = global_power_valid();
+ sort(all_devices.begin(), all_devices.end(), power_device_sort);
+
+ /* div attr css_class and css_id */
+ tag_attr div_attr;
+ init_div(&div_attr, "clear_block", "devinfo");
+
+ /* Set Table attributes, rows, and cols */
+ table_attributes std_table_css;
+ cols=2;
+ if (show_power)
+ cols=3;
+
+ idx = cols;
+ rows= all_devices.size() + 1;
+ init_std_side_table_attr(&std_table_css, rows, cols);
+
+ /* Set Title attributes */
+ tag_attr title_attr;
+ init_title_attr(&title_attr);
+
+ /* Add section */
+ report.add_div(&div_attr);
+
+ /* Device Summary */
+ int summary_size=2;
+ string *summary = new string[summary_size];
+ pw = global_power();
+ char buf[32];
+ if (pw > 0.0001) {
+ summary[0]= __("The battery reports a discharge rate of: ");
+ summary[1]=string(fmt_prefix(pw, buf));
+ summary[1].append(" W");
+ report.add_summary_list(summary, summary_size);
+
+ summary[0]= __("The energy consumed was : ");
+ summary[1]=string(fmt_prefix(global_joules(), buf));
+ summary[1].append(" J");
+ report.add_summary_list(summary, summary_size);
+ }
+
+ if (show_power) {
+ summary[0]=__("The system baseline power is estimated at: ");
+ summary[1]=string(fmt_prefix(get_parameter_value("base power"), buf));
+ summary[1].append(" W");
+ report.add_summary_list(summary, summary_size);
+ }
+ delete [] summary;
+
+ /* Set array of data in row Major order */
+ string *device_data = new string[cols * rows];
+ device_data[0]= __("Usage");
+ device_data[1]= __("Device Name");
+ if (show_power)
+ device_data[2]= __("PW Estimate");
+
+ for (i = 0; i < all_devices.size(); i++) {
+ double P;
+ char util[128];
+ char power[128];
+
+ util[0] = 0;
+ if (all_devices[i]->util_units()) {
+ if (all_devices[i]->utilization() < 1000)
+ sprintf(util, "%5.1f%s",
+ all_devices[i]->utilization(),
+ all_devices[i]->util_units());
+ else
+ sprintf(util, "%5i%s",
+ (int)all_devices[i]->utilization(),
+ all_devices[i]->util_units());
+ }
+
+ P = all_devices[i]->power_usage(&all_results, &all_parameters);
+ format_watts(P, power, 11);
+
+ if (!show_power || !all_devices[i]->power_valid())
+ strcpy(power, " ");
+
+ device_data[idx]= string(util);
+ idx+=1;
+
+ device_data[idx]= string(all_devices[i]->human_name());
+ idx+=1;
+
+ if (show_power) {
+ device_data[idx]= string(power);
+ idx+=1;
+ }
+ }
+ /* Report Output */
+ report.add_title(&title_attr, __("Device Power Report"));
+ report.add_table(device_data, &std_table_css);
+ delete [] device_data;
+}
+
+
+void create_all_devices(void)
+{
+ create_all_backlights();
+ create_all_usb_devices();
+ create_all_ahcis();
+ create_all_alsa();
+ create_all_rfkills();
+ create_i915_gpu();
+ create_thinkpad_fan();
+ create_thinkpad_light();
+ create_all_nics();
+ create_all_runtime_pm_devices();
+}
+
+
+void clear_all_devices(void)
+{
+ unsigned int i;
+ for (i = 0; i < all_devices.size(); i++) {
+ delete all_devices[i];
+ }
+ all_devices.clear();
+}
diff --git a/src/devices/device.h b/src/devices/device.h
new file mode 100644
index 0000000..a373875
--- /dev/null
+++ b/src/devices/device.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_DEVICE_H
+#define _INCLUDE_GUARD_DEVICE_H
+
+
+#include <vector>
+#include <limits.h>
+
+struct parameter_bundle;
+struct result_bundle;
+
+class device {
+public:
+ int cached_valid;
+ bool hide;
+
+ char guilty[4096];
+ char real_path[PATH_MAX+1];
+
+ virtual void start_measurement(void);
+ virtual void end_measurement(void);
+
+ device(void);
+
+ virtual ~device() {};
+
+ void register_sysfs_path(const char *path);
+
+ virtual double utilization(void); /* percentage */
+
+ virtual const char * util_units(void) { return "%"; };
+
+ virtual const char * class_name(void) { return "abstract device";};
+ virtual const char * device_name(void) { return "abstract device";};
+
+ virtual const char * human_name(void) { return device_name(); };
+
+ virtual double power_usage(struct result_bundle *results, struct parameter_bundle *bundle) { return 0.0; };
+
+ virtual bool show_in_list(void) {return !hide;};
+
+ virtual int power_valid(void) { return 1;};
+
+ virtual void register_power_with_devlist(struct result_bundle *results, struct parameter_bundle *bundle) { ; };
+
+ virtual int grouping_prio(void) { return 0; }; /* priority of this device class if multiple classes match to the same underlying device. 0 is lowest */
+};
+
+using namespace std;
+
+extern vector<class device *> all_devices;
+
+extern void devices_start_measurement(void);
+extern void devices_end_measurement(void);
+extern void show_report_devices(void);
+extern void report_devices(void);
+
+
+extern void create_all_devices(void);
+extern void clear_all_devices(void);
+
+#endif
diff --git a/src/devices/gpu_rapl_device.cpp b/src/devices/gpu_rapl_device.cpp
new file mode 100644
index 0000000..71d71a0
--- /dev/null
+++ b/src/devices/gpu_rapl_device.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Srinivas Pandruvada<Srinivas.Pandruvada@linux.intel.com>
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "../parameters/parameters.h"
+#include "gpu_rapl_device.h"
+
+gpu_rapl_device::gpu_rapl_device(i915gpu *parent)
+ : i915gpu(),
+ device_valid(false)
+{
+ last_time = time(NULL);
+ if (rapl.pp1_domain_present()) {
+ device_valid = true;
+ parent->add_child(this);
+ rapl.get_pp1_energy_status(&last_energy);
+ }
+}
+
+void gpu_rapl_device::start_measurement(void)
+{
+ last_time = time(NULL);
+
+ rapl.get_pp1_energy_status(&last_energy);
+}
+
+void gpu_rapl_device::end_measurement(void)
+{
+ time_t curr_time = time(NULL);
+ double energy;
+
+ consumed_power = 0.0;
+ if ((curr_time - last_time) > 0) {
+ rapl.get_pp1_energy_status(&energy);
+ consumed_power = (energy-last_energy)/(curr_time-last_time);
+ last_energy = energy;
+ last_time = curr_time;
+ }
+}
+
+double gpu_rapl_device::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+ if (rapl.pp1_domain_present())
+ return consumed_power;
+ else
+ return 0.0;
+}
diff --git a/src/devices/gpu_rapl_device.h b/src/devices/gpu_rapl_device.h
new file mode 100644
index 0000000..fbde246
--- /dev/null
+++ b/src/devices/gpu_rapl_device.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Srinivas Pandruvada <Srinivas.Pandruvada@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_GPU_RAPL_DEVICE_H
+#define _INCLUDE_GUARD_GPU_RAPL_DEVICE_H
+
+#include <vector>
+#include <string>
+
+using namespace std;
+
+#include <sys/time.h>
+#include "i915-gpu.h"
+#include "cpu/rapl/rapl_interface.h"
+
+class gpu_rapl_device: public i915gpu {
+
+ c_rapl_interface rapl;
+ time_t last_time;
+ double last_energy;
+ double consumed_power;
+ bool device_valid;
+
+public:
+ gpu_rapl_device(i915gpu *parent);
+ virtual const char * class_name(void) { return "GPU core";};
+ virtual const char * device_name(void) { return "GPU core";};
+ bool device_present() { return device_valid;}
+ virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+ virtual void start_measurement(void);
+ virtual void end_measurement(void);
+
+};
+
+
+#endif
diff --git a/src/devices/i915-gpu.cpp b/src/devices/i915-gpu.cpp
new file mode 100644
index 0000000..d0f1d69
--- /dev/null
+++ b/src/devices/i915-gpu.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <limits.h>
+#include "../lib.h"
+
+using namespace std;
+
+#include "device.h"
+#include "i915-gpu.h"
+#include "../parameters/parameters.h"
+#include "../process/powerconsumer.h"
+#include "gpu_rapl_device.h"
+
+#include <string.h>
+#include <unistd.h>
+
+i915gpu::i915gpu(): device()
+{
+ index = get_param_index("gpu-operations");
+ rindex = get_result_index("gpu-operations");
+}
+
+const char * i915gpu::device_name(void)
+{
+ if (child_devices.size())
+ return "GPU misc";
+ else
+ return "GPU";
+}
+
+void i915gpu::start_measurement(void)
+{
+}
+
+void i915gpu::end_measurement(void)
+{
+}
+
+
+double i915gpu::utilization(void)
+{
+ return get_result_value(rindex);
+
+}
+
+void create_i915_gpu(void)
+{
+ char filename[PATH_MAX];
+ class i915gpu *gpu;
+ gpu_rapl_device *rapl_dev;
+
+ pt_strcpy(filename, "/sys/kernel/debug/tracing/events/i915/i915_gem_ring_dispatch/format");
+
+ if (access(filename, R_OK) !=0) {
+ /* try an older tracepoint */
+ pt_strcpy(filename, "/sys/kernel/debug/tracing/events/i915/i915_gem_request_submit/format");
+ if (access(filename, R_OK) != 0)
+ return;
+ }
+
+ register_parameter("gpu-operations");
+
+ gpu = new class i915gpu();
+ all_devices.push_back(gpu);
+
+ rapl_dev = new class gpu_rapl_device(gpu);
+ if (rapl_dev->device_present())
+ all_devices.push_back(rapl_dev);
+}
+
+
+
+double i915gpu::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+ double power;
+ double factor;
+ double util;
+ double child_power;
+
+ power = 0;
+ factor = get_parameter_value(index, bundle);
+ util = get_result_value(rindex, result);
+
+ power += util * factor / 100.0;
+ for (unsigned int i = 0; i < child_devices.size(); ++i) {
+ child_power = child_devices[i]->power_usage(result, bundle);
+ if ((power - child_power) > 0.0)
+ power -= child_power;
+ }
+
+ return power;
+}
diff --git a/src/devices/i915-gpu.h b/src/devices/i915-gpu.h
new file mode 100644
index 0000000..7653b94
--- /dev/null
+++ b/src/devices/i915-gpu.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_i915_GPU_H
+#define _INCLUDE_GUARD_i915_GPU_H
+
+
+#include "device.h"
+
+class i915gpu: public device {
+ int index;
+ int rindex;
+ vector<device *>child_devices;
+
+public:
+
+ i915gpu();
+
+ virtual void start_measurement(void);
+ virtual void end_measurement(void);
+
+ virtual double utilization(void); /* percentage */
+
+ virtual const char * class_name(void) { return "GPU";};
+
+ virtual const char * device_name(void);
+ virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+ virtual bool show_in_list(void) {return false;};
+ virtual const char * util_units(void) { return " ops/s"; };
+
+ virtual void add_child(device *dev_ptr) { child_devices.push_back(dev_ptr);}
+};
+
+extern void create_i915_gpu(void);
+
+
+#endif \ No newline at end of file
diff --git a/src/devices/network.cpp b/src/devices/network.cpp
new file mode 100644
index 0000000..8087b7f
--- /dev/null
+++ b/src/devices/network.cpp
@@ -0,0 +1,441 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <string>
+#include <map>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <linux/ethtool.h>
+
+using namespace std;
+
+#include "device.h"
+#include "network.h"
+#include "../lib.h"
+#include "../parameters/parameters.h"
+#include "../process/process.h"
+extern "C" {
+#include "../tuning/iw.h"
+}
+
+#include <string.h>
+#include <net/if.h>
+#include <linux/sockios.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+static map<string, class network *> nics;
+
+#ifdef DISABLE_TRYCATCH
+
+static inline void ethtool_cmd_speed_set(struct ethtool_cmd *ep,
+ __u32 speed)
+{
+
+ ep->speed = (__u16)speed;
+ ep->speed_hi = (__u16)(speed >> 16);
+}
+
+static inline __u32 ethtool_cmd_speed(struct ethtool_cmd *ep)
+{
+ return (ep->speed_hi << 16) | ep->speed;
+}
+
+#endif
+
+static void do_proc_net_dev(void)
+{
+ static time_t last_time;
+ class network *dev;
+ ifstream file;
+ char line[4096];
+ char *c, *c2;
+
+ if (time(NULL) == last_time)
+ return;
+
+ last_time = time(NULL);
+
+ file.open("/proc/net/dev", ios::in);
+ if (!file)
+ return;
+
+ file.getline(line, 4096);
+ file.getline(line, 4096);
+
+ while (file) {
+ int i = 0;
+ unsigned long val = 0;
+ uint64_t pkt = 0;
+ file.getline(line, 4096);
+ c = strchr(line, ':');
+ if (!c)
+ continue;
+ *c = 0;
+ c2 = c +1;
+ c = line; while (c && *c == ' ') c++;
+ /* c now points to the name of the nic */
+
+ dev = nics[c];
+ if (!dev)
+ continue;
+
+ c = c2++;
+ while (c != c2 && strlen(c) > 0) {
+ c2 = c;
+ val = strtoull(c, &c, 10);
+ i++;
+ if (i == 2 || i == 10)
+ pkt += val;
+
+ }
+ dev->pkts = pkt;
+ }
+ file.close();
+}
+
+
+network::network(const char *_name, const char *path): device()
+{
+ char line[4096];
+ std::string filename(path);
+ char devname[128];
+ start_up = 0;
+ end_up = 0;
+ start_speed = 0;
+ end_speed = 0;
+ start_pkts = 0;
+ end_pkts = 0;
+ pkts = 0;
+ valid_100 = -1;
+ valid_1000 = -1;
+ valid_high = -1;
+ valid_powerunsave = -1;
+
+ pt_strcpy(sysfs_path, path);
+ register_sysfs_path(sysfs_path);
+ pt_strcpy(devname, _name);
+ sprintf(humanname, "nic:%s", _name);
+ pt_strcpy(name, devname);
+
+ snprintf(devname, sizeof(devname), "%s-up", _name);
+ index_up = get_param_index(devname);
+ rindex_up = get_result_index(devname);
+
+ snprintf(devname, sizeof(devname), "%s-powerunsave", _name);
+ index_powerunsave = get_param_index(devname);
+ rindex_powerunsave = get_result_index(devname);
+
+ snprintf(devname, sizeof(devname), "%s-link-100", _name);
+ index_link_100 = get_param_index(devname);
+ rindex_link_100 = get_result_index(devname);
+
+ snprintf(devname, sizeof(devname), "%s-link-1000", _name);
+ index_link_1000 = get_param_index(devname);
+ rindex_link_1000 = get_result_index(devname);
+
+ snprintf(devname, sizeof(devname), "%s-link-high", _name);
+ index_link_high = get_param_index(devname);
+ rindex_link_high = get_result_index(devname);
+
+ snprintf(devname, sizeof(devname), "%s-packets", _name);
+ index_pkts = get_param_index(devname);
+ rindex_pkts = get_result_index(devname);
+
+ memset(line, 0, 4096);
+ filename.append("/device/driver");
+ if (readlink(filename.c_str(), line, 4096) > 0) {
+ snprintf(humanname, sizeof(humanname), _("Network interface: %s (%s)"), _name, basename(line));
+ };
+}
+
+static int net_iface_up(const char *iface)
+{
+ int sock;
+ struct ifreq ifr;
+ int ret;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock<0)
+ return 0;
+
+ pt_strcpy(ifr.ifr_name, iface);
+
+ /* Check if the interface is up */
+ ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
+ if (ret<0) {
+ close(sock);
+ return 0;
+ }
+
+ if (ifr.ifr_flags & (IFF_UP | IFF_RUNNING)) {
+ close(sock);
+ return 1;
+ }
+
+ close(sock);
+
+ return 0;
+}
+
+static int iface_link(const char *name)
+{
+ int sock;
+ struct ifreq ifr;
+ struct ethtool_value cmd;
+ int link;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock<0)
+ return 0;
+
+ pt_strcpy(ifr.ifr_name, name);
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ cmd.cmd = ETHTOOL_GLINK;
+ ifr.ifr_data = (caddr_t)&cmd;
+ ioctl(sock, SIOCETHTOOL, &ifr);
+ close(sock);
+
+ link = cmd.data;
+
+ return link;
+}
+
+
+static int iface_speed(const char *name)
+{
+ int sock;
+ struct ifreq ifr;
+ struct ethtool_cmd cmd;
+ int speed;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock<0)
+ return 0;
+
+ pt_strcpy(ifr.ifr_name, name);
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ cmd.cmd = ETHTOOL_GSET;
+ ifr.ifr_data = (caddr_t)&cmd;
+ ioctl(sock, SIOCETHTOOL, &ifr);
+ close(sock);
+
+ speed = ethtool_cmd_speed(&cmd);
+
+
+ if (speed > 0 && speed <= 100)
+ speed = 100;
+ if (speed > 100 && speed <= 1000)
+ speed = 1000;
+ if (speed == 65535 || !iface_link(name))
+ speed = 0; /* no link */
+
+ return speed;
+}
+
+void network::start_measurement(void)
+{
+ start_up = 1;
+ start_speed = 0;
+ end_up = 1;
+ end_speed = 0;
+
+ start_speed = iface_speed(name);
+
+ start_up = net_iface_up(name);
+
+ do_proc_net_dev();
+ start_pkts = pkts;
+
+ gettimeofday(&before, NULL);
+}
+
+
+void network::end_measurement(void)
+{
+ int u_100, u_1000, u_high, u_powerunsave;
+
+ gettimeofday(&after, NULL);
+
+ end_speed = iface_speed(name);
+ end_up = net_iface_up(name);
+ do_proc_net_dev();
+ end_pkts = pkts;
+
+ duration = (after.tv_sec - before.tv_sec) + (after.tv_usec - before.tv_usec) / 1000000.0;
+
+ u_100 = 0;
+ u_1000 = 0;
+ u_high = 0;
+
+ if (start_speed == 100)
+ u_100 += 50;
+ if (start_speed == 1000)
+ u_1000 += 50;
+ if (start_speed > 1000)
+ u_high += 50;
+ if (end_speed == 100)
+ u_100 += 50;
+ if (end_speed == 1000)
+ u_1000 += 50;
+ if (end_speed > 1000)
+ u_high += 50;
+
+ if (start_pkts > end_pkts)
+ end_pkts = start_pkts;
+
+ u_powerunsave = 100 - 100 * get_wifi_power_saving(name);
+
+ report_utilization(rindex_link_100, u_100);
+ report_utilization(rindex_link_1000, u_1000);
+ report_utilization(rindex_link_high, u_high);
+ report_utilization(rindex_up, (start_up+end_up) / 2.0);
+ report_utilization(rindex_pkts, (end_pkts - start_pkts)/(duration + 0.001));
+ report_utilization(rindex_powerunsave, u_powerunsave);
+}
+
+
+double network::utilization(void)
+{
+ return (end_pkts - start_pkts) / (duration + 0.001);
+}
+
+const char * network::device_name(void)
+{
+ return name;
+}
+
+static void netdev_callback(const char *d_name)
+{
+ char devname[128];
+
+ std::string f_name("/sys/class/net/");
+ if (strcmp(d_name, "lo") == 0)
+ return;
+
+ f_name.append(d_name);
+
+ snprintf(devname, sizeof(devname), "%s-up", d_name);
+ register_parameter(devname);
+
+ snprintf(devname, sizeof(devname), "%s-powerunsave", d_name);
+ register_parameter(devname);
+
+ snprintf(devname, sizeof(devname), "%s-link-100", d_name);
+ register_parameter(devname);
+
+ snprintf(devname, sizeof(devname), "%s-link-1000", d_name);
+ register_parameter(devname);
+
+ snprintf(devname, sizeof(devname), "%s-link-high", d_name);
+ register_parameter(devname);
+
+ snprintf(devname, sizeof(devname), "%s-packets", d_name);
+ register_parameter(devname);
+
+ network *bl = new(std::nothrow) class network(d_name, f_name.c_str());
+ if (bl) {
+ all_devices.push_back(bl);
+ nics[d_name] = bl;
+ }
+}
+
+void create_all_nics(callback fn)
+{
+ if (!fn)
+ fn = &netdev_callback;
+ process_directory("/sys/class/net/", fn);
+}
+
+double network::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+ double power;
+ double factor;
+ double util;
+
+ power = 0;
+ factor = get_parameter_value(index_up, bundle);
+ util = get_result_value(rindex_up, result);
+
+ power += util * factor;
+
+ if (valid_100 == -1) {
+ valid_100 = utilization_power_valid(rindex_link_100);
+ valid_1000 = utilization_power_valid(rindex_link_1000);
+ valid_high = utilization_power_valid(rindex_link_high);
+ valid_powerunsave = utilization_power_valid(rindex_powerunsave);
+ }
+
+ if (valid_100 > 0) {
+ factor = get_parameter_value(index_link_100, bundle);
+ util = get_result_value(rindex_link_100, result);
+ power += util * factor / 100;
+ }
+
+
+ if (valid_1000 > 0) {
+ factor = get_parameter_value(index_link_1000, bundle);
+ util = get_result_value(rindex_link_1000, result);
+ power += util * factor / 100;
+ }
+
+ if (valid_high > 0) {
+ factor = get_parameter_value(index_link_high, bundle);
+ util = get_result_value(rindex_link_high, result);
+ power += util * factor / 100;
+ }
+
+ if (valid_powerunsave > 0) {
+ factor = get_parameter_value(index_powerunsave, bundle);
+ util = get_result_value(rindex_powerunsave, result);
+ power += util * factor / 100;
+ }
+
+ factor = get_parameter_value(index_pkts, bundle);
+ util = get_result_value(rindex_pkts, result);
+ if (util > 5000)
+ util = 5000;
+
+ power += util * factor / 100;
+
+ return power;
+}
diff --git a/src/devices/network.h b/src/devices/network.h
new file mode 100644
index 0000000..7fb4cc6
--- /dev/null
+++ b/src/devices/network.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_NETWORK_H
+#define _INCLUDE_GUARD_NETWORK_H
+
+#include <sys/time.h>
+#include <limits.h>
+
+#include "device.h"
+#include "../parameters/parameters.h"
+
+class network: public device {
+ int start_up, end_up;
+ uint64_t start_pkts, end_pkts;
+ struct timeval before, after;
+
+ int start_speed; /* 0 is "no link" */
+ int end_speed; /* 0 is "no link" */
+
+ char sysfs_path[PATH_MAX];
+ char name[4096];
+ char humanname[4096];
+ int index_up;
+ int rindex_up;
+ int index_link_100;
+ int rindex_link_100;
+ int index_link_1000;
+ int rindex_link_1000;
+ int index_link_high;
+ int rindex_link_high;
+ int index_pkts;
+ int rindex_pkts;
+ int index_powerunsave;
+ int rindex_powerunsave;
+
+ int valid_100;
+ int valid_1000;
+ int valid_high;
+ int valid_powerunsave;
+public:
+ uint64_t pkts;
+ double duration;
+
+ network(const char *_name, const char *path);
+
+ virtual void start_measurement(void);
+ virtual void end_measurement(void);
+
+ virtual double utilization(void);
+ virtual const char * util_units(void) { return " pkts/s"; };
+
+ virtual const char * class_name(void) { return "ethernet";};
+
+ virtual const char * device_name(void);
+ virtual const char * human_name(void) { return humanname; };
+ virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+ virtual int power_valid(void) { return utilization_power_valid(rindex_up) + utilization_power_valid(rindex_link_100) + utilization_power_valid(rindex_link_1000) + utilization_power_valid(rindex_link_high);};
+ virtual int grouping_prio(void) { return 10; };
+};
+
+extern void create_all_nics(callback fn = NULL);
+
+#endif
diff --git a/src/devices/rfkill.cpp b/src/devices/rfkill.cpp
new file mode 100644
index 0000000..99a652f
--- /dev/null
+++ b/src/devices/rfkill.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <limits.h>
+
+
+using namespace std;
+
+#include "device.h"
+#include "rfkill.h"
+#include "../parameters/parameters.h"
+
+#include <string.h>
+#include <unistd.h>
+
+rfkill::rfkill(char *_name, char *path): device()
+{
+ char line[4096];
+ char filename[PATH_MAX];
+ char devname[128];
+ start_soft = 0;
+ start_hard = 0;
+ end_soft = 0;
+ end_hard = 0;
+ pt_strcpy(sysfs_path, path);
+ register_sysfs_path(sysfs_path);
+ snprintf(devname, sizeof(devname), "radio:%s", _name);
+ snprintf(humanname, sizeof(humanname), "radio:%s", _name);
+ pt_strcpy(name, devname);
+ register_parameter(devname);
+ index = get_param_index(devname);
+ rindex = get_result_index(name);
+
+ memset(line, 0, 4096);
+ snprintf(filename, sizeof(filename), "%s/device/driver", path);
+ if (readlink(filename, line, sizeof(line)) > 0) {
+ snprintf(humanname, sizeof(humanname), _("Radio device: %s"), basename(line));
+ }
+ snprintf(filename, sizeof(filename), "%s/device/device/driver", path);
+ if (readlink(filename, line, sizeof(line)) > 0) {
+ snprintf(humanname, sizeof(humanname), _("Radio device: %s"), basename(line));
+ }
+}
+
+void rfkill::start_measurement(void)
+{
+ char filename[PATH_MAX];
+ ifstream file;
+
+ start_hard = 1;
+ start_soft = 1;
+ end_hard = 1;
+ end_soft = 1;
+
+ snprintf(filename, sizeof(filename), "%s/hard", sysfs_path);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> start_hard;
+ }
+ file.close();
+
+ snprintf(filename, sizeof(filename), "%s/soft", sysfs_path);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> start_soft;
+ }
+ file.close();
+}
+
+void rfkill::end_measurement(void)
+{
+ char filename[PATH_MAX];
+ ifstream file;
+
+ snprintf(filename, sizeof(filename), "%s/hard", sysfs_path);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> end_hard;
+ }
+ file.close();
+ snprintf(filename, sizeof(filename), "%s/soft", sysfs_path);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> end_soft;
+ }
+ file.close();
+
+ report_utilization(name, utilization());
+}
+
+
+double rfkill::utilization(void)
+{
+ double p;
+ int rfk;
+
+ rfk = start_soft+end_soft;
+ if (rfk < start_hard+end_hard)
+ rfk = start_hard+end_hard;
+
+ p = 100 - 50.0 * rfk;
+
+ return p;
+}
+
+const char * rfkill::device_name(void)
+{
+ return name;
+}
+
+static void create_all_rfkills_callback(const char *d_name)
+{
+ char filename[PATH_MAX];
+ char name[4096] = {0};
+ class rfkill *bl;
+ ifstream file;
+
+ snprintf(filename, sizeof(filename), "/sys/class/rfkill/%s/name", d_name);
+ strncpy(name, d_name, sizeof(name) - 1);
+ file.open(filename, ios::in);
+ if (file) {
+ file.getline(name, 100);
+ file.close();
+ }
+
+ snprintf(filename, sizeof(filename), "/sys/class/rfkill/%s", d_name);
+ bl = new class rfkill(name, filename);
+ all_devices.push_back(bl);
+}
+
+void create_all_rfkills(void)
+{
+ process_directory("/sys/class/rfkill/", create_all_rfkills_callback);
+}
+
+double rfkill::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+ double power;
+ double factor;
+ double util;
+
+ power = 0;
+ factor = get_parameter_value(index, bundle);
+ util = get_result_value(rindex, result);
+
+ power += util * factor / 100.0;
+
+ return power;
+}
diff --git a/src/devices/rfkill.h b/src/devices/rfkill.h
new file mode 100644
index 0000000..429ba18
--- /dev/null
+++ b/src/devices/rfkill.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_RFKILL_H
+#define _INCLUDE_GUARD_RFKILL_H
+
+#include <limits.h>
+
+#include "device.h"
+#include "../parameters/parameters.h"
+
+class rfkill: public device {
+ int start_soft, end_soft;
+ int start_hard, end_hard;
+ char sysfs_path[PATH_MAX];
+ char name[4096];
+ char humanname[4096];
+ int index;
+ int rindex;
+public:
+
+ rfkill(char *_name, char *path);
+
+ virtual void start_measurement(void);
+ virtual void end_measurement(void);
+
+ virtual double utilization(void); /* percentage */
+
+ virtual const char * class_name(void) { return "radio";};
+
+ virtual const char * device_name(void);
+ virtual const char * human_name(void) { return humanname; };
+ virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+ virtual int power_valid(void) { return utilization_power_valid(rindex);};
+ virtual int grouping_prio(void) { return 5; };
+};
+
+extern void create_all_rfkills(void);
+
+
+#endif \ No newline at end of file
diff --git a/src/devices/runtime_pm.cpp b/src/devices/runtime_pm.cpp
new file mode 100644
index 0000000..26f9d32
--- /dev/null
+++ b/src/devices/runtime_pm.cpp
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "runtime_pm.h"
+
+#include <string.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <limits.h>
+
+#include "../parameters/parameters.h"
+#include "../lib.h"
+
+#include <iostream>
+#include <fstream>
+
+runtime_pmdevice::runtime_pmdevice(const char *_name, const char *path) : device()
+{
+ pt_strcpy(sysfs_path, path);
+ register_sysfs_path(sysfs_path);
+ pt_strcpy(name, _name);
+ snprintf(humanname, sizeof(humanname), "runtime-%s", _name);
+
+ index = get_param_index(humanname);
+ r_index = get_result_index(humanname);
+
+ before_suspended_time = 0;
+ before_active_time = 0;
+ after_suspended_time = 0;
+ after_active_time = 0;
+
+ register_parameter(humanname);
+}
+
+void runtime_pmdevice::start_measurement(void)
+{
+ char filename[PATH_MAX];
+ ifstream file;
+
+ before_suspended_time = 0;
+ before_active_time = 0;
+ after_suspended_time = 0;
+ after_active_time = 0;
+
+ snprintf(filename, sizeof(filename), "%s/power/runtime_suspended_time", sysfs_path);
+ file.open(filename, ios::in);
+ if (!file)
+ return;
+ file >> before_suspended_time;
+ file.close();
+
+ snprintf(filename, sizeof(filename), "%s/power/runtime_active_time", sysfs_path);
+ file.open(filename, ios::in);
+ if (!file)
+ return;
+ file >> before_active_time;
+ file.close();
+}
+
+void runtime_pmdevice::end_measurement(void)
+{
+ char filename[PATH_MAX];
+ ifstream file;
+
+ snprintf(filename, sizeof(filename), "%s/power/runtime_suspended_time", sysfs_path);
+ file.open(filename, ios::in);
+ if (!file)
+ return;
+ file >> after_suspended_time;
+ file.close();
+
+ snprintf(filename, sizeof(filename), "%s/power/runtime_active_time", sysfs_path);
+ file.open(filename, ios::in);
+ if (!file)
+ return;
+ file >> after_active_time;
+ file.close();
+}
+
+double runtime_pmdevice::utilization(void) /* percentage */
+{
+ double d;
+ d = 100 * (after_active_time - before_active_time) / (0.0001 + after_active_time - before_active_time + after_suspended_time - before_suspended_time);
+
+ if (d < 0.00)
+ d = 0.0;
+ if (d > 99.9)
+ d = 100.0;
+ return d;
+}
+
+const char * runtime_pmdevice::device_name(void)
+{
+ return name;
+}
+
+const char * runtime_pmdevice::human_name(void)
+{
+ return humanname;
+}
+
+
+double runtime_pmdevice::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+ double power;
+ double factor;
+ double util;
+
+ power = 0;
+
+ factor = get_parameter_value(index, bundle);
+ util = get_result_value(r_index, result);
+ power += util * factor / 100.0;
+
+ return power;
+}
+
+void runtime_pmdevice::set_human_name(char *_name)
+{
+ pt_strcpy(humanname, _name);
+}
+
+
+int device_has_runtime_pm(const char *sysfs_path)
+{
+ char filename[PATH_MAX];
+ ifstream file;
+ unsigned long value;
+
+ snprintf(filename, sizeof(filename), "%s/power/runtime_suspended_time", sysfs_path);
+ file.open(filename, ios::in);
+ if (!file)
+ return 0;
+ file >> value;
+ file.close();
+ if (value)
+ return 1;
+
+ snprintf(filename, sizeof(filename), "%s/power/runtime_active_time", sysfs_path);
+ file.open(filename, ios::in);
+ if (!file)
+ return 0;
+ file >> value;
+ file.close();
+ if (value)
+ return 1;
+
+ return 0;
+}
+
+static void do_bus(const char *bus)
+{
+ /* /sys/bus/pci/devices/0000\:00\:1f.0/power/runtime_suspended_time */
+
+ struct dirent *entry;
+ DIR *dir;
+ char filename[PATH_MAX];
+
+ snprintf(filename, sizeof(filename), "/sys/bus/%s/devices/", bus);
+ dir = opendir(filename);
+ if (!dir)
+ return;
+ while (1) {
+ ifstream file;
+ class runtime_pmdevice *dev;
+ entry = readdir(dir);
+
+ if (!entry)
+ break;
+ if (entry->d_name[0] == '.')
+ continue;
+
+ snprintf(filename, sizeof(filename), "/sys/bus/%s/devices/%s", bus, entry->d_name);
+ dev = new class runtime_pmdevice(entry->d_name, filename);
+
+ if (strcmp(bus, "i2c") == 0) {
+ string devname;
+ char dev_name[4096];
+ bool is_adapter = false;
+
+ snprintf(filename, sizeof(filename), "/sys/bus/%s/devices/%s/new_device", bus, entry->d_name);
+ if (access(filename, W_OK) == 0)
+ is_adapter = true;
+
+ snprintf(filename, sizeof(filename), "/sys/bus/%s/devices/%s/name", bus, entry->d_name);
+ file.open(filename, ios::in);
+ if (file) {
+ getline(file, devname);
+ file.close();
+ }
+
+ snprintf(dev_name, sizeof(dev_name), _("I2C %s (%s): %s"), (is_adapter ? _("Adapter") : _("Device")), entry->d_name, devname.c_str());
+ dev->set_human_name(dev_name);
+ }
+
+ if (strcmp(bus, "pci") == 0) {
+ uint16_t vendor = 0, device = 0;
+
+ snprintf(filename, sizeof(filename), "/sys/bus/%s/devices/%s/vendor", bus, entry->d_name);
+
+ file.open(filename, ios::in);
+ if (file) {
+ file >> hex >> vendor;
+ file.close();
+ }
+
+
+ snprintf(filename, sizeof(filename), "/sys/bus/%s/devices/%s/device", bus, entry->d_name);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> hex >> device;
+ file.close();
+ }
+
+ if (vendor && device) {
+ char devname[4096];
+ snprintf(devname, sizeof(devname), _("PCI Device: %s"),
+ pci_id_to_name(vendor, device, filename, 4095));
+ dev->set_human_name(devname);
+ }
+ }
+ all_devices.push_back(dev);
+ }
+ closedir(dir);
+}
+
+void create_all_runtime_pm_devices(void)
+{
+ do_bus("pci");
+ do_bus("spi");
+ do_bus("platform");
+ do_bus("i2c");
+}
diff --git a/src/devices/runtime_pm.h b/src/devices/runtime_pm.h
new file mode 100644
index 0000000..77bf398
--- /dev/null
+++ b/src/devices/runtime_pm.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_RUNTIMEPM_H
+#define _INCLUDE_GUARD_RUNTIMEPM_H
+
+#include <limits.h>
+
+#include "device.h"
+#include "../parameters/parameters.h"
+
+class runtime_pmdevice: public device {
+ uint64_t before_suspended_time, before_active_time;
+ uint64_t after_suspended_time, after_active_time;
+ char sysfs_path[PATH_MAX];
+ char name[4096];
+ char humanname[4096];
+ int index;
+ int r_index;
+public:
+
+ runtime_pmdevice(const char *_name, const char *path);
+
+ virtual void start_measurement(void);
+ virtual void end_measurement(void);
+
+ virtual double utilization(void); /* percentage */
+
+ virtual const char * class_name(void) { return "runtime_pm";};
+
+ virtual const char * device_name(void);
+ virtual const char * human_name(void);
+ virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+ virtual int power_valid(void) { return utilization_power_valid(r_index);};
+
+ void set_human_name(char *name);
+ virtual int grouping_prio(void) { return 1; };
+};
+
+extern void create_all_runtime_pm_devices(void);
+
+extern int device_has_runtime_pm(const char *sysfs_path);
+
+
+#endif \ No newline at end of file
diff --git a/src/devices/thinkpad-fan.cpp b/src/devices/thinkpad-fan.cpp
new file mode 100644
index 0000000..8e2ce53
--- /dev/null
+++ b/src/devices/thinkpad-fan.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <math.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "../lib.h"
+
+
+#include "device.h"
+#include "thinkpad-fan.h"
+#include "../parameters/parameters.h"
+#include "../process/powerconsumer.h"
+
+#include <string.h>
+#include <unistd.h>
+
+thinkpad_fan::thinkpad_fan(): device()
+{
+ start_rate = 0;
+ end_rate = 0;
+ fan_index = get_param_index("thinkpad-fan");
+ fansqr_index = get_param_index("thinkpad-fan-sqr");
+ fancub_index = get_param_index("thinkpad-fan-cub");
+ r_index = get_result_index("thinkpad-fan");
+ register_sysfs_path("/sys/devices/platform/thinkpad_hwmon");
+}
+
+void thinkpad_fan::start_measurement(void)
+{
+ /* read the rpms of the fan */
+ start_rate = read_sysfs("/sys/devices/platform/thinkpad_hwmon/fan1_input");
+}
+
+void thinkpad_fan::end_measurement(void)
+{
+ end_rate = read_sysfs("/sys/devices/platform/thinkpad_hwmon/fan1_input");
+
+ report_utilization("thinkpad-fan", utilization());
+}
+
+
+double thinkpad_fan::utilization(void)
+{
+ return (start_rate+end_rate) / 2;
+}
+
+void create_thinkpad_fan(void)
+{
+ char filename[PATH_MAX];
+ class thinkpad_fan *fan;
+
+ pt_strcpy(filename, "/sys/devices/platform/thinkpad_hwmon/fan1_input");
+
+ if (access(filename, R_OK) !=0)
+ return;
+
+ register_parameter("thinkpad-fan", 10);
+ register_parameter("thinkpad-fan-sqr", 5);
+ register_parameter("thinkpad-fan-cub", 10);
+
+ fan = new class thinkpad_fan();
+ all_devices.push_back(fan);
+}
+
+
+
+double thinkpad_fan::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+ double power;
+ double factor;
+ double util;
+
+
+ power = 0;
+ util = get_result_value(r_index, result);
+
+ if (util < 0)
+ util = 0;
+
+
+ /* physics dictact that fan power goes cubic with the rpms, but there's also a linear component for friction*/
+ factor = get_parameter_value(fancub_index, bundle);
+ power += factor * pow(util / 3600.0, 3);
+
+ factor = get_parameter_value(fansqr_index, bundle) - 5.0;
+ power += factor * pow(util / 3600.0, 2);
+
+ factor = get_parameter_value(fan_index, bundle) - 10.0;
+ power += util / 5000.0 * factor;
+
+ if (power <= 0.0)
+ power = 0.0;
+
+ return power;
+}
diff --git a/src/devices/thinkpad-fan.h b/src/devices/thinkpad-fan.h
new file mode 100644
index 0000000..34c4c43
--- /dev/null
+++ b/src/devices/thinkpad-fan.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_THINKPAD_FAN_H
+#define _INCLUDE_GUARD_THINKPAD_FAN_H
+
+
+#include "device.h"
+#include "../parameters/parameters.h"
+
+class thinkpad_fan: public device {
+ double start_rate, end_rate;
+ int fan_index, fansqr_index, fancub_index;
+ int r_index;
+public:
+
+ thinkpad_fan();
+
+ virtual void start_measurement(void);
+ virtual void end_measurement(void);
+
+ virtual double utilization(void); /* percentage */
+
+ virtual const char * class_name(void) { return "fan";};
+
+ virtual const char * device_name(void) { return "Fan-1";};
+ virtual const char * human_name(void) { return "Laptop fan";};
+ 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 utilization_power_valid(r_index);};
+ virtual int grouping_prio(void) { return 1; };
+};
+
+extern void create_thinkpad_fan(void);
+
+
+#endif \ No newline at end of file
diff --git a/src/devices/thinkpad-light.cpp b/src/devices/thinkpad-light.cpp
new file mode 100644
index 0000000..d047ab3
--- /dev/null
+++ b/src/devices/thinkpad-light.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <math.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "../lib.h"
+
+
+#include "device.h"
+#include "thinkpad-light.h"
+#include "../parameters/parameters.h"
+#include "../process/powerconsumer.h"
+
+#include <string.h>
+#include <unistd.h>
+
+thinkpad_light::thinkpad_light(): device()
+{
+ start_rate = 0;
+ end_rate = 0;
+ light_index = get_param_index("thinkpad-light");
+ r_index = get_result_index("thinkpad-light");
+ register_sysfs_path("/sys/devices/platform/thinkpad_acpi/leds/tpacpi::thinklight");
+}
+
+void thinkpad_light::start_measurement(void)
+{
+ /* read the rpms of the light */
+ start_rate = read_sysfs("/sys/devices/platform/thinkpad_acpi/leds/tpacpi::thinklight/brightness");
+}
+
+void thinkpad_light::end_measurement(void)
+{
+ end_rate = read_sysfs("/sys/devices/platform/thinkpad_acpi/leds/tpacpi::thinklight/brightness");
+
+ report_utilization("thinkpad-light", utilization());
+}
+
+
+double thinkpad_light::utilization(void)
+{
+ return (start_rate+end_rate) / 2.55 / 2.0;
+}
+
+void create_thinkpad_light(void)
+{
+ char filename[PATH_MAX];
+ class thinkpad_light *light;
+
+ pt_strcpy(filename, "/sys/devices/platform/thinkpad_acpi/leds/tpacpi::thinklight/brightness");
+
+ if (access(filename, R_OK) !=0)
+ return;
+
+ register_parameter("thinkpad-light", 10);
+
+ light = new class thinkpad_light();
+ all_devices.push_back(light);
+}
+
+
+
+double thinkpad_light::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+ double power;
+ double factor;
+ double util;
+
+
+ power = 0;
+ util = get_result_value(r_index, result);
+
+ if (util < 0)
+ util = 0;
+
+
+ factor = get_parameter_value(light_index, bundle) - 10.0;
+ power += util / 100.0 * factor;
+
+ if (power <= 0.0)
+ power = 0.0;
+
+ return power;
+}
diff --git a/src/devices/thinkpad-light.h b/src/devices/thinkpad-light.h
new file mode 100644
index 0000000..64a1789
--- /dev/null
+++ b/src/devices/thinkpad-light.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_THINKPAD_LIGHT_H
+#define _INCLUDE_GUARD_THINKPAD_LIGHT_H
+
+
+#include "device.h"
+#include "../parameters/parameters.h"
+
+class thinkpad_light: public device {
+ double start_rate, end_rate;
+ int light_index;
+ int r_index;
+public:
+
+ thinkpad_light();
+
+ virtual void start_measurement(void);
+ virtual void end_measurement(void);
+
+ virtual double utilization(void); /* percentage */
+
+ virtual const char * class_name(void) { return "light";};
+
+ virtual const char * device_name(void) { return "Light-1";};
+ virtual const char * human_name(void) { return "Thinkpad light";};
+ virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+ virtual const char * util_units(void) { return "%"; };
+ virtual int power_valid(void) { return utilization_power_valid(r_index);};
+ virtual int grouping_prio(void) { return 1; };
+};
+
+extern void create_thinkpad_light(void);
+
+
+#endif \ No newline at end of file
diff --git a/src/devices/usb.cpp b/src/devices/usb.cpp
new file mode 100644
index 0000000..5042699
--- /dev/null
+++ b/src/devices/usb.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "usb.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include "../lib.h"
+#include "../devlist.h"
+#include "../parameters/parameters.h"
+
+#include <iostream>
+#include <fstream>
+
+usbdevice::usbdevice(const char *_name, const char *path, const char *devid): device()
+{
+ ifstream file;
+ char filename[PATH_MAX];
+ char vendor[4096];
+ char product[4096];
+
+ pt_strcpy(sysfs_path, path);
+ register_sysfs_path(sysfs_path);
+ pt_strcpy(name, _name);
+ pt_strcpy(devname, devid);
+ snprintf(humanname, sizeof(humanname), _("USB device: %s"), pretty_print(devid, vendor, 4096));
+ active_before = 0;
+ active_after = 0;
+ connected_before = 0;
+ connected_after = 0;
+ busnum = 0;
+ devnum = 0;
+
+ index = get_param_index(devname);
+ r_index = get_result_index(name);
+ rootport = 0;
+ cached_valid = 0;
+
+
+ /* root ports and hubs should count as 0 power ... their activity is derived */
+ snprintf(filename, sizeof(filename), "%s/bDeviceClass", path);
+ file.open(filename, ios::in);
+ if (file) {
+ int dclass = 0;
+
+ file >> dclass;
+ file.close();
+ if (dclass == 9)
+ rootport = 1;
+ };
+
+ vendor[0] = 0;
+ product[0] = 0;
+ snprintf(filename, sizeof(filename), "%s/manufacturer", path);
+ file.open(filename, ios::in);
+ if (file) {
+ file.getline(vendor, 2047);
+ if (strstr(vendor, "Linux "))
+ vendor[0] = 0;
+ file.close();
+ };
+ snprintf(filename, sizeof(filename), "%s/product", path);
+ file.open(filename, ios::in);
+ if (file) {
+ file.getline(product, 2040);
+ file.close();
+ };
+ if (strlen(vendor) && strlen(product))
+ snprintf(humanname, sizeof(humanname), _("USB device: %s (%s)"), product, vendor);
+ else if (strlen(product))
+ snprintf(humanname, sizeof(humanname), _("USB device: %s"), product);
+ else if (strlen(vendor))
+ snprintf(humanname, sizeof(humanname), _("USB device: %s"), vendor);
+
+ /* For usbdevfs we need bus number and device number */
+ snprintf(filename, sizeof(filename), "%s/busnum", path);
+ file.open(filename, ios::in);
+ if (file) {
+
+ file >> busnum;
+ file.close();
+ };
+ snprintf(filename, sizeof(filename), "%s/devnum", path);
+ file.open(filename, ios::in);
+ if (file) {
+
+ file >> devnum;
+ file.close();
+ };
+}
+
+
+
+void usbdevice::start_measurement(void)
+{
+ ifstream file;
+ char fullpath[PATH_MAX];
+
+ active_before = 0;
+ active_after = 0;
+ connected_before = 0;
+ connected_after = 0;
+
+ snprintf(fullpath, sizeof(fullpath), "%s/power/active_duration", sysfs_path);
+ file.open(fullpath, ios::in);
+ if (file) {
+ file >> active_before;
+ }
+ file.close();
+
+ snprintf(fullpath, sizeof(fullpath), "%s/power/connected_duration", sysfs_path);
+ file.open(fullpath, ios::in);
+ if (file) {
+ file >> connected_before;
+ }
+ file.close();
+}
+
+void usbdevice::end_measurement(void)
+{
+ ifstream file;
+ char fullpath[PATH_MAX];
+
+ snprintf(fullpath, sizeof(fullpath), "%s/power/active_duration", sysfs_path);
+ file.open(fullpath, ios::in);
+ if (file) {
+ file >> active_after;
+ }
+ file.close();
+
+ snprintf(fullpath, sizeof(fullpath), "%s/power/connected_duration", sysfs_path);
+ file.open(fullpath, ios::in);
+ if (file) {
+ file >> connected_after;
+ }
+ file.close();
+ report_utilization(name, utilization());
+
+}
+
+double usbdevice::utilization(void) /* percentage */
+{
+ double d;
+ d = 100.0 * (active_after - active_before) / (0.01 + connected_after - connected_before);
+ if (d < 0.0)
+ d = 0.0;
+ if (d > 99.8)
+ d = 100.0;
+ return d;
+}
+
+const char * usbdevice::device_name(void)
+{
+ return name;
+}
+
+const char * usbdevice::human_name(void)
+{
+ return humanname;
+}
+
+void usbdevice::register_power_with_devlist(struct result_bundle *results, struct parameter_bundle *bundle)
+{
+ char devfs_name[1024];
+
+ snprintf(devfs_name, sizeof(devfs_name), "usb/%03d/%03d", busnum,
+ devnum);
+
+ register_devpower(devfs_name, power_usage(results, bundle), this);
+}
+
+double usbdevice::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+ double power;
+ double factor;
+ double util;
+
+ if (rootport || !cached_valid)
+ return 0.0;
+
+
+ power = 0;
+ factor = get_parameter_value(index, bundle);
+ util = get_result_value(r_index, result);
+
+ power += util * factor / 100.0;
+
+ return power;
+}
+
+static void create_all_usb_devices_callback(const char *d_name)
+{
+ char filename[PATH_MAX];
+ ifstream file;
+ class usbdevice *usb;
+ char device_name[PATH_MAX];
+ char vendorid[64], devid[64];
+ char devid_name[4096];
+
+ snprintf(filename, sizeof(filename), "/sys/bus/usb/devices/%s", d_name);
+ snprintf(device_name, sizeof(device_name), "%s/power/active_duration", filename);
+ if (access(device_name, R_OK) != 0)
+ return;
+
+ snprintf(device_name, sizeof(device_name), "%s/idVendor", filename);
+ file.open(device_name, ios::in);
+ if (file)
+ file.getline(vendorid, 64);
+ file.close();
+ snprintf(device_name, sizeof(device_name), "%s/idProduct", filename);
+ file.open(device_name, ios::in);
+ if (file)
+ file.getline(devid, 64);
+ file.close();
+
+ snprintf(devid_name, sizeof(devid_name), "usb-device-%s-%s", vendorid, devid);
+ snprintf(device_name, sizeof(device_name), "usb-device-%s-%s-%s", d_name, vendorid, devid);
+ if (result_device_exists(device_name))
+ return;
+
+ usb = new class usbdevice(device_name, filename, devid_name);
+ all_devices.push_back(usb);
+ register_parameter(devid_name, 0.1);
+}
+
+void create_all_usb_devices(void)
+{
+ process_directory("/sys/bus/usb/devices/", create_all_usb_devices_callback);
+}
diff --git a/src/devices/usb.h b/src/devices/usb.h
new file mode 100644
index 0000000..7e76a55
--- /dev/null
+++ b/src/devices/usb.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_USB_H
+#define _INCLUDE_GUARD_USB_H
+
+#include <limits.h>
+
+#include "device.h"
+#include "../parameters/parameters.h"
+
+class usbdevice: public device {
+ int active_before, active_after;
+ int connected_before, connected_after;
+ char sysfs_path[PATH_MAX];
+ char name[4096];
+ char devname[4096];
+ char humanname[4096];
+ int index;
+ int r_index;
+ int rootport;
+ int busnum;
+ int devnum;
+public:
+
+ usbdevice(const char *_name, const char *path, const char *devid);
+
+ virtual void start_measurement(void);
+ virtual void end_measurement(void);
+
+ virtual double utilization(void); /* percentage */
+
+ virtual const char * class_name(void) { return "usb";};
+
+ virtual const char * device_name(void);
+ virtual const char * human_name(void);
+ virtual void register_power_with_devlist(struct result_bundle *results, struct parameter_bundle *bundle);
+ virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+ virtual int power_valid(void) { return utilization_power_valid(r_index);};
+ virtual int grouping_prio(void) { return 4; };
+};
+
+extern void create_all_usb_devices(void);
+
+
+#endif \ No newline at end of file
diff --git a/src/devlist.cpp b/src/devlist.cpp
new file mode 100644
index 0000000..70ae70e
--- /dev/null
+++ b/src/devlist.cpp
@@ -0,0 +1,351 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+/*
+ * Code to track centrally which process has what /dev files open
+ */
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <vector>
+#include <algorithm>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+
+using namespace std;
+
+#include "devlist.h"
+#include "lib.h"
+#include "report/report.h"
+#include "report/report-maker.h"
+#include "report/report-data-html.h"
+
+#include "process/process.h"
+#include "devices/device.h"
+/*
+
+* collect list of processes that have devices open
+ (alternate between before and after lists)
+
+* charge a "surcharge" to a device (sub)string
+ - count how many openers
+ - add proprotion to each process that has it open
+
+* list of devices + power they use for processing
+
+*/
+
+static vector<struct devuser *> one;
+static vector<struct devuser *> two;
+static vector<struct devpower *> devpower;
+
+static int phase;
+/*
+ * 0 - one = before, two = after
+ * 1 - one = after, two = before
+ */
+
+void clean_open_devices()
+{
+ unsigned int i=0;
+
+ for (i = 0; i < one.size(); i++) {
+ free(one[i]);
+ }
+
+ for (i = 0; i < two.size(); i++) {
+ free(two[i]);
+ }
+
+ for (i = 0; i < devpower.size(); i++){
+ free(devpower[i]);
+ }
+}
+
+void collect_open_devices(void)
+{
+ struct dirent *entry;
+ DIR *dir;
+ char filename[PATH_MAX];
+ char link[PATH_MAX];
+ unsigned int i;
+ vector<struct devuser *> *target;
+
+ if (phase == 1)
+ target = &one;
+ else
+ target = &two;
+
+ for (i = 0; i < target->size(); i++) {
+ free((*target)[i]);
+ }
+ target->resize(0);
+
+
+ dir = opendir("/proc/");
+ if (!dir)
+ return;
+ while (1) {
+ struct dirent *entry2;
+ DIR *dir2;
+ entry = readdir(dir);
+
+ if (!entry)
+ break;
+ if (entry->d_name[0] == '.')
+ continue;
+ if (strcmp(entry->d_name, "self") == 0)
+ continue;
+
+ snprintf(filename, sizeof(filename), "/proc/%s/fd/", entry->d_name);
+
+ dir2 = opendir(filename);
+ if (!dir2)
+ continue;
+ while (1) {
+ int ret;
+ struct devuser * dev;
+ entry2 = readdir(dir2);
+ if (!entry2)
+ break;
+ if (!isdigit(entry2->d_name[0]))
+ continue;
+ snprintf(filename, sizeof(filename), "/proc/%s/fd/%s", entry->d_name, entry2->d_name);
+ memset(link, 0, sizeof(link));
+ ret = readlink(filename, link, sizeof(link) - 1);
+ if (ret < 0)
+ continue;
+
+ if (strcmp(link, "/dev/null") == 0)
+ continue;
+ if (strcmp(link, "/dev/.udev/queue.bin") == 0)
+ continue;
+ if (strcmp(link, "/dev/initctl") == 0)
+ continue;
+ if (strcmp(link, "/dev/ptmx") == 0)
+ continue;
+ if (strstr(link, "/dev/pts/"))
+ continue;
+ if (strstr(link, "/dev/shm/"))
+ continue;
+ if (strstr(link, "/dev/urandom"))
+ continue;
+ if (strstr(link, "/dev/tty"))
+ continue;
+
+ if (strncmp(link, "/dev", 4)==0) {
+ dev = (struct devuser *)malloc(sizeof(struct devuser));
+ if (!dev)
+ continue;
+ dev->pid = strtoull(entry->d_name, NULL, 10);
+ strncpy(dev->device, link, 251);
+ dev->device[251] = '\0';
+ strncpy(dev->comm, read_sysfs_string("/proc/%s/comm", entry->d_name).c_str(), 31);
+ dev->comm[31] = '\0';
+ target->push_back(dev);
+
+ }
+ }
+ closedir(dir2);
+ }
+ closedir(dir);
+
+ if (phase)
+ phase = 0;
+ else
+ phase = 1;
+}
+
+
+/* returns 0 if no process is identified as having the device open and a value > 0 otherwise */
+int charge_device_to_openers(const char *devstring, double power, class device *_dev)
+{
+ unsigned int i;
+ int openers = 0;
+ class process *proc;
+ /* 1. count the number of openers */
+
+ for (i = 0; i < one.size(); i++) {
+ if (strstr(one[i]->device, devstring))
+ openers++;
+ }
+ for (i = 0; i < two.size(); i++) {
+ if (strstr(two[i]->device, devstring))
+ openers++;
+ }
+
+
+ /* 2. divide power by this number */
+
+ if (!openers)
+ return 0;
+ power = power / openers;
+
+
+ /* 3. for each process that has it open, add the charge */
+
+ for (i = 0; i < one.size(); i++)
+ if (strstr(one[i]->device, devstring)) {
+ proc = find_create_process(one[i]->comm, one[i]->pid);
+ if (proc) {
+ proc->power_charge += power;
+ if (strlen(_dev->guilty) < 2000 && strstr(_dev->guilty, one[i]->comm) == NULL) {
+ strcat(_dev->guilty, one[i]->comm);
+ strcat(_dev->guilty, " ");
+ }
+ }
+ }
+
+ for (i = 0; i < two.size(); i++)
+ if (strstr(two[i]->device, devstring)) {
+ proc = find_create_process(two[i]->comm, two[i]->pid);
+ if (proc) {
+ proc->power_charge += power;
+ if (strlen(_dev->guilty) < 2000 && strstr(_dev->guilty, two[i]->comm) == NULL) {
+ strcat(_dev->guilty, two[i]->comm);
+ strcat(_dev->guilty, " ");
+ }
+ }
+ }
+
+
+
+ return openers;
+}
+
+void clear_devpower(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < devpower.size(); i++) {
+ devpower[i]->power = 0.0;
+ devpower[i]->dev->guilty[0] = 0;
+ }
+}
+
+void register_devpower(const char *devstring, double power, class device *_dev)
+{
+ unsigned int i;
+ struct devpower *dev = NULL;
+
+ for (i = 0; i < devpower.size(); i++)
+ if (strcmp(devstring, devpower[i]->device) == 0) {
+ dev = devpower[i];
+ }
+
+ if (!dev) {
+ dev = (struct devpower *)malloc(sizeof (struct devpower));
+ pt_strcpy(dev->device, devstring);
+ dev->power = 0.0;
+ devpower.push_back(dev);
+ }
+ dev->dev = _dev;
+ dev->power = power;
+}
+
+void run_devpower_list(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < devpower.size(); i++) {
+ int ret;
+ ret = charge_device_to_openers(devpower[i]->device, devpower[i]->power, devpower[i]->dev);
+ if (ret)
+ devpower[i]->dev->hide = true;
+ else
+ devpower[i]->dev->hide = false;
+
+ }
+
+}
+
+static bool devlist_sort(struct devuser * i, struct devuser * j)
+{
+ if (i->pid != j->pid)
+ return i->pid < j->pid;
+
+ return (strcmp(i->device, j->device)< 0);
+}
+
+void report_show_open_devices(void)
+{
+ vector<struct devuser *> *target;
+ unsigned int i;
+ char prev[128], proc[128];
+ int idx, cols, rows;
+
+ prev[0] = 0;
+ if (phase == 1)
+ target = &one;
+ else
+ target = &two;
+
+ if (target->size() == 0)
+ return;
+
+
+ /* Set Table attributes, rows, and cols */
+ table_attributes std_table_css;
+ cols = 2;
+ idx = cols;
+ rows= target->size() + 1;
+ init_std_table_attr(&std_table_css, rows, cols);
+
+ /* Set Title attributes */
+ tag_attr title_attr;
+ init_title_attr(&title_attr);
+
+ /* Set array of data in row Major order */
+ string *process_data = new string[cols * rows];
+
+ sort(target->begin(), target->end(), devlist_sort);
+ process_data[0]=__("Process");
+ process_data[1]=__("Device");
+
+ for (i = 0; i < target->size(); i++) {
+ proc[0] = 0;
+ if (strcmp(prev, (*target)[i]->comm) != 0)
+ snprintf(proc, sizeof(proc), "%s", (*target)[i]->comm);
+
+ process_data[idx]=string(proc);
+ idx+=1;
+ process_data[idx]=string((*target)[i]->device);
+ idx+=1;
+ snprintf(prev, sizeof(prev), "%s", (*target)[i]->comm);
+ }
+
+ /* Report Output */
+ /* No div attribute here inherits from device power report */
+ report.add_title(&title_attr, __("Process Device Activity"));
+ report.add_table(process_data, &std_table_css);
+ delete [] process_data;
+ report.end_div();
+}
diff --git a/src/devlist.h b/src/devlist.h
new file mode 100644
index 0000000..35dfd6c
--- /dev/null
+++ b/src/devlist.h
@@ -0,0 +1,27 @@
+#ifndef __INCLUDE_GUARD_DEVLIST_H__
+#define __INCLUDE_GUARD_DEVLIST_H__
+
+struct devuser {
+ unsigned int pid;
+ char comm[32];
+ char device[252];
+};
+
+class device;
+
+struct devpower {
+ char device[252];
+ double power;
+ class device *dev;
+};
+
+extern void clean_open_devices();
+extern void collect_open_devices(void);
+
+extern void clear_devpower(void);
+extern void register_devpower(const char *devstring, double power, class device *dev);
+extern void run_devpower_list(void);
+
+extern void report_show_open_devices(void);
+
+#endif
diff --git a/src/display.cpp b/src/display.cpp
new file mode 100644
index 0000000..cc03919
--- /dev/null
+++ b/src/display.cpp
@@ -0,0 +1,342 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "display.h"
+#include "lib.h"
+
+#include <ncurses.h>
+
+
+#include <vector>
+#include <map>
+#include <string>
+#include <string.h>
+
+using namespace std;
+
+static int display = 0;
+
+vector<string> tab_names;
+map<string, class tab_window *> tab_windows;
+map<string, string> tab_translations;
+
+map<string, string> bottom_lines;
+
+void create_tab(const string &name, const string &translation, class tab_window *w, string bottom_line)
+{
+ if (!w)
+ w = new(class tab_window);
+
+ w->win = newpad(1000,1000);
+ tab_names.push_back(name);
+ tab_windows[name] = w;
+ tab_translations[name] = translation;
+ bottom_lines[name] = bottom_line;
+}
+
+
+void init_display(void)
+{
+ initscr();
+ start_color();
+
+ cbreak(); /* character at a time input */
+ noecho(); /* don't show the user input */
+ keypad(stdscr, TRUE); /* enable cursor/etc keys */
+
+ use_default_colors();
+
+ create_tab("Overview", _("Overview"));
+ create_tab("Idle stats", _("Idle stats"));
+ create_tab("Frequency stats", _("Frequency stats"));
+ create_tab("Device stats", _("Device stats"));
+
+ display = 1;
+}
+
+void reset_display(void)
+{
+ if (!display)
+ return;
+
+ keypad(stdscr, FALSE);
+ echo();
+ nocbreak();
+
+ resetterm();
+}
+
+
+WINDOW *tab_bar = NULL;
+WINDOW *bottom_line = NULL;
+
+static int current_tab;
+
+void show_tab(unsigned int tab)
+{
+ class tab_window *win;
+ unsigned int i;
+ int tab_pos = 17;
+ const char *c;
+
+ if (!display)
+ return;
+
+ if (tab_bar) {
+ delwin(tab_bar);
+ tab_bar = NULL;
+ }
+
+ if (bottom_line) {
+ delwin(bottom_line);
+ bottom_line = NULL;
+ }
+
+ tab_bar = newwin(1, 0, 0, 0);
+
+ wattrset(tab_bar, A_REVERSE);
+ mvwprintw(tab_bar, 0,0, "%120s", "");
+ mvwprintw(tab_bar, 0,0, "PowerTOP %s", PACKAGE_VERSION);
+
+ bottom_line = newwin(1, 0, LINES-1, 0);
+ wattrset(bottom_line, A_REVERSE);
+ mvwprintw(bottom_line, 0,0, "%120s", "");
+
+ c = bottom_lines[tab_names[tab]].c_str();
+ if (c && strlen(c) > 0)
+ mvwprintw(bottom_line, 0,0, "%s", c);
+ else
+ mvwprintw(bottom_line, 0, 0,
+ "<ESC> %s | <TAB> / <Shift + TAB> %s | ", _("Exit"),
+ _("Navigate"));
+
+
+ current_tab = tab;
+
+ for (i = 0; i < tab_names.size(); i++) {
+ if (i == tab)
+ wattrset(tab_bar, A_NORMAL);
+ else
+ wattrset(tab_bar, A_REVERSE);
+ mvwprintw(tab_bar, 0, tab_pos, " %s ", tab_translations[tab_names[i]].c_str());
+
+ tab_pos += 3 + tab_names[i].length();
+ }
+
+ wrefresh(tab_bar);
+ wrefresh(bottom_line);
+
+ win = tab_windows[tab_names[tab]];
+ if (!win)
+ return;
+
+ prefresh(win->win, win->ypad_pos, win->xpad_pos, 1, 0, LINES - 3, COLS - 1);
+}
+
+WINDOW *get_ncurses_win(const char *name)
+{
+ class tab_window *w;
+ WINDOW *win;
+
+ w= tab_windows[name];
+ if (!w)
+ return NULL;
+
+ win = w->win;
+
+ return win;
+}
+
+WINDOW *get_ncurses_win(int nr)
+{
+ class tab_window *w;
+ WINDOW *win;
+
+ w= tab_windows[tab_names[nr]];
+ if (!w)
+ return NULL;
+
+ win = w->win;
+
+ return win;
+}
+
+WINDOW *get_ncurses_win(const string &name)
+{
+ return get_ncurses_win(name.c_str());
+}
+
+void show_prev_tab(void)
+{
+ class tab_window *w;
+
+ if (!display)
+ return;
+ w = tab_windows[tab_names[current_tab]];
+ if (w)
+ w->hide();
+
+ current_tab --;
+ if (current_tab < 0)
+ current_tab = tab_names.size() - 1;
+
+ w = tab_windows[tab_names[current_tab]];
+ if (w)
+ w->expose();
+
+ show_tab(current_tab);
+}
+
+void show_next_tab(void)
+{
+ class tab_window *w;
+
+ if (!display)
+ return;
+
+ w = tab_windows[tab_names[current_tab]];
+ if (w)
+ w->hide();
+
+ current_tab ++;
+ if (current_tab >= (int)tab_names.size())
+ current_tab = 0;
+
+ w = tab_windows[tab_names[current_tab]];
+ if (w)
+ w->expose();
+
+ show_tab(current_tab);
+}
+
+void show_cur_tab(void)
+{
+ if (!display)
+ return;
+ show_tab(current_tab);
+}
+
+void cursor_down(void)
+{
+ class tab_window *w;
+
+ w = tab_windows[tab_names[current_tab]];
+ if (w) {
+ if (w->ypad_pos < 1000) {
+ if (tab_names[current_tab] == "Tunables" || tab_names[current_tab] == "WakeUp") {
+ if ((w->cursor_pos + 7) >= LINES) {
+ prefresh(w->win, ++w->ypad_pos, w->xpad_pos,
+ 1, 0, LINES - 3, COLS - 1);
+ }
+ w->cursor_down();
+ } else {
+ prefresh(w->win, ++w->ypad_pos, w->xpad_pos,
+ 1, 0, LINES - 3, COLS - 1);
+ }
+ }
+ }
+
+ show_cur_tab();
+}
+
+void cursor_up(void)
+{
+ class tab_window *w;
+
+ w = tab_windows[tab_names[current_tab]];
+
+ if (w) {
+ w->cursor_up();
+ if(w->ypad_pos > 0) {
+ prefresh(w->win, --w->ypad_pos, w->xpad_pos,
+ 1, 0, LINES - 3, COLS - 1);
+ }
+ }
+
+ show_cur_tab();
+}
+
+void cursor_left(void)
+{
+ class tab_window *w;
+
+ w = tab_windows[tab_names[current_tab]];
+
+ if (w) {
+ if (w->xpad_pos > 0) {
+ prefresh(w->win, w->ypad_pos,--w->xpad_pos,
+ 1, 0, LINES - 3, COLS - 1);
+ }
+ }
+}
+
+void cursor_right(void)
+{
+ class tab_window *w;
+
+ w = tab_windows[tab_names[current_tab]];
+
+ if (w) {
+ if (w->xpad_pos < 1000) {
+ prefresh(w->win, w->ypad_pos, ++w->xpad_pos,
+ 1, 0, LINES - 3, COLS - 1);
+ }
+ }
+}
+
+void cursor_enter(void)
+{
+ class tab_window *w;
+
+ w = tab_windows[tab_names[current_tab]];
+
+ if (w) {
+ w->cursor_enter();
+ w->repaint();
+ }
+ show_cur_tab();
+}
+
+void window_refresh()
+{
+ class tab_window *w;
+
+ w = tab_windows[tab_names[current_tab]];
+
+ if (w) {
+ w->ypad_pos = 0;
+ w->xpad_pos = 0;
+ w->window_refresh();
+ w->repaint();
+ }
+
+ show_cur_tab();
+}
+
+int ncurses_initialized(void)
+{
+ if (display)
+ return 1;
+ return 0;
+}
diff --git a/src/display.h b/src/display.h
new file mode 100644
index 0000000..9db87ec
--- /dev/null
+++ b/src/display.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef __INCLUDE_GUARD_DISPLAY_H_
+#define __INCLUDE_GUARD_DISPLAY_H_
+
+
+#include <map>
+#include <string>
+#include <ncurses.h>
+
+using namespace std;
+
+extern void init_display(void);
+extern void reset_display(void);
+extern int ncurses_initialized(void);
+extern void show_tab(unsigned int tab);
+extern void show_next_tab(void);
+extern void show_prev_tab(void);
+extern void show_cur_tab(void);
+extern void cursor_up(void);
+extern void cursor_down(void);
+extern void cursor_right(void);
+extern void cursor_left(void);
+extern void cursor_enter(void);
+extern void window_refresh(void);
+
+class tab_window {
+public:
+ int cursor_pos;
+ int cursor_max;
+ short int xpad_pos, ypad_pos;
+ WINDOW *win;
+
+ tab_window() {
+ cursor_pos = 0;
+ cursor_max = 0;
+ xpad_pos =0;
+ ypad_pos = 0;
+ win = NULL;
+ }
+
+ virtual void cursor_down(void) {
+ if (cursor_pos < cursor_max)
+ cursor_pos++;
+ repaint();
+ } ;
+ virtual void cursor_up(void) {
+ if (cursor_pos > 0)
+ cursor_pos--;
+ repaint();
+ };
+ virtual void cursor_left(void) { };
+ virtual void cursor_right(void) { };
+
+ virtual void cursor_enter(void) { };
+ virtual void window_refresh() { };
+
+ virtual void repaint(void) { };
+ virtual void expose(void) { cursor_pos = 0; repaint();};
+ virtual void hide(void) { };
+
+ virtual ~tab_window()
+ {
+ delwin(win);
+ win = NULL;
+ }
+};
+
+extern map<string, class tab_window *> tab_windows;
+
+WINDOW *get_ncurses_win(const char *name);
+WINDOW *get_ncurses_win(const string &name);
+WINDOW *get_ncurses_win(int nr);
+
+void create_tab(const string &name, const string &translation, class tab_window *w = NULL, string bottom_line = "");
+
+#endif
diff --git a/src/lib.cpp b/src/lib.cpp
new file mode 100644
index 0000000..5cd1c4a
--- /dev/null
+++ b/src/lib.cpp
@@ -0,0 +1,597 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ * Peter Anvin
+ */
+#include <map>
+#include <string.h>
+#include <iostream>
+#include <utility>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <ctype.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include "lib.h"
+
+#ifndef HAVE_NO_PCI
+extern "C" {
+#include <pci/pci.h>
+}
+#endif
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <locale.h>
+#include <libintl.h>
+#include <limits>
+#include <math.h>
+#include <ncurses.h>
+#include <fcntl.h>
+#include <glob.h>
+
+static int kallsyms_read = 0;
+
+int is_turbo(uint64_t freq, uint64_t max, uint64_t maxmo)
+{
+ if (freq != max)
+ return 0;
+ if (maxmo + 1000 != max)
+ return 0;
+ return 1;
+}
+
+double percentage(double F)
+{
+ F = F * 100.0;
+// if (F > 100.0)
+// F = 100.0;
+ if (F < 0.0)
+ F = 0.0;
+ return F;
+}
+
+char *hz_to_human(unsigned long hz, char *buffer, int digits)
+{
+ unsigned long long Hz;
+
+ buffer[0] = 0;
+
+ Hz = hz;
+
+ /* default: just put the Number in */
+ sprintf(buffer,"%9lli", Hz);
+
+ if (Hz>1000) {
+ if (digits == 2)
+ sprintf(buffer, "%4lli MHz", (Hz+500)/1000);
+ else
+ sprintf(buffer, "%6lli MHz", (Hz+500)/1000);
+ }
+
+ if (Hz>1500000) {
+ if (digits == 2)
+ sprintf(buffer, "%4.2f GHz", (Hz+5000.0)/1000000);
+ else
+ sprintf(buffer, "%3.1f GHz", (Hz+5000.0)/1000000);
+ }
+
+ return buffer;
+}
+
+using namespace std;
+
+map<unsigned long, string> kallsyms;
+
+static void read_kallsyms(void)
+{
+ ifstream file;
+ char line[1024];
+ kallsyms_read = 1;
+
+ file.open("/proc/kallsyms", ios::in);
+
+ while (file) {
+ char *c = NULL, *c2 = NULL;
+ unsigned long address = 0;
+ memset(line, 0, 1024);
+ file.getline(line, 1024);
+ c = strchr(line, ' ');
+ if (!c)
+ continue;
+ *c = 0;
+ c2 = c + 1;
+ if (*c2) c2++;
+ if (*c2) c2++;
+
+ address = strtoull(line, NULL, 16);
+ c = strchr(c2, '\t');
+ if (c)
+ *c = 0;
+ if (address != 0)
+ kallsyms[address] = c2;
+ }
+ file.close();
+}
+
+const char *kernel_function(uint64_t address)
+{
+ const char *c;
+ if (!kallsyms_read)
+ read_kallsyms();
+
+ c = kallsyms[address].c_str();
+ if (!c)
+ return "";
+ return c;
+}
+
+static int _max_cpu;
+int get_max_cpu(void)
+{
+ return _max_cpu;
+}
+
+void set_max_cpu(int cpu)
+{
+ if (cpu > _max_cpu)
+ _max_cpu = cpu;
+}
+
+
+void write_sysfs(const string &filename, const string &value)
+{
+ ofstream file;
+
+ file.open(filename.c_str(), ios::out);
+ if (!file)
+ return;
+ try
+ {
+ file << value;
+ file.close();
+ } catch (std::exception &exc) {
+ return;
+ }
+}
+
+int read_sysfs(const string &filename, bool *ok)
+{
+ ifstream file;
+ int i;
+
+ file.open(filename.c_str(), ios::in);
+ if (!file) {
+ if (ok)
+ *ok = false;
+ return 0;
+ }
+ try
+ {
+ file >> i;
+ if (ok)
+ *ok = true;
+ } catch (std::exception &exc) {
+ if (ok)
+ *ok = false;
+ i = 0;
+ }
+ file.close();
+ return i;
+}
+
+string read_sysfs_string(const string &filename)
+{
+ ifstream file;
+ char content[4096];
+ char *c;
+
+ file.open(filename.c_str(), ios::in);
+ if (!file)
+ return "";
+ try
+ {
+ file.getline(content, 4096);
+ file.close();
+ c = strchr(content, '\n');
+ if (c)
+ *c = 0;
+ } catch (std::exception &exc) {
+ file.close();
+ return "";
+ }
+ return content;
+}
+
+string read_sysfs_string(const char *format, const char *param)
+{
+ ifstream file;
+ char content[4096];
+ char *c;
+ char filename[PATH_MAX];
+
+
+ snprintf(filename, sizeof(filename), format, param);
+
+ file.open(filename, ios::in);
+ if (!file)
+ return "";
+ try
+ {
+ file.getline(content, 4096);
+ file.close();
+ c = strchr(content, '\n');
+ if (c)
+ *c = 0;
+ } catch (std::exception &exc) {
+ file.close();
+ return "";
+ }
+ return content;
+}
+
+void align_string(char *buffer, size_t min_sz, size_t max_sz)
+{
+ size_t sz;
+
+ /** mbsrtowcs() allows NULL dst and zero sz,
+ * comparing to mbstowcs(), which causes undefined
+ * behaviour under given circumstances*/
+
+ /* start with mbsrtowcs() local mbstate_t * and
+ * NULL dst pointer*/
+ sz = mbsrtowcs(NULL, (const char **)&buffer, max_sz, NULL);
+ if (sz == (size_t)-1) {
+ buffer[min_sz] = 0x00;
+ return;
+ }
+ while (sz < min_sz) {
+ strcat(buffer, " ");
+ sz++;
+ }
+}
+
+void format_watts(double W, char *buffer, unsigned int len)
+{
+ buffer[0] = 0;
+ char buf[32];
+ sprintf(buffer, _("%7sW"), fmt_prefix(W, buf));
+
+ if (W < 0.0001)
+ sprintf(buffer, _(" 0 mW"));
+
+ align_string(buffer, len, len);
+}
+
+#ifndef HAVE_NO_PCI
+static struct pci_access *pci_access;
+
+char *pci_id_to_name(uint16_t vendor, uint16_t device, char *buffer, int len)
+{
+ char *ret;
+
+ buffer[0] = 0;
+
+ if (!pci_access) {
+ pci_access = pci_alloc();
+ pci_init(pci_access);
+ }
+
+ ret = pci_lookup_name(pci_access, buffer, len, PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE, vendor, device);
+
+ return ret;
+}
+
+void end_pci_access(void)
+{
+ if (pci_access)
+ pci_free_name_list(pci_access);
+}
+
+#else
+
+char *pci_id_to_name(uint16_t vendor, uint16_t device, char *buffer, int len)
+{
+ return NULL;
+}
+
+void end_pci_access(void)
+{
+}
+
+#endif /* HAVE_NO_PCI */
+
+int utf_ok = -1;
+
+
+
+/* pretty print numbers while limiting the precision */
+char *fmt_prefix(double n, char *buf)
+{
+ static const char prefixes[] = "yzafpnum kMGTPEZY";
+ char tmpbuf[16];
+ int omag, npfx;
+ char *p, *q, pfx, *c;
+ int i;
+
+ if (utf_ok == -1) {
+ char *g;
+ g = getenv("LANG");
+ if (g && strstr(g, "UTF-8"))
+ utf_ok = 1;
+ else
+ utf_ok = 0;
+ }
+
+ p = buf;
+
+ *p = ' ';
+ if (n < 0.0) {
+ *p = '-';
+ n = -n;
+ p++;
+ }
+
+ snprintf(tmpbuf, sizeof tmpbuf, "%.2e", n);
+ c = strchr(tmpbuf, 'e');
+ if (!c) {
+ sprintf(buf, "NaN");
+ return buf;
+ }
+ omag = atoi(c + 1);
+
+ npfx = ((omag + 27) / 3) - (27/3);
+ omag = (omag + 27) % 3;
+
+ q = tmpbuf;
+ if (omag == 2)
+ omag = -1;
+
+ for (i = 0; i < 3; i++) {
+ while (!isdigit(*q))
+ q++;
+ *p++ = *q++;
+ if (i == omag)
+ *p++ = '.';
+ }
+ *p++ = ' ';
+
+ pfx = prefixes[npfx + 8];
+
+ if (pfx == ' ') {
+ /* do nothing */
+ } else if (pfx == 'u' && utf_ok > 0) {
+ strcpy(p, "µ"); /* Mu is a multibyte sequence */
+ while (*p)
+ p++;
+ } else {
+ *p++ = pfx;
+ }
+ *p = '\0';
+
+ return buf;
+}
+
+static map<string, string> pretty_prints;
+static int pretty_print_init = 0;
+
+static void init_pretty_print(void)
+{
+ pretty_prints["[12] i8042"] = _("PS/2 Touchpad / Keyboard / Mouse");
+ pretty_prints["ahci"] = _("SATA controller");
+ pretty_prints["usb-device-8087-0020"] = _("Intel built in USB hub");
+
+ pretty_print_init = 1;
+}
+
+
+char *pretty_print(const char *str, char *buf, int len)
+{
+ const char *p;
+
+ if (!pretty_print_init)
+ init_pretty_print();
+
+ p = pretty_prints[str].c_str();
+
+ if (strlen(p) == 0)
+ p = str;
+
+ snprintf(buf, len, "%s", p);
+
+ if (len)
+ buf[len - 1] = 0;
+ return buf;
+}
+
+int equals(double a, double b)
+{
+ return fabs(a - b) <= std::numeric_limits<double>::epsilon();
+}
+
+void process_directory(const char *d_name, callback fn)
+{
+ struct dirent *entry;
+ DIR *dir;
+ dir = opendir(d_name);
+ if (!dir)
+ return;
+ while (1) {
+ entry = readdir(dir);
+ if (!entry)
+ break;
+ if (entry->d_name[0] == '.')
+ continue;
+ fn(entry->d_name);
+ }
+ closedir(dir);
+}
+
+void process_glob(const char *d_glob, callback fn)
+{
+ glob_t g;
+ size_t c;
+
+ switch (glob(d_glob, GLOB_ERR | GLOB_MARK | GLOB_NOSORT, NULL, &g)) {
+ case GLOB_NOSPACE:
+ fprintf(stderr,_("glob returned GLOB_NOSPACE\n"));
+ globfree(&g);
+ return;
+ case GLOB_ABORTED:
+ fprintf(stderr,_("glob returned GLOB_ABORTED\n"));
+ globfree(&g);
+ return;
+ case GLOB_NOMATCH:
+ fprintf(stderr,_("glob returned GLOB_NOMATCH\n"));
+ globfree(&g);
+ return;
+ }
+
+ for (c=0; c < g.gl_pathc; c++) {
+ fn(g.gl_pathv[c]);
+ }
+ globfree(&g);
+}
+
+int get_user_input(char *buf, unsigned sz)
+{
+ fflush(stdout);
+ echo();
+ /* Upon successful completion, these functions return OK. Otherwise, they return ERR. */
+ int ret = getnstr(buf, sz);
+ noecho();
+ fflush(stdout);
+ /* to distinguish between getnstr error and empty line */
+ return ret || strlen(buf);
+}
+
+int read_msr(int cpu, uint64_t offset, uint64_t *value)
+{
+#if defined(__i386__) || defined(__x86_64__)
+ ssize_t retval;
+ uint64_t msr;
+ int fd;
+ char msr_path[256];
+
+ snprintf(msr_path, sizeof(msr_path), "/dev/cpu/%d/msr", cpu);
+
+ if (access(msr_path, R_OK) != 0){
+ snprintf(msr_path, sizeof(msr_path), "/dev/msr%d", cpu);
+
+ if (access(msr_path, R_OK) != 0){
+ fprintf(stderr,
+ _("Model-specific registers (MSR)\
+ not found (try enabling CONFIG_X86_MSR).\n"));
+ return -1;
+ }
+ }
+
+ fd = open(msr_path, O_RDONLY);
+ if (fd < 0)
+ return -1;
+ retval = pread(fd, &msr, sizeof msr, offset);
+ close(fd);
+ if (retval != sizeof msr) {
+ return -1;
+ }
+ *value = msr;
+
+ return retval;
+#else
+ return -1;
+#endif
+}
+
+int write_msr(int cpu, uint64_t offset, uint64_t value)
+{
+#if defined(__i386__) || defined(__x86_64__)
+ ssize_t retval;
+ int fd;
+ char msr_path[256];
+
+ snprintf(msr_path, sizeof(msr_path), "/dev/cpu/%d/msr", cpu);
+
+ if (access(msr_path, R_OK) != 0){
+ snprintf(msr_path, sizeof(msr_path), "/dev/msr%d", cpu);
+
+ if (access(msr_path, R_OK) != 0){
+ fprintf(stderr,
+ _("Model-specific registers (MSR)\
+ not found (try enabling CONFIG_X86_MSR).\n"));
+ return -1;
+ }
+ }
+
+ fd = open(msr_path, O_WRONLY);
+ if (fd < 0)
+ return -1;
+ retval = pwrite(fd, &value, sizeof value, offset);
+ close(fd);
+ if (retval != sizeof value) {
+ return -1;
+ }
+
+ return retval;
+#else
+ return -1;
+#endif
+}
+
+#define UI_NOTIFY_BUFF_SZ 2048
+
+void ui_notify_user_ncurses(const char *frmt, ...)
+{
+ char notify[UI_NOTIFY_BUFF_SZ];
+ va_list list;
+
+ start_color();
+ init_pair(1, COLOR_BLACK, COLOR_WHITE);
+ attron(COLOR_PAIR(1));
+ va_start(list, frmt);
+ /* there is no ncurses *print() function which takes
+ * int x, int y and va_list, this is why we use temp
+ * buffer */
+ vsnprintf(notify, UI_NOTIFY_BUFF_SZ - 1, frmt, list);
+ va_end(list);
+ mvprintw(1, 0, "%s", notify);
+ attroff(COLOR_PAIR(1));
+}
+
+void ui_notify_user_console(const char *frmt, ...)
+{
+ va_list list;
+
+ va_start(list, frmt);
+ vprintf(frmt, list);
+ va_end(list);
+}
diff --git a/src/lib.h b/src/lib.h
new file mode 100644
index 0000000..6d85eb6
--- /dev/null
+++ b/src/lib.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef INCLUDE_GUARD_LIB_H
+#define INCLUDE_GUARD_LIB_H
+
+#include <libintl.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <cstring>
+
+/* Include only for Automake builds */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef ENABLE_NLS
+#define _(STRING) gettext(STRING)
+#else
+#define _(STRING) (STRING)
+#endif
+
+extern int is_turbo(uint64_t freq, uint64_t max, uint64_t maxmo);
+
+extern int get_max_cpu(void);
+extern void set_max_cpu(int cpu);
+
+extern double percentage(double F);
+extern char *hz_to_human(unsigned long hz, char *buffer, int digits = 2);
+
+
+extern const char *kernel_function(uint64_t address);
+
+
+
+#include <ctime>
+#include <string>
+using namespace std;
+
+extern void write_sysfs(const string &filename, const string &value);
+extern int read_sysfs(const string &filename, bool *ok = NULL);
+extern string read_sysfs_string(const string &filename);
+extern string read_sysfs_string(const char *format, const char *param);
+
+extern void format_watts(double W, char *buffer, unsigned int len);
+
+extern char *pci_id_to_name(uint16_t vendor, uint16_t device, char *buffer, int len);
+extern void end_pci_access(void);
+
+
+extern char *fmt_prefix(double n, char *buf);
+extern char *pretty_print(const char *str, char *buf, int len);
+extern int equals(double a, double b);
+
+template<size_t N> void pt_strcpy(char (&d)[N], const char *s)
+{
+ strncpy(d, s, N);
+ d[N-1] = '\0';
+}
+
+typedef void (*callback)(const char*);
+extern void process_directory(const char *d_name, callback fn);
+extern void process_glob(const char *glob, callback fn);
+extern int utf_ok;
+extern int get_user_input(char *buf, unsigned sz);
+extern int read_msr(int cpu, uint64_t offset, uint64_t *value);
+extern int write_msr(int cpu, uint64_t offset, uint64_t value);
+
+extern void align_string(char *buffer, size_t min_sz, size_t max_sz);
+
+extern void ui_notify_user_ncurses(const char *frmt, ...);
+extern void ui_notify_user_console(const char *frmt, ...);
+extern void (*ui_notify_user) (const char *frmt, ...);
+#endif
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..45aaa58
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,578 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This 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.
+ *
+ * getopt code is taken from "The GNU C Library" reference manual,
+ * section 24.2 "Parsing program options using getopt"
+ * http://www.gnu.org/s/libc/manual/html_node/Getopt-Long-Option-Example.html
+ * Manual published under the terms of the Free Documentation License.
+ *
+ * Authors:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <locale.h>
+#include <sys/resource.h>
+#include <limits.h>
+#include <pthread.h>
+
+#include "cpu/cpu.h"
+#include "process/process.h"
+#include "perf/perf.h"
+#include "perf/perf_bundle.h"
+#include "lib.h"
+#include "../config.h"
+
+
+#include "devices/device.h"
+#include "devices/devfreq.h"
+#include "devices/usb.h"
+#include "devices/ahci.h"
+#include "measurement/measurement.h"
+#include "parameters/parameters.h"
+#include "calibrate/calibrate.h"
+
+
+#include "tuning/tuning.h"
+#include "wakeup/wakeup.h"
+
+#include "display.h"
+#include "devlist.h"
+#include "report/report.h"
+
+#define DEBUGFS_MAGIC 0x64626720
+
+#define NR_OPEN_DEF 1024 * 1024
+
+int debug_learning = 0;
+unsigned time_out = 20;
+int leave_powertop = 0;
+void (*ui_notify_user) (const char *frmt, ...);
+
+enum {
+ OPT_AUTO_TUNE = CHAR_MAX + 1,
+ OPT_EXTECH,
+ OPT_DEBUG
+};
+
+static const struct option long_options[] =
+{
+ /* These options set a flag. */
+ {"auto-tune", no_argument, NULL, OPT_AUTO_TUNE},
+ {"calibrate", no_argument, NULL, 'c'},
+ {"csv", optional_argument, NULL, 'C'},
+ {"debug", no_argument, &debug_learning, OPT_DEBUG},
+ {"extech", optional_argument, NULL, OPT_EXTECH},
+ {"html", optional_argument, NULL, 'r'},
+ {"iteration", optional_argument, NULL, 'i'},
+ {"quiet", no_argument, NULL, 'q'},
+ {"sample", optional_argument, NULL, 's'},
+ {"time", optional_argument, NULL, 't'},
+ {"workload", optional_argument, NULL, 'w'},
+ {"version", no_argument, NULL, 'V'},
+ {"help", no_argument, NULL, 'h'},
+ {NULL, 0, NULL, 0}
+};
+
+static void print_version()
+{
+ printf(_("PowerTOP version " PACKAGE_VERSION "\n"));
+}
+
+static bool set_refresh_timeout()
+{
+ static char buf[4];
+ mvprintw(1, 0, "%s (currently %u): ", _("Set refresh time out"), time_out);
+ memset(buf, '\0', sizeof(buf));
+ get_user_input(buf, sizeof(buf) - 1);
+ show_tab(0);
+ unsigned time = strtoul(buf, NULL, 0);
+ if (!time) return 0;
+ if (time > 32) time = 32;
+ time_out = time;
+ return 1;
+}
+
+static void print_usage()
+{
+ printf("%s\n\n", _("Usage: powertop [OPTIONS]"));
+ printf(" --auto-tune\t %s\n", _("sets all tunable options to their GOOD setting"));
+ printf(" -c, --calibrate\t %s\n", _("runs powertop in calibration mode"));
+ printf(" -C, --csv%s\t %s\n", _("[=filename]"), _("generate a csv report"));
+ printf(" --debug\t\t %s\n", _("run in \"debug\" mode"));
+ printf(" --extech%s\t %s\n", _("[=devnode]"), _("uses an Extech Power Analyzer for measurements"));
+ printf(" -r, --html%s\t %s\n", _("[=filename]"), _("generate a html report"));
+ printf(" -i, --iteration%s\n", _("[=iterations] number of times to run each test"));
+ printf(" -q, --quiet\t\t %s\n", _("suppress stderr output"));
+ printf(" -s, --sample%s\t %s\n", _("[=seconds]"), _("interval for power consumption measurement"));
+ printf(" -t, --time%s\t %s\n", _("[=seconds]"), _("generate a report for 'x' seconds"));
+ printf(" -w, --workload%s %s\n", _("[=workload]"), _("file to execute for workload"));
+ printf(" -V, --version\t\t %s\n", _("print version information"));
+ printf(" -h, --help\t\t %s\n", _("print this help menu"));
+ printf("\n");
+ printf("%s\n\n", _("For more help please refer to the 'man 8 powertop'"));
+}
+
+static void do_sleep(int seconds)
+{
+ time_t target;
+ int delta;
+
+ if (!ncurses_initialized()) {
+ sleep(seconds);
+ return;
+ }
+ target = time(NULL) + seconds;
+ delta = seconds;
+ do {
+ int c;
+ usleep(6000);
+ halfdelay(delta * 10);
+
+ c = getch();
+ switch (c) {
+ case KEY_BTAB:
+ show_prev_tab();
+ break;
+ case '\t':
+ show_next_tab();
+ break;
+ case KEY_RIGHT:
+ cursor_right();
+ break;
+ case KEY_LEFT:
+ cursor_left();
+ break;
+ case KEY_NPAGE:
+ case KEY_DOWN:
+ cursor_down();
+ break;
+ case KEY_PPAGE:
+ case KEY_UP:
+ cursor_up();
+ break;
+ case ' ':
+ case '\n':
+ cursor_enter();
+ break;
+ case 's':
+ if (set_refresh_timeout())
+ return;
+ break;
+ case 'r':
+ window_refresh();
+ return;
+ case KEY_EXIT:
+ case 'q':
+ case 27: // Escape
+ leave_powertop = 1;
+ return;
+ }
+
+ delta = target - time(NULL);
+ if (delta <= 0)
+ break;
+
+ } while (1);
+}
+
+extern "C" {
+ static volatile bool end_thread;
+ void* measure_background_thread(void *arg)
+ {
+ int sleep_time = *((int *) arg);
+ while (!end_thread) {
+ do_sleep(sleep_time);
+ global_sample_power();
+ }
+ return 0;
+ }
+}
+
+void one_measurement(int seconds, int sample_interval, char *workload)
+{
+ create_all_usb_devices();
+ start_power_measurement();
+ devices_start_measurement();
+ start_devfreq_measurement();
+ start_process_measurement();
+ start_cpu_measurement();
+
+ if (workload && workload[0]) {
+ pthread_t thread = 0UL;
+ end_thread = false;
+ if (pthread_create(&thread, NULL, measure_background_thread, &sample_interval))
+ fprintf(stderr, "ERROR: workload measurement thread creation failed\n");
+
+ if (system(workload))
+ fprintf(stderr, _("Unknown issue running workload!\n"));
+
+ if (thread)
+ {
+ end_thread = true;
+ pthread_join( thread, NULL);
+ }
+ global_sample_power();
+ } else {
+ while (seconds > 0)
+ {
+ do_sleep(sample_interval > seconds ? seconds : sample_interval);
+ seconds -= sample_interval;
+ global_sample_power();
+ }
+ }
+ end_cpu_measurement();
+ end_process_measurement();
+ collect_open_devices();
+ end_devfreq_measurement();
+ devices_end_measurement();
+ end_power_measurement();
+
+ process_cpu_data();
+ process_process_data();
+
+ /* output stats */
+ process_update_display();
+ report_summary();
+ w_display_cpu_cstates();
+ w_display_cpu_pstates();
+ if (reporttype != REPORT_OFF) {
+ report_display_cpu_cstates();
+ report_display_cpu_pstates();
+ }
+ report_process_update_display();
+ tuning_update_display();
+ wakeup_update_display();
+ end_process_data();
+
+ global_power();
+ compute_bundle();
+
+ show_report_devices();
+ report_show_open_devices();
+
+ report_devices();
+ display_devfreq_devices();
+ report_devfreq_devices();
+ ahci_create_device_stats_table();
+ store_results(measurement_time);
+ end_cpu_data();
+}
+
+void out_of_memory()
+{
+ reset_display();
+ printf("%s...\n",_("PowerTOP is out of memory. PowerTOP is Aborting"));
+ abort();
+}
+
+void make_report(int time, char *workload, int iterations, int sample_interval, char *file)
+{
+
+ /* one to warm up everything */
+ fprintf(stderr, _("Preparing to take measurements\n"));
+ utf_ok = 0;
+ one_measurement(1, sample_interval, NULL);
+
+ if (!workload[0])
+ fprintf(stderr, _("Taking %d measurement(s) for a duration of %d second(s) each.\n"),iterations,time);
+ else
+ fprintf(stderr, _("Measuring workload %s.\n"), workload);
+ for (int i=0; i != iterations; i++){
+ init_report_output(file, iterations);
+ initialize_tuning();
+ initialize_wakeup();
+ /* and then the real measurement */
+ one_measurement(time, sample_interval, workload);
+ report_show_tunables();
+ report_show_wakeup();
+ finish_report_output();
+ clear_tuning();
+ }
+ /* and wrap up */
+ learn_parameters(50, 0);
+ save_all_results("saved_results.powertop");
+ save_parameters("saved_parameters.powertop");
+ end_pci_access();
+ exit(0);
+}
+
+static void checkroot() {
+ int uid;
+ uid = getuid();
+
+ if (uid != 0) {
+ printf(_("PowerTOP " PACKAGE_VERSION " must be run with root privileges.\n"));
+ printf(_("exiting...\n"));
+ exit(EXIT_FAILURE);
+ }
+
+}
+
+static int get_nr_open(void) {
+ int nr_open = NR_OPEN_DEF;
+ ifstream file;
+
+ file.open("/proc/sys/fs/nr_open", ios::in);
+ if (file) {
+ file >> nr_open;
+ file.close();
+ }
+ return nr_open;
+}
+
+static void powertop_init(int auto_tune)
+{
+ static char initialized = 0;
+ int ret;
+ struct statfs st_fs;
+ struct rlimit rlmt;
+
+ if (initialized)
+ return;
+
+ checkroot();
+
+ rlmt.rlim_cur = rlmt.rlim_max = get_nr_open();
+ setrlimit (RLIMIT_NOFILE, &rlmt);
+
+ if (system("/sbin/modprobe cpufreq_stats > /dev/null 2>&1"))
+ fprintf(stderr, _("modprobe cpufreq_stats failed\n"));
+#if defined(__i386__) || defined(__x86_64__)
+ if (system("/sbin/modprobe msr > /dev/null 2>&1"))
+ fprintf(stderr, _("modprobe msr failed\n"));
+#endif
+ statfs("/sys/kernel/debug", &st_fs);
+
+ if (st_fs.f_type != (long) DEBUGFS_MAGIC) {
+ if (access("/bin/mount", X_OK) == 0) {
+ ret = system("/bin/mount -t debugfs debugfs /sys/kernel/debug > /dev/null 2>&1");
+ } else {
+ ret = system("mount -t debugfs debugfs /sys/kernel/debug > /dev/null 2>&1");
+ }
+ if (ret != 0) {
+ if (!auto_tune) {
+ fprintf(stderr, _("Failed to mount debugfs!\n"));
+ fprintf(stderr, _("exiting...\n"));
+ exit(EXIT_FAILURE);
+ } else {
+ fprintf(stderr, _("Failed to mount debugfs!\n"));
+ fprintf(stderr, _("Should still be able to auto tune...\n"));
+ }
+ }
+ }
+
+ srand(time(NULL));
+
+ if (access("/var/cache/", W_OK) == 0)
+ mkdir("/var/cache/powertop", 0600);
+ else
+ mkdir("/data/local/powertop", 0600);
+
+ load_results("saved_results.powertop");
+ load_parameters("saved_parameters.powertop");
+
+ enumerate_cpus();
+ create_all_devices();
+ create_all_devfreq_devices();
+ detect_power_meters();
+
+ register_parameter("base power", 100, 0.5);
+ register_parameter("cpu-wakeups", 39.5);
+ register_parameter("cpu-consumption", 1.56);
+ register_parameter("gpu-operations", 0.5576);
+ register_parameter("disk-operations-hard", 0.2);
+ register_parameter("disk-operations", 0.0);
+ register_parameter("xwakes", 0.1);
+
+ load_parameters("saved_parameters.powertop");
+
+ initialized = 1;
+}
+
+void clean_shutdown()
+{
+ close_results();
+ clean_open_devices();
+ clear_all_devices();
+ clear_all_devfreq();
+ clear_all_cpus();
+
+ return;
+}
+
+
+int main(int argc, char **argv)
+{
+ int option_index;
+ int c;
+ char filename[PATH_MAX];
+ char workload[PATH_MAX] = {0};
+ int iterations = 1, auto_tune = 0, sample_interval = 5;
+
+ set_new_handler(out_of_memory);
+
+ setlocale (LC_ALL, "");
+
+#ifdef ENABLE_NLS
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+#endif
+ ui_notify_user = ui_notify_user_ncurses;
+ while (1) { /* parse commandline options */
+ c = getopt_long(argc, argv, "cC::r::i:qt:w:Vh", long_options, &option_index);
+ /* Detect the end of the options. */
+ if (c == -1)
+ break;
+ switch (c) {
+ case OPT_AUTO_TUNE:
+ auto_tune = 1;
+ leave_powertop = 1;
+ ui_notify_user = ui_notify_user_console;
+ break;
+ case 'c':
+ powertop_init(0);
+ calibrate();
+ break;
+ case 'C': /* csv report */
+ reporttype = REPORT_CSV;
+ snprintf(filename, sizeof(filename), "%s", optarg ? optarg : "powertop.csv");
+ if (!strlen(filename))
+ {
+ fprintf(stderr, _("Invalid CSV filename\n"));
+ exit(1);
+ }
+ break;
+ case OPT_DEBUG:
+ /* implemented using getopt_long(3) flag */
+ break;
+ case OPT_EXTECH: /* Extech power analyzer support */
+ checkroot();
+ extech_power_meter(optarg ? optarg : "/dev/ttyUSB0");
+ break;
+ case 'r': /* html report */
+ reporttype = REPORT_HTML;
+ snprintf(filename, sizeof(filename), "%s", optarg ? optarg : "powertop.html");
+ if (!strlen(filename))
+ {
+ fprintf(stderr, _("Invalid HTML filename\n"));
+ exit(1);
+ }
+ break;
+ case 'i':
+ iterations = (optarg ? atoi(optarg) : 1);
+ break;
+ case 'q':
+ if (freopen("/dev/null", "a", stderr))
+ fprintf(stderr, _("Quiet mode failed!\n"));
+ break;
+ case 's':
+ sample_interval = (optarg ? atoi(optarg) : 5);
+ break;
+ case 't':
+ time_out = (optarg ? atoi(optarg) : 20);
+ break;
+ case 'w': /* measure workload */
+ snprintf(workload, sizeof(workload), "%s", optarg ? optarg : "");
+ break;
+ case 'V':
+ print_version();
+ exit(0);
+ break;
+ case 'h':
+ print_usage();
+ exit(0);
+ break;
+ case '?': /* Unknown option */
+ /* getopt_long already printed an error message. */
+ exit(1);
+ break;
+ }
+ }
+
+ powertop_init(auto_tune);
+
+ if (reporttype != REPORT_OFF)
+ make_report(time_out, workload, iterations, sample_interval, filename);
+
+ if (debug_learning)
+ printf("Learning debugging enabled\n");
+
+ learn_parameters(250, 0);
+ save_parameters("saved_parameters.powertop");
+
+
+ if (debug_learning) {
+ learn_parameters(1000, 1);
+ dump_parameter_bundle();
+ end_pci_access();
+ exit(0);
+ }
+ if (!auto_tune)
+ init_display();
+
+ initialize_devfreq();
+ initialize_tuning();
+ initialize_wakeup();
+ /* first one is short to not let the user wait too long */
+ one_measurement(1, sample_interval, NULL);
+
+ if (!auto_tune) {
+ tuning_update_display();
+ show_tab(0);
+ } else {
+ auto_toggle_tuning();
+ }
+
+ while (!leave_powertop) {
+ if (!auto_tune)
+ show_cur_tab();
+ one_measurement(time_out, sample_interval, NULL);
+ learn_parameters(15, 0);
+ }
+ if (!auto_tune)
+ endwin();
+ fprintf(stderr, "%s\n", _("Leaving PowerTOP"));
+
+ end_process_data();
+ clear_process_data();
+ end_cpu_data();
+ clear_cpu_data();
+
+ save_all_results("saved_results.powertop");
+ save_parameters("saved_parameters.powertop");
+ learn_parameters(500, 0);
+ save_parameters("saved_parameters.powertop");
+ end_pci_access();
+ clear_tuning();
+ reset_display();
+
+ clean_shutdown();
+
+ return 0;
+}
diff --git a/src/measurement/acpi.cpp b/src/measurement/acpi.cpp
new file mode 100644
index 0000000..572852c
--- /dev/null
+++ b/src/measurement/acpi.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "measurement.h"
+#include "acpi.h"
+#include <iostream>
+#include <fstream>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "../lib.h"
+
+using namespace std;
+
+acpi_power_meter::acpi_power_meter(const char *acpi_name)
+{
+ rate = 0.0;
+ capacity = 0.0;
+ voltage = 0.0;
+ pt_strcpy(battery_name, acpi_name);
+}
+
+/*
+present: yes
+capacity state: ok
+charging state: discharging
+present rate: 8580 mW
+remaining capacity: 34110 mWh
+present voltage: 12001 mV
+*/
+
+void acpi_power_meter::measure(void)
+{
+ char filename[PATH_MAX];
+ char line[4096];
+ ifstream file;
+
+ double _rate = 0;
+ double _capacity = 0;
+ double _voltage = 0;
+
+ char rate_units[16];
+ char capacity_units[16];
+ char voltage_units[16];
+
+ rate_units[0] = 0;
+ capacity_units[0] = 0;
+ voltage_units[0] = 0;
+
+ rate = 0;
+ voltage = 0;
+ capacity = 0;
+
+ snprintf(filename, sizeof(filename), "/proc/acpi/battery/%s/state", battery_name);
+
+ file.open(filename, ios::in);
+ if (!file)
+ return;
+
+ while (file) {
+ char *c;
+ file.getline(line, sizeof(line));
+
+ if (strstr(line, "present:") && (strstr(line, "yes") == NULL)) {
+ return;
+ }
+ if (strstr(line, "charging state:") && (strstr(line, "discharging") == NULL)) {
+ return; /* not discharging */
+ }
+ if (strstr(line, "present rate:")) {
+ c = strchr(line, ':');
+ c++;
+ while (*c == ' ') c++;
+ _rate = strtoull(c, NULL, 10);
+ c = strchr(c, ' ');
+ if (c) {
+ c++;
+ pt_strcpy(rate_units, c);
+ } else {
+ _rate = 0;
+ strcpy(rate_units, "Unknown");
+ }
+
+ }
+ if (strstr(line, "remaining capacity:")) {
+ c = strchr(line, ':');
+ c++;
+ while (*c == ' ') c++;
+ _capacity = strtoull(c, NULL, 10);
+ c = strchr(c, ' ');
+ if (c) {
+ c++;
+ pt_strcpy(capacity_units, c);
+ } else {
+ _capacity = 0;
+ strcpy(capacity_units, "Unknown");
+ }
+ }
+ if (strstr(line, "present voltage:")) {
+ c = strchr(line, ':');
+ c++;
+ while (*c == ' ') c++;
+ _voltage = strtoull(c, NULL, 10);
+ c = strchr(c, ' ');
+ if (c) {
+ c++;
+ pt_strcpy(voltage_units, c);
+ } else {
+ _voltage = 0;
+ strcpy(voltage_units, "Unknown");
+ }
+ }
+ }
+ file.close();
+
+ /* BIOS report random crack-inspired units. Lets try to get to the Si-system units */
+
+ if (strcmp(voltage_units, "mV") == 0) {
+ _voltage = _voltage / 1000.0;
+ strcpy(voltage_units, "V");
+ }
+
+ if (strcmp(rate_units, "mW") == 0) {
+ _rate = _rate / 1000.0;
+ strcpy(rate_units, "W");
+ }
+
+ if (strcmp(rate_units, "mA") == 0) {
+ _rate = _rate / 1000.0;
+ strcpy(rate_units, "A");
+ }
+
+ if (strcmp(capacity_units, "mAh") == 0) {
+ _capacity = _capacity / 1000.0;
+ strcpy(capacity_units, "Ah");
+ }
+ if (strcmp(capacity_units, "mWh") == 0) {
+ _capacity = _capacity / 1000.0;
+ strcpy(capacity_units, "Wh");
+ }
+ if (strcmp(capacity_units, "Wh") == 0) {
+ _capacity = _capacity * 3600.0;
+ strcpy(capacity_units, "J");
+ }
+
+
+ if (strcmp(capacity_units, "Ah") == 0 && strcmp(voltage_units, "V") == 0) {
+ _capacity = _capacity * 3600.0 * _voltage;
+ strcpy(capacity_units, "J");
+ }
+
+ if (strcmp(rate_units, "A") == 0 && strcmp(voltage_units, "V")==0 ) {
+ _rate = _rate * _voltage;
+ strcpy(rate_units, "W");
+ }
+
+
+
+
+ if (strcmp(capacity_units, "J") == 0)
+ capacity = _capacity;
+ else
+ capacity = 0.0;
+
+ if (strcmp(rate_units, "W")==0)
+ rate = _rate;
+ else
+ rate = 0.0;
+
+ if (strcmp(voltage_units, "V")==0)
+ voltage = _voltage;
+ else
+ voltage = 0.0;
+}
+
+
+void acpi_power_meter::end_measurement(void)
+{
+ measure();
+}
+
+void acpi_power_meter::start_measurement(void)
+{
+ /* ACPI battery state is a lagging indication, lets only measure at the end */
+}
+
+
+double acpi_power_meter::power(void)
+{
+ return rate;
+}
diff --git a/src/measurement/acpi.h b/src/measurement/acpi.h
new file mode 100644
index 0000000..25bbe04
--- /dev/null
+++ b/src/measurement/acpi.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef __INCLUDE_GUARD_ACPI_H
+#define __INCLUDE_GUARD_ACPI_H
+
+#include "measurement.h"
+
+class acpi_power_meter: public power_meter {
+ char battery_name[256];
+
+ double capacity;
+ double rate;
+ double voltage;
+ void measure(void);
+public:
+ acpi_power_meter(const char *_battery_name);
+ virtual void start_measurement(void);
+ virtual void end_measurement(void);
+
+ virtual double power(void);
+ virtual double dev_capacity(void) { return capacity; };
+};
+
+#endif
diff --git a/src/measurement/extech.cpp b/src/measurement/extech.cpp
new file mode 100644
index 0000000..867aca7
--- /dev/null
+++ b/src/measurement/extech.cpp
@@ -0,0 +1,354 @@
+/*
+ * extech - Program for controlling the extech Device
+ * This file is part of PowerTOP
+ *
+ * Based on earlier client by Patrick Mochel for Wattsup Pro device
+ * Copyright (c) 2005 Patrick Mochel
+ * Copyright (c) 2006 Intel Corporation
+ * Copyright (c) 2011 Intel Corporation
+ *
+ * Authors:
+ * Patrick Mochel
+ * Venkatesh Pallipadi
+ * Arjan van de Ven
+ *
+ * Thanks to Rajiv Kapoor for finding out the DTR, RTS line bits issue below
+ * Without that this program would never work.
+ *
+ *
+ * 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.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <time.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <sys/stat.h>
+
+#include "measurement.h"
+#include "extech.h"
+#include "../lib.h"
+#include <iostream>
+#include <fstream>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+using namespace std;
+
+struct packet {
+ char buf[256];
+ char op[32];
+ double watts;
+ int len;
+};
+
+
+static int open_device(const char *device_name)
+{
+ struct stat s;
+ int ret;
+
+ ret = stat(device_name, &s);
+ if (ret < 0)
+ return -1;
+
+ if (!S_ISCHR(s.st_mode))
+ return -1;
+
+ ret = access(device_name, R_OK | W_OK);
+ if (ret)
+ return -1;
+
+ ret = open(device_name, O_RDWR | O_NONBLOCK | O_NOCTTY);
+ if (ret < 0)
+ return -1;
+
+ return ret;
+}
+
+
+static int setup_serial_device(int dev_fd)
+{
+ struct termios t;
+ int ret;
+ int flgs;
+
+ ret = tcgetattr(dev_fd, &t);
+ if (ret)
+ return ret;
+
+ cfmakeraw(&t);
+ cfsetispeed(&t, B9600);
+ cfsetospeed(&t, B9600);
+ tcflush(dev_fd, TCIFLUSH);
+
+ t.c_iflag = IGNPAR;
+ t.c_cflag = B9600 | CS8 | CREAD | CLOCAL;
+ t.c_oflag = 0;
+ t.c_lflag = 0;
+ t.c_cc[VMIN] = 2;
+ t.c_cc[VTIME] = 0;
+
+ t.c_iflag &= ~(IXON | IXOFF | IXANY);
+ t.c_oflag &= ~(IXON | IXOFF | IXANY);
+
+ ret = tcsetattr(dev_fd, TCSANOW, &t);
+
+ if (ret)
+ return ret;
+
+ /*
+ * Root caused by Rajiv Kapoor. Without this extech reads
+ * will fail
+ */
+
+ /* get DTR and RTS line bits settings */
+ ioctl(dev_fd, TIOCMGET, &flgs);
+
+ /* set DTR to 1 and RTS to 0 */
+ flgs |= TIOCM_DTR;
+ flgs &= ~TIOCM_RTS;
+ ioctl(dev_fd, TIOCMSET, &flgs);
+
+ return 0;
+}
+
+
+static unsigned int decode_extech_value(unsigned char byt3, unsigned char byt4, char *a)
+{
+ unsigned int input = ((unsigned int)byt4 << 8) + byt3;
+ unsigned int i;
+ unsigned int idx;
+ unsigned char revnum[] = { 0x0, 0x8, 0x4, 0xc,
+ 0x2, 0xa, 0x6, 0xe,
+ 0x1, 0x9, 0x5, 0xd,
+ 0x3, 0xb, 0x7, 0xf};
+ unsigned char revdec[] = { 0x0, 0x2, 0x1, 0x3};
+
+ unsigned int digit_map[] = {0x2, 0x3c, 0x3c0, 0x3c00};
+ unsigned int digit_shift[] = {1, 2, 6, 10};
+
+ unsigned int sign;
+ unsigned int decimal;
+
+ /* this is basically BCD encoded floating point... but kinda weird */
+
+ decimal = (input & 0xc000) >> 14;
+ decimal = revdec[decimal];
+
+ sign = input & 0x1;
+
+ idx = 0;
+ if (sign)
+ a[idx++] = '+';
+ else
+ a[idx++] = '-';
+
+ /* first digit is only one or zero */
+ a[idx] = '0';
+ if ((input & digit_map[0]) >> digit_shift[0])
+ a[idx] += 1;
+
+ idx++;
+ /* Reverse the remaining three digits and store in the array */
+ for (i = 1; i < 4; i++) {
+ int dig = ((input & digit_map[i]) >> digit_shift[i]);
+ dig = revnum[dig];
+ if (dig > 0xa)
+ goto error_exit;
+
+ a[idx++] = '0' + dig;
+ }
+
+ /* Fit the decimal point where appropriate */
+ for (i = 0; i < decimal; i++)
+ a[idx - i] = a[idx - i - 1];
+
+ a[idx - decimal] = '.';
+ a[++idx] = '0';
+ a[++idx] = '\0';
+
+ return 0;
+error_exit:
+ return -1;
+}
+
+static int parse_packet(struct packet * p)
+{
+ int i;
+ int ret;
+
+ p->buf[p->len] = '\0';
+
+ /*
+ * First character in 5 character block should be '02'
+ * Fifth character in 5 character block should be '03'
+ */
+ for (i = 0; i < 4; i++) {
+ if (p->buf[i * 0] != 2 || p->buf[i * 0 + 4] != 3) {
+ printf("Invalid packet\n");
+ return -1;
+ }
+ }
+
+ for (i = 0; i < 1; i++) {
+ ret = decode_extech_value(p->buf[5 * i + 2],
+ p->buf[5 * i + 3],
+ &(p->op[8 * i]));
+ if (ret) {
+ printf("Invalid packet, conversion failed\n");
+ return -1;
+ }
+ p->watts = strtod( &(p->op[8 * i]), NULL);
+ }
+ return 0;
+}
+
+
+static double extech_read(int fd)
+{
+ struct packet p;
+ fd_set read_fd;
+ struct timeval tv;
+ int ret;
+
+ if (fd < 0)
+ return 0.0;
+
+ FD_ZERO(&read_fd);
+ FD_SET(fd, &read_fd);
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 500000;
+
+ memset(&p, 0, sizeof(p));
+
+ ret = select(fd + 1, &read_fd, NULL, NULL, &tv);
+ if (ret <= 0)
+ return -1;
+
+ ret = read(fd, &p.buf, 250);
+ if (ret < 0)
+ return ret;
+ p.len = ret;
+
+ if (!parse_packet(&p))
+ return p.watts;
+
+ return -1000.0;
+}
+
+extech_power_meter::extech_power_meter(const char *extech_name)
+{
+ rate = 0.0;
+ pt_strcpy(dev_name, extech_name);
+ int ret;
+
+ fd = open_device(dev_name);
+ if (fd < 0)
+ return;
+
+ ret = setup_serial_device(fd);
+ if (ret) {
+ close(fd);
+ fd = -1;
+ return;
+ }
+}
+
+
+void extech_power_meter::measure(void)
+{
+ /* trigger the extech to send data */
+ if(write(fd, " ", 1) == -1)
+ printf("Error: %s\n", strerror(errno));
+
+ rate = extech_read(fd);
+
+}
+
+void extech_power_meter::sample(void)
+{
+ ssize_t ret;
+ struct timespec tv;
+
+ tv.tv_sec = 0;
+ tv.tv_nsec = 200000000;
+ while (!end_thread) {
+ nanosleep(&tv, NULL);
+ /* trigger the extech to send data */
+ ret = write(fd, " ", 1);
+ if (ret < 0)
+ continue;
+
+ sum += extech_read(fd);
+ samples++;
+
+ }
+}
+
+extern "C"
+{
+ void* thread_proc(void *arg)
+ {
+ class extech_power_meter *parent;
+ parent = (class extech_power_meter*)arg;
+ parent->sample();
+ return 0;
+ }
+}
+
+void extech_power_meter::end_measurement(void)
+{
+ end_thread = 1;
+ pthread_join( thread, NULL);
+ if (samples){
+ rate = sum / samples;
+ }
+ else
+ measure();
+}
+
+void extech_power_meter::start_measurement(void)
+{
+ end_thread = 0;
+ sum = samples = 0;
+
+ if (pthread_create(&thread, NULL, thread_proc, this))
+ fprintf(stderr, "ERROR: extech measurement thread creation failed\n");
+
+}
+
+
+double extech_power_meter::power(void)
+{
+ return rate;
+}
diff --git a/src/measurement/extech.h b/src/measurement/extech.h
new file mode 100644
index 0000000..b7b330a
--- /dev/null
+++ b/src/measurement/extech.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef __INCLUDE_GUARD_EXTECH_H
+#define __INCLUDE_GUARD_EXTECH_H
+
+#include <pthread.h>
+#include "measurement.h"
+
+class extech_power_meter: public power_meter {
+ char dev_name[256];
+ int fd;
+
+ double rate;
+ void measure(void);
+ double sum;
+ int samples;
+ int end_thread;
+ pthread_t thread;
+public:
+ extech_power_meter(const char *_dev_name);
+ virtual void start_measurement(void);
+ virtual void end_measurement(void);
+ virtual void sample(void);
+
+ virtual double power(void);
+ virtual double dev_capacity(void) { return 0.0; };
+};
+
+#endif
diff --git a/src/measurement/measurement.cpp b/src/measurement/measurement.cpp
new file mode 100644
index 0000000..caee24e
--- /dev/null
+++ b/src/measurement/measurement.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "measurement.h"
+#include "acpi.h"
+#include "extech.h"
+#include "sysfs.h"
+#include "opal-sensors.h"
+#include "../parameters/parameters.h"
+#include "../lib.h"
+
+#include <string>
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <fstream>
+#include <unistd.h>
+#include <time.h>
+
+double min_power = 50000.0;
+
+void power_meter::start_measurement(void)
+{
+}
+
+
+void power_meter::end_measurement(void)
+{
+}
+
+
+double power_meter::power(void)
+{
+ return 0.0;
+}
+
+vector<class power_meter *> power_meters;
+
+static struct timespec tlast;
+
+void start_power_measurement(void)
+{
+ unsigned int i;
+ clock_gettime(CLOCK_REALTIME, &tlast);
+ for (i = 0; i < power_meters.size(); i++)
+ power_meters[i]->start_measurement();
+ all_results.joules = 0.0;
+}
+void end_power_measurement(void)
+{
+ unsigned int i;
+ for (i = 0; i < power_meters.size(); i++)
+ power_meters[i]->end_measurement();
+}
+
+double global_power(void)
+{
+ bool global_discharging = false;
+ double total = 0.0;
+ unsigned int i;
+
+ for (i = 0; i < power_meters.size(); i++) {
+ global_discharging |= power_meters[i]->is_discharging();
+ total += power_meters[i]->power();
+ }
+
+ /* report global time left if at least one battery is discharging */
+ if (!global_discharging)
+ return 0.0;
+
+ all_results.power = total;
+ if (total < min_power && total > 0.01)
+ min_power = total;
+ return total;
+}
+
+void global_sample_power(void)
+{
+ struct timespec tnow;
+
+ clock_gettime(CLOCK_REALTIME, &tnow);
+ /* power * time = joules */
+ all_results.joules += global_power() * \
+ ( ((double)tnow.tv_sec + 1.0e-9*tnow.tv_nsec) - \
+ ((double)tlast.tv_sec + 1.0e-9*tlast.tv_nsec));
+ tlast = tnow;
+}
+
+double global_joules(void)
+{
+ return all_results.joules;
+}
+
+double global_time_left(void)
+{
+ bool global_discharging = false;
+ double total_capacity = 0.0;
+ double total_rate = 0.0;
+ unsigned int i;
+ for (i = 0; i < power_meters.size(); i++) {
+ global_discharging |= power_meters[i]->is_discharging();
+ total_capacity += power_meters[i]->dev_capacity();
+ total_rate += power_meters[i]->power();
+ }
+ /* report global time left if at least one battery is discharging */
+ if (!global_discharging)
+ return 0.0;
+
+ /* return 0.0 instead of INF+ */
+ if (total_rate < 0.001)
+ return 0.0;
+ return total_capacity / total_rate;
+}
+
+void sysfs_power_meters_callback(const char *d_name)
+{
+ std::string type = read_sysfs_string("/sys/class/power_supply/%s/type", d_name);
+
+ if (type != "Battery" && type != "UPS")
+ return;
+
+ class sysfs_power_meter *meter;
+ meter = new(std::nothrow) class sysfs_power_meter(d_name);
+ if (meter)
+ power_meters.push_back(meter);
+}
+
+void acpi_power_meters_callback(const char *d_name)
+{
+ class acpi_power_meter *meter;
+ meter = new(std::nothrow) class acpi_power_meter(d_name);
+ if (meter)
+ power_meters.push_back(meter);
+}
+
+void sysfs_opal_sensors_callback(const char *d_name)
+{
+ class opal_sensors_power_meter *meter;
+ const char *c;
+
+ /* Those that end in / are directories and we don't want them */
+ c = strrchr(d_name, '/');
+ if (c && *(c+1) == '\0')
+ return;
+
+ meter = new(std::nothrow) class opal_sensors_power_meter(d_name);
+ if (meter)
+ power_meters.push_back(meter);
+}
+
+void detect_power_meters(void)
+{
+ process_directory("/sys/class/power_supply", sysfs_power_meters_callback);
+ process_glob("/sys/devices/platform/opal-sensor/hwmon/hwmon*/power*", sysfs_opal_sensors_callback);
+ if (power_meters.size() == 0) {
+ process_directory("/proc/acpi/battery", acpi_power_meters_callback);
+ }
+}
+
+void extech_power_meter(const char *devnode)
+{
+ class extech_power_meter *meter;
+
+ meter = new class extech_power_meter(devnode);
+
+ power_meters.push_back(meter);
+}
diff --git a/src/measurement/measurement.h b/src/measurement/measurement.h
new file mode 100644
index 0000000..9a84bc2
--- /dev/null
+++ b/src/measurement/measurement.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef __INCLUDE_GUARD_MEASUREMENT_H
+#define __INCLUDE_GUARD_MEASUREMENT_H
+
+#include <vector>
+
+using namespace std;
+
+class power_meter {
+ bool discharging = false;
+public:
+ virtual ~power_meter() {};
+
+ virtual void start_measurement(void);
+ virtual void end_measurement(void);
+ virtual double power(void);
+
+ virtual double dev_capacity(void)
+ {
+ return 0.0; /* in Joules */
+ }
+
+ virtual void set_discharging(bool d)
+ {
+ discharging = d;
+ }
+
+ virtual bool is_discharging()
+ {
+ return discharging;
+ }
+};
+
+extern vector<class power_meter *> power_meters;
+
+extern void start_power_measurement(void);
+extern void end_power_measurement(void);
+extern double global_power(void);
+extern void global_sample_power(void);
+extern double global_joules(void);
+extern double global_time_left(void);
+
+extern void detect_power_meters(void);
+extern void extech_power_meter(const char *devnode);
+
+extern double min_power;
+
+#endif
diff --git a/src/measurement/opal-sensors.cpp b/src/measurement/opal-sensors.cpp
new file mode 100644
index 0000000..a70ec56
--- /dev/null
+++ b/src/measurement/opal-sensors.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015 IBM Corp.
+ *
+ * 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:
+ * Stewart Smith <stewart@linux.vnet.ibm.com>
+ */
+#include "measurement.h"
+#include "opal-sensors.h"
+#include "../lib.h"
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+
+opal_sensors_power_meter::opal_sensors_power_meter(const char *power_supply_name)
+{
+ strncpy(name, power_supply_name, sizeof(name));
+}
+
+double opal_sensors_power_meter::power(void)
+{
+ bool ok;
+ int value;
+ double r = 0;
+
+ value = read_sysfs(name, &ok);
+
+ if(ok)
+ r = value / 1000000.0;
+ return r;
+}
diff --git a/src/measurement/opal-sensors.h b/src/measurement/opal-sensors.h
new file mode 100644
index 0000000..7962091
--- /dev/null
+++ b/src/measurement/opal-sensors.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015 IBM Corp.
+ *
+ * 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:
+ * Stewart Smith <stewart@linux.vnet.ibm.com>
+ */
+#ifndef INCLUDE_GUARD_OPAL_SENSORS_H
+#define INCLUDE_GUARD_OPAL_SENSORS_H
+
+#include "measurement.h"
+#include <limits.h>
+
+class opal_sensors_power_meter: public power_meter {
+ char name[PATH_MAX];
+public:
+ opal_sensors_power_meter(const char *power_supply_name);
+ virtual void start_measurement(void) {};
+ virtual void end_measurement(void) {};
+
+ virtual double power(void);
+ virtual double dev_capacity(void) { return 0.0; }
+};
+
+#endif
diff --git a/src/measurement/sysfs.cpp b/src/measurement/sysfs.cpp
new file mode 100644
index 0000000..c5a7a12
--- /dev/null
+++ b/src/measurement/sysfs.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2011 Anssi Hannula
+ *
+ * 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:
+ * Anssi Hannula <anssi.hannula@iki.fi>
+ */
+#include "measurement.h"
+#include "sysfs.h"
+#include "../lib.h"
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+
+sysfs_power_meter::sysfs_power_meter(const char *power_supply_name)
+{
+ rate = 0.0;
+ capacity = 0.0;
+ pt_strcpy(name, power_supply_name);
+}
+
+bool sysfs_power_meter::get_sysfs_attr(const char *attribute, int *value)
+{
+ char filename[PATH_MAX];
+ bool ok;
+
+ snprintf(filename, sizeof(filename), "/sys/class/power_supply/%s/%s", name, attribute);
+ *value = read_sysfs(filename, &ok);
+
+ return ok;
+}
+
+bool sysfs_power_meter::is_present()
+{
+ int present = 0;
+
+ if (!get_sysfs_attr("present", &present))
+ return true; /* assume always present */
+
+ return present;
+}
+
+double sysfs_power_meter::get_voltage()
+{
+ int voltage;
+
+ if (!get_sysfs_attr("voltage_now", &voltage))
+ return -1.0;
+
+ /* µV to V */
+ return voltage / 1000000.0;
+}
+
+bool sysfs_power_meter::set_rate_from_power()
+{
+ int power;
+
+ if (!get_sysfs_attr("power_now", &power))
+ return false;
+
+ /* µW to W */
+ rate = power / 1000000.0;
+ return true;
+}
+
+bool sysfs_power_meter::set_rate_from_current(double voltage)
+{
+ int current;
+
+ if (!get_sysfs_attr("current_now", &current))
+ return false;
+
+ /* current: µA
+ * voltage: V
+ * rate: W */
+ rate = (current / 1000000.0) * voltage;
+ return true;
+}
+
+bool sysfs_power_meter::set_capacity_from_energy()
+{
+ int energy;
+
+ if (!get_sysfs_attr("energy_now", &energy))
+ return false;
+
+ /* µWh to J */
+ capacity = energy / 1000000.0 * 3600.0;
+ return true;
+}
+
+bool sysfs_power_meter::set_capacity_from_charge(double voltage)
+{
+ int charge;
+
+ if (!get_sysfs_attr("charge_now", &charge))
+ return false;
+
+ /* charge: µAh
+ * voltage: V
+ * capacity: J */
+ capacity = (charge / 1000000.0) * voltage * 3600.0;
+ return true;
+}
+
+void sysfs_power_meter::measure()
+{
+ bool got_rate = false;
+ bool got_capacity = false;
+
+ rate = 0.0;
+ capacity = 0.0;
+ this->set_discharging(false);
+
+ if (!is_present())
+ return;
+ /** do not jump over. we may have discharging battery */
+ if (read_sysfs_string("/sys/class/power_supply/%s/status", name) == "Discharging")
+ this->set_discharging(true);
+
+ got_rate = set_rate_from_power();
+ got_capacity = set_capacity_from_energy();
+
+ if (!got_rate || !got_capacity) {
+ double voltage = get_voltage();
+ if (voltage < 0.0)
+ return;
+ if (!got_rate)
+ set_rate_from_current(voltage);
+ if (!got_capacity)
+ set_capacity_from_charge(voltage);
+ }
+}
+
+void sysfs_power_meter::end_measurement(void)
+{
+ measure();
+}
+
+void sysfs_power_meter::start_measurement(void)
+{
+ /* Battery state is generally a lagging indication, lets only measure at the end */
+}
diff --git a/src/measurement/sysfs.h b/src/measurement/sysfs.h
new file mode 100644
index 0000000..5b440f5
--- /dev/null
+++ b/src/measurement/sysfs.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011 Anssi Hannula
+ *
+ * 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:
+ * Anssi Hannula <anssi.hannula@iki.fi>
+ */
+#ifndef INCLUDE_GUARD_SYSFS_H
+#define INCLUDE_GUARD_SYSFS_H
+
+#include "measurement.h"
+
+class sysfs_power_meter: public power_meter {
+ char name[256];
+
+ double capacity;
+ double rate;
+
+ bool get_sysfs_attr(const char *attribute, int *value);
+ bool is_present();
+ double get_voltage();
+
+ bool set_rate_from_power();
+ bool set_rate_from_current(double voltage);
+ bool set_capacity_from_energy();
+ bool set_capacity_from_charge(double voltage);
+
+ void measure();
+public:
+ sysfs_power_meter(const char *power_supply_name);
+ virtual void start_measurement(void);
+ virtual void end_measurement(void);
+
+ virtual double power(void) { return rate; }
+ virtual double dev_capacity(void) { return capacity; }
+};
+
+#endif
diff --git a/src/parameters/learn.cpp b/src/parameters/learn.cpp
new file mode 100644
index 0000000..aaef5a2
--- /dev/null
+++ b/src/parameters/learn.cpp
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "parameters.h"
+#include "../measurement/measurement.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+extern int debug_learning;
+
+double calculate_params(struct parameter_bundle *params)
+{
+ unsigned int i;
+
+ params->score = 0;
+
+
+ for (i = 0; i < past_results.size(); i++)
+ compute_bundle(params, past_results[i]);
+
+ return params->score;
+}
+
+
+/*
+ * gradual linear convergence of non-independent variables works better if once in a while
+ * you make a wrong move....
+ */
+static int random_disturb(int retry_left)
+{
+ if (retry_left < 10)
+ return 0;
+
+ if ( (rand() % 500) == 7)
+ return 1;
+ return 0;
+}
+
+static int try_zero(double value)
+{
+ if (value > 0.01)
+ if ( (rand() % 100) == 1)
+ return 1;
+
+ if ( (rand() % 5) == 1)
+ return 1;
+ return 0;
+}
+
+static unsigned int previous_measurements;
+
+static void weed_empties(struct parameter_bundle *best_so_far)
+{
+ double best_score;
+ unsigned int i;
+
+ best_score = best_so_far->score;
+
+
+ for (i = 0; i < best_so_far->parameters.size(); i++) {
+ double orgvalue;
+
+ orgvalue = best_so_far->parameters[i];
+
+
+ best_so_far->parameters[i] = 0.0;
+
+ calculate_params(best_so_far);
+ if (best_so_far->score > best_score) {
+ best_so_far->parameters[i] = orgvalue;
+ } else {
+ best_score = best_so_far->score;
+ }
+
+ }
+ calculate_params(best_so_far);
+
+}
+
+/* leaks like a sieve */
+void learn_parameters(int iterations, int do_base_power)
+{
+ struct parameter_bundle *best_so_far;
+ double best_score = 10000000000000000.0;
+ int retry = iterations;
+ int prevparam = -1;
+ int locked = 0;
+ static unsigned int bpi = 0;
+ unsigned int i;
+ time_t start;
+
+ /* don't start fitting anything until we have at least 1 more measurement than we have parameters */
+ if (past_results.size() <= all_parameters.parameters.size())
+ return;
+
+
+
+// if (past_results.size() == previous_measurements)
+// return;
+
+ precompute_valid();
+
+
+ previous_measurements = past_results.size();
+
+ double delta = 0.50;
+
+ best_so_far = &all_parameters;
+
+ if (!bpi)
+ bpi = get_param_index("base power");
+
+ calculate_params(best_so_far);
+ best_score = best_so_far->score;
+
+ delta = 0.001 / pow(0.8, iterations / 2.0);
+ if (iterations < 25)
+ delta = 0.001 / pow(0.5, iterations / 2.0);
+
+ if (delta > 0.2)
+ delta = 0.2;
+
+ if (1.0 * best_score / past_results.size() < 4 && delta > 0.05)
+ delta = 0.05;
+
+ if (debug_learning)
+ printf("Delta starts at %5.3f\n", delta);
+
+ if (best_so_far->parameters[bpi] > min_power * 0.9)
+ best_so_far->parameters[bpi] = min_power * 0.9;
+
+ /* We want to give up a little of base power, to give other parameters room to change;
+ base power is the end post for everything after all
+ */
+ if (do_base_power && !debug_learning)
+ best_so_far->parameters[bpi] = best_so_far->parameters[bpi] * 0.9998;
+
+ start = time(NULL);
+
+ while (retry--) {
+ int changed = 0;
+ int bestparam;
+ double newvalue = 0;
+ double orgscore;
+ double weight;
+
+ bestparam = -1;
+
+ if (time(NULL) - start > 1 && !debug_learning)
+ retry = 0;
+
+ calculate_params(best_so_far);
+ orgscore = best_score = best_so_far->score;
+
+
+ for (i = 1; i < best_so_far->parameters.size(); i++) {
+ double value, orgvalue;
+
+ weight = delta * best_so_far->weights[i];
+
+ orgvalue = value = best_so_far->parameters[i];
+ if (value <= 0.001) {
+ value = 0.1;
+ } else
+ value = value * (1 + weight);
+
+ if (i == bpi && value > min_power)
+ value = min_power;
+
+ if (i == bpi && orgvalue > min_power)
+ orgvalue = min_power;
+
+ if (value > 5000)
+ value = 5000;
+
+// printf("Trying %s %4.2f -> %4.2f\n", param.c_str(), best_so_far->parameters[param], value);
+ best_so_far->parameters[i] = value;
+
+ calculate_params(best_so_far);
+ if (best_so_far->score < best_score || random_disturb(retry)) {
+ best_score = best_so_far->score;
+ newvalue = value;
+ bestparam = i;
+ changed++;
+ }
+
+ value = orgvalue * 1 / (1 + weight);
+
+ if (value < 0.0001)
+ value = 0.0;
+
+ if (try_zero(value))
+ value = 0.0;
+
+
+ if (value > 5000)
+ value = 5000;
+
+
+// printf("Trying %s %4.2f -> %4.2f\n", param.c_str(), orgvalue, value);
+
+ if (orgvalue != value) {
+ best_so_far->parameters[i] = value;
+
+ calculate_params(best_so_far);
+
+ if (best_so_far->score + 0.00001 < best_score || (random_disturb(retry) && value > 0.0)) {
+ best_score = best_so_far->score;
+ newvalue = value;
+ bestparam = i;
+ changed++;
+ }
+ }
+ best_so_far->parameters[i] = orgvalue;
+
+ }
+ if (!changed) {
+ double mult;
+
+ if (!locked) {
+ mult = 0.8;
+ if (iterations < 25)
+ mult = 0.5;
+ delta = delta * mult;
+ }
+ locked = 0;
+ prevparam = -1;
+ } else {
+ if (debug_learning) {
+ printf("Retry is %i \n", retry);
+ printf("delta is %5.4f\n", delta);
+ printf("Best parameter is %i \n", bestparam);
+ printf("Changing score from %4.3f to %4.3f\n", orgscore, best_score);
+ printf("Changing value from %4.3f to %4.3f\n", best_so_far->parameters[bestparam], newvalue);
+ }
+ best_so_far->parameters[bestparam] = newvalue;
+ if (prevparam == bestparam)
+ delta = delta * 1.1;
+ prevparam = bestparam;
+ locked = 1;
+ }
+
+ if (delta < 0.001 && !locked)
+ break;
+
+ if (retry % 50 == 49)
+ weed_empties(best_so_far);
+ }
+
+
+ /* now we weed out all parameters that don't have value */
+ if (iterations > 50)
+ weed_empties(best_so_far);
+
+ if (debug_learning)
+ printf("Final score %4.2f (%i points)\n", best_so_far->score / past_results.size(), (int)past_results.size());
+// dump_parameter_bundle(best_so_far);
+// dump_past_results();
+}
diff --git a/src/parameters/parameters.cpp b/src/parameters/parameters.cpp
new file mode 100644
index 0000000..38e1752
--- /dev/null
+++ b/src/parameters/parameters.cpp
@@ -0,0 +1,462 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "parameters.h"
+#include "../measurement/measurement.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include <vector>
+#include <unistd.h>
+#include <limits.h>
+
+
+struct parameter_bundle all_parameters;
+struct result_bundle all_results;
+
+vector <struct result_bundle *> past_results;
+
+map <string, int> param_index;
+static int maxindex = 1;
+map <string, int> result_index;
+static int maxresindex = 1;
+
+int get_param_index(const char *name)
+{
+ std::map<string, int>::iterator it;
+ int index = 0;
+
+ it = param_index.find(name);
+ if (it == param_index.end()) {
+ param_index[name] = ++maxindex;
+ index = maxindex;
+ } else
+ index = it->second;
+
+ if (index == 0)
+ printf("OH BLA\n");
+ return index;
+}
+
+int get_result_index(const char *name)
+{
+ std::map<string, int>::iterator it;
+ int index = 0;
+
+ it = result_index.find(name);
+ if (it == result_index.end()) {
+ result_index[name] = ++maxresindex;
+ index = maxresindex;
+ } else
+ index = it->second;
+
+ return index;
+}
+
+
+void register_parameter(const char *name, double default_value, double weight)
+{
+ int index;
+
+ index = get_param_index(name);
+
+ if (index >= (int)all_parameters.parameters.size()) {
+ all_parameters.parameters.resize(index+1, 0.0);
+ all_parameters.weights.resize(index+1, 1.0);
+ }
+
+ if (all_parameters.parameters[index] <= 0.0001)
+ all_parameters.parameters[index] = default_value;
+
+ all_parameters.weights[index] = weight;
+}
+
+void set_parameter_value(const char *name, double value, struct parameter_bundle *bundle)
+{
+ int index;
+
+ index = get_param_index(name);
+
+ if (index >= (int)bundle->parameters.size()) {
+ bundle->parameters.resize(index+1, 0.0);
+ bundle->weights.resize(index+1, 1.0);
+ }
+
+ bundle->parameters[index] = value;
+}
+
+double get_parameter_value(const char *name, struct parameter_bundle *the_bundle)
+{
+ unsigned int index;
+ index = get_param_index(name);
+ return get_parameter_value(index, the_bundle);
+}
+
+double get_parameter_value(unsigned int index, struct parameter_bundle *the_bundle)
+{
+ if (index >= the_bundle->parameters.size()) {
+ fprintf(stderr, "BUG: requesting unregistered parameter %d\n", index);
+ return 0;
+ }
+ return the_bundle->parameters[index];
+}
+
+double get_parameter_weight(int index, struct parameter_bundle *the_bundle)
+{
+ return the_bundle->weights[index];
+}
+
+double get_result_value(const char *name, struct result_bundle *the_bundle)
+{
+ return get_result_value(get_result_index(name), the_bundle);
+}
+
+void set_result_value(const char *name, double value, struct result_bundle *the_bundle)
+{
+ unsigned int index = get_result_index(name);
+ if (index >= the_bundle->utilization.size())
+ the_bundle->utilization.resize(index+1);
+ the_bundle->utilization[index] = value;
+}
+
+void set_result_value(unsigned int index, double value, struct result_bundle *the_bundle)
+{
+ if (index >= the_bundle->utilization.size())
+ the_bundle->utilization.resize(index+1);
+ the_bundle->utilization[index] = value;
+}
+
+double get_result_value(int index, struct result_bundle *the_bundle)
+{
+ if (!the_bundle)
+ return 0;
+ if (index >= (int) the_bundle->utilization.size())
+ return 0;
+ return the_bundle->utilization[index];
+}
+
+
+int result_device_exists(const char *name)
+{
+ unsigned int i;
+ for (i = 0; i < all_devices.size(); i++) {
+ if (strcmp(all_devices[i]->device_name(), name) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+void report_utilization(const char *name, double value, struct result_bundle *bundle)
+{
+ set_result_value(name, value, bundle);
+}
+void report_utilization(int index, double value, struct result_bundle *bundle)
+{
+ set_result_value(index, value, bundle);
+}
+
+
+
+double compute_bundle(struct parameter_bundle *parameters, struct result_bundle *results)
+{
+ double power = 0;
+ unsigned int i;
+
+ static int bpi = 0;
+
+ if (!bpi)
+ bpi = get_param_index("base power");
+
+ for (i = 0; i < all_devices.size(); i++)
+ power += all_devices[i]->power_usage(results, parameters);
+
+ parameters->actual_power = results->power;
+ parameters->guessed_power = power;
+ /* scale the squared error by the actual power so that non-idle data points weigh heavier */
+ parameters->score += results->power * (power - results->power) * (power - results->power);
+ parameters->parameters[bpi] = power;
+ return power;
+}
+
+static int precomputed_valid = 0;
+void precompute_valid(void)
+{
+ unsigned int i;
+
+
+ for (i = 0; i < all_devices.size(); i++) {
+ all_devices[i]->cached_valid = all_devices[i]->power_valid();
+ }
+ precomputed_valid = 1;
+}
+
+double bundle_power(struct parameter_bundle *parameters, struct result_bundle *results)
+{
+ double power = 0;
+ unsigned int i;
+ static int bpi = 0;
+
+ if (!bpi)
+ bpi = get_param_index("base power");
+
+ if (!precomputed_valid)
+ precompute_valid();
+
+
+ power = parameters->parameters[bpi];
+
+ for (i = 0; i < all_devices.size(); i++) {
+
+ if (all_devices[i]->cached_valid)
+ power += all_devices[i]->power_usage(results, parameters);
+ }
+
+ return power;
+}
+
+
+void dump_parameter_bundle(struct parameter_bundle *para)
+{
+ map<string, int>::iterator it;
+ int index;
+
+ printf("\n\n");
+ printf("Parameter state \n");
+ printf("----------------------------------\n");
+ printf("Value\t\tName\n");
+ for (it = param_index.begin(); it != param_index.end(); it++) {
+ index = it->second;
+ printf("%5.2f\t\t%s (%i)\n", para->parameters[index], it->first.c_str(), index);
+ }
+
+ printf("\n");
+ printf("Score: %5.1f (%5.1f)\n", sqrt(para->score / (0.001 + past_results.size()) / average_power()), para->score);
+ printf("Guess: %5.1f\n", para->guessed_power);
+ printf("Actual: %5.1f\n", para->actual_power);
+
+ printf("----------------------------------\n");
+}
+
+void dump_result_bundle(struct result_bundle *res)
+{
+ map<string, int>::iterator it;
+ unsigned int index;
+
+ printf("\n\n");
+ printf("Utilisation state \n");
+ printf("----------------------------------\n");
+ printf("Value\t\tName\n");
+ for (it = result_index.begin(); it != result_index.end(); it++) {
+ index = get_result_index(it->first.c_str());
+ printf("%5.2f%%\t\t%s(%i)\n", res->utilization[index], it->first.c_str(), index);
+ }
+
+ printf("\n");
+ printf("Power: %5.1f\n", res->power);
+
+ printf("----------------------------------\n");
+}
+
+struct result_bundle * clone_results(struct result_bundle *bundle)
+{
+ struct result_bundle *b2;
+ map<string, double>::iterator it;
+ unsigned int i;
+
+ b2 = new struct result_bundle;
+
+ if (!b2)
+ return NULL;
+
+ b2->power = bundle->power;
+ b2->utilization.resize(bundle->utilization.size());
+
+ for (i = 0; i < bundle->utilization.size(); i++) {
+ b2->utilization[i] = bundle->utilization[i];
+ }
+
+ return b2;
+}
+
+
+struct parameter_bundle * clone_parameters(struct parameter_bundle *bundle)
+{
+ struct parameter_bundle *b2;
+ unsigned int i;
+
+ b2 = new struct parameter_bundle;
+
+ if (!b2)
+ return NULL;
+
+ b2->score = 0;
+ b2->guessed_power = 0;
+ b2->actual_power = bundle->actual_power;
+ b2->parameters.resize(bundle->parameters.size());
+ for (i = 0; i < bundle->parameters.size(); i++) {
+ b2->parameters[i] = bundle->parameters[i];
+ }
+
+ return b2;
+}
+
+
+void store_results(double duration)
+{
+ if (duration < 5)
+ return;
+ global_power();
+ if (all_results.power > 0.01) {
+ unsigned int overflow_index;
+ overflow_index = 50 + (rand() % MAX_KEEP);
+ if (past_results.size() >= MAX_PARAM) {
+ /* memory leak, must free old one first */
+ past_results[overflow_index] = clone_results(&all_results);
+ } else {
+ past_results.push_back(clone_results(&all_results));
+ }
+ if ((past_results.size() % 10) == 0)
+ save_all_results("saved_results.powertop");
+ }
+
+}
+
+
+
+void dump_past_results(void)
+{
+ unsigned int j;
+ unsigned int i;
+ struct result_bundle *result;
+
+ for (j = 0; j < past_results.size(); j+=10) {
+ printf("Est ");
+ for (i = j; i < past_results.size() && i < j + 10; i++) {
+ result = past_results[i];
+ printf("%6.2f ", bundle_power(&all_parameters, result));
+ }
+ printf("\n");
+ printf("Actual ");
+ for (i = j; i < past_results.size() && i < j + 10; i++) {
+ result = past_results[i];
+ printf("%6.2f ", result->power);
+ }
+ printf("\n\n");
+ }
+}
+
+double average_power(void)
+{
+ double sum = 0.0;
+ unsigned int i;
+ for (i = 0; i < past_results.size(); i++)
+ sum += past_results[i]->power;
+
+ if (past_results.size())
+ sum = sum / past_results.size() + 0.0001;
+ else
+ sum = 0.0001;
+ return sum;
+}
+
+int utilization_power_valid(const char *u)
+{
+ unsigned int i;
+ unsigned int index;
+ double first_value;
+
+ index = get_result_index(u);
+ if (index <= 0)
+ return 0;
+
+ first_value = past_results[0]->utilization[index];
+ for (i = 1; i < past_results.size(); i++) {
+ if (get_result_value(index, past_results[i]) < first_value - 0.0001)
+ return 1;
+ if (get_result_value(index, past_results[i]) > first_value + 0.0001)
+ return 1;
+ }
+
+ return 0;
+}
+
+int utilization_power_valid(int index)
+{
+ unsigned int i;
+ double first_value;
+
+ if (index <= 0)
+ return 0;
+
+ if (past_results.size() == 0)
+ return 0;
+
+ if (index >= (int)past_results[0]->utilization.size())
+ return 0;
+ first_value = past_results[0]->utilization[index];
+ for (i = 1; i < past_results.size(); i++) {
+ if (get_result_value(index, past_results[i]) < first_value - 0.0001)
+ return 1;
+ if (get_result_value(index, past_results[i]) > first_value + 0.0001)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* force power data to be valid to the rest of the system */
+int global_power_override = 0;
+int global_run_times=0;
+/*
+ * only report power numbers once we have 3* more measurements than
+ * we have parameters; anything less and our model fit is highly suspect
+ */
+int global_power_valid(void)
+{
+ if (past_results.size() > 3 * all_parameters.parameters.size())
+ return 1;
+
+ if (past_results.size() > 0 && global_run_times < 1){
+ printf("To show power estimates do %ld measurement(s) connected to battery only\n",
+ (3 * all_parameters.parameters.size()) - past_results.size());
+ global_run_times += 1;
+ }
+
+ return global_power_override;
+}
+
+/* find the directory to store powertop results/parameters based on distribution*/
+char* get_param_directory(const char *filename)
+{
+ static char tempfilename[PATH_MAX];
+
+ if (access("/var/cache/powertop", W_OK ) == 0)
+ snprintf(tempfilename, sizeof(tempfilename), "/var/cache/powertop/%s", filename);
+ if (access("/data/local/powertop", W_OK ) == 0)
+ snprintf(tempfilename, sizeof(tempfilename), "/data/local/powertop/%s", filename);
+
+ return tempfilename;
+};
diff --git a/src/parameters/parameters.h b/src/parameters/parameters.h
new file mode 100644
index 0000000..1781a0e
--- /dev/null
+++ b/src/parameters/parameters.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef __INCLUDE_GUARD_PARAMETERS_H_
+#define __INCLUDE_GUARD_PARAMETERS_H_
+
+
+#include <map>
+#include <vector>
+#include <string>
+
+#include "string.h"
+#include "../devices/device.h"
+#include "../lib.h"
+
+using namespace std;
+
+#define MAX_KEEP 700
+#define MAX_PARAM 750
+
+
+struct parameter_bundle
+{
+ double score;
+ double guessed_power;
+ double actual_power;
+
+ vector<double> parameters;
+ vector<double> weights;
+};
+
+extern struct parameter_bundle all_parameters;
+extern map <string, int> param_index;
+extern map <string, int> result_index;
+
+extern int get_param_index(const char *param);
+extern int get_result_index(const char *param);
+
+
+extern void register_parameter(const char *name, double default_value = 0.00, double weight = 1.0);
+extern double get_parameter_value(const char *name, struct parameter_bundle *bundle = &all_parameters);
+extern double get_parameter_value(unsigned int index, struct parameter_bundle *bundle = &all_parameters);
+extern void set_parameter_value(const char *name, double value, struct parameter_bundle *bundle = &all_parameters);
+
+
+struct result_bundle
+{
+ double joules;
+ double power;
+ vector <double> utilization; /* device name, device utilization %age */
+};
+
+extern struct result_bundle all_results;
+extern vector <struct result_bundle *> past_results;
+
+extern double get_result_value(const char *name, struct result_bundle *bundle = &all_results);
+extern double get_result_value(int index, struct result_bundle *bundle = &all_results);
+
+extern void set_result_value(const char *name, double value, struct result_bundle *bundle = &all_results);
+
+
+extern int result_device_exists(const char *name);
+
+extern void report_utilization(const char *name, double value, struct result_bundle *bundle = &all_results);
+extern void report_utilization(int index, double value, struct result_bundle *bundle = &all_results);
+
+
+extern void precompute_valid(void);
+
+extern double compute_bundle(struct parameter_bundle *parameters = &all_parameters, struct result_bundle *results = &all_results);
+
+
+void dump_parameter_bundle(struct parameter_bundle *patameters = &all_parameters);
+void dump_result_bundle(struct result_bundle *res = &all_results);
+
+extern struct result_bundle * clone_results(struct result_bundle *bundle);
+extern struct parameter_bundle * clone_parameters(struct parameter_bundle *bundle);
+
+extern void store_results(double duration);
+extern void learn_parameters(int iterations, int do_base_power);
+extern char *get_param_directory(const char *filename);
+extern void save_all_results(const char *filename = "saved_results.powertop");
+extern void close_results(void);
+extern void load_results(const char *filename);
+extern void save_parameters(const char *filename);
+extern void load_parameters(const char *filename);
+
+extern void dump_past_results(void);
+extern double bundle_power(struct parameter_bundle *parameters, struct result_bundle *results);
+
+extern double average_power(void);
+
+extern int utilization_power_valid(const char *u);
+extern int utilization_power_valid(int index);
+extern double calculate_params(struct parameter_bundle *params = &all_parameters);
+int global_power_valid(void);
+
+
+extern int global_power_override;
+
+
+#endif
diff --git a/src/parameters/persistent.cpp b/src/parameters/persistent.cpp
new file mode 100644
index 0000000..0711b4d
--- /dev/null
+++ b/src/parameters/persistent.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+#include <stdlib.h>
+
+#include "parameters.h"
+#include "../measurement/measurement.h"
+
+using namespace std;
+
+void save_all_results(const char *filename)
+{
+ ofstream file;
+ unsigned int i;
+ struct result_bundle *bundle;
+ char* pathname;
+
+ pathname = get_param_directory(filename);
+
+ file.open(pathname, ios::out);
+ if (!file) {
+ cout << _("Cannot save to file") << " " << pathname << "\n";
+ return;
+ }
+ for (i = 0; i < past_results.size(); i++) {
+ bundle = past_results[i];
+ map<string, int>::iterator it;
+ file << setiosflags(ios::fixed) << setprecision(5) << bundle->power << "\n";
+
+ for (it = result_index.begin(); it != result_index.end(); it++) {
+ file << it->first << "\t" << setprecision(5) << get_result_value(it->second, bundle) << "\n";
+ }
+ file << ":\n";
+ }
+
+ file.close();
+
+}
+
+void close_results()
+{
+ for (unsigned int i = 0; i < past_results.size(); i++) {
+ delete past_results[i];
+ }
+
+ past_results.clear();
+ return;
+}
+
+void load_results(const char *filename)
+{
+ ifstream file;
+ char line[4096];
+ char *c1;
+ struct result_bundle *bundle;
+ int first = 1;
+ unsigned int count = 0;
+ char* pathname;
+ int bundle_saved = 0;
+
+ pathname = get_param_directory(filename);
+
+ file.open(pathname, ios::in);
+ if (!file) {
+ cout << _("Cannot load from file") << " " << pathname << "\n";
+ return;
+ }
+
+ bundle = new struct result_bundle;
+
+ while (file) {
+ double d;
+ if (first) {
+ file.getline(line, 4096);
+ if (strlen(line)>0) {
+ sscanf(line, "%lf", &bundle->power);
+ if (bundle->power < min_power)
+ min_power = bundle->power;
+ }
+ first = 0;
+ continue;
+ }
+ file.getline(line, 4096);
+ if (strlen(line) < 3) {
+ int overflow_index;
+
+ bundle_saved = 1;
+ overflow_index = 50 + (rand() % MAX_KEEP);
+ if (past_results.size() >= MAX_PARAM) {
+ /* memory leak, must free old one first */
+ past_results[overflow_index] = bundle;
+ } else {
+ past_results.push_back(bundle);
+ }
+ bundle = new struct result_bundle;
+ first = 1;
+ count++;
+ continue;
+ }
+ c1 = strchr(line, '\t');
+ if (!c1)
+ continue;
+ *c1 = 0;
+ c1++;
+ sscanf(c1, "%lf", &d);
+ set_result_value(line, d, bundle);
+ }
+
+ if (bundle_saved == 0)
+ delete bundle;
+
+ file.close();
+ // '%i" is for count, do not translate
+ fprintf(stderr, _("Loaded %i prior measurements\n"), count);
+}
+
+void save_parameters(const char *filename)
+{
+ ofstream file;
+ char* pathname;
+
+// printf("result size is %i, #parameters is %i \n", (int)past_results.size(), (int)all_parameters.parameters.size());
+
+ if (!global_power_valid())
+ return;
+
+ pathname = get_param_directory(filename);
+
+ file.open(pathname, ios::out);
+ if (!file) {
+ cout << _("Cannot save to file") << " " << pathname << "\n";
+ return;
+ }
+
+ map<string, int>::iterator it;
+
+ for (it = param_index.begin(); it != param_index.end(); it++) {
+ int index;
+ index = it->second;
+ file << it->first << "\t" << setprecision(9) << all_parameters.parameters[index] << "\n";
+ }
+ file.close();
+}
+
+void load_parameters(const char *filename)
+{
+ ifstream file;
+ char line[4096];
+ char *c1;
+ char* pathname;
+
+ pathname = get_param_directory(filename);
+
+ file.open(pathname, ios::in);
+ if (!file) {
+ cout << _("Cannot load from file") << " " << pathname << "\n";
+ cout << _("File will be loaded after taking minimum number of measurement(s) with battery only \n");
+ return;
+ }
+
+ while (file) {
+ double d;
+ memset(line, 0, 4096);
+ file.getline(line, 4095);
+
+ c1 = strchr(line, '\t');
+ if (!c1)
+ continue;
+ *c1 = 0;
+ c1++;
+ sscanf(c1, "%lf", &d);
+
+
+ set_parameter_value(line, d);
+ }
+
+ file.close();
+}
diff --git a/src/perf/perf.cpp b/src/perf/perf.cpp
new file mode 100644
index 0000000..9ed0ba8
--- /dev/null
+++ b/src/perf/perf.cpp
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include <iostream>
+#include <fstream>
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <fcntl.h>
+
+#include "perf_event.h"
+#include "perf.h"
+#include "../lib.h"
+#include "../display.h"
+
+struct pevent *perf_event::pevent;
+
+static int get_trace_type(const char *eventname)
+{
+ string str;
+ int this_trace;
+
+ str = read_sysfs_string("/sys/kernel/debug/tracing/events/%s/id",
+ eventname);
+ if (str.length() < 1)
+ return -1;
+
+ this_trace = strtoull(str.c_str(), NULL, 10);
+ return this_trace;
+}
+
+static inline int sys_perf_event_open(struct perf_event_attr *attr,
+ pid_t pid, int cpu, int group_fd,
+ unsigned long flags)
+{
+ attr->size = sizeof(*attr);
+ return syscall(__NR_perf_event_open, attr, pid, cpu,
+ group_fd, flags);
+}
+
+void perf_event::create_perf_event(char *eventname, int _cpu)
+{
+ struct perf_event_attr attr;
+ int ret;
+ int err;
+
+ struct {
+ __u64 count;
+ __u64 time_enabled;
+ __u64 time_running;
+ __u64 id;
+ } read_data;
+
+ if (perf_fd != -1)
+ clear();
+
+ memset(&attr, 0, sizeof(attr));
+
+ attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
+ PERF_FORMAT_TOTAL_TIME_RUNNING |
+ PERF_FORMAT_ID;
+
+ attr.sample_freq = 0;
+ attr.sample_period = 1;
+ attr.sample_type |= PERF_SAMPLE_RAW | PERF_SAMPLE_CPU | PERF_SAMPLE_TIME;
+
+ attr.mmap = 1;
+ attr.comm = 1;
+ attr.inherit = 0;
+ attr.disabled = 1;
+
+ attr.type = PERF_TYPE_TRACEPOINT;
+ attr.config = trace_type;
+
+ if (attr.config <= 0)
+ return;
+
+ perf_fd = sys_perf_event_open(&attr, -1, _cpu, -1, 0);
+
+ if (perf_fd < 0) {
+ err = errno;
+ reset_display();
+ if (err == EMFILE)
+ fprintf(stderr, _("Too many open files, please increase the limit of open file descriptors.\n"));
+ else {
+ fprintf(stderr, _("PowerTOP %s needs the kernel to support the 'perf' subsystem\n"), PACKAGE_VERSION);
+ fprintf(stderr, _("as well as support for trace points in the kernel:\n"));
+ fprintf(stderr, "CONFIG_PERF_EVENTS=y\nCONFIG_PERF_COUNTERS=y\nCONFIG_TRACEPOINTS=y\nCONFIG_TRACING=y\n");
+ }
+ exit(EXIT_FAILURE);
+ }
+ if (read(perf_fd, &read_data, sizeof(read_data)) == -1) {
+ reset_display();
+ perror("Unable to read perf file descriptor\n");
+ exit(-1);
+ }
+
+ fcntl(perf_fd, F_SETFL, O_NONBLOCK);
+
+ perf_mmap = mmap(NULL, (bufsize+1)*getpagesize(),
+ PROT_READ | PROT_WRITE, MAP_SHARED, perf_fd, 0);
+ if (perf_mmap == MAP_FAILED) {
+ fprintf(stderr, "failed to mmap with %d (%s)\n", errno, strerror(errno));
+ return;
+ }
+
+ ret = ioctl(perf_fd, PERF_EVENT_IOC_ENABLE, 0);
+
+ if (ret < 0) {
+ fprintf(stderr, "failed to enable perf \n");
+ }
+
+ pc = (perf_event_mmap_page *)perf_mmap;
+ data_mmap = (unsigned char *)perf_mmap + getpagesize();
+
+
+}
+
+void perf_event::set_event_name(const char *event_name)
+{
+ free(name);
+ name = strdup(event_name);
+ if (!name) {
+ fprintf(stderr, "failed to allocate event name\n");
+ return;
+ }
+
+ char *c;
+
+ c = strchr(name, ':');
+ if (c)
+ *c = '/';
+
+ trace_type = get_trace_type(name);
+}
+
+perf_event::~perf_event(void)
+{
+ free(name);
+
+ if (perf_event::pevent->ref_count == 1) {
+ pevent_free(perf_event::pevent);
+ perf_event::pevent = NULL;
+ clear();
+ } else
+ pevent_unref(perf_event::pevent);
+}
+
+void perf_event::set_cpu(int _cpu)
+{
+ cpu = _cpu;
+}
+
+static void allocate_pevent(void)
+{
+ if (!perf_event::pevent)
+ perf_event::pevent = pevent_alloc();
+ else
+ pevent_ref(perf_event::pevent);
+}
+
+perf_event::perf_event(const char *event_name, int _cpu, int buffer_size)
+{
+ allocate_pevent();
+ name = NULL;
+ perf_fd = -1;
+ bufsize = buffer_size;
+ cpu = _cpu;
+ perf_mmap = NULL;
+ trace_type = 0;
+ set_event_name(event_name);
+}
+
+perf_event::perf_event(void)
+{
+ allocate_pevent();
+ name = NULL;
+ perf_fd = -1;
+ bufsize = 128;
+ perf_mmap = NULL;
+ cpu = 0;
+ trace_type = 0;
+}
+
+void perf_event::start(void)
+{
+ create_perf_event(name, cpu);
+}
+
+void perf_event::stop(void)
+{
+ int ret;
+ ret = ioctl(perf_fd, PERF_EVENT_IOC_DISABLE, 0);
+ if (ret)
+ cout << "stop failing\n";
+}
+
+void perf_event::process(void *cookie)
+{
+ struct perf_event_header *header;
+
+ if (perf_fd < 0)
+ return;
+
+ while (pc->data_tail != pc->data_head ) {
+ while (pc->data_tail >= (unsigned int)bufsize * getpagesize())
+ pc->data_tail -= bufsize * getpagesize();
+
+ header = (struct perf_event_header *)( (unsigned char *)data_mmap + pc->data_tail);
+
+ if (header->size == 0)
+ break;
+
+ pc->data_tail += header->size;
+
+ while (pc->data_tail >= (unsigned int)bufsize * getpagesize())
+ pc->data_tail -= bufsize * getpagesize();
+
+ if (header->type == PERF_RECORD_SAMPLE)
+ handle_event(header, cookie);
+ }
+ pc->data_tail = pc->data_head;
+}
+
+void perf_event::clear(void)
+{
+ if (perf_mmap) {
+// memset(perf_mmap, 0, (bufsize)*getpagesize());
+ munmap(perf_mmap, (bufsize+1)*getpagesize());
+ perf_mmap = NULL;
+ }
+ if (perf_fd != -1)
+ close(perf_fd);
+ perf_fd = -1;
+}
diff --git a/src/perf/perf.h b/src/perf/perf.h
new file mode 100644
index 0000000..ee072ae
--- /dev/null
+++ b/src/perf/perf.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_PERF_H_
+#define _INCLUDE_GUARD_PERF_H_
+
+#include <iostream>
+
+
+extern "C" {
+ #include "../traceevent/event-parse.h"
+}
+
+
+using namespace std;
+
+class perf_event {
+protected:
+ int perf_fd;
+ void * perf_mmap;
+ void * data_mmap;
+ struct perf_event_mmap_page *pc;
+
+
+
+ int bufsize;
+ char *name;
+ int cpu;
+ void create_perf_event(char *eventname, int cpu);
+
+public:
+ unsigned int trace_type;
+
+ perf_event(void);
+ perf_event(const char *event_name, int cpu = 0, int buffer_size = 128);
+
+ virtual ~perf_event(void);
+
+
+ void set_event_name(const char *event_name);
+ void set_cpu(int cpu);
+
+ void start(void);
+ void stop(void);
+ void clear(void);
+
+ void process(void *cookie);
+
+ virtual void handle_event(struct perf_event_header *header, void *cookie) { };
+
+ static struct pevent *pevent;
+
+};
+
+#endif
diff --git a/src/perf/perf_bundle.cpp b/src/perf/perf_bundle.cpp
new file mode 100644
index 0000000..3d216ff
--- /dev/null
+++ b/src/perf/perf_bundle.cpp
@@ -0,0 +1,348 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <malloc.h>
+#include <algorithm>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include "perf_bundle.h"
+#include "perf_event.h"
+#include "perf.h"
+
+#include "../cpu/cpu.h"
+
+#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
+# define USE_DECLTYPE
+#endif
+
+class perf_bundle_event: public perf_event
+{
+public:
+ perf_bundle_event(void);
+ virtual void handle_event(struct perf_event_header *header, void *cookie);
+};
+
+perf_bundle_event::perf_bundle_event(void) : perf_event()
+{
+}
+
+
+void perf_bundle_event::handle_event(struct perf_event_header *header, void *cookie)
+{
+ unsigned char *buffer;
+ vector<void *> *vector;
+
+ buffer = (unsigned char *)malloc(header->size);
+ memcpy(buffer, header, header->size);
+
+#ifdef USE_DECLTYPE
+ vector = (decltype(vector))cookie;
+#else
+ vector = (typeof(vector))cookie;
+#endif
+ vector->push_back(buffer);
+}
+
+
+void perf_bundle::release(void)
+{
+ class perf_event *ev;
+ unsigned int i = 0;
+
+ for (i = 0; i < events.size(); i++) {
+ ev = events[i];
+ if (!ev)
+ continue;
+ ev->clear();
+ delete ev;
+ }
+ events.clear();
+
+ for (i = 0; i < event_names.size(); i++) {
+ free((void*)event_names[i]);
+ }
+ event_names.clear();
+
+ for(i = 0; i < records.size(); i++) {
+ free(records[i]);
+ }
+ records.clear();
+}
+
+static char * read_file(const char *file)
+{
+ char *buffer = NULL; /* quient gcc */
+ char buf[4096];
+ int len = 0;
+ int fd;
+ int r;
+
+ fd = open(file, O_RDONLY);
+ if (fd < 0)
+ exit(-1);
+
+ while((r = read(fd, buf, 4096)) > 0) {
+ if (len) {
+ char *tmp = (char *)realloc(buffer, len + r + 1);
+ if (!tmp)
+ free(buffer);
+ buffer = tmp;
+ } else
+ buffer = (char *)malloc(r + 1);
+ if (!buffer)
+ goto out;
+ memcpy(buffer + len, buf, r);
+ len += r;
+ buffer[len] = '\0';
+ }
+out:
+ close(fd);
+ return buffer;
+}
+
+static void parse_event_format(const char *event_name)
+{
+ char *tptr;
+ char *name = strdup(event_name);
+ char *sys = strtok_r(name, ":", &tptr);
+ char *event = strtok_r(NULL, ":", &tptr);
+ char *file;
+ char *buf;
+
+ file = (char *)malloc(strlen(sys) + strlen(event) +
+ strlen("/sys/kernel/debug/tracing/events////format") + 2);
+ sprintf(file, "/sys/kernel/debug/tracing/events/%s/%s/format", sys, event);
+
+ buf = read_file(file);
+ free(file);
+ if (!buf) {
+ free(name);
+ return;
+ }
+
+ pevent_parse_event(perf_event::pevent, buf, strlen(buf), sys);
+ free(name);
+ free(buf);
+}
+
+bool perf_bundle::add_event(const char *event_name)
+{
+ unsigned int i;
+ int event_added = false;
+ class perf_event *ev;
+
+
+ for (i = 0; i < all_cpus.size(); i++) {
+
+ if (!all_cpus[i])
+ continue;
+
+ ev = new class perf_bundle_event();
+
+ ev->set_event_name(event_name);
+ ev->set_cpu(i);
+
+ if ((int)ev->trace_type >= 0) {
+ if (event_names.find(ev->trace_type) == event_names.end()) {
+ event_names[ev->trace_type] = strdup(event_name);
+ parse_event_format(event_name);
+ }
+ events.push_back(ev);
+ event_added = true;
+ } else {
+ delete ev;
+ }
+ }
+ return event_added;
+}
+
+void perf_bundle::start(void)
+{
+ unsigned int i;
+ class perf_event *ev;
+
+ for (i = 0; i < events.size(); i++) {
+ ev = events[i];
+ if (!ev)
+ continue;
+ ev->start();
+ }
+}
+void perf_bundle::stop(void)
+{
+ unsigned int i;
+ class perf_event *ev;
+
+ for (i = 0; i < events.size(); i++) {
+ ev = events[i];
+ if (!ev)
+ continue;
+ ev->stop();
+ }
+}
+void perf_bundle::clear(void)
+{
+ unsigned int i;
+
+ class perf_event *ev;
+
+ for (i = 0; i < events.size(); i++) {
+ ev = events[i];
+ if (!ev)
+ continue;
+ ev->clear();
+ }
+
+ for (i = 0; i < records.size(); i++) {
+ free(records[i]);
+ }
+ records.resize(0);
+}
+
+
+struct trace_entry {
+ uint64_t time;
+ uint32_t cpu;
+ uint32_t res;
+ __u32 size;
+} __attribute__((packed));;
+
+
+struct perf_sample {
+ struct perf_event_header header;
+ struct trace_entry trace;
+ unsigned char data[0];
+} __attribute__((packed));
+
+static uint64_t timestamp(perf_event_header *event)
+{
+ struct perf_sample *sample;
+
+ if (event->type != PERF_RECORD_SAMPLE)
+ return 0;
+
+ sample = (struct perf_sample *)event;
+
+#if 0
+ int i;
+ unsigned char *x;
+
+ printf("header:\n");
+ printf(" type is %x \n", sample->header.type);
+ printf(" misc is %x \n", sample->header.misc);
+ printf(" size is %i \n", sample->header.size);
+ printf("sample:\n");
+ printf(" time is %llx \n", sample->trace.time);
+ printf(" cpu is %i / %x \n", sample->trace.cpu, sample->trace.cpu);
+ printf(" res is %i / %x \n", sample->trace.res, sample->trace.res);
+ printf(" size is %i / %x \n", sample->trace.size, sample->trace.size);
+ printf(" type is %i / %x \n", sample->trace.type, sample->trace.type);
+ printf(" flags is %i / %x \n", sample->trace.flags, sample->trace.flags);
+ printf(" p/c is %i / %x \n", sample->trace.preempt_count, sample->trace.preempt_count);
+ printf(" pid is %i / %x \n", sample->trace.pid, sample->trace.pid);
+ printf(" lock dept is %i / %x \n", sample->trace.lock_depth, sample->trace.lock_depth);
+
+ x = (unsigned char *)sample;
+ for (i = 0; i < sample->header.size; i++)
+ printf("%02x ", *(x+i));
+ printf("\n");
+#endif
+ return sample->trace.time;
+
+}
+
+static bool event_sort_function (void *i, void *j)
+{
+ struct perf_event_header *I, *J;
+
+ I = (struct perf_event_header *) i;
+ J = (struct perf_event_header *) j;
+ return (timestamp(I)<timestamp(J));
+}
+
+/*
+ * sample's PERF_SAMPLE_CPU cpu nr is a raw_smp_processor_id() by the
+ * time of perf_event_output(), which may differ from struct perf_event
+ * cpu, thus we need to fix sample->trace.cpu.
+ */
+static void fixup_sample_trace_cpu(struct perf_sample *sample)
+{
+ struct event_format *event;
+ struct pevent_record rec;
+ unsigned long long cpu_nr;
+ int type;
+ int ret;
+
+ rec.data = &sample->data;
+ type = pevent_data_type(perf_event::pevent, &rec);
+ event = pevent_find_event(perf_event::pevent, type);
+ if (!event)
+ return;
+ /** don't touch trace if event does not contain cpu_id field*/
+ ret = pevent_get_field_val(NULL, event, "cpu_id", &rec, &cpu_nr, 0);
+ if (ret < 0)
+ return;
+ sample->trace.cpu = cpu_nr;
+}
+
+void perf_bundle::process(void)
+{
+ unsigned int i;
+ class perf_event *ev;
+
+ /* fixme: reserve enough space in the array in one go */
+ for (i = 0; i < events.size(); i++) {
+ ev = events[i];
+ if (!ev)
+ continue;
+ ev->process(&records);
+ }
+ sort(records.begin(), records.end(), event_sort_function);
+
+ for (i = 0; i < records.size(); i++) {
+ struct perf_sample *sample;
+
+ sample = (struct perf_sample *)records[i];
+ if (!sample)
+ continue;
+
+ if (sample->header.type != PERF_RECORD_SAMPLE)
+ continue;
+
+ fixup_sample_trace_cpu(sample);
+ handle_trace_point(&sample->data, sample->trace.cpu, sample->trace.time);
+ }
+}
+
+void perf_bundle::handle_trace_point(void *trace, int cpu, uint64_t time)
+{
+ printf("UH OH... abstract handle_trace_point called\n");
+}
diff --git a/src/perf/perf_bundle.h b/src/perf/perf_bundle.h
new file mode 100644
index 0000000..ec50744
--- /dev/null
+++ b/src/perf/perf_bundle.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_PERF_BUNDLE_H_
+#define _INCLUDE_GUARD_PERF_BUNDLE_H_
+
+#include <iostream>
+#include <vector>
+#include <map>
+
+using namespace std;
+
+#include "perf.h"
+class perf_event;
+
+
+class perf_bundle {
+protected:
+ vector<class perf_event *> events;
+ std::map<int, char*> event_names;
+public:
+ vector<void *> records;
+ virtual ~perf_bundle() {};
+
+ virtual void release(void);
+ bool add_event(const char *event_name);
+
+ void start(void);
+ void stop(void);
+ void clear(void);
+
+ void process(void);
+
+ virtual void handle_trace_point(void *trace, int cpu = 0, uint64_t time = 0);
+};
+
+
+#endif
diff --git a/src/perf/perf_event.h b/src/perf/perf_event.h
new file mode 100644
index 0000000..92a38b8
--- /dev/null
+++ b/src/perf/perf_event.h
@@ -0,0 +1,910 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+/*
+ * Performance events:
+ *
+ * Copyright (C) 2008-2009, Thomas Gleixner <tglx@linutronix.de>
+ * Copyright (C) 2008-2009, Red Hat, Inc., Ingo Molnar
+ * Copyright (C) 2008-2009, Red Hat, Inc., Peter Zijlstra
+ *
+ * Data type definitions, declarations, prototypes.
+ *
+ * Started by: Thomas Gleixner and Ingo Molnar
+ *
+ * For licencing details see kernel-base/COPYING
+ */
+#ifndef _LINUX_PERF_EVENT_H
+#define _LINUX_PERF_EVENT_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/byteorder.h>
+#include <sys/syscall.h>
+
+
+/*
+ * User-space ABI bits:
+ */
+
+/*
+ * attr.type
+ */
+enum perf_type_id {
+ PERF_TYPE_HARDWARE = 0,
+ PERF_TYPE_SOFTWARE = 1,
+ PERF_TYPE_TRACEPOINT = 2,
+ PERF_TYPE_HW_CACHE = 3,
+ PERF_TYPE_RAW = 4,
+
+ PERF_TYPE_MAX, /* non-ABI */
+};
+
+/*
+ * Generalized performance event event_id types, used by the
+ * attr.event_id parameter of the sys_perf_event_open()
+ * syscall:
+ */
+enum perf_hw_id {
+ /*
+ * Common hardware events, generalized by the kernel:
+ */
+ PERF_COUNT_HW_CPU_CYCLES = 0,
+ PERF_COUNT_HW_INSTRUCTIONS = 1,
+ PERF_COUNT_HW_CACHE_REFERENCES = 2,
+ PERF_COUNT_HW_CACHE_MISSES = 3,
+ PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
+ PERF_COUNT_HW_BRANCH_MISSES = 5,
+ PERF_COUNT_HW_BUS_CYCLES = 6,
+
+ PERF_COUNT_HW_MAX, /* non-ABI */
+};
+
+/*
+ * Generalized hardware cache events:
+ *
+ * { L1-D, L1-I, LLC, ITLB, DTLB, BPU } x
+ * { read, write, prefetch } x
+ * { accesses, misses }
+ */
+enum perf_hw_cache_id {
+ PERF_COUNT_HW_CACHE_L1D = 0,
+ PERF_COUNT_HW_CACHE_L1I = 1,
+ PERF_COUNT_HW_CACHE_LL = 2,
+ PERF_COUNT_HW_CACHE_DTLB = 3,
+ PERF_COUNT_HW_CACHE_ITLB = 4,
+ PERF_COUNT_HW_CACHE_BPU = 5,
+
+ PERF_COUNT_HW_CACHE_MAX, /* non-ABI */
+};
+
+enum perf_hw_cache_op_id {
+ PERF_COUNT_HW_CACHE_OP_READ = 0,
+ PERF_COUNT_HW_CACHE_OP_WRITE = 1,
+ PERF_COUNT_HW_CACHE_OP_PREFETCH = 2,
+
+ PERF_COUNT_HW_CACHE_OP_MAX, /* non-ABI */
+};
+
+enum perf_hw_cache_op_result_id {
+ PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0,
+ PERF_COUNT_HW_CACHE_RESULT_MISS = 1,
+
+ PERF_COUNT_HW_CACHE_RESULT_MAX, /* non-ABI */
+};
+
+/*
+ * Special "software" events provided by the kernel, even if the hardware
+ * does not support performance events. These events measure various
+ * physical and sw events of the kernel (and allow the profiling of them as
+ * well):
+ */
+enum perf_sw_ids {
+ PERF_COUNT_SW_CPU_CLOCK = 0,
+ PERF_COUNT_SW_TASK_CLOCK = 1,
+ PERF_COUNT_SW_PAGE_FAULTS = 2,
+ PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
+ PERF_COUNT_SW_CPU_MIGRATIONS = 4,
+ PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
+ PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
+
+ PERF_COUNT_SW_MAX, /* non-ABI */
+};
+
+/*
+ * Bits that can be set in attr.sample_type to request information
+ * in the overflow packets.
+ */
+enum perf_event_sample_format {
+ PERF_SAMPLE_IP = 1U << 0,
+ PERF_SAMPLE_TID = 1U << 1,
+ PERF_SAMPLE_TIME = 1U << 2,
+ PERF_SAMPLE_ADDR = 1U << 3,
+ PERF_SAMPLE_READ = 1U << 4,
+ PERF_SAMPLE_CALLCHAIN = 1U << 5,
+ PERF_SAMPLE_ID = 1U << 6,
+ PERF_SAMPLE_CPU = 1U << 7,
+ PERF_SAMPLE_PERIOD = 1U << 8,
+ PERF_SAMPLE_STREAM_ID = 1U << 9,
+ PERF_SAMPLE_RAW = 1U << 10,
+
+ PERF_SAMPLE_MAX = 1U << 11, /* non-ABI */
+};
+
+/*
+ * The format of the data returned by read() on a perf event fd,
+ * as specified by attr.read_format:
+ *
+ * struct read_format {
+ * { u64 value;
+ * { u64 time_enabled; } && PERF_FORMAT_ENABLED
+ * { u64 time_running; } && PERF_FORMAT_RUNNING
+ * { u64 id; } && PERF_FORMAT_ID
+ * } && !PERF_FORMAT_GROUP
+ *
+ * { u64 nr;
+ * { u64 time_enabled; } && PERF_FORMAT_ENABLED
+ * { u64 time_running; } && PERF_FORMAT_RUNNING
+ * { u64 value;
+ * { u64 id; } && PERF_FORMAT_ID
+ * } cntr[nr];
+ * } && PERF_FORMAT_GROUP
+ * };
+ */
+enum perf_event_read_format {
+ PERF_FORMAT_TOTAL_TIME_ENABLED = 1U << 0,
+ PERF_FORMAT_TOTAL_TIME_RUNNING = 1U << 1,
+ PERF_FORMAT_ID = 1U << 2,
+ PERF_FORMAT_GROUP = 1U << 3,
+
+ PERF_FORMAT_MAX = 1U << 4, /* non-ABI */
+};
+
+#define PERF_ATTR_SIZE_VER0 64 /* sizeof first published struct */
+
+/*
+ * Hardware event_id to monitor via a performance monitoring event:
+ */
+struct perf_event_attr {
+
+ /*
+ * Major type: hardware/software/tracepoint/etc.
+ */
+ __u32 type;
+
+ /*
+ * Size of the attr structure, for fwd/bwd compat.
+ */
+ __u32 size;
+
+ /*
+ * Type specific configuration information.
+ */
+ __u64 config;
+
+ union {
+ __u64 sample_period;
+ __u64 sample_freq;
+ };
+
+ __u64 sample_type;
+ __u64 read_format;
+
+ __u64 disabled : 1, /* off by default */
+ inherit : 1, /* children inherit it */
+ pinned : 1, /* must always be on PMU */
+ exclusive : 1, /* only group on PMU */
+ exclude_user : 1, /* don't count user */
+ exclude_kernel : 1, /* ditto kernel */
+ exclude_hv : 1, /* ditto hypervisor */
+ exclude_idle : 1, /* don't count when idle */
+ mmap : 1, /* include mmap data */
+ comm : 1, /* include comm data */
+ freq : 1, /* use freq, not period */
+ inherit_stat : 1, /* per task counts */
+ enable_on_exec : 1, /* next exec enables */
+ task : 1, /* trace fork/exit */
+ watermark : 1, /* wakeup_watermark */
+
+ __reserved_1 : 49;
+
+ union {
+ __u32 wakeup_events; /* wakeup every n events */
+ __u32 wakeup_watermark; /* bytes before wakeup */
+ };
+ __u32 __reserved_2;
+
+ __u64 __reserved_3;
+};
+
+/*
+ * Ioctls that can be done on a perf event fd:
+ */
+#define PERF_EVENT_IOC_ENABLE _IO ('$', 0)
+#define PERF_EVENT_IOC_DISABLE _IO ('$', 1)
+#define PERF_EVENT_IOC_REFRESH _IO ('$', 2)
+#define PERF_EVENT_IOC_RESET _IO ('$', 3)
+#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, u64)
+#define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5)
+
+enum perf_event_ioc_flags {
+ PERF_IOC_FLAG_GROUP = 1U << 0,
+};
+
+/*
+ * Structure of the page that can be mapped via mmap
+ */
+struct perf_event_mmap_page {
+ __u32 version; /* version number of this structure */
+ __u32 compat_version; /* lowest version this is compat with */
+
+ /*
+ * Bits needed to read the hw events in user-space.
+ *
+ * u32 seq;
+ * s64 count;
+ *
+ * do {
+ * seq = pc->lock;
+ *
+ * barrier()
+ * if (pc->index) {
+ * count = pmc_read(pc->index - 1);
+ * count += pc->offset;
+ * } else
+ * goto regular_read;
+ *
+ * barrier();
+ * } while (pc->lock != seq);
+ *
+ * NOTE: for obvious reason this only works on self-monitoring
+ * processes.
+ */
+ __u32 lock; /* seqlock for synchronization */
+ __u32 index; /* hardware event identifier */
+ __s64 offset; /* add to hardware event value */
+ __u64 time_enabled; /* time event active */
+ __u64 time_running; /* time event on cpu */
+
+ /*
+ * Hole for extension of the self monitor capabilities
+ */
+
+ __u64 __reserved[123]; /* align to 1k */
+
+ /*
+ * Control data for the mmap() data buffer.
+ *
+ * User-space reading the @data_head value should issue an rmb(), on
+ * SMP capable platforms, after reading this value -- see
+ * perf_event_wakeup().
+ *
+ * When the mapping is PROT_WRITE the @data_tail value should be
+ * written by userspace to reflect the last read data. In this case
+ * the kernel will not over-write unread data.
+ */
+ __u64 data_head; /* head in the data section */
+ __u64 data_tail; /* user-space written tail */
+};
+
+#define PERF_RECORD_MISC_CPUMODE_MASK (3 << 0)
+#define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0)
+#define PERF_RECORD_MISC_KERNEL (1 << 0)
+#define PERF_RECORD_MISC_USER (2 << 0)
+#define PERF_RECORD_MISC_HYPERVISOR (3 << 0)
+
+struct perf_event_header {
+ __u32 type;
+ __u16 misc;
+ __u16 size;
+};
+
+enum perf_event_type {
+
+ /*
+ * The MMAP events record the PROT_EXEC mappings so that we can
+ * correlate userspace IPs to code. They have the following structure:
+ *
+ * struct {
+ * struct perf_event_header header;
+ *
+ * u32 pid, tid;
+ * u64 addr;
+ * u64 len;
+ * u64 pgoff;
+ * char filename[];
+ * };
+ */
+ PERF_RECORD_MMAP = 1,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u64 id;
+ * u64 lost;
+ * };
+ */
+ PERF_RECORD_LOST = 2,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ *
+ * u32 pid, tid;
+ * char comm[];
+ * };
+ */
+ PERF_RECORD_COMM = 3,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u32 pid, ppid;
+ * u32 tid, ptid;
+ * u64 time;
+ * };
+ */
+ PERF_RECORD_EXIT = 4,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u64 time;
+ * u64 id;
+ * u64 stream_id;
+ * };
+ */
+ PERF_RECORD_THROTTLE = 5,
+ PERF_RECORD_UNTHROTTLE = 6,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u32 pid, ppid;
+ * u32 tid, ptid;
+ * u64 time;
+ * };
+ */
+ PERF_RECORD_FORK = 7,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ * u32 pid, tid;
+ *
+ * struct read_format values;
+ * };
+ */
+ PERF_RECORD_READ = 8,
+
+ /*
+ * struct {
+ * struct perf_event_header header;
+ *
+ * { u64 ip; } && PERF_SAMPLE_IP
+ * { u32 pid, tid; } && PERF_SAMPLE_TID
+ * { u64 time; } && PERF_SAMPLE_TIME
+ * { u64 addr; } && PERF_SAMPLE_ADDR
+ * { u64 id; } && PERF_SAMPLE_ID
+ * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
+ * { u32 cpu, res; } && PERF_SAMPLE_CPU
+ * { u64 period; } && PERF_SAMPLE_PERIOD
+ *
+ * { struct read_format values; } && PERF_SAMPLE_READ
+ *
+ * { u64 nr,
+ * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN
+ *
+ * #
+ * # The RAW record below is opaque data wrt the ABI
+ * #
+ * # That is, the ABI doesn't make any promises wrt to
+ * # the stability of its content, it may vary depending
+ * # on event, hardware, kernel version and phase of
+ * # the moon.
+ * #
+ * # In other words, PERF_SAMPLE_RAW contents are not an ABI.
+ * #
+ *
+ * { u32 size;
+ * char data[size];}&& PERF_SAMPLE_RAW
+ * };
+ */
+ PERF_RECORD_SAMPLE = 9,
+
+ PERF_RECORD_MAX, /* non-ABI */
+};
+
+enum perf_callchain_context {
+ PERF_CONTEXT_HV = (__u64)-32,
+ PERF_CONTEXT_KERNEL = (__u64)-128,
+ PERF_CONTEXT_USER = (__u64)-512,
+
+ PERF_CONTEXT_GUEST = (__u64)-2048,
+ PERF_CONTEXT_GUEST_KERNEL = (__u64)-2176,
+ PERF_CONTEXT_GUEST_USER = (__u64)-2560,
+
+ PERF_CONTEXT_MAX = (__u64)-4095,
+};
+
+#define PERF_FLAG_FD_NO_GROUP (1U << 0)
+#define PERF_FLAG_FD_OUTPUT (1U << 1)
+
+#ifdef __KERNEL__
+/*
+ * Kernel-internal data types and definitions:
+ */
+
+#ifdef CONFIG_PERF_EVENTS
+# include <asm/perf_event.h>
+#endif
+
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/rculist.h>
+#include <linux/rcupdate.h>
+#include <linux/spinlock.h>
+#include <linux/hrtimer.h>
+#include <linux/fs.h>
+#include <linux/pid_namespace.h>
+#include <linux/workqueue.h>
+#include <asm/atomic.h>
+
+#define PERF_MAX_STACK_DEPTH 255
+
+struct perf_callchain_entry {
+ __u64 nr;
+ __u64 ip[PERF_MAX_STACK_DEPTH];
+};
+
+struct perf_raw_record {
+ u32 size;
+ void *data;
+};
+
+struct task_struct;
+
+/**
+ * struct hw_perf_event - performance event hardware details:
+ */
+struct hw_perf_event {
+#ifdef CONFIG_PERF_EVENTS
+ union {
+ struct { /* hardware */
+ u64 config;
+ unsigned long config_base;
+ unsigned long event_base;
+ int idx;
+ };
+ struct { /* software */
+ s64 remaining;
+ struct hrtimer hrtimer;
+ };
+ };
+ atomic64_t prev_count;
+ u64 sample_period;
+ u64 last_period;
+ atomic64_t period_left;
+ u64 interrupts;
+
+ u64 freq_count;
+ u64 freq_interrupts;
+ u64 freq_stamp;
+#endif
+};
+
+struct perf_event;
+
+/**
+ * struct pmu - generic performance monitoring unit
+ */
+struct pmu {
+ int (*enable) (struct perf_event *event);
+ void (*disable) (struct perf_event *event);
+ void (*read) (struct perf_event *event);
+ void (*unthrottle) (struct perf_event *event);
+};
+
+/**
+ * enum perf_event_active_state - the states of a event
+ */
+enum perf_event_active_state {
+ PERF_EVENT_STATE_ERROR = -2,
+ PERF_EVENT_STATE_OFF = -1,
+ PERF_EVENT_STATE_INACTIVE = 0,
+ PERF_EVENT_STATE_ACTIVE = 1,
+};
+
+struct file;
+
+struct perf_mmap_data {
+ struct rcu_head rcu_head;
+#ifdef CONFIG_PERF_USE_VMALLOC
+ struct work_struct work;
+#endif
+ int data_order;
+ int nr_pages; /* nr of data pages */
+ int writable; /* are we writable */
+ int nr_locked; /* nr pages mlocked */
+
+ atomic_t poll; /* POLL_ for wakeups */
+ atomic_t events; /* event_id limit */
+
+ atomic_long_t head; /* write position */
+ atomic_long_t done_head; /* completed head */
+
+ atomic_t lock; /* concurrent writes */
+ atomic_t wakeup; /* needs a wakeup */
+ atomic_t lost; /* nr records lost */
+
+ long watermark; /* wakeup watermark */
+
+ struct perf_event_mmap_page *user_page;
+ void *data_pages[0];
+};
+
+struct perf_pending_entry {
+ struct perf_pending_entry *next;
+ void (*func)(struct perf_pending_entry *);
+};
+
+/**
+ * struct perf_event - performance event kernel representation:
+ */
+struct perf_event {
+#ifdef CONFIG_PERF_EVENTS
+ struct list_head group_entry;
+ struct list_head event_entry;
+ struct list_head sibling_list;
+ int nr_siblings;
+ struct perf_event *group_leader;
+ struct perf_event *output;
+ const struct pmu *pmu;
+
+ enum perf_event_active_state state;
+ atomic64_t count;
+
+ /*
+ * These are the total time in nanoseconds that the event
+ * has been enabled (i.e. eligible to run, and the task has
+ * been scheduled in, if this is a per-task event)
+ * and running (scheduled onto the CPU), respectively.
+ *
+ * They are computed from tstamp_enabled, tstamp_running and
+ * tstamp_stopped when the event is in INACTIVE or ACTIVE state.
+ */
+ u64 total_time_enabled;
+ u64 total_time_running;
+
+ /*
+ * These are timestamps used for computing total_time_enabled
+ * and total_time_running when the event is in INACTIVE or
+ * ACTIVE state, measured in nanoseconds from an arbitrary point
+ * in time.
+ * tstamp_enabled: the notional time when the event was enabled
+ * tstamp_running: the notional time when the event was scheduled on
+ * tstamp_stopped: in INACTIVE state, the notional time when the
+ * event was scheduled off.
+ */
+ u64 tstamp_enabled;
+ u64 tstamp_running;
+ u64 tstamp_stopped;
+
+ struct perf_event_attr attr;
+ struct hw_perf_event hw;
+
+ struct perf_event_context *ctx;
+ struct file *filp;
+
+ /*
+ * These accumulate total time (in nanoseconds) that children
+ * events have been enabled and running, respectively.
+ */
+ atomic64_t child_total_time_enabled;
+ atomic64_t child_total_time_running;
+
+ /*
+ * Protect attach/detach and child_list:
+ */
+ struct mutex child_mutex;
+ struct list_head child_list;
+ struct perf_event *parent;
+
+ int oncpu;
+ int cpu;
+
+ struct list_head owner_entry;
+ struct task_struct *owner;
+
+ /* mmap bits */
+ struct mutex mmap_mutex;
+ atomic_t mmap_count;
+ struct perf_mmap_data *data;
+
+ /* poll related */
+ wait_queue_head_t waitq;
+ struct fasync_struct *fasync;
+
+ /* delayed work for NMIs and such */
+ int pending_wakeup;
+ int pending_kill;
+ int pending_disable;
+ struct perf_pending_entry pending;
+
+ atomic_t event_limit;
+
+ void (*destroy)(struct perf_event *);
+ struct rcu_head rcu_head;
+
+ struct pid_namespace *ns;
+ u64 id;
+#endif
+};
+
+/**
+ * struct perf_event_context - event context structure
+ *
+ * Used as a container for task events and CPU events as well:
+ */
+struct perf_event_context {
+ /*
+ * Protect the states of the events in the list,
+ * nr_active, and the list:
+ */
+ spinlock_t lock;
+ /*
+ * Protect the list of events. Locking either mutex or lock
+ * is sufficient to ensure the list doesn't change; to change
+ * the list you need to lock both the mutex and the spinlock.
+ */
+ struct mutex mutex;
+
+ struct list_head group_list;
+ struct list_head event_list;
+ int nr_events;
+ int nr_active;
+ int is_active;
+ int nr_stat;
+ atomic_t refcount;
+ struct task_struct *task;
+
+ /*
+ * Context clock, runs when context enabled.
+ */
+ u64 time;
+ u64 timestamp;
+
+ /*
+ * These fields let us detect when two contexts have both
+ * been cloned (inherited) from a common ancestor.
+ */
+ struct perf_event_context *parent_ctx;
+ u64 parent_gen;
+ u64 generation;
+ int pin_count;
+ struct rcu_head rcu_head;
+};
+
+/**
+ * struct perf_event_cpu_context - per cpu event context structure
+ */
+struct perf_cpu_context {
+ struct perf_event_context ctx;
+ struct perf_event_context *task_ctx;
+ int active_oncpu;
+ int max_pertask;
+ int exclusive;
+
+ /*
+ * Recursion avoidance:
+ *
+ * task, softirq, irq, nmi context
+ */
+ int recursion[4];
+};
+
+struct perf_output_handle {
+ struct perf_event *event;
+ struct perf_mmap_data *data;
+ unsigned long head;
+ unsigned long offset;
+ int nmi;
+ int sample;
+ int locked;
+ unsigned long flags;
+};
+
+#ifdef CONFIG_PERF_EVENTS
+
+/*
+ * Set by architecture code:
+ */
+extern int perf_max_events;
+
+extern const struct pmu *hw_perf_event_init(struct perf_event *event);
+
+extern void perf_event_task_sched_in(struct task_struct *task, int cpu);
+extern void perf_event_task_sched_out(struct task_struct *task,
+ struct task_struct *next, int cpu);
+extern void perf_event_task_tick(struct task_struct *task, int cpu);
+extern int perf_event_init_task(struct task_struct *child);
+extern void perf_event_exit_task(struct task_struct *child);
+extern void perf_event_free_task(struct task_struct *task);
+extern void set_perf_event_pending(void);
+extern void perf_event_do_pending(void);
+extern void perf_event_print_debug(void);
+extern void __perf_disable(void);
+extern bool __perf_enable(void);
+extern void perf_disable(void);
+extern void perf_enable(void);
+extern int perf_event_task_disable(void);
+extern int perf_event_task_enable(void);
+extern int hw_perf_group_sched_in(struct perf_event *group_leader,
+ struct perf_cpu_context *cpuctx,
+ struct perf_event_context *ctx, int cpu);
+extern void perf_event_update_userpage(struct perf_event *event);
+
+struct perf_sample_data {
+ u64 type;
+
+ u64 ip;
+ struct {
+ u32 pid;
+ u32 tid;
+ } tid_entry;
+ u64 time;
+ u64 addr;
+ u64 id;
+ u64 stream_id;
+ struct {
+ u32 cpu;
+ u32 reserved;
+ } cpu_entry;
+ u64 period;
+ struct perf_callchain_entry *callchain;
+ struct perf_raw_record *raw;
+};
+
+extern void perf_output_sample(struct perf_output_handle *handle,
+ struct perf_event_header *header,
+ struct perf_sample_data *data,
+ struct perf_event *event);
+extern void perf_prepare_sample(struct perf_event_header *header,
+ struct perf_sample_data *data,
+ struct perf_event *event,
+ struct pt_regs *regs);
+
+extern int perf_event_overflow(struct perf_event *event, int nmi,
+ struct perf_sample_data *data,
+ struct pt_regs *regs);
+
+/*
+ * Return 1 for a software event, 0 for a hardware event
+ */
+static inline int is_software_event(struct perf_event *event)
+{
+ return (event->attr.type != PERF_TYPE_RAW) &&
+ (event->attr.type != PERF_TYPE_HARDWARE) &&
+ (event->attr.type != PERF_TYPE_HW_CACHE);
+}
+
+extern atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX];
+
+extern void __perf_sw_event(u32, u64, int, struct pt_regs *, u64);
+
+static inline void
+perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr)
+{
+ if (atomic_read(&perf_swevent_enabled[event_id]))
+ __perf_sw_event(event_id, nr, nmi, regs, addr);
+}
+
+extern void __perf_event_mmap(struct vm_area_struct *vma);
+
+static inline void perf_event_mmap(struct vm_area_struct *vma)
+{
+ if (vma->vm_flags & VM_EXEC)
+ __perf_event_mmap(vma);
+}
+
+extern void perf_event_comm(struct task_struct *tsk);
+extern void perf_event_fork(struct task_struct *tsk);
+
+extern struct perf_callchain_entry *perf_callchain(struct pt_regs *regs);
+
+extern int sysctl_perf_event_paranoid;
+extern int sysctl_perf_event_mlock;
+extern int sysctl_perf_event_sample_rate;
+
+extern void perf_event_init(void);
+extern void perf_tp_event(int event_id, u64 addr, u64 count,
+ void *record, int entry_size);
+
+#ifndef perf_misc_flags
+#define perf_misc_flags(regs) (user_mode(regs) ? PERF_RECORD_MISC_USER : \
+ PERF_RECORD_MISC_KERNEL)
+#define perf_instruction_pointer(regs) instruction_pointer(regs)
+#endif
+
+extern int perf_output_begin(struct perf_output_handle *handle,
+ struct perf_event *event, unsigned int size,
+ int nmi, int sample);
+extern void perf_output_end(struct perf_output_handle *handle);
+extern void perf_output_copy(struct perf_output_handle *handle,
+ const void *buf, unsigned int len);
+#else
+static inline void
+perf_event_task_sched_in(struct task_struct *task, int cpu) { }
+static inline void
+perf_event_task_sched_out(struct task_struct *task,
+ struct task_struct *next, int cpu) { }
+static inline void
+perf_event_task_tick(struct task_struct *task, int cpu) { }
+static inline int perf_event_init_task(struct task_struct *child) { return 0; }
+static inline void perf_event_exit_task(struct task_struct *child) { }
+static inline void perf_event_free_task(struct task_struct *task) { }
+static inline void perf_event_do_pending(void) { }
+static inline void perf_event_print_debug(void) { }
+static inline void perf_disable(void) { }
+static inline void perf_enable(void) { }
+static inline int perf_event_task_disable(void) { return -EINVAL; }
+static inline int perf_event_task_enable(void) { return -EINVAL; }
+
+static inline void
+perf_sw_event(u32 event_id, u64 nr, int nmi,
+ struct pt_regs *regs, u64 addr) { }
+
+static inline void perf_event_mmap(struct vm_area_struct *vma) { }
+static inline void perf_event_comm(struct task_struct *tsk) { }
+static inline void perf_event_fork(struct task_struct *tsk) { }
+static inline void perf_event_init(void) { }
+
+#endif
+
+#define perf_output_put(handle, x) \
+ perf_output_copy((handle), &(x), sizeof(x))
+
+#endif /* __KERNEL__ */
+
+
+#if 0
+/*
+ * trace_flag_type is an enumeration that holds different
+ * states when a trace occurs. These are:
+ * IRQS_OFF - interrupts were disabled
+ * IRQS_NOSUPPORT - arch does not support irqs_disabled_flags
+ * NEED_RESCED - reschedule is requested
+ * HARDIRQ - inside an interrupt handler
+ * SOFTIRQ - inside a softirq handler
+ */
+enum trace_flag_type {
+ TRACE_FLAG_IRQS_OFF = 0x01,
+ TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
+ TRACE_FLAG_NEED_RESCHED = 0x04,
+ TRACE_FLAG_HARDIRQ = 0x08,
+ TRACE_FLAG_SOFTIRQ = 0x10,
+};
+#endif
+
+#endif /* _LINUX_PERF_EVENT_H */
diff --git a/src/powertop.css b/src/powertop.css
new file mode 100644
index 0000000..daa20c5
--- /dev/null
+++ b/src/powertop.css
@@ -0,0 +1,263 @@
+<!DOCTYPE html>
+<html lang='en'>
+<head>
+<title>PowerTOP report</title>
+<meta http-equiv='content-type' content='text/html;charset=utf-8'>
+
+<script type='text/javascript'>
+
+var powertop = {
+ blocks: {
+ summary: 'Summary',
+ cpuidle: 'CPU Idle',
+ cpufreq: 'CPU Frequency',
+ software: 'Software Info',
+ devinfo: 'Device Info',
+ tuning: 'Tuning',
+ ahci: 'AHCI'
+ },
+ cadd: function(idx, c){
+ var el = document.getElementById(idx);
+ if (el) {
+ var cn = el.className;
+ if (cn.indexOf(c) != -1)
+ return;
+ cn += ' ' + c;
+ el.className = cn;
+ }
+ },
+ crm: function(id, c){
+ var el = document.getElementById(id);
+ if (el) {
+ var cn = el.className
+ while (cn.indexOf(' ' + c) != -1)
+ cn = cn.replace(' ' + c,'');
+ el.className = cn;
+ }
+ },
+ newbutton: function(id, txt) {
+ var x = document.createElement('div');
+ x.id = id + '_button';
+ x.className = 'nav_button';
+ x.textContent = txt;
+ x.innerText = txt;
+ x.onclick = function() { powertop.toggle(id); };
+ return x;
+ },
+ setupbuttons: function() {
+ var t = document.getElementById('main_menu');
+ if (t) {
+ for (var b in powertop.blocks) {
+ t.appendChild(powertop.newbutton(b, powertop.blocks[b]));
+ }
+ t.appendChild(powertop.newbutton('all', 'All'));
+ }
+ },
+ toggle: function(b) {
+ powertop.baseall();
+ if (b == 'all') {
+ for (var c in powertop.blocks) {
+ powertop.crm(c, 'hide');
+ }
+ } else {
+ powertop.crm(b, 'hide');
+ }
+ powertop.cadd(b + '_button', 'pressed');
+ },
+ baseall: function() {
+ for (var b in powertop.blocks) {
+ powertop.cadd(b, 'hide');
+ powertop.crm(b + '_button', 'pressed');
+ }
+ powertop.cadd('all', 'hide');
+ powertop.crm('all_button', 'pressed');
+ },
+ onload: function() {
+ powertop.setupbuttons();
+ powertop.toggle('summary');
+ }
+}
+</script>
+
+<style type='text/css'>
+/* General CSS */
+*{
+ margin:0px;
+ padding:0px;
+ width: auto;
+}
+
+body {
+ background-color: #eee; /* Background color */
+ color: #222; /* Font color */
+ font-family: Helvetica;
+ font-size: 14px;
+}
+
+#main_container{
+ margin: 2px auto;
+}
+
+/* Top logo & system table css */
+#main_header{
+ min-width: 960px;
+}
+
+img.pwtop_logo{
+ float:left;
+ height:40%;
+ width: 40%;
+ padding:20px;
+}
+
+.sys_info
+{
+ float: right;
+ height:116px;
+ width:450px;
+ font-size: 12px;
+ text-align: left;
+}
+
+th{
+ text-align: left;
+}
+
+/* CSS Main Content */
+
+.content_title
+{
+ color: #296629;
+ padding:0px;
+ margin:2px;
+}
+
+#chart_div{
+ float: left;
+}
+
+.small
+{
+ font-size: 10px;
+}
+
+table.emphasis2
+{
+ font-size: 13px;
+ max-width:95%;
+}
+
+
+th.emph_title {
+ padding:5px;
+}
+
+tr.emph1:nth-child(odd) {
+ background: #ffffff;
+}
+
+tr.emph1:nth-child(even) {
+ background: #ebebeb;
+}
+
+tr.tune:nth-child(odd) {
+ background: #fffcfc;
+}
+tr.tune:nth-child(even) {
+ background: #fff0f0;
+}
+
+td.no_wrap:first-child {
+ white-space:nowrap;
+}
+
+.side_by_side_left{
+ float:left;
+}
+.side_by_side_right{
+ float:right;
+}
+
+#device{
+ display: inline-block;
+}
+.clear_block{
+ clear:both;
+}
+
+td.package{
+ background-color: #e0ddfa; /*purple*/
+}
+
+td.core{
+ background-color: #d1ddff; /*ccebff; /*blue*/
+}
+
+td.cpu{
+ background-color: #ffffeb; /* yellow */
+}
+
+th.title{
+ text-align: center;
+ /*border-bottom: 1px solid #666;*/
+}
+
+
+li.summary_list
+{
+ display: inline;
+ padding: 5px;
+ background-color: #f6f6f9;
+ font-size: 12px;
+}
+
+
+
+/* main menu css*/
+#main_menu {
+ clear:both;
+ font-weight: bold;
+ padding: 5px 0;
+ text-align: left;
+ background-image: -webkit-gradient(linear, left top, left bottom,
+ from(#aaa), to(#eee));
+ background: -moz-linear-gradient(top, #aaa, #eee);
+}
+
+
+#main_menu div {
+ font-size: 12px;
+ font-weight: bold;
+ color: white;
+}
+
+#main_menu div.nav_button {
+ margin: 0 0.2em;
+ display: inline;
+ cursor: pointer;
+ color: #223232;
+ font-size: 13px;
+ font-weight: bold;
+ padding: 5px;
+ text-align: center;
+ text-decoration: none;
+}
+
+div.pressed {
+ border: -webkit-gradient(linear, left top, left bottom,
+ from(#b2ffb2), to(#e0ffe0));
+ border-width:0px 8px 0px 8px;
+ background: #999;
+ background-image: -webkit-gradient(linear, left top, left bottom,
+ from(#b2ffb2), to(#e0ffe0));
+ background: -moz-linear-gradient(top, #b2ffb2, #e0ffe0);
+}
+
+div.hide {
+ display: none;
+}
+</style>
+</head>
+
+<body onload='powertop.onload();'>
+<div id=\"main_container\">
diff --git a/src/process/do_process.cpp b/src/process/do_process.cpp
new file mode 100644
index 0000000..be8d3bd
--- /dev/null
+++ b/src/process/do_process.cpp
@@ -0,0 +1,1230 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "process.h"
+#include "interrupt.h"
+#include "timer.h"
+#include "work.h"
+#include "processdevice.h"
+#include "../lib.h"
+#include "../report/report.h"
+#include "../report/report-data-html.h"
+#include "../report/report-maker.h"
+#include "../devlist.h"
+
+#include <vector>
+#include <algorithm>
+#include <stack>
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+
+#include "../perf/perf_bundle.h"
+#include "../perf/perf_event.h"
+#include "../parameters/parameters.h"
+#include "../display.h"
+#include "../measurement/measurement.h"
+
+static class perf_bundle * perf_events;
+
+vector <class power_consumer *> all_power;
+
+vector< vector<class power_consumer *> > cpu_stack;
+
+vector<int> cpu_level;
+vector<int> cpu_credit;
+vector<class power_consumer *> cpu_blame;
+
+#define LEVEL_HARDIRQ 1
+#define LEVEL_SOFTIRQ 2
+#define LEVEL_TIMER 3
+#define LEVEL_WAKEUP 4
+#define LEVEL_PROCESS 5
+#define LEVEL_WORK 6
+
+static uint64_t first_stamp, last_stamp;
+
+double measurement_time;
+
+static void push_consumer(unsigned int cpu, class power_consumer *consumer)
+{
+ if (cpu_stack.size() <= cpu)
+ cpu_stack.resize(cpu + 1);
+ cpu_stack[cpu].push_back(consumer);
+}
+
+static void pop_consumer(unsigned int cpu)
+{
+ if (cpu_stack.size() <= cpu)
+ cpu_stack.resize(cpu + 1);
+
+ if (cpu_stack[cpu].size())
+ cpu_stack[cpu].resize(cpu_stack[cpu].size()-1);
+}
+
+static int consumer_depth(unsigned int cpu)
+{
+ if (cpu_stack.size() <= cpu)
+ cpu_stack.resize(cpu + 1);
+ return cpu_stack[cpu].size();
+}
+
+static class power_consumer *current_consumer(unsigned int cpu)
+{
+ if (cpu_stack.size() <= cpu)
+ cpu_stack.resize(cpu + 1);
+ if (cpu_stack[cpu].size())
+
+ return cpu_stack[cpu][cpu_stack[cpu].size()-1];
+
+ return NULL;
+}
+
+static void clear_consumers(void)
+{
+ unsigned int i;
+ for (i = 0; i < cpu_stack.size(); i++)
+ cpu_stack[i].resize(0);
+}
+
+static void consumer_child_time(unsigned int cpu, uint64_t time)
+{
+ unsigned int i;
+ if (cpu_stack.size() <= cpu)
+ cpu_stack.resize(cpu + 1);
+ for (i = 0; i < cpu_stack[cpu].size(); i++)
+ cpu_stack[cpu][i]->child_runtime += time;
+}
+
+static void set_wakeup_pending(unsigned int cpu)
+{
+ if (cpu_credit.size() <= cpu)
+ cpu_credit.resize(cpu + 1);
+
+ cpu_credit[cpu] = 1;
+}
+
+static void clear_wakeup_pending(unsigned int cpu)
+{
+ if (cpu_credit.size() <= cpu)
+ cpu_credit.resize(cpu + 1);
+
+ cpu_credit[cpu] = 0;
+}
+
+static int get_wakeup_pending(unsigned int cpu)
+{
+ if (cpu_credit.size() <= cpu)
+ cpu_credit.resize(cpu + 1);
+ return cpu_credit[cpu];
+}
+
+static void change_blame(unsigned int cpu, class power_consumer *consumer, int level)
+{
+ if (cpu_level[cpu] >= level)
+ return;
+ cpu_blame[cpu] = consumer;
+ cpu_level[cpu] = level;
+}
+
+static void consume_blame(unsigned int cpu)
+{
+ if (!get_wakeup_pending(cpu))
+ return;
+ if (cpu_level.size() <= cpu)
+ return;
+ if (cpu_blame.size() <= cpu)
+ return;
+ if (!cpu_blame[cpu])
+ return;
+
+ cpu_blame[cpu]->wake_ups++;
+ cpu_blame[cpu] = NULL;
+ cpu_level[cpu] = 0;
+ clear_wakeup_pending(cpu);
+}
+
+
+class perf_process_bundle: public perf_bundle
+{
+ virtual void handle_trace_point(void *trace, int cpu, uint64_t time);
+};
+
+static bool comm_is_xorg(char *comm)
+{
+ return strcmp(comm, "Xorg") == 0 || strcmp(comm, "X") == 0;
+}
+
+/* some processes shouldn't be blamed for the wakeup if they wake a process up... for now this is a hardcoded list */
+int dont_blame_me(char *comm)
+{
+ if (comm_is_xorg(comm))
+ return 1;
+ if (strcmp(comm, "dbus-daemon") == 0)
+ return 1;
+
+ return 0;
+}
+
+static char * get_pevent_field_str(void *trace, struct event_format *event, struct format_field *field)
+{
+ unsigned long long offset, len;
+ if (field->flags & FIELD_IS_DYNAMIC) {
+ offset = field->offset;
+ len = field->size;
+ offset = pevent_read_number(event->pevent, (char *)trace + offset, len);
+ offset &= 0xffff;
+ return (char *)trace + offset;
+ }
+ /** no __data_loc field type*/
+ return (char *)trace + field->offset;
+}
+
+void perf_process_bundle::handle_trace_point(void *trace, int cpu, uint64_t time)
+{
+ struct event_format *event;
+ struct pevent_record rec; /* holder */
+ struct format_field *field;
+ unsigned long long val;
+ int type;
+ int ret;
+
+ rec.data = trace;
+
+ type = pevent_data_type(perf_event::pevent, &rec);
+ event = pevent_find_event(perf_event::pevent, type);
+ if (!event)
+ return;
+
+ if (time < first_stamp)
+ first_stamp = time;
+
+ if (time > last_stamp) {
+ last_stamp = time;
+ measurement_time = (0.0001 + last_stamp - first_stamp) / 1000000000 ;
+ }
+
+ if (strcmp(event->name, "sched_switch") == 0) {
+ class process *old_proc = NULL;
+ class process *new_proc = NULL;
+ const char *next_comm;
+ int next_pid;
+ int prev_pid;
+
+ field = pevent_find_any_field(event, "next_comm");
+ if (!field || !(field->flags & FIELD_IS_STRING))
+ return; /* ?? */
+
+ next_comm = get_pevent_field_str(trace, event, field);
+
+ ret = pevent_get_field_val(NULL, event, "next_pid", &rec, &val, 0);
+ if (ret < 0)
+ return;
+ next_pid = (int)val;
+
+ ret = pevent_get_field_val(NULL, event, "prev_pid", &rec, &val, 0);
+ if (ret < 0)
+ return;
+ prev_pid = (int)val;
+
+ /* find new process pointer */
+ new_proc = find_create_process(next_comm, next_pid);
+
+ /* find the old process pointer */
+
+ while (consumer_depth(cpu) > 1) {
+ pop_consumer(cpu);
+ }
+
+ if (consumer_depth(cpu) == 1)
+ old_proc = (class process *)current_consumer(cpu);
+
+ if (old_proc && strcmp(old_proc->name(), "process"))
+ old_proc = NULL;
+
+ /* retire the old process */
+
+ if (old_proc) {
+ old_proc->deschedule_thread(time, prev_pid);
+ old_proc->waker = NULL;
+ }
+
+ if (consumer_depth(cpu))
+ pop_consumer(cpu);
+
+ push_consumer(cpu, new_proc);
+
+ /* start new process */
+ new_proc->schedule_thread(time, next_pid);
+
+ if (strncmp(next_comm,"migration/", 10) && strncmp(next_comm,"kworker/", 8) && strncmp(next_comm, "kondemand/",10)) {
+ if (next_pid) {
+ /* If someone woke us up.. blame him instead */
+ if (new_proc->waker) {
+ change_blame(cpu, new_proc->waker, LEVEL_PROCESS);
+ } else {
+ change_blame(cpu, new_proc, LEVEL_PROCESS);
+ }
+ }
+
+ consume_blame(cpu);
+ }
+ new_proc->waker = NULL;
+ }
+ else if (strcmp(event->name, "sched_wakeup") == 0) {
+ class power_consumer *from = NULL;
+ class process *dest_proc = NULL;
+ class process *from_proc = NULL;
+ const char *comm;
+ int flags;
+ int pid;
+
+ ret = pevent_get_common_field_val(NULL, event, "common_flags", &rec, &val, 0);
+ if (ret < 0)
+ return;
+ flags = (int)val;
+
+ if ( (flags & TRACE_FLAG_HARDIRQ) || (flags & TRACE_FLAG_SOFTIRQ)) {
+ class timer *timer;
+ timer = (class timer *) current_consumer(cpu);
+ if (timer && strcmp(timer->name(), "timer")==0) {
+ if (strcmp(timer->handler, "delayed_work_timer_fn") &&
+ strcmp(timer->handler, "hrtimer_wakeup") &&
+ strcmp(timer->handler, "it_real_fn"))
+ from = timer;
+ }
+ /* woken from interrupt */
+ /* TODO: find the current irq handler and set "from" to that */
+ } else {
+ from = current_consumer(cpu);
+ }
+
+
+ field = pevent_find_any_field(event, "comm");
+
+ if (!field || !(field->flags & FIELD_IS_STRING))
+ return;
+
+ comm = get_pevent_field_str(trace, event, field);
+
+ ret = pevent_get_field_val(NULL, event, "pid", &rec, &val, 0);
+ if (ret < 0)
+ return;
+ pid = (int)val;
+
+ dest_proc = find_create_process(comm, pid);
+
+ if (from && strcmp(from->name(), "process")!=0){
+ /* not a process doing the wakeup */
+ from = NULL;
+ from_proc = NULL;
+ } else {
+ from_proc = (class process *) from;
+ }
+
+ if (from_proc && (dest_proc->running == 0) && (dest_proc->waker == NULL) && (pid != 0) && !dont_blame_me(from_proc->comm))
+ dest_proc->waker = from;
+ if (from)
+ dest_proc->last_waker = from;
+
+ /* Account processes that wake up X specially */
+ if (from && dest_proc && comm_is_xorg(dest_proc->comm))
+ from->xwakes ++ ;
+
+ }
+ else if (strcmp(event->name, "irq_handler_entry") == 0) {
+ class interrupt *irq = NULL;
+ const char *handler;
+ int nr;
+
+ field = pevent_find_any_field(event, "name");
+ if (!field || !(field->flags & FIELD_IS_STRING))
+ return; /* ?? */
+
+ handler = get_pevent_field_str(trace, event, field);
+
+ ret = pevent_get_field_val(NULL, event, "irq", &rec, &val, 0);
+ if (ret < 0)
+ return;
+ nr = (int)val;
+
+ irq = find_create_interrupt(handler, nr, cpu);
+
+
+ push_consumer(cpu, irq);
+
+ irq->start_interrupt(time);
+
+ if (strstr(irq->handler, "timer") ==NULL)
+ change_blame(cpu, irq, LEVEL_HARDIRQ);
+
+ }
+
+ else if (strcmp(event->name, "irq_handler_exit") == 0) {
+ class interrupt *irq = NULL;
+ uint64_t t;
+
+ /* find interrupt (top of stack) */
+ irq = (class interrupt *)current_consumer(cpu);
+ if (!irq || strcmp(irq->name(), "interrupt"))
+ return;
+ pop_consumer(cpu);
+ /* retire interrupt */
+ t = irq->end_interrupt(time);
+ consumer_child_time(cpu, t);
+ }
+
+ else if (strcmp(event->name, "softirq_entry") == 0) {
+ class interrupt *irq = NULL;
+ const char *handler = NULL;
+ int vec;
+
+ ret = pevent_get_field_val(NULL, event, "vec", &rec, &val, 0);
+ if (ret < 0) {
+ fprintf(stderr, "softirq_entry event returned no vector number?\n");
+ return;
+ }
+ vec = (int)val;
+
+ if (vec <= 9)
+ handler = softirqs[vec];
+
+ if (!handler)
+ return;
+
+ irq = find_create_interrupt(handler, vec, cpu);
+
+ push_consumer(cpu, irq);
+
+ irq->start_interrupt(time);
+ change_blame(cpu, irq, LEVEL_SOFTIRQ);
+ }
+ else if (strcmp(event->name, "softirq_exit") == 0) {
+ class interrupt *irq = NULL;
+ uint64_t t;
+
+ irq = (class interrupt *) current_consumer(cpu);
+ if (!irq || strcmp(irq->name(), "interrupt"))
+ return;
+ pop_consumer(cpu);
+ /* pop irq */
+ t = irq->end_interrupt(time);
+ consumer_child_time(cpu, t);
+ }
+ else if (strcmp(event->name, "timer_expire_entry") == 0) {
+ class timer *timer = NULL;
+ uint64_t function;
+ uint64_t tmr;
+
+ ret = pevent_get_field_val(NULL, event, "function", &rec, &val, 0);
+ if (ret < 0) {
+ fprintf(stderr, "timer_expire_entry event returned no function value?\n");
+ return;
+ }
+ function = (uint64_t)val;
+
+ timer = find_create_timer(function);
+
+ if (timer->is_deferred())
+ return;
+
+ ret = pevent_get_field_val(NULL, event, "timer", &rec, &val, 0);
+ if (ret < 0) {
+ fprintf(stderr, "softirq_entry event returned no timer ?\n");
+ return;
+ }
+ tmr = (uint64_t)val;
+
+ push_consumer(cpu, timer);
+ timer->fire(time, tmr);
+
+ if (strcmp(timer->handler, "delayed_work_timer_fn"))
+ change_blame(cpu, timer, LEVEL_TIMER);
+ }
+ else if (strcmp(event->name, "timer_expire_exit") == 0) {
+ class timer *timer = NULL;
+ uint64_t tmr;
+ uint64_t t;
+
+ ret = pevent_get_field_val(NULL, event, "timer", &rec, &val, 0);
+ if (ret < 0)
+ return;
+ tmr = (uint64_t)val;
+
+ timer = (class timer *) current_consumer(cpu);
+ if (!timer || strcmp(timer->name(), "timer")) {
+ return;
+ }
+ pop_consumer(cpu);
+ t = timer->done(time, tmr);
+ if (t == ~0ULL) {
+ timer->fire(first_stamp, tmr);
+ t = timer->done(time, tmr);
+ }
+ consumer_child_time(cpu, t);
+ }
+ else if (strcmp(event->name, "hrtimer_expire_entry") == 0) {
+ class timer *timer = NULL;
+ uint64_t function;
+ uint64_t tmr;
+
+ ret = pevent_get_field_val(NULL, event, "function", &rec, &val, 0);
+ if (ret < 0)
+ return;
+ function = (uint64_t)val;
+
+ timer = find_create_timer(function);
+
+ ret = pevent_get_field_val(NULL, event, "hrtimer", &rec, &val, 0);
+ if (ret < 0)
+ return;
+ tmr = (uint64_t)val;
+
+ push_consumer(cpu, timer);
+ timer->fire(time, tmr);
+
+ if (strcmp(timer->handler, "delayed_work_timer_fn"))
+ change_blame(cpu, timer, LEVEL_TIMER);
+ }
+ else if (strcmp(event->name, "hrtimer_expire_exit") == 0) {
+ class timer *timer = NULL;
+ uint64_t tmr;
+ uint64_t t;
+
+ timer = (class timer *) current_consumer(cpu);
+ if (!timer || strcmp(timer->name(), "timer")) {
+ return;
+ }
+
+ ret = pevent_get_field_val(NULL, event, "hrtimer", &rec, &val, 0);
+ if (ret < 0)
+ return;
+ tmr = (uint64_t)val;
+
+ pop_consumer(cpu);
+ t = timer->done(time, tmr);
+ if (t == ~0ULL) {
+ timer->fire(first_stamp, tmr);
+ t = timer->done(time, tmr);
+ }
+ consumer_child_time(cpu, t);
+ }
+ else if (strcmp(event->name, "workqueue_execute_start") == 0) {
+ class work *work = NULL;
+ uint64_t function;
+ uint64_t wk;
+
+ ret = pevent_get_field_val(NULL, event, "function", &rec, &val, 0);
+ if (ret < 0)
+ return;
+ function = (uint64_t)val;
+
+ ret = pevent_get_field_val(NULL, event, "work", &rec, &val, 0);
+ if (ret < 0)
+ return;
+ wk = (uint64_t)val;
+
+ work = find_create_work(function);
+
+
+ push_consumer(cpu, work);
+ work->fire(time, wk);
+
+
+ if (strcmp(work->handler, "do_dbs_timer") != 0 && strcmp(work->handler, "vmstat_update") != 0)
+ change_blame(cpu, work, LEVEL_WORK);
+ }
+ else if (strcmp(event->name, "workqueue_execute_end") == 0) {
+ class work *work = NULL;
+ uint64_t t;
+ uint64_t wk;
+
+ ret = pevent_get_field_val(NULL, event, "work", &rec, &val, 0);
+ if (ret < 0)
+ return;
+ wk = (uint64_t)val;
+
+ work = (class work *) current_consumer(cpu);
+ if (!work || strcmp(work->name(), "work")) {
+ return;
+ }
+ pop_consumer(cpu);
+ t = work->done(time, wk);
+ if (t == ~0ULL) {
+ work->fire(first_stamp, wk);
+ t = work->done(time, wk);
+ }
+ consumer_child_time(cpu, t);
+ }
+ else if (strcmp(event->name, "cpu_idle") == 0) {
+ pevent_get_field_val(NULL, event, "state", &rec, &val, 0);
+ if (val == (unsigned int)-1)
+ consume_blame(cpu);
+ else
+ set_wakeup_pending(cpu);
+ }
+ else if (strcmp(event->name, "power_start") == 0) {
+ set_wakeup_pending(cpu);
+ }
+ else if (strcmp(event->name, "power_end") == 0) {
+ consume_blame(cpu);
+ }
+ else if (strcmp(event->name, "i915_gem_ring_dispatch") == 0
+ || strcmp(event->name, "i915_gem_request_submit") == 0) {
+ /* any kernel contains only one of the these tracepoints,
+ * the latter one got replaced by the former one */
+ class power_consumer *consumer = NULL;
+ int flags;
+
+ ret = pevent_get_common_field_val(NULL, event, "common_flags", &rec, &val, 0);
+ if (ret < 0)
+ return;
+ flags = (int)val;
+
+ consumer = current_consumer(cpu);
+ /* currently we don't count graphic requests submitted from irq contect */
+ if ( (flags & TRACE_FLAG_HARDIRQ) || (flags & TRACE_FLAG_SOFTIRQ)) {
+ consumer = NULL;
+ }
+
+
+ /* if we are X, and someone just woke us, account the GPU op to the guy waking us */
+ if (consumer && strcmp(consumer->name(), "process")==0) {
+ class process *proc = NULL;
+ proc = (class process *) consumer;
+ if (comm_is_xorg(proc->comm) && proc->last_waker) {
+ consumer = proc->last_waker;
+ }
+ }
+
+
+
+ if (consumer) {
+ consumer->gpu_ops++;
+ }
+ }
+ else if (strcmp(event->name, "writeback_inode_dirty") == 0) {
+ static uint64_t prev_time;
+ class power_consumer *consumer = NULL;
+ int dev;
+
+ consumer = current_consumer(cpu);
+
+ ret = pevent_get_field_val(NULL, event, "dev", &rec, &val, 0);
+ if (ret < 0)
+
+ return;
+ dev = (int)val;
+
+ if (consumer && strcmp(consumer->name(),
+ "process")==0 && dev > 0) {
+
+ consumer->disk_hits++;
+
+ /* if the previous inode dirty was > 1 second ago, it becomes a hard hit */
+ if ((time - prev_time) > 1000000000)
+ consumer->hard_disk_hits++;
+
+ prev_time = time;
+ }
+ }
+}
+
+void start_process_measurement(void)
+{
+ if (!perf_events) {
+ perf_events = new perf_process_bundle();
+ perf_events->add_event("sched:sched_switch");
+ perf_events->add_event("sched:sched_wakeup");
+ perf_events->add_event("irq:irq_handler_entry");
+ perf_events->add_event("irq:irq_handler_exit");
+ perf_events->add_event("irq:softirq_entry");
+ perf_events->add_event("irq:softirq_exit");
+ perf_events->add_event("timer:timer_expire_entry");
+ perf_events->add_event("timer:timer_expire_exit");
+ perf_events->add_event("timer:hrtimer_expire_entry");
+ perf_events->add_event("timer:hrtimer_expire_exit");
+ if (!perf_events->add_event("power:cpu_idle")){
+ perf_events->add_event("power:power_start");
+ perf_events->add_event("power:power_end");
+ }
+ perf_events->add_event("workqueue:workqueue_execute_start");
+ perf_events->add_event("workqueue:workqueue_execute_end");
+ perf_events->add_event("i915:i915_gem_ring_dispatch");
+ perf_events->add_event("i915:i915_gem_request_submit");
+ perf_events->add_event("writeback:writeback_inode_dirty");
+ }
+
+ first_stamp = ~0ULL;
+ last_stamp = 0;
+ perf_events->start();
+}
+
+void end_process_measurement(void)
+{
+ if (!perf_events)
+ return;
+
+ perf_events->stop();
+}
+
+
+static bool power_cpu_sort(class power_consumer * i, class power_consumer * j)
+{
+ double iW, jW;
+
+ iW = i->Witts();
+ jW = j->Witts();
+
+ if (equals(iW, jW)) {
+ double iR, jR;
+
+ iR = i->accumulated_runtime - i->child_runtime;
+ jR = j->accumulated_runtime - j->child_runtime;
+
+ if (equals(iR, jR))
+ return i->wake_ups > j->wake_ups;
+ return (iR > jR);
+ }
+
+ return (iW > jW);
+}
+
+double total_wakeups(void)
+{
+ double total = 0;
+ unsigned int i;
+ for (i = 0; i < all_power.size() ; i++)
+ total += all_power[i]->wake_ups;
+
+ total = total / measurement_time;
+
+
+ return total;
+}
+
+double total_gpu_ops(void)
+{
+ double total = 0;
+ unsigned int i;
+ for (i = 0; i < all_power.size() ; i++)
+ total += all_power[i]->gpu_ops;
+
+
+ total = total / measurement_time;
+
+
+ return total;
+}
+
+double total_disk_hits(void)
+{
+ double total = 0;
+ unsigned int i;
+ for (i = 0; i < all_power.size() ; i++)
+ total += all_power[i]->disk_hits;
+
+
+ total = total / measurement_time;
+
+
+ return total;
+}
+
+
+double total_hard_disk_hits(void)
+{
+ double total = 0;
+ unsigned int i;
+ for (i = 0; i < all_power.size() ; i++)
+ total += all_power[i]->hard_disk_hits;
+
+
+ total = total / measurement_time;
+
+
+ return total;
+}
+
+double total_xwakes(void)
+{
+ double total = 0;
+ unsigned int i;
+ for (i = 0; i < all_power.size() ; i++)
+ total += all_power[i]->xwakes;
+
+
+ total = total / measurement_time;
+
+
+ return total;
+}
+
+void process_update_display(void)
+{
+ unsigned int i;
+ WINDOW *win;
+ double pw;
+ double joules;
+ int tl;
+ int tlt;
+ int tlr;
+
+ int show_power;
+ int need_linebreak = 0;
+
+ sort(all_power.begin(), all_power.end(), power_cpu_sort);
+
+ show_power = global_power_valid();
+
+ win = get_ncurses_win("Overview");
+ if (!win)
+ return;
+
+ wclear(win);
+
+ wmove(win, 1,0);
+
+#if 0
+ double sum;
+ calculate_params();
+ sum = 0.0;
+ sum += get_parameter_value("base power");
+ for (i = 0; i < all_power.size(); i++) {
+ sum += all_power[i]->Witts();
+ }
+
+ wprintw(win, _("Estimated power: %5.1f Measured power: %5.1f Sum: %5.1f\n\n"),
+ all_parameters.guessed_power, global_power(), sum);
+#endif
+
+ pw = global_power();
+ joules = global_joules();
+ tl = global_time_left() / 60;
+ tlt = (tl /60);
+ tlr = tl % 60;
+
+ if (pw > 0.0001) {
+ char buf[32];
+ wprintw(win, _("The battery reports a discharge rate of %sW\n"),
+ fmt_prefix(pw, buf));
+ wprintw(win, _("The energy consumed was %sJ\n"),
+ fmt_prefix(joules, buf));
+ need_linebreak = 1;
+ }
+ if (tl > 0 && pw > 0.0001) {
+ wprintw(win, _("The estimated remaining time is %i hours, %i minutes\n"), tlt, tlr);
+ need_linebreak = 1;
+ }
+
+ if (need_linebreak)
+ wprintw(win, "\n");
+
+
+ wprintw(win, "%s: %3.1f %s, %3.1f %s, %3.1f %s %3.1f%% %s\n\n",_("Summary"), total_wakeups(), _("wakeups/second"), total_gpu_ops(), _("GPU ops/seconds"), total_disk_hits(), _("VFS ops/sec and"), total_cpu_time()*100, _("CPU use"));
+
+
+ if (show_power)
+ wprintw(win, "%s %s %s %s %s\n", _("Power est."), _("Usage"), _("Events/s"), _("Category"), _("Description"));
+ else
+ wprintw(win, " %s %s %s %s\n", _("Usage"), _("Events/s"), _("Category"), _("Description"));
+
+ for (i = 0; i < all_power.size(); i++) {
+ char power[16];
+ char name[20];
+ char usage[20];
+ char events[20];
+ char descr[128];
+
+ format_watts(all_power[i]->Witts(), power, 10);
+ if (!show_power)
+ strcpy(power, " ");
+ snprintf(name, sizeof(name), "%s", all_power[i]->type());
+
+ align_string(name, 14, 20);
+
+ if (all_power[i]->events() == 0 && all_power[i]->usage() == 0 && all_power[i]->Witts() == 0)
+ break;
+
+ usage[0] = 0;
+ if (all_power[i]->usage_units()) {
+ if (all_power[i]->usage() < 1000)
+ snprintf(usage, sizeof(usage), "%5.1f%s", all_power[i]->usage(), all_power[i]->usage_units());
+ else
+ snprintf(usage, sizeof(usage), "%5i%s", (int)all_power[i]->usage(), all_power[i]->usage_units());
+ }
+
+ align_string(usage, 14, 20);
+
+ snprintf(events, sizeof(events), "%5.1f", all_power[i]->events());
+ if (!all_power[i]->show_events())
+ events[0] = 0;
+ else if (all_power[i]->events() <= 0.3)
+ snprintf(events, sizeof(events), "%5.2f", all_power[i]->events());
+
+ align_string(events, 12, 20);
+ wprintw(win, "%s %s %s %s %s\n", power, usage, events, name, pretty_print(all_power[i]->description(), descr, 128));
+ }
+}
+
+void report_process_update_display(void)
+{
+ unsigned int i;
+ unsigned int total;
+ int show_power, cols, rows, idx;
+
+ /* div attr css_class and css_id */
+ tag_attr div_attr;
+ init_div(&div_attr, "clear_block", "software");
+
+ /* Set Table attributes, rows, and cols */
+ cols=7;
+ sort(all_power.begin(), all_power.end(), power_cpu_sort);
+ show_power = global_power_valid();
+ if (show_power)
+ cols=8;
+
+ idx=cols;
+
+ total = all_power.size();
+ if (total > 100)
+ total = 100;
+
+ rows=total+1;
+ table_attributes std_table_css;
+ init_nowarp_table_attr(&std_table_css, rows, cols);
+
+
+ /* Set Title attributes */
+ tag_attr title_attr;
+ init_title_attr(&title_attr);
+
+ /* Set array of data in row Major order */
+ string *software_data = new string[cols * rows];
+ software_data[0]=__("Usage");
+ software_data[1]=__("Wakeups/s");
+ software_data[2]=__("GPU ops/s");
+ software_data[3]=__("Disk IO/s");
+ software_data[4]=__("GFX Wakeups/s");
+ software_data[5]=__("Category");
+ software_data[6]=__("Description");
+
+ if (show_power)
+ software_data[7]=__("PW Estimate");
+
+
+ for (i = 0; i < total; i++) {
+ char power[16];
+ char name[20];
+ char usage[20];
+ char wakes[20];
+ char gpus[20];
+ char disks[20];
+ char xwakes[20];
+ char descr[128];
+ format_watts(all_power[i]->Witts(), power, 10);
+
+ if (!show_power)
+ strcpy(power, " ");
+ snprintf(name, sizeof(name), "%s", all_power[i]->type());
+
+ if (strcmp(name, "Device") == 0)
+ continue;
+
+ if (all_power[i]->events() == 0 && all_power[i]->usage() == 0
+ && all_power[i]->Witts() == 0)
+ break;
+
+ usage[0] = 0;
+ if (all_power[i]->usage_units()) {
+ if (all_power[i]->usage() < 1000)
+ snprintf(usage, sizeof(usage), "%5.1f%s", all_power[i]->usage(), all_power[i]->usage_units());
+ else
+ snprintf(usage, sizeof(usage), "%5i%s", (int)all_power[i]->usage(), all_power[i]->usage_units());
+ }
+ snprintf(wakes, sizeof(wakes), "%5.1f", all_power[i]->wake_ups / measurement_time);
+ if (all_power[i]->wake_ups / measurement_time <= 0.3)
+ snprintf(wakes, sizeof(wakes), "%5.2f", all_power[i]->wake_ups / measurement_time);
+ snprintf(gpus, sizeof(gpus), "%5.1f", all_power[i]->gpu_ops / measurement_time);
+ snprintf(disks, sizeof(disks), "%5.1f (%5.1f)", all_power[i]->hard_disk_hits / measurement_time,
+ all_power[i]->disk_hits / measurement_time);
+ snprintf(xwakes, sizeof(xwakes), "%5.1f", all_power[i]->xwakes / measurement_time);
+ if (!all_power[i]->show_events()) {
+ wakes[0] = 0;
+ gpus[0] = 0;
+ disks[0] = 0;
+ }
+
+ if (all_power[i]->gpu_ops == 0)
+ gpus[0] = 0;
+ if (all_power[i]->wake_ups == 0)
+ wakes[0] = 0;
+ if (all_power[i]->disk_hits == 0)
+ disks[0] = 0;
+ if (all_power[i]->xwakes == 0)
+ xwakes[0] = 0;
+
+ software_data[idx]=string(usage);
+ idx+=1;
+
+ software_data[idx]=string(wakes);
+ idx+=1;
+
+ software_data[idx]=string(gpus);
+ idx+=1;
+
+ software_data[idx]=string(disks);
+ idx+=1;
+
+ software_data[idx]=string(xwakes);
+ idx+=1;
+
+ software_data[idx]=string(name);
+ idx+=1;
+
+ software_data[idx]=string(pretty_print(all_power[i]->description(), descr, 128));
+ idx+=1;
+ if (show_power) {
+ software_data[idx]=string(power);
+ idx+=1;
+ }
+ }
+
+ /* Report Output */
+ report.add_div(&div_attr);
+ report.add_title(&title_attr, __("Overview of Software Power Consumers"));
+ report.add_table(software_data, &std_table_css);
+ report.end_div();
+ delete [] software_data;
+}
+
+void report_summary(void)
+{
+ unsigned int i;
+ unsigned int total;
+ int show_power;
+ int rows, cols, idx;
+
+ sort(all_power.begin(), all_power.end(), power_cpu_sort);
+ show_power = global_power_valid();
+
+ /* div attr css_class and css_id */
+ tag_attr div_attr;
+ init_div(&div_attr, "clear_block", "summary");
+
+
+ /* Set table attributes, rows, and cols */
+ cols=4;
+ if (show_power)
+ cols=5;
+ idx=cols;
+ total = all_power.size();
+ if (total > 10)
+ total = 10;
+ rows=total+1;
+ table_attributes std_table_css;
+ init_std_table_attr(&std_table_css, rows, cols);
+
+ /* Set title attributes */
+ tag_attr title_attr;
+ init_title_attr(&title_attr);
+
+ /* Set array for summary */
+ int summary_size =12;
+ string *summary = new string [summary_size];
+ summary[0]=__("Target:");
+ summary[1]=__("1 units/s");
+ summary[2]=__("System: ");
+ summary[3]= double_to_string(total_wakeups());
+ summary[3].append(__(" wakeup/s"));
+ summary[4]=__("CPU: ");
+ summary[5]= double_to_string(total_cpu_time()*100);
+ summary[5].append(__("\% usage"));
+ summary[6]=__("GPU:");
+ summary[7]=double_to_string(total_gpu_ops());
+ summary[7].append(__(" ops/s"));
+ summary[8]=__("GFX:");
+ summary[9]=double_to_string(total_xwakes());
+ summary[9].append(__(" wakeups/s"));
+ summary[10]=__("VFS:");
+ summary[11]= double_to_string(total_disk_hits());
+ summary[11].append(__(" ops/s"));
+
+ /* Set array of data in row Major order */
+ string *summary_data = new string[cols * (rows + 1)];
+ summary_data[0]=__("Usage");
+ summary_data[1]=__("Events/s");
+ summary_data[2]=__("Category");
+ summary_data[3]=__("Description");
+ if (show_power)
+ summary_data[4]=__("PW Estimate");
+
+ for (i = 0; i < all_power.size(); i++) {
+ char power[16];
+ char name[20];
+ char usage[20];
+ char events[20];
+ char descr[128];
+ format_watts(all_power[i]->Witts(), power, 10);
+
+ if (!show_power)
+ strcpy(power, " ");
+ snprintf(name, sizeof(name), "%s", all_power[i]->type());
+
+ if (i > total)
+ break;
+
+ if (all_power[i]->events() == 0 && all_power[i]->usage() == 0 &&
+ all_power[i]->Witts() == 0)
+ break;
+
+ usage[0] = 0;
+ if (all_power[i]->usage_units()) {
+ if (all_power[i]->usage() < 1000)
+ snprintf(usage, sizeof(usage), "%5.1f%s", all_power[i]->usage_summary(),
+ all_power[i]->usage_units_summary());
+ else
+ snprintf(usage, sizeof(usage), "%5i%s", (int)all_power[i]->usage_summary(),
+ all_power[i]->usage_units_summary());
+ }
+ snprintf(events, sizeof(events), "%5.1f", all_power[i]->events());
+ if (!all_power[i]->show_events())
+ events[0] = 0;
+ else if (all_power[i]->events() <= 0.3)
+ snprintf(events, sizeof(events), "%5.2f", all_power[i]->events());
+
+ summary_data[idx]=string(usage);
+ idx+=1;
+
+ summary_data[idx]=string(events);
+ idx+=1;
+
+ summary_data[idx]=string(name);
+ idx+=1;
+
+ summary_data[idx]=string(pretty_print(all_power[i]->description(), descr, 128));
+ idx+=1;
+
+ if (show_power){
+ summary_data[idx]=power;
+ idx+=1;
+ }
+ }
+
+ /* Report Summary for all */
+ report.add_summary_list(summary, summary_size);
+ report.add_div(&div_attr);
+ report.add_title(&title_attr, __("Top 10 Power Consumers"));
+ report.add_table(summary_data, &std_table_css);
+ report.end_div();
+ delete [] summary;
+ delete [] summary_data;
+}
+
+
+void process_process_data(void)
+{
+ if (!perf_events)
+ return;
+
+ clear_processes();
+ clear_interrupts();
+
+ all_power.erase(all_power.begin(), all_power.end());
+ clear_consumers();
+
+
+ cpu_credit.resize(0, 0);
+ cpu_credit.resize(get_max_cpu()+1, 0);
+ cpu_level.resize(0, 0);
+ cpu_level.resize(get_max_cpu()+1, 0);
+ cpu_blame.resize(0, NULL);
+ cpu_blame.resize(get_max_cpu()+1, NULL);
+
+
+
+ /* process data */
+ perf_events->process();
+ perf_events->clear();
+
+ run_devpower_list();
+
+ merge_processes();
+
+ all_processes_to_all_power();
+ all_interrupts_to_all_power();
+ all_timers_to_all_power();
+ all_work_to_all_power();
+ all_devices_to_all_power();
+
+ sort(all_power.begin(), all_power.end(), power_cpu_sort);
+}
+
+
+double total_cpu_time(void)
+{
+ unsigned int i;
+ double total = 0.0;
+ for (i = 0; i < all_power.size() ; i++) {
+ if (all_power[i]->child_runtime > all_power[i]->accumulated_runtime)
+ all_power[i]->child_runtime = 0;
+ total += all_power[i]->accumulated_runtime - all_power[i]->child_runtime;
+ }
+
+ total = (total / (0.0001 + last_stamp - first_stamp));
+
+ return total;
+}
+
+
+
+void end_process_data(void)
+{
+ report_utilization("cpu-consumption", total_cpu_time());
+ report_utilization("cpu-wakeups", total_wakeups());
+ report_utilization("gpu-operations", total_gpu_ops());
+ report_utilization("disk-operations", total_disk_hits());
+ report_utilization("disk-operations-hard", total_hard_disk_hits());
+ report_utilization("xwakes", total_xwakes());
+
+ all_power.erase(all_power.begin(), all_power.end());
+ clear_processes();
+ clear_proc_devices();
+ clear_interrupts();
+ clear_timers();
+ clear_work();
+ clear_consumers();
+
+ perf_events->clear();
+
+}
+
+void clear_process_data(void)
+{
+ if (perf_events)
+ perf_events->release();
+ delete perf_events;
+}
+
diff --git a/src/process/interrupt.cpp b/src/process/interrupt.cpp
new file mode 100644
index 0000000..a6553b1
--- /dev/null
+++ b/src/process/interrupt.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include "process.h"
+#include "interrupt.h"
+#include "../lib.h"
+
+const char* softirqs[] = {
+ "HI_SOFTIRQ",
+ "timer(softirq)",
+ "net tx(softirq)",
+ "net_rx(softirq)",
+ "block(softirq)",
+ "block_iopoll(softirq)",
+ "tasklet(softirq)",
+ "sched(softirq)",
+ "hrtimer(softirq)",
+ "RCU(softirq)",
+ NULL
+};
+
+
+interrupt::interrupt(const char *_handler, int _number) : power_consumer()
+{
+ char buf[128];
+ running_since = 0;
+ number = _number;
+ pt_strcpy(handler, _handler);
+ raw_count = 0;
+ snprintf(desc, sizeof(desc), "[%i] %s", number, pretty_print(handler, buf, 128));
+}
+
+
+vector <class interrupt *> all_interrupts;
+
+void interrupt::start_interrupt(uint64_t time)
+{
+ running_since = time;
+ raw_count ++;
+}
+
+uint64_t interrupt::end_interrupt(uint64_t time)
+{
+ uint64_t delta;
+
+ delta = time - running_since;
+ accumulated_runtime += delta;
+ return delta;
+}
+
+const char * interrupt::description(void)
+{
+ if (child_runtime > accumulated_runtime)
+ child_runtime = 0;
+ return desc;
+}
+
+double interrupt::usage_summary(void)
+{
+ double t;
+ t = (accumulated_runtime - child_runtime) / 1000000.0 / measurement_time / 10;
+ return t;
+}
+
+const char * interrupt::usage_units_summary(void)
+{
+ return "%";
+}
+
+
+class interrupt * find_create_interrupt(const char *_handler, int nr, int cpu)
+{
+ char handler[64];
+ unsigned int i;
+ class interrupt *new_irq;
+
+ pt_strcpy(handler, _handler);
+ if (strcmp(handler, "timer")==0)
+ sprintf(handler, "timer/%i", cpu);
+
+
+ for (i = 0; i < all_interrupts.size(); i++) {
+ if (all_interrupts[i] && all_interrupts[i]->number == nr && strcmp(handler, all_interrupts[i]->handler) == 0)
+ return all_interrupts[i];
+ }
+
+ new_irq = new class interrupt(handler, nr);
+ all_interrupts.push_back(new_irq);
+ return new_irq;
+}
+
+void all_interrupts_to_all_power(void)
+{
+ unsigned int i;
+ for (i = 0; i < all_interrupts.size() ; i++)
+ if (all_interrupts[i]->accumulated_runtime)
+ all_power.push_back(all_interrupts[i]);
+}
+
+void clear_interrupts(void)
+{
+ std::vector<class interrupt *>::iterator it = all_interrupts.begin();
+ while (it != all_interrupts.end()) {
+ delete *it;
+ it = all_interrupts.erase(it);
+ }
+}
diff --git a/src/process/interrupt.h b/src/process/interrupt.h
new file mode 100644
index 0000000..8d3a4d7
--- /dev/null
+++ b/src/process/interrupt.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_INTERRUPT_H
+#define _INCLUDE_GUARD_INTERRUPT_H
+
+#include <stdint.h>
+
+#include "powerconsumer.h"
+
+class interrupt : public power_consumer {
+ uint64_t running_since;
+ char desc[256];
+public:
+ char handler[32];
+ int number;
+
+ int raw_count;
+
+ interrupt(const char *_handler, int _number);
+
+ virtual void start_interrupt(uint64_t time);
+ virtual uint64_t end_interrupt(uint64_t time);
+
+ virtual const char * description(void);
+
+ virtual const char * name(void) { return "interrupt"; };
+ virtual const char * type(void) { return "Interrupt"; };
+ virtual double usage_summary(void);
+ virtual const char * usage_units_summary(void);
+};
+
+extern vector <class interrupt *> all_interrupts;
+extern const char* softirqs[];
+
+
+extern class interrupt * find_create_interrupt(const char *_handler, int nr, int cpu);
+extern void all_interrupts_to_all_power(void);
+extern void clear_interrupts(void);
+
+#endif
diff --git a/src/process/powerconsumer.cpp b/src/process/powerconsumer.cpp
new file mode 100644
index 0000000..2ff2132
--- /dev/null
+++ b/src/process/powerconsumer.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "powerconsumer.h"
+#include "process.h"
+#include "../parameters/parameters.h"
+
+double power_consumer::Witts(void)
+{
+ double cost;
+ double timecost;
+ double wakeupcost;
+ double gpucost;
+ double disk_cost;
+ double hard_disk_cost;
+ double xwake_cost;
+
+ if (child_runtime > accumulated_runtime)
+ child_runtime = 0;
+
+ timecost = get_parameter_value("cpu-consumption");
+ wakeupcost = get_parameter_value("cpu-wakeups");
+ gpucost = get_parameter_value("gpu-operations");
+ disk_cost = get_parameter_value("disk-operations");
+ hard_disk_cost = get_parameter_value("disk-operations-hard");
+ xwake_cost = get_parameter_value("xwakes");
+
+ cost = 0;
+
+ cost += wakeupcost * wake_ups / 10000.0;
+ cost += ( (accumulated_runtime - child_runtime) / 1000000000.0) * timecost;
+ cost += gpucost * gpu_ops / 100.0;
+ cost += hard_disk_cost * hard_disk_hits / 100.0;
+ cost += disk_cost * disk_hits / 100.0;
+ cost += xwake_cost * xwakes / 100.0;
+
+ cost = cost / measurement_time;
+
+ cost += power_charge;
+
+ return cost;
+}
+
+power_consumer::power_consumer(void)
+{
+ accumulated_runtime = 0;
+ child_runtime = 0;
+ disk_hits = 0;
+ wake_ups = 0;
+ gpu_ops = 0;
+ hard_disk_hits = 0;
+ xwakes = 0;
+ waker = NULL;
+ last_waker = NULL;
+ power_charge = 0.0;
+}
+
+double power_consumer::usage(void)
+{
+ double t;
+ t = (accumulated_runtime - child_runtime) / 1000000.0 / measurement_time;
+ if (t < 0.7)
+ t = t * 1000;
+ return t;
+}
+
+const char * power_consumer::usage_units(void)
+{
+ double t;
+ t = (accumulated_runtime - child_runtime) / 1000000.0 / measurement_time;
+ if (t < 0.7) {
+ if (utf_ok)
+ return " µs/s";
+ else
+ return " us/s";
+ }
+ return " ms/s";
+}
diff --git a/src/process/powerconsumer.h b/src/process/powerconsumer.h
new file mode 100644
index 0000000..0ae384a
--- /dev/null
+++ b/src/process/powerconsumer.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef __INCLUDE_GUARD_POWER_CONSUMER_
+#define __INCLUDE_GUARD_POWER_CONSUMER_
+
+#include <stdint.h>
+#include <vector>
+#include <algorithm>
+
+using namespace std;
+
+extern double measurement_time;
+
+class power_consumer;
+
+class power_consumer {
+
+public:
+ uint64_t accumulated_runtime;
+ uint64_t child_runtime;
+ int disk_hits;
+ int wake_ups;
+ int gpu_ops;
+ int hard_disk_hits; /* those which are likely a wakeup of the disk */
+ int xwakes;
+
+ double power_charge; /* power consumed by devices opened by this process */
+ class power_consumer *waker;
+ class power_consumer *last_waker;
+
+ power_consumer(void);
+ virtual ~power_consumer() {};
+
+ virtual double Witts(void);
+ virtual const char * description(void) { return ""; };
+
+ virtual const char * name(void) { return "abstract"; };
+ virtual const char * type(void) { return "abstract"; };
+
+ virtual double usage(void);
+ virtual const char * usage_units(void);
+
+ virtual double usage_summary(void) { return usage();};
+ virtual const char * usage_units_summary(void) { return usage_units(); };
+ virtual double events(void) { return (wake_ups + gpu_ops + hard_disk_hits) / measurement_time;};
+ virtual int show_events(void) { return 1; };
+};
+
+extern vector <class power_consumer *> all_power;
+
+extern double total_wakeups(void);
+extern double total_cpu_time(void);
+extern double total_gpu_ops(void);
+
+
+
+#endif \ No newline at end of file
diff --git a/src/process/process.cpp b/src/process/process.cpp
new file mode 100644
index 0000000..dad90ba
--- /dev/null
+++ b/src/process/process.cpp
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+
+
+#include "process.h"
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <iostream>
+#include <fstream>
+#include <algorithm>
+#include <iterator>
+#include "../lib.h"
+
+
+vector <class process *> all_processes;
+
+void process::account_disk_dirty(void)
+{
+ disk_hits++;
+}
+
+void process::schedule_thread(uint64_t time, int thread_id)
+{
+ running_since = time;
+ running = 1;
+}
+
+
+uint64_t process::deschedule_thread(uint64_t time, int thread_id)
+{
+ uint64_t delta;
+
+ if (!running_since)
+ return 0;
+
+ delta = time - running_since;
+
+ if (time < running_since)
+ printf("%llu time %llu since \n", (unsigned long long)time,
+ (unsigned long long)running_since);
+
+ if (thread_id == 0) /* idle thread */
+ delta = 0;
+ accumulated_runtime += delta;
+ running = 0;
+
+ return delta;
+}
+
+static void cmdline_to_string(std::string& str)
+{
+ std::replace(str.begin(), str.end(), '\0', ' ');
+}
+
+
+process::process(const char *_comm, int _pid, int _tid) : power_consumer()
+{
+ char line[4097];
+ ifstream file;
+ ssize_t pos;
+
+ pt_strcpy(comm, _comm);
+ pid = _pid;
+ is_idle = 0;
+ running = 0;
+ last_waker = NULL;
+ waker = NULL;
+ is_kernel = 0;
+ tgid = _tid;
+
+ if (_tid == 0) {
+ sprintf(line, "/proc/%i/status", _pid);
+ file.open(line);
+ while (file) {
+ file.getline(line, 4096);
+ line[4096] = '\0';
+ if (strstr(line, "Tgid")) {
+ char *c;
+ c = strchr(line, ':');
+ if (!c)
+ continue;
+ c++;
+ tgid = strtoull(c, NULL, 10);
+ break;
+ }
+ }
+ file.close();
+ }
+
+ if (strncmp(_comm, "kondemand/", 10) == 0)
+ is_idle = 1;
+
+ pos = snprintf(desc, sizeof(desc), "[PID %d] ", pid);
+
+ if (pos < 0)
+ pos = 0;
+ if ((size_t)pos > sizeof(desc))
+ return;
+
+ strncpy(desc + pos, comm, sizeof(desc) - pos - 1);
+ desc[sizeof(desc) - 1] = '\0';
+
+ sprintf(line, "/proc/%i/cmdline", _pid);
+ file.open(line, ios::binary);
+ if (file) {
+ std::string cmdline(std::istreambuf_iterator<char>(file), (std::istreambuf_iterator<char>()));
+ file.close();
+ if (cmdline.size() < 1) {
+ is_kernel = 1;
+ snprintf(desc + pos, sizeof(desc) - pos, "[%s]", comm);
+ } else {
+ cmdline_to_string(cmdline);
+ strncpy(desc + pos, cmdline.c_str(), sizeof(desc) - pos - 1);
+ desc[sizeof(desc) - 1] = '\0';
+ }
+ }
+}
+
+const char * process::description(void)
+{
+
+ if (child_runtime > accumulated_runtime)
+ child_runtime = 0;
+
+ return desc;
+}
+
+double process::usage_summary(void)
+{
+ double t;
+ t = (accumulated_runtime - child_runtime) / 1000000.0 / measurement_time / 10;
+ return t;
+}
+
+const char * process::usage_units_summary(void)
+{
+ return "%";
+}
+
+class process * find_create_process(const char *comm, int pid)
+{
+ unsigned int i;
+ class process *new_proc;
+
+ for (i = 0; i < all_processes.size(); i++) {
+ if (all_processes[i]->pid == pid && strcmp(comm, all_processes[i]->comm) == 0)
+ return all_processes[i];
+ }
+
+ new_proc = new class process(comm, pid);
+ all_processes.push_back(new_proc);
+ return new_proc;
+}
+
+class process * find_create_process(char *comm, int pid)
+{
+ return find_create_process((const char*)comm, pid);
+}
+
+static void merge_process(class process *one, class process *two)
+{
+ one->accumulated_runtime += two->accumulated_runtime;
+ one->child_runtime += two->child_runtime;
+ one->wake_ups += two->wake_ups;
+ one->disk_hits += two->disk_hits;
+ one->hard_disk_hits += two->hard_disk_hits;
+ one->xwakes += two->xwakes;
+ one->gpu_ops += two->gpu_ops;
+ one->power_charge += two->power_charge;
+}
+
+
+void merge_processes(void)
+{
+ std::vector<class process*>::iterator it1, it2;
+ class process *one, *two;
+
+ it1 = all_processes.begin();
+ while (it1 != all_processes.end()) {
+ it2 = it1 + 1;
+ one = *it1;
+ while (it2 != all_processes.end()) {
+ two = *it2;
+ /* fold threads */
+ if (one->pid == two->tgid && two->tgid != 0) {
+ merge_process(one, two);
+ delete *it2;
+ it2 = all_processes.erase(it2);
+ continue;
+ }
+ /* find dupes and add up */
+ if (!strcmp(one->desc, two->desc)) {
+ merge_process(one, two);
+ delete *it2;
+ it2 = all_processes.erase(it2);
+ continue;
+ }
+ ++it2;
+ }
+ ++it1;
+ }
+}
+
+void all_processes_to_all_power(void)
+{
+ unsigned int i;
+ for (i = 0; i < all_processes.size() ; i++)
+ if (all_processes[i]->accumulated_runtime ||
+ all_processes[i]->power_charge)
+ all_power.push_back(all_processes[i]);
+}
+
+void clear_processes(void)
+{
+ std::vector <class process *>::iterator it = all_processes.begin();
+ while (it != all_processes.end()) {
+ delete *it;
+ it = all_processes.erase(it);
+ }
+}
diff --git a/src/process/process.h b/src/process/process.h
new file mode 100644
index 0000000..66293f7
--- /dev/null
+++ b/src/process/process.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_PROCESS_H
+#define _INCLUDE_GUARD_PROCESS_H
+
+#include <stdint.h>
+
+#include "powerconsumer.h"
+
+#ifdef __x86_64__
+#define BIT64 1
+#endif
+
+/*
+Need to collect
+ * CPU time consumed by each application
+ * Number of wakeups out of idle -- received and wakeups sent
+ * Number of disk dirties (inode for now)
+ */
+class process : public power_consumer {
+ uint64_t running_since;
+public:
+ char desc[256];
+ int tgid;
+ char comm[16];
+ int pid;
+
+
+ int is_idle; /* count this as if the cpu was idle */
+ int running;
+ int is_kernel; /* kernel thread */
+
+ process(const char *_comm, int _pid, int _tid = 0);
+
+ virtual void schedule_thread(uint64_t time, int thread_id);
+ virtual uint64_t deschedule_thread(uint64_t time, int thread_id = 0);
+
+ virtual void account_disk_dirty(void);
+
+ virtual const char * description(void);
+ virtual const char * name(void) { return "process"; };
+ virtual const char * type(void) { return "Process"; };
+
+ virtual double usage_summary(void);
+ virtual const char * usage_units_summary(void);
+
+};
+
+extern vector <class process *> all_processes;
+
+extern double measurement_time;
+
+
+extern void start_process_measurement(void);
+extern void end_process_measurement(void);
+extern void process_process_data(void);
+extern void end_process_data(void);
+extern void clear_process_data(void);
+extern void merge_processes(void);
+
+extern class process * find_create_process(const char *comm, int pid);
+extern class process * find_create_process(char *comm, int pid);
+extern void all_processes_to_all_power(void);
+
+extern void clear_processes(void);
+extern void process_update_display(void);
+extern void report_process_update_display(void);
+extern void report_summary(void);
+
+
+
+extern void clear_timers(void);
+
+#endif
diff --git a/src/process/processdevice.cpp b/src/process/processdevice.cpp
new file mode 100644
index 0000000..00f48c8
--- /dev/null
+++ b/src/process/processdevice.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "processdevice.h"
+#include "../parameters/parameters.h"
+#include <stdio.h>
+
+vector<class device_consumer *> all_proc_devices;
+
+
+device_consumer::device_consumer(class device *dev) : power_consumer()
+{
+ device = dev;
+ power = device->power_usage(&all_results, &all_parameters);
+ prio = dev->grouping_prio();
+}
+
+
+const char * device_consumer::description(void)
+{
+ snprintf(str, sizeof(str), "%s", device->human_name());
+ return str;
+}
+
+double device_consumer::Witts(void)
+{
+ return power;
+}
+
+static void add_device(class device *device)
+{
+ class device_consumer *dev;
+ unsigned int i;
+
+ /* first check if we want to be shown at all */
+
+ if (device->show_in_list() == 0)
+ return;
+
+ /* then check if a device with the same underlying object is already registered */
+ for (i = 0; i < all_proc_devices.size(); i++) {
+ class device_consumer *cdev;
+ cdev = all_proc_devices[i];
+ if (device->real_path[0] != 0 && strcmp(cdev->device->real_path, device->real_path) == 0) {
+ /* we have a device with the same underlying object */
+
+ /* aggregate the power */
+ cdev->power += device->power_usage(&all_results, &all_parameters);
+
+ if (cdev->prio < device->grouping_prio()) {
+ cdev->device = device;
+ cdev->prio = device->grouping_prio();
+ }
+
+ return;
+ }
+ }
+
+ dev = new class device_consumer(device);
+ all_power.push_back(dev);
+ all_proc_devices.push_back(dev);
+}
+
+void all_devices_to_all_power(void)
+{
+ unsigned int i;
+ for (i = 0; i < all_devices.size(); i++)
+ add_device(all_devices[i]);
+}
+
+void clear_proc_devices(void)
+{
+ std::vector<class device_consumer *>::iterator it = all_proc_devices.begin();
+ while (it != all_proc_devices.end()) {
+ delete *it;
+ it = all_proc_devices.erase(it);
+ }
+}
diff --git a/src/process/processdevice.h b/src/process/processdevice.h
new file mode 100644
index 0000000..3392d3e
--- /dev/null
+++ b/src/process/processdevice.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_DEVICE2_H
+#define _INCLUDE_GUARD_DEVICE2_H
+
+#include <stdint.h>
+
+#include "powerconsumer.h"
+#include "../devices/device.h"
+
+class device_consumer : public power_consumer {
+ char str[4096];
+public:
+ int prio;
+ double power;
+ class device *device;
+ device_consumer(class device *dev);
+
+ virtual const char * description(void);
+ virtual const char * name(void) { return "device"; };
+ virtual const char * type(void) { return "Device"; };
+ virtual double Witts(void);
+ virtual double usage(void) { return device->utilization();};
+ virtual const char * usage_units(void) {return device->util_units();};
+ virtual int show_events(void) { return 0; };
+};
+
+extern void all_devices_to_all_power(void);
+extern vector<class device_consumer *> all_proc_devices;
+
+extern void clear_proc_devices(void);
+
+#endif
diff --git a/src/process/timer.cpp b/src/process/timer.cpp
new file mode 100644
index 0000000..5d9d2f8
--- /dev/null
+++ b/src/process/timer.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <map>
+#include <utility>
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "timer.h"
+#include "../lib.h"
+#include "process.h"
+
+using namespace std;
+
+static bool timer_is_deferred(const char *handler)
+{
+ FILE *file;
+ bool ret = false;
+ char line[4096];
+
+ file = fopen("/proc/timer_stats", "r");
+ if (!file) {
+ return ret;
+ }
+
+ while (!feof(file)) {
+ if (fgets(line, 4096, file) == NULL)
+ break;
+ if (strstr(line, handler)) {
+ ret = (strstr(line, "D,") != NULL);
+ if (ret == true)
+ break;
+ }
+ }
+ fclose(file);
+ return ret;
+}
+
+timer::timer(unsigned long address) : power_consumer()
+{
+ pt_strcpy(handler, kernel_function(address));
+ raw_count = 0;
+ deferred = timer_is_deferred(handler);
+}
+
+
+static map<unsigned long, class timer *> all_timers;
+static map<unsigned long, uint64_t> running_since;
+
+void timer::fire(uint64_t time, uint64_t timer_struct)
+{
+ running_since[timer_struct] = time;
+}
+
+uint64_t timer::done(uint64_t time, uint64_t timer_struct)
+{
+ int64_t delta;
+
+ if (running_since.find(timer_struct) == running_since.end())
+ return ~0ULL;
+
+ if (running_since[timer_struct] > time)
+ return 0;
+
+ delta = time - running_since[timer_struct];
+
+ accumulated_runtime += delta;
+
+ raw_count++;
+
+ return delta;
+}
+
+double timer::usage_summary(void)
+{
+ double t;
+ t = (accumulated_runtime - child_runtime) / 1000000.0 / measurement_time / 10;
+ return t;
+}
+
+const char * timer::usage_units_summary(void)
+{
+ return "%";
+}
+
+
+
+static void add_timer(const pair<unsigned long, class timer*>& elem)
+{
+ all_power.push_back(elem.second);
+}
+
+void all_timers_to_all_power(void)
+{
+ for_each(all_timers.begin(), all_timers.end(), add_timer);
+
+}
+
+
+const char * timer::description(void)
+{
+ if (child_runtime > accumulated_runtime)
+ child_runtime = 0;
+
+ snprintf(desc, sizeof(desc), "%s", handler);
+ return desc;
+}
+
+
+class timer * find_create_timer(uint64_t func)
+{
+ class timer * timer;
+ if (all_timers.find(func) != all_timers.end())
+ return all_timers[func];
+
+ timer = new class timer(func);
+ all_timers[func] = timer;
+ return timer;
+
+}
+
+void clear_timers(void)
+{
+ std::map<unsigned long, class timer *>::iterator it = all_timers.begin();
+ while (it != all_timers.end()) {
+ delete it->second;
+ all_timers.erase(it);
+ it = all_timers.begin();
+ }
+ running_since.clear();
+}
+
+bool timer::is_deferred(void)
+{
+ return deferred;
+}
diff --git a/src/process/timer.h b/src/process/timer.h
new file mode 100644
index 0000000..7718c3b
--- /dev/null
+++ b/src/process/timer.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_TIMER_H
+#define _INCLUDE_GUARD_TIMER_H
+
+#include <stdint.h>
+
+#include "powerconsumer.h"
+
+class timer : public power_consumer {
+ char desc[256];
+public:
+ char handler[32];
+ int raw_count;
+ bool deferred;
+
+ timer(unsigned long timer_func);
+
+ void fire(uint64_t time, uint64_t timer_struct);
+ uint64_t done(uint64_t time, uint64_t timer_struct);
+ bool is_deferred(void);
+
+ virtual const char * description(void);
+ virtual const char * name(void) { return "timer"; };
+ virtual const char * type(void) { return "Timer"; };
+ virtual double usage_summary(void);
+ virtual const char * usage_units_summary(void);
+
+};
+
+class timer_list {
+public:
+ uint64_t timer_address;
+ uint64_t timer_func;
+};
+
+
+extern void all_timers_to_all_power(void);
+extern class timer * find_create_timer(uint64_t func);
+extern void clear_timers(void);
+
+#endif
diff --git a/src/process/work.cpp b/src/process/work.cpp
new file mode 100644
index 0000000..1b5c71d
--- /dev/null
+++ b/src/process/work.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <map>
+#include <utility>
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "work.h"
+#include "../lib.h"
+#include "process.h"
+
+using namespace std;
+
+
+work::work(unsigned long address) : power_consumer()
+{
+ pt_strcpy(handler, kernel_function(address));
+ raw_count = 0;
+ snprintf(desc, sizeof(desc), "%s", handler);
+}
+
+
+static map<unsigned long, class work *> all_work;
+static map<unsigned long, uint64_t> running_since;
+
+void work::fire(uint64_t time, uint64_t work_struct)
+{
+ running_since[work_struct] = time;
+}
+
+uint64_t work::done(uint64_t time, uint64_t work_struct)
+{
+ int64_t delta;
+
+ if (running_since.find(work_struct) == running_since.end())
+ return ~0ULL;
+
+ if (running_since[work_struct] > time)
+ return 0;
+
+ delta = time - running_since[work_struct];
+
+ accumulated_runtime += delta;
+
+ raw_count++;
+
+ return delta;
+}
+
+double work::usage_summary(void)
+{
+ double t;
+ t = (accumulated_runtime - child_runtime) / 1000000.0 / measurement_time / 10;
+ return t;
+}
+
+const char * work::usage_units_summary(void)
+{
+ return "%";
+}
+
+
+
+
+static void add_work(const pair<unsigned long, class work*>& elem)
+{
+ all_power.push_back(elem.second);
+}
+
+void all_work_to_all_power(void)
+{
+ for_each(all_work.begin(), all_work.end(), add_work);
+
+}
+
+void clear_work(void)
+{
+ std::map<unsigned long, class work *>::iterator it = all_work.begin();
+ while (it != all_work.end()) {
+ delete it->second;
+ all_work.erase(it);
+ it = all_work.begin();
+ }
+ running_since.clear();
+}
+
+
+const char * work::description(void)
+{
+ if (child_runtime > accumulated_runtime)
+ child_runtime = 0;
+
+ return desc;
+}
+
+
+class work * find_create_work(uint64_t func)
+{
+ class work * work;
+ if (all_work.find(func) != all_work.end())
+ return all_work[func];
+
+ work = new class work(func);
+ all_work[func] = work;
+ return work;
+}
diff --git a/src/process/work.h b/src/process/work.h
new file mode 100644
index 0000000..ddd7c87
--- /dev/null
+++ b/src/process/work.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_WORK_H
+#define _INCLUDE_GUARD_WORK_H
+
+#include <stdint.h>
+
+#include "powerconsumer.h"
+
+class work : public power_consumer {
+ char desc[256];
+public:
+ char handler[32];
+ int raw_count;
+
+ work(unsigned long work_func);
+
+ void fire(uint64_t time, uint64_t work_struct);
+ uint64_t done(uint64_t time, uint64_t work_struct);
+
+ virtual const char * description(void);
+ virtual const char * name(void) { return "work"; };
+ virtual const char * type(void) { return "kWork"; };
+ virtual double usage_summary(void);
+ virtual const char * usage_units_summary(void);
+
+};
+
+
+extern void all_work_to_all_power(void);
+extern class work * find_create_work(uint64_t func);
+
+extern void clear_work(void);
+
+#endif
diff --git a/src/report/report-data-html.cpp b/src/report/report-data-html.cpp
new file mode 100644
index 0000000..d9b713e
--- /dev/null
+++ b/src/report/report-data-html.cpp
@@ -0,0 +1,128 @@
+#include "report-data-html.h"
+
+void init_div(struct tag_attr *div_attr, const char *css_class, const char *css_id)
+{
+ div_attr->css_class=css_class;
+ div_attr->css_id=css_id;
+}
+
+void
+init_top_table_attr(struct table_attributes *table_css, int rows, int cols){
+ table_css->pos_table_title=L;
+ table_css->table_class="emphasis1";
+ table_css->th_class="table_sysinfo";
+ table_css->td_class="";
+ table_css->tr_class="";
+ table_css->title_mod=0;
+ table_css->rows=rows;
+ table_css->cols=cols;
+}
+
+void init_title_attr(struct tag_attr *title_attr)
+{
+ title_attr->css_class="content_title";
+ title_attr->css_id="";
+}
+
+void init_std_table_attr(struct table_attributes *table_css, int rows, int cols){
+ table_css->table_class="emphasis2";
+ table_css->tr_class="emph1";
+ table_css->th_class="emph_title";
+ table_css->td_class="";
+ table_css->pos_table_title=T;
+ table_css->title_mod=0;
+ table_css->rows=rows;
+ table_css->cols=cols;
+}
+void init_std_side_table_attr(struct table_attributes *table_css, int rows, int cols){
+ table_css->table_class="emphasis2 side_by_side_left";
+ table_css->tr_class="emph1";
+ table_css->th_class="emph_title";
+ table_css->td_class="";
+ table_css->pos_table_title=T;
+ table_css->title_mod=0;
+ table_css->rows=rows;
+ table_css->cols=cols;
+}
+
+
+void init_pkg_table_attr(struct table_attributes *table_css, int rows, int cols){
+ table_css->table_class="emphasis2 side_by_side_left";
+ table_css->tr_class="";
+ table_css->th_class="title";
+ table_css->td_class="package";
+ table_css->pos_table_title=T;
+ table_css->title_mod=0;
+ table_css->rows=rows;
+ table_css->cols=cols;
+}
+
+void init_core_table_attr(struct table_attributes *table_css, int title_mod,
+ int rows, int cols){
+ table_css->table_class="emphasis2 side_by_side_left";
+ table_css->tr_class="";
+ table_css->th_class="title";
+ table_css->td_class="core";
+ table_css->pos_table_title=TC;
+ table_css->title_mod=title_mod;
+ table_css->rows=rows;
+ table_css->cols=cols;
+}
+
+void init_cpu_table_attr(struct table_attributes *table_css, int title_mod,
+ int rows, int cols){
+ table_css->table_class="emphasis2 side_by_side_left";
+ table_css->tr_class="";
+ table_css->th_class="title";
+ table_css->td_class="cpu";
+ table_css->pos_table_title=TLC;
+ table_css->title_mod=title_mod;
+ table_css->rows=rows;
+ table_css->cols=cols;
+}
+
+
+void init_nowarp_table_attr(struct table_attributes *table_css, int rows, int cols){
+ table_css->table_class="emphasis2";
+ table_css->tr_class="emph1";
+ table_css->th_class="emph_title";
+ table_css->td_class="no_wrap";
+ table_css->pos_table_title=T;
+ table_css->title_mod=0;
+ table_css->rows=rows;
+ table_css->cols=cols;
+}
+
+void init_tune_table_attr(struct table_attributes *table_css, int rows, int cols){
+ table_css->table_class="emphasis2";
+ table_css->tr_class="tune";
+ table_css->th_class="emph_title";
+ table_css->td_class="";
+ table_css->pos_table_title=T;
+ table_css->rows=rows;
+ table_css->cols=cols;
+}
+
+void init_wakeup_table_attr(struct table_attributes *table_css, int rows, int cols){
+ table_css->table_class="emphasis2";
+ table_css->tr_class="tune";
+ table_css->th_class="emph_title";
+ table_css->td_class="";
+ table_css->pos_table_title=T;
+ table_css->rows=rows;
+ table_css->cols=cols;
+}
+
+/* Other Helper Functions */
+string
+double_to_string(double dval)
+{
+ ostringstream dtmp;
+ string str;
+ dtmp << dval;
+ str= dtmp.str();
+ str = str.substr(0, str.find(".")+2);
+ return str;
+}
+
+
diff --git a/src/report/report-data-html.h b/src/report/report-data-html.h
new file mode 100644
index 0000000..e506f5a
--- /dev/null
+++ b/src/report/report-data-html.h
@@ -0,0 +1,76 @@
+#ifndef PowerTop_REPORT_DATA_HTML_H_C58C116411234A34AC2EFB8D23A69713
+#define PowerTop_REPORT_DATA_HTML_H_C58C116411234A34AC2EFB8D23A69713
+
+#include <string>
+#include <sstream>
+
+using namespace std;
+
+struct tag_attr {
+ const char *css_class;
+ const char *css_id;
+};
+/* T:Top, L:Left, TL:Top-Left, TLC: Top-Left-Center */
+enum position { T, L, TL, TC, TLC };
+
+struct table_attributes {
+ const char *table_class;
+ const char *td_class;
+ const char *tr_class;
+ const char *th_class;
+ position pos_table_title;
+ int title_mod;
+ int rows;
+ int cols;
+};
+
+struct table_size {
+ int rows;
+ int cols;
+};
+
+
+/* Definition of css attributes for the cases that apply to powertop
+ * html report
+ * */
+
+void
+init_div(struct tag_attr *div_attr, const char *css_class, const char *css_id);
+
+void
+init_top_table_attr(struct table_attributes *table_css, int rows, int cols);
+
+void
+init_title_attr(struct tag_attr *title_attr);
+
+void
+init_std_table_attr(struct table_attributes *table_css, int rows, int cols);
+
+void
+init_std_side_table_attr(struct table_attributes *table_css, int rows,
+ int cols);
+
+void
+init_pkg_table_attr(struct table_attributes *table_css, int rows, int cols);
+
+void
+init_core_table_attr(struct table_attributes *table_css, int title_mod,
+ int rows, int cols);
+
+void
+init_cpu_table_attr(struct table_attributes *table_css, int title_mod,
+ int rows, int cols);
+void
+init_nowarp_table_attr(struct table_attributes *table_css, int rows, int cols);
+
+void
+init_tune_table_attr(struct table_attributes *table_css, int rows, int cols);
+
+void
+init_wakeup_table_attr(struct table_attributes *table_css, int rows, int cols);
+
+/* Other helper functions */
+string
+double_to_string(double dval);
+
+#endif
diff --git a/src/report/report-formatter-base.cpp b/src/report/report-formatter-base.cpp
new file mode 100644
index 0000000..4e10603
--- /dev/null
+++ b/src/report/report-formatter-base.cpp
@@ -0,0 +1,114 @@
+/* Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ *
+ * Common part of report_formatter_csv and report_formatter_html.
+ * Written by Igor Zhbanov <i.zhbanov@samsung.com>
+ * 2012.10 */
+
+/* Uncomment to disable asserts */
+/*#define NDEBUG*/
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdarg.h>
+
+#include "report-formatter-base.h"
+
+/* ************************************************************************ */
+
+const char *
+report_formatter_string_base::get_result()
+{
+ return result.c_str();
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_string_base::clear_result()
+{
+ result.clear();
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_string_base::add(const char *str)
+{
+ assert(str);
+
+ result += escape_string(str);
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_string_base::add_exact(const char *str)
+{
+ assert(str);
+
+ result += std::string(str);
+}
+
+/* ************************************************************************ */
+
+#define LINE_SIZE 8192
+
+void
+report_formatter_string_base::addv(const char *fmt, va_list ap)
+{
+ char str[LINE_SIZE];
+
+ assert(fmt);
+
+ vsnprintf(str, sizeof(str), fmt, ap);
+ add(str);
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_string_base::addf(const char *fmt, ...)
+{
+ va_list ap;
+
+ assert(fmt);
+
+ va_start(ap, fmt);
+ addv(fmt, ap);
+ va_end(ap);
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_string_base::addf_exact(const char *fmt, ...)
+{
+ char str[LINE_SIZE];
+ va_list ap;
+
+ assert(fmt);
+
+ va_start(ap, fmt);
+ vsnprintf(str, sizeof(str), fmt, ap);
+ add_exact(str);
+ va_end(ap);
+}
diff --git a/src/report/report-formatter-base.h b/src/report/report-formatter-base.h
new file mode 100644
index 0000000..e35a2ff
--- /dev/null
+++ b/src/report/report-formatter-base.h
@@ -0,0 +1,52 @@
+/* Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ *
+ * Common part of report_formatter_csv and report_formatter_html.
+ * Written by Igor Zhbanov <i.zhbanov@samsung.com>
+ * 2012.10 */
+
+#ifndef _REPORT_FORMATTER_BASE_H_
+#define _REPORT_FORMATTER_BASE_H_
+
+#include "report-formatter.h"
+
+class report_formatter_string_base: public report_formatter
+{
+public:
+ virtual const char *get_result();
+ virtual void clear_result();
+
+ virtual void add(const char *str);
+ virtual void addv(const char *fmt, va_list ap);
+
+protected:
+ void add_exact(const char *str);
+ void addf(const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+ void addf_exact(const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+
+ virtual std::string escape_string(const char *str) = 0;
+
+ std::string result;
+};
+
+#endif /* _REPORT_FORMATTER_BASE_H_ */
diff --git a/src/report/report-formatter-csv.cpp b/src/report/report-formatter-csv.cpp
new file mode 100644
index 0000000..0360fd8
--- /dev/null
+++ b/src/report/report-formatter-csv.cpp
@@ -0,0 +1,163 @@
+/* Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ *
+ * CSV report generator.
+ * Written by Igor Zhbanov <i.zhbanov@samsung.com>
+ * 2012.10 */
+
+/* Uncomment to disable asserts */
+/*#define NDEBUG*/
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdarg.h>
+
+#include "report-formatter-csv.h"
+#include "report-data-html.h"
+
+
+/* ************************************************************************ */
+report_formatter_csv::report_formatter_csv()
+{
+ /* Do nothing special */
+}
+
+/* ************************************************************************ */
+void
+report_formatter_csv::finish_report()
+{
+ /* Do nothing special */
+}
+
+
+string
+report_formatter_csv::escape_string(const char *str)
+{
+ string res;
+
+ assert(str);
+
+ for (const char *i = str; *i; i++) {
+ switch (*i) {
+ case '"':
+ res += '"';
+#ifdef REPORT_CSV_SPACE_NEED_QUOTES
+ case ' ':
+#endif /* REPORT_CSV_SPACE_NEED_QUOTES */
+ case '\n':
+ case REPORT_CSV_DELIMITER:
+ csv_need_quotes = true;
+ break;
+ }
+
+ res += *i;
+ }
+
+ return res;
+}
+
+
+
+
+/* Report Style */
+void
+report_formatter_csv::add_header()
+{
+ add_exact("____________________________________________________________________\n");
+}
+
+void
+report_formatter_csv::end_header()
+{
+ /* Do nothing */
+}
+
+void
+report_formatter_csv::add_logo()
+{
+ add_exact("\t\t\tP o w e r T O P\n");
+}
+
+
+void
+report_formatter_csv::add_div(struct tag_attr * div_attr)
+{
+ add_exact("\n");
+}
+
+void
+report_formatter_csv::end_div()
+{
+ /*Do nothing*/
+}
+
+void
+report_formatter_csv::add_title(struct tag_attr *title_att, const char *title)
+{
+ add_exact("____________________________________________________________________\n");
+ addf_exact(" * * * %s * * *\n", title);
+}
+
+void
+report_formatter_csv::add_navigation()
+{
+ /* No nav in csv - thinking on table of contents */
+}
+
+void
+report_formatter_csv::add_summary_list(string *list, int size)
+{
+ int i;
+ add_exact("\n");
+ for (i=0; i < size; i+=2){
+ addf_exact("%s %s", list[i].c_str(), list[i+1].c_str());
+ if(i < (size - 1))
+ add_exact(";");
+ }
+ add_exact("\n");
+}
+
+void
+report_formatter_csv::add_table(string *system_data, struct table_attributes* tb_attr)
+{
+ int i, j;
+ int offset=0;
+ string tmp_str="";
+ int empty_row=0;
+ add_exact("\n");
+ for (i=0; i < tb_attr->rows; i++){
+ for (j=0; j < tb_attr->cols; j++){
+ offset = i * (tb_attr->cols) + j;
+ tmp_str=system_data[offset];
+
+ if(tmp_str == "&nbsp;")
+ empty_row+=1;
+ else{
+ addf_exact("%s", system_data[offset].c_str());
+ if(j < (tb_attr->cols - 1))
+ add_exact(";");
+ }
+ }
+ if(empty_row < tb_attr->cols)
+ add_exact("\n");
+ empty_row=0;
+ }
+}
diff --git a/src/report/report-formatter-csv.h b/src/report/report-formatter-csv.h
new file mode 100644
index 0000000..7edfc01
--- /dev/null
+++ b/src/report/report-formatter-csv.h
@@ -0,0 +1,73 @@
+/* Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ *
+ * CSV report generator.
+ * Written by Igor Zhbanov <i.zhbanov@samsung.com>
+ * 2012.10 */
+
+#ifndef _REPORT_FORMATTER_CSV_H_
+#define _REPORT_FORMATTER_CSV_H_
+
+#include <string>
+
+#include "report-formatter-base.h"
+
+/* Offices like semicolon separated values instead of comma */
+#define REPORT_CSV_DELIMITER ','
+
+/* "a,b,c" vs "a, b, c" */
+/*#define REPORT_CSV_ADD_SPACE*/
+
+/* Whether to escape with quotes empty cell values */
+/*#define REPORT_CSV_ESCAPE_EMPTY*/
+
+/* Whether to escape with quotes empty cell values with spaces */
+/*#define REPORT_CSV_SPACE_NEED_QUOTES*/
+
+using namespace std;
+
+/* ************************************************************************ */
+
+class report_formatter_csv: public report_formatter_string_base
+{
+public:
+ report_formatter_csv();
+ void finish_report();
+
+ /* Report Style */
+ void add_logo();
+ void add_header();
+ void end_header();
+ void add_div(struct tag_attr *div_attr);
+ void end_div();
+ void add_title(struct tag_attr *title_att, const char *title);
+ void add_navigation();
+ void add_summary_list(string *list, int size);
+ void add_table(string *system_data, struct table_attributes *tb_attr);
+
+private:
+ void add_quotes();
+ string escape_string(const char *str);
+ bool csv_need_quotes;
+ size_t text_start;
+};
+
+#endif /* _REPORT_FORMATTER_CSV_H_ */
diff --git a/src/report/report-formatter-html.cpp b/src/report/report-formatter-html.cpp
new file mode 100644
index 0000000..387bd76
--- /dev/null
+++ b/src/report/report-formatter-html.cpp
@@ -0,0 +1,376 @@
+/* Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ *
+ * HTML report generator.
+ * Written by Igor Zhbanov <i.zhbanov@samsung.com>
+ * 2012.10 */
+
+/* Uncomment to disable asserts */
+/*#define NDEBUG*/
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdarg.h>
+
+#include "report-formatter-html.h"
+#include "css.h" /* For HTML-report header */
+
+/* ************************************************************************ */
+
+#ifdef EXTERNAL_CSS_FILE /* Where is it defined? */
+static const char report_html_alternative_head[] =
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" "
+ "\"http://www.w3.org/TR/html4/loose.dtd\">\n"
+ "<html>\n"
+ "<head>\n"
+ "<title>PowerTOP report</title>\n"
+ "<link rel=\"stylesheet\" href=\"powertop.css\">\n"
+ "</head>\n"
+ "<body>\n";
+#endif /* EXTERNAL_CSS_FILE */
+
+/* ************************************************************************ */
+
+static const char report_html_footer[] =
+ "</body>\n"
+ "</html>\n";
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::init_markup()
+{
+ /*here all html code*/
+}
+
+/* ************************************************************************ */
+
+report_formatter_html::report_formatter_html()
+{
+ init_markup();
+ add_doc_header();
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::finish_report()
+{
+ add_doc_footer();
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::add_doc_header()
+{
+#ifdef EXTERNAL_CSS_FILE /* Where is it defined? */
+ add_exact(report_html_alternative_head);
+#else /* !EXTERNAL_CSS_FILE */
+ add_exact(css);
+#endif /* !EXTERNAL_CSS_FILE */
+}
+
+/* ************************************************************************ */
+
+void
+report_formatter_html::add_doc_footer()
+{
+ add_exact(report_html_footer);
+}
+
+/* ************************************************************************ */
+string
+report_formatter_html::escape_string(const char *str)
+{
+ string res;
+
+ assert(str);
+
+ for (const char *i = str; *i; i++) {
+ switch (*i) {
+ case '<':
+ res += "&lt;";
+ continue;
+ case '>':
+ res += "&gt;";
+ continue;
+ case '&':
+ res += "&amp;";
+ continue;
+#ifdef REPORT_HTML_ESCAPE_QUOTES
+ case '"':
+ res += "&quot;";
+ continue;
+ case '\'':
+ res += "&apos;";
+ continue;
+#endif /* REPORT_HTML_ESCAPE_QUOTES */
+ }
+
+ res += *i;
+ }
+
+ return res;
+}
+
+
+/* Report Style */
+void
+report_formatter_html::add_logo()
+{
+ add_exact("<img alt=\"PowerTop\" class=\"pwtop_logo\" src=\"data:image/png;base64,"
+ "iVBORw0KGgoAAAANSUhEUgAAAbQAAABDCAYAAAD01PBTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA"
+ "GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAGsxJREFUeNrsXQt4FNXZ/nLhmutq"
+ "VdAKMXJHTMhiLGAuLUEfSg2xSFSUgIkkRPQ3QiHxqcRwswQrRq2EBKjhapvU3yCgtaQ+CRGUSyAB"
+ "vNDfRhArqEA2FwjksvnPN0xokpnZPWd2dnd297w851kyt3OZ+c4773e+c8aro6MDODg4ODg4XB3e"
+ "vAk4ODg4ODihcXBwcHBwcELj4ODg4ODQDr68CWxCrPgbTlJwj33l4m81SSbeVBwcHBz2hRcPCqEG"
+ "ElaCSGKYBldXV4PJZILO325MF3uN68LDwyE4OLheJLjOVM2bk4ODg4MTmqMxB4mMENa08vJyKC0t"
+ "FQispqaG+gKDBw8WiA1JLiEhAUJCQk6TzXkklZJ0ijcxBwcHByc0e6qxDEyExILy8vJgx44dml08"
+ "LCwMMjIyBHIj6m0T2ZTDiY2Dwz3xzsEbM3tsWkV5ahVJJV3/fizyQhlvURsJzcvLaw/5iXNQmcrE"
+ "dP1vUsYqRzUIyQuJLKeoqCho6dKlcPr0abvlFRQUJBDbc88910lsGaStVY23kfMyGQwFcQOpa52K"
+ "fIrJzwwVRVSbXwH5SdU6Hwc/0ywoIeVP1FHZe3aqNtsj6eDVPkMOvxeEQBJV1A+fVyPjc8uCWpIK"
+ "8V6Q8mnaN5KyO7Wvt7U+egwKievZoMSAQTQqNPYSe2Ta3t6OgR1FFRUVYcnJyXYlsk7U19cDkiYq"
+ "wOzs7NmE2HCMbo6Pj0+pyoeDBaFiZwUqzlMDo4oysuZXpYY0dQa9ld8oJi3t0eAi96JWhRJb5YBy"
+ "hXbmQ/JEG84lRFDigs+6pK8n9bn+bKmpkyuF7eMbXTExpsMkGTUls7b2DFOd6eiC5xeETZo0iZrM"
+ "vG+6EXxHD4e+UydD34d+DYFD7oDFixZD9pJsiI+Ph+joaGpiW7hwIURERATVVNe8R8pTSlIwo7Ks"
+ "YuwMbSEmR57HUk53cMfUuqA9xtnxnur+5YJ0wjNIuuggMpOzq2JUViSFgntghlinwyQx9RuuGLaP"
+ "FUQjSiOdeKGtF2trayuqqamZPX36dKtE5tW/H/SOjIBe946FXqNHgJdf/277J9x4C6yceL/kPKL6"
+ "hITjcMeOHVO8Pu4zjjPCxo0bpyUlJZWTss3x9fVliYisZSAO5offxhcJNfkZWBWaGxhznQva4x5G"
+ "ezS4y73QkfsUXyr+TcqT6KJqTbGvJ3VKI3WierZceWJ1ATEi1Q9Sa2trMEnVmzZtmm1NlaEK83sm"
+ "BQxb3gK/Z1MEUutJZohdsVNRKUkSKrUlS5bA4cOH4dChQzBr1iyLZUtJSYHk5OQwcm45KWO4nRSK"
+ "GnIKtfHhtHd+tW5gxHUeYI8u73IknawBFQTobyywWCYIxdVRgCrY3QkNsUp8i2fC1atXg81mczkh"
+ "s7CnnnpKcPnJwSfkdghYthgCl2VCn19OpLo2ua7FNGbMGFi/fj2cPHkSnnjiCcXrbNmyBUkt6MKF"
+ "CxWkvLSkxqJQ1JCTLQrNqOJesZSxzpHBQ5zQFEnNYEXRhLrJvdhjoz3YtV90Q1LDOlntP1yd0NA4"
+ "mCOJUPls3rw5bO7cubL70bXY/8nHIOjVpYJrkRY/f2CSrEKTS4MGDRKI7aOPPhL+L4etW7dCampq"
+ "IJb3ypUrNKRWxth2jlRoas73tPEzV1eZBgp7dHlCIx3rKh2TWVcCMIL7gKqvd4elr7CSubQHNzc3"
+ "FxH1E5aWlqaoyvyfSQGfOwYxF+TurOeBdV5fVFQUHDhwABYtWiQQWE/s3LkTCPEGFRYWlpKyh/fr"
+ "189kgajryBtyFaWxGcixoeQclg7UVgOJY1SRLIquyk0M19WjNDOt2KOruBvhscgLtTJkNkOsIyuu"
+ "h6iT61L1VySvuC42pybgBN2P40h+dW5iG1b7endYnDiUNlih+fLljGM1NbORPGTZffRwwb2ohswQ"
+ "x1a9hqzCnIICA6GwoABW5+YqKrWVK1YMJseWUhqO5gSlIkDD0QrNHcbPwA2mHRisRD26ekAIK7Gg"
+ "PSKpTEYioyUzkfjKOs8hCedKZNlD1bhSX29NdWqt0GqJQd6p9mRiCGonJFp987906VJ4fX39a4mP"
+ "PAINDQ3ShhgxVCAztWg5eAQufvRP2Lxli8WxMUt4ev58CAwKgnnz5kn2rXz5ZbgvKiqGKLocPz+/"
+ "HI069lA7HauVwjMydhz2gE3PtJPhLHu0NOewhDZiTUG10E78rSX5aHrfxHEpFjtAIsrSKn8kNlIG"
+ "bNdihnJkknMK7aDSbGpfGyafW+zrdaXQMOyXJPQFTtb6TZ5ctyg1NRW+/fZbyb7ekWMhcOULcHF6"
+ "Mlx6c6MqMmvK/ZPwfySjlStXUo+l9UyPP/44rFu3TjYfdJOaTKaXmpqaLI2n2SswRAt/vFHr+9pZ"
+ "ZzdQNnpUi532OE6r++zi7i+WzrdESzLr0n5o34lA75o2gA5VGr7UkKR5X++tU0MqY5TXFivZ2NiY"
+ "sXfv3rDdu3dL9uGYGYbkC41x041wtXwfM6m1f3Om29+VlZWqCQ3TzJkzIT09XZIPkrFIlnkW2o5l"
+ "grWjFRr1XDYc39OBOuP47zOV5ehnRU8QFQVtvdBLkmZHMhBWB2E4JZMmQtBJxKZpX6/nMTRNIvYa"
+ "GhqCiUHmyLnxMJoRA0A655T1eyRB+EVS06ATsCmtWrUK7rrrLsl18/PzcQJ2DKlXggZtx6KYtIqY"
+ "itPiwe0Brs7sj0KtOh0XBctqKLn2VqLiWBzt8IIB9LluqaZ9va4JjVFpKL59mM3mjK1btwadOXNG"
+ "sg8JrGsACM41w3lnmNS6HzvJzNp8NJq0bds2CAwMlL5uZWbi/jwLRaB1OxoY5obREFqhLffKhk6R"
+ "KzT722MdYwfqTuoM60M7gRrbyVErdbCoNN0uBi0qzjotni29RznaVElTXV0wscQMVDs9IazB+Bup"
+ "+xbnnWFS637s0gPYnAbdfrus63Hfvn1w/NixwaR+sRp08FaJSiQ9a51ULWW+Wis0d5lQ7QqgDjhi"
+ "dBm7kzordOA4YQlDHxmn8zb2CEKzKRSbcELCrt27FdTZNIvn+o4aDv0DfFW7H63x1enT38LsJ5+A"
+ "hYueB5OpXvG4zMWZcDshtp7Iz1+H+zM0ULc0HQ+NOquivF+hGpaLRY1ycKgFi7vdYc+jSJy0L68G"
+ "nU+01mTajbc7P4XmDnPG9u3bZdWZpRVAmtIXQEvFfrjc2Cb83Tx7LpNSE1yOHWbF9Ld3/wbhY8Ph"
+ "/R0fwJ83boKhw4fA8RPHFY9fvHix1A3yl3egzlQ37cKFCyE2PiCaERolkRooA0M4oXG4IqE52v1d"
+ "Zad6uCTcltDOnz8fYjKZwj788EPJPjlXYyda8wuh5cfui3FcudTO7H60FPDxcu6ybse2tbbDbx+O"
+ "Vzx+ypQpsmNpH3zwAe5PsNGwQjU6poohX05oHO5IaFVOmJZg7/VbOaFpCNWDy9jRY4cvqfBNNwqr"
+ "5cuec+kyNH18QOZa135Z3I+WCO3KlSuS4y/8VA9r89+QPR7JDEmtJ3AaAtkfa+ODbtTomCqGfC0a"
+ "FuWYnbPeiDk8CGJACO2z6IzVatyF0DQJJNI7oVEHBsgQSiwGT/SEEpkhWt4qgA6zdC3GXgZ/5uhH"
+ "S4Q2zig/T/WVV/6oeM6jjz4qOX7//v24b5oOFFrXic00BmbU6L7X8gnVurRHWZv0gDo7nNAYFWGo"
+ "G7RznUsSmjjOYlBbyQ6zOVyO0PDjnEq4cvQL2e39lyy6Hv3YqdQskZpAQmazYtpQ8Db06dtbcl5T"
+ "YzMc+Owz2XPG/+IXErcjLuF1/Phx+OHcuViZMtTRvr1ZGtMSo9UMDIasBaFRu3gcYWikDTo0Tv92"
+ "tV6ddS1PN3rRYFEOzqqzS0+nEINVDFq0sZ4VWpzaG3ru7Lng+vqGwd99952U0BSCQVqPHIP2lnYp"
+ "mYUOBJ/B/40yxFVFOkP6LRu05ZS5SH5y/Btr1yieM2H8BMnxJ46fwH3hdlRpLO5GWiK1FhhC+3Dz"
+ "8TPHIVWtPXJVqhtC06tCi9OqrrokNHG17lVqK0n0UThGDfYELnOlSEAywSMCAT7TfYURnHwdvO4V"
+ "q+7HDiv/5qXPIyqtl+S8z/YfVDxn9F2jJcef+e4M7gu244NOYwRlKog0VAPD4+NnLmCPHBwW1Jmm"
+ "z5avzgxH7QrMtT3cHcFyX6H2uflnihdo/Uaq5nz6+HZTZ3JKD5WaHFHSfBfNeM9Y2F95sNs2dDsq"
+ "nTtq1CipQjtxQovAEFsVWq2KfPG6JbYQGp9QrVt79NT7wsdz6YlMk77e3oQmjDc4oX26vambzeZw"
+ "7OilCk35O2ftzS2SbX1uu8lipuh+bP5rKbSfOiMhM1y6yhrGR0ZJCA3x+eefw8iRIyXbAwICJNuQ"
+ "uJXywg6f3A80MmsuPKMNaklupXtbIx1Zpglw6M8e3aljd6cxNCSSULkPl6p5tsi1nN7X94Q7zEOT"
+ "Ln3Uwd7ObVdapY1z60CL53S6H/slTpNjE6vp3shI2esKwSwyx1++dElJqqh+ADRQaFUyRFpLYdxx"
+ "CqqANviAuxv1ixLeBBz26OvFdR/dmtByZTpU2U6+7V/Xgstw7Kvr+JfSOFjTJ0fAGGCAvuu2XD8H"
+ "/4/buv49sE/fbuc1trVC0rPz4fZBg4R0qOFit7/x/7gNPzYqh+J3C8F09RA8k5F0/Rz8+72dm2S4"
+ "rM2ae5NGyRjk1t6jXNGjViXhGBTW++MTql0bZeILDQeH3fv6nvB18QqiCiiUIzS5Lv6p8VGQZfwV"
+ "wKlT3XcU/QoGh4RIjn/44Yfh1WFjAda/Lb1Yl2u8lpcHXZe+P9ncBGeTHoIbSBLyPXkEoMvfNeI2"
+ "DCxpzF4tufT0+U1w/OJceCQTSLpB2IZ/j/9tO+z43x6kAz7WCI3lUzK1KsilzALhzLBTnpzQXLjT"
+ "ccE+hhbOCounjl7UyN2om77e3RRamtx8F7O5Q7aT7927t7BPLvn28pEc/58fvlE8vmvq6NDWlezn"
+ "L39bmhqlY2UdYn2VwLBQcagC4ViEhcAMtUtg0RhnHVcBukSJ+HFeT4WBPwL26+tpJpG7skJDMpP1"
+ "1ROKMckFUOBEZHntBsJE57bW5m7bTn75teLxWqDtxEnZ7YOH+TBdh6KMtRTkZFBBLlVW8lRDojSd"
+ "giM7TVyN5E7en1Ap5jTeDBx2IjOqcVlvFzWcyaSTKbSgGqrlQty/+OILxaWlQkJ/Ljn+4vl6IYqQ"
+ "5gvTatBy8Ihk288GKN+S0/+STvzGaEisrwYEYFSh0Mos3AOaCdZxKhUadzfqT5mNc9NlyFg8AXp3"
+ "ObqaV0Po6wmZUX8t3ZUIDRk6UTQcix10h9lsuvXWW+UJTWE5qrFh8usrrs1/0+IyVpjURFWafzwv"
+ "CfdHjDL2YiK0QKJEsb4aEEA38qKMNrTWgdEEhhgYSZQTmn5QJr5cJrpxHd1pDM1VXjiEvp4Q2TiS"
+ "mLwxenQ5VkH3sN8y1gm0dw4ZUi2nmhobGwGXw7rtttsk+57/n4WwdfM7ku2bijbD4t9lWcyvZ07e"
+ "fv2tlrH5rztkt4+L6QW+XkHg7dUbWsw/9SC0NsnxkZGRqIbKNVBoArl0ecvWInSe5r7F9bjfXKHp"
+ "u3PPFRV4rofUmUXVOHxpKfFrAPaoi1P6emth+Y4mNN2MN5ByVJDOPubgwe4Tl/+xZw/MmT1bcjyO"
+ "ud12+83wnzM/dtve0tIGz2akwxuvrVXMa3ZSEuwh1/3qq6/Aq38/+XlpXdD6+Veya0Giu3FcTG9o"
+ "66i/zpLeXn2IjO4DZ783wen/kyq0ESNGWHU5IkkRsqoCulXuq7oQjcXOjeJFg2kOnEIYv8QI+Ar7"
+ "2tgjae/DQL8QdC65VpanNSAGIhDSoFmcwCmEBmwf7dSS0GpJ2+hubNltP/BJBFp5pMzE5bI9ZYpz"
+ "nRc+L2+vf//gn1BcXKJ4XkBAIOwovaa4DFveAp87lFckEb65tupN2X0xv+kj2WbuuEoIrgEOV7TI"
+ "khnJu2bosGEmiiZhHUcz2GocIvHUMeTJJ1Q7FolA74bKJASY6aHtRP1tQUbF5MqEpku4LaGZO8zl"
+ "kyZNkmw/eOigsKAv2S9J+BHNmwfcIHu9l3KyobyiXPa8zmS1gydk1pCdCx2Xm2XV2ZRH+yqeu3fX"
+ "Vck2JGysp4YPcyiDodASSxmDQYZyo3SoFwPbkiUycRXlZHtPJTQaz4YzCc3tXfVuS2hEvZQPHz68"
+ "Xi445L333lOMVixc92d0xUjOaW83Q1paGixd/pLiuX1iJyqWB92MpnmLZANBEEkL+kP/AC/ZfV8c"
+ "aZV1NyYkJGC+RRo+zCyEVqtRvqFdAkMM3CgdTmo4hsEyHlYsE8jDCU0dwdgEUQ3SEmidreNTnNCc"
+ "b61FD5FOvyc2b94MjQ0Nsv7DYUOHQnJKkuIl/7K9GGIIcVWUl0vO9Xs2RaoUfzwvLK2FK4LIKTNE"
+ "9NQ+wtiZEt5dLz2PkDWMGD789MiRI6vpmoJqgrVAaGKHZdDIyGmUXBxlZ1DHV9i3C6llAduXGfZ4"
+ "WBOxuLlTHeh2nAH0kZUe4ar3dnNDzZs1a5ZkO0Y7biKkpqS0FmQsgphfjle87k8/1kH600/DveMj"
+ "IWPhs1BOyA2jJ3FtR3Qrohq7smsPNOW+Cab0xRY/BjoywhfmZfsp7kd19uURaXRjEqkXgzqjfaiN"
+ "WhML5XGhMgrRY43SSWAZTzOSl55VntIw4goVtAsuG8D6km9agWVM0yMWjHZrQhs1evQpPz+/imnx"
+ "8ZJ9a9euFeal4adX5NKfXi+AyPFjLV6/seES/OPvH8PT8+fD/Q88cK2nT3pGUGOX334HWg4etXj+"
+ "4KG9YOHqAIvHbFlzWbIN3ajx8fH1pJx5WrtOxDESo63XYTzeSElofPzMfi9/rONpGCQyw4OaiOVl"
+ "KtPeKk38nhjL/DOu0NzDUCEnPf1p2X0vLlli8QsvG9ZtggcT7rdLudDN+IetAeAfoBwIgq5GubGz"
+ "9HnpWL68u8aMMdnBKEPBtiWv1OQbqrGbk0MdqbGOpxV4SpCIuFoFyxfgC+xIZnh9FoWcS7MOIic0"
+ "F8CYu8eUDxw4cMe8efMk+06ePAm5q3MtLmm1IucVWJ27Gvr2661Jefr7e8GC1f7X3YxmuCrMM+sJ"
+ "dDW+u0E6djZw4ABBnaE7VUWHRTuO5gyFRtMxcpej/UmNZTwNX0A8KUiEhexnEOLR3C1Lrol2sgfY"
+ "ViXxmO/TeXuEkUJHxsyZMxsIsUn2bdu2DXa8v0NY4Ffp3/0P3A+ffXoQ4hN+Db16+6gqAxLZ9Kf6"
+ "wRulwZIAkJ6k9tNZM6xZ1CR7neXLV2CZcu4Ou9uksjmsvWXOAO1dfzREZG08wFkTqoWvPjswFevA"
+ "ZFjG0+yqRlxYpQnPNCGgPSIJaUFm6GY8DGwTuLNc+JMxzPD1hEqGhYWdqj569LVlS5e+NDc1VbI/"
+ "OztbWJMxXmasrSuWZq8QEob9by/eBKe/+R5aW9oskhiS16gIX4iWmTQtR2pNjVcImTXC5Sbp0l2E"
+ "lMEYEVFB6pNnQ3OUWVFDmkcaiiuV1FoxRGvhx55ilE53DeF4GrlfOJ5GS64zcNK1hyyHlcXQLp3P"
+ "9WFCRmWdL3aEYKjaSSTCTrtQo/bQZgrBg+DrKRUNHzs2hxhcbFpqakxBofQev5STI6w2Ff/gg1av"
+ "hfO/ErpMB0CCu9zcDLs/fh0eTu0nbAsZ6qs4r0wJP5xtJmR2SXbcbOiwIfC7hQvR1TjHxqawdRyq"
+ "zIZ8Q51YbleBLogbx9MISeUCfSQdTrquVfqkkxuptBJCNCzt0pXY4kSiclSEaKKnjJ11wtuTKkuM"
+ "LSE1NbU+NiZGdn8OITV0QdJ8LqZrQnKb+dhjkL0ukKixXkJiJTNcSf+FJ+oJmbVK9vn794c1f1yD"
+ "ec0ZGxFxykmEZGuHW+XkcnOFxm4vWYz3rYByPU5XJ7Us0P8LVpYnTKT2aEKLMBpNqNKys7MbcAK1"
+ "HF5dswYWLFx47WOgjMS2btklVeXCaMYXZtXLuhn9/PtCYcF6GDhw4FJS/lINOqk6G41R7bm2EJIn"
+ "TajW2xs1y3iaJwWJTNYxqWXRujU5obk4jOPGVfv7B8zOz18HQxVIraKiAh6Mj4f3398JZnMHddq7"
+ "+ypTWTCSEVWZXDTjNTLrAwX5G2DIkKGbSLlzNGwGW8hFlRFTRlhqrQo5odn+AsQ6Pw3Hfdw+SARd"
+ "efi9LtBfBGGip5KZRxIa4p7Ie0oDAvyfXJef3xARESF7TFNTEyxbvgymTYuHXbt2wrXvuVhLdED3"
+ "Iqq5FemNsuNlCH9/P4HMhg0buomUd47GTaCWIOrEDs7R+XpSuL7uyFvF/LQZnrIyPyGPREYVay+g"
+ "jdyJY3zgwfD21IrfExlZ5O/vH5O/dm391KlTFY87e+4cIbblED9tGhSuXy/MXVNyOW4/cIPidS43"
+ "dggr5i9PbxDci5bUHCrHrVu24u9SUs45dqi+M9yGtpzvSWMBuhzEVzGehkEicZ5ww5BESELjd8b3"
+ "4qpEVTbZk8LzleDryZWPvPfe6s8+/TT2xd//vig6Kips+YoVgjKTwzlCbBs2bBDSgAEDAJUdjsN1"
+ "ui2HDRsGH354RfgEDCqwS01mOP+9GU6R/3+psFq+HB5JTISUlJSGgICA2aR8pfaoN7r/SGdD+9FC"
+ "LYnFWUTqMtD5x0tRiRxmeG5wPC2R1Mkj7p/o6ssV54uh6zXVjioeQ7XLPDHwwxK8UFl4Oj7dvz+Y"
+ "/OScPXv2ubzXX4fKykqHlwFJ8sUXX4SIsWNryJ8J4ydMOMUfTw4O1wchuK7uV3wZoHXH9pxHVkUI"
+ "jK+WwwmNDvv37YslP0VHjx4dvHHjRjhaXW33PP38/SAlOQWVWT2S6oSJE/P4neDg4ODghKYJ9n2y"
+ "bw6SCxJbcXExVH6ivWJDRZacnAzRUdHg7+//OuY38b6JJt76HBwcHJzQNMcnlZVIbBnnzp0L21tZ"
+ "Kbgiq21QbbcMuBmi74uGKVOm4NjbaVSDJOXdFxXFiYyDg4ODE5r9Ubl3bwj5QXLD9a7C0BVZffQo"
+ "NDY1wddffy0c0yT+f8Att8AAcRFkorxg6JAhMIQkDB4hqgxJrJyk0qjo6FLeshwcHByc0JyGvRUV"
+ "GEASTlIsSSFiQuD2MJJwLKxTxpnE/wspOibmFG9BDg4ODk5oHBwcHBwcivDmTcDBwcHB4Q74fwEG"
+ "APNNNssrHc8WAAAAAElFTkSuQmCC\">");
+}
+
+void
+report_formatter_html::add_header()
+{
+ add_exact("<header id=\"main_header\">\n");
+}
+
+void
+report_formatter_html::end_header()
+{
+ add_exact("</header>\n\n");
+}
+
+void
+report_formatter_html::add_div(struct tag_attr * div_attr)
+{
+ string empty="";
+ string tmp_str;
+
+ if (div_attr->css_class == empty && div_attr->css_id == empty)
+ add_exact("<div>\n");
+
+ else if (div_attr->css_class == empty && div_attr->css_id != empty)
+ addf_exact("<div id=\"%s\">\n", div_attr->css_id);
+
+ else if (div_attr->css_class != empty && div_attr->css_id == empty)
+ addf_exact("<div class=\"%s\">\n", div_attr->css_class);
+
+ else if (div_attr->css_class != empty && div_attr->css_id != empty)
+ addf_exact("<div class=\"%s\" id=\"%s\">\n",
+ div_attr->css_class, div_attr->css_id);
+}
+
+void
+report_formatter_html::end_div()
+{
+ add_exact("</div>\n");
+}
+
+void
+report_formatter_html::add_title(struct tag_attr *title_att, const char *title)
+{
+ addf_exact("<h2 class=\"%s\"> %s </h2>\n", title_att->css_class, title);
+}
+
+void
+report_formatter_html::add_navigation()
+{
+ add_exact("<br/><div id=\"main_menu\"> </div>\n");
+}
+
+void
+report_formatter_html::add_summary_list(string *list, int size)
+{
+ int i;
+ add_exact("<div><br/> <ul>\n");
+ for (i=0; i < size; i+=2){
+ addf_exact("<li class=\"summary_list\"> <b> %s </b> %s </li>",
+ list[i].c_str(), list[i+1].c_str());
+ }
+ add_exact("</ul> </div> <br />\n");
+}
+
+
+void
+report_formatter_html::add_table(string *system_data, struct table_attributes* tb_attr)
+{
+ int i, j;
+ int offset=0;
+ string empty="";
+
+ if (tb_attr->table_class == empty)
+ add_exact("<table>\n");
+ else
+ addf_exact("<table class=\"%s\">\n", tb_attr->table_class);
+
+ for (i=0; i < tb_attr->rows; i++){
+ if (tb_attr->tr_class == empty)
+ add_exact("<tr> ");
+ else
+ addf_exact("<tr class=\"%s\"> ", tb_attr->tr_class);
+
+ for (j=0; j < tb_attr->cols; j++){
+ offset = i * (tb_attr->cols) + j;
+
+ if (tb_attr->pos_table_title == T && i==0)
+ addf_exact("<th class=\"%s\"> %s </th> ",
+ tb_attr->th_class,system_data[offset].c_str());
+ else if (tb_attr->pos_table_title == L && j==0)
+ addf_exact("<th class=\"%s\"> %s </th> ",
+ tb_attr->th_class, system_data[offset].c_str());
+ else if (tb_attr->pos_table_title == TL && ( i==0 || j==0 ))
+ addf_exact("<th class=\"%s\"> %s </th> ",
+ tb_attr->th_class, system_data[offset].c_str());
+ else if (tb_attr->pos_table_title == TC && ((i % tb_attr->title_mod ) == 0))
+ addf_exact("<th class=\"%s\"> %s </th> ", tb_attr->th_class,
+ system_data[offset].c_str());
+ else if (tb_attr->pos_table_title == TLC && ((i % tb_attr->title_mod) == 0 || j==0))
+ addf_exact("<th class=\"%s\"> %s </th> ", tb_attr->th_class,
+ system_data[offset].c_str());
+ else
+ if ( tb_attr->td_class == empty)
+ addf_exact("<td > %s </td> ", system_data[offset].c_str());
+ else
+ addf_exact("<td class=\"%s\"> %s </td> ", tb_attr->td_class,
+ system_data[offset].c_str());
+ }
+ add_exact("</tr>\n");
+ }
+ add_exact("</table>\n");
+}
+
diff --git a/src/report/report-formatter-html.h b/src/report/report-formatter-html.h
new file mode 100644
index 0000000..c003fd9
--- /dev/null
+++ b/src/report/report-formatter-html.h
@@ -0,0 +1,73 @@
+/* Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ *
+ * HTML report generator.
+ * Written by Igor Zhbanov <i.zhbanov@samsung.com>
+ * 2012.10 */
+
+#ifndef _REPORT_FORMATTER_HTML_H_
+#define _REPORT_FORMATTER_HTML_H_
+
+#include <string>
+
+#include "report-formatter-base.h"
+#include "report-data-html.h"
+
+using namespace std;
+
+/* Whether to replace " and ' in HTML by &quot; and &apos; respectively */
+/*#define REPORT_HTML_ESCAPE_QUOTES*/
+
+/* ************************************************************************ */
+
+struct html_section {
+ const char *id;
+};
+
+/* ************************************************************************ */
+
+class report_formatter_html: public report_formatter_string_base
+{
+public:
+ report_formatter_html();
+ void finish_report();
+
+ /* Report Style */
+ void add_logo();
+ void add_header();
+ void end_header();
+ void add_div(struct tag_attr *div_attr);
+ void end_div();
+ void add_title(struct tag_attr *title_att, const char *title);
+ void add_navigation();
+ void add_summary_list(string *list, int size);
+ void add_table(string *system_data, struct table_attributes *tb_attr);
+
+private:
+ /* Document structure related functions */
+ void init_markup();
+ void add_doc_header();
+ void add_doc_footer();
+ string escape_string(const char *str);
+
+};
+
+#endif /* _REPORT_FORMATTER_HTML_H_ */
diff --git a/src/report/report-formatter.h b/src/report/report-formatter.h
new file mode 100644
index 0000000..940b5cf
--- /dev/null
+++ b/src/report/report-formatter.h
@@ -0,0 +1,57 @@
+/* Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ *
+ * report_formatter interface.
+ * Written by Igor Zhbanov <i.zhbanov@samsung.com>
+ * 2012.10 */
+
+#ifndef _REPORT_FORMATTER_H_
+#define _REPORT_FORMATTER_H_
+
+#include "report-maker.h"
+using namespace std;
+
+class report_formatter
+{
+public:
+ virtual ~report_formatter() {}
+
+ virtual void finish_report() {}
+ virtual const char *get_result() {return "Basic report_formatter::get_result() call\n";}
+ virtual void clear_result() {}
+
+ virtual void add(const char *str) {}
+ virtual void addv(const char *fmt, va_list ap) {}
+
+ /* *** Report Style *** */
+ virtual void add_logo() {}
+ virtual void add_header() {}
+ virtual void end_header() {}
+ virtual void add_div(struct tag_attr *div_attr) {}
+ virtual void end_div() {}
+ virtual void add_title(struct tag_attr *att_title, const char *title) {}
+ virtual void add_navigation() {}
+ virtual void add_summary_list(string *list, int size) {}
+ virtual void add_table(string *system_data,
+ struct table_attributes *tb_attr) {}
+};
+
+#endif /* _REPORT_FORMATTER_H_ */
diff --git a/src/report/report-maker.cpp b/src/report/report-maker.cpp
new file mode 100644
index 0000000..4049a54
--- /dev/null
+++ b/src/report/report-maker.cpp
@@ -0,0 +1,187 @@
+/* Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ *
+ * Generic report generator.
+ * Written by Igor Zhbanov <i.zhbanov@samsung.com>
+ * 2012.10 */
+
+/* Uncomment to disable asserts */
+/*#define NDEBUG*/
+
+#include <assert.h>
+#include <stdarg.h>
+
+#include "report-maker.h"
+#include "report-formatter-csv.h"
+#include "report-formatter-html.h"
+
+/* ************************************************************************ */
+
+report_maker::report_maker(report_type t)
+{
+ type = t;
+ formatter = NULL;
+ setup_report_formatter();
+ clear_result(); /* To reset state and add document header */
+}
+
+/* ************************************************************************ */
+
+report_maker::~report_maker()
+{
+ delete formatter;
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::finish_report()
+{
+ formatter->finish_report();
+}
+
+/* ************************************************************************ */
+
+const char *
+report_maker::get_result()
+{
+ return formatter->get_result();
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::clear_result()
+{
+ formatter->clear_result();
+}
+
+/* ************************************************************************ */
+
+report_type
+report_maker::get_type()
+{
+ return type;
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::set_type(report_type t)
+{
+ clear_result();
+ type = t;
+ setup_report_formatter();
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::setup_report_formatter()
+{
+ delete formatter;
+
+ if (type == REPORT_HTML)
+ formatter = new report_formatter_html();
+ else if (type == REPORT_CSV)
+ formatter = new report_formatter_csv();
+ else if (type == REPORT_OFF)
+ formatter = new report_formatter();
+ else
+ assert(false);
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::add(const char *str)
+{
+ assert(str);
+ formatter->add(str);
+}
+
+/* ************************************************************************ */
+
+void
+report_maker::addf(const char *fmt, ...)
+{
+ va_list ap;
+ assert(fmt);
+ va_start(ap, fmt);
+ formatter->addv(fmt, ap);
+ va_end(ap);
+}
+
+/* *** Report Style *** */
+void
+report_maker::add_logo()
+{
+ formatter->add_logo();
+}
+
+void
+report_maker::add_header()
+{
+ formatter->add_header();
+}
+
+void
+report_maker::end_header()
+{
+ formatter->end_header();
+}
+
+void
+report_maker::add_title(struct tag_attr *att_title, const char *title)
+{
+ formatter->add_title(att_title, title);
+}
+
+void
+report_maker::add_div(struct tag_attr * div_attr)
+{
+ formatter->add_div(div_attr);
+}
+
+void
+report_maker::end_div()
+{
+ formatter->end_div();
+}
+
+void
+report_maker::add_navigation()
+{
+ formatter->add_navigation();
+}
+
+void
+report_maker::add_summary_list(string *list, int size)
+{
+ formatter->add_summary_list(list, size);
+}
+
+void
+report_maker::add_table(string *system_data, struct table_attributes *tb_attr)
+{
+ formatter->add_table(system_data, tb_attr);
+}
+
diff --git a/src/report/report-maker.h b/src/report/report-maker.h
new file mode 100644
index 0000000..bda4cef
--- /dev/null
+++ b/src/report/report-maker.h
@@ -0,0 +1,139 @@
+/* Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ *
+ * Generic report generator.
+ * Written by Igor Zhbanov <i.zhbanov@samsung.com>
+ * 2012.10 */
+
+#ifndef _REPORT_MAKER_H_
+#define _REPORT_MAKER_H_
+
+/* This report generator implements the following document structure:
+ * body
+ * \---> section
+ * |---> Title
+ * |---> paragraph
+ * |---> table
+ * |---> list
+ *
+ * The report body consists of a number of sections (a.k.a. <div>s,
+ * a.k.a. tabs).
+ * Each section can contain titles (<h2>), paragraphs (<p>)
+ * and tables (<table>).
+ *
+ * A header is a single line of text.
+ *
+ * Paragraphs can contain only text.
+ *
+ *
+ * Each section, table, row or cell could have its own formatting.
+ *
+ * Example of usage:
+ * report_maker report(REPORT_OFF);
+ *
+ * report.set_type(REPORT_HTML);
+ * report.add_div
+ * report.add_title
+ * report.add_list
+ * report.add_table
+ * report.finish_report();
+ * const char *result = report.get_result();
+ */
+
+#include <stdarg.h>
+
+#include <string>
+using namespace std;
+/* Conditional gettext. We need original strings for CSV. */
+#ifdef ENABLE_NLS
+#define __(STRING) \
+ ((report.get_type() == REPORT_CSV) ? (STRING) : gettext(STRING))
+#else
+#define __(STRING) (STRING)
+#endif
+
+#ifndef UNUSED
+#define UNUSED __attribute__((unused))
+#endif /* UNUSED */
+
+/* ************************************************************************ */
+
+enum report_type {
+ REPORT_OFF,
+ REPORT_HTML,
+ REPORT_CSV
+};
+
+/* ************************************************************************ */
+
+enum section_type {
+ SECTION_DEFAULT,
+ SECTION_SYSINFO,
+ SECTION_CPUIDLE,
+ SECTION_CPUFREQ,
+ SECTION_DEVFREQ,
+ SECTION_DEVPOWER,
+ SECTION_SOFTWARE,
+ SECTION_SUMMARY,
+ SECTION_TUNING,
+ SECTION_MAX /* Must be last in this enum */
+};
+
+
+/* ************************************************************************ */
+
+class report_formatter;
+
+class report_maker
+{
+public:
+ report_maker(report_type t);
+ ~report_maker();
+
+ report_type get_type();
+ void set_type(report_type t);
+
+ void addf(const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+
+ void finish_report();
+ const char *get_result();
+ void clear_result();
+
+ void add(const char *str);
+
+ /* *** Report Style *** */
+ void add_header();
+ void end_header();
+ void add_logo();
+ void add_div(struct tag_attr *div_attr);
+ void end_div();
+ void add_title(struct tag_attr *att_title, const char *title);
+ void add_navigation();
+ void add_summary_list(string *list, int size);
+ void add_table(string *system_data, struct table_attributes *tb_attr);
+
+private:
+ void setup_report_formatter();
+ report_type type;
+ report_formatter *formatter;
+};
+#endif /* _REPORT_MAKER_H_ */
diff --git a/src/report/report.cpp b/src/report/report.cpp
new file mode 100644
index 0000000..2efe835
--- /dev/null
+++ b/src/report/report.cpp
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2011, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ * Chris Ferron <chris.e.ferron@linux.intel.com>
+ */
+
+#include "lib.h"
+#include "report.h"
+#include "report-maker.h"
+#include <errno.h>
+#include <string.h>
+#include <utility>
+#include <iostream>
+#include <fstream>
+#include <string.h>
+#include <malloc.h>
+#include <unistd.h>
+#include <limits.h>
+#include "report-data-html.h"
+
+using namespace std;
+
+struct reportstream reportout;
+report_type reporttype = REPORT_OFF;
+report_maker report(REPORT_OFF);
+
+string cpu_model(void)
+{
+ ifstream file;
+
+ file.open("/proc/cpuinfo", ios::in);
+
+ if (!file)
+ return "";
+
+ while (file) {
+ char line[4096];
+ file.getline(line, 4096);
+ if (strstr(line, "model name")) {
+ char *c;
+ c = strchr(line, ':');
+ if (c) {
+ file.close();
+ c++;
+ return c;
+ }
+ }
+ }
+ file.close();
+ return "";
+}
+
+static string read_os_release(const string &filename)
+{
+ ifstream file;
+ char content[4096];
+ char *c;
+ const char *pname = "PRETTY_NAME=";
+ string os("");
+
+ file.open(filename.c_str(), ios::in);
+ if (!file)
+ return "";
+ while (file.getline(content, 4096)) {
+ if (strncasecmp(pname, content, strlen(pname)) == 0) {
+ c = strchr(content, '=');
+ if (!c)
+ break;
+ c += 1;
+ if (*c == '"' || *c == '\'')
+ c += 1;
+ *strchrnul(c, '"') = 0;
+ *strchrnul(c, '\'') = 0;
+ os = c;
+ break;
+ }
+ }
+ file.close();
+ return os;
+}
+
+static void system_info(void)
+{
+ string str;
+ char version_date[64];
+ time_t now = time(NULL);
+
+ /* div attr css_class and css_id */
+ tag_attr div_attr;
+ init_div(&div_attr, "sys_info", "");
+
+ /* Set Table attributes, rows, and cols */
+ table_attributes sys_table;
+ init_top_table_attr(&sys_table, 5, 2);
+
+ /* Set Title attributes */
+ tag_attr title_attr;
+ init_title_attr(&title_attr);
+
+ /* Set array of data in row Major order */
+ string *system_data = new string[sys_table.rows * sys_table.cols];
+ system_data[0]=__("PowerTOP Version");
+ snprintf(version_date, sizeof(version_date), "%s ran at %s", PACKAGE_VERSION, ctime(&now));
+ system_data[1]=version_date;
+
+ str = read_sysfs_string("/proc/version");
+ size_t found = str.find(" ");
+ found = str.find(" ", found+1);
+ found = str.find(" ", found+1);
+ str = str.substr(0,found);
+ system_data[2]=__("Kernel Version");
+ system_data[3]=str.c_str();
+
+ str = read_sysfs_string("/sys/devices/virtual/dmi/id/board_vendor");
+ system_data[4]=__("System Name");
+ system_data[5]= str.c_str();
+ str = read_sysfs_string("/sys/devices/virtual/dmi/id/board_name");
+ system_data[5].append(str.c_str());
+ str = read_sysfs_string("/sys/devices/virtual/dmi/id/product_version");
+ system_data[5].append(str.c_str());
+ str = cpu_model();
+ system_data[6]=__("CPU Information");
+ stringstream n_proc;
+ n_proc << sysconf(_SC_NPROCESSORS_ONLN);
+ system_data[7]= n_proc.str();
+ system_data[7].append(str.c_str());
+
+ str = read_sysfs_string("/etc/system-release");
+ if (str.length() < 1)
+ str = read_sysfs_string("/etc/redhat-release");
+ if (str.length() < 1)
+ str = read_os_release("/etc/os-release");
+
+ system_data[8]=__("OS Information");
+ system_data[9]=str;
+
+ /* Report Output */
+ report.add_header();
+ report.add_logo();
+ report.add_div(&div_attr);
+ report.add_title(&title_attr, __("System Information"));
+ report.add_table(system_data, &sys_table);
+ report.end_header();
+ report.end_div();
+ report.add_navigation();
+ delete [] system_data;
+}
+
+void init_report_output(char *filename_str, int iterations)
+{
+ size_t period;
+ string filename;
+ time_t stamp;
+ char datestr[200];
+
+ if (iterations == 1)
+ snprintf(reportout.filename, sizeof(reportout.filename), "%s", filename_str);
+ else
+ {
+ filename = string(filename_str);
+ period = filename.find_last_of(".");
+ if (period > filename.length())
+ period = filename.length();
+ memset(&datestr, 0, 200);
+ memset(&stamp, 0, sizeof(time_t));
+ stamp = time(NULL);
+ strftime(datestr, sizeof(datestr), "%Y%m%d-%H%M%S", localtime(&stamp));
+ snprintf(reportout.filename, sizeof(reportout.filename), "%s-%s%s",
+ filename.substr(0, period).c_str(), datestr,
+ filename.substr(period).c_str());
+ }
+
+ reportout.report_file = fopen(reportout.filename, "wm");
+ if (!reportout.report_file) {
+ fprintf(stderr, _("Cannot open output file %s (%s)\n"),
+ reportout.filename, strerror(errno));
+ }
+
+ report.set_type(reporttype);
+ system_info();
+}
+
+void finish_report_output(void)
+{
+ if (reporttype == REPORT_OFF)
+ return;
+
+ report.finish_report();
+ if (reportout.report_file)
+ {
+ fprintf(stderr, _("PowerTOP outputting using base filename %s\n"), reportout.filename);
+ fputs(report.get_result(), reportout.report_file);
+ fdatasync(fileno(reportout.report_file));
+ fclose(reportout.report_file);
+ }
+ report.clear_result();
+}
diff --git a/src/report/report.h b/src/report/report.h
new file mode 100644
index 0000000..c1aee1b
--- /dev/null
+++ b/src/report/report.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef __INCLUDE_GUARD_REPORT_H_
+#define __INCLUDE_GUARD_REPORT_H_
+
+#include <string>
+#include <stdio.h>
+#include <limits.h>
+
+#include "report-maker.h"
+
+using namespace std;
+
+struct reportstream {
+ FILE *report_file;
+ char filename[PATH_MAX];
+};
+
+extern report_type reporttype;
+extern report_maker report;
+extern struct reportstream reportout;
+extern void init_report_output(char *filename_str, int iterations);
+extern void finish_report_output(void);
+
+#endif
diff --git a/src/tuning/bluetooth.cpp b/src/tuning/bluetooth.cpp
new file mode 100644
index 0000000..2958849
--- /dev/null
+++ b/src/tuning/bluetooth.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "tuning.h"
+#include "tunable.h"
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utility>
+#include <iostream>
+#include <fstream>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include "../lib.h"
+#include "bluetooth.h"
+
+bt_tunable::bt_tunable(void) : tunable("", 1.0, _("Good"), _("Bad"), _("Unknown"))
+{
+ sprintf(desc, _("Bluetooth device interface status"));
+ pt_strcpy(toggle_bad, "/usr/sbin/hciconfig hci0 up &> /dev/null &");
+ pt_strcpy(toggle_good, "/usr/sbin/hciconfig hci0 down &> /dev/null");
+}
+
+
+
+/* structure definitions copied from include/net/bluetooth/hci.h from the 2.6.20 kernel */
+#define HCIGETDEVINFO _IOR('H', 211, int)
+#define BTPROTO_HCI 1
+
+#define __u16 uint16_t
+#define __u8 uint8_t
+#define __u32 uint32_t
+
+typedef struct {
+ __u8 b[6];
+} __attribute__((packed)) bdaddr_t;
+
+struct hci_dev_stats {
+ __u32 err_rx;
+ __u32 err_tx;
+ __u32 cmd_tx;
+ __u32 evt_rx;
+ __u32 acl_tx;
+ __u32 acl_rx;
+ __u32 sco_tx;
+ __u32 sco_rx;
+ __u32 byte_rx;
+ __u32 byte_tx;
+};
+
+
+struct hci_dev_info {
+ __u16 dev_id;
+ char name[8];
+
+ bdaddr_t bdaddr;
+
+ __u32 flags;
+ __u8 type;
+
+ __u8 features[8];
+
+ __u32 pkt_type;
+ __u32 link_policy;
+ __u32 link_mode;
+
+ __u16 acl_mtu;
+ __u16 acl_pkts;
+ __u16 sco_mtu;
+ __u16 sco_pkts;
+
+ struct hci_dev_stats stat;
+};
+
+static int previous_bytes = -1;
+static time_t last_check_time = 0;
+static int last_check_result;
+
+int bt_tunable::good_bad(void)
+{
+ struct hci_dev_info devinfo;
+ FILE *file = 0;
+ int fd;
+ int thisbytes = 0;
+ int ret;
+ int result = TUNE_GOOD;
+
+ fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+ if (fd < 0)
+ return TUNE_GOOD;
+
+ memset(&devinfo, 0, sizeof(devinfo));
+ strcpy(devinfo.name, "hci0");
+ ret = ioctl(fd, HCIGETDEVINFO, (void *) &devinfo);
+ if (ret < 0)
+ goto out;
+
+ if ( (devinfo.flags & 1) == 0 &&
+ access("/sys/module/hci_usb",F_OK)) /* interface down already */
+ goto out;
+
+ thisbytes += devinfo.stat.byte_rx;
+ thisbytes += devinfo.stat.byte_tx;
+
+ /* device is active... so we need to leave it on */
+ if (thisbytes != previous_bytes)
+ goto out;
+
+
+ /* this check is expensive.. only do it once per minute */
+ if (time(NULL) - last_check_time > 60) {
+ last_check_result = TUNE_BAD;
+ /* now, also check for active connections */
+ file = popen("/usr/bin/hcitool con 2> /dev/null", "r");
+ if (file) {
+ char line[2048];
+ /* first line is standard header */
+ if (fgets(line, 2047, file) == NULL)
+ goto out;
+ memset(line, 0, 2048);
+ if (fgets(line, 2047, file) == NULL) {
+ result = last_check_result = TUNE_GOOD;
+ goto out;
+ }
+
+ if (strlen(line) > 0) {
+ result = last_check_result = TUNE_GOOD;
+ goto out;
+ }
+ }
+ last_check_time = time(NULL);
+ };
+
+ result = last_check_result;
+
+out:
+ previous_bytes = thisbytes;
+ if (file)
+ pclose(file);
+ close(fd);
+ return result;
+}
+
+void bt_tunable::toggle(void)
+{
+ int good;
+ good = good_bad();
+
+ if (good == TUNE_GOOD) {
+ if(system("/usr/sbin/hciconfig hci0 up &> /dev/null &"))
+ printf("System is not available\n");
+ return;
+ }
+ if(system("/usr/sbin/hciconfig hci0 down &> /dev/null"))
+ printf("System is not available\n");
+}
+
+const char *bt_tunable::toggle_script(void)
+{
+ int good;
+ good = good_bad();
+
+ if (good == TUNE_GOOD) {
+ return toggle_bad;
+ }
+ return toggle_good;
+}
+
+
+void add_bt_tunable(void)
+{
+ struct hci_dev_info devinfo;
+ class bt_tunable *bt;
+ int fd;
+ int ret;
+
+ /* first check if /sys/modules/bluetooth exists, if not, don't probe bluetooth because
+ it would trigger an autoload */
+
+// if (access("/sys/module/bluetooth",F_OK))
+// return;
+
+
+ /* check if hci0 exists */
+ fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+ if (fd < 0)
+ return;
+
+ memset(&devinfo, 0, sizeof(devinfo));
+ strcpy(devinfo.name, "hci0");
+ ret = ioctl(fd, HCIGETDEVINFO, (void *) &devinfo);
+ close(fd);
+ if (ret < 0)
+ return;
+
+
+ bt = new class bt_tunable();
+ all_tunables.push_back(bt);
+}
diff --git a/src/tuning/bluetooth.h b/src/tuning/bluetooth.h
new file mode 100644
index 0000000..ecb667d
--- /dev/null
+++ b/src/tuning/bluetooth.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_BLUETOOTH_TUNE_H
+#define _INCLUDE_GUARD_BLUETOOTH_TUNE_H
+
+#include <vector>
+
+#include "tunable.h"
+
+using namespace std;
+
+class bt_tunable : public tunable {
+public:
+ bt_tunable(void);
+
+ virtual int good_bad(void);
+
+ virtual void toggle(void);
+
+ virtual const char *toggle_script(void);
+
+};
+
+extern void add_bt_tunable(void);
+
+
+#endif
diff --git a/src/tuning/ethernet.cpp b/src/tuning/ethernet.cpp
new file mode 100644
index 0000000..5b128d1
--- /dev/null
+++ b/src/tuning/ethernet.cpp
@@ -0,0 +1,157 @@
+;/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "tuning.h"
+#include "tunable.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utility>
+#include <iostream>
+#include <fstream>
+#include <sys/socket.h>
+#include <errno.h>
+#include <linux/types.h>
+#include <net/if.h>
+#include <linux/sockios.h>
+#include <sys/ioctl.h>
+
+#include <linux/ethtool.h>
+
+#include "../lib.h"
+#include "ethernet.h"
+
+extern void create_all_nics(callback fn);
+
+ethernet_tunable::ethernet_tunable(const char *iface) : tunable("", 0.3, _("Good"), _("Bad"), _("Unknown"))
+{
+ memset(interf, 0, sizeof(interf));
+ pt_strcpy(interf, iface);
+ sprintf(desc, _("Wake-on-lan status for device %s"), iface);
+ snprintf(toggle_good, sizeof(toggle_good), "ethtool -s %s wol d;", iface);
+
+}
+
+
+int ethernet_tunable::good_bad(void)
+{
+ int sock;
+ struct ifreq ifr;
+ struct ethtool_wolinfo wol;
+ int ret;
+ int result = TUNE_GOOD;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock<0)
+ return result;
+
+ pt_strcpy(ifr.ifr_name, interf);
+
+ /* Check if the interf is up */
+ ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
+ if (ret<0) {
+ close(sock);
+ return result;
+ }
+
+ memset(&wol, 0, sizeof(wol));
+
+ wol.cmd = ETHTOOL_GWOL;
+ ifr.ifr_data = (caddr_t)&wol;
+ ioctl(sock, SIOCETHTOOL, &ifr);
+
+ if (wol.wolopts)
+ result = TUNE_BAD;
+
+ close(sock);
+
+ return result;
+}
+
+void ethernet_tunable::toggle(void)
+{
+ int sock;
+ struct ifreq ifr;
+ struct ethtool_wolinfo wol;
+ int ret;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock<0)
+ return;
+
+ pt_strcpy(ifr.ifr_name, interf);
+
+ /* Check if the interface is up */
+ ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
+ if (ret<0) {
+ close(sock);
+ return;
+ }
+
+ memset(&wol, 0, sizeof(wol));
+
+ wol.cmd = ETHTOOL_GWOL;
+ ifr.ifr_data = (caddr_t)&wol;
+ ioctl(sock, SIOCETHTOOL, &ifr);
+ wol.cmd = ETHTOOL_SWOL;
+ wol.wolopts = 0;
+ ioctl(sock, SIOCETHTOOL, &ifr);
+
+ close(sock);
+}
+
+const char *ethernet_tunable::toggle_script(void)
+{
+ int good;
+ good = good_bad();
+
+ if (good != TUNE_GOOD) {
+ return toggle_good;
+ }
+
+ return NULL;
+}
+
+
+void ethtunable_callback(const char *d_name)
+{
+ class ethernet_tunable *eth;
+ if (strcmp(d_name, "lo") == 0)
+ return;
+ eth = new(std::nothrow) class ethernet_tunable(d_name);
+ if (eth)
+ all_tunables.push_back(eth);
+}
+
+void add_ethernet_tunable(void)
+{
+ create_all_nics(&ethtunable_callback);
+}
diff --git a/src/tuning/ethernet.h b/src/tuning/ethernet.h
new file mode 100644
index 0000000..85810fb
--- /dev/null
+++ b/src/tuning/ethernet.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_ETHERNET_TUNE_H
+#define _INCLUDE_GUARD_ETHERNET_TUNE_H
+
+#include <vector>
+
+#include "tunable.h"
+
+using namespace std;
+
+class ethernet_tunable : public tunable {
+public:
+ char interf[4096];
+ ethernet_tunable(const char *iface);
+
+ virtual int good_bad(void);
+
+ virtual void toggle(void);
+
+ virtual const char *toggle_script(void);
+
+};
+
+extern void add_ethernet_tunable(void);
+
+#endif
diff --git a/src/tuning/iw.c b/src/tuning/iw.c
new file mode 100644
index 0000000..68eb6dc
--- /dev/null
+++ b/src/tuning/iw.c
@@ -0,0 +1,303 @@
+/*
+ * This code has been blatently stolen from
+ *
+ * nl80211 userspace tool
+ *
+ * Copyright 2007, 2008 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * and has been stripped down to just the pieces needed.
+ */
+
+/*
+
+Copyright (c) 2007, 2008 Johannes Berg
+Copyright (c) 2007 Andy Lutomirski
+Copyright (c) 2007 Mike Kershaw
+Copyright (c) 2008-2009 Luis R. Rodriguez
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+*/
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <net/if.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+#include "nl80211.h"
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+
+#include <asm/errno.h>
+#include <linux/genetlink.h>
+#include "iw.h"
+
+
+#ifndef HAVE_LIBNL20
+/* libnl 2.0 compatibility code */
+
+static inline struct nl_handle *nl_socket_alloc(void)
+{
+ return nl_handle_alloc();
+}
+
+static inline void nl_socket_free(struct nl_sock *h)
+{
+ nl_handle_destroy(h);
+}
+
+static inline int __genl_ctrl_alloc_cache(struct nl_sock *h, struct nl_cache **cache)
+{
+ struct nl_cache *tmp = genl_ctrl_alloc_cache(h);
+ if (!tmp)
+ return -ENOMEM;
+ *cache = tmp;
+ return 0;
+}
+#define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache
+#endif /* HAVE_LIBNL20 */
+
+
+static int nl80211_init(struct nl80211_state *state)
+{
+ int err;
+
+ state->nl_sock = nl_socket_alloc();
+ if (!state->nl_sock) {
+ fprintf(stderr, "Failed to allocate netlink socket.\n");
+ return -ENOMEM;
+ }
+
+ if (genl_connect(state->nl_sock)) {
+ fprintf(stderr, "Failed to connect to generic netlink.\n");
+ err = -ENOLINK;
+ goto out_handle_destroy;
+ }
+
+ if (genl_ctrl_alloc_cache(state->nl_sock, &state->nl_cache)) {
+ fprintf(stderr, "Failed to allocate generic netlink cache.\n");
+ err = -ENOMEM;
+ goto out_handle_destroy;
+ }
+
+ state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211");
+ if (!state->nl80211) {
+ err = -ENOENT;
+ goto out_cache_free;
+ }
+
+ return 0;
+
+ out_cache_free:
+ nl_cache_free(state->nl_cache);
+ out_handle_destroy:
+ nl_socket_free(state->nl_sock);
+ return err;
+}
+
+static void nl80211_cleanup(struct nl80211_state *state)
+{
+ genl_family_put(state->nl80211);
+ nl_cache_free(state->nl_cache);
+ nl_socket_free(state->nl_sock);
+}
+
+static int enable_power_save;
+
+
+static int set_power_save(struct nl80211_state *state,
+ struct nl_cb *cb,
+ struct nl_msg *msg)
+{
+ enum nl80211_ps_state ps_state;
+
+ ps_state = NL80211_PS_DISABLED;
+ if (enable_power_save)
+ ps_state = NL80211_PS_ENABLED;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state);
+
+ return 0;
+
+ nla_put_failure:
+ return -ENOBUFS;
+}
+
+static int print_power_save_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *attrs[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+ nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!attrs[NL80211_ATTR_PS_STATE])
+ return 0;
+
+ switch (nla_get_u32(attrs[NL80211_ATTR_PS_STATE])) {
+ case NL80211_PS_ENABLED:
+ enable_power_save = 1;
+ break;
+ case NL80211_PS_DISABLED:
+ default:
+ enable_power_save = 0;
+ break;
+ }
+
+ return NL_SKIP;
+}
+
+static int get_power_save(struct nl80211_state *state,
+ struct nl_cb *cb,
+ struct nl_msg *msg)
+{
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
+ print_power_save_handler, NULL);
+ return 0;
+}
+
+static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
+ void *arg)
+{
+ int *ret = arg;
+ *ret = err->error;
+ return NL_STOP;
+}
+
+static int finish_handler(struct nl_msg *msg, void *arg)
+{
+ int *ret = arg;
+ *ret = 0;
+ return NL_SKIP;
+}
+
+static int ack_handler(struct nl_msg *msg, void *arg)
+{
+ int *ret = arg;
+ *ret = 0;
+ return NL_STOP;
+}
+
+static int __handle_cmd(struct nl80211_state *state, const char *iface, int get)
+{
+ struct nl_cb *cb;
+ struct nl_msg *msg;
+ int devidx = 0;
+ int err;
+
+ devidx = if_nametoindex(iface);
+ if (devidx == 0)
+ devidx = -1;
+ if (devidx < 0)
+ return -errno;
+
+ msg = nlmsg_alloc();
+ if (!msg) {
+ fprintf(stderr, "failed to allocate netlink message\n");
+ return 2;
+ }
+
+ cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (!cb) {
+ fprintf(stderr, "failed to allocate netlink callbacks\n");
+ err = 2;
+ goto out_free_msg;
+ }
+
+ if (get)
+ genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
+ 0, NL80211_CMD_GET_POWER_SAVE, 0);
+ else
+ genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
+ 0, NL80211_CMD_SET_POWER_SAVE, 0);
+
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
+
+ if (get)
+ err = get_power_save(state, cb, msg);
+ else
+ err = set_power_save(state, cb, msg);
+
+ if (err)
+ goto out;
+
+ err = nl_send_auto_complete(state->nl_sock, msg);
+ if (err < 0)
+ goto out;
+
+ err = 1;
+
+ nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
+
+ while (err > 0)
+ nl_recvmsgs(state->nl_sock, cb);
+ out:
+ nl_cb_put(cb);
+ out_free_msg:
+ nlmsg_free(msg);
+ return err;
+ nla_put_failure:
+ fprintf(stderr, "building message failed\n");
+ return 2;
+}
+
+
+int set_wifi_power_saving(const char *iface, int state)
+{
+ struct nl80211_state nlstate;
+ int err;
+
+ err = nl80211_init(&nlstate);
+ if (err)
+ return 1;
+
+ enable_power_save = state;
+ err = __handle_cmd(&nlstate, iface, 0);
+
+ nl80211_cleanup(&nlstate);
+
+ return err;
+}
+
+
+int get_wifi_power_saving(const char *iface)
+{
+ struct nl80211_state nlstate;
+ int err;
+
+ enable_power_save = 0;
+
+ err = nl80211_init(&nlstate);
+ if (err)
+ return 1;
+
+ err = __handle_cmd(&nlstate, iface, 1);
+
+ nl80211_cleanup(&nlstate);
+
+ if (err) /* not a wifi interface */
+ return 1;
+
+ return enable_power_save;
+}
diff --git a/src/tuning/iw.h b/src/tuning/iw.h
new file mode 100644
index 0000000..6ea5a3d
--- /dev/null
+++ b/src/tuning/iw.h
@@ -0,0 +1,69 @@
+#ifndef __IW_H
+#define __IW_H
+
+/*
+ * This code has been blatently stolen from
+ *
+ * nl80211 userspace tool
+ *
+ * Copyright 2007, 2008 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * and has been stripped down to just the pieces needed.
+ */
+
+/*
+
+Copyright (c) 2007, 2008 Johannes Berg
+Copyright (c) 2007 Andy Lutomirski
+Copyright (c) 2007 Mike Kershaw
+Copyright (c) 2008-2009 Luis R. Rodriguez
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+*/
+
+#include <stdbool.h>
+
+#define ETH_ALEN 6
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef HAVE_LIBNL20
+#define nl_sock nl_handle
+#endif
+
+struct nl80211_state {
+ struct nl_sock *nl_sock;
+ struct nl_cache *nl_cache;
+ struct genl_family *nl80211;
+};
+
+enum command_identify_by {
+ CIB_NONE,
+ CIB_PHY,
+ CIB_NETDEV,
+};
+
+enum id_input {
+ II_NONE,
+ II_NETDEV,
+ II_PHY_NAME,
+ II_PHY_IDX,
+};
+
+int get_wifi_power_saving(const char *iface);
+int set_wifi_power_saving(const char *iface, int state);
+
+#endif /* __IW_H */
diff --git a/src/tuning/nl80211.h b/src/tuning/nl80211.h
new file mode 100644
index 0000000..83b0514
--- /dev/null
+++ b/src/tuning/nl80211.h
@@ -0,0 +1,1897 @@
+#ifndef __LINUX_NL80211_H
+#define __LINUX_NL80211_H
+/*
+ * 802.11 netlink interface public header
+ *
+ * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2008 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2008 Luis Carlos Cobo <luisca@cozybit.com>
+ * Copyright 2008 Michael Buesch <mb@bu3sch.de>
+ * Copyright 2008, 2009 Luis R. Rodriguez <lrodriguez@atheros.com>
+ * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
+ * Copyright 2008 Colin McCabe <colin@cozybit.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/types.h>
+
+/**
+ * DOC: Station handling
+ *
+ * Stations are added per interface, but a special case exists with VLAN
+ * interfaces. When a station is bound to an AP interface, it may be moved
+ * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN).
+ * The station is still assumed to belong to the AP interface it was added
+ * to.
+ *
+ * TODO: need more info?
+ */
+
+/**
+ * DOC: Frame transmission/registration support
+ *
+ * Frame transmission and registration support exists to allow userspace
+ * management entities such as wpa_supplicant react to management frames
+ * that are not being handled by the kernel. This includes, for example,
+ * certain classes of action frames that cannot be handled in the kernel
+ * for various reasons.
+ *
+ * Frame registration is done on a per-interface basis and registrations
+ * cannot be removed other than by closing the socket. It is possible to
+ * specify a registration filter to register, for example, only for a
+ * certain type of action frame. In particular with action frames, those
+ * that userspace registers for will not be returned as unhandled by the
+ * driver, so that the registered application has to take responsibility
+ * for doing that.
+ *
+ * The type of frame that can be registered for is also dependent on the
+ * driver and interface type. The frame types are advertised in wiphy
+ * attributes so applications know what to expect.
+ *
+ * NOTE: When an interface changes type while registrations are active,
+ * these registrations are ignored until the interface type is
+ * changed again. This means that changing the interface type can
+ * lead to a situation that couldn't otherwise be produced, but
+ * any such registrations will be dormant in the sense that they
+ * will not be serviced, i.e. they will not receive any frames.
+ *
+ * Frame transmission allows userspace to send for example the required
+ * responses to action frames. It is subject to some sanity checking,
+ * but many frames can be transmitted. When a frame was transmitted, its
+ * status is indicated to the sending socket.
+ *
+ * For more technical details, see the corresponding command descriptions
+ * below.
+ */
+
+/**
+ * enum nl80211_commands - supported nl80211 commands
+ *
+ * @NL80211_CMD_UNSPEC: unspecified command to catch errors
+ *
+ * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request
+ * to get a list of all present wiphys.
+ * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
+ * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
+ * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ,
+ * %NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT,
+ * %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
+ * and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
+ * However, for setting the channel, see %NL80211_CMD_SET_CHANNEL
+ * instead, the support here is for backward compatibility only.
+ * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
+ * or rename notification. Has attributes %NL80211_ATTR_WIPHY and
+ * %NL80211_ATTR_WIPHY_NAME.
+ * @NL80211_CMD_DEL_WIPHY: Wiphy deleted. Has attributes
+ * %NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME.
+ *
+ * @NL80211_CMD_GET_INTERFACE: Request an interface's configuration;
+ * either a dump request on a %NL80211_ATTR_WIPHY or a specific get
+ * on an %NL80211_ATTR_IFINDEX is supported.
+ * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires
+ * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
+ * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response
+ * to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX,
+ * %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also
+ * be sent from userspace to request creation of a new virtual interface,
+ * then requires attributes %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFTYPE and
+ * %NL80211_ATTR_IFNAME.
+ * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes
+ * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from
+ * userspace to request deletion of a virtual interface, then requires
+ * attribute %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
+ * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
+ * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT,
+ * %NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD.
+ * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
+ * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC, %NL80211_ATTR_KEY_CIPHER,
+ * and %NL80211_ATTR_KEY_SEQ attributes.
+ * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
+ * or %NL80211_ATTR_MAC.
+ *
+ * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a
+ * %NL80222_CMD_NEW_BEACON message)
+ * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
+ * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
+ * %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes.
+ * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
+ * parameters are like for %NL80211_CMD_SET_BEACON.
+ * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
+ *
+ * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
+ * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_STATION: Set station attributes for station identified by
+ * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
+ * the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
+ * or, if no MAC address given, all stations, on the interface identified
+ * by %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to
+ * destination %NL80211_ATTR_MAC on the interface identified by
+ * %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to
+ * destination %NL80211_ATTR_MAC on the interface identified by
+ * %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the
+ * the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
+ * or, if no MAC address given, all mesh paths, on the interface identified
+ * by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by
+ * %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_GET_REG: ask the wireless core to send us its currently set
+ * regulatory domain.
+ * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command
+ * after being queried by the kernel. CRDA replies by sending a regulatory
+ * domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our
+ * current alpha2 if it found a match. It also provides
+ * NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each
+ * regulatory rule is a nested set of attributes given by
+ * %NL80211_ATTR_REG_RULE_FREQ_[START|END] and
+ * %NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by
+ * %NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and
+ * %NL80211_ATTR_REG_RULE_POWER_MAX_EIRP.
+ * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain
+ * to the specified ISO/IEC 3166-1 alpha2 country code. The core will
+ * store this as a valid request and then query userspace for it.
+ *
+ * @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the
+ * interface identified by %NL80211_ATTR_IFINDEX
+ *
+ * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the
+ * interface identified by %NL80211_ATTR_IFINDEX
+ *
+ * @NL80211_CMD_SET_MGMT_EXTRA_IE: Set extra IEs for management frames. The
+ * interface is identified with %NL80211_ATTR_IFINDEX and the management
+ * frame subtype with %NL80211_ATTR_MGMT_SUBTYPE. The extra IE data to be
+ * added to the end of the specified management frame is specified with
+ * %NL80211_ATTR_IE. If the command succeeds, the requested data will be
+ * added to all specified management frames generated by
+ * kernel/firmware/driver.
+ * Note: This command has been removed and it is only reserved at this
+ * point to avoid re-using existing command number. The functionality this
+ * command was planned for has been provided with cleaner design with the
+ * option to specify additional IEs in NL80211_CMD_TRIGGER_SCAN,
+ * NL80211_CMD_AUTHENTICATE, NL80211_CMD_ASSOCIATE,
+ * NL80211_CMD_DEAUTHENTICATE, and NL80211_CMD_DISASSOCIATE.
+ *
+ * @NL80211_CMD_GET_SCAN: get scan results
+ * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
+ * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to
+ * NL80211_CMD_GET_SCAN and on the "scan" multicast group)
+ * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
+ * partial scan results may be available
+ *
+ * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation
+ * or noise level
+ * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
+ * NL80211_CMD_GET_SURVEY and on the "scan" multicast group)
+ *
+ * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain
+ * has been changed and provides details of the request information
+ * that caused the change such as who initiated the regulatory request
+ * (%NL80211_ATTR_REG_INITIATOR), the wiphy_idx
+ * (%NL80211_ATTR_REG_ALPHA2) on which the request was made from if
+ * the initiator was %NL80211_REGDOM_SET_BY_COUNTRY_IE or
+ * %NL80211_REGDOM_SET_BY_DRIVER, the type of regulatory domain
+ * set (%NL80211_ATTR_REG_TYPE), if the type of regulatory domain is
+ * %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on
+ * to (%NL80211_ATTR_REG_ALPHA2).
+ * @NL80211_CMD_REG_BEACON_HINT: indicates to userspace that an AP beacon
+ * has been found while world roaming thus enabling active scan or
+ * any mode of operation that initiates TX (beacons) on a channel
+ * where we would not have been able to do either before. As an example
+ * if you are world roaming (regulatory domain set to world or if your
+ * driver is using a custom world roaming regulatory domain) and while
+ * doing a passive scan on the 5 GHz band you find an AP there (if not
+ * on a DFS channel) you will now be able to actively scan for that AP
+ * or use AP mode on your card on that same channel. Note that this will
+ * never be used for channels 1-11 on the 2 GHz band as they are always
+ * enabled world wide. This beacon hint is only sent if your device had
+ * either disabled active scanning or beaconing on a channel. We send to
+ * userspace the wiphy on which we removed a restriction from
+ * (%NL80211_ATTR_WIPHY) and the channel on which this occurred
+ * before (%NL80211_ATTR_FREQ_BEFORE) and after (%NL80211_ATTR_FREQ_AFTER)
+ * the beacon hint was processed.
+ *
+ * @NL80211_CMD_AUTHENTICATE: authentication request and notification.
+ * This command is used both as a command (request to authenticate) and
+ * as an event on the "mlme" multicast group indicating completion of the
+ * authentication process.
+ * When used as a command, %NL80211_ATTR_IFINDEX is used to identify the
+ * interface. %NL80211_ATTR_MAC is used to specify PeerSTAAddress (and
+ * BSSID in case of station mode). %NL80211_ATTR_SSID is used to specify
+ * the SSID (mainly for association, but is included in authentication
+ * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ is used
+ * to specify the frequence of the channel in MHz. %NL80211_ATTR_AUTH_TYPE
+ * is used to specify the authentication type. %NL80211_ATTR_IE is used to
+ * define IEs (VendorSpecificInfo, but also including RSN IE and FT IEs)
+ * to be added to the frame.
+ * When used as an event, this reports reception of an Authentication
+ * frame in station and IBSS modes when the local MLME processed the
+ * frame, i.e., it was for the local STA and was received in correct
+ * state. This is similar to MLME-AUTHENTICATE.confirm primitive in the
+ * MLME SAP interface (kernel providing MLME, userspace SME). The
+ * included %NL80211_ATTR_FRAME attribute contains the management frame
+ * (including both the header and frame body, but not FCS). This event is
+ * also used to indicate if the authentication attempt timed out. In that
+ * case the %NL80211_ATTR_FRAME attribute is replaced with a
+ * %NL80211_ATTR_TIMED_OUT flag (and %NL80211_ATTR_MAC to indicate which
+ * pending authentication timed out).
+ * @NL80211_CMD_ASSOCIATE: association request and notification; like
+ * NL80211_CMD_AUTHENTICATE but for Association and Reassociation
+ * (similar to MLME-ASSOCIATE.request, MLME-REASSOCIATE.request,
+ * MLME-ASSOCIATE.confirm or MLME-REASSOCIATE.confirm primitives).
+ * @NL80211_CMD_DEAUTHENTICATE: deauthentication request and notification; like
+ * NL80211_CMD_AUTHENTICATE but for Deauthentication frames (similar to
+ * MLME-DEAUTHENTICATION.request and MLME-DEAUTHENTICATE.indication
+ * primitives).
+ * @NL80211_CMD_DISASSOCIATE: disassociation request and notification; like
+ * NL80211_CMD_AUTHENTICATE but for Disassociation frames (similar to
+ * MLME-DISASSOCIATE.request and MLME-DISASSOCIATE.indication primitives).
+ *
+ * @NL80211_CMD_MICHAEL_MIC_FAILURE: notification of a locally detected Michael
+ * MIC (part of TKIP) failure; sent on the "mlme" multicast group; the
+ * event includes %NL80211_ATTR_MAC to describe the source MAC address of
+ * the frame with invalid MIC, %NL80211_ATTR_KEY_TYPE to show the key
+ * type, %NL80211_ATTR_KEY_IDX to indicate the key identifier, and
+ * %NL80211_ATTR_KEY_SEQ to indicate the TSC value of the frame; this
+ * event matches with MLME-MICHAELMICFAILURE.indication() primitive
+ *
+ * @NL80211_CMD_JOIN_IBSS: Join a new IBSS -- given at least an SSID and a
+ * FREQ attribute (for the initial frequency if no peer can be found)
+ * and optionally a MAC (as BSSID) and FREQ_FIXED attribute if those
+ * should be fixed rather than automatically determined. Can only be
+ * executed on a network interface that is UP, and fixed BSSID/FREQ
+ * may be rejected. Another optional parameter is the beacon interval,
+ * given in the %NL80211_ATTR_BEACON_INTERVAL attribute, which if not
+ * given defaults to 100 TU (102.4ms).
+ * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is
+ * determined by the network interface.
+ *
+ * @NL80211_CMD_TESTMODE: testmode command, takes a wiphy (or ifindex) attribute
+ * to identify the device, and the TESTDATA blob attribute to pass through
+ * to the driver.
+ *
+ * @NL80211_CMD_CONNECT: connection request and notification; this command
+ * requests to connect to a specified network but without separating
+ * auth and assoc steps. For this, you need to specify the SSID in a
+ * %NL80211_ATTR_SSID attribute, and can optionally specify the association
+ * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC,
+ * %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
+ * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
+ * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
+ * It is also sent as an event, with the BSSID and response IEs when the
+ * connection is established or failed to be established. This can be
+ * determined by the STATUS_CODE attribute.
+ * @NL80211_CMD_ROAM: request that the card roam (currently not implemented),
+ * sent as an event when the card/driver roamed by itself.
+ * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
+ * userspace that a connection was dropped by the AP or due to other
+ * reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
+ * %NL80211_ATTR_REASON_CODE attributes are used.
+ *
+ * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices
+ * associated with this wiphy must be down and will follow.
+ *
+ * @NL80211_CMD_REMAIN_ON_CHANNEL: Request to remain awake on the specified
+ * channel for the specified amount of time. This can be used to do
+ * off-channel operations like transmit a Public Action frame and wait for
+ * a response while being associated to an AP on another channel.
+ * %NL80211_ATTR_IFINDEX is used to specify which interface (and thus
+ * radio) is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the
+ * frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be
+ * optionally used to specify additional channel parameters.
+ * %NL80211_ATTR_DURATION is used to specify the duration in milliseconds
+ * to remain on the channel. This command is also used as an event to
+ * notify when the requested duration starts (it may take a while for the
+ * driver to schedule this time due to other concurrent needs for the
+ * radio).
+ * When called, this operation returns a cookie (%NL80211_ATTR_COOKIE)
+ * that will be included with any events pertaining to this request;
+ * the cookie is also used to cancel the request.
+ * @NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: This command can be used to cancel a
+ * pending remain-on-channel duration if the desired operation has been
+ * completed prior to expiration of the originally requested duration.
+ * %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify the
+ * radio. The %NL80211_ATTR_COOKIE attribute must be given as well to
+ * uniquely identify the request.
+ * This command is also used as an event to notify when a requested
+ * remain-on-channel duration has expired.
+ *
+ * @NL80211_CMD_SET_TX_BITRATE_MASK: Set the mask of rates to be used in TX
+ * rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface
+ * and @NL80211_ATTR_TX_RATES the set of allowed rates.
+ *
+ * @NL80211_CMD_REGISTER_FRAME: Register for receiving certain mgmt frames
+ * (via @NL80211_CMD_FRAME) for processing in userspace. This command
+ * requires an interface index, a frame type attribute (optional for
+ * backward compatibility reasons, if not given assumes action frames)
+ * and a match attribute containing the first few bytes of the frame
+ * that should match, e.g. a single byte for only a category match or
+ * four bytes for vendor frames including the OUI. The registration
+ * cannot be dropped, but is removed automatically when the netlink
+ * socket is closed. Multiple registrations can be made.
+ * @NL80211_CMD_REGISTER_ACTION: Alias for @NL80211_CMD_REGISTER_FRAME for
+ * backward compatibility
+ * @NL80211_CMD_FRAME: Management frame TX request and RX notification. This
+ * command is used both as a request to transmit a management frame and
+ * as an event indicating reception of a frame that was not processed in
+ * kernel code, but is for us (i.e., which may need to be processed in a
+ * user space application). %NL80211_ATTR_FRAME is used to specify the
+ * frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and
+ * optionally %NL80211_ATTR_WIPHY_CHANNEL_TYPE) is used to indicate on
+ * which channel the frame is to be transmitted or was received. If this
+ * channel is not the current channel (remain-on-channel or the
+ * operational channel) the device will switch to the given channel and
+ * transmit the frame, optionally waiting for a response for the time
+ * specified using %NL80211_ATTR_DURATION. When called, this operation
+ * returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the
+ * TX status event pertaining to the TX request.
+ * @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this
+ * command may be used with the corresponding cookie to cancel the wait
+ * time if it is known that it is no longer necessary.
+ * @NL80211_CMD_ACTION: Alias for @NL80211_CMD_FRAME for backward compatibility.
+ * @NL80211_CMD_FRAME_TX_STATUS: Report TX status of a management frame
+ * transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies
+ * the TX command and %NL80211_ATTR_FRAME includes the contents of the
+ * frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged
+ * the frame.
+ * @NL80211_CMD_ACTION_TX_STATUS: Alias for @NL80211_CMD_FRAME_TX_STATUS for
+ * backward compatibility.
+ * @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command
+ * is used to configure connection quality monitoring notification trigger
+ * levels.
+ * @NL80211_CMD_NOTIFY_CQM: Connection quality monitor notification. This
+ * command is used as an event to indicate the that a trigger level was
+ * reached.
+ * @NL80211_CMD_SET_CHANNEL: Set the channel (using %NL80211_ATTR_WIPHY_FREQ
+ * and %NL80211_ATTR_WIPHY_CHANNEL_TYPE) the given interface (identifed
+ * by %NL80211_ATTR_IFINDEX) shall operate on.
+ * In case multiple channels are supported by the device, the mechanism
+ * with which it switches channels is implementation-defined.
+ * When a monitor interface is given, it can only switch channel while
+ * no other interfaces are operating to avoid disturbing the operation
+ * of any other interfaces, and other interfaces will again take
+ * precedence when they are used.
+ *
+ * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface.
+ *
+ * @NL80211_CMD_JOIN_MESH: Join a mesh. The mesh ID must be given, and initial
+ * mesh config parameters may be given.
+ * @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the
+ * network is determined by the network interface.
+ *
+ * @NL80211_CMD_MAX: highest used command number
+ * @__NL80211_CMD_AFTER_LAST: internal use
+ */
+enum nl80211_commands {
+/* don't change the order or add anything inbetween, this is ABI! */
+ NL80211_CMD_UNSPEC,
+
+ NL80211_CMD_GET_WIPHY, /* can dump */
+ NL80211_CMD_SET_WIPHY,
+ NL80211_CMD_NEW_WIPHY,
+ NL80211_CMD_DEL_WIPHY,
+
+ NL80211_CMD_GET_INTERFACE, /* can dump */
+ NL80211_CMD_SET_INTERFACE,
+ NL80211_CMD_NEW_INTERFACE,
+ NL80211_CMD_DEL_INTERFACE,
+
+ NL80211_CMD_GET_KEY,
+ NL80211_CMD_SET_KEY,
+ NL80211_CMD_NEW_KEY,
+ NL80211_CMD_DEL_KEY,
+
+ NL80211_CMD_GET_BEACON,
+ NL80211_CMD_SET_BEACON,
+ NL80211_CMD_NEW_BEACON,
+ NL80211_CMD_DEL_BEACON,
+
+ NL80211_CMD_GET_STATION,
+ NL80211_CMD_SET_STATION,
+ NL80211_CMD_NEW_STATION,
+ NL80211_CMD_DEL_STATION,
+
+ NL80211_CMD_GET_MPATH,
+ NL80211_CMD_SET_MPATH,
+ NL80211_CMD_NEW_MPATH,
+ NL80211_CMD_DEL_MPATH,
+
+ NL80211_CMD_SET_BSS,
+
+ NL80211_CMD_SET_REG,
+ NL80211_CMD_REQ_SET_REG,
+
+ NL80211_CMD_GET_MESH_PARAMS,
+ NL80211_CMD_SET_MESH_PARAMS,
+
+ NL80211_CMD_SET_MGMT_EXTRA_IE /* reserved; not used */,
+
+ NL80211_CMD_GET_REG,
+
+ NL80211_CMD_GET_SCAN,
+ NL80211_CMD_TRIGGER_SCAN,
+ NL80211_CMD_NEW_SCAN_RESULTS,
+ NL80211_CMD_SCAN_ABORTED,
+
+ NL80211_CMD_REG_CHANGE,
+
+ NL80211_CMD_AUTHENTICATE,
+ NL80211_CMD_ASSOCIATE,
+ NL80211_CMD_DEAUTHENTICATE,
+ NL80211_CMD_DISASSOCIATE,
+
+ NL80211_CMD_MICHAEL_MIC_FAILURE,
+
+ NL80211_CMD_REG_BEACON_HINT,
+
+ NL80211_CMD_JOIN_IBSS,
+ NL80211_CMD_LEAVE_IBSS,
+
+ NL80211_CMD_TESTMODE,
+
+ NL80211_CMD_CONNECT,
+ NL80211_CMD_ROAM,
+ NL80211_CMD_DISCONNECT,
+
+ NL80211_CMD_SET_WIPHY_NETNS,
+
+ NL80211_CMD_GET_SURVEY,
+ NL80211_CMD_NEW_SURVEY_RESULTS,
+
+ NL80211_CMD_SET_PMKSA,
+ NL80211_CMD_DEL_PMKSA,
+ NL80211_CMD_FLUSH_PMKSA,
+
+ NL80211_CMD_REMAIN_ON_CHANNEL,
+ NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
+
+ NL80211_CMD_SET_TX_BITRATE_MASK,
+
+ NL80211_CMD_REGISTER_FRAME,
+ NL80211_CMD_REGISTER_ACTION = NL80211_CMD_REGISTER_FRAME,
+ NL80211_CMD_FRAME,
+ NL80211_CMD_ACTION = NL80211_CMD_FRAME,
+ NL80211_CMD_FRAME_TX_STATUS,
+ NL80211_CMD_ACTION_TX_STATUS = NL80211_CMD_FRAME_TX_STATUS,
+
+ NL80211_CMD_SET_POWER_SAVE,
+ NL80211_CMD_GET_POWER_SAVE,
+
+ NL80211_CMD_SET_CQM,
+ NL80211_CMD_NOTIFY_CQM,
+
+ NL80211_CMD_SET_CHANNEL,
+ NL80211_CMD_SET_WDS_PEER,
+
+ NL80211_CMD_FRAME_WAIT_CANCEL,
+
+ NL80211_CMD_JOIN_MESH,
+ NL80211_CMD_LEAVE_MESH,
+
+ /* add new commands above here */
+
+ /* used to define NL80211_CMD_MAX below */
+ __NL80211_CMD_AFTER_LAST,
+ NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1
+};
+
+/*
+ * Allow user space programs to use #ifdef on new commands by defining them
+ * here
+ */
+#define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS
+#define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE
+#define NL80211_CMD_REG_CHANGE NL80211_CMD_REG_CHANGE
+#define NL80211_CMD_AUTHENTICATE NL80211_CMD_AUTHENTICATE
+#define NL80211_CMD_ASSOCIATE NL80211_CMD_ASSOCIATE
+#define NL80211_CMD_DEAUTHENTICATE NL80211_CMD_DEAUTHENTICATE
+#define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE
+#define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT
+
+/**
+ * enum nl80211_attrs - nl80211 netlink attributes
+ *
+ * @NL80211_ATTR_UNSPEC: unspecified attribute to catch errors
+ *
+ * @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf.
+ * /sys/class/ieee80211/<phyname>/index
+ * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
+ * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
+ * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
+ * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
+ * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
+ * NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including
+ * this attribute)
+ * NL80211_CHAN_HT20 = HT20 only
+ * NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel
+ * NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel
+ * @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is
+ * less than or equal to the RTS threshold; allowed range: 1..255;
+ * dot11ShortRetryLimit; u8
+ * @NL80211_ATTR_WIPHY_RETRY_LONG: TX retry limit for frames whose length is
+ * greater than the RTS threshold; allowed range: 1..255;
+ * dot11ShortLongLimit; u8
+ * @NL80211_ATTR_WIPHY_FRAG_THRESHOLD: fragmentation threshold, i.e., maximum
+ * length in octets for frames; allowed range: 256..8000, disable
+ * fragmentation with (u32)-1; dot11FragmentationThreshold; u32
+ * @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length
+ * larger than or equal to this use RTS/CTS handshake); allowed range:
+ * 0..65536, disable with (u32)-1; dot11RTSThreshold; u32
+ * @NL80211_ATTR_WIPHY_COVERAGE_CLASS: Coverage Class as defined by IEEE 802.11
+ * section 7.3.2.9; dot11CoverageClass; u8
+ *
+ * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
+ * @NL80211_ATTR_IFNAME: network interface name
+ * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
+ *
+ * @NL80211_ATTR_MAC: MAC address (various uses)
+ *
+ * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of
+ * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ * keys
+ * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ * section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ * CCMP keys, each six bytes in little endian
+ *
+ * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU
+ * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing
+ * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
+ * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
+ *
+ * @NL80211_ATTR_STA_AID: Association ID for the station (u16)
+ * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of
+ * &enum nl80211_sta_flags (deprecated, use %NL80211_ATTR_STA_FLAGS2)
+ * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by
+ * IEEE 802.11 7.3.1.6 (u16).
+ * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported
+ * rates as defined by IEEE 802.11 7.3.2.2 but without the length
+ * restriction (at most %NL80211_MAX_SUPP_RATES).
+ * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
+ * to, or the AP interface the station was originally added to to.
+ * @NL80211_ATTR_STA_INFO: information about a station, part of station info
+ * given for %NL80211_CMD_GET_STATION, nested attribute containing
+ * info as possible, see &enum nl80211_sta_info.
+ *
+ * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands,
+ * consisting of a nested array.
+ *
+ * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes).
+ * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link.
+ * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path.
+ * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path
+ * info given for %NL80211_CMD_GET_MPATH, nested attribute described at
+ * &enum nl80211_mpath_info.
+ *
+ * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of
+ * &enum nl80211_mntr_flags.
+ *
+ * @NL80211_ATTR_REG_ALPHA2: an ISO-3166-alpha2 country code for which the
+ * current regulatory domain should be set to or is already set to.
+ * For example, 'CR', for Costa Rica. This attribute is used by the kernel
+ * to query the CRDA to retrieve one regulatory domain. This attribute can
+ * also be used by userspace to query the kernel for the currently set
+ * regulatory domain. We chose an alpha2 as that is also used by the
+ * IEEE-802.11d country information element to identify a country.
+ * Users can also simply ask the wireless core to set regulatory domain
+ * to a specific alpha2.
+ * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory
+ * rules.
+ *
+ * @NL80211_ATTR_BSS_CTS_PROT: whether CTS protection is enabled (u8, 0 or 1)
+ * @NL80211_ATTR_BSS_SHORT_PREAMBLE: whether short preamble is enabled
+ * (u8, 0 or 1)
+ * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled
+ * (u8, 0 or 1)
+ * @NL80211_ATTR_BSS_BASIC_RATES: basic rates, array of basic
+ * rates in format defined by IEEE 802.11 7.3.2.2 but without the length
+ * restriction (at most %NL80211_MAX_SUPP_RATES).
+ *
+ * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from
+ * association request when used with NL80211_CMD_NEW_STATION)
+ *
+ * @NL80211_ATTR_SUPPORTED_IFTYPES: nested attribute containing all
+ * supported interface types, each a flag attribute with the number
+ * of the interface mode.
+ *
+ * @NL80211_ATTR_MGMT_SUBTYPE: Management frame subtype for
+ * %NL80211_CMD_SET_MGMT_EXTRA_IE.
+ *
+ * @NL80211_ATTR_IE: Information element(s) data (used, e.g., with
+ * %NL80211_CMD_SET_MGMT_EXTRA_IE).
+ *
+ * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with
+ * a single scan request, a wiphy attribute.
+ * @NL80211_ATTR_MAX_SCAN_IE_LEN: maximum length of information elements
+ * that can be added to a scan request
+ *
+ * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
+ * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
+ * scanning and include a zero-length SSID (wildcard) for wildcard scan
+ * @NL80211_ATTR_BSS: scan result BSS
+ *
+ * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain
+ * currently in effect. This could be any of the %NL80211_REGDOM_SET_BY_*
+ * @NL80211_ATTR_REG_TYPE: indicates the type of the regulatory domain currently
+ * set. This can be one of the nl80211_reg_type (%NL80211_REGDOM_TYPE_*)
+ *
+ * @NL80211_ATTR_SUPPORTED_COMMANDS: wiphy attribute that specifies
+ * an array of command numbers (i.e. a mapping index to command number)
+ * that the driver for the given wiphy supports.
+ *
+ * @NL80211_ATTR_FRAME: frame data (binary attribute), including frame header
+ * and body, but not FCS; used, e.g., with NL80211_CMD_AUTHENTICATE and
+ * NL80211_CMD_ASSOCIATE events
+ * @NL80211_ATTR_SSID: SSID (binary attribute, 0..32 octets)
+ * @NL80211_ATTR_AUTH_TYPE: AuthenticationType, see &enum nl80211_auth_type,
+ * represented as a u32
+ * @NL80211_ATTR_REASON_CODE: ReasonCode for %NL80211_CMD_DEAUTHENTICATE and
+ * %NL80211_CMD_DISASSOCIATE, u16
+ *
+ * @NL80211_ATTR_KEY_TYPE: Key Type, see &enum nl80211_key_type, represented as
+ * a u32
+ *
+ * @NL80211_ATTR_FREQ_BEFORE: A channel which has suffered a regulatory change
+ * due to considerations from a beacon hint. This attribute reflects
+ * the state of the channel _before_ the beacon hint processing. This
+ * attributes consists of a nested attribute containing
+ * NL80211_FREQUENCY_ATTR_*
+ * @NL80211_ATTR_FREQ_AFTER: A channel which has suffered a regulatory change
+ * due to considerations from a beacon hint. This attribute reflects
+ * the state of the channel _after_ the beacon hint processing. This
+ * attributes consists of a nested attribute containing
+ * NL80211_FREQUENCY_ATTR_*
+ *
+ * @NL80211_ATTR_CIPHER_SUITES: a set of u32 values indicating the supported
+ * cipher suites
+ *
+ * @NL80211_ATTR_FREQ_FIXED: a flag indicating the IBSS should not try to look
+ * for other networks on different channels
+ *
+ * @NL80211_ATTR_TIMED_OUT: a flag indicating than an operation timed out; this
+ * is used, e.g., with %NL80211_CMD_AUTHENTICATE event
+ *
+ * @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is
+ * used for the association (&enum nl80211_mfp, represented as a u32);
+ * this attribute can be used
+ * with %NL80211_CMD_ASSOCIATE request
+ *
+ * @NL80211_ATTR_STA_FLAGS2: Attribute containing a
+ * &struct nl80211_sta_flag_update.
+ *
+ * @NL80211_ATTR_CONTROL_PORT: A flag indicating whether user space controls
+ * IEEE 802.1X port, i.e., sets/clears %NL80211_STA_FLAG_AUTHORIZED, in
+ * station mode. If the flag is included in %NL80211_CMD_ASSOCIATE
+ * request, the driver will assume that the port is unauthorized until
+ * authorized by user space. Otherwise, port is marked authorized by
+ * default in station mode.
+ * @NL80211_ATTR_CONTROL_PORT_ETHERTYPE: A 16-bit value indicating the
+ * ethertype that will be used for key negotiation. It can be
+ * specified with the associate and connect commands. If it is not
+ * specified, the value defaults to 0x888E (PAE, 802.1X). This
+ * attribute is also used as a flag in the wiphy information to
+ * indicate that protocols other than PAE are supported.
+ * @NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT: When included along with
+ * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, indicates that the custom
+ * ethertype frames used for key negotiation must not be encrypted.
+ *
+ * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
+ * We recommend using nested, driver-specific attributes within this.
+ *
+ * @NL80211_ATTR_DISCONNECTED_BY_AP: A flag indicating that the DISCONNECT
+ * event was due to the AP disconnecting the station, and not due to
+ * a local disconnect request.
+ * @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT
+ * event (u16)
+ * @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating
+ * that protected APs should be used.
+ *
+ * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE to
+ * indicate which unicast key ciphers will be used with the connection
+ * (an array of u32).
+ * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT and ASSOCIATE to indicate
+ * which group key cipher will be used with the connection (a u32).
+ * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT and ASSOCIATE to indicate
+ * which WPA version(s) the AP we want to associate with is using
+ * (a u32 with flags from &enum nl80211_wpa_versions).
+ * @NL80211_ATTR_AKM_SUITES: Used with CONNECT and ASSOCIATE to indicate
+ * which key management algorithm(s) to use (an array of u32).
+ *
+ * @NL80211_ATTR_REQ_IE: (Re)association request information elements as
+ * sent out by the card, for ROAM and successful CONNECT events.
+ * @NL80211_ATTR_RESP_IE: (Re)association response information elements as
+ * sent by peer, for ROAM and successful CONNECT events.
+ *
+ * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE
+ * commands to specify using a reassociate frame
+ *
+ * @NL80211_ATTR_KEY: key information in a nested attribute with
+ * %NL80211_KEY_* sub-attributes
+ * @NL80211_ATTR_KEYS: array of keys for static WEP keys for connect()
+ * and join_ibss(), key information is in a nested attribute each
+ * with %NL80211_KEY_* sub-attributes
+ *
+ * @NL80211_ATTR_PID: Process ID of a network namespace.
+ *
+ * @NL80211_ATTR_GENERATION: Used to indicate consistent snapshots for
+ * dumps. This number increases whenever the object list being
+ * dumped changes, and as such userspace can verify that it has
+ * obtained a complete and consistent snapshot by verifying that
+ * all dump messages contain the same generation number. If it
+ * changed then the list changed and the dump should be repeated
+ * completely from scratch.
+ *
+ * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface
+ *
+ * @NL80211_ATTR_SURVEY_INFO: survey information about a channel, part of
+ * the survey response for %NL80211_CMD_GET_SURVEY, nested attribute
+ * containing info as possible, see &enum survey_info.
+ *
+ * @NL80211_ATTR_PMKID: PMK material for PMKSA caching.
+ * @NL80211_ATTR_MAX_NUM_PMKIDS: maximum number of PMKIDs a firmware can
+ * cache, a wiphy attribute.
+ *
+ * @NL80211_ATTR_DURATION: Duration of an operation in milliseconds, u32.
+ *
+ * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects.
+ *
+ * @NL80211_ATTR_TX_RATES: Nested set of attributes
+ * (enum nl80211_tx_rate_attributes) describing TX rates per band. The
+ * enum nl80211_band value is used as the index (nla_type() of the nested
+ * data. If a band is not included, it will be configured to allow all
+ * rates based on negotiated supported rates information. This attribute
+ * is used with %NL80211_CMD_SET_TX_BITRATE_MASK.
+ *
+ * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain
+ * at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME.
+ * @NL80211_ATTR_FRAME_TYPE: A u16 indicating the frame type/subtype for the
+ * @NL80211_CMD_REGISTER_FRAME command.
+ * @NL80211_ATTR_TX_FRAME_TYPES: wiphy capability attribute, which is a
+ * nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing
+ * information about which frame types can be transmitted with
+ * %NL80211_CMD_FRAME.
+ * @NL80211_ATTR_RX_FRAME_TYPES: wiphy capability attribute, which is a
+ * nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing
+ * information about which frame types can be registered for RX.
+ *
+ * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was
+ * acknowledged by the recipient.
+ *
+ * @NL80211_ATTR_CQM: connection quality monitor configuration in a
+ * nested attribute with %NL80211_ATTR_CQM_* sub-attributes.
+ *
+ * @NL80211_ATTR_LOCAL_STATE_CHANGE: Flag attribute to indicate that a command
+ * is requesting a local authentication/association state change without
+ * invoking actual management frame exchange. This can be used with
+ * NL80211_CMD_AUTHENTICATE, NL80211_CMD_DEAUTHENTICATE,
+ * NL80211_CMD_DISASSOCIATE.
+ *
+ * @NL80211_ATTR_AP_ISOLATE: (AP mode) Do not forward traffic between stations
+ * connected to this BSS.
+ *
+ * @NL80211_ATTR_WIPHY_TX_POWER_SETTING: Transmit power setting type. See
+ * &enum nl80211_tx_power_setting for possible values.
+ * @NL80211_ATTR_WIPHY_TX_POWER_LEVEL: Transmit power level in signed mBm units.
+ * This is used in association with @NL80211_ATTR_WIPHY_TX_POWER_SETTING
+ * for non-automatic settings.
+ *
+ * @NL80211_ATTR_SUPPORT_IBSS_RSN: The device supports IBSS RSN, which mostly
+ * means support for per-station GTKs.
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_TX: Bitmap of allowed antennas for transmitting.
+ * This can be used to mask out antennas which are not attached or should
+ * not be used for transmitting. If an antenna is not selected in this
+ * bitmap the hardware is not allowed to transmit on this antenna.
+ *
+ * Each bit represents one antenna, starting with antenna 1 at the first
+ * bit. Depending on which antennas are selected in the bitmap, 802.11n
+ * drivers can derive which chainmasks to use (if all antennas belonging to
+ * a particular chain are disabled this chain should be disabled) and if
+ * a chain has diversity antennas whether diversity should be used or not.
+ * HT capabilities (STBC, TX Beamforming, Antenna selection) can be
+ * derived from the available chains after applying the antenna mask.
+ * Non-802.11n drivers can derive wether to use diversity or not.
+ * Drivers may reject configurations or RX/TX mask combinations they cannot
+ * support by returning -EINVAL.
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_RX: Bitmap of allowed antennas for receiving.
+ * This can be used to mask out antennas which are not attached or should
+ * not be used for receiving. If an antenna is not selected in this bitmap
+ * the hardware should not be configured to receive on this antenna.
+ * For a more detailed description see @NL80211_ATTR_WIPHY_ANTENNA_TX.
+ *
+ * @NL80211_ATTR_MCAST_RATE: Multicast tx rate (in 100 kbps) for IBSS
+ *
+ * @NL80211_ATTR_OFFCHANNEL_TX_OK: For management frame TX, the frame may be
+ * transmitted on another channel when the channel given doesn't match
+ * the current channel. If the current channel doesn't match and this
+ * flag isn't set, the frame will be rejected. This is also used as an
+ * nl80211 capability flag.
+ *
+ * @NL80211_ATTR_BSS_HTOPMODE: HT operation mode (u16)
+ *
+ * @NL80211_ATTR_MAX: highest attribute number currently defined
+ * @__NL80211_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_attrs {
+/* don't change the order or add anything between, this is ABI! */
+ NL80211_ATTR_UNSPEC,
+
+ NL80211_ATTR_WIPHY,
+ NL80211_ATTR_WIPHY_NAME,
+
+ NL80211_ATTR_IFINDEX,
+ NL80211_ATTR_IFNAME,
+ NL80211_ATTR_IFTYPE,
+
+ NL80211_ATTR_MAC,
+
+ NL80211_ATTR_KEY_DATA,
+ NL80211_ATTR_KEY_IDX,
+ NL80211_ATTR_KEY_CIPHER,
+ NL80211_ATTR_KEY_SEQ,
+ NL80211_ATTR_KEY_DEFAULT,
+
+ NL80211_ATTR_BEACON_INTERVAL,
+ NL80211_ATTR_DTIM_PERIOD,
+ NL80211_ATTR_BEACON_HEAD,
+ NL80211_ATTR_BEACON_TAIL,
+
+ NL80211_ATTR_STA_AID,
+ NL80211_ATTR_STA_FLAGS,
+ NL80211_ATTR_STA_LISTEN_INTERVAL,
+ NL80211_ATTR_STA_SUPPORTED_RATES,
+ NL80211_ATTR_STA_VLAN,
+ NL80211_ATTR_STA_INFO,
+
+ NL80211_ATTR_WIPHY_BANDS,
+
+ NL80211_ATTR_MNTR_FLAGS,
+
+ NL80211_ATTR_MESH_ID,
+ NL80211_ATTR_STA_PLINK_ACTION,
+ NL80211_ATTR_MPATH_NEXT_HOP,
+ NL80211_ATTR_MPATH_INFO,
+
+ NL80211_ATTR_BSS_CTS_PROT,
+ NL80211_ATTR_BSS_SHORT_PREAMBLE,
+ NL80211_ATTR_BSS_SHORT_SLOT_TIME,
+
+ NL80211_ATTR_HT_CAPABILITY,
+
+ NL80211_ATTR_SUPPORTED_IFTYPES,
+
+ NL80211_ATTR_REG_ALPHA2,
+ NL80211_ATTR_REG_RULES,
+
+ NL80211_ATTR_MESH_PARAMS,
+
+ NL80211_ATTR_BSS_BASIC_RATES,
+
+ NL80211_ATTR_WIPHY_TXQ_PARAMS,
+ NL80211_ATTR_WIPHY_FREQ,
+ NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+
+ NL80211_ATTR_KEY_DEFAULT_MGMT,
+
+ NL80211_ATTR_MGMT_SUBTYPE,
+ NL80211_ATTR_IE,
+
+ NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
+
+ NL80211_ATTR_SCAN_FREQUENCIES,
+ NL80211_ATTR_SCAN_SSIDS,
+ NL80211_ATTR_GENERATION, /* replaces old SCAN_GENERATION */
+ NL80211_ATTR_BSS,
+
+ NL80211_ATTR_REG_INITIATOR,
+ NL80211_ATTR_REG_TYPE,
+
+ NL80211_ATTR_SUPPORTED_COMMANDS,
+
+ NL80211_ATTR_FRAME,
+ NL80211_ATTR_SSID,
+ NL80211_ATTR_AUTH_TYPE,
+ NL80211_ATTR_REASON_CODE,
+
+ NL80211_ATTR_KEY_TYPE,
+
+ NL80211_ATTR_MAX_SCAN_IE_LEN,
+ NL80211_ATTR_CIPHER_SUITES,
+
+ NL80211_ATTR_FREQ_BEFORE,
+ NL80211_ATTR_FREQ_AFTER,
+
+ NL80211_ATTR_FREQ_FIXED,
+
+
+ NL80211_ATTR_WIPHY_RETRY_SHORT,
+ NL80211_ATTR_WIPHY_RETRY_LONG,
+ NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
+ NL80211_ATTR_WIPHY_RTS_THRESHOLD,
+
+ NL80211_ATTR_TIMED_OUT,
+
+ NL80211_ATTR_USE_MFP,
+
+ NL80211_ATTR_STA_FLAGS2,
+
+ NL80211_ATTR_CONTROL_PORT,
+
+ NL80211_ATTR_TESTDATA,
+
+ NL80211_ATTR_PRIVACY,
+
+ NL80211_ATTR_DISCONNECTED_BY_AP,
+ NL80211_ATTR_STATUS_CODE,
+
+ NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+ NL80211_ATTR_CIPHER_SUITE_GROUP,
+ NL80211_ATTR_WPA_VERSIONS,
+ NL80211_ATTR_AKM_SUITES,
+
+ NL80211_ATTR_REQ_IE,
+ NL80211_ATTR_RESP_IE,
+
+ NL80211_ATTR_PREV_BSSID,
+
+ NL80211_ATTR_KEY,
+ NL80211_ATTR_KEYS,
+
+ NL80211_ATTR_PID,
+
+ NL80211_ATTR_4ADDR,
+
+ NL80211_ATTR_SURVEY_INFO,
+
+ NL80211_ATTR_PMKID,
+ NL80211_ATTR_MAX_NUM_PMKIDS,
+
+ NL80211_ATTR_DURATION,
+
+ NL80211_ATTR_COOKIE,
+
+ NL80211_ATTR_WIPHY_COVERAGE_CLASS,
+
+ NL80211_ATTR_TX_RATES,
+
+ NL80211_ATTR_FRAME_MATCH,
+
+ NL80211_ATTR_ACK,
+
+ NL80211_ATTR_PS_STATE,
+
+ NL80211_ATTR_CQM,
+
+ NL80211_ATTR_LOCAL_STATE_CHANGE,
+
+ NL80211_ATTR_AP_ISOLATE,
+
+ NL80211_ATTR_WIPHY_TX_POWER_SETTING,
+ NL80211_ATTR_WIPHY_TX_POWER_LEVEL,
+
+ NL80211_ATTR_TX_FRAME_TYPES,
+ NL80211_ATTR_RX_FRAME_TYPES,
+ NL80211_ATTR_FRAME_TYPE,
+
+ NL80211_ATTR_CONTROL_PORT_ETHERTYPE,
+ NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT,
+
+ NL80211_ATTR_SUPPORT_IBSS_RSN,
+
+ NL80211_ATTR_WIPHY_ANTENNA_TX,
+ NL80211_ATTR_WIPHY_ANTENNA_RX,
+
+ NL80211_ATTR_MCAST_RATE,
+
+ NL80211_ATTR_OFFCHANNEL_TX_OK,
+
+ NL80211_ATTR_BSS_HT_OPMODE,
+
+ /* add attributes here, update the policy in nl80211.c */
+
+ __NL80211_ATTR_AFTER_LAST,
+ NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
+};
+
+/* source-level API compatibility */
+#define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
+
+/*
+ * Allow user space programs to use #ifdef on new attributes by defining them
+ * here
+ */
+#define NL80211_CMD_CONNECT NL80211_CMD_CONNECT
+#define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY
+#define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES
+#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS
+#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ
+#define NL80211_ATTR_WIPHY_CHANNEL_TYPE NL80211_ATTR_WIPHY_CHANNEL_TYPE
+#define NL80211_ATTR_MGMT_SUBTYPE NL80211_ATTR_MGMT_SUBTYPE
+#define NL80211_ATTR_IE NL80211_ATTR_IE
+#define NL80211_ATTR_REG_INITIATOR NL80211_ATTR_REG_INITIATOR
+#define NL80211_ATTR_REG_TYPE NL80211_ATTR_REG_TYPE
+#define NL80211_ATTR_FRAME NL80211_ATTR_FRAME
+#define NL80211_ATTR_SSID NL80211_ATTR_SSID
+#define NL80211_ATTR_AUTH_TYPE NL80211_ATTR_AUTH_TYPE
+#define NL80211_ATTR_REASON_CODE NL80211_ATTR_REASON_CODE
+#define NL80211_ATTR_CIPHER_SUITES_PAIRWISE NL80211_ATTR_CIPHER_SUITES_PAIRWISE
+#define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP
+#define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS
+#define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
+#define NL80211_ATTR_KEY NL80211_ATTR_KEY
+#define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
+
+#define NL80211_MAX_SUPP_RATES 32
+#define NL80211_MAX_SUPP_REG_RULES 32
+#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0
+#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16
+#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24
+#define NL80211_HT_CAPABILITY_LEN 26
+
+#define NL80211_MAX_NR_CIPHER_SUITES 5
+#define NL80211_MAX_NR_AKM_SUITES 2
+
+/**
+ * enum nl80211_iftype - (virtual) interface types
+ *
+ * @NL80211_IFTYPE_UNSPECIFIED: unspecified type, driver decides
+ * @NL80211_IFTYPE_ADHOC: independent BSS member
+ * @NL80211_IFTYPE_STATION: managed BSS member
+ * @NL80211_IFTYPE_AP: access point
+ * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points
+ * @NL80211_IFTYPE_WDS: wireless distribution interface
+ * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
+ * @NL80211_IFTYPE_MESH_POINT: mesh point
+ * @NL80211_IFTYPE_P2P_CLIENT: P2P client
+ * @NL80211_IFTYPE_P2P_GO: P2P group owner
+ * @NL80211_IFTYPE_MAX: highest interface type number currently defined
+ * @NUM_NL80211_IFTYPES: number of defined interface types
+ *
+ * These values are used with the %NL80211_ATTR_IFTYPE
+ * to set the type of an interface.
+ *
+ */
+enum nl80211_iftype {
+ NL80211_IFTYPE_UNSPECIFIED,
+ NL80211_IFTYPE_ADHOC,
+ NL80211_IFTYPE_STATION,
+ NL80211_IFTYPE_AP,
+ NL80211_IFTYPE_AP_VLAN,
+ NL80211_IFTYPE_WDS,
+ NL80211_IFTYPE_MONITOR,
+ NL80211_IFTYPE_MESH_POINT,
+ NL80211_IFTYPE_P2P_CLIENT,
+ NL80211_IFTYPE_P2P_GO,
+
+ /* keep last */
+ NUM_NL80211_IFTYPES,
+ NL80211_IFTYPE_MAX = NUM_NL80211_IFTYPES - 1
+};
+
+/**
+ * enum nl80211_sta_flags - station flags
+ *
+ * Station flags. When a station is added to an AP interface, it is
+ * assumed to be already associated (and hence authenticated.)
+ *
+ * @__NL80211_STA_FLAG_INVALID: attribute number 0 is reserved
+ * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X)
+ * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
+ * with short barker preamble
+ * @NL80211_STA_FLAG_WME: station is WME/QoS capable
+ * @NL80211_STA_FLAG_MFP: station uses management frame protection
+ * @NL80211_STA_FLAG_MAX: highest station flag number currently defined
+ * @__NL80211_STA_FLAG_AFTER_LAST: internal use
+ */
+enum nl80211_sta_flags {
+ __NL80211_STA_FLAG_INVALID,
+ NL80211_STA_FLAG_AUTHORIZED,
+ NL80211_STA_FLAG_SHORT_PREAMBLE,
+ NL80211_STA_FLAG_WME,
+ NL80211_STA_FLAG_MFP,
+
+ /* keep last */
+ __NL80211_STA_FLAG_AFTER_LAST,
+ NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
+};
+
+/**
+ * struct nl80211_sta_flag_update - station flags mask/set
+ * @mask: mask of station flags to set
+ * @set: which values to set them to
+ *
+ * Both mask and set contain bits as per &enum nl80211_sta_flags.
+ */
+struct nl80211_sta_flag_update {
+ __u32 mask;
+ __u32 set;
+} __attribute__((packed));
+
+/**
+ * enum nl80211_rate_info - bitrate information
+ *
+ * These attribute types are used with %NL80211_STA_INFO_TXRATE
+ * when getting information about the bitrate of a station.
+ *
+ * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
+ * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
+ * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 MHz dualchannel bitrate
+ * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
+ * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
+ * @__NL80211_RATE_INFO_AFTER_LAST: internal use
+ */
+enum nl80211_rate_info {
+ __NL80211_RATE_INFO_INVALID,
+ NL80211_RATE_INFO_BITRATE,
+ NL80211_RATE_INFO_MCS,
+ NL80211_RATE_INFO_40_MHZ_WIDTH,
+ NL80211_RATE_INFO_SHORT_GI,
+
+ /* keep last */
+ __NL80211_RATE_INFO_AFTER_LAST,
+ NL80211_RATE_INFO_MAX = __NL80211_RATE_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_sta_info - station information
+ *
+ * These attribute types are used with %NL80211_ATTR_STA_INFO
+ * when getting information about a station.
+ *
+ * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
+ * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
+ * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
+ * @__NL80211_STA_INFO_AFTER_LAST: internal
+ * @NL80211_STA_INFO_MAX: highest possible station info attribute
+ * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
+ * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
+ * containing info as possible, see &enum nl80211_sta_info_txrate.
+ * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station)
+ * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this
+ * station)
+ * @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station)
+ * @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station)
+ * @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm)
+ */
+enum nl80211_sta_info {
+ __NL80211_STA_INFO_INVALID,
+ NL80211_STA_INFO_INACTIVE_TIME,
+ NL80211_STA_INFO_RX_BYTES,
+ NL80211_STA_INFO_TX_BYTES,
+ NL80211_STA_INFO_LLID,
+ NL80211_STA_INFO_PLID,
+ NL80211_STA_INFO_PLINK_STATE,
+ NL80211_STA_INFO_SIGNAL,
+ NL80211_STA_INFO_TX_BITRATE,
+ NL80211_STA_INFO_RX_PACKETS,
+ NL80211_STA_INFO_TX_PACKETS,
+ NL80211_STA_INFO_TX_RETRIES,
+ NL80211_STA_INFO_TX_FAILED,
+ NL80211_STA_INFO_SIGNAL_AVG,
+
+ /* keep last */
+ __NL80211_STA_INFO_AFTER_LAST,
+ NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_mpath_flags - nl80211 mesh path flags
+ *
+ * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active
+ * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running
+ * @NL80211_MPATH_FLAG_SN_VALID: the mesh path contains a valid SN
+ * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set
+ * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded
+ */
+enum nl80211_mpath_flags {
+ NL80211_MPATH_FLAG_ACTIVE = 1<<0,
+ NL80211_MPATH_FLAG_RESOLVING = 1<<1,
+ NL80211_MPATH_FLAG_SN_VALID = 1<<2,
+ NL80211_MPATH_FLAG_FIXED = 1<<3,
+ NL80211_MPATH_FLAG_RESOLVED = 1<<4,
+};
+
+/**
+ * enum nl80211_mpath_info - mesh path information
+ *
+ * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting
+ * information about a mesh path.
+ *
+ * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_MPATH_INFO_FRAME_QLEN: number of queued frames for this destination
+ * @NL80211_MPATH_INFO_SN: destination sequence number
+ * @NL80211_MPATH_INFO_METRIC: metric (cost) of this mesh path
+ * @NL80211_MPATH_INFO_EXPTIME: expiration time for the path, in msec from now
+ * @NL80211_MPATH_INFO_FLAGS: mesh path flags, enumerated in
+ * &enum nl80211_mpath_flags;
+ * @NL80211_MPATH_INFO_DISCOVERY_TIMEOUT: total path discovery timeout, in msec
+ * @NL80211_MPATH_INFO_DISCOVERY_RETRIES: mesh path discovery retries
+ * @NL80211_MPATH_INFO_MAX: highest mesh path information attribute number
+ * currently defind
+ * @__NL80211_MPATH_INFO_AFTER_LAST: internal use
+ */
+enum nl80211_mpath_info {
+ __NL80211_MPATH_INFO_INVALID,
+ NL80211_MPATH_INFO_FRAME_QLEN,
+ NL80211_MPATH_INFO_SN,
+ NL80211_MPATH_INFO_METRIC,
+ NL80211_MPATH_INFO_EXPTIME,
+ NL80211_MPATH_INFO_FLAGS,
+ NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
+ NL80211_MPATH_INFO_DISCOVERY_RETRIES,
+
+ /* keep last */
+ __NL80211_MPATH_INFO_AFTER_LAST,
+ NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_band_attr - band attributes
+ * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band,
+ * an array of nested frequency attributes
+ * @NL80211_BAND_ATTR_RATES: supported bitrates in this band,
+ * an array of nested bitrate attributes
+ * @NL80211_BAND_ATTR_HT_MCS_SET: 16-byte attribute containing the MCS set as
+ * defined in 802.11n
+ * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE
+ * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n
+ * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n
+ * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined
+ * @__NL80211_BAND_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_band_attr {
+ __NL80211_BAND_ATTR_INVALID,
+ NL80211_BAND_ATTR_FREQS,
+ NL80211_BAND_ATTR_RATES,
+
+ NL80211_BAND_ATTR_HT_MCS_SET,
+ NL80211_BAND_ATTR_HT_CAPA,
+ NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
+ NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
+
+ /* keep last */
+ __NL80211_BAND_ATTR_AFTER_LAST,
+ NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
+};
+
+#define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA
+
+/**
+ * enum nl80211_frequency_attr - frequency attributes
+ * @__NL80211_FREQUENCY_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
+ * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current
+ * regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is
+ * permitted on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted
+ * on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
+ * on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
+ * (100 * dBm).
+ * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
+ * currently defined
+ * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_frequency_attr {
+ __NL80211_FREQUENCY_ATTR_INVALID,
+ NL80211_FREQUENCY_ATTR_FREQ,
+ NL80211_FREQUENCY_ATTR_DISABLED,
+ NL80211_FREQUENCY_ATTR_PASSIVE_SCAN,
+ NL80211_FREQUENCY_ATTR_NO_IBSS,
+ NL80211_FREQUENCY_ATTR_RADAR,
+ NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
+
+ /* keep last */
+ __NL80211_FREQUENCY_ATTR_AFTER_LAST,
+ NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1
+};
+
+#define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER
+
+/**
+ * enum nl80211_bitrate_attr - bitrate attributes
+ * @__NL80211_BITRATE_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps
+ * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported
+ * in 2.4 GHz band.
+ * @NL80211_BITRATE_ATTR_MAX: highest bitrate attribute number
+ * currently defined
+ * @__NL80211_BITRATE_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_bitrate_attr {
+ __NL80211_BITRATE_ATTR_INVALID,
+ NL80211_BITRATE_ATTR_RATE,
+ NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE,
+
+ /* keep last */
+ __NL80211_BITRATE_ATTR_AFTER_LAST,
+ NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_initiator - Indicates the initiator of a reg domain request
+ * @NL80211_REGDOM_SET_BY_CORE: Core queried CRDA for a dynamic world
+ * regulatory domain.
+ * @NL80211_REGDOM_SET_BY_USER: User asked the wireless core to set the
+ * regulatory domain.
+ * @NL80211_REGDOM_SET_BY_DRIVER: a wireless drivers has hinted to the
+ * wireless core it thinks its knows the regulatory domain we should be in.
+ * @NL80211_REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an
+ * 802.11 country information element with regulatory information it
+ * thinks we should consider. cfg80211 only processes the country
+ * code from the IE, and relies on the regulatory domain information
+ * structure passed by userspace (CRDA) from our wireless-regdb.
+ * If a channel is enabled but the country code indicates it should
+ * be disabled we disable the channel and re-enable it upon disassociation.
+ */
+enum nl80211_reg_initiator {
+ NL80211_REGDOM_SET_BY_CORE,
+ NL80211_REGDOM_SET_BY_USER,
+ NL80211_REGDOM_SET_BY_DRIVER,
+ NL80211_REGDOM_SET_BY_COUNTRY_IE,
+};
+
+/**
+ * enum nl80211_reg_type - specifies the type of regulatory domain
+ * @NL80211_REGDOM_TYPE_COUNTRY: the regulatory domain set is one that pertains
+ * to a specific country. When this is set you can count on the
+ * ISO / IEC 3166 alpha2 country code being valid.
+ * @NL80211_REGDOM_TYPE_WORLD: the regulatory set domain is the world regulatory
+ * domain.
+ * @NL80211_REGDOM_TYPE_CUSTOM_WORLD: the regulatory domain set is a custom
+ * driver specific world regulatory domain. These do not apply system-wide
+ * and are only applicable to the individual devices which have requested
+ * them to be applied.
+ * @NL80211_REGDOM_TYPE_INTERSECTION: the regulatory domain set is the product
+ * of an intersection between two regulatory domains -- the previously
+ * set regulatory domain on the system and the last accepted regulatory
+ * domain request to be processed.
+ */
+enum nl80211_reg_type {
+ NL80211_REGDOM_TYPE_COUNTRY,
+ NL80211_REGDOM_TYPE_WORLD,
+ NL80211_REGDOM_TYPE_CUSTOM_WORLD,
+ NL80211_REGDOM_TYPE_INTERSECTION,
+};
+
+/**
+ * enum nl80211_reg_rule_attr - regulatory rule attributes
+ * @__NL80211_REG_RULE_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional
+ * considerations for a given frequency range. These are the
+ * &enum nl80211_reg_rule_flags.
+ * @NL80211_ATTR_FREQ_RANGE_START: starting frequencry for the regulatory
+ * rule in KHz. This is not a center of frequency but an actual regulatory
+ * band edge.
+ * @NL80211_ATTR_FREQ_RANGE_END: ending frequency for the regulatory rule
+ * in KHz. This is not a center a frequency but an actual regulatory
+ * band edge.
+ * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this
+ * frequency range, in KHz.
+ * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain
+ * for a given frequency range. The value is in mBi (100 * dBi).
+ * If you don't have one then don't send this.
+ * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for
+ * a given frequency range. The value is in mBm (100 * dBm).
+ * @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number
+ * currently defined
+ * @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_reg_rule_attr {
+ __NL80211_REG_RULE_ATTR_INVALID,
+ NL80211_ATTR_REG_RULE_FLAGS,
+
+ NL80211_ATTR_FREQ_RANGE_START,
+ NL80211_ATTR_FREQ_RANGE_END,
+ NL80211_ATTR_FREQ_RANGE_MAX_BW,
+
+ NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
+ NL80211_ATTR_POWER_RULE_MAX_EIRP,
+
+ /* keep last */
+ __NL80211_REG_RULE_ATTR_AFTER_LAST,
+ NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_reg_rule_flags - regulatory rule flags
+ *
+ * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed
+ * @NL80211_RRF_NO_CCK: CCK modulation not allowed
+ * @NL80211_RRF_NO_INDOOR: indoor operation not allowed
+ * @NL80211_RRF_NO_OUTDOOR: outdoor operation not allowed
+ * @NL80211_RRF_DFS: DFS support is required to be used
+ * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links
+ * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links
+ * @NL80211_RRF_PASSIVE_SCAN: passive scan is required
+ * @NL80211_RRF_NO_IBSS: no IBSS is allowed
+ */
+enum nl80211_reg_rule_flags {
+ NL80211_RRF_NO_OFDM = 1<<0,
+ NL80211_RRF_NO_CCK = 1<<1,
+ NL80211_RRF_NO_INDOOR = 1<<2,
+ NL80211_RRF_NO_OUTDOOR = 1<<3,
+ NL80211_RRF_DFS = 1<<4,
+ NL80211_RRF_PTP_ONLY = 1<<5,
+ NL80211_RRF_PTMP_ONLY = 1<<6,
+ NL80211_RRF_PASSIVE_SCAN = 1<<7,
+ NL80211_RRF_NO_IBSS = 1<<8,
+};
+
+/**
+ * enum nl80211_survey_info - survey information
+ *
+ * These attribute types are used with %NL80211_ATTR_SURVEY_INFO
+ * when getting information about a survey.
+ *
+ * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel
+ * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm)
+ * @NL80211_SURVEY_INFO_IN_USE: channel is currently being used
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME: amount of time (in ms) that the radio
+ * spent on this channel
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY: amount of the time the primary
+ * channel was sensed busy (either due to activity or energy detect)
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY: amount of time the extension
+ * channel was sensed busy
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_RX: amount of time the radio spent
+ * receiving data
+ * @NL80211_SURVEY_INFO_CHANNEL_TIME_TX: amount of time the radio spent
+ * transmitting data
+ * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
+ * currently defined
+ * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
+ */
+enum nl80211_survey_info {
+ __NL80211_SURVEY_INFO_INVALID,
+ NL80211_SURVEY_INFO_FREQUENCY,
+ NL80211_SURVEY_INFO_NOISE,
+ NL80211_SURVEY_INFO_IN_USE,
+ NL80211_SURVEY_INFO_CHANNEL_TIME,
+ NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY,
+ NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY,
+ NL80211_SURVEY_INFO_CHANNEL_TIME_RX,
+ NL80211_SURVEY_INFO_CHANNEL_TIME_TX,
+
+ /* keep last */
+ __NL80211_SURVEY_INFO_AFTER_LAST,
+ NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_mntr_flags - monitor configuration flags
+ *
+ * Monitor configuration flags.
+ *
+ * @__NL80211_MNTR_FLAG_INVALID: reserved
+ *
+ * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS
+ * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP
+ * @NL80211_MNTR_FLAG_CONTROL: pass control frames
+ * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering
+ * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing.
+ * overrides all other flags.
+ *
+ * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
+ * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
+ */
+enum nl80211_mntr_flags {
+ __NL80211_MNTR_FLAG_INVALID,
+ NL80211_MNTR_FLAG_FCSFAIL,
+ NL80211_MNTR_FLAG_PLCPFAIL,
+ NL80211_MNTR_FLAG_CONTROL,
+ NL80211_MNTR_FLAG_OTHER_BSS,
+ NL80211_MNTR_FLAG_COOK_FRAMES,
+
+ /* keep last */
+ __NL80211_MNTR_FLAG_AFTER_LAST,
+ NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_meshconf_params - mesh configuration parameters
+ *
+ * Mesh configuration parameters
+ *
+ * @__NL80211_MESHCONF_INVALID: internal use
+ *
+ * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in
+ * millisecond units, used by the Peer Link Open message
+ *
+ * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the initial confirm timeout, in
+ * millisecond units, used by the peer link management to close a peer link
+ *
+ * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in
+ * millisecond units
+ *
+ * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed
+ * on this mesh interface
+ *
+ * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link
+ * open retries that can be sent to establish a new peer link instance in a
+ * mesh
+ *
+ * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
+ * point.
+ *
+ * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
+ * source mesh point for path selection elements.
+ *
+ * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
+ * open peer links when we detect compatible mesh peers.
+ *
+ * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames
+ * containing a PREQ that an MP can send to a particular destination (path
+ * target)
+ *
+ * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths
+ * (in milliseconds)
+ *
+ * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait
+ * until giving up on a path discovery (in milliseconds)
+ *
+ * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh
+ * points receiving a PREQ shall consider the forwarding information from the
+ * root to be valid. (TU = time unit)
+ *
+ * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in
+ * TUs) during which an MP can send only one action frame containing a PREQ
+ * reference element
+ *
+ * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs)
+ * that it takes for an HWMP information element to propagate across the mesh
+ *
+ * @NL80211_MESHCONF_ROOTMODE: whether root mode is enabled or not
+ *
+ * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
+ *
+ * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_meshconf_params {
+ __NL80211_MESHCONF_INVALID,
+ NL80211_MESHCONF_RETRY_TIMEOUT,
+ NL80211_MESHCONF_CONFIRM_TIMEOUT,
+ NL80211_MESHCONF_HOLDING_TIMEOUT,
+ NL80211_MESHCONF_MAX_PEER_LINKS,
+ NL80211_MESHCONF_MAX_RETRIES,
+ NL80211_MESHCONF_TTL,
+ NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+ NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
+ NL80211_MESHCONF_PATH_REFRESH_TIME,
+ NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
+ NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
+ NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
+ NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
+ NL80211_MESHCONF_HWMP_ROOTMODE,
+ NL80211_MESHCONF_ELEMENT_TTL,
+
+ /* keep last */
+ __NL80211_MESHCONF_ATTR_AFTER_LAST,
+ NL80211_MESHCONF_ATTR_MAX = __NL80211_MESHCONF_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_txq_attr - TX queue parameter attributes
+ * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved
+ * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*)
+ * @NL80211_TXQ_ATTR_TXOP: Maximum burst time in units of 32 usecs, 0 meaning
+ * disabled
+ * @NL80211_TXQ_ATTR_CWMIN: Minimum contention window [a value of the form
+ * 2^n-1 in the range 1..32767]
+ * @NL80211_TXQ_ATTR_CWMAX: Maximum contention window [a value of the form
+ * 2^n-1 in the range 1..32767]
+ * @NL80211_TXQ_ATTR_AIFS: Arbitration interframe space [0..255]
+ * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal
+ * @NL80211_TXQ_ATTR_MAX: Maximum TXQ attribute number
+ */
+enum nl80211_txq_attr {
+ __NL80211_TXQ_ATTR_INVALID,
+ NL80211_TXQ_ATTR_QUEUE,
+ NL80211_TXQ_ATTR_TXOP,
+ NL80211_TXQ_ATTR_CWMIN,
+ NL80211_TXQ_ATTR_CWMAX,
+ NL80211_TXQ_ATTR_AIFS,
+
+ /* keep last */
+ __NL80211_TXQ_ATTR_AFTER_LAST,
+ NL80211_TXQ_ATTR_MAX = __NL80211_TXQ_ATTR_AFTER_LAST - 1
+};
+
+enum nl80211_txq_q {
+ NL80211_TXQ_Q_VO,
+ NL80211_TXQ_Q_VI,
+ NL80211_TXQ_Q_BE,
+ NL80211_TXQ_Q_BK
+};
+
+enum nl80211_channel_type {
+ NL80211_CHAN_NO_HT,
+ NL80211_CHAN_HT20,
+ NL80211_CHAN_HT40MINUS,
+ NL80211_CHAN_HT40PLUS
+};
+
+/**
+ * enum nl80211_bss - netlink attributes for a BSS
+ *
+ * @__NL80211_BSS_INVALID: invalid
+ * @NL80211_BSS_BSSID: BSSID of the BSS (6 octets)
+ * @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
+ * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
+ * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
+ * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
+ * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
+ * raw information elements from the probe response/beacon (bin);
+ * if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are
+ * from a Probe Response frame; otherwise they are from a Beacon frame.
+ * However, if the driver does not indicate the source of the IEs, these
+ * IEs may be from either frame subtype.
+ * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
+ * in mBm (100 * dBm) (s32)
+ * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
+ * in unspecified units, scaled to 0..100 (u8)
+ * @NL80211_BSS_STATUS: status, if this BSS is "used"
+ * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms
+ * @NL80211_BSS_BEACON_IES: binary attribute containing the raw information
+ * elements from a Beacon frame (bin); not present if no Beacon frame has
+ * yet been received
+ * @__NL80211_BSS_AFTER_LAST: internal
+ * @NL80211_BSS_MAX: highest BSS attribute
+ */
+enum nl80211_bss {
+ __NL80211_BSS_INVALID,
+ NL80211_BSS_BSSID,
+ NL80211_BSS_FREQUENCY,
+ NL80211_BSS_TSF,
+ NL80211_BSS_BEACON_INTERVAL,
+ NL80211_BSS_CAPABILITY,
+ NL80211_BSS_INFORMATION_ELEMENTS,
+ NL80211_BSS_SIGNAL_MBM,
+ NL80211_BSS_SIGNAL_UNSPEC,
+ NL80211_BSS_STATUS,
+ NL80211_BSS_SEEN_MS_AGO,
+ NL80211_BSS_BEACON_IES,
+
+ /* keep last */
+ __NL80211_BSS_AFTER_LAST,
+ NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_bss_status - BSS "status"
+ * @NL80211_BSS_STATUS_AUTHENTICATED: Authenticated with this BSS.
+ * @NL80211_BSS_STATUS_ASSOCIATED: Associated with this BSS.
+ * @NL80211_BSS_STATUS_IBSS_JOINED: Joined to this IBSS.
+ *
+ * The BSS status is a BSS attribute in scan dumps, which
+ * indicates the status the interface has wrt. this BSS.
+ */
+enum nl80211_bss_status {
+ NL80211_BSS_STATUS_AUTHENTICATED,
+ NL80211_BSS_STATUS_ASSOCIATED,
+ NL80211_BSS_STATUS_IBSS_JOINED,
+};
+
+/**
+ * enum nl80211_auth_type - AuthenticationType
+ *
+ * @NL80211_AUTHTYPE_OPEN_SYSTEM: Open System authentication
+ * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only)
+ * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r)
+ * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP)
+ * @__NL80211_AUTHTYPE_NUM: internal
+ * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm
+ * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by
+ * trying multiple times); this is invalid in netlink -- leave out
+ * the attribute for this on CONNECT commands.
+ */
+enum nl80211_auth_type {
+ NL80211_AUTHTYPE_OPEN_SYSTEM,
+ NL80211_AUTHTYPE_SHARED_KEY,
+ NL80211_AUTHTYPE_FT,
+ NL80211_AUTHTYPE_NETWORK_EAP,
+
+ /* keep last */
+ __NL80211_AUTHTYPE_NUM,
+ NL80211_AUTHTYPE_MAX = __NL80211_AUTHTYPE_NUM - 1,
+ NL80211_AUTHTYPE_AUTOMATIC
+};
+
+/**
+ * enum nl80211_key_type - Key Type
+ * @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key
+ * @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key
+ * @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS)
+ * @NUM_NL80211_KEYTYPES: number of defined key types
+ */
+enum nl80211_key_type {
+ NL80211_KEYTYPE_GROUP,
+ NL80211_KEYTYPE_PAIRWISE,
+ NL80211_KEYTYPE_PEERKEY,
+
+ NUM_NL80211_KEYTYPES
+};
+
+/**
+ * enum nl80211_mfp - Management frame protection state
+ * @NL80211_MFP_NO: Management frame protection not used
+ * @NL80211_MFP_REQUIRED: Management frame protection required
+ */
+enum nl80211_mfp {
+ NL80211_MFP_NO,
+ NL80211_MFP_REQUIRED,
+};
+
+enum nl80211_wpa_versions {
+ NL80211_WPA_VERSION_1 = 1 << 0,
+ NL80211_WPA_VERSION_2 = 1 << 1,
+};
+
+/**
+ * enum nl80211_key_attributes - key attributes
+ * @__NL80211_KEY_INVALID: invalid
+ * @NL80211_KEY_DATA: (temporal) key data; for TKIP this consists of
+ * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ * keys
+ * @NL80211_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ * section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ * CCMP keys, each six bytes in little endian
+ * @NL80211_KEY_DEFAULT: flag indicating default key
+ * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key
+ * @NL80211_KEY_TYPE: the key type from enum nl80211_key_type, if not
+ * specified the default depends on whether a MAC address was
+ * given with the command using the key or not (u32)
+ * @__NL80211_KEY_AFTER_LAST: internal
+ * @NL80211_KEY_MAX: highest key attribute
+ */
+enum nl80211_key_attributes {
+ __NL80211_KEY_INVALID,
+ NL80211_KEY_DATA,
+ NL80211_KEY_IDX,
+ NL80211_KEY_CIPHER,
+ NL80211_KEY_SEQ,
+ NL80211_KEY_DEFAULT,
+ NL80211_KEY_DEFAULT_MGMT,
+ NL80211_KEY_TYPE,
+
+ /* keep last */
+ __NL80211_KEY_AFTER_LAST,
+ NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_tx_rate_attributes - TX rate set attributes
+ * @__NL80211_TXRATE_INVALID: invalid
+ * @NL80211_TXRATE_LEGACY: Legacy (non-MCS) rates allowed for TX rate selection
+ * in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with
+ * 1 = 500 kbps) but without the IE length restriction (at most
+ * %NL80211_MAX_SUPP_RATES in a single array).
+ * @__NL80211_TXRATE_AFTER_LAST: internal
+ * @NL80211_TXRATE_MAX: highest TX rate attribute
+ */
+enum nl80211_tx_rate_attributes {
+ __NL80211_TXRATE_INVALID,
+ NL80211_TXRATE_LEGACY,
+
+ /* keep last */
+ __NL80211_TXRATE_AFTER_LAST,
+ NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_band - Frequency band
+ * @NL80211_BAND_2GHZ: 2.4 GHz ISM band
+ * @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
+ */
+enum nl80211_band {
+ NL80211_BAND_2GHZ,
+ NL80211_BAND_5GHZ,
+};
+
+enum nl80211_ps_state {
+ NL80211_PS_DISABLED,
+ NL80211_PS_ENABLED,
+};
+
+/**
+ * enum nl80211_attr_cqm - connection quality monitor attributes
+ * @__NL80211_ATTR_CQM_INVALID: invalid
+ * @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm. This value specifies
+ * the threshold for the RSSI level at which an event will be sent. Zero
+ * to disable.
+ * @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm. This value specifies
+ * the minimum amount the RSSI level must change after an event before a
+ * new event may be issued (to reduce effects of RSSI oscillation).
+ * @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event
+ * @NL80211_ATTR_CQM_PKT_LOSS_EVENT: a u32 value indicating that this many
+ * consecutive packets were not acknowledged by the peer
+ * @__NL80211_ATTR_CQM_AFTER_LAST: internal
+ * @NL80211_ATTR_CQM_MAX: highest key attribute
+ */
+enum nl80211_attr_cqm {
+ __NL80211_ATTR_CQM_INVALID,
+ NL80211_ATTR_CQM_RSSI_THOLD,
+ NL80211_ATTR_CQM_RSSI_HYST,
+ NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
+ NL80211_ATTR_CQM_PKT_LOSS_EVENT,
+
+ /* keep last */
+ __NL80211_ATTR_CQM_AFTER_LAST,
+ NL80211_ATTR_CQM_MAX = __NL80211_ATTR_CQM_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_cqm_rssi_threshold_event - RSSI threshold event
+ * @NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW: The RSSI level is lower than the
+ * configured threshold
+ * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the
+ * configured threshold
+ */
+enum nl80211_cqm_rssi_threshold_event {
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+};
+
+
+/**
+ * enum nl80211_tx_power_setting - TX power adjustment
+ * @NL80211_TX_POWER_AUTOMATIC: automatically determine transmit power
+ * @NL80211_TX_POWER_LIMITED: limit TX power by the mBm parameter
+ * @NL80211_TX_POWER_FIXED: fix TX power to the mBm parameter
+ */
+enum nl80211_tx_power_setting {
+ NL80211_TX_POWER_AUTOMATIC,
+ NL80211_TX_POWER_LIMITED,
+ NL80211_TX_POWER_FIXED,
+};
+
+#endif /* __LINUX_NL80211_H */
diff --git a/src/tuning/runtime.cpp b/src/tuning/runtime.cpp
new file mode 100644
index 0000000..cb62533
--- /dev/null
+++ b/src/tuning/runtime.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "tuning.h"
+#include "tunable.h"
+#include "unistd.h"
+#include "runtime.h"
+#include <string.h>
+#include <utility>
+#include <iostream>
+#include <fstream>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <limits.h>
+
+#include "../lib.h"
+#include "../devices/runtime_pm.h"
+
+runtime_tunable::runtime_tunable(const char *path, const char *bus, const char *dev, const char *port) : tunable("", 0.4, _("Good"), _("Bad"), _("Unknown"))
+{
+ ifstream file;
+ sprintf(runtime_path, "%s/power/control", path);
+
+
+ sprintf(desc, _("Runtime PM for %s device %s"), bus, dev);
+ if (!device_has_runtime_pm(path))
+ sprintf(desc, _("%s device %s has no runtime power management"), bus, dev);
+
+ if (strcmp(bus, "pci") == 0) {
+ char filename[PATH_MAX];
+ uint16_t vendor = 0, device = 0;
+
+ snprintf(filename, sizeof(filename), "/sys/bus/%s/devices/%s/vendor", bus, dev);
+
+ file.open(filename, ios::in);
+ if (file) {
+ file >> hex >> vendor;
+ file.close();
+ }
+
+
+ snprintf(filename, sizeof(filename), "/sys/bus/%s/devices/%s/device", bus, dev);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> hex >> device;
+ file.close();
+ }
+
+ if (vendor && device) {
+ if (!device_has_runtime_pm(path))
+ sprintf(desc, _("PCI Device %s has no runtime power management"), pci_id_to_name(vendor, device, filename, 4095));
+ else
+ sprintf(desc, _("Runtime PM for PCI Device %s"), pci_id_to_name(vendor, device, filename, 4095));
+ }
+
+ if (string(path).find("ata") != string::npos)
+ sprintf(desc, _("Runtime PM for port %s of PCI device: %s"), port, pci_id_to_name(vendor, device, filename, 4095));
+
+ if (string(path).find("block") != string::npos)
+ sprintf(desc, _("Runtime PM for disk %s"), port);
+
+ }
+ snprintf(toggle_good, sizeof(toggle_good), "echo 'auto' > '%s';", runtime_path);
+ snprintf(toggle_bad, sizeof(toggle_bad), "echo 'on' > '%s';", runtime_path);
+}
+
+int runtime_tunable::good_bad(void)
+{
+ string content;
+
+ content = read_sysfs_string(runtime_path);
+
+ if (strcmp(content.c_str(), "auto") == 0)
+ return TUNE_GOOD;
+
+ return TUNE_BAD;
+}
+
+void runtime_tunable::toggle(void)
+{
+ int good;
+ good = good_bad();
+
+ if (good == TUNE_GOOD) {
+ write_sysfs(runtime_path, "on");
+ return;
+ }
+
+ write_sysfs(runtime_path, "auto");
+}
+
+const char *runtime_tunable::toggle_script(void)
+{
+ int good;
+ good = good_bad();
+
+ if (good == TUNE_GOOD) {
+ return toggle_bad;
+ }
+
+ return toggle_good;
+}
+
+
+void add_runtime_tunables(const char *bus)
+{
+ struct dirent *entry;
+ DIR *dir;
+ char filename[PATH_MAX], port[PATH_MAX];
+ int max_ports = 32, count=0;
+
+ snprintf(filename, sizeof(filename), "/sys/bus/%s/devices/", bus);
+ dir = opendir(filename);
+ if (!dir)
+ return;
+ while (1) {
+ class runtime_tunable *runtime, *runtime_ahci_port, *runtime_ahci_disk;
+
+ entry = readdir(dir);
+
+ if (!entry)
+ break;
+ if (entry->d_name[0] == '.')
+ continue;
+
+ snprintf(filename, sizeof(filename), "/sys/bus/%s/devices/%s/power/control", bus, entry->d_name);
+
+ if (access(filename, R_OK) != 0)
+ continue;
+
+
+ snprintf(filename, sizeof(filename), "/sys/bus/%s/devices/%s", bus, entry->d_name);
+
+ runtime = new class runtime_tunable(filename, bus, entry->d_name, NULL);
+
+ if (!device_has_runtime_pm(filename))
+ all_untunables.push_back(runtime);
+ else
+ all_tunables.push_back(runtime);
+
+ for (int i=0; i < max_ports; i++) {
+ snprintf(port, sizeof(port), "ata%d", i);
+ snprintf(filename, sizeof(filename), "/sys/bus/%s/devices/%s/%s/power/control", bus, entry->d_name, port);
+
+ if (access(filename, R_OK) != 0)
+ continue;
+
+ snprintf(filename, sizeof(filename), "/sys/bus/%s/devices/%s/%s", bus, entry->d_name, port);
+ runtime_ahci_port = new class runtime_tunable(filename, bus, entry->d_name, port);
+
+ if (!device_has_runtime_pm(filename))
+ all_untunables.push_back(runtime_ahci_port);
+ else
+ all_tunables.push_back(runtime_ahci_port);
+ }
+
+ for (char blk = 'a'; blk <= 'z'; blk++)
+ {
+ if (count != 0)
+ break;
+
+ snprintf(filename, sizeof(filename), "/sys/block/sd%c/device/power/control", blk);
+
+ if (access(filename, R_OK) != 0)
+ continue;
+
+ snprintf(port, sizeof(port), "sd%c", blk);
+ snprintf(filename, sizeof(filename), "/sys/block/%s/device", port);
+ runtime_ahci_disk = new class runtime_tunable(filename, bus, entry->d_name, port);
+ if (!device_has_runtime_pm(filename))
+ all_untunables.push_back(runtime_ahci_disk);
+ else
+ all_tunables.push_back(runtime_ahci_disk);
+ }
+ count = 1;
+
+ }
+ closedir(dir);
+}
diff --git a/src/tuning/runtime.h b/src/tuning/runtime.h
new file mode 100644
index 0000000..84a8ef5
--- /dev/null
+++ b/src/tuning/runtime.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_RUNTIME_TUNE_H
+#define _INCLUDE_GUARD_RUNTIME_TUNE_H
+
+#include <vector>
+#include <limits.h>
+
+#include "tunable.h"
+using namespace std;
+
+class runtime_tunable : public tunable {
+ char runtime_path[PATH_MAX];
+public:
+ runtime_tunable(const char *runtime_path, const char *bus, const char *dev, const char *port);
+
+ virtual int good_bad(void);
+
+ virtual void toggle(void);
+
+ virtual const char *toggle_script(void);
+
+};
+
+extern void add_runtime_tunables(const char *bus);
+
+
+#endif
diff --git a/src/tuning/tunable.cpp b/src/tuning/tunable.cpp
new file mode 100644
index 0000000..827b913
--- /dev/null
+++ b/src/tuning/tunable.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "tuning.h"
+#include "tunable.h"
+#include <string.h>
+#include "../lib.h"
+
+vector<class tunable *> all_tunables;
+vector<class tunable *> all_untunables;
+
+
+tunable::tunable(const char *str, double _score, const char *good, const char *bad, const char *neutral)
+{
+ score = _score;
+ pt_strcpy(desc, str);
+ pt_strcpy(good_string, good);
+ pt_strcpy(bad_string, bad);
+ pt_strcpy(neutral_string, neutral);
+}
+
+
+tunable::tunable(void)
+{
+ score = 0;
+ desc[0] = 0;
+ pt_strcpy(good_string, _("Good"));
+ pt_strcpy(bad_string, _("Bad"));
+ pt_strcpy(neutral_string, _("Unknown"));
+}
diff --git a/src/tuning/tunable.h b/src/tuning/tunable.h
new file mode 100644
index 0000000..3372378
--- /dev/null
+++ b/src/tuning/tunable.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_TUNABLE_H
+#define _INCLUDE_GUARD_TUNABLE_H
+
+#include <vector>
+
+#include "../lib.h"
+
+using namespace std;
+
+#define TUNE_GOOD 1
+#define TUNE_BAD -1
+#define TUNE_UNFIXABLE -2
+#define TUNE_UNKNOWN 0
+#define TUNE_NEUTRAL 0
+
+class tunable {
+
+ char good_string[128];
+ char bad_string[128];
+ char neutral_string[128];
+protected:
+ char toggle_good[4096];
+ char toggle_bad[4096];
+public:
+ char desc[4096];
+ double score;
+
+ tunable(void);
+ tunable(const char *str, double _score, const char *good = "", const char *bad = "", const char *neutral ="");
+ virtual ~tunable() {};
+
+ virtual int good_bad(void) { return TUNE_NEUTRAL; }
+
+ virtual char *result_string(void)
+ {
+ switch (good_bad()) {
+ case TUNE_GOOD:
+ return good_string;
+ case TUNE_BAD:
+ case TUNE_UNFIXABLE:
+ return bad_string;
+ }
+ return neutral_string;
+ }
+
+
+ virtual const char *description(void) { return desc; };
+
+ virtual void toggle(void) { };
+
+ virtual const char *toggle_script(void) { return NULL; }
+};
+
+extern vector<class tunable *> all_tunables;
+extern vector<class tunable *> all_untunables;
+
+#endif
diff --git a/src/tuning/tuning.cpp b/src/tuning/tuning.cpp
new file mode 100644
index 0000000..bc34741
--- /dev/null
+++ b/src/tuning/tuning.cpp
@@ -0,0 +1,332 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include <algorithm>
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+
+
+#include "tuning.h"
+#include "tuningi2c.h"
+#include "tuningsysfs.h"
+#include "tuningusb.h"
+#include "runtime.h"
+#include "bluetooth.h"
+#include "ethernet.h"
+#include "wifi.h"
+#include "../display.h"
+#include "../report/report.h"
+#include "../report/report-maker.h"
+#include "../report/report-data-html.h"
+#include "../lib.h"
+
+static void sort_tunables(void);
+static bool should_clear = false;
+
+class tuning_window *tune_window;
+
+class tuning_window: public tab_window {
+public:
+ virtual void repaint(void);
+ virtual void cursor_enter(void);
+ virtual void expose(void);
+ virtual void window_refresh(void);
+};
+
+static void init_tuning(void)
+{
+ add_sysfs_tunable(_("Enable Audio codec power management"), "/sys/module/snd_hda_intel/parameters/power_save", "1");
+ add_sysfs_tunable(_("NMI watchdog should be turned off"), "/proc/sys/kernel/nmi_watchdog", "0");
+ add_sysfs_tunable(_("Power Aware CPU scheduler"), "/sys/devices/system/cpu/sched_mc_power_savings", "1");
+ add_sysfs_tunable(_("VM writeback timeout"), "/proc/sys/vm/dirty_writeback_centisecs", "1500");
+ add_sata_tunables();
+ add_usb_tunables();
+ add_runtime_tunables("pci");
+ add_bt_tunable();
+ add_wifi_tunables();
+ add_i2c_tunables();
+
+ sort_tunables();
+}
+
+void initialize_tuning(void)
+{
+ class tuning_window *w;
+
+ w = new tuning_window();
+ create_tab("Tunables", _("Tunables"), w, _(" <ESC> Exit | <Enter> Toggle tunable | <r> Window refresh"));
+
+ init_tuning();
+
+ w->cursor_max = all_tunables.size() - 1;
+
+ if (tune_window)
+ delete tune_window;
+
+ tune_window = w;
+}
+
+
+
+static void __tuning_update_display(int cursor_pos)
+{
+ WINDOW *win;
+ unsigned int i;
+
+ win = get_ncurses_win("Tunables");
+
+ if (!win)
+ return;
+
+ if (should_clear) {
+ should_clear = false;
+ wclear(win);
+ }
+
+ wmove(win, 2,0);
+
+ for (i = 0; i < all_tunables.size(); i++) {
+ char res[128];
+ char desc[4096];
+ pt_strcpy(res, all_tunables[i]->result_string());
+ pt_strcpy(desc, all_tunables[i]->description());
+ while (strlen(res) < 12)
+ strcat(res, " ");
+
+ while (strlen(desc) < 103)
+ strcat(desc, " ");
+ if ((int)i != cursor_pos) {
+ wattrset(win, A_NORMAL);
+ wprintw(win, " ");
+ } else {
+ wattrset(win, A_REVERSE);
+ wprintw(win, ">> ");
+ }
+ wprintw(win, "%s %s\n", _(res), _(desc));
+ }
+}
+
+void tuning_update_display(void)
+{
+ class tab_window *w;
+
+ w = tab_windows["Tunables"];
+ if (!w)
+ return;
+ w->repaint();
+}
+
+void tuning_window::repaint(void)
+{
+ __tuning_update_display(cursor_pos);
+}
+
+void tuning_window::cursor_enter(void)
+{
+ class tunable *tun;
+ const char *toggle_script;
+ tun = all_tunables[cursor_pos];
+ if (!tun)
+ return;
+ /** device will change its state so need to store toggle script before
+ * we toggle()*/
+ toggle_script = tun->toggle_script();
+ tun->toggle();
+ ui_notify_user(">> %s\n", toggle_script);
+}
+
+static bool tunables_sort(class tunable * i, class tunable * j)
+{
+ int i_g, j_g;
+ double d;
+
+ i_g = i->good_bad();
+ j_g = j->good_bad();
+
+ if (!equals(i_g, j_g))
+ return i_g < j_g;
+
+ d = i->score - j->score;
+ if (d < 0.0)
+ d = -d;
+ if (d > 0.0001)
+ return i->score > j->score;
+
+ if (strcasecmp(i->description(), j->description()) == -1)
+ return true;
+
+ return false;
+}
+
+void tuning_window::window_refresh()
+{
+ clear_tuning();
+ should_clear = true;
+ init_tuning();
+}
+
+static void sort_tunables(void)
+{
+ sort(all_tunables.begin(), all_tunables.end(), tunables_sort);
+}
+
+void tuning_window::expose(void)
+{
+ cursor_pos = 0;
+ sort_tunables();
+ repaint();
+}
+
+void report_show_tunables(void)
+{
+ unsigned int i;
+ /* three tables; bad, unfixable, good */
+ sort_tunables();
+ int idx, rows = 0, cols;
+
+ /* First Table */
+
+ /* div attr css_class and css_id */
+ tag_attr div_attr;
+ init_div(&div_attr, "clear_block", "tuning");
+
+ /* Set Title attributes */
+ tag_attr title_attr;
+ init_title_attr(&title_attr);
+
+ /* Set Table attributes, rows, and cols */
+ table_attributes tune_table_css;
+ cols=2;
+ idx = cols;
+
+ for (i = 0; i < all_tunables.size(); i++) {
+ int tgb;
+ tgb = all_tunables[i]->good_bad();
+ if (tgb == TUNE_BAD)
+ rows+=1;
+ }
+ /* add section */
+ report.add_div(&div_attr);
+
+ if (rows > 0){
+ rows= rows + 1;
+ init_tune_table_attr(&tune_table_css, rows, cols);
+
+ /* Set array of data in row Major order */
+ string *tunable_data = new string[cols * rows];
+
+ tunable_data[0]=__("Description");
+ tunable_data[1]=__("Script");
+
+ for (i = 0; i < all_tunables.size(); i++) {
+ int gb;
+ gb = all_tunables[i]->good_bad();
+ if (gb != TUNE_BAD)
+ continue;
+ tunable_data[idx]=string(all_tunables[i]->description());
+ idx+=1;
+ tunable_data[idx]=string(all_tunables[i]->toggle_script());
+ idx+=1;
+ }
+
+ /* Report Output */
+ report.add_title(&title_attr,__("Software Settings in Need of Tuning"));
+ report.add_table(tunable_data, &tune_table_css);
+ delete [] tunable_data;
+ }
+
+ /* Second Table */
+ /* Set Table attributes, rows, and cols */
+ cols=1;
+ rows= all_untunables.size() + 1;
+ init_tune_table_attr(&tune_table_css, rows, cols);
+
+ /* Set array of data in row Major order */
+ string *untunable_data = new string[rows];
+ untunable_data[0]=__("Description");
+
+ for (i = 0; i < all_untunables.size(); i++)
+ untunable_data[i+1]= string(all_untunables[i]->description());
+
+ /* Report Output */
+ report.add_title(&title_attr,__("Untunable Software Issues"));
+ report.add_table(untunable_data, &tune_table_css);
+ delete [] untunable_data;
+
+ /* Third Table */
+ /* Set Table attributes, rows, and cols */
+ rows = 1;
+ for (i = 0; i < all_tunables.size(); i++) {
+ int gb;
+ gb = all_tunables[i]->good_bad();
+ if (gb != TUNE_GOOD)
+ continue;
+ rows+=1;
+ }
+ cols = 1;
+ init_tune_table_attr(&tune_table_css, rows, cols);
+
+ /* Set array of data in row Major order */
+ string *tuned_data = new string[rows];
+ tuned_data[0]=__("Description");
+ idx=cols;
+ for (i = 0; i < all_tunables.size(); i++) {
+ int gb;
+ gb = all_tunables[i]->good_bad();
+ if (gb != TUNE_GOOD)
+ continue;
+
+ tuned_data[idx]=string(all_tunables[i]->description());
+ idx+=1;
+ }
+ /* Report Output */
+ report.add_title(&title_attr,__("Optimal Tuned Software Settings"));
+ report.add_table(tuned_data, &tune_table_css);
+ report.end_div();
+ delete [] tuned_data;
+}
+
+void clear_tuning()
+{
+ for (size_t i = 0; i < all_tunables.size(); i++) {
+ delete all_tunables[i];
+ }
+ all_tunables.clear();
+
+ for (size_t i = 0; i < all_untunables.size(); i++) {
+ delete all_untunables[i];
+ }
+ all_untunables.clear();
+}
+
+void auto_toggle_tuning()
+{
+ for (unsigned int i = 0; i < all_tunables.size(); i++) {
+ if (all_tunables[i]->good_bad() == TUNE_BAD)
+ all_tunables[i]->toggle();
+ }
+}
diff --git a/src/tuning/tuning.h b/src/tuning/tuning.h
new file mode 100644
index 0000000..f70001b
--- /dev/null
+++ b/src/tuning/tuning.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_TUNING_H
+#define _INCLUDE_GUARD_TUNING_H
+
+extern void initialize_tuning(void);
+extern void tuning_update_display(void);
+extern void report_show_tunables(void);
+extern void clear_tuning(void);
+extern void auto_toggle_tuning(void);
+#endif
diff --git a/src/tuning/tuningi2c.cpp b/src/tuning/tuningi2c.cpp
new file mode 100644
index 0000000..b75e811
--- /dev/null
+++ b/src/tuning/tuningi2c.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2015, Intel Corporation
+ *
+ * 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.
+ *
+ * Authors:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ * Daniel Leung <daniel.leung@linux.intel.com>
+ */
+
+#include "tuning.h"
+#include "tunable.h"
+#include "unistd.h"
+#include "tuningi2c.h"
+#include <string.h>
+#include <dirent.h>
+#include <utility>
+#include <iostream>
+#include <fstream>
+#include <ctype.h>
+#include <limits.h>
+
+#include "../lib.h"
+#include "../devices/runtime_pm.h"
+
+i2c_tunable::i2c_tunable(const char *path, const char *name, bool is_adapter) : tunable("", 0.9, _("Good"), _("Bad"), _("Unknown"))
+{
+ ifstream file;
+ char filename[PATH_MAX];
+ string devname;
+
+ snprintf(filename, sizeof(filename), "%s/name", path);
+ file.open(filename, ios::in);
+ if (file) {
+ getline(file, devname);
+ file.close();
+ }
+
+ if (is_adapter) {
+ snprintf(i2c_path, sizeof(i2c_path), "%s/device/power/control", path);
+ snprintf(filename, sizeof(filename), "%s/device", path);
+ } else {
+ snprintf(i2c_path, sizeof(i2c_path), "%s/power/control", path);
+ snprintf(filename, sizeof(filename), "%s/device", path);
+ }
+
+ if (device_has_runtime_pm(filename))
+ snprintf(desc, sizeof(desc), _("Runtime PM for I2C %s %s (%s)"), (is_adapter ? _("Adapter") : _("Device")), name, (devname.empty() ? "" : devname.c_str()));
+ else
+ snprintf(desc, sizeof(desc), _("I2C %s %s has no runtime power management"), (is_adapter ? _("Adapter") : _("Device")), name);
+
+ snprintf(toggle_good, sizeof(toggle_good), "echo 'auto' > '%s';", i2c_path);
+ snprintf(toggle_bad, sizeof(toggle_bad), "echo 'on' > '%s';", i2c_path);
+}
+
+int i2c_tunable::good_bad(void)
+{
+ string content;
+
+ content = read_sysfs_string(i2c_path);
+
+ if (strcmp(content.c_str(), "auto") == 0)
+ return TUNE_GOOD;
+
+ return TUNE_BAD;
+}
+
+void i2c_tunable::toggle(void)
+{
+ int good;
+ good = good_bad();
+
+ if (good == TUNE_GOOD) {
+ write_sysfs(i2c_path, "on");
+ return;
+ }
+
+ write_sysfs(i2c_path, "auto");
+}
+
+const char *i2c_tunable::toggle_script(void)
+{
+ int good;
+ good = good_bad();
+
+ if (good == TUNE_GOOD) {
+ return toggle_bad;
+ }
+
+ return toggle_good;
+}
+
+static void add_i2c_callback(const char *d_name)
+{
+ class i2c_tunable *i2c;
+ char filename[PATH_MAX];
+ bool is_adapter = false;
+
+ snprintf(filename, PATH_MAX, "/sys/bus/i2c/devices/%s/new_device", d_name);
+ if (access(filename, W_OK) == 0)
+ is_adapter = true;
+
+ snprintf(filename, PATH_MAX, "/sys/bus/i2c/devices/%s", d_name);
+ i2c = new class i2c_tunable(filename, d_name, is_adapter);
+
+ if (is_adapter)
+ snprintf(filename, PATH_MAX, "/sys/bus/i2c/devices/%s/device", d_name);
+ else
+ snprintf(filename, PATH_MAX, "/sys/bus/i2c/devices/%s", d_name);
+
+ if (device_has_runtime_pm(filename))
+ all_tunables.push_back(i2c);
+ else
+ all_untunables.push_back(i2c);
+}
+
+void add_i2c_tunables(void)
+{
+ process_directory("/sys/bus/i2c/devices/", add_i2c_callback);
+}
diff --git a/src/tuning/tuningi2c.h b/src/tuning/tuningi2c.h
new file mode 100644
index 0000000..8fd8784
--- /dev/null
+++ b/src/tuning/tuningi2c.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2015, Intel Corporation
+ *
+ * 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.
+ *
+ * Authors:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ * Daniel Leung <daniel.leung@linux.intel.com>
+ */
+
+#ifndef _INCLUDE_GUARD_I2C_TUNE_H
+#define _INCLUDE_GUARD_I2C_TUNE_H
+
+#include <vector>
+#include <limits.h>
+
+#include "tunable.h"
+
+using namespace std;
+
+class i2c_tunable : public tunable {
+ char i2c_path[PATH_MAX];
+public:
+ i2c_tunable(const char *path, const char *name, bool is_adapter);
+
+ virtual int good_bad(void);
+
+ virtual void toggle(void);
+
+ virtual const char *toggle_script(void);
+
+};
+
+extern void add_i2c_tunables(void);
+
+
+#endif
diff --git a/src/tuning/tuningsysfs.cpp b/src/tuning/tuningsysfs.cpp
new file mode 100644
index 0000000..631e9fd
--- /dev/null
+++ b/src/tuning/tuningsysfs.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "tuning.h"
+#include "tunable.h"
+#include "unistd.h"
+#include "tuningsysfs.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <utility>
+#include <iostream>
+#include <fstream>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <limits.h>
+
+
+#include "../lib.h"
+
+sysfs_tunable::sysfs_tunable(const char *str, const char *_sysfs_path, const char *_target_content) : tunable(str, 1.0, _("Good"), _("Bad"), _("Unknown"))
+{
+ pt_strcpy(sysfs_path, _sysfs_path);
+ pt_strcpy(target_value, _target_content);
+ bad_value[0] = 0;
+ snprintf(toggle_good, sizeof(toggle_good), "echo '%s' > '%s';", target_value, sysfs_path);
+ snprintf(toggle_bad, sizeof(toggle_bad), "echo '%s' > '%s';", bad_value, sysfs_path);
+}
+
+int sysfs_tunable::good_bad(void)
+{
+ char current_value[4096], *c;
+ ifstream file;
+
+ file.open(sysfs_path, ios::in);
+ if (!file)
+ return TUNE_NEUTRAL;
+ file.getline(current_value, 4096);
+ file.close();
+
+ c = strchr(current_value, '\n');
+ if (c)
+ *c = 0;
+
+ if (strcmp(current_value, target_value) == 0)
+ return TUNE_GOOD;
+
+ pt_strcpy(bad_value, current_value);
+ return TUNE_BAD;
+}
+
+void sysfs_tunable::toggle(void)
+{
+ int good;
+ good = good_bad();
+
+ if (good == TUNE_GOOD) {
+ if (strlen(bad_value) > 0)
+ write_sysfs(sysfs_path, bad_value);
+ return;
+ }
+
+ write_sysfs(sysfs_path, target_value);
+}
+
+const char *sysfs_tunable::toggle_script(void) {
+ int good;
+ good = good_bad();
+
+ if (good == TUNE_GOOD) {
+ if (strlen(bad_value) > 0)
+ return toggle_bad;
+ return NULL;
+ }
+
+ return toggle_good;
+}
+
+
+void add_sysfs_tunable(const char *str, const char *_sysfs_path, const char *_target_content)
+{
+ class sysfs_tunable *tunable;
+
+ if (access(_sysfs_path, R_OK) != 0)
+ return;
+
+ tunable = new class sysfs_tunable(str, _sysfs_path, _target_content);
+
+
+ all_tunables.push_back(tunable);
+}
+
+static void add_sata_tunables_callback(const char *d_name)
+{
+ char filename[PATH_MAX];
+ char msg[4096];
+
+ snprintf(filename, sizeof(filename), "/sys/class/scsi_host/%s/link_power_management_policy", d_name);
+ snprintf(msg, sizeof(msg), _("Enable SATA link power management for %s"), d_name);
+ add_sysfs_tunable(msg, filename, "med_power_with_dipm");
+}
+
+void add_sata_tunables(void)
+{
+ process_directory("/sys/class/scsi_host", add_sata_tunables_callback);
+}
diff --git a/src/tuning/tuningsysfs.h b/src/tuning/tuningsysfs.h
new file mode 100644
index 0000000..57b9de7
--- /dev/null
+++ b/src/tuning/tuningsysfs.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_SYSFS_TUNE_H
+#define _INCLUDE_GUARD_SYSFS_TUNE_H
+
+#include <vector>
+#include <limits.h>
+
+#include "tunable.h"
+
+using namespace std;
+
+class sysfs_tunable : public tunable {
+ char sysfs_path[PATH_MAX];
+ char target_value[4096];
+ char bad_value[4096];
+public:
+ sysfs_tunable(const char *str, const char *sysfs_path, const char *target_content);
+
+ virtual int good_bad(void);
+
+ virtual void toggle(void);
+
+ virtual const char *toggle_script(void);
+
+};
+
+extern void add_sysfs_tunable(const char *str, const char *_sysfs_path, const char *_target_content);
+extern void add_sata_tunables(void);
+
+#endif
diff --git a/src/tuning/tuningusb.cpp b/src/tuning/tuningusb.cpp
new file mode 100644
index 0000000..3b7b2b1
--- /dev/null
+++ b/src/tuning/tuningusb.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "tuning.h"
+#include "tunable.h"
+#include "unistd.h"
+#include "tuningusb.h"
+#include <string.h>
+#include <dirent.h>
+#include <utility>
+#include <iostream>
+#include <fstream>
+#include <limits.h>
+
+#include "../lib.h"
+
+usb_tunable::usb_tunable(const char *path, const char *name) : tunable("", 0.9, _("Good"), _("Bad"), _("Unknown"))
+{
+ ifstream file;
+ char filename[PATH_MAX];
+ char vendor[2048];
+ char product[2048];
+ string str1, str2;
+ snprintf(usb_path, sizeof(usb_path), "%s/power/control", path);
+
+ vendor[0] = 0;
+ product[0] = 0;
+
+ str1 = read_sysfs_string("%s/idVendor", path);
+ str2 = read_sysfs_string("%s/idProduct", path);
+
+ snprintf(desc, sizeof(desc), _("Autosuspend for unknown USB device %s (%s:%s)"), name, str1.c_str(), str2.c_str());
+
+ snprintf(filename, sizeof(filename), "%s/manufacturer", path);
+ file.open(filename, ios::in);
+ if (file) {
+ file.getline(vendor, 2047);
+ if (strstr(vendor, "Linux "))
+ vendor[0] = 0;
+ file.close();
+ };
+ snprintf(filename, sizeof(filename), "%s/product", path);
+ file.open(filename, ios::in);
+ if (file) {
+ file.getline(product, 2040);
+ file.close();
+ };
+ if (strlen(vendor) && strlen(product))
+ snprintf(desc, sizeof(desc), _("Autosuspend for USB device %s [%s]"), product, vendor);
+ else if (strlen(product))
+ snprintf(desc, sizeof(desc), _("Autosuspend for USB device %s [%s]"), product, name);
+ else if (strlen(vendor))
+ snprintf(desc, sizeof(desc), _("Autosuspend for USB device %s [%s]"), vendor, name);
+
+ snprintf(toggle_good, sizeof(toggle_good), "echo 'auto' > '%s';", usb_path);
+ snprintf(toggle_bad, sizeof(toggle_bad), "echo 'on' > '%s';", usb_path);
+}
+
+int usb_tunable::good_bad(void)
+{
+ string content;
+
+ content = read_sysfs_string(usb_path);
+
+ if (strcmp(content.c_str(), "auto") == 0)
+ return TUNE_GOOD;
+
+ return TUNE_BAD;
+}
+
+void usb_tunable::toggle(void)
+{
+ int good;
+ good = good_bad();
+
+ if (good == TUNE_GOOD) {
+ write_sysfs(usb_path, "on");
+ return;
+ }
+
+ write_sysfs(usb_path, "auto");
+}
+
+const char *usb_tunable::toggle_script(void)
+{
+ int good;
+ good = good_bad();
+
+ if (good == TUNE_GOOD) {
+ return toggle_bad;
+ }
+
+ return toggle_good;
+}
+
+static void add_usb_callback(const char *d_name)
+{
+ class usb_tunable *usb;
+ char filename[PATH_MAX];
+ DIR *dir;
+
+ snprintf(filename, sizeof(filename), "/sys/bus/usb/devices/%s/power/control", d_name);
+ if (access(filename, R_OK) != 0)
+ return;
+
+ snprintf(filename, sizeof(filename), "/sys/bus/usb/devices/%s/power/active_duration", d_name);
+ if (access(filename, R_OK)!=0)
+ return;
+
+ /* every interface of this device should support autosuspend */
+ snprintf(filename, sizeof(filename), "/sys/bus/usb/devices/%s", d_name);
+ if ((dir = opendir(filename))) {
+ struct dirent *entry;
+ while ((entry = readdir(dir))) {
+ /* dirname: <busnum>-<devnum>...:<config num>-<interface num> */
+ if (!isdigit(entry->d_name[0]))
+ continue;
+ snprintf(filename, sizeof(filename), "/sys/bus/usb/devices/%s/%s/supports_autosuspend", d_name, entry->d_name);
+ if (access(filename, R_OK) == 0 && read_sysfs(filename) == 0)
+ break;
+ }
+ closedir(dir);
+ if (entry)
+ return;
+ }
+
+ snprintf(filename, sizeof(filename), "/sys/bus/usb/devices/%s", d_name);
+ usb = new class usb_tunable(filename, d_name);
+ all_tunables.push_back(usb);
+}
+
+void add_usb_tunables(void)
+{
+ process_directory("/sys/bus/usb/devices/", add_usb_callback);
+}
diff --git a/src/tuning/tuningusb.h b/src/tuning/tuningusb.h
new file mode 100644
index 0000000..4e27e3a
--- /dev/null
+++ b/src/tuning/tuningusb.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_USB_TUNE_H
+#define _INCLUDE_GUARD_USB_TUNE_H
+
+#include <vector>
+#include <limits.h>
+
+#include "tunable.h"
+
+using namespace std;
+
+class usb_tunable : public tunable {
+ char usb_path[PATH_MAX];
+public:
+ usb_tunable(const char *usb_path, const char *path);
+
+ virtual int good_bad(void);
+
+ virtual void toggle(void);
+
+ virtual const char *toggle_script(void);
+
+};
+
+extern void add_usb_tunables(void);
+
+
+#endif
diff --git a/src/tuning/wifi.cpp b/src/tuning/wifi.cpp
new file mode 100644
index 0000000..f7a91ec
--- /dev/null
+++ b/src/tuning/wifi.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "tuning.h"
+#include "tunable.h"
+#include "unistd.h"
+#include "wifi.h"
+#include <string.h>
+#include <utility>
+#include <iostream>
+#include <fstream>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "../lib.h"
+
+extern "C" {
+#include "iw.h"
+}
+
+
+wifi_tunable::wifi_tunable(const char *_iface) : tunable("", 1.5, _("Good"), _("Bad"), _("Unknown"))
+{
+ pt_strcpy(iface, _iface);
+ sprintf(desc, _("Wireless Power Saving for interface %s"), iface);
+
+ snprintf(toggle_good, sizeof(toggle_good), "iw dev %s set power_save on", iface);
+ snprintf(toggle_bad, sizeof(toggle_bad), "iw dev %s set power_save off", iface);
+}
+
+int wifi_tunable::good_bad(void)
+{
+ if (get_wifi_power_saving(iface))
+ return TUNE_GOOD;
+
+ return TUNE_BAD;
+}
+
+void wifi_tunable::toggle(void)
+{
+ int good;
+ good = good_bad();
+
+ if (good == TUNE_GOOD) {
+ set_wifi_power_saving(iface, 0);
+ return;
+ }
+
+ set_wifi_power_saving(iface, 1);
+}
+
+const char *wifi_tunable::toggle_script(void)
+{
+ int good;
+ good = good_bad();
+
+ if (good == TUNE_GOOD) {
+ return toggle_bad;
+ }
+
+ return toggle_good;
+}
+
+void add_wifi_tunables(void)
+{
+ struct dirent *entry;
+ DIR *dir;
+ char* wlan_name;
+ class wifi_tunable *wifi;
+
+
+ dir = opendir("/sys/class/net/");
+ if (!dir)
+ return;
+ while (1) {
+ entry = readdir(dir);
+ if (!entry)
+ break;
+ wlan_name = strstr(entry->d_name, "wlan");
+ if (wlan_name) {
+ wifi = new class wifi_tunable(wlan_name);
+ all_tunables.push_back(wifi);
+ }
+
+ }
+
+ closedir(dir);
+
+}
diff --git a/src/tuning/wifi.h b/src/tuning/wifi.h
new file mode 100644
index 0000000..50ca68c
--- /dev/null
+++ b/src/tuning/wifi.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * 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:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_WIFI_TUNE_H
+#define _INCLUDE_GUARD_WIFI_TUNE_H
+
+#include <vector>
+
+#include "tunable.h"
+
+using namespace std;
+
+class wifi_tunable : public tunable {
+ char iface[4096];
+public:
+ wifi_tunable(const char *_iface);
+
+ virtual int good_bad(void);
+
+ virtual void toggle(void);
+
+ virtual const char *toggle_script(void);
+
+};
+
+extern void add_wifi_tunables(void);
+
+
+#endif
diff --git a/src/wakeup/waketab.cpp b/src/wakeup/waketab.cpp
new file mode 100644
index 0000000..77d7567
--- /dev/null
+++ b/src/wakeup/waketab.cpp
@@ -0,0 +1,195 @@
+#include <algorithm>
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include "wakeup.h"
+#include <vector>
+#include "../lib.h"
+#include "../measurement/sysfs.h"
+#include "../display.h"
+#include "../report/report.h"
+#include "../report/report-maker.h"
+#include "../report/report-data-html.h"
+#include "wakeup_ethernet.h"
+#include "wakeup_usb.h"
+
+using namespace std;
+
+static bool should_clear = false;
+
+class wakeup_window *newtab_window;
+
+class wakeup_window: public tab_window {
+public:
+ virtual void repaint(void);
+ virtual void cursor_enter(void);
+ virtual void expose(void);
+ virtual void window_refresh(void);
+};
+
+static void init_wakeup(void)
+{
+ add_ethernet_wakeup();
+ add_usb_wakeup();
+}
+
+void initialize_wakeup(void)
+{
+ class wakeup_window *win;
+
+ win = new wakeup_window();
+
+ create_tab("WakeUp", _("WakeUp"), win, _(" <ESC> Exit | <Enter> Toggle wakeup | <r> Window refresh"));
+
+ init_wakeup();
+
+ win->cursor_max = wakeup_all.size() - 1;
+
+ if (newtab_window)
+ delete newtab_window;
+
+ newtab_window = win;
+}
+
+static void __wakeup_update_display(int cursor_pos)
+{
+ WINDOW *win;
+ unsigned int i;
+
+ win = get_ncurses_win("WakeUp");
+
+ if (!win)
+ return;
+
+ if (should_clear) {
+ should_clear = false;
+ wclear(win);
+ }
+
+ wmove(win, 1,0);
+
+ for (i = 0; i < wakeup_all.size(); i++) {
+ char res[128];
+ char desc[4096];
+ pt_strcpy(res, wakeup_all[i]->wakeup_string());
+ pt_strcpy(desc, wakeup_all[i]->description());
+ while (strlen(res) < 12)
+ strcat(res, " ");
+
+ while (strlen(desc) < 103)
+ strcat(desc, " ");
+
+ if ((int)i != cursor_pos) {
+ wattrset(win, A_NORMAL);
+ wprintw(win, " ");
+ } else {
+ wattrset(win, A_REVERSE);
+ wprintw(win, ">> ");
+ }
+ wprintw(win, "%s %s\n", _(res), _(desc));
+ }
+}
+
+void wakeup_update_display(void)
+{
+ class tab_window *wt;
+
+ wt = tab_windows["WakeUp"];
+ if (!wt)
+ return;
+ wt->repaint();
+}
+
+void wakeup_window::repaint(void)
+{
+ __wakeup_update_display(cursor_pos);
+}
+
+void wakeup_window::cursor_enter(void)
+{
+ class wakeup *wake;
+ const char *wakeup_toggle_script;
+ wake = wakeup_all[cursor_pos];
+ if (!wake)
+ return;
+ wakeup_toggle_script = wake->wakeup_toggle_script();
+ wake->wakeup_toggle();
+ ui_notify_user(">> %s\n", wakeup_toggle_script);
+}
+
+void report_show_wakeup(void)
+{
+ unsigned int i;
+ int idx, rows = 0, cols;
+
+ /* div attr css_class and css_id */
+ tag_attr div_attr;
+ init_div(&div_attr, "clear_block", "wakeup");
+
+ /* Set Title attributes */
+ tag_attr title_attr;
+ init_title_attr(&title_attr);
+
+ /* Set Table attributes, rows, and cols */
+ table_attributes wakeup_table_css;
+ cols=2;
+ idx = cols;
+
+ for (i = 0; i < wakeup_all.size(); i++) {
+ int tgb;
+ tgb = wakeup_all[i]->wakeup_value();
+ if (tgb == WAKEUP_DISABLE)
+ rows+=1;
+ }
+
+ /* add section */
+
+ report.add_div(&div_attr);
+ if (rows > 0){
+ rows= rows + 1;
+ init_wakeup_table_attr(&wakeup_table_css, rows, cols);
+
+ /* Set array of data in row Major order */
+ string *wakeup_data = new string[cols * rows];
+
+ wakeup_data[0]=__("Description");
+ wakeup_data[1]=__("Script");
+
+ for (i = 0; i < wakeup_all.size(); i++) {
+ int gb;
+ gb = wakeup_all[i]->wakeup_value();
+ if (gb != WAKEUP_DISABLE)
+ continue;
+ wakeup_data[idx]=string(wakeup_all[i]->description());
+ idx+=1;
+ wakeup_data[idx]=string(wakeup_all[i]->wakeup_toggle_script());
+ idx+=1;
+ }
+
+ /* Report Output */
+ report.add_title(&title_attr,__("Wake status of the devices"));
+ report.add_table(wakeup_data, &wakeup_table_css);
+ delete [] wakeup_data;
+ }
+}
+
+void wakeup_window::expose(void)
+{
+ cursor_pos = 0;
+ repaint();
+}
+
+void wakeup_window::window_refresh(void)
+{
+ clear_wakeup();
+ should_clear = true;
+ init_wakeup();
+}
+
+void clear_wakeup()
+{
+ for (size_t i = 0; i < wakeup_all.size(); i++) {
+ delete wakeup_all[i];
+ }
+ wakeup_all.clear();
+}
diff --git a/src/wakeup/wakeup.cpp b/src/wakeup/wakeup.cpp
new file mode 100644
index 0000000..9d83a9a
--- /dev/null
+++ b/src/wakeup/wakeup.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018, Intel Corporation
+ *
+ * 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:
+ * Gayatri Kammela <gayatri.kammela@intel.com>
+ */
+
+#include <string.h>
+#include <ncurses.h>
+#include "wakeup.h"
+#include <vector>
+#include "../lib.h"
+
+using namespace std;
+
+vector<class wakeup *> wakeup_all;
+
+wakeup::wakeup(const char *str, double _score, const char *enable, const char *disable)
+{
+ score = _score;
+ pt_strcpy(desc, str);
+ pt_strcpy(wakeup_enable, enable);
+ pt_strcpy(wakeup_disable, disable);
+}
+
+wakeup::wakeup(void)
+{
+ score = 0;
+ desc[0] = 0;
+ pt_strcpy(wakeup_enable, _("Enabled"));
+ pt_strcpy(wakeup_disable, _("Disabled"));
+ pt_strcpy(wakeup_idle, _("Unknown"));
+}
+
diff --git a/src/wakeup/wakeup.h b/src/wakeup/wakeup.h
new file mode 100644
index 0000000..13f99a3
--- /dev/null
+++ b/src/wakeup/wakeup.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018, Intel Corporation
+ *
+ * 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:
+ * Gayatri Kammela <gayatri.kammela@intel.com>
+ */
+#ifndef _INCLUDE_GUARD_WAKEUP_H
+#define _INCLUDE_GUARD_WAKEUP_H
+
+#include<vector>
+#include <limits.h>
+
+using namespace std;
+
+#define WAKEUP_ENABLE 1
+#define WAKEUP_DISABLE 0
+
+class wakeup {
+ char wakeup_enable[128];
+ char wakeup_disable[128];
+ char wakeup_idle[128];
+protected:
+ char toggle_enable[4096];
+ char toggle_disable[4096];
+public:
+ char desc[4096];
+ double score;
+
+ wakeup(const char *str, double _score, const char *enable = "", const char *disable = "");
+ wakeup(void);
+
+ virtual ~wakeup () {};
+
+ virtual int wakeup_value(void) { return WAKEUP_DISABLE; }
+
+ virtual char *wakeup_string(void)
+ {
+ switch (wakeup_value()) {
+ case WAKEUP_ENABLE:
+ return wakeup_enable;
+ case WAKEUP_DISABLE:
+ return wakeup_disable;
+ }
+ return wakeup_idle;
+ }
+
+
+ virtual const char *description(void) { return desc; };
+
+ virtual void wakeup_toggle(void) { };
+
+ virtual const char *wakeup_toggle_script(void) { return toggle_enable; }
+
+};
+
+extern vector<class wakeup *> wakeup_all;
+
+extern void initialize_wakeup(void);
+extern void wakeup_update_display(void);
+extern void report_show_wakeup(void);
+extern void clear_wakeup(void);
+
+#endif
diff --git a/src/wakeup/wakeup_ethernet.cpp b/src/wakeup/wakeup_ethernet.cpp
new file mode 100644
index 0000000..6ce1725
--- /dev/null
+++ b/src/wakeup/wakeup_ethernet.cpp
@@ -0,0 +1,111 @@
+;/*
+ * Copyright 2018, Intel Corporation
+ *
+ * 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:
+ * Gayatri Kammela <gayatri.kammela@intel.com>
+ */
+
+#include "wakeup.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utility>
+#include <iostream>
+#include <fstream>
+#include <sys/socket.h>
+#include <errno.h>
+#include <linux/types.h>
+#include <net/if.h>
+#include <linux/sockios.h>
+#include <sys/ioctl.h>
+
+#include <linux/ethtool.h>
+
+#include "../lib.h"
+#include "wakeup_ethernet.h"
+
+ethernet_wakeup::ethernet_wakeup(const char *path, const char *iface) : wakeup("", 0.5, _("Enabled"), _("Disabled"))
+{
+ memset(interf, 0, sizeof(interf));
+ pt_strcpy(interf, iface);
+ sprintf(desc, _("Wake-on-lan status for device %s"), iface);
+ snprintf(eth_path, sizeof(eth_path), "/sys/class/net/%s/device/power/wakeup", iface);
+ snprintf(toggle_enable, sizeof(toggle_enable), "echo 'enabled' > '%s';", eth_path);
+ snprintf(toggle_disable, sizeof(toggle_disable), "echo 'disabled' > '%s';", eth_path);
+}
+
+int ethernet_wakeup::wakeup_value(void)
+{
+ string content;
+
+ content = read_sysfs_string(eth_path);
+
+ if (strcmp(content.c_str(), "enabled") == 0)
+ return WAKEUP_ENABLE;
+
+ return WAKEUP_DISABLE;
+}
+
+void ethernet_wakeup::wakeup_toggle(void)
+{
+ int enable;
+ enable = wakeup_value();
+
+ if (enable == WAKEUP_ENABLE) {
+ write_sysfs(eth_path, "disabled");
+ return;
+ }
+
+ write_sysfs(eth_path, "enabled");
+}
+
+const char *ethernet_wakeup::wakeup_toggle_script(void)
+{
+ int enable;
+ enable = wakeup_value();
+
+ if (enable == WAKEUP_ENABLE) {
+ return toggle_disable;
+ }
+
+ return toggle_enable;
+}
+
+void wakeup_eth_callback(const char *d_name)
+{
+ class ethernet_wakeup *eth;
+ char filename[PATH_MAX];
+
+ snprintf(filename, sizeof(filename), "/sys/class/net/%s/device/power/wakeup", d_name);
+ if (access(filename, R_OK) != 0)
+ return;
+
+ snprintf(filename, sizeof(filename), "/sys/class/net/%s/device/power/wakeup", d_name);
+ eth = new class ethernet_wakeup(filename, d_name);
+ wakeup_all.push_back(eth);
+}
+
+void add_ethernet_wakeup(void)
+{
+ process_directory("/sys/class/net/", wakeup_eth_callback);
+}
diff --git a/src/wakeup/wakeup_ethernet.h b/src/wakeup/wakeup_ethernet.h
new file mode 100644
index 0000000..682bf95
--- /dev/null
+++ b/src/wakeup/wakeup_ethernet.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018, Intel Corporation
+ *
+ * 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:
+ * Gayatri Kammela <gayatri.kammela@intel.com>
+ */
+#ifndef _INCLUDE_GUARD_ETHERNET_WAKEUP_H
+#define _INCLUDE_GUARD_ETHERNET_WAKEUP_H
+
+#include <vector>
+
+#include "wakeup.h"
+
+using namespace std;
+
+class ethernet_wakeup : public wakeup {
+ char eth_path[PATH_MAX];
+public:
+ char interf[4096];
+ ethernet_wakeup(const char *eth_path, const char *iface);
+
+ virtual int wakeup_value(void);
+
+ virtual void wakeup_toggle(void);
+
+ virtual const char *wakeup_toggle_script(void);
+
+};
+
+extern void add_ethernet_wakeup(void);
+
+#endif
diff --git a/src/wakeup/wakeup_usb.cpp b/src/wakeup/wakeup_usb.cpp
new file mode 100644
index 0000000..e0e4567
--- /dev/null
+++ b/src/wakeup/wakeup_usb.cpp
@@ -0,0 +1,111 @@
+;/*
+ * Copyright 2018, Intel Corporation
+ *
+ * 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:
+ * Gayatri Kammela <gayatri.kammela@intel.com>
+ */
+
+#include "wakeup.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utility>
+#include <iostream>
+#include <fstream>
+#include <sys/socket.h>
+#include <errno.h>
+#include <linux/types.h>
+#include <net/if.h>
+#include <linux/sockios.h>
+#include <sys/ioctl.h>
+
+#include <linux/ethtool.h>
+
+#include "../lib.h"
+#include "wakeup_usb.h"
+
+usb_wakeup::usb_wakeup(const char *path, const char *iface) : wakeup("", 0.5, _("Enabled"), _("Disabled"))
+{
+ memset(interf, 0, sizeof(interf));
+ pt_strcpy(interf, iface);
+ sprintf(desc, _("Wake status for USB device %s"), iface);
+ snprintf(usb_path, sizeof(usb_path), "/sys/bus/usb/devices/%s/power/wakeup", iface);
+ snprintf(toggle_enable, sizeof(toggle_enable), "echo 'enabled' > '%s';", usb_path);
+ snprintf(toggle_disable, sizeof(toggle_disable), "echo 'disabled' > '%s';", usb_path);
+}
+
+int usb_wakeup::wakeup_value(void)
+{
+ string content;
+
+ content = read_sysfs_string(usb_path);
+
+ if (strcmp(content.c_str(), "enabled") == 0)
+ return WAKEUP_ENABLE;
+
+ return WAKEUP_DISABLE;
+}
+
+void usb_wakeup::wakeup_toggle(void)
+{
+ int enable;
+ enable = wakeup_value();
+
+ if (enable == WAKEUP_ENABLE) {
+ write_sysfs(usb_path, "disabled");
+ return;
+ }
+
+ write_sysfs(usb_path, "enabled");
+}
+
+const char *usb_wakeup::wakeup_toggle_script(void)
+{
+ int enable;
+ enable = wakeup_value();
+
+ if (enable == WAKEUP_ENABLE) {
+ return toggle_disable;
+ }
+
+ return toggle_enable;
+}
+
+void wakeup_usb_callback(const char *d_name)
+{
+ class usb_wakeup *usb;
+ char filename[PATH_MAX];
+
+ snprintf(filename, sizeof(filename), "/sys/bus/usb/devices/%s/power/wakeup", d_name);
+ if (access(filename, R_OK) != 0)
+ return;
+
+ snprintf(filename, sizeof(filename), "/sys/bus/usb/devices/%s/power/wakeup", d_name);
+ usb = new class usb_wakeup(filename, d_name);
+ wakeup_all.push_back(usb);
+}
+
+void add_usb_wakeup(void)
+{
+ process_directory("/sys/bus/usb/devices/", wakeup_usb_callback);
+}
diff --git a/src/wakeup/wakeup_usb.h b/src/wakeup/wakeup_usb.h
new file mode 100644
index 0000000..f7a1f7e
--- /dev/null
+++ b/src/wakeup/wakeup_usb.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018, Intel Corporation
+ *
+ * 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:
+ * Gayatri Kammela <gayatri.kammela@intel.com>
+ */
+#ifndef _INCLUDE_GUARD_USB_WAKEUP_H
+#define _INCLUDE_GUARD_USB_WAKEUP_H
+
+#include <vector>
+
+#include "wakeup.h"
+
+using namespace std;
+
+class usb_wakeup : public wakeup {
+ char usb_path[PATH_MAX];
+public:
+ char interf[4096];
+ usb_wakeup(const char *usb_path, const char *iface);
+
+ virtual int wakeup_value(void);
+
+ virtual void wakeup_toggle(void);
+
+ virtual const char *wakeup_toggle_script(void);
+
+};
+
+extern void add_usb_wakeup(void);
+
+#endif