diff options
Diffstat (limited to '')
-rw-r--r-- | src/devices/devfreq.cpp | 334 |
1 files changed, 334 insertions, 0 deletions
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; + } +} |