cpufreq-info.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. /*
  2. * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
  3. *
  4. * Licensed under the terms of the GNU GPL License version 2.
  5. */
  6. #include <unistd.h>
  7. #include <stdio.h>
  8. #include <errno.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <limits.h>
  12. #include <getopt.h>
  13. #include "cpufreq.h"
  14. #include "helpers/sysfs.h"
  15. #include "helpers/helpers.h"
  16. #include "helpers/bitmask.h"
  17. #define LINE_LEN 10
  18. static unsigned int count_cpus(void)
  19. {
  20. FILE *fp;
  21. char value[LINE_LEN];
  22. unsigned int ret = 0;
  23. unsigned int cpunr = 0;
  24. fp = fopen("/proc/stat", "r");
  25. if (!fp) {
  26. printf(_("Couldn't count the number of CPUs (%s: %s), assuming 1\n"), "/proc/stat", strerror(errno));
  27. return 1;
  28. }
  29. while (!feof(fp)) {
  30. if (!fgets(value, LINE_LEN, fp))
  31. continue;
  32. value[LINE_LEN - 1] = '\0';
  33. if (strlen(value) < (LINE_LEN - 2))
  34. continue;
  35. if (strstr(value, "cpu "))
  36. continue;
  37. if (sscanf(value, "cpu%d ", &cpunr) != 1)
  38. continue;
  39. if (cpunr > ret)
  40. ret = cpunr;
  41. }
  42. fclose(fp);
  43. /* cpu count starts from 0, on error return 1 (UP) */
  44. return ret + 1;
  45. }
  46. static void proc_cpufreq_output(void)
  47. {
  48. unsigned int cpu, nr_cpus;
  49. struct cpufreq_policy *policy;
  50. unsigned int min_pctg = 0;
  51. unsigned int max_pctg = 0;
  52. unsigned long min, max;
  53. printf(_(" minimum CPU frequency - maximum CPU frequency - governor\n"));
  54. nr_cpus = count_cpus();
  55. for (cpu = 0; cpu < nr_cpus; cpu++) {
  56. policy = cpufreq_get_policy(cpu);
  57. if (!policy)
  58. continue;
  59. if (cpufreq_get_hardware_limits(cpu, &min, &max)) {
  60. max = 0;
  61. } else {
  62. min_pctg = (policy->min * 100) / max;
  63. max_pctg = (policy->max * 100) / max;
  64. }
  65. printf("CPU%3d %9lu kHz (%3d %%) - %9lu kHz (%3d %%) - %s\n",
  66. cpu , policy->min, max ? min_pctg : 0, policy->max,
  67. max ? max_pctg : 0, policy->governor);
  68. cpufreq_put_policy(policy);
  69. }
  70. }
  71. static int no_rounding;
  72. static void print_speed(unsigned long speed)
  73. {
  74. unsigned long tmp;
  75. if (no_rounding) {
  76. if (speed > 1000000)
  77. printf("%u.%06u GHz", ((unsigned int) speed/1000000),
  78. ((unsigned int) speed%1000000));
  79. else if (speed > 100000)
  80. printf("%u MHz", (unsigned int) speed);
  81. else if (speed > 1000)
  82. printf("%u.%03u MHz", ((unsigned int) speed/1000),
  83. (unsigned int) (speed%1000));
  84. else
  85. printf("%lu kHz", speed);
  86. } else {
  87. if (speed > 1000000) {
  88. tmp = speed%10000;
  89. if (tmp >= 5000)
  90. speed += 10000;
  91. printf("%u.%02u GHz", ((unsigned int) speed/1000000),
  92. ((unsigned int) (speed%1000000)/10000));
  93. } else if (speed > 100000) {
  94. tmp = speed%1000;
  95. if (tmp >= 500)
  96. speed += 1000;
  97. printf("%u MHz", ((unsigned int) speed/1000));
  98. } else if (speed > 1000) {
  99. tmp = speed%100;
  100. if (tmp >= 50)
  101. speed += 100;
  102. printf("%u.%01u MHz", ((unsigned int) speed/1000),
  103. ((unsigned int) (speed%1000)/100));
  104. }
  105. }
  106. return;
  107. }
  108. static void print_duration(unsigned long duration)
  109. {
  110. unsigned long tmp;
  111. if (no_rounding) {
  112. if (duration > 1000000)
  113. printf("%u.%06u ms", ((unsigned int) duration/1000000),
  114. ((unsigned int) duration%1000000));
  115. else if (duration > 100000)
  116. printf("%u us", ((unsigned int) duration/1000));
  117. else if (duration > 1000)
  118. printf("%u.%03u us", ((unsigned int) duration/1000),
  119. ((unsigned int) duration%1000));
  120. else
  121. printf("%lu ns", duration);
  122. } else {
  123. if (duration > 1000000) {
  124. tmp = duration%10000;
  125. if (tmp >= 5000)
  126. duration += 10000;
  127. printf("%u.%02u ms", ((unsigned int) duration/1000000),
  128. ((unsigned int) (duration%1000000)/10000));
  129. } else if (duration > 100000) {
  130. tmp = duration%1000;
  131. if (tmp >= 500)
  132. duration += 1000;
  133. printf("%u us", ((unsigned int) duration / 1000));
  134. } else if (duration > 1000) {
  135. tmp = duration%100;
  136. if (tmp >= 50)
  137. duration += 100;
  138. printf("%u.%01u us", ((unsigned int) duration/1000),
  139. ((unsigned int) (duration%1000)/100));
  140. } else
  141. printf("%lu ns", duration);
  142. }
  143. return;
  144. }
  145. /* --boost / -b */
  146. static int get_boost_mode(unsigned int cpu)
  147. {
  148. int support, active, b_states = 0, ret, pstate_no, i;
  149. /* ToDo: Make this more global */
  150. unsigned long pstates[MAX_HW_PSTATES] = {0,};
  151. if (cpupower_cpu_info.vendor != X86_VENDOR_AMD &&
  152. cpupower_cpu_info.vendor != X86_VENDOR_INTEL)
  153. return 0;
  154. ret = cpufreq_has_boost_support(cpu, &support, &active, &b_states);
  155. if (ret) {
  156. printf(_("Error while evaluating Boost Capabilities"
  157. " on CPU %d -- are you root?\n"), cpu);
  158. return ret;
  159. }
  160. /* P state changes via MSR are identified via cpuid 80000007
  161. on Intel and AMD, but we assume boost capable machines can do that
  162. if (cpuid_eax(0x80000000) >= 0x80000007
  163. && (cpuid_edx(0x80000007) & (1 << 7)))
  164. */
  165. printf(_(" boost state support:\n"));
  166. printf(_(" Supported: %s\n"), support ? _("yes") : _("no"));
  167. printf(_(" Active: %s\n"), active ? _("yes") : _("no"));
  168. if (cpupower_cpu_info.vendor == X86_VENDOR_AMD &&
  169. cpupower_cpu_info.family >= 0x10) {
  170. ret = decode_pstates(cpu, cpupower_cpu_info.family, b_states,
  171. pstates, &pstate_no);
  172. if (ret)
  173. return ret;
  174. printf(_(" Boost States: %d\n"), b_states);
  175. printf(_(" Total States: %d\n"), pstate_no);
  176. for (i = 0; i < pstate_no; i++) {
  177. if (i < b_states)
  178. printf(_(" Pstate-Pb%d: %luMHz (boost state)"
  179. "\n"), i, pstates[i]);
  180. else
  181. printf(_(" Pstate-P%d: %luMHz\n"),
  182. i - b_states, pstates[i]);
  183. }
  184. } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_HAS_TURBO_RATIO) {
  185. double bclk;
  186. unsigned long long intel_turbo_ratio = 0;
  187. unsigned int ratio;
  188. /* Any way to autodetect this ? */
  189. if (cpupower_cpu_info.caps & CPUPOWER_CAP_IS_SNB)
  190. bclk = 100.00;
  191. else
  192. bclk = 133.33;
  193. intel_turbo_ratio = msr_intel_get_turbo_ratio(cpu);
  194. dprint (" Ratio: 0x%llx - bclk: %f\n",
  195. intel_turbo_ratio, bclk);
  196. ratio = (intel_turbo_ratio >> 24) & 0xFF;
  197. if (ratio)
  198. printf(_(" %.0f MHz max turbo 4 active cores\n"),
  199. ratio * bclk);
  200. ratio = (intel_turbo_ratio >> 16) & 0xFF;
  201. if (ratio)
  202. printf(_(" %.0f MHz max turbo 3 active cores\n"),
  203. ratio * bclk);
  204. ratio = (intel_turbo_ratio >> 8) & 0xFF;
  205. if (ratio)
  206. printf(_(" %.0f MHz max turbo 2 active cores\n"),
  207. ratio * bclk);
  208. ratio = (intel_turbo_ratio >> 0) & 0xFF;
  209. if (ratio)
  210. printf(_(" %.0f MHz max turbo 1 active cores\n"),
  211. ratio * bclk);
  212. }
  213. return 0;
  214. }
  215. /* --freq / -f */
  216. static int get_freq_kernel(unsigned int cpu, unsigned int human)
  217. {
  218. unsigned long freq = cpufreq_get_freq_kernel(cpu);
  219. printf(_(" current CPU frequency: "));
  220. if (!freq) {
  221. printf(_(" Unable to call to kernel\n"));
  222. return -EINVAL;
  223. }
  224. if (human) {
  225. print_speed(freq);
  226. } else
  227. printf("%lu", freq);
  228. printf(_(" (asserted by call to kernel)\n"));
  229. return 0;
  230. }
  231. /* --hwfreq / -w */
  232. static int get_freq_hardware(unsigned int cpu, unsigned int human)
  233. {
  234. unsigned long freq = cpufreq_get_freq_hardware(cpu);
  235. printf(_(" current CPU frequency: "));
  236. if (!freq) {
  237. printf("Unable to call hardware\n");
  238. return -EINVAL;
  239. }
  240. if (human) {
  241. print_speed(freq);
  242. } else
  243. printf("%lu", freq);
  244. printf(_(" (asserted by call to hardware)\n"));
  245. return 0;
  246. }
  247. /* --hwlimits / -l */
  248. static int get_hardware_limits(unsigned int cpu)
  249. {
  250. unsigned long min, max;
  251. printf(_(" hardware limits: "));
  252. if (cpufreq_get_hardware_limits(cpu, &min, &max)) {
  253. printf(_("Not Available\n"));
  254. return -EINVAL;
  255. }
  256. print_speed(min);
  257. printf(" - ");
  258. print_speed(max);
  259. printf("\n");
  260. return 0;
  261. }
  262. /* --driver / -d */
  263. static int get_driver(unsigned int cpu)
  264. {
  265. char *driver = cpufreq_get_driver(cpu);
  266. if (!driver) {
  267. printf(_(" no or unknown cpufreq driver is active on this CPU\n"));
  268. return -EINVAL;
  269. }
  270. printf(" driver: %s\n", driver);
  271. cpufreq_put_driver(driver);
  272. return 0;
  273. }
  274. /* --policy / -p */
  275. static int get_policy(unsigned int cpu)
  276. {
  277. struct cpufreq_policy *policy = cpufreq_get_policy(cpu);
  278. if (!policy) {
  279. printf(_(" Unable to determine current policy\n"));
  280. return -EINVAL;
  281. }
  282. printf(_(" current policy: frequency should be within "));
  283. print_speed(policy->min);
  284. printf(_(" and "));
  285. print_speed(policy->max);
  286. printf(".\n ");
  287. printf(_("The governor \"%s\" may decide which speed to use\n"
  288. " within this range.\n"),
  289. policy->governor);
  290. cpufreq_put_policy(policy);
  291. return 0;
  292. }
  293. /* --governors / -g */
  294. static int get_available_governors(unsigned int cpu)
  295. {
  296. struct cpufreq_available_governors *governors =
  297. cpufreq_get_available_governors(cpu);
  298. printf(_(" available cpufreq governors: "));
  299. if (!governors) {
  300. printf(_("Not Available\n"));
  301. return -EINVAL;
  302. }
  303. while (governors->next) {
  304. printf("%s ", governors->governor);
  305. governors = governors->next;
  306. }
  307. printf("%s\n", governors->governor);
  308. cpufreq_put_available_governors(governors);
  309. return 0;
  310. }
  311. /* --affected-cpus / -a */
  312. static int get_affected_cpus(unsigned int cpu)
  313. {
  314. struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu);
  315. printf(_(" CPUs which need to have their frequency coordinated by software: "));
  316. if (!cpus) {
  317. printf(_("Not Available\n"));
  318. return -EINVAL;
  319. }
  320. while (cpus->next) {
  321. printf("%d ", cpus->cpu);
  322. cpus = cpus->next;
  323. }
  324. printf("%d\n", cpus->cpu);
  325. cpufreq_put_affected_cpus(cpus);
  326. return 0;
  327. }
  328. /* --related-cpus / -r */
  329. static int get_related_cpus(unsigned int cpu)
  330. {
  331. struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu);
  332. printf(_(" CPUs which run at the same hardware frequency: "));
  333. if (!cpus) {
  334. printf(_("Not Available\n"));
  335. return -EINVAL;
  336. }
  337. while (cpus->next) {
  338. printf("%d ", cpus->cpu);
  339. cpus = cpus->next;
  340. }
  341. printf("%d\n", cpus->cpu);
  342. cpufreq_put_related_cpus(cpus);
  343. return 0;
  344. }
  345. /* --stats / -s */
  346. static int get_freq_stats(unsigned int cpu, unsigned int human)
  347. {
  348. unsigned long total_trans = cpufreq_get_transitions(cpu);
  349. unsigned long long total_time;
  350. struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time);
  351. while (stats) {
  352. if (human) {
  353. print_speed(stats->frequency);
  354. printf(":%.2f%%",
  355. (100.0 * stats->time_in_state) / total_time);
  356. } else
  357. printf("%lu:%llu",
  358. stats->frequency, stats->time_in_state);
  359. stats = stats->next;
  360. if (stats)
  361. printf(", ");
  362. }
  363. cpufreq_put_stats(stats);
  364. if (total_trans)
  365. printf(" (%lu)\n", total_trans);
  366. return 0;
  367. }
  368. /* --latency / -y */
  369. static int get_latency(unsigned int cpu, unsigned int human)
  370. {
  371. unsigned long latency = cpufreq_get_transition_latency(cpu);
  372. printf(_(" maximum transition latency: "));
  373. if (!latency || latency == UINT_MAX) {
  374. printf(_(" Cannot determine or is not supported.\n"));
  375. return -EINVAL;
  376. }
  377. if (human) {
  378. print_duration(latency);
  379. printf("\n");
  380. } else
  381. printf("%lu\n", latency);
  382. return 0;
  383. }
  384. static void debug_output_one(unsigned int cpu)
  385. {
  386. struct cpufreq_available_frequencies *freqs;
  387. get_driver(cpu);
  388. get_related_cpus(cpu);
  389. get_affected_cpus(cpu);
  390. get_latency(cpu, 1);
  391. get_hardware_limits(cpu);
  392. freqs = cpufreq_get_available_frequencies(cpu);
  393. if (freqs) {
  394. printf(_(" available frequency steps: "));
  395. while (freqs->next) {
  396. print_speed(freqs->frequency);
  397. printf(", ");
  398. freqs = freqs->next;
  399. }
  400. print_speed(freqs->frequency);
  401. printf("\n");
  402. cpufreq_put_available_frequencies(freqs);
  403. }
  404. get_available_governors(cpu);
  405. get_policy(cpu);
  406. if (get_freq_hardware(cpu, 1) < 0)
  407. get_freq_kernel(cpu, 1);
  408. get_boost_mode(cpu);
  409. }
  410. static struct option info_opts[] = {
  411. {"debug", no_argument, NULL, 'e'},
  412. {"boost", no_argument, NULL, 'b'},
  413. {"freq", no_argument, NULL, 'f'},
  414. {"hwfreq", no_argument, NULL, 'w'},
  415. {"hwlimits", no_argument, NULL, 'l'},
  416. {"driver", no_argument, NULL, 'd'},
  417. {"policy", no_argument, NULL, 'p'},
  418. {"governors", no_argument, NULL, 'g'},
  419. {"related-cpus", no_argument, NULL, 'r'},
  420. {"affected-cpus", no_argument, NULL, 'a'},
  421. {"stats", no_argument, NULL, 's'},
  422. {"latency", no_argument, NULL, 'y'},
  423. {"proc", no_argument, NULL, 'o'},
  424. {"human", no_argument, NULL, 'm'},
  425. {"no-rounding", no_argument, NULL, 'n'},
  426. { },
  427. };
  428. int cmd_freq_info(int argc, char **argv)
  429. {
  430. extern char *optarg;
  431. extern int optind, opterr, optopt;
  432. int ret = 0, cont = 1;
  433. unsigned int cpu = 0;
  434. unsigned int human = 0;
  435. int output_param = 0;
  436. do {
  437. ret = getopt_long(argc, argv, "oefwldpgrasmybn", info_opts,
  438. NULL);
  439. switch (ret) {
  440. case '?':
  441. output_param = '?';
  442. cont = 0;
  443. break;
  444. case -1:
  445. cont = 0;
  446. break;
  447. case 'b':
  448. case 'o':
  449. case 'a':
  450. case 'r':
  451. case 'g':
  452. case 'p':
  453. case 'd':
  454. case 'l':
  455. case 'w':
  456. case 'f':
  457. case 'e':
  458. case 's':
  459. case 'y':
  460. if (output_param) {
  461. output_param = -1;
  462. cont = 0;
  463. break;
  464. }
  465. output_param = ret;
  466. break;
  467. case 'm':
  468. if (human) {
  469. output_param = -1;
  470. cont = 0;
  471. break;
  472. }
  473. human = 1;
  474. break;
  475. case 'n':
  476. no_rounding = 1;
  477. break;
  478. default:
  479. fprintf(stderr, "invalid or unknown argument\n");
  480. return EXIT_FAILURE;
  481. }
  482. } while (cont);
  483. switch (output_param) {
  484. case 'o':
  485. if (!bitmask_isallclear(cpus_chosen)) {
  486. printf(_("The argument passed to this tool can't be "
  487. "combined with passing a --cpu argument\n"));
  488. return -EINVAL;
  489. }
  490. break;
  491. case 0:
  492. output_param = 'e';
  493. }
  494. ret = 0;
  495. /* Default is: show output of CPU 0 only */
  496. if (bitmask_isallclear(cpus_chosen))
  497. bitmask_setbit(cpus_chosen, 0);
  498. switch (output_param) {
  499. case -1:
  500. printf(_("You can't specify more than one --cpu parameter and/or\n"
  501. "more than one output-specific argument\n"));
  502. return -EINVAL;
  503. case '?':
  504. printf(_("invalid or unknown argument\n"));
  505. return -EINVAL;
  506. case 'o':
  507. proc_cpufreq_output();
  508. return EXIT_SUCCESS;
  509. }
  510. for (cpu = bitmask_first(cpus_chosen);
  511. cpu <= bitmask_last(cpus_chosen); cpu++) {
  512. if (!bitmask_isbitset(cpus_chosen, cpu))
  513. continue;
  514. printf(_("analyzing CPU %d:\n"), cpu);
  515. if (sysfs_is_cpu_online(cpu) != 1) {
  516. printf(_(" *is offline\n"));
  517. printf("\n");
  518. continue;
  519. }
  520. switch (output_param) {
  521. case 'b':
  522. get_boost_mode(cpu);
  523. break;
  524. case 'e':
  525. debug_output_one(cpu);
  526. break;
  527. case 'a':
  528. ret = get_affected_cpus(cpu);
  529. break;
  530. case 'r':
  531. ret = get_related_cpus(cpu);
  532. break;
  533. case 'g':
  534. ret = get_available_governors(cpu);
  535. break;
  536. case 'p':
  537. ret = get_policy(cpu);
  538. break;
  539. case 'd':
  540. ret = get_driver(cpu);
  541. break;
  542. case 'l':
  543. ret = get_hardware_limits(cpu);
  544. break;
  545. case 'w':
  546. ret = get_freq_hardware(cpu, human);
  547. break;
  548. case 'f':
  549. ret = get_freq_kernel(cpu, human);
  550. break;
  551. case 's':
  552. ret = get_freq_stats(cpu, human);
  553. break;
  554. case 'y':
  555. ret = get_latency(cpu, human);
  556. break;
  557. }
  558. if (ret)
  559. return ret;
  560. printf("\n");
  561. }
  562. return ret;
  563. }