当前位置: 首页 > news >正文

CCF-202412-T3缓存模拟90分

缓存模拟

时间限制:1.0 秒

空间限制:512 MiB

相关文件:题目目录

题目背景

西西艾弗岛半导体制造厂近期正在研发一种新型的处理器产品。该处理器的缓存,计划采用组相连的方式。 为了选定合适的组相连参数,我们需要对缓存的工作过程进行模拟,进而推算其性能。

处理器的缓存,存储着内存中的部分数据。当处理器的运行需要访问内存中的数据时,如果所需数据已经存储在缓存中,则可以用更为快捷的缓存访问代替内存访问,来提高处理器性能。

处理器的缓存包含若干缓存行,每个缓存行存储特定大小的数据。为了便于叙述,我们认为处理器对内存的访问,也是以缓存行为单位进行的。 以缓存行的大小为单位,将全部内存空间划分为若干块(编号从 00 开始),这样每个内存块的数据便可以恰好存储在一个缓存行中。

nn-路组相联是这样的一种缓存结构:每 nn 个缓存行划分为一组。假设共有 NN 个这样的(编号从 00 到 N−1N−1),那么编号为 kk 的内存块仅可以被存储在编号为 (k÷n)(k÷n) 的这 nn 个缓存行的任意一个中。其中,÷÷ 表示忽略余数的整除运算, 表示整除取余数运算。一般而言,nn 和 NN 是 22 的幂次。例如,当 n=4n=4、N=8N=8 时,编号为 0、1、2、3、32、33、34、35 的内存块可以被存储在0 的任意缓存行中;编号为 4、5、6、7、36、37、38、39 的内存块可以被存储在1 的任意缓存行中。

题目描述

具体而言,给定要读取写入的内存块编号,即可确定该内存块可能位于的缓存行组的编号。此时,可能存在的情况有两种:

  • 该缓存行组的某个缓存行已经存储了该内存块的数据,即命中
  • 该缓存行组的所有缓存行都没有存储该内存块的数据,即未命中

当发生命中时,处理器可以直接使用或修改该缓存行中的数据,而不需要实际读写内存。 当发生未命中时,处理器需要从内存中读取数据,并将其存储到该缓存行组中的一个缓存行中,然后再使用或修改该缓存行中的数据。这个将内存中的数据读入到缓存的过程称为载入

当执行载入操作时,如果该缓存行组中有尚未存储数据的缓存行,那么将数据存储到其中一个尚未存储数据的缓存行中,并在缓存行中记录所存储的数据块的编号;否则,按照一定方法,选择该组中的一个缓存行,并将数据存储到其中,这一过程称为替换

当发生替换时,需要考虑被替换的缓存行是否发生过修改,即执行过操作。如果发生过修改,则需要先将缓存行中的数据写入内存中的对应位置;然后忽略该缓存行中的数据、将新读入的数据存入其中,并记录所存储数据块的编号。

在一个缓存行组中选择被替换的缓存行的方法有很多种,该种处理器采用的是最近最少使用(LRU)方法。该方法将一个缓存行组中存有数据的缓存行排成一队,每次读或写一个缓存行时,都将该缓存行移动到队列的最前端。当需要替换缓存行时,选择队列的最后一个缓存行(最久没被读写)进行替换。

本题目中,将给出一系列的处理器运行时遇到的对内存的读写指令,并假定初始时处理器的缓存为空。你需要根据上文描述的缓存工作过程,给出处理器对内存的实际读写操作序列。

输入格式

从标准输入读入数据。

输入的第一行包含空格分隔的三个整数 n,N,qn,N,q,分别表示组相联的路数 nn 和组数 NN,以及要处理的读写指令的数量 qq。

接下来 qq 行,每行包含空格分隔的两个整数 oo 和 aa。其中,oo 表示读写指令的类型,aa 表示要读写的内存块的编号。oo 为 00 或 11,分别表示读和写操作。

输出格式

输出到标准输出。

输出若干行,每行包含空格分隔的两个整数 o′o′ 和 a′a′,表示实际处理器对内存的读写操作。o′o′ 为 00 或 11,分别表示读和写操作;a′a′ 表示要读写的内存块的编号。

样例输入

4 8 8 0 0 0 1 1 2 0 1 1 0 0 32 1 33 0 34

样例输出

0 0 0 1 0 2 0 32 1 2 0 33 0 34

样例解释

