【體系結構】轉移預測器設計與比較

關聯預測器

一個[m,n]預測器表示使用前m個分支行爲去從2^m個分支預測中進行選擇,每一個預測是對應於單個分支的n位預測器。這種相關分支預測器的吸引人之處,即在於它與兩位預測器相比可以取得更高的預測率,並且只需要少量的額外硬件支持。其硬件的簡單性表現在:最近m個分支的全局歷史記錄可以記錄在一個m位移位寄存器中,每一位記錄着該分支是被執行還是未被執行。對分支預測緩衝站的訪問可由分支地址的低位拼接上m位全局歷史記錄而得到。以下是一個[2,2]預測器及如何訪問預測器的例子。


下面具體實現一個[10,2]的關聯預測器

[10,2]關聯預測器表示使用前10個分支行爲去從2^10個分支預測中進行選擇,每一個預測是對應於單個分支的2位預測器。最近10個分支的全局歷史可以記錄在一個10位移位寄存器中,每一位記錄着該分支是被執行還是未被執行。實驗要求限制30K空間,即2^10*2*分支選擇的入口數目=30K,得到分支選擇的入口數目是15,爲方便編程,近似使用16bit入口數目,即用低4位地址作爲入口地址。於是,對分支預測緩衝站可由分支地址的低4位拼接上10位全局歷史記錄而得到。[10,2]關聯預測器設計如下圖所示。


2位預測期可以表示4種狀態,計數器在分支執行時加1,不執行時減1;計數器在00或11時處於飽和狀態。2位預測器狀態轉移情況如下圖。


所設計的[10,2]關聯預測器大小爲: 2^10×2 ×16=32K bit。

Tournament預測器

Tournament預測器使用兩個預測期:一個基於全局信息的Global Predictor,以及一個基於局部信息的Local Predictor,並使用一個選擇器在局部預測器與全局預測器中做出選擇。具體設計如下:


全局預測器:使用最後12個分支跳轉情況進行索引,即全局預測器也有2^12=4K個入口,每個入口都是一個標準的兩位預測器。
局部預測器:設計爲兩層,上面一層是一個局部歷史記錄,使用指令地址的低10位進行地址索引,即有2^10=1K個入口,每個入口10位,分別對應這個入口最近的10個分支,即最近10次分支的跳轉情況,這種10位歷史記錄允許對10個分支進行記錄和預測,從局部歷史記錄選擇出的入口對一個1K的入口表進行索引,這些入口由3位計數器構成,以提供本地預測。
選擇器:使用分支局部地址的低12位分支局部地址索引,即有2^12=4K個選擇器,每個索引得到一個兩位計數器,用來選擇使用局部預測器還是使用全局預測器的預測結果。在設計時默認使用局部預測器,當兩個預測器都正確或都不正確時,不改變計數器;當全局預測器正確而局部預測器預測錯誤時,計數器加1,否則減1。其狀態轉移情況如下圖。


所設計的Tournament預測器大小爲: 2^12×2+2^10×10+2^10 ×3+2^12×2=29K bit。

*此外,在蒐集資料時發現有些文獻的選擇器使用全局歷史,即最近12個分支的情況作爲選擇器的兩位計數器,實驗時也嘗試瞭如下設計,但結果證明第一種情況更好。


分支歷史表預測器

最簡單的動態分支預測方案是分支歷史表。分支歷史表是一個較小的按照分支地址的低位地址部分進行訪問的存取器。即存儲器中包含n位預測位以說明分支是否曾成功轉移,在實驗中實現此種簡單的2bit分支歷史表預測器作爲性能對比。同樣限制爲30K內存,則2×分支歷史選擇的入口數目=30K,得到分支選擇的入口數爲30K,即可得到指令低14bit作爲預測器索引。

所設計分支歷史表預測器大小爲: 2^14×2=32K bit。


實驗代碼

// Branch Predication Simulation
// Coded by Wei Lan (Student ID: 1201214149)

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <bitset>
#include <map>
#include <vector>
#include <set>
#include <cmath>
using namespace std;

// global variables
#define BITS4  0x0000f
#define BITS10 0x003ff
#define BITS12 0x00fff
#define BITS14 0x03fff

// 2-bit branch history table predictor
vector<bitset<2> > branch_history_table(pow((float)2,14),bitset<2>(string("00")));

// [10,2] correlating predictor
const int M=10;
const int N=2;
const int ADD_INDEX=14-M;
int branch_saved=0;
int predict_true=0,predict_false=0,actual_true=0,actual_false=0;
bitset<M> latest_branch(string("0000000000"));
vector<vector<bitset<N> > > correlating_predictor_table(pow((float)2,ADD_INDEX),vector<bitset <N> >(pow((float)2,M), bitset<N>(string("00"))));

