menu.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /*
  2. * menu.c - the menu idle governor
  3. *
  4. * Copyright (C) 2006-2007 Adam Belay <abelay@novell.com>
  5. *
  6. * This code is licenced under the GPL.
  7. */
  8. #include <linux/kernel.h>
  9. #include <linux/cpuidle.h>
  10. #include <linux/latency.h>
  11. #include <linux/time.h>
  12. #include <linux/ktime.h>
  13. #include <linux/hrtimer.h>
  14. #include <linux/tick.h>
  15. #define BREAK_FUZZ 4 /* 4 us */
  16. struct menu_device {
  17. int last_state_idx;
  18. unsigned int expected_us;
  19. unsigned int predicted_us;
  20. unsigned int last_measured_us;
  21. unsigned int elapsed_us;
  22. };
  23. static DEFINE_PER_CPU(struct menu_device, menu_devices);
  24. /**
  25. * menu_select - selects the next idle state to enter
  26. * @dev: the CPU
  27. */
  28. static int menu_select(struct cpuidle_device *dev)
  29. {
  30. struct menu_device *data = &__get_cpu_var(menu_devices);
  31. int i;
  32. /* determine the expected residency time */
  33. data->expected_us =
  34. (u32) ktime_to_ns(tick_nohz_get_sleep_length()) / 1000;
  35. /* find the deepest idle state that satisfies our constraints */
  36. for (i = 1; i < dev->state_count; i++) {
  37. struct cpuidle_state *s = &dev->states[i];
  38. if (s->target_residency > data->expected_us)
  39. break;
  40. if (s->target_residency > data->predicted_us)
  41. break;
  42. if (s->exit_latency > system_latency_constraint())
  43. break;
  44. }
  45. data->last_state_idx = i - 1;
  46. return i - 1;
  47. }
  48. /**
  49. * menu_reflect - attempts to guess what happened after entry
  50. * @dev: the CPU
  51. *
  52. * NOTE: it's important to be fast here because this operation will add to
  53. * the overall exit latency.
  54. */
  55. static void menu_reflect(struct cpuidle_device *dev)
  56. {
  57. struct menu_device *data = &__get_cpu_var(menu_devices);
  58. int last_idx = data->last_state_idx;
  59. unsigned int measured_us =
  60. cpuidle_get_last_residency(dev) + data->elapsed_us;
  61. struct cpuidle_state *target = &dev->states[last_idx];
  62. /*
  63. * Ugh, this idle state doesn't support residency measurements, so we
  64. * are basically lost in the dark. As a compromise, assume we slept
  65. * for one full standard timer tick. However, be aware that this
  66. * could potentially result in a suboptimal state transition.
  67. */
  68. if (!(target->flags & CPUIDLE_FLAG_TIME_VALID))
  69. measured_us = USEC_PER_SEC / HZ;
  70. /* Predict time remaining until next break event */
  71. if (measured_us + BREAK_FUZZ < data->expected_us - target->exit_latency) {
  72. data->predicted_us = max(measured_us, data->last_measured_us);
  73. data->last_measured_us = measured_us;
  74. data->elapsed_us = 0;
  75. } else {
  76. if (data->elapsed_us < data->elapsed_us + measured_us)
  77. data->elapsed_us = measured_us;
  78. else
  79. data->elapsed_us = -1;
  80. data->predicted_us = max(measured_us, data->last_measured_us);
  81. }
  82. }
  83. /**
  84. * menu_enable_device - scans a CPU's states and does setup
  85. * @dev: the CPU
  86. */
  87. static int menu_enable_device(struct cpuidle_device *dev)
  88. {
  89. struct menu_device *data = &per_cpu(menu_devices, dev->cpu);
  90. memset(data, 0, sizeof(struct menu_device));
  91. return 0;
  92. }
  93. static struct cpuidle_governor menu_governor = {
  94. .name = "menu",
  95. .rating = 20,
  96. .enable = menu_enable_device,
  97. .select = menu_select,
  98. .reflect = menu_reflect,
  99. .owner = THIS_MODULE,
  100. };
  101. /**
  102. * init_menu - initializes the governor
  103. */
  104. static int __init init_menu(void)
  105. {
  106. return cpuidle_register_governor(&menu_governor);
  107. }
  108. /**
  109. * exit_menu - exits the governor
  110. */
  111. static void __exit exit_menu(void)
  112. {
  113. cpuidle_unregister_governor(&menu_governor);
  114. }
  115. MODULE_LICENSE("GPL");
  116. module_init(init_menu);
  117. module_exit(exit_menu);