该处理器的缓存为 4 路组相联,共有 8 组。初始时,处理器的缓存为空。共需要处理 8 条指令:

  • 第 1 条指令为读取内存块 0,未命中,要实际读取内存块 0,并存储到组 0 的一个缓存行;
  • 第 2 条指令为读取内存块 1,未命中,要实际读取内存块 1,并存储到组 0 的另一个缓存行;
  • 第 3 条指令为写入内存块 2,未命中,要实际读取内存块 2,并存储到组 0 的第三个缓存行,然后根据指令在缓存中对其进行修改;
  • 第 4 条指令为读取内存块 1,命中,直接从缓存中调取数据;
  • 第 5 条指令为写入内存块 0,命中,直接修改缓存中的数据;
  • 第 6 条指令为读取内存块 32,未命中,要实际读取内存块 32,并存储到组 0 的第四个缓存行;
  • 第 7 条指令为写入内存块 33,未命中,此时组 0 中的 4 个缓存行都保存了数据:最近使用的是保存有内存块 32 的缓存行,其次是保存有内存块 0 的缓存行,然后是 1,最后是 2,因此选择替换保存有内存块 2 的缓存行。注意到该缓存行在执行第 3 条指令时被修改过,因此需要先将其写入内存,然后再读取内存块 33 的数据存储到该缓存行中;
  • 第 8 条指令为读取内存块 34,未命中,此时组 0 中的 4 个缓存行都保存了数据,按照同样的办法,选择保存有内存块 1 的缓存行替换。注意到该缓存行未被修改过,因此可以直接读取内存块 34 的数据存储到该缓存行中。

子任务

对于 20% 的数据,有 n=1,N=1n=1,N=1;

对于 40% 的数据,有 n=1n=1;

另外 20% 的数据,有 N=1,q≤nN=1,q≤n;

对于 100% 的数据,有 1≤n,N,n×N≤655361≤n,N,n×N≤65536,且 n,Nn,N 为 2 的幂次;1≤q≤1051≤q≤105,0≤a<2300≤a<230。

#include<iostream> #include<vector> #include<unordered_map> #include<list> #include<cstring> using namespace std; #define dashu 100005 int n,N,q;//n cachesize; N cacheline amount; q amount of command struct danyuan{ list<int>::iterator weizhi;//队列内部的迭代器,end()是无效的 int dirty; //int bianhao;//对应的内存块编号 //int val;//模拟不需要考虑 }; struct custom_hash { size_t operator()(int x) const { x = ((x >> 16) ^ x) * 0x45d9f3b; x = ((x >> 16) ^ x) * 0x45d9f3b; x = (x >> 16) ^ x; return (size_t)x; } }; struct cache_line{ list<int> que; unordered_map<int,danyuan,custom_hash> xuhaozhi; }; void out(cache_line &hang){ cout<<"list: ---------"<<endl; for(auto it:hang.que){ cout<<it<<' '; }cout<<endl; cout<<"hash: ---------"<<endl; for(auto it:hang.xuhaozhi){ int val=it.first; cout<<val<<' '; }cout<<endl; cout<<endl; } //cache_line zuxianglian[dashu]; void read(int num){ printf("0 %d\n",num); } void write(int num){ printf("1 %d\n",num); } //输入序号,O(1)时间查到内存块是否在缓存行中 bool hit(int xuhao,cache_line &hang){ auto it=hang.xuhaozhi.find(xuhao); if(it==hang.xuhaozhi.end()){ //cout<<xuhao<<"not in dict"<<endl; return false; } //string res=(it->second.weizhi!=hang.que.end())?" hit":" not hit"; //cout<<xuhao<<res<<endl; return (it->second.weizhi!=hang.que.end()); } //通过哈希表找到list中相应的迭代器,保证list头插入该迭代器 void hitmod(int caozuo,int xuhao,cache_line &hang){ auto it=hang.xuhaozhi[xuhao].weizhi; hang.que.splice(hang.que.begin(),hang.que,it); if(hang.xuhaozhi[xuhao].dirty==0&&caozuo==1) hang.xuhaozhi[xuhao].dirty=1; } void addnode(int caozuo,int xuhao,cache_line& hang){ read(xuhao); hang.que.push_front(xuhao); auto it=hang.que.begin(); hang.xuhaozhi[xuhao]={it,caozuo}; //cout<<xuhao<<' '<<&(*it)<<endl; } int LRUvic(cache_line& hang){ return *hang.que.rbegin(); } void delmod(int victim){ write(victim); } //忽略缓存单元旧的值,把新的值放上去,顺便换到队首 void delnode(int caozuo,int xuhao,int victim,cache_line &hang){ read(xuhao); auto it=hang.xuhaozhi[victim].weizhi; *it=xuhao; //链表把删除的节点替换到最前面 hang.que.splice(hang.que.begin(),hang.que,it); //哈希表删除旧内存块索引,更新新的内存块索引 hang.xuhaozhi.erase(victim); hang.xuhaozhi[xuhao]={it,caozuo}; } void solve(int caozuo,int xuhao,cache_line &hang){ //cout<<caozuo<<' '<<xuhao<<endl; if(hit(xuhao,hang)) { hitmod(caozuo,xuhao,hang); return; } //load if((signed)hang.que.size()<n){ addnode(caozuo,xuhao,hang); //cout<<"addnode "<<caozuo<<" " <<xuhao<<" "<<&(hang)<<endl; return; } //replace int victim=LRUvic(hang);//返回队尾的内存块编号 //未命中,满队列替换,写回绝对要考虑脏位 //队列里绝对没有这个内存块 danyuan vict=hang.xuhaozhi[victim]; if(vict.dirty){ delmod(victim); } delnode(caozuo,xuhao,victim,hang); return; } int main(){ //freopen("1.in","r",stdin); ios_base::sync_with_stdio(0); cin.tie(0); scanf("%d %d %d",&n,&N,&q); //试试模块化,一步步来 //初始化一下 vector<cache_line> zuxianglian(N); for (int i = 0; i < N; i++) { zuxianglian[i].xuhaozhi.reserve(n * 2); // 提前分配足够桶 zuxianglian[i].xuhaozhi.max_load_factor(0.25); // 降低负载率,减少碰撞 } for(int i=1;i<=q;i++){ int caozuo,xuhao;//操作 序号 scanf("%d %d",&caozuo,&xuhao); int formatxuhao=xuhao%(n*N); int gn=formatxuhao/n; auto &hang=zuxianglian[gn]; //cout<<"start----- "<<caozuo<<' '<<xuhao<<endl; solve(caozuo,xuhao,hang); //out(hang); //cout<<caozuo<<' '<<xuhao<<' '<<gn<<endl; } return 0; }

