aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/perf_counter.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/perf_counter.c')
-rw-r--r--kernel/perf_counter.c101
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
1768static void perf_output_simple(struct perf_counter *counter, 1768void 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
1824static 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
1861void 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/*