cpuidle_sysfs.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /*
  2. * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc
  3. *
  4. * Licensed under the terms of the GNU GPL License version 2.
  5. *
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <stdint.h>
  10. #include <string.h>
  11. #include <limits.h>
  12. #include "helpers/sysfs.h"
  13. #include "helpers/helpers.h"
  14. #include "idle_monitor/cpupower-monitor.h"
  15. #define CPUIDLE_STATES_MAX 10
  16. static cstate_t cpuidle_cstates[CPUIDLE_STATES_MAX];
  17. struct cpuidle_monitor cpuidle_sysfs_monitor;
  18. static unsigned long long **previous_count;
  19. static unsigned long long **current_count;
  20. struct timespec start_time;
  21. static unsigned long long timediff;
  22. static int cpuidle_get_count_percent(unsigned int id, double *percent,
  23. unsigned int cpu)
  24. {
  25. unsigned long long statediff = current_count[cpu][id]
  26. - previous_count[cpu][id];
  27. dprint("%s: - diff: %llu - percent: %f (%u)\n",
  28. cpuidle_cstates[id].name, timediff, *percent, cpu);
  29. if (timediff == 0)
  30. *percent = 0.0;
  31. else
  32. *percent = ((100.0 * statediff) / timediff);
  33. dprint("%s: - timediff: %llu - statediff: %llu - percent: %f (%u)\n",
  34. cpuidle_cstates[id].name, timediff, statediff, *percent, cpu);
  35. return 0;
  36. }
  37. static int cpuidle_start(void)
  38. {
  39. int cpu, state;
  40. clock_gettime(CLOCK_REALTIME, &start_time);
  41. for (cpu = 0; cpu < cpu_count; cpu++) {
  42. for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num;
  43. state++) {
  44. previous_count[cpu][state] =
  45. sysfs_get_idlestate_time(cpu, state);
  46. dprint("CPU %d - State: %d - Val: %llu\n",
  47. cpu, state, previous_count[cpu][state]);
  48. }
  49. };
  50. return 0;
  51. }
  52. static int cpuidle_stop(void)
  53. {
  54. int cpu, state;
  55. struct timespec end_time;
  56. clock_gettime(CLOCK_REALTIME, &end_time);
  57. timediff = timespec_diff_us(start_time, end_time);
  58. for (cpu = 0; cpu < cpu_count; cpu++) {
  59. for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num;
  60. state++) {
  61. current_count[cpu][state] =
  62. sysfs_get_idlestate_time(cpu, state);
  63. dprint("CPU %d - State: %d - Val: %llu\n",
  64. cpu, state, previous_count[cpu][state]);
  65. }
  66. };
  67. return 0;
  68. }
  69. void fix_up_intel_idle_driver_name(char *tmp, int num)
  70. {
  71. /* fix up cpuidle name for intel idle driver */
  72. if (!strncmp(tmp, "NHM-", 4)) {
  73. switch (num) {
  74. case 1:
  75. strcpy(tmp, "C1");
  76. break;
  77. case 2:
  78. strcpy(tmp, "C3");
  79. break;
  80. case 3:
  81. strcpy(tmp, "C6");
  82. break;
  83. }
  84. } else if (!strncmp(tmp, "SNB-", 4)) {
  85. switch (num) {
  86. case 1:
  87. strcpy(tmp, "C1");
  88. break;
  89. case 2:
  90. strcpy(tmp, "C3");
  91. break;
  92. case 3:
  93. strcpy(tmp, "C6");
  94. break;
  95. case 4:
  96. strcpy(tmp, "C7");
  97. break;
  98. }
  99. } else if (!strncmp(tmp, "ATM-", 4)) {
  100. switch (num) {
  101. case 1:
  102. strcpy(tmp, "C1");
  103. break;
  104. case 2:
  105. strcpy(tmp, "C2");
  106. break;
  107. case 3:
  108. strcpy(tmp, "C4");
  109. break;
  110. case 4:
  111. strcpy(tmp, "C6");
  112. break;
  113. }
  114. }
  115. }
  116. static struct cpuidle_monitor *cpuidle_register(void)
  117. {
  118. int num;
  119. char *tmp;
  120. /* Assume idle state count is the same for all CPUs */
  121. cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0);
  122. if (cpuidle_sysfs_monitor.hw_states_num <= 0)
  123. return NULL;
  124. for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) {
  125. tmp = sysfs_get_idlestate_name(0, num);
  126. if (tmp == NULL)
  127. continue;
  128. fix_up_intel_idle_driver_name(tmp, num);
  129. strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1);
  130. free(tmp);
  131. tmp = sysfs_get_idlestate_desc(0, num);
  132. if (tmp == NULL)
  133. continue;
  134. strncpy(cpuidle_cstates[num].desc, tmp, CSTATE_DESC_LEN - 1);
  135. free(tmp);
  136. cpuidle_cstates[num].range = RANGE_THREAD;
  137. cpuidle_cstates[num].id = num;
  138. cpuidle_cstates[num].get_count_percent =
  139. cpuidle_get_count_percent;
  140. };
  141. /* Free this at program termination */
  142. previous_count = malloc(sizeof(long long *) * cpu_count);
  143. current_count = malloc(sizeof(long long *) * cpu_count);
  144. for (num = 0; num < cpu_count; num++) {
  145. previous_count[num] = malloc(sizeof(long long) *
  146. cpuidle_sysfs_monitor.hw_states_num);
  147. current_count[num] = malloc(sizeof(long long) *
  148. cpuidle_sysfs_monitor.hw_states_num);
  149. }
  150. cpuidle_sysfs_monitor.name_len = strlen(cpuidle_sysfs_monitor.name);
  151. return &cpuidle_sysfs_monitor;
  152. }
  153. void cpuidle_unregister(void)
  154. {
  155. int num;
  156. for (num = 0; num < cpu_count; num++) {
  157. free(previous_count[num]);
  158. free(current_count[num]);
  159. }
  160. free(previous_count);
  161. free(current_count);
  162. }
  163. struct cpuidle_monitor cpuidle_sysfs_monitor = {
  164. .name = "Idle_Stats",
  165. .hw_states = cpuidle_cstates,
  166. .start = cpuidle_start,
  167. .stop = cpuidle_stop,
  168. .do_register = cpuidle_register,
  169. .unregister = cpuidle_unregister,
  170. .needs_root = 0,
  171. .overflow_s = UINT_MAX,
  172. };