Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Linux kernel compatability enhancements (through 3.19)
[palacios.git] / linux_module / iface-pwrstat.c
1 /*
2  *
3  * Intel RAPL (Sandy Bridge and above) Accessor
4  * (c) Kyle C. Hale, Chang Bae 2013
5  *
6  *
7  */
8 #include <asm/msr.h>
9 #include <asm/msr-index.h>
10 #include <linux/math64.h>
11
12 #include <palacios/vmm_types.h>
13 #include <palacios/vmm_util.h>
14
15 #include <interfaces/vmm_pwrstat.h>
16
17 #include "vm.h"
18 #include "palacios.h"
19 #include "util-queue.h"
20 #include "linux-exts.h"
21 #include "iface-pwrstat.h"
22
23
24 enum rapl_domain_id {
25         RAPL_DOMAIN_PKG,
26         RAPL_DOMAIN_PP0,
27         RAPL_DOMAIN_PP1,
28         RAPL_DOMAIN_DRAM,
29         RAPL_DOMAIN_MAX
30 };
31
32
33 struct rapl_domain_msr {
34         int     limit;
35         int     status;
36 };
37
38
39 struct rapl_domain {
40         enum rapl_domain_id domain_id;
41         struct rapl_domain_msr msrs;
42         int valid;
43 };
44
45
46 static struct rapl_domain rapl_domains[] = {
47         [RAPL_DOMAIN_PKG] = {
48                 .domain_id = RAPL_DOMAIN_PKG,
49                 .msrs   = {
50                         .limit  = MSR_PKG_POWER_LIMIT,
51                         .status = MSR_PKG_ENERGY_STATUS,
52                 },
53                 .valid  = 1,
54         },
55         [RAPL_DOMAIN_PP0] = {
56                 .domain_id = RAPL_DOMAIN_PP0,
57                 .msrs   = {
58                         .limit  = MSR_PP0_POWER_LIMIT,
59                         .status = MSR_PP0_ENERGY_STATUS,
60                 },
61                 .valid  = 1,
62         },
63         [RAPL_DOMAIN_PP1] = {
64                 .domain_id = RAPL_DOMAIN_PP1,
65                 .msrs   = {
66                         .limit  = MSR_PP1_POWER_LIMIT,
67                         .status = MSR_PP1_ENERGY_STATUS,
68                 },
69         },
70         [RAPL_DOMAIN_DRAM] = {
71                 .domain_id = RAPL_DOMAIN_DRAM,
72                 .msrs   = {
73                         .limit  = MSR_DRAM_POWER_LIMIT,
74                         .status = MSR_DRAM_ENERGY_STATUS,
75                 },
76         },
77 };
78
79 static unsigned int power_unit_divisor;
80 static unsigned int energy_unit_divisor;
81 static unsigned int time_unit_divisor;
82
83 enum unit_type {
84         POWER_UNIT,
85         ENERGY_UNIT,
86         TIME_UNIT
87 };
88
89 static inline void cpuid_string(u32 id, u32 dest[4]) {
90         asm volatile("cpuid"
91                    :"=a"(*dest),"=b"(*(dest+1)),"=c"(*(dest+2)),"=d"(*(dest+3))
92                    :"a"(id));
93 }
94
95
96 static int rapl_check_unit (void)
97 {
98         u64 output;
99         u32 value;
100
101         rdmsrl(MSR_RAPL_POWER_UNIT, output);
102
103         /* energy unit: 1/enery_unit_divisor Joules */
104         value = (output & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
105         energy_unit_divisor = 1 << value;
106
107         /* power unit: 1/power_unit_divisor Watts */
108         value = (output & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
109         power_unit_divisor = 1 << value;
110
111         /* time unit: 1/time_unit_divisor Seconds */
112         value = (output & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
113         time_unit_divisor = 1 << value;
114
115         return 0;
116 }
117
118
119 static u64 rapl_unit_xlate(enum unit_type type, u64 value, int action)
120 {
121         u64 divisor;
122
123         switch (type) {
124         case POWER_UNIT:
125                 divisor = power_unit_divisor;
126                 break;
127         case ENERGY_UNIT:
128                 divisor = energy_unit_divisor;
129                 break;
130         case TIME_UNIT:
131                 divisor = time_unit_divisor;
132                 break;
133         default:
134                 return 0;
135         };
136
137         if (action)
138                 return value * divisor; /* value is from users */
139         else
140                 return div64_u64(value, divisor); /* value is from MSR */
141 }
142
143
144 static int rapl_read_energy(struct rapl_domain * domain)
145 {
146         u64 value;
147         u32 msr = domain->msrs.status;
148
149         rdmsrl(msr, value);
150         return rapl_unit_xlate(ENERGY_UNIT, value, 0);
151 }
152
153
154 static int rapl_ctr_valid (v3_pwrstat_ctr_t ctr) 
155 {
156         switch (ctr) {
157                 case V3_PWRSTAT_PKG_ENERGY:
158                         return rapl_domains[RAPL_DOMAIN_PKG].valid;
159                 case V3_PWRSTAT_CORE_ENERGY:
160                         return rapl_domains[RAPL_DOMAIN_PP0].valid;
161                 case V3_PWRSTAT_EXT_ENERGY:
162                         return rapl_domains[RAPL_DOMAIN_PP1].valid;
163                 case V3_PWRSTAT_DRAM_ENERGY:
164                         return rapl_domains[RAPL_DOMAIN_DRAM].valid;
165                 default:
166                         return 0;
167         }
168         
169         return 0;
170 }
171
172
173 static uint64_t rapl_get_value (v3_pwrstat_ctr_t ctr)
174 {
175         switch (ctr) {
176                 case V3_PWRSTAT_PKG_ENERGY:
177                         return rapl_read_energy(&rapl_domains[RAPL_DOMAIN_PKG]);
178                 case V3_PWRSTAT_CORE_ENERGY:
179                         return rapl_read_energy(&rapl_domains[RAPL_DOMAIN_PP0]);
180                 case V3_PWRSTAT_EXT_ENERGY:
181                         return rapl_read_energy(&rapl_domains[RAPL_DOMAIN_PP1]);
182                 case V3_PWRSTAT_DRAM_ENERGY:
183                         return rapl_read_energy(&rapl_domains[RAPL_DOMAIN_DRAM]);
184                 default:
185                         ERROR("Invalid Powerstat Counter\n");
186                         return -1;
187         }
188         
189         return -1;
190 }
191
192
193 static int get_cpu_vendor (char name[13])
194 {
195         u32 dest[4];
196         u32 maxid;
197
198         cpuid_string(0,dest);
199         maxid=dest[0];
200         ((u32*)name)[0]=dest[1];
201         ((u32*)name)[1]=dest[3];
202         ((u32*)name)[2]=dest[2];
203         name[12]=0;
204
205         return maxid;
206 }
207
208
209 static int get_cpu_model (void) 
210 {
211         u32 dest[4] = {0, 0, 0, 0};
212         u32 ex_model, model;
213         cpuid_string(1, dest);
214         ex_model = (dest[0] & 0xF0000U) >> 16;
215         model = (dest[0] & 0xF0U) >> 4;
216     return (model + (ex_model << 4));
217 }
218
219
220 static int supports_rapl (void) 
221 {
222         unsigned int model = get_cpu_model();
223         switch (model) {
224                 case SANDY_BRIDGE_E3_MODEL_NO:
225                         return 1;
226                 case SANDY_BRIDGE_E5_MODEL_NO:
227                         return 1;
228                 case IVY_BRIDGE_MODEL_NO:
229                         return 1;
230                 case HASWELL_MODEL_NO:
231                         return 1;
232                 default:
233                         break;
234         }
235
236         return 0;
237 }
238
239
240 static int is_intel(void)
241 {
242         char name[13];
243         get_cpu_vendor(name);
244         return !strcmp(name,"GenuineIntel");
245 }
246
247
248 static int rapl_init (void) 
249 {
250         if (supports_rapl()) {
251                 INFO("Intel RAPL featureset detected\n");
252         } else {
253                 ERROR("This machine does not support Intel RAPL functionality\n");
254                 return -1;
255         }
256
257         if (get_cpu_model() == SANDY_BRIDGE_E3_MODEL_NO) {
258                 INFO("Sandy Bridge E3, supports PP1 (no DRAM)\n");
259                 rapl_domains[RAPL_DOMAIN_PP1].valid = 1;
260         } else if (get_cpu_model() == SANDY_BRIDGE_E5_MODEL_NO) {
261                 INFO("Sandy Bridge E5, supports DRAM domain\n");
262                 rapl_domains[RAPL_DOMAIN_DRAM].valid = 1;
263         }
264
265         if (rapl_check_unit()) {
266                 return -1;
267         }
268
269         return 0;
270 }
271
272
273 static int rapl_deinit (void) 
274 {
275         INFO("Intel RAPL deinit\n");
276         return 0;
277 }
278
279
280 static struct v3_pwrstat_iface intel_rapl_pwrstat = {
281         .init      = rapl_init,
282         .deinit    = rapl_deinit,
283         .ctr_valid = rapl_ctr_valid,
284         .get_value = rapl_get_value,
285 };
286
287
288 static int pwrstat_init (void)
289 {
290         if (is_intel()) {
291             if  (supports_rapl()) { 
292                 INFO("Palacios Power stats using Intel RAPL\n");
293                 V3_Init_Pwrstat(&intel_rapl_pwrstat);
294             } else {
295                 INFO("Intel machine, but no RAPL functionality, so no power statistics available\n");
296                 return -1;
297             }
298         } else {
299                 ERROR("Not an Intel Machine, no power statistics available\n");
300                 return -1;
301         }
302         
303         return 0;
304 }
305
306
307 static int pwrstat_deinit(void)
308 {
309     // nothing to do
310     return 0;
311 }
312
313
314 static struct linux_ext pwrstat_ext = {
315   .name = "POWERSTAT",
316   .init = pwrstat_init,
317   .deinit = pwrstat_deinit,
318   .guest_init = NULL,
319   .guest_deinit = NULL
320 };
321
322 register_extension(&pwrstat_ext);