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.


990fb2942a5430313876e3f2ec8a745741f460a1
[palacios.git] / linux_module / iface-pmu.c
1 /*
2  * PMU
3  * (c) Chang S. Bae, 2013
4  */
5
6 #include <linux/cdev.h>
7 #include <linux/errno.h>
8 #include <asm/msr.h>
9 #include <asm/msr-index.h>
10
11 #include <palacios/vmm_types.h>
12 #include <palacios/vmm_util.h>
13 #include <interfaces/vmm_pmu.h>
14
15 #include "vm.h"
16 #include "palacios.h"
17 #include "iface-pmu-intel.h"
18 #include "iface-pmu-amd.h"
19 #include "util-queue.h"
20 #include "linux-exts.h"
21
22
23 // Number of inits/deinits we have seen (inc on init, dec on deinit)
24 // This is per CPU - init/deinit mean init/deinit PMU
25 // tracking ON THE CURRENT CORE
26 static DEFINE_PER_CPU(u32, pmu_refcount) = 0;
27
28
29 /*
30  * some macros may be commonly used
31  */
32 #define MSR_READ(msrs, c) do {rdmsrl((c), (msrs).q);} while (0)
33 #define MSR_WRITE(msrs, c) do {wrmsrl((c), (msrs).q);} while (0)
34 #define SET_BIT(val, i) ((val) |= (1 << i))
35 #define CLEAR_BIT(val, u, i) ((val) &= ~((u&1) << i))
36 #define SET_BYTE(val, u, i) ((val) |= ((u&255) << i))
37 #define CHECK_BIT(val, i) ((val) & (1U << i))
38
39
40 static inline void cpuid_string(u32 id, u32 dest[4]) {
41   asm volatile("cpuid"
42                :"=a"(*dest),"=b"(*(dest+1)),"=c"(*(dest+2)),"=d"(*(dest+3))
43                :"a"(id));
44 }
45
46
47 static int get_cpu_vendor(char name[13])
48 {
49   u32 dest[4];
50   u32 maxid;
51
52   cpuid_string(0,dest);
53   maxid=dest[0];
54   ((u32*)name)[0]=dest[1];
55   ((u32*)name)[1]=dest[3];
56   ((u32*)name)[2]=dest[2];
57   name[12]=0;
58    
59   return maxid;
60 }
61
62 static int is_intel(void)
63 {
64   char name[13];
65   get_cpu_vendor(name);
66   return !strcmp(name,"GenuineIntel");
67 }
68
69 static int is_amd(void)
70 {
71   char name[13];
72   get_cpu_vendor(name);
73   return !strcmp(name,"AuthenticAMD");
74 }
75
76
77
78 /*
79  * AMD and Intel implementations are distinguished by prefix: INTEL or AMD
80  */
81
82 /*
83  * name: *_get_slot
84  * description: check available slots in pmu
85  * return: -1 if none, else returns index: 0 ... 3
86  */
87
88 static int intel_get_slot(void) {
89
90   int i, slot;
91   struct msr control;
92
93   slot = -1;
94   control.q = 0x0;
95
96   for (i=0; i<INTEL_NUM_PMU_CONTROLS; i++) {
97     INTEL_CTRL_READ(control, i);
98     if(control.q & (0x1<<INTEL_EN_BIT)) {
99       continue;
100     } else {
101       slot = i;
102       break;
103     }
104   }
105
106   return slot;
107 }
108
109 static int amd_get_slot(void) {
110   int i, slot;
111   struct msr control;
112
113   slot = -1;
114   control.q = 0x0;
115
116   for (i=0; i<AMD_NUM_PMU_CONTROLS; i++) {
117     AMD_CTRL_READ(control, i);
118     if(control.q & (0x1<<AMD_EN_BIT)) {
119       continue;
120     } else {
121       slot = i;
122       break;
123     }
124   }
125
126   return slot;
127   return -1;
128 }
129
130 /*
131  * name: *_find_idx
132  * description: find index of pmu register that is available
133  */
134 static int intel_find_idx(uint8_t event, uint8_t mask) {
135   int i;
136
137   struct msr control;
138
139   control.q = 0x0;
140
141   for (i=0; i<INTEL_NUM_PMU_COUNTERS; i++) {
142     INTEL_CTRL_READ(control, i);
143     if((((control.l>>INTEL_EVENT_BIT) & 0xff) == event) &&
144        (((control.l>>INTEL_UMASK_BIT) & 0xff) == mask)) {
145       return i;
146     }
147   }
148
149   return -1;
150 }
151
152
153 /*
154  * following implementations : init, deinit, start_tracking, stop_track and get_value
155  * specifically fit into the pmu interface
156  */
157
158 static uint64_t intel_get_value(v3_pmon_ctr_t ctr) {
159   /*
160    * local variables
161    */
162   int ctr_idx;
163   struct msr count;
164
165   count.q = 0x0;
166
167   switch(ctr) {
168   case V3_PMON_CLOCK_COUNT:
169     INTEL_FIXED_CTR_READ(count, INTEL_IDX_CLK_IN_FPMU);
170     break;
171   case V3_PMON_RETIRED_INST_COUNT:
172     INTEL_FIXED_CTR_READ(count, INTEL_IDX_INST_IN_FPMU);
173     break;
174   case V3_PMON_MEM_LOAD_COUNT:
175     if((ctr_idx = intel_find_idx(INTEL_MEM_INST_RETIRED, INTEL_LOADS)) >= 0) {
176       INTEL_CTR_READ(count, ctr_idx);
177     } else {
178       goto INTEL_READ_FAILED;
179     }
180     break;
181   case V3_PMON_MEM_STORE_COUNT:
182     if((ctr_idx = intel_find_idx(INTEL_MEM_INST_RETIRED, INTEL_STORES)) >= 0) {
183       INTEL_CTR_READ(count, ctr_idx);
184     } else {
185       goto INTEL_READ_FAILED;
186     }
187     break;
188   case V3_PMON_CACHE_MISS_COUNT:
189     if((ctr_idx = intel_find_idx(INTEL_MEM_LOAD_RETIRED, INTEL_L3_MISS)) >= 0) {
190       INTEL_CTR_READ(count, ctr_idx);
191     } else {
192       goto INTEL_READ_FAILED;
193     }
194     break;
195   case V3_PMON_TLB_MISS_COUNT:
196     if((ctr_idx = intel_find_idx(INTEL_MEM_LOAD_RETIRED, INTEL_DTLB_MISS)) >= 0) {
197       INTEL_CTR_READ(count, ctr_idx);
198     } else {
199       goto INTEL_READ_FAILED;
200     }
201     break;
202   }
203
204   return (uint64_t)count.q;
205
206  INTEL_READ_FAILED:
207   return 0;
208 }
209
210
211 static int intel_start_tracking(v3_pmon_ctr_t ctr) {
212   /*
213    * local variables
214    */
215   int ctr_idx;
216   struct msr msrs;
217
218   /*
219    * check if available slot in PMU, except for fixed counters (Intel specific)
220    */
221
222   switch(ctr) {
223   case V3_PMON_CLOCK_COUNT:
224     INTEL_FIXED_CTRL_READ(msrs);
225     msrs.l |= 0x3<<8;
226     INTEL_FIXED_CTRL_WRITE(msrs);
227     break;
228   case V3_PMON_RETIRED_INST_COUNT:
229     INTEL_FIXED_CTRL_READ(msrs);
230     msrs.l |= 0x3;
231     INTEL_FIXED_CTRL_WRITE(msrs);
232     break;
233   case V3_PMON_MEM_LOAD_COUNT:
234     if((ctr_idx = intel_get_slot()) >= 0) {
235       INTEL_CTRL_START(INTEL_MEM_INST_RETIRED, INTEL_LOADS, ctr_idx);
236     } else {
237       goto INTEL_START_FAILED;
238     }
239     break;
240   case V3_PMON_MEM_STORE_COUNT:
241     if((ctr_idx = intel_get_slot()) >= 0) {
242       INTEL_CTRL_START(INTEL_MEM_INST_RETIRED, INTEL_STORES, ctr_idx);
243     } else {
244       goto INTEL_START_FAILED;
245     }
246     break;
247   case V3_PMON_CACHE_MISS_COUNT:
248     if((ctr_idx = intel_get_slot()) >= 0) {
249       INTEL_CTRL_START(INTEL_MEM_LOAD_RETIRED, INTEL_L3_MISS, ctr_idx);
250     } else {
251       goto INTEL_START_FAILED;
252     }
253     break;
254   case V3_PMON_TLB_MISS_COUNT:
255     if((ctr_idx = intel_get_slot()) >= 0) {
256       INTEL_CTRL_START(INTEL_MEM_LOAD_RETIRED, INTEL_DTLB_MISS, ctr_idx);
257     } else {
258       goto INTEL_START_FAILED;
259     }
260     break;
261   }
262
263   return 0;
264
265  INTEL_START_FAILED:
266   ERROR("ERROR: no more slot remains for pmon events\n");
267   return -1;
268 }
269
270 /*
271  * descript: disabling pmu event counts
272  */
273
274 static int intel_stop_tracking(v3_pmon_ctr_t ctr) {
275   /*
276    * local variables
277    */
278   int ctr_idx = -1;
279   struct msr msrs;
280
281   /*
282    * check if available slot in PMU, except
283    */
284
285   switch(ctr) {
286   case V3_PMON_CLOCK_COUNT:
287     INTEL_FIXED_CTRL_READ(msrs);
288     msrs.l &= ~(0xf<<8);
289     INTEL_FIXED_CTRL_WRITE(msrs);
290     break;
291   case V3_PMON_RETIRED_INST_COUNT:
292     INTEL_FIXED_CTRL_READ(msrs);
293     msrs.l &= ~(0xf);
294     INTEL_FIXED_CTRL_WRITE(msrs);
295     break;
296   case V3_PMON_MEM_LOAD_COUNT:
297     if((ctr_idx = intel_find_idx(INTEL_MEM_INST_RETIRED, INTEL_LOADS)) >= 0) {
298       INTEL_CTRL_STOP(ctr_idx);
299     } else {
300       goto INTEL_STOP_FAILED;
301     }
302     break;
303   case V3_PMON_MEM_STORE_COUNT:
304     if((ctr_idx = intel_find_idx(INTEL_MEM_INST_RETIRED, INTEL_STORES)) >= 0) {
305       INTEL_CTRL_STOP(ctr_idx);
306     } else {
307       goto INTEL_STOP_FAILED;
308     }
309     break;
310   case V3_PMON_CACHE_MISS_COUNT:
311     if((ctr_idx = intel_find_idx(INTEL_MEM_LOAD_RETIRED, INTEL_L3_MISS)) >= 0) {
312       INTEL_CTRL_STOP(ctr_idx);
313     } else {
314       goto INTEL_STOP_FAILED;
315     }
316     break;
317   case V3_PMON_TLB_MISS_COUNT:
318     if((ctr_idx = intel_find_idx(INTEL_MEM_LOAD_RETIRED, INTEL_DTLB_MISS)) >= 0) {
319       INTEL_CTRL_STOP(ctr_idx);
320     } else {
321       goto INTEL_STOP_FAILED;
322     }
323     break;
324   }
325
326   return 0;
327
328  INTEL_STOP_FAILED:
329   ERROR("ERROR: no more slot remains for pmon events\n");
330   return -1;
331 }
332
333 static void intel_pmu_init(void) {
334   int i;
335   struct msr control;
336
337   if ((get_cpu_var(pmu_refcount)++) > 1) {
338     put_cpu_var(pmu_refcount);
339     // only the first init clears the pmu
340     return;
341   }
342   put_cpu_var(pmu_refcount);
343     
344
345   control.q=0x0;
346
347   /*
348    * per Intel PMU architecture,
349    * there are two class of counters
350    * fixed ones (3 counters) and programmable ones (4 counters)
351    * events for fixed coutners are determined, so enabling or not is the option
352    * whereas, programmable ones are litterally programmable.
353    */
354
355   /*
356    * enable fixed counters in global
357    */
358   MSR_READ(control, INTEL_IA32_PERF_GLOBAL_CTRL);
359   control.q |= 0x70000000f; // enable fix counters (3 for the intel model)
360   MSR_WRITE(control, INTEL_IA32_PERF_GLOBAL_CTRL);
361
362   /*
363    * disable in fixed counters control
364    */
365
366   INTEL_FIXED_CTRL_WRITE(control);
367
368   /*
369    * clean up programmable counter control
370    */
371   for (i=0; i<INTEL_NUM_PMU_CONTROLS; i++) {
372     INTEL_CTRL_WRITE(control, i);
373   }
374 }
375
376 static void intel_pmu_deinit(void) {
377   if ((get_cpu_var(pmu_refcount)--)==0) {
378     put_cpu_var(pmu_refcount);
379     // actually deinit
380     return;
381   }
382   put_cpu_var(pmu_refcount);
383 }
384
385
386
387
388
389 static int amd_find_idx(uint8_t event, uint8_t mask) {
390   int i;
391
392   struct msr control;
393
394   control.q = 0x0;
395
396   for (i=0; i<AMD_NUM_PMU_COUNTERS; i++) {
397     AMD_CTRL_READ(control, i);
398     if((((control.l>>AMD_EVENT_BIT) & 0xff) == event) &&
399        (((control.l>>AMD_UMASK_BIT) & 0xff) == mask)) {
400       return i;
401     }
402   }
403
404   return -1;
405 }
406
407
408 static uint64_t amd_get_value(v3_pmon_ctr_t ctr) {
409   int ctr_idx;
410   struct msr count;
411
412   count.q = 0x0;
413
414   switch(ctr) {
415   case V3_PMON_CLOCK_COUNT:
416     if((ctr_idx = amd_find_idx(AMD_CLK_NOT_HALTED, 0x0)) >= 0) {
417       AMD_CTR_READ(count, ctr_idx);
418     } else {
419       goto AMD_READ_FAILED;
420     }
421     break;
422   case V3_PMON_RETIRED_INST_COUNT:
423     if((ctr_idx = amd_find_idx(AMD_RETIRED_INSTRUCTIONS, 0x0)) >= 0) {
424       AMD_CTR_READ(count, ctr_idx);
425     } else {
426       goto AMD_READ_FAILED;
427     }
428     break;
429   case V3_PMON_MEM_LOAD_COUNT:
430     if((ctr_idx = amd_find_idx(AMD_DATA_CACHE_ACCESSES, 0x0)) >= 0) {
431       AMD_CTR_READ(count, ctr_idx);
432     } else {
433       goto AMD_READ_FAILED;
434     }
435     break;
436   case V3_PMON_MEM_STORE_COUNT:
437     if((ctr_idx = amd_find_idx(AMD_DATA_CACHE_ACCESSES, 0x0)) >= 0) {
438       AMD_CTR_READ(count, ctr_idx);
439     } else {
440       goto AMD_READ_FAILED;
441     }
442     break;
443   case V3_PMON_CACHE_MISS_COUNT:
444     if((ctr_idx = amd_find_idx(AMD_DATA_CACHE_MISSES, 0x0)) >= 0) {
445       AMD_CTR_READ(count, ctr_idx);
446     } else {
447       goto AMD_READ_FAILED;
448     }
449     break;
450   case V3_PMON_TLB_MISS_COUNT:
451     if((ctr_idx = amd_find_idx(AMD_L1_DTLB_AND_L2_DTLB_MISS, 0x7)) >= 0) {
452       AMD_CTR_READ(count, ctr_idx);
453     } else {
454       goto AMD_READ_FAILED;
455     }
456     break;
457   }
458
459   return (uint64_t)count.q;
460
461  AMD_READ_FAILED:
462   return 0;
463 }
464
465 static int amd_start_tracking(v3_pmon_ctr_t ctr) {
466
467   int ctr_idx;
468
469   switch(ctr) {
470   case V3_PMON_CLOCK_COUNT:
471     if((ctr_idx = amd_get_slot()) >= 0) {
472       AMD_CTRL_START(AMD_CLK_NOT_HALTED, 0x0, ctr_idx);
473     } else {
474       goto AMD_START_FAILED;
475     }
476     break;
477   case V3_PMON_RETIRED_INST_COUNT:
478     if((ctr_idx = amd_get_slot()) >= 0) {
479       AMD_CTRL_START(AMD_RETIRED_INSTRUCTIONS, 0x0, ctr_idx);
480     } else {
481       goto AMD_START_FAILED;
482     }
483     break;
484   case V3_PMON_MEM_LOAD_COUNT:
485     if((ctr_idx = amd_get_slot()) >= 0) {
486       AMD_CTRL_START(AMD_DATA_CACHE_ACCESSES, 0x0, ctr_idx);
487     } else {
488       goto AMD_START_FAILED;
489     }
490     break;
491   case V3_PMON_MEM_STORE_COUNT:
492     if((ctr_idx = amd_get_slot()) >= 0) {
493       AMD_CTRL_START(AMD_DATA_CACHE_ACCESSES, 0x0, ctr_idx);
494     } else {
495       goto AMD_START_FAILED;
496     }
497     break;
498   case V3_PMON_CACHE_MISS_COUNT:
499     if((ctr_idx = amd_get_slot()) >= 0) {
500       AMD_CTRL_START(AMD_DATA_CACHE_MISSES, 0x0, ctr_idx);
501     } else {
502       goto AMD_START_FAILED;
503     }
504     break;
505   case V3_PMON_TLB_MISS_COUNT:
506     if((ctr_idx = amd_get_slot()) >= 0) {
507       AMD_CTRL_START(AMD_L1_DTLB_AND_L2_DTLB_MISS, 0x7, ctr_idx);
508     } else {
509       goto AMD_START_FAILED;
510     }
511     break;
512   }
513
514   return 0;
515
516  AMD_START_FAILED:
517   ERROR("ERROR: no more slot remains for pmon events\n");
518   return -1;
519 }
520
521
522 static int amd_stop_tracking(v3_pmon_ctr_t ctr) {
523
524   int ctr_idx = -1;
525
526
527   switch(ctr) {
528   case V3_PMON_CLOCK_COUNT:
529     if((ctr_idx = amd_find_idx(AMD_CLK_NOT_HALTED, 0x0)) >= 0) {
530       AMD_CTRL_STOP(ctr_idx);
531     } else {
532       goto AMD_STOP_FAILED;
533     }
534     break;
535   case V3_PMON_RETIRED_INST_COUNT:
536     if((ctr_idx = amd_find_idx(AMD_RETIRED_INSTRUCTIONS, 0x0)) >= 0) {
537       AMD_CTRL_STOP(ctr_idx);
538     } else {
539       goto AMD_STOP_FAILED;
540     }
541     break;
542   case V3_PMON_MEM_LOAD_COUNT:
543     if((ctr_idx = amd_find_idx(AMD_DATA_CACHE_ACCESSES, 0x0)) >= 0) {
544       AMD_CTRL_STOP(ctr_idx);
545     } else {
546       goto AMD_STOP_FAILED;
547     }
548     break;
549   case V3_PMON_MEM_STORE_COUNT:
550     if((ctr_idx = amd_find_idx(AMD_DATA_CACHE_ACCESSES, 0x0)) >= 0) {
551       AMD_CTRL_STOP(ctr_idx);
552     } else {
553       goto AMD_STOP_FAILED;
554     }
555     break;
556   case V3_PMON_CACHE_MISS_COUNT:
557     if((ctr_idx = amd_find_idx(AMD_DATA_CACHE_MISSES, 0x0)) >= 0) {
558       AMD_CTRL_STOP(ctr_idx);
559     } else {
560       goto AMD_STOP_FAILED;
561     }
562     break;
563   case V3_PMON_TLB_MISS_COUNT:
564     if((ctr_idx = amd_find_idx(AMD_L1_DTLB_AND_L2_DTLB_MISS, 0x7)) >= 0) {
565       AMD_CTRL_STOP(ctr_idx);
566     } else {
567       goto AMD_STOP_FAILED;
568     }
569     break;
570   }
571
572   return 0;
573
574  AMD_STOP_FAILED:
575   ERROR("ERROR: no more slot remains for pmon events\n");
576   return -1;
577 }
578
579
580 static void amd_pmu_init(void) {
581
582   int i;
583   struct msr control;
584
585   
586   if ((get_cpu_var(pmu_refcount)++) > 1) {
587     put_cpu_var(pmu_refcount);
588     // only the first init clears the pmu
589     return;
590   }
591   put_cpu_var(pmu_refcount);
592   
593   
594
595   // initialize variables
596   control.q=0x0;
597
598   /*
599    * clean up programmable counter control
600    */
601   for (i=0; i<AMD_NUM_PMU_CONTROLS; i++) {
602     AMD_CTRL_WRITE(control, i);
603   }
604 }
605
606 static void amd_pmu_deinit(void) {
607   if ((get_cpu_var(pmu_refcount)--)==0) {
608     put_cpu_var(pmu_refcount);
609     // actually deinit
610     return;
611   }
612   put_cpu_var(pmu_refcount);
613 }
614
615
616 static struct v3_pmu_iface palacios_pmu_intel = {
617   .init = intel_pmu_init,
618   .deinit = intel_pmu_deinit,
619   .start_tracking = intel_start_tracking,
620   .stop_tracking = intel_stop_tracking,
621   .get_value = intel_get_value
622 };
623
624 static struct v3_pmu_iface palacios_pmu_amd = {
625   .init = amd_pmu_init,
626   .deinit = amd_pmu_deinit,
627   .start_tracking = amd_start_tracking,
628   .stop_tracking = amd_stop_tracking,
629   .get_value = amd_get_value
630 };
631
632 static int pmu_init( void ) {
633   if (is_intel()) {
634     INFO("Intel PMU featureset detected\n");
635     V3_Init_PMU(&palacios_pmu_intel);
636   } else if (is_amd()) { 
637     INFO("AMD PMU featureset detected\n");
638     V3_Init_PMU(&palacios_pmu_amd);
639   } else {
640     ERROR("This is neither an Intel nor AMD machine - No PMU functionality configured\n");
641     return -1;
642   }
643
644   return 0;
645 }
646
647 static int pmu_deinit(void)
648 {
649     // nothing
650     return 0;
651 }
652
653
654 static struct linux_ext pmu_ext = {
655   .name = "PMU",
656   .init = pmu_init,
657   .deinit = pmu_deinit,
658   .guest_init = NULL,
659   .guest_deinit = NULL
660 };
661
662 register_extension(&pmu_ext);
663
664
665
666