| /* |
| * 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 "tuningsysfs.h" |
| #include "tuningusb.h" |
| #include "runtime.h" |
| #include "bluetooth.h" |
| #include "cpufreq.h" |
| #include "ethernet.h" |
| #include "wifi.h" |
| #include "../display.h" |
| #include "../report.h" |
| #include "../lib.h" |
| |
| static void sort_tunables(void); |
| static bool should_clear = false; |
| |
| #ifndef DISABLE_NCURSES |
| 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); |
| }; |
| #endif // DISABLE_NCURSES |
| |
| 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(_("Enable SATA link power management for /dev/sda"), "/sys/class/scsi_host/host0/link_power_management_policy", "min_power"); |
| 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_usb_tunables(); |
| add_runtime_tunables("pci"); |
| add_ethernet_tunable(); |
| add_bt_tunable(); |
| add_wifi_tunables(); |
| add_cpufreq_tunable(); |
| |
| sort_tunables(); |
| } |
| |
| void initialize_tuning(void) |
| { |
| #ifndef DISABLE_NCURSES |
| class tuning_window *w; |
| |
| w = new tuning_window(); |
| create_tab("Tunables", _("Tunables"), w, _(" <ESC> Exit | <Enter> Toggle tunable | <r> Window refresh")); |
| #endif // DISABLE_NCURSES |
| |
| init_tuning(); |
| |
| #ifndef DISABLE_NCURSES |
| w->cursor_max = all_tunables.size() - 1; |
| #endif // DISABLE_NCURSES |
| } |
| |
| |
| |
| static void __tuning_update_display(int cursor_pos) |
| { |
| #ifndef DISABLE_NCURSES |
| 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]; |
| strcpy(res, all_tunables[i]->result_string()); |
| 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)); |
| } |
| #endif |
| } |
| |
| void tuning_update_display(void) |
| { |
| #ifndef DISABLE_NCURSES |
| class tab_window *w; |
| |
| w = tab_windows["Tunables"]; |
| if (!w) |
| return; |
| w->repaint(); |
| #endif |
| } |
| #ifndef DISABLE_NCURSES |
| void tuning_window::repaint(void) |
| { |
| __tuning_update_display(cursor_pos); |
| } |
| |
| void tuning_window::cursor_enter(void) |
| { |
| class tunable *tun; |
| |
| tun = all_tunables[cursor_pos]; |
| if (!tun) |
| return; |
| tun->toggle(); |
| } |
| #endif // DISABLE_NCURSES |
| |
| 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); |
| } |
| #ifndef DISABLE_NCURSES |
| void tuning_window::expose(void) |
| { |
| cursor_pos = 0; |
| sort_tunables(); |
| repaint(); |
| } |
| #endif // DISABLE_NCURSES |
| static const char *tune_class(int line) |
| { |
| if (line & 1) { |
| return "tunable_odd"; |
| } |
| return "tunable_even"; |
| } |
| |
| static const char *tune_class_bad(int line) |
| { |
| if (line & 1) { |
| return "tunable_odd_bad"; |
| } |
| return "tunable_even_bad"; |
| } |
| |
| |
| void report_show_tunables(void) |
| { |
| unsigned int i, line; |
| /* three sections; bad, unfixable, good */ |
| |
| if ((!reportout.csv_report)&&(!reportout.http_report)) |
| return; |
| |
| sort_tunables(); |
| |
| |
| if (reporttype) |
| fprintf(reportout.http_report, "<div id=\"tuning\">\n"); |
| |
| line = 0; |
| for (i = 0; i < all_tunables.size(); i++) { |
| int gb; |
| |
| gb = all_tunables[i]->good_bad(); |
| |
| if (gb != TUNE_BAD) |
| continue; |
| |
| if (line == 0) { |
| if(reporttype) |
| fprintf(reportout.http_report,"<h2>Software Settings in need of Tuning</h2>\n <table width=\"100%%\">\n"); |
| else |
| fprintf(reportout.csv_report,"**Software Settings in need of Tuning**, \n\n"); |
| |
| } |
| |
| line++; |
| if (i < 1 && !reporttype) |
| fprintf(reportout.csv_report, "Description, \n"); |
| |
| if (reporttype) |
| fprintf(reportout.http_report, "<tr class=\"%s\"><td>%s</td><td>%s</td></tr>\n", tune_class_bad(line), all_tunables[i]->description(), all_tunables[i]->toggle_script()); |
| else |
| fprintf(reportout.csv_report, "\"%s\", \n", all_tunables[i]->description()); |
| } |
| |
| if (line > 0) { |
| if(reporttype) |
| fprintf(reportout.http_report,"</table>\n"); |
| else |
| fprintf(reportout.csv_report, "\n"); |
| } |
| |
| |
| line = 0; |
| for (i = 0; i < all_untunables.size(); i++) { |
| if (line == 0) { |
| if(reporttype) |
| fprintf(reportout.http_report, |
| "<h2>Untunable Software Issues</h2>\n <table width=\"100%%\">\n"); |
| else |
| fprintf(reportout.csv_report, |
| "**Untunable Software Issues**,\n\n"); |
| } |
| |
| line++; |
| if (i < 1 && !reporttype) |
| fprintf(reportout.csv_report, "Description, \n"); |
| |
| if (reporttype) |
| fprintf(reportout.http_report, |
| "<tr class=\"%s\"><td>%s</td></tr>\n", |
| tune_class_bad(line), all_untunables[i]->description()); |
| else |
| fprintf(reportout.csv_report,"\"%s\", \n", all_untunables[i]->description()); |
| } |
| |
| if (line > 0) { |
| if(reporttype) |
| fprintf(reportout.http_report,"</table>\n"); |
| else |
| fprintf(reportout.csv_report,"\n"); |
| } |
| |
| line = 0; |
| for (i = 0; i < all_tunables.size(); i++) { |
| int gb; |
| |
| gb = all_tunables[i]->good_bad(); |
| |
| if (gb != TUNE_GOOD) |
| continue; |
| |
| if (line == 0) { |
| if (reporttype) |
| fprintf(reportout.http_report, |
| "<h2>Optimal Tuned Software Settings</h2>\n <table width=\"100%%\">\n"); |
| else |
| fprintf(reportout.csv_report, |
| "**Optimal Tuned Software Settings**, \n\n"); |
| } |
| |
| line++; |
| if (i < 1 && !reporttype) |
| fprintf(reportout.csv_report, "Description, \n"); |
| |
| if (reporttype) |
| fprintf(reportout.http_report,"<tr class=\"%s\"><td>%s</td></tr>\n", |
| tune_class(line), all_tunables[i]->description()); |
| else |
| fprintf(reportout.csv_report,"\"%s\", \n", all_tunables[i]->description()); |
| } |
| |
| if (line > 0){ |
| if (reporttype) |
| fprintf(reportout.http_report,"</table></div>\n"); |
| else |
| fprintf(reportout.csv_report,"\n"); |
| } |
| } |
| |
| 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(); |
| } |