perf tools: Add hist_entry allocation callbacks
Jiri Olsa
reviewercover perf tools: Add hist_entry allocation callbacks
hi,
this patchset tries to add support provide own allocation zalloc/free methods for hist_entry object.
v2 changes:
- merged patch 1 and 2 from RFC
The reason is to provide a way to be able to store more data within hist_entry object in a transparent way to its current usage by allocating its own hist_entry sub object.
The user/app which wants to allocate its own hist_entry sub object provides following ops struct:
struct hist_entry_ops *ops {
void* (*new)(size_t);
void (*free)(void *);
}via new interface function:
struct hist_entry * hists__add_entry_ops(struct hists *hists,
struct hist_entry_ops *ops,
...
I'm using this for c2c code to enlarge hist_entry object with large stats structure, which has no use to standard perf usage/commands.
It might be used to lower the hist_entry footproint for default perf usage by uing this for things like hierarchy output that adds extra stuff into hist_entry object.
Available at:
git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
perf/he_ops
thanks,
jirka
---
Jiri Olsa (3):
perf tools: Introduce hist_entry__init function perf tools: Introduce hist_entry_ops
perf tools: Introduce hists__add_entry_ops function
tools/perf/util/hist.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------- tools/perf/util/hist.h | 11 ++++++ tools/perf/util/sort.h | 6 ++++ 3 files changed, 148 insertions(+), 73 deletions(-)
Jiri Olsa
reviewerPATCH 1/3 perf tools: Introduce hist_entry__init function
Move hist_entry initialization code into separate function. It'll be useful and more clear for following patches that introduce allocation callbacks.
Releasing the hist_entry object in hist_entry__new function (where it's allocated) rather than in hist_entry__init.
--- tools/perf/util/hist.c | 139 ++++++++++++++++++++++++++----------------------- 1 file changed, 73 insertions(+), 66 deletions(-)
tools/perf/util/hist.c +73 -66
@@ -352,86 +352,93 @@ void hists__delete_entries(struct hists *hists)* histogram, sorted on item, collects periods */ -static struct hist_entry *hist_entry__new (struct hist_entry *template, -bool sample_self) -{ -size_t callchain_size =0 ; -struct hist_entry *he; +static int hist_entry__init (struct hist_entry *he, +struct hist_entry *template, +bool sample_self) +{ + *he = *template; + +if (symbol_conf.cumulate_callchain) { + he->stat_acc =malloc (sizeof (he->stat)); +if (he->stat_acc ==NULL ) +return -ENOMEM ; +memcpy (he->stat_acc, &he->stat,sizeof (he->stat)); +if (!sample_self) +memset (&he->stat,0 ,sizeof (he->stat)); + } -if (symbol_conf.use_callchain) - callchain_size =sizeof (struct callchain_root ); +map__get (he->ms.map); - he =zalloc (sizeof (*he) + callchain_size); +if (he->branch_info) { +/* +* This branch info is (a part of) allocated from +* sample__resolve_bstack() and will be freed after +* adding new entries. So we need to save a copy. +*/ + he->branch_info =malloc (sizeof (*he->branch_info)); +if (he->branch_info ==NULL ) { +map__zput (he->ms.map); +free (he->stat_acc); +return -ENOMEM ; + } -if (he !=NULL ) { - *he = *template; +memcpy (he->branch_info, template->branch_info, +sizeof (*he->branch_info)); -if (symbol_conf.cumulate_callchain) { - he->stat_acc =malloc (sizeof (he->stat)); -if (he->stat_acc ==NULL ) { -free (he); -return NULL ; - } -memcpy (he->stat_acc, &he->stat,sizeof (he->stat)); -if (!sample_self) -memset (&he->stat,0 ,sizeof (he->stat)); - } +map__get (he->branch_info->from.map); +map__get (he->branch_info->to.map); + } -map__get (he->ms.map); +if (he->mem_info) { +map__get (he->mem_info->iaddr.map); +map__get (he->mem_info->daddr.map); + } -if (he->branch_info) { -/* -* This branch info is (a part of) allocated from -* sample__resolve_bstack() and will be freed after -* adding new entries. So we need to save a copy. -*/ - he->branch_info =malloc (sizeof (*he->branch_info)); -if (he->branch_info ==NULL ) { -map__zput (he->ms.map); -free (he->stat_acc); -free (he); -return NULL ; - } +if (symbol_conf.use_callchain) +callchain_init (he->callchain); -memcpy (he->branch_info, template->branch_info, -sizeof (*he->branch_info)); +if (he->raw_data) { + he->raw_data =memdup (he->raw_data, he->raw_size); -map__get (he->branch_info->from.map); -map__get (he->branch_info->to.map); +if (he->raw_data ==NULL ) { +map__put (he->ms.map); +if (he->branch_info) { +map__put (he->branch_info->from.map); +map__put (he->branch_info->to.map); +free (he->branch_info); + } +if (he->mem_info) { +map__put (he->mem_info->iaddr.map); +map__put (he->mem_info->daddr.map); + } +free (he->stat_acc); +return -ENOMEM ; } + } +INIT_LIST_HEAD (&he->pairs.node); +thread__get (he->thread); -if (he->mem_info) { -map__get (he->mem_info->iaddr.map); -map__get (he->mem_info->daddr.map); - } +if (!symbol_conf.report_hierarchy) + he->leaf = true; -if (symbol_conf.use_callchain) -callchain_init (he->callchain); +return 0 ; +} -if (he->raw_data) { - he->raw_data =memdup (he->raw_data, he->raw_size); +static struct hist_entry *hist_entry__new (struct hist_entry *template, +bool sample_self) +{ +size_t callchain_size =0 ; +struct hist_entry *he; +int err =0 ; -if (he->raw_data ==NULL ) { -map__put (he->ms.map); -if (he->branch_info) { -map__put (he->branch_info->from.map); -map__put (he->branch_info->to.map); -free (he->branch_info); - } -if (he->mem_info) { -map__put (he->mem_info->iaddr.map); -map__put (he->mem_info->daddr.map); - } -free (he->stat_acc); -free (he); -return NULL ; - } - } -INIT_LIST_HEAD (&he->pairs.node); -thread__get (he->thread); +if (symbol_conf.use_callchain) + callchain_size =sizeof (struct callchain_root ); -if (!symbol_conf.report_hierarchy) - he->leaf = true; + he =zalloc (sizeof (*he) + callchain_size); +if (he) { + err =hist_entry__init (he, template, sample_self); +if (err) +zfree (&he); }return he;
Signature · 1 line
2.4.11
tip-bot for Jiri Olsa
merge bot[tip:perf/core] perf hists: Introduce hist_entry__init function
perf hists: Introduce hist_entry__init function
Commit-ID: 0a269a6bb3f86abb218b8632f13c4ecd9b6b92af Gitweb: http://git.kernel.org/tip/0a269a6bb3f86abb218b8632f13c4ecd9b6b92af Author: Jiri Olsa <[email protected]> AuthorDate: Tue, 5 Jul 2016 08:56:03 +0200 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Tue, 12 Jul 2016 00:00:39 -0300
perf hists: Introduce hist_entry__init function
Move the 'struct hist_entry' initialization code to a separate function. It'll be useful and more clear for the following patches that introduce allocation callbacks.
Releasing the hist_entry object in hist_entry__new function (where it's allocated) rather than in hist_entry__init.
--- tools/perf/util/hist.c | 139 ++++++++++++++++++++++++++----------------------- 1 file changed, 73 insertions(+), 66 deletions(-)
tools/perf/util/hist.c +73 -66
@@ -352,86 +352,93 @@ void hists__delete_entries(struct hists *hists)* histogram, sorted on item, collects periods */ -static struct hist_entry *hist_entry__new (struct hist_entry *template, -bool sample_self) -{ -size_t callchain_size =0 ; -struct hist_entry *he; +static int hist_entry__init (struct hist_entry *he, +struct hist_entry *template, +bool sample_self) +{ + *he = *template; + +if (symbol_conf.cumulate_callchain) { + he->stat_acc =malloc (sizeof (he->stat)); +if (he->stat_acc ==NULL ) +return -ENOMEM ; +memcpy (he->stat_acc, &he->stat,sizeof (he->stat)); +if (!sample_self) +memset (&he->stat,0 ,sizeof (he->stat)); + } -if (symbol_conf.use_callchain) - callchain_size =sizeof (struct callchain_root ); +map__get (he->ms.map); - he =zalloc (sizeof (*he) + callchain_size); +if (he->branch_info) { +/* +* This branch info is (a part of) allocated from +* sample__resolve_bstack() and will be freed after +* adding new entries. So we need to save a copy. +*/ + he->branch_info =malloc (sizeof (*he->branch_info)); +if (he->branch_info ==NULL ) { +map__zput (he->ms.map); +free (he->stat_acc); +return -ENOMEM ; + } -if (he !=NULL ) { - *he = *template; +memcpy (he->branch_info, template->branch_info, +sizeof (*he->branch_info)); -if (symbol_conf.cumulate_callchain) { - he->stat_acc =malloc (sizeof (he->stat)); -if (he->stat_acc ==NULL ) { -free (he); -return NULL ; - } -memcpy (he->stat_acc, &he->stat,sizeof (he->stat)); -if (!sample_self) -memset (&he->stat,0 ,sizeof (he->stat)); - } +map__get (he->branch_info->from.map); +map__get (he->branch_info->to.map); + } -map__get (he->ms.map); +if (he->mem_info) { +map__get (he->mem_info->iaddr.map); +map__get (he->mem_info->daddr.map); + } -if (he->branch_info) { -/* -* This branch info is (a part of) allocated from -* sample__resolve_bstack() and will be freed after -* adding new entries. So we need to save a copy. -*/ - he->branch_info =malloc (sizeof (*he->branch_info)); -if (he->branch_info ==NULL ) { -map__zput (he->ms.map); -free (he->stat_acc); -free (he); -return NULL ; - } +if (symbol_conf.use_callchain) +callchain_init (he->callchain); -memcpy (he->branch_info, template->branch_info, -sizeof (*he->branch_info)); +if (he->raw_data) { + he->raw_data =memdup (he->raw_data, he->raw_size); -map__get (he->branch_info->from.map); -map__get (he->branch_info->to.map); +if (he->raw_data ==NULL ) { +map__put (he->ms.map); +if (he->branch_info) { +map__put (he->branch_info->from.map); +map__put (he->branch_info->to.map); +free (he->branch_info); + } +if (he->mem_info) { +map__put (he->mem_info->iaddr.map); +map__put (he->mem_info->daddr.map); + } +free (he->stat_acc); +return -ENOMEM ; } + } +INIT_LIST_HEAD (&he->pairs.node); +thread__get (he->thread); -if (he->mem_info) { -map__get (he->mem_info->iaddr.map); -map__get (he->mem_info->daddr.map); - } +if (!symbol_conf.report_hierarchy) + he->leaf = true; -if (symbol_conf.use_callchain) -callchain_init (he->callchain); +return 0 ; +} -if (he->raw_data) { - he->raw_data =memdup (he->raw_data, he->raw_size); +static struct hist_entry *hist_entry__new (struct hist_entry *template, +bool sample_self) +{ +size_t callchain_size =0 ; +struct hist_entry *he; +int err =0 ; -if (he->raw_data ==NULL ) { -map__put (he->ms.map); -if (he->branch_info) { -map__put (he->branch_info->from.map); -map__put (he->branch_info->to.map); -free (he->branch_info); - } -if (he->mem_info) { -map__put (he->mem_info->iaddr.map); -map__put (he->mem_info->daddr.map); - } -free (he->stat_acc); -free (he); -return NULL ; - } - } -INIT_LIST_HEAD (&he->pairs.node); -thread__get (he->thread); +if (symbol_conf.use_callchain) + callchain_size =sizeof (struct callchain_root ); -if (!symbol_conf.report_hierarchy) - he->leaf = true; + he =zalloc (sizeof (*he) + callchain_size); +if (he) { + err =hist_entry__init (he, template, sample_self); +if (err) +zfree (&he); }return he;
Jiri Olsa
reviewerPATCH 2/3 perf tools: Introduce hist_entry_ops
In reply to Jiri OlsaIntroducing allocation callbacks, that allows to extend current hist_entry object into objects with special needs without polluting the current hist_entry object.
--- tools/perf/util/hist.c | 31 +++++++++++++++++++++++++++---- tools/perf/util/sort.h | 6 ++++++ 2 files changed, 33 insertions(+), 4 deletions(-)
tools/perf/util/hist.c +27 -4
@@ -424,21 +424,42 @@ static int hist_entry__init(struct hist_entry *he,return 0 ; } +static void *hist_entry__zalloc (size_t size) +{ +return zalloc (size +sizeof (struct hist_entry )); +} + +static void hist_entry__free (void *ptr) +{ +free (ptr); +} + +static struct hist_entry_ops default_ops = { + .new = hist_entry__zalloc, + .free = hist_entry__free, +}; +static struct hist_entry *hist_entry__new (struct hist_entry *template,bool sample_self) { +struct hist_entry_ops *ops = template->ops;size_t callchain_size =0 ;struct hist_entry *he;int err =0 ; +if (!ops) + ops = template->ops = &default_ops; +if (symbol_conf.use_callchain) callchain_size =sizeof (struct callchain_root ); - he =zalloc (sizeof (*he) + callchain_size); + he = ops->new (callchain_size);if (he) { err =hist_entry__init (he, template, sample_self); -if (err) -zfree (&he); +if (err) { + ops->free (he); + he =NULL ; + } }return he;
@@ -1050,6 +1071,8 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)void hist_entry__delete (struct hist_entry *he) { +struct hist_entry_ops *ops = he->ops; +thread__zput (he->thread);map__zput (he->ms.map);
@@ -1074,7 +1097,7 @@ void hist_entry__delete(struct hist_entry *he)free_callchain (he->callchain);free (he->trace_output);free (he->raw_data); -free (he); + ops->free (he); }/*
tools/perf/util/sort.h +6 -0
@@ -67,6 +67,11 @@ struct hist_entry_diff { }; }; +struct hist_entry_ops { +void * (*new)(size_t ); +void (*free)(void *); +}; +/** * struct hist_entry - histogram entry *
@@ -125,6 +130,7 @@ struct hist_entry {void *trace_output;struct perf_hpp_list *hpp_list;struct hist_entry *parent_he; +struct hist_entry_ops *ops; union { /* this is for hierarchical entry structure */ struct {
Signature · 1 line
2.4.11
tip-bot for Jiri Olsa
merge bot[tip:perf/core] perf hists: Introduce hist_entry_ops
perf hists: Introduce hist_entry_ops
Commit-ID: f542e7670e48bc9d0aed351c1fd2ae0b65cc6f68 Gitweb: http://git.kernel.org/tip/f542e7670e48bc9d0aed351c1fd2ae0b65cc6f68 Author: Jiri Olsa <[email protected]> AuthorDate: Tue, 5 Jul 2016 08:56:04 +0200 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Tue, 12 Jul 2016 00:00:39 -0300
perf hists: Introduce hist_entry_ops
Introducing allocation callbacks, that allows to extend current hist_entry object into objects with special needs without polluting the current hist_entry object.
--- tools/perf/util/hist.c | 31 +++++++++++++++++++++++++++---- tools/perf/util/sort.h | 6 ++++++ 2 files changed, 33 insertions(+), 4 deletions(-)
tools/perf/util/hist.c +27 -4
@@ -424,21 +424,42 @@ static int hist_entry__init(struct hist_entry *he,return 0 ; } +static void *hist_entry__zalloc (size_t size) +{ +return zalloc (size +sizeof (struct hist_entry )); +} + +static void hist_entry__free (void *ptr) +{ +free (ptr); +} + +static struct hist_entry_ops default_ops = { + .new = hist_entry__zalloc, + .free = hist_entry__free, +}; +static struct hist_entry *hist_entry__new (struct hist_entry *template,bool sample_self) { +struct hist_entry_ops *ops = template->ops;size_t callchain_size =0 ;struct hist_entry *he;int err =0 ; +if (!ops) + ops = template->ops = &default_ops; +if (symbol_conf.use_callchain) callchain_size =sizeof (struct callchain_root ); - he =zalloc (sizeof (*he) + callchain_size); + he = ops->new (callchain_size);if (he) { err =hist_entry__init (he, template, sample_self); -if (err) -zfree (&he); +if (err) { + ops->free (he); + he =NULL ; + } }return he;
@@ -1050,6 +1071,8 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)void hist_entry__delete (struct hist_entry *he) { +struct hist_entry_ops *ops = he->ops; +thread__zput (he->thread);map__zput (he->ms.map);
@@ -1074,7 +1097,7 @@ void hist_entry__delete(struct hist_entry *he)free_callchain (he->callchain);free (he->trace_output);free (he->raw_data); -free (he); + ops->free (he); }/*
tools/perf/util/sort.h +6 -0
@@ -67,6 +67,11 @@ struct hist_entry_diff { }; }; +struct hist_entry_ops { +void *(*new)(size_t size); +void (*free)(void *ptr); +}; +/** * struct hist_entry - histogram entry *
@@ -125,6 +130,7 @@ struct hist_entry {void *trace_output;struct perf_hpp_list *hpp_list;struct hist_entry *parent_he; +struct hist_entry_ops *ops; union { /* this is for hierarchical entry structure */ struct {
Jiri Olsa
reviewerPATCH 3/3 perf tools: Introduce hists__add_entry_ops function
In reply to Jiri OlsaIntroducing hists__add_entry_ops function to allow using the allocation callbacks externally.
--- tools/perf/util/hist.c | 42 +++++++++++++++++++++++++++++++++++------- tools/perf/util/hist.h | 11 +++++++++++ 2 files changed, 46 insertions(+), 7 deletions(-)
tools/perf/util/hist.c +35 -7
@@ -559,13 +559,15 @@ out:return he; } -struct hist_entry *hists__add_entry (struct hists *hists, -struct addr_location *al, -struct symbol *sym_parent, -struct branch_info *bi, -struct mem_info *mi, -struct perf_sample *sample, -bool sample_self) +static struct hist_entry * +__hists__add_entry (struct hists *hists, +struct addr_location *al, +struct symbol *sym_parent, +struct branch_info *bi, +struct mem_info *mi, +struct perf_sample *sample, +bool sample_self, +struct hist_entry_ops *ops) {struct hist_entry entry = { .thread = al->thread,
@@ -592,11 +594,37 @@ struct hist_entry *hists__add_entry(struct hists *hists, .transaction = sample->transaction, .raw_data = sample->raw_data, .raw_size = sample->raw_size, + .ops = ops, };return hists__findnew_entry (hists, &entry, al, sample_self); } +struct hist_entry *hists__add_entry (struct hists *hists, +struct addr_location *al, +struct symbol *sym_parent, +struct branch_info *bi, +struct mem_info *mi, +struct perf_sample *sample, +bool sample_self) +{ +return __hists__add_entry (hists, al, sym_parent, bi, mi, + sample, sample_self,NULL ); +} + +struct hist_entry *hists__add_entry_ops (struct hists *hists, +struct hist_entry_ops *ops, +struct addr_location *al, +struct symbol *sym_parent, +struct branch_info *bi, +struct mem_info *mi, +struct perf_sample *sample, +bool sample_self) +{ +return __hists__add_entry (hists, al, sym_parent, bi, mi, + sample, sample_self, ops); +} +static int iter_next_nop_entry (struct hist_entry_iter *iter__maybe_unused ,struct addr_location *al__maybe_unused )
tools/perf/util/hist.h +11 -0
@@ -10,6 +10,7 @@#include "ui/progress.h" struct hist_entry ; +struct hist_entry_ops ;struct addr_location ;struct symbol ;
@@ -127,6 +128,16 @@ struct hist_entry *hists__add_entry(struct hists *hists,struct mem_info *mi, struct perf_sample *sample, bool sample_self); + +struct hist_entry *hists__add_entry_ops (struct hists *hists, +struct hist_entry_ops *ops, +struct addr_location *al, +struct symbol *sym_parent, +struct branch_info *bi, +struct mem_info *mi, +struct perf_sample *sample, +bool sample_self); +int hist_entry_iter__add (struct hist_entry_iter *iter,struct addr_location *al,int max_stack_depth,void *arg);
Signature · 1 line
2.4.11
tip-bot for Jiri Olsa
merge bot[tip:perf/core] perf hists: Introduce hists__add_entry_ops function
perf hists: Introduce hists__add_entry_ops function
Commit-ID: a5051979f533afc65112cc42a20f25db08bf2272 Gitweb: http://git.kernel.org/tip/a5051979f533afc65112cc42a20f25db08bf2272 Author: Jiri Olsa <[email protected]> AuthorDate: Tue, 5 Jul 2016 08:56:05 +0200 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Tue, 12 Jul 2016 00:00:39 -0300
perf hists: Introduce hists__add_entry_ops function
Introducing hists__add_entry_ops function to allow using the allocation callbacks externally.
--- tools/perf/util/hist.c | 42 +++++++++++++++++++++++++++++++++++------- tools/perf/util/hist.h | 11 +++++++++++ 2 files changed, 46 insertions(+), 7 deletions(-)
tools/perf/util/hist.c +35 -7
@@ -559,13 +559,15 @@ out:return he; } -struct hist_entry *hists__add_entry (struct hists *hists, -struct addr_location *al, -struct symbol *sym_parent, -struct branch_info *bi, -struct mem_info *mi, -struct perf_sample *sample, -bool sample_self) +static struct hist_entry * +__hists__add_entry (struct hists *hists, +struct addr_location *al, +struct symbol *sym_parent, +struct branch_info *bi, +struct mem_info *mi, +struct perf_sample *sample, +bool sample_self, +struct hist_entry_ops *ops) {struct hist_entry entry = { .thread = al->thread,
@@ -592,11 +594,37 @@ struct hist_entry *hists__add_entry(struct hists *hists, .transaction = sample->transaction, .raw_data = sample->raw_data, .raw_size = sample->raw_size, + .ops = ops, };return hists__findnew_entry (hists, &entry, al, sample_self); } +struct hist_entry *hists__add_entry (struct hists *hists, +struct addr_location *al, +struct symbol *sym_parent, +struct branch_info *bi, +struct mem_info *mi, +struct perf_sample *sample, +bool sample_self) +{ +return __hists__add_entry (hists, al, sym_parent, bi, mi, + sample, sample_self,NULL ); +} + +struct hist_entry *hists__add_entry_ops (struct hists *hists, +struct hist_entry_ops *ops, +struct addr_location *al, +struct symbol *sym_parent, +struct branch_info *bi, +struct mem_info *mi, +struct perf_sample *sample, +bool sample_self) +{ +return __hists__add_entry (hists, al, sym_parent, bi, mi, + sample, sample_self, ops); +} +static int iter_next_nop_entry (struct hist_entry_iter *iter__maybe_unused ,struct addr_location *al__maybe_unused )
tools/perf/util/hist.h +11 -0
@@ -10,6 +10,7 @@#include "ui/progress.h" struct hist_entry ; +struct hist_entry_ops ;struct addr_location ;struct symbol ;
@@ -127,6 +128,16 @@ struct hist_entry *hists__add_entry(struct hists *hists,struct mem_info *mi, struct perf_sample *sample, bool sample_self); + +struct hist_entry *hists__add_entry_ops (struct hists *hists, +struct hist_entry_ops *ops, +struct addr_location *al, +struct symbol *sym_parent, +struct branch_info *bi, +struct mem_info *mi, +struct perf_sample *sample, +bool sample_self); +int hist_entry_iter__add (struct hist_entry_iter *iter,struct addr_location *al,int max_stack_depth,void *arg);
Em Tue, Jul 05, 2016 at 08:56:02AM +0200, Jiri Olsa escreveu:
Quoted 6 lines
hi,
this patchset tries to add support provide own allocation zalloc/free methods forhist_entryobject.v2 changes:
- merged patch 1 and 2 from RFC
Thanks applied.