diff options
author | Marco Castelluccio <mcastelluccio@mozilla.com> | 2018-07-05 15:52:59 +0000 |
---|---|---|
committer | Marco Castelluccio <mcastelluccio@mozilla.com> | 2018-07-05 15:52:59 +0000 |
commit | 171f1837de1002d59f22d72d4794e2b7eb9c2214 (patch) | |
tree | 250e1870f681cab79319838ec5c70e006fa8bf94 /lib/profile | |
parent | 8147185ac81719159a02231d2e06570bcf65617f (diff) |
Make __gcov_flush flush counters for all shared libraries
Summary:
This will make the behavior of __gcov_flush match the GCC behavior.
I would like to rename __gcov_flush to __llvm_gcov_flush (in case of programs linking to libraries built with different compilers), but I guess we can't for compatibility reasons.
Reviewers: davidxl
Reviewed By: davidxl
Subscribers: samsonov, vitalybuka, pcc, kcc, junbuml, glider, fhahn, eugenis, dvyukov, davidxl, srhines, chh, llvm-commits, #sanitizers
Differential Revision: https://reviews.llvm.org/D48538
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@336365 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/profile')
-rw-r--r-- | lib/profile/GCDAProfiling.c | 149 |
1 files changed, 80 insertions, 69 deletions
diff --git a/lib/profile/GCDAProfiling.c b/lib/profile/GCDAProfiling.c index 68a0cab66..ad58db4c4 100644 --- a/lib/profile/GCDAProfiling.c +++ b/lib/profile/GCDAProfiling.c @@ -86,31 +86,76 @@ static uint64_t file_size = 0; static int new_file = 0; static int fd = -1; -/* - * A list of functions to write out the data. - */ -typedef void (*writeout_fn)(); +typedef void (*fn_ptr)(); + +typedef void* dynamic_object_id; +// The address of this variable identifies a given dynamic object. +static dynamic_object_id current_id; +#define CURRENT_ID (¤t_id) -struct writeout_fn_node { - writeout_fn fn; - struct writeout_fn_node *next; +struct fn_node { + dynamic_object_id id; + fn_ptr fn; + struct fn_node* next; }; -static struct writeout_fn_node *writeout_fn_head = NULL; -static struct writeout_fn_node *writeout_fn_tail = NULL; +struct fn_list { + struct fn_node *head, *tail; +}; /* - * A list of flush functions that our __gcov_flush() function should call. + * A list of functions to write out the data, shared between all dynamic objects. */ -typedef void (*flush_fn)(); +struct fn_list writeout_fn_list; -struct flush_fn_node { - flush_fn fn; - struct flush_fn_node *next; -}; +/* + * A list of flush functions that our __gcov_flush() function should call, shared between all dynamic objects. + */ +struct fn_list flush_fn_list; + +static void fn_list_insert(struct fn_list* list, fn_ptr fn) { + struct fn_node* new_node = malloc(sizeof(struct fn_node)); + new_node->fn = fn; + new_node->next = NULL; + new_node->id = CURRENT_ID; + + if (!list->head) { + list->head = list->tail = new_node; + } else { + list->tail->next = new_node; + list->tail = new_node; + } +} + +static void fn_list_remove(struct fn_list* list) { + struct fn_node* curr = list->head; + struct fn_node* prev = NULL; + struct fn_node* next = NULL; + + while (curr) { + next = curr->next; + + if (curr->id == CURRENT_ID) { + if (curr == list->head) { + list->head = next; + } + + if (curr == list->tail) { + list->tail = prev; + } -static struct flush_fn_node *flush_fn_head = NULL; -static struct flush_fn_node *flush_fn_tail = NULL; + if (prev) { + prev->next = next; + } + + free(curr); + } else { + prev = curr; + } + + curr = next; + } +} static void resize_write_buffer(uint64_t size) { if (!new_file) return; @@ -403,6 +448,7 @@ void llvm_gcda_summary_info() { const uint32_t obj_summary_len = 9; /* Length for gcov compatibility. */ uint32_t i; uint32_t runs = 1; + static uint32_t run_counted = 0; // We only want to increase the run count once. uint32_t val = 0; uint64_t save_cur_pos = cur_pos; @@ -429,7 +475,9 @@ void llvm_gcda_summary_info() { read_32bit_value(); /* checksum, unused */ read_32bit_value(); /* num, unused */ - runs += read_32bit_value(); /* Add previous run count to new counter. */ + uint32_t prev_runs = read_32bit_value(); + /* Add previous run count to new counter, if not already counted before. */ + runs = run_counted ? prev_runs : prev_runs + 1; } cur_pos = save_cur_pos; @@ -447,6 +495,8 @@ void llvm_gcda_summary_info() { write_bytes("\0\0\0\xa3", 4); /* tag indicates 1 program */ write_32bit_value(0); /* 0 length */ + run_counted = 1; + #ifdef DEBUG_GCDAPROFILING fprintf(stderr, "llvmgcda: %u runs\n", runs); #endif @@ -479,61 +529,34 @@ void llvm_gcda_end_file() { } COMPILER_RT_VISIBILITY -void llvm_register_writeout_function(writeout_fn fn) { - struct writeout_fn_node *new_node = malloc(sizeof(struct writeout_fn_node)); - new_node->fn = fn; - new_node->next = NULL; - - if (!writeout_fn_head) { - writeout_fn_head = writeout_fn_tail = new_node; - } else { - writeout_fn_tail->next = new_node; - writeout_fn_tail = new_node; - } +void llvm_register_writeout_function(fn_ptr fn) { + fn_list_insert(&writeout_fn_list, fn); } COMPILER_RT_VISIBILITY void llvm_writeout_files(void) { - struct writeout_fn_node *curr = writeout_fn_head; + struct fn_node *curr = writeout_fn_list.head; while (curr) { - curr->fn(); + if (curr->id == CURRENT_ID) { + curr->fn(); + } curr = curr->next; } } COMPILER_RT_VISIBILITY void llvm_delete_writeout_function_list(void) { - while (writeout_fn_head) { - struct writeout_fn_node *node = writeout_fn_head; - writeout_fn_head = writeout_fn_head->next; - free(node); - } - - writeout_fn_head = writeout_fn_tail = NULL; + fn_list_remove(&writeout_fn_list); } COMPILER_RT_VISIBILITY -void llvm_register_flush_function(flush_fn fn) { - struct flush_fn_node *new_node = malloc(sizeof(struct flush_fn_node)); - new_node->fn = fn; - new_node->next = NULL; - - if (!flush_fn_head) { - flush_fn_head = flush_fn_tail = new_node; - } else { - flush_fn_tail->next = new_node; - flush_fn_tail = new_node; - } +void llvm_register_flush_function(fn_ptr fn) { + fn_list_insert(&flush_fn_list, fn); } -// __gcov_flush is hidden. When called in a .so file, -// it dumps profile data of the calling .so file. -// If a main program needs to dump profile data of each linked -// .so files, it should use dlsym to find and call llvm_gcov_flush. -COMPILER_RT_VISIBILITY void __gcov_flush() { - struct flush_fn_node *curr = flush_fn_head; + struct fn_node* curr = flush_fn_list.head; while (curr) { curr->fn(); @@ -541,25 +564,13 @@ void __gcov_flush() { } } -// llvm_gcov_flush is not hidden for a program to use dlsym to -// find and call for any linked .so file. -void llvm_gcov_flush() { - __gcov_flush(); -} - COMPILER_RT_VISIBILITY void llvm_delete_flush_function_list(void) { - while (flush_fn_head) { - struct flush_fn_node *node = flush_fn_head; - flush_fn_head = flush_fn_head->next; - free(node); - } - - flush_fn_head = flush_fn_tail = NULL; + fn_list_remove(&flush_fn_list); } COMPILER_RT_VISIBILITY -void llvm_gcov_init(writeout_fn wfn, flush_fn ffn) { +void llvm_gcov_init(fn_ptr wfn, fn_ptr ffn) { static int atexit_ran = 0; if (wfn) |