diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-11-20 16:19:55 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-11-21 08:11:40 -0500 |
commit | 59ed446f792cc07d37b1536b9c4664d14e25e425 (patch) | |
tree | 707c009e252b082ffac5c5209f4bdc013b1b5c62 /kernel/perf_event.c | |
parent | 2b8988c9f7defe319cffe0cd362a7cd356c86f62 (diff) |
perf: Fix event scaling for inherited counters
Properly account the full hierarchy of counters for both the
count (we already did so) and the scale times (new).
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <20091120212509.153379276@chello.nl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/perf_event.c')
-rw-r--r-- | kernel/perf_event.c | 48 |
1 files changed, 26 insertions, 22 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index fdfae888a67c..80f40da9a01e 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -1774,14 +1774,25 @@ static int perf_event_read_size(struct perf_event *event) | |||
1774 | return size; | 1774 | return size; |
1775 | } | 1775 | } |
1776 | 1776 | ||
1777 | u64 perf_event_read_value(struct perf_event *event) | 1777 | u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running) |
1778 | { | 1778 | { |
1779 | struct perf_event *child; | 1779 | struct perf_event *child; |
1780 | u64 total = 0; | 1780 | u64 total = 0; |
1781 | 1781 | ||
1782 | *enabled = 0; | ||
1783 | *running = 0; | ||
1784 | |||
1782 | total += perf_event_read(event); | 1785 | total += perf_event_read(event); |
1783 | list_for_each_entry(child, &event->child_list, child_list) | 1786 | *enabled += event->total_time_enabled + |
1787 | atomic64_read(&event->child_total_time_enabled); | ||
1788 | *running += event->total_time_running + | ||
1789 | atomic64_read(&event->child_total_time_running); | ||
1790 | |||
1791 | list_for_each_entry(child, &event->child_list, child_list) { | ||
1784 | total += perf_event_read(child); | 1792 | total += perf_event_read(child); |
1793 | *enabled += child->total_time_enabled; | ||
1794 | *running += child->total_time_running; | ||
1795 | } | ||
1785 | 1796 | ||
1786 | return total; | 1797 | return total; |
1787 | } | 1798 | } |
@@ -1793,19 +1804,15 @@ static int perf_event_read_group(struct perf_event *event, | |||
1793 | struct perf_event *leader = event->group_leader, *sub; | 1804 | struct perf_event *leader = event->group_leader, *sub; |
1794 | int n = 0, size = 0, ret = 0; | 1805 | int n = 0, size = 0, ret = 0; |
1795 | u64 values[5]; | 1806 | u64 values[5]; |
1796 | u64 count; | 1807 | u64 count, enabled, running; |
1797 | 1808 | ||
1798 | count = perf_event_read_value(leader); | 1809 | count = perf_event_read_value(leader, &enabled, &running); |
1799 | 1810 | ||
1800 | values[n++] = 1 + leader->nr_siblings; | 1811 | values[n++] = 1 + leader->nr_siblings; |
1801 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { | 1812 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) |
1802 | values[n++] = leader->total_time_enabled + | 1813 | values[n++] = enabled; |
1803 | atomic64_read(&leader->child_total_time_enabled); | 1814 | if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) |
1804 | } | 1815 | values[n++] = running; |
1805 | if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { | ||
1806 | values[n++] = leader->total_time_running + | ||
1807 | atomic64_read(&leader->child_total_time_running); | ||
1808 | } | ||
1809 | values[n++] = count; | 1816 | values[n++] = count; |
1810 | if (read_format & PERF_FORMAT_ID) | 1817 | if (read_format & PERF_FORMAT_ID) |
1811 | values[n++] = primary_event_id(leader); | 1818 | values[n++] = primary_event_id(leader); |
@@ -1820,7 +1827,7 @@ static int perf_event_read_group(struct perf_event *event, | |||
1820 | list_for_each_entry(sub, &leader->sibling_list, group_entry) { | 1827 | list_for_each_entry(sub, &leader->sibling_list, group_entry) { |
1821 | n = 0; | 1828 | n = 0; |
1822 | 1829 | ||
1823 | values[n++] = perf_event_read_value(sub); | 1830 | values[n++] = perf_event_read_value(sub, &enabled, &running); |
1824 | if (read_format & PERF_FORMAT_ID) | 1831 | if (read_format & PERF_FORMAT_ID) |
1825 | values[n++] = primary_event_id(sub); | 1832 | values[n++] = primary_event_id(sub); |
1826 | 1833 | ||
@@ -1838,18 +1845,15 @@ static int perf_event_read_group(struct perf_event *event, | |||
1838 | static int perf_event_read_one(struct perf_event *event, | 1845 | static int perf_event_read_one(struct perf_event *event, |
1839 | u64 read_format, char __user *buf) | 1846 | u64 read_format, char __user *buf) |
1840 | { | 1847 | { |
1848 | u64 enabled, running; | ||
1841 | u64 values[4]; | 1849 | u64 values[4]; |
1842 | int n = 0; | 1850 | int n = 0; |
1843 | 1851 | ||
1844 | values[n++] = perf_event_read_value(event); | 1852 | values[n++] = perf_event_read_value(event, &enabled, &running); |
1845 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { | 1853 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) |
1846 | values[n++] = event->total_time_enabled + | 1854 | values[n++] = enabled; |
1847 | atomic64_read(&event->child_total_time_enabled); | 1855 | if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) |
1848 | } | 1856 | values[n++] = running; |
1849 | if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { | ||
1850 | values[n++] = event->total_time_running + | ||
1851 | atomic64_read(&event->child_total_time_running); | ||
1852 | } | ||
1853 | if (read_format & PERF_FORMAT_ID) | 1857 | if (read_format & PERF_FORMAT_ID) |
1854 | values[n++] = primary_event_id(event); | 1858 | values[n++] = primary_event_id(event); |
1855 | 1859 | ||