aperfmperf.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /*
  2. * x86 APERF/MPERF KHz calculation for
  3. * /sys/.../cpufreq/scaling_cur_freq
  4. *
  5. * Copyright (C) 2017 Intel Corp.
  6. * Author: Len Brown <len.brown@intel.com>
  7. *
  8. * This file is licensed under GPLv2.
  9. */
  10. #include <linux/delay.h>
  11. #include <linux/ktime.h>
  12. #include <linux/math64.h>
  13. #include <linux/percpu.h>
  14. #include <linux/smp.h>
  15. #include "cpu.h"
  16. struct aperfmperf_sample {
  17. unsigned int khz;
  18. ktime_t time;
  19. u64 aperf;
  20. u64 mperf;
  21. };
  22. static DEFINE_PER_CPU(struct aperfmperf_sample, samples);
  23. #define APERFMPERF_CACHE_THRESHOLD_MS 10
  24. #define APERFMPERF_REFRESH_DELAY_MS 10
  25. #define APERFMPERF_STALE_THRESHOLD_MS 1000
  26. /*
  27. * aperfmperf_snapshot_khz()
  28. * On the current CPU, snapshot APERF, MPERF, and jiffies
  29. * unless we already did it within 10ms
  30. * calculate kHz, save snapshot
  31. */
  32. static void aperfmperf_snapshot_khz(void *dummy)
  33. {
  34. u64 aperf, aperf_delta;
  35. u64 mperf, mperf_delta;
  36. struct aperfmperf_sample *s = this_cpu_ptr(&samples);
  37. unsigned long flags;
  38. local_irq_save(flags);
  39. rdmsrl(MSR_IA32_APERF, aperf);
  40. rdmsrl(MSR_IA32_MPERF, mperf);
  41. local_irq_restore(flags);
  42. aperf_delta = aperf - s->aperf;
  43. mperf_delta = mperf - s->mperf;
  44. /*
  45. * There is no architectural guarantee that MPERF
  46. * increments faster than we can read it.
  47. */
  48. if (mperf_delta == 0)
  49. return;
  50. s->time = ktime_get();
  51. s->aperf = aperf;
  52. s->mperf = mperf;
  53. s->khz = div64_u64((cpu_khz * aperf_delta), mperf_delta);
  54. }
  55. static bool aperfmperf_snapshot_cpu(int cpu, ktime_t now, bool wait)
  56. {
  57. s64 time_delta = ktime_ms_delta(now, per_cpu(samples.time, cpu));
  58. /* Don't bother re-computing within the cache threshold time. */
  59. if (time_delta < APERFMPERF_CACHE_THRESHOLD_MS)
  60. return true;
  61. smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, wait);
  62. /* Return false if the previous iteration was too long ago. */
  63. return time_delta <= APERFMPERF_STALE_THRESHOLD_MS;
  64. }
  65. unsigned int aperfmperf_get_khz(int cpu)
  66. {
  67. if (!cpu_khz)
  68. return 0;
  69. if (!static_cpu_has(X86_FEATURE_APERFMPERF))
  70. return 0;
  71. aperfmperf_snapshot_cpu(cpu, ktime_get(), true);
  72. return per_cpu(samples.khz, cpu);
  73. }
  74. void arch_freq_prepare_all(void)
  75. {
  76. ktime_t now = ktime_get();
  77. bool wait = false;
  78. int cpu;
  79. if (!cpu_khz)
  80. return;
  81. if (!static_cpu_has(X86_FEATURE_APERFMPERF))
  82. return;
  83. for_each_online_cpu(cpu)
  84. if (!aperfmperf_snapshot_cpu(cpu, now, false))
  85. wait = true;
  86. if (wait)
  87. msleep(APERFMPERF_REFRESH_DELAY_MS);
  88. }
  89. unsigned int arch_freq_get_on_cpu(int cpu)
  90. {
  91. if (!cpu_khz)
  92. return 0;
  93. if (!static_cpu_has(X86_FEATURE_APERFMPERF))
  94. return 0;
  95. if (aperfmperf_snapshot_cpu(cpu, ktime_get(), true))
  96. return per_cpu(samples.khz, cpu);
  97. msleep(APERFMPERF_REFRESH_DELAY_MS);
  98. smp_call_function_single(cpu, aperfmperf_snapshot_khz, NULL, 1);
  99. return per_cpu(samples.khz, cpu);
  100. }