1 
2 #include <xen/lib.h>
3 #include <xen/smp.h>
4 #include <xen/time.h>
5 #include <xen/perfc.h>
6 #include <xen/keyhandler.h>
7 #include <xen/spinlock.h>
8 #include <xen/mm.h>
9 #include <xen/guest_access.h>
10 #include <public/sysctl.h>
11 #include <asm/perfc.h>
12 
13 #define PERFCOUNTER( var, name )              { name, TYPE_SINGLE, 0 },
14 #define PERFCOUNTER_ARRAY( var, name, size )  { name, TYPE_ARRAY,  size },
15 #define PERFSTATUS( var, name )               { name, TYPE_S_SINGLE, 0 },
16 #define PERFSTATUS_ARRAY( var, name, size )   { name, TYPE_S_ARRAY,  size },
17 static const struct {
18     const char *name;
19     enum { TYPE_SINGLE, TYPE_ARRAY,
20            TYPE_S_SINGLE, TYPE_S_ARRAY
21     } type;
22     unsigned int nr_elements;
23 } perfc_info[] = {
24 #include <xen/perfc_defn.h>
25 };
26 
27 #define NR_PERFCTRS (sizeof(perfc_info) / sizeof(perfc_info[0]))
28 
29 DEFINE_PER_CPU(perfc_t[NUM_PERFCOUNTERS], perfcounters);
30 
perfc_printall(unsigned char key)31 void perfc_printall(unsigned char key)
32 {
33     unsigned int i, j;
34     s_time_t now = NOW();
35 
36     printk("Xen performance counters SHOW  (now = %"PRI_stime")\n", now);
37 
38     for ( i = j = 0; i < NR_PERFCTRS; i++ )
39     {
40         unsigned int k, cpu;
41         unsigned long long sum = 0;
42 
43         printk("%-32s  ",  perfc_info[i].name);
44         switch ( perfc_info[i].type )
45         {
46         case TYPE_SINGLE:
47         case TYPE_S_SINGLE:
48             for_each_online_cpu ( cpu )
49                 sum += per_cpu(perfcounters, cpu)[j];
50             if ( perfc_info[i].type == TYPE_S_SINGLE )
51                 sum = (perfc_t) sum;
52             printk("TOTAL[%12Lu]", sum);
53             if ( sum )
54             {
55                 k = 0;
56                 for_each_online_cpu ( cpu )
57                 {
58                     if ( k > 0 && (k % 4) == 0 )
59                         printk("\n%53s", "");
60                     printk("  CPU%02u[%10"PRIperfc"u]", cpu, per_cpu(perfcounters, cpu)[j]);
61                     ++k;
62                 }
63             }
64             ++j;
65             break;
66         case TYPE_ARRAY:
67         case TYPE_S_ARRAY:
68             for_each_online_cpu ( cpu )
69             {
70                 perfc_t *counters = per_cpu(perfcounters, cpu) + j;
71 
72                 for ( k = 0; k < perfc_info[i].nr_elements; k++ )
73                     sum += counters[k];
74             }
75             if ( perfc_info[i].type == TYPE_S_ARRAY )
76                 sum = (perfc_t) sum;
77             printk("TOTAL[%12Lu]", sum);
78             if (sum)
79             {
80 #ifdef CONFIG_PERF_ARRAYS
81                 for ( k = 0; k < perfc_info[i].nr_elements; k++ )
82                 {
83                     sum = 0;
84                     for_each_online_cpu ( cpu )
85                         sum += per_cpu(perfcounters, cpu)[j + k];
86                     if ( perfc_info[i].type == TYPE_S_ARRAY )
87                         sum = (perfc_t) sum;
88                     if ( (k % 4) == 0 )
89                         printk("\n%16s", "");
90                     printk("  ARR%02u[%10Lu]", k, sum);
91                 }
92 #else
93                 k = 0;
94                 for_each_online_cpu ( cpu )
95                 {
96                     perfc_t *counters = per_cpu(perfcounters, cpu) + j;
97                     unsigned int n;
98 
99                     sum = 0;
100                     for ( n = 0; n < perfc_info[i].nr_elements; n++ )
101                         sum += counters[n];
102                     if ( perfc_info[i].type == TYPE_S_ARRAY )
103                         sum = (perfc_t) sum;
104                     if ( k > 0 && (k % 4) == 0 )
105                         printk("\n%53s", "");
106                     printk("  CPU%02u[%10Lu]", cpu, sum);
107                     ++k;
108                 }
109 #endif
110             }
111             j += perfc_info[i].nr_elements;
112             break;
113         }
114         printk("\n");
115     }
116 }
117 
perfc_reset(unsigned char key)118 void perfc_reset(unsigned char key)
119 {
120     unsigned int i, j;
121     s_time_t now = NOW();
122 
123     if ( key != '\0' )
124         printk("Xen performance counters RESET (now = %"PRI_stime")\n", now);
125 
126     /* leave STATUS counters alone -- don't reset */
127 
128     for ( i = j = 0; i < NR_PERFCTRS; i++ )
129     {
130         unsigned int cpu;
131 
132         switch ( perfc_info[i].type )
133         {
134         case TYPE_SINGLE:
135             for_each_online_cpu ( cpu )
136                 per_cpu(perfcounters, cpu)[j] = 0;
137         case TYPE_S_SINGLE:
138             ++j;
139             break;
140         case TYPE_ARRAY:
141             for_each_online_cpu ( cpu )
142                 memset(per_cpu(perfcounters, cpu) + j, 0,
143                        perfc_info[i].nr_elements * sizeof(perfc_t));
144         case TYPE_S_ARRAY:
145             j += perfc_info[i].nr_elements;
146             break;
147         }
148     }
149 
150     arch_perfc_reset();
151 }
152 
153 static struct xen_sysctl_perfc_desc perfc_d[NR_PERFCTRS];
154 static xen_sysctl_perfc_val_t *perfc_vals;
155 static unsigned int      perfc_nbr_vals;
156 static cpumask_t         perfc_cpumap;
157 
perfc_copy_info(XEN_GUEST_HANDLE_64 (xen_sysctl_perfc_desc_t)desc,XEN_GUEST_HANDLE_64 (xen_sysctl_perfc_val_t)val)158 static int perfc_copy_info(XEN_GUEST_HANDLE_64(xen_sysctl_perfc_desc_t) desc,
159                            XEN_GUEST_HANDLE_64(xen_sysctl_perfc_val_t) val)
160 {
161     unsigned int i, j, v;
162 
163     /* We only copy the name and array-size information once. */
164     if ( !cpumask_equal(&cpu_online_map, &perfc_cpumap) )
165     {
166         unsigned int nr_cpus;
167         perfc_cpumap = cpu_online_map;
168         nr_cpus = cpumask_weight(&perfc_cpumap);
169 
170         perfc_nbr_vals = 0;
171 
172         for ( i = 0; i < NR_PERFCTRS; i++ )
173         {
174             safe_strcpy(perfc_d[i].name, perfc_info[i].name);
175 
176             switch ( perfc_info[i].type )
177             {
178             case TYPE_SINGLE:
179             case TYPE_S_SINGLE:
180                 perfc_d[i].nr_vals = nr_cpus;
181                 break;
182             case TYPE_ARRAY:
183             case TYPE_S_ARRAY:
184                 perfc_d[i].nr_vals = perfc_info[i].nr_elements;
185                 break;
186             }
187             perfc_nbr_vals += perfc_d[i].nr_vals;
188         }
189 
190         xfree(perfc_vals);
191         perfc_vals = xmalloc_array(xen_sysctl_perfc_val_t, perfc_nbr_vals);
192     }
193 
194     if ( guest_handle_is_null(desc) )
195         return 0;
196 
197     if ( perfc_vals == NULL )
198         return -ENOMEM;
199 
200     /* Architecture may fill counters from hardware.  */
201     arch_perfc_gather();
202 
203     /* We gather the counts together every time. */
204     for ( i = j = v = 0; i < NR_PERFCTRS; i++ )
205     {
206         unsigned int cpu;
207 
208         switch ( perfc_info[i].type )
209         {
210         case TYPE_SINGLE:
211         case TYPE_S_SINGLE:
212             for_each_cpu ( cpu, &perfc_cpumap )
213                 perfc_vals[v++] = per_cpu(perfcounters, cpu)[j];
214             ++j;
215             break;
216         case TYPE_ARRAY:
217         case TYPE_S_ARRAY:
218             memset(perfc_vals + v, 0, perfc_d[i].nr_vals * sizeof(*perfc_vals));
219             for_each_cpu ( cpu, &perfc_cpumap )
220             {
221                 perfc_t *counters = per_cpu(perfcounters, cpu) + j;
222                 unsigned int k;
223 
224                 for ( k = 0; k < perfc_d[i].nr_vals; k++ )
225                     perfc_vals[v + k] += counters[k];
226             }
227             v += perfc_d[i].nr_vals;
228             j += perfc_info[i].nr_elements;
229             break;
230         }
231     }
232     BUG_ON(v != perfc_nbr_vals);
233 
234     if ( copy_to_guest(desc, perfc_d, NR_PERFCTRS) )
235         return -EFAULT;
236     if ( copy_to_guest(val, perfc_vals, perfc_nbr_vals) )
237         return -EFAULT;
238     return 0;
239 }
240 
241 /* Dom0 control of perf counters */
perfc_control(struct xen_sysctl_perfc_op * pc)242 int perfc_control(struct xen_sysctl_perfc_op *pc)
243 {
244     static DEFINE_SPINLOCK(lock);
245     int rc;
246 
247     spin_lock(&lock);
248 
249     switch ( pc->cmd )
250     {
251     case XEN_SYSCTL_PERFCOP_reset:
252         rc = perfc_copy_info(pc->desc, pc->val);
253         perfc_reset(0);
254         break;
255 
256     case XEN_SYSCTL_PERFCOP_query:
257         rc = perfc_copy_info(pc->desc, pc->val);
258         break;
259 
260     default:
261         rc = -EINVAL;
262         break;
263     }
264 
265     spin_unlock(&lock);
266 
267     pc->nr_counters = NR_PERFCTRS;
268     pc->nr_vals = perfc_nbr_vals;
269 
270     return rc;
271 }
272 
273 /*
274  * Local variables:
275  * mode: C
276  * c-file-style: "BSD"
277  * c-basic-offset: 4
278  * tab-width: 4
279  * indent-tabs-mode: nil
280  * End:
281  */
282