📄 bpred.c
字号:
/* * bpred.c - branch predictor routines * * This file is a part of the SimpleScalar tool suite written by * Todd M. Austin as a part of the Multiscalar Research Project. * * The tool suite is currently maintained by Doug Burger and Todd M. Austin. * * Copyright (C) 1994, 1995, 1996, 1997 by Todd M. Austin * * This source file is distributed "as is" in the hope that it will be * useful. The tool set comes with no warranty, and no author or * distributor accepts any responsibility for the consequences of its * use. * * Everyone is granted permission to copy, modify and redistribute * this tool set under the following conditions: * * This source code is distributed for non-commercial use only. * Please contact the maintainer for restrictions applying to * commercial use. * * Permission is granted to anyone to make or distribute copies * of this source code, either as received or modified, in any * medium, provided that all copyright notices, permission and * nonwarranty notices are preserved, and that the distributor * grants the recipient permission for further redistribution as * permitted by this document. * * Permission is granted to distribute this file in compiled * or executable form under the same conditions that apply for * source code, provided that either: * * A. it is accompanied by the corresponding machine-readable * source code, * B. it is accompanied by a written offer, with no time limit, * to give anyone a machine-readable copy of the corresponding * source code in return for reimbursement of the cost of * distribution. This written offer must permit verbatim * duplication by anyone, or * C. it is distributed by someone who received only the * executable form, and is accompanied by a copy of the * written offer of source code that they received concurrently. * * In other words, you are welcome to use, share and improve this * source file. You are forbidden to forbid anyone else to use, share * and improve what you give them. * * INTERNET: dburger@cs.wisc.edu * US Mail: 1210 W. Dayton Street, Madison, WI 53706 * * $Id: bpred.c,v 1.1.1.1 1997/05/22 00:33:18 aklauser Exp $ * * $Log: bpred.c,v $ * Revision 1.1.1.1 1997/05/22 00:33:18 aklauser * * Revision 1.11 1997/05/01 20:23:00 skadron * BTB bug fixes; jumps no longer update direction state; non-taken * branches non longer update BTB * * Revision 1.10 1997/05/01 00:05:42 skadron * Separated BTB from direction-predictor * * Revision 1.9 1997/04/30 01:42:42 skadron * 1. Not aggressively returning the BTB target regardless of hit on jump's, * but instead returning just "taken" when it's a BTB miss yields an * apparent epsilon performance improvement for cc1 and perl. * 2. Bug fix: if no retstack, treat return's as any other jump * * Revision 1.8 1997/04/29 23:50:33 skadron * Added r31 info to distinguish between return-JRs and other JRs for bpred * * Revision 1.7 1997/04/29 22:53:04 skadron * Hopefully bpred is now right: bpred now allocates entries only for * branches; on a BTB miss it still returns a direction; and it uses a * return-address stack. Returns are not yet distinguished among JR's * * Revision 1.6 1997/04/28 17:37:02 skadron * Bpred now allocates entries for any instruction instead of only * branches; also added return-address stack * * Revision 1.5 1997/04/24 16:57:21 skadron * Bpred used to return no prediction if the indexing branch didn't match * in the BTB. Now it can predict a direction even on a BTB address * conflict * * Revision 1.4 1997/03/27 16:31:52 skadron * Fixed bug: sim-outorder calls bpred_after_priming(), even if no bpred * exists. Now we check for a null ptr. * * Revision 1.3 1997/03/25 16:16:33 skadron * Statistics now take account of priming: statistics report only * post-prime info. * * Revision 1.2 1997/02/24 18:02:41 skadron * Fixed output format of a formula stat * * Revision 1.1 1997/02/16 22:23:54 skadron * Initial revision * * */#include <stdio.h>#include <stdlib.h>#include <math.h>#include <assert.h>#include "misc.h"#include "ss.h"#include "bpred.h"/* create a branch predictor */struct bpred * /* branch predictory instance */bpred_create(enum bpred_class class, /* type of predictor to create */ unsigned int bimod_size, /* bimod table size */ unsigned int l1size, /* 2lev l1 table size */ unsigned int l2size, /* 2lev l2 table size */ unsigned int meta_size, /* meta table size */ unsigned int shift_width, /* history register width */ unsigned int xor, /* history xor address flag */ unsigned int btb_sets, /* number of sets in BTB */ unsigned int btb_assoc, /* BTB associativity */ unsigned int retstack_size) /* num entries in ret-addr stack */{ struct bpred *pred; if (!(pred = calloc(1, sizeof(struct bpred)))) fatal("out of virtual memory"); pred->class = class; switch (class) { case BPredComb: /* bimodal component */ pred->dirpred.bimod = bpred_dir_create(BPred2bit, bimod_size, 0, 0, 0); /* 2-level component */ pred->dirpred.twolev = bpred_dir_create(BPred2Level, l1size, l2size, shift_width, xor); /* metapredictor component */ pred->dirpred.meta = bpred_dir_create(BPred2bit, meta_size, 0, 0, 0); break; case BPred2Level: pred->dirpred.twolev = bpred_dir_create(class, l1size, l2size, shift_width, xor); break; case BPred2bit: pred->dirpred.bimod = bpred_dir_create(class, bimod_size, 0, 0, 0); case BPredTaken: case BPredNotTaken: /* no other state */ break; default: panic("bogus predictor class"); } /* allocate ret-addr stack */ switch (class) { case BPredComb: case BPred2Level: case BPred2bit: { int i; /* allocate BTB */ if (!btb_sets || (btb_sets & (btb_sets-1)) != 0) fatal("number of BTB sets must be non-zero and a power of two"); if (!btb_assoc || (btb_assoc & (btb_assoc-1)) != 0) fatal("BTB associativity must be non-zero and a power of two"); if (!(pred->btb.btb_data = calloc(btb_sets * btb_assoc, sizeof(struct bpred_btb_ent)))) fatal("cannot allocate BTB"); pred->btb.sets = btb_sets; pred->btb.assoc = btb_assoc; if (pred->btb.assoc > 1) for (i=0; i < (pred->btb.assoc*pred->btb.sets); i++) { if (i % pred->btb.assoc != pred->btb.assoc - 1) pred->btb.btb_data[i].next = &pred->btb.btb_data[i+1]; else pred->btb.btb_data[i].next = NULL; if (i % pred->btb.assoc != pred->btb.assoc - 1) pred->btb.btb_data[i+1].prev = &pred->btb.btb_data[i]; } /* allocate retstack */ if ((retstack_size & (retstack_size-1)) != 0) fatal("Return-address-stack size must be zero or a power of two"); pred->retstack.size = retstack_size; if (retstack_size) if (!(pred->retstack.stack = calloc(retstack_size, sizeof(struct bpred_btb_ent)))) fatal("cannot allocate return-address-stack"); pred->retstack.tos = retstack_size - 1; break; } case BPredTaken: case BPredNotTaken: /* no other state */ break; default: panic("bogus predictor class"); } return pred;}/* create a branch direction predictor */struct bpred_dir * /* branch direction predictor instance */bpred_dir_create ( enum bpred_class class, /* type of predictor to create */ unsigned int l1size, /* level-1 table size */ unsigned int l2size, /* level-2 table size (if relevant) */ unsigned int shift_width, /* history register width */ unsigned int xor) /* history xor address flag */{ struct bpred_dir *pred_dir; unsigned int cnt; int flipflop; if (!(pred_dir = calloc(1, sizeof(struct bpred_dir)))) fatal("out of virtual memory"); pred_dir->class = class; cnt = -1; switch (class) { case BPred2Level: { if (!l1size || (l1size & (l1size-1)) != 0) fatal("level-1 size, `%d', must be non-zero and a power of two", l1size); pred_dir->config.two.l1size = l1size; if (!l2size || (l2size & (l2size-1)) != 0) fatal("level-2 size, `%d', must be non-zero and a power of two", l2size); pred_dir->config.two.l2size = l2size; if (!shift_width || shift_width > 30) fatal("shift register width, `%d', must be non-zero and positive", shift_width); pred_dir->config.two.shift_width = shift_width; pred_dir->config.two.xor = xor; pred_dir->config.two.shiftregs = calloc(l1size, sizeof(int)); if (!pred_dir->config.two.shiftregs) fatal("cannot allocate shift register table"); pred_dir->config.two.l2table = calloc(l2size, sizeof(unsigned char)); if (!pred_dir->config.two.l2table) fatal("cannot allocate second level table"); /* initialize counters to weakly this-or-that */ flipflop = 1; for (cnt = 0; cnt < l2size; cnt++) { pred_dir->config.two.l2table[cnt] = flipflop; flipflop = 3 - flipflop; } break; } case BPred2bit: if (!l1size || (l1size & (l1size-1)) != 0) fatal("2bit table size, `%d', must be non-zero and a power of two", l1size); pred_dir->config.bimod.size = l1size; if (!(pred_dir->config.bimod.table = calloc(l1size, sizeof(unsigned char)))) fatal("cannot allocate 2bit storage"); /* initialize counters to weakly this-or-that */ flipflop = 1; for (cnt = 0; cnt < l1size; cnt++) { pred_dir->config.bimod.table[cnt] = flipflop; flipflop = 3 - flipflop; } break; case BPredTaken: case BPredNotTaken: /* no other state */ break; default: panic("bogus branch direction predictor class"); } return pred_dir;}/* print branch direction predictor configuration */voidbpred_dir_config( struct bpred_dir *pred_dir, /* branch direction predictor instance */ char name[], /* predictor name */ FILE *stream) /* output stream */{ switch (pred_dir->class) { case BPred2Level: fprintf(stream, "pred_dir: %s: 2-lvl: %d l1-sz, %d bits/ent, %s xor, %d l2-sz, direct-mapped\n", name, pred_dir->config.two.l1size, pred_dir->config.two.shift_width, pred_dir->config.two.xor ? "" : "no", pred_dir->config.two.l2size); break; case BPred2bit: fprintf(stream, "pred_dir: %s: 2-bit: %d entries, direct-mapped\n", name, pred_dir->config.bimod.size); break; case BPredTaken: fprintf(stream, "pred_dir: %s: predict taken\n", name); break; case BPredNotTaken: fprintf(stream, "pred_dir: %s: predict not taken\n", name); break; default: panic("bogus branch direction predictor class"); }}/* print branch predictor configuration */voidbpred_config(struct bpred *pred, /* branch predictor instance */ FILE *stream) /* output stream */{ switch (pred->class) { case BPredComb: bpred_dir_config (pred->dirpred.bimod, "bimod", stream); bpred_dir_config (pred->dirpred.twolev, "2lev", stream); bpred_dir_config (pred->dirpred.meta, "meta", stream); fprintf(stream, "btb: %d sets x %d associativity", pred->btb.sets, pred->btb.assoc); fprintf(stream, "ret_stack: %d entries", pred->retstack.size); break; case BPred2Level: bpred_dir_config (pred->dirpred.twolev, "2lev", stream); fprintf(stream, "btb: %d sets x %d associativity", pred->btb.sets, pred->btb.assoc); fprintf(stream, "ret_stack: %d entries", pred->retstack.size); break; case BPred2bit: bpred_dir_config (pred->dirpred.bimod, "bimod", stream); fprintf(stream, "btb: %d sets x %d associativity", pred->btb.sets, pred->btb.assoc); fprintf(stream, "ret_stack: %d entries", pred->retstack.size); break; case BPredTaken: bpred_dir_config (pred->dirpred.bimod, "taken", stream); break; case BPredNotTaken: bpred_dir_config (pred->dirpred.bimod, "nottaken", stream); break; default: panic("bogus branch predictor class"); }}/* print predictor stats */voidbpred_stats(struct bpred *pred, /* branch predictor instance */ FILE *stream) /* output stream */{ fprintf(stream, "pred: addr-prediction rate = %f\n", (double)pred->addr_hits/(double)(pred->addr_hits+pred->misses)); fprintf(stream, "pred: dir-prediction rate = %f\n", (double)pred->dir_hits/(double)(pred->dir_hits+pred->misses));}/* register branch predictor stats */voidbpred_reg_stats(struct bpred *pred, /* branch predictor instance */ struct stat_sdb_t *sdb) /* stats database */{ char buf[512], buf1[512], *name; /* get a name for this predictor */ switch (pred->class) { case BPredComb: name = "bpred_comb"; break; case BPred2Level: name = "bpred_2lev"; break; case BPred2bit: name = "bpred_bimod"; break; case BPredTaken: name = "bpred_taken"; break; case BPredNotTaken: name = "bpred_nottaken"; break; default: panic("bogus branch predictor class"); } sprintf(buf, "%s.lookups", name); stat_reg_counter(sdb, buf, "total number of bpred lookups", &pred->lookups, 0, NULL); sprintf(buf, "%s.updates", name); sprintf(buf1, "%s.dir_hits + %s.misses", name, name); stat_reg_formula(sdb, buf, "total number of updates", buf1, "%11.0f"); sprintf(buf, "%s.addr_hits", name); stat_reg_counter(sdb, buf, "total number of address-predicted hits", &pred->addr_hits, 0, NULL); sprintf(buf, "%s.dir_hits", name); stat_reg_counter(sdb, buf, "total number of direction-predicted hits " "(includes addr-hits)", &pred->dir_hits, 0, NULL); if (pred->class == BPredComb) { sprintf(buf, "%s.used_bimod", name); stat_reg_counter(sdb, buf, "total number of bimodal predictions used", &pred->used_bimod, 0, NULL); sprintf(buf, "%s.used_2lev", name); stat_reg_counter(sdb, buf, "total number of 2-level predictions used", &pred->used_2lev, 0, NULL); } sprintf(buf, "%s.misses", name); stat_reg_counter(sdb, buf, "total number of misses", &pred->misses, 0, NULL); sprintf(buf, "%s.jr_hits", name); stat_reg_counter(sdb, buf, "total number of address-predicted hits for JR's", &pred->jr_hits, 0, NULL); sprintf(buf, "%s.jr_seen", name); stat_reg_counter(sdb, buf, "total number of JR's seen", &pred->jr_seen, 0, NULL); sprintf(buf, "%s.bpred_addr_rate", name); sprintf(buf1, "%s.addr_hits / %s.updates", name, name); stat_reg_formula(sdb, buf, "branch address-prediction rate (i.e., addr-hits/updates)", buf1, "%9.4f"); sprintf(buf, "%s.bpred_dir_rate", name); sprintf(buf1, "%s.dir_hits / %s.updates", name, name); stat_reg_formula(sdb, buf, "branch direction-prediction rate (i.e., all-hits/updates)", buf1, "%9.4f"); sprintf(buf, "%s.bpred_jr_rate", name); sprintf(buf1, "%s.jr_hits / %s.jr_seen", name, name); stat_reg_formula(sdb, buf, "JR address-prediction rate (i.e., JR addr-hits/JRs seen)", buf1, "%9.4f"); sprintf(buf, "%s.retstack_pushes", name); stat_reg_counter(sdb, buf, "total number of address pushed onto ret-addr stack", &pred->retstack_pushes, 0, NULL); sprintf(buf, "%s.retstack_pops", name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -