近日,在体系结构的课程中,老师留了一个上机作业,为cache—主存—辅存三级调度模拟,要求如下:
实现三级存储体系的模拟调度程序
描述:CPU在cache访问数据块,若命中给出对应的cache实地址,若不命中在主存中查找,如果找到调入到cache中,若是cache已满使用LRU算法进行替换,采用写回法保持cache与主存的一致性。若是没有命中在辅存中查找,找到之后调入到主存,并更新cache。
实验要求:
(1)主存的容量可以更改
(2)分配给程序的页面数可以更改
(3)Cache采用组相连映像,cache大小、组数、组内块数均可以更改
(4)地址流可以采用输入的方式给出
(5)辅存部分可以不用实现
(6)要求有图形化的用户界面,上述参数均可以直接输入。
(7)显示执行程序时数据块以及页面的替换过程
(8)编程语言:选取自己熟悉的高级语言
百度了很久,没有找到Cache组相联映像的LRU替换算法,以下只是自己的一点想法与思路,若有不足,欢迎指正。
程序运行界面如下:
点击确定后:
第0组Cache块中各个块的使用情况为:
T1时刻 1
T2时刻 1
T3时刻 1 4
T4时刻 4 1
T5时刻 4 1
T6时刻 4 1
T7时刻 1 0
T8时刻 0 1
T9时刻 0 1
T10时刻 1 5
T11时刻 5 4
T12时刻 5 4
T13时刻 5 4
T14时刻 5 4
T15时刻 5 4
第1组Cache块中各个块的使用情况为:
T2时刻 2
T3时刻 2
T4时刻 2
T5时刻 2 3
T6时刻 3 7
T7时刻 3 7
T8时刻 3 7
T9时刻 7 2
T10时刻 7 2
T11时刻 7 2
T12时刻 2 6
T13时刻 2 6
T14时刻 6 7
T15时刻 7 2
下面是Cache类的代码,主要实现Cache的LRU替换算法,使用LinkedHashMap本身自带的特性实现的LRU算法
import java.util.LinkedHashMap; import java.util.Map; /** * 模拟Catch块中的LRU替换算法 * 此处使用java中LinkedHashMap,利用其自身特性,对removeEldestEntry()方法进行重写 * @author SUIXUE * */ public class Cache { public int cacheSize = 2; public Cache(){ } public Cache(int cacheSize){ this.cacheSize = cacheSize; } //此处的写法避免了新建类,也无需继承 Map<Integer, Integer> map = new LinkedHashMap<Integer, Integer>((int) Math.ceil(cacheSize / 0.75f) + 1, 0.75f, true) { /** * */ private static final long serialVersionUID = 1L; @Override protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) { return size() > cacheSize; } }; /** * 重写toString()方法 */ @Override public String toString() { StringBuilder sb = new StringBuilder(); for (Map.Entry<Integer, Integer> entry : this.map.entrySet()) { sb.append(String.format("%s ", entry.getKey())); } return sb.toString(); } /** * 此处的主要目的是在Cache中采用组相联映像时,在输出结果时同时显示当前时间 * @param addr * @return */ public String display(int[] addr){ StringBuilder sb = new StringBuilder(); int index =15-addr.length+1; for(int i = 0; i < addr.length;i++){ this.map.put(addr[i], 0); sb.append("T").append(index++).append("时刻 ").append(this.toString()+"\n"); } return sb.toString(); } }
下面是主界面的代码
1 import java.awt.BorderLayout; 2 import java.awt.GridLayout; 3 import java.awt.event.ActionEvent; 4 import java.awt.event.ActionListener; 5 import java.util.ArrayList; 6 7 import javax.swing.BorderFactory; 8 import javax.swing.JButton; 9 import javax.swing.JFrame; 10 import javax.swing.JLabel; 11 import javax.swing.JOptionPane; 12 import javax.swing.JPanel; 13 import javax.swing.JScrollPane; 14 import javax.swing.JTextArea; 15 import javax.swing.JTextField; 16 17 /** 18 * MainFrame类: 继承JFrame,同时实现接口ActionListener 19 * 20 * @author SUIXUE 21 * 22 */ 23 public class MainFrame extends JFrame implements ActionListener { 24 25 /** 26 * 27 */ 28 private static final long serialVersionUID = 1L; 29 30 private int memory = 0; 31 private int page = 0; 32 private int memoryQuNum = 0; 33 34 public int cacheSizeNum = 16; 35 public int cacheGroupNum = 2; 36 public int cacheBlockNumber = 2; 37 38 private int cacheNum = cacheGroupNum * cacheBlockNumber; 39 private int memoryBlockNum = 0; 40 public int[] addr = new int[] {1,2,4,1,3,7,0,1,2,5,4,6,4,7,2};//默认的地址流,可以在界面文本框中更改 41 42 public Cache[] cache;// 将cache的每组看做一个cache块 43 public ArrayList<Integer>[] cacheAddrs;// 每组都有对应的地址流 44 45 /** 46 * 初始化Cache分组(本方法是将每个分组看做一个单独独立的Cache块) 47 */ 48 public void initCache() { 49 for (int i = 0; i < cache.length; i++) { 50 cache[i] = new Cache(cacheBlockNumber); 51 } 52 } 53 54 /** 55 * 初始化地址流 56 * 将用户输入的地址流,通过分析,分别对应进入不同的Cache分组中 57 */ 58 public void initAddrs() { 59 for (int i = 0; i < cacheAddrs.length; i++) { 60 cacheAddrs[i] = new ArrayList<>(); 61 } 62 for (int i = 0; i < addr.length; i++) { 63 int temp = addr[i] % this.cacheNum;// 7%4 = 3 64 int groupNum = temp / this.cacheBlockNumber;// 3/2 = 1 65 66 ArrayList<Integer> arrayList = cacheAddrs[groupNum]; 67 arrayList.add(addr[i]);// 向各组添加地址流 68 69 //当当前地址不对其他组进行影响时,其他组中的Cache地址流其实等同于该时刻仍是它上一次的地址 70 if(i != 0){ 71 for(int j = 0; j < cacheGroupNum;j++){ 72 if(j != groupNum && cacheAddrs[j].size()>0){ 73 cacheAddrs[j].add(cacheAddrs[j].get(cacheAddrs[j].size()-1)); 74 } 75 } 76 } 77 } 78 } 79 80 private JPanel mainPanel; 81 82 /** 83 * 左侧面板 84 */ 85 private JPanel originalPanel; 86 87 // 主存大小 88 private JPanel memoryPanel; 89 private JLabel memorySizeLabel; 90 private JTextField memorySize; 91 92 // 页面数 93 private JPanel pagePanel; 94 private JLabel pageNumLabel; 95 private JTextField pageNum; 96 97 // cache 98 private JPanel cachePanel; 99 100 // cache大小 101 private JPanel cacheSizePanel; 102 private JLabel cacheSizeLabel; 103 private JTextField cacheSize; 104 105 // 组数 106 private JPanel cacheGroupSizePanel; 107 private JLabel cacheGroupSizeLabel; 108 private JTextField cacheGroupSize; 109 110 // 组内块数 111 private JPanel cacheBlockNumPanel; 112 private JLabel cacheBlockNumLabel; 113 private JTextField cacheBlockNum; 114 115 // 按钮 116 private JPanel button; 117 private JPanel addrPanel; 118 private JTextField addrText; 119 private JLabel addrLabel; 120 private JButton affirm; 121 122 /** 123 * 右侧面板 124 */ 125 private JScrollPane scrollPanel; 126 private JPanel resultPanel; 127 128 private JLabel display; 129 130 // 右侧转换结果显示框 131 private JTextArea resultArea; 132 133 /** 134 * 构造函数 135 */ 136 public MainFrame() { 137 initComponent(); 138 } 139 140 // 初始各组件 141 private void initComponent() { 142 143 // 设置布局 144 mainPanel = new JPanel(); 145 mainPanel.setLayout(new GridLayout(1, 2)); 146 147 // --------左侧面板--------------- 148 originalPanel = new JPanel(); 149 originalPanel.setLayout(new BorderLayout()); 150 151 // -------主存面板---------------- 152 memoryPanel = new JPanel(); 153 memorySizeLabel = new JLabel("主存容量"); 154 memorySize = new JTextField(10); 155 memorySize.setHorizontalAlignment(JTextField.RIGHT); 156 memorySize.setText("32"); 157 JLabel unitLabel = new JLabel("KB"); 158 memoryPanel.add(memorySizeLabel, BorderLayout.WEST); 159 memoryPanel.add(memorySize, BorderLayout.CENTER); 160 memoryPanel.add(unitLabel, BorderLayout.EAST); 161 162 // ---------页面大小面板---------------- 163 pagePanel = new JPanel(); 164 pageNumLabel = new JLabel("页面大小"); 165 pageNum = new JTextField(10); 166 pageNum.setHorizontalAlignment(JTextField.RIGHT); 167 pageNum.setText("3"); 168 JLabel unitLabel1 = new JLabel("页"); 169 pagePanel.add(pageNumLabel, BorderLayout.WEST); 170 pagePanel.add(pageNum, BorderLayout.CENTER); 171 pagePanel.add(unitLabel1, BorderLayout.EAST); 172 173 JPanel tempPanel = new JPanel(); 174 tempPanel.setLayout(new GridLayout(2, 1)); 175 tempPanel.add(memoryPanel); 176 tempPanel.add(pagePanel); 177 178 // -----------cache面板--------------- 179 cachePanel = new JPanel(); 180 cachePanel.setLayout(new GridLayout(3, 1)); 181 cachePanel.setBorder(BorderFactory.createTitledBorder("cache")); 182 183 cacheSizeLabel = new JLabel("cahce大小"); 184 cacheSize = new JTextField(10); 185 cacheSize.setHorizontalAlignment(JTextField.RIGHT); 186 cacheSize.setText("16"); 187 JLabel unitLabel2 = new JLabel("KB"); 188 cacheSizePanel = new JPanel(); 189 cacheSizePanel.add(cacheSizeLabel, BorderLayout.WEST); 190 cacheSizePanel.add(cacheSize, BorderLayout.CENTER); 191 cacheSizePanel.add(unitLabel2, BorderLayout.EAST); 192 193 cacheGroupSizeLabel = new JLabel("cahce组数"); 194 cacheGroupSize = new JTextField(10); 195 cacheGroupSize.setHorizontalAlignment(JTextField.RIGHT); 196 cacheGroupSize.setText("2"); 197 JLabel unitLabel3 = new JLabel("组"); 198 cacheGroupSizePanel = new JPanel(); 199 cacheGroupSizePanel.add(cacheGroupSizeLabel, BorderLayout.WEST); 200 cacheGroupSizePanel.add(cacheGroupSize, BorderLayout.CENTER); 201 cacheGroupSizePanel.add(unitLabel3, BorderLayout.EAST); 202 203 cacheBlockNumLabel = new JLabel("组内块数 "); 204 cacheBlockNum = new JTextField(10); 205 cacheBlockNum.setHorizontalAlignment(JTextField.RIGHT); 206 cacheBlockNum.setText("2"); 207 JLabel unitLabel4 = new JLabel("块"); 208 cacheBlockNumPanel = new JPanel(); 209 cacheBlockNumPanel.add(cacheBlockNumLabel, BorderLayout.WEST); 210 cacheBlockNumPanel.add(cacheBlockNum, BorderLayout.CENTER); 211 cacheBlockNumPanel.add(unitLabel4, BorderLayout.EAST); 212 213 cachePanel.add(cacheSizePanel); 214 cachePanel.add(cacheGroupSizePanel); 215 cachePanel.add(cacheBlockNumPanel); 216 217 button = new JPanel(); 218 button.setLayout(new GridLayout(2,1)); 219 220 addrLabel = new JLabel("块地址流 "); 221 addrText = new JTextField(20); 222 addrText.setHorizontalAlignment(JTextField.RIGHT); 223 addrText.setText("1 2 4 1 3 7 0 1 2 5 4 6 4 7 2"); 224 addrPanel = new JPanel(); 225 addrPanel.add(addrLabel,BorderLayout.WEST); 226 addrPanel.add(addrText,BorderLayout.CENTER); 227 228 JPanel affirmPanel = new JPanel(); 229 affirm = new JButton("确定"); 230 affirmPanel.add(affirm,BorderLayout.CENTER); 231 232 button.add(addrPanel); 233 button.add(affirmPanel); 234 affirm.addActionListener(this); 235 236 originalPanel.add(tempPanel, BorderLayout.NORTH); 237 originalPanel.add(cachePanel, BorderLayout.CENTER); 238 originalPanel.add(button, BorderLayout.SOUTH); 239 240 // --------右侧面板--------------- 241 resultPanel = new JPanel(); 242 resultPanel.setLayout(new BorderLayout()); 243 244 display = new JLabel("Cache中各个块的使用情况"); 245 246 resultArea = new JTextArea(); 247 resultArea.setEditable(false); 248 resultArea.setBorder(BorderFactory.createTitledBorder("RESULT")); 249 250 scrollPanel = new JScrollPane(resultArea); 251 252 resultPanel.add(display, BorderLayout.NORTH); 253 resultPanel.add(scrollPanel, BorderLayout.CENTER); 254 255 // ------------------------------------------------------- 256 mainPanel.add(originalPanel); 257 mainPanel.add(resultPanel); 258 mainPanel.setBorder(BorderFactory.createTitledBorder("三级调度模拟")); 259 260 this.add(mainPanel); 261 this.setTitle("小可爱的三级调度模拟"); 262 this.setSize(750, 350); 263 this.setDefaultCloseOperation(EXIT_ON_CLOSE); 264 this.setResizable(false); 265 this.setLocationRelativeTo(null); 266 this.setVisible(true); 267 268 } 269 270 @Override 271 public void actionPerformed(ActionEvent e) { 272 273 try { 274 this.memory = Integer.valueOf(memorySize.getText()); 275 this.page = Integer.valueOf(pageNum.getText()); 276 this.cacheSizeNum = Integer.valueOf(cacheSize.getText()); 277 this.cacheGroupNum = Integer.valueOf(cacheGroupSize.getText()); 278 this.cacheBlockNumber = Integer.valueOf(cacheBlockNum.getText()); 279 this.cacheNum = cacheGroupNum * cacheBlockNumber; 280 this.memoryQuNum = this.memory / this.cacheSizeNum; 281 this.memoryBlockNum = this.memoryQuNum * this.cacheNum; 282 283 cache = new Cache[cacheGroupNum]; 284 cacheAddrs = new ArrayList[cacheGroupNum]; 285 286 String addrString = this.addrText.getText(); 287 String[] addrItems = addrString.split(" "); 288 289 for(int i=0;i<addrItems.length;i++){ 290 this.addr[i]=Integer.parseInt(addrItems[i]); 291 } 292 293 this.initCache(); 294 this.initAddrs(); 295 296 StringBuilder sb = new StringBuilder(); 297 for (int i = 0; i < this.cache.length; i++) { 298 sb.append("第").append(i).append("组Cache块中各个块的使用情况为:\n"); 299 int[] addrTemp = new int[cacheAddrs[i].size()]; 300 for (int j = 0; j < this.cacheAddrs[i].size(); j++) { 301 addrTemp[j] = ((Integer) this.cacheAddrs[i].get(j)) 302 .intValue(); 303 } 304 sb.append(this.cache[i].display(addrTemp)).append("\n"); 305 } 306 resultArea.setText(sb.toString()); 307 } catch (Exception ex) { 308 JOptionPane.showMessageDialog(null, "所有输入均为正整数!\n地址流输入只能用一个空格隔开", "Sorry", 309 JOptionPane.INFORMATION_MESSAGE); 310 memorySize.setText("32"); 311 pageNum.setText("3"); 312 cacheSize.setText("16"); 313 cacheGroupSize.setText("2"); 314 cacheBlockNum.setText("2"); 315 addrText.setText("1 2 4 1 3 7 0 1 2 5 4 6 4 7 2"); 316 } 317 318 } 319 320 /** 321 * main 方法 322 * 323 * @param args 324 */ 325 public static void main(String[] args) { 326 new MainFrame(); 327 } 328 }
在解决Cache的组相联映像中,我主要采用的方法是将地址流随Cache分组而进行分组,只有特定的主存块才能进入到特定的Cache组中。针对每一组的Cache进行基本的Cache的LRU替换算法(Cache类中)