Skip to content

Commit d3e7cad

Browse files
committed
perf annotate: Add a hashmap for symbol histogram
Now symbol histogram uses an array to save per-offset sample counts. But it wastes a lot of memory if the symbol has a few samples only. Add a hashmap to save values only for actual samples. For now, it has duplicate histogram (one in the existing array and another in the new hash map). Once it can convert to use the hash in all places, we can get rid of the array later. Reviewed-by: Ian Rogers <[email protected]> Reviewed-by: Arnaldo Carvalho de Melo <[email protected]> Tested-by: Arnaldo Carvalho de Melo <[email protected]> Cc: Andi Kleen <[email protected]> Signed-off-by: Namhyung Kim <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 7bfc84b commit d3e7cad

File tree

2 files changed

+42
-2
lines changed

2 files changed

+42
-2
lines changed

tools/perf/util/annotate.c

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "arch/common.h"
3939
#include "namespaces.h"
4040
#include "thread.h"
41+
#include "hashmap.h"
4142
#include <regex.h>
4243
#include <linux/bitops.h>
4344
#include <linux/kernel.h>
@@ -863,6 +864,17 @@ bool arch__is(struct arch *arch, const char *name)
863864
return !strcmp(arch->name, name);
864865
}
865866

867+
/* symbol histogram: key = offset << 16 | evsel->core.idx */
868+
static size_t sym_hist_hash(long key, void *ctx __maybe_unused)
869+
{
870+
return (key >> 16) + (key & 0xffff);
871+
}
872+
873+
static bool sym_hist_equal(long key1, long key2, void *ctx __maybe_unused)
874+
{
875+
return key1 == key2;
876+
}
877+
866878
static struct annotated_source *annotated_source__new(void)
867879
{
868880
struct annotated_source *src = zalloc(sizeof(*src));
@@ -877,6 +889,8 @@ static __maybe_unused void annotated_source__delete(struct annotated_source *src
877889
{
878890
if (src == NULL)
879891
return;
892+
893+
hashmap__free(src->samples);
880894
zfree(&src->histograms);
881895
free(src);
882896
}
@@ -909,6 +923,14 @@ static int annotated_source__alloc_histograms(struct annotated_source *src,
909923
src->sizeof_sym_hist = sizeof_sym_hist;
910924
src->nr_histograms = nr_hists;
911925
src->histograms = calloc(nr_hists, sizeof_sym_hist) ;
926+
927+
if (src->histograms == NULL)
928+
return -1;
929+
930+
src->samples = hashmap__new(sym_hist_hash, sym_hist_equal, NULL);
931+
if (src->samples == NULL)
932+
zfree(&src->histograms);
933+
912934
return src->histograms ? 0 : -1;
913935
}
914936

@@ -920,6 +942,7 @@ void symbol__annotate_zero_histograms(struct symbol *sym)
920942
if (notes->src != NULL) {
921943
memset(notes->src->histograms, 0,
922944
notes->src->nr_histograms * notes->src->sizeof_sym_hist);
945+
hashmap__clear(notes->src->samples);
923946
}
924947
if (notes->branch && notes->branch->cycles_hist) {
925948
memset(notes->branch->cycles_hist, 0,
@@ -983,8 +1006,10 @@ static int __symbol__inc_addr_samples(struct map_symbol *ms,
9831006
struct perf_sample *sample)
9841007
{
9851008
struct symbol *sym = ms->sym;
986-
unsigned offset;
1009+
long hash_key;
1010+
u64 offset;
9871011
struct sym_hist *h;
1012+
struct sym_hist_entry *entry;
9881013

9891014
pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map__unmap_ip(ms->map, addr));
9901015

@@ -1002,15 +1027,28 @@ static int __symbol__inc_addr_samples(struct map_symbol *ms,
10021027
__func__, __LINE__, sym->name, sym->start, addr, sym->end, sym->type == STT_FUNC);
10031028
return -ENOMEM;
10041029
}
1030+
1031+
hash_key = offset << 16 | evidx;
1032+
if (!hashmap__find(src->samples, hash_key, &entry)) {
1033+
entry = zalloc(sizeof(*entry));
1034+
if (entry == NULL)
1035+
return -ENOMEM;
1036+
1037+
if (hashmap__add(src->samples, hash_key, entry) < 0)
1038+
return -ENOMEM;
1039+
}
1040+
10051041
h->nr_samples++;
10061042
h->addr[offset].nr_samples++;
10071043
h->period += sample->period;
10081044
h->addr[offset].period += sample->period;
1045+
entry->nr_samples++;
1046+
entry->period += sample->period;
10091047

10101048
pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64
10111049
", evidx=%d] => nr_samples: %" PRIu64 ", period: %" PRIu64 "\n",
10121050
sym->start, sym->name, addr, addr - sym->start, evidx,
1013-
h->addr[offset].nr_samples, h->addr[offset].period);
1051+
entry->nr_samples, entry->period);
10141052
return 0;
10151053
}
10161054

tools/perf/util/annotate.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "symbol_conf.h"
1313
#include "mutex.h"
1414
#include "spark.h"
15+
#include "hashmap.h"
1516

1617
struct hist_browser_timer;
1718
struct hist_entry;
@@ -280,6 +281,7 @@ struct annotated_source {
280281
size_t sizeof_sym_hist;
281282
struct sym_hist *histograms;
282283
struct annotation_line **offsets;
284+
struct hashmap *samples;
283285
int nr_histograms;
284286
int nr_entries;
285287
int nr_asm_entries;

0 commit comments

Comments
 (0)