[计算机系统] HNU实验4 tracefile 生成器和分析思路

去年写的代码了,不是最优解,但是可以保证得解,毕业了,开源吧

// traceFileGenerator.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
// s = 4 (有2^4 = 16个Cache组)  bits,E = 4 (每组有4行) ,b = 4 (每行有2^b = 2 ^ 4 = 16bytes)
// 要求命中次数为 20 、替换次数为 20, 且至少访问  10  个 Cache 组
// hits = 20, evictions = 20, cacheSets = 10
// 生成的数据格式:
// 第一行 I num1 num2 顶格(可以省略)
// 从第二行开始使用 :前面空一格,然后L/S/M,然后再空一格 + 地址值 + 偏移量(用一个 1 =< 随机数 < 2^b)+ 换行
// 分析:
// M 操作是一次L,一次S,即要么提供两次hit,0次eviction; 
//   要么提供一次miss(第一次L),一次hit(第二次S),eviction为0还是1要看这个组中是否出现了全满的情况
//  (全满则驱逐eviction=1,否则为0)

// L 和 S 的行为是一致的,在生成代码的时候,L和S标记可以任意替换
// 分析L的行为:
// 首先肯定是读到了一行 L addr, bias(不用管这个bias)
// 根据 addr 解析出  (行标记)+(组索引)+(块偏移)
// 每次相隔的地址值相差2^(b+s)就会发生同一个组的现象 
// (分析极限情况 addr = lineNum + setNum + bias),两个setNum相同就会出现分到同一个组
// 想让两个setNum完全相同,那么就是加上一个lineNum最低位为1的值,即2^(b+s)
// 
// 如果此时E = 1,那么不同的地址就是一定会发生驱逐,eviction++
// E !=  1时

// 为了使得M指令占到1/3所以优先使用M指令
// 因为必须要访问对应的cacheSets个cache组
// 所以首先使用M指令访问连续cacheSets个cache的第一行(E>=1,第一行一定能被访问到)
// 从第0组访问到第cacheSets-1组
// 所以前cacheSets条指令为:
// M randAddr, randValue     有限制:(0<=randAddr<2^b) (1=< randValue <2^b-randAddr)
// M randAddr+2^b, randValue 
// ...

// M randAddr+(cacheSets-1)*(2^b)
// 这样以后就会产生 cacheSets 次hits和miss,0次eviction
// 同时使用了 cacheSets 次M,提高了M的占比

// 接着看问题:
// 要求命中次数为 20                      替换次数为 20           且至少访问  10  个 Cache 组
//  hits (20 - cacheSets = 10次)   evictions(20 - 0 = 20次)     cacheSets(已经满足)

// 还有需要 hits - cacheSets (10) 次 hits 和 evication (20) 次 evication
// 要产生 hits 非常简单,只需要对第0组的同一个地址进行hits - cacheSets访问即可
// 使用M 指令 M randAddr, randValue 有限制:(0<=randAddr<2^b) (1=< randValue <2^b-randAddr)
// hits - cacheSets次就可以了,这样仅仅会产生hits,而且提高了M指令的使用次数

// 到这里,已经解决了命中次数,和至少访问Cache组的需求
// 而且到目前为止,都只使用了M指令而没有使用S/L指令

// 那么还剩下evication的evication次的次数需求没有满足
// 此时只需要驱逐evication次就可以了

// 要产生替换,前提是一个组全部都填满了
// 然后再交替地向这个组中写间隔2^(b+s)的数据就可以了
// 同样是首先将第0组填满,此时就不能使用M了,因为使用M会带来命中
// 所以使用 E-1次L或者S来将第0组填满
// L/S randAddr+1*2^(b+s), randValue     有限制:(0<=randAddr<2^b) (1=< randValue <2^b-randAddr)
// L/S randAddr+2*2^(b+s), randValue
// L/S randAddr+3*2^(b+s), randValue
// ...
// L/S randAddr+(E-1)*2^(b+s), randValue
// 这样的E-1次操作全部都会不命中

// 这样过后,就完成了驱逐的条件准备,因为此时向第0组中交替写数据就可以了
// int count = evictions; 
// int i = 0;
// while(count>0){
//    L/S randAddr+(E+i)*2^(b+s), randValue    有限制:(0<=randAddr<2^b) (1=< randValue <2^b-randAddr)
//    count--;
// }

// 经过evictions次循环,就完成了evication的要求
// M指令的占比达到了
// (cacheSets + hits) / (cacheSets + hits + E - 1 + evications)
// 在实例的题目中 E = 4, hits = 20, evictions = 20, cacheSets = 10
// 10+20 / 10+20+3+20 = 0.566 > 1 / 3
// 满足所有要求

