diff options
Diffstat (limited to 'kernel/perf_counter.c')
-rw-r--r-- | kernel/perf_counter.c | 101 |
1 files changed, 40 insertions, 61 deletions
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 860cdc26bd7a..995063df910f 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c | |||
@@ -1765,27 +1765,34 @@ static void perf_output_end(struct perf_output_handle *handle) | |||
1765 | rcu_read_unlock(); | 1765 | rcu_read_unlock(); |
1766 | } | 1766 | } |
1767 | 1767 | ||
1768 | static void perf_output_simple(struct perf_counter *counter, | 1768 | void perf_counter_output(struct perf_counter *counter, |
1769 | int nmi, struct pt_regs *regs) | 1769 | int nmi, struct pt_regs *regs) |
1770 | { | 1770 | { |
1771 | int ret; | 1771 | int ret; |
1772 | u64 record_type = counter->hw_event.record_type; | ||
1772 | struct perf_output_handle handle; | 1773 | struct perf_output_handle handle; |
1773 | struct perf_event_header header; | 1774 | struct perf_event_header header; |
1774 | u64 ip; | 1775 | u64 ip; |
1775 | struct { | 1776 | struct { |
1776 | u32 pid, tid; | 1777 | u32 pid, tid; |
1777 | } tid_entry; | 1778 | } tid_entry; |
1779 | struct { | ||
1780 | u64 event; | ||
1781 | u64 counter; | ||
1782 | } group_entry; | ||
1778 | struct perf_callchain_entry *callchain = NULL; | 1783 | struct perf_callchain_entry *callchain = NULL; |
1779 | int callchain_size = 0; | 1784 | int callchain_size = 0; |
1780 | 1785 | ||
1781 | header.type = PERF_EVENT_OVERFLOW; | 1786 | header.type = PERF_EVENT_COUNTER_OVERFLOW; |
1782 | header.size = sizeof(header); | 1787 | header.size = sizeof(header); |
1783 | 1788 | ||
1784 | ip = instruction_pointer(regs); | 1789 | if (record_type & PERF_RECORD_IP) { |
1785 | header.type |= __PERF_EVENT_IP; | 1790 | ip = instruction_pointer(regs); |
1786 | header.size += sizeof(ip); | 1791 | header.type |= __PERF_EVENT_IP; |
1792 | header.size += sizeof(ip); | ||
1793 | } | ||
1787 | 1794 | ||
1788 | if (counter->hw_event.include_tid) { | 1795 | if (record_type & PERF_RECORD_TID) { |
1789 | /* namespace issues */ | 1796 | /* namespace issues */ |
1790 | tid_entry.pid = current->group_leader->pid; | 1797 | tid_entry.pid = current->group_leader->pid; |
1791 | tid_entry.tid = current->pid; | 1798 | tid_entry.tid = current->pid; |
@@ -1794,7 +1801,13 @@ static void perf_output_simple(struct perf_counter *counter, | |||
1794 | header.size += sizeof(tid_entry); | 1801 | header.size += sizeof(tid_entry); |
1795 | } | 1802 | } |
1796 | 1803 | ||
1797 | if (counter->hw_event.callchain) { | 1804 | if (record_type & PERF_RECORD_GROUP) { |
1805 | header.type |= __PERF_EVENT_GROUP; | ||
1806 | header.size += sizeof(u64) + | ||
1807 | counter->nr_siblings * sizeof(group_entry); | ||
1808 | } | ||
1809 | |||
1810 | if (record_type & PERF_RECORD_CALLCHAIN) { | ||
1798 | callchain = perf_callchain(regs); | 1811 | callchain = perf_callchain(regs); |
1799 | 1812 | ||
1800 | if (callchain) { | 1813 | if (callchain) { |
@@ -1810,69 +1823,35 @@ static void perf_output_simple(struct perf_counter *counter, | |||
1810 | return; | 1823 | return; |
1811 | 1824 | ||
1812 | perf_output_put(&handle, header); | 1825 | perf_output_put(&handle, header); |
1813 | perf_output_put(&handle, ip); | ||
1814 | 1826 | ||
1815 | if (counter->hw_event.include_tid) | 1827 | if (record_type & PERF_RECORD_IP) |
1816 | perf_output_put(&handle, tid_entry); | 1828 | perf_output_put(&handle, ip); |
1817 | 1829 | ||
1818 | if (callchain) | 1830 | if (record_type & PERF_RECORD_TID) |
1819 | perf_output_copy(&handle, callchain, callchain_size); | 1831 | perf_output_put(&handle, tid_entry); |
1820 | |||
1821 | perf_output_end(&handle); | ||
1822 | } | ||
1823 | |||
1824 | static void perf_output_group(struct perf_counter *counter, int nmi) | ||
1825 | { | ||
1826 | struct perf_output_handle handle; | ||
1827 | struct perf_event_header header; | ||
1828 | struct perf_counter *leader, *sub; | ||
1829 | unsigned int size; | ||
1830 | struct { | ||
1831 | u64 event; | ||
1832 | u64 counter; | ||
1833 | } entry; | ||
1834 | int ret; | ||
1835 | |||
1836 | size = sizeof(header) + counter->nr_siblings * sizeof(entry); | ||
1837 | 1832 | ||
1838 | ret = perf_output_begin(&handle, counter, size, nmi); | 1833 | if (record_type & PERF_RECORD_GROUP) { |
1839 | if (ret) | 1834 | struct perf_counter *leader, *sub; |
1840 | return; | 1835 | u64 nr = counter->nr_siblings; |
1841 | 1836 | ||
1842 | header.type = PERF_EVENT_GROUP; | 1837 | perf_output_put(&handle, nr); |
1843 | header.size = size; | ||
1844 | 1838 | ||
1845 | perf_output_put(&handle, header); | 1839 | leader = counter->group_leader; |
1840 | list_for_each_entry(sub, &leader->sibling_list, list_entry) { | ||
1841 | if (sub != counter) | ||
1842 | sub->hw_ops->read(sub); | ||
1846 | 1843 | ||
1847 | leader = counter->group_leader; | 1844 | group_entry.event = sub->hw_event.config; |
1848 | list_for_each_entry(sub, &leader->sibling_list, list_entry) { | 1845 | group_entry.counter = atomic64_read(&sub->count); |
1849 | if (sub != counter) | ||
1850 | sub->hw_ops->read(sub); | ||
1851 | 1846 | ||
1852 | entry.event = sub->hw_event.config; | 1847 | perf_output_put(&handle, group_entry); |
1853 | entry.counter = atomic64_read(&sub->count); | 1848 | } |
1854 | |||
1855 | perf_output_put(&handle, entry); | ||
1856 | } | 1849 | } |
1857 | 1850 | ||
1858 | perf_output_end(&handle); | 1851 | if (callchain) |
1859 | } | 1852 | perf_output_copy(&handle, callchain, callchain_size); |
1860 | |||
1861 | void perf_counter_output(struct perf_counter *counter, | ||
1862 | int nmi, struct pt_regs *regs) | ||
1863 | { | ||
1864 | switch (counter->hw_event.record_type) { | ||
1865 | case PERF_RECORD_SIMPLE: | ||
1866 | return; | ||
1867 | |||
1868 | case PERF_RECORD_IRQ: | ||
1869 | perf_output_simple(counter, nmi, regs); | ||
1870 | break; | ||
1871 | 1853 | ||
1872 | case PERF_RECORD_GROUP: | 1854 | perf_output_end(&handle); |
1873 | perf_output_group(counter, nmi); | ||
1874 | break; | ||
1875 | } | ||
1876 | } | 1855 | } |
1877 | 1856 | ||
1878 | /* | 1857 | /* |