diff options
| author | Tzvetomir Stoyanov <tstoyanov@vmware.com> | 2019-04-01 12:43:08 -0400 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2019-04-01 14:18:09 -0400 |
| commit | 6699ed712a97f70267e017f509126b890f6f6b28 (patch) | |
| tree | 51121a341e65c4f38001f329a8a8a21a0f889e61 /tools | |
| parent | fed33e905c4beea96a066686f8be2b489eb5068e (diff) | |
tools lib traceevent: Implement a new API, tep_list_events_copy()
Existing API tep_list_events() is not thread safe, it uses the internal
array sort_events to keep cache of the sorted events and reuses it. This
patch implements a new API, tep_list_events_copy(), which allocates new
sorted array each time it is called. It could be used when a sorted
events functionality is needed in thread safe use cases. It is up to the
caller to free the array.
Signed-off-by: Tzvetomir Stoyanov <tstoyanov@vmware.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lore.kernel.org/linux-trace-devel/20181218133013.31094-1-tstoyanov@vmware.com
Link: http://lkml.kernel.org/r/20190401164343.117437443@goodmis.org
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/lib/traceevent/event-parse.c | 109 | ||||
| -rw-r--r-- | tools/lib/traceevent/event-parse.h | 5 |
2 files changed, 91 insertions, 23 deletions
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 666e23ded6ed..c00aebab3c33 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c | |||
| @@ -5651,32 +5651,26 @@ static int events_system_cmp(const void *a, const void *b) | |||
| 5651 | return events_id_cmp(a, b); | 5651 | return events_id_cmp(a, b); |
| 5652 | } | 5652 | } |
| 5653 | 5653 | ||
| 5654 | struct tep_event **tep_list_events(struct tep_handle *pevent, enum tep_event_sort_type sort_type) | 5654 | static struct tep_event **list_events_copy(struct tep_handle *tep) |
| 5655 | { | 5655 | { |
| 5656 | struct tep_event **events; | 5656 | struct tep_event **events; |
| 5657 | int (*sort)(const void *a, const void *b); | ||
| 5658 | |||
| 5659 | events = pevent->sort_events; | ||
| 5660 | |||
| 5661 | if (events && pevent->last_type == sort_type) | ||
| 5662 | return events; | ||
| 5663 | 5657 | ||
| 5664 | if (!events) { | 5658 | if (!tep) |
| 5665 | events = malloc(sizeof(*events) * (pevent->nr_events + 1)); | 5659 | return NULL; |
| 5666 | if (!events) | ||
| 5667 | return NULL; | ||
| 5668 | 5660 | ||
| 5669 | memcpy(events, pevent->events, sizeof(*events) * pevent->nr_events); | 5661 | events = malloc(sizeof(*events) * (tep->nr_events + 1)); |
| 5670 | events[pevent->nr_events] = NULL; | 5662 | if (!events) |
| 5663 | return NULL; | ||
| 5671 | 5664 | ||
| 5672 | pevent->sort_events = events; | 5665 | memcpy(events, tep->events, sizeof(*events) * tep->nr_events); |
| 5666 | events[tep->nr_events] = NULL; | ||
| 5667 | return events; | ||
| 5668 | } | ||
| 5673 | 5669 | ||
| 5674 | /* the internal events are sorted by id */ | 5670 | static void list_events_sort(struct tep_event **events, int nr_events, |
| 5675 | if (sort_type == TEP_EVENT_SORT_ID) { | 5671 | enum tep_event_sort_type sort_type) |
| 5676 | pevent->last_type = sort_type; | 5672 | { |
| 5677 | return events; | 5673 | int (*sort)(const void *a, const void *b); |
| 5678 | } | ||
| 5679 | } | ||
| 5680 | 5674 | ||
| 5681 | switch (sort_type) { | 5675 | switch (sort_type) { |
| 5682 | case TEP_EVENT_SORT_ID: | 5676 | case TEP_EVENT_SORT_ID: |
| @@ -5689,11 +5683,82 @@ struct tep_event **tep_list_events(struct tep_handle *pevent, enum tep_event_sor | |||
| 5689 | sort = events_system_cmp; | 5683 | sort = events_system_cmp; |
| 5690 | break; | 5684 | break; |
| 5691 | default: | 5685 | default: |
| 5686 | sort = NULL; | ||
| 5687 | } | ||
| 5688 | |||
| 5689 | if (sort) | ||
| 5690 | qsort(events, nr_events, sizeof(*events), sort); | ||
| 5691 | } | ||
| 5692 | |||
| 5693 | /** | ||
| 5694 | * tep_list_events - Get events, sorted by given criteria. | ||
| 5695 | * @tep: a handle to the tep context | ||
| 5696 | * @sort_type: desired sort order of the events in the array | ||
| 5697 | * | ||
| 5698 | * Returns an array of pointers to all events, sorted by the given | ||
| 5699 | * @sort_type criteria. The last element of the array is NULL. The returned | ||
| 5700 | * memory must not be freed, it is managed by the library. | ||
| 5701 | * The function is not thread safe. | ||
| 5702 | */ | ||
| 5703 | struct tep_event **tep_list_events(struct tep_handle *tep, | ||
| 5704 | enum tep_event_sort_type sort_type) | ||
| 5705 | { | ||
| 5706 | struct tep_event **events; | ||
| 5707 | |||
| 5708 | if (!tep) | ||
| 5709 | return NULL; | ||
| 5710 | |||
| 5711 | events = tep->sort_events; | ||
| 5712 | if (events && tep->last_type == sort_type) | ||
| 5692 | return events; | 5713 | return events; |
| 5714 | |||
| 5715 | if (!events) { | ||
| 5716 | events = list_events_copy(tep); | ||
| 5717 | if (!events) | ||
| 5718 | return NULL; | ||
| 5719 | |||
| 5720 | tep->sort_events = events; | ||
| 5721 | |||
| 5722 | /* the internal events are sorted by id */ | ||
| 5723 | if (sort_type == TEP_EVENT_SORT_ID) { | ||
| 5724 | tep->last_type = sort_type; | ||
| 5725 | return events; | ||
| 5726 | } | ||
| 5693 | } | 5727 | } |
| 5694 | 5728 | ||
| 5695 | qsort(events, pevent->nr_events, sizeof(*events), sort); | 5729 | list_events_sort(events, tep->nr_events, sort_type); |
| 5696 | pevent->last_type = sort_type; | 5730 | tep->last_type = sort_type; |
| 5731 | |||
| 5732 | return events; | ||
| 5733 | } | ||
| 5734 | |||
| 5735 | |||
| 5736 | /** | ||
| 5737 | * tep_list_events_copy - Thread safe version of tep_list_events() | ||
| 5738 | * @tep: a handle to the tep context | ||
| 5739 | * @sort_type: desired sort order of the events in the array | ||
| 5740 | * | ||
| 5741 | * Returns an array of pointers to all events, sorted by the given | ||
| 5742 | * @sort_type criteria. The last element of the array is NULL. The returned | ||
| 5743 | * array is newly allocated inside the function and must be freed by the caller | ||
| 5744 | */ | ||
| 5745 | struct tep_event **tep_list_events_copy(struct tep_handle *tep, | ||
| 5746 | enum tep_event_sort_type sort_type) | ||
| 5747 | { | ||
| 5748 | struct tep_event **events; | ||
| 5749 | |||
| 5750 | if (!tep) | ||
| 5751 | return NULL; | ||
| 5752 | |||
| 5753 | events = list_events_copy(tep); | ||
| 5754 | if (!events) | ||
| 5755 | return NULL; | ||
| 5756 | |||
| 5757 | /* the internal events are sorted by id */ | ||
| 5758 | if (sort_type == TEP_EVENT_SORT_ID) | ||
| 5759 | return events; | ||
| 5760 | |||
| 5761 | list_events_sort(events, tep->nr_events, sort_type); | ||
| 5697 | 5762 | ||
| 5698 | return events; | 5763 | return events; |
| 5699 | } | 5764 | } |
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index aec48f2aea8a..41159358abc2 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h | |||
| @@ -544,7 +544,10 @@ void tep_event_info(struct trace_seq *s, struct tep_event *event, | |||
| 544 | int tep_strerror(struct tep_handle *pevent, enum tep_errno errnum, | 544 | int tep_strerror(struct tep_handle *pevent, enum tep_errno errnum, |
| 545 | char *buf, size_t buflen); | 545 | char *buf, size_t buflen); |
| 546 | 546 | ||
| 547 | struct tep_event **tep_list_events(struct tep_handle *pevent, enum tep_event_sort_type); | 547 | struct tep_event **tep_list_events(struct tep_handle *tep, |
| 548 | enum tep_event_sort_type); | ||
| 549 | struct tep_event **tep_list_events_copy(struct tep_handle *tep, | ||
| 550 | enum tep_event_sort_type); | ||
| 548 | struct tep_format_field **tep_event_common_fields(struct tep_event *event); | 551 | struct tep_format_field **tep_event_common_fields(struct tep_event *event); |
| 549 | struct tep_format_field **tep_event_fields(struct tep_event *event); | 552 | struct tep_format_field **tep_event_fields(struct tep_event *event); |
| 550 | 553 | ||
