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