powertop.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * A mini 'powertop' utility:
  4. * Analyze power consumption on Intel-based laptops.
  5. * Based on powertop 1.11.
  6. *
  7. * Copyright (C) 2010 Marek Polacek <mmpolacek@gmail.com>
  8. *
  9. * Licensed under GPLv2, see file LICENSE in this source tree.
  10. */
  11. //config:config POWERTOP
  12. //config: bool "powertop (9.9 kb)"
  13. //config: default y
  14. //config: help
  15. //config: Analyze power consumption on Intel-based laptops
  16. //config:
  17. //config:config FEATURE_POWERTOP_INTERACTIVE
  18. //config: bool "Accept keyboard commands"
  19. //config: default y
  20. //config: depends on POWERTOP
  21. //config: help
  22. //config: Without this, powertop will only refresh display every 10 seconds.
  23. //config: No keyboard commands will work, only ^C to terminate.
  24. //applet:IF_POWERTOP(APPLET(powertop, BB_DIR_USR_SBIN, BB_SUID_DROP))
  25. //kbuild:lib-$(CONFIG_POWERTOP) += powertop.o
  26. // XXX This should be configurable
  27. #define ENABLE_FEATURE_POWERTOP_PROCIRQ 1
  28. #include "libbb.h"
  29. //#define debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__)
  30. #define debug(fmt, ...) ((void)0)
  31. #define BLOATY_HPET_IRQ_NUM_DETECTION 0
  32. #define MAX_CSTATE_COUNT 8
  33. #define IRQCOUNT 40
  34. #define DEFAULT_SLEEP 10
  35. #define DEFAULT_SLEEP_STR "10"
  36. /* Frequency of the ACPI timer */
  37. #define FREQ_ACPI 3579.545
  38. #define FREQ_ACPI_1000 3579545
  39. /* Max filename length of entry in /sys/devices subsystem */
  40. #define BIG_SYSNAME_LEN 16
  41. #define ESC "\033"
  42. typedef unsigned long long ullong;
  43. struct line {
  44. char *string;
  45. int count;
  46. /*int disk_count;*/
  47. };
  48. #if ENABLE_FEATURE_POWERTOP_PROCIRQ
  49. struct irqdata {
  50. smallint active;
  51. int number;
  52. ullong count;
  53. char irq_desc[32];
  54. };
  55. #endif
  56. struct globals {
  57. struct line *lines; /* the most often used member */
  58. int lines_cnt;
  59. int lines_cumulative_count;
  60. int maxcstate;
  61. unsigned total_cpus;
  62. smallint cant_enable_timer_stats;
  63. #if ENABLE_FEATURE_POWERTOP_PROCIRQ
  64. # if BLOATY_HPET_IRQ_NUM_DETECTION
  65. smallint scanned_timer_list;
  66. int percpu_hpet_start;
  67. int percpu_hpet_end;
  68. # endif
  69. int interrupt_0;
  70. int total_interrupt;
  71. struct irqdata interrupts[IRQCOUNT];
  72. #endif
  73. ullong start_usage[MAX_CSTATE_COUNT];
  74. ullong last_usage[MAX_CSTATE_COUNT];
  75. ullong start_duration[MAX_CSTATE_COUNT];
  76. ullong last_duration[MAX_CSTATE_COUNT];
  77. #if ENABLE_FEATURE_POWERTOP_INTERACTIVE
  78. struct termios init_settings;
  79. #endif
  80. };
  81. #define G (*ptr_to_globals)
  82. #define INIT_G() do { \
  83. SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
  84. } while (0)
  85. #if ENABLE_FEATURE_POWERTOP_INTERACTIVE
  86. static void reset_term(void)
  87. {
  88. tcsetattr_stdin_TCSANOW(&G.init_settings);
  89. }
  90. static void sig_handler(int signo UNUSED_PARAM)
  91. {
  92. reset_term();
  93. _exit_FAILURE();
  94. }
  95. #endif
  96. static int write_str_to_file(const char *fname, const char *str)
  97. {
  98. FILE *fp = fopen_for_write(fname);
  99. if (!fp)
  100. return 1;
  101. fputs(str, fp);
  102. fclose(fp);
  103. return 0;
  104. }
  105. /* Make it more readable */
  106. #define start_timer() write_str_to_file("/proc/timer_stats", "1\n")
  107. #define stop_timer() write_str_to_file("/proc/timer_stats", "0\n")
  108. static NOINLINE void clear_lines(void)
  109. {
  110. int i;
  111. if (G.lines) {
  112. for (i = 0; i < G.lines_cnt; i++)
  113. free(G.lines[i].string);
  114. free(G.lines);
  115. G.lines_cnt = 0;
  116. G.lines = NULL;
  117. }
  118. }
  119. static void update_lines_cumulative_count(void)
  120. {
  121. int i;
  122. for (i = 0; i < G.lines_cnt; i++)
  123. G.lines_cumulative_count += G.lines[i].count;
  124. }
  125. static int line_compare(const void *p1, const void *p2)
  126. {
  127. const struct line *a = p1;
  128. const struct line *b = p2;
  129. return (b->count /*+ 50 * b->disk_count*/) - (a->count /*+ 50 * a->disk_count*/);
  130. }
  131. static void sort_lines(void)
  132. {
  133. qsort(G.lines, G.lines_cnt, sizeof(G.lines[0]), line_compare);
  134. }
  135. /* Save C-state usage and duration. Also update maxcstate. */
  136. static void read_cstate_counts(ullong *usage, ullong *duration)
  137. {
  138. DIR *dir;
  139. struct dirent *d;
  140. dir = opendir("/proc/acpi/processor");
  141. if (!dir)
  142. return;
  143. while ((d = readdir(dir)) != NULL) {
  144. FILE *fp;
  145. char buf[192];
  146. int level;
  147. int len;
  148. len = strlen(d->d_name); /* "CPUnn" */
  149. if (len < 3 || len > BIG_SYSNAME_LEN)
  150. continue;
  151. sprintf(buf, "%s/%s/power", "/proc/acpi/processor", d->d_name);
  152. fp = fopen_for_read(buf);
  153. if (!fp)
  154. continue;
  155. // Example file contents:
  156. // active state: C0
  157. // max_cstate: C8
  158. // maximum allowed latency: 2000000000 usec
  159. // states:
  160. // C1: type[C1] promotion[--] demotion[--] latency[001] usage[00006173] duration[00000000000000000000]
  161. // C2: type[C2] promotion[--] demotion[--] latency[001] usage[00085191] duration[00000000000083024907]
  162. // C3: type[C3] promotion[--] demotion[--] latency[017] usage[01017622] duration[00000000017921327182]
  163. level = 0;
  164. while (fgets(buf, sizeof(buf), fp)) {
  165. char *p = strstr(buf, "age[");
  166. if (!p)
  167. continue;
  168. p += 4;
  169. usage[level] += bb_strtoull(p, NULL, 10) + 1;
  170. p = strstr(buf, "ation[");
  171. if (!p)
  172. continue;
  173. p += 6;
  174. duration[level] += bb_strtoull(p, NULL, 10);
  175. if (level >= MAX_CSTATE_COUNT-1)
  176. break;
  177. level++;
  178. if (level > G.maxcstate) /* update maxcstate */
  179. G.maxcstate = level;
  180. }
  181. fclose(fp);
  182. }
  183. closedir(dir);
  184. }
  185. /* Add line and/or update count */
  186. static void save_line(const char *string, int count)
  187. {
  188. int i;
  189. for (i = 0; i < G.lines_cnt; i++) {
  190. if (strcmp(string, G.lines[i].string) == 0) {
  191. /* It's already there, only update count */
  192. G.lines[i].count += count;
  193. return;
  194. }
  195. }
  196. /* Add new line */
  197. G.lines = xrealloc_vector(G.lines, 4, G.lines_cnt);
  198. G.lines[G.lines_cnt].string = xstrdup(string);
  199. G.lines[G.lines_cnt].count = count;
  200. /*G.lines[G.lines_cnt].disk_count = 0;*/
  201. G.lines_cnt++;
  202. }
  203. #if ENABLE_FEATURE_POWERTOP_PROCIRQ
  204. static int is_hpet_irq(const char *name)
  205. {
  206. char *p;
  207. # if BLOATY_HPET_IRQ_NUM_DETECTION
  208. long hpet_chan;
  209. /* Learn the range of existing hpet timers. This is done once */
  210. if (!G.scanned_timer_list) {
  211. FILE *fp;
  212. char buf[80];
  213. G.scanned_timer_list = true;
  214. fp = fopen_for_read("/proc/timer_list");
  215. if (!fp)
  216. return 0;
  217. while (fgets(buf, sizeof(buf), fp)) {
  218. p = strstr(buf, "Clock Event Device: hpet");
  219. if (!p)
  220. continue;
  221. p += sizeof("Clock Event Device: hpet")-1;
  222. if (!isdigit(*p))
  223. continue;
  224. hpet_chan = xatoi_positive(p);
  225. if (hpet_chan < G.percpu_hpet_start)
  226. G.percpu_hpet_start = hpet_chan;
  227. if (hpet_chan > G.percpu_hpet_end)
  228. G.percpu_hpet_end = hpet_chan;
  229. }
  230. fclose(fp);
  231. }
  232. # endif
  233. //TODO: optimize
  234. p = strstr(name, "hpet");
  235. if (!p)
  236. return 0;
  237. p += 4;
  238. if (!isdigit(*p))
  239. return 0;
  240. # if BLOATY_HPET_IRQ_NUM_DETECTION
  241. hpet_chan = xatoi_positive(p);
  242. if (hpet_chan < G.percpu_hpet_start || hpet_chan > G.percpu_hpet_end)
  243. return 0;
  244. # endif
  245. return 1;
  246. }
  247. /* Save new IRQ count, return delta from old one */
  248. static int save_irq_count(int irq, ullong count)
  249. {
  250. int unused = IRQCOUNT;
  251. int i;
  252. for (i = 0; i < IRQCOUNT; i++) {
  253. if (G.interrupts[i].active && G.interrupts[i].number == irq) {
  254. ullong old = G.interrupts[i].count;
  255. G.interrupts[i].count = count;
  256. return count - old;
  257. }
  258. if (!G.interrupts[i].active && unused > i)
  259. unused = i;
  260. }
  261. if (unused < IRQCOUNT) {
  262. G.interrupts[unused].active = 1;
  263. G.interrupts[unused].count = count;
  264. G.interrupts[unused].number = irq;
  265. }
  266. return count;
  267. }
  268. /* Read /proc/interrupts, save IRQ counts and IRQ description */
  269. static void process_irq_counts(void)
  270. {
  271. FILE *fp;
  272. char buf[128];
  273. /* Reset values */
  274. G.interrupt_0 = 0;
  275. G.total_interrupt = 0;
  276. fp = xfopen_for_read("/proc/interrupts");
  277. while (fgets(buf, sizeof(buf), fp)) {
  278. char irq_desc[sizeof(" <kernel IPI> : ") + sizeof(buf)];
  279. char *p;
  280. const char *name;
  281. int nr;
  282. ullong count;
  283. ullong delta;
  284. p = strchr(buf, ':');
  285. if (!p)
  286. continue;
  287. /* 0: 143646045 153901007 IO-APIC-edge timer
  288. * ^
  289. */
  290. *p = '\0';
  291. /* Deal with non-maskable interrupts -- make up fake numbers */
  292. nr = index_in_strings("NMI\0RES\0CAL\0TLB\0TRM\0THR\0SPU\0", buf);
  293. if (nr >= 0) {
  294. nr += 20000;
  295. } else {
  296. /* bb_strtou doesn't eat leading spaces, using strtoul */
  297. errno = 0;
  298. nr = strtoul(buf, NULL, 10);
  299. if (errno)
  300. continue;
  301. }
  302. p++;
  303. /* 0: 143646045 153901007 IO-APIC-edge timer
  304. * ^
  305. */
  306. /* Sum counts for this IRQ */
  307. count = 0;
  308. while (1) {
  309. char *tmp;
  310. p = skip_whitespace(p);
  311. if (!isdigit(*p))
  312. break;
  313. count += bb_strtoull(p, &tmp, 10);
  314. p = tmp;
  315. }
  316. /* 0: 143646045 153901007 IO-APIC-edge timer
  317. * NMI: 1 2 Non-maskable interrupts
  318. * ^
  319. */
  320. if (nr < 20000) {
  321. /* Skip to the interrupt name, e.g. 'timer' */
  322. p = strchr(p, ' ');
  323. if (!p)
  324. continue;
  325. p = skip_whitespace(p);
  326. }
  327. name = p;
  328. chomp(p);
  329. /* Save description of the interrupt */
  330. if (nr >= 20000)
  331. sprintf(irq_desc, " <kernel IPI> : %s", name);
  332. else
  333. sprintf(irq_desc, " <interrupt> : %s", name);
  334. delta = save_irq_count(nr, count);
  335. /* Skip per CPU timer interrupts */
  336. if (is_hpet_irq(name))
  337. continue;
  338. if (nr != 0 && delta != 0)
  339. save_line(irq_desc, delta);
  340. if (nr == 0)
  341. G.interrupt_0 = delta;
  342. else
  343. G.total_interrupt += delta;
  344. }
  345. fclose(fp);
  346. }
  347. #else /* !ENABLE_FEATURE_POWERTOP_PROCIRQ */
  348. # define process_irq_counts() ((void)0)
  349. #endif
  350. static NOINLINE int process_timer_stats(void)
  351. {
  352. char buf[128];
  353. char line[15 + 3 + 128];
  354. int n;
  355. FILE *fp;
  356. buf[0] = '\0';
  357. n = 0;
  358. fp = NULL;
  359. if (!G.cant_enable_timer_stats)
  360. fp = fopen_for_read("/proc/timer_stats");
  361. if (fp) {
  362. // Example file contents:
  363. // Timer Stats Version: v0.2
  364. // Sample period: 1.329 s
  365. // 76, 0 swapper hrtimer_start_range_ns (tick_sched_timer)
  366. // 88, 0 swapper hrtimer_start_range_ns (tick_sched_timer)
  367. // 24, 3787 firefox hrtimer_start_range_ns (hrtimer_wakeup)
  368. // 46D, 1136 kondemand/1 do_dbs_timer (delayed_work_timer_fn)
  369. // ...
  370. // 1, 1656 Xorg hrtimer_start_range_ns (hrtimer_wakeup)
  371. // 1, 2159 udisks-daemon hrtimer_start_range_ns (hrtimer_wakeup)
  372. // 331 total events, 249.059 events/sec
  373. while (fgets(buf, sizeof(buf), fp)) {
  374. const char *count, *process, *func;
  375. char *p;
  376. int idx;
  377. unsigned cnt;
  378. count = skip_whitespace(buf);
  379. p = strchr(count, ',');
  380. if (!p)
  381. continue;
  382. *p++ = '\0';
  383. cnt = bb_strtou(count, NULL, 10);
  384. if (strcmp(skip_non_whitespace(count), " total events") == 0) {
  385. #if ENABLE_FEATURE_POWERTOP_PROCIRQ
  386. n = cnt / G.total_cpus;
  387. if (n > 0 && n < G.interrupt_0) {
  388. sprintf(line, " <interrupt> : %s", "extra timer interrupt");
  389. save_line(line, G.interrupt_0 - n);
  390. }
  391. #endif
  392. break;
  393. }
  394. if (strchr(count, 'D'))
  395. continue; /* deferred */
  396. p = skip_whitespace(p); /* points to pid now */
  397. process = NULL;
  398. get_func_name:
  399. p = strchr(p, ' ');
  400. if (!p)
  401. continue;
  402. *p++ = '\0';
  403. p = skip_whitespace(p);
  404. if (process == NULL) {
  405. process = p;
  406. goto get_func_name;
  407. }
  408. func = p;
  409. //if (strcmp(process, "swapper") == 0
  410. // && strcmp(func, "hrtimer_start_range_ns (tick_sched_timer)\n") == 0
  411. //) {
  412. // process = "[kernel scheduler]";
  413. // func = "Load balancing tick";
  414. //}
  415. if (is_prefixed_with(func, "tick_nohz_"))
  416. continue;
  417. if (is_prefixed_with(func, "tick_setup_sched_timer"))
  418. continue;
  419. //if (strcmp(process, "powertop") == 0)
  420. // continue;
  421. idx = index_in_strings("insmod\0modprobe\0swapper\0", process);
  422. if (idx != -1) {
  423. process = idx < 2 ? "[kernel module]" : "<kernel core>";
  424. }
  425. chomp(p);
  426. // 46D\01136\0kondemand/1\0do_dbs_timer (delayed_work_timer_fn)
  427. // ^ ^ ^
  428. // count process func
  429. //if (strchr(process, '['))
  430. sprintf(line, "%15.15s : %s", process, func);
  431. //else
  432. // sprintf(line, "%s", process);
  433. save_line(line, cnt);
  434. }
  435. fclose(fp);
  436. }
  437. return n;
  438. }
  439. #ifdef __i386__
  440. static void cpuid_eax_ecx_edx(unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx)
  441. {
  442. asm ("cpuid"
  443. : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
  444. : "0" (*eax), "2" (*ecx), "3" (*edx)
  445. );
  446. }
  447. #endif
  448. #ifdef __i386__
  449. static NOINLINE void print_intel_cstates(void)
  450. {
  451. int bios_table[8] = { 0 };
  452. int nbios = 0;
  453. DIR *cpudir;
  454. struct dirent *d;
  455. int i;
  456. unsigned eax, ebx, ecx, edx;
  457. cpudir = opendir("/sys/devices/system/cpu");
  458. if (!cpudir)
  459. return;
  460. /* Loop over cpuN entries */
  461. while ((d = readdir(cpudir)) != NULL) {
  462. DIR *dir;
  463. int len;
  464. char fname[sizeof("/sys/devices/system/cpu//cpuidle//desc") + 2*BIG_SYSNAME_LEN];
  465. len = strlen(d->d_name);
  466. if (len < 3 || len > BIG_SYSNAME_LEN)
  467. continue;
  468. if (!isdigit(d->d_name[3]))
  469. continue;
  470. len = sprintf(fname, "%s/%s/cpuidle", "/sys/devices/system/cpu", d->d_name);
  471. dir = opendir(fname);
  472. if (!dir)
  473. continue;
  474. /*
  475. * Every C-state has its own stateN directory, that
  476. * contains a 'time' and a 'usage' file.
  477. */
  478. while ((d = readdir(dir)) != NULL) {
  479. FILE *fp;
  480. char buf[64];
  481. int n;
  482. n = strlen(d->d_name);
  483. if (n < 3 || n > BIG_SYSNAME_LEN)
  484. continue;
  485. sprintf(fname + len, "/%s/desc", d->d_name);
  486. fp = fopen_for_read(fname);
  487. if (fp) {
  488. char *p = fgets(buf, sizeof(buf), fp);
  489. fclose(fp);
  490. if (!p)
  491. break;
  492. p = strstr(p, "MWAIT ");
  493. if (p) {
  494. int pos;
  495. p += sizeof("MWAIT ") - 1;
  496. pos = (bb_strtoull(p, NULL, 16) >> 4) + 1;
  497. if (pos >= ARRAY_SIZE(bios_table))
  498. continue;
  499. bios_table[pos]++;
  500. nbios++;
  501. }
  502. }
  503. }
  504. closedir(dir);
  505. }
  506. closedir(cpudir);
  507. if (!nbios)
  508. return;
  509. eax = 5;
  510. ecx = edx = 0; /* paranoia, should not be needed */
  511. cpuid_eax_ecx_edx(&eax, /*unused:*/&ebx, &ecx, &edx);
  512. if (!edx || !(ecx & 1))
  513. return;
  514. printf("Your %s the following C-states: ", "CPU supports");
  515. i = 0;
  516. while (edx) {
  517. if (edx & 7)
  518. printf("C%u ", i);
  519. edx >>= 4;
  520. i++;
  521. }
  522. bb_putchar('\n');
  523. /* Print BIOS C-States */
  524. printf("Your %s the following C-states: ", "BIOS reports");
  525. for (i = 0; i < ARRAY_SIZE(bios_table); i++)
  526. if (bios_table[i])
  527. printf("C%u ", i);
  528. bb_putchar('\n');
  529. }
  530. #else
  531. # define print_intel_cstates() ((void)0)
  532. #endif
  533. static void show_timerstats(void)
  534. {
  535. unsigned lines;
  536. /* Get terminal height */
  537. get_terminal_width_height(STDOUT_FILENO, NULL, &lines);
  538. /* We don't have whole terminal just for timerstats */
  539. lines -= 12;
  540. if (!G.cant_enable_timer_stats) {
  541. int i, n = 0;
  542. char strbuf6[6];
  543. puts("\nTop causes for wakeups:");
  544. for (i = 0; i < G.lines_cnt; i++) {
  545. if ((G.lines[i].count > 0 /*|| G.lines[i].disk_count > 0*/)
  546. && n++ < lines
  547. ) {
  548. /* NB: upstream powertop prints "(wakeups/sec)",
  549. * we print just "(wakeup counts)".
  550. */
  551. /*char c = ' ';
  552. if (G.lines[i].disk_count)
  553. c = 'D';*/
  554. smart_ulltoa5(G.lines[i].count, strbuf6, " KMGTPEZY")[0] = '\0';
  555. printf(/*" %5.1f%% (%s)%c %s\n"*/
  556. " %5.1f%% (%s) %s\n",
  557. G.lines[i].count * 100.0 / G.lines_cumulative_count,
  558. strbuf6, /*c,*/
  559. G.lines[i].string);
  560. }
  561. }
  562. } else {
  563. bb_putchar('\n');
  564. bb_simple_error_msg("no stats available; run as root or"
  565. " enable the timer_stats module");
  566. }
  567. }
  568. // Example display from powertop version 1.11
  569. // Cn Avg residency P-states (frequencies)
  570. // C0 (cpu running) ( 0.5%) 2.00 Ghz 0.0%
  571. // polling 0.0ms ( 0.0%) 1.67 Ghz 0.0%
  572. // C1 mwait 0.0ms ( 0.0%) 1333 Mhz 0.1%
  573. // C2 mwait 0.1ms ( 0.1%) 1000 Mhz 99.9%
  574. // C3 mwait 12.1ms (99.4%)
  575. //
  576. // Wakeups-from-idle per second : 93.6 interval: 15.0s
  577. // no ACPI power usage estimate available
  578. //
  579. // Top causes for wakeups:
  580. // 32.4% ( 26.7) <interrupt> : extra timer interrupt
  581. // 29.0% ( 23.9) <kernel core> : hrtimer_start_range_ns (tick_sched_timer)
  582. // 9.0% ( 7.5) <kernel core> : hrtimer_start (tick_sched_timer)
  583. // 6.5% ( 5.3) <interrupt> : ata_piix
  584. // 5.0% ( 4.1) inetd : hrtimer_start_range_ns (hrtimer_wakeup)
  585. //usage:#define powertop_trivial_usage
  586. //usage: ""
  587. //usage:#define powertop_full_usage "\n\n"
  588. //usage: "Analyze power consumption on Intel-based laptops"
  589. int powertop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  590. int powertop_main(int argc UNUSED_PARAM, char UNUSED_PARAM **argv)
  591. {
  592. ullong cur_usage[MAX_CSTATE_COUNT];
  593. ullong cur_duration[MAX_CSTATE_COUNT];
  594. char cstate_lines[MAX_CSTATE_COUNT + 2][64];
  595. #if ENABLE_FEATURE_POWERTOP_INTERACTIVE
  596. struct pollfd pfd[1];
  597. pfd[0].fd = 0;
  598. pfd[0].events = POLLIN;
  599. #endif
  600. INIT_G();
  601. #if ENABLE_FEATURE_POWERTOP_PROCIRQ && BLOATY_HPET_IRQ_NUM_DETECTION
  602. G.percpu_hpet_start = INT_MAX;
  603. G.percpu_hpet_end = INT_MIN;
  604. #endif
  605. /* Print warning when we don't have superuser privileges */
  606. if (geteuid() != 0)
  607. bb_simple_error_msg("run as root to collect enough information");
  608. /* Get number of CPUs */
  609. G.total_cpus = get_cpu_count();
  610. puts("Collecting data for "DEFAULT_SLEEP_STR" seconds");
  611. #if ENABLE_FEATURE_POWERTOP_INTERACTIVE
  612. /* Turn on unbuffered input; turn off echoing, ^C ^Z etc */
  613. set_termios_to_raw(STDIN_FILENO, &G.init_settings, TERMIOS_CLEAR_ISIG);
  614. bb_signals(BB_FATAL_SIGS, sig_handler);
  615. /* So we don't forget to reset term settings */
  616. die_func = reset_term;
  617. #endif
  618. /* Collect initial data */
  619. process_irq_counts();
  620. /* Read initial usage and duration */
  621. read_cstate_counts(G.start_usage, G.start_duration);
  622. /* Copy them to "last" */
  623. memcpy(G.last_usage, G.start_usage, sizeof(G.last_usage));
  624. memcpy(G.last_duration, G.start_duration, sizeof(G.last_duration));
  625. /* Display C-states */
  626. print_intel_cstates();
  627. G.cant_enable_timer_stats |= stop_timer(); /* 1 on error */
  628. /* The main loop */
  629. for (;;) {
  630. //double maxsleep = 0.0;
  631. ullong totalticks, totalevents;
  632. int i;
  633. G.cant_enable_timer_stats |= start_timer(); /* 1 on error */
  634. #if !ENABLE_FEATURE_POWERTOP_INTERACTIVE
  635. sleep(DEFAULT_SLEEP);
  636. #else
  637. if (safe_poll(pfd, 1, DEFAULT_SLEEP * 1000) > 0) {
  638. unsigned char c;
  639. if (safe_read(STDIN_FILENO, &c, 1) != 1)
  640. break; /* EOF/error */
  641. if (c == G.init_settings.c_cc[VINTR])
  642. break; /* ^C */
  643. if ((c | 0x20) == 'q')
  644. break;
  645. }
  646. #endif
  647. G.cant_enable_timer_stats |= stop_timer(); /* 1 on error */
  648. clear_lines();
  649. process_irq_counts();
  650. /* Clear the stats */
  651. memset(cur_duration, 0, sizeof(cur_duration));
  652. memset(cur_usage, 0, sizeof(cur_usage));
  653. /* Read them */
  654. read_cstate_counts(cur_usage, cur_duration);
  655. /* Count totalticks and totalevents */
  656. totalticks = totalevents = 0;
  657. for (i = 0; i < MAX_CSTATE_COUNT; i++) {
  658. if (cur_usage[i] != 0) {
  659. totalticks += cur_duration[i] - G.last_duration[i];
  660. totalevents += cur_usage[i] - G.last_usage[i];
  661. }
  662. }
  663. /* Home; clear screen */
  664. printf(ESC"[H" ESC"[J");
  665. /* Clear C-state lines */
  666. memset(&cstate_lines, 0, sizeof(cstate_lines));
  667. if (totalevents == 0 && G.maxcstate <= 1) {
  668. /* This should not happen */
  669. strcpy(cstate_lines[0], "C-state information is not available\n");
  670. } else {
  671. double percentage;
  672. unsigned newticks;
  673. newticks = G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000 - totalticks;
  674. /* Handle rounding errors: do not display negative values */
  675. if ((int)newticks < 0)
  676. newticks = 0;
  677. sprintf(cstate_lines[0], "Cn\t\t Avg residency\n");
  678. percentage = newticks * 100.0 / (G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000);
  679. sprintf(cstate_lines[1], "C0 (cpu running) (%4.1f%%)\n", percentage);
  680. /* Compute values for individual C-states */
  681. for (i = 0; i < MAX_CSTATE_COUNT; i++) {
  682. if (cur_usage[i] != 0) {
  683. double slept;
  684. slept = (cur_duration[i] - G.last_duration[i])
  685. / (cur_usage[i] - G.last_usage[i] + 0.1) / FREQ_ACPI;
  686. percentage = (cur_duration[i] - G.last_duration[i]) * 100
  687. / (G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000);
  688. sprintf(cstate_lines[i + 2], "C%u\t\t%5.1fms (%4.1f%%)\n",
  689. i + 1, slept, percentage);
  690. //if (maxsleep < slept)
  691. // maxsleep = slept;
  692. }
  693. }
  694. }
  695. for (i = 0; i < MAX_CSTATE_COUNT + 2; i++)
  696. if (cstate_lines[i][0])
  697. fputs_stdout(cstate_lines[i]);
  698. i = process_timer_stats();
  699. #if ENABLE_FEATURE_POWERTOP_PROCIRQ
  700. if (totalevents == 0) {
  701. /* No C-state info available, use timerstats */
  702. totalevents = i * G.total_cpus + G.total_interrupt;
  703. if (i < 0)
  704. totalevents += G.interrupt_0 - i;
  705. }
  706. #endif
  707. /* Upstream powertop prints wakeups per sec per CPU,
  708. * we print just raw wakeup counts.
  709. */
  710. //TODO: show real seconds (think about manual refresh)
  711. printf("\nWakeups-from-idle in %u seconds: %llu\n",
  712. DEFAULT_SLEEP,
  713. totalevents
  714. );
  715. update_lines_cumulative_count();
  716. sort_lines();
  717. show_timerstats();
  718. fflush(stdout);
  719. /* Clear the stats */
  720. memset(cur_duration, 0, sizeof(cur_duration));
  721. memset(cur_usage, 0, sizeof(cur_usage));
  722. /* Get new values */
  723. read_cstate_counts(cur_usage, cur_duration);
  724. /* Save them */
  725. memcpy(G.last_usage, cur_usage, sizeof(G.last_usage));
  726. memcpy(G.last_duration, cur_duration, sizeof(G.last_duration));
  727. } /* for (;;) */
  728. bb_putchar('\n');
  729. #if ENABLE_FEATURE_POWERTOP_INTERACTIVE
  730. reset_term();
  731. #endif
  732. return EXIT_SUCCESS;
  733. }