// 情形2:
// 上面的分析已经解决了cacheSets >= hits 的情况
// 下面要分析cacheSets < hits的情况
// 在cacheSets >= hits 的时候,可以确定性地一次性进行cacheSets次M访问
// 这样带来了CacheSets次命中(不命中次数不统计,忽略)

// 情形二算法流程:
// 第一步:当cacheSet < hits  的时候,只能进行hits次M访问,趁机访问hits个不同的组
// 还有cacheSets - hits个Set需要访问,那么此时就不能再用M去访问这些新组了

// 第二步:再应该使用L/S去访问这些新的组 即再使用L / S 去访问这cacheSets - hits个Sets
// 这样就完成了访问组的要求和hits的要求

// 第三步:完成eviction的要求
// eviction仍然是首先将第一组填满,只能用L/S 不能使用M(会带来新的hit)

// 第四步:完成eviction的要求
// 然后使用L/S 指令循环访问第一个Set,设置循环周期为E+1(或者+2),防止溢出


/*
 L 10,1
 M 20,1
 L 22,1
 S 18,1
 L 110,1
 L 210,1
 M 12,1
*/
// 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
// #define DEBUG

#pragma warning(disable: 4996)

using namespace std;

// 随机数生成器
int randInt(int a, int b) {
	int temp = 0;
	temp = int(double(rand()) / RAND_MAX * (b - a) + a);
	return temp;
}

// 10进制转16进制
string getHexStr(int colorValue) {
	char hexStr[10];
	memset(hexStr, sizeof(hexStr), '\0');
	if (hexStr) {
		memset(hexStr, sizeof(hexStr), '\0');
		sprintf(hexStr, "%X", colorValue);
	}
	string hexString = hexStr;
	
#ifdef DEBUG
	printf("colorValue = %d , str = %s \n", colorValue, hexStr);
#endif // DEBUG

	return hexString;
}

// 判断是否为偶数,为偶数返回true
bool isEvenNum(int num) {
	while (num > 0) {
		num -= 2;
	}
	if (num == 0) {
		return true;
	}
	return false;
}
map  addrMap;

string addMap(string addr) {
	std::map::iterator it = addrMap.find(addr);
	// 如果不在map中
	if (it == addrMap.end()) {
		addrMap.insert(std::pair(addr, 1));
	}
	else {	// 如果在map中,地址次数+1
		addrMap[addr] = addrMap[addr] + 1;
	}
	return addr;
}

void checkAddr() {
	bool hasBug = true;
	int count = 0;
	cout << "\nAddress Repeat check Result: \n";
	for (std::map::iterator it = addrMap.begin(); it != addrMap.end(); ++it) {
		if (it->second > 1) {
			std::cout << "Modification Needed" << it->first << " => " << it->second << '\n';
			hasBug = true;
		}
		count++;
	}
	if (!hasBug) {
		cout << "All " << count << " addresses has been checked for no repeat." << endl;
	}
}

