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.


Cleanup based on cppcheck pass (Linux module and user)
[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 }
128
129 /*
130  * name: *_find_idx
131  * description: find index of pmu register that is available
132  */
133 static int intel_find_idx(uint8_t event, uint8_t mask) {
134   int i;
135
136   struct msr control;
137
138   control.q = 0x0;
139
140   for (i=0; i<INTEL_NUM_PMU_COUNTERS; i++) {
141     INTEL_CTRL_READ(control, i);
142     if((((control.l>>INTEL_EVENT_BIT) & 0xff) == event) &&
143        (((control.l>>INTEL_UMASK_BIT) & 0xff) == mask)) {
144       return i;
145     }
146   }
147
148   return -1;
149 }
150
151
152 /*
153  * following implementations : init, deinit, start_tracking, stop_track and get_value
154  * specifically fit into the pmu interface
155  */
156
157 static uint64_t intel_get_value(v3_pmon_ctr_t ctr) {
158   /*
159    * local variables
160    */
161   int ctr_idx;
162   struct msr count;
163
164   count.q = 0x0;
165
166   switch(ctr) {
167   case V3_PMON_CLOCK_COUNT:
168     INTEL_FIXED_CTR_READ(count, INTEL_IDX_CLK_IN_FPMU);
169     break;
170   case V3_PMON_RETIRED_INST_COUNT:
171     INTEL_FIXED_CTR_READ(count, INTEL_IDX_INST_IN_FPMU);
172     break;
173   case V3_PMON_MEM_LOAD_COUNT:
174     if((ctr_idx = intel_find_idx(INTEL_MEM_INST_RETIRED, INTEL_LOADS)) >= 0) {
175       INTEL_CTR_READ(count, ctr_idx);
176     } else {
177       goto INTEL_READ_FAILED;
178     }
179     break;
180   case V3_PMON_MEM_STORE_COUNT:
181     if((ctr_idx = intel_find_idx(INTEL_MEM_INST_RETIRED, INTEL_STORES)) >= 0) {
182       INTEL_CTR_READ(count, ctr_idx);
183     } else {
184       goto INTEL_READ_FAILED;
185     }
186     break;
187   case V3_PMON_CACHE_MISS_COUNT:
188     if((ctr_idx = intel_find_idx(INTEL_MEM_LOAD_RETIRED, INTEL_L3_MISS)) >= 0) {
189       INTEL_CTR_READ(count, ctr_idx);
190     } else {
191       goto INTEL_READ_FAILED;
192     }
193     break;
194   case V3_PMON_TLB_MISS_COUNT:
195     if((ctr_idx = intel_find_idx(INTEL_MEM_LOAD_RETIRED, INTEL_DTLB_MISS)) >= 0) {
196       INTEL_CTR_READ(count, ctr_idx);
197     } else {
198       goto INTEL_READ_FAILED;
199     }
200     break;
201   }
202
203   return (uint64_t)count.q;
204
205  INTEL_READ_FAILED:
206   return 0;
207 }
208
209
210 static int intel_start_tracking(v3_pmon_ctr_t ctr) {
211   /*
212    * local variables
213    */
214   int ctr_idx;
215   struct msr msrs;
216
217   /*
218    * check if available slot in PMU, except for fixed counters (Intel specific)
219    */
220
221   switch(ctr) {
222   case V3_PMON_CLOCK_COUNT:
223     INTEL_FIXED_CTRL_READ(msrs);
224     msrs.l |= 0x3<<8;
225     INTEL_FIXED_CTRL_WRITE(msrs);
226     break;
227   case V3_PMON_RETIRED_INST_COUNT:
228     INTEL_FIXED_CTRL_READ(msrs);
229     msrs.l |= 0x3;
230     INTEL_FIXED_CTRL_WRITE(msrs);
231     break;
232   case V3_PMON_MEM_LOAD_COUNT:
233     if((ctr_idx = intel_get_slot()) >= 0) {
234       INTEL_CTRL_START(INTEL_MEM_INST_RETIRED, INTEL_LOADS, ctr_idx);
235     } else {
236       goto INTEL_START_FAILED;
237     }
238     break;
239   case V3_PMON_MEM_STORE_COUNT:
240     if((ctr_idx = intel_get_slot()) >= 0) {
241       INTEL_CTRL_START(INTEL_MEM_INST_RETIRED, INTEL_STORES, ctr_idx);
242     } else {
243       goto INTEL_START_FAILED;
244     }
245     break;
246   case V3_PMON_CACHE_MISS_COUNT:
247     if((ctr_idx = intel_get_slot()) >= 0) {
248       INTEL_CTRL_START(INTEL_MEM_LOAD_RETIRED, INTEL_L3_MISS, ctr_idx);
249     } else {
250       goto INTEL_START_FAILED;
251     }
252     break;
253   case V3_PMON_TLB_MISS_COUNT:
254     if((ctr_idx = intel_get_slot()) >= 0) {
255       INTEL_CTRL_START(INTEL_MEM_LOAD_RETIRED, INTEL_DTLB_MISS, ctr_idx);
256     } else {
257       goto INTEL_START_FAILED;
258     }
259     break;
260   }
261
262   return 0;
263
264  INTEL_START_FAILED:
265   ERROR("ERROR: no more slot remains for pmon events\n");
266   return -1;
267 }
268
269 /*
270  * descript: disabling pmu event counts
271  */
272
273 static int intel_stop_tracking(v3_pmon_ctr_t ctr) {
274   /*
275    * local variables
276    */
277   int ctr_idx = -1;
278   struct msr msrs;
279
280   /*
281    * check if available slot in PMU, except
282    */
283
284   switch(ctr) {
285   case V3_PMON_CLOCK_COUNT:
286     INTEL_FIXED_CTRL_READ(msrs);
287     msrs.l &= ~(0xf<<8);
288     INTEL_FIXED_CTRL_WRITE(msrs);
289     break;
290   case V3_PMON_RETIRED_INST_COUNT:
291     INTEL_FIXED_CTRL_READ(msrs);
292     msrs.l &= ~(0xf);
293     INTEL_FIXED_CTRL_WRITE(msrs);
294     break;
295   case V3_PMON_MEM_LOAD_COUNT:
296     if((ctr_idx = intel_find_idx(INTEL_MEM_INST_RETIRED, INTEL_LOADS)) >= 0) {
297       INTEL_CTRL_STOP(ctr_idx);
298     } else {
299       goto INTEL_STOP_FAILED;
300     }
301     break;
302   case V3_PMON_MEM_STORE_COUNT:
303     if((ctr_idx = intel_find_idx(INTEL_MEM_INST_RETIRED, INTEL_STORES)) >= 0) {
304       INTEL_CTRL_STOP(ctr_idx);
305     } else {
306       goto INTEL_STOP_FAILED;
307     }
308     break;
309   case V3_PMON_CACHE_MISS_COUNT:
310     if((ctr_idx = intel_find_idx(INTEL_MEM_LOAD_RETIRED, INTEL_L3_MISS)) >= 0) {
311       INTEL_CTRL_STOP(ctr_idx);
312     } else {
313       goto INTEL_STOP_FAILED;
314     }
315     break;
316   case V3_PMON_TLB_MISS_COUNT:
317     if((ctr_idx = intel_find_idx(INTEL_MEM_LOAD_RETIRED, INTEL_DTLB_MISS)) >= 0) {
318       INTEL_CTRL_STOP(ctr_idx);
319     } else {
320       goto INTEL_STOP_FAILED;
321     }
322     break;
323   }
324
325   return 0;
326
327  INTEL_STOP_FAILED:
328   ERROR("ERROR: no more slot remains for pmon events\n");
329   return -1;
330 }
331
332 static void intel_pmu_init(void) {
333   int i;
334   struct msr control;
335
336   if ((get_cpu_var(pmu_refcount)++) > 1) {
337     put_cpu_var(pmu_refcount);
338     // only the first init clears the pmu
339     return;
340   }
341   put_cpu_var(pmu_refcount);
342     
343
344   control.q=0x0;
345
346   /*
347    * per Intel PMU architecture,
348    * there are two class of counters
349    * fixed ones (3 counters) and programmable ones (4 counters)
350    * events for fixed coutners are determined, so enabling or not is the option
351    * whereas, programmable ones are litterally programmable.
352    */
353
354   /*
355    * enable fixed counters in global
356    */
357   MSR_READ(control, INTEL_IA32_PERF_GLOBAL_CTRL);
358   control.q |= 0x70000000f; // enable fix counters (3 for the intel model)
359   MSR_WRITE(control, INTEL_IA32_PERF_GLOBAL_CTRL);
360
361   /*
362    * disable in fixed counters control
363    */
364
365   INTEL_FIXED_CTRL_WRITE(control);
366
367   /*
368    * clean up programmable counter control
369    */
370   for (i=0; i<INTEL_NUM_PMU_CONTROLS; i++) {
371     INTEL_CTRL_WRITE(control, i);
372   }
373 }
374
375 static void intel_pmu_deinit(void) {
376   if ((get_cpu_var(pmu_refcount)--)==0) {
377     put_cpu_var(pmu_refcount);
378     // actually deinit
379     return;
380   }
381   put_cpu_var(pmu_refcount);
382 }
383
384
385
386
387
388 static int amd_find_idx(uint8_t event, uint8_t mask) {
389   int i;
390
391   struct msr control;
392
393   control.q = 0x0;
394
395   for (i=0; i<AMD_NUM_PMU_COUNTERS; i++) {
396     AMD_CTRL_READ(control, i);
397     if((((control.l>>AMD_EVENT_BIT) & 0xff) == event) &&
398        (((control.l>>AMD_UMASK_BIT) & 0xff) == mask)) {
399       return i;
400     }
401   }
402
403   return -1;
404 }
405
406
407 static uint64_t amd_get_value(v3_pmon_ctr_t ctr) {
408   int ctr_idx;
409   struct msr count;
410
411   count.q = 0x0;
412
413   switch(ctr) {
414   case V3_PMON_CLOCK_COUNT:
415     if((ctr_idx = amd_find_idx(AMD_CLK_NOT_HALTED, 0x0)) >= 0) {
416       AMD_CTR_READ(count, ctr_idx);
417     } else {
418       goto AMD_READ_FAILED;
419     }
420     break;
421   case V3_PMON_RETIRED_INST_COUNT:
422     if((ctr_idx = amd_find_idx(AMD_RETIRED_INSTRUCTIONS, 0x0)) >= 0) {
423       AMD_CTR_READ(count, ctr_idx);
424     } else {
425       goto AMD_READ_FAILED;
426     }
427     break;
428   case V3_PMON_MEM_LOAD_COUNT:
429     if((ctr_idx = amd_find_idx(AMD_DATA_CACHE_ACCESSES, 0x0)) >= 0) {
430       AMD_CTR_READ(count, ctr_idx);
431     } else {
432       goto AMD_READ_FAILED;
433     }
434     break;
435   case V3_PMON_MEM_STORE_COUNT:
436     if((ctr_idx = amd_find_idx(AMD_DATA_CACHE_ACCESSES, 0x0)) >= 0) {
437       AMD_CTR_READ(count, ctr_idx);
438     } else {
439       goto AMD_READ_FAILED;
440     }
441     break;
442   case V3_PMON_CACHE_MISS_COUNT:
443     if((ctr_idx = amd_find_idx(AMD_DATA_CACHE_MISSES, 0x0)) >= 0) {
444       AMD_CTR_READ(count, ctr_idx);
445     } else {
446       goto AMD_READ_FAILED;
447     }
448     break;
449   case V3_PMON_TLB_MISS_COUNT:
450     if((ctr_idx = amd_find_idx(AMD_L1_DTLB_AND_L2_DTLB_MISS, 0x7)) >= 0) {
451       AMD_CTR_READ(count, ctr_idx);
452     } else {
453       goto AMD_READ_FAILED;
454     }
455     break;
456   }
457
458   return (uint64_t)count.q;
459
460  AMD_READ_FAILED:
461   return 0;
462 }
463
464 static int amd_start_tracking(v3_pmon_ctr_t ctr) {
465
466   int ctr_idx;
467
468   switch(ctr) {
469   case V3_PMON_CLOCK_COUNT:
470     if((ctr_idx = amd_get_slot()) >= 0) {
471       AMD_CTRL_START(AMD_CLK_NOT_HALTED, 0x0, ctr_idx);
472     } else {
473       goto AMD_START_FAILED;
474     }
475     break;
476   case V3_PMON_RETIRED_INST_COUNT:
477     if((ctr_idx = amd_get_slot()) >= 0) {
478       AMD_CTRL_START(AMD_RETIRED_INSTRUCTIONS, 0x0, ctr_idx);
479     } else {
480       goto AMD_START_FAILED;
481     }
482     break;
483   case V3_PMON_MEM_LOAD_COUNT:
484     if((ctr_idx = amd_get_slot()) >= 0) {
485       AMD_CTRL_START(AMD_DATA_CACHE_ACCESSES, 0x0, ctr_idx);
486     } else {
487       goto AMD_START_FAILED;
488     }
489     break;
490   case V3_PMON_MEM_STORE_COUNT:
491     if((ctr_idx = amd_get_slot()) >= 0) {
492       AMD_CTRL_START(AMD_DATA_CACHE_ACCESSES, 0x0, ctr_idx);
493     } else {
494       goto AMD_START_FAILED;
495     }
496     break;
497   case V3_PMON_CACHE_MISS_COUNT:
498     if((ctr_idx = amd_get_slot()) >= 0) {
499       AMD_CTRL_START(AMD_DATA_CACHE_MISSES, 0x0, ctr_idx);
500     } else {
501       goto AMD_START_FAILED;
502     }
503     break;
504   case V3_PMON_TLB_MISS_COUNT:
505     if((ctr_idx = amd_get_slot()) >= 0) {
506       AMD_CTRL_START(AMD_L1_DTLB_AND_L2_DTLB_MISS, 0x7, ctr_idx);
507     } else {
508       goto AMD_START_FAILED;
509     }
510     break;
511   }
512
513   return 0;
514
515  AMD_START_FAILED:
516   ERROR("ERROR: no more slot remains for pmon events\n");
517   return -1;
518 }
519
520
521 static int amd_stop_tracking(v3_pmon_ctr_t ctr) {
522
523   int ctr_idx = -1;
524
525
526   switch(ctr) {
527   case V3_PMON_CLOCK_COUNT:
528     if((ctr_idx = amd_find_idx(AMD_CLK_NOT_HALTED, 0x0)) >= 0) {
529       AMD_CTRL_STOP(ctr_idx);
530     } else {
531       goto AMD_STOP_FAILED;
532     }
533     break;
534   case V3_PMON_RETIRED_INST_COUNT:
535     if((ctr_idx = amd_find_idx(AMD_RETIRED_INSTRUCTIONS, 0x0)) >= 0) {
536       AMD_CTRL_STOP(ctr_idx);
537     } else {
538       goto AMD_STOP_FAILED;
539     }
540     break;
541   case V3_PMON_MEM_LOAD_COUNT:
542     if((ctr_idx = amd_find_idx(AMD_DATA_CACHE_ACCESSES, 0x0)) >= 0) {
543       AMD_CTRL_STOP(ctr_idx);
544     } else {
545       goto AMD_STOP_FAILED;
546     }
547     break;
548   case V3_PMON_MEM_STORE_COUNT:
549     if((ctr_idx = amd_find_idx(AMD_DATA_CACHE_ACCESSES, 0x0)) >= 0) {
550       AMD_CTRL_STOP(ctr_idx);
551     } else {
552       goto AMD_STOP_FAILED;
553     }
554     break;
555   case V3_PMON_CACHE_MISS_COUNT:
556     if((ctr_idx = amd_find_idx(AMD_DATA_CACHE_MISSES, 0x0)) >= 0) {
557       AMD_CTRL_STOP(ctr_idx);
558     } else {
559       goto AMD_STOP_FAILED;
560     }
561     break;
562   case V3_PMON_TLB_MISS_COUNT:
563     if((ctr_idx = amd_find_idx(AMD_L1_DTLB_AND_L2_DTLB_MISS, 0x7)) >= 0) {
564       AMD_CTRL_STOP(ctr_idx);
565     } else {
566       goto AMD_STOP_FAILED;
567     }
568     break;
569   }
570
571   return 0;
572
573  AMD_STOP_FAILED:
574   ERROR("ERROR: no more slot remains for pmon events\n");
575   return -1;
576 }
577
578
579 static void amd_pmu_init(void) {
580
581   int i;
582   struct msr control;
583
584   
585   if ((get_cpu_var(pmu_refcount)++) > 1) {
586     put_cpu_var(pmu_refcount);
587     // only the first init clears the pmu
588     return;
589   }
590   put_cpu_var(pmu_refcount);
591   
592   
593
594   // initialize variables
595   control.q=0x0;
596
597   /*
598    * clean up programmable counter control
599    */
600   for (i=0; i<AMD_NUM_PMU_CONTROLS; i++) {
601     AMD_CTRL_WRITE(control, i);
602   }
603 }
604
605 static void amd_pmu_deinit(void) {
606   if ((get_cpu_var(pmu_refcount)--)==0) {
607     put_cpu_var(pmu_refcount);
608     // actually deinit
609     return;
610   }
611   put_cpu_var(pmu_refcount);
612 }
613
614
615 static struct v3_pmu_iface palacios_pmu_intel = {
616   .init = intel_pmu_init,
617   .deinit = intel_pmu_deinit,
618   .start_tracking = intel_start_tracking,
619   .stop_tracking = intel_stop_tracking,
620   .get_value = intel_get_value
621 };
622
623 static struct v3_pmu_iface palacios_pmu_amd = {
624   .init = amd_pmu_init,
625   .deinit = amd_pmu_deinit,
626   .start_tracking = amd_start_tracking,
627   .stop_tracking = amd_stop_tracking,
628   .get_value = amd_get_value
629 };
630
631 static int pmu_init( void ) {
632   if (is_intel()) {
633     INFO("Intel PMU featureset detected\n");
634     V3_Init_PMU(&palacios_pmu_intel);
635   } else if (is_amd()) { 
636     INFO("AMD PMU featureset detected\n");
637     V3_Init_PMU(&palacios_pmu_amd);
638   } else {
639     ERROR("This is neither an Intel nor AMD machine - No PMU functionality configured\n");
640     return -1;
641   }
642
643   return 0;
644 }
645
646 static int pmu_deinit(void)
647 {
648     // nothing
649     return 0;
650 }
651
652
653 static struct linux_ext pmu_ext = {
654   .name = "PMU",
655   .init = pmu_init,
656   .deinit = pmu_deinit,
657   .guest_init = NULL,
658   .guest_deinit = NULL
659 };
660
661 register_extension(&pmu_ext);
662
663
664
665