root/tools/power/cpupower/utils/idle_monitor/snb_idle.c

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

DEFINITIONS

This source file includes following definitions.
  1. snb_get_count
  2. snb_get_count_percent
  3. snb_start
  4. snb_stop
  5. snb_register
  6. snb_unregister

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
   4  *
   5  *  Based on Len Brown's <lenb@kernel.org> turbostat tool.
   6  */
   7 
   8 #if defined(__i386__) || defined(__x86_64__)
   9 
  10 #include <stdio.h>
  11 #include <stdint.h>
  12 #include <stdlib.h>
  13 #include <string.h>
  14 
  15 #include "helpers/helpers.h"
  16 #include "idle_monitor/cpupower-monitor.h"
  17 
  18 #define MSR_PKG_C2_RESIDENCY    0x60D
  19 #define MSR_PKG_C7_RESIDENCY    0x3FA
  20 #define MSR_CORE_C7_RESIDENCY   0x3FE
  21 
  22 #define MSR_TSC 0x10
  23 
  24 enum intel_snb_id { C7 = 0, PC2, PC7, SNB_CSTATE_COUNT, TSC = 0xFFFF };
  25 
  26 static int snb_get_count_percent(unsigned int self_id, double *percent,
  27                                  unsigned int cpu);
  28 
  29 static cstate_t snb_cstates[SNB_CSTATE_COUNT] = {
  30         {
  31                 .name                   = "C7",
  32                 .desc                   = N_("Processor Core C7"),
  33                 .id                     = C7,
  34                 .range                  = RANGE_CORE,
  35                 .get_count_percent      = snb_get_count_percent,
  36         },
  37         {
  38                 .name                   = "PC2",
  39                 .desc                   = N_("Processor Package C2"),
  40                 .id                     = PC2,
  41                 .range                  = RANGE_PACKAGE,
  42                 .get_count_percent      = snb_get_count_percent,
  43         },
  44         {
  45                 .name                   = "PC7",
  46                 .desc                   = N_("Processor Package C7"),
  47                 .id                     = PC7,
  48                 .range                  = RANGE_PACKAGE,
  49                 .get_count_percent      = snb_get_count_percent,
  50         },
  51 };
  52 
  53 static unsigned long long tsc_at_measure_start;
  54 static unsigned long long tsc_at_measure_end;
  55 static unsigned long long *previous_count[SNB_CSTATE_COUNT];
  56 static unsigned long long *current_count[SNB_CSTATE_COUNT];
  57 /* valid flag for all CPUs. If a MSR read failed it will be zero */
  58 static int *is_valid;
  59 
  60 static int snb_get_count(enum intel_snb_id id, unsigned long long *val,
  61                         unsigned int cpu)
  62 {
  63         int msr;
  64 
  65         switch (id) {
  66         case C7:
  67                 msr = MSR_CORE_C7_RESIDENCY;
  68                 break;
  69         case PC2:
  70                 msr = MSR_PKG_C2_RESIDENCY;
  71                 break;
  72         case PC7:
  73                 msr = MSR_PKG_C7_RESIDENCY;
  74                 break;
  75         case TSC:
  76                 msr = MSR_TSC;
  77                 break;
  78         default:
  79                 return -1;
  80         };
  81         if (read_msr(cpu, msr, val))
  82                 return -1;
  83         return 0;
  84 }
  85 
  86 static int snb_get_count_percent(unsigned int id, double *percent,
  87                                  unsigned int cpu)
  88 {
  89         *percent = 0.0;
  90 
  91         if (!is_valid[cpu])
  92                 return -1;
  93 
  94         *percent = (100.0 *
  95                 (current_count[id][cpu] - previous_count[id][cpu])) /
  96                 (tsc_at_measure_end - tsc_at_measure_start);
  97 
  98         dprint("%s: previous: %llu - current: %llu - (%u)\n",
  99                 snb_cstates[id].name, previous_count[id][cpu],
 100                 current_count[id][cpu], cpu);
 101 
 102         dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n",
 103                snb_cstates[id].name,
 104                (unsigned long long) tsc_at_measure_end - tsc_at_measure_start,
 105                current_count[id][cpu] - previous_count[id][cpu],
 106                *percent, cpu);
 107 
 108         return 0;
 109 }
 110 
 111 static int snb_start(void)
 112 {
 113         int num, cpu;
 114         unsigned long long val;
 115 
 116         for (num = 0; num < SNB_CSTATE_COUNT; num++) {
 117                 for (cpu = 0; cpu < cpu_count; cpu++) {
 118                         snb_get_count(num, &val, cpu);
 119                         previous_count[num][cpu] = val;
 120                 }
 121         }
 122         snb_get_count(TSC, &tsc_at_measure_start, base_cpu);
 123         return 0;
 124 }
 125 
 126 static int snb_stop(void)
 127 {
 128         unsigned long long val;
 129         int num, cpu;
 130 
 131         snb_get_count(TSC, &tsc_at_measure_end, base_cpu);
 132 
 133         for (num = 0; num < SNB_CSTATE_COUNT; num++) {
 134                 for (cpu = 0; cpu < cpu_count; cpu++) {
 135                         is_valid[cpu] = !snb_get_count(num, &val, cpu);
 136                         current_count[num][cpu] = val;
 137                 }
 138         }
 139         return 0;
 140 }
 141 
 142 struct cpuidle_monitor intel_snb_monitor;
 143 
 144 static struct cpuidle_monitor *snb_register(void)
 145 {
 146         int num;
 147 
 148         if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL
 149             || cpupower_cpu_info.family != 6)
 150                 return NULL;
 151 
 152         switch (cpupower_cpu_info.model) {
 153         case 0x2A: /* SNB */
 154         case 0x2D: /* SNB Xeon */
 155         case 0x3A: /* IVB */
 156         case 0x3E: /* IVB Xeon */
 157         case 0x3C: /* HSW */
 158         case 0x3F: /* HSW */
 159         case 0x45: /* HSW */
 160         case 0x46: /* HSW */
 161                 break;
 162         default:
 163                 return NULL;
 164         }
 165 
 166         is_valid = calloc(cpu_count, sizeof(int));
 167         for (num = 0; num < SNB_CSTATE_COUNT; num++) {
 168                 previous_count[num] = calloc(cpu_count,
 169                                         sizeof(unsigned long long));
 170                 current_count[num]  = calloc(cpu_count,
 171                                         sizeof(unsigned long long));
 172         }
 173         intel_snb_monitor.name_len = strlen(intel_snb_monitor.name);
 174         return &intel_snb_monitor;
 175 }
 176 
 177 void snb_unregister(void)
 178 {
 179         int num;
 180         free(is_valid);
 181         for (num = 0; num < SNB_CSTATE_COUNT; num++) {
 182                 free(previous_count[num]);
 183                 free(current_count[num]);
 184         }
 185 }
 186 
 187 struct cpuidle_monitor intel_snb_monitor = {
 188         .name                   = "SandyBridge",
 189         .hw_states              = snb_cstates,
 190         .hw_states_num          = SNB_CSTATE_COUNT,
 191         .start                  = snb_start,
 192         .stop                   = snb_stop,
 193         .do_register            = snb_register,
 194         .unregister             = snb_unregister,
 195         .needs_root             = 1,
 196         .overflow_s             = 922000000 /* 922337203 seconds TSC overflow
 197                                                at 20GHz */
 198 };
 199 #endif /* defined(__i386__) || defined(__x86_64__) */

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