int main()
{
	
	srand(time(0));

	int s = 0;
	int E = 0;
	int b = 0;
	int hits = 0;
	int evictions = 0;
	int cacheSets = 0;
	
	// 记录报告信息
	int lineCounters = 0;  // 总生成指令条数
	int MCmdCounters = 0;  // M 指令条数
	

	cout << "Enter s = ";
	cin >> s;
	cout << "Enter E = ";
	cin >> E;
	cout << "Enter b = ";
	cin >> b;
	cout << "Enter hits = ";
	cin >> hits;
	cout << "Enter evictions = ";
	cin >> evictions;
	cout << "Visit cacheSets >= ";
	cin >> cacheSets;
	cout << "Enter ID = ";
	string ID;
	cin >> ID;
	// begin to write file
	ofstream fout;

#ifdef DEBUG
	fout.open("C:/Users/lenovo/Desktop/debug/debug_trace_" + ID + ".trace");
#else
	fout.open("./trace_"+ID+".trace");
#endif

	// 首先解决至少访问的cache组数

	// 为了使得M指令占到1/3所以优先使用M指令
	// 因为必须要访问对应的cacheSets个cache组
	// 所以首先使用M指令访问连续cacheSets个cache的第一行(E>=1,第一行一定能被访问到)
	// 从第0组访问到第cacheSets-1组
	// 所以前cacheSets条指令为:
	// M randAddr, randValue     有限制:(0<=randAddr<2^b-1) (1=< randValue <2^b-1-randAddr)
	// M randAddr+2^b, randValue 
	// ...

	// 为了简单首先使用randAddr = 0
	int tempAddr = 0;
	if (cacheSets <= hits) {
		for (int i = 0; i < cacheSets; i++) {
			lineCounters++;
			MCmdCounters++;
			int ranI = randInt(0, pow(2, b) - 2);
			// fout << " M " << getHexStr(tempAddr) << ", " << getHexStr(randInt(1, pow(2, b) - 1 - ranI)) << endl;
			fout << " M " << addMap(getHexStr(tempAddr)) << ", " << getHexStr(ranI) << endl;
			tempAddr += (int)(pow(2, b));
		}
	}
	else { // cacheSets < hits
		for (int i = 0; i < hits; i++) {
			lineCounters++;
			MCmdCounters++;
			int ranI = randInt(0, pow(2, b) - 2);
			// fout << " M " << getHexStr(tempAddr) << ", " << getHexStr(randInt(1, pow(2, b) - 1 - ranI)) << endl;
			fout << " M " << addMap(getHexStr(tempAddr)) << ", " << getHexStr(ranI) << endl;
			tempAddr += (int)(pow(2, b));
		}

		// 第二种情况:
		// cacheSets - hits个Set需要访问,那么此时就不能再用M去访问这些新组了, 使用L/S
		// 第二步:再应该使用L/S去访问这些新的组 即再使用L / S 去访问这cacheSets - hits个Sets
		// 这样就完成了访问组的要求和hits的要求
		for (int i = 0; i < cacheSets - hits; i++) {
			lineCounters++;
			int ranI = randInt(0, pow(2, b) - 2);
			int randChoice = randInt(3, 6);
			if (randChoice == 3 || randChoice == 5) {
				fout << " L ";
			}
			else {
				fout << " L ";
			}
			// fout << " M " << getHexStr(tempAddr) << ", " << getHexStr(randInt(1, pow(2, b) - 1 - ranI)) << endl;
			fout << addMap(getHexStr(tempAddr)) << ", " << getHexStr(ranI) << endl;
			tempAddr += (int)(pow(2, b));
		}
	}

#ifdef DEBUG
	cout << "30%" << endl;
#endif // DEBUG
	
	

	if (cacheSets <= hits) {
		// 然后处理命中次数
		// 还有需要 hits - cacheSets (10) 次 hits 和 evication (20) 次 evication
		// 要产生 hits 非常简单,只需要对第0组的同一个地址进行hits - cacheSets访问即可
		// 使用M 指令 M randAddr, randValue 有限制:(0<=randAddr<2^b) (1=< randValue <2^b-randAddr)
		// hits - cacheSets次就可以了,这样仅仅会产生hits,而且提高了M指令的使用次数

		// 如果是偶数次,那么直接( hits - cacheSets / 2 )次 M 操作 就可以了
		int noRepeat = 1;
		if (isEvenNum(hits - cacheSets)) {
			for (int i = 0; i < (hits - cacheSets) / 2; i++) {
				lineCounters++;
				MCmdCounters++;
				tempAddr = 0;
				int ranI = randInt(0, pow(2, b) - 2);
				fout << " M " << addMap(getHexStr(tempAddr+noRepeat)) << ", " << getHexStr(ranI) << endl;
				noRepeat++;
			}
		}
		else {
			// 基数次
			// 第一个用L,之后的偶数次(可能是0)用M
			tempAddr = 0;
			fout << " L " << tempAddr << ", " << 1 << endl;
			for (int i = 0; i < (hits - cacheSets - 1) / 2; i++) {
				tempAddr = 0;
				MCmdCounters++;
				lineCounters++;
				int ranI = randInt(0, pow(2, b) - 2);
				fout << " M " << addMap(getHexStr(tempAddr + noRepeat)) << ", " << getHexStr(ranI) << endl;
				noRepeat++;
			}
		}
	}

#ifdef DEBUG
	cout << "60%" << endl;
#endif // DEBUG
	
	
	
	// 最后处理替换问题
	// 那么还剩下evication的evication次的次数需求没有满足
	// 此时只需要驱逐evication次就可以了

	// 要产生替换,前提是一个组全部都填满了
	// 然后再交替地向这个组中写间隔2^(b+s)的数据就可以了
	// 同样是首先将第0组填满,此时就不能使用M了,因为使用M会带来命中
	// 所以使用 E-1次L或者S来将第0组填满
	// L/S randAddr+1*2^(b+s), randValue     有限制:(0<=randAddr<2^b) (1=< randValue <2^b-randAddr)
	// L/S randAddr+2*2^(b+s), randValue
	// L/S randAddr+3*2^(b+s), randValue
	
	// 首先把第一组填满
	
	for (int i = 0; i < E - 1; i++) {
		lineCounters++;
		// int ranI = randInt(0, pow(2, b) - 1);
		int randChoice = randInt(3, 6);
		if (randChoice == 3 || randChoice == 5){
			fout << " L ";
		}
		else {
			fout << " L ";
		}
		int ranI = randInt(0, pow(2, b) - 2);
		fout << addMap(getHexStr(((i + 1) * (int)(pow(2, (b + s)))))) << ", " << getHexStr(ranI) << endl;
	}
	
	// 然后不停地驱逐
	// 这样过后,就完成了驱逐的条件准备,因为此时向第0组中交替写数据就可以了
	int count = evictions; 
	int i = 0;
	tempAddr = 0;
	while(count>0){
		lineCounters++;
		// int ranI = randInt(0, pow(2, b) - 1);
		int randChoice = randInt(3, 6);
		if (randChoice == 3 || randChoice == 5) {
			fout << " L ";
		}
		else {
			fout << " L ";
		}
		int ranI = randInt(0, pow(2, b) - 2);
		fout << addMap(getHexStr(((tempAddr) + (i+E) * (int)(pow(2, (b + s)))))) << ", " << getHexStr(ranI) << endl;
		count--;
		i++;
	}
	
#ifdef DEBUG
	cout << "100%" << endl;
#endif // DEBUG
	
	
	
	fout << flush;
	fout.close();


	// show in std io:
	cout << endl << "-------------------------R E P O R T-------------------------" << endl << endl;
	cout << "All Traces : " << lineCounters << " lines\n";
	cout << "M orders : " << MCmdCounters << " times\n";
	cout << "M order rates : " << double(MCmdCounters) / double(lineCounters) << "\n";
	cout << "L order rates : " << 1 - double(MCmdCounters) / double(lineCounters) << "\n";
	cout << "Effects should look like : ";
	cout << "hits:" << hits << " misses:" << cacheSets + E - 1 + evictions << " evictions:" << evictions << endl;
	cout << "Visited the Sets from Cache->sets[0] to Cache->sets[" << cacheSets - 1 << "]" << endl;
#ifdef DEBUG
	cout << "CMD : ./csim-ref -s " << s << " -E " << E << " -b " << b << " -t traces/debug_trace_" << ID << ".trace\n\n";
#else
	cout << "CMD : ./csim-ref -s " << s << " -E " << E << " -b " << b << " -t traces/trace_" << ID << ".trace\n\n";
#endif
	// 检查是否有重复地址
	checkAddr();
	cout << "----------- By IdioSpace Technology @ youhengchan -----------" << endl << endl;

#ifdef DEBUG
	fout.open("C:/Users/lenovo/Desktop/debug/debug_report_" + ID + ".txt");
#else
	fout.open("./report_" + ID + ".txt");
#endif
	// 输出trace file 效果:
	
	fout << "-----------------------U S E R  I N F O-----------------------" << endl;
	fout << "Cache s = " << s << endl;
	fout << "Cache E = " << E << endl;
	fout << "Cache b = " << b << endl;
	fout << "Q hits = " << hits << endl;
	fout << "Q evictions = " << evictions << endl;
	fout << "Q Visit cacheSets >= " << cacheSets << endl;

	fout << endl << "-------------------------R E P O R T--------------------------" << endl;
	fout << "All Traces : " << lineCounters << " lines\n";
	fout << "M orders : " << MCmdCounters << " times\n";
	fout << "M order rates : " << double(MCmdCounters) / double(lineCounters) << "\n";
	fout << "Effects should look like : ";
	fout << "hits:" << hits << " misses:" << cacheSets + E - 1 + evictions << " evictions:" << evictions << endl;
	fout << "Visited the Sets from Cache->sets[0] to Cache->sets[" << cacheSets - 1 << "]" << endl;
#ifdef DEBUG
	fout << "CMD : ./csim-ref -s " << s << " -E " << E << " -b " << b << " -t traces/debug_trace_" << ID << ".trace\n\n";
#else
	fout << "CMD : ./csim-ref -s " << s << " -E " << E << " -b " << b << " -t traces/trace_" << ID << ".trace\n\n";
#endif
    // misses 解释:
	// CacheSets : 首先为了解决至少访问CacheSets个组,使用CacheSets条M指令
	// E - 1:为了构造驱逐使用L/S将第一组填满
	// evictions :最后要满足eviction次驱逐,每次驱逐前全部都是misss
	

	fout << "------------------------C O N T A C T------------------------" << endl;
	fout << "Email : [email protected]" << endl;
	fout << "CSDN Blog: blog.csdn.net/chenhanxuan1999" << endl;
	fout << "Github : github.com/youhengchan" << endl;
	fout << endl << endl;
	fout << "TraceFile Generated BY IdioSpace Technology @ youhengchan\n\n" ;
	fout << flush;
	fout.close();

	system("pause");
	return 0;
}

 

你可能感兴趣的:(计算机系统,HNU实验题)