/* * 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 * Peter Anvin */ #include #include #include #include #include #include #include #include #include #include #include #include #include "lib.h" #ifndef HAVE_NO_PCI extern "C" { #include } #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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 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 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::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); }