perf/core improvements and fixes
Arnaldo Carvalho de Melo
maintainerFrom: Arnaldo Carvalho de Melo <[email protected]>
Hi Ingo,
Please consider pulling,
- Arnaldo
The following changes since commit 0bd106d26dbe444160104b3153ca1652d2ab913b:
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent (2016-01-12 11:01:16 +0100)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git tags/perf-core-for-mingo
for you to fetch changes up to 34b7b0f95d41d2351a080e774d71085171db90e6:
perf tools: Fallback to srcdir/Documentation/tips.txt (2016-01-12 12:42:08 -0300)
----------------------------------------------------------------
perf/core improvements and fixes:
User visible new features:
- Add --buildid-all option to 'perf record' to avoid processing samples, just collecting build-ids for _all_ the DSOs that appears in PERF_RECORD_MMAP records (Namhyung Kim)
- Add some more usage tips to appear in the hists browser (top & report) (Namhyung Kim, Andi Kleen)
- Fix mmap2 event allocation in synthesize code, where we were allocating space just for PERF_RECORD_MMAP, the older variant, which could lead to corner case problems (Wang Nan)
Developer stuff:
- Make list.h self-sufficient, removing one more reference to kernel headers that lead to recent breakage when some rculist change was made in the kernel sources. (Josh Poimboeuf)
Add missing NORETURN define for parse-options.h in tools/lib/subcmd (Josh Poimboeuf)
- Fallback to srcdir/Documentation/ when not finding tips.txt elsewhere (Namhyung Kim)
----------------------------------------------------------------
Jiri Olsa (1):
perf stat: Fix recort_usage typo
Josh Poimboeuf (3):
tools: Make list.h self-sufficient
tools: Fix formatting of the "make -C tools" help message tools subcmd: Add missing NORETURN define for parse-options.h
Namhyung Kim (6):
perf record: Add --buildid-all option
perf tools: Add more usage tips
perf tools: Add file_only config option to strlist perf tools: Set and pass DOCDIR to builtin-report.c perf ui/tui: Print helpline message as is perf tools: Fallback to srcdir/Documentation/tips.txt
Wang Nan (1):
perf tools: Fix mmap2 event allocation in synthesize code
tools/Makefile | 32 +- tools/include/linux/list.h | 753 ++++++++++++++++++++++++++++++- tools/lib/subcmd/parse-options.h | 4 + tools/perf/Build | 1 + tools/perf/Documentation/perf-record.txt | 3 + tools/perf/Documentation/tips.txt | 15 + tools/perf/builtin-record.c | 26 +- tools/perf/builtin-report.c | 10 +- tools/perf/builtin-stat.c | 8 +- tools/perf/config/Makefile | 3 + tools/perf/ui/browsers/hists.c | 2 +- tools/perf/util/event.c | 4 +- tools/perf/util/strlist.c | 8 + tools/perf/util/strlist.h | 9 +- tools/perf/util/util.c | 11 +- 15 files changed, 847 insertions(+), 42 deletions(-)
Arnaldo Carvalho de Melo
maintainerPATCH 1/11 perf stat: Fix recort_usage typo
From: Jiri Olsa <[email protected]>
Markus reported gcc 6 complains when compiling perf stat command:
builtin-stat.c:1591:27: error: ‘recort_usage’ defined but not used [-Werror=unused-const-variable]
static const char * const recort_usage[] = {
^~~~~~~~~~~~I fixed the typo and realized we already export record_usage, so I also prefixed it with stat (and included report_usage).
--- tools/perf/builtin-stat.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
tools/perf/builtin-stat.c +4 -4
@@ -1588,7 +1588,7 @@ static int add_default_attributes(void)return perf_evlist__add_default_attrs (evsel_list, very_very_detailed_attrs); } -static const char *const recort_usage[] = { +static const char *const stat_record_usage[] = {"perf stat record [<options>]" ,NULL , };
@@ -1611,7 +1611,7 @@ static int __cmd_record(int argc, const char **argv)struct perf_session *session;struct perf_data_file *file = &perf_stat.file; - argc =parse_options (argc, argv, stat_options, record_usage, + argc =parse_options (argc, argv, stat_options, stat_record_usage,PARSE_OPT_STOP_AT_NON_OPTION );if (output_name)
@@ -1745,7 +1745,7 @@ int process_cpu_map_event(struct perf_tool *tool __maybe_unused,return set_maps (st); } -static const char *const report_usage[] = { +static const char *const stat_report_usage[] = {"perf stat report [<options>]" ,NULL , };
@@ -1779,7 +1779,7 @@ static int __cmd_report(int argc, const char **argv)struct stat st;int ret; - argc =parse_options (argc, argv, options, report_usage,0 ); + argc =parse_options (argc, argv, options, stat_report_usage,0 );if (!input_name || !strlen (input_name)) {if (!fstat (STDIN_FILENO , &st) &&S_ISFIFO (st.st_mode))
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 2/11 perf tools: Fix mmap2 event allocation in synthesize code
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
perf_event__synthesize_mmap_events() issues mmap2 events, but the memory of that event is allocated using:
mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size);
If path of mmap source file is long (near PATH_MAX), random crash would happen. Should use sizeof(mmap_event->mmap2).
Fix two memory allocations.
--- tools/perf/util/event.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
tools/perf/util/event.c +2 -2
@@ -503,7 +503,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,if (comm_event ==NULL ) goto out; - mmap_event =malloc (sizeof (mmap_event->mmap) + machine->id_hdr_size); + mmap_event =malloc (sizeof (mmap_event->mmap2) + machine->id_hdr_size);if (mmap_event ==NULL ) goto out_free_comm;
@@ -577,7 +577,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,if (comm_event ==NULL ) goto out; - mmap_event =malloc (sizeof (mmap_event->mmap) + machine->id_hdr_size); + mmap_event =malloc (sizeof (mmap_event->mmap2) + machine->id_hdr_size);if (mmap_event ==NULL ) goto out_free_comm;
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 3/11 tools: Make list.h self-sufficient
In reply to Arnaldo Carvalho de MeloFrom: Josh Poimboeuf <[email protected]>
Commit 7f5f873c6a07 ("rculist: Use WRITE_ONCE() when deleting from reader-visible list") added the use of the WRITE_ONCE macro to the kernel version of list.h, which broke the stacktool build because the tools list.h includes the kernel list.h.
Avoid this type of situation in the future and make list.h self-sufficient by copying the kernel list.h routines directly into tools list.h.
This is a straight copy except for adjustments to the include statements and copying of the tools-specific list routines (list_del_range and list_for_each_from).
--- tools/include/linux/list.h | 753 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 747 insertions(+), 6 deletions(-)
tools/include/linux/list.h +747 -6
@@ -1,11 +1,751 @@ -#include <linux/compiler.h> -#include <linux/kernel.h> +#ifndef __TOOLS_LINUX_LIST_H +#define __TOOLS_LINUX_LIST_H +#include <linux/types.h> +#include <linux/poison.h> +#include <linux/kernel.h> +#include <linux/compiler.h> + +/* +* Simple doubly linked list implementation. +* +* Some of the internal functions ("__xxx") are useful when +* manipulating whole lists rather than single entries, as +* sometimes we already know the next/prev entries and we can +* generate better code by using them directly rather than +* using the generic single-entry routines. +*/ + +#define LIST_HEAD_INIT (name) { &(name), &(name) } + +#define LIST_HEAD (name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD (struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* +* Insert a new entry between two known consecutive entries. +* +* This is only for internal list manipulation where we know +* the prev/next entries already! +*/ +#ifndef CONFIG_DEBUG_LIST +static inline void __list_add (struct list_head *new, +struct list_head *prev, +struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} +#else +extern void __list_add (struct list_head *new, +struct list_head *prev, +struct list_head *next); +#endif + +/** +* list_add - add a new entry +* @new: new entry to be added +* @head: list head to add it after +* +* Insert a new entry after the specified head. +* This is good for implementing stacks. +*/ +static inline void list_add (struct list_head *new,struct list_head *head) +{ +__list_add (new, head, head->next); +} + + +/** +* list_add_tail - add a new entry +* @new: new entry to be added +* @head: list head to add it before +* +* Insert a new entry before the specified head. +* This is useful for implementing queues. +*/ +static inline void list_add_tail (struct list_head *new,struct list_head *head) +{ +__list_add (new, head->prev, head); +} + +/* +* Delete a list entry by making the prev/next entries +* point to each other. +* +* This is only for internal list manipulation where we know +* the prev/next entries already! +*/ +static inline void __list_del (struct list_head * prev,struct list_head * next) +{ + next->prev = prev; +WRITE_ONCE (prev->next, next); +} + +/** +* list_del - deletes entry from list. +* @entry: the element to delete from the list. +* Note: list_empty() on entry does not return true after this, the entry is +* in an undefined state. +*/ +#ifndef CONFIG_DEBUG_LIST +static inline void __list_del_entry (struct list_head *entry) +{ +__list_del (entry->prev, entry->next); +} + +static inline void list_del (struct list_head *entry) +{ +__list_del (entry->prev, entry->next); + entry->next =LIST_POISON1 ; + entry->prev =LIST_POISON2 ; +} +#else +extern void __list_del_entry (struct list_head *entry); +extern void list_del (struct list_head *entry); +#endif + +/** +* list_replace - replace old entry by new one +* @old : the element to be replaced +* @new : the new element to insert +* +* If @old was empty, it will be overwritten. +*/ +static inline void list_replace (struct list_head *old, +struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init (struct list_head *old, +struct list_head *new) +{ +list_replace (old, new); +INIT_LIST_HEAD (old); +} + +/** +* list_del_init - deletes entry from list and reinitialize it. +* @entry: the element to delete from the list. +*/ +static inline void list_del_init (struct list_head *entry) +{ +__list_del_entry (entry); +INIT_LIST_HEAD (entry); +} + +/** +* list_move - delete from one list and add as another's head +* @list: the entry to move +* @head: the head that will precede our entry +*/ +static inline void list_move (struct list_head *list,struct list_head *head) +{ +__list_del_entry (list); +list_add (list, head); +} + +/** +* list_move_tail - delete from one list and add as another's tail +* @list: the entry to move +* @head: the head that will follow our entry +*/ +static inline void list_move_tail (struct list_head *list, +struct list_head *head) +{ +__list_del_entry (list); +list_add_tail (list, head); +} + +/** +* list_is_last - tests whether @list is the last entry in list @head +* @list: the entry to test +* @head: the head of the list +*/ +static inline int list_is_last (const struct list_head *list, +const struct list_head *head) +{ +return list->next == head; +} + +/** +* list_empty - tests whether a list is empty +* @head: the list to test. +*/ +static inline int list_empty (const struct list_head *head) +{ +return head->next == head; +} + +/** +* list_empty_careful - tests whether a list is empty and not being modified +* @head: the list to test +* +* Description: +* tests whether a list is empty _and_ checks that no other CPU might be +* in the process of modifying either member (next or prev) +* +* NOTE: using list_empty_careful() without synchronization +* can only be safe if the only activity that can happen +* to the list entry is list_del_init(). Eg. it cannot be used +* if another CPU could re-list_add() it. +*/ +static inline int list_empty_careful (const struct list_head *head) +{ +struct list_head *next = head->next; +return (next == head) && (next == head->prev); +} + +/** +* list_rotate_left - rotate the list to the left +* @head: the head of the list +*/ +static inline void list_rotate_left (struct list_head *head) +{ +struct list_head *first; + +if (!list_empty (head)) { + first = head->next; +list_move_tail (first, head); + } +} + +/** +* list_is_singular - tests whether a list has just one entry. +* @head: the list to test. +*/ +static inline int list_is_singular (const struct list_head *head) +{ +return !list_empty (head) && (head->next == head->prev); +} + +static inline void __list_cut_position (struct list_head *list, +struct list_head *head,struct list_head *entry) +{ +struct list_head *new_first = entry->next; + list->next = head->next; + list->next->prev = list; + list->prev = entry; + entry->next = list; + head->next = new_first; + new_first->prev = head; +} + +/** +* list_cut_position - cut a list into two +* @list: a new list to add all removed entries +* @head: a list with entries +* @entry: an entry within head, could be the head itself +* and if so we won't cut the list +* +* This helper moves the initial part of @head, up to and +* including @entry, from @head to @list. You should +* pass on @entry an element you know is on @head. @list +* should be an empty list or a list you do not care about +* losing its data. +* +*/ +static inline void list_cut_position (struct list_head *list, +struct list_head *head,struct list_head *entry) +{ +if (list_empty (head)) +return ; +if (list_is_singular (head) && + (head->next != entry && head != entry)) +return ; +if (entry == head) +INIT_LIST_HEAD (list); +else +__list_cut_position (list, head, entry); +} + +static inline void __list_splice (const struct list_head *list, +struct list_head *prev, +struct list_head *next) +{ +struct list_head *first = list->next; +struct list_head *last = list->prev; + + first->prev = prev; + prev->next = first; + + last->next = next; + next->prev = last; +} + +/** +* list_splice - join two lists, this is designed for stacks +* @list: the new list to add. +* @head: the place to add it in the first list. +*/ +static inline void list_splice (const struct list_head *list, +struct list_head *head) +{ +if (!list_empty (list)) +__list_splice (list, head, head->next); +} + +/** +* list_splice_tail - join two lists, each list being a queue +* @list: the new list to add. +* @head: the place to add it in the first list. +*/ +static inline void list_splice_tail (struct list_head *list, +struct list_head *head) +{ +if (!list_empty (list)) +__list_splice (list, head->prev, head); +} + +/** +* list_splice_init - join two lists and reinitialise the emptied list. +* @list: the new list to add. +* @head: the place to add it in the first list. +* +* The list at @list is reinitialised +*/ +static inline void list_splice_init (struct list_head *list, +struct list_head *head) +{ +if (!list_empty (list)) { +__list_splice (list, head, head->next); +INIT_LIST_HEAD (list); + } +} + +/** +* list_splice_tail_init - join two lists and reinitialise the emptied list +* @list: the new list to add. +* @head: the place to add it in the first list. +* +* Each of the lists is a queue. +* The list at @list is reinitialised +*/ +static inline void list_splice_tail_init (struct list_head *list, +struct list_head *head) +{ +if (!list_empty (list)) { +__list_splice (list, head->prev, head); +INIT_LIST_HEAD (list); + } +} + +/** +* list_entry - get the struct for this entry +* @ptr: the &struct list_head pointer. +* @type: the type of the struct this is embedded in. +* @member: the name of the list_head within the struct. +*/ +#define list_entry (ptr, type, member) \ + container_of(ptr, type, member) + +/** +* list_first_entry - get the first element from a list +* @ptr: the list head to take the element from. +* @type: the type of the struct this is embedded in. +* @member: the name of the list_head within the struct. +* +* Note, that list is expected to be not empty. +*/ +#define list_first_entry (ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** +* list_last_entry - get the last element from a list +* @ptr: the list head to take the element from. +* @type: the type of the struct this is embedded in. +* @member: the name of the list_head within the struct. +* +* Note, that list is expected to be not empty. +*/ +#define list_last_entry (ptr, type, member) \ + list_entry((ptr)->prev, type, member) + +/** +* list_first_entry_or_null - get the first element from a list +* @ptr: the list head to take the element from. +* @type: the type of the struct this is embedded in. +* @member: the name of the list_head within the struct. +* +* Note that if the list is empty, it returns NULL. +*/ +#define list_first_entry_or_null (ptr, type, member) \ + (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL) + +/** +* list_next_entry - get the next element in list +* @pos: the type * to cursor +* @member: the name of the list_head within the struct. +*/ +#define list_next_entry (pos, member) \ + list_entry((pos)->member.next, typeof(*(pos)), member) + +/** +* list_prev_entry - get the prev element in list +* @pos: the type * to cursor +* @member: the name of the list_head within the struct. +*/ +#define list_prev_entry (pos, member) \ + list_entry((pos)->member.prev, typeof(*(pos)), member) + +/** +* list_for_each - iterate over a list +* @pos: the &struct list_head to use as a loop cursor. +* @head: the head for your list. +*/ +#define list_for_each (pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** +* list_for_each_prev - iterate over a list backwards +* @pos: the &struct list_head to use as a loop cursor. +* @head: the head for your list. +*/ +#define list_for_each_prev (pos, head) \ + for (pos = (head)->prev; pos != (head); pos = pos->prev) + +/** +* list_for_each_safe - iterate over a list safe against removal of list entry +* @pos: the &struct list_head to use as a loop cursor. +* @n: another &struct list_head to use as temporary storage +* @head: the head for your list. +*/ +#define list_for_each_safe (pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** +* list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry +* @pos: the &struct list_head to use as a loop cursor. +* @n: another &struct list_head to use as temporary storage +* @head: the head for your list. +*/ +#define list_for_each_prev_safe (pos, n, head) \ + for (pos = (head)->prev, n = pos->prev; \ + pos != (head); \ + pos = n, n = pos->prev) + +/** +* list_for_each_entry - iterate over list of given type +* @pos: the type * to use as a loop cursor. +* @head: the head for your list. +* @member: the name of the list_head within the struct. +*/ +#define list_for_each_entry (pos, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_next_entry(pos, member)) + +/** +* list_for_each_entry_reverse - iterate backwards over list of given type. +* @pos: the type * to use as a loop cursor. +* @head: the head for your list. +* @member: the name of the list_head within the struct. +*/ +#define list_for_each_entry_reverse (pos, head, member) \ + for (pos = list_last_entry(head, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_prev_entry(pos, member)) + +/** +* list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() +* @pos: the type * to use as a start point +* @head: the head of the list +* @member: the name of the list_head within the struct. +* +* Prepares a pos entry for use as a start point in list_for_each_entry_continue(). +*/ +#define list_prepare_entry (pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** +* list_for_each_entry_continue - continue iteration over list of given type +* @pos: the type * to use as a loop cursor. +* @head: the head for your list. +* @member: the name of the list_head within the struct. +* +* Continue to iterate over list of given type, continuing after +* the current position. +*/ +#define list_for_each_entry_continue (pos, head, member) \ + for (pos = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = list_next_entry(pos, member)) + +/** +* list_for_each_entry_continue_reverse - iterate backwards from the given point +* @pos: the type * to use as a loop cursor. +* @head: the head for your list. +* @member: the name of the list_head within the struct. +* +* Start to iterate over list of given type backwards, continuing after +* the current position. +*/ +#define list_for_each_entry_continue_reverse (pos, head, member) \ + for (pos = list_prev_entry(pos, member); \ + &pos->member != (head); \ + pos = list_prev_entry(pos, member)) + +/** +* list_for_each_entry_from - iterate over list of given type from the current point +* @pos: the type * to use as a loop cursor. +* @head: the head for your list. +* @member: the name of the list_head within the struct. +* +* Iterate over list of given type, continuing from current position. +*/ +#define list_for_each_entry_from (pos, head, member) \ + for (; &pos->member != (head); \ + pos = list_next_entry(pos, member)) + +/** +* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry +* @pos: the type * to use as a loop cursor. +* @n: another type * to use as temporary storage +* @head: the head for your list. +* @member: the name of the list_head within the struct. +*/ +#define list_for_each_entry_safe (pos, n, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member), \ + n = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = n, n = list_next_entry(n, member)) + +/** +* list_for_each_entry_safe_continue - continue list iteration safe against removal +* @pos: the type * to use as a loop cursor. +* @n: another type * to use as temporary storage +* @head: the head for your list. +* @member: the name of the list_head within the struct. +* +* Iterate over list of given type, continuing after current point, +* safe against removal of list entry. +*/ +#define list_for_each_entry_safe_continue (pos, n, head, member) \ + for (pos = list_next_entry(pos, member), \ + n = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = n, n = list_next_entry(n, member)) + +/** +* list_for_each_entry_safe_from - iterate over list from current point safe against removal +* @pos: the type * to use as a loop cursor. +* @n: another type * to use as temporary storage +* @head: the head for your list. +* @member: the name of the list_head within the struct. +* +* Iterate over list of given type from current point, safe against +* removal of list entry. +*/ +#define list_for_each_entry_safe_from (pos, n, head, member) \ + for (n = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = n, n = list_next_entry(n, member)) + +/** +* list_for_each_entry_safe_reverse - iterate backwards over list safe against removal +* @pos: the type * to use as a loop cursor. +* @n: another type * to use as temporary storage +* @head: the head for your list. +* @member: the name of the list_head within the struct. +* +* Iterate backwards over list of given type, safe against removal +* of list entry. +*/ +#define list_for_each_entry_safe_reverse (pos, n, head, member) \ + for (pos = list_last_entry(head, typeof(*pos), member), \ + n = list_prev_entry(pos, member); \ + &pos->member != (head); \ + pos = n, n = list_prev_entry(n, member)) -#include "../../../include/linux/list.h" +/** +* list_safe_reset_next - reset a stale list_for_each_entry_safe loop +* @pos: the loop cursor used in the list_for_each_entry_safe loop +* @n: temporary storage used in list_for_each_entry_safe +* @member: the name of the list_head within the struct. +* +* list_safe_reset_next is not safe to use in general if the list may be +* modified concurrently (eg. the lock is dropped in the loop body). An +* exception to this is if the cursor element (pos) is pinned in the list, +* and list_safe_reset_next is called after re-taking the lock and before +* completing the current iteration of the loop body. +*/ +#define list_safe_reset_next (pos, n, member) \ + n = list_next_entry(pos, member) + +/* +* Double linked lists with a single pointer list head. +* Mostly useful for hash tables where the two pointer list head is +* too wasteful. +* You lose the ability to access the tail in O(1). +*/ + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD (name) struct hlist_head name = { .first = NULL } +#define INIT_HLIST_HEAD (ptr) ((ptr)->first = NULL) +static inline void INIT_HLIST_NODE (struct hlist_node *h) +{ + h->next =NULL ; + h->pprev =NULL ; +} + +static inline int hlist_unhashed (const struct hlist_node *h) +{ +return !h->pprev; +} + +static inline int hlist_empty (const struct hlist_head *h) +{ +return !h->first; +} + +static inline void __hlist_del (struct hlist_node *n) +{ +struct hlist_node *next = n->next; +struct hlist_node **pprev = n->pprev; + +WRITE_ONCE (*pprev, next); +if (next) + next->pprev = pprev; +} + +static inline void hlist_del (struct hlist_node *n) +{ +__hlist_del (n); + n->next =LIST_POISON1 ; + n->pprev =LIST_POISON2 ; +} + +static inline void hlist_del_init (struct hlist_node *n) +{ +if (!hlist_unhashed (n)) { +__hlist_del (n); +INIT_HLIST_NODE (n); + } +} + +static inline void hlist_add_head (struct hlist_node *n,struct hlist_head *h) +{ +struct hlist_node *first = h->first; + n->next = first; +if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + +/* next must be != NULL */ +static inline void hlist_add_before (struct hlist_node *n, +struct hlist_node *next) +{ + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; +} + +static inline void hlist_add_behind (struct hlist_node *n, +struct hlist_node *prev) +{ + n->next = prev->next; + prev->next = n; + n->pprev = &prev->next; + +if (n->next) + n->next->pprev = &n->next; +} + +/* after that we'll appear to be on some hlist and hlist_del will work */ +static inline void hlist_add_fake (struct hlist_node *n) +{ + n->pprev = &n->next; +} + +static inline bool hlist_fake (struct hlist_node *h) +{ +return h->pprev == &h->next; +} + +/* +* Move a list from one list head to another. Fixup the pprev +* reference of the first entry if it exists. +*/ +static inline void hlist_move_list (struct hlist_head *old, +struct hlist_head *new) +{ + new->first = old->first; +if (new->first) + new->first->pprev = &new->first; + old->first =NULL ; +} + +#define hlist_entry (ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each (pos, head) \ + for (pos = (head)->first; pos ; pos = pos->next) + +#define hlist_for_each_safe (pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) + +#define hlist_entry_safe (ptr, type, member) \ + ({ typeof(ptr) ____ptr = (ptr); \ + ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ + }) + +/** +* hlist_for_each_entry - iterate over list of given type +* @pos: the type * to use as a loop cursor. +* @head: the head for your list. +* @member: the name of the hlist_node within the struct. +*/ +#define hlist_for_each_entry (pos, head, member) \ + for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\ + pos; \ + pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) + +/** +* hlist_for_each_entry_continue - iterate over a hlist continuing after current point +* @pos: the type * to use as a loop cursor. +* @member: the name of the hlist_node within the struct. +*/ +#define hlist_for_each_entry_continue (pos, member) \ + for (pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member);\ + pos; \ + pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) + +/** +* hlist_for_each_entry_from - iterate over a hlist continuing from current point +* @pos: the type * to use as a loop cursor. +* @member: the name of the hlist_node within the struct. +*/ +#define hlist_for_each_entry_from (pos, member) \ + for (; pos; \ + pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) + +/** +* hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry +* @pos: the type * to use as a loop cursor. +* @n: another &struct hlist_node to use as temporary storage +* @head: the head for your list. +* @member: the name of the hlist_node within the struct. +*/ +#define hlist_for_each_entry_safe (pos, n, head, member) \ + for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\ + pos && ({ n = pos->member.next; 1; }); \ + pos = hlist_entry_safe(n, typeof(*pos), member)) -#ifndef TOOLS_LIST_H -#define TOOLS_LIST_H /** * list_del_range - deletes range of entries from list. * @begin: first element in the range to delete from the list.
@@ -27,4 +767,5 @@ static inline void list_del_range(struct list_head *begin,*/ #define list_for_each_from (pos, head) \ for (; pos != (head); pos = pos->next) -#endif + +#endif /* __TOOLS_LINUX_LIST_H */
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 4/11 tools: Fix formatting of the "make -C tools" help message
In reply to Arnaldo Carvalho de MeloFrom: Josh Poimboeuf <[email protected]>
Align the x86_energy_perf_policy line with the others and restore the original alphabetical sorting.
--- tools/Makefile | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-)
tools/Makefile +16 -16
@@ -8,23 +8,23 @@ include scripts/Makefile.include help: @echo 'Possible targets:' @echo '' - @echo ' acpi - ACPI tools' - @echo ' cgroup - cgroup tools' - @echo ' cpupower - a tool for all things x86 CPU power' - @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer' - @echo ' hv - tools used when in Hyper-V clients' - @echo ' iio - IIO tools' - @echo ' lguest - a minimal 32-bit x86 hypervisor' - @echo ' perf - Linux performance measurement and analysis tool' - @echo ' selftests - various kernel selftests' - @echo ' turbostat - Intel CPU idle stats and freq reporting tool' - @echo ' usb - USB testing tools' - @echo ' virtio - vhost test module' - @echo ' net - misc networking tools' - @echo ' vm - misc vm tools' + @echo ' acpi - ACPI tools' + @echo ' cgroup - cgroup tools' + @echo ' cpupower - a tool for all things x86 CPU power' + @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer' + @echo ' freefall - laptop accelerometer program for disk protection' + @echo ' hv - tools used when in Hyper-V clients' + @echo ' iio - IIO tools' + @echo ' lguest - a minimal 32-bit x86 hypervisor' + @echo ' net - misc networking tools' + @echo ' perf - Linux performance measurement and analysis tool' + @echo ' selftests - various kernel selftests' + @echo ' tmon - thermal monitoring and tuning tool' + @echo ' turbostat - Intel CPU idle stats and freq reporting tool' + @echo ' usb - USB testing tools' + @echo ' virtio - vhost test module' + @echo ' vm - misc vm tools' @echo ' x86_energy_perf_policy - Intel energy policy tool' - @echo ' tmon - thermal monitoring and tuning tool' - @echo ' freefall - laptop accelerometer program for disk protection' @echo '' @echo 'You can do:' @echo ' $$ make -C tools/ <tool>_install'
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 5/11 tools subcmd: Add missing NORETURN define for parse-options.h
In reply to Arnaldo Carvalho de MeloFrom: Josh Poimboeuf <[email protected]>
parse-options.h uses the NORETURN macro without defining it. perf doesn't see a build error because it defines the macro in util.h before including parse-options.h. But any other tool including it will see an error.
Define the macro in parse-options.h (if not already defined) so that other tools can include it.
--- tools/lib/subcmd/parse-options.h | 4 ++++ 1 file changed, 4 insertions(+)
tools/lib/subcmd/parse-options.h +4 -0
@@ -4,6 +4,10 @@#include <stdbool.h> #include <stdint.h> +#ifndef NORETURN +#define NORETURN __attribute__((__noreturn__)) +#endif +enum parse_opt_type {/* special types */ OPTION_END ,
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 6/11 perf record: Add --buildid-all option
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
The --buildid-all option is to record build-id of all DSOs in the file. It might be very costly to postprocess samples to find which DSO hits.
--- tools/perf/Documentation/perf-record.txt | 3 +++ tools/perf/builtin-record.c | 26 ++++++++++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-)
tools/perf/Documentation/perf-record.txt +3 -0
@@ -338,6 +338,9 @@ Options passed to clang when compiling BPF scriptlets. Specify vmlinux path which has debuginfo. (enabled when BPF prologue is on) +--buildid-all:: +Record build-id of all DSOs regardless whether it's actually hit or not. + SEE ALSO -------- linkperf:perf-stat[1], linkperf:perf-list[1]
tools/perf/builtin-record.c +20 -6
@@ -50,6 +50,7 @@ struct record {int realtime_prio;bool no_buildid;bool no_buildid_cache; +bool buildid_all;unsigned long long samples; };
@@ -362,6 +363,13 @@ static int process_buildids(struct record *rec)*/ symbol_conf.ignore_vmlinux_buildid = true; +/* +* If --buildid-all is given, it marks all DSO regardless of hits, +* so no need to process samples. +*/ +if (rec->buildid_all) + rec->tool.sample =NULL ; +return perf_session__process_events (session); }
@@ -756,12 +764,8 @@ out_child:if (!rec->no_buildid) {process_buildids (rec); -/* -* We take all buildids when the file contains -* AUX area tracing data because we do not decode the -* trace because it would take too long. -*/ -if (rec->opts.full_auxtrace) + +if (rec->buildid_all)dsos__hit_all (rec->session); }perf_session__write_header (rec->session, rec->evlist, fd, true);
@@ -1138,6 +1142,8 @@ struct option __record_options[] = { "options passed to clang when compiling BPF scriptlets"),OPT_STRING (0 ,"vmlinux" , &symbol_conf.vmlinux_name,"file" ,"vmlinux pathname" ), +OPT_BOOLEAN (0 ,"buildid-all" , &record.buildid_all, +"Record build-id of all DSOs regardless of hits" ), OPT_END() };
@@ -1255,6 +1261,14 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)if (err) goto out_symbol_exit; +/* +* We take all buildids when the file contains +* AUX area tracing data because we do not decode the +* trace because it would take too long. +*/ +if (rec->opts.full_auxtrace) + rec->buildid_all = true; +if (record_opts__config (&rec->opts)) { err = -EINVAL ; goto out_symbol_exit;
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 7/11 perf tools: Add more usage tips
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
Thanks to Andi Kleen for providing useful tips.
--- tools/perf/Documentation/tips.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
tools/perf/Documentation/tips.txt +15 -0
@@ -12,3 +12,18 @@ List events using substring match: perf list <keyword> To see list of saved events and attributes: perf evlist -v Use --symfs <dir> if your symbol files are in non-standard locations To see callchains in a more compact form: perf report -g folded +Show individual samples with: perf script +Limit to show entries above 5% only: perf report --percent-limit 5 +Profiling branch (mis)predictions with: perf record -b / perf report +Treat branches as callchains: perf report --branch-history +To count events in every 1000 msec: perf stat -I 1000 +Print event counts in CSV format with: perf stat -x, +If you have debuginfo enabled, try: perf report -s sym,srcline +For memory address profiling, try: perf mem record / perf mem report +For tracepoint events, try: perf report -s trace_fields +To record callchains for each sample: perf record -g +To record every process run by an user: perf record -u <user> +Skip collecing build-id when recording: perf record -B +To change sampling frequency to 100 Hz: perf record -F 100 +See assembly instructions with percentage: perf annotate <symbol> +If you prefer Intel style assembly, try: perf annotate -M intel
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 8/11 perf tools: Add file_only config option to strlist
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
If strlist_config.dirname is present, the strlist__new() tries to load stirngs from dirname/list file first but if it failes it falls back to add 'list' as string. But sometimes it's not desired so adds new file_only field to prevent it.
[ Add documentation for strlist_config::file_only, in the struct definition */
--- tools/perf/util/strlist.c | 8 ++++++++ tools/perf/util/strlist.h | 9 ++++++++- 2 files changed, 16 insertions(+), 1 deletion(-)
tools/perf/util/strlist.c +8 -0
@@ -126,6 +126,11 @@ static int strlist__parse_list_entry(struct strlist *slist, const char *s, err =strlist__load (slist, subst); goto out; } + +if (slist->file_only) { + err = -ENOENT ; + goto out; + } } err =strlist__add (slist, s);
@@ -157,11 +162,13 @@ struct strlist *strlist__new(const char *list, const struct strlist_config *confif (slist !=NULL ) {bool dupstr = true; +bool file_only = false;const char *dirname =NULL ;if (config) { dupstr = !config->dont_dupstr; dirname = config->dirname; + file_only = config->file_only; }rblist__init (&slist->rblist);
@@ -170,6 +177,7 @@ struct strlist *strlist__new(const char *list, const struct strlist_config *conf slist->rblist.node_delete = strlist__node_delete; slist->dupstr = dupstr; + slist->file_only = file_only;if (list &&strlist__parse_list (slist, list, dirname) !=0 ) goto out_error;
tools/perf/util/strlist.h +8 -1
@@ -13,11 +13,18 @@ struct str_node {struct strlist {struct rblist rblist; -bool dupstr; +bool dupstr; +bool file_only; }; +/* +* @file_only: When dirname is present, only consider entries as filenames, +* that should not be added to the list if dirname/entry is not +* found +*/ struct strlist_config {bool dont_dupstr; +bool file_only;const char *dirname; };
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 9/11 perf tools: Set and pass DOCDIR to builtin-report.c
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
It'll be used to locate perf document directory to find tips.txt in case it's not installed on the system.
--- tools/perf/Build | 1 + tools/perf/config/Makefile | 3 +++ 2 files changed, 4 insertions(+)
tools/perf/Build +1 -0
@@ -42,6 +42,7 @@ CFLAGS_perf.o += -DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))" \ -include $(OUTPUT)PERF-VERSION-FILE CFLAGS_builtin-trace.o += -DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_SQ))" CFLAGS_builtin-report.o += -DTIPDIR="BUILD_STR($(tipdir_SQ))" +CFLAGS_builtin-report.o += -DDOCDIR="BUILD_STR($(srcdir_SQ)/Documentation)" libperf-y += util/ libperf-y += arch/
tools/perf/config/Makefile +3 -0
@@ -692,6 +692,7 @@ template_dir = share/perf-core/templates STRACE_GROUPS_DIR = share/perf-core/strace/groups htmldir = share/doc/perf-doc tipdir = share/doc/perf-tip +srcdir = $(srctree)/tools/perf ifeq ($(prefix),/usr) sysconfdir = /etc ETC_PERFCONFIG = $(sysconfdir)/perfconfig
@@ -722,6 +723,7 @@ tipdir_SQ = $(subst ','\'',$(tipdir)) prefix_SQ = $(subst ','\'',$(prefix)) sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) libdir_SQ = $(subst ','\'',$(libdir)) +srcdir_SQ = $(subst ','\'',$(srcdir)) ifneq ($(filter /%,$(firstword $(perfexecdir))),) perfexec_instdir = $(perfexecdir)
@@ -776,6 +778,7 @@ $(call detected_var,STRACE_GROUPS_DIR_SQ) $(call detected_var,prefix_SQ) $(call detected_var,perfexecdir_SQ) $(call detected_var,tipdir_SQ) +$(call detected_var,srcdir_SQ) $(call detected_var,LIBDIR) $(call detected_var,GTK_CFLAGS) $(call detected_var,PERL_EMBED_CCOPTS)
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 10/11 perf ui/tui: Print helpline message as is
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
When a tip message contains a percent sign, it was treated printf format specifier so broken string was printed like below.
Tip: Limit to show entries above 577nly: perf report --percent-limit 5
^^^
As ui_browser__show receives format string, pass additional "%s" so that the help (tip) message can be printed as is.
Tip: Limit to show entries above 5% only: perf report --percent-limit 5
--- tools/perf/ui/browsers/hists.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/ui/browsers/hists.c +1 -1
@@ -480,7 +480,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *help)hists__browser_title (browser->hists, hbt, title,sizeof (title)); -if (ui_browser__show (&browser->b, title, help) <0 ) +if (ui_browser__show (&browser->b, title,"%s" , help) <0 )return -1 ;while (1 ) {
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 11/11 perf tools: Fallback to srcdir/Documentation/tips.txt
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
Some people don't install perf, but just use compiled version in the source. Fallback to lookup the source directory for those poor guys. :)
--- tools/perf/builtin-report.c | 10 +++++++++- tools/perf/util/util.c | 11 ++++++----- 2 files changed, 15 insertions(+), 6 deletions(-)
tools/perf/builtin-report.c +9 -1
@@ -28,6 +28,7 @@#include "util/tool.h" #include <subcmd/parse-options.h> +#include <subcmd/exec-cmd.h> #include "util/parse-events.h" #include "util/thread.h"
@@ -433,7 +434,14 @@ static int report__browse_hists(struct report *rep)int ret;struct perf_session *session = rep->session;struct perf_evlist *evlist = session->evlist; -const char *help =perf_tip (TIPDIR ); +const char *help =perf_tip (system_path (TIPDIR )); + +if (help ==NULL ) { +/* fallback for people who don't install perf ;-) */ + help =perf_tip (DOCDIR ); +if (help ==NULL ) + help ="Cannot load tips.txt file, please install perf!" ; + }switch (use_browser) {case 1 :
tools/perf/util/util.c +6 -5
@@ -17,7 +17,6 @@#include <unistd.h> #include "callchain.h" #include "strlist.h" -#include <subcmd/exec-cmd.h> struct callchain_param callchain_param = { .mode =CHAIN_GRAPH_ABS ,
@@ -672,14 +671,16 @@ const char *perf_tip(const char *dirpath)struct str_node *node;char *tip =NULL ;struct strlist_config conf = { - .dirname =system_path (dirpath) , + .dirname = dirpath, + .file_only = true, }; tips =strlist__new ("tips.txt" , &conf); -if (tips ==NULL ||strlist__nr_entries (tips) ==1 ) { - tip = (char *)"Cannot find tips.txt file" ; +if (tips ==NULL ) +return errno ==ENOENT ?NULL :"Tip: get more memory! ;-p" ; + +if (strlist__nr_entries (tips) ==0 ) goto out; - } node =strlist__entry (tips,random () %strlist__nr_entries (tips));if (asprintf (&tip,"Tip: %s" , node->s) <0 )
Signature · 1 line
2.1.0
Quoted 70 lines · Arnaldo Carvalho de Melo
From: Arnaldo Carvalho de Melo <[email protected]>
Hi Ingo,
Please consider pulling,
- Arnaldo
The following changes since commit
0bd106d26dbe444160104b3153ca1652d2ab913b:Merge tag 'perf-core-for-mingo' of
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linuxinto perf/urgent (2016-01-12 11:01:16 +0100)are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.gittags/perf-core-for-mingofor you to fetch changes up to
34b7b0f95d41d2351a080e774d71085171db90e6:perf tools: Fallback to
srcdir/Documentation/tips.txt(2016-01-12 12:42:08 -0300)----------------------------------------------------------------
perf/core improvements and fixes:User visible new features:
- Add --buildid-all option to 'perf record' to avoid processing samples, just collecting build-ids for _all_ the DSOs that appears in
PERF_RECORD_MMAPrecords (Namhyung Kim)- Add some more usage tips to appear in the hists browser (top & report) (Namhyung Kim, Andi Kleen)
- Fix mmap2 event allocation in synthesize code, where we were allocating space just for
PERF_RECORD_MMAP, the older variant, which could lead to corner case problems (Wang Nan)Developer stuff:
- Make
list.hself-sufficient, removing one more reference to kernel headers that lead to recent breakage when some rculist change was made in the kernel sources. (Josh Poimboeuf)Add missing NORETURN define for
parse-options.hintools/lib/subcmd(Josh Poimboeuf)- Fallback to srcdir/Documentation/ when not finding tips.txt elsewhere (Namhyung Kim)
Signed-off-by Arnaldo Carvalho de Melo <[email protected]>----------------------------------------------------------------
Jiri Olsa (1):
perf stat: Fixrecort_usagetypoJosh Poimboeuf (3):
tools: Makelist.hself-sufficient
tools: Fix formatting of the "make -C tools" help message tools subcmd: Add missing NORETURN define forparse-options.hNamhyung Kim (6):
perf record: Add --buildid-all option
perf tools: Add more usage tips
perf tools: Addfile_onlyconfig option to strlist perf tools: Set and pass DOCDIR tobuiltin-report.cperf ui/tui: Print helpline message as is perf tools: Fallback tosrcdir/Documentation/tips.txtWang Nan (1):
perf tools: Fix mmap2 event allocation in synthesize code
Quoted 16 lines
tools/Makefile | 32 +- tools/include/linux/list.h | 753 ++++++++++++++++++++++++++++++- tools/lib/subcmd/parse-options.h | 4 + tools/perf/Build | 1 + tools/perf/Documentation/perf-record.txt | 3 + tools/perf/Documentation/tips.txt | 15 + tools/perf/builtin-record.c | 26 +- tools/perf/builtin-report.c | 10 +- tools/perf/builtin-stat.c | 8 +- tools/perf/config/Makefile | 3 + tools/perf/ui/browsers/hists.c | 2 +- tools/perf/util/event.c | 4 +- tools/perf/util/strlist.c | 8 + tools/perf/util/strlist.h | 9 +- tools/perf/util/util.c | 11 +- 15 files changed, 847 insertions(+), 42 deletions(-)
Pulled into perf/urgent, thanks a lot Arnaldo!
Ingo