aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/perf_event.c
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2009-11-20 16:19:49 -0500
committerIngo Molnar <mingo@elte.hu>2009-11-21 08:11:37 -0500
commitabf4868b8548cae18d4fe8bbfb4e207443be01be (patch)
tree0a8900bb5413826bc1f3ac9ccc435c4750dfedab /kernel/perf_event.c
parentf6d9dd237da400effb265f3554c64413f8a3e7b4 (diff)
perf: Fix PERF_FORMAT_GROUP scale info
As Corey reported, the total_enabled and total_running times could occasionally be 0, even though there were events counted. It turns out this is because we record the times before reading the counter while the latter updates the times. This patch corrects that. While looking at this code I found that there is a lot of locking iffyness around, the following patches correct most of that. Reported-by: Corey Ashford <cjashfor@linux.vnet.ibm.com> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> LKML-Reference: <20091120212508.685559857@chello.nl> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/perf_event.c')
-rw-r--r--kernel/perf_event.c52
1 files changed, 21 insertions, 31 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index 68fbf4ff6888..9a18ff28ea5b 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -1784,30 +1784,15 @@ u64 perf_event_read_value(struct perf_event *event)
1784} 1784}
1785EXPORT_SYMBOL_GPL(perf_event_read_value); 1785EXPORT_SYMBOL_GPL(perf_event_read_value);
1786 1786
1787static int perf_event_read_entry(struct perf_event *event,
1788 u64 read_format, char __user *buf)
1789{
1790 int n = 0, count = 0;
1791 u64 values[2];
1792
1793 values[n++] = perf_event_read_value(event);
1794 if (read_format & PERF_FORMAT_ID)
1795 values[n++] = primary_event_id(event);
1796
1797 count = n * sizeof(u64);
1798
1799 if (copy_to_user(buf, values, count))
1800 return -EFAULT;
1801
1802 return count;
1803}
1804
1805static int perf_event_read_group(struct perf_event *event, 1787static int perf_event_read_group(struct perf_event *event,
1806 u64 read_format, char __user *buf) 1788 u64 read_format, char __user *buf)
1807{ 1789{
1808 struct perf_event *leader = event->group_leader, *sub; 1790 struct perf_event *leader = event->group_leader, *sub;
1809 int n = 0, size = 0, err = -EFAULT; 1791 int n = 0, size = 0, ret = 0;
1810 u64 values[3]; 1792 u64 values[5];
1793 u64 count;
1794
1795 count = perf_event_read_value(leader);
1811 1796
1812 values[n++] = 1 + leader->nr_siblings; 1797 values[n++] = 1 + leader->nr_siblings;
1813 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { 1798 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
@@ -1818,28 +1803,33 @@ static int perf_event_read_group(struct perf_event *event,
1818 values[n++] = leader->total_time_running + 1803 values[n++] = leader->total_time_running +
1819 atomic64_read(&leader->child_total_time_running); 1804 atomic64_read(&leader->child_total_time_running);
1820 } 1805 }
1806 values[n++] = count;
1807 if (read_format & PERF_FORMAT_ID)
1808 values[n++] = primary_event_id(leader);
1821 1809
1822 size = n * sizeof(u64); 1810 size = n * sizeof(u64);
1823 1811
1824 if (copy_to_user(buf, values, size)) 1812 if (copy_to_user(buf, values, size))
1825 return -EFAULT; 1813 return -EFAULT;
1826 1814
1827 err = perf_event_read_entry(leader, read_format, buf + size); 1815 ret += size;
1828 if (err < 0)
1829 return err;
1830
1831 size += err;
1832 1816
1833 list_for_each_entry(sub, &leader->sibling_list, group_entry) { 1817 list_for_each_entry(sub, &leader->sibling_list, group_entry) {
1834 err = perf_event_read_entry(sub, read_format, 1818 n = 0;
1835 buf + size);
1836 if (err < 0)
1837 return err;
1838 1819
1839 size += err; 1820 values[n++] = perf_event_read_value(sub);
1821 if (read_format & PERF_FORMAT_ID)
1822 values[n++] = primary_event_id(sub);
1823
1824 size = n * sizeof(u64);
1825
1826 if (copy_to_user(buf + size, values, size))
1827 return -EFAULT;
1828
1829 ret += size;
1840 } 1830 }
1841 1831
1842 return size; 1832 return ret;
1843} 1833}
1844 1834
1845static int perf_event_read_one(struct perf_event *event, 1835static int perf_event_read_one(struct perf_event *event,