去年写的代码了,不是最优解,但是可以保证得解,毕业了,开源吧
// 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