// tournament predictor
vector< bitset<10> > local_history_table(pow((float)2,10), bitset<10>(string("0000000000")));
vector< bitset<3> > local_predictor_table(pow((float)2,10),bitset<3>(string("000")));
vector< bitset<2> > global_predictor_table(pow((float)2,12), bitset<2>(string("00")));
bitset<12> global_history_table(string("000000000000"));
int global_saved=0;
vector<bitset<2> > selecotors(pow((float)2,12), bitset<2>(string("00")));

// predition fuction
bool correlating(string current_pc, string next_pc);
bool tournament(string current_pc, string next_pc);
bool bht(string current_pc,string next_pc);

int main(){
	string filenames[7]={"gcc.log", "compress.log", "crafty.log", "gzip.log", "mcf.log", "parser.log", "vpr.log"};
	double bht_average=0.0,correlating_average=0.0,tournament_average=0.0;
	for(int i=0;i<7;i++){
		cout<<"Testing file: "<<filenames[i]<<endl;
		ifstream fin(filenames[i]);
		int bht_predict_correct=0,bht_predict_wrong=0,
			correlating_predict_correct=0,correlating_predict_wrong=0,
			tournament_predict_correct=0,tournament_predict_wrong=0;
		string line;
		while(getline(fin,line)){
			stringstream theline(line);
			theline<<line;
			string current_pc;
			string next_pc;
			theline>>current_pc;
			theline>>next_pc;
			if(bht(current_pc,next_pc))
				++bht_predict_correct;
			else
				++bht_predict_wrong;
			if(correlating(current_pc,next_pc))
				++correlating_predict_correct;
			else
				++correlating_predict_wrong;
			if(tournament(current_pc,next_pc))
				++tournament_predict_correct;
			else
				++tournament_predict_wrong;

		}
		float bht_correct_rate=(float)(bht_predict_correct)/(float)(bht_predict_correct+bht_predict_wrong);
		cout<<"The correct rate for 2-bit branch history table predictor is: "<<bht_correct_rate<<endl;
		bht_average+=bht_correct_rate;
		float correlating_correct_rate=(float)correlating_predict_correct/(float)(correlating_predict_correct+correlating_predict_wrong);
		cout<<"The correct rate for ("<<M<<","<<N<<") correlating predictor is: "<<correlating_correct_rate<<endl;
		correlating_average+=correlating_correct_rate;
		float tournament_correct_rate=(float)tournament_predict_correct/(float)(tournament_predict_correct+tournament_predict_wrong);
		cout<<"The correct rate for tournament predictor is: "<<tournament_correct_rate<<endl;
		tournament_average+=tournament_correct_rate;
		cout<<endl;
		fin.close();
	}
	bht_average /=7.0;
	correlating_average /=7.0;
	tournament_average /=7.0;
	cout<<"Average: "<<bht_average<<" "<<correlating_average<<" "<<tournament_average<<endl;

	return 0;
}

bool correlating(string current_pc, string next_pc){
	bool jump_actual=false,jump_predict=false;
	long current_add=strtol(current_pc.c_str(), NULL, 16);
	long next_add=strtol(next_pc.c_str(), NULL, 16);

	bitset<ADD_INDEX> current_add_low=bitset<ADD_INDEX>(current_add & BITS4);
	if(correlating_predictor_table[current_add_low.to_ulong()][latest_branch.to_ullong()].at(1)==1)
		jump_predict=true;

	if((next_add-current_add)!=4)
		jump_actual=true;
	
	// Reset predictor and tables
	if(jump_actual){
		long tmp_predict=correlating_predictor_table[current_add_low.to_ulong()][latest_branch.to_ullong()].to_ulong();
		tmp_predict=(tmp_predict+1)>3 ? 3: (tmp_predict+1);
		correlating_predictor_table[current_add_low.to_ulong()][latest_branch.to_ullong()]=bitset<N>(tmp_predict);
	}
	else {
		long tmp_predict=correlating_predictor_table[current_add_low.to_ulong()][latest_branch.to_ullong()].to_ulong();
		tmp_predict=(tmp_predict-1)<0 ? 0: (tmp_predict-1);
		correlating_predictor_table[current_add_low.to_ulong()][latest_branch.to_ullong()]=bitset<N>(tmp_predict);
	}
	long tmp_latest=latest_branch.to_ulong();
	latest_branch=bitset<M>( (tmp_latest << 1 ) & BITS10);
	latest_branch[0]=jump_actual ? 1 : 0;
	return !(jump_actual ^ jump_predict);
}



