From: Nicholas Nethercote Date: Wed, 5 Jun 2002 14:41:10 +0000 (+0000) Subject: Cache simulator now handles basic block discards correctly. When X-Git-Tag: svn/VALGRIND_1_0_3~86 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=77dca1afe505d4fcb1abcc5da3fced7833d4e7c5;p=thirdparty%2Fvalgrind.git Cache simulator now handles basic block discards correctly. When VG_(cachesim_discard_notify) is called, the cost centre array for the basic block is removed from the table, and its counts are aggregated into a single "discard" cost centre, and the cost centre array is free'd. The aggregate discard cost centre is given the filename:function_name "(discarded):(discarded)". Mentioned this in the manual. Only tested with tests/discard.c. Seems to work well for that case though :) git-svn-id: svn://svn.valgrind.org/valgrind/trunk@385 --- diff --git a/cachegrind/cg_main.c b/cachegrind/cg_main.c index 130e7eb2b1..20a693c6ca 100644 --- a/cachegrind/cg_main.c +++ b/cachegrind/cg_main.c @@ -132,6 +132,11 @@ static void init_idCC(CC_type X_CC, idCC* cc, Addr instr_addr, initCC(&cc->D); } +#define ADD_CC_TO(CC_type, cc, total) \ + total.a += ((CC_type*)BBCC_ptr)->cc.a; \ + total.m1 += ((CC_type*)BBCC_ptr)->cc.m1; \ + total.m2 += ((CC_type*)BBCC_ptr)->cc.m2; + /* If 1, address of each instruction is printed as a comment after its counts * in cachegrind.out */ #define PRINT_INSTR_ADDRS 0 @@ -223,6 +228,10 @@ static Int no_debug_BBs = 0; static Int BB_retranslations = 0; +static CC Ir_discards; +static CC Dr_discards; +static CC Dw_discards; + static void init_BBCC_table() { Int i; @@ -315,11 +324,11 @@ static UInt hash(Char *s, UInt table_size) * cost centre. Also sets BB_seen_before by reference. */ static __inline__ BBCC* get_BBCC(Addr bb_orig_addr, UCodeBlock* cb, - Bool *BB_seen_before) + Bool remove, Bool *BB_seen_before) { file_node *curr_file_node; fn_node *curr_fn_node; - BBCC *curr_BBCC; + BBCC **prev_BBCC_next_ptr, *curr_BBCC; Char filename[FILENAME_LEN], fn_name[FN_NAME_LEN]; UInt filename_hash, fnname_hash, BBCC_hash; Int dummy_line_num; @@ -352,11 +361,16 @@ static __inline__ BBCC* get_BBCC(Addr bb_orig_addr, UCodeBlock* cb, } BBCC_hash = bb_orig_addr % N_BBCC_ENTRIES; + prev_BBCC_next_ptr = &(curr_fn_node->BBCCs[BBCC_hash]); curr_BBCC = curr_fn_node->BBCCs[BBCC_hash]; while (NULL != curr_BBCC && bb_orig_addr != curr_BBCC->orig_addr) { + prev_BBCC_next_ptr = &(curr_BBCC->next); curr_BBCC = curr_BBCC->next; } if (curr_BBCC == NULL) { + + vg_assert(False == remove); + curr_fn_node->BBCCs[BBCC_hash] = curr_BBCC = new_BBCC(bb_orig_addr, cb, curr_fn_node->BBCCs[BBCC_hash]); *BB_seen_before = False; @@ -369,7 +383,15 @@ static __inline__ BBCC* get_BBCC(Addr bb_orig_addr, UCodeBlock* cb, "BB retranslation, retrieving from BBCC table"); } *BB_seen_before = True; - BB_retranslations++; + + if (True == remove) { + // Remove curr_BBCC from chain; it will be used and free'd by the + // caller. + *prev_BBCC_next_ptr = curr_BBCC->next; + + } else { + BB_retranslations++; + } } VGP_POPCC; return curr_BBCC; @@ -471,7 +493,7 @@ UCodeBlock* VG_(cachesim_instrument)(UCodeBlock* cb_in, Addr orig_addr) /* Get BBCC (creating if necessary -- requires a counting pass over the BB * if it's the first time it's been seen), and point to start of the * BBCC array. */ - BBCC_node = get_BBCC(orig_addr, cb_in, &BB_seen_before); + BBCC_node = get_BBCC(orig_addr, cb_in, False, &BB_seen_before); BBCC_ptr0 = BBCC_ptr = (Addr)(BBCC_node->array); cb = VG_(allocCodeBlock)(); @@ -708,6 +730,10 @@ void VG_(init_cachesim)(void) initCC(&Dr_total); initCC(&Dw_total); + initCC(&Ir_discards); + initCC(&Dr_discards); + initCC(&Dw_discards); + cachesim_I1_initcache(); cachesim_D1_initcache(); cachesim_L2_initcache(); @@ -768,11 +794,6 @@ static void fprint_BBCC(Int fd, BBCC* BBCC_node, Char *first_instr_fl, Addr instr_addr; switch ( ((iCC*)BBCC_ptr)->tag ) { -#define ADD_CC_TO(CC_type, cc, total) \ - total.a += ((CC_type*)BBCC_ptr)->cc.a; \ - total.m1 += ((CC_type*)BBCC_ptr)->cc.m1; \ - total.m2 += ((CC_type*)BBCC_ptr)->cc.m2; - case INSTR_CC: instr_addr = ((iCC*)BBCC_ptr)->instr_addr; sprint_iCC(buf, (iCC*)BBCC_ptr); @@ -797,8 +818,6 @@ static void fprint_BBCC(Int fd, BBCC* BBCC_node, Char *first_instr_fl, BBCC_ptr += sizeof(idCC); break; -#undef ADD_CC_TO - default: VG_(panic)("Unknown CC type in fprint_BBCC()\n"); break; @@ -907,6 +926,32 @@ static void fprint_BBCC_table_and_calc_totals(Int client_argc, } } + /* Print stats from any discarded basic blocks */ + if (0 != Ir_discards.a) { + + VG_(sprintf)(buf, "fl=(discarded)\n"); + VG_(write)(fd, (void*)buf, VG_(strlen)(buf)); + VG_(sprintf)(buf, "fn=(discarded)\n"); + VG_(write)(fd, (void*)buf, VG_(strlen)(buf)); + + /* Use 0 as line number */ + VG_(sprintf)(buf, "0 %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", + Ir_discards.a, Ir_discards.m1, Ir_discards.m2, + Dr_discards.a, Dr_discards.m1, Dr_discards.m2, + Dw_discards.a, Dw_discards.m1, Dw_discards.m2); + VG_(write)(fd, (void*)buf, VG_(strlen)(buf)); + + Ir_total.a += Ir_discards.a; + Ir_total.m1 += Ir_discards.m1; + Ir_total.m2 += Ir_discards.m2; + Dr_total.a += Dr_discards.a; + Dr_total.m1 += Dr_discards.m1; + Dr_total.m2 += Dr_discards.m2; + Dw_total.a += Dw_discards.a; + Dw_total.m1 += Dw_discards.m1; + Dw_total.m2 += Dw_discards.m2; + } + /* Summary stats must come after rest of table, since we calculate them * during traversal. */ VG_(sprintf)(buf, "summary: " @@ -1091,10 +1136,60 @@ void VG_(show_cachesim_results)(Int client_argc, Char** client_argv) } +/* Called when a translation is invalidated due to self-modifying code or + * unloaded of a shared object. + * + * Finds the BBCC in the table, removes it, adds the counts to the discard + * counters, and then frees the BBCC. */ void VG_(cachesim_notify_discard) ( TTEntry* tte ) { - VG_(printf)( "cachesim_notify_discard: %p for %d\n", - tte->orig_addr, (Int)tte->orig_size); + BBCC *BBCC_node; + Addr BBCC_ptr0, BBCC_ptr; + Bool BB_seen_before; + + VG_(printf)( "cachesim_notify_discard: %p for %d\n", + tte->orig_addr, (Int)tte->orig_size); + + /* 2nd arg won't be used since BB should have been seen before (assertions + * ensure this). */ + BBCC_node = get_BBCC(tte->orig_addr, NULL, True, &BB_seen_before); + BBCC_ptr0 = BBCC_ptr = (Addr)(BBCC_node->array); + + vg_assert(True == BB_seen_before); + + while (BBCC_ptr - BBCC_ptr0 < BBCC_node->array_size) { + + /* We pretend the CC is an iCC for getting the tag. This is ok + * because both CC types have tag as their first byte. Once we know + * the type, we can cast and act appropriately. */ + + switch ( ((iCC*)BBCC_ptr)->tag ) { + + case INSTR_CC: + ADD_CC_TO(iCC, I, Ir_discards); + BBCC_ptr += sizeof(iCC); + break; + + case READ_CC: + case MOD_CC: + ADD_CC_TO(idCC, I, Ir_discards); + ADD_CC_TO(idCC, D, Dr_discards); + BBCC_ptr += sizeof(idCC); + break; + + case WRITE_CC: + ADD_CC_TO(idCC, I, Ir_discards); + ADD_CC_TO(idCC, D, Dw_discards); + BBCC_ptr += sizeof(idCC); + break; + + default: + VG_(panic)("Unknown CC type in VG_(cachesim_notify_discard)()\n"); + break; + } + } + + VG_(free)(VG_AR_PRIVATE, BBCC_node); } /*--------------------------------------------------------------------*/ diff --git a/cachegrind/docs/manual.html b/cachegrind/docs/manual.html index 3daf1529ae..3b797dfce8 100644 --- a/cachegrind/docs/manual.html +++ b/cachegrind/docs/manual.html @@ -1197,8 +1197,7 @@ A brief description of the available macros: fresh memory, and just call this occasionally to discard large chunks of old code all at once.

- Warning: minimally tested. Also, doesn't interact well with the - cache simulator. + Warning: minimally tested, especially for the cache simulator.

@@ -2313,7 +2312,9 @@ contains no instructions that write to memory). The name ??? is used if the the file name and/or function name could not be determined from debugging information. If most of the entries have the form ???:??? the program probably wasn't -compiled with -g.

+compiled with -g. If any code was invalidated (either due to +self-modifying code or unloading of shared objects) its counts are aggregated +into a single cost centre written as (discarded):(discarded).

It is worth noting that functions will come from three types of source files:

    diff --git a/coregrind/docs/manual.html b/coregrind/docs/manual.html index 3daf1529ae..3b797dfce8 100644 --- a/coregrind/docs/manual.html +++ b/coregrind/docs/manual.html @@ -1197,8 +1197,7 @@ A brief description of the available macros: fresh memory, and just call this occasionally to discard large chunks of old code all at once.

    - Warning: minimally tested. Also, doesn't interact well with the - cache simulator. + Warning: minimally tested, especially for the cache simulator.

    @@ -2313,7 +2312,9 @@ contains no instructions that write to memory). The name ??? is used if the the file name and/or function name could not be determined from debugging information. If most of the entries have the form ???:??? the program probably wasn't -compiled with -g.

    +compiled with -g. If any code was invalidated (either due to +self-modifying code or unloading of shared objects) its counts are aggregated +into a single cost centre written as (discarded):(discarded).

    It is worth noting that functions will come from three types of source files:

      diff --git a/docs/manual.html b/docs/manual.html index 3daf1529ae..3b797dfce8 100644 --- a/docs/manual.html +++ b/docs/manual.html @@ -1197,8 +1197,7 @@ A brief description of the available macros: fresh memory, and just call this occasionally to discard large chunks of old code all at once.

      - Warning: minimally tested. Also, doesn't interact well with the - cache simulator. + Warning: minimally tested, especially for the cache simulator.

      @@ -2313,7 +2312,9 @@ contains no instructions that write to memory). The name ??? is used if the the file name and/or function name could not be determined from debugging information. If most of the entries have the form ???:??? the program probably wasn't -compiled with -g.

      +compiled with -g. If any code was invalidated (either due to +self-modifying code or unloading of shared objects) its counts are aggregated +into a single cost centre written as (discarded):(discarded).

      It is worth noting that functions will come from three types of source files:

        diff --git a/memcheck/docs/manual.html b/memcheck/docs/manual.html index 3daf1529ae..3b797dfce8 100644 --- a/memcheck/docs/manual.html +++ b/memcheck/docs/manual.html @@ -1197,8 +1197,7 @@ A brief description of the available macros: fresh memory, and just call this occasionally to discard large chunks of old code all at once.

        - Warning: minimally tested. Also, doesn't interact well with the - cache simulator. + Warning: minimally tested, especially for the cache simulator.

        @@ -2313,7 +2312,9 @@ contains no instructions that write to memory). The name ??? is used if the the file name and/or function name could not be determined from debugging information. If most of the entries have the form ???:??? the program probably wasn't -compiled with -g.

        +compiled with -g. If any code was invalidated (either due to +self-modifying code or unloading of shared objects) its counts are aggregated +into a single cost centre written as (discarded):(discarded).

        It is worth noting that functions will come from three types of source files:

          diff --git a/vg_cachesim.c b/vg_cachesim.c index 130e7eb2b1..20a693c6ca 100644 --- a/vg_cachesim.c +++ b/vg_cachesim.c @@ -132,6 +132,11 @@ static void init_idCC(CC_type X_CC, idCC* cc, Addr instr_addr, initCC(&cc->D); } +#define ADD_CC_TO(CC_type, cc, total) \ + total.a += ((CC_type*)BBCC_ptr)->cc.a; \ + total.m1 += ((CC_type*)BBCC_ptr)->cc.m1; \ + total.m2 += ((CC_type*)BBCC_ptr)->cc.m2; + /* If 1, address of each instruction is printed as a comment after its counts * in cachegrind.out */ #define PRINT_INSTR_ADDRS 0 @@ -223,6 +228,10 @@ static Int no_debug_BBs = 0; static Int BB_retranslations = 0; +static CC Ir_discards; +static CC Dr_discards; +static CC Dw_discards; + static void init_BBCC_table() { Int i; @@ -315,11 +324,11 @@ static UInt hash(Char *s, UInt table_size) * cost centre. Also sets BB_seen_before by reference. */ static __inline__ BBCC* get_BBCC(Addr bb_orig_addr, UCodeBlock* cb, - Bool *BB_seen_before) + Bool remove, Bool *BB_seen_before) { file_node *curr_file_node; fn_node *curr_fn_node; - BBCC *curr_BBCC; + BBCC **prev_BBCC_next_ptr, *curr_BBCC; Char filename[FILENAME_LEN], fn_name[FN_NAME_LEN]; UInt filename_hash, fnname_hash, BBCC_hash; Int dummy_line_num; @@ -352,11 +361,16 @@ static __inline__ BBCC* get_BBCC(Addr bb_orig_addr, UCodeBlock* cb, } BBCC_hash = bb_orig_addr % N_BBCC_ENTRIES; + prev_BBCC_next_ptr = &(curr_fn_node->BBCCs[BBCC_hash]); curr_BBCC = curr_fn_node->BBCCs[BBCC_hash]; while (NULL != curr_BBCC && bb_orig_addr != curr_BBCC->orig_addr) { + prev_BBCC_next_ptr = &(curr_BBCC->next); curr_BBCC = curr_BBCC->next; } if (curr_BBCC == NULL) { + + vg_assert(False == remove); + curr_fn_node->BBCCs[BBCC_hash] = curr_BBCC = new_BBCC(bb_orig_addr, cb, curr_fn_node->BBCCs[BBCC_hash]); *BB_seen_before = False; @@ -369,7 +383,15 @@ static __inline__ BBCC* get_BBCC(Addr bb_orig_addr, UCodeBlock* cb, "BB retranslation, retrieving from BBCC table"); } *BB_seen_before = True; - BB_retranslations++; + + if (True == remove) { + // Remove curr_BBCC from chain; it will be used and free'd by the + // caller. + *prev_BBCC_next_ptr = curr_BBCC->next; + + } else { + BB_retranslations++; + } } VGP_POPCC; return curr_BBCC; @@ -471,7 +493,7 @@ UCodeBlock* VG_(cachesim_instrument)(UCodeBlock* cb_in, Addr orig_addr) /* Get BBCC (creating if necessary -- requires a counting pass over the BB * if it's the first time it's been seen), and point to start of the * BBCC array. */ - BBCC_node = get_BBCC(orig_addr, cb_in, &BB_seen_before); + BBCC_node = get_BBCC(orig_addr, cb_in, False, &BB_seen_before); BBCC_ptr0 = BBCC_ptr = (Addr)(BBCC_node->array); cb = VG_(allocCodeBlock)(); @@ -708,6 +730,10 @@ void VG_(init_cachesim)(void) initCC(&Dr_total); initCC(&Dw_total); + initCC(&Ir_discards); + initCC(&Dr_discards); + initCC(&Dw_discards); + cachesim_I1_initcache(); cachesim_D1_initcache(); cachesim_L2_initcache(); @@ -768,11 +794,6 @@ static void fprint_BBCC(Int fd, BBCC* BBCC_node, Char *first_instr_fl, Addr instr_addr; switch ( ((iCC*)BBCC_ptr)->tag ) { -#define ADD_CC_TO(CC_type, cc, total) \ - total.a += ((CC_type*)BBCC_ptr)->cc.a; \ - total.m1 += ((CC_type*)BBCC_ptr)->cc.m1; \ - total.m2 += ((CC_type*)BBCC_ptr)->cc.m2; - case INSTR_CC: instr_addr = ((iCC*)BBCC_ptr)->instr_addr; sprint_iCC(buf, (iCC*)BBCC_ptr); @@ -797,8 +818,6 @@ static void fprint_BBCC(Int fd, BBCC* BBCC_node, Char *first_instr_fl, BBCC_ptr += sizeof(idCC); break; -#undef ADD_CC_TO - default: VG_(panic)("Unknown CC type in fprint_BBCC()\n"); break; @@ -907,6 +926,32 @@ static void fprint_BBCC_table_and_calc_totals(Int client_argc, } } + /* Print stats from any discarded basic blocks */ + if (0 != Ir_discards.a) { + + VG_(sprintf)(buf, "fl=(discarded)\n"); + VG_(write)(fd, (void*)buf, VG_(strlen)(buf)); + VG_(sprintf)(buf, "fn=(discarded)\n"); + VG_(write)(fd, (void*)buf, VG_(strlen)(buf)); + + /* Use 0 as line number */ + VG_(sprintf)(buf, "0 %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", + Ir_discards.a, Ir_discards.m1, Ir_discards.m2, + Dr_discards.a, Dr_discards.m1, Dr_discards.m2, + Dw_discards.a, Dw_discards.m1, Dw_discards.m2); + VG_(write)(fd, (void*)buf, VG_(strlen)(buf)); + + Ir_total.a += Ir_discards.a; + Ir_total.m1 += Ir_discards.m1; + Ir_total.m2 += Ir_discards.m2; + Dr_total.a += Dr_discards.a; + Dr_total.m1 += Dr_discards.m1; + Dr_total.m2 += Dr_discards.m2; + Dw_total.a += Dw_discards.a; + Dw_total.m1 += Dw_discards.m1; + Dw_total.m2 += Dw_discards.m2; + } + /* Summary stats must come after rest of table, since we calculate them * during traversal. */ VG_(sprintf)(buf, "summary: " @@ -1091,10 +1136,60 @@ void VG_(show_cachesim_results)(Int client_argc, Char** client_argv) } +/* Called when a translation is invalidated due to self-modifying code or + * unloaded of a shared object. + * + * Finds the BBCC in the table, removes it, adds the counts to the discard + * counters, and then frees the BBCC. */ void VG_(cachesim_notify_discard) ( TTEntry* tte ) { - VG_(printf)( "cachesim_notify_discard: %p for %d\n", - tte->orig_addr, (Int)tte->orig_size); + BBCC *BBCC_node; + Addr BBCC_ptr0, BBCC_ptr; + Bool BB_seen_before; + + VG_(printf)( "cachesim_notify_discard: %p for %d\n", + tte->orig_addr, (Int)tte->orig_size); + + /* 2nd arg won't be used since BB should have been seen before (assertions + * ensure this). */ + BBCC_node = get_BBCC(tte->orig_addr, NULL, True, &BB_seen_before); + BBCC_ptr0 = BBCC_ptr = (Addr)(BBCC_node->array); + + vg_assert(True == BB_seen_before); + + while (BBCC_ptr - BBCC_ptr0 < BBCC_node->array_size) { + + /* We pretend the CC is an iCC for getting the tag. This is ok + * because both CC types have tag as their first byte. Once we know + * the type, we can cast and act appropriately. */ + + switch ( ((iCC*)BBCC_ptr)->tag ) { + + case INSTR_CC: + ADD_CC_TO(iCC, I, Ir_discards); + BBCC_ptr += sizeof(iCC); + break; + + case READ_CC: + case MOD_CC: + ADD_CC_TO(idCC, I, Ir_discards); + ADD_CC_TO(idCC, D, Dr_discards); + BBCC_ptr += sizeof(idCC); + break; + + case WRITE_CC: + ADD_CC_TO(idCC, I, Ir_discards); + ADD_CC_TO(idCC, D, Dw_discards); + BBCC_ptr += sizeof(idCC); + break; + + default: + VG_(panic)("Unknown CC type in VG_(cachesim_notify_discard)()\n"); + break; + } + } + + VG_(free)(VG_AR_PRIVATE, BBCC_node); } /*--------------------------------------------------------------------*/