1ba77c9e1SLi Zefan #include "builtin.h" 2ba77c9e1SLi Zefan #include "perf.h" 3ba77c9e1SLi Zefan 4ba77c9e1SLi Zefan #include "util/util.h" 5ba77c9e1SLi Zefan #include "util/cache.h" 6ba77c9e1SLi Zefan #include "util/symbol.h" 7ba77c9e1SLi Zefan #include "util/thread.h" 8ba77c9e1SLi Zefan #include "util/header.h" 9ba77c9e1SLi Zefan 10ba77c9e1SLi Zefan #include "util/parse-options.h" 11ba77c9e1SLi Zefan #include "util/trace-event.h" 12ba77c9e1SLi Zefan 13ba77c9e1SLi Zefan #include "util/debug.h" 14ba77c9e1SLi Zefan #include "util/data_map.h" 15ba77c9e1SLi Zefan 16ba77c9e1SLi Zefan #include <linux/rbtree.h> 17ba77c9e1SLi Zefan 18ba77c9e1SLi Zefan struct alloc_stat; 19ba77c9e1SLi Zefan typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *); 20ba77c9e1SLi Zefan 21ba77c9e1SLi Zefan static char const *input_name = "perf.data"; 22ba77c9e1SLi Zefan 23ba77c9e1SLi Zefan static struct perf_header *header; 24ba77c9e1SLi Zefan static u64 sample_type; 25ba77c9e1SLi Zefan 26ba77c9e1SLi Zefan static int alloc_flag; 27ba77c9e1SLi Zefan static int caller_flag; 28ba77c9e1SLi Zefan 29ba77c9e1SLi Zefan static int alloc_lines = -1; 30ba77c9e1SLi Zefan static int caller_lines = -1; 31ba77c9e1SLi Zefan 327707b6b6SLi Zefan static bool raw_ip; 337707b6b6SLi Zefan 34*29b3e152SLi Zefan static char default_sort_order[] = "frag,hit,bytes"; 35*29b3e152SLi Zefan 36ba77c9e1SLi Zefan static char *cwd; 37ba77c9e1SLi Zefan static int cwdlen; 38ba77c9e1SLi Zefan 39ba77c9e1SLi Zefan struct alloc_stat { 40ba77c9e1SLi Zefan union { 41ba77c9e1SLi Zefan u64 call_site; 42ba77c9e1SLi Zefan u64 ptr; 43ba77c9e1SLi Zefan }; 44ba77c9e1SLi Zefan u64 bytes_req; 45ba77c9e1SLi Zefan u64 bytes_alloc; 46ba77c9e1SLi Zefan u32 hit; 47ba77c9e1SLi Zefan 48ba77c9e1SLi Zefan struct rb_node node; 49ba77c9e1SLi Zefan }; 50ba77c9e1SLi Zefan 51ba77c9e1SLi Zefan static struct rb_root root_alloc_stat; 52ba77c9e1SLi Zefan static struct rb_root root_alloc_sorted; 53ba77c9e1SLi Zefan static struct rb_root root_caller_stat; 54ba77c9e1SLi Zefan static struct rb_root root_caller_sorted; 55ba77c9e1SLi Zefan 56ba77c9e1SLi Zefan static unsigned long total_requested, total_allocated; 57ba77c9e1SLi Zefan 58ba77c9e1SLi Zefan struct raw_event_sample { 59ba77c9e1SLi Zefan u32 size; 60ba77c9e1SLi Zefan char data[0]; 61ba77c9e1SLi Zefan }; 62ba77c9e1SLi Zefan 63ba77c9e1SLi Zefan static int 64ba77c9e1SLi Zefan process_comm_event(event_t *event, unsigned long offset, unsigned long head) 65ba77c9e1SLi Zefan { 66ba77c9e1SLi Zefan struct thread *thread = threads__findnew(event->comm.pid); 67ba77c9e1SLi Zefan 68ba77c9e1SLi Zefan dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", 69ba77c9e1SLi Zefan (void *)(offset + head), 70ba77c9e1SLi Zefan (void *)(long)(event->header.size), 71ba77c9e1SLi Zefan event->comm.comm, event->comm.pid); 72ba77c9e1SLi Zefan 73ba77c9e1SLi Zefan if (thread == NULL || 74ba77c9e1SLi Zefan thread__set_comm(thread, event->comm.comm)) { 75ba77c9e1SLi Zefan dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 76ba77c9e1SLi Zefan return -1; 77ba77c9e1SLi Zefan } 78ba77c9e1SLi Zefan 79ba77c9e1SLi Zefan return 0; 80ba77c9e1SLi Zefan } 81ba77c9e1SLi Zefan 82ba77c9e1SLi Zefan static void insert_alloc_stat(unsigned long ptr, 83ba77c9e1SLi Zefan int bytes_req, int bytes_alloc) 84ba77c9e1SLi Zefan { 85ba77c9e1SLi Zefan struct rb_node **node = &root_alloc_stat.rb_node; 86ba77c9e1SLi Zefan struct rb_node *parent = NULL; 87ba77c9e1SLi Zefan struct alloc_stat *data = NULL; 88ba77c9e1SLi Zefan 89ba77c9e1SLi Zefan if (!alloc_flag) 90ba77c9e1SLi Zefan return; 91ba77c9e1SLi Zefan 92ba77c9e1SLi Zefan while (*node) { 93ba77c9e1SLi Zefan parent = *node; 94ba77c9e1SLi Zefan data = rb_entry(*node, struct alloc_stat, node); 95ba77c9e1SLi Zefan 96ba77c9e1SLi Zefan if (ptr > data->ptr) 97ba77c9e1SLi Zefan node = &(*node)->rb_right; 98ba77c9e1SLi Zefan else if (ptr < data->ptr) 99ba77c9e1SLi Zefan node = &(*node)->rb_left; 100ba77c9e1SLi Zefan else 101ba77c9e1SLi Zefan break; 102ba77c9e1SLi Zefan } 103ba77c9e1SLi Zefan 104ba77c9e1SLi Zefan if (data && data->ptr == ptr) { 105ba77c9e1SLi Zefan data->hit++; 106ba77c9e1SLi Zefan data->bytes_req += bytes_req; 107ba77c9e1SLi Zefan data->bytes_alloc += bytes_req; 108ba77c9e1SLi Zefan } else { 109ba77c9e1SLi Zefan data = malloc(sizeof(*data)); 110ba77c9e1SLi Zefan data->ptr = ptr; 111ba77c9e1SLi Zefan data->hit = 1; 112ba77c9e1SLi Zefan data->bytes_req = bytes_req; 113ba77c9e1SLi Zefan data->bytes_alloc = bytes_alloc; 114ba77c9e1SLi Zefan 115ba77c9e1SLi Zefan rb_link_node(&data->node, parent, node); 116ba77c9e1SLi Zefan rb_insert_color(&data->node, &root_alloc_stat); 117ba77c9e1SLi Zefan } 118ba77c9e1SLi Zefan } 119ba77c9e1SLi Zefan 120ba77c9e1SLi Zefan static void insert_caller_stat(unsigned long call_site, 121ba77c9e1SLi Zefan int bytes_req, int bytes_alloc) 122ba77c9e1SLi Zefan { 123ba77c9e1SLi Zefan struct rb_node **node = &root_caller_stat.rb_node; 124ba77c9e1SLi Zefan struct rb_node *parent = NULL; 125ba77c9e1SLi Zefan struct alloc_stat *data = NULL; 126ba77c9e1SLi Zefan 127ba77c9e1SLi Zefan if (!caller_flag) 128ba77c9e1SLi Zefan return; 129ba77c9e1SLi Zefan 130ba77c9e1SLi Zefan while (*node) { 131ba77c9e1SLi Zefan parent = *node; 132ba77c9e1SLi Zefan data = rb_entry(*node, struct alloc_stat, node); 133ba77c9e1SLi Zefan 134ba77c9e1SLi Zefan if (call_site > data->call_site) 135ba77c9e1SLi Zefan node = &(*node)->rb_right; 136ba77c9e1SLi Zefan else if (call_site < data->call_site) 137ba77c9e1SLi Zefan node = &(*node)->rb_left; 138ba77c9e1SLi Zefan else 139ba77c9e1SLi Zefan break; 140ba77c9e1SLi Zefan } 141ba77c9e1SLi Zefan 142ba77c9e1SLi Zefan if (data && data->call_site == call_site) { 143ba77c9e1SLi Zefan data->hit++; 144ba77c9e1SLi Zefan data->bytes_req += bytes_req; 145ba77c9e1SLi Zefan data->bytes_alloc += bytes_req; 146ba77c9e1SLi Zefan } else { 147ba77c9e1SLi Zefan data = malloc(sizeof(*data)); 148ba77c9e1SLi Zefan data->call_site = call_site; 149ba77c9e1SLi Zefan data->hit = 1; 150ba77c9e1SLi Zefan data->bytes_req = bytes_req; 151ba77c9e1SLi Zefan data->bytes_alloc = bytes_alloc; 152ba77c9e1SLi Zefan 153ba77c9e1SLi Zefan rb_link_node(&data->node, parent, node); 154ba77c9e1SLi Zefan rb_insert_color(&data->node, &root_caller_stat); 155ba77c9e1SLi Zefan } 156ba77c9e1SLi Zefan } 157ba77c9e1SLi Zefan 158ba77c9e1SLi Zefan static void process_alloc_event(struct raw_event_sample *raw, 159ba77c9e1SLi Zefan struct event *event, 160ba77c9e1SLi Zefan int cpu __used, 161ba77c9e1SLi Zefan u64 timestamp __used, 162ba77c9e1SLi Zefan struct thread *thread __used, 163ba77c9e1SLi Zefan int node __used) 164ba77c9e1SLi Zefan { 165ba77c9e1SLi Zefan unsigned long call_site; 166ba77c9e1SLi Zefan unsigned long ptr; 167ba77c9e1SLi Zefan int bytes_req; 168ba77c9e1SLi Zefan int bytes_alloc; 169ba77c9e1SLi Zefan 170ba77c9e1SLi Zefan ptr = raw_field_value(event, "ptr", raw->data); 171ba77c9e1SLi Zefan call_site = raw_field_value(event, "call_site", raw->data); 172ba77c9e1SLi Zefan bytes_req = raw_field_value(event, "bytes_req", raw->data); 173ba77c9e1SLi Zefan bytes_alloc = raw_field_value(event, "bytes_alloc", raw->data); 174ba77c9e1SLi Zefan 175ba77c9e1SLi Zefan insert_alloc_stat(ptr, bytes_req, bytes_alloc); 176ba77c9e1SLi Zefan insert_caller_stat(call_site, bytes_req, bytes_alloc); 177ba77c9e1SLi Zefan 178ba77c9e1SLi Zefan total_requested += bytes_req; 179ba77c9e1SLi Zefan total_allocated += bytes_alloc; 180ba77c9e1SLi Zefan } 181ba77c9e1SLi Zefan 182ba77c9e1SLi Zefan static void process_free_event(struct raw_event_sample *raw __used, 183ba77c9e1SLi Zefan struct event *event __used, 184ba77c9e1SLi Zefan int cpu __used, 185ba77c9e1SLi Zefan u64 timestamp __used, 186ba77c9e1SLi Zefan struct thread *thread __used) 187ba77c9e1SLi Zefan { 188ba77c9e1SLi Zefan } 189ba77c9e1SLi Zefan 190ba77c9e1SLi Zefan static void 191ba77c9e1SLi Zefan process_raw_event(event_t *raw_event __used, void *more_data, 192ba77c9e1SLi Zefan int cpu, u64 timestamp, struct thread *thread) 193ba77c9e1SLi Zefan { 194ba77c9e1SLi Zefan struct raw_event_sample *raw = more_data; 195ba77c9e1SLi Zefan struct event *event; 196ba77c9e1SLi Zefan int type; 197ba77c9e1SLi Zefan 198ba77c9e1SLi Zefan type = trace_parse_common_type(raw->data); 199ba77c9e1SLi Zefan event = trace_find_event(type); 200ba77c9e1SLi Zefan 201ba77c9e1SLi Zefan if (!strcmp(event->name, "kmalloc") || 202ba77c9e1SLi Zefan !strcmp(event->name, "kmem_cache_alloc")) { 203ba77c9e1SLi Zefan process_alloc_event(raw, event, cpu, timestamp, thread, 0); 204ba77c9e1SLi Zefan return; 205ba77c9e1SLi Zefan } 206ba77c9e1SLi Zefan 207ba77c9e1SLi Zefan if (!strcmp(event->name, "kmalloc_node") || 208ba77c9e1SLi Zefan !strcmp(event->name, "kmem_cache_alloc_node")) { 209ba77c9e1SLi Zefan process_alloc_event(raw, event, cpu, timestamp, thread, 1); 210ba77c9e1SLi Zefan return; 211ba77c9e1SLi Zefan } 212ba77c9e1SLi Zefan 213ba77c9e1SLi Zefan if (!strcmp(event->name, "kfree") || 214ba77c9e1SLi Zefan !strcmp(event->name, "kmem_cache_free")) { 215ba77c9e1SLi Zefan process_free_event(raw, event, cpu, timestamp, thread); 216ba77c9e1SLi Zefan return; 217ba77c9e1SLi Zefan } 218ba77c9e1SLi Zefan } 219ba77c9e1SLi Zefan 220ba77c9e1SLi Zefan static int 221ba77c9e1SLi Zefan process_sample_event(event_t *event, unsigned long offset, unsigned long head) 222ba77c9e1SLi Zefan { 223ba77c9e1SLi Zefan u64 ip = event->ip.ip; 224ba77c9e1SLi Zefan u64 timestamp = -1; 225ba77c9e1SLi Zefan u32 cpu = -1; 226ba77c9e1SLi Zefan u64 period = 1; 227ba77c9e1SLi Zefan void *more_data = event->ip.__more_data; 228ba77c9e1SLi Zefan struct thread *thread = threads__findnew(event->ip.pid); 229ba77c9e1SLi Zefan 230ba77c9e1SLi Zefan if (sample_type & PERF_SAMPLE_TIME) { 231ba77c9e1SLi Zefan timestamp = *(u64 *)more_data; 232ba77c9e1SLi Zefan more_data += sizeof(u64); 233ba77c9e1SLi Zefan } 234ba77c9e1SLi Zefan 235ba77c9e1SLi Zefan if (sample_type & PERF_SAMPLE_CPU) { 236ba77c9e1SLi Zefan cpu = *(u32 *)more_data; 237ba77c9e1SLi Zefan more_data += sizeof(u32); 238ba77c9e1SLi Zefan more_data += sizeof(u32); /* reserved */ 239ba77c9e1SLi Zefan } 240ba77c9e1SLi Zefan 241ba77c9e1SLi Zefan if (sample_type & PERF_SAMPLE_PERIOD) { 242ba77c9e1SLi Zefan period = *(u64 *)more_data; 243ba77c9e1SLi Zefan more_data += sizeof(u64); 244ba77c9e1SLi Zefan } 245ba77c9e1SLi Zefan 246ba77c9e1SLi Zefan dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", 247ba77c9e1SLi Zefan (void *)(offset + head), 248ba77c9e1SLi Zefan (void *)(long)(event->header.size), 249ba77c9e1SLi Zefan event->header.misc, 250ba77c9e1SLi Zefan event->ip.pid, event->ip.tid, 251ba77c9e1SLi Zefan (void *)(long)ip, 252ba77c9e1SLi Zefan (long long)period); 253ba77c9e1SLi Zefan 254ba77c9e1SLi Zefan if (thread == NULL) { 255ba77c9e1SLi Zefan pr_debug("problem processing %d event, skipping it.\n", 256ba77c9e1SLi Zefan event->header.type); 257ba77c9e1SLi Zefan return -1; 258ba77c9e1SLi Zefan } 259ba77c9e1SLi Zefan 260ba77c9e1SLi Zefan dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 261ba77c9e1SLi Zefan 262ba77c9e1SLi Zefan process_raw_event(event, more_data, cpu, timestamp, thread); 263ba77c9e1SLi Zefan 264ba77c9e1SLi Zefan return 0; 265ba77c9e1SLi Zefan } 266ba77c9e1SLi Zefan 267ba77c9e1SLi Zefan static int sample_type_check(u64 type) 268ba77c9e1SLi Zefan { 269ba77c9e1SLi Zefan sample_type = type; 270ba77c9e1SLi Zefan 271ba77c9e1SLi Zefan if (!(sample_type & PERF_SAMPLE_RAW)) { 272ba77c9e1SLi Zefan fprintf(stderr, 273ba77c9e1SLi Zefan "No trace sample to read. Did you call perf record " 274ba77c9e1SLi Zefan "without -R?"); 275ba77c9e1SLi Zefan return -1; 276ba77c9e1SLi Zefan } 277ba77c9e1SLi Zefan 278ba77c9e1SLi Zefan return 0; 279ba77c9e1SLi Zefan } 280ba77c9e1SLi Zefan 281ba77c9e1SLi Zefan static struct perf_file_handler file_handler = { 282ba77c9e1SLi Zefan .process_sample_event = process_sample_event, 283ba77c9e1SLi Zefan .process_comm_event = process_comm_event, 284ba77c9e1SLi Zefan .sample_type_check = sample_type_check, 285ba77c9e1SLi Zefan }; 286ba77c9e1SLi Zefan 287ba77c9e1SLi Zefan static int read_events(void) 288ba77c9e1SLi Zefan { 289ba77c9e1SLi Zefan register_idle_thread(); 290ba77c9e1SLi Zefan register_perf_file_handler(&file_handler); 291ba77c9e1SLi Zefan 292cc612d81SArnaldo Carvalho de Melo return mmap_dispatch_perf_file(&header, input_name, NULL, false, 0, 0, 293ba77c9e1SLi Zefan &cwdlen, &cwd); 294ba77c9e1SLi Zefan } 295ba77c9e1SLi Zefan 296ba77c9e1SLi Zefan static double fragmentation(unsigned long n_req, unsigned long n_alloc) 297ba77c9e1SLi Zefan { 298ba77c9e1SLi Zefan if (n_alloc == 0) 299ba77c9e1SLi Zefan return 0.0; 300ba77c9e1SLi Zefan else 301ba77c9e1SLi Zefan return 100.0 - (100.0 * n_req / n_alloc); 302ba77c9e1SLi Zefan } 303ba77c9e1SLi Zefan 304ba77c9e1SLi Zefan static void __print_result(struct rb_root *root, int n_lines, int is_caller) 305ba77c9e1SLi Zefan { 306ba77c9e1SLi Zefan struct rb_node *next; 307ba77c9e1SLi Zefan 3081b145ae5SArnaldo Carvalho de Melo printf("%.78s\n", graph_dotted_line); 3091b145ae5SArnaldo Carvalho de Melo printf("%-28s|", is_caller ? "Callsite": "Alloc Ptr"); 3101b145ae5SArnaldo Carvalho de Melo printf("Total_alloc/Per | Total_req/Per | Hit | Frag\n"); 3111b145ae5SArnaldo Carvalho de Melo printf("%.78s\n", graph_dotted_line); 312ba77c9e1SLi Zefan 313ba77c9e1SLi Zefan next = rb_first(root); 314ba77c9e1SLi Zefan 315ba77c9e1SLi Zefan while (next && n_lines--) { 3161b145ae5SArnaldo Carvalho de Melo struct alloc_stat *data = rb_entry(next, struct alloc_stat, 3171b145ae5SArnaldo Carvalho de Melo node); 3181b145ae5SArnaldo Carvalho de Melo struct symbol *sym = NULL; 3191b145ae5SArnaldo Carvalho de Melo char bf[BUFSIZ]; 3201b145ae5SArnaldo Carvalho de Melo u64 addr; 321ba77c9e1SLi Zefan 3221b145ae5SArnaldo Carvalho de Melo if (is_caller) { 3231b145ae5SArnaldo Carvalho de Melo addr = data->call_site; 3247707b6b6SLi Zefan if (!raw_ip) 3257707b6b6SLi Zefan sym = kernel_maps__find_symbol(addr, 3267707b6b6SLi Zefan NULL, NULL); 3271b145ae5SArnaldo Carvalho de Melo } else 3281b145ae5SArnaldo Carvalho de Melo addr = data->ptr; 329ba77c9e1SLi Zefan 3301b145ae5SArnaldo Carvalho de Melo if (sym != NULL) 3317707b6b6SLi Zefan snprintf(bf, sizeof(bf), "%s+%Lx", sym->name, 3321b145ae5SArnaldo Carvalho de Melo addr - sym->start); 3331b145ae5SArnaldo Carvalho de Melo else 3341b145ae5SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "%#Lx", addr); 3351b145ae5SArnaldo Carvalho de Melo 3361b145ae5SArnaldo Carvalho de Melo printf("%-28s|%8llu/%-6lu |%8llu/%-6lu|%6lu|%8.3f%%\n", 3371b145ae5SArnaldo Carvalho de Melo bf, (unsigned long long)data->bytes_alloc, 338ba77c9e1SLi Zefan (unsigned long)data->bytes_alloc / data->hit, 339ba77c9e1SLi Zefan (unsigned long long)data->bytes_req, 340ba77c9e1SLi Zefan (unsigned long)data->bytes_req / data->hit, 341ba77c9e1SLi Zefan (unsigned long)data->hit, 342ba77c9e1SLi Zefan fragmentation(data->bytes_req, data->bytes_alloc)); 343ba77c9e1SLi Zefan 344ba77c9e1SLi Zefan next = rb_next(next); 345ba77c9e1SLi Zefan } 346ba77c9e1SLi Zefan 347ba77c9e1SLi Zefan if (n_lines == -1) 348ba77c9e1SLi Zefan printf(" ... | ... | ... | ... | ... \n"); 349ba77c9e1SLi Zefan 3507707b6b6SLi Zefan printf("%.78s\n", graph_dotted_line); 351ba77c9e1SLi Zefan } 352ba77c9e1SLi Zefan 353ba77c9e1SLi Zefan static void print_summary(void) 354ba77c9e1SLi Zefan { 355ba77c9e1SLi Zefan printf("\nSUMMARY\n=======\n"); 356ba77c9e1SLi Zefan printf("Total bytes requested: %lu\n", total_requested); 357ba77c9e1SLi Zefan printf("Total bytes allocated: %lu\n", total_allocated); 358ba77c9e1SLi Zefan printf("Total bytes wasted on internal fragmentation: %lu\n", 359ba77c9e1SLi Zefan total_allocated - total_requested); 360ba77c9e1SLi Zefan printf("Internal fragmentation: %f%%\n", 361ba77c9e1SLi Zefan fragmentation(total_requested, total_allocated)); 362ba77c9e1SLi Zefan } 363ba77c9e1SLi Zefan 364ba77c9e1SLi Zefan static void print_result(void) 365ba77c9e1SLi Zefan { 366ba77c9e1SLi Zefan if (caller_flag) 367ba77c9e1SLi Zefan __print_result(&root_caller_sorted, caller_lines, 1); 368ba77c9e1SLi Zefan if (alloc_flag) 369ba77c9e1SLi Zefan __print_result(&root_alloc_sorted, alloc_lines, 0); 370ba77c9e1SLi Zefan print_summary(); 371ba77c9e1SLi Zefan } 372ba77c9e1SLi Zefan 373*29b3e152SLi Zefan struct sort_dimension { 374*29b3e152SLi Zefan const char name[20]; 375*29b3e152SLi Zefan sort_fn_t cmp; 376*29b3e152SLi Zefan struct list_head list; 377*29b3e152SLi Zefan }; 378*29b3e152SLi Zefan 379*29b3e152SLi Zefan static LIST_HEAD(caller_sort); 380*29b3e152SLi Zefan static LIST_HEAD(alloc_sort); 381*29b3e152SLi Zefan 382ba77c9e1SLi Zefan static void sort_insert(struct rb_root *root, struct alloc_stat *data, 383*29b3e152SLi Zefan struct list_head *sort_list) 384ba77c9e1SLi Zefan { 385ba77c9e1SLi Zefan struct rb_node **new = &(root->rb_node); 386ba77c9e1SLi Zefan struct rb_node *parent = NULL; 387*29b3e152SLi Zefan struct sort_dimension *sort; 388ba77c9e1SLi Zefan 389ba77c9e1SLi Zefan while (*new) { 390ba77c9e1SLi Zefan struct alloc_stat *this; 391*29b3e152SLi Zefan int cmp = 0; 392ba77c9e1SLi Zefan 393ba77c9e1SLi Zefan this = rb_entry(*new, struct alloc_stat, node); 394ba77c9e1SLi Zefan parent = *new; 395ba77c9e1SLi Zefan 396*29b3e152SLi Zefan list_for_each_entry(sort, sort_list, list) { 397*29b3e152SLi Zefan cmp = sort->cmp(data, this); 398*29b3e152SLi Zefan if (cmp) 399*29b3e152SLi Zefan break; 400*29b3e152SLi Zefan } 401ba77c9e1SLi Zefan 402ba77c9e1SLi Zefan if (cmp > 0) 403ba77c9e1SLi Zefan new = &((*new)->rb_left); 404ba77c9e1SLi Zefan else 405ba77c9e1SLi Zefan new = &((*new)->rb_right); 406ba77c9e1SLi Zefan } 407ba77c9e1SLi Zefan 408ba77c9e1SLi Zefan rb_link_node(&data->node, parent, new); 409ba77c9e1SLi Zefan rb_insert_color(&data->node, root); 410ba77c9e1SLi Zefan } 411ba77c9e1SLi Zefan 412ba77c9e1SLi Zefan static void __sort_result(struct rb_root *root, struct rb_root *root_sorted, 413*29b3e152SLi Zefan struct list_head *sort_list) 414ba77c9e1SLi Zefan { 415ba77c9e1SLi Zefan struct rb_node *node; 416ba77c9e1SLi Zefan struct alloc_stat *data; 417ba77c9e1SLi Zefan 418ba77c9e1SLi Zefan for (;;) { 419ba77c9e1SLi Zefan node = rb_first(root); 420ba77c9e1SLi Zefan if (!node) 421ba77c9e1SLi Zefan break; 422ba77c9e1SLi Zefan 423ba77c9e1SLi Zefan rb_erase(node, root); 424ba77c9e1SLi Zefan data = rb_entry(node, struct alloc_stat, node); 425*29b3e152SLi Zefan sort_insert(root_sorted, data, sort_list); 426ba77c9e1SLi Zefan } 427ba77c9e1SLi Zefan } 428ba77c9e1SLi Zefan 429ba77c9e1SLi Zefan static void sort_result(void) 430ba77c9e1SLi Zefan { 431*29b3e152SLi Zefan __sort_result(&root_alloc_stat, &root_alloc_sorted, &alloc_sort); 432*29b3e152SLi Zefan __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort); 433ba77c9e1SLi Zefan } 434ba77c9e1SLi Zefan 435ba77c9e1SLi Zefan static int __cmd_kmem(void) 436ba77c9e1SLi Zefan { 437ba77c9e1SLi Zefan setup_pager(); 438ba77c9e1SLi Zefan read_events(); 439ba77c9e1SLi Zefan sort_result(); 440ba77c9e1SLi Zefan print_result(); 441ba77c9e1SLi Zefan 442ba77c9e1SLi Zefan return 0; 443ba77c9e1SLi Zefan } 444ba77c9e1SLi Zefan 445ba77c9e1SLi Zefan static const char * const kmem_usage[] = { 446ba77c9e1SLi Zefan "perf kmem [<options>] {record}", 447ba77c9e1SLi Zefan NULL 448ba77c9e1SLi Zefan }; 449ba77c9e1SLi Zefan 450ba77c9e1SLi Zefan static int ptr_cmp(struct alloc_stat *l, struct alloc_stat *r) 451ba77c9e1SLi Zefan { 452ba77c9e1SLi Zefan if (l->ptr < r->ptr) 453ba77c9e1SLi Zefan return -1; 454ba77c9e1SLi Zefan else if (l->ptr > r->ptr) 455ba77c9e1SLi Zefan return 1; 456ba77c9e1SLi Zefan return 0; 457ba77c9e1SLi Zefan } 458ba77c9e1SLi Zefan 459*29b3e152SLi Zefan static struct sort_dimension ptr_sort_dimension = { 460*29b3e152SLi Zefan .name = "ptr", 461*29b3e152SLi Zefan .cmp = ptr_cmp, 462*29b3e152SLi Zefan }; 463*29b3e152SLi Zefan 464ba77c9e1SLi Zefan static int callsite_cmp(struct alloc_stat *l, struct alloc_stat *r) 465ba77c9e1SLi Zefan { 466ba77c9e1SLi Zefan if (l->call_site < r->call_site) 467ba77c9e1SLi Zefan return -1; 468ba77c9e1SLi Zefan else if (l->call_site > r->call_site) 469ba77c9e1SLi Zefan return 1; 470ba77c9e1SLi Zefan return 0; 471ba77c9e1SLi Zefan } 472ba77c9e1SLi Zefan 473*29b3e152SLi Zefan static struct sort_dimension callsite_sort_dimension = { 474*29b3e152SLi Zefan .name = "callsite", 475*29b3e152SLi Zefan .cmp = callsite_cmp, 476*29b3e152SLi Zefan }; 477*29b3e152SLi Zefan 478f3ced7cdSPekka Enberg static int hit_cmp(struct alloc_stat *l, struct alloc_stat *r) 479f3ced7cdSPekka Enberg { 480f3ced7cdSPekka Enberg if (l->hit < r->hit) 481f3ced7cdSPekka Enberg return -1; 482f3ced7cdSPekka Enberg else if (l->hit > r->hit) 483f3ced7cdSPekka Enberg return 1; 484f3ced7cdSPekka Enberg return 0; 485f3ced7cdSPekka Enberg } 486f3ced7cdSPekka Enberg 487*29b3e152SLi Zefan static struct sort_dimension hit_sort_dimension = { 488*29b3e152SLi Zefan .name = "hit", 489*29b3e152SLi Zefan .cmp = hit_cmp, 490*29b3e152SLi Zefan }; 491*29b3e152SLi Zefan 492ba77c9e1SLi Zefan static int bytes_cmp(struct alloc_stat *l, struct alloc_stat *r) 493ba77c9e1SLi Zefan { 494ba77c9e1SLi Zefan if (l->bytes_alloc < r->bytes_alloc) 495ba77c9e1SLi Zefan return -1; 496ba77c9e1SLi Zefan else if (l->bytes_alloc > r->bytes_alloc) 497ba77c9e1SLi Zefan return 1; 498ba77c9e1SLi Zefan return 0; 499ba77c9e1SLi Zefan } 500ba77c9e1SLi Zefan 501*29b3e152SLi Zefan static struct sort_dimension bytes_sort_dimension = { 502*29b3e152SLi Zefan .name = "bytes", 503*29b3e152SLi Zefan .cmp = bytes_cmp, 504*29b3e152SLi Zefan }; 505*29b3e152SLi Zefan 506f3ced7cdSPekka Enberg static int frag_cmp(struct alloc_stat *l, struct alloc_stat *r) 507f3ced7cdSPekka Enberg { 508f3ced7cdSPekka Enberg double x, y; 509f3ced7cdSPekka Enberg 510f3ced7cdSPekka Enberg x = fragmentation(l->bytes_req, l->bytes_alloc); 511f3ced7cdSPekka Enberg y = fragmentation(r->bytes_req, r->bytes_alloc); 512f3ced7cdSPekka Enberg 513f3ced7cdSPekka Enberg if (x < y) 514f3ced7cdSPekka Enberg return -1; 515f3ced7cdSPekka Enberg else if (x > y) 516f3ced7cdSPekka Enberg return 1; 517f3ced7cdSPekka Enberg return 0; 518f3ced7cdSPekka Enberg } 519f3ced7cdSPekka Enberg 520*29b3e152SLi Zefan static struct sort_dimension frag_sort_dimension = { 521*29b3e152SLi Zefan .name = "frag", 522*29b3e152SLi Zefan .cmp = frag_cmp, 523*29b3e152SLi Zefan }; 524*29b3e152SLi Zefan 525*29b3e152SLi Zefan static struct sort_dimension *avail_sorts[] = { 526*29b3e152SLi Zefan &ptr_sort_dimension, 527*29b3e152SLi Zefan &callsite_sort_dimension, 528*29b3e152SLi Zefan &hit_sort_dimension, 529*29b3e152SLi Zefan &bytes_sort_dimension, 530*29b3e152SLi Zefan &frag_sort_dimension, 531*29b3e152SLi Zefan }; 532*29b3e152SLi Zefan 533*29b3e152SLi Zefan #define NUM_AVAIL_SORTS \ 534*29b3e152SLi Zefan (int)(sizeof(avail_sorts) / sizeof(struct sort_dimension *)) 535*29b3e152SLi Zefan 536*29b3e152SLi Zefan static int sort_dimension__add(const char *tok, struct list_head *list) 537*29b3e152SLi Zefan { 538*29b3e152SLi Zefan struct sort_dimension *sort; 539*29b3e152SLi Zefan int i; 540*29b3e152SLi Zefan 541*29b3e152SLi Zefan for (i = 0; i < NUM_AVAIL_SORTS; i++) { 542*29b3e152SLi Zefan if (!strcmp(avail_sorts[i]->name, tok)) { 543*29b3e152SLi Zefan sort = malloc(sizeof(*sort)); 544*29b3e152SLi Zefan if (!sort) 545*29b3e152SLi Zefan die("malloc"); 546*29b3e152SLi Zefan memcpy(sort, avail_sorts[i], sizeof(*sort)); 547*29b3e152SLi Zefan list_add_tail(&sort->list, list); 548*29b3e152SLi Zefan return 0; 549*29b3e152SLi Zefan } 550*29b3e152SLi Zefan } 551*29b3e152SLi Zefan 552*29b3e152SLi Zefan return -1; 553*29b3e152SLi Zefan } 554*29b3e152SLi Zefan 555*29b3e152SLi Zefan static int setup_sorting(struct list_head *sort_list, const char *arg) 556*29b3e152SLi Zefan { 557*29b3e152SLi Zefan char *tok; 558*29b3e152SLi Zefan char *str = strdup(arg); 559*29b3e152SLi Zefan 560*29b3e152SLi Zefan if (!str) 561*29b3e152SLi Zefan die("strdup"); 562*29b3e152SLi Zefan 563*29b3e152SLi Zefan while (true) { 564*29b3e152SLi Zefan tok = strsep(&str, ","); 565*29b3e152SLi Zefan if (!tok) 566*29b3e152SLi Zefan break; 567*29b3e152SLi Zefan if (sort_dimension__add(tok, sort_list) < 0) { 568*29b3e152SLi Zefan error("Unknown --sort key: '%s'", tok); 569*29b3e152SLi Zefan return -1; 570*29b3e152SLi Zefan } 571*29b3e152SLi Zefan } 572*29b3e152SLi Zefan 573*29b3e152SLi Zefan free(str); 574*29b3e152SLi Zefan return 0; 575*29b3e152SLi Zefan } 576*29b3e152SLi Zefan 577ba77c9e1SLi Zefan static int parse_sort_opt(const struct option *opt __used, 578ba77c9e1SLi Zefan const char *arg, int unset __used) 579ba77c9e1SLi Zefan { 580ba77c9e1SLi Zefan if (!arg) 581ba77c9e1SLi Zefan return -1; 582ba77c9e1SLi Zefan 583ba77c9e1SLi Zefan if (caller_flag > alloc_flag) 584*29b3e152SLi Zefan return setup_sorting(&caller_sort, arg); 585ba77c9e1SLi Zefan else 586*29b3e152SLi Zefan return setup_sorting(&alloc_sort, arg); 587ba77c9e1SLi Zefan 588ba77c9e1SLi Zefan return 0; 589ba77c9e1SLi Zefan } 590ba77c9e1SLi Zefan 591ba77c9e1SLi Zefan static int parse_stat_opt(const struct option *opt __used, 592ba77c9e1SLi Zefan const char *arg, int unset __used) 593ba77c9e1SLi Zefan { 594ba77c9e1SLi Zefan if (!arg) 595ba77c9e1SLi Zefan return -1; 596ba77c9e1SLi Zefan 597ba77c9e1SLi Zefan if (strcmp(arg, "alloc") == 0) 598ba77c9e1SLi Zefan alloc_flag = (caller_flag + 1); 599ba77c9e1SLi Zefan else if (strcmp(arg, "caller") == 0) 600ba77c9e1SLi Zefan caller_flag = (alloc_flag + 1); 601ba77c9e1SLi Zefan else 602ba77c9e1SLi Zefan return -1; 603ba77c9e1SLi Zefan return 0; 604ba77c9e1SLi Zefan } 605ba77c9e1SLi Zefan 606ba77c9e1SLi Zefan static int parse_line_opt(const struct option *opt __used, 607ba77c9e1SLi Zefan const char *arg, int unset __used) 608ba77c9e1SLi Zefan { 609ba77c9e1SLi Zefan int lines; 610ba77c9e1SLi Zefan 611ba77c9e1SLi Zefan if (!arg) 612ba77c9e1SLi Zefan return -1; 613ba77c9e1SLi Zefan 614ba77c9e1SLi Zefan lines = strtoul(arg, NULL, 10); 615ba77c9e1SLi Zefan 616ba77c9e1SLi Zefan if (caller_flag > alloc_flag) 617ba77c9e1SLi Zefan caller_lines = lines; 618ba77c9e1SLi Zefan else 619ba77c9e1SLi Zefan alloc_lines = lines; 620ba77c9e1SLi Zefan 621ba77c9e1SLi Zefan return 0; 622ba77c9e1SLi Zefan } 623ba77c9e1SLi Zefan 624ba77c9e1SLi Zefan static const struct option kmem_options[] = { 625ba77c9e1SLi Zefan OPT_STRING('i', "input", &input_name, "file", 626ba77c9e1SLi Zefan "input file name"), 627ba77c9e1SLi Zefan OPT_CALLBACK(0, "stat", NULL, "<alloc>|<caller>", 628ba77c9e1SLi Zefan "stat selector, Pass 'alloc' or 'caller'.", 629ba77c9e1SLi Zefan parse_stat_opt), 630*29b3e152SLi Zefan OPT_CALLBACK('s', "sort", NULL, "key[,key2...]", 631*29b3e152SLi Zefan "sort by key(s): ptr, call_site, bytes, hit, frag", 632ba77c9e1SLi Zefan parse_sort_opt), 633ba77c9e1SLi Zefan OPT_CALLBACK('l', "line", NULL, "num", 634ba77c9e1SLi Zefan "show n lins", 635ba77c9e1SLi Zefan parse_line_opt), 6367707b6b6SLi Zefan OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), 637ba77c9e1SLi Zefan OPT_END() 638ba77c9e1SLi Zefan }; 639ba77c9e1SLi Zefan 640ba77c9e1SLi Zefan static const char *record_args[] = { 641ba77c9e1SLi Zefan "record", 642ba77c9e1SLi Zefan "-a", 643ba77c9e1SLi Zefan "-R", 644ba77c9e1SLi Zefan "-M", 645ba77c9e1SLi Zefan "-f", 646ba77c9e1SLi Zefan "-c", "1", 647ba77c9e1SLi Zefan "-e", "kmem:kmalloc", 648ba77c9e1SLi Zefan "-e", "kmem:kmalloc_node", 649ba77c9e1SLi Zefan "-e", "kmem:kfree", 650ba77c9e1SLi Zefan "-e", "kmem:kmem_cache_alloc", 651ba77c9e1SLi Zefan "-e", "kmem:kmem_cache_alloc_node", 652ba77c9e1SLi Zefan "-e", "kmem:kmem_cache_free", 653ba77c9e1SLi Zefan }; 654ba77c9e1SLi Zefan 655ba77c9e1SLi Zefan static int __cmd_record(int argc, const char **argv) 656ba77c9e1SLi Zefan { 657ba77c9e1SLi Zefan unsigned int rec_argc, i, j; 658ba77c9e1SLi Zefan const char **rec_argv; 659ba77c9e1SLi Zefan 660ba77c9e1SLi Zefan rec_argc = ARRAY_SIZE(record_args) + argc - 1; 661ba77c9e1SLi Zefan rec_argv = calloc(rec_argc + 1, sizeof(char *)); 662ba77c9e1SLi Zefan 663ba77c9e1SLi Zefan for (i = 0; i < ARRAY_SIZE(record_args); i++) 664ba77c9e1SLi Zefan rec_argv[i] = strdup(record_args[i]); 665ba77c9e1SLi Zefan 666ba77c9e1SLi Zefan for (j = 1; j < (unsigned int)argc; j++, i++) 667ba77c9e1SLi Zefan rec_argv[i] = argv[j]; 668ba77c9e1SLi Zefan 669ba77c9e1SLi Zefan return cmd_record(i, rec_argv, NULL); 670ba77c9e1SLi Zefan } 671ba77c9e1SLi Zefan 672ba77c9e1SLi Zefan int cmd_kmem(int argc, const char **argv, const char *prefix __used) 673ba77c9e1SLi Zefan { 674ba77c9e1SLi Zefan symbol__init(0); 675ba77c9e1SLi Zefan 676ba77c9e1SLi Zefan argc = parse_options(argc, argv, kmem_options, kmem_usage, 0); 677ba77c9e1SLi Zefan 678ba77c9e1SLi Zefan if (argc && !strncmp(argv[0], "rec", 3)) 679ba77c9e1SLi Zefan return __cmd_record(argc, argv); 680ba77c9e1SLi Zefan else if (argc) 681ba77c9e1SLi Zefan usage_with_options(kmem_usage, kmem_options); 682ba77c9e1SLi Zefan 683*29b3e152SLi Zefan if (list_empty(&caller_sort)) 684*29b3e152SLi Zefan setup_sorting(&caller_sort, default_sort_order); 685*29b3e152SLi Zefan if (list_empty(&alloc_sort)) 686*29b3e152SLi Zefan setup_sorting(&alloc_sort, default_sort_order); 687ba77c9e1SLi Zefan 688ba77c9e1SLi Zefan return __cmd_kmem(); 689ba77c9e1SLi Zefan } 690ba77c9e1SLi Zefan 691