非常奇怪,不使用哈希表是90分,用了哈希表也是90,红黑树也是90,Claude生成了双向链表和手搓哈希表,加快读都没过,非常奇怪,不知道性能瓶颈在哪里。也构造了新的哈希函数避免哈希被卡。太奇怪了,百思不得其解

http://www.jsqmd.com/news/512530/

相关文章:

  • 巴西空运专线市场盘点:五大服务商助力中巴贸易 - 时事观察官
  • remove high frequency but keep low frequency
  • 20252918 2025-2026-2 《网络攻防实践》第1周作业
  • VMware 虚拟机安装--urbutun3种下载的镜像选择指南
  • Clawdbot优化升级:提升Qwen3:32B代理网关性能与稳定性的方法
  • 光伏PV三相并网逆变器MATLAB仿真模型:高效功率输出与稳定直流母线电压
  • RP2040嵌入式视觉平台:轻量级MIPI/并行摄像头采集方案
  • RP2350A开发板硬件设计与电源架构解析
  • msjint40.dll文件丢失不可怕 免费下载修复方法分享
  • 2026年上海房产律师推荐:房产继承分割难题高性价比律师与避坑指南 - 十大品牌推荐
  • 从Demo到实战:手把手教你定制Cartographer的Launch和Lua配置文件(Gazebo仿真版)
  • 手机号逆向查询QQ号:3步快速找回遗忘账号的终极指南
  • ESP32 cam (3)http协议 上传图片给电脑flask服务器 - MKT
  • 聊聊菲尔格林产品的优势,2026年干冰清洗机选购哪家好 - myqiye
  • IT 补丁管理的8大深坑,如何破解?
  • CNN架构解析:TranslateGemma模型中的卷积神经网络应用
  • 告别机械音!Qwen3-TTS实测:97ms低延迟生成真人级语音
  • 短视频种草新时代:传声港新媒体平台五大平台赋能品牌增长新引擎 - 博客湾
  • 刚学完苍穹外卖,大模型就杀到家门口了?传统后端开发何去何从,我该转型Agent吗?
  • 通义千问1.5-1.8B-Chat-GPTQ-Int4:Win11右键菜单改回Win10风格——操作指南与原理讲解
  • 讲讲2026年专业的欧亚联盟EAC认证机构,荣仪达有啥优势 - mypinpai
  • [特殊字符] GLM-4V-9B系统集成:与现有CRM系统的对接实践
  • MicroPython嵌入式开发实战:GPIO/UART/I2C外设控制与低功耗设计
  • 分析AI搜索优化,南方网通讯灵AI性价比和效果究竟如何? - 工业品网
  • STM32 + RTOS移植成功率提升300%的关键动作(基于ARM Cortex-M3/M4/M7的8项寄存器级校验清单,含MPU配置checklist)
  • 谁懂!京东e卡到底怎么用啊!!!
  • Swift面试题2024:从基础到高阶的全面解析
  • AI+医疗工程化:模型上线到医院内网前,要补哪些系统能力?
  • 从GCN到GNN:图神经网络的核心演进与工业级应用剖析
  • nlp_structbert_sentence-similarity_chinese-large应对对抗性文本攻击的鲁棒性分析