diff options
-rw-r--r-- | tools/perf/util/auxtrace.c | 123 | ||||
-rw-r--r-- | tools/perf/util/auxtrace.h | 14 |
2 files changed, 137 insertions, 0 deletions
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index c4515e1a9d7f..3cd89eca1e88 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c | |||
@@ -40,6 +40,8 @@ | |||
40 | #include "asm/bug.h" | 40 | #include "asm/bug.h" |
41 | #include "auxtrace.h" | 41 | #include "auxtrace.h" |
42 | 42 | ||
43 | #include <linux/hash.h> | ||
44 | |||
43 | #include "event.h" | 45 | #include "event.h" |
44 | #include "session.h" | 46 | #include "session.h" |
45 | #include "debug.h" | 47 | #include "debug.h" |
@@ -944,3 +946,124 @@ int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr, | |||
944 | 946 | ||
945 | return 1; | 947 | return 1; |
946 | } | 948 | } |
949 | |||
950 | /** | ||
951 | * struct auxtrace_cache - hash table to implement a cache | ||
952 | * @hashtable: the hashtable | ||
953 | * @sz: hashtable size (number of hlists) | ||
954 | * @entry_size: size of an entry | ||
955 | * @limit: limit the number of entries to this maximum, when reached the cache | ||
956 | * is dropped and caching begins again with an empty cache | ||
957 | * @cnt: current number of entries | ||
958 | * @bits: hashtable size (@sz = 2^@bits) | ||
959 | */ | ||
960 | struct auxtrace_cache { | ||
961 | struct hlist_head *hashtable; | ||
962 | size_t sz; | ||
963 | size_t entry_size; | ||
964 | size_t limit; | ||
965 | size_t cnt; | ||
966 | unsigned int bits; | ||
967 | }; | ||
968 | |||
969 | struct auxtrace_cache *auxtrace_cache__new(unsigned int bits, size_t entry_size, | ||
970 | unsigned int limit_percent) | ||
971 | { | ||
972 | struct auxtrace_cache *c; | ||
973 | struct hlist_head *ht; | ||
974 | size_t sz, i; | ||
975 | |||
976 | c = zalloc(sizeof(struct auxtrace_cache)); | ||
977 | if (!c) | ||
978 | return NULL; | ||
979 | |||
980 | sz = 1UL << bits; | ||
981 | |||
982 | ht = calloc(sz, sizeof(struct hlist_head)); | ||
983 | if (!ht) | ||
984 | goto out_free; | ||
985 | |||
986 | for (i = 0; i < sz; i++) | ||
987 | INIT_HLIST_HEAD(&ht[i]); | ||
988 | |||
989 | c->hashtable = ht; | ||
990 | c->sz = sz; | ||
991 | c->entry_size = entry_size; | ||
992 | c->limit = (c->sz * limit_percent) / 100; | ||
993 | c->bits = bits; | ||
994 | |||
995 | return c; | ||
996 | |||
997 | out_free: | ||
998 | free(c); | ||
999 | return NULL; | ||
1000 | } | ||
1001 | |||
1002 | static void auxtrace_cache__drop(struct auxtrace_cache *c) | ||
1003 | { | ||
1004 | struct auxtrace_cache_entry *entry; | ||
1005 | struct hlist_node *tmp; | ||
1006 | size_t i; | ||
1007 | |||
1008 | if (!c) | ||
1009 | return; | ||
1010 | |||
1011 | for (i = 0; i < c->sz; i++) { | ||
1012 | hlist_for_each_entry_safe(entry, tmp, &c->hashtable[i], hash) { | ||
1013 | hlist_del(&entry->hash); | ||
1014 | auxtrace_cache__free_entry(c, entry); | ||
1015 | } | ||
1016 | } | ||
1017 | |||
1018 | c->cnt = 0; | ||
1019 | } | ||
1020 | |||
1021 | void auxtrace_cache__free(struct auxtrace_cache *c) | ||
1022 | { | ||
1023 | if (!c) | ||
1024 | return; | ||
1025 | |||
1026 | auxtrace_cache__drop(c); | ||
1027 | free(c->hashtable); | ||
1028 | free(c); | ||
1029 | } | ||
1030 | |||
1031 | void *auxtrace_cache__alloc_entry(struct auxtrace_cache *c) | ||
1032 | { | ||
1033 | return malloc(c->entry_size); | ||
1034 | } | ||
1035 | |||
1036 | void auxtrace_cache__free_entry(struct auxtrace_cache *c __maybe_unused, | ||
1037 | void *entry) | ||
1038 | { | ||
1039 | free(entry); | ||
1040 | } | ||
1041 | |||
1042 | int auxtrace_cache__add(struct auxtrace_cache *c, u32 key, | ||
1043 | struct auxtrace_cache_entry *entry) | ||
1044 | { | ||
1045 | if (c->limit && ++c->cnt > c->limit) | ||
1046 | auxtrace_cache__drop(c); | ||
1047 | |||
1048 | entry->key = key; | ||
1049 | hlist_add_head(&entry->hash, &c->hashtable[hash_32(key, c->bits)]); | ||
1050 | |||
1051 | return 0; | ||
1052 | } | ||
1053 | |||
1054 | void *auxtrace_cache__lookup(struct auxtrace_cache *c, u32 key) | ||
1055 | { | ||
1056 | struct auxtrace_cache_entry *entry; | ||
1057 | struct hlist_head *hlist; | ||
1058 | |||
1059 | if (!c) | ||
1060 | return NULL; | ||
1061 | |||
1062 | hlist = &c->hashtable[hash_32(key, c->bits)]; | ||
1063 | hlist_for_each_entry(entry, hlist, hash) { | ||
1064 | if (entry->key == key) | ||
1065 | return entry; | ||
1066 | } | ||
1067 | |||
1068 | return NULL; | ||
1069 | } | ||
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index ba78d825bf73..53b60a64a693 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h | |||
@@ -333,6 +333,20 @@ int auxtrace_heap__add(struct auxtrace_heap *heap, unsigned int queue_nr, | |||
333 | void auxtrace_heap__pop(struct auxtrace_heap *heap); | 333 | void auxtrace_heap__pop(struct auxtrace_heap *heap); |
334 | void auxtrace_heap__free(struct auxtrace_heap *heap); | 334 | void auxtrace_heap__free(struct auxtrace_heap *heap); |
335 | 335 | ||
336 | struct auxtrace_cache_entry { | ||
337 | struct hlist_node hash; | ||
338 | u32 key; | ||
339 | }; | ||
340 | |||
341 | struct auxtrace_cache *auxtrace_cache__new(unsigned int bits, size_t entry_size, | ||
342 | unsigned int limit_percent); | ||
343 | void auxtrace_cache__free(struct auxtrace_cache *auxtrace_cache); | ||
344 | void *auxtrace_cache__alloc_entry(struct auxtrace_cache *c); | ||
345 | void auxtrace_cache__free_entry(struct auxtrace_cache *c, void *entry); | ||
346 | int auxtrace_cache__add(struct auxtrace_cache *c, u32 key, | ||
347 | struct auxtrace_cache_entry *entry); | ||
348 | void *auxtrace_cache__lookup(struct auxtrace_cache *c, u32 key); | ||
349 | |||
336 | struct auxtrace_record *auxtrace_record__init(struct perf_evlist *evlist, | 350 | struct auxtrace_record *auxtrace_record__init(struct perf_evlist *evlist, |
337 | int *err); | 351 | int *err); |
338 | 352 | ||