diff options
-rw-r--r-- | include/linux/perf_counter.h | 10 | ||||
-rw-r--r-- | kernel/perf_counter.c | 104 |
2 files changed, 65 insertions, 49 deletions
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h index 00081d84169f..88f863ec2748 100644 --- a/include/linux/perf_counter.h +++ b/include/linux/perf_counter.h | |||
@@ -157,10 +157,14 @@ struct perf_counter_hw_event { | |||
157 | /* | 157 | /* |
158 | * Ioctls that can be done on a perf counter fd: | 158 | * Ioctls that can be done on a perf counter fd: |
159 | */ | 159 | */ |
160 | #define PERF_COUNTER_IOC_ENABLE _IO ('$', 0) | 160 | #define PERF_COUNTER_IOC_ENABLE _IOW('$', 0, u32) |
161 | #define PERF_COUNTER_IOC_DISABLE _IO ('$', 1) | 161 | #define PERF_COUNTER_IOC_DISABLE _IOW('$', 1, u32) |
162 | #define PERF_COUNTER_IOC_REFRESH _IOW('$', 2, u32) | 162 | #define PERF_COUNTER_IOC_REFRESH _IOW('$', 2, u32) |
163 | #define PERF_COUNTER_IOC_RESET _IO ('$', 3) | 163 | #define PERF_COUNTER_IOC_RESET _IOW('$', 3, u32) |
164 | |||
165 | enum perf_counter_ioc_flags { | ||
166 | PERF_IOC_FLAG_GROUP = 1U << 0, | ||
167 | }; | ||
164 | 168 | ||
165 | /* | 169 | /* |
166 | * Structure of the page that can be mapped via mmap | 170 | * Structure of the page that can be mapped via mmap |
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index fdb0d2421276..f4883f1f47eb 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c | |||
@@ -82,7 +82,7 @@ list_add_counter(struct perf_counter *counter, struct perf_counter_context *ctx) | |||
82 | * add it straight to the context's counter list, or to the group | 82 | * add it straight to the context's counter list, or to the group |
83 | * leader's sibling list: | 83 | * leader's sibling list: |
84 | */ | 84 | */ |
85 | if (counter->group_leader == counter) | 85 | if (group_leader == counter) |
86 | list_add_tail(&counter->list_entry, &ctx->counter_list); | 86 | list_add_tail(&counter->list_entry, &ctx->counter_list); |
87 | else { | 87 | else { |
88 | list_add_tail(&counter->list_entry, &group_leader->sibling_list); | 88 | list_add_tail(&counter->list_entry, &group_leader->sibling_list); |
@@ -385,24 +385,6 @@ static void perf_counter_disable(struct perf_counter *counter) | |||
385 | spin_unlock_irq(&ctx->lock); | 385 | spin_unlock_irq(&ctx->lock); |
386 | } | 386 | } |
387 | 387 | ||
388 | /* | ||
389 | * Disable a counter and all its children. | ||
390 | */ | ||
391 | static void perf_counter_disable_family(struct perf_counter *counter) | ||
392 | { | ||
393 | struct perf_counter *child; | ||
394 | |||
395 | perf_counter_disable(counter); | ||
396 | |||
397 | /* | ||
398 | * Lock the mutex to protect the list of children | ||
399 | */ | ||
400 | mutex_lock(&counter->mutex); | ||
401 | list_for_each_entry(child, &counter->child_list, child_list) | ||
402 | perf_counter_disable(child); | ||
403 | mutex_unlock(&counter->mutex); | ||
404 | } | ||
405 | |||
406 | static int | 388 | static int |
407 | counter_sched_in(struct perf_counter *counter, | 389 | counter_sched_in(struct perf_counter *counter, |
408 | struct perf_cpu_context *cpuctx, | 390 | struct perf_cpu_context *cpuctx, |
@@ -753,24 +735,6 @@ static int perf_counter_refresh(struct perf_counter *counter, int refresh) | |||
753 | return 0; | 735 | return 0; |
754 | } | 736 | } |
755 | 737 | ||
756 | /* | ||
757 | * Enable a counter and all its children. | ||
758 | */ | ||
759 | static void perf_counter_enable_family(struct perf_counter *counter) | ||
760 | { | ||
761 | struct perf_counter *child; | ||
762 | |||
763 | perf_counter_enable(counter); | ||
764 | |||
765 | /* | ||
766 | * Lock the mutex to protect the list of children | ||
767 | */ | ||
768 | mutex_lock(&counter->mutex); | ||
769 | list_for_each_entry(child, &counter->child_list, child_list) | ||
770 | perf_counter_enable(child); | ||
771 | mutex_unlock(&counter->mutex); | ||
772 | } | ||
773 | |||
774 | void __perf_counter_sched_out(struct perf_counter_context *ctx, | 738 | void __perf_counter_sched_out(struct perf_counter_context *ctx, |
775 | struct perf_cpu_context *cpuctx) | 739 | struct perf_cpu_context *cpuctx) |
776 | { | 740 | { |
@@ -1307,31 +1271,79 @@ static unsigned int perf_poll(struct file *file, poll_table *wait) | |||
1307 | 1271 | ||
1308 | static void perf_counter_reset(struct perf_counter *counter) | 1272 | static void perf_counter_reset(struct perf_counter *counter) |
1309 | { | 1273 | { |
1274 | (void)perf_counter_read(counter); | ||
1310 | atomic_set(&counter->count, 0); | 1275 | atomic_set(&counter->count, 0); |
1276 | perf_counter_update_userpage(counter); | ||
1277 | } | ||
1278 | |||
1279 | static void perf_counter_for_each_sibling(struct perf_counter *counter, | ||
1280 | void (*func)(struct perf_counter *)) | ||
1281 | { | ||
1282 | struct perf_counter_context *ctx = counter->ctx; | ||
1283 | struct perf_counter *sibling; | ||
1284 | |||
1285 | spin_lock_irq(&ctx->lock); | ||
1286 | counter = counter->group_leader; | ||
1287 | |||
1288 | func(counter); | ||
1289 | list_for_each_entry(sibling, &counter->sibling_list, list_entry) | ||
1290 | func(sibling); | ||
1291 | spin_unlock_irq(&ctx->lock); | ||
1292 | } | ||
1293 | |||
1294 | static void perf_counter_for_each_child(struct perf_counter *counter, | ||
1295 | void (*func)(struct perf_counter *)) | ||
1296 | { | ||
1297 | struct perf_counter *child; | ||
1298 | |||
1299 | mutex_lock(&counter->mutex); | ||
1300 | func(counter); | ||
1301 | list_for_each_entry(child, &counter->child_list, child_list) | ||
1302 | func(child); | ||
1303 | mutex_unlock(&counter->mutex); | ||
1304 | } | ||
1305 | |||
1306 | static void perf_counter_for_each(struct perf_counter *counter, | ||
1307 | void (*func)(struct perf_counter *)) | ||
1308 | { | ||
1309 | struct perf_counter *child; | ||
1310 | |||
1311 | mutex_lock(&counter->mutex); | ||
1312 | perf_counter_for_each_sibling(counter, func); | ||
1313 | list_for_each_entry(child, &counter->child_list, child_list) | ||
1314 | perf_counter_for_each_sibling(child, func); | ||
1315 | mutex_unlock(&counter->mutex); | ||
1311 | } | 1316 | } |
1312 | 1317 | ||
1313 | static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 1318 | static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
1314 | { | 1319 | { |
1315 | struct perf_counter *counter = file->private_data; | 1320 | struct perf_counter *counter = file->private_data; |
1316 | int err = 0; | 1321 | void (*func)(struct perf_counter *); |
1322 | u32 flags = arg; | ||
1317 | 1323 | ||
1318 | switch (cmd) { | 1324 | switch (cmd) { |
1319 | case PERF_COUNTER_IOC_ENABLE: | 1325 | case PERF_COUNTER_IOC_ENABLE: |
1320 | perf_counter_enable_family(counter); | 1326 | func = perf_counter_enable; |
1321 | break; | 1327 | break; |
1322 | case PERF_COUNTER_IOC_DISABLE: | 1328 | case PERF_COUNTER_IOC_DISABLE: |
1323 | perf_counter_disable_family(counter); | 1329 | func = perf_counter_disable; |
1324 | break; | ||
1325 | case PERF_COUNTER_IOC_REFRESH: | ||
1326 | err = perf_counter_refresh(counter, arg); | ||
1327 | break; | 1330 | break; |
1328 | case PERF_COUNTER_IOC_RESET: | 1331 | case PERF_COUNTER_IOC_RESET: |
1329 | perf_counter_reset(counter); | 1332 | func = perf_counter_reset; |
1330 | break; | 1333 | break; |
1334 | |||
1335 | case PERF_COUNTER_IOC_REFRESH: | ||
1336 | return perf_counter_refresh(counter, arg); | ||
1331 | default: | 1337 | default: |
1332 | err = -ENOTTY; | 1338 | return -ENOTTY; |
1333 | } | 1339 | } |
1334 | return err; | 1340 | |
1341 | if (flags & PERF_IOC_FLAG_GROUP) | ||
1342 | perf_counter_for_each(counter, func); | ||
1343 | else | ||
1344 | perf_counter_for_each_child(counter, func); | ||
1345 | |||
1346 | return 0; | ||
1335 | } | 1347 | } |
1336 | 1348 | ||
1337 | /* | 1349 | /* |