root/arch/x86/kernel/cpu/aperfmperf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. aperfmperf_snapshot_khz
  2. aperfmperf_snapshot_cpu
  3. aperfmperf_get_khz
  4. arch_freq_prepare_all
  5. arch_freq_get_on_cpu

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

/* [<][>][^][v][top][bottom][index][help] */