aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorJiri Olsa <jolsa@redhat.com>2012-07-22 08:14:39 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2012-07-25 10:33:04 -0400
commit4dff624ae05bf3fb89f7653b3a55e7a5f1f1dadf (patch)
tree5cd5d244727d08afc07f8a5ef4e55d2f6f215994 /tools
parent949d160b6962c13fc071afefa22997780fcc94a5 (diff)
perf symbols: Add dso data caching
Adding dso data caching so we don't need to open/read/close, each time we want dso data. The DSO data caching affects following functions: dso__data_read_offset dso__data_read_addr Each DSO read tries to find the data (based on offset) inside the cache. If it's not present it fills the cache from file, and returns the data. If it is present, data are returned with no file read. Each data read is cached by reading cache page sized/aligned amount of DSO data. The cache page size is hardcoded to 4096. The cache is using RB tree with file offset as a sort key. Signed-off-by: Jiri Olsa <jolsa@redhat.com> Cc: Arun Sharma <asharma@fb.com> Cc: Benjamin Redelings <benjamin.redelings@nescent.org> Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com> Cc: Cyrill Gorcunov <gorcunov@openvz.org> Cc: Frank Ch. Eigler <fche@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Robert Richter <robert.richter@amd.com> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> Cc: Ulrich Drepper <drepper@gmail.com> Link: http://lkml.kernel.org/r/1342959280-5361-17-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/util/symbol.c154
-rw-r--r--tools/perf/util/symbol.h11
2 files changed, 147 insertions, 18 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 8131949d10f..fdad4eeeb42 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -29,6 +29,7 @@
29#define NT_GNU_BUILD_ID 3 29#define NT_GNU_BUILD_ID 3
30#endif 30#endif
31 31
32static void dso_cache__free(struct rb_root *root);
32static bool dso__build_id_equal(const struct dso *dso, u8 *build_id); 33static bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
33static int elf_read_build_id(Elf *elf, void *bf, size_t size); 34static int elf_read_build_id(Elf *elf, void *bf, size_t size);
34static void dsos__add(struct list_head *head, struct dso *dso); 35static void dsos__add(struct list_head *head, struct dso *dso);
@@ -343,6 +344,7 @@ struct dso *dso__new(const char *name)
343 dso__set_short_name(dso, dso->name); 344 dso__set_short_name(dso, dso->name);
344 for (i = 0; i < MAP__NR_TYPES; ++i) 345 for (i = 0; i < MAP__NR_TYPES; ++i)
345 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; 346 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
347 dso->cache = RB_ROOT;
346 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; 348 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
347 dso->data_type = DSO_BINARY_TYPE__NOT_FOUND; 349 dso->data_type = DSO_BINARY_TYPE__NOT_FOUND;
348 dso->loaded = 0; 350 dso->loaded = 0;
@@ -378,6 +380,7 @@ void dso__delete(struct dso *dso)
378 free((char *)dso->short_name); 380 free((char *)dso->short_name);
379 if (dso->lname_alloc) 381 if (dso->lname_alloc)
380 free(dso->long_name); 382 free(dso->long_name);
383 dso_cache__free(&dso->cache);
381 free(dso); 384 free(dso);
382} 385}
383 386
@@ -3008,22 +3011,87 @@ int dso__data_fd(struct dso *dso, struct machine *machine)
3008 return -EINVAL; 3011 return -EINVAL;
3009} 3012}
3010 3013
3011static ssize_t dso_cache_read(struct dso *dso __used, u64 offset __used, 3014static void
3012 u8 *data __used, ssize_t size __used) 3015dso_cache__free(struct rb_root *root)
3013{ 3016{
3014 return -EINVAL; 3017 struct rb_node *next = rb_first(root);
3018
3019 while (next) {
3020 struct dso_cache *cache;
3021
3022 cache = rb_entry(next, struct dso_cache, rb_node);
3023 next = rb_next(&cache->rb_node);
3024 rb_erase(&cache->rb_node, root);
3025 free(cache);
3026 }
3015} 3027}
3016 3028
3017static int dso_cache_add(struct dso *dso __used, u64 offset __used, 3029static struct dso_cache*
3018 u8 *data __used, ssize_t size __used) 3030dso_cache__find(struct rb_root *root, u64 offset)
3019{ 3031{
3020 return 0; 3032 struct rb_node **p = &root->rb_node;
3033 struct rb_node *parent = NULL;
3034 struct dso_cache *cache;
3035
3036 while (*p != NULL) {
3037 u64 end;
3038
3039 parent = *p;
3040 cache = rb_entry(parent, struct dso_cache, rb_node);
3041 end = cache->offset + DSO__DATA_CACHE_SIZE;
3042
3043 if (offset < cache->offset)
3044 p = &(*p)->rb_left;
3045 else if (offset >= end)
3046 p = &(*p)->rb_right;
3047 else
3048 return cache;
3049 }
3050 return NULL;
3051}
3052
3053static void
3054dso_cache__insert(struct rb_root *root, struct dso_cache *new)
3055{
3056 struct rb_node **p = &root->rb_node;
3057 struct rb_node *parent = NULL;
3058 struct dso_cache *cache;
3059 u64 offset = new->offset;
3060
3061 while (*p != NULL) {
3062 u64 end;
3063
3064 parent = *p;
3065 cache = rb_entry(parent, struct dso_cache, rb_node);
3066 end = cache->offset + DSO__DATA_CACHE_SIZE;
3067
3068 if (offset < cache->offset)
3069 p = &(*p)->rb_left;
3070 else if (offset >= end)
3071 p = &(*p)->rb_right;
3072 }
3073
3074 rb_link_node(&new->rb_node, parent, p);
3075 rb_insert_color(&new->rb_node, root);
3076}
3077
3078static ssize_t
3079dso_cache__memcpy(struct dso_cache *cache, u64 offset,
3080 u8 *data, u64 size)
3081{
3082 u64 cache_offset = offset - cache->offset;
3083 u64 cache_size = min(cache->size - cache_offset, size);
3084
3085 memcpy(data, cache->data + cache_offset, cache_size);
3086 return cache_size;
3021} 3087}
3022 3088
3023static ssize_t read_dso_data(struct dso *dso, struct machine *machine, 3089static ssize_t
3024 u64 offset, u8 *data, ssize_t size) 3090dso_cache__read(struct dso *dso, struct machine *machine,
3091 u64 offset, u8 *data, ssize_t size)
3025{ 3092{
3026 ssize_t rsize = -1; 3093 struct dso_cache *cache;
3094 ssize_t ret;
3027 int fd; 3095 int fd;
3028 3096
3029 fd = dso__data_fd(dso, machine); 3097 fd = dso__data_fd(dso, machine);
@@ -3031,28 +3099,78 @@ static ssize_t read_dso_data(struct dso *dso, struct machine *machine,
3031 return -1; 3099 return -1;
3032 3100
3033 do { 3101 do {
3034 if (-1 == lseek(fd, offset, SEEK_SET)) 3102 u64 cache_offset;
3103
3104 ret = -ENOMEM;
3105
3106 cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE);
3107 if (!cache)
3035 break; 3108 break;
3036 3109
3037 rsize = read(fd, data, size); 3110 cache_offset = offset & DSO__DATA_CACHE_MASK;
3038 if (-1 == rsize) 3111 ret = -EINVAL;
3112
3113 if (-1 == lseek(fd, cache_offset, SEEK_SET))
3039 break; 3114 break;
3040 3115
3041 if (dso_cache_add(dso, offset, data, size)) 3116 ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE);
3042 pr_err("Failed to add data int dso cache."); 3117 if (ret <= 0)
3118 break;
3119
3120 cache->offset = cache_offset;
3121 cache->size = ret;
3122 dso_cache__insert(&dso->cache, cache);
3123
3124 ret = dso_cache__memcpy(cache, offset, data, size);
3043 3125
3044 } while (0); 3126 } while (0);
3045 3127
3128 if (ret <= 0)
3129 free(cache);
3130
3046 close(fd); 3131 close(fd);
3047 return rsize; 3132 return ret;
3133}
3134
3135static ssize_t dso_cache_read(struct dso *dso, struct machine *machine,
3136 u64 offset, u8 *data, ssize_t size)
3137{
3138 struct dso_cache *cache;
3139
3140 cache = dso_cache__find(&dso->cache, offset);
3141 if (cache)
3142 return dso_cache__memcpy(cache, offset, data, size);
3143 else
3144 return dso_cache__read(dso, machine, offset, data, size);
3048} 3145}
3049 3146
3050ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, 3147ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
3051 u64 offset, u8 *data, ssize_t size) 3148 u64 offset, u8 *data, ssize_t size)
3052{ 3149{
3053 if (dso_cache_read(dso, offset, data, size)) 3150 ssize_t r = 0;
3054 return read_dso_data(dso, machine, offset, data, size); 3151 u8 *p = data;
3055 return 0; 3152
3153 do {
3154 ssize_t ret;
3155
3156 ret = dso_cache_read(dso, machine, offset, p, size);
3157 if (ret < 0)
3158 return ret;
3159
3160 /* Reached EOF, return what we have. */
3161 if (!ret)
3162 break;
3163
3164 BUG_ON(ret > size);
3165
3166 r += ret;
3167 p += ret;
3168 offset += ret;
3169 size -= ret;
3170
3171 } while (size);
3172
3173 return r;
3056} 3174}
3057 3175
3058ssize_t dso__data_read_addr(struct dso *dso, struct map *map, 3176ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 9b9ea00173a..980d5f57373 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -182,10 +182,21 @@ enum dso_swap_type {
182 DSO_SWAP__YES, 182 DSO_SWAP__YES,
183}; 183};
184 184
185#define DSO__DATA_CACHE_SIZE 4096
186#define DSO__DATA_CACHE_MASK ~(DSO__DATA_CACHE_SIZE - 1)
187
188struct dso_cache {
189 struct rb_node rb_node;
190 u64 offset;
191 u64 size;
192 char data[0];
193};
194
185struct dso { 195struct dso {
186 struct list_head node; 196 struct list_head node;
187 struct rb_root symbols[MAP__NR_TYPES]; 197 struct rb_root symbols[MAP__NR_TYPES];
188 struct rb_root symbol_names[MAP__NR_TYPES]; 198 struct rb_root symbol_names[MAP__NR_TYPES];
199 struct rb_root cache;
189 enum dso_kernel_type kernel; 200 enum dso_kernel_type kernel;
190 enum dso_swap_type needs_swap; 201 enum dso_swap_type needs_swap;
191 enum dso_binary_type symtab_type; 202 enum dso_binary_type symtab_type;