[34] | 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 | |
---|
| 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%46s", ""); |
---|
| 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 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%46s", ""); |
---|
| 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 | arch_perfc_printall(); |
---|
| 119 | } |
---|
| 120 | |
---|
| 121 | void perfc_reset(unsigned char key) |
---|
| 122 | { |
---|
| 123 | unsigned int i, j; |
---|
| 124 | s_time_t now = NOW(); |
---|
| 125 | |
---|
| 126 | if ( key != '\0' ) |
---|
| 127 | printk("Xen performance counters RESET (now = 0x%08X:%08X)\n", |
---|
| 128 | (u32)(now>>32), (u32)now); |
---|
| 129 | |
---|
| 130 | /* leave STATUS counters alone -- don't reset */ |
---|
| 131 | |
---|
| 132 | for ( i = j = 0; i < NR_PERFCTRS; i++ ) |
---|
| 133 | { |
---|
| 134 | unsigned int cpu; |
---|
| 135 | |
---|
| 136 | switch ( perfc_info[i].type ) |
---|
| 137 | { |
---|
| 138 | case TYPE_SINGLE: |
---|
| 139 | for_each_cpu ( cpu ) |
---|
| 140 | per_cpu(perfcounters, cpu)[j] = 0; |
---|
| 141 | case TYPE_S_SINGLE: |
---|
| 142 | ++j; |
---|
| 143 | break; |
---|
| 144 | case TYPE_ARRAY: |
---|
| 145 | for_each_cpu ( cpu ) |
---|
| 146 | memset(per_cpu(perfcounters, cpu) + j, 0, |
---|
| 147 | perfc_info[i].nr_elements * sizeof(perfc_t)); |
---|
| 148 | case TYPE_S_ARRAY: |
---|
| 149 | j += perfc_info[i].nr_elements; |
---|
| 150 | break; |
---|
| 151 | } |
---|
| 152 | } |
---|
| 153 | |
---|
| 154 | arch_perfc_reset(); |
---|
| 155 | } |
---|
| 156 | |
---|
| 157 | static xen_sysctl_perfc_desc_t perfc_d[NR_PERFCTRS]; |
---|
| 158 | static xen_sysctl_perfc_val_t *perfc_vals; |
---|
| 159 | static unsigned int perfc_nbr_vals; |
---|
| 160 | static int perfc_init = 0; |
---|
| 161 | static int perfc_copy_info(XEN_GUEST_HANDLE_64(xen_sysctl_perfc_desc_t) desc, |
---|
| 162 | XEN_GUEST_HANDLE_64(xen_sysctl_perfc_val_t) val) |
---|
| 163 | { |
---|
| 164 | unsigned int i, j, v; |
---|
| 165 | |
---|
| 166 | /* We only copy the name and array-size information once. */ |
---|
| 167 | if ( !perfc_init ) |
---|
| 168 | { |
---|
| 169 | for ( i = 0; i < NR_PERFCTRS; i++ ) |
---|
| 170 | { |
---|
| 171 | safe_strcpy(perfc_d[i].name, perfc_info[i].name); |
---|
| 172 | |
---|
| 173 | switch ( perfc_info[i].type ) |
---|
| 174 | { |
---|
| 175 | case TYPE_SINGLE: |
---|
| 176 | case TYPE_S_SINGLE: |
---|
| 177 | perfc_d[i].nr_vals = num_possible_cpus(); |
---|
| 178 | break; |
---|
| 179 | case TYPE_ARRAY: |
---|
| 180 | case TYPE_S_ARRAY: |
---|
| 181 | perfc_d[i].nr_vals = perfc_info[i].nr_elements; |
---|
| 182 | break; |
---|
| 183 | } |
---|
| 184 | perfc_nbr_vals += perfc_d[i].nr_vals; |
---|
| 185 | } |
---|
| 186 | perfc_vals = xmalloc_array(xen_sysctl_perfc_val_t, perfc_nbr_vals); |
---|
| 187 | perfc_init = 1; |
---|
| 188 | } |
---|
| 189 | |
---|
| 190 | if ( guest_handle_is_null(desc) ) |
---|
| 191 | return 0; |
---|
| 192 | |
---|
| 193 | if ( perfc_vals == NULL ) |
---|
| 194 | return -ENOMEM; |
---|
| 195 | |
---|
| 196 | /* Architecture may fill counters from hardware. */ |
---|
| 197 | arch_perfc_gather(); |
---|
| 198 | |
---|
| 199 | /* We gather the counts together every time. */ |
---|
| 200 | for ( i = j = v = 0; i < NR_PERFCTRS; i++ ) |
---|
| 201 | { |
---|
| 202 | unsigned int cpu; |
---|
| 203 | |
---|
| 204 | switch ( perfc_info[i].type ) |
---|
| 205 | { |
---|
| 206 | case TYPE_SINGLE: |
---|
| 207 | case TYPE_S_SINGLE: |
---|
| 208 | for_each_cpu ( cpu ) |
---|
| 209 | perfc_vals[v++] = per_cpu(perfcounters, cpu)[j]; |
---|
| 210 | ++j; |
---|
| 211 | break; |
---|
| 212 | case TYPE_ARRAY: |
---|
| 213 | case TYPE_S_ARRAY: |
---|
| 214 | memset(perfc_vals + v, 0, perfc_d[i].nr_vals * sizeof(*perfc_vals)); |
---|
| 215 | for_each_cpu ( cpu ) |
---|
| 216 | { |
---|
| 217 | perfc_t *counters = per_cpu(perfcounters, cpu) + j; |
---|
| 218 | unsigned int k; |
---|
| 219 | |
---|
| 220 | for ( k = 0; k < perfc_d[i].nr_vals; k++ ) |
---|
| 221 | perfc_vals[v + k] += counters[k]; |
---|
| 222 | } |
---|
| 223 | v += perfc_d[i].nr_vals; |
---|
| 224 | j += perfc_info[i].nr_elements; |
---|
| 225 | break; |
---|
| 226 | } |
---|
| 227 | } |
---|
| 228 | BUG_ON(v != perfc_nbr_vals); |
---|
| 229 | |
---|
| 230 | if ( copy_to_guest(desc, (xen_sysctl_perfc_desc_t *)perfc_d, NR_PERFCTRS) ) |
---|
| 231 | return -EFAULT; |
---|
| 232 | if ( copy_to_guest(val, perfc_vals, perfc_nbr_vals) ) |
---|
| 233 | return -EFAULT; |
---|
| 234 | return 0; |
---|
| 235 | } |
---|
| 236 | |
---|
| 237 | /* Dom0 control of perf counters */ |
---|
| 238 | int perfc_control(xen_sysctl_perfc_op_t *pc) |
---|
| 239 | { |
---|
| 240 | static DEFINE_SPINLOCK(lock); |
---|
| 241 | int rc; |
---|
| 242 | |
---|
| 243 | spin_lock(&lock); |
---|
| 244 | |
---|
| 245 | switch ( pc->cmd ) |
---|
| 246 | { |
---|
| 247 | case XEN_SYSCTL_PERFCOP_reset: |
---|
| 248 | rc = perfc_copy_info(pc->desc, pc->val); |
---|
| 249 | perfc_reset(0); |
---|
| 250 | break; |
---|
| 251 | |
---|
| 252 | case XEN_SYSCTL_PERFCOP_query: |
---|
| 253 | rc = perfc_copy_info(pc->desc, pc->val); |
---|
| 254 | break; |
---|
| 255 | |
---|
| 256 | default: |
---|
| 257 | rc = -EINVAL; |
---|
| 258 | break; |
---|
| 259 | } |
---|
| 260 | |
---|
| 261 | spin_unlock(&lock); |
---|
| 262 | |
---|
| 263 | pc->nr_counters = NR_PERFCTRS; |
---|
| 264 | pc->nr_vals = perfc_nbr_vals; |
---|
| 265 | |
---|
| 266 | return rc; |
---|
| 267 | } |
---|
| 268 | |
---|
| 269 | /* |
---|
| 270 | * Local variables: |
---|
| 271 | * mode: C |
---|
| 272 | * c-set-style: "BSD" |
---|
| 273 | * c-basic-offset: 4 |
---|
| 274 | * tab-width: 4 |
---|
| 275 | * indent-tabs-mode: nil |
---|
| 276 | * End: |
---|
| 277 | */ |
---|