bool tournament(string current_pc, string next_pc){
	bool jump_actual=false,jump_predict=false,
		local_predict=false,global_predict=false;
	long current_add=strtol(current_pc.c_str(), NULL, 16);
	long next_add=strtol(next_pc.c_str(), NULL, 16);
	// Local predict 
	int local_index=current_add & BITS10;
	if(local_predictor_table[local_history_table[local_index].to_ulong()].at(2)==1){
		local_predict=true;
	}
	// Global predict
	if(global_predictor_table[global_history_table.to_ulong()].at(1)==1){
		global_predict=true;
	}
	if(selecotors[current_add & BITS12].at(1)==0)
		jump_predict=local_predict;
	else
		jump_predict=global_predict;

	// Update local and predictors and tables
	if((next_add-current_add)!=4)
		jump_actual=true;

	if(jump_actual){
		long local_tmp=local_predictor_table[local_history_table[local_index].to_ulong()].to_ulong();
		local_tmp=(local_tmp+1) > 7 ? 7 : (local_tmp+1) ;
		local_predictor_table[local_history_table[local_index].to_ulong()]=bitset<3>(local_tmp);
	}
	else{
		long local_tmp=local_predictor_table[local_history_table[local_index].to_ulong()].to_ulong();
		local_tmp=(local_tmp-1) < 0 ? 0 : (local_tmp-1) ;
		local_predictor_table[local_history_table[local_index].to_ulong()]=bitset<3>(local_tmp);
	}
	long local_history_tmp=local_history_table[local_index].to_ulong();
	local_history_tmp=(local_history_tmp<<1) & BITS10;
	local_history_table[local_index]=bitset<10>(local_history_tmp);
	local_history_table[local_index][0]= jump_actual ? 1: 0;

	// Update global and predictors and tables
	if( jump_actual){
		long global_tmp=global_predictor_table[global_history_table.to_ulong()].to_ulong();
		global_tmp=(global_tmp+1) > 3 ? 3 : (global_tmp+1) ;
		global_predictor_table[global_history_table.to_ulong()]=bitset<2>(global_tmp);
	}
	else {
		long global_tmp=global_predictor_table[global_history_table.to_ulong()].to_ulong();
		global_tmp=(global_tmp-1) < 0 ? 0 : (global_tmp-1) ;
		global_predictor_table[global_history_table.to_ulong()]=bitset<2>(global_tmp);
	}
	long global_history_tmp=global_history_table.to_ulong();
	global_history_tmp=( (global_history_tmp<<1) & BITS12);
	global_history_table=bitset<12>(global_history_tmp);
	global_history_table[0]=jump_actual ? 1:0;

	// Update selecotrs
	if(local_predict^global_predict){
		if( local_predict^jump_actual ){
			long selecotor_tmp=selecotors[current_add & BITS12].to_ulong();
			selecotor_tmp=(selecotor_tmp+1)>3 ? 3:  (selecotor_tmp+1);
			selecotors[current_add&0xfff]=bitset<2>(selecotor_tmp);
		}
		else if(global_predict^jump_actual ){
			long selecotor_tmp=selecotors[current_add & BITS12].to_ulong();
			selecotor_tmp=(selecotor_tmp-1)<0 ? 0:  (selecotor_tmp-1);
			selecotors[current_add&0xfff]=bitset<2>(selecotor_tmp);
		}
	}

	return !(jump_actual ^ jump_predict);
}

bool bht(string current_pc,string next_pc){
	bool jump_actual=false,jump_predict=false;
	long current_add=strtol(current_pc.c_str(), NULL, 16);
	long next_add=strtol(next_pc.c_str(), NULL, 16);

	if((next_add-current_add)!=4)
		jump_actual=true;

	if(branch_history_table[current_add & BITS14].at(1))
		jump_predict=true;

	// Update histroy table
	if(jump_actual){
		long tmp=branch_history_table[current_add & BITS14].to_ulong();
		tmp=(tmp+1)>3 ? 3:(tmp+1);
		branch_history_table[current_add & BITS14]=bitset<2>(tmp);
	}
	else{
		long tmp=branch_history_table[current_add & BITS14].to_ulong();
		tmp=(tmp-1)<0 ? 0:(tmp-1);
		branch_history_table[current_add & BITS14]=bitset<2>(tmp);
	}
	return !(jump_actual ^ jump_predict);

}


(轉載請註明作者和出處:http://blog.csdn.net/xiaowei_cqu 未經允許請勿用於商業用途)





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章