1 
2 #include <xen/cpumask.h>
3 #include <xen/errno.h>
4 #include <xen/guest_access.h>
5 #include <xen/lib.h>
6 #include <xen/perfc.h>
7 #include <xen/spinlock.h>
8 #include <xen/time.h>
9 
10 #include <public/sysctl.h>
11 
12 #define PERFCOUNTER( var, name )              { name, TYPE_SINGLE, 0 },
13 #define PERFCOUNTER_ARRAY( var, name, size )  { name, TYPE_ARRAY,  size },
14 #define PERFSTATUS( var, name )               { name, TYPE_S_SINGLE, 0 },
15 #define PERFSTATUS_ARRAY( var, name, size )   { name, TYPE_S_ARRAY,  size },
16 static const struct {
17     const char *name;
18     enum { TYPE_SINGLE, TYPE_ARRAY,
19            TYPE_S_SINGLE, TYPE_S_ARRAY
20     } type;
21     unsigned int nr_elements;
22 } perfc_info[] = {
23 #include <xen/perfc_defn.h>
24 };
25 
26 #define NR_PERFCTRS (sizeof(perfc_info) / sizeof(perfc_info[0]))
27 
28 DEFINE_PER_CPU(perfc_t[NUM_PERFCOUNTERS], perfcounters);
29 
perfc_printall(unsigned char key)30 void cf_check perfc_printall(unsigned char key)
31 {
32     unsigned int i, j;
33     s_time_t now = NOW();
34 
35     printk("Xen performance counters SHOW  (now = %"PRI_stime")\n", now);
36 
37     for ( i = j = 0; i < NR_PERFCTRS; i++ )
38     {
39         unsigned int k, cpu;
40         unsigned long long sum = 0;
41 
42         printk("%-32s  ",  perfc_info[i].name);
43         switch ( perfc_info[i].type )
44         {
45         case TYPE_SINGLE:
46         case TYPE_S_SINGLE:
47             for_each_online_cpu ( cpu )
48                 sum += per_cpu(perfcounters, cpu)[j];
49             if ( perfc_info[i].type == TYPE_S_SINGLE )
50                 sum = (perfc_t) sum;
51             printk("TOTAL[%12Lu]", sum);
52             if ( sum )
53             {
54                 k = 0;
55                 for_each_online_cpu ( cpu )
56                 {
57                     if ( k > 0 && (k % 4) == 0 )
58                         printk("\n%53s", "");
59                     printk("  CPU%02u[%10u]", cpu, per_cpu(perfcounters, cpu)[j]);
60                     ++k;
61                 }
62             }
63             ++j;
64             break;
65         case TYPE_ARRAY:
66         case TYPE_S_ARRAY:
67             for_each_online_cpu ( cpu )
68             {
69                 perfc_t *counters = per_cpu(perfcounters, cpu) + j;
70 
71                 for ( k = 0; k < perfc_info[i].nr_elements; k++ )
72                     sum += counters[k];
73             }
74             if ( perfc_info[i].type == TYPE_S_ARRAY )
75                 sum = (perfc_t) sum;
76             printk("TOTAL[%12Lu]", sum);
77             if (sum)
78             {
79 #ifdef CONFIG_PERF_ARRAYS
80                 for ( k = 0; k < perfc_info[i].nr_elements; k++ )
81                 {
82                     sum = 0;
83                     for_each_online_cpu ( cpu )
84                         sum += per_cpu(perfcounters, cpu)[j + k];
85                     if ( perfc_info[i].type == TYPE_S_ARRAY )
86                         sum = (perfc_t) sum;
87                     if ( (k % 4) == 0 )
88                         printk("\n%16s", "");
89                     printk("  ARR%02u[%10Lu]", k, sum);
90                 }
91 #else
92                 k = 0;
93                 for_each_online_cpu ( cpu )
94                 {
95                     perfc_t *counters = per_cpu(perfcounters, cpu) + j;
96                     unsigned int n;
97 
98                     sum = 0;
99                     for ( n = 0; n < perfc_info[i].nr_elements; n++ )
100                         sum += counters[n];
101                     if ( perfc_info[i].type == TYPE_S_ARRAY )
102                         sum = (perfc_t) sum;
103                     if ( k > 0 && (k % 4) == 0 )
104                         printk("\n%53s", "");
105                     printk("  CPU%02u[%10Lu]", cpu, sum);
106                     ++k;
107                 }
108 #endif
109             }
110             j += perfc_info[i].nr_elements;
111             break;
112         }
113         printk("\n");
114     }
115 }
116 
perfc_reset(unsigned char key)117 void cf_check perfc_reset(unsigned char key)
118 {
119     unsigned int i, j;
120     s_time_t now = NOW();
121 
122     if ( key != '\0' )
123         printk("Xen performance counters RESET (now = %"PRI_stime")\n", now);
124 
125     /* leave STATUS counters alone -- don't reset */
126 
127     for ( i = j = 0; i < NR_PERFCTRS; i++ )
128     {
129         unsigned int cpu;
130 
131         switch ( perfc_info[i].type )
132         {
133         case TYPE_SINGLE:
134             for_each_online_cpu ( cpu )
135                 per_cpu(perfcounters, cpu)[j] = 0;
136             fallthrough;
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             fallthrough;
145         case TYPE_S_ARRAY:
146             j += perfc_info[i].nr_elements;
147             break;
148         }
149     }
150 }
151 
152 #ifdef CONFIG_SYSCTL
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     /* We gather the counts together every time. */
201     for ( i = j = v = 0; i < NR_PERFCTRS; i++ )
202     {
203         unsigned int cpu;
204 
205         switch ( perfc_info[i].type )
206         {
207         case TYPE_SINGLE:
208         case TYPE_S_SINGLE:
209             for_each_cpu ( cpu, &perfc_cpumap )
210                 perfc_vals[v++] = per_cpu(perfcounters, cpu)[j];
211             ++j;
212             break;
213         case TYPE_ARRAY:
214         case TYPE_S_ARRAY:
215             memset(perfc_vals + v, 0, perfc_d[i].nr_vals * sizeof(*perfc_vals));
216             for_each_cpu ( cpu, &perfc_cpumap )
217             {
218                 perfc_t *counters = per_cpu(perfcounters, cpu) + j;
219                 unsigned int k;
220 
221                 for ( k = 0; k < perfc_d[i].nr_vals; k++ )
222                     perfc_vals[v + k] += counters[k];
223             }
224             v += perfc_d[i].nr_vals;
225             j += perfc_info[i].nr_elements;
226             break;
227         }
228     }
229     BUG_ON(v != perfc_nbr_vals);
230 
231     if ( copy_to_guest(desc, perfc_d, NR_PERFCTRS) )
232         return -EFAULT;
233     if ( copy_to_guest(val, perfc_vals, perfc_nbr_vals) )
234         return -EFAULT;
235     return 0;
236 }
237 
238 /* Dom0 control of perf counters */
perfc_control(struct xen_sysctl_perfc_op * pc)239 int perfc_control(struct xen_sysctl_perfc_op *pc)
240 {
241     static DEFINE_SPINLOCK(lock);
242     int rc;
243 
244     spin_lock(&lock);
245 
246     switch ( pc->cmd )
247     {
248     case XEN_SYSCTL_PERFCOP_reset:
249         rc = perfc_copy_info(pc->desc, pc->val);
250         perfc_reset(0);
251         break;
252 
253     case XEN_SYSCTL_PERFCOP_query:
254         rc = perfc_copy_info(pc->desc, pc->val);
255         break;
256 
257     default:
258         rc = -EINVAL;
259         break;
260     }
261 
262     spin_unlock(&lock);
263 
264     pc->nr_counters = NR_PERFCTRS;
265     pc->nr_vals = perfc_nbr_vals;
266 
267     return rc;
268 }
269 #endif /* CONFIG_SYSCTL */
270 
271 /*
272  * Local variables:
273  * mode: C
274  * c-file-style: "BSD"
275  * c-basic-offset: 4
276  * tab-width: 4
277  * indent-tabs-mode: nil
278  * End:
279  */
280