/* This function implements the GHB based PC/CS prefetching as described in the * 2005 paper by Nesbit and Smith. The index table lookup is based on the PC * of the instruction causing the miss. The GHB entries are looked at for finding * constant stride accesses. Based on this, prefetching is done. */ static void prefetcher_ghb_pc_cs(struct mod_t *mod, struct mod_stack_t *stack, int it_index) { struct prefetcher_t *pref; int chain, stride, i; unsigned int prev_addr, cur_addr, prefetch_addr = 0; assert(mod->kind == mod_kind_cache && mod->cache != NULL); pref = mod->cache->prefetcher; chain = pref->index_table[it_index].ptr; /* The lookup depth must be at least 2 - which essentially means * two strides have been seen so far, prefetch for the next. * It doesn't really help to prefetch on a lookup of depth 1. * It is too low an accuracy and leads to lot of illegal and * redundant prefetches. Hence keeping the minimum at 2. */ assert(pref->lookup_depth >= 2); /* The table should've been updated before calling this function. */ assert(pref->ghb[chain].addr == stack->addr); /* If there's only one element in this linked list, nothing to do. */ if (pref->ghb[chain].next == -1) return; prev_addr = pref->ghb[chain].addr; chain = pref->ghb[chain].next; cur_addr = pref->ghb[chain].addr; stride = prev_addr - cur_addr; for (i = 2; i <= pref->lookup_depth; i++) { prev_addr = cur_addr; chain = pref->ghb[chain].next; /* The linked list (history) is smaller than the lookup depth */ if (chain == -1) break; cur_addr = pref->ghb[chain].addr; /* The stride changed, can't prefetch */ if (stride != prev_addr - cur_addr) break; /* If this is the last iteration (we've seen as much history as * the lookup depth specified), then do a prefetch. */ if (i == pref->lookup_depth) prefetch_addr = stack->addr + stride; } if (prefetch_addr > 0) prefetcher_do_prefetch(mod, stack, prefetch_addr); }
/* This function implements the GHB based PC/DC prefetching as described in the * 2005 paper by Nesbit and Smith. The index table lookup is based on the PC * of the instruction causing the miss. The last three accesses are looked at * to find the last two strides (deltas). The list is then looked up backwards * to see if this pair of strides occurred earlier, if yes, the next stride * is obtained from the history there. This stride decides the new * prefetch_addr. */ static void prefetcher_ghb_pc_dc(struct mod_t *mod, struct mod_stack_t *stack, int it_index) { struct prefetcher_t *pref; int chain, chain2, stride[PREFETCHER_LOOKUP_DEPTH_MAX], i, pref_stride; unsigned int prev_addr, cur_addr, prefetch_addr = 0; assert(mod->kind == mod_kind_cache && mod->cache != NULL); pref = mod->cache->prefetcher; chain = pref->index_table[it_index].ptr; /* The lookup depth must be at least 2 - which essentially means * two strides have been seen so far, predict the next stride. */ assert(pref->lookup_depth >= 2 && pref->lookup_depth <= PREFETCHER_LOOKUP_DEPTH_MAX); /* The table should've been updated before calling this function. */ assert(pref->ghb[chain].addr == stack->addr); /* Collect "lookup_depth" number of strides (deltas). * This doesn't really make sense for a depth > 2, but * I'll just have the code here for generality. */ for (i = 0; i < pref->lookup_depth; i++) { prev_addr = pref->ghb[chain].addr; chain = pref->ghb[chain].next; /* The chain isn't long enough */ if (chain == -1) return; cur_addr = pref->ghb[chain].addr; stride[i] = prev_addr - cur_addr; } chain = pref->index_table[it_index].ptr; chain = pref->ghb[chain].next; assert(chain != -1); /* "chain" now points to the second element of the list. * Try to match the stride array starting from here. */ while (chain != -1) { /* This really doesn't look realistic to implement in * hardware. Too much time consuming I feel. */ chain2 = chain; for (i = 0; i < pref->lookup_depth; i++) { prev_addr = pref->ghb[chain2].addr; chain2 = pref->ghb[chain2].next; /* The chain isn't long enough and we * haven't found a match till now. */ if (chain2 == -1) return; cur_addr = pref->ghb[chain2].addr; if (stride[i] != prev_addr - cur_addr) break; } /* If we traversed the above loop full, we have a match. */ if (i == pref->lookup_depth) { cur_addr = pref->ghb[chain].addr; assert(pref->ghb[chain].prev != -1 && pref->ghb[chain].prev_it_ghb == prefetcher_ptr_ghb); chain = pref->ghb[chain].prev; prev_addr = pref->ghb[chain].addr; pref_stride = prev_addr - cur_addr; prefetch_addr = stack->addr + pref_stride; break; } chain = pref->ghb[chain].next; } if (prefetch_addr > 0) prefetcher_do_prefetch(mod, stack, prefetch_addr); }