History

perf/core: Add PERF_SAMPLE_DATA_PAGE_SIZE

Current perf can report both virtual addresses and physical addresses, but not the MMU page size. Without the MMU page size information of the utilized page, users cannot decide whether to promote/demote large pages to optimize memory usage. Add a new sample type for the data MMU page size. Current perf already has a facility to collect data virtual addresses. A page walker is required to walk the pages tables and calculate the MMU page size from a given virtual address. On some platforms, e.g., X86, the page walker is invoked in an NMI handler. So the page walker must be NMI-safe and low overhead. Besides, the page walker should work for both user and kernel virtual address. The existing generic page walker, e.g., walk_page_range_novma(), is a little bit complex and doesn't guarantee the NMI-safe. The follow_page() is only for user-virtual address. Add a new function perf_get_page_size() to walk the page tables and calculate the MMU page size. In the function: - Interrupts have to be disabled to prevent any teardown of the page tables. - For user space threads, the current->mm is used for the page walker. For kernel threads and the like, the current->mm is NULL. The init_mm is used for the page walker. The active_mm is not used here, because it can be NULL. Quote from Peter Zijlstra, "context_switch() can set prev->active_mm to NULL when it transfers it to @next. It does this before @current is updated. So an NMI that comes in between this active_mm swizzling and updating @current will see !active_mm." - The MMU page size is calculated from the page table level. The method should work for all architectures, but it has only been verified on X86. Should there be some architectures, which support perf, where the method doesn't work, it can be fixed later separately. Reporting the wrong page size would not be fatal for the architecture. Some under discussion features may impact the method in the future. Quote from Dave Hansen, "There are lots of weird things folks are trying to do with the page tables, like Address Space Isolation. For instance, if you get a perf NMI when running userspace, current->mm->pgd is *different* than the PGD that was in use when userspace was running. It's close enough today, but it might not stay that way." If the case happens later, lots of consecutive page walk errors will happen. The worst case is that lots of page-size '0' are returned, which would not be fatal. In the perf tool, a check is implemented to detect this case. Once it happens, a kernel patch could be implemented accordingly then.

Kan Liang committed 6 years ago

Commit 8d97e711 parent f91072e3 files · +107 −1Browse files

Showing the changes to include/uapi/linux (1 of 3 files). Show all

Unified · Split

include/uapi/linux/perf_event.h+3−1
@@ -143,8 +143,9 @@ enum perf_event_sample_format { · 142 unmodified lines
143 PERF_SAMPLE_PHYS_ADDR = 1U << 19,143 PERF_SAMPLE_PHYS_ADDR = 1U << 19,
144 PERF_SAMPLE_AUX = 1U << 20,144 PERF_SAMPLE_AUX = 1U << 20,
145 PERF_SAMPLE_CGROUP = 1U << 21,145 PERF_SAMPLE_CGROUP = 1U << 21,
146 PERF_SAMPLE_DATA_PAGE_SIZE = 1U << 22,
146 147
147 PERF_SAMPLE_MAX = 1U << 22, /* non-ABI */148 PERF_SAMPLE_MAX = 1U << 23, /* non-ABI */
148 149
149 __PERF_SAMPLE_CALLCHAIN_EARLY = 1ULL << 63, /* non-ABI; internal use */150 __PERF_SAMPLE_CALLCHAIN_EARLY = 1ULL << 63, /* non-ABI; internal use */
150};151};
@@ -896,6 +897,7 @@ enum perf_event_type { · 745 unmodified lines
896 * { u64 phys_addr;} && PERF_SAMPLE_PHYS_ADDR897 * { u64 phys_addr;} && PERF_SAMPLE_PHYS_ADDR
897 * { u64 size;898 * { u64 size;
898 * char data[size]; } && PERF_SAMPLE_AUX899 * char data[size]; } && PERF_SAMPLE_AUX
900 * { u64 data_page_size;} && PERF_SAMPLE_DATA_PAGE_SIZE
899 * };901 * };
900 */902 */
901 PERF_RECORD_SAMPLE = 9,903 PERF_RECORD_SAMPLE = 9,