summaryrefslogtreecommitdiffstats
path: root/src/lib.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib.cpp597
1 files changed, 597 insertions, 0 deletions
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);
+}