From d011adaf317727263ae6b82326b8763b33a16692 Mon Sep 17 00:00:00 2001 From: mbabaie Date: Mon, 2 Oct 2023 17:10:27 -0700 Subject: [PATCH 01/28] mem-DRAM-cache-with-stdlib mem: small fixes to compile gem5 after rebase Change-Id: I6fc7c0b161b945f338dc60856864235d838951cb mem: Add Octopi cache test Change-Id: Ie7464e72e9bbcded0a58d23e56a4460759a08834 mem: small fixes Change-Id: I1513e2a39e8823a57db377b8b3a03954bdb18ab3 mem: dcache with ports -- working version Change-Id: I7aaa0468977742ad27196dfd9f8b40aa66ea048e stdlib: fix cache line size error Change-Id: I98fb1403a8da9dc204c9f8ea5fb2d9d2f11c981c stdlib: temp change Change-Id: I04921d596811dfad5df32c1fbbd9532d5da6a59f configs: Use DiskImageWorkload and fix path Change-Id: I017f3d7b7fd18fbe39311599fbfffbf6d9260d5f Signed-off-by: Jason Lowe-Power stdlib: Sync changes Change-Id: Ie18db282c97fcc2cc2c1131de8b9cab09c0ece07 configs: HACK\! enable checkpointing in octotpi Signed-off-by: Jason Lowe-Power mem: cache warmup exit handling misc: Add checkpoint script Change-Id: I8e00452aed65fd49e80e6a7816cb6f6dad94455e mem: some minor updates Change-Id: I56108f2d8b02b777c0c35146d0e7aeee5f6cbf17 mem: just the GAPBS and NPB scripts are updated mem: latest version, modified for write age be ignored for cases not needed mem: updated stats mem: just updated some stats and params mem: more updates on stats stdlib: checkpoint script Change-Id: I8792cd616fad975973e5de96addc0d912bfb1c4e mem: syncing changes Change-Id: Ic48c244896f5560886a1fe0d0b9e84049a923e41 mem: update scripts Change-Id: I7142400634f362fab80c2553a82cb3d79a9ff1b8 misc: documentation Change-Id: I24f00455adc2ef6697cc0c70ed76a292f76df774 stdlib: add missing local change Change-Id: I3a4981e8412c466c130165b4f68343039ac0aaab misc: doc update Change-Id: Ia8b68057f5ff1a25b5b935f43f0158b16cad8fb4 mem-ruby: Fix warmup with backing store When warming up with Ruby backing store enabled, you cannot access both the backing store and the mem_interface with the packet. This change now accesses one or the other. The downside to this approach is that with this change you cannot restore a checkpoint or switch CPUs and disable backing store. Change-Id: I2d9f542a759d47fea571abd0d3141ce5996a81c3 Signed-off-by: Jason Lowe-Power arch-riscv: Copy miscregs on takeOverFrom Previously, the miscregs were not copied when switching CPUs. This caused failures after the switch because of an incorrect SATP. This change copies all of the miscregs from the old thread context to the new thread context. Change-Id: I4d1e9534b909e55a078fdfa579f4956d1c3a37db Signed-off-by: Jason Lowe-Power ckpt restore script for gapbs o3: Add looppoint stuff in this branch Update restore script small changes syncing changes small changes mem: removed old files mem: created TDRAM_32 mem: modified scripts traff gen mem: added plot data mem: added some test cases mem: latest plots mem:latest version mem: updated scripts and merged with latest version of TDRAM mem: updated old scripts mem: updated old scripts python: Allow SimObjectVector to match proxy There are proxies (like System.memories) which want to find *all* of the SimObjects that are of that type. However, the code currently cannot deal with SimObjectVectors. This change now checks for SimObjectVectors and updates the proxy list with each SimObject in the vector. It's been tested with System.memories and a VectorParam.SimpleMemory. This is needed to allow multiple discontinuous phys_mem parameters for Ruby's backing store. Change-Id: I937fbfc41a8a611b1b3a491caec41e8a9dcb0947 Signed-off-by: Jason Lowe-Power mem-ruby: Allow multiple backing store ranges This change enables Ruby to have multiple backing store ranges. The phys_mem parameter is now a list of simple memory objects, one for each discontiguous range. This is needed to have a second memory range above 4GiB for x86 simulation. Note that this is currently not used in Ruby.py, but it should be straightforward to set up for anyone's specific use case. Change-Id: I591a2b82a06bec69f583ba21f7267b6f535f48b1 Signed-off-by: Jason Lowe-Power configs: Updates to system to work with more memory Signed-off-by: Jason Lowe-Power mem: updated scripts mem: updated scripts mem: fixed the exitSimLoop error cpu-o3: Update looppoint analysis Improve the output for the recent PCs and update the types. Change-Id: Id86f7f0c2329cc9104912cf2655a0202541a450e Signed-off-by: Jason Lowe-Power misc: Add region info for workloads For use with the loop point tracker Change-Id: Id51cc7907cbc064dfd75cb26b887d1a0f5752428 Signed-off-by: Jason Lowe-Power just some updates on the scripts updated scripts, used for chkpts and restores configs: Add restore both script and update info Change-Id: Ib17f94cd59a8b152e5b8bf3d489e20236800a6e8 Signed-off-by: Jason Lowe-Power cpu-o3: Update looppoint probe to keep order Make sure that the recent PCs are presented in order instead of randomly. Change-Id: I9b2efae991507ff49dcc9525c5aea87c78e12e2e Signed-off-by: Jason Lowe-Power cpu-o3: Fix off by one in looppoint analysis We should insert PCs into the PC list with "1" access instead of 0 Change-Id: I9a773675a99e22d9b7603f00f28e4cc2dac766c2 Signed-off-by: Jason Lowe-Power Revert "cpu-o3: Fix off by one in looppoint analysis" This should be reverted since the loop point counting also has this off-by-one "error" This reverts commit 27ba5eb99db5aac81a9c701f68c08bf56394ae93. cpu: Update looppoint pc-count hash function TBH, I'm not sure this is needed or not Change-Id: I69f14c201c375fac76823b7bf8948aba0d426f9d Signed-off-by: Jason Lowe-Power configs: add workload info Change-Id: Ie21cc50223797e6c6b056a0b2aeacea209c80db1 Signed-off-by: Jason Lowe-Power configs: update info with 24 hour point Change-Id: Icec1036ce8cc839a6a459f0625d3e0cf33f1e580 Signed-off-by: Jason Lowe-Power fixed some status for Oracle configs: Update info with D/25 classes Change-Id: I1764a50e3d6da7c47ebd2c6d1eaa864fde0e2bef Signed-off-by: Jason Lowe-Power configs: Update restore both script Change-Id: Ieffb8924b8e2d9f6ddb19895733ab5a829fd7e20 Signed-off-by: Jason Lowe-Power revised version for combined dirmap and set-asso, only tested for dirmap first version tested with traff gen and tc in GAP mem: added serialize and unserialize for chkpt and rstr latest version of set-associative mem: added data plot for set-assoc mem: added data plot for set-assoc fixed unserialization new set-assoc data mem: latest version fixing tag issue in unserialization data plots data plots data plots updated plots misc: Google traces files misc: gtraces config data plots for comparing running for longer hours data plots for comparing running for longer hours small changes in scripts for chkpt and pc analysis mem: updated google scripts mem: updated google scripts updated scripts with new pc updated scripts with new pc updated scripts backup parent 41af1e744aaf2a2dd291d32ad1ec1b672b8822b9 author mbabaie 1689618387 -0700 committer mbabaie 1693268224 -0700 plots mem: updated plots first version, incomplete latest version all 3 cases Rd Hit/MissCl/MissDirty are implemented and tested on traffgen mem: latest version few minor changes first version tested bfs tc bt sp latest version tested on calss C and 22 data plots, 1st data plots, 1st data plots, 1st fixed the plot for breakdown of probing fixed the plot for breakdown of probing fixed the plot for breakdown of probing latest version with new stats runs bash file latest files in the directory just some comments removed tiny changes in the script tested archs --- Methodology.md | 31 + Octopi-cache/components/Octopi.py | 162 + Octopi-cache/components/__init__.py | 0 Octopi-cache/components/core_complex.py | 192 + Octopi-cache/components/octopi_network.py | 34 + .../components/ruby_network_components.py | 71 + ...v-2channel-1ccd-checkpoint-timing-gapbs.py | 162 + ...v-2channel-1ccd-checkpoint-timing-npb-c.py | 164 + .../riscv-2channel-1ccd-checkpoint-timing.py | 162 + .../riscv-2channel-1ccd-checkpoint.py | 148 + ...iscv-2channel-1ccd-restore-timing-gapbs.py | 160 + .../old-run-scripts/riscv-2channel-1ccd.py | 101 + Octopi-cache/restore-npb-gapbs-looppoint.py | 259 ++ Octopi-cache/riscv-hpc.py | 87 + build_opts/RISCV_MESI_Three_Level | 2 + cold-miss-check-plots.ipynb | 466 +++ configs-drtrace/drtrace.py | 61 + configs-drtrace/drtrace_new.py | 88 + configs-drtrace/system/MESI_Two_Level.py | 312 ++ configs-drtrace/system/MI_example_caches.py | 275 ++ configs-drtrace/system/MOESI_CMP_directory.py | 350 ++ configs-drtrace/system/__init__.py | 30 + configs-drtrace/system/ruby_system.py | 124 + configs-npb-gapbs/gapbs_checkpoint.py | 199 + configs-npb-gapbs/gapbs_restore.py | 179 + configs-npb-gapbs/info.py | 325 ++ configs-npb-gapbs/npb_checkpoint.py | 255 ++ configs-npb-gapbs/npb_restore.py | 222 ++ configs-npb-gapbs/restore_both.py | 331 ++ configs-npb-gapbs/system/MESI_Two_Level.py | 332 ++ configs-npb-gapbs/system/MI_example_caches.py | 275 ++ .../system/MOESI_CMP_directory.py | 350 ++ configs-npb-gapbs/system/__init__.py | 32 + configs-npb-gapbs/system/caches.py | 173 + configs-npb-gapbs/system/fs_tools.py | 39 + configs-npb-gapbs/system/ruby_system.py | 294 ++ configs-npb-gapbs/system/ruby_system_new.py | 363 ++ configs-npb-gapbs/system/system.py | 414 ++ configs-npb-gapbs/system/system_back.py | 397 ++ .../riscv-hello-save-checkpoint.py | 36 +- .../gem5_library/x86-gapbs-benchmarks.py | 4 +- configs/ruby/Ruby.py | 12 +- data-plots.ipynb | 2874 ++++++++++++++ data_plot_compare_hours.ipynb | 772 ++++ defMemCtrlr.py | 77 + dr_trace_player.py | 78 + dr_trace_player_core.py | 72 + drtrace-stdlib.py | 109 + gapbs_checkpoint.sh | 22 + gapbs_run.sh | 22 + googleTracesRun.sh | 4 + link.ipynb | 1604 ++++++++ missRatio_swe.py | 136 + npb_checkpoint.sh | 22 + npb_checkpoint_c_class.sh | 22 + npb_run.sh | 22 + npb_run_c.sh | 22 + plots_1GBdramCache/data-plots.ipynb | 1331 +++++++ realAppRun.sh | 32 + set-associative-data-plots.ipynb | 513 +++ src/cpu/kvm/vm.cc | 7 +- src/cpu/o3/probe/O3LooppointAnalysis.py | 28 + src/cpu/o3/probe/SConscript | 5 + src/cpu/o3/probe/o3looppoint_analysis.cc | 114 + src/cpu/o3/probe/o3looppoint_analysis.hh | 126 + src/cpu/probes/pc_count_pair.hh | 4 +- .../testers/dr_trace_player/DRTracePlayer.py | 106 + src/cpu/testers/dr_trace_player/SConscript | 35 + .../testers/dr_trace_player/trace_player.cc | 380 ++ .../testers/dr_trace_player/trace_player.hh | 204 + .../testers/dr_trace_player/trace_reader.cc | 249 ++ .../testers/dr_trace_player/trace_reader.hh | 260 ++ src/mem/DCacheCtrl.py | 60 + src/mem/DRAMInterface.py | 197 +- src/mem/MemCtrl.py | 11 +- src/mem/PolicyManager.py | 46 + src/mem/SConscript | 8 + src/mem/abstract_mem.cc | 11 +- src/mem/abstract_mem.hh | 27 + .../replacement_policies/replaceable_entry.hh | 18 + src/mem/coherent_xbar.cc | 15 +- src/mem/dram_cache_ctrl.cc | 1917 ++++++++++ src/mem/dram_cache_ctrl.hh | 465 +++ src/mem/dram_interface.cc | 676 +++- src/mem/dram_interface.hh | 90 +- src/mem/hbm_ctrl.cc | 4 +- src/mem/mem_ctrl.cc | 510 ++- src/mem/mem_ctrl.hh | 82 +- src/mem/mem_interface.cc | 2 +- src/mem/mem_interface.hh | 23 +- src/mem/packet.hh | 11 +- src/mem/packet_queue.cc | 8 +- src/mem/physical.cc | 27 +- src/mem/policy_manager.cc | 3358 +++++++++++++++++ src/mem/policy_manager.hh | 544 +++ src/mem/ruby/structures/CacheMemory.cc | 16 +- src/mem/ruby/structures/CacheMemory.hh | 2 +- src/mem/ruby/system/RubyPort.cc | 14 +- src/mem/ruby/system/RubySystem.cc | 10 +- src/mem/ruby/system/RubySystem.hh | 11 +- src/mem/ruby/system/RubySystem.py | 2 +- src/mem/xbar.cc | 8 +- src/python/SConscript | 1 + src/python/gem5/components/memory/__init__.py | 3 + src/python/gem5/components/memory/dcache.py | 190 + .../components/memory/dram_interfaces/hbm.py | 88 + .../gem5/components/memory/multi_channel.py | 1 - .../processors/simple_switchable_processor.py | 36 + src/python/gem5/simulate/exit_event.py | 7 + src/python/gem5/simulate/simulator.py | 1 + src/python/m5/SimObject.py | 15 +- traffGen_def.py | 131 + traffGen_mem.py | 88 + 113 files changed, 25433 insertions(+), 226 deletions(-) create mode 100644 Methodology.md create mode 100644 Octopi-cache/components/Octopi.py create mode 100644 Octopi-cache/components/__init__.py create mode 100644 Octopi-cache/components/core_complex.py create mode 100644 Octopi-cache/components/octopi_network.py create mode 100644 Octopi-cache/components/ruby_network_components.py create mode 100644 Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing-gapbs.py create mode 100644 Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing-npb-c.py create mode 100644 Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing.py create mode 100644 Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint.py create mode 100644 Octopi-cache/old-run-scripts/riscv-2channel-1ccd-restore-timing-gapbs.py create mode 100644 Octopi-cache/old-run-scripts/riscv-2channel-1ccd.py create mode 100644 Octopi-cache/restore-npb-gapbs-looppoint.py create mode 100644 Octopi-cache/riscv-hpc.py create mode 100644 build_opts/RISCV_MESI_Three_Level create mode 100644 cold-miss-check-plots.ipynb create mode 100644 configs-drtrace/drtrace.py create mode 100644 configs-drtrace/drtrace_new.py create mode 100755 configs-drtrace/system/MESI_Two_Level.py create mode 100755 configs-drtrace/system/MI_example_caches.py create mode 100755 configs-drtrace/system/MOESI_CMP_directory.py create mode 100755 configs-drtrace/system/__init__.py create mode 100755 configs-drtrace/system/ruby_system.py create mode 100755 configs-npb-gapbs/gapbs_checkpoint.py create mode 100755 configs-npb-gapbs/gapbs_restore.py create mode 100644 configs-npb-gapbs/info.py create mode 100755 configs-npb-gapbs/npb_checkpoint.py create mode 100755 configs-npb-gapbs/npb_restore.py create mode 100755 configs-npb-gapbs/restore_both.py create mode 100755 configs-npb-gapbs/system/MESI_Two_Level.py create mode 100755 configs-npb-gapbs/system/MI_example_caches.py create mode 100755 configs-npb-gapbs/system/MOESI_CMP_directory.py create mode 100755 configs-npb-gapbs/system/__init__.py create mode 100755 configs-npb-gapbs/system/caches.py create mode 100755 configs-npb-gapbs/system/fs_tools.py create mode 100755 configs-npb-gapbs/system/ruby_system.py create mode 100644 configs-npb-gapbs/system/ruby_system_new.py create mode 100755 configs-npb-gapbs/system/system.py create mode 100755 configs-npb-gapbs/system/system_back.py create mode 100644 data-plots.ipynb create mode 100644 data_plot_compare_hours.ipynb create mode 100644 defMemCtrlr.py create mode 100644 dr_trace_player.py create mode 100644 dr_trace_player_core.py create mode 100644 drtrace-stdlib.py create mode 100755 gapbs_checkpoint.sh create mode 100755 gapbs_run.sh create mode 100755 googleTracesRun.sh create mode 100644 link.ipynb create mode 100644 missRatio_swe.py create mode 100755 npb_checkpoint.sh create mode 100755 npb_checkpoint_c_class.sh create mode 100755 npb_run.sh create mode 100755 npb_run_c.sh create mode 100644 plots_1GBdramCache/data-plots.ipynb create mode 100755 realAppRun.sh create mode 100644 set-associative-data-plots.ipynb create mode 100644 src/cpu/o3/probe/O3LooppointAnalysis.py create mode 100644 src/cpu/o3/probe/o3looppoint_analysis.cc create mode 100644 src/cpu/o3/probe/o3looppoint_analysis.hh create mode 100644 src/cpu/testers/dr_trace_player/DRTracePlayer.py create mode 100644 src/cpu/testers/dr_trace_player/SConscript create mode 100644 src/cpu/testers/dr_trace_player/trace_player.cc create mode 100644 src/cpu/testers/dr_trace_player/trace_player.hh create mode 100644 src/cpu/testers/dr_trace_player/trace_reader.cc create mode 100644 src/cpu/testers/dr_trace_player/trace_reader.hh create mode 100644 src/mem/DCacheCtrl.py create mode 100644 src/mem/PolicyManager.py create mode 100644 src/mem/dram_cache_ctrl.cc create mode 100644 src/mem/dram_cache_ctrl.hh create mode 100644 src/mem/policy_manager.cc create mode 100644 src/mem/policy_manager.hh create mode 100644 src/python/gem5/components/memory/dcache.py create mode 100644 traffGen_def.py create mode 100644 traffGen_mem.py diff --git a/Methodology.md b/Methodology.md new file mode 100644 index 0000000000..740fddb1fc --- /dev/null +++ b/Methodology.md @@ -0,0 +1,31 @@ +# Documentation on the methodology work for DRAM cache experiments + +This is not a very detailed or formal document, but tries to at least point to +the relevant links or paths and important notes. + +- DRAM cache component is part of the stdlib in this repo ("src/python/gem5/components/memory/dcache.py"). +- Octopi-cache is a three level MESI cache hiearchy + + +## gem5 scripts used to take checkpoints + +- **NPB D Class:** Octopi-cache/riscv-2channel-1ccd-checkpoint-timing.py + +- **NPB C Class:** ctopi-cache/riscv-2channel-1ccd-checkpoint-timing.py + +- **GAPBS (2^25 vertices):** Octopi-cache/riscv-2channel-1ccd-checkpoint-timing-gapbs.py + + +## Bash scripts used (will show the directory where the checkpoints and results are) + +- **NPB:** `npb_checkpoint.sh` and `npb_checkpoint_c_class.sh` +- **GAPBS:** `gapbs_checkpoint.sh` + +The gem5 directory I have been using is here: `/home/aakahlow/Dcache_Src/dramCacheController`. +D Class and GAPBS checkpoints will go there. The C class checkpoints will be stored in /projects (exact path in the npb_checkpoint_c_class.sh script). + +## Looppoint stuff + +- The branch with O3 loop point analysis stuff: https://github.com/darchr/gem5/commits/looppointAnalysis-Ayaz +- example.py script in the above branch is a modified version of Zhantong's example script to use looppoint analysis probe and print most recent PC + count. + diff --git a/Octopi-cache/components/Octopi.py b/Octopi-cache/components/Octopi.py new file mode 100644 index 0000000000..91d72e69e4 --- /dev/null +++ b/Octopi-cache/components/Octopi.py @@ -0,0 +1,162 @@ +from gem5.components.cachehierarchies.ruby.abstract_ruby_cache_hierarchy import AbstractRubyCacheHierarchy +from gem5.components.cachehierarchies.abstract_three_level_cache_hierarchy import ( + AbstractThreeLevelCacheHierarchy, +) +from gem5.coherence_protocol import CoherenceProtocol +from gem5.isas import ISA +from gem5.components.boards.abstract_board import AbstractBoard +from gem5.utils.requires import requires + +from gem5.components.cachehierarchies.ruby.caches.mesi_three_level.directory import Directory +from gem5.components.cachehierarchies.ruby.caches.mesi_three_level.dma_controller import DMAController + +from m5.objects import RubySystem, DMASequencer, RubyPortProxy, SimpleMemory, AddrRange + +from .core_complex import CoreComplex +from .octopi_network import OctopiNetwork +from .ruby_network_components import RubyNetworkComponent, RubyRouter, RubyExtLink, RubyIntLink + +# CoreComplex sub-systems own the L1, L2, L3 controllers +# OctopiCache owns the directory controllers +# RubySystem owns the DMA Controllers +class OctopiCache(AbstractRubyCacheHierarchy, AbstractThreeLevelCacheHierarchy): + def __init__( + self, + l1i_size: str, + l1i_assoc: int, + l1d_size: str, + l1d_assoc: int, + l2_size: str, + l2_assoc: int, + l3_size: str, + l3_assoc: int, + num_core_complexes: int, + is_fullsystem: bool + ): + AbstractRubyCacheHierarchy.__init__(self=self) + AbstractThreeLevelCacheHierarchy.__init__( + self=self, + l1i_size=l1i_size, + l1i_assoc=l1i_assoc, + l1d_size=l1d_size, + l1d_assoc=l1d_assoc, + l2_size=l2_size, + l2_assoc=l2_assoc, + l3_size=l3_size, + l3_assoc=l3_assoc, + ) + + self._directory_controllers = [] + self._dma_controllers = [] + self._io_controllers = [] + self._core_complexes = [] + self._num_core_complexes = num_core_complexes + self._is_fullsystem = is_fullsystem + + def incorporate_cache(self, board: AbstractBoard) -> None: + + requires( + coherence_protocol_required=CoherenceProtocol.MESI_THREE_LEVEL + ) + + cache_line_size = board.get_cache_line_size() + + self.ruby_system = RubySystem() + # MESI_Three_Level needs 3 virtual networks + self.ruby_system.number_of_virtual_networks = 3 + self.ruby_system.network = OctopiNetwork(self.ruby_system) + self.ruby_system.access_backing_store = True + + # Get the first range and the range part. + addr_range_0 = board.get_mem_ports()[0][0] + self.ruby_system.phys_mem = SimpleMemory( + range=AddrRange(start=addr_range_0.start, + end=addr_range_0.end), + in_addr_map=False) + + # Setting up the core complex + all_cores = board.get_processor().get_cores() + num_cores_per_core_complex = len(all_cores) // self._num_core_complexes + + self.core_complexes = [CoreComplex( + board = board, + cores = all_cores[core_complex_idx*num_cores_per_core_complex:(core_complex_idx + 1) * num_cores_per_core_complex], + ruby_system = self.ruby_system, + l1i_size = self._l1i_size, + l1i_assoc = self._l1i_assoc, + l1d_size = self._l1d_size, + l1d_assoc = self._l1d_assoc, + l2_size = self._l2_size, + l2_assoc = self._l2_assoc, + l3_size = self._l3_size, + l3_assoc = self._l3_assoc, + ) for core_complex_idx in range(self._num_core_complexes)] + + self.ruby_system.network.incorporate_ccds(self.core_complexes) + + self._create_directory_controllers(board) + self._create_dma_controllers(board, self.ruby_system) + + self.ruby_system.num_of_sequencers = len(all_cores) + len(self._dma_controllers) + len(self._io_controllers) + # SimpleNetwork requires .int_links and .routers to exist + # if we want to call SimpleNetwork.setup_buffers() + self.ruby_system.network.int_links = self.ruby_system.network._int_links + self.ruby_system.network.ext_links = self.ruby_system.network._ext_links + self.ruby_system.network.routers = self.ruby_system.network._routers + self.ruby_system.network.setup_buffers() + + # Set up a proxy port for the system_port. Used for load binaries and + # other functional-only things. + self.ruby_system.sys_port_proxy = RubyPortProxy() + board.connect_system_port(self.ruby_system.sys_port_proxy.in_ports) + + def _create_directory_controllers(self, board): + # Adding controllers + self.directory_controllers = [Directory( + self.ruby_system.network, board.get_cache_line_size(), addr_range, mem_port + ) for addr_range, mem_port in board.get_mem_ports() + ] + for ctrl in self.directory_controllers: + ctrl.ruby_system = self.ruby_system + # Adding controller routers + self.directory_controller_routers = [RubyRouter(self.ruby_system.network) for _ in range(len(self.directory_controllers))] + for router in self.directory_controller_routers: + self.ruby_system.network._add_router(router) + # Adding an external link for each controller and its router + self.directory_controller_ext_links = [RubyExtLink(ext_node=dir_ctrl, int_node=dir_router) for dir_ctrl, dir_router in zip(self.directory_controllers, self.directory_controller_routers)] + for ext_link in self.directory_controller_ext_links: + self.ruby_system.network._add_ext_link(ext_link) + _directory_controller_int_links = [] + for router in self.directory_controller_routers: + int_link_1, int_link_2 = RubyIntLink.create_bidirectional_links(router, self.ruby_system.network.cross_ccd_router) + _directory_controller_int_links.extend([int_link_1, int_link_2]) + self.ruby_system.network._add_int_link(int_link_1) + self.ruby_system.network._add_int_link(int_link_2) + self.directory_controller_int_links = _directory_controller_int_links + + def _create_dma_controllers(self, board, ruby_system): + # IOController for full system simulation + if self._is_fullsystem: + self.io_sequencer = DMASequencer(version=0, ruby_system=self.ruby_system) + self.io_sequencer.in_ports = board.get_mem_side_coherent_io_port() + self.ruby_system.io_controller = DMAController( + dma_sequencer=self.io_sequencer, + ruby_system=self.ruby_system + ) + self._io_controllers.append(self.ruby_system.io_controller) + self.io_controller_router = RubyRouter(self.ruby_system.network) + self.ruby_system.network._add_router(self.io_controller_router) + self.io_controller_ext_link = RubyExtLink(ext_node=self._io_controllers[0], int_node=self.io_controller_router) + self.ruby_system.network._add_ext_link(self.io_controller_ext_link) + self.io_controller_int_links = RubyIntLink.create_bidirectional_links(self.io_controller_router, self.ruby_system.network.cross_ccd_router) + self.ruby_system.network._add_int_link(self.io_controller_int_links[0]) + self.ruby_system.network._add_int_link(self.io_controller_int_links[1]) + + self._dma_controllers = [] + if board.has_dma_ports(): + for i, port in enumerate(dma_ports): + ctrl = DMAController(self.ruby_system.network, cache_line_size) + ctrl.dma_sequencer = DMASequencer(version=i+1, in_ports=port) + self._dma_controllers.append(ctrl) + ctrl.ruby_system = self.ruby_system + ruby_system.dma_controllers = self._dma_controllers diff --git a/Octopi-cache/components/__init__.py b/Octopi-cache/components/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Octopi-cache/components/core_complex.py b/Octopi-cache/components/core_complex.py new file mode 100644 index 0000000000..877e219d1e --- /dev/null +++ b/Octopi-cache/components/core_complex.py @@ -0,0 +1,192 @@ +from typing import List, Tuple + +from gem5.isas import ISA +from gem5.components.boards.abstract_board import AbstractBoard +from gem5.components.processors.abstract_core import AbstractCore +from gem5.components.cachehierarchies.abstract_three_level_cache_hierarchy import ( + AbstractThreeLevelCacheHierarchy, +) +from gem5.components.cachehierarchies.ruby.caches.mesi_three_level.l1_cache import L1Cache +from gem5.components.cachehierarchies.ruby.caches.mesi_three_level.l2_cache import L2Cache +from gem5.components.cachehierarchies.ruby.caches.mesi_three_level.l3_cache import L3Cache +from gem5.components.cachehierarchies.ruby.caches.mesi_three_level.directory import Directory + +from m5.objects import SubSystem, L2Cache_Controller, AddrRange, RubySequencer, Switch, SimpleIntLink, SimpleExtLink, SubSystem, SimObject + +from .ruby_network_components import RubyRouter, RubyExtLink, RubyIntLink, RubyNetworkComponent + +class CoreComplex(SubSystem, RubyNetworkComponent): + _core_id = 0 + _core_complex_id = 0 + + @classmethod + def _get_core_id(cls): + cls._core_id += 1 + return cls._core_id - 1 + + @classmethod + def _get_core_complex_id(cls): + cls._core_complex_id += 1 + return cls._core_complex_id - 1 + + def __init__( + self, + board: AbstractBoard, + cores: List[AbstractCore], + ruby_system, + l1i_size: str, + l1i_assoc: int, + l1d_size: str, + l1d_assoc: int, + l2_size: str, + l2_assoc: int, + l3_size: str, + l3_assoc: int, + ): + SubSystem.__init__(self=self) + RubyNetworkComponent.__init__(self=self) + + self._l1i_size = l1i_size + self._l1i_assoc = l1i_assoc + self._l1d_size = l1d_size + self._l1d_assoc = l1d_assoc + self._l2_size = l2_size + self._l2_assoc = l2_assoc + self._l3_size = l3_size + self._l3_assoc = l3_assoc + + self._board = board + self._cores = cores + self._ruby_system = ruby_system + self._cache_line_size = 64 + + self._directory_controllers = [] + + self._core_complex_id = self._get_core_complex_id() + self.main_router = RubyRouter(self._ruby_system) # this will be connect to component outside the core complex + self._add_router(self.main_router) + self._create_core_complex() + + def get_main_router(self): + return self.main_router + + def _create_core_complex(self): + # Create L1 caches, L2 cache, and corresponding controllers per core + self.core_clusters = [self._create_core_cluster(core) for core in self._cores] + # Create L3 cache and its corresponding controller + self._create_shared_cache() + # Setting up one router and one external link per controller + self._create_external_links() + # Setting up L1/L2 links, L2/main links, L3/main link + self._create_internal_links() + + def _create_core_cluster(self, core: AbstractCore): + cluster = SubSystem() + core_id = self._get_core_id() + + cluster.l1_cache = L1Cache( + l1i_size = self._l1i_size, + l1i_assoc = self._l1i_assoc, + l1d_size = self._l1d_size, + l1d_assoc = self._l1d_assoc, + network = self._ruby_system.network, + core = core, + cache_line_size = self._cache_line_size, + target_isa = self._board.processor.get_isa(), + clk_domain = self._board.get_clock_domain(), + ) + cluster.l1_cache.sequencer = RubySequencer( + version = core_id, + dcache = cluster.l1_cache.Dcache, + clk_domain = cluster.l1_cache.clk_domain + ) + + if self._board.has_io_bus(): + cluster.l1_cache.sequencer.connectIOPorts(self._board.get_io_bus()) + cluster.l1_cache.ruby_system = self._ruby_system + core.connect_icache(cluster.l1_cache.sequencer.in_ports) + core.connect_dcache(cluster.l1_cache.sequencer.in_ports) + core.connect_walker_ports( + cluster.l1_cache.sequencer.in_ports, cluster.l1_cache.sequencer.in_ports + ) + if self._board.get_processor().get_isa() == ISA.X86: + core.connect_interrupt( + cluster.l1_cache.sequencer.interrupt_out_port, + cluster.l1_cache.sequencer.in_ports + ) + else: + core.connect_interrupt() + + cluster.l2_cache = L2Cache( + l2_size=self._l2_size, + l2_assoc=self._l2_assoc, + network=self._ruby_system.network, + core=core, + num_l3Caches=1, # each core complex has 1 slice of L3 Cache + cache_line_size=self._cache_line_size, + cluster_id=self._core_complex_id, + target_isa=self._board.processor.get_isa(), + clk_domain=self._board.get_clock_domain(), + ) + cluster.l2_cache.ruby_system = self._ruby_system + # L0Cache in the ruby backend is l1 cache in stdlib + # L1Cache in the ruby backend is l2 cache in stdlib + cluster.l2_cache.bufferFromL0 = cluster.l1_cache.bufferToL1 + cluster.l2_cache.bufferToL0 = cluster.l1_cache.bufferFromL1 + + return cluster + + def _create_shared_cache(self): + self.l3_cache = L3Cache( + l3_size=self._l3_size, + l3_assoc=self._l3_assoc, + network=self._ruby_system.network, + num_l3Caches=1, + cache_line_size=self._cache_line_size, + cluster_id=self._core_complex_id, + ) + self.l3_cache.ruby_system = self._ruby_system + + # This is where all routers and links are created + def _create_external_links(self): + # create a router per cache controller + # - there is one L3 per ccd + self.l3_router = RubyRouter(self._ruby_system) + self._add_router(self.l3_router) + # - there is one L1 and one L2 per cluster + for cluster in self.core_clusters: + cluster.l1_router = RubyRouter(self._ruby_system) + self._add_router(cluster.l1_router) + cluster.l2_router = RubyRouter(self._ruby_system) + self._add_router(cluster.l2_router) + + # create an ext link from a controller to a router + self.l3_router_link = RubyExtLink(ext_node=self.l3_cache, int_node=self.l3_router, bandwidth_factor=64) + self._add_ext_link(self.l3_router_link) + for cluster in self.core_clusters: + cluster.l1_router_link = RubyExtLink(ext_node=cluster.l1_cache, int_node=cluster.l1_router) + self._add_ext_link(cluster.l1_router_link) + cluster.l2_router_link = RubyExtLink(ext_node=cluster.l2_cache, int_node=cluster.l2_router) + self._add_ext_link(cluster.l2_router_link) + + def _create_internal_links(self): + # create L1/L2 links + for cluster in self.core_clusters: + l1_to_l2, l2_to_l1 = RubyIntLink.create_bidirectional_links(cluster.l1_router, cluster.l2_router) + cluster.l1_to_l2_link = l1_to_l2 + cluster.l2_to_l1_link = l2_to_l1 + self._add_int_link(l1_to_l2) + self._add_int_link(l2_to_l1) + # create L2/main_router links + for cluster in self.core_clusters: + l2_to_main, main_to_l2 = RubyIntLink.create_bidirectional_links(cluster.l2_router, self.main_router) + cluster.l2_to_main_link = l2_to_main + cluster.main_to_l2_link = main_to_l2 + self._add_int_link(l2_to_main) + self._add_int_link(main_to_l2) + # create L3/main_router link + l3_to_main, main_to_l3 = RubyIntLink.create_bidirectional_links(self.l3_router, self.main_router, bandwidth_factor=64) + self.l3_to_main_link = l3_to_main + self.main_to_l3_link = main_to_l3 + self._add_int_link(l3_to_main) + self._add_int_link(main_to_l3) diff --git a/Octopi-cache/components/octopi_network.py b/Octopi-cache/components/octopi_network.py new file mode 100644 index 0000000000..5b1ab1b9bc --- /dev/null +++ b/Octopi-cache/components/octopi_network.py @@ -0,0 +1,34 @@ +from .ruby_network_components import RubyNetworkComponent, RubyExtLink, RubyIntLink, RubyRouter + +from m5.objects import SimpleNetwork + +# . The Network owns all routers, all int links and all ext links that are not in CCD's. +# . The CCD subsystems are not of type RubyNetwork, so we need to copy the references of +# routers and links to OctopiNetwork._routers, ._int_links, and ._ext_links; which will +# be, in turns, copied to RubyNetwork.routers, .int_links, and .ext_links respectively. +# +# Terms: "connect" -> create int links +# "incorporate" -> copy references of routers and links, create routers/links if necessary +class OctopiNetwork(SimpleNetwork, RubyNetworkComponent): + def __init__(self, ruby_system): + SimpleNetwork.__init__(self=self) + RubyNetworkComponent.__init__(self=self) + self.netifs = [] + self.ruby_system = ruby_system + self.number_of_virtual_networks = ruby_system.number_of_virtual_networks + + self.cross_ccd_router = RubyRouter(self) + self._add_router(self.cross_ccd_router) + + def connect_ccd_routers_to_cross_ccd_router(self, ccds): + for ccd in ccds: + int_link_1, int_link_2 = RubyIntLink.create_bidirectional_links(self.cross_ccd_router, ccd.get_main_router(), bandwidth_factor=64) + ccd.to_cross_ccd_router_link = int_link_1 + ccd.from_cross_ccd_router_link = int_link_2 + self._add_int_link(int_link_1) + self._add_int_link(int_link_2) + + def incorporate_ccds(self, ccds): + for ccd in ccds: + self.incorporate_ruby_subsystem(ccd) + self.connect_ccd_routers_to_cross_ccd_router(ccds) diff --git a/Octopi-cache/components/ruby_network_components.py b/Octopi-cache/components/ruby_network_components.py new file mode 100644 index 0000000000..6e9b2d4abc --- /dev/null +++ b/Octopi-cache/components/ruby_network_components.py @@ -0,0 +1,71 @@ +from m5.objects import Switch, SimpleIntLink, SimpleExtLink + +class RubyNetworkComponent(): + def __init__(self): + super().__init__() + self._routers = [] + self._ext_links = [] + self._int_links = [] + def _add_router(self, router): + self._routers.append(router) + def _add_ext_link(self, link): + self._ext_links.append(link) + def _add_int_link(self, link): + self._int_links.append(link) + def get_routers(self): + return self._routers + def get_ext_links(self): + return self._ext_links + def get_int_links(self): + return self._int_links + def incorporate_ruby_subsystem(self, other_ruby_subsystem): + self._routers.extend(other_ruby_subsystem.get_routers()) + self._ext_links.extend(other_ruby_subsystem.get_ext_links()) + self._int_links.extend(other_ruby_subsystem.get_int_links()) + +class RubyRouter(Switch): + _router_id = 0 + + @classmethod + def _get_router_id(cls): + cls._router_id += 1 + return cls._router_id - 1 + + def __init__(self, network): + super().__init__() + self.router_id = self._get_router_id() + self.virt_nets = network.number_of_virtual_networks + +class RubyExtLink(SimpleExtLink): + _link_id = 0 + + @classmethod + def _get_link_id(cls): + cls._link_id += 1 + return cls._link_id - 1 + + def __init__(self, ext_node, int_node, bandwidth_factor=16): + super().__init__() + self.link_id = self._get_link_id() + self.ext_node = ext_node + self.int_node = int_node + self.bandwidth_factor = bandwidth_factor + +class RubyIntLink(SimpleIntLink): + _link_id = 0 + + @classmethod + def _get_link_id(cls): + cls._link_id += 1 + return cls._link_id - 1 + + @classmethod + def create_bidirectional_links(cls, node_1, node_2, bandwidth_factor=16): + return [RubyIntLink(node_1, node_2, bandwidth_factor), RubyIntLink(node_2, node_1, bandwidth_factor)] + + def __init__(self, src_node, dst_node, bandwidth_factor=16): + super().__init__() + self.link_id = self._get_link_id() + self.src_node = src_node + self.dst_node = dst_node + self.bandwidth_factor = bandwidth_factor diff --git a/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing-gapbs.py b/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing-gapbs.py new file mode 100644 index 0000000000..f944b288db --- /dev/null +++ b/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing-gapbs.py @@ -0,0 +1,162 @@ +from gem5.components.boards.riscv_board import RiscvBoard +from gem5.components.memory.memory import ChanneledMemory +from gem5.components.processors.simple_processor import SimpleProcessor +from gem5.components.processors.cpu_types import CPUTypes +from gem5.isas import ISA +from gem5.utils.requires import requires +from gem5.utils.override import overrides +from gem5.resources.resource import Resource, DiskImageResource +from gem5.simulate.simulator import Simulator +from gem5.components.processors.simple_switchable_processor import ( + SimpleSwitchableProcessor, +) +from gem5.components.memory import CascadeLakeCache, OracleCache, RamCache +from gem5.simulate.simulator import ExitEvent +import m5 +from components.Octopi import OctopiCache + +# Sample command to use this script +# build/RISCV/gem5.opt --outdir=bfs.25 riscv-2channel-1ccd-checkpoint.py +# --benchmark bfs --size 25 --ckpt_path checkpoints-gapbs/bfs.25.ckpt/ +# + +requires(isa_required=ISA.RISCV) + +import argparse +parser = argparse.ArgumentParser() +parser.add_argument("--benchmark", type=str) +parser.add_argument("--size", type=str) +parser.add_argument("--ckpt_path", type=str) + +args = parser.parse_args() + +num_ccds = 1 +num_cores = 8 +command = f"/home/ubuntu/gapbs/{args.benchmark} -g {args.size};" + +cache_hierarchy = OctopiCache( + l1i_size = "32KiB", + l1i_assoc = 8, + l1d_size = "32KiB", + l1d_assoc = 8, + l2_size = "512KiB", + l2_assoc = 8, + l3_size = "32MiB", + l3_assoc = 16, + num_core_complexes = 1, + is_fullsystem = True, +) +memory = RamCache() + +processor = SwitchableProcessor( + starting_core_type=CPUTypes.TIMING, + switch_core_type=CPUTypes.TIMING, # TODO + isa=ISA.RISCV, + num_cores=num_cores +) + +class HighPerformanceRiscvBoard(RiscvBoard): + @overrides(RiscvBoard) + def get_default_kernel_args(self): + return [ + "earlyprintk=ttyS0", + "console=ttyS0", + "lpj=7999923", + "root=/dev/vda1", + "init=/root/init.sh", + "rw", + ] + +# Setup the board. +board = HighPerformanceRiscvBoard( + clk_freq="4GHz", + processor=processor, + memory=memory, + cache_hierarchy=cache_hierarchy, +) + +# Set the Full System workload. +board.set_kernel_disk_workload( + kernel=Resource("riscv-bootloader-vmlinux-5.10"), + disk_image=DiskImageResource( + "/projects/gem5/npb-gapbs-riscv.img", root_partition="1" + ), + readfile_contents=f"{command}" +) + +# The first exit_event ends with a `workbegin` cause. This means that the +# system started successfully and the execution on the program started. +def handle_workbegin(): + print("Done booting Linux") + print("Resetting stats at the start of ROI!") + + m5.stats.dump() + m5.stats.reset() + + # switch the processor to timing CPU for warmup + print("Switching the CPU") + processor.switch() + # schedule an exit event for 1 second. + m5.scheduleTickExitFromCurrent(1000000000000) + yield False + +""" +def handle_cachewarmup(): + print("Cache warmed up as we reached : ") + print(simulator.get_last_exit_event_cause()) + print("Taking the checkpoint!") + + m5.stats.dump() + m5.stats.reset() + save_checkpoint() + yield True +""" +# Running things for 1sec and will +# not take ckpt if cache gets +# warmed up during Linux boot +def handle_cachewarmup(): + print("Cache warmed up as we reached : ") + print(simulator.get_last_exit_event_cause()) + print("Will continue simulation!") + + m5.stats.dump() + m5.stats.reset() + #save_checkpoint() + yield False + +def handle_schedtick(): + print("Cache warmed up as we reached : ") + print(simulator.get_last_exit_event_cause()) + print("Taking the checkpoint!") + + m5.stats.dump() + m5.stats.reset() + save_checkpoint() + yield True + +def handle_workend(): + print("Dump stats at the end of the ROI!") + + m5.stats.dump() + yield True + + +simulator = Simulator( + board=board, + on_exit_event={ + ExitEvent.WORKBEGIN: handle_workbegin(), + ExitEvent.WORKEND: handle_workend(), + ExitEvent.CACHE_WARMUP: handle_cachewarmup(), + ExitEvent.SCHEDULED_TICK: handle_schedtick(), + }, +) + +def save_checkpoint(): + simulator.save_checkpoint(args.ckpt_path) + + +print("Beginning simulation!") + +simulator.run() + +print("End of the simulation, we should have created a ckpt.") diff --git a/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing-npb-c.py b/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing-npb-c.py new file mode 100644 index 0000000000..03d994a947 --- /dev/null +++ b/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing-npb-c.py @@ -0,0 +1,164 @@ +from gem5.components.boards.riscv_board import RiscvBoard +from gem5.components.memory.memory import ChanneledMemory +from gem5.components.processors.simple_processor import SimpleProcessor +from gem5.components.processors.cpu_types import CPUTypes +from gem5.isas import ISA +from gem5.utils.requires import requires +from gem5.utils.override import overrides +from gem5.resources.resource import Resource, DiskImageResource +from gem5.simulate.simulator import Simulator +from gem5.components.processors.simple_switchable_processor import ( + SimpleSwitchableProcessor, +) +from gem5.components.memory import CascadeLakeCache, OracleCache, RamCache +from gem5.simulate.simulator import ExitEvent +import m5 +from components.Octopi import OctopiCache + +# Sample command to use this script +# build/RISCV/gem5.opt Octopi-cache/riscv-2channel-1ccd-checkpoint-timing-npb-c.py --benchmark bt --size C --ckpt_path test-dir/ + +requires(isa_required=ISA.RISCV) + +import argparse +parser = argparse.ArgumentParser() +parser.add_argument("--benchmark", type=str) +parser.add_argument("--size", type=str) +parser.add_argument("--ckpt_path", type=str) + +args = parser.parse_args() + +num_ccds = 1 +num_cores = 8 +command = f"/home/ubuntu/gem5-npb/NPB3.3-OMP/bin/{args.benchmark}.{args.size}.x;" + +cache_hierarchy = OctopiCache( + l1i_size = "32KiB", + l1i_assoc = 8, + l1d_size = "32KiB", + l1d_assoc = 8, + l2_size = "512KiB", + l2_assoc = 8, + l3_size = "32MiB", + l3_assoc = 16, + num_core_complexes = 1, + is_fullsystem = True, +) +memory = RamCache() + +processor = SimpleSwitchableProcessor( + starting_core_type=CPUTypes.TIMING, + switch_core_type=CPUTypes.TIMING, # TODO + isa=ISA.RISCV, + num_cores=num_cores +) + +class HighPerformanceRiscvBoard(RiscvBoard): + @overrides(RiscvBoard) + def get_default_kernel_args(self): + return [ + "earlyprintk=ttyS0", + "console=ttyS0", + "lpj=7999923", + "root=/dev/vda1", + "init=/root/init.sh", + "rw", + ] + +# Setup the board. +board = HighPerformanceRiscvBoard( + clk_freq="4GHz", + processor=processor, + memory=memory, + cache_hierarchy=cache_hierarchy, +) + +# Set the Full System workload. +board.set_kernel_disk_workload( + kernel=Resource("riscv-bootloader-vmlinux-5.10"), + disk_image=DiskImageResource( + "/projects/gem5/npb-gapbs-riscv.img", root_partition="1" + ), + readfile_contents=f"{command}" +) + +# The first exit_event ends with a `workbegin` cause. This means that the +# system started successfully and the execution on the program started. +def handle_workbegin(): + print("Done booting Linux") + print("Resetting stats at the start of ROI!") + + m5.stats.dump() + m5.stats.reset() + + # switch the processor to timing CPU for warmup + print("Switching the CPU") + processor.switch() + # schedule an exit event for 1 second. + m5.scheduleTickExitFromCurrent(1000000000000) + yield False + +# This event is scheduled every 100ms to get an +# update on the progress of the simulation itself +def handle_progress_update(): + + while True: + print("Simulated another 100ms") + + print( + f"Total sim time so far : {simulator.get_current_tick() / 1e12} sec" + ) + + m5.scheduleTickExitFromCurrent(100000000000, "progress_update") + yield False + +# Running things for 1sec and will +# not take ckpt if cache gets +# warmed up during Linux boot +def handle_cachewarmup(): + print("Cache warmed up as we reached : ") + print(simulator.get_last_exit_event_cause()) + print("Will continue simulation!") + + m5.stats.dump() + m5.stats.reset() + #save_checkpoint() + yield False + +def handle_schedtick(): + print("Going to take the ckpt because : ") + print(simulator.get_last_exit_event_cause()) + print("Taking the checkpoint!") + + m5.stats.dump() + m5.stats.reset() + save_checkpoint() + yield True + +def handle_workend(): + print("Dump stats at the end of the ROI!") + + m5.stats.dump() + yield True + + +simulator = Simulator( + board=board, + on_exit_event={ + ExitEvent.WORKBEGIN: handle_workbegin(), + ExitEvent.WORKEND: handle_workend(), + ExitEvent.CACHE_WARMUP: handle_cachewarmup(), + ExitEvent.SCHEDULED_TICK: handle_schedtick(), + #ExitEvent.SCHEDULED_TICK_PROGRESS: handle_progress_update(), + }, +) + +def save_checkpoint(): + simulator.save_checkpoint(args.ckpt_path) + +print("Beginning simulation!") + +#m5.scheduleTickExitFromCurrent(100000000000, "progress_update") +simulator.run() + +print("End of the simulation, we should have created a ckpt.") diff --git a/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing.py b/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing.py new file mode 100644 index 0000000000..27391f4931 --- /dev/null +++ b/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing.py @@ -0,0 +1,162 @@ +from gem5.components.boards.riscv_board import RiscvBoard +from gem5.components.memory.memory import ChanneledMemory +from gem5.components.processors.simple_processor import SimpleProcessor +from gem5.components.processors.cpu_types import CPUTypes +from gem5.isas import ISA +from gem5.utils.requires import requires +from gem5.utils.override import overrides +from gem5.resources.resource import Resource, DiskImageResource +from gem5.simulate.simulator import Simulator +from gem5.components.processors.simple_switchable_processor import ( + SimpleSwitchableProcessor, +) +from gem5.components.memory import CascadeLakeCache, OracleCache, RamCache +from gem5.simulate.simulator import ExitEvent +import m5 +from components.Octopi import OctopiCache + +# Sample command to use this script +# build/RISCV/gem5.opt --outdir=bt.D riscv-2channel-1ccd-checkpoint.py +# --benchmark bt --size D --ckpt_path checkpoints-npb/bt.D.ckpt/ +# + +requires(isa_required=ISA.RISCV) + +import argparse +parser = argparse.ArgumentParser() +parser.add_argument("--benchmark", type=str) +parser.add_argument("--size", type=str) +parser.add_argument("--ckpt_path", type=str) + +args = parser.parse_args() + +num_ccds = 1 +num_cores = 8 +command = f"/home/ubuntu/gem5-npb/NPB3.3-OMP/bin/{args.benchmark}.{args.size}.x;" + +cache_hierarchy = OctopiCache( + l1i_size = "32KiB", + l1i_assoc = 8, + l1d_size = "32KiB", + l1d_assoc = 8, + l2_size = "512KiB", + l2_assoc = 8, + l3_size = "32MiB", + l3_assoc = 16, + num_core_complexes = 1, + is_fullsystem = True, +) +memory = RamCache() + +processor = SimpleSwitchableProcessor( + starting_core_type=CPUTypes.TIMING, + switch_core_type=CPUTypes.TIMING, # TODO + isa=ISA.RISCV, + num_cores=num_cores +) + +class HighPerformanceRiscvBoard(RiscvBoard): + @overrides(RiscvBoard) + def get_default_kernel_args(self): + return [ + "earlyprintk=ttyS0", + "console=ttyS0", + "lpj=7999923", + "root=/dev/vda1", + "init=/root/init.sh", + "rw", + ] + +# Setup the board. +board = HighPerformanceRiscvBoard( + clk_freq="4GHz", + processor=processor, + memory=memory, + cache_hierarchy=cache_hierarchy, +) + +# Set the Full System workload. +board.set_kernel_disk_workload( + kernel=Resource("riscv-bootloader-vmlinux-5.10"), + disk_image=DiskImageResource( + "/projects/gem5/npb-gapbs-riscv.img", root_partition="1" + ), + readfile_contents=f"{command}" +) + +# The first exit_event ends with a `workbegin` cause. This means that the +# system started successfully and the execution on the program started. +def handle_workbegin(): + print("Done booting Linux") + print("Resetting stats at the start of ROI!") + + m5.stats.dump() + m5.stats.reset() + + # switch the processor to timing CPU for warmup + print("Switching the CPU") + processor.switch() + # schedule an exit event for 1 second. + m5.scheduleTickExitFromCurrent(1000000000000) + yield False + +""" +def handle_cachewarmup(): + print("Cache warmed up as we reached : ") + print(simulator.get_last_exit_event_cause()) + print("Taking the checkpoint!") + + m5.stats.dump() + m5.stats.reset() + save_checkpoint() + yield True +""" +# Running things for 1sec and will +# not take ckpt if cache gets +# warmed up during Linux boot +def handle_cachewarmup(): + print("Cache warmed up as we reached : ") + print(simulator.get_last_exit_event_cause()) + print("Will continue simulation!") + + m5.stats.dump() + m5.stats.reset() + #save_checkpoint() + yield False + +def handle_schedtick(): + print("Cache warmed up as we reached : ") + print(simulator.get_last_exit_event_cause()) + print("Taking the checkpoint!") + + m5.stats.dump() + m5.stats.reset() + save_checkpoint() + yield True + +def handle_workend(): + print("Dump stats at the end of the ROI!") + + m5.stats.dump() + yield True + + +simulator = Simulator( + board=board, + on_exit_event={ + ExitEvent.WORKBEGIN: handle_workbegin(), + ExitEvent.WORKEND: handle_workend(), + ExitEvent.CACHE_WARMUP: handle_cachewarmup(), + ExitEvent.SCHEDULED_TICK: handle_schedtick(), + }, +) + +def save_checkpoint(): + simulator.save_checkpoint(args.ckpt_path) + + +print("Beginning simulation!") + +simulator.run() + +print("End of the simulation, we should have created a ckpt.") diff --git a/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint.py b/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint.py new file mode 100644 index 0000000000..cf503bb3d7 --- /dev/null +++ b/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint.py @@ -0,0 +1,148 @@ +from gem5.components.boards.riscv_board import RiscvBoard +from gem5.components.memory.memory import ChanneledMemory +from gem5.components.processors.simple_processor import SimpleProcessor +from gem5.components.processors.cpu_types import CPUTypes +from gem5.isas import ISA +from gem5.utils.requires import requires +from gem5.utils.override import overrides +from gem5.resources.resource import Resource, DiskImageResource +from gem5.simulate.simulator import Simulator +from gem5.components.processors.simple_switchable_processor import ( + SimpleSwitchableProcessor, +) +from gem5.components.memory import CascadeLakeCache, OracleCache, RamCache +from gem5.simulate.simulator import ExitEvent +import m5 +from components.Octopi import OctopiCache + +# Sample command to use this script +# build/RISCV/gem5.opt --outdir=bt.D riscv-2channel-1ccd-checkpoint.py +# --benchmark bt --size D --ckpt_path checkpoints-npb/bt.D.ckpt/ +# + +requires(isa_required=ISA.RISCV) + +import argparse +parser = argparse.ArgumentParser() +parser.add_argument("--benchmark", type=str) +parser.add_argument("--size", type=str) +parser.add_argument("--ckpt_path", type=str) + +args = parser.parse_args() + +num_ccds = 1 +num_cores = 8 +command = f"/home/ubuntu/gem5-npb/NPB3.3-OMP/bin/{args.benchmark}.{args.size}.x;" + +cache_hierarchy = OctopiCache( + l1i_size = "32KiB", + l1i_assoc = 8, + l1d_size = "32KiB", + l1d_assoc = 8, + l2_size = "512KiB", + l2_assoc = 8, + l3_size = "32MiB", + l3_assoc = 32, + num_core_complexes = 1, + is_fullsystem = True, +) +memory = RamCache() + +processor = SimpleSwitchableProcessor( + starting_core_type=CPUTypes.ATOMIC, + switch_core_type=CPUTypes.TIMING, # TODO + isa=ISA.RISCV, + num_cores=num_cores +) + +class HighPerformanceRiscvBoard(RiscvBoard): + @overrides(RiscvBoard) + def get_default_kernel_args(self): + return [ + "earlyprintk=ttyS0", + "console=ttyS0", + "lpj=7999923", + "root=/dev/vda1", + "init=/root/init.sh", + "rw", + ] + +# Setup the board. +board = HighPerformanceRiscvBoard( + clk_freq="4GHz", + processor=processor, + memory=memory, + cache_hierarchy=cache_hierarchy, +) + +# Set the Full System workload. +board.set_kernel_disk_workload( + kernel=Resource("riscv-bootloader-vmlinux-5.10"), + disk_image=DiskImageResource( + "/projects/gem5/npb-gapbs-riscv.img", root_partition="1" + ), + readfile_contents=f"{command}" +) + +# The first exit_event ends with a `workbegin` cause. This means that the +# system started successfully and the execution on the program started. +def handle_workbegin(): + print("Done booting Linux") + print("Resetting stats at the start of ROI!") + + m5.stats.dump() + m5.stats.reset() + + # switch the processor to timing CPU for warmup + processor.switch() + # schedule an exit event for 1 second. + m5.scheduleTickExitFromCurrent(1000000000000) + yield False + + +def handle_cachewarmup(): + print("Cache warmed up as we reached : ") + print(simulator.get_last_exit_event_cause()) + print("Taking the checkpoint!") + + m5.stats.dump() + m5.stats.reset() + save_checkpoint() + yield True + +def handle_schedtick(): + print("Cache warmed up as we reached : ") + print(simulator.get_last_exit_event_cause()) + print("Taking the checkpoint!") + + m5.stats.dump() + m5.stats.reset() + save_checkpoint() + yield True + +def handle_workend(): + print("Dump stats at the end of the ROI!") + + m5.stats.dump() + yield True + + +simulator = Simulator( + board=board, + on_exit_event={ + ExitEvent.WORKBEGIN: handle_workbegin(), + ExitEvent.WORKEND: handle_workend(), + ExitEvent.CACHE_WARMUP: handle_cachewarmup(), + ExitEvent.SCHEDULED_TICK: handle_schedtick(), + }, +) + +def save_checkpoint(): + simulator.save_checkpoint(args.ckpt_path) + + +print("Beginning simulation!") + +simulator.run() + +print("End of the simulation, we should have created a ckpt.") diff --git a/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-restore-timing-gapbs.py b/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-restore-timing-gapbs.py new file mode 100644 index 0000000000..da8dde9be9 --- /dev/null +++ b/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-restore-timing-gapbs.py @@ -0,0 +1,160 @@ +from gem5.components.boards.riscv_board import RiscvBoard +from gem5.components.memory.memory import ChanneledMemory +from gem5.components.processors.simple_processor import SimpleProcessor +from gem5.components.processors.cpu_types import CPUTypes +from gem5.isas import ISA +from gem5.utils.requires import requires +from gem5.utils.override import overrides +from gem5.resources.resource import Resource, DiskImageResource +from gem5.simulate.simulator import Simulator +from gem5.components.processors.simple_switchable_processor import ( + SimpleSwitchableProcessor, +) +from gem5.components.processors.simple_processor import ( + SimpleProcessor, +) +from gem5.components.memory import CascadeLakeCache, OracleCache, RamCache +from gem5.simulate.simulator import ExitEvent +import m5 +from components.Octopi import OctopiCache +from pathlib import Path + +# Sample command to use this script +# build/RISCV/gem5.opt -re --outdir=/projects/gem5/sssp16-test/ Octopi-cache/riscv-2channel-1ccd-restore-timing-gapbs.py --benchmark sssp --size 16 --ckpt_path /projects/gem5/dramcache/jason-checkpoints/gapbs/16/sssp/ckpt +# build/RISCV/gem5.opt -re --outdir=/projects/gem5/sssp16-test/ Octopi-cache/riscv-2channel-1ccd-restore-timing-gapbs.py --benchmark sssp --size C --ckpt_path /projects/gem5/dramcache/jason-checkpoints/npb/c/bt/ckpt + +requires(isa_required=ISA.RISCV) + +import argparse +parser = argparse.ArgumentParser() +parser.add_argument("--benchmark", type=str) +parser.add_argument("--size", type=str) +parser.add_argument("--ckpt_path", type=str) + +args = parser.parse_args() + +num_ccds = 1 +num_cores = 8 +#command = f"/home/ubuntu/gapbs/{args.benchmark} -g {args.size};" +command = f"/home/ubuntu/gem5-npb/NPB3.3-OMP/bin/{args.benchmark}.{args.size}.x;" + +cache_hierarchy = OctopiCache( + l1i_size = "32KiB", + l1i_assoc = 8, + l1d_size = "32KiB", + l1d_assoc = 8, + l2_size = "512KiB", + l2_assoc = 8, + l3_size = "32MiB", + l3_assoc = 16, + num_core_complexes = 1, + is_fullsystem = True, +) +memory = RamCache() + +""" +processor = SimpleSwitchableProcessor( + starting_core_type=CPUTypes.TIMING, + switch_core_type=CPUTypes.TIMING, # TODO + isa=ISA.RISCV, + num_cores=num_cores +) +""" + +processor = SimpleProcessor( + cpu_type=CPUTypes.TIMING, isa=ISA.RISCV, num_cores=num_cores +) + +class HighPerformanceRiscvBoard(RiscvBoard): + @overrides(RiscvBoard) + def get_default_kernel_args(self): + return [ + "earlyprintk=ttyS0", + "console=ttyS0", + "lpj=7999923", + "root=/dev/vda1", + "init=/root/init.sh", + "rw", + ] + +# Setup the board. +board = HighPerformanceRiscvBoard( + clk_freq="4GHz", + processor=processor, + memory=memory, + cache_hierarchy=cache_hierarchy, +) + +# Set the Full System workload. +board.set_kernel_disk_workload( + kernel=Resource("riscv-bootloader-vmlinux-5.10"), + disk_image=DiskImageResource( + "/projects/gem5/npb-gapbs-riscv.img", root_partition="1" + ), + readfile_contents=f"{command}", + checkpoint=Path(args.ckpt_path) +) + +# The first exit_event ends with a `workbegin` cause. This means that the +# system started successfully and the execution on the program started. +def handle_workbegin(): + print("Unexpected case!") + print("Workload begin should have not hit again!") + yield False + +# This event is scheduled every 100ms to get an +# update on the progress of the simulation itself +def handle_progress_update(): + + while True: + print("Simulated another 100ms") + + print( + f"Total sim time so far : {simulator.get_current_tick() / 1e12} sec" + ) + + m5.scheduleTickExitFromCurrent(100000000000, "progress_update") + yield False + +def handle_cachewarmup(): + # we probably should never hit this + # case during ckpt restore + print("DRAM Cache warmed up!") + print("Will continue simulation!") + yield False + +def handle_schedtick(): + print("Terminating the simulation because : ") + print(simulator.get_last_exit_event_cause()) + m5.stats.dump() + yield True + +def handle_workend(): + print("Terminating the simulation because : ") + print(simulator.get_last_exit_event_cause()) + m5.stats.dump() + yield True + + +simulator = Simulator( + board=board, + on_exit_event={ + ExitEvent.WORKBEGIN: handle_workbegin(), + ExitEvent.WORKEND: handle_workend(), + ExitEvent.CACHE_WARMUP: handle_cachewarmup(), + ExitEvent.SCHEDULED_TICK: handle_schedtick(), + #ExitEvent.SCHEDULED_TICK_PROGRESS: handle_progress_update(), + }, +) + +print("Beginning simulation!") +print(f"Will restore the checkpoint from : {args.ckpt_path} ") + +# progress update +#m5.scheduleTickExitFromCurrent(100000000000, "progress_update") + +# Running the actual simulation for 1 second +#m5.scheduleTickExitFromCurrent(1000000000000) +simulator.run(1000000000000) + +print("End of the simulation!") diff --git a/Octopi-cache/old-run-scripts/riscv-2channel-1ccd.py b/Octopi-cache/old-run-scripts/riscv-2channel-1ccd.py new file mode 100644 index 0000000000..3b0b11ec00 --- /dev/null +++ b/Octopi-cache/old-run-scripts/riscv-2channel-1ccd.py @@ -0,0 +1,101 @@ +from gem5.components.boards.riscv_board import RiscvBoard +from gem5.components.memory.memory import ChanneledMemory +from gem5.components.processors.simple_processor import SimpleProcessor +from gem5.components.processors.cpu_types import CPUTypes +from gem5.isas import ISA +from gem5.utils.requires import requires +from gem5.utils.override import overrides +from gem5.resources.resource import Resource, DiskImageResource +from gem5.simulate.simulator import Simulator +from gem5.components.processors.simple_switchable_processor import ( + SimpleSwitchableProcessor, +) +from gem5.components.memory import CascadeLakeCache, OracleCache, RamCache +import m5 + +from m5.objects import HBM_1000_4H_1x64 + +from components.Octopi import OctopiCache + +requires(isa_required=ISA.RISCV) + +import argparse +parser = argparse.ArgumentParser() +parser.add_argument("--command", type=str) +parser.add_argument("--checkpoint-path", type=str) + +args = parser.parse_args() + +num_ccds = 1 +num_cores = 8 +command = args.command + +cache_hierarchy = OctopiCache( + l1i_size = "32KiB", + l1i_assoc = 8, + l1d_size = "32KiB", + l1d_assoc = 8, + l2_size = "512KiB", + l2_assoc = 8, + l3_size = "32MiB", + l3_assoc = 32, + num_core_complexes = 1, + is_fullsystem = True, +) +memory = RamCache() + +""" +memory = ChanneledMemory( + dram_interface_class = HBM_1000_4H_1x64, + num_channels = 2, + interleaving_size = 2**8, + size = "64GiB", + addr_mapping = None +) +""" + +processor = SimpleSwitchableProcessor( + starting_core_type=CPUTypes.TIMING, + switch_core_type=CPUTypes.TIMING, # TODO + isa=ISA.RISCV, + num_cores=num_cores +) + +class HighPerformanceRiscvBoard(RiscvBoard): + @overrides(RiscvBoard) + def get_default_kernel_args(self): + return [ + "earlyprintk=ttyS0", + "console=ttyS0", + "lpj=7999923", + "root=/dev/vda1", + "init=/root/init.sh", + "rw", + ] + +# Setup the board. +board = HighPerformanceRiscvBoard( + clk_freq="4GHz", + processor=processor, + memory=memory, + cache_hierarchy=cache_hierarchy, +) + +# Set the Full System workload. +board.set_kernel_disk_workload( + kernel=Resource("riscv-bootloader-vmlinux-5.10"), + #disk_image=DiskImageResource( + # "/projects/gem5/npb-gapbs-riscv.img", root_partition="1" + #), + disk_image=DiskImageResource("/scr/hn/DISK_IMAGES/ubuntu-2204-riscv.img"), + readfile_contents=f"{command}" +) + +m5.scheduleTickExitFromCurrent(1000000000) + +simulator = Simulator(board=board) +print("Beginning simulation!") +simulator.run() +print("We are exiting because : ") +print(simulator.get_last_exit_event_cause()) +simulator.save_checkpoint(args.checkpoint_path) diff --git a/Octopi-cache/restore-npb-gapbs-looppoint.py b/Octopi-cache/restore-npb-gapbs-looppoint.py new file mode 100644 index 0000000000..6e5a22e4c3 --- /dev/null +++ b/Octopi-cache/restore-npb-gapbs-looppoint.py @@ -0,0 +1,259 @@ +from gem5.components.boards.riscv_board import RiscvBoard +from gem5.components.memory.memory import ChanneledMemory +from gem5.components.processors.simple_processor import SimpleProcessor +from gem5.components.processors.cpu_types import CPUTypes +from gem5.isas import ISA +from gem5.utils.requires import requires +from gem5.utils.override import overrides +from gem5.resources.resource import Resource, DiskImageResource +from gem5.simulate.simulator import Simulator +from gem5.components.processors.simple_switchable_processor import ( + SimpleSwitchableProcessor, + MySimpleProcessor, +) +from gem5.components.processors.simple_processor import SimpleProcessor +from gem5.components.memory import CascadeLakeCache, OracleCache, RambusCache +from gem5.simulate.simulator import ExitEvent +import m5 +from components.Octopi import OctopiCache +from pathlib import Path +from m5.objects import O3LooppointAnalysis, O3LooppointAnalysisManager + + +# Sample command to use this script +# build/RISCV_MESI_Three_Level/gem5.opt -re --outdir=m5out Octopi-cache/restore-npb-gapbs-looppoint.py RambusBaseline bt 128MiB + +requires(isa_required=ISA.RISCV) + +import argparse + +parser = argparse.ArgumentParser() +parser.add_argument("experiment", type=str) +parser.add_argument("benchmark", type=str) +parser.add_argument("cache_size", type=str) + +args = parser.parse_args() + +ckpt_path = "/projects/gem5/dramcache/jason-checkpoints/npb/c/"+args.benchmark+"/ckpt" +print("Checkpoint directory: "+ckpt_path) + +# Valid addresses for looppoint analysis +# The addresses are the .text section range +text_start = { + "bt.C": "111b0", + "cg.C": "112a0", + "ft.C": "113a0", + "is.C": "10df0", + "lu.C": "11450", + "mg.C": "11630", + "sp.C": "11250", + "ua.C": "11aa0", + "bt.D": "111b0", + "cg.D": "112a0", + "ft.D": "113a0", + "lu.D": "11450", + "mg.D": "11630", + "sp.D": "11250", + "ua.D": "11aa0", + "bc": "12c80", + "bfs": "12bb0", + "cc": "12e60", + "cc_sv": "12ca0", + "pr": "12dd0", + "sssp": "12d80", + "tc": "12c00", +} + +text_size = { + "bt.C": "e14a", + "cg.C": "2b84", + "ft.C": "353a", + "is.C": "1692", + "lu.C": "df12", + "mg.C": "66ca", + "sp.C": "b31e", + "ua.C": "190f4", + "bt.D": "e500", + "cg.D": "2a4a", + "ft.D": "35ba", + "lu.D": "e0e0", + "mg.D": "687a", + "sp.D": "b7d4", + "ua.D": "191f0", + "bc": "af82", + "bfs": "a008", + "cc": "a51a", + "cc_sv": "98a4", + "pr": "9b14", + "sssp": "acf8", + "tc": "9cc2", +} + + +num_ccds = 1 +num_cores = 8 +command = ( + f"/home/ubuntu/gem5-npb/NPB3.3-OMP/bin/{args.benchmark}.C.x;" +) + +cache_hierarchy = OctopiCache( + l1i_size="32KiB", + l1i_assoc=8, + l1d_size="32KiB", + l1d_assoc=8, + l2_size="512KiB", + l2_assoc=8, + l3_size="32MiB", + l3_assoc=16, + num_core_complexes=1, + is_fullsystem=True, +) + +if args.experiment == "RambusBaseline": + memory = RambusCache(args.cache_size) +elif args.experiment == "CascadeLakeBaseline": + memory = CascadeLakeCache(args.cache_size) +elif args.experiment == "OracleBaseline": + memory = OracleCache(args.cache_size) + +processor = MySimpleProcessor( + starting_core_type=CPUTypes.O3, + switch_core_type=CPUTypes.O3, + isa=ISA.RISCV, + num_cores=num_cores, +) + +lpmanager = O3LooppointAnalysisManager() + +# dump the tick and the PC counter as well + +for core in processor.get_cores(): + lplistener = O3LooppointAnalysis() + lplistener.ptmanager = lpmanager + lplistener.validAddrRangeStart = int(text_start[args.benchmark+".C"], 16) + lplistener.validAddrRangeSize = int(text_size[args.benchmark+".C"], 16) + core.core.probeListener = lplistener + + +class HighPerformanceRiscvBoard(RiscvBoard): + @overrides(RiscvBoard) + def get_default_kernel_args(self): + return [ + "earlyprintk=ttyS0", + "console=ttyS0", + "lpj=7999923", + "root=/dev/vda1", + "init=/root/init.sh", + "rw", + ] + + +# Setup the board. +board = HighPerformanceRiscvBoard( + clk_freq="4GHz", + processor=processor, + memory=memory, + cache_hierarchy=cache_hierarchy, +) + +# Set the Full System workload. +board.set_kernel_disk_workload( + kernel=Resource("riscv-bootloader-vmlinux-5.10"), + disk_image=DiskImageResource( + "/projects/gem5/npb-gapbs-riscv.img", root_partition="1" + ), + readfile_contents=f"{command}", + checkpoint=Path(ckpt_path), +) + +# The first exit_event ends with a `workbegin` cause. This means that the +# system started successfully and the execution on the program started. +def handle_workbegin(): + print("Unexpected case!") + print("Workload begin should have not hit again!") + yield False + + +# This event is scheduled every 100ms to get an +# update on the progress of the simulation itself +def handle_progress_update(): + + while True: + print("Simulated another 100ms") + + print( + f"Total sim time so far : {simulator.get_current_tick() / 1e12} sec" + ) + + print("Most recent (PC, count, tick) at this point in simulation") + mostRecentPc = lpmanager.getMostRecentPc() + for pc, tick in mostRecentPc: + count = lpmanager.getPcCount(pc) + print(f"{hex(pc)},{count[0]},{count[1]}\n") + + m5.scheduleTickExitFromCurrent(100_000_000_000, "progress_update") + yield False + + +def handle_cachewarmup(): + # we probably should never hit this + # case during ckpt restore + print("DRAM Cache warmed up!") + print("Will continue simulation!") + yield False + + +def handle_schedtick(): + print("Terminating the simulation because : ") + print(simulator.get_last_exit_event_cause()) + m5.stats.dump() + yield True + + +def handle_workend(): + print("Terminating the simulation because : ") + print(simulator.get_last_exit_event_cause()) + m5.stats.dump() + yield True + + +simulator = Simulator( + board=board, + on_exit_event={ + ExitEvent.WORKBEGIN: handle_workbegin(), + ExitEvent.WORKEND: handle_workend(), + ExitEvent.CACHE_WARMUP: handle_cachewarmup(), + ExitEvent.SCHEDULED_TICK: handle_schedtick(), + ExitEvent.SCHEDULED_TICK_PROGRESS: handle_progress_update(), + }, +) + +print("Beginning simulation!") +print(f"Will restore the checkpoint from : {ckpt_path} ") + +# Start the simulation so that the +# scheduleTickExitFromCurrent() can be used +#simulator.run(1000) +# progress update +#m5.scheduleTickExitFromCurrent(100_000_000_000, "progress_update") + +def DumpLoopPointCounters(): + mostRecentPc = lpmanager.getMostRecentPc() + print("Most recent (PC, count, tick) at the end of the simulation") + for pc, tick in mostRecentPc: + count = lpmanager.getPcCount(pc) + print(f"{hex(pc)},{count[0]},{count[1]}") + +# Simulate 1s in 10 intervals +numIteration = 10 + +print("Simulating ten intervals of 100ms!") + +for interval_number in range(numIteration): + print("Interval number: {} \n".format(interval_number)) + simulator.run(100_000_000_000) + print(f"Exiting simulation loop because of : {simulator.get_last_exit_event_cause()}") + DumpLoopPointCounters() + m5.stats.dump() + +print("End of the simulation!") diff --git a/Octopi-cache/riscv-hpc.py b/Octopi-cache/riscv-hpc.py new file mode 100644 index 0000000000..74001499a9 --- /dev/null +++ b/Octopi-cache/riscv-hpc.py @@ -0,0 +1,87 @@ +from gem5.components.boards.riscv_board import RiscvBoard +from gem5.components.memory.memory import ChanneledMemory +from gem5.components.processors.simple_processor import SimpleProcessor +from gem5.components.processors.cpu_types import CPUTypes +from gem5.isas import ISA +from gem5.utils.requires import requires +from gem5.utils.override import overrides +from gem5.resources.resource import Resource, DiskImageResource +from gem5.simulate.simulator import Simulator +from gem5.components.memory import CascadeLakeCache, OracleCache, RamCache + +from m5.objects import HBM_1000_4H_1x64 + +from components.Octopi import OctopiCache + +requires(isa_required=ISA.RISCV) + + + +import argparse +parser = argparse.ArgumentParser() +parser.add_argument("--command", type=str) +parser.add_argument("--num_ccxs", type=int, required=True) +parser.add_argument("--num_cores", type=int, required=True) +args = parser.parse_args() + +num_ccxs = args.num_ccxs +num_cores = args.num_cores +command = args.command + +cache_hierarchy = OctopiCache( + l1i_size = "32KiB", + l1i_assoc = 8, + l1d_size = "32KiB", + l1d_assoc = 8, + l2_size = "512KiB", + l2_assoc = 8, + l3_size = "32MiB", + l3_assoc = 32, + num_core_complexes = num_ccxs, + is_fullsystem = True, +) + +#memory = ChanneledMemory( +# dram_interface_class = HBM_1000_4H_1x64, +# num_channels = num_ccxs, # should equal to the number of core complexes +# interleaving_size = 2**8, +# size = "8GiB", +# addr_mapping = None +#) + +memory = RamCache() + +processor = SimpleProcessor( + cpu_type=CPUTypes.TIMING, isa=ISA.RISCV, num_cores=num_cores +) + +class HighPerformanceRiscvBoard(RiscvBoard): + @overrides(RiscvBoard) + def get_default_kernel_args(self): + return [ + "earlyprintk=ttyS0", + "console=ttyS0", + "lpj=7999923", + "root=/dev/vda1", + "init=/root/init.sh", + "rw", + ] + +# Setup the board. +board = HighPerformanceRiscvBoard( + clk_freq="4GHz", + processor=processor, + memory=memory, + cache_hierarchy=cache_hierarchy, +) + +# Set the Full System workload. +board.set_kernel_disk_workload( + kernel=Resource("riscv-bootloader-vmlinux-5.10"), + disk_image=DiskImageResource("/scr/hn/DISK_IMAGES/ubuntu-2204-riscv.img"), + readfile_contents=f"{command}" +) + +simulator = Simulator(board=board) +print("Beginning simulation!") +simulator.run() diff --git a/build_opts/RISCV_MESI_Three_Level b/build_opts/RISCV_MESI_Three_Level new file mode 100644 index 0000000000..348e8deec0 --- /dev/null +++ b/build_opts/RISCV_MESI_Three_Level @@ -0,0 +1,2 @@ +USE_RISCV_ISA = True +PROTOCOL = 'MESI_Three_Level' diff --git a/cold-miss-check-plots.ipynb b/cold-miss-check-plots.ipynb new file mode 100644 index 0000000000..8c7ea949f7 --- /dev/null +++ b/cold-miss-check-plots.ipynb @@ -0,0 +1,466 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import sys\n", + "from matplotlib import pyplot as plt\n", + "import os\n", + "\n", + "cmap = plt.get_cmap('Set1')\n", + "\n", + "Stats = ['simSeconds ',\n", + "'hostSeconds ',\n", + "'system.mem_ctrl.readReqs ',\n", + "'system.mem_ctrl.writeReqs ',\n", + "'system.mem_ctrl.servicedByWrQ ',\n", + "'system.mem_ctrl.mergedWrBursts ',\n", + "'system.mem_ctrl.numTotHits ',\n", + "'system.mem_ctrl.numTotMisses ',\n", + "'system.mem_ctrl.numColdMisses ',\n", + "'system.mem_ctrl.numHotMisses ',\n", + "'system.mem_ctrl.numRdMissClean ',\n", + "'system.mem_ctrl.numRdMissDirty ',\n", + "'system.mem_ctrl.numRdHit ',\n", + "'system.mem_ctrl.numWrMissClean ',\n", + "'system.mem_ctrl.numWrMissDirty ',\n", + "'system.mem_ctrl.numWrHit ',\n", + "'system.mem_ctrl.numRdHitDirty ',\n", + "'system.mem_ctrl.numRdHitClean ',\n", + "'system.mem_ctrl.numWrHitDirty ',\n", + "'system.mem_ctrl.numWrHitClean ',\n", + "'system.o3Cpu0.thread_0.numInsts ',\n", + "'system.o3Cpu1.thread_0.numInsts ',\n", + "'system.o3Cpu2.thread_0.numInsts ',\n", + "'system.o3Cpu3.thread_0.numInsts ',\n", + "'system.o3Cpu4.thread_0.numInsts ',\n", + "'system.o3Cpu5.thread_0.numInsts ',\n", + "'system.o3Cpu6.thread_0.numInsts ',\n", + "'system.o3Cpu7.thread_0.numInsts ',\n", + "'system.mem_ctrl.avgRdBWSys ',\n", + "'system.mem_ctrl.avgWrBWSys ',\n", + "'system.mem_ctrl.avgORBLen ',\n", + "'system.far_mem_ctrl.avgRdBWSys ',\n", + "'system.far_mem_ctrl.avgWrBWSys ',\n", + "'system.loc_mem_ctrl.avgRdBWSys ',\n", + "'system.loc_mem_ctrl.avgWrBWSys ',\n", + "'system.loc_mem_ctrl.dram.readBursts ',\n", + "'system.loc_mem_ctrl.dram.writeBursts ',\n", + "'system.loc_mem_ctrl.dram_2.readBursts ',\n", + "'system.loc_mem_ctrl.dram_2.writeBursts ',\n", + "'system.far_mem_ctrl.dram.readBursts ',\n", + "'system.far_mem_ctrl.dram.writeBursts ',\n", + "'system.loc_mem_ctrl.dram.avgRdBW ',\n", + "'system.loc_mem_ctrl.dram.avgWrBW ',\n", + "'system.loc_mem_ctrl.dram_2.avgRdBW ',\n", + "'system.loc_mem_ctrl.dram_2.avgWrBW ',\n", + "'system.far_mem_ctrl.dram.avgRdBW ',\n", + "'system.far_mem_ctrl.dram.avgWrBW ',\n", + "'system.loc_mem_ctrl.dram.busUtil ',\n", + "'system.loc_mem_ctrl.dram.busUtilRead ',\n", + "'system.loc_mem_ctrl.dram.busUtilWrite ',\n", + "'system.loc_mem_ctrl.dram_2.busUtil ',\n", + "'system.loc_mem_ctrl.dram_2.busUtilRead ',\n", + "'system.loc_mem_ctrl.dram_2.busUtilWrite ',\n", + "'system.far_mem_ctrl.dram.busUtil ',\n", + "'system.far_mem_ctrl.dram.busUtilRead ',\n", + "'system.far_mem_ctrl.dram.busUtilWrite ',\n", + "'system.far_mem_ctrl.dram.bytesRead ',\n", + "'system.far_mem_ctrl.dram.bytesWritten ',\n", + "'system.loc_mem_ctrl.dram.bytesRead ',\n", + "'system.loc_mem_ctrl.dram.bytesWritten ',\n", + "'system.loc_mem_ctrl.dram_2.bytesRead ',\n", + "'system.loc_mem_ctrl.dram_2.bytesWritten ',\n", + "'system.mem_ctrl.avgTimeTagCheckRes ',\n", + "'system.mem_ctrl.avgTimeTagCheckResRd ',\n", + "'system.mem_ctrl.avgTimeTagCheckResWr ',\n", + "'system.mem_ctrl.avgPktRespTimeRd ',\n", + "'system.mem_ctrl.avgPktRespTimeWr ',\n", + "'system.mem_ctrl.avgPktORBTime ',\n", + "'system.mem_ctrl.avgPktORBTimeRd ',\n", + "'system.mem_ctrl.avgPktORBTimeWr ',\n", + "'system.mem_ctrl.avgTimeInLocRead ',\n", + "'system.mem_ctrl.avgTimeInLocWrite ',\n", + "'system.mem_ctrl.avgTimeInFarRead '\n", + " ]\n", + "\n", + "dfCols = [\n", + " 'app',\n", + " 'simSeconds',\n", + " 'hostSeconds',\n", + " 'readReqs',\n", + " 'writeReqs',\n", + " 'servicedByWrQ',\n", + " 'mergedWrBursts',\n", + " 'numTotHits',\n", + " 'numTotMisses',\n", + " 'numColdMisses',\n", + " 'numHotMisses',\n", + " 'numRdMissClean',\n", + " 'numRdMissDirty',\n", + " 'numRdHit',\n", + " 'numWrMissClean',\n", + " 'numWrMissDirty',\n", + " 'numWrHit',\n", + " 'numRdHitDirty',\n", + " 'numRdHitClean',\n", + " 'numWrHitDirty',\n", + " 'numWrHitClean',\n", + " 'numInsts0',\n", + " 'numInsts1',\n", + " 'numInsts2',\n", + " 'numInsts3',\n", + " 'numInsts4',\n", + " 'numInsts5',\n", + " 'numInsts6',\n", + " 'numInsts7',\n", + " 'avgRdBWSys',\n", + " 'avgWrBWSys',\n", + " 'avgORBLen',\n", + " 'farAvgRdBWSys',\n", + " 'farAvgWrBWSys',\n", + " 'locAvgRdBWSys',\n", + " 'locAvgWrBWSys',\n", + " 'readBursts1',\n", + " 'writeBursts1',\n", + " 'readBursts2',\n", + " 'writeBursts2',\n", + " 'readBursts3',\n", + " 'writeBursts3',\n", + " 'loc1AvgRdBW',\n", + " 'loc1AvgWrBW',\n", + " 'loc2AvgRdBW',\n", + " 'loc2AvgWrBW',\n", + " 'farAvgRdBW',\n", + " 'farAvgWrBW',\n", + " 'loc1BusUtil',\n", + " 'loc1BusUtilRead',\n", + " 'loc1BusUtilWrite',\n", + " 'loc2BusUtil',\n", + " 'loc2BusUtilRead',\n", + " 'loc2BusUtilWrite',\n", + " 'farBusUtil',\n", + " 'farBusUtilRead',\n", + " 'farBusUtilWrite',\n", + " 'farBytesRead',\n", + " 'farBytesWritten',\n", + " 'loc1BytesRead',\n", + " 'loc1BytesWritten',\n", + " 'loc2BytesRead',\n", + " 'loc2BytesWritten',\n", + " 'avgTimeTagCheckRes',\n", + " 'avgTimeTagCheckResRd',\n", + " 'avgTimeTagCheckResWr',\n", + " 'avgPktRespTimeRd',\n", + " 'avgPktRespTimeWr',\n", + " 'avgPktORBTime',\n", + " 'avgPktORBTimeRd',\n", + " 'avgPktORBTimeWr',\n", + " 'avgTimeInLocRead',\n", + " 'avgTimeInLocWrite',\n", + " 'avgTimeInFarRead'\n", + "\n", + " ]\n", + "##########################################################\n", + "\n", + "def getStat(filename, stat, index):\n", + " filename = os.path.join(filename).replace('\\\\','/')\n", + " #print(stat)\n", + " #print(filename)\n", + " try:\n", + " x = 0\n", + " with open(filename) as f:\n", + " readlines = f.readlines()\n", + " for l in readlines:\n", + " if stat in l and x < (index-1):\n", + " x = x+1\n", + " elif stat in l and x == (index-1):\n", + " return l\n", + " return 0.0 #for cases where stat was not found\n", + " except: #for cases where the file was not found\n", + " return 0.0\n", + "\n", + "##########################################################\n", + "\n", + "def creatDataFrame(dataDir, suite, index):\n", + " app = []\n", + " if suite == \"GAPBS\":\n", + " app = ['bc', 'bfs', 'cc', 'pr', 'sssp', 'tc']\n", + " if suite == \"NPB\":\n", + " app = ['bt', 'cg', 'ft', 'is', 'lu', 'mg', 'sp', 'ua']\n", + " rows = []\n", + " i = 0\n", + " for a in app:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}/stats.txt'.format(dataDir, a)\n", + " ret_line = getStat(time_file_path, stat, index[i])\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + " i = i+1\n", + " df = pd.DataFrame(rows, columns= dfCols)\n", + " df['totNumInsts'] = df['numInsts0'].astype(int)+df['numInsts1'].astype(int)+df['numInsts2'].astype(int)+df['numInsts3'].astype(int)+df['numInsts4'].astype(int)+df['numInsts5'].astype(int)+df['numInsts6'].astype(int)+df['numInsts7'].astype(int)\n", + " df['totBW'] = (df['avgRdBWSys'].astype(float)+df['avgWrBWSys'].astype(float))/1000000000\n", + " df['coldRate'] = (df['numColdMisses'].astype(float) / df['numTotMisses'].astype(float)) *100\n", + " df['injRate'] = (df['readReqs'].astype(float) + df['writeReqs'].astype(float))*64/1000000000 / df['simSeconds'].astype(float)\n", + " df['BIPS'] = (df['totNumInsts'].astype(float)/1000000000)/df['simSeconds'].astype(float)\n", + " \n", + " df['accAmp'] = (df['farBytesRead'].astype(float) + df['farBytesWritten'].astype(float) +\n", + " df['loc1BytesRead'].astype(float) + df['loc1BytesWritten'].astype(float) + \n", + " df['loc2BytesRead'].astype(float) + df['loc2BytesWritten'].astype(float)) / (df['readReqs'].astype(float) * 64 + df['writeReqs'].astype(float) * 64)\n", + " \n", + " df['BWBloat'] = (df['loc1AvgRdBW'].astype(float) + df['loc1AvgWrBW'].astype(float) +\n", + " df['loc2AvgRdBW'].astype(float) + df['loc2AvgWrBW'].astype(float) +\n", + " df['farAvgRdBW'].astype(float) + df['farAvgWrBW'].astype(float)) / ((df['avgRdBWSys'].astype(float) + df['avgWrBWSys'].astype(float)) / 1000000)\n", + " return df" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "df_gap_22 = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/pcAnalysis/3hour/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [10,7,7,8,10,32])\n", + "df_npb_c = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/pcAnalysis/3hour/1GB_8GB_g22_nC/NPB\", \"NPB\", [9,8,3,8,4,12,12,9])\n", + "df_gap_25 = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/pcAnalysis/3hour/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [10,9,4,6,6,12])\n", + "df_npb_d = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/pcAnalysis/3hour/1GB_85GB_g25_nD/NPB\", \"NPB\", [14,6,2,6,16,9,13,1])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "df_gap_22_2 = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/pcAnalysis/3hour_1halfChkpt/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [8,6,8,7,5,24])\n", + "df_npb_c_2 = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/pcAnalysis/3hour_1halfChkpt/1GB_8GB_g22_nC/NPB\", \"NPB\", [3,7,3,8,13,11,11,8])\n", + "df_gap_25_2 = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/pcAnalysis/3hour_1halfChkpt/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [6,5,6,4,5,10])\n", + "df_npb_d_2 = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/pcAnalysis/3hour_1halfChkpt/1GB_85GB_g25_nD/NPB\", \"NPB\", [10,4,0,4,13,8,10,0])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 13.574369\n", + "1 0.772378\n", + "2 0.042189\n", + "3 0.001220\n", + "4 0.000000\n", + "5 15.545457\n", + "dtype: float64\n", + "0 1.069289\n", + "1 2.450410\n", + "2 0.102372\n", + "3 4.181787\n", + "4 6.680209\n", + "5 9.491518\n", + "dtype: float64\n", + "0 0.123416\n", + "1 0.000628\n", + "2 35.656932\n", + "3 13.277294\n", + "4 0.000610\n", + "5 16.376971\n", + "6 0.263860\n", + "7 0.007352\n", + "dtype: float64\n", + "0 6.729032\n", + "1 6.215870\n", + "2 33.964109\n", + "3 12.628388\n", + "4 6.571731\n", + "5 11.891573\n", + "6 7.345704\n", + "7 44.730473\n", + "dtype: float64\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAACUCAYAAACeNFNKAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAdAElEQVR4nO3deZxU1Zn/8c9XQIlrA6KiRMFdo0YTYkSitiBC1EBnIYvinmCMRo3jmDiZccno7yeTRVAzRJwYF4zGKOASoyGYDlHRCCqCookKjCAoifsGiM/8cU9j0XY31cutqi6+79erXlX31K06T1Xdqn76nHPPUURgZmZmVk02KHcAZmZmZh3NCY6ZmZlVHSc4ZmZmVnWc4JiZmVnVcYJjZmZmVccJjpmZmVWd3BIcSddIelnSvIKynpKmSfp7uu6RyiXpcknPSnpC0qfyisvMzMyqX54tONcCwxuV/QCYHhG7ANPTNsDngV3SZQwwIce4zMzMrMrlluBExAzglUbFI4Hr0u3rgLqC8usj8xBQI6lPXrGZmZlZdSv1GJytI2Jpur0M2Drd3g54oWC/xanMzMzMrNW6lqviiAhJrV4nQtIYsm4sNtlkk0/vvvvuHR6bmTXvmWeeAWC33XYrcyRmZjB79ux/RETvxuWlTnBektQnIpamLqiXU/kS4OMF+/VNZR8REROBiQADBgyIWbNm5RmvmTVSW1sLQH19fVnjMDMDkLSoqfJSd1HdARyfbh8P3F5Qflw6m+oA4PWCriwzMzOzVsmtBUfSTUAtsKWkxcAFwKXALZJOBhYBX0273w0cATwLvAOcmFdcZmZmVv1yS3Ai4hvN3DWkiX0DOK29da5atYrFixfz3nvvtfepKlafPn2oqakpdxhmZmYVrWyDjPOwePFiNttsM/r164ekcofT4d59912WLFniBMfMzGwdqmqphvfee49evXpVZXID0L17d1atWlXuMMzMzCpeVbXgAJ0muVmwYAHHHXcckujbty833HAD77zzDnV1daxatYrNN9+cm266ic0222zNYzrLazMzMyu3qmrB6Uxqamq46667mDFjBv379+fuu++mW7duTJo0iRkzZjBy5EiuvfbacodpZmbWKVVdC06DAy64t12Pf+iiYc3et2LFCkaNGsXKlSupqalhyJAh3HzzzaxatYrevXtzyy238MILL3DMMcfQ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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap_22['app']\n", + "gap_22 = 100 * df_gap_22['numColdMisses'].astype(float)/(df_gap_22['numTotMisses'].astype(float)+df_gap_22['numTotHits'].astype(float))\n", + "gap_25 = 100 * df_gap_25['numColdMisses'].astype(float)/(df_gap_25['numTotMisses'].astype(float)+df_gap_25['numTotHits'].astype(float))\n", + "\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,100])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_22[i], width=1, color=cmap(1), label='gap-22' if i==0 else None)\n", + " plt.bar(i*3+1, gap_25[i], width=1, color=cmap(2), label='gap-25' if i==0 else None)\n", + "\n", + "offset = 17\n", + "app_npb = df_npb_c['app']\n", + "npb_c = 100 * df_npb_c['numColdMisses'].astype(float)/(df_npb_c['numTotMisses'].astype(float)+df_npb_c['numTotHits'].astype(float))\n", + "npb_d = 100 * df_npb_d['numColdMisses'].astype(float)/(df_npb_d['numTotMisses'].astype(float)+df_npb_d['numTotHits'].astype(float))\n", + "\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_c[i], width=1, color=cmap(3), label='npb-C' if i==0 else None)\n", + " plt.bar(offset+i*3+2, npb_d[i], width=1, color=cmap(4), label='npb-D' if i==0 else None)\n", + "\n", + "plt.figtext(0.3, 0.01, \"GAPBS\")\n", + "plt.figtext(0.75, 0.01, \"NPB\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "\n", + "plt.ylabel(\"cold miss ratio %\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_bips.pdf\")\n", + "\n", + "print(gap_22)\n", + "print(gap_25)\n", + "print(npb_c)\n", + "print(npb_d)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 8.510806\n", + "1 3.012487\n", + "2 0.045814\n", + "3 0.001406\n", + "4 0.867148\n", + "5 23.142106\n", + "dtype: float64\n", + "0 1.868160\n", + "1 0.064662\n", + "2 0.000441\n", + "3 3.308614\n", + "4 5.962230\n", + "5 10.727102\n", + "dtype: float64\n", + "0 0.466393\n", + "1 0.000634\n", + "2 18.562396\n", + "3 13.471984\n", + "4 3.162869\n", + "5 13.837872\n", + "6 2.085634\n", + "7 0.011461\n", + "dtype: float64\n", + "0 9.366265\n", + "1 9.372335\n", + "2 NaN\n", + "3 19.375005\n", + "4 7.491977\n", + "5 7.667257\n", + "6 9.246283\n", + "7 NaN\n", + "dtype: float64\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAACUCAYAAACeNFNKAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAc4ElEQVR4nO3de7yUZbn/8c9XQElFFyAqSgqeNTUtMpHUJYiQGqwOVJ5PhZmm5jbL3d4e2vr7ye4gqG0SyzymmQIeMo20FYlogoqgaKnAFgSlPJ8A8dp/PPfCYbnWYtbhmZk1fN+v17xmnnuemfua07OudT/3QRGBmZmZWTVZr9wBmJmZmXU0JzhmZmZWdZzgmJmZWdVxgmNmZmZVxwmOmZmZVR0nOGZmZlZ1cktwJF0t6WVJcwvKekmaKukf6bpnKpekyyQ9K+kJSZ/KKy4zMzOrfnm24FwDjGhU9gPgvojYEbgvbQN8HtgxXcYAE3KMy8zMzKpcbglOREwDXmlUPAq4Nt2+FqgrKL8uMg8BNZL65hWbmZmZVbdS98HZIiKWpNtLgS3S7a2BFwr2W5TKzMzMzFqta7kqjoiQ1Op1IiSNITuNxUYbbfTpXXbZpcNjM7PWeeaZZwDYeeedyxyJma1rZs2a9c+I6NO4vNQJzkuS+kbEknQK6uVUvhj4eMF+/VLZR0TERGAiwMCBA2PmzJl5xmtmRaitrQWgvr6+rHGY2bpH0sKmykt9iuoO4Lh0+zjg9oLyY9Noqn2B1wtOZZmZmZm1Sm4tOJJuAmqBzSQtAs4HLgFukXQSsBD4atr9buBQ4FngHeCEvOIyMzOz6pdbghMRRzRz19Am9g3g1PbWuXLlShYtWsR7773X3qeqWH379qWmpqbcYZiZmVW0snUyzsOiRYvo0aMH/fv3R1K5w+lw7777LosXL3aCY2ZmthZVtVTDe++9R+/evasyuQHo3r07K1euLHcYZmZmFa+qWnCATpPczJ8/n2OPPRZJ9OvXj+uvv5533nmHuro6Vq5cySabbMJNN91Ejx49Vj+ms7w2MzOzcquqFpzOpKamhrvuuotp06YxYMAA7r77brp168YNN9zAtGnTGDVqFNdcc025wzQzM+uUqq4Fp8G+59/brsc/dOHwZu9bvnw5o0ePZsWKFdTU1DB06FBuvvlmVq5cSZ8+fbjlllt44YUXOOqoo+jduzcvv/wyN910EwMGDFj9HD179lx9u1u3bnTp0oXu3bvTt2/f1WU+HWVmZtY2RbfgSPqCpHpJD0n6dp5BVbopU6aw3377cc8999CzZ0+6du26ujVm11135f777wfglVdeYdKkSYwfP56xY8c2+VwvvvgiU6dO5ZBDDlld9tZbb3HllVdy5JFHluT1mJmZVZtmExxJezUqOgY4CNgPOCXHmCre/Pnz2XPPPQHYa6+9ePvttznppJM48MADufXWW3nxxRcB2GOPPejatSt77bUXzz77LFOnTqW2tpYzzzwTyFqCjjvuOK666iq6ds0a0yKCE088kYsvvtijpczMzNqopRacUyRdJWnLtP0C8B/AucCLuUdWwQYMGMCcOXMAeOKJJ1i+fDk77bQTf/nLX/jyl79MNq0PzJ07l1WrVjF79my23357hg0bRn19PePGjQNgzJgxnHrqqey2226rn/u8885j8ODBDBkypOSvy8zMrFo0m+BExMnAFcCVks4DzgNmAHOAkaUJrzLV1dUxffp0hg8fztKlS9lss8244447OPzww1mwYMHq/TbffHPq6uo4/fTTOeecc9Z4jhkzZjBp0iTGjRtHbW0tkydP5sUXX2Ts2LFMnjyZ2tpaJkyYUOJXZmZmVh1a7GQcEbOBUZK+QLZu1HURcV1JImunljoJt9cGG2zApEmT6Nq1K6eccgo77bQTjz766Br7LFiwgH79+nHDDTc0+RyDBg3izTff/Ej5ihUrconZzMxsXdJSH5xvSXpQ0oPARsAIoEbSvZIOKFmEFeqwww5j8ODBvPPOOwwaNKjc4ZiZmVmBllpwvh0Re0raAHgwIm4GLpN0PfCfwLS2Virpu8A3gCA75XUC0Be4GegNzAKOiYiKbc64996Wh6H379+/2dYbMzMzy1dLnYwXS/p3smTm6YbCiHg1Is5qa4WStgZOBwZGxO5AF+DrwFjg0ojYAXgVOKmtdZiZmdm6raUEZxRZ68oDwLEdXG9X4GOSugIbAkuAIcCt6f5rgboOrtPMzMzWEc2eokqnh+7s6AojYrGknwD/C7wL/JHslNRrEfF+2m0RsHVH121mZmbrhpKvRSWpJ1nr0ABgKz7swFzs48dImilp5rJly3KKMn/z589n//3354ADDuDII49k1apVAOy8887U1tZSW1vLU089VeYozczMOqdyLLZ5MDA/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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap_22_2['app']\n", + "gap_22 = 100 * df_gap_22_2['numColdMisses'].astype(float)/(df_gap_22_2['numTotMisses'].astype(float)+df_gap_22_2['numTotHits'].astype(float))\n", + "gap_25 = 100 * df_gap_25_2['numColdMisses'].astype(float)/(df_gap_25_2['numTotMisses'].astype(float)+df_gap_25_2['numTotHits'].astype(float))\n", + "\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,100])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_22[i], width=1, color=cmap(1), label='gap-22' if i==0 else None)\n", + " plt.bar(i*3+1, gap_25[i], width=1, color=cmap(2), label='gap-25' if i==0 else None)\n", + "\n", + "offset = 17\n", + "app_npb = df_npb_c_2['app']\n", + "npb_c = 100 * df_npb_c_2['numColdMisses'].astype(float)/(df_npb_c_2['numTotMisses'].astype(float)+df_npb_c_2['numTotHits'].astype(float))\n", + "npb_d = 100 * df_npb_d_2['numColdMisses'].astype(float)/(df_npb_d_2['numTotMisses'].astype(float)+df_npb_d_2['numTotHits'].astype(float))\n", + "\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_c[i], width=1, color=cmap(3), label='npb-C' if i==0 else None)\n", + " plt.bar(offset+i*3+2, npb_d[i], width=1, color=cmap(4), label='npb-D' if i==0 else None)\n", + "\n", + "plt.figtext(0.3, 0.01, \"GAPBS\")\n", + "plt.figtext(0.75, 0.01, \"NPB\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "\n", + "plt.ylabel(\"cold miss ratio %\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_bips.pdf\")\n", + "\n", + "print(gap_22)\n", + "print(gap_25)\n", + "print(npb_c)\n", + "print(npb_d)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/configs-drtrace/drtrace.py b/configs-drtrace/drtrace.py new file mode 100644 index 0000000000..aad1d2e6f5 --- /dev/null +++ b/configs-drtrace/drtrace.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2019 The Regents of the University of California. +# All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power, Ayaz Akram + + +import argparse +import time +import m5 +import m5.ticks +from m5.objects import * + +from system import * + +supported_protocols = ["MESI_Two_Level"] + +def parse_options(): + + parser = argparse.ArgumentParser(description='For use with gem5.') + + parser.add_argument("num_cpus", type=int, help="Number of CPU cores") + parser.add_argument("workload", help="The google trace workload to run") + + return parser.parse_args() + +if __name__ == "__m5_main__": + args = parse_options() + + # create the system we are going to simulate + system = MyRubySystem("MESI_Two_Level", args.num_cpus, args) + + # set up the root SimObject and start the simulation + root = Root(full_system = True, system = system) + + # instantiate all of the objects we've created above + m5.instantiate() + + exit_event = m5.simulate(1000*1000000) diff --git a/configs-drtrace/drtrace_new.py b/configs-drtrace/drtrace_new.py new file mode 100644 index 0000000000..feed6b006f --- /dev/null +++ b/configs-drtrace/drtrace_new.py @@ -0,0 +1,88 @@ +import m5 +import argparse +from m5.objects import * +from system import * + +""" +Usage: +------ + +``` +./build/X86/gem5.opt \ + drtrace.py \ + --path \ + --workload \ + --players \ + --dram +``` +""" + +parser = argparse.ArgumentParser( + description="A script to run google traces." +) + +benchmark_choices = ["charlie", "delta", "merced", "whiskey"] + +parser.add_argument( + "path", + type=str, + help="Main directory containing the traces.", +) + +parser.add_argument( + "workload", + type=str, + help="Input the benchmark program to execute.", + choices=benchmark_choices, +) + +parser.add_argument( + "players", + type=int, + help="Input the number of players to use.", +) + +parser.add_argument( + "dcache_policy", + type=str, + help="The architecture of DRAM cache: " + "CascadeLakeNoPartWrs, Oracle, BearWriteOpt, Rambus", +) +parser.add_argument( + "assoc", + type=int, + help="THe associativity of the DRAM cache", +) +parser.add_argument( + "dcache_size", + type=str, + help="The size of DRAM cache", +) +parser.add_argument( + "main_mem_size", + type=str, + help="The size of main memory", +) +parser.add_argument( + "is_link", + type=int, + help="whether to use a link for backing store or not", +) +parser.add_argument( + "link_lat", + type=str, + help="latency of the link to backing store" +) + +args = parser.parse_args() + +#system = System() +system = MyRubySystem("MESI_Two_Level", args.players, args.assoc, args.dcache_size, args.main_mem_size, args.dcache_policy, args.is_link, args.link_lat, args) + +root = Root(full_system=True, system=system) + +m5.instantiate() + +print("Beginning simulation!") +exit_event = m5.simulate(100000000000) +print(f"Exiting @ tick {m5.curTick()} because {exit_event.getCause()}") diff --git a/configs-drtrace/system/MESI_Two_Level.py b/configs-drtrace/system/MESI_Two_Level.py new file mode 100755 index 0000000000..c8cd7d218f --- /dev/null +++ b/configs-drtrace/system/MESI_Two_Level.py @@ -0,0 +1,312 @@ +#Copyright (c) 2020 The Regents of the University of California. +#All Rights Reserved +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + + +""" This file creates a set of Ruby caches for the MESI TWO Level protocol +This protocol models two level cache hierarchy. The L1 cache is split into +instruction and data cache. + +This system support the memory size of up to 3GB. + +""" + +import math + +from m5.defines import buildEnv +from m5.util import fatal, panic + +from m5.objects import * + +class MESITwoLevelCache(RubySystem): + + def __init__(self): + if buildEnv['PROTOCOL'] != 'MESI_Two_Level': + fatal("This system assumes MESI_Two_Level!") + + super(MESITwoLevelCache, self).__init__() + + self._numL2Caches = 8 + + def setup(self, system, cpus, mem_ctrls): + """Set up the Ruby cache subsystem. Note: This can't be done in the + constructor because many of these items require a pointer to the + ruby system (self). This causes infinite recursion in initialize() + if we do this in the __init__. + """ + # Ruby's global network. + self.network = MyNetwork(self) + + # MESI_Two_Level example uses 5 virtual networks + self.number_of_virtual_networks = 5 + self.network.number_of_virtual_networks = 5 + + # There is a single global list of all of the controllers to make it + # easier to connect everything to the global network. This can be + # customized depending on the topology/network requirements. + # L1 caches are private to a core, hence there are one L1 cache per CPU + # core. The number of L2 caches are dependent to the architecture. + self.controllers = \ + [L1Cache(system, self, cpu, self._numL2Caches) for cpu in cpus] + \ + [L2Cache(system, self, self._numL2Caches) for num in \ + range(self._numL2Caches)] + \ + [DirController(self, system.mem_ranges, mem_ctrls)] + + # Create one sequencer per CPU and dma controller. + # Sequencers for other controllers can be here here. + self.sequencers = [RubySequencer(version = i, + # Grab dcache from ctrl + dcache = self.controllers[i].L1Dcache, + clk_domain = self.controllers[i].clk_domain, + ) for i in range(len(cpus))] + + for i,c in enumerate(self.controllers[:len(cpus)]): + c.sequencer = self.sequencers[i] + + self.num_of_sequencers = len(self.sequencers) + + # Create the network and connect the controllers. + # NOTE: This is quite different if using Garnet! + self.network.connectControllers(self.controllers) + self.network.setup_buffers() + + # Set up a proxy port for the system_port. Used for load binaries and + # other functional-only things. + self.sys_port_proxy = RubyPortProxy() + system.system_port = self.sys_port_proxy.in_ports + + # Connect the cpu's cache, interrupt, and TLB ports to Ruby + for i,cpu in enumerate(cpus): + cpu.port = self.sequencers[i].in_ports + +class L1Cache(L1Cache_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, system, ruby_system, cpu, num_l2Caches): + """Creating L1 cache controller. Consist of both instruction + and data cache. The size of data cache is 512KB and + 8-way set associative. The instruction cache is 32KB, + 2-way set associative. + """ + super(L1Cache, self).__init__() + + self.version = self.versionCount() + block_size_bits = int(math.log(system.cache_line_size, 2)) + l1i_size = '32kB' + l1i_assoc = '2' + l1d_size = '512kB' + l1d_assoc = '8' + # This is the cache memory object that stores the cache data and tags + self.L1Icache = RubyCache(size = l1i_size, + assoc = l1i_assoc, + start_index_bit = block_size_bits , + is_icache = True) + self.L1Dcache = RubyCache(size = l1d_size, + assoc = l1d_assoc, + start_index_bit = block_size_bits, + is_icache = False) + self.l2_select_num_bits = int(math.log(num_l2Caches , 2)) + self.clk_domain = cpu.clk_domain + self.prefetcher = RubyPrefetcher() + self.send_evictions = self.sendEvicts(cpu) + self.transitions_per_cycle = 4 + self.enable_prefetch = False + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def getBlockSizeBits(self, system): + bits = int(math.log(system.cache_line_size, 2)) + if 2**bits != system.cache_line_size.value: + panic("Cache line size not a power of 2!") + return bits + + def sendEvicts(self, cpu): + """True if the CPU model or ISA requires sending evictions from caches + to the CPU. Two scenarios warrant forwarding evictions to the CPU: + 1. The O3 model must keep the LSQ coherent with the caches + 2. The x86 mwait instruction is built on top of coherence + 3. The local exclusive monitor in ARM systems + """ + if type(cpu) is DerivO3CPU: + return True + return False + + def connectQueues(self, ruby_system): + """Connect all of the queues for this controller. + """ + self.mandatoryQueue = MessageBuffer() + self.requestFromL1Cache = MessageBuffer() + self.requestFromL1Cache.out_port = ruby_system.network.in_port + self.responseFromL1Cache = MessageBuffer() + self.responseFromL1Cache.out_port = ruby_system.network.in_port + self.unblockFromL1Cache = MessageBuffer() + self.unblockFromL1Cache.out_port = ruby_system.network.in_port + + self.optionalQueue = MessageBuffer() + + self.requestToL1Cache = MessageBuffer() + self.requestToL1Cache.in_port = ruby_system.network.out_port + self.responseToL1Cache = MessageBuffer() + self.responseToL1Cache.in_port = ruby_system.network.out_port + +class L2Cache(L2Cache_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, system, ruby_system, num_l2Caches): + + super(L2Cache, self).__init__() + + self.version = self.versionCount() + # This is the cache memory object that stores the cache data and tags + self.L2cache = RubyCache(size = '1 MB', + assoc = 16, + start_index_bit = self.getBlockSizeBits(system, + num_l2Caches)) + + self.transitions_per_cycle = '4' + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def getBlockSizeBits(self, system, num_l2caches): + l2_bits = int(math.log(num_l2caches, 2)) + bits = int(math.log(system.cache_line_size, 2)) + l2_bits + return bits + + + def connectQueues(self, ruby_system): + """Connect all of the queues for this controller. + """ + self.DirRequestFromL2Cache = MessageBuffer() + self.DirRequestFromL2Cache.out_port = ruby_system.network.in_port + self.L1RequestFromL2Cache = MessageBuffer() + self.L1RequestFromL2Cache.out_port = ruby_system.network.in_port + self.responseFromL2Cache = MessageBuffer() + self.responseFromL2Cache.out_port = ruby_system.network.in_port + self.unblockToL2Cache = MessageBuffer() + self.unblockToL2Cache.in_port = ruby_system.network.out_port + self.L1RequestToL2Cache = MessageBuffer() + self.L1RequestToL2Cache.in_port = ruby_system.network.out_port + self.responseToL2Cache = MessageBuffer() + self.responseToL2Cache.in_port = ruby_system.network.out_port + + +class DirController(Directory_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, ruby_system, ranges, mem_ctrls): + """ranges are the memory ranges assigned to this controller. + """ + if len(mem_ctrls) > 1: + panic("This cache system can only be connected to one mem ctrl") + super(DirController, self).__init__() + self.version = self.versionCount() + self.addr_ranges = ranges + self.ruby_system = ruby_system + self.directory = RubyDirectoryMemory() + # Connect this directory to the memory side. + self.memory_out_port = mem_ctrls[0].port + self.connectQueues(ruby_system) + + def connectQueues(self, ruby_system): + self.requestToDir = MessageBuffer() + self.requestToDir.in_port = ruby_system.network.out_port + self.responseToDir = MessageBuffer() + self.responseToDir.in_port = ruby_system.network.out_port + self.responseFromDir = MessageBuffer() + self.responseFromDir.out_port = ruby_system.network.in_port + self.requestToMemory = MessageBuffer() + self.responseFromMemory = MessageBuffer() + +class DMAController(DMA_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, ruby_system): + super(DMAController, self).__init__() + self.version = self.versionCount() + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def connectQueues(self, ruby_system): + self.mandatoryQueue = MessageBuffer() + self.responseFromDir = MessageBuffer(ordered = True) + self.responseFromDir.in_port = ruby_system.network.out_port + self.requestToDir = MessageBuffer() + self.requestToDir.out_port = ruby_system.network.in_port + + +class MyNetwork(SimpleNetwork): + """A simple point-to-point network. This doesn't not use garnet. + """ + + def __init__(self, ruby_system): + super(MyNetwork, self).__init__() + self.netifs = [] + self.ruby_system = ruby_system + + def connectControllers(self, controllers): + """Connect all of the controllers to routers and connec the routers + together in a point-to-point network. + """ + # Create one router/switch per controller in the system + self.routers = [Switch(router_id = i) for i in range(len(controllers))] + + # Make a link from each controller to the router. The link goes + # externally to the network. + self.ext_links = [SimpleExtLink(link_id=i, ext_node=c, + int_node=self.routers[i]) + for i, c in enumerate(controllers)] + + # Make an "internal" link (internal to the network) between every pair + # of routers. + link_count = 0 + self.int_links = [] + for ri in self.routers: + for rj in self.routers: + if ri == rj: continue # Don't connect a router to itself! + link_count += 1 + self.int_links.append(SimpleIntLink(link_id = link_count, + src_node = ri, + dst_node = rj)) diff --git a/configs-drtrace/system/MI_example_caches.py b/configs-drtrace/system/MI_example_caches.py new file mode 100755 index 0000000000..3c7a71d7b1 --- /dev/null +++ b/configs-drtrace/system/MI_example_caches.py @@ -0,0 +1,275 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2015 Jason Power +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Power + +""" This file creates a set of Ruby caches, the Ruby network, and a simple +point-to-point topology. +See Part 3 in the Learning gem5 book: learning.gem5.org/book/part3 +You can change simple_ruby to import from this file instead of from msi_caches +to use the MI_example protocol instead of MSI. + +IMPORTANT: If you modify this file, it's likely that the Learning gem5 book + also needs to be updated. For now, email Jason + +""" + +import math + +from m5.defines import buildEnv +from m5.util import fatal, panic + +from m5.objects import * + +class MIExampleSystem(RubySystem): + + def __init__(self): + if buildEnv['PROTOCOL'] != 'MI_example': + fatal("This system assumes MI_example!") + + super(MIExampleSystem, self).__init__() + + def setup(self, system, cpus, mem_ctrls, dma_ports, iobus): + """Set up the Ruby cache subsystem. Note: This can't be done in the + constructor because many of these items require a pointer to the + ruby system (self). This causes infinite recursion in initialize() + if we do this in the __init__. + """ + # Ruby's global network. + self.network = MyNetwork(self) + + # MI example uses 5 virtual networks + self.number_of_virtual_networks = 5 + self.network.number_of_virtual_networks = 5 + + # There is a single global list of all of the controllers to make it + # easier to connect everything to the global network. This can be + # customized depending on the topology/network requirements. + # Create one controller for each L1 cache (and the cache mem obj.) + # Create a single directory controller (Really the memory cntrl) + self.controllers = \ + [L1Cache(system, self, cpu) for cpu in cpus] + \ + [DirController(self, system.mem_ranges, mem_ctrls)] + \ + [DMAController(self) for i in range(len(dma_ports))] + + # Create one sequencer per CPU. In many systems this is more + # complicated since you have to create sequencers for DMA controllers + # and other controllers, too. + self.sequencers = [RubySequencer(version = i, + # Grab dcache from ctrl + dcache = self.controllers[i].cacheMemory, + clk_domain = self.controllers[i].clk_domain, + pio_request_port = iobus.cpu_side_ports, + mem_request_port = iobus.cpu_side_ports, + pio_response_port = iobus.mem_side_ports + ) for i in range(len(cpus))] + \ + [DMASequencer(version = i, + in_ports = port) + for i,port in enumerate(dma_ports) + ] + + for i,c in enumerate(self.controllers[0:len(cpus)]): + c.sequencer = self.sequencers[i] + + for i,d in enumerate(self.controllers[-len(dma_ports):]): + i += len(cpus) + d.dma_sequencer = self.sequencers[i] + + self.num_of_sequencers = len(self.sequencers) + + # Create the network and connect the controllers. + # NOTE: This is quite different if using Garnet! + self.network.connectControllers(self.controllers) + self.network.setup_buffers() + + # Set up a proxy port for the system_port. Used for load binaries and + # other functional-only things. + self.sys_port_proxy = RubyPortProxy() + system.system_port = self.sys_port_proxy.in_ports + self.sys_port_proxy.pio_request_port = iobus.cpu_side_ports + + # Connect the cpu's cache, interrupt, and TLB ports to Ruby + for i,cpu in enumerate(cpus): + cpu.icache_port = self.sequencers[i].in_ports + cpu.dcache_port = self.sequencers[i].in_ports + cpu.createInterruptController() + isa = buildEnv['TARGET_ISA'] + if isa == 'x86': + cpu.interrupts[0].pio = self.sequencers[i].interrupt_out_port + cpu.interrupts[0].int_requestor = self.sequencers[i].in_ports + cpu.interrupts[0].int_responder = self.sequencers[i].interrupt_out_port + if isa == 'x86' or isa == 'arm': + cpu.mmu.connectWalkerPorts( + self.sequencers[i].in_ports, self.sequencers[i].in_ports) + +class L1Cache(L1Cache_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, system, ruby_system, cpu): + """CPUs are needed to grab the clock domain and system is needed for + the cache block size. + """ + super(L1Cache, self).__init__() + + self.version = self.versionCount() + # This is the cache memory object that stores the cache data and tags + self.cacheMemory = RubyCache(size = '16kB', + assoc = 8, + start_index_bit = self.getBlockSizeBits(system)) + self.clk_domain = cpu.clk_domain + self.send_evictions = self.sendEvicts(cpu) + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def getBlockSizeBits(self, system): + bits = int(math.log(system.cache_line_size, 2)) + if 2**bits != system.cache_line_size.value: + panic("Cache line size not a power of 2!") + return bits + + def sendEvicts(self, cpu): + """True if the CPU model or ISA requires sending evictions from caches + to the CPU. Two scenarios warrant forwarding evictions to the CPU: + 1. The O3 model must keep the LSQ coherent with the caches + 2. The x86 mwait instruction is built on top of coherence + 3. The local exclusive monitor in ARM systems + """ + if type(cpu) is DerivO3CPU or \ + buildEnv['TARGET_ISA'] in ('x86', 'arm'): + return True + return False + + def connectQueues(self, ruby_system): + """Connect all of the queues for this controller. + """ + self.mandatoryQueue = MessageBuffer() + self.requestFromCache = MessageBuffer(ordered = True) + self.requestFromCache.out_port = ruby_system.network.in_port + self.responseFromCache = MessageBuffer(ordered = True) + self.responseFromCache.out_port = ruby_system.network.in_port + self.forwardToCache = MessageBuffer(ordered = True) + self.forwardToCache.in_port = ruby_system.network.out_port + self.responseToCache = MessageBuffer(ordered = True) + self.responseToCache.in_port = ruby_system.network.out_port + +class DirController(Directory_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, ruby_system, ranges, mem_ctrls): + """ranges are the memory ranges assigned to this controller. + """ + if len(mem_ctrls) > 1: + panic("This cache system can only be connected to one mem ctrl") + super(DirController, self).__init__() + self.version = self.versionCount() + self.addr_ranges = ranges + self.ruby_system = ruby_system + self.directory = RubyDirectoryMemory() + # Connect this directory to the memory side. + self.memory_out_port = mem_ctrls[0].port + self.connectQueues(ruby_system) + + def connectQueues(self, ruby_system): + self.requestToDir = MessageBuffer(ordered = True) + self.requestToDir.in_port = ruby_system.network.out_port + self.dmaRequestToDir = MessageBuffer(ordered = True) + self.dmaRequestToDir.in_port = ruby_system.network.out_port + + self.responseFromDir = MessageBuffer() + self.responseFromDir.out_port = ruby_system.network.in_port + self.dmaResponseFromDir = MessageBuffer(ordered = True) + self.dmaResponseFromDir.out_port = ruby_system.network.in_port + self.forwardFromDir = MessageBuffer() + self.forwardFromDir.out_port = ruby_system.network.in_port + self.requestToMemory = MessageBuffer() + self.responseFromMemory = MessageBuffer() + +class DMAController(DMA_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, ruby_system): + super(DMAController, self).__init__() + self.version = self.versionCount() + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def connectQueues(self, ruby_system): + self.mandatoryQueue = MessageBuffer() + self.requestToDir = MessageBuffer() + self.requestToDir.out_port = ruby_system.network.in_port + self.responseFromDir = MessageBuffer(ordered = True) + self.responseFromDir.in_port = ruby_system.network.out_port + + +class MyNetwork(SimpleNetwork): + """A simple point-to-point network. This doesn't not use garnet. + """ + + def __init__(self, ruby_system): + super(MyNetwork, self).__init__() + self.netifs = [] + self.ruby_system = ruby_system + + def connectControllers(self, controllers): + """Connect all of the controllers to routers and connec the routers + together in a point-to-point network. + """ + # Create one router/switch per controller in the system + self.routers = [Switch(router_id = i) for i in range(len(controllers))] + + # Make a link from each controller to the router. The link goes + # externally to the network. + self.ext_links = [SimpleExtLink(link_id=i, ext_node=c, + int_node=self.routers[i]) + for i, c in enumerate(controllers)] + + # Make an "internal" link (internal to the network) between every pair + # of routers. + link_count = 0 + self.int_links = [] + for ri in self.routers: + for rj in self.routers: + if ri == rj: continue # Don't connect a router to itself! + link_count += 1 + self.int_links.append(SimpleIntLink(link_id = link_count, + src_node = ri, + dst_node = rj)) diff --git a/configs-drtrace/system/MOESI_CMP_directory.py b/configs-drtrace/system/MOESI_CMP_directory.py new file mode 100755 index 0000000000..33f9f47e74 --- /dev/null +++ b/configs-drtrace/system/MOESI_CMP_directory.py @@ -0,0 +1,350 @@ +#Copyright (c) 2020 The Regents of the University of California. +#All Rights Reserved +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + + +""" This file creates a set of Ruby caches for the MOESI CMP directory +protocol. +This protocol models two level cache hierarchy. The L1 cache is split into +instruction and data cache. + +This system support the memory size of up to 3GB. + +""" + +from __future__ import print_function +from __future__ import absolute_import + +import math + +from m5.defines import buildEnv +from m5.util import fatal, panic + +from m5.objects import * + +class MOESICMPDirCache(RubySystem): + + def __init__(self): + if buildEnv['PROTOCOL'] != 'MOESI_CMP_directory': + fatal("This system assumes MOESI_CMP_directory!") + + super(MOESICMPDirCache, self).__init__() + + self._numL2Caches = 8 + + def setup(self, system, cpus, mem_ctrls, dma_ports, iobus): + """Set up the Ruby cache subsystem. Note: This can't be done in the + constructor because many of these items require a pointer to the + ruby system (self). This causes infinite recursion in initialize() + if we do this in the __init__. + """ + # Ruby's global network. + self.network = MyNetwork(self) + + # MOESI_CMP_directory example uses 3 virtual networks + self.number_of_virtual_networks = 3 + self.network.number_of_virtual_networks = 3 + + # There is a single global list of all of the controllers to make it + # easier to connect everything to the global network. This can be + # customized depending on the topology/network requirements. + # L1 caches are private to a core, hence there are one L1 cache per CPU + # core. The number of L2 caches are dependent to the architecture. + self.controllers = \ + [L1Cache(system, self, cpu, self._numL2Caches) for cpu in cpus] + \ + [L2Cache(system, self, self._numL2Caches) for num in \ + range(self._numL2Caches)] + [DirController(self, \ + system.mem_ranges, mem_ctrls)] + [DMAController(self) for i \ + in range(len(dma_ports))] + + # Create one sequencer per CPU and dma controller. + # Sequencers for other controllers can be here here. + self.sequencers = [RubySequencer(version = i, + # Grab dcache from ctrl + dcache = self.controllers[i].L1Dcache, + clk_domain = self.controllers[i].clk_domain, + pio_request_port = iobus.cpu_side_ports, + mem_request_port = iobus.cpu_side_ports, + pio_response_port = iobus.mem_side_ports + ) for i in range(len(cpus))] + \ + [DMASequencer(version = i, + in_ports = port) + for i,port in enumerate(dma_ports) + ] + + for i,c in enumerate(self.controllers[:len(cpus)]): + c.sequencer = self.sequencers[i] + + #Connecting the DMA sequencer to DMA controller + for i,d in enumerate(self.controllers[-len(dma_ports):]): + i += len(cpus) + d.dma_sequencer = self.sequencers[i] + + self.num_of_sequencers = len(self.sequencers) + + # Create the network and connect the controllers. + # NOTE: This is quite different if using Garnet! + self.network.connectControllers(self.controllers) + self.network.setup_buffers() + + # Set up a proxy port for the system_port. Used for load binaries and + # other functional-only things. + self.sys_port_proxy = RubyPortProxy() + system.system_port = self.sys_port_proxy.in_ports + self.sys_port_proxy.pio_request_port = iobus.cpu_side_ports + + # Connect the cpu's cache, interrupt, and TLB ports to Ruby + for i,cpu in enumerate(cpus): + cpu.icache_port = self.sequencers[i].in_ports + cpu.dcache_port = self.sequencers[i].in_ports + cpu.createInterruptController() + isa = buildEnv['TARGET_ISA'] + if isa == 'x86': + cpu.interrupts[0].pio = self.sequencers[i].interrupt_out_port + cpu.interrupts[0].int_requestor = self.sequencers[i].in_ports + cpu.interrupts[0].int_responder = self.sequencers[i].interrupt_out_port + if isa == 'x86' or isa == 'arm': + cpu.mmu.connectWalkerPorts( + self.sequencers[i].in_ports, self.sequencers[i].in_ports) + +class L1Cache(L1Cache_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, system, ruby_system, cpu, num_l2Caches): + """Creating L1 cache controller. Consist of both instruction + and data cache. The size of data cache is 512KB and + 8-way set associative. The instruction cache is 32KB, + 2-way set associative. + """ + super(L1Cache, self).__init__() + + self.version = self.versionCount() + block_size_bits = int(math.log(system.cache_line_size, 2)) + l1i_size = '32kB' + l1i_assoc = '2' + l1d_size = '512kB' + l1d_assoc = '8' + # This is the cache memory object that stores the cache data and tags + self.L1Icache = RubyCache(size = l1i_size, + assoc = l1i_assoc, + start_index_bit = block_size_bits , + is_icache = True, + dataAccessLatency = 1, + tagAccessLatency = 1) + self.L1Dcache = RubyCache(size = l1d_size, + assoc = l1d_assoc, + start_index_bit = block_size_bits, + is_icache = False, + dataAccessLatency = 1, + tagAccessLatency = 1) + self.clk_domain = cpu.clk_domain + self.prefetcher = RubyPrefetcher() + self.send_evictions = self.sendEvicts(cpu) + self.transitions_per_cycle = 4 + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def getBlockSizeBits(self, system): + bits = int(math.log(system.cache_line_size, 2)) + if 2**bits != system.cache_line_size.value: + panic("Cache line size not a power of 2!") + return bits + + def sendEvicts(self, cpu): + """True if the CPU model or ISA requires sending evictions from caches + to the CPU. Two scenarios warrant forwarding evictions to the CPU: + 1. The O3 model must keep the LSQ coherent with the caches + 2. The x86 mwait instruction is built on top of coherence + 3. The local exclusive monitor in ARM systems + """ + if type(cpu) is DerivO3CPU or \ + buildEnv['TARGET_ISA'] in ('x86', 'arm'): + return True + return False + + def connectQueues(self, ruby_system): + """Connect all of the queues for this controller. + """ + self.mandatoryQueue = MessageBuffer() + self.requestFromL1Cache = MessageBuffer() + self.requestFromL1Cache.out_port = ruby_system.network.in_port + self.responseFromL1Cache = MessageBuffer() + self.responseFromL1Cache.out_port = ruby_system.network.in_port + self.requestToL1Cache = MessageBuffer() + self.requestToL1Cache.in_port = ruby_system.network.out_port + self.responseToL1Cache = MessageBuffer() + self.responseToL1Cache.in_port = ruby_system.network.out_port + self.triggerQueue = MessageBuffer(ordered = True) + +class L2Cache(L2Cache_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, system, ruby_system, num_l2Caches): + + super(L2Cache, self).__init__() + + self.version = self.versionCount() + # This is the cache memory object that stores the cache data and tags + self.L2cache = RubyCache(size = '1 MB', + assoc = 16, + start_index_bit = self.getL2StartIdx(system, + num_l2Caches), + dataAccessLatency = 20, + tagAccessLatency = 20) + + self.transitions_per_cycle = '4' + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def getL2StartIdx(self, system, num_l2caches): + l2_bits = int(math.log(num_l2caches, 2)) + bits = int(math.log(system.cache_line_size, 2)) + l2_bits + return bits + + + def connectQueues(self, ruby_system): + """Connect all of the queues for this controller. + """ + self.GlobalRequestFromL2Cache = MessageBuffer() + self.GlobalRequestFromL2Cache.out_port = ruby_system.network.in_port + self.L1RequestFromL2Cache = MessageBuffer() + self.L1RequestFromL2Cache.out_port = ruby_system.network.in_port + self.responseFromL2Cache = MessageBuffer() + self.responseFromL2Cache.out_port = ruby_system.network.in_port + + self.GlobalRequestToL2Cache = MessageBuffer() + self.GlobalRequestToL2Cache.in_port = ruby_system.network.out_port + self.L1RequestToL2Cache = MessageBuffer() + self.L1RequestToL2Cache.in_port = ruby_system.network.out_port + self.responseToL2Cache = MessageBuffer() + self.responseToL2Cache.in_port = ruby_system.network.out_port + self.triggerQueue = MessageBuffer(ordered = True) + + + +class DirController(Directory_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, ruby_system, ranges, mem_ctrls): + """ranges are the memory ranges assigned to this controller. + """ + if len(mem_ctrls) > 1: + panic("This cache system can only be connected to one mem ctrl") + super(DirController, self).__init__() + self.version = self.versionCount() + self.addr_ranges = ranges + self.ruby_system = ruby_system + self.directory = RubyDirectoryMemory() + # Connect this directory to the memory side. + self.memory_out_port = mem_ctrls[0].port + self.connectQueues(ruby_system) + + def connectQueues(self, ruby_system): + self.requestToDir = MessageBuffer() + self.requestToDir.in_port = ruby_system.network.out_port + self.responseToDir = MessageBuffer() + self.responseToDir.in_port = ruby_system.network.out_port + self.responseFromDir = MessageBuffer() + self.responseFromDir.out_port = ruby_system.network.in_port + self.forwardFromDir = MessageBuffer() + self.forwardFromDir.out_port = ruby_system.network.in_port + self.requestToMemory = MessageBuffer() + self.responseFromMemory = MessageBuffer() + self.triggerQueue = MessageBuffer(ordered = True) + +class DMAController(DMA_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, ruby_system): + super(DMAController, self).__init__() + self.version = self.versionCount() + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def connectQueues(self, ruby_system): + self.mandatoryQueue = MessageBuffer() + self.responseFromDir = MessageBuffer() + self.responseFromDir.in_port = ruby_system.network.out_port + self.reqToDir = MessageBuffer() + self.reqToDir.out_port = ruby_system.network.in_port + self.respToDir = MessageBuffer() + self.respToDir.out_port = ruby_system.network.in_port + self.triggerQueue = MessageBuffer(ordered = True) + + +class MyNetwork(SimpleNetwork): + """A simple point-to-point network. This doesn't not use garnet. + """ + + def __init__(self, ruby_system): + super(MyNetwork, self).__init__() + self.netifs = [] + self.ruby_system = ruby_system + + def connectControllers(self, controllers): + """Connect all of the controllers to routers and connec the routers + together in a point-to-point network. + """ + # Create one router/switch per controller in the system + self.routers = [Switch(router_id = i) for i in range(len(controllers))] + + # Make a link from each controller to the router. The link goes + # externally to the network. + self.ext_links = [SimpleExtLink(link_id=i, ext_node=c, + int_node=self.routers[i]) + for i, c in enumerate(controllers)] + + # Make an "internal" link (internal to the network) between every pair + # of routers. + link_count = 0 + self.int_links = [] + for ri in self.routers: + for rj in self.routers: + if ri == rj: continue # Don't connect a router to itself! + link_count += 1 + self.int_links.append(SimpleIntLink(link_id = link_count, + src_node = ri, + dst_node = rj)) diff --git a/configs-drtrace/system/__init__.py b/configs-drtrace/system/__init__.py new file mode 100755 index 0000000000..cd2696fb02 --- /dev/null +++ b/configs-drtrace/system/__init__.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2016 Jason Lowe-Power +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power + +from .ruby_system import MyRubySystem diff --git a/configs-drtrace/system/ruby_system.py b/configs-drtrace/system/ruby_system.py new file mode 100755 index 0000000000..ea339b924e --- /dev/null +++ b/configs-drtrace/system/ruby_system.py @@ -0,0 +1,124 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2016 Jason Lowe-Power +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power + +import m5 +from m5.objects import * + + +class MyRubySystem(System): + + def __init__(self, mem_sys, num_cpus, assoc, dcache_size, main_mem_size, policy, is_link, link_lat, opts, restore=False): + super(MyRubySystem, self).__init__() + self._opts = opts + + # Set up the clock domain and the voltage domain + self.clk_domain = SrcClockDomain() + self.clk_domain.clock = '5GHz' + self.clk_domain.voltage_domain = VoltageDomain() + + self.mem_ranges = [AddrRange(Addr(main_mem_size))] + + # self.intrctrl = IntrControl() + self._createMemoryControllers(assoc, dcache_size, policy, is_link, link_lat) + + # Create the cache hierarchy for the system. + if mem_sys == 'MI_example': + from .MI_example_caches import MIExampleSystem + self.caches = MIExampleSystem() + elif mem_sys == 'MESI_Two_Level': + from .MESI_Two_Level import MESITwoLevelCache + self.caches = MESITwoLevelCache() + elif mem_sys == 'MOESI_CMP_directory': + from .MOESI_CMP_directory import MOESICMPDirCache + self.caches = MOESICMPDirCache() + + self.reader = DRTraceReader( + directory=f"/{opts.path}/{opts.workload}/", num_players=num_cpus + ) + + self.players = [ + DRTracePlayer( + reader=self.reader, + send_data=True, + compress_address_range=self.mem_ranges[0], + ) + for _ in range(num_cpus) + ] + + self.caches.setup(self, self.players, self.mem_ctrl) + + self.caches.access_backing_store = True + self.caches.phys_mem = SimpleMemory(range=self.mem_ranges[0], + in_addr_map=False) + + + def _createMemoryControllers(self, assoc, dcache_size, policy, is_link, link_lat): + + self.mem_ctrl = PolicyManager(range=self.mem_ranges[0], kvm_map=False) + self.mem_ctrl.static_frontend_latency = "10ns" + self.mem_ctrl.static_backend_latency = "10ns" + + self.mem_ctrl.loc_mem_policy = policy + + self.mem_ctrl.assoc = assoc + + # self.mem_ctrl.bypass_dcache = True + + # TDRAM cache + self.loc_mem_ctrl = MemCtrl() + self.loc_mem_ctrl.consider_oldest_write = True + self.loc_mem_ctrl.oldest_write_age_threshold = 5000000 + self.loc_mem_ctrl.dram = TDRAM_32(range=self.mem_ranges[0], in_addr_map=False, kvm_map=False) + + + self.mem_ctrl.loc_mem = self.loc_mem_ctrl.dram + self.loc_mem_ctrl.static_frontend_latency = "1ns" + self.loc_mem_ctrl.static_backend_latency = "1ns" + self.loc_mem_ctrl.static_frontend_latency_tc = "0ns" + self.loc_mem_ctrl.static_backend_latency_tc = "0ns" + + # main memory + self.far_mem_ctrl = MemCtrl() + self.far_mem_ctrl.dram = DDR4_2400_16x4(range=self.mem_ranges[0], in_addr_map=False, kvm_map=False) + self.far_mem_ctrl.static_frontend_latency = "1ns" + self.far_mem_ctrl.static_backend_latency = "1ns" + + self.loc_mem_ctrl.port = self.mem_ctrl.loc_req_port + + self.far_mem_ctrl.port = self.mem_ctrl.far_req_port + + self.mem_ctrl.orb_max_size = 128 + self.mem_ctrl.dram_cache_size = dcache_size + + self.loc_mem_ctrl.dram.read_buffer_size = 64 + self.loc_mem_ctrl.dram.write_buffer_size = 64 + + self.far_mem_ctrl.dram.read_buffer_size = 64 + self.far_mem_ctrl.dram.write_buffer_size = 64 + diff --git a/configs-npb-gapbs/gapbs_checkpoint.py b/configs-npb-gapbs/gapbs_checkpoint.py new file mode 100755 index 0000000000..c41abac760 --- /dev/null +++ b/configs-npb-gapbs/gapbs_checkpoint.py @@ -0,0 +1,199 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2019 The Regents of the University of California. +# All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power, Ayaz Akram + +""" Script to run GAP Benchmark suites workloads. + The workloads have two modes: synthetic and real graphs. +""" +import argparse +import time +import m5 +import m5.ticks +from m5.objects import * + +from system import * + +supported_protocols = ["MESI_Two_Level"] +supported_cpu_types = ["kvm", "atomic", "timing"] + + +def writeBenchScript(dir, benchmark_name, size, synthetic): + """ + This method creates a script in dir which will be eventually + passed to the simulated system (to run a specific benchmark + at bootup). + """ + input_file_name = "{}/run_{}_{}".format(dir, benchmark_name, size) + if synthetic: + with open(input_file_name, "w") as f: + f.write("./{} -g {}\n".format(benchmark_name, size)) + elif synthetic == 0: + with open(input_file_name, "w") as f: + # The workloads that are copied to the disk image using Packer + # should be located in /home/gem5/. + # Since the command running the workload will be executed with + # pwd = /home/gem5/gapbs, the path to the copied workload is + # ../{workload-name} + f.write("./{} -sf ../{}".format(benchmark_name, size)) + + return input_file_name + + +def parse_options(): + + parser = argparse.ArgumentParser( + description="For use with gem5. This " + "runs a GAPBS applications. This only works " + "with x86 ISA." + ) + + # The manditry position arguments. + parser.add_argument( + "benchmark", type=str, help="The GAPBS application to run" + ) + parser.add_argument("graph", type=str, help="The GAPBS application to run") + parser.add_argument( + "dcache_policy", + type=str, + help="The architecture of DRAM cache: " + "CascadeLakeNoPartWrs, Oracle, BearWriteOpt, Rambus", + ) + parser.add_argument( + "is_link", + type=int, + help="whether to use a link for backing store or not", + ) + parser.add_argument( + "link_lat", type=str, help="latency of the link to backing store" + ) + return parser.parse_args() + + +if __name__ == "__m5_main__": + args = parse_options() + + kernel = "/home/mbabaie/code-review/dramCacheController/fs-resources/x86-linux-kernel-4.19.83" + disk = ( + "/home/mbabaie/code-review/dramCacheController/fs-resources/x86-gapbs" + ) + num_cpus = 8 + cpu_type = "Timing" + mem_sys = "MESI_Two_Level" + synthetic = 1 + + dcache_size = "" + mem_size = "" + if args.graph == "22": + dcache_size = "1GiB" + mem_size = "8GiB" + elif args.graph == "25": + dcache_size = "1GiB" + mem_size = "85GiB" + assoc = 1 + # create the system we are going to simulate + system = MyRubySystem( + kernel, + disk, + mem_sys, + num_cpus, + assoc, + dcache_size, + mem_size, + args.dcache_policy, + args.is_link, + args.link_lat, + 0, + args, + ) + + system.m5ops_base = 0xFFFF0000 + + # Exit from guest on workbegin/workend + system.exit_on_work_items = True + + # Create and pass a script to the simulated system to run the reuired + # benchmark + system.readfile = writeBenchScript( + m5.options.outdir, args.benchmark, args.graph, synthetic + ) + + # set up the root SimObject and start the simulation + root = Root(full_system=True, system=system) + + if system.getHostParallel(): + # Required for running kvm on multiple host cores. + # Uses gem5's parallel event queue feature + # Note: The simulator is quite picky about this number! + root.sim_quantum = int(1e9) # 1 ms + + # needed for long running jobs + # m5.disableAllListeners() + + # instantiate all of the objects we've created above + m5.instantiate() + + globalStart = time.time() + + print("Running the simulation") + print("Using cpu: {}".format(cpu_type)) + exit_event = m5.simulate() + + if exit_event.getCause() == "workbegin": + print("Done booting Linux") + # Reached the start of ROI + # start of ROI is marked by an + # m5_work_begin() call + print("Resetting stats at the start of ROI!") + m5.stats.reset() + start_tick = m5.curTick() + start_insts = system.totalInsts() + # switching CPU to timing + system.switchCpus(system.cpu, system.timingCpu) + else: + print("Unexpected termination of simulation !") + exit() + + m5.stats.reset() + print( + "After reset ************************************************ statring smiulation:\n" + ) + for interval_number in range(150): + print("Interval number: {} \n".format(interval_number)) + exit_event = m5.simulate(10000000000) + if exit_event.getCause() == "cacheIsWarmedup": + print("Caught cacheIsWarmedup exit event!") + break + print( + "-------------------------------------------------------------------" + ) + + print( + "After sim ************************************************ End of warm-up \n" + ) + m5.stats.dump() + system.switchCpus(system.timingCpu, system.o3Cpu) + m5.checkpoint(m5.options.outdir + "/cpt") diff --git a/configs-npb-gapbs/gapbs_restore.py b/configs-npb-gapbs/gapbs_restore.py new file mode 100755 index 0000000000..4ea8c95bc8 --- /dev/null +++ b/configs-npb-gapbs/gapbs_restore.py @@ -0,0 +1,179 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2019 The Regents of the University of California. +# All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power, Ayaz Akram + +""" Script to run GAP Benchmark suites workloads. + The workloads have two modes: synthetic and real graphs. +""" +import argparse +import time +import m5 +import m5.ticks +from m5.objects import * + +from system import * + +supported_protocols = ["MESI_Two_Level"] +supported_cpu_types = ["kvm", "atomic", "timing"] + + +def writeBenchScript(dir, benchmark_name, size, synthetic): + """ + This method creates a script in dir which will be eventually + passed to the simulated system (to run a specific benchmark + at bootup). + """ + input_file_name = "{}/run_{}_{}".format(dir, benchmark_name, size) + if synthetic: + with open(input_file_name, "w") as f: + f.write("./{} -g {}\n".format(benchmark_name, size)) + elif synthetic == 0: + with open(input_file_name, "w") as f: + # The workloads that are copied to the disk image using Packer + # should be located in /home/gem5/. + # Since the command running the workload will be executed with + # pwd = /home/gem5/gapbs, the path to the copied workload is + # ../{workload-name} + f.write("./{} -sf ../{}".format(benchmark_name, size)) + + return input_file_name + + +def parse_options(): + parser = argparse.ArgumentParser( + description="For use with gem5. This " + "runs a GAPBS applications. This only works " + "with x86 ISA." + ) + + # The manditry position arguments. + parser.add_argument( + "benchmark", type=str, help="The GAPBS application to run" + ) + parser.add_argument("graph", type=str, help="The GAPBS application to run") + parser.add_argument( + "dcache_policy", type=str, help="The architecture of DRAM cache" + ) + parser.add_argument( + "is_link", + type=int, + help="whether to use a link for backing store or not", + ) + parser.add_argument( + "link_lat", type=str, help="latency of the link to backing store" + ) + parser.add_argument( + "checkpoint_path", type=str, help="Path to checkpoint dir" + ) + + return parser.parse_args() + + +if __name__ == "__m5_main__": + args = parse_options() + + kernel = "/home/mbabaie/code-review/dramCacheController/fs-resources/x86-linux-kernel-4.19.83" + disk = ( + "/home/mbabaie/code-review/dramCacheController/fs-resources/x86-gapbs" + ) + num_cpus = 8 + cpu_type = "Timing" + mem_sys = "MESI_Two_Level" + synthetic = 1 + + dcache_size = "" + mem_size = "" + if args.graph == "22": + dcache_size = "512MiB" + mem_size = "8GiB" + elif args.graph == "25": + dcache_size = "512MiB" + mem_size = "85GiB" + + # create the system we are going to simulate + system = MyRubySystem( + kernel, + disk, + mem_sys, + num_cpus, + dcache_size, + mem_size, + args.dcache_policy, + args.is_link, + args.link_lat, + args, + restore=True, + ) + + system.m5ops_base = 0xFFFF0000 + + # Exit from guest on workbegin/workend + system.exit_on_work_items = True + + # Create and pass a script to the simulated system to run the reuired + # benchmark + system.readfile = writeBenchScript( + m5.options.outdir, args.benchmark, args.graph, synthetic + ) + + # set up the root SimObject and start the simulation + root = Root(full_system=True, system=system) + + if system.getHostParallel(): + # Required for running kvm on multiple host cores. + # Uses gem5's parallel event queue feature + # Note: The simulator is quite picky about this number! + root.sim_quantum = int(1e9) # 1 ms + + # needed for long running jobs + m5.disableAllListeners() + + # instantiate all of the objects we've created above + m5.instantiate(args.checkpoint_path) + + globalStart = time.time() + + print("Running the simulation ************************************** \n") + print("Simulating 100 intervals of 10ms each! \n") + + numIteration = 0 + + if args.benchmark == "bfs": + numIteration = 360 + elif args.benchmark == "cc": + numIteration = 280 + elif args.benchmark == "sssp": + numIteration = 160 + else: + numIteration = 100 + + for interval_number in range(numIteration): + print("Interval number: {} \n".format(interval_number)) + exit_event = m5.simulate(10000000000) + m5.stats.dump() + + print("End of simulation ******************************************** \n") diff --git a/configs-npb-gapbs/info.py b/configs-npb-gapbs/info.py new file mode 100644 index 0000000000..7547fb421a --- /dev/null +++ b/configs-npb-gapbs/info.py @@ -0,0 +1,325 @@ +text_info = { + # exe size start + "bt.A.x": (0x00018402, 0x0000000000400E50), + "bt.B.x": (0x000183E2, 0x0000000000400E50), + "bt.C.x": (0x00018342, 0x0000000000400E50), + "bt.D.x": (0x00018562, 0x0000000000400E50), + "cg.A.x": (0x00005D22, 0x0000000000400F60), + "cg.B.x": (0x00005DC2, 0x0000000000400F60), + "cg.C.x": (0x00005E32, 0x0000000000400F60), + "cg.D.x": (0x00005AC2, 0x0000000000400F60), + "ep.A.x": (0x00001E52, 0x0000000000400DB0), + "ep.B.x": (0x00001E52, 0x0000000000400DB0), + "ep.C.x": (0x00001E52, 0x0000000000400DB0), + "ep.D.x": (0x00001E52, 0x0000000000400DB0), + "ft.A.x": (0x00005202, 0x0000000000400F60), + "ft.B.x": (0x00005752, 0x0000000000400F60), + "ft.C.x": (0x00005762, 0x0000000000400F60), + "ft.D.x": (0x00005772, 0x0000000000400F60), + "is.A.x": (0x000020B2, 0x0000000000400BE0), + "is.B.x": (0x000020C2, 0x0000000000400BE0), + "is.C.x": (0x000020B2, 0x0000000000400BE0), + "is.D.x": (0x00001EB2, 0x0000000000400BE0), + "lu.A.x": (0x00016A82, 0x0000000000400F50), + "lu.B.x": (0x00016A52, 0x0000000000400F50), + "lu.C.x": (0x000169C2, 0x0000000000400F50), + "lu.D.x": (0x00016DD2, 0x0000000000400F50), + "mg.A.x": (0x0000B4A2, 0x00000000004010F0), + "mg.B.x": (0x0000B4A2, 0x00000000004010F0), + "mg.C.x": (0x0000B5E2, 0x00000000004010F0), + "mg.D.x": (0x0000B772, 0x00000000004010F0), + "sp.A.x": (0x00014162, 0x0000000000400EB0), + "sp.B.x": (0x00014162, 0x0000000000400EB0), + "sp.C.x": (0x00014052, 0x0000000000400EB0), + "sp.D.x": (0x000141B2, 0x0000000000400EB0), + "ua.A.x": (0x000274E2, 0x00000000004010C0), + "ua.B.x": (0x00027612, 0x00000000004010C0), + "ua.C.x": (0x00027552, 0x00000000004010C0), + "ua.D.x": (0x000274C2, 0x00000000004010C0), + "bc-22": (0x0000EFD2, 0x00000000004029F0), + "bfs-22": (0x0000DCF2, 0x00000000004028A0), + "cc-22": (0x0000E4C2, 0x0000000000402BE0), + "cc_sv-22": (0x0000DF12, 0x0000000000402970), + "pr-22": (0x0000E022, 0x0000000000402A10), + "sssp-22": (0x0000E692, 0x00000000004029C0), + "tc-22": (0x0000DEE2, 0x0000000000402890), + "bc-25": (0x0000EFD2, 0x00000000004029F0), + "bfs-25": (0x0000DCF2, 0x00000000004028A0), + "cc-25": (0x0000E4C2, 0x0000000000402BE0), + "cc_sv-25": (0x0000DF12, 0x0000000000402970), + "pr-25": (0x0000E022, 0x0000000000402A10), + "sssp-25": (0x0000E692, 0x00000000004029C0), + "tc-25": (0x0000DEE2, 0x0000000000402890), +} + +interval_info_1hr = { + # exe pc count + "bc-22": (0x404E08, 5409997), + "bfs-22": (0x403790, 3930710), + "bt.C.x": (0x4080E0, 1270955), + "cc-22": (0x4037B0, 8388093), + "cg.C.x": (0x4019D8, 29870850), + "pr-22": (0x4036C0, 25174574), + "ft.C.x": (0x400D70, 6760163), + "ua.C.x": (0x406B00, 344413), + "mg.C.x": (0x401B08, 4467087), + "sp.C.x": (0x409170, 1569121), + "lu.C.x": (0x402980, 5146555), + "is.C.x": (0x4017C9, 48480186), + "tc-22": (0x4052E0, 240202), + "sssp-22": (0x405441, 12651169), + "bc-25": (0x404E1A, 2192896), + "bfs-25": (0x4038E0, 11170933), + "bt.D.x": (0x407FD0, 3729824), + "cc-25": (0x404688, 6506055), + "cg.D.x": (0x4019D8, 17675668), + "pr-25": (0x4036C0, 19663604), + "ft.D.x": (0x400D70, 6498319), + "ua.D.x": (0x400F30, 2709903), + "mg.D.x": (0x401920, 3670463), + "sp.D.x": (0x409000, 3786010), + "lu.D.x": (0x402600, 116), + "is.D.x": (0x401661, 42645519), + "tc-25": (0x4030A0, 5800667), + "sssp-25": (0x405418, 979358), +} + +interval_info_3hr = { + # exe pc count + "bc-22": (0x404E08, 14968517), + "bfs-22": (0x403790, 12277309), + "bt.C.x": (0x408600, 1906919), + "cc-22": (0x404238, 5701575), + "cg.C.x": (0x4019D8, 73121983), + "pr-22": (0x4036C0, 69152771), + "ft.C.x": (0x400D70, 16530458), + "ua.C.x": (0x41D080, 4205282), + "mg.C.x": (0x401920, 12053283), + "sp.C.x": (0x409668, 2192349), + "lu.C.x": (0x402980, 9952905), + "is.C.x": (0x401955, 12922496), + "tc-22": (0x4034E0, 1507255), + "sssp-22": (0x405441, 33740179), + "bc-25": (0x404E08, 6310746), + "bfs-25": (0x4045D0, 2021755), + "bt.D.x": (0x407FD0, 10661006), + "cc-25": (0x4037B0, 31963857), + "cg.D.x": (0x4019D8, 45636549), + "pr-25": (0x4036C0, 51691344), + "ft.D.x": (0x400D70, 13065409), + "ua.D.x": (0x400F30, 8415248), + "mg.D.x": (0x401920, 11871798), + "sp.D.x": (0x409000, 9962530), + "lu.D.x": (0x4027F8, 32448), + "is.D.x": (0x401661, 119913839), + "tc-25": (0x4030A0, 30335985), + "sssp-25": (0x405441, 19973164), +} + +interval_info_6hr = { + # exe pc count + "bc-22": (0x404E08, 29440776), + "bfs-22": (0x4045D0, 3029875), + "bt.C.x": (0x409A20, 1173559), + "cc-22": (0x4037B0, 33552375), + "cg.C.x": (0x4019D8, 148363776), + "pr-22": (0x4036C0, 138691628), + "ft.C.x": (0x400D70, 30067439), + "ua.C.x": (0x405757, 134017), + "mg.C.x": (0x401920, 23222866), + "sp.C.x": (0x40AA60, 1691001), + "lu.C.x": (0x402980, 9952905), + "is.C.x": (0x401955, 79966814), + "tc-22": (0x405800, 516587), + "sssp-22": (0x405441, 67113550), + "bc-25": (0x404E08, 12151937), + "bfs-25": (0x403790, 8317180), + "bt.D.x": (0x407FD0, 21901834), + "cc-25": (0x404238, 32589977), + "cg.D.x": (0x4019D8, 91326969), + "pr-25": (0x4036C0, 99790518), + "ft.D.x": (0x400D70, 26209008), + "ua.D.x": (0x400F30, 13977417), + "mg.D.x": (0x401B08, 24048507), + "sp.D.x": (0x409000, 19860707), + "lu.D.x": (0x4027F8, 100054), + "is.D.x": (0x401661, 241880887), + "tc-25": (0x40CA70, 19083641), + "sssp-25": (0x405441, 42573632), +} + +interval_info_12hr = { + # exe pc count + "bc-22": (0x4036F0, 48778942), + "bfs-22": (0x403790, 54892278), + "bt.C.x": (0x40BF58, 611768), + "cc-22": (0x404688, 39592660), + "cg.C.x": (0x4019D8, 294906202), + "pr-22": (0x4036C0, 271266245), + "ft.C.x": (0x400D70, 56313323), + "ua.C.x": (0x41DCA0, 21222925), + "mg.C.x": (0x401B08, 45327484), + "sp.C.x": (0x40CFA0, 1219582), + "lu.C.x": (0x405C00, 72382), + "is.C.x": (0x401AF0, 129738785), + "tc-22": (0x4054A0, 87026806), + "sssp-22": (0x405441, 89183250), + "bc-25": (0x404E08, 25995768), + "bfs-25": (0x4038E0, 36114591), + "bt.D.x": (0x407FD0, 44658580), + "cc-25": (0x404688, 31320744), + "cg.D.x": (0x4019D8, 19366202), + "pr-25": (0x4036C0, 204816690), + "ft.D.x": (0x401C10, 56461566), + "ua.D.x": (0x4044C4, 6852508), + "mg.D.x": (0x401B08, 47676346), + "sp.D.x": (0x409000, 39454655), + "lu.D.x": (0x4029A0, 10268832), + "is.D.x": (0x401661, 481770516), + "tc-25": (0x40CA70, 19083641), + "sssp-25": (0x405441, 89681018), +} + +interval_info_24hr = { + # exe pc count + "bt.C.x": (0x40D230, 2377023), + "cg.C.x": (0x4019D8, 578428198), + "ft.C.x": (0x405830, 58382196), + "is.C.x": (0x401AF0, 184476965), + "lu.C.x": (0x40D4C0, 1146276), + "mg.C.x": (0x4012F8, 121010179), + "sp.C.x": (0x40EEE8, 3428040), + "ua.C.x": (0x41DCA0, 39733523), + "bc-22": (0x404E1A, 11556233), + "bfs-22": (0x401028, 65), + "cc-22": (0x404238, 39015034), + "pr-22": (0x4036C0, 530256860), + "tc-22": (0x405390, 7008077), + "sssp-22": (0x4054A0, 212570793), + "bc-25": (0x404E08, 44535390), + "bfs-25": (0x403988, 87740083), + "bt.D.x": (0x407FD0, 53208177), + "cc-25": (0x4037B0, 133906775), + "cg.D.x": (0x4019D8, 351587199), + "pr-25": (0x4036C0, 401728224), + "ft.D.x": (0x400D70, 110793818), + "ua.D.x": (0x4039C4, 12695182), ### + "mg.D.x": (0x401B08, 75633571), + "sp.D.x": (0x409000, 47034804), + "lu.D.x": (0x4029A0, 53146691), + "is.D.x": (0x401661, 858226422), + "tc-25": (0x40CA70, 19083641), + "sssp-25": (0x405441, 169473207), +} + +benchmark_choices_npb = [ + "bt.A.x", + "cg.A.x", + "ep.A.x", + "ft.A.x", + "is.A.x", + "lu.A.x", + "mg.A.x", + "sp.A.x", + "ua.A.x", + "bt.B.x", + "cg.B.x", + "ep.B.x", + "ft.B.x", + "is.B.x", + "lu.B.x", + "mg.B.x", + "sp.B.x", + "ua.B.x", + "bt.C.x", + "cg.C.x", + "ep.C.x", + "ft.C.x", + "is.C.x", + "lu.C.x", + "mg.C.x", + "sp.C.x", + "ua.C.x", + "bt.D.x", + "cg.D.x", + "ep.D.x", + "ft.D.x", + "is.D.x", + "lu.D.x", + "mg.D.x", + "sp.D.x", + "ua.D.x", + "bt.F.x", + "cg.F.x", + "ep.F.x", + "ft.F.x", + "is.F.x", + "lu.F.x", + "mg.F.x", + "sp.F.x", + "ua.F.x", +] +benchmark_choices_gapbs = [ + "bfs-22", + "bc-22", + "cc-22", + "pr-22", + "sssp-22", + "tc-22", + "bfs-25", + "bc-25", + "cc-25", + "pr-25", + "sssp-25", + "tc-25", +] + +interval_info_1hr_512MiB = { + # exe pc count + "bc-22": (0x404E08, 4355635), + "bfs-22": (0x403790, 3210973), + "bt.C.x": (0x408600, 623227), + "cc-22": (0x404688, 2218838), + "cg.C.x": (0x4019D8, 8334402), + "pr-22": (0x4036C0, 6426778), + "ft.C.x": (0x405830, 11202023), + "ua.C.x": (0x421ff6, 182749), + "mg.C.x": (0x401920, 1886013), + "sp.C.x": (0x409668, 445619), + "lu.C.x": (0x404160, 457680), + "is.C.x": (0x401955, 12277189), + "tc-22": (0x4052E0, 1059969), + "sssp-22": (0x405441, 4457679), +} + +interval_info_1GBdramCache_3hr = { + # exe pc count + "bt.C.x": (0x40f3d8,244911), + "cg.C.x": (0x4019d8,42463422), + "ft.C.x": (0x401c00,7146042), + "is.C.x": (0x401af0,46965216), + "lu.C.x": (0x40abf8,764707), + "mg.C.x": (0x401b08,6680641), + "sp.C.x": (0x40e2e0,441148), + "ua.C.x": (0x41dca0,1351162), + "bc-22": (0x4036f0,1315303), + "bfs-22": (0x403790,6915678), + "cc-22": (0x4037b0,8303408), + "pr-22": (0x4036c0,35167103), + "tc-22": (0x405640,760), + "sssp-22": (0x405390,2908597), + "bc-25": (0x404e1a,1578848), + "bfs-25": (0x403790,5365971), + "bt.D.x": (0x407fd0,4048773), + "cc-25": (0x404688,5396243), + "cg.D.x": (0x4019d8,13523512), + "pr-25": (0x4036c0,15770394), + "ft.D.x": (0x401c10,4648334), + "ua.D.x": (0x403f30,31180), + "mg.D.x": (0x401920,4263169), + "sp.D.x": (0x409000,3544598), + "lu.D.x": (0x4027f8,27621), + "is.D.x": (0x401661,31545953), + "tc-25": (0x4030a0,15958999), + "sssp-25": (0x405441,7679886), +} \ No newline at end of file diff --git a/configs-npb-gapbs/npb_checkpoint.py b/configs-npb-gapbs/npb_checkpoint.py new file mode 100755 index 0000000000..6300d56441 --- /dev/null +++ b/configs-npb-gapbs/npb_checkpoint.py @@ -0,0 +1,255 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2019 The Regents of the University of California. +# All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power, Ayaz Akram + +""" Script to run NAS parallel benchmarks with gem5. + The script expects kernel, diskimage, mem_sys, + cpu (kvm, atomic, or timing), benchmark to run + and number of cpus as arguments. + + If your application has ROI annotations, this script will count the total + number of instructions executed in the ROI. It also tracks how much + wallclock and simulated time. +""" +import argparse +import time +import m5 +import m5.ticks +from m5.objects import * + +from system import * + + +def writeBenchScript(dir, bench): + """ + This method creates a script in dir which will be eventually + passed to the simulated system (to run a specific benchmark + at bootup). + """ + file_name = "{}/run_{}".format(dir, bench) + bench_file = open(file_name, "w+") + bench_file.write("/home/gem5/NPB3.3-OMP/bin/{} \n".format(bench)) + + # sleeping for sometime (5 seconds here) makes sure + # that the benchmark's output has been + # printed to the console + bench_file.write("sleep 5 \n") + bench_file.write("m5 exit \n") + bench_file.close() + return file_name + + +supported_protocols = [ + "classic", + "MI_example", + "MESI_Two_Level", + "MOESI_CMP_directory", +] +supported_cpu_types = ["kvm", "atomic", "timing"] +benchmark_choices = [ + "bt.A.x", + "cg.A.x", + "ep.A.x", + "ft.A.x", + "is.A.x", + "lu.A.x", + "mg.A.x", + "sp.A.x", + "bt.B.x", + "cg.B.x", + "ep.B.x", + "ft.B.x", + "is.B.x", + "lu.B.x", + "mg.B.x", + "sp.B.x", + "bt.C.x", + "cg.C.x", + "ep.C.x", + "ft.C.x", + "is.C.x", + "lu.C.x", + "mg.C.x", + "sp.C.x", + "bt.D.x", + "cg.D.x", + "ep.D.x", + "ft.D.x", + "is.D.x", + "lu.D.x", + "mg.D.x", + "sp.D.x", + "bt.F.x", + "cg.F.x", + "ep.F.x", + "ft.F.x", + "is.F.x", + "lu.F.x", + "mg.F.x", + "sp.F.x", + "ua.C.x", + "ua.D.x", +] + + +def parse_options(): + + parser = argparse.ArgumentParser( + description="For use with gem5. This " + "runs a NAS Parallel Benchmark application. This only works " + "with x86 ISA." + ) + + # The manditry position arguments. + parser.add_argument( + "benchmark", + type=str, # choices=benchmark_choices, + help="The NPB application to run", + ) + parser.add_argument( + "class_size", type=str, help="The NPB application class to run" + ) + parser.add_argument( + "dcache_policy", + type=str, + help="The architecture of DRAM cache: " + "CascadeLakeNoPartWrs, Oracle, BearWriteOpt, Rambus, RambusTagProbOpt", + ) + parser.add_argument( + "is_link", + type=int, + help="whether to use a link for backing store or not", + ) + parser.add_argument( + "link_lat", type=str, help="latency of the link to backing store" + ) + + return parser.parse_args() + + +if __name__ == "__m5_main__": + args = parse_options() + + kernel = "/home/mbabaie/code-review/dramCacheController/fs-resources/x86-linux-kernel-4.19.83" + disk = "/home/mbabaie/code-review/dramCacheController/fs-resources/x86-npb" + num_cpus = 8 + cpu_type = "Timing" + mem_sys = "MESI_Two_Level" + + dcache_size = "" + mem_size = "" + if args.class_size == "C": + dcache_size = "1GiB" + mem_size = "8GiB" + elif args.class_size == "D": + dcache_size = "1GiB" + mem_size = "85GiB" + assoc = 1 + benchmark = args.benchmark + + # create the system we are going to simulate + system = MyRubySystem( + kernel, + disk, + mem_sys, + num_cpus, + assoc, + dcache_size, + mem_size, + args.dcache_policy, + args.is_link, + args.link_lat, + 0, + args, + ) + + system.m5ops_base = 0xFFFF0000 + + # Exit from guest on workbegin/workend + system.exit_on_work_items = True + + # Create and pass a script to the simulated system to run the reuired + # benchmark + system.readfile = writeBenchScript(m5.options.outdir, benchmark) + + # set up the root SimObject and start the simulation + root = Root(full_system=True, system=system) + + if system.getHostParallel(): + # Required for running kvm on multiple host cores. + # Uses gem5's parallel event queue feature + # Note: The simulator is quite picky about this number! + root.sim_quantum = int(1e9) # 1 ms + + # needed for long running jobs + # m5.disableAllListeners() + + # instantiate all of the objects we've created above + m5.instantiate() + + globalStart = time.time() + + print("Running the simulation") + print("Using cpu: {}".format(cpu_type)) + exit_event = m5.simulate() + + if exit_event.getCause() == "workbegin": + print("Done booting Linux") + # Reached the start of ROI + # start of ROI is marked by an + # m5_work_begin() call + print("Resetting stats at the start of ROI!") + m5.stats.reset() + start_tick = m5.curTick() + start_insts = system.totalInsts() + # switching CPU to timing + system.switchCpus(system.cpu, system.timingCpu) + else: + print(exit_event.getCause()) + print("Unexpected termination of simulation !") + exit() + + m5.stats.reset() + print( + "After reset ************************************************ statring smiulation:\n" + ) + for interval_number in range(105): + print("Interval number: {} \n".format(interval_number)) + exit_event = m5.simulate(10000000000) + if exit_event.getCause() == "cacheIsWarmedup": + print("Caught cacheIsWarmedup exit event!") + break + print( + "-------------------------------------------------------------------" + ) + + print( + "After sim ************************************************ End of warm-up \n" + ) + m5.stats.dump() + system.switchCpus(system.timingCpu, system.o3Cpu) + m5.checkpoint(m5.options.outdir + "/cpt") diff --git a/configs-npb-gapbs/npb_restore.py b/configs-npb-gapbs/npb_restore.py new file mode 100755 index 0000000000..224af6d58c --- /dev/null +++ b/configs-npb-gapbs/npb_restore.py @@ -0,0 +1,222 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2019 The Regents of the University of California. +# All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power, Ayaz Akram + +""" Script to run NAS parallel benchmarks with gem5. + The script expects kernel, diskimage, mem_sys, + cpu (kvm, atomic, or timing), benchmark to run + and number of cpus as arguments. + + If your application has ROI annotations, this script will count the total + number of instructions executed in the ROI. It also tracks how much + wallclock and simulated time. +""" +import argparse +import time +import m5 +import m5.ticks +from m5.objects import * + +from system import * + + +def writeBenchScript(dir, bench): + """ + This method creates a script in dir which will be eventually + passed to the simulated system (to run a specific benchmark + at bootup). + """ + file_name = "{}/run_{}".format(dir, bench) + bench_file = open(file_name, "w+") + bench_file.write("/home/gem5/NPB3.3-OMP/bin/{} \n".format(bench)) + + # sleeping for sometime (5 seconds here) makes sure + # that the benchmark's output has been + # printed to the console + bench_file.write("sleep 5 \n") + bench_file.write("m5 exit \n") + bench_file.close() + return file_name + + +supported_protocols = [ + "classic", + "MI_example", + "MESI_Two_Level", + "MOESI_CMP_directory", +] +supported_cpu_types = ["kvm", "atomic", "timing"] +benchmark_choices = [ + "bt.A.x", + "cg.A.x", + "ep.A.x", + "ft.A.x", + "is.A.x", + "lu.A.x", + "mg.A.x", + "sp.A.x", + "bt.B.x", + "cg.B.x", + "ep.B.x", + "ft.B.x", + "is.B.x", + "lu.B.x", + "mg.B.x", + "sp.B.x", + "bt.C.x", + "cg.C.x", + "ep.C.x", + "ft.C.x", + "is.C.x", + "lu.C.x", + "mg.C.x", + "sp.C.x", + "bt.D.x", + "cg.D.x", + "ep.D.x", + "ft.D.x", + "is.D.x", + "lu.D.x", + "mg.D.x", + "sp.D.x", + "bt.F.x", + "cg.F.x", + "ep.F.x", + "ft.F.x", + "is.F.x", + "lu.F.x", + "mg.F.x", + "sp.F.x", +] + + +def parse_options(): + + parser = argparse.ArgumentParser( + description="For use with gem5. This " + "runs a NAS Parallel Benchmark application. This only works " + "with x86 ISA." + ) + + # The manditry position arguments. + parser.add_argument( + "benchmark", + type=str, # choices=benchmark_choices, + help="The NPB application to run", + ) + parser.add_argument( + "class_size", type=str, help="The NPB application class to run" + ) + parser.add_argument( + "dcache_policy", + type=str, + help="The architecture of DRAM cache: " + "CascadeLakeNoPartWrs, Oracle, BearWriteOpt, Rambus", + ) + parser.add_argument( + "is_link", + type=int, + help="whether to use a link for backing store or not", + ) + parser.add_argument( + "link_lat", type=str, help="latency of the link to backing store" + ) + parser.add_argument( + "checkpoint_path", type=str, help="Path to checkpoint dir" + ) + return parser.parse_args() + + +if __name__ == "__m5_main__": + args = parse_options() + + kernel = "/home/mbabaie/code-review/dramCacheController/fs-resources/x86-linux-kernel-4.19.83" + disk = "/home/mbabaie/code-review/dramCacheController/fs-resources/x86-npb" + num_cpus = 8 + cpu_type = "Timing" + mem_sys = "MESI_Two_Level" + + dcache_size = "" + mem_size = "" + if args.class_size == "C": + dcache_size = "128MiB" + mem_size = "16GiB" + elif args.class_size == "D": + dcache_size = "512MiB" + mem_size = "85GiB" + + benchmark = args.benchmark + "." + args.class_size + ".x" + + system = MyRubySystem( + kernel, + disk, + mem_sys, + num_cpus, + dcache_size, + mem_size, + args.dcache_policy, + args.is_link, + args.link_lat, + args, + restore=True, + ) + + system.m5ops_base = 0xFFFF0000 + + # Exit from guest on workbegin/workend + system.exit_on_work_items = True + + # Create and pass a script to the simulated system to run the reuired + # benchmark + system.readfile = writeBenchScript(m5.options.outdir, benchmark) + + # set up the root SimObject and start the simulation + root = Root(full_system=True, system=system) + + if system.getHostParallel(): + # Required for running kvm on multiple host cores. + # Uses gem5's parallel event queue feature + # Note: The simulator is quite picky about this number! + root.sim_quantum = int(1e9) # 1 ms + + # needed for long running jobs + m5.disableAllListeners() + + # instantiate all of the objects we've created above + m5.instantiate(args.checkpoint_path) + + globalStart = time.time() + + print("Running the simulation ************************************** \n") + print("Simulating 100 intervals of 10ms each! \n") + + for interval_number in range(100): + print("Interval number: {} \n".format(interval_number)) + exit_event = m5.simulate(10000000000) + m5.stats.dump() + + print("End of simulation ******************************************** \n") diff --git a/configs-npb-gapbs/restore_both.py b/configs-npb-gapbs/restore_both.py new file mode 100755 index 0000000000..b661bcacd2 --- /dev/null +++ b/configs-npb-gapbs/restore_both.py @@ -0,0 +1,331 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2019 The Regents of the University of California. +# All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power, Ayaz Akram + +""" Script to run NAS parallel benchmarks with gem5. + The script expects kernel, diskimage, mem_sys, + cpu (kvm, atomic, or timing), benchmark to run + and number of cpus as arguments. + + If your application has ROI annotations, this script will count the total + number of instructions executed in the ROI. It also tracks how much + wallclock and simulated time. +""" +import argparse +import time +import m5 +import m5.ticks +from m5.objects import * + +from system import * +from info import ( + text_info, + interval_info_1hr, + interval_info_3hr, + interval_info_6hr, + interval_info_12hr, + interval_info_24hr, + benchmark_choices_gapbs, + benchmark_choices_npb, + interval_info_1hr_512MiB, + interval_info_1GBdramCache_3hr, +) + + +def writeBenchScriptNPB(dir, bench): + """ + This method creates a script in dir which will be eventually + passed to the simulated system (to run a specific benchmark + at bootup). + """ + file_name = "{}/run_{}".format(dir, bench) + bench_file = open(file_name, "w+") + bench_file.write("/home/gem5/NPB3.3-OMP/bin/{} \n".format(bench)) + + # sleeping for sometime (5 seconds here) makes sure + # that the benchmark's output has been + # printed to the console + bench_file.write("sleep 5 \n") + bench_file.write("m5 exit \n") + bench_file.close() + return file_name + + +def writeBenchScriptGAPBS(dir, benchmark_name): + """ + This method creates a script in dir which will be eventually + passed to the simulated system (to run a specific benchmark + at bootup). + """ + synthetic = True + benchmark, size = benchmark_name.split("-") + input_file_name = "{}/run_{}_{}".format(dir, benchmark, size) + if synthetic: + with open(input_file_name, "w") as f: + f.write("./{} -g {}\n".format(benchmark, size)) + elif synthetic == 0: + with open(input_file_name, "w") as f: + # The workloads that are copied to the disk image using Packer + # should be located in /home/gem5/. + # Since the command running the workload will be executed with + # pwd = /home/gem5/gapbs, the path to the copied workload is + # ../{workload-name} + f.write("./{} -sf ../{}".format(benchmark, size)) + + return input_file_name + + +supported_protocols = [ + "classic", + "MI_example", + "MESI_Two_Level", + "MOESI_CMP_directory", +] +supported_cpu_types = ["kvm", "atomic", "timing"] + + +def parse_options(): + parser = argparse.ArgumentParser( + description="For use with gem5. This " + "runs a NAS Parallel Benchmark application. This only works " + "with x86 ISA." + ) + + # The manditry position arguments. + parser.add_argument( + "benchmark", + type=str, + choices=benchmark_choices_npb + benchmark_choices_gapbs, + help="The NPB application to run", + ) + parser.add_argument( + "dcache_policy", + type=str, + help="The architecture of DRAM cache: " + "CascadeLakeNoPartWrs, Oracle, BearWriteOpt, Rambus", + ) + parser.add_argument( + "assoc", + type=int, + help="THe associativity of the DRAM cache", + ) + parser.add_argument( + "is_link", + type=int, + help="whether to use a link for backing store or not", + ) + parser.add_argument( + "link_lat", type=str, help="latency of the link to backing store" + ) + parser.add_argument( + "bypass", + type=int, + help="bypass DRAM cache", + ) + parser.add_argument("--do_analysis", action="store_true", default=False) + return parser.parse_args() + + +def do_analysis(): + print( + "**************** Doing analysis! Simulating 100 intervals of 10ms each! ********************\n" + ) + start = time.time() + + for interval_number in range(100): + print(f"Working on interval number: {interval_number}") + exit_event = m5.simulate(10_000_000_000) # 10 ms + m5.stats.dump() + + print( + f"Done with interval {interval_number} at {(time.time() - start)/60:0.2f}" + ) + mostRecentPc = lpmanager.getMostRecentPc() + print(f"Exit because {exit_event.getCause()}, before for") + for pc, tick in mostRecentPc: + count = lpmanager.getPcCount(pc) + print("in for loop") + print(f"{hex(pc)},{count[0]},{count[1]}") + if exit_event.getCause() != "simulate() limit reached": + if ( + exit_event.getCause() == "workend" + or exit_event.getCause() == "workbegin" + ): + print(f"Exit because {exit_event.getCause()}, continuing...") + else: + print(f"Exiting because {exit_event.getCause()}") + break + + +def run(): + print("Simulating 100 intervals of 10ms each! \n") + + for interval_number in range(100): + print("Interval number: {}".format(interval_number)) + exit_event = m5.simulate(10_000_000_000) # 10 ms + # m5.stats.dump() + + if exit_event.getCause() != "simulate() limit reached": + if ( + exit_event.getCause() == "workend" + or exit_event.getCause() == "workbegin" + ): + print("Workload finished, continuing...") + else: + print(f"Exiting because {exit_event.getCause()}") + break + + +if __name__ == "__m5_main__": + args = parse_options() + + kernel = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-linux-kernel-4.19.83" + disk = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-npb" + ckpt_base = "/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/chkpt1GigDC/" + + num_cpus = 8 + cpu_type = "Timing" + mem_sys = "MESI_Two_Level" + + dcache_size = "1GB" + mem_size = "" + checkpoint_dir = "" + + if args.benchmark in benchmark_choices_npb: + if args.benchmark.split(".")[1] == "C": + checkpoint_dir = ( + ckpt_base + + "1GB_8GB_g22_nC_1halfSec/NPB/" + + args.benchmark.split(".")[0] + + "/cpt" + ) + mem_size = "8GiB" + elif args.benchmark.split(".")[1] == "D": + checkpoint_dir = ( + ckpt_base + + "1GB_85GB_g25_nD_1halfSec/NPB/" + + args.benchmark.split(".")[0] + + "/cpt" + ) + mem_size = "85GiB" + else: + if args.benchmark.split("-")[1] == "22": + checkpoint_dir = ( + ckpt_base + + "1GB_8GB_g22_nC_1halfSec/GAPBS/" + + args.benchmark.split("-")[0] + + "/cpt" + ) + mem_size = "8GiB" + elif args.benchmark.split("-")[1] == "25": + checkpoint_dir = ( + ckpt_base + + "1GB_85GB_g25_nD_1halfSec/GAPBS/" + + args.benchmark.split("-")[0] + + "/cpt" + ) + mem_size = "85GiB" + + benchmark = args.benchmark + + system = MyRubySystem( + kernel, + disk, + mem_sys, + num_cpus, + args.assoc, + dcache_size, + mem_size, + args.dcache_policy, + args.is_link, + args.link_lat, + args.bypass, + args, + restore=True, + ) + + if args.do_analysis: + lpmanager = O3LooppointAnalysisManager() + + for core in system.o3Cpu: + lplistener = O3LooppointAnalysis() + lplistener.ptmanager = lpmanager + lplistener.validAddrRangeStart = text_info[args.benchmark][1] + lplistener.validAddrRangeSize = text_info[args.benchmark][0] + core.probeListener = lplistener + else: + pc, count = interval_info_1GBdramCache_3hr[args.benchmark] + system.global_tracker = PcCountTrackerManager( + targets=[PcCountPair(pc, count)] + ) + + for core in system.o3Cpu: + core.core_tracker = PcCountTracker( + targets=[PcCountPair(pc, count)], + core=core, + ptmanager=system.global_tracker, + ) + + system.m5ops_base = 0xFFFF0000 + + # Exit from guest on workbegin/workend + system.exit_on_work_items = True + + # Create and pass a script to the simulated system to run the reuired + # benchmark + if args.benchmark in benchmark_choices_npb: + system.readfile = writeBenchScriptNPB( + m5.options.outdir, args.benchmark + ) + else: + system.readfile = writeBenchScriptGAPBS( + m5.options.outdir, args.benchmark + ) + + # set up the root SimObject and start the simulation + root = Root(full_system=True, system=system) + + if system.getHostParallel(): + # Required for running kvm on multiple host cores. + # Uses gem5's parallel event queue feature + # Note: The simulator is quite picky about this number! + root.sim_quantum = int(1e9) # 1 ms + + # needed for long running jobs + m5.disableAllListeners() + + # instantiate all of the objects we've created above + m5.instantiate(checkpoint_dir) + + print("Running the simulation ************************************** \n") + + if args.do_analysis: + do_analysis() + else: + run() + + print("End of simulation ******************************************** \n") diff --git a/configs-npb-gapbs/system/MESI_Two_Level.py b/configs-npb-gapbs/system/MESI_Two_Level.py new file mode 100755 index 0000000000..8307e74634 --- /dev/null +++ b/configs-npb-gapbs/system/MESI_Two_Level.py @@ -0,0 +1,332 @@ +#Copyright (c) 2020 The Regents of the University of California. +#All Rights Reserved +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + + +""" This file creates a set of Ruby caches for the MESI TWO Level protocol +This protocol models two level cache hierarchy. The L1 cache is split into +instruction and data cache. + +This system support the memory size of up to 3GB. + +""" + +import math + +from m5.defines import buildEnv +from m5.util import fatal, panic + +from m5.objects import * + +class MESITwoLevelCache(RubySystem): + + def __init__(self): + if buildEnv['PROTOCOL'] != 'MESI_Two_Level': + fatal("This system assumes MESI_Two_Level!") + + super(MESITwoLevelCache, self).__init__() + + self._numL2Caches = 8 + + def setup(self, system, cpus, mem_ctrls, mem_ranges, dma_ports, iobus): + """Set up the Ruby cache subsystem. Note: This can't be done in the + constructor because many of these items require a pointer to the + ruby system (self). This causes infinite recursion in initialize() + if we do this in the __init__. + """ + # Ruby's global network. + self.network = MyNetwork(self) + + # MESI_Two_Level example uses 5 virtual networks + self.number_of_virtual_networks = 5 + self.network.number_of_virtual_networks = 5 + + # There is a single global list of all of the controllers to make it + # easier to connect everything to the global network. This can be + # customized depending on the topology/network requirements. + # L1 caches are private to a core, hence there are one L1 cache per CPU + # core. The number of L2 caches are dependent to the architecture. + self.controllers = \ + [L1Cache(system, self, cpu, self._numL2Caches) for cpu in cpus] + \ + [L2Cache(system, self, self._numL2Caches) for num in \ + range(self._numL2Caches)] + \ + [DirController(self, rng, mem_ctrl) for rng,mem_ctrl in zip(mem_ranges,mem_ctrls)] + \ + [DMAController(self) for i in range(len(dma_ports))] + + # Create one sequencer per CPU and dma controller. + # Sequencers for other controllers can be here here. + self.sequencers = [RubySequencer(version = i, + # Grab dcache from ctrl + dcache = self.controllers[i].L1Dcache, + clk_domain = self.controllers[i].clk_domain, + pio_request_port = iobus.cpu_side_ports, + mem_request_port = iobus.cpu_side_ports, + pio_response_port = iobus.mem_side_ports + ) for i in range(len(cpus))] + \ + [DMASequencer(version = i, + in_ports = port) + for i,port in enumerate(dma_ports) + ] + + for i,c in enumerate(self.controllers[:len(cpus)]): + c.sequencer = self.sequencers[i] + + #Connecting the DMA sequencer to DMA controller + for i,d in enumerate(self.controllers[-len(dma_ports):]): + i += len(cpus) + d.dma_sequencer = self.sequencers[i] + + self.num_of_sequencers = len(self.sequencers) + + # Create the network and connect the controllers. + # NOTE: This is quite different if using Garnet! + self.network.connectControllers(self.controllers) + self.network.setup_buffers() + + # Set up a proxy port for the system_port. Used for load binaries and + # other functional-only things. + self.sys_port_proxy = RubyPortProxy() + system.system_port = self.sys_port_proxy.in_ports + self.sys_port_proxy.pio_request_port = iobus.cpu_side_ports + + # Connect the cpu's cache, interrupt, and TLB ports to Ruby + for i,cpu in enumerate(cpus): + cpu.icache_port = self.sequencers[i].in_ports + cpu.dcache_port = self.sequencers[i].in_ports + cpu.createInterruptController() + cpu.interrupts[0].pio = self.sequencers[i].interrupt_out_port + cpu.interrupts[0].int_requestor = self.sequencers[i].in_ports + cpu.interrupts[0].int_responder = self.sequencers[i].interrupt_out_port + cpu.mmu.connectWalkerPorts( + self.sequencers[i].in_ports, self.sequencers[i].in_ports) +class L1Cache(L1Cache_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, system, ruby_system, cpu, num_l2Caches): + """Creating L1 cache controller. Consist of both instruction + and data cache. The size of data cache is 512KB and + 8-way set associative. The instruction cache is 32KB, + 2-way set associative. + """ + super(L1Cache, self).__init__() + + self.version = self.versionCount() + block_size_bits = int(math.log(system.cache_line_size, 2)) + l1i_size = '32kB' + l1i_assoc = '2' + l1d_size = '512kB' + l1d_assoc = '8' + # This is the cache memory object that stores the cache data and tags + self.L1Icache = RubyCache(size = l1i_size, + assoc = l1i_assoc, + start_index_bit = block_size_bits , + is_icache = True) + self.L1Dcache = RubyCache(size = l1d_size, + assoc = l1d_assoc, + start_index_bit = block_size_bits, + is_icache = False) + self.l2_select_num_bits = int(math.log(num_l2Caches , 2)) + self.clk_domain = cpu.clk_domain + self.prefetcher = RubyPrefetcher() + self.send_evictions = self.sendEvicts(cpu) + self.transitions_per_cycle = 4 + self.enable_prefetch = False + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def getBlockSizeBits(self, system): + bits = int(math.log(system.cache_line_size, 2)) + if 2**bits != system.cache_line_size.value: + panic("Cache line size not a power of 2!") + return bits + + def sendEvicts(self, cpu): + """True if the CPU model or ISA requires sending evictions from caches + to the CPU. Two scenarios warrant forwarding evictions to the CPU: + 1. The O3 model must keep the LSQ coherent with the caches + 2. The x86 mwait instruction is built on top of coherence + 3. The local exclusive monitor in ARM systems + """ + if type(cpu) is X86O3CPU: + return True + return False + + def connectQueues(self, ruby_system): + """Connect all of the queues for this controller. + """ + self.mandatoryQueue = MessageBuffer() + self.requestFromL1Cache = MessageBuffer() + self.requestFromL1Cache.out_port = ruby_system.network.in_port + self.responseFromL1Cache = MessageBuffer() + self.responseFromL1Cache.out_port = ruby_system.network.in_port + self.unblockFromL1Cache = MessageBuffer() + self.unblockFromL1Cache.out_port = ruby_system.network.in_port + + self.optionalQueue = MessageBuffer() + + self.requestToL1Cache = MessageBuffer() + self.requestToL1Cache.in_port = ruby_system.network.out_port + self.responseToL1Cache = MessageBuffer() + self.responseToL1Cache.in_port = ruby_system.network.out_port + +class L2Cache(L2Cache_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, system, ruby_system, num_l2Caches): + + super(L2Cache, self).__init__() + + self.version = self.versionCount() + # This is the cache memory object that stores the cache data and tags + self.L2cache = RubyCache(size = '1 MB', + assoc = 16, + start_index_bit = self.getBlockSizeBits(system, + num_l2Caches)) + + self.transitions_per_cycle = '4' + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def getBlockSizeBits(self, system, num_l2caches): + l2_bits = int(math.log(num_l2caches, 2)) + bits = int(math.log(system.cache_line_size, 2)) + l2_bits + return bits + + + def connectQueues(self, ruby_system): + """Connect all of the queues for this controller. + """ + self.DirRequestFromL2Cache = MessageBuffer() + self.DirRequestFromL2Cache.out_port = ruby_system.network.in_port + self.L1RequestFromL2Cache = MessageBuffer() + self.L1RequestFromL2Cache.out_port = ruby_system.network.in_port + self.responseFromL2Cache = MessageBuffer() + self.responseFromL2Cache.out_port = ruby_system.network.in_port + self.unblockToL2Cache = MessageBuffer() + self.unblockToL2Cache.in_port = ruby_system.network.out_port + self.L1RequestToL2Cache = MessageBuffer() + self.L1RequestToL2Cache.in_port = ruby_system.network.out_port + self.responseToL2Cache = MessageBuffer() + self.responseToL2Cache.in_port = ruby_system.network.out_port + + +class DirController(Directory_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, ruby_system, ranges, mem_ctrls): + """ranges are the memory ranges assigned to this controller. + """ + if len(mem_ctrls) > 1: + panic("This cache system can only be connected to one mem ctrl") + super(DirController, self).__init__() + self.version = self.versionCount() + self.addr_ranges = ranges + self.ruby_system = ruby_system + self.directory = RubyDirectoryMemory() + # Connect this directory to the memory side. + self.memory_out_port = mem_ctrls[0].port + self.connectQueues(ruby_system) + + def connectQueues(self, ruby_system): + self.requestToDir = MessageBuffer() + self.requestToDir.in_port = ruby_system.network.out_port + self.responseToDir = MessageBuffer() + self.responseToDir.in_port = ruby_system.network.out_port + self.responseFromDir = MessageBuffer() + self.responseFromDir.out_port = ruby_system.network.in_port + self.requestToMemory = MessageBuffer() + self.responseFromMemory = MessageBuffer() + +class DMAController(DMA_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, ruby_system): + super(DMAController, self).__init__() + self.version = self.versionCount() + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def connectQueues(self, ruby_system): + self.mandatoryQueue = MessageBuffer() + self.responseFromDir = MessageBuffer(ordered = True) + self.responseFromDir.in_port = ruby_system.network.out_port + self.requestToDir = MessageBuffer() + self.requestToDir.out_port = ruby_system.network.in_port + + +class MyNetwork(SimpleNetwork): + """A simple point-to-point network. This doesn't not use garnet. + """ + + def __init__(self, ruby_system): + super(MyNetwork, self).__init__() + self.netifs = [] + self.ruby_system = ruby_system + + def connectControllers(self, controllers): + """Connect all of the controllers to routers and connec the routers + together in a point-to-point network. + """ + # Create one router/switch per controller in the system + self.routers = [Switch(router_id = i) for i in range(len(controllers))] + + # Make a link from each controller to the router. The link goes + # externally to the network. + self.ext_links = [SimpleExtLink(link_id=i, ext_node=c, + int_node=self.routers[i]) + for i, c in enumerate(controllers)] + + # Make an "internal" link (internal to the network) between every pair + # of routers. + link_count = 0 + self.int_links = [] + for ri in self.routers: + for rj in self.routers: + if ri == rj: continue # Don't connect a router to itself! + link_count += 1 + self.int_links.append(SimpleIntLink(link_id = link_count, + src_node = ri, + dst_node = rj)) diff --git a/configs-npb-gapbs/system/MI_example_caches.py b/configs-npb-gapbs/system/MI_example_caches.py new file mode 100755 index 0000000000..3c7a71d7b1 --- /dev/null +++ b/configs-npb-gapbs/system/MI_example_caches.py @@ -0,0 +1,275 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2015 Jason Power +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Power + +""" This file creates a set of Ruby caches, the Ruby network, and a simple +point-to-point topology. +See Part 3 in the Learning gem5 book: learning.gem5.org/book/part3 +You can change simple_ruby to import from this file instead of from msi_caches +to use the MI_example protocol instead of MSI. + +IMPORTANT: If you modify this file, it's likely that the Learning gem5 book + also needs to be updated. For now, email Jason + +""" + +import math + +from m5.defines import buildEnv +from m5.util import fatal, panic + +from m5.objects import * + +class MIExampleSystem(RubySystem): + + def __init__(self): + if buildEnv['PROTOCOL'] != 'MI_example': + fatal("This system assumes MI_example!") + + super(MIExampleSystem, self).__init__() + + def setup(self, system, cpus, mem_ctrls, dma_ports, iobus): + """Set up the Ruby cache subsystem. Note: This can't be done in the + constructor because many of these items require a pointer to the + ruby system (self). This causes infinite recursion in initialize() + if we do this in the __init__. + """ + # Ruby's global network. + self.network = MyNetwork(self) + + # MI example uses 5 virtual networks + self.number_of_virtual_networks = 5 + self.network.number_of_virtual_networks = 5 + + # There is a single global list of all of the controllers to make it + # easier to connect everything to the global network. This can be + # customized depending on the topology/network requirements. + # Create one controller for each L1 cache (and the cache mem obj.) + # Create a single directory controller (Really the memory cntrl) + self.controllers = \ + [L1Cache(system, self, cpu) for cpu in cpus] + \ + [DirController(self, system.mem_ranges, mem_ctrls)] + \ + [DMAController(self) for i in range(len(dma_ports))] + + # Create one sequencer per CPU. In many systems this is more + # complicated since you have to create sequencers for DMA controllers + # and other controllers, too. + self.sequencers = [RubySequencer(version = i, + # Grab dcache from ctrl + dcache = self.controllers[i].cacheMemory, + clk_domain = self.controllers[i].clk_domain, + pio_request_port = iobus.cpu_side_ports, + mem_request_port = iobus.cpu_side_ports, + pio_response_port = iobus.mem_side_ports + ) for i in range(len(cpus))] + \ + [DMASequencer(version = i, + in_ports = port) + for i,port in enumerate(dma_ports) + ] + + for i,c in enumerate(self.controllers[0:len(cpus)]): + c.sequencer = self.sequencers[i] + + for i,d in enumerate(self.controllers[-len(dma_ports):]): + i += len(cpus) + d.dma_sequencer = self.sequencers[i] + + self.num_of_sequencers = len(self.sequencers) + + # Create the network and connect the controllers. + # NOTE: This is quite different if using Garnet! + self.network.connectControllers(self.controllers) + self.network.setup_buffers() + + # Set up a proxy port for the system_port. Used for load binaries and + # other functional-only things. + self.sys_port_proxy = RubyPortProxy() + system.system_port = self.sys_port_proxy.in_ports + self.sys_port_proxy.pio_request_port = iobus.cpu_side_ports + + # Connect the cpu's cache, interrupt, and TLB ports to Ruby + for i,cpu in enumerate(cpus): + cpu.icache_port = self.sequencers[i].in_ports + cpu.dcache_port = self.sequencers[i].in_ports + cpu.createInterruptController() + isa = buildEnv['TARGET_ISA'] + if isa == 'x86': + cpu.interrupts[0].pio = self.sequencers[i].interrupt_out_port + cpu.interrupts[0].int_requestor = self.sequencers[i].in_ports + cpu.interrupts[0].int_responder = self.sequencers[i].interrupt_out_port + if isa == 'x86' or isa == 'arm': + cpu.mmu.connectWalkerPorts( + self.sequencers[i].in_ports, self.sequencers[i].in_ports) + +class L1Cache(L1Cache_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, system, ruby_system, cpu): + """CPUs are needed to grab the clock domain and system is needed for + the cache block size. + """ + super(L1Cache, self).__init__() + + self.version = self.versionCount() + # This is the cache memory object that stores the cache data and tags + self.cacheMemory = RubyCache(size = '16kB', + assoc = 8, + start_index_bit = self.getBlockSizeBits(system)) + self.clk_domain = cpu.clk_domain + self.send_evictions = self.sendEvicts(cpu) + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def getBlockSizeBits(self, system): + bits = int(math.log(system.cache_line_size, 2)) + if 2**bits != system.cache_line_size.value: + panic("Cache line size not a power of 2!") + return bits + + def sendEvicts(self, cpu): + """True if the CPU model or ISA requires sending evictions from caches + to the CPU. Two scenarios warrant forwarding evictions to the CPU: + 1. The O3 model must keep the LSQ coherent with the caches + 2. The x86 mwait instruction is built on top of coherence + 3. The local exclusive monitor in ARM systems + """ + if type(cpu) is DerivO3CPU or \ + buildEnv['TARGET_ISA'] in ('x86', 'arm'): + return True + return False + + def connectQueues(self, ruby_system): + """Connect all of the queues for this controller. + """ + self.mandatoryQueue = MessageBuffer() + self.requestFromCache = MessageBuffer(ordered = True) + self.requestFromCache.out_port = ruby_system.network.in_port + self.responseFromCache = MessageBuffer(ordered = True) + self.responseFromCache.out_port = ruby_system.network.in_port + self.forwardToCache = MessageBuffer(ordered = True) + self.forwardToCache.in_port = ruby_system.network.out_port + self.responseToCache = MessageBuffer(ordered = True) + self.responseToCache.in_port = ruby_system.network.out_port + +class DirController(Directory_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, ruby_system, ranges, mem_ctrls): + """ranges are the memory ranges assigned to this controller. + """ + if len(mem_ctrls) > 1: + panic("This cache system can only be connected to one mem ctrl") + super(DirController, self).__init__() + self.version = self.versionCount() + self.addr_ranges = ranges + self.ruby_system = ruby_system + self.directory = RubyDirectoryMemory() + # Connect this directory to the memory side. + self.memory_out_port = mem_ctrls[0].port + self.connectQueues(ruby_system) + + def connectQueues(self, ruby_system): + self.requestToDir = MessageBuffer(ordered = True) + self.requestToDir.in_port = ruby_system.network.out_port + self.dmaRequestToDir = MessageBuffer(ordered = True) + self.dmaRequestToDir.in_port = ruby_system.network.out_port + + self.responseFromDir = MessageBuffer() + self.responseFromDir.out_port = ruby_system.network.in_port + self.dmaResponseFromDir = MessageBuffer(ordered = True) + self.dmaResponseFromDir.out_port = ruby_system.network.in_port + self.forwardFromDir = MessageBuffer() + self.forwardFromDir.out_port = ruby_system.network.in_port + self.requestToMemory = MessageBuffer() + self.responseFromMemory = MessageBuffer() + +class DMAController(DMA_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, ruby_system): + super(DMAController, self).__init__() + self.version = self.versionCount() + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def connectQueues(self, ruby_system): + self.mandatoryQueue = MessageBuffer() + self.requestToDir = MessageBuffer() + self.requestToDir.out_port = ruby_system.network.in_port + self.responseFromDir = MessageBuffer(ordered = True) + self.responseFromDir.in_port = ruby_system.network.out_port + + +class MyNetwork(SimpleNetwork): + """A simple point-to-point network. This doesn't not use garnet. + """ + + def __init__(self, ruby_system): + super(MyNetwork, self).__init__() + self.netifs = [] + self.ruby_system = ruby_system + + def connectControllers(self, controllers): + """Connect all of the controllers to routers and connec the routers + together in a point-to-point network. + """ + # Create one router/switch per controller in the system + self.routers = [Switch(router_id = i) for i in range(len(controllers))] + + # Make a link from each controller to the router. The link goes + # externally to the network. + self.ext_links = [SimpleExtLink(link_id=i, ext_node=c, + int_node=self.routers[i]) + for i, c in enumerate(controllers)] + + # Make an "internal" link (internal to the network) between every pair + # of routers. + link_count = 0 + self.int_links = [] + for ri in self.routers: + for rj in self.routers: + if ri == rj: continue # Don't connect a router to itself! + link_count += 1 + self.int_links.append(SimpleIntLink(link_id = link_count, + src_node = ri, + dst_node = rj)) diff --git a/configs-npb-gapbs/system/MOESI_CMP_directory.py b/configs-npb-gapbs/system/MOESI_CMP_directory.py new file mode 100755 index 0000000000..33f9f47e74 --- /dev/null +++ b/configs-npb-gapbs/system/MOESI_CMP_directory.py @@ -0,0 +1,350 @@ +#Copyright (c) 2020 The Regents of the University of California. +#All Rights Reserved +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + + +""" This file creates a set of Ruby caches for the MOESI CMP directory +protocol. +This protocol models two level cache hierarchy. The L1 cache is split into +instruction and data cache. + +This system support the memory size of up to 3GB. + +""" + +from __future__ import print_function +from __future__ import absolute_import + +import math + +from m5.defines import buildEnv +from m5.util import fatal, panic + +from m5.objects import * + +class MOESICMPDirCache(RubySystem): + + def __init__(self): + if buildEnv['PROTOCOL'] != 'MOESI_CMP_directory': + fatal("This system assumes MOESI_CMP_directory!") + + super(MOESICMPDirCache, self).__init__() + + self._numL2Caches = 8 + + def setup(self, system, cpus, mem_ctrls, dma_ports, iobus): + """Set up the Ruby cache subsystem. Note: This can't be done in the + constructor because many of these items require a pointer to the + ruby system (self). This causes infinite recursion in initialize() + if we do this in the __init__. + """ + # Ruby's global network. + self.network = MyNetwork(self) + + # MOESI_CMP_directory example uses 3 virtual networks + self.number_of_virtual_networks = 3 + self.network.number_of_virtual_networks = 3 + + # There is a single global list of all of the controllers to make it + # easier to connect everything to the global network. This can be + # customized depending on the topology/network requirements. + # L1 caches are private to a core, hence there are one L1 cache per CPU + # core. The number of L2 caches are dependent to the architecture. + self.controllers = \ + [L1Cache(system, self, cpu, self._numL2Caches) for cpu in cpus] + \ + [L2Cache(system, self, self._numL2Caches) for num in \ + range(self._numL2Caches)] + [DirController(self, \ + system.mem_ranges, mem_ctrls)] + [DMAController(self) for i \ + in range(len(dma_ports))] + + # Create one sequencer per CPU and dma controller. + # Sequencers for other controllers can be here here. + self.sequencers = [RubySequencer(version = i, + # Grab dcache from ctrl + dcache = self.controllers[i].L1Dcache, + clk_domain = self.controllers[i].clk_domain, + pio_request_port = iobus.cpu_side_ports, + mem_request_port = iobus.cpu_side_ports, + pio_response_port = iobus.mem_side_ports + ) for i in range(len(cpus))] + \ + [DMASequencer(version = i, + in_ports = port) + for i,port in enumerate(dma_ports) + ] + + for i,c in enumerate(self.controllers[:len(cpus)]): + c.sequencer = self.sequencers[i] + + #Connecting the DMA sequencer to DMA controller + for i,d in enumerate(self.controllers[-len(dma_ports):]): + i += len(cpus) + d.dma_sequencer = self.sequencers[i] + + self.num_of_sequencers = len(self.sequencers) + + # Create the network and connect the controllers. + # NOTE: This is quite different if using Garnet! + self.network.connectControllers(self.controllers) + self.network.setup_buffers() + + # Set up a proxy port for the system_port. Used for load binaries and + # other functional-only things. + self.sys_port_proxy = RubyPortProxy() + system.system_port = self.sys_port_proxy.in_ports + self.sys_port_proxy.pio_request_port = iobus.cpu_side_ports + + # Connect the cpu's cache, interrupt, and TLB ports to Ruby + for i,cpu in enumerate(cpus): + cpu.icache_port = self.sequencers[i].in_ports + cpu.dcache_port = self.sequencers[i].in_ports + cpu.createInterruptController() + isa = buildEnv['TARGET_ISA'] + if isa == 'x86': + cpu.interrupts[0].pio = self.sequencers[i].interrupt_out_port + cpu.interrupts[0].int_requestor = self.sequencers[i].in_ports + cpu.interrupts[0].int_responder = self.sequencers[i].interrupt_out_port + if isa == 'x86' or isa == 'arm': + cpu.mmu.connectWalkerPorts( + self.sequencers[i].in_ports, self.sequencers[i].in_ports) + +class L1Cache(L1Cache_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, system, ruby_system, cpu, num_l2Caches): + """Creating L1 cache controller. Consist of both instruction + and data cache. The size of data cache is 512KB and + 8-way set associative. The instruction cache is 32KB, + 2-way set associative. + """ + super(L1Cache, self).__init__() + + self.version = self.versionCount() + block_size_bits = int(math.log(system.cache_line_size, 2)) + l1i_size = '32kB' + l1i_assoc = '2' + l1d_size = '512kB' + l1d_assoc = '8' + # This is the cache memory object that stores the cache data and tags + self.L1Icache = RubyCache(size = l1i_size, + assoc = l1i_assoc, + start_index_bit = block_size_bits , + is_icache = True, + dataAccessLatency = 1, + tagAccessLatency = 1) + self.L1Dcache = RubyCache(size = l1d_size, + assoc = l1d_assoc, + start_index_bit = block_size_bits, + is_icache = False, + dataAccessLatency = 1, + tagAccessLatency = 1) + self.clk_domain = cpu.clk_domain + self.prefetcher = RubyPrefetcher() + self.send_evictions = self.sendEvicts(cpu) + self.transitions_per_cycle = 4 + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def getBlockSizeBits(self, system): + bits = int(math.log(system.cache_line_size, 2)) + if 2**bits != system.cache_line_size.value: + panic("Cache line size not a power of 2!") + return bits + + def sendEvicts(self, cpu): + """True if the CPU model or ISA requires sending evictions from caches + to the CPU. Two scenarios warrant forwarding evictions to the CPU: + 1. The O3 model must keep the LSQ coherent with the caches + 2. The x86 mwait instruction is built on top of coherence + 3. The local exclusive monitor in ARM systems + """ + if type(cpu) is DerivO3CPU or \ + buildEnv['TARGET_ISA'] in ('x86', 'arm'): + return True + return False + + def connectQueues(self, ruby_system): + """Connect all of the queues for this controller. + """ + self.mandatoryQueue = MessageBuffer() + self.requestFromL1Cache = MessageBuffer() + self.requestFromL1Cache.out_port = ruby_system.network.in_port + self.responseFromL1Cache = MessageBuffer() + self.responseFromL1Cache.out_port = ruby_system.network.in_port + self.requestToL1Cache = MessageBuffer() + self.requestToL1Cache.in_port = ruby_system.network.out_port + self.responseToL1Cache = MessageBuffer() + self.responseToL1Cache.in_port = ruby_system.network.out_port + self.triggerQueue = MessageBuffer(ordered = True) + +class L2Cache(L2Cache_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, system, ruby_system, num_l2Caches): + + super(L2Cache, self).__init__() + + self.version = self.versionCount() + # This is the cache memory object that stores the cache data and tags + self.L2cache = RubyCache(size = '1 MB', + assoc = 16, + start_index_bit = self.getL2StartIdx(system, + num_l2Caches), + dataAccessLatency = 20, + tagAccessLatency = 20) + + self.transitions_per_cycle = '4' + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def getL2StartIdx(self, system, num_l2caches): + l2_bits = int(math.log(num_l2caches, 2)) + bits = int(math.log(system.cache_line_size, 2)) + l2_bits + return bits + + + def connectQueues(self, ruby_system): + """Connect all of the queues for this controller. + """ + self.GlobalRequestFromL2Cache = MessageBuffer() + self.GlobalRequestFromL2Cache.out_port = ruby_system.network.in_port + self.L1RequestFromL2Cache = MessageBuffer() + self.L1RequestFromL2Cache.out_port = ruby_system.network.in_port + self.responseFromL2Cache = MessageBuffer() + self.responseFromL2Cache.out_port = ruby_system.network.in_port + + self.GlobalRequestToL2Cache = MessageBuffer() + self.GlobalRequestToL2Cache.in_port = ruby_system.network.out_port + self.L1RequestToL2Cache = MessageBuffer() + self.L1RequestToL2Cache.in_port = ruby_system.network.out_port + self.responseToL2Cache = MessageBuffer() + self.responseToL2Cache.in_port = ruby_system.network.out_port + self.triggerQueue = MessageBuffer(ordered = True) + + + +class DirController(Directory_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, ruby_system, ranges, mem_ctrls): + """ranges are the memory ranges assigned to this controller. + """ + if len(mem_ctrls) > 1: + panic("This cache system can only be connected to one mem ctrl") + super(DirController, self).__init__() + self.version = self.versionCount() + self.addr_ranges = ranges + self.ruby_system = ruby_system + self.directory = RubyDirectoryMemory() + # Connect this directory to the memory side. + self.memory_out_port = mem_ctrls[0].port + self.connectQueues(ruby_system) + + def connectQueues(self, ruby_system): + self.requestToDir = MessageBuffer() + self.requestToDir.in_port = ruby_system.network.out_port + self.responseToDir = MessageBuffer() + self.responseToDir.in_port = ruby_system.network.out_port + self.responseFromDir = MessageBuffer() + self.responseFromDir.out_port = ruby_system.network.in_port + self.forwardFromDir = MessageBuffer() + self.forwardFromDir.out_port = ruby_system.network.in_port + self.requestToMemory = MessageBuffer() + self.responseFromMemory = MessageBuffer() + self.triggerQueue = MessageBuffer(ordered = True) + +class DMAController(DMA_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, ruby_system): + super(DMAController, self).__init__() + self.version = self.versionCount() + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def connectQueues(self, ruby_system): + self.mandatoryQueue = MessageBuffer() + self.responseFromDir = MessageBuffer() + self.responseFromDir.in_port = ruby_system.network.out_port + self.reqToDir = MessageBuffer() + self.reqToDir.out_port = ruby_system.network.in_port + self.respToDir = MessageBuffer() + self.respToDir.out_port = ruby_system.network.in_port + self.triggerQueue = MessageBuffer(ordered = True) + + +class MyNetwork(SimpleNetwork): + """A simple point-to-point network. This doesn't not use garnet. + """ + + def __init__(self, ruby_system): + super(MyNetwork, self).__init__() + self.netifs = [] + self.ruby_system = ruby_system + + def connectControllers(self, controllers): + """Connect all of the controllers to routers and connec the routers + together in a point-to-point network. + """ + # Create one router/switch per controller in the system + self.routers = [Switch(router_id = i) for i in range(len(controllers))] + + # Make a link from each controller to the router. The link goes + # externally to the network. + self.ext_links = [SimpleExtLink(link_id=i, ext_node=c, + int_node=self.routers[i]) + for i, c in enumerate(controllers)] + + # Make an "internal" link (internal to the network) between every pair + # of routers. + link_count = 0 + self.int_links = [] + for ri in self.routers: + for rj in self.routers: + if ri == rj: continue # Don't connect a router to itself! + link_count += 1 + self.int_links.append(SimpleIntLink(link_id = link_count, + src_node = ri, + dst_node = rj)) diff --git a/configs-npb-gapbs/system/__init__.py b/configs-npb-gapbs/system/__init__.py new file mode 100755 index 0000000000..33cc74a09a --- /dev/null +++ b/configs-npb-gapbs/system/__init__.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2016 Jason Lowe-Power +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power + +from .system import MySystem +from .ruby_system import MyRubySystemOld +from .ruby_system_new import MyRubySystem diff --git a/configs-npb-gapbs/system/caches.py b/configs-npb-gapbs/system/caches.py new file mode 100755 index 0000000000..9e44211111 --- /dev/null +++ b/configs-npb-gapbs/system/caches.py @@ -0,0 +1,173 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2016 Jason Lowe-Power +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power + +""" Caches with options for a simple gem5 configuration script + +This file contains L1 I/D and L2 caches to be used in the simple +gem5 configuration script. +""" + +from m5.objects import Cache, L2XBar, StridePrefetcher + +# Some specific options for caches +# For all options see src/mem/cache/BaseCache.py + +class PrefetchCache(Cache): + + def __init__(self, options): + super(PrefetchCache, self).__init__() + if not options or options.no_prefetchers: + return + self.prefetcher = StridePrefetcher() + +class L1Cache(PrefetchCache): + """Simple L1 Cache with default values""" + + assoc = 8 + tag_latency = 1 + data_latency = 1 + response_latency = 1 + mshrs = 16 + tgts_per_mshr = 20 + writeback_clean = True + + def __init__(self, options=None): + super(L1Cache, self).__init__(options) + pass + + def connectBus(self, bus): + """Connect this cache to a memory-side bus""" + self.mem_side = bus.cpu_side_ports + + def connectCPU(self, cpu): + """Connect this cache's port to a CPU-side port + This must be defined in a subclass""" + raise NotImplementedError + +class L1ICache(L1Cache): + """Simple L1 instruction cache with default values""" + + def __init__(self, opts=None): + super(L1ICache, self).__init__(opts) + if not opts or not opts.l1i_size: + return + self.size = opts.l1i_size + + def connectCPU(self, cpu): + """Connect this cache's port to a CPU icache port""" + self.cpu_side = cpu.icache_port + +class L1DCache(L1Cache): + """Simple L1 data cache with default values""" + + def __init__(self, opts=None): + super(L1DCache, self).__init__(opts) + if not opts or not opts.l1d_size: + return + self.size = opts.l1d_size + + def connectCPU(self, cpu): + """Connect this cache's port to a CPU dcache port""" + self.cpu_side = cpu.dcache_port + +class MMUCache(Cache): + # Default parameters + size = '8kB' + assoc = 4 + tag_latency = 1 + data_latency = 1 + response_latency = 1 + mshrs = 20 + tgts_per_mshr = 12 + writeback_clean = True + + def __init__(self): + super(MMUCache, self).__init__() + + def connectCPU(self, cpu): + """Connect the CPU itb and dtb to the cache + Note: This creates a new crossbar + """ + self.mmubus = L2XBar() + self.cpu_side = self.mmubus.mem_side_ports + cpu.mmu.connectWalkerPorts( + self.mmubus.cpu_side_ports, self.mmubus.cpu_side_ports) + + def connectBus(self, bus): + """Connect this cache to a memory-side bus""" + self.mem_side = bus.cpu_side_ports + +class L2Cache(PrefetchCache): + """Simple L2 Cache with default values""" + + # Default parameters + assoc = 16 + tag_latency = 10 + data_latency = 10 + response_latency = 1 + mshrs = 20 + tgts_per_mshr = 12 + writeback_clean = True + + def __init__(self, opts=None): + super(L2Cache, self).__init__(opts) + if not opts or not opts.l2_size: + return + self.size = opts.l2_size + + def connectCPUSideBus(self, bus): + self.cpu_side = bus.mem_side_ports + + def connectMemSideBus(self, bus): + self.mem_side = bus.cpu_side_ports + +class L3Cache(Cache): + """Simple L3 Cache bank with default values + This assumes that the L3 is made up of multiple banks. This cannot + be used as a standalone L3 cache. + """ + + # Default parameters + assoc = 32 + tag_latency = 40 + data_latency = 40 + response_latency = 10 + mshrs = 256 + tgts_per_mshr = 12 + clusivity = 'mostly_excl' + + def __init__(self, opts): + super(L3Cache, self).__init__() + self.size = (opts.l3_size) + + def connectCPUSideBus(self, bus): + self.cpu_side = bus.mem_side_ports + + def connectMemSideBus(self, bus): + self.mem_side = bus.cpu_side_ports diff --git a/configs-npb-gapbs/system/fs_tools.py b/configs-npb-gapbs/system/fs_tools.py new file mode 100755 index 0000000000..5e5e2df6e4 --- /dev/null +++ b/configs-npb-gapbs/system/fs_tools.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2016 Jason Lowe-Power +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power + +from m5.objects import IdeDisk, CowDiskImage, RawDiskImage + +class CowDisk(IdeDisk): + + def __init__(self, filename): + super(CowDisk, self).__init__() + self.driveID = 'device0' + self.image = CowDiskImage(child=RawDiskImage(read_only=True), + read_only=False) + self.image.child.image_file = filename diff --git a/configs-npb-gapbs/system/ruby_system.py b/configs-npb-gapbs/system/ruby_system.py new file mode 100755 index 0000000000..7390af62fc --- /dev/null +++ b/configs-npb-gapbs/system/ruby_system.py @@ -0,0 +1,294 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2016 Jason Lowe-Power +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power + +import m5 +from m5.objects import * +from .fs_tools import * + + +class MyRubySystemOld(System): + + def __init__(self, kernel, disk, mem_sys, num_cpus, opts, restore=False): + super(MyRubySystemOld, self).__init__() + self._opts = opts + + # Use parallel if using KVM. Don't use parallel is restoring cpt + self._host_parallel = not restore + self._restore = restore + + # Set up the clock domain and the voltage domain + self.clk_domain = SrcClockDomain() + self.clk_domain.clock = '5GHz' + self.clk_domain.voltage_domain = VoltageDomain() + + self.mem_ranges = [AddrRange(Addr('3GiB')), # All data + AddrRange(0xC0000000, size=0x100000), # For I/0 + ] + + self.initFS(num_cpus) + + # Replace these paths with the path to your disk images. + # The first disk is the root disk. The second could be used for swap + # or anything else. + self.setDiskImages(disk, disk) + + # Change this path to point to the kernel you want to use + self.workload.object_file = kernel + # Options specified on the kernel command line + boot_options = ['earlyprintk=ttyS0', 'console=ttyS0', 'lpj=7999923', + 'root=/dev/hda1'] + + self.workload.command_line = ' '.join(boot_options) + + # Create the CPUs for our system. + self.createCPU(num_cpus) + + # self.intrctrl = IntrControl() + self.createMemoryControllers() + + # Create the cache hierarchy for the system. + if mem_sys == 'MI_example': + from .MI_example_caches import MIExampleSystem + self.caches = MIExampleSystem() + elif mem_sys == 'MESI_Two_Level': + from .MESI_Two_Level import MESITwoLevelCache + self.caches = MESITwoLevelCache() + elif mem_sys == 'MOESI_CMP_directory': + from .MOESI_CMP_directory import MOESICMPDirCache + self.caches = MOESICMPDirCache() + if self._restore: + cpus = self.o3Cpu + else: + cpus = self.cpu + self.caches.setup(self, cpus, self.mem_ctrl, self.mem_ranges[:1], + [self.pc.south_bridge.ide.dma, + self.iobus.mem_side_ports], + self.iobus) + + self.caches.access_backing_store = True + self.caches.phys_mem = [SimpleMemory(range=self.mem_ranges[0], + in_addr_map=False)] + + if self._host_parallel: + # To get the KVM CPUs to run on different host CPUs + # Specify a different event queue for each CPU + for i,cpu in enumerate(self.cpu): + for obj in cpu.descendants(): + obj.eventq_index = 0 + + # the number of eventqs are set based + # on experiments with few benchmarks + + cpu.eventq_index = i + 1 + + def getHostParallel(self): + return self._host_parallel + + def totalInsts(self): + return sum([cpu.totalInsts() for cpu in self.cpu]) + + def createCPUThreads(self, cpu): + for c in cpu: + c.createThreads() + + def createCPU(self, num_cpus): + + if not self._restore: + # Note KVM needs a VM and atomic_noncaching + self.cpu = [X86KvmCPU(cpu_id = i) + for i in range(num_cpus)] + self.kvm_vm = KvmVM() + self.mem_mode = 'atomic_noncaching' + self.createCPUThreads(self.cpu) + + self.atomicCpu = [X86AtomicSimpleCPU(cpu_id = i, + switched_out = True) + for i in range(num_cpus)] + self.createCPUThreads(self.atomicCpu) + + self.timingCpu = [X86TimingSimpleCPU(cpu_id = i, + switched_out = True) + for i in range(num_cpus)] + self.createCPUThreads(self.timingCpu) + + self.o3Cpu = [X86O3CPU(cpu_id = i, + switched_out = True) + for i in range(num_cpus)] + self.createCPUThreads(self.o3Cpu) + else: + self.o3Cpu = [X86O3CPU(cpu_id = i) + for i in range(num_cpus)] + self.mem_mode = 'timing' + self.createCPUThreads(self.o3Cpu) + + def switchCpus(self, old, new): + assert(new[0].switchedOut()) + m5.switchCpus(self, list(zip(old, new))) + + def setDiskImages(self, img_path_1, img_path_2): + disk0 = CowDisk(img_path_1) + disk2 = CowDisk(img_path_2) + self.pc.south_bridge.ide.disks = [disk0, disk2] + + def createMemoryControllers(self): + + self.mem_ctrl = PolicyManager(range=self.mem_ranges[0], kvm_map=False) + self.mem_ctrl.static_frontend_latency = "10ns" + self.mem_ctrl.static_backend_latency = "10ns" + + self.mem_ctrl.loc_mem_policy = 'Rambus' # 'CascadeLakeNoPartWrs' # 'Oracle' # + + # self.mem_ctrl.bypass_dcache = True + + # TDRAM cache + self.loc_mem_ctrl = MemCtrl() + self.loc_mem_ctrl.consider_oldest_write = True + self.loc_mem_ctrl.oldest_write_age_threshold = 2500000 + self.loc_mem_ctrl.dram = TDRAM_32(range=self.mem_ranges[0], in_addr_map=False, kvm_map=False) + + + self.mem_ctrl.loc_mem = self.loc_mem_ctrl.dram + self.loc_mem_ctrl.static_frontend_latency = "1ns" + self.loc_mem_ctrl.static_backend_latency = "1ns" + self.loc_mem_ctrl.static_frontend_latency_tc = "0ns" + self.loc_mem_ctrl.static_backend_latency_tc = "0ns" + + # main memory + self.far_mem_ctrl = MemCtrl() + self.far_mem_ctrl.dram = DDR4_2400_16x4(range=self.mem_ranges[0], in_addr_map=False, kvm_map=False) + self.far_mem_ctrl.static_frontend_latency = "1ns" + self.far_mem_ctrl.static_backend_latency = "1ns" + + self.loc_mem_ctrl.port = self.mem_ctrl.loc_req_port + self.far_mem_ctrl.port = self.mem_ctrl.far_req_port + + self.mem_ctrl.orb_max_size = 128 + self.mem_ctrl.dram_cache_size = "128MiB" + + self.loc_mem_ctrl.dram.read_buffer_size = 64 + self.loc_mem_ctrl.dram.write_buffer_size = 64 + + self.far_mem_ctrl.dram.read_buffer_size = 64 + self.far_mem_ctrl.dram.write_buffer_size = 64 + + + + def initFS(self, cpus): + self.pc = Pc() + + self.workload = X86FsLinux() + + # North Bridge + self.iobus = IOXBar() + + # connect the io bus + # Note: pass in a reference to where Ruby will connect to in the future + # so the port isn't connected twice. + self.pc.attachIO(self.iobus, [self.pc.south_bridge.ide.dma]) + + ############################################### + + # Add in a Bios information structure. + self.workload.smbios_table.structures = [X86SMBiosBiosInformation()] + + # Set up the Intel MP table + base_entries = [] + ext_entries = [] + for i in range(cpus): + bp = X86IntelMPProcessor( + local_apic_id = i, + local_apic_version = 0x14, + enable = True, + bootstrap = (i ==0)) + base_entries.append(bp) + io_apic = X86IntelMPIOAPIC( + id = cpus, + version = 0x11, + enable = True, + address = 0xfec00000) + self.pc.south_bridge.io_apic.apic_id = io_apic.id + base_entries.append(io_apic) + pci_bus = X86IntelMPBus(bus_id = 0, bus_type='PCI ') + base_entries.append(pci_bus) + isa_bus = X86IntelMPBus(bus_id = 1, bus_type='ISA ') + base_entries.append(isa_bus) + connect_busses = X86IntelMPBusHierarchy(bus_id=1, + subtractive_decode=True, parent_bus=0) + ext_entries.append(connect_busses) + pci_dev4_inta = X86IntelMPIOIntAssignment( + interrupt_type = 'INT', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 0, + source_bus_irq = 0 + (4 << 2), + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = 16) + base_entries.append(pci_dev4_inta) + def assignISAInt(irq, apicPin): + assign_8259_to_apic = X86IntelMPIOIntAssignment( + interrupt_type = 'ExtInt', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 1, + source_bus_irq = irq, + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = 0) + base_entries.append(assign_8259_to_apic) + assign_to_apic = X86IntelMPIOIntAssignment( + interrupt_type = 'INT', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 1, + source_bus_irq = irq, + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = apicPin) + base_entries.append(assign_to_apic) + assignISAInt(0, 2) + assignISAInt(1, 1) + for i in range(3, 15): + assignISAInt(i, i) + self.workload.intel_mp_table.base_entries = base_entries + self.workload.intel_mp_table.ext_entries = ext_entries + + entries = \ + [ + # Mark the first megabyte of memory as reserved + X86E820Entry(addr = 0, size = '639kB', range_type = 1), + X86E820Entry(addr = 0x9fc00, size = '385kB', range_type = 2), + # Mark the rest of physical memory as available + X86E820Entry(addr = 0x100000, + size = '%dB' % (self.mem_ranges[0].size() - 0x100000), + range_type = 1), + ] + + # Reserve the last 16kB of the 32-bit address space for m5ops + entries.append(X86E820Entry(addr = 0xFFFF0000, size = '64kB', + range_type=2)) + + self.workload.e820_table.entries = entries diff --git a/configs-npb-gapbs/system/ruby_system_new.py b/configs-npb-gapbs/system/ruby_system_new.py new file mode 100644 index 0000000000..96711da955 --- /dev/null +++ b/configs-npb-gapbs/system/ruby_system_new.py @@ -0,0 +1,363 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2016 Jason Lowe-Power +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power + +import m5 +from m5.objects import * +from .fs_tools import * + + +class MyRubySystem(System): + def __init__( + self, + kernel, + disk, + mem_sys, + num_cpus, + assoc, + dcache_size, + main_mem_size, + policy, + is_link, + link_lat, + bypass, + opts, + restore=False, + ): + super(MyRubySystem, self).__init__() + print("Creating MyRubySystem") + self._opts = opts + + # Use parallel if using KVM. Don't use parallel is restoring cpt + self._host_parallel = not restore + self._restore = restore + + # Set up the clock domain and the voltage domain + self.clk_domain = SrcClockDomain() + self.clk_domain.clock = "5GHz" + self.clk_domain.voltage_domain = VoltageDomain() + + self.mem_ranges = [ + AddrRange(Addr("128MiB")), # kernel data + AddrRange(0xC0000000, size=0x100000), # For I/0 + AddrRange( + 0x100000000, size=main_mem_size + ), # starting at 4GiB for 16 GiB + ] + + self.initFS(num_cpus) + + # Replace these paths with the path to your disk images. + # The first disk is the root disk. The second could be used for swap + # or anything else. + self.setDiskImages(disk, disk) + + # Change this path to point to the kernel you want to use + self.workload.object_file = kernel + # Options specified on the kernel command line + boot_options = [ + "earlyprintk=ttyS0", + "console=ttyS0", + "lpj=7999923", + "root=/dev/hda1", + ] + + self.workload.command_line = " ".join(boot_options) + + # Create the CPUs for our system. + self.createCPU(num_cpus) + + # self.intrctrl = IntrControl() + self._createMemoryControllers( + assoc, dcache_size, policy, is_link, link_lat, bypass + ) + + # Create the cache hierarchy for the system. + if mem_sys == "MI_example": + from .MI_example_caches import MIExampleSystem + + self.caches = MIExampleSystem() + elif mem_sys == "MESI_Two_Level": + from .MESI_Two_Level import MESITwoLevelCache + + self.caches = MESITwoLevelCache() + elif mem_sys == "MOESI_CMP_directory": + from .MOESI_CMP_directory import MOESICMPDirCache + + self.caches = MOESICMPDirCache() + if self._restore: + cpus = self.o3Cpu + else: + cpus = self.cpu + self.caches.setup( + self, + cpus, + [self.kernel_mem_ctrl, self.mem_ctrl], + [self.mem_ranges[0], self.mem_ranges[2]], + [self.pc.south_bridge.ide.dma, self.iobus.mem_side_ports], + self.iobus, + ) + + self.caches.access_backing_store = True + self.caches.phys_mem = [ + SimpleMemory(range=self.mem_ranges[0], in_addr_map=False), + SimpleMemory(range=self.mem_ranges[2], in_addr_map=False), + ] + + if self._host_parallel: + # To get the KVM CPUs to run on different host CPUs + # Specify a different event queue for each CPU + for i, cpu in enumerate(self.cpu): + for obj in cpu.descendants(): + obj.eventq_index = 0 + + # the number of eventqs are set based + # on experiments with few benchmarks + + cpu.eventq_index = i + 1 + + def getHostParallel(self): + return self._host_parallel + + def totalInsts(self): + return sum([cpu.totalInsts() for cpu in self.cpu]) + + def createCPUThreads(self, cpu): + for c in cpu: + c.createThreads() + + def createCPU(self, num_cpus): + + if not self._restore: + # Note KVM needs a VM and atomic_noncaching + self.cpu = [X86KvmCPU(cpu_id=i) for i in range(num_cpus)] + self.kvm_vm = KvmVM() + self.mem_mode = "atomic_noncaching" + self.createCPUThreads(self.cpu) + + self.atomicCpu = [ + X86AtomicSimpleCPU(cpu_id=i, switched_out=True) + for i in range(num_cpus) + ] + self.createCPUThreads(self.atomicCpu) + + self.timingCpu = [ + X86TimingSimpleCPU(cpu_id=i, switched_out=True) + for i in range(num_cpus) + ] + self.createCPUThreads(self.timingCpu) + + self.o3Cpu = [ + X86O3CPU(cpu_id=i, switched_out=True) for i in range(num_cpus) + ] + self.createCPUThreads(self.o3Cpu) + else: + self.o3Cpu = [X86O3CPU(cpu_id=i) for i in range(num_cpus)] + self.mem_mode = "timing" + self.createCPUThreads(self.o3Cpu) + + def switchCpus(self, old, new): + assert new[0].switchedOut() + m5.switchCpus(self, list(zip(old, new))) + + def setDiskImages(self, img_path_1, img_path_2): + disk0 = CowDisk(img_path_1) + disk2 = CowDisk(img_path_2) + self.pc.south_bridge.ide.disks = [disk0, disk2] + + def _createKernelMemoryController(self, cls): + return MemCtrl(dram=cls(range=self.mem_ranges[0], kvm_map=False)) + + def _createMemoryControllers( + self, assoc, dcache_size, policy, is_link, link_lat, bypass + ): + self.kernel_mem_ctrl = self._createKernelMemoryController( + DDR3_1600_8x8 + ) + + self.mem_ctrl = PolicyManager(range=self.mem_ranges[2], kvm_map=False) + self.mem_ctrl.static_frontend_latency = "10ns" + self.mem_ctrl.static_backend_latency = "10ns" + + self.mem_ctrl.loc_mem_policy = policy + + self.mem_ctrl.assoc = assoc + + if bypass == 0: + self.mem_ctrl.bypass_dcache = False + elif bypass == 1: + self.mem_ctrl.bypass_dcache = True + + # TDRAM cache + self.loc_mem_ctrl = MemCtrl() + self.loc_mem_ctrl.consider_oldest_write = True + self.loc_mem_ctrl.oldest_write_age_threshold = 2500000 + self.loc_mem_ctrl.dram = TDRAM_32( + range=self.mem_ranges[2], in_addr_map=False, kvm_map=False + ) + + self.mem_ctrl.loc_mem = self.loc_mem_ctrl.dram + self.loc_mem_ctrl.static_frontend_latency = "1ns" + self.loc_mem_ctrl.static_backend_latency = "1ns" + self.loc_mem_ctrl.static_frontend_latency_tc = "0ns" + self.loc_mem_ctrl.static_backend_latency_tc = "0ns" + + # main memory + self.far_mem_ctrl = MemCtrl() + self.far_mem_ctrl.dram = DDR4_2400_16x4( + range=self.mem_ranges[2], in_addr_map=False, kvm_map=False + ) + self.far_mem_ctrl.static_frontend_latency = "1ns" + self.far_mem_ctrl.static_backend_latency = "1ns" + + self.loc_mem_ctrl.port = self.mem_ctrl.loc_req_port + + # far backing store + if is_link == 1: + self.membusPolManFarMem = L2XBar(width=64) + self.membusPolManFarMem.cpu_side_ports = self.mem_ctrl.far_req_port + self.membusPolManFarMem.mem_side_ports = self.far_mem_ctrl.port + self.membusPolManFarMem.frontend_latency = link_lat + self.membusPolManFarMem.response_latency = link_lat + else: + self.far_mem_ctrl.port = self.mem_ctrl.far_req_port + + self.mem_ctrl.orb_max_size = 128 + self.mem_ctrl.dram_cache_size = dcache_size + + self.loc_mem_ctrl.dram.read_buffer_size = 64 + self.loc_mem_ctrl.dram.write_buffer_size = 64 + + self.far_mem_ctrl.dram.read_buffer_size = 64 + self.far_mem_ctrl.dram.write_buffer_size = 64 + + def initFS(self, cpus): + self.pc = Pc() + + self.workload = X86FsLinux() + + # North Bridge + self.iobus = IOXBar() + + # connect the io bus + # Note: pass in a reference to where Ruby will connect to in the future + # so the port isn't connected twice. + self.pc.attachIO(self.iobus, [self.pc.south_bridge.ide.dma]) + + ############################################### + + # Add in a Bios information structure. + self.workload.smbios_table.structures = [X86SMBiosBiosInformation()] + + # Set up the Intel MP table + base_entries = [] + ext_entries = [] + for i in range(cpus): + bp = X86IntelMPProcessor( + local_apic_id=i, + local_apic_version=0x14, + enable=True, + bootstrap=(i == 0), + ) + base_entries.append(bp) + io_apic = X86IntelMPIOAPIC( + id=cpus, version=0x11, enable=True, address=0xFEC00000 + ) + self.pc.south_bridge.io_apic.apic_id = io_apic.id + base_entries.append(io_apic) + pci_bus = X86IntelMPBus(bus_id=0, bus_type="PCI ") + base_entries.append(pci_bus) + isa_bus = X86IntelMPBus(bus_id=1, bus_type="ISA ") + base_entries.append(isa_bus) + connect_busses = X86IntelMPBusHierarchy( + bus_id=1, subtractive_decode=True, parent_bus=0 + ) + ext_entries.append(connect_busses) + pci_dev4_inta = X86IntelMPIOIntAssignment( + interrupt_type="INT", + polarity="ConformPolarity", + trigger="ConformTrigger", + source_bus_id=0, + source_bus_irq=0 + (4 << 2), + dest_io_apic_id=io_apic.id, + dest_io_apic_intin=16, + ) + base_entries.append(pci_dev4_inta) + + def assignISAInt(irq, apicPin): + assign_8259_to_apic = X86IntelMPIOIntAssignment( + interrupt_type="ExtInt", + polarity="ConformPolarity", + trigger="ConformTrigger", + source_bus_id=1, + source_bus_irq=irq, + dest_io_apic_id=io_apic.id, + dest_io_apic_intin=0, + ) + base_entries.append(assign_8259_to_apic) + assign_to_apic = X86IntelMPIOIntAssignment( + interrupt_type="INT", + polarity="ConformPolarity", + trigger="ConformTrigger", + source_bus_id=1, + source_bus_irq=irq, + dest_io_apic_id=io_apic.id, + dest_io_apic_intin=apicPin, + ) + base_entries.append(assign_to_apic) + + assignISAInt(0, 2) + assignISAInt(1, 1) + for i in range(3, 15): + assignISAInt(i, i) + self.workload.intel_mp_table.base_entries = base_entries + self.workload.intel_mp_table.ext_entries = ext_entries + + entries = [ + # Mark the first megabyte of memory as reserved + X86E820Entry(addr=0, size="639kB", range_type=1), + X86E820Entry(addr=0x9FC00, size="385kB", range_type=2), + # Mark the rest of physical memory as available + X86E820Entry( + addr=0x100000, + size="%dB" % (self.mem_ranges[0].size() - 0x100000), + range_type=1, + ), + X86E820Entry( + addr=0x100000000, + size="%dB" % (self.mem_ranges[2].size()), + range_type=1, + ), + ] + + # Reserve the last 16kB of the 32-bit address space for m5ops + entries.append( + X86E820Entry(addr=0xFFFF0000, size="64kB", range_type=2) + ) + + self.workload.e820_table.entries = entries diff --git a/configs-npb-gapbs/system/system.py b/configs-npb-gapbs/system/system.py new file mode 100755 index 0000000000..6365b39d63 --- /dev/null +++ b/configs-npb-gapbs/system/system.py @@ -0,0 +1,414 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2018 The Regents of the University of California +# All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power + +import m5 +from m5.objects import * +from .fs_tools import * +from .caches import * + + +class MySystem(System): + + def __init__(self, kernel, disk, num_cpus, opts, no_kvm=False): + super(MySystem, self).__init__() + self._opts = opts + self._no_kvm = no_kvm + + self._host_parallel = not self._opts.no_host_parallel + + # Set up the clock domain and the voltage domain + self.clk_domain = SrcClockDomain() + self.clk_domain.clock = '2.3GHz' + self.clk_domain.voltage_domain = VoltageDomain() + + #mem_size = '32GB' + #self.mem_ranges = [AddrRange('100MB'), # For kernel + # AddrRange(0xC0000000, size=0x100000), # For I/0 + # AddrRange(Addr('4GB'), size = mem_size) # All data + # ] + + + self.mem_ranges = [AddrRange(Addr('2GiB')), # All data + AddrRange(0xC0000000, size=0x100000), # For I/0 + ] + + # Create the main memory bus + # This connects to main memory + self.membus = SystemXBar(width = 64) # 64-byte width + self.membus.badaddr_responder = BadAddr() + self.membus.default = Self.badaddr_responder.pio + + # Set up the system port for functional access from the simulator + self.system_port = self.membus.cpu_side_ports + + self.initFS(self.membus, num_cpus) + + + # Replace these paths with the path to your disk images. + # The first disk is the root disk. The second could be used for swap + # or anything else. + + self.setDiskImages(disk, disk) + + if opts.second_disk: + self.setDiskImages(disk, opts.second_disk) + else: + self.setDiskImages(disk, disk) + + # Change this path to point to the kernel you want to use + self.workload.object_file = kernel + # Options specified on the kernel command line + boot_options = ['earlyprintk=ttyS0', 'console=ttyS0', 'lpj=7999923', + 'root=/dev/hda1'] + + self.workload.command_line = ' '.join(boot_options) + + # Create the CPUs for our system. + self.createCPU(num_cpus) + + # Create the cache heirarchy for the system. + self.createCacheHierarchy() + + # Set up the interrupt controllers for the system (x86 specific) + self.setupInterrupts() + + # self.intrctrl = IntrControl() + + self.createMemoryControllersDDR4() + + if self._host_parallel: + # To get the KVM CPUs to run on different host CPUs + # Specify a different event queue for each CPU + for i,cpu in enumerate(self.cpu): + for obj in cpu.descendants(): + obj.eventq_index = 0 + + # the number of eventqs are set based + # on experiments with few benchmarks + + if len(self.cpu) > 16: + cpu.eventq_index = (i/4) + 1 + else: + cpu.eventq_index = (i/2) + 1 + def getHostParallel(self): + return self._host_parallel + + def totalInsts(self): + return sum([cpu.totalInsts() for cpu in self.cpu]) + + def createCPUThreads(self, cpu): + for c in cpu: + c.createThreads() + + def createCPU(self, num_cpus): + if self._no_kvm: + self.cpu = [AtomicSimpleCPU(cpu_id = i, switched_out = False) + for i in range(num_cpus)] + self.createCPUThreads(self.cpu) + self.mem_mode = 'timing' + + else: + # Note KVM needs a VM and atomic_noncaching + self.cpu = [X86KvmCPU(cpu_id = i) + for i in range(num_cpus)] + self.createCPUThreads(self.cpu) + self.kvm_vm = KvmVM() + self.mem_mode = 'atomic_noncaching' + + self.atomicCpu = [AtomicSimpleCPU(cpu_id = i, + switched_out = True) + for i in range(num_cpus)] + self.createCPUThreads(self.atomicCpu) + + self.timingCpu = [TimingSimpleCPU(cpu_id = i, + switched_out = True) + for i in range(num_cpus)] + + self.createCPUThreads(self.timingCpu) + + def switchCpus(self, old, new): + assert(new[0].switchedOut()) + m5.switchCpus(self, list(zip(old, new))) + + def setDiskImages(self, img_path_1, img_path_2): + disk0 = CowDisk(img_path_1) + disk2 = CowDisk(img_path_2) + self.pc.south_bridge.ide.disks = [disk0, disk2] + + def createCacheHierarchy(self): + # Create an L3 cache (with crossbar) + self.l3bus = L2XBar(width = 64, + snoop_filter = SnoopFilter(max_capacity='32MB')) + + for cpu in self.cpu: + # Create a memory bus, a coherent crossbar, in this case + cpu.l2bus = L2XBar() + + # Create an L1 instruction and data cache + cpu.icache = L1ICache(self._opts) + cpu.dcache = L1DCache(self._opts) + cpu.mmucache = MMUCache() + + # Connect the instruction and data caches to the CPU + cpu.icache.connectCPU(cpu) + cpu.dcache.connectCPU(cpu) + cpu.mmucache.connectCPU(cpu) + + # Hook the CPU ports up to the l2bus + cpu.icache.connectBus(cpu.l2bus) + cpu.dcache.connectBus(cpu.l2bus) + cpu.mmucache.connectBus(cpu.l2bus) + + # Create an L2 cache and connect it to the l2bus + cpu.l2cache = L2Cache(self._opts) + cpu.l2cache.connectCPUSideBus(cpu.l2bus) + + # Connect the L2 cache to the L3 bus + cpu.l2cache.connectMemSideBus(self.l3bus) + + self.l3cache = L3Cache(self._opts) + self.l3cache.connectCPUSideBus(self.l3bus) + + # Connect the L3 cache to the membus + self.l3cache.connectMemSideBus(self.membus) + + def setupInterrupts(self): + for cpu in self.cpu: + # create the interrupt controller CPU and connect to the membus + cpu.createInterruptController() + + # For x86 only, connect interrupts to the memory + # Note: these are directly connected to the memory bus and + # not cached + cpu.interrupts[0].pio = self.membus.mem_side_ports + cpu.interrupts[0].int_requestor = self.membus.cpu_side_ports + cpu.interrupts[0].int_responder = self.membus.mem_side_ports + + # Memory latency: Using the smaller number from [3]: 96ns + def createMemoryControllersDDR4(self): + self._createMemoryControllers(1, DDR4_2400_16x4) + + def _createMemoryControllers(self, num, cls): + + self.mem_ctrl = PolicyManager(range=self.mem_ranges[0]) + # FOR DDR4 + # self.mem_ctrl.tRP = '14.16ns' + # self.mem_ctrl.tRCD_RD = '14.16ns' + # self.mem_ctrl.tRL = '14.16ns' + + # self.loc_mem_ctrl = HBMCtrl() + # self.loc_mem_ctrl.dram = HBM_2000_4H_1x64(range=AddrRange(start = '0', end = '1GiB', masks = [1 << 6], intlvMatch = 0), in_addr_map=False, kvm_map=False, null=True) + # self.loc_mem_ctrl.dram_2 = HBM_2000_4H_1x64(range=AddrRange(start = '0', end = '1GiB', masks = [1 << 6], intlvMatch = 1), in_addr_map=False, kvm_map=False, null=True) + + self.loc_mem_ctrl = MemCtrl() + self.loc_mem_ctrl.dram = DDR4_2400_16x4(range=self.mem_ranges[0], in_addr_map=False, kvm_map=False) + + self.far_mem_ctrl = MemCtrl() + self.far_mem_ctrl.dram = DDR4_2400_16x4(range=self.mem_ranges[0], in_addr_map=False, kvm_map=False) + + self.loc_mem_ctrl.port = self.mem_ctrl.loc_req_port + self.far_mem_ctrl.port = self.mem_ctrl.far_req_port + + self.mem_ctrl.dram_cache_size = "128MiB" + + # self.mem_ctrl = MemCtrl() + # self.mem_ctrl.dram = DDR4_2400_16x4(range=self.mem_ranges[0]) + + def _createKernelMemoryController(self, cls): + return MemCtrl(dram = cls(range = self.mem_ranges[0]), + port = self.membus.mem_side_ports) + + def _getInterleaveRanges(self, rng, num, intlv_low_bit, xor_low_bit): + from math import log + bits = int(log(num, 2)) + if 2**bits != num: + m5.fatal("Non-power of two number of memory controllers") + + intlv_bits = bits + ranges = [ + AddrRange(start=rng.start, + end=rng.end, + intlvHighBit = intlv_low_bit + intlv_bits - 1, + xorHighBit = xor_low_bit + intlv_bits - 1, + intlvBits = intlv_bits, + intlvMatch = i) + for i in range(num) + ] + + return ranges + + def initFS(self, membus, cpus): + self.pc = Pc() + self.workload = X86FsLinux() + + # Constants similar to x86_traits.hh + IO_address_space_base = 0x8000000000000000 + pci_config_address_space_base = 0xc000000000000000 + interrupts_address_space_base = 0xa000000000000000 + APIC_range_size = 1 << 12 + + # North Bridge + self.iobus = IOXBar() + self.bridge = Bridge(delay='50ns') + self.bridge.mem_side_port = self.iobus.cpu_side_ports + self.bridge.cpu_side_port = membus.mem_side_ports + # Allow the bridge to pass through: + # 1) kernel configured PCI device memory map address: address range + # [0xC0000000, 0xFFFF0000). (The upper 64kB are reserved for m5ops.) + # 2) the bridge to pass through the IO APIC (two pages, already + # contained in 1), + # 3) everything in the IO address range up to the local APIC, and + # 4) then the entire PCI address space and beyond. + self.bridge.ranges = \ + [ + AddrRange(0xC0000000, 0xFFFF0000), + AddrRange(IO_address_space_base, + interrupts_address_space_base - 1), + AddrRange(pci_config_address_space_base, + Addr.max) + ] + + # Create a bridge from the IO bus to the memory bus to allow access + # to the local APIC (two pages) + self.apicbridge = Bridge(delay='50ns') + self.apicbridge.cpu_side_port = self.iobus.mem_side_ports + self.apicbridge.mem_side_port = membus.cpu_side_ports + self.apicbridge.ranges = [AddrRange(interrupts_address_space_base, + interrupts_address_space_base + + cpus * APIC_range_size + - 1)] + + # connect the io bus + self.pc.attachIO(self.iobus) + + # Add a tiny cache to the IO bus. + # This cache is required for the classic memory model for coherence + self.iocache = Cache(assoc=8, + tag_latency = 50, + data_latency = 50, + response_latency = 50, + mshrs = 20, + size = '1kB', + tgts_per_mshr = 12, + addr_ranges = self.mem_ranges) + self.iocache.cpu_side = self.iobus.mem_side_ports + self.iocache.mem_side = self.membus.cpu_side_ports + + ############################################### + + # Add in a Bios information structure. + self.workload.smbios_table.structures = [X86SMBiosBiosInformation()] + + # Set up the Intel MP table + base_entries = [] + ext_entries = [] + for i in range(cpus): + bp = X86IntelMPProcessor( + local_apic_id = i, + local_apic_version = 0x14, + enable = True, + bootstrap = (i ==0)) + base_entries.append(bp) + io_apic = X86IntelMPIOAPIC( + id = cpus, + version = 0x11, + enable = True, + address = 0xfec00000) + self.pc.south_bridge.io_apic.apic_id = io_apic.id + base_entries.append(io_apic) + pci_bus = X86IntelMPBus(bus_id = 0, bus_type='PCI ') + base_entries.append(pci_bus) + isa_bus = X86IntelMPBus(bus_id = 1, bus_type='ISA ') + base_entries.append(isa_bus) + connect_busses = X86IntelMPBusHierarchy(bus_id=1, + subtractive_decode=True, parent_bus=0) + ext_entries.append(connect_busses) + pci_dev4_inta = X86IntelMPIOIntAssignment( + interrupt_type = 'INT', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 0, + source_bus_irq = 0 + (4 << 2), + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = 16) + base_entries.append(pci_dev4_inta) + def assignISAInt(irq, apicPin): + assign_8259_to_apic = X86IntelMPIOIntAssignment( + interrupt_type = 'ExtInt', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 1, + source_bus_irq = irq, + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = 0) + base_entries.append(assign_8259_to_apic) + assign_to_apic = X86IntelMPIOIntAssignment( + interrupt_type = 'INT', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 1, + source_bus_irq = irq, + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = apicPin) + base_entries.append(assign_to_apic) + assignISAInt(0, 2) + assignISAInt(1, 1) + for i in range(3, 15): + assignISAInt(i, i) + self.workload.intel_mp_table.base_entries = base_entries + self.workload.intel_mp_table.ext_entries = ext_entries + + entries = \ + [ + # Mark the first megabyte of memory as reserved + X86E820Entry(addr = 0, size = '639kB', range_type = 1), + X86E820Entry(addr = 0x9fc00, size = '385kB', range_type = 2), + # Mark the rest of physical memory as available + X86E820Entry(addr = 0x100000, + size = '%dB' % (self.mem_ranges[0].size() - 0x100000), + range_type = 1), + ] + # Mark [mem_size, 3GB) as reserved if memory less than 3GB, which + # force IO devices to be mapped to [0xC0000000, 0xFFFF0000). Requests + # to this specific range can pass though bridge to iobus. + #entries.append(X86E820Entry(addr = self.mem_ranges[0].size(), + # size='%dB' % (0xC0000000 - self.mem_ranges[0].size()), + # range_type=2)) + + # Reserve the last 16kB of the 32-bit address space for m5ops + entries.append(X86E820Entry(addr = 0xFFFF0000, size = '64kB', + range_type=2)) + + # Add the rest of memory. This is where all the actual data is + #entries.append(X86E820Entry(addr = self.mem_ranges[-1].start, + # size='%dB' % (self.mem_ranges[-1].size()), + # range_type=1)) + + self.workload.e820_table.entries = entries + diff --git a/configs-npb-gapbs/system/system_back.py b/configs-npb-gapbs/system/system_back.py new file mode 100755 index 0000000000..8a645b918f --- /dev/null +++ b/configs-npb-gapbs/system/system_back.py @@ -0,0 +1,397 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2018 The Regents of the University of California +# All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power + +import m5 +from m5.objects import * +from .fs_tools import * +from .caches import * + + +class MySystem(System): + + def __init__(self, kernel, disk, num_cpus, opts, no_kvm=False): + super(MySystem, self).__init__() + self._opts = opts + self._no_kvm = no_kvm + + self._host_parallel = not self._opts.no_host_parallel + + # Set up the clock domain and the voltage domain + self.clk_domain = SrcClockDomain() + self.clk_domain.clock = '2.3GHz' + self.clk_domain.voltage_domain = VoltageDomain() + + mem_size = '32GB' + self.mem_ranges = [AddrRange('100MB'), # For kernel + AddrRange(0xC0000000, size=0x100000), # For I/0 + AddrRange(Addr('4GB'), size = mem_size) # All data + ] + + + self.mem_ranges = [AddrRange(Addr('3GB')), # All data + AddrRange(0xC0000000, size=0x100000), # For I/0 + ] + + # Create the main memory bus + # This connects to main memory + self.membus = SystemXBar(width = 64) # 64-byte width + self.membus.badaddr_responder = BadAddr() + self.membus.default = Self.badaddr_responder.pio + + # Set up the system port for functional access from the simulator + self.system_port = self.membus.cpu_side_ports + + self.initFS(self.membus, num_cpus) + + + # Replace these paths with the path to your disk images. + # The first disk is the root disk. The second could be used for swap + # or anything else. + + self.setDiskImages(disk, disk) + + if opts.second_disk: + self.setDiskImages(disk, opts.second_disk) + else: + self.setDiskImages(disk, disk) + + # Change this path to point to the kernel you want to use + self.workload.object_file = kernel + # Options specified on the kernel command line + boot_options = ['earlyprintk=ttyS0', 'console=ttyS0', 'lpj=7999923', + 'root=/dev/hda1'] + + self.workload.command_line = ' '.join(boot_options) + + # Create the CPUs for our system. + self.createCPU(num_cpus) + + # Create the cache heirarchy for the system. + self.createCacheHierarchy() + + # Set up the interrupt controllers for the system (x86 specific) + self.setupInterrupts() + + self.createMemoryControllersDDR4() + + if self._host_parallel: + # To get the KVM CPUs to run on different host CPUs + # Specify a different event queue for each CPU + for i,cpu in enumerate(self.cpu): + for obj in cpu.descendants(): + obj.eventq_index = 0 + + # the number of eventqs are set based + # on experiments with few benchmarks + + if len(self.cpu) > 16: + cpu.eventq_index = (i/4) + 1 + else: + cpu.eventq_index = (i/2) + 1 + def getHostParallel(self): + return self._host_parallel + + def totalInsts(self): + return sum([cpu.totalInsts() for cpu in self.cpu]) + + def createCPUThreads(self, cpu): + for c in cpu: + c.createThreads() + + def createCPU(self, num_cpus): + if self._no_kvm: + self.cpu = [AtomicSimpleCPU(cpu_id = i, switched_out = False) + for i in range(num_cpus)] + self.createCPUThreads(self.cpu) + self.mem_mode = 'timing' + + else: + # Note KVM needs a VM and atomic_noncaching + self.cpu = [X86KvmCPU(cpu_id = i) + for i in range(num_cpus)] + self.createCPUThreads(self.cpu) + self.kvm_vm = KvmVM() + self.mem_mode = 'atomic_noncaching' + + self.atomicCpu = [AtomicSimpleCPU(cpu_id = i, + switched_out = True) + for i in range(num_cpus)] + self.createCPUThreads(self.atomicCpu) + + self.timingCpu = [TimingSimpleCPU(cpu_id = i, + switched_out = True) + for i in range(num_cpus)] + + self.createCPUThreads(self.timingCpu) + + def switchCpus(self, old, new): + assert(new[0].switchedOut()) + m5.switchCpus(self, list(zip(old, new))) + + def setDiskImages(self, img_path_1, img_path_2): + disk0 = CowDisk(img_path_1) + disk2 = CowDisk(img_path_2) + self.pc.south_bridge.ide.disks = [disk0, disk2] + + def createCacheHierarchy(self): + # Create an L3 cache (with crossbar) + self.l3bus = L2XBar(width = 64, + snoop_filter = SnoopFilter(max_capacity='32MB')) + + for cpu in self.cpu: + # Create a memory bus, a coherent crossbar, in this case + cpu.l2bus = L2XBar() + + # Create an L1 instruction and data cache + cpu.icache = L1ICache(self._opts) + cpu.dcache = L1DCache(self._opts) + cpu.mmucache = MMUCache() + + # Connect the instruction and data caches to the CPU + cpu.icache.connectCPU(cpu) + cpu.dcache.connectCPU(cpu) + cpu.mmucache.connectCPU(cpu) + + # Hook the CPU ports up to the l2bus + cpu.icache.connectBus(cpu.l2bus) + cpu.dcache.connectBus(cpu.l2bus) + cpu.mmucache.connectBus(cpu.l2bus) + + # Create an L2 cache and connect it to the l2bus + cpu.l2cache = L2Cache(self._opts) + cpu.l2cache.connectCPUSideBus(cpu.l2bus) + + # Connect the L2 cache to the L3 bus + cpu.l2cache.connectMemSideBus(self.l3bus) + + self.l3cache = L3Cache(self._opts) + self.l3cache.connectCPUSideBus(self.l3bus) + + # Connect the L3 cache to the membus + self.l3cache.connectMemSideBus(self.membus) + + def setupInterrupts(self): + for cpu in self.cpu: + # create the interrupt controller CPU and connect to the membus + cpu.createInterruptController() + + # For x86 only, connect interrupts to the memory + # Note: these are directly connected to the memory bus and + # not cached + cpu.interrupts[0].pio = self.membus.mem_side_ports + cpu.interrupts[0].int_requestor = self.membus.cpu_side_ports + cpu.interrupts[0].int_responder = self.membus.mem_side_ports + + # Memory latency: Using the smaller number from [3]: 96ns + def createMemoryControllersDDR4(self): + self._createMemoryControllers(8, DDR4_2400_16x4) + + def _createMemoryControllers(self, num, cls): + kernel_controller = self._createKernelMemoryController(cls) + + ranges = self._getInterleaveRanges(self.mem_ranges[-1], num, 7, 20) + + self.mem_cntrls = [ + MemCtrl(dram = cls(range = ranges[i]), + port = self.membus.mem_side_ports) + for i in range(num) + ] + [kernel_controller] + + def _createKernelMemoryController(self, cls): + return MemCtrl(dram = cls(range = self.mem_ranges[0]), + port = self.membus.mem_side_ports) + + def _getInterleaveRanges(self, rng, num, intlv_low_bit, xor_low_bit): + from math import log + bits = int(log(num, 2)) + if 2**bits != num: + m5.fatal("Non-power of two number of memory controllers") + + intlv_bits = bits + ranges = [ + AddrRange(start=rng.start, + end=rng.end, + intlvHighBit = intlv_low_bit + intlv_bits - 1, + xorHighBit = xor_low_bit + intlv_bits - 1, + intlvBits = intlv_bits, + intlvMatch = i) + for i in range(num) + ] + + return ranges + + def initFS(self, membus, cpus): + self.pc = Pc() + self.workload = X86FsLinux() + + # Constants similar to x86_traits.hh + IO_address_space_base = 0x8000000000000000 + pci_config_address_space_base = 0xc000000000000000 + interrupts_address_space_base = 0xa000000000000000 + APIC_range_size = 1 << 12; + + # North Bridge + self.iobus = IOXBar() + self.bridge = Bridge(delay='50ns') + self.bridge.mem_side_port = self.iobus.cpu_side_ports + self.bridge.cpu_side_port = membus.mem_side_ports + # Allow the bridge to pass through: + # 1) kernel configured PCI device memory map address: address range + # [0xC0000000, 0xFFFF0000). (The upper 64kB are reserved for m5ops.) + # 2) the bridge to pass through the IO APIC (two pages, already + # contained in 1), + # 3) everything in the IO address range up to the local APIC, and + # 4) then the entire PCI address space and beyond. + self.bridge.ranges = \ + [ + AddrRange(0xC0000000, 0xFFFF0000), + AddrRange(IO_address_space_base, + interrupts_address_space_base - 1), + AddrRange(pci_config_address_space_base, + Addr.max) + ] + + # Create a bridge from the IO bus to the memory bus to allow access + # to the local APIC (two pages) + self.apicbridge = Bridge(delay='50ns') + self.apicbridge.cpu_side_port = self.iobus.mem_side_ports + self.apicbridge.mem_side_port = membus.cpu_side_ports + self.apicbridge.ranges = [AddrRange(interrupts_address_space_base, + interrupts_address_space_base + + cpus * APIC_range_size + - 1)] + + # connect the io bus + self.pc.attachIO(self.iobus) + + # Add a tiny cache to the IO bus. + # This cache is required for the classic memory model for coherence + self.iocache = Cache(assoc=8, + tag_latency = 50, + data_latency = 50, + response_latency = 50, + mshrs = 20, + size = '1kB', + tgts_per_mshr = 12, + addr_ranges = self.mem_ranges) + self.iocache.cpu_side = self.iobus.mem_side_ports + self.iocache.mem_side = self.membus.cpu_side_ports + + ############################################### + + # Add in a Bios information structure. + self.workload.smbios_table.structures = [X86SMBiosBiosInformation()] + + # Set up the Intel MP table + base_entries = [] + ext_entries = [] + for i in range(cpus): + bp = X86IntelMPProcessor( + local_apic_id = i, + local_apic_version = 0x14, + enable = True, + bootstrap = (i ==0)) + base_entries.append(bp) + io_apic = X86IntelMPIOAPIC( + id = cpus, + version = 0x11, + enable = True, + address = 0xfec00000) + self.pc.south_bridge.io_apic.apic_id = io_apic.id + base_entries.append(io_apic) + pci_bus = X86IntelMPBus(bus_id = 0, bus_type='PCI ') + base_entries.append(pci_bus) + isa_bus = X86IntelMPBus(bus_id = 1, bus_type='ISA ') + base_entries.append(isa_bus) + connect_busses = X86IntelMPBusHierarchy(bus_id=1, + subtractive_decode=True, parent_bus=0) + ext_entries.append(connect_busses) + pci_dev4_inta = X86IntelMPIOIntAssignment( + interrupt_type = 'INT', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 0, + source_bus_irq = 0 + (4 << 2), + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = 16) + base_entries.append(pci_dev4_inta) + def assignISAInt(irq, apicPin): + assign_8259_to_apic = X86IntelMPIOIntAssignment( + interrupt_type = 'ExtInt', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 1, + source_bus_irq = irq, + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = 0) + base_entries.append(assign_8259_to_apic) + assign_to_apic = X86IntelMPIOIntAssignment( + interrupt_type = 'INT', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 1, + source_bus_irq = irq, + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = apicPin) + base_entries.append(assign_to_apic) + assignISAInt(0, 2) + assignISAInt(1, 1) + for i in range(3, 15): + assignISAInt(i, i) + self.workload.intel_mp_table.base_entries = base_entries + self.workload.intel_mp_table.ext_entries = ext_entries + + entries = \ + [ + # Mark the first megabyte of memory as reserved + X86E820Entry(addr = 0, size = '639kB', range_type = 1), + X86E820Entry(addr = 0x9fc00, size = '385kB', range_type = 2), + # Mark the rest of physical memory as available + X86E820Entry(addr = 0x100000, + size = '%dB' % (self.mem_ranges[0].size() - 0x100000), + range_type = 1), + ] + # Mark [mem_size, 3GB) as reserved if memory less than 3GB, which + # force IO devices to be mapped to [0xC0000000, 0xFFFF0000). Requests + # to this specific range can pass though bridge to iobus. + entries.append(X86E820Entry(addr = self.mem_ranges[0].size(), + size='%dB' % (0xC0000000 - self.mem_ranges[0].size()), + range_type=2)) + + # Reserve the last 16kB of the 32-bit address space for m5ops + entries.append(X86E820Entry(addr = 0xFFFF0000, size = '64kB', + range_type=2)) + + # Add the rest of memory. This is where all the actual data is + entries.append(X86E820Entry(addr = self.mem_ranges[-1].start, + size='%dB' % (self.mem_ranges[-1].size()), + range_type=1)) + + self.workload.e820_table.entries = entries + diff --git a/configs/example/gem5_library/checkpoints/riscv-hello-save-checkpoint.py b/configs/example/gem5_library/checkpoints/riscv-hello-save-checkpoint.py index 234153a57f..08c7801960 100644 --- a/configs/example/gem5_library/checkpoints/riscv-hello-save-checkpoint.py +++ b/configs/example/gem5_library/checkpoints/riscv-hello-save-checkpoint.py @@ -53,6 +53,36 @@ from gem5.components.cachehierarchies.classic.no_cache import NoCache from gem5.components.processors.simple_processor import SimpleProcessor from gem5.simulate.simulator import Simulator +from gem5.components.cachehierarchies.ruby.mesi_two_level_cache_hierarchy import ( + MESITwoLevelCacheHierarchy, +) +#from gem5.components.cachehierarchies.ruby.mesi_three_level_cache_hierarchy import ( +# MESIThreeLevelCacheHierarchy, +#) + +""" +cache_hierarchy = MESIThreeLevelCacheHierarchy( + l1i_size = "32KiB", + l1i_assoc = 8, + l1d_size = "32KiB", + l1d_assoc = 8, + l2_size = "512KiB", + l2_assoc = 8, + l3_size = "32MiB", + l3_assoc = 32, + num_l3_banks=1, + ) +""" + +cache_hierarchy = MESITwoLevelCacheHierarchy( + l1d_size="32kB", + l1d_assoc=8, + l1i_size="32kB", + l1i_assoc=8, + l2_size="256kB", + l2_assoc=16, + num_l2_banks=2, +) parser = argparse.ArgumentParser() @@ -68,17 +98,17 @@ # This check ensures the gem5 binary is compiled to the RISCV ISA target. # If not, an exception will be thrown. -requires(isa_required=ISA.RISCV) +#requires(isa_required=ISA.RISCV) # In this setup we don't have a cache. `NoCache` can be used for such setups. -cache_hierarchy = NoCache() +#cache_hierarchy = NoCache() # We use a single channel DDR3_1600 memory system memory = SingleChannelDDR3_1600(size="32MB") # We use a simple Timing processor with one core. processor = SimpleProcessor( - cpu_type=CPUTypes.TIMING, isa=ISA.RISCV, num_cores=1 + cpu_type=CPUTypes.O3, isa=ISA.RISCV, num_cores=1 ) # The gem5 library simble board which can be used to run simple SE-mode diff --git a/configs/example/gem5_library/x86-gapbs-benchmarks.py b/configs/example/gem5_library/x86-gapbs-benchmarks.py index c20d2ea4cc..902596ec6a 100644 --- a/configs/example/gem5_library/x86-gapbs-benchmarks.py +++ b/configs/example/gem5_library/x86-gapbs-benchmarks.py @@ -46,7 +46,7 @@ --size ``` """ - +#./build/X86/gem5.opt configs/example/gem5_library/x86-gabps-benchmarks.py --benchmark bc --synthetic 1 --size 4 import argparse import time import sys @@ -195,7 +195,7 @@ ) exit(-1) - command = f"./{args.benchmark} -g {args.size}\n" + command = "./{} -n 1 -g {}\n".format(args.benchmark, args.size) else: command = f"./{args.benchmark} -sf ../{args.size}" diff --git a/configs/ruby/Ruby.py b/configs/ruby/Ruby.py index d3c2efbb3f..5438dad889 100644 --- a/configs/ruby/Ruby.py +++ b/configs/ruby/Ruby.py @@ -41,7 +41,7 @@ import m5 from m5.objects import * from m5.defines import buildEnv -from m5.util import addToPath, fatal +from m5.util import addToPath, fatal, warn from gem5.isas import ISA from gem5.runtime import get_runtime_isa @@ -293,9 +293,13 @@ def create_system( # Create a backing copy of physical memory in case required if options.access_backing_store: ruby.access_backing_store = True - ruby.phys_mem = SimpleMemory( - range=system.mem_ranges[0], in_addr_map=False - ) + if len(system.mem_ranges) > 1: + warn("Backing store not supported for multiple memory ranges") + # Note: to make this support multiple memory ranges you need to create + # one SimpleMemory for each physical memory range + ruby.phys_mem = [ + SimpleMemory(range=system.mem_ranges[0], in_addr_map=False) + ] def create_directories(options, bootmem, ruby_system, system): diff --git a/data-plots.ipynb b/data-plots.ipynb new file mode 100644 index 0000000000..84a5a7818e --- /dev/null +++ b/data-plots.ipynb @@ -0,0 +1,2874 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import sys\n", + "from matplotlib import pyplot as plt\n", + "import os\n", + "import statistics\n", + "\n", + "cmap = plt.get_cmap('Set1')\n", + "\n", + "Stats = ['simSeconds ',\n", + "'hostSeconds ',\n", + "'system.mem_ctrl.readReqs ',\n", + "'system.mem_ctrl.writeReqs ',\n", + "'system.mem_ctrl.servicedByWrQ ',\n", + "'system.mem_ctrl.mergedWrBursts ',\n", + "'system.mem_ctrl.numTotHits ',\n", + "'system.mem_ctrl.numTotMisses ',\n", + "'system.mem_ctrl.numColdMisses ',\n", + "'system.mem_ctrl.numHotMisses ',\n", + "'system.mem_ctrl.numRdMissClean ',\n", + "'system.mem_ctrl.numRdMissDirty ',\n", + "'system.mem_ctrl.numRdHit ',\n", + "'system.mem_ctrl.numWrMissClean ',\n", + "'system.mem_ctrl.numWrMissDirty ',\n", + "'system.mem_ctrl.numWrHit ',\n", + "'system.mem_ctrl.numRdHitDirty ',\n", + "'system.mem_ctrl.numRdHitClean ',\n", + "'system.mem_ctrl.numWrHitDirty ',\n", + "'system.mem_ctrl.numWrHitClean ',\n", + "'system.o3Cpu0.thread_0.numInsts ',\n", + "'system.o3Cpu1.thread_0.numInsts ',\n", + "'system.o3Cpu2.thread_0.numInsts ',\n", + "'system.o3Cpu3.thread_0.numInsts ',\n", + "'system.o3Cpu4.thread_0.numInsts ',\n", + "'system.o3Cpu5.thread_0.numInsts ',\n", + "'system.o3Cpu6.thread_0.numInsts ',\n", + "'system.o3Cpu7.thread_0.numInsts ',\n", + "'system.mem_ctrl.avgRdBWSys ',\n", + "'system.mem_ctrl.avgWrBWSys ',\n", + "'system.mem_ctrl.avgORBLen ',\n", + "'system.far_mem_ctrl.avgRdBWSys ',\n", + "'system.far_mem_ctrl.avgWrBWSys ',\n", + "'system.loc_mem_ctrl.avgRdBWSys ',\n", + "'system.loc_mem_ctrl.avgWrBWSys ',\n", + "'system.loc_mem_ctrl.dram.readBursts ',\n", + "'system.loc_mem_ctrl.dram.writeBursts ',\n", + "'system.loc_mem_ctrl.dram_2.readBursts ',\n", + "'system.loc_mem_ctrl.dram_2.writeBursts ',\n", + "'system.far_mem_ctrl.dram.readBursts ',\n", + "'system.far_mem_ctrl.dram.writeBursts ',\n", + "'system.loc_mem_ctrl.dram.avgRdBW ',\n", + "'system.loc_mem_ctrl.dram.avgWrBW ',\n", + "'system.loc_mem_ctrl.dram_2.avgRdBW ',\n", + "'system.loc_mem_ctrl.dram_2.avgWrBW ',\n", + "'system.far_mem_ctrl.dram.avgRdBW ',\n", + "'system.far_mem_ctrl.dram.avgWrBW ',\n", + "'system.loc_mem_ctrl.dram.busUtil ',\n", + "'system.loc_mem_ctrl.dram.busUtilRead ',\n", + "'system.loc_mem_ctrl.dram.busUtilWrite ',\n", + "'system.loc_mem_ctrl.dram_2.busUtil ',\n", + "'system.loc_mem_ctrl.dram_2.busUtilRead ',\n", + "'system.loc_mem_ctrl.dram_2.busUtilWrite ',\n", + "'system.far_mem_ctrl.dram.busUtil ',\n", + "'system.far_mem_ctrl.dram.busUtilRead ',\n", + "'system.far_mem_ctrl.dram.busUtilWrite ',\n", + "'system.far_mem_ctrl.dram.bytesRead ',\n", + "'system.far_mem_ctrl.dram.bytesWritten ',\n", + "'system.loc_mem_ctrl.dram.bytesRead ',\n", + "'system.loc_mem_ctrl.dram.bytesWritten ',\n", + "'system.loc_mem_ctrl.dram_2.bytesRead ',\n", + "'system.loc_mem_ctrl.dram_2.bytesWritten ',\n", + "'system.mem_ctrl.avgTimeTagCheckRes ',\n", + "'system.mem_ctrl.avgTimeTagCheckResRd ',\n", + "'system.mem_ctrl.avgTimeTagCheckResWr ',\n", + "'system.mem_ctrl.avgPktRespTimeRd ',\n", + "'system.mem_ctrl.avgPktRespTimeWr ',\n", + "'system.mem_ctrl.avgPktORBTime ',\n", + "'system.mem_ctrl.avgPktORBTimeRd ',\n", + "'system.mem_ctrl.avgPktORBTimeWr ',\n", + "'system.mem_ctrl.avgTimeInLocRead ',\n", + "'system.mem_ctrl.avgTimeInLocWrite ',\n", + "'system.mem_ctrl.avgTimeInFarRead ',\n", + "'system.mem_ctrl.missRatio ',\n", + "'system.loc_mem_ctrl.dram.actDelayedDueToTagAct ',\n", + "'system.loc_mem_ctrl.noCandidBSlot ',\n", + "'system.loc_mem_ctrl.foundCandidBSlot ',\n", + "'system.loc_mem_ctrl.foundCandidBSlotRH ',\n", + "'system.loc_mem_ctrl.foundCandidBSlotRMC ',\n", + "'system.loc_mem_ctrl.foundCandidBSlotRMD ',\n", + "'system.loc_mem_ctrl.dram.readMC',\n", + "'system.loc_mem_ctrl.dram.writeBurstsTC'\n", + " ]\n", + "\n", + "dfCols = [\n", + " 'app',\n", + " 'simSeconds',\n", + " 'hostSeconds',\n", + " 'readReqs',\n", + " 'writeReqs',\n", + " 'servicedByWrQ',\n", + " 'mergedWrBursts',\n", + " 'numTotHits',\n", + " 'numTotMisses',\n", + " 'numColdMisses',\n", + " 'numHotMisses',\n", + " 'numRdMissClean',\n", + " 'numRdMissDirty',\n", + " 'numRdHit',\n", + " 'numWrMissClean',\n", + " 'numWrMissDirty',\n", + " 'numWrHit',\n", + " 'numRdHitDirty',\n", + " 'numRdHitClean',\n", + " 'numWrHitDirty',\n", + " 'numWrHitClean',\n", + " 'numInsts0',\n", + " 'numInsts1',\n", + " 'numInsts2',\n", + " 'numInsts3',\n", + " 'numInsts4',\n", + " 'numInsts5',\n", + " 'numInsts6',\n", + " 'numInsts7',\n", + " 'avgRdBWSys',\n", + " 'avgWrBWSys',\n", + " 'avgORBLen',\n", + " 'farAvgRdBWSys',\n", + " 'farAvgWrBWSys',\n", + " 'locAvgRdBWSys',\n", + " 'locAvgWrBWSys',\n", + " 'readBursts1',\n", + " 'writeBursts1',\n", + " 'readBursts2',\n", + " 'writeBursts2',\n", + " 'readBursts3',\n", + " 'writeBursts3',\n", + " 'loc1AvgRdBW',\n", + " 'loc1AvgWrBW',\n", + " 'loc2AvgRdBW',\n", + " 'loc2AvgWrBW',\n", + " 'farAvgRdBW',\n", + " 'farAvgWrBW',\n", + " 'loc1BusUtil',\n", + " 'loc1BusUtilRead',\n", + " 'loc1BusUtilWrite',\n", + " 'loc2BusUtil',\n", + " 'loc2BusUtilRead',\n", + " 'loc2BusUtilWrite',\n", + " 'farBusUtil',\n", + " 'farBusUtilRead',\n", + " 'farBusUtilWrite',\n", + " 'farBytesRead',\n", + " 'farBytesWritten',\n", + " 'loc1BytesRead',\n", + " 'loc1BytesWritten',\n", + " 'loc2BytesRead',\n", + " 'loc2BytesWritten',\n", + " 'avgTimeTagCheckRes',\n", + " 'avgTimeTagCheckResRd',\n", + " 'avgTimeTagCheckResWr',\n", + " 'avgPktRespTimeRd',\n", + " 'avgPktRespTimeWr',\n", + " 'avgPktORBTime',\n", + " 'avgPktORBTimeRd',\n", + " 'avgPktORBTimeWr',\n", + " 'avgTimeInLocRead',\n", + " 'avgTimeInLocWrite',\n", + " 'avgTimeInFarRead',\n", + " 'missRatio',\n", + " 'actDelayedDueToTagAct',\n", + " 'noCandidBSlot',\n", + " 'foundCandidBSlot',\n", + " 'foundCandidBSlotRH',\n", + " 'foundCandidBSlotRMC',\n", + " 'foundCandidBSlotRMD',\n", + " 'readBurstsMC',\n", + " 'writeBurstsTC'\n", + "\n", + " ]\n", + "##########################################################\n", + "\n", + "def getStat(filename, stat, index):\n", + " filename = os.path.join(filename).replace('\\\\','/')\n", + " #print(stat)\n", + " #print(filename)\n", + " try:\n", + " x = 0\n", + " with open(filename) as f:\n", + " readlines = f.readlines()\n", + " for l in readlines:\n", + " if stat in l and x < (index-1):\n", + " x = x+1\n", + " elif stat in l and x == (index-1):\n", + " return l\n", + " return 0.0 #for cases where stat was not found\n", + " except: #for cases where the file was not found\n", + " return 0.0\n", + "\n", + "##########################################################\n", + "\n", + "def creatDataFrame(dataDir, suite, index):\n", + " app = []\n", + " if suite == \"GAPBS\":\n", + " app = ['bc', 'bfs', 'cc', 'pr', 'sssp', 'tc']\n", + " if suite == \"NPB\":\n", + " app = ['bt', 'cg', 'ft', 'is', 'lu', 'mg', 'sp', 'ua']\n", + " rows = []\n", + " i = 0\n", + " for a in app:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}/stats.txt'.format(dataDir, a)\n", + " ret_line = getStat(time_file_path, stat, index[i])\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + " i = i+1\n", + " df = pd.DataFrame(rows, columns= dfCols)\n", + " df['totNumInsts'] = df['numInsts0'].astype(int)+df['numInsts1'].astype(int)+df['numInsts2'].astype(int)+df['numInsts3'].astype(int)+df['numInsts4'].astype(int)+df['numInsts5'].astype(int)+df['numInsts6'].astype(int)+df['numInsts7'].astype(int)\n", + " df['totBW'] = (df['avgRdBWSys'].astype(float)+df['avgWrBWSys'].astype(float))/1000000000\n", + " df['coldRate'] = (df['numColdMisses'].astype(float) / (df['numTotMisses'].astype(float)+df['numTotHits'].astype(float))) *100\n", + " df['injRate'] = (df['readReqs'].astype(float) + df['writeReqs'].astype(float))*64/1000000000 / df['simSeconds'].astype(float)\n", + " df['BIPS'] = (df['totNumInsts'].astype(float)/1000000000)/df['simSeconds'].astype(float)\n", + " \n", + " df['accAmp'] = (df['farBytesRead'].astype(float) + df['farBytesWritten'].astype(float) +\n", + " df['loc1BytesRead'].astype(float) + df['loc1BytesWritten'].astype(float) + \n", + " df['loc2BytesRead'].astype(float) + df['loc2BytesWritten'].astype(float)) / (df['readReqs'].astype(float) * 64 + df['writeReqs'].astype(float) * 64)\n", + " \n", + " df['BWBloat'] = (df['loc1AvgRdBW'].astype(float) + df['loc1AvgWrBW'].astype(float) +\n", + " df['loc2AvgRdBW'].astype(float) + df['loc2AvgWrBW'].astype(float) +\n", + " df['farAvgRdBW'].astype(float) + df['farAvgWrBW'].astype(float)) / ((df['avgRdBWSys'].astype(float) + df['avgWrBWSys'].astype(float)) / 1000000)\n", + " \n", + "\n", + " df['locMemReadBursts'] = df['readBursts1'].astype(float) + df['readBurstsMC'].astype(float)\n", + " df['locMemWriteBursts'] = df['writeBursts1'].astype(float) + df['writeBurstsTC'].astype(float)\n", + " \n", + " \n", + " return df" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "df_gap22_cas = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/cascade/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", + "df_npbC_cas = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/cascade/1GB_8GB_g22_nC/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", + "\n", + "df_gap25_cas = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/cascade/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", + "df_npbD_cas = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/cascade/1GB_85GB_g25_nD/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", + "\n", + "df_gap22_ram = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/rambus/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", + "df_npbC_ram = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/rambus/1GB_8GB_g22_nC/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", + "\n", + "df_gap25_ram = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/rambus/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", + "df_npbD_ram = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/rambus/1GB_85GB_g25_nD/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", + "\n", + "\n", + "df_gap22_orc = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/oracle/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", + "df_npbC_orc = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/oracle/1GB_8GB_g22_nC/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", + "\n", + "df_gap25_orc = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/oracle/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", + "df_npbD_orc = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/oracle/1GB_85GB_g25_nD/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", + "\n", + "df_gap22_noDC = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/noDC/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", + "df_npbC_noDC = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/noDC/1GB_8GB_g22_nC/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", + "\n", + "df_gap25_noDC = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/noDC/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", + "df_npbD_noDC = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/noDC/1GB_85GB_g25_nD/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "df_gap22_ram_prob = creatDataFrame(\"/home/babaie/projects/rambusDesign/tagProbOptRealImplOnSetAssoBranch/dramCacheController/newResults/rambusTagPr/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [7,5,7,6,5,15])\n", + "df_npbC_ram_prob = creatDataFrame(\"/home/babaie/projects/rambusDesign/tagProbOptRealImplOnSetAssoBranch/dramCacheController/newResults/rambusTagPr/1GB_8GB_g22_nC/NPB\", \"NPB\",[3,6,3,6,11,8,8,7])\n", + "\n", + "df_gap25_ram_prob = creatDataFrame(\"/home/babaie/projects/rambusDesign/tagProbOptRealImplOnSetAssoBranch/dramCacheController/newResults/rambusTagPr/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [4,4,5,4,4,7])\n", + "df_npbD_ram_prob = creatDataFrame(\"/home/babaie/projects/rambusDesign/tagProbOptRealImplOnSetAssoBranch/dramCacheController/newResults/rambusTagPr/1GB_85GB_g25_nD/NPB\", \"NPB\",[7,4,2,3,9,5,7,1])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAACXCAYAAAAYoCHkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAcAUlEQVR4nO3de5hU1Znv8e8PRVs9KAHRMCJCoiESb5GWiEEl4i3GDJKjqMcx6GCYZMzES8QoM9HEo0GjER01ZghGiZp4i5cM8RIP0mKMN1AQFWWIgdiGCBIvYCSKvuePvVqLtrq6uqvr0sXv8zz9dO21d+31dtWuXW+vvfZaigjMzMzM6kmPagdgZmZm1tWc4JiZmVndcYJjZmZmdccJjpmZmdUdJzhmZmZWd5zgmJmZWd0pW4Ij6WeSVkh6Jqesj6T7Jf1P+v2xVC5J/ylpiaSnJe1ZrrjMzMys/pWzBec64NBWZWcBsyJiJ2BWWgb4IrBT+pkIXF3GuMzMzKzOlS3BiYg5wF9bFY8BZqTHM4Ajcsp/HplHgd6S+pcrNjMzM6tvle6Ds21ELE+P/wJsmx5vB7yUs11zKjMzMzPrsI2rVXFEhKQOzxMhaSLZZSy22GKLYZ/+9Ke7PDYza9sLL7wAwJAhQ6ociZkZzJs379WI6Ne6vNIJziuS+kfE8nQJakUqfxnYPme7AansIyJiGjANoLGxMebOnVvOeM2slVGjRgHQ1NRU1TjMzAAkLctXXulLVL8GxqfH44G7csq/mu6m2ht4I+dSlpmZmVmHlK0FR9IvgVHA1pKagXOBC4FbJE0AlgHj0uZ3A4cBS4C/ASeWKy4zMzOrf2VLcCLi2DZWjc6zbQAnlysWMzOzanj33Xdpbm5m7dq11Q6lLjQ0NDBgwAB69uzZ7rZV62RsZmZW75qbm+nVqxeDBg1CUrXD6dYiglWrVtHc3MzgwYPb3d5TNZiZmZXJ2rVr6du3r5ObLiCJvn37Ft0a5gTHzMysjCqV3MyaNYtRo0ax3377MXbsWFatWlWWepYuXcoJJ5zQ7nbXXXcd06dPb3e7kSNHFl13R15LX6IyMzPr5lauXMl5553HzJkz6dWrF4sXL+add96pdlhV5QTHzMysAvY+976Snv/o9w9pc93dd9/N8ccfT69evQD41Kc+BcC1117LjBkzWLNmDT/4wQ84+OCDmTx5MnPmzKFnz57ceOON9OjRgxNPPJG3336bESNGMGXKFMaNG8crr7zCpptuym233caWW27JOeecw+zZsxk6dOgH9c6cOZMf/vCHrFu3jnPOOYdDD209BeX68u0Xsv41p5xyCvvssw+jR49mwoQJrF69mp133pkf//jHnXq9fInKzMysm1u+fDn9+390Csejjz6apqYmZs2axSWXXALAww8/zJw5c5g9ezb9+/dnypQpnHbaaTQ1NXHBBRcA2eWlBx98kHHjxnHzzTezfPlyHn/8cR566CH2339/AN5//30uueQSHnjgAZqamrj44ovbjbP1fluceuqpjBgxgmOOOYYLL7yQs88+m9mzZ9OrVy8eeeSRTr0mbsExMzPr5vr378+f//znj5Tfd999XH755UQEK1ZkkweceeaZjB8/nr59+3LBBRewePHiDxKbHj168N577zFp0iQWLlzIm2++ydixY1m2bBm77bYbAMOGDeO3v/0tr776KosWLeLAAw8EYMWKFUREm/1k8u0XYPHixTQ0NHDZZZcBsGjRIs466ywksWbNGoYPH96p18QtOGZmZt3cYYcdxg033MDq1asBWLJkCcuXL2fKlCncc8893HXXXfTokX3lH3DAAVx//fVss802zJw5kyFDhvDoo48CWavM/Pnzeeutt5gzZw4nn3wyEcEOO+zAwoULAXjqqacA2Hrrrdl1112ZNWsWTU1NLFiwoGAn4Hz7hexy2rHHHsukSZOAbJ67Sy+9lKamJubOncuYMWM69Zq4BcfMzKyb69evH9/97nc5/PDDiQj69OnDNddcw+GHH85+++3H8OHD6d27NwBjxozh7bffBuDWW29l//33Z/z48Zx//vnss88+TJ48mSVLlnDooYey/fbbs91229G/f3+GDRvGvvvuy+677w5krT2nn346o0ePRhJDhw7lqquuWi+uSy+9lJtuugmAqVOnfmS/LSZMmMCUKVO46KKLmDx5MhMnTuSNN96gR48eTJ8+nUGDBnX4NVFLBtUdebJNs8rzZJtmxVu0aBE777xztcOoK61fU0nzIqKx9XbtXqJKE2D+k6Rz0vJASZ27IGZmZmZWAcX0wfkxMAJomVtqNXBV25u3T9Jpkp6V9IykX0pqkDRY0mOSlki6WdImpdRhZmZmG65iEpzPRcTJwFqAiHgN6HTyIWk74FtAY0TsAmwEHANc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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_cas['app']\n", + "gap_22_cas = df_gap22_cas['coldRate'].astype(float)\n", + "\n", + "gap_25_cas = df_gap25_cas['coldRate'].astype(float)\n", + "\n", + "app_npb = df_npbC_cas['app']\n", + "npb_C_cas = df_npbC_cas['coldRate'].astype(float)\n", + "\n", + "npb_D_cas = df_npbD_cas['coldRate'].astype(float)\n", + "\n", + "# Multi bar Chart1\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,100])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*2, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + "\n", + "offset = i*2+1\n", + "for i,app in enumerate(app_npb):\n", + " plt.bar(offset+i*2+1, npb_C_cas[i], width=1, color=cmap(1))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=10, color='black')\n", + "\n", + "plt.ylabel(\"Cold Miss Rate\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "\n", + "# Multi bar Chart2\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,100])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*2, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + "\n", + "offset = i*2+1\n", + "for i,app in enumerate(app_npb):\n", + " plt.bar(offset+i*2+1, npb_D_cas[i], width=1, color=cmap(1))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=10, color='black')\n", + "\n", + "plt.ylabel(\"Cold Miss Rate\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAACXCAYAAAAYoCHkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAcjUlEQVR4nO3de7xVVb338c8XJREPSiIagghaopiaQSZeSQzRKLQjoo8ZGsmpx1I0L0gnTVPRMi+n1B7ChLzkNdNDXl8oD2XeIEQwgsgkMRSkVDA8CvzOH3NsW2wXe6299rrtxff9eu3XWnPMueb47bXmmvu3xxxzDEUEZmZmZo2kQ60DMDMzMys3JzhmZmbWcJzgmJmZWcNxgmNmZmYNxwmOmZmZNRwnOGZmZtZwKpbgSPqZpOWS5ueUbSvpUUl/So8fTuWS9F+SFkt6XtInKxWXmZmZNb5KtuBMAYY1KxsPTI+IjwHT0zLAkcDH0s9Y4IYKxmVmZmYNrmIJTkTMBP7erHgEMDU9nwocnVP+88g8BXSV1KNSsZmZmVljq3YfnB0iYll6/iqwQ3reE3g5Z7ulqczMzMys1TavVcUREZJaPU+EpLFkl7HYaqutBuy+++5lj83MNm7hwoUA9OvXr8aRmJnB7NmzX4+I7s3Lq53gvCapR0QsS5eglqfyV4Cdcrbrlco+ICImAZMABg4cGLNmzapkvGbWzODBgwGYMWNGTeMwMwOQtCRfebUvUd0PjE7PRwP35ZR/Od1NtT/wZs6lLDMzM7NWqVgLjqRfAIOB7SQtBS4ELgfulDQGWAIclzZ/ADgKWAz8EzilUnGZmZlZ46tYghMRJ2xk1ZA82wZwWqViMTMzq4X33nuPpUuX8s4779Q6lIbQqVMnevXqRceOHQtuW7NOxmZmZo1u6dKldOnShT59+iCp1uG0axHBypUrWbp0KX379i24vadqMDMzq5B33nmHbt26ObkpA0l069at6NYwJzhmZmYVVK3kZvr06QwePJhDDjmEY445hpUrV1aknpdeeomTTz654HZTpkxh8uTJBbc76KCDiq67Ne9lwUtUknoBxwMHAzsCa4D5wK+BByNifdG1mZmZWdmtWLGCiy++mGnTptGlSxcWLVrEu+++W+uwaqrFBEfSTWQjCk8DriAbt6YTsBvZPFPfljQ+TctgZmZmG7H/hQ+36fVPXXTERtc98MADnHTSSXTp0gWA3XbbDYCbbrqJqVOnsnr1ai677DKGDh3KhAkTmDlzJh07duTWW2+lQ4cOnHLKKaxZs4ZBgwYxceJEjjvuOF577TW22GIL7r77brbeemsuuOACHn/8cfr37/9+vdOmTeP73/8+a9eu5YILLmDYsOZTUG4o334h619zxhlncMABBzBkyBDGjBnDqlWr2GOPPbj++utLer8KteD8MCLm5ymfD/xS0oeA3iXVbGZmZmWxbNky9tprrw+Ujxo1ilNOOYU333yTkSNHMnToUJ544glmzpxJhw4diAjGjRvHmWeeydChQ1m/PrsoM2XKFDp37szkyZO54447GD58OM888wy/+c1vuO2223jkkUdYv349V155JY899hjr16/nyCOPLJjgNN/vqaeeCsC4ceMYNGgQxx9/PN/61rc4//zzGTRoEOeddx5PPvkkgwYNavV70mKCky+5kbQr0Dki5kXEu2Rj15iZmVmN9OjRg7/97W8fKH/44Ye59tpriQiWL88mDzj33HMZPXo03bp149JLL2XRokVceumlAHTo0IF169ZxzjnnMG/ePN566y2OOeYYlixZwt577w3AgAEDeOSRR3j99ddZsGABhx9+OADLly8nIjbaTybffgEWLVpEp06duOaaawBYsGAB48ePRxKrV69mv/32K+k9aVUnY0kTgG8DZ0i6uaQazczMrKyOOuoobrnlFlatWgXA4sWLWbZsGRMnTuTBBx/kvvvuo0OH7E/+YYcdxs0338z222/PtGnT6NevH0899RQA69ev57nnnuPtt99m5syZnHbaaUQEO++8M/PmzQNgzpw5AGy33XbstddeTJ8+nRkzZjB37twWOwHn2y9kl9NOOOEEzjnnHCCb5+6qq65ixowZzJo1ixEjRpT0nhTqg3M6cF1ErEtF+0TEqLTu+ZJqNDMzs7Lq3r073/nOdxg+fDgRwbbbbsuNN97I8OHDOeSQQ9hvv/3o2rUrACNGjGDNmjUA3HXXXRx66KGMHj2aSy65hAMOOIAJEyawePFihg0bxk477UTPnj3p0aMHAwYM4OCDD2afffYBstaes846iyFDhiCJ/v37c911120Q11VXXcXtt98OwNVXX/2B/TYZM2YMEydO5IorrmDChAmMHTuWN998kw4dOjB58mT69OnT6vdETRlU3pXSicDJwI8i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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAACXCAYAAAAYoCHkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAbvklEQVR4nO3de5yVZb338c8XxUbaKAloCCqoSWloJZEoIh7CE4m2RfQpAlPZlWV4VvYu063b3JmHJ936GCZuDxvPUWxDfGE8mHkCFdFINhkmioGU4AFT4Lf/uK+xxbhm1po1c681s/i+X695zbrPv7nXve51zXVd9/VTRGBmZmZWT7rUOgAzMzOz9uYCjpmZmdUdF3DMzMys7riAY2ZmZnXHBRwzMzOrOy7gmJmZWd3ZPM+dSzodOBkIYCFwItAHmAb0BOYD4yLivZb206tXr+jfv3+eoZpZM1544QUABg4cWONIzMw+bP78+a9HRO+m85XXODiS+gK/AXaPiLWS7gTuB44A7o2IaZKuBxZExHUt7Wvw4MExb968XOI0s5aNGDECgDlz5tQ0DjOzYiTNj4jBTefn3US1ObClpM2BbsBy4CDg7rT8ZuDonGMwMzOzTUxuBZyIeAW4HPgTWcFmNVmT1BsRsS6ttgzom1cMZmZmtmnKrQ+OpI8Bo4EBwBvAXcBhrdh+IjARYMcdd8whQjMzs3y9//77LFu2jHfffbfWodSFhoYG+vXrR9euXUuum2cn40OAP0bESgBJ9wL7AT0kbZ5qcfoBrxTbOCJuAG6ArA9OjnGamW0S9rnggXbZz2MXHtou+9kULFu2jO7du9O/f38k1TqcTi0iWLVqFcuWLWPAgAEl18+zD86fgH0kdVP2rh4M/A74NXBsWmc8MD3HGMzMzGrm3XffpWfPni7ctANJ9OzZs+zasDz74DxO1pn4KbJHxLuQ1cicC5whaQnZo+I35hWDmZlZrblw035acy5zfYoqIi6IiE9GxKcjYlxE/C0iXoyIIRGxa0SMiYi/5RmDmZnZpmD27NmMGDGC4cOHc8wxx7Bq1apcjrN06VImTJhQcr2pU6cyZcqUkusNGzasHaL6sFwH+jMzM7NMW/tAtdT3aeXKlVx00UXMmDGD7t27s3jxYt57r8UxdOteyRocSf0knSVpuqQnJc2V9B+SjpTkVA9mZmY1dv/99zNu3Di6d+8OwG677UafPn246aabGDFiBIMHD2bWrFkATJ48mWHDhnHggQfy6quv8tprr3H44YczYsQIzj//fACOO+44DjjgAEaOHMmaNWsA+P73v8/+++/PpZde+sFxZ8yYwfDhw9l3332ZOXNmyTiL7ReyDsSnnXYa06ZNY+XKlRx11FEceOCBfOtb36r4nLRYgyPpJrJxamYAlwErgAZgN7JHvv9Z0nkRMbfiCMzMzGqoHp4uW758OYMGDfrQ/LFjx3LiiSeyevVqxowZw8iRI3nkkUeYO3cuXbp0ISKYNGkSp59+OiNHjmTDhg1A1rzUrVs3pkyZwh133MGoUaN44oknePjhh7n99tuZNWsWGzZs4PLLL+ehhx5iw4YNHH744Rx2WMujwTTd7ymnnALApEmTGDp0KMcffzxnnnkm559/PkOHDuXcc8/l0UcfZejQoa0+J6WaqH4cEc8Vmf8ccK+kLQAPUmNmZlZDffr04dVXX/3Q/AceeICrr76aiGDFihUAnHPOOYwfP56ePXtyySWXsHjxYi655BIAunTpwvr16zn77LNZuHAha9as4ZhjjuGll15izz33BGDvvfdm1qxZvP766yxatIhDDjkEgBUrVhARzXYELrZfgMWLF9PQ0MBVV10FwKJFizjvvPOQxFtvvcWQIUMqOictNjEVK9xI2kXSoLT8vYhYUtGRzczMrF0cccQR3Hrrrbz55psALFmyhOXLl3PppZfyq1/9iunTp9OlS/aVf9BBB3HLLbew7bbbMmPGDAYOHMhjjz0GwIYNG3jmmWd4++23mTt3LqeeeioRwU477cTChQsBePrppwHo1asXgwYNYvbs2cyZM4cFCxa0+JRTsf1C1px2wgkncPbZZwNZYt8rrriCOXPmMG/ePEaPHl3ROWlVJ2NJk4FdgQ2SPhIR4yo6qpmZmbWb3r17873vfY9Ro0YREWyzzTbceOONjBo1iuHDhzNkyBB69OgBwOjRo1m7di0Ad911FwcccADjx4/n4osvZt9992Xy5MksWbKEww47jB122IG+ffvSp08f9t57b/bff3/22msvIKvtOeOMMzj44IORxO6778611167UVxXXHEF06ZNA+DKK6/80H4bnXTSSVx66aVcdtllTJ48mYkTJ7J69Wq6dOnClClT6N+/f6vPSYvZxCWdBlwbEevT9B0RMTa9fjYi9mz1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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_cas['app']\n", + "gap_22_cas = df_gap22_cas['missRatio'].astype(float)-df_gap22_cas['coldRate'].astype(float)\n", + "\n", + "gap_25_cas = df_gap25_cas['missRatio'].astype(float)-df_gap25_cas['coldRate'].astype(float)\n", + "\n", + "app_npb = df_npbC_cas['app']\n", + "npb_C_cas = df_npbC_cas['missRatio'].astype(float)-df_npbC_cas['coldRate'].astype(float)\n", + "\n", + "npb_D_cas = df_npbD_cas['missRatio'].astype(float)-df_npbD_cas['coldRate'].astype(float)\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,100])\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*2, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + "\n", + "offset = i*2+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*2+1, npb_C_cas[i], width=1, color=cmap(1))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "\n", + "plt.ylabel(\"Hot Miss Rate (%)\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "#plt.ylim([0,55])\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*2, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + "\n", + "offset = i*2+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*2+1, npb_D_cas[i], width=1, color=cmap(1))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "\n", + "plt.ylabel(\"Hot Miss Rate (%)\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAACXCAYAAAAYoCHkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAc70lEQVR4nO3de5yVVd338c8XRUlvFEE0FBVSM8lDCZl4RDE1s5DuRHl8FLkxOlieUlPuxPLW0DQP5aEIUzTLU5pFpPkgI2aeQEVUlEghh0ZFbw9omgK/549rjW7Gzew9e/ZpNt/36zWvva+1r32t3+zDNb9Za11rKSIwMzMzayTdah2AmZmZWbk5wTEzM7OG4wTHzMzMGo4THDMzM2s4TnDMzMys4TjBMTMzs4ZTsQRH0i8lvSTpiZyy3pLukvS3dLtRKpekn0haKOlxSbtUKi4zMzNrfJVswbkGOKhN2enAjIjYFpiRtgE+D2ybfsYDV1YwLjMzM2twFUtwImIW8L9tikcAU9P9qcChOeXXRuYBoJekfpWKzczMzBpbtcfgbBoRLen+C8Cm6f7mwPM5+zWnMjMzM7MOW7tWFUdESOrwOhGSxpN1Y7H++usP/sQnPlH22Mxs9Z555hkAtttuuxpHYmYGc+bMeTki+rYtr3aC86KkfhHRkrqgXkrlS4Atcvbrn8o+JCImA5MBhgwZErNnz65kvGbWxrBhwwBoamqqaRxmZgCSFucrr3YX1e+BMen+GOD2nPKj09VUuwGv53RlmZmZmXVIxVpwJP0GGAZsLKkZOAs4D7hJ0jhgMTAq7T4dOBhYCPwLGFupuMzMzKzxVSzBiYjRq3loeJ59AziuUrGYmZnVwnvvvUdzczPvvPNOrUNpCD169KB///5079694L5FJTiShgB7AZsBbwNPAHdFxKudCdTMzKyRNTc307NnTwYMGICkWofTpUUEr7zyCs3NzQwcOLDg/u2OwZE0VtIjwBnAR4BnyAYG7wn8P0lTJW1ZhrjNzMwazjvvvEOfPn2c3JSBJPr06VN0a1ihQcbrAXtExH9GxA8jYkpEXBYRx0fEYOBistmHzczMLI9qJTczZsxg2LBh7L333owcOZJXXnmlIvUsWrSIY445puB+11xzDVOmTCm435577ll03R15LdvtooqIyws8/ljRNZmZmVlFLF26lLPPPptp06bRs2dPFixYwLvvvlvrsGqqQ4OMJX0R+A7Qg2xphSsqEpWZmVmD2e2sOzv1/Ad+cOBqH5s+fTpHHXUUPXv2BODjH/84AFdffTVTp07lzTff5Ic//CEHHHAAEyZMYNasWXTv3p3rr7+ebt26MXbsWN5++22GDh3KpEmTGDVqFC+++CLrrrsut9xyCxtssAETJ05k5syZDBo06P16p02bxo9+9COWL1/OxIkTOeigtktQrirfcSEbX3PCCSew++67M3z4cMaNG8eyZcvYfvvtueKK0lKNQmNwPtWm6ChgX2B34Bsl1WhmZmZl1dLSQr9+H17C8fDDD6epqYkZM2Zw4YUXAnDfffcxa9YsZs6cSb9+/Zg0aRInnXQSTU1NnHvuuUDWvXTPPfcwatQobrzxRlpaWnjooYe499572WeffQBYuXIlF154IXfffTdNTU1ccMEFBeNse9xWJ554IkOHDuWII47gvPPO44wzzmDmzJn07NmT+++/v6TXpFALzjckdQPOjIgXyNaL+h6wEvhnSTWamZlZWfXr149//vPDf5bvvPNOLr30UiKCl17KFg847bTTGDNmDH369OHcc89lwYIF7yc23bp1Y8WKFZx66qnMmzePN954g5EjR7J48WJ22mknAAYPHsyf//xnXn75ZebPn8/+++8PwEsvvURErHacTL7jAixYsIAePXpwySWXADB//nxOP/10JPHmm2+y6667lvSatNuCExFfAy4Dfi5pIjARuB+YB3yppBrNzMysrA4++GB+9atfsWzZMgAWLlxIS0sLkyZN4k9/+hO333473bplf/L3228/rrvuOjbZZBOmTZvGdtttxwMPPABkrTKPPfYYb731FrNmzeK4444jIthqq62YN28eAI8++igAG2+8MTvuuCMzZsygqamJuXPntjsION9xIetOGz16NKeeeiqQrXN30UUX0dTUxOzZsxkxYkRJr0nBMTgRMRcYkcbf3E429ubakmozMzOzsuvbty9nnnkmhxxyCBFB7969ueqqqzjkkEPYe++92XXXXenVqxcAI0aM4O233wbg5ptvZp999mHMmDGcc8457L777kyYMIGFCxdy0EEHscUWW7D55pvTr18/Bg8ezF577cXOO+8MZK09J598MsOHD0cSgwYN4vLLV7026aKLLuKGG24A4OKLL/7QcVuNGzeOSZMmcf755zNhwgTG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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_cas['app']\n", + "gap_22_cas = df_gap22_cas['missRatio'].astype(float)\n", + "\n", + "gap_25_cas = df_gap25_cas['missRatio'].astype(float)\n", + "\n", + "app_npb = df_npbC_cas['app']\n", + "npb_C_cas = df_npbC_cas['missRatio'].astype(float)\n", + "\n", + "npb_D_cas = df_npbD_cas['missRatio'].astype(float)\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,100])\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*2, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + "\n", + "offset = i*2+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*2+1, npb_C_cas[i], width=1, color=cmap(1))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "\n", + "plt.ylabel(\"Total Miss Rate (%)\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "#plt.ylim([0,55])\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*2, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + "\n", + "offset = i*2+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*2+1, npb_D_cas[i], width=1, color=cmap(1))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "\n", + "plt.ylabel(\"Total Miss Rate (%)\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAACgCAYAAAAB3xbxAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAgVklEQVR4nO3de7xUdb3/8ddbRFESNgqaR1RQSxO8oFh6xNxQHi8koEWCHu+XNDPNLv40j4hp5k/LTM0yFU00NUu8EWkGlndAUUC0UvFCHkwN8IYifM4fa22YvZnZe83ea2bP3ryfj8c89qzv+q61PjNrZu3vfNf3oojAzMzMrDNZq70DMDMzM8ubCzhmZmbW6biAY2ZmZp2OCzhmZmbW6biAY2ZmZp2OCzhmZmbW6biAY2ZmZp2OCzhmZmbW6eRawJE0QFKf9PlGkq6RdIuk7fM8jpmZmVlz8q7B+WXB8wuA/wXuAK7L+ThmZmZmJeVWwJE0DtgaOCl9fhDQBdgO6CvpHEmfz+t4ZmZmZqUoz7moJM0EDgY2AS6MiC+k6Q9FxJDcDmRmZmbWjLVz3t/5wKPAR8BYSNrlAG/kfBwzMzOzknKtwTEzMzOrBRXtJi7p3Eru38zMzKyYSo+DMyJrRkndJD0h6WlJcyWNr2RgZmZm1nnl3QanKZWR90NgWES8K6kr8JCkP0TEYxWKzczMzDqpShdwds2aMZLGQO+mi13ThxsImZmZWdlyK+BI+lmJdAAi4psZ9tEFmAlsA1wZEY/nFZ+ZmZmtOfKswTkRmAPcBvyT8m5PARARy4GdJdUBd0gaGBFzGtZLOgE4AaB79+67brfddnnEbWZleP755wHYdttt2zkSMzOYOXPmmxHRp2l6bt3EJW0EjAYOAT4GbgVuj4hFrdzfOcD7EXFJsfWDBw+OGTNmtDJaM2ut+vp6AKZNm9aucZiZQTLIcEQMbpqeWy+qiHgrIn4REUOBo4E64FlJh2cMsE9ac4Ok9YB9gOfyis/MzMzWHLk3Mpa0C8koxvsAfyBpU5PFpsANaTuctYDbIuKevOMzMzOzzi/PRsbnAcOBecAtwJkR8XHW7SPiGWBQXvGYmZnZmivPGpyzgZeAndLHD9MeVCLpBb5jjscqauHChbz99tuVPox1UF27dqV3797U1dW1dyhmZlZheRZw+ue4r1Z5++23+fSnP02XLl3aOxSrMRHB0qVLmT9/vgs4ZmZrgNwKOBHxcrF0SUNI2uScnNexmuPCjRUjifXWW6+9wzAzsyqpyFxUkgZJuljSfOAHdNLeUIsXL6a+vp76+nrq6urYY489qK+vZ+DAgeyxxx4MGTKEPffck+uvv37lNv3796e+vp699tqLww8/nOXLl69c98Mf/pD+/ftT2HW/f//+HHfccSuXb7zxRiQxf/78arzE3E2fPp1hw4ax9957M3ToUKZPn96m/W2zzTY5RWZmZp1Jno2MP01SUzMWeJNkHByl3carbvdxf8xlP4+N37fkup49e64cC6S+vp6JEyfSt2/fRs8XLVrEqFGj2HLLLRk6dChdunRZuc0xxxzDfffdx/777w/APffcw7Bhw3j44YcZMmQIkNRIvfLKK3z44Yesu+663H777ey6a+YZMDIZMWl4Lvu5a9S9za5fvHgxRx55JJMnT6Zfv37Mnz+fAw44gEcffZSePXsCsHz5ctfCmZlZm+VZg/McMAz4UkQMiYjLgeUtbNPp1dXV8f3vf5+bb765UfqKFStYtGjRytqap556igEDBnDSSScxceLERnn3339/7r33Xt544w26du3aYduQ3HPPPYwaNYp+/foB0K9fP0aOHMkVV1zBbrvtxuGHH87xxx/P1KlTGTp0KHvttRcjR45k6dKlANx6663svvvuDB06lIsuuqjRvpctW8Zxxx3H0KFDGTJkCE888US1X56ZmdWQPBsZHwyMAaZKmkLSVbzs6Ro6o80335wFCxYASQ1FfX09L774IoMGDWLffZMaoptuuokjjzySwYMHc/rpp7Ns2TK6du0KwJgxYzjttNNYsGABX/3qV7n66qvb7bW0xWuvvcYWW2zRKG3LLbdkyZIlzJ8/nwceeIAePXrw3nvvMXXqVADOOOMMbrvtNoYPH87555/PY489Rvfu3Rvd2gO49tpr2WabbbjmmmtYuHAhBx98MA8//HDVXpuZmdWWPBsZTwImSeoOjAROAzaWdBVwR0Tcl9exOppXX32VzTbbDGDlLarFixez//77s2jRInr16sWdd97JnDnJtFtvvPEGkydPZuTIkQBsuummvPvuu9xyyy386U9/6rAFnM0224xnn322Udorr7xC9+7dGThwID169ABg7ty5nH322Xz44YcsXLiQHj168MILL7DjjjvSvXt3YPXG5LNn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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_ram['app']\n", + "gap_22_ram = df_gap22_ram['simSeconds'].astype(float)*1000\n", + "gap_22_orc = df_gap22_orc['simSeconds'].astype(float)*1000\n", + "gap_22_noDC = df_gap22_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "\n", + "gap_25_ram = df_gap25_ram['simSeconds'].astype(float)*1000\n", + "gap_25_orc = df_gap25_orc['simSeconds'].astype(float)*1000\n", + "gap_25_noDC = df_gap25_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "\n", + "app_npb = df_npbC_ram['app']\n", + "npb_C_ram = df_npbC_ram['simSeconds'].astype(float)*1000\n", + "npb_C_orc = df_npbC_orc['simSeconds'].astype(float)*1000\n", + "npb_C_noDC = df_npbC_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "npb_D_ram = df_npbD_ram['simSeconds'].astype(float)*1000\n", + "npb_D_orc = df_npbD_orc['simSeconds'].astype(float)*1000\n", + "npb_D_noDC = df_npbD_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "\n", + "# Multi bar Chart1\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,3])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_22_ram[i]/gap_22_noDC[i], width=1, color=cmap(1), label='TDRAM' if i==0 else None)\n", + " plt.bar(i*3+1, gap_22_orc[i]/gap_22_noDC[i], width=1, color=cmap(2), label='Oracle' if i==0 else None)\n", + "\n", + "offset = i*3+2\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_C_ram[i]/npb_C_noDC[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*3+2, npb_C_orc[i]/npb_C_noDC[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()\n", + "\n", + "# Multi bar Chart2\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,3])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_25_ram[i]/gap_25_noDC[i], width=1, color=cmap(1), label='TDRAM' if i==0 else None)\n", + " plt.bar(i*3+1, gap_25_orc[i]/gap_25_noDC[i], width=1, color=cmap(2), label='Oracle' if i==0 else None)\n", + "\n", + "offset = i*3+2\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_D_ram[i]/npb_D_noDC[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*3+2, npb_D_orc[i]/npb_D_noDC[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", + "plt.legend(fontsize=9, ncol=2)\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_cas['app']\n", + "gap_22_cas = df_gap22_cas['simSeconds'].astype(float)*1000\n", + "gap_22_ram = df_gap22_ram['simSeconds'].astype(float)*1000\n", + "gap_22_noDC = df_gap22_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "\n", + "gap_25_cas = df_gap25_cas['simSeconds'].astype(float)*1000\n", + "gap_25_ram = df_gap25_ram['simSeconds'].astype(float)*1000\n", + "gap_25_noDC = df_gap25_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "\n", + "app_npb = df_npbC_cas['app']\n", + "npb_C_cas = df_npbC_cas['simSeconds'].astype(float)*1000\n", + "npb_C_ram = df_npbC_ram['simSeconds'].astype(float)*1000\n", + "npb_C_noDC = df_npbC_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "npb_D_cas = df_npbD_cas['simSeconds'].astype(float)*1000\n", + "npb_D_ram = df_npbD_ram['simSeconds'].astype(float)*1000\n", + "npb_D_noDC = df_npbD_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "\n", + "# Multi bar Chart1\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,3])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_22_cas[i]/gap_22_noDC[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + " plt.bar(i*3+1, gap_22_ram[i]/gap_22_noDC[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", + "\n", + "offset = i*3+2\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_C_cas[i]/npb_C_noDC[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*3+2, npb_C_ram[i]/npb_C_noDC[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "\n", + "# Multi bar Chart2\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,3])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_25_cas[i]/gap_25_noDC[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + " plt.bar(i*3+1, gap_25_ram[i]/gap_25_noDC[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", + "\n", + "offset = i*3+2\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_D_cas[i]/npb_D_noDC[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*3+2, npb_D_ram[i]/npb_D_noDC[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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ujUvvvhiIV6ierPlllvy0UcfAXDllVey2267MXPmTA47LKmNe+211+jRowd9+/blySefLN9u0KBBTJo0iUcffZQjj1y3Gqi6sHjxYrbccsvy5ZYtW7J69WqWLl3KL3/5S66++mp69+5NaWkpM2bM4KabbgKo8vwrc8kll/Dwww/z3HPPcdddd61TrWQhGxk/CDwoqRUwADgX6CDpRmBSRDxeqGOZma3vOnbsyIcffviN9Mcee4xrr72WiODjjz8G4Be/+AUnnngim2++OaNHj2bBggXlXyzNmjVjzZo1DB8+nLlz57J8+XIGDRrEe++9x+67J6N77LXXXjz++OMsXbqU+fPnc8ghhwDw8ccfExHVNvysar8ACxYsoGXLllxzzTUAzJ8/nwsvvBBJfPbZZ+y9994Ffa3q2gcffMBOO+3EO++8w/Dhwxk2bBgDBw7kX//6FytWrGDu3Ln07duXL774gh122KG8MLPDDjvw+uuv06pVKzbZZJN6/i9yq3wOrlq1ihYtWtChQwc6deoEwKxZsxg1ahRffvklb7zxBsA3zr9Mc+bMoX///kByC2zJkiVstdVWtYqv4DfHImJlRNwdEUcBnYBXgf8p9HHMzNZnRxxxBHfeeScrVqwA4O2332bx4sWMGTOGv/71rzz00EPlXx4HHXQQd9xxBx06dGDy5MnsuOOOzJgxA0hqZWbPns3KlSt55plnOOOMM4gIttlmG+bOnQskNQ4A7dq1Y7fddmPatGmUlpYyZ86crL1aqtovJF/kgwcPZvjw4UAycevVV19NaWkpr7zyCgMGDCjOi1YHPvjgA5544gl69OhRnta8eXPOPPNMxo0bxwMPPMD48eOZOnUq06dPZ/Hixaxdu7Y87w9/+EOGDMlrhqN6d/jhh3P77bezcuVKAMaNG8fAgQMrFFp+97vfMX78eJ588knatm0L8I3zL1O3bt2YMmUKpaWlvPbaa7Uu3EANanAkbRwRn+fI0xzYNCKWpkkrSW5T1T5CM7NGrLpGwuuqffv2/OpXv6Jfv35EBJttthm33nor/fr1o3fv3uy9997lXygDBgzgP//5DwB/+ctfOPDAAznxxBO5/PLL2X///bnooot4++236du3L9/97nfZaqut6NixI3vttRe9evWia9euQPJr+/zzz+fggw9GEjvvvDM33HBDhbiuvvrq8t5B48aN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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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b9+el156qRAvUaPZYost+PDDDwG48sor2W233Zg2bRqHHZbUyL3++uvsueee9OnTh6effrpqu4EDBzJx4kQee+wxjjxy3WqgSmHRokVsscUWVctt27Zl1apVLFmyhF/96leMGTOG3r17U1FRwcsvv8zNN98MkPX8q3TJJZfw8MMP88ILL3D33Xe7VtLMmr1CNjJ+EHhQUjugP3Au0FnSjcDEiHiyUMdqTF26dOGDDz74WvoTTzzBtddeS0Tw0UcfAXDhhRdy4oknsvnmmzNq1Cjeeeedqi+WVq1asWbNGoYNG8bs2bNZunQpAwcOZP78+Xzve0mP+j322IMnn3ySJUuWMHfuXA455BAAPvroIyKi1saf2fYL8M4779C2bVuuueYaAObOnctFF12EJJYvX85ee+1V0Neq1BYuXMhOO+3Ee++9x7Bhwxg6dCgDBgzgX//6F8uWLWP27Nn06dOHL774gh122KGqMLPDDjvwxhtv0K5dOzbZZJNG/i9yq3kOrly5kjZt2tC5c2e6du0KwIwZMxg5ciSrV6/mzTffBPja+Zdp1qxZ9OvXD0hugS1evJgtt9yyFP+OmVlRFPxGfUSsiIg/R8RRQFfgNeC/Cn2cxnLEEUdw1113sWzZMgDeffddFi1axOjRo3n88cd56KGHqr48DjroIO688046d+7MpEmT2HHHHXn55ZeBpFZm5syZrFixgueee44zzjiDiGDrrbdm9uzZQFLjANCxY0d22203pkyZQkVFBbNmzaqzZ0u2/ULyRT5o0CCGDRsGJJMljhkzhoqKCqZPn07//v2L86KVwMKFC3nqqafYc889q9Jat27NmWeeydixY3nggQcYN24ckydPZurUqSxatIi1a9dW5f3Rj37E4MF5zSrS6A4//HDuuOMOVqxYAcDYsWMZMGBAtULLH/7wB8aNG8fTTz9dNX5NzfMvU48ePXj00UepqKjg9ddfd+HGzJq9vGtwJG0cEZ/lyNMa+GZELEmTVpDcpirp1bKuRsLrqlOnTvzmN7+hb9++RASbbbYZt912G3379qV3797stddeVV8o/fv35/PPPwfgr3/9KwcccAAnnngil19+Ofvttx8XX3wx7777Ln369OE73/kOW265JV26dGGPPfagV69edO/eHUh+bZ9//vkcfPDBSGLnnXfmhhtuqBbXmDFjqnoHjR079mv7rXTSSScxevRofv/733PxxRdzyimn8Omnn9KqVSvGjRtHt27d1un1qa2RcLH88pe/pGPHjmy44YZcf/31bLTRRtXWH3roofz6179mgw02qNZbauedd+b555+vWq7sOTVv3ryCxFVXI+F11blzZ4YPH06fPn1o1aoVPXr0YNiwYfz5z3+uyjNw4ED69+/P7rvvXnU+XnTRRdXOv9/97ndV+UeOHMlRRx1VdU7ff//9RYvfzKwUcs4mLmk/YBzwjYjYSlJ34BcRcXqNfMcDN5MUav4XGAXcDrwK/DYiXitk4DVnE587dy477bRTIQ9hZqnMz5dnEzezpqS22cTzqcEZCxwGPAwQEbMk9c6S79fAHhHxbjrh5kvA0RHxyDrEbWZmZlZvebXBiYj3ayRl6/69KiLeTfO/BvyvCzdmZmbWGPKpwXk/vU0VktoA55DMGF5TZ0nnZyx3yFyOiDHrFmpudfUsMrOGyXUb28ysKcqngHMqcC1JQ+GFwJNkn1fqVqB9HctF1bZtWz7++GM233xzF3LMCqiyG7rZ+iDXaOyl7khhDZezgJP2iDohj3wjCxJRA3Xt2pUFCxawePHixgzDrEXKNrilmVlTlrOAI2kb4CygW2b+iOiXJe+BwJnAd9OkucD1EVFRgFjr1KZNG7bZZptiH8bMzMyagXxuUT0I3AY8AqytLZOkI4HrgcvSh4DvA7dLOjMiHlvnaM3MzMzykE8BZ2VE/DGPfMOAARExKyNtpqTpwHWACzhmZmZWEvkUcK6VNIKkcXHVFMxZBu77do3CTWW+v0v61rqFaWZmZpa/fAo4uwGDgYP46hZVpMuZVtSxj7rWmZmZmRVUPgWcY4BtI2JVjnzbSXo4S7qAbesdmZmZWQu1z4gn6lxfzDkV1xf5FHDmAB2Aj3Lkq2sq6qvyDcjMmp9cF2vwBXt95vPDGkM+BZwOwFuSXqV6G5xq3cQj4tmaG0r6fqEn2TQzMzPLJZ8Czoh12P84kq7iZmZWYq45sfVZPiMZf61mph7ynjNB0neAO4BvkTRiviUirl2HY5uZmVXJp8DXuUcJArGSqLWAI+mFiCiTtIykwFG1CoiI2CSP/ddn+oYvgV9GxGuS2gMzJD0VEW/WYx9mZmZmtRdwIqIs/VvvCTMldQd6VT7PNj5OluMtAhalz5dJmksywacLOGZmZlYvrXJlkHRnPmkZ684B7gY6p4+7JJ1Vn6AkdQN6AK/UZzszMzMzyK+R8S6ZC5I2APaoI/9JwN4RsSLN/3vgJZLpGnKS9A3gfuDciFhaY90pwCkAW221VT67MzMzs/VQXW1whgMXAxtJqixoCFgF3FLHPgWsyVheQ56NjSW1ISnc3B0RD9RcHxG3VB67Z8+eUXO9mZnVT78Hj6xz/cMDHi1RJGaFVVcbnNHAaEmjI2J4PfY5HnhF0sR0eQDJbOR1kqQ039yIGFOP45mZNSnunm3W+PLpJl6fwg0RMUbSs8D+adLQiHg9j033J5nzarakmWnaxRHhWcjNzMysXvJpg9MQM0l6RG0AIGmriPh/dW0QES9Qj3FzzMzMzGpT8AJO2mNqBPB/fNX+JoDvFfpYZmZmZtnkVcCR1JpkhOGq/HXUyJwD7BgRH697eOYZZ83MzOovZwGnRo3M2jS5rhqZ94FPCxKdmZmZWQPkU4NT3xqZ94AKSY9SffZx94wyMzOzksingFPfGpn/lz42TB9mZmZmJZVPAadeNTIRUZ8JNs3MzMwKLp8CjmtkzGydecRcMyulfAb6GwlVc0QREcuLHZQ1Pe7NZWZWOrl+EIB/FOSSz2ziu0p6HXgDeEPSDEm75NrOzMzMrLHkc4vqFuD8iJgKIKkcuBXYL1tmSV1JZg4vI+lO/jxwTkQsKEC8JdNcaixcyl+/ec4jW1/c3P+unHl+8dBPShCJNRc5a3CAdpWFG4CIqADa1ZF/PPAw0AXYAngkTTMzMzMribx6UUn6DXBnuvwTkp5VtekUEZkFmgmSzm1gfGZmth7IVRt9JINKFIm1FPnU4PwM6AQ8kD46pWm1+VjSTyS1Th8/ATxtg5mZmZVMPr2o/g2cXY99/oykDc5YkjY4fwOGNCQ4MzMzs4aotYAj6ZqIOFfSIyQFlWoiol8tm3atuU7S/iQjIpuZmZkVXV01OJVtbq6q5z6vA76fR5pZs9VcetlZ0+WBD82Kq9YCTkTMSJ/uHhHXZq6TdA7wbI20fUm6jneSdH7Gqk2A1oUJ18zMzCy3fHpRnQhcWyNtSJa0DYFvpPtsn5G+FDi6gfFZM+HxeMzMmp+WXBtdVxucQcCPgW0kPZyxqj3wr5r5I+JZ4FlJEyJifsEjNTMzM8tTXTU4fwMWAR2BqzPSlwF/r20jF27MzNadR+41Wzd1tcGZD8wH9i1dOGYtg2/Z1Z+/0M2skHK2wZG0jK+6iW8ItAFWRMQmxQzMzKy+PDeXmVXKZ6C/qgbDkgT0B/apmU/SdWQZLydjP/UZLNDMrCjcPbt+XLNmzVU+vaiqREQAD0oaAVxUY/X09O/+wM7AvenyMcCb6xKkrZtcFyhfnFo2f6GbtUy+ttctn1tUP8xYbAX0BFbWzBcRf0rznwaURcSX6fJNwPMFidbMCs6/0M2sNs25PWE+NThHZTz/EphHcpuqNt8kGdyvsiv5N9K0Okm6HegLfBQRu+YRlzUz/rVhZs2dfxA0H/m0wRlaz31eAbwuaSogoDdwaR7bTQCuB+6o5/EaRXMu1VrT4AKfmVnx5HOL6k/AORHxSbr8TeDqiPhZtvwRMV7S48DeadJ/RcSHuY4TEc9J6pZv4M2Bv8DMzKyla6rfdUraDdeRQXo9InrkSstYJ+AEYNuIuEzSVsC3I2JazmCSAs6kfG5RbbPNNjFixIhc2RrstXlfG6y5mg2/sTDnPjb7sHOd67fY9VuOo55xNBVN5fXIFUc+seSKo2YsM2fOBGD33Xdv1DiyKUQcu3bcLec+cmlJr4fjKHwc+cTSVK4hzeHaPnTo0BkR0bNmeqs8tm2V1toAIGkz6q75+W+SwQEHpcvLgBvqEWutJJ0iabqk6atXry7ELs3MzKwFyqeR8dXAS5L+mi4fA4yqI//eEfF9Sa8DRMS/JW24jnGS7usW4BaAnj17xpAhQwqx26xuyjFgWOf/nJJzH0c+n7WSq8qQq3JX2zmOpqmpvB654sgnllxx1IylvLwcgGuuuaZR48imEHFsPz53HLmq3FvS6+E4Ch9HPrE0lWtIc7i2Dx2avalwPo2M75A0HTgoTfphRNQ1rs1qSa1JB/2T1AlYW79wzczMzBou34H+NiOZnmG8pE6StomIf9aS94/ARKCzpFHA0cCvcx1A0l+AcqCjpAXAiIi4Lc/4bD2Rayh+D8NvZmaQXy+qESSD++0IjCeZi+oukhGLvyYi7pY0AziYpJv4gIiYm+s4ETEoVx6zXNx938zMIL9GxgOBfsAKgIj4AGhfW2ZJtwFtI+KGiLg+IuZKurQQwZqZmZnlI58Czqp0DqrKNjXtcuQ/DPiTpJ9mpPVrYHxmZmZm9ZZPAec+STcDHST9HHgaGFdH/o9IRi8+RtINkjYguVVlZmZmVhL59KK6StKhwFKSdjiXRMRTdWyiiPgUOCq9NVUBbFqAWM0KoqmOumlmZoWTTyPjk9LeTE+ly60ljYiIkbVs8nDlk4i4NG1wfF5BojUzMzPLQz63qA6W9JikLpJ2AV6mjkbGETGixvIjEXFQbfnNzMzMCi2fW1Q/lnQcMJukJ9WPI+LFmvkkvRARZZKWkTZIrlyV7CY2KVTQZmZmZnXJ5xbV9sA5wP3ATsDgdLLNzzLzRURZ+rfW2h0zMzOzUshnJONHgDMiYko6U/j5wKvALpmZ0kk4axURuadxNTMzMyuAfAo4e0XEUkjuMwFXS3okS74ZJLemsnUJD2DbBkdpZmZmVg+1NjKWdCFARCyVdEyN1UNq5o+IbSJi2/RvzYcLN2ZmZlYydfWiOj7j+fAa6/rUtVNJ35S0l6TelY8GR2hmZmZWT3XdolItz7Mtf7VCOpmkUXJXYCawD/AS4K7iZmZmVhJ11eBELc+zLWc6B9gTmB8RBwI9gE8aFJ2ZmZlZA9RVg9Nd0lKS2pqN0ueky23r2G5lRKyUhKT/iIi3JO1YqIDNzMzMcqm1gBMRrRu4zwWSOgAPAk9J+jcwv4H7MjMzM6u3fLqJ10tEDEyfXippKslEm5MLfRwzMzOz2uQzF1W9pb2ovgcsAxYAuxbjOGZmZmbZFLwGR9JvScbJeQ9YmyYH7kVlZmZmJVLwAg5wLLBdRKwqwr7NzMzMcirGLao5QIci7NfMzMwsL8WowRkNvC5pDvBFZWJE9CvCsczMzMy+phgFnD8Bvwdm81UbHDMzM7OSKUYB57OI+GMR9mtmZmaWl2IUcJ6XNBp4mOq3qF4rwrHMzMzMvqYYBZwe6d99MtLy6iYuqQ9wLdAaGBcRVxQ+PDMzM2vpClrAkdQaeDgixjZw2xuAQ0kGB3xV0sMR8WYhYzQzM7OWr6DdxCNiDTCogZvvBbwbEe+lY+jcA/QvWHBmZma23ijGLaoXJV0P3AusqEzMow3OlsD7GcsLgL0LH56ZmZm1dIqIwu4wmWCzpoiIOtvgSDoa6BMRJ6fLg4G9I+LMjDynAKekizsCbxcm6oLoCCxp7CBoOnFA04nFcVTnOKpzHNU5juocR3VNJY5MW0dEp5qJxZhN/MAGbroQ+E7Gctc0LXPftwC3NHD/RSVpekT0dBxfaSqxOA7H4Tgch+NoWXHko+BTNUjaVNIYSdPTx9WSNs1j01eB7SVtI2lD4HiSruZmZmZm9VKMuahuB5aRTLp5LLAUGJ9ro4j4EjgTeAKYC9wXEW8UIT4zMzNr4YrRyHi7iPhRxvJISTPz2TAiHgMeK0JMpdBUbp01lTig6cTiOKpzHNU5juocR3WOo7qmEkdOxWhk/BIwLCJeSJf3B66KiH0LeiAzMzOzWhSjgNMduAPYFBDwL2BIRMwq6IHMzMzMalHwNjgRMSsiugPfA3aLiB4trXAjqZukOU0xBkm9JL0haaakjRojNms6JHWQdHpjxwF1nrPnStq4MWJqCiSdLWmupBWSdm6kGP7WGMetSdLyxo7BWo6Ct8GR9B/Aj4BuwAaSAIiIywp9LMvqBGB0RNzV2IE0VZJap6Nurw86AKcD/93IcdTlXOAu4LNGjqOxnA4cAlwO7AyUfHqaiNiv1Mc0K7Zi9KJ6iGSKhS9JRjKufLQ0G0i6O/3l9T+SNpa0p6S/SZolaZqk9iWO4WySnmu/TdO7SHourc2ZI6lXMYOR9FNJf0///zslfUvSxHR5lqSiX0TTWoK3srw38yT9XtJrwDEFPF47SY+m/98cScdJukLSm+lrcVWa75h0/SxJz6VpQyQ9JKlC0v9KGlGouDJcAWyXngNXSvovSbPTOBpjMtts5+wWwNRaBgktqCzn6HaSXk5fk8tLXYMg6SZgW+CfwInAlel7tV2J41ie/i3pNaOOeMolTcpYvl7SkCIer/K6MUHSO+k5eoikF9PP5l6SOkl6Kq0hHydpvqSORYon23VlnqQ/pOfqNEn/WYxj14ijWq2rpAskXSrp55JeTeO7X021BjYiCvoA5hR6n03tQVI7FcD+6fLtwIXAe8CeadomwAYljuECYAJwdJr2S+BX6fPWQPsixrML8A7QMV3ejGS6jnMzjr9pI703FwDzgAuLcLwfAbdmLG9NMsJ2Zfu2Dunf2cCWNdKGAIuAzYGNgDlAzyK8HnPS54cDfwM2rnyPiv1+1OO96ViC42c7RycBg9LlU4HlpXxN0uPOIxkdtuqz2wgxLE//luyakSOOcmBSRvr1JG05i3lufgnsRvLDf0Z6forkB/uDaQzD0/x90nO5KOdtluvKpul5Uvne/DTz9Sny6zInY/kC4FJg84y0y4GzSnme5PsoRg3O3yTtVoT9NjXvR8SL6fO7gMOARRHxKkBELI1kbJ9SxlBWY/2rwFBJl5K0h1pWxFgOAv4aEUsAIuJfadqN6fKaiPi0iMfPVNvrcm8RjjUbODStHepFMvr2SuA2ST/kq9suLwITJP2c5Iuj0lMR8XFEfA48wNffw0I6BBgfEZ9B1XtUarnO2WLKdo7uC/w1Xf/nEsbSVJXymtHU/DMiZkfEWuANYEok3+CzSb7oy0gmgSYiJgP/LmIs1a4rGdfOv2T8bcyeybtKel7SbJJmEbs0Yiy1KkYBpwyYIenttCp4tqS/F+E4ja1m97OlTSCGassR8RzQm+RLd4Kkn5YqsEZW2+tS8FulEfEO8H2SC9LlwMXAXsD/AH2ByWm+U4Ffk0xHMkPS5jlibanWt/+3WWlC14wvqf791LYEx/wi4/najOW1FGfMuFrVvK5IuqRyVWa2EoRS2/swATgzInYDRlKa96feilHAORzYHvgBcBTJRf6oIhynsW0lqbIE/WPgZaCLpD0BJLWXVOwPRc0YXshcKWlr4P8i4lZgHMkHplieAY6p/OKWtBkwBTgtXW6t/KbsKIQ6X5dCkrQF8FkkjbqvJPly2DSSQSvPA7qn+baLiFci4hJgMV/Nu3aopM2U9HgbQFLTU0jLgMq2YE+R/DrfOI1pswIfKx/Z3pvMGIsp2zn6MsntAEimh2lMpXodalXia0Zd5gM7S/oPSR2AgxspjkwvkrRxRNIPgG8W60BZriuV78NxGX9fKtbxM/wf0FnS5ko6EPVN09sDiyS1IanBaZKKMdnm/ELvs4l6GzhD0u0kvR6uI7mAXpd+WX1OckugmI0Wa8ZwI9V7y5QDwyStTuMo2q+xiHhD0ijgWUlrgNeBc4BbJJ0ErCEp7JTiQ5ntdTmrSMfajaRh6FpgNXA+MElSW5L79+en+a6UtH2aNgWYBewOTAPuJ5lc9q6ImF7I4CLi47Sh5BzgcZL53aZLWkUyavjFhTxeHrK9N6uAyZI+iIZP1ptTLefoucBdkn5FUttWqtuo2dwD3Kqk4fXREfGPRoihnBJdM+oSEe9Luo+kXdo/Sd6rxjYS+IukwSTXsQ9JCqXFUPO6chpJrfA30zsiXwCDinTsKhGxWtJlJNephcBb6arfAK+Q/Fh7hUYumNem4AP9mTUmSd1IGt/t2tix5JL2CukZEWc2dizrq7Q26/OICEnHkzQ47t/YcVnTk9ZgrImIL9NayBsjYvcSHn8eyfViSamO2dyV9L6imVkTswdwvSQBnwA/a9xwrAnbCrhPUiuSWsefN3I8loNrcMzMzKzFKUYjYzMzM7NG5QKOmZmZtTgu4JiZmVmL4wKONRtK5rb6s6T3JM2Q9JKkgRnrr5G0MG0EWJk2RNJiJXPrvJmOJFwz/Q2lc1al6/aR9Eq6bm46qmu2eO5OB7ScI+n2dEyIynl0Pk23n5kxSJeZrSNJIenqjOULKj+jSuZJWqiv5tLqlyX9LUk3Zl4naux/TcZ1YZakX9aW15o2v2nWLKS9XB4EnouIbSNiD5KB2bqm61sBA4H3gQNqbH5v2p2zHPidpG9lpkfELiS9IioH0foTcEq6za7AfbWEdTfwXZIxKzYCTs5Y93y6790j4rIG/dNmls0XwA9V+0SXY9PP7jHA7RmFk8r0nUk+szWvE5U+z7guHEoyeG0xJsK1InMBx5qLg4BVEXFTZUJEzI+I69LFcpL5Y26klgGwIuIj4B8kE2JWUTLidDu+mlumM8kkmJVzaL1Zy/4eixTJQFhdG/avmVk9fAncQjJSeK0iYm6at2ZBaEOSqQVyziWVXjNOAc5Mf2RZM+ICjjUXuwCv1bF+EMkEdBOBIytvF2WStC2wLfBumnScpJkkI3RuBjySpo8F3pY0UdIv0lGJa5UeazDpvFOpfdPq7cclNcmJ6MyasRuAE1TH9C+S9iaZR2pxmnRe+nlfBLwTETPzOVBEvEcyQW7ndQnYSs8FHGuWJN2QFiBelbQhcATwYEQsJRk6/LCM7JUFmb8Av8iYRbvy1tW3SSa1GwaQ3lLqCTxJMl9SZsElm/8muXX2fLr8GrB1RHQnmcLjwXX5X82suvRzfgdwdpbVlQWZq4Dj4qvB3ipvUXUG2qUjV1sL5gKONRdvkDHxX0ScQTIBXyeSwkwHYHY6nHkZ1W9TVba12TsiJtbccXoBfIRkoszKtH9ExI3pMbormWzuibTx4bjKfJJGpDGcn7Ht0ohYnj5/DGhTR3sBM2uYa4CTSG4vZxqbft57ZfzoqBIRq0l+tPSW9J2MzgCnZjtIWvO7BviosOFbsbmAY83FM0BbSadlpG2c/h0EnBwR3SKiG7ANySzdG5O/MpL2OUg6MuN++/YkF7dPIuKw9MJ5cprvZJLC1aCIWFu5I0nfrtxe0l4kn7OP6/fvmlld0prY+0gKOXlLP5v7A/+IiPczOgPclCVvJ+Am4PqMmiBrJjwXlTUL6WSIA4Cxki4kua++gqR3w1jg1Iy8KyS9AByVY7fHSSojKYAsAIak6YPT43xG0kjxhIhYk2X7m4D5wEtpeeaB9PbW0cBpkr4kmVX+eF8czYriaiDfyWrPk/QToA3wd5Jby9lslN7iakPy+b8TGLOOcVoj8FxUZmZm1uL4FpWZmZm1OC7gmJmZWYvjAo6ZmZm1OC7gmJmZWYvjAo6ZmZm1OC7gmJmZWYvjAo6ZmZm1OC7gmJmZWYvz/wGDjOeYlV4vFAAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_cas['app']\n", + "gap_22_cas = df_gap22_cas['simSeconds'].astype(float)*1000\n", + "gap_22_ram = df_gap22_ram['simSeconds'].astype(float)*1000\n", + "gap_22_orc = df_gap22_orc['simSeconds'].astype(float)*1000\n", + "gap_22_noDC = df_gap22_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "\n", + "gap_25_cas = df_gap25_cas['simSeconds'].astype(float)*1000\n", + "gap_25_ram = df_gap25_ram['simSeconds'].astype(float)*1000\n", + "gap_25_orc = df_gap25_orc['simSeconds'].astype(float)*1000\n", + "gap_25_noDC = df_gap25_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "\n", + "app_npb = df_npbC_cas['app']\n", + "npb_C_cas = df_npbC_cas['simSeconds'].astype(float)*1000\n", + "npb_C_ram = df_npbC_ram['simSeconds'].astype(float)*1000\n", + "npb_C_orc = df_npbC_orc['simSeconds'].astype(float)*1000\n", + "npb_C_noDC = df_npbC_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "npb_D_cas = df_npbD_cas['simSeconds'].astype(float)*1000\n", + "npb_D_ram = df_npbD_ram['simSeconds'].astype(float)*1000\n", + "npb_D_orc = df_npbD_orc['simSeconds'].astype(float)*1000\n", + "npb_D_noDC = df_npbD_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "\n", + "# Multi bar Chart1\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,3])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*4, gap_22_cas[i]/gap_22_noDC[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + " plt.bar(i*4+1, gap_22_ram[i]/gap_22_noDC[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", + " plt.bar(i*4+2, gap_22_orc[i]/gap_22_noDC[i], width=1, color=cmap(3), label='Oracle' if i==0 else None)\n", + "\n", + "offset = i*4+3\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*4+1, npb_C_cas[i]/npb_C_noDC[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*4+2, npb_C_ram[i]/npb_C_noDC[i], width=1, color=cmap(2))\n", + " plt.bar(offset+i*4+3, npb_C_orc[i]/npb_C_noDC[i], width=1, color=cmap(3))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", + "plt.legend(fontsize=8, ncol=3)\n", + "plt.tight_layout()\n", + "\n", + "# Multi bar Chart2\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,3])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*4, gap_25_cas[i]/gap_25_noDC[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + " plt.bar(i*4+1, gap_25_ram[i]/gap_25_noDC[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", + " plt.bar(i*4+2, gap_25_orc[i]/gap_25_noDC[i], width=1, color=cmap(3), label='Oracle' if i==0 else None)\n", + "\n", + "offset = i*4+3\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*4+1, npb_D_cas[i]/npb_D_noDC[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*4+2, npb_D_ram[i]/npb_D_noDC[i], width=1, color=cmap(2))\n", + " plt.bar(offset+i*4+3, npb_D_orc[i]/npb_D_noDC[i], width=1, color=cmap(3))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", + "plt.legend(fontsize=8, ncol=3)\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_cas['app']\n", + "gap_22_cas = df_gap22_cas['totBW'].astype(float)\n", + "gap_22_ram = df_gap22_ram['totBW'].astype(float)\n", + "gap_22_noDC = (df_gap22_noDC['farAvgRdBWSys'].astype(float)+df_gap22_noDC['farAvgWrBWSys'].astype(float))/1000000000\n", + "\n", + "\n", + "gap_25_cas = df_gap25_cas['totBW'].astype(float)\n", + "gap_25_ram = df_gap25_ram['totBW'].astype(float)\n", + "gap_25_noDC = (df_gap25_noDC['farAvgRdBWSys'].astype(float)+df_gap25_noDC['farAvgWrBWSys'].astype(float))/1000000000\n", + "\n", + "app_npb = df_npbC_cas['app']\n", + "npb_C_cas = df_npbC_cas['totBW'].astype(float)\n", + "npb_C_ram = df_npbC_ram['totBW'].astype(float)\n", + "npb_C_noDC = (df_npbC_noDC['farAvgRdBWSys'].astype(float)+df_npbC_noDC['farAvgWrBWSys'].astype(float))/1000000000\n", + "\n", + "npb_D_cas = df_npbD_cas['totBW'].astype(float)\n", + "npb_D_ram = df_npbD_ram['totBW'].astype(float)\n", + "npb_D_noDC = (df_npbD_noDC['farAvgRdBWSys'].astype(float)+df_npbD_noDC['farAvgWrBWSys'].astype(float))/1000000000\n", + "\n", + "\n", + "# Multi bar Chart1\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "#plt.ylim([0,2.5])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + " plt.bar(i*3+1, gap_22_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", + "\n", + "offset = i*3+2\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_C_cas[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*3+2, npb_C_ram[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "#plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Observed BW at LLC (GB/s)\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "\n", + "# Multi bar Chart2\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "#plt.ylim([0,2.5])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + " plt.bar(i*3+1, gap_25_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", + "\n", + "offset = i*3+2\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_D_cas[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*3+2, npb_D_ram[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "#plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Observed BW at LLC (GB/s)\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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ngsEGdBzc3MTaqNnz5788ssvLFu2jN69e5OTk8MxxxzDNddcAwS3UKxcuTKqTUpavAB1EsENuU+Z2f+Z2cdmthRYTJDZ/B53H5/iPoqIVBvZ2dnMmjULgFmzZtGtWzdmz55duHzssccWrrtt2zaeeOIJIPEAtW7dOmrXrk2tWrXo06cPw4YNK8ya3qNHjxRsUfJKDVDuvtHdHwhH77UgmA33KHdv4e6XuPt7FdJLEZFqIjs7m7fffhsIAtI111xTuDxv3jzGjBnDn/70J0499VRmzpxJ69atgeCepClTppCTk0N+fj6LFi2iR48edOvWjbPPPpsNGzYA8Morr3DyySczb948DjnkEDIzf70/trgs59dffz1dunShc+fOTJ48GYAnn3ySrl270rlzZwYMGFCYSql58+YMGjSITp06cfXVV5d7XyQ8l5O7b3H3r3Tvk4hI6jRv3pw1a9awYcMGvvrqK3r06MGiRYtYuXIljRo1om7durRo0YLJkycXZjOB4J6knj17kpeXR4cOHQrTD02bNo2srCweeeQRACZPnsxpp53GihUraNasWal9efXVV1m3bh0zZszgzTff5K9//SvuTq9evZg+fTpz5szhxx9/ZObMmUCQrWLkyJHMmTOHyZMns379+nLtizJlMxcRkdQ7+uijyc3NpUmTJtSoUYMaNWowbdo0srOzWb16Ncccc0zcOj766KPCmW83btxIjx492LJlC2vXrqVJkyY0a9YsbgaIRYsWMWPGjMJAuGnTJtauXcv8+fO588472bZtG8uXL+f0008HoGnTpjRp0gSAjIwM1q1bx29+85uk94NmwxURSTPZ2dnccccdhYHoqKOO4t577y28/lSjRo2dXlM00/jhhx/OU089RV5eHnPnzuVvf/sbeXl5dOnSBQiC4Oeff05sPtPXX399hzrbtGnDCSecQF5eHnl5eXzwwQc0atSI6667jieeeIIZM2bQsWPHwlN8BVnPC5R3gHfCR1Bm1gI42N3fMLO6QE13/7FcrYuIVBEVOTw8OzubwYMHFwaorKws/v73v5OVlcULL7xQ7GuOOOIIvvjiC/r06cPw4cO5//776devH1u2bAGCa0m5ubkMHDgQgJo1a/Lcc88xZMgQ1q1bx5YtW8jKyuKEE04orPOUU05h9uzZ5OTkYGZkZGTw+OOPc8EFF3D88cdz6KGH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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "x1 = df_gap22_cas['app']\n", + "y1 = 100 * df_gap22_cas['numRdMissClean'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", + "y2 = 100 * df_gap22_cas['numRdMissDirty'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", + "y3 = 100 * df_gap22_cas['numWrMissClean'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", + "y4 = 100 * df_gap22_cas['numWrMissDirty'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(6,3)\n", + "plt.ylim([0,110])\n", + "\n", + "for i,app in enumerate(x1): \n", + " plt.bar(i*4, y1[i], width=3, color=cmap(1), label='Read/Clean' if i==0 else None)\n", + " plt.bar(i*4, y2[i], bottom = y1[i], width=3, color=cmap(2), label='Read/Dirty' if i==0 else None)\n", + " plt.bar(i*4, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3), label='Write/Clean' if i==0 else None)\n", + " plt.bar(i*4, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4), label='Write/Dirty' if i==0 else None)\n", + "\n", + "offset = (i+1)*4\n", + "x2 = df_npbC_cas['app']\n", + "y1 = 100 * df_npbC_cas['numRdMissClean'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", + "y2 = 100 * df_npbC_cas['numRdMissDirty'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", + "y3 = 100 * df_npbC_cas['numWrMissClean'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", + "y4 = 100 * df_npbC_cas['numWrMissDirty'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", + "\n", + "for i,app in enumerate(x2): \n", + " plt.bar(i*4+offset, y1[i], width=3, color=cmap(1))\n", + " plt.bar(i*4+offset, y2[i], bottom = y1[i], width=3, color=cmap(2))\n", + " plt.bar(i*4+offset, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3))\n", + " plt.bar(i*4+offset, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*4, list(x1)+list(x2))\n", + "plt.axvline(x=offset-2, color='black')\n", + "\n", + "plt.ylabel(\"DRAM Cache Miss Rate (%)\", fontsize=10)\n", + "plt.legend(fontsize=9, ncol=1)\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_mpki.pdf\")\n", + "\n", + "x1 = df_gap25_cas['app']\n", + "y1 = 100 * df_gap25_cas['numRdMissClean'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", + "y2 = 100 * df_gap25_cas['numRdMissDirty'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", + "y3 = 100 * df_gap25_cas['numWrMissClean'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", + "y4 = 100 * df_gap25_cas['numWrMissDirty'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(6,3)\n", + "plt.ylim([0,110])\n", + "for i,app in enumerate(x1): \n", + " plt.bar(i*4, y1[i], width=3, color=cmap(1), label='Read/Clean' if i==0 else None)\n", + " plt.bar(i*4, y2[i], bottom = y1[i], width=3, color=cmap(2), label='Read/Dirty' if i==0 else None)\n", + " plt.bar(i*4, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3), label='Write/Clean' if i==0 else None)\n", + " plt.bar(i*4, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4), label='Write/Dirty' if i==0 else None)\n", + "\n", + "offset = (i+1)*4\n", + "x2 = df_npbD_cas['app']\n", + "y1 = 100 * df_npbD_cas['numRdMissClean'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", + "y2 = 100 * df_npbD_cas['numRdMissDirty'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", + "y3 = 100 * df_npbD_cas['numWrMissClean'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", + "y4 = 100 * df_npbD_cas['numWrMissDirty'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", + "\n", + "for i,app in enumerate(x2): \n", + " plt.bar(i*4+offset, y1[i], width=3, color=cmap(1))\n", + " plt.bar(i*4+offset, y2[i], bottom = y1[i], width=3, color=cmap(2))\n", + " plt.bar(i*4+offset, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3))\n", + " plt.bar(i*4+offset, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*4, list(x1)+list(x2))\n", + "plt.axvline(x=offset-2, color='black')\n", + "\n", + "plt.ylabel(\"DRAM Cache Miss Rate (%)\", fontsize=10)\n", + "plt.legend(fontsize=9, ncol=1)\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAagAAADfCAYAAACj4kcNAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAfx0lEQVR4nO3de5xd873/8de7kTShiEhcIxLiOCVOSuLWjOYiWi0nQkOlCA4NLUVUqzdSPdqf0lIPNOquPalLpSTEoZpk4pISuSAiQqRRcVK5lCgShM/vj7V2bGNm9p49e83smf1+Ph7zmL2+a+3v97P27bPXWt/9/SoiMDMzqzSfau0AzMzM6uMEZWZmFckJyszMKpITlJmZVSQnKDMzq0ibtHYAzdG9e/fo3bt3a4dhVWrx4sUA7L777q0ciVnbNnfu3NUR0aNueZtOUL1792bOnDmtHYZVqSFDhgBQW1vbqnGYtXWSXq6v3Kf4zMysIjlBmZlZRXKCMjOzitSmr0HV54033mDFihWtHYZlqHPnzvTs2ZOOHTu2dihmlqF2l6BWr15N79696dKlS2uHYhmICNasWcPy5cvp06dPa4djZhlqd6f43n//fTp37tzaYVhGJLH11luzfv361g7FzDLW7hIUJB9i1n75+TWrDu3uFF++A8Y/WJZ6Hr/oS42uX7ZsGXvvvTf9+/dn3bp1jB49mnPOOafk9vr27cuSJUtKvn9dI+45rCz1TBk5tdH13/rWtzjkkEM48sgjee655+jXrx+rV6+mW7du/OY3v2HNmjVccMEFG7c/7rjjmDhxIsuWLeOZZ55hxIgRZYnTzNqHdnkE1RoGDBhAbW0ts2bNYsKECbz99tutHVKLq6mp4bHHHgPgscceY9iwYcyaNWvj8kEHHbRx2w8++ICJEycCSYKfMmVKywdsZhXNCarM3nnnHd577z02bNjAqaeeytChQ6mpqWH27NkAXH755QwbNox9992X8ePHA/Dhhx9y/PHHM3jwYMaNG9ea4TdLTU0Njz76KJAkpO9+97sbl2fPns2ECRM4/fTTOfzww3nkkUfo27cvkDwmU6dOZciQIcydO5cFCxYwfPhwhg0bxjHHHMO6detabZ/MrPU4QZXJ3LlzGTx4MDvttBNnnHEGt912G3379mXGjBlMmjRpY+I57bTTmD59OrNnz+ahhx7i73//O5MnT2azzTZj5syZjBo1ig0bNrTy3pSmV69erF69mnXr1rFixQqGDx/OggULWL58Od27d6dLly7svPPO3HfffRuHCQI499xzOeyww6itrWXAgAGcccYZ3HTTTUyfPp1BgwZx4403tt5OmVmryewalKSbgMOBlRHRLy3rBtwB9AaWAcdExOtKrnpfCXwFeAc4KSLmZRVbFgYMGMBf/vIXnn76ac4//3x23XVXZs2axQMPPADA2rVrAZg0aRI33HADkli6dCmvvPIKL7zwAvvttx8A+++/f5vuBLDffvsxZcoUtttuOzp06ECHDh2YPn06NTU1rFq1is9//vMF61i4cCFjxowBYP369QwfPjzrsM2sAmV5BHULcGidsu8D0yJiN2BaugzwZWC39G8sMCHDuDLVv39/dthhB/bcc0/GjBlDbW0ttbW1zJuX5NsLLriABx98kBkzZtCnTx8igt12223joLdPPvkkEdGau9AsNTU1XHrppRsT0T777MOVV1658fpThw4dPnGfTp06feyosV+/ftx2223U1tby+OOPc+GFF7ZM8GZWUTJLUBHxMPDPOsVHALemt28FRuaV/y4SjwNdJW2fVWxZGzduHL///e9ZvHgxQ4cOZejQofzoRz8C4KijjmLQoEEcf/zxfOYznwHgiCOOYO3atQwePJi7776bTTZpu50ra2pqmDdv3sYENWjQIObPn8+gQYMavM9ee+3FSy+9xKhRo1iwYAHXXHMNJ510EsOGDWPYsGHMnDmzpcI3swqiLL+tS+oN3Jd3iu+NiOia3hbwekR0lXQfcElEPJqumwacHxGNzqUxcODAqDvdxqJFi/jsZz9b9n2xylIJz7On2zArD0lzI2Jg3fJW6yQRSWZscnaUNFbSHElzVq1alUFkZmZWCVo6Qb2WO3WX/l+Zlr8K7JS3Xc+07BMi4rqIGBgRA3v0+MQEjGZm1k60dIKaApyY3j4RmJxXPkaJA4C1EVHykORtuZOBFebn16w6ZNnN/DZgCNBd0nJgPHAJcKekU4CXgWPSze8n6WK+hKSb+cmlttuxY0fWr1/v0czbqdxo5h4Q2Kz9yyxBRcToBlYdXM+2AZxRjna7d+/OsmXLylGVVajcfFBm1r613f7MDejatStdu3Zt7TDMzKyZPNSRmZlVJCcoMzOrSE5QZmZWkQpeg5LUmWTQ14OAHYB1wLPA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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "x1 = df_gap22_cas['app']\n", + "y1 = 100 * df_gap22_cas['numRdHit'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", + "y2 = 100 * df_gap22_cas['numWrHit'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(6,3)\n", + "plt.ylim([0,110])\n", + "\n", + "for i,app in enumerate(x1): \n", + " plt.bar(i*4, y1[i], width=3, color=cmap(1), label='Read' if i==0 else None)\n", + " plt.bar(i*4, y2[i], bottom = y1[i], width=3, color=cmap(2), label='Write' if i==0 else None)\n", + "\n", + "offset = (i+1)*4\n", + "x2 = df_npbC_cas['app']\n", + "y1 = 100 * df_npbC_cas['numRdHit'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", + "y2 = 100 * df_npbC_cas['numWrHit'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", + "\n", + "for i,app in enumerate(x2): \n", + " plt.bar(i*4+offset, y1[i], width=3, color=cmap(1))\n", + " plt.bar(i*4+offset, y2[i], bottom = y1[i], width=3, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*4, list(x1)+list(x2))\n", + "plt.axvline(x=offset-2, color='black')\n", + "\n", + "plt.ylabel(\"DRAM Cache Hit Rate (%)\", fontsize=10)\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_mpki.pdf\")\n", + "\n", + "x1 = df_gap25_cas['app']\n", + "y1 = 100 * df_gap25_cas['numRdHit'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", + "y2 = 100 * df_gap25_cas['numWrHit'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(6,3)\n", + "plt.ylim([0,110])\n", + "\n", + "for i,app in enumerate(x1): \n", + " plt.bar(i*4, y1[i], width=3, color=cmap(1), label='Read' if i==0 else None)\n", + " plt.bar(i*4, y2[i], bottom = y1[i], width=3, color=cmap(2), label='Write' if i==0 else None)\n", + "\n", + "offset = (i+1)*4\n", + "x2 = df_npbD_cas['app']\n", + "y1 = 100 * df_npbD_cas['numRdHit'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", + "y2 = 100 * df_npbD_cas['numWrHit'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", + "\n", + "for i,app in enumerate(x2): \n", + " plt.bar(i*4+offset, y1[i], width=3, color=cmap(1))\n", + " plt.bar(i*4+offset, y2[i], bottom = y1[i], width=3, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*4, list(x1)+list(x2))\n", + "plt.axvline(x=offset-2, color='black')\n", + "\n", + "plt.ylabel(\"DRAM Cache Hit Rate (%)\", fontsize=10)\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_mpki.pdf\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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yPT+COA3kXgK6JIuC1HR7r77bg499FB69+4NJAuSHnxwUuNzwgknUF1dzR577MGddyYv2S233MLee+/NoEGDGDduHAAPPfQQ++23H9XV1Zx11lkAnHvuuQwaNIg99tiDCRMmALBy5UqGDRvGkCFDuOSSS2pjWLhwIcOGDWPw4MEMGzaMpUuXZor94IMPprq6mr333psnn3xyvX1vv/02I0eO5N5772XWrFkMGTKEwYMHM2rUKFatWtWMV6xydenShe985zvcdNNN65WvW7eO5cuXExEAPPfcc+yyyy6cfvrpTJ48eb1jhw4dyt13382SJUvo0KEDXbp0KVf4ZmZWIEsT1YXA3sDDABExQ1KvxpxEUk+gP/A3oFvB0g//ImnCgiT5WVjwsNfTssJlIirOwoUL6dGjR9F9V199NZ06deLNN9/kgAMOYPjw4dx0001MnjyZT3/606xbt46I4PTTT+eRRx6hW7durF27FoDzzz+fTp06sXr1anbbbTfGjBnDxIkTGThwIOPGjePGG29kzpw5AJxzzjl873vfY5999mHKlClcdtllXHHFFSVjv+222+jUqRNz585l7Nix/OUvyXqqixcv5ogjjuDiiy9mr7324nOf+xyTJ09mu+224+c//znXXXcdZ5xxRgu9gpWlR48eLFq0CEhGPFVXV/Pqq6/Sv3//2sT1xhtv5IQTTmDAgAGcffbZrFmzhg4dOgBw9NFHc+aZZ7Jo0SJGjRpVm5yamVl5ZUlw1kTEijqjkiLrCSR9HPgjcGZEvF34PBERkjI/V/p8pwCnAGy3XesvidWjRw9mz579kfJ169Zx0UUX8cQTT7DxxhuzYEGyVMb48eO54ooreOeddxg1ahT77rsvXbt2rR02XNPH45prruGOO+6gqqqKJUuWsGTJEl566SWOOOIIAD772c8yceJEAGbNmsV5550HwAcffECfPn1Kxr1q1Sq+8Y1vMG/ePKqqqmr/qAP84he/YOzYsey1114AvPDCCxx//PEAvPfeewwZMqRJr1VbsHDhQrbZZhuA2iaqFStWMHToUJYvX84WW2zBlClTat/zJUuWcM8999T27+nevTsrV67klltu4YEHHnCCY2bWSrIkOC9IOhaoktQX+DrwRJYnl9SBJLm5MZ0NGeANSd0jYnHaBLUkLV9E0oG5xrZp2XoiYgIwAWDAgAGNSo7y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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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J2lToEdEXNCExx5MkhzNkjQjLfs/ksTmVkknAPOAMem6e4ADgZeBd4BxTThWm1m+fDnHHHMMt99+O3369CEiuP/++9s6LKtniy22qEsGa2trmTJlCttvv/16fy9btoyDDz6YHXfckaFDh1JTU1O3z/HHH8/999/PiBEjALjrrrsYNmwYjz32GEOGDAGS6qe///3vrFq1is6dO/Pb3/6WT37yk23xdM3MNnhlq5okHQTMAO5NlwdIurPcfhHx54hQRHw8Igakt3si4s2I2C8i+kXE8Ij4V7p9RMT4iOgTEf0jol0MUXz33Xdz0EEH0adPHyCZkPSAA5IrPscddxy1tbXsscce3Hln8pLdcsst7LXXXgwdOpQJEyYA8NBDDzF48GBqa2s544wzADj77LMZOnQoe+yxBxMnTgRgxYoVjBw5kuHDh3PRRRfVxTB//nxGjhzJsGHDGDlyJA21TarvgAMOoLa2lr322osnnnhivXVvvfUWBx98MPfeey+zZs1i+PDhDBs2jDFjxrBy5coWvGLVq2vXrnzzm9/kpptuWq983bp1LFu2jKTJGDz77LPstttunHrqqUyZMmW9bUeMGMHdd9/N4sWL6dSpE127dq1U+GZmViRLFdX5wF4k3bmJiBmSeucYU7syf/58evbsWXLdT3/6U7p06cKbb77Jvvvuy6hRo7jpppuYMmUKH/vYx1i3bh0RwamnnsojjzzCtttuy9q1awE499xz6dKlC6tWraJ///6MGzeOSZMmMWTIECZMmMCNN97InDlzADjrrLP49re/zd57783UqVO59NJLufzyy8vGftttt9GlSxfmzp3L+PHj+eMfk/lUFy1axGGHHcaFF17InnvuyWc/+1mmTJnCDjvswI9//GOuu+46TjvttFZ6BatLz549Wbgwafq1du1aamtrefXVVxk4cGBd4nrjjTdy3HHHMWjQIM4880zWrFlDp06dADjyyCM5/fTTWbhwIWPGjKlLTs3MrLKyJDhrImJ5vV5JTer51JH17NmT2bNnf6B83bp1XHDBBTz++ONsvPHGzJuXTJVx8cUXc/nll/P2228zZswY9tlnH7baaqu6bsOFNh7XXHMNd9xxBzU1NSxevJjFixfz0ksvcdhhhwHwqU99ikmTJgEwa9YszjnnHADee+89+vbtWzbulStX8tWvfpUXX3yRmpqauh91gCuvvJLx48ez5557AvD8889z7LHHAvDuu+8yfPjwZr1W7cH8+fPZbrvtAOqqqJYvX86IESNYtmwZW265JVOnTq17zxcvXsw999xT176nR48erFixgltuuYUHHnjACY6ZWRvJkuA8L+looEZSP+ArwOP5htV+jBw5kosvvpgTTjihrppq2rRpbL311sycOZM///nPLF26tG5d7969mThxIqtWraJfv37MmzePf/3rXyxZsoTu3buzbt06li9fzg033MDMmTNZs2YNO++8MxFBv379mD59Ovvttx9PPfVUXQy77bYbEyZMYODAgQCsXr26bNz33nsvNTU1PProo8yZM4dRo0bVrfvud7/Lfffdx+TJkxk7diy77747N998Mz169Mj8+O3R8uXLufjii/nWt761XvkWW2zBKaecwqWXXsoBBxzA6NGj666QvfLKK0yYMKEuwQEYP348c+bMYdNNN61o/GZm9r4sCc6XgW8Cq4CbgPuA7+UZVGsp1/upNWyxxRZMmTKF8ePH8+6777J69WoOP/xwTj75ZNasWcO+++7LgAED6tpinHXWWcyaNYs1a9Zw8sknI4mrr76aUaNG0blzZwYOHMgPfvADdt11V4YMGcIuu+zCVlttBcCJJ57ImDFjmDZtGrvvvntdDFdccQXjx49nxYoVQNIgtn4vqH/84x/rXXmZMmUKF198McOHD2fw4MHrbbvxxhszZcoUxo0bx5o1a7j66qsZO3Zs3ejQEyZMYP/992+117CtR/08/PDDqampYd26dRx//PEMGzbsA9sceeSR9O/fn6VLl3L00UfXlffp04e5c+fy1lvvD/F04IEHcuCBB1YkdjMzK02FhpMlV0o1wAMRMbRyIWU3aNCgmD59/bbIc+fOZZdddmmjiMzKa++f0draWoDMQxSYtXeeqqG6SXo6IgbVL2+0F1VErAXWSdoit8jMzMzMWlmWKqoVJGPZTAPeLhRGxFdyi8rMzMysBbIkOLelt3YjIjwXlVWlxqqEzcys9WQZyfgXlQiktWyyySa8+eabbLXVVk5yrOq8++67dWPmmJlZfhpMcCT9HpgI3BsRa+qt2wkYC7weEdfnGmETbb/99ixYsCDzaL5mlVbobm9mZvlp7ArOicCZwI8k/QtYAmwC9CaZL+qqiJjayP5tolOnTvTu7YGWzczMNmQNJjgR8U/gG8A3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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_cas['app']\n", + "gap_22_cas = df_gap22_cas['avgTimeTagCheckResRd'].astype(float)\n", + "gap_22_ram = df_gap22_ram['avgTimeTagCheckResRd'].astype(float)\n", + "\n", + "\n", + "gap_25_cas = df_gap25_cas['avgTimeTagCheckResRd'].astype(float)\n", + "gap_25_ram = df_gap25_ram['avgTimeTagCheckResRd'].astype(float)\n", + "\n", + "\n", + "app_npb = df_npbC_cas['app']\n", + "npb_C_cas = df_npbC_cas['avgTimeTagCheckResRd'].astype(float)\n", + "npb_C_ram = df_npbC_ram['avgTimeTagCheckResRd'].astype(float)\n", + "\n", + "npb_D_cas = df_npbD_cas['avgTimeTagCheckResRd'].astype(float)\n", + "npb_D_ram = df_npbD_ram['avgTimeTagCheckResRd'].astype(float)\n", + "\n", + "\n", + "# Multi bar Chart1\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + " plt.bar(i*3+1, gap_22_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", + "\n", + "offset = i*3+2\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_C_cas[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*3+2, npb_C_ram[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Avg Tag Check Latency (reads) (ns)\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()\n", + "\n", + "# Multi bar Chart2\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + " plt.bar(i*3+1, gap_25_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", + "\n", + "offset = i*3+2\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_D_cas[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*3+2, npb_D_ram[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Avg Tag Check Latency (reads) (ns)\")\n", + "plt.legend(fontsize=9, ncol=2)\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAAClCAYAAABREodCAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAe0klEQVR4nO3deZgU1b3/8fcHRFCjEAUjigoaNaKICxhR1HEFlajEq8afjwvXXLKoiRtJ5CYajYoGl+TGLYpGE427JoG4BhkxRkVQEZTgzwWvCy64ICgiwvf+UdXYDD09NUt1zwyf1/P0M12nu6s+00v16VOnzlFEYGZmZtaedKh2ADMzM7OW5gqOmZmZtTuu4JiZmVm74wqOmZmZtTuu4JiZmVm74wqOmZmZtTuu4JiZmVm74wqOmZmZtTurNXQHSQOA3YENgUXATOChiPgw52xmZmZmTVJvC46kEZKeBs4E1gBmA+8Cg4F/SLpR0iaViWlmZmaWXbkWnDWB3SJiUakbJW0PbAH8bw65zMzMzJpMnovKzMzM2psGOxlL2kzSeEnzJL0r6a+SNqtEODMzM7OmyHIW1Z+B24ENSDoa3wHckmcoMzMzs+Zo8BCVpOciYrs6ZdMjon+uyczMzMyaKEsF5yLgQ+BWIIAjga8CYwEi4oOcM5qZmZk1SpYKzqtlbo6IcH8cMzMza1V8FpWZmZm1O1lGMu4IHAT0Lr5/RFyaXywzMzOzpmuwggOMBz4DZgDL8o1jZmZm1nxZKji96p5FlZfu3btH7969K7EpMytj9uzZAGy11VZVTmJmVt60adPmRUSPuuVZKjj3Sdo/Ih7MIdcKevfuzdSpU/PejJk1oKamBoDa2tqq5jAza4ik10qVZ6ngPAHcI6kDsAQQydlT67RgPjMzM7MWk6WCcykwCJgRPuXKzMzM2oAsFZzXgZnVqNx89NFHzJ07t9KbtXauS5cu9OrVi06dOlU7ipmZ5SRLBecVoFbSfcDiQmElThOfN28evXv3Zo011sh7U7aKiAjef/993njjDfr06VPtOGZmlpMsFZxX08vq6aVilixZQpcuXSq5SWvnJLHeeuvx3nvvVTuKmZnlqMHZxCPinFKXSoSD5AspbxMnTqSmpoY99tiD4cOH8/777+eynTlz5nD88cc3eL8bbriBcePGNXi/wYMHt0Cq6pg/fz41NTXU1NTQtWtXampqGDFiBP3792efffbhgAMOYNq0aUDyfGy11VbstddeHHrooXz++efL17PFFltw6623Ll+uqanh5JNPXr48bNiwlZ7zSrynzMysuhqs4EjqIWmspHslPVy4VCJcJbz33nuce+65jB8/nsmTJ3PRRRet8AVq+ejatSu1tbXU1tbSr18/amtr2XTTTbnkkkuYOHEi1157LSeeeCKffvopAKNGjWLSpEkMGDCABx9MRiyYPn06gwcPZvz48Sus+/XXXyciWLBgAfPnz6/4/2ZmZtWX5RDVzcBtwDDg+8BxQMXb93c5+4FmPf6Jc4aULL/33ns55phjWHvttQHYcsstAfjDH/7AjTfeyMKFC7ngggvYf//9GT16NJMnT6ZTp07cfPPNdOjQgREjRrBo0SIGDRrEmDFjOOKII3jnnXfo3Lkzd955J+ussw5nnXUWkyZNom/fvsu3O2HCBH7961/zxRdfcNZZZzF06NCy+UutF5I+JT/+8Y/Zdddd2WeffTjhhBNYsGABW2+9NVdeeWWznjOAg/9yULMe/7dD/96kx/Xq1YshQ4bw1FNPrVD+0UcfLb9+991388Mf/pALLriAxYsX07lzZwAGDhzIlClTePXVVznwwAOXD1pnZmarjgZbcID1IuI6YElEPBIR/wnsnXOuipk7dy49e/ZcqfzII4+ktraWiRMncvHFFwPw2GOPMXnyZCZNmkTPnj0ZM2YMp556KrW1tZx//vlAcjjlkUce4YgjjuC2225j7ty5TJkyhUcffZQ999wTgGXLlnHxxRfz8MMPU1tby9ixYxvMWXe9BaeccgqDBg3iO9/5DhdeeCFnnnkmkyZNYu211+bxxx9viaeoajbccEPefvttAMaOHUu/fv2YMmUKQ4YkldVnnnmGgQMHMnToUP7xj38sf9zw4cO55557uPfeeznooOZV0MzMrG3K0oKzJP07V9JBwFvAug09SFIXYDLQOd3OnRFxdlOD5qVnz5689dZbK5U/8MAD/Pa3vyUiePfddwH4yU9+wnHHHcd6663H+eefz4svvri8YtOhQweWLl3KqFGjmDFjBh9//DHDhw/ntddeY7vtkpkudtppJx588EHmzZvHrFmz2HfffQF49913iYh6+4aUWi/Aiy++SJcuXfjNb34DwKxZs/jZz36GJBYuXMjOO+/cos9Vpb355ptsvfXW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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAAClCAYAAABREodCAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAetElEQVR4nO3de7xc873/8dc7RIJGUhJtCEkoKkS0klQINkGCFKm6/XpccrSpFq1bnMpRShEEaU/dSigtdb+0SV0b2aKKSBChKT+XOC5xiUskRETyOX+sNTGJ2bPXvqyZvXfez8djHnvWd2bWeu+5rPnOd33X96uIwMzMzKwtaVftAGZmZmbNzRUcMzMza3NcwTEzM7M2xxUcMzMza3NcwTEzM7M2xxUcMzMza3NcwTEzM7M2xxUcMzMza3NWr+8OkvoDOwEbAIuAZ4EHIuKDnLOZmZmZNUqdLTiSRkp6EjgVWBN4HngHGAz8XdJ1kjauTEwzMzOz7Mq14KwF7BgRi0rdKGlbYDPgf3PIZWZmZtZo8lxUZmZm1tbU28lY0iaSJkqaJ+kdSX+RtEklwpmZmZk1RpazqP4M3AJ8naSj8a3AjXmGMjMzM2uKeg9RSXomIrZZqWxmRPTLNZmZmZlZI2Wp4JwPfADcBARwMPBVYBxARLyfc0YzMzOzBslSwXmlzM0REe6PY2ZmZi2Kz6IyMzOzNifLSMarAfsAvYrvHxEX5xfLzMzMrPHqreAAE4FPgVnAsnzjmJmZmTVdlgpOj5XPospL165do1evXpXYlJmV8fzzzwOwxRZbVDmJmVl5M2bMmBcR3VYuz1LBuUfSnhFxfw65VtCrVy+mT5+e92bMrB41NTUA1NbWVjWHmVl9JL1aqjxLBecx4E5J7YAlgEjOnlqnGfOZmZmZNZssFZyLgUHArPApV2ZmZtYKZKngvAY8W43KzYcffsjcuXMrvVlr4zp27EiPHj1o3759taOYmVlOslRwXgZqJd0DLC4UVuI08Xnz5tGrVy/WXHPNvDdlq4iI4L333uP111+nd+/e1Y5jZmY5yVLBeSW9rJFeKmbJkiV07Nixkpu0Nk4S6623Hu+++261o5iZWY7qnU08Is4sdalEOEi+kPI2efJkampq2HnnnRkxYgTvvfdeLtuZM2cORx55ZL33u/baa5kwYUK99xs8eHAzpKqO+fPnU1NTQ01NDZ07d6ampoaRI0fSr18/hgwZwl577cWMGTOA5PnYYost2HXXXdl///357LPPlq9ns80246abblq+XFNTw3HHHbd8efjw4V96zivxnjIzs+qqt4IjqZukcZLulvRg4VKJcJXw7rvvctZZZzFx4kSmTp3K+eefv8IXqOWjc+fO1NbWUltbS9++famtraVnz55cdNFFTJ48mauuuopjjjmGTz75BIDRo0czZcoU+vfvz/33JyMWzJw5k8GDBzNx4sQV1v3aa68RESxYsID58+dX/H8zM7Pqy3KI6gbgZmA4cDRwBFDx9v3tz7ivSY9/7MyhJcvvvvtuDjvsMDp16gTA5ptvDsAf/vAHrrvuOhYuXMi5557LnnvuyZgxY5g6dSrt27fnhhtuoF27dowcOZJFixYxaNAgxo4dy0EHHcTbb79Nhw4duO2221hnnXU4/fTTmTJlCn369Fm+3UmTJnHBBRfw+eefc/rppzNs2LCy+UutF5I+JT//+c/ZYYcdGDJkCEcddRQLFixgyy235LLLLmvScwaw7137NOnxf93/b416XI8ePRg6dChPPPHECuUffvjh8ut33HEHP/3pTzn33HNZvHgxHTp0AGDAgAFMmzaNV155hb333nv5oHVmZrbqqLcFB1gvIq4GlkTEQxHxn8BuOeeqmLlz59K9e/cvlR988MHU1tYyefJkLrzwQgAeeeQRpk6dypQpU+jevTtjx47lhBNOoLa2lnPOOQdIDqc89NBDHHTQQdx8883MnTuXadOm8fDDD7PLLrsAsGzZMi688EIefPBBamtrGTduXL05V15vwfHHH8+gQYM45JBDOO+88zj11FOZMmUKnTp14tFHH22Op6hqNthgA9566y0Axo0bR9++fZk2bRpDhyaV1aeeeooBAwYwbNgw/v73vy9/3IgRI7jzzju5++672WefplXQzMysdcrSgrMk/TtX0j7Am8C69T1IUkdgKtAh3c5tEXFGY4PmpXv37rz55ptfKr/vvvv47W9/S0TwzjvvAHDKKadwxBFHsN5663HOOefwwgsvLK/YtGvXjqVLlzJ69GhmzZrFRx99xIgRI3j11VfZZptkpovtttuO+++/n3nz5jF79mx23313AN555x0ios6+IaXWC/DCCy/QsWNHfvOb3wAwe/ZsfvGLXyCJhQsXMnDgwGZ9rirtjTfeYMstt+Tll19m9OjRjBw5kv3335/333+fBQsWMGvWLIYNG8bixYvZfPPNl1dmNt98c5577jnWXnvt5S1dZma2asnSgnO2pM7AScDJwATghAyPWwzsFhH9gG2BYZK2b2zQvOy9995cf/31LFiwAIAXX3yRuXPnMnbsWO655x7+8pe/0K5d8jTttttu/OlPf2L99ddn0qRJbLHFFjz22GNA0irz9NNP8/HHHzN16lSOOeYYIoKePXsya9YsIGlxAOjatSt9+/Zl8uTJ1NbWMnPmzLIdX0utF5Iv8kMPPZTRo0cDybxBF198MbW1tUyfPp399tsvnyetAt544w0eeOABBgwYsLxstdVW49hjj2X8+PHccccdTJgwgXvvvZcpU6Ywd+5cli37Yi7YAw44gMMOO6wa0c3MrAWotwUnIialV+cDu2ZdcTow4MJ0sX16aXEjIXfr1o1f/vKXDB8+nIhg3XXX5eqrr2b48OHsvPPODBw4kC5dugCw3377sWjRIgBuvfVWdtllF4444gjOPvtsdthhB8aMGcOLL77IsGHD2Gijjdhwww3p3r072223HTvttBP9+vUDktaeE088kSFDhiCJPn36cOmll66Q6+KLL15+dtD48eO/tN6Co446irFjx3L++eczZswYRo0axfz582nXrh0TJkygtU1eetJJJ9G1a1fWWGMNLrnkki+NgbTHHntw2mmnsfrqq69wtlSfPn14+OGHly8XzpyaM2dOJWKbmVkLozwHKJa0GjAD+AZwaUT8V7n79+/fP4on25w9ezZbbrllbvls1eX3VnmebNPMWgtJMyKi/8rlWQ5RNVpELI2IbYEewEBJW5cINkrSdEnTPfiamZmZNYdcKzgFEfEhMAX40rnQEXFlRPSPiP7dunWrRBwzMzNr4+rtgyPpXOCCtJKCpK8CJ0XEafU8rhvJqeUfSloT2AM4v+mRzayaGjomVV1jUFl+/BqZZTtNfK+IGFNYiIgPJO0NlK3gAN2B69J+OO2AW4o6LGdW7vRps8bIs9+Zma2oJVW2WlIWy1+WCs5qkjpExGKAtDWmQ30PiohngG81JVz79u359NNPPZu4NZvCbOKexNXMrG3LOlXDZEl/SJdHAtflF+kLXbt29Wm+1uw6duxIjx49qh3DzMxylGUcnPMlzQR2T4t+HRFNmxgqoy5duiwfg8bMrCXz4Q9rCL9f8pel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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_cas['app']\n", + "gap_22_cas = df_gap22_cas['BWBloat'].astype(float)\n", + "gap_22_ram = df_gap22_ram['BWBloat'].astype(float)\n", + "\n", + "\n", + "gap_25_cas = df_gap25_cas['BWBloat'].astype(float)\n", + "gap_25_ram = df_gap25_ram['BWBloat'].astype(float)\n", + "\n", + "app_npb = df_npbC_cas['app']\n", + "npb_C_cas = df_npbC_cas['BWBloat'].astype(float)\n", + "npb_C_ram = df_npbC_ram['BWBloat'].astype(float)\n", + "\n", + "npb_D_cas = df_npbD_cas['BWBloat'].astype(float)\n", + "npb_D_ram = df_npbD_ram['BWBloat'].astype(float)\n", + "\n", + "\n", + "# Multi bar Chart1\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,3.5])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + " plt.bar(i*3+1, gap_22_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", + "\n", + "offset = i*3+2\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_C_cas[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*3+2, npb_C_ram[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"BW Bloat (due to acc amp)\")\n", + "plt.legend(fontsize=8, ncol=2, loc='upper left')\n", + "plt.tight_layout()\n", + "\n", + "# Multi bar Chart2\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,3.5])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + " plt.bar(i*3+1, gap_25_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", + "\n", + "offset = i*3+2\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_D_cas[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*3+2, npb_D_ram[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"BW Bloat (due to acc amp)\")\n", + "plt.legend(fontsize=8, ncol=2, loc='upper left')\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Anything above is old results.\n", + "Tag probing results starts here:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_308484/3690351968.py:27: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " app_gap[len(app_gap)] = \"gmean\"\n", + "/tmp/ipykernel_308484/3690351968.py:30: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " app_npb[len(app_npb)] = \"gmean\"\n", + "/tmp/ipykernel_308484/3690351968.py:64: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " app_gap[len(app_gap)] = \"gmean\"\n", + "/tmp/ipykernel_308484/3690351968.py:67: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " app_npb[len(app_npb)] = \"gmean\"\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAlVElEQVR4nO3debxVZb3H8c83RI8DggN6TUSQtKtIoWLqRfMgdp3CoRuo5UBOOeaQOaRpdi3pdk1JuxqaF80JLU0UJbvGEdBUIAcQxExRMRSwBMkUgd/9Y6192BzPsM7ee51h832/Xue193r22uv5rT2s89vPetbzKCIwMzMzqyafau8AzMzMzCrNCY6ZmZlVHSc4ZmZmVnWc4JiZmVnVcYJjZmZmVWed9g6gHJtvvnn06dOnvcMwW+vNnTsXgM9+9rPtHImZrW1mzJixOCJ6Nizv1AlOnz59mD59enuHYbbWq62tBaCurq5d4zCztY+k1xsr9ykqMzMzqzpOcMzMzKzqOMExMzOzqtOp++A05uOPP2b+/Pl8+OGH7R2KWdWqqamhV69edO3atb1DMTNrVNUlOPPnz6dbt2706dMHSe0djlnViQjeffdd5s+fT9++fds7HDOzRlXdKaoPP/yQzTbbzMmNWU4ksdlmm7mV1Mw6tKpLcAAnN2Y583fMzDq6qjtFVWzPy39Xke08dcUBTT62ZMkSDjvsMACee+45dtxxR9Zbbz0WL15Mt27d6NKlCxHBySefzMiRIwHo27cv2267LStXrqRPnz6MHTuWLl26APCjH/2Im266iVdffbX+n0jfvn0ZOnQoN998MwC/+tWvOO6443jttddoONBhc9suuPLKK+nVq1d9PAUjR47k+eefZ+ONN2ajjTbijjvuoEePHi2+PmPHjmX+/PlceumlLa5bikN/e0hFtjP+8AlNPtbR3sfPfOYzvPLKKxXZ74Li9+mcc87hkksuoWfPT4yNZWZWFaqyBactde/enbq6Ourq6hg4cCD33nsvdXV1bL755tx7771MnTqVCRMmMHbsWCZNmgRAly5dqKurY8qUKXTt2pVHH320fnsPPfQQ++23H0888UR9WZcuXXjjjTf46KOPAPj1r3/Nbrvt1mg8zW07i+uuu47HH3+cwYMHc+ONN67x2MqVK1u1rc6ko72Pebv22mud3JhZVXOC0wZ69OjBJZdcwp133rlG+apVq3jvvfeICACeffZZ+vfvz2mnncbtt9++xroHHXQQEyZMYOHChXTt2rXFlpWG2548eTK77LILw4YN4+mnn24x5l133ZXXX3+dsWPHMnz4cA4//HBGjx7NTTfdxB577MEee+zBLbfcUr/+008/zbBhw9hll12YMmVKlpel02nr9/Hcc89l33335ZhjjmHVqlUsXryYoUOHUltby+DBg3n55ZcBOP/889lrr70YMmQI48aNA5JEdZ999mGvvfaqbzEqVltby/z585k3bx677bYbxxxzDLvuuivXXnstkLRojRgxgqFDh7LffvtVvDXJzCxvTnDayDbbbMNbb70FJC0htbW19OnTh5UrV3LAAckpsDvuuIPjjz+eQYMGMXv2bD7++OP65x911FGMGzeOcePGMWLEiCbraWrb5513Hg888ADjx4+vb0FozqOPPkr//v0BWLZsGffffz/HHnss119/PVOmTGHKlCmMHj2aRYsWAcnl+Q8++CD3338/5557bmkvUifQVu/jihUrGDFiBI8//jjrr78+48ePp3v37jzyyCPU1dVx6aWXMmrUKAAeeeQRpkyZwqRJkxg+fDhz5sxh4sSJTJ48malTp3LLLbfw7rvvNlnXggULGDNmDE8++SSjR48G4KqrruIrX/kKjz32GNdccw0XXXRR2a+dmVlbyi3BkbSNpEmSZkt6UdLZafmmkn4v6c/p7SZpuST9TNIrkl6QtGtesbWHN998k6233hpYfWpj5syZLFq0iPfee49Vq1bxwAMPcOWVV3LggQeycOFCHn744frnb7XVVixbtoy7776bYcOG1Zdff/311NbWctJJJzW5bYClS5fSu3dvJPGFL3wBgKlTp1JbW0ttbS3Lli0D4KyzzmLffffln//8Z/0299xzTyTx6quvMmDAANZdd13WXXddBgwYwGuvvQbA7rvvDiTzgy1ZsiTHV7J9tdX7WPw+7bHHHsydO5f33nuPY445hi9+8YtcccUVvPnmmwCMGjWKE044gZEjRzJnzhxmzZrF7NmzGTJkCEOHDmXp0qX16zZmxx13ZIMNNqCmpqa+D9HMmTMZPXo0tbW1nH322fWfIzOzziLPFpwVwLcjYidgT+AMSTsBFwGPRcT2wGPpMsBBwPbp3ynADTnG1qaWLFnCVVddxdFHH71Geffu3Tn11FP58Y9/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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "gap_22_prob = df_gap22_ram_prob['avgTimeTagCheckResRd'].astype(float)\n", + "gap_22_ram = df_gap22_ram['avgTimeTagCheckResRd'].astype(float)\n", + "gap_22_prob[len(gap_22_prob)] = statistics.geometric_mean(df_gap22_ram_prob['avgTimeTagCheckResRd'].astype(float))\n", + "gap_22_ram[len(gap_22_ram)] = statistics.geometric_mean(df_gap22_ram['avgTimeTagCheckResRd'].astype(float))\n", + "\n", + "\n", + "gap_25_prob = df_gap25_ram_prob['avgTimeTagCheckResRd'].astype(float)\n", + "gap_25_ram = df_gap25_ram['avgTimeTagCheckResRd'].astype(float)\n", + "gap_25_prob[len(gap_25_prob)] = statistics.geometric_mean(df_gap25_ram_prob['avgTimeTagCheckResRd'].astype(float))\n", + "gap_25_ram[len(gap_25_ram)] = statistics.geometric_mean(df_gap25_ram['avgTimeTagCheckResRd'].astype(float))\n", + "\n", + "npb_C_prob = df_npbC_ram_prob['avgTimeTagCheckResRd'].astype(float)\n", + "npb_C_ram = df_npbC_ram['avgTimeTagCheckResRd'].astype(float)\n", + "npb_C_prob[len(npb_C_prob)] = statistics.geometric_mean(df_npbC_ram_prob['avgTimeTagCheckResRd'].astype(float))\n", + "npb_C_ram[len(npb_C_ram)] = statistics.geometric_mean(df_npbC_ram['avgTimeTagCheckResRd'].astype(float))\n", + "\n", + "\n", + "\n", + "npb_D_prob = df_npbD_ram_prob['avgTimeTagCheckResRd'].astype(float)\n", + "npb_D_ram = df_npbD_ram['avgTimeTagCheckResRd'].astype(float)\n", + "npb_D_prob[len(npb_D_prob)] = statistics.geometric_mean(df_npbD_ram_prob['avgTimeTagCheckResRd'].astype(float))\n", + "npb_D_ram[len(npb_D_ram)] = statistics.geometric_mean(df_npbD_ram['avgTimeTagCheckResRd'].astype(float))\n", + "\n", + "################################## \n", + "# Multi bar Chart1\n", + "app_gap = df_gap22_ram_prob['app']\n", + "app_gap[len(app_gap)] = \"gmean\"\n", + "\n", + "app_npb = df_npbC_ram_prob['app']\n", + "app_npb[len(app_npb)] = \"gmean\"\n", + "\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,3)\n", + "plt.ylim([0,220])\n", + "barWidth = 1\n", + "tickSize = 3\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*tickSize-barWidth/2, gap_22_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", + " plt.bar(i*tickSize+barWidth/2, gap_22_ram[i], width=barWidth, color=cmap(2), label='TDRAM-baseline' if i==0 else None)\n", + "\n", + "offset = i+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar((offset+i)*tickSize-barWidth/2, npb_C_prob[i], width=1, color=cmap(1))\n", + " plt.bar((offset+i)*tickSize+barWidth/2, npb_C_ram[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.25, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.7, -0.01, \"NPB-C\")\n", + "\n", + "brLab = np.arange(len(app_gap)+len(app_npb))\n", + "plt.xticks(brLab*tickSize, list(app_gap)+list(app_npb))\n", + "\n", + "plt.axvline(x=(offset-0.5)*tickSize, color='black')\n", + "# plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Tag Comparison Latency (ns)\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()\n", + "\n", + "###############################################################################\n", + "# Multi bar Chart2\n", + "app_gap = df_gap25_ram_prob['app']\n", + "app_gap[len(app_gap)] = \"gmean\"\n", + "\n", + "app_npb = df_npbD_ram_prob['app']\n", + "app_npb[len(app_npb)] = \"gmean\"\n", + "\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,3)\n", + "plt.ylim([0,220])\n", + "barWidth = 1\n", + "tickSize = 3\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*tickSize-barWidth/2, gap_25_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Probe' if i==0 else None)\n", + " plt.bar(i*tickSize+barWidth/2, gap_25_ram[i], width=barWidth, color=cmap(2), label='TDRAM-baseline' if i==0 else None)\n", + "\n", + "offset = i+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar((offset+i)*tickSize-barWidth/2, npb_D_prob[i], width=1, color=cmap(1))\n", + " plt.bar((offset+i)*tickSize+barWidth/2, npb_D_ram[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.25, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.70, -0.01, \"NPB-D\")\n", + "\n", + "brLab = np.arange(len(app_gap)+len(app_npb))\n", + "plt.xticks(brLab*tickSize, list(app_gap)+list(app_npb))\n", + "\n", + "plt.axvline(x=(offset-0.5)*tickSize, color='black')\n", + "# plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Tag Comparison Latency (ns)\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_308484/1065878878.py:27: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " app_gap[len(app_gap)] = \"gmean\"\n", + "/tmp/ipykernel_308484/1065878878.py:30: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " app_npb[len(app_npb)] = \"gmean\"\n", + "/tmp/ipykernel_308484/1065878878.py:64: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " app_gap[len(app_gap)] = \"gmean\"\n", + "/tmp/ipykernel_308484/1065878878.py:67: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " app_npb[len(app_npb)] = \"gmean\"\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAnRklEQVR4nO3de5xVdb3/8dc7REeRS14Pgjh4KRVRUBQ9oI5geQtRCwLzwskkCyotT2n60+xY2kXRtOyAcjAviZcQVEzLQEBTAUOuYigoQyRgCmJeuHx+f6w142ac2bNnz+y57Hk/H4/9mL2+e+31/ax9WfPZ3/Vd368iAjMzM7Ni8qmmDsDMzMysoTnBMTMzs6LjBMfMzMyKjhMcMzMzKzpOcMzMzKzoOMExMzOzolOwBEdSiaQXJL0kaZGka9Ly7pKel7RM0kRJ26flO6TLy9LHSwsVm5mZmRW3QrbgfAgMiIjDgF7AyZKOBn4GjImI/YG3gQvS9S8A3k7Lx6TrmZmZmdVZwRKcSGxMF9umtwAGAA+m5XcCZ6T3B6fLpI8PlKRCxWdmZmbFa7tCblxSG2AusD/wa+BV4J2I2JyuUg50Se93AVYCRMRmSeuBXYF1VbY5EhgJ0K5duyMOPPDAQu6CmeVg6dKlAHz2s59t4kjMrLWZO3fuuojYvWp5QROciNgC9JLUCZgE1DsbiYixwFiAPn36xJw5c+q7STOrp7KyMgCmT5/epHGYWesj6fXqyhvlKqqIeAeYBhwDdJJUkVh1BVal91cBewOkj3cE3mqM+MzMzKy4FPIqqt3Tlhsk7Qh8DlhCkuh8KV3tfGByen9Kukz6+F/CM4GamZlZHgp5iqozcGfaD+dTwP0R8aikxcB9kq4F/gbcka5/B3CXpGXAv4BhBYzNzMzMiljBEpyImA/0rqb8NeCoaso/AIbUt95NmzZRXl7OBx98UN9NmVkNSkpK6Nq1K23btm3qUMzMqlXQTsZNoby8nPbt21NaWoqvMjdreBHBW2+9RXl5Od27d2/qcMzMqlV0UzV88MEH7Lrrrk5uzApEErvuuqtbSc2sWSu6BAdwcmNWYP6OmVlzV3SnqDIdffUTDbKd5645qcbH1q9fz+DBgwGYN28eBx10EDvssAPr1q2jffv2tGnThojgwgsvZMSIEQB0796dffbZhy1btlBaWsqECRNo06YNAD/96U8ZN24cr732WuU/ke7duzNw4EBuv/12AO666y7OO+88li9fTmlp6TbxZNt2hWuvvZauXbtWxlNhxIgRvPTSS3To0IGdd96Ze+65h06dOtX6+kyYMIHy8nKuvPLKWtfNx+kPn9Yg25lyxmM1Ptbc3sf999+fZcuWNch+V8h8ny6++GKuuOIKdt/9E2NjmZkVhaJswWlMHTt2ZPr06UyfPp1evXrxwAMPMH36dHbbbTceeOABZs2axWOPPcaECROYNm0aAG3atGH69OnMnDmTtm3b8uSTT1Zu79FHH2XAgAE888wzlWVt2rThjTfe4MMPPwTgwQcf5Igjjqg2nmzbzsUtt9zC008/Tb9+/fjtb3+7zWNbtmyp07Zakub2PhbaTTfd5OTGzIqaE5xG0KlTJ6644gruvffebcq3bt3KO++8Q8VwP3/729/o0aMH3/jGN7j77ru3WfeUU07hscceY82aNbRt27bWlpWq254xYwa9e/dm0KBBPP/887XGfPjhh/P6668zYcIEhgwZwhlnnMHNN9/MuHHj6Nu3L3379mX8+PGV6z///PMMGjSI3r17M3PmzFxelhansd/HSy65hOOPP55zzjmHrVu3sm7dOgYOHEhZWRn9+vXjlVdeAeDSSy/lmGOO4YQTTmDixIlAkqgee+yxHHPMMZUtRpnKysooLy9nxYoVHHHEEZxzzjkcfvjh3HTTTUDSojV06FAGDhzIgAEDGrw1ycys0JzgNJK9996bVauSQZu3bNlCWVkZpaWlbNmyhZNOSk6B3XPPPZx//vn06dOHxYsXs2nTpsrnDxs2jIkTJzJx4kSGDh1aYz01bfu73/0ukydPZsqUKZUtCNk8+eST9OjRA4CNGzcyadIkzj33XG699VZmzpzJzJkzufnmm1m7di2QXJ7/yCOPMGnSJC655JL8XqQWoLHex82bNzN06FCefvppdtxxR6ZMmULHjh15/PHHmT59OldeeSXXX389AI8//jgzZ85k2rRpDBkyhCVLlvDHP/6RGTNmMGvWLMaPH89bb9U8KPjq1asZO3Yszz77LDfffDMA1113HWeddRZPPfUUY8aM4bLLLqv3a2dm1pic4DSSlStX0qVLMq9oxamNBQsWsHbtWt555x22bt3K5MmTufbaazn55JNZs2YNU6dOrXx+586d2bhxI/fddx+DBg2qLL/11lspKyvja1/7Wo3bBtiwYQPdunVDEkcdlQxDNGvWLMrKyigrK2PjxmTi929961scf/zxvP/++5XbPProo5HEa6+9Rs+ePdl+++3Zfvvt6dmzJ8uXLwfgyCOPBKC0tJT169cX8JVsWo31Pma+T3379mXp0qW88847nHPOORx33HFcc801rFy5EoDrr7+er371q4wYMYIlS5awcOFCFi9ezAknnMDAgQPZsGFD5brVOeigg9hpp50oKSmp7EO0YMECbr75ZsrKyvjOd75T+TkyM2spirqTcXOxfv16rrvuuk90wu3YsSMXXXQRP/vZzzjppJMYPHgwv/zlLwF49dVXufzyyys7vgKMGjWKxYsXs+OOO1aWjR49mtGjR3+izsxt//znP6d9+/aUl5fTtWtXZs+ezf7770///v0/MTniLbfcQv/+/bcpq/in1717d+bPn89HH30EJP8Eu3fvzuLFi5k7dy4Ab7zxBh06dMjzlWreGvN9jAjmzJlD3759mT17NieffDJ33303vXv35vLLL2fq1KnceOONRAQnnngigwYNYtasWVx11VVcc8019O7dm4ceeghJbNq0ibZt2zJv3rxq96u6K6J69OjBMcccw5lnnglQ+Z6bmbUUTnAKaMiQIbRp04atW7fy1a9+lQEDBnxinWHDhtGzZ0/WrVvH2WefXVm+3377sWTJEjZs2FBZduqpp3LqqafmXH/Ftn/4wx9yww03MGjQIPbaay/at2+f1/7ssccefPOb36xMgEaPHl3ZUXWnnXbitNNO4x//+AdjxozJa/vNVVO8j9tttx0PPfQQ3//+9+nSpQunn346L7/8MmeffTYzZsyoPH24efNmTjnlFCAZA+qqq67ikEMO4cQTT+T444+nTZs2lae46uKKK67goosu4pZbbiEiOO2007j00kvrtA0zs6akljyfZZ8+fWLOnDnblC1ZsoSDDjqoiSIyaz0yv2tlZWUAn2gRNDMrNElzI6JP1XL3wTEzM7Oi4wTHzMzMik5RJjgt+bSbWUvg75iZNXdFl+CUlJTw1ltv+QBsViAVs4mXlJQ0dShmZjUququounbtSnl5eeUAdGbW8EpKSujatWtTh2FmVqOsCY6kEuALwLHAXsD7wELgsYhYVPjw6q5t27Z07969qcMwMzOzJlRjgiPpGpLkZjrwPLAGKAE+A1yfJj/fi4j5jRCn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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAmRklEQVR4nO3de7yVc97/8ddbotCBxJ1COYxDGkXEr4xUxmkSbqUcux0apmbGaebW8GPcY4aZQYxMfkV3xjGnFGLQlMoMKqKTSEWlEKOcO31+f1zX3pZtH9bee619WL2fj8d+rHV9r8P3c63DtT/r+72u66uIwMzMzKyQbFHbAZiZmZnlmhMcMzMzKzhOcMzMzKzgOMExMzOzguMEx8zMzAqOExwzMzMrOHlLcCQ1kvSKpNclzZN0bVreTtLLkhZJGitpq7R863R6UTq/bb5iMzMzs8KWzxacb4AeEXEg0BE4VtJhwB+BYRGxF/Bv4Lx0+fOAf6flw9LlzMzMzCotbwlOJD5PJxumfwH0AB5Jy+8GTkqf90mnSef3lKR8xWdmZmaFa8t8blxSA2AWsBdwO/AO8GlEbEgXWQ60Tp+3BpYBRMQGSWuAFsDqEtscBAwC2HbbbQ/ed99987kLZpaFhQsXArDPPvvUciRmtrmZNWvW6ohoWbI8rwlORGwEOkpqDowDqp2NRMRIYCRA586dY+bMmdXdpJlVU/fu3QGYMmVKrcZhZpsfSe+WVl4jV1FFxKfAZOBwoLmkosSqDbAifb4C2BUgnd8M+Lgm4jMzM7PCks+rqFqmLTdIagwcDSwgSXROTRc7BxifPp+QTpPO/0d4JFAzMzOrgnx2UbUC7k7Pw9kCeCginpQ0H3hQ0nXAa8Bd6fJ3AfdIWgR8AvTPY2xmZmZWwFSfG0lKOwdn/fr1LF++nK+//rqWojLb/KxatYqIoF27drRp04aGDRvWdkhmtpmQNCsiOpcsz+tJxrVh+fLlNGnShLZt2+KrzM1qxhZbbEFE0KRJE5YvX067du1qOyQz28wV3FANX3/9NS1atHByY1bDJNGiRQu3nppZnVBwCQ7g5Maslvi7Z2Z1RcF1UWU67Jq/52Q7L117TJnz1qxZQ58+fQCYPXs2++23H1tvvTWrV6+mSZMmNGjQgIjgggsuYODAgQC0a9eO3XffnY0bN9K2bVvGjBlDgwYNAPjDH/7AqFGjWLx4cfE/i3bt2tGzZ0/uvPNOAO655x7OPvtslixZQtu2bb8TT3nbLnLdddfRpk2b4niKDBw4kNdff52mTZuy3Xbbcd9999G8efMKX58xY8awfPlyrrrqqgqXzaUTHz8hJ9uZcNJTZc6ra+/vXnvtxaJFi3Ky30Uy37+LL76YK6+8kpYtv3fPLDOzeqUgW3BqUrNmzZgyZQpTpkyhY8eOPPzww0yZMoUdd9yRhx9+mOnTp/PUU08xZswYJk+eDECDBg2YMmUK06ZNo2HDhjz77LPF23vyySfp0aMHL774YnFZgwYNeO+99/jmm28AeOSRRzj44INLjae8bWfjtttu44UXXqBr167ccccd35m3cePGSm2rENS19zffbrnlFic3ZlYQnODUgObNm3PllVdy//33f6d806ZNfPrppxRdyfbaa6/Rvn17LrroIu69997vLHvcccfx1FNP8eGHH9KwYcMKW1ZKbnvq1Kl06tSJ3r178/LLL1cY80EHHcS7777LmDFj6Nu3LyeddBK33noro0aNokuXLnTp0oXRo0cXL//yyy/Tu3dvOnXqxLRp0wCYM2cOvXr1okePHvTr14+vvvqqwnrro5p+fy+55BKOPPJIzjzzTDZt2sTq1avp2bMn3bt3p2vXrrz11lsAXH755Rx++OEcddRRjB07FkgS2COOOILDDz+8uMUoU/fu3Vm+fDlLly7l4IMP5swzz+Sggw7illtuAZIWrX79+tGzZ0969OiR89YkM7NccYJTQ3bddVdWrEhu2rxx40a6d+9O27Zt2bhxI8cck3SB3XfffZxzzjl07tyZ+fPns379+uL1+/fvz9ixYxk7diz9+vUrs56ytn3ppZcyfvx4JkyYUNxSUJ5nn32W9u3bA/D5558zbtw4zjrrLIYPH860adOYNm0at956Kx999BGQXJ7/xBNPMG7cOC655BIABg8ezOjRo/nHP/5B165dueuuu8qsr76rqfd3w4YN9OvXjxdeeIHGjRszYcIEmjVrxtNPP82UKVO46qqruOGGGwB4+umnmTZtGpMnT6Zv374sWLCAZ555hqlTpzJ9+nRGjx7Nxx+XfbPwlStXMnLkSP75z39y6623AnD99ddzyimnMGnSJIYNG8YVV1xR7dfOzCwfCvocnLpk2bJltG6djCta1IWxZs0ajjvuOD799FO23357xo8fz9y5cwH48MMPmThxYvH5H61ateLzzz/nwQcf5Pnnn2fkyJEADB8+nEceeYS99tqLO++8s9Rtt2jRgrVr17LbbrsBcOihhwIwffr04vNmnnzySQB+/vOf07RpU/bff3/OP/98HnzwQQ477DAksXjxYjp06MBWW20FQIcOHViyZAkAhxxyCABt27ZlzZo1AMybN4+zzz4bSK5u69WrVx5f4dpVU++vpOL3r0uXLixcuJCuXbsyePBgVq1axbp162jSpAkAN9xwA+eeey5bbLEFv/rVr5g/fz7z58/nqKOOAmDt2rUsW7aszH3ab7/92GabbYr3CZJWuRdeeKG4+3LLLX0IMbO6yUenGrBmzRquv/76752E26xZMy688EL++Mc/cswxx9CnTx9uvPFGAN555x2GDh1a/A8QkhaR+fPn07hx4+KyIUOGMGTIkO/VmbntP/3pT8X3J2nTpg0zZsxgr732olu3bt8bHPG2226jW7du3ykr+ufWrl073njjDdatWwck/+zatWvH/PnzmTVrFgDvvfceTZs2BeCAAw7ggQceoFWrVgDF6xWamnx/I4KZM2fSpUsXZsyYwbHHHsu9995Lp06dGDp0KBMnTuTmm28mIujVqxe9e/dm+vTpXH311Vx77bV06tSJRx99FEmsX7+ehg0bMnv27FL3q7Qrotq3b8/hhx/OySefDBTue2pm9Z8TnDzq27cvDRo0YNOmTZx77rn06NHje8v079+fDh06sHr1ak4//fTi8j333JMFCxawdu3a4rLjjz+e448/Puv6i7b9m9/8hptuuonevXuzyy67FP/Cr6yddtqJn/3sZ8UJ0JAhQ4pPSN1mm2044YQTeP/99xk2bBgAt99+OwMHDizuihk6dChHH310lequi2rj/d1yyy159NFH+fWvf03r1q058cQTefPNNzn99NOZOnVqcbfihg0bOO6444Ck9ezqq6/mgAMOoFevXhx55JE0aNCguIurMq688kouvPBCbrvtNiKCE044gcsvv7xS2zAzqwkFN1TDggUL2G+//WopIrPN08KFCwHYZ599/B00sxpV1lANPsnYzMzMCo67qMzMrOBkeyPQ8m70afVbQbbg1OduN7P6zN89M6srCi7BadSoER9//LEPtGY1LCL4+OOPadSoUW2HYmZWeF1Ubdq0Yfny5cU3oDOz/Fu1ahURwdZb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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "gap_22_prob = df_gap22_ram_prob['avgPktRespTimeRd'].astype(float)\n", + "gap_22_ram = df_gap22_ram['avgPktRespTimeRd'].astype(float)\n", + "gap_22_prob[len(gap_22_prob)] = statistics.geometric_mean(df_gap22_ram_prob['avgPktRespTimeRd'].astype(float))\n", + "gap_22_ram[len(gap_22_ram)] = statistics.geometric_mean(df_gap22_ram['avgPktRespTimeRd'].astype(float))\n", + "\n", + "\n", + "gap_25_prob = df_gap25_ram_prob['avgPktRespTimeRd'].astype(float)\n", + "gap_25_ram = df_gap25_ram['avgPktRespTimeRd'].astype(float)\n", + "gap_25_prob[len(gap_25_prob)] = statistics.geometric_mean(df_gap25_ram_prob['avgPktRespTimeRd'].astype(float))\n", + "gap_25_ram[len(gap_25_ram)] = statistics.geometric_mean(df_gap25_ram['avgPktRespTimeRd'].astype(float))\n", + "\n", + "npb_C_prob = df_npbC_ram_prob['avgPktRespTimeRd'].astype(float)\n", + "npb_C_ram = df_npbC_ram['avgPktRespTimeRd'].astype(float)\n", + "npb_C_prob[len(npb_C_prob)] = statistics.geometric_mean(df_npbC_ram_prob['avgPktRespTimeRd'].astype(float))\n", + "npb_C_ram[len(npb_C_ram)] = statistics.geometric_mean(df_npbC_ram['avgPktRespTimeRd'].astype(float))\n", + "\n", + "\n", + "\n", + "npb_D_prob = df_npbD_ram_prob['avgPktRespTimeRd'].astype(float)\n", + "npb_D_ram = df_npbD_ram['avgPktRespTimeRd'].astype(float)\n", + "npb_D_prob[len(npb_D_prob)] = statistics.geometric_mean(df_npbD_ram_prob['avgPktRespTimeRd'].astype(float))\n", + "npb_D_ram[len(npb_D_ram)] = statistics.geometric_mean(df_npbD_ram['avgPktRespTimeRd'].astype(float))\n", + "\n", + "################################## \n", + "# Multi bar Chart1\n", + "app_gap = df_gap22_ram_prob['app']\n", + "app_gap[len(app_gap)] = \"gmean\"\n", + "\n", + "app_npb = df_npbC_ram_prob['app']\n", + "app_npb[len(app_npb)] = \"gmean\"\n", + "\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,3)\n", + "plt.ylim([0,300])\n", + "barWidth = 1\n", + "tickSize = 3\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*tickSize-barWidth/2, gap_22_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", + " plt.bar(i*tickSize+barWidth/2, gap_22_ram[i], width=barWidth, color=cmap(2), label='TDRAM-baseline' if i==0 else None)\n", + "\n", + "offset = i+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar((offset+i)*tickSize-barWidth/2, npb_C_prob[i], width=1, color=cmap(1))\n", + " plt.bar((offset+i)*tickSize+barWidth/2, npb_C_ram[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.25, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.7, -0.01, \"NPB-C\")\n", + "\n", + "brLab = np.arange(len(app_gap)+len(app_npb))\n", + "plt.xticks(brLab*tickSize, list(app_gap)+list(app_npb))\n", + "\n", + "plt.axvline(x=(offset-0.5)*tickSize, color='black')\n", + "# plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Avg Rd Resp Time (ns) (ns)\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()\n", + "\n", + "###############################################################################\n", + "# Multi bar Chart2\n", + "app_gap = df_gap25_ram_prob['app']\n", + "app_gap[len(app_gap)] = \"gmean\"\n", + "\n", + "app_npb = df_npbD_ram_prob['app']\n", + "app_npb[len(app_npb)] = \"gmean\"\n", + "\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,3)\n", + "plt.ylim([0,300])\n", + "barWidth = 1\n", + "tickSize = 3\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*tickSize-barWidth/2, gap_25_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Probe' if i==0 else None)\n", + " plt.bar(i*tickSize+barWidth/2, gap_25_ram[i], width=barWidth, color=cmap(2), label='TDRAM-baseline' if i==0 else None)\n", + "\n", + "offset = i+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar((offset+i)*tickSize-barWidth/2, npb_D_prob[i], width=1, color=cmap(1))\n", + " plt.bar((offset+i)*tickSize+barWidth/2, npb_D_ram[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.25, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.70, -0.01, \"NPB-D\")\n", + "\n", + "brLab = np.arange(len(app_gap)+len(app_npb))\n", + "plt.xticks(brLab*tickSize, list(app_gap)+list(app_npb))\n", + "\n", + "plt.axvline(x=(offset-0.5)*tickSize, color='black')\n", + "# plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Avg Rd Resp Time (ns)\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_308484/3412151829.py:27: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " app_gap[len(app_gap)] = \"gmean\"\n", + "/tmp/ipykernel_308484/3412151829.py:30: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " app_npb[len(app_npb)] = \"gmean\"\n", + "/tmp/ipykernel_308484/3412151829.py:64: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " app_gap[len(app_gap)] = \"gmean\"\n", + "/tmp/ipykernel_308484/3412151829.py:67: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " app_npb[len(app_npb)] = \"gmean\"\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAnRElEQVR4nO3de5xd0/3/8ddbgriEoPhqEhKXFkGFEH6CSaJuaSR8iVCXNC5fLSVUlWqpfv1Q1aJ8yzcujboUdUsQt5/SoKRJCImkNCIkaVSCJEKCJJ/fH3tNHJOZM2dmzjkzc+b9fDzOY85eZ5+9Pvtc9nzO2muvpYjAzMzMrJKs0dwBmJmZmRWbExwzMzOrOE5wzMzMrOI4wTEzM7OK4wTHzMzMKo4THDMzM6s4JUtwJN0q6X1JU3PKNpb0lKR/pr8bpXJJ+p2kGZJek7RbznNOTOv/U9KJpYrXzMzMKkcpW3BGAQfXKDsfeDoitgOeTssAhwDbpdupwA2QJUTAxUBvYE/g4uqkyMzMzKwuJUtwImIc8GGN4kHAben+bcDgnPI/RuYloJOkLYCDgKci4sOI+Ah4itWTJjMzM7OvaF/m+jaPiHnp/nvA5ul+Z2B2znpzUlld5auRdCpZ6w/rrbfe7ttvv30RwzazQr3xxhsAfPOb32zmSMysLZg0adKCiNi0Znm5E5xVIiIkFW2eiIgYCYwE6NWrV0ycOLFYmzazBqiqqgLg2WefbdY4zKxtkPRObeXlvorq3+nUE+nv+6l8LtA1Z70uqayucjMzM7M6lTvBGQNUXwl1IjA6p/yEdDXVXsCidCrrCeBASRulzsUHpjIzMzOzOpXsFJWkPwFVwNckzSG7GuoK4F5JJwHvAEPS6mOBQ4EZwKfA9wAi4kNJ/w1MSOv9MiJqdlw2MzMz+4qSJTgRcUwdD/WvZd0ATq9jO7cCtzY1ni+++II5c+awbNmypm7KzPLYaaedmDp1av0rmpmVULN1Mi63OXPm0LFjR7p164ak5g7HrCItXbqUAw880AmOmTW7NjNVw7Jly9hkk02c3JiVUIcOHejYsWNzh2Fm1nYSHMDJjVmJ+TtmZi1FmzlFlWuvi4tzIdZLlxyU9/FFixYxaNAgACZPnswOO+zA2muvzYIFC+jYsSPt2rUjIjjllFMYNmwYAN27d2errbZixYoVdOvWjVGjRtGuXTsALrvsMm666SZmzpy56h9J9+7d6d+/PzfffDMAt99+OyeccAJvv/023bp1+0o8+bZd7dJLL6VLly6r4qk2bNgwXn31VTbYYAPWX3997rzzTjp16lTvazRq1CjmzJnDz372s3rXbajDHhpQlO2MGfxonY+1tPdw2223ZcaMGUXZ72q579GIESO48MIL2XTT1cbMMjNrVdpkglMuG2644arBzqqqqrjjjjvo0qXLV+4vXLiQwYMHs9VWW9G3b1/atWu36jnDhw/nySef5JBDDgHgkUceoV+/frzwwgv06dMHgHbt2vHuu+/y2Wefsfbaa3Pfffex++671xpPvm0X4rrrrqNPnz5cdtll3HjjjZx//vmrHluxYsVqyVIlaGnvYaldc801zVKvVb5Cf5Dk+8Fh1hBt6hRVS9SpUycuvPBC7rrrrq+Ur1y5koULF5JdYAavvPIKPXr04Pvf/z533HHHV9Y95JBDePTRR3n//fdZc801621ZqbntcePG0bNnTwYOHMj48ePrjXm33XbjnXfeYdSoURx11FEMHjyYa6+9lptuuonevXvTu3dvbr31ywvfxo8fz8CBA+nZsyfPPfdcIS9Lq1Lu9/Dss89m//3357jjjmPlypUsWLCA/v37U1VVxT777MObb74JwLnnnsvee+9N3759ueeee4AsSd13333Ze++9V7UY5aqqqmLOnDnMmjWL3XffneOOO47ddtttVeKzaNEihgwZQv/+/enXr1/RW5PMzIrFLTgtQNeuXZk7NxugecWKFVRVVTFz5kx69uzJQQdlp8HuvPNOTjzxRHr16sU555zDF198wZprrgnA0KFDGTFiBHPnzmXIkCGMHDmy1nrq2vY555zD6NGj6dq166qyfJ588kl69OgBwJIlSxg7diwLFizggAMOYMKEbMiiPfbYg4EDBwLZJfqPP/44s2bN4sgjj6QSp9Eo13u4fPlyhgwZwtVXX80pp5zCmDFjGDBgAI899hhrrbUWjz32GFdccQW33norjz32GK+++irt27dn5cqVTJ8+nccff5xx48axcuVK9t13Xw4//PA692nevHk899xzrLHGGuywww6MGDGCyy+/nCOOOIKhQ4fy6quvcv7553PfffcV+dW01qTQU/6b9SxxIGY1uAWnBZg9ezadO2dziFaf3pgyZQrz589n4cKFrFy5ktGjR3PppZdy8MEH8/777zN27NhVz99iiy1YsmQJd99996qkAuD666+nqqqKk08+uc5tAyxevJgtt9wSSey5554APP/881RVVVFVVcWSJUsA+OEPf8j+++/P0qVLV21zr732QhIzZ85k5513Zq211mKttdZi55135u233wayZAegW7duLFq0qISvZPMp13uY+x717t2bN954g4ULF3Lcccex3377cckllzB7djY/7RVXXMHw4cMZNmwY06dPZ+rUqUybNo2+ffvSv39/Fi9evGrd2uywww6su+66dOjQYdXpxylTpnDttddSVVXFWWedteozZGbW0rgFp5ktWrSIyy+/fLVOuBtuuCGnnXYav/rVrzjooIMYNGgQV111FQBvvfUWF1xwwarOrwCnn34606ZNY5111llVdsYZZ3DGGWesVmfutq+88ko6duzInDlz6NKlCxMmTGDbbbelT58+q02WWN0HJ1f1P77u3bvz2muv8fnnnwPZP8Lu3bszbdo0Jk2aBMC7777LBhts0MhXquUq53sYEUycOJHevXszYcIEDj74YO644w569uzJBRdcwNixY/ntb39LRHDAAQcwcOBAnn/+eS666CIuueQSevbsyf3334+kVS1IkydPrnW/arsiqkePHuy9996rWn6q328zs5bGCU4zOeqoo2jXrh0rV65k+PDh9OvXb7V1hg4dys4778yCBQs49thjV5Vvs802TJ8+ncWLF68qO/TQQzn00EMLrr962z/96U/5zW9+w8CBA/n617/e6DFMNttsM37wgx+sSoDOOOOMVVfirLvuugwYMIB//etfXH311Y3afkvUHO9h+/btuf/++znvvPPo3Lkzhx12GP/4xz849thjGTdu3KpTh8uXL1/VsXnZsmVcdNFF7LTTThxwwAHsv//+tGvXjnXWWYcxY8Y0aJ8vvPBCTjvtNK677joiggEDBnDuuec2aBtmZuWg6g6QlaRXr15Rs5/H9OnT2WGHHZopIrO245lnnuGSSy5ZrQXQKlPhfXB+V9B6vorKGkrSpIjoVbPcfXDMzMys4jjBMTMzs4rTphKcSjwdZ9aS+DtmZi1Fm0lwOnTowAcffOADsFkJLVu2jI8//ri5wzAzaztXUXXp0oU5c+Ywf/785g7FrKI9+eSTzR2CmVnbSXDWXHNNunfv3txhmFW8qVOnNncIZmb1JziSNgP2Ab4O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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAmdklEQVR4nO3deZhU1bnv8e9PQBFlUESDoELEG+eIokjAiIAxahDNFRyiQtR4NJJEjTEhejQmOYkax2iOXlQOxnkWVDQaIwIaOYCiKIjiSBOIYBTizPDeP/bqtoTuorq7qofq3+d5+qnaq3bt9e4adr+11tp7KSIwMzMzKycbNHYAZmZmZsXmBMfMzMzKjhMcMzMzKztOcMzMzKzsOMExMzOzsuMEx8zMzMpOyRIcSeMkvSvppZyyzSU9Lum1dLtZKpekP0paIOlFSXvmPGdkWv81SSNLFa+ZmZmVj1K24IwHvr1W2S+AJyJiB+CJtAxwMLBD+jsFuBayhAi4AOgL7ANcUJkUmZmZmdWkZAlOREwB/rVW8TDgpnT/JuDwnPI/R+ZZoJOkrsBBwOMR8a+IeB94nHWTJjMzM7Mvad3A9W0VEYvT/SXAVul+N2BhznoVqaym8nVIOoWs9YdNNtlkrx133LGIYZtZoebPnw/A1772tUaOxMxaglmzZi2LiC5rlzd0glMlIkJS0eaJiIixwFiAPn36xMyZM4u1aTOrhYEDBwIwefLkRo3DzFoGSW9XV97QZ1H9M3U9kW7fTeWLgG1y1uueymoqNzMzM6tRQyc4E4HKM6FGAhNyyk9IZ1PtCyxPXVl/Ab4labM0uPhbqczMzMysRiXropJ0OzAQ2EJSBdnZUBcBd0k6CXgbGJFWnwQcAiwAPga+DxAR/5L0G2BGWu/XEbH2wGUzMzOzL1FE0YbBNBnVjcFZuXIlFRUVfPrpp40UlVnLsGTJEgC+8pWvVJW1bduW7t2706ZNm8YKy8zKlKRZEdFn7fJGG2Tc0CoqKmjfvj09evRAUmOHY1a2Ntgg6/muPIsqInjvvfeoqKigZ8+ejRmambUgLWaqhk8//ZTOnTs7uTFrYJLo3LmzW0/NrEG1mAQHcHJj1kj83TOzhtZiuqhy7XtBcU7EevbCg/I+vnz5coYNGwbA7Nmz2Wmnndhoo41YtmwZ7du3p1WrVkQEP/jBDxg1ahQAPXv2ZLvttmP16tX06NGD8ePH06pVKwB+97vfcf311/PGG29U/cPo2bMngwcP5oYbbgDg5ptv5oQTTuDNN9+kR48eX4on37Yr/fa3v6V79+5V8VQaNWoUL7zwAh06dGDTTTfl1ltvpVOnTut9jcaPH09FRQXnnXfeetctlsMeOLQo25l4+MM1PtbU3ttevXqxYMGCoux3pdz37owzzuDcc8+lS5d1rqVlZtYktagWnIbWsWNHJk+ezOTJk9ljjz24++67mTx5MltssQV3330306ZN4+GHH2b8+PE8+eSTALRq1YrJkyczdepU2rRpw2OPPVa1vYceeohBgwbx9NNPV5W1atWKd955h88++wyAe+65h7322qvaePJtuxBXX301Tz31FP379+e666770mOrV6+u1baau6b23pbalVde6eTGzJoVJziNrFOnTpx77rncdtttXypfs2YNH3zwAZVnuT3//PPssssunHbaadxyyy1fWvfggw/m4Ycf5t1336VNmzbrbVlZe9tTpkyhd+/eDB06lOnTp6835j333JO3336b8ePHM3z4cA4//HCuuuoqrr/+evr27Uvfvn0ZN25c1frTp09n6NCh9O7dm6lTpwIwZ84chgwZwqBBgxgxYgSffPLJeuttbhr6vT3zzDPZf//9Oe6441izZg3Lli1j8ODBDBw4kP79+/Pqq68CcPbZZ9OvXz8OOOAA7rzzTiBLXvfbbz/69etX1WKUa+DAgVRUVPDWW2+x1157cdxxx7Hnnnty5ZVXAlmL1ogRIxg8eDAjR47k7bervbComVmDcYLTBGyzzTYsWpRdoHn16tUMHDiQHj16sHr1ag46KOsGu/XWWxk5ciR9+vRh7ty5rFy5sur5Rx99NHfeeSd33nknI0aMqLaOfNs+66yzmDBhAhMnTqxqLcjnscceY5dddgHgww8/5P777+f444/nmmuuYerUqUydOpWrrrqKpUuXAtkp+g8++CD3338/Z555JgCnn34648aN429/+xv9+/fnxhtvrMMr1/Q11Hu7atUqRowYwVNPPcXGG2/MxIkT6dixI4888giTJ0/mvPPO46KLLgLgkUceYerUqTz55JMMHz6cefPm8eijjzJlyhSmTZvGuHHjeO+992qsa/HixYwdO5ZnnnmGq666CoDf//73fPe73+WJJ55gzJgxXHbZZfV+7czM6qNFjsFp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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "gap_22_prob = df_gap22_ram_prob['avgPktRespTimeWr'].astype(float)\n", + "gap_22_ram = df_gap22_ram['avgPktRespTimeWr'].astype(float)\n", + "gap_22_prob[len(gap_22_prob)] = statistics.geometric_mean(df_gap22_ram_prob['avgPktRespTimeWr'].astype(float))\n", + "gap_22_ram[len(gap_22_ram)] = statistics.geometric_mean(df_gap22_ram['avgPktRespTimeWr'].astype(float))\n", + "\n", + "\n", + "gap_25_prob = df_gap25_ram_prob['avgPktRespTimeWr'].astype(float)\n", + "gap_25_ram = df_gap25_ram['avgPktRespTimeWr'].astype(float)\n", + "gap_25_prob[len(gap_25_prob)] = statistics.geometric_mean(df_gap25_ram_prob['avgPktRespTimeWr'].astype(float))\n", + "gap_25_ram[len(gap_25_ram)] = statistics.geometric_mean(df_gap25_ram['avgPktRespTimeWr'].astype(float))\n", + "\n", + "npb_C_prob = df_npbC_ram_prob['avgPktRespTimeWr'].astype(float)\n", + "npb_C_ram = df_npbC_ram['avgPktRespTimeWr'].astype(float)\n", + "npb_C_prob[len(npb_C_prob)] = statistics.geometric_mean(df_npbC_ram_prob['avgPktRespTimeWr'].astype(float))\n", + "npb_C_ram[len(npb_C_ram)] = statistics.geometric_mean(df_npbC_ram['avgPktRespTimeWr'].astype(float))\n", + "\n", + "\n", + "\n", + "npb_D_prob = df_npbD_ram_prob['avgPktRespTimeWr'].astype(float)\n", + "npb_D_ram = df_npbD_ram['avgPktRespTimeWr'].astype(float)\n", + "npb_D_prob[len(npb_D_prob)] = statistics.geometric_mean(df_npbD_ram_prob['avgPktRespTimeWr'].astype(float))\n", + "npb_D_ram[len(npb_D_ram)] = statistics.geometric_mean(df_npbD_ram['avgPktRespTimeWr'].astype(float))\n", + "\n", + "################################## \n", + "# Multi bar Chart1\n", + "app_gap = df_gap22_ram_prob['app']\n", + "app_gap[len(app_gap)] = \"gmean\"\n", + "\n", + "app_npb = df_npbC_ram_prob['app']\n", + "app_npb[len(app_npb)] = \"gmean\"\n", + "\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,3)\n", + "plt.ylim([0,1000])\n", + "barWidth = 1\n", + "tickSize = 3\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*tickSize-barWidth/2, gap_22_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", + " plt.bar(i*tickSize+barWidth/2, gap_22_ram[i], width=barWidth, color=cmap(2), label='TDRAM-baseline' if i==0 else None)\n", + "\n", + "offset = i+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar((offset+i)*tickSize-barWidth/2, npb_C_prob[i], width=1, color=cmap(1))\n", + " plt.bar((offset+i)*tickSize+barWidth/2, npb_C_ram[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.25, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.7, -0.01, \"NPB-C\")\n", + "\n", + "brLab = np.arange(len(app_gap)+len(app_npb))\n", + "plt.xticks(brLab*tickSize, list(app_gap)+list(app_npb))\n", + "\n", + "plt.axvline(x=(offset-0.5)*tickSize, color='black')\n", + "# plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Avg Wr ORB Time (ns) (ns)\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()\n", + "\n", + "###############################################################################\n", + "# Multi bar Chart2\n", + "app_gap = df_gap25_ram_prob['app']\n", + "app_gap[len(app_gap)] = \"gmean\"\n", + "\n", + "app_npb = df_npbD_ram_prob['app']\n", + "app_npb[len(app_npb)] = \"gmean\"\n", + "\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,3)\n", + "plt.ylim([0,1000])\n", + "barWidth = 1\n", + "tickSize = 3\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*tickSize-barWidth/2, gap_25_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Probe' if i==0 else None)\n", + " plt.bar(i*tickSize+barWidth/2, gap_25_ram[i], width=barWidth, color=cmap(2), label='TDRAM-baseline' if i==0 else None)\n", + "\n", + "offset = i+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar((offset+i)*tickSize-barWidth/2, npb_D_prob[i], width=1, color=cmap(1))\n", + " plt.bar((offset+i)*tickSize+barWidth/2, npb_D_ram[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.25, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.70, -0.01, \"NPB-D\")\n", + "\n", + "brLab = np.arange(len(app_gap)+len(app_npb))\n", + "plt.xticks(brLab*tickSize, list(app_gap)+list(app_npb))\n", + "\n", + "plt.axvline(x=(offset-0.5)*tickSize, color='black')\n", + "# plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Avg Wr ORB time (ns)\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_308484/1314087200.py:35: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " app_gap[len(app_gap)] = \"gmean\"\n", + "/tmp/ipykernel_308484/1314087200.py:38: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " app_npb[len(app_npb)] = \"gmean\"\n", + "/tmp/ipykernel_308484/1314087200.py:72: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " app_gap[len(app_gap)] = \"gmean\"\n", + "/tmp/ipykernel_308484/1314087200.py:75: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " app_npb[len(app_npb)] = \"gmean\"\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAlkklEQVR4nO3de5xd873/8de7I8Ql4ri1mogZl1/rEhWGyAk1Ej2uoVUURUNRKnVrTlvlUD1OqVLyi5YTmqYqSBUVhPJTkYTSJIRIIg5CM6SHpJU0rUsun98fa+2xM2b2rJnZay573s/HYz9mr+9ae30/+7bms7/r+11fRQRmZmZmleQTnR2AmZmZWbk5wTEzM7OK4wTHzMzMKo4THDMzM6s4TnDMzMys4jjBMTMzs4qTW4IjaVtJj0uaL2mepPOa2KZO0nJJc9LbpXnFY2ZmZj3HejnuezXw7Yh4VlIfYLakRyNifqPtpkfEETnGYWZmZj1Mbi04EbEkIp5N7/8dWAD0y6s+MzMzs4I8W3AaSKoGBgHPNLF6iKTngbeA0RExr4nHnwmcCbDxxhvv9dnPfjbHaM0sq4ULFwLwmc98ppMjMbOeavbs2UsjYqvG5cp7qgZJmwBPAP8VEfc0WrcpsDYiVko6DBgTETuV2l9tbW3MmjUrv4DNLLO6ujoApk6d2qlxmFnPJWl2RNQ2Ls91FJWkXsDdwMTGyQ1ARKyIiJXp/SlAL0lb5hmTmZmZVb48R1EJ+AWwICJ+2sw2n0q3Q9I+aTzL8orJzMzMeoY8++AMBU4G5kqak5Z9HxgAEBE3AccAZ0taDbwHHB+e3tzMzMzaKbcEJyJmAGphmxuAG9pb16pVq6ivr+f9999v767MrBm9e/emf//+9OrVq7NDMTNrUYeMospbfX09ffr0obq6mvSMl5mVUUSwbNky6uvrqamp6exwzMxaVBFTNbz//vtsscUWTm7MciKJLbbYwq2kZtZtVESCAzi5McuZv2Nm1p1UxCmqYvte9vuy7Ofpyw9udt3y5cs56qijAJgzZw4777wzG2ywAUuXLqVPnz5UVVUREZxxxhmMHDkSgJqaGrbbbjvWrFlDdXU1EyZMoKqqCoAf/ehH3Hzzzbz22msN/0RqamoYPnw4t9xyCwC//vWvOeWUU1i0aBHV1dXrxFNq3wVXXHEF/fv3b4inYOTIkTz//PNsuummbLLJJkycOJHNNtusxddnwoQJ1NfXc8kll7S4bVsc+bvDy7KfyV98sNl1Xe193HHHHXnllVfK8rwLit+n888/n4svvpittvrY9bDMzCpOxbTgdKS+ffsydepUpk6dyh577MFdd93F1KlT2XLLLbnrrruYMWMGDz74IBMmTODxxx8HoKqqiqlTpzJ9+nR69erFI4880rC/Bx54gGHDhvHkk082lFVVVfHnP/+ZDz74AIDf/va37LXXXk3GU2rfWYwdO5YnnniCoUOHctNNN62zbs2aNa3aV3fS1d7HvF1//fVObsysx3CCk5PNNtuMiy++mNtvv32d8rVr1/Luu+9SGA3/3HPPseuuu3L22Wdz2223rbPtoYceyoMPPsjbb79Nr169WmxZabzvadOmMWjQIEaMGMEzzzQ1S8a69txzT9544w0mTJjAscceyxe/+EXGjBnDzTffzODBgxk8eDDjx49v2P6ZZ55hxIgRDBo0iOnTp2d5Wbqdjn4fL7jgAg444ABOOukk1q5dy9KlSxk+fDh1dXUMHTqUl19+GYDRo0czZMgQDjzwQCZNmgQkier+++/PkCFDGlqMitXV1VFfX8/rr7/OXnvtxUknncSee+7J9ddfDyQtWscddxzDhw9n2LBhZW9NMjPrSE5wcrTtttvy5ptvAklLSF1dHdXV1axZs4aDD05OgU2cOJGvfe1r1NbWMn/+fFatWtXw+OOPP55JkyYxadIkjjvuuGbraW7fF154Iffddx+TJ09uaEEo5ZFHHmHXXXcFYOXKldx7772cfPLJ3HDDDUyfPp3p06czZswY3nnnHSAZnn///fdz7733csEFF7TtReoGOup9XL16NccddxxPPPEEG264IZMnT6Zv37489NBDTJ06lUsuuYSrrroKgIceeojp06fz+OOPc+yxx7JgwQIefvhhpk2bxowZMxg/fjzLljV/zcwlS5Ywbtw4nnrqKcaMGQPAlVdeydFHH81jjz3Gddddx/e+9712v3ZmZp3FCU6OFi9eTL9+yQTqhVMbc+fO5Z133uHdd99l7dq13HfffVxxxRUccsghvP3220yZMqXh8dtssw0rV67kzjvvZMSIEQ3lN9xwA3V1dZx++unN7htgxYoVDBgwAEnss88+AMyYMYO6ujrq6upYuXIlAN/61rc44IADeO+99xr2ue+++yKJ1157jYEDB7L++uuz/vrrM3DgQBYtWgTA3nvvDUB1dTXLly/P8ZXsXB31Pha/T4MHD2bhwoW8++67nHTSSXz+85/n8ssvZ/HixQBcddVVnHbaaYwcOZIFCxbw4osvMn/+fA488ECGDx/OihUrGrZtys4778xGG21E7969G/oQzZ07lzFjxlBXV8d5553X8DkyM+uOKq6TcVexfPlyrrzyyo91wu3bty9nnXUWP/7xjzn44IM56qijuOaaawB49dVXueiiixo6vgKcc845zJ8/nw033LChbNSoUYwaNepjdRbv++qrr6ZPnz7U19fTv39/Zs6cyY477sh+++33sYkRx44dy3777bdOWeGfXk1NDS+88AIffvghkPwTrKmpYf78+cyePRuAP//5z2y66aZtfKW6to58HyOCWbNmMXjwYGbOnMkhhxzCbbfdxqBBg7jooouYMmUKP/3pT4kIDjroIEaMGMGMGTO49NJLufzyyxk0aBB33303kli1ahW9evVizpw5TT6vpkZE7brrrgwZMoQvfelLAA3vuZlZd+QEp8yOPfZYqqqqWLt2LaeddhrDhg372DbHH388AwcOZOnSpZx44okN5TvssAMLFixgxYoVDWWHHXYYhx12WOb6C/v+/ve/z7XXXsuIESP49Kc/TZ8+fdr0fLbeemu++c1vNiRAo0aNauioutFGG3H44Yfz1ltvcd1117Vp/11VZ7yP6623HnfffTff+c536NevH0ceeSQvvfQSJ554ItOmTWs4fbh69WoOPfRQILkG1KWXXspuu+3GQQcdxAEHHEBVVVXDKa7WuPjiiznrrLMYO3YsEcHhhx/O6NGjW7UPM7OuQt1t6qfa2tqYNWvWOmULFixg55137qSIzHqOxt+1uro6gI+1CpqZdRRJsyOitnG5++CYmZlZxXGCY2ZmZhWnYhKc7naqzay78XfMzLqTikhwevfuzbJly3wANstJYTbx3r17d3YoZmaZtDiKStJGwLeBARFxhqSdgM9ExAO5R5dR//79qa+vb7gAnZmVX+/evenfv39nh2FmlkmWYeK/BGYDQ9LlN4G7gC6T4PTq1YuamprODsPMzMy6iCynqHaIiKuBVQAR8U/g41cJMzMzM+sisiQ4H0raEAgASTsALU9sZGZmZtZJspyiugx4GNhW0kRgKDAyz6DMzMzM2qPFBCciHpX0LLAv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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAlhElEQVR4nO3de5xd873/8de7IySI5Li1KmLG5dG6RIUQOaFGonUNqiiKhqIuaV2ao1UO1ePUpW45ScsJTVN1S9UtCOWnIgmqSTSEBAehGdKStJKmbrl8fn+stcfOmNmzZmavuex5Px+P/Zi9vmvt9f3s25rP/q7v+n4VEZiZmZlVks90dABmZmZm5eYEx8zMzCqOExwzMzOrOE5wzMzMrOI4wTEzM7OK4wTHzMzMKk5uCY6kLSQ9LmmepBclndXINrWSlkqak94uyiseMzMz6z7WynHfK4HvR8SzknoDsyU9GhHzGmw3PSIOzjEOMzMz62Zya8GJiEUR8Wx6/5/AfGDzvOozMzMzK8izBaeepGpgIPBMI6uHSHoOeBsYHREvNvL4U4FTAdZbb71dv/jFL+YYrZll9fLLLwPwhS98oYMjMbPuavbs2YsjYpOG5cp7qgZJ6wNPAP8dEXc3WLcBsDoilks6EBgTEduW2t+gQYNi1qxZ+QVsZpnV1tYCMHXq1A6Nw8y6L0mzI2JQw/Jcr6KS1AO4C7i1YXIDEBHLImJ5en8K0EPSxnnGZGZmZpUvz6uoBPwSmB8R1zSxzefS7ZC0exrPkrxiMjMzs+4hzz44Q4HjgbmS5qRlPwL6A0TEDcARwOmSVgIfAEeHpzc3MzOzNsotwYmIGYCa2WYcMK6tda1YsYK6ujo+/PDDtu7KzJrQs2dP+vXrR48ePTo6FLOSDrn3oEzbTT7swZwjsY7ULldR5a2uro7evXtTXV1NesbLzMooIliyZAl1dXXU1NR0dDhmZs2qiKkaPvzwQzbaaCMnN2Y5kcRGG23kVlIz6zIqIsEBnNyY5czfMTPrSiriFFWxPS7+fVn288dL9mty3dKlSzn00EMBmDNnDttttx3rrLMOixcvpnfv3lRVVRERnHLKKYwcORKAmpoattxyS1atWkV1dTUTJ06kqqoKgJ/+9KfceOONvP766/X/RGpqahg+fDg33XQTAL/5zW844YQTWLBgAdXV1WvEU2rfBZdeein9+vWrj6dg5MiRPPfcc2ywwQasv/763HrrrfTt27fZ12fixInU1dVx4YUXNrtta2Q9h96cUufYO9v7uM022/Dqq6+W5XkXFL9PZ599NhdccAGbbPKp8bDMzCpOxbTgtKc+ffowdepUpk6dys4778ydd97J1KlT2XjjjbnzzjuZMWMGDz74IBMnTuTxxx8HoKqqiqlTpzJ9+nR69OjBI488Ur+/Bx54gGHDhvHkk0/Wl1VVVfGXv/yFjz76CIDf/e537Lrrro3GU2rfWYwdO5YnnniCoUOHcsMNN6yxbtWqVS3aV1fS2d7HvF133XVObsys23CCk5O+fftywQUXcNttt61Rvnr1at577z0KV8P/+c9/ZocdduD000/nlltuWWPbAw44gAcffJB33nmHHj16NNuy0nDf06ZNY+DAgYwYMYJnnmlslow17bLLLrz55ptMnDiRI488ksMOO4wxY8Zw4403MnjwYAYPHsyECRPqt3/mmWcYMWIEAwcOZPr06Vleli6nvd/Hc845h7333pvjjjuO1atXs3jxYoYPH05tbS1Dhw7llVdeAWD06NEMGTKEffbZh0mTJgFJorrXXnsxZMiQ+hajYrW1tdTV1fHGG2+w6667ctxxx7HLLrtw3XXXAUmL1lFHHcXw4cMZNmxY2VuTzMzakxOcHG2xxRa89dZbQNISUltbS3V1NatWrWK//ZJTYLfeeivf+ta3GDRoEPPmzWPFihX1jz/66KOZNGkSkyZN4qijjmqynqb2fe6553LfffcxefLk+haEUh555BF22GEHAJYvX84999zD8ccfz7hx45g+fTrTp09nzJgxvPvuu0Byef7999/PPffcwznnnNO6F6kLaK/3ceXKlRx11FE88cQT9OrVi8mTJ9OnTx8eeughpk6dyoUXXsjll18OwEMPPcT06dN5/PHHOfLII5k/fz4PP/ww06ZNY8aMGUyYMIElS5oeM3PRokWMHz+ep556ijFjxgBw2WWXcfjhh/PYY49x7bXX8sMf/rDNr52ZWUdxgpOjhQsXsvnmyQTqhVMbc+fO5d133+W9995j9erV3HfffVx66aXsv//+vPPOO0yZMqX+8ZttthnLly/njjvuYMSIEfXl48aNo7a2lpNPPrnJfQMsW7aM/v37I4ndd98dgBkzZlBbW0ttbS3Lly8H4Lvf/S577703H3zwQf0+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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "gap_22_prob = df_gap22_ram_prob['simSeconds'].astype(float)/df_gap22_noDC['simSeconds'].astype(float)\n", + "gap_22_ram = df_gap22_ram['simSeconds'].astype(float)/df_gap22_noDC['simSeconds'].astype(float)\n", + "geo_meanC = df_gap22_ram_prob['simSeconds'].astype(float)/df_gap22_noDC['simSeconds'].astype(float)\n", + "geo_meanR = df_gap22_ram['simSeconds'].astype(float)/df_gap22_noDC['simSeconds'].astype(float)\n", + "gap_22_prob[len(gap_22_prob)] = statistics.geometric_mean(geo_meanC)\n", + "gap_22_ram[len(gap_22_ram)] = statistics.geometric_mean(geo_meanR)\n", + "\n", + "\n", + "gap_25_prob = df_gap25_ram_prob['simSeconds'].astype(float)/df_gap25_noDC['simSeconds'].astype(float)\n", + "gap_25_ram = df_gap25_ram['simSeconds'].astype(float)/df_gap25_noDC['simSeconds'].astype(float)\n", + "geo_meanC = df_gap25_ram_prob['simSeconds'].astype(float)/df_gap25_noDC['simSeconds'].astype(float)\n", + "geo_meanR = df_gap25_ram['simSeconds'].astype(float)/df_gap25_noDC['simSeconds'].astype(float)\n", + "gap_25_prob[len(gap_25_prob)] = statistics.geometric_mean(geo_meanC)\n", + "gap_25_ram[len(gap_25_ram)] = statistics.geometric_mean(geo_meanR)\n", + "\n", + "npb_C_prob = df_npbC_ram_prob['simSeconds'].astype(float)/df_npbC_noDC['simSeconds'].astype(float)\n", + "npb_C_ram = df_npbC_ram['simSeconds'].astype(float)/df_npbC_noDC['simSeconds'].astype(float)\n", + "geo_meanC = df_npbC_ram_prob['simSeconds'].astype(float)/df_npbC_noDC['simSeconds'].astype(float)\n", + "geo_meanR = df_npbC_ram['simSeconds'].astype(float)/df_npbC_noDC['simSeconds'].astype(float)\n", + "npb_C_prob[len(npb_C_prob)] = statistics.geometric_mean(geo_meanC)\n", + "npb_C_ram[len(npb_C_ram)] = statistics.geometric_mean(geo_meanR)\n", + "\n", + "\n", + "\n", + "npb_D_prob = df_npbD_ram_prob['simSeconds'].astype(float)/df_npbD_noDC['simSeconds'].astype(float)\n", + "npb_D_ram = df_npbD_ram['simSeconds'].astype(float)/df_npbD_noDC['simSeconds'].astype(float)\n", + "geo_mean = df_npbD_ram_prob['simSeconds'].astype(float)/df_npbD_noDC['simSeconds'].astype(float)\n", + "geo_mean = df_npbD_ram['simSeconds'].astype(float)/df_npbD_noDC['simSeconds'].astype(float)\n", + "npb_D_prob[len(npb_D_prob)] = statistics.geometric_mean(geo_meanC)\n", + "npb_D_ram[len(npb_D_ram)] = statistics.geometric_mean(geo_meanR)\n", + "\n", + "################################## \n", + "# Multi bar Chart1\n", + "app_gap = df_gap22_ram_prob['app']\n", + "app_gap[len(app_gap)] = \"gmean\"\n", + "\n", + "app_npb = df_npbC_ram_prob['app']\n", + "app_npb[len(app_npb)] = \"gmean\"\n", + "\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,3)\n", + "plt.ylim([0,2.5])\n", + "barWidth = 1\n", + "tickSize = 3\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*tickSize-barWidth/2, gap_22_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", + " plt.bar(i*tickSize+barWidth/2, gap_22_ram[i], width=barWidth, color=cmap(2), label='TDRAM-baseline' if i==0 else None)\n", + "\n", + "offset = i+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar((offset+i)*tickSize-barWidth/2, npb_C_prob[i], width=1, color=cmap(1))\n", + " plt.bar((offset+i)*tickSize+barWidth/2, npb_C_ram[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.25, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.7, -0.01, \"NPB-C\")\n", + "\n", + "brLab = np.arange(len(app_gap)+len(app_npb))\n", + "plt.xticks(brLab*tickSize, list(app_gap)+list(app_npb))\n", + "\n", + "plt.axvline(x=(offset-0.5)*tickSize, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Normalized Execution Time\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()\n", + "\n", + "###############################################################################\n", + "# Multi bar Chart2\n", + "app_gap = df_gap25_ram_prob['app']\n", + "app_gap[len(app_gap)] = \"gmean\"\n", + "\n", + "app_npb = df_npbD_ram_prob['app']\n", + "app_npb[len(app_npb)] = \"gmean\"\n", + "\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,3)\n", + "plt.ylim([0,2.5])\n", + "barWidth = 1\n", + "tickSize = 3\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*tickSize-barWidth/2, gap_25_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", + " plt.bar(i*tickSize+barWidth/2, gap_25_ram[i], width=barWidth, color=cmap(2), label='TDRAM-baseline' if i==0 else None)\n", + "\n", + "offset = i+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar((offset+i)*tickSize-barWidth/2, npb_D_prob[i], width=1, color=cmap(1))\n", + " plt.bar((offset+i)*tickSize+barWidth/2, npb_D_ram[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.25, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.70, -0.01, \"NPB-D\")\n", + "\n", + "brLab = np.arange(len(app_gap)+len(app_npb))\n", + "plt.xticks(brLab*tickSize, list(app_gap)+list(app_npb))\n", + "\n", + "plt.axvline(x=(offset-0.5)*tickSize, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Normalized Execution Time\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAfFElEQVR4nO3debxVdb3/8de7I4oggwMaigqS15ESPU5XzKNWThHaT8zhqphDmpbDtSzrFw38SiuvebWLDzHDFBOHEBUv6TVOoiUKKoKgZeAAoUAFXhJF4fP7Y30Pbo77bM60Bxbv5+NxHnuv71p7r/fZwzqfs9Z3ra8iAjMzM7M8+Ui1A5iZmZl1Nhc4ZmZmljsucMzMzCx3XOCYmZlZ7rjAMTMzs9xxgWNmZma5U7YCR9ItkhZLml3QtpWkRyT9Od1umdol6T8lvSzpeUn7liuXmZmZ5V859+CMBY5u1vYN4NGI2BV4NE0DHAPsmn7OA0aXMZeZmZnlXNkKnIh4DPh7s+ZhwK3p/q3A8QXtv4rMk0BvSX3Llc3MzMzybZMKr2+7iFiU7r8BbJfu7wC8XrDcgtS2iGYknUe2l4fu3bvvt/vuu5cvrZl9yEsvvQTAbrvtVuUkZmYwY8aMpRHRp3l7pQuctSIiJLV5nIiIuAm4CaC+vj6mT5/e6dnMrGUNDQ0ANDY2VjWHmRmApFeLtVf6LKo3mw49pdvFqX0hsGPBcv1Sm5mZmVmbVbrAuR84M90/E5hY0H5GOpvqIGB5waEsMzMzszYp2yEqSb8GGoBtJC0ARgJXAXdJOht4FTgpLf4QcCzwMvA2cFa5cpmZmVn+la3AiYhTWph1ZJFlA7iwM9a7bNkyFi3yzp9a07dvX3r37l3tGGZmtpGoWifjclm6dCn9+/dn8803r3YUS1auXMnChQtd4JiZWcXkbqiG9957j65du1Y7hhXo2rUr7733XrVjmJnZRiR3BQ6ApGpHsAJ+P8zMrNJyd4iq0EEjf9spz/Pk945qcd7y5csZNmwYAM899xx77LEHm222GUuXLqVHjx7U1dUREZx77rmMGDECgAEDBrDzzjuzevVq+vfvz9ixY6mrqwPghz/8IWPGjGHevHlrC4MBAwZw5JFHcvPNNwNw2223ccYZZzB//nz69++/Tp5Sz91k1KhR9OvXb22eJiNGjGDmzJn07NmTLbbYgnHjxrXqsNLYsWNZsGAB3/72t9e7rJmZWSXkcg9OJfXq1YvGxkYaGxvZZ599uPvuu2lsbGSbbbbh7rvv5vHHH2fSpEmMHTuWKVOmAFBXV0djYyNTp06lS5cuPPzww2uf78EHH+SII47giSeeWNtWV1fHa6+9xrvvvgvAPffcw3777Vc0T6nnbo3rr7+e3//+9xxyyCHceOON68xbvXp1m57LzMysWlzgVEDv3r351re+xR133LFO+5o1a1i2bBnZSWTw7LPPstdee3HBBRdw++23r7PsMcccw6RJk1i8eDFdunRZ756V5s/92GOPMXjwYIYOHcq0adPWm3nffffl1VdfZezYsQwfPpzjjz+e6667jjFjxnDggQdy4IEHcsstt6xdftq0aQwdOpTBgwczderU1rwsZmZmZeMCp0J23HFHFi7MLs68evVqGhoa6N+/P6tXr+aoo7JDYOPGjePMM8+kvr6eOXPmrNMx9+STT2b8+PGMHz+ek046qeg6Sj33ZZddxsSJE7n//vvX7gkq5eGHH2avvfYCYMWKFUyYMIHTTz+dG264galTpzJ16lSuu+46lixZAmSdux944AEmTJjApZde2r4XyczMrJO4wKmQ119/nR122AH44DDSrFmzWLJkCcuWLWPNmjVMnDiRUaNGcfTRR7N48WIeeuihtY/v27cvK1as4M4772To0KFr22+44QYaGho455xzWnxugLfeeouddtoJSRxwwAEAPP744zQ0NNDQ0MCKFSsA+MpXvsJhhx3GypUr1z7nQQcdhCTmzZvHoEGD2HTTTdl0000ZNGgQ8+fPB2D//fcHoH///ixfvryMr6SZmdn6ucCpgOXLl/OjH/2IU05Z99qHvXr14vzzz+fqq69mypQpDBs2jMmTJzN58mQmTZrEuHHj1ln+wgsv5IQTTljnGj8XXXQRjY2NazsgF3tugB49erBgwQIAnn76aQCGDBmytv/QFltsAXzQB2f06NFrT7dv6qQ8YMAAnn/+eVatWsWqVauYNWsWAwYMAGDGjBkAvPbaa/Ts2bPjL5qZmVkH5PosqmobPnw4dXV1rFmzhi9+8YscccQRH1rm5JNPZtCgQSxdupRTTz11bfvAgQOZO3cub7311tq2Y489lmOPPbbV62967iuvvJJrrrmGoUOHsv3229OjR492/T7bbrstX/7ylxkyZAiQFVd9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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "gap_22_prob = 100* df_gap22_ram_prob['actDelayedDueToTagAct'].astype(float)/(df_gap22_ram_prob['numTotMisses'].astype(float)+df_gap22_ram_prob['numTotHits'].astype(float))\n", + "#gap_22_prob[len(gap_22_prob)] = statistics.geometric_mean(df_gap22_ram_prob['actDelayedDueToTagAct'].astype(float))\n", + "\n", + "\n", + "gap_25_prob = 100* df_gap25_ram_prob['actDelayedDueToTagAct'].astype(float)/(df_gap25_ram_prob['numTotMisses'].astype(float)+df_gap25_ram_prob['numTotHits'].astype(float))\n", + "#gap_25_prob[len(gap_25_prob)] = statistics.geometric_mean(df_gap25_ram_prob['actDelayedDueToTagAct'].astype(float))\n", + "\n", + "npb_C_prob = 100* df_npbC_ram_prob['actDelayedDueToTagAct'].astype(float)/(df_npbC_ram_prob['numTotMisses'].astype(float)+df_npbC_ram_prob['numTotHits'].astype(float))\n", + "#npb_C_prob[len(npb_C_prob)] = statistics.geometric_mean(df_npbC_ram_prob['actDelayedDueToTagAct'].astype(float))\n", + "\n", + "\n", + "\n", + "npb_D_prob = 100* df_npbD_ram_prob['actDelayedDueToTagAct'].astype(float)/(df_npbD_ram_prob['numTotMisses'].astype(float)+df_npbD_ram_prob['numTotHits'].astype(float))\n", + "#npb_D_prob[len(npb_D_prob)] = statistics.geometric_mean(df_npbD_ram_prob['actDelayedDueToTagAct'].astype(float))\n", + "\n", + "################################## \n", + "# Multi bar Chart1\n", + "app_gap = df_gap22_ram_prob['app']\n", + "#app_gap[len(app_gap)] = \"gmean\"\n", + "\n", + "app_npb = df_npbC_ram_prob['app']\n", + "#app_npb[len(app_npb)] = \"gmean\"\n", + "\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,3)\n", + "plt.ylim([0,100])\n", + "barWidth = 1\n", + "tickSize = 2\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*tickSize-barWidth/2, gap_22_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", + "\n", + "offset = i+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar((offset+i)*tickSize-barWidth/2, npb_C_prob[i], width=1, color=cmap(1))\n", + "\n", + "plt.figtext(0.25, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.7, -0.01, \"NPB-C\")\n", + "\n", + "brLab = np.arange(len(app_gap)+len(app_npb))\n", + "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", + "\n", + "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", + "# plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"ACT delayed (%)\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()\n", + "\n", + "###############################################################################\n", + "# Multi bar Chart2\n", + "app_gap = df_gap25_ram_prob['app']\n", + "#app_gap[len(app_gap)] = \"gmean\"\n", + "\n", + "app_npb = df_npbD_ram_prob['app']\n", + "#app_npb[len(app_npb)] = \"gmean\"\n", + "\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,3)\n", + "plt.ylim([0,100])\n", + "barWidth = 1\n", + "tickSize = 2\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*tickSize-barWidth/2, gap_25_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Probe' if i==0 else None)\n", + "offset = i+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar((offset+i)*tickSize-barWidth/2, npb_D_prob[i], width=1, color=cmap(1))\n", + "\n", + "plt.figtext(0.25, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.70, -0.01, \"NPB-D\")\n", + "\n", + "brLab = np.arange(len(app_gap)+len(app_npb))\n", + "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", + "\n", + "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", + "# plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"ACT delayed (%)\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "x1 = df_gap22_ram_prob['app']\n", + "y1 = 100 * df_gap22_ram_prob['noCandidBSlot'].astype(float)/(df_gap22_ram_prob['locMemReadBursts'].astype(float)+df_gap22_ram_prob['locMemWriteBursts'].astype(float))\n", + "y2 = 100 * df_gap22_ram_prob['foundCandidBSlotRH'].astype(float)/(df_gap22_ram_prob['locMemReadBursts'].astype(float)+df_gap22_ram_prob['locMemWriteBursts'].astype(float))\n", + "y3 = 100 * df_gap22_ram_prob['foundCandidBSlotRMC'].astype(float)/(df_gap22_ram_prob['locMemReadBursts'].astype(float)+df_gap22_ram_prob['locMemWriteBursts'].astype(float))\n", + "y4 = 100 * df_gap22_ram_prob['foundCandidBSlotRMD'].astype(float)/(df_gap22_ram_prob['locMemReadBursts'].astype(float)+df_gap22_ram_prob['locMemWriteBursts'].astype(float))\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(6,3)\n", + "plt.ylim([0,110])\n", + "\n", + "for i,app in enumerate(x1): \n", + " plt.bar(i*4, y1[i], width=3, color=cmap(1), label='Not Probed' if i==0 else None)\n", + " plt.bar(i*4, y2[i], bottom = y1[i], width=3, color=cmap(2), label='Read-Hit' if i==0 else None)\n", + " plt.bar(i*4, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3), label='Read-MC' if i==0 else None)\n", + " plt.bar(i*4, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4), label='Read-MD' if i==0 else None)\n", + "\n", + "offset = (i+1)*4\n", + "x2 = df_npbC_ram_prob['app']\n", + "y1 = 100 * df_npbC_ram_prob['noCandidBSlot'].astype(float)/(df_npbC_ram_prob['locMemReadBursts'].astype(float)+df_npbC_ram_prob['locMemWriteBursts'].astype(float))\n", + "y2 = 100 * df_npbC_ram_prob['foundCandidBSlotRH'].astype(float)/(df_npbC_ram_prob['locMemReadBursts'].astype(float)+df_npbC_ram_prob['locMemWriteBursts'].astype(float))\n", + "y3 = 100 * df_npbC_ram_prob['foundCandidBSlotRMC'].astype(float)/(df_npbC_ram_prob['locMemReadBursts'].astype(float)+df_npbC_ram_prob['locMemWriteBursts'].astype(float))\n", + "y4 = 100 * df_npbC_ram_prob['foundCandidBSlotRMD'].astype(float)/(df_npbC_ram_prob['locMemReadBursts'].astype(float)+df_npbC_ram_prob['locMemWriteBursts'].astype(float))\n", + "\n", + "for i,app in enumerate(x2): \n", + " plt.bar(i*4+offset, y1[i], width=3, color=cmap(1))\n", + " plt.bar(i*4+offset, y2[i], bottom = y1[i], width=3, color=cmap(2))\n", + " plt.bar(i*4+offset, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3))\n", + " plt.bar(i*4+offset, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*4, list(x1)+list(x2))\n", + "plt.axvline(x=offset-2, color='black')\n", + "plt.axhline(y=100, color='gray')\n", + "\n", + "plt.ylabel(\"Breakdown of B slots probing (%)\", fontsize=10)\n", + "plt.legend(fontsize=9, ncol=2, loc='lower right')\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_mpki.pdf\")\n", + "\n", + "x1 = df_gap25_ram_prob['app']\n", + "y1 = 100 * df_gap25_ram_prob['noCandidBSlot'].astype(float)/(df_gap25_ram_prob['locMemReadBursts'].astype(float)+df_gap25_ram_prob['locMemWriteBursts'].astype(float))\n", + "y2 = 100 * df_gap25_ram_prob['foundCandidBSlotRH'].astype(float)/(df_gap25_ram_prob['locMemReadBursts'].astype(float)+df_gap25_ram_prob['locMemWriteBursts'].astype(float))\n", + "y3 = 100 * df_gap25_ram_prob['foundCandidBSlotRMC'].astype(float)/(df_gap25_ram_prob['locMemReadBursts'].astype(float)+df_gap25_ram_prob['locMemWriteBursts'].astype(float))\n", + "y4 = 100 * df_gap25_ram_prob['foundCandidBSlotRMD'].astype(float)/(df_gap25_ram_prob['locMemReadBursts'].astype(float)+df_gap25_ram_prob['locMemWriteBursts'].astype(float))\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(6,3)\n", + "plt.ylim([0,110])\n", + "for i,app in enumerate(x1): \n", + " plt.bar(i*4, y1[i], width=3, color=cmap(1), label='Not Probed' if i==0 else None)\n", + " plt.bar(i*4, y2[i], bottom = y1[i], width=3, color=cmap(2), label='Read-Hit' if i==0 else None)\n", + " plt.bar(i*4, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3), label='Read-MC' if i==0 else None)\n", + " plt.bar(i*4, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4), label='Read-MD' if i==0 else None)\n", + "\n", + "offset = (i+1)*4\n", + "x2 = df_npbD_ram_prob['app']\n", + "y1 = 100 * df_npbD_ram_prob['noCandidBSlot'].astype(float)/(df_npbD_ram_prob['locMemReadBursts'].astype(float)+df_npbD_ram_prob['locMemWriteBursts'].astype(float))\n", + "y2 = 100 * df_npbD_ram_prob['foundCandidBSlotRH'].astype(float)/(df_npbD_ram_prob['locMemReadBursts'].astype(float)+df_npbD_ram_prob['locMemWriteBursts'].astype(float))\n", + "y3 = 100 * df_npbD_ram_prob['foundCandidBSlotRMC'].astype(float)/(df_npbD_ram_prob['locMemReadBursts'].astype(float)+df_npbD_ram_prob['locMemWriteBursts'].astype(float))\n", + "y4 = 100 * df_npbD_ram_prob['foundCandidBSlotRMD'].astype(float)/(df_npbD_ram_prob['locMemReadBursts'].astype(float)+df_npbD_ram_prob['locMemWriteBursts'].astype(float))\n", + "\n", + "for i,app in enumerate(x2): \n", + " plt.bar(i*4+offset, y1[i], width=3, color=cmap(1))\n", + " plt.bar(i*4+offset, y2[i], bottom = y1[i], width=3, color=cmap(2))\n", + " plt.bar(i*4+offset, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3))\n", + " plt.bar(i*4+offset, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*4, list(x1)+list(x2))\n", + "plt.axvline(x=offset-2, color='black')\n", + "plt.axhline(y=100, color='gray')\n", + "\n", + "plt.ylabel(\"Breakdown of B slots probing (%)\", fontsize=10)\n", + "plt.legend(fontsize=9, ncol=2, loc='lower right')\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_308484/3451258688.py:35: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " app_gap[len(app_gap)] = \"gmean\"\n", + "/tmp/ipykernel_308484/3451258688.py:38: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " app_npb[len(app_npb)] = \"gmean\"\n", + "/tmp/ipykernel_308484/3451258688.py:70: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " app_gap[len(app_gap)] = \"gmean\"\n", + "/tmp/ipykernel_308484/3451258688.py:73: SettingWithCopyWarning: \n", + "A value is trying to be set on a copy of a slice from a DataFrame\n", + "\n", + "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", + " app_npb[len(app_npb)] = \"gmean\"\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAfB0lEQVR4nO3de7xUdb3/8de7LYoKSiKWgbjR/KkZhroVPVputX7eIrK8YP1ULCWvpWank5ZmxzJ/HY/HIwWpcSjFS94ShWP6KLeCJQEGIhAexQtbLQETJC/cPuePtWY7jPsye+9Ze2DN+/l47MfM+s531ue71qxZ+zPfdfkqIjAzMzPLkw9UuwFmZmZmleYEx8zMzHLHCY6ZmZnljhMcMzMzyx0nOGZmZpY7TnDMzMwsdzJLcCTtJOkRSQskzZf0jVbqNEpaIWlO+ndZVu0xMzOz2rFZhvNeC3wzIp6U1BeYLenhiFhQUm9aRHw2w3aYmZlZjcmsByciXo2IJ9PnbwILgYFZxTMzMzMryLIHp4WkemAfYEYrLx8kaS7wCnBxRMxv5f1jgDEAW2+99X577LFHhq01s3ItWrQIgN13373KLTGzWjV79uxlETGgtFxZD9UgqQ/wKPDDiLin5LVtgPURsUrSMcB1EbFbe/NraGiIWbNmZddgMytbY2MjAE1NTVVth5nVLkmzI6KhtDzTq6gk9QLuBiaVJjcAEbEyIlalz6cCvSRtn2WbzMzMLP+yvIpKwC+AhRHx723U+XBaD0kHpO1ZnlWbzMzMrDZkeQ7OwcApwDxJc9KyS4DBABExHjgeOFvSWuBtYFR4eHMzMzPrpswSnIiYDqiDOmOBsd2NtWbNGpqbm3nnnXe6OyuroN69ezNo0CB69epV7aaYmVmN6ZGrqLLW3NxM3759qa+vJz3iZVUWESxfvpzm5maGDBlS7eaYmVmNycVQDe+88w79+/d3crMRkUT//v3dq2ZmZlWRiwQHcHKzEfJnYmZm1ZKLQ1TFDrz8txWZzxNXHNnmaytWrGDkyJEAzJkzhz333JMtttiCZcuW0bdvX+rq6ogIzjzzTEaPHg3AkCFD2HnnnVm3bh319fVMnDiRuro6AH70ox9x4403snjx4pakYMiQIRxxxBHcdNNNANx8882ceuqpPP/889TX12/QnvbmXXDllVcyaNCglvYUjB49mrlz57LNNtvQp08fJk2aRL9+/TpcPxMnTqS5uZnvfve7HdY1MzPrabnpwelJ2267LU1NTTQ1NTFs2DDuvPNOmpqa2H777bnzzjuZPn06U6ZMYeLEiTzyyCMA1NXV0dTUxLRp0+jVqxcPPfRQy/weeOABDj/8cB5//PGWsrq6Ol566SXeffddAO666y7222+/VtvT3rzLcf311/Poo49y8MEHM378+A1eW7duXafmZWZmtjFwgpORfv36cemll3LrrbduUL5+/XreeOMNClfD//nPf2avvfbi7LPP5pZbbtmg7tFHH82UKVN47bXX6NWrV4c9K6Xzfuyxx9hnn30YMWIEM2a0NkrGhvbdd19efPFFJk6cyAknnMDnP/95rrvuOm688UaGDx/O8OHDmTBhQkv9GTNmMGLECPbZZx+mTZtWzmoxMzPrEU5wMrTTTjvx8ssvA0lPSGNjI/X19axbt44jj0wOgU2aNInTTjuNhoYGFixYwJo1a1reP2rUKO644w7uuOMOTjzxxDbjtDXviy66iPvuu4/Jkye39AS156GHHmKvvfYCYNWqVdx7772ccsopjB07lmnTpjFt2jSuu+46li5dCiSX599///3ce++9XHjhhV1bSWZmZhlwgpOhJUuWMHBgMoB64TDSvHnzWLp0KW+88Qbr16/nvvvu48orr+Soo47itddeY+rUqS3v33HHHVm1ahW33347I0aMaCkfO3YsjY2NnHHGGW3OG2DlypUMHjwYSRxwwAEATJ8+ncbGRhobG1m1ahUA559/Poceeihvv/12yzwPPPBAJLF48WKGDh3K5ptvzuabb87QoUN5/vnnAdh///0BqK+vZ8WKFRmuSTMzs85xgpORFStWcNVVV3HyySdvUL7tttty1llncfXVV/PII48wcuRIHnzwQR588EGmTJnCpEmTNqh/7rnnctxxx7Hlllu2lJ133nk0NTW1nIDc2rwB+vbtS3NzMwAzZ84E4JBDDmk5f6hPnz7Ae+fgjBs3jt69ewO0nKQ8ZMgQnnrqKVavXs3q1auZN29ey31tZs+eDcBLL73ENtts0/2VZmZmViG5u4qq2k444QTq6upYv349X/nKVzj88MPfV2fUqFEMHTqUZcuW8aUvfamlfNddd2XhwoWsXLmypeyYY47hmGOOKTt+Yd6XXHIJ11xzDSNGjOAjH/kIffv27dLy7LDDDpxzzjkccsghQJJcDRiQjEq/1VZbceyxx/LKK69w7bXXdmn+ZmZmWdCmNvRTQ0NDzJo1a4OyhQsXsueee1apRdYefzb51tjYCEBTU1NV22FmtUvS7IhoKC33ISozMzPLHSc4ZmZmlju5SXA2tUNttcCfiZmZVUsuEpzevXuzfPly/0PdiBRGEy9clWVmZtaTcnEV1aBBg2hubm65AZ1tHHr37s2gQYOq3QwzM6tBuUhwevXq1XJvFjMzM7NcHKIyMzMzK+YEx8zMzHLHCY6ZmZnljhMcMzMzyx0nOGZmZpY7TnDMzMwsd5zgmJmZWe44wTEzM7PccYJjZmZmuZNZgiNpJ0mPSFogab6kb7RSR5L+U9Kzkp6StG9W7TEzM7PakeVQDWuBb0bEk5L6ArMlPRwRC4rqHA3slv4NB8alj2ZmZmZdllkPTkS8GhFPps/fBBYCA0uqjQR+FYkngH6SdsyqTWZmZlYbeuQcHEn1wD7AjJKXBgJLiqabeX8ShKQxkmZJmuURw83MzKwjmSc4kvoAdwMXRMTKrswjIm6IiIaIaBgwYEBlG2hmZma5k2mCI6kXSXIzKSLuaaXKy8BORdOD0jIzMzOzLsvyKioBvwAWRsS/t1FtMnBqejXVgcCKiHg1qzaZmZlZbcjyKqqDgVOAeZLmpGWXAIMBImI8MBU4BngWeAs4PcP2mJmZWY3ILMGJiOmAOqgTwLlZtcHMzMxqk+9kbGZmZrnjBMfMzMxyxwmOmZmZ5Y4THDMzM8sdJzhmZmaWO05wzMzMLHec4JiZmVnuOMExMzOz3HGCY2ZmZrnjBMfMzMxyxwmOmZmZ5Y4THDMzM8sdJzhmZmaWO05wzMzMLHec4JiZmVnuOMExMzOz3HGCY2ZmZrnjBMfMzMxyxwmOmZmZ5Y4THDMzM8sdJzhmZmaWO05wzMzMLHec4JiZmVnuOMExMzOz3HGCY2ZmZrnjBMfMzMxyJ7MER9IESa9JerqN1xslrZA0J/27LKu2mJmZWW3ZrNyKkjYH9gACWBQRqzt4y0RgLPCrdupMi4jPltsGMzMzs3KU1YMj6VjgOeA/SZKWZyUd3d57IuIx4PVut9DMzMysk8rtwbkGOCwingWQtCswBfjvbsY/SNJc4BXg4oiY31olSWOAMQCDBw/uZkgzMzPLu3LPwXmzkNykFgNvdjP2k8DOEfEJ4HrgN21VjIgbIqIhIhoGDBjQzbBmZmaWd+UmOLMkTZU0WtJpwP3ATElfkPSFrgSOiJURsSp9PhXoJWn7rszLzMzMrFi5h6h6A38DDk2nlwJbAiNITjq+p7OBJX0Y+FtEhKQDSJKt5Z2dj5mZmVmpshKciDi9szOWdBvQCGwvqRm4HOiVzm88cDxwtqS1wNvAqIiIzsYxMzMzK1VWgiPpv0h6ajYQEV9p6z0RcXJ784yIsSRXZJmZmZlVVLmHqB4oet4bOI7kyiczMzOzjU65h6juLp5ODz9Nz6RFZmZmZt3U1aEadgN2qGRDzMzMzCql3HNw3iQ5B0fp41+Bb2fYLjMzM7MuK/cQVd+sG2JmZmZWKe0mOJL2be/1iHiyss0xMzMz676OenCuSR97Aw3AXJLDVHsDs4CDsmuamZmZWde0e5JxRBwWEYcBrwL7puNB7QfsA7zcEw00MzMz66xyr6LaPSLmFSYi4mlgz2yaZGZmZtY95d7o7ylJNwG3pNNfBp7KpklmZmYdO/Dy33b5vU9ccWQFW2Ibo3ITnNOBs4FvpNOPAeMyaZGZmZlZN5V7mfg7ksYDUyNiUcZtMjMzM+uWss7BkfQ5YA7wYDo9TNLkDNtlZmZm1mXlnmR8OXAA8AZARMwBhmTTJDMzM7PuKTfBWRMRK0rKotKNMTMzM6uEck8yni/pS0CdpN2ArwN/yK5ZZmZd152ra8BX2JjlQbk9OOcDewHvArcCK4ALMmqTmZmZWbeUexXVW8Clkn6YPjczMzPbaJWV4Ej6J+AmoA8wWNIngK9FxDlZNs7yzTfpMjOzrJR7iOpa4EhgOUBEzAU+lVWjzMzMzLqj3ASHiFhSUrSuwm0xMzMzq4hyr6Jakh6mCkm9SIZsWJhds8zMzMy6rtwenLOAc4GBwCvAsHTazMzMbKNT7lVUy0hGELeM+IRbMzOzyin3KqpdgOuAA0nuYPxH4MKIWJxh26rCiYblkbfr/PNnbFnaFLevcs/BuRX4KXBcOj0KuA0Y3tYbJE0APgu8FhEfb+V1kSRNxwBvAaMj4snym26V4Du+9hyvazOznlNugrNVRNxcNH2LpG918J6JwFjgV228fjSwW/o3HBhHOwmTWaVsir9EzMyscxTR8ZiZkq4G/g7cTnKI6iTgg8BPACLi9TbeVw880EYPzs+Bpoi4LZ1eBDRGxKvttWXIkCFx+eWXd9jmrnryhVYXpSz71m9XU3GrGbvW4lYzdntx58yZA8CwYcN6NG5Hqrmuq6Va67qaNsXty+u68k4//fTZEdFQWl5uD86J6eOY9FHp4yiShGeXLrRpIFB8b53mtOx9CY6kMYXYAwcO7EIoM7OesTH/I7BNn7ev8rXbgyNpf2BJRPw1nT4N+CLwAvD9tnpuit5fT9s9OA8AP46I6en074BvR8Ss9ubZ0NAQs2a1W6VbqnX4YlOMW83YtRa3mrHbi9vY2AhAU1NTj8btSB7X9cYat5pqcV3X4jJ3RFKXenB+Dnw6ncGngKtIRhYfBtwAHN+NNr0M7FQ0PSgtMzOzTcjG/M/PaldHN/qrK+qlOQm4ISLujojvAR/tZuzJwKlKHAis6Oj8GzMzM7NydNSDUydps4hYCxzBe+fgdPheSbcBjcD2kpqBy4FeABExHphKcon4sySXiZ/elQUwMzMzK9VRgnMb8KikZcDbwDQASR8FVrT3xog4uYPXAw/3YGZmZhloN8GJiB+mJ//uCDwU752R/AGSc3HMzMzMNjodXiYeEU+0UvZMNs0xMzMz675yRxM3MzMz22Q4wTEzM7PccYJjZmZmueMEx8zMzHLHCY6ZmZnljhMcMzMzyx0nOGZmZpY7TnDMzMwsd5zgmJmZWe44wTEzM7PccYJjZmZmueMEx8zMzHLHCY6ZmZnljhMcMzMzyx0nOGZmZpY7TnDMzMwsd5zgmJmZWe44wTEzM7PccYJjZmZmueMEx8zMzHLHCY6ZmZnljhMcMzMzyx0nOGZmZpY7TnDMzMwsdzJNcCQdJWmRpGcl/Usrr4+WtFTSnPTvjCzbY2ZmZrVhs6xmLKkO+CnwGaAZmClpckQsKKl6R0Scl1U7zMzMrPZk2YNzAPBsRCyOiNXA7cDIDOOZmZmZAdkmOAOBJUXTzWlZqS9KekrSXZJ2am1GksZImiVp1tKlS7Noq5mZmeVItU8yvh+oj4i9gYeBX7ZWKSJuiIiGiGgYMGBAjzbQzMzMNj1ZJjgvA8U9MoPSshYRsTwi3k0nbwL2y7A9ZmZmViOyTHBmArtJGiJpc2AUMLm4gqQdiyY/ByzMsD1mZmZWIzK7iioi1ko6D/gtUAdMiIj5kn4AzIqIycDXJX0OWAu8DozOqj1mZmZWOzJLcAAiYiowtaTssqLn3wG+k2UbzMzMrPZU+yRjMzMzs4pzgmNmZma54wTHzMzMcscJjpmZmeWOExwzMzPLHSc4ZmZmljtOcMzMzCx3nOCYmZlZ7jjBMTMzs9xxgmNmZma54wTHzMzMcscJjpmZmeWOExwzMzPLHSc4ZmZmljtOcMzMzCx3nOCYmZlZ7jjBMTMzs9xxgmNmZma54wTHzMzMcscJjpmZmeWOExwzMzPLHSc4ZmZmljtOcMzMzCx3nOCYmZlZ7jjBMTMzs9xxgmNmZma5k2mCI+koSYskPSvpX1p5fQtJd6Svz5BUn2V7zMzMrDZkluBIqgN+ChwNfAw4WdLHSqp9Ffh7RHwUuBa4Oqv2mJmZWe3IsgfnAODZiFgcEauB24GRJXVGAr9Mn98FHCFJGbbJzMzMaoAiIpsZS8cDR0XEGen0KcDwiDivqM7TaZ3mdPq5tM6yknmNAcakk7sDizJpdMe2B5Z1WCtfsWstbjVj11rcasautbjVjF1rcasZu9biFuwcEQNKCzerRks6KyJuAG6odjskzYqIhlqKXWtxqxm71uJWM3atxa1m7FqLW83YtRa3I1keonoZ2KloelBa1modSZsB2wLLM2yTmZmZ1YAsE5yZwG6ShkjaHBgFTC6pMxk4LX1+PPD7yOqYmZmZmdWMzA5RRcRaSecBvwXqgAkRMV/SD4BZETEZ+AVws6RngddJkqCNWTUPk1Urdq3FrWbsWotbzdi1FreasWstbjVj11rcdmV2krGZmZlZtfhOxmZmZpY7TnDMzMwsd5zgtEFSfXqfnqrHlPRJSfMlzZG0ZU+2ybIjqZ+kc6rdjp7UzjZ+gaStqtGmniDp65IWSvpHK3d0zzLuH3oqVlHMVT0d06w1TnA2DV8GroqIYRHxdrUbUy3p8B950g+oqQSnHRcAuU1wSD7nzwB3kgxd0yMi4p96KpbZxsYJTvs2kzQp/eV1l6StJO0v6Q+S5kr6k6S+Gcf8OnAi8K9p+Y6SHkt7c56W9MlKBpd0qqSn0uW7WdKHJN2bTs+VlMkOM/1l/5dW1vcLkq6W9CRwQjfmv7WkKekyPC3pJEk/lrQgXd5/S+udkL4+V9JjadloSfdJapL0P5Iur9Bi/xjYNf0sfyLp25LmpbF/3Mnl+56SgW2nS7pN0sVpe6+VNCtdp/tLuiddhiuL3vv/0m15jqSfFxJJSePS986XdEVR/RckXSHpybS9e3RyuVvbxj8CPCLpkU7OqyytbNe7Snoibf+VWfY6SBoP7AI8T3JbjJ+k63rXrGIWxV6VPma632gjdqOkB4qmx0oaXeEYhf3GREnPpNvVpyU9nm7nB0gaIOnhdDu+SdKLkravYBta27e8IOn/p9vXnyR9tFLxiuJu0Buafue/L+lMSTPT9tytMntGN7F9SHkiwn+t/AH1QAAHp9MTgH8GFgP7p2XbAJtlHPNiYCJwfFr2TeDS9Hkd0LeC8fcCngG2T6e3A+4ALiiKt20Pru+LgReAf67A/L8I3Fg0vTPJkB+FKwn7pY/zgIElZaOBV4H+wJbA00BDhZb56fT50cAfgK0K674T89kfmAP0BvoC/5Ouuybg6rTON4BXgB2BLYDmdHn2BO4HeqX1fgacWtyG9HNvAvZOp18Azk+fnwPcVKHPefuMtq3WtusHgJPT6bOAVVnELmrDCyS3s2/5LvfEX2G5yHC/0U7MRuCBovKxwOgKx6oH1gJDSX6wz063KZGMdfibNO530vpHpdtfxbY13r9v2Tb9vAvr+9Ti9VDhZX+6aPpi4PtA/6KyKwvf1Q7mtcnsQzrz5x6c9i2JiMfT57cARwKvRsRMgIhYGRFrM455SMnrM4HTJX0fGBoRb1Yw9uHAnZGOBRYRr6dl49LpdRGxooLxSrW17HdUYN7zgM8o6Q36JMldtN8BfiHpC8Bbab3HgYmSziT5UhY8HBHLIzlEeA/v/1y669PAf0XEW9Cy7st1MHBfRLyTbg/3F71WuLnmPGB+RLwaEe+SJOo7AUcA+wEzJc1Jp3dJ33Oikp6zP5MkCcWHVu5JH2eT7Gg7o6NtvNJa264PIjlcBHBrxvE3BlnuN6rt+YiYFxHrgfnA7yL5zzmPZNs8hGSwZyLiQeDvFY6/wb6laB95W9HjQRWO2Z6PS5omaR7J6Q17lfGeTW0fUhYnOO0rvUnQyirE3GA6Ih4DPkXyD3qipFN7oE09pa1l/0e3ZxzxDLAvyZf0SuASkhHv7wI+CzyY1jsL+C7JF3e2pP4dtG1j9276uL7oeWF6M5Jfur+M5PyuYRGxe0R8X9IQkl9wR0TE3sAUkl93pfNdR+dvGLqprstNVpX2G2vZ8H9M77YqdlPpdl28zWc+3mLpvkXSZYWXiqtlELqt9TsROC8ihgJX0P31vjHuQ8riBKd9gyUVMu8vAU8AO0raH0BSXyVjaGUZc3rxi5J2Bv4WETcCN5F8sSrl98AJhX/qkrYDfgecnU7XSdq2gvFKtbvs3SHpI8BbEXEL8BOSnf22ETEVuBD4RFpv14iYERGXAUt5bzy1z0jaTslVbJ8n6enprjdJuoMBHib5hb1V2o7tOjGfx4ERknpL6kOSsJXrd8DxknYoxE23sW1IEssVkj5EcgitUlr7nIvXRaW1tl0/QXJoAXr2DupZLmebMt5vtOVF4GOStpDUj+SXfTU8TnIeI5L+L/DBSs68lX1LYd2eVPT4x0rGTP0N2EFSf0lb8N73vi/wqqReJD045djU9iFl2SRGE6+iRcC5kiYAC4DrSXaW16f/6N4mObRQyRMUS2OOIzmmWdAIfEvSmjRuxX6JRTKUxg+BRyWtI+lW/AZwg6SvkmTaZ5PNlxVaX/bzKzTvoSQnd64H1gAXAQ9I6k3yC+SitN5PJO2Wlv0OmAsMA/4E3E0yaOwtETGruw2KiOVKToZ8Gvhvkq7gWZJWA1NJepnKmc9MSZOBp0h2evOAsg4lRsQCSd8FHpL0AZJ1c25EPCHpz8BfgCVUJqEraO1zXg08KOmViDisgrHa2q4vAG6RdClJ712Wh16L3Q7cqOTE6uMj4rkeittIRvuNtkTEEkm/Jjln7XmS9V4NVwC3STqFZN/1V5JEs1JK9y1nk/QMf1DSUyQ9FSdXMB4AEbFGydBHfyLpmftL+tL3gBkkP9BmUEZCvQnuQ8rioRpsoyCpnuREvI9Xuy2llFz50RAR51W7LW2R1CciVqU9QI8BYyLiyWq3a2OVrqe3IyIkjSI54XhktdtllZf2bqyLZHzEg4BxETEs45gvkOwzlmUZp5LyuA9xD45ZPtyg5AZyvUmOh2/SO6YesB8wVpKAN4CvVLc5lqHBwK/T3oXVwJlVbs/GKnf7EPfgmJmZWe74JGMzMzPLHSc4ZmZmljtOcMzMzCx3nOCYmZlZ7jjBsS5RMgjnrZIWS5ot6Y+Sjit6/T8kvZxeuVAoGy1pqZIB2RakwyGUls9XOtBm+tqBkmakry1Ucqv51tozSclAcU9LmpDe5ApJX1YyyOI8JYOkfiLTFWNWYySFpGuKpi8ufE+VDP74st4b5PNzrZT/RcmgjK3+P5L0YUm3S3ou3ddMlfR/emThbJPmBMc6Lb209jfAYxGxS0TsR3I32EHp6x8AjiO5udOhJW+/I70HRSPwo/QOly3lEbEXyaWchbuA/pLkfgzDgI8Dv26jWZOAPUhuurUlcEZa/jxwaHrb8n8FbujaUptZG94FvqC2R+i+Nv3+ngBMKEpkCuUfI/nelu4rCvuae4GmiNg13dd8B/hQaV2zUk5wrCsOB1ZHxPhCQUS8GBHXp5ONJIPejaONO3hGxGvAcySjerdQMvTF1rw3IN4OJCN5Fwb7XNDG/KZGiuTOnoPS8j9ERGFeTxTKzaxi1pL8cLiwvUoRsTCtW5oIbU5y75XWBsE8DFhTsq+ZGxHTutViqwlOcKwr9gLauwnUySQj6N4LHFs4XFRM0i4kI84+mxadpGQk2peB7XhvNNtrgUWS7pX0tXRohTalsU4hHTyzxFdJhkQws8r6KfBltTNWnaThJAM0Lk2LLky/868Cz0TEnFbe9nGS0abNOs0JjnWbpJ9KmitppqTNgWOA30TESpKxUI4sql5IZG4DvhYRr6flhUNXHyYZB+VbABHxA6ABeIhkYMbWEpdiPyM5dLbBLzxJh5EkON/u8oKaWavS7/qvgK+38nIhkfk34KR47+6yhUNUOwBbp0NmmFWMExzrivkUjUYcEeeSjBQ8gCSZ6QfMS8djOYQND1MVzrUZHhH3ls443fndTzLad6HsuYgYl8b4hJLRc3+bnqB4U6GepMvTNlxUPE9Je5OMoDwyIpZ3a8nNrC3/QfIjYuuS8mvT7/wnWzu0FBFrSH64fErSTun3eo6ks0j2Nftl3XDLJyc41hW/B3pLOruobKv08WTgjIioj4h6YAjwmcJVUWU6hOT8HCQdm55oCLAbyYjmb0TEkelO84y03hkkydXJEbG+MCNJg4F7gFMi4pnOLqiZlSftjf01SZJTtvT7fTDwXEQsSb/Xw9Lzbn4PbCFpTFH9vSV9spJtt3xygmOdlvayfB44VNLzkv5EcrXT5cBRwJSiuv8ApgMjOpjtSemvtqeAfUiueILkfJpFaRf3zcCXI2JdK+8fT3JlxR/T+VyWll8G9Ad+lpbP6vQCm1m5ruH9JxG3pXDo6mmgjuTw8gbSfc1xwKfTy8TnA1cBf61Mcy3PPNimmZmZ5Y57cMzMzCx3nOCYmZlZ7jjBMTMzs9xxgmNmZma54wTHzMzMcscJjpmZmeWOExwzMzPLnf8FgEIu5MDrknwAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAfDElEQVR4nO3de5xVdb3/8de7cRAVlFQ8GaiD5kONKNTxdrSa9PjzFpHlBeqoWEpeS81TJ63Ifnbx5zGORzqQGodSvOQtUcjLoxwFS+ISiEB0FC+MWgImSKLcPr8/1trjZpzLZmav2cPa7+fjMY+919rfvT6ftfbaaz573b6KCMzMzMzy5H2VTsDMzMys3FzgmJmZWe64wDEzM7PccYFjZmZmueMCx8zMzHLHBY6ZmZnlTmYFjqQ9JD0maZGkhZK+1kqbBkmrJM1L/76bVT5mZmZWPbbJcNobgK9HxFxJfYE5kh6NiEUt2k2PiE9nmIeZmZlVmcz24ETEqxExN33+JrAYGJBVPDMzM7OCLPfgNJNUBxwIzGzl5SMkzQdeAS6PiIWtvH80MBpghx12OHj//ffPMFszK9WSJUsA2G+//SqciZlVqzlz5qyIiP4txyvrrhok9QEeB34QEfe2eG1HYFNErJF0InB9ROzb3vTq6+tj9uzZ2SVsZiVraGgAoLGxsaJ5mFn1kjQnIupbjs/0KipJtcA9wOSWxQ1ARKyOiDXp82lAraRds8zJzMzM8i/Lq6gE/BxYHBE/aaPNB9J2SDo0zWdlVjmZmZlZdcjyHJwjgTOABZLmpeOuAPYEiIgJwCnA+ZI2AGuBEeHuzc3MzKyLMitwImIGoA7ajAPGdTXW+vXraWpq4u233+7qpKyMevfuzcCBA6mtra10KmZmVmW65SqqrDU1NdG3b1/q6upIj3hZhUUEK1eupKmpiUGDBlU6HTMzqzK56Krh7bffZpdddnFx04NIYpdddvFeNTMzq4hcFDiAi5seyJ+JmZlVSi4OURU7fMzDZZnOU1cd1+Zrq1atYvjw4QDMmzePAw44gG233ZYVK1bQt29fampqiAjOPfdcRo0aBcCgQYPYa6+92LhxI3V1dUyaNImamhoAfvjDH3LTTTexdOnS5qJg0KBBHHPMMdx8880A3HLLLZx55pk8//zz1NXVbZZPe9MuuPrqqxk4cGBzPgWjRo1i/vz57LjjjvTp04fJkyfTr1+/DpfPpEmTaGpq4tvf/naHbc3MzLpbbvbgdKeddtqJxsZGGhsbGTp0KHfddReNjY3suuuu3HXXXcyYMYOpU6cyadIkHnvsMQBqampobGxk+vTp1NbW8sgjjzRP78EHH+Too4/mySefbB5XU1PDSy+9xDvvvAPA3XffzcEHH9xqPu1NuxQ33HADjz/+OEceeSQTJkzY7LWNGzdu0bTMzMx6Ahc4GenXrx9XXnklt91222bjN23axBtvvEHhavg//elPDB48mPPPP59bb711s7YnnHACU6dO5bXXXqO2trbDPSstp/3EE09w4IEHMmzYMGbObK2XjM0ddNBBvPjii0yaNIlTTz2Vz372s1x//fXcdNNNHHbYYRx22GFMnDixuf3MmTMZNmwYBx54INOnTy9lsZiZmXULFzgZ2mOPPXj55ZeBZE9IQ0MDdXV1bNy4keOOSw6BTZ48mbPOOov6+noWLVrE+vXrm98/YsQI7rzzTu68805OO+20NuO0Ne3LLruM+++/nylTpjTvCWrPI488wuDBgwFYs2YN9913H2eccQbjxo1j+vTpTJ8+neuvv57ly5cDyeX5DzzwAPfddx+XXnpp5xaSmZlZBlzgZGjZsmUMGJB0oF44jLRgwQKWL1/OG2+8waZNm7j//vu5+uqrOf7443nttdeYNm1a8/t333131qxZwx133MGwYcOax48bN46GhgbOOeecNqcNsHr1avbcc08kceihhwIwY8YMGhoaaGhoYM2aNQBcfPHFfPKTn2Tt2rXN0zz88MORxNKlSxkyZAi9evWiV69eDBkyhOeffx6AQw45BIC6ujpWrVqV4ZI0MzPbMi5wMrJq1Sp+9KMfMXLkyM3G77TTTpx33nlcc801PPbYYwwfPpyHHnqIhx56iKlTpzJ58uTN2l944YWcfPLJbLfdds3jLrroIhobG5tPQG5t2gB9+/alqakJgFmzZgFw1FFHNZ8/1KdPH+Ddc3DGjx9P7969AZpPUh40aBBPP/0069atY926dSxYsKD5vjZz5swB4KWXXmLHHXfs+kIzMzMrk9xdRVVpp556KjU1NWzatIkvfelLHH300e9pM2LECIYMGcKKFSv4whe+0Dx+n332YfHixaxevbp53IknnsiJJ55YcvzCtK+44gquu+46hg0bxgc/+EH69u3bqfnZbbfd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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "gap_22_prob = df_gap22_ram_prob['simSeconds'].astype(float)\n", + "gap_22_ram = df_gap22_ram['simSeconds'].astype(float)\n", + "geo_meanC = df_gap22_ram_prob['simSeconds'].astype(float)\n", + "geo_meanR = df_gap22_ram['simSeconds'].astype(float)\n", + "gap_22_prob[len(gap_22_prob)] = statistics.geometric_mean(geo_meanC)\n", + "gap_22_ram[len(gap_22_ram)] = statistics.geometric_mean(geo_meanR)\n", + "\n", + "\n", + "gap_25_prob = df_gap25_ram_prob['simSeconds'].astype(float)\n", + "gap_25_ram = df_gap25_ram['simSeconds'].astype(float)\n", + "geo_meanC = df_gap25_ram_prob['simSeconds'].astype(float)\n", + "geo_meanR = df_gap25_ram['simSeconds'].astype(float)\n", + "gap_25_prob[len(gap_25_prob)] = statistics.geometric_mean(geo_meanC)\n", + "gap_25_ram[len(gap_25_ram)] = statistics.geometric_mean(geo_meanR)\n", + "\n", + "npb_C_prob = df_npbC_ram_prob['simSeconds'].astype(float)\n", + "npb_C_ram = df_npbC_ram['simSeconds'].astype(float)\n", + "geo_meanC = df_npbC_ram_prob['simSeconds'].astype(float)\n", + "geo_meanR = df_npbC_ram['simSeconds'].astype(float)\n", + "npb_C_prob[len(npb_C_prob)] = statistics.geometric_mean(geo_meanC)\n", + "npb_C_ram[len(npb_C_ram)] = statistics.geometric_mean(geo_meanR)\n", + "\n", + "\n", + "\n", + "npb_D_prob = df_npbD_ram_prob['simSeconds'].astype(float)\n", + "npb_D_ram = df_npbD_ram['simSeconds'].astype(float)\n", + "geo_mean = df_npbD_ram_prob['simSeconds'].astype(float)\n", + "geo_mean = df_npbD_ram['simSeconds'].astype(float)\n", + "npb_D_prob[len(npb_D_prob)] = statistics.geometric_mean(geo_meanC)\n", + "npb_D_ram[len(npb_D_ram)] = statistics.geometric_mean(geo_meanR)\n", + "\n", + "################################## \n", + "# Multi bar Chart1\n", + "app_gap = df_gap22_ram_prob['app']\n", + "app_gap[len(app_gap)] = \"gmean\"\n", + "\n", + "app_npb = df_npbC_ram_prob['app']\n", + "app_npb[len(app_npb)] = \"gmean\"\n", + "\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,3)\n", + "plt.ylim([0,2.5])\n", + "barWidth = 1\n", + "tickSize = 2\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*tickSize-barWidth/2, gap_22_ram[i]/gap_22_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", + "\n", + "offset = i+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar((offset+i)*tickSize-barWidth/2, npb_C_ram[i]/npb_C_prob[i], width=1, color=cmap(1))\n", + "\n", + "plt.figtext(0.25, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.7, -0.01, \"NPB-C\")\n", + "\n", + "brLab = np.arange(len(app_gap)+len(app_npb))\n", + "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", + "\n", + "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Speedup\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()\n", + "\n", + "###############################################################################\n", + "# Multi bar Chart2\n", + "app_gap = df_gap25_ram_prob['app']\n", + "app_gap[len(app_gap)] = \"gmean\"\n", + "\n", + "app_npb = df_npbD_ram_prob['app']\n", + "app_npb[len(app_npb)] = \"gmean\"\n", + "\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,3)\n", + "plt.ylim([0,2.5])\n", + "barWidth = 1\n", + "tickSize = 2\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*tickSize-barWidth/2, gap_25_ram[i]/gap_25_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", + " \n", + "offset = i+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar((offset+i)*tickSize-barWidth/2, npb_D_ram[i]/npb_D_prob[i], width=1, color=cmap(1))\n", + " \n", + "plt.figtext(0.25, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.70, -0.01, \"NPB-D\")\n", + "\n", + "brLab = np.arange(len(app_gap)+len(app_npb))\n", + "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", + "\n", + "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Speedup\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADoCAYAAADi1J7wAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAkyklEQVR4nO3deZxcVZn/8c+XJqxmEQhMBELCMighrAGioDQgskZwYf8hO4MQVhFF+RlR3FEGQWDYJojRsEgEA8MySCCgLAlbIBGFkAAxQDJDAiiQkDzzxz0VK0139e2qutWV7u/79apX1z11656na7n99LlnUURgZmZm1pOs1N0BmJmZmdWbExwzMzPrcZzgmJmZWY/jBMfMzMx6HCc4ZmZm1uM4wTEzM7MexwmOmZmZ9ThOcMzMzKzHWbmjBySdVemJEfGz+odjZmZmVrsOExygb/q5ObADcFvaHgU8WmRQZmZmZrVQZ0s1SHoA2C8i3krbfYHbI+JTDYjPzMzMrMvy9MFZD1hUtr0olZmZmZk1pUqXqEp+CTwqaULaPhAYW1RAZmZmZrXq9BIVgKTtgE+mzQci4olCozIzMzOrQYcJjqS1Kj0xIv63kIjMzMzMalQpwVkKvAK8XyoqezgiYuOKB5auBfYHXo+ILVPZWsANwBBgFnBwRLwhScDFwL7AP4CjI+LxKn8nMzMz6+UqdTL+OfAGcCdwFLBxRAxNt4rJTTIW2LtN2deBeyNiM+DetA2wD7BZup0IXJ77NzAzMzNro2IfnNSy0gocBuwI3A1cHhEv5jq4NASYWNaC8xzQGhFzJQ0CJkXE5pL+I93/Tdv9qv7NzMzMrNeqOIoqsuznPklPAIcC3wX+ClxVZX3rlSUtr/LP4ebrAy+X7fdKKvtAgiPpRLJWHtZcc83tP/rRj1YZiplV47nnngNg88037+ZIzMxg6tSp8yNiYNvySks1rAkcABwCDARuAbaPiJfqEVBEhKTOh3B98HlXAlcCjBgxIqZMmVKPcMwsp9bWVgAmTZrUrXGYmQFImt1eeaUWnNfJWmvGp58BjJA0AiAibqkijtckDSq7RPV6Kp8DbFi23wapzMzMzKzLKiU4N5ElNZunW7kga9HpqtvIOiz/MP28tax8tKTxwE7AQve/MTMzs2p1mOBExNG1HFjSb8g6KK8j6RVgDFlic6Ok44DZwMFp9zvIhog/TzZM/Jha6jYzM7PeLc9SDctImhgR++fZNyIO6+ChPdrZN4BTuhJLRxYsWMDcuW78aTaDBg1iwIAB3R2GmZn1El1KcMhGNjW1+fPnM2TIEFZfffXuDsWSd955hzlz5jjBMTOzhsmzmni5pl+DavHixay22mrdHYaVWW211Vi8eHF3h2FmZr1IlxKciDi2qEDqKZuf0JqF3w8zM2u0SvPgTCMbLdWuiNiqkIjqaOSYu+pynIfP36vDxxYuXMgBBxwAwJNPPsnHPvYxVl11VebPn0/fvn1paWkhIjjhhBM4+uijARg6dCgbbbQRS5YsYciQIYwdO5aWlhYAvv/973PVVVcxc+bMZYnB0KFD2WOPPbj66qsBuP766/nSl77Eiy++yJAhQ5aLp9KxSy644AI22GCDZfGUHH300Tz11FP069ePD33oQ4wbNy7XZaWxY8fyyiuvcN5553W6r5mZWSNUasHZHxhFthbVncAR6XZHuhnQv39/Jk2axKRJk9hmm2246aabmDRpEuussw433XQTDz74ILfffjtjx47lvvvuA6ClpYVJkyYxefJk+vTpw913373seBMnTmT33XfnoYceWlbW0tLCSy+9xHvvvQfAzTffzPbbb99uPJWOnccll1zC/fffz84778wVV1yx3GNLlizp0rHMzMy6S4cJTkTMjojZwJ4RcU5ETEu3rwOfaVyIK74BAwbwzW9+k1//+tfLlS9dupQFCxZQWg/siSeeYNiwYXz5y1/mV7/61XL77rPPPtx+++28/vrr9OnTp9OWlbbHfuCBB9h2220ZNWoUjzzySKcxb7fddsyePZuxY8dy0EEHceCBB3LxxRdz1VVXsdNOO7HTTjtx7bXXLtv/kUceYdSoUWy77bZMnjw5z8tiZmZWmDx9cCRp57KNT+R8npXZcMMNmTMnm5x5yZIltLa2MmTIEJYsWcJee2WXwMaNG8dRRx3FiBEjmD59+nIdcw899FBuuOEGbrjhBg4++OB266h07LPOOotbb72V2267bVlLUCV33303w4YNA+Dtt99mwoQJHHnkkVx66aVMnjyZyZMnc/HFFzNv3jwg69z9+9//ngkTJnDmmWdW9yKZmZnVSZ5E5TjgMkmzJM0CLgNWiM7GzeTll19m/fWzUfaly0jTpk1j3rx5LFiwgKVLl3LrrbdywQUXsPfee/P6669z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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "gap_22_prob = (df_gap22_ram_prob['foundCandidBSlotRMC'].astype(float)+df_gap22_ram_prob['foundCandidBSlotRMD'].astype(float))\n", + "gap_22 = (df_gap22_ram_prob['numRdMissClean'].astype(float)+df_gap22_ram_prob['numRdMissDirty'].astype(float))\n", + "\n", + "gap_25_prob = (df_gap25_ram_prob['foundCandidBSlotRMC'].astype(float)+df_gap25_ram_prob['foundCandidBSlotRMD'].astype(float))\n", + "gap_25 = (df_gap25_ram_prob['numRdMissClean'].astype(float)+df_gap25_ram_prob['numRdMissDirty'].astype(float))\n", + "\n", + "npb_C_prob = (df_npbC_ram_prob['foundCandidBSlotRMC'].astype(float)+df_npbC_ram_prob['foundCandidBSlotRMD'].astype(float))\n", + "npb_C = (df_npbC_ram_prob['numRdMissClean'].astype(float)+df_npbC_ram_prob['numRdMissDirty'].astype(float))\n", + "\n", + "npb_D_prob = (df_npbD_ram_prob['foundCandidBSlotRMC'].astype(float)+df_npbD_ram_prob['foundCandidBSlotRMD'].astype(float))\n", + "npb_D = (df_npbD_ram_prob['numRdMissClean'].astype(float)+df_npbD_ram_prob['numRdMissDirty'].astype(float))\n", + "\n", + "################################## \n", + "# Multi bar Chart1\n", + "app_gap = df_gap22_ram_prob['app']\n", + "\n", + "app_npb = df_npbC_ram_prob['app']\n", + "\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,3)\n", + "plt.ylim([0,100])\n", + "barWidth = 1\n", + "tickSize = 2\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*tickSize-barWidth/2, 100*gap_22_prob[i]/gap_22[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", + "\n", + "offset = i+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar((offset+i)*tickSize-barWidth/2, 100*npb_C_prob[i]/npb_C[i], width=1, color=cmap(1))\n", + "\n", + "plt.figtext(0.25, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.7, -0.01, \"NPB-C\")\n", + "\n", + "brLab = np.arange(len(app_gap)+len(app_npb))\n", + "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", + "\n", + "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", + "\n", + "plt.ylabel(\"Percentage of probed Rd-MC and Rd-Md\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()\n", + "\n", + "###############################################################################\n", + "# Multi bar Chart2\n", + "app_gap = df_gap25_ram_prob['app']\n", + "\n", + "app_npb = df_npbD_ram_prob['app']\n", + "\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,3)\n", + "plt.ylim([0,100])\n", + "barWidth = 1\n", + "tickSize = 2\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*tickSize-barWidth/2, 100*gap_25_prob[i]/gap_25[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", + " \n", + "offset = i+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar((offset+i)*tickSize-barWidth/2, 100*npb_D_prob[i]/npb_D[i], width=1, color=cmap(1))\n", + " \n", + "plt.figtext(0.25, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.70, -0.01, \"NPB-D\")\n", + "\n", + "brLab = np.arange(len(app_gap)+len(app_npb))\n", + "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", + "\n", + "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", + "\n", + "plt.ylabel(\"Percentage of probed Rd-MC and Rd-Md\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAh3UlEQVR4nO3deZxcVZ338c+XJmHNYiDwRCAkREYFIluAIKgN6LBNDDiE9WFRkUF2EXceI5pBHRcGQcMrLBPEKAEkgoRhGUxDAAkkbAEiiglLYiTJaBKiQLbf88c9HSptd6VSVbequvr7fr3qVXVP3b7n17Xc/vU5556jiMDMzMysmWxS7wDMzMzMqs0JjpmZmTUdJzhmZmbWdJzgmJmZWdNxgmNmZmZNxwmOmZmZNZ3cEhxJN0haJOm5grIBku6X9Id0/65ULkk/kvSSpGcl7ZNXXGZmZtb88mzBmQgc0aHsy8ADEbEr8EDaBjgS2DXdzgLG5xiXmZmZNbncEpyIeAj4S4fi0cCN6fGNwDEF5T+NzGNAf0mD8orNzMzMmtumNa5v+4hYmB7/Gdg+Pd4BeK1gv/mpbCEdSDqLrJWHrbbaat/3ve99+UVrZv/gxRdfBOC9731vnSMxM4NZs2YtiYiBHctrneCsExEhaaPXiYiICcAEgBEjRsTMmTOrHpuZda21tRWAtra2usZhZgYg6ZXOymt9FdXr7V1P6X5RKl8A7FSw346pzMzMzGyj1TrBuRM4PT0+HbijoPy0dDXVSGBZQVeWmZmZ2UbJrYtK0i+AVmBbSfOBscB3gFskfRp4BTg+7X43cBTwEvB34JN5xWVmZmbNL7cEJyJO6uKpwzrZN4Bzq1Hv0qVLWbjQjT+NZtCgQfTv37/eYZiZWQ9Rt0HGeVmyZAlDhgxhiy22qHcolrz55pssWLDACY6ZmdVM0y3VsGrVKjbffPN6h2EFNt98c1atWlXvMMzMrAdpugQHQFK9Q7ACfj/MzKzWmq6LqtDIsfdW5TiPXXZ4l88tW7aM0aNHA/D000/z/ve/n80224wlS5bQp08fWlpaiAg+85nPcMYZZwAwdOhQdt55Z9asWcOQIUOYOHEiLS0tAFx++eVce+21zJ07d11iMHToUA477DCuu+46AG666SZOO+005s2bx5AhQ9aLp9ix240bN44dd9xxXTztzjjjDJ555hn69u3L1ltvzaRJk0rqVpo4cSLz58/n0ksv3eC+ZmZmtdCULTi11K9fP9ra2mhra2Ovvfbi1ltvpa2tjW233ZZbb72Vhx9+mKlTpzJx4kSmTZsGQEtLC21tbUyfPp1evXpx3333rTveXXfdxaGHHsojjzyyrqylpYVXX32Vt99+G4DbbruNfffdt9N4ih27FFdddRUPPvggBx10ENdcc816z61Zs2ajjmVmZlYvTnBqoH///nzta1/j5z//+Xrla9euZenSpWQXkcFTTz3F7rvvzmc/+1l+9rOfrbfvkUceydSpU1m0aBG9evXaYMtKx2M/9NBD7L333owaNYoZM2ZsMOZ99tmHV155hYkTJzJmzBiOOeYYrrzySq699loOOOAADjjgAG644YZ1+8+YMYNRo0ax9957M3369FJeFjMzs9w4wamRnXbaiQULssmZ16xZQ2trK0OGDGHNmjUcfnjWBTZp0iROP/10RowYwQsvvLDewNwTTzyRyZMnM3nyZI4//vhO6yh27Isvvpg77riDO++8c11LUDH33Xcfu+++OwArVqxgypQpnHrqqVx99dVMnz6d6dOnc+WVV7J48WIgG9z961//milTpvC5z32uvBfJzMysSpzg1Mhrr73GDjvsALzTjTR79mwWL17M0qVLWbt2LXfccQfjxo3jiCOOYNGiRdx9993rfn7QoEGsWLGCm2++mVGjRq0rv/rqq2ltbeXMM8/s8tgAy5cvZ/DgwUhi//33B+Dhhx+mtbWV1tZWVqxYAcD555/PRz7yEd588811xxw5ciSSmDt3LsOHD6d379707t2b4cOHM2/ePAD2228/AIYMGcKyZctyfCXNzMw2zAlODSxbtoxvf/vbnHTS+nMf9uvXj7PPPpvvfve7TJs2jdGjR3PPPfdwzz33MHXqVCZNmrTe/ueeey7HHnvsenP8nHfeebS1ta0bgNzZsQH69OnD/PnzAXjiiScAOPjgg9eNH9p6662Bd8bgjB8/ft3l9u2DlIcOHcqzzz7LypUrWblyJbNnz2bo0KEAzJo1C4BXX32Vvn37Vv6imZmZVaCpr6KqtzFjxtDS0sLatWv51Kc+xaGHHvoP+5x44okMHz6cJUuWcPLJJ68rHzZsGHPmzGH58uXryo466iiOOuqokutvP/ZXv/pVfvCDHzBq1Cje/e5306dPn7J+n+22245zzjmHgw8+GMiSq4EDsxXqt9xyS44++mj+9Kc/ccUVV5R1fDMzs2pR+yDU7mjEiBExc+bM9crmzJnD+9///jpFZF3x+9I8WltbAWhra6trHGZmAJJmRcSIjuXuojIzM7Om02WCI+nitOp3x/JPS7oo16jMzMzMKlCsBecU4KedlN8EfCqfcKqjO3e7NSO/H2ZmVmvFEpxNI+IfVkiMiJVAwy4u1KtXL9566616h2EF3nrrLXr16lXvMMzMrAcpdhXVJpK2j4jXCwslbZ9zTBXZdtttefnll+sdhnUwaNCgeodgZmY9SLEE53vAVEmfB55MZfum8u/nHVi5+vfvX9ICkWZmZta8ukxwIuKnkhYD3wT2SMXPAV+PiP+uRXBmZmZm5Sg60V9KZJzMmJmZWbfSZYIj6UfFfjAiLqh+OGZmZmaVK9aCczZZl9QtwJ9o4CunzMysexo59t6Kj/HYZYdXIRJrNsUSnEHAGOAEYDUwGbgtIpbWIC4zMzOzsnU5D05E/G9EXBMRhwCfBPoDL0g6tVbBmZmZmZVjg6uJS9oHOAn4GNmA41l5B2VmZmZWiWKDjL8JHA3MAW4GvhIRq2sVmJmZmVm5irXgXArMA/ZMt8slQTbYOCLiA/mHZ2ZmZrbxiiU4Q/OqVNLngDOBAGaTjfEZRNZStA1ZN9ipad0rMzMzs41SbJDxKx1vwPCCx2WRtANwATAiIvYAWoATge8CV0TEe4C/Ap8utw4zMzPr2YqtJt6Zb1ap3k2BLSRtCmwJLAQOBW5Lz98IHFOluszMzKyH2dgEp+LJ/iJiAdlina+SJTbLyLqklhYMYp4P7NBpANJZkmZKmrl48eJKwzEzM7MmtLEJzr9VWqGkdwGjycb4vBvYCjii1J+PiAkRMSIiRgwcOLDScMzMzKwJFbtM/BNdlO8IEBG3l1nnR4F5EbE4He924CCgv6RNUyvOjsCCMo9vZmZmPVyxq6hGpfvtgA8Cv0nbhwCPAuUmOK8CIyVtCbwJHAbMBKYBx5FdSXU6cEeZxzczM7MerssEJyI+CSDpPmC3iFiYtgcBE8utMCJmSLoNeJJsjaungAnAVOBmSeNS2fXl1mFmZmY92waXagB2ak9ukteBwZVUGhFjgbEdiucC+1dyXDMzMzMoLcF5QNK9wC/S9gnA/+QXkpmZmVllNpjgRMR5ko4FPpyKJkTElHzDMjMzq62RY++t+BiPXXZ4FSKxaiilBYeU0EwBkLSJpFMiYlKukZkVUY0TEfhkZGbWrLqcB0dSX0lfkXS1pH9W5jyysTLH1y5EMzMzs41TrAXnJrI1oX5LtjDmV8lmMj4mIp7OPzQzMzOrp+7cbVcswdklIoYDSLqObFmFwRHxVk0iMzMzMytTsaUaVrU/iIg1wHwnN2ZmZtYdFGvB2VPS8vRYZKt/L0+PIyL65h6dmZmZWRmKzWTcUstAzMzMzKplY1cTNzMzM2t4TnDMzMys6TjBMTMzs6bjBMfMzMyaTpeDjCW9AURXz/sqKjMzM2tUxa6i6gMg6Vtkk/zdRHaJ+CnAoJpEZ2ZmZlaGUrqoPh4RP4mINyJieUSMB0bnHZiZmZlZuUpJcP4m6RRJLe0riQN/yzswMzMzs3KVkuCcTLZ6+OvpNiaVmZmZmTWkYks1ABARL+MuKTMzM+tGNtiCI+mfJD0g6bm0/QFJl+YfmpmZmVl5Sumiuhb4Cml18Yh4Fjgxz6DMzMzMKlFKgrNlRDzeoWx1HsGYmZmZVUMpCc4SScNIk/5JOo5sXhwzMzOzhrTBQcbAucAE4H2SFgDzyCb7MzMzM2tIpVxFNRf4qKStgE0i4o38wzIzMzMrXylXUW0j6UfAdKBN0pWStsk/NDMzM7PylDIG52ZgMfCvwHHp8eRKKpXUX9Jtkn4naY6kAyUNkHS/pD+k+3dVUoeZmZn1XKUkOIMi4lsRMS/dxgHbV1jvlcA9EfE+YE9gDvBl4IGI2BV4IG2bmZmZbbRSEpz7JJ2Y1qHaRNLxwL3lViipH/Bh4HqAiFgZEUvJZku+Me12I3BMuXWYmZlZz9blIGNJb5BdGi7gIuBn6alNgBXAJWXWOZSsm+u/JO0JzAIuBLaPiPbLz/9MF61Eks4CzgIYPHhwmSGYmZlZM+sywYmIPjnWuQ9wfkTMkHQlHbqjIiIkRRdxTSC7bJ0RI0Z0uo+ZmVl3NXJs2Z0k63nsssOrcpzuqpR5cJD0cbJuJYC2iLirgjrnA/MjYkbavo0swXld0qCIWChpELCogjoq5g+YmZlZ91XKZeLfIetCeiHdLpT07XIrjIg/A69Jem8qOiwd907g9FR2OnBHuXWYmZlZz1ZKC85RwF4RsRZA0o3AU2QLcJbrfGCSpN7AXOCTZMnWLZI+DbwCHF/B8c3MzKwHK6mLCugP/CU97ldppRHxNDCik6cOq/TYZmaFqtHd7K5ms+6nlATncuApSdPIrqj6MJ6jxszMzBpY0QRH0ibAWmAksF8q/lIaR2NmZmbWkIomOBGxVtIXI+IWskHAZmZmZg2vlJmM/0fSJZJ2SutFDZA0IPfIzMzMzMpUyhicE9L9uQVlAexS/XDMzMzMKrfBBCcihtYiEDMzM7Nq2WCCI2lz4BzgYLKWm+nANRHxVs6xmZmZmZWllC6qnwJvAFel7ZOBm4AxeQVlZmZmVolSEpw9ImK3gu1pkl7IKyAzMzOzSpVyFdWTkka2b0g6AJiZX0hmZmZmlSmlBWdf4FFJr6btwcCLkmYDEREfyC06MzMzszKUkuAckXsUZmZmZlVUymXir9QiEDMzM7NqKWUMjpmZmVm30mWCI2mzWgZiZmZmVi3FWnB+CyDpphrFYmZmZlYVxcbg9JZ0MvBBSZ/o+GRE3J5fWGZmZmblK5bgnA2cAvQHRnV4LgAnOGbAyLH3VnyMxy47vAqRmJlZuy4TnIh4GHhY0syIuL6GMZmZmZlVpJR5cG6SdAHw4bT9INlim6vyC8vMzMysfKUkOD8BeqV7gFOB8cCZeQVlZmZmVolSEpz9ImLPgu3fSHomr4DsH3mMh5mZ2cYpZaK/NZKGtW9I2gVYk19IZmZmZpUppQXnC8A0SXMBATsDn8w1KjMri1v7zMwypaxF9YCkXYH3pqIXI+LtfMMyMzMzK19Ja1FFxNsR8Wy6VSW5kdQi6SlJd6XtoZJmSHpJ0mRJvatRj5mZmfU89Vxs80JgTsH2d4ErIuI9wF+BT9clKjMzM+v26pLgSNoROBq4Lm0LOBS4Le1yI3BMPWIzMzOz7m+DCY4y/1fS19P2YEn7V1jvfwJfBNam7W2ApRGxOm3PB3boIp6zJM2UNHPx4sUVhmFmZmbNqJQWnJ8ABwInpe03gB+XW6GkfwEWRcSscn4+IiZExIiIGDFw4MBywzAzM7MmVspl4gdExD6SngKIiL9WOAD4IODjko4CNgf6AlcC/SVtmlpxdgQWVFCHmZmZ9WCltOCsktRCtoI4kgbyTtfSRouIr0TEjhExBDgR+E1EnAJMA45Lu50O3FFuHWZmZtazlZLg/AiYAmwn6d+Bh4HLc4jlS8DFkl4iG5PjFczNzMysLKVM9DdJ0izgMLKZjI+JiDkb+LGSREQb0JYezwUqHbxsZmYbUI0Zr8GzXltj22CCI2kAsAj4RUFZr4hYlWdgZmZmZuUqpYvqSWAx8HvgD+nxy5KelLRvnsGZmZmZlaOUBOd+4KiI2DYitgGOBO4CziG7hNzMzMysoZSS4IyMiHUdthFxH3BgRDwGbJZbZGZmZmZlKmUenIWSvgTcnLZPAF5Pl46Xfbm4mZmZWV5KSXBOBsYCv0rbj6SyFuD4fMIyM2s+1bh6yVcumZWmlMvElwDnd/H0S9UNx8zMzKxypVwmPpBsYczdyZZWACAiDs0xLjMzM7OylTLIeBLwO2AocBnwMvBEjjGZmZmZVaSUBGebiLgeWBURD0bEpwC33piZmVnDKmWQcfuMxQslHQ38CRiQX0hmZmZmlSklwRknqR/weeAqoC9wUZ5BmZmZmVWilATnrxGxDFgGHAIg6aBco7KG5ctczcysOyhlDM5VJZaZmZmZNYQuW3AkHQh8EBgo6eKCp/qSTfJnZmZm1pCKdVH1BrZO+/QpKF8OHJdnUGZmZmaV6DLBiYgHgQclTYyIV2oYk5mZmVlFShlkvJmkCcCQwv09k7GZmZk1qlISnFuBa4DrgDX5hmNmZmZWuVISnNURMT73SMysaVRjOgHwlAJmVr5SLhP/taRzJA2SNKD9lntkZmZmZmUqpQXn9HT/hYKyAHapfjhmZmZmldtgghMRQ2sRiJmZmVm1bLCLStKWki5NV1IhaVdJ/5J/aGZmZmblKWUMzn8BK8lmNQZYAIzLLSIzMzOzCpWS4AyLiP8AVgFExN8B5RqVmZmZWQVKSXBWStqCbGAxkoYBb5dboaSdJE2T9IKk5yVdmMoHSLpf0h/S/bvKrcPMzMx6tlISnLHAPcBOkiYBDwBfrKDO1cDnI2I3YCRwrqTdgC8DD0TErqmOL1dQh5mZmfVgpVxFdb+kJ8mSEQEXRsSSciuMiIXAwvT4DUlzgB2A0UBr2u1GoA34Urn1mJmZWc9VylVUx5LNZjw1Iu4CVks6phqVSxoC7A3MALZPyQ/An4Htu/iZsyTNlDRz8eLF1QjDzMzMmkxJXVQRsax9IyKWknVbVUTS1sAvgYsiYnnhcxERpDE/HUXEhIgYEREjBg4cWGkYZmZm1oRKSXA626eUGZC7JKkXWXIzKSJuT8WvSxqUnh8ELKqkDjMzM+u5SklwZkr6oaRh6fZDYFa5FUoScD0wJyJ+WPDUnbyzLMTpwB3l1mFmZmY9WykJzvlkE/1NBm4G3gLOraDOg4BTgUMlPZ1uRwHfAT4m6Q/AR9O2mZmZ2UYr2tUkqQW4KyIOqVaFEfEwXU8UeFi16jEzM7Oeq2gLTkSsAdZK6lejeMzMzMwqVspg4RXAbEn3A39rL4yIC3KLyszMzKwCpSQ4t6ebmZmZWbdQykzGN6a1qAZHxIs1iMnMzMysIqXMZDwKeJpsPSok7SXpzpzjMjMzMytbKZeJfwPYH1gKEBFPA7vkFpGZmZlZhUpJcFYVLtWQrM0jGDMzM7NqKGWQ8fOSTgZaJO0KXAA8mm9YZmZmZuUrdSbj3YG3gZ8Dy4CLcozJzMzMrCJdtuBI2hw4G3gPMBs4MCJW1yowMzMzs3IVa8G5ERhBltwcCXy/JhGZmZmZVajYGJzdImI4gKTrgcdrE5KZmZlZZYq14Kxqf+CuKTMzM+tOirXg7ClpeXosYIu0LSAiom/u0ZmZmZmVocsEJyJaahmImZmZWbWUcpm4mZmZWbfiBMfMzMyajhMcMzMzazpOcMzMzKzpOMExMzOzpuMEx8zMzJqOExwzMzNrOk5wzMzMrOk4wTEzM7Om4wTHzMzMmo4THDMzM2s6DZXgSDpC0ouSXpL05XrHY2ZmZt1TwyQ4klqAHwNHArsBJ0narb5RmZmZWXfUMAkOsD/wUkTMjYiVwM3A6DrHZGZmZt2QIqLeMQAg6TjgiIg4M22fChwQEed12O8s4Ky0+V7gxZoGur5tgSV1rL9Qo8TSKHGAY+lMo8QBjqUzjRIHOJbONEoc4FgK7RwRAzsWblqPSCoREROACfWOA0DSzIgYUe84oHFiaZQ4wLE0chzgWBo5DnAsjRwHOJZSNFIX1QJgp4LtHVOZmZmZ2UZppATnCWBXSUMl9QZOBO6sc0xmZmbWDTVMF1VErJZ0HnAv0ALcEBHP1zmsDWmIrrKkUWJplDjAsXSmUeIAx9KZRokDHEtnGiUOcCwb1DCDjM3MzMyqpZG6qMzMzMyqwgmOmZmZNR0nOCWSNETSc40Yg6QPSXpe0tOStqhHbNaYJPWXdE6944Cin9+LJG1Zj5gahaQLJM2R9Ld6zuAu6dF61V1I0op6x2DdnxOc5nAK8O2I2Csi3qx3MI0sLQnSk/QHGiLBKeIioEcnOGTv0ceAW8mWqqmLiPhgveo2qzYnOBtnU0mT0n9at0naUtJ+kh6V9IykxyX1qXEMFwDHA99K5YMkPZRac56T9KE8g5F0mqRn0+9/k6TtJU1J289IqtkJM7UQ/K6T9+hlSd+V9CQwpor1bSVpavo9n5N0gqTvSHohvSbfT/uNSc8/I+mhVHaGpDsktUn6g6Sx1Yqrg+8Aw9Ln4XuSviRpdorlOznVWUxnn993A9MkTatFAJ18ZodJeiy9LuNq3Xog6RpgF2AecDrwvfR+DatlHCmWFem+pueRIvG0SrqrYPtqSWfkXGf7eWSipN+nz+tHJT2Svqv7Sxoo6f7Ucn6dpFckbZtjTJ2da16W9B/pc/u4pPfkVX9BHOu1wkq6RNI3JH1G0hMpvl+qUVpkI8K3Em7AECCAg9L2DcAXgbnAfqmsL7BpjWO4BJgIHJfKPg98LT1uAfrkGM/uwO+BbdP2AGAycFFB/f3q/B5dArwMfDGH+v4VuLZge2eypUPar07sn+5nAzt0KDsDWAhsA2wBPAeMyOk1eS49PhJ4FNiy/f2q1XtTwvuzbY1i6OwzexdwUto+G1hRy9cl1fsy2XT3677L9bi1/+61PI9sII5W4K6C8quBM3KuewiwGhhO1ggwK31WRbY+4q9SHF9J+x+RPte5fYY7Odf0S5+Z9vfotMLXKefX5rmC7UuAbwDbFJSNA86v5eelq5tbcDbOaxHxSHr8M+BwYGFEPAEQEcsjYnWNYzi4w/NPAJ+U9A1geES8kWMshwK3RsQSgIj4Syobn7bXRMSyHOvvTFevz+Qc6poNfCy1Dn2IbObtt4DrJX0C+Hva7xFgoqTPkP2xaHd/RPxvZN2Kt/OP72W1fRT4r4j4O6x7v2ptQ5/fvHX2mT2QrGsI4Oc1jqdR1fI80ojmRcTsiFgLPA88ENlf79lkf+QPJlsQmoi4B/hrzvGsd64pOK/+ouD+wJxjKGYPSdMlzSYbMrF7HWNZxwnOxuk4adDyBohhve2IeAj4MNkf24mSTqtVYA2iq9fnb1WvKOL3wD5kJ59xwFeB/YHbgH8B7kn7nQ1cSrYUySxJ22wg1mbWE3/nbqeBziOrWf/v1OY1qvftgsdrC7bXUocJcjueayR9vf2pwt1qEEpX78dE4LyIGA5cRu3ep6Kc4GycwZLas+STgceAQZL2A5DUR1LeH/6OMTxc+KSknYHXI+Ja4DqyL0VefgOMaf+DLWkA8ADw2bTdIqlfjvV3pujrU02S3g38PSJ+BnyP7A9Cv4i4G/gcsGfab1hEzIiIrwOLeWfNtY9JGqDsyrdjyFp6qu0NoH1c2P1k/5VvmeIakEN9G9LZ+1MYY946+8w+RtYFANkSMfVUy9eiSzU+jxTzCrCbpM0k9QcOq1McHT1CNvYRSf8MvCvPyjo517S/HycU3P82zxiS14HtJG0jaTOyf+Qg+8wulNSLrAWnITjB2TgvAudKmkP2gb6K7IN1laRnyP6A5J25doxhfIfnW4FnJD2VYrsyr0AiW0rj34EH0+//Q+BC4JDUVDmL2l8RsqHXp5qGA49LehoYS/afy12SniX7w31x2u97aSDgc2RjYJ5J5Y8DvwSeBX4ZETOrHWBE/C/wSKr7MLL13WammC+pdn0l6Oz9mQDcU4tBxl18Zi8CLk7v23uAWnerFroZ+IKkp+oxyLhAKzU6jxQTEa8Bt5CNUbsFeKoecXTiMuCf0/dqDPBnsuQ0Lx3PNeNS+bvS5/ZCsn+qchURq4Bvkp277gd+l576f8AMssTvd53/dO15qQZrGpKGkA2026PesWxIuhJkREScV+9YerrUovVmRISkE8kGHI+ud1zWuFLrxZrI1lA8EBgfEXvVOIaXyc4hS2pZb3fSMIttmpnVyb7A1ZIELAU+Vd9wrBsYDNwiaRNgJfCZOsdjnXALjpmZmTUdj8ExMzOzpuMEx8zMzJqOExwzMzNrOk5wzMzMrOk4wbGyKFtU8+eS5kqaJem3ko4teP4/JS1IVxm0l50habGyBfxeSEsXdCx/XmmRzPTcSEkz0nNz0tTxncUzSdKLyhaiuyFNOIWkU5QtrDhb2aKoe+b6wpj1MJJC0g8Kti9p/54qW4hxgd5ZtPPjnZT/TtL4wnNFh+P/H0k3S/pjOtfcLemfavLLWbfmBMc2Wrqc9lfAQxGxS0TsSzYD7I7p+U2AY4HXgI90+PHJab6IVuBySdsXlkfE7mSXXbbP0HkjcFb6mT3IJvvqzCTgfWQTYm0BnJnK5wEfSVOIf4tsUjkzq563gU+o69W0r0jf3zHADQWJTHv5bmTf247nivZzzRSgLSKGpXPNV4DtO+5r1pETHCvHocDKiLimvSAiXomIq9JmK9kCdeOBkzo7QEQsAv5ItgL3OsqWutiKdxav245s1e32xTtf6OJ4d0dCNsvmjqn80YhoP9Zj7eVmVjWryf5xKDqTbkTMSft2TIR6k80A39mClYcAqzqca56JiOkVRWw9ghMcK8fuwJNFnj+JbHXbKcDR7d1FhSTtAuwCvJSKTkjTkC8ABgC/TuVXAC9KmiLp3yQVXQoj1XUqaaHLDj4N/HexnzezsvwYOEVF1p6TdADZYpWLU9Hn0nd+IfD7iHi6kx/bg2zJF7ON5gTHKibpx5KekfSEpN7AUcCvImI52fokhxfs3p7I/AL4t4j4Sypv77r6P2Qr5n4BICK+CYwA7iNbnLGzxKXQT8i6ztb7D0/SIWQJzpfK/kXNrFPpu/5T4IJOnm5PZL4PnBDvzC7b3kW1HbBVWibDrGqc4Fg5nqdgdeGIOJdsIceBZMlMf2B2WivlYNbvpmofa3NAREzpeOB08vs12crc7WV/jIjxqY49la1ke28aoHhd+36SxqYYLi48pqQPkK2IPDotPmlm1fefZP9EbNWh/Ir0nf9QZ11LaQHHe4APS9opfa+flnQ22blm37wDt+bkBMfK8Rtgc0mfLSjbMt2fBJwZEUMiYggwFPhY+1VRJTqYbHwOko5OAw0BdgXWAEsj4vB00jwz7XcmWXJ1UkSsbT+QpMHA7cCpEfH7jf1Fzaw0qTX2FrIkp2Tp+30Q8MeIeC19r/dK425+A2wm6ayC/T8g6UPVjN2akxMc22ipleUY4COS5kl6nOxqp7HAEcDUgn3/BjwMjNrAYU9I/7U9C+xNdsUTZONpXkxN3DcBp0TEmk5+/hqyKyt+m47z9VT+dWAb4CepfOZG/8JmVqof8I+DiLvS3nX1HNBC1r28nnSuORb4aLpM/Hng28CfqxOuNTMvtmlmZmZNxy04ZmZm1nSc4JiZmVnTcYJjZmZmTccJjpmZmTUdJzhmZmbWdJzgmJmZWdNxgmNmZmZN5/8DgXSrJVIjS2sAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAh30lEQVR4nO3deZhcVZ3/8feHJmHNYiAwkRASkJ8KRrYAQVBbkGEzAg6BAMOiIiI7iDs/I04GdVwYBA1PWCaIUQJIBAnDMpiGgBJJ2AJElAkEEiNJ1CQEgWzf+eOeDpW2u7pSVbeqUv15PU89VffUrXu+XVV9+9vnnHuOIgIzMzOzZrJJvQMwMzMzqzYnOGZmZtZ0nOCYmZlZ03GCY2ZmZk3HCY6ZmZk1HSc4ZmZm1nRyS3Ak3SBpkaRnCsoGSLpf0h/T/TtSuST9UNILkp6WtHdecZmZmVnzy7MFZyJweIeyLwMPRMSuwANpG+AIYNd0OxMYn2NcZmZm1uRyS3Ai4iHgrx2KjwZuTI9vBI4pKP9JZB4F+ksalFdsZmZm1tw2rXF920fEwvT4z8D26fEOwCsF+81PZQvpQNKZZK08bLXVVvu85z3vyS9aM/sHzz//PADvfve76xyJmRnMmjVrSUQM7Fhe6wRnnYgISRu8TkRETAAmAIwYMSJmzpxZ9djMrGutra0AtLW11TUOMzMASfM6K6/1VVSvtnc9pftFqXwBsGPBfoNTmZmZmdkGq3WCcydwWnp8GnBHQfmp6WqqkcCygq4sMzMzsw2SWxeVpJ8DrcC2kuYDY4FvA7dI+jQwDzg+7X43cCTwAvB34JN5xWVmZmbNL7cEJyJO7OKpQzrZN4BzqlHv0qVLWbjQjT+NZtCgQfTv37/eYZiZWQ9Rt0HGeVmyZAlDhw5liy22qHcolrzxxhssWLDACY6ZmdVM0y3VsGrVKjbffPN6h2EFNt98c1atWlXvMMzMrAdpugQHQFK9Q7AC/jzMzKzWmq6LqtDIsfdW5TiPXnZYl88tW7aMo48+GoAnn3yS9773vWy22WYsWbKEPn360NLSQkTwmc98htNPPx2AYcOGsdNOO7FmzRqGDh3KxIkTaWlpAeDyyy/n2muvZe7cuesSg2HDhnHIIYdw3XXXAXDTTTdx6qmn8uKLLzJ06ND14il27Hbjxo1j8ODB6+Jpd/rpp/PUU0/Rt29ftt56ayZNmlRSt9LEiROZP38+l156abf7mpmZ1UJTtuDUUr9+/Whra6OtrY0999yTW2+9lba2NrbddltuvfVWHn74YaZOncrEiROZNm0aAC0tLbS1tTF9+nR69erFfffdt+54d911FwcffDCPPPLIurKWlhZefvll3nrrLQBuu+029tlnn07jKXbsUlx11VU8+OCDHHjggVxzzTXrPbdmzZoNOpaZmVm9OMGpgf79+/O1r32Nn/3sZ+uVr127lqVLl5JdRAZPPPEEu+++O5/73Of46U9/ut6+RxxxBFOnTmXRokX06tWr25aVjsd+6KGH2GuvvRg1ahQzZszoNua9996befPmMXHiREaPHs0xxxzDlVdeybXXXsv+++/P/vvvzw033LBu/xkzZjBq1Cj22msvpk+fXsrbYmZmlhsnODWy4447smBBNjnzmjVraG1tZejQoaxZs4bDDsu6wCZNmsRpp53GiBEjeO6559YbmDtmzBgmT57M5MmTOf744zuto9ixL774Yu644w7uvPPOdS1Bxdx3333svvvuAKxYsYIpU6ZwyimncPXVVzN9+nSmT5/OlVdeyeLFi4FscPevfvUrpkyZwkUXXVTem2RmZlYlTnBq5JVXXmGHHXYA3u5Gmj17NosXL2bp0qWsXbuWO+64g3HjxnH44YezaNEi7r777nWvHzRoECtWrODmm29m1KhR68qvvvpqWltbOeOMM7o8NsDy5csZMmQIkthvv/0AePjhh2ltbaW1tZUVK1YAcN555/HhD3+YN954Y90xR44ciSTmzp3L8OHD6d27N71792b48OG8+OKLAOy7774ADB06lGXLluX4TpqZmXXPCU4NLFu2jG9961uceOL6cx/269ePs846i+985ztMmzaNo48+mnvuuYd77rmHqVOnMmnSpPX2P+ecczj22GPXm+Pn3HPPpa2tbd0A5M6ODdCnTx/mz58PwGOPPQbAQQcdtG780NZbbw28PQZn/Pjx6y63bx+kPGzYMJ5++mlWrlzJypUrmT17NsOGDQNg1qxZALz88sv07du38jfNzMysAk19FVW9jR49mpaWFtauXcunPvUpDj744H/YZ8yYMQwfPpwlS5Zw0kknrSvfZZddmDNnDsuXL19XduSRR3LkkUeWXH/7sb/61a/y/e9/n1GjRvHOd76TPn36lPXzbLfddpx99tkc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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "gap_22_prob = (df_gap22_ram_prob['foundCandidBSlotRMC'].astype(float))\n", + "gap_22 = (df_gap22_ram_prob['numRdMissClean'].astype(float))\n", + "\n", + "gap_25_prob = (df_gap25_ram_prob['foundCandidBSlotRMC'].astype(float))\n", + "gap_25 = (df_gap25_ram_prob['numRdMissClean'].astype(float))\n", + "\n", + "npb_C_prob = (df_npbC_ram_prob['foundCandidBSlotRMC'].astype(float))\n", + "npb_C = (df_npbC_ram_prob['numRdMissClean'].astype(float))\n", + "\n", + "npb_D_prob = (df_npbD_ram_prob['foundCandidBSlotRMC'].astype(float))\n", + "npb_D = (df_npbD_ram_prob['numRdMissClean'].astype(float))\n", + "\n", + "################################## \n", + "# Multi bar Chart1\n", + "app_gap = df_gap22_ram_prob['app']\n", + "\n", + "app_npb = df_npbC_ram_prob['app']\n", + "\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,3)\n", + "plt.ylim([0,100])\n", + "barWidth = 1\n", + "tickSize = 2\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*tickSize-barWidth/2, 100*gap_22_prob[i]/gap_22[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", + "\n", + "offset = i+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar((offset+i)*tickSize-barWidth/2, 100*npb_C_prob[i]/npb_C[i], width=1, color=cmap(1))\n", + "\n", + "plt.figtext(0.25, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.7, -0.01, \"NPB-C\")\n", + "\n", + "brLab = np.arange(len(app_gap)+len(app_npb))\n", + "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", + "\n", + "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", + "\n", + "plt.ylabel(\"Percentage of probed Rd-MC\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()\n", + "\n", + "###############################################################################\n", + "# Multi bar Chart2\n", + "app_gap = df_gap25_ram_prob['app']\n", + "\n", + "app_npb = df_npbD_ram_prob['app']\n", + "\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,3)\n", + "plt.ylim([0,100])\n", + "barWidth = 1\n", + "tickSize = 2\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*tickSize-barWidth/2, 100*gap_25_prob[i]/gap_25[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", + " \n", + "offset = i+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar((offset+i)*tickSize-barWidth/2, 100*npb_D_prob[i]/npb_D[i], width=1, color=cmap(1))\n", + " \n", + "plt.figtext(0.25, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.70, -0.01, \"NPB-D\")\n", + "\n", + "brLab = np.arange(len(app_gap)+len(app_npb))\n", + "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", + "\n", + "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", + "\n", + "plt.ylabel(\"Percentage of probed Rd-MC\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_308484/3573616793.py:27: RuntimeWarning: invalid value encountered in double_scalars\n", + " plt.bar(i*tickSize-barWidth/2, 100*gap_22_prob[i]/gap_22[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", + "/tmp/ipykernel_308484/3573616793.py:31: RuntimeWarning: invalid value encountered in double_scalars\n", + " plt.bar((offset+i)*tickSize-barWidth/2, 100*npb_C_prob[i]/npb_C[i], width=1, color=cmap(1))\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAh0klEQVR4nO3deZhcVZ3/8feHJmHNYiAwEYgJkUHByNZAENQGdNiMAYew/lhUZJBdBnd+RjQijguDoOEJi2EwSgCJIGFYBtMQQAIJEAJEFBOWxEiS0SQEgWzf+eOeDpW2l9tVXUtXf17PU0/VPXXrnm9XVd/+9rlnUURgZmZmVk82qXYAZmZmZt3NCY6ZmZnVHSc4ZmZmVnec4JiZmVndcYJjZmZmdccJjpmZmdWdsiU4km6QtETSswVlgyTdL+mP6f5dqVySfizpRUnPSNq7XHGZmZlZ/StnC84k4PBWZV8BHoiIXYAH0jbAEcAu6XYmMKGMcZmZmVmdK1uCExEPAX9tVTwGuDE9vhE4uqD8vyLzGDBQ0pByxWZmZmb1bdMK17d9RCxOj/8CbJ8e7wC8WrDfwlS2mFYknUnWysNWW221z/ve977yRWtmJXnhhRcA2HXXXasciZn1ZLNnz14WEYO78ppKJzgbRERI6vI6ERExEZgI0NjYGLNmzer22MysezQ1NQHQ3Nxc1TjMrGeT9HJXX1PpUVSvtVx6SvdLUvkiYKeC/XZMZWZmZmZdVukE507gtPT4NOCOgvJT02iqUcCKgktZZmZmZl1StktUkn4JNAHbSloIjAMuB26R9FngZeC4tPvdwJHAi8DfgU+XKy4zMzOrf2VLcCLixHaeOrSNfQM4pzvqXb58OYsXu/Gn1gwZMoSBAwdWOwwzM+slqtbJuFyWLVvGsGHD2GKLLaodiiVvvvkmixYtcoJjZmYVU3dLNaxZs4bNN9+82mFYgc0335w1a9ZUOwwzM+tF6i7BAZBU7RCsgD8PMzOrtLq7RFVo1Lh7u+U4j116WLvPrVixgjFjxgDw9NNP8/73v5/NNtuMZcuW0a9fPxoaGogIPve5z3H66acDMHz4cN7znvewbt06hg0bxqRJk2hoaADgsssu49prr2X+/PkbEoPhw4dz6KGHct111wFw0003ceqpp7JgwQKGDRu2UTwdHbvF+PHj2XHHHTfE0+L0009nzpw59O/fn6233prJkyfnuqw0adIkFi5cyCWXXNLpvmZmZpVQly04lTRgwACam5tpbm5mzz335NZbb6W5uZltt92WW2+9lYcffphp06YxadIkpk+fDkBDQwPNzc3MmDGDPn36cN9992043l133cUhhxzCI488sqGsoaGBV155hbfffhuA2267jX322afNeDo6dh5XXXUVDz74IAceeCDXXHPNRs+tW7euS8cyMzOrFic4FTBw4EC+/vWv84tf/GKj8vXr17N8+XKyQWTw1FNPsfvuu/P5z3+en//85xvte8QRRzBt2jSWLFlCnz59Om1ZaX3shx56iL322ovRo0czc+bMTmPee++9efnll5k0aRJjx47l6KOP5sorr+Taa69l//33Z//99+eGG27YsP/MmTMZPXo0e+21FzNmzMjztpiZmZWNE5wK2WmnnVi0KJuced26dTQ1NTFs2DDWrVvHYYdll8AmT57MaaedRmNjI88///xGHXNPOOEEpkyZwpQpUzjuuOParKOjY1900UXccccd3HnnnRtagjpy3333sfvuuwOwatUqpk6dyimnnMLVV1/NjBkzmDFjBldeeSVLly4Fss7dv/nNb5g6dSpf+MIXinuTzMzMuokTnAp59dVX2WGHHYB3LiPNnTuXpUuXsnz5ctavX88dd9zB+PHjOfzww1myZAl33333htcPGTKEVatWcfPNNzN69OgN5VdffTVNTU2cccYZ7R4bYOXKlQwdOhRJ7LfffgA8/PDDNDU10dTUxKpVqwA477zz+OhHP8qbb7654ZijRo1CEvPnz2fkyJH07duXvn37MnLkSBYsWADAvvvuC8CwYcNYsWJFGd9JMzOzzjnBqYAVK1bw3e9+lxNP3HjuwwEDBnDWWWfxve99j+nTpzNmzBjuuece7rnnHqZNm8bkyZM32v+cc87hmGOO2WiOn3PPPZfm5uYNHZDbOjZAv379WLhwIQBPPPEEAAcddNCG/kNbb7018E4fnAkTJmwYbt/SSXn48OE888wzrF69mtWrVzN37lyGDx8OwOzZswF45ZVX6N+/f+lvmpmZWQnqehRVtY0dO5aGhgbWr1/PZz7zGQ455JB/2OeEE05g5MiRLFu2jJNOOmlD+YgRI5g3bx4rV67cUHbkkUdy5JFH5q6/5dhf+9rX+OEPf8jo0aN597vfTb9+/Yr6ebbbbjvOPvts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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAht0lEQVR4nO3de7hVVb3/8ffHLXjlIooeUhE0f5VG3raKabXTOt4itCOKelQqM/Ou2b0TWRyz08VMCx+8hBklapKmHi/H2IqWJKiISpahKEQCFSCmcvv+/phj42K3L4u11lxrsfbn9Tzr2WuOOfcc373W2nN/9xhjjqGIwMzMzKyRbFLrAMzMzMwqzQmOmZmZNRwnOGZmZtZwnOCYmZlZw3GCY2ZmZg3HCY6ZmZk1nNwSHEnXS1ok6emCsgGS7pf0p/R1m1QuST+U9LykpyTtm1dcZmZm1vjybMGZCBzRruyLwAMRsTvwQNoGOBLYPT3OAMbnGJeZmZk1uNwSnIh4CPh7u+KRwA3p+Q3AMQXlP43Mo0B/SYPyis3MzMwa26ZVrm+HiFiYnv8V2CE93xF4ueC4+alsIe1IOoOslYetttpqv3e+8535RWtm/+K5554D4B3veEeNIzEzg5kzZy6JiIHty6ud4KwTESFpg9eJiIgJwASA5ubmmDFjRsVjM7POtbS0ANDa2lrTOMzMACTN66i82ndRvdLW9ZS+LkrlC4CdC47bKZWZmZmZbbBqJzh3AKel56cBtxeUn5ruphoOLCvoyjIzMzPbILl1UUn6BdACbCdpPjAWuAy4WdIngXnA8enwu4GjgOeBfwIfzysuMzMza3y5JTgRcWInuw7r4NgAzq5EvUuXLmXhQjf+1JtBgwbRv3//WodhZmY9RM0GGedlyZIlDBkyhC222KLWoVjy+uuvs2DBAic4ZmZWNQ23VMOqVavYfPPNax2GFdh8881ZtWpVrcMwM7MepOESHABJtQ7BCvj9MDOzamu4LqpCw8feW5HzPHrJ4Z3uW7ZsGSNHjgTgySef5F3vehebbbYZS5YsoU+fPjQ1NRERfOpTn2LMmDEADB06lF122YU1a9YwZMgQJk6cSFNTEwCXXnop11xzDXPnzl2XGAwdOpTDDjuMa6+9FoAbb7yRU089lRdeeIEhQ4asF09X524zbtw4dtppp3XxtBkzZgyzZs2ib9++bL311kyaNKmobqWJEycyf/58vvrVr3Z7rJmZWTU0ZAtONfXr14/W1lZaW1vZe++9ueWWW2htbWW77bbjlltu4eGHH+auu+5i4sSJTJ06FYCmpiZaW1uZNm0avXr14r777lt3vjvvvJNDDz2URx55ZF1ZU1MTL730Em+++SYAt956K/vtt1+H8XR17mJceeWVPPjggxx88MFcffXV6+1bs2bNBp3LzMysVpzgVEH//v35yle+ws9//vP1yteuXcvSpUvJbiKDJ554gj333JPPfOYz/OxnP1vv2COPPJK77rqLRYsW0atXr25bVtqf+6GHHmKfffZhxIgRTJ8+vduY9913X+bNm8fEiRMZNWoUxxxzDFdccQXXXHMNBx54IAceeCDXX3/9uuOnT5/OiBEj2GeffZg2bVoxL4uZmVlunOBUyc4778yCBdnkzGvWrKGlpYUhQ4awZs0aDj886wKbNGkSp512Gs3NzTz77LPrDcwdPXo0kydPZvLkyRx//PEd1tHVuS+66CJuv/127rjjjnUtQV2577772HPPPQFYsWIFU6ZM4ZRTTuGqq65i2rRpTJs2jSuuuILFixcD2eDuX//610yZMoULL7ywtBfJzMysQpzgVMnLL7/MjjvuCLzVjTR79mwWL17M0qVLWbt2Lbfffjvjxo3jiCOOYNGiRdx9993rvn/QoEGsWLGCm266iREjRqwrv+qqq2hpaeH000/v9NwAy5cvZ/DgwUjigAMOAODhhx+mpaWFlpYWVqxYAcC5557LBz7wAV5//fV15xw+fDiSmDt3LsOGDaN379707t2bYcOG8cILLwCw//77AzBkyBCWLVuW4ytpZmbWPSc4VbBs2TK+9a1vceKJ68992K9fP84880y+/e1vM3XqVEaOHMk999zDPffcw1133cWkSZPWO/7ss8/m2GOPXW+On3POOYfW1tZ1A5A7OjdAnz59mD9/PgCPPfYYAIcccsi68UNbb7018NYYnPHjx6+73b5tkPLQoUN56qmnWLlyJStXrmT27NkMHToUgJkzZwLw0ksv0bdv3/JfNDMzszI09F1UtTZq1CiamppYu3Ytn/jEJzj00EP/5ZjRo0czbNgwlixZwkknnbSufLfddmPOnDksX758XdlRRx3FUUcdVXT9bef+8pe/zPe+9z1GjBjB2972Nvr06VPSz7P99ttz1llnccgh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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "gap_22_prob = (df_gap22_ram_prob['foundCandidBSlotRMD'].astype(float))\n", + "gap_22 = (df_gap22_ram_prob['numRdMissDirty'].astype(float))\n", + "\n", + "gap_25_prob = (df_gap25_ram_prob['foundCandidBSlotRMD'].astype(float))\n", + "gap_25 = (df_gap25_ram_prob['numRdMissDirty'].astype(float))\n", + "\n", + "npb_C_prob = (df_npbC_ram_prob['foundCandidBSlotRMD'].astype(float))\n", + "npb_C = (df_npbC_ram_prob['numRdMissDirty'].astype(float))\n", + "\n", + "npb_D_prob = (df_npbD_ram_prob['foundCandidBSlotRMD'].astype(float))\n", + "npb_D = (df_npbD_ram_prob['numRdMissDirty'].astype(float))\n", + "\n", + "################################## \n", + "# Multi bar Chart1\n", + "app_gap = df_gap22_ram_prob['app']\n", + "\n", + "app_npb = df_npbC_ram_prob['app']\n", + "\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,3)\n", + "plt.ylim([0,100])\n", + "barWidth = 1\n", + "tickSize = 2\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*tickSize-barWidth/2, 100*gap_22_prob[i]/gap_22[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", + "\n", + "offset = i+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar((offset+i)*tickSize-barWidth/2, 100*npb_C_prob[i]/npb_C[i], width=1, color=cmap(1))\n", + "\n", + "plt.figtext(0.25, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.7, -0.01, \"NPB-C\")\n", + "\n", + "brLab = np.arange(len(app_gap)+len(app_npb))\n", + "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", + "\n", + "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", + "\n", + "plt.ylabel(\"Percentage of probed Rd-Md\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()\n", + "\n", + "###############################################################################\n", + "# Multi bar Chart2\n", + "app_gap = df_gap25_ram_prob['app']\n", + "\n", + "app_npb = df_npbD_ram_prob['app']\n", + "\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,3)\n", + "plt.ylim([0,100])\n", + "barWidth = 1\n", + "tickSize = 2\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*tickSize-barWidth/2, 100*gap_25_prob[i]/gap_25[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", + " \n", + "offset = i+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar((offset+i)*tickSize-barWidth/2, 100*npb_D_prob[i]/npb_D[i], width=1, color=cmap(1))\n", + " \n", + "plt.figtext(0.25, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.70, -0.01, \"NPB-D\")\n", + "\n", + "brLab = np.arange(len(app_gap)+len(app_npb))\n", + "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", + "\n", + "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", + "\n", + "plt.ylabel(\"Percentage of probed Rd-Md\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAhY0lEQVR4nO3de5xXVb3/8de7EUUMQWH0oIMyXn7mhZOXUTHpNEGGmoT1S4P8qVjGsaS8dNX6RZ4fp6sejkc9+gAlLElRi7zm5ZgkWpCgIgpahrchlMESI/ECfH5/7DX4dZj7zPfCnvfz8ZjHfPfa+7vXZ77f7+z5zFprr6WIwMzMzCxP3lPuAMzMzMx6mhMcMzMzyx0nOGZmZpY7TnDMzMwsd5zgmJmZWe5sU+4AumPw4MExbNiwcodh1qs8/fTTAOy3335ljsTMDBYvXrwmIqqbl2/VCc6wYcNYtGhRucMw61Xq6+sBmDdvXlnjMDMDkPR8S+XuojIzM7PccYJjZmZmueMEx8zMzHJnqx6D05K3336bhoYG3njjjXKHYu3o27cvNTU19OnTp9yhmJlZzuQuwWloaKB///4MGzYMSeUOx1oREbzyyis0NDRQW1tb7nDMzCxnctdF9cYbbzBo0CAnNxVOEoMGDXJLm5mZFUXuEhzAyc1Wwu+TmZkVS9G6qCTNBE4AVkfEQc32fQW4GKiOiDXK/tJdChwPvA5MjIhHuhvDiCl3d/cUACy4aEyr+9auXcu4ceMAeOyxx9h///3ZbrvtWLNmDf3796eqqoqI4POf/zwTJ04EoLa2lj333JONGzcybNgwZs2aRVVVFQDf+973mDFjBitWrNicANTW1jJ69GiuvvpqAH72s59x2mmn8eyzz9J8osO2zt1k6tSp1NTUbI6nycSJE1myZAk77rgj733ve5k9ezYDBw5s9/WZNWsWDQ0NfPvb3273WDMzs1IoZgvOLODY5oWShgIfBV4oKD4O2Dd9TQKuLGJcPWrAgAHMmzePefPmcfDBB3PTTTcxb948Bg8ezE033cSDDz7IHXfcwaxZs7j//vsBqKqqYt68ecyfP58+ffpwzz33bD7f7bffzqhRo3jooYc2l1VVVfHCCy/w5ptvAnDzzTdz2GGHtRhPW+fuiMsuu4zf/va3HH300Vx11VXv2rdx48ZOncvMzKxcipbgRMQDwF9b2DUN+DoQBWXjgJ9GZgEwUNKQYsVWagMHDuRb3/oWP//5z99VvmnTJl599VUispfi0Ucf5cADD+QLX/gC11133buOPe6447jjjjtYvXo1ffr0abdlpfm5H3jgAQ455BDGjh3LwoUL24350EMP5fnnn2fWrFmcdNJJnHjiiVx66aXMmDGDI488kiOPPJKZM2duPn7hwoWMHTuWQw45hPnz5wOwdOlSPvKRjzBq1ChOPvlk1q9f3269ZmZmPaGkY3AkjQNWRsSSZrt2B14s2G5IZS2dY5KkRZIWNTY2FinSnjd06FBWrlwJZC0h9fX1DBs2jI0bNzJmTNYFNnv2bE4//XTq6upYtmwZb7/99ubnjx8/njlz5jBnzhxOPvnkVutp7dznn38+t9xyC7feeuvmlqC23HPPPRx44IEArFu3jrlz53Lqqady+eWXM3/+fObPn8+ll15K03vw9ttvc9tttzF37lzOO+88AM4++2xmzpzJb37zG44++miuueaaLrxyZmZmnVeyBEdSP+BC4DvdOU9ETI+Iuoioq67eYm2tivXiiy+y++5ZztbUjbR06VIaGxt59dVX2bRpE7fccgtTp07l2GOPZfXq1dx5552bnz9kyBDWrVvHDTfcwNixYzeXX3755dTX13PmmWe2em6A1157jT322ANJHHHEEQA8+OCD1NfXU19fz7p16wD40pe+xIc+9CHWr1+/+ZwjRoxAEitWrGD48OFsu+22bLvttgwfPpxnn30WgMMPPxzI1gdbu3YtAE8++SSnnXYa9fX1XH/99bz00kvFennNzMzepZTz4OwN1AJL0uDZGuARSUcAK4GhBcfWpLJcWLt2Ld///ve3GIQ7YMAAzjrrLH74wx8yZswYxo0bx8UXXwzAn//8Zy644ILNA5ghaxFZtmwZ22+//eayyZMnM3ny5C3qLDz3j370I/r3709DQwM1NTU8/PDD7LPPPowcOXKLBRMvu+wyRo4c+a6ypkHKtbW1PP7447z11ltA1gVVW1vLsmXLWLx4MQAvvPACO+64IwAHHXQQ119/PUOGZL2NTc8zMzMrtpIlOBGxFNilaVvSc0BduovqVmCypBuAI4G1EbGqVLEVy0knnURVVRWbNm3is5/9LKNGjdrimPHjxzN8+HDWrFnDZz7zmc3le++9N8uXL+e1117bXHb88cdz/PHHd7j+pnNfeOGF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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "gap_22_prob = df_gap22_ram_prob['actDelayedDueToTagAct'].astype(float)/1000\n", + "gap_25_prob = df_gap25_ram_prob['actDelayedDueToTagAct'].astype(float)/1000\n", + "npb_C_prob = df_npbC_ram_prob['actDelayedDueToTagAct'].astype(float)/1000\n", + "npb_D_prob = df_npbD_ram_prob['actDelayedDueToTagAct'].astype(float)/1000\n", + "################################## \n", + "# Multi bar Chart1\n", + "app_gap = df_gap22_ram_prob['app']\n", + "#app_gap[len(app_gap)] = \"gmean\"\n", + "\n", + "app_npb = df_npbC_ram_prob['app']\n", + "#app_npb[len(app_npb)] = \"gmean\"\n", + "\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,3)\n", + "plt.ylim([0,150])\n", + "barWidth = 1\n", + "tickSize = 2\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*tickSize-barWidth/2, gap_22_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", + "\n", + "offset = i+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar((offset+i)*tickSize-barWidth/2, npb_C_prob[i], width=1, color=cmap(1))\n", + "\n", + "plt.figtext(0.25, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.7, -0.01, \"NPB-C\")\n", + "\n", + "brLab = np.arange(len(app_gap)+len(app_npb))\n", + "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", + "\n", + "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", + "# plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"ACT delayed (K)\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()\n", + "\n", + "###############################################################################\n", + "# Multi bar Chart2\n", + "app_gap = df_gap25_ram_prob['app']\n", + "#app_gap[len(app_gap)] = \"gmean\"\n", + "\n", + "app_npb = df_npbD_ram_prob['app']\n", + "#app_npb[len(app_npb)] = \"gmean\"\n", + "\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,3)\n", + "plt.ylim([0,150])\n", + "barWidth = 1\n", + "tickSize = 2\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*tickSize-barWidth/2, gap_25_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Probe' if i==0 else None)\n", + "offset = i+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar((offset+i)*tickSize-barWidth/2, npb_D_prob[i], width=1, color=cmap(1))\n", + "\n", + "plt.figtext(0.25, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.70, -0.01, \"NPB-D\")\n", + "\n", + "brLab = np.arange(len(app_gap)+len(app_npb))\n", + "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", + "\n", + "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", + "# plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"ACT delayed (K)\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/data_plot_compare_hours.ipynb b/data_plot_compare_hours.ipynb new file mode 100644 index 0000000000..78c19347e8 --- /dev/null +++ b/data_plot_compare_hours.ipynb @@ -0,0 +1,772 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import sys\n", + "from matplotlib import pyplot as plt\n", + "import os\n", + "\n", + "cmap = plt.get_cmap('Set1')\n", + "\n", + "Stats = ['simSeconds ',\n", + "'hostSeconds ',\n", + "'system.mem_ctrl.readReqs ',\n", + "'system.mem_ctrl.writeReqs ',\n", + "'system.mem_ctrl.servicedByWrQ ',\n", + "'system.mem_ctrl.mergedWrBursts ',\n", + "'system.mem_ctrl.numTotHits ',\n", + "'system.mem_ctrl.numTotMisses ',\n", + "'system.mem_ctrl.numColdMisses ',\n", + "'system.mem_ctrl.numHotMisses ',\n", + "'system.mem_ctrl.numRdMissClean ',\n", + "'system.mem_ctrl.numRdMissDirty ',\n", + "'system.mem_ctrl.numRdHit ',\n", + "'system.mem_ctrl.numWrMissClean ',\n", + "'system.mem_ctrl.numWrMissDirty ',\n", + "'system.mem_ctrl.numWrHit ',\n", + "'system.mem_ctrl.numRdHitDirty ',\n", + "'system.mem_ctrl.numRdHitClean ',\n", + "'system.mem_ctrl.numWrHitDirty ',\n", + "'system.mem_ctrl.numWrHitClean ',\n", + "'system.o3Cpu0.thread_0.numInsts ',\n", + "'system.o3Cpu1.thread_0.numInsts ',\n", + "'system.o3Cpu2.thread_0.numInsts ',\n", + "'system.o3Cpu3.thread_0.numInsts ',\n", + "'system.o3Cpu4.thread_0.numInsts ',\n", + "'system.o3Cpu5.thread_0.numInsts ',\n", + "'system.o3Cpu6.thread_0.numInsts ',\n", + "'system.o3Cpu7.thread_0.numInsts ',\n", + "'system.mem_ctrl.avgRdBWSys ',\n", + "'system.mem_ctrl.avgWrBWSys ',\n", + "'system.mem_ctrl.avgORBLen ',\n", + "'system.far_mem_ctrl.avgRdBWSys ',\n", + "'system.far_mem_ctrl.avgWrBWSys ',\n", + "'system.loc_mem_ctrl.avgRdBWSys ',\n", + "'system.loc_mem_ctrl.avgWrBWSys ',\n", + "'system.loc_mem_ctrl.dram.readBursts ',\n", + "'system.loc_mem_ctrl.dram.writeBursts ',\n", + "'system.loc_mem_ctrl.dram_2.readBursts ',\n", + "'system.loc_mem_ctrl.dram_2.writeBursts ',\n", + "'system.far_mem_ctrl.dram.readBursts ',\n", + "'system.far_mem_ctrl.dram.writeBursts ',\n", + "'system.loc_mem_ctrl.dram.avgRdBW ',\n", + "'system.loc_mem_ctrl.dram.avgWrBW ',\n", + "'system.loc_mem_ctrl.dram_2.avgRdBW ',\n", + "'system.loc_mem_ctrl.dram_2.avgWrBW ',\n", + "'system.far_mem_ctrl.dram.avgRdBW ',\n", + "'system.far_mem_ctrl.dram.avgWrBW ',\n", + "'system.loc_mem_ctrl.dram.busUtil ',\n", + "'system.loc_mem_ctrl.dram.busUtilRead ',\n", + "'system.loc_mem_ctrl.dram.busUtilWrite ',\n", + "'system.loc_mem_ctrl.dram_2.busUtil ',\n", + "'system.loc_mem_ctrl.dram_2.busUtilRead ',\n", + "'system.loc_mem_ctrl.dram_2.busUtilWrite ',\n", + "'system.far_mem_ctrl.dram.busUtil ',\n", + "'system.far_mem_ctrl.dram.busUtilRead ',\n", + "'system.far_mem_ctrl.dram.busUtilWrite ',\n", + "'system.far_mem_ctrl.dram.bytesRead ',\n", + "'system.far_mem_ctrl.dram.bytesWritten ',\n", + "'system.loc_mem_ctrl.dram.bytesRead ',\n", + "'system.loc_mem_ctrl.dram.bytesWritten ',\n", + "'system.loc_mem_ctrl.dram_2.bytesRead ',\n", + "'system.loc_mem_ctrl.dram_2.bytesWritten ',\n", + "'system.mem_ctrl.avgTimeTagCheckRes ',\n", + "'system.mem_ctrl.avgTimeTagCheckResRd ',\n", + "'system.mem_ctrl.avgTimeTagCheckResWr ',\n", + "'system.mem_ctrl.avgPktRespTimeRd ',\n", + "'system.mem_ctrl.avgPktRespTimeWr ',\n", + "'system.mem_ctrl.avgPktORBTime ',\n", + "'system.mem_ctrl.avgPktORBTimeRd ',\n", + "'system.mem_ctrl.avgPktORBTimeWr ',\n", + "'system.mem_ctrl.avgTimeInLocRead ',\n", + "'system.mem_ctrl.avgTimeInLocWrite ',\n", + "'system.mem_ctrl.avgTimeInFarRead '\n", + " ]\n", + "\n", + "dfCols = [\n", + " 'app',\n", + " 'simSeconds',\n", + " 'hostSeconds',\n", + " 'readReqs',\n", + " 'writeReqs',\n", + " 'servicedByWrQ',\n", + " 'mergedWrBursts',\n", + " 'numTotHits',\n", + " 'numTotMisses',\n", + " 'numColdMisses',\n", + " 'numHotMisses',\n", + " 'numRdMissClean',\n", + " 'numRdMissDirty',\n", + " 'numRdHit',\n", + " 'numWrMissClean',\n", + " 'numWrMissDirty',\n", + " 'numWrHit',\n", + " 'numRdHitDirty',\n", + " 'numRdHitClean',\n", + " 'numWrHitDirty',\n", + " 'numWrHitClean',\n", + " 'numInsts0',\n", + " 'numInsts1',\n", + " 'numInsts2',\n", + " 'numInsts3',\n", + " 'numInsts4',\n", + " 'numInsts5',\n", + " 'numInsts6',\n", + " 'numInsts7',\n", + " 'avgRdBWSys',\n", + " 'avgWrBWSys',\n", + " 'avgORBLen',\n", + " 'farAvgRdBWSys',\n", + " 'farAvgWrBWSys',\n", + " 'locAvgRdBWSys',\n", + " 'locAvgWrBWSys',\n", + " 'readBursts1',\n", + " 'writeBursts1',\n", + " 'readBursts2',\n", + " 'writeBursts2',\n", + " 'readBursts3',\n", + " 'writeBursts3',\n", + " 'loc1AvgRdBW',\n", + " 'loc1AvgWrBW',\n", + " 'loc2AvgRdBW',\n", + " 'loc2AvgWrBW',\n", + " 'farAvgRdBW',\n", + " 'farAvgWrBW',\n", + " 'loc1BusUtil',\n", + " 'loc1BusUtilRead',\n", + " 'loc1BusUtilWrite',\n", + " 'loc2BusUtil',\n", + " 'loc2BusUtilRead',\n", + " 'loc2BusUtilWrite',\n", + " 'farBusUtil',\n", + " 'farBusUtilRead',\n", + " 'farBusUtilWrite',\n", + " 'farBytesRead',\n", + " 'farBytesWritten',\n", + " 'loc1BytesRead',\n", + " 'loc1BytesWritten',\n", + " 'loc2BytesRead',\n", + " 'loc2BytesWritten',\n", + " 'avgTimeTagCheckRes',\n", + " 'avgTimeTagCheckResRd',\n", + " 'avgTimeTagCheckResWr',\n", + " 'avgPktRespTimeRd',\n", + " 'avgPktRespTimeWr',\n", + " 'avgPktORBTime',\n", + " 'avgPktORBTimeRd',\n", + " 'avgPktORBTimeWr',\n", + " 'avgTimeInLocRead',\n", + " 'avgTimeInLocWrite',\n", + " 'avgTimeInFarRead'\n", + "\n", + " ]\n", + "##########################################################\n", + "\n", + "def getStat(filename, stat):\n", + " filename = os.path.join(filename).replace('\\\\','/')\n", + " #print(stat)\n", + " #print(filename)\n", + " try:\n", + " with open(filename) as f:\n", + " readlines = f.readlines()\n", + " for l in readlines:\n", + " if stat in l:\n", + " return l\n", + " return 0.0 #for cases where stat was not found\n", + " except: #for cases where the file was not found\n", + " return 0.0\n", + "\n", + "##########################################################\n", + "\n", + "def creatDataFrame(dataDir, suite):\n", + " app = []\n", + " if suite == \"GAPBS\":\n", + " app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", + " if suite == \"NPB\":\n", + " app = ['bt', 'cg', 'ft', 'is', 'lu', 'mg', 'sp', 'ua']\n", + " rows = []\n", + " for a in app:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}/stats.txt'.format(dataDir, a)\n", + " ret_line = getStat(time_file_path, stat)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + " df = pd.DataFrame(rows, columns= dfCols)\n", + " df['totNumInsts'] = df['numInsts0'].astype(int)+df['numInsts1'].astype(int)+df['numInsts2'].astype(int)+df['numInsts3'].astype(int)+df['numInsts4'].astype(int)+df['numInsts5'].astype(int)+df['numInsts6'].astype(int)+df['numInsts7'].astype(int)\n", + " df['totBW'] = (df['avgRdBWSys'].astype(float)+df['avgWrBWSys'].astype(float))/1000000000\n", + " df['coldRate'] = (df['numColdMisses'].astype(float) / df['numTotMisses'].astype(float)) *100\n", + " df['injRate'] = (df['readReqs'].astype(float) + df['writeReqs'].astype(float))*64/1000000000 / df['simSeconds'].astype(float)\n", + " df['BIPS'] = (df['totNumInsts'].astype(float)/1000000000)/df['simSeconds'].astype(float)\n", + " \n", + " df['accAmp'] = (df['farBytesRead'].astype(float) + df['farBytesWritten'].astype(float) +\n", + " df['loc1BytesRead'].astype(float) + df['loc1BytesWritten'].astype(float) + \n", + " df['loc2BytesRead'].astype(float) + df['loc2BytesWritten'].astype(float)) / (df['readReqs'].astype(float) * 64 + df['writeReqs'].astype(float) * 64)\n", + " \n", + " df['BWBloat'] = (df['loc1AvgRdBW'].astype(float) + df['loc1AvgWrBW'].astype(float) +\n", + " df['loc2AvgRdBW'].astype(float) + df['loc2AvgWrBW'].astype(float) +\n", + " df['farAvgRdBW'].astype(float) + df['farAvgWrBW'].astype(float)) / ((df['avgRdBWSys'].astype(float) + df['avgWrBWSys'].astype(float)) / 1000000)\n", + " return df" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "df_gap22_dc_ram = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/rambus_g22_nC/GAPBS\", \"GAPBS\")\n", + "df_npbC_dc_ram = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/rambus_g22_nC/NPB\", \"NPB\")\n", + "df_gap22_dc_cas = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/cascade_g22_nC/GAPBS\", \"GAPBS\")\n", + "df_npbC_dc_cas = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/cascade_g22_nC/NPB\", \"NPB\")\n", + "df_gap22_dc_orc = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/oracle_g22_nC/GAPBS\", \"GAPBS\")\n", + "df_npbC_dc_orc = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/oracle_g22_nC/NPB\", \"NPB\")\n", + "df_gap22_noDC = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/noDC_g22_nC/GAPBS\", \"GAPBS\")\n", + "df_npbC_noDC = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/noDC_g22_nC/NPB\", \"NPB\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "df_gap22_dc_ram_3hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/3hrPC/rambus_g22_nC/GAPBS\", \"GAPBS\")\n", + "df_npbC_dc_ram_3hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/3hrPC/rambus_g22_nC/NPB\", \"NPB\")\n", + "df_gap22_dc_cas_3hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/3hrPC/cascade_g22_nC/GAPBS\", \"GAPBS\")\n", + "df_npbC_dc_cas_3hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/3hrPC/cascade_g22_nC/NPB\", \"NPB\")\n", + "df_gap22_dc_orc_3hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/3hrPC/oracle_g22_nC/GAPBS\", \"GAPBS\")\n", + "df_npbC_dc_orc_3hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/3hrPC/oracle_g22_nC/NPB\", \"NPB\")\n", + "df_gap22_noDC_3hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/3hrPC/noDC_g22_nC/GAPBS\", \"GAPBS\")\n", + "df_npbC_noDC_3hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/3hrPC/noDC_g22_nC/NPB\", \"NPB\")\n", + "\n", + "df_gap22_dc_ram_6hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/6hour/6hour/rambus_g22_nC/GAPBS\", \"GAPBS\")\n", + "df_npbC_dc_ram_6hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/6hour/6hour/rambus_g22_nC/NPB\", \"NPB\")\n", + "df_gap22_dc_cas_6hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/6hour/6hour/cascade_g22_nC/GAPBS\", \"GAPBS\")\n", + "df_npbC_dc_cas_6hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/6hour/6hour/cascade_g22_nC/NPB\", \"NPB\")\n", + "df_gap22_dc_orc_6hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/6hour/6hour/oracle_g22_nC/GAPBS\", \"GAPBS\")\n", + "df_npbC_dc_orc_6hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/6hour/6hour/oracle_g22_nC/NPB\", \"NPB\")\n", + "df_gap22_noDC_6hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/6hour/6hour/noDC_g22_nC/GAPBS\", \"GAPBS\")\n", + "df_npbC_noDC_6hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/6hour/6hour/noDC_g22_nC/NPB\", \"NPB\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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KrQEarWat956i/bt23PixAnuueceHnnkEd59911bZ60iRdiNUaNGKd26dVNMJpNl2eLFi5Vu3bopR44cUQDl77//tmEOa1db/hVFUe6//35l1KhRlnU//PCD4uHhoeTm5jZ3VuuUm5ur6HQ65aOPPqqy7oMPPlDc3d2VjIwMG+SsYer6nYSFhSnTpk2zVfYaZNSoUcr9999v+bxkyRKlffv2il6vt12mytm9e7cCKCdPnqywPCMjQwGU6Ojoardzd3dXVq1aVe26lStXKoCybds2y7JDhw4pgLJ9+/amy3wD1Odv6o033rBJ3upS2/f6vffeU3x9fZWioiLLso8++kgBlL179zZjLhvmjTfeUMLCwiyfAeWnn36yWX4uRdl3257vCXUpf32q7nfg6emprFy5stnzVZNRo0Ypw4cPt3w2GAyKq6urctttt1mWpaWlKYASExOjLF68WOnRo0eFfTz++OMKoGRlZTVXtmtU0/VXURRl1qxZio+Pj1JQUGBZ9t577ylubm6K0WhszmzWqrprZ+/evZWnn3662vTff/+94uvra/2MNZA0hbIzgwcPrtB8YMiQIRw7doy9e/ei0WgYNWqUDXNXt5rybzQaq6SdMGECYWFhREREcNttt/HVV19RWFjYnNmt0aFDhygpKWHcuHFV1sXGxtKnT58W0y64rt9J//79bZW1RomNjWXEiBEVSvdtqXfv3owbN46ePXty/fXX89FHH5GVlYWPjw+zZ89m0qRJXHXVVbz55pukpaVZtlu0aBF33nkn48ePZ9myZVWacmm1WgYMGGD53LVrV7y8vDh06FCznVtlDfme25PavtdHjhyhV69eODk5WZYNHDiwObN32bPne0Jr1KtXL8t7jUaDr68vPXv2tCwLDAwE4OzZsxw5cqTCdQjs6/tR0/W3/HoXFxfL5yFDhpCfn2/zZqUN8c8//zBu3DjatGmDu7s7t912GxkZGXb3HZHAooUof7NrLdzd3dmzZw/ffPMNwcHBPPXUU/Tu3dsu2ms6Oztf0rqWyNXV1dZZuCT29nvQaDT8/fff/PHHH0RGRvL222/TpUsXEhMTWblyJTExMQwdOpRvv/2Wzp07s23bNgCWLl3KwYMHueKKK1i3bh2RkZH89NNPNj6b1sne/mZERfZ8T2gIlUplaYJTprS01Ea5qVnlQhmVSlVhWVnhgb02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EsKcOXPqNS+JXq9n+fLl9O7dGxcXF/z8/Bg2bBgrV660q8lEReslnbeFaGFOnDjBsGHD8PLy4sUXX6Rnz57odDri4uL48MMPadOmDVdffbUl/aeffsojjzzCp59+ysMPP1xlfx4eHhw5cgSTycS+ffu4/fbbSU1N5c8//7SkWblyJZMnT6a0tNSSxtXVleeeew6A6dOno9fr+eyzz4iIiODMmTOsXbuWjIyMGs/j8OHDmEwmPvjgAzp27MiBAweYO3cuBQUFlonJtm7dSq9evVi8eDGBgYH8+uuvzJw5E09PT6688sqm+pEKIUSTcHJy4uWXX+bf//433t7eNaY7cuQI7u7uHDt2jHnz5nHVVVexf/9+y4Rozz77LHPnzsVoNHL06FHmzZvHfffdxxdffFHjPvV6PZMmTWLfvn0899xzDBs2DA8PD7Zt28arr75Knz59iIqKaupTFqIi206jIYRoqEmTJilt27ZV8vPzq11fNlGZoihKdHS00qZNG0Wv1yshISHKli1bKqQtm4CtvBdeeEFRq9VKYWGhoigVJ0gqM2fOHGXq1KmKoihKVlaWAijR0dGNPDNFWb58udK+ffta00ydOlW5/fbbG30sIYRoSrNmzVKuvPJKpWvXrsrDDz9sWf7TTz9ZJotcv359lUnNvvrqqwoTMVY3Ud1zzz2nREZG1nr8l19+WVGr1cqePXuqrNPr9TXeM4RoStIUSogWJCMjg7/++ot7770XV1fXatOUVbkDfPLJJ9x88804ODhw880388knn9R5DGdnZ0wmEwaDodr1R48eZd26dQwaNAgANzc33NzcWL16dYXmUZciJycHHx+fRqcRQghb0Gg0vPjii7z99tucPn26XtuUzZNSvhloeSkpKfzyyy+Wa25NvvrqK8aPH0+fPn2qrHNwcKjxniFEU5LAQogW5Pjx4yiKQpcuXSos9/PzszzgL168GIDc3Fz++9//MmPGDABmzJjBd999R35+fo37P3bsGO+//z79+/fH3d3dsvzmm2/Gzc0NJycnunTpQvfu3S3jl2u1WlatWsVnn32Gl5cXw4YN47HHHmP//v0NPre3336bf//73zWm+e6779i5cye33357g/YthBDN5dprryUqKoqnn366zrRpaWm8+uqrtGnTpsJ1ffHixbi5ueHs7Ezbtm1RqVS8/vrrte7r2LFjdO3atdH5F6IxJLAQohXYsWMHsbGxdO/e3VJr8M0339ChQwd69+4NQFRUFGFhYXz77bcVts3JycHNzQ0XFxe6dOlCYGBglQ7Sb7zxBrGxsezbt49ff/2Vo0ePctttt1nWT58+ndTUVH7++WcmT55MdHQ0ffv2ZdWqVQDcddddlsDHzc2tSv5TUlKYPHky119/PXPnzq32HNevX8/tt9/ORx99RPfu3S/5ZyWEENb28ssv89lnn3Ho0KFq17dt2xZXV1dCQkIoKCjghx9+wNHR0bL+4YcfJjY2lv3797N27VoArrjiCoxGI0CF6+ldd90FgCLTkgk7IJ23hWhBOnbsiEql4siRIxWWR0REABer1MHcDOrgwYNotRe/5iaTiU8//ZQ5c+ZYlrm7u7Nnzx7UajXBwcEV9lEmKCiIjh07AtClSxfy8vK4+eabef755y3LnZycmDBhAhMmTODJJ5/kzjvv5Omnn2b27Nk8++yzPPTQQ9WeU2pqKmPGjGHo0KF8+OGH1abZsGEDV111FW+88QYzZ86sz49KCCFsZuTIkUyaNIklS5Ywe/bsKus3bdqEh4cHAQEBFWqHy/j5+VmurZ06dWLFihUMGTKE9evXM378eGJjYy1pPTw8AOjcuTOHDx+2yvkIUV8SWAjRgvj6+jJhwgT+85//sGDBghrbzMbFxbFr1y6io6Mr9EfIzMxk9OjRHD582FJlrlarLTew+iobuaSoqKjGNJGRkaxevRqAgIAAAgICqqRJSUlhzJgx9OvXj5UrV6JWV61EjY6O5sorr+Tll19m3rx5DcqnEELYyrJly4iKiqrSdBWgffv2eHl51Xtfla+51V2zb7nlFh577DH27t1bpZ9FaWkper1e+lkIq5PAQogW5t1332XYsGH079+fpUuX0qtXL9RqNTt37uTw4cP069ePTz75hIEDBzJy5Mgq2w8YMIBPPvmk2nktapKdnU16ejomk4ljx47x7LPP0rlzZ7p160ZGRgbXX389d9xxB7169cLd3Z1du3axfPlyrrnmmhr3mZKSwujRowkLC+PVV1/l3LlzlnVBQUGAufnTlVdeyf3338/06dNJT08HwNHRUTpwCyHsWs+ePbn11lt56623GrxtXl4e6enpKIrCqVOneOSRR/D392fo0KE1brNw4UJ+++03xo0bx3PPPcfw4cMt1+OXX36ZTz75RIabFdZn41GphBCXIDU1VZk/f77Svn17xcHBQXFzc1MGDhyovPLKK0pOTo7i6+urLF++vNptX375ZSUgIEDR6/XVDjdbGWB5qVQqJTg4WLnxxhuVhIQERVEUpbi4WHn00UeVvn37Kp6enoqLi4vSpUsX5YknnrAMWVudlStXVth3+VeZWbNmVbt+1KhRDf6ZCSGENc2aNUu55pprKixLTExUHB0dax1utrKwsLAK1zt/f39l6tSpyt69e+vMQ3FxsfLSSy8pPXv2VJycnBQfHx9l2LBhyqpVq5TS0tJGnJ0Q9aNSFOntI4QQQgghhGgcGRVKCCGEEEII0WgSWAghhBBCCCEaTQILIYQQQgghRKNJYCGEEEIIIYRoNAkshBBCCCGEEI0mgYUQQgghhBCi0SSwEEIIIYQQQjSaBBZCCCGEEEKIRpPAQgghhBBCCNFoElgIIYQQQgghGk0CCyGEEEIIIUSjSWAhhBBCCCGEaLT/B4jOIOIrwDjkAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_dc_cas['app']\n", + "gap = df_gap22_dc_cas['simSeconds'].astype(float) * 1000\n", + "gap_3hr = df_gap22_dc_cas_3hr['simSeconds'].astype(float) * 1000\n", + "gap_6hr = df_gap22_dc_cas_6hr['simSeconds'].astype(float) * 1000\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,1000])\n", + "\n", + "x = np.arange(6)*4+1\n", + "plt.plot(x, gap, label='1 hour', color=cmap(1))\n", + "plt.plot(x, gap_3hr, label='3 hour', color=cmap(2))\n", + "plt.plot(x, gap_6hr, label='6 hour', color=cmap(3))\n", + "plt.scatter(x, gap, color=cmap(1))\n", + "plt.scatter(x, gap_3hr, color=cmap(2))\n", + "plt.scatter(x, gap_6hr, color=cmap(3))\n", + "\n", + "app_npb = df_npbC_dc_cas['app']\n", + "npb = df_npbC_dc_cas['simSeconds'].astype(float) * 1000\n", + "npb_3hr = df_npbC_dc_cas_3hr['simSeconds'].astype(float) * 1000\n", + "npb_6hr = df_npbC_dc_cas_6hr['simSeconds'].astype(float) * 1000\n", + "x=np.arange(6,14)*4+1\n", + "plt.plot(x, npb, color=cmap(1))\n", + "plt.plot(x, npb_3hr, color=cmap(2))\n", + "plt.plot(x, npb_6hr, color=cmap(3))\n", + "plt.scatter(x, npb, color=cmap(1))\n", + "plt.scatter(x, npb_3hr, color=cmap(2))\n", + "plt.scatter(x, npb_6hr, color=cmap(3))\n", + "\n", + "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, 0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=23, color='black')\n", + "\n", + "plt.ylabel(\"Execution Time (ms)\")\n", + "plt.title(\"Cascade Lake\", fontsize = 9)\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_dc_cas['app']\n", + "gap = df_gap22_dc_cas['simSeconds'].astype(float) * 1000\n", + "gap_3h = df_gap22_dc_cas_3hr['simSeconds'].astype(float) * 1000\n", + "gap_6hr = df_gap22_dc_cas_6hr['simSeconds'].astype(float) * 1000\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,1000])\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*4, gap[i], width=1, color=cmap(1), label='1 hour' if i==0 else None)\n", + " plt.bar(i*4+1, gap_3h[i], width=1, color=cmap(2), label='3 hours' if i==0 else None)\n", + " plt.bar(i*4+2, gap_6hr[i], width=1, color=cmap(3), label='6 hours' if i==0 else None)\n", + "\n", + "offset = i*5-2\n", + "app_npb = df_npbC_dc_cas['app']\n", + "npb_cas = df_npbC_dc_cas['simSeconds'].astype(float) * 1000\n", + "npb_cas_3hr = df_npbC_dc_cas_3hr['simSeconds'].astype(float) * 1000\n", + "npb_cas_6hr = df_npbC_dc_cas_6hr['simSeconds'].astype(float) * 1000\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*4+1, npb_cas[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*4+2, npb_cas_3hr[i], width=1, color=cmap(2))\n", + " plt.bar(offset+i*4+3, npb_cas_6hr[i], width=1, color=cmap(3))\n", + "\n", + "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, 0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset-0.25, color='black')\n", + "\n", + "plt.ylabel(\"Execution Time (ms)\")\n", + "plt.title(\"Cascade Lake\", fontsize = 9)\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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Y8mSJbCzs4OTkxNef/111A7cpVAosHLlSnh6ekIikcDf3x+bNm0yc4r1NZX+UaNG4aOPPsLx48fB4/EwatQoAMCXX36JgIAASKVSuLq64oEHHjBvBurQarVYt24d/P39IZFI4OXlhXfffRcAcPPmTcycORMODg6wtrZG//79cebMGTOnuKFRo0ZhyZIlTf6f8vHxwdtvv425c+fC1tYWixcvNnOKGzd//nwcO3YMn3zyCTdZZ1paGq5cuYIpU6bA1tYWcrkcw4cPR0pKitnS+fvvvyM8PBxWVlZwdHTEuHHjUFFRgaNHj2LgwIGwtraGvb09hg0bhvT0dADApUuXMHr0aMjlctja2qJfv344d+4cAGDr1q2wt7fH7t27ud/JhAkTcOPGDbPlEWj+d56eno7nn3++0UlVLUFzv+tTp04hMjISUqkU/fv3x+7duy26edH8+fOxdOlSZGRkgMfjwcfHBwBw33336b23dHVrIy35mmAoHo/XoNbI3t4eW7duNUt6GjNq1CgsXboUy5YtQ7du3eDq6opvv/2WmzhYLpfD398ff/31F/eZPXv2cMdm9OjR2LZtm0U1a27q/Dt//nxMnz4db775JpydnWFra4snn3wSSqXS3EnW01htb2RkJNasWQMA+PjjjxEeHg5ra2t4enri6aefRnl5eccntAVUY2Fhtm3bhoULF+Ls2bM4d+4cFi9eDC8vLyxatAhz585FVFQUPv30U/Tu3Rupqam4deuWuZOsp6n079y5Ey+//DIuX76MnTt3QiwW49y5c3j22Wfx/fffY+jQoSgsLMSJEyfMnQXOqlWr8O2332L9+vW46667kJ2djYSEBJSXl2PkyJHo3r079uzZAzc3N1y4cAFardbcSW5Uc/+nAODDDz/EG2+8gdWrV5s5pU375JNPcO3aNYSFheGtt94CAGg0GowYMQKjRo3C4cOHYWtri5MnT0KtVpsljdnZ2Zg5cybWrVuH++67D2VlZThx4gQYY5g+fToWLVqEn3/+GUqlEmfPnuVuumfPno0+ffrgq6++gkAgQExMDEQiEbffyspKvPvuu9i+fTvEYjGefvppPPLIIzh58qRZ8gk0/zvv3bs3Fi9ezP3/sjRN/a5LS0sxdepUTJ48GT/99BPS09MtvundJ598gp49e+Kbb75BdHQ0BAIBXFxcsGXLFkycOBECgcDc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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_dc_ram['app']\n", + "gap = df_gap22_dc_ram['simSeconds'].astype(float) * 1000\n", + "gap_3hr = df_gap22_dc_ram_3hr['simSeconds'].astype(float) * 1000\n", + "gap_6hr = df_gap22_dc_ram_6hr['simSeconds'].astype(float) * 1000\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,1000])\n", + "\n", + "x = np.arange(6)*4+1\n", + "plt.plot(x, gap, label='1 hour', color=cmap(1))\n", + "plt.plot(x, gap_3hr, label='3 hour', color=cmap(2))\n", + "plt.plot(x, gap_6hr, label='6 hour', color=cmap(3))\n", + "plt.scatter(x, gap, color=cmap(1))\n", + "plt.scatter(x, gap_3hr, color=cmap(2))\n", + "plt.scatter(x, gap_6hr, color=cmap(3))\n", + "\n", + "app_npb = df_npbC_dc_ram['app']\n", + "npb = df_npbC_dc_ram['simSeconds'].astype(float) * 1000\n", + "npb_3hr = df_npbC_dc_ram_3hr['simSeconds'].astype(float) * 1000\n", + "npb_6hr = df_npbC_dc_ram_6hr['simSeconds'].astype(float) * 1000\n", + "x=np.arange(6,14)*4+1\n", + "plt.plot(x, npb, color=cmap(1))\n", + "plt.plot(x, npb_3hr, color=cmap(2))\n", + "plt.plot(x, npb_6hr, color=cmap(3))\n", + "plt.scatter(x, npb, color=cmap(1))\n", + "plt.scatter(x, npb_3hr, color=cmap(2))\n", + "plt.scatter(x, npb_6hr, color=cmap(3))\n", + "\n", + "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, 0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=23, color='black')\n", + "\n", + "plt.ylabel(\"Execution Time (ms)\")\n", + "plt.title(\"TDRAM\", fontsize = 9)\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_dc_ram['app']\n", + "gap = df_gap22_dc_ram['simSeconds'].astype(float) * 1000\n", + "gap_3hr = df_gap22_dc_ram_3hr['simSeconds'].astype(float) * 1000\n", + "gap_6hr = df_gap22_dc_ram_6hr['simSeconds'].astype(float) * 1000\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,1000])\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*4, gap[i], width=1, color=cmap(1), label='1 hour' if i==0 else None)\n", + " plt.bar(i*4+1, gap_3h[i], width=1, color=cmap(2), label='3 hours' if i==0 else None)\n", + " plt.bar(i*4+2, gap_6hr[i], width=1, color=cmap(3), label='6 hours' if i==0 else None)\n", + "\n", + "offset = i*5-2\n", + "app_npb = df_npbC_dc_ram['app']\n", + "npb = df_npbC_dc_ram['simSeconds'].astype(float) * 1000\n", + "npb_3hr = df_npbC_dc_ram_3hr['simSeconds'].astype(float) * 1000\n", + "npb_6hr = df_npbC_dc_ram_6hr['simSeconds'].astype(float) * 1000\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*4+1, npb[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*4+2, npb_3hr[i], width=1, color=cmap(2))\n", + " plt.bar(offset+i*4+3, npb_6hr[i], width=1, color=cmap(3))\n", + "\n", + "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, 0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset-0.25, color='black')\n", + "\n", + "plt.ylabel(\"Execution Time (ms)\")\n", + "plt.title(\"TDRAM\", fontsize = 9)\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_noDC['app']\n", + "gap = df_gap22_noDC['simSeconds'].astype(float) * 1000\n", + "gap_3hr = df_gap22_noDC_3hr['simSeconds'].astype(float) * 1000\n", + "gap_6hr = df_gap22_noDC_6hr['simSeconds'].astype(float) * 1000\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,1000])\n", + "\n", + "x = np.arange(6)*4+1\n", + "plt.plot(x, gap, label='1 hour', color=cmap(1))\n", + "plt.plot(x, gap_3hr, label='3 hour', color=cmap(2))\n", + "plt.plot(x, gap_6hr, label='6 hour', color=cmap(3))\n", + "plt.scatter(x, gap, color=cmap(1))\n", + "plt.scatter(x, gap_3hr, color=cmap(2))\n", + "plt.scatter(x, gap_6hr, color=cmap(3))\n", + "\n", + "app_npb = df_npbC_noDC['app']\n", + "npb = df_npbC_noDC['simSeconds'].astype(float) * 1000\n", + "npb_3hr = df_npbC_noDC_3hr['simSeconds'].astype(float) * 1000\n", + "npb_6hr = df_npbC_noDC_6hr['simSeconds'].astype(float) * 1000\n", + "x=np.arange(6,14)*4+1\n", + "plt.plot(x, npb, color=cmap(1))\n", + "plt.plot(x, npb_3hr, color=cmap(2))\n", + "plt.plot(x, npb_6hr, color=cmap(3))\n", + "plt.scatter(x, npb, color=cmap(1))\n", + "plt.scatter(x, npb_3hr, color=cmap(2))\n", + "plt.scatter(x, npb_6hr, color=cmap(3))\n", + "\n", + "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, 0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=23, color='black')\n", + "\n", + "plt.ylabel(\"Execution Time (ms)\")\n", + "plt.title(\"No DRAM $\", fontsize = 9)\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_noDC['app']\n", + "gap = df_gap22_noDC['simSeconds'].astype(float) * 1000\n", + "gap_3h = df_gap22_noDC_3hr['simSeconds'].astype(float) * 1000\n", + "gap_6hr = df_gap22_noDC_6hr['simSeconds'].astype(float) * 1000\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,1000])\n", + "\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*4, gap[i], width=1, color=cmap(1), label='1 hour' if i==0 else None)\n", + " plt.bar(i*4+1, gap_3h[i], width=1, color=cmap(2), label='3 hours' if i==0 else None)\n", + " plt.bar(i*4+2, gap_6hr[i], width=1, color=cmap(3), label='6 hours' if i==0 else None)\n", + "\n", + "offset = i*5-2\n", + "app_npb = df_npbC_noDC['app']\n", + "npb = df_npbC_noDC['simSeconds'].astype(float) * 1000\n", + "npb_3hr = df_npbC_noDC_3hr['simSeconds'].astype(float) * 1000\n", + "npb_6hr = df_npbC_noDC_6hr['simSeconds'].astype(float) * 1000\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*4+1, npb[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*4+2, npb_3hr[i], width=1, color=cmap(2))\n", + " plt.bar(offset+i*4+3, npb_6hr[i], width=1, color=cmap(3))\n", + "\n", + "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, 0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset-0.25, color='black')\n", + "\n", + "plt.ylabel(\"Execution Time (ms)\")\n", + "plt.title(\"No DRAM $\", fontsize = 9)\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAx4AAADOCAYAAACw7NSMAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAACWtUlEQVR4nOzdd1xTV//A8c9NQsLeWwFRHIAg4t5bq1Vr1bZ2qR3aPt3tYx9rl3ba5c9uW6t1dGuttlr3qHuBIiAORET23iNk3N8fUZQCisr2vF+vaHLvyc05AZL7veec75FkWZYRBEEQBEEQBEGoR4rGroAgCIIgCIIgCC2fCDwEQRAEQRAEQah3IvAQBEEQBEEQBKHeicBDEARBEARBEIR6JwIPQRAEQRAEQRDqnQg8BEEQBEEQBEGodyLwEARBEARBEASh3onAQxAEQRAEQRCEeicCD0EQBEEQBEEQ6p0IPARBEAShmZg+fXpjV0EQBOGmicBDEAShCbO2tq64KZVKNBpNxePRo0cDIEkSlpaW2Nra4ujoSJ8+ffj000/R6XQVx1m+fDlKpRJra2tsbGzw8/Nj4cKFVV6vuLgYW1tbevXqVWXf9OnTkSSJJUuWVNq+evVqJEliwoQJNbZDkiQiIiJu7k24VH9Jkpg1a1al7RMmTGDevHk3fdzp06ejVquxsbHBzs6ODh068OSTTxIfH1+p3OX32NraGjc3N6ZMmUJGRkaV4z366KNIksSpU6cqbf/nn3+QJIn+/ftX2q7VanFyckKSJPLy8m66HYIgCM2BCDwEQRCasKKioorbgAED+PDDDyseb9q0qaLcgQMHKCgoID09nQ8++IAVK1Ywbtw4ZFmuKBMUFERRURGFhYWsXLmS1157jZ07d1Z6vVWrVqFUKjl69CjR0dFV6tOxY0eWLVtWaduyZcvo1KlTHbe8KgcHBxYtWkRiYmKdHvepp56isLCQ/Px8tmzZglqtpmvXrlWChwMHDlBUVERMTAyZmZlVgqDCwkJWrVqFo6MjS5curfI6NjY2XLhwgdjY2Iptf/75J66urtet48qVK/H39+eXX37B1dWVQYMGkZube5MtFgRBaBwi8BAEQWhBzMzMGDRoEH/88Qe7d++uFJxcrW/fvgQGBhIeHl5p+9KlS3nkkUcYOHBgtSfPI0aMICEhgbNnzwKQkpLC0aNHr9nb0bNnz4rXtLa25v333wcgLCyMfv36YW9vT0BAAL/88ss12+bt7c2kSZOYO3dujWVu9Jj/5uvry+eff07v3r1rfB0nJycmTpxY5b377bffsLKy4sMPP+SHH36o1OMEoFAoePjhhysFbsuWLeORRx65Zp2Sk5N59NFH+b//+z/uv/9+EhISeP3111GpVDfUNkEQhMYmAg9BEIQWyNfXl27durF79+4q+2RZZs+ePURHR9OhQ4eK7WfOnGH//v1Mnz6dadOm8eOPP1JeXl7puUqlkqlTp/L9998DsGLFCu699140Gk2NdTly5Ahwpcfg1VdfJS8vjzvuuIMpU6aQmZnJokWLmDFjBvv3779mu95++21+++03YmJiquy72WNWZ/LkydW+dwDp6emsXr260nsHpqDtwQcfZMqUKRQXF7N+/foqz50+fTorV67EYDCQnJxMWFgYd9111zXrkpWVhSRJ9OvXDwALCwtGjBiBjY3NDbdLEAShMYnAQxAEoYVq1aoVOTk5FY+joqKwt7fH3NycQYMG8d///pfx48dX7F+6dCkhISEEBwczefJkSkpK+PPPP6scd/r06fzwww/o9XqWL19+3Sv21fn7779xcXHh2WefreileeCBB1ixYsU1n9emTRtmzpzJq6++WmfHrM6/3zuAAQMGYGNjg7u7O6WlpXz55ZcV+2JiYjh06BDTpk3D2tqau+++u9oeo44dO+Lj48PWrVtZsWIF99133zWDNjANkRs7dixBQUHs3r2bFStWkJWVdcNtEgRBaGwi8BAEQWihkpOTcXR0rHgcFBREXl4ehYWFvPHGG+zcuRO9Xg+AXq9n5cqVTJs2DTDNR6jp5LlDhw74+vry5ptvolar6d69+w3XLSkpiTZt2lTa1rZtW5KSkq773Ndee41du3Zx8ODBGzrm6NGjKybmXx7uVZN/v3cAe/fupbCwkIMHD5KUlERKSkrFvqVLl9KlSxe6dOkCwLRp09iyZQvJyclVjv3II4/w/fffVxu0Xbx4sVJCgYsXL6JQKFi7di1r166lVatWrFq1Cj8/vyrtFwRBaOpE4CEIgtACXbhwgfDwcAYPHlxln1qt5q233qK0tJSvv/4agA0bNpCens4777yDu7s77u7u/PXXX2zbtq3aydyPPPIIH3zwQa17OyRJqvS4devWXLhwoUqdW7dufd1jOTs78/LLLzN7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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_noDC['app']\n", + "\n", + "gap_noDC = df_gap22_noDC['simSeconds'].astype(float) * 1000\n", + "gap_noDC_3hr = df_gap22_noDC_3hr['simSeconds'].astype(float) * 1000\n", + "gap_noDC_6hr = df_gap22_noDC_6hr['simSeconds'].astype(float) * 1000\n", + "\n", + "gap_ram = df_gap22_dc_ram['simSeconds'].astype(float) * 1000\n", + "gap_ram_3hr = df_gap22_dc_ram_3hr['simSeconds'].astype(float) * 1000\n", + "gap_ram_6hr = df_gap22_dc_ram_6hr['simSeconds'].astype(float) * 1000\n", + "\n", + "gap_cas = df_gap22_dc_cas['simSeconds'].astype(float) * 1000\n", + "gap_cas_3hr = df_gap22_dc_cas_3hr['simSeconds'].astype(float) * 1000\n", + "gap_cas_6hr = df_gap22_dc_cas_6hr['simSeconds'].astype(float) * 1000\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "\n", + "x = np.arange(6)*4+1\n", + "plt.plot(x, gap_ram/gap_noDC, label='1 hour', color=cmap(1))\n", + "plt.plot(x, gap_ram_3hr/gap_noDC_3hr, label='3 hour', color=cmap(2))\n", + "plt.plot(x, gap_ram_6hr/gap_noDC_6hr, label='6 hour', color=cmap(3))\n", + "plt.scatter(x, gap_ram/gap_noDC, color=cmap(1))\n", + "plt.scatter(x, gap_ram_3hr/gap_noDC_3hr, color=cmap(2))\n", + "plt.scatter(x, gap_ram_6hr/gap_noDC_6hr, color=cmap(3))\n", + "\n", + "app_npb = df_npbC_noDC['app']\n", + "\n", + "npb_noDC = df_npbC_noDC['simSeconds'].astype(float) * 1000\n", + "npb_noDC_3hr = df_npbC_noDC_3hr['simSeconds'].astype(float) * 1000\n", + "npb_noDC_6hr = df_npbC_noDC_6hr['simSeconds'].astype(float) * 1000\n", + "\n", + "npb_ram = df_npbC_dc_ram['simSeconds'].astype(float) * 1000\n", + "npb_ram_3hr = df_npbC_dc_ram_3hr['simSeconds'].astype(float) * 1000\n", + "npb_ram_6hr = df_npbC_dc_ram_6hr['simSeconds'].astype(float) * 1000\n", + "\n", + "npb_cas = df_npbC_dc_cas['simSeconds'].astype(float) * 1000\n", + "npb_cas_3hr = df_npbC_dc_cas_3hr['simSeconds'].astype(float) * 1000\n", + "npb_cas_6hr = df_npbC_dc_cas_6hr['simSeconds'].astype(float) * 1000\n", + "\n", + "x=np.arange(6,14)*4+1\n", + "plt.plot(x, npb_ram/npb_noDC, color=cmap(1))\n", + "plt.plot(x, npb_ram_3hr/npb_noDC_3hr, color=cmap(2))\n", + "plt.plot(x, npb_ram_6hr/npb_noDC_6hr, color=cmap(3))\n", + "plt.scatter(x, npb_ram/npb_noDC, color=cmap(1))\n", + "plt.scatter(x, npb_ram_3hr/npb_noDC_3hr, color=cmap(2))\n", + "plt.scatter(x, npb_ram_6hr/npb_noDC_6hr, color=cmap(3))\n", + "\n", + "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, 0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=23, color='black')\n", + "\n", + "plt.ylabel(\"Speedup\")\n", + "plt.title(\"TDRAM to No-DRAM-$\", fontsize = 9)\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "\n", + "x = np.arange(6)*4+1\n", + "plt.plot(x, gap_cas/gap_noDC, label='1 hour', color=cmap(1))\n", + "plt.plot(x, gap_cas_3hr/gap_noDC_3hr, label='3 hour', color=cmap(2))\n", + "plt.plot(x, gap_cas_6hr/gap_noDC_6hr, label='6 hour', color=cmap(3))\n", + "plt.scatter(x, gap_cas/gap_noDC, color=cmap(1))\n", + "plt.scatter(x, gap_cas_3hr/gap_noDC_3hr, color=cmap(2))\n", + "plt.scatter(x, gap_cas_6hr/gap_noDC_6hr, color=cmap(3))\n", + "\n", + "x=np.arange(6,14)*4+1\n", + "plt.plot(x, npb_cas/npb_noDC, color=cmap(1))\n", + "plt.plot(x, npb_cas_3hr/npb_noDC_3hr, color=cmap(2))\n", + "plt.plot(x, npb_cas_6hr/npb_noDC_6hr, color=cmap(3))\n", + "plt.scatter(x, npb_cas/npb_noDC, color=cmap(1))\n", + "plt.scatter(x, npb_cas_3hr/npb_noDC_3hr, color=cmap(2))\n", + "plt.scatter(x, npb_cas_6hr/npb_noDC_6hr, color=cmap(3))\n", + "\n", + "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, 0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=23, color='black')\n", + "\n", + "plt.ylabel(\"Speedup\")\n", + "plt.title(\"Cascade Lake to No-DRAM-$\", fontsize = 9)\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/defMemCtrlr.py b/defMemCtrlr.py new file mode 100644 index 0000000000..b7b2cac644 --- /dev/null +++ b/defMemCtrlr.py @@ -0,0 +1,77 @@ +from m5.objects import * +import m5 +import argparse +from m5.objects.DRAMInterface import * +from m5.objects.NVMInterface import * + +args = argparse.ArgumentParser() + +args.add_argument( + "device", + type = str, + help = "Memory device to use as a dram cache (local memory)" +) + +args.add_argument( + "traffic_mode", + type = str, + help = "Traffic type to use" +) + +options = args.parse_args() + +system = System() +system.clk_domain = SrcClockDomain() +system.clk_domain.clock = "4GHz" +system.clk_domain.voltage_domain = VoltageDomain() +system.mem_mode = 'timing' + +system.generator = PyTrafficGen() + +system.mem_ctrl = MemCtrl() +system.mem_ctrl.dram = eval(options.device)(range=AddrRange('8GB')) + +system.mem_ranges = [AddrRange('8GB')] + +system.membus = SystemXBar() +system.membus.cpu_side_ports = system.generator.port +system.mem_ctrl.port = system.membus.mem_side_ports +system.membus.frontend_latency = 100 #options.xbarLatency +system.membus.response_latency = 100 #options.xbarLatency + +def createRandomTraffic(tgen): + yield tgen.createRandom(1000000000, # duration + 0, # min_addr + AddrRange("1GB").end, # max_adr + 64, # block_size + 1000, # min_period + 1000, # max_period + 0, # rd_perc + 0) # data_limit + yield tgen.createExit(0) + +def createLinearTraffic(tgen): + yield tgen.createLinear(0, # duration + 0, # min_addr + AddrRange("1GB").end, # max_adr + 64, # block_size + 1000, # min_period + 1000, # max_period + 100, # rd_perc + 104857600) # data_limit + yield tgen.createExit(0) + + +root = Root(full_system=False, system=system) + +m5.instantiate() + +if options.traffic_mode == 'linear': + system.generator.start(createLinearTraffic(system.generator)) +elif options.traffic_mode == 'random': + system.generator.start(createRandomTraffic(system.generator)) +else: + print('Wrong traffic type! Exiting!') + exit() + +exit_event = m5.simulate() \ No newline at end of file diff --git a/dr_trace_player.py b/dr_trace_player.py new file mode 100644 index 0000000000..7eaac2a78d --- /dev/null +++ b/dr_trace_player.py @@ -0,0 +1,78 @@ +# Copyright (c) 2021 The Regents of the University of California +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +from typing import Optional +from pathlib import Path + +from m5.objects import DRTraceReader +from gem5.utils.override import overrides + +from gem5.components.processors.abstract_generator import AbstractGenerator +from gem5.components.boards.abstract_board import AbstractBoard +from dr_trace_player_core import DRTracePlayerCore + + +class DRTracePlayerGenerator(AbstractGenerator): + def __init__( + self, + trace_directory: Path, + num_cores: int, + max_ipc: int, + max_outstanding_reqs: int, + clk_freq: Optional[str] = None, + ): + super().__init__( + cores=[ + DRTracePlayerCore( + max_ipc=max_ipc, + max_outstanding_reqs=max_outstanding_reqs, + clk_freq=clk_freq, + ) + for _ in range(num_cores) + ] + ) + + self.reader = DRTraceReader( + directory=trace_directory, num_players=num_cores + ) + + for core in self.get_cores(): + core.set_reader(self.reader) + + @overrides(AbstractGenerator) + def start_traffic(self): + """ + Since DRTracePlayer does not need a call to start_traffic to + start generation. This function is just pass. + """ + pass + + @overrides(AbstractGenerator) + def incorporate_processor(self, board: AbstractBoard) -> None: + super().incorporate_processor(board) + for core in self.get_cores(): + core.set_memory_range(board.mem_ranges[0]) diff --git a/dr_trace_player_core.py b/dr_trace_player_core.py new file mode 100644 index 0000000000..fd32a7ce4b --- /dev/null +++ b/dr_trace_player_core.py @@ -0,0 +1,72 @@ +# Copyright (c) 2021 The Regents of the University of California +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +from typing import Optional + +from gem5.components.processors.abstract_generator_core import ( + AbstractGeneratorCore, +) +from gem5.components.processors.abstract_core import AbstractCore +from gem5.utils.override import overrides + +from m5.objects import ( + AddrRange, + DRTracePlayer, + DRTraceReader, + Port, + SrcClockDomain, + VoltageDomain, +) + + +class DRTracePlayerCore(AbstractGeneratorCore): + def __init__( + self, + max_ipc: int, + max_outstanding_reqs: int, + clk_freq: Optional[str] = None, + ): + super().__init__() + self.player = DRTracePlayer( + max_ipc=max_ipc, + max_outstanding_reqs=max_outstanding_reqs, + send_data=True, + ) + if clk_freq: + clock_domain = SrcClockDomain( + clock=clk_freq, voltage_domain=VoltageDomain() + ) + self.generator.clk_domain = clock_domain + + @overrides(AbstractCore) + def connect_dcache(self, port: Port) -> None: + self.player.port = port + + def set_reader(self, reader: DRTraceReader): + self.player.reader = reader + + def set_memory_range(self, range: AddrRange): + self.player.compress_address_range = range diff --git a/drtrace-stdlib.py b/drtrace-stdlib.py new file mode 100644 index 0000000000..c7625f7e9c --- /dev/null +++ b/drtrace-stdlib.py @@ -0,0 +1,109 @@ +import m5 +import argparse +from m5.objects import * + +from gem5.components.boards.test_board import TestBoard +from gem5.components.memory.hbm import HighBandwidthMemory +from gem5.components.memory.single_channel import SingleChannelDDR4_2400 +from gem5.components.memory.multi_channel import DualChannelDDR4_2400 +from gem5.components.memory.dram_interfaces.hbm import HBM_2000_4H_1x64 + +from gem5.components.cachehierarchies.ruby.mesi_two_level_cache_hierarchy import ( + MESITwoLevelCacheHierarchy, +) + +from gem5.components.cachehierarchies.classic.private_l1_shared_l2_cache_hierarchy import( + PrivateL1SharedL2CacheHierarchy, +) + +from gem5.simulate.simulator import Simulator + +from dr_trace_player import DRTracePlayerGenerator + +parser = argparse.ArgumentParser( + description="A script to run google traces." +) + +benchmark_choices = ["charlie", "delta", "merced", "whiskey"] + +parser.add_argument( + "--path", + type=str, + required=True, + help="Main directory containing the traces.", +) + +parser.add_argument( + "--workload", + type=str, + required=True, + help="Input the benchmark program to execute.", + choices=benchmark_choices, +) + +parser.add_argument( + "--players", + type=int, + required=True, + help="Input the number of players to use.", +) + +parser.add_argument( + "--ruby", + type=int, + required=True, + help="Use with ruby or classic caches", +) + + +args = parser.parse_args() + +generator = DRTracePlayerGenerator( + "{}/{}/".format(args.path, args.workload), + num_cores=8, + max_ipc=8, + max_outstanding_reqs=16, +) + +if args.ruby == 1: + cache_hierarchy = MESITwoLevelCacheHierarchy( + l1d_size="512kB", + l1d_assoc=8, + l1i_size="32kB", + l1i_assoc=2, + l2_size="1MB", + l2_assoc=16, + num_l2_banks=8, + ) +elif args.ruby == 0: + cache_hierarchy = PrivateL1SharedL2CacheHierarchy( + l1d_size="512kB", + l1d_assoc=8, + l1i_size="32kB", + l1i_assoc=2, + l2_size="1MB", + l2_assoc=16, + ) +else: + print("WRONG RUBY OPTION") + exit() + +memory = DualChannelDDR4_2400(size="3GB") + +board = TestBoard( + clk_freq="5GHz", # Ignored for these generators + generator=generator, # We pass the traffic generator as the processor. + memory=memory, + # With no cache hierarchy the test board will directly connect the + # generator to the memory + cache_hierarchy=cache_hierarchy, +) + +root = Root(full_system=False, system=board) + +board._pre_instantiate() +m5.instantiate() +exit_event = m5.simulate(100000000) + +#simulator = Simulator(board=board) +#simulator.run(100000000000) diff --git a/gapbs_checkpoint.sh b/gapbs_checkpoint.sh new file mode 100755 index 0000000000..2ff694c74d --- /dev/null +++ b/gapbs_checkpoint.sh @@ -0,0 +1,22 @@ + +#!/bin/bash + +# $1 is the size of the gapbs to run + +if [ $1 != '22'] && [ $1 != '25'] +then + echo "Run with different size" + exit +fi + +bms=(bc bfs cc pr tc sssp) + +if [! -d checkpoints-gapbs]; then + mkdir -p checkpoints-gapbs; +fi + +for bm in "${bms[@]}" +do +echo $bm +build/RISCV/gem5.opt -re --outdir=$bm.timing Octopi-cache/riscv-2channel-1ccd-checkpoint-timing-gapbs.py --benchmark $bm --size $1 --ckpt_path checkpoints-gapbs/$bm.timing/$bm & +done diff --git a/gapbs_run.sh b/gapbs_run.sh new file mode 100755 index 0000000000..6755d567eb --- /dev/null +++ b/gapbs_run.sh @@ -0,0 +1,22 @@ + +#!/bin/bash + +# $1 is the size of the gapbs to run + +if [ $1 != '22'] && [ $1 != '25'] +then + echo "Run with different size" + exit +fi + +bms=(bc bfs cc pr tc sssp) + +if [! -d GAPBS_Base]; then + mkdir -p GAPBS_Base; +fi + +for bm in "${bms[@]}" +do +echo $bm +M5_OVERRIDE_PY_SOURCE=TRUE build/RISCV/gem5.opt -re --outdir=GAPBS_Base/$bm.22.O3 Octopi-cache/restore-npb-gapbs-looppoint.py --benchmark $bm --size $1 --ckpt_path /projects/gem5/dramcache/jason-checkpoints/gapbs/$1/$bm/ckpt & +done diff --git a/googleTracesRun.sh b/googleTracesRun.sh new file mode 100755 index 0000000000..e9d125b202 --- /dev/null +++ b/googleTracesRun.sh @@ -0,0 +1,4 @@ +build/X86_MESI_Two_Level/gem5.opt --outdir=gtResults/1/ram/charlie configs-drtrace/drtrace_new.py /projects/google-traces/ charlie 8 Rambus 1 1GiB 8GiB 0 0 & +build/X86_MESI_Two_Level/gem5.opt --outdir=gtResults/1/ram/delta configs-drtrace/drtrace_new.py /projects/google-traces/ delta 8 Rambus 1 1GiB 8GiB 0 0 & +build/X86_MESI_Two_Level/gem5.opt --outdir=gtResults/1/ram/merced configs-drtrace/drtrace_new.py /projects/google-traces/ merced 8 Rambus 1 1GiB 8GiB 0 0 & +build/X86_MESI_Two_Level/gem5.opt --outdir=gtResults/1/ram/whiskey configs-drtrace/drtrace_new.py /projects/google-traces/ whiskey 8 Rambus 1 1GiB 8GiB 0 0 & \ No newline at end of file diff --git a/link.ipynb b/link.ipynb new file mode 100644 index 0000000000..e0f8ddf91f --- /dev/null +++ b/link.ipynb @@ -0,0 +1,1604 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import sys\n", + "from matplotlib import pyplot as plt\n", + "import os\n", + "\n", + "cmap = plt.get_cmap('Set1')\n", + "\n", + "def getStat(filename, stat, suite, app, i, j, k):\n", + " filename = os.path.join(filename).replace('\\\\','/')\n", + " #print(stat)\n", + " #print(filename)\n", + " try:\n", + " if suite==\"gapbs\" and app==\"bfs\" :\n", + " x = 0\n", + " with open(filename) as f:\n", + " readlines = f.readlines()\n", + " for l in readlines:\n", + " if stat in l and x < (i-1):\n", + " x = x+1\n", + " elif stat in l and x == (i-1):\n", + " return l\n", + " return 0.0 #for cases where stat was not found\n", + " elif suite==\"gapbs\" and app==\"cc\" :\n", + " x = 0\n", + " with open(filename) as f:\n", + " readlines = f.readlines()\n", + " for l in readlines:\n", + " if stat in l and x < (j-1):\n", + " x = x+1\n", + " elif stat in l and x == (j-1):\n", + " return l\n", + " return 0.0 #for cases where stat was not found\n", + " elif suite==\"gapbs\" and app==\"sssp\" :\n", + " x = 0\n", + " with open(filename) as f:\n", + " readlines = f.readlines()\n", + " for l in readlines:\n", + " if stat in l and x < (k-1):\n", + " x = x+1\n", + " elif stat in l and x == (k-1):\n", + " return l\n", + " return 0.0 #for cases where stat was not found\n", + " # elif suite==\"npb\" and app==\"ep\" :\n", + " # x = 0\n", + " # with open(filename) as f:\n", + " # readlines = f.readlines()\n", + " # for l in readlines:\n", + " # if stat in l and x < (3-1):\n", + " # x = x+1\n", + " # elif stat in l and x == (3-1):\n", + " # return l\n", + " # return 0.0 #for cases where stat was not found\n", + " else: \n", + " x = 0\n", + " with open(filename) as f:\n", + " readlines = f.readlines()\n", + " for l in readlines:\n", + " if stat in l and x < 9:\n", + " x = x+1\n", + " elif stat in l and x == 9:\n", + " return l\n", + " return 0.0 #for cases where stat was not found\n", + " except: #for cases where the file was not found\n", + " return 0.0\n", + "\n", + "Stats = ['simSeconds ',\n", + "'hostSeconds ',\n", + "'system.mem_ctrl.readReqs ',\n", + "'system.mem_ctrl.writeReqs ',\n", + "'system.mem_ctrl.servicedByWrQ ',\n", + "'system.mem_ctrl.mergedWrBursts ',\n", + "'system.mem_ctrl.numTotHits ',\n", + "'system.mem_ctrl.numTotMisses ',\n", + "'system.mem_ctrl.numColdMisses ',\n", + "'system.mem_ctrl.numHotMisses ',\n", + "'system.mem_ctrl.numRdMissClean ',\n", + "'system.mem_ctrl.numRdMissDirty ',\n", + "'system.mem_ctrl.numRdHit ',\n", + "'system.mem_ctrl.numWrMissClean ',\n", + "'system.mem_ctrl.numWrMissDirty ',\n", + "'system.mem_ctrl.numWrHit ',\n", + "'system.mem_ctrl.numRdHitDirty ',\n", + "'system.mem_ctrl.numRdHitClean ',\n", + "'system.mem_ctrl.numWrHitDirty ',\n", + "'system.mem_ctrl.numWrHitClean ',\n", + "'system.o3Cpu0.thread_0.numInsts ',\n", + "'system.o3Cpu1.thread_0.numInsts ',\n", + "'system.o3Cpu2.thread_0.numInsts ',\n", + "'system.o3Cpu3.thread_0.numInsts ',\n", + "'system.o3Cpu4.thread_0.numInsts ',\n", + "'system.o3Cpu5.thread_0.numInsts ',\n", + "'system.o3Cpu6.thread_0.numInsts ',\n", + "'system.o3Cpu7.thread_0.numInsts ',\n", + "'system.mem_ctrl.avgRdBWSys ',\n", + "'system.mem_ctrl.avgWrBWSys ',\n", + "'system.mem_ctrl.avgORBLen ',\n", + "'system.far_mem_ctrl.avgRdBWSys ',\n", + "'system.far_mem_ctrl.avgWrBWSys ',\n", + "'system.loc_mem_ctrl.avgRdBWSys ',\n", + "'system.loc_mem_ctrl.avgWrBWSys ',\n", + "'system.loc_mem_ctrl.dram.readBursts ',\n", + "'system.loc_mem_ctrl.dram.writeBursts ',\n", + "'system.loc_mem_ctrl.dram_2.readBursts ',\n", + "'system.loc_mem_ctrl.dram_2.writeBursts ',\n", + "'system.far_mem_ctrl.dram.readBursts ',\n", + "'system.far_mem_ctrl.dram.writeBursts ',\n", + "'system.loc_mem_ctrl.dram.avgRdBW ',\n", + "'system.loc_mem_ctrl.dram.avgWrBW ',\n", + "'system.loc_mem_ctrl.dram_2.avgRdBW ',\n", + "'system.loc_mem_ctrl.dram_2.avgWrBW ',\n", + "'system.far_mem_ctrl.dram.avgRdBW ',\n", + "'system.far_mem_ctrl.dram.avgWrBW ',\n", + "'system.loc_mem_ctrl.dram.busUtil ',\n", + "'system.loc_mem_ctrl.dram.busUtilRead ',\n", + "'system.loc_mem_ctrl.dram.busUtilWrite ',\n", + "'system.loc_mem_ctrl.dram_2.busUtil ',\n", + "'system.loc_mem_ctrl.dram_2.busUtilRead ',\n", + "'system.loc_mem_ctrl.dram_2.busUtilWrite ',\n", + "'system.far_mem_ctrl.dram.busUtil ',\n", + "'system.far_mem_ctrl.dram.busUtilRead ',\n", + "'system.far_mem_ctrl.dram.busUtilWrite ',\n", + "'system.far_mem_ctrl.dram.bytesRead ',\n", + "'system.far_mem_ctrl.dram.bytesWritten ',\n", + "'system.loc_mem_ctrl.dram.bytesRead ',\n", + "'system.loc_mem_ctrl.dram.bytesWritten ',\n", + "'system.loc_mem_ctrl.dram_2.bytesRead ',\n", + "'system.loc_mem_ctrl.dram_2.bytesWritten ',\n", + "'system.mem_ctrl.avgTimeTagCheckRes ',\n", + "'system.mem_ctrl.avgTimeTagCheckResRd ',\n", + "'system.mem_ctrl.avgTimeTagCheckResWr ',\n", + "'system.mem_ctrl.avgPktRespTimeRd ',\n", + "'system.mem_ctrl.avgPktRespTimeWr ',\n", + "'system.mem_ctrl.avgPktORBTime ',\n", + "'system.mem_ctrl.avgPktORBTimeRd ',\n", + "'system.mem_ctrl.avgPktORBTimeWr '\n", + " ]\n", + "\n", + "dfCols = [\n", + " 'app',\n", + " 'simSeconds',\n", + " 'hostSeconds',\n", + " 'readReqs',\n", + " 'writeReqs',\n", + " 'servicedByWrQ',\n", + " 'mergedWrBursts',\n", + " 'numTotHits',\n", + " 'numTotMisses',\n", + " 'numColdMisses',\n", + " 'numHotMisses',\n", + " 'numRdMissClean',\n", + " 'numRdMissDirty',\n", + " 'numRdHit',\n", + " 'numWrMissClean',\n", + " 'numWrMissDirty',\n", + " 'numWrHit',\n", + " 'numRdHitDirty',\n", + " 'numRdHitClean',\n", + " 'numWrHitDirty',\n", + " 'numWrHitClean',\n", + " 'numInsts0',\n", + " 'numInsts1',\n", + " 'numInsts2',\n", + " 'numInsts3',\n", + " 'numInsts4',\n", + " 'numInsts5',\n", + " 'numInsts6',\n", + " 'numInsts7',\n", + " 'avgRdBWSys',\n", + " 'avgWrBWSys',\n", + " 'avgORBLen',\n", + " 'farAvgRdBWSys',\n", + " 'farAvgWrBWSys',\n", + " 'locAvgRdBWSys',\n", + " 'locAvgWrBWSys',\n", + " 'readBursts1',\n", + " 'writeBursts1',\n", + " 'readBursts2',\n", + " 'writeBursts2',\n", + " 'readBursts3',\n", + " 'writeBursts3',\n", + " 'loc1AvgRdBW',\n", + " 'loc1AvgWrBW',\n", + " 'loc2AvgRdBW',\n", + " 'loc2AvgWrBW',\n", + " 'farAvgRdBW',\n", + " 'farAvgWrBW',\n", + " 'loc1BusUtil',\n", + " 'loc1BusUtilRead',\n", + " 'loc1BusUtilWrite',\n", + " 'loc2BusUtil',\n", + " 'loc2BusUtilRead',\n", + " 'loc2BusUtilWrite',\n", + " 'farBusUtil',\n", + " 'farBusUtilRead',\n", + " 'farBusUtilWrite',\n", + " 'farBytesRead',\n", + " 'farBytesWritten',\n", + " 'loc1BytesRead',\n", + " 'loc1BytesWritten',\n", + " 'loc2BytesRead',\n", + " 'loc2BytesWritten',\n", + " 'avgTimeTagCheckRes',\n", + " 'avgTimeTagCheckResRd',\n", + " 'avgTimeTagCheckResWr',\n", + " 'avgPktRespTimeRd',\n", + " 'avgPktRespTimeWr',\n", + " 'avgPktORBTime',\n", + " 'avgPktORBTimeRd',\n", + " 'avgPktORBTimeWr'\n", + "\n", + " ]\n", + "\n", + "def gmean(x, size):\n", + " y = 1\n", + " for i in range(size):\n", + " y = x[i] * y\n", + " return y**(1/size)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/GAPBS/50ns'\n", + "\n", + "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 29, 28, 12)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_g_ram_50ns = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_g_ram_50ns['totNumInsts'] = df_g_ram_50ns['numInsts0'].astype(int)+df_g_ram_50ns['numInsts1'].astype(int)+df_g_ram_50ns['numInsts2'].astype(int)+df_g_ram_50ns['numInsts3'].astype(int)+df_g_ram_50ns['numInsts4'].astype(int)+df_g_ram_50ns['numInsts5'].astype(int)+df_g_ram_50ns['numInsts6'].astype(int)+df_g_ram_50ns['numInsts7'].astype(int)\n", + "df_g_ram_50ns['totBW'] = (df_g_ram_50ns['avgRdBWSys'].astype(float)+df_g_ram_50ns['avgWrBWSys'].astype(float))/1000000000\n", + "df_g_ram_50ns['coldRate'] = (df_g_ram_50ns['numColdMisses'].astype(float) / df_g_ram_50ns['numTotMisses'].astype(float)) *100\n", + "df_g_ram_50ns['injRate'] = (df_g_ram_50ns['readReqs'].astype(float) + df_g_ram_50ns['writeReqs'].astype(float))*64/1000000000 / df_g_ram_50ns['simSeconds'].astype(float)\n", + "df_g_ram_50ns['BIPS'] = (df_g_ram_50ns['totNumInsts'].astype(float)/1000000000)/df_g_ram_50ns['simSeconds'].astype(float)\n", + "\n", + "df_g_ram_50ns['accAmp'] = (df_g_ram_50ns['farBytesRead'].astype(float) + df_g_ram_50ns['farBytesWritten'].astype(float) +\n", + " df_g_ram_50ns['loc1BytesRead'].astype(float) + df_g_ram_50ns['loc1BytesWritten'].astype(float) + \n", + " df_g_ram_50ns['loc2BytesRead'].astype(float) + df_g_ram_50ns['loc2BytesWritten'].astype(float)) / (df_g_ram_50ns['readReqs'].astype(float) * 64 + df_g_ram_50ns['writeReqs'].astype(float) * 64)\n", + "\n", + "df_g_ram_50ns['BWBloat'] = (df_g_ram_50ns['loc1AvgRdBW'].astype(float) + df_g_ram_50ns['loc1AvgWrBW'].astype(float) +\n", + " df_g_ram_50ns['loc2AvgRdBW'].astype(float) + df_g_ram_50ns['loc2AvgWrBW'].astype(float) +\n", + " df_g_ram_50ns['farAvgRdBW'].astype(float) + df_g_ram_50ns['farAvgWrBW'].astype(float)) / ((df_g_ram_50ns['avgRdBWSys'].astype(float) + df_g_ram_50ns['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_g_ram_50ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_ram_50ns.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/NPB/50ns'\n", + "\n", + "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_n_ram_50ns = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_n_ram_50ns['totNumInsts'] = df_n_ram_50ns['numInsts0'].astype(int)+df_n_ram_50ns['numInsts1'].astype(int)+df_n_ram_50ns['numInsts2'].astype(int)+df_n_ram_50ns['numInsts3'].astype(int)+df_n_ram_50ns['numInsts4'].astype(int)+df_n_ram_50ns['numInsts5'].astype(int)+df_n_ram_50ns['numInsts6'].astype(int)+df_n_ram_50ns['numInsts7'].astype(int)\n", + "df_n_ram_50ns['totBW'] = (df_n_ram_50ns['avgRdBWSys'].astype(float)+df_n_ram_50ns['avgWrBWSys'].astype(float))/1000000000\n", + "df_n_ram_50ns['coldRate'] = (df_n_ram_50ns['numColdMisses'].astype(float) / df_n_ram_50ns['numTotMisses'].astype(float)) *100\n", + "df_n_ram_50ns['injRate'] = (df_n_ram_50ns['readReqs'].astype(float) + df_n_ram_50ns['writeReqs'].astype(float))*64/1000000000 / df_n_ram_50ns['simSeconds'].astype(float)\n", + "df_n_ram_50ns['BIPS'] = (df_n_ram_50ns['totNumInsts'].astype(float)/1000000000)/df_n_ram_50ns['simSeconds'].astype(float)\n", + "\n", + "df_n_ram_50ns['accAmp'] = (df_n_ram_50ns['farBytesRead'].astype(float) + df_n_ram_50ns['farBytesWritten'].astype(float) +\n", + " df_n_ram_50ns['loc1BytesRead'].astype(float) + df_n_ram_50ns['loc1BytesWritten'].astype(float) + \n", + " df_n_ram_50ns['loc2BytesRead'].astype(float) + df_n_ram_50ns['loc2BytesWritten'].astype(float)) / (df_n_ram_50ns['readReqs'].astype(float) * 64 + df_n_ram_50ns['writeReqs'].astype(float) * 64)\n", + "\n", + "df_n_ram_50ns['BWBloat'] = (df_n_ram_50ns['loc1AvgRdBW'].astype(float) + df_n_ram_50ns['loc1AvgWrBW'].astype(float) +\n", + " df_n_ram_50ns['loc2AvgRdBW'].astype(float) + df_n_ram_50ns['loc2AvgWrBW'].astype(float) +\n", + " df_n_ram_50ns['farAvgRdBW'].astype(float) + df_n_ram_50ns['farAvgWrBW'].astype(float)) / ((df_n_ram_50ns['avgRdBWSys'].astype(float) + df_n_ram_50ns['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_n_ram_50ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_ram_50ns.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/GAPBS/100ns'\n", + "\n", + "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 27, 27, 12)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_g_ram_100ns = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_g_ram_100ns['totNumInsts'] = df_g_ram_100ns['numInsts0'].astype(int)+df_g_ram_100ns['numInsts1'].astype(int)+df_g_ram_100ns['numInsts2'].astype(int)+df_g_ram_100ns['numInsts3'].astype(int)+df_g_ram_100ns['numInsts4'].astype(int)+df_g_ram_100ns['numInsts5'].astype(int)+df_g_ram_100ns['numInsts6'].astype(int)+df_g_ram_100ns['numInsts7'].astype(int)\n", + "df_g_ram_100ns['totBW'] = (df_g_ram_100ns['avgRdBWSys'].astype(float)+df_g_ram_100ns['avgWrBWSys'].astype(float))/1000000000\n", + "df_g_ram_100ns['coldRate'] = (df_g_ram_100ns['numColdMisses'].astype(float) / df_g_ram_100ns['numTotMisses'].astype(float)) *100\n", + "df_g_ram_100ns['injRate'] = (df_g_ram_100ns['readReqs'].astype(float) + df_g_ram_100ns['writeReqs'].astype(float))*64/1000000000 / df_g_ram_100ns['simSeconds'].astype(float)\n", + "df_g_ram_100ns['BIPS'] = (df_g_ram_100ns['totNumInsts'].astype(float)/1000000000)/df_g_ram_100ns['simSeconds'].astype(float)\n", + "\n", + "df_g_ram_100ns['accAmp'] = (df_g_ram_100ns['farBytesRead'].astype(float) + df_g_ram_100ns['farBytesWritten'].astype(float) +\n", + " df_g_ram_100ns['loc1BytesRead'].astype(float) + df_g_ram_100ns['loc1BytesWritten'].astype(float) + \n", + " df_g_ram_100ns['loc2BytesRead'].astype(float) + df_g_ram_100ns['loc2BytesWritten'].astype(float)) / (df_g_ram_100ns['readReqs'].astype(float) * 64 + df_g_ram_100ns['writeReqs'].astype(float) * 64)\n", + "\n", + "df_g_ram_100ns['BWBloat'] = (df_g_ram_100ns['loc1AvgRdBW'].astype(float) + df_g_ram_100ns['loc1AvgWrBW'].astype(float) +\n", + " df_g_ram_100ns['loc2AvgRdBW'].astype(float) + df_g_ram_100ns['loc2AvgWrBW'].astype(float) +\n", + " df_g_ram_100ns['farAvgRdBW'].astype(float) + df_g_ram_100ns['farAvgWrBW'].astype(float)) / ((df_g_ram_100ns['avgRdBWSys'].astype(float) + df_g_ram_100ns['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_g_ram_100ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_ram_100ns.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/NPB/100ns'\n", + "\n", + "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_n_ram_100ns = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_n_ram_100ns['totNumInsts'] = df_n_ram_100ns['numInsts0'].astype(int)+df_n_ram_100ns['numInsts1'].astype(int)+df_n_ram_100ns['numInsts2'].astype(int)+df_n_ram_100ns['numInsts3'].astype(int)+df_n_ram_100ns['numInsts4'].astype(int)+df_n_ram_100ns['numInsts5'].astype(int)+df_n_ram_100ns['numInsts6'].astype(int)+df_n_ram_100ns['numInsts7'].astype(int)\n", + "df_n_ram_100ns['totBW'] = (df_n_ram_100ns['avgRdBWSys'].astype(float)+df_n_ram_100ns['avgWrBWSys'].astype(float))/1000000000\n", + "df_n_ram_100ns['coldRate'] = (df_n_ram_100ns['numColdMisses'].astype(float) / df_n_ram_100ns['numTotMisses'].astype(float)) *100\n", + "df_n_ram_100ns['injRate'] = (df_n_ram_100ns['readReqs'].astype(float) + df_n_ram_100ns['writeReqs'].astype(float))*64/1000000000 / df_n_ram_100ns['simSeconds'].astype(float)\n", + "df_n_ram_100ns['BIPS'] = (df_n_ram_100ns['totNumInsts'].astype(float)/1000000000)/df_n_ram_100ns['simSeconds'].astype(float)\n", + "\n", + "df_n_ram_100ns['accAmp'] = (df_n_ram_100ns['farBytesRead'].astype(float) + df_n_ram_100ns['farBytesWritten'].astype(float) +\n", + " df_n_ram_100ns['loc1BytesRead'].astype(float) + df_n_ram_100ns['loc1BytesWritten'].astype(float) + \n", + " df_n_ram_100ns['loc2BytesRead'].astype(float) + df_n_ram_100ns['loc2BytesWritten'].astype(float)) / (df_n_ram_100ns['readReqs'].astype(float) * 64 + df_n_ram_100ns['writeReqs'].astype(float) * 64)\n", + "\n", + "df_n_ram_100ns['BWBloat'] = (df_n_ram_100ns['loc1AvgRdBW'].astype(float) + df_n_ram_100ns['loc1AvgWrBW'].astype(float) +\n", + " df_n_ram_100ns['loc2AvgRdBW'].astype(float) + df_n_ram_100ns['loc2AvgWrBW'].astype(float) +\n", + " df_n_ram_100ns['farAvgRdBW'].astype(float) + df_n_ram_100ns['farAvgWrBW'].astype(float)) / ((df_n_ram_100ns['avgRdBWSys'].astype(float) + df_n_ram_100ns['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_n_ram_100ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_ram_100ns.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/GAPBS/250ns'\n", + "\n", + "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 26, 21, 10)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_g_ram_250ns = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_g_ram_250ns['totNumInsts'] = df_g_ram_250ns['numInsts0'].astype(int)+df_g_ram_250ns['numInsts1'].astype(int)+df_g_ram_250ns['numInsts2'].astype(int)+df_g_ram_250ns['numInsts3'].astype(int)+df_g_ram_250ns['numInsts4'].astype(int)+df_g_ram_250ns['numInsts5'].astype(int)+df_g_ram_250ns['numInsts6'].astype(int)+df_g_ram_250ns['numInsts7'].astype(int)\n", + "df_g_ram_250ns['totBW'] = (df_g_ram_250ns['avgRdBWSys'].astype(float)+df_g_ram_250ns['avgWrBWSys'].astype(float))/1000000000\n", + "df_g_ram_250ns['coldRate'] = (df_g_ram_250ns['numColdMisses'].astype(float) / df_g_ram_250ns['numTotMisses'].astype(float)) *100\n", + "df_g_ram_250ns['injRate'] = (df_g_ram_250ns['readReqs'].astype(float) + df_g_ram_250ns['writeReqs'].astype(float))*64/1000000000 / df_g_ram_250ns['simSeconds'].astype(float)\n", + "df_g_ram_250ns['BIPS'] = (df_g_ram_250ns['totNumInsts'].astype(float)/1000000000)/df_g_ram_250ns['simSeconds'].astype(float)\n", + "\n", + "df_g_ram_250ns['accAmp'] = (df_g_ram_250ns['farBytesRead'].astype(float) + df_g_ram_250ns['farBytesWritten'].astype(float) +\n", + " df_g_ram_250ns['loc1BytesRead'].astype(float) + df_g_ram_250ns['loc1BytesWritten'].astype(float) + \n", + " df_g_ram_250ns['loc2BytesRead'].astype(float) + df_g_ram_250ns['loc2BytesWritten'].astype(float)) / (df_g_ram_250ns['readReqs'].astype(float) * 64 + df_g_ram_250ns['writeReqs'].astype(float) * 64)\n", + "\n", + "df_g_ram_250ns['BWBloat'] = (df_g_ram_250ns['loc1AvgRdBW'].astype(float) + df_g_ram_250ns['loc1AvgWrBW'].astype(float) +\n", + " df_g_ram_250ns['loc2AvgRdBW'].astype(float) + df_g_ram_250ns['loc2AvgWrBW'].astype(float) +\n", + " df_g_ram_250ns['farAvgRdBW'].astype(float) + df_g_ram_250ns['farAvgWrBW'].astype(float)) / ((df_g_ram_250ns['avgRdBWSys'].astype(float) + df_g_ram_250ns['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_g_ram_250ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_ram_250ns.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/NPB/250ns'\n", + "\n", + "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_n_ram_250ns = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_n_ram_250ns['totNumInsts'] = df_n_ram_250ns['numInsts0'].astype(int)+df_n_ram_250ns['numInsts1'].astype(int)+df_n_ram_250ns['numInsts2'].astype(int)+df_n_ram_250ns['numInsts3'].astype(int)+df_n_ram_250ns['numInsts4'].astype(int)+df_n_ram_250ns['numInsts5'].astype(int)+df_n_ram_250ns['numInsts6'].astype(int)+df_n_ram_250ns['numInsts7'].astype(int)\n", + "df_n_ram_250ns['totBW'] = (df_n_ram_250ns['avgRdBWSys'].astype(float)+df_n_ram_250ns['avgWrBWSys'].astype(float))/1000000000\n", + "df_n_ram_250ns['coldRate'] = (df_n_ram_250ns['numColdMisses'].astype(float) / df_n_ram_250ns['numTotMisses'].astype(float)) *100\n", + "df_n_ram_250ns['injRate'] = (df_n_ram_250ns['readReqs'].astype(float) + df_n_ram_250ns['writeReqs'].astype(float))*64/1000000000 / df_n_ram_250ns['simSeconds'].astype(float)\n", + "df_n_ram_250ns['BIPS'] = (df_n_ram_250ns['totNumInsts'].astype(float)/1000000000)/df_n_ram_250ns['simSeconds'].astype(float)\n", + "\n", + "df_n_ram_250ns['accAmp'] = (df_n_ram_250ns['farBytesRead'].astype(float) + df_n_ram_250ns['farBytesWritten'].astype(float) +\n", + " df_n_ram_250ns['loc1BytesRead'].astype(float) + df_n_ram_250ns['loc1BytesWritten'].astype(float) + \n", + " df_n_ram_250ns['loc2BytesRead'].astype(float) + df_n_ram_250ns['loc2BytesWritten'].astype(float)) / (df_n_ram_250ns['readReqs'].astype(float) * 64 + df_n_ram_250ns['writeReqs'].astype(float) * 64)\n", + "\n", + "df_n_ram_250ns['BWBloat'] = (df_n_ram_250ns['loc1AvgRdBW'].astype(float) + df_n_ram_250ns['loc1AvgWrBW'].astype(float) +\n", + " df_n_ram_250ns['loc2AvgRdBW'].astype(float) + df_n_ram_250ns['loc2AvgWrBW'].astype(float) +\n", + " df_n_ram_250ns['farAvgRdBW'].astype(float) + df_n_ram_250ns['farAvgWrBW'].astype(float)) / ((df_n_ram_250ns['avgRdBWSys'].astype(float) + df_n_ram_250ns['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_n_ram_250ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_ram_250ns.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/GAPBS/500ns'\n", + "\n", + "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 21, 20, 10)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_g_ram_500ns = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_g_ram_500ns['totNumInsts'] = df_g_ram_500ns['numInsts0'].astype(int)+df_g_ram_500ns['numInsts1'].astype(int)+df_g_ram_500ns['numInsts2'].astype(int)+df_g_ram_500ns['numInsts3'].astype(int)+df_g_ram_500ns['numInsts4'].astype(int)+df_g_ram_500ns['numInsts5'].astype(int)+df_g_ram_500ns['numInsts6'].astype(int)+df_g_ram_500ns['numInsts7'].astype(int)\n", + "df_g_ram_500ns['totBW'] = (df_g_ram_500ns['avgRdBWSys'].astype(float)+df_g_ram_500ns['avgWrBWSys'].astype(float))/1000000000\n", + "df_g_ram_500ns['coldRate'] = (df_g_ram_500ns['numColdMisses'].astype(float) / df_g_ram_500ns['numTotMisses'].astype(float)) *100\n", + "df_g_ram_500ns['injRate'] = (df_g_ram_500ns['readReqs'].astype(float) + df_g_ram_500ns['writeReqs'].astype(float))*64/1000000000 / df_g_ram_500ns['simSeconds'].astype(float)\n", + "df_g_ram_500ns['BIPS'] = (df_g_ram_500ns['totNumInsts'].astype(float)/1000000000)/df_g_ram_500ns['simSeconds'].astype(float)\n", + "\n", + "df_g_ram_500ns['accAmp'] = (df_g_ram_500ns['farBytesRead'].astype(float) + df_g_ram_500ns['farBytesWritten'].astype(float) +\n", + " df_g_ram_500ns['loc1BytesRead'].astype(float) + df_g_ram_500ns['loc1BytesWritten'].astype(float) + \n", + " df_g_ram_500ns['loc2BytesRead'].astype(float) + df_g_ram_500ns['loc2BytesWritten'].astype(float)) / (df_g_ram_500ns['readReqs'].astype(float) * 64 + df_g_ram_500ns['writeReqs'].astype(float) * 64)\n", + "\n", + "df_g_ram_500ns['BWBloat'] = (df_g_ram_500ns['loc1AvgRdBW'].astype(float) + df_g_ram_500ns['loc1AvgWrBW'].astype(float) +\n", + " df_g_ram_500ns['loc2AvgRdBW'].astype(float) + df_g_ram_500ns['loc2AvgWrBW'].astype(float) +\n", + " df_g_ram_500ns['farAvgRdBW'].astype(float) + df_g_ram_500ns['farAvgWrBW'].astype(float)) / ((df_g_ram_500ns['avgRdBWSys'].astype(float) + df_g_ram_500ns['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_g_ram_500ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_ram_500ns.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/NPB/500ns'\n", + "\n", + "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_n_ram_500ns = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_n_ram_500ns['totNumInsts'] = df_n_ram_500ns['numInsts0'].astype(int)+df_n_ram_500ns['numInsts1'].astype(int)+df_n_ram_500ns['numInsts2'].astype(int)+df_n_ram_500ns['numInsts3'].astype(int)+df_n_ram_500ns['numInsts4'].astype(int)+df_n_ram_500ns['numInsts5'].astype(int)+df_n_ram_500ns['numInsts6'].astype(int)+df_n_ram_500ns['numInsts7'].astype(int)\n", + "df_n_ram_500ns['totBW'] = (df_n_ram_500ns['avgRdBWSys'].astype(float)+df_n_ram_500ns['avgWrBWSys'].astype(float))/1000000000\n", + "df_n_ram_500ns['coldRate'] = (df_n_ram_500ns['numColdMisses'].astype(float) / df_n_ram_500ns['numTotMisses'].astype(float)) *100\n", + "df_n_ram_500ns['injRate'] = (df_n_ram_500ns['readReqs'].astype(float) + df_n_ram_500ns['writeReqs'].astype(float))*64/1000000000 / df_n_ram_500ns['simSeconds'].astype(float)\n", + "df_n_ram_500ns['BIPS'] = (df_n_ram_500ns['totNumInsts'].astype(float)/1000000000)/df_n_ram_500ns['simSeconds'].astype(float)\n", + "\n", + "df_n_ram_500ns['accAmp'] = (df_n_ram_500ns['farBytesRead'].astype(float) + df_n_ram_500ns['farBytesWritten'].astype(float) +\n", + " df_n_ram_500ns['loc1BytesRead'].astype(float) + df_n_ram_500ns['loc1BytesWritten'].astype(float) + \n", + " df_n_ram_500ns['loc2BytesRead'].astype(float) + df_n_ram_500ns['loc2BytesWritten'].astype(float)) / (df_n_ram_500ns['readReqs'].astype(float) * 64 + df_n_ram_500ns['writeReqs'].astype(float) * 64)\n", + "\n", + "df_n_ram_500ns['BWBloat'] = (df_n_ram_500ns['loc1AvgRdBW'].astype(float) + df_n_ram_500ns['loc1AvgWrBW'].astype(float) +\n", + " df_n_ram_500ns['loc2AvgRdBW'].astype(float) + df_n_ram_500ns['loc2AvgWrBW'].astype(float) +\n", + " df_n_ram_500ns['farAvgRdBW'].astype(float) + df_n_ram_500ns['farAvgWrBW'].astype(float)) / ((df_n_ram_500ns['avgRdBWSys'].astype(float) + df_n_ram_500ns['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_n_ram_500ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_ram_500ns.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/GAPBS/1us'\n", + "\n", + "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 18, 16, 10)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_g_ram_1us = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_g_ram_1us['totNumInsts'] = df_g_ram_1us['numInsts0'].astype(int)+df_g_ram_1us['numInsts1'].astype(int)+df_g_ram_1us['numInsts2'].astype(int)+df_g_ram_1us['numInsts3'].astype(int)+df_g_ram_1us['numInsts4'].astype(int)+df_g_ram_1us['numInsts5'].astype(int)+df_g_ram_1us['numInsts6'].astype(int)+df_g_ram_1us['numInsts7'].astype(int)\n", + "df_g_ram_1us['totBW'] = (df_g_ram_1us['avgRdBWSys'].astype(float)+df_g_ram_1us['avgWrBWSys'].astype(float))/1000000000\n", + "df_g_ram_1us['coldRate'] = (df_g_ram_1us['numColdMisses'].astype(float) / df_g_ram_1us['numTotMisses'].astype(float)) *100\n", + "df_g_ram_1us['injRate'] = (df_g_ram_1us['readReqs'].astype(float) + df_g_ram_1us['writeReqs'].astype(float))*64/1000000000 / df_g_ram_1us['simSeconds'].astype(float)\n", + "df_g_ram_1us['BIPS'] = (df_g_ram_1us['totNumInsts'].astype(float)/1000000000)/df_g_ram_1us['simSeconds'].astype(float)\n", + "\n", + "df_g_ram_1us['accAmp'] = (df_g_ram_1us['farBytesRead'].astype(float) + df_g_ram_1us['farBytesWritten'].astype(float) +\n", + " df_g_ram_1us['loc1BytesRead'].astype(float) + df_g_ram_1us['loc1BytesWritten'].astype(float) + \n", + " df_g_ram_1us['loc2BytesRead'].astype(float) + df_g_ram_1us['loc2BytesWritten'].astype(float)) / (df_g_ram_1us['readReqs'].astype(float) * 64 + df_g_ram_1us['writeReqs'].astype(float) * 64)\n", + "\n", + "df_g_ram_1us['BWBloat'] = (df_g_ram_1us['loc1AvgRdBW'].astype(float) + df_g_ram_1us['loc1AvgWrBW'].astype(float) +\n", + " df_g_ram_1us['loc2AvgRdBW'].astype(float) + df_g_ram_1us['loc2AvgWrBW'].astype(float) +\n", + " df_g_ram_1us['farAvgRdBW'].astype(float) + df_g_ram_1us['farAvgWrBW'].astype(float)) / ((df_g_ram_1us['avgRdBWSys'].astype(float) + df_g_ram_1us['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_g_ram_1us.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_ram_1us.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/NPB/1us'\n", + "\n", + "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_n_ram_1us = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_n_ram_1us['totNumInsts'] = df_n_ram_1us['numInsts0'].astype(int)+df_n_ram_1us['numInsts1'].astype(int)+df_n_ram_1us['numInsts2'].astype(int)+df_n_ram_1us['numInsts3'].astype(int)+df_n_ram_1us['numInsts4'].astype(int)+df_n_ram_1us['numInsts5'].astype(int)+df_n_ram_1us['numInsts6'].astype(int)+df_n_ram_1us['numInsts7'].astype(int)\n", + "df_n_ram_1us['totBW'] = (df_n_ram_1us['avgRdBWSys'].astype(float)+df_n_ram_1us['avgWrBWSys'].astype(float))/1000000000\n", + "df_n_ram_1us['coldRate'] = (df_n_ram_1us['numColdMisses'].astype(float) / df_n_ram_1us['numTotMisses'].astype(float)) *100\n", + "df_n_ram_1us['injRate'] = (df_n_ram_1us['readReqs'].astype(float) + df_n_ram_1us['writeReqs'].astype(float))*64/1000000000 / df_n_ram_1us['simSeconds'].astype(float)\n", + "df_n_ram_1us['BIPS'] = (df_n_ram_1us['totNumInsts'].astype(float)/1000000000)/df_n_ram_1us['simSeconds'].astype(float)\n", + "\n", + "df_n_ram_1us['accAmp'] = (df_n_ram_1us['farBytesRead'].astype(float) + df_n_ram_1us['farBytesWritten'].astype(float) +\n", + " df_n_ram_1us['loc1BytesRead'].astype(float) + df_n_ram_1us['loc1BytesWritten'].astype(float) + \n", + " df_n_ram_1us['loc2BytesRead'].astype(float) + df_n_ram_1us['loc2BytesWritten'].astype(float)) / (df_n_ram_1us['readReqs'].astype(float) * 64 + df_n_ram_1us['writeReqs'].astype(float) * 64)\n", + "\n", + "df_n_ram_1us['BWBloat'] = (df_n_ram_1us['loc1AvgRdBW'].astype(float) + df_n_ram_1us['loc1AvgWrBW'].astype(float) +\n", + " df_n_ram_1us['loc2AvgRdBW'].astype(float) + df_n_ram_1us['loc2AvgWrBW'].astype(float) +\n", + " df_n_ram_1us['farAvgRdBW'].astype(float) + df_n_ram_1us['farAvgWrBW'].astype(float)) / ((df_n_ram_1us['avgRdBWSys'].astype(float) + df_n_ram_1us['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_n_ram_1us.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_ram_1us.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/GAPBS/2us'\n", + "\n", + "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 15, 13, 10)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_g_ram_2us = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_g_ram_2us['totNumInsts'] = df_g_ram_2us['numInsts0'].astype(int)+df_g_ram_2us['numInsts1'].astype(int)+df_g_ram_2us['numInsts2'].astype(int)+df_g_ram_2us['numInsts3'].astype(int)+df_g_ram_2us['numInsts4'].astype(int)+df_g_ram_2us['numInsts5'].astype(int)+df_g_ram_2us['numInsts6'].astype(int)+df_g_ram_2us['numInsts7'].astype(int)\n", + "df_g_ram_2us['totBW'] = (df_g_ram_2us['avgRdBWSys'].astype(float)+df_g_ram_2us['avgWrBWSys'].astype(float))/1000000000\n", + "df_g_ram_2us['coldRate'] = (df_g_ram_2us['numColdMisses'].astype(float) / df_g_ram_2us['numTotMisses'].astype(float)) *100\n", + "df_g_ram_2us['injRate'] = (df_g_ram_2us['readReqs'].astype(float) + df_g_ram_2us['writeReqs'].astype(float))*64/1000000000 / df_g_ram_2us['simSeconds'].astype(float)\n", + "df_g_ram_2us['BIPS'] = (df_g_ram_2us['totNumInsts'].astype(float)/1000000000)/df_g_ram_2us['simSeconds'].astype(float)\n", + "\n", + "df_g_ram_2us['accAmp'] = (df_g_ram_2us['farBytesRead'].astype(float) + df_g_ram_2us['farBytesWritten'].astype(float) +\n", + " df_g_ram_2us['loc1BytesRead'].astype(float) + df_g_ram_2us['loc1BytesWritten'].astype(float) + \n", + " df_g_ram_2us['loc2BytesRead'].astype(float) + df_g_ram_2us['loc2BytesWritten'].astype(float)) / (df_g_ram_2us['readReqs'].astype(float) * 64 + df_g_ram_2us['writeReqs'].astype(float) * 64)\n", + "\n", + "df_g_ram_2us['BWBloat'] = (df_g_ram_2us['loc1AvgRdBW'].astype(float) + df_g_ram_2us['loc1AvgWrBW'].astype(float) +\n", + " df_g_ram_2us['loc2AvgRdBW'].astype(float) + df_g_ram_2us['loc2AvgWrBW'].astype(float) +\n", + " df_g_ram_2us['farAvgRdBW'].astype(float) + df_g_ram_2us['farAvgWrBW'].astype(float)) / ((df_g_ram_2us['avgRdBWSys'].astype(float) + df_g_ram_2us['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_g_ram_2us.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_ram_2us.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/NPB/2us'\n", + "\n", + "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_n_ram_2us = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_n_ram_2us['totNumInsts'] = df_n_ram_2us['numInsts0'].astype(int)+df_n_ram_2us['numInsts1'].astype(int)+df_n_ram_2us['numInsts2'].astype(int)+df_n_ram_2us['numInsts3'].astype(int)+df_n_ram_2us['numInsts4'].astype(int)+df_n_ram_2us['numInsts5'].astype(int)+df_n_ram_2us['numInsts6'].astype(int)+df_n_ram_2us['numInsts7'].astype(int)\n", + "df_n_ram_2us['totBW'] = (df_n_ram_2us['avgRdBWSys'].astype(float)+df_n_ram_2us['avgWrBWSys'].astype(float))/1000000000\n", + "df_n_ram_2us['coldRate'] = (df_n_ram_2us['numColdMisses'].astype(float) / df_n_ram_2us['numTotMisses'].astype(float)) *100\n", + "df_n_ram_2us['injRate'] = (df_n_ram_2us['readReqs'].astype(float) + df_n_ram_2us['writeReqs'].astype(float))*64/1000000000 / df_n_ram_2us['simSeconds'].astype(float)\n", + "df_n_ram_2us['BIPS'] = (df_n_ram_2us['totNumInsts'].astype(float)/1000000000)/df_n_ram_2us['simSeconds'].astype(float)\n", + "\n", + "df_n_ram_2us['accAmp'] = (df_n_ram_2us['farBytesRead'].astype(float) + df_n_ram_2us['farBytesWritten'].astype(float) +\n", + " df_n_ram_2us['loc1BytesRead'].astype(float) + df_n_ram_2us['loc1BytesWritten'].astype(float) + \n", + " df_n_ram_2us['loc2BytesRead'].astype(float) + df_n_ram_2us['loc2BytesWritten'].astype(float)) / (df_n_ram_2us['readReqs'].astype(float) * 64 + df_n_ram_2us['writeReqs'].astype(float) * 64)\n", + "\n", + "df_n_ram_2us['BWBloat'] = (df_n_ram_2us['loc1AvgRdBW'].astype(float) + df_n_ram_2us['loc1AvgWrBW'].astype(float) +\n", + " df_n_ram_2us['loc2AvgRdBW'].astype(float) + df_n_ram_2us['loc2AvgWrBW'].astype(float) +\n", + " df_n_ram_2us['farAvgRdBW'].astype(float) + df_n_ram_2us['farAvgWrBW'].astype(float)) / ((df_n_ram_2us['avgRdBWSys'].astype(float) + df_n_ram_2us['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_n_ram_2us.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_ram_2us.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/GAPBS/50ns'\n", + "\n", + "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 27, 25, 12)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_g_cas_50ns = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_g_cas_50ns['totNumInsts'] = df_g_cas_50ns['numInsts0'].astype(int)+df_g_cas_50ns['numInsts1'].astype(int)+df_g_cas_50ns['numInsts2'].astype(int)+df_g_cas_50ns['numInsts3'].astype(int)+df_g_cas_50ns['numInsts4'].astype(int)+df_g_cas_50ns['numInsts5'].astype(int)+df_g_cas_50ns['numInsts6'].astype(int)+df_g_cas_50ns['numInsts7'].astype(int)\n", + "df_g_cas_50ns['totBW'] = (df_g_cas_50ns['avgRdBWSys'].astype(float)+df_g_cas_50ns['avgWrBWSys'].astype(float))/1000000000\n", + "df_g_cas_50ns['coldRate'] = (df_g_cas_50ns['numColdMisses'].astype(float) / df_g_cas_50ns['numTotMisses'].astype(float)) *100\n", + "df_g_cas_50ns['injRate'] = (df_g_cas_50ns['readReqs'].astype(float) + df_g_cas_50ns['writeReqs'].astype(float))*64/1000000000 / df_g_cas_50ns['simSeconds'].astype(float)\n", + "df_g_cas_50ns['BIPS'] = (df_g_cas_50ns['totNumInsts'].astype(float)/1000000000)/df_g_cas_50ns['simSeconds'].astype(float)\n", + "\n", + "df_g_cas_50ns['accAmp'] = (df_g_cas_50ns['farBytesRead'].astype(float) + df_g_cas_50ns['farBytesWritten'].astype(float) +\n", + " df_g_cas_50ns['loc1BytesRead'].astype(float) + df_g_cas_50ns['loc1BytesWritten'].astype(float) + \n", + " df_g_cas_50ns['loc2BytesRead'].astype(float) + df_g_cas_50ns['loc2BytesWritten'].astype(float)) / (df_g_cas_50ns['readReqs'].astype(float) * 64 + df_g_cas_50ns['writeReqs'].astype(float) * 64)\n", + "\n", + "df_g_cas_50ns['BWBloat'] = (df_g_cas_50ns['loc1AvgRdBW'].astype(float) + df_g_cas_50ns['loc1AvgWrBW'].astype(float) +\n", + " df_g_cas_50ns['loc2AvgRdBW'].astype(float) + df_g_cas_50ns['loc2AvgWrBW'].astype(float) +\n", + " df_g_cas_50ns['farAvgRdBW'].astype(float) + df_g_cas_50ns['farAvgWrBW'].astype(float)) / ((df_g_cas_50ns['avgRdBWSys'].astype(float) + df_g_cas_50ns['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_g_cas_50ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_cas_50ns.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/NPB/50ns'\n", + "\n", + "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_n_cas_50ns = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_n_cas_50ns['totNumInsts'] = df_n_cas_50ns['numInsts0'].astype(int)+df_n_cas_50ns['numInsts1'].astype(int)+df_n_cas_50ns['numInsts2'].astype(int)+df_n_cas_50ns['numInsts3'].astype(int)+df_n_cas_50ns['numInsts4'].astype(int)+df_n_cas_50ns['numInsts5'].astype(int)+df_n_cas_50ns['numInsts6'].astype(int)+df_n_cas_50ns['numInsts7'].astype(int)\n", + "df_n_cas_50ns['totBW'] = (df_n_cas_50ns['avgRdBWSys'].astype(float)+df_n_cas_50ns['avgWrBWSys'].astype(float))/1000000000\n", + "df_n_cas_50ns['coldRate'] = (df_n_cas_50ns['numColdMisses'].astype(float) / df_n_cas_50ns['numTotMisses'].astype(float)) *100\n", + "df_n_cas_50ns['injRate'] = (df_n_cas_50ns['readReqs'].astype(float) + df_n_cas_50ns['writeReqs'].astype(float))*64/1000000000 / df_n_cas_50ns['simSeconds'].astype(float)\n", + "df_n_cas_50ns['BIPS'] = (df_n_cas_50ns['totNumInsts'].astype(float)/1000000000)/df_n_cas_50ns['simSeconds'].astype(float)\n", + "\n", + "df_n_cas_50ns['accAmp'] = (df_n_cas_50ns['farBytesRead'].astype(float) + df_n_cas_50ns['farBytesWritten'].astype(float) +\n", + " df_n_cas_50ns['loc1BytesRead'].astype(float) + df_n_cas_50ns['loc1BytesWritten'].astype(float) + \n", + " df_n_cas_50ns['loc2BytesRead'].astype(float) + df_n_cas_50ns['loc2BytesWritten'].astype(float)) / (df_n_cas_50ns['readReqs'].astype(float) * 64 + df_n_cas_50ns['writeReqs'].astype(float) * 64)\n", + "\n", + "df_n_cas_50ns['BWBloat'] = (df_n_cas_50ns['loc1AvgRdBW'].astype(float) + df_n_cas_50ns['loc1AvgWrBW'].astype(float) +\n", + " df_n_cas_50ns['loc2AvgRdBW'].astype(float) + df_n_cas_50ns['loc2AvgWrBW'].astype(float) +\n", + " df_n_cas_50ns['farAvgRdBW'].astype(float) + df_n_cas_50ns['farAvgWrBW'].astype(float)) / ((df_n_cas_50ns['avgRdBWSys'].astype(float) + df_n_cas_50ns['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_n_cas_50ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_cas_50ns.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/GAPBS/100ns'\n", + "\n", + "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 25, 24, 16)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_g_cas_100ns = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_g_cas_100ns['totNumInsts'] = df_g_cas_100ns['numInsts0'].astype(int)+df_g_cas_100ns['numInsts1'].astype(int)+df_g_cas_100ns['numInsts2'].astype(int)+df_g_cas_100ns['numInsts3'].astype(int)+df_g_cas_100ns['numInsts4'].astype(int)+df_g_cas_100ns['numInsts5'].astype(int)+df_g_cas_100ns['numInsts6'].astype(int)+df_g_cas_100ns['numInsts7'].astype(int)\n", + "df_g_cas_100ns['totBW'] = (df_g_cas_100ns['avgRdBWSys'].astype(float)+df_g_cas_100ns['avgWrBWSys'].astype(float))/1000000000\n", + "df_g_cas_100ns['coldRate'] = (df_g_cas_100ns['numColdMisses'].astype(float) / df_g_cas_100ns['numTotMisses'].astype(float)) *100\n", + "df_g_cas_100ns['injRate'] = (df_g_cas_100ns['readReqs'].astype(float) + df_g_cas_100ns['writeReqs'].astype(float))*64/1000000000 / df_g_cas_100ns['simSeconds'].astype(float)\n", + "df_g_cas_100ns['BIPS'] = (df_g_cas_100ns['totNumInsts'].astype(float)/1000000000)/df_g_cas_100ns['simSeconds'].astype(float)\n", + "\n", + "df_g_cas_100ns['accAmp'] = (df_g_cas_100ns['farBytesRead'].astype(float) + df_g_cas_100ns['farBytesWritten'].astype(float) +\n", + " df_g_cas_100ns['loc1BytesRead'].astype(float) + df_g_cas_100ns['loc1BytesWritten'].astype(float) + \n", + " df_g_cas_100ns['loc2BytesRead'].astype(float) + df_g_cas_100ns['loc2BytesWritten'].astype(float)) / (df_g_cas_100ns['readReqs'].astype(float) * 64 + df_g_cas_100ns['writeReqs'].astype(float) * 64)\n", + "\n", + "df_g_cas_100ns['BWBloat'] = (df_g_cas_100ns['loc1AvgRdBW'].astype(float) + df_g_cas_100ns['loc1AvgWrBW'].astype(float) +\n", + " df_g_cas_100ns['loc2AvgRdBW'].astype(float) + df_g_cas_100ns['loc2AvgWrBW'].astype(float) +\n", + " df_g_cas_100ns['farAvgRdBW'].astype(float) + df_g_cas_100ns['farAvgWrBW'].astype(float)) / ((df_g_cas_100ns['avgRdBWSys'].astype(float) + df_g_cas_100ns['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_g_cas_100ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_cas_100ns.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/NPB/100ns'\n", + "\n", + "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_n_cas_100ns = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_n_cas_100ns['totNumInsts'] = df_n_cas_100ns['numInsts0'].astype(int)+df_n_cas_100ns['numInsts1'].astype(int)+df_n_cas_100ns['numInsts2'].astype(int)+df_n_cas_100ns['numInsts3'].astype(int)+df_n_cas_100ns['numInsts4'].astype(int)+df_n_cas_100ns['numInsts5'].astype(int)+df_n_cas_100ns['numInsts6'].astype(int)+df_n_cas_100ns['numInsts7'].astype(int)\n", + "df_n_cas_100ns['totBW'] = (df_n_cas_100ns['avgRdBWSys'].astype(float)+df_n_cas_100ns['avgWrBWSys'].astype(float))/1000000000\n", + "df_n_cas_100ns['coldRate'] = (df_n_cas_100ns['numColdMisses'].astype(float) / df_n_cas_100ns['numTotMisses'].astype(float)) *100\n", + "df_n_cas_100ns['injRate'] = (df_n_cas_100ns['readReqs'].astype(float) + df_n_cas_100ns['writeReqs'].astype(float))*64/1000000000 / df_n_cas_100ns['simSeconds'].astype(float)\n", + "df_n_cas_100ns['BIPS'] = (df_n_cas_100ns['totNumInsts'].astype(float)/1000000000)/df_n_cas_100ns['simSeconds'].astype(float)\n", + "\n", + "df_n_cas_100ns['accAmp'] = (df_n_cas_100ns['farBytesRead'].astype(float) + df_n_cas_100ns['farBytesWritten'].astype(float) +\n", + " df_n_cas_100ns['loc1BytesRead'].astype(float) + df_n_cas_100ns['loc1BytesWritten'].astype(float) + \n", + " df_n_cas_100ns['loc2BytesRead'].astype(float) + df_n_cas_100ns['loc2BytesWritten'].astype(float)) / (df_n_cas_100ns['readReqs'].astype(float) * 64 + df_n_cas_100ns['writeReqs'].astype(float) * 64)\n", + "\n", + "df_n_cas_100ns['BWBloat'] = (df_n_cas_100ns['loc1AvgRdBW'].astype(float) + df_n_cas_100ns['loc1AvgWrBW'].astype(float) +\n", + " df_n_cas_100ns['loc2AvgRdBW'].astype(float) + df_n_cas_100ns['loc2AvgWrBW'].astype(float) +\n", + " df_n_cas_100ns['farAvgRdBW'].astype(float) + df_n_cas_100ns['farAvgWrBW'].astype(float)) / ((df_n_cas_100ns['avgRdBWSys'].astype(float) + df_n_cas_100ns['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_n_cas_100ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_cas_100ns.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/GAPBS/250ns'\n", + "\n", + "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 24, 19, 10)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_g_cas_250ns = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_g_cas_250ns['totNumInsts'] = df_g_cas_250ns['numInsts0'].astype(int)+df_g_cas_250ns['numInsts1'].astype(int)+df_g_cas_250ns['numInsts2'].astype(int)+df_g_cas_250ns['numInsts3'].astype(int)+df_g_cas_250ns['numInsts4'].astype(int)+df_g_cas_250ns['numInsts5'].astype(int)+df_g_cas_250ns['numInsts6'].astype(int)+df_g_cas_250ns['numInsts7'].astype(int)\n", + "df_g_cas_250ns['totBW'] = (df_g_cas_250ns['avgRdBWSys'].astype(float)+df_g_cas_250ns['avgWrBWSys'].astype(float))/1000000000\n", + "df_g_cas_250ns['coldRate'] = (df_g_cas_250ns['numColdMisses'].astype(float) / df_g_cas_250ns['numTotMisses'].astype(float)) *100\n", + "df_g_cas_250ns['injRate'] = (df_g_cas_250ns['readReqs'].astype(float) + df_g_cas_250ns['writeReqs'].astype(float))*64/1000000000 / df_g_cas_250ns['simSeconds'].astype(float)\n", + "df_g_cas_250ns['BIPS'] = (df_g_cas_250ns['totNumInsts'].astype(float)/1000000000)/df_g_cas_250ns['simSeconds'].astype(float)\n", + "\n", + "df_g_cas_250ns['accAmp'] = (df_g_cas_250ns['farBytesRead'].astype(float) + df_g_cas_250ns['farBytesWritten'].astype(float) +\n", + " df_g_cas_250ns['loc1BytesRead'].astype(float) + df_g_cas_250ns['loc1BytesWritten'].astype(float) + \n", + " df_g_cas_250ns['loc2BytesRead'].astype(float) + df_g_cas_250ns['loc2BytesWritten'].astype(float)) / (df_g_cas_250ns['readReqs'].astype(float) * 64 + df_g_cas_250ns['writeReqs'].astype(float) * 64)\n", + "\n", + "df_g_cas_250ns['BWBloat'] = (df_g_cas_250ns['loc1AvgRdBW'].astype(float) + df_g_cas_250ns['loc1AvgWrBW'].astype(float) +\n", + " df_g_cas_250ns['loc2AvgRdBW'].astype(float) + df_g_cas_250ns['loc2AvgWrBW'].astype(float) +\n", + " df_g_cas_250ns['farAvgRdBW'].astype(float) + df_g_cas_250ns['farAvgWrBW'].astype(float)) / ((df_g_cas_250ns['avgRdBWSys'].astype(float) + df_g_cas_250ns['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_g_cas_250ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_cas_250ns.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/NPB/250ns'\n", + "\n", + "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_n_cas_250ns = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_n_cas_250ns['totNumInsts'] = df_n_cas_250ns['numInsts0'].astype(int)+df_n_cas_250ns['numInsts1'].astype(int)+df_n_cas_250ns['numInsts2'].astype(int)+df_n_cas_250ns['numInsts3'].astype(int)+df_n_cas_250ns['numInsts4'].astype(int)+df_n_cas_250ns['numInsts5'].astype(int)+df_n_cas_250ns['numInsts6'].astype(int)+df_n_cas_250ns['numInsts7'].astype(int)\n", + "df_n_cas_250ns['totBW'] = (df_n_cas_250ns['avgRdBWSys'].astype(float)+df_n_cas_250ns['avgWrBWSys'].astype(float))/1000000000\n", + "df_n_cas_250ns['coldRate'] = (df_n_cas_250ns['numColdMisses'].astype(float) / df_n_cas_250ns['numTotMisses'].astype(float)) *100\n", + "df_n_cas_250ns['injRate'] = (df_n_cas_250ns['readReqs'].astype(float) + df_n_cas_250ns['writeReqs'].astype(float))*64/1000000000 / df_n_cas_250ns['simSeconds'].astype(float)\n", + "df_n_cas_250ns['BIPS'] = (df_n_cas_250ns['totNumInsts'].astype(float)/1000000000)/df_n_cas_250ns['simSeconds'].astype(float)\n", + "\n", + "df_n_cas_250ns['accAmp'] = (df_n_cas_250ns['farBytesRead'].astype(float) + df_n_cas_250ns['farBytesWritten'].astype(float) +\n", + " df_n_cas_250ns['loc1BytesRead'].astype(float) + df_n_cas_250ns['loc1BytesWritten'].astype(float) + \n", + " df_n_cas_250ns['loc2BytesRead'].astype(float) + df_n_cas_250ns['loc2BytesWritten'].astype(float)) / (df_n_cas_250ns['readReqs'].astype(float) * 64 + df_n_cas_250ns['writeReqs'].astype(float) * 64)\n", + "\n", + "df_n_cas_250ns['BWBloat'] = (df_n_cas_250ns['loc1AvgRdBW'].astype(float) + df_n_cas_250ns['loc1AvgWrBW'].astype(float) +\n", + " df_n_cas_250ns['loc2AvgRdBW'].astype(float) + df_n_cas_250ns['loc2AvgWrBW'].astype(float) +\n", + " df_n_cas_250ns['farAvgRdBW'].astype(float) + df_n_cas_250ns['farAvgWrBW'].astype(float)) / ((df_n_cas_250ns['avgRdBWSys'].astype(float) + df_n_cas_250ns['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_n_cas_250ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_cas_250ns.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/GAPBS/500ns'\n", + "\n", + "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 21, 19, 10)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_g_cas_500ns = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_g_cas_500ns['totNumInsts'] = df_g_cas_500ns['numInsts0'].astype(int)+df_g_cas_500ns['numInsts1'].astype(int)+df_g_cas_500ns['numInsts2'].astype(int)+df_g_cas_500ns['numInsts3'].astype(int)+df_g_cas_500ns['numInsts4'].astype(int)+df_g_cas_500ns['numInsts5'].astype(int)+df_g_cas_500ns['numInsts6'].astype(int)+df_g_cas_500ns['numInsts7'].astype(int)\n", + "df_g_cas_500ns['totBW'] = (df_g_cas_500ns['avgRdBWSys'].astype(float)+df_g_cas_500ns['avgWrBWSys'].astype(float))/1000000000\n", + "df_g_cas_500ns['coldRate'] = (df_g_cas_500ns['numColdMisses'].astype(float) / df_g_cas_500ns['numTotMisses'].astype(float)) *100\n", + "df_g_cas_500ns['injRate'] = (df_g_cas_500ns['readReqs'].astype(float) + df_g_cas_500ns['writeReqs'].astype(float))*64/1000000000 / df_g_cas_500ns['simSeconds'].astype(float)\n", + "df_g_cas_500ns['BIPS'] = (df_g_cas_500ns['totNumInsts'].astype(float)/1000000000)/df_g_cas_500ns['simSeconds'].astype(float)\n", + "\n", + "df_g_cas_500ns['accAmp'] = (df_g_cas_500ns['farBytesRead'].astype(float) + df_g_cas_500ns['farBytesWritten'].astype(float) +\n", + " df_g_cas_500ns['loc1BytesRead'].astype(float) + df_g_cas_500ns['loc1BytesWritten'].astype(float) + \n", + " df_g_cas_500ns['loc2BytesRead'].astype(float) + df_g_cas_500ns['loc2BytesWritten'].astype(float)) / (df_g_cas_500ns['readReqs'].astype(float) * 64 + df_g_cas_500ns['writeReqs'].astype(float) * 64)\n", + "\n", + "df_g_cas_500ns['BWBloat'] = (df_g_cas_500ns['loc1AvgRdBW'].astype(float) + df_g_cas_500ns['loc1AvgWrBW'].astype(float) +\n", + " df_g_cas_500ns['loc2AvgRdBW'].astype(float) + df_g_cas_500ns['loc2AvgWrBW'].astype(float) +\n", + " df_g_cas_500ns['farAvgRdBW'].astype(float) + df_g_cas_500ns['farAvgWrBW'].astype(float)) / ((df_g_cas_500ns['avgRdBWSys'].astype(float) + df_g_cas_500ns['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_g_cas_500ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_cas_500ns.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/NPB/500ns'\n", + "\n", + "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_n_cas_500ns = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_n_cas_500ns['totNumInsts'] = df_n_cas_500ns['numInsts0'].astype(int)+df_n_cas_500ns['numInsts1'].astype(int)+df_n_cas_500ns['numInsts2'].astype(int)+df_n_cas_500ns['numInsts3'].astype(int)+df_n_cas_500ns['numInsts4'].astype(int)+df_n_cas_500ns['numInsts5'].astype(int)+df_n_cas_500ns['numInsts6'].astype(int)+df_n_cas_500ns['numInsts7'].astype(int)\n", + "df_n_cas_500ns['totBW'] = (df_n_cas_500ns['avgRdBWSys'].astype(float)+df_n_cas_500ns['avgWrBWSys'].astype(float))/1000000000\n", + "df_n_cas_500ns['coldRate'] = (df_n_cas_500ns['numColdMisses'].astype(float) / df_n_cas_500ns['numTotMisses'].astype(float)) *100\n", + "df_n_cas_500ns['injRate'] = (df_n_cas_500ns['readReqs'].astype(float) + df_n_cas_500ns['writeReqs'].astype(float))*64/1000000000 / df_n_cas_500ns['simSeconds'].astype(float)\n", + "df_n_cas_500ns['BIPS'] = (df_n_cas_500ns['totNumInsts'].astype(float)/1000000000)/df_n_cas_500ns['simSeconds'].astype(float)\n", + "\n", + "df_n_cas_500ns['accAmp'] = (df_n_cas_500ns['farBytesRead'].astype(float) + df_n_cas_500ns['farBytesWritten'].astype(float) +\n", + " df_n_cas_500ns['loc1BytesRead'].astype(float) + df_n_cas_500ns['loc1BytesWritten'].astype(float) + \n", + " df_n_cas_500ns['loc2BytesRead'].astype(float) + df_n_cas_500ns['loc2BytesWritten'].astype(float)) / (df_n_cas_500ns['readReqs'].astype(float) * 64 + df_n_cas_500ns['writeReqs'].astype(float) * 64)\n", + "\n", + "df_n_cas_500ns['BWBloat'] = (df_n_cas_500ns['loc1AvgRdBW'].astype(float) + df_n_cas_500ns['loc1AvgWrBW'].astype(float) +\n", + " df_n_cas_500ns['loc2AvgRdBW'].astype(float) + df_n_cas_500ns['loc2AvgWrBW'].astype(float) +\n", + " df_n_cas_500ns['farAvgRdBW'].astype(float) + df_n_cas_500ns['farAvgWrBW'].astype(float)) / ((df_n_cas_500ns['avgRdBWSys'].astype(float) + df_n_cas_500ns['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_n_cas_500ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_cas_500ns.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/GAPBS/1us'\n", + "\n", + "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 17, 16, 10)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_g_cas_1us = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_g_cas_1us['totNumInsts'] = df_g_cas_1us['numInsts0'].astype(int)+df_g_cas_1us['numInsts1'].astype(int)+df_g_cas_1us['numInsts2'].astype(int)+df_g_cas_1us['numInsts3'].astype(int)+df_g_cas_1us['numInsts4'].astype(int)+df_g_cas_1us['numInsts5'].astype(int)+df_g_cas_1us['numInsts6'].astype(int)+df_g_cas_1us['numInsts7'].astype(int)\n", + "df_g_cas_1us['totBW'] = (df_g_cas_1us['avgRdBWSys'].astype(float)+df_g_cas_1us['avgWrBWSys'].astype(float))/1000000000\n", + "df_g_cas_1us['coldRate'] = (df_g_cas_1us['numColdMisses'].astype(float) / df_g_cas_1us['numTotMisses'].astype(float)) *100\n", + "df_g_cas_1us['injRate'] = (df_g_cas_1us['readReqs'].astype(float) + df_g_cas_1us['writeReqs'].astype(float))*64/1000000000 / df_g_cas_1us['simSeconds'].astype(float)\n", + "df_g_cas_1us['BIPS'] = (df_g_cas_1us['totNumInsts'].astype(float)/1000000000)/df_g_cas_1us['simSeconds'].astype(float)\n", + "\n", + "df_g_cas_1us['accAmp'] = (df_g_cas_1us['farBytesRead'].astype(float) + df_g_cas_1us['farBytesWritten'].astype(float) +\n", + " df_g_cas_1us['loc1BytesRead'].astype(float) + df_g_cas_1us['loc1BytesWritten'].astype(float) + \n", + " df_g_cas_1us['loc2BytesRead'].astype(float) + df_g_cas_1us['loc2BytesWritten'].astype(float)) / (df_g_cas_1us['readReqs'].astype(float) * 64 + df_g_cas_1us['writeReqs'].astype(float) * 64)\n", + "\n", + "df_g_cas_1us['BWBloat'] = (df_g_cas_1us['loc1AvgRdBW'].astype(float) + df_g_cas_1us['loc1AvgWrBW'].astype(float) +\n", + " df_g_cas_1us['loc2AvgRdBW'].astype(float) + df_g_cas_1us['loc2AvgWrBW'].astype(float) +\n", + " df_g_cas_1us['farAvgRdBW'].astype(float) + df_g_cas_1us['farAvgWrBW'].astype(float)) / ((df_g_cas_1us['avgRdBWSys'].astype(float) + df_g_cas_1us['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_g_cas_1us.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_cas_1us.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/NPB/1us'\n", + "\n", + "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_n_cas_1us = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_n_cas_1us['totNumInsts'] = df_n_cas_1us['numInsts0'].astype(int)+df_n_cas_1us['numInsts1'].astype(int)+df_n_cas_1us['numInsts2'].astype(int)+df_n_cas_1us['numInsts3'].astype(int)+df_n_cas_1us['numInsts4'].astype(int)+df_n_cas_1us['numInsts5'].astype(int)+df_n_cas_1us['numInsts6'].astype(int)+df_n_cas_1us['numInsts7'].astype(int)\n", + "df_n_cas_1us['totBW'] = (df_n_cas_1us['avgRdBWSys'].astype(float)+df_n_cas_1us['avgWrBWSys'].astype(float))/1000000000\n", + "df_n_cas_1us['coldRate'] = (df_n_cas_1us['numColdMisses'].astype(float) / df_n_cas_1us['numTotMisses'].astype(float)) *100\n", + "df_n_cas_1us['injRate'] = (df_n_cas_1us['readReqs'].astype(float) + df_n_cas_1us['writeReqs'].astype(float))*64/1000000000 / df_n_cas_1us['simSeconds'].astype(float)\n", + "df_n_cas_1us['BIPS'] = (df_n_cas_1us['totNumInsts'].astype(float)/1000000000)/df_n_cas_1us['simSeconds'].astype(float)\n", + "\n", + "df_n_cas_1us['accAmp'] = (df_n_cas_1us['farBytesRead'].astype(float) + df_n_cas_1us['farBytesWritten'].astype(float) +\n", + " df_n_cas_1us['loc1BytesRead'].astype(float) + df_n_cas_1us['loc1BytesWritten'].astype(float) + \n", + " df_n_cas_1us['loc2BytesRead'].astype(float) + df_n_cas_1us['loc2BytesWritten'].astype(float)) / (df_n_cas_1us['readReqs'].astype(float) * 64 + df_n_cas_1us['writeReqs'].astype(float) * 64)\n", + "\n", + "df_n_cas_1us['BWBloat'] = (df_n_cas_1us['loc1AvgRdBW'].astype(float) + df_n_cas_1us['loc1AvgWrBW'].astype(float) +\n", + " df_n_cas_1us['loc2AvgRdBW'].astype(float) + df_n_cas_1us['loc2AvgWrBW'].astype(float) +\n", + " df_n_cas_1us['farAvgRdBW'].astype(float) + df_n_cas_1us['farAvgWrBW'].astype(float)) / ((df_n_cas_1us['avgRdBWSys'].astype(float) + df_n_cas_1us['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_n_cas_1us.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_cas_1us.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/GAPBS/2us'\n", + "\n", + "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 15, 14, 10)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_g_cas_2us = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_g_cas_2us['totNumInsts'] = df_g_cas_2us['numInsts0'].astype(int)+df_g_cas_2us['numInsts1'].astype(int)+df_g_cas_2us['numInsts2'].astype(int)+df_g_cas_2us['numInsts3'].astype(int)+df_g_cas_2us['numInsts4'].astype(int)+df_g_cas_2us['numInsts5'].astype(int)+df_g_cas_2us['numInsts6'].astype(int)+df_g_cas_2us['numInsts7'].astype(int)\n", + "df_g_cas_2us['totBW'] = (df_g_cas_2us['avgRdBWSys'].astype(float)+df_g_cas_2us['avgWrBWSys'].astype(float))/1000000000\n", + "df_g_cas_2us['coldRate'] = (df_g_cas_2us['numColdMisses'].astype(float) / df_g_cas_2us['numTotMisses'].astype(float)) *100\n", + "df_g_cas_2us['injRate'] = (df_g_cas_2us['readReqs'].astype(float) + df_g_cas_2us['writeReqs'].astype(float))*64/1000000000 / df_g_cas_2us['simSeconds'].astype(float)\n", + "df_g_cas_2us['BIPS'] = (df_g_cas_2us['totNumInsts'].astype(float)/1000000000)/df_g_cas_2us['simSeconds'].astype(float)\n", + "\n", + "df_g_cas_2us['accAmp'] = (df_g_cas_2us['farBytesRead'].astype(float) + df_g_cas_2us['farBytesWritten'].astype(float) +\n", + " df_g_cas_2us['loc1BytesRead'].astype(float) + df_g_cas_2us['loc1BytesWritten'].astype(float) + \n", + " df_g_cas_2us['loc2BytesRead'].astype(float) + df_g_cas_2us['loc2BytesWritten'].astype(float)) / (df_g_cas_2us['readReqs'].astype(float) * 64 + df_g_cas_2us['writeReqs'].astype(float) * 64)\n", + "\n", + "df_g_cas_2us['BWBloat'] = (df_g_cas_2us['loc1AvgRdBW'].astype(float) + df_g_cas_2us['loc1AvgWrBW'].astype(float) +\n", + " df_g_cas_2us['loc2AvgRdBW'].astype(float) + df_g_cas_2us['loc2AvgWrBW'].astype(float) +\n", + " df_g_cas_2us['farAvgRdBW'].astype(float) + df_g_cas_2us['farAvgWrBW'].astype(float)) / ((df_g_cas_2us['avgRdBWSys'].astype(float) + df_g_cas_2us['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_g_cas_2us.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_cas_2us.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [], + "source": [ + "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/NPB/2us'\n", + "\n", + "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", + "\n", + "rows = []\n", + "\n", + "for a in app:\n", + " #for t in time:\n", + " #for s in size:\n", + " #for c in cache:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", + " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + "\n", + "#print(rows)\n", + "df_n_cas_2us = pd.DataFrame(rows, columns= dfCols)\n", + "\n", + "df_n_cas_2us['totNumInsts'] = df_n_cas_2us['numInsts0'].astype(int)+df_n_cas_2us['numInsts1'].astype(int)+df_n_cas_2us['numInsts2'].astype(int)+df_n_cas_2us['numInsts3'].astype(int)+df_n_cas_2us['numInsts4'].astype(int)+df_n_cas_2us['numInsts5'].astype(int)+df_n_cas_2us['numInsts6'].astype(int)+df_n_cas_2us['numInsts7'].astype(int)\n", + "df_n_cas_2us['totBW'] = (df_n_cas_2us['avgRdBWSys'].astype(float)+df_n_cas_2us['avgWrBWSys'].astype(float))/1000000000\n", + "df_n_cas_2us['coldRate'] = (df_n_cas_2us['numColdMisses'].astype(float) / df_n_cas_2us['numTotMisses'].astype(float)) *100\n", + "df_n_cas_2us['injRate'] = (df_n_cas_2us['readReqs'].astype(float) + df_n_cas_2us['writeReqs'].astype(float))*64/1000000000 / df_n_cas_2us['simSeconds'].astype(float)\n", + "df_n_cas_2us['BIPS'] = (df_n_cas_2us['totNumInsts'].astype(float)/1000000000)/df_n_cas_2us['simSeconds'].astype(float)\n", + "\n", + "df_n_cas_2us['accAmp'] = (df_n_cas_2us['farBytesRead'].astype(float) + df_n_cas_2us['farBytesWritten'].astype(float) +\n", + " df_n_cas_2us['loc1BytesRead'].astype(float) + df_n_cas_2us['loc1BytesWritten'].astype(float) + \n", + " df_n_cas_2us['loc2BytesRead'].astype(float) + df_n_cas_2us['loc2BytesWritten'].astype(float)) / (df_n_cas_2us['readReqs'].astype(float) * 64 + df_n_cas_2us['writeReqs'].astype(float) * 64)\n", + "\n", + "df_n_cas_2us['BWBloat'] = (df_n_cas_2us['loc1AvgRdBW'].astype(float) + df_n_cas_2us['loc1AvgWrBW'].astype(float) +\n", + " df_n_cas_2us['loc2AvgRdBW'].astype(float) + df_n_cas_2us['loc2AvgWrBW'].astype(float) +\n", + " df_n_cas_2us['farAvgRdBW'].astype(float) + df_n_cas_2us['farAvgWrBW'].astype(float)) / ((df_n_cas_2us['avgRdBWSys'].astype(float) + df_n_cas_2us['avgWrBWSys'].astype(float)) / 1000000)\n", + "\n", + "df_n_cas_2us.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_cas_2us.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "g = []\n", + "n = []\n", + "\n", + "bips_g_cas = df_g_cas_50ns['BIPS'].astype(float)\n", + "bips_g_ram = df_g_ram_50ns['BIPS'].astype(float)\n", + "bips_n_cas = df_n_cas_50ns['BIPS'].astype(float)\n", + "bips_n_ram = df_n_ram_50ns['BIPS'].astype(float)\n", + "\n", + "\n", + "g.append(gmean(bips_g_ram,6) / gmean(bips_g_cas, 6))\n", + "n.append(gmean(bips_n_ram,5) / gmean(bips_n_cas, 5))\n", + "\n", + "\n", + "bips_g_cas = df_g_cas_100ns['BIPS'].astype(float)\n", + "bips_g_ram = df_g_ram_100ns['BIPS'].astype(float)\n", + "bips_n_cas = df_n_cas_100ns['BIPS'].astype(float)\n", + "bips_n_ram = df_n_ram_100ns['BIPS'].astype(float)\n", + "\n", + "\n", + "g.append(gmean(bips_g_ram,6) / gmean(bips_g_cas, 6))\n", + "n.append(gmean(bips_n_ram,5) / gmean(bips_n_cas, 5))\n", + "\n", + "bips_g_cas = df_g_cas_250ns['BIPS'].astype(float)\n", + "bips_g_ram = df_g_ram_250ns['BIPS'].astype(float)\n", + "bips_n_cas = df_n_cas_250ns['BIPS'].astype(float)\n", + "bips_n_ram = df_n_ram_250ns['BIPS'].astype(float)\n", + "\n", + "\n", + "g.append(gmean(bips_g_ram,6) / gmean(bips_g_cas, 6))\n", + "n.append(gmean(bips_n_ram,5) / gmean(bips_n_cas, 5))\n", + "\n", + "bips_g_cas = df_g_cas_500ns['BIPS'].astype(float)\n", + "bips_g_ram = df_g_ram_500ns['BIPS'].astype(float)\n", + "bips_n_cas = df_n_cas_500ns['BIPS'].astype(float)\n", + "bips_n_ram = df_n_ram_500ns['BIPS'].astype(float)\n", + "\n", + "\n", + "g.append(gmean(bips_g_ram,6) / gmean(bips_g_cas, 6))\n", + "n.append(gmean(bips_n_ram,5) / gmean(bips_n_cas, 5))\n", + "\n", + "bips_g_cas = df_g_cas_1us['BIPS'].astype(float)\n", + "bips_g_ram = df_g_ram_1us['BIPS'].astype(float)\n", + "bips_n_cas = df_n_cas_1us['BIPS'].astype(float)\n", + "bips_n_ram = df_n_ram_1us['BIPS'].astype(float)\n", + "\n", + "\n", + "g.append(gmean(bips_g_ram,6) / gmean(bips_g_cas, 6))\n", + "n.append(gmean(bips_n_ram,5) / gmean(bips_n_cas, 5))\n", + "\n", + "bips_g_cas = df_g_cas_2us['BIPS'].astype(float)\n", + "bips_g_ram = df_g_ram_2us['BIPS'].astype(float)\n", + "bips_n_cas = df_n_cas_2us['BIPS'].astype(float)\n", + "bips_n_ram = df_n_ram_2us['BIPS'].astype(float)\n", + "\n", + "\n", + "g.append(gmean(bips_g_ram,6) / gmean(bips_g_cas, 6))\n", + "n.append(gmean(bips_n_ram,5) / gmean(bips_n_cas, 5))\n", + "\n", + "x = ['50ns', '100ns', '250ns', '500ns', '1us', '2us']\n", + "x_axis = np.arange(6)\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(4,2)\n", + "\n", + "plt.ylim([0,1.7])\n", + "len = 0.4\n", + "plt.bar(x_axis-len, g, width=len, label = 'GAPBS')\n", + "plt.bar(x_axis, n, width=len, label = 'NPB')\n", + "\n", + "plt.xticks(x_axis-(len/2), x, fontsize=8)\n", + "plt.axhline(y=1, color='gray')\n", + "\n", + "plt.title(\"BIPS(TDRAM/Cascade)\", fontsize=8)\n", + "plt.xlabel(\"Link latency\", fontsize=8)\n", + "plt.ylabel(\"Speedup\", fontsize=8)\n", + "plt.legend(fontsize=8, ncol=2)\n", + "plt.tight_layout()\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/missRatio_swe.py b/missRatio_swe.py new file mode 100644 index 0000000000..66704c5728 --- /dev/null +++ b/missRatio_swe.py @@ -0,0 +1,136 @@ +from m5.objects import * +import m5 +import argparse +from m5.objects.DRAMInterface import * +from m5.objects.NVMInterface import * + +args = argparse.ArgumentParser() + +args.add_argument( + "traffic_mode", + type = str, + help = "Traffic type to use" +) + +args.add_argument( + "rd_prct", + type=int, + help="Read Percentage", +) + +args.add_argument( + "end_address", + type=str, + help="end address", +) + +options = args.parse_args() + +system = System() +system.clk_domain = SrcClockDomain() +system.clk_domain.clock = "4GHz" +system.clk_domain.voltage_domain = VoltageDomain() +system.mem_mode = 'timing' + +system.generator = PyTrafficGen() + +system.mem_ctrl = PolicyManager(range=AddrRange('3GiB')) + +system.mem_ctrl.orb_max_size = 128 +system.mem_ctrl.static_frontend_latency = "10ns" +system.mem_ctrl.static_backend_latency = "10ns" +#system.mem_ctrl.bypass_dcache = True + +system.loc_mem_ctrl = MemCtrl() +#system.loc_mem_ctrl.consider_oldest_write= True +system.loc_mem_ctrl.dram = TDRAM(range=AddrRange('3GiB'), in_addr_map=False, null=True) +system.mem_ctrl.loc_mem_policy = 'Rambus' + +# system.loc_mem_ctrl = MemCtrl() +# #system.loc_mem_ctrl.consider_oldest_write= True +# system.loc_mem_ctrl.dram = TDRAM_32(range=AddrRange('3GiB'), in_addr_map=False, null=True) +# system.loc_mem_ctrl.dram.activation_limit = 8 +# system.loc_mem_ctrl.dram.page_policy = "close_adaptive" +# system.mem_ctrl.loc_mem_policy = 'Rambus' +# system.loc_mem_ctrl.dram.read_buffer_size = 64 +# system.loc_mem_ctrl.dram.write_buffer_size = 64 + +# system.loc_mem_ctrl = HBMCtrl() +# system.loc_mem_ctrl.dram = HBM_2000_4H_1x64(range=AddrRange(start = '0', end = '3GiB', masks = [1 << 6], intlvMatch = 0), in_addr_map=False, kvm_map=False, null=True) +# system.loc_mem_ctrl.dram_2 = HBM_2000_4H_1x64(range=AddrRange(start = '0', end = '3GiB', masks = [1 << 6], intlvMatch = 1), in_addr_map=False, kvm_map=False, null=True) +# system.mem_ctrl.loc_mem_policy = 'CascadeLakeNoPartWrs' +# system.loc_mem_ctrl.dram.read_buffer_size = 32 +# system.loc_mem_ctrl.dram.write_buffer_size = 32 +# system.loc_mem_ctrl.dram_2.read_buffer_size = 32 +# system.loc_mem_ctrl.dram_2.write_buffer_size = 32 + +system.mem_ctrl.loc_mem = system.loc_mem_ctrl.dram +system.loc_mem_ctrl.static_frontend_latency = "2ns" +system.loc_mem_ctrl.static_backend_latency = "2ns" +system.loc_mem_ctrl.static_frontend_latency_tc = "1ns" +system.loc_mem_ctrl.static_backend_latency_tc = "1ns" + +system.far_mem_ctrl = MemCtrl() +system.far_mem_ctrl.dram = DDR4_2400_16x4(range=AddrRange('3GiB'),in_addr_map=False, null=True) +system.far_mem_ctrl.dram.read_buffer_size = 64 +system.far_mem_ctrl.dram.write_buffer_size = 64 +system.far_mem_ctrl.static_frontend_latency = "2ns" +system.far_mem_ctrl.static_backend_latency = "2ns" + +system.mem_ctrl.dram_cache_size = "1GiB" + +system.generator.port = system.mem_ctrl.port +system.loc_mem_ctrl.port = system.mem_ctrl.loc_req_port +system.far_mem_ctrl.port = system.mem_ctrl.far_req_port + +def createRandomTraffic(tgen): + yield tgen.createRandom(10000000000, # duration + 0, # min_addr + AddrRange(options.end_address).end, # max_adr + 64, # block_size + 1000, # min_period + 1000, # max_period + options.rd_prct, # rd_perc + 0) # data_limit + yield tgen.createExit(0) + +def createLinearTraffic(tgen): + yield tgen.createLinear(10000000000, # duration + 0, # min_addr + AddrRange('3GiB').end, # max_adr + 64, # block_size + 1000, # min_period + 1000, # max_period + options.rd_prct, # rd_perc + 0) # data_limit + yield tgen.createExit(0) + +root = Root(full_system=False, system=system) + +m5.instantiate() + +if options.traffic_mode == 'linear': + system.generator.start(createLinearTraffic(system.generator)) +elif options.traffic_mode == 'random': + system.generator.start(createRandomTraffic(system.generator)) +else: + print('Wrong traffic type! Exiting!') + exit() + +exit_event = m5.simulate() +print(f"Exit reason {exit_event.getCause()}") + +# for testing checkpointing +# exit_event = m5.simulate(1000000000) +# print(f"Exit reason {exit_event.getCause()}") + +# # print("Draining") +# # m5.drain() +# # print("Done draining!") +# m5.stats.dump() +# m5.checkpoint(m5.options.outdir + '/cpt-test') +# m5.stats.reset() + +# system.generator.start(createLinearTraffic(system.generator)) +# exit_event = m5.simulate() +# print(f"Exit reason {exit_event.getCause()}") diff --git a/npb_checkpoint.sh b/npb_checkpoint.sh new file mode 100755 index 0000000000..51923fd558 --- /dev/null +++ b/npb_checkpoint.sh @@ -0,0 +1,22 @@ + +#!/bin/bash + +# $1 is the class of the NPB to run + +if [ $1 != 'C'] && [ $1 != 'D'] +then + echo "Run with C or D Class" + exit +fi + +bms=(bt cg dc ep ft is lu mg sp ua) + +if [! -d checkpoints-npb]; then + mkdir -p checkpoints-npb; +fi + +for bm in "${bms[@]}" +do +echo $bm +build/RISCV/gem5.opt -re --outdir=$bm.timing Octopi-cache/riscv-2channel-1ccd-checkpoint-timing.py --benchmark $bm --size $1 --ckpt_path checkpoints-npb/$bm.timing/$bm & +done diff --git a/npb_checkpoint_c_class.sh b/npb_checkpoint_c_class.sh new file mode 100755 index 0000000000..c80d422ba9 --- /dev/null +++ b/npb_checkpoint_c_class.sh @@ -0,0 +1,22 @@ + +#!/bin/bash + +# $1 is the class of the NPB to run + +if [ $1 != 'C'] && [ $1 != 'D'] +then + echo "Run with C or D Class" + exit +fi + +bms=(bt cg dc ep ft is lu mg sp ua) + +if [! -d /projects/gem5/npb-checkpoints]; then + mkdir -p /projects/gem5/npb-checkpoints; +fi + +for bm in "${bms[@]}" +do +echo $bm +M5_OVERRIDE_PY_SOURCE=TRUE build/RISCV/gem5.opt -re --outdir=/projects/gem5/npb-checkpoints/results/$bm.$1.timing Octopi-cache/riscv-2channel-1ccd-checkpoint-timing-npb-c.py --benchmark $bm --size $1 --ckpt_path /projects/gem5/npb-checkpoints/$bm.$1.timing/$bm.$1 & +done diff --git a/npb_run.sh b/npb_run.sh new file mode 100755 index 0000000000..1596b924a2 --- /dev/null +++ b/npb_run.sh @@ -0,0 +1,22 @@ + +#!/bin/bash + +# $1 is the class of the NPB to run + +if [ $1 != 'C'] && [ $1 != 'D'] +then + echo "Run with C or D Class" + exit +fi + +bms=(bt cg dc ep ft is lu mg sp ua) + +if [! -d results_npb]; then + mkdir -p results_npb; +fi + +for bm in "${bms[@]}" +do +echo $bm +M5_OVERRIDE_PY_SOURCE=TRUE build/RISCV/gem5.opt --debug-flags=O3LooppointAnalysis -re --outdir=results_npb/$bm.$1.O3 Octopi-cache/restore-npb-gapbs-looppoint.py --benchmark $bm.$1 --size $1 --ckpt_path /projects/gem5/dramcache/jason-checkpoints/npb/c/$bm/ckpt & +done diff --git a/npb_run_c.sh b/npb_run_c.sh new file mode 100755 index 0000000000..b778ec155f --- /dev/null +++ b/npb_run_c.sh @@ -0,0 +1,22 @@ + +#!/bin/bash + +# $1 is the class of the NPB to run + +if [ $1 != 'C'] && [ $1 != 'D'] +then + echo "Run with C or D Class" + exit +fi + +bms=(bt cg dc ep ft is lu mg sp ua) + +if [! -d NPB_Base]; then + mkdir -p NPB_Base; +fi + +for bm in "${bms[@]}" +do +echo $bm +M5_OVERRIDE_PY_SOURCE=TRUE build/RISCV/gem5.opt -re --outdir=NPB_Base/$bm.$1.O3 Octopi-cache/restore-npb-gapbs-looppoint.py --benchmark $bm.$1 --size $1 --ckpt_path /projects/gem5/dramcache/jason-checkpoints/npb/c/$bm/ckpt & +done diff --git a/plots_1GBdramCache/data-plots.ipynb b/plots_1GBdramCache/data-plots.ipynb new file mode 100644 index 0000000000..2596a775b4 --- /dev/null +++ b/plots_1GBdramCache/data-plots.ipynb @@ -0,0 +1,1331 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import sys\n", + "from matplotlib import pyplot as plt\n", + "import os\n", + "import statistics\n", + "\n", + "cmap = plt.get_cmap('Set1')\n", + "\n", + "Stats = ['simSeconds ',\n", + "'hostSeconds ',\n", + "'system.mem_ctrl.readReqs ',\n", + "'system.mem_ctrl.writeReqs ',\n", + "'system.mem_ctrl.servicedByWrQ ',\n", + "'system.mem_ctrl.mergedWrBursts ',\n", + "'system.mem_ctrl.numTotHits ',\n", + "'system.mem_ctrl.numTotMisses ',\n", + "'system.mem_ctrl.numColdMisses ',\n", + "'system.mem_ctrl.numHotMisses ',\n", + "'system.mem_ctrl.numRdMissClean ',\n", + "'system.mem_ctrl.numRdMissDirty ',\n", + "'system.mem_ctrl.numRdHit ',\n", + "'system.mem_ctrl.numWrMissClean ',\n", + "'system.mem_ctrl.numWrMissDirty ',\n", + "'system.mem_ctrl.numWrHit ',\n", + "'system.mem_ctrl.numRdHitDirty ',\n", + "'system.mem_ctrl.numRdHitClean ',\n", + "'system.mem_ctrl.numWrHitDirty ',\n", + "'system.mem_ctrl.numWrHitClean ',\n", + "'system.o3Cpu0.thread_0.numInsts ',\n", + "'system.o3Cpu1.thread_0.numInsts ',\n", + "'system.o3Cpu2.thread_0.numInsts ',\n", + "'system.o3Cpu3.thread_0.numInsts ',\n", + "'system.o3Cpu4.thread_0.numInsts ',\n", + "'system.o3Cpu5.thread_0.numInsts ',\n", + "'system.o3Cpu6.thread_0.numInsts ',\n", + "'system.o3Cpu7.thread_0.numInsts ',\n", + "'system.mem_ctrl.avgRdBWSys ',\n", + "'system.mem_ctrl.avgWrBWSys ',\n", + "'system.mem_ctrl.avgORBLen ',\n", + "'system.far_mem_ctrl.avgRdBWSys ',\n", + "'system.far_mem_ctrl.avgWrBWSys ',\n", + "'system.loc_mem_ctrl.avgRdBWSys ',\n", + "'system.loc_mem_ctrl.avgWrBWSys ',\n", + "'system.loc_mem_ctrl.dram.readBursts ',\n", + "'system.loc_mem_ctrl.dram.writeBursts ',\n", + "'system.loc_mem_ctrl.dram_2.readBursts ',\n", + "'system.loc_mem_ctrl.dram_2.writeBursts ',\n", + "'system.far_mem_ctrl.dram.readBursts ',\n", + "'system.far_mem_ctrl.dram.writeBursts ',\n", + "'system.loc_mem_ctrl.dram.avgRdBW ',\n", + "'system.loc_mem_ctrl.dram.avgWrBW ',\n", + "'system.loc_mem_ctrl.dram_2.avgRdBW ',\n", + "'system.loc_mem_ctrl.dram_2.avgWrBW ',\n", + "'system.far_mem_ctrl.dram.avgRdBW ',\n", + "'system.far_mem_ctrl.dram.avgWrBW ',\n", + "'system.loc_mem_ctrl.dram.busUtil ',\n", + "'system.loc_mem_ctrl.dram.busUtilRead ',\n", + "'system.loc_mem_ctrl.dram.busUtilWrite ',\n", + "'system.loc_mem_ctrl.dram_2.busUtil ',\n", + "'system.loc_mem_ctrl.dram_2.busUtilRead ',\n", + "'system.loc_mem_ctrl.dram_2.busUtilWrite ',\n", + "'system.far_mem_ctrl.dram.busUtil ',\n", + "'system.far_mem_ctrl.dram.busUtilRead ',\n", + "'system.far_mem_ctrl.dram.busUtilWrite ',\n", + "'system.far_mem_ctrl.dram.bytesRead ',\n", + "'system.far_mem_ctrl.dram.bytesWritten ',\n", + "'system.loc_mem_ctrl.dram.bytesRead ',\n", + "'system.loc_mem_ctrl.dram.bytesWritten ',\n", + "'system.loc_mem_ctrl.dram_2.bytesRead ',\n", + "'system.loc_mem_ctrl.dram_2.bytesWritten ',\n", + "'system.mem_ctrl.avgTimeTagCheckRes ',\n", + "'system.mem_ctrl.avgTimeTagCheckResRd ',\n", + "'system.mem_ctrl.avgTimeTagCheckResWr ',\n", + "'system.mem_ctrl.avgPktRespTimeRd ',\n", + "'system.mem_ctrl.avgPktRespTimeWr ',\n", + "'system.mem_ctrl.avgPktORBTime ',\n", + "'system.mem_ctrl.avgPktORBTimeRd ',\n", + "'system.mem_ctrl.avgPktORBTimeWr ',\n", + "'system.mem_ctrl.avgTimeInLocRead ',\n", + "'system.mem_ctrl.avgTimeInLocWrite ',\n", + "'system.mem_ctrl.avgTimeInFarRead ',\n", + "'system.mem_ctrl.missRatio '\n", + " ]\n", + "\n", + "dfCols = [\n", + " 'app',\n", + " 'simSeconds',\n", + " 'hostSeconds',\n", + " 'readReqs',\n", + " 'writeReqs',\n", + " 'servicedByWrQ',\n", + " 'mergedWrBursts',\n", + " 'numTotHits',\n", + " 'numTotMisses',\n", + " 'numColdMisses',\n", + " 'numHotMisses',\n", + " 'numRdMissClean',\n", + " 'numRdMissDirty',\n", + " 'numRdHit',\n", + " 'numWrMissClean',\n", + " 'numWrMissDirty',\n", + " 'numWrHit',\n", + " 'numRdHitDirty',\n", + " 'numRdHitClean',\n", + " 'numWrHitDirty',\n", + " 'numWrHitClean',\n", + " 'numInsts0',\n", + " 'numInsts1',\n", + " 'numInsts2',\n", + " 'numInsts3',\n", + " 'numInsts4',\n", + " 'numInsts5',\n", + " 'numInsts6',\n", + " 'numInsts7',\n", + " 'avgRdBWSys',\n", + " 'avgWrBWSys',\n", + " 'avgORBLen',\n", + " 'farAvgRdBWSys',\n", + " 'farAvgWrBWSys',\n", + " 'locAvgRdBWSys',\n", + " 'locAvgWrBWSys',\n", + " 'readBursts1',\n", + " 'writeBursts1',\n", + " 'readBursts2',\n", + " 'writeBursts2',\n", + " 'readBursts3',\n", + " 'writeBursts3',\n", + " 'loc1AvgRdBW',\n", + " 'loc1AvgWrBW',\n", + " 'loc2AvgRdBW',\n", + " 'loc2AvgWrBW',\n", + " 'farAvgRdBW',\n", + " 'farAvgWrBW',\n", + " 'loc1BusUtil',\n", + " 'loc1BusUtilRead',\n", + " 'loc1BusUtilWrite',\n", + " 'loc2BusUtil',\n", + " 'loc2BusUtilRead',\n", + " 'loc2BusUtilWrite',\n", + " 'farBusUtil',\n", + " 'farBusUtilRead',\n", + " 'farBusUtilWrite',\n", + " 'farBytesRead',\n", + " 'farBytesWritten',\n", + " 'loc1BytesRead',\n", + " 'loc1BytesWritten',\n", + " 'loc2BytesRead',\n", + " 'loc2BytesWritten',\n", + " 'avgTimeTagCheckRes',\n", + " 'avgTimeTagCheckResRd',\n", + " 'avgTimeTagCheckResWr',\n", + " 'avgPktRespTimeRd',\n", + " 'avgPktRespTimeWr',\n", + " 'avgPktORBTime',\n", + " 'avgPktORBTimeRd',\n", + " 'avgPktORBTimeWr',\n", + " 'avgTimeInLocRead',\n", + " 'avgTimeInLocWrite',\n", + " 'avgTimeInFarRead',\n", + " 'missRatio'\n", + "\n", + " ]\n", + "##########################################################\n", + "\n", + "def getStat(filename, stat, index):\n", + " filename = os.path.join(filename).replace('\\\\','/')\n", + " #print(stat)\n", + " #print(filename)\n", + " try:\n", + " x = 0\n", + " with open(filename) as f:\n", + " readlines = f.readlines()\n", + " for l in readlines:\n", + " if stat in l and x < (index-1):\n", + " x = x+1\n", + " elif stat in l and x == (index-1):\n", + " return l\n", + " return 0.0 #for cases where stat was not found\n", + " except: #for cases where the file was not found\n", + " return 0.0\n", + "\n", + "##########################################################\n", + "\n", + "def creatDataFrame(dataDir, suite, index):\n", + " app = []\n", + " if suite == \"GAPBS\":\n", + " app = ['bc', 'bfs', 'cc', 'pr', 'sssp', 'tc']\n", + " if suite == \"NPB\":\n", + " app = ['bt', 'cg', 'ft', 'is', 'lu', 'mg', 'sp', 'ua']\n", + " rows = []\n", + " i = 0\n", + " for a in app:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}/stats.txt'.format(dataDir, a)\n", + " ret_line = getStat(time_file_path, stat, index[i])\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + " i = i+1\n", + " df = pd.DataFrame(rows, columns= dfCols)\n", + " df['totNumInsts'] = df['numInsts0'].astype(int)+df['numInsts1'].astype(int)+df['numInsts2'].astype(int)+df['numInsts3'].astype(int)+df['numInsts4'].astype(int)+df['numInsts5'].astype(int)+df['numInsts6'].astype(int)+df['numInsts7'].astype(int)\n", + " df['totBW'] = (df['avgRdBWSys'].astype(float)+df['avgWrBWSys'].astype(float))/1000000000\n", + " df['coldRate'] = (df['numColdMisses'].astype(float) / (df['numTotMisses'].astype(float)+df['numTotHits'].astype(float))) *100\n", + " df['injRate'] = (df['readReqs'].astype(float) + df['writeReqs'].astype(float))*64/1000000000 / df['simSeconds'].astype(float)\n", + " df['BIPS'] = (df['totNumInsts'].astype(float)/1000000000)/df['simSeconds'].astype(float)\n", + " \n", + " df['accAmp'] = (df['farBytesRead'].astype(float) + df['farBytesWritten'].astype(float) +\n", + " df['loc1BytesRead'].astype(float) + df['loc1BytesWritten'].astype(float) + \n", + " df['loc2BytesRead'].astype(float) + df['loc2BytesWritten'].astype(float)) / (df['readReqs'].astype(float) * 64 + df['writeReqs'].astype(float) * 64)\n", + " \n", + " df['BWBloat'] = (df['loc1AvgRdBW'].astype(float) + df['loc1AvgWrBW'].astype(float) +\n", + " df['loc2AvgRdBW'].astype(float) + df['loc2AvgWrBW'].astype(float) +\n", + " df['farAvgRdBW'].astype(float) + df['farAvgWrBW'].astype(float)) / ((df['avgRdBWSys'].astype(float) + df['avgWrBWSys'].astype(float)) / 1000000)\n", + " return df" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [], + "source": [ + "df_gap22_cas = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/cascade/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", + "df_npbC_cas = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/cascade/1GB_8GB_g22_nC/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", + "\n", + "df_gap25_cas = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/cascade/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", + "df_npbD_cas = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/cascade/1GB_85GB_g25_nD/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", + "\n", + "df_gap22_ram = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/rambus/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", + "df_npbC_ram = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/rambus/1GB_8GB_g22_nC/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", + "\n", + "df_gap25_ram = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/rambus/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", + "df_npbD_ram = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/rambus/1GB_85GB_g25_nD/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", + "\n", + "\n", + "df_gap22_orc = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/oracle/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", + "df_npbC_orc = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/oracle/1GB_8GB_g22_nC/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", + "\n", + "df_gap25_orc = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/oracle/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", + "df_npbD_orc = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/oracle/1GB_85GB_g25_nD/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", + "\n", + "df_gap22_noDC = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/noDC/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", + "df_npbC_noDC = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/noDC/1GB_8GB_g22_nC/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", + "\n", + "df_gap25_noDC = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/noDC/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", + "df_npbD_noDC = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/noDC/1GB_85GB_g25_nD/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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WoT33ntPyhIREYHZs2fDw8NDmm7W2dkZQ4YM0WgWIiIiIiKqXJULi5iYGAAPeyxWrVqlctmTiYkJmjZtilWrVmk03LJlyzBt2jSMHTsWN2/ehLOzMz744ANMnz5dajN58mQUFRVhzJgxyM/PR9euXbFz507ew4KIiIiIqA7JhJr37+7Zsye2bNkCW1vb2spU5xQKBaytrVFQUMDLoohIrxUVFUk9yoWFhbCwsNByIiIi0mfqfE9We1aoP/74o9rBiIiIiIjoxVSt6WavXbuG7du34+rVqygtLVVZ9+jmdURERERE9PJQu7BITEzEoEGD0KxZM6SlpcHb2xuXL1+GEAJt27atjYxERERERKTj1J5uNjo6GhMnTsTp06dhZmaGzZs3IysrC927d8ewYcNqIyMREREREek4tQuL8+fP49133wUAGBkZ4d69e7C0tMQXX3yB+fPnazwgERERERHpPrULCwsLC2lchZOTEy5evCit+/vvvzWXjIiIiIiI9IbaYyw6deqEP//8Ey1btkT//v3x6aef4vTp09iyZQs6depUGxmJiIiIiEjHqV1YLFq0CIWFhQCAmTNnorCwEBs3boSHhwdnhCIiIiIiekmpXVg0a9ZM+reFhYXG77ZNRERERET6R+0xFpXZsmULfHx8NLU7IiIiIiLSI2oVFt988w3efPNNvPPOO0hJSQEA7NmzB35+fhg5ciQCAgJqJSQREREREem2KhcW8+bNw7hx43D58mVs374dvXr1wpw5czBixAi8/fbbuHbtGmJjY2szKxERERER6agqj7GIj49HXFwcQkJCsH//fnTv3h0HDx7EX3/9BQsLi9rMSEREREREOq7KPRZXr15Fr169AACvvvoqjI2NMXPmTBYVRERERERU9cKipKQEZmZm0mMTExPY2dnVSigiIiIiItIvak03O23aNNSrVw8AUFpaitmzZ8Pa2lqlDe9lQURERET08qlyYdGtWzekp6dLj7t06YJLly6ptJHJZJpLRkREREREeqPKhUVSUlItxqjc9evXERUVhV9//RXFxcVwd3dHfHw8/P39AQBCCMyYMQNxcXHIz89HQEAAYmNj4eHhoZW8REREREQvI43dIK823LlzBwEBATA2Nsavv/6Kc+fO4euvv4atra3UZsGCBVi6dClWrVqFlJQUWFhYICgoCPfv39diciIiIiKil4taYyzq2vz58+Hi4oL4+HhpmZubm/RvIQQWL16MqVOnYvDgwQCAdevWwcHBAdu2bUNwcHCdZyYiIiIiehnpdI/F9u3b4e/vj2HDhqFhw4bw8/NDXFyctD4zMxM5OTkIDAyUlllbW6Njx45ITk7WRmQiIiIiopeSThcWly5dksZL7Nq1Cx999BE++eQTrF27FgCQk5MDAHBwcFDZzsHBQVpXkZKSEigUCpUfIiIiIiKqPp2+FEqpVMLf3x9z5swBAPj5+eHMmTNYtWoVQkJCqr3fuXPnYubMmZqKSURERET00lO7x2Lnzp34888/pccrVqyAr68v3nnnHdy5c0ej4ZycnNCqVSuVZS1btsTVq1cBAI6OjgCA3NxclTa5ubnSuopER0ejoKBA+snKytJobiIiIiKil43ahcWkSZOkS4dOnz6NTz/9FP3790dmZiYiIyM1Gi4gIEDl3hkAcOHCBbi6ugJ4OJDb0dERiYmJ0nqFQoGUlBR07ty50v2amppCLper/BARERERUfWpfSlUZmam1IuwefNmDBw4EHPmzMHx48fRv39/jYabMGECunTpgjlz5uCtt97C4cOH8e233+Lbb78F8PCGfBEREZg9ezY8PDzg5uaGadOmwdnZGUOGDNFoFiIiIiIiqpzahYWJiQmKi4sBAL///jveffddAICdnZ3GB0G3b98eW7duRXR0NL744gu4ublh8eLFGDFihNRm8uTJKCoqwpgxY5Cfn4+uXbti586dMDMz02gWIiIiIiKqnEwIIdTZYNCgQSgtLUVAQABmzZqFzMxMNGrUCL/99hvCw8Nx4cKF2spaaxQKBaytrVFQUMDLoohIrxUVFcHS0hIAUFhYCAsLCy0nIiIifabO92S1x1gsX74cRkZG+PnnnxEbG4tGjRoBAH799Vf069eveomJiIiIiEivqd1j8SJijwURvSjYY0FERJpUqz0Wx48fx+nTp6XH//73vzFkyBBMmTIFpaWl6qclIiIiIiK9p3Zh8cEHH0jjKC5duoTg4GDUq1cPmzZtwuTJkzUekIiIiIiIdJ/ahcWFCxfg6+sLANi0aRO6deuGDRs2ICEhAZs3b9Z0PiIiIiIi0gNqFxZCCCiVSgAPp5t9dO8KFxcX/P3335pNR0REREREekHtwsLf3x+zZ8/Gd999h71792LAgAEAHt44z8HBQeMBiYiIiIhI96ldWCxevBjHjx9HeHg4/vnPf8Ld3R0A8PPPP6NLly4aD0hERERERLpPY9PN3r9/H4aGhjA2NtbE7uoUp5slohcFp5slIiJNUud7spGmfqmZmZmmdkVERERERHqmSoWFnZ0dLly4gPr168PW1hYymazStnl5eRoLR0RERERE+qFKhUVMTAysrKwAPBxjQURERERE9DiNjbHQZxxjQUQvCo6xICIiTVLne7Las0IRERERERE9qcqDtw0NDavUrry8vNphiIiIiIhIP1W5sBBCwNXVFSEhIfDz86vNTEREREREpGeqXFgcPnwYq1evxpIlS+Dm5ob33nsPI0aMgK2tbW3mIyIiIiIiPVDlMRb+/v6IjY3FjRs3EBkZia1bt6Jx48YIDg7G7t27azOjZN68eZDJZIiIiJCW3b9/Hx9//DHs7e1haWmJoUOHIjc3t07yEBERERHRQ2oP3jYzM8M//vEPJCYm4syZM7h58yb69etX6/evOHLkCL755hv4+PioLJ8wYQJ++eUXbNq0CXv37kV2djbeeOONWs1CRERERESqqjUr1LVr1zB79mz06dMHaWlpmDRpUq1O01pYWIgRI0YgLi5O5dKrgoICrF69GosWLUKvXr3Qrl07xMfH4+DBgzh06FCt5SEiIiIiIlVVLixKS0uxceNG9O3bFx4eHjh+/DgWL16MrKwszJs3D0ZGVR6uobaPP/4YAwYMQGBgoMryY8eO4cGDByrLW7RogSZNmiA5ObnW8hARERERkaoqVwNOTk6wsrJCSEgIVq5ciYYNGwJ4eDOmx2m65+LHH3/E8ePHceTIkafW5eTkwMTEBDY2NirLHRwckJOTU+k+S0pKUFJSIj1WKBQay0tERERE9DKqco/FnTt3cPXqVcyaNQuenp6wtbVV+bGxsdH4DFFZWVkYP3481q9fDzMzM43td+7cubC2tpZ+XFxcNLZvIiIiIqKXUZV7LP7444/azFGhY8eO4ebNm2jbtq20rLy8HPv27cPy5cuxa9culJaWIj8/X6XXIjc3F46OjpXuNzo6GpGRkdJjhULB4oKIiIiIqAaqXFh07969NnNUqHfv3jh9+rTKstDQULRo0QJRUVFwcXGBsbExEhMTMXToUABAeno6rl69is6dO1e6X1NTU5iamtZqdiIiIiKil0ntjbjWACsrK3h7e6sss7CwgL29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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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ixYtwnvvvSdlmTRpEubMmQMvLy/pcrOurq4IDg7WahYiIiIiIqqa2oVFbGwsgEc9FvHx8SrDnszMzNC0aVPEx8drNdyyZcswbdo0jBs3Djdu3ICrqys++OADTJ8+XVonMjISJSUlGDt2LIqKitC9e3fs2LGD97AgIiIiIqpDMqHh/bt79+6NzZs3w97evrYy1TmFQgFbW1sUFxdzWBQRGbSSkhKpR/nu3buwsrLScSIiIjJkmnxO1viqUL/99lu1gxERERER0YupWpebvXbtGrZt24acnByUl5erLHt88zoiIiIiInp5aFxYJCcnY/DgwWjWrBkyMzPh4+ODy5cvQwiB9u3b10ZGIiIiIiLScxpfbjY6OhpTpkzByZMnYWFhgU2bNuHq1avo2bMnhg4dWhsZiYiIiIhIz2lcWJw9exbvvvsuAMDExAT37t2DtbU1Zs2aha+++krrAYmIiIiISP9pXFhYWVlJ8ypcXFxw8eJFadmff/6pvWRERERERGQwNJ5j0blzZ/z+++9o1aoVBg4ciE8++QQnT57E5s2b0blz59rISEREREREek7jwmLRokW4e/cuAGDmzJm4e/cuNmzYAC8vL14RioiIiIjoJaVxYdGsWTPpeysrK63fbZuIiIiIiAyPxnMsqrJ582a0bdtWW7sjIiIiIiIDolFh8c033+Ctt97C3//+d6SnpwMA9uzZAz8/P4wYMQLdunWrlZBERERERKTf1C4s5s2bhwkTJuDy5cvYtm0b+vTpg5iYGAwfPhx/+9vfcO3aNcTFxdVmViIiIiIi0lNqz7FITExEQkICRo4cif3796Nnz544ePAgLly4ACsrq9rMSEREREREek7tHoucnBz06dMHAPDqq6/C1NQUM2fOZFFBRERERETqFxZlZWWwsLCQHpuZmcHBwaFWQhERERERkWHR6HKz06ZNQ7169QAA5eXlmDNnDmxtbVXW4b0siIiIiIhePmoXFj169EBWVpb0uGvXrrh06ZLKOjKZTHvJiIiIiIjIYKhdWKSkpNRijKpdv34dUVFR+OWXX1BaWgpPT08kJibC398fACCEwIwZM5CQkICioiJ069YNcXFx8PLy0kleIiIiIqKXkdZukFcbbt++jW7dusHU1BS//PILzpw5g4ULF8Le3l5aZ/78+Vi6dCni4+ORnp4OKysrBAUF4f79+zpMTkRERET0ctFojkVd++qrr+Du7o7ExESpzcPDQ/peCIHFixfj888/x5AhQwAAa9euhZOTE7Zu3YrQ0NA6z0xERERE9DLS6x6Lbdu2wd/fH0OHDkXDhg3h5+eHhIQEaXl2djby8/MRGBgotdna2iIgIACpqam6iExERERE9FLS68Li0qVL0nyJX3/9FR999BE+/vhjrFmzBgCQn58PAHByclLZzsnJSVpWmbKyMigUCpUvIiIiIiKqPr0eCqVUKuHv74+YmBgAgJ+fH06dOoX4+HiMHDmy2vudO3cuZs6cqa2YREREREQvPY17LHbs2IHff/9derxixQr4+vri73//O27fvq3VcC4uLmjdurVKW6tWrZCTkwMAcHZ2BgAUFBSorFNQUCAtq0x0dDSKi4ulr6tXr2o1NxERERHRy0bjwuLTTz+Vhg6dPHkSn3zyCQYOHIjs7GxERERoNVy3bt1U7p0BAOfOnUOTJk0APJrI7ezsjOTkZGm5QqFAeno6unTpUuV+zc3NIZfLVb6IiIiIiKj6NB4KlZ2dLfUibNq0Ca+99hpiYmJw7NgxDBw4UKvhJk+ejK5duyImJgZvv/02Dh06hG+//RbffvstgEc35Js0aRLmzJkDLy8veHh4YNq0aXB1dUVwcLBWsxARERERUdU0LizMzMxQWloKANi9ezfeffddAICDg4PWJ0F37NgRW7ZsQXR0NGbNmgUPDw8sXrwYw4cPl9aJjIxESUkJxo4di6KiInTv3h07duyAhYWFVrMQEREREVHVZEIIockGgwcPRnl5Obp164bZs2cjOzsbjRo1ws6dOxEeHo5z587VVtZao1AoYGtri+LiYg6LIiKDVlJSAmtrawDA3bt3YWVlpeNERERkyDT5nKzxHIvly5fDxMQEP/30E+Li4tCoUSMAwC+//IIBAwZULzERERERERk0jXssXkTssSCiFwV7LIiISJtqtcfi2LFjOHnypPT43//+N4KDgzF16lSUl5drnpaIiIiIiAyexoXFBx98IM2juHTpEkJDQ1GvXj1s3LgRkZGRWg9IRERERET6T+PC4ty5c/D19QUAbNy4ET169MD69euRlJSETZs2aTsfEREREREZAI0LCyEElEolgEeXm3187wp3d3f8+eef2k1HREREREQGQePCwt/fH3PmzMH333+PvXv3YtCgQQAe3TjPyclJ6wGJ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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_cas['app']\n", + "gap_22_cas = df_gap22_cas['coldRate'].astype(float)\n", + "\n", + "gap_25_cas = df_gap25_cas['coldRate'].astype(float)\n", + "\n", + "app_npb = df_npbC_cas['app']\n", + "npb_C_cas = df_npbC_cas['coldRate'].astype(float)\n", + "\n", + "npb_D_cas = df_npbD_cas['coldRate'].astype(float)\n", + "\n", + "# Multi bar Chart1\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,100])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*2, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + "\n", + "offset = i*2+1\n", + "for i,app in enumerate(app_npb):\n", + " plt.bar(offset+i*2+1, npb_C_cas[i], width=1, color=cmap(1))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=10, color='black')\n", + "\n", + "plt.ylabel(\"Cold Miss Rate\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "\n", + "# Multi bar Chart2\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,100])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*2, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + "\n", + "offset = i*2+1\n", + "for i,app in enumerate(app_npb):\n", + " plt.bar(offset+i*2+1, npb_D_cas[i], width=1, color=cmap(1))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=10, color='black')\n", + "\n", + "plt.ylabel(\"Cold Miss Rate\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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u4kdERERERG9X5QuLFavXo3u3bvD398f/v7+svaCggJs2LABffr0KdeARERERESk+ZQuLPr27Yu2bdvCyspKrv3+/fvo27cvCwsiIiIiUgiHZr5blL6PhRACEonklfYbN27A3Ny8XEIREREREZF2UbjHwtPTExKJBBKJBK1bt4ae3v82LSwsRGpqKtq2bauSkEREREREpNkULiye35AuOTkZgYGBMDU1lS0zMDCAo6NjqS43S0RERERE2k/hwmL8+PEAAEdHR3Tv3p03qCMiIiKi9x7nifyP0pO3Q0JCVJGDiIiIiIi0mNKFRWFhIaKjo7Fp0yZcv34dBQUFcsuzsrLKLRwREREREWkHpa8KFRUVhTlz5qB79+7IyclBeHg4OnfuDB0dHUyYMEEFEYmIiIiISNMpXVisXbsWy5cvx1dffQU9PT307NkTP/74I8aNG4fExERVZCQiIiIiIg2ndGGRkZGB+vXrAwBMTU2Rk5MDAGjfvj1+++238k1HRERERERaQenCwt7eHunp6QCAmjVrYs+ePQCAY8eOwdDQsHzTERERERGRVlC6sPjkk08QHx8PABg6dCjGjh0LFxcX9OnTB/369Sv3gEREREREpPmUvirU9OnTZd93794d1atXx5EjR+Di4oIOHTqUazgiIiIiItIOShcWL/P19YWvry8A4Pjx4/Dy8ipzKCIiIiIi0i5KD4V68OABHj16JNeWnJyMDh06wMfHp9yCERERERGR9lC4sEhLS4Ofnx/Mzc1hbm6O8PBw5OXloU+fPvDx8YGJiQmOHDmiyqxERERERKShFB4K9fXXX+Px48eYN28e4uLiMG/ePBw6dAg+Pj64fPky7O3tVZmTiIiIiIg0mMKFxcGDBxEXFwdfX19069YNNjY26NWrF0aMGKHCeEREREREpA0UHgqVmZkJJycnAICVlRUqVKiAjz76SGXBiIiIiIhIeyg1eVtHR0fuewMDg3IPRERERERE2kfhoVBCCNSqVQsSiQTAs6tDeXp6yhUbAJCVlVW+CYnKie/43So/RmJUoMqPQURE5UPVnwv8TKD3jcKFRUxMjCpzEBERERGRFlO4sAgJCVFlDkyfPh2RkZEYPnw45s6dCwB4/PgxvvrqK2zYsAH5+fkIDAzE4sWLYW1trdIsRERERESkHKVvkKcKx44dww8//AB3d3e59pEjR+LX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ZGdny/VaZGZmwsbGpth9GRoawtDQsFQ5iIiIiIiodBQuLObPnw/g2U3wfvzxR5iamsqWFRYW4uDBg6hTp45SBxdCYOjQodi6dSv2798PJycnueWNGjWCvr4+4uPjERwcDABISUnB9evX4efnp9SxiIiIiIhIdRQuLKKjowE8KwaWLl0qN+zJwMAAjo6OWLp0qVIHHzx4MNatW4dffvkFZmZmsnkT5ubmMDY2hrm5OcLCwhAeHo5KlSpBKpVi6NCh8PPz4xWhiIiIiIg0iMKFRWpqKgCgZcuWiIuLQ8WKFct88CVLlgAAWrRoIdceExOD0NBQAM8KGh0dHQQHByM/Px+BgYFYvHhxmY9NRERERETlR+k5Fn/++afs++fzLSQSSakOXtJ8jRcZGRlh0aJFWLRoUamOQUREREREqleq+1isXr0a9evXh7GxMYyNjeHu7o41a9aUdzYiIiIiItISSvdYzJkzB2PHjsWQIUPg7+8PAPjrr78wcOBA/Pfffxg5cmS5hyQiIiIiIs2mdGGxYMECLFmyBH369JG1dezYEW5ubpgwYQILCyIiIiKi95DSQ6HS09PRpEmTV9qbNGmC9PT0cglFRERERETaRenCwtnZGZs2bXqlfePGjXBxcSmXUEREREREpF2UHgoVFRWF7t274+DBg7I5FocPH0Z8fHyxBQcREREREb37lC4sgoODkZSUhOjoaGzbtg0AULduXRw9ehSenp7lnY+IXuA7frdK958YFajS/RMREdG7S+nCAgAaNWqEn376qbyzEBERERGRllK4sMjNzVVoPalUWuowRERERESknRQuLCwsLF57h20hBCQSCQoLC8slGBG9mzici4iI6N2kcGHx559/yr4XQuDjjz/Gjz/+iKpVq6okGBERERERaQ+FC4vmzZvLPdbV1YWvry9q1KhR7qGIiIiIiEi7KH0fCyIiIiIiopexsCAiIiIiojIrU2HxusncRERERET0/lB4jkXnzp3lHj9+/BgDBw6EiYmJXHtcXFz5JCMiIiIiIq2hcGFhbm4u97h3797lHoaIiIiIiLSTwoVFTEyMKnMQEREREZEWU7iwoLLhTcGIiIiI6F3Gq0IREREREVGZsbAgIiIiIqIyY2FBRERERERlxsKCiIiIiIjKjIUFERERERGVmVYUFosWLYKjoyOMjIzg4+ODo0ePqjsSERER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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_cas['app']\n", + "gap_22_cas = df_gap22_cas['missRatio'].astype(float)-df_gap22_cas['coldRate'].astype(float)\n", + "\n", + "gap_25_cas = df_gap25_cas['missRatio'].astype(float)-df_gap25_cas['coldRate'].astype(float)\n", + "\n", + "app_npb = df_npbC_cas['app']\n", + "npb_C_cas = df_npbC_cas['missRatio'].astype(float)-df_npbC_cas['coldRate'].astype(float)\n", + "\n", + "npb_D_cas = df_npbD_cas['missRatio'].astype(float)-df_npbD_cas['coldRate'].astype(float)\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,100])\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*2, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + "\n", + "offset = i*2+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*2+1, npb_C_cas[i], width=1, color=cmap(1))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "\n", + "plt.ylabel(\"Hot Miss Rate (%)\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "#plt.ylim([0,55])\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*2, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + "\n", + "offset = i*2+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*2+1, npb_D_cas[i], width=1, color=cmap(1))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "\n", + "plt.ylabel(\"Hot Miss Rate (%)\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_cas['app']\n", + "gap_22_cas = df_gap22_cas['missRatio'].astype(float)\n", + "\n", + "gap_25_cas = df_gap25_cas['missRatio'].astype(float)\n", + "\n", + "app_npb = df_npbC_cas['app']\n", + "npb_C_cas = df_npbC_cas['missRatio'].astype(float)\n", + "\n", + "npb_D_cas = df_npbD_cas['missRatio'].astype(float)\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,100])\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*2, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + "\n", + "offset = i*2+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*2+1, npb_C_cas[i], width=1, color=cmap(1))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "\n", + "plt.ylabel(\"Total Miss Rate (%)\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "#plt.ylim([0,55])\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*2, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + "\n", + "offset = i*2+1\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*2+1, npb_D_cas[i], width=1, color=cmap(1))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "\n", + "plt.ylabel(\"Total Miss Rate (%)\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAxYAAADSCAYAAADXL1aYAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAABBOklEQVR4nO3dd3gUVfs38O+kbPomJJCQQBqETgJIJ0roTYg0RVoKCKJAgCglICDwUMUgoIJiSEBFUSmiwqOPIaGEIpJCDzX0EkoqkLbn/YOX/bGk7WaTLfD9XNdeV/bMnDP3bGZn9945Z44khBDQkfnz58PKygpTp04FAMTFxaFXr16ws7NDZmYmYmJiMHz4cF2FQ0RERERElcRElxv75Zdf0LhxY+XzhQsXIiwsDHfv3sXnn3+ORYsW6TIcIiIiIiKqJGa62MjGjRshhEBaWhqSk5Nx7949CCGQkJCA1157DRs3boRCocDFixexceNGAEBQUJAuQiMiIiIiokqgk8TC09MTACCTyeDi4gJPT08kJydDLpejc+fOEEIgLy8PkiTBy8sLOuydRURERERElUDS5RiLHj16wNraGtOnT8f8+fNRs2ZNREdHAwCOHz+OwYMHIzU1VVfhEBERERFRJdFpYpGSkoI33ngDV65cQcOGDfHnn3/C3d0dAPDBBx+gsLAQK1eu1FU4RERERERUSXSaWDx17949ODk5qZTdvHkTcrkcNjY2ug6HiIiIiIi0pJfE4qlr167Bzc0NJiY6vTkVERERERFVMr1+o2/cuDHS0tL0GQIREREREVUCvSYWvPsTEREREdGLgX2QiIiIiIhIa3pNLGbOnAlHR8cK11+zZg38/Pwgl8shl8vRvn177Nq1qxIjJCIiIiIideh18La2fvvtN5iamqJevXoQQmDDhg345JNPkJSUhCZNmug7PCIiIiKil4bOEov58+ertd6cOXO02o6joyM++eQTjB49Wqt2iIiIiIhIfTpLLExMTODm5gZnZ+dSB21LkoTExMQKtV9UVISff/4ZwcHBSEpKQuPGjbUJl4iIiIiINGCmqw317t0bu3fvRqtWrTBq1Cj07du3UuavOH78ONq3b4/Hjx/D1tYW27ZtKzWpyMvLQ15envK5QqHA/fv34eTkBEmStI6FiIiIiOhFIoRAdna2WnPP6XSMxY0bN7BhwwbExMQgKysLQUFBGDVqFBo0aFDhNvPz83HlyhVkZmbil19+wTfffIM9e/aUmFx8/PHHmDdvnja7QERERET00rl69Spq165d5jp6G7y9d+9eREdHY8uWLfD19cXff/8NKysrrdvt1q0b6tati6+++qrYsuevWGRmZsLDwwNXr16FXC7XettERPqWm5sLNzc3AE9+zLGxsdFzREREZMyysrLg7u6OjIwM2Nvbl7muzrpCPa9169ZIS0vDqVOnkJSUhIKCgkpJLBQKhUry8CwLCwtYWFgUK396u1oiImNnamqq/FsulzOxICKiSqHOsAGdJxYHDx7E+vXr8dNPP6F+/foIDQ3FsGHDKvTFPiIiAr1794aHhweys7OxadMmxMfH488//6yCyImIiIiIqDQ6SyyWLVuGmJgY3L17F8OHD8e+ffvg5+enVZt37txBUFAQbt68CXt7e/j5+eHPP/9E9+7dKylqIiIiIiJSh05vN+vh4YG+fftCJpOVul5kZKQuwgHwpM+Yvb09MjMzS71iUlRUhIKCAp3FRKRP5ubmKl1pyPjk5ubC1tYWAJCTk8OuUEREpBV1vi8/pbMrFh07doQkSTh58qSuNqm1nJwcXLt2rdR5N4heNJIkoXbt2sovpkRERETq0lliER8fr6tNVYqioiJcu3YN1tbWqFGjBue5oBeeEALp6em4du0a6tWrxysXREREpBG93RXqeadPn0ZUVBSWL1+u71AAAAUFBRBCoEaNGpVytyoiY1CjRg2kpaWhoKCAiQURERFpRPupr7WQm5uLqKgodOjQAU2aNMF///tffYZTIl6poJcJj3ciIiKqKL0kFgkJCRg1ahRcXFwwduxYdOjQAadOncKJEyf0EQ4REREREWlJZ4nFnTt3sGzZMjRs2BCDBw+Gg4MD4uPjYWJiglGjRqFhw4a6CoXohZaWlgZJkpCRkaHvUIiIiOglorMxFp6enhg8eDBWrlyJ7t27w8REr72wKqzd3KqffO/QvJ5qrffsnXsePXoEMzMzmJubAwBee+017Nq1C5IkwcrKCmZmZjAzM0ODBg0wZMgQjB8/XrluTEwMRo8eDSsrK0iSBBcXF4wfPx5TpkxR2V5ubi5cXV3RqFEjHD58WGVZSEgINmzYgHXr1uGdd95Rlv/8889466238MYbb2D79u0VeTk0Erj99Srfxo7+f2hc5++//8a8efOQ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/v374evrW2zwdlhYmNpt+fr6YufOnXB3d9c0DCIiIiIiMiAaT5Dn7e1demOShIsXL6rdlp2dHVJSUvQ227YmE34QERkDTpBHRESVqUonyONYCSIiIiIiep7GE+RVptdeew1WVlb6DIGIiIiIiCqBWlcswsPDsWDBAtjY2CA8PLzMdSMjI9Xe+M6dO9VetySLFy/G1q1bcebMGVhZWaFDhw5YunQpGjRooFW7RERERESkGbUSi6SkJBQUFCj/1lZRURG2b9+O06dPAwCaNGmCwMBAmJqaatTOnj17MH78eLRu3RqFhYWYOXMmevTogVOnTrFfMRERERGRDmk8eFtb58+fx+uvv45r164pryykpqbC3d0df/zxh8a3sX1Weno6nJ2dsWfPHnTs2LHc9Tl4m4heNBy8TURElUmT78saj7EYNWoUsrOzi5Xn5uZi1KhR5dYPCwtDnTp1cPXqVSQmJiIxMRFXrlyBt7e3RreqLUlmZiYAwNHRscTleXl5yMrKUnkQEREREZH2NL5iYWpqips3b8LZ2Vml/O7du6hZsyYKCwvLrG9jY4NDhw7B19dXpTwlJQX+/v7IycnRJBwlhUKBwMBAZGRkYP/+/SWu8/HHH2PevHnFynnFgoheFLxiQURElalKbjeblZUFIQSEEMjOzoalpaVyWVFREXbu3Fks2SiJhYVFiVc8cnJyIJPJ1A2nmPHjx+PEiROlJhUAEBERoTL4PCsri5PzERERERFVArUTCwcHB0iSBEmSUL9+/WLLJUkq8WrA8/r27YuxY8ciKioKbdq0AQAcPnwY48aNQ2BgoAah/58JEybg999/x969e1G7du1S17OwsICFhUWFtkFERERERKVTO7GIi4uDEAJdunTBli1bVMYxyGQyeHp6ws3Nrdx2Vq1aheDgYLRv3x7m5uYAgMLCQgQGBmLlypUaBS+EwMSJE7Ft2zbEx8eXOSs4ERERERFVHbUTi4CAAABPZt728PCAJEkV2qCDgwN+/fVXnDt3DmfOnAEANGrUCD4+Phq3NX78eGzatAm//vor7OzscOvWLQCAvb09J94jIiIiItIhnd9utjKVltxER0cjJCSk3Pq83SwRvWg4eJuIiCpTlQzerixFRUWIiYlBbGws7ty5A4VCobJ89+7dardlxDkREREREdELReeJxaRJkxATE4PXX38dTZs2rXCXKiIiIiIiMhw6Tyx+/PFH/PTTT+jTp4+uN01ERERERFVE45m3tSWTySo0UJuIiIiIiAyXxonF7du3MXLkSLi5ucHMzAympqYqj/J88MEHWLlyJcdHEBERERG9QDTuChUSEoIrV65g9uzZcHV11XiMxP79+xEXF4ddu3ahSZMmyrksntq6daumIRERERERkZ5pnFjs378f+/btQ/PmzSu0QQcHBwwYMKBCdYmIiIiIyDBpnFi4u7tr1Y0pOjq6wnWJiIjazf1Tq/qH5vWspEiIdEubY5/HPemCxmMsPvvsM8yYMQNpaWlVEA4RERERERkjja9YDBkyBA8fPkTdunVhbW1dbIzE/fv3Ky04IiIiIiIyDhonFp999lkVhEFERERERMZM48QiODi4KuIgIiIiIiIjVqGZt4uKirB9+3acPn0aANCkSRMEBgaqNY8FERERERG9eDQevH3+/Hk0atQIQUFB2Lp1K7Zu3YoRI0agSZMmuHDhglpt7NmzB/369YOPjw98fHwQGBiIffv2aRw8EREREREZBo0Ti7CwMNStWxdXr15FYmIiEhMTceXKFXh7eyMsLKzc+t999x26desGa2trhIWFISwsDFZWVujatSs2bdpUoZ0gIiIiIiL90rgr1J49e3Do0CE4Ojoqy5ycnLBkyRL4+/uXW3/hwoVYtmwZpkyZoiwLCwtDZGQkFixYgGHDhmkaEhEREVG5OAcKUdXS+IqFhYUFsrOzi5Xn5ORAJpOVW//ixYvo169fsfLAwEBcunRJ03CIiIiIiMgAaJxY9O3bF2PHjsXhw4chhIAQAocOHcK4ceMQGBhYbn13d3fExsYWK//777/h7u6uaThERERERGQANO4KtWrVKgQHB6N9+/bKyfEKCwsRGBiIlStXllv/gw8+QFhYGJKTk9GhQwcAQEJCAmJiYtSqT0RERKQPgdtf16r+jv5/VFIkRIZJ48TCwcEBv/76K86dO4czZ84AABo1agQfHx+16r/33nuoWbMmPv30U/z000/K+ps3b8Ybb7yhaThERERERGQAKjSPBQDUq1cP9erVq1DdAQMGYMCAARXdNBERERERGRi1Eovw8HAsWLAANjY2CA8PL3PdyMjIMpfXqVMHR44cgZOTk0p5RkYGXnnlFVy8eFGdkIiIiIiIyIColVgkJSWhoKBA+bc20tLSUFRUVKw8Ly8P169f16ptIiIiIiLSD7USi7i4uBL/1sSOHTuUf//555+wt7dXPi8qKkJsbCy8vLwq1DYREREREemXxmMsRo0ahZUrV8LOzk6lPDc3FxMnTsT69etLrNe/f38AgCRJCA4OVllmbm4OLy8vfPrpp5qGQ3rGyYaIiIiICKhAYrFhwwYsWbKkWGLx6NEjbNy4sdTEQqFQAAC8vb1x5MgRVK9evQLhEtGLgkkpvax47BPRi0rtxCIrK0s5IV52djYsLS2Vy4qKirBz5044OzuX2w5n1y6OHzJERKQubeZS4DwKRFSV1E4sHBwcIEkSJElC/fr1iy2XJAnz5s2r1OCIiIiIiMg4qJ1YxMXFQQiBLl26YMuWLXB0dFQuk8lk8PT0hJubW5UESUREREREhk3txCIgIADAk65MHh4ekCSpyoIiIiIiIiLjovHg7cuXL+Py5culLu/YsaNWARERERFR5dJmbA7A8TmkHo0Ti06dOhUre/bqRUmT32VlZandvlwu1zQkogrjwHkiIvXxnElEZdE4sXjw4IHK84KCAiQlJWH27NlYuHBhiXWeDvxWR0mJCRERERERGTaNE4tnZ8x+qnv37pDJZAgPD8fRo0eLLX92tu60tDTMmDEDISEhaN++PQDg4MGD2LBhAxYvXqxpOET0kuJlfSIiIsOicWJRGhcXF6Smppa47OnAbwCYP38+IiMjMXToUGVZYGAgfH198fXXXxeblZvKxy9YLy92SyAiIiJDoXFicezYMZXnQgjcvHkTS5YsQfPmzcutf/DgQaxdu7ZYeatWrfDOO+9oGg4RERERERkAjROL5s2bQ5IkCCFUytu1a4f169eXW9/d3R3r1q3DsmXLVMq/+eYbuLu7axoOERGRRniVl4ioamicWFy6dEnluYmJCWrUqAFLS0u16q9YsQKDBg3Crl270LZtWwDAP//8g3PnzmHLli0axbJ371588sknOHr0KG7evIlt27ahf//+GrVBRFQR7IZGRESkSuPEwtPTU6sN9unTB2fPnsWaNWtw5swZAEC/fv0wbtw4ja9Y5ObmolmzZhg1ahQGDhyoVVykH/zlkIiIiOjFoHFiERYWBh8fH4SFhamUf/755zh//jw+++yzcttwd3fHokWLNN10Mb1790bv3r21bic/Px/5+flat1NRptDuFrsmRSZa1ddm3405dkD7+PV53ADG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ebGuqwDg7e0NBwcHtdt6/pxb0jl72LBhmDlzJpKSkoqNsygoKEB+fj7HWVCVY2JBZGS+/PJL+Pv7o1WrVvj444/h5+cHExMTHDlyBGfOnEHLli0RFRWFNm3aoGPHjsXqt27dGlFRUSXOa1GajIwM3Lp1CwqFAufOncP8+fNRv359NGrUCPfu3cObb76JUaNGwc/PD3Z2dvj333+xbNkyvPHGG6W2ef36dXTq1Amenp5Yvnw50tPTlctq1qwJ4En3p759+2LSpEkYNGgQbt26BQCQyWQcwE1EBs3X1xfDhw/HqlWrNK6bnZ2NW7duQQiBq1evYtq0aahRowY6dOhQap3Jkyfjjz/+QNeuXbFgwQK8+uqryvPx0qVLERUVxdvNUtXT812piKgCbty4ISZMmCC8vb2Fubm5sLW1FW3atBGffPKJyMzMFE5OTmLZsmUl1l26dKlwdnYW+fn5Jd5u9nkAlA9JkoSrq6sYMmSIuHDhghBCiMePH4sZM2aIV155Rdjb2wtra2vRoEED8dFHHylvWVuS6OholbaffTwVHBxc4vKAgACNXzMioqoUHBws3njjDZWyS5cuCZlMVubtZp/n6empcr6rUaOG6NOnj0hKSio3hsePH4vFixcLX19fYWlpKRwdHYW/v7+IiYkRBQUFWuwdkXokITjah4iIiIiItMO7QhERERERkdaYWBARERERkdaYWBARERERkdaYWBARERERkdaYWBARERERkdaYWBARERERkdaYWBARERERkdaYWBARERERkdaYWBARERERkdaYWBARERERkdaYWBARERERkdaYWBARERERkdb+H7nyKaLPkc3SAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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qU9yYaGpkpISREdHIy4uDunp6VAoFCrz9+zZo/a6tHwJDiIiIiIiKofWC4vJkycjOjoab775Jpo3b17lLlVERERERKQ/tF5Y/PTTT/j555/Rr18/bW+aiIiIiIheEMkXyNOUTCar0kBtIiIiIiLSX5ILi7t372LkyJFwcXGBiYkJjI2NVW6V+fjjj7Fy5UqOjyAiIiIieolI7goVFBSEGzduYNasWXB2dpY8RuLgwYPYu3cvdu7ciWbNmimvZfHU1q1bpUYiIiIiIiIdk1xYHDx4EAcOHEDLli2rtEE7OzsMHDiwSm2JiIiIiEg/SS4sXF1dNerGFBUVVeW2RERERESknySPsVixYgU+/fRTpKSkvIA4RERERERkiCQfsXj33Xfx6NEjNGjQAJaWlqXGSDx48KDawhER0YvRIezPKrc9Mqd3NSYhIqKXheTCYsWKFS8gBhERERG9rDT5MQPgDxqGQnJhERgY+CJyEBERERGRAavSlbdLSkqwfft2nD9/HgDQrFkz+Pv7q3UdCyIiIiIievlIHrx9+fJlNGnSBKNGjcLWrVuxdetWjBgxAs2aNcOVK1fUWse+ffswYMAAeHp6wtPTE/7+/jhw4IDk8EREREREpB8kH7EIDg5GgwYNcOTIEdjb2wMA7t+/jxEjRiA4OBh//PFHhe2///57jB49GoMGDUJwcDAAICEhAd27d0d0dDSGDRtWhd0gXWGfSSIielX4b39To/axARV/RyIydJILi3379qkUFQDg4OCARYsWoXPnzpW2nz9/PpYsWYKpU6cqpwUHByM8PBzz5s1jYUFEREREZIAkd4UyMzNDTk5Oqem5ubmQyWSVtr969SoGDBhQarq/vz+uXbsmNQ4REREREekByUcs+vfvj/HjxyMiIgLt2rUDABw9ehQTJkyAv79/pe1dXV0RFxcHT09Plem7d++Gq6ur1DhEREREatG0+65jq2oKQvSSklxYrFq1CoGBgejYsaPy4njFxcXw9/fHypUrK23/8ccfIzg4GElJSejUqROAJ2MsoqOj1WpPRERERET6R3JhYWdnh19//RWXLl3ChQsXAABNmjQpdQSiPB988AFq166NZcuW4eeff1a237RpE9566y2pcYiIiIiISA9U6ToWAODl5QUvL68qtR04cCAGDhxY1U0TEREREZGeUauwCAkJwbx582BlZYWQkJAKlw0PD69wfv369fH333/DwcFBZXpmZiZee+01XL16VZ1IRERERESkR9QqLBITE1FUVKT8WxMpKSkoKSkpNb2goAC3bt3SaN1ERET6jtf/IaKXlVqFxd69e8v8W4rY2Fjl33/++SdsbW2V90tKShAXFwcPD48qrZuIiIiIiHRL8hiLMWPGYOXKlbCxsVGZnpeXh0mTJiEyMrLMdgEBAQAAQRAQGBioMs/U1BQeHh5YtmyZ1DhERERERKQHJF8gLyYmBvn5+aWm5+fnY8OGDeW2UygUUCgUcHNzQ3p6uvK+QqFAQUEBkpOT0b9/f6lxiIiIiIhID6h9xCI7OxuiKEIUReTk5MDc3Fw5r6SkBDt27ICjo2Ol6+HVtUmfsK8zERERUfVQu7Cws7ODIAgQBAENGzYsNV8QBMyZM6dawxERERERkWFQu7DYu3cvRFFEt27dsGXLFtjb2yvnyWQyuLu7w8XF5YWEJCIioif8t79Z5baxAX9UYxIiIlVqFxa+vr4AnnRlcnNzgyAILywUEb382A3NcGnyxRbgl1siopeV5LNCXb9+HdevXy93fpcuXTQKREREREREhkdyYeHn51dq2rNHL8q6+F12drba65fL5VIjERERERGRjkkuLB4+fKhyv6ioCImJiZg1axbmz59fZpunA7/VUVZhQkRE9BS70RkudqMjerlJLiyevWL2Uz179oRMJkNISAiOHz9eav6zV+tOSUnBp59+iqCgIHTs2BEAcPjwYcTExGDhwoVS45CB44cMGSp+uSUiIlIlubAoj5OTE5KTk8uc93TgNwDMnTsX4eHhGDp0qHKav78/vL298Z///KfUVbmJiIiI6NXGHyINg+TC4tSpUyr3RVFEWloaFi1ahJYtW1ba/vDhw1i3bl2p6W3atMH7778vNQ4RkUHihyQRkeHgUWr1SC4sWrZsCUEQIIqiyvQOHTogMjKy0vaurq5Yv349lixZojL922+/haurq9Q4RDrFL4dERGQI+HlF2iC5sLh27ZrKfSMjI9SqVQvm5uZqtV++fDkGDx6MnTt3on379gCAY8eO4dKlS9iyZYukLPv378eXX36J48ePIy0tDdu2bUNAQICkdRARERERkeYkFxbu7u4abbBfv364ePEi1q5diwsXLgAABgwYgAkTJkg+YpGXl4cWLVpgzJgxGDRokEa5dImH14ik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kz6+jo6OpZa5desWunbtitatWyMqKgpGRpUfRE1KSoKzs7OkvERE2rZo0SK0bNmyVNdVAKhXrx7s7OzUXtfz77lS3rPT09OxceNGBAQEqPUeS6QJFhZEBubrr79G586d0aZNG3z++efw8fGBkZER/v77b1y4cAGtW7dGREQE2rVrhy5dupRq37ZtW0REREjqTpSZmYk7d+5AoVDg0qVLmDt3Lho2bIgmTZrg/v37ePvttzFmzBj4+PjAxsYG//zzD5YsWYK33nqr3HXeunULfn5+cHd3x9KlS5GRkaGcV7t2bQBATEwMZDIZWrVqBQDYunUrIiMj8e2336qdnYhIF7y9vTF8+HCsWrVKctucnBzcuXMHoiji5s2bmD59OmrVqoVOnTpV2E4URWW7zMxMHD58GAsWLICtrW2p62sQvQgsLIgMTIMGDZCYmIgFCxYgNDQUqampMDMzQ9OmTfHJJ59g/PjxqF+/vnIQ9/MGDx6MZcuWYcGCBWpvc/To0QCe9M+tXbs2unTpggULFsDExATW1tZo3749li9fjitXrqCoqAiurq4YN25cmdekeOqvv/7C5cuXcfnyZdStW1dl3tP+wAAwb948XL9+HSYmJmjcuDE2bdqEIUOGqJ2diEhX5s6dW2pcmzpmz56N2bNnAwBq1aqFtm3bYteuXZV2ZcrOzoazszMEQYBcLkejRo0QGBiIyZMnq9VlikhTgvjsJzgREREREVEVsLMdERERERFpjIUFERERERFpjIUFERERERFpjIUFERERERFpjIUFERERERFpjIUFERERERFpjIUFERERERFpjIUFERERERFpjIUFERERERFpjIUFERERERFpjIUFERERERFpjIUFERERERFp7P8AIFyMpvbAIY4AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_ram['app']\n", + "gap_22_ram = df_gap22_ram['simSeconds'].astype(float)*1000\n", + "gap_22_orc = df_gap22_orc['simSeconds'].astype(float)*1000\n", + "gap_22_noDC = df_gap22_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "\n", + "gap_25_ram = df_gap25_ram['simSeconds'].astype(float)*1000\n", + "gap_25_orc = df_gap25_orc['simSeconds'].astype(float)*1000\n", + "gap_25_noDC = df_gap25_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "\n", + "app_npb = df_npbC_ram['app']\n", + "npb_C_ram = df_npbC_ram['simSeconds'].astype(float)*1000\n", + "npb_C_orc = df_npbC_orc['simSeconds'].astype(float)*1000\n", + "npb_C_noDC = df_npbC_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "npb_D_ram = df_npbD_ram['simSeconds'].astype(float)*1000\n", + "npb_D_orc = df_npbD_orc['simSeconds'].astype(float)*1000\n", + "npb_D_noDC = df_npbD_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "\n", + "# Multi bar Chart1\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,3])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_22_ram[i]/gap_22_noDC[i], width=1, color=cmap(1), label='TDRAM' if i==0 else None)\n", + " plt.bar(i*3+1, gap_22_orc[i]/gap_22_noDC[i], width=1, color=cmap(2), label='Oracle' if i==0 else None)\n", + "\n", + "offset = i*3+2\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_C_ram[i]/npb_C_noDC[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*3+2, npb_C_orc[i]/npb_C_noDC[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()\n", + "\n", + "# Multi bar Chart2\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,3])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_25_ram[i]/gap_25_noDC[i], width=1, color=cmap(1), label='TDRAM' if i==0 else None)\n", + " plt.bar(i*3+1, gap_25_orc[i]/gap_25_noDC[i], width=1, color=cmap(2), label='Oracle' if i==0 else None)\n", + "\n", + "offset = i*3+2\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_D_ram[i]/npb_D_noDC[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*3+2, npb_D_orc[i]/npb_D_noDC[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", + "plt.legend(fontsize=9, ncol=2)\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_cas['app']\n", + "gap_22_cas = df_gap22_cas['simSeconds'].astype(float)*1000\n", + "gap_22_ram = df_gap22_ram['simSeconds'].astype(float)*1000\n", + "gap_22_noDC = df_gap22_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "\n", + "gap_25_cas = df_gap25_cas['simSeconds'].astype(float)*1000\n", + "gap_25_ram = df_gap25_ram['simSeconds'].astype(float)*1000\n", + "gap_25_noDC = df_gap25_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "\n", + "app_npb = df_npbC_cas['app']\n", + "npb_C_cas = df_npbC_cas['simSeconds'].astype(float)*1000\n", + "npb_C_ram = df_npbC_ram['simSeconds'].astype(float)*1000\n", + "npb_C_noDC = df_npbC_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "npb_D_cas = df_npbD_cas['simSeconds'].astype(float)*1000\n", + "npb_D_ram = df_npbD_ram['simSeconds'].astype(float)*1000\n", + "npb_D_noDC = df_npbD_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "\n", + "# Multi bar Chart1\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,3])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_22_cas[i]/gap_22_noDC[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + " plt.bar(i*3+1, gap_22_ram[i]/gap_22_noDC[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", + "\n", + "offset = i*3+2\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_C_cas[i]/npb_C_noDC[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*3+2, npb_C_ram[i]/npb_C_noDC[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "\n", + "# Multi bar Chart2\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,3])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_25_cas[i]/gap_25_noDC[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + " plt.bar(i*3+1, gap_25_ram[i]/gap_25_noDC[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", + "\n", + "offset = i*3+2\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_D_cas[i]/npb_D_noDC[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*3+2, npb_D_ram[i]/npb_D_noDC[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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LyoqgoeHR6XJUDgRDRERPU80NTVhaWmJzMxMpKenqzocIqIqSSQSWFpaQlNTs85tiE4sli1bhsGDB+P8+fMoKytDdHQ0zp8/jyNHjmD//v3Vrvf0TJZEREQvEiMjIzg4OKC0tFTVoRARVUlbW7teSQVQxwnyrly5ghUrViA1NRVFRUV46aWXEBYWBldX13oFo2ycII+InjecII/oxeW3e6io+gn+exopEnqeiPm+LPqKBQC0b98emzZtqlNwgiDg1KlTSE9Ph0QiQbt27eDh4cE+p0RERERETVidEgsAyM7ORnZ2NioqKuTK3dzcql1n3759CA4OxvXr12Ujz58kFzExMejdu3ddwyEiIiIiIhUSnVicOnUKAQEBuHDhQqXbUkkkEpSXl1e5XlpaGoYNGwYvLy9ERUXB0dERgiDg/PnzWLt2LYYMGYIzZ87Azs6ubntCREREREQqIzqxCAoKQocOHbB582a0bNlS4S5Ma9asQffu3ZGYmChX7ujoiJEjR6J///6IiorCunXrxIZEREREREQqJjqxuHr1KuLj42Fvby9qvaSkJCxfvrzKZRKJBDNnzkR4eLjYcIiIiIiISA1o1F5FXr9+/ZCamip6QxkZGTXeNcrFxQXXr18X3S4REREREame6CsWX375JQICAvDPP//AxcWl0ux8fn5+Va5XVFQEAwODats1MDDAgwcPxIZDRERERERqQHRicfToURw+fBi//vprpWU1Dd4GgPPnz+P27dtVLrtz547YUIiIiIiISE2ITiymT5+O8ePHY8GCBWjZsqWodfv161fpTlLA44REEATOZUFERET0nOge8bvCdY8tGtSIkZCyiE4scnNzMWvWLNFJxbVr18RuioiIGpiYD3qAH/ZERKQ40YnFq6++in379qF9+/ai1rOxsRG7KSIiIqJ6YTJNpDyiE4sOHTogPDwchw4dgqura6XB2yEhIQq35erqil9++QVWVlZiwyAiIiIiIjVSp7tCGRkZYf/+/di/f7/cMolEIiqxSE9PR2lpqdgQiIiISIn4qz8RKUJ0YsGxEkRERESNT2xC18KjkQIhUpDoCfIa0ssvvwx9fX1VhkBERERERA1AoSsWoaGhWLJkCQwNDREaGlpj3cjISIU3/ssvvyhctyrLly/Hzp07cfHiRejr66NHjx745JNP0LFjx3q1S0RERERE4iiUWCQnJ8vGQiQnJ9d7o+Xl5di9ezcuXLgAAHB2doafnx80NTVFtbN//36899578PT0RFlZGebPn4+BAwfi/PnzMDQ0rHecRERERESkGIUSi3379lX5d12kpaVh6NChyMzMlF1ZWL58OaysrLBnzx5Rt7H97bff5J7HxcWhRYsWOHXqFHr37l2vOImIiIiISHGix1gEBQWhsLCwUvn9+/cRFBRU6/ohISGws7PDjRs3cPr0aZw+fRoZGRlo166dqDtKVSU/Px8AYGZmVuXy4uJiFBQUyD2IiIiIiKj+RCcWW7ZswcOHDyuVP3z4EFu3bq11/f3792PlypVyX/7Nzc2xYsWKSrevFaOiogIzZ85Ez5494eLiUmWd5cuXw8TERPbg/BlERERERA1D4dvNFhQUQBAECIKAwsJC6OnpyZaVl5fjl19+QYsWLWptR1dXt8orHkVFRdDR0VE0nEree+89/PPPPzh06FC1dcLDw+UGnxcUFDC5ICIiamB+u4cqXDfBf08jRkJEyqRwYmFqagqJRAKJRIIOHTpUWi6RSLBo0aJa2xk2bBimTJmCzZs3o1u3bgCA48ePY+rUqfDz8xMR+v+ZNm0afv75Zxw4cACWlpbV1tPV1YWurm6dtkFERERERNVTOLHYt28fBEFA3759ER8fL9eVSUdHBzY2NmjTpk2t7axduxYBAQHw9vaGtrY2AKCsrAx+fn6Ijo4WFbwgCJg+fTp27dqFpKQktGvXTtT6REREysCZq4noRaBwYuHj4wPg8czb1tbWkEgkddqgqakpfvzxR1y+fBkXL14EAHTq1An29vai23rvvfewbds2/PjjjzA2Nsbt27cBACYmJpx4j4iIiIhIiRROLJ6wsbFpkA07ODjAwcGhXm1s2LABAODr6ytXHhsbi8DAwHq1TUREREREihOdWNRXeXk54uLikJiYiOzsbFRUVMgt/+uvvxRuSxCEhg6PiIiIiIjqQOmJxYwZMxAXF4ehQ4fCxcWlzl2qiIiIiIhIfSg9sfjuu+/w/fffY8iQIcreNBERERERNRKlJxY6Ojp1GqhN6ol3OiEiIiIioA4zb//333+YMGEC2rRpAy0tLWhqaso9avP+++8jOjqa4yOIiIiIiJ4joq9YBAYGIiMjAwsWLEDr1q1Fj5E4dOgQ9u3bh19//RXOzs6yuSye2Llzp9iQiIiIiIhIxUQnFocOHcLBgwfh7u5epw2amppi5MiRdVqXiIiIiIjUk+jEwsrKql7dmGJjY+u8LhERERERqSfRYyzWrFmDefPmIT09vRHCISIiIiKipkj0FYs33ngDDx48QPv27WFgYFBpjEReXl6DBUdERKrlt3uownUT/Pc0YiRERKTuRCcWa9asaYQwiIiIiOhFJeZHDIA/ZKgr0YlFQEBAY8RBRERERERNWJ0myCsvL8fu3btx4cIFAICzszP8/PwUmseCSJ2ImeCPk/sRERERVU90YpGWloYhQ4bg5s2b6NixIwBg+fLlsLKywp49e9C+ffta29i/fz9WrVolS0ycnJwwZ84cvPzyy2LDISJSKs42T0REVDXRiUVISAjat2+PY8eOwczMDACQm5uL8ePHIyQkBHv21Nzn7euvv8akSZPw6quvIiQkBABw+PBh9OvXD3FxcXjzzTfrsBtN24v0RYV9KImI6Hny+YivRdV/+8fxjRQJkeqJTiz2798vl1QAgLm5OVasWIGePXvWuv7SpUuxcuVKzJo1S1YWEhKCyMhILFmy5IVMLIiIiIiImjrR81jo6uqisLCwUnlRURF0dHRqXf/q1asYPnx4pXI/Pz9cu3ZNbDhERERERKQGRF+xGDZsGKZMmYLNmzejW7duAIDjx49j6tSp8PPzq3V9KysrJCYmwt7eXq587969sLKyEhsOERERUYMR22V3KMY2UiRETY/oxGLt2rUICAiAt7e3bHK8srIy+Pn5ITo6utb133//fYSEhCAlJQU9evQA8HiMRVxcnELrExERERGR+hGdWJiamuLHH3/E5cuXcfHiRQBAp06dKl2BqM4777yDVq1aYfXq1fj+++9l62/fvh0jRowQGw4REREREamBOs1jAQAODg5wcHCo07ojR47EyJEj67ppIiIiIiJSMwolFqGhoViyZAkMDQ0RGhpaY93IyMgal9vZ2eHkyZMwNzeXK7937x5eeuklXL16VZGQiIiIiIhIjSiUWCQnJ6O0tFT2d32kp6ejvLy8UnlxcTFu3rxZr7aJqGl4keZuIaoLzvlDRE2RQonFvn37qvxbjISEBNnfv//+O0xMTGTPy8vLkZiYCFtb2zq1TUREREREqiV6jEVQUBCio6NhbGwsV37//n1Mnz4dMTExVa7n7+8PAJBIJAgICJBbpq2tDVtbW6xevVpsOERE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dy7279+P48ePy9X/6KOPsGjRovrtABERERHRC+bGjRuwtLSssY7Sr1j4+/sre5My4eHhCA0NlT2vqKhAXl4ezM3Nm/wM4AUFBbCyssKNGzcglUpVHY4ojF11mnL8jF11mnL8jF01mnLsQNOOn7GrTlOP/wlBEFBYWIg2bdrUWlfpiUVERESDtdW8eXNoamriv//+kyv/77//0KpVq0r1dXV1oaurK1dmamraYPGoA6lU2mQPXsauOk05fsauOk05fsauGk05dqBpx8/YVaepxw8AJiYmCtVT+u1mnzh16hS+/vprfP3110hOTq5TGzo6OujSpQsSExNlZRUVFUhMTJTrGkVERERERI1L6VcssrOzMWbMGCQlJcmuFty7dw99+vTBd999BwsLC1HthYaGIiAgAF27dkW3bt2wZs0a3L9/H5MmTWqE6ImIiIiIqCpKv2Ixffp0FBYW4ty5c8jLy0NeXh7++ecfFBQUICQkRHR7b7zxBlatWoWFCxfC3d0dKSkp+O2339CyZctGiF596erqIiIiolJXr6aAsatOU46fsatOU46fsatGU44daNrxM3bVaerx14XS7wplYmKCvXv3wtPTU678xIkTGDhwIO7du6fMcIiIiIiIqAEo/YpFRUUFtLW1K5Vra2ujoqJC2eEQEREREVEDUHpi0bdvX8yYMQO3bt2Sld28eROzZs1Cv379lB0OERERERE1AKV3hbpx4wb8/Pxw7tw5WFlZycpcXFyQkJBQ68QbRERERESkfpR+xcLKygqnT5/Gnj17MHPmTMycORO//PILTp8+zaRCAb6+vpg5c6aqwxCltpgfPHiAUaNGQSqVQiKRcJwNkRppiuec54kgCJgyZQrMzMwgkUiQkpKi6pAU1pSPnaYcO5EqKf12swAgkUgwYMAADBgwQBWbJzWzZcsWHDx4EEeOHEHz5s0VnoSFqKnw9fWFu7s71qxZo+pQGpytra3sRyJqeL/99hvi4uKQlJQEOzs7tG7dGrt27YK/v7+qQ6vVzp07qxxTSUTPL5UkFomJiUhMTER2dnalAdsxMTGqCIlU6MqVK+jUqRNcXFxUHQo9paSkBDo6OqoOg+iFduXKFbRu3Ro9evRQdSiimZmZqToEIlIypXeFWrRoEQYOHIjExETcuXMHd+/elXtQ7crKyjBt2jSYmJigefPmWLBgAZ4MlSku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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_cas['app']\n", + "gap_22_cas = df_gap22_cas['simSeconds'].astype(float)*1000\n", + "gap_22_ram = df_gap22_ram['simSeconds'].astype(float)*1000\n", + "gap_22_orc = df_gap22_orc['simSeconds'].astype(float)*1000\n", + "gap_22_noDC = df_gap22_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "\n", + "gap_25_cas = df_gap25_cas['simSeconds'].astype(float)*1000\n", + "gap_25_ram = df_gap25_ram['simSeconds'].astype(float)*1000\n", + "gap_25_orc = df_gap25_orc['simSeconds'].astype(float)*1000\n", + "gap_25_noDC = df_gap25_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "\n", + "app_npb = df_npbC_cas['app']\n", + "npb_C_cas = df_npbC_cas['simSeconds'].astype(float)*1000\n", + "npb_C_ram = df_npbC_ram['simSeconds'].astype(float)*1000\n", + "npb_C_orc = df_npbC_orc['simSeconds'].astype(float)*1000\n", + "npb_C_noDC = df_npbC_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "npb_D_cas = df_npbD_cas['simSeconds'].astype(float)*1000\n", + "npb_D_ram = df_npbD_ram['simSeconds'].astype(float)*1000\n", + "npb_D_orc = df_npbD_orc['simSeconds'].astype(float)*1000\n", + "npb_D_noDC = df_npbD_noDC['simSeconds'].astype(float)*1000\n", + "\n", + "\n", + "# Multi bar Chart1\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,3])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*4, gap_22_cas[i]/gap_22_noDC[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + " plt.bar(i*4+1, gap_22_ram[i]/gap_22_noDC[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", + " plt.bar(i*4+2, gap_22_orc[i]/gap_22_noDC[i], width=1, color=cmap(3), label='Oracle' if i==0 else None)\n", + "\n", + "offset = i*4+3\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*4+1, npb_C_cas[i]/npb_C_noDC[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*4+2, npb_C_ram[i]/npb_C_noDC[i], width=1, color=cmap(2))\n", + " plt.bar(offset+i*4+3, npb_C_orc[i]/npb_C_noDC[i], width=1, color=cmap(3))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", + "plt.legend(fontsize=8, ncol=3)\n", + "plt.tight_layout()\n", + "\n", + "# Multi bar Chart2\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,3])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*4, gap_25_cas[i]/gap_25_noDC[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + " plt.bar(i*4+1, gap_25_ram[i]/gap_25_noDC[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", + " plt.bar(i*4+2, gap_25_orc[i]/gap_25_noDC[i], width=1, color=cmap(3), label='Oracle' if i==0 else None)\n", + "\n", + "offset = i*4+3\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*4+1, npb_D_cas[i]/npb_D_noDC[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*4+2, npb_D_ram[i]/npb_D_noDC[i], width=1, color=cmap(2))\n", + " plt.bar(offset+i*4+3, npb_D_orc[i]/npb_D_noDC[i], width=1, color=cmap(3))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", + "plt.legend(fontsize=8, ncol=3)\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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69bFxIkTcfjwYXz66acICwuTthUUFEgHcwOvv6FOT0+XjgV7n3R0dIp9u+/h4YETJ06o3YeRspT3/Hn73NRJea9fV1dXXL16FXl5edJl586de5/xKq1q1apq+7svjzq+18ujZs2axa6eJiQkaPQ3zK6ursXeKwH1ei2U9/fh8uXLePHihXTdmJgYGBkZwd7eXlVxi3n7uZKZmSktii5cuICioiL897//RcuWLVG3bl08efJEVVGVSubCwtfXF99++22plVVeXh5mzpyJbt26KTTcx+jBgweYNGkS4uPjsW3bNqxcuRLjx4+Hk5MThg0bhhEjRiAyMhKJiYmIjo7Gzp07VR0ZQNm5S3PgwAGsWLECsbGxuH//Pn755RcUFRXB1dX1PacuTk9PD0FBQZg6dSp++eUX3LlzBzExMdiwYQP8/f1hZWWFvn374uTJk7h79y52796N06dPqzRzaeT5v3jfzpw5g4ULF+L8+fN48OAB9uzZg+fPn0NfXx/BwcE4ffo07t+/j8OHDyMhIQH169fHixcvEBgYiOjoaNy/fx8nT57EuXPnihUNVatWxddff40zZ87gwoULCAgIQMuWLVVyid/JyQlnzpzBvXv38M8//yAwMBCZmZkYNGgQzp8/j4SEBGzatAnx8fHvPZssynv+ODk54fjx43j8+LHa3DjijfJev59//jmKioowevRo3Lx5E4cOHcKyZcsAQC3vblUaJycnREVFITk5uVj3EHWmru/18ujUqRNWrVqFS5cu4fz58xgzZozGdGsszZdffom4uDgEBQXh1q1b2Llzp/QOV6p+LZT19+HNe31+fj5GjhyJGzdu4Pfff0dISAgCAwOhpSXXDU6VplOnTti0aRNOnDiBq1evYtiwYdIv9FxcXPDq1SusXLkSd+/exaZNm/Djjz+qOLGSyDoY4+HDh8LS0lI4ODiIxYsXi19//VVERkaKRYsWCXt7e2FhYSEePHigvNEgH4EOHTqIsWPHijFjxggTExNhamoqpk+fLh1I+eLFCzFx4kRhbW0tdHR0hIuLi9i4caOKU78799uDt0+cOCE6dOggTE1Nhb6+vvDw8BA7duxQUfriCgsLxfz584Wjo6OoWrWqcHBwEAsXLhRCCHHv3j3Rr18/YWJiIgwMDETTpk1VMji4PO/6v1D14NsbN24IX19fUbNmTaGrqyvq1q0rVq5cKZKTk0Xfvn2lz21HR0cxa9YsUVhYKPLy8sSgQYOEvb290NHRETY2NiIwMFA6EDcsLExUq1ZN7N69W9SqVUvo6uoKHx8fcf/+fZWcY3x8vGjZsqXQ19cXAERiYqK4fPmy6Nq1qzAwMBDGxsaiXbt24s6dOyrJV553PX9Onz4tPDw8hK6urpDjz8d7U97r9+TJk8LDw0Po6OiIJk2aiK1btwoAIi4uTsWpS/f24O19+/YJFxcXUaVKlWLL1dGbwc/q/F5fnn8P3n78+LHo2rWrMDQ0FHXq1BG///672g3e/vfNIoQo/X0e/xqE/uuvvwoXFxehq6srvL29xdq1awWAYjc3UIWy/j4I8Xrwdp8+fcSsWbOEmZmZMDIyEqNGjRIvX75UaeZ/y8jIEAMHDhQmJibC3t5ehIeHFxu8/f333wtra2uhr68vfH19xS+//KIWg+YVTSLEWx3CypGYmIixY8fi8OHD0n5kEokEXbp0wapVq+Di4qKE0oeIZPUhz/pclvDwcEyYMEGj+m2T6m3ZsgXDhw9HRkYGx2fQR23BggX48ccf1XoQdEBAANLT00vMKULqR66Zt52dnfHHH38gLS0NCQkJAF5f3uHYCiIiUme//PILatWqBVtbW1y+fBlBQUEYMGAAiwr66KxZswbNmjWDmZkZTp48iaVLlyIwMFDVsegDIVdh8Yapqana3J6MiIjoXZKTkzFr1iwkJyfD2toa/fv315iJtYgUKSEhAfPnz0dqaiocHBzwf//3fwgODlZ1LPpAyNUVioiIiIiIqDTqMZSeiIiIiIg0GgsLIiIiIiKqNBYWRERERERUaSwsiIiIiIio0lhYEBERERFRpbGwICIiIiKiSmNhQaSBkpOTMX78eLi4uEBPTw+WlpZo06YN1q5di9zc3GLrLlq0CNra2li6dGmJ/YSHh0MikUAikUBLSwt2dnYYPnw4nj17Jl3nTbtEIkGVKlXg4OCASZMmIS8vT7rO8+fP8dVXX8HBwQG6urqwsrKCr68vTp48WeY53Lt3DyNHjoSzszP09fVRu3ZthISEID8/X7pOdHQ0+vTpA2traxgaGsLLywtbtmypzK+OiEgpAgICIJFI8N133xVbHhkZCYlEAuD1e9q/31MtLS3Rr18/3L17V7q+k5OTtF1bWxs2NjYYOXIk0tLS3pkhPz8fS5YsgaenJwwMDGBubo42bdogLCwMr169UuwJE5WiQhPkEZHq3L17F23atEH16tWxcOFCuLu7Q1dXF1evXsW6detga2sLPz8/6fobN27E1KlTsXHjRkyZMqXE/kxMTBAfH4+ioiJcvnwZw4cPx5MnT3Do0CHpOmFhYejWrRtevXolXcfQ0BDz5s0DAPTr1w/5+fmIiIhArVq18PTpU0RFRSElJaXM84iLi0NRURF++uknuLi44Nq1axg1ahRycnKwbNkyAMCpU6fg4eGBoKAgWFpa4sCBAxg6dCiqVauGXr16KepXSkSkEHp6eli8eDG+/PJLmJqalrlefHw8jI2NkZCQgNGjR6N37964cuUKtLW1AQBz587FqFGjUFhYiFu3bmH06NH45ptvsGnTpjL3mZ+fD19fX1y+fBnz5s1DmzZtYGJigpiYGCxbtgyNGjWCl5eXok+ZqDhBRBrF19dX2NnZiezs7FLbi4qKpP+Ojo4Wtra2Ij8/X9jY2IiTJ08WWzcsLExUq1at2LIFCxYILS0tkZubK4QQAoDYu3dvsXVGjhwpevToIYQQIi0tTQAQ0dHRlTwzIZYsWSKcnZ3LXadHjx5i+PDhlT4WEZEiDRs2TPTq1UvUq1dPTJkyRbp879694s3HrWPHjgkAIi0tTdq+ZcsWAUDExcUJIYRwdHQUoaGhxfY9b9480aBBg3KPv3jxYqGlpSUuXrxYoi0/P7/MvxlEisSuUEQaJCUlBYcPH8a4ceNgaGhY6jpvLrkDwIYNG+Dv74+qVavC398fGzZseOcx9PX1UVRUhIKCglLbb926haNHj6JFixYAACMjIxgZGSEyMrJY96iKyMjIQI0aNSq9DhGRKmhra2PhwoVYuXIlHj16JNM2+vr6AFCsG+i/PX78GPv375e+55Zly5Yt8PHxQaNGjUq0Va1atcy/GUSKxMKCSIPcvn0bQgi4uroWW25ubi79gB8UFAQAyMzMxK5du/Cf//wHAPCf//wHO3fuRHZ2dpn7T0hIwI8//oimTZvC2NhYutzf3x9GRkbQ09ODq6sr3NzcEBwcDACoUqUKwsPDERERgerVq6NNmzaYPn06rly5Ive5rVy5El9++WWZ6+zcuRPnzp3D8OHD5do3EdH78sknn8DLywshISHvXDcpKQnLli2Dra1tsff1oKAgGBkZQV9fH3Z2dpBIJPj+++/L3VdCQgLq1atX6fxElcHCgugDcPbsWcTGxsLNzU161WDbtm2oXbs2PD09AQBeXl5wdHTEjh07im2bkZEBIyMjGBgYwNXVFZaWliUGSIeGhiI2NhaXL1/GgQMHcOvWLQwZMkTa3q9fPzx58gT79u1Dt27dEB0djcaNGyM8PBwAMGbMGGnhY2RkVCL/48eP0a1bN/Tv3x+jRo0q9RyPHTuG4cOHY/369XBzc6vw74qISNkWL16MiIgI3Lx5s9R2Ozs7GBoawsbGBjk5Odi9ezd0dHSk7VOmTEFsbCyuXLmCqKgoAEDPnj1RWFgIAMXeT8eMGQMAEEIo+ayI3o2Dt4k0iIuLCyQSCeLj44str1WrFoD/d0kdeN0N6vr166hS5f+9zIuKirBx40aMHDlSuszY2BgXL16ElpYWrK2ti+3jDSsrK7i4uAAAXF1dkZWVBX9/f8yfP1+6XE9PD126dEGXLl0wc+ZMfPHFFwgJCUFAQADmzp2LyZMnl3pOT548QceOHdG6dWusW7eu1HX++usv9O7dG6GhoRg6dKgsvyoiIpVp3749fH19ERwcjICAgBLtJ06cgImJCSwsLIpdHX7D3Nxc+t5ap04d/PDDD2jVqhWOHTsGHx8fxMbGStc1MTEBANStWxdxcXFKOR8iWbGwINIgZmZm6NKlC1atWoWvv/66zD6zV69exfnz5xEdHV1sPEJqaiq8vb0RFxcnvWSupaUl/QMmqzd3Lnnx4kWZ6zRo0ACRkZEAAAsLC1hYWJRY5/Hjx+jYsSOaNGmCsLAwaGmVvIgaHR2NXr16YfHixRg9erRcOYmIVOW7776Dl5dXia6rAODs7Izq1avLvK+333NLe8/+/PPPMX36dFy6dKnEOItXr14hPz+f4yxI6VhYEGmYNWvWoE2bNmjatClmz54NDw8PaGlp4dy5c4iLi0OTJk2wYcMGNG/eHO3bty+xfbNmzbBhw4ZS57UoS3p6OpKTk1FUVISEhATMnTsXdevWRf369ZGSkoL+/ftjxIgR8PDwgLGxMc6fP48lS5agT58+Ze7z8ePH8Pb2hqOjI5YtW4bnz59L26ysrAC87v7Uq1cvjB8/Hv369UNycjIAQEdHhwO4iUitubu7Y/DgwVixYoXc22ZlZSE5ORlCCDx8+BBTp05FzZo10bp16zK3mTBhAn777Td07twZ8+bNQ9u2baXvx4sXL8aGDRt4u1lSPhXflYqIKuDJkyciMDBQODs7i6pVqwojIyPRvHlzsXTpUpGRkSHMzMzEkiVLSt128eLFwsLCQuTn55d6u9m3AZD+SCQSYW1tLQYOHCju3LkjhBDi5cuXYtq0aaJx48aiWrVqwsDAQLi6uooZM2ZIb1lbmrCwsGL7/vfPG8OGDSu1vUOHDnL/zoiIlGnYsGGiT58+xZYlJiYKHR2dcm83+zZHR8di73c1a9YUPXr0EJcuXXpnhpcvX4pFixYJd3d3oaenJ2rUqCHatGkjwsPDxatXrypxdkSykQjB0T5ERERERFQ5vCsUERERERFVGgsLIiIiIiKqNBYWRERERERUaSwsiIiIiIio0lhYEBERERFRpbGwICIiIiKiSmNhQURERERElcbCgoiIiIiIKo2FBRERERERVRoLCyIiIiIiqjQWFkREREREVGksLIiIiIiIqNL+Pz5ah2LH45NzAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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91NTU4OOjo7EDxERERERVS6px1jo6urC2NgYvXv3xrhx47Bz584yew6kkZ2djbt374qXExISEBsbC319fVhZWSEgIADz5s1DgwYNYGNjgxkzZsDMzExirgsiIiIiIlI8qQsLV1dXXL58GadOnRJfBuXu7g4DA4NyP/jFixfh4eEhXp40aRIAYNiwYQgLC8OUKVOQk5OD0aNHIz09He3bt8ehQ4egrq5e7sckIiIiIiL5k7qwiImJQXZ2Nv755x+cOHECS5Ysga+vLxo2bAh3d3d07NgRHTt2hLGxsdQP7u7uDkEQSm0XiUSYM2cO5syZI/UxiYiIiIio6kldWACAlpYWunXrhm7dugEAsrKycPr0aRw9ehSjRo1CdnY2CgoKKiUoERERERFVXzIVFm8VFRXhwoULiIqKwokTJ3DmzBnk5OTIdVZuIiIiIiKqOaQuLM6fP4+oqChERUXhn3/+QXZ2NiwsLODu7o7ly5fDw8MD1tbWlRiViIiIiIiqK6kLi9atW8PU1BQeHh74+eef4eHhgfr161dmNiKij4J3eM8K7R/h86eckhAREVUeqQuLW7duwd7evjKzEBERERFRDSX1BHn29vbIysrCpUuXkJ2dDQD4999/MXToUPTv3x/btm2rtJBERERERFS9Sd1jcerUKfTq1QvZ2dnQ09PDjh078MUXX8Dc3BzKysrYt28fcnNzMWrUqMrMS0RERERE1ZDUPRbTp09H//798fjxYwQEBGDgwIHw9/fHrVu3cP36dcyePRurVq2qzKxERERERFRNSd1jcfXqVaxbtw7m5uYIDAzErFmzMHDgQHH7oEGDsHjx4koJSRz8SURERETVm9Q9FpmZmdDX1wcAqKqqonbt2tDW1ha3a2trIzc3V/4JiYiIiIio2pO6sBCJRBCJRKUuExERERHRp0vqS6EEQUDnzp2hovJml9zcXPTu3RuqqqoAgIKCgspJSB8FXspFRERE9HGTurAIDg6WWO7Tp0+xbfr161fxREREVK3wiwEiUiS+B9Uc5S4siIiIiIiI3pK6sCAiIiIqD37jTPRpYGFBREREVAYWRkTSkfquUERERERERKVhYUFERERERBXGS6FIKq2DD1dof+MmcgpCpAB8/tOnjq8BIpKGVIXF8uXLpT7gd999V+4wRERERERUM0lVWISEhEgsJycnIzc3F3Xq1AEApKeno3bt2jA2NmZhQR8lDtwjIiIiKptUYywSEhLEP/Pnz4ebmxtu3bqF1NRUpKam4tatW2jatCnmzp1b2XmJiIiIiKgaknnw9owZM7BixQrY29uL19nb2yMkJATTp0+XazgiIiIiIqoZZC4sEhMTUVBQUGx9YWEhnj9/LpdQRERERERUs8h8V6jOnTvjm2++wYYNG9C0aVMAwKVLl/Dtt9/C09NTruFmzZqF2bNnS6yzt7dHXFycXB+HiOhjxjv6EBFRVZC5sNi0aROGDRuG5s2bo1atWgCAgoICeHl5YcOGDXIP6OjoiGPHjomXVVR4h1wiIiKimoJfbnw6ZP6UbmRkhL/++gt37twR9xw4ODigYcOGcg8HvCkkTE1NK+XYVYkvKiIiIiqPin6GiJntJackRGUr99f/1tbWEAQB9evXr9RehPj4eJiZmUFdXR1t2rTBwoULYWVlVer2eXl5yMvLEy9nZmZWWjYiIqKqwFteE1FNIHNFkJubi/Hjx2Pz5s0AgDt37sDW1hbjx4+Hubk5pk6dKrdwrVq1QlhYGOzt7ZGYmIjZs2fjs88+w/Xr16GtrV3iPgsXLiw2LoOIPUZERERElUvmwiIoKAhXrlxBVFQUunXrJl7v6emJWbNmybWw6N69u/jfLi4uaNWqFerVq4fdu3dj5MiRpeabNGmSeDkzMxOWlpZyy0REREQ1C79cIqoaMhcW4eHh2LVrF1q3bg2RSCRe7+joiHv37sk13Pvq1KmDhg0b4u7du6Vuo6amBjU1tUrNQUREREREkmQuLJKTk2FsbFxsfU5OjkShURmys7Nx7949DBkypFIfh4iIiOhjwTE6VFVkniCvefPm+PPP/3+CvS0mNmzYgDZt2sgvGYDJkyfj5MmTePDgAc6ePYu+fftCWVkZvr6+cn0cIiIiIiKqGJl7LBYsWIDu3bvj5s2bKCgowLJly3Dz5k2cPXsWJ0+elGu4J0+ewNfXFykpKTAyMkL79u0RExMDIyMjuT4OERERERFVjMyFRfv27REbG4tFixbB2dkZR44cQdOmTREdHQ1nZ2e5htu5c6dcj0dERERERJWjXBNQ1K9fH+vXr5d3FiIiIiIiqqFkHmPh6emJsLAwTjxHRERERERiMvdYODo6IigoCGPHjkXPnj3x1VdfoUePHqhVq1Zl5CMiIqrxOI8CEX0KZO6xWLZsGZ4+fYrw8HBoampi6NChMDExwejRo+U+eJuIiIiIiGoGmQsLAFBSUkLXrl0RFhaG58+f49dff8X58+fRqVMneecjIiIiIqIaoFyDt99KSkrCzp078dtvv+Hq1ato2bKlvHIREREREVENInOPRWZmJkJDQ9GlSxdYWlpizZo18Pb2Rnx8PGJiYiojIxERERERVXMy91iYmJhAT08PAwcOxMKFC9G8efPKyEVERERERDWITIWFIAhYvnw5Bg8ejNq1a1dWJiIiIiIiqmFkuhRKEASMGzcOT58+raw8RERERERUA8nUY6GkpIQGDRogJSUFDRo0qKxMREREREQfBe/wnhXaP8LnTzklqXwyD95etGgRvv/+e1y/fr0y8hARERERUQ0k8+DtoUOHIjc3F66urlBVVYWGhoZEe2pqqtzCEREREREpUuvgwxXa37iJnILUADIXFr/88kslxCAiIiIioppM5sJi2LBhlZGDiIiIiIhqMJnHWADAvXv3MH36dPj6+uLFixcAgL///hs3btyQazgiIiIiIqoZZC4sTp48CWdnZ5w7dw779u1DdnY2AODKlSsIDg6We0AiIiIiIqr+ZC4spk6dinnz5uHo0aNQVVUVr+/UqRNiYmLkGo6IiIiIiGoGmQuLa9euoW/fvsXWGxsb47///pNLKCIiIiIiqllkLizq1KmDxMTEYusvX74Mc3NzuYQiIiIiIqKaRebCYtCgQQgMDERSUhJEIhGKiopw5swZTJ48GUOHDq2MjEREREREVM3JXFgsWLAADg4OsLS0RHZ2Nho3bowOHTqgbdu2mD59emVkJCIiIiKiak7meSxUVVWxfv16zJw5E9euXUN2djaaNGmCBg0aVEY+IiIiIiKqAco1jwUAWFpaokePHujXrx9ycnKQlpYmz1wSVq1aBWtra6irq6NVq1Y4f/58pT0WERERERHJTubCIiAgABs3bgQAFBYWomPHjmjatCksLS0RFRUl73zYtWsXJk2ahODgYPz7779wdXWFl5eXeGI+IiIiIiJSPJkLiz179sDV1RUAcODAAdy/fx9xcXGYOHEifvjhB7kH/PnnnzFq1CgMHz4cjRs3xtq1a1G7dm1s2rRJ7o9FRERERETlI/MYi//++w+mpqYAgL/++gsDBgxAw4YNMWLECCxbtkyu4fLz83Hp0iUEBQWJ1ykpKcHT0xPR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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_cas['app']\n", + "gap_22_cas = df_gap22_cas['totBW'].astype(float)\n", + "gap_22_ram = df_gap22_ram['totBW'].astype(float)\n", + "gap_22_noDC = (df_gap22_noDC['farAvgRdBWSys'].astype(float)+df_gap22_noDC['farAvgWrBWSys'].astype(float))/1000000000\n", + "\n", + "\n", + "gap_25_cas = df_gap25_cas['totBW'].astype(float)\n", + "gap_25_ram = df_gap25_ram['totBW'].astype(float)\n", + "gap_25_noDC = (df_gap25_noDC['farAvgRdBWSys'].astype(float)+df_gap25_noDC['farAvgWrBWSys'].astype(float))/1000000000\n", + "\n", + "app_npb = df_npbC_cas['app']\n", + "npb_C_cas = df_npbC_cas['totBW'].astype(float)\n", + "npb_C_ram = df_npbC_ram['totBW'].astype(float)\n", + "npb_C_noDC = (df_npbC_noDC['farAvgRdBWSys'].astype(float)+df_npbC_noDC['farAvgWrBWSys'].astype(float))/1000000000\n", + "\n", + "npb_D_cas = df_npbD_cas['totBW'].astype(float)\n", + "npb_D_ram = df_npbD_ram['totBW'].astype(float)\n", + "npb_D_noDC = (df_npbD_noDC['farAvgRdBWSys'].astype(float)+df_npbD_noDC['farAvgWrBWSys'].astype(float))/1000000000\n", + "\n", + "\n", + "# Multi bar Chart1\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "#plt.ylim([0,2.5])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + " plt.bar(i*3+1, gap_22_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", + "\n", + "offset = i*3+2\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_C_cas[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*3+2, npb_C_ram[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "#plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Observed BW at LLC (GB/s)\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "\n", + "# Multi bar Chart2\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "#plt.ylim([0,2.5])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + " plt.bar(i*3+1, gap_25_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", + "\n", + "offset = i*3+2\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_D_cas[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*3+2, npb_D_ram[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "#plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Observed BW at LLC (GB/s)\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "x1 = df_gap22_cas['app']\n", + "y1 = 100 * df_gap22_cas['numRdMissClean'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", + "y2 = 100 * df_gap22_cas['numRdMissDirty'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", + "y3 = 100 * df_gap22_cas['numWrMissClean'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", + "y4 = 100 * df_gap22_cas['numWrMissDirty'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(6,3)\n", + "plt.ylim([0,110])\n", + "\n", + "for i,app in enumerate(x1): \n", + " plt.bar(i*4, y1[i], width=3, color=cmap(1), label='Read/Clean' if i==0 else None)\n", + " plt.bar(i*4, y2[i], bottom = y1[i], width=3, color=cmap(2), label='Read/Dirty' if i==0 else None)\n", + " plt.bar(i*4, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3), label='Write/Clean' if i==0 else None)\n", + " plt.bar(i*4, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4), label='Write/Dirty' if i==0 else None)\n", + "\n", + "offset = (i+1)*4\n", + "x2 = df_npbC_cas['app']\n", + "y1 = 100 * df_npbC_cas['numRdMissClean'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", + "y2 = 100 * df_npbC_cas['numRdMissDirty'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", + "y3 = 100 * df_npbC_cas['numWrMissClean'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", + "y4 = 100 * df_npbC_cas['numWrMissDirty'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", + "\n", + "for i,app in enumerate(x2): \n", + " plt.bar(i*4+offset, y1[i], width=3, color=cmap(1))\n", + " plt.bar(i*4+offset, y2[i], bottom = y1[i], width=3, color=cmap(2))\n", + " plt.bar(i*4+offset, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3))\n", + " plt.bar(i*4+offset, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*4, list(x1)+list(x2))\n", + "plt.axvline(x=offset-2, color='black')\n", + "\n", + "plt.ylabel(\"DRAM Cache Miss Rate (%)\", fontsize=10)\n", + "plt.legend(fontsize=9, ncol=1)\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_mpki.pdf\")\n", + "\n", + "x1 = df_gap25_cas['app']\n", + "y1 = 100 * df_gap25_cas['numRdMissClean'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", + "y2 = 100 * df_gap25_cas['numRdMissDirty'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", + "y3 = 100 * df_gap25_cas['numWrMissClean'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", + "y4 = 100 * df_gap25_cas['numWrMissDirty'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(6,3)\n", + "plt.ylim([0,110])\n", + "for i,app in enumerate(x1): \n", + " plt.bar(i*4, y1[i], width=3, color=cmap(1), label='Read/Clean' if i==0 else None)\n", + " plt.bar(i*4, y2[i], bottom = y1[i], width=3, color=cmap(2), label='Read/Dirty' if i==0 else None)\n", + " plt.bar(i*4, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3), label='Write/Clean' if i==0 else None)\n", + " plt.bar(i*4, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4), label='Write/Dirty' if i==0 else None)\n", + "\n", + "offset = (i+1)*4\n", + "x2 = df_npbD_cas['app']\n", + "y1 = 100 * df_npbD_cas['numRdMissClean'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", + "y2 = 100 * df_npbD_cas['numRdMissDirty'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", + "y3 = 100 * df_npbD_cas['numWrMissClean'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", + "y4 = 100 * df_npbD_cas['numWrMissDirty'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", + "\n", + "for i,app in enumerate(x2): \n", + " plt.bar(i*4+offset, y1[i], width=3, color=cmap(1))\n", + " plt.bar(i*4+offset, y2[i], bottom = y1[i], width=3, color=cmap(2))\n", + " plt.bar(i*4+offset, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3))\n", + " plt.bar(i*4+offset, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*4, list(x1)+list(x2))\n", + "plt.axvline(x=offset-2, color='black')\n", + "\n", + "plt.ylabel(\"DRAM Cache Miss Rate (%)\", fontsize=10)\n", + "plt.legend(fontsize=9, ncol=1)\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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KSnazFGqli1bYtu2bQgLC8P06dPh6uqKxYsXY+DAgcp9JkyYgIKCAowYMQI5OTlo3749du3apVNrON1K1Fwx+UKB5dMNERHR20qnJ4cDQLdu3dCtW7cyt8tkMkyfPh3Tp08vx1RERET0NtLpyeFEREREukTnR5yo8ukR07Vc+okN3FEu/RAR0duDI05EREREErFwIiIiIpKIhRMRERGRRCyciIiIiCRi4UREREQkEQsnIiIiIoleuXD6559/sHv3bjx8+BAAIITQWCgiIiIiXaR24XT37l34+/ujXr166NKlCzIyMgAAw4YNwxdffKHxgERERES6Qu3Cady4cTAwMEBaWhpMTU2V7R9++CF27dql0XBEREREukTtlcP37NmD3bt3o2bNmirtbm5uuHbtmsaCEREREekatUecCgoKVEaansrOzoaRkZFGQhERERHpIrULpw4dOmDDhg3K+zKZDAqFAuHh4fD19dVoOCIiIiJdovapuvDwcLz77rtISEhAUVERJkyYgPPnzyM7OxuHDx/WRkYiIiIinaD2iFPjxo1x+fJltG/fHj179kRBQQF69+6NxMRE1KlTRxsZiYiIiHSC2iNOAGBpaYmvv/5a01mIiIiIdNorFU45OTk4ceIEbt26BYVCobLt448/1kgwIiKif+sR07Vc+okN3FEu/dCbR+3C6bfffsPAgQORn58PuVwOmUym3CaTyVg4ERERUaWl9hynL774AkOHDkV+fj5ycnJw79495S07O1sbGYmIiIh0gtqF040bNzBmzJhS13IiIiIiqszULpwCAgKQkJCgjSxEREREOk3SHKfY2Fjlv7t27Yrx48fjwoULcHd3R5UqVVT27dGjh2YTEhEREekISYVTYGDgc23Tp09/rk0mk6GkpOS1QxERERHpIkmF07+XHCAiIiJ6G6k9x4mIiIjobaV24TRmzBgsXbr0ufbly5dj7NixmshEREREpJPULpx++eUXtGvX7rn2tm3b4ueff9ZIKCIiIiJdpHbhdPfuXVhaWj7XLpfLcefOHY2EIiIiItJFahdOdevWxa5du55r//3331G7dm2NhCIiIiLSRWp/V11oaChCQkJw+/Zt+Pn5AQDi4uLw7bffYvHixZrOR0RERKQz1C6chg4disLCQsyaNQszZswAANSqVQurVq3iF/wSERFRpaZ24QQAn376KT79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FStWaKxfIiIiotJInuO0ZcsWfPXVV88VTQDg5+eHSZMmYdOmTRoNR0RERKRLJBdOf//9N95///0yt3fu3BlnzpzRSCgiIiIiXSS5cMrOzoadnV2Z2+3s7HDv3j2NhCIiIiLSRZILp5KSEhgYlD0lSl9fH8XFxRoJRURERKSL1LqqLjg4GEZGRqVuf/YrTIiIiIgqI8mFU1BQ0Ev30eQVdURERES6RnLhFBkZqc0cRERERDpPp79yhYiIiEiXqPWVK0RERET/9jatpM4RJyIiIiKJWDgRERERScTCiYiIiEgiFk5EREREErFwIiIiIpKIhRMRERGRRCyciIiIiCRi4UREREQkEQsnIiIiIolYOBERERFJxMKJiIiISCIWTkREREQSsXAiIiIikoiFExEREZFELJyIiIiIJGLhRERERCQRCyciIiIiiVg4EREREUnEwomIiIhIIhZORERERBKxcCIiIiKSiIUTERERkUQsnIiIiIgkYuFEREREJBELJyIiIiKJDCo6gKasWLEC8+fPR2ZmJpo2bYply5ahVatWFR2LiIgqoVuJY8qno8Dy6YakqxSF048//ojQ0FBERESgdevWWLx4MQICApCUlARbW9uKjkdE9MbrEdO1XPqJDdxRLv0QvapKUTgtXLgQw4cPx5AhQwAAERER2LFjB9atW4dJkyZVcDoiojefroyw6EoOenu98YVTUVERTp06hbCwMGWbnp4e/P39cfTo0VIfU1hYiMLCQuX93NxcAEBeXp5WMhYXFmjluP/2svzMwRy6lKOgoEClraSkBADw+MHjcs1RFl35ufD1YI4X0ZX3x81jw8onh592/p9++vyEEC/fWbzhbty4IQCII0eOqLSPHz9etGrVqtTHTJ06VQDgjTfeeOONN954U97S09NfWne88SNOryIsLAyhoaHK+wqFAtnZ2bCxsYFMJqvAZE/k5eXByckJ6enpkMvlzMEczMEczMEczKFFQgjcv38fjo6OL933jS+cqlWrBn19fWRlZam0Z2Vlwd7evtTHGBkZwcjISKXNyspKWxFfmVwu14k3FHMwB3MwB3MwR2XOAQCWlpaS9nvj13EyNDRE8+bNERcXp2xTKBSIi4uDl5dXBSYjIiKiyuaNH3ECgNDQUAQFBaFFixZo1aoVFi9ejIKCAuVVdkRERESaUCkKpw8//BC3b9/GlClT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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "x1 = df_gap22_cas['app']\n", + "y1 = 100 * df_gap22_cas['numRdHit'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", + "y2 = 100 * df_gap22_cas['numWrHit'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(6,3)\n", + "plt.ylim([0,110])\n", + "\n", + "for i,app in enumerate(x1): \n", + " plt.bar(i*4, y1[i], width=3, color=cmap(1), label='Read' if i==0 else None)\n", + " plt.bar(i*4, y2[i], bottom = y1[i], width=3, color=cmap(2), label='Write' if i==0 else None)\n", + "\n", + "offset = (i+1)*4\n", + "x2 = df_npbC_cas['app']\n", + "y1 = 100 * df_npbC_cas['numRdHit'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", + "y2 = 100 * df_npbC_cas['numWrHit'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", + "\n", + "for i,app in enumerate(x2): \n", + " plt.bar(i*4+offset, y1[i], width=3, color=cmap(1))\n", + " plt.bar(i*4+offset, y2[i], bottom = y1[i], width=3, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*4, list(x1)+list(x2))\n", + "plt.axvline(x=offset-2, color='black')\n", + "\n", + "plt.ylabel(\"DRAM Cache Hit Rate (%)\", fontsize=10)\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_mpki.pdf\")\n", + "\n", + "x1 = df_gap25_cas['app']\n", + "y1 = 100 * df_gap25_cas['numRdHit'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", + "y2 = 100 * df_gap25_cas['numWrHit'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(6,3)\n", + "plt.ylim([0,110])\n", + "\n", + "for i,app in enumerate(x1): \n", + " plt.bar(i*4, y1[i], width=3, color=cmap(1), label='Read' if i==0 else None)\n", + " plt.bar(i*4, y2[i], bottom = y1[i], width=3, color=cmap(2), label='Write' if i==0 else None)\n", + "\n", + "offset = (i+1)*4\n", + "x2 = df_npbD_cas['app']\n", + "y1 = 100 * df_npbD_cas['numRdHit'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", + "y2 = 100 * df_npbD_cas['numWrHit'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", + "\n", + "for i,app in enumerate(x2): \n", + " plt.bar(i*4+offset, y1[i], width=3, color=cmap(1))\n", + " plt.bar(i*4+offset, y2[i], bottom = y1[i], width=3, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*4, list(x1)+list(x2))\n", + "plt.axvline(x=offset-2, color='black')\n", + "\n", + "plt.ylabel(\"DRAM Cache Hit Rate (%)\", fontsize=10)\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_mpki.pdf\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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6v379/H777+rPnNLsmnTJvj4+KBly5ZF1unr65f4N4NIk0QXFuPHj4elpSUGDx6M/fv3o7CwsDJyEVEx/v77bwiCoLqGzCt16tRR/YM/efJkAIBCocCvv/6Kjz76CADw0UcfYfv27cjKyirx+AkJCVixYgVatWoFMzMz1fJBgwbB1NQURkZGcHJygouLC0JDQwG87AoZERGBdevWQS6Xw8vLC19//TUuXbok+tyWLFmCTz/9tMRttm/fjrNnzyIoKEjUsYmIqsrAgQPh4eGBadOm/ee2qampmD9/PurVq6f2uT558mSYmprC2NgY9evXh0QiwYIFC0o9VkJCApydnSucn6giRBcWqamp2Lp1KyQSCT744APY2Nhg9OjROHXqVGXkI6IyOHPmDGJjY+Hi4qJqNdiyZQsaN24Md3d3AICHhwccHBywbds2tX0zMzNhamqKmjVrwsnJCVZWVkUGSIeFhSE2NhZxcXHYu3cvbt68iaFDh6rW+/n5ISUlBXv27EGPHj0QFRWFt956CxEREQCAkSNHqgqf4lo479+/jx49euD999/H8OHDiz3Ho0ePIigoCKtWrYKLi0u5nysiosr2/fffY926dbh+/Xqx6+vXrw8TExPY2toiOzsbO3bsgIGBgWr9pEmTEBsbi0uXLiEyMhIA0Lt3b9WXuf/8PB05ciQAQBB39QCiylGRflTZ2dnCxo0bhV69egkGBgZCo0aNNNNBi4iK9ejRI0EikQhz5swpdn2nTp2EsWPHCoIgCK1btxYkEokglUpVN4lEInTo0EG1fXh4uGBmZiYkJCQIiYmJqnEV/4Rixlhs2bJFACAkJCSUmDU4OFiwt7cXBEEQ0tPThYSEBNXtn+7fvy80adJEGDp0qFBYWFjssaKiogQTExPh559/LvHxiIi0KSAgQOjfv7/qfq9evYT+/fsXO8biwoULwt9//y0oFIoixylujEV0dLQAQDh8+LAgCILa52l6erogCILg5uYmdO/evXJOjqiMRM8K9U81a9aEr68vnj59ijt37pRYmRORZtSuXRvdunXDTz/9hDFjxpTYZ/by5cs4d+4coqKi1MYjPHnyBN7e3rhx44aqyVxPTw+Ojo6icryaueT58+clbtO8eXPs3r0bAGBpaQlLS8si29y/fx+dO3eGp6cnwsPDoadXtBE1KioKffr0wffff48RI0aIyklEpC1z586Fh4dHka6rANCwYUPI5fIyH+vfn7nFfWYPHjwYX3/9NS5evFhknEV+fj7y8vI4zoIqneiuUACQk5ODTZs2oVevXqhXrx4WLlyIgQMH4urVq5rOR0T/smzZMhQUFKBVq1bYtm0brl+/jvj4eGzcuBE3btyAVCrFmjVr0KZNG3Ts2BEtWrRQ3Tp27IjWrVuXaRD3P2VkZCAtLQ0pKSk4duwYZsyYgaZNm6JZs2Z4/PgxunTpgo0bN+LSpUtISkrCL7/8gnnz5qF///4lHvP+/fvw9vaGvb095s+fj4cPHyItLQ1paWmqbY4ePYrevXvj888/h5+fn2r9kydPyv38ERFVBVdXVwwZMgSLFy8Wve+zZ8+QlpaG1NRUnDlzBpMmTULdunXRoUOHEvcZN24cvLy80LVrVyxduhRxcXG4desWtm/fjnbt2iEhIaEip0NUNmKbOD788EPBxMREqFu3rjB69Gjh1KlTldGSQkSlSElJEUJCQoSGDRsK+vr6gqmpqdCmTRvhhx9+EDIzM4XatWsL8+bNK3bf77//XrC0tBTy8vKKnW723wCobhKJRLCxsRE+/PBDITExURAEQXjx4oXw1VdfCW+99ZZgbm4u1KxZU3BychL+97//Fdu16pXw8HC1Y//z9kpAQECx6zt16iT6OSMiqkz/7golCIKQlJQkGBgYlDrd7L85ODiofd7VrVtX6NWrl3Dx4sX/zPDixQthzpw5gqurq2BkZCRYWFgIXl5eQkREhJCfn1+BsyMqG4kgiBvtM2TIEAwZMgS+vr6qprlXrly5ghYtWpS/yiEiIiIiIp0kurD4t2fPnmHLli1YvXo1zp8/z+lniYiIiIjeQOUaYwEAx48fR0BAAGxsbDB//nx06dIFp0+f1mQ2IiIiIiLSEaJmhUpLS0NERATWrFkDhUKBDz74ALm5udi9ezeaN29eWRmJiIiIiKiaK3OLRd++feHk5IRLly5h4cKFSElJwZIlSyozGxERERER6Ygyt1gcOHAAn3/+OUaNGoUmTZpUZiYiIiIiItIxZW6x+Ouvv/Ds2TN4enqibdu2+Omnn/Do0aPKzEZERERERDpC9KxQ2dnZ2LZtG9auXYszZ86gsLAQCxYswMcffwwzM7PKyklERERERNVYhaabjY+Px5o1a7BhwwZkZGSgW7du2LNnjybzERERERGRDqjwdSwAoLCwEL///jvWrl3LwoKIiIiI6A2kkcKCiIiIiIjebOW+QB4REREREdErLCyIiIiIiKjC/h93Oh1K/dn24AAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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cHCw2AVKJpPhgw8+KDR7ESnr0KEDjI2NYW5ujilTpuDTTz/FX3/9VeKq14MHD4apqSkWL16MgwcPwt/fX2yteHUbP348goKClFqaAMDAwABubm4wNjau6EsjIiKicpAI//0rXgKFQgF9fX3cuHEDDRo0qMhclSo9PR0mJiZIS0tTWizvxYsXiI2Nhb29PfT19aswIRGVBl+zL2c/MzIyAvBybRJDQ8MqTkRE1UV51k4q7ZpI9PYp7nNyUVRqsdDS0kKDBg3E7jZERERERERAGcZYLFiwAFOmTMH169crIg8REREREWkglVeRGzFiBLKzs9GiRQvo6uqKi6W98vpc9kRERERE9G5QubD4+eefKyAGERERERFpMpULi1eLWhEREREREb1SqjEWWVlZKp1U1eOrOxUmziKiKqRQKKo6AhER0TurVC0WDg4OmDBhAry8vGBlZVXkMYIg4OjRo1iyZAk6d+6MgIAAtQatCjo6OpBIJEhJSUHt2rVLnKefiKqOIAjIzc1FSkoKtLS0oKurW9WRiIiI3jmlKixCQ0Mxffp0fPfdd2jRogVat24Na2tr6Ovr49mzZ7h58ybCwsKgra2NgIAAfP755xWdu1JIpVK89957ePDgAeLi4qo6DhG9QY0aNWBrawstLZUnvCMiIqJyKlVh0ahRI+zatQvx8fHYuXMnTp06hbNnz+L58+eoVasWWrVqhTVr1qB3795v3erbRkZGaNCgAfLy8qo6ChGVQCqVQltbmy2LREREVUSlwdu2traYPHkyJk+eXFF5qiWpVPrWFUxEREREROrE/gJERERERFRuLCyIiIiIiKjcWFgQEREREVG5sbAgIiIiIqJyY2FBRERERETlpnJhUbduXcyZMwfx8fEVkYeIiIiIiDSQyoXFxIkTsXv3btSrVw89evTAtm3bkJOTUxHZiIiIiIhIQ5SpsIiIiMCFCxfQuHFjjB8/HlZWVvDz88Ply5dVOtfJkyfRv39/WFtbQyKRYO/evUr7vb29IZFIlG69evVSOubp06cYPnw4ZDIZ5HI5fH19kZmZqeplERERERFROZR5jMX777+PZcuWISEhAbNmzcLatWvRpk0btGzZEuvXr4cgCG88R1ZWFlq0aIFff/212GN69eqFxMRE8bZ161al/cOHD8eNGzdw5MgR7N+/HydPnsTo0aPLellERERERFQG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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_cas['app']\n", + "gap_22_cas = df_gap22_cas['avgTimeTagCheckResRd'].astype(float)\n", + "gap_22_ram = df_gap22_ram['avgTimeTagCheckResRd'].astype(float)\n", + "\n", + "\n", + "gap_25_cas = df_gap25_cas['avgTimeTagCheckResRd'].astype(float)\n", + "gap_25_ram = df_gap25_ram['avgTimeTagCheckResRd'].astype(float)\n", + "\n", + "\n", + "app_npb = df_npbC_cas['app']\n", + "npb_C_cas = df_npbC_cas['avgTimeTagCheckResRd'].astype(float)\n", + "npb_C_ram = df_npbC_ram['avgTimeTagCheckResRd'].astype(float)\n", + "\n", + "npb_D_cas = df_npbD_cas['avgTimeTagCheckResRd'].astype(float)\n", + "npb_D_ram = df_npbD_ram['avgTimeTagCheckResRd'].astype(float)\n", + "\n", + "\n", + "# Multi bar Chart1\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + " plt.bar(i*3+1, gap_22_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", + "\n", + "offset = i*3+2\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_C_cas[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*3+2, npb_C_ram[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Avg Tag Check Latency (reads) (ns)\")\n", + "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", + "plt.tight_layout()\n", + "\n", + "# Multi bar Chart2\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + " plt.bar(i*3+1, gap_25_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", + "\n", + "offset = i*3+2\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_D_cas[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*3+2, npb_D_ram[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"Avg Tag Check Latency (reads) (ns)\")\n", + "plt.legend(fontsize=9, ncol=2)\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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Ktq2bStu3bolMjMzRXx8vDA0NBSbNm0S6enp4tSpU2L58uXa7obSp59+KmrVqiViYmLExYsXxaFDh8TatWtFbm6u8PDwEB06dBCHDh0SaWlpYvPmzeLo0aPajlzKq7YlV1dXIZfLxeLFi8XFixfFxYsXqzTfzZs3hZGRkVi6dKm4cuWKSE5OFt98843Izc0VNjY2YtKkSeLixYvi3LlzIiYmRly9elUIIYSPj4/44IMPxPnz58WFCxfEli1bRGJiohBCiOjoaGFsbCwCAwPF0aNHxYkTJ0RQUJBo165dlfbtuYcPH4q2bduKoUOHilu3bolbt26JjIwMYWdnJ95++20RHx8vUlNTxfr160VKSopWMr7Kq17b9evXF7NmzVL2T9eU91rOzs4WdnZ24oMPPhBnz54Vf/zxh2jcuLEAIBISErQdu5SHDx+KWbNmifr164tbt26Ju3fvCgAiOjpa+VgfdOrUSYwbN07n9wFleZ5dCCEAlPo8Y2NjI6Kjo6s8V3k6deokrK2txezZs8WFCxfE7NmzhaGhoXj99dfFmjVrxIULF8TIkSOFvb29yMvLE5cvXxbGxsZi0qRJIiUlRfz444+iXr16AoDIysrSdndeus+IjIwUVlZW4t133xVnzpwRO3fuFA4ODmLatGnajq3k6uoqli1bVqKtefPmYsaMGUIIIZYtWyb2798vrly5ImJjY4WXl5cYOXJk1QetAioXFq+99pro3r27OHz4sBg+fLioV6+eGDx4sCguLhbFxcVi1KhRonXr1pWZVe916tRJeHt7C4VCoWyLiooS3t7eIjU1VQAQe/fu1WLCsr0stxBCjBs3TnTq1Ek5bevWrUIul4ucnJyqjvpKOTk5wtTUVKxdu7bUtO+++05YW1uLzMxMLSST5lX/E1dXV9GrVy9txRMnT54UAER6enqJ9szMTAFAxMXFlbmctbW1iImJKXNadHS0ACCOHTumbDt//rwAII4fP6658BL888OIEEJMnTpVuLu7i8LCQq3kkUqV7ejFnaWueNlredWqVcLe3l48efJE2bZ27VqdLSyEePbBw9XVVfm4rA+3uu7560GX9wHl0cfCon379srHT58+FZaWluLDDz9Utt26dUsAEH///beIiooSzZo1K7GOzz77TGcKi/L2GUIIERkZKezs7EReXp6ybdWqVcLKykoUFxdXZcxy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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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3Lgx3nrrLXz++ec4c+YMNm/ejLZt25ZHRiIiIiIi0nOSC4vFixcjLy8PADB9+nTk5eVh/fr18PT05BWhiIiIiIiqKMmFhbu7u/J3KysryXfbJiIiIiKiyqdM97EAgJMnT+L8+fMAgKZNm8LPz09roYiIiIiIyLBILizS09MxYMAAxMbGonr16gCArKwsBAUF4ffff4eDg4O2MxIRERERkZ6TfFWoMWPGIDc3F0lJSXjw4AEePHiAs2fPIicnB2PHji2PjEREREREpOckH7H4559/sGfPHjRu3FjZ1qRJE/zwww/o3r27VsMREREREZFhkHzEQqFQwNTUtES7qakpFAqFVkIREREREZFhkVxYdOnSBePGjcPt27eVbbdu3cKECRPQtWtXrYYjIiIiIiLDILmwWLZsGXJycuDm5oYGDRqgQYMGqF+/PnJycrB06dLyyEhERERERHpO8hgLFxcXnDp1Cnv27EFycjIAoHHjxggODtZ6OCIiIiIiMgxluo+FTCZDt27d0K1bN23nISIiIiIiA6RWYfH999+rvUBecpaIiIiIqOpRq7CIiIhQa2EymYyFBRERERFRFaRWYXHt2rXyzkFERERERAZM8lWhiIiIiIiIXiSpsLh06RI2bdqkPILx119/oVOnTvD398fs2bMhhCiXkEREREREpN/UvirUli1b0L9/fxgZGUEmk2HlypX49NNPERgYCLlcjm+//RYmJiYIDw8vz7xERERERKSH1D5iMXv2bHz55Zd4/Pgxli9fjhEjRmDu3LnYsWMHtm/fjh9++AHR0dHlGJWIiIiIiPSV2oXFhQsXMHToUMhkMoSGhqKwsFDlpnjdu3fH9evXyyUkERERERHpN7ULi/z8fNjY2Dx9kpERLC0tUa1aNeV0S0tLFBQUaD8hERERERHpPbULC5lMBplMVupjIiIiIiKqutQevC2EQMOGDZXFRF5eHvz8/GBkZKScTkREREREVZPahUVUVFR55iAiIiIiIgOmdmERGhpanjmIiIiIiMiA8c7bRERERESkMb0oLH744Qe4ubnBwsICbdq0wX//+19dRyIiIiIiIgl0XlisX78eYWFhmDZtGk6dOoXmzZujR48eSE9P13U0IiIiIiJSk84Li8WLF2P48OEYMmQImjRpghUrVqBatWqIjIzUdTQiIiIiIlKT2oO39+3bh4CAAJiZ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UgeengaVlJQEE5P/vcwVCgUiIyMxbNgwZZuNjQ1OnToFIyMjODk5qSzjmdq1a8PDwwMA4OXlhdzcXAwcOBCzZs1StltYWKBbt27o1q0bvvnmG3z88ceYNm0aBg8ejBkzZmDixIkv7dPt27cRFBSE9u3bY+XKla/9G7Rp0wa7d+9+7XxERLrSqVMn9OjRA5MnT8bgwYNLTD948CDkcjkcHR1Vjg4/U7NmTeV7q6enJ/7973+jXbt22LdvH4KDg5GQkKCcVy6XvzbP+fPnIZfLYW9vX+Y+EamDhQWRAbG3t0e3bt2wbNkyjBkzptRxFmfOnMGJEycQGxurMmbhwYMHCAwMRHJyMho1agQAMDIyUu7A1GVsbAwAePToUanzNGnSBFu3bgXw9BxfR0fHEvPcunULQUFBaNmyJaKiomBk9PqDqAkJCXBycpKUl4ioos2bNw++vr4lTl0FgPr166N69epqL+vF91wp79np6elYt24dQkJC1HqPJdIECwsiA/Pjjz8iICAArVq1wrfffgsfHx8YGRkhLi4OycnJaNmyJVavXo3WrVujU6dOJZ7v7++P1atXSzqdKCsrC3fu3IFCocClS5cwY8YMNGzYEI0bN0ZGRgb69euHoUOHwsfHBzY2Njhx4gQWLFiAPn36lLrMW7duITAwEK6urli4cCHu3bunnFa7dm0AwJo1a2BmZgY/Pz8AwObNmxEZGYn//Oc/amcnItIFb29vfPDBB/j+++8lPzc3Nxd37tyBEAI3b97El19+CQcHB7Rv3/6VzxNCKJ+XlZWFo0ePYs6cObC1tS1xfw2i8sDCgsjANGjQAPHx8ZgzZw4mT56M1NRUmJubo0mTJpg4cSI++eQTuLu7Kwdxv6hv375YtGgR5syZo/Y6hwwZAuDp+bm1a9dGp06dMGfOHJiYmMDa2hpt2rRBREQErly5gqKiIri4uGD48OEvvSfFM7t378bly5dx+fJlODs7q0x7dj4wAMycORPXr1+HiYkJGjVqhPXr1+O9995TOzsRka7MmDGjxLg2dUydOhVTp04FADg4OMDf3x+7du167alMOTk5cHJygkwmg1wuh5eXF0JDQzFu3Di1Tpki0pRMPL8HJyIiIiIiKgOebEdERERERBpjYUFERERERBpjYUFERERERBpjYUFERERERBpjYUFERERERBpjYUFERERERBpjYUFERERERBpjYUFERERERBpjYUFERERERBpjYUFERERERBpjYUFERERERBpjYUFERERERBr7f1lfDq65aiLxAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_cas['app']\n", + "gap_22_cas = df_gap22_cas['BWBloat'].astype(float)\n", + "gap_22_ram = df_gap22_ram['BWBloat'].astype(float)\n", + "\n", + "\n", + "gap_25_cas = df_gap25_cas['BWBloat'].astype(float)\n", + "gap_25_ram = df_gap25_ram['BWBloat'].astype(float)\n", + "\n", + "app_npb = df_npbC_cas['app']\n", + "npb_C_cas = df_npbC_cas['BWBloat'].astype(float)\n", + "npb_C_ram = df_npbC_ram['BWBloat'].astype(float)\n", + "\n", + "npb_D_cas = df_npbD_cas['BWBloat'].astype(float)\n", + "npb_D_ram = df_npbD_ram['BWBloat'].astype(float)\n", + "\n", + "\n", + "# Multi bar Chart1\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,3.5])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + " plt.bar(i*3+1, gap_22_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", + "\n", + "offset = i*3+2\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_C_cas[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*3+2, npb_C_ram[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, -0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"BW Bloat (due to acc amp)\")\n", + "plt.legend(fontsize=8, ncol=2, loc='upper left')\n", + "plt.tight_layout()\n", + "\n", + "# Multi bar Chart2\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "plt.ylim([0,3.5])\n", + "\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*3, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", + " plt.bar(i*3+1, gap_25_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", + "\n", + "offset = i*3+2\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*3+1, npb_D_cas[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*3+2, npb_D_ram[i], width=1, color=cmap(2))\n", + "\n", + "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", + "plt.figtext(0.75, -0.01, \"NPB-D\")\n", + "\n", + "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1, color='grey')\n", + "\n", + "plt.ylabel(\"BW Bloat (due to acc amp)\")\n", + "plt.legend(fontsize=8, ncol=2, loc='upper left')\n", + "plt.tight_layout()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/realAppRun.sh b/realAppRun.sh new file mode 100755 index 0000000000..3aca47a56e --- /dev/null +++ b/realAppRun.sh @@ -0,0 +1,32 @@ +# script #App #Policy #Assoc #EnableLinkLatency #LinkLatency #EnableBypassDRAM$ +# # configs-npb-gapbs/restore_both.py bt.D.x Rambus 1 0 0 0 + +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/NPB/bt configs-npb-gapbs/restore_both.py bt.D.x RambusTagProbOpt 1 1 1250 0 7.5ns & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/NPB/cg configs-npb-gapbs/restore_both.py cg.D.x RambusTagProbOpt 1 1 1250 0 7.5ns & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/NPB/ft configs-npb-gapbs/restore_both.py ft.D.x RambusTagProbOpt 1 1 1250 0 7.5ns & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/NPB/is configs-npb-gapbs/restore_both.py is.D.x RambusTagProbOpt 1 1 1250 0 7.5ns & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/NPB/lu configs-npb-gapbs/restore_both.py lu.D.x RambusTagProbOpt 1 1 1250 0 7.5ns & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/NPB/mg configs-npb-gapbs/restore_both.py mg.D.x RambusTagProbOpt 1 1 1250 0 7.5ns & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/NPB/sp configs-npb-gapbs/restore_both.py sp.D.x RambusTagProbOpt 1 1 1250 0 7.5ns & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/NPB/ua configs-npb-gapbs/restore_both.py ua.D.x RambusTagProbOpt 1 1 1250 0 7.5ns & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/GAPBS/bc configs-npb-gapbs/restore_both.py bc-25 RambusTagProbOpt 1 1 1250 0 7.5ns & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/GAPBS/bfs configs-npb-gapbs/restore_both.py bfs-25 RambusTagProbOpt 1 1 1250 0 7.5ns & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/GAPBS/cc configs-npb-gapbs/restore_both.py cc-25 RambusTagProbOpt 1 1 1250 0 7.5ns & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/GAPBS/pr configs-npb-gapbs/restore_both.py pr-25 RambusTagProbOpt 1 1 1250 0 7.5ns & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/GAPBS/tc configs-npb-gapbs/restore_both.py tc-25 RambusTagProbOpt 1 1 1250 0 7.5ns & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/GAPBS/sssp configs-npb-gapbs/restore_both.py sssp-25 RambusTagProbOpt 1 1 1250 0 7.5ns & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/NPB/bt configs-npb-gapbs/restore_both.py bt.C.x RambusTagProbOpt 1 1 1250 0 7.5ns & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/NPB/cg configs-npb-gapbs/restore_both.py cg.C.x RambusTagProbOpt 1 1 1250 0 7.5ns & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/NPB/ft configs-npb-gapbs/restore_both.py ft.C.x RambusTagProbOpt 1 1 1250 0 7.5ns & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/NPB/is configs-npb-gapbs/restore_both.py is.C.x RambusTagProbOpt 1 1 1250 0 7.5ns & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/NPB/lu configs-npb-gapbs/restore_both.py lu.C.x RambusTagProbOpt 1 1 1250 0 7.5ns & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/NPB/mg configs-npb-gapbs/restore_both.py mg.C.x RambusTagProbOpt 1 1 1250 0 7.5ns & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/NPB/sp configs-npb-gapbs/restore_both.py sp.C.x RambusTagProbOpt 1 1 1250 0 7.5ns & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/NPB/ua configs-npb-gapbs/restore_both.py ua.C.x RambusTagProbOpt 1 1 1250 0 7.5ns & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/GAPBS/bc configs-npb-gapbs/restore_both.py bc-22 RambusTagProbOpt 1 1 1250 0 7.5ns & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/GAPBS/bfs configs-npb-gapbs/restore_both.py bfs-22 RambusTagProbOpt 1 1 1250 0 7.5ns & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/GAPBS/cc configs-npb-gapbs/restore_both.py cc-22 RambusTagProbOpt 1 1 1250 0 7.5ns & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/GAPBS/pr configs-npb-gapbs/restore_both.py pr-22 RambusTagProbOpt 1 1 1250 0 7.5ns & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/GAPBS/tc configs-npb-gapbs/restore_both.py tc-22 RambusTagProbOpt 1 1 1250 0 7.5ns & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/GAPBS/sssp configs-npb-gapbs/restore_both.py sssp-22 RambusTagProbOpt 1 1 1250 0 7.5ns & diff --git a/set-associative-data-plots.ipynb b/set-associative-data-plots.ipynb new file mode 100644 index 0000000000..79cb41287d --- /dev/null +++ b/set-associative-data-plots.ipynb @@ -0,0 +1,513 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import sys\n", + "from matplotlib import pyplot as plt\n", + "import os\n", + "\n", + "cmap = plt.get_cmap('Set1')\n", + "\n", + "Stats = ['simSeconds ',\n", + "'hostSeconds ',\n", + "'system.mem_ctrl.readReqs ',\n", + "'system.mem_ctrl.writeReqs ',\n", + "'system.mem_ctrl.servicedByWrQ ',\n", + "'system.mem_ctrl.mergedWrBursts ',\n", + "'system.mem_ctrl.numTotHits ',\n", + "'system.mem_ctrl.numTotMisses ',\n", + "'system.mem_ctrl.numColdMisses ',\n", + "'system.mem_ctrl.numHotMisses ',\n", + "'system.mem_ctrl.numRdMissClean ',\n", + "'system.mem_ctrl.numRdMissDirty ',\n", + "'system.mem_ctrl.numRdHit ',\n", + "'system.mem_ctrl.numWrMissClean ',\n", + "'system.mem_ctrl.numWrMissDirty ',\n", + "'system.mem_ctrl.numWrHit ',\n", + "'system.mem_ctrl.numRdHitDirty ',\n", + "'system.mem_ctrl.numRdHitClean ',\n", + "'system.mem_ctrl.numWrHitDirty ',\n", + "'system.mem_ctrl.numWrHitClean ',\n", + "'system.o3Cpu0.thread_0.numInsts ',\n", + "'system.o3Cpu1.thread_0.numInsts ',\n", + "'system.o3Cpu2.thread_0.numInsts ',\n", + "'system.o3Cpu3.thread_0.numInsts ',\n", + "'system.o3Cpu4.thread_0.numInsts ',\n", + "'system.o3Cpu5.thread_0.numInsts ',\n", + "'system.o3Cpu6.thread_0.numInsts ',\n", + "'system.o3Cpu7.thread_0.numInsts ',\n", + "'system.mem_ctrl.avgRdBWSys ',\n", + "'system.mem_ctrl.avgWrBWSys ',\n", + "'system.mem_ctrl.avgORBLen ',\n", + "'system.far_mem_ctrl.avgRdBWSys ',\n", + "'system.far_mem_ctrl.avgWrBWSys ',\n", + "'system.loc_mem_ctrl.avgRdBWSys ',\n", + "'system.loc_mem_ctrl.avgWrBWSys ',\n", + "'system.loc_mem_ctrl.dram.readBursts ',\n", + "'system.loc_mem_ctrl.dram.writeBursts ',\n", + "'system.loc_mem_ctrl.dram_2.readBursts ',\n", + "'system.loc_mem_ctrl.dram_2.writeBursts ',\n", + "'system.far_mem_ctrl.dram.readBursts ',\n", + "'system.far_mem_ctrl.dram.writeBursts ',\n", + "'system.loc_mem_ctrl.dram.avgRdBW ',\n", + "'system.loc_mem_ctrl.dram.avgWrBW ',\n", + "'system.loc_mem_ctrl.dram_2.avgRdBW ',\n", + "'system.loc_mem_ctrl.dram_2.avgWrBW ',\n", + "'system.far_mem_ctrl.dram.avgRdBW ',\n", + "'system.far_mem_ctrl.dram.avgWrBW ',\n", + "'system.loc_mem_ctrl.dram.busUtil ',\n", + "'system.loc_mem_ctrl.dram.busUtilRead ',\n", + "'system.loc_mem_ctrl.dram.busUtilWrite ',\n", + "'system.loc_mem_ctrl.dram_2.busUtil ',\n", + "'system.loc_mem_ctrl.dram_2.busUtilRead ',\n", + "'system.loc_mem_ctrl.dram_2.busUtilWrite ',\n", + "'system.far_mem_ctrl.dram.busUtil ',\n", + "'system.far_mem_ctrl.dram.busUtilRead ',\n", + "'system.far_mem_ctrl.dram.busUtilWrite ',\n", + "'system.far_mem_ctrl.dram.bytesRead ',\n", + "'system.far_mem_ctrl.dram.bytesWritten ',\n", + "'system.loc_mem_ctrl.dram.bytesRead ',\n", + "'system.loc_mem_ctrl.dram.bytesWritten ',\n", + "'system.loc_mem_ctrl.dram_2.bytesRead ',\n", + "'system.loc_mem_ctrl.dram_2.bytesWritten ',\n", + "'system.mem_ctrl.avgTimeTagCheckRes ',\n", + "'system.mem_ctrl.avgTimeTagCheckResRd ',\n", + "'system.mem_ctrl.avgTimeTagCheckResWr ',\n", + "'system.mem_ctrl.avgPktRespTimeRd ',\n", + "'system.mem_ctrl.avgPktRespTimeWr ',\n", + "'system.mem_ctrl.avgPktORBTime ',\n", + "'system.mem_ctrl.avgPktORBTimeRd ',\n", + "'system.mem_ctrl.avgPktORBTimeWr ',\n", + "'system.mem_ctrl.avgTimeInLocRead ',\n", + "'system.mem_ctrl.avgTimeInLocWrite ',\n", + "'system.mem_ctrl.avgTimeInFarRead '\n", + " ]\n", + "\n", + "dfCols = [\n", + " 'app',\n", + " 'simSeconds',\n", + " 'hostSeconds',\n", + " 'readReqs',\n", + " 'writeReqs',\n", + " 'servicedByWrQ',\n", + " 'mergedWrBursts',\n", + " 'numTotHits',\n", + " 'numTotMisses',\n", + " 'numColdMisses',\n", + " 'numHotMisses',\n", + " 'numRdMissClean',\n", + " 'numRdMissDirty',\n", + " 'numRdHit',\n", + " 'numWrMissClean',\n", + " 'numWrMissDirty',\n", + " 'numWrHit',\n", + " 'numRdHitDirty',\n", + " 'numRdHitClean',\n", + " 'numWrHitDirty',\n", + " 'numWrHitClean',\n", + " 'numInsts0',\n", + " 'numInsts1',\n", + " 'numInsts2',\n", + " 'numInsts3',\n", + " 'numInsts4',\n", + " 'numInsts5',\n", + " 'numInsts6',\n", + " 'numInsts7',\n", + " 'avgRdBWSys',\n", + " 'avgWrBWSys',\n", + " 'avgORBLen',\n", + " 'farAvgRdBWSys',\n", + " 'farAvgWrBWSys',\n", + " 'locAvgRdBWSys',\n", + " 'locAvgWrBWSys',\n", + " 'readBursts1',\n", + " 'writeBursts1',\n", + " 'readBursts2',\n", + " 'writeBursts2',\n", + " 'readBursts3',\n", + " 'writeBursts3',\n", + " 'loc1AvgRdBW',\n", + " 'loc1AvgWrBW',\n", + " 'loc2AvgRdBW',\n", + " 'loc2AvgWrBW',\n", + " 'farAvgRdBW',\n", + " 'farAvgWrBW',\n", + " 'loc1BusUtil',\n", + " 'loc1BusUtilRead',\n", + " 'loc1BusUtilWrite',\n", + " 'loc2BusUtil',\n", + " 'loc2BusUtilRead',\n", + " 'loc2BusUtilWrite',\n", + " 'farBusUtil',\n", + " 'farBusUtilRead',\n", + " 'farBusUtilWrite',\n", + " 'farBytesRead',\n", + " 'farBytesWritten',\n", + " 'loc1BytesRead',\n", + " 'loc1BytesWritten',\n", + " 'loc2BytesRead',\n", + " 'loc2BytesWritten',\n", + " 'avgTimeTagCheckRes',\n", + " 'avgTimeTagCheckResRd',\n", + " 'avgTimeTagCheckResWr',\n", + " 'avgPktRespTimeRd',\n", + " 'avgPktRespTimeWr',\n", + " 'avgPktORBTime',\n", + " 'avgPktORBTimeRd',\n", + " 'avgPktORBTimeWr',\n", + " 'avgTimeInLocRead',\n", + " 'avgTimeInLocWrite',\n", + " 'avgTimeInFarRead'\n", + "\n", + " ]\n", + "##########################################################\n", + "\n", + "def getStat(filename, stat, index):\n", + " filename = os.path.join(filename).replace('\\\\','/')\n", + " #print(stat)\n", + " #print(filename)\n", + " try:\n", + " x = 0\n", + " with open(filename) as f:\n", + " readlines = f.readlines()\n", + " for l in readlines:\n", + " if stat in l and x < (index-1):\n", + " x = x+1\n", + " elif stat in l and x == (index-1):\n", + " return l\n", + " return 0.0 #for cases where stat was not found\n", + " except: #for cases where the file was not found\n", + " return 0.0\n", + "\n", + "##########################################################\n", + "\n", + "def creatDataFrame(dataDir, suite, index):\n", + " app = []\n", + " if suite == \"GAPBS\":\n", + " app = ['bc', 'bfs', 'cc', 'pr', 'sssp', 'tc']\n", + " if suite == \"NPB\":\n", + " app = ['bt', 'cg', 'ft', 'is', 'lu', 'mg', 'sp', 'ua']\n", + " rows = []\n", + " i = 0\n", + " for a in app:\n", + " stats = [a]\n", + " for stat in Stats:\n", + " time_file_path = '{}/{}/stats.txt'.format(dataDir, a)\n", + " ret_line = getStat(time_file_path, stat, index[i])\n", + "\n", + " if ret_line != 0:\n", + " #if ret_line=='nan' :\n", + " # stat_val = 0\n", + " #else:\n", + " stat_val = ret_line.split()[1]\n", + " else:\n", + " stat_val = 0\n", + " stats.append(stat_val)\n", + "\n", + " rows.append(stats)\n", + " i = i+1\n", + " df = pd.DataFrame(rows, columns= dfCols)\n", + " df['totNumInsts'] = df['numInsts0'].astype(int)+df['numInsts1'].astype(int)+df['numInsts2'].astype(int)+df['numInsts3'].astype(int)+df['numInsts4'].astype(int)+df['numInsts5'].astype(int)+df['numInsts6'].astype(int)+df['numInsts7'].astype(int)\n", + " df['totBW'] = (df['avgRdBWSys'].astype(float)+df['avgWrBWSys'].astype(float))/1000000000\n", + " df['coldRate'] = (df['numColdMisses'].astype(float) / df['numTotMisses'].astype(float)) *100\n", + " df['injRate'] = (df['readReqs'].astype(float) + df['writeReqs'].astype(float))*64/1000000000 / df['simSeconds'].astype(float)\n", + " df['BIPS'] = (df['totNumInsts'].astype(float)/1000000000)/df['simSeconds'].astype(float)\n", + " \n", + " df['accAmp'] = (df['farBytesRead'].astype(float) + df['farBytesWritten'].astype(float) +\n", + " df['loc1BytesRead'].astype(float) + df['loc1BytesWritten'].astype(float) + \n", + " df['loc2BytesRead'].astype(float) + df['loc2BytesWritten'].astype(float)) / (df['readReqs'].astype(float) * 64 + df['writeReqs'].astype(float) * 64)\n", + " \n", + " df['BWBloat'] = (df['loc1AvgRdBW'].astype(float) + df['loc1AvgWrBW'].astype(float) +\n", + " df['loc2AvgRdBW'].astype(float) + df['loc2AvgWrBW'].astype(float) +\n", + " df['farAvgRdBW'].astype(float) + df['farAvgWrBW'].astype(float)) / ((df['avgRdBWSys'].astype(float) + df['avgWrBWSys'].astype(float)) / 1000000)\n", + " return df" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "df_gap22_dc_1 = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/set-Assoc-Res-Correct2/128MiB_16GB_g22_nC/1/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", + "df_npbC_dc_1 = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/set-Assoc-Res-Correct2/128MiB_16GB_g22_nC/1/NPB\", \"NPB\", [1,1,1,1,1,1,1,1])\n", + "df_gap22_dc_2 = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/set-Assoc-Res-Correct2/128MiB_16GB_g22_nC/2/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", + "df_npbC_dc_2 = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/set-Assoc-Res-Correct2/128MiB_16GB_g22_nC/2/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", + "df_gap22_dc_8 = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/set-Assoc-Res-Correct2/128MiB_16GB_g22_nC/8/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", + "df_npbC_dc_8 = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/set-Assoc-Res-Correct2/128MiB_16GB_g22_nC/8/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", + "df_gap22_dc_16 = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/set-Assoc-Res-Correct2/128MiB_16GB_g22_nC/16/GAPBS\", \"GAPBS\", [1,1,1,1,1,1,1,1])\n", + "df_npbC_dc_16 = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/set-Assoc-Res-Correct2/128MiB_16GB_g22_nC/16/NPB\", \"NPB\", [1,1,1,1,1,1,1,1])" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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AKxbtw49e/bE8uXL4ezsrJGcRERERER1mampKXr27Cm/3a5dOyxfvlyrGZQeY1FQUFCjA9e0/T+lp6cjJycHXbt2lW+ztrZG27ZtkZiYCABITEyEjY2NvKgAgK5du8LAwACnT5+u9NhFRUXIy8tT+CIiIiIielGsWbNG/uG8tihdWHh5eWHJkiXIzs6utI0QAj/++CN69OiBtWvXqhUsJycHAODo6Kiw3dHRUb4vJycHDg4OCvvr1asHW1tbeZuKLF68GNbW1vIvV1dXtbISEREREdUVixYtwrVr17B48WKtPq7SXaHi4+Mxc+ZMzJkzB35+fggICICzszNMTU3x4MED/PHHH0hMTES9evUwY8YMjBkzpjZzq2XGjBmIioqS387Ly2NxQURERER6b/ny5di3bx+OHTsGc3NzrT620oWFt7c39u7dixs3buDrr79GQkICTp06hcLCQtSvXx+tWrXC5s2b0aNHDxgaGqodzMnJCQBw584dNGjQQL79zp078Pf3l7e5e/euwv1KS0uRm5srv39FTExMYGJionZGIiIiIqK6YuXKldi9ezeOHTsGGxsbrT9+jQdvu7m5YfLkyZg8eXJt5JFr1KgRnJycEBcXJy8k8vLycPr0aYwbNw4A0L59ezx8+BDnzp1D69atAQDHjx+HTCZD27ZtazUfEREREVFdcevWLUyePBmenp544403APz9YXpV4441TaVZoTQlPz8f165dk99OT09HSkoKbG1t4ebmhkmTJmHBggVo0qSJfLpZZ2dn+VoXPj4+6N69O0aPHo2NGzeipKQEkZGRGDRoEGeEIiIiIiKtUXa9idri4uICIYROM+i0sDh79qy8ogIgH/cQHh6O2NhYTJ06FQUFBYiIiMDDhw/RsWNHHD58WL6GBQDs3LkTkZGR6NKli3yBPHUHjhMRERERUc3otLAIDg6usrKSSCSYN28e5s2bV2kbW1tbLoZHRERERKRjSk83S0REREREVBkWFkREREREpDaVC4uEhAQMGTIE7du3x+3btwEAO3bswC+//KKxcEREREREpB9UKiz27t2LkJAQmJmZITk5GUVFRQCAR48eYdGiRRoNSEREREREdZ9Kg7cXLFiAjRs3YtiwYfjyyy/l2wMDA7FgwQKNhSMiIiIi0geb+v2nVo475tshSrf9/vvv8cknn0Amk6G0tBQfffQRwsPDayVXRVQqLFJTU9GpU6dy262trfHw4UN1MxERERERUQ0IITBkyBDEx8fD19cXGRkZaNasGd566y1YWVlpJYNKXaGcnJwUFrZ75pdffoGnp6faoYiIiIiIqGYkEon8Q/68vDzY2dnBxMREa4+v0hWL0aNHY+LEidi6dSskEgmysrKQmJiIKVOmYNasWZrOSEREREREVZBIJNizZw/eeustWFhY4MGDB9i3bx+MjY21lkGlwmL69OmQyWTo0qULnjx5gk6dOsHExARTpkzB+PHjNZ2RiIiIiIiqUFpaigULFmDfvn3o1KkTzpw5g759++LSpUuoX7++VjKo1BVKIpHg448/Rm5uLn777TckJSXh3r17mD9/vqbzERERERFRNVJSUpCVlSUfB/3aa6/BxcUFycnJWsug0hWLZ4yNjdG8eXNNZSEiIiIiIhW4uroiOzsbly9fho+PD65du4br16/D29tbaxlUKiyePn2KdevW4cSJE7h79y5kMpnC/vPnz2skHBERERERVc/R0RFffPEF3n33XRgYGEAmk2H9+vVwc3PTWgaVCotRo0bh6NGjePvtt9GmTRtIJBJN5yIiIiIi0hs1WW+itoSFhSEsLExnj69SYfHdd9/h+++/R2BgoKbzEBERERGRHlJp8HbDhg21ttAGERERERHVfSoVFitWrMC0adOQmZmp6TxERERERKSHVOoKFRAQgKdPn8LT0xPm5uYwMjJS2J+bm6uRcERERET04ul7oJdS7Q72P1TLSUiTVCoswsLCcPv2bSxatAiOjo4cvE1EREREGrep33+qbTOm1dDqDzRHaCANVUelwuLUqVNITEyEn5+fpvMQERERkR5rF32k2jYOrbQQhLROpTEWzZo1Q2FhoaazEBERERGRnlLpisWSJUswefJkLFy4EC1btiw3xkIqlWokHBERERGRXphTS0MDlOzGNWHCBBw8eBCZmZlITk6Gv78/AKCoqAiTJ0/GkSNHYGpqCj8/P/znP9V3MVOFSoVF9+7dAQBdunRR2C6EgEQiQVlZmfrJiIiIiIhIKW+//TamTp2Kjh07KmyfPn06JBIJrl69ColEgpycnFrLoFJhceLECU3nICIiIiIiFXXq1KnctoKCAmzZsgW3bt2ST7bk5ORUaxlUKiyCgoI0nYOIiIiIiDTo+vXrsLW1xaJFi3Ds2DGYmZlhzpw55XodaYrShcXFixfRokULGBgY4OLFi1W29fX1VTsYERERERGprrS0FJmZmWjevDmWLFmC5ORkdOvWDb///jscHR01/nhKFxb+/v7IycmBg4MD/P39IZFIIET5wSQcY0FEREREpHtubm4wMDDA4MGDAQCtWrVCo0aNcOnSJd0WFunp6bC3t5d/T0RERER1n1KLzH07RAtJSNvq16+PLl264MiRI+jZsyfS09ORnp4OHx+fWnk8pQsLd3d3GBoaIjs7G+7u7rUShoiIiIiIam7MmDE4dOgQcnJyEBISAisrK1y7dg0bN27EqFGjMG3aNBgYGGDTpk1o2LBhrWSo0eDtiro+ERGRflBmNVwASJobUm0bZT4BBfgpKBG9RJRcb6K2bNq0qcLtnp6eWpvRVaVZoYiI6MXV90Cvatv0QphyB1NmwSgd/zEmqouU+SBAmQ8BiLSpxoXFv//9b1haWlbZZsKECSoHIiIiIiIt44cApAE1Liw2btwIQ0PDSvdLJBIWFkRERES1TJmri0ANrjASqanGhcXZs2fh4OBQG1mIiIiIiPSCTCbTdQSN0sRY6hoVFs+WAiciIiIiehkZGxvDwMAAWVlZsLe3h7Gxsd7/jyyEwL179yCRSGBkZKTycTgrFBERERGRkgwMDNCoUSNkZ2cjKytL13E0RiKRwMXFpcohD9WpUWERHR1d7cBtIiIiIqIXmbGxMdzc3FBaWoqysjJdx9EIIyMjtYoKQIXCgoiIiIjoZfes25A6XYdeNAa6DkBERERERPqPhQUREREREamNhQUREREREamtxutYEBERERG9rJRemDCm+oUJx3w7RN04dYpKhcWdO3cwZcoUxMXF4e7du+WmoX1RRscTERER0cujXfSRats4tNJCED2lUmExfPhw3LhxA7NmzUKDBg30flEQIiIiIiJSj0qFxS+//IKEhAT4+/trOA4RERER0UtijpIfzs/Rj0WqVRq87erqylW4iYiIiIhITqUrFqtXr8b06dOxadMmeHh4aDgSERFR7dnU7z9KtXvRBlUSEdU2lQqLgQMH4smTJ2jcuDHMzc3LrTiYm5urkXBERERERKQfVL5ioQ1z5szB3LlzFbZ5e3vjypUrAICnT59i8uTJ+PLLL1FUVISQkBB8/vnncHR01Eo+IiIiIiL6m0qFRXh4uKZzVOrVV1/FsWPH5Lfr1ftf5A8//BCHDh3C119/DWtra0RGRuKtt97CyZMntZaPiIjoRabc9Jtrq21zsP8hTcQhojpM5QXyysrKcODAAVy+fBnA3wVA3759YWhoqLFwwN+FhJOTU7ntjx49wpYtW7Br1y507twZABATEwMfHx8kJSWhXbt2Gs1BRERERESVU6mwuHbtGnr27Inbt2/D29sbALB48WK4urri0KFDaNy4scYCpqWlwdnZGaampmjfvj0WL14MNzc3nDt3DiUlJejatau8bbNmzeDm5obExMQqC4uioiIUFRXJb+fl5WksLxERvSCUmQZST6aAJCLSBpUKiwkTJqBx48ZISkqCra0tAOD+/fsYMmQIJkyYgEOHNHO5s23btoiNjYW3tzeys7Mxd+5cvP766/jtt9+Qk5MDY2Nj2NjYKNzH0dEROTk5VR538eLF5cZuEBFR3aapLjm9EKaJOFRDnI2L6MWnUmHx008/KRQVAGBnZ4clS5YgMDBQY+F69Ogh/97X1xdt27aFu7s7vvrqK5iZmal83BkzZiAqKkp+Oy8vD66urmplJSIiIg3glSIivaXSAnkmJiZ4/Phxue35+fkwNjZWO1RlbGxs0LRpU1y7dg1OTk4oLi7Gw4cPFdrcuXOnwjEZzzMxMYFUKlX4IiIiIiIi1al0xaJ3796IiIjAli1b0KZNGwDA6dOnMXbsWPTt21ejAZ+Xn5+P69evY+jQoWjdujWMjIwQFxeH0NBQAEBqaipu3LiB9u3b11oGIlKfMl1aACBpbkgtJyEiIiJNUamwWLt2LcLDw9G+fXv54nilpaXo27cv1qxZo7FwU6ZMQZ8+feDu7o6srCxER0fD0NAQYWFhsLa2xqhRoxAVFQVbW1tIpVKMHz8e7du354xQRC+Ivgd6VdumV4xy/eXZb5uIiKh2qVRY2NjY4Ntvv0VaWpp8sTofHx94eXlpNNytW7cQFhaG+/fvw97eHh07dkRSUhLs7e0BAKtWrYKBgQFCQ0MVFsgjIiqH/baJiIhqlcrrWABAkyZN0KRJE01lKefLL7+scr+pqSk+++wzfPbZZ7WWgYiIiIiIqqd0YREVFYX58+fDwsJCYUaliqxcuVLtYKQ/lO0vr9Q0kEp0a2GXFiIiIqK6R+nCIjk5GSUlJfLviXRGmS4tALu1EBEREWmR0oXFiRMnKvyeiIiIiIhIpXUsRo4cWeE6FgUFBRg5cqTaoYiIiIiISL+oVFhs27YNhYWF5bYXFhZi+/btaociIiIiIiL9UqNZofLy8iCEgBACjx8/hqmpqXxfWVkZvv/+ezg4OGg85MuAC4YRERERkT6rUWFhY2MDiUQCiUSCpk2bltsvkUgwd+5cjYUjosqxGCUiIqK6pEaFxYkTJyCEQOfOnbF3717Y2trK9xkbG8Pd3R3Ozs4aD0n/o6mViDll68tDo6tXtxpafSPOxkVERPRSqlFhERQUBABIT0+Hm5sbJBIlp/2kuodTthIRERGRBqm08nZmZiYyMzMr3d+pUyeVAxERERERkf5RqbAIDg4ut+35qxdlZWUqByIiIiIiIv2j0nSzDx48UPi6e/cuDh8+jNdeew1Hjx7VdEYiIiIiIqrjVLpiYW1tXW5bt27dYGxsjKioKJw7d07tYEREREREpD9UumJRGUdHR6SmpmrykEREREREpAdUumJx8eJFhdtCCGRnZ2PJkiXw9/fXRC4iIiIiItIjKhUW/v7+kEgkEEJxKtJ27dph69atGglGRERERET6Q6XCIj09XeG2gYEB7O3tYWpqqpFQRERERESkX1QqLNzd3TWdg4iIiEij2kUfqbZN0twQLSQhejmoNHh7woQJWLt2bbnt69evx6RJk9TNREREREREekalKxZ79+7FwYMHy23v0KEDlixZgtWrV6ubi0grlPk0C+AnWkREL6q+B3op1a5XTFi1bca0Glr9geaI6tsQ6SmVCov79+9XuJaFVCrFX3/9pXYoorpGmT88Sv3R+XaIJuIQERER1TkqFRZeXl44fPgwIiMjFbb/8MMP8PT01EgwohfSHImS7fiJFhEREekXlQqLqKgoREZG4t69e+jcuTMAIC4uDitWrGA3KCIiIiKil5BKhcXIkSNRVFSEhQsXYv78+QAADw8PbNiwAcOGDdNoQCIiIiIiqvtUKiwAYNy4cRg3bhzu3bsHMzMzWFpaajIXERERERHpEZWmmwWA0tJSHDt2DPv27ZOvwJ2VlYX8/HyNhSMiIiIiIv2g0hWLzMxMdO/eHTdu3EBRURG6desGKysrLF26FEVFRdi4caOmcxIREb30NvX7j1LtOO0pEemCSlcsJk6ciICAADx48ABmZmby7QMGDEBcXJzGwhERERERkX5Q6YpFQkICTp06BWNjY4XtHh4euH37tkaCERERvSiUWYyTC3ESkb5TqbCQyWQoKysrt/3WrVuwsrJSOxQREdHLRqmFOFH9QpxERLqiUleoN998U2G9ColEgvz8fERHR6Nnz56aykZERERERHpCpSsWK1asQEhICJo3b46nT5/ivffeQ1paGurXr4/du3drOiMREREREdVxKhUWLi4uuHDhAvbs2YMLFy4gPz8fo0aNwuDBgxUGcxMRERER0ctBpcLi3r17sLe3x+DBgzF48GCFfZcuXULLli01Eo6IiIiIiPSDSmMsWrZsiUOHDpXbvnz5crRp00btUEREREREpF9UKiyioqIQGhqKcePGobCwELdv30aXLl2wbNky7Nq1S9MZiYiIiIiojlOpsJg6dSoSExORkJAAX19f+Pr6wsTEBBcvXsSAAQM0nZGIiIiIiOo4lQoLAPDy8kKLFi2QkZGBvLw8DBw4EE5OTprMRkREREREekKlwuLkyZPw9fVFWloaLl68iA0bNmD8+PEYOHAgHjx4oOmMRERERERUx6lUWHTu3BkDBw5EUlISfHx88P777yM5ORk3btzgjFBERERERC8hlaabPXr0KIKCghS2NW7cGCdPnsTChQs1EoyIiIiIiPSHSlcs/llUyA9mYIBZs2apFYiIiIiIiPRPjQqLnj174tGjR/LbS5YswcOHD+W379+/j+bNm2ssHBERERER6YcaFRZHjhxBUVGR/PaiRYuQm5srv11aWorU1FTNpSMiIiIiIr1Qo8JCCFHlbSIiIiIiejmpvI4FERERERHRMzUqLCQSCSQSSbltRERERET0cqvRdLNCCAwfPhwmJiYAgKdPn2Ls2LGwsLAAAIXxF9r22Wef4dNPP0VOTg78/Pywbt06tGnTRmd5iIiIiIheJjUqLMLDwxVuDxkypFybYcOGqZdIBXv27EFUVBQ2btyItm3bYvXq1QgJCUFqaiocHBy0noeIiIiI6GVTo8IiJiamtnKoZeXKlRg9ejRGjBgBANi4cSMOHTqErVu3Yvr06TpOR0RERET04lNp5e26pLi4GOfOncOMGTPk2wwMDNC1a1ckJiZWeJ+ioiKFblvP1ubIy8ur3bBVKC0qUKpdyZOSatsUlhRW2yZP2V5rSvxMmP1vL3p2QMn8zA5At9kLCgqe25yHsrIyAPqRvSrK5Gf2vzH73zSVHdDgOZ7ZATD7M5r8v6C2PPv/WJnZYCVCz+eMzcrKQsOGDXHq1Cm0b99evn3q1Kn46aefcPr06XL3mTNnDubOnavNmEREREREeuvmzZtwcXGpso3eX7FQxYwZMxAVFSW/LZPJkJubCzs7O72f5SovLw+urq64efMmpFKpruPUCLPrBrPrBrPrBrPrhj5nB/Q7P7Prhj5n/ychBB4/fgxnZ+dq2+p9YVG/fn0YGhrizp07Ctvv3LkDJyenCu9jYmIin9nqGRsbm9qKqBNSqVRvX8jMrhvMrhvMrhvMrhv6nB3Q7/zMrhv6nP151tbWSrXT+wXyjI2N0bp1a8TFxcm3yWQyxMXFKXSNIiIiIiKi2qP3VywAICoqCuHh4QgICECbNm2wevVqFBQUyGeJIiIiIiKi2vVCFBYDBw7EvXv3MHv2bOTk5MDf3x+HDx+Go6OjrqNpnYmJCaKjo8t19dIHzK4bzK4bzK4bzK4b+pwd0O/8zK4b+pxdHXo/KxQREREREeme3o+xICIiIiIi3WNhQUREREREamNhQUREREREamNhoaeCg4MxadIkXceokeoyP3nyBKGhoZBKpZBIJHj48KHWshFRxfTxXPOiEUIgIiICtra2kEgkSElJ0XUkpejra0dfcxPVBSwsqM7Ytm0bEhIScOrUKWRnZyu9GAuRPnhR/1nx8PDA6tWrdR3jhXb48GHExsbiu+++Q3Z2Nlq1aoUDBw7oOla19u3bh/nz5+s6BhFp0Qsx3Sy9GK5fvw4fHx+0aNFC11Ho/ysuLoaxsbGuYxC91K5fv44GDRqgQ4cOuo5SI7a2trqOQERaxisWeqy0tBSRkZGwtrZG/fr1MWvWLDybPbioqAjTpk2Dq6srTExM4OXlhS1btug4ceWZg4ODsWLFCvz888+QSCQIDg4GAHz++edo0qQJTE1N4ejoiLffflu3TwB/r+y+bNkyeHl5wcTEBG5ubli4cCEA4NatWwgLC4OtrS0sLCwQEBCA06dP6zjx/wQHByMyMrLS142Hhwfmz5+PYcOGQSqVIiIiQqv5vvnmG7Rs2RJmZmaws7ND165dUVBQgPj4eLRp0wYWFhawsbFBYGAgMjMzAQAXLlzAG2+8ASsrK0ilUrRu3Rpnz54FAMTGxsLGxgYHDhyQv45CQkJw8+ZNrT6v4cOH46effsKaNWsgkUggkUiQkZGB33//Hb1794ZUKoWVlRVef/11XL9+XavZlFHV+zYzMxMffvih/HnVJVW9V0+dOgV/f3+YmpoiICAABw4cqJPdjIYPH47x48fjxo0bkEgk8PDwAAAMGDBA4XZd9PxVurp4LleGRCIpd3XIxsYGsbGxOsnzT8HBwRg/fjwmTZqEV155BY6Ojti8ebN8kWArKyt4eXnhhx9+kN/n4MGD8t/FG2+8gW3btum8+3Fl5/7hw4ejf//+mDt3Luzt7SGVSjF27FgUFxfrLOvzKrpi6+/vjzlz5gAAVq5ciZYtW8LCwgKurq744IMPkJ+fr/2gWsQrFnps27ZtGDVqFH799VecPXsWERERcHNzw+jRozFs2DAkJiZi7dq18PPzQ3p6Ov766y9dR6408759+zB9+nT89ttv2LdvH4yNjXH27FlMmDABO3bsQIcOHZCbm4uEhARdPwXMmDEDmzdvxqpVq9CxY0dkZ2fjypUryM/PR1BQEBo2bIiDBw/CyckJ58+fh0wm03VkBVW9bgBg+fLlmD17NqKjo7WaKzs7G2FhYVi2bBkGDBiAx48fIyEhAUII9O/fH6NHj8bu3btRXFyMX3/9Vf5P7ODBg9GqVSts2LABhoaGSElJgZGRkfy4T548wcKFC7F9+3YYGxvjgw8+wKBBg3Dy5EmtPbc1a9bg6tWraNGiBebNmwcAKCsrQ6dOnRAcHIzjx49DKpXi5MmTKC0t1VouZVX1vvXz80NERIT89VOXVPZezcvLQ58+fdCzZ0/s2rULmZmZdbab2po1a9C4cWN88cUXOHPmDAwNDeHg4ICYmBh0794dhoaGuo5Yrbp6Ln9RbNu2DVOnTsWvv/6KPXv2YNy4cdi/fz8GDBiAmTNnYtWqVRg6dChu3LiBO3fu4O2338bEiRPx/vvvIzk5GVOmTNFp/qrO/QAQFxcHU1NTxMfHIyMjAyNGjICdnZ38Q4K6zMDAAGvXrkWjRo3w559/4oMPPsDUqVPx+eef6zpa7RGkl4KCgoSPj4+QyWTybdOmTRM+Pj4iNTVVABA//vijDhOWV1VmIYSYOHGiCAoKku/bu3evkEqlIi8vT9tRK5WXlydMTEzE5s2by+3btGmTsLKyEvfv39dBMuVU9ztwd3cX/fv310m2c+fOCQAiIyNDYfv9+/cFABEfH1/h/aysrERsbGyF+2JiYgQAkZSUJN92+fJlAUCcPn1ac+GVEBQUJCZOnCi/PWPGDNGoUSNRXFys1Rw1pcxrZtWqVTpKV7mq3qsbNmwQdnZ2orCwUL5t8+bNAoBITk7WYkrlrFq1Sri7u8tvAxD79+/XWR5lPXvN18VzeVWef69W9LO2trYWMTExWs9VkaCgINGxY0f57dLSUmFhYSGGDh0q35adnS0AiMTERDFt2jTRokULhWN8/PHHAoB48OCBtmIrqOzcL4QQ4eHhwtbWVhQUFMi3bdiwQVhaWoqysjJtxqxQRec/Pz8/ER0dXWH7r7/+WtjZ2dV+MB1iVyg91q5dO4WuB+3bt0daWhqSk5NhaGiIoKAgHaarWGWZy8rKyrXt1q0b3N3d4enpiaFDh2Lnzp148uSJNuOWc/nyZRQVFaFLly7l9qWkpKBVq1Z1vl9xdb+DgIAAneTy8/NDly5d0LJlS7zzzjvYvHkzHjx4AFtbWwwfPhwhISHo06cP1qxZg+zsbPn9oqKi8P7776Nr165YsmRJua5E9erVw2uvvSa/3axZM9jY2ODy5ctae24VSUlJweuvv65wdaWuqsn7tq6o6r2ampoKX19fmJqayre1adNGm/FeKnXxXP4i8fX1lX9vaGgIOzs7tGzZUr7N0dERAHD37l2kpqYqnA8B3b/2Kzv3P7/f3Nxcfrt9+/bIz8/XepdWVRw7dgxdunRBw4YNYWVlhaFDh+L+/fsv9OufhcUL6Pk/lvrMysoK58+fx+7du9GgQQPMnj0bfn5+Ou0HamZmptI+fWJhYaGTxzU0NMSPP/6IH374Ac2bN8e6devg7e2N9PR0xMTEIDExER06dMCePXvQtGlTJCUlAQDmzJmD33//Hb169cLx48fRvHlz7N+/XyfPoSZelNdLXcWfb91RF8/lypJIJPIuOc+UlJToKE3F/vnhhEQiUdj27EOButYt95mqzv11nYGBQaWvj4yMDPTu3Ru+vr7Yu3cvzp07h88++wwA6swYkdrAwkKP/XNQcFJSEpo0aQI/Pz/IZDL89NNPOkpWucoyV9ZPuF69eujatSuWLVuGixcvIiMjA8ePH9dG1Ao1adIEZmZmiIuLK7fP19cXKSkpyM3N1UEy5dX0d6BNEokEgYGBmDt3LpKTk2FsbCwvElq1aoUZM2bg1KlTaNGiBXbt2iW/X9OmTfHhhx/i6NGjeOuttxATEyPfV1paKh/MDfz9afXDhw/h4+OjvScGwNjYWOETfl9fXyQkJNS5f1IqUtVr5p/Pq66o6r3q7e2NS5cuoaioSL7tzJkz2oynFiMjozr5M69KXTuXK8ve3l7hCmlaWppef9rs7e2tcD4E6sZrv6pz/4ULF1BYWChvm5SUBEtLS7i6uuoqrtw/Xx95eXnygujcuXOQyWRYsWIF2rVrh6ZNmyIrK0tXUbWGhYUeu3HjBqKiopCamordu3dj3bp1mDhxIjw8PBAeHo6RI0fiwIEDSE9PR3x8PL766itdR640c0W+++47rF27FikpKcjMzMT27dshk8ng7e2t5dT/Y2pqimnTpmHq1KnYvn07rl+/jqSkJGzZsgVhYWFwcnJC//79cfLkSfz555/Yu3cvEhMTdZa3IjX5HWjT6dOnsWjRIpw9exY3btzAvn37cO/ePZiZmWHGjBlITExEZmYmjh49irS0NPj4+KCwsBCRkZGIj49HZmYmTp48iTNnzigUDUZGRhg/fjxOnz6Nc+fOYfjw4WjXrp3WL/97eHjg9OnTyMjIwF9//YXIyEjk5eVh0KBBOHv2LNLS0rBjxw6kpqZqNZcyqnrNeHh44Oeff8bt27frxAQRz1T1Xn3vvfcgk8kQERGBy5cv48iRI1i+fDkA1LmZrSri4eGBuLg45OTkKHQZqavq4rlcWZ07d8b69euRnJyMs2fPYuzYsXrRfbEyY8aMwZUrVzBt2jRcvXoVX331lXyGK1299is79z87jxcXF2PUqFH4448/8P333yM6OhqRkZEwMND9v7CdO3fGjh07kJCQgEuXLiE8PFz+IZ2XlxdKSkqwbt06/Pnnn9ixYwc2btyo48RaoOtBHqSaoKAg8cEHH4ixY8cKqVQqXnnlFTFz5kz5AMvCwkLx4YcfigYNGghjY2Ph5eUltm7dWqcz/3PwdkJCgggKChKvvPKKMDMzE76+vmLPnj06Sv8/ZWVlYsGCBcLd3V0YGRkJNzc3sWjRIiGEEBkZGSI0NFRIpVJhbm4uAgICtD5IuCrV/Q50ORD3jz/+ECEhIcLe3l6YmJiIpk2binXr1omcnBzRv39/+WvZ3d1dzJ49W5SVlYmioiIxaNAg4erqKoyNjYWzs7OIjIyUD8qNiYkR1tbWYu/evcLT01OYmJiIrl27iszMTK0/v9TUVNGuXTthZmYmAIj09HRx4cIF8eabbwpzc3NhZWUlXn/9dXH9+nWtZ6tKda+ZxMRE4evrK0xMTERd+5NS1Xv15MmTwtfXVxgbG4vWrVuLXbt2CQDiypUrOk5d3j8Hbx88eFB4eXmJevXqKWyva54Ngq6r5/LKPD94+/bt2+LNN98UFhYWokmTJuL777+vc4O3n58UQoiKz+N4bhD6t99+K7y8vISJiYkIDg4WGzZsEAAUJjPQpsrO/UL8PXi7X79+Yvbs2cLOzk5YWlqK0aNHi6dPn+ok6z89evRIDBw4UEilUuHq6ipiY2MVBm+vXLlSNGjQQJiZmYmQkBCxfft2nQ6U1waJEP/oHEZEL6zg4GD4+/u/NCslx8bGYtKkSXrRl5t0a+fOnRgxYgQePXrE8Rn0Ulm4cCE2btxYJwdDDx8+HA8fPtSLlebpb1zHgoiIXjrbt2+Hp6cnGjZsiAsXLmDatGl49913WVTQC+/zzz/Ha6+9Bjs7O5w8eRKffvopIiMjdR2LXhAsLIiI6KWTk5OD2bNnIycnBw0aNMA777yjFwtuEakrLS0NCxYsQG5uLtzc3DB58mTMmDFD17HoBcGuUEREREREpDbdD6knIiIiIiK9x8KCiIiIiIjUxsKCSA/l5ORg4sSJ8PLygqmpKRwdHREYGIgNGzaUW7xp8eLFMDQ0xKefflruOLGxsZBIJJBIJDAwMICLiwtGjBiBu3fvyts82y+RSFCvXj24ubkhKipKYXGxe/fuYdy4cXBzc4OJiQmcnJwQEhKCkydPVvocMjIyMGrUKDRq1AhmZmZo3LgxoqOjFVYkjY+PR79+/dCgQQNYWFjA398fO3fuVOdHR0RUK4YPHw6JRIIlS5YobD9w4IB8jYj4+HiFc6qjoyNCQ0Px559/ytt7eHjI9xsaGsLZ2RmjRo1Sas2S4uJiLFu2DH5+fjA3N0f9+vURGBiImJgYvViMk/QfB28T6Zk///wTgYGBsLGxwaJFi9CyZUuYmJjg0qVL+OKLL9CwYUP07dtX3n7r1q2YOnUqtm7dio8++qjc8aRSKVJTUyGTyXDhwgWMGDECWVlZOHLkiLxNTEwMunfvjpKSEnkbCwsLzJ8/HwAQGhqK4uJibNu2DZ6enrhz5w7i4uJw//79Sp/HlStXIJPJsGnTJnh5eeG3337D6NGjUVBQIF+s7NSpU/D19cW0adPg6OiI7777DsOGDYO1tTV69+6tqR8pEZFGmJqaYunSpRgzZgxeeeWVStulpqbCysoKaWlpiIiIQJ8+fXDx4kX54mrz5s3D6NGjUVZWhqtXryIiIgITJkzAjh07Kj1mcXExQkJCcOHCBcyfPx+BgYGQSqVISkrC8uXL0apVK/j7+2v6KRMp0u0yGkRUUyEhIcLFxUXk5+dXuP/ZwmVCCBEfHy8aNmwoiouLhbOzszh58qRC22cLyD1v4cKFwsDAQDx58kQIobiw0jOjRo0SPXv2FEII8eDBAwFAxMfHq/nMhFi2bJlo1KhRlW169uwpRowYofZjERFpUnh4uOjdu7do1qyZ+Oijj+Tb9+/fL1888sSJE+UWSNu5c6fC4owVLXA3f/580bx58yoff+nSpcLAwECcP3++3L7i4uJK/2YQaRK7QhHpkfv37+Po0aP4v//7P1hYWFTY5tkldwDYsmULwsLCYGRkhLCwMGzZsqXaxzAzM4NMJkNpaWmF+69evYrjx4+jbdu2AABLS0tYWlriwIEDCt2jVPHo0SPY2tqq3YaISBcMDQ2xaNEirFu3Drdu3VLqPs/WTnm+G+jzbt++jf/+97/yc25ldu7cia5du6JVq1bl9hkZGVX6N4NIk1hYEOmRa9euQQgBb29vhe3169eX/4M/bdo0AEBeXh6++eYbDBkyBAAwZMgQfPXVV8jPz6/0+Glpadi4cSMCAgJgZWUl3x4WFgZLS0uYmprC29sbr776qnze83r16iE2Nhbbtm2DjY0NAgMDMXPmTFy8eLHGz23dunUYM2ZMpW2++uornDlzBiNGjKjRsYmItGXAgAHw9/dHdHR0tW2zs7OxfPlyNGzYUOG8Pm3aNFhaWsLMzAwuLi6QSCRYuXJllcdKS0tDs2bN1M5PpA4WFkQvgF9//RUpKSl49dVX5VcNdu/ejcaNG8PPzw8A4O/vD3d3d+zZs0fhvo8ePYKlpSXMzc3h7e0NR0fHcgOkV61ahZSUFFy4cAHfffcdrl69iqFDh8r3h4aGIisrCwcPHkT37t0RHx+Pf/3rX4iNjQUAjB07Vl74WFpalst/+/ZtdO/eHe+88w5Gjx5d4XM8ceIERowYgc2bN+PVV19V+WdFRFTbli5dim3btuHy5csV7ndxcYGFhQWcnZ1RUFCAvXv3wtjYWL7/o48+QkpKCi5evIi4uDgAQK9evVBWVgYACufTsWPHAgAElyWjOoCDt4n0iJeXFyQSCVJTUxW2e3p6AvjfJXXg725Qv//+O+rV+9/bXCaTYevWrRg1apR8m5WVFc6fPw8DAwM0aNBA4RjPODk5wcvLCwDg7e2Nx48fIywsDAsWLJBvNzU1Rbdu3dCtWzfMmjUL77//PqKjozF8+HDMmzcPU6ZMqfA5ZWVl4Y033kCHDh3wxRdfVNjmp59+Qp8+fbBq1SoMGzZMmR8VEZHOdOrUCSEhIZgxYwaGDx9ebn9CQgKkUikcHBwUrg4/U79+ffm5tUmTJli9ejXat2+PEydOoGvXrkhJSZG3lUqlAICmTZviypUrtfJ8iJTFwoJIj9jZ2aFbt25Yv349xo8fX2mf2UuXLuHs2bOIj49XGI+Qm5uL4OBgXLlyRX7J3MDAQP4HTFnPZi4pLCystE3z5s1x4MABAICDgwMcHBzKtbl9+zbeeOMNtG7dGjExMTAwKH8RNT4+Hr1798bSpUsRERFRo5xERLqyZMkS+Pv7l+u6CgCNGjWCjY2N0sf65zm3onP2e++9h5kzZyI5ObncOIuSkhIUFxdznAXVOhYWRHrm888/R2BgIAICAjBnzhz4+vrCwMAAZ86cwZUrV9C6dWts2bIFbdq0QadOncrd/7XXXsOWLVsqXNeiMg8fPkROTg5kMhnS0tIwb948NG3aFD4+Prh//z7eeecdjBw5Er6+vrCyssLZs2exbNky9OvXr9Jj3r59G8HBwXB3d8fy5ctx7949+T4nJycAf3d/6t27NyZOnIjQ0FDk5OQAAIyNjTmAm4jqtJYtW2Lw4MFYu3Ztje/7+PFj5OTkQAiBmzdvYurUqbC3t0eHDh0qvc+kSZNw6NAhdOnSBfPnz0fHjh3l5+OlS5diy5YtnG6Wap+OZ6UiIhVkZWWJyMhI0ahRI2FkZCQsLS1FmzZtxKeffioePXok7OzsxLJlyyq879KlS4WDg4MoLi6ucLrZfwIg/5JIJKJBgwZi4MCB4vr160IIIZ4+fSqmT58u/vWvfwlra2thbm4uvL29xSeffCKfsrYiMTExCsd+/uuZ8PDwCvcHBQXV+GdGRFSbwsPDRb9+/RS2paenC2Nj4yqnm/0nd3d3hfOdvb296Nmzp0hOTq42w9OnT8XixYtFy5YthampqbC1tRWBgYEiNjZWlJSUqPHsiJQjEYKjfYiIiIiISD2cFYqIiIiIiNTGwoKIiIiIiNTGwoKIiIiIiNTGwoKIiIiIiNTGwoKIiIiIiNTGwoKIiIiIiNTGwoKIiIiIiNTGwoKIiIiIiNTGwoKIiIiIiNTGwoKIiIiIiNTGwoKIiIiIiNTGwoKIiIiIiNT2/wB0U5ZOZKZSjAAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_dc_1['app']\n", + "gap_1 = df_gap22_dc_1['simSeconds'].astype(float)*1000\n", + "gap_2 = df_gap22_dc_2['simSeconds'].astype(float)*1000\n", + "gap_8 = df_gap22_dc_8['simSeconds'].astype(float)*1000\n", + "gap_16 = df_gap22_dc_16['simSeconds'].astype(float)*1000\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "\n", + "#plt.ylim([0,200])\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*5, gap_1[i], width=1, color=cmap(1), label='1' if i==0 else None)\n", + " plt.bar(i*5+1, gap_2[i], width=1, color=cmap(2), label='2' if i==0 else None)\n", + " plt.bar(i*5+2, gap_8[i], width=1, color=cmap(3), label='8' if i==0 else None)\n", + " plt.bar(i*5+3, gap_16[i], width=1, color=cmap(4), label='16' if i==0 else None)\n", + "\n", + "offset = i*6-1\n", + "app_npb = df_npbC_dc_1['app']\n", + "npb_1 = df_npbC_dc_1['simSeconds'].astype(float)*1000\n", + "npb_2 = df_npbC_dc_2['simSeconds'].astype(float)*1000\n", + "npb_8 = df_npbC_dc_8['simSeconds'].astype(float)*1000\n", + "npb_16 = df_npbC_dc_16['simSeconds'].astype(float)*1000\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*5+1, npb_1[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*5+2, npb_2[i], width=1, color=cmap(2))\n", + " plt.bar(offset+i*5+3, npb_8[i], width=1, color=cmap(3))\n", + " plt.bar(offset+i*5+4, npb_16[i], width=1, color=cmap(4))\n", + "\n", + "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, 0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*5+1.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "\n", + "plt.ylabel(\"Execution Time (ms)\")\n", + "plt.legend(fontsize=8, ncol=1)\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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SrIKi8WLF2Pq1KmYMmVKiQPiLVmyROvBiIiIiIjIcMgqLB6fZn9VO74QEREREVHZZBUWY8eOBQD069cPvr6+GstOnz6t/VREREREZFB4p1DDpo3/P0V9LIYPH474+PjnziMiIiKiV4OJiQkkScKtW7dQvXr1Ei+bp8pNCIFbt25BkiSYmJi88HZkFRY3b95ERkYGHjx4gKSkJHVFk52djby8vBfeOREREREZNmNjY9SuXRvXrl3DlStX9B2HXpAkSahduzaMjY1feBuyCovt27dj2bJlSE9PR+/evdXz7ezsEBYW9sI7JyIiIiLDZ21tjbp166KwsFDfUegFmZiYlKuoABSOYzF37lzMmDGjXDusaBzHgoheZhzHgoiIdEln41gMGzYMV69efWa+m5ubsoRERERERPRSUVRYNGvWDJIkQQiBhw8f4v79+3B0dMTNmzd1lY+IiIiIiAyAosLi1q1bGtO7d+/GqVOntBqIiIiIiIgMj1F5Vu7fvz/279+vrSxERERERGSgFJ2xyMnJUf+7uLgYx44d05hHRERERESvJkWFhb29vbqPhbGxMerWrYsVK1boKhsRERERERkIRYWFSqXSVQ4iIiIiIjJgivpYnDhxAvfu3VNP37t3D3FxcVoPRUREREREhkXRGYuxY8fixIkT6mkLCwuMGzeOxQUREVVa6/psldVu7HeDdZyEiOjlpuiMhUql0hjqu0qVKigqKtJ6KCIiIiIiMiyKCgtTU1OkpKSopy9cuAATExOthyIiIiIiIsOi6FKoWbNmoV27dujWrRsA4ODBg4iIiNBJMCIiIlJwKVeTIc9vNFuUMw0RUekUFRY9evTAH3/8gZ9//hkAMGPGDLz22ms6CUZERERERIZD8cjb1tbWaNCgASZMmAB3d3cUFBTIXvf3339Hr169ULNmTUiShL179z53nejoaDRt2hRmZmbw8vJCZGSk0shERERERKRjis5YfPvtt5g6dSqMjIyQmpqKM2fOIDw8HAcOHJC1fl5eHvz8/DBixAj079//ue1TU1PRo0cPjBs3Dtu2bUNUVBRGjRoFFxcXBAUFKYlORERE9EqRcxkd74ZG2qSosPj0008RHx+PwMBAAICfnx/S0tJkr9+tWzd1/ww51q5dC09PTyxevBgA4OPjgz/++ANLly5VXFjcLyhClQLewYqIXi73C4ohmZg9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AwCWLVumyyxERERERGSgZBUWzZo1AwB06NABf//9N4BHg90REREREREBCsaxWLZsGZydneHk5AQnJye4uLi88FgWRERERET0cpFVWGzduhVr167Fpk2bcPv2bfz999+IjIzEunXrsG3bNl1nJCIiIiKiSk5WYfHll19ix44dCAoKgr29PapWrYqgoCB88803WLduna4zEhERERFRJSersMjIyICfn98z8319fZGZman1UEREREREZFhkFRY2NjalLrOystJaGCIiIiIiMkyy7gqVmZmJFStWlLjs1q1bWg1ERERERESGR1Zh0blzZyQkJJS4LDAwUKuBiIiIiIjI8MgqLCIiInSdg4iIiIiIDJjscSyIiIiIiIhKw8KCiIiIiIjKjYUFERERERGV2wsVFunp6UhPT9d2FiIiIiIiMlCKCotz586hYcOG6kfjxo1x/vx5XWUjIiIiIiIDoaiwmDBhAj788ENkZWUhKysLH374IcaPH6+rbEREREREZCAUFRZZWVl4++231dODBg1CVlaW1kMREREREZFhUVRYGBsb4+zZs+rps2fPwtjYWOuhiIiIiIjIsMgaIO+x+fPno3379vD19QUAJCUlYdu2bToJRkREREREhkNRYREUFIRz587h2LFjAIBWrVqhWrVqOglGRERERESGQ3Hn7erVq6Nnz57o2bMnqlWrhgkTJugqGxERERERGQhFhcXRo0efmXfkyBGthSEiIiIiIsMk61KoHTt24JtvvkFqair69++vnp+dnQ1ra2udhSMiIiIiIsMgq7CoX78++vTpg/j4ePTp00c939bWFp06ddJZOCIiIiIiMgyyCgs/Pz/4+fmhR48eqF69uq4zERERERGRgVHUx4JFBRERERERlURRYUFERERERFQSFhZERERERFRuiguLXbt2Yf78+QCA69evIykpSeuhiIiIiIjIsCgqLGbOnImvvvoKkZGRj1Y2MsLYsWMV73T16tXw8PCAubk5Xn/9dRw/frzM9v/+979Rv359mJubo3Hjxjhw4IDifRIRERERke4oKiy+++47fP/997CysgIAuLi4IDc3V9EOd+zYgdDQUMyaNQvx8fHw8/NDUFAQbt68WWL7I0eOIDg4GCNHjkRCQgL69u2Lvn374s8//1S0XyIiIiIi0h1FhYWFhQWMjY015gkhFO1wyZIlGD16NEJC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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_dc_1['app']\n", + "gap_1 = df_gap22_dc_1['simSeconds'].astype(float)*1000\n", + "gap_2 = df_gap22_dc_2['simSeconds'].astype(float)*1000\n", + "gap_8 = df_gap22_dc_8['simSeconds'].astype(float)*1000\n", + "gap_16 = df_gap22_dc_16['simSeconds'].astype(float)*1000\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "\n", + "plt.ylim([0,1.7])\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*5, gap_1[i]/gap_1[i], width=1, color=cmap(1), label='1' if i==0 else None)\n", + " plt.bar(i*5+1, gap_2[i]/gap_1[i], width=1, color=cmap(2), label='2' if i==0 else None)\n", + " plt.bar(i*5+2, gap_8[i]/gap_1[i], width=1, color=cmap(3), label='8' if i==0 else None)\n", + " plt.bar(i*5+3, gap_16[i]/gap_1[i], width=1, color=cmap(4), label='16' if i==0 else None)\n", + "\n", + "offset = i*6-1\n", + "app_npb = df_npbC_dc_1['app']\n", + "npb_1 = df_npbC_dc_1['simSeconds'].astype(float)*1000\n", + "npb_2 = df_npbC_dc_2['simSeconds'].astype(float)*1000\n", + "npb_8 = df_npbC_dc_8['simSeconds'].astype(float)*1000\n", + "npb_16 = df_npbC_dc_16['simSeconds'].astype(float)*1000\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*5+1, npb_1[i]/npb_1[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*5+2, npb_2[i]/npb_1[i], width=1, color=cmap(2))\n", + " plt.bar(offset+i*5+3, npb_8[i]/npb_1[i], width=1, color=cmap(3))\n", + " plt.bar(offset+i*5+4, npb_16[i]/npb_1[i], width=1, color=cmap(4))\n", + "\n", + "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, 0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*5+1.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "plt.axhline(y=1)\n", + "\n", + "plt.ylabel(\"Relative to Dir-Map Execution Time (ms)\", fontsize=8)\n", + "plt.legend(fontsize=8, ncol=2)\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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3rC3t8fy5ctx//596T5LS0sAry5/6t27N6ZOnQo/Pz9kZWUBALS1tTmAm4hqtBYtWmDo0KFYs2ZNpe/75MkTZGVlQQiBW7duYcaMGTA3N0e7du3KvM+0adNw6NAh+Pj4YMGCBWjfvr30fLx06VJs2bKF081S9VPxrFREVAV3794VQUFBokGDBkJLS0sYGhqKVq1aia+//lo8fvxYmJmZiWXLlpV636VLl4p69eqJ/Pz8Uqeb/TcA0i+JRCKsrKzERx99JFJTU4UQQrx48UJ88cUX4r333hO1a9cW+vr6wsXFRcyaNUs6ZW1pwsPDix37za/XRo4cWer+Tp06VfpnRkRUnUaOHCn69etXbFtaWprQ1tYud7rZf7O3ty92vjM3Nxc9e/YUCQkJFWZ48eKFWLx4sWjRooXQ1dUVpqamwsvLS0RERIiCggI5nh2RbCRCcLQPERERERHJh7NCERERERGR3FhYEBERERGR3FhYEBERERGR3FhYEBERERGR3FhYEBERERGR3FhYEBERERGR3FhYEBERERGR3FhYEBERERGR3FhYEBERERGR3FhYEBERERGR3FhYEBERERGR3FhYEBERERGR3P4/AQ8cUghOIeAAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_dc_1['app']\n", + "gap_1 = 100 * df_gap22_dc_1['numTotMisses'].astype(float) / (df_gap22_dc_1['numTotMisses'].astype(float)+df_gap22_dc_1['numTotHits'].astype(float))\n", + "gap_2 = 100 * df_gap22_dc_2['numTotMisses'].astype(float) / (df_gap22_dc_2['numTotMisses'].astype(float)+df_gap22_dc_2['numTotHits'].astype(float))\n", + "gap_8 = 100 * df_gap22_dc_8['numTotMisses'].astype(float) / (df_gap22_dc_8['numTotMisses'].astype(float)+df_gap22_dc_8['numTotHits'].astype(float))\n", + "gap_16 = 100 * df_gap22_dc_16['numTotMisses'].astype(float) / (df_gap22_dc_16['numTotMisses'].astype(float)+df_gap22_dc_16['numTotHits'].astype(float))\n", + "\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "\n", + "plt.ylim([0,110])\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*5, gap_1[i], width=1, color=cmap(1), label='1' if i==0 else None)\n", + " plt.bar(i*5+1, gap_2[i], width=1, color=cmap(2), label='2' if i==0 else None)\n", + " plt.bar(i*5+2, gap_8[i], width=1, color=cmap(3), label='8' if i==0 else None)\n", + " plt.bar(i*5+3, gap_16[i], width=1, color=cmap(4), label='16' if i==0 else None)\n", + "\n", + "offset = i*6-1\n", + "app_npb = df_npbC_dc_1['app']\n", + "npb_1 = 100 * df_npbC_dc_1['numTotMisses'].astype(float) / (df_npbC_dc_1['numTotMisses'].astype(float)+df_npbC_dc_1['numTotHits'].astype(float))\n", + "npb_2 = 100 * df_npbC_dc_2['numTotMisses'].astype(float) / (df_npbC_dc_2['numTotMisses'].astype(float)+df_npbC_dc_2['numTotHits'].astype(float))\n", + "npb_8 = 100 * df_npbC_dc_8['numTotMisses'].astype(float) / (df_npbC_dc_8['numTotMisses'].astype(float)+df_npbC_dc_8['numTotHits'].astype(float))\n", + "npb_16 = 100 * df_npbC_dc_16['numTotMisses'].astype(float) / (df_npbC_dc_16['numTotMisses'].astype(float)+df_npbC_dc_16['numTotHits'].astype(float))\n", + "\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*5+1, npb_1[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*5+2, npb_2[i], width=1, color=cmap(2))\n", + " plt.bar(offset+i*5+3, npb_8[i], width=1, color=cmap(3))\n", + " plt.bar(offset+i*5+4, npb_16[i], width=1, color=cmap(4))\n", + "\n", + "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, 0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*5+1.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "\n", + "plt.ylabel(\"Miss Ratio (%)\")\n", + "plt.legend(fontsize=8, ncol=2)\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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IiLSPkobY1ERnTp1QqdOncrcJ4TA0qVL8dVXX6FHjx4AgE2bNsHGxga7du1Cv379qjIqERERERG9htzTzerq6sr1T1nS0tKQmZmJgIAA2TZzc3N88MEHSEhIKPd++fn5yMnJKfGPiIiIiIhUS+4eCyEEnJycEBwcDG9vb1VmAgBkZmYCQKlF92xsbGT7yjJv3jzMmDFDpdmIiIiIiKgkuQuLEydOYP369Vi2bBmcnZ3xySefYODAgahevboq8yksPDwcoaGhsts5OTlwcHBQYyIiIiIioref3IWFj48PfHx8EBERge3btyMqKgpTpkxBt27dMHz4cLRv316pwWxtbQEA9+7dg52dnWz7vXv34OXlVe79DAwMYGBgoNQspAbTy5/SuGQ7odocRERERCQXhQdvGxoaYtCgQRg0aBDS0tIwfPhwdOzYEffv34elpaXSgjk7O8PW1haxsbGyQiInJwfHjx/H6NGjlfY4VLXW9vhernajVH+1HREREREpUYVmhbp9+zaio6MRHR2NJ0+eYPLkyZBKpQofJzc3F1evXpXdTktLQ1JSEiwtLeHo6IgJEyZg9uzZcHV1lU03W6tWrRJrXRARERERkfrJXVgUFBRg586dWL9+PeLj49GpUycsXboUnTp1qvBsUKdOnULbtm1lt1+OjQgODkZ0dDTCwsKQl5eHkSNHIisrCy1btsS+ffu4hgURERERkYaRu7Cws7ODmZkZgoODsXr1atSsWRPAi0XuXqVIz0WbNm0gRPnXyEskEsycORMzZ86U+5hERERERFT15C4sHj16hEePHmHWrFmYPXt2qf1CCEgkEhQVFSk1IBERERERaT65C4uDBw+qMgcREREREWkxuQsLf39/VeYgIiIiIiItpqPuAEREREREpP1YWBARERERUaWxsCAiIiIiokpjYUFERERERJXGwoKIiIiIiCpNrlmhevfuLfcBY2JiKhyGiIiIiIi0k1yFhbm5uez/Qgjs3LkT5ubm8PHxAQCcPn0aWVlZChUg9PbpvqvLG9t0Qf8qSEJEREREVU2uwiIqKkr2/ylTpuDjjz/GmjVroKurCwAoKirC559/DqlUqpqURERERESk0RQeY7FhwwZ88cUXsqICAHR1dREaGooNGzYoNRwREREREWkHuVfefun58+dITk6Gm5tbie3JyckoLi5WWjAiIiIC1vb4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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app_gap = df_gap22_dc_1['app']\n", + "gap_1 = 100 * df_gap22_dc_1['numColdMisses'].astype(float) / (df_gap22_dc_1['numTotMisses'].astype(float)+df_gap22_dc_1['numTotHits'].astype(float))\n", + "gap_2 = 100 * df_gap22_dc_2['numColdMisses'].astype(float) / (df_gap22_dc_2['numTotMisses'].astype(float)+df_gap22_dc_2['numTotHits'].astype(float))\n", + "gap_8 = 100 * df_gap22_dc_8['numColdMisses'].astype(float) / (df_gap22_dc_8['numTotMisses'].astype(float)+df_gap22_dc_8['numTotHits'].astype(float))\n", + "gap_16 = 100 * df_gap22_dc_16['numColdMisses'].astype(float) / (df_gap22_dc_16['numTotMisses'].astype(float)+df_gap22_dc_16['numTotHits'].astype(float))\n", + "\n", + "\n", + "# Multi bar Chart\n", + "fig = plt.figure()\n", + "fig.set_size_inches(8,2)\n", + "\n", + "plt.ylim([0,30])\n", + "for i,app in enumerate(app_gap):\n", + " plt.bar(i*5, gap_1[i], width=1, color=cmap(1), label='1' if i==0 else None)\n", + " plt.bar(i*5+1, gap_2[i], width=1, color=cmap(2), label='2' if i==0 else None)\n", + " plt.bar(i*5+2, gap_8[i], width=1, color=cmap(3), label='8' if i==0 else None)\n", + " plt.bar(i*5+3, gap_16[i], width=1, color=cmap(4), label='16' if i==0 else None)\n", + "\n", + "offset = i*6-1\n", + "app_npb = df_npbC_dc_1['app']\n", + "npb_1 = 100 * df_npbC_dc_1['numColdMisses'].astype(float) / (df_npbC_dc_1['numTotMisses'].astype(float)+df_npbC_dc_1['numTotHits'].astype(float))\n", + "npb_2 = 100 * df_npbC_dc_2['numColdMisses'].astype(float) / (df_npbC_dc_2['numTotMisses'].astype(float)+df_npbC_dc_2['numTotHits'].astype(float))\n", + "npb_8 = 100 * df_npbC_dc_8['numColdMisses'].astype(float) / (df_npbC_dc_8['numTotMisses'].astype(float)+df_npbC_dc_8['numTotHits'].astype(float))\n", + "npb_16 = 100 * df_npbC_dc_16['numColdMisses'].astype(float) / (df_npbC_dc_16['numTotMisses'].astype(float)+df_npbC_dc_16['numTotHits'].astype(float))\n", + "\n", + "for i,app in enumerate(app_npb): \n", + " plt.bar(offset+i*5+1, npb_1[i], width=1, color=cmap(1))\n", + " plt.bar(offset+i*5+2, npb_2[i], width=1, color=cmap(2))\n", + " plt.bar(offset+i*5+3, npb_8[i], width=1, color=cmap(3))\n", + " plt.bar(offset+i*5+4, npb_16[i], width=1, color=cmap(4))\n", + "\n", + "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", + "plt.figtext(0.75, 0.01, \"NPB-C\")\n", + "\n", + "plt.xticks(np.arange(14)*5+1.5, list(app_gap)+list(app_npb))\n", + "plt.axvline(x=offset, color='black')\n", + "\n", + "plt.ylabel(\"Cold Miss Ratio (%)\")\n", + "plt.legend(fontsize=8, ncol=2)\n", + "plt.tight_layout()\n", + "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/src/cpu/kvm/vm.cc b/src/cpu/kvm/vm.cc index e714a40b22..6c73ef4f23 100644 --- a/src/cpu/kvm/vm.cc +++ b/src/cpu/kvm/vm.cc @@ -467,10 +467,11 @@ KvmVM::setUserMemoryRegion(uint32_t slot, m.userspace_addr = (__u64)host_addr; if (ioctl(KVM_SET_USER_MEMORY_REGION, (void *)&m) == -1) { + perror("Error!"); panic("Failed to setup KVM memory region:\n" - "\tHost Address: 0x%p\n" - "\tGuest Address: 0x%llx\n", - "\tSize: %ll\n", + "\tHost Address: 0x%llx\n" + "\tGuest Address: 0x%llx\n" + "\tSize: %llu\n" "\tFlags: 0x%x\n", m.userspace_addr, m.guest_phys_addr, m.memory_size, m.flags); diff --git a/src/cpu/o3/probe/O3LooppointAnalysis.py b/src/cpu/o3/probe/O3LooppointAnalysis.py new file mode 100644 index 0000000000..949fe0b0db --- /dev/null +++ b/src/cpu/o3/probe/O3LooppointAnalysis.py @@ -0,0 +1,28 @@ +from m5.params import * +from m5.objects.Probe import ProbeListenerObject +from m5.objects import SimObject +from m5.util.pybind import * + +class O3LooppointAnalysis(ProbeListenerObject): + + type = "O3LooppointAnalysis" + cxx_header = "cpu/o3/probe/o3looppoint_analysis.hh" + cxx_class = "gem5::o3::O3LooppointAnalysis" + + ptmanager = Param.O3LooppointAnalysisManager("the PcCountAnalsi manager") + validAddrRangeStart = Param.Addr(0, "the starting address of the valid " + "insturction address range") + validAddrRangeSize = Param.Addr(0, "the size of the valid address range") + +class O3LooppointAnalysisManager(SimObject): + + type = "O3LooppointAnalysisManager" + cxx_header = "cpu/o3/probe/o3looppoint_analysis.hh" + cxx_class = "gem5::o3::O3LooppointAnalysisManager" + + cxx_exports = [ + PyBindMethod("getCounter"), + PyBindMethod("getPcCount"), + PyBindMethod("getMostRecentPc"), + PyBindMethod("getCurrentPc") + ] diff --git a/src/cpu/o3/probe/SConscript b/src/cpu/o3/probe/SConscript index 6039ef2eb9..94fc552a10 100644 --- a/src/cpu/o3/probe/SConscript +++ b/src/cpu/o3/probe/SConscript @@ -45,3 +45,8 @@ if not env['CONF']['USE_NULL_ISA']: SimObject('ElasticTrace.py', sim_objects=['ElasticTrace'], tags='protobuf') Source('elastic_trace.cc', tags='protobuf') DebugFlag('ElasticTrace', tags='protobuf') + + SimObject('O3LooppointAnalysis.py', sim_objects=['O3LooppointAnalysis','O3LooppointAnalysisManager']) + Source('o3looppoint_analysis.cc') + + DebugFlag("O3LooppointAnalysis") \ No newline at end of file diff --git a/src/cpu/o3/probe/o3looppoint_analysis.cc b/src/cpu/o3/probe/o3looppoint_analysis.cc new file mode 100644 index 0000000000..16111dc99a --- /dev/null +++ b/src/cpu/o3/probe/o3looppoint_analysis.cc @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2023 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpu/o3/probe/o3looppoint_analysis.hh" +#include "cpu/o3/dyn_inst.hh" + + +namespace gem5 +{ + +namespace o3 +{ + +O3LooppointAnalysis::O3LooppointAnalysis(const O3LooppointAnalysisParams &p) + : ProbeListenerObject(p), + manager(p.ptmanager), + validAddrLowerBound(p.validAddrRangeStart), + validAddrUpperBound(p.validAddrRangeStart+p.validAddrRangeSize) +{ + DPRINTF(O3LooppointAnalysis, "the valid address range start from %i to " + " %i \n", validAddrLowerBound, validAddrUpperBound); +} + +/** + * ProbeListenerArg generates a listener for the class of Arg and the + * class type T which is the class containing the function that notify will + * call. + * + * Note that the function is passed as a pointer on construction. + */ + +void +O3LooppointAnalysis::regProbeListeners() +{ + // connect the probe listener with the probe "RetriedInstsPC" in the + // corresponding core. + // when "RetiredInstsPC" notifies the probe listener, then the function + // 'check_pc' is automatically called + typedef ProbeListenerArg + O3LooppointAnalysisListener; + listeners.push_back(new O3LooppointAnalysisListener(this, "Commit", + &O3LooppointAnalysis::checkPc)); +} + +void +O3LooppointAnalysis::checkPc(const DynInstConstPtr& dynInst) { + + auto &pcstate = dynInst->pcState().as(); + if (dynInst->staticInst->isMicroop() && !dynInst->staticInst->isLastMicroop()) + return; + if(validAddrUpperBound!=0) { + if(pcstate.pc() < validAddrLowerBound || pcstate.pc() > validAddrUpperBound) + return; + } + if (dynInst->staticInst->isControl() && dynInst->staticInst->isDirectCtrl() && dynInst->tcBase()->getIsaPtr()->inUserMode()) { + if(pcstate.npc() < pcstate.pc()) + manager->countPc(pcstate.npc()); + } +} + +O3LooppointAnalysisManager::O3LooppointAnalysisManager(const O3LooppointAnalysisManagerParams &p) + : SimObject(p), + currentPc(0) +{ + +} + +void +O3LooppointAnalysisManager::countPc(const Addr pc) +{ + if (counter.find(pc) == counter.end()){ + counter.insert(std::make_pair(pc,std::make_pair(Addr(0), curTick()))); + } + else{ + ++counter.find(pc)->second.first; + // update the tick when this pc is last accessed + counter.find(pc)->second.second = curTick(); + } + currentPc = pc; + auto it = std::find_if(mostRecentPc.begin(), mostRecentPc.end(), + [&pc](const std::pair& p) { return p.first == pc; }); + if (it == mostRecentPc.end()) { + // If pc is not in the list, then add it to the front of the list + while (mostRecentPc.size() >= 5) { + mostRecentPc.pop_back(); + } + mostRecentPc.push_front(std::make_pair(pc,curTick())); + } else { + if (it != mostRecentPc.begin()) { + // If pc is in the list, but not at the front, then move it to the + // front of the list + mostRecentPc.push_front(*it); + mostRecentPc.erase(it); + } + it->second = curTick(); + } +} + +} // namespace o3 +} // namespace gem5 diff --git a/src/cpu/o3/probe/o3looppoint_analysis.hh b/src/cpu/o3/probe/o3looppoint_analysis.hh new file mode 100644 index 0000000000..94d323e378 --- /dev/null +++ b/src/cpu/o3/probe/o3looppoint_analysis.hh @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2023 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPU_SIMPLE_PROBES_O3LOOPPOINT_ANALYSIS_HH__ +#define __CPU_SIMPLE_PROBES_O3LOOPPOINT_ANALYSIS_HH__ + +#include +#include + +#include "params/O3LooppointAnalysis.hh" +#include "params/O3LooppointAnalysisManager.hh" +#include "sim/probe/probe.hh" +#include "cpu/simple_thread.hh" +#include "arch/generic/pcstate.hh" +#include "cpu/probes/pc_count_pair.hh" +#include "debug/O3LooppointAnalysis.hh" +#include "cpu/o3/dyn_inst_ptr.hh" + +namespace gem5 +{ + +namespace o3 +{ +class O3LooppointAnalysis : public ProbeListenerObject +{ + public: + O3LooppointAnalysis(const O3LooppointAnalysisParams ¶ms); + + virtual void regProbeListeners(); + + void checkPc(const DynInstConstPtr& dynInst); + + private: + + O3LooppointAnalysisManager *manager; + Addr validAddrLowerBound; + Addr validAddrUpperBound; +}; + +class O3LooppointAnalysisManager : public SimObject +{ + public: + O3LooppointAnalysisManager(const O3LooppointAnalysisManagerParams ¶ms); + void countPc(Addr pc); + + private: + /** + * a set of Program Counter addresses that should notify the + * PcCounterTrackerManager for + * counter maps addresses to a pair of + * counter and the last tick the address was accessed + */ + std::map> counter; + std::list> mostRecentPc; + Addr currentPc; + + + public: + std::map> + getCounter() const + { + return counter; + } + + // returns a pair of the count and last tick + // the count was incremented + std::pair + getPcCount(Addr pc) const + { + if(counter.find(pc) != counter.end()) { + return counter.find(pc)->second; + } + return std::make_pair(-1, -1); + } + + // returns a vector of the most recently + // accessed PCs + std::vector> + getMostRecentPc() const + { + std::vector> recent_pcs; + for (auto it = mostRecentPc.begin(); it != mostRecentPc.end(); it++) { + recent_pcs.push_back(*it); + } + return recent_pcs; + } + + Addr + getCurrentPc() const + { + return currentPc; + } + +}; + + + +} // namespace o3 +} // namespace gem5 + +#endif // __CPU_SIMPLE_PROBES_O3LOOPPOINT_ANALYSIS_HH__ diff --git a/src/cpu/probes/pc_count_pair.hh b/src/cpu/probes/pc_count_pair.hh index fd6bc639fe..3d25b852b5 100644 --- a/src/cpu/probes/pc_count_pair.hh +++ b/src/cpu/probes/pc_count_pair.hh @@ -86,9 +86,9 @@ class PcCountPair { size_t operator()(const PcCountPair& item) const { - size_t xHash = std::hash()(item.pc); + size_t xHash = std::hash()(item.pc); size_t yHash = std::hash()(item.count); - return xHash * 2 + yHash; + return xHash ^ yHash << 32; } }; diff --git a/src/cpu/testers/dr_trace_player/DRTracePlayer.py b/src/cpu/testers/dr_trace_player/DRTracePlayer.py new file mode 100644 index 0000000000..fcc014be40 --- /dev/null +++ b/src/cpu/testers/dr_trace_player/DRTracePlayer.py @@ -0,0 +1,106 @@ +# Copyright (c) 2022 The Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +from m5.params import * +from m5.proxy import * + +from m5.objects.ClockedObject import ClockedObject +from m5.objects.SimObject import SimObject + + +class DRTraceReader(SimObject): + """This is a trace reader which is shared between possibly many different + trace players. + """ + + type = "DRTraceReader" + cxx_class = "gem5::DRTraceReader" + cxx_header = "cpu/testers/dr_trace_player/trace_reader.hh" + + directory = Param.String("Directory which contains the memtrace files") + + num_players = Param.Int("Total number of players connected to this reader") + + # Since this is the thing which sees the timestamps, this is what will do + # the "context switches." So, if we want to add different context switch + # options, this is the place. + + +class DRTracePlayer(ClockedObject): + """This is a trace player object. One of these represents a "core." + + You can limit the amount of ILP by using the `max_ipc` and/or the + `max_outstanding_reqs` parameters. If these are set to 0, then there is no + limit. + + This model assumes that instructions are executed in order, except for + memory instructions. I.e., instructions are executed sequentially, the + memory instructions are sent to memory sequentially, but other + instructions can execute (including memory instructions) while prior + instructions are waiting for memory. + + When used with caches, `send_data` should be true. + + The addresses are virtual-ish addresses in the trace. Currently, there is + no address translation. Instead, if the backing address space (i.e., main + memory) has a limited range you should set the `compress_address_range` to + be the backing memory's address range. + You can set memory range to be much larger when using `is_null=True` on + the abstract memory. + """ + + type = "DRTracePlayer" + cxx_class = "gem5::DRTracePlayer" + cxx_header = "cpu/testers/dr_trace_player/trace_player.hh" + + # Port used for sending requests and receiving responses + port = RequestPort("This port sends requests and receives responses") + + # System used to determine the mode of the memory system + system = Param.System(Parent.any, "System this generator is part of") + + reader = Param.DRTraceReader("The reader for this player") + + max_ipc = Param.Int( + 1, + "Max number of instructions per cycle. Zero means no limit.", + ) + + max_outstanding_reqs = Param.Int( + 16, + "Max number of memory instructions outstanding. Zero means no limit.", + ) + + send_data = Param.Bool( + False, + "If true, this player will send dummy data on writes and make space " + "for reads. If false, system.memory.null should be true.", + ) + + compress_address_range = Param.AddrRange( + 0, "Compress the addresses into the given range if valid." + ) diff --git a/src/cpu/testers/dr_trace_player/SConscript b/src/cpu/testers/dr_trace_player/SConscript new file mode 100644 index 0000000000..2881fba8b8 --- /dev/null +++ b/src/cpu/testers/dr_trace_player/SConscript @@ -0,0 +1,35 @@ +# Copyright (c) 2022 The Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +Import("*") + +SimObject("DRTracePlayer.py", sim_objects=["DRTracePlayer", "DRTraceReader"]) + +Source("trace_player.cc") +Source("trace_reader.cc") + +DebugFlag("DRTrace") diff --git a/src/cpu/testers/dr_trace_player/trace_player.cc b/src/cpu/testers/dr_trace_player/trace_player.cc new file mode 100644 index 0000000000..4ee814f94f --- /dev/null +++ b/src/cpu/testers/dr_trace_player/trace_player.cc @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2022 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpu/testers/dr_trace_player/trace_player.hh" + +#include "base/trace.hh" +#include "debug/DRTrace.hh" +#include "sim/sim_exit.hh" +#include "sim/system.hh" + +namespace gem5 +{ + +DRTracePlayer::DRTracePlayer(const Params ¶ms) : + ClockedObject(params), + executeNextInstEvent([this]{ executeNextInst(); }, + name()+".exec_next_event"), + retryExecuteInstEvent([this]{ retryExecuteInst(); }, + name()+".retry_exec_event"), + reader(params.reader), + playerId(0), + requestorId(params.system->getRequestorId(this)), + maxOutstandingMemReqs(params.max_outstanding_reqs), + maxInstsPerCycle(params.max_ipc), + compressAddressRange(params.compress_address_range), + cacheLineSize(params.system->cacheLineSize()), + port(name() + ".port", *this), + stats(this) +{ + +} + +void +DRTracePlayer::startup() +{ + // Get the first instruction and schedule it to be run in the first cycle + schedule(executeNextInstEvent, 0); +} + +void +DRTracePlayer::executeNextInst() +{ + assert(!stalled); + nextRef = reader->getNextTraceReference(playerId); + tryExecuteInst(nextRef); +} + +void +DRTracePlayer::retryExecuteInst() +{ + assert(stalled); + stalled = false; + tryExecuteInst(nextRef); +} + +void +DRTracePlayer::tryExecuteInst(DRTraceReader::TraceRef &cur_ref) +{ + assert(!stalled); + if (!cur_ref.isValid) { + // End of trace for this player exit the simulation + // TODO: Move this to when the last instruction is completed + exitSimLoopNow("End of DRTrace"); + } + + DPRINTF(DRTrace, "Exec reference pc: %0#x, addr: %0#x, size: %d, " + "%s, type: %d, valid: %d\n", cur_ref.pc, cur_ref.addr, + cur_ref.size, cur_ref.isMemRef() ? "memory" : "other", + cur_ref.type, cur_ref.isValid); + + stalled = executeGenericInst(cur_ref); + if (stalled) { + return; // Note: executeGenericInst scheduled the event + } + + if (cur_ref.isMemRef()) { + stalled = executeMemInst(cur_ref); + if (stalled) { + return; // Note: recvRetry will schedule the retry event + } + } + + // If we got here, then we know there are more instructions to execute + // this cycle + assert(!executeNextInstEvent.scheduled()); + assert(!retryExecuteInstEvent.scheduled()); + schedule(executeNextInstEvent, curTick()); +} + +void +DRTracePlayer::scheduleInstRetry() +{ + assert(!executeNextInstEvent.scheduled()); + if (!retryExecuteInstEvent.scheduled()) { + schedule(retryExecuteInstEvent, nextCycle()); + numExecutingInsts = 0; + } else { + assert(numExecutingInsts == 0); + } +} + +bool +DRTracePlayer::executeGenericInst(DRTraceReader::TraceRef &cur_inst) +{ + if (maxInstsPerCycle && (numExecutingInsts++ > maxInstsPerCycle)) { + DPRINTF(DRTrace, "Stalling for instruction limit\n"); + scheduleInstRetry(); + return true; // Stall for a cycle + } + + if (cur_inst.isInstRef()) { + assert(cur_inst.pc != 0); + curPC = cur_inst.pc; + stats.numInsts++; + } + + return false; +} + +bool +DRTracePlayer::executeMemInst(DRTraceReader::TraceRef &mem_ref) +{ + assert(mem_ref.addr != 0); + + if (maxOutstandingMemReqs && + (numOutstandingMemReqs + 1 > maxOutstandingMemReqs)) { + DPRINTF(DRTrace, "Stalling for outstanding memory limit\n"); + stats.memStalls++; + return true; // Will be unstalled in recvResponse + } + + if (!trySendMemRef(mem_ref)) { + stats.numMemInsts++; + return false; + } else { + return true; + } +} + +bool +DRTracePlayer::trySendMemRef(DRTraceReader::TraceRef &mem_ref) +{ + // split_pkt will be nullptr if not a split req + auto [pkt, split_pkt] = getPacket(mem_ref); + + // ensure that currently we are not in process of + // retrying to send the second part of a previously + // stalled request to avoid duplicate first pkt in + // the memory system. + // Also, the assumption is that we cannot start a + // new memory request in parallel. + if (!retrySplitPkt) { + DPRINTF(DRTrace, "Trying to send %s\n", pkt->print()); + + if (!port.sendTimingReq(pkt)) { + DPRINTF(DRTrace, "Failed to send pkt\n"); + if (stats.memStallStart == 0) { + stats.memStallStart = curTick(); + } + delete pkt; + delete split_pkt; + + // return true if we have to stall on the first pkt + // irrespective of if this is a split req + return true; + } else { + numOutstandingMemReqs++; + stats.outstandingMemReqs.sample(numOutstandingMemReqs); + stats.latencyTracker[pkt] = curTick(); + if (split_pkt == nullptr) { + // if this is not a split req, we can + // return here + return false; + } + } + } else { + // we should delete the first pkt here + // if we are only trying to resend the + // second pkt + delete pkt; + } + + DPRINTF(DRTrace, "Trying to send split %s\n", split_pkt->print()); + + // if the first pkt is sent out, and the current + // request is a split request, try to send out + // the second pkt + if (!port.sendTimingReq(split_pkt)) { + DPRINTF(DRTrace, "Failed to send pkt (split pkt) \n"); + if (stats.memStallStart == 0) { + stats.memStallStart = curTick(); + } + delete split_pkt; + // also remember that we only need to retry on second part of + // the split pkt + retrySplitPkt = true; + return true; + } else { + numOutstandingMemReqs++; + stats.outstandingMemReqs.sample(numOutstandingMemReqs); + stats.latencyTracker[split_pkt] = curTick(); + retrySplitPkt = false; + // At this point, we are sure that both pkts of the split req + // are received by the port + return false; + } +} + +std::tuple +DRTracePlayer::getPacket(DRTraceReader::TraceRef &mem_ref) +{ + Request::Flags flags = Request::PHYSICAL; + if (mem_ref.type == DRTraceReader::TraceRef::PREFETCH) { + flags = flags | Request::PREFETCH; + } + + Addr addr = mem_ref.addr; + if (compressAddressRange.size()) { + addr -= compressAddressRange.start(); + addr %= compressAddressRange.size(); + } + + bool split_req = false; + unsigned size = mem_ref.size; + Addr split_addr = roundDown(addr + size - 1, cacheLineSize); + if (split_addr > addr) { + DPRINTF(DRTrace, "Split pkt (crosses cache line boundary) created\n"); + size = split_addr - addr; + split_req = true; + } + + // Create new request + RequestPtr req = std::make_shared(addr, size, flags, + requestorId); + req->setPC(curPC); + + MemCmd cmd; + if (mem_ref.type == DRTraceReader::TraceRef::READ || + mem_ref.type == DRTraceReader::TraceRef::PREFETCH) { + cmd = MemCmd::ReadReq; + } else { + assert(mem_ref.type == DRTraceReader::TraceRef::WRITE); + cmd = MemCmd::WriteReq; + } + // Embed it in a packet + PacketPtr pkt = new Packet(req, cmd); + + if (params().send_data) { + uint8_t* pkt_data = new uint8_t[req->getSize()]; + pkt->dataDynamic(pkt_data); + + if (cmd.isWrite()) { + std::fill_n(pkt_data, req->getSize(), (uint8_t)requestorId); + } + } + + PacketPtr split_pkt = nullptr; + + // In case of split packets when we want to send two requests. + // For the second request, the starting address + // will be split_addr and the size will be cacheLineSize - size + + if (split_req) { + + // Create the split request + RequestPtr split_req = std::make_shared(split_addr, + cacheLineSize - size, flags, requestorId); + split_req->setPC(curPC); + + // Embed it in a packet + split_pkt = new Packet(split_req, cmd); + + if (params().send_data) { + uint8_t* split_pkt_data = new uint8_t[split_req->getSize()]; + split_pkt->dataDynamic(split_pkt_data); + + if (cmd.isWrite()) { + std::fill_n(split_pkt_data, split_req->getSize(), + (uint8_t)requestorId); + } + } + } + + return {pkt, split_pkt}; +} + +Port & +DRTracePlayer::getPort(const std::string &if_name, PortID idx) +{ + if (if_name == "port") { + return port; + } else { + return ClockedObject::getPort(if_name, idx); + } +} + +void +DRTracePlayer::recvReqRetry() +{ + DPRINTF(DRTrace, "Received retry request\n"); + assert(stalled); + + stats.memStalledTime.sample(curTick() - stats.memStallStart); + stats.memStallStart = 0; + + scheduleInstRetry(); +} + +bool +DRTracePlayer::recvTimingResp(PacketPtr pkt) +{ + DPRINTF(DRTrace, "Received response for %s\n", pkt->print()); + numOutstandingMemReqs--; + + stats.memLatency.sample(curTick() - stats.latencyTracker[pkt]); + stats.latencyTracker.erase(pkt); + + delete pkt; + + if (stalled) { + scheduleInstRetry(); + } + + return true; +} + +DRTracePlayer::Stats::Stats(statistics::Group *parent) : + statistics::Group(parent), + ADD_STAT(numInsts, statistics::units::Count::get(), + "Number of instructions executed (not counting memory)"), + ADD_STAT(numMemInsts, statistics::units::Count::get(), + "Number of memory instructions executed"), + ADD_STAT(memStalledTime, statistics::units::Tick::get(), + "Total time stalled for memory each time stalled"), + ADD_STAT(memLatency, statistics::units::Tick::get(), + "Latency for each memory access"), + ADD_STAT(memStalls, statistics::units::Count::get(), + "Number of times stalled for outstanding memory limit"), + ADD_STAT(instStalls, statistics::units::Count::get(), + "Number of times stalled for IPC limit"), + ADD_STAT(outstandingMemReqs, statistics::units::Count::get(), + "Number of outstanding requests for each new request") +{ + memStalledTime + .init(16) + .flags(statistics::pdf | statistics::dist); + memLatency + .init(16) + .flags(statistics::pdf | statistics::dist); + outstandingMemReqs + .init(16) + .flags(statistics::pdf | statistics::dist); +} + +} // namespace gem5 diff --git a/src/cpu/testers/dr_trace_player/trace_player.hh b/src/cpu/testers/dr_trace_player/trace_player.hh new file mode 100644 index 0000000000..8f614054b6 --- /dev/null +++ b/src/cpu/testers/dr_trace_player/trace_player.hh @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2022 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef __CPU_TESTERS_DR_TRACE_PLAYER_TRACE_PLAYER_HH__ +#define __CPU_TESTERS_DR_TRACE_PLAYER_TRACE_PLAYER_HH__ + +/** + * @file + * Contains the player for dynamario traces + * This object works with the trace reader to play dynamorio traces + */ + +#include + +#include "base/addr_range.hh" +#include "cpu/testers/dr_trace_player/trace_reader.hh" +#include "mem/port.hh" +#include "params/DRTracePlayer.hh" +#include "sim/clocked_object.hh" + +namespace gem5 +{ + +/** + * An object to play dynamorio traces. + * This object represents on "core." The core can execute instructions from + * multiple different threads. The trace reader acts as the scheduler and + * chooses which cores will execute which thread and when. + * The cores (players) must request the next item from the centralized trace + * reader. + */ +class DRTracePlayer : public ClockedObject +{ + private: + // Events + EventFunctionWrapper executeNextInstEvent; + EventFunctionWrapper retryExecuteInstEvent; + + // Parameters + DRTraceReader *reader; + int playerId; + int requestorId; + int maxOutstandingMemReqs; + int maxInstsPerCycle; + AddrRange compressAddressRange; + int cacheLineSize; + + // variable to keep track of retries for split pkts + bool retrySplitPkt = false; + + // State + bool stalled = false; + Addr curPC = 0; + DRTraceReader::TraceRef nextRef; + int numExecutingInsts = 0; + int numOutstandingMemReqs = 0; + + /** + * @brief Take the current reference in nextRef and try to execute it. + * + * The instruction may no be able to be executed (stalled), if so, this + * function will ensure the correct events will be scheduled. + * + * @param cur_ref the instruction to execute + */ + void tryExecuteInst(DRTraceReader::TraceRef &cur_ref); + + /** + * @brief Called from the similarly named event. + * + * Gets a new instruction and calls `tryExecuteInst` + */ + void executeNextInst(); + + /** + * @brief Like `executeNextInst`, but does not get a new instruction + */ + void retryExecuteInst(); + + /** + * @brief Helper function to schedule instruction retries + */ + void scheduleInstRetry(); + + /** + * @brief Do the timing execution for a generic instruction + * + * This should be called for *all* instructions that are executed. + * + * @param cur_inst The instruction to execute + * @return true if we should now stall (retry will be scheduled) + * @return false if we can execute more instructions this cycle + */ + bool executeGenericInst(DRTraceReader::TraceRef &cur_inst); + + /** + * @brief Do the timing execution for a memory instruction + * + * @param mem_ref The memory instruction to execute + * @return true if we should now stall (retry will be scheduled) + * @return false if we can execute more instructions this cycle + */ + bool executeMemInst(DRTraceReader::TraceRef &mem_ref); + + void recvReqRetry(); + + bool recvTimingResp(PacketPtr pkt); + + std::tuple + getPacket(DRTraceReader::TraceRef &mem_ref); + + /** + * @brief Send a request to memory based on the trace + * + * @param mem_ref + * @return true if the port is stalled + * @return false if the port accepted the packet + */ + bool trySendMemRef(DRTraceReader::TraceRef &mem_ref); + + public: + PARAMS(DRTracePlayer); + DRTracePlayer(const Params ¶ms); + + void startup() override; + + Port &getPort(const std::string &if_name, + PortID idx=InvalidPortID) override; + + private: + class DataPort : public RequestPort + { + public: + DataPort(const std::string &name, DRTracePlayer &player) : + RequestPort(name, &player), player(player) + { } + + protected: + void recvReqRetry() override { player.recvReqRetry(); } + + bool recvTimingResp(PacketPtr pkt) override + { return player.recvTimingResp(pkt); } + + void recvTimingSnoopReq(PacketPtr pkt) override { } + + void recvFunctionalSnoop(PacketPtr pkt) override { } + + Tick recvAtomicSnoop(PacketPtr pkt) override { return 0; } + + private: + DRTracePlayer &player; + }; + + DataPort port; + + struct Stats : public statistics::Group + { + Stats(statistics::Group *parent); + + statistics::Scalar numInsts; + statistics::Scalar numMemInsts; + + statistics::Histogram memStalledTime; + statistics::Histogram memLatency; + + statistics::Scalar memStalls; + statistics::Scalar instStalls; + + statistics::Histogram outstandingMemReqs; + + Tick memStallStart = 0; + std::map latencyTracker; + } stats; +}; + +} // namespace gem5 + +#endif //__CPU_TESTERS_DR_TRACE_PLAYER_TRACE_PLAYER_HH__ diff --git a/src/cpu/testers/dr_trace_player/trace_reader.cc b/src/cpu/testers/dr_trace_player/trace_reader.cc new file mode 100644 index 0000000000..afaa3950da --- /dev/null +++ b/src/cpu/testers/dr_trace_player/trace_reader.cc @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2022 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpu/testers/dr_trace_player/trace_reader.hh" + +#include +#include +#include +#include + +#include + +#include "base/trace.hh" +#include "debug/DRTrace.hh" + +namespace gem5 +{ + +DRTraceReader::DRTraceReader(const Params ¶ms) : + SimObject(params), + directory(params.directory) +{ + // Check to make sure the directory exists and has files in it named + // *.memtrace.gz + fatal_if(!is_directory(directory), "DRTraceReader requires the " + "directory parameter to point to valid directory. %s is not a" + "directory", directory.string().c_str()); + + for (auto const& dir_entry : + std::filesystem::directory_iterator{directory}) { + // get all files that end with ".memtrace.gz" + std::filesystem::path p(dir_entry); + if (p.extension().string() == std::string(".gz") && + p.stem().extension().string() == std::string(".memtrace")) { + filenames.emplace_back(p.string()); + } + } + + fatal_if(filenames.empty(), "Did not find any trace files in %s. Make sure" + " you pass a directory which has files *.memtrace.gz to " + "DRTraceReader.", directory.string().c_str()); + + DPRINTF(DRTrace, "Found %d trace files in %s\n", + filenames.size(), directory.string().c_str()); + + currentTids.resize(params.num_players, -1); +} + +// TODO: Close all files on exit + +void +DRTraceReader::init() +{ + // open the files + for (auto const &file : filenames) { + gzFile fdz = gzopen(file.c_str(), "rb"); + fatal_if(!fdz, "Could not open the file %s.", file); + traceFiles.push_back(fdz); + } + timestamps.resize(traceFiles.size(), 0); + + // Get the first timestamp in each file. + for (int i = 0; i < traceFiles.size(); i++) { + DRTraceEntry raw_entry = _getNextEntry(i); + while (raw_entry.size != TRACE_MARKER_TYPE_TIMESTAMP) { + // Keep getting entries until we get the first timestamp + raw_entry = _getNextEntry(i); + } + timestamps[i] = raw_entry.addr; // set the timestamp + } +} + +DRTraceReader::DRTraceEntry +DRTraceReader::_getNextEntry(unsigned int tid) +{ + panic_if(tid > traceFiles.size(), "tid (%d) out of range.", tid); + auto bytes = sizeof(DRTraceReader::DRTraceEntry); + DRTraceReader::DRTraceEntry entry{}; + auto bytes_read = gzread(traceFiles[tid], (void*)&entry, bytes); + assert(bytes_read == bytes); + return entry; +} + +DRTraceReader::TraceRef +DRTraceReader::getNextTraceReference(unsigned player_id) +{ + assert(player_id < currentTids.size()); + + TraceRef ref; + + int cur_tid = currentTids[player_id]; + if (cur_tid < 0) { + // Nothing executing on this player. See if there's something else + // to execute + unsigned int next_tid = getLowestTimestampThread(); + if (next_tid == std::numeric_limits::max()) { + // nothing else to do, return invalid reference + return ref; + } + currentTids[player_id] = next_tid; + return getNextTraceReference(player_id); + } + + DRTraceReader::DRTraceEntry raw_entry = _getNextEntry(cur_tid); + + switch (raw_entry.type) { + case TRACE_TYPE_MARKER: + if (raw_entry.size == TRACE_MARKER_TYPE_TIMESTAMP) { + uint64_t delta = raw_entry.addr - timestamps[cur_tid]; + // Switch??? + if (delta > 0) { + // for now, assert true as we shouldn't see the same + // timestamp twice. In the future, we want to make this + // delta check a parameter. + timestamps[cur_tid] = raw_entry.addr; + unsigned int next_tid = getLowestTimestampThread(); + if (next_tid == std::numeric_limits::max()) { + // nothing else to do + currentTids[player_id] = -1; + } else { + currentTids[player_id] = next_tid; + // Use this new TID to get the next instruction + return getNextTraceReference(player_id); + } + } + } else { + warn_once("Skipping unknown marker type: %d, value: %d.\n", + raw_entry.size, raw_entry.addr); + return getNextTraceReference(player_id); + } + break; + case TRACE_TYPE_READ: + ref.addr = raw_entry.addr; + ref.size = raw_entry.size; + ref.isValid = true; + ref.type = TraceRef::READ; + break; + case TRACE_TYPE_WRITE: + ref.addr = raw_entry.addr; + ref.size = raw_entry.size; + ref.isValid = true; + ref.type = TraceRef::WRITE; + break; + case TRACE_TYPE_PREFETCH: + case TRACE_TYPE_PREFETCH_READ_L1: + case TRACE_TYPE_PREFETCHT1: + case TRACE_TYPE_PREFETCHT2: + case TRACE_TYPE_PREFETCHNTA: + ref.addr = raw_entry.addr; + ref.size = raw_entry.size; + ref.isValid = true; + ref.type = TraceRef::PREFETCH; + break; + case TRACE_TYPE_INSTR: + case TRACE_TYPE_INSTR_SYSENTER: + case TRACE_TYPE_INSTR_NO_FETCH: + ref.pc = raw_entry.addr; + ref.size = raw_entry.size; + ref.isValid = true; + ref.type = TraceRef::GENERIC_INST; + break; + case TRACE_TYPE_INSTR_DIRECT_JUMP: + ref.pc = raw_entry.addr; + ref.size = raw_entry.size; + ref.isValid = true; + ref.type = TraceRef::DIRECT_JUMP; + break; + case TRACE_TYPE_INSTR_INDIRECT_JUMP: + ref.pc = raw_entry.addr; + ref.size = raw_entry.size; + ref.isValid = true; + ref.type = TraceRef::INDIRECT_JUMP; + break; + case TRACE_TYPE_INSTR_CONDITIONAL_JUMP: + ref.pc = raw_entry.addr; + ref.size = raw_entry.size; + ref.isValid = true; + ref.type = TraceRef::CONDITIONAL_JUMP; + break; + case TRACE_TYPE_INSTR_DIRECT_CALL: + ref.pc = raw_entry.addr; + ref.size = raw_entry.size; + ref.isValid = true; + ref.type = TraceRef::DIRECT_CALL; + break; + case TRACE_TYPE_INSTR_INDIRECT_CALL: + ref.pc = raw_entry.addr; + ref.size = raw_entry.size; + ref.isValid = true; + ref.type = TraceRef::INDIRECT_CALL; + break; + case TRACE_TYPE_INSTR_RETURN: + ref.pc = raw_entry.addr; + ref.size = raw_entry.size; + ref.isValid = true; + ref.type = TraceRef::RETURN; + break; + case TRACE_TYPE_HEADER: + DPRINTF(DRTrace, "Found header in trace. Version %d\n", + raw_entry.addr); + panic_if(raw_entry.addr != 3, + "DRTraceReader only works with version 3"); + return getNextTraceReference(player_id); + break; + case TRACE_TYPE_FOOTER: + case TRACE_TYPE_THREAD_EXIT: + DPRINTF(DRTrace, "Found footer or thread exit in trace\n"); + // TODO: Close the file + // Return an invalid reference since we're at the end + break; + case TRACE_TYPE_THREAD: + DPRINTF(DRTrace, "Found thread %d\n", raw_entry.addr); + return getNextTraceReference(player_id); + case TRACE_TYPE_PID: + DPRINTF(DRTrace, "Found pid %d\n", raw_entry.addr); + return getNextTraceReference(player_id); + default: + panic("Unknown trace type %d\n", raw_entry.type); + } + + return ref; +} + +} // namespace gem5 diff --git a/src/cpu/testers/dr_trace_player/trace_reader.hh b/src/cpu/testers/dr_trace_player/trace_reader.hh new file mode 100644 index 0000000000..e8b492dbc9 --- /dev/null +++ b/src/cpu/testers/dr_trace_player/trace_reader.hh @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2022 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __CPU_TESTERS_DR_TRACE_PLAYER_TRACE_READER_HH__ +#define __CPU_TESTERS_DR_TRACE_PLAYER_TRACE_READER_HH__ + +/** + * @file + * Contains the reader for dynamario traces + * See https://dynamorio.org/sec_drcachesim_format.html for details on the + * trace format. + * This file reimplements some of the code from drcachesim. See the dynamario + * git repo for the original code. This is built using version 9.0.19202. + * https://github.com/DynamoRIO/dynamorio + */ + +#include + +#include +#include +#include +#include + +#include "params/DRTraceReader.hh" +#include "sim/sim_object.hh" + +namespace gem5 +{ + + +/** + * An object which reads Dynamorio traces. + * Note that this is not a complete reader. It is currently only designed to + * read the google workload traces + * https://dynamorio.org/google_workload_traces.html + */ +class DRTraceReader : public SimObject +{ + public: + struct TraceRef + { + // Only used for instruction references + // (Note: we could add this to memory references in the future) + Addr pc = 0; + // Memory address referenced. Only used for memory references + Addr addr = 0; + unsigned int size = 0; + // True if this reference is valid. An invalid reference means the + // stream is over. + bool isValid = false; + // Thread id of the reference + int tid = 0; + // See dynamorio/clients/drcachesim/common/trace_entry.h for details + // There is not necessarily a 1-to-1 mapping with TRACE_TYPE + enum + { + // Inst types + GENERIC_INST, + DIRECT_JUMP, + INDIRECT_JUMP, + CONDITIONAL_JUMP, + DIRECT_CALL, + INDIRECT_CALL, + RETURN, + // memory types + READ, + WRITE, + PREFETCH + } type = {}; + + bool + isMemRef() + { + return type == READ || type == WRITE || type == PREFETCH; + } + + bool + isInstRef() + { + return !isMemRef(); + } + }; + + private: + /** + * Slightly modified trace entry from dynamorio. + * See dynamorio/clients/drcachesim/common/trace_entry.h for original. + * This is compatible with "version 3" of the trace + */ + struct GEM5_PACKED DRTraceEntry + { + unsigned short type; + unsigned short size; + uint64_t addr; + }; + + private: + + /// The directory which contains the trace files (one per thread) + std::filesystem::path directory; + /// All of the filenames of the trace files + std::vector filenames; + + /// The open trace files (one per thread) + std::vector traceFiles; + + /// The current timestamps for each trace file. Should be the same length + /// as the traceFiles above. + std::vector timestamps; + + /// The current thread being executed on each player. If -1, then nothing + /// is executing on that player + std::vector currentTids; + + /** + * @brief Get the Next Entry object for the give thread id + * + * @param tid The thread id of the trace file to get + * @return TraceEntry + */ + DRTraceEntry _getNextEntry(unsigned int tid); + + unsigned int + getLowestTimestampThread() + { + return std::distance(timestamps.begin(), + std::min_element(timestamps.begin(), timestamps.end())); + } + + enum + { + TRACE_TYPE_READ, + TRACE_TYPE_WRITE, + TRACE_TYPE_PREFETCH, + TRACE_TYPE_PREFETCHT0, + TRACE_TYPE_PREFETCH_READ_L1 = + TRACE_TYPE_PREFETCHT0, + TRACE_TYPE_PREFETCHT1, + TRACE_TYPE_PREFETCH_READ_L2 = + TRACE_TYPE_PREFETCHT1, + TRACE_TYPE_PREFETCHT2, + TRACE_TYPE_PREFETCH_READ_L3 = + TRACE_TYPE_PREFETCHT2, + TRACE_TYPE_PREFETCHNTA, + TRACE_TYPE_PREFETCH_READ, + TRACE_TYPE_PREFETCH_WRITE, + TRACE_TYPE_PREFETCH_INSTR, + TRACE_TYPE_INSTR, + TRACE_TYPE_INSTR_DIRECT_JUMP, + TRACE_TYPE_INSTR_INDIRECT_JUMP, + TRACE_TYPE_INSTR_CONDITIONAL_JUMP, + TRACE_TYPE_INSTR_DIRECT_CALL, + TRACE_TYPE_INSTR_INDIRECT_CALL, + TRACE_TYPE_INSTR_RETURN, + TRACE_TYPE_INSTR_BUNDLE, + TRACE_TYPE_INSTR_FLUSH, + TRACE_TYPE_INSTR_FLUSH_END, + TRACE_TYPE_DATA_FLUSH, + TRACE_TYPE_DATA_FLUSH_END, + TRACE_TYPE_THREAD, + TRACE_TYPE_THREAD_EXIT, + TRACE_TYPE_PID, + TRACE_TYPE_HEADER, + TRACE_TYPE_FOOTER, + TRACE_TYPE_HARDWARE_PREFETCH, + TRACE_TYPE_MARKER, + TRACE_TYPE_INSTR_NO_FETCH, + TRACE_TYPE_INSTR_MAYBE_FETCH, + TRACE_TYPE_INSTR_SYSENTER, + TRACE_TYPE_PREFETCH_READ_L1_NT, + TRACE_TYPE_PREFETCH_READ_L2_NT, + TRACE_TYPE_PREFETCH_READ_L3_NT, + TRACE_TYPE_PREFETCH_INSTR_L1, + TRACE_TYPE_PREFETCH_INSTR_L1_NT, + TRACE_TYPE_PREFETCH_INSTR_L2, + TRACE_TYPE_PREFETCH_INSTR_L2_NT, + TRACE_TYPE_PREFETCH_INSTR_L3, + TRACE_TYPE_PREFETCH_INSTR_L3_NT, + TRACE_TYPE_PREFETCH_WRITE_L1, + TRACE_TYPE_PREFETCH_WRITE_L1_NT, + TRACE_TYPE_PREFETCH_WRITE_L2, + TRACE_TYPE_PREFETCH_WRITE_L2_NT, + TRACE_TYPE_PREFETCH_WRITE_L3, + TRACE_TYPE_PREFETCH_WRITE_L3_NT, + }; + enum + { + TRACE_MARKER_TYPE_KERNEL_EVENT, + TRACE_MARKER_TYPE_KERNEL_XFER, + TRACE_MARKER_TYPE_TIMESTAMP, + TRACE_MARKER_TYPE_CPU_ID, + TRACE_MARKER_TYPE_FUNC_ID, + TRACE_MARKER_TYPE_FUNC_RETADDR, + TRACE_MARKER_TYPE_FUNC_ARG, + TRACE_MARKER_TYPE_FUNC_RETVAL, + TRACE_MARKER_TYPE_SPLIT_VALUE, + TRACE_MARKER_TYPE_FILETYPE, + TRACE_MARKER_TYPE_CACHE_LINE_SIZE, + TRACE_MARKER_TYPE_INSTRUCTION_COUNT, + TRACE_MARKER_TYPE_VERSION, + TRACE_MARKER_TYPE_RSEQ_ABORT, + TRACE_MARKER_TYPE_WINDOW_ID, + TRACE_MARKER_TYPE_PHYSICAL_ADDRESS, + TRACE_MARKER_TYPE_PHYSICAL_ADDRESS_NOT_AVAILABLE, + TRACE_MARKER_TYPE_VIRTUAL_ADDRESS, + TRACE_MARKER_TYPE_PAGE_SIZE, + TRACE_MARKER_TYPE_RESERVED_END = 100, + }; + + public: + PARAMS(DRTraceReader); + DRTraceReader(const Params ¶ms); + + void init() override; + + ~DRTraceReader() + { + for (auto &file : traceFiles) { + gzclose(file); + } + } + + /** + * Used by the DRTracePlayers to get the next traced instruction + * + */ + TraceRef getNextTraceReference(unsigned player_id); + + +}; + +} // namespace gem5 + + +#endif //__CPU_TESTERS_DR_TRACE_PLAYER_TRACE_READER_HH__ diff --git a/src/mem/DCacheCtrl.py b/src/mem/DCacheCtrl.py new file mode 100644 index 0000000000..0609b09641 --- /dev/null +++ b/src/mem/DCacheCtrl.py @@ -0,0 +1,60 @@ +# Copyright (c) 2012-2020 ARM Limited +# All rights reserved. +# +# The license below extends only to copyright in the software and shall +# not be construed as granting a license to any other intellectual +# property including but not limited to intellectual property relating +# to a hardware implementation of the functionality of the software +# licensed hereunder. You may use the software subject to the license +# terms below provided that you ensure that this notice is replicated +# unmodified and in its entirety in all distributions of the software, +# modified or unmodified, in source code or in binary form. +# +# Copyright (c) 2013 Amin Farmahini-Farahani +# Copyright (c) 2015 University of Kaiserslautern +# Copyright (c) 2015 The University of Bologna +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +from m5.params import * +from m5.proxy import * +from m5.objects.MemCtrl import * + +class DCacheCtrl(MemCtrl): + type = 'DCacheCtrl' + cxx_header = "mem/dram_cache_ctrl.hh" + cxx_class = 'gem5::memory::DCacheCtrl' + + req_port = RequestPort("This port responds to DRAM cache controller " + "requests for backing memory") + + dram_cache_size = Param.MemorySize('128MiB', + "DRAM cache block size in bytes") + block_size = Param.Unsigned(64, "DRAM cache block size in bytes") + addr_size = Param.Unsigned(64,"Addr size of the request from outside world") + orb_max_size = Param.Unsigned(256, "Outstanding Requests Buffer size") + crb_max_size = Param.Unsigned(32, "Conflicting Requests Buffer size") + always_hit = Param.Bool(True, "") + always_dirty = Param.Bool(True, "") diff --git a/src/mem/DRAMInterface.py b/src/mem/DRAMInterface.py index dea62a6be1..d1f472015f 100644 --- a/src/mem/DRAMInterface.py +++ b/src/mem/DRAMInterface.py @@ -39,6 +39,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. from m5.objects.MemCtrl import MemCtrl +# from m5.objects.PolicyManager import PolicyManager from m5.objects.MemInterface import * @@ -53,6 +54,13 @@ class DRAMInterface(MemInterface): cxx_header = "mem/dram_interface.hh" cxx_class = "gem5::memory::DRAMInterface" + # pol_man = Param.PolicyManager("Policy Manager which is used just in HBM2_Rambus " + # "for sending dirty data from flush buffer to the " + # "controller during refresh") + enable_read_flush_buffer = Param.Bool(False, "Enable reading from flush buffer " + "during refresh, only for HBM2_Rambus") + is_alloy = Param.Bool(False, "Alloy needs a different decode packet") + # scheduler page policy page_policy = Param.PageManage("open_adaptive", "Page management policy") @@ -179,6 +187,15 @@ class DRAMInterface(MemInterface): # time to exit self-refresh mode with locked DLL tXSDLL = Param.Latency("0ns", "Self-refresh exit latency DLL") + tTAGBURST = Param.Latency("0ns", "tRL_FAST") + tRL_FAST = Param.Latency("0ns", "tRL_FAST") + tHM2DQ = Param.Latency("0ns", "tHM2DQ") + tRTW_int = Param.Latency("0ns", "tRTW_int") + tRFBD = Param.Latency("0ns", "tRFBD") + tRCD_FAST = Param.Latency("0ns", "tRCD_FAST") + tRC_FAST = Param.Latency("0ns", "tRCD_FAST") + flushBuffer_high_thresh_perc = Param.Percent(0, "Threshold to force writes") + # number of data beats per clock. with DDR, default is 2, one per edge # used in drampower.cc beats_per_clock = Param.Unsigned(2, "Data beats per clock") @@ -549,7 +566,7 @@ class DDR4_2400_16x4(DRAMInterface): # CAS-to-CAS delay for bursts to the same bank group # tBURST is equivalent to tCCD_S; no explicit parameter required # for CAS-to-CAS delay for bursts to different bank groups - tCCD_L = "5ns" + tCCD_L = '5ns' # DDR4-2400 17-17-17 tRCD = "14.16ns" @@ -1255,6 +1272,184 @@ class HBM_2000_4H_1x64(DRAMInterface): two_cycle_activate = True +# A single HBM2 x64 interface (tested with HBMCtrl in gem5) +# to be used as a single pseudo channel. The timings are based +# on HBM gen2 specifications. 4H stack, 8Gb per die and total capacity +# of 4GiB. +class TDRAM(DRAMInterface): + + # 64-bit interface for a single pseudo channel + device_bus_width = 64 + + # HBM2 supports BL4 + burst_length = 8 + + # size of channel in bytes, 4H stack of 8Gb dies is 4GiB per stack; + # with 16 pseudo channels, 256MiB per pseudo channel + device_size = "256MiB" + + device_rowbuffer_size = "1KiB" + + # 1x128 configuration + devices_per_rank = 1 + + ranks_per_channel = 1 + + banks_per_rank = 32 + + bank_groups_per_rank = 8 + + # 1000 MHz for 2Gbps DDR data rate + tCK = "1ns" + + # new + tTAGBURST = "1ns" + tRL_FAST = "1ns" + tHM2DQ = "1ns" + tRTW_int = "2ns" + tRFBD = "2ns" + tRCD_FAST = "7.5ns" + tRC_FAST = "10.5ns" + enable_read_flush_buffer = True + flushBuffer_high_thresh_perc = 80 + + tRP = "14ns" + + tCCD_L = "4ns" + + tRCD = "12ns" + tRCD_WR = "6ns" + tCL = "18ns" + tCWL = "7ns" + tRAS = "28ns" + + tBURST = "4ns" + + # value for 2Gb device from JEDEC spec + tRFC = "220ns" + + # value for 2Gb device from JEDEC spec + tREFI = "3.9us" + + tWR = "14ns" + tRTP = "5ns" + tWTR = "4ns" + tWTR_L = "9ns" + tRTW = "18ns" + + #tAAD from RBus + tAAD = "1ns" + + # single rank device, set to 0 + tCS = "0ns" + + tRRD = "3ns" + tRRD_L = "4ns" + + # for a single pseudo channel + tXAW = "16ns" + activation_limit = 4 + + # 4tCK + tXP = "8ns" + + # start with tRFC + tXP -> 160ns + 8ns = 168ns + tXS = "216ns" + + page_policy = 'close' + + read_buffer_size = 64 + write_buffer_size = 64 + + two_cycle_activate = True + +class TDRAM_32(DRAMInterface): + + # 64-bit interface for a single pseudo channel + device_bus_width = 32 + + # HBM2 supports BL4 + burst_length = 16 + + # size of channel in bytes, 4H stack of 8Gb dies is 4GiB per stack; + # with 16 pseudo channels, 256MiB per pseudo channel + device_size = "1GiB" + + device_rowbuffer_size = "2KiB" + + # 1x128 configuration + devices_per_rank = 1 + + ranks_per_channel = 1 + + banks_per_rank = 32 + + bank_groups_per_rank = 8 + + # 1000 MHz for 2Gbps DDR data rate + tCK = "0.5ns" + + # new + tTAGBURST = "0.5ns" + tRL_FAST = "7.5ns" + tHM2DQ = "0ns" + tRTW_int = "1ns" + tRFBD = "1ns" + tRCD_FAST = "7.5ns" + enable_read_flush_buffer = True + flushBuffer_high_thresh_perc = 80 + + tRP = "14ns" + + tCCD_L = "2ns" + + tRCD = "12ns" + tRCD_WR = "6ns" + tCL = "18ns" + tCWL = "7ns" + tRAS = "28ns" + + tBURST = "2ns" + + # value for 2Gb device from JEDEC spec + tRFC = "220ns" + + # value for 2Gb device from JEDEC spec + tREFI = "3.9us" + + tWR = "14ns" + tRTP = "5ns" + tWTR = "4ns" + tWTR_L = "9ns" + tRTW = "18ns" + + #tAAD from RBus + tAAD = "1ns" + + # single rank device, set to 0 + tCS = "0ns" + + tRRD = "2ns" + tRRD_L = "2ns" + + # for a single pseudo channel + tXAW = "16ns" + activation_limit = 8 + + # 4tCK + tXP = "8ns" + + # start with tRFC + tXP -> 160ns + 8ns = 168ns + tXS = "216ns" + + page_policy = 'close' + + read_buffer_size = 64 + write_buffer_size = 64 + + two_cycle_activate = True + + addr_mapping = 'RoCoRaBaCh' # A single DDR5-4400 32bit channel (4x8 configuration) # A DDR5 DIMM is made up of two (32 bit) channels. diff --git a/src/mem/MemCtrl.py b/src/mem/MemCtrl.py index 62e4d97b26..b25b437701 100644 --- a/src/mem/MemCtrl.py +++ b/src/mem/MemCtrl.py @@ -77,7 +77,7 @@ class MemCtrl(QoSMemCtrl): # threshold in percentage for when to start writes if the read # queue is empty write_low_thresh_perc = Param.Percent(50, "Threshold to start writes") - + oldest_write_age_threshold = Param.Unsigned(2500000, "The age of oldest write request in the write queue in ticks") # minimum write bursts to schedule before switching back to reads min_writes_per_switch = Param.Unsigned( 16, "Minimum write bursts before switching to reads" @@ -98,7 +98,14 @@ class MemCtrl(QoSMemCtrl): static_frontend_latency = Param.Latency("10ns", "Static frontend latency") static_backend_latency = Param.Latency("10ns", "Static backend latency") + static_frontend_latency_tc = Param.Latency("0ns", "Static frontend latency") + static_backend_latency_tc = Param.Latency("0ns", "Static backend latency") + command_window = Param.Latency("10ns", "Static backend latency") + + consider_oldest_write = Param.Bool(False, "a flag to consider age of write " + "reqs for bus switching") + disable_sanity_check = Param.Bool(False, "Disable port resp Q size check") @@ -120,4 +127,4 @@ class MemCtrl(QoSMemCtrl): doi = {10.1109/ISPASS.2014.6844484} } """, -) +) \ No newline at end of file diff --git a/src/mem/PolicyManager.py b/src/mem/PolicyManager.py new file mode 100644 index 0000000000..0483d0cfce --- /dev/null +++ b/src/mem/PolicyManager.py @@ -0,0 +1,46 @@ +from m5.params import * +from m5.proxy import * +from m5.SimObject import SimObject +from m5.objects.ReplacementPolicies import * +from m5.objects.AbstractMemory import AbstractMemory +from m5.objects.DRAMInterface import * + +class Policy(Enum): vals = ['CascadeLakeNoPartWrs', 'Oracle', 'BearWriteOpt', 'Rambus', 'RambusTagProbOpt'] +class ReplPolicySetAssoc(Enum): vals = ['bip_rp', 'brrip_rp', 'dueling_rp', 'fifo_rp', 'lfu_rp', 'lru_rp', 'mru_rp', 'random_rp', 'second_chance_rp', 'ship_rp', 'tree_plru_rp', 'weighted_lru_rp'] + +class PolicyManager(AbstractMemory): + type = 'PolicyManager' + cxx_header = "mem/policy_manager.hh" + cxx_class = 'gem5::memory::PolicyManager' + + port = ResponsePort("This port responds to memory requests") + loc_req_port = RequestPort("This port responds to requests for DRAM cache controller") + far_req_port = RequestPort("This port responds to requests for backing store controller") + + loc_burst_size = Param.Unsigned(64, "Local memory burst size") + far_burst_size = Param.Unsigned(64, "Far memory burst size") + + loc_mem_policy = Param.Policy('CascadeLakeNoPartWrs', "DRAM Cache Policy") + loc_mem = Param.AbstractMemory("local memory device") + + assoc = Param.Unsigned(1, "Number of ways per each set in DRAM cache, if it is set-associative") + replPol = Param.ReplPolicySetAssoc('lru_rp', "Replacement policy, if it is set-associative") + replacement_policy = Param.BaseReplacementPolicy(LRURP(), "Replacement policy") + + dram_cache_size = Param.MemorySize('128MiB', "DRAM cache block size in bytes") + block_size = Param.Unsigned(64, "DRAM cache block size in bytes") + addr_size = Param.Unsigned(64,"Addr size of the request from outside world") + orb_max_size = Param.Unsigned(256, "Outstanding Requests Buffer size") + crb_max_size = Param.Unsigned(32, "Conflicting Requests Buffer size") + extreme = Param.Bool(False, "Control flag for enforcing hit/miss & dirty/clean") + always_hit = Param.Bool(True, "Control flag for enforcing hit/miss") + always_dirty = Param.Bool(False, "Control flag for enforcing clean/dirty") + + static_frontend_latency = Param.Latency("10ns", "Static frontend latency") + static_backend_latency = Param.Latency("10ns", "Static backend latency") + + cache_warmup_ratio = Param.Float(0.95, "DRAM cache warmup ratio") + + bypass_dcache = Param.Bool(False, "if the DRAM cache needs to be bypassed") + + diff --git a/src/mem/SConscript b/src/mem/SConscript index e2a91146d0..6e8beaa8c9 100644 --- a/src/mem/SConscript +++ b/src/mem/SConscript @@ -52,6 +52,8 @@ SimObject('MemCtrl.py', sim_objects=['MemCtrl'], enums=['MemSched']) SimObject('HeteroMemCtrl.py', sim_objects=['HeteroMemCtrl']) SimObject('HBMCtrl.py', sim_objects=['HBMCtrl']) +SimObject('DCacheCtrl.py', sim_objects=['DCacheCtrl']) +SimObject('PolicyManager.py', sim_objects=['PolicyManager'], enums=['Policy', 'ReplPolicySetAssoc']) SimObject('MemInterface.py', sim_objects=['MemInterface'], enums=['AddrMap']) SimObject('DRAMInterface.py', sim_objects=['DRAMInterface'], enums=['PageManage']) @@ -81,6 +83,8 @@ Source('external_slave.cc') Source('mem_ctrl.cc') Source('hetero_mem_ctrl.cc') Source('hbm_ctrl.cc') +Source('dram_cache_ctrl.cc') +Source('policy_manager.cc') Source('mem_interface.cc') Source('dram_interface.cc') Source('nvm_interface.cc') @@ -144,6 +148,8 @@ CompoundFlag('XBar', ['BaseXBar', 'CoherentXBar', 'NoncoherentXBar', DebugFlag('Bridge') DebugFlag('CommMonitor') DebugFlag('DRAM') +DebugFlag('DRAMT') +DebugFlag('DecodePkt') DebugFlag('DRAMPower') DebugFlag('DRAMState') DebugFlag('NVM') @@ -151,6 +157,8 @@ DebugFlag('ExternalPort') DebugFlag('HtmMem', 'Hardware Transactional Memory (Mem side)') DebugFlag('LLSC') DebugFlag('MemCtrl') +DebugFlag('DCacheCtrl') +DebugFlag('PolicyManager') DebugFlag('MMU') DebugFlag('MemoryAccess') DebugFlag('PacketQueue') diff --git a/src/mem/abstract_mem.cc b/src/mem/abstract_mem.cc index 9340f7e96f..d0cc1d8189 100644 --- a/src/mem/abstract_mem.cc +++ b/src/mem/abstract_mem.cc @@ -395,7 +395,16 @@ AbstractMemory::access(PacketPtr pkt) uint8_t *host_addr = toHostAddr(pkt->getAddr()); - if (pkt->cmd == MemCmd::SwapReq) { + if (pkt->cmd == MemCmd::SwapResp) { + if (pkt->isAtomicOp()) { + if (pmemAddr) { + pkt->writeData(host_addr); + (*(pkt->getAtomicOp()))(host_addr); + } + } else { + fatal("Did not expect this access in timing mode"); + } + } else if (pkt->cmd == MemCmd::SwapReq) { if (pkt->isAtomicOp()) { if (pmemAddr) { pkt->setData(host_addr); diff --git a/src/mem/abstract_mem.hh b/src/mem/abstract_mem.hh index 7f12487421..572e28ff03 100644 --- a/src/mem/abstract_mem.hh +++ b/src/mem/abstract_mem.hh @@ -46,6 +46,7 @@ #ifndef __MEM_ABSTRACT_MEMORY_HH__ #define __MEM_ABSTRACT_MEMORY_HH__ +#include "enums/Policy.hh" #include "mem/backdoor.hh" #include "mem/port.hh" #include "params/AbstractMemory.hh" @@ -225,6 +226,32 @@ class AbstractMemory : public ClockedObject void initState() override; + enums::Policy locMemPolicy; + + virtual Tick get_tRP() { panic("AbstractMemory get_tRP should not be executed from here.\n"); + return false;} + virtual Tick get_tRCD_RD() { panic("AbstractMemory get_tRCD_RD should not be executed from here.\n"); + return false;} + virtual Tick get_tRL() { panic("AbstractMemory get_tRL should not be executed from here.\n"); + return false;} + + virtual bool recvReadFlushBuffer(Addr addr) + { + panic("AbstractMemory recvReadFlushBuffer should not be executed from here.\n"); + return false; + } + + virtual void setPolicyManager(AbstractMemory* _polMan) + { + panic("AbstractMemory setPolicyManager should not be executed from here.\n"); + } + + virtual bool checkFwdMrgeInFB(Addr addr) + { + panic("AbstractMemory checkFwdMrgeInFB should not be executed from here.\n"); + return false; + } + /** * See if this is a null memory that should never store data and * always return zero. diff --git a/src/mem/cache/replacement_policies/replaceable_entry.hh b/src/mem/cache/replacement_policies/replaceable_entry.hh index bb88cefd1d..cf31130399 100644 --- a/src/mem/cache/replacement_policies/replaceable_entry.hh +++ b/src/mem/cache/replacement_policies/replaceable_entry.hh @@ -34,6 +34,7 @@ #include "base/compiler.hh" #include "base/cprintf.hh" +#include "base/types.hh" namespace gem5 { @@ -61,6 +62,23 @@ struct ReplacementData {}; */ class ReplaceableEntry { + public: + Addr tagDC; + Addr indexDC; + // constant to indicate that the cache line is valid + bool validLine; + // constant to indicate that the cache line is dirty + bool dirtyLine; + Addr farMemAddr; + + ReplaceableEntry(Addr _tagDC, Addr _indexDC, bool _validLine, bool _dirtyLine, Addr _farMemAddr) : + tagDC(_tagDC), + indexDC(_indexDC), + validLine(_validLine), + dirtyLine(_dirtyLine), + farMemAddr(_farMemAddr) + { } + protected: /** * Set to which this entry belongs. diff --git a/src/mem/coherent_xbar.cc b/src/mem/coherent_xbar.cc index 74ef1ead36..a600cda34e 100644 --- a/src/mem/coherent_xbar.cc +++ b/src/mem/coherent_xbar.cc @@ -291,6 +291,7 @@ CoherentXBar::recvTimingReq(PacketPtr pkt, PortID cpu_side_port_id) // since it is a normal request, attempt to send the packet success = memSidePorts[mem_side_port_id]->sendTimingReq(pkt); + // std::cout << "4: " << pkt->getAddr() << " : " << xbar_delay << "\n"; } else { // no need to forward, turn this packet around and respond // directly @@ -343,9 +344,9 @@ CoherentXBar::recvTimingReq(PacketPtr pkt, PortID cpu_side_port_id) assert(routeTo.find(pkt->req) == routeTo.end()); routeTo[pkt->req] = cpu_side_port_id; - panic_if(routeTo.size() > maxRoutingTableSizeCheck, - "%s: Routing table exceeds %d packets\n", - name(), maxRoutingTableSizeCheck); + // panic_if(routeTo.size() > maxRoutingTableSizeCheck, + // "%s: Routing table exceeds %d packets\n", + // name(), maxRoutingTableSizeCheck); } // update the layer state and schedule an idle event @@ -438,8 +439,9 @@ CoherentXBar::recvTimingReq(PacketPtr pkt, PortID cpu_side_port_id) rsp_pkt->headerDelay = 0; cpuSidePorts[rsp_port_id]->schedTimingResp(rsp_pkt, response_time); - } + // std::cout << "1: " << pkt->getAddr() << " : " << response_time-clockEdge() << "\n"; + } return success; } @@ -492,6 +494,7 @@ CoherentXBar::recvTimingResp(PacketPtr pkt, PortID mem_side_port_id) pkt->headerDelay = 0; cpuSidePorts[cpu_side_port_id]->schedTimingResp(pkt, curTick() + latency); + // std::cout << "2: " << pkt->getAddr() << " : " << latency << "\n"; // remove the request from the routing table routeTo.erase(route_lookup); @@ -680,6 +683,7 @@ CoherentXBar::recvTimingSnoopResp(PacketPtr pkt, PortID cpu_side_port_id) pkt->headerDelay = 0; cpuSidePorts[dest_port_id]->schedTimingResp(pkt, curTick() + latency); + // std::cout << "3: " << pkt->getAddr() << " : " << latency << "\n"; respLayers[dest_port_id]->succeededTiming(packetFinishTime); } @@ -700,7 +704,7 @@ void CoherentXBar::forwardTiming(PacketPtr pkt, PortID exclude_cpu_side_port_id, const std::vector& dests) { - DPRINTF(CoherentXBar, "%s for %s\n", __func__, pkt->print()); + DPRINTF(CoherentXBar, "%s for %s \n", __func__, pkt->print()); // snoops should only happen if the system isn't bypassing caches assert(!system->bypassCaches()); @@ -714,6 +718,7 @@ CoherentXBar::forwardTiming(PacketPtr pkt, PortID exclude_cpu_side_port_id, // from if (exclude_cpu_side_port_id == InvalidPortID || p->getId() != exclude_cpu_side_port_id) { + // std::cout << "here\n"; // cache is not allowed to refuse snoop p->sendTimingSnoopReq(pkt); fanout++; diff --git a/src/mem/dram_cache_ctrl.cc b/src/mem/dram_cache_ctrl.cc new file mode 100644 index 0000000000..7db3960519 --- /dev/null +++ b/src/mem/dram_cache_ctrl.cc @@ -0,0 +1,1917 @@ +/* + * Copyright (c) 2010-2020 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Copyright (c) 2013 Amin Farmahini-Farahani + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mem/dram_cache_ctrl.hh" + +#include "base/trace.hh" +#include "debug/DCacheCtrl.hh" +#include "debug/DRAM.hh" +#include "debug/Drain.hh" +#include "debug/QOS.hh" +#include "mem/dram_interface.hh" +#include "mem/mem_interface.hh" +#include "sim/system.hh" + +namespace gem5 +{ + +namespace memory +{ + +DCacheCtrl::DCacheCtrl(const DCacheCtrlParams &p): + MemCtrl(p), + reqPort(name() + ".req_port", *this), + dramCacheSize(p.dram_cache_size), + blockSize(p.block_size), + addrSize(p.addr_size), + orbMaxSize(p.orb_max_size), orbSize(0), + crbMaxSize(p.crb_max_size), crbSize(0), + alwaysHit(p.always_hit), alwaysDirty(p.always_dirty), + retry(false), retryFMW(false), + stallRds(false), sendFarRdReq(true), + waitingForRetryReqPort(false), + rescheduleLocRead(false), + rescheduleLocWrite(false), + locWrCounter(0), farWrCounter(0), + maxConf(0), + maxLocRdEvQ(0), maxLocRdRespEvQ(0), maxLocWrEvQ(0), + maxFarRdEvQ(0), maxFarRdRespEvQ(0), maxFarWrEvQ(0), + locMemReadEvent([this]{ processLocMemReadEvent(); }, name()), + locMemReadRespEvent([this]{ processLocMemReadRespEvent(); }, name()), + locMemWriteEvent([this]{ processLocMemWriteEvent(); }, name()), + farMemReadEvent([this]{ processFarMemReadEvent(); }, name()), + farMemReadRespEvent([this]{ processFarMemReadRespEvent(); }, name()), + farMemWriteEvent([this]{ processFarMemWriteEvent(); }, name()), + dcstats(*this) +{ + fatal_if(!dram, "DRAM cache controller must have a DRAM interface.\n"); + + panic_if(orbMaxSize<8, "ORB maximum size must be at least 8.\n"); + + // hook up interfaces to the controller + dram->setCtrl(this, commandWindow); + + tagMetadataStore.resize(dramCacheSize/blockSize); + dirtAdrGen(); + pktLocMemRead.resize(1); + pktLocMemWrite.resize(1); + + // This is actually a locWriteHighThreshold + writeHighThreshold = 0.5 * orbMaxSize; + + minLocWrPerSwitch = 0.25 * orbMaxSize; +} + +void +DCacheCtrl::init() +{ + if (!port.isConnected()) { + fatal("DCacheCtrl %s is unconnected!\n", name()); + } else if (!reqPort.isConnected()) { + fatal("DCacheCtrl %s is unconnected!\n", name()); + } else { + port.sendRangeChange(); + //reqPort.recvRangeChange(); + } +} + +DCacheCtrl::DCCtrlStats::DCCtrlStats(DCacheCtrl &_ctrl) + : statistics::Group(&_ctrl), + ctrl(_ctrl), + +///// + ADD_STAT(readReqs, statistics::units::Count::get(), + "Number of read requests accepted"), + ADD_STAT(writeReqs, statistics::units::Count::get(), + "Number of write requests accepted"), + + ADD_STAT(readBursts, statistics::units::Count::get(), + "Number of controller read bursts, including those serviced by " + "the write queue"), + ADD_STAT(writeBursts, statistics::units::Count::get(), + "Number of controller write bursts, including those merged in " + "the write queue"), + ADD_STAT(servicedByWrQ, statistics::units::Count::get(), + "Number of controller read bursts serviced by the write queue"), + ADD_STAT(mergedWrBursts, statistics::units::Count::get(), + "Number of controller write bursts merged with an existing one"), + + ADD_STAT(neitherReadNorWriteReqs, statistics::units::Count::get(), + "Number of requests that are neither read nor write"), + + ADD_STAT(avgRdQLen, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average read queue length when enqueuing"), + ADD_STAT(avgWrQLen, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average write queue length when enqueuing"), + + ADD_STAT(numRdRetry, statistics::units::Count::get(), + "Number of times read queue was full causing retry"), + ADD_STAT(numWrRetry, statistics::units::Count::get(), + "Number of times write queue was full causing retry"), + + ADD_STAT(readPktSize, statistics::units::Count::get(), + "Read request sizes (log2)"), + ADD_STAT(writePktSize, statistics::units::Count::get(), + "Write request sizes (log2)"), + + ADD_STAT(rdQLenPdf, statistics::units::Count::get(), + "What read queue length does an incoming req see"), + ADD_STAT(wrQLenPdf, statistics::units::Count::get(), + "What write queue length does an incoming req see"), + + ADD_STAT(rdPerTurnAround, statistics::units::Count::get(), + "Reads before turning the bus around for writes"), + ADD_STAT(wrPerTurnAround, statistics::units::Count::get(), + "Writes before turning the bus around for reads"), + + ADD_STAT(bytesReadWrQ, statistics::units::Byte::get(), + "Total number of bytes read from write queue"), + ADD_STAT(bytesReadSys, statistics::units::Byte::get(), + "Total read bytes from the system interface side"), + ADD_STAT(bytesWrittenSys, statistics::units::Byte::get(), + "Total written bytes from the system interface side"), + + ADD_STAT(avgRdBWSys, statistics::units::Rate< + statistics::units::Byte, statistics::units::Second>::get(), + "Average system read bandwidth in Byte/s"), + ADD_STAT(avgWrBWSys, statistics::units::Rate< + statistics::units::Byte, statistics::units::Second>::get(), + "Average system write bandwidth in Byte/s"), + + ADD_STAT(totGap, statistics::units::Tick::get(), + "Total gap between requests"), + ADD_STAT(avgGap, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), + "Average gap between requests"), + + ADD_STAT(requestorReadBytes, statistics::units::Byte::get(), + "Per-requestor bytes read from memory"), + ADD_STAT(requestorWriteBytes, statistics::units::Byte::get(), + "Per-requestor bytes write to memory"), + ADD_STAT(requestorReadRate, statistics::units::Rate< + statistics::units::Byte, statistics::units::Second>::get(), + "Per-requestor bytes read from memory rate"), + ADD_STAT(requestorWriteRate, statistics::units::Rate< + statistics::units::Byte, statistics::units::Second>::get(), + "Per-requestor bytes write to memory rate"), + ADD_STAT(requestorReadAccesses, statistics::units::Count::get(), + "Per-requestor read serviced memory accesses"), + ADD_STAT(requestorWriteAccesses, statistics::units::Count::get(), + "Per-requestor write serviced memory accesses"), + ADD_STAT(requestorReadTotalLat, statistics::units::Tick::get(), + "Per-requestor read total memory access latency"), + ADD_STAT(requestorWriteTotalLat, statistics::units::Tick::get(), + "Per-requestor write total memory access latency"), + ADD_STAT(requestorReadAvgLat, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), + "Per-requestor read average memory access latency"), + ADD_STAT(requestorWriteAvgLat, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), + "Per-requestor write average memory access latency"), +//////// + + ADD_STAT(avgORBLen, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average ORB length"), + ADD_STAT(avgLocRdQLenStrt, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average local read queue length"), + ADD_STAT(avgLocWrQLenStrt, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average local write queue length"), + ADD_STAT(avgFarRdQLenStrt, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average far read queue length"), + ADD_STAT(avgFarWrQLenStrt, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average far write queue length"), + + ADD_STAT(avgLocRdQLenEnq, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average local read queue length when enqueuing"), + ADD_STAT(avgLocWrQLenEnq, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average local write queue length when enqueuing"), + ADD_STAT(avgFarRdQLenEnq, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average far read queue length when enqueuing"), + ADD_STAT(avgFarWrQLenEnq, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average far write queue length when enqueuing"), + + ADD_STAT(numWrBacks, + "Total number of write backs from DRAM cache to main memory"), + ADD_STAT(totNumConf, + "Total number of packets conflicted on DRAM cache"), + ADD_STAT(totNumORBFull, + "Total number of packets ORB full"), + ADD_STAT(totNumConfBufFull, + "Total number of packets conflicted yet couldn't " + "enter confBuffer"), + + ADD_STAT(maxNumConf, + "Maximum number of packets conflicted on DRAM cache"), + ADD_STAT(maxLocRdEvQ, + "Maximum number of packets in locMemReadEvent concurrently"), + ADD_STAT(maxLocRdRespEvQ, + "Maximum number of packets in locMemReadRespEvent concurrently"), + ADD_STAT(maxLocWrEvQ, + "Maximum number of packets in locMemRWriteEvent concurrently"), + ADD_STAT(maxFarRdEvQ, + "Maximum number of packets in farMemReadEvent concurrently"), + ADD_STAT(maxFarRdRespEvQ, + "Maximum number of packets in farMemReadRespEvent concurrently"), + ADD_STAT(maxFarWrEvQ, + "Maximum number of packets in farMemWriteEvent concurrently"), + + ADD_STAT(rdToWrTurnAround, + "Maximum number of packets in farMemReadRespEvent concurrently"), + ADD_STAT(wrToRdTurnAround, + "Maximum number of packets in farMemWriteEvent concurrently"), + + ADD_STAT(sentRdPort, + "Number of read packets successfully sent through the request port to the far memory."), + ADD_STAT(failedRdPort, + "Number of read packets failed to be sent through the request port to the far memory."), + ADD_STAT(recvdRdPort, + "Number of read packets resp recvd through the request port from the far memory."), + ADD_STAT(sentWrPort, + "Number of write packets successfully sent through the request port to the far memory."), + ADD_STAT(failedWrPort, + "Number of write packets failed to be sent through the request port to the far memory."), + ADD_STAT(totPktsServiceTime, + "stat"), + ADD_STAT(totPktsORBTime, + "stat"), + ADD_STAT(totTimeFarRdtoSend, + "stat"), + ADD_STAT(totTimeFarRdtoRecv, + "stat"), + ADD_STAT(totTimeFarWrtoSend, + "stat"), + ADD_STAT(totTimeInLocRead, + "stat"), + ADD_STAT(totTimeInLocWrite, + "stat"), + ADD_STAT(totTimeInFarRead, + "stat"), + ADD_STAT(QTLocRd, + "stat"), + ADD_STAT(QTLocWr, + "stat") +{ +} + +void +DCacheCtrl::DCCtrlStats::regStats() +{ + using namespace statistics; + + assert(ctrl.system()); + const auto max_requestors = ctrl.system()->maxRequestors(); + + avgRdQLen.precision(2); + avgWrQLen.precision(2); + + avgORBLen.precision(4); + avgLocRdQLenStrt.precision(2); + avgLocWrQLenStrt.precision(2); + avgFarRdQLenStrt.precision(2); + avgFarWrQLenStrt.precision(2); + + avgLocRdQLenEnq.precision(2); + avgLocWrQLenEnq.precision(2); + avgFarRdQLenEnq.precision(2); + avgFarWrQLenEnq.precision(2); + + readPktSize.init(ceilLog2(ctrl.system()->cacheLineSize()) + 1); + writePktSize.init(ceilLog2(ctrl.system()->cacheLineSize()) + 1); + + rdQLenPdf.init(ctrl.readBufferSize); + wrQLenPdf.init(ctrl.writeBufferSize); + + rdPerTurnAround + .init(ctrl.readBufferSize) + .flags(nozero); + wrPerTurnAround + .init(ctrl.writeBufferSize) + .flags(nozero); + + avgRdBWSys.precision(8); + avgWrBWSys.precision(8); + avgGap.precision(2); + + // per-requestor bytes read and written to memory + requestorReadBytes + .init(max_requestors) + .flags(nozero | nonan); + + requestorWriteBytes + .init(max_requestors) + .flags(nozero | nonan); + + // per-requestor bytes read and written to memory rate + requestorReadRate + .flags(nozero | nonan) + .precision(12); + + requestorReadAccesses + .init(max_requestors) + .flags(nozero); + + requestorWriteAccesses + .init(max_requestors) + .flags(nozero); + + requestorReadTotalLat + .init(max_requestors) + .flags(nozero | nonan); + + requestorReadAvgLat + .flags(nonan) + .precision(2); + + requestorWriteRate + .flags(nozero | nonan) + .precision(12); + + requestorWriteTotalLat + .init(max_requestors) + .flags(nozero | nonan); + + requestorWriteAvgLat + .flags(nonan) + .precision(2); + + for (int i = 0; i < max_requestors; i++) { + const std::string requestor = ctrl.system()->getRequestorName(i); + requestorReadBytes.subname(i, requestor); + requestorReadRate.subname(i, requestor); + requestorWriteBytes.subname(i, requestor); + requestorWriteRate.subname(i, requestor); + requestorReadAccesses.subname(i, requestor); + requestorWriteAccesses.subname(i, requestor); + requestorReadTotalLat.subname(i, requestor); + requestorReadAvgLat.subname(i, requestor); + requestorWriteTotalLat.subname(i, requestor); + requestorWriteAvgLat.subname(i, requestor); + } + + // Formula stats + avgRdBWSys = (bytesReadSys) / simSeconds; + avgWrBWSys = (bytesWrittenSys) / simSeconds; + + avgGap = totGap / (readReqs + writeReqs); + + requestorReadRate = requestorReadBytes / simSeconds; + requestorWriteRate = requestorWriteBytes / simSeconds; + requestorReadAvgLat = requestorReadTotalLat / requestorReadAccesses; + requestorWriteAvgLat = requestorWriteTotalLat / requestorWriteAccesses; +} + +void +DCacheCtrl::accessAndRespond(PacketPtr pkt, Tick static_latency, + MemInterface* mem_intr) +{ + bool needsResponse = pkt->needsResponse(); + // do the actual memory access which also turns the packet into a + // response + panic_if(!mem_intr->getAddrRange().contains(pkt->getAddr()), + "Can't handle address range for packet %s\n", pkt->print()); + mem_intr->access(pkt); + // PacketPtr copyOwPkt = new Packet(pkt, false, pkt->isRead()); + // reqPort.sendFunctional(copyOwPkt); + + // turn packet around to go back to requestor if response expected + if (needsResponse) { + // access already turned the packet into a response + assert(pkt->isResponse()); + // response_time consumes the static latency and is charged also + // with headerDelay that takes into account the delay provided by + // the xbar and also the payloadDelay that takes into account the + // number of data beats. + Tick response_time = curTick() + static_latency + pkt->headerDelay + + pkt->payloadDelay; + // Here we reset the timing of the packet before sending it out. + pkt->headerDelay = pkt->payloadDelay = 0; + + // queue the packet in the response queue to be sent out after + // the static latency has passed + port.schedTimingResp(pkt, response_time); + } else { + // @todo the packet is going to be deleted, and the MemPacket + // is still having a pointer to it + pendingDelete.reset(pkt); + } + + return; +} + +bool +DCacheCtrl::recvTimingReq(PacketPtr pkt) +{ + // This is where we enter from the outside world + DPRINTF(DCacheCtrl, "dc: got %s %lld\n", pkt->cmdString(), pkt->getAddr()); + + panic_if(pkt->cacheResponding(), "Should not see packets where cache " + "is responding"); + + panic_if(!(pkt->isRead() || pkt->isWrite()), + "Should only see read and writes at memory controller\n"); + + // Calc avg gap between requests + if (prevArrival != 0) { + dcstats.totGap += curTick() - prevArrival; + } + prevArrival = curTick(); + + // Validate that pkt's address maps to the dram + assert(dram && dram->getAddrRange().contains(pkt->getAddr())); + + + // Find out how many memory packets a pkt translates to + // If the burst size is equal or larger than the pkt size, then a pkt + // translates to only one memory packet. Otherwise, a pkt translates to + // multiple memory packets + + if ( + ((pktFarMemWrite.size() >= (orbMaxSize/2)) || (!pktFarMemWrite.empty() && pktFarMemRead.empty())) && + !waitingForRetryReqPort + ) { + if (!farMemWriteEvent.scheduled() && !farMemReadEvent.scheduled()) { + sendFarRdReq = false; + schedule(farMemWriteEvent, curTick()+1000); + } + } + + Addr addr = pkt->getAddr(); + + unsigned burst_size = dram->bytesPerBurst(); + + unsigned size = std::min((addr | (burst_size - 1)) + 1, + addr + pkt->getSize()) - addr; + + // check merging for writes + if (pkt->isWrite()) { + + dcstats.writePktSize[ceilLog2(size)]++; + dcstats.writeBursts++; + dcstats.requestorWriteAccesses[pkt->requestorId()]++; + + assert(pkt->getSize() != 0); + + bool merged = isInWriteQueue.find(pkt->getAddr()) != + isInWriteQueue.end(); + + if (merged) { + + dcstats.mergedWrBursts++; + + accessAndRespond(pkt, frontendLatency, dram); + + return true; + } + } + + // check forwarding for reads + bool foundInORB = false; + bool foundInCRB = false; + bool foundInFarMemWrite = false; + + if (pkt->isRead()) { + + assert(pkt->getSize() != 0); + + if (isInWriteQueue.find(pkt->getAddr()) != isInWriteQueue.end()) { + + if (!ORB.empty()) { + for (const auto& e : ORB) { + + // check if the read is subsumed in the write queue + // packet we are looking at + if (e.second->validEntry && + e.second->owPkt->isWrite() && + e.second->owPkt->getAddr() <= addr && + ((addr + size) <= + (e.second->owPkt->getAddr() + + e.second->owPkt->getSize()))) { + + foundInORB = true; + + dcstats.servicedByWrQ++; + + dcstats.bytesReadWrQ += burst_size; + + break; + } + } + } + + if (!foundInORB && !CRB.empty()) { + for (const auto& e : CRB) { + + // check if the read is subsumed in the write queue + // packet we are looking at + if (e.second->isWrite() && + e.second->getAddr() <= addr && + ((addr + size) <= + (e.second->getAddr() + e.second->getSize()))) { + + foundInCRB = true; + + dcstats.servicedByWrQ++; + + dcstats.bytesReadWrQ += burst_size; + + break; + } + } + } + + if (!foundInORB && !foundInCRB && !pktFarMemWrite.empty()) { + for (const auto& e : pktFarMemWrite) { + // check if the read is subsumed in the write queue + // packet we are looking at + if (e.second->getAddr() <= addr && + ((addr + size) <= + (e.second->getAddr() + + e.second->getSize()))) { + + foundInFarMemWrite = true; + + dcstats.servicedByWrQ++; + + dcstats.bytesReadWrQ += burst_size; + + break; + } + } + } + } + + if (foundInORB || foundInCRB || foundInFarMemWrite) { + dcstats.readPktSize[ceilLog2(size)]++; + dcstats.readBursts++; + dcstats.requestorReadAccesses[pkt->requestorId()]++; + + accessAndRespond(pkt, frontendLatency, dram); + + return true; + } + } + + // process conflicting requests. + // conflicts are checked only based on Index of DRAM cache + if (checkConflictInDramCache(pkt)) { + + dcstats.totNumConf++; + + if (CRB.size()>=crbMaxSize) { + + dcstats.totNumConfBufFull++; + + retry = true; + + if (pkt->isRead()) { + dcstats.numRdRetry++; + } + else { + dcstats.numWrRetry++; + } + return false; + } + + CRB.push_back(std::make_pair(curTick(), pkt)); + + if (pkt->isWrite()) { + isInWriteQueue.insert(pkt->getAddr()); + } + + if (CRB.size() > maxConf) { + maxConf = CRB.size(); + dcstats.maxNumConf = CRB.size(); + } + + return true; + } + // check if ORB or FMWB is full and set retry + if (pktFarMemWrite.size()>= (orbMaxSize / 2)) { + DPRINTF(DCacheCtrl, "FMWBfull: %lld\n", pkt->getAddr()); + retryFMW = true; + + if (pkt->isRead()) { + dcstats.numRdRetry++; + } + else { + dcstats.numWrRetry++; + } + return false; + } + + if (ORB.size() >= orbMaxSize) { + DPRINTF(DCacheCtrl, "ORBfull: addr %lld\n", pkt->getAddr()); + dcstats.totNumORBFull++; + retry = true; + + if (pkt->isRead()) { + dcstats.numRdRetry++; + } + else { + dcstats.numWrRetry++; + } + return false; + } + + // if none of the above cases happens, + // then add the pkt to the outstanding requests buffer + handleRequestorPkt(pkt); + + if (pkt->isWrite()) { + isInWriteQueue.insert(pkt->getAddr()); + } + + pktLocMemRead[0].push_back(ORB.at(pkt->getAddr())->dccPkt); + + dcstats.avgLocRdQLenEnq = pktLocMemRead[0].size() + addrLocRdRespReady.size(); + + if (!stallRds && !rescheduleLocRead && !locMemReadEvent.scheduled()) { + schedule(locMemReadEvent, std::max(dram->nextReqTime, curTick())); + } + + ORB.at(pkt->getAddr())->locRdEntered = curTick(); + + if (pktLocMemRead[0].size() > maxLocRdEvQ) { + maxLocRdEvQ = pktLocMemRead[0].size(); + dcstats.maxLocRdEvQ = pktLocMemRead[0].size(); + } + + DPRINTF(DCacheCtrl, "DRAM cache controller accepted packet %lld\n", pkt->getAddr()); + + return true; +} + +void +DCacheCtrl::processLocMemReadEvent() +{ + if (stallRds || dram->isBusy(false, false) || rescheduleLocRead) { + // it's possible that dram is busy and we return here before + // reching to read_found check to set rescheduleLocRead + if (dram->isBusy(false, false)) { + rescheduleLocRead = true; + } + return; + } + + assert(!pktLocMemRead[0].empty()); + + MemPacketQueue::iterator to_read; + + bool read_found = false; + + bool switched_cmd_type = (busState == DCacheCtrl::WRITE); + + for (auto queue = pktLocMemRead.rbegin(); + queue != pktLocMemRead.rend(); ++queue) { + to_read = MemCtrl::chooseNext((*queue), switched_cmd_type ? + minWriteToReadDataGap() : 0, dram); + // to_read = MemCtrl::chooseNext((*queue), 0, dram); + if (to_read != queue->end()) { + // candidate read found + read_found = true; + break; + } + } + + if (!read_found) { + DPRINTF(DCacheCtrl, " !read_found LocRd: %lld\n", curTick()); + // Probably dram is refreshing. + // Simply return, let the dram device + // reschedule again once refresh is done. + rescheduleLocRead = true; + return; + } + + auto orbEntry = ORB.at((*to_read)->getAddr()); + + DPRINTF(DCacheCtrl, "LocRd: %lld\n", orbEntry->owPkt->getAddr()); + + // sanity check for the chosen packet + assert(orbEntry->validEntry); + assert(orbEntry->dccPkt->isDram()); + assert(orbEntry->dccPkt->isRead()); + assert(orbEntry->state == locMemRead); + assert(!orbEntry->issued); + + busState = DCacheCtrl::READ; + + if (switched_cmd_type) { + dcstats.wrToRdTurnAround++; + } + + Tick cmdAt = MemCtrl::doBurstAccess(orbEntry->dccPkt, dram); + dcstats.QTLocRd += ((cmdAt-orbEntry->locRdEntered)/1000); + + // sanity check + //assert(orbEntry->dccPkt->size <= dram->bytesPerBurst()); + assert(orbEntry->dccPkt->readyTime >= curTick()); + + if (orbEntry->owPkt->isRead() && orbEntry->isHit) { + logResponse(DCacheCtrl::READ, + orbEntry->dccPkt->requestorId(), + orbEntry->dccPkt->qosValue(), + orbEntry->owPkt->getAddr(), 1, + orbEntry->dccPkt->readyTime - orbEntry->dccPkt->entryTime); + } + + if (addrLocRdRespReady.empty()) { + assert(!locMemReadRespEvent.scheduled()); + schedule(locMemReadRespEvent, orbEntry->dccPkt->readyTime); + } + else { + assert(ORB.at(addrLocRdRespReady.back())->dccPkt->readyTime + <= orbEntry->dccPkt->readyTime); + + assert(locMemReadRespEvent.scheduled()); + } + + addrLocRdRespReady.push_back(orbEntry->owPkt->getAddr()); + + if (addrLocRdRespReady.size() > maxLocRdRespEvQ) { + maxLocRdRespEvQ = addrLocRdRespReady.size(); + dcstats.maxLocRdRespEvQ = addrLocRdRespReady.size(); + } + + // keep the state as it is, no transition + orbEntry->state = locMemRead; + // mark the entry as issued (while in locMemRead) + orbEntry->issued = true; + // record the tick it was issued + orbEntry->locRdIssued = curTick(); + orbEntry->locRdExit = orbEntry->dccPkt->readyTime; + + pktLocMemRead[0].erase(to_read); + + unsigned rdsNum = pktLocMemRead[0].size(); + unsigned wrsNum = pktLocMemWrite[0].size(); + + if ((rdsNum == 0 && wrsNum != 0) || + (wrsNum >= writeHighThreshold)) { + stallRds = true; + if (!locMemWriteEvent.scheduled()) { + schedule(locMemWriteEvent, std::max(dram->nextReqTime, curTick())); + } + return; + } + + if (!pktLocMemRead[0].empty() && !locMemReadEvent.scheduled()) { + //assert(!locMemReadEvent.scheduled()); + schedule(locMemReadEvent, std::max(dram->nextReqTime, curTick())); + } +} + +void +DCacheCtrl::processLocMemReadRespEvent() +{ + assert(!addrLocRdRespReady.empty()); + + reqBufferEntry* orbEntry = ORB.at(addrLocRdRespReady.front()); + + DPRINTF(DCacheCtrl, "LocRdResp: %lld\n", orbEntry->owPkt->getAddr()); + + // A series of sanity check + assert(orbEntry->validEntry); + assert(orbEntry->dccPkt->isDram()); + assert(orbEntry->dccPkt->isRead()); + assert(orbEntry->state == locMemRead); + assert(orbEntry->issued); + assert(orbEntry->dccPkt->readyTime == curTick()); + + orbEntry->issued = false; + + if (orbEntry->handleDirtyLine) { + handleDirtyCacheLine(orbEntry); + } + + // A flag which is used for retrying read requests + // in case one slot in ORB becomes available here + // (happens only for read hits) + bool canRetry = false; + + dram->respondEvent(orbEntry->dccPkt->rank); + + // Read Hit + if (orbEntry->owPkt->isRead() && + orbEntry->dccPkt->isDram() && + orbEntry->isHit) { + + DPRINTF(DCacheCtrl, "Read Hit: %lld\n", orbEntry->owPkt->getAddr()); + + + PacketPtr copyOwPkt = new Packet(orbEntry->owPkt, + false, + orbEntry->owPkt->isRead()); + + accessAndRespond(orbEntry->owPkt, + frontendLatency + backendLatency, + dram); + + ORB.at(copyOwPkt->getAddr()) = new reqBufferEntry(orbEntry->validEntry, + orbEntry->arrivalTick, + orbEntry->tagDC, + orbEntry->indexDC, + copyOwPkt, + orbEntry->dccPkt, + orbEntry->state, + orbEntry->issued, + orbEntry->isHit, + orbEntry->conflict, + orbEntry->dirtyLineAddr, + orbEntry->handleDirtyLine, + orbEntry->locRdEntered, + orbEntry->locRdIssued, + orbEntry->locRdExit, + orbEntry->locWrEntered, + orbEntry->locWrExit, + orbEntry->farRdEntered, + orbEntry->farRdIssued, + orbEntry->farRdRecvd, + orbEntry->farRdExit); + + delete orbEntry; + + orbEntry = ORB.at(addrLocRdRespReady.front()); + } + + // Write (Hit & Miss) + if (orbEntry->owPkt->isWrite() && + orbEntry->dccPkt->isRead() && + orbEntry->dccPkt->isDram()) { + // This is a write request which has done a tag check. + // Delete its dcc packet which is read and create + // a new one which is write. + delete orbEntry->dccPkt; + + orbEntry->dccPkt = dram->decodePacket(orbEntry->owPkt, + orbEntry->owPkt->getAddr(), + orbEntry->owPkt->getSize(), + false); + + orbEntry->dccPkt->entryTime = orbEntry->arrivalTick; + + // pass the second argument "false" to + // indicate a write access to DRAM + dram->setupRank(orbEntry->dccPkt->rank, false); + + //** transition to locMemWrite + orbEntry->state = locMemWrite; + orbEntry->issued = false; + orbEntry->locWrEntered = curTick(); + + pktLocMemWrite[0].push_back(orbEntry->dccPkt); + + dcstats.avgLocWrQLenEnq = pktLocMemWrite[0].size(); + + unsigned rdsNum = pktLocMemRead[0].size(); + unsigned wrsNum = pktLocMemWrite[0].size(); + + if ((rdsNum == 0 && wrsNum != 0) || + (wrsNum >= writeHighThreshold)) { + // stall reads, switch to writes + stallRds = true; + if (!locMemWriteEvent.scheduled() && !rescheduleLocWrite) { + schedule(locMemWriteEvent, + std::max(dram->nextReqTime, curTick())); + } + } + + if (pktLocMemWrite[0].size() > maxLocWrEvQ) { + maxLocWrEvQ = pktLocMemWrite[0].size(); + dcstats.maxLocWrEvQ = pktLocMemWrite[0].size(); + } + } + + // Read Miss + if (orbEntry->owPkt->isRead() && + orbEntry->dccPkt->isRead() && + orbEntry->dccPkt->isDram() && + !orbEntry->isHit) { + DPRINTF(DCacheCtrl, "Read Miss: %lld\n", orbEntry->owPkt->getAddr()); + // initiate a read from far memory + // delete the current dcc pkt which is for read from local memory + delete orbEntry->dccPkt; + + // orbEntry->dccPkt->entryTime = orbEntry->arrivalTick; + // orbEntry->dccPkt->readyTime = MaxTick; + //** transition to farMemRead + orbEntry->state = farMemRead; + orbEntry->issued = false; + orbEntry->farRdEntered = curTick(); + + // if (pktFarMemRead.empty() && sendFarRdReq) { + // assert(!farMemReadEvent.scheduled()); + // schedule(farMemReadEvent, std::max(dram->nextReqTime, curTick())); + // } else { + // assert(farMemReadEvent.scheduled() || !sendFarRdReq || waitingForRetryReqPort); + // } + + PacketPtr copyOwPkt_2 = new Packet(orbEntry->owPkt, + false, + orbEntry->owPkt->isRead()); + + pktFarMemRead.push_back(copyOwPkt_2); + + dcstats.avgFarRdQLenEnq = countFarRdInORB(); + + if (pktFarMemRead.size() > maxFarRdEvQ) { + maxFarRdEvQ = pktFarMemRead.size(); + dcstats.maxFarRdEvQ = pktFarMemRead.size(); + } + + if (!farMemReadEvent.scheduled() && sendFarRdReq && !waitingForRetryReqPort) { + schedule(farMemReadEvent, std::max(dram->nextReqTime, curTick())); + } + + if (pktFarMemRead.size() > maxFarRdEvQ) { + maxFarRdEvQ = pktFarMemRead.size(); + dcstats.maxFarRdEvQ = pktFarMemRead.size(); + } + } + + // if (orbEntry->handleDirtyLine) { + // numDirtyLinesInDrRdRespQ--; + // } + + addrLocRdRespReady.pop_front(); + + if (!addrLocRdRespReady.empty()) { + assert(ORB.at(addrLocRdRespReady.front())->dccPkt->readyTime + >= curTick()); + assert(!locMemReadRespEvent.scheduled()); + schedule(locMemReadRespEvent, + ORB.at(addrLocRdRespReady.front())->dccPkt->readyTime); + } else { + + unsigned rdsNum = pktLocMemRead[0].size(); + unsigned wrsNum = pktLocMemWrite[0].size(); + + // if there is nothing left in any queue, signal a drain + if (drainState() == DrainState::Draining && + !wrsNum && !rdsNum && + allIntfDrained()) { + DPRINTF(Drain, "Controller done draining\n"); + signalDrainDone(); + } else /*if (orbEntry->owPkt->isRead() && + orbEntry->dccPkt->isDram() && + orbEntry->isHit)*/ { + // check the refresh state and kick the refresh event loop + // into action again if banks already closed and just waiting + // for read to complete + dram->checkRefreshState(orbEntry->dccPkt->rank); + } + } + + if (orbEntry->owPkt->isRead() && + orbEntry->dccPkt->isDram() && + orbEntry->isHit) { + DPRINTF(DCacheCtrl, "resu conf: %lld\n", orbEntry->owPkt->getAddr()); + // Remove the request from the ORB and + // bring in a conflicting req waiting + // in the CRB, if any. + canRetry = !resumeConflictingReq(orbEntry); + } + + if (retry && canRetry) { + retry = false; + port.sendRetryReq(); + } +} + +void +DCacheCtrl::processLocMemWriteEvent() +{ + if (dram->isBusy(false, false) || rescheduleLocWrite) { + // it's possible that dram is busy and we reach here before + // reching to write_found check to set rescheduleLocWrite + if (dram->isBusy(false, false)) { + rescheduleLocWrite = true; + } + return; + } + + assert(stallRds); + + assert(!pktLocMemWrite[0].empty()); + + MemPacketQueue::iterator to_write; + + bool write_found = false; + + bool switched_cmd_type = (busState == DCacheCtrl::READ); + + if (switched_cmd_type) { + dcstats.rdToWrTurnAround++; + } + + for (auto queue = pktLocMemWrite.rbegin(); + queue != pktLocMemWrite.rend(); ++queue) { + to_write = chooseNext((*queue), switched_cmd_type ? + minReadToWriteDataGap() : 0, dram); + // to_write = chooseNext((*queue), 0, dram); + if (to_write != queue->end()) { + // candidate write found + write_found = true; + break; + } + } + + if (!write_found) { + // Probably dram is refreshing. + // Simply return, let the dram device + // reschedule again once refresh is done. + rescheduleLocWrite = true; + return; + } + + auto orbEntry = ORB.at((*to_write)->getAddr()); + + DPRINTF(DCacheCtrl, "LocWr: %lld\n", orbEntry->owPkt->getAddr()); + + bool canRetry = false; + + assert(orbEntry->validEntry); + + if (orbEntry->owPkt->isRead()) { + assert(!orbEntry->isHit); + } + assert(orbEntry->dccPkt->isDram()); + assert(orbEntry->state == locMemWrite); + //assert(orbEntry->dccPkt->size <= dram->bytesPerBurst()); + + busState = DCacheCtrl::WRITE; + + Tick cmdAt = MemCtrl::doBurstAccess(orbEntry->dccPkt, dram); + dcstats.QTLocWr += ((cmdAt - orbEntry->locWrEntered)/1000); + + orbEntry->locWrExit = orbEntry->dccPkt->readyTime; + + locWrCounter++; + + if (orbEntry->owPkt->isWrite()) { + // log the response + logResponse(DCacheCtrl::WRITE, + orbEntry->dccPkt->requestorId(), + orbEntry->dccPkt->qosValue(), + orbEntry->owPkt->getAddr(), + 1, + orbEntry->dccPkt->readyTime - orbEntry->arrivalTick); + } + + // Remove the request from the ORB and + // bring in a conflicting req waiting + // in the CRB, if any. + canRetry = !resumeConflictingReq(orbEntry); + + pktLocMemWrite[0].erase(to_write); + + if (retry && canRetry) { + retry = false; + port.sendRetryReq(); + } + + + if (locWrCounter < minLocWrPerSwitch && !pktLocMemWrite[0].empty() + // && !pktLocMemRead[0].empty() + ) { + // assert(!locMemWriteEvent.scheduled()); + stallRds = true; + if (!locMemWriteEvent.scheduled()) { + schedule(locMemWriteEvent, std::max(dram->nextReqTime, curTick())); + } + return; + } + else if (pktLocMemRead[0].empty() && !pktLocMemWrite[0].empty()) { + // assert(!locMemWriteEvent.scheduled()); + stallRds = true; + locWrCounter = 0; + if (!locMemWriteEvent.scheduled()) { + schedule(locMemWriteEvent, std::max(dram->nextReqTime, curTick())); + } + return; + } + else if (!pktLocMemRead[0].empty() && (pktLocMemWrite[0].empty()||locWrCounter>=(minLocWrPerSwitch))) { + // assert(!locMemReadEvent.scheduled()); + stallRds = false; + locWrCounter = 0; + if (!locMemReadEvent.scheduled()) { + schedule(locMemReadEvent, std::max(dram->nextReqTime, curTick())); + } + return; + } + else if (pktLocMemRead[0].empty() && pktLocMemWrite[0].empty()) { + stallRds = false; + locWrCounter = 0; + } +} + + +void +DCacheCtrl::processFarMemReadEvent() +{ + if (!sendFarRdReq || waitingForRetryReqPort) { + return; + } + + assert(!pktFarMemRead.empty()); + + auto rdPkt = pktFarMemRead.front(); + if (reqPort.sendTimingReq(rdPkt)) { + DPRINTF(DCacheCtrl, "FarRdSent: %lld\n", rdPkt->getAddr()); + pktFarMemRead.pop_front(); + dcstats.sentRdPort++; + ORB.at(rdPkt->getAddr())->farRdIssued = curTick(); + // delete rdPkt; + } else { + DPRINTF(DCacheCtrl, "FarRdRetry: %lld\n", rdPkt->getAddr()); + waitingForRetryReqPort = true; + dcstats.failedRdPort++; + return; + } + + if ((pktFarMemWrite.size() >= (orbMaxSize/2)) || + (!pktFarMemWrite.empty() && pktFarMemRead.empty())) { + + sendFarRdReq = false; + if (!farMemWriteEvent.scheduled()) { + schedule(farMemWriteEvent, curTick()+1000); + } + + return; + } + + if (!pktFarMemRead.empty() && !farMemReadEvent.scheduled()) { + + sendFarRdReq = true; + + schedule(farMemReadEvent, curTick()+1000); + + return; + } +} + +void +DCacheCtrl::processFarMemReadRespEvent() +{ + assert(!pktFarMemReadResp.empty()); + + auto orbEntry = ORB.at(pktFarMemReadResp.front()->getAddr()); + + DPRINTF(DCacheCtrl, "FarMemReadRespEvent %lld\n", orbEntry->owPkt->getAddr()); + + // sanity check for the chosen packet + assert(orbEntry->validEntry); + assert(orbEntry->state == farMemRead); + //assert(orbEntry->issued); + assert(orbEntry->owPkt->isRead()); + assert(!orbEntry->isHit); + + // Read miss from dram cache, now is available + // to send the response back to requestor + if (orbEntry->owPkt->isRead() && !orbEntry->isHit) { + + logResponse(DCacheCtrl::READ, + orbEntry->owPkt->requestorId(), + orbEntry->owPkt->qosValue(), + orbEntry->owPkt->getAddr(), 1, + curTick() - orbEntry->arrivalTick); + + PacketPtr copyOwPkt = new Packet(orbEntry->owPkt, + false, + orbEntry->owPkt->isRead()); + accessAndRespond(orbEntry->owPkt, + frontendLatency + backendLatency, + dram); + ORB.at(copyOwPkt->getAddr()) = new reqBufferEntry(orbEntry->validEntry, + orbEntry->arrivalTick, + orbEntry->tagDC, + orbEntry->indexDC, + copyOwPkt, + orbEntry->dccPkt, + orbEntry->state, + orbEntry->issued, + orbEntry->isHit, + orbEntry->conflict, + orbEntry->dirtyLineAddr, + orbEntry->handleDirtyLine, + orbEntry->locRdEntered, + orbEntry->locRdIssued, + orbEntry->locRdExit, + orbEntry->locWrEntered, + orbEntry->locWrExit, + orbEntry->farRdEntered, + orbEntry->farRdIssued, + orbEntry->farRdRecvd, + orbEntry->farRdExit); + delete orbEntry; + orbEntry = ORB.at(pktFarMemReadResp.front()->getAddr()); + + } + + orbEntry->dccPkt = dram->decodePacket(pktFarMemReadResp.front(), + pktFarMemReadResp.front()->getAddr(), + pktFarMemReadResp.front()->getSize(), + false); + orbEntry->dccPkt->entryTime = orbEntry->arrivalTick; + + // pass the second argument "false" to + // indicate a write access to DRAM + dram->setupRank(orbEntry->dccPkt->rank, false); + + //** transition to locMemWrite + orbEntry->state = locMemWrite; + orbEntry->issued = false; + orbEntry->farRdExit = curTick(); + orbEntry->locWrEntered = curTick(); + + pktLocMemWrite[0].push_back(orbEntry->dccPkt); + + dcstats.avgLocWrQLenEnq = pktLocMemWrite[0].size(); + + unsigned rdsNum = pktLocMemRead[0].size(); + unsigned wrsNum = pktLocMemWrite[0].size(); + + if ((rdsNum == 0 && wrsNum != 0) || + (wrsNum >= writeHighThreshold)) { + // stall reads, switch to writes + stallRds = true; + if (!locMemWriteEvent.scheduled() && !rescheduleLocWrite) { + schedule(locMemWriteEvent, + std::max(dram->nextReqTime, curTick())); + } + } + + if (pktLocMemWrite[0].size() > maxLocWrEvQ) { + maxLocWrEvQ = pktLocMemWrite[0].size(); + dcstats.maxLocWrEvQ = pktLocMemWrite[0].size(); + } + + delete pktFarMemReadResp.front(); + pktFarMemReadResp.pop_front(); + + if (!pktFarMemReadResp.empty() && !farMemReadRespEvent.scheduled()) { + schedule(farMemReadRespEvent, curTick()); + } + + /*std::cout << curTick() << " : " << + ORB.size() << ", " << + CRB.size() << ", " << + pktLocMemRead[0].size() << ", " << + pktLocMemWrite[0].size() << ", " << + pktFarMemRead.size() << ", " << + pktFarMemWrite.size() << ", " << + addrLocRdRespReady.size() << ", " << + pktFarMemReadResp.size() << " // " << + locMemReadEvent.scheduled() << ", " << + locMemWriteEvent.scheduled() << ", " << + farMemReadEvent.scheduled() << ", " << + farMemWriteEvent.scheduled() << ", " << + locMemReadRespEvent.scheduled() << ", " << + farMemReadRespEvent.scheduled() << " // " << + stallRds << ", " << + rescheduleLocRead << ", " << + rescheduleLocWrite << " // " << dram->isBusy(false, false) << "\n";*/ +} + +void +DCacheCtrl::processFarMemWriteEvent() +{ + assert(!pktFarMemWrite.empty()); + assert(!sendFarRdReq); + assert(!waitingForRetryReqPort); + auto wrPkt = pktFarMemWrite.front().second; + if (reqPort.sendTimingReq(wrPkt)) { + DPRINTF(DCacheCtrl, "FarWrSent: %lld\n", wrPkt->getAddr()); + dcstats.totTimeFarWrtoSend += ((curTick() - pktFarMemWrite.front().first)/1000); + pktFarMemWrite.pop_front(); + farWrCounter++; + dcstats.sentWrPort++; + } else { + DPRINTF(DCacheCtrl, "FarWrRetry: %lld\n", wrPkt->getAddr()); + waitingForRetryReqPort = true; + dcstats.failedWrPort++; + return; + } + + if (retryFMW && pktFarMemWrite.size()< (orbMaxSize / 2)) { + retryFMW = false; + port.sendRetryReq(); + } + + if (!pktFarMemWrite.empty() && + (farWrCounter < (orbMaxSize/8) || pktFarMemRead.empty())) { + + sendFarRdReq = false; + if (!farMemWriteEvent.scheduled()) { + schedule(farMemWriteEvent, curTick()+1000); + } + + return; + } + + if (farWrCounter >= (orbMaxSize/8) && !pktFarMemRead.empty()) { + + sendFarRdReq = true; + if (!farMemReadEvent.scheduled()) { + schedule(farMemReadEvent, curTick()+1000); + } + + return; + } +} + +void +DCacheCtrl::recvReqRetry() +{ + assert(waitingForRetryReqPort); + waitingForRetryReqPort = false; + + if (sendFarRdReq) { + if (!farMemReadEvent.scheduled()) { + schedule(farMemReadEvent, curTick()); + } + return; + } else { + if (!farMemWriteEvent.scheduled()) { + schedule(farMemWriteEvent, curTick()); + } + return; + } +} + +bool +DCacheCtrl::recvTimingResp(PacketPtr pkt) // This is equivalant of farMemReadRespEvent +{ + DPRINTF(DCacheCtrl, "recvTimingResp %lld, %s\n", pkt->getAddr(), pkt->cmdString()); + + if (pkt->isRead()) { + pktFarMemReadResp.push_back(pkt); + if (pktFarMemReadResp.size() > maxFarRdRespEvQ) { + maxFarRdRespEvQ = pktFarMemReadResp.size(); + dcstats.maxFarRdRespEvQ = pktFarMemReadResp.size(); + } + + if (!farMemReadRespEvent.scheduled()) { + schedule(farMemReadRespEvent, curTick()); + } + + ORB.at(pkt->getAddr())->farRdRecvd = curTick(); + dcstats.recvdRdPort++; + } else{ + assert(pkt->isWrite()); + + delete pkt; + } + + return true; +} + +bool +DCacheCtrl::requestEventScheduled(uint8_t pseudo_channel) const +{ + assert(pseudo_channel == 0); + return (locMemReadEvent.scheduled() || locMemWriteEvent.scheduled()); +} + +void +DCacheCtrl::restartScheduler(Tick tick, uint8_t pseudo_channel) +{ + assert(pseudo_channel == 0); + if (!stallRds) { + //assert(rescheduleLocRead); + rescheduleLocRead = false; + if (!locMemReadEvent.scheduled() && !pktLocMemRead[0].empty()) { + schedule(locMemReadEvent, tick); + } + return; + } else { + //assert(rescheduleLocWrite); + rescheduleLocWrite = false; + if (!locMemWriteEvent.scheduled() && !pktLocMemWrite[0].empty()) { + schedule(locMemWriteEvent, tick); + } + return; + } + +} + +Port & +DCacheCtrl::getPort(const std::string &if_name, PortID idx) +{ + panic_if(idx != InvalidPortID, "This object doesn't support vector ports"); + + // This is the name from the Python SimObject declaration (SimpleMemobj.py) + if (if_name == "port") { + return port; + } else if (if_name == "req_port") { + return reqPort; + } else { + // pass it along to our super class + return qos::MemCtrl::getPort(if_name, idx); + } +} + + +///////////////////////////////////////////////////////////////////////////////////////// + +bool +DCacheCtrl::checkConflictInDramCache(PacketPtr pkt) +{ + unsigned indexDC = returnIndexDC(pkt->getAddr(), pkt->getSize()); + + for (auto e = ORB.begin(); e != ORB.end(); ++e) { + if (indexDC == e->second->indexDC && e->second->validEntry) { + + e->second->conflict = true; + + return true; + } + } + return false; +} + +Addr +DCacheCtrl::returnIndexDC(Addr request_addr, unsigned size) +{ + int index_bits = ceilLog2(dramCacheSize/blockSize); + int block_bits = ceilLog2(size); + return bits(request_addr, block_bits + index_bits-1, block_bits); +} + +Addr +DCacheCtrl::returnTagDC(Addr request_addr, unsigned size) +{ + int index_bits = ceilLog2(dramCacheSize/blockSize); + int block_bits = ceilLog2(size); + return bits(request_addr, addrSize-1, (index_bits+block_bits)); +} + +void +DCacheCtrl::checkHitOrMiss(reqBufferEntry* orbEntry) +{ + // access the tagMetadataStore data structure to + // check if it's hit or miss + + // orbEntry->isHit = + // tagMetadataStore.at(orbEntry->indexDC).validLine && + // (orbEntry->tagDC == tagMetadataStore.at(orbEntry->indexDC).tagDC); + + // if (!tagMetadataStore.at(orbEntry->indexDC).validLine && + // !orbEntry->isHit) { + // dcstats.numColdMisses++; + // } else if (tagMetadataStore.at(orbEntry->indexDC).validLine && + // !orbEntry->isHit) { + // dcstats.numHotMisses++; + // } + + // always hit + // orbEntry->isHit = true; + + // always miss + // orbEntry->isHit = false; + + orbEntry->isHit = alwaysHit; +} + +bool +DCacheCtrl::checkDirty(Addr addr) +{ + // Addr index = returnIndexDC(addr, blockSize); + // return (tagMetadataStore.at(index).validLine && + // tagMetadataStore.at(index).dirtyLine); + + + // always dirty + // return true; + + // always clean + // return false; + + return alwaysDirty; +} + +void +DCacheCtrl::handleRequestorPkt(PacketPtr pkt) +{ + // Set is_read and is_dram to + // "true", to do initial DRAM Read + MemPacket* dcc_pkt = dram->decodePacket(pkt, + pkt->getAddr(), + pkt->getSize(), + true); + + // pass the second argument "true", for + // initial DRAM Read for all the received packets + dram->setupRank(dcc_pkt->rank, true); + + reqBufferEntry* orbEntry = new reqBufferEntry( + true, curTick(), + returnTagDC(pkt->getAddr(), pkt->getSize()), + returnIndexDC(pkt->getAddr(), pkt->getSize()), + pkt, dcc_pkt, + locMemRead, false, + false, false, + -1, false, + curTick(), MaxTick, MaxTick, + MaxTick, MaxTick, + MaxTick, MaxTick, MaxTick, MaxTick + ); + + ORB.emplace(pkt->getAddr(), orbEntry); + + // dcstats.avgORBLen = ORB.size(); + dcstats.avgORBLen = ORB.size(); + dcstats.avgLocRdQLenStrt = countLocRdInORB(); + dcstats.avgFarRdQLenStrt = countFarRdInORB(); + dcstats.avgLocWrQLenStrt = countLocWrInORB(); + dcstats.avgFarWrQLenStrt = countFarWr(); + + if (pkt->isRead()) { + logRequest(DCacheCtrl::READ, pkt->requestorId(), pkt->qosValue(), + pkt->getAddr(), 1); + } else { + //copying the packet + PacketPtr copyOwPkt = new Packet(pkt, false, pkt->isRead()); + + accessAndRespond(pkt, frontendLatency, dram); + + ORB.at(copyOwPkt->getAddr()) = new reqBufferEntry(orbEntry->validEntry, + orbEntry->arrivalTick, + orbEntry->tagDC, + orbEntry->indexDC, + copyOwPkt, + orbEntry->dccPkt, + orbEntry->state, + orbEntry->issued, + orbEntry->isHit, + orbEntry->conflict, + orbEntry->dirtyLineAddr, + orbEntry->handleDirtyLine, + orbEntry->locRdEntered, + orbEntry->locRdIssued, + orbEntry->locRdExit, + orbEntry->locWrEntered, + orbEntry->locWrExit, + orbEntry->farRdEntered, + orbEntry->farRdIssued, + orbEntry->farRdRecvd, + orbEntry->farRdExit); + + delete orbEntry; + + orbEntry = ORB.at(copyOwPkt->getAddr()); + + logRequest(DCacheCtrl::WRITE, copyOwPkt->requestorId(), + copyOwPkt->qosValue(), + copyOwPkt->getAddr(), 1); + } + + checkHitOrMiss(orbEntry); + + if (checkDirty(orbEntry->owPkt->getAddr()) && !orbEntry->isHit) { + orbEntry->dirtyLineAddr = tagMetadataStore.at(orbEntry->indexDC).farMemAddr; + orbEntry->handleDirtyLine = true; + } + + // Updating Tag & Metadata + tagMetadataStore.at(orbEntry->indexDC).tagDC = orbEntry->tagDC; + tagMetadataStore.at(orbEntry->indexDC).indexDC = orbEntry->indexDC; + tagMetadataStore.at(orbEntry->indexDC).validLine = true; + + if (orbEntry->owPkt->isRead()) { + if (orbEntry->isHit) { + tagMetadataStore.at(orbEntry->indexDC).dirtyLine = + tagMetadataStore.at(orbEntry->indexDC).dirtyLine; + } else { + tagMetadataStore.at(orbEntry->indexDC).dirtyLine = false; + } + } else { + tagMetadataStore.at(orbEntry->indexDC).dirtyLine = true; + } + + tagMetadataStore.at(orbEntry->indexDC).farMemAddr = + orbEntry->owPkt->getAddr(); + + + Addr addr = pkt->getAddr(); + + unsigned burst_size = dram->bytesPerBurst(); + + unsigned size = std::min((addr | (burst_size - 1)) + 1, + addr + pkt->getSize()) - addr; + + if (pkt->isRead()) { + dcstats.readPktSize[ceilLog2(size)]++; + dcstats.readBursts++; + dcstats.requestorReadAccesses[pkt->requestorId()]++; + dcstats.readReqs++; + } else { + dcstats.writePktSize[ceilLog2(size)]++; + dcstats.writeBursts++; + dcstats.requestorWriteAccesses[pkt->requestorId()]++; + dcstats.writeReqs++; + } + + // std::cout << pkt->getAddr() << ", " << + // ORB.size() << ", " << + // countLocRdInORB() << ", " << + // countFarRdInORB() << ", " << + // countLocWrInORB() << ", " << + // countFarWr() << "\n"; +} + +bool +DCacheCtrl::resumeConflictingReq(reqBufferEntry* orbEntry) +{ + assert(orbEntry->dccPkt->readyTime != MaxTick); + assert(orbEntry->dccPkt->readyTime >= curTick()); + dcstats.totPktsServiceTime += ((orbEntry->locWrExit - orbEntry->arrivalTick)/1000); + dcstats.totPktsORBTime += ((curTick() - orbEntry->arrivalTick)/1000); + dcstats.totTimeFarRdtoSend += ((orbEntry->farRdIssued - orbEntry->farRdEntered)/1000); + dcstats.totTimeFarRdtoRecv += ((orbEntry->farRdRecvd - orbEntry->farRdIssued)/1000); + dcstats.totTimeInLocRead += ((orbEntry->locRdExit - orbEntry->locRdEntered)/1000); + dcstats.totTimeInLocWrite += ((orbEntry->locWrExit - orbEntry->locWrEntered)/1000); + dcstats.totTimeInFarRead += ((orbEntry->farRdExit - orbEntry->farRdEntered)/1000); + + // std::cout << (orbEntry->farRdRecvd-orbEntry->arrivalTick)/1000 << ", " << orbEntry->arrivalTick << ", " << orbEntry->farRdRecvd << "\n"; + + // std::cout << ((orbEntry->locWrExit - orbEntry->arrivalTick)/1000) << ", " << + // ((orbEntry->locRdExit - orbEntry->locRdEntered)/1000) << ", " << + // ((orbEntry->locWrExit - orbEntry->locWrEntered)/1000) << ", " << + // ((orbEntry->farRdExit - orbEntry->farRdEntered)/1000) << ", " << + // ((orbEntry->farRdIssued - orbEntry->farRdEntered)/1000) << ", " << + // ((orbEntry->farRdRecvd - orbEntry->farRdIssued)/1000) << "\n"; + + bool conflictFound = false; + + if (orbEntry->owPkt->isWrite()) { + isInWriteQueue.erase(orbEntry->owPkt->getAddr()); + } + + logStatsDcache(orbEntry); + + for (auto e = CRB.begin(); e != CRB.end(); ++e) { + + auto entry = *e; + + if (returnIndexDC(entry.second->getAddr(), entry.second->getSize()) + == orbEntry->indexDC) { + + conflictFound = true; + + Addr confAddr = entry.second->getAddr(); + + ORB.erase(orbEntry->owPkt->getAddr()); + + delete orbEntry->owPkt; + + delete orbEntry->dccPkt; + + delete orbEntry; + + handleRequestorPkt(entry.second); + + ORB.at(confAddr)->arrivalTick = entry.first; + + CRB.erase(e); + + checkConflictInCRB(ORB.at(confAddr)); + + pktLocMemRead[0].push_back(ORB.at(confAddr)->dccPkt); + + dcstats.avgLocRdQLenEnq = pktLocMemRead[0].size() + addrLocRdRespReady.size(); + + if (!stallRds && !rescheduleLocRead && !locMemReadEvent.scheduled()) { + schedule(locMemReadEvent, std::max(dram->nextReqTime, curTick())); + } + + if (pktLocMemRead[0].size() > maxLocRdEvQ) { + maxLocRdEvQ = pktLocMemRead[0].size(); + dcstats.maxLocRdEvQ = pktLocMemRead[0].size(); + } + + break; + } + + } + + if (!conflictFound) { + + ORB.erase(orbEntry->owPkt->getAddr()); + + delete orbEntry->owPkt; + + delete orbEntry->dccPkt; + + delete orbEntry; + } + + return conflictFound; +} + +void +DCacheCtrl::checkConflictInCRB(reqBufferEntry* orbEntry) +{ + for (auto e = CRB.begin(); e != CRB.end(); ++e) { + + auto entry = *e; + + if (returnIndexDC(entry.second->getAddr(),entry.second->getSize()) + == orbEntry->indexDC) { + orbEntry->conflict = true; + break; + } + } +} + +void +DCacheCtrl::logStatsDcache(reqBufferEntry* orbEntry) +{ + +} + +void +DCacheCtrl::handleDirtyCacheLine(reqBufferEntry* orbEntry) +{ + assert(orbEntry->dirtyLineAddr != -1); + + // create a new request packet + PacketPtr wbPkt = getPacket(orbEntry->dirtyLineAddr, + orbEntry->owPkt->getSize(), + MemCmd::WriteReq); + + pktFarMemWrite.push_back(std::make_pair(curTick(), wbPkt)); + + dcstats.avgFarWrQLenEnq = pktFarMemWrite.size(); + + if ( + ((pktFarMemWrite.size() >= (orbMaxSize/2)) || (!pktFarMemWrite.empty() && pktFarMemRead.empty())) && + !waitingForRetryReqPort + ) { + sendFarRdReq = false; + if (!farMemWriteEvent.scheduled()) { + schedule(farMemWriteEvent, curTick()); + } + } + + if (pktFarMemWrite.size() > maxFarWrEvQ) { + maxFarWrEvQ = pktFarMemWrite.size(); + dcstats.maxFarWrEvQ = pktFarMemWrite.size(); + } + + dcstats.numWrBacks++; +} + +PacketPtr +DCacheCtrl::getPacket(Addr addr, unsigned size, const MemCmd& cmd, + Request::FlagsType flags) +{ + // Create new request + RequestPtr req = std::make_shared(addr, size, flags, + 0); + // Dummy PC to have PC-based prefetchers latch on; get entropy into higher + // bits + req->setPC(((Addr)0) << 2); + + // Embed it in a packet + PacketPtr pkt = new Packet(req, cmd); + + uint8_t* pkt_data = new uint8_t[req->getSize()]; + pkt->dataDynamic(pkt_data); + + if (cmd.isWrite()) { + std::fill_n(pkt_data, req->getSize(), (uint8_t)0); + } + + return pkt; +} + + + +void +DCacheCtrl::dirtAdrGen() +{ + for (int i=0; istate == locMemRead) { + count++; + } + } + return count; +} + +unsigned +DCacheCtrl::countFarRdInORB() +{ + unsigned count =0; + for (auto i : ORB) { + if (i.second->state == farMemRead) { + count++; + } + } + return count; +} + +unsigned +DCacheCtrl::countLocWrInORB() +{ + unsigned count =0; + for (auto i : ORB) { + if (i.second->state == locMemWrite) { + count++; + } + } + return count; +} + +unsigned +DCacheCtrl::countFarWr() +{ + return pktFarMemWrite.size(); +} + + + +/* reqBufferEntry* +DCacheCtrl::makeOrbEntry(reqBufferEntry* orbEntry, PacketPtr copyOwPkt) +{ + return new reqBufferEntry(orbEntry->validEntry, + orbEntry->arrivalTick, + orbEntry->tagDC, + orbEntry->indexDC, + copyOwPkt, + orbEntry->dccPkt, + orbEntry->state, + orbEntry->issued, + orbEntry->isHit, + orbEntry->conflict, + orbEntry->dirtyLineAddr, + orbEntry->handleDirtyLine, + orbEntry->locRdEntered, + orbEntry->locRdIssued, + orbEntry->locRdExit, + orbEntry->locWrEntered, + orbEntry->locWrExit, + orbEntry->farRdEntered, + orbEntry->farRdIssued, + orbEntry->farRdRecvd, + orbEntry->farRdExit); +} */ + +} // namespace memory +} // namespace gem5 diff --git a/src/mem/dram_cache_ctrl.hh b/src/mem/dram_cache_ctrl.hh new file mode 100644 index 0000000000..20f4b4fde3 --- /dev/null +++ b/src/mem/dram_cache_ctrl.hh @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2012-2020 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Copyright (c) 2013 Amin Farmahini-Farahani + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * DCacheCtrl declaration + */ + +#ifndef __DCACHE_CTRL_HH__ +#define __DCACHE_CTRL_HH__ + +#include "mem/mem_ctrl.hh" +#include "params/DCacheCtrl.hh" +#include + +namespace gem5 +{ + +namespace memory +{ +class DCacheCtrl : public MemCtrl +{ + private: + + class RequestPortDCache : public RequestPort + { + public: + + RequestPortDCache(const std::string& name, DCacheCtrl& _ctrl) + : RequestPort(name, &_ctrl), ctrl(_ctrl) + { } + + protected: + + void recvReqRetry() + { ctrl.recvReqRetry(); } + + bool recvTimingResp(PacketPtr pkt) + { return ctrl.recvTimingResp(pkt); } + + // to send timing requests it calls bool sendTimingReq(PacketPtr pkt); + + // void recvTimingSnoopReq(PacketPtr pkt) { } + + // void recvFunctionalSnoop(PacketPtr pkt) { } + + // Tick recvAtomicSnoop(PacketPtr pkt) { return 0; } + + private: + + DCacheCtrl& ctrl; + + }; + + /** + * Outcoming port, for a multi-ported controller add a crossbar + * in front of it + */ + RequestPortDCache reqPort; + + /** + * The following are basic design parameters of the unified + * DRAM cache controller, and are initialized based on parameter values. + * The rowsPerBank is determined based on the capacity, number of + * ranks and banks, the burst size, and the row buffer size. + */ + + unsigned long long dramCacheSize; + unsigned blockSize; + unsigned addrSize; + unsigned orbMaxSize; + unsigned orbSize; + unsigned crbMaxSize; + unsigned crbSize; + bool alwaysHit; + bool alwaysDirty; + + struct tagMetaStoreEntry + { + // DRAM cache related metadata + Addr tagDC; + Addr indexDC; + // constant to indicate that the cache line is valid + bool validLine = false; + // constant to indicate that the cache line is dirty + bool dirtyLine = false; + Addr farMemAddr; + }; + + /** A storage to keep the tag and metadata for the + * DRAM Cache entries. + */ + std::vector tagMetadataStore; + + /** Different states a packet can transition from one + * to the other while it's process in the DRAM Cache + * Controller. + */ + enum reqState + { + locMemRead, locMemWrite, + farMemRead, farMemWrite + }; + + /** + * A class for the entries of the + * outstanding request buffer (ORB). + */ + class reqBufferEntry + { + public: + + bool validEntry; + Tick arrivalTick; + + // DRAM cache related metadata + Addr tagDC; + Addr indexDC; + + // pointer to the outside world (ow) packet received from llc + const PacketPtr owPkt; + + // pointer to the dram cache controller (dcc) packet + MemPacket* dccPkt; + + reqState state; + bool issued; + bool isHit; + bool conflict; + + Addr dirtyLineAddr; + bool handleDirtyLine; + + // recording the tick when the req transitions into a new stats. + // The subtract between each two consecutive states entrance ticks, + // is the number of ticks the req spent in the proceeded state. + // The subtract between entrance and issuance ticks for each state, + // is the number of ticks for waiting time in that state. + Tick locRdEntered; + Tick locRdIssued; + Tick locRdExit; + Tick locWrEntered; + Tick locWrExit; + Tick farRdEntered; + Tick farRdIssued; + Tick farRdRecvd; + Tick farRdExit; + + reqBufferEntry( + bool _validEntry, Tick _arrivalTick, + Addr _tagDC, Addr _indexDC, + PacketPtr _owPkt, MemPacket* _dccPkt, + reqState _state, bool _issued, + bool _isHit, bool _conflict, + Addr _dirtyLineAddr, bool _handleDirtyLine, + Tick _locRdEntered, Tick _locRdIssued, Tick _locRdExit, + Tick _locWrEntered, Tick _locWrExit, + Tick _farRdEntered, Tick _farRdIssued, Tick _farRdRecvd, Tick _farRdExit) + : + validEntry(_validEntry), arrivalTick(_arrivalTick), + tagDC(_tagDC), indexDC(_indexDC), + owPkt( _owPkt), dccPkt(_dccPkt), + state(_state), issued(_issued), + isHit(_isHit), conflict(_conflict), + dirtyLineAddr(_dirtyLineAddr), handleDirtyLine(_handleDirtyLine), + locRdEntered(_locRdEntered), locRdIssued(_locRdIssued), locRdExit(_locRdExit), + locWrEntered(_locWrEntered), locWrExit(_locWrExit), + farRdEntered(_farRdEntered), farRdIssued(_farRdIssued), farRdRecvd(_farRdRecvd), farRdExit(_farRdExit) + { } + }; + + /** + * This is the outstanding request buffer (ORB) data + * structure, the main DS within the DRAM Cache + * Controller. The key is the address, for each key + * the map returns a reqBufferEntry which maintains + * the entire info related to that address while it's + * been processed in the DRAM Cache controller. + */ + std::map ORB; + + typedef std::pair timeReqPair; + /** + * This is the second important data structure + * within the DRAM cache controller which holds + * received packets that had conflict with some + * other address(s) in the DRAM Cache that they + * are still under process in the controller. + * Once thoes addresses are finished processing, + * Conflicting Requets Buffre (CRB) is consulted + * to see if any packet can be moved into the + * outstanding request buffer and start being + * processed in the DRAM cache controller. + */ + std::vector CRB; + + /** + * This is a unified retry flag for both reads and writes. + * It helps remember if we have to retry a request when available. + */ + bool retry; + bool retryFMW; + + // Counters and flags to keep track of read/write switchings + // stallRds: A flag to stop processing reads and switching to writes + bool stallRds; + bool sendFarRdReq; + bool waitingForRetryReqPort; + bool rescheduleLocRead; + bool rescheduleLocWrite; + float locWrDrainPerc; + unsigned minLocWrPerSwitch; + unsigned minFarWrPerSwitch; + unsigned locWrCounter; + unsigned farWrCounter; + + /** + * A queue for evicted dirty lines of DRAM cache, + * to be written back to the backing memory. + * These packets are not maintained in the ORB. + */ + std::deque pktFarMemWrite; + + // Maintenance Queues + std::vector pktLocMemRead; + std::vector pktLocMemWrite; + std::deque pktFarMemRead; + std::deque pktFarMemReadResp; + + std::deque addrLocRdRespReady; + //std::deque addrFarRdRespReady; + + // Maintenance variables + unsigned maxConf, maxLocRdEvQ, maxLocRdRespEvQ, + maxLocWrEvQ, maxFarRdEvQ, maxFarRdRespEvQ, maxFarWrEvQ; + + // needs be reimplemented + bool recvTimingReq(PacketPtr pkt) override; + + void accessAndRespond(PacketPtr pkt, Tick static_latency, + MemInterface* mem_intr) override; + + // events + void processLocMemReadEvent(); + EventFunctionWrapper locMemReadEvent; + + void processLocMemReadRespEvent(); + EventFunctionWrapper locMemReadRespEvent; + + void processLocMemWriteEvent(); + EventFunctionWrapper locMemWriteEvent; + + void processFarMemReadEvent(); + EventFunctionWrapper farMemReadEvent; + + void processFarMemReadRespEvent(); + EventFunctionWrapper farMemReadRespEvent; + + void processFarMemWriteEvent(); + EventFunctionWrapper farMemWriteEvent; + + // management functions + void printQSizes(); + void handleRequestorPkt(PacketPtr pkt); + void checkHitOrMiss(reqBufferEntry* orbEntry); + bool checkDirty(Addr addr); + void handleDirtyCacheLine(reqBufferEntry* orbEntry); + bool checkConflictInDramCache(PacketPtr pkt); + void checkConflictInCRB(reqBufferEntry* orbEntry); + bool resumeConflictingReq(reqBufferEntry* orbEntry); + void logStatsDcache(reqBufferEntry* orbEntry); + //reqBufferEntry* makeOrbEntry(reqBufferEntry* orbEntry, PacketPtr copyOwPkt); + PacketPtr getPacket(Addr addr, unsigned size, const MemCmd& cmd, Request::FlagsType flags = 0); + void dirtAdrGen(); + + unsigned countLocRdInORB(); + unsigned countFarRdInORB(); + unsigned countLocWrInORB(); + unsigned countFarWr(); + + Addr returnIndexDC(Addr pkt_addr, unsigned size); + Addr returnTagDC(Addr pkt_addr, unsigned size); + + // port management + void recvReqRetry(); + + void retryReq(); + + bool recvTimingResp(PacketPtr pkt); + + /** Packet waiting to be sent. */ + PacketPtr retryPkt; + + /** Tick when the stalled packet was meant to be sent. */ + // Tick retryPktTick; + + /** Reqs waiting for response **/ + std::unordered_map waitingResp; + + unsigned maxOutstandingReqs = 0; + + struct DCCtrlStats : public statistics::Group + { + DCCtrlStats(DCacheCtrl &ctrl); + + void regStats() override; + + DCacheCtrl &ctrl; + + // All statistics that the model needs to capture + statistics::Scalar readReqs; + statistics::Scalar writeReqs; + statistics::Scalar readBursts; + statistics::Scalar writeBursts; + statistics::Scalar servicedByWrQ; + statistics::Scalar mergedWrBursts; + statistics::Scalar neitherReadNorWriteReqs; + // Average queue lengths + statistics::Average avgRdQLen; + statistics::Average avgWrQLen; + + statistics::Scalar numRdRetry; + statistics::Scalar numWrRetry; + statistics::Vector readPktSize; + statistics::Vector writePktSize; + statistics::Vector rdQLenPdf; + statistics::Vector wrQLenPdf; + statistics::Histogram rdPerTurnAround; + statistics::Histogram wrPerTurnAround; + + statistics::Scalar bytesReadWrQ; + statistics::Scalar bytesReadSys; + statistics::Scalar bytesWrittenSys; + // Average bandwidth + statistics::Formula avgRdBWSys; + statistics::Formula avgWrBWSys; + + statistics::Scalar totGap; + statistics::Formula avgGap; + + // per-requestor bytes read and written to memory + statistics::Vector requestorReadBytes; + statistics::Vector requestorWriteBytes; + + // per-requestor bytes read and written to memory rate + statistics::Formula requestorReadRate; + statistics::Formula requestorWriteRate; + + // per-requestor read and write serviced memory accesses + statistics::Vector requestorReadAccesses; + statistics::Vector requestorWriteAccesses; + + // per-requestor read and write total memory access latency + statistics::Vector requestorReadTotalLat; + statistics::Vector requestorWriteTotalLat; + + // per-requestor raed and write average memory access latency + statistics::Formula requestorReadAvgLat; + statistics::Formula requestorWriteAvgLat; + + statistics::Average avgORBLen; + statistics::Average avgLocRdQLenStrt; + statistics::Average avgLocWrQLenStrt; + statistics::Average avgFarRdQLenStrt; + statistics::Average avgFarWrQLenStrt; + + statistics::Average avgLocRdQLenEnq; + statistics::Average avgLocWrQLenEnq; + statistics::Average avgFarRdQLenEnq; + statistics::Average avgFarWrQLenEnq; + + + statistics::Scalar numWrBacks; + statistics::Scalar totNumConf; + statistics::Scalar totNumORBFull; + statistics::Scalar totNumConfBufFull; + + statistics::Scalar maxNumConf; + statistics::Scalar maxLocRdEvQ; + statistics::Scalar maxLocRdRespEvQ; + statistics::Scalar maxLocWrEvQ; + statistics::Scalar maxFarRdEvQ; + statistics::Scalar maxFarRdRespEvQ; + statistics::Scalar maxFarWrEvQ; + + statistics::Scalar rdToWrTurnAround; + statistics::Scalar wrToRdTurnAround; + + statistics::Scalar sentRdPort; + statistics::Scalar failedRdPort; + statistics::Scalar recvdRdPort; + statistics::Scalar sentWrPort; + statistics::Scalar failedWrPort; + + statistics::Scalar totPktsServiceTime; + statistics::Scalar totPktsORBTime; + statistics::Scalar totTimeFarRdtoSend; + statistics::Scalar totTimeFarRdtoRecv; + statistics::Scalar totTimeFarWrtoSend; + statistics::Scalar totTimeInLocRead; + statistics::Scalar totTimeInLocWrite; + statistics::Scalar totTimeInFarRead; + statistics::Scalar QTLocRd; + statistics::Scalar QTLocWr; + }; + + DCCtrlStats dcstats; + + public: + + DCacheCtrl(const DCacheCtrlParams &p); + + void init() override; + + Port &getPort(const std::string &if_name, + PortID idx=InvalidPortID) override; + + // TODO: write events + bool requestEventScheduled(uint8_t pseudo_channel = 0) const override; + void restartScheduler(Tick tick, uint8_t pseudo_channel = 0) override; + bool respondEventScheduled(uint8_t pseudo_channel = 0) const override { return locMemReadRespEvent.scheduled(); } + +}; + +} // namespace memory +} // namespace gem5 + +#endif //__DCACHE_CTRL_HH__ diff --git a/src/mem/dram_interface.cc b/src/mem/dram_interface.cc index 65e06db4d3..06aedcff50 100644 --- a/src/mem/dram_interface.cc +++ b/src/mem/dram_interface.cc @@ -44,8 +44,11 @@ #include "base/cprintf.hh" #include "base/trace.hh" #include "debug/DRAM.hh" +#include "debug/DRAMT.hh" #include "debug/DRAMPower.hh" #include "debug/DRAMState.hh" +#include "debug/MemCtrl.hh" +#include "enums/Policy.hh" #include "sim/system.hh" namespace gem5 @@ -59,6 +62,7 @@ namespace memory std::pair DRAMInterface::chooseNextFRFCFS(MemPacketQueue& queue, Tick min_col_at) const { + DPRINTF(DRAM, "in dram->chooseNextFRFCFS func\n"); std::vector earliest_banks(ranksPerChannel, 0); // Has minBankPrep been called to populate earliest_banks? @@ -93,13 +97,12 @@ DRAMInterface::chooseNextFRFCFS(MemPacketQueue& queue, Tick min_col_at) const const Tick col_allowed_at = pkt->isRead() ? bank.rdAllowedAt : bank.wrAllowedAt; - DPRINTF(DRAM, "%s checking DRAM packet in bank %d, row %d\n", - __func__, pkt->bank, pkt->row); + DPRINTF(DRAM, "%s : %d, %d, %d, checking DRAM packet in bank %d, row %d, min: %d, cmdRd/Wr: %d, act: %d, pre: %d\n", + __func__, queue.size(), pkt->isRead(), pkt->isTagCheck, pkt->bank, pkt->row, min_col_at/1000, col_allowed_at/1000, bank.actAllowedAt/1000, bank.preAllowedAt/1000); // check if rank is not doing a refresh and thus is available, // if not, jump to the next packet if (burstReady(pkt)) { - DPRINTF(DRAM, "%s bank %d - Rank %d available\n", __func__, pkt->bank, pkt->rank); @@ -137,6 +140,7 @@ DRAMInterface::chooseNextFRFCFS(MemPacketQueue& queue, Tick min_col_at) const std::tie(earliest_banks, hidden_bank_prep) = minBankPrep(queue, min_col_at); filled_earliest_banks = true; + DPRINTF(DRAM, "%s !filled_earliest_banks\n", __func__); } // bank is amongst first available banks @@ -154,12 +158,15 @@ DRAMInterface::chooseNextFRFCFS(MemPacketQueue& queue, Tick min_col_at) const if (hidden_bank_prep || !found_prepped_pkt) { selected_pkt_it = i; selected_col_at = col_allowed_at; + DPRINTF(DRAM, "%s behind the scenes: %d\n", __func__, bits(earliest_banks[pkt->rank], + pkt->bank, pkt->bank)); + } } } } else { DPRINTF(DRAM, "%s bank %d - Rank %d not available\n", __func__, - pkt->bank, pkt->rank); + pkt->bank, pkt->rank); } } } @@ -171,19 +178,20 @@ DRAMInterface::chooseNextFRFCFS(MemPacketQueue& queue, Tick min_col_at) const return std::make_pair(selected_pkt_it, selected_col_at); } -void +Tick DRAMInterface::activateBank(Rank& rank_ref, Bank& bank_ref, - Tick act_tick, uint32_t row) + Tick act_tick, uint32_t row, bool isTagCheck) { assert(rank_ref.actTicks.size() == activationLimit); // verify that we have command bandwidth to issue the activate // if not, shift to next burst window Tick act_at; - if (twoCycleActivate) + if (twoCycleActivate) { act_at = ctrl->verifyMultiCmd(act_tick, maxCommandsPerWindow, tAAD); - else + } else { act_at = ctrl->verifySingleCmd(act_tick, maxCommandsPerWindow, true); + } DPRINTF(DRAM, "Activate at tick %d\n", act_at); @@ -213,9 +221,10 @@ DRAMInterface::activateBank(Rank& rank_ref, Bank& bank_ref, // The next access has to respect tRAS for this bank bank_ref.preAllowedAt = act_at + tRAS; + // Respect the row-to-column command delay for both read and write cmds bank_ref.rdAllowedAt = std::max(act_at + tRCD_RD, bank_ref.rdAllowedAt); - bank_ref.wrAllowedAt = std::max(act_at + tRCD_WR, bank_ref.wrAllowedAt); + bank_ref.wrAllowedAt = isTagCheck ? std::max(act_at + tRCD_RD + tRTW_int, bank_ref.wrAllowedAt): std::max(act_at + tRCD_WR, bank_ref.wrAllowedAt); // start by enforcing tRRD for (int i = 0; i < banksPerRank; i++) { @@ -263,11 +272,13 @@ DRAMInterface::activateBank(Rank& rank_ref, Bank& bank_ref, DPRINTF(DRAM, "Enforcing tXAW with X = %d, next activate " "no earlier than %llu\n", activationLimit, rank_ref.actTicks.back() + tXAW); - for (int j = 0; j < banksPerRank; j++) + for (int j = 0; j < banksPerRank; j++) { // next activate must not happen before end of window rank_ref.banks[j].actAllowedAt = - std::max(rank_ref.actTicks.back() + tXAW, - rank_ref.banks[j].actAllowedAt); + std::max(rank_ref.actTicks.back() + tXAW, rank_ref.banks[j].actAllowedAt); + if (rank_ref.actTicks.back() + tXAW > rank_ref.banks[j].actAllowedAt) { + } + } } } @@ -278,6 +289,8 @@ DRAMInterface::activateBank(Rank& rank_ref, Bank& bank_ref, else if (rank_ref.activateEvent.when() > act_at) // move it sooner in time reschedule(rank_ref.activateEvent, act_at); + + return act_at; } void @@ -316,7 +329,7 @@ DRAMInterface::prechargeBank(Rank& rank_ref, Bank& bank, Tick pre_tick, assert(rank_ref.numBanksActive != 0); --rank_ref.numBanksActive; - DPRINTF(DRAM, "Precharging bank %d, rank %d at tick %lld, now got " + DPRINTF(DRAMT, "Precharging bank %d, rank %d at tick %lld, now got " "%d active\n", bank.bank, rank_ref.rank, pre_at, rank_ref.numBanksActive); @@ -350,9 +363,9 @@ DRAMInterface::doBurstAccess(MemPacket* mem_pkt, Tick next_burst_at, DPRINTF(DRAM, "Timing access to addr %#x, rank/bank/row %d %d %d\n", mem_pkt->addr, mem_pkt->rank, mem_pkt->bank, mem_pkt->row); + Tick act_at = MaxTick; // get the rank Rank& rank_ref = *ranks[mem_pkt->rank]; - assert(rank_ref.inRefIdleState()); // are we in or transitioning to a low-power state and have not scheduled @@ -382,28 +395,43 @@ DRAMInterface::doBurstAccess(MemPacket* mem_pkt, Tick next_burst_at, } // next we need to account for the delay in activating the page - Tick act_tick = std::max(bank_ref.actAllowedAt, curTick()); + Tick act_tick; + if (mem_pkt->isLocMem) { + if (polMan->locMemPolicy == enums::RambusTagProbOpt) { + act_tick = std::max(std::max(bank_ref.tagActAllowedAt, bank_ref.actAllowedAt), curTick()); + + if (bank_ref.tagActAllowedAt > bank_ref.actAllowedAt && bank_ref.tagActAllowedAt > curTick()) { + stats.actDelayedDueToTagAct++; + } + } else { + act_tick = std::max(bank_ref.actAllowedAt, curTick()); + } + } else { + act_tick = std::max(bank_ref.actAllowedAt, curTick()); + } // Record the activation and deal with all the global timing // constraints caused be a new activation (tRRD and tXAW) - activateBank(rank_ref, bank_ref, act_tick, mem_pkt->row); + act_at = activateBank(rank_ref, bank_ref, act_tick, mem_pkt->row, mem_pkt->isTagCheck); } // respect any constraints on the command (e.g. tRCD or tCCD) - const Tick col_allowed_at = mem_pkt->isRead() ? - bank_ref.rdAllowedAt : bank_ref.wrAllowedAt; + const Tick col_allowed_at = mem_pkt->isRead() ? bank_ref.rdAllowedAt : bank_ref.wrAllowedAt; // we need to wait until the bus is available before we can issue // the command; need to ensure minimum bus delay requirement is met Tick cmd_at = std::max({col_allowed_at, next_burst_at, curTick()}); + // verify that we have command bandwidth to issue the burst // if not, shift to next burst window Tick max_sync = clkResyncDelay + (mem_pkt->isRead() ? tRL : tWL); - if (dataClockSync && ((cmd_at - rank_ref.lastBurstTick) > max_sync)) + if (dataClockSync && ((cmd_at - rank_ref.lastBurstTick) > max_sync)) { cmd_at = ctrl->verifyMultiCmd(cmd_at, maxCommandsPerWindow, tCK); - else + } + else { cmd_at = ctrl->verifySingleCmd(cmd_at, maxCommandsPerWindow, false); + } // if we are interleaving bursts, ensure that // 1) we don't double interleave on next burst issue @@ -421,15 +449,217 @@ DRAMInterface::doBurstAccess(MemPacket* mem_pkt, Tick next_burst_at, cmd_at = rank_ref.lastBurstTick + tBURST; } } + DPRINTF(DRAM, "Schedule RD/WR burst at tick %d\n", cmd_at); // update the packet ready time - if (mem_pkt->isRead()) { - mem_pkt->readyTime = cmd_at + tRL + tBURST; + Tick stall_delay = 0; + if(mem_pkt->isTagCheck) { + + assert(mem_pkt->isLocMem); + + // Calculating the tag check ready time + if (mem_pkt->pkt->owIsRead) { + assert((cmd_at + tRCD_FAST + tRL_FAST) > tRCD_RD); + mem_pkt->tagCheckReady = (cmd_at + tRCD_FAST + tRL_FAST) - tRCD_RD; + } else { + assert((cmd_at + tRCD_FAST + tRL_FAST) > (tRCD_RD + tRTW_int)); + mem_pkt->tagCheckReady = (cmd_at + tRCD_FAST + tRL_FAST) - (tRCD_RD + tRTW_int); + } + stats.tagResBursts++; + + // tag is sent back only for Rd Miss Cleans, for other cases tag is already known. + if (!mem_pkt->pkt->owIsRead && !mem_pkt->pkt->isHit && mem_pkt->pkt->isDirty) { + mem_pkt->tagCheckReady += tTAGBURST; + stats.tagBursts++; + } + + if (polMan->locMemPolicy == enums::RambusTagProbOpt) { + assert((mem_pkt->tagCheckReady + tRC_FAST) > (tRL_FAST + tRCD_FAST)); + bank_ref.tagActAllowedAt = (mem_pkt->tagCheckReady + tRC_FAST) - (tRL_FAST + tRCD_FAST); + } + + // Calculating the data ready time + if (mem_pkt->pkt->owIsRead) { + + mem_pkt->readyTime = cmd_at + std::max(tRL, tRL_FAST + tHM2DQ) + tBURST; + + // Rd Miss Clean + if (mem_pkt->pkt->owIsRead && !mem_pkt->pkt->isHit && !mem_pkt->pkt->isDirty) { + + if (!flushBuffer.empty()) { + + assert(!mem_pkt->pkt->hasDirtyData); + mem_pkt->pkt->hasDirtyData = true; + + assert(mem_pkt->pkt->dirtyLineAddr == -1); + mem_pkt->pkt->dirtyLineAddr = flushBuffer.front(); + + flushBuffer.pop_front(); + + stats.totReadFBByRdMC++; + + DPRINTF(DRAM, "Rd M C !FB.empty: %x\n", mem_pkt->pkt->dirtyLineAddr); + } + else { + DPRINTF(DRAM, "Rd M C FB.empty: %x\n", mem_pkt->pkt->dirtyLineAddr); + } + } + + // Rd Miss Dirty + if (mem_pkt->pkt->owIsRead && !mem_pkt->pkt->isHit && mem_pkt->pkt->isDirty) { + + assert(mem_pkt->pkt->dirtyLineAddr != -1); + + assert(!mem_pkt->pkt->hasDirtyData); + + mem_pkt->pkt->hasDirtyData = true; + + DPRINTF(DRAM, "Rd M D: %x\n", mem_pkt->addr); + } + + // stats + // Every respQueue which will generate an event, increment count + ++rank_ref.outstandingEvents; + + if (!(mem_pkt->pkt->owIsRead && !mem_pkt->pkt->isHit && !mem_pkt->pkt->isDirty && !mem_pkt->pkt->hasDirtyData)) { + stats.readBursts++; + if (row_hit) { + stats.readRowHits++; + } + stats.bytesRead += burstSize; + } + + if (!(mem_pkt->pkt->owIsRead && !mem_pkt->pkt->isHit && !mem_pkt->pkt->isDirty)) { + stats.perBankRdBursts[mem_pkt->bankId]++; + // Update latency stats + stats.totMemAccLat += mem_pkt->readyTime - mem_pkt->entryTime; + stats.totQLat += cmd_at - mem_pkt->entryTime; + stats.totBusLat += tBURST; + } else { + stats.totMemAccLat += mem_pkt->tagCheckReady - mem_pkt->entryTime; + stats.totQLat += cmd_at - mem_pkt->entryTime; + stats.totBusLat += tBURST; + stats.readMC++; + } + + // Update latency stats + // stats.totMemAccLat += mem_pkt->readyTime - mem_pkt->entryTime; + // stats.totQLat += cmd_at - mem_pkt->entryTime; + // stats.totBusLat += tBURST; + } + // Wr + else { + assert(!mem_pkt->pkt->owIsRead); + + mem_pkt->readyTime = cmd_at + tWL + tBURST; + + if (!mem_pkt->pkt->isHit && mem_pkt->pkt->isDirty) { + + DPRINTF(DRAM, "Wr M D: %x\n", mem_pkt->addr); + + Tick pushBackFBTick = cmd_at + tCCD_L; + + if (tempFlushBuffer.empty()) { + assert(!addToFlushBufferEvent.scheduled()); + schedule(addToFlushBufferEvent, pushBackFBTick); + } else { + assert(tempFlushBuffer.back().first <= pushBackFBTick); + assert(addToFlushBufferEvent.scheduled()); + } + + tempFlushBuffer.push_back(std::make_pair(pushBackFBTick, mem_pkt->pkt->dirtyLineAddr)); + + if ((tempFlushBuffer.size() + flushBuffer.size()) >= (banksPerRank * flushBufferHighThreshold) && + !readFlushBufferEvent.scheduled() && + !flushBuffer.empty()) { + + // Flush the flushBuffer and send some dirty data + // to the controller. + + assert(endOfReadFlushBuffPeriod == 0); + + assert(readFlushBufferCount == 0); + + stall_delay = tRFBD + (tempFlushBuffer.size() + flushBuffer.size()) * tBURST; + + mem_pkt->readyTime += stall_delay; + + endOfReadFlushBuffPeriod = cmd_at + tWL + stall_delay; + + schedule(readFlushBufferEvent, cmd_at + tWL + tRFBD + tBURST); + DPRINTF(DRAM, "wr M D Schd FBRdEv: %x at %d\n", mem_pkt->addr, cmd_at + tWL + tRFBD + tBURST); + + stats.totStallToFlushFB++; + + cmd_at += stall_delay; + } + + } + + // stats + if (!rank_ref.writeDoneEvent.scheduled()) { + schedule(rank_ref.writeDoneEvent, mem_pkt->readyTime); + // New event, increment count + ++rank_ref.outstandingEvents; + + } else if (rank_ref.writeDoneEvent.when() < mem_pkt->readyTime) { + reschedule(rank_ref.writeDoneEvent, mem_pkt->readyTime); + } + // will remove write from queue when returned to parent function + // decrement count for DRAM rank + --rank_ref.writeEntries; + + stats.writeBurstsTC++; + if (row_hit) { + stats.writeRowHits++; + } + stats.bytesWritten += burstSize; + stats.perBankWrBursts[mem_pkt->bankId]++; + + // Update latency stats + stats.totMemAccLatWrTC += mem_pkt->readyTime - mem_pkt->entryTime; + stats.totQLatWrTC += cmd_at - mem_pkt->entryTime; + stats.totBusLatWrTC += tBURST; + } + } else { - mem_pkt->readyTime = cmd_at + tWL + tBURST; + // assert(mem_pkt->tagCheckReady == MaxTick); + if (mem_pkt->isRead()) { + mem_pkt->readyTime = cmd_at + tRL + tBURST; + if (mem_pkt->isLocMem) { + if(polMan->locMemPolicy == enums::RambusTagProbOpt && + !mem_pkt->pkt->isHit && + mem_pkt->pkt->isDirty) { + // a probed Rd Miss Dirty + mem_pkt->pkt->hasDirtyData = true; + } + } + } else { + mem_pkt->readyTime = cmd_at + tWL + tBURST; + } } + // Tag probing B slot comes here. + // For now we only prob for read requests. + // NOTE: both tag check packets and regular packets can reach here. Thus: + // some mem_pkt may not have a ow pkt pointer, like fills! + if (mem_pkt->isLocMem) { + if (polMan->locMemPolicy == enums::RambusTagProbOpt) { + assert(mem_pkt->BSlotBusyUntil==MaxTick); + if (mem_pkt->isTagCheck) { + mem_pkt->BSlotBusyUntil = bank_ref.tagActAllowedAt - tRL_FAST + tRC_FAST; + } else { + mem_pkt->BSlotBusyUntil = std::max(act_at,bank_ref.tagActAllowedAt) + tRC_FAST; + } + } + } + + + DPRINTF(DRAMT, "curr pkt, addr: %d, isRd: %d, isTC: %d, bank %d, row %d, act: %d, RdAlw: %d, WrAlw: %d, cmd: %d, rdy: %d\n", + mem_pkt->getAddr(), mem_pkt->isRead(), mem_pkt->isTagCheck, (unsigned) mem_pkt->bank, (unsigned) mem_pkt->row, + act_at/1000, bank_ref.rdAllowedAt/1000, bank_ref.wrAllowedAt/1000, cmd_at/1000, mem_pkt->readyTime/1000); + rank_ref.lastBurstTick = cmd_at; // update the time for the next read/write burst for each @@ -447,16 +677,16 @@ DRAMInterface::doBurstAccess(MemPacket* mem_pkt, Tick next_burst_at, // tCCD_L_WR is required for write-to-write // Need to also take bus turnaround delays into account dly_to_rd_cmd = mem_pkt->isRead() ? - tCCD_L : std::max(tCCD_L, wrToRdDlySameBG); + tCCD_L : std::max(tCCD_L, wrToRdDlySameBG); // 2 : 13 wrToRdDlySameBG(tWL + _p.tBURST_MAX + _p.tWTR_L), dly_to_wr_cmd = mem_pkt->isRead() ? - std::max(tCCD_L, rdToWrDlySameBG) : + std::max(tCCD_L, rdToWrDlySameBG) : // 20 : 2 rdToWrDlySameBG(_p.tRTW + _p.tBURST_MAX), tCCD_L_WR; } else { // tBURST is default requirement for diff BG timing // Need to also take bus turnaround delays into account - dly_to_rd_cmd = mem_pkt->isRead() ? burst_gap : + dly_to_rd_cmd = mem_pkt->isRead() ? burst_gap : // 2 : 13 tBURST + tWTR + tWL; writeToReadDelay(); - dly_to_wr_cmd = mem_pkt->isRead() ? readToWriteDelay() : + dly_to_wr_cmd = mem_pkt->isRead() ? readToWriteDelay() : // 20 : 2 tBURST + tRTW; burst_gap; } } else { @@ -482,6 +712,7 @@ DRAMInterface::doBurstAccess(MemPacket* mem_pkt, Tick next_burst_at, bank_ref.preAllowedAt = std::max(bank_ref.preAllowedAt, mem_pkt->isRead() ? cmd_at + tRTP : mem_pkt->readyTime + tWR); + DPRINTF(DRAMT, "doBurstFunc, bank: %d, PRE: %d\n", (unsigned)bank_ref.bank, bank_ref.preAllowedAt/1000); // increment the bytes accessed and the accesses per row bank_ref.bytesAccessed += burstSize; @@ -572,50 +803,70 @@ DRAMInterface::doBurstAccess(MemPacket* mem_pkt, Tick next_burst_at, } // Update the stats and schedule the next request - if (mem_pkt->isRead()) { - // Every respQueue which will generate an event, increment count - ++rank_ref.outstandingEvents; - - stats.readBursts++; - if (row_hit) - stats.readRowHits++; - stats.bytesRead += burstSize; - stats.perBankRdBursts[mem_pkt->bankId]++; - - // Update latency stats - stats.totMemAccLat += mem_pkt->readyTime - mem_pkt->entryTime; - stats.totQLat += cmd_at - mem_pkt->entryTime; - stats.totBusLat += tBURST; + if (mem_pkt->isTagCheck) { + // stats are already calculated } else { - // Schedule write done event to decrement event count - // after the readyTime has been reached - // Only schedule latest write event to minimize events - // required; only need to ensure that final event scheduled covers - // the time that writes are outstanding and bus is active - // to holdoff power-down entry events - if (!rank_ref.writeDoneEvent.scheduled()) { - schedule(rank_ref.writeDoneEvent, mem_pkt->readyTime); - // New event, increment count + if (mem_pkt->isRead()) { + // Every respQueue which will generate an event, increment count ++rank_ref.outstandingEvents; - } else if (rank_ref.writeDoneEvent.when() < mem_pkt->readyTime) { - reschedule(rank_ref.writeDoneEvent, mem_pkt->readyTime); - } - // will remove write from queue when returned to parent function - // decrement count for DRAM rank - --rank_ref.writeEntries; + stats.readBursts++; + if (row_hit) { + stats.readRowHits++; + } + stats.bytesRead += burstSize; + stats.perBankRdBursts[mem_pkt->bankId]++; + + // Update latency stats + stats.totMemAccLat += mem_pkt->readyTime - mem_pkt->entryTime; + stats.totQLat += cmd_at - mem_pkt->entryTime; + stats.totBusLat += tBURST; + } else { + // Schedule write done event to decrement event count + // after the readyTime has been reached + // Only schedule latest write event to minimize events + // required; only need to ensure that final event scheduled covers + // the time that writes are outstanding and bus is active + // to holdoff power-down entry events + if (!rank_ref.writeDoneEvent.scheduled()) { + schedule(rank_ref.writeDoneEvent, mem_pkt->readyTime); + // New event, increment count + ++rank_ref.outstandingEvents; + + } else if (rank_ref.writeDoneEvent.when() < mem_pkt->readyTime) { + reschedule(rank_ref.writeDoneEvent, mem_pkt->readyTime); + } + // will remove write from queue when returned to parent function + // decrement count for DRAM rank + --rank_ref.writeEntries; + + stats.writeBursts++; + if (row_hit) { + stats.writeRowHits++; + } + stats.bytesWritten += burstSize; + stats.perBankWrBursts[mem_pkt->bankId]++; - stats.writeBursts++; - if (row_hit) - stats.writeRowHits++; - stats.bytesWritten += burstSize; - stats.perBankWrBursts[mem_pkt->bankId]++; + // Update latency stats + stats.totMemAccLatWr += mem_pkt->readyTime - mem_pkt->entryTime; + stats.totQLatWr += cmd_at - mem_pkt->entryTime; + stats.totBusLatWr += tBURST; + } } // Update bus state to reflect when previous command was issued return std::make_pair(cmd_at, cmd_at + burst_gap); } +void +DRAMInterface::updateTagActAllowed(unsigned rankNumber, unsigned bankNumber, Tick BSlotTagBankBusyAt) +{ + assert(BSlotTagBankBusyAt!=MaxTick); + ranks[rankNumber]->banks[bankNumber].tagActAllowedAt = BSlotTagBankBusyAt; + DPRINTF(DRAM, "updateTagFunc tagActAllowedAt change, rank/bank %d/%d -- tagActAllowedAt: %d\n", + rankNumber, bankNumber, BSlotTagBankBusyAt); +} + void DRAMInterface::addRankToRankDelay(Tick cmd_at) { @@ -646,24 +897,36 @@ DRAMInterface::DRAMInterface(const DRAMInterfaceParams &_p) tRFC(_p.tRFC), tREFI(_p.tREFI), tRRD(_p.tRRD), tRRD_L(_p.tRRD_L), tPPD(_p.tPPD), tAAD(_p.tAAD), tXAW(_p.tXAW), tXP(_p.tXP), tXS(_p.tXS), + tTAGBURST(_p.tTAGBURST), tRL_FAST(_p. tRL_FAST), tHM2DQ(_p.tHM2DQ), + tRTW_int(_p.tRTW_int), tRFBD(_p.tRFBD), tRCD_FAST(_p.tRCD_FAST), + tRC_FAST(_p.tRC_FAST), + flushBufferHighThreshold(_p.flushBuffer_high_thresh_perc / 100.0), clkResyncDelay(_p.tBURST_MAX), dataClockSync(_p.data_clock_sync), burstInterleave(tBURST != tBURST_MIN), twoCycleActivate(_p.two_cycle_activate), activationLimit(_p.activation_limit), - wrToRdDlySameBG(tWL + _p.tBURST_MAX + _p.tWTR_L), + wrToRdDlySameBG(tWL + _p.tBURST_MAX + _p.tWTR), rdToWrDlySameBG(_p.tRTW + _p.tBURST_MAX), + maxFBLen(0), pageMgmt(_p.page_policy), maxAccessesPerRow(_p.max_accesses_per_row), timeStampOffset(0), activeRank(0), enableDRAMPowerdown(_p.enable_dram_powerdown), lastStatsResetTick(0), - stats(*this) + // polMan(_p.pol_man), + stats(*this), + readFlushBufferEvent([this] {processReadFlushBufferEvent();}, name()), + addToFlushBufferEvent([this] {processAddToFlushBufferEvent();}, name()), + endOfReadFlushBuffPeriod(0), + readFlushBufferCount(0), + enableReadFlushBuffer(_p.enable_read_flush_buffer), + isAlloy(_p.is_alloy) { DPRINTF(DRAM, "Setting up DRAM Interface\n"); - fatal_if(!isPowerOf2(burstSize), "DRAM burst size %d is not allowed, " - "must be a power of two\n", burstSize); + // fatal_if(!isPowerOf2(burstSize), "DRAM burst size %d is not allowed, " + // "must be a power of two\n", burstSize); // sanity check the ranks since we rely on bit slicing for the // address decoding @@ -717,17 +980,19 @@ DRAMInterface::DRAMInterface(const DRAMInterfaceParams &_p) banksPerRank, bankGroupsPerRank); } // tCCD_L should be greater than minimal, back-to-back burst delay - if (tCCD_L <= tBURST) { + if (tCCD_L < tBURST) { fatal("tCCD_L (%d) should be larger than the minimum bus delay " "(%d) when bank groups per rank (%d) is greater than 1\n", tCCD_L, tBURST, bankGroupsPerRank); } + // tCCD_L_WR should be greater than minimal, back-to-back burst delay - if (tCCD_L_WR <= tBURST) { + if (tCCD_L_WR < tBURST) { fatal("tCCD_L_WR (%d) should be larger than the minimum bus delay " " (%d) when bank groups per rank (%d) is greater than 1\n", tCCD_L_WR, tBURST, bankGroupsPerRank); } + // tRRD_L is greater than minimal, same bank group ACT-to-ACT delay // some datasheets might specify it equal to tRRD if (tRRD_L < tRRD) { @@ -844,8 +1109,14 @@ DRAMInterface::decodePacket(const PacketPtr pkt, Addr pkt_addr, // always the top bits, and check before creating the packet uint64_t row; + Addr mappedAddr = pkt_addr; + + if (isAlloy) { + mappedAddr = ((pkt_addr / 64) * 8) + pkt_addr; + } + // Get packed address, starting at 0 - Addr addr = getCtrlAddr(pkt_addr); + Addr addr = getCtrlAddr(mappedAddr); // truncate the address to a memory burst, which makes it unique to // a specific buffer, row, bank, rank and channel @@ -905,8 +1176,8 @@ DRAMInterface::decodePacket(const PacketPtr pkt, Addr pkt_addr, assert(row < rowsPerBank); assert(row < Bank::NO_ROW); - DPRINTF(DRAM, "Address: %#x Rank %d Bank %d Row %d\n", - pkt_addr, rank, bank, row); + // DPRINTF(DRAM, "Address: %#x Rank %d Bank %d Row %d\n", + // pkt_addr, rank, bank, row); // create the corresponding memory packet with the entry time and // ready time set to the current tick, the latter will be updated @@ -927,6 +1198,113 @@ void DRAMInterface::setupRank(const uint8_t rank, const bool is_read) } } +void +DRAMInterface::setPolicyManager(AbstractMemory* _polMan) +{ + polMan = _polMan; +} + +void +DRAMInterface::processReadFlushBufferEvent() +{ + // It is possible that a ReadFlushBufferEvent is scheduled and + // before reaching to the scheduled time or concurrent with that, + // Read Miss Cleans also pop packet from flushBuffer. + // So, it should return for the scheduled event. + if (flushBuffer.empty()) { + if (readFlushBufferCount > 0) { + stats.avgReadFBPerEvent = readFlushBufferCount; + } + endOfReadFlushBuffPeriod = 0; + readFlushBufferCount = 0; + return; + } + + assert(endOfReadFlushBuffPeriod >= curTick()); + assert(flushBuffer.front() != -1); + + + if (polMan->recvReadFlushBuffer(flushBuffer.front())) { + DPRINTF(DRAM, "sent rd FB: %d\n", flushBuffer.front()); + readFlushBufferCount++; + flushBuffer.pop_front(); + stats.totReadFBSent++; + stats.readBursts++; + stats.bytesRead += burstSize; + stats.totBusLat += tBURST; + + Tick nextBurstFB = curTick() + tBURST; + + if (nextBurstFB <= endOfReadFlushBuffPeriod && !flushBuffer.empty()) { + schedule(readFlushBufferEvent, nextBurstFB); + return; + } else { + // Either the time is beyond the tRFC or flushBuffer is empty. + // Reset control params + stats.avgReadFBPerEvent = readFlushBufferCount; + endOfReadFlushBuffPeriod = 0; + readFlushBufferCount = 0; + return; + } + } else { + // Policy manager has no empty entry available in its write back buffer. + stats.totReadFBFailed++; + // End of readFlushBuffer round. + // Reset control params + stats.avgReadFBPerEvent = readFlushBufferCount; + endOfReadFlushBuffPeriod = 0; + readFlushBufferCount = 0; + return; + } +} + +void +DRAMInterface::processAddToFlushBufferEvent() +{ + assert(!tempFlushBuffer.empty()); + assert(tempFlushBuffer.front().first == curTick()); + + flushBuffer.push_back(tempFlushBuffer.front().second); + + DPRINTF(DRAM, "Wr M D to FB: %x\n", tempFlushBuffer.front().second); + + tempFlushBuffer.pop_front(); + + stats.totPktsPushedFB++; + + stats.avgFBLenEnq = flushBuffer.size(); + + if (flushBuffer.size() > maxFBLen) { + maxFBLen = flushBuffer.size(); + stats.maxFBLenEnq = flushBuffer.size(); + } + + if (!tempFlushBuffer.empty()) { + assert(tempFlushBuffer.front().first >= curTick()); + assert(!addToFlushBufferEvent.scheduled()); + schedule(addToFlushBufferEvent, tempFlushBuffer.front().first); + } + +} + +bool +DRAMInterface::checkFwdMrgeInFB(Addr addr) +{ + for (int i=0; i < flushBuffer.size(); i++) { + if (flushBuffer.at(i) == addr) { + return true; + } + } + + for (int i=0; i < tempFlushBuffer.size(); i++) { + if (tempFlushBuffer.at(i).second == addr) { + return true; + } + } + + return false; +} + void DRAMInterface::respondEvent(uint8_t rank) { @@ -1024,6 +1402,8 @@ DRAMInterface::suspend() } } +typedef std::pair got_waiting_pair; + std::pair, bool> DRAMInterface::minBankPrep(const MemPacketQueue& queue, Tick min_col_at) const @@ -1040,12 +1420,15 @@ DRAMInterface::minBankPrep(const MemPacketQueue& queue, // determine if we have queued transactions targetting the // bank in question - std::vector got_waiting(ranksPerChannel * banksPerRank, false); + std::vector got_waiting(ranksPerChannel * banksPerRank); for (const auto& p : queue) { - if (p->pseudoChannel != pseudoChannel) + if (p->pseudoChannel != pseudoChannel) { continue; - if (p->isDram() && ranks[p->rank]->inRefIdleState()) - got_waiting[p->bankId] = true; + } + if (p->isDram() && ranks[p->rank]->inRefIdleState()) { + got_waiting[p->bankId].first = true; + got_waiting[p->bankId].second = p->isTagCheck? true : false; + } } // Find command with optimal bank timing @@ -1056,7 +1439,7 @@ DRAMInterface::minBankPrep(const MemPacketQueue& queue, // if we have waiting requests for the bank, and it is // amongst the first available, update the mask - if (got_waiting[bank_id]) { + if (got_waiting[bank_id].first) { // make sure this rank is not currently refreshing. assert(ranks[i]->inRefIdleState()); // simplistic approximation of when the bank can issue @@ -1068,14 +1451,15 @@ DRAMInterface::minBankPrep(const MemPacketQueue& queue, // latest Tick for which ACT can occur without // incurring additoinal delay on the data bus - const Tick tRCD = ctrl->inReadBusState(false, this) ? - tRCD_RD : tRCD_WR; + const Tick tRCD = ctrl->inReadBusState(false, + (MemInterface*)(this)) ? tRCD_RD : + (got_waiting[bank_id].second ? tRCD_RD+tRTW_int : tRCD_WR); const Tick hidden_act_max = std::max(min_col_at - tRCD, curTick()); // When is the earliest the R/W burst can issue? const Tick col_allowed_at = ctrl->inReadBusState(false, - this) ? + (MemInterface*)(this)) ? ranks[i]->banks[j].rdAllowedAt : ranks[i]->banks[j].wrAllowedAt; Tick col_at = std::max(col_allowed_at, act_at + tRCD); @@ -1314,6 +1698,7 @@ DRAMInterface::Rank::processRefreshEvent() DPRINTF(DRAM, "Refresh awaiting draining\n"); return; } else { + DPRINTF(DRAM, "ELSE of Refresh awaiting draining\n"); refreshState = REF_PD_EXIT; } } @@ -1328,12 +1713,14 @@ DRAMInterface::Rank::processRefreshEvent() scheduleWakeUpEvent(dram.tXP); return; } else { + DPRINTF(DRAM, "ELSE of Wake Up for refresh\n"); refreshState = REF_PRE; } } // at this point, ensure that all banks are precharged if (refreshState == REF_PRE) { + DPRINTF(DRAM, "REF_PRE\n"); // precharge any active bank if (numBanksActive != 0) { // at the moment, we use a precharge all even if there is @@ -1378,6 +1765,7 @@ DRAMInterface::Rank::processRefreshEvent() // we are already idle schedulePowerEvent(PWR_REF, curTick()); } else { + DPRINTF(DRAM, "banks state is closed but... %d %d\n", prechargeEvent.scheduled(), dram.ctrl->respondEventScheduled()); // banks state is closed but haven't transitioned pwrState to IDLE // or have outstanding ACT,RD/WR,Auto-PRE sequence scheduled // should have outstanding precharge or read response event @@ -1400,6 +1788,20 @@ DRAMInterface::Rank::processRefreshEvent() // last but not least we perform the actual refresh if (refreshState == REF_START) { + dram.stats.totNumberRefreshEvent++; + if (dram.enableReadFlushBuffer && !dram.readFlushBufferEvent.scheduled()) { + // Time to be proactive and send some dirty data + // from flushBuffer to the controller. + assert(dram.endOfReadFlushBuffPeriod == 0); + assert(dram.readFlushBufferCount == 0); + + if (!dram.flushBuffer.empty()) { + dram.endOfReadFlushBuffPeriod = curTick() + dram.tRFC; + schedule(dram.readFlushBufferEvent, curTick() + dram.tRFBD + dram.tBURST); + dram.stats.refSchdRFB++; + } + } + // should never get here with any banks active assert(numBanksActive == 0); assert(pwrState == PWR_REF); @@ -1848,31 +2250,99 @@ DRAMInterface::DRAMStats::DRAMStats(DRAMInterface &_dram) ADD_STAT(readBursts, statistics::units::Count::get(), "Number of DRAM read bursts"), + ADD_STAT(readMC, statistics::units::Count::get(), + "Number of DRAM cache read miss cleans"), ADD_STAT(writeBursts, statistics::units::Count::get(), "Number of DRAM write bursts"), - + ADD_STAT(writeBurstsTC, statistics::units::Count::get(), + "Number of DRAM write bursts for tag check"), + ADD_STAT(tagResBursts, statistics::units::Count::get(), + "Number of tag bursts returned by write miss dirties"), + ADD_STAT(tagBursts, statistics::units::Count::get(), + "Number of tag check bursts"), + + ADD_STAT(avgFBLenEnq, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average flush buffer length when enqueuing"), + ADD_STAT(avgReadFBPerEvent, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average number of reads from flush buffer per event"), + ADD_STAT(totNumberRefreshEvent, statistics::units::Count::get(), + "Total number of refresh events"), + ADD_STAT(totReadFBSent, statistics::units::Count::get(), + "Total number of reads from flush buffer per event"), + ADD_STAT(totReadFBFailed, statistics::units::Count::get(), + "Total number of reads from flush buffer failed to be received by policy manager (write back buffer full)"), + ADD_STAT(totReadFBByRdMC, statistics::units::Count::get(), + "Total number of reads from flush buffer during Read Miss Clean"), + ADD_STAT(totStallToFlushFB, statistics::units::Count::get(), + "Total number of reads from flush buffer during Read Miss Clean"), + ADD_STAT(totPktsPushedFB, statistics::units::Count::get(), + "Total number of packets pushed into flush buffer"), + ADD_STAT(maxFBLenEnq, statistics::units::Count::get(), + "Maximum flush buffer length when enqueuing"), + ADD_STAT(refSchdRFB, statistics::units::Count::get(), + "Maximum flush buffer length when enqueuing"), + ADD_STAT( actDelayedDueToTagAct, statistics::units::Count::get(), + " "), ADD_STAT(perBankRdBursts, statistics::units::Count::get(), "Per bank write bursts"), ADD_STAT(perBankWrBursts, statistics::units::Count::get(), "Per bank write bursts"), ADD_STAT(totQLat, statistics::units::Tick::get(), - "Total ticks spent queuing"), + "Total ticks spent queuing for reads"), ADD_STAT(totBusLat, statistics::units::Tick::get(), - "Total ticks spent in databus transfers"), + "Total ticks spent in databus transfers for reads"), ADD_STAT(totMemAccLat, statistics::units::Tick::get(), "Total ticks spent from burst creation until serviced " - "by the DRAM"), + "by the DRAM for reads"), + + ADD_STAT(totQLatWr, statistics::units::Tick::get(), + "Total ticks spent queuing for writes"), + ADD_STAT(totBusLatWr, statistics::units::Tick::get(), + "Total ticks spent in databus transfers for writes"), + ADD_STAT(totMemAccLatWr, statistics::units::Tick::get(), + "Total ticks spent from burst creation until serviced " + "by the DRAM for writes"), + + ADD_STAT(totQLatWrTC, statistics::units::Tick::get(), + "Total ticks spent queuing for writes tag check"), + ADD_STAT(totBusLatWrTC, statistics::units::Tick::get(), + "Total ticks spent in databus transfers for writes tag check"), + ADD_STAT(totMemAccLatWrTC, statistics::units::Tick::get(), + "Total ticks spent from burst creation until serviced " + "by the DRAM for writes tag check"), ADD_STAT(avgQLat, statistics::units::Rate< statistics::units::Tick, statistics::units::Count>::get(), - "Average queueing delay per DRAM burst"), + "Average queueing delay per DRAM burst for reads"), ADD_STAT(avgBusLat, statistics::units::Rate< statistics::units::Tick, statistics::units::Count>::get(), - "Average bus latency per DRAM burst"), + "Average bus latency per DRAM burst for reads"), ADD_STAT(avgMemAccLat, statistics::units::Rate< statistics::units::Tick, statistics::units::Count>::get(), - "Average memory access latency per DRAM burst"), + "Average memory access latency per DRAM burst for reads"), + + ADD_STAT(avgQLatWr, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), + "Average queueing delay per DRAM burst for writes"), + ADD_STAT(avgBusLatWr, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), + "Average bus latency per DRAM burst for writes"), + ADD_STAT(avgMemAccLatWr, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), + "Average memory access latency per DRAM burst for writes"), + + ADD_STAT(avgQLatWrTC, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), + "Average queueing delay per DRAM burst for writes tag check"), + ADD_STAT(avgBusLatWrTC, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), + "Average bus latency per DRAM burst for writes tag check"), + ADD_STAT(avgMemAccLatWrTC, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), + "Average memory access latency per DRAM burst for writes tag check"), ADD_STAT(readRowHits, statistics::units::Count::get(), "Number of row buffer hits during reads"), @@ -1908,8 +2378,10 @@ DRAMInterface::DRAMStats::DRAMStats(DRAMInterface &_dram) "Data bus utilization in percentage for writes"), ADD_STAT(pageHitRate, statistics::units::Ratio::get(), - "Row buffer hit rate, read and write combined") + "Row buffer hit rate, read and write combined"), + ADD_STAT(hitMissBusUtil, statistics::units::Ratio::get(), + "Hit/Miss bus utilization") { } @@ -1922,6 +2394,16 @@ DRAMInterface::DRAMStats::regStats() avgBusLat.precision(2); avgMemAccLat.precision(2); + avgQLatWr.precision(2); + avgBusLatWr.precision(2); + avgMemAccLatWr.precision(2); + + avgQLatWrTC.precision(2); + avgBusLatWrTC.precision(2); + avgMemAccLatWrTC.precision(2); + + avgFBLenEnq.precision(2); + readRowHitRate.precision(2); writeRowHitRate.precision(2); @@ -1940,13 +2422,23 @@ DRAMInterface::DRAMStats::regStats() pageHitRate.precision(2); + hitMissBusUtil.precision(2); + // Formula stats - avgQLat = totQLat / readBursts; - avgBusLat = totBusLat / readBursts; - avgMemAccLat = totMemAccLat / readBursts; + avgQLat = totQLat / (readBursts+readMC); + avgBusLat = totBusLat / (readBursts+readMC); + avgMemAccLat = totMemAccLat / (readBursts+readMC); + + avgQLatWr = totQLatWr / writeBursts; + avgBusLatWr = totBusLatWr / writeBursts; + avgMemAccLatWr = totMemAccLatWr / writeBursts; + + avgQLatWrTC = totQLatWrTC / writeBurstsTC; + avgBusLatWrTC = totBusLatWrTC / writeBurstsTC; + avgMemAccLatWrTC = totMemAccLatWrTC / writeBurstsTC; readRowHitRate = (readRowHits / readBursts) * 100; - writeRowHitRate = (writeRowHits / writeBursts) * 100; + writeRowHitRate = (writeRowHits / (writeBursts+writeBurstsTC)) * 100; avgRdBW = (bytesRead / 1000000) / simSeconds; avgWrBW = (bytesWritten / 1000000) / simSeconds; @@ -1958,7 +2450,9 @@ DRAMInterface::DRAMStats::regStats() busUtilWrite = avgWrBW / peakBW * 100; pageHitRate = (writeRowHits + readRowHits) / - (writeBursts + readBursts) * 100; + (writeBursts + writeBurstsTC + readBursts) * 100; + + hitMissBusUtil = (((tagResBursts * dram.tCK) + (tagBursts * dram.tTAGBURST)) * 0.000000000001) / simSeconds * 100; } DRAMInterface::RankStats::RankStats(DRAMInterface &_dram, Rank &_rank) diff --git a/src/mem/dram_interface.hh b/src/mem/dram_interface.hh index e20e33faf9..f98f4d511b 100644 --- a/src/mem/dram_interface.hh +++ b/src/mem/dram_interface.hh @@ -48,7 +48,7 @@ #include "mem/drampower.hh" #include "mem/mem_interface.hh" -#include "params/DRAMInterface.hh" +// #include "mem/policy_manager.hh" namespace gem5 { @@ -519,6 +519,14 @@ class DRAMInterface : public MemInterface const Tick tXAW; const Tick tXP; const Tick tXS; + const Tick tTAGBURST; + const Tick tRL_FAST; + const Tick tHM2DQ; + const Tick tRTW_int; + const Tick tRFBD; + const Tick tRCD_FAST; + const Tick tRC_FAST; + float flushBufferHighThreshold; const Tick clkResyncDelay; const bool dataClockSync; const bool burstInterleave; @@ -527,6 +535,8 @@ class DRAMInterface : public MemInterface const Tick wrToRdDlySameBG; const Tick rdToWrDlySameBG; + unsigned maxFBLen; + enums::PageManage pageMgmt; /** @@ -558,8 +568,8 @@ class DRAMInterface : public MemInterface * @param act_tick Time when the activation takes place * @param row Index of the row */ - void activateBank(Rank& rank_ref, Bank& bank_ref, Tick act_tick, - uint32_t row); + Tick activateBank(Rank& rank_ref, Bank& bank_ref, Tick act_tick, + uint32_t row, bool isTagCheck); /** * Precharge a given bank and also update when the precharge is @@ -587,7 +597,23 @@ class DRAMInterface : public MemInterface /** total number of DRAM bursts serviced */ statistics::Scalar readBursts; + statistics::Scalar readMC; statistics::Scalar writeBursts; + statistics::Scalar writeBurstsTC; + statistics::Scalar tagResBursts; + statistics::Scalar tagBursts; + + statistics::Average avgFBLenEnq; + statistics::Average avgReadFBPerEvent; + statistics::Scalar totNumberRefreshEvent; + statistics::Scalar totReadFBSent; + statistics::Scalar totReadFBFailed; + statistics::Scalar totReadFBByRdMC; + statistics::Scalar totStallToFlushFB; + statistics::Scalar totPktsPushedFB; + statistics::Scalar maxFBLenEnq; + statistics::Scalar refSchdRFB; + statistics::Scalar actDelayedDueToTagAct; /** DRAM per bank stats */ statistics::Vector perBankRdBursts; @@ -598,11 +624,27 @@ class DRAMInterface : public MemInterface statistics::Scalar totBusLat; statistics::Scalar totMemAccLat; + statistics::Scalar totQLatWr; + statistics::Scalar totBusLatWr; + statistics::Scalar totMemAccLatWr; + + statistics::Scalar totQLatWrTC; + statistics::Scalar totBusLatWrTC; + statistics::Scalar totMemAccLatWrTC; + // Average latencies per request statistics::Formula avgQLat; statistics::Formula avgBusLat; statistics::Formula avgMemAccLat; + statistics::Formula avgQLatWr; + statistics::Formula avgBusLatWr; + statistics::Formula avgMemAccLatWr; + + statistics::Formula avgQLatWrTC; + statistics::Formula avgBusLatWrTC; + statistics::Formula avgMemAccLatWrTC; + // Row hit count and rate statistics::Scalar readRowHits; statistics::Scalar writeRowHits; @@ -622,6 +664,7 @@ class DRAMInterface : public MemInterface statistics::Formula busUtilRead; statistics::Formula busUtilWrite; statistics::Formula pageHitRate; + statistics::Formula hitMissBusUtil; }; DRAMStats stats; @@ -659,6 +702,36 @@ class DRAMInterface : public MemInterface } public: + + //AbstractMemory* polMan; + + Tick get_tRP() override { return tRP;} + Tick get_tRCD_RD() override { return tRCD_RD;} + Tick get_tRL() override { return tRL;} + + // void setPolicyManager(PolicyManager* _polMan) override; + void setPolicyManager(AbstractMemory* _polMan) override; + + + void processReadFlushBufferEvent(); + EventFunctionWrapper readFlushBufferEvent; + + void processAddToFlushBufferEvent(); + EventFunctionWrapper addToFlushBufferEvent; + + Tick endOfReadFlushBuffPeriod; + unsigned readFlushBufferCount; + bool enableReadFlushBuffer; + bool isAlloy; + + bool checkFwdMrgeInFB(Addr addr) override; + + std::deque flushBuffer; + + typedef std::pair tempFBEntry; + + std::deque tempFlushBuffer; + /** * Initialize the DRAM interface and verify parameters */ @@ -800,6 +873,17 @@ class DRAMInterface : public MemInterface void chooseRead(MemPacketQueue& queue) override { } bool writeRespQueueFull() const override { return false;} + Tick nextTagActAvailability(unsigned rankNumber, unsigned bankNumber) override + { return ranks[rankNumber]->banks[bankNumber].tagActAllowedAt; } + + Tick getTRCFAST() override { return tRC_FAST;} + + Tick getTRLFAST() override { return tRL_FAST;} + + Tick getTRCDFAST() override { return tRCD_FAST;} + + void updateTagActAllowed(unsigned rankNumber, unsigned bankNumber, Tick BSlotTagBankBusyAt) override; + DRAMInterface(const DRAMInterfaceParams &_p); }; diff --git a/src/mem/hbm_ctrl.cc b/src/mem/hbm_ctrl.cc index f87fa2dcbb..95e607b17d 100644 --- a/src/mem/hbm_ctrl.cc +++ b/src/mem/hbm_ctrl.cc @@ -207,8 +207,8 @@ bool HBMCtrl::recvTimingReq(PacketPtr pkt) { // This is where we enter from the outside world - DPRINTF(MemCtrl, "recvTimingReq: request %s addr %#x size %d\n", - pkt->cmdString(), pkt->getAddr(), pkt->getSize()); + DPRINTF(MemCtrl, "recvTimingReq: request %s addr %#x size %d isTagCheck: %d\n", + pkt->cmdString(), pkt->getAddr(), pkt->getSize(), pkt->isTagCheck); panic_if(pkt->cacheResponding(), "Should not see packets where cache " "is responding"); diff --git a/src/mem/mem_ctrl.cc b/src/mem/mem_ctrl.cc index 97c7741abd..e1935f4590 100644 --- a/src/mem/mem_ctrl.cc +++ b/src/mem/mem_ctrl.cc @@ -42,6 +42,7 @@ #include "base/trace.hh" #include "debug/DRAM.hh" +#include "debug/DRAMT.hh" #include "debug/Drain.hh" #include "debug/MemCtrl.hh" #include "debug/NVM.hh" @@ -70,12 +71,17 @@ MemCtrl::MemCtrl(const MemCtrlParams &p) : writeBufferSize(dram->writeBufferSize), writeHighThreshold(writeBufferSize * p.write_high_thresh_perc / 100.0), writeLowThreshold(writeBufferSize * p.write_low_thresh_perc / 100.0), + oldestWriteAgeThreshold(p.oldest_write_age_threshold), + oldestWriteAge(0), minWritesPerSwitch(p.min_writes_per_switch), minReadsPerSwitch(p.min_reads_per_switch), memSchedPolicy(p.mem_sched_policy), frontendLatency(p.static_frontend_latency), backendLatency(p.static_backend_latency), + frontendLatencyTC(p.static_frontend_latency_tc), + backendLatencyTC(p.static_backend_latency_tc), commandWindow(p.command_window), + considerOldestWrite(p.consider_oldest_write), prevArrival(0), stats(*this) { @@ -91,9 +97,6 @@ MemCtrl::MemCtrl(const MemCtrlParams &p) : fatal("Write buffer low threshold %d must be smaller than the " "high threshold %d\n", p.write_low_thresh_perc, p.write_high_thresh_perc); - if (p.disable_sanity_check) { - port.disableSanityCheck(); - } } void @@ -135,7 +138,7 @@ MemCtrl::recvAtomic(PacketPtr pkt) Tick MemCtrl::recvAtomicLogic(PacketPtr pkt, MemInterface* mem_intr) { - DPRINTF(MemCtrl, "recvAtomic: %s 0x%x\n", + DPRINTF(MemCtrl, "recvAtomic: %s %x\n", pkt->cmdString(), pkt->getAddr()); panic_if(pkt->cacheResponding(), "Should not see packets where cache " @@ -221,23 +224,25 @@ MemCtrl::addToReadQueue(PacketPtr pkt, Addr burst_addr = burstAlign(addr, mem_intr); // if the burst address is not present then there is no need // looking any further - if (isInWriteQueue.find(burst_addr) != isInWriteQueue.end()) { - for (const auto& vec : writeQueue) { - for (const auto& p : vec) { - // check if the read is subsumed in the write queue - // packet we are looking at - if (p->addr <= addr && - ((addr + size) <= (p->addr + p->size))) { - - foundInWrQ = true; - stats.servicedByWrQ++; - pktsServicedByWrQ++; - DPRINTF(MemCtrl, - "Read to addr %#x with size %d serviced by " - "write queue\n", - addr, size); - stats.bytesReadWrQ += burst_size; - break; + if (!pkt->isTagCheck) { + if (isInWriteQueue.find(burst_addr) != isInWriteQueue.end()) { + for (const auto& vec : writeQueue) { + for (const auto& p : vec) { + // check if the read is subsumed in the write queue + // packet we are looking at + if (p->addr <= addr && + ((addr + size) <= (p->addr + p->size))) { + + foundInWrQ = true; + stats.servicedByWrQ++; + pktsServicedByWrQ++; + DPRINTF(MemCtrl, + "Read to addr %x with size %d serviced by " + "write queue\n", + addr, size); + stats.bytesReadWrQ += burst_size; + break; + } } } } @@ -249,7 +254,7 @@ MemCtrl::addToReadQueue(PacketPtr pkt, // Make the burst helper for split packets if (pkt_count > 1 && burst_helper == NULL) { - DPRINTF(MemCtrl, "Read to addr %#x translates to %d " + DPRINTF(MemCtrl, "Read to addr %x translates to %d " "memory requests\n", pkt->getAddr(), pkt_count); burst_helper = new BurstHelper(pkt_count); } @@ -257,6 +262,8 @@ MemCtrl::addToReadQueue(PacketPtr pkt, MemPacket* mem_pkt; mem_pkt = mem_intr->decodePacket(pkt, addr, size, true, mem_intr->pseudoChannel); + mem_pkt->isTagCheck = pkt->isTagCheck; + mem_pkt->isLocMem = pkt->isLocMem; // Increment read entries of the rank (dram) // Increment count to trigger issue of non-deterministic read (nvm) @@ -273,9 +280,13 @@ MemCtrl::addToReadQueue(PacketPtr pkt, readQueue[mem_pkt->qosValue()].push_back(mem_pkt); // log packet + DPRINTF(MemCtrl, "logRequest rd: %d %d %x\n", + pkt->requestorId(), + pkt->qosValue(), mem_pkt->addr); + logRequest(MemCtrl::READ, pkt->requestorId(), pkt->qosValue(), mem_pkt->addr, 1); - + mem_intr->readQueueSize++; // Update stats @@ -287,7 +298,7 @@ MemCtrl::addToReadQueue(PacketPtr pkt, } // If all packets are serviced by write queue, we send the repsonse back - if (pktsServicedByWrQ == pkt_count) { + if (pktsServicedByWrQ == pkt_count && !pkt->isTagCheck) { accessAndRespond(pkt, frontendLatency, mem_intr); return true; } @@ -323,8 +334,8 @@ MemCtrl::addToWriteQueue(PacketPtr pkt, unsigned int pkt_count, // see if we can merge with an existing item in the write // queue and keep track of whether we have merged or not - bool merged = isInWriteQueue.find(burstAlign(addr, mem_intr)) != - isInWriteQueue.end(); + bool merged = (isInWriteQueue.find(burstAlign(addr, mem_intr)) != + isInWriteQueue.end()) && !pkt->isTagCheck; // if the item was not merged we need to create a new write // and enqueue it @@ -332,6 +343,9 @@ MemCtrl::addToWriteQueue(PacketPtr pkt, unsigned int pkt_count, MemPacket* mem_pkt; mem_pkt = mem_intr->decodePacket(pkt, addr, size, false, mem_intr->pseudoChannel); + mem_pkt->isTagCheck = pkt->isTagCheck; + mem_pkt->isLocMem = pkt->isLocMem; + // Default readyTime to Max if nvm interface; //will be reset once read is issued mem_pkt->readyTime = MaxTick; @@ -345,14 +359,18 @@ MemCtrl::addToWriteQueue(PacketPtr pkt, unsigned int pkt_count, writeQueue[mem_pkt->qosValue()].push_back(mem_pkt); isInWriteQueue.insert(burstAlign(addr, mem_intr)); - + // log packet + DPRINTF(MemCtrl, "logRequest wr: %d %d %x\n", + pkt->requestorId(), + pkt->qosValue(), mem_pkt->addr); + logRequest(MemCtrl::WRITE, pkt->requestorId(), pkt->qosValue(), mem_pkt->addr, 1); - + mem_intr->writeQueueSize++; - assert(totalWriteQueueSize == isInWriteQueue.size()); + //assert(totalWriteQueueSize == isInWriteQueue.size()); // Update stats stats.avgWrQLen = totalWriteQueueSize; @@ -375,7 +393,9 @@ MemCtrl::addToWriteQueue(PacketPtr pkt, unsigned int pkt_count, // snoop the write queue for any upcoming reads // @todo, if a pkt size is larger than burst size, we might need a // different front end latency - accessAndRespond(pkt, frontendLatency, mem_intr); + if (!pkt->isTagCheck) { + accessAndRespond(pkt, frontendLatency, mem_intr); + } } void @@ -385,19 +405,19 @@ MemCtrl::printQs() const DPRINTF(MemCtrl, "===READ QUEUE===\n\n"); for (const auto& queue : readQueue) { for (const auto& packet : queue) { - DPRINTF(MemCtrl, "Read %#x\n", packet->addr); + DPRINTF(MemCtrl, "Read %d\n", packet->addr); } } DPRINTF(MemCtrl, "\n===RESP QUEUE===\n\n"); for (const auto& packet : respQueue) { - DPRINTF(MemCtrl, "Response %#x\n", packet->addr); + DPRINTF(MemCtrl, "Response %d\n", packet->addr); } DPRINTF(MemCtrl, "\n===WRITE QUEUE===\n\n"); for (const auto& queue : writeQueue) { for (const auto& packet : queue) { - DPRINTF(MemCtrl, "Write %#x\n", packet->addr); + DPRINTF(MemCtrl, "Write %d\n", packet->addr); } } #endif // TRACING_ON @@ -407,7 +427,7 @@ bool MemCtrl::recvTimingReq(PacketPtr pkt) { // This is where we enter from the outside world - DPRINTF(MemCtrl, "recvTimingReq: request %s addr %#x size %d\n", + DPRINTF(MemCtrl, "recvTimingReq: request %s addr %x size %d\n", pkt->cmdString(), pkt->getAddr(), pkt->getSize()); panic_if(pkt->cacheResponding(), "Should not see packets where cache " @@ -442,7 +462,7 @@ MemCtrl::recvTimingReq(PacketPtr pkt) if (pkt->isWrite()) { assert(size != 0); if (writeQueueFull(pkt_count)) { - DPRINTF(MemCtrl, "Write queue full, not accepting\n"); + DPRINTF(MemCtrl, "Write queue full, not accepting, readQ size: %d, writeQ size: %d\n", readQueue[pkt->qosValue()].size(), writeQueue[pkt->qosValue()].size()); // remember that we have to retry this port retryWrReq = true; stats.numWrRetry++; @@ -462,7 +482,7 @@ MemCtrl::recvTimingReq(PacketPtr pkt) assert(pkt->isRead()); assert(size != 0); if (readQueueFull(pkt_count)) { - DPRINTF(MemCtrl, "Read queue full, not accepting\n"); + DPRINTF(MemCtrl, "Read queue full, not accepting, readQ size: %d, writeQ size: %d\n", readQueue[pkt->qosValue()].size(), writeQueue[pkt->qosValue()].size()); // remember that we have to retry this port retryRdReq = true; stats.numRdRetry++; @@ -558,7 +578,7 @@ MemCtrl::chooseNext(MemPacketQueue& queue, Tick extra_col_delay, MemInterface* mem_intr) { // This method does the arbitration between requests. - + DPRINTF(MemCtrl, "in chooseNext func\n"); MemPacketQueue::iterator ret = queue.end(); if (!queue.empty()) { @@ -601,6 +621,7 @@ std::pair MemCtrl::chooseNextFRFCFS(MemPacketQueue& queue, Tick extra_col_delay, MemInterface* mem_intr) { + DPRINTF(MemCtrl, "in chooseNextFRFCFS func\n"); auto selected_pkt_it = queue.end(); Tick col_allowed_at = MaxTick; @@ -622,7 +643,7 @@ void MemCtrl::accessAndRespond(PacketPtr pkt, Tick static_latency, MemInterface* mem_intr) { - DPRINTF(MemCtrl, "Responding to Address %#x.. \n", pkt->getAddr()); + DPRINTF(MemCtrl, "Responding to Address %x: %s.. \n", pkt->getAddr(), pkt->cmdString()); bool needsResponse = pkt->needsResponse(); // do the actual memory access which also turns the packet into a @@ -639,11 +660,35 @@ MemCtrl::accessAndRespond(PacketPtr pkt, Tick static_latency, // with headerDelay that takes into account the delay provided by // the xbar and also the payloadDelay that takes into account the // number of data beats. - Tick response_time = curTick() + static_latency + pkt->headerDelay + - pkt->payloadDelay; + Tick response_time; + if (pkt->isTagCheck && pkt->isWrite()) { + assert(!pkt->owIsRead); + // Note: in this case static latency is TagCheckReady time actually! + response_time = static_latency + frontendLatencyTC + backendLatencyTC; + } else { + response_time = curTick() + static_latency + pkt->headerDelay + + pkt->payloadDelay; + } // Here we reset the timing of the packet before sending it out. pkt->headerDelay = pkt->payloadDelay = 0; + if (pkt->isTagCheck && pkt->owIsRead && !pkt->isHit) { + if (pkt->isDirty) { + assert(pkt->hasDirtyData); + } + else if (!pkt->isDirty && !pkt->hasDirtyData) { + // No response is needed. + // It was a just a bubble (null data). + DPRINTF(MemCtrl, "Done, Rd Miss Clean No Dirty Data\n"); + delete pkt; + return; + } + } + + if (pkt->isTagCheck) { + pkt->isTagCheck = false; + } + // queue the packet in the response queue to be sent out after // the static latency has passed port.schedTimingResp(pkt, response_time); @@ -658,6 +703,76 @@ MemCtrl::accessAndRespond(PacketPtr pkt, Tick static_latency, return; } +void +MemCtrl::sendTagCheckRespond(MemPacket* mem_pkt) +{ + DPRINTF(MemCtrl, "sendTagCheckRespond : %x \n", mem_pkt->addr); + assert(mem_pkt->isRead()); + assert(mem_pkt->pkt->isRead()); + assert(mem_pkt->tagCheckReady != MaxTick); + + PacketPtr tagCheckResPkt = getPacket(mem_pkt->addr, 8, MemCmd::ReadReq); + + tagCheckResPkt->isTagCheck = mem_pkt->pkt->isTagCheck; + tagCheckResPkt->isLocMem = mem_pkt->pkt->isLocMem; + tagCheckResPkt->owIsRead = mem_pkt->pkt->owIsRead; + tagCheckResPkt->isHit = mem_pkt->pkt->isHit; + tagCheckResPkt->isDirty = mem_pkt->pkt->isDirty; + tagCheckResPkt->hasDirtyData = mem_pkt->pkt->hasDirtyData; + tagCheckResPkt->dirtyLineAddr = mem_pkt->pkt->dirtyLineAddr; + + tagCheckResPkt->makeResponse(); + + // Tick response_time = curTick() + tagCheckResPkt->headerDelay; + // response_time += tagCheckResPkt->payloadDelay; + // Here we reset the timing of the packet before sending it out. + tagCheckResPkt->headerDelay = tagCheckResPkt->payloadDelay = 0; + + // queue the packet in the response queue to be sent out after + // the static latency has passed + port.schedTimingResp(tagCheckResPkt, mem_pkt->tagCheckReady + frontendLatencyTC + backendLatencyTC); +} + +void +MemCtrl::updateOldestWriteAge() +{ + // Assumption: writeQueue has only one priority = has just one vector in it. + for (const auto& vec : writeQueue) { + if (vec.empty()) { + oldestWriteAge = 0; + } else { + for (const auto& p : vec) { + oldestWriteAge = std::max(oldestWriteAge, curTick() - p->entryTime); + } + } + } +} + +PacketPtr +MemCtrl::getPacket(Addr addr, unsigned size, const MemCmd& cmd, + Request::FlagsType flags) +{ + // Create new request + RequestPtr req = std::make_shared(addr, size, flags, + 0); + // Dummy PC to have PC-based prefetchers latch on; get entropy into higher + // bits + req->setPC(((Addr)0) << 2); + + // Embed it in a packet + PacketPtr pkt = new Packet(req, cmd); + + uint8_t* pkt_data = new uint8_t[req->getSize()]; + + pkt->dataDynamic(pkt_data); + + if (cmd.isWrite()) { + std::fill_n(pkt_data, req->getSize(), (uint8_t)0); + } + + return pkt; +} + void MemCtrl::pruneBurstTick() { @@ -767,7 +882,7 @@ MemCtrl::verifyMultiCmd(Tick cmd_tick, Tick max_cmds_per_burst, } bool -MemCtrl::inReadBusState(bool next_state, const MemInterface* mem_intr) const +MemCtrl::inReadBusState(bool next_state, MemInterface* mem_intr) const { // check the bus state if (next_state) { @@ -780,7 +895,7 @@ MemCtrl::inReadBusState(bool next_state, const MemInterface* mem_intr) const } bool -MemCtrl::inWriteBusState(bool next_state, const MemInterface* mem_intr) const +MemCtrl::inWriteBusState(bool next_state, MemInterface* mem_intr) const { // check the bus state if (next_state) { @@ -792,6 +907,12 @@ MemCtrl::inWriteBusState(bool next_state, const MemInterface* mem_intr) const } } +uint32_t +MemCtrl::bytesPerBurst() const +{ + return dram->bytesPerBurst(); +} + Tick MemCtrl::doBurstAccess(MemPacket* mem_pkt, MemInterface* mem_intr) { @@ -808,13 +929,14 @@ MemCtrl::doBurstAccess(MemPacket* mem_pkt, MemInterface* mem_intr) std::tie(cmd_at, mem_intr->nextBurstAt) = mem_intr->doBurstAccess(mem_pkt, mem_intr->nextBurstAt, queue); - DPRINTF(MemCtrl, "Access to %#x, ready at %lld next burst at %lld.\n", + DPRINTF(MemCtrl, "Access to %x, ready at %lld next burst at %lld.\n", mem_pkt->addr, mem_pkt->readyTime, mem_intr->nextBurstAt); // Update the minimum timing between the requests, this is a // conservative estimate of when we have to schedule the next // request to not introduce any unecessary bubbles. In most cases // we will wake up sooner than we have to. + assert(mem_intr->nextBurstAt > mem_intr->commandOffset()); mem_intr->nextReqTime = mem_intr->nextBurstAt - mem_intr->commandOffset(); // Update the common bus stats @@ -883,6 +1005,13 @@ MemCtrl::processNextReqEvent(MemInterface* mem_intr, EventFunctionWrapper& resp_event, EventFunctionWrapper& next_req_event, bool& retry_wr_req) { + DPRINTF(MemCtrl, "processNextReqEvent: readQueueSize: %d, writeQueueSize:%d, readQ: %d, writeQ: %d, respQ: %d\n", + mem_intr->readQueueSize, mem_intr->writeQueueSize, readQueue[0].size(), writeQueue[0].size(), + respQueue.size()); + if (considerOldestWrite) { + updateOldestWriteAge(); + } + // transition is handled by QoS algorithm if enabled if (turnPolicy) { // select bus state - only done if QoS algorithms are in use @@ -901,14 +1030,14 @@ MemCtrl::processNextReqEvent(MemInterface* mem_intr, if (switched_cmd_type) { if (mem_intr->busState == MemCtrl::READ) { DPRINTF(MemCtrl, - "Switching to writes after %d reads with %d reads " - "waiting\n", mem_intr->readsThisTime, mem_intr->readQueueSize); + "Switching to writes after %d reads with %d reads " + "waiting\n", mem_intr->readsThisTime, mem_intr->readQueueSize); stats.rdPerTurnAround.sample(mem_intr->readsThisTime); mem_intr->readsThisTime = 0; } else { DPRINTF(MemCtrl, - "Switching to reads after %d writes with %d writes " - "waiting\n", mem_intr->writesThisTime, mem_intr->writeQueueSize); + "Switching to reads after %d writes with %d writes " + "waiting\n", mem_intr->writesThisTime, mem_intr->writeQueueSize); stats.wrPerTurnAround.sample(mem_intr->writesThisTime); mem_intr->writesThisTime = 0; } @@ -942,7 +1071,8 @@ MemCtrl::processNextReqEvent(MemInterface* mem_intr, // if we are draining) if (!(mem_intr->writeQueueSize == 0) && (drainState() == DrainState::Draining || - mem_intr->writeQueueSize > writeLowThreshold)) { + mem_intr->writeQueueSize > writeLowThreshold || + (considerOldestWrite && oldestWriteAge > oldestWriteAgeThreshold))) { DPRINTF(MemCtrl, "Switching to writes due to read queue empty\n"); @@ -974,7 +1104,7 @@ MemCtrl::processNextReqEvent(MemInterface* mem_intr, prio--; - DPRINTF(QOS, + DPRINTF(MemCtrl, "Checking READ queue [%d] priority [%d elements]\n", prio, queue->size()); @@ -1003,20 +1133,60 @@ MemCtrl::processNextReqEvent(MemInterface* mem_intr, auto mem_pkt = *to_read; + DPRINTF(MemCtrl, "Read pkt chosen before doburst: %x\n", mem_pkt->getAddr()); + Tick cmd_at = doBurstAccess(mem_pkt, mem_intr); + if (mem_pkt->isLocMem) { + if (dram->polMan->locMemPolicy == enums::RambusTagProbOpt) { + assert(mem_pkt->BSlotBusyUntil!=MaxTick); + assert(!mem_pkt->probedRdMC); + } + + if (mem_pkt->probedRdH) { + assert(mem_pkt->tagCheckReady != MaxTick); + assert(!mem_pkt->probedRdMD); + assert (mem_pkt->tagCheckReady > (dram->getTRCDFAST() + dram->getTRLFAST())); + assert(cmd_at > (mem_pkt->tagCheckReady - dram->getTRCDFAST() - dram->getTRLFAST())); + + stats.deltaAbSlotRdH += + (cmd_at - (mem_pkt->tagCheckReady - dram->getTRCDFAST() - dram->getTRLFAST())); + + } else if (mem_pkt->probedRdMD) { + assert(mem_pkt->tagCheckReady != MaxTick); + assert(!mem_pkt->probedRdH); + assert (mem_pkt->tagCheckReady > (dram->getTRCDFAST() + dram->getTRLFAST())); + assert(cmd_at > (mem_pkt->tagCheckReady - dram->getTRCDFAST() - dram->getTRLFAST())); + + stats.deltaAbSlotRdMD += + (cmd_at - (mem_pkt->tagCheckReady - dram->getTRCDFAST() - dram->getTRLFAST())); + } + } + + assert((*to_read)->getAddr() == mem_pkt->getAddr()); + + if (mem_pkt->isTagCheck) { + DPRINTF(MemCtrl, "read times: %x, %s: tag: %d data: %d \n", mem_pkt->addr, mem_pkt->pkt->cmdString(), mem_pkt->tagCheckReady, mem_pkt->readyTime); + sendTagCheckRespond(mem_pkt); + } + DPRINTF(MemCtrl, - "Command for %#x, issued at %lld.\n", mem_pkt->addr, cmd_at); + "Command for %x, issued at %lld.\n", mem_pkt->addr, cmd_at); // sanity check assert(pktSizeCheck(mem_pkt, mem_intr)); assert(mem_pkt->readyTime >= curTick()); // log the response + DPRINTF(MemCtrl, "logResponse rd1: %d %d %x %d\n", + (*to_read)->requestorId(), + mem_pkt->qosValue(), mem_pkt->getAddr(), + mem_pkt->readyTime - mem_pkt->entryTime); + logResponse(MemCtrl::READ, (*to_read)->requestorId(), mem_pkt->qosValue(), mem_pkt->getAddr(), 1, mem_pkt->readyTime - mem_pkt->entryTime); - + mem_intr->readQueueSize--; // Insert into response queue. It will be sent back to the @@ -1036,16 +1206,31 @@ MemCtrl::processNextReqEvent(MemInterface* mem_intr, // there are no other writes that can issue // Also ensure that we've issued a minimum defined number // of reads before switching, or have emptied the readQ - if ((mem_intr->writeQueueSize > writeHighThreshold) && - (mem_intr->readsThisTime >= minReadsPerSwitch || - mem_intr->readQueueSize == 0) - && !(nvmWriteBlock(mem_intr))) { + if (((mem_intr->writeQueueSize > writeHighThreshold) && + (mem_intr->readsThisTime >= minReadsPerSwitch || mem_intr->readQueueSize == 0) && + !(nvmWriteBlock(mem_intr))) || (considerOldestWrite && oldestWriteAge > oldestWriteAgeThreshold)) { switch_to_writes = true; } // remove the request from the queue - // the iterator is no longer valid . + // the iterator is no longer valid . readQueue[mem_pkt->qosValue()].erase(to_read); + + // Tag probing B slot comes here. + if (mem_pkt->isLocMem && dram->polMan->locMemPolicy == enums::RambusTagProbOpt) { + assert(mem_pkt->BSlotBusyUntil != MaxTick); + + DPRINTF(MemCtrl, "Rd--> Start probing for B slot: Aslot addr: %x , end of tag bank busy for B slot: %d\n", + mem_pkt->getAddr(), mem_pkt->BSlotBusyUntil); + bool found = findCandidateForBSlot(mem_pkt); + DPRINTF(MemCtrl, "Rd--> B slot result: found flag: %d\n",found); + + if (found) { + stats.foundCandidBSlot++; + } else { + stats.noCandidBSlot++; + } + } } // switching to writes, either because the read queue is empty @@ -1069,6 +1254,9 @@ MemCtrl::processNextReqEvent(MemInterface* mem_intr, DPRINTF(QOS, "Checking WRITE queue [%d] priority [%d elements]\n", prio, queue->size()); + DPRINTF(MemCtrl, + "Checking WRITE queue of size [%d] : \n", + queue->size()); // If we are changing command type, incorporate the minimum // bus turnaround delay @@ -1096,22 +1284,52 @@ MemCtrl::processNextReqEvent(MemInterface* mem_intr, // sanity check assert(pktSizeCheck(mem_pkt, mem_intr)); + DPRINTF(MemCtrl, "Write pkt chosen before doburst: %x\n", mem_pkt->getAddr()); + Tick cmd_at = doBurstAccess(mem_pkt, mem_intr); + DPRINTF(MemCtrl, - "Command for %#x, issued at %lld.\n", mem_pkt->addr, cmd_at); + "Command for %x, issued at %lld.\n", mem_pkt->addr, cmd_at); + + if (mem_pkt->isTagCheck) { + DPRINTF(MemCtrl, "write times: %x, %s: tag: %d data: %d \n", mem_pkt->addr, mem_pkt->pkt->cmdString(), mem_pkt->tagCheckReady, mem_pkt->readyTime); + // Note: the second argument in this function call is NOT delay! + accessAndRespond(mem_pkt->pkt, mem_pkt->tagCheckReady, mem_intr); + } isInWriteQueue.erase(burstAlign(mem_pkt->addr, mem_intr)); // log the response + DPRINTF(MemCtrl, "logResponse wr1: %d %d %x %d\n", + mem_pkt->requestorId(), + mem_pkt->qosValue(), mem_pkt->getAddr(), + mem_pkt->readyTime - mem_pkt->entryTime); + logResponse(MemCtrl::WRITE, mem_pkt->requestorId(), mem_pkt->qosValue(), mem_pkt->getAddr(), 1, mem_pkt->readyTime - mem_pkt->entryTime); - + mem_intr->writeQueueSize--; // remove the request from the queue - the iterator is no longer valid writeQueue[mem_pkt->qosValue()].erase(to_write); + // Tag probing B slot comes here. + if (mem_pkt->isLocMem && dram->polMan->locMemPolicy == enums::RambusTagProbOpt) { + assert(mem_pkt->BSlotBusyUntil != MaxTick); + + DPRINTF(MemCtrl, "WR--> Start probing for B slot: Aslot addr: %x , end of tag bank busy for B slot: %d\n", + mem_pkt->getAddr(), mem_pkt->BSlotBusyUntil); + bool found = findCandidateForBSlot(mem_pkt); + DPRINTF(MemCtrl, "WR--> B slot result: found flag: %d\n",found); + + if (found) { + stats.foundCandidBSlot++; + } else { + stats.noCandidBSlot++; + } + } + delete mem_pkt; // If we emptied the write queue, or got sufficiently below the @@ -1178,6 +1396,145 @@ MemCtrl::pktSizeCheck(MemPacket* mem_pkt, MemInterface* mem_intr) const return (mem_pkt->size <= mem_intr->bytesPerBurst()); } +bool +MemCtrl::findCandidateForBSlot(MemPacket* AslotPkt) +{ + DPRINTF(MemCtrl, "findCandidateForBSlot: Aslot addr: %x, BSlotTagBankBusyUntil: %d, readQ size: %d\n", + AslotPkt->getAddr(), AslotPkt->BSlotBusyUntil, readQueue[AslotPkt->qosValue()].size()); + + assert(AslotPkt->BSlotBusyUntil != MaxTick); + + MemPacketQueue::iterator BslotPktIt; + + for (auto queue = readQueue.rbegin(); + queue != readQueue.rend(); ++queue) { + BslotPktIt = searchReadQueueForBSlot((*queue), AslotPkt); + + if (BslotPktIt != queue->end()) { + // A proper candidate for B slot is found! + auto BslotPkt = *BslotPktIt; + assert(BslotPkt != AslotPkt); + dram->updateTagActAllowed(BslotPkt->rank, BslotPkt->bank, AslotPkt->BSlotBusyUntil); + + DPRINTF(MemCtrl, "B slot found: Addr A: %x, isRead: %d /// Addr B: %x, IsRead: %d, IsHit: %d: IsDirty: %d\n", + AslotPkt->getAddr(), AslotPkt->isRead(), BslotPkt->getAddr(), + BslotPkt->pkt->owIsRead, BslotPkt->pkt->isHit, BslotPkt->pkt->isDirty); + + handleTCforBSlotPkt(BslotPktIt, AslotPkt->BSlotBusyUntil); + + if (BslotPkt->pkt->owIsRead && BslotPkt->pkt->isHit) { + stats.foundCandidBSlotRH++; + } else if (BslotPkt->pkt->owIsRead && !BslotPkt->pkt->isHit && !BslotPkt->pkt->isDirty) { + stats.foundCandidBSlotRMC++; + } else if (BslotPkt->pkt->owIsRead && !BslotPkt->pkt->isHit && BslotPkt->pkt->isDirty) { + stats.foundCandidBSlotRMD++; + } + return true; + } + } + return false; + +} + +MemPacketQueue::iterator +MemCtrl::searchReadQueueForBSlot(MemPacketQueue& queue, MemPacket* AslotPkt) +{ + DPRINTF(MemCtrl, "searchReadQueueForBSlot: Aslot addr: %x, BSlotTagBankBusyUntil: %d\n", + AslotPkt->getAddr(), AslotPkt->BSlotBusyUntil); + + MemPacketQueue::iterator youngest = queue.end(); + + for (auto i = queue.begin(); i != queue.end() ; ++i) { + MemPacket* BslotPkt = *i; + if (BslotPkt->isTagCheck && BslotPkt != AslotPkt) { + Tick tagActAllowedAt = dram->nextTagActAvailability(BslotPkt->rank, BslotPkt->bank); + if (AslotPkt->BSlotBusyUntil >= tagActAllowedAt + dram->getTRCFAST()) { + auto prev_mem_pkt = *youngest; + if (youngest == queue.end()) { + youngest = i; + } else if (BslotPkt->entryTime > prev_mem_pkt->entryTime) { + youngest = i; + } + } + } + } + + return youngest; +} + +void +MemCtrl::handleTCforBSlotPkt(MemPacketQueue::iterator BslotPktIt, Tick BSlotTagBankBusyUntil) +{ + // assert(policy == rambustagprob); + auto BslotPkt = *BslotPktIt; + + // read hits + if (BslotPkt->pkt->isRead() && BslotPkt->pkt->isHit) { + BslotPkt->tagCheckReady = BSlotTagBankBusyUntil + dram->getTRCDFAST() + + dram->getTRLFAST() - dram->getTRCFAST(); + sendTagCheckRespond(BslotPkt); + BslotPkt->isTagCheck = false; + BslotPkt->pkt->isTagCheck = false; + DPRINTF(MemCtrl, "Rd Hit successfully probed for TC, curTick: %d, adr: %x, tagCheckReady: %d\n", curTick(), BslotPkt->pkt->getAddr(), BslotPkt->tagCheckReady); + + assert(!BslotPkt->probedRdH); + BslotPkt->probedRdH = true; + + return; + } + + // read miss cleans + else if (BslotPkt->pkt->isRead() && !BslotPkt->pkt->isHit && !BslotPkt->pkt->isDirty) { + BslotPkt->tagCheckReady = BSlotTagBankBusyUntil + dram->getTRCDFAST() + + dram->getTRLFAST() - dram->getTRCFAST(); + sendTagCheckRespond(BslotPkt); + BslotPkt->isTagCheck = false; + BslotPkt->pkt->isTagCheck = false; + + // log the response + DPRINTF(MemCtrl, "logResponse rd2: %d %d %x %d\n", + BslotPkt->pkt->requestorId(), + BslotPkt->pkt->qosValue(), BslotPkt->addr, + BslotPkt->tagCheckReady - BslotPkt->entryTime); + + logResponse(MemCtrl::READ, BslotPkt->pkt->requestorId(), + BslotPkt->pkt->qosValue(), BslotPkt->addr, 1, + BslotPkt->tagCheckReady - BslotPkt->entryTime); + + dram->readQueueSize--; + + //remove the packet from read queue + readQueue[BslotPkt->qosValue()].erase(BslotPktIt); + + DPRINTF(MemCtrl, "Rd Miss Clean successfully probed for TC, curTick: %d, adr: %x, tagCheckReady: %d, readQ size:%d\n", + curTick(), BslotPkt->pkt->getAddr(), BslotPkt->tagCheckReady, readQueue[BslotPkt->qosValue()].size()); + + assert(!BslotPkt->probedRdMC); + BslotPkt->probedRdMC = true; + + delete BslotPkt->pkt; + delete BslotPkt; + return; + } + // read miss dirty + else if (BslotPkt->pkt->isRead() && !BslotPkt->pkt->isHit && BslotPkt->pkt->isDirty) { + BslotPkt->tagCheckReady = BSlotTagBankBusyUntil + dram->getTRCDFAST() + + dram->getTRLFAST() - dram->getTRCFAST(); + sendTagCheckRespond(BslotPkt); + BslotPkt->isTagCheck = false; + BslotPkt->pkt->isTagCheck = false; + DPRINTF(MemCtrl, "Rd Miss Dirty successfully probed for TC, curTick: %d, adr: %x, tagCheckReady: %d\n", + curTick(), BslotPkt->pkt->getAddr(), BslotPkt->tagCheckReady); + + assert(!BslotPkt->probedRdMD); + BslotPkt->probedRdMD = true; + + return; + } + + +} + MemCtrl::CtrlStats::CtrlStats(MemCtrl &_ctrl) : statistics::Group(&_ctrl), ctrl(_ctrl), @@ -1198,9 +1555,6 @@ MemCtrl::CtrlStats::CtrlStats(MemCtrl &_ctrl) ADD_STAT(mergedWrBursts, statistics::units::Count::get(), "Number of controller write bursts merged with an existing one"), - ADD_STAT(neitherReadNorWriteReqs, statistics::units::Count::get(), - "Number of requests that are neither read nor write"), - ADD_STAT(avgRdQLen, statistics::units::Rate< statistics::units::Count, statistics::units::Tick>::get(), "Average read queue length when enqueuing"), @@ -1227,6 +1581,17 @@ MemCtrl::CtrlStats::CtrlStats(MemCtrl &_ctrl) "Reads before turning the bus around for writes"), ADD_STAT(wrPerTurnAround, statistics::units::Count::get(), "Writes before turning the bus around for reads"), + + ADD_STAT(noCandidBSlot, statistics::units::Count::get(), + " "), + ADD_STAT(foundCandidBSlot, statistics::units::Count::get(), + " "), + ADD_STAT(foundCandidBSlotRH, statistics::units::Count::get(), + " "), + ADD_STAT(foundCandidBSlotRMC, statistics::units::Count::get(), + " "), + ADD_STAT(foundCandidBSlotRMD, statistics::units::Count::get(), + " "), ADD_STAT(bytesReadWrQ, statistics::units::Byte::get(), "Total number of bytes read from write queue"), @@ -1271,7 +1636,15 @@ MemCtrl::CtrlStats::CtrlStats(MemCtrl &_ctrl) "Per-requestor read average memory access latency"), ADD_STAT(requestorWriteAvgLat, statistics::units::Rate< statistics::units::Tick, statistics::units::Count>::get(), - "Per-requestor write average memory access latency") + "Per-requestor write average memory access latency"), + + ADD_STAT(deltaAbSlotRdH, statistics::units::Tick::get(), "stat"), + ADD_STAT(deltaAbSlotRdMD, statistics::units::Tick::get(), "stat"), + + ADD_STAT(avgDeltaAbSlotRdH, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgDeltaAbSlotRdMD, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat") { } @@ -1303,6 +1676,9 @@ MemCtrl::CtrlStats::regStats() avgWrBWSys.precision(8); avgGap.precision(2); + avgDeltaAbSlotRdH.precision(2); + avgDeltaAbSlotRdMD.precision(2); + // per-requestor bytes read and written to memory requestorReadBytes .init(max_requestors) @@ -1369,6 +1745,11 @@ MemCtrl::CtrlStats::regStats() requestorWriteRate = requestorWriteBytes / simSeconds; requestorReadAvgLat = requestorReadTotalLat / requestorReadAccesses; requestorWriteAvgLat = requestorWriteTotalLat / requestorWriteAccesses; + + avgDeltaAbSlotRdH = (deltaAbSlotRdH/foundCandidBSlotRH)/1000; + avgDeltaAbSlotRdMD = (deltaAbSlotRdMD/foundCandidBSlotRMD)/1000; + + } void @@ -1427,8 +1808,9 @@ MemCtrl::drain() { // if there is anything in any of our internal queues, keep track // of that as well - if (totalWriteQueueSize || totalReadQueueSize || !respQEmpty() || - !allIntfDrained()) { + if (!(!totalWriteQueueSize && !totalReadQueueSize && respQEmpty() && + allIntfDrained())) { + DPRINTF(Drain, "Memory controller not drained, write: %d, read: %d," " resp: %d\n", totalWriteQueueSize, totalReadQueueSize, respQueue.size()); diff --git a/src/mem/mem_ctrl.hh b/src/mem/mem_ctrl.hh index 917798ffa7..1e175f22ef 100644 --- a/src/mem/mem_ctrl.hh +++ b/src/mem/mem_ctrl.hh @@ -54,6 +54,7 @@ #include "base/callback.hh" #include "base/statistics.hh" +#include "debug/MemCtrl.hh" #include "enums/MemSched.hh" #include "mem/qos/mem_ctrl.hh" #include "mem/qport.hh" @@ -100,7 +101,7 @@ class MemPacket public: /** When did request enter the controller */ - const Tick entryTime; + Tick entryTime; /** When will request leave the controller */ Tick readyTime; @@ -156,6 +157,20 @@ class MemPacket */ uint8_t _qosValue; + /** + * DRAM cache specific flags + * + */ + bool isTagCheck = false; + Tick tagCheckReady = MaxTick; + bool isLocMem = false; + Tick BSlotBusyUntil = MaxTick; + bool probedRdH = false; + bool probedRdMC = false; + bool probedRdMD = false; + + + /** * Set the packet QoS value * (interface compatibility with Packet) @@ -213,6 +228,20 @@ class MemPacket burstHelper(NULL), _qosValue(_pkt->qosValue()) { } + /* + // MemPacket(PacketPtr _pkt, bool is_read, bool is_dram, uint8_t _channel, + // uint8_t _rank, uint8_t _bank, uint32_t _row, uint16_t bank_id, + // Addr _addr, unsigned int _size, + // bool _isTagCheck, bool _isHit, bool _isDirty, Tick _tagCheckReady) + // : entryTime(curTick()), readyTime(curTick()), pkt(_pkt), + // _requestorId(pkt->requestorId()), + // read(is_read), dram(is_dram), pseudoChannel(_channel), rank(_rank), + // bank(_bank), row(_row), bankId(bank_id), addr(_addr), size(_size), + // burstHelper(NULL), _qosValue(_pkt->qosValue()), + // isTagCheck(_isTagCheck), isHit(_isHit), isDirty(_isDirty), tagCheckReady(_tagCheckReady) + // { } + */ + }; // The memory packets are store in a multiple dequeue structure, @@ -383,7 +412,9 @@ class MemCtrl : public qos::MemCtrl */ virtual void accessAndRespond(PacketPtr pkt, Tick static_latency, MemInterface* mem_intr); + void sendTagCheckRespond(MemPacket* pkt); + PacketPtr getPacket(Addr addr, unsigned size, const MemCmd& cmd, Request::FlagsType flags = 0); /** * Determine if there is a packet that can issue. * @@ -503,7 +534,7 @@ class MemCtrl : public qos::MemCtrl + */ MemInterface* dram; - virtual AddrRangeList getAddrRanges(); + // virtual AddrRangeList getAddrRanges(); /** * The following are basic design parameters of the memory @@ -515,6 +546,8 @@ class MemCtrl : public qos::MemCtrl uint32_t writeBufferSize; uint32_t writeHighThreshold; uint32_t writeLowThreshold; + uint32_t oldestWriteAgeThreshold; + Tick oldestWriteAge; const uint32_t minWritesPerSwitch; const uint32_t minReadsPerSwitch; @@ -538,12 +571,24 @@ class MemCtrl : public qos::MemCtrl */ const Tick backendLatency; + /** + * Pipeline latency of the controller frontend for tag Check (TC). + */ + const Tick frontendLatencyTC; + + /** + * Pipeline latency of the backend and PHY for tag Check (TC). + */ + const Tick backendLatencyTC; + /** * Length of a command window, used to check * command bandwidth */ const Tick commandWindow; + bool considerOldestWrite; + /** * Till when must we wait before issuing next RD/WR burst? */ @@ -588,6 +633,12 @@ class MemCtrl : public qos::MemCtrl statistics::Histogram rdPerTurnAround; statistics::Histogram wrPerTurnAround; + statistics::Scalar noCandidBSlot; + statistics::Scalar foundCandidBSlot; + statistics::Scalar foundCandidBSlotRH; + statistics::Scalar foundCandidBSlotRMC; + statistics::Scalar foundCandidBSlotRMD; + statistics::Scalar bytesReadWrQ; statistics::Scalar bytesReadSys; statistics::Scalar bytesWrittenSys; @@ -617,6 +668,12 @@ class MemCtrl : public qos::MemCtrl // per-requestor raed and write average memory access latency statistics::Formula requestorReadAvgLat; statistics::Formula requestorWriteAvgLat; + + statistics::Scalar deltaAbSlotRdH; + statistics::Scalar deltaAbSlotRdMD; + + statistics::Formula avgDeltaAbSlotRdH; + statistics::Formula avgDeltaAbSlotRdMD; }; CtrlStats stats; @@ -677,6 +734,8 @@ class MemCtrl : public qos::MemCtrl MemCtrl(const MemCtrlParams &p); + virtual AddrRangeList getAddrRanges(); + /** * Ensure that all interfaced have drained commands * @@ -754,6 +813,7 @@ class MemCtrl : public qos::MemCtrl { assert(pseudo_channel == 0); schedule(nextReqEvent, tick); + DPRINTF(MemCtrl, "Scheduling next request after refreshing\n"); } /** @@ -762,7 +822,7 @@ class MemCtrl : public qos::MemCtrl * @param next_state Check either the current or next bus state * @return True when bus is currently in a read state */ - bool inReadBusState(bool next_state, const MemInterface* mem_intr) const; + bool inReadBusState(bool next_state, MemInterface* mem_intr) const; /** * Check the current direction of the memory channel @@ -770,7 +830,21 @@ class MemCtrl : public qos::MemCtrl * @param next_state Check either the current or next bus state * @return True when bus is currently in a write state */ - bool inWriteBusState(bool next_state, const MemInterface* mem_intr) const; + bool inWriteBusState(bool next_state, MemInterface* mem_intr) const; + + uint32_t bytesPerBurst() const; + + Addr burstAlign(Addr addr) const { return burstAlign(addr, dram); } + + void accessAndRespond(PacketPtr pkt, Tick static_latency) { accessAndRespond(pkt, static_latency, dram); } + + void updateOldestWriteAge(); + + bool findCandidateForBSlot(MemPacket* AslotPkt); + + void handleTCforBSlotPkt(MemPacketQueue::iterator BslotPktIt, Tick BSlotTagBankBusyUntil); + + MemPacketQueue::iterator searchReadQueueForBSlot(MemPacketQueue& queue, MemPacket* AslotPkt); Port &getPort(const std::string &if_name, PortID idx=InvalidPortID) override; diff --git a/src/mem/mem_interface.cc b/src/mem/mem_interface.cc index e97448f457..2e1f3f3bce 100644 --- a/src/mem/mem_interface.cc +++ b/src/mem/mem_interface.cc @@ -79,7 +79,7 @@ MemInterface::setCtrl(MemCtrl* _ctrl, unsigned int command_window, { ctrl = _ctrl; maxCommandsPerWindow = command_window / tCK; - // setting the pseudo channel number for this interface + // setting the pseudo channel number for this interfacez pseudoChannel = pseudo_channel; } diff --git a/src/mem/mem_interface.hh b/src/mem/mem_interface.hh index b0f762fc80..8eede9246b 100644 --- a/src/mem/mem_interface.hh +++ b/src/mem/mem_interface.hh @@ -97,13 +97,14 @@ class MemInterface : public AbstractMemory Tick wrAllowedAt; Tick preAllowedAt; Tick actAllowedAt; + Tick tagActAllowedAt; uint32_t rowAccesses; uint32_t bytesAccessed; Bank() : openRow(NO_ROW), bank(0), bankgr(0), - rdAllowedAt(0), wrAllowedAt(0), preAllowedAt(0), actAllowedAt(0), + rdAllowedAt(0), wrAllowedAt(0), preAllowedAt(0), actAllowedAt(0), tagActAllowedAt(0), rowAccesses(0), bytesAccessed(0) { } }; @@ -167,6 +168,8 @@ class MemInterface : public AbstractMemory public: + AbstractMemory* polMan; + /** * Buffer sizes for read and write queues in the controller * These are passed to the controller on instantiation @@ -275,7 +278,7 @@ class MemInterface : public AbstractMemory /** * @return number of bytes in a burst for this interface */ - uint32_t bytesPerBurst() const { return burstSize; } + virtual uint32_t bytesPerBurst() const { return burstSize; } /* * @return time to offset next command @@ -412,6 +415,22 @@ class MemInterface : public AbstractMemory "should not be executed from here.\n"); } + virtual Tick nextTagActAvailability(unsigned rankNumber, unsigned bankNumber) + { panic("MemInterface nextTagActAvailability should not be executed from here.\n"); } + + virtual Tick getTRCFAST() + { panic("MemInterface getTRCFAST should not be executed from here.\n"); } + + virtual Tick getTRLFAST() + { panic("MemInterface getTRLFAST should not be executed from here.\n"); } + + virtual Tick getTRCDFAST() + { panic("MemInterface getTRCDFAST should not be executed from here.\n"); } + + virtual void updateTagActAllowed(unsigned rankNumber, unsigned bankNumber, Tick BSlotTagAllowedAt) + { panic("MemInterface updateTagActAllowed should not be executed from here.\n"); } + + typedef MemInterfaceParams Params; MemInterface(const Params &_p); }; diff --git a/src/mem/packet.hh b/src/mem/packet.hh index df2a8165fc..162747d87a 100644 --- a/src/mem/packet.hh +++ b/src/mem/packet.hh @@ -297,6 +297,15 @@ class Packet : public Printable, public Extensible typedef uint32_t FlagsType; typedef gem5::Flags Flags; + bool isTagCheck = false; + bool isLocMem = false; + bool owIsRead = false; + bool isHit = false; + bool isDirty = false; + bool hasDirtyData = false; + Addr dirtyLineAddr = -1; + + private: enum : FlagsType { @@ -1233,7 +1242,7 @@ class Packet : public Printable, public Extensible const T* getConstPtr() const { - assert(flags.isSet(STATIC_DATA|DYNAMIC_DATA)); + //assert(flags.isSet(STATIC_DATA|DYNAMIC_DATA)); return (const T*)data; } diff --git a/src/mem/packet_queue.cc b/src/mem/packet_queue.cc index 535764fbc8..91f78a438b 100644 --- a/src/mem/packet_queue.cc +++ b/src/mem/packet_queue.cc @@ -118,10 +118,10 @@ PacketQueue::schedSendTiming(PacketPtr pkt, Tick when) // add a very basic sanity check on the port to ensure the // invisible buffer is not growing beyond reasonable limits - if (!_disableSanityCheck && transmitList.size() > 128) { - panic("Packet queue %s has grown beyond 128 packets\n", - name()); - } + // if (!_disableSanityCheck && transmitList.size() > 256) { + // panic("Packet queue %s has grown beyond 256 packets\n", + // name()); + // } // we should either have an outstanding retry, or a send event // scheduled, but there is an unfortunate corner case where the diff --git a/src/mem/physical.cc b/src/mem/physical.cc index 06f2cdc003..737951b7c5 100644 --- a/src/mem/physical.cc +++ b/src/mem/physical.cc @@ -116,18 +116,21 @@ PhysicalMemory::PhysicalMemory(const std::string& _name, "Skipping memory %s that is not in global address map\n", m->name()); - // sanity check - fatal_if(m->getAddrRange().interleaved(), - "Memory %s that is not in the global address map cannot " - "be interleaved\n", m->name()); - - // simply do it independently, also note that this kind of - // memories are allowed to overlap in the logic address - // map - std::vector unmapped_mems{m}; - createBackingStore(m->getAddrRange(), unmapped_mems, - m->isConfReported(), m->isInAddrMap(), - m->isKvmMap()); + // Only create backing stores for non-null memories + if (!m->isNull()) { + // sanity check + fatal_if(m->getAddrRange().interleaved(), + "Memory %s that is not in the global address map cannot " + "be interleaved\n", m->name()); + + // simply do it independently, also note that this kind of + // memories are allowed to overlap in the logic address + // map + std::vector unmapped_mems{m}; + createBackingStore(m->getAddrRange(), unmapped_mems, + m->isConfReported(), m->isInAddrMap(), + m->isKvmMap()); + } } } diff --git a/src/mem/policy_manager.cc b/src/mem/policy_manager.cc new file mode 100644 index 0000000000..b28fb785fb --- /dev/null +++ b/src/mem/policy_manager.cc @@ -0,0 +1,3358 @@ +#include "mem/policy_manager.hh" + +#include "base/trace.hh" +#include "debug/PolicyManager.hh" +#include "debug/Drain.hh" +#include "mem/dram_interface.hh" +#include "sim/sim_exit.hh" +#include "sim/system.hh" + +namespace gem5 +{ + +namespace memory +{ + +PolicyManager::PolicyManager(const PolicyManagerParams &p): + AbstractMemory(p), + port(name() + ".port", *this), + locReqPort(name() + ".loc_req_port", *this), + farReqPort(name() + ".far_req_port", *this), + locBurstSize(p.loc_burst_size), + farBurstSize(p.far_burst_size), + locMem(p.loc_mem), + replacementPolicy(p.replacement_policy), + dramCacheSize(p.dram_cache_size), + blockSize(p.block_size), + assoc(p.assoc), + addrSize(p.addr_size), + orbMaxSize(p.orb_max_size), orbSize(0), + crbMaxSize(p.crb_max_size), crbSize(0), + extreme(p.extreme), + alwaysHit(p.always_hit), alwaysDirty(p.always_dirty), + bypassDcache(p.bypass_dcache), + frontendLatency(p.static_frontend_latency), + backendLatency(p.static_backend_latency), + numColdMisses(0), + cacheWarmupRatio(p.cache_warmup_ratio), + infoCacheWarmupRatio(0.05), + resetStatsWarmup(false), + prevArrival(0), + retryLLC(false), retryLLCFarMemWr(false), + retryTagCheck(false), retryLocMemRead(false), retryFarMemRead(false), + retryLocMemWrite(false), retryFarMemWrite(false), + maxConf(0), + tagCheckEvent([this]{ processTagCheckEvent(); }, name()), + locMemReadEvent([this]{ processLocMemReadEvent(); }, name()), + locMemWriteEvent([this]{ processLocMemWriteEvent(); }, name()), + farMemReadEvent([this]{ processFarMemReadEvent(); }, name()), + farMemWriteEvent([this]{ processFarMemWriteEvent(); }, name()), + polManStats(*this) +{ + panic_if(orbMaxSize<8, "ORB maximum size must be at least 8.\n"); + + locMemPolicy = p.loc_mem_policy; + + locMem->setPolicyManager(this); + + unsigned numOfSets = dramCacheSize/(blockSize * assoc); + + for (int i = 0; i < numOfSets; i++) { + std::vector tempSet; + for (int j = 0; j < assoc; j++) { + ReplaceableEntry* tempWay = new ReplaceableEntry (-1, -1, false, false, -1); + tempWay->replacementData = replacementPolicy->instantiateEntry(); + tempSet.push_back(tempWay); + } + tagMetadataStore.push_back(tempSet); + } +} + +Tick +PolicyManager::recvAtomic(PacketPtr pkt) +{ + if (!getAddrRange().contains(pkt->getAddr())) { + panic("Can't handle address range for packet %s\n", pkt->print()); + } + + DPRINTF(PolicyManager, "recvAtomic: %s %d\n", + pkt->cmdString(), pkt->getAddr()); + + panic_if(pkt->cacheResponding(), "Should not see packets where cache " + "is responding"); + + // do the actual memory access and turn the packet into a response + access(pkt); + + if (pkt->hasData()) { + // this value is not supposed to be accurate, just enough to + // keep things going, mimic a closed page + // also this latency can't be 0 + // panic("Can't handle this process --> implement accessLatency() " + // "according to your interface. pkt: %s\n", pkt->print()); + return accessLatency(); + } + + return 0; +} + +Tick +PolicyManager::recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &backdoor) +{ + Tick latency = recvAtomic(pkt); + getBackdoor(backdoor); + return latency; +} + +void +PolicyManager::recvFunctional(PacketPtr pkt) +{ + bool found; + + if (getAddrRange().contains(pkt->getAddr())) { + // rely on the abstract memory + functionalAccess(pkt); + found = true; + } else { + found = false; + } + + panic_if(!found, "Can't handle address range for packet %s\n", + pkt->print()); +} + +Tick +PolicyManager::accessLatency() +{ + // THIS IS FOR DRAM ONLY! + // return (tRP + tRCD_RD + tRL); + return (locMem->get_tRP() + locMem->get_tRCD_RD() + locMem->get_tRL()); +} + +bool +PolicyManager::findInORB(Addr addr) +{ + bool found = false; + for (const auto& e : ORB) { + if (e.second->owPkt->getAddr() == addr) { + found = true; + } + } + + return found; +} + +unsigned +PolicyManager::findDupInORB(Addr addr) +{ + unsigned count=0; + for (const auto& e : ORB) { + if (e.second->owPkt->getAddr() == addr) { + + count++; + } + } + return count; +} + +void +PolicyManager::init() +{ + if (!port.isConnected()) { + fatal("Policy Manager %s is unconnected!\n", name()); + } else if (!locReqPort.isConnected()) { + fatal("Policy Manager %s is unconnected!\n", name()); + } else if (!farReqPort.isConnected()) { + fatal("Policy Manager %s is unconnected!\n", name()); + } else { + port.sendRangeChange(); + //reqPort.recvRangeChange(); + } +} + +bool +PolicyManager::recvTimingReq(PacketPtr pkt) +{ + if (bypassDcache) { + return farReqPort.sendTimingReq(pkt); + } + + // This is where we enter from the outside world + DPRINTF(PolicyManager, "recvTimingReq: request %s addr 0x%x-> %d size %d\n", + pkt->cmdString(), pkt->getAddr(), pkt->getAddr(), pkt->getSize()); + + panic_if(pkt->cacheResponding(), "Should not see packets where cache " + "is responding"); + + panic_if(!(pkt->isRead() || pkt->isWrite()), + "Should only see read and writes at memory controller\n"); + assert(pkt->getSize() != 0); + + // Calc avg gap between requests + if (prevArrival != 0) { + polManStats.totGap += curTick() - prevArrival; + } + prevArrival = curTick(); + + // Find out how many memory packets a pkt translates to + // If the burst size is equal or larger than the pkt size, then a pkt + // translates to only one memory packet. Otherwise, a pkt translates to + // multiple memory packets + + const Addr base_addr = pkt->getAddr(); + Addr addr = base_addr; + uint32_t burst_size = locBurstSize; + unsigned size = std::min((addr | (burst_size - 1)) + 1, + base_addr + pkt->getSize()) - addr; + + // check merging for writes + if (pkt->isWrite()) { + + // polManStats.writePktSize[ceilLog2(size)]++; + + bool merged = isInWriteQueue.find((addr & ~(Addr(locBurstSize - 1)))) != + isInWriteQueue.end(); + + bool mergedInLocMemFB = locMem->checkFwdMrgeInFB(pkt->getAddr()); + + assert(!(mergedInLocMemFB && merged)); + + if (merged) { + + polManStats.mergedWrBursts++; + polManStats.mergedWrPolManWB++; + + DPRINTF(PolicyManager, "merged in policy manager write back buffer: %lld\n", pkt->getAddr()); + + // farMemCtrl->accessInterface(pkt); + + // sendRespondToRequestor(pkt, frontendLatency); + accessAndRespond(pkt, frontendLatency); + return true; + } else if (mergedInLocMemFB) { + + polManStats.mergedWrBursts++; + polManStats.mergedWrLocMemFB++; + + DPRINTF(PolicyManager, "merged in DRAM cache flush buffer: %lld\n", pkt->getAddr()); + + // farMemCtrl->accessInterface(pkt); + + // sendRespondToRequestor(pkt, frontendLatency); + accessAndRespond(pkt, frontendLatency); + return true; + } + + } + + // check forwarding for reads + bool foundInORB = false; + bool foundInCRB = false; + bool foundInFarMemWrite = false; + bool foundInLocMemFB = false; + + if (pkt->isRead()) { + + if (isInWriteQueue.find(pkt->getAddr()) != isInWriteQueue.end()) { + + if (!ORB.empty()) { + for (const auto& e : ORB) { + + // check if the read is subsumed in the write queue + // packet we are looking at + if (e.second->validEntry && + e.second->owPkt->isWrite() && + e.second->owPkt->getAddr() <= addr && + ((addr + size) <= + (e.second->owPkt->getAddr() + + e.second->owPkt->getSize()))) { + + foundInORB = true; + + polManStats.servicedByWrQ++; + + polManStats.bytesReadWrQ += burst_size; + + break; + } + } + } + + if (!foundInORB && !CRB.empty()) { + for (const auto& e : CRB) { + + // check if the read is subsumed in the write queue + // packet we are looking at + if (e.second->isWrite() && + e.second->getAddr() <= addr && + ((addr + size) <= + (e.second->getAddr() + e.second->getSize()))) { + + foundInCRB = true; + + polManStats.servicedByWrQ++; + + polManStats.bytesReadWrQ += burst_size; + + break; + } + } + } + + if (!foundInORB && !foundInCRB && !pktFarMemWrite.empty()) { + for (const auto& e : pktFarMemWrite) { + // check if the read is subsumed in the write queue + // packet we are looking at + if (e.second->getAddr() <= addr && + ((addr + size) <= + (e.second->getAddr() + + e.second->getSize()))) { + + foundInFarMemWrite = true; + + polManStats.servicedByWrQ++; + + polManStats.bytesReadWrQ += burst_size; + + break; + } + } + } + } + + if (locMem->checkFwdMrgeInFB(pkt->getAddr())) { + // This is not faithful to the real hardware + // for transferring the FB data to the policy manager + // since the case is very rare. + foundInLocMemFB = true; + + polManStats.servicedByFB++; + + polManStats.bytesReadWrQ += burst_size; + } + + if (foundInORB || foundInCRB || foundInFarMemWrite || foundInLocMemFB) { + DPRINTF(PolicyManager, "FW: %lld\n", pkt->getAddr()); + + polManStats.readPktSize[ceilLog2(size)]++; + + // farMemCtrl->accessInterface(pkt); + + // sendRespondToRequestor(pkt, frontendLatency); + accessAndRespond(pkt, frontendLatency); + return true; + } + } + + // process conflicting requests. + // conflicts are checked only based on Index of DRAM cache + if (checkConflictInORB(pkt)) { + + polManStats.totNumConf++; + + if (CRB.size()>=crbMaxSize) { + + DPRINTF(PolicyManager, "CRBfull: %lld\n", pkt->getAddr()); + + polManStats.totNumCRBFull++; + + retryLLC = true; + + if (pkt->isRead()) { + polManStats.numRdRetry++; + } + else { + polManStats.numWrRetry++; + } + return false; + } + + CRB.push_back(std::make_pair(curTick(), pkt)); + DPRINTF(PolicyManager, "CRB PB: %d: %s\n", pkt->getAddr(), pkt->cmdString()); + + if (pkt->isWrite()) { + isInWriteQueue.insert(pkt->getAddr()); + } + + if (CRB.size() > maxConf) { + maxConf = CRB.size(); + polManStats.maxNumConf = CRB.size(); + } + return true; + } + // check if ORB or FMWB is full and set retry + if (pktFarMemWrite.size() >= (orbMaxSize / 2)) { + + DPRINTF(PolicyManager, "FMWBfull: %lld\n", pkt->getAddr()); + + retryLLCFarMemWr = true; + + if (pkt->isRead()) { + polManStats.numRdRetry++; + } + else { + polManStats.numWrRetry++; + } + return false; + } + + if (ORB.size() >= orbMaxSize) { + + DPRINTF(PolicyManager, "ORBfull: addr %lld\n", pkt->getAddr()); + + polManStats.totNumORBFull++; + + retryLLC = true; + + if (pkt->isRead()) { + polManStats.numRdRetry++; + } + else { + polManStats.numWrRetry++; + } + return false; + } + + // if none of the above cases happens, + // add it to the ORB + handleRequestorPkt(pkt); + + if (pkt->isWrite()) { + isInWriteQueue.insert(pkt->getAddr()); + } + + setNextState(ORB.at(pkt->getAddr())); + + handleNextState(ORB.at(pkt->getAddr())); + + DPRINTF(PolicyManager, "Policy manager accepted packet 0x%x %d\n", pkt->getAddr(), pkt->getAddr()); + + return true; +} + +void +PolicyManager::processTagCheckEvent() +{ + // sanity check for the chosen packet + auto orbEntry = ORB.at(pktTagCheck.front()); + assert(orbEntry->pol == enums::Rambus || orbEntry->pol == enums::RambusTagProbOpt); + assert(orbEntry->validEntry); + assert(orbEntry->state == tagCheck); + assert(!orbEntry->issued); + + PacketPtr tagCheckPktPtr; + + if (orbEntry->owPkt->isRead()) { + tagCheckPktPtr = getPacket(pktTagCheck.front(), + blockSize, + MemCmd::ReadReq); + } else { + assert(orbEntry->owPkt->isWrite()); + tagCheckPktPtr = getPacket(pktTagCheck.front(), + blockSize, + MemCmd::WriteReq); + } + + tagCheckPktPtr->isTagCheck = true; + tagCheckPktPtr->isLocMem = true; + tagCheckPktPtr->owIsRead = orbEntry->owPkt->isRead(); + tagCheckPktPtr->isHit = orbEntry->isHit; + tagCheckPktPtr->isDirty = orbEntry->prevDirty; + assert(!tagCheckPktPtr->hasDirtyData); + tagCheckPktPtr->dirtyLineAddr = orbEntry->dirtyLineAddr; + + if (extreme) { + tagCheckPktPtr->isDirty = alwaysDirty; + tagCheckPktPtr->isHit = alwaysHit; + } + + if (tagCheckPktPtr->owIsRead && !tagCheckPktPtr->isHit) { + + if (!tagCheckPktPtr->isDirty) { + assert(tagCheckPktPtr->dirtyLineAddr == -1); + } else { + assert(tagCheckPktPtr->dirtyLineAddr != -1); + } + } + + if (locReqPort.sendTimingReq(tagCheckPktPtr)) { + DPRINTF(PolicyManager, "Tag check req sent for adr: %lld\n", tagCheckPktPtr->getAddr()); + orbEntry->state = waitingTCtag; + orbEntry->issued = true; + orbEntry->tagCheckIssued = curTick(); + pktTagCheck.pop_front(); + polManStats.sentTagCheckPort++; + } else { + DPRINTF(PolicyManager, "Sending tag check failed for adr: %lld\n", tagCheckPktPtr->getAddr()); + retryTagCheck = true; + delete tagCheckPktPtr; + polManStats.failedTagCheckPort++; + } + + if (!pktTagCheck.empty() && !tagCheckEvent.scheduled() && !retryTagCheck) { + schedule(tagCheckEvent, curTick()+1000); + } +} + +void +PolicyManager::processLocMemReadEvent() +{ + // sanity check for the chosen packet + auto orbEntry = ORB.at(pktLocMemRead.front()); + DPRINTF(PolicyManager, "loc mem read START : %lld--> %d, %d, %d, %d, %d, %d, %d:\n", orbEntry->owPkt->getAddr(), ORB.size(), pktLocMemRead.size(), + pktLocMemWrite.size(), pktFarMemRead.size(), pktFarMemWrite.size(), CRB.size(), orbEntry->state); + assert(orbEntry->validEntry); + assert(orbEntry->state == locMemRead); + assert(!orbEntry->issued); + + PacketPtr rdLocMemPkt = getPacket(pktLocMemRead.front(), + blockSize, + MemCmd::ReadReq); + rdLocMemPkt->isLocMem = true; + if (locReqPort.sendTimingReq(rdLocMemPkt)) { + DPRINTF(PolicyManager, "loc mem read is sent : %lld--> %d, %d, %d, %d, %d, %d\n", rdLocMemPkt->getAddr(), ORB.size(), pktLocMemRead.size(), + pktLocMemWrite.size(), pktFarMemRead.size(), pktFarMemWrite.size(), CRB.size()); + orbEntry->state = waitingLocMemReadResp; + orbEntry->issued = true; + orbEntry->locRdIssued = curTick(); + pktLocMemRead.pop_front(); + polManStats.sentLocRdPort++; + } else { + DPRINTF(PolicyManager, "loc mem read sending failed: %lld\n", rdLocMemPkt->getAddr()); + retryLocMemRead = true; + delete rdLocMemPkt; + polManStats.failedLocRdPort++; + } + + if (!pktLocMemRead.empty() && !locMemReadEvent.scheduled() && !retryLocMemRead) { + schedule(locMemReadEvent, curTick()+1000); + } +} + +void +PolicyManager::processLocMemWriteEvent() +{ + // sanity check for the chosen packet + auto orbEntry = ORB.at(pktLocMemWrite.front()); + DPRINTF(PolicyManager, "loc mem write START : %lld--> %d, %d, %d, %d, %d, %d, %d:\n", orbEntry->owPkt->getAddr(), ORB.size(), pktLocMemRead.size(), + pktLocMemWrite.size(), pktFarMemRead.size(), pktFarMemWrite.size(), CRB.size(), orbEntry->state); + assert(orbEntry->validEntry); + assert(orbEntry->state == locMemWrite); + assert(!orbEntry->issued); + + PacketPtr wrLocMemPkt = getPacket(pktLocMemWrite.front(), + blockSize, + MemCmd::WriteReq); + wrLocMemPkt->isLocMem = true; + assert(!wrLocMemPkt->isTagCheck); + + if (locReqPort.sendTimingReq(wrLocMemPkt)) { + DPRINTF(PolicyManager, "loc mem write is sent : %lld\n", wrLocMemPkt->getAddr()); + orbEntry->state = waitingLocMemWriteResp; + orbEntry->issued = true; + orbEntry->locWrIssued = curTick(); + pktLocMemWrite.pop_front(); + polManStats.sentLocWrPort++; + } else { + DPRINTF(PolicyManager, "loc mem write sending failed: %lld\n", wrLocMemPkt->getAddr()); + retryLocMemWrite = true; + delete wrLocMemPkt; + polManStats.failedLocWrPort++; + } + + if (!pktLocMemWrite.empty() && !locMemWriteEvent.scheduled() && !retryLocMemWrite) { + schedule(locMemWriteEvent, curTick()+1000); + } +} + +void +PolicyManager::processFarMemReadEvent() +{ + // sanity check for the chosen packet + auto orbEntry = ORB.at(pktFarMemRead.front()); + assert(orbEntry->validEntry); + assert(orbEntry->state == farMemRead); + assert(!orbEntry->issued); + + PacketPtr rdFarMemPkt = getPacket(pktFarMemRead.front(), + blockSize, + MemCmd::ReadReq); + + if (farReqPort.sendTimingReq(rdFarMemPkt)) { + DPRINTF(PolicyManager, "far mem read is sent : %lld\n", rdFarMemPkt->getAddr()); + orbEntry->state = waitingFarMemReadResp; + orbEntry->issued = true; + orbEntry->farRdIssued = curTick(); + pktFarMemRead.pop_front(); + polManStats.sentFarRdPort++; + } else { + DPRINTF(PolicyManager, "far mem read sending failed: %lld\n", rdFarMemPkt->getAddr()); + retryFarMemRead = true; + delete rdFarMemPkt; + polManStats.failedFarRdPort++; + } + + if (!pktFarMemRead.empty() && !farMemReadEvent.scheduled() && !retryFarMemRead) { + schedule(farMemReadEvent, curTick()+1000); + } +} + +void +PolicyManager::processFarMemWriteEvent() +{ + PacketPtr wrFarMemPkt = getPacket(pktFarMemWrite.front().second->getAddr(), + blockSize, + MemCmd::WriteReq); + DPRINTF(PolicyManager, "FarMemWriteEvent: request %s addr %#x\n", + wrFarMemPkt->cmdString(), wrFarMemPkt->getAddr()); + + if (farReqPort.sendTimingReq(wrFarMemPkt)) { + DPRINTF(PolicyManager, "far mem write is sent : %lld\n", wrFarMemPkt->getAddr()); + pktFarMemWrite.pop_front(); + polManStats.sentFarWrPort++; + } else { + DPRINTF(PolicyManager, "far mem write sending failed: %lld\n", wrFarMemPkt->getAddr()); + retryFarMemWrite = true; + delete wrFarMemPkt; + polManStats.failedFarWrPort++; + } + + if (!pktFarMemWrite.empty() && !farMemWriteEvent.scheduled() && !retryFarMemWrite) { + schedule(farMemWriteEvent, curTick()+1000); + } else { + if (drainState() == DrainState::Draining && pktFarMemWrite.empty() && + ORB.empty()) { + DPRINTF(Drain, "PolicyManager done draining in farMemWrite\n"); + signalDrainDone(); + } + } + + if (retryLLCFarMemWr && pktFarMemWrite.size()< (orbMaxSize / 2)) { + + DPRINTF(PolicyManager, "retryLLCFarMemWr sent\n"); + + retryLLCFarMemWr = false; + + port.sendRetryReq(); + } +} + +bool +PolicyManager::locMemRecvTimingResp(PacketPtr pkt) +{ + DPRINTF(PolicyManager, "locMemRecvTimingResp : %d: %s\n", pkt->getAddr(), pkt->cmdString()); + + // either read miss dirty data, + // or read miss clean FB data, + // or stall and send from FB + if ((locMemPolicy == enums::Rambus || locMemPolicy == enums::RambusTagProbOpt) + && !pkt->isTagCheck && pkt->hasDirtyData) { + DPRINTF(PolicyManager, "locMemRecvTimingResp: rd miss data async %d:\n", pkt->getAddr()); + assert(pkt->owIsRead); + assert(!pkt->isHit); + handleDirtyCacheLine(pkt->dirtyLineAddr); + if (pkt->isDirty && locMemPolicy == enums::RambusTagProbOpt) { + auto orbEntry = ORB.at(pkt->getAddr()); + assert(!orbEntry->rcvdLocRdResp); + orbEntry->rcvdLocRdResp = true; + if (orbEntry->rcvdLocRdResp && orbEntry->rcvdFarRdResp) { + orbEntry->state = locMemWrite; + orbEntry->locWrEntered = curTick(); + orbEntry->issued = false; + handleNextState(orbEntry); + } + } + delete pkt; + return true; + } + + if (!findInORB(pkt->getAddr())) { + std::cout << "!findInORB: " << pkt->getAddr() << " / " << pkt->cmdString() << "\n"; + std::cout << "+++++++++++++++++++++\n+++++++++++++++++++++\n+++++++++++++++++++++\n"; + } + + auto orbEntry = ORB.at(pkt->getAddr()); + + if(pkt->isTagCheck) { + + assert(orbEntry->pol == enums::Rambus || orbEntry->pol == enums::RambusTagProbOpt); + assert(orbEntry->state == waitingTCtag); + + if (pkt->hasDirtyData) { + assert(orbEntry->owPkt->isRead()); + assert(!orbEntry->isHit); + if (!orbEntry->prevDirty) { // rd miss clean with FB dirty data + assert(orbEntry->dirtyLineAddr == -1); + assert(!orbEntry->handleDirtyLine); + orbEntry->handleDirtyLine = true; + orbEntry->dirtyLineAddr = pkt->dirtyLineAddr; + } else { // dirty + assert(orbEntry->dirtyLineAddr != -1); + assert(orbEntry->handleDirtyLine); + } + } + + // Rd Miss Dirty + if (orbEntry->owPkt->isRead() && !orbEntry->isHit && orbEntry->prevDirty) { + if (locMemPolicy == enums::Rambus) { + // This assert is true only for Rambus policy. + // for RambusTagProbOpt it can be either true or false, + // since a Rd MD TC packet may or may not be probed + // and will carry a dirty flag or not. If it is probed, + // this flag will be set later! not when TC is sent! + assert(pkt->hasDirtyData); + } + assert(orbEntry->handleDirtyLine); + assert(orbEntry->dirtyLineAddr != -1); + } + + // if (!(orbEntry->owPkt->isRead() && orbEntry->isHit)) { + // orbEntry->tagCheckExit = curTick(); + // } + orbEntry->tagCheckExit = curTick(); + + if (orbEntry->owPkt->isRead() && orbEntry->isHit) { + orbEntry->state = waitingLocMemReadResp; + } + + } else { + if (pkt->isRead()) { + + if (orbEntry->pol == enums::CascadeLakeNoPartWrs || + orbEntry->pol == enums::Oracle || + orbEntry->pol == enums::BearWriteOpt) + { + assert(orbEntry->state == waitingLocMemReadResp); + if (orbEntry->handleDirtyLine) { + assert(!orbEntry->isHit); + handleDirtyCacheLine(orbEntry->dirtyLineAddr); + } + orbEntry->locRdExit = curTick(); + } + + if (orbEntry->pol == enums::Rambus || orbEntry->pol == enums::RambusTagProbOpt) { + assert(orbEntry->state == waitingLocMemReadResp); + assert(orbEntry->isHit); + assert(!pkt->hasDirtyData); + assert(orbEntry->dirtyLineAddr == -1); + orbEntry->locRdExit = curTick(); + orbEntry->state = locRdRespReady; + + // else { + // // just a null data, which resembles the bubble on the data bus for this case in Rambus-baseline + // assert(pkt->owIsRead && !pkt->isHit && !pkt->isDirty && !pkt->hasDirtyData); + // return true; + // } + } + + } + else { + assert(pkt->isWrite()); + + if (orbEntry->pol == enums::CascadeLakeNoPartWrs || + orbEntry->pol == enums::Oracle || + orbEntry->pol == enums::BearWriteOpt) + { + assert(orbEntry->state == waitingLocMemWriteResp); + orbEntry->locWrExit = curTick(); + } + + if (orbEntry->pol == enums::Rambus || orbEntry->pol == enums::RambusTagProbOpt) { + if (orbEntry->state == waitingLocMemWriteResp) { + assert(orbEntry->owPkt->isRead()); + assert(!orbEntry->isHit); + orbEntry->locWrExit = curTick(); + } + if (orbEntry->state == waitingTCtag) { + assert(orbEntry->owPkt->isWrite()); + orbEntry->tagCheckExit = curTick(); + } + } + + + } + } + + // IMPORTANT: + // orbEntry should not be used as the passed argument in setNextState and + // handleNextState functions, reason: it's possible that orbEntry may be + // deleted and updated, which will not be reflected here in the scope of + // current lines since it's been read at line #475. + setNextState(ORB.at(pkt->getAddr())); + + handleNextState(ORB.at(pkt->getAddr())); + + delete pkt; + + return true; +} + +bool +PolicyManager::farMemRecvTimingResp(PacketPtr pkt) +{ + if (bypassDcache) { + port.schedTimingResp(pkt, curTick()); + return true; + } + + DPRINTF(PolicyManager, "farMemRecvTimingResp : %lld , %s \n", pkt->getAddr(), pkt->cmdString()); + + if (pkt->isRead()) { + auto orbEntry = ORB.at(pkt->getAddr()); + + DPRINTF(PolicyManager, "farMemRecvTimingResp : continuing to far read resp: %d\n", + orbEntry->owPkt->isRead()); + + assert(orbEntry->state == waitingFarMemReadResp); + + if (locMemPolicy == enums::RambusTagProbOpt && + !orbEntry->isHit && orbEntry->prevDirty) { + assert(!orbEntry->rcvdFarRdResp); + orbEntry->rcvdFarRdResp = true; + } + + orbEntry->farRdExit = curTick(); + + // IMPORTANT: + // orbEntry should not be used as the passed argument in setNextState and + // handleNextState functions, reason: it's possible that orbEntry may be + // deleted and updated, which will not be reflected here in the scope of + // current lines since it's been read at line #508. + setNextState(ORB.at(pkt->getAddr())); + + // The next line is absolutely required since the orbEntry will + // be deleted and renewed within setNextState() + // orbEntry = ORB.at(pkt->getAddr()); + + handleNextState(ORB.at(pkt->getAddr())); + + delete pkt; + } + else { + assert(pkt->isWrite()); + delete pkt; + } + + return true; +} + +void +PolicyManager::locMemRecvReqRetry() +{ + // assert(retryLocMemRead || retryLocMemWrite); + DPRINTF(PolicyManager, "locMemRecvReqRetry start: %d, %d , %d \n", retryTagCheck, retryLocMemRead, retryLocMemWrite); + bool schedTC = false; + bool schedRd = false; + bool schedWr = false; + + if (retryTagCheck) { + + if (!tagCheckEvent.scheduled() && !pktTagCheck.empty()) { + assert(locMemPolicy == enums::Rambus || locMemPolicy == enums::RambusTagProbOpt); + schedule(tagCheckEvent, curTick()); + } + retryTagCheck = false; + schedTC = true; + } + + if (retryLocMemRead) { + + if (!locMemReadEvent.scheduled() && !pktLocMemRead.empty()) { + schedule(locMemReadEvent, curTick()); + } + retryLocMemRead = false; + schedRd = true; + } + + if (retryLocMemWrite) { + if (!locMemWriteEvent.scheduled() && !pktLocMemWrite.empty()) { + schedule(locMemWriteEvent, curTick()); + } + retryLocMemWrite = false; + schedWr = true; + } + if (!schedTC && !schedRd && !schedWr) { + // panic("Wrong local mem retry event happend.\n"); + + // TODO: there are cases where none of retryLocMemRead and retryLocMemWrite + // are true, yet locMemRecvReqRetry() is called. I should fix this later. + if ((locMemPolicy == enums::Rambus || locMemPolicy == enums::RambusTagProbOpt) && !tagCheckEvent.scheduled() && !pktTagCheck.empty()) { + schedule(tagCheckEvent, curTick()); + } + if (!locMemReadEvent.scheduled() && !pktLocMemRead.empty()) { + schedule(locMemReadEvent, curTick()); + } + if (!locMemWriteEvent.scheduled() && !pktLocMemWrite.empty()) { + schedule(locMemWriteEvent, curTick()); + } + } + + DPRINTF(PolicyManager, "locMemRecvReqRetry end: %d, %d , %d \n", schedTC, schedRd, schedWr); +} + +void +PolicyManager::farMemRecvReqRetry() +{ + if (bypassDcache) { + port.sendRetryReq(); + return; + } + + // assert(retryFarMemRead || retryFarMemWrite); + + bool schedRd = false; + bool schedWr = false; + + if (retryFarMemRead) { + if (!farMemReadEvent.scheduled() && !pktFarMemRead.empty()) { + schedule(farMemReadEvent, curTick()); + } + retryFarMemRead = false; + schedRd = true; + } + if (retryFarMemWrite) { + if (!farMemWriteEvent.scheduled() && !pktFarMemWrite.empty()) { + schedule(farMemWriteEvent, curTick()); + } + retryFarMemWrite = false; + schedWr = true; + } + // else { + // panic("Wrong far mem retry event happend.\n"); + // } + if (!schedRd && !schedWr) { + // panic("Wrong local mem retry event happend.\n"); + + // TODO: there are cases where none of retryFarMemRead and retryFarMemWrite + // are true, yet farMemRecvReqRetry() is called. I should fix this later. + if (!farMemReadEvent.scheduled() && !pktFarMemRead.empty()) { + schedule(farMemReadEvent, curTick()); + } + if (!farMemWriteEvent.scheduled() && !pktFarMemWrite.empty()) { + schedule(farMemWriteEvent, curTick()); + } + } + + DPRINTF(PolicyManager, "farMemRecvReqRetry: %d , %d \n", schedRd, schedWr); +} + +void +PolicyManager::setNextState(reqBufferEntry* orbEntry) +{ + orbEntry->issued = false; + enums::Policy pol = orbEntry->pol; + reqState state = orbEntry->state; + bool isRead = orbEntry->owPkt->isRead(); + bool isHit = orbEntry->isHit; + //This must be checked for the first 3 policies, later. + // bool isDirty = checkDirty(orbEntry->owPkt->getAddr()); + bool isDirty = orbEntry->prevDirty; + + /////////////////////////////////////////////////////////////////////////////////////// + // CascadeLakeNoPartWrs + + // start --> read tag + if (orbEntry->pol == enums::CascadeLakeNoPartWrs && + orbEntry->state == start) { + orbEntry->state = locMemRead; + orbEntry->locRdEntered = curTick(); + return; + } + + // tag ready && read && hit --> DONE + if (orbEntry->pol == enums::CascadeLakeNoPartWrs && + orbEntry->owPkt->isRead() && + orbEntry->state == waitingLocMemReadResp && + orbEntry->isHit) { + // done + // do nothing + return; + } + + // tag ready && write --> loc write + if (orbEntry->pol == enums::CascadeLakeNoPartWrs && + orbEntry->owPkt->isWrite() && + orbEntry->state == waitingLocMemReadResp) { + // write it to the DRAM cache + orbEntry->state = locMemWrite; + orbEntry->locWrEntered = curTick(); + return; + } + + // loc read resp ready && read && miss --> far read + if (orbEntry->pol == enums::CascadeLakeNoPartWrs && + orbEntry->owPkt->isRead() && + orbEntry->state == waitingLocMemReadResp && + !orbEntry->isHit) { + + orbEntry->state = farMemRead; + orbEntry->farRdEntered = curTick(); + return; + } + + // far read resp ready && read && miss --> loc write + if (orbEntry->pol == enums::CascadeLakeNoPartWrs && + orbEntry->owPkt->isRead() && + orbEntry->state == waitingFarMemReadResp && + !orbEntry->isHit) { + + PacketPtr copyOwPkt = new Packet(orbEntry->owPkt, + false, + orbEntry->owPkt->isRead()); + + accessAndRespond(orbEntry->owPkt, + frontendLatency + backendLatency + backendLatency); + + ORB.at(copyOwPkt->getAddr()) = new reqBufferEntry( + orbEntry->validEntry, + orbEntry->arrivalTick, + orbEntry->tagDC, + orbEntry->indexDC, + orbEntry->wayNum, + copyOwPkt, + orbEntry->pol, + orbEntry->state, + orbEntry->issued, + orbEntry->isHit, + orbEntry->conflict, + orbEntry->prevDirty, + orbEntry->rcvdLocRdResp, + orbEntry->rcvdFarRdResp, + orbEntry->dirtyLineAddr, + orbEntry->handleDirtyLine, + orbEntry->tagCheckEntered, + orbEntry->tagCheckIssued, + orbEntry->tagCheckExit, + orbEntry->locRdEntered, + orbEntry->locRdIssued, + orbEntry->locRdExit, + orbEntry->locWrEntered, + orbEntry->locWrIssued, + orbEntry->locWrExit, + orbEntry->farRdEntered, + orbEntry->farRdIssued, + orbEntry->farRdExit); + delete orbEntry; + + orbEntry = ORB.at(copyOwPkt->getAddr()); + + polManStats.totPktRespTime += ((curTick() - orbEntry->arrivalTick)/1000); + polManStats.totPktRespTimeRd += ((curTick() - orbEntry->arrivalTick)/1000); + + orbEntry->state = locMemWrite; + + orbEntry->locWrEntered = curTick(); + + return; + } + + // loc write received + if (orbEntry->pol == enums::CascadeLakeNoPartWrs && + // orbEntry->owPkt->isRead() && + // !orbEntry->isHit && + orbEntry->state == waitingLocMemWriteResp) { + // done + // do nothing + return; + } + + //////////////////////////////////////////////////////////////////////// + /// Oracle + + // RD Hit Dirty & Clean, RD Miss Dirty, WR Miss Dirty + // start --> read loc + if (pol == enums::Oracle && state == start && + ((isRead && isHit) || (isRead && !isHit && isDirty) || (!isRead && !isHit && isDirty)) + ) { + orbEntry->state = locMemRead; + orbEntry->locRdEntered = curTick(); + return; + } + // RD Miss Clean + // start --> read far + if (pol == enums::Oracle && state == start && + (isRead && !isHit && !isDirty) + ) { + orbEntry->state = farMemRead; + orbEntry->farRdEntered = curTick(); + return; + } + // WR Hit Dirty & Clean, WR Miss Clean + // start --> write loc + if (pol == enums::Oracle && state == start && + ((!isRead && isHit)|| (!isRead && !isHit && !isDirty)) + ) { + orbEntry->state = locMemWrite; + orbEntry->locWrEntered = curTick(); + return; + } + + // RD Hit Dirty & Clean + // start --> read loc --> done + if (pol == enums::Oracle && + isRead && isHit && + state == waitingLocMemReadResp ) { + // done + // do nothing + return; + } + + // RD Miss Dirty: + // start --> read loc --> read far + if (pol == enums::Oracle && + isRead && !isHit && isDirty && + state == waitingLocMemReadResp ) { + orbEntry->state = farMemRead; + orbEntry->farRdEntered = curTick(); + return; + } + + // WR Miss Dirty: + // start --> read loc --> loc write + if (pol == enums::Oracle && + !isRead && !isHit && isDirty && + state == waitingLocMemReadResp) { + // write it to the DRAM cache + orbEntry->state = locMemWrite; + orbEntry->locWrEntered = curTick(); + return; + } + + // RD Miss Clean & Dirty + // start --> ... --> far read -> loc write + if (pol == enums::Oracle && + (isRead && !isHit) && + state == waitingFarMemReadResp + ) { + PacketPtr copyOwPkt = new Packet(orbEntry->owPkt, + false, + orbEntry->owPkt->isRead()); + + accessAndRespond(orbEntry->owPkt, + frontendLatency + backendLatency + backendLatency); + + ORB.at(copyOwPkt->getAddr()) = new reqBufferEntry( + orbEntry->validEntry, + orbEntry->arrivalTick, + orbEntry->tagDC, + orbEntry->indexDC, + orbEntry->wayNum, + copyOwPkt, + orbEntry->pol, + orbEntry->state, + orbEntry->issued, + orbEntry->isHit, + orbEntry->conflict, + orbEntry->prevDirty, + orbEntry->rcvdLocRdResp, + orbEntry->rcvdFarRdResp, + orbEntry->dirtyLineAddr, + orbEntry->handleDirtyLine, + orbEntry->tagCheckEntered, + orbEntry->tagCheckIssued, + orbEntry->tagCheckExit, + orbEntry->locRdEntered, + orbEntry->locRdIssued, + orbEntry->locRdExit, + orbEntry->locWrEntered, + orbEntry->locWrIssued, + orbEntry->locWrExit, + orbEntry->farRdEntered, + orbEntry->farRdIssued, + orbEntry->farRdExit); + delete orbEntry; + + orbEntry = ORB.at(copyOwPkt->getAddr()); + + polManStats.totPktRespTime += ((curTick() - orbEntry->arrivalTick)/1000); + polManStats.totPktRespTimeRd += ((curTick() - orbEntry->arrivalTick)/1000); + + orbEntry->state = locMemWrite; + + orbEntry->locWrEntered = curTick(); + + return; + } + + // loc write received + if (pol == enums::Oracle && + state == waitingLocMemWriteResp) { + assert (!(isRead && isHit)); + // done + // do nothing + return; + } + + //////////////////////////////////////////////////////////////////////// + // BEAR Write optimized + if (orbEntry->pol == enums::BearWriteOpt && + orbEntry->state == start && !(orbEntry->owPkt->isWrite() && orbEntry->isHit)) { + orbEntry->state = locMemRead; + orbEntry->locRdEntered = curTick(); + DPRINTF(PolicyManager, "set: start -> locMemRead : %d\n", orbEntry->owPkt->getAddr()); + return; + } + + if (orbEntry->pol == enums::BearWriteOpt && + orbEntry->state == start && orbEntry->owPkt->isWrite() && orbEntry->isHit) { + orbEntry->state = locMemWrite; + orbEntry->locRdEntered = curTick(); + DPRINTF(PolicyManager, "set: start -> locMemWrite : %d\n", orbEntry->owPkt->getAddr()); + return; + } + + // tag ready && read && hit --> DONE + if (orbEntry->pol == enums::BearWriteOpt && + orbEntry->owPkt->isRead() && + orbEntry->state == waitingLocMemReadResp && + orbEntry->isHit) { + DPRINTF(PolicyManager, "set: waitingLocMemReadResp -> NONE : %d\n", orbEntry->owPkt->getAddr()); + + // done + // do nothing + return; + } + + // tag ready && write --> loc write + if (orbEntry->pol == enums::BearWriteOpt && + orbEntry->owPkt->isWrite() && + orbEntry->state == waitingLocMemReadResp) { + assert(!orbEntry->isHit); + // write it to the DRAM cache + orbEntry->state = locMemWrite; + orbEntry->locWrEntered = curTick(); + DPRINTF(PolicyManager, "set: waitingLocMemReadResp -> locMemWrite : %d\n", orbEntry->owPkt->getAddr()); + return; + } + + // loc read resp ready && read && miss --> far read + if (orbEntry->pol == enums::BearWriteOpt && + orbEntry->owPkt->isRead() && + orbEntry->state == waitingLocMemReadResp && + !orbEntry->isHit) { + + orbEntry->state = farMemRead; + orbEntry->farRdEntered = curTick(); + DPRINTF(PolicyManager, "set: waitingLocMemReadResp -> farMemRead : %d\n", orbEntry->owPkt->getAddr()); + return; + } + + // far read resp ready && read && miss --> loc write + if (orbEntry->pol == enums::BearWriteOpt && + orbEntry->owPkt->isRead() && + orbEntry->state == waitingFarMemReadResp && + !orbEntry->isHit) { + + PacketPtr copyOwPkt = new Packet(orbEntry->owPkt, + false, + orbEntry->owPkt->isRead()); + + accessAndRespond(orbEntry->owPkt, + frontendLatency + backendLatency + backendLatency); + + ORB.at(copyOwPkt->getAddr()) = new reqBufferEntry( + orbEntry->validEntry, + orbEntry->arrivalTick, + orbEntry->tagDC, + orbEntry->indexDC, + orbEntry->wayNum, + copyOwPkt, + orbEntry->pol, + orbEntry->state, + orbEntry->issued, + orbEntry->isHit, + orbEntry->conflict, + orbEntry->prevDirty, + orbEntry->rcvdLocRdResp, + orbEntry->rcvdFarRdResp, + orbEntry->dirtyLineAddr, + orbEntry->handleDirtyLine, + orbEntry->tagCheckEntered, + orbEntry->tagCheckIssued, + orbEntry->tagCheckExit, + orbEntry->locRdEntered, + orbEntry->locRdIssued, + orbEntry->locRdExit, + orbEntry->locWrEntered, + orbEntry->locWrIssued, + orbEntry->locWrExit, + orbEntry->farRdEntered, + orbEntry->farRdIssued, + orbEntry->farRdExit); + delete orbEntry; + + orbEntry = ORB.at(copyOwPkt->getAddr()); + + polManStats.totPktRespTime += ((curTick() - orbEntry->arrivalTick)/1000); + polManStats.totPktRespTimeRd += ((curTick() - orbEntry->arrivalTick)/1000); + + orbEntry->state = locMemWrite; + + orbEntry->locWrEntered = curTick(); + + DPRINTF(PolicyManager, "set: waitingFarMemReadResp -> locMemWrite : %d\n", orbEntry->owPkt->getAddr()); + + return; + } + + // loc write received + if (orbEntry->pol == enums::BearWriteOpt && + // orbEntry->owPkt->isRead() && + // !orbEntry->isHit && + orbEntry->state == waitingLocMemWriteResp) { + DPRINTF(PolicyManager, "set: waitingLocMemWriteResp -> NONE : %d\n", orbEntry->owPkt->getAddr()); + + // done + // do nothing + + return; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Rambus + // start --> read tag + if (orbEntry->pol == enums::Rambus && + orbEntry->state == start) { + orbEntry->state = tagCheck; + orbEntry->tagCheckEntered = curTick(); + return; + } + + // tag ready + // read && hit --> wait for data + if (orbEntry->pol == enums::Rambus && + orbEntry->state == waitingTCtag && + orbEntry->owPkt->isRead() && orbEntry->isHit) { + // orbEntry->state = waitingLocMemReadResp; + // do nothing + return; + } + + // tag ready + // read && miss --> don't wait for dirty data (MC with FB>0/MD), transition to far read + if (orbEntry->pol == enums::Rambus && + orbEntry->state == waitingTCtag && + orbEntry->owPkt->isRead() && + !orbEntry->isHit) { + orbEntry->state = farMemRead; + orbEntry->farRdEntered = curTick(); + return; + } + + // tag ready + // write --> done + if (orbEntry->pol == enums::Rambus && + orbEntry->state == waitingTCtag && + orbEntry->owPkt->isWrite()) { + // done, do nothing and return; + return; + } + + // tag ready && read && hit --> DONE + if (orbEntry->pol == enums::Rambus && + orbEntry->state == waitingLocMemReadResp) { + assert(orbEntry->isHit); + assert(orbEntry->owPkt->isRead()); + // done + // do nothing + return; + } + + // tag ready && read && hit --> DONE + if (orbEntry->pol == enums::Rambus && + orbEntry->state == locRdRespReady) { + assert(orbEntry->isHit); + assert(orbEntry->owPkt->isRead()); + // done + // do nothing + return; + } + + // far read resp ready && read && miss --> loc write + if (orbEntry->pol == enums::Rambus && + orbEntry->state == waitingFarMemReadResp) { + + assert(orbEntry->owPkt->isRead()); + assert(!orbEntry->isHit); + + PacketPtr copyOwPkt = new Packet(orbEntry->owPkt, + false, + orbEntry->owPkt->isRead()); + + accessAndRespond(orbEntry->owPkt, + frontendLatency + backendLatency + backendLatency); + + ORB.at(copyOwPkt->getAddr()) = new reqBufferEntry( + orbEntry->validEntry, + orbEntry->arrivalTick, + orbEntry->tagDC, + orbEntry->indexDC, + orbEntry->wayNum, + copyOwPkt, + orbEntry->pol, + orbEntry->state, + orbEntry->issued, + orbEntry->isHit, + orbEntry->conflict, + orbEntry->prevDirty, + orbEntry->rcvdLocRdResp, + orbEntry->rcvdFarRdResp, + orbEntry->dirtyLineAddr, + orbEntry->handleDirtyLine, + orbEntry->tagCheckEntered, + orbEntry->tagCheckIssued, + orbEntry->tagCheckExit, + orbEntry->locRdEntered, + orbEntry->locRdIssued, + orbEntry->locRdExit, + orbEntry->locWrEntered, + orbEntry->locWrIssued, + orbEntry->locWrExit, + orbEntry->farRdEntered, + orbEntry->farRdIssued, + orbEntry->farRdExit); + delete orbEntry; + + orbEntry = ORB.at(copyOwPkt->getAddr()); + + polManStats.totPktRespTime += ((curTick() - orbEntry->arrivalTick)/1000); + polManStats.totPktRespTimeRd += ((curTick() - orbEntry->arrivalTick)/1000); + + orbEntry->state = locMemWrite; + + orbEntry->locWrEntered = curTick(); + + return; + } + + // loc write received + if (orbEntry->pol == enums::Rambus && + orbEntry->state == waitingLocMemWriteResp) { + assert(orbEntry->owPkt->isRead()); + assert(!orbEntry->isHit); + // done + // do nothing + return; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // RambusTagProbOpt + // start --> read tag + if (orbEntry->pol == enums::RambusTagProbOpt && + orbEntry->state == start) { + orbEntry->state = tagCheck; + orbEntry->tagCheckEntered = curTick(); + return; + } + + // tag ready + // read && hit --> wait for data + if (orbEntry->pol == enums::RambusTagProbOpt && + orbEntry->state == waitingTCtag && + orbEntry->owPkt->isRead() && + orbEntry->isHit) { + // do nothing + return; + } + + // tag ready + // read && miss --> don't wait for dirty data (MC with FB>0/MD), transition to far read + if (orbEntry->pol == enums::RambusTagProbOpt && + orbEntry->state == waitingTCtag && + orbEntry->owPkt->isRead() && + !orbEntry->isHit) { + orbEntry->state = farMemRead; + orbEntry->farRdEntered = curTick(); + return; + } + + // tag ready + // write --> done + if (orbEntry->pol == enums::RambusTagProbOpt && + orbEntry->state == waitingTCtag && + orbEntry->owPkt->isWrite()) { + // done, do nothing and return; + return; + } + + // tag ready && read && hit --> DONE + if (orbEntry->pol == enums::RambusTagProbOpt && + orbEntry->state == waitingLocMemReadResp) { + assert(orbEntry->isHit); + assert(orbEntry->owPkt->isRead()); + // done + // do nothing + return; + } + + // tag ready && read && hit --> DONE + if (orbEntry->pol == enums::RambusTagProbOpt && + orbEntry->state == locRdRespReady) { + assert(orbEntry->isHit); + assert(orbEntry->owPkt->isRead()); + // done + // do nothing + return; + } + + // far read resp ready && read && miss --> loc write + if (orbEntry->pol == enums::RambusTagProbOpt && + orbEntry->state == waitingFarMemReadResp) { + + assert(orbEntry->owPkt->isRead()); + assert(!orbEntry->isHit); + + PacketPtr copyOwPkt = new Packet(orbEntry->owPkt, + false, + orbEntry->owPkt->isRead()); + + accessAndRespond(orbEntry->owPkt, + frontendLatency + backendLatency + backendLatency); + ORB.at(copyOwPkt->getAddr()) = new reqBufferEntry( + orbEntry->validEntry, + orbEntry->arrivalTick, + orbEntry->tagDC, + orbEntry->indexDC, + orbEntry->wayNum, + copyOwPkt, + orbEntry->pol, + orbEntry->state, + orbEntry->issued, + orbEntry->isHit, + orbEntry->conflict, + orbEntry->prevDirty, + orbEntry->rcvdLocRdResp, + orbEntry->rcvdFarRdResp, + orbEntry->dirtyLineAddr, + orbEntry->handleDirtyLine, + orbEntry->tagCheckEntered, + orbEntry->tagCheckIssued, + orbEntry->tagCheckExit, + orbEntry->locRdEntered, + orbEntry->locRdIssued, + orbEntry->locRdExit, + orbEntry->locWrEntered, + orbEntry->locWrIssued, + orbEntry->locWrExit, + orbEntry->farRdEntered, + orbEntry->farRdIssued, + orbEntry->farRdExit); + delete orbEntry; + + orbEntry = ORB.at(copyOwPkt->getAddr()); + + polManStats.totPktRespTime += ((curTick() - orbEntry->arrivalTick)/1000); + polManStats.totPktRespTimeRd += ((curTick() - orbEntry->arrivalTick)/1000); + + if (orbEntry->prevDirty && orbEntry->rcvdLocRdResp && orbEntry->rcvdFarRdResp) { + orbEntry->state = locMemWrite; + orbEntry->locWrEntered = curTick(); + } else if (!orbEntry->prevDirty) { + orbEntry->state = locMemWrite; + orbEntry->locWrEntered = curTick(); + } + + return; + } + + // loc write received + if (orbEntry->pol == enums::RambusTagProbOpt && + orbEntry->state == waitingLocMemWriteResp) { + assert(orbEntry->owPkt->isRead()); + assert(!orbEntry->isHit); + // done + // do nothing + return; + } +} + +void +PolicyManager::handleNextState(reqBufferEntry* orbEntry) +{ + //////////////////////////////////////////////////////////////////////// + // CascadeLakeNoPartWrs + + if (orbEntry->pol == enums::CascadeLakeNoPartWrs && + orbEntry->state == locMemRead) { + + // assert(!pktLocMemRead.empty()); + + pktLocMemRead.push_back(orbEntry->owPkt->getAddr()); + + polManStats.avgLocRdQLenEnq = pktLocMemRead.size(); + + if (!locMemReadEvent.scheduled() && !retryLocMemRead) { + schedule(locMemReadEvent, curTick()); + } + return; + } + + if (orbEntry->pol == enums::CascadeLakeNoPartWrs && + orbEntry->owPkt->isRead() && + orbEntry->state == waitingLocMemReadResp && + orbEntry->isHit) { + // DONE + // send the respond to the requestor + + PacketPtr copyOwPkt = new Packet(orbEntry->owPkt, + false, + orbEntry->owPkt->isRead()); + + accessAndRespond(orbEntry->owPkt, + frontendLatency + backendLatency); + + ORB.at(copyOwPkt->getAddr()) = new reqBufferEntry( + orbEntry->validEntry, + orbEntry->arrivalTick, + orbEntry->tagDC, + orbEntry->indexDC, + orbEntry->wayNum, + copyOwPkt, + orbEntry->pol, + orbEntry->state, + orbEntry->issued, + orbEntry->isHit, + orbEntry->conflict, + orbEntry->prevDirty, + orbEntry->rcvdLocRdResp, + orbEntry->rcvdFarRdResp, + orbEntry->dirtyLineAddr, + orbEntry->handleDirtyLine, + orbEntry->tagCheckEntered, + orbEntry->tagCheckIssued, + orbEntry->tagCheckExit, + orbEntry->locRdEntered, + orbEntry->locRdIssued, + orbEntry->locRdExit, + orbEntry->locWrEntered, + orbEntry->locWrIssued, + orbEntry->locWrExit, + orbEntry->farRdEntered, + orbEntry->farRdIssued, + orbEntry->farRdExit); + delete orbEntry; + + orbEntry = ORB.at(copyOwPkt->getAddr()); + + polManStats.totPktRespTime += ((curTick() - orbEntry->arrivalTick)/1000); + polManStats.totPktRespTimeRd += ((curTick() - orbEntry->arrivalTick)/1000); + + // clear ORB + resumeConflictingReq(orbEntry); + + return; + } + + if (orbEntry->pol == enums::CascadeLakeNoPartWrs && + orbEntry->owPkt->isRead() && + orbEntry->state == farMemRead) { + + assert(!orbEntry->isHit); + + // do a read from far mem + pktFarMemRead.push_back(orbEntry->owPkt->getAddr()); + + polManStats.avgFarRdQLenEnq = pktFarMemRead.size(); + + if (!farMemReadEvent.scheduled() && !retryFarMemRead) { + schedule(farMemReadEvent, curTick()); + } + return; + + } + + if (orbEntry->pol == enums::CascadeLakeNoPartWrs && + orbEntry->state == locMemWrite) { + + if (orbEntry->owPkt->isRead()) { + assert(!orbEntry->isHit); + } + + // do a read from far mem + pktLocMemWrite.push_back(orbEntry->owPkt->getAddr()); + + polManStats.avgLocWrQLenEnq = pktLocMemWrite.size(); + + + if (!locMemWriteEvent.scheduled() && !retryLocMemWrite) { + schedule(locMemWriteEvent, curTick()); + } + return; + + } + + if (orbEntry->pol == enums::CascadeLakeNoPartWrs && + // orbEntry->owPkt->isRead() && + // !orbEntry->isHit && + orbEntry->state == waitingLocMemWriteResp) { + // DONE + // clear ORB + resumeConflictingReq(orbEntry); + + return; + } + + //////////////////////////////////////////////////////////////////////// + // Oracle + if (orbEntry->pol == enums::Oracle && + orbEntry->state == locMemRead) { + + pktLocMemRead.push_back(orbEntry->owPkt->getAddr()); + + polManStats.avgLocRdQLenEnq = pktLocMemRead.size(); + + if (!locMemReadEvent.scheduled() && !retryLocMemRead) { + schedule(locMemReadEvent, curTick()); + } + return; + } + + if (orbEntry->pol == enums::Oracle && + orbEntry->owPkt->isRead() && + orbEntry->state == waitingLocMemReadResp && + orbEntry->isHit) { + // DONE + // send the respond to the requestor + + PacketPtr copyOwPkt = new Packet(orbEntry->owPkt, + false, + orbEntry->owPkt->isRead()); + + accessAndRespond(orbEntry->owPkt, + frontendLatency + backendLatency); + + ORB.at(copyOwPkt->getAddr()) = new reqBufferEntry( + orbEntry->validEntry, + orbEntry->arrivalTick, + orbEntry->tagDC, + orbEntry->indexDC, + orbEntry->wayNum, + copyOwPkt, + orbEntry->pol, + orbEntry->state, + orbEntry->issued, + orbEntry->isHit, + orbEntry->conflict, + orbEntry->prevDirty, + orbEntry->rcvdLocRdResp, + orbEntry->rcvdFarRdResp, + orbEntry->dirtyLineAddr, + orbEntry->handleDirtyLine, + orbEntry->tagCheckEntered, + orbEntry->tagCheckIssued, + orbEntry->tagCheckExit, + orbEntry->locRdEntered, + orbEntry->locRdIssued, + orbEntry->locRdExit, + orbEntry->locWrEntered, + orbEntry->locWrIssued, + orbEntry->locWrExit, + orbEntry->farRdEntered, + orbEntry->farRdIssued, + orbEntry->farRdExit); + delete orbEntry; + + orbEntry = ORB.at(copyOwPkt->getAddr()); + + polManStats.totPktRespTime += ((curTick() - orbEntry->arrivalTick)/1000); + polManStats.totPktRespTimeRd += ((curTick() - orbEntry->arrivalTick)/1000); + + // clear ORB + resumeConflictingReq(orbEntry); + + return; + } + + if (orbEntry->pol == enums::Oracle && + orbEntry->state == farMemRead) { + + assert(orbEntry->owPkt->isRead() && !orbEntry->isHit); + + // do a read from far mem + pktFarMemRead.push_back(orbEntry->owPkt->getAddr()); + + polManStats.avgFarRdQLenEnq = pktFarMemRead.size(); + + if (!farMemReadEvent.scheduled() && !retryFarMemRead) { + schedule(farMemReadEvent, curTick()); + } + return; + + } + + if (orbEntry->pol == enums::Oracle && + orbEntry->state == locMemWrite) { + + if (orbEntry->owPkt->isRead()) { + assert(!orbEntry->isHit); + } + + // do a read from far mem + pktLocMemWrite.push_back(orbEntry->owPkt->getAddr()); + + polManStats.avgLocWrQLenEnq = pktLocMemWrite.size(); + + + if (!locMemWriteEvent.scheduled() && !retryLocMemWrite) { + schedule(locMemWriteEvent, curTick()); + } + return; + + } + + if (orbEntry->pol == enums::Oracle && + orbEntry->state == waitingLocMemWriteResp) { + // DONE + // clear ORB + resumeConflictingReq(orbEntry); + + return; + } + + //////////////////////////////////////////////////////////////////////// + // BEAR Write Optmized + if (orbEntry->pol == enums::BearWriteOpt && + orbEntry->state == locMemRead) { + + pktLocMemRead.push_back(orbEntry->owPkt->getAddr()); + + polManStats.avgLocRdQLenEnq = pktLocMemRead.size(); + + if (!locMemReadEvent.scheduled() && !retryLocMemRead) { + schedule(locMemReadEvent, curTick()); + } + return; + } + + if (orbEntry->pol == enums::BearWriteOpt && + orbEntry->owPkt->isRead() && + orbEntry->state == waitingLocMemReadResp && + orbEntry->isHit) { + // DONE + // send the respond to the requestor + + PacketPtr copyOwPkt = new Packet(orbEntry->owPkt, + false, + orbEntry->owPkt->isRead()); + + accessAndRespond(orbEntry->owPkt, + frontendLatency + backendLatency); + + ORB.at(copyOwPkt->getAddr()) = new reqBufferEntry( + orbEntry->validEntry, + orbEntry->arrivalTick, + orbEntry->tagDC, + orbEntry->indexDC, + orbEntry->wayNum, + copyOwPkt, + orbEntry->pol, + orbEntry->state, + orbEntry->issued, + orbEntry->isHit, + orbEntry->conflict, + orbEntry->prevDirty, + orbEntry->rcvdLocRdResp, + orbEntry->rcvdFarRdResp, + orbEntry->dirtyLineAddr, + orbEntry->handleDirtyLine, + orbEntry->tagCheckEntered, + orbEntry->tagCheckIssued, + orbEntry->tagCheckExit, + orbEntry->locRdEntered, + orbEntry->locRdIssued, + orbEntry->locRdExit, + orbEntry->locWrEntered, + orbEntry->locWrIssued, + orbEntry->locWrExit, + orbEntry->farRdEntered, + orbEntry->farRdIssued, + orbEntry->farRdExit); + delete orbEntry; + + orbEntry = ORB.at(copyOwPkt->getAddr()); + + polManStats.totPktRespTime += ((curTick() - orbEntry->arrivalTick)/1000); + polManStats.totPktRespTimeRd += ((curTick() - orbEntry->arrivalTick)/1000); + + // clear ORB + resumeConflictingReq(orbEntry); + + return; + } + + if (orbEntry->pol == enums::BearWriteOpt && + orbEntry->owPkt->isRead() && + orbEntry->state == farMemRead) { + + assert(!orbEntry->isHit); + + // do a read from far mem + pktFarMemRead.push_back(orbEntry->owPkt->getAddr()); + + polManStats.avgFarRdQLenEnq = pktFarMemRead.size(); + + if (!farMemReadEvent.scheduled() && !retryFarMemRead) { + schedule(farMemReadEvent, curTick()); + } + return; + + } + + if (orbEntry->pol == enums::BearWriteOpt && + orbEntry->state == locMemWrite) { + + if (orbEntry->owPkt->isRead()) { + assert(!orbEntry->isHit); + } + + // do a read from far mem + pktLocMemWrite.push_back(orbEntry->owPkt->getAddr()); + + polManStats.avgLocWrQLenEnq = pktLocMemWrite.size(); + + + if (!locMemWriteEvent.scheduled() && !retryLocMemWrite) { + schedule(locMemWriteEvent, curTick()); + } + return; + + } + + if (orbEntry->pol == enums::BearWriteOpt && + // orbEntry->owPkt->isRead() && + // !orbEntry->isHit && + orbEntry->state == waitingLocMemWriteResp) { + // DONE + // clear ORB + resumeConflictingReq(orbEntry); + + return; + } + + //////////////////////////////////////////////////////////////////////// + // Rambus + + if (orbEntry->pol == enums::Rambus && + orbEntry->state == tagCheck) { + + pktTagCheck.push_back(orbEntry->owPkt->getAddr()); + + polManStats.avgTagCheckQLenEnq = pktTagCheck.size(); + + if (!tagCheckEvent.scheduled() && !retryTagCheck) { + schedule(tagCheckEvent, curTick()); + } + return; + } + + if (orbEntry->pol == enums::Rambus && + orbEntry->state == waitingLocMemReadResp) { + return; + } + + if (orbEntry->pol == enums::Rambus && + orbEntry->state == locRdRespReady) { + assert(orbEntry->owPkt->isRead()); + assert(orbEntry->isHit); + // DONE + // send the respond to the requestor + + PacketPtr copyOwPkt = new Packet(orbEntry->owPkt, + false, + orbEntry->owPkt->isRead()); + + accessAndRespond(orbEntry->owPkt, + frontendLatency + backendLatency); + + ORB.at(copyOwPkt->getAddr()) = new reqBufferEntry( + orbEntry->validEntry, + orbEntry->arrivalTick, + orbEntry->tagDC, + orbEntry->indexDC, + orbEntry->wayNum, + copyOwPkt, + orbEntry->pol, + orbEntry->state, + orbEntry->issued, + orbEntry->isHit, + orbEntry->conflict, + orbEntry->prevDirty, + orbEntry->rcvdLocRdResp, + orbEntry->rcvdFarRdResp, + orbEntry->dirtyLineAddr, + orbEntry->handleDirtyLine, + orbEntry->tagCheckEntered, + orbEntry->tagCheckIssued, + orbEntry->tagCheckExit, + orbEntry->locRdEntered, + orbEntry->locRdIssued, + orbEntry->locRdExit, + orbEntry->locWrEntered, + orbEntry->locWrIssued, + orbEntry->locWrExit, + orbEntry->farRdEntered, + orbEntry->farRdIssued, + orbEntry->farRdExit); + delete orbEntry; + + orbEntry = ORB.at(copyOwPkt->getAddr()); + + polManStats.totPktRespTime += ((curTick() - orbEntry->arrivalTick)/1000); + polManStats.totPktRespTimeRd += ((curTick() - orbEntry->arrivalTick)/1000); + + // clear ORB + resumeConflictingReq(orbEntry); + + return; + } + + if (orbEntry->pol == enums::Rambus && + orbEntry->owPkt->isWrite()) { + // DONE + // respond for writes is already sent to the requestor. + // clear ORB + assert(orbEntry->state == waitingTCtag); + + resumeConflictingReq(orbEntry); + + return; + } + + if (orbEntry->pol == enums::Rambus && + orbEntry->state == farMemRead) { + + assert(orbEntry->owPkt->isRead()); + assert(!orbEntry->isHit); + + // do a read from far mem + pktFarMemRead.push_back(orbEntry->owPkt->getAddr()); + + polManStats.avgFarRdQLenEnq = pktFarMemRead.size(); + + if (!farMemReadEvent.scheduled() && !retryFarMemRead) { + schedule(farMemReadEvent, curTick()); + } + return; + + } + + if (orbEntry->pol == enums::Rambus && + orbEntry->state == locMemWrite) { + + assert(orbEntry->owPkt->isRead()); + assert(!orbEntry->isHit); + + pktLocMemWrite.push_back(orbEntry->owPkt->getAddr()); + + polManStats.avgLocWrQLenEnq = pktLocMemWrite.size(); + + + if (!locMemWriteEvent.scheduled() && !retryLocMemWrite) { + schedule(locMemWriteEvent, curTick()); + } + return; + + } + + if (orbEntry->pol == enums::Rambus && + // orbEntry->owPkt->isRead() && + // !orbEntry->isHit && + orbEntry->state == waitingLocMemWriteResp) { + // DONE + // clear ORB + assert(orbEntry->owPkt->isRead()); + assert(!orbEntry->isHit); + resumeConflictingReq(orbEntry); + + return; + } + + //////////////////////////////////////////////////////////////////////// + // RambusTagProbOpt + + if (orbEntry->pol == enums::RambusTagProbOpt && + orbEntry->state == tagCheck) { + + pktTagCheck.push_back(orbEntry->owPkt->getAddr()); + + polManStats.avgTagCheckQLenEnq = pktTagCheck.size(); + + if (!tagCheckEvent.scheduled() && !retryTagCheck) { + schedule(tagCheckEvent, curTick()); + } + return; + } + + if (orbEntry->pol == enums::RambusTagProbOpt && + orbEntry->state == waitingLocMemReadResp) { + return; + } + + if (orbEntry->pol == enums::RambusTagProbOpt && + orbEntry->state == locRdRespReady) { + assert(orbEntry->owPkt->isRead()); + assert(orbEntry->isHit); + // DONE + // send the respond to the requestor + + PacketPtr copyOwPkt = new Packet(orbEntry->owPkt, + false, + orbEntry->owPkt->isRead()); + + accessAndRespond(orbEntry->owPkt, + frontendLatency + backendLatency); + + ORB.at(copyOwPkt->getAddr()) = new reqBufferEntry( + orbEntry->validEntry, + orbEntry->arrivalTick, + orbEntry->tagDC, + orbEntry->indexDC, + orbEntry->wayNum, + copyOwPkt, + orbEntry->pol, + orbEntry->state, + orbEntry->issued, + orbEntry->isHit, + orbEntry->conflict, + orbEntry->prevDirty, + orbEntry->rcvdLocRdResp, + orbEntry->rcvdFarRdResp, + orbEntry->dirtyLineAddr, + orbEntry->handleDirtyLine, + orbEntry->tagCheckEntered, + orbEntry->tagCheckIssued, + orbEntry->tagCheckExit, + orbEntry->locRdEntered, + orbEntry->locRdIssued, + orbEntry->locRdExit, + orbEntry->locWrEntered, + orbEntry->locWrIssued, + orbEntry->locWrExit, + orbEntry->farRdEntered, + orbEntry->farRdIssued, + orbEntry->farRdExit); + delete orbEntry; + + orbEntry = ORB.at(copyOwPkt->getAddr()); + + polManStats.totPktRespTime += ((curTick() - orbEntry->arrivalTick)/1000); + polManStats.totPktRespTimeRd += ((curTick() - orbEntry->arrivalTick)/1000); + + // clear ORB + resumeConflictingReq(orbEntry); + + return; + } + + if (orbEntry->pol == enums::RambusTagProbOpt && + orbEntry->owPkt->isWrite()) { + // DONE + // respond for writes is already sent to the requestor. + // clear ORB + assert(orbEntry->state == waitingTCtag); + + resumeConflictingReq(orbEntry); + + return; + } + + if (orbEntry->pol == enums::RambusTagProbOpt && + orbEntry->state == farMemRead) { + + assert(orbEntry->owPkt->isRead()); + assert(!orbEntry->isHit); + + // do a read from far mem + pktFarMemRead.push_back(orbEntry->owPkt->getAddr()); + + polManStats.avgFarRdQLenEnq = pktFarMemRead.size(); + + if (!farMemReadEvent.scheduled() && !retryFarMemRead) { + schedule(farMemReadEvent, curTick()); + } + return; + + } + + if (orbEntry->pol == enums::RambusTagProbOpt && + orbEntry->state == locMemWrite) { + + assert(orbEntry->owPkt->isRead()); + assert(!orbEntry->isHit); + + pktLocMemWrite.push_back(orbEntry->owPkt->getAddr()); + + polManStats.avgLocWrQLenEnq = pktLocMemWrite.size(); + + + if (!locMemWriteEvent.scheduled() && !retryLocMemWrite) { + schedule(locMemWriteEvent, curTick()); + } + return; + + } + + if (orbEntry->pol == enums::RambusTagProbOpt && + // orbEntry->owPkt->isRead() && + // !orbEntry->isHit && + orbEntry->state == waitingLocMemWriteResp) { + // DONE + // clear ORB + assert(orbEntry->owPkt->isRead()); + assert(!orbEntry->isHit); + resumeConflictingReq(orbEntry); + + return; + } +} + +void +PolicyManager::handleRequestorPkt(PacketPtr pkt) +{ + Addr tag = returnTagDC(pkt->getAddr(), pkt->getSize()); + Addr index = returnIndexDC(pkt->getAddr(), pkt->getSize()); + Addr way = findMatchingWay(index, tag); + + if (way == noMatchingWay) { // MISSED! Candidate = Either there's an empty way to fill in or a victim will be selected. + way = getCandidateWay(index); + } + + assert(way < assoc); + + reqBufferEntry* orbEntry = new reqBufferEntry( + true, curTick(), + tag, index, way, + pkt, + locMemPolicy, start, + false, false, false, + false, false, false, + -1, false, + MaxTick, MaxTick, MaxTick, + MaxTick, MaxTick, MaxTick, + MaxTick, MaxTick, MaxTick, + MaxTick, MaxTick, MaxTick + ); + + ORB.emplace(pkt->getAddr(), orbEntry); + + DPRINTF(PolicyManager, "handleRequestorPkt added to ORB: adr= %d, index= %d, tag= %d, %s\n", orbEntry->owPkt->getAddr(), orbEntry->indexDC, orbEntry->tagDC, orbEntry->owPkt->cmdString()); + + polManStats.avgORBLen = ORB.size(); + polManStats.avgTagCheckQLenStrt = countTagCheckInORB(); + polManStats.avgLocRdQLenStrt = countLocRdInORB(); + polManStats.avgFarRdQLenStrt = countFarRdInORB(); + polManStats.avgLocWrQLenStrt = countLocWrInORB(); + polManStats.avgFarWrQLenStrt = countFarWr(); + + Addr addr = pkt->getAddr(); + unsigned burst_size = locBurstSize; + unsigned size = std::min((addr | (burst_size - 1)) + 1, + addr + pkt->getSize()) - addr; + + if(pkt->isRead()) { + polManStats.bytesReadSys += size; + polManStats.readPktSize[ceilLog2(size)]++; + polManStats.readReqs++; + } else { + polManStats.bytesWrittenSys += size; + polManStats.writePktSize[ceilLog2(size)]++; + polManStats.writeReqs++; + } + + if (pkt->isWrite()) { + + PacketPtr copyOwPkt = new Packet(orbEntry->owPkt, + false, + orbEntry->owPkt->isRead()); + + accessAndRespond(orbEntry->owPkt, + frontendLatency + backendLatency); + + ORB.at(copyOwPkt->getAddr()) = new reqBufferEntry( + orbEntry->validEntry, + orbEntry->arrivalTick, + orbEntry->tagDC, + orbEntry->indexDC, + orbEntry->wayNum, + copyOwPkt, + orbEntry->pol, + orbEntry->state, + orbEntry->issued, + orbEntry->isHit, + orbEntry->conflict, + orbEntry->prevDirty, + orbEntry->rcvdLocRdResp, + orbEntry->rcvdFarRdResp, + orbEntry->dirtyLineAddr, + orbEntry->handleDirtyLine, + orbEntry->tagCheckEntered, + orbEntry->tagCheckIssued, + orbEntry->tagCheckExit, + orbEntry->locRdEntered, + orbEntry->locRdIssued, + orbEntry->locRdExit, + orbEntry->locWrEntered, + orbEntry->locWrIssued, + orbEntry->locWrExit, + orbEntry->farRdEntered, + orbEntry->farRdIssued, + orbEntry->farRdExit); + delete orbEntry; + + orbEntry = ORB.at(copyOwPkt->getAddr()); + } + + checkHitOrMiss(orbEntry); + if (checkDirty(orbEntry->indexDC, orbEntry->wayNum) && !orbEntry->isHit) { + if (extreme && tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->farMemAddr == -1) { + // extreme cases are faked. So, this address for cold misses are -1, so we fake it to a random address like 1024. + orbEntry->dirtyLineAddr = orbEntry->owPkt->getAddr() == 0 ? 64 : (orbEntry->owPkt->getAddr()-64); + } else { + orbEntry->dirtyLineAddr = tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->farMemAddr; + + } + orbEntry->handleDirtyLine = true; + } + + if (extreme) { + orbEntry->prevDirty = alwaysDirty; + } else { + orbEntry->prevDirty = tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->dirtyLine; + } + + // Updating Tag & Metadata + tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->tagDC = orbEntry->tagDC; + tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->indexDC = orbEntry->indexDC; + tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->validLine = true; + replacementPolicy->touch(tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->replacementData, pkt); + + if (orbEntry->owPkt->isRead()) { + if (orbEntry->isHit) { + tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->dirtyLine = + tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->dirtyLine; + } else { + tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->dirtyLine = false; + } + } else { // write + tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->dirtyLine = true; + tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->farMemAddr = + orbEntry->owPkt->getAddr(); + } + + // tagMetadataStore.at(orbEntry->indexDC).farMemAddr = + // orbEntry->owPkt->getAddr(); + + DPRINTF(PolicyManager, "ORB+: adr= %d, index= %d, tag= %d, cmd= %s, isHit= %d, wasDirty= %d, dirtyAddr= %d\n", orbEntry->owPkt->getAddr(), orbEntry->indexDC, orbEntry->tagDC, orbEntry->owPkt->cmdString(), orbEntry->isHit, orbEntry->prevDirty, orbEntry->dirtyLineAddr); +} + +bool +PolicyManager::checkConflictInORB(PacketPtr pkt) +{ + Addr indexDC = returnIndexDC(pkt->getAddr(), pkt->getSize()); + //Addr tagDC = returnTagDC(pkt->getAddr(), pkt->getSize()); + + std::vector sameIndex; + + for (auto e = ORB.begin(); e != ORB.end(); ++e) { + if (e->second->validEntry && indexDC == e->second->indexDC /*&& tagDC != e->second->tagDC*/) { + sameIndex.push_back(e->first); + } + } + if (sameIndex.size() == assoc) { + for (int i=0; iconflict = true; + } + return true; + } + return false; +} + +void +PolicyManager::checkHitOrMiss(reqBufferEntry* orbEntry) +{ + // look up the tagMetadataStore data structure to + // check if it's hit or miss + + bool currValid = tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->validLine; + bool currDirty = tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->dirtyLine; + + if (extreme) { + orbEntry->isHit = alwaysHit; + currValid = true; + currDirty = alwaysDirty; + } else { + orbEntry->isHit = currValid && (orbEntry->tagDC == tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->tagDC); + } + + if (orbEntry->isHit) { + + polManStats.numTotHits++; + + if (orbEntry->owPkt->isRead()) { + polManStats.numRdHit++; + if (currDirty) { + polManStats.numRdHitDirty++; + } else { + polManStats.numRdHitClean++; + } + } else { + polManStats.numWrHit++; + if (currDirty) { + polManStats.numWrHitDirty++; + } else { + polManStats.numWrHitClean++; + } + } + + } else { + + polManStats.numTotMisses++; + + unsigned invalidBlocks = 0; + for (int i = 0; i < assoc; i++) { + if (!tagMetadataStore.at(orbEntry->indexDC).at(i)->validLine) { + invalidBlocks++; + } + } + + if (invalidBlocks == assoc) { + polManStats.numColdMissesSet++; + } + + if (currValid) { + polManStats.numHotMisses++; + } else { + polManStats.numColdMisses++; + numColdMisses++; + } + + if (orbEntry->owPkt->isRead()) { + if (currDirty && currValid) { + polManStats.numRdMissDirty++; + } else { + polManStats.numRdMissClean++; + } + } else { + if (currDirty && currValid) { + polManStats.numWrMissDirty++; + } else { + polManStats.numWrMissClean++; + } + + } + } + + if ((numColdMisses >= (unsigned)(infoCacheWarmupRatio * dramCacheSize/blockSize)) && !resetStatsWarmup) { + inform("DRAM cache warm up percentage : %f, @ %d .. \n", infoCacheWarmupRatio*100.0, curTick()); + infoCacheWarmupRatio = infoCacheWarmupRatio + 0.05; + } + + if ((numColdMisses >= (unsigned)(cacheWarmupRatio * dramCacheSize/blockSize)) && !resetStatsWarmup) { + inform("DRAM cache fully warmed up @ %d .. \n", curTick()); + exitSimLoop("cacheIsWarmedup",0); + resetStatsWarmup = true; + } +} + +bool +PolicyManager::checkDirty(Addr index, int way) +{ + // Addr index = returnIndexDC(addr, blockSize); + // Addr tag = returnTagDC(addr, blockSize); + assert(way >= 0); + if (extreme) { + return alwaysDirty; + } else { + return (tagMetadataStore.at(index).at(way)->validLine && + tagMetadataStore.at(index).at(way)->dirtyLine); + } +} + +void +PolicyManager::accessAndRespond(PacketPtr pkt, Tick static_latency) +{ + DPRINTF(PolicyManager, "Responding to Address %d: %s\n", pkt->getAddr(), pkt->cmdString()); + + bool needsResponse = pkt->needsResponse(); + // do the actual memory access which also turns the packet into a + // response + panic_if(!getAddrRange().contains(pkt->getAddr()), + "Can't handle address range for packet %s\n", pkt->print()); + access(pkt); + + // turn packet around to go back to requestor if response expected + assert(needsResponse); + //if (needsResponse) { + // access already turned the packet into a response + assert(pkt->isResponse()); + // response_time consumes the static latency and is charged also + // with headerDelay that takes into account the delay provided by + // the xbar and also the payloadDelay that takes into account the + // number of data beats. + Tick response_time = curTick() + static_latency + pkt->headerDelay + + pkt->payloadDelay; + // Here we reset the timing of the packet before sending it out. + pkt->headerDelay = pkt->payloadDelay = 0; + + // queue the packet in the response queue to be sent out after + // the static latency has passed + port.schedTimingResp(pkt, response_time); + //} + // else { + // // @todo the packet is going to be deleted, and the MemPacket + // // is still having a pointer to it + // pendingDelete.reset(pkt); + // } + + DPRINTF(PolicyManager, "Done\n"); + + return; +} + +PacketPtr +PolicyManager::getPacket(Addr addr, unsigned size, const MemCmd& cmd, + Request::FlagsType flags) +{ + // Create new request + RequestPtr req = std::make_shared(addr, size, flags, + 0); + // Dummy PC to have PC-based prefetchers latch on; get entropy into higher + // bits + req->setPC(((Addr)0) << 2); + + // Embed it in a packet + PacketPtr pkt = new Packet(req, cmd); + + uint8_t* pkt_data = new uint8_t[req->getSize()]; + + pkt->dataDynamic(pkt_data); + + if (cmd.isWrite()) { + std::fill_n(pkt_data, req->getSize(), (uint8_t)0); + } + + return pkt; +} + +void +PolicyManager::sendRespondToRequestor(PacketPtr pkt, Tick static_latency) +{ + PacketPtr copyOwPkt = new Packet(pkt, + false, + pkt->isRead()); + copyOwPkt->makeResponse(); + + Tick response_time = curTick() + static_latency + copyOwPkt->headerDelay; + response_time += copyOwPkt->payloadDelay; + // Here we reset the timing of the packet before sending it out. + copyOwPkt->headerDelay = copyOwPkt->payloadDelay = 0; + + // queue the packet in the response queue to be sent out after + // the static latency has passed + port.schedTimingResp(copyOwPkt, response_time); + +} + +bool +PolicyManager::resumeConflictingReq(reqBufferEntry* orbEntry) +{ + DPRINTF(PolicyManager, "resumeConflictingReq: %d: %d \n", curTick(), orbEntry->owPkt->getAddr()); + + bool conflictFound = false; + + if (orbEntry->owPkt->isWrite()) { + isInWriteQueue.erase(orbEntry->owPkt->getAddr()); + } + + logStatsPolMan(orbEntry); + + for (auto e = CRB.begin(); e != CRB.end(); ++e) { + + auto entry = *e; + + if (returnIndexDC(entry.second->getAddr(), entry.second->getSize()) + == orbEntry->indexDC) { + + DPRINTF(PolicyManager, "conf found: %d\n", entry.second->getAddr()); + + conflictFound = true; + + Addr confAddr = entry.second->getAddr(); + + ORB.erase(orbEntry->owPkt->getAddr()); + + delete orbEntry->owPkt; + + delete orbEntry; + + handleRequestorPkt(entry.second); + + ORB.at(confAddr)->arrivalTick = entry.first; + + CRB.erase(e); + + checkConflictInCRB(ORB.at(confAddr)); + + setNextState(ORB.at(confAddr)); + + handleNextState(ORB.at(confAddr)); + + break; + } + + } + + if (!conflictFound) { + DPRINTF(PolicyManager, "no conf for: %d\n", orbEntry->owPkt->getAddr()); + + ORB.erase(orbEntry->owPkt->getAddr()); + + delete orbEntry->owPkt; + + delete orbEntry; + + if (retryLLC) { + DPRINTF(PolicyManager, "retryLLC: sent\n"); + retryLLC = false; + port.sendRetryReq(); + } else { + if (drainState() == DrainState::Draining && ORB.empty() && + pktFarMemWrite.empty()) { + DPRINTF(Drain, "PolicyManager done draining\n"); + signalDrainDone(); + } + } + } + + return conflictFound; +} + +void +PolicyManager::checkConflictInCRB(reqBufferEntry* orbEntry) +{ + for (auto e = CRB.begin(); e != CRB.end(); ++e) { + + auto entry = *e; + + if (returnIndexDC(entry.second->getAddr(),entry.second->getSize()) + == orbEntry->indexDC) { + orbEntry->conflict = true; + break; + } + } +} + +unsigned +PolicyManager::countTagCheckInORB() +{ + unsigned count =0; + for (auto i : ORB) { + if (i.second->state == tagCheck) { + count++; + } + } + return count; +} + +unsigned +PolicyManager::countLocRdInORB() +{ + unsigned count =0; + for (auto i : ORB) { + if (i.second->state == locMemRead) { + count++; + } + } + return count; +} + +unsigned +PolicyManager::countFarRdInORB() +{ + unsigned count =0; + for (auto i : ORB) { + if (i.second->state == farMemRead) { + count++; + } + } + return count; +} + +unsigned +PolicyManager::countLocWrInORB() +{ + unsigned count =0; + for (auto i : ORB) { + if (i.second->state == locMemWrite) { + count++; + } + } + return count; +} + +unsigned +PolicyManager::countFarWr() +{ + return pktFarMemWrite.size(); +} + +AddrRangeList +PolicyManager::getAddrRanges() +{ + return farReqPort.getAddrRanges(); +} + +Addr +PolicyManager::returnIndexDC(Addr request_addr, unsigned size) +{ + int index_bits = ceilLog2(dramCacheSize/(blockSize*assoc)); + int block_bits = ceilLog2(size); + return bits(request_addr, block_bits + index_bits-1, block_bits); +} + +Addr +PolicyManager::returnTagDC(Addr request_addr, unsigned size) +{ + int index_bits = ceilLog2(dramCacheSize/(blockSize*assoc)); + int block_bits = ceilLog2(size); + return bits(request_addr, addrSize-1, (index_bits+block_bits)); +} + +int +PolicyManager::findMatchingWay(Addr index, Addr tag) +{ + for (int i = 0; i < assoc; i++) { + if (tagMetadataStore.at(index).at(i)->validLine && tagMetadataStore.at(index).at(i)->tagDC == tag) { + return i; + } + } + + return noMatchingWay; +} + +int +PolicyManager::getCandidateWay(Addr index) +{ + if (assoc == 1) { + // equal to direct mapped cache + return 0; + } else { + // first find an empty way + for (int i = 0; i < assoc; i++) { + if (!tagMetadataStore.at(index).at(i)->validLine) { + return i; + } + } + + // if no empty way is found (= all the ways are filled), pick a victim to evcuate + std::vector entries; + + for (int i = 0; i < assoc; i++) { + if (tagMetadataStore.at(index).at(i)->validLine) { + entries.push_back(tagMetadataStore.at(index).at(i)); + } + } + + ReplaceableEntry* victim = replacementPolicy->getVictim(entries); + + for (int i = 0; i < assoc; i++) { + if (entries.at(i)->tagDC == victim->tagDC) { + assert(entries.at(i)->validLine); + return i; + } + } + } + + return -1; +} + +void +PolicyManager::handleDirtyCacheLine(Addr dirtyLineAddr) +{ + DPRINTF(PolicyManager, "handleDirtyCacheLine: %d\n", dirtyLineAddr); + assert(dirtyLineAddr != -1); + + // create a new request packet + PacketPtr wbPkt = getPacket(dirtyLineAddr, + blockSize, + MemCmd::WriteReq); + + pktFarMemWrite.push_back(std::make_pair(curTick(), wbPkt)); + + polManStats.avgFarWrQLenEnq = pktFarMemWrite.size(); + + if (!farMemWriteEvent.scheduled() && !retryFarMemWrite) { + schedule(farMemWriteEvent, curTick()); + } + + polManStats.numWrBacks++; +} + +void +PolicyManager::logStatsPolMan(reqBufferEntry* orbEntry) +{ + if (locMemPolicy == enums::Rambus || locMemPolicy == enums::RambusTagProbOpt) { + assert(orbEntry->arrivalTick != MaxTick); + assert(orbEntry->tagCheckEntered != MaxTick); + assert(orbEntry->tagCheckExit != MaxTick); + + polManStats.totPktLifeTime += ((curTick() - orbEntry->arrivalTick)/1000); + polManStats.totPktORBTime += ((curTick() - orbEntry->tagCheckEntered)/1000); + polManStats.totTimeTagCheckRes += ((orbEntry->tagCheckExit - orbEntry->tagCheckEntered)/1000); + + if (orbEntry->owPkt->isRead()) { + polManStats.totPktLifeTimeRd += ((curTick() - orbEntry->arrivalTick)/1000); + polManStats.totPktORBTimeRd += ((curTick() - orbEntry->tagCheckEntered)/1000); + polManStats.totTimeTagCheckResRd += ((orbEntry->tagCheckExit - orbEntry->tagCheckEntered)/1000); + + if (orbEntry->isHit) { + polManStats.totTimeTagCheckResRdH += ((orbEntry->tagCheckExit - orbEntry->tagCheckEntered)/1000); + } else if (!orbEntry->isHit && !orbEntry->prevDirty) { + polManStats.totTimeTagCheckResRdMC += ((orbEntry->tagCheckExit - orbEntry->tagCheckEntered)/1000); + } else if (!orbEntry->isHit && orbEntry->prevDirty) { + polManStats.totTimeTagCheckResRdMD += ((orbEntry->tagCheckExit - orbEntry->tagCheckEntered)/1000); + } + + } else { + polManStats.totPktRespTime += ((curTick() - orbEntry->arrivalTick)/1000); + polManStats.totPktRespTimeWr += ((curTick() - orbEntry->arrivalTick)/1000); + polManStats.totPktLifeTimeWr += ((curTick() - orbEntry->arrivalTick)/1000); + polManStats.totPktORBTimeWr += ((curTick() - orbEntry->tagCheckEntered)/1000); + polManStats.totTimeTagCheckResWr += ((orbEntry->tagCheckExit - orbEntry->tagCheckEntered)/1000); + } + + if (orbEntry->owPkt->isRead() && orbEntry->isHit) { + assert(orbEntry->locRdExit != MaxTick); + polManStats.totTimeInLocRead += ((orbEntry->locRdExit - orbEntry->tagCheckEntered)/1000); + } + + if (orbEntry->owPkt->isRead() && !orbEntry->isHit) { + assert(orbEntry->farRdExit != MaxTick); + assert(orbEntry->farRdEntered != MaxTick); + assert(orbEntry->farRdIssued != MaxTick); + assert(orbEntry->tagCheckExit != MaxTick); + assert(orbEntry->locWrExit != MaxTick); + assert(orbEntry->locWrEntered != MaxTick); + + polManStats.totTimeInFarRead += ((orbEntry->farRdExit - orbEntry->farRdEntered)/1000); + polManStats.totTimeFarRdtoSend += ((orbEntry->farRdIssued - orbEntry->farRdEntered)/1000); + polManStats.totTimeFarRdtoRecv += ((orbEntry->farRdExit - orbEntry->farRdIssued)/1000); + polManStats.totTimeInLocWrite += ((orbEntry->locWrExit - orbEntry->locWrEntered)/1000); + } + } + else { + // MUST be updated since they are average, they should be per case + if (locMemPolicy == enums::Oracle ) { + if ((orbEntry->owPkt->isRead() && orbEntry->isHit) || + (orbEntry->owPkt->isRead() && !orbEntry->isHit && orbEntry->prevDirty) || + (!orbEntry->owPkt->isRead() && !orbEntry->isHit && orbEntry->prevDirty)) { + polManStats.totPktORBTime += ((curTick() - orbEntry->locRdEntered)/1000); + if (orbEntry->owPkt->isRead()) { + polManStats.totPktORBTimeRd += ((curTick() - orbEntry->locRdEntered)/1000); + polManStats.totTimeTagCheckResRd += ((orbEntry->locRdExit - orbEntry->locRdEntered)/1000); + } else { + polManStats.totPktORBTimeWr += ((curTick() - orbEntry->locRdEntered)/1000); + polManStats.totTimeTagCheckResWr += ((orbEntry->locRdExit - orbEntry->locRdEntered)/1000); + } + } + else if (!orbEntry->owPkt->isRead() && (orbEntry->isHit || (!orbEntry->isHit && !orbEntry->prevDirty))) { + polManStats.totPktORBTime += ((curTick() - orbEntry->locWrEntered)/1000); + polManStats.totPktORBTimeWr += ((curTick() - orbEntry->locWrEntered)/1000); + polManStats.totTimeTagCheckResWr += ((orbEntry->locRdExit - orbEntry->locRdEntered)/1000); + } + else if (orbEntry->owPkt->isRead() && !orbEntry->isHit && !orbEntry->prevDirty) { + polManStats.totPktORBTime += ((curTick() - orbEntry->farRdEntered)/1000); + polManStats.totPktORBTimeRd += ((curTick() - orbEntry->farRdEntered)/1000); + polManStats.totTimeTagCheckResRd += ((orbEntry->locRdExit - orbEntry->locRdEntered)/1000); + } + + } else { // locMemPolicy == enums::CascadeLakeNoPartWrs + // This is incorrect for locMemPolicy == enums::BearWriteOpt + polManStats.totPktORBTime += ((curTick() - orbEntry->locRdEntered)/1000); + + if (orbEntry->owPkt->isRead()) { + polManStats.totPktORBTimeRd += ((curTick() - orbEntry->locRdEntered)/1000); + polManStats.totTimeTagCheckResRd += ((orbEntry->locRdExit - orbEntry->locRdEntered)/1000); + } else { + polManStats.totPktORBTimeWr += ((curTick() - orbEntry->locRdEntered)/1000); + polManStats.totTimeTagCheckResWr += ((orbEntry->locRdExit - orbEntry->locRdEntered)/1000); + } + } + + polManStats.totPktLifeTime += ((curTick() - orbEntry->arrivalTick)/1000); + + polManStats.totTimeFarRdtoSend += ((orbEntry->farRdIssued - orbEntry->farRdEntered)/1000); + polManStats.totTimeFarRdtoRecv += ((orbEntry->farRdExit - orbEntry->farRdIssued)/1000); + polManStats.totTimeInLocRead += ((orbEntry->locRdExit - orbEntry->locRdEntered)/1000); + polManStats.totTimeInLocWrite += ((orbEntry->locWrExit - orbEntry->locWrEntered)/1000); + polManStats.totTimeInFarRead += ((orbEntry->farRdExit - orbEntry->farRdEntered)/1000); + + if (orbEntry->owPkt->isRead()) { + polManStats.totPktLifeTimeRd += ((curTick() - orbEntry->arrivalTick)/1000); + } else { + polManStats.totPktLifeTimeWr += ((curTick() - orbEntry->arrivalTick)/1000); + polManStats.totPktRespTime += ((curTick() - orbEntry->arrivalTick)/1000); + polManStats.totPktRespTimeWr += ((curTick() - orbEntry->arrivalTick)/1000); + } + + } +} + + +void +PolicyManager::ReqPortPolManager::recvReqRetry() +{ + if (this->name().find("loc_req_port") != std::string::npos) { + polMan.locMemRecvReqRetry(); + } + if (this->name().find("far_req_port") != std::string::npos) { + polMan.farMemRecvReqRetry(); + } +} + +bool +PolicyManager::ReqPortPolManager::recvTimingResp(PacketPtr pkt) +{ + // since in the constructor we are appending loc_req_port + // to the loc mem port, the name should always have the substring + // irrespective of the configuration names + if (this->name().find("loc_req_port") != std::string::npos) { + return polMan.locMemRecvTimingResp(pkt); + } else if (this->name().find("far_req_port") != std::string::npos) { + return polMan.farMemRecvTimingResp(pkt); + } else { + std::cout << "Port name error, fix it!\n"; + return false; + } +} + +PolicyManager::PolicyManagerStats::PolicyManagerStats(PolicyManager &_polMan) + : statistics::Group(&_polMan), + polMan(_polMan), + +///// + ADD_STAT(readReqs, statistics::units::Count::get(), + "Number of read requests accepted"), + ADD_STAT(writeReqs, statistics::units::Count::get(), + "Number of write requests accepted"), + + ADD_STAT(servicedByWrQ, statistics::units::Count::get(), + "Number of controller read bursts serviced by the write queue"), + ADD_STAT(servicedByFB, statistics::units::Count::get(), + "Number of controller read bursts serviced by the flush buffer"), + ADD_STAT(mergedWrBursts, statistics::units::Count::get(), + "Number of controller write bursts merged with an existing one"), + ADD_STAT(mergedWrPolManWB, statistics::units::Count::get(), + "Number of controller write bursts merged with an existing one in write back buffer"), + ADD_STAT(mergedWrLocMemFB, statistics::units::Count::get(), + "Number of controller write bursts merged with an existing one in flush buffer"), + + ADD_STAT(numRdRetry, statistics::units::Count::get(), + "Number of times read queue was full causing retry"), + ADD_STAT(numWrRetry, statistics::units::Count::get(), + "Number of times write queue was full causing retry"), + + ADD_STAT(readPktSize, statistics::units::Count::get(), + "Read request sizes (log2)"), + ADD_STAT(writePktSize, statistics::units::Count::get(), + "Write request sizes (log2)"), + + ADD_STAT(bytesReadWrQ, statistics::units::Byte::get(), + "Total number of bytes read from write queue"), + ADD_STAT(bytesReadSys, statistics::units::Byte::get(), + "Total read bytes from the system interface side"), + ADD_STAT(bytesWrittenSys, statistics::units::Byte::get(), + "Total written bytes from the system interface side"), + + ADD_STAT(avgRdBWSys, statistics::units::Rate< + statistics::units::Byte, statistics::units::Second>::get(), + "Average system read bandwidth in Byte/s"), + ADD_STAT(avgWrBWSys, statistics::units::Rate< + statistics::units::Byte, statistics::units::Second>::get(), + "Average system write bandwidth in Byte/s"), + + ADD_STAT(totGap, statistics::units::Tick::get(), + "Total gap between requests"), + ADD_STAT(avgGap, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), + "Average gap between requests"), + + ADD_STAT(avgORBLen, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average ORB length"), + ADD_STAT(avgTagCheckQLenStrt, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average local read queue length"), + ADD_STAT(avgLocRdQLenStrt, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average local read queue length"), + ADD_STAT(avgLocWrQLenStrt, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average local write queue length"), + ADD_STAT(avgFarRdQLenStrt, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average far read queue length"), + ADD_STAT(avgFarWrQLenStrt, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average far write queue length"), + + ADD_STAT(avgTagCheckQLenEnq, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average local read queue length when enqueuing"), + ADD_STAT(avgLocRdQLenEnq, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average local read queue length when enqueuing"), + ADD_STAT(avgLocWrQLenEnq, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average local write queue length when enqueuing"), + ADD_STAT(avgFarRdQLenEnq, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average far read queue length when enqueuing"), + ADD_STAT(avgFarWrQLenEnq, statistics::units::Rate< + statistics::units::Count, statistics::units::Tick>::get(), + "Average far write queue length when enqueuing"), + + ADD_STAT(numWrBacks, statistics::units::Count::get(), + "Total number of write backs from DRAM cache to main memory"), + ADD_STAT(totNumConf, statistics::units::Count::get(), + "Total number of packets conflicted on DRAM cache"), + ADD_STAT(totNumORBFull, statistics::units::Count::get(), + "Total number of packets ORB full"), + ADD_STAT(totNumCRBFull, statistics::units::Count::get(), + "Total number of packets conflicted yet couldn't " + "enter confBuffer"), + + ADD_STAT(maxNumConf, statistics::units::Count::get(), + "Maximum number of packets conflicted on DRAM cache"), + + ADD_STAT(sentTagCheckPort, statistics::units::Count::get(), + "stat"), + ADD_STAT(failedTagCheckPort, statistics::units::Count::get(), + "stat"), + ADD_STAT(sentLocRdPort, statistics::units::Count::get(), + "stat"), + ADD_STAT(sentLocWrPort, statistics::units::Count::get(), + "stat"), + ADD_STAT(failedLocRdPort, statistics::units::Count::get(), + "stat"), + ADD_STAT(failedLocWrPort, statistics::units::Count::get(), + "stat"), + // ADD_STAT(recvdRdPort, statistics::units::Count::get(), + // "stat"), + ADD_STAT(sentFarRdPort, statistics::units::Count::get(), + "stat"), + ADD_STAT(sentFarWrPort, statistics::units::Count::get(), + "stat"), + ADD_STAT(failedFarRdPort, statistics::units::Count::get(), + "stat"), + ADD_STAT(failedFarWrPort, statistics::units::Count::get(), + "stat"), + + ADD_STAT(totPktLifeTime, statistics::units::Tick::get(), "stat"), + ADD_STAT(totPktLifeTimeRd, statistics::units::Tick::get(), "stat"), + ADD_STAT(totPktLifeTimeWr, statistics::units::Tick::get(), "stat"), + ADD_STAT(totPktORBTime, statistics::units::Tick::get(), "stat"), + ADD_STAT(totPktORBTimeRd, statistics::units::Tick::get(), "stat"), + ADD_STAT(totPktORBTimeWr, statistics::units::Tick::get(), "stat"), + ADD_STAT(totPktRespTime, statistics::units::Tick::get(), "stat"), + ADD_STAT(totPktRespTimeRd, statistics::units::Tick::get(), "stat"), + ADD_STAT(totPktRespTimeWr, statistics::units::Tick::get(), "stat"), + ADD_STAT(totTimeTagCheckRes, statistics::units::Tick::get(), "stat"), + ADD_STAT(totTimeTagCheckResRd, statistics::units::Tick::get(), "stat"), + ADD_STAT(totTimeTagCheckResWr, statistics::units::Tick::get(), "stat"), + ADD_STAT(totTimeTagCheckResRdH, statistics::units::Tick::get(), "stat"), + ADD_STAT(totTimeTagCheckResRdMC, statistics::units::Tick::get(), "stat"), + ADD_STAT(totTimeTagCheckResRdMD, statistics::units::Tick::get(), "stat"), + ADD_STAT(totTimeInLocRead, statistics::units::Tick::get(), "stat"), + ADD_STAT(totTimeInLocWrite, statistics::units::Tick::get(), "stat"), + ADD_STAT(totTimeInFarRead, statistics::units::Tick::get(), "stat"), + ADD_STAT(totTimeFarRdtoSend, statistics::units::Tick::get(), "stat"), + ADD_STAT(totTimeFarRdtoRecv, statistics::units::Tick::get(), "stat"), + ADD_STAT(totTimeFarWrtoSend, statistics::units::Tick::get(), "stat"), + + ADD_STAT(avgPktLifeTime, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgPktLifeTimeRd, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgPktLifeTimeWr, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgPktORBTime, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgPktORBTimeRd, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgPktORBTimeWr, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgPktRespTime, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgPktRespTimeRd, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgPktRespTimeWr, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgTimeTagCheckRes, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgTimeTagCheckResRd, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgTimeTagCheckResWr, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgTimeTagCheckResRdH, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgTimeTagCheckResRdMC, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgTimeTagCheckResRdMD, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgTimeInLocRead, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgTimeInLocWrite, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgTimeInFarRead, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgTimeFarRdtoSend, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgTimeFarRdtoRecv, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + ADD_STAT(avgTimeFarWrtoSend, statistics::units::Rate< + statistics::units::Tick, statistics::units::Count>::get(), "stat"), + + ADD_STAT(numTotHits, statistics::units::Count::get(), "stat"), + ADD_STAT(numTotMisses, statistics::units::Count::get(), "stat"), + ADD_STAT(numColdMisses, statistics::units::Count::get(), "stat"), + ADD_STAT(numColdMissesSet, statistics::units::Count::get(), "stat"), + ADD_STAT(numHotMisses, statistics::units::Count::get(), "stat"), + ADD_STAT(numRdMissClean, statistics::units::Count::get(), "stat"), + ADD_STAT(numRdMissDirty, statistics::units::Count::get(), "stat"), + ADD_STAT(numRdHit, statistics::units::Count::get(), "stat"), + ADD_STAT(numWrMissClean, statistics::units::Count::get(), "stat"), + ADD_STAT(numWrMissDirty, statistics::units::Count::get(), "stat"), + ADD_STAT(numWrHit, statistics::units::Count::get(), "stat"), + ADD_STAT(numRdHitDirty, statistics::units::Count::get(), "stat"), + ADD_STAT(numRdHitClean, statistics::units::Count::get(), "stat"), + ADD_STAT(numWrHitDirty, statistics::units::Count::get(), "stat"), + ADD_STAT(numWrHitClean, statistics::units::Count::get(), "stat"), + + ADD_STAT(missRatio, statistics::units::Rate< + statistics::units::Count, statistics::units::Count>::get(), "stat"), + ADD_STAT(dirtyRatio, statistics::units::Rate< + statistics::units::Count, statistics::units::Count>::get(), "stat") + +{ +} + +void +PolicyManager::PolicyManagerStats::regStats() +{ + using namespace statistics; + + avgORBLen.precision(4); + avgLocRdQLenStrt.precision(2); + avgLocWrQLenStrt.precision(2); + avgFarRdQLenStrt.precision(2); + avgFarWrQLenStrt.precision(2); + + avgLocRdQLenEnq.precision(2); + avgLocWrQLenEnq.precision(2); + avgFarRdQLenEnq.precision(2); + avgFarWrQLenEnq.precision(2); + + avgPktLifeTime.precision(2); + avgPktLifeTimeRd.precision(2); + avgPktLifeTimeWr.precision(2); + avgPktORBTime.precision(2); + avgPktORBTimeRd.precision(2); + avgPktORBTimeWr.precision(2); + avgPktRespTime.precision(2); + avgPktRespTimeRd.precision(2); + avgPktRespTimeWr.precision(2); + avgTimeTagCheckRes.precision(2); + avgTimeTagCheckResRd.precision(2); + avgTimeTagCheckResWr.precision(2); + avgTimeTagCheckResRdH.precision(2); + avgTimeTagCheckResRdMC.precision(2); + avgTimeTagCheckResRdMD.precision(2); + avgTimeInLocRead.precision(2); + avgTimeInLocWrite.precision(2); + avgTimeInFarRead.precision(2); + avgTimeFarRdtoSend.precision(2); + avgTimeFarRdtoRecv.precision(2); + avgTimeFarWrtoSend.precision(2); + + readPktSize.init(ceilLog2(polMan.blockSize) + 1); + writePktSize.init(ceilLog2(polMan.blockSize) + 1); + + avgRdBWSys.precision(8); + avgWrBWSys.precision(8); + avgGap.precision(2); + + missRatio.precision(2); + dirtyRatio.precision(2); + + // Formula stats + avgRdBWSys = (bytesReadSys) / simSeconds; + avgWrBWSys = (bytesWrittenSys) / simSeconds; + + avgPktLifeTime = (totPktLifeTime) / (readReqs + writeReqs); + avgPktLifeTimeRd = (totPktLifeTimeRd) / (readReqs); + avgPktLifeTimeWr = (totPktLifeTimeWr) / (writeReqs); + + avgPktORBTime = (totPktORBTime) / (readReqs + writeReqs); + avgPktORBTimeRd = (totPktORBTimeRd) / (readReqs); + avgPktORBTimeWr = (totPktORBTimeWr) / (writeReqs); + + avgPktRespTime = (totPktRespTime) / (readReqs + writeReqs); + avgPktRespTimeRd = (totPktRespTimeRd) / (readReqs); + avgPktRespTimeWr = (totPktRespTimeWr) / (writeReqs); + + if (polMan.locMemPolicy == enums::Rambus || polMan.locMemPolicy == enums::RambusTagProbOpt) { + avgTimeTagCheckRes = (totTimeTagCheckRes) / (readReqs + writeReqs); + avgTimeInLocRead = (totTimeInLocRead) / (numRdHit); + } else { + avgTimeTagCheckRes = (totTimeInLocRead) / (readReqs + writeReqs); + avgTimeInLocRead = (totTimeInLocRead) / (readReqs + writeReqs); + } + + avgTimeTagCheckResRd = (totTimeTagCheckResRd) / (readReqs); + avgTimeTagCheckResWr = (totTimeTagCheckResWr) / (writeReqs); + + avgTimeTagCheckResRdH = (totTimeTagCheckResRdH) / (numRdHit); + avgTimeTagCheckResRdMC = (totTimeTagCheckResRdMC) / (numRdMissClean); + avgTimeTagCheckResRdMD = (totTimeTagCheckResRdMD) / (numRdMissDirty); + + + avgTimeInLocWrite = (totTimeInLocWrite) / (numRdMissClean + numRdMissDirty + writeReqs); + avgTimeInFarRead = (totTimeInFarRead) / (numRdMissClean + numRdMissDirty); + + avgTimeFarRdtoSend = (totTimeFarRdtoSend) / (sentFarRdPort); + avgTimeFarRdtoRecv = (totTimeFarRdtoRecv) / (sentFarRdPort); + avgTimeFarWrtoSend = (totTimeFarWrtoSend) / (sentFarWrPort); + + missRatio = (numTotMisses / (readReqs + writeReqs)) * 100; + dirtyRatio = ((numRdMissDirty + numWrMissDirty) / (readReqs + writeReqs)) * 100; + + avgGap = totGap / (readReqs + writeReqs); + +} + +Port & +PolicyManager::getPort(const std::string &if_name, PortID idx) +{ + panic_if(idx != InvalidPortID, "This object doesn't support vector ports"); + + // This is the name from the Python SimObject declaration (SimpleMemobj.py) + if (if_name == "port") { + return port; + } else if (if_name == "loc_req_port") { + return locReqPort; + } else if (if_name == "far_req_port") { + return farReqPort; + } else { + // pass it along to our super class + panic("PORT NAME ERROR !!!!\n"); + } +} + +DrainState +PolicyManager::drain() +{ + if (!ORB.empty() || !pktFarMemWrite.empty()) { + DPRINTF(Drain, "DRAM cache is not drained! Have %d in ORB and %d in " + "writeback queue.\n", ORB.size(), pktFarMemWrite.size()); + return DrainState::Draining; + } else { + return DrainState::Drained; + } +} + +void +PolicyManager::serialize(CheckpointOut &cp) const +{ + ScopedCheckpointSection sec(cp, "tagMetadataStore"); + paramOut(cp, "numEntries", tagMetadataStore.size()*assoc); + int count = 0; + for (auto const &set : tagMetadataStore) { + for (auto const way : set) { + ScopedCheckpointSection sec_entry(cp,csprintf("Entry%d", count++)); + if (way->validLine) { + paramOut(cp, "validLine", way->validLine); + paramOut(cp, "tagDC", way->tagDC); + paramOut(cp, "indexDC", way->indexDC); + paramOut(cp, "dirtyLine", way->dirtyLine); + paramOut(cp, "farMemAddr", way->farMemAddr); + } else { + paramOut(cp, "validLine", way->validLine); + } + } + } +} + +void +PolicyManager::unserialize(CheckpointIn &cp) +{ + ScopedCheckpointSection sec(cp, "tagMetadataStore"); + int num_entries = 0; + unsigned countValid = 0; + unsigned countInvalid = 0; + unsigned numOfSets = dramCacheSize / (blockSize * assoc); + paramIn(cp, "numEntries", num_entries); + warn_if(num_entries > tagMetadataStore.size()*assoc, "Unserializing larger tag " + "store into a smaller tag store. Stopping when index doesn't fit"); + warn_if(num_entries < tagMetadataStore.size()*assoc, "Unserializing smaller " + "tag store into a larger tag store. Not fully warmed up."); + for (int i = 0; i < num_entries; i++) { + ScopedCheckpointSection sec_entry(cp,csprintf("Entry%d", i)); + bool valid = false; + paramIn(cp, "validLine", valid); + if (!valid){ + countInvalid++; + } + if (valid) { + countValid++; + Addr tag = 0; + Addr index = 0; + bool dirty = false; + Addr far_addr = 0; + paramIn(cp, "tagDC", tag); + paramIn(cp, "indexDC", index); + paramIn(cp, "dirtyLine", dirty); + paramIn(cp, "farMemAddr", far_addr); + Addr newIndex = index % numOfSets; + if (newIndex < tagMetadataStore.size()) { + // Only insert if this entry fits into the current store. + // tagMetadataStore.at(newIndex).at(i / numOfSets)->tagDC = tag; + // tagMetadataStore.at(newIndex).at(i / numOfSets)->indexDC = newIndex; + // tagMetadataStore.at(newIndex).at(i / numOfSets)->validLine = valid; + // tagMetadataStore.at(newIndex).at(i / numOfSets)->dirtyLine = dirty; + // tagMetadataStore.at(newIndex).at(i / numOfSets)->farMemAddr = far_addr; + int way = findEmptyWay(newIndex); + tagMetadataStore.at(newIndex).at(way)->tagDC = returnTagDC(far_addr, blockSize); // = tag; + tagMetadataStore.at(newIndex).at(way)->indexDC = newIndex; + tagMetadataStore.at(newIndex).at(way)->validLine = valid; + tagMetadataStore.at(newIndex).at(way)->dirtyLine = dirty; + tagMetadataStore.at(newIndex).at(way)->farMemAddr = far_addr; + } + } + } +} + +int +PolicyManager::findEmptyWay(Addr index) +{ + for (int i=0; ivalidLine) { + return i; + } + } + + return -1; +} + +bool +PolicyManager::recvReadFlushBuffer(Addr addr) +{ + if (pktFarMemWrite.size() < (orbMaxSize / 2)) { + handleDirtyCacheLine(addr); + return true; + } + return false; +} + +} // namespace memory +} // namespace gem5 diff --git a/src/mem/policy_manager.hh b/src/mem/policy_manager.hh new file mode 100644 index 0000000000..c9b6979251 --- /dev/null +++ b/src/mem/policy_manager.hh @@ -0,0 +1,544 @@ +/** + * @file + * DCacheCtrl declaration + */ + +#ifndef __POLICY_MANAGER_HH__ +#define __POLICY_MANAGER_HH__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "base/callback.hh" +#include "base/compiler.hh" +#include "base/logging.hh" +#include "base/statistics.hh" +#include "base/trace.hh" +#include "base/types.hh" +#include "enums/Policy.hh" +#include "enums/ReplPolicySetAssoc.hh" +#include "mem/cache/replacement_policies/base.hh" +#include "mem/cache/replacement_policies/replaceable_entry.hh" +#include "mem/mem_ctrl.hh" +#include "mem/mem_interface.hh" +#include "mem/packet.hh" +#include "mem/qport.hh" +#include "mem/request.hh" +#include "params/PolicyManager.hh" +#include "sim/clocked_object.hh" +#include "sim/cur_tick.hh" +#include "sim/eventq.hh" +#include "sim/system.hh" + +#define noMatchingWay 1000000 + +namespace gem5 +{ + +namespace memory +{ + +// class DRAMInterface; + +class PolicyManager : public AbstractMemory +{ + protected: + + class RespPortPolManager : public QueuedResponsePort + { + private: + + RespPacketQueue queue; + PolicyManager& polMan; + + public: + + RespPortPolManager(const std::string& name, PolicyManager& _polMan) + : QueuedResponsePort(name, queue), + queue(_polMan, *this, true), + polMan(_polMan) + { } + + protected: + + Tick recvAtomic(PacketPtr pkt) override + {return polMan.recvAtomic(pkt);} + + Tick recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &backdoor) override + {return polMan.recvAtomicBackdoor(pkt, backdoor);} + + void recvFunctional(PacketPtr pkt) override + {polMan.recvFunctional(pkt);} + + bool recvTimingReq(PacketPtr pkt) override + {return polMan.recvTimingReq(pkt);} + + AddrRangeList getAddrRanges() const override + {return polMan.getAddrRanges();} + + }; + + class ReqPortPolManager : public RequestPort + { + public: + + ReqPortPolManager(const std::string& name, PolicyManager& _polMan) + : RequestPort(name, &_polMan), polMan(_polMan) + { } + + protected: + + void recvReqRetry(); + + bool recvTimingResp(PacketPtr pkt); + + private: + + PolicyManager& polMan; + + }; + + RespPortPolManager port; + ReqPortPolManager locReqPort; + ReqPortPolManager farReqPort; + + unsigned locBurstSize; + unsigned farBurstSize; + + // enums::Policy locMemPolicy; + + /** + * The following are basic design parameters of the unified + * DRAM cache controller, and are initialized based on parameter values. + * The rowsPerBank is determined based on the capacity, number of + * ranks and banks, the burst size, and the row buffer size. + */ + + // MemInterface* locMem; + AbstractMemory* locMem; + + /** Replacement policy */ + replacement_policy::Base* replacementPolicy; + + unsigned long long dramCacheSize; + unsigned blockSize; + unsigned assoc; + unsigned addrSize; + unsigned orbMaxSize; + unsigned orbSize; + unsigned crbMaxSize; + unsigned crbSize; + bool extreme; + bool alwaysHit; + bool alwaysDirty; + bool bypassDcache; + + /** + * Pipeline latency of the controller frontend. The frontend + * contribution is added to writes (that complete when they are in + * the write buffer) and reads that are serviced the write buffer. + */ + const Tick frontendLatency; + + /** + * Pipeline latency of the backend and PHY. Along with the + * frontend contribution, this latency is added to reads serviced + * by the memory. + */ + const Tick backendLatency; + + unsigned numColdMisses; + float cacheWarmupRatio; + // used to print an update + // whenever cache is warmed up + // by an additional 5% (hard-coded value) + float infoCacheWarmupRatio; + bool resetStatsWarmup; + + Tick prevArrival; + + std::unordered_set isInWriteQueue; + + /** A storage to keep the tag and metadata for the + * DRAM Cache entries. + */ + std::vector> tagMetadataStore; + + /** Different states a packet can transition from one + * to the other while it's process in the DRAM Cache Controller. + */ + enum reqState + { + start, + tagCheck, waitingTCtag, //WaitingTCdata, + locMemRead, waitingLocMemReadResp, locRdRespReady, + locMemWrite, waitingLocMemWriteResp, + farMemRead, waitingFarMemReadResp, + farMemWrite, waitingFarMemWriteResp + }; + + /** + * A class for the entries of the + * outstanding request buffer (ORB). + */ + class reqBufferEntry + { + public: + + bool validEntry; + Tick arrivalTick; + + // DRAM cache related metadata + Addr tagDC; + Addr indexDC; + int wayNum; + + // pointer to the outside world (ow) packet received from llc + const PacketPtr owPkt; + + enums::Policy pol; + reqState state; + + bool issued; + bool isHit; + bool conflict; + bool prevDirty; + // rcvdRdResp is only used for read misses, + // since the data response from a tag check + // may be received too late + // (after rd from far mem & write to loc). + // Note: writes responds are very quick, + // just an ack with a frontend latency only. + bool rcvdLocRdResp; + bool rcvdFarRdResp; + Addr dirtyLineAddr; + bool handleDirtyLine; + + + // recording the tick when the req transitions into a new stats. + // The subtract between each two consecutive states entrance ticks, + // is the number of ticks the req spent in the proceeded state. + // The subtract between entrance and issuance ticks for each state, + // is the number of ticks for waiting time in that state. + Tick tagCheckEntered; + Tick tagCheckIssued; + Tick tagCheckExit; + Tick locRdEntered; + Tick locRdIssued; + Tick locRdExit; + Tick locWrEntered; + Tick locWrIssued; + Tick locWrExit; + Tick farRdEntered; + Tick farRdIssued; + Tick farRdExit; + + reqBufferEntry( + bool _validEntry, Tick _arrivalTick, + Addr _tagDC, Addr _indexDC, int _wayNum, + PacketPtr _owPkt, + enums::Policy _pol, reqState _state, + bool _issued, bool _isHit, bool _conflict, + bool _prevDirty, bool _rcvdLocRdResp, bool _rcvdFarRdResp, + Addr _dirtyLineAddr, bool _handleDirtyLine, + Tick _tagCheckEntered, Tick _tagCheckIssued, Tick _tagCheckExit, + Tick _locRdEntered, Tick _locRdIssued, Tick _locRdExit, + Tick _locWrEntered, Tick _locWrIssued, Tick _locWrExit, + Tick _farRdEntered, Tick _farRdIssued, Tick _farRdExit) + : + validEntry(_validEntry), arrivalTick(_arrivalTick), + tagDC(_tagDC), indexDC(_indexDC), wayNum(_wayNum), + owPkt( _owPkt), + pol(_pol), state(_state), + issued(_issued), isHit(_isHit), conflict(_conflict), + prevDirty(_prevDirty), rcvdLocRdResp(_rcvdLocRdResp), rcvdFarRdResp(_rcvdFarRdResp), + dirtyLineAddr(_dirtyLineAddr), handleDirtyLine(_handleDirtyLine), + tagCheckEntered(_tagCheckEntered), tagCheckIssued(_tagCheckIssued), tagCheckExit(_tagCheckExit), + locRdEntered(_locRdEntered), locRdIssued(_locRdIssued), locRdExit(_locRdExit), + locWrEntered(_locWrEntered), locWrIssued(_locWrIssued), locWrExit(_locWrExit), + farRdEntered(_farRdEntered), farRdIssued(_farRdIssued), farRdExit(_farRdExit) + { } + }; + + /** + * This is the outstanding request buffer (ORB) data + * structure, the main DS within the DRAM Cache + * Controller. The key is the address, for each key + * the map returns a reqBufferEntry which maintains + * the entire info related to that address while it's + * been processed in the DRAM Cache controller. + */ + std::map ORB; + + typedef std::pair timeReqPair; + /** + * This is the second important data structure + * within the DRAM cache controller which holds + * received packets that had conflict with some + * other address(s) in the DRAM Cache that they + * are still under process in the controller. + * Once thoes addresses are finished processing, + * Conflicting Requets Buffre (CRB) is consulted + * to see if any packet can be moved into the + * outstanding request buffer and start being + * processed in the DRAM cache controller. + */ + std::vector CRB; + + /** + * This is a unified retry flag for both reads and writes. + * It helps remember if we have to retry a request when available. + */ + bool retryLLC; + bool retryLLCFarMemWr; + bool retryTagCheck; + bool retryLocMemRead; + bool retryFarMemRead; + bool retryLocMemWrite; + bool retryFarMemWrite; + + /** + * A queue for evicted dirty lines of DRAM cache, + * to be written back to the backing memory. + * These packets are not maintained in the ORB. + */ + std::deque pktFarMemWrite; + + // Maintenance Queues + std::deque pktTagCheck; // Used only for Rambus policy + std::deque pktLocMemRead; + std::deque pktLocMemWrite; + std::deque pktFarMemRead; + + // Maintenance variables + unsigned maxConf; + + AddrRangeList getAddrRanges(); + + // events + + // Used only for Rambus policy + void processTagCheckEvent(); + EventFunctionWrapper tagCheckEvent; + + void processLocMemReadEvent(); + EventFunctionWrapper locMemReadEvent; + + void processLocMemWriteEvent(); + EventFunctionWrapper locMemWriteEvent; + + void processFarMemReadEvent(); + EventFunctionWrapper farMemReadEvent; + + void processFarMemWriteEvent(); + EventFunctionWrapper farMemWriteEvent; + + // management functions + void setNextState(reqBufferEntry* orbEntry); + void handleNextState(reqBufferEntry* orbEntry); + void sendRespondToRequestor(PacketPtr pkt, Tick static_latency); + void printQSizes() {} + void handleRequestorPkt(PacketPtr pkt); + void checkHitOrMiss(reqBufferEntry* orbEntry); + bool checkDirty(Addr index, int way); + void handleDirtyCacheLine(Addr dirtyLineAddr); + bool checkConflictInORB(PacketPtr pkt); + void checkConflictInCRB(reqBufferEntry* orbEntry); + bool resumeConflictingReq(reqBufferEntry* orbEntry); + void logStatsPolMan(reqBufferEntry* orbEntry); + void accessAndRespond(PacketPtr pkt, Tick static_latency); + PacketPtr getPacket(Addr addr, unsigned size, const MemCmd& cmd, Request::FlagsType flags = 0); + Tick accessLatency(); + bool findInORB(Addr addr); + unsigned findDupInORB(Addr addr); + + unsigned countTagCheckInORB(); + unsigned countLocRdInORB(); + unsigned countFarRdInORB(); + unsigned countLocWrInORB(); + unsigned countFarWr(); + + Addr returnIndexDC(Addr pkt_addr, unsigned size); + Addr returnTagDC(Addr pkt_addr, unsigned size); + int returnWayDC(Addr index, Addr tag); + int findMatchingWay(Addr index, Addr tag); + int getCandidateWay(Addr index); + int findEmptyWay(Addr index); + + // port management + void locMemRecvReqRetry(); + void farMemRecvReqRetry(); + + bool locMemRecvTimingResp(PacketPtr pkt); + bool farMemRecvTimingResp(PacketPtr pkt); + struct PolicyManagerStats : public statistics::Group + { + PolicyManagerStats(PolicyManager &polMan); + + void regStats() override; + + const PolicyManager &polMan; + + // All statistics that the model needs to capture + statistics::Scalar readReqs; + statistics::Scalar writeReqs; + + statistics::Scalar servicedByWrQ; + statistics::Scalar servicedByFB; + statistics::Scalar mergedWrBursts; + statistics::Scalar mergedWrPolManWB; + statistics::Scalar mergedWrLocMemFB; + + statistics::Scalar numRdRetry; + statistics::Scalar numWrRetry; + + statistics::Vector readPktSize; + statistics::Vector writePktSize; + + statistics::Scalar bytesReadWrQ; + statistics::Scalar bytesReadSys; + statistics::Scalar bytesWrittenSys; + + // Average bandwidth + statistics::Formula avgRdBWSys; + statistics::Formula avgWrBWSys; + + statistics::Scalar totGap; + statistics::Formula avgGap; + + // DRAM Cache Specific Stats + statistics::Average avgORBLen; + statistics::Average avgTagCheckQLenStrt; + statistics::Average avgLocRdQLenStrt; + statistics::Average avgLocWrQLenStrt; + statistics::Average avgFarRdQLenStrt; + statistics::Average avgFarWrQLenStrt; + + statistics::Average avgTagCheckQLenEnq; + statistics::Average avgLocRdQLenEnq; + statistics::Average avgLocWrQLenEnq; + statistics::Average avgFarRdQLenEnq; + statistics::Average avgFarWrQLenEnq; + + statistics::Scalar numWrBacks; + statistics::Scalar totNumConf; + statistics::Scalar totNumORBFull; + statistics::Scalar totNumCRBFull; + + statistics::Scalar maxNumConf; + + statistics::Scalar sentTagCheckPort; + statistics::Scalar failedTagCheckPort; + statistics::Scalar sentLocRdPort; + statistics::Scalar sentLocWrPort; + statistics::Scalar failedLocRdPort; + statistics::Scalar failedLocWrPort; + statistics::Scalar sentFarRdPort; + statistics::Scalar sentFarWrPort; + statistics::Scalar failedFarRdPort; + statistics::Scalar failedFarWrPort; + + statistics::Scalar totPktLifeTime; + statistics::Scalar totPktLifeTimeRd; + statistics::Scalar totPktLifeTimeWr; + statistics::Scalar totPktORBTime; + statistics::Scalar totPktORBTimeRd; + statistics::Scalar totPktORBTimeWr; + statistics::Scalar totPktRespTime; + statistics::Scalar totPktRespTimeRd; + statistics::Scalar totPktRespTimeWr; + statistics::Scalar totTimeTagCheckRes; + statistics::Scalar totTimeTagCheckResRd; + statistics::Scalar totTimeTagCheckResWr; + statistics::Scalar totTimeTagCheckResRdH; + statistics::Scalar totTimeTagCheckResRdMC; + statistics::Scalar totTimeTagCheckResRdMD; + statistics::Scalar totTimeInLocRead; + statistics::Scalar totTimeInLocWrite; + statistics::Scalar totTimeInFarRead; + statistics::Scalar totTimeFarRdtoSend; + statistics::Scalar totTimeFarRdtoRecv; + statistics::Scalar totTimeFarWrtoSend; + + statistics::Formula avgPktLifeTime; + statistics::Formula avgPktLifeTimeRd; + statistics::Formula avgPktLifeTimeWr; + statistics::Formula avgPktORBTime; + statistics::Formula avgPktORBTimeRd; + statistics::Formula avgPktORBTimeWr; + statistics::Formula avgPktRespTime; + statistics::Formula avgPktRespTimeRd; + statistics::Formula avgPktRespTimeWr; + statistics::Formula avgTimeTagCheckRes; + statistics::Formula avgTimeTagCheckResRd; + statistics::Formula avgTimeTagCheckResWr; + statistics::Formula avgTimeTagCheckResRdH; + statistics::Formula avgTimeTagCheckResRdMC; + statistics::Formula avgTimeTagCheckResRdMD; + statistics::Formula avgTimeInLocRead; + statistics::Formula avgTimeInLocWrite; + statistics::Formula avgTimeInFarRead; + statistics::Formula avgTimeFarRdtoSend; + statistics::Formula avgTimeFarRdtoRecv; + statistics::Formula avgTimeFarWrtoSend; + + statistics::Scalar numTotHits; + statistics::Scalar numTotMisses; + statistics::Scalar numColdMisses; + statistics::Scalar numColdMissesSet; + statistics::Scalar numHotMisses; + statistics::Scalar numRdMissClean; + statistics::Scalar numRdMissDirty; + statistics::Scalar numRdHit; + statistics::Scalar numWrMissClean; + statistics::Scalar numWrMissDirty; + statistics::Scalar numWrHit; + statistics::Scalar numRdHitDirty; + statistics::Scalar numRdHitClean; + statistics::Scalar numWrHitDirty; + statistics::Scalar numWrHitClean; + + statistics::Formula missRatio; + statistics::Formula dirtyRatio; + + }; + + PolicyManagerStats polManStats; + + public: + + PolicyManager(const PolicyManagerParams &p); + + void init(); + + Port &getPort(const std::string &if_name, + PortID idx=InvalidPortID); + + // For preparing for checkpoints + DrainState drain() override; + + // Serializes the tag state so that we don't have to warm up each time. + void serialize(CheckpointOut &cp) const override; + void unserialize(CheckpointIn &cp) override; + + bool recvReadFlushBuffer(Addr addr) override; + + protected: + + Tick recvAtomic(PacketPtr pkt); + Tick recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &backdoor); + void recvFunctional(PacketPtr pkt); + bool recvTimingReq(PacketPtr pkt); +}; + +} // namespace memory +} // namespace gem5 + +#endif //__POLICY_MANAGER_HH__ diff --git a/src/mem/ruby/structures/CacheMemory.cc b/src/mem/ruby/structures/CacheMemory.cc index 5a5eaffa02..ea0ecc2e02 100644 --- a/src/mem/ruby/structures/CacheMemory.cc +++ b/src/mem/ruby/structures/CacheMemory.cc @@ -52,6 +52,7 @@ #include "mem/cache/replacement_policies/weighted_lru_rp.hh" #include "mem/ruby/protocol/AccessPermission.hh" #include "mem/ruby/system/RubySystem.hh" +#include "mem/simple_mem.hh" namespace gem5 { @@ -436,9 +437,20 @@ CacheMemory::recordCacheContents(int cntrl, CacheRecorder* tr) const if (request_type != RubyRequestType_NULL) { Tick lastAccessTick; lastAccessTick = m_cache[i][j]->getLastAccess(); - tr->addRecord(cntrl, m_cache[i][j]->m_Address, + // I want to get the data from the backing store if using + // access backing store + DataBlock data; + Addr addr = m_cache[i][j]->m_Address; + auto rs = params().ruby_system; + if (rs->getAccessBackingStore()) { + uint8_t *ptr = rs->getPhysMem(addr)->toHostAddr(addr); + data.setData(ptr, 0, rs->getBlockSizeBytes()); + } else { + data = m_cache[i][j]->getDataBlk(); + } + tr->addRecord(cntrl, addr, 0, request_type, lastAccessTick, - m_cache[i][j]->getDataBlk()); + data); warmedUpBlocks++; } } diff --git a/src/mem/ruby/structures/CacheMemory.hh b/src/mem/ruby/structures/CacheMemory.hh index a63bb02748..001d3cb152 100644 --- a/src/mem/ruby/structures/CacheMemory.hh +++ b/src/mem/ruby/structures/CacheMemory.hh @@ -69,7 +69,7 @@ namespace ruby class CacheMemory : public SimObject { public: - typedef RubyCacheParams Params; + PARAMS(RubyCache); typedef std::shared_ptr ReplData; CacheMemory(const Params &p); ~CacheMemory(); diff --git a/src/mem/ruby/system/RubyPort.cc b/src/mem/ruby/system/RubyPort.cc index ae21dc95ad..2e41c2f6cc 100644 --- a/src/mem/ruby/system/RubyPort.cc +++ b/src/mem/ruby/system/RubyPort.cc @@ -367,9 +367,13 @@ RubyPort::MemResponsePort::recvAtomic(PacketPtr pkt) pkt->getAddr(), (MachineType)mem_interface_type); AbstractController *mem_interface = rs->m_abstract_controls[mem_interface_type][id.getNum()]; - Tick latency = mem_interface->recvAtomic(pkt); - if (access_backing_store) - rs->getPhysMem()->access(pkt); + Tick latency; + if (access_backing_store) { + rs->getPhysMem(pkt->getAddr())->access(pkt); + latency = 1000; + } else { + latency = mem_interface->recvAtomic(pkt); + } return latency; } @@ -411,7 +415,7 @@ RubyPort::MemResponsePort::recvFunctional(PacketPtr pkt) // The following command performs the real functional access. // This line should be removed once Ruby supplies the official version // of data. - rs->getPhysMem()->functionalAccess(pkt); + rs->getPhysMem(pkt->getAddr())->functionalAccess(pkt); } else { bool accessSucceeded = false; bool needsResponse = pkt->needsResponse(); @@ -632,7 +636,7 @@ RubyPort::MemResponsePort::hitCallback(PacketPtr pkt) auto dmem = owner.system->getDeviceMemory(pkt); dmem->access(pkt); } else if (owner.system->isMemAddr(pkt->getAddr())) { - rs->getPhysMem()->access(pkt); + rs->getPhysMem(pkt->getAddr())->access(pkt); } else { panic("Packet is in neither device nor system memory!"); } diff --git a/src/mem/ruby/system/RubySystem.cc b/src/mem/ruby/system/RubySystem.cc index b38c903b09..7370023249 100644 --- a/src/mem/ruby/system/RubySystem.cc +++ b/src/mem/ruby/system/RubySystem.cc @@ -94,7 +94,15 @@ RubySystem::RubySystem(const Params &p) statistics::registerDumpCallback([this]() { collateStats(); }); // Create the profiler m_profiler = new Profiler(p, this); - m_phys_mem = p.phys_mem; + + // Set up the physical memories for the backing store + for (auto &mem : p.phys_mem) { + m_phys_mem.insert(mem->getAddrRange(), mem); + } + + fatal_if(m_access_backing_store && m_phys_mem.empty(), + "If using access backing store, a phys_mem must be provided to the " + "Ruby system."); } void diff --git a/src/mem/ruby/system/RubySystem.hh b/src/mem/ruby/system/RubySystem.hh index e16d699204..7e51d60d6c 100644 --- a/src/mem/ruby/system/RubySystem.hh +++ b/src/mem/ruby/system/RubySystem.hh @@ -37,6 +37,7 @@ #include +#include "base/addr_range_map.hh" #include "base/callback.hh" #include "base/output.hh" #include "mem/packet.hh" @@ -75,7 +76,13 @@ class RubySystem : public ClockedObject static bool getWarmupEnabled() { return m_warmup_enabled; } static bool getCooldownEnabled() { return m_cooldown_enabled; } - memory::SimpleMemory *getPhysMem() { return m_phys_mem; } + memory::SimpleMemory *getPhysMem(Addr addr) { + auto it = m_phys_mem.contains(addr); + panic_if (it == m_phys_mem.end(), + "Cannot find physical memory for address %#x", addr); + return it->second; + } + Cycles getStartCycle() { return m_start_cycle; } bool getAccessBackingStore() { return m_access_backing_store; } @@ -142,7 +149,7 @@ class RubySystem : public ClockedObject static bool m_warmup_enabled; static unsigned m_systems_to_warmup; static bool m_cooldown_enabled; - memory::SimpleMemory *m_phys_mem; + AddrRangeMap m_phys_mem; const bool m_access_backing_store; //std::vector m_networks; diff --git a/src/mem/ruby/system/RubySystem.py b/src/mem/ruby/system/RubySystem.py index 64e39bda4c..36b5d0dcf5 100644 --- a/src/mem/ruby/system/RubySystem.py +++ b/src/mem/ruby/system/RubySystem.py @@ -48,7 +48,7 @@ class RubySystem(ClockedObject): 64, "number of bits that a memory address requires" ) - phys_mem = Param.SimpleMemory(NULL, "") + phys_mem = VectorParam.SimpleMemory([], "Memories for backing store") system = Param.System(Parent.any, "system object") access_backing_store = Param.Bool( diff --git a/src/mem/xbar.cc b/src/mem/xbar.cc index 0d4b2fca97..ce1a294ae6 100644 --- a/src/mem/xbar.cc +++ b/src/mem/xbar.cc @@ -123,8 +123,8 @@ BaseXBar::calcPacketTiming(PacketPtr pkt, Tick header_delay) // do a quick sanity check to ensure the timings are not being // ignored, note that this specific value may cause problems for // slower interconnects - panic_if(pkt->headerDelay > sim_clock::as_int::us, - "Encountered header delay exceeding 1 us\n"); + // panic_if(pkt->headerDelay > sim_clock::as_int::us, + // "Encountered header delay exceeding 1 us\n"); if (pkt->hasData()) { // the payloadDelay takes into account the relative time to @@ -196,8 +196,8 @@ BaseXBar::Layer::tryTiming(SrcType* src_port) // for a retry from the peer if (state == BUSY || waitingForPeer != NULL) { // the port should not be waiting already - assert(std::find(waitingForLayer.begin(), waitingForLayer.end(), - src_port) == waitingForLayer.end()); + // assert(std::find(waitingForLayer.begin(), waitingForLayer.end(), + // src_port) == waitingForLayer.end()); // put the port at the end of the retry list waiting for the // layer to be freed up (and in the case of a busy peer, for diff --git a/src/python/SConscript b/src/python/SConscript index eaaea203f0..766b6edd62 100644 --- a/src/python/SConscript +++ b/src/python/SConscript @@ -191,6 +191,7 @@ PySource('gem5.components.memory', 'gem5/components/memory/memory.py') PySource('gem5.components.memory', 'gem5/components/memory/single_channel.py') PySource('gem5.components.memory', 'gem5/components/memory/multi_channel.py') PySource('gem5.components.memory', 'gem5/components/memory/hbm.py') +PySource('gem5.components.memory', 'gem5/components/memory/dcache.py') PySource('gem5.components.memory.dram_interfaces', 'gem5/components/memory/dram_interfaces/__init__.py') PySource('gem5.components.memory.dram_interfaces', diff --git a/src/python/gem5/components/memory/__init__.py b/src/python/gem5/components/memory/__init__.py index 546d5d98ed..2ea8c0651d 100644 --- a/src/python/gem5/components/memory/__init__.py +++ b/src/python/gem5/components/memory/__init__.py @@ -37,6 +37,9 @@ from .multi_channel import DualChannelDDR4_2400 from .multi_channel import DualChannelLPDDR3_1600 from .hbm import HBM2Stack +from .dcache import CascadeLakeCache +from .dcache import OracleCache +from .dcache import RambusCache try: from .dramsys import DRAMSysMem diff --git a/src/python/gem5/components/memory/dcache.py b/src/python/gem5/components/memory/dcache.py new file mode 100644 index 0000000000..7fe326cffc --- /dev/null +++ b/src/python/gem5/components/memory/dcache.py @@ -0,0 +1,190 @@ +# Copyright (c) 2022 The Regents of the University of California +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +""" DRAM Cache based memory system + Uses Policy Manager and two other memory systems +""" + +from .memory import ChanneledMemory +from .abstract_memory_system import AbstractMemorySystem +from ..boards.abstract_board import AbstractBoard +from math import log +from ...utils.override import overrides +from m5.objects import AddrRange, DRAMInterface, Port, PolicyManager, L2XBar, IOXBar +from typing import Type, Optional, Union, Sequence, Tuple, List +from .memory import _try_convert +from .dram_interfaces.hbm import TDRAM_32 +from .dram_interfaces.ddr4 import DDR4_2400_8x8 +from .multi_channel import DualChannelDDR4_2400 +from .single_channel import SingleChannelDDR4_2400 + +class DCacheSystem(AbstractMemorySystem): + """ + This class creates a DRAM cache based memory system. + It can connect two memory systems with a DRAM cache + policy manager. + """ + + def __init__( + self, + loc_mem: Type[ChanneledMemory], + far_mem: Type[ChanneledMemory], + loc_mem_policy: [str] = None, + size: [str] = None, + cache_size: [str] = None, + ) -> None: + """ + :param loc_mem_policy: DRAM cache policy to be used + :param size: Optionally specify the size of the DRAM controller's + address space. By default, it starts at 0 and ends at the size of + the DRAM device specified + """ + super().__init__() + + self._size = size + + self.policy_manager = PolicyManager() + self.policy_manager.static_frontend_latency = "10ns" + self.policy_manager.static_backend_latency = "10ns" + + + self.policy_manager.loc_mem_policy = loc_mem_policy + self.policy_manager.bypass_dcache = False + + self.policy_manager.dram_cache_size = cache_size + self.policy_manager.cache_warmup_ratio = 0.95 + + self.loc_mem = loc_mem() + self.far_mem = far_mem() + + for dram in self.loc_mem._dram: + dram.in_addr_map = False + dram.null = True + #dram.range = AddrRange('1GiB') + + # TODO: this loc_mem in policy manager + # is a single DRAM interface, which probably + # needs to be updated for a multi-channel local + # memory, the stdlib component can then be updated. + self.policy_manager.loc_mem = self.loc_mem._dram[0] + + self.policy_manager.orb_max_size = 128 + + for dram in self.far_mem._dram: + dram.in_addr_map = False + dram.null = True + # DRAM interface DDR4_2400_16x4 + # by default has a write buffer size of 128 + dram.read_buffer_size = 64 + dram.write_buffer_size = 64 + + self._loc_mem_controller = self.loc_mem.get_memory_controllers()[0] + self._far_mem_controller = self.far_mem.get_memory_controllers()[0] + + self._loc_mem_controller.consider_oldest_write= True + self._loc_mem_controller.static_frontend_latency = "1ns" + self._loc_mem_controller.static_backend_latency = "1ns" + + self._far_mem_controller.static_frontend_latency = "1ns" + self._far_mem_controller.static_backend_latency = "1ns" + + self._loc_mem_controller.port = self.policy_manager.loc_req_port + self._far_mem_controller.port = self.policy_manager.far_req_port + + # If need to use XBar + #self.farMemXBar = L2XBar(width=64) + #self.nearMemXBar = L2XBar(width=64) + + #self.policy_manager.far_req_port = self.farMemXBar.cpu_side_ports + #self.policy_manager.loc_req_port = self.nearMemXBar.cpu_side_ports + + #for ctrl in self.loc_mem.get_memory_controllers(): + # self.nearMemXBar.mem_side_ports = ctrl.port + + #for ctrl in self.far_mem.get_memory_controllers(): + # self.farMemXBar.mem_side_ports = ctrl.port + + @overrides(AbstractMemorySystem) + def get_size(self) -> int: + return self._size + + @overrides(AbstractMemorySystem) + def set_memory_range(self, ranges: List[AddrRange]) -> None: + + self.policy_manager.range = ranges[0] + for dram in self.far_mem._dram: + dram.range = ranges[0] + for dram in self.loc_mem._dram: + dram.range = ranges[0] + + @overrides(AbstractMemorySystem) + def incorporate_memory(self, board: AbstractBoard) -> None: + pass + + @overrides(AbstractMemorySystem) + def get_memory_controllers(self): + return [self.policy_manager] + + @overrides(AbstractMemorySystem) + def get_mem_ports(self) -> Sequence[Tuple[AddrRange, Port]]: + return [(self.policy_manager.range, self.policy_manager.port)] + +def SingleChannelTDRAM32( + size: Optional[str] = None, +) -> AbstractMemorySystem: + if not size: + size = "256MiB" + return ChanneledMemory( + TDRAM_32, + 1, + 64, + size=size + ) + + +def CascadeLakeCache(cache_size) -> AbstractMemorySystem: + return DCacheSystem( + SingleChannelTDRAM32, + SingleChannelDDR4_2400, + 'CascadeLakeNoPartWrs', + size='64GiB', + cache_size=cache_size) + +def OracleCache(cache_size) -> AbstractMemorySystem: + return DCacheSystem( + SingleChannelTDRAM32, + SingleChannelDDR4_2400, + 'Oracle', + size='64GiB', + cache_size=cache_size) + +def RambusCache(cache_size) -> AbstractMemorySystem: + return DCacheSystem( + SingleChannelTDRAM32, + SingleChannelDDR4_2400, + 'Rambus', + size='64GiB', + cache_size=cache_size) \ No newline at end of file diff --git a/src/python/gem5/components/memory/dram_interfaces/hbm.py b/src/python/gem5/components/memory/dram_interfaces/hbm.py index 5063c4d9e1..b6c0d1790f 100644 --- a/src/python/gem5/components/memory/dram_interfaces/hbm.py +++ b/src/python/gem5/components/memory/dram_interfaces/hbm.py @@ -276,3 +276,91 @@ class HBM_2000_4H_1x64(DRAMInterface): write_buffer_size = 64 two_cycle_activate = True + +class TDRAM_32(DRAMInterface): + + # 64-bit interface for a single pseudo channel + device_bus_width = 32 + + # HBM2 supports BL4 + burst_length = 16 + + # size of channel in bytes, 4H stack of 8Gb dies is 4GiB per stack; + # with 16 pseudo channels, 256MiB per pseudo channel + device_size = "1GiB" + + device_rowbuffer_size = "2KiB" + + # 1x128 configuration + devices_per_rank = 1 + + ranks_per_channel = 1 + + banks_per_rank = 32 + + bank_groups_per_rank = 8 + + # 1000 MHz for 2Gbps DDR data rate + tCK = "0.5ns" + + # new + tTAGBURST = "0.5ns" + tRLFAST = "7.5ns" + tHM2DQ = "0ns" + tRTW_int = "1ns" + tRFBD = "1ns" + tRCD_FAST = "7.5ns" + enable_read_flush_buffer = True + flushBuffer_high_thresh_perc = 80 + + tRP = "14ns" + + tCCD_L = "2ns" + + tRCD = "12ns" + tRCD_WR = "6ns" + tCL = "18ns" + tCWL = "7ns" + tRAS = "28ns" + + tBURST = "2ns" + + # value for 2Gb device from JEDEC spec + tRFC = "220ns" + + # value for 2Gb device from JEDEC spec + tREFI = "3.9us" + + tWR = "14ns" + tRTP = "5ns" + tWTR = "4ns" + tWTR_L = "9ns" + tRTW = "18ns" + + #tAAD from RBus + tAAD = "1ns" + + # single rank device, set to 0 + tCS = "0ns" + + tRRD = "2ns" + tRRD_L = "2ns" + + # for a single pseudo channel + tXAW = "16ns" + activation_limit = 8 + + # 4tCK + tXP = "8ns" + + # start with tRFC + tXP -> 160ns + 8ns = 168ns + tXS = "216ns" + + page_policy = 'close' + + read_buffer_size = 64 + write_buffer_size = 64 + + two_cycle_activate = True + + addr_mapping = 'RoCoRaBaCh' diff --git a/src/python/gem5/components/memory/multi_channel.py b/src/python/gem5/components/memory/multi_channel.py index 1f14190c97..732dc1d49a 100644 --- a/src/python/gem5/components/memory/multi_channel.py +++ b/src/python/gem5/components/memory/multi_channel.py @@ -60,7 +60,6 @@ def DualChannelDDR4_2400( """ return ChanneledMemory(DDR4_2400_8x8, 2, 64, size=size) - def DualChannelLPDDR3_1600( size: Optional[str] = None, ) -> AbstractMemorySystem: diff --git a/src/python/gem5/components/processors/simple_switchable_processor.py b/src/python/gem5/components/processors/simple_switchable_processor.py index e3978412c3..fa8990d0c8 100644 --- a/src/python/gem5/components/processors/simple_switchable_processor.py +++ b/src/python/gem5/components/processors/simple_switchable_processor.py @@ -123,3 +123,39 @@ def switch(self): self.switch_to_processor(self._start_key) self._current_is_start = not self._current_is_start + +class MySimpleProcessor(SimpleSwitchableProcessor): + def __init__( + self, + starting_core_type: CPUTypes, + switch_core_type: CPUTypes, + num_cores: int, + isa = None, + ) -> None: + if not isa: + warn( + "An ISA for the SimpleSwitchableProcessor was not set. This " + "will result in usage of `runtime.get_runtime_isa` to obtain " + "the ISA. This function is deprecated and will be removed in " + "future releases of gem5. Please explicitly state the ISA " + "via the processor constructor." + ) + if num_cores <= 0: + raise AssertionError("Number of cores must be a positive integer!") + self._start_key = "switch" + self._switch_key = "start" + self._current_is_start = True + self._mem_mode = get_mem_mode(starting_core_type) + switchable_cores = { + self._start_key: [ + SimpleCore(cpu_type=starting_core_type, core_id=i, isa=isa) + for i in range(num_cores) + ], + self._switch_key: [ + SimpleCore(cpu_type=switch_core_type, core_id=i, isa=isa) + for i in range(num_cores) + ], + } + SwitchableProcessor.__init__(self, + switchable_cores=switchable_cores, starting_cores=self._start_key + ) \ No newline at end of file diff --git a/src/python/gem5/simulate/exit_event.py b/src/python/gem5/simulate/exit_event.py index cffe864f06..e150440979 100644 --- a/src/python/gem5/simulate/exit_event.py +++ b/src/python/gem5/simulate/exit_event.py @@ -43,6 +43,7 @@ class ExitEvent(Enum): FAIL = "fail" # An exit because the simulation has failed. CHECKPOINT = "checkpoint" # An exit to load a checkpoint. SCHEDULED_TICK = "scheduled tick exit" + SCHEDULED_TICK_PROGRESS = "progress update" MAX_TICK = "max tick" # An exit due to a maximum tick value being met. USER_INTERRUPT = ( # An exit due to a user interrupt (e.g., cntr + c) "user interupt" @@ -53,6 +54,7 @@ class ExitEvent(Enum): PERF_COUNTER_DISABLE = "performance counter disabled" PERF_COUNTER_RESET = "performance counter reset" PERF_COUNTER_INTERRUPT = "performance counter interrupt" + CACHE_WARMUP = "dram cache is warmed up" @classmethod def translate_exit_status(cls, exit_string: str) -> "ExitEvent": @@ -82,6 +84,8 @@ def translate_exit_status(cls, exit_string: str) -> "ExitEvent": return ExitEvent.MAX_TICK elif exit_string == "Tick exit reached": return ExitEvent.SCHEDULED_TICK + elif exit_string == "progress_update": + return ExitEvent.SCHEDULED_TICK_PROGRESS elif exit_string == "switchcpu": return ExitEvent.SWITCHCPU elif exit_string == "m5_fail instruction encountered": @@ -102,6 +106,9 @@ def translate_exit_status(cls, exit_string: str) -> "ExitEvent": return ExitEvent.PERF_COUNTER_RESET elif exit_string == "performance counter interrupt": return ExitEvent.PERF_COUNTER_INTERRUPT + elif exit_string == "cacheIsWarmedup": + # This is for the DRAM cache warmup + return ExitEvent.CACHE_WARMUP elif exit_string.endswith("will terminate the simulation.\n"): # This is for the traffic generator exit event return ExitEvent.EXIT diff --git a/src/python/gem5/simulate/simulator.py b/src/python/gem5/simulate/simulator.py index e355d200ad..9b5c7f552a 100644 --- a/src/python/gem5/simulate/simulator.py +++ b/src/python/gem5/simulate/simulator.py @@ -277,6 +277,7 @@ def print_hello() -> bool: ExitEvent.USER_INTERRUPT: exit_generator(), ExitEvent.MAX_TICK: exit_generator(), ExitEvent.SCHEDULED_TICK: exit_generator(), + ExitEvent.SCHEDULED_TICK_PROGRESS: exit_generator(), ExitEvent.SIMPOINT_BEGIN: warn_default_decorator( reset_stats_generator, "simpoint begin", diff --git a/src/python/m5/SimObject.py b/src/python/m5/SimObject.py index f2c1b30def..96695ec1e6 100644 --- a/src/python/m5/SimObject.py +++ b/src/python/m5/SimObject.py @@ -38,6 +38,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +from builtins import print import sys from types import FunctionType, MethodType, ModuleType from functools import wraps @@ -1075,7 +1076,11 @@ def find_all(self, ptype): if issubclass(pdesc.ptype, ptype): match_obj = self._values[pname] if not isproxy(match_obj) and not isNullPointer(match_obj): - all[match_obj] = True + if isinstance(match_obj, SimObjectVector): + for obj in match_obj: + all[obj] = True + else: + all[match_obj] = True # Also make sure to sort the keys based on the objects' path to # ensure that the order is the same on all hosts return sorted(all.keys(), key=lambda o: o.path()), True @@ -1231,7 +1236,9 @@ def getCCParams(self): # necessary to construct it. Does *not* recursively create # children. def getCCObject(self): + # print(self) if not self._ccObject: + # print(f"{self}: Doing initial creation") # Make sure this object is in the configuration hierarchy if not self._parent and not isRoot(self): raise RuntimeError("Attempt to instantiate orphan node") @@ -1241,10 +1248,14 @@ def getCCObject(self): if not self.abstract: params = self.getCCParams() self._ccObject = params.create() + # print(f"{self}: Actually created") + # else: + # print("I am abstract?") elif self._ccObject == -1: raise RuntimeError( - f"{self.path()}: Cycle found in configuration hierarchy." + "%s: Cycle found in configuration hierarchy." % self.path() ) + # print(f"retuning {self._ccObject}") return self._ccObject def descendants(self): diff --git a/traffGen_def.py b/traffGen_def.py new file mode 100644 index 0000000000..19468d670e --- /dev/null +++ b/traffGen_def.py @@ -0,0 +1,131 @@ +from m5.objects import * +import m5 +import argparse +from m5.objects.DRAMInterface import * +from m5.objects.NVMInterface import * + +args = argparse.ArgumentParser() + +args.add_argument( + "traffic_mode", + type = str, + help = "Traffic type to use" +) + +args.add_argument( + "rd_prct", + type=int, + help="Read Percentage", +) + +args.add_argument( + "extreme", + type=int, + help="extreme", +) + +args.add_argument( + "hit_miss", + type=int, + help="hit_miss", +) + +args.add_argument( + "clean_dirty", + type=int, + help="clean_dirty", +) + +options = args.parse_args() + +system = System() +system.clk_domain = SrcClockDomain() +system.clk_domain.clock = "4GHz" +system.clk_domain.voltage_domain = VoltageDomain() +system.mem_mode = 'timing' + +system.generator = PyTrafficGen() + +system.mem_ctrl = PolicyManager(range=AddrRange('3GiB')) + +system.mem_ctrl.orb_max_size = 128 +system.mem_ctrl.assoc = 1 +system.mem_ctrl.static_frontend_latency = "10ns" +system.mem_ctrl.static_backend_latency = "10ns" + +system.loc_mem_ctrl = MemCtrl() +system.loc_mem_ctrl.dram = TDRAM_32(range=AddrRange('3GiB'), in_addr_map=False, null=True) +system.mem_ctrl.loc_mem_policy = 'RambusTagProbOpt' + +system.mem_ctrl.loc_mem = system.loc_mem_ctrl.dram +system.loc_mem_ctrl.static_frontend_latency = "1ns" +system.loc_mem_ctrl.static_backend_latency = "1ns" +system.loc_mem_ctrl.static_frontend_latency_tc = "0ns" +system.loc_mem_ctrl.static_backend_latency_tc = "0ns" +system.loc_mem_ctrl.consider_oldest_write = True +system.loc_mem_ctrl.oldest_write_age_threshold = 2500000 + +system.far_mem_ctrl = MemCtrl() +system.far_mem_ctrl.dram = DDR4_2400_16x4(range=AddrRange('3GiB'),in_addr_map=False, null=True) +system.far_mem_ctrl.dram.read_buffer_size = 64 +system.far_mem_ctrl.dram.write_buffer_size = 64 +system.far_mem_ctrl.static_frontend_latency = "1ns" +system.far_mem_ctrl.static_backend_latency = "1ns" + +if options.extreme == 1: + system.mem_ctrl.extreme = True +else : + system.mem_ctrl.extreme = False + +if options.hit_miss == 1: + system.mem_ctrl.always_hit = True +else : + system.mem_ctrl.always_hit = False + +if options.clean_dirty == 1: + system.mem_ctrl.always_dirty = True +else : + system.mem_ctrl.always_dirty = False + +system.mem_ctrl.dram_cache_size = "128MiB" + +system.generator.port = system.mem_ctrl.port +system.loc_mem_ctrl.port = system.mem_ctrl.loc_req_port +system.far_mem_ctrl.port = system.mem_ctrl.far_req_port + +def createRandomTraffic(tgen): + yield tgen.createRandom(10000000000, # duration + 0, # min_addr + AddrRange('3GiB').end, # max_adr + 64, # block_size + 1000, # min_period + 1000, # max_period + options.rd_prct, # rd_perc + 0) # data_limit + yield tgen.createExit(0) + +def createLinearTraffic(tgen): + yield tgen.createLinear(10000000000, # duration + 0, # min_addr + AddrRange('3GiB').end, # max_adr + 64, # block_size + 1000, # min_period + 1000, # max_period + options.rd_prct, # rd_perc + 0) # data_limit + yield tgen.createExit(0) + +root = Root(full_system=False, system=system) + +m5.instantiate() + +if options.traffic_mode == 'linear': + system.generator.start(createLinearTraffic(system.generator)) +elif options.traffic_mode == 'random': + system.generator.start(createRandomTraffic(system.generator)) +else: + print('Wrong traffic type! Exiting!') + exit() + +exit_event = m5.simulate() +print(f"Exit reason {exit_event.getCause()}") diff --git a/traffGen_mem.py b/traffGen_mem.py new file mode 100644 index 0000000000..e108b40981 --- /dev/null +++ b/traffGen_mem.py @@ -0,0 +1,88 @@ +from m5.objects import * +import m5 +import argparse +from m5.objects.DRAMInterface import * +from m5.objects.NVMInterface import * + +args = argparse.ArgumentParser() + +args.add_argument( + "traffic_mode", + type = str, + help = "Traffic type to use" +) + +args.add_argument( + "rd_prct", + type=int, + help="Read Percentage", +) + +options = args.parse_args() + +system = System() +system.clk_domain = SrcClockDomain() +system.clk_domain.clock = "4GHz" +system.clk_domain.voltage_domain = VoltageDomain() +system.mem_mode = 'timing' + +system.generator = PyTrafficGen() + +system.mem_ctrl = MemCtrl() +system.mem_ctrl.dram = TDRAM_32(range=AddrRange('3GiB')) +system.mem_ctrl.dram.activation_limit = 8 +system.mem_ctrl.dram.addr_mapping = 'RoCoRaBaCh' + +# DDR4 Alloy +# system.mem_ctrl.dram = DDR4_2400_16x4(range=AddrRange('3GiB')) +# system.mem_ctrl.dram.burst_length = 10 +# system.mem_ctrl.dram.tBURST = "4.165ns" +# system.mem_ctrl.dram.tCCD_L = "5ns" "6.25ns" +# system.mem_ctrl.dram.is_alloy = True + +# HBM2 1 PC Alloy +# system.mem_ctrl.dram = HBM_2000_4H_1x64(range=AddrRange('3GiB')) +# system.mem_ctrl.dram.burst_length = 10 +# system.mem_ctrl.dram.tBURST = "5ns" +# #system.mem_ctrl.dram.tCCD_L = "7ns" +# system.mem_ctrl.dram.is_alloy = True + + +system.generator.port = system.mem_ctrl.port + +def createRandomTraffic(tgen): + yield tgen.createRandom(10000000000, # duration + 0, # min_addr + AddrRange('3GiB').end, # max_adr + 64, # block_size + 1000, # min_period + 1000, # max_period + options.rd_prct, # rd_perc + 0) # data_limit + yield tgen.createExit(0) + +def createLinearTraffic(tgen): + yield tgen.createLinear(10000000000, # duration + 0, # min_addr + AddrRange('3GiB').end, # max_adr + 64, # block_size + 1000, # min_period + 1000, # max_period + options.rd_prct, # rd_perc + 0) # data_limit + yield tgen.createExit(0) + +root = Root(full_system=False, system=system) + +m5.instantiate() + +if options.traffic_mode == 'linear': + system.generator.start(createLinearTraffic(system.generator)) +elif options.traffic_mode == 'random': + system.generator.start(createRandomTraffic(system.generator)) +else: + print('Wrong traffic type! Exiting!') + exit() + +exit_event = m5.simulate() +print(f"Exit reason {exit_event.getCause()}") \ No newline at end of file From 3d94b88be6301831373e098b23fc2be5b5919c86 Mon Sep 17 00:00:00 2001 From: mbabaie Date: Mon, 2 Oct 2023 17:01:29 -0700 Subject: [PATCH 02/28] merge conflicts resolved --- cmd.txt | 486 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 486 insertions(+) create mode 100644 cmd.txt diff --git a/cmd.txt b/cmd.txt new file mode 100644 index 0000000000..8965ec914c --- /dev/null +++ b/cmd.txt @@ -0,0 +1,486 @@ + 29 git status + 30 clear + 31 git status + 32 ssh babaie@galaxy.cs.ucdavis.edu + 33 cd paper-draft1/papers/tdram-paper/hpca2024-latex-template/ + 34 git status + 35 git diff + 36 git pull + 37 git status + 38 git diff + 39 git statsh + 40 git stash + 41 git pull + 42 qgit rebase --continue + 43 git rebase --continue + 44 cd ../../../ + 45 cd ../ + 46 mkdir paper-draft-postsubmission + 47 cd paper-draft-postsubmission/ + 48 git clone https://github.com/darchr/papers.git + 49 cd papers/tdram-paper/hpca2024-latex-template/ + 50 make + 51 zip -r TDRAM-Paper.zip /home/babaie/projects/rambusDesign/paper-draft-postsubmission/papers/tdram-paper/hpca2024-latex-template + 52 ls + 53 cd checkSetAssociative/dramCacheController/ + 54 git status + 55 sudo apt install git + 56 git status + 57 git diff + 58 cd ../../1gigDRAMCache/dramCacheController/ + 59 clear + 60 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 0 0 + 61 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 0 0 + 62 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 0 0 + 63 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 0 0 + 64 mkdir longerTagCheckLatency + 65 cd longerTagCheckLatency/ + 66 git clone https://github.com/darchr/dramCacheController.git + 67 cd dramCacheController/ + 68 git checkout tag_prob_real_implementation + 69 scons build/X86_MESI_Two_Level/gem5.opt -j40 --linker=gold --without-tcmalloc + 70 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 0 0 + 71 cd projects/ + 72 mkdir stable_gem5 + 73 cd stable_gem5/ + 74 git clone https://github.com/gem5/gem5 + 75 ls + 76 cd ../../../ + 77 cd stable_gem5/ + 78 git clone https://github.com/gem5/gem5 + 79 cd ../../ + 80 git lofg + 81 git log + 82 cd tagProbing/dramCacheController/ + 83 git status + 84 cd ../../tagProbingNew/dramCacheController/ + 85 git status + 86 cd /home/babaie/projects/rambusDesign/tagProbOptRealImplOnSetAssoBranch/dramCacheController + 87 git status + 88 git log + 89 cd /home/babaie/projects/rambusDesign/tagProbOptRealImplOnSetAssoBranch/dramCacheController + 90 git status + 91 cd /home/babaie/projects/rambusDesign/tagProbingNew/dramCacheController + 92 git status + 93 cd /home/babaie/projects/rambusDesign/tagProbing/dramCacheController + 94 git status + 95 cd ../../ + 96 mkdir tagProb-Backup + 97 mkdir setAssoc-Backup + 98 cd tagProb-Backup/ + 99 git clone https://github.com/darchr/dramCacheController + 100 git checkout tag_prob_backup + 101 cd dramCacheController/ + 102 git checkout tag_prob_backup + 103 cd ../setAssoc-Backup/ + 104 git clone https://github.com/darchr/dramCacheController + 105 cd dramCacheController/ + 106 git checkout set_associative_backup + 107 cd setAssoc-Backup/dramCacheController/ + 108 git status + 109 cd ../../tagProb-Backup/dramCacheController/ + 110 git status + 111 cd ... + 112 cd ../.. + 113 mkdir merge tagPrbIntoSetAsso + 114 mkdir mergeTagPrbIntoSetAsso + 115 cd mergeTagPrbIntoSetAsso/ + 116 git clone https://github.com/darchr/dramCacheController + 117 ls + 118 cd dramCacheController/ + 119 git status + 120 git checkout set_associative_backup + 121 git checkout tag_prob_backup + 122 git status + 123 git rebase set_associative_backup + 124 cd ../ + 125 rm -r dramCacheController/ + 126 ls + 127 git clone https://github.com/darchr/dramCacheController + 128 cd ../ + 129 rm -r mergeTagPrbIntoSetAsso/ + 130 mkdir mergeSetTagPrb + 131 cd mergeSetTagPrb/ + 132 git clone https://github.com/darchr/dramCacheController + 133 cd mergeSetTagPrb/ + 134 git clone https://github.com/darchr/dramCacheController + 135 clear + 136 ls + 137 cd mergeSetTagPrb/ + 138 git clone https://github.com/darchr/dramCacheController + 139 cd dramCacheController/ + 140 clear + 141 git checkout tag_prob_backup + 142 clear + 143 git status + 144 git rebase -i HEAD~15 + 145 git rebase -i HEAD~25 + 146 git rebase --abort + 147 git rebase -i HEAD~25 + 148 git rebase --abort + 149 git rebase -i HEAD~25 + 150 git status + 151 git status + 152 git add realAppRun.sh + 153 git rebase --continue + 154 git status + 155 git add realAppRun.sh + 156 git rebase --continue + 157 git status + 158 git add realAppRun.sh + 159 git rebase --continue + 160 git add realAppRun.sh + 161 git rebase --continue --ours + 162 git rebase --continue + 163 git log + 164 clear + 165 git status + 166 git format-patch -1 + 167 git checkout set_associative_backup + 168 git log + 169 clear + 170 git am 0001-parent-41af1e744aaf2a2dd291d32ad1ec1b672b8822b9.patch + 171 git status + 172 git am --abort + 173 git am -3 < 0001-parent-41af1e744aaf2a2dd291d32ad1ec1b672b8822b9.patch + 174 git status + 175 git add realAppRun.sh + 176 git am --continue + 177 git log + 178 git log + 179 git show + 180 git diff src/mem/dram_interface.cc + 181 scons build/X86_MESI_Two_Level/gem5.opt -j30 + 182 cd mergeSetTagPrb/ + 183 cd dramCacheController/ + 184 git status + 185 git push + 186 history > git-cmds.txt + 187 mkdir gem5-23 + 188 cd gem5-23/ + 189 git clone https://github.com/darchr/dramCacheController.git + 190 git switch -c develop23 + 191 git checkout -b develop23 + 192 cd dramCacheController/ + 193 git switch -c develop23 + 194 git pull https://github.com/gem5/gem5.git develop + 195 git checkout develop22 + 196 cd ../ + 197 cd ../ + 198 rm -r gem5-23/ + 199 mkdir gem5-dev + 200 cd gem5-dev/ + 201 mkdir dev23 + 202 cd dev23/ + 203 git clone https://github.com/darchr/dramCacheController.git + 204 cd dramCacheController/ + 205 git checkout develop22 + 206 git pull + 207 git pull https://github.com/gem5/gem5.git develop + 208 git status + 209 git checkout -b develop23 + 210 git status + 211 git add . + 212 git push + 213 git push --set-upstream origin develop23 + 214 scons build/X86_MESI_Two_Level/gem5.opt -j30 + 215 cd ../../../ + 216 cd setAssoc-Backup/dramCacheController/ + 217 git status + 218 git checkout -b set_associative_backup + 219 git checkout -b set_associative_backup2 + 220 git push + 221 git push --set-upstream origin set_associative_backup2 + 222 git status + 223 git pull + 224 git status + 225 git status + 226 cd ../../../mergeSetTagPrb/dramCacheController/ + 227 git status + 228 git diff + 229 git commit -am "just some comments removed" + 230 git push + 231 git status + 232 git branch -m set_associative_backup merged_tagPrb_setAssoc + 233 git status + 234 git branch -a + 235 git status + 236 git status + 237 cd mergeSetTagPrb/dramCacheController/ + 238 git status + 239 scons build/X86_MESI_Two_Level/gem5.opt -j30 + 240 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 1 0 + 241 scons build/X86_MESI_Two_Level/gem5.opt -j30 + 242 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 1 0 + 243 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold + 244 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 1 0 + 245 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold + 246 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 1 0 + 247 gdb --args build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 1 0 + 248 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold + 249 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 1 0 + 250 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 1 1 + 251 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 0 0 + 252 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 0 1 + 253 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 0 1 1 0 + 254 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 0 1 1 1 + 255 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 0 1 0 0 + 256 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 0 1 0 1 + 257 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 0 0 + 258 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 0 1 + 259 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold + 260 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 0 1 + 261 build/X86_MESI_Two_Level/gem5.opt --debug-flag=DRAMT traffGen_def.py random 100 1 0 1 + 262 build/X86_MESI_Two_Level/gem5.opt -re --debug-flag=DRAMT traffGen_def.py random 100 1 0 1 + 263 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold + 264 build/X86_MESI_Two_Level/gem5.opt -re --debug-flag=DRAMT traffGen_def.py random 100 1 0 1 + 265 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold + 266 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold + 267 build/X86_MESI_Two_Level/gem5.opt -re --debug-flag=DRAMT traffGen_def.py random 100 1 0 1 + 268 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold + 269 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold + 270 build/X86_MESI_Two_Level/gem5.opt -re --debug-flag=DRAMT traffGen_def.py random 100 1 0 1 + 271 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold + 272 build/X86_MESI_Two_Level/gem5.opt -re --debug-flag=DRAMT traffGen_def.py random 100 1 0 1 + 273 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold + 274 build/X86_MESI_Two_Level/gem5.opt -re --debug-flag=DRAMT traffGen_def.py random 100 1 0 1 + 275 ls + 276 cd mergeSetTagPrb/dramCacheController/ + 277 git status + 278 cd ../../ + 279 mkdir codeReview + 280 cd codeReview/ + 281 ls ../code + 282 cd ../code/dramCacheController/ + 283 git status + 284 cd ../../codeReview/ + 285 git clone https://github.com/darchr/dramCacheController.git + 286 clear + 287 ls + 288 cd codeReview/ + 289 ls + 290 clear + 291 git clone https://github.com/darchr/dramCacheController.git + 292 cd dramCacheController/ + 293 git checkout set_associative_backup + 294 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc + 295 screen -ls + 296 screen -S test + 297 cd + 298 cd ../../../ + 299 cd codeReview/dramCacheController/ + 300 build/X86_MESI_Two_Level/gem5.opt -re configs-npb-gapbs/npb_checkpoint.py bt C RambusTagProbOpt 0 0 + 301 build/X86_MESI_Two_Level/gem5.opt -re configs-npb-gapbs/npb_checkpoint.py bt C RambusTagProbOpt 0 0 + 302 build/X86_MESI_Two_Level/gem5.opt -re configs-npb-gapbs/npb_checkpoint.py bt C RambusTagProbOpt 0 0 + 303 gdb --args build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/npb_checkpoint.py bt C RambusTagProbOpt 0 0 + 304 du -hs /home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/chkpt1GigDC/1GB_8GB_g22_nC_1halfSec + 305 du -hs /home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/chkpt1GigDC/1GB_85GB_g25_nD_1halfSec/ + 306 clear + 307 du -hs /home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/chkpt1GigDC/chkpts1GBDC.zip + 308 cd /home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/chkpt1GigDC + 309 clear + 310 zip -r chkpts1GBDC.zip 1GB_8GB_g22_nC_1halfSec/ 1GB_85GB_g25_nD_1halfSec/ + 311 du -hs 1GB_8GB_g22_nC_1halfSec/ + 312 du -hs 1GB_85GB_g25_nD_1halfSec/ + 313 screen -ls + 314 sudo apt install screen + 315 clear + 316 screen -ls + 317 screen -S zipTest + 318 chmod 777 checkpoints_backup/ + 319 sudo chmod 777 checkpoints_backup/ + 320 sudo chmod 777 checkpoints_backup/ + 321 sudo nautilus + 322 du -hs GAPBS/ + 323 du -hs NPB/ + 324 cd ../ + 325 ls + 326 ls -hs 1GB_85GB_g25_nD_1halfSec/ + 327 du -hs 1GB_85GB_g25_nD_1halfSec/ + 328 cd 1GB_85GB_g25_nD_1halfSec/ + 329 du -hs NPB/ + 330 du -hs GAPBS/ + 331 sudo cp -r /home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/chkpt1GigDC/1GB_8GB_g22_nC_1halfSec/ . + 332 cd /home/babaie/projects/rambusDesign/1gigDRAMCache/ + 333 ls + 334 cd dramCacheController/chkpt1GigDC/ + 335 ls + 336 sudo nautilus + 337 sudo nautilus + 338 sudo nautilus + 339 sudo nautilus + 340 chmod 777 checkpoints_backup/ + 341 sudo chmod 777 checkpoints_backup/ + 342 lsblk + 343 sudo smartctl -i /dev/sda + 344 wget https://download.teamviewer.com/download/linux/teamviewer_amd64.deb + 345 sudo apt install ./teamviewer_amd64.deb + 346 sudo gedit custom.conf + 347 htop + 348 sudo snap install htop + 349 htop + 350 sudo chmod 777 checkpoints_backup/ + 351 sudo apt install ./google-chrome-stable_current_amd64.deb + 352 cd ../../ + 353 TDRAM-reproduction + 354 mkdir TDRAM-reproduction + 355 cd TDRAM-reproduction/ + 356 git clone https://github.com/darchr/dramCacheController.git + 357 cd dramCacheController/ + 358 git checkout set_associative_backup2 + 359 /bin/python3 /home/babaie/time.py + 360 /bin/python3 /home/babaie/time.py + 361 /bin/python3 /home/babaie/time.py + 362 top + 363 top + 364 ./realAppRun.sh + 365 ./realAppRun.sh + 366 clear + 367 ./realAppRun.sh + 368 ./realAppRun.sh + 369 clear + 370 ./realAppRun.sh + 371 clear + 372 ./realAppRun.sh + 373 ./realAppRun.sh + 374 clear + 375 ./realAppRun.sh + 376 clear + 377 ./realAppRun.sh + 378 clear + 379 cd /home/babaie/projects/rambusDesign/tagProbOptRealImplOnSetAssoBranch/dramCacheController + 380 clear + 381 ./realAppRun.sh + 382 clear + 383 ./realAppRun.sh + 384 clear + 385 ./realAppRun.sh + 386 clear + 387 ./realAppRun.sh + 388 clear + 389 ./realAppRun.sh + 390 cd 1gigDRAMCache/dramCacheController/ + 391 clear + 392 ./realAppRun.sh + 393 clear + 394 build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/rambusTagPr/1GB_8GB_g22_nC/GAPBS/bfs configs-npb-gapbs/restore_both.py bfs-22 RambusTagProbOpt 1 0 0 0 & + 395 q + 396 clear + 397 pkill gem5 + 398 clear + 399 build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/rambusTagPr/1GB_8GB_g22_nC/NPB/bt --debug-flags=DRAM,MemCtrl,PolicyManager configs-npb-gapbs/restore_both.py bt.C.x RambusTagProbOpt 1 0 0 0 + 400 clear + 401 clear + 402 ./realAppRun.sh + 403 clear + 404 ./realAppRun.sh + 405 git status + 406 clear + 407 ./realAppRun.sh + 408 clear + 409 ./realAppRun.sh + 410 clear + 411 ./realAppRun.sh + 412 clear + 413 ./realAppRun.sh + 414 clear + 415 ./realAppRun.sh + 416 screen -d + 417 screen -d + 418 build/X86_MESI_Two_Level/gem5.opt -re --outdir=m5out/1GB_85GB_g25_nD/NPB/bt configs-npb-gapbs/restore_both.py bt.D.x RambusTagProbOpt 1 1 1250 0 7.5ns + 419 build/X86_MESI_Two_Level/gem5.opt -re --outdir=m5out/1GB_85GB_g25_nD/NPB/bt configs-npb-gapbs/restore_both.py bt.D.x RambusTagProbOpt 1 1 1250 0 7.5ns + 420 ./realAppRun.sh + 421 screen -ls + 422 killall screen + 423 screen -S pc6hour + 424 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc + 425 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmallocbuild/X86_MESI_Two_Level/gem5.opt -re --outdir=pcAnalysis/6hour_1halfChkpt/1GB_8GB_g22_nC/NPB/ft configs-npb-gapbs/restore_both.py ft.C.x CascadeLakeNoPartWrs 1 0 0 0 + 426 ls build/X86_MESI_Two_Level/ + 427 build/X86_MESI_Two_Level/gem5.opt -re --outdir=pcAnalysis/6hour_1halfChkpt/1GB_8GB_g22_nC/NPB/ft configs-npb-gapbs/restore_both.py ft.C.x CascadeLakeNoPartWrs 1 0 0 0 + 428 rm -r build/ + 429 top + 430 top + 431 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc + 432 screen -ls + 433 killall screen + 434 screen -S pc6hour + 435 top + 436 pkill gem5 + 437 top + 438 pkill gem5 + 439 screen -r pc6hour + 440 top + 441 to -u babaie + 442 top -u babaie + 443 cd pcAnalysis/ + 444 clear grep -r "Done with interval" | tail -1 + 445 clear grep "Done with interval" | tail -1 + 446 grep -r "Done with interval" | tail -1 + 447 grep -Irn "Done with interval" | tail -1 + 462 cd codeReview/dramCacheController/ + 463 git status + 464 git diff + 465 git pull + 466 git stash + 467 git pull + 468 git status + 469 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc + 470 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x RambusTagProbOpt 0 0 0 + 471 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x RambusTagProbOpt 1 0 0 0 + 472 pkill gem5 + 473 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x Rambus 1 0 0 0 + 474 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc + 475 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x Rambus 1 0 0 0 + 476 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc + 477 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc + 478 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x Rambus 1 0 0 0 + 479 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc + 480 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x Rambus 1 0 0 0 + 481 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc + 482 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc + 483 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc + 484 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x Rambus 1 0 0 0 + 485 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc + 486 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x Rambus 1 0 0 0 + 487 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc + 488 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x Rambus 1 0 0 0 + 489 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc + 490 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x Rambus 1 0 0 0 + 491 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x CascadeLakeNoPartWrs 1 0 0 0 + 492 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x Oracle 1 0 0 0 + 493 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py mg.C.x RambusTagProbOpt 0 0 0 + 494 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py mg.C.x RambusTagProbOpt 1 0 0 0 + 495 git status + 496 cd ../../gem5-23/dramCacheController/ + 497 git status + 498 ls + 499 cd ../../gem5-dev/ + 500 cd ../../ + 501 cd ../../ + 502 cd gem5-dev/ + 503 ls + 504 cd dev23/dramCacheController/ + 505 git status + 506 git pull + 507 cd ../../ + 508 ls + 509 git clone https://github.com/gem5/gem5.git + 510 cd gem5/ + 511 git checkout develop + 512 cd ../../ + 513 mkdir dc-gem5-dev-fork + 514 cd dc-gem5-dev-fork/ + 515 git clone https://github.com/darchr/dramCacheController.git + 516 cd dramCacheController/ + 517 git remote add fork https://github.com/gem5/gem5.git + 518 git fetch fork develop + 519 git checkout -b gem5-develop fork/develop + 520 git push + 521 git status + 522 tig + 523 apt install tig + 524 git status + 525 git remote -v + 526 git push origin gem5-develop:gem5-develop + 527 history -3000 > cmd.txt + 528 history 3000 > cmd.txt From 344160fbd42bc6a94965d14e140a9e41abbbbf0e Mon Sep 17 00:00:00 2001 From: mbabaie Date: Tue, 3 Oct 2023 15:09:32 -0700 Subject: [PATCH 03/28] tested fs --- Methodology.md | 31 - Octopi-cache/components/Octopi.py | 162 - Octopi-cache/components/__init__.py | 0 Octopi-cache/components/core_complex.py | 192 -- Octopi-cache/components/octopi_network.py | 34 - .../components/ruby_network_components.py | 71 - ...v-2channel-1ccd-checkpoint-timing-gapbs.py | 162 - ...v-2channel-1ccd-checkpoint-timing-npb-c.py | 164 - .../riscv-2channel-1ccd-checkpoint-timing.py | 162 - .../riscv-2channel-1ccd-checkpoint.py | 148 - ...iscv-2channel-1ccd-restore-timing-gapbs.py | 160 - .../old-run-scripts/riscv-2channel-1ccd.py | 101 - Octopi-cache/restore-npb-gapbs-looppoint.py | 259 -- Octopi-cache/riscv-hpc.py | 87 - cmd.txt | 486 --- cold-miss-check-plots.ipynb | 466 --- configs-npb-gapbs/gapbs_restore.py | 179 - configs-npb-gapbs/npb_restore.py | 222 -- configs-npb-gapbs/restore_both.py | 6 +- configs-npb-gapbs/system/ruby_system.py | 294 -- data-plots.ipynb | 2874 ----------------- data_plot_compare_hours.ipynb | 772 ----- defMemCtrlr.py | 77 - dr_trace_player.py | 78 - dr_trace_player_core.py | 72 - drtrace-stdlib.py | 109 - gapbs_checkpoint.sh | 22 - gapbs_run.sh | 22 - googleTracesRun.sh | 4 - link.ipynb | 1604 --------- missRatio_swe.py | 136 - npb_checkpoint.sh | 22 - npb_checkpoint_c_class.sh | 22 - npb_run.sh | 22 - npb_run_c.sh | 22 - plots_1GBdramCache/data-plots.ipynb | 1331 -------- realAppRun.sh | 32 - set-associative-data-plots.ipynb | 513 --- src/mem/nvm_interface.cc | 4 +- traffGen_def.py | 131 - traffGen_mem.py | 88 - 41 files changed, 5 insertions(+), 11338 deletions(-) delete mode 100644 Methodology.md delete mode 100644 Octopi-cache/components/Octopi.py delete mode 100644 Octopi-cache/components/__init__.py delete mode 100644 Octopi-cache/components/core_complex.py delete mode 100644 Octopi-cache/components/octopi_network.py delete mode 100644 Octopi-cache/components/ruby_network_components.py delete mode 100644 Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing-gapbs.py delete mode 100644 Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing-npb-c.py delete mode 100644 Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing.py delete mode 100644 Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint.py delete mode 100644 Octopi-cache/old-run-scripts/riscv-2channel-1ccd-restore-timing-gapbs.py delete mode 100644 Octopi-cache/old-run-scripts/riscv-2channel-1ccd.py delete mode 100644 Octopi-cache/restore-npb-gapbs-looppoint.py delete mode 100644 Octopi-cache/riscv-hpc.py delete mode 100644 cmd.txt delete mode 100644 cold-miss-check-plots.ipynb delete mode 100755 configs-npb-gapbs/gapbs_restore.py delete mode 100755 configs-npb-gapbs/npb_restore.py delete mode 100755 configs-npb-gapbs/system/ruby_system.py delete mode 100644 data-plots.ipynb delete mode 100644 data_plot_compare_hours.ipynb delete mode 100644 defMemCtrlr.py delete mode 100644 dr_trace_player.py delete mode 100644 dr_trace_player_core.py delete mode 100644 drtrace-stdlib.py delete mode 100755 gapbs_checkpoint.sh delete mode 100755 gapbs_run.sh delete mode 100755 googleTracesRun.sh delete mode 100644 link.ipynb delete mode 100644 missRatio_swe.py delete mode 100755 npb_checkpoint.sh delete mode 100755 npb_checkpoint_c_class.sh delete mode 100755 npb_run.sh delete mode 100755 npb_run_c.sh delete mode 100644 plots_1GBdramCache/data-plots.ipynb delete mode 100755 realAppRun.sh delete mode 100644 set-associative-data-plots.ipynb delete mode 100644 traffGen_def.py delete mode 100644 traffGen_mem.py diff --git a/Methodology.md b/Methodology.md deleted file mode 100644 index 740fddb1fc..0000000000 --- a/Methodology.md +++ /dev/null @@ -1,31 +0,0 @@ -# Documentation on the methodology work for DRAM cache experiments - -This is not a very detailed or formal document, but tries to at least point to -the relevant links or paths and important notes. - -- DRAM cache component is part of the stdlib in this repo ("src/python/gem5/components/memory/dcache.py"). -- Octopi-cache is a three level MESI cache hiearchy - - -## gem5 scripts used to take checkpoints - -- **NPB D Class:** Octopi-cache/riscv-2channel-1ccd-checkpoint-timing.py - -- **NPB C Class:** ctopi-cache/riscv-2channel-1ccd-checkpoint-timing.py - -- **GAPBS (2^25 vertices):** Octopi-cache/riscv-2channel-1ccd-checkpoint-timing-gapbs.py - - -## Bash scripts used (will show the directory where the checkpoints and results are) - -- **NPB:** `npb_checkpoint.sh` and `npb_checkpoint_c_class.sh` -- **GAPBS:** `gapbs_checkpoint.sh` - -The gem5 directory I have been using is here: `/home/aakahlow/Dcache_Src/dramCacheController`. -D Class and GAPBS checkpoints will go there. The C class checkpoints will be stored in /projects (exact path in the npb_checkpoint_c_class.sh script). - -## Looppoint stuff - -- The branch with O3 loop point analysis stuff: https://github.com/darchr/gem5/commits/looppointAnalysis-Ayaz -- example.py script in the above branch is a modified version of Zhantong's example script to use looppoint analysis probe and print most recent PC + count. - diff --git a/Octopi-cache/components/Octopi.py b/Octopi-cache/components/Octopi.py deleted file mode 100644 index 91d72e69e4..0000000000 --- a/Octopi-cache/components/Octopi.py +++ /dev/null @@ -1,162 +0,0 @@ -from gem5.components.cachehierarchies.ruby.abstract_ruby_cache_hierarchy import AbstractRubyCacheHierarchy -from gem5.components.cachehierarchies.abstract_three_level_cache_hierarchy import ( - AbstractThreeLevelCacheHierarchy, -) -from gem5.coherence_protocol import CoherenceProtocol -from gem5.isas import ISA -from gem5.components.boards.abstract_board import AbstractBoard -from gem5.utils.requires import requires - -from gem5.components.cachehierarchies.ruby.caches.mesi_three_level.directory import Directory -from gem5.components.cachehierarchies.ruby.caches.mesi_three_level.dma_controller import DMAController - -from m5.objects import RubySystem, DMASequencer, RubyPortProxy, SimpleMemory, AddrRange - -from .core_complex import CoreComplex -from .octopi_network import OctopiNetwork -from .ruby_network_components import RubyNetworkComponent, RubyRouter, RubyExtLink, RubyIntLink - -# CoreComplex sub-systems own the L1, L2, L3 controllers -# OctopiCache owns the directory controllers -# RubySystem owns the DMA Controllers -class OctopiCache(AbstractRubyCacheHierarchy, AbstractThreeLevelCacheHierarchy): - def __init__( - self, - l1i_size: str, - l1i_assoc: int, - l1d_size: str, - l1d_assoc: int, - l2_size: str, - l2_assoc: int, - l3_size: str, - l3_assoc: int, - num_core_complexes: int, - is_fullsystem: bool - ): - AbstractRubyCacheHierarchy.__init__(self=self) - AbstractThreeLevelCacheHierarchy.__init__( - self=self, - l1i_size=l1i_size, - l1i_assoc=l1i_assoc, - l1d_size=l1d_size, - l1d_assoc=l1d_assoc, - l2_size=l2_size, - l2_assoc=l2_assoc, - l3_size=l3_size, - l3_assoc=l3_assoc, - ) - - self._directory_controllers = [] - self._dma_controllers = [] - self._io_controllers = [] - self._core_complexes = [] - self._num_core_complexes = num_core_complexes - self._is_fullsystem = is_fullsystem - - def incorporate_cache(self, board: AbstractBoard) -> None: - - requires( - coherence_protocol_required=CoherenceProtocol.MESI_THREE_LEVEL - ) - - cache_line_size = board.get_cache_line_size() - - self.ruby_system = RubySystem() - # MESI_Three_Level needs 3 virtual networks - self.ruby_system.number_of_virtual_networks = 3 - self.ruby_system.network = OctopiNetwork(self.ruby_system) - self.ruby_system.access_backing_store = True - - # Get the first range and the range part. - addr_range_0 = board.get_mem_ports()[0][0] - self.ruby_system.phys_mem = SimpleMemory( - range=AddrRange(start=addr_range_0.start, - end=addr_range_0.end), - in_addr_map=False) - - # Setting up the core complex - all_cores = board.get_processor().get_cores() - num_cores_per_core_complex = len(all_cores) // self._num_core_complexes - - self.core_complexes = [CoreComplex( - board = board, - cores = all_cores[core_complex_idx*num_cores_per_core_complex:(core_complex_idx + 1) * num_cores_per_core_complex], - ruby_system = self.ruby_system, - l1i_size = self._l1i_size, - l1i_assoc = self._l1i_assoc, - l1d_size = self._l1d_size, - l1d_assoc = self._l1d_assoc, - l2_size = self._l2_size, - l2_assoc = self._l2_assoc, - l3_size = self._l3_size, - l3_assoc = self._l3_assoc, - ) for core_complex_idx in range(self._num_core_complexes)] - - self.ruby_system.network.incorporate_ccds(self.core_complexes) - - self._create_directory_controllers(board) - self._create_dma_controllers(board, self.ruby_system) - - self.ruby_system.num_of_sequencers = len(all_cores) + len(self._dma_controllers) + len(self._io_controllers) - # SimpleNetwork requires .int_links and .routers to exist - # if we want to call SimpleNetwork.setup_buffers() - self.ruby_system.network.int_links = self.ruby_system.network._int_links - self.ruby_system.network.ext_links = self.ruby_system.network._ext_links - self.ruby_system.network.routers = self.ruby_system.network._routers - self.ruby_system.network.setup_buffers() - - # Set up a proxy port for the system_port. Used for load binaries and - # other functional-only things. - self.ruby_system.sys_port_proxy = RubyPortProxy() - board.connect_system_port(self.ruby_system.sys_port_proxy.in_ports) - - def _create_directory_controllers(self, board): - # Adding controllers - self.directory_controllers = [Directory( - self.ruby_system.network, board.get_cache_line_size(), addr_range, mem_port - ) for addr_range, mem_port in board.get_mem_ports() - ] - for ctrl in self.directory_controllers: - ctrl.ruby_system = self.ruby_system - # Adding controller routers - self.directory_controller_routers = [RubyRouter(self.ruby_system.network) for _ in range(len(self.directory_controllers))] - for router in self.directory_controller_routers: - self.ruby_system.network._add_router(router) - # Adding an external link for each controller and its router - self.directory_controller_ext_links = [RubyExtLink(ext_node=dir_ctrl, int_node=dir_router) for dir_ctrl, dir_router in zip(self.directory_controllers, self.directory_controller_routers)] - for ext_link in self.directory_controller_ext_links: - self.ruby_system.network._add_ext_link(ext_link) - _directory_controller_int_links = [] - for router in self.directory_controller_routers: - int_link_1, int_link_2 = RubyIntLink.create_bidirectional_links(router, self.ruby_system.network.cross_ccd_router) - _directory_controller_int_links.extend([int_link_1, int_link_2]) - self.ruby_system.network._add_int_link(int_link_1) - self.ruby_system.network._add_int_link(int_link_2) - self.directory_controller_int_links = _directory_controller_int_links - - def _create_dma_controllers(self, board, ruby_system): - # IOController for full system simulation - if self._is_fullsystem: - self.io_sequencer = DMASequencer(version=0, ruby_system=self.ruby_system) - self.io_sequencer.in_ports = board.get_mem_side_coherent_io_port() - self.ruby_system.io_controller = DMAController( - dma_sequencer=self.io_sequencer, - ruby_system=self.ruby_system - ) - self._io_controllers.append(self.ruby_system.io_controller) - self.io_controller_router = RubyRouter(self.ruby_system.network) - self.ruby_system.network._add_router(self.io_controller_router) - self.io_controller_ext_link = RubyExtLink(ext_node=self._io_controllers[0], int_node=self.io_controller_router) - self.ruby_system.network._add_ext_link(self.io_controller_ext_link) - self.io_controller_int_links = RubyIntLink.create_bidirectional_links(self.io_controller_router, self.ruby_system.network.cross_ccd_router) - self.ruby_system.network._add_int_link(self.io_controller_int_links[0]) - self.ruby_system.network._add_int_link(self.io_controller_int_links[1]) - - self._dma_controllers = [] - if board.has_dma_ports(): - for i, port in enumerate(dma_ports): - ctrl = DMAController(self.ruby_system.network, cache_line_size) - ctrl.dma_sequencer = DMASequencer(version=i+1, in_ports=port) - self._dma_controllers.append(ctrl) - ctrl.ruby_system = self.ruby_system - ruby_system.dma_controllers = self._dma_controllers diff --git a/Octopi-cache/components/__init__.py b/Octopi-cache/components/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Octopi-cache/components/core_complex.py b/Octopi-cache/components/core_complex.py deleted file mode 100644 index 877e219d1e..0000000000 --- a/Octopi-cache/components/core_complex.py +++ /dev/null @@ -1,192 +0,0 @@ -from typing import List, Tuple - -from gem5.isas import ISA -from gem5.components.boards.abstract_board import AbstractBoard -from gem5.components.processors.abstract_core import AbstractCore -from gem5.components.cachehierarchies.abstract_three_level_cache_hierarchy import ( - AbstractThreeLevelCacheHierarchy, -) -from gem5.components.cachehierarchies.ruby.caches.mesi_three_level.l1_cache import L1Cache -from gem5.components.cachehierarchies.ruby.caches.mesi_three_level.l2_cache import L2Cache -from gem5.components.cachehierarchies.ruby.caches.mesi_three_level.l3_cache import L3Cache -from gem5.components.cachehierarchies.ruby.caches.mesi_three_level.directory import Directory - -from m5.objects import SubSystem, L2Cache_Controller, AddrRange, RubySequencer, Switch, SimpleIntLink, SimpleExtLink, SubSystem, SimObject - -from .ruby_network_components import RubyRouter, RubyExtLink, RubyIntLink, RubyNetworkComponent - -class CoreComplex(SubSystem, RubyNetworkComponent): - _core_id = 0 - _core_complex_id = 0 - - @classmethod - def _get_core_id(cls): - cls._core_id += 1 - return cls._core_id - 1 - - @classmethod - def _get_core_complex_id(cls): - cls._core_complex_id += 1 - return cls._core_complex_id - 1 - - def __init__( - self, - board: AbstractBoard, - cores: List[AbstractCore], - ruby_system, - l1i_size: str, - l1i_assoc: int, - l1d_size: str, - l1d_assoc: int, - l2_size: str, - l2_assoc: int, - l3_size: str, - l3_assoc: int, - ): - SubSystem.__init__(self=self) - RubyNetworkComponent.__init__(self=self) - - self._l1i_size = l1i_size - self._l1i_assoc = l1i_assoc - self._l1d_size = l1d_size - self._l1d_assoc = l1d_assoc - self._l2_size = l2_size - self._l2_assoc = l2_assoc - self._l3_size = l3_size - self._l3_assoc = l3_assoc - - self._board = board - self._cores = cores - self._ruby_system = ruby_system - self._cache_line_size = 64 - - self._directory_controllers = [] - - self._core_complex_id = self._get_core_complex_id() - self.main_router = RubyRouter(self._ruby_system) # this will be connect to component outside the core complex - self._add_router(self.main_router) - self._create_core_complex() - - def get_main_router(self): - return self.main_router - - def _create_core_complex(self): - # Create L1 caches, L2 cache, and corresponding controllers per core - self.core_clusters = [self._create_core_cluster(core) for core in self._cores] - # Create L3 cache and its corresponding controller - self._create_shared_cache() - # Setting up one router and one external link per controller - self._create_external_links() - # Setting up L1/L2 links, L2/main links, L3/main link - self._create_internal_links() - - def _create_core_cluster(self, core: AbstractCore): - cluster = SubSystem() - core_id = self._get_core_id() - - cluster.l1_cache = L1Cache( - l1i_size = self._l1i_size, - l1i_assoc = self._l1i_assoc, - l1d_size = self._l1d_size, - l1d_assoc = self._l1d_assoc, - network = self._ruby_system.network, - core = core, - cache_line_size = self._cache_line_size, - target_isa = self._board.processor.get_isa(), - clk_domain = self._board.get_clock_domain(), - ) - cluster.l1_cache.sequencer = RubySequencer( - version = core_id, - dcache = cluster.l1_cache.Dcache, - clk_domain = cluster.l1_cache.clk_domain - ) - - if self._board.has_io_bus(): - cluster.l1_cache.sequencer.connectIOPorts(self._board.get_io_bus()) - cluster.l1_cache.ruby_system = self._ruby_system - core.connect_icache(cluster.l1_cache.sequencer.in_ports) - core.connect_dcache(cluster.l1_cache.sequencer.in_ports) - core.connect_walker_ports( - cluster.l1_cache.sequencer.in_ports, cluster.l1_cache.sequencer.in_ports - ) - if self._board.get_processor().get_isa() == ISA.X86: - core.connect_interrupt( - cluster.l1_cache.sequencer.interrupt_out_port, - cluster.l1_cache.sequencer.in_ports - ) - else: - core.connect_interrupt() - - cluster.l2_cache = L2Cache( - l2_size=self._l2_size, - l2_assoc=self._l2_assoc, - network=self._ruby_system.network, - core=core, - num_l3Caches=1, # each core complex has 1 slice of L3 Cache - cache_line_size=self._cache_line_size, - cluster_id=self._core_complex_id, - target_isa=self._board.processor.get_isa(), - clk_domain=self._board.get_clock_domain(), - ) - cluster.l2_cache.ruby_system = self._ruby_system - # L0Cache in the ruby backend is l1 cache in stdlib - # L1Cache in the ruby backend is l2 cache in stdlib - cluster.l2_cache.bufferFromL0 = cluster.l1_cache.bufferToL1 - cluster.l2_cache.bufferToL0 = cluster.l1_cache.bufferFromL1 - - return cluster - - def _create_shared_cache(self): - self.l3_cache = L3Cache( - l3_size=self._l3_size, - l3_assoc=self._l3_assoc, - network=self._ruby_system.network, - num_l3Caches=1, - cache_line_size=self._cache_line_size, - cluster_id=self._core_complex_id, - ) - self.l3_cache.ruby_system = self._ruby_system - - # This is where all routers and links are created - def _create_external_links(self): - # create a router per cache controller - # - there is one L3 per ccd - self.l3_router = RubyRouter(self._ruby_system) - self._add_router(self.l3_router) - # - there is one L1 and one L2 per cluster - for cluster in self.core_clusters: - cluster.l1_router = RubyRouter(self._ruby_system) - self._add_router(cluster.l1_router) - cluster.l2_router = RubyRouter(self._ruby_system) - self._add_router(cluster.l2_router) - - # create an ext link from a controller to a router - self.l3_router_link = RubyExtLink(ext_node=self.l3_cache, int_node=self.l3_router, bandwidth_factor=64) - self._add_ext_link(self.l3_router_link) - for cluster in self.core_clusters: - cluster.l1_router_link = RubyExtLink(ext_node=cluster.l1_cache, int_node=cluster.l1_router) - self._add_ext_link(cluster.l1_router_link) - cluster.l2_router_link = RubyExtLink(ext_node=cluster.l2_cache, int_node=cluster.l2_router) - self._add_ext_link(cluster.l2_router_link) - - def _create_internal_links(self): - # create L1/L2 links - for cluster in self.core_clusters: - l1_to_l2, l2_to_l1 = RubyIntLink.create_bidirectional_links(cluster.l1_router, cluster.l2_router) - cluster.l1_to_l2_link = l1_to_l2 - cluster.l2_to_l1_link = l2_to_l1 - self._add_int_link(l1_to_l2) - self._add_int_link(l2_to_l1) - # create L2/main_router links - for cluster in self.core_clusters: - l2_to_main, main_to_l2 = RubyIntLink.create_bidirectional_links(cluster.l2_router, self.main_router) - cluster.l2_to_main_link = l2_to_main - cluster.main_to_l2_link = main_to_l2 - self._add_int_link(l2_to_main) - self._add_int_link(main_to_l2) - # create L3/main_router link - l3_to_main, main_to_l3 = RubyIntLink.create_bidirectional_links(self.l3_router, self.main_router, bandwidth_factor=64) - self.l3_to_main_link = l3_to_main - self.main_to_l3_link = main_to_l3 - self._add_int_link(l3_to_main) - self._add_int_link(main_to_l3) diff --git a/Octopi-cache/components/octopi_network.py b/Octopi-cache/components/octopi_network.py deleted file mode 100644 index 5b1ab1b9bc..0000000000 --- a/Octopi-cache/components/octopi_network.py +++ /dev/null @@ -1,34 +0,0 @@ -from .ruby_network_components import RubyNetworkComponent, RubyExtLink, RubyIntLink, RubyRouter - -from m5.objects import SimpleNetwork - -# . The Network owns all routers, all int links and all ext links that are not in CCD's. -# . The CCD subsystems are not of type RubyNetwork, so we need to copy the references of -# routers and links to OctopiNetwork._routers, ._int_links, and ._ext_links; which will -# be, in turns, copied to RubyNetwork.routers, .int_links, and .ext_links respectively. -# -# Terms: "connect" -> create int links -# "incorporate" -> copy references of routers and links, create routers/links if necessary -class OctopiNetwork(SimpleNetwork, RubyNetworkComponent): - def __init__(self, ruby_system): - SimpleNetwork.__init__(self=self) - RubyNetworkComponent.__init__(self=self) - self.netifs = [] - self.ruby_system = ruby_system - self.number_of_virtual_networks = ruby_system.number_of_virtual_networks - - self.cross_ccd_router = RubyRouter(self) - self._add_router(self.cross_ccd_router) - - def connect_ccd_routers_to_cross_ccd_router(self, ccds): - for ccd in ccds: - int_link_1, int_link_2 = RubyIntLink.create_bidirectional_links(self.cross_ccd_router, ccd.get_main_router(), bandwidth_factor=64) - ccd.to_cross_ccd_router_link = int_link_1 - ccd.from_cross_ccd_router_link = int_link_2 - self._add_int_link(int_link_1) - self._add_int_link(int_link_2) - - def incorporate_ccds(self, ccds): - for ccd in ccds: - self.incorporate_ruby_subsystem(ccd) - self.connect_ccd_routers_to_cross_ccd_router(ccds) diff --git a/Octopi-cache/components/ruby_network_components.py b/Octopi-cache/components/ruby_network_components.py deleted file mode 100644 index 6e9b2d4abc..0000000000 --- a/Octopi-cache/components/ruby_network_components.py +++ /dev/null @@ -1,71 +0,0 @@ -from m5.objects import Switch, SimpleIntLink, SimpleExtLink - -class RubyNetworkComponent(): - def __init__(self): - super().__init__() - self._routers = [] - self._ext_links = [] - self._int_links = [] - def _add_router(self, router): - self._routers.append(router) - def _add_ext_link(self, link): - self._ext_links.append(link) - def _add_int_link(self, link): - self._int_links.append(link) - def get_routers(self): - return self._routers - def get_ext_links(self): - return self._ext_links - def get_int_links(self): - return self._int_links - def incorporate_ruby_subsystem(self, other_ruby_subsystem): - self._routers.extend(other_ruby_subsystem.get_routers()) - self._ext_links.extend(other_ruby_subsystem.get_ext_links()) - self._int_links.extend(other_ruby_subsystem.get_int_links()) - -class RubyRouter(Switch): - _router_id = 0 - - @classmethod - def _get_router_id(cls): - cls._router_id += 1 - return cls._router_id - 1 - - def __init__(self, network): - super().__init__() - self.router_id = self._get_router_id() - self.virt_nets = network.number_of_virtual_networks - -class RubyExtLink(SimpleExtLink): - _link_id = 0 - - @classmethod - def _get_link_id(cls): - cls._link_id += 1 - return cls._link_id - 1 - - def __init__(self, ext_node, int_node, bandwidth_factor=16): - super().__init__() - self.link_id = self._get_link_id() - self.ext_node = ext_node - self.int_node = int_node - self.bandwidth_factor = bandwidth_factor - -class RubyIntLink(SimpleIntLink): - _link_id = 0 - - @classmethod - def _get_link_id(cls): - cls._link_id += 1 - return cls._link_id - 1 - - @classmethod - def create_bidirectional_links(cls, node_1, node_2, bandwidth_factor=16): - return [RubyIntLink(node_1, node_2, bandwidth_factor), RubyIntLink(node_2, node_1, bandwidth_factor)] - - def __init__(self, src_node, dst_node, bandwidth_factor=16): - super().__init__() - self.link_id = self._get_link_id() - self.src_node = src_node - self.dst_node = dst_node - self.bandwidth_factor = bandwidth_factor diff --git a/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing-gapbs.py b/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing-gapbs.py deleted file mode 100644 index f944b288db..0000000000 --- a/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing-gapbs.py +++ /dev/null @@ -1,162 +0,0 @@ -from gem5.components.boards.riscv_board import RiscvBoard -from gem5.components.memory.memory import ChanneledMemory -from gem5.components.processors.simple_processor import SimpleProcessor -from gem5.components.processors.cpu_types import CPUTypes -from gem5.isas import ISA -from gem5.utils.requires import requires -from gem5.utils.override import overrides -from gem5.resources.resource import Resource, DiskImageResource -from gem5.simulate.simulator import Simulator -from gem5.components.processors.simple_switchable_processor import ( - SimpleSwitchableProcessor, -) -from gem5.components.memory import CascadeLakeCache, OracleCache, RamCache -from gem5.simulate.simulator import ExitEvent -import m5 -from components.Octopi import OctopiCache - -# Sample command to use this script -# build/RISCV/gem5.opt --outdir=bfs.25 riscv-2channel-1ccd-checkpoint.py -# --benchmark bfs --size 25 --ckpt_path checkpoints-gapbs/bfs.25.ckpt/ -# - -requires(isa_required=ISA.RISCV) - -import argparse -parser = argparse.ArgumentParser() -parser.add_argument("--benchmark", type=str) -parser.add_argument("--size", type=str) -parser.add_argument("--ckpt_path", type=str) - -args = parser.parse_args() - -num_ccds = 1 -num_cores = 8 -command = f"/home/ubuntu/gapbs/{args.benchmark} -g {args.size};" - -cache_hierarchy = OctopiCache( - l1i_size = "32KiB", - l1i_assoc = 8, - l1d_size = "32KiB", - l1d_assoc = 8, - l2_size = "512KiB", - l2_assoc = 8, - l3_size = "32MiB", - l3_assoc = 16, - num_core_complexes = 1, - is_fullsystem = True, -) -memory = RamCache() - -processor = SwitchableProcessor( - starting_core_type=CPUTypes.TIMING, - switch_core_type=CPUTypes.TIMING, # TODO - isa=ISA.RISCV, - num_cores=num_cores -) - -class HighPerformanceRiscvBoard(RiscvBoard): - @overrides(RiscvBoard) - def get_default_kernel_args(self): - return [ - "earlyprintk=ttyS0", - "console=ttyS0", - "lpj=7999923", - "root=/dev/vda1", - "init=/root/init.sh", - "rw", - ] - -# Setup the board. -board = HighPerformanceRiscvBoard( - clk_freq="4GHz", - processor=processor, - memory=memory, - cache_hierarchy=cache_hierarchy, -) - -# Set the Full System workload. -board.set_kernel_disk_workload( - kernel=Resource("riscv-bootloader-vmlinux-5.10"), - disk_image=DiskImageResource( - "/projects/gem5/npb-gapbs-riscv.img", root_partition="1" - ), - readfile_contents=f"{command}" -) - -# The first exit_event ends with a `workbegin` cause. This means that the -# system started successfully and the execution on the program started. -def handle_workbegin(): - print("Done booting Linux") - print("Resetting stats at the start of ROI!") - - m5.stats.dump() - m5.stats.reset() - - # switch the processor to timing CPU for warmup - print("Switching the CPU") - processor.switch() - # schedule an exit event for 1 second. - m5.scheduleTickExitFromCurrent(1000000000000) - yield False - -""" -def handle_cachewarmup(): - print("Cache warmed up as we reached : ") - print(simulator.get_last_exit_event_cause()) - print("Taking the checkpoint!") - - m5.stats.dump() - m5.stats.reset() - save_checkpoint() - yield True -""" -# Running things for 1sec and will -# not take ckpt if cache gets -# warmed up during Linux boot -def handle_cachewarmup(): - print("Cache warmed up as we reached : ") - print(simulator.get_last_exit_event_cause()) - print("Will continue simulation!") - - m5.stats.dump() - m5.stats.reset() - #save_checkpoint() - yield False - -def handle_schedtick(): - print("Cache warmed up as we reached : ") - print(simulator.get_last_exit_event_cause()) - print("Taking the checkpoint!") - - m5.stats.dump() - m5.stats.reset() - save_checkpoint() - yield True - -def handle_workend(): - print("Dump stats at the end of the ROI!") - - m5.stats.dump() - yield True - - -simulator = Simulator( - board=board, - on_exit_event={ - ExitEvent.WORKBEGIN: handle_workbegin(), - ExitEvent.WORKEND: handle_workend(), - ExitEvent.CACHE_WARMUP: handle_cachewarmup(), - ExitEvent.SCHEDULED_TICK: handle_schedtick(), - }, -) - -def save_checkpoint(): - simulator.save_checkpoint(args.ckpt_path) - - -print("Beginning simulation!") - -simulator.run() - -print("End of the simulation, we should have created a ckpt.") diff --git a/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing-npb-c.py b/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing-npb-c.py deleted file mode 100644 index 03d994a947..0000000000 --- a/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing-npb-c.py +++ /dev/null @@ -1,164 +0,0 @@ -from gem5.components.boards.riscv_board import RiscvBoard -from gem5.components.memory.memory import ChanneledMemory -from gem5.components.processors.simple_processor import SimpleProcessor -from gem5.components.processors.cpu_types import CPUTypes -from gem5.isas import ISA -from gem5.utils.requires import requires -from gem5.utils.override import overrides -from gem5.resources.resource import Resource, DiskImageResource -from gem5.simulate.simulator import Simulator -from gem5.components.processors.simple_switchable_processor import ( - SimpleSwitchableProcessor, -) -from gem5.components.memory import CascadeLakeCache, OracleCache, RamCache -from gem5.simulate.simulator import ExitEvent -import m5 -from components.Octopi import OctopiCache - -# Sample command to use this script -# build/RISCV/gem5.opt Octopi-cache/riscv-2channel-1ccd-checkpoint-timing-npb-c.py --benchmark bt --size C --ckpt_path test-dir/ - -requires(isa_required=ISA.RISCV) - -import argparse -parser = argparse.ArgumentParser() -parser.add_argument("--benchmark", type=str) -parser.add_argument("--size", type=str) -parser.add_argument("--ckpt_path", type=str) - -args = parser.parse_args() - -num_ccds = 1 -num_cores = 8 -command = f"/home/ubuntu/gem5-npb/NPB3.3-OMP/bin/{args.benchmark}.{args.size}.x;" - -cache_hierarchy = OctopiCache( - l1i_size = "32KiB", - l1i_assoc = 8, - l1d_size = "32KiB", - l1d_assoc = 8, - l2_size = "512KiB", - l2_assoc = 8, - l3_size = "32MiB", - l3_assoc = 16, - num_core_complexes = 1, - is_fullsystem = True, -) -memory = RamCache() - -processor = SimpleSwitchableProcessor( - starting_core_type=CPUTypes.TIMING, - switch_core_type=CPUTypes.TIMING, # TODO - isa=ISA.RISCV, - num_cores=num_cores -) - -class HighPerformanceRiscvBoard(RiscvBoard): - @overrides(RiscvBoard) - def get_default_kernel_args(self): - return [ - "earlyprintk=ttyS0", - "console=ttyS0", - "lpj=7999923", - "root=/dev/vda1", - "init=/root/init.sh", - "rw", - ] - -# Setup the board. -board = HighPerformanceRiscvBoard( - clk_freq="4GHz", - processor=processor, - memory=memory, - cache_hierarchy=cache_hierarchy, -) - -# Set the Full System workload. -board.set_kernel_disk_workload( - kernel=Resource("riscv-bootloader-vmlinux-5.10"), - disk_image=DiskImageResource( - "/projects/gem5/npb-gapbs-riscv.img", root_partition="1" - ), - readfile_contents=f"{command}" -) - -# The first exit_event ends with a `workbegin` cause. This means that the -# system started successfully and the execution on the program started. -def handle_workbegin(): - print("Done booting Linux") - print("Resetting stats at the start of ROI!") - - m5.stats.dump() - m5.stats.reset() - - # switch the processor to timing CPU for warmup - print("Switching the CPU") - processor.switch() - # schedule an exit event for 1 second. - m5.scheduleTickExitFromCurrent(1000000000000) - yield False - -# This event is scheduled every 100ms to get an -# update on the progress of the simulation itself -def handle_progress_update(): - - while True: - print("Simulated another 100ms") - - print( - f"Total sim time so far : {simulator.get_current_tick() / 1e12} sec" - ) - - m5.scheduleTickExitFromCurrent(100000000000, "progress_update") - yield False - -# Running things for 1sec and will -# not take ckpt if cache gets -# warmed up during Linux boot -def handle_cachewarmup(): - print("Cache warmed up as we reached : ") - print(simulator.get_last_exit_event_cause()) - print("Will continue simulation!") - - m5.stats.dump() - m5.stats.reset() - #save_checkpoint() - yield False - -def handle_schedtick(): - print("Going to take the ckpt because : ") - print(simulator.get_last_exit_event_cause()) - print("Taking the checkpoint!") - - m5.stats.dump() - m5.stats.reset() - save_checkpoint() - yield True - -def handle_workend(): - print("Dump stats at the end of the ROI!") - - m5.stats.dump() - yield True - - -simulator = Simulator( - board=board, - on_exit_event={ - ExitEvent.WORKBEGIN: handle_workbegin(), - ExitEvent.WORKEND: handle_workend(), - ExitEvent.CACHE_WARMUP: handle_cachewarmup(), - ExitEvent.SCHEDULED_TICK: handle_schedtick(), - #ExitEvent.SCHEDULED_TICK_PROGRESS: handle_progress_update(), - }, -) - -def save_checkpoint(): - simulator.save_checkpoint(args.ckpt_path) - -print("Beginning simulation!") - -#m5.scheduleTickExitFromCurrent(100000000000, "progress_update") -simulator.run() - -print("End of the simulation, we should have created a ckpt.") diff --git a/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing.py b/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing.py deleted file mode 100644 index 27391f4931..0000000000 --- a/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint-timing.py +++ /dev/null @@ -1,162 +0,0 @@ -from gem5.components.boards.riscv_board import RiscvBoard -from gem5.components.memory.memory import ChanneledMemory -from gem5.components.processors.simple_processor import SimpleProcessor -from gem5.components.processors.cpu_types import CPUTypes -from gem5.isas import ISA -from gem5.utils.requires import requires -from gem5.utils.override import overrides -from gem5.resources.resource import Resource, DiskImageResource -from gem5.simulate.simulator import Simulator -from gem5.components.processors.simple_switchable_processor import ( - SimpleSwitchableProcessor, -) -from gem5.components.memory import CascadeLakeCache, OracleCache, RamCache -from gem5.simulate.simulator import ExitEvent -import m5 -from components.Octopi import OctopiCache - -# Sample command to use this script -# build/RISCV/gem5.opt --outdir=bt.D riscv-2channel-1ccd-checkpoint.py -# --benchmark bt --size D --ckpt_path checkpoints-npb/bt.D.ckpt/ -# - -requires(isa_required=ISA.RISCV) - -import argparse -parser = argparse.ArgumentParser() -parser.add_argument("--benchmark", type=str) -parser.add_argument("--size", type=str) -parser.add_argument("--ckpt_path", type=str) - -args = parser.parse_args() - -num_ccds = 1 -num_cores = 8 -command = f"/home/ubuntu/gem5-npb/NPB3.3-OMP/bin/{args.benchmark}.{args.size}.x;" - -cache_hierarchy = OctopiCache( - l1i_size = "32KiB", - l1i_assoc = 8, - l1d_size = "32KiB", - l1d_assoc = 8, - l2_size = "512KiB", - l2_assoc = 8, - l3_size = "32MiB", - l3_assoc = 16, - num_core_complexes = 1, - is_fullsystem = True, -) -memory = RamCache() - -processor = SimpleSwitchableProcessor( - starting_core_type=CPUTypes.TIMING, - switch_core_type=CPUTypes.TIMING, # TODO - isa=ISA.RISCV, - num_cores=num_cores -) - -class HighPerformanceRiscvBoard(RiscvBoard): - @overrides(RiscvBoard) - def get_default_kernel_args(self): - return [ - "earlyprintk=ttyS0", - "console=ttyS0", - "lpj=7999923", - "root=/dev/vda1", - "init=/root/init.sh", - "rw", - ] - -# Setup the board. -board = HighPerformanceRiscvBoard( - clk_freq="4GHz", - processor=processor, - memory=memory, - cache_hierarchy=cache_hierarchy, -) - -# Set the Full System workload. -board.set_kernel_disk_workload( - kernel=Resource("riscv-bootloader-vmlinux-5.10"), - disk_image=DiskImageResource( - "/projects/gem5/npb-gapbs-riscv.img", root_partition="1" - ), - readfile_contents=f"{command}" -) - -# The first exit_event ends with a `workbegin` cause. This means that the -# system started successfully and the execution on the program started. -def handle_workbegin(): - print("Done booting Linux") - print("Resetting stats at the start of ROI!") - - m5.stats.dump() - m5.stats.reset() - - # switch the processor to timing CPU for warmup - print("Switching the CPU") - processor.switch() - # schedule an exit event for 1 second. - m5.scheduleTickExitFromCurrent(1000000000000) - yield False - -""" -def handle_cachewarmup(): - print("Cache warmed up as we reached : ") - print(simulator.get_last_exit_event_cause()) - print("Taking the checkpoint!") - - m5.stats.dump() - m5.stats.reset() - save_checkpoint() - yield True -""" -# Running things for 1sec and will -# not take ckpt if cache gets -# warmed up during Linux boot -def handle_cachewarmup(): - print("Cache warmed up as we reached : ") - print(simulator.get_last_exit_event_cause()) - print("Will continue simulation!") - - m5.stats.dump() - m5.stats.reset() - #save_checkpoint() - yield False - -def handle_schedtick(): - print("Cache warmed up as we reached : ") - print(simulator.get_last_exit_event_cause()) - print("Taking the checkpoint!") - - m5.stats.dump() - m5.stats.reset() - save_checkpoint() - yield True - -def handle_workend(): - print("Dump stats at the end of the ROI!") - - m5.stats.dump() - yield True - - -simulator = Simulator( - board=board, - on_exit_event={ - ExitEvent.WORKBEGIN: handle_workbegin(), - ExitEvent.WORKEND: handle_workend(), - ExitEvent.CACHE_WARMUP: handle_cachewarmup(), - ExitEvent.SCHEDULED_TICK: handle_schedtick(), - }, -) - -def save_checkpoint(): - simulator.save_checkpoint(args.ckpt_path) - - -print("Beginning simulation!") - -simulator.run() - -print("End of the simulation, we should have created a ckpt.") diff --git a/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint.py b/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint.py deleted file mode 100644 index cf503bb3d7..0000000000 --- a/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-checkpoint.py +++ /dev/null @@ -1,148 +0,0 @@ -from gem5.components.boards.riscv_board import RiscvBoard -from gem5.components.memory.memory import ChanneledMemory -from gem5.components.processors.simple_processor import SimpleProcessor -from gem5.components.processors.cpu_types import CPUTypes -from gem5.isas import ISA -from gem5.utils.requires import requires -from gem5.utils.override import overrides -from gem5.resources.resource import Resource, DiskImageResource -from gem5.simulate.simulator import Simulator -from gem5.components.processors.simple_switchable_processor import ( - SimpleSwitchableProcessor, -) -from gem5.components.memory import CascadeLakeCache, OracleCache, RamCache -from gem5.simulate.simulator import ExitEvent -import m5 -from components.Octopi import OctopiCache - -# Sample command to use this script -# build/RISCV/gem5.opt --outdir=bt.D riscv-2channel-1ccd-checkpoint.py -# --benchmark bt --size D --ckpt_path checkpoints-npb/bt.D.ckpt/ -# - -requires(isa_required=ISA.RISCV) - -import argparse -parser = argparse.ArgumentParser() -parser.add_argument("--benchmark", type=str) -parser.add_argument("--size", type=str) -parser.add_argument("--ckpt_path", type=str) - -args = parser.parse_args() - -num_ccds = 1 -num_cores = 8 -command = f"/home/ubuntu/gem5-npb/NPB3.3-OMP/bin/{args.benchmark}.{args.size}.x;" - -cache_hierarchy = OctopiCache( - l1i_size = "32KiB", - l1i_assoc = 8, - l1d_size = "32KiB", - l1d_assoc = 8, - l2_size = "512KiB", - l2_assoc = 8, - l3_size = "32MiB", - l3_assoc = 32, - num_core_complexes = 1, - is_fullsystem = True, -) -memory = RamCache() - -processor = SimpleSwitchableProcessor( - starting_core_type=CPUTypes.ATOMIC, - switch_core_type=CPUTypes.TIMING, # TODO - isa=ISA.RISCV, - num_cores=num_cores -) - -class HighPerformanceRiscvBoard(RiscvBoard): - @overrides(RiscvBoard) - def get_default_kernel_args(self): - return [ - "earlyprintk=ttyS0", - "console=ttyS0", - "lpj=7999923", - "root=/dev/vda1", - "init=/root/init.sh", - "rw", - ] - -# Setup the board. -board = HighPerformanceRiscvBoard( - clk_freq="4GHz", - processor=processor, - memory=memory, - cache_hierarchy=cache_hierarchy, -) - -# Set the Full System workload. -board.set_kernel_disk_workload( - kernel=Resource("riscv-bootloader-vmlinux-5.10"), - disk_image=DiskImageResource( - "/projects/gem5/npb-gapbs-riscv.img", root_partition="1" - ), - readfile_contents=f"{command}" -) - -# The first exit_event ends with a `workbegin` cause. This means that the -# system started successfully and the execution on the program started. -def handle_workbegin(): - print("Done booting Linux") - print("Resetting stats at the start of ROI!") - - m5.stats.dump() - m5.stats.reset() - - # switch the processor to timing CPU for warmup - processor.switch() - # schedule an exit event for 1 second. - m5.scheduleTickExitFromCurrent(1000000000000) - yield False - - -def handle_cachewarmup(): - print("Cache warmed up as we reached : ") - print(simulator.get_last_exit_event_cause()) - print("Taking the checkpoint!") - - m5.stats.dump() - m5.stats.reset() - save_checkpoint() - yield True - -def handle_schedtick(): - print("Cache warmed up as we reached : ") - print(simulator.get_last_exit_event_cause()) - print("Taking the checkpoint!") - - m5.stats.dump() - m5.stats.reset() - save_checkpoint() - yield True - -def handle_workend(): - print("Dump stats at the end of the ROI!") - - m5.stats.dump() - yield True - - -simulator = Simulator( - board=board, - on_exit_event={ - ExitEvent.WORKBEGIN: handle_workbegin(), - ExitEvent.WORKEND: handle_workend(), - ExitEvent.CACHE_WARMUP: handle_cachewarmup(), - ExitEvent.SCHEDULED_TICK: handle_schedtick(), - }, -) - -def save_checkpoint(): - simulator.save_checkpoint(args.ckpt_path) - - -print("Beginning simulation!") - -simulator.run() - -print("End of the simulation, we should have created a ckpt.") diff --git a/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-restore-timing-gapbs.py b/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-restore-timing-gapbs.py deleted file mode 100644 index da8dde9be9..0000000000 --- a/Octopi-cache/old-run-scripts/riscv-2channel-1ccd-restore-timing-gapbs.py +++ /dev/null @@ -1,160 +0,0 @@ -from gem5.components.boards.riscv_board import RiscvBoard -from gem5.components.memory.memory import ChanneledMemory -from gem5.components.processors.simple_processor import SimpleProcessor -from gem5.components.processors.cpu_types import CPUTypes -from gem5.isas import ISA -from gem5.utils.requires import requires -from gem5.utils.override import overrides -from gem5.resources.resource import Resource, DiskImageResource -from gem5.simulate.simulator import Simulator -from gem5.components.processors.simple_switchable_processor import ( - SimpleSwitchableProcessor, -) -from gem5.components.processors.simple_processor import ( - SimpleProcessor, -) -from gem5.components.memory import CascadeLakeCache, OracleCache, RamCache -from gem5.simulate.simulator import ExitEvent -import m5 -from components.Octopi import OctopiCache -from pathlib import Path - -# Sample command to use this script -# build/RISCV/gem5.opt -re --outdir=/projects/gem5/sssp16-test/ Octopi-cache/riscv-2channel-1ccd-restore-timing-gapbs.py --benchmark sssp --size 16 --ckpt_path /projects/gem5/dramcache/jason-checkpoints/gapbs/16/sssp/ckpt -# build/RISCV/gem5.opt -re --outdir=/projects/gem5/sssp16-test/ Octopi-cache/riscv-2channel-1ccd-restore-timing-gapbs.py --benchmark sssp --size C --ckpt_path /projects/gem5/dramcache/jason-checkpoints/npb/c/bt/ckpt - -requires(isa_required=ISA.RISCV) - -import argparse -parser = argparse.ArgumentParser() -parser.add_argument("--benchmark", type=str) -parser.add_argument("--size", type=str) -parser.add_argument("--ckpt_path", type=str) - -args = parser.parse_args() - -num_ccds = 1 -num_cores = 8 -#command = f"/home/ubuntu/gapbs/{args.benchmark} -g {args.size};" -command = f"/home/ubuntu/gem5-npb/NPB3.3-OMP/bin/{args.benchmark}.{args.size}.x;" - -cache_hierarchy = OctopiCache( - l1i_size = "32KiB", - l1i_assoc = 8, - l1d_size = "32KiB", - l1d_assoc = 8, - l2_size = "512KiB", - l2_assoc = 8, - l3_size = "32MiB", - l3_assoc = 16, - num_core_complexes = 1, - is_fullsystem = True, -) -memory = RamCache() - -""" -processor = SimpleSwitchableProcessor( - starting_core_type=CPUTypes.TIMING, - switch_core_type=CPUTypes.TIMING, # TODO - isa=ISA.RISCV, - num_cores=num_cores -) -""" - -processor = SimpleProcessor( - cpu_type=CPUTypes.TIMING, isa=ISA.RISCV, num_cores=num_cores -) - -class HighPerformanceRiscvBoard(RiscvBoard): - @overrides(RiscvBoard) - def get_default_kernel_args(self): - return [ - "earlyprintk=ttyS0", - "console=ttyS0", - "lpj=7999923", - "root=/dev/vda1", - "init=/root/init.sh", - "rw", - ] - -# Setup the board. -board = HighPerformanceRiscvBoard( - clk_freq="4GHz", - processor=processor, - memory=memory, - cache_hierarchy=cache_hierarchy, -) - -# Set the Full System workload. -board.set_kernel_disk_workload( - kernel=Resource("riscv-bootloader-vmlinux-5.10"), - disk_image=DiskImageResource( - "/projects/gem5/npb-gapbs-riscv.img", root_partition="1" - ), - readfile_contents=f"{command}", - checkpoint=Path(args.ckpt_path) -) - -# The first exit_event ends with a `workbegin` cause. This means that the -# system started successfully and the execution on the program started. -def handle_workbegin(): - print("Unexpected case!") - print("Workload begin should have not hit again!") - yield False - -# This event is scheduled every 100ms to get an -# update on the progress of the simulation itself -def handle_progress_update(): - - while True: - print("Simulated another 100ms") - - print( - f"Total sim time so far : {simulator.get_current_tick() / 1e12} sec" - ) - - m5.scheduleTickExitFromCurrent(100000000000, "progress_update") - yield False - -def handle_cachewarmup(): - # we probably should never hit this - # case during ckpt restore - print("DRAM Cache warmed up!") - print("Will continue simulation!") - yield False - -def handle_schedtick(): - print("Terminating the simulation because : ") - print(simulator.get_last_exit_event_cause()) - m5.stats.dump() - yield True - -def handle_workend(): - print("Terminating the simulation because : ") - print(simulator.get_last_exit_event_cause()) - m5.stats.dump() - yield True - - -simulator = Simulator( - board=board, - on_exit_event={ - ExitEvent.WORKBEGIN: handle_workbegin(), - ExitEvent.WORKEND: handle_workend(), - ExitEvent.CACHE_WARMUP: handle_cachewarmup(), - ExitEvent.SCHEDULED_TICK: handle_schedtick(), - #ExitEvent.SCHEDULED_TICK_PROGRESS: handle_progress_update(), - }, -) - -print("Beginning simulation!") -print(f"Will restore the checkpoint from : {args.ckpt_path} ") - -# progress update -#m5.scheduleTickExitFromCurrent(100000000000, "progress_update") - -# Running the actual simulation for 1 second -#m5.scheduleTickExitFromCurrent(1000000000000) -simulator.run(1000000000000) - -print("End of the simulation!") diff --git a/Octopi-cache/old-run-scripts/riscv-2channel-1ccd.py b/Octopi-cache/old-run-scripts/riscv-2channel-1ccd.py deleted file mode 100644 index 3b0b11ec00..0000000000 --- a/Octopi-cache/old-run-scripts/riscv-2channel-1ccd.py +++ /dev/null @@ -1,101 +0,0 @@ -from gem5.components.boards.riscv_board import RiscvBoard -from gem5.components.memory.memory import ChanneledMemory -from gem5.components.processors.simple_processor import SimpleProcessor -from gem5.components.processors.cpu_types import CPUTypes -from gem5.isas import ISA -from gem5.utils.requires import requires -from gem5.utils.override import overrides -from gem5.resources.resource import Resource, DiskImageResource -from gem5.simulate.simulator import Simulator -from gem5.components.processors.simple_switchable_processor import ( - SimpleSwitchableProcessor, -) -from gem5.components.memory import CascadeLakeCache, OracleCache, RamCache -import m5 - -from m5.objects import HBM_1000_4H_1x64 - -from components.Octopi import OctopiCache - -requires(isa_required=ISA.RISCV) - -import argparse -parser = argparse.ArgumentParser() -parser.add_argument("--command", type=str) -parser.add_argument("--checkpoint-path", type=str) - -args = parser.parse_args() - -num_ccds = 1 -num_cores = 8 -command = args.command - -cache_hierarchy = OctopiCache( - l1i_size = "32KiB", - l1i_assoc = 8, - l1d_size = "32KiB", - l1d_assoc = 8, - l2_size = "512KiB", - l2_assoc = 8, - l3_size = "32MiB", - l3_assoc = 32, - num_core_complexes = 1, - is_fullsystem = True, -) -memory = RamCache() - -""" -memory = ChanneledMemory( - dram_interface_class = HBM_1000_4H_1x64, - num_channels = 2, - interleaving_size = 2**8, - size = "64GiB", - addr_mapping = None -) -""" - -processor = SimpleSwitchableProcessor( - starting_core_type=CPUTypes.TIMING, - switch_core_type=CPUTypes.TIMING, # TODO - isa=ISA.RISCV, - num_cores=num_cores -) - -class HighPerformanceRiscvBoard(RiscvBoard): - @overrides(RiscvBoard) - def get_default_kernel_args(self): - return [ - "earlyprintk=ttyS0", - "console=ttyS0", - "lpj=7999923", - "root=/dev/vda1", - "init=/root/init.sh", - "rw", - ] - -# Setup the board. -board = HighPerformanceRiscvBoard( - clk_freq="4GHz", - processor=processor, - memory=memory, - cache_hierarchy=cache_hierarchy, -) - -# Set the Full System workload. -board.set_kernel_disk_workload( - kernel=Resource("riscv-bootloader-vmlinux-5.10"), - #disk_image=DiskImageResource( - # "/projects/gem5/npb-gapbs-riscv.img", root_partition="1" - #), - disk_image=DiskImageResource("/scr/hn/DISK_IMAGES/ubuntu-2204-riscv.img"), - readfile_contents=f"{command}" -) - -m5.scheduleTickExitFromCurrent(1000000000) - -simulator = Simulator(board=board) -print("Beginning simulation!") -simulator.run() -print("We are exiting because : ") -print(simulator.get_last_exit_event_cause()) -simulator.save_checkpoint(args.checkpoint_path) diff --git a/Octopi-cache/restore-npb-gapbs-looppoint.py b/Octopi-cache/restore-npb-gapbs-looppoint.py deleted file mode 100644 index 6e5a22e4c3..0000000000 --- a/Octopi-cache/restore-npb-gapbs-looppoint.py +++ /dev/null @@ -1,259 +0,0 @@ -from gem5.components.boards.riscv_board import RiscvBoard -from gem5.components.memory.memory import ChanneledMemory -from gem5.components.processors.simple_processor import SimpleProcessor -from gem5.components.processors.cpu_types import CPUTypes -from gem5.isas import ISA -from gem5.utils.requires import requires -from gem5.utils.override import overrides -from gem5.resources.resource import Resource, DiskImageResource -from gem5.simulate.simulator import Simulator -from gem5.components.processors.simple_switchable_processor import ( - SimpleSwitchableProcessor, - MySimpleProcessor, -) -from gem5.components.processors.simple_processor import SimpleProcessor -from gem5.components.memory import CascadeLakeCache, OracleCache, RambusCache -from gem5.simulate.simulator import ExitEvent -import m5 -from components.Octopi import OctopiCache -from pathlib import Path -from m5.objects import O3LooppointAnalysis, O3LooppointAnalysisManager - - -# Sample command to use this script -# build/RISCV_MESI_Three_Level/gem5.opt -re --outdir=m5out Octopi-cache/restore-npb-gapbs-looppoint.py RambusBaseline bt 128MiB - -requires(isa_required=ISA.RISCV) - -import argparse - -parser = argparse.ArgumentParser() -parser.add_argument("experiment", type=str) -parser.add_argument("benchmark", type=str) -parser.add_argument("cache_size", type=str) - -args = parser.parse_args() - -ckpt_path = "/projects/gem5/dramcache/jason-checkpoints/npb/c/"+args.benchmark+"/ckpt" -print("Checkpoint directory: "+ckpt_path) - -# Valid addresses for looppoint analysis -# The addresses are the .text section range -text_start = { - "bt.C": "111b0", - "cg.C": "112a0", - "ft.C": "113a0", - "is.C": "10df0", - "lu.C": "11450", - "mg.C": "11630", - "sp.C": "11250", - "ua.C": "11aa0", - "bt.D": "111b0", - "cg.D": "112a0", - "ft.D": "113a0", - "lu.D": "11450", - "mg.D": "11630", - "sp.D": "11250", - "ua.D": "11aa0", - "bc": "12c80", - "bfs": "12bb0", - "cc": "12e60", - "cc_sv": "12ca0", - "pr": "12dd0", - "sssp": "12d80", - "tc": "12c00", -} - -text_size = { - "bt.C": "e14a", - "cg.C": "2b84", - "ft.C": "353a", - "is.C": "1692", - "lu.C": "df12", - "mg.C": "66ca", - "sp.C": "b31e", - "ua.C": "190f4", - "bt.D": "e500", - "cg.D": "2a4a", - "ft.D": "35ba", - "lu.D": "e0e0", - "mg.D": "687a", - "sp.D": "b7d4", - "ua.D": "191f0", - "bc": "af82", - "bfs": "a008", - "cc": "a51a", - "cc_sv": "98a4", - "pr": "9b14", - "sssp": "acf8", - "tc": "9cc2", -} - - -num_ccds = 1 -num_cores = 8 -command = ( - f"/home/ubuntu/gem5-npb/NPB3.3-OMP/bin/{args.benchmark}.C.x;" -) - -cache_hierarchy = OctopiCache( - l1i_size="32KiB", - l1i_assoc=8, - l1d_size="32KiB", - l1d_assoc=8, - l2_size="512KiB", - l2_assoc=8, - l3_size="32MiB", - l3_assoc=16, - num_core_complexes=1, - is_fullsystem=True, -) - -if args.experiment == "RambusBaseline": - memory = RambusCache(args.cache_size) -elif args.experiment == "CascadeLakeBaseline": - memory = CascadeLakeCache(args.cache_size) -elif args.experiment == "OracleBaseline": - memory = OracleCache(args.cache_size) - -processor = MySimpleProcessor( - starting_core_type=CPUTypes.O3, - switch_core_type=CPUTypes.O3, - isa=ISA.RISCV, - num_cores=num_cores, -) - -lpmanager = O3LooppointAnalysisManager() - -# dump the tick and the PC counter as well - -for core in processor.get_cores(): - lplistener = O3LooppointAnalysis() - lplistener.ptmanager = lpmanager - lplistener.validAddrRangeStart = int(text_start[args.benchmark+".C"], 16) - lplistener.validAddrRangeSize = int(text_size[args.benchmark+".C"], 16) - core.core.probeListener = lplistener - - -class HighPerformanceRiscvBoard(RiscvBoard): - @overrides(RiscvBoard) - def get_default_kernel_args(self): - return [ - "earlyprintk=ttyS0", - "console=ttyS0", - "lpj=7999923", - "root=/dev/vda1", - "init=/root/init.sh", - "rw", - ] - - -# Setup the board. -board = HighPerformanceRiscvBoard( - clk_freq="4GHz", - processor=processor, - memory=memory, - cache_hierarchy=cache_hierarchy, -) - -# Set the Full System workload. -board.set_kernel_disk_workload( - kernel=Resource("riscv-bootloader-vmlinux-5.10"), - disk_image=DiskImageResource( - "/projects/gem5/npb-gapbs-riscv.img", root_partition="1" - ), - readfile_contents=f"{command}", - checkpoint=Path(ckpt_path), -) - -# The first exit_event ends with a `workbegin` cause. This means that the -# system started successfully and the execution on the program started. -def handle_workbegin(): - print("Unexpected case!") - print("Workload begin should have not hit again!") - yield False - - -# This event is scheduled every 100ms to get an -# update on the progress of the simulation itself -def handle_progress_update(): - - while True: - print("Simulated another 100ms") - - print( - f"Total sim time so far : {simulator.get_current_tick() / 1e12} sec" - ) - - print("Most recent (PC, count, tick) at this point in simulation") - mostRecentPc = lpmanager.getMostRecentPc() - for pc, tick in mostRecentPc: - count = lpmanager.getPcCount(pc) - print(f"{hex(pc)},{count[0]},{count[1]}\n") - - m5.scheduleTickExitFromCurrent(100_000_000_000, "progress_update") - yield False - - -def handle_cachewarmup(): - # we probably should never hit this - # case during ckpt restore - print("DRAM Cache warmed up!") - print("Will continue simulation!") - yield False - - -def handle_schedtick(): - print("Terminating the simulation because : ") - print(simulator.get_last_exit_event_cause()) - m5.stats.dump() - yield True - - -def handle_workend(): - print("Terminating the simulation because : ") - print(simulator.get_last_exit_event_cause()) - m5.stats.dump() - yield True - - -simulator = Simulator( - board=board, - on_exit_event={ - ExitEvent.WORKBEGIN: handle_workbegin(), - ExitEvent.WORKEND: handle_workend(), - ExitEvent.CACHE_WARMUP: handle_cachewarmup(), - ExitEvent.SCHEDULED_TICK: handle_schedtick(), - ExitEvent.SCHEDULED_TICK_PROGRESS: handle_progress_update(), - }, -) - -print("Beginning simulation!") -print(f"Will restore the checkpoint from : {ckpt_path} ") - -# Start the simulation so that the -# scheduleTickExitFromCurrent() can be used -#simulator.run(1000) -# progress update -#m5.scheduleTickExitFromCurrent(100_000_000_000, "progress_update") - -def DumpLoopPointCounters(): - mostRecentPc = lpmanager.getMostRecentPc() - print("Most recent (PC, count, tick) at the end of the simulation") - for pc, tick in mostRecentPc: - count = lpmanager.getPcCount(pc) - print(f"{hex(pc)},{count[0]},{count[1]}") - -# Simulate 1s in 10 intervals -numIteration = 10 - -print("Simulating ten intervals of 100ms!") - -for interval_number in range(numIteration): - print("Interval number: {} \n".format(interval_number)) - simulator.run(100_000_000_000) - print(f"Exiting simulation loop because of : {simulator.get_last_exit_event_cause()}") - DumpLoopPointCounters() - m5.stats.dump() - -print("End of the simulation!") diff --git a/Octopi-cache/riscv-hpc.py b/Octopi-cache/riscv-hpc.py deleted file mode 100644 index 74001499a9..0000000000 --- a/Octopi-cache/riscv-hpc.py +++ /dev/null @@ -1,87 +0,0 @@ -from gem5.components.boards.riscv_board import RiscvBoard -from gem5.components.memory.memory import ChanneledMemory -from gem5.components.processors.simple_processor import SimpleProcessor -from gem5.components.processors.cpu_types import CPUTypes -from gem5.isas import ISA -from gem5.utils.requires import requires -from gem5.utils.override import overrides -from gem5.resources.resource import Resource, DiskImageResource -from gem5.simulate.simulator import Simulator -from gem5.components.memory import CascadeLakeCache, OracleCache, RamCache - -from m5.objects import HBM_1000_4H_1x64 - -from components.Octopi import OctopiCache - -requires(isa_required=ISA.RISCV) - - - -import argparse -parser = argparse.ArgumentParser() -parser.add_argument("--command", type=str) -parser.add_argument("--num_ccxs", type=int, required=True) -parser.add_argument("--num_cores", type=int, required=True) -args = parser.parse_args() - -num_ccxs = args.num_ccxs -num_cores = args.num_cores -command = args.command - -cache_hierarchy = OctopiCache( - l1i_size = "32KiB", - l1i_assoc = 8, - l1d_size = "32KiB", - l1d_assoc = 8, - l2_size = "512KiB", - l2_assoc = 8, - l3_size = "32MiB", - l3_assoc = 32, - num_core_complexes = num_ccxs, - is_fullsystem = True, -) - -#memory = ChanneledMemory( -# dram_interface_class = HBM_1000_4H_1x64, -# num_channels = num_ccxs, # should equal to the number of core complexes -# interleaving_size = 2**8, -# size = "8GiB", -# addr_mapping = None -#) - -memory = RamCache() - -processor = SimpleProcessor( - cpu_type=CPUTypes.TIMING, isa=ISA.RISCV, num_cores=num_cores -) - -class HighPerformanceRiscvBoard(RiscvBoard): - @overrides(RiscvBoard) - def get_default_kernel_args(self): - return [ - "earlyprintk=ttyS0", - "console=ttyS0", - "lpj=7999923", - "root=/dev/vda1", - "init=/root/init.sh", - "rw", - ] - -# Setup the board. -board = HighPerformanceRiscvBoard( - clk_freq="4GHz", - processor=processor, - memory=memory, - cache_hierarchy=cache_hierarchy, -) - -# Set the Full System workload. -board.set_kernel_disk_workload( - kernel=Resource("riscv-bootloader-vmlinux-5.10"), - disk_image=DiskImageResource("/scr/hn/DISK_IMAGES/ubuntu-2204-riscv.img"), - readfile_contents=f"{command}" -) - -simulator = Simulator(board=board) -print("Beginning simulation!") -simulator.run() diff --git a/cmd.txt b/cmd.txt deleted file mode 100644 index 8965ec914c..0000000000 --- a/cmd.txt +++ /dev/null @@ -1,486 +0,0 @@ - 29 git status - 30 clear - 31 git status - 32 ssh babaie@galaxy.cs.ucdavis.edu - 33 cd paper-draft1/papers/tdram-paper/hpca2024-latex-template/ - 34 git status - 35 git diff - 36 git pull - 37 git status - 38 git diff - 39 git statsh - 40 git stash - 41 git pull - 42 qgit rebase --continue - 43 git rebase --continue - 44 cd ../../../ - 45 cd ../ - 46 mkdir paper-draft-postsubmission - 47 cd paper-draft-postsubmission/ - 48 git clone https://github.com/darchr/papers.git - 49 cd papers/tdram-paper/hpca2024-latex-template/ - 50 make - 51 zip -r TDRAM-Paper.zip /home/babaie/projects/rambusDesign/paper-draft-postsubmission/papers/tdram-paper/hpca2024-latex-template - 52 ls - 53 cd checkSetAssociative/dramCacheController/ - 54 git status - 55 sudo apt install git - 56 git status - 57 git diff - 58 cd ../../1gigDRAMCache/dramCacheController/ - 59 clear - 60 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 0 0 - 61 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 0 0 - 62 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 0 0 - 63 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 0 0 - 64 mkdir longerTagCheckLatency - 65 cd longerTagCheckLatency/ - 66 git clone https://github.com/darchr/dramCacheController.git - 67 cd dramCacheController/ - 68 git checkout tag_prob_real_implementation - 69 scons build/X86_MESI_Two_Level/gem5.opt -j40 --linker=gold --without-tcmalloc - 70 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 0 0 - 71 cd projects/ - 72 mkdir stable_gem5 - 73 cd stable_gem5/ - 74 git clone https://github.com/gem5/gem5 - 75 ls - 76 cd ../../../ - 77 cd stable_gem5/ - 78 git clone https://github.com/gem5/gem5 - 79 cd ../../ - 80 git lofg - 81 git log - 82 cd tagProbing/dramCacheController/ - 83 git status - 84 cd ../../tagProbingNew/dramCacheController/ - 85 git status - 86 cd /home/babaie/projects/rambusDesign/tagProbOptRealImplOnSetAssoBranch/dramCacheController - 87 git status - 88 git log - 89 cd /home/babaie/projects/rambusDesign/tagProbOptRealImplOnSetAssoBranch/dramCacheController - 90 git status - 91 cd /home/babaie/projects/rambusDesign/tagProbingNew/dramCacheController - 92 git status - 93 cd /home/babaie/projects/rambusDesign/tagProbing/dramCacheController - 94 git status - 95 cd ../../ - 96 mkdir tagProb-Backup - 97 mkdir setAssoc-Backup - 98 cd tagProb-Backup/ - 99 git clone https://github.com/darchr/dramCacheController - 100 git checkout tag_prob_backup - 101 cd dramCacheController/ - 102 git checkout tag_prob_backup - 103 cd ../setAssoc-Backup/ - 104 git clone https://github.com/darchr/dramCacheController - 105 cd dramCacheController/ - 106 git checkout set_associative_backup - 107 cd setAssoc-Backup/dramCacheController/ - 108 git status - 109 cd ../../tagProb-Backup/dramCacheController/ - 110 git status - 111 cd ... - 112 cd ../.. - 113 mkdir merge tagPrbIntoSetAsso - 114 mkdir mergeTagPrbIntoSetAsso - 115 cd mergeTagPrbIntoSetAsso/ - 116 git clone https://github.com/darchr/dramCacheController - 117 ls - 118 cd dramCacheController/ - 119 git status - 120 git checkout set_associative_backup - 121 git checkout tag_prob_backup - 122 git status - 123 git rebase set_associative_backup - 124 cd ../ - 125 rm -r dramCacheController/ - 126 ls - 127 git clone https://github.com/darchr/dramCacheController - 128 cd ../ - 129 rm -r mergeTagPrbIntoSetAsso/ - 130 mkdir mergeSetTagPrb - 131 cd mergeSetTagPrb/ - 132 git clone https://github.com/darchr/dramCacheController - 133 cd mergeSetTagPrb/ - 134 git clone https://github.com/darchr/dramCacheController - 135 clear - 136 ls - 137 cd mergeSetTagPrb/ - 138 git clone https://github.com/darchr/dramCacheController - 139 cd dramCacheController/ - 140 clear - 141 git checkout tag_prob_backup - 142 clear - 143 git status - 144 git rebase -i HEAD~15 - 145 git rebase -i HEAD~25 - 146 git rebase --abort - 147 git rebase -i HEAD~25 - 148 git rebase --abort - 149 git rebase -i HEAD~25 - 150 git status - 151 git status - 152 git add realAppRun.sh - 153 git rebase --continue - 154 git status - 155 git add realAppRun.sh - 156 git rebase --continue - 157 git status - 158 git add realAppRun.sh - 159 git rebase --continue - 160 git add realAppRun.sh - 161 git rebase --continue --ours - 162 git rebase --continue - 163 git log - 164 clear - 165 git status - 166 git format-patch -1 - 167 git checkout set_associative_backup - 168 git log - 169 clear - 170 git am 0001-parent-41af1e744aaf2a2dd291d32ad1ec1b672b8822b9.patch - 171 git status - 172 git am --abort - 173 git am -3 < 0001-parent-41af1e744aaf2a2dd291d32ad1ec1b672b8822b9.patch - 174 git status - 175 git add realAppRun.sh - 176 git am --continue - 177 git log - 178 git log - 179 git show - 180 git diff src/mem/dram_interface.cc - 181 scons build/X86_MESI_Two_Level/gem5.opt -j30 - 182 cd mergeSetTagPrb/ - 183 cd dramCacheController/ - 184 git status - 185 git push - 186 history > git-cmds.txt - 187 mkdir gem5-23 - 188 cd gem5-23/ - 189 git clone https://github.com/darchr/dramCacheController.git - 190 git switch -c develop23 - 191 git checkout -b develop23 - 192 cd dramCacheController/ - 193 git switch -c develop23 - 194 git pull https://github.com/gem5/gem5.git develop - 195 git checkout develop22 - 196 cd ../ - 197 cd ../ - 198 rm -r gem5-23/ - 199 mkdir gem5-dev - 200 cd gem5-dev/ - 201 mkdir dev23 - 202 cd dev23/ - 203 git clone https://github.com/darchr/dramCacheController.git - 204 cd dramCacheController/ - 205 git checkout develop22 - 206 git pull - 207 git pull https://github.com/gem5/gem5.git develop - 208 git status - 209 git checkout -b develop23 - 210 git status - 211 git add . - 212 git push - 213 git push --set-upstream origin develop23 - 214 scons build/X86_MESI_Two_Level/gem5.opt -j30 - 215 cd ../../../ - 216 cd setAssoc-Backup/dramCacheController/ - 217 git status - 218 git checkout -b set_associative_backup - 219 git checkout -b set_associative_backup2 - 220 git push - 221 git push --set-upstream origin set_associative_backup2 - 222 git status - 223 git pull - 224 git status - 225 git status - 226 cd ../../../mergeSetTagPrb/dramCacheController/ - 227 git status - 228 git diff - 229 git commit -am "just some comments removed" - 230 git push - 231 git status - 232 git branch -m set_associative_backup merged_tagPrb_setAssoc - 233 git status - 234 git branch -a - 235 git status - 236 git status - 237 cd mergeSetTagPrb/dramCacheController/ - 238 git status - 239 scons build/X86_MESI_Two_Level/gem5.opt -j30 - 240 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 1 0 - 241 scons build/X86_MESI_Two_Level/gem5.opt -j30 - 242 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 1 0 - 243 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold - 244 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 1 0 - 245 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold - 246 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 1 0 - 247 gdb --args build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 1 0 - 248 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold - 249 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 1 0 - 250 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 1 1 - 251 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 0 0 - 252 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 0 1 - 253 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 0 1 1 0 - 254 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 0 1 1 1 - 255 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 0 1 0 0 - 256 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 0 1 0 1 - 257 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 0 0 - 258 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 0 1 - 259 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold - 260 build/X86_MESI_Two_Level/gem5.opt traffGen_def.py random 100 1 0 1 - 261 build/X86_MESI_Two_Level/gem5.opt --debug-flag=DRAMT traffGen_def.py random 100 1 0 1 - 262 build/X86_MESI_Two_Level/gem5.opt -re --debug-flag=DRAMT traffGen_def.py random 100 1 0 1 - 263 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold - 264 build/X86_MESI_Two_Level/gem5.opt -re --debug-flag=DRAMT traffGen_def.py random 100 1 0 1 - 265 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold - 266 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold - 267 build/X86_MESI_Two_Level/gem5.opt -re --debug-flag=DRAMT traffGen_def.py random 100 1 0 1 - 268 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold - 269 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold - 270 build/X86_MESI_Two_Level/gem5.opt -re --debug-flag=DRAMT traffGen_def.py random 100 1 0 1 - 271 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold - 272 build/X86_MESI_Two_Level/gem5.opt -re --debug-flag=DRAMT traffGen_def.py random 100 1 0 1 - 273 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold - 274 build/X86_MESI_Two_Level/gem5.opt -re --debug-flag=DRAMT traffGen_def.py random 100 1 0 1 - 275 ls - 276 cd mergeSetTagPrb/dramCacheController/ - 277 git status - 278 cd ../../ - 279 mkdir codeReview - 280 cd codeReview/ - 281 ls ../code - 282 cd ../code/dramCacheController/ - 283 git status - 284 cd ../../codeReview/ - 285 git clone https://github.com/darchr/dramCacheController.git - 286 clear - 287 ls - 288 cd codeReview/ - 289 ls - 290 clear - 291 git clone https://github.com/darchr/dramCacheController.git - 292 cd dramCacheController/ - 293 git checkout set_associative_backup - 294 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc - 295 screen -ls - 296 screen -S test - 297 cd - 298 cd ../../../ - 299 cd codeReview/dramCacheController/ - 300 build/X86_MESI_Two_Level/gem5.opt -re configs-npb-gapbs/npb_checkpoint.py bt C RambusTagProbOpt 0 0 - 301 build/X86_MESI_Two_Level/gem5.opt -re configs-npb-gapbs/npb_checkpoint.py bt C RambusTagProbOpt 0 0 - 302 build/X86_MESI_Two_Level/gem5.opt -re configs-npb-gapbs/npb_checkpoint.py bt C RambusTagProbOpt 0 0 - 303 gdb --args build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/npb_checkpoint.py bt C RambusTagProbOpt 0 0 - 304 du -hs /home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/chkpt1GigDC/1GB_8GB_g22_nC_1halfSec - 305 du -hs /home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/chkpt1GigDC/1GB_85GB_g25_nD_1halfSec/ - 306 clear - 307 du -hs /home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/chkpt1GigDC/chkpts1GBDC.zip - 308 cd /home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/chkpt1GigDC - 309 clear - 310 zip -r chkpts1GBDC.zip 1GB_8GB_g22_nC_1halfSec/ 1GB_85GB_g25_nD_1halfSec/ - 311 du -hs 1GB_8GB_g22_nC_1halfSec/ - 312 du -hs 1GB_85GB_g25_nD_1halfSec/ - 313 screen -ls - 314 sudo apt install screen - 315 clear - 316 screen -ls - 317 screen -S zipTest - 318 chmod 777 checkpoints_backup/ - 319 sudo chmod 777 checkpoints_backup/ - 320 sudo chmod 777 checkpoints_backup/ - 321 sudo nautilus - 322 du -hs GAPBS/ - 323 du -hs NPB/ - 324 cd ../ - 325 ls - 326 ls -hs 1GB_85GB_g25_nD_1halfSec/ - 327 du -hs 1GB_85GB_g25_nD_1halfSec/ - 328 cd 1GB_85GB_g25_nD_1halfSec/ - 329 du -hs NPB/ - 330 du -hs GAPBS/ - 331 sudo cp -r /home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/chkpt1GigDC/1GB_8GB_g22_nC_1halfSec/ . - 332 cd /home/babaie/projects/rambusDesign/1gigDRAMCache/ - 333 ls - 334 cd dramCacheController/chkpt1GigDC/ - 335 ls - 336 sudo nautilus - 337 sudo nautilus - 338 sudo nautilus - 339 sudo nautilus - 340 chmod 777 checkpoints_backup/ - 341 sudo chmod 777 checkpoints_backup/ - 342 lsblk - 343 sudo smartctl -i /dev/sda - 344 wget https://download.teamviewer.com/download/linux/teamviewer_amd64.deb - 345 sudo apt install ./teamviewer_amd64.deb - 346 sudo gedit custom.conf - 347 htop - 348 sudo snap install htop - 349 htop - 350 sudo chmod 777 checkpoints_backup/ - 351 sudo apt install ./google-chrome-stable_current_amd64.deb - 352 cd ../../ - 353 TDRAM-reproduction - 354 mkdir TDRAM-reproduction - 355 cd TDRAM-reproduction/ - 356 git clone https://github.com/darchr/dramCacheController.git - 357 cd dramCacheController/ - 358 git checkout set_associative_backup2 - 359 /bin/python3 /home/babaie/time.py - 360 /bin/python3 /home/babaie/time.py - 361 /bin/python3 /home/babaie/time.py - 362 top - 363 top - 364 ./realAppRun.sh - 365 ./realAppRun.sh - 366 clear - 367 ./realAppRun.sh - 368 ./realAppRun.sh - 369 clear - 370 ./realAppRun.sh - 371 clear - 372 ./realAppRun.sh - 373 ./realAppRun.sh - 374 clear - 375 ./realAppRun.sh - 376 clear - 377 ./realAppRun.sh - 378 clear - 379 cd /home/babaie/projects/rambusDesign/tagProbOptRealImplOnSetAssoBranch/dramCacheController - 380 clear - 381 ./realAppRun.sh - 382 clear - 383 ./realAppRun.sh - 384 clear - 385 ./realAppRun.sh - 386 clear - 387 ./realAppRun.sh - 388 clear - 389 ./realAppRun.sh - 390 cd 1gigDRAMCache/dramCacheController/ - 391 clear - 392 ./realAppRun.sh - 393 clear - 394 build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/rambusTagPr/1GB_8GB_g22_nC/GAPBS/bfs configs-npb-gapbs/restore_both.py bfs-22 RambusTagProbOpt 1 0 0 0 & - 395 q - 396 clear - 397 pkill gem5 - 398 clear - 399 build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/rambusTagPr/1GB_8GB_g22_nC/NPB/bt --debug-flags=DRAM,MemCtrl,PolicyManager configs-npb-gapbs/restore_both.py bt.C.x RambusTagProbOpt 1 0 0 0 - 400 clear - 401 clear - 402 ./realAppRun.sh - 403 clear - 404 ./realAppRun.sh - 405 git status - 406 clear - 407 ./realAppRun.sh - 408 clear - 409 ./realAppRun.sh - 410 clear - 411 ./realAppRun.sh - 412 clear - 413 ./realAppRun.sh - 414 clear - 415 ./realAppRun.sh - 416 screen -d - 417 screen -d - 418 build/X86_MESI_Two_Level/gem5.opt -re --outdir=m5out/1GB_85GB_g25_nD/NPB/bt configs-npb-gapbs/restore_both.py bt.D.x RambusTagProbOpt 1 1 1250 0 7.5ns - 419 build/X86_MESI_Two_Level/gem5.opt -re --outdir=m5out/1GB_85GB_g25_nD/NPB/bt configs-npb-gapbs/restore_both.py bt.D.x RambusTagProbOpt 1 1 1250 0 7.5ns - 420 ./realAppRun.sh - 421 screen -ls - 422 killall screen - 423 screen -S pc6hour - 424 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc - 425 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmallocbuild/X86_MESI_Two_Level/gem5.opt -re --outdir=pcAnalysis/6hour_1halfChkpt/1GB_8GB_g22_nC/NPB/ft configs-npb-gapbs/restore_both.py ft.C.x CascadeLakeNoPartWrs 1 0 0 0 - 426 ls build/X86_MESI_Two_Level/ - 427 build/X86_MESI_Two_Level/gem5.opt -re --outdir=pcAnalysis/6hour_1halfChkpt/1GB_8GB_g22_nC/NPB/ft configs-npb-gapbs/restore_both.py ft.C.x CascadeLakeNoPartWrs 1 0 0 0 - 428 rm -r build/ - 429 top - 430 top - 431 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc - 432 screen -ls - 433 killall screen - 434 screen -S pc6hour - 435 top - 436 pkill gem5 - 437 top - 438 pkill gem5 - 439 screen -r pc6hour - 440 top - 441 to -u babaie - 442 top -u babaie - 443 cd pcAnalysis/ - 444 clear grep -r "Done with interval" | tail -1 - 445 clear grep "Done with interval" | tail -1 - 446 grep -r "Done with interval" | tail -1 - 447 grep -Irn "Done with interval" | tail -1 - 462 cd codeReview/dramCacheController/ - 463 git status - 464 git diff - 465 git pull - 466 git stash - 467 git pull - 468 git status - 469 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc - 470 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x RambusTagProbOpt 0 0 0 - 471 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x RambusTagProbOpt 1 0 0 0 - 472 pkill gem5 - 473 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x Rambus 1 0 0 0 - 474 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc - 475 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x Rambus 1 0 0 0 - 476 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc - 477 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc - 478 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x Rambus 1 0 0 0 - 479 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc - 480 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x Rambus 1 0 0 0 - 481 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc - 482 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc - 483 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc - 484 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x Rambus 1 0 0 0 - 485 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc - 486 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x Rambus 1 0 0 0 - 487 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc - 488 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x Rambus 1 0 0 0 - 489 scons build/X86_MESI_Two_Level/gem5.opt -j30 --linker=gold --without-tcmalloc - 490 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x Rambus 1 0 0 0 - 491 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x CascadeLakeNoPartWrs 1 0 0 0 - 492 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py bt.C.x Oracle 1 0 0 0 - 493 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py mg.C.x RambusTagProbOpt 0 0 0 - 494 build/X86_MESI_Two_Level/gem5.opt configs-npb-gapbs/restore_both.py mg.C.x RambusTagProbOpt 1 0 0 0 - 495 git status - 496 cd ../../gem5-23/dramCacheController/ - 497 git status - 498 ls - 499 cd ../../gem5-dev/ - 500 cd ../../ - 501 cd ../../ - 502 cd gem5-dev/ - 503 ls - 504 cd dev23/dramCacheController/ - 505 git status - 506 git pull - 507 cd ../../ - 508 ls - 509 git clone https://github.com/gem5/gem5.git - 510 cd gem5/ - 511 git checkout develop - 512 cd ../../ - 513 mkdir dc-gem5-dev-fork - 514 cd dc-gem5-dev-fork/ - 515 git clone https://github.com/darchr/dramCacheController.git - 516 cd dramCacheController/ - 517 git remote add fork https://github.com/gem5/gem5.git - 518 git fetch fork develop - 519 git checkout -b gem5-develop fork/develop - 520 git push - 521 git status - 522 tig - 523 apt install tig - 524 git status - 525 git remote -v - 526 git push origin gem5-develop:gem5-develop - 527 history -3000 > cmd.txt - 528 history 3000 > cmd.txt diff --git a/cold-miss-check-plots.ipynb b/cold-miss-check-plots.ipynb deleted file mode 100644 index 8c7ea949f7..0000000000 --- a/cold-miss-check-plots.ipynb +++ /dev/null @@ -1,466 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "import numpy as np\n", - "import sys\n", - "from matplotlib import pyplot as plt\n", - "import os\n", - "\n", - "cmap = plt.get_cmap('Set1')\n", - "\n", - "Stats = ['simSeconds ',\n", - "'hostSeconds ',\n", - "'system.mem_ctrl.readReqs ',\n", - "'system.mem_ctrl.writeReqs ',\n", - "'system.mem_ctrl.servicedByWrQ ',\n", - "'system.mem_ctrl.mergedWrBursts ',\n", - "'system.mem_ctrl.numTotHits ',\n", - "'system.mem_ctrl.numTotMisses ',\n", - "'system.mem_ctrl.numColdMisses ',\n", - "'system.mem_ctrl.numHotMisses ',\n", - "'system.mem_ctrl.numRdMissClean ',\n", - "'system.mem_ctrl.numRdMissDirty ',\n", - "'system.mem_ctrl.numRdHit ',\n", - "'system.mem_ctrl.numWrMissClean ',\n", - "'system.mem_ctrl.numWrMissDirty ',\n", - "'system.mem_ctrl.numWrHit ',\n", - "'system.mem_ctrl.numRdHitDirty ',\n", - "'system.mem_ctrl.numRdHitClean ',\n", - "'system.mem_ctrl.numWrHitDirty ',\n", - "'system.mem_ctrl.numWrHitClean ',\n", - "'system.o3Cpu0.thread_0.numInsts ',\n", - "'system.o3Cpu1.thread_0.numInsts ',\n", - "'system.o3Cpu2.thread_0.numInsts ',\n", - "'system.o3Cpu3.thread_0.numInsts ',\n", - "'system.o3Cpu4.thread_0.numInsts ',\n", - "'system.o3Cpu5.thread_0.numInsts ',\n", - "'system.o3Cpu6.thread_0.numInsts ',\n", - "'system.o3Cpu7.thread_0.numInsts ',\n", - "'system.mem_ctrl.avgRdBWSys ',\n", - "'system.mem_ctrl.avgWrBWSys ',\n", - "'system.mem_ctrl.avgORBLen ',\n", - "'system.far_mem_ctrl.avgRdBWSys ',\n", - "'system.far_mem_ctrl.avgWrBWSys ',\n", - "'system.loc_mem_ctrl.avgRdBWSys ',\n", - "'system.loc_mem_ctrl.avgWrBWSys ',\n", - "'system.loc_mem_ctrl.dram.readBursts ',\n", - "'system.loc_mem_ctrl.dram.writeBursts ',\n", - "'system.loc_mem_ctrl.dram_2.readBursts ',\n", - "'system.loc_mem_ctrl.dram_2.writeBursts ',\n", - "'system.far_mem_ctrl.dram.readBursts ',\n", - "'system.far_mem_ctrl.dram.writeBursts ',\n", - "'system.loc_mem_ctrl.dram.avgRdBW ',\n", - "'system.loc_mem_ctrl.dram.avgWrBW ',\n", - "'system.loc_mem_ctrl.dram_2.avgRdBW ',\n", - "'system.loc_mem_ctrl.dram_2.avgWrBW ',\n", - "'system.far_mem_ctrl.dram.avgRdBW ',\n", - "'system.far_mem_ctrl.dram.avgWrBW ',\n", - "'system.loc_mem_ctrl.dram.busUtil ',\n", - "'system.loc_mem_ctrl.dram.busUtilRead ',\n", - "'system.loc_mem_ctrl.dram.busUtilWrite ',\n", - "'system.loc_mem_ctrl.dram_2.busUtil ',\n", - "'system.loc_mem_ctrl.dram_2.busUtilRead ',\n", - "'system.loc_mem_ctrl.dram_2.busUtilWrite ',\n", - "'system.far_mem_ctrl.dram.busUtil ',\n", - "'system.far_mem_ctrl.dram.busUtilRead ',\n", - "'system.far_mem_ctrl.dram.busUtilWrite ',\n", - "'system.far_mem_ctrl.dram.bytesRead ',\n", - "'system.far_mem_ctrl.dram.bytesWritten ',\n", - "'system.loc_mem_ctrl.dram.bytesRead ',\n", - "'system.loc_mem_ctrl.dram.bytesWritten ',\n", - "'system.loc_mem_ctrl.dram_2.bytesRead ',\n", - "'system.loc_mem_ctrl.dram_2.bytesWritten ',\n", - "'system.mem_ctrl.avgTimeTagCheckRes ',\n", - "'system.mem_ctrl.avgTimeTagCheckResRd ',\n", - "'system.mem_ctrl.avgTimeTagCheckResWr ',\n", - "'system.mem_ctrl.avgPktRespTimeRd ',\n", - "'system.mem_ctrl.avgPktRespTimeWr ',\n", - "'system.mem_ctrl.avgPktORBTime ',\n", - "'system.mem_ctrl.avgPktORBTimeRd ',\n", - "'system.mem_ctrl.avgPktORBTimeWr ',\n", - "'system.mem_ctrl.avgTimeInLocRead ',\n", - "'system.mem_ctrl.avgTimeInLocWrite ',\n", - "'system.mem_ctrl.avgTimeInFarRead '\n", - " ]\n", - "\n", - "dfCols = [\n", - " 'app',\n", - " 'simSeconds',\n", - " 'hostSeconds',\n", - " 'readReqs',\n", - " 'writeReqs',\n", - " 'servicedByWrQ',\n", - " 'mergedWrBursts',\n", - " 'numTotHits',\n", - " 'numTotMisses',\n", - " 'numColdMisses',\n", - " 'numHotMisses',\n", - " 'numRdMissClean',\n", - " 'numRdMissDirty',\n", - " 'numRdHit',\n", - " 'numWrMissClean',\n", - " 'numWrMissDirty',\n", - " 'numWrHit',\n", - " 'numRdHitDirty',\n", - " 'numRdHitClean',\n", - " 'numWrHitDirty',\n", - " 'numWrHitClean',\n", - " 'numInsts0',\n", - " 'numInsts1',\n", - " 'numInsts2',\n", - " 'numInsts3',\n", - " 'numInsts4',\n", - " 'numInsts5',\n", - " 'numInsts6',\n", - " 'numInsts7',\n", - " 'avgRdBWSys',\n", - " 'avgWrBWSys',\n", - " 'avgORBLen',\n", - " 'farAvgRdBWSys',\n", - " 'farAvgWrBWSys',\n", - " 'locAvgRdBWSys',\n", - " 'locAvgWrBWSys',\n", - " 'readBursts1',\n", - " 'writeBursts1',\n", - " 'readBursts2',\n", - " 'writeBursts2',\n", - " 'readBursts3',\n", - " 'writeBursts3',\n", - " 'loc1AvgRdBW',\n", - " 'loc1AvgWrBW',\n", - " 'loc2AvgRdBW',\n", - " 'loc2AvgWrBW',\n", - " 'farAvgRdBW',\n", - " 'farAvgWrBW',\n", - " 'loc1BusUtil',\n", - " 'loc1BusUtilRead',\n", - " 'loc1BusUtilWrite',\n", - " 'loc2BusUtil',\n", - " 'loc2BusUtilRead',\n", - " 'loc2BusUtilWrite',\n", - " 'farBusUtil',\n", - " 'farBusUtilRead',\n", - " 'farBusUtilWrite',\n", - " 'farBytesRead',\n", - " 'farBytesWritten',\n", - " 'loc1BytesRead',\n", - " 'loc1BytesWritten',\n", - " 'loc2BytesRead',\n", - " 'loc2BytesWritten',\n", - " 'avgTimeTagCheckRes',\n", - " 'avgTimeTagCheckResRd',\n", - " 'avgTimeTagCheckResWr',\n", - " 'avgPktRespTimeRd',\n", - " 'avgPktRespTimeWr',\n", - " 'avgPktORBTime',\n", - " 'avgPktORBTimeRd',\n", - " 'avgPktORBTimeWr',\n", - " 'avgTimeInLocRead',\n", - " 'avgTimeInLocWrite',\n", - " 'avgTimeInFarRead'\n", - "\n", - " ]\n", - "##########################################################\n", - "\n", - "def getStat(filename, stat, index):\n", - " filename = os.path.join(filename).replace('\\\\','/')\n", - " #print(stat)\n", - " #print(filename)\n", - " try:\n", - " x = 0\n", - " with open(filename) as f:\n", - " readlines = f.readlines()\n", - " for l in readlines:\n", - " if stat in l and x < (index-1):\n", - " x = x+1\n", - " elif stat in l and x == (index-1):\n", - " return l\n", - " return 0.0 #for cases where stat was not found\n", - " except: #for cases where the file was not found\n", - " return 0.0\n", - "\n", - "##########################################################\n", - "\n", - "def creatDataFrame(dataDir, suite, index):\n", - " app = []\n", - " if suite == \"GAPBS\":\n", - " app = ['bc', 'bfs', 'cc', 'pr', 'sssp', 'tc']\n", - " if suite == \"NPB\":\n", - " app = ['bt', 'cg', 'ft', 'is', 'lu', 'mg', 'sp', 'ua']\n", - " rows = []\n", - " i = 0\n", - " for a in app:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}/stats.txt'.format(dataDir, a)\n", - " ret_line = getStat(time_file_path, stat, index[i])\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - " i = i+1\n", - " df = pd.DataFrame(rows, columns= dfCols)\n", - " df['totNumInsts'] = df['numInsts0'].astype(int)+df['numInsts1'].astype(int)+df['numInsts2'].astype(int)+df['numInsts3'].astype(int)+df['numInsts4'].astype(int)+df['numInsts5'].astype(int)+df['numInsts6'].astype(int)+df['numInsts7'].astype(int)\n", - " df['totBW'] = (df['avgRdBWSys'].astype(float)+df['avgWrBWSys'].astype(float))/1000000000\n", - " df['coldRate'] = (df['numColdMisses'].astype(float) / df['numTotMisses'].astype(float)) *100\n", - " df['injRate'] = (df['readReqs'].astype(float) + df['writeReqs'].astype(float))*64/1000000000 / df['simSeconds'].astype(float)\n", - " df['BIPS'] = (df['totNumInsts'].astype(float)/1000000000)/df['simSeconds'].astype(float)\n", - " \n", - " df['accAmp'] = (df['farBytesRead'].astype(float) + df['farBytesWritten'].astype(float) +\n", - " df['loc1BytesRead'].astype(float) + df['loc1BytesWritten'].astype(float) + \n", - " df['loc2BytesRead'].astype(float) + df['loc2BytesWritten'].astype(float)) / (df['readReqs'].astype(float) * 64 + df['writeReqs'].astype(float) * 64)\n", - " \n", - " df['BWBloat'] = (df['loc1AvgRdBW'].astype(float) + df['loc1AvgWrBW'].astype(float) +\n", - " df['loc2AvgRdBW'].astype(float) + df['loc2AvgWrBW'].astype(float) +\n", - " df['farAvgRdBW'].astype(float) + df['farAvgWrBW'].astype(float)) / ((df['avgRdBWSys'].astype(float) + df['avgWrBWSys'].astype(float)) / 1000000)\n", - " return df" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "df_gap_22 = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/pcAnalysis/3hour/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [10,7,7,8,10,32])\n", - "df_npb_c = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/pcAnalysis/3hour/1GB_8GB_g22_nC/NPB\", \"NPB\", [9,8,3,8,4,12,12,9])\n", - "df_gap_25 = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/pcAnalysis/3hour/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [10,9,4,6,6,12])\n", - "df_npb_d = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/pcAnalysis/3hour/1GB_85GB_g25_nD/NPB\", \"NPB\", [14,6,2,6,16,9,13,1])\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "df_gap_22_2 = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/pcAnalysis/3hour_1halfChkpt/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [8,6,8,7,5,24])\n", - "df_npb_c_2 = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/pcAnalysis/3hour_1halfChkpt/1GB_8GB_g22_nC/NPB\", \"NPB\", [3,7,3,8,13,11,11,8])\n", - "df_gap_25_2 = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/pcAnalysis/3hour_1halfChkpt/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [6,5,6,4,5,10])\n", - "df_npb_d_2 = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/pcAnalysis/3hour_1halfChkpt/1GB_85GB_g25_nD/NPB\", \"NPB\", [10,4,0,4,13,8,10,0])\n" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0 13.574369\n", - "1 0.772378\n", - "2 0.042189\n", - "3 0.001220\n", - "4 0.000000\n", - "5 15.545457\n", - "dtype: float64\n", - "0 1.069289\n", - "1 2.450410\n", - "2 0.102372\n", - "3 4.181787\n", - "4 6.680209\n", - "5 9.491518\n", - "dtype: float64\n", - "0 0.123416\n", - "1 0.000628\n", - "2 35.656932\n", - "3 13.277294\n", - "4 0.000610\n", - "5 16.376971\n", - "6 0.263860\n", - "7 0.007352\n", - "dtype: float64\n", - "0 6.729032\n", - "1 6.215870\n", - "2 33.964109\n", - "3 12.628388\n", - "4 6.571731\n", - "5 11.891573\n", - "6 7.345704\n", - "7 44.730473\n", - "dtype: float64\n" - ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAACUCAYAAACeNFNKAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAdAElEQVR4nO3deZxU1Zn/8c9XQIlrA6KiRMFdo0YTYkSitiBC1EBnIYvinmCMRo3jmDiZccno7yeTRVAzRJwYF4zGKOASoyGYDlHRCCqCookKjCAoifsGiM/8cU9j0XY31cutqi6+79erXlX31K06T1Xdqn76nHPPUURgZmZmVk02KHcAZmZmZh3NCY6ZmZlVHSc4ZmZmVnWc4JiZmVnVcYJjZmZmVccJjpmZmVWd3BIcSddIelnSvIKynpKmSfp7uu6RyiXpcknPSnpC0qfyisvMzMyqX54tONcCwxuV/QCYHhG7ANPTNsDngV3SZQwwIce4zMzMrMrlluBExAzglUbFI4Hr0u3rgLqC8usj8xBQI6lPXrGZmZlZdSv1GJytI2Jpur0M2Drd3g54oWC/xanMzMzMrNW6lqviiAhJrV4nQtIYsm4sNtlkk0/vvvvuHR6bmTXvmWeeAWC33XYrcyRmZjB79ux/RETvxuWlTnBektQnIpamLqiXU/kS4OMF+/VNZR8REROBiQADBgyIWbNm5RmvmTVSW1sLQH19fVnjMDMDkLSoqfJSd1HdARyfbh8P3F5Qflw6m+oA4PWCriwzMzOzVsmtBUfSTUAtsKWkxcAFwKXALZJOBhYBX0273w0cATwLvAOcmFdcZmZmVv1yS3Ai4hvN3DWkiX0DOK29da5atYrFixfz3nvvtfepKlafPn2oqakpdxhmZmYVrWyDjPOwePFiNttsM/r164ekcofT4d59912WLFniBMfMzGwdqmqphvfee49evXpVZXID0L17d1atWlXuMMzMzCpeVbXgAJ0muVmwYAHHHXcckujbty833HAD77zzDnV1daxatYrNN9+cm266ic0222zNYzrLazMzMyu3qmrB6Uxqamq46667mDFjBv379+fuu++mW7duTJo0iRkzZjBy5EiuvfbacodpZmbWKVVdC06DAy64t12Pf+iiYc3et2LFCkaNGsXKlSupqalhyJAh3HzzzaxatYrevXtzyy238MILL3DMMcfQ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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap_22['app']\n", - "gap_22 = 100 * df_gap_22['numColdMisses'].astype(float)/(df_gap_22['numTotMisses'].astype(float)+df_gap_22['numTotHits'].astype(float))\n", - "gap_25 = 100 * df_gap_25['numColdMisses'].astype(float)/(df_gap_25['numTotMisses'].astype(float)+df_gap_25['numTotHits'].astype(float))\n", - "\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,100])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_22[i], width=1, color=cmap(1), label='gap-22' if i==0 else None)\n", - " plt.bar(i*3+1, gap_25[i], width=1, color=cmap(2), label='gap-25' if i==0 else None)\n", - "\n", - "offset = 17\n", - "app_npb = df_npb_c['app']\n", - "npb_c = 100 * df_npb_c['numColdMisses'].astype(float)/(df_npb_c['numTotMisses'].astype(float)+df_npb_c['numTotHits'].astype(float))\n", - "npb_d = 100 * df_npb_d['numColdMisses'].astype(float)/(df_npb_d['numTotMisses'].astype(float)+df_npb_d['numTotHits'].astype(float))\n", - "\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_c[i], width=1, color=cmap(3), label='npb-C' if i==0 else None)\n", - " plt.bar(offset+i*3+2, npb_d[i], width=1, color=cmap(4), label='npb-D' if i==0 else None)\n", - "\n", - "plt.figtext(0.3, 0.01, \"GAPBS\")\n", - "plt.figtext(0.75, 0.01, \"NPB\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "\n", - "plt.ylabel(\"cold miss ratio %\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_bips.pdf\")\n", - "\n", - "print(gap_22)\n", - "print(gap_25)\n", - "print(npb_c)\n", - "print(npb_d)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0 8.510806\n", - "1 3.012487\n", - "2 0.045814\n", - "3 0.001406\n", - "4 0.867148\n", - "5 23.142106\n", - "dtype: float64\n", - "0 1.868160\n", - "1 0.064662\n", - "2 0.000441\n", - "3 3.308614\n", - "4 5.962230\n", - "5 10.727102\n", - "dtype: float64\n", - "0 0.466393\n", - "1 0.000634\n", - "2 18.562396\n", - "3 13.471984\n", - "4 3.162869\n", - "5 13.837872\n", - "6 2.085634\n", - "7 0.011461\n", - "dtype: float64\n", - "0 9.366265\n", - "1 9.372335\n", - "2 NaN\n", - "3 19.375005\n", - "4 7.491977\n", - "5 7.667257\n", - "6 9.246283\n", - "7 NaN\n", - "dtype: float64\n" - ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAACUCAYAAACeNFNKAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAc4ElEQVR4nO3de7yUZbn/8c9XQElFFyAqSgqeNTUtMpHUJYiQGqwOVJ5PhZmm5jbL3d4e2vr7ye4gqG0SyzymmQIeMo20FYlogoqgaKnAFgSlPJ8A8dp/PPfCYbnWYtbhmZk1fN+v17xmnnuemfua07OudT/3QRGBmZmZWTVZr9wBmJmZmXU0JzhmZmZWdZzgmJmZWdVxgmNmZmZVxwmOmZmZVR0nOGZmZlZ1cktwJF0t6WVJcwvKekmaKukf6bpnKpekyyQ9K+kJSZ/KKy4zMzOrfnm24FwDjGhU9gPgvojYEbgvbQN8HtgxXcYAE3KMy8zMzKpcbglOREwDXmlUPAq4Nt2+FqgrKL8uMg8BNZL65hWbmZmZVbdS98HZIiKWpNtLgS3S7a2BFwr2W5TKzMzMzFqta7kqjoiQ1Op1IiSNITuNxUYbbfTpXXbZpcNjM7PWeeaZZwDYeeedyxyJma1rZs2a9c+I6NO4vNQJzkuS+kbEknQK6uVUvhj4eMF+/VLZR0TERGAiwMCBA2PmzJl5xmtmRaitrQWgvr6+rHGY2bpH0sKmykt9iuoO4Lh0+zjg9oLyY9Noqn2B1wtOZZmZmZm1Sm4tOJJuAmqBzSQtAs4HLgFukXQSsBD4atr9buBQ4FngHeCEvOIyMzOz6pdbghMRRzRz19Am9g3g1PbWuXLlShYtWsR7773X3qeqWH379qWmpqbcYZiZmVW0snUyzsOiRYvo0aMH/fv3R1K5w+lw7777LosXL3aCY2ZmthZVtVTDe++9R+/evasyuQHo3r07K1euLHcYZmZmFa+qWnCATpPczJ8/n2OPPRZJ9OvXj+uvv5533nmHuro6Vq5cySabbMJNN91Ejx49Vj+ms7w2MzOzcquqFpzOpKamhrvuuotp06YxYMAA7r77brp168YNN9zAtGnTGDVqFNdcc025wzQzM+uUqq4Fp8G+59/brsc/dOHwZu9bvnw5o0ePZsWKFdTU1DB06FBuvvlmVq5cSZ8+fbjlllt44YUXOOqoo+jduzcvv/wyN910EwMGDFj9HD179lx9u1u3bnTp0oXu3bvTt2/f1WU+HWVmZtY2RbfgSPqCpHpJD0n6dp5BVbopU6aw3377cc8999CzZ0+6du26ujVm11135f777wfglVdeYdKkSYwfP56xY8c2+VwvvvgiU6dO5ZBDDlld9tZbb3HllVdy5JFHluT1mJmZVZtmExxJezUqOgY4CNgPOCXHmCre/Pnz2XPPPQHYa6+9ePvttznppJM48MADufXWW3nxxRcB2GOPPejatSt77bUXzz77LFOnTqW2tpYzzzwTyFqCjjvuOK666iq6ds0a0yKCE088kYsvvtijpczMzNqopRacUyRdJWnLtP0C8B/AucCLuUdWwQYMGMCcOXMAeOKJJ1i+fDk77bQTf/nLX/jyl79MNq0PzJ07l1WrVjF79my23357hg0bRn19PePGjQNgzJgxnHrqqey2226rn/u8885j8ODBDBkypOSvy8zMrFo0m+BExMnAFcCVks4DzgNmAHOAkaUJrzLV1dUxffp0hg8fztKlS9lss8244447OPzww1mwYMHq/TbffHPq6uo4/fTTOeecc9Z4jhkzZjBp0iTGjRtHbW0tkydP5sUXX2Ts2LFMnjyZ2tpaJkyYUOJXZmZmVh1a7GQcEbOBUZK+QLZu1HURcV1JImunljoJt9cGG2zApEmT6Nq1K6eccgo77bQTjz766Br7LFiwgH79+nHDDTc0+RyDBg3izTff/Ej5ihUrconZzMxsXdJSH5xvSXpQ0oPARsAIoEbSvZIOKFmEFeqwww5j8ODBvPPOOwwaNKjc4ZiZmVmBllpwvh0Re0raAHgwIm4GLpN0PfCfwLS2Virpu8A3gCA75XUC0Be4GegNzAKOiYiKbc64996Wh6H379+/2dYbMzMzy1dLnYwXS/p3smTm6YbCiHg1Is5qa4WStgZOBwZGxO5AF+DrwFjg0ojYAXgVOKmtdZiZmdm6raUEZxRZ68oDwLEdXG9X4GOSugIbAkuAIcCt6f5rgboOrtPMzMzWEc2eokqnh+7s6AojYrGknwD/C7wL/JHslNRrEfF+2m0RsHVH121mZmbrhpKvRSWpJ1nr0ABgKz7swFzs48dImilp5rJly3KKMn/z589n//3354ADDuDII49k1apVAOy8887U1tZSW1vLU089VeYozczMOqdyLLZ5MDA/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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap_22_2['app']\n", - "gap_22 = 100 * df_gap_22_2['numColdMisses'].astype(float)/(df_gap_22_2['numTotMisses'].astype(float)+df_gap_22_2['numTotHits'].astype(float))\n", - "gap_25 = 100 * df_gap_25_2['numColdMisses'].astype(float)/(df_gap_25_2['numTotMisses'].astype(float)+df_gap_25_2['numTotHits'].astype(float))\n", - "\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,100])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_22[i], width=1, color=cmap(1), label='gap-22' if i==0 else None)\n", - " plt.bar(i*3+1, gap_25[i], width=1, color=cmap(2), label='gap-25' if i==0 else None)\n", - "\n", - "offset = 17\n", - "app_npb = df_npb_c_2['app']\n", - "npb_c = 100 * df_npb_c_2['numColdMisses'].astype(float)/(df_npb_c_2['numTotMisses'].astype(float)+df_npb_c_2['numTotHits'].astype(float))\n", - "npb_d = 100 * df_npb_d_2['numColdMisses'].astype(float)/(df_npb_d_2['numTotMisses'].astype(float)+df_npb_d_2['numTotHits'].astype(float))\n", - "\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_c[i], width=1, color=cmap(3), label='npb-C' if i==0 else None)\n", - " plt.bar(offset+i*3+2, npb_d[i], width=1, color=cmap(4), label='npb-D' if i==0 else None)\n", - "\n", - "plt.figtext(0.3, 0.01, \"GAPBS\")\n", - "plt.figtext(0.75, 0.01, \"NPB\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "\n", - "plt.ylabel(\"cold miss ratio %\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_bips.pdf\")\n", - "\n", - "print(gap_22)\n", - "print(gap_25)\n", - "print(npb_c)\n", - "print(npb_d)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "orig_nbformat": 4, - "vscode": { - "interpreter": { - "hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/configs-npb-gapbs/gapbs_restore.py b/configs-npb-gapbs/gapbs_restore.py deleted file mode 100755 index 4ea8c95bc8..0000000000 --- a/configs-npb-gapbs/gapbs_restore.py +++ /dev/null @@ -1,179 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2019 The Regents of the University of California. -# All rights reserved. -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Jason Lowe-Power, Ayaz Akram - -""" Script to run GAP Benchmark suites workloads. - The workloads have two modes: synthetic and real graphs. -""" -import argparse -import time -import m5 -import m5.ticks -from m5.objects import * - -from system import * - -supported_protocols = ["MESI_Two_Level"] -supported_cpu_types = ["kvm", "atomic", "timing"] - - -def writeBenchScript(dir, benchmark_name, size, synthetic): - """ - This method creates a script in dir which will be eventually - passed to the simulated system (to run a specific benchmark - at bootup). - """ - input_file_name = "{}/run_{}_{}".format(dir, benchmark_name, size) - if synthetic: - with open(input_file_name, "w") as f: - f.write("./{} -g {}\n".format(benchmark_name, size)) - elif synthetic == 0: - with open(input_file_name, "w") as f: - # The workloads that are copied to the disk image using Packer - # should be located in /home/gem5/. - # Since the command running the workload will be executed with - # pwd = /home/gem5/gapbs, the path to the copied workload is - # ../{workload-name} - f.write("./{} -sf ../{}".format(benchmark_name, size)) - - return input_file_name - - -def parse_options(): - parser = argparse.ArgumentParser( - description="For use with gem5. This " - "runs a GAPBS applications. This only works " - "with x86 ISA." - ) - - # The manditry position arguments. - parser.add_argument( - "benchmark", type=str, help="The GAPBS application to run" - ) - parser.add_argument("graph", type=str, help="The GAPBS application to run") - parser.add_argument( - "dcache_policy", type=str, help="The architecture of DRAM cache" - ) - parser.add_argument( - "is_link", - type=int, - help="whether to use a link for backing store or not", - ) - parser.add_argument( - "link_lat", type=str, help="latency of the link to backing store" - ) - parser.add_argument( - "checkpoint_path", type=str, help="Path to checkpoint dir" - ) - - return parser.parse_args() - - -if __name__ == "__m5_main__": - args = parse_options() - - kernel = "/home/mbabaie/code-review/dramCacheController/fs-resources/x86-linux-kernel-4.19.83" - disk = ( - "/home/mbabaie/code-review/dramCacheController/fs-resources/x86-gapbs" - ) - num_cpus = 8 - cpu_type = "Timing" - mem_sys = "MESI_Two_Level" - synthetic = 1 - - dcache_size = "" - mem_size = "" - if args.graph == "22": - dcache_size = "512MiB" - mem_size = "8GiB" - elif args.graph == "25": - dcache_size = "512MiB" - mem_size = "85GiB" - - # create the system we are going to simulate - system = MyRubySystem( - kernel, - disk, - mem_sys, - num_cpus, - dcache_size, - mem_size, - args.dcache_policy, - args.is_link, - args.link_lat, - args, - restore=True, - ) - - system.m5ops_base = 0xFFFF0000 - - # Exit from guest on workbegin/workend - system.exit_on_work_items = True - - # Create and pass a script to the simulated system to run the reuired - # benchmark - system.readfile = writeBenchScript( - m5.options.outdir, args.benchmark, args.graph, synthetic - ) - - # set up the root SimObject and start the simulation - root = Root(full_system=True, system=system) - - if system.getHostParallel(): - # Required for running kvm on multiple host cores. - # Uses gem5's parallel event queue feature - # Note: The simulator is quite picky about this number! - root.sim_quantum = int(1e9) # 1 ms - - # needed for long running jobs - m5.disableAllListeners() - - # instantiate all of the objects we've created above - m5.instantiate(args.checkpoint_path) - - globalStart = time.time() - - print("Running the simulation ************************************** \n") - print("Simulating 100 intervals of 10ms each! \n") - - numIteration = 0 - - if args.benchmark == "bfs": - numIteration = 360 - elif args.benchmark == "cc": - numIteration = 280 - elif args.benchmark == "sssp": - numIteration = 160 - else: - numIteration = 100 - - for interval_number in range(numIteration): - print("Interval number: {} \n".format(interval_number)) - exit_event = m5.simulate(10000000000) - m5.stats.dump() - - print("End of simulation ******************************************** \n") diff --git a/configs-npb-gapbs/npb_restore.py b/configs-npb-gapbs/npb_restore.py deleted file mode 100755 index 224af6d58c..0000000000 --- a/configs-npb-gapbs/npb_restore.py +++ /dev/null @@ -1,222 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2019 The Regents of the University of California. -# All rights reserved. -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Jason Lowe-Power, Ayaz Akram - -""" Script to run NAS parallel benchmarks with gem5. - The script expects kernel, diskimage, mem_sys, - cpu (kvm, atomic, or timing), benchmark to run - and number of cpus as arguments. - - If your application has ROI annotations, this script will count the total - number of instructions executed in the ROI. It also tracks how much - wallclock and simulated time. -""" -import argparse -import time -import m5 -import m5.ticks -from m5.objects import * - -from system import * - - -def writeBenchScript(dir, bench): - """ - This method creates a script in dir which will be eventually - passed to the simulated system (to run a specific benchmark - at bootup). - """ - file_name = "{}/run_{}".format(dir, bench) - bench_file = open(file_name, "w+") - bench_file.write("/home/gem5/NPB3.3-OMP/bin/{} \n".format(bench)) - - # sleeping for sometime (5 seconds here) makes sure - # that the benchmark's output has been - # printed to the console - bench_file.write("sleep 5 \n") - bench_file.write("m5 exit \n") - bench_file.close() - return file_name - - -supported_protocols = [ - "classic", - "MI_example", - "MESI_Two_Level", - "MOESI_CMP_directory", -] -supported_cpu_types = ["kvm", "atomic", "timing"] -benchmark_choices = [ - "bt.A.x", - "cg.A.x", - "ep.A.x", - "ft.A.x", - "is.A.x", - "lu.A.x", - "mg.A.x", - "sp.A.x", - "bt.B.x", - "cg.B.x", - "ep.B.x", - "ft.B.x", - "is.B.x", - "lu.B.x", - "mg.B.x", - "sp.B.x", - "bt.C.x", - "cg.C.x", - "ep.C.x", - "ft.C.x", - "is.C.x", - "lu.C.x", - "mg.C.x", - "sp.C.x", - "bt.D.x", - "cg.D.x", - "ep.D.x", - "ft.D.x", - "is.D.x", - "lu.D.x", - "mg.D.x", - "sp.D.x", - "bt.F.x", - "cg.F.x", - "ep.F.x", - "ft.F.x", - "is.F.x", - "lu.F.x", - "mg.F.x", - "sp.F.x", -] - - -def parse_options(): - - parser = argparse.ArgumentParser( - description="For use with gem5. This " - "runs a NAS Parallel Benchmark application. This only works " - "with x86 ISA." - ) - - # The manditry position arguments. - parser.add_argument( - "benchmark", - type=str, # choices=benchmark_choices, - help="The NPB application to run", - ) - parser.add_argument( - "class_size", type=str, help="The NPB application class to run" - ) - parser.add_argument( - "dcache_policy", - type=str, - help="The architecture of DRAM cache: " - "CascadeLakeNoPartWrs, Oracle, BearWriteOpt, Rambus", - ) - parser.add_argument( - "is_link", - type=int, - help="whether to use a link for backing store or not", - ) - parser.add_argument( - "link_lat", type=str, help="latency of the link to backing store" - ) - parser.add_argument( - "checkpoint_path", type=str, help="Path to checkpoint dir" - ) - return parser.parse_args() - - -if __name__ == "__m5_main__": - args = parse_options() - - kernel = "/home/mbabaie/code-review/dramCacheController/fs-resources/x86-linux-kernel-4.19.83" - disk = "/home/mbabaie/code-review/dramCacheController/fs-resources/x86-npb" - num_cpus = 8 - cpu_type = "Timing" - mem_sys = "MESI_Two_Level" - - dcache_size = "" - mem_size = "" - if args.class_size == "C": - dcache_size = "128MiB" - mem_size = "16GiB" - elif args.class_size == "D": - dcache_size = "512MiB" - mem_size = "85GiB" - - benchmark = args.benchmark + "." + args.class_size + ".x" - - system = MyRubySystem( - kernel, - disk, - mem_sys, - num_cpus, - dcache_size, - mem_size, - args.dcache_policy, - args.is_link, - args.link_lat, - args, - restore=True, - ) - - system.m5ops_base = 0xFFFF0000 - - # Exit from guest on workbegin/workend - system.exit_on_work_items = True - - # Create and pass a script to the simulated system to run the reuired - # benchmark - system.readfile = writeBenchScript(m5.options.outdir, benchmark) - - # set up the root SimObject and start the simulation - root = Root(full_system=True, system=system) - - if system.getHostParallel(): - # Required for running kvm on multiple host cores. - # Uses gem5's parallel event queue feature - # Note: The simulator is quite picky about this number! - root.sim_quantum = int(1e9) # 1 ms - - # needed for long running jobs - m5.disableAllListeners() - - # instantiate all of the objects we've created above - m5.instantiate(args.checkpoint_path) - - globalStart = time.time() - - print("Running the simulation ************************************** \n") - print("Simulating 100 intervals of 10ms each! \n") - - for interval_number in range(100): - print("Interval number: {} \n".format(interval_number)) - exit_event = m5.simulate(10000000000) - m5.stats.dump() - - print("End of simulation ******************************************** \n") diff --git a/configs-npb-gapbs/restore_both.py b/configs-npb-gapbs/restore_both.py index b661bcacd2..feb0984399 100755 --- a/configs-npb-gapbs/restore_both.py +++ b/configs-npb-gapbs/restore_both.py @@ -203,9 +203,9 @@ def run(): if __name__ == "__m5_main__": args = parse_options() - kernel = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-linux-kernel-4.19.83" - disk = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-npb" - ckpt_base = "/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/chkpt1GigDC/" + kernel = "/fullSystemDisksKernel/x86-linux-kernel-4.19.83" + disk = "/fullSystemDisksKernel/x86-npb" + ckpt_base = "/chkpt1GigDC/" num_cpus = 8 cpu_type = "Timing" diff --git a/configs-npb-gapbs/system/ruby_system.py b/configs-npb-gapbs/system/ruby_system.py deleted file mode 100755 index 7390af62fc..0000000000 --- a/configs-npb-gapbs/system/ruby_system.py +++ /dev/null @@ -1,294 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2016 Jason Lowe-Power -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Jason Lowe-Power - -import m5 -from m5.objects import * -from .fs_tools import * - - -class MyRubySystemOld(System): - - def __init__(self, kernel, disk, mem_sys, num_cpus, opts, restore=False): - super(MyRubySystemOld, self).__init__() - self._opts = opts - - # Use parallel if using KVM. Don't use parallel is restoring cpt - self._host_parallel = not restore - self._restore = restore - - # Set up the clock domain and the voltage domain - self.clk_domain = SrcClockDomain() - self.clk_domain.clock = '5GHz' - self.clk_domain.voltage_domain = VoltageDomain() - - self.mem_ranges = [AddrRange(Addr('3GiB')), # All data - AddrRange(0xC0000000, size=0x100000), # For I/0 - ] - - self.initFS(num_cpus) - - # Replace these paths with the path to your disk images. - # The first disk is the root disk. The second could be used for swap - # or anything else. - self.setDiskImages(disk, disk) - - # Change this path to point to the kernel you want to use - self.workload.object_file = kernel - # Options specified on the kernel command line - boot_options = ['earlyprintk=ttyS0', 'console=ttyS0', 'lpj=7999923', - 'root=/dev/hda1'] - - self.workload.command_line = ' '.join(boot_options) - - # Create the CPUs for our system. - self.createCPU(num_cpus) - - # self.intrctrl = IntrControl() - self.createMemoryControllers() - - # Create the cache hierarchy for the system. - if mem_sys == 'MI_example': - from .MI_example_caches import MIExampleSystem - self.caches = MIExampleSystem() - elif mem_sys == 'MESI_Two_Level': - from .MESI_Two_Level import MESITwoLevelCache - self.caches = MESITwoLevelCache() - elif mem_sys == 'MOESI_CMP_directory': - from .MOESI_CMP_directory import MOESICMPDirCache - self.caches = MOESICMPDirCache() - if self._restore: - cpus = self.o3Cpu - else: - cpus = self.cpu - self.caches.setup(self, cpus, self.mem_ctrl, self.mem_ranges[:1], - [self.pc.south_bridge.ide.dma, - self.iobus.mem_side_ports], - self.iobus) - - self.caches.access_backing_store = True - self.caches.phys_mem = [SimpleMemory(range=self.mem_ranges[0], - in_addr_map=False)] - - if self._host_parallel: - # To get the KVM CPUs to run on different host CPUs - # Specify a different event queue for each CPU - for i,cpu in enumerate(self.cpu): - for obj in cpu.descendants(): - obj.eventq_index = 0 - - # the number of eventqs are set based - # on experiments with few benchmarks - - cpu.eventq_index = i + 1 - - def getHostParallel(self): - return self._host_parallel - - def totalInsts(self): - return sum([cpu.totalInsts() for cpu in self.cpu]) - - def createCPUThreads(self, cpu): - for c in cpu: - c.createThreads() - - def createCPU(self, num_cpus): - - if not self._restore: - # Note KVM needs a VM and atomic_noncaching - self.cpu = [X86KvmCPU(cpu_id = i) - for i in range(num_cpus)] - self.kvm_vm = KvmVM() - self.mem_mode = 'atomic_noncaching' - self.createCPUThreads(self.cpu) - - self.atomicCpu = [X86AtomicSimpleCPU(cpu_id = i, - switched_out = True) - for i in range(num_cpus)] - self.createCPUThreads(self.atomicCpu) - - self.timingCpu = [X86TimingSimpleCPU(cpu_id = i, - switched_out = True) - for i in range(num_cpus)] - self.createCPUThreads(self.timingCpu) - - self.o3Cpu = [X86O3CPU(cpu_id = i, - switched_out = True) - for i in range(num_cpus)] - self.createCPUThreads(self.o3Cpu) - else: - self.o3Cpu = [X86O3CPU(cpu_id = i) - for i in range(num_cpus)] - self.mem_mode = 'timing' - self.createCPUThreads(self.o3Cpu) - - def switchCpus(self, old, new): - assert(new[0].switchedOut()) - m5.switchCpus(self, list(zip(old, new))) - - def setDiskImages(self, img_path_1, img_path_2): - disk0 = CowDisk(img_path_1) - disk2 = CowDisk(img_path_2) - self.pc.south_bridge.ide.disks = [disk0, disk2] - - def createMemoryControllers(self): - - self.mem_ctrl = PolicyManager(range=self.mem_ranges[0], kvm_map=False) - self.mem_ctrl.static_frontend_latency = "10ns" - self.mem_ctrl.static_backend_latency = "10ns" - - self.mem_ctrl.loc_mem_policy = 'Rambus' # 'CascadeLakeNoPartWrs' # 'Oracle' # - - # self.mem_ctrl.bypass_dcache = True - - # TDRAM cache - self.loc_mem_ctrl = MemCtrl() - self.loc_mem_ctrl.consider_oldest_write = True - self.loc_mem_ctrl.oldest_write_age_threshold = 2500000 - self.loc_mem_ctrl.dram = TDRAM_32(range=self.mem_ranges[0], in_addr_map=False, kvm_map=False) - - - self.mem_ctrl.loc_mem = self.loc_mem_ctrl.dram - self.loc_mem_ctrl.static_frontend_latency = "1ns" - self.loc_mem_ctrl.static_backend_latency = "1ns" - self.loc_mem_ctrl.static_frontend_latency_tc = "0ns" - self.loc_mem_ctrl.static_backend_latency_tc = "0ns" - - # main memory - self.far_mem_ctrl = MemCtrl() - self.far_mem_ctrl.dram = DDR4_2400_16x4(range=self.mem_ranges[0], in_addr_map=False, kvm_map=False) - self.far_mem_ctrl.static_frontend_latency = "1ns" - self.far_mem_ctrl.static_backend_latency = "1ns" - - self.loc_mem_ctrl.port = self.mem_ctrl.loc_req_port - self.far_mem_ctrl.port = self.mem_ctrl.far_req_port - - self.mem_ctrl.orb_max_size = 128 - self.mem_ctrl.dram_cache_size = "128MiB" - - self.loc_mem_ctrl.dram.read_buffer_size = 64 - self.loc_mem_ctrl.dram.write_buffer_size = 64 - - self.far_mem_ctrl.dram.read_buffer_size = 64 - self.far_mem_ctrl.dram.write_buffer_size = 64 - - - - def initFS(self, cpus): - self.pc = Pc() - - self.workload = X86FsLinux() - - # North Bridge - self.iobus = IOXBar() - - # connect the io bus - # Note: pass in a reference to where Ruby will connect to in the future - # so the port isn't connected twice. - self.pc.attachIO(self.iobus, [self.pc.south_bridge.ide.dma]) - - ############################################### - - # Add in a Bios information structure. - self.workload.smbios_table.structures = [X86SMBiosBiosInformation()] - - # Set up the Intel MP table - base_entries = [] - ext_entries = [] - for i in range(cpus): - bp = X86IntelMPProcessor( - local_apic_id = i, - local_apic_version = 0x14, - enable = True, - bootstrap = (i ==0)) - base_entries.append(bp) - io_apic = X86IntelMPIOAPIC( - id = cpus, - version = 0x11, - enable = True, - address = 0xfec00000) - self.pc.south_bridge.io_apic.apic_id = io_apic.id - base_entries.append(io_apic) - pci_bus = X86IntelMPBus(bus_id = 0, bus_type='PCI ') - base_entries.append(pci_bus) - isa_bus = X86IntelMPBus(bus_id = 1, bus_type='ISA ') - base_entries.append(isa_bus) - connect_busses = X86IntelMPBusHierarchy(bus_id=1, - subtractive_decode=True, parent_bus=0) - ext_entries.append(connect_busses) - pci_dev4_inta = X86IntelMPIOIntAssignment( - interrupt_type = 'INT', - polarity = 'ConformPolarity', - trigger = 'ConformTrigger', - source_bus_id = 0, - source_bus_irq = 0 + (4 << 2), - dest_io_apic_id = io_apic.id, - dest_io_apic_intin = 16) - base_entries.append(pci_dev4_inta) - def assignISAInt(irq, apicPin): - assign_8259_to_apic = X86IntelMPIOIntAssignment( - interrupt_type = 'ExtInt', - polarity = 'ConformPolarity', - trigger = 'ConformTrigger', - source_bus_id = 1, - source_bus_irq = irq, - dest_io_apic_id = io_apic.id, - dest_io_apic_intin = 0) - base_entries.append(assign_8259_to_apic) - assign_to_apic = X86IntelMPIOIntAssignment( - interrupt_type = 'INT', - polarity = 'ConformPolarity', - trigger = 'ConformTrigger', - source_bus_id = 1, - source_bus_irq = irq, - dest_io_apic_id = io_apic.id, - dest_io_apic_intin = apicPin) - base_entries.append(assign_to_apic) - assignISAInt(0, 2) - assignISAInt(1, 1) - for i in range(3, 15): - assignISAInt(i, i) - self.workload.intel_mp_table.base_entries = base_entries - self.workload.intel_mp_table.ext_entries = ext_entries - - entries = \ - [ - # Mark the first megabyte of memory as reserved - X86E820Entry(addr = 0, size = '639kB', range_type = 1), - X86E820Entry(addr = 0x9fc00, size = '385kB', range_type = 2), - # Mark the rest of physical memory as available - X86E820Entry(addr = 0x100000, - size = '%dB' % (self.mem_ranges[0].size() - 0x100000), - range_type = 1), - ] - - # Reserve the last 16kB of the 32-bit address space for m5ops - entries.append(X86E820Entry(addr = 0xFFFF0000, size = '64kB', - range_type=2)) - - self.workload.e820_table.entries = entries diff --git a/data-plots.ipynb b/data-plots.ipynb deleted file mode 100644 index 84a5a7818e..0000000000 --- a/data-plots.ipynb +++ /dev/null @@ -1,2874 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "import numpy as np\n", - "import sys\n", - "from matplotlib import pyplot as plt\n", - "import os\n", - "import statistics\n", - "\n", - "cmap = plt.get_cmap('Set1')\n", - "\n", - "Stats = ['simSeconds ',\n", - "'hostSeconds ',\n", - "'system.mem_ctrl.readReqs ',\n", - "'system.mem_ctrl.writeReqs ',\n", - "'system.mem_ctrl.servicedByWrQ ',\n", - "'system.mem_ctrl.mergedWrBursts ',\n", - "'system.mem_ctrl.numTotHits ',\n", - "'system.mem_ctrl.numTotMisses ',\n", - "'system.mem_ctrl.numColdMisses ',\n", - "'system.mem_ctrl.numHotMisses ',\n", - "'system.mem_ctrl.numRdMissClean ',\n", - "'system.mem_ctrl.numRdMissDirty ',\n", - "'system.mem_ctrl.numRdHit ',\n", - "'system.mem_ctrl.numWrMissClean ',\n", - "'system.mem_ctrl.numWrMissDirty ',\n", - "'system.mem_ctrl.numWrHit ',\n", - "'system.mem_ctrl.numRdHitDirty ',\n", - "'system.mem_ctrl.numRdHitClean ',\n", - "'system.mem_ctrl.numWrHitDirty ',\n", - "'system.mem_ctrl.numWrHitClean ',\n", - "'system.o3Cpu0.thread_0.numInsts ',\n", - "'system.o3Cpu1.thread_0.numInsts ',\n", - "'system.o3Cpu2.thread_0.numInsts ',\n", - "'system.o3Cpu3.thread_0.numInsts ',\n", - "'system.o3Cpu4.thread_0.numInsts ',\n", - "'system.o3Cpu5.thread_0.numInsts ',\n", - "'system.o3Cpu6.thread_0.numInsts ',\n", - "'system.o3Cpu7.thread_0.numInsts ',\n", - "'system.mem_ctrl.avgRdBWSys ',\n", - "'system.mem_ctrl.avgWrBWSys ',\n", - "'system.mem_ctrl.avgORBLen ',\n", - "'system.far_mem_ctrl.avgRdBWSys ',\n", - "'system.far_mem_ctrl.avgWrBWSys ',\n", - "'system.loc_mem_ctrl.avgRdBWSys ',\n", - "'system.loc_mem_ctrl.avgWrBWSys ',\n", - "'system.loc_mem_ctrl.dram.readBursts ',\n", - "'system.loc_mem_ctrl.dram.writeBursts ',\n", - "'system.loc_mem_ctrl.dram_2.readBursts ',\n", - "'system.loc_mem_ctrl.dram_2.writeBursts ',\n", - "'system.far_mem_ctrl.dram.readBursts ',\n", - "'system.far_mem_ctrl.dram.writeBursts ',\n", - "'system.loc_mem_ctrl.dram.avgRdBW ',\n", - "'system.loc_mem_ctrl.dram.avgWrBW ',\n", - "'system.loc_mem_ctrl.dram_2.avgRdBW ',\n", - "'system.loc_mem_ctrl.dram_2.avgWrBW ',\n", - "'system.far_mem_ctrl.dram.avgRdBW ',\n", - "'system.far_mem_ctrl.dram.avgWrBW ',\n", - "'system.loc_mem_ctrl.dram.busUtil ',\n", - "'system.loc_mem_ctrl.dram.busUtilRead ',\n", - "'system.loc_mem_ctrl.dram.busUtilWrite ',\n", - "'system.loc_mem_ctrl.dram_2.busUtil ',\n", - "'system.loc_mem_ctrl.dram_2.busUtilRead ',\n", - "'system.loc_mem_ctrl.dram_2.busUtilWrite ',\n", - "'system.far_mem_ctrl.dram.busUtil ',\n", - "'system.far_mem_ctrl.dram.busUtilRead ',\n", - "'system.far_mem_ctrl.dram.busUtilWrite ',\n", - "'system.far_mem_ctrl.dram.bytesRead ',\n", - "'system.far_mem_ctrl.dram.bytesWritten ',\n", - "'system.loc_mem_ctrl.dram.bytesRead ',\n", - "'system.loc_mem_ctrl.dram.bytesWritten ',\n", - "'system.loc_mem_ctrl.dram_2.bytesRead ',\n", - "'system.loc_mem_ctrl.dram_2.bytesWritten ',\n", - "'system.mem_ctrl.avgTimeTagCheckRes ',\n", - "'system.mem_ctrl.avgTimeTagCheckResRd ',\n", - "'system.mem_ctrl.avgTimeTagCheckResWr ',\n", - "'system.mem_ctrl.avgPktRespTimeRd ',\n", - "'system.mem_ctrl.avgPktRespTimeWr ',\n", - "'system.mem_ctrl.avgPktORBTime ',\n", - "'system.mem_ctrl.avgPktORBTimeRd ',\n", - "'system.mem_ctrl.avgPktORBTimeWr ',\n", - "'system.mem_ctrl.avgTimeInLocRead ',\n", - "'system.mem_ctrl.avgTimeInLocWrite ',\n", - "'system.mem_ctrl.avgTimeInFarRead ',\n", - "'system.mem_ctrl.missRatio ',\n", - "'system.loc_mem_ctrl.dram.actDelayedDueToTagAct ',\n", - "'system.loc_mem_ctrl.noCandidBSlot ',\n", - "'system.loc_mem_ctrl.foundCandidBSlot ',\n", - "'system.loc_mem_ctrl.foundCandidBSlotRH ',\n", - "'system.loc_mem_ctrl.foundCandidBSlotRMC ',\n", - "'system.loc_mem_ctrl.foundCandidBSlotRMD ',\n", - "'system.loc_mem_ctrl.dram.readMC',\n", - "'system.loc_mem_ctrl.dram.writeBurstsTC'\n", - " ]\n", - "\n", - "dfCols = [\n", - " 'app',\n", - " 'simSeconds',\n", - " 'hostSeconds',\n", - " 'readReqs',\n", - " 'writeReqs',\n", - " 'servicedByWrQ',\n", - " 'mergedWrBursts',\n", - " 'numTotHits',\n", - " 'numTotMisses',\n", - " 'numColdMisses',\n", - " 'numHotMisses',\n", - " 'numRdMissClean',\n", - " 'numRdMissDirty',\n", - " 'numRdHit',\n", - " 'numWrMissClean',\n", - " 'numWrMissDirty',\n", - " 'numWrHit',\n", - " 'numRdHitDirty',\n", - " 'numRdHitClean',\n", - " 'numWrHitDirty',\n", - " 'numWrHitClean',\n", - " 'numInsts0',\n", - " 'numInsts1',\n", - " 'numInsts2',\n", - " 'numInsts3',\n", - " 'numInsts4',\n", - " 'numInsts5',\n", - " 'numInsts6',\n", - " 'numInsts7',\n", - " 'avgRdBWSys',\n", - " 'avgWrBWSys',\n", - " 'avgORBLen',\n", - " 'farAvgRdBWSys',\n", - " 'farAvgWrBWSys',\n", - " 'locAvgRdBWSys',\n", - " 'locAvgWrBWSys',\n", - " 'readBursts1',\n", - " 'writeBursts1',\n", - " 'readBursts2',\n", - " 'writeBursts2',\n", - " 'readBursts3',\n", - " 'writeBursts3',\n", - " 'loc1AvgRdBW',\n", - " 'loc1AvgWrBW',\n", - " 'loc2AvgRdBW',\n", - " 'loc2AvgWrBW',\n", - " 'farAvgRdBW',\n", - " 'farAvgWrBW',\n", - " 'loc1BusUtil',\n", - " 'loc1BusUtilRead',\n", - " 'loc1BusUtilWrite',\n", - " 'loc2BusUtil',\n", - " 'loc2BusUtilRead',\n", - " 'loc2BusUtilWrite',\n", - " 'farBusUtil',\n", - " 'farBusUtilRead',\n", - " 'farBusUtilWrite',\n", - " 'farBytesRead',\n", - " 'farBytesWritten',\n", - " 'loc1BytesRead',\n", - " 'loc1BytesWritten',\n", - " 'loc2BytesRead',\n", - " 'loc2BytesWritten',\n", - " 'avgTimeTagCheckRes',\n", - " 'avgTimeTagCheckResRd',\n", - " 'avgTimeTagCheckResWr',\n", - " 'avgPktRespTimeRd',\n", - " 'avgPktRespTimeWr',\n", - " 'avgPktORBTime',\n", - " 'avgPktORBTimeRd',\n", - " 'avgPktORBTimeWr',\n", - " 'avgTimeInLocRead',\n", - " 'avgTimeInLocWrite',\n", - " 'avgTimeInFarRead',\n", - " 'missRatio',\n", - " 'actDelayedDueToTagAct',\n", - " 'noCandidBSlot',\n", - " 'foundCandidBSlot',\n", - " 'foundCandidBSlotRH',\n", - " 'foundCandidBSlotRMC',\n", - " 'foundCandidBSlotRMD',\n", - " 'readBurstsMC',\n", - " 'writeBurstsTC'\n", - "\n", - " ]\n", - "##########################################################\n", - "\n", - "def getStat(filename, stat, index):\n", - " filename = os.path.join(filename).replace('\\\\','/')\n", - " #print(stat)\n", - " #print(filename)\n", - " try:\n", - " x = 0\n", - " with open(filename) as f:\n", - " readlines = f.readlines()\n", - " for l in readlines:\n", - " if stat in l and x < (index-1):\n", - " x = x+1\n", - " elif stat in l and x == (index-1):\n", - " return l\n", - " return 0.0 #for cases where stat was not found\n", - " except: #for cases where the file was not found\n", - " return 0.0\n", - "\n", - "##########################################################\n", - "\n", - "def creatDataFrame(dataDir, suite, index):\n", - " app = []\n", - " if suite == \"GAPBS\":\n", - " app = ['bc', 'bfs', 'cc', 'pr', 'sssp', 'tc']\n", - " if suite == \"NPB\":\n", - " app = ['bt', 'cg', 'ft', 'is', 'lu', 'mg', 'sp', 'ua']\n", - " rows = []\n", - " i = 0\n", - " for a in app:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}/stats.txt'.format(dataDir, a)\n", - " ret_line = getStat(time_file_path, stat, index[i])\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - " i = i+1\n", - " df = pd.DataFrame(rows, columns= dfCols)\n", - " df['totNumInsts'] = df['numInsts0'].astype(int)+df['numInsts1'].astype(int)+df['numInsts2'].astype(int)+df['numInsts3'].astype(int)+df['numInsts4'].astype(int)+df['numInsts5'].astype(int)+df['numInsts6'].astype(int)+df['numInsts7'].astype(int)\n", - " df['totBW'] = (df['avgRdBWSys'].astype(float)+df['avgWrBWSys'].astype(float))/1000000000\n", - " df['coldRate'] = (df['numColdMisses'].astype(float) / (df['numTotMisses'].astype(float)+df['numTotHits'].astype(float))) *100\n", - " df['injRate'] = (df['readReqs'].astype(float) + df['writeReqs'].astype(float))*64/1000000000 / df['simSeconds'].astype(float)\n", - " df['BIPS'] = (df['totNumInsts'].astype(float)/1000000000)/df['simSeconds'].astype(float)\n", - " \n", - " df['accAmp'] = (df['farBytesRead'].astype(float) + df['farBytesWritten'].astype(float) +\n", - " df['loc1BytesRead'].astype(float) + df['loc1BytesWritten'].astype(float) + \n", - " df['loc2BytesRead'].astype(float) + df['loc2BytesWritten'].astype(float)) / (df['readReqs'].astype(float) * 64 + df['writeReqs'].astype(float) * 64)\n", - " \n", - " df['BWBloat'] = (df['loc1AvgRdBW'].astype(float) + df['loc1AvgWrBW'].astype(float) +\n", - " df['loc2AvgRdBW'].astype(float) + df['loc2AvgWrBW'].astype(float) +\n", - " df['farAvgRdBW'].astype(float) + df['farAvgWrBW'].astype(float)) / ((df['avgRdBWSys'].astype(float) + df['avgWrBWSys'].astype(float)) / 1000000)\n", - " \n", - "\n", - " df['locMemReadBursts'] = df['readBursts1'].astype(float) + df['readBurstsMC'].astype(float)\n", - " df['locMemWriteBursts'] = df['writeBursts1'].astype(float) + df['writeBurstsTC'].astype(float)\n", - " \n", - " \n", - " return df" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "df_gap22_cas = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/cascade/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", - "df_npbC_cas = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/cascade/1GB_8GB_g22_nC/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", - "\n", - "df_gap25_cas = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/cascade/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", - "df_npbD_cas = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/cascade/1GB_85GB_g25_nD/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", - "\n", - "df_gap22_ram = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/rambus/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", - "df_npbC_ram = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/rambus/1GB_8GB_g22_nC/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", - "\n", - "df_gap25_ram = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/rambus/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", - "df_npbD_ram = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/rambus/1GB_85GB_g25_nD/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", - "\n", - "\n", - "df_gap22_orc = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/oracle/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", - "df_npbC_orc = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/oracle/1GB_8GB_g22_nC/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", - "\n", - "df_gap25_orc = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/oracle/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", - "df_npbD_orc = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/oracle/1GB_85GB_g25_nD/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", - "\n", - "df_gap22_noDC = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/noDC/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", - "df_npbC_noDC = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/noDC/1GB_8GB_g22_nC/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", - "\n", - "df_gap25_noDC = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/noDC/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", - "df_npbD_noDC = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/noDC/1GB_85GB_g25_nD/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "df_gap22_ram_prob = creatDataFrame(\"/home/babaie/projects/rambusDesign/tagProbOptRealImplOnSetAssoBranch/dramCacheController/newResults/rambusTagPr/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [7,5,7,6,5,15])\n", - "df_npbC_ram_prob = creatDataFrame(\"/home/babaie/projects/rambusDesign/tagProbOptRealImplOnSetAssoBranch/dramCacheController/newResults/rambusTagPr/1GB_8GB_g22_nC/NPB\", \"NPB\",[3,6,3,6,11,8,8,7])\n", - "\n", - "df_gap25_ram_prob = creatDataFrame(\"/home/babaie/projects/rambusDesign/tagProbOptRealImplOnSetAssoBranch/dramCacheController/newResults/rambusTagPr/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [4,4,5,4,4,7])\n", - "df_npbD_ram_prob = creatDataFrame(\"/home/babaie/projects/rambusDesign/tagProbOptRealImplOnSetAssoBranch/dramCacheController/newResults/rambusTagPr/1GB_85GB_g25_nD/NPB\", \"NPB\",[7,4,2,3,9,5,7,1])\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAACXCAYAAAAYoCHkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAcAUlEQVR4nO3de5hU1Znv8e8PRVs9KAHRMCJCoiESb5GWiEEl4i3GDJKjqMcx6GCYZMzES8QoM9HEo0GjER01ZghGiZp4i5cM8RIP0mKMN1AQFWWIgdiGCBIvYCSKvuePvVqLtrq6uqvr0sXv8zz9dO21d+31dtWuXW+vvfZaigjMzMzM6kmPagdgZmZm1tWc4JiZmVndcYJjZmZmdccJjpmZmdUdJzhmZmZWd5zgmJmZWd0pW4Ij6WeSVkh6Jqesj6T7Jf1P+v2xVC5J/ylpiaSnJe1ZrrjMzMys/pWzBec64NBWZWcBsyJiJ2BWWgb4IrBT+pkIXF3GuMzMzKzOlS3BiYg5wF9bFY8BZqTHM4Ajcsp/HplHgd6S+pcrNjMzM6tvle6Ds21ELE+P/wJsmx5vB7yUs11zKjMzMzPrsI2rVXFEhKQOzxMhaSLZZSy22GKLYZ/+9Ke7PDYza9sLL7wAwJAhQ6ociZkZzJs379WI6Ne6vNIJziuS+kfE8nQJakUqfxnYPme7AansIyJiGjANoLGxMebOnVvOeM2slVGjRgHQ1NRU1TjMzAAkLctXXulLVL8GxqfH44G7csq/mu6m2ht4I+dSlpmZmVmHlK0FR9IvgVHA1pKagXOBC4FbJE0AlgHj0uZ3A4cBS4C/ASeWKy4zMzOrf2VLcCLi2DZWjc6zbQAnlysWMzOzanj33Xdpbm5m7dq11Q6lLjQ0NDBgwAB69uzZ7rZV62RsZmZW75qbm+nVqxeDBg1CUrXD6dYiglWrVtHc3MzgwYPb3d5TNZiZmZXJ2rVr6du3r5ObLiCJvn37Ft0a5gTHzMysjCqV3MyaNYtRo0ax3377MXbsWFatWlWWepYuXcoJJ5zQ7nbXXXcd06dPb3e7kSNHFl13R15LX6IyMzPr5lauXMl5553HzJkz6dWrF4sXL+add96pdlhV5QTHzMysAvY+976Snv/o9w9pc93dd9/N8ccfT69evQD41Kc+BcC1117LjBkzWLNmDT/4wQ84+OCDmTx5MnPmzKFnz57ceOON9OjRgxNPPJG3336bESNGMGXKFMaNG8crr7zCpptuym233caWW27JOeecw+zZsxk6dOgH9c6cOZMf/vCHrFu3jnPOOYdDD209BeX68u0Xsv41p5xyCvvssw+jR49mwoQJrF69mp133pkf//jHnXq9fInKzMysm1u+fDn9+390Csejjz6apqYmZs2axSWXXALAww8/zJw5c5g9ezb9+/dnypQpnHbaaTQ1NXHBBRcA2eWlBx98kHHjxnHzzTezfPlyHn/8cR566CH2339/AN5//30uueQSHnjgAZqamrj44ovbjbP1fluceuqpjBgxgmOOOYYLL7yQs88+m9mzZ9OrVy8eeeSRTr0mbsExMzPr5vr378+f//znj5Tfd999XH755UQEK1ZkkweceeaZjB8/nr59+3LBBRewePHiDxKbHj168N577zFp0iQWLlzIm2++ydixY1m2bBm77bYbAMOGDeO3v/0tr776KosWLeLAAw8EYMWKFUREm/1k8u0XYPHixTQ0NHDZZZcBsGjRIs466ywksWbNGoYPH96p18QtOGZmZt3cYYcdxg033MDq1asBWLJkCcuXL2fKlCncc8893HXXXfTokX3lH3DAAVx//fVss802zJw5kyFDhvDoo48CWavM/Pnzeeutt5gzZw4nn3wyEcEOO+zAwoULAXjqqacA2Hrrrdl1112ZNWsWTU1NLFiwoGAn4Hz7hexy2rHHHsukSZOAbJ67Sy+9lKamJubOncuYMWM69Zq4BcfMzKyb69evH9/97nc5/PDDiQj69OnDNddcw+GHH85+++3H8OHD6d27NwBjxozh7bffBuDWW29l//33Z/z48Zx//vnss88+TJ48mSVLlnDooYey/fbbs91229G/f3+GDRvGvvvuy+677w5krT2nn346o0ePRhJDhw7lqquuWi+uSy+9lJtuugmAqVOnfmS/LSZMmMCUKVO46KKLmDx5MhMnTuSNN96gR48eTJ8+nUGDBnX4NVFLBtUdebJNs8rzZJtmxVu0aBE777xztcOoK61fU0nzIqKx9XbtXqJKE2D+k6Rz0vJASZ27IGZmZmZWAcX0wfkxMAJomVtqNXBV25u3T9Jpkp6V9IykX0pqkDRY0mOSlki6WdImpdRhZmZmG65iEpzPRcTJwFqAiHgN6HTyIWk74FtAY0TsAmwEHANcBEyNiB2B14AJna3DzMzMNmzFJDjvStoICABJ/YD3S6x3Y2AzSRsDmwPLgQOA29L6GcARJdZhZmZWdd25r2ut6chrWUyC85/AHcA2ki4AfgdM6VxoEBEvA5cAfyJLbN4A5gGvR8S6tFkzsF3+PZiZmXUPDQ0NrFq1yklOF2iZTbyhoaGo7du9TTwibpQ0DxgNCDgiIhZ1NkBJHwPGAIOB14FbgcJjO6///InARICBAwd2NgwzM7OyGzBgAM3NzaxcubLaodSFhoYGBgwYUNS27SY4kq6PiOOB5/OUdcaBwB8jYmXa1+3A54HekjZOrTgDgJfzPTkipgHTILtNvJMxmJmZlV3Pnj0ZPHhwtcPYIBVzieozuQupP86wEur8E7C3pM2VDXk4GngOmA0cmbYZD9xVQh1mZma2AWszwZF0tqTVwG6S3pS0Oi2voITkIyIeI+tM/CSwMMUwDfgOcLqkJUBf4JrO1mFmZmYbtjYvUUXEFGCKpCkRcXZXVhoR5wLntip+EfAAgmZmZlayYjoZn506Bu8ENOSUzylnYGZmZmadVUwn45OAU8g6/s4H9gYeIRu3xszMzKzmFNPJ+BRgL2BZRHwB+CzZ7d1mZmZmNamYBGdtRKwFkLRpRDwPDClvWGZmZmad1+4lKqBZUm/gTuB+Sa8By8oZlJmZmVkpiulkPDY9/J6k2cBWwD1ljcrMzMysBMVcovpARDxINqv43eUJx8zMzKx0hQb6O0DSYklrJN0gaVdJc8km2ry6ciGamZmZdUyhFpwfkU1q2Zds5OFHgOsiYlhE3F6J4MzMzMw6o1AfnIiIpvT4TkkvR8SVFYjJzMzMrCSFEpzekr6Su23usltxzMzMrFYVSnAeBL6cszwnZzkAJzhmZmZWkwpNtnliuSpN4+pMB3YhS5b+GXgBuBkYBCwFxkXEa+WKwczMzOpXh24T70KXA/dGxKeB3YFFwFnArIjYCZiVls3MzMw6rOIJjqStgP2AawAi4p2IeB0YA8xIm80Ajqh0bGZmZlYfqtGCMxhYCVwr6SlJ0yVtAWwbEcvTNn8Btq1CbGZmZlYH2k1wJB0lqVd6/B+Sbpe0Zwl1bgzsCVwdEZ8F3qLV5aiICLK+OfnimShprqS5K1euLCEMMzMzq1fFtOB8NyJWSxoJHEh2aamUkYybgeaIeCwt30aW8LwiqT9A+r0i35MjYlpENEZEY79+/UoIw8zMzOpVMQnOe+n3l4BpEfEbYJPOVhgRfwFekjQkFY0GngN+DYxPZeOBuzpbh5mZmW3Y2p1NHHhZ0n8BBwEXSdqU0vvu/Btwo6RNgBeBE9M+b5E0AVgGjCuxDjMzM9tAFZPgjAMOBS6JiNfT5aNJpVQaEfOBxjyrRpeyXzMzMzMoLsHpD/wmIv4uaRSwG/DzcgZlZmZmVopiLjX9CnhP0o7ANGB74BdljcrMzMysBMUkOO9HxDrgK8AVETGJrFXHzMzMrCYVk+C8K+lY4KvAzFTWs3whmZmZmZWmmATnRGAEcEFE/FHSYOD68oZlZmZm1nntdjKOiOeAb+Us/xG4qJxBmZmZmZWizQRH0i0RMU7SQvJMmxARu5U1MjMzM7NOKtSCc0r6fXglAjEzMzPrKm0mOC0ze0fEssqFY2ZmZla6QpeoVrP+pSmlZZFN+L1lmWMzMzMz65RCl6hmAR8Hbgduiog/VSYkMzMzs9K0eZt4RBwBHAKsBH4q6UFJ/yqpT1dULGkjSU9JmpmWB0t6TNISSTeniTjNzMzMOqzgODgR8UZEXAt8Efgv4DzghC6q+xRgUc7yRcDUiNgReA2Y0EX1mJmZ2QamYIIjaR9JVwBPAvsAYyPi0lIrlTQA+BIwPS0LOAC4LW0yAzii1HrMzMxsw1Sok/FS4HXgJmAisC6V7wkQEU+WUO9lwJlAr7TcF3g9zXkF0AxsV8L+zczMbANWqJPxUrK7pg4BDia7e6pFkLW4dJikw4EVETFP0qhOPH8iWcLFwIEDOxOCmZmZ1blC4+CMKlOdnwf+UdJhQAOwJXA50FvSxqkVZwDwchtxTQOmATQ2Nn5khGUzMzOzYibb7FIRcXZEDIiIQcAxwAMRcRwwGzgybTYeuKvSsZmZmVl9qHiCU8B3gNMlLSHrk3NNleMxMzOzbqrd2cTLKSKagKb0+EVgeDXjMTMzs/pQ6C6qPQs9scS7qMzMzMzKplALzo/S7wagEVhAdifVbsBcYER5QzMzM7Nq2vvc+0rex6PfP6QLIum4QlM1fCEivgAsB/aMiMaIGAZ8ljbucDIzMzOrBcV0Mh4SEQtbFiLiGWDn8oVkZmZmVppiOhk/LWk6cENaPg54unwhmZmZmZWmmATnROAbZJNjAswBri5bRGZmZmYlajfBiYi1wNT0Y2ZmZlbzCt0mvpBszqm8ImK3skRkZmZmVqJCLTiHVywKMzMzsy5UaLLNZS2PJW0L7JUWH4+IFeUOzMzMzKyz2r1NXNI44HHgKGAc8JikIws/y8zMzKx6irmL6t+BvVpabST1A/4fcFtnKpS0PfBzYFuyPj7TIuJySX2Am4FBwFJgXES81pk6zMzMbMNWzEB/PVpdklpV5PPasg74dkQMBfYGTpY0FDgLmBUROwGz0rKZmZlZhxXTgnOvpPuAX6blo4F7OlthRCwnm/6BiFgtaRGwHTAGGJU2m0E2y/h3OluPmZmZbbiKGQdnkqSvACNT0bSIuKMrKpc0iGxuq8eAbVPyA/AXsktYZmZmZh1WaBycHcmSjocj4nbg9lQ+UtInI+IPpVQs6X8BvwJOjYg3JX2wLiJCUt4xeCRNBCYCDBw4sJQQzMwqqjvPzGzW3RRqwbkMODtP+Rtp3Zc7W6mknmTJzY0peQJ4RVL/iFguqT+Q91b0iJgGTANobGxscyBCMzPLrysSLXCyZbWtUGfhbXNnEW+RygZ1tkJlTTXXAIsi4tKcVb8GxqfH44G7OluHmZmZbdgKteD0LrBusxLq/DxwPLBQ0vxUNhm4ELhF0gRgGdmYO2ZmZmYdVijBmSvpaxHx09xCSScB8zpbYUT8DlAbq0d3dr9mZmZmLQolOKcCd0g6jg8TmkZgE2BsmeMyMzMz67RCc1G9Auwj6QvALqn4NxHxQEUiMzMzM+ukYsbBmQ3MrkAsZmZmZl2ilCkXzMzMzGqSIrrvUDK9evWKYcOGVTsMsw3K/PnzAdhjjz2qGkd39OTSv5a8jz0H9amJOKBrYrHaVivHbCEPPvjgvIhobF1ezFxUZtZNdIeTkZlZJXTrBGfIkCE0NTVVOwyzmtEVI9Q2tTM67ahRo7LtCnz2ammk3FqaHqES70+l4oCuicU+qt4+P+U+TnKnesrlPjhmZmZWd7p1C46ZmXVv9dbC5vm5aodbcMzMzKzuuAXHrET+r8/MrPa4BcfMzMzqTk214Eg6FLgc2AiYHhEXVjkkq1G1dJeBmZnVnppJcCRtBFwFHAQ0A09I+nVEPFeNePwFamZm1n3V0iWq4cCSiHgxIt4BbgLGVDkmMzMz64ZqpgUH2A54KWe5GfhclWKpKe7EamZm1jE1MxeVpCOBQyPipLR8PPC5iPhmq+0mAhPT4hDghYoGur6tgVerWH+uWomlVuIAx5JPrcQBjiWfWokDHEs+tRIHOJZcO0REv9aFtdSC8zKwfc7ygFS2noiYBkyrVFCFSJqbb4KvaqiVWGolDnAstRwHOJZajgMcSy3HAY6lGLXUB+cJYCdJgyVtAhwD/LrKMZmZmVk3VDMtOBGxTtI3gfvIbhP/WUQ8W+WwzMzMrBuqmQQHICLuBu6udhwdUBOXypJaiaVW4gDHkk+txAGOJZ9aiQMcSz61Egc4lnbVTCdjMzMzs65SS31wzMzMzLqEE5wiSRok6ZlajEHSvpKelTRf0mbViM1qk6Tekv612nFAweP3VEmbVyOmWiHpW5IWSXpL0tAqxvH7atWdS9Kaasdg3Z8TnPpwHDAlIvaIiLerHUwtS1OCbEh6AzWR4BRwKrBBJzhk79FBwK1A1RKciNinWnWbdTUnOB2zsaQb039at0naXNJekn4vaYGkxyX1qnAM3wLGAf83lfeXNCe15jwjad9yBiPpq5KeTn//9ZK2lXRHWl4gqWInzNRC8Hye92ippIskPQkc1YX1bSHpN+nvfEbS0ZIulPRcek0uSdsdldYvkDQnlZ0g6S5JTZL+R9K5XRVXKxcCn0zHw8WSviNpYYqlGpPZ5jt+/wGYLWl2JQLIc8x+UtKj6XU5v9KtB5J+AnwC+CMwHrg4vV+frGQcKZY16XdFzyMF4hklaWbO8pWSTihznS3nkeskLU7H64GSHk6f1eGS+km6P7WcT5e0TNLWZYwp37lmqaQfpuP2cUk7lqv+nDjWa4WVdIak70n6mqQnUny/Uq20yEaEf4r4AQYBAXw+Lf8MOBN4EdgrlW0JbFzhGM4ArgOOTGXfBv49Pd4I6FXGeD4DLAa2Tst9gJuBU3Pq36rK79EZwFLgzDLU97+Bn+Ys70A2snZL5/3e6fdCYLtWZScAy4G+wGbAM0BjmV6TZ9LjLwK/BzZveb8q9d4U8f5sXaEY8h2zM4Fj0/LXgTWVfF1SvUvJRoP94LNcjZ+Wv72S55F24hgFzMwpvxI4ocx1DwLWAbuSNQLMS8eqyOZHvDPFcXba/tB0XJftGM5zrtkqHTMt79FXc1+nMr82z+QsnwF8D+ibU3Y+8G+VPF7a+nELTse8FBEPp8c3AIcAyyPiCYCIeDMi1lU4hpGt1j8BnCjpe8CuEbG6jLEcANwaEa8CRMRfU9nVafm9iHijjPXn09brc3MZ6loIHJRah/YlG3l7LXCNpK8Af0vbPQxcJ+lrZF8WLe6PiFWRXVa8nY++l13tQODaiPgbfPB+VVp7x2+55TtmR5BdGgL4RYXjqVWVPI/Uoj9GxMKIeB94FpgV2bf3QrIv+ZFkE0ITEfcCr5U5nvXONTnn1V/m/B5R5hgK2UXSQ5IWknWZ+EwVY/mAE5yOaX1P/Zs1EMN6yxExB9iP7Mv2OklfrVRgNaKt1+etLq8oYjGwJ9nJ53xgMjAcuA04HLg3bfd14D/IpiKZJ6lvO7HWsw3xb+52aug8so71v6caKlTv33Mev5+z/D5VGD+u9blG0jktq3I3q0Aobb0f1wHfjIhdge9TufepICc4HTNQUkuW/H+AR4H+kvYCkNRLUrkP/tYx/C53paQdgFci4qfAdLIPRbk8ABzV8oUtqQ8wC/hGWt5I0lZlrD+fgq9PV5L0D8DfIuIG4GKyL4StIhuw8jRg97TdJyPisYg4B1jJh3OuHSSpj7I7344ga+npaquBln5h95P9V755iqtPGeprT773JzfGcst3zD5KdgkAsiliqqmSr0WbKnweKWQZMFTSppJ6A6OrFEdrD5P1fUTSwcDHyllZnnNNy/txdM7vR8oZQ/IKsI2kvpI2JftHDrJjdrmknmQtODXBCU7HvACcLGkR2QF9BdmBdYWkBWRfIOXOXFvHcHWr9aOABZKeSrFdXq5AIptK4wLgwfT3XwqcAnwhNVXOo/J3hLT3+nSlXYHHJc0HziX7z2WmpKfJvrhPT9tdnDoCPkPWB2ZBKn8c+BXwNPCriJjb1QFGxCrg4VT3aLL53eammM/o6vqKkO/9mQbcW4lOxm0cs6cCp6f3bUeg0pdVc90ETJL0VDU6GecYRYXOI4VExEvALWR91G4BnqpGHHl8Hzg4fa6OAv5ClpyWS+tzzfmp/GPpuD2F7J+qsoqId4HzyM5d9wPPp1XfBR4jS/yez//syvNIxlY3JA0i62i3S7VjaU+6E6QxIr5Z7Vg2dKlF6+2ICEnHkHU4HlPtuKx2pdaL9yKbQ3EEcHVE7FHhGJaSnUNerWS93UlNzUVlZlYFw4ArJQl4Hfjn6oZj3cBA4BZJPYB3gK9VOR7Lwy04ZmZmVnfcB8fMzMzqjhMcMzMzqztOcMzMzKzuOMGxbkPZPFe/kPSipHmSHpE0Nmf9ZZJeTh3/WspOkLRS2Zw6z6XRhFuXP6s0b1Vat7ekx9K6RWk013zx3CjpBWVzw/wsjQHRMn/OG+n583MG5TKzEkkKST/KWT6j5TOqbF6kl/XhHFr/mKf8eUlX554nWu3/vZzzwgJJ325rW6ttftOsW0h3uNwJzImIT0TEMLJB2Qak9T2AscBLwP6tnn5zuoVzFPADSdvmlkfEZ8juhGgZNGsGMDE9Zxey8TfyuRH4NNkYFZsBJ+Wseyjte4+IOK9Tf7SZ5fN34Ctqe3LLqemzexTws5zkpKV8KNlntvV5osXbOeeFg8jmcCvXZLhWRk5wrLs4AHgnIn7SUhARyyLiirQ4imzOmKuBY/PtICJWAH8gmxTzA8pGn96CD+eT2YZsIsyW+bSea2N/d0dCNvDVgM79aWbWAevIBocsOLBdRCxK27ZOhDYhG5C13fmj0jljIvDN9E+WdSNOcKy7+AzwZIH1x5JNOHcH8KWWy0W5JH0C+ASwJBUdnUYGfZlsVun/TuVTgRck3SHpXyQVHJ061XU8ae6pZERq3r5HUk1MPGdWR64CjlOBqWAkfY5s7qiVqei09HlfDiyOiPnFVBQRL5JNkrtNKQFb5TnBsW5J0lUpgXhC0ibAYcCdEfEm2ZDhh+Rs3pLI/BL4l5xZtFsuXX2cbBK7SQDpklIj8Fuy+ZJyE5d8fkx26eyhtPwksENE7E42ncedpfytZra+9Dn/OfCtPKtbEplLgKPjw8HeWi5RbQNskUattjrmBMe6i2fJmfAvIk4mm1upH1ky0xtYmIYvH8n6l6la+tp8LiLuaL3jdAL8b7LJMlvK/hARV6c6dlc2udx9qfPh9JbtJJ2bYjg957lvRsSa9PhuoGeB/gJm1jmXARPILi/nmpo+7/vm/NPxgTSf0r3AfpK2z7kZ4Ov5Kkktv+8BK7o2fCs3JzjWXTwANEj6Rk7Z5un3scBJETEoIgYBg8lm6t6c4o0k65+DpC/lXG/fiezk9npEHJJOnCel7U4iS66OjYj3W3Yk6eMtz5c0nOxztqpjf66ZFZJaYm8hS3KKlj6bnwf+EBEv5dwM8JM82/YDfgJcmdMSZN2E56KybiFNhHgEMFXSmWTX1d8iu7thKvD1nG3fkvQ74Mvt7PZoSSPJEpBm4IRUfnyq529knRSPi4j38jz/J8Ay4JGUz9yeLm8dCXxD0jrgbeAYnxzNyuJHQLET1p4m6Z+AnsDTZJeW89ksXeLqSfb5v55s1nnrZjwXlZmZmdUdX6IyMzOzuuMEx8zMzOqOExwzMzOrO05wzMzMrO44wTEzM7O64wTHzMzM6o4THDMzM6s7TnDMzMys7vx/sS+N/7XKpJkAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_cas['app']\n", - "gap_22_cas = df_gap22_cas['coldRate'].astype(float)\n", - "\n", - "gap_25_cas = df_gap25_cas['coldRate'].astype(float)\n", - "\n", - "app_npb = df_npbC_cas['app']\n", - "npb_C_cas = df_npbC_cas['coldRate'].astype(float)\n", - "\n", - "npb_D_cas = df_npbD_cas['coldRate'].astype(float)\n", - "\n", - "# Multi bar Chart1\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,100])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*2, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - "\n", - "offset = i*2+1\n", - "for i,app in enumerate(app_npb):\n", - " plt.bar(offset+i*2+1, npb_C_cas[i], width=1, color=cmap(1))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=10, color='black')\n", - "\n", - "plt.ylabel(\"Cold Miss Rate\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "\n", - "# Multi bar Chart2\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,100])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*2, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - "\n", - "offset = i*2+1\n", - "for i,app in enumerate(app_npb):\n", - " plt.bar(offset+i*2+1, npb_D_cas[i], width=1, color=cmap(1))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=10, color='black')\n", - "\n", - "plt.ylabel(\"Cold Miss Rate\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAACXCAYAAAAYoCHkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAcjUlEQVR4nO3de7xVVb338c8XJREPSiIagghaopiaQSZeSQzRKLQjoo8ZGsmpx1I0L0gnTVPRMi+n1B7ChLzkNdNDXl8oD2XeIEQwgsgkMRSkVDA8CvzOH3NsW2wXe6299rrtxff9eu3XWnPMueb47bXmmvu3xxxzDEUEZmZmZo2kQ60DMDMzMys3JzhmZmbWcJzgmJmZWcNxgmNmZmYNxwmOmZmZNRwnOGZmZtZwKpbgSPqZpOWS5ueUbSvpUUl/So8fTuWS9F+SFkt6XtInKxWXmZmZNb5KtuBMAYY1KxsPTI+IjwHT0zLAkcDH0s9Y4IYKxmVmZmYNrmIJTkTMBP7erHgEMDU9nwocnVP+88g8BXSV1KNSsZmZmVljq3YfnB0iYll6/iqwQ3reE3g5Z7ulqczMzMys1TavVcUREZJaPU+EpLFkl7HYaqutBuy+++5lj83MNm7hwoUA9OvXr8aRmJnB7NmzX4+I7s3Lq53gvCapR0QsS5eglqfyV4Cdcrbrlco+ICImAZMABg4cGLNmzapkvGbWzODBgwGYMWNGTeMwMwOQtCRfebUvUd0PjE7PRwP35ZR/Od1NtT/wZs6lLDMzM7NWqVgLjqRfAIOB7SQtBS4ELgfulDQGWAIclzZ/ADgKWAz8EzilUnGZmZlZ46tYghMRJ2xk1ZA82wZwWqViMTMzq4X33nuPpUuX8s4779Q6lIbQqVMnevXqRceOHQtuW7NOxmZmZo1u6dKldOnShT59+iCp1uG0axHBypUrWbp0KX379i24vadqMDMzq5B33nmHbt26ObkpA0l069at6NYwJzhmZmYVVK3kZvr06QwePJhDDjmEY445hpUrV1aknpdeeomTTz654HZTpkxh8uTJBbc76KCDiq67Ne9lwUtUknoBxwMHAzsCa4D5wK+BByNifdG1mZmZWdmtWLGCiy++mGnTptGlSxcWLVrEu+++W+uwaqrFBEfSTWQjCk8DriAbt6YTsBvZPFPfljQ+TctgZmZmG7H/hQ+36fVPXXTERtc98MADnHTSSXTp0gWA3XbbDYCbbrqJqVOnsnr1ai677DKGDh3KhAkTmDlzJh07duTWW2+lQ4cOnHLKKaxZs4ZBgwYxceJEjjvuOF577TW22GIL7r77brbeemsuuOACHn/8cfr37/9+vdOmTeP73/8+a9eu5YILLmDYsOZTUG4o334h619zxhlncMABBzBkyBDGjBnDqlWr2GOPPbj++utLer8KteD8MCLm5ymfD/xS0oeA3iXVbGZmZmWxbNky9tprrw+Ujxo1ilNOOYU333yTkSNHMnToUJ544glmzpxJhw4diAjGjRvHmWeeydChQ1m/PrsoM2XKFDp37szkyZO54447GD58OM888wy/+c1vuO2223jkkUdYv349V155JY899hjr16/nyCOPLJjgNN/vqaeeCsC4ceMYNGgQxx9/PN/61rc4//zzGTRoEOeddx5PPvkkgwYNavV70mKCky+5kbQr0Dki5kXEu2Rj15iZmVmN9OjRg7/97W8fKH/44Ye59tpriQiWL88mDzj33HMZPXo03bp149JLL2XRokVceumlAHTo0IF169ZxzjnnMG/ePN566y2OOeYYlixZwt577w3AgAEDeOSRR3j99ddZsGABhx9+OADLly8nIjbaTybffgEWLVpEp06duOaaawBYsGAB48ePRxKrV69mv/32K+k9aVUnY0kTgG8DZ0i6uaQazczMrKyOOuoobrnlFlatWgXA4sWLWbZsGRMnTuTBBx/kvvvuo0OH7E/+YYcdxs0338z222/PtGnT6NevH0899RQA69ev57nnnuPtt99m5syZnHbaaUQEO++8M/PmzQNgzpw5AGy33XbstddeTJ8+nRkzZjB37twWOwHn2y9kl9NOOOEEzjnnHCCb5+6qq65ixowZzJo1ixEjRpT0nhTqg3M6cF1ErEtF+0TEqLTu+ZJqNDMzs7Lq3r073/nOdxg+fDgRwbbbbsuNN97I8OHDOeSQQ9hvv/3o2rUrACNGjGDNmjUA3HXXXRx66KGMHj2aSy65hAMOOIAJEyawePFihg0bxk477UTPnj3p0aMHAwYM4OCDD2afffYBstaes846iyFDhiCJ/v37c911120Q11VXXcXtt98OwNVXX/2B/TYZM2YMEydO5IorrmDChAmMHTuWN998kw4dOjB58mT69OnT6vdETRlU3pXSicDJwI8i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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAACXCAYAAAAYoCHkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAbvklEQVR4nO3de5yVZb338c8XxUbaKAloCCqoSWloJZEoIh7CE4m2RfQpAlPZlWV4VvYu063b3JmHJ936GCZuDxvPUWxDfGE8mHkCFdFINhkmioGU4AFT4Lf/uK+xxbhm1po1c681s/i+X695zbrPv7nXve51zXVd9/VTRGBmZmZWT7rUOgAzMzOz9uYCjpmZmdUdF3DMzMys7riAY2ZmZnXHBRwzMzOrOy7gmJmZWd3ZPM+dSzodOBkIYCFwItAHmAb0BOYD4yLivZb206tXr+jfv3+eoZpZM1544QUABg4cWONIzMw+bP78+a9HRO+m85XXODiS+gK/AXaPiLWS7gTuB44A7o2IaZKuBxZExHUt7Wvw4MExb968XOI0s5aNGDECgDlz5tQ0DjOzYiTNj4jBTefn3US1ObClpM2BbsBy4CDg7rT8ZuDonGMwMzOzTUxuBZyIeAW4HPgTWcFmNVmT1BsRsS6ttgzom1cMZmZmtmnKrQ+OpI8Bo4EBwBvAXcBhrdh+IjARYMcdd8whQjMzs3y9//77LFu2jHfffbfWodSFhoYG+vXrR9euXUuum2cn40OAP0bESgBJ9wL7AT0kbZ5qcfoBrxTbOCJuAG6ArA9OjnGamW0S9rnggXbZz2MXHtou+9kULFu2jO7du9O/f38k1TqcTi0iWLVqFcuWLWPAgAEl18+zD86fgH0kdVP2rh4M/A74NXBsWmc8MD3HGMzMzGrm3XffpWfPni7ctANJ9OzZs+zasDz74DxO1pn4KbJHxLuQ1cicC5whaQnZo+I35hWDmZlZrblw035acy5zfYoqIi6IiE9GxKcjYlxE/C0iXoyIIRGxa0SMiYi/5RmDmZnZpmD27NmMGDGC4cOHc8wxx7Bq1apcjrN06VImTJhQcr2pU6cyZcqUkusNGzasHaL6sFwH+jMzM7NMW/tAtdT3aeXKlVx00UXMmDGD7t27s3jxYt57r8UxdOteyRocSf0knSVpuqQnJc2V9B+SjpTkVA9mZmY1dv/99zNu3Di6d+8OwG677UafPn246aabGDFiBIMHD2bWrFkATJ48mWHDhnHggQfy6quv8tprr3H44YczYsQIzj//fACOO+44DjjgAEaOHMmaNWsA+P73v8/+++/PpZde+sFxZ8yYwfDhw9l3332ZOXNmyTiL7ReyDsSnnXYa06ZNY+XKlRx11FEceOCBfOtb36r4nLRYgyPpJrJxamYAlwErgAZgN7JHvv9Z0nkRMbfiCMzMzGqoHp4uW758OYMGDfrQ/LFjx3LiiSeyevVqxowZw8iRI3nkkUeYO3cuXbp0ISKYNGkSp59+OiNHjmTDhg1A1rzUrVs3pkyZwh133MGoUaN44oknePjhh7n99tuZNWsWGzZs4PLLL+ehhx5iw4YNHH744Rx2WMujwTTd7ymnnALApEmTGDp0KMcffzxnnnkm559/PkOHDuXcc8/l0UcfZejQoa0+J6WaqH4cEc8Vmf8ccK+kLQAPUmNmZlZDffr04dVXX/3Q/AceeICrr76aiGDFihUAnHPOOYwfP56ePXtyySWXsHjxYi655BIAunTpwvr16zn77LNZuHAha9as4ZhjjuGll15izz33BGDvvfdm1qxZvP766yxatIhDDjkEgBUrVhARzXYELrZfgMWLF9PQ0MBVV10FwKJFizjvvPOQxFtvvcWQIUMqOictNjEVK9xI2kXSoLT8vYhYUtGRzczMrF0cccQR3Hrrrbz55psALFmyhOXLl3PppZfyq1/9iunTp9OlS/aVf9BBB3HLLbew7bbbMmPGDAYOHMhjjz0GwIYNG3jmmWd4++23mTt3LqeeeioRwU477cTChQsBePrppwHo1asXgwYNYvbs2cyZM4cFCxa0+JRTsf1C1px2wgkncPbZZwNZYt8rrriCOXPmMG/ePEaPHl3ROWlVJ2NJk4FdgQ2SPhIR4yo6qpmZmbWb3r17873vfY9Ro0YREWyzzTbceOONjBo1iuHDhzNkyBB69OgBwOjRo1m7di0Ad911FwcccADjx4/n4osvZt9992Xy5MksWbKEww47jB122IG+ffvSp08f9t57b/bff3/22msvIKvtOeOMMzj44IORxO6778611167UVxXXHEF06ZNA+DKK6/80H4bnXTSSVx66aVcdtllTJ48mYkTJ7J69Wq6dOnClClT6N+/f6vPSYvZxCWdBlwbEevT9B0RMTa9fjYi9mz1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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_cas['app']\n", - "gap_22_cas = df_gap22_cas['missRatio'].astype(float)-df_gap22_cas['coldRate'].astype(float)\n", - "\n", - "gap_25_cas = df_gap25_cas['missRatio'].astype(float)-df_gap25_cas['coldRate'].astype(float)\n", - "\n", - "app_npb = df_npbC_cas['app']\n", - "npb_C_cas = df_npbC_cas['missRatio'].astype(float)-df_npbC_cas['coldRate'].astype(float)\n", - "\n", - "npb_D_cas = df_npbD_cas['missRatio'].astype(float)-df_npbD_cas['coldRate'].astype(float)\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,100])\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*2, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - "\n", - "offset = i*2+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*2+1, npb_C_cas[i], width=1, color=cmap(1))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "\n", - "plt.ylabel(\"Hot Miss Rate (%)\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "#plt.ylim([0,55])\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*2, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - "\n", - "offset = i*2+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*2+1, npb_D_cas[i], width=1, color=cmap(1))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "\n", - "plt.ylabel(\"Hot Miss Rate (%)\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAACXCAYAAAAYoCHkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAc70lEQVR4nO3de5yVVd338c8XRUlvFEE0FBVSM8lDCZl4RDE1s5DuRHl8FLkxOlieUlPuxPLW0DQP5aEIUzTLU5pFpPkgI2aeQEVUlEghh0ZFbw9omgK/549rjW7Gzew9e/ZpNt/36zWvva+1r32t3+zDNb9Za11rKSIwMzMzayTdah2AmZmZWbk5wTEzM7OG4wTHzMzMGo4THDMzM2s4TnDMzMys4TjBMTMzs4ZTsQRH0i8lvSTpiZyy3pLukvS3dLtRKpekn0haKOlxSbtUKi4zMzNrfJVswbkGOKhN2enAjIjYFpiRtgE+D2ybfsYDV1YwLjMzM2twFUtwImIW8L9tikcAU9P9qcChOeXXRuYBoJekfpWKzczMzBpbtcfgbBoRLen+C8Cm6f7mwPM5+zWnMjMzM7MOW7tWFUdESOrwOhGSxpN1Y7H++usP/sQnPlH22Mxs9Z555hkAtttuuxpHYmYGc+bMeTki+rYtr3aC86KkfhHRkrqgXkrlS4Atcvbrn8o+JCImA5MBhgwZErNnz65kvGbWxrBhwwBoamqqaRxmZgCSFucrr3YX1e+BMen+GOD2nPKj09VUuwGv53RlmZmZmXVIxVpwJP0GGAZsLKkZOAs4D7hJ0jhgMTAq7T4dOBhYCPwLGFupuMzMzKzxVSzBiYjRq3loeJ59AziuUrGYmZnVwnvvvUdzczPvvPNOrUNpCD169KB///5079694L5FJTiShgB7AZsBbwNPAHdFxKudCdTMzKyRNTc307NnTwYMGICkWofTpUUEr7zyCs3NzQwcOLDg/u2OwZE0VtIjwBnAR4BnyAYG7wn8P0lTJW1ZhrjNzMwazjvvvEOfPn2c3JSBJPr06VN0a1ihQcbrAXtExH9GxA8jYkpEXBYRx0fEYOBistmHzczMLI9qJTczZsxg2LBh7L333owcOZJXXnmlIvUsWrSIY445puB+11xzDVOmTCm435577ll03R15LdvtooqIyws8/ljRNZmZmVlFLF26lLPPPptp06bRs2dPFixYwLvvvlvrsGqqQ4OMJX0R+A7Qg2xphSsqEpWZmVmD2e2sOzv1/Ad+cOBqH5s+fTpHHXUUPXv2BODjH/84AFdffTVTp07lzTff5Ic//CEHHHAAEyZMYNasWXTv3p3rr7+ebt26MXbsWN5++22GDh3KpEmTGDVqFC+++CLrrrsut9xyCxtssAETJ05k5syZDBo06P16p02bxo9+9COWL1/OxIkTOeigtktQrirfcSEbX3PCCSew++67M3z4cMaNG8eyZcvYfvvtueKK0lKNQmNwPtWm6ChgX2B34Bsl1WhmZmZl1dLSQr9+H17C8fDDD6epqYkZM2Zw4YUXAnDfffcxa9YsZs6cSb9+/Zg0aRInnXQSTU1NnHvuuUDWvXTPPfcwatQobrzxRlpaWnjooYe499572WeffQBYuXIlF154IXfffTdNTU1ccMEFBeNse9xWJ554IkOHDuWII47gvPPO44wzzmDmzJn07NmT+++/v6TXpFALzjckdQPOjIgXyNaL+h6wEvhnSTWamZlZWfXr149//vPDf5bvvPNOLr30UiKCl17KFg847bTTGDNmDH369OHcc89lwYIF7yc23bp1Y8WKFZx66qnMmzePN954g5EjR7J48WJ22mknAAYPHsyf//xnXn75ZebPn8/+++8PwEsvvURErHacTL7jAixYsIAePXpwySWXADB//nxOP/10JPHmm2+y6667lvSatNuCExFfAy4Dfi5pIjARuB+YB3yppBrNzMysrA4++GB+9atfsWzZMgAWLlxIS0sLkyZN4k9/+hO333473bplf/L3228/rrvuOjbZZBOmTZvGdtttxwMPPABkrTKPPfYYb731FrNmzeK4444jIthqq62YN28eAI8++igAG2+8MTvuuCMzZsygqamJuXPntjsION9xIetOGz16NKeeeiqQrXN30UUX0dTUxOzZsxkxYkRJr0nBMTgRMRcYkcbf3E429ubakmozMzOzsuvbty9nnnkmhxxyCBFB7969ueqqqzjkkEPYe++92XXXXenVqxcAI0aM4O233wbg5ptvZp999mHMmDGcc8457L777kyYMIGFCxdy0EEHscUWW7D55pvTr18/Bg8ezF577cXOO+8MZK09J598MsOHD0cSgwYN4vLLV7026aKLLuKGG24A4OKLL/7QcVuNGzeOSZMmcf755zNhwgTGjx/P66+/Trdu3ZgyZQoDBgzo8Gui1gwq74PS14Gj0+ZPgFuAbwJfAM6NiFkdrrGMvNimWfV5sU2z4s2fP5/tt9++1mE0lLavqaQ5ETGk7X6F5sH5ZkTsTjaw+NSIWB4RPwGOAA4tY7xmZmZmZVOoi2qJpAlkE/493VqYlmg4udRKJZ0EHAsE2XiesUA/4AagDzAHOCoi1uyL+M3MzKwkhVpwRpAlIH/hg66qTpG0OXA8MCQidgDWImsROh+4OCK2AV4FxpWjPjMzM1vzFEpwNouIP0TEHRGxou2DyvQvod61gY9IWpusdagF2I9sjA/AVNwFZmZmDaC9sa7WMR15LQt1UV2Q5sG5nazbaCnZLMbbkI3LGQ6cBTR3ILglki4E/kG2Mvmf07Ffi4jlabdmYPPVHMLMrGidnT0W2p9B1qw9PXr04JVXXvGCm2XQupp4jx49itq/0FpUh0kaBBwJ/BfZOJl/AfOB6WRXUhW3rGciaSOyrq+BwGvAzUD7czuv+vzxwHiALbf0QuZmZla/+vfvT3NzM0uXLq11KA2hR48e9O9fXMdRMfPgPAX8d2eDyrE/8FxELAWQdCuwB9BL0tqpFac/sGQ18UwGJkN2mXgZ4zIzMyur7t27M3DgwFqHsUYqNAanEv4B7CZpPWXtdcOBp4CZwFfSPmPIusXMzMzMOqzqCU5EPEg2mPgRsiu0upG1yHwXOFnSQrJLxa+qdmxmZmbWGAp2UVVCRJxFNjg517NAaStqmZmZmeUoqgUnXQ7+f9OCm0jaUpKTETMzM6tLxXZRXQEMBUan7WXA5avf3czMzKx2iu2i+mxE7CLpUciWapC0TgXjMjMzMytZsS0470lai2ztKCT1BVZWLCozMzOzTig2wfkJcBuwiaRzydammlSxqMzMzMw6oaguqoi4XtIcsjlrBBwaEfMrGpmZmZlZiYpKcCRdFxFHAU/nKTMzMzOrK8V2UX0ydyONxxlc/nDMzMzMOq/dBEfSGZKWATtJekPSsrT9El5KwczMzOpUuwlOREyKiJ7ABRGxQUT0TD99IuKMKsVoZmZm1iHFDjI+Q9JGwLZAj5zyWZUKzMzMzKxUxQ4yPhY4AegPPAbsBtwP7FexyMzMzMxKVOwg4xOAzwCLI2Jf4NPAa6VWKqmXpFskPS1pvqShknpLukvS39LtRqUe38zMzNZsxSY470TEOwCS1o2Ip4HtOlHvpcAdEfEJYGdgPnA6MCMitgVmpG0zMzOzDit2LapmSb2A3wF3SXoVWFxKhZI2BPYGjgGIiHeBdyWNAIal3aYCTcB3S6nDzMzM1mzFDjIeme5+X9JMYEPgTyXWORBYClwtaWdgDlkX2KYR0ZL2eQHYtMTjm5mZ2Rqu2C6q90XEPcA7wPQS61wb2AW4MiI+DbxFm+6oiAjSwp5tSRovabak2UuXLi0xBDMzM2tk7bbgSNoP+BmwGVn31PnA1WTrUZ1bYp3NQHNEPJi2byFLcF6U1C8iWiT1I5tM8EMiYjIwGWDIkCF5kyAzM7OO2u2sOzt9jAd+cGAZIrFyKNSC82NgPNCHLBG5H7gmIgZHxK2lVBgRLwDPS2odpDwceAr4PTAmlY3BMyWbmZlZiQqNwYmIaEr3fydpSURcVoZ6vw1cL2kd4FlgLFmydZOkcWQDmEeVoR4zs7rhFgKz6imU4PSS9OXc/XO3O9GK8xgwJM9Dw0s5npmZmVmuQgnOPcAXc7Zn5WwHUFKCY2ZmZlZJ7SY4ETG2WoGYmZmZlUuHLxM3MzMzq3dOcMzMzKzhOMExMzOzhlNUgiPpMEk90/3vSbpV0i6VDc3MzMysNMW24JwZEcsk7QnsD1wFXFm5sMzMzMxKV2yCsyLdfgGYHBF/BNapTEhmZmZmnVNsgrNE0s+Bw4HpktbtwHPNzMzMqqrYJGUUcCdwYES8BvQGTq1UUGZmZmadUWgm41b9gD9GxL8lDQN2Aq6tVFBmZmZmnVFsC85vgRWStgEmA1sAv+5MxZLWkvSopGlpe6CkByUtlHRjWojTzMzMrMOKTXBWRsRy4MvATyPiVLJWnc44AZifs30+cHFEbAO8Cozr5PHNzMxsDVVsgvOepNHA0cC0VNa91Eol9Se7ImtK2hawH3BL2mUqcGipxzczM7M1W7EJzlhgKHBuRDwnaSBwXSfqvQQ4DViZtvsAr6VWIoBmYPNOHN/MzMzWYEUNMo6Ip4Djc7afI+tS6jBJhwAvRcScNGC5o88fD4wH2HLLLUsJwczMzBpcuwmOpJsiYpSkeUC0fTwidiqhzj2AL0k6GOgBbABcCvSStHZqxekPLMn35IiYTDbQmSFDhnwoJjMzM7NCLTgnpNtDylVhRJwBnAGQWnBOiYgjJd0MfAW4ARgD3F6uOs3MzGzN0m6CExEt6XZxFWL5LnCDpHOAR8nWuzIzMzPrsEJdVMtYtWtKaVtARMQGnak8IpqApnT/WWDXzhyvUe121p2dPsYDPziwDJGYmZl1DYW6qGYAHwVuBW6IiH9UPiQzMzOzzmn3MvGIOBQ4EFgK/ELSPZK+Kal3NYIzMzMzK0XBy8Qj4nXgaklTgSOAn5Bd/XRRhWMzM7MKKEe3N7jr2+pbwQRH0u7AaGAv4C/AyIi4t9KBmZmZmZWq0CDjRcBrZJdujweWp/JdACLikcqGZ/XGA57NzKwrKNSCs4jsqqkDgQPIrp5qFWTrR5mZmZnVlULz4AyrUhxmZmZmZVPsYptmZmZmXYYTHDMzM2s4TnDMzMys4RS6imqX9h73VVRmZmZWjwpdRfXjdh4r6SoqSVsA1wKbpmNMjohL0+zINwIDyK7eGhURr3b0+GZrMl/Gb2aWKXQV1b4VqHM58J2IeERST2COpLuAY4AZEXGepNOB08lWGDczMzPrkIIzGbeStAMwiGyZBgAi4tqOVhgRLUBLur9M0nxgc2AEMCztNpVslXEnOFb33GpiZlZ/ikpwJJ1FlnwMAqYDnydbtqHDCU6b4w4APg08CGyakh+AF8i6sMzy8lo6ZmbWnmKvovoKMBx4ISLGAjsDG3amYkn/AfwWODEi3sh9LCKCbHxOvueNlzRb0uylS5d2JgQzMzNrUMUmOG9HxEpguaQNgJeALUqtVFJ3suTm+oi4NRW/KKlferxfquNDImJyRAyJiCF9+/YtNQQzMzNrYMWOwZktqRfwC2AO8CZwfykVShJwFTA/Ii7Keej3wBjgvHR7eynHLxd3gZiZmXVdRSU4EfHNdPdnku4ANoiIx0uscw/gKGCepMdS2QSyxOYmSeOAxcCoEo9vZmZmZdCVL6IodpDxjIgYDhARi9qWdURE/IVVVyXP1eHjmZmZmbVVaCbjHsB6wMaSNuKDxGQDsku7zczMzOpOoRacrwEnApsBucsyvAFcVqGYzMzMzDql0EzGlwKXSvp2RPy0SjGZmZmZdUqxV1H9XNLxwN5puwn4eUS8V5GozMzMzDqh2ATnCqB7uoXsKqgrgWMrEZSZmZlZZxQaZLx2RCwHPhMRO+c8dLekuZUNzczMzKw0hWYyfijdrpC0dWuhpI8BKyoWlZmZmVknFOqiar0s/BRgpqRn0/YAYGylgjIzMzPrjEIJTl9JJ6f7PwfWSvdXkK0CPrNSgZmZmZmVqlCCsxbwH3x45uG1gZ4VicjMzMyskwolOC0RcXZVIjEzMzMrk2LH4JiZFa0cC/RB7RbpM7Our1CCU9XFLyUdBFxK1jU2JSLOq2b9ZmZWXV15tWqrb4WWavjfagUiaS3gcuBzQDPwsKTfR8RT1YrBzMys1twCWh6F5sGppl2BhRHxbES8C9wAjKhxTGZmZtYF1VOCsznwfM52cyozMzMz6xBFRK1jAEDSV4CDIuLYtH0U8NmI+Fab/cYD49PmdsAzVQ10VRsDL9ew/lz1Eku9xAGOJZ96iQMcSz71Egc4lnzqJQ5wLLm2ioi+bQuLXWyzGpYAW+Rs909lq4iIycDkagXVHkmzI2JIreOA+omlXuIAx1LPcYBjqec4wLHUcxzgWIpRT11UDwPbShooaR3gCOD3NY7JzMzMuqC6acGJiOWSvgXcSXaZ+C8j4skah2VmZmZdUN0kOAARMR2YXus4OqAuusqSeomlXuIAx5JPvcQBjiWfeokDHEs+9RIHOJaC6maQsZmZmVm51NMYHDMzM7OycIJTJEkDJD1RjzFI2kvSk5Iek/SRWsRm9UlSL0nfrHUc0O7n90RJ69Uipnoh6XhJ8yW9JWlQDeP4a63qziXpzVrHYF2fE5zGcCQwKSI+FRFv1zqYepaWBFmT9ALqIsFpx4nAGp3gkL1HnwNuBmqW4ETE7rWq26zcnOB0zNqSrk//ad0iaT1Jn5H0V0lzJT0kqWeVYzgeGAX8TyrvJ2lWas15QtJelQxG0tGSHk+//3WSNpV0W9qeK6lqJ8zUQvB0nvdokaTzJT0CHFbG+taX9Mf0ez4h6XBJ50l6Kr0mF6b9DkuPz5U0K5UdI+l2SU2S/ibprHLF1cZ5wNbp83CBpO9KmpdiqcVitvk+v5sBMyXNrEYAeT6zW0t6IL0u51S79UDSz4CPAc8BY4AL0vu1dTXjSLG8mW6reh5pJ55hkqblbF8m6ZgK19l6HrlG0oL0ed1f0n3pu7qrpL6S7kot51MkLZa0cQVjyneuWSTpR+lz+5CkbSpVf04cq7TCSjpF0vclfVXSwym+36peWmQjwj9F/AADgAD2SNu/BE4DngU+k8o2ANaucgynANcAX0ll3wH+O91fC+hZwXg+CSwANk7bvYEbgRNz6t+wxu/RKcAi4LQK1PefwC9ytrcim1m7dfB+r3Q7D9i8TdkxQAvQB/gI8AQwpEKvyRPp/ueBvwLrtb5f1Xpvinh/Nq5SDPk+s9OA0Wn768Cb1XxdUr2LyGaDff+7XIuf1t+9mueRAnEMA6bllF8GHFPhugcAy4EdyRoB5qTPqsjWR/xdiuOMtP9B6XNdsc9wnnPNhukz0/oeHZ37OlX4tXkiZ/sU4PtAn5yyc4BvV/Pzsroft+B0zPMRcV+6/yvgQKAlIh4GiIg3ImJ5lWPYs83jDwNjJX0f2DEillUwlv2AmyPiZXh/9fn9gCvT9oqIeL2C9eezutfnxgrUNQ/4XGod2ots5u13gKskfRn4V9rvPuAaSV8l+2PR6q6IeCWybsVb+fB7WW77A1dHxL/g/fer2gp9fist32d2KFnXEMCvqxxPvarmeaQePRcR8yJiJfAkMCOyv97zyP7I70m2IDQRcQfwaoXjWeVck3Ne/U3O7dAKx9CeHSTdK2ke2ZCJT9Ywlvc5wemYttfUv1EHMayyHRGzgL3J/theI+noagVWJ1b3+rxV9ooiFgC7kJ18zgEmALsCtwCHAHek/b4OfI9sKZI5kvoUiLWRrYm/c5dTR+eR5az6d6pHler9d879lTnbK6nB/HFtzzWSJrY+lLtbFUJZ3ftxDfCtiNgR+AHVe5/a5QSnY7aU1Jol/x/gAaCfpM8ASOopqdIf/rYx/CX3QUlbAS9GxC+AKWRfikq5Gzis9Q+2pN7ADOAbaXstSRtWsP582n19yknSZsC/IuJXwAVkfxA2jGzCypOAndN+W0fEgxExEVjKB2uufU5Sb2VXvh1K1tJTbsuA1nFhd5H9V75eiqt3BeorJN/7kxtjpeX7zD5A1gUA2RIxtVTN12K1qnweac9iYJCkdSX1AobXKI627iMb+4ikA4CNKllZnnNN6/txeM7t/ZWMIXkR2ERSH0nrkv0jB9lntkVSd7IWnLrgBKdjngGOkzSf7AP9U7IP1k8lzSX7A1LpzLVtDFe2eXwYMFfSoym2SysVSGRLaZwL3JN+/4uAE4B9U1PlHKp/RUih16ecdgQekvQYcBbZfy7TJD1O9of75LTfBWkg4BNkY2DmpvKHgN8CjwO/jYjZ5Q4wIl4B7kt1Dydb3212ivmUctdXhHzvz2TgjmoMMl7NZ/ZE4OT0vm0DVLtbNdcNwKmSHq3FIOMcw6jSeaQ9EfE8cBPZGLWbgEdrEUcePwAOSN+rw4AXyJLTSml7rjknlW+UPrcnkP1TVVER8R5wNtm56y7g6fTQmcCDZInf0/mfXX2eydgahqQBZAPtdqh1LIWkK0GGRMS3ah3Lmi61aL0dESHpCLIBxyNqHZfVr9R6sSKyNRSHAldGxKeqHMMisnPIy9Wstyupq7WozMxqYDBwmSQBrwH/VdtwrAvYErhJUjfgXeCrNY7H8nALjpmZmTUcj8ExMzOzhuMEx8zMzBqOExwzMzNrOE5wrMtQts7VryU9K2mOpPsljcx5/BJJS9LAv9ayYyQtVbamzlNpNuG25U8qrVuVHttN0oPpsflpNtd88Vwv6Rlla8P8Ms0BgaQjla11NE/ZOmU7V/SFMVuDSApJP87ZPqX1O6psXaQl+mANrS/lKX9a0pW554k2x/+opBsk/T2dZ6ZL+nhVfjkrKyc41iWkK1x+B8yKiI9FxGCySdn6p8e7ASOB54F92jz9xnQJ5zDgh5I2zS2PiE+SXQnROmnWVGB8es4OZPNv5HM98AmyOSo+Ahybyp8D9kmzev4P2TwvZlYe/wa+rNUvbnlx+u4eBvwyJ5FpLR9E9p1te55oPc/cBjRFxNbpPHMGsGnbfa3+OcGxrmI/4N2I+FlrQUQsjoifps1hZGvGXAmMzneAiHgJ+DvZopjvUzb79Pp8sJ7MJmQLYbaup/XUao43PRKyia/6p/K/RkTrsR5oLTezslhO9k9DuxPbRcT8tG/bRGgdsglZ860ftS/wXpvzzNyIuLdTEVtNOMGxruKTwCPtPD6abMG524AvtHYX5ZL0MeBjwMJUdHiaGXQJ2arSf0jlFwPPSLpN0tcktTs7darrKNLaU22MA/7U3vPNrMMuB45UO0vBSPos2dpRS1PRSen73gIsiIjH8jxtB7IZ2K0BOMGxLknS5ZLmSnpY0jrAwcDvIuINsinDD8zZvTWR+Q3wtZxVtFu7rj5KtojdqQARcTYwBPgz2XpJ+RKXXFeQdZ2t8l+epH3JEpzvlvyLmtmHpO/5tcDxeR5uTWQuBA6PDyZ7a+2i2gRYP81abQ3MCY51FU+Ss+BfRBxHtrZSX7JkphcwL01fvierdlO1jrX5bETc1vbA6QT4B7LFMlvL/h4RV6Y6dla2uNydaZDilNb9JJ2VYjg595iSdiJbpHBEWg/KzMrrErJ/INZvU35x+r7vla9rKa2ndAewt6Qt0nf6MUlfJzvPDK504FYdTnCsq7gb6CHpGzll66Xb0cCxETEgIgYAA8lW6l6P4u1JNj4HSV9Igw0BtgVWAK9FxIHpxHls2u9YsuRqdESsbD2QpC2BW4GjImJBR39RMysstcTeRJbkFC19t/cA/h4Rz6fv9KfSuJu7gXUljc/ZfydJe5UzdqsOJzjWJaRWlkOBfSQ9J+khsqudzgIOAv6Ys+9bZKt5f7HAYQ9P/7k9Dnya7IonyMbTPJOaua8DjoyIFXme/zOyqyvuT8eZmMonAn2AK1J52VcJNzMAfsyHBxGvTmvX1RPAWmRdy6tI55mRwP7pMvEngUlkq4VbF+O1qMzMzKzhuAXHzMzMGo4THDMzM2s4TnDMzMys4TjBMTMzs4bjBMfMzMwajhMcMzMzazhOcMzMzKzhOMExMzOzhvP/AesU0o+YDkIkAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_cas['app']\n", - "gap_22_cas = df_gap22_cas['missRatio'].astype(float)\n", - "\n", - "gap_25_cas = df_gap25_cas['missRatio'].astype(float)\n", - "\n", - "app_npb = df_npbC_cas['app']\n", - "npb_C_cas = df_npbC_cas['missRatio'].astype(float)\n", - "\n", - "npb_D_cas = df_npbD_cas['missRatio'].astype(float)\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,100])\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*2, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - "\n", - "offset = i*2+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*2+1, npb_C_cas[i], width=1, color=cmap(1))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "\n", - "plt.ylabel(\"Total Miss Rate (%)\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "#plt.ylim([0,55])\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*2, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - "\n", - "offset = i*2+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*2+1, npb_D_cas[i], width=1, color=cmap(1))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "\n", - "plt.ylabel(\"Total Miss Rate (%)\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAACgCAYAAAAB3xbxAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAgVklEQVR4nO3de7xUdb3/8ddbRFESNgqaR1RQSxO8oFh6xNxQHi8koEWCHu+XNDPNLv40j4hp5k/LTM0yFU00NUu8EWkGlndAUUC0UvFCHkwN8IYifM4fa22YvZnZe83ea2bP3ryfj8c89qzv+q61PjNrZu3vfNf3oojAzMzMrDNZq70DMDMzM8ubCzhmZmbW6biAY2ZmZp2OCzhmZmbW6biAY2ZmZp2OCzhmZmbW6biAY2ZmZp2OCzhmZmbW6eRawJE0QFKf9PlGkq6RdIuk7fM8jpmZmVlz8q7B+WXB8wuA/wXuAK7L+ThmZmZmJeVWwJE0DtgaOCl9fhDQBdgO6CvpHEmfz+t4ZmZmZqUoz7moJM0EDgY2AS6MiC+k6Q9FxJDcDmRmZmbWjLVz3t/5wKPAR8BYSNrlAG/kfBwzMzOzknKtwTEzMzOrBRXtJi7p3Eru38zMzKyYSo+DMyJrRkndJD0h6WlJcyWNr2RgZmZm1nnl3QanKZWR90NgWES8K6kr8JCkP0TEYxWKzczMzDqpShdwds2aMZLGQO+mi13ThxsImZmZWdlyK+BI+lmJdAAi4psZ9tEFmAlsA1wZEY/nFZ+ZmZmtOfKswTkRmAPcBvyT8m5PARARy4GdJdUBd0gaGBFzGtZLOgE4AaB79+67brfddnnEbWZleP755wHYdttt2zkSMzOYOXPmmxHRp2l6bt3EJW0EjAYOAT4GbgVuj4hFrdzfOcD7EXFJsfWDBw+OGTNmtDJaM2ut+vp6AKZNm9aucZiZQTLIcEQMbpqeWy+qiHgrIn4REUOBo4E64FlJh2cMsE9ac4Ok9YB9gOfyis/MzMzWHLk3Mpa0C8koxvsAfyBpU5PFpsANaTuctYDbIuKevOMzMzOzzi/PRsbnAcOBecAtwJkR8XHW7SPiGWBQXvGYmZnZmivPGpyzgZeAndLHD9MeVCLpBb5jjscqauHChbz99tuVPox1UF27dqV3797U1dW1dyhmZlZheRZw+ue4r1Z5++23+fSnP02XLl3aOxSrMRHB0qVLmT9/vgs4ZmZrgNwKOBHxcrF0SUNI2uScnNexmuPCjRUjifXWW6+9wzAzsyqpyFxUkgZJuljSfOAHdNLeUIsXL6a+vp76+nrq6urYY489qK+vZ+DAgeyxxx4MGTKEPffck+uvv37lNv3796e+vp699tqLww8/nOXLl69c98Mf/pD+/ftT2HW/f//+HHfccSuXb7zxRiQxf/78arzE3E2fPp1hw4ax9957M3ToUKZPn96m/W2zzTY5RWZmZp1Jno2MP01SUzMWeJNkHByl3carbvdxf8xlP4+N37fkup49e64cC6S+vp6JEyfSt2/fRs8XLVrEqFGj2HLLLRk6dChdunRZuc0xxxzDfffdx/777w/APffcw7Bhw3j44YcZMmQIkNRIvfLKK3z44Yesu+663H777ey6a+YZMDIZMWl4Lvu5a9S9za5fvHgxRx55JJMnT6Zfv37Mnz+fAw44gEcffZSePXsCsHz5ctfCmZlZm+VZg/McMAz4UkQMiYjLgeUtbNPp1dXV8f3vf5+bb765UfqKFStYtGjRytqap556igEDBnDSSScxceLERnn3339/7r33Xt544w26du3aYduQ3HPPPYwaNYp+/foB0K9fP0aOHMkVV1zBbrvtxuGHH87xxx/P1KlTGTp0KHvttRcjR45k6dKlANx6663svvvuDB06lIsuuqjRvpctW8Zxxx3H0KFDGTJkCE888US1X56ZmdWQPBsZHwyMAaZKmkLSVbzs6Ro6o80335wFCxYASQ1FfX09L774IoMGDWLffZMaoptuuokjjzySwYMHc/rpp7Ns2TK6du0KwJgxYzjttNNYsGABX/3qV7n66qvb7bW0xWuvvcYWW2zRKG3LLbdkyZIlzJ8/nwceeIAePXrw3nvvMXXqVADOOOMMbrvtNoYPH87555/PY489Rvfu3Rvd2gO49tpr2WabbbjmmmtYuHAhBx98MA8//HDVXpuZmdWWPBsZTwImSeoOjAROAzaWdBVwR0Tcl9exOppXX32VzTbbDGDlLarFixez//77s2jRInr16sWdd97JnDnJtFtvvPEGkydPZuTIkQBsuummvPvuu9xyyy386U9/6rAFnM0224xnn322Udorr7xC9+7dGThwID169ABg7ty5nH322Xz44YcsXLiQHj168MILL7DjjjvSvXt3YPXG5LNn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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_ram['app']\n", - "gap_22_ram = df_gap22_ram['simSeconds'].astype(float)*1000\n", - "gap_22_orc = df_gap22_orc['simSeconds'].astype(float)*1000\n", - "gap_22_noDC = df_gap22_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "\n", - "gap_25_ram = df_gap25_ram['simSeconds'].astype(float)*1000\n", - "gap_25_orc = df_gap25_orc['simSeconds'].astype(float)*1000\n", - "gap_25_noDC = df_gap25_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "\n", - "app_npb = df_npbC_ram['app']\n", - "npb_C_ram = df_npbC_ram['simSeconds'].astype(float)*1000\n", - "npb_C_orc = df_npbC_orc['simSeconds'].astype(float)*1000\n", - "npb_C_noDC = df_npbC_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "npb_D_ram = df_npbD_ram['simSeconds'].astype(float)*1000\n", - "npb_D_orc = df_npbD_orc['simSeconds'].astype(float)*1000\n", - "npb_D_noDC = df_npbD_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "\n", - "# Multi bar Chart1\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,3])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_22_ram[i]/gap_22_noDC[i], width=1, color=cmap(1), label='TDRAM' if i==0 else None)\n", - " plt.bar(i*3+1, gap_22_orc[i]/gap_22_noDC[i], width=1, color=cmap(2), label='Oracle' if i==0 else None)\n", - "\n", - "offset = i*3+2\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_C_ram[i]/npb_C_noDC[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*3+2, npb_C_orc[i]/npb_C_noDC[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()\n", - "\n", - "# Multi bar Chart2\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,3])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_25_ram[i]/gap_25_noDC[i], width=1, color=cmap(1), label='TDRAM' if i==0 else None)\n", - " plt.bar(i*3+1, gap_25_orc[i]/gap_25_noDC[i], width=1, color=cmap(2), label='Oracle' if i==0 else None)\n", - "\n", - "offset = i*3+2\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_D_ram[i]/npb_D_noDC[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*3+2, npb_D_orc[i]/npb_D_noDC[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", - "plt.legend(fontsize=9, ncol=2)\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAACgCAYAAAAB3xbxAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAh60lEQVR4nO3de5xVdb3/8dcbxFBCiItFkYIeNS+EF7TUEQfRvBFKeSMz5WieUvNWeIJjgqZhP00y9egxVEo7qZWacryGjrdUBIUAUY4pHFE8Ih25eBc+vz/WGtgMs2fWHtaevWd4Px+P/Zi9vuu71vcz+7LmO9/1vSgiMDMzM2tPOlQ6ADMzM7O8uYJjZmZm7Y4rOGZmZtbuuIJjZmZm7Y4rOGZmZtbuuIJjZmZm7Y4rOGZmZtbuuIJjZmZm7U6uFRxJO0vqnT7vKWmSpFsl7ZRnOWZmZmZNybsF5z8Knl8CvAncCdyYczlmZmZmReVWwZE0DtgW+H76fATQEfgS0FfSBZIG51WemZmZWTHKcy0qSTOAbwCfBSZExNA0/YmIqMmtIDMzM7MmbJLz+S4GngI+AkZC0i8HeCvncszMzMyKyrUFx8zMzKwalHWYuKTx5Ty/mZmZWWPKPQ/O8KwZJXWWNE3SLElzJV1YzsDMzMys/cq7D05DKiHvh8ABEbFSUifgCUn3RcTTZYrNzMzM2qlyV3D2yJoxks5AK9PNTunDHYTMzMysZLlVcCT9qkg6ABFxZoZzdARmAP8EXBMRz+QVn5mZmW088mzB+R4wB7gdeIPSbk8BEBGrgF0ldQfulLRLRMyp3y/pVOBUgC5duuzxpS99KY+4zawEL730EgA77LBDhSMxM4MZM2a8HRG9G6bnNkxcUk/gaOBY4BPgNuCPEfFOC893AfBeRFze2P5BgwbF9OnTWxitmbVUbW0tAHV1dRWNw8wMkkmGI2JQw/TcRlFFxNKIuC4ihgCjgO7AC5JOyBhg77TlBkmbAQcBL+YVn5mZmW08cu9kLGl3klmMDwLuI+lTk0Uf4DdpP5wOwO0RMSXv+MzMzKz9y7OT8UXA4cA84FZgTER8kvX4iPgbsFtLy//4449ZtGgRH3zwQUtPYQU6d+5M37596dSpU6VDMTMzK1meLTjnA68CA9PHz9IRVCIZBf7lHMtaz6JFi+jatSv9+vVbM3LLWiYiWLp0KYsWLaJ///6VDsfMzKxkeVZwKvqX8IMPPnDlJieS6NmzJ0uWLKl0KGZmZi2SWwUnIhY2li6phqRPzul5lVWMKzf58WtpZmZtWVnWopK0m6TLJC0Afko7Gw01depUamtrGTx4MCNGjGDp0qVlKWfBggWcdNJJzeabPHkykyZNajZfTU1NDlGZmZlVvzw7GW9P0lIzEnibZB4cpcPGW9VXxz2wQcc/feHBRfctWbKEiy66iClTptC1a1fmz5/PRx99tEHlmZmZWb7ybMF5ETgAGBYRNRFxFbAqx/NXhXvvvZcTTjiBrl27ArD99tvTp08fbrrpJmpraxk0aBAPPvggAGPHjqWmpoYhQ4bwxhtv8Oabb3LooYdSW1vLmDFjADjmmGPYf//9+drXvsby5csBuOCCC9hvv/2YMGHCmnKnTJnC4MGD2Weffbj//vubjbOx80LSgfjMM8/k1ltvZcmSJQwfPpwhQ4Zw2mmn5fYamZmZVVqeFZxvAIuBRyT9WtJQWrBcQ7VbvHgxffr0WS/92GOPpa6ujqlTp3L55cnky08++SSPPfYYjzzyCH369GHChAmcc8451NXVcckllwDJ7aVHH32UY445httuu43Fixczbdo0Hn/8cfbff38AVq9ezeWXX87DDz9MXV0dl112WbNxNjxvvbPPPpu9996b4447jksvvZQxY8bwyCOP0LVrV5566qk8XiIzM7OKy7OT8V3AXZK6AEcAZwNbSroWuDMiHsyrrErq06cPb7zxxnrpDzzwAFdeeSURwVtvvQXAeeedx4knnkjPnj255JJLmD9//pqKTYcOHVi1ahWjR49m9uzZLF++nBEjRrBw4UK+/OVkRP0ee+zBgw8+yNtvv828efM48MADAXjrrbeIiKIdgRs7L8D8+fPp3Lkzv/zlLwGYN28eP/7xj5HEypUr2WuvvXJ9rczMzCol907GEfFuRPxnRHwd6As8B/xr3uVUymGHHcYtt9zCihUrAHj55ZdZvHgxEyZM4L777uPPf/4zHTokL+sBBxzAzTffzJZbbsmUKVPYYYcdePrpp4GkVWbmzJm8++67PPbYY5x++ulEBFtvvTWzZ88G4PnnnwegV69eDBgwgKlTp1JXV8esWbOaHOXU2HkhuZ02cuRIRo8eDSSLJV5xxRXU1dUxffp0jjjiiPK8aGZmZq0scwuOpM0j4r1m8nQEPhMRb6dJ75LcpvpCy0MsXVOdhDdU7969+clPfsKwYcOICHr06MENN9zAsGHDGDx4MHvttRfdu3cH4IgjjuD9998H4A9/+AP7778/J554IhdffDH77LMPY8eO5eWXX+aQQw7hi1/8Il/4whfo06cPe+yxB/vttx8DBw4Ektaec889l6FDhyKJnXbaiWuuuWaduK644gpuvfVWACZOnLjeeeudfPLJTJgwgZ///OeMHTuWU089lWXLltGhQwcmTZpEv379yvbamZmZtZZmVxOXtA8wCfh0RGwlaSDwLxFxWoN8xwH/QVKp+W/gEuBG4FngpxHxXJ6BN1xNfN68eey44455FrHR82tqjfFq4mZWTYqtJp6lBWcicDBwN0BEzJI0uJF85wN7RMTL6YKbTwFHRcQ9GxC3mZmZWcky9cGJiNcaJDU2/PujiHg5zf8c8N+u3JiZmVklZGnBeS29TRWSOgFnkawY3tCWks4t2O5euB0RV2xYqGZmZmbZZKngfA+4kqSj8OvAgzS+rtSvga5NbJuZmbU5w+86vKT8dx/5X2WKxErRbAUnHRF1fIZ8F+YSkZmZmdkGarYPjqT+kq6QdIeku+sfRfIOkfQnSXPTxx8l1eYddCUtW7aM2tpaamtr6datG7W1tYwaNYqBAwcydOhQDj30UGbMmAEkswnvsMMODBkyhCOPPHKdNau22267NcO6IRmZ8oMf/GDN9rBhwzIttGlmZmbry3KL6i7gBuAeYHWxTJIOB64GLkofAnYHbpR0RkTcu8HRZlRqc2JDTTUvduvWbc3w2JqaGurq6hg/fjzHH388Bx54IIsWLeKoo47i4YcfBmD06NGccsopXHzxxTz44IMMGzaMWbNmUVNTwz333MNxxx235tyvvfYaEcHKlStZtmwZvXr12qDfw8zMbGOVpYLzQUT8KkO+0cCRETGrIG2mpOnAVUCrVXAqqW/fvhx88ME8++yz66S/8847a57fcccdnHbaafzsZz/jww8/5FOf+hQAe+65J9OmTePVV1/lsMMO46WXXmrN0M3MzNqNLMPEr5Q0TtLeknavfzSS73MNKjcARMTfgM9ucKRtyOc//3nefPNNAC677DIGDBjAtGnTOPjgZIbl559/nj333JNDDjmEv/zlL2uOGzFiBHfeeSf33nsvhx++Ya1QZmZmG7MsLTgDgBOAA1h7iyrS7ULvNnGOpva1O6+//jo77rgjr7zyCqNHj2bUqFEceeSR/OMf/2DFihXMnj2bQw45hA8//JDtt99+TWVm++23Z+7cuXTp0oUtttiiwr+FmZlZ25WlgnM0sE1EfNRMvm2LdD4WsE3JkbVRr7/+Og899BBjxozhlVdeAaBjx46cccYZTJw4kR49ejBp0iSGDh0KwPDhw1m9em3Xpm9+85v07t27IrGbmVnr+uq4BzLnLec6i+1RlgrOHKA78FYz+ZpaivryrAHloRJzEPzwhz+kV69ebLrpplx99dVsttlm6+w/6KCDOP/889lkk03WGS2100478fjjj6/Zrh85tWDBgtYI2yw3pVyowRfrjZE/I9aaslRwugMvSnoW+LA+MSKGF2aKiEcbHihp97wX2awmTzzxBADjx49n/Pjx6+0vHObdoUOH9ToeA1x66aXA+gsX9uvXj8mTJ+cVqpmZ2UYlSwVn3AacfxLJUHEzM6sQt5zYxijLTMbrtcyUQJkzSl8Efksy4iqA6yPiyg0o28zMrFGlVPq23K2MgVjZFK3gSHoiImokrSCpcKzZBUREZBnmU8ryDZ8AP4yI5yR1BWZIeigiXsh6gohAylynsiZERPOZzMzMqlTRCk5E1KQ/S14wU9JAYL/6543Nj9NIeYuBxenzFZLmkSzwmamC07lzZ5YuXUrPnj1dydlAEcHSpUvp3LlzpUMxMzNrkWZvUUm6OSJOaC6tYN9ZwHeBO9KkWyRdHxFXZQ1KUj9gN+CZrMf07duXRYsWsWTJkqyHWBM6d+5M3759Kx2GmZlZi2TpZLxz4YakTYA9msh/MvCViHg3zf9z4CmS5RqaJenTwJ+AsyNieYN9pwKnAmy11VbrHNepUyf69++fpQgzMzNr55rqgzMGGAtsJqm+oiHgI+D6Js4pYFXB9ioydjaW1ImkcvO7iLij4f6IuL6+7EGDBrmTiJlZGZSyYHEl5h0zy6KpPjgTgAmSJkTEmBLOeRPwjKQ70+0jSVYjb5KSjjM3APMi4ooSyjMzq0qepdascrIMEy+lckNEXCHpUWDfNGlURDyf4dB9Sda8mi1pZpo2NiI2ilXIzczMLD9Z+uC0xEySEVGbAEjaKiL+p6kDIuIJSpg3x8zMzKyY3Cs4kn5AMvvx/7K2/00AX867LDMzM7PGZKrgSOpIMsPwmvxNtMicBewQEUs3PDzzPXwzM7PSZZkHp7BFZnWa3FSLzGvAslyiMzMzM2uBLC04pbbIvALUSfov1l193COjzMzMrFVkqeCU2iLzP+lj0/RhZmZm1qqyVHBKapGJiFIW2DQzMzPLXZYKjltkzCx3ni3XzMopy0R/F8KaNaKIiJXlDsqqTymjucAjuszM8lbKPwXgfww6NJdB0i6SngfmAnMlzZC0c3PHmZmZmVVKlltU1wPnRsQjAJJqgV8D+zSWWVJfkpXDa0iGkz8OnBURi3KIt9W0xflnXLvfOLXFz6qZWbk124IDdKmv3ABERB3QpYn8NwF3A32AzwP3pGlmZmZmrSLTKCpJPwFuTre/TTKyqpjeEVFYoZks6ewWxmdmZhspd0S3DZGlBeefgd7AHemjd5pWzFJJ35bUMX18G/CyDWZmZtZqsoyi+j/gzBLO+c8kfXAmkvTB+StwUkuCMzMzM2uJohUcSb+MiLMl3UNSUVlHRAwvcmjfhvsk7UsyI7KZmZlZ2TXVglPf5+byEs95FbB7hjSzNs2jlyxPHgVplq+iFZyImJE+3TUirizcJ+ks4NEGaXuTDB3vLencgl1bAB3zCdfMzMyseVlGUZ0IXNkg7aRG0jYFPp2es2tB+nLgqBbGZ22URz+YmbUd7XG2+qb64IwEvgX0l3R3wa6uwD8a5o+IR4FHJU2OiIW5R2pmZmaWUVMtOH8FFgO9gF8UpK8A/lbsIFduzMzMrNKa6oOzEFgI7N164Zi1T+5AambWuprtgyNpBWuHiW8KdALejYgtyhmYmVlLeYSbmWWZ6G9Nh2FJAo4Avtown6SraGS+nILzlDJZoJlZq3CHeLP2KcsoqjUiIoC7JI0Dftxg9/T0577ATsBt6fbRwAsbEqSZ5cO3ysxsY5HlFtU3CjY7AIOADxrmi4jfpPm/D9RExCfp9nXA47lEa2ZmZhXXFlo+s7TgfL3g+SfAApLbVMV8hmRyv/qh5J9O05ok6UZgGPBWROySIS4zMzOzRmXpgzOqxHNeCjwv6RFAwGBgfIbjJgNXA78tsbyKaws1WTMzs41Jh+YySPqNpO4F259JW1saFRE3AV8B7gTuAPauv33VlIh4jEYmEDQzMzMrlZJ+w01kkJ6PiN2aSyvYJ+B4YJuIuEjSVsDnImJas8FI/YApWW5R9e/fP8aNG9dcthZ7bkH2utamn349c95deg2oijhKjaWUOEqNpdTXpFq0xfcmjzhmzpwJwK677triOEqNpVq+N9USR6mxVMt7Uy1xlBpLtbw31RJHqbGU+xo/atSoGRExqGF6sy04QAdJa/rQSOpB07e2/p1kcsCR6fYK4JoSYi1K0qmSpkua/vHHH+dxSjMzM2uHsrTgfAcYC/whTToauCQibi6S/7mI2L2wlUfSrIgY2GwwJbTgDBo0KKZPn95cthYrZaKwLXf7Vea8pfbBKVccpcZS6kJs5XxNqkVbfG/yiKO2thaAurq6FsdRaizV8r2pljhKjaVa3ptqiaPUWKrlvamWOEqNpdzXeEmNtuBk6WT8W0nTgQPSpG9ERFPz2nwsqSPppH+SegOrWxCzmZmZWYtkneivB8nyDDdJ6i2pf0S8WiTvr0g6GG8p6RLgKOD85gqQ9HugFuglaREwLiJuyBifbSRK/S/D0/CbmW2cskz0N45kcr8dgJtI1qK6hWTG4vVExO8kzQCGkgwTPzIi5jVXTkSMbC6PWak8hN/MbOOUpZPxCGA48C5ARLwBdC2WWdINQOeIuCYiro6IeZLG5xGsmZmZWRZZKjgfpWtQ1fep6dJM/oOB36Sdk+sNb2F8ZmZmZiXLUsG5XdJ/AN0lfRf4CzCpifxvkcxefLSkayRtQnKryszMzKxVZBlFdbmkg4DlJP1wLoiIh5o4RBGxDPh6emuqDuiWQ6xmZmZmmWTpZHxyOprpoXS7o6RxEXFhkUPurn8SEePTDsfn5BKtmZmZWQZZblENlXSvpD6SdgaepolOxhExrsH2PRFxQLH8ZmZmZnnLcovqW5KOBWaTjKT6VkQ82TCfpCciokbSCtIOyfW7ktPEFnkFbWZmZtaULLeotgPOAv4E7AickC7D8F5hvoioSX8Wbd0xMzMzaw1ZZjK+Bzg9IqamK4WfCzwL7FyYKV2Es6iIKG2pUjMzM7MWylLB2SsilkNynwn4haR7Gsk3g+TWVGNDwgPYpsVRmpmZmZWgaCdjSecBRMRySUc32H1Sw/wR0T8itkl/Nny4cmNmZmatpqlRVMcVPB/TYN8hTZ1U0mck7SVpcP2jxRGamZmZlaipW1Qq8ryx7bU7pFNIOiX3BWYCXwWeAjxU3MzMzFpFUy04UeR5Y9uFzgL2BBZGxBBgN+CdFkVnZmZm1gJNteAMlLScpLVms/Q56XbnJo77ICI+kISkT0XEi5J2yCtgMzMzs+YUreBERMcWnnORpO7AXcBDkv4PWNjCc5mZmZmVLMsw8ZJExIj06XhJj5AstHl/3uWYmZmZFZNlLaqSpaOovgysABYBu5SjHDMzM7PG5N6CI+mnJPPkvAKsTpMDj6IyMzOzVpJ7BQc4Btg2Ij4qw7nNzMzMmlWOW1RzgO5lOK+ZmZlZJuVowZkAPC9pDvBhfWJEDC9DWWZmZmbrKUcF5zfAz4HZrO2DY2ZmZtZqylHBeS8iflWG85qZmZllUo4KzuOSJgB3s+4tqufKUJaZmZnZespRwdkt/fnVgrRMw8QlHQJcCXQEJkXEpfmHZ2ZmZu1drhUcSR2BuyNiYguPvQY4iGRywGcl3R0RL+QZo5mZmbV/uQ4Tj4hVwMgWHr4X8HJEvJLOoXMrcERuwZmZmdlGoxy3qJ6UdDVwG/BufWKGPjhfAF4r2F4EfCX/8MzMzKy9K0cFZ9f050UFabks1SDpVODUdHOlpJc29Jw56QW8nSWjUFXEAdUTi+NYXxljyS0OaYNjbHPvTbXEAdUTi+NYX1v4/uagWt4bgK0bSyzHauJDWnjo68AXC7b7pmmF574euL6F5y8bSdMjYpDjWKtaYnEc1RkHVE8sjmN91RKL46jOOKC6Yikm96UaJHWTdIWk6enjF5K6ZTj0WWA7Sf0lbQocRzLU3MzMzKwk5ViL6kZgBcmim8cAy4GbmjsoIj4BzgAeAOYBt0fE3DLEZ2ZmZu1cOfrgbBsR3yzYvlDSzCwHRsS9wL1liKncquW2WbXEAdUTi+NYV7XEAdUTi+NYX7XE4jjWVS1xQHXF0ihFRL4nlJ4CRkfEE+n2vsDlEbF3rgWZmZmZFVGOCs5A4LdAN0DAP4CTImJWrgWZmZmZFZF7H5yImBURA4EvAwMiYrf2VLmR1E/SnGqMQdJ+kuZKmilps0rEZtVFUndJp1U6Dmjyc3u2pM0rEVM1kHSmpHmS3pW0UwXj+Gulyi6IYWWlY7D2I/c+OJI+BXwT6AdsUj9XRkRc1MRhlo/jgQkRcUulA6lmkjqms25vDLoDpwH/XuE4mnI2cAvwXoXjqJTTgAOBi4GdgIosTxMR+1SiXLNyKccoqj+TLLHwCclMxvWP9mQTSb9L/+v6o6TNJe0p6a+SZkmaJqlrK8dwJsmotZ+m6X0kPZa25syRtF85g5H0HUl/S3//myV9VtKd6fYsSa1y8UxbCV5s5P1ZIOnnkp4Djs6xvC6S/iv9HedIOlbSpZJeSF+Py9N8R6f7Z0l6LE07SdKfJdVJ+m9J4/KKq8ClwLbp5+AySf8qaXYaRyUWs23sc/t54BFJj7RGAI18VreV9HT6ulzcmq0Ikq4DtgFeBU4ELkvfq21bK4aCWFamP1v12lEkllpJUwq2r5Z0UpnLrL92TJY0P/2cHijpyfT7uZek3pIeSlvKJ0laKKlXmeJp7NqyQNL/Sz+r0yT9UznKbhDHOi2vkn4kabyk70p6No3vT6rGVtiIyPUBzMn7nNX0IGmZCmDfdPtG4DzgFWDPNG0LYJNWjuFHwGTgqDTth8C/pc87Al3LGM/OwHygV7rdg2SpjrMLyu9WwffnR8AC4LwylPdN4NcF21sDL7G2f1v39Ods4AsN0k4CFgM9gc2AOcCgMrwec9LnhwJ/BTavf59a4z3J+N70aqUYGvusTgFGptvfA1a28uuygGRW2DXf30o86n/v1rx2NBFDLTClIP1qkr6c5f58fgIMIPnnf0b6GRXJP+13pXGMSfMfkn6ey/LZbeTa0i39rNS/N98pfI3K/LrMKdj+ETAe6FmQdjHwg9b6nGR9lKMF56+SBpThvNXktYh4Mn1+C3AwsDgingWIiOWRzOvTmjHUNNj/LDBK0niSvlAryhjLAcAfIuJtgIj4R5p2bbq9KiKWlbH8hoq9NreVoazZwEFp69B+JLNvfwDcIOkbrL3t8iQwWdJ3Sf5o1HsoIpZGxPvAHaz/PubpQOCmiHgP1rxPra25z225NfZZ3Rv4Q7r/P1s5nmrUmteOavNqRMyOiNXAXGBqJH/BZ5P8oa8hWQiaiLgf+L8yxrLOtaXgGvr7gp+VHJ28i6THJc0m6R6xcwVjaVQ5Kjg1wAxJL6XNwLMl/a0M5VRSw6Fny6sghnW2I+IxYDDJH9zJkr7TWoFVgWKvTe63SiNiPrA7ycXoYmAssBfwR2AYcH+a73vA+STLkcyQ1LOZWNurje33bXOq5NrxCev+fercSuV+WPB8dcH2asozb1xRDa8tki6o31WYrRVCKfZeTAbOiIgBwIW03nuUWTkqOIcC2wFfA75OcpH/ehnKqaStJNXXnL8FPA30kbQngKSuksr9ZWgYwxOFOyVtDfxvRPwamETyRSmXh4Gj6/9oS+oBTAW+n253VLblOvLS5GuTJ0mfB96LpGP3ZSR/GLpFMmnlOcDANN+2EfFMRFwALGHtumsHSeqhZNTbkSQtPXlaAdT3B3uI5D/zzdOYeuRcVhaNvTeFMZZbY5/Vp0luB0CyREyltObrUFQrXzuKWQjsJOlTkroDQysQQ2OeJOnriKSvAZ8pV0GNXFvq34djC34+Va7yC/wvsKWknkoGEQ1L07sCiyV1ImnBqTrlWGxzYd7nrEIvAadLupFkxMNVJBfOq9I/VO+T3A4oZ2fFhjFcy7ojZWqB0ZI+TuMo239hETFX0iXAo5JWAc8DZwHXSzoZWEVS2WmNLyM0/tr8oExlDSDpGLoa+Bg4F5giqTPJvftz03yXSdouTZsKzAJ2BaYBfyJZXPaWiJieZ3ARsTTtJDkHuI9kfbfpkj4imTV8bJ7lZdDYe/MRcL+kN6Lli/VmUuSzejZwi6R/I2lxa83bqYVuBX6tpOP1URHx9wrFUUsrXTuKiYjXJN1O0i/tVZL3qRpcCPxe0gkk17M3SSqm5dDw2vJ9kpbhz6R3RT4ERpap7DUi4mNJF5Fcq14HXkx3/QR4huQftmeogsp5Q7lP9GdWSZL6kXS826XSsTQnHRUyKCLOqHQsG7O0Rev9iAhJx5F0OD6i0nFZ9UlbMFZFxCdpS+S1EbFrK5a/gOSa8XZrldmWteo9RTOzKrQHcLUkAe8A/1zZcKyKbQXcLqkDScvjdyscjzXBLThmZmbW7pSjk7GZmZlZRbmCY2ZmZu2OKzhmZmbW7riCY22GkvWt/lPSK5JmSHpK0oiC/b+U9HraAbA+7SRJS5Ssq/NCOpNww/S5StesSvd9VdIz6b556YyujcXzu3RCyzmSbkzng6hfR2dZevzMggm6zGwDSQpJvyjY/lH9d1TJGkmva+06WsMbSX9R0rWF14kG519VcF2YJemHxfJadfObZm1COsLlLuCxiNgmIvYgmZStb7q/AzACeA3Yv8Hht6VDOWuBn0n6bGF6ROxMMiKifgKt3wCnpsfsAtxeJKzfAV8ima9iM+CUgn2Pp+feNSIuatEvbWaN+RD4hoovcjkx/e4eDdxYUDmpT9+J5Dvb8DpR7/2C68JBJJPXlmMhXCszV3CsrTgA+CgirqtPiIiFEXFVullLsnbMtRSZ/Coi3gL+TrIg5hpKZp3uwtp1ZbYkWQSzfh2tF4qc795IkUyC1bdlv5qZleAT4HqSmcKLioh5ad6GFaFNSZYVaHYdqfSacSpwRvpPlrUhruBYW7Ez8FwT+0eSLD53J3B4/e2iQpK2AbYBXk6TjpU0k2R2zh7APWn6ROAlSXdK+pd0VuKi0rJOIF13KrV32rx9n6SqW4TOrI27BjheTSwBI+krJGtILUmTzkm/74uB+RExM0tBEfEKyQK5W25IwNb6XMGxNknSNWkF4llJmwKHAXdFxHKSacMPLsheX5H5PfAvBato19+6+hzJgnajAdJbSoOAB0nWSyqsuDTm30lunT2ebj8HbB0RA0mW8bhrQ35XM1tX+j3/LXBmI7vrKzKXA8fG2sne6m9RbQl0SWettnbMFRxrK+ZSsOhfRJxOsgBfb5LKTHdgdjqVeQ3r3qaq72vzlYi4s+GJ0wvgPSQLZdan/T0irk3LGKhkobkH0s6Hk+rzSRqXxnBuwbHLI2Jl+vxeoFMT/QXMrGV+CZxMcnu50MT0+75fwT8da0TExyT/tAyW9MWCwQDfa6yQtOV3FfBWvuFbubmCY23Fw0BnSd8vSNs8/TkSOCUi+kVEP6A/ySrdm5NdDUn/HCQdXnC/fTuSi9s7EXFweuE8Jc13CknlamRErK4/kaTP1R8vaS+S79nS0n5dM2tK2hJ7O0klJ7P0u7kv8PeIeK1gMMB1jeTtDVwHXF3QEmRthNeisjYhXQjxSGCipPNI7qu/SzK6YSLwvYK870p6Avh6M6c9VlINSQVkEXBSmn5CWs57JJ0Uj4+IVY0cfx2wEHgqrc/ckd7eOgr4vqRPSFaWP84XR7Oy+AWQdbHacyR9G+gE/I3k1nJjNktvcXUi+f7fDFyxgXFaBXgtKjMzM2t3fIvKzMzM2h1XcMzMzKzdcQXHzMzM2h1XcMzMzKzdcQXHzMzM2h1XcMzMzKzdcQXHzMzM2h1XcMzMzKzd+f/eLQdLxmLEjQAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_cas['app']\n", - "gap_22_cas = df_gap22_cas['simSeconds'].astype(float)*1000\n", - "gap_22_ram = df_gap22_ram['simSeconds'].astype(float)*1000\n", - "gap_22_noDC = df_gap22_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "\n", - "gap_25_cas = df_gap25_cas['simSeconds'].astype(float)*1000\n", - "gap_25_ram = df_gap25_ram['simSeconds'].astype(float)*1000\n", - "gap_25_noDC = df_gap25_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "\n", - "app_npb = df_npbC_cas['app']\n", - "npb_C_cas = df_npbC_cas['simSeconds'].astype(float)*1000\n", - "npb_C_ram = df_npbC_ram['simSeconds'].astype(float)*1000\n", - "npb_C_noDC = df_npbC_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "npb_D_cas = df_npbD_cas['simSeconds'].astype(float)*1000\n", - "npb_D_ram = df_npbD_ram['simSeconds'].astype(float)*1000\n", - "npb_D_noDC = df_npbD_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "\n", - "# Multi bar Chart1\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,3])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_22_cas[i]/gap_22_noDC[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - " plt.bar(i*3+1, gap_22_ram[i]/gap_22_noDC[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", - "\n", - "offset = i*3+2\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_C_cas[i]/npb_C_noDC[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*3+2, npb_C_ram[i]/npb_C_noDC[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "\n", - "# Multi bar Chart2\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,3])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_25_cas[i]/gap_25_noDC[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - " plt.bar(i*3+1, gap_25_ram[i]/gap_25_noDC[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", - "\n", - "offset = i*3+2\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_D_cas[i]/npb_D_noDC[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*3+2, npb_D_ram[i]/npb_D_noDC[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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ujUvvvhiIV6ierPlllvy0UcfAXDllVey2267MXPmTA47LKmNe+211+jRowd9+/blySefLN9u0KBBTJo0iUcffZQjj1y3Gqi6sHjxYrbccsvy5ZYtW7J69WqWLl3KL3/5S66++mp69+5NaWkpM2bM4KabbgKo8vwrc8kll/Dwww/z3HPPcdddd61TrWQhGxk/CDwoqRUwADgX6CDpRmBSRDxeqGOZma3vOnbsyIcffviN9Mcee4xrr72WiODjjz8G4Be/+AUnnngim2++OaNHj2bBggXlXyzNmjVjzZo1DB8+nLlz57J8+XIGDRrEe++9x+67J6N77LXXXjz++OMsXbqU+fPnc8ghhwDw8ccfExHVNvysar8ACxYsoGXLllxzzTUAzJ8/nwsvvBBJfPbZZ+y9994Ffa3q2gcffMBOO+3EO++8w/Dhwxk2bBgDBw7kX//6FytWrGDu3Ln07duXL774gh122KG8MLPDDjvw+uuv06pVKzbZZJN6/i9yq3wOrlq1ihYtWtChQwc6deoEwKxZsxg1ahRffvklb7zxBsA3zr9Mc+bMoX///kByC2zJkiVstdVWtYqv4DfHImJlRNwdEUcBnYBXgf8p9HHMzNZnRxxxBHfeeScrVqwA4O2332bx4sWMGTOGv/71rzz00EPlXx4HHXQQd9xxBx06dGDy5MnsuOOOzJgxA0hqZWbPns3KlSt55plnOOOMM4gIttlmG+bOnQskNQ4A7dq1Y7fddmPatGmUlpYyZ86crL1aqtovJF/kgwcPZvjw4UAycevVV19NaWkpr7zyCgMGDCjOi1YHPvjgA5544gl69OhRnta8eXPOPPNMxo0bxwMPPMD48eOZOnUq06dPZ/Hixaxdu7Y87w9/+EOGDMlrhqN6d/jhh3P77bezcuVKAMaNG8fAgQMrFFp+97vfMX78eJ588knatm0L8I3zL1O3bt2YMmUKpaWlvPbaa7Uu3EANanAkbRwRn+fI0xzYNCKWpkkrSW5T1T5CM7NGrLpGwuuqffv2/OpXv6Jfv35EBJttthm33nor/fr1o3fv3uy9997lXygDBgzgP//5DwB/+ctfOPDAAznxxBO5/PLL2X///bnooot4++236du3L9/97nfZaqut6NixI3vttRe9evWia9euQPJr+/zzz+fggw9GEjvvvDM33HBDhbiuvvrq8t5B48aN+8Z+y5x00kmMGTOG3/72t1x00UWccsopfPrppzRr1ozx48fTuXPndXp9qmskXCw///nPadeuHRtuuCHXX389G220UYX1hx56KBdffDEbbLBBhd5SO++8M88++2z5clnPqYULFxYkrmyNhNdVhw4dGDFiBH379qVZs2Z069aN4cOHc/fdd5fnGTRoEAMGDGCPPfYoPx8vvPDCCuffb37zm/L8o0aN4qijjio/p++///5ax5dzNnFJ+wPjgW9HxNaSugI/i4jTK+U7HriJpFDzd2A0cBvwMvDriHi11lFWwbOJm9UPzyae3fz589lpp53qOwyzJqvyZ6y62cTzqcEZBxwGPAwQEXMk9a4i38XAXhHxdjrh5ovA0RHxSG3+ATMzM7PayqsNTkS8Xympqu7fqyPi7TT/q8DfXbgxMzOz+pBPDc776W2qkNQCOIdkxvDKOkg6P2O5beZyRFy9bqGamTUO2XoWmVnt5WpWkymfGpxTSeaR2gr4ANiDqueVugVonfGovGxm1uS1bNmSZcuW1ehCbGa5lc0m3rJly7zy56zBSXtEnZBHvlF5HdHMrAnr1KkTixYtynvGYzPLX8uWLcvH2MklZwFHUhfgLKBzZv6I6F9F3j7AmcD30qT5wPURUZpXNGZmjVyLFi3o0qVLfYdhtt7Lpw3Og8CtwCPA2uoySToSuB64LH0I2BO4TdKZEfHoOkdrZmZmlod8CjirIuL3eeQbDgyMiDkZabMlvQJcB7iAY2ZmZnUinwLOtZJGAo8D5dOeVjFw33cqFW7K8v1N0hbrFqaZmZlZ/vIp4OwGDAEO4utbVJEuZ1qZZR/Z1pmZmZkVVD4FnGOAbSMi15zl20l6uIp0AdvWODIzMzOzWsqngDMPaAt8nCNftulfx+YbkJmZmdm6yqeA0xZ4U9LLVGyDU6GbeEQ8XXlDSXsWepJNMzMzs1zyKeCMXIf9jyfpKm5mZmZWZ/IZyfgbNTM1kPdkLJK+C9wObEHSiPnmiLh2HY5tZmZm66lqCziSnouInpJWkBQ4ylcBERGb5LH/mkzf8BXw84h4VVJrYJakJyLijRrsw8zMzKz6Ak5E9Ez/1niiTEldgV5lz6saH6eK4y0GFqfPV0iaTzLBpws4ZmaN2L4jH8uZZ8aow+ogEluf5DMX1R0RMSRXWsa6c4CfAg+kSXdKujkirss3KEmdgW7AS/luY2Zmlo0LWuuXfBoZ75K5IGkDYK8s+U8C9omIlWn+3wIvkkzXkJOkbwP3A+dGxPJK604BTgHYeuut89mdmZmZrYeytcEZAVwEbCSprKAhYDVwc5Z9CliTsbyGPBsbS2pBUri5KyIeqLw+Im4uO3b37t2j8nozs4bANQVm9S9bG5wxwBhJYyJiRA32OQF4SdKkdHkgyWzkWUlSmm9+RFxdg+OZmZmZVZBPN/GaFG6IiKslPQ0ckCYNi4jX8tj0AJI5r+ZKmp2mXRQRnoXczMzMaiSfNji1MZukR9QGAJK2joj/y7ZBRDxHDcbNMTMzM6tOwQs4ks4iGf34n3zd/iaA3Qt9LDMzM7Oq5FXAkdScZITh8vxZamTOAXaMiGXrHp6ZWf7cuNfMyuQzDk5mjczaNDlbjcz7wKcFic7MzMysFvKpwalpjcw7QKmkKVScfdw9o8zMzKxO5FPAqWmNzP+ljw3Th5kViW/J1Fz/B4/Muv7hgVPqKBJriHx+NB35FHBqVCMTETWZYNPMzMys4PIp4LhGxszMzBqVfAb6GwXlc0QREZ8VOyj7Wq5bEL79YGbV8S1MW581y5VB0q6SXgNeB16XNEvSLrm2MzMzM6svOQs4JJNbnh8R20TENsDPgVuqyyypk6RJkpZI+ljS/ZI6FSpgMzMzs1zyaYPTKiKmly1ERKmkVlnyTwDuBo5Jl3+cph1a6yit3vlWmZkVk3svWaHlU4PzjqRfSeqcPi4m6VlVnfYRMSEivkofE4H2BYnWzMzMLA/51OD8NzAKeCBdfjZNq84yST8G/pwuDwY8bYOZmdXaTQPuzJnnZw/9uA4iscYin15U/wbOrsE+/xu4DhhHMqXDC8DQ2gRnZmZmVhvVFnAkXRMR50p6hKSgUkFE9K9m006V10k6gGRE5EbDbU7MzMwar2w1OHekf8fWcJ/XAXvmkWbWaLkAbGbWsFVbwImIWenTPSLi2sx1ks4Bnq6Uth+wP9Be0vkZqzYBmhcmXKssV88DcO8DMzNb/+TTyPhE4NpKaUOrSNsQ+Ha6z9YZ6cuBo2sZn1mj5IKn5eJu0WbFla0NzmDgR0AXSQ9nrGoN/Kty/oh4Gnha0sSIeK/gkTYw/gIzs2JyryGzdZOtBucFYDHQDrgqI30F8LfqNlofCjdmZmbWsGVrg/Me8B6wX92FY5adG/eaWVPga1nx5WyDI2kFX3cT3xBoAayMiE2KGZg1Lr5lZ9Y4uS1QzfjWYeORz0B/5Q2GJQkYAOxbOZ+k66hivJyM/dRksEAza0Ry/RoF/yI1s7qVTy+qchERwIOSRgIXVlr9Svr3AGBn4N50+RjgjXUJ0ixfjakmKdcvQf8KNLNia8q3yvK5RfWDjMVmQHdgVeV8EfGnNP9pQM+I+Cpd/iPJ/FXrHX+BmZmZ1Y98anCOynj+FbCQ5DZVdTYlGdyvrCv5t9O0rCTdBvQDPo6IXfOIy8zy4DYWNeM2FmZNQz5tcIbVcJ9XAK9Jmg4I6A1cmsd2E4HrgdtreDzLwTVJZma2vmmWK4OkP0lqm7G8aVrbUqWImADsA0wCHgD2K7t9lU1EPEMVAwiamZmZ1ZSSdsNZMkivRUS3XGkZ6wScAGwbEZdJ2hr4TkTMzBmM1BmYnM8tqi5dusTIkSNzZau1VxdmL2tt+O0Pcu5js486ZF2/5a5bOI56iGPXdrvlzFMXcdTF65FPLDV9PWbPng3AHnvsUaM49uy8WY2OUxuFeD1yvS+Q+71xHI4jl1yx1MXnpSHFsS6GDRs2KyK6V07Ppw1OM0mbRsS/ASRtlmO7PwBrgYOAy0hGPr4f6FHjqCuRdApwCsBWW221rrszMzOzdfThvH9mXZ9Pga8Y8ingXAW8KOkv6fIxwOgs+feJiD0lvQYQEf+WtOE6xkm6r5uBmwG6d+8eQ4cOLcRuq/THHF3nOvzXtJz7OPLZKiu5yg0dm7vti+MofBzbT8geRz5tkhrL65FPLGMHXpV1fWUlJSUAXHPNNTWK4/dDi9/dtBCvR673BXK/N47DceSSK5a6+LzkE8fCtr/PuY8j/z446/p8Xo91MWxY1U2F82lkfLukV0hqZAB+EBHZxrX5UlJz0kH/JLUnqdExswaornoNuTeXmdWlfAf624xkeoYJktpL6hIR71aT9/ckDYw7SBoNHA1cnOsAkv4MlADtJC0CRkbErXnGZ2Zm1mQ0pkFLG6p8BvobSTK4347ABJK5qO4kGbH4GyLiLkmzgINJuokPjIj5uY4TEdnruMysSfP4M2Y14yFAssvZTRwYBPQHVgJExIdA6+oyS7oVaBkRN0TE9RExX9KlhQjWzMzMLB/5FHBWp3NQlbWpaZUj/2HAnyT9JCOtfy3jMzMzM6uxfAo490m6CWgr6afAk8D4LPk/Jhm9+BhJN0jagORWlZmZmVmdyKcX1VhJhwLLSdrhXBIRT2TZRBHxKXBUemuqFGhTgFjNzMzM8pJPI+OT0t5MT6TLzSWNjIhR1WzycNmTiLg0bXB8XkGiNTMzM8tDPreoDpb0qKSOknYBZpClkXFEjKy0/EhEHFRdfjMzM7NCy+cW1Y8kHQfMJelJ9aOIeL5yPknPRURPSStIGySXrUp2E5sUKmgzMzOzbPK5RbU9cA7JfFI7AUPSyTY/z8wXET3Tv9XW7piZmZnVhXxGMn4EOCMipqUzhZ8PvAzskpkpnYSzWhGRexpXMzMzswLIp4Czd0Qsh+Q+E3CVpEeqyDeL5NZUVV3CA9i21lGamZmZ1UC1jYwl/QIgIpZLOqbS6qGV80dEl4jYNv1b+eHCjZmZmdWZbL2ojs94PqLSur7ZdippU0l7S+pd9qh1hGZmZmY1lO0Wlap5XtXy1yukk0kaJXcCZgP7Ai8C7ipuZmZmdSJbDU5U87yq5UznAD2A9yKiD9AN+KRW0ZmZmZnVQrYanK6SlpPU1myUPiddbpllu1URsUoSkr4VEW9K2rFQAZuZmZnlUm0BJyKa13KfiyS1BR4EnpD0b+C9Wu7LzMzMrMby6SZeIxExKH16qaTpJBNtTi30cczMzMyqk89cVDWW9qLaHVgBLAJ2LcZxzMzMzKpS8BocSb8mGSfnHWBtmhy4F5WZmZnVkYIXcIBjge0iYnUR9m1mZmaWUzFuUc0D2hZhv2ZmZmZ5KUYNzhjgNUnzgC/KEiOifxGOZWZmZvYNxSjg/An4LTCXr9vgmJmZmdWZYhRwPo+I3xdhv2ZmZmZ5KUYB51lJY4CHqXiL6tUiHMvMzMzsG4pRwOmW/t03Iy2vbuKS+gLXAs2B8RFxReHDMzMzs6auoAUcSc2BhyNiXC23vQE4lGRwwJclPRwRbxQyRjMzM2v6CtpNPCLWAINrufnewNsR8U46hs49wICCBWdmZmbrjWLconpe0vXAvcDKssQ82uBsBbyfsbwI2Kfw4ZmZmVlTp4go7A6TCTYri4jI2gZH0tFA34g4OV0eAuwTEWdm5DkFOCVd3BF4qzBRF0Q7YGl9B0HDiQMaTiyOoyLHUZHjqMhxVOQ4KmoocWTaJiLaV04sxmzifWq56QfAdzOWO6Vpmfu+Gbi5lvsvKkmvRER3x/G1hhKL43AcjsNxOI6mFUc+Cj5Vg6Q2kq6W9Er6uEpSmzw2fRnYXlIXSRsCx5N0NTczMzOrkWLMRXUbsIJk0s1jgeXAhFwbRcRXwJnAY8B84L6IeL0I8ZmZmVkTV4xGxttFxA8zlkdJmp3PhhHxKPBoEWKqCw3l1llDiQMaTiyOoyLHUZHjqMhxVOQ4KmooceRUjEbGLwLDI+K5dPkAYGxE7FfQA5mZmZlVoxgFnK7A7UAbQMC/gKERMaegBzIzMzOrRsHb4ETEnIjoCuwO7BYR3Zpa4UZSZ0nzGmIMknpJel3SbEkb1Uds1nBIaivp9PqOA7Kes+dK2rg+YmoIJJ0tab6klZJ2rqcYXqiP41Ym6bP6jsGajoK3wZH0LeCHQGdgA0kARMRlhT6WVekEYExE3FnfgTRUkpqno26vD9oCpwN/qOc4sjkXuBP4vJ7jqC+nA4cAlwM7A3U+PU1E7F/XxzQrtmL0onqIZIqFr0hGMi57NDUbSLor/eX1v5I2ltRD0guS5kiaKal1HcdwNknPtV+n6R0lPZPW5syT1KuYwUj6iaS/pf//HZK2kDQpXZ4jqegX0bSW4M0q3puFkn4r6VXgmAIer5WkKen/N0/ScZKukPRG+lqMTfMdk66fI+mZNG2opIcklUr6u6SRhYorwxXAduk5cKWk/5E0N42jPiazreqc3RKYXs0goQVVxTm6naQZ6WtyeV3XIEj6I7At8C5wInBl+l5tV8dxfJb+rdNrRpZ4SiRNzli+XtLQIh6v7LoxUdKC9Bw9RNLz6Wdzb0ntJT2R1pCPl/SepHZFiqeq68pCSb9Lz9WZkv6rGMeuFEeFWldJF0i6VNJPJb2cxne/GmoNbEQU9AHMK/Q+G9qDpHYqgAPS5duAXwDvAD3StE2ADeo4hguAicDRadrPgV+mz5sDrYsYzy7AAqBdurwZyXQd52Ycv009vTcXAAuBXxTheD8EbslY3oZkhO2y9m1t079zga0qpQ0FFgObAxsB84DuRXg95qXPDwdeADYue4+K/X7U4L1pVwfHr+ocnQwMTpdPBT6ry9ckPe5CktFhyz+79RDDZ+nfOrtm5IijBJickX49SVvOYp6bXwG7kfzwn5WenyL5wf5gGsOINH/f9FwuynlbxXWlTXqelL03P8l8fYr8uszLWL4AuBTYPCPtcuCsujxP8n0UowbnBUm7FWG/Dc37EfF8+vxO4DBgcUS8DBARyyMZ26cuY+hZaf3LwDBJl5K0h1pRxFgOAv4SEUsBIuJfadqN6fKaiPi0iMfPVN3rcm8RjjUXODStHepFMvr2KuBWST/g69suzwMTJf2U5IujzBMRsSwi/gM8wDffw0I6BJgQEZ9D+XtU13Kds8VU1Tm6H/CXdP3ddRhLQ1WX14yG5t2ImBsRa4HXgWmRfIPPJfmi70kyCTQRMRX4dxFjqXBdybh2/jnjb332TN5V0rOS5pI0i9ilHmOpVjEKOD2BWZLeSquC50r6WxGOU98qdz9b3gBiqLAcEc8AvUm+dCdK+kldBVbPqntdCn6rNCIWAHuSXJAuBy4C9gb+F+gHTE3znQpcTDIdySxJm+eItala3/7fRqUBXTO+ouL3U8s6OOYXGc/XZiyvpThjxlWr8nVF0iVlqzKz1UEo1b0PE4EzI2I3YBR18/7UWDEKOIcD2wPfB44iucgfVYTj1LetJZWVoH8EzAA6SuoBIKm1pGJ/KCrH8FzmSknbAP+MiFuA8SQfmGJ5Cjim7Itb0mbANOC0dLm58puyoxCyvi6FJGlL4PNIGnVfSfLl0CaSQSvPA7qm+baLiJci4hJgCV/Pu3aopM2U9HgbSFLTU0grgLK2YE+Q/DrfOI1pswIfKx9VvTeZMRZTVefoDJLbAZBMD1Of6up1qFYdXzOyeQ/YWdK3JLUFDq6nODI9T9LGEUnfBzYt1oGquK6UvQ/HZfx9sVjHz/BPoIOkzZV0IOqXprcGFktqQVKD0yAVY7LN9wq9zwbqLeAMSbeR9Hq4juQCel36ZfUfklsCxWy0WDmGG6nYW6YEGC7pyzSOov0ai4jXJY0Gnpa0BngNOAe4WdJJwBqSwk5dfCirel3OKtKxdiNpGLoW+BI4H5gsqSXJ/fvz03xXSto+TZsGzAH2AGYC95NMLntnRLxSyOAiYlnaUHIe8FeS+d1ekbSaZNTwiwp5vDxU9d6sBqZK+jBqP1lvTtWco+cCd0r6JUltW13dRq3KPcAtShpeHx0R/6iHGEqoo2tGNhHxvqT7SNqlvUvyXtW3UcCfJQ0huY59RFIoLYbK15XTSGqFN03viHwBDC7SsctFxJeSLiO5Tn0AvJmu+hXwEsmPtZeo54J5dQo+0J9ZfZLUmaTx3a71HUsuaa+Q7hFxZn3Hsr5Ka7P+ExEh6XiSBscD6jsua3jSGow1EfFVWgt5Y0TsUYfHX0hyvVhaV8ds7Or0vqKZWQOzF3C9JAGfAP9dv+FYA7Y1cJ+kZiS1jj+t53gsB9fgmJmZWZNTjEbGZmZmZvXKBRwzMzNrclzAMTMzsybHBRxrNJTMbXW3pHckzZL0oqRBGeuvkfRB2giwLG2opCVK5tZ5Ix1JuHL660rnrErX7SvppXTd/HRU16riuSsd0HKepNvSMSGQdELGIJcvSOpa1BfGbD0iKSRdlbF8QdlnVMk8SR/o67m0+leR/qakGzOvE5X2/x1J90j6R3qdeVTSDnXyz1lBuYBjjULay+VB4JmI2DYi9iIZmK1Tur4ZMAh4Hziw0ub3pt05S4DfSNoiMz0idiHpFVE2iNafgFPSbXYF7qsmrLuA75GMWbERcHKa/i5wYDrK56+Bm2v3X5tZFb4AfqDqJ7ocl352jwFuyyjIlKXvTPKZrXydKLvOTAJKI2K79DozAtiicl5r+FzAscbiIGB1RPyxLCEi3ouI69LFEpL5Y26kmgGwIuJj4B8kE2KWUzLidCu+nlumA8kkmGVzaL1Rzf4ejRTJQFid0vQXIqJsXzPK0s2sIL4i+dFwXrZMETE/zVu5ILQhydQCVc0l1Qf4stJ1Zk5EPLtOEVu9cAHHGotdgFezrB9MMgHdJODIsttFmSRtC2wLvJ0mHSdpNskInZsBj6Tp44C3JE2S9LN0VOJqpccaQjrvVCUnkYwgbGaFcwNwgrJM/yJpH5J5pJakSeeln/fFwIKImF3FZruSzCRuTYALONYoSbpB0hxJL0vaEDgCeDAilpMMHX5YRvaygsyfgZ9lzKJdduvqOyST2g0HiIjLgO7A4yTzJVVVcMn0B5JbZxV+5UnqQ1LA+Z9a/6Nm9g3p5/x24OwqVpcVZMYCx8XXg72V3aLqALRKR662JswFHGssXidj4r+IOINkAr72JIWZtsDcdDjznlS8TVXW1mafiJhUecfpBfARkokyy9L+ERE3psfoqmSyucfSRorjy/JJGpnGcH7mPiXtTjJZ4YCIWLZO/7mZVeUakh8QrSqlj0s/772qurUUEV+S/GjpLem76Wd6tqRTSa4zexU7cKsbLuBYY/EU0FLSaRlpG6d/BwMnR0TniOgMdCGZpXtj8teTpH0Oko5MGxsCbE8yUegnEXFYeuE8Oc13MknhanBErC3bkaStgQeAIRGxoKb/qJnlltbE3kdSyMlb+tk+APhHRLyffqb3SNvdPAV8S9IpGfl3l9SrkLFb3XABxxqFtJZlIHCgpHclzSTp7TQS6AtMyci7EngOOCrHbo9Lf7n9DehG0uMJkvY0b6XV3HcAJ0TEmiq2/yNJ74oX0/1ckqZfAmwO/CFNL+gM4WZW7iq+2Yi4OmW3ruYBzUluLVeQXmcGAYek3cRfB8aQzBxujYznojIzM7MmxzU4ZmZm1uS4gGNmZmZNjgs4ZmZm1uS4gGNmZmZNjgs4ZmZm1uS4gGNmZmZNjgs4ZmZm1uS4gGNmZmZNzv8DuCTvF+TCh7YAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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b9+el156qRAvUaPZYost+PDDDwG48sor2W233Zg2bRqHHZbUyL3++uvsueee9OnTh6effrpqu4EDBzJx4kQee+wxjjxy3WqgSmHRokVsscUWVctt27Zl1apVLFmyhF/96leMGTOG3r17U1FRwcsvv8zNN98MkPX8q3TJJZfw8MMP88ILL3D33Xe7VtLMmr1CNjJ+EHhQUjugP3Au0FnSjcDEiHiyUMdqTF26dOGDDz74WvoTTzzBtddeS0Tw0UcfAXDhhRdy4oknsvnmmzNq1Cjeeeedqi+WVq1asWbNGoYNG8bs2bNZunQpAwcOZP78+Xzve0mP+j322IMnn3ySJUuWMHfuXA455BAAPvroIyKi1saf2fYL8M4779C2bVuuueYaAObOnctFF12EJJYvX85ee+1V0Neq1BYuXMhOO+3Ee++9x7Bhwxg6dCgDBgzgX//6F8uWLWP27Nn06dOHL774gh122KGqMLPDDjvwxhtv0K5dOzbZZJNG/i9yq3kOrly5kjZt2tC5c2e6du0KwIwZMxg5ciSrV6/mzTffBPja+Zdp1qxZ9OvXD0hugS1evJgtt9yyFP+OmVlRFPxGfUSsiIg/R8RRQFfgNeC/Cn2cxnLEEUdw1113sWzZMgDeffddFi1axOjRo3n88cd56KGHqr48DjroIO688046d+7MpEmT2HHHHXn55ZeBpFZm5syZrFixgueee44zzjiDiGDrrbdm9uzZQFLjANCxY0d22203pkyZQkVFBbNmzaqzZ0u2/ULyRT5o0CCGDRsGJJMljhkzhoqKCqZPn07//v2L86KVwMKFC3nqqafYc889q9Jat27NmWeeydixY3nggQcYN24ckydPZurUqSxatIi1a9dW5f3Rj37E4MF5zSrS6A4//HDuuOMOVqxYAcDYsWMZMGBAtULLH/7wB8aNG8fTTz9dNX5NzfMvU48ePXj00UepqKjg9ddfd+HGzJq9vGtwJG0cEZ/lyNMa+GZELEmTVpDcpirp1bKuRsLrqlOnTvzmN7+hb9++RASbbbYZt912G3379qV3797stddeVV8o/fv35/PPPwfgr3/9KwcccAAnnngil19+Ofvttx8XX3wx7777Ln369OE73/kOW265JV26dGGPPfagV69edO/eHUh+bZ9//vkcfPDBSGLnnXfmhhtuqBbXmDFjqnoHjR079mv7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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_cas['app']\n", - "gap_22_cas = df_gap22_cas['simSeconds'].astype(float)*1000\n", - "gap_22_ram = df_gap22_ram['simSeconds'].astype(float)*1000\n", - "gap_22_orc = df_gap22_orc['simSeconds'].astype(float)*1000\n", - "gap_22_noDC = df_gap22_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "\n", - "gap_25_cas = df_gap25_cas['simSeconds'].astype(float)*1000\n", - "gap_25_ram = df_gap25_ram['simSeconds'].astype(float)*1000\n", - "gap_25_orc = df_gap25_orc['simSeconds'].astype(float)*1000\n", - "gap_25_noDC = df_gap25_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "\n", - "app_npb = df_npbC_cas['app']\n", - "npb_C_cas = df_npbC_cas['simSeconds'].astype(float)*1000\n", - "npb_C_ram = df_npbC_ram['simSeconds'].astype(float)*1000\n", - "npb_C_orc = df_npbC_orc['simSeconds'].astype(float)*1000\n", - "npb_C_noDC = df_npbC_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "npb_D_cas = df_npbD_cas['simSeconds'].astype(float)*1000\n", - "npb_D_ram = df_npbD_ram['simSeconds'].astype(float)*1000\n", - "npb_D_orc = df_npbD_orc['simSeconds'].astype(float)*1000\n", - "npb_D_noDC = df_npbD_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "\n", - "# Multi bar Chart1\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,3])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*4, gap_22_cas[i]/gap_22_noDC[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - " plt.bar(i*4+1, gap_22_ram[i]/gap_22_noDC[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", - " plt.bar(i*4+2, gap_22_orc[i]/gap_22_noDC[i], width=1, color=cmap(3), label='Oracle' if i==0 else None)\n", - "\n", - "offset = i*4+3\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*4+1, npb_C_cas[i]/npb_C_noDC[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*4+2, npb_C_ram[i]/npb_C_noDC[i], width=1, color=cmap(2))\n", - " plt.bar(offset+i*4+3, npb_C_orc[i]/npb_C_noDC[i], width=1, color=cmap(3))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", - "plt.legend(fontsize=8, ncol=3)\n", - "plt.tight_layout()\n", - "\n", - "# Multi bar Chart2\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,3])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*4, gap_25_cas[i]/gap_25_noDC[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - " plt.bar(i*4+1, gap_25_ram[i]/gap_25_noDC[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", - " plt.bar(i*4+2, gap_25_orc[i]/gap_25_noDC[i], width=1, color=cmap(3), label='Oracle' if i==0 else None)\n", - "\n", - "offset = i*4+3\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*4+1, npb_D_cas[i]/npb_D_noDC[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*4+2, npb_D_ram[i]/npb_D_noDC[i], width=1, color=cmap(2))\n", - " plt.bar(offset+i*4+3, npb_D_orc[i]/npb_D_noDC[i], width=1, color=cmap(3))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", - "plt.legend(fontsize=8, ncol=3)\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_cas['app']\n", - "gap_22_cas = df_gap22_cas['totBW'].astype(float)\n", - "gap_22_ram = df_gap22_ram['totBW'].astype(float)\n", - "gap_22_noDC = (df_gap22_noDC['farAvgRdBWSys'].astype(float)+df_gap22_noDC['farAvgWrBWSys'].astype(float))/1000000000\n", - "\n", - "\n", - "gap_25_cas = df_gap25_cas['totBW'].astype(float)\n", - "gap_25_ram = df_gap25_ram['totBW'].astype(float)\n", - "gap_25_noDC = (df_gap25_noDC['farAvgRdBWSys'].astype(float)+df_gap25_noDC['farAvgWrBWSys'].astype(float))/1000000000\n", - "\n", - "app_npb = df_npbC_cas['app']\n", - "npb_C_cas = df_npbC_cas['totBW'].astype(float)\n", - "npb_C_ram = df_npbC_ram['totBW'].astype(float)\n", - "npb_C_noDC = (df_npbC_noDC['farAvgRdBWSys'].astype(float)+df_npbC_noDC['farAvgWrBWSys'].astype(float))/1000000000\n", - "\n", - "npb_D_cas = df_npbD_cas['totBW'].astype(float)\n", - "npb_D_ram = df_npbD_ram['totBW'].astype(float)\n", - "npb_D_noDC = (df_npbD_noDC['farAvgRdBWSys'].astype(float)+df_npbD_noDC['farAvgWrBWSys'].astype(float))/1000000000\n", - "\n", - "\n", - "# Multi bar Chart1\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "#plt.ylim([0,2.5])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - " plt.bar(i*3+1, gap_22_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", - "\n", - "offset = i*3+2\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_C_cas[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*3+2, npb_C_ram[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "#plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Observed BW at LLC (GB/s)\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "\n", - "# Multi bar Chart2\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "#plt.ylim([0,2.5])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - " plt.bar(i*3+1, gap_25_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", - "\n", - "offset = i*3+2\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_D_cas[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*3+2, npb_D_ram[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "#plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Observed BW at LLC (GB/s)\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAagAAADfCAYAAACj4kcNAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAo4UlEQVR4nO3deXgUVdr38e8tyO6ICooSFgVfHVEByQiYKGFxRUUZ1GHcUBDmETcYHZXRAcblcRlcGBUHF0BxGXciOCoKQWQRiIq4gwwIPC6AKC7s3O8fVYlNSNKdTnXSIb/PdeVK1+nqc05Vd+dOVZ26j7k7IiIi6Wa3yu6AiIhIcRSgREQkLSlAiYhIWlKAEhGRtKQAJSIiaalmZXegPBo1auQtW7as7G5INfXZZ58BcMghh1RyT0Sqtvz8/DXu3rhoeZUOUC1btmTBggWV3Q2ppnJycgDIy8ur1H6IVHVmtry4cp3iExGRtKQAJSIiaUkBSkRE0lKVvgYlIpJKW7ZsYeXKlWzcuLGyu7JLqFOnDhkZGey+++4Jra8AJSJSgpUrV7LHHnvQsmVLzKyyu1OluTtr165l5cqVHHjggQm9Rqf4RERKsHHjRvbZZx8FpwiYGfvss0+ZjkYVoERESqHgFJ2y7kud4hMRSUCn4a9FUs/ckSdGUk91oCMoEZE0s2zZMvbaay9ycnLo2LEj99xzT7nqa926deHj5cuX069fPwCee+45jjvuOLp06UKXLl14/fXXWbZsGT169ChXe1HREZSISBrq0KEDb7zxBtu2beOwww7jkksuoX79+uWuNzc3l9NOO405c+bwwAMP8Morr9CgQQN++eUX8vPzI+h5dHQEJSKSxn755Rc2b97M1q1bGTBgAF27diU7O5t58+YBcNddd9GtWzd+97vfMXz4cAC2b9/OeeedR5cuXRgyZMgO9b3++uuceOKJjBs3juuvv54GDRoAUK9ePY499tgd1l2xYgU9e/akW7du9OzZk9WrVwNw4YUXkpOTw1FHHUVubi4A48eP54wzzqB3794cfvjhzJw5s9zbnrIAZWaPmtm3ZvZhTNneZjbVzBaHv/cKy83MRpvZEjP7wMyOSlW/RESqgvz8fLp06UKzZs0YPHgwTz31FK1bt2b69Ok8//zzhYFn0KBBTJs2jXnz5jF16lS+/PJLJk2aRP369ZkxYwZ9+vRh69atAKxfv57ddtuNBg0asGLFCpo1a1ZqH6655hpuvPFGpk2bxsCBA7n99tsBeOCBB8jLy2Pq1KkMGzZsh9e88MILjB07lnvvvbfc+yCVp/jGA/cBj8WUXQe86e63mdl14fK1wMnAweFPR2BM+FtEpFoqOMW3cOFCrr32Wlq1asXs2bN59dVXAfjhhx8AeP7553n44YcxM5YuXcqKFSv4/PPPOfroowHo2LFj4ei5//znP5x00kkANGvWjC+//JJDDz20xD4sWrSI6667DoCtW7fSunVrtm/fzsiRI5k9ezY1a9Zk+fJf87x26NABgObNm7N27dpy74OUBSh3f8vMWhYp7gXkhI8nAHkEAaoX8Ji7OzDXzBqa2f7u/lWq+iciUhW0bduWAw44gDZt2tC6devCI6fNmzcDcOONN/Lpp59Su3ZtsrKycHcOPvhgpk6dSv/+/Zk/fz7Bn1Z4+eWXC4+CLrroIoYNG8YxxxxDgwYN2LBhA/n5+WRkZBS23aZNG66//nrat29f2ObChQv54IMPePvtt1mzZg2tWrUqXD92GHlBm+VR0YMk9osJOl8D+4WPmwIrYtZbGZYpQIlIWqjM4eFDhgxh4MCBtG3blq5duwKQmZnJnXfeSe/evcnKyuLQQw8tvJ7Uq1cvnnvuObp06ULHjh2pWbMmW7du5ZtvvqFp06YAdO7cmcGDB3PKKacUBpYbbrhhh3ZHjRrF4MGD+emnnwC4+OKL6d27N1u2bKFLly60a9eOhg0bpmy7LYooV2LlwRHUZHc/PFz+3t0bxjy/zt33MrPJwG3u/nZY/iZwrbvvNNmTmQ0EBgI0b968Q+zhpUhF0nxQu75PPvmE3/72t5XdjUh8++235Ofnc/LJJ1dqP4rbp2aW7+6ZRdet6FF835jZ/mGH9ge+DctXAbFX6zLCsp24+1h3z3T3zMaNd5qAUUREirHvvvtWenAqq4oOULnAheHjC4FJMeUXhKP5OgE/6PqTiEj1lrJrUGb2FMGAiEZmthIYDtwGPGNm/YHlwNnh6q8ApwBLgF+Ai1LVLxERqRpSOYqvbwlPdS9mXQcGp6ovIiJS9SiThIiIpKWEjqDMbDegLXAAsAH40N2/Lf1VIiK7jtNf6hlJPblnTIm7zrJly2jfvj1t27Zlw4YN9O3bl6uuuirpNlu3bs2SJUuAIFns8OHDycnJYeTIkbRo0YINGzbQvn17br/9dvbcc0/Gjx9P06ZNOf7443eo5/vvvyc3N5cLLrgg6b6URalHUGbWyszGElwbug3oC1wKvGFmc83sojB4iYhIhDp06EBeXh6zZ89mzJgx/Pzzz5HUW5AsFqB///7k5eXxzjvvcMghh3DllVcC0K9fv52C0/bt2/n+++957LHHdqozVeIFl5uBiUArdz/R3c9z9z7ufiRwOrAncH6qOykiUl2lKllsUUOGDGHmzJls376dESNGMHHiRCA4+ho2bBjdu3fn1ltvJT8/n5ycHKZMmUK7du0KM1o8/vjj3HTTTZFue6mn+EoZ6EB4iu+eSHsjIiLAr8liFy5cyA033FCYLPbhhx/mm2++oXfv3syaNYtBgwYxdOhQ3J2srCz69+9Pfn5+YbLYWbNm8eKLLwI7JostTuPGjVmzZs0OZVu3buW0007j1ltvZdmyZSxdupQ33ngDgLlz55Kbm0ufPn2YMGECEyZMiHQflGkUn5m1BkYAdYF/uPucSHsjIiJA6pPFFmf16tU0atRoh7IaNWrQqVOnYtcfMGAAl156Ke3bt6devXqFaZSiUmqAMrM67r4xpugm4C/h45eBdpH2RkREdpCqZLFFjR49mqysLHbbbccrP2ZWGOBq1apVOHUHQIsWLTAzRo4cSf/+/SPf9nhHUC+b2ePuXnBVbAvQEnBgW+S9ERFJU4mMvkuVVCSLBXjkkUd444032LBhA0ceeSSjR48utR9NmjShbt26/P73v+fSSy+le/fu9O/fn8GDB/Poo49Gvt2lJos1sxrA/wCnArcCnwJXEJzie8jdP428R2WQmZnpCxbslE9WpEIoWeyuT8li43vppZeYP38+t9xyS0LrlyVZbLxBEtuA+8zsceBGgmB1g7t/kWjnRUSk8qUiWexdd93FM888w6RJk+KvnIR416A6AtcAmwmOoDYAt5jZKuAmd/8+Jb0SEZG0N3ToUIYOHZqy+uNdg/oXQRLXBsA4d88C/mBmXYB/A5U3g5eIiOzS4gWorQSDIuoTHEUB4O4zgBmp65aIiFR38QLUH4FBBMGpYpIviYiIED9ALXb3P5e2gpmZp3LeeBGRNPCvXhMjqWfQpPMiqac6iJeLb7qZXW5mzWMLzayWmXUzswn8OkOuiIiU06WXXlqYmujjjz9mt91247vvvgPggQce2Cnf3bnnngsEGdBzc3MTaqNnz5788ssvLFu2jN69e5OTk8MxxxzDNddcAwS3UKxcuTKqTUpavAB1EsENuU+Z2f+Z2cdmthRYTJDZ/B53H5/iPoqIVBvZ2dnMmjULgFmzZtGtWzdmz55duHzssccWrrtt2zaeeOIJIPEAtW7dOmrXrk2tWrXo06cPw4YNK8ya3qNHjxRsUfJKDVDuvtHdHwhH77UgmA33KHdv4e6XuPt7FdJLEZFqIjs7m7fffhsIAtI111xTuDxv3jzGjBnDn/70J0499VRmzpxJ69atgeCepClTppCTk0N+fj6LFi2iR48edOvWjbPPPpsNGzYA8Morr3DyySczb948DjnkEDIzf70/trgs59dffz1dunShc+fOTJ48GYAnn3ySrl270rlzZwYMGFCYSql58+YMGjSITp06cfXVV5d7XyQ8l5O7b3H3r3Tvk4hI6jRv3pw1a9awYcMGvvrqK3r06MGiRYtYuXIljRo1om7durRo0YLJkycXZjOB4J6knj17kpeXR4cOHQrTD02bNo2srCweeeQRACZPnsxpp53GihUraNasWal9efXVV1m3bh0zZszgzTff5K9//SvuTq9evZg+fTpz5szhxx9/ZObMmUCQrWLkyJHMmTOHyZMns379+nLtizJlMxcRkdQ7+uijyc3NpUmTJtSoUYMaNWowbdo0srOzWb16Ncccc0zcOj766KPCmW83btxIjx492LJlC2vXrqVJkyY0a9YsbgaIRYsWMWPGjMJAuGnTJtauXcv8+fO588472bZtG8uXL+f0008HoGnTpjRp0gSAjIwM1q1bx29+85uk94NmwxURSTPZ2dnccccdhYHoqKOO4t577y28/lSjRo2dXlM00/jhhx/OU089RV5eHnPnzuVvf/sbeXl5dOnSBQiC4Oeff05sPtPXX399hzrbtGnDCSecQF5eHnl5eXzwwQc0atSI6667jieeeIIZM2bQsWPHwlN8BVnPC5R3gHfCR1Bm1gI42N3fMLO6QE13/7FcrYuIVBEVOTw8OzubwYMHFwaorKws/v73v5OVlcULL7xQ7GuOOOIIvvjiC/r06cPw4cO5//776devH1u2bAGCa0m5ubkMHDgQgJo1a/Lcc88xZMgQ1q1bx5YtW8jKyuKEE04orPOUU05h9uzZ5OTkYGZkZGTw+OOPc8EFF3D88cdz6KGH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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "x1 = df_gap22_cas['app']\n", - "y1 = 100 * df_gap22_cas['numRdMissClean'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", - "y2 = 100 * df_gap22_cas['numRdMissDirty'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", - "y3 = 100 * df_gap22_cas['numWrMissClean'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", - "y4 = 100 * df_gap22_cas['numWrMissDirty'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(6,3)\n", - "plt.ylim([0,110])\n", - "\n", - "for i,app in enumerate(x1): \n", - " plt.bar(i*4, y1[i], width=3, color=cmap(1), label='Read/Clean' if i==0 else None)\n", - " plt.bar(i*4, y2[i], bottom = y1[i], width=3, color=cmap(2), label='Read/Dirty' if i==0 else None)\n", - " plt.bar(i*4, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3), label='Write/Clean' if i==0 else None)\n", - " plt.bar(i*4, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4), label='Write/Dirty' if i==0 else None)\n", - "\n", - "offset = (i+1)*4\n", - "x2 = df_npbC_cas['app']\n", - "y1 = 100 * df_npbC_cas['numRdMissClean'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", - "y2 = 100 * df_npbC_cas['numRdMissDirty'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", - "y3 = 100 * df_npbC_cas['numWrMissClean'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", - "y4 = 100 * df_npbC_cas['numWrMissDirty'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", - "\n", - "for i,app in enumerate(x2): \n", - " plt.bar(i*4+offset, y1[i], width=3, color=cmap(1))\n", - " plt.bar(i*4+offset, y2[i], bottom = y1[i], width=3, color=cmap(2))\n", - " plt.bar(i*4+offset, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3))\n", - " plt.bar(i*4+offset, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*4, list(x1)+list(x2))\n", - "plt.axvline(x=offset-2, color='black')\n", - "\n", - "plt.ylabel(\"DRAM Cache Miss Rate (%)\", fontsize=10)\n", - "plt.legend(fontsize=9, ncol=1)\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_mpki.pdf\")\n", - "\n", - "x1 = df_gap25_cas['app']\n", - "y1 = 100 * df_gap25_cas['numRdMissClean'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", - "y2 = 100 * df_gap25_cas['numRdMissDirty'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", - "y3 = 100 * df_gap25_cas['numWrMissClean'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", - "y4 = 100 * df_gap25_cas['numWrMissDirty'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(6,3)\n", - "plt.ylim([0,110])\n", - "for i,app in enumerate(x1): \n", - " plt.bar(i*4, y1[i], width=3, color=cmap(1), label='Read/Clean' if i==0 else None)\n", - " plt.bar(i*4, y2[i], bottom = y1[i], width=3, color=cmap(2), label='Read/Dirty' if i==0 else None)\n", - " plt.bar(i*4, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3), label='Write/Clean' if i==0 else None)\n", - " plt.bar(i*4, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4), label='Write/Dirty' if i==0 else None)\n", - "\n", - "offset = (i+1)*4\n", - "x2 = df_npbD_cas['app']\n", - "y1 = 100 * df_npbD_cas['numRdMissClean'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", - "y2 = 100 * df_npbD_cas['numRdMissDirty'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", - "y3 = 100 * df_npbD_cas['numWrMissClean'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", - "y4 = 100 * df_npbD_cas['numWrMissDirty'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", - "\n", - "for i,app in enumerate(x2): \n", - " plt.bar(i*4+offset, y1[i], width=3, color=cmap(1))\n", - " plt.bar(i*4+offset, y2[i], bottom = y1[i], width=3, color=cmap(2))\n", - " plt.bar(i*4+offset, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3))\n", - " plt.bar(i*4+offset, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*4, list(x1)+list(x2))\n", - "plt.axvline(x=offset-2, color='black')\n", - "\n", - "plt.ylabel(\"DRAM Cache Miss Rate (%)\", fontsize=10)\n", - "plt.legend(fontsize=9, ncol=1)\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAagAAADfCAYAAACj4kcNAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAfx0lEQVR4nO3de5xd873/8de7kTShiEhcIxLiOCVOSuLWjOYiWi0nQkOlCA4NLUVUqzdSPdqf0lIPNOquPalLpSTEoZpk4pISuSAiQqRRcVK5lCgShM/vj7V2bGNm9p49e83smf1+Ph7zmL2+a+3v97P27bPXWt/9/SoiMDMzqzSfau0AzMzM6uMEZWZmFckJyszMKpITlJmZVSQnKDMzq0ibtHYAzdG9e/fo3bt3a4dhVWrx4sUA7L777q0ciVnbNnfu3NUR0aNueZtOUL1792bOnDmtHYZVqSFDhgBQW1vbqnGYtXWSXq6v3Kf4zMysIjlBmZlZRXKCMjOzitSmr0HV54033mDFihWtHYZlqHPnzvTs2ZOOHTu2dihmlqF2l6BWr15N79696dKlS2uHYhmICNasWcPy5cvp06dPa4djZhlqd6f43n//fTp37tzaYVhGJLH11luzfv361g7FzDLW7hIUJB9i1n75+TWrDu3uFF++A8Y/WJZ6Hr/oS42uX7ZsGXvvvTf9+/dn3bp1jB49mnPOOafk9vr27cuSJUtKvn9dI+45rCz1TBk5tdH13/rWtzjkkEM48sgjee655+jXrx+rV6+mW7du/OY3v2HNmjVccMEFG7c/7rjjmDhxIsuWLeOZZ55hxIgRZYnTzNqHdnkE1RoGDBhAbW0ts2bNYsKECbz99tutHVKLq6mp4bHHHgPgscceY9iwYcyaNWvj8kEHHbRx2w8++ICJEycCSYKfMmVKywdsZhXNCarM3nnnHd577z02bNjAqaeeytChQ6mpqWH27NkAXH755QwbNox9992X8ePHA/Dhhx9y/PHHM3jwYMaNG9ea4TdLTU0Njz76KJAkpO9+97sbl2fPns2ECRM4/fTTOfzww3nkkUfo27cvkDwmU6dOZciQIcydO5cFCxYwfPhwhg0bxjHHHMO6detabZ/MrPU4QZXJ3LlzGTx4MDvttBNnnHEGt912G3379mXGjBlMmjRpY+I57bTTmD59OrNnz+ahhx7i73//O5MnT2azzTZj5syZjBo1ig0bNrTy3pSmV69erF69mnXr1rFixQqGDx/OggULWL58Od27d6dLly7svPPO3HfffRuHCQI499xzOeyww6itrWXAgAGcccYZ3HTTTUyfPp1BgwZx4403tt5OmVmryewalKSbgMOBlRHRLy3rBtwB9AaWAcdExOtKrnpfCXwFeAc4KSLmZRVbFgYMGMBf/vIXnn76ac4//3x23XVXZs2axQMPPADA2rVrAZg0aRI33HADkli6dCmvvPIKL7zwAvvttx8A+++/f5vuBLDffvsxZcoUtttuOzp06ECHDh2YPn06NTU1rFq1is9//vMF61i4cCFjxowBYP369QwfPjzrsM2sAmV5BHULcGidsu8D0yJiN2BaugzwZWC39G8sMCHDuDLVv39/dthhB/bcc0/GjBlDbW0ttbW1zJuX5NsLLriABx98kBkzZtCnTx8igt12223joLdPPvkkEdGau9AsNTU1XHrppRsT0T777MOVV1658fpThw4dPnGfTp06feyosV+/ftx2223U1tby+OOPc+GFF7ZM8GZWUTJLUBHxMPDPOsVHALemt28FRuaV/y4SjwNdJW2fVWxZGzduHL///e9ZvHgxQ4cOZejQofzoRz8C4KijjmLQoEEcf/zxfOYznwHgiCOOYO3atQwePJi7776bTTZpu50ra2pqmDdv3sYENWjQIObPn8+gQYMavM9ee+3FSy+9xKhRo1iwYAHXXHMNJ510EsOGDWPYsGHMnDmzpcI3swqiLL+tS+oN3Jd3iu+NiOia3hbwekR0lXQfcElEPJqumwacHxGNzqUxcODAqDvdxqJFi/jsZz9b9n2xylIJz7On2zArD0lzI2Jg3fJW6yQRSWZscnaUNFbSHElzVq1alUFkZmZWCVo6Qb2WO3WX/l+Zlr8K7JS3Xc+07BMi4rqIGBgRA3v0+MQEjGZm1k60dIKaApyY3j4RmJxXPkaJA4C1EVHykORtuZOBFebn16w6ZNnN/DZgCNBd0nJgPHAJcKekU4CXgWPSze8n6WK+hKSb+cmlttuxY0fWr1/v0czbqdxo5h4Q2Kz9yyxBRcToBlYdXM+2AZxRjna7d+/OsmXLylGVVajcfFBm1r613f7MDejatStdu3Zt7TDMzKyZPNSRmZlVJCcoMzOrSE5QZmZWkQpeg5LUmWTQ14OAHYB1wLPA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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "x1 = df_gap22_cas['app']\n", - "y1 = 100 * df_gap22_cas['numRdHit'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", - "y2 = 100 * df_gap22_cas['numWrHit'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(6,3)\n", - "plt.ylim([0,110])\n", - "\n", - "for i,app in enumerate(x1): \n", - " plt.bar(i*4, y1[i], width=3, color=cmap(1), label='Read' if i==0 else None)\n", - " plt.bar(i*4, y2[i], bottom = y1[i], width=3, color=cmap(2), label='Write' if i==0 else None)\n", - "\n", - "offset = (i+1)*4\n", - "x2 = df_npbC_cas['app']\n", - "y1 = 100 * df_npbC_cas['numRdHit'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", - "y2 = 100 * df_npbC_cas['numWrHit'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", - "\n", - "for i,app in enumerate(x2): \n", - " plt.bar(i*4+offset, y1[i], width=3, color=cmap(1))\n", - " plt.bar(i*4+offset, y2[i], bottom = y1[i], width=3, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*4, list(x1)+list(x2))\n", - "plt.axvline(x=offset-2, color='black')\n", - "\n", - "plt.ylabel(\"DRAM Cache Hit Rate (%)\", fontsize=10)\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_mpki.pdf\")\n", - "\n", - "x1 = df_gap25_cas['app']\n", - "y1 = 100 * df_gap25_cas['numRdHit'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", - "y2 = 100 * df_gap25_cas['numWrHit'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(6,3)\n", - "plt.ylim([0,110])\n", - "\n", - "for i,app in enumerate(x1): \n", - " plt.bar(i*4, y1[i], width=3, color=cmap(1), label='Read' if i==0 else None)\n", - " plt.bar(i*4, y2[i], bottom = y1[i], width=3, color=cmap(2), label='Write' if i==0 else None)\n", - "\n", - "offset = (i+1)*4\n", - "x2 = df_npbD_cas['app']\n", - "y1 = 100 * df_npbD_cas['numRdHit'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", - "y2 = 100 * df_npbD_cas['numWrHit'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", - "\n", - "for i,app in enumerate(x2): \n", - " plt.bar(i*4+offset, y1[i], width=3, color=cmap(1))\n", - " plt.bar(i*4+offset, y2[i], bottom = y1[i], width=3, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*4, list(x1)+list(x2))\n", - "plt.axvline(x=offset-2, color='black')\n", - "\n", - "plt.ylabel(\"DRAM Cache Hit Rate (%)\", fontsize=10)\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_mpki.pdf\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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yPT+COA3kXgK6JIuC1HR7r77bg499FB69+4NJAuSHnxwUuNzwgknUF1dzR577MGddyYv2S233MLee+/NoEGDGDduHAAPPfQQ++23H9XV1Zx11lkAnHvuuQwaNIg99tiDCRMmALBy5UqGDRvGkCFDuOSSS2pjWLhwIcOGDWPw4MEMGzaMpUuXZor94IMPprq6mr333psnn3xyvX1vv/02I0eO5N5772XWrFkMGTKEwYMHM2rUKFatWtWMV6xydenShe985zvcdNNN65WvW7eO5cuXExEAPPfcc+yyyy6cfvrpTJ48eb1jhw4dyt13382SJUvo0KEDXbp0KVf4ZmZWIEsT1YXA3sDDABExQ1KvxpxEUk+gP/A3oFvB0g//ImnCgiT5WVjwsNfTssJlIirOwoUL6dGjR9F9V199NZ06deLNN9/kgAMOYPjw4dx0001MnjyZT3/606xbt46I4PTTT+eRRx6hW7durF27FoDzzz+fTp06sXr1anbbbTfGjBnDxIkTGThwIOPGjePGG29kzpw5AJxzzjl873vfY5999mHKlClcdtllXHHFFSVjv+222+jUqRNz585l7Nix/OUvyXqqixcv5ogjjuDiiy9mr7324nOf+xyTJ09mu+224+c//znXXXcdZ5xxRgu9gpWlR48eLFq0CEhGPFVXV/Pqq6/Sv3//2sT1xhtv5IQTTmDAgAGcffbZrFmzhg4dOgBw9NFHc+aZZ7Jo0SJGjRpVm5yamVl5ZUlw1kTEijqjkiLrCSR9HPgjcGZEvF34PBERkjI/V/p8pwCnAGy3XesvidWjRw9mz579kfJ169Zx0UUX8cQTT7DxxhuzYEGyVMb48eO54ooreOeddxg1ahT77rsvXbt2rR02XNPH45prruGOO+6gqqqKJUuWsGTJEl566SWOOOIIAD772c8yceJEAGbNmsV5550HwAcffECfPn1Kxr1q1Sq+8Y1vMG/ePKqqqmr/qAP84he/YOzYsey1114AvPDCCxx//PEAvPfeewwZMqRJr1VbsHDhQrbZZhuA2iaqFStWMHToUJYvX84WW2zBlClTat/zJUuWcM8999T27+nevTsrV67klltu4YEHHnCCY2bWSrIkOC9IOhaoktQX+DrwRJYnl9SBJLm5MZ0NGeANSd0jYnHaBLUkLV9E0oG5xrZp2XoiYgIwAWDAgAGNSo7y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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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J2lToEdEXNCExx5MkhzNkjQjLfs/ksTmVkknAPOAMem6e4ADgZeBd4BxTThWm1m+fDnHHHMMt99+O3369CEiuP/++9s6LKtniy22qEsGa2trmTJlCttvv/16fy9btoyDDz6YHXfckaFDh1JTU1O3z/HHH8/999/PiBEjALjrrrsYNmwYjz32GEOGDAGS6qe///3vrFq1is6dO/Pb3/6WT37yk23xdM3MNnhlq5okHQTMAO5NlwdIurPcfhHx54hQRHw8Igakt3si4s2I2C8i+kXE8Ij4V7p9RMT4iOgTEf0jol0MUXz33Xdz0EEH0adPHyCZkPSAA5IrPscddxy1tbXsscce3Hln8pLdcsst7LXXXgwdOpQJEyYA8NBDDzF48GBqa2s544wzADj77LMZOnQoe+yxBxMnTgRgxYoVjBw5kuHDh3PRRRfVxTB//nxGjhzJsGHDGDlyJA21TarvgAMOoLa2lr322osnnnhivXVvvfUWBx98MPfeey+zZs1i+PDhDBs2jDFjxrBy5coWvGLVq2vXrnzzm9/kpptuWq983bp1LFu2jKTJGDz77LPstttunHrqqUyZMmW9bUeMGMHdd9/N4sWL6dSpE127dq1U+GZmViRLFdX5wF4k3bmJiBmSeucYU7syf/58evbsWXLdT3/6U7p06cKbb77Jvvvuy6hRo7jpppuYMmUKH/vYx1i3bh0RwamnnsojjzzCtttuy9q1awE499xz6dKlC6tWraJ///6MGzeOSZMmMWTIECZMmMCNN97InDlzADjrrLP49re/zd57783UqVO59NJLufzyy8vGftttt9GlSxfmzp3L+PHj+eMfk/lUFy1axGGHHcaFF17InnvuyWc/+1mmTJnCDjvswI9//GOuu+46TjvttFZ6BatLz549Wbgwafq1du1aamtrefXVVxk4cGBd4nrjjTdy3HHHMWjQIM4880zWrFlDp06dADjyyCM5/fTTWbhwIWPGjKlLTs3MrLKyJDhrImJ5vV5JTer51JH17NmT2bNnf6B83bp1XHDBBTz++ONsvPHGzJuXTJVx8cUXc/nll/P2228zZswY9tlnH7baaqu6bsOFNh7XXHMNd9xxBzU1NSxevJjFixfz0ksvcdhhhwHwqU99ikmTJgEwa9YszjnnHADee+89+vbtWzbulStX8tWvfpUXX3yRmpqauh91gCuvvJLx48ez5557AvD8889z7LHHAvDuu+8yfPjwZr1W7cH8+fPZbrvtAOqqqJYvX86IESNYtmwZW265JVOnTq17zxcvXsw999xT176nR48erFixgltuuYUHHnjACY6ZWRvJkuA8L+looEZSP+ArwOP5htV+jBw5kosvvpgTTjihrppq2rRpbL311sycOZM///nPLF26tG5d7969mThxIqtWraJfv37MmzePf/3rXyxZsoTu3buzbt06li9fzg033MDMmTNZs2YNO++8MxFBv379mD59Ovvttx9PPfVUXQy77bYbEyZMYODAgQCsXr26bNz33nsvNTU1PProo8yZM4dRo0bVrfvud7/Lfffdx+TJkxk7diy77747N998Mz169Mj8+O3R8uXLufjii/nWt761XvkWW2zBKaecwqWXXsoBBxzA6NGj666QvfLKK0yYMKEuwQEYP348c+bMYdNNN61o/GZm9r4sCc6XgW8Cq4CbgPuA7+UZVGsp1/upNWyxxRZMmTKF8ePH8+6777J69WoOP/xwTj75ZNasWcO+++7LgAED6tpinHXWWcyaNYs1a9Zw8sknI4mrr76aUaNG0blzZwYOHMgPfvADdt11V4YMGcIuu+zCVlttBcCJJ57ImDFjmDZtGrvvvntdDFdccQXjx49nxYoVQNIgtn4vqH/84x/rXXmZMmUKF198McOHD2fw4MHrbbvxxhszZcoUxo0bx5o1a7j66qsZO3Zs3ejQEyZMYP/992+117CtR/08/PDDqampYd26dRx//PEMGzbsA9sceeSR9O/fn6VLl3L00UfXlffp04e5c+fy1lvvD/F04IEHcuCBB1YkdjMzK02FhpMlV0o1wAMRMbRyIWU3aNCgmD59/bbIc+fOZZdddmmjiMzKa++f0draWoDMQxSYtXeeqqG6SXo6IgbVL2+0F1VErAXWSdoit8jMzMzMWlmWKqoVJGPZTAPeLhRGxFdyi8rMzMysBbIkOLelt3YjIjwXlVWlxqqEzcys9WQZyfgXlQiktWyyySa8+eabbLXVVk5yrOq8++67dWPmmJlZfhpMcCT9HpgI3BsRa+qt2wkYC7weEdfnGmETbb/99ixYsCDzaL5mlVbobm9mZvlp7ArOicCZwI8k/QtYAmwC9CaZL+qqiJjayP5tolOnTvTu7YGWzczMNmQNJjgR8U/gG8A3JPUCegArgZci4p3KhGdmZmbWdFkaGRMRrwOv5xqJmZmZWSspO5u4mZmZWXvjBMfMzMw6nLIJjqSDJDkRMjMzs3YjS+JyBPA3Sd+X9F9ZH1jS9ZIWS5pdVHa+pIWSZqS3A4vWTZD0sqQXJeU/S6aZmZl1WGUTnIg4BhgIvAJMlvSEpJMkbV5m18nA50uU/zAiBqS3ewAk7QocCeyW7vPTdKJPMzMzsybL2ovqLUm/BTYFTgcOAc6SdGVE/KSBff6Udi/PYjRwS0SsAl6T9DKwF/BExv3NzMwy2/u8+zJvu83AHAOx3GRpgzNK0u3Aw0AnYK+IGAF8AvhaM455mqSZaRXWlmnZdsD8om0WpGVmZmZmTZalDc4XSaqV+kfEZRGxGCAd7O+EJh7vGqAPMABYBFzRxP1Jq8emS5ru6RjMzMyslCwJzvnAXwsLkjYtVD1FxINNOVhEvBERayNiHTCJpBoKYCHQs2jT7dOyUo8xMSIGRcSg7t27N+XwZmZmtoHI0gbnN8Cni5bXpmV7NvVgknpExKJ08RCg0MPqTuAmST8APgr0oyipMrPGNaU9wZMXuJOimXV8WRKcjSNidWEhIlZL+lC5nSTdDNQCW0taAJwH1EoaAATJ1A8np4/5vKRbgTnAe8D4iFjbtKdiG4qm/JiDf9DNzDZEWRKcJZJGRcSdAJJGA0vL7RQRR5Uovq6R7S8ELswQj5mZmVmjsiQ4pwA3SroKEElvp2NzjcrMzMysBcomOBHxCrC3pM3S5RW5R2VmZmbWAmUTHEmdSbqK9wI2lgRARHwn18jMzMzMmilLFdVUYDnwNLAq33DMzMzMWi5LgrN9RJSaU8rMzMysKmUZ6O9xSf1zj8TMzMyslWS5gjMEGCvpNZIqKgERER/PNTKzVjLqjpGZt73z4LtzjMTMzColS4IzIvcozMzMzFpRlm7i8yQNAfpFxA2SugOb5R+amVn75lG3rRx/RvKTpZv4ecAgYGfgBqATMAUYnG9oZtbeeE4sK8efEauULI2MDwFGAW8DRMQ/gM3zDMrMzMysJbK0wVkdESEpACR1yTkmMzMzq6COWFWW5QrOrZJ+DnSVdCLwAHBtvmGZmZmZNV+WRsaXS9ofeIukHc65ETEt98jMzJqpI/43amZNk6WR8aURcTYwrUSZmZmZWdXJ0gZnf6B+MjOiRFmH49b+ZmZm7VODbXAknSppFrCzpJlFt9eAmeUeWNL1khZLml1U1k3SNEl/S++3TMsl6UpJL6fH2KM1npyZmZltmBprZHwTcBBwZ3pfuH0yIo7J8NiTgfqTdJ4DPBgR/YAH02VIrgj1S28nAddkjN/MzMzsAxqsooqI5cBy4CgASdsAmwCbSdosIv7e2ANHxJ8k9apXPBqoTf/+BfAwSVXXaOCXERHAk5K6SuoREYua/IzMKsQNWc3MqlfZbuKSDpL0N+A14BHgdeAPzTzetkVJyz+BbdO/twPmF223IC0rFc9JkqZLmr5kyZJmhmFmZmYdWZZxcL4H7A28FBG9gf2AJ1t64PRqTTRjv4kRMSgiBnXv3r2lYZiZmVkHlKUX1ZqIeFPSRpI2ioiHJP2omcd7o1D1JKkHsDgtXwj0LNpu+7TMzCx3o+4YmXnbOw++O8dIzKy1ZElwlknaDPgTcKOkxaTzUjXDncBxwCXp/dSi8tMk3QJ8Clju9jfvc3d1MzOzpslSRTUaeAc4A7gXeAX4QrmdJN0MPEHSzXyBpBNIEpv90zY9w9NlgHuAV4GXgUnA/zbxeZiZmZnVyTJVQ+FqzTqSnk9IegwYXGa/oxpYtV+JbQMYXy4WMzMzsyyyXMEpZYdWjcLMzMysFTU3wWly7yczMzOzSmmwikrSoQ2tAjbNJxwzMzOzlmusDc5Bjay7q7UDsern3lxmZtZeNDZVw7hKBmJmleExX8xsQ9DcNjhmZmZmVcsJjpmZmXU4ZcfBkaR0nJriss4RsSq/sMw6HlcNmZlVTpapGq4Dji8spNM2TKXEgH1mZlad3EnANjRZqqgWSPopgKQtgfuBKblGZWZmZtYCZROciDgXWCHpZyTJzRURcUPukZmZmZk1U9aB/v4CfBv4KxCSDo2I2/IOzszMzKw5mjLQ37NAp7Q8ACc4VagpDVnBjVnNzKxj8kB/ZtYmnIybNZ17Y2ZXtg2OpF9I6lq0vKWk63ONyszMzKwFsnQT/3hELCssRMS/JQ1syUElvQ78B1gLvBcRgyR1A34N9AJeB8ZExL9bchwzMzPbMGVJcDaStGUh2UgTkSz7lTM0IpYWLZ8DPBgRl0g6J10+uxWOY2ZmTeBqEOsIsiQqVwBPSPpNunw4cGEOsYwGatO/fwE8jBMcMzMza4ayCU5E/FLSdGBYWnRoRMxp4XEDuF9SAD+PiInAthGxKF3/T2DbFh7DzMzaMTdEt5bIWtXUDXg7Im6Q1F1S74h4rQXHHRIRCyVtA0yT9ELxyoiINPn5AEknAScB7LDDDi0IwczMzDqqLJNtngcMAnYGbiAZC2cKMLi5B42Ihen9Ykm3A3sBb0jqERGLJPUAFjew70RgIsCgQYNKJkFmZu2R276YtZ4sV3AOAQYCzwBExD8kbd7cA0rqAmwUEf9J//4c8B3gTuA44JL0fmpzj2Ftz5eWzcysLWVJcFYXVxmlSUlLbAvcLqlw/Jsi4l5JTwG3SjoBmAeMaeFxzMzMbAOVJcG5VdLPga6STgSOByY194AR8SrwiRLlbwL7Nfdx25ovLZuZmVWPLL2oLpe0P/AWSTuccyNiWu6RmZmZmTVTpl5UaULjpMbMzMzahSy9qA4FLgW2AZTeIiI+knNsZmZmVoXaQ7OMLFdwvg8cFBFz8w7GzMzMrDWUnU0ceMPJjZmZmbUnDV7BSaumAKZL+jVwB7CqsD4ibss3NDMzM7PmaayK6qCiv98hGZCvIAAnOGZmZlaVGkxwImJcJQMxMzMzay0NtsGRdJmkk0uUnyzpknzDMjMzM2u+xhoZDyOd1LKeScAX8gnHzMzMrOUaS3A6R8QHZuuOiHUkY+GYmZmZVaXGEpyVkvrVL0zLVuYXkpmZmVnLNNaL6lzgD5K+Bzydlg0CJgCn5xyXmZmZWbM11ovqD5IOBs4CvpwWzwa+GBGzKhCbmZmZWbM0OlVDRMwGjqtQLGZmZmatIstUDWZmZmbtStUlOJI+L+lFSS9LOqet4zEzM7P2p6oSHEk1wNXACGBX4ChJu7ZtVGZmZtbeqMRQN+tvIF1Zong5MD0iprZqMNI+wPkRcUC6PAEgIi4utX3v3r3jvPPOa80Q1vPM6//KvO2HNluYedvdt+5fFXE0NZb2GEdTY2mPcTQ1lpbGMWPGDAAGDBhQsTgaiqUh1fLeVEscTY2lPcbR1FjaYxxNjaU9xtEc48aNezoiBtUvz3IFZxNgAPC39PZxYHvgBEk/asUYAbYD5hctL0jLzMzMzDJrtBdV6uPA4IhYCyDpGuBRYAhQ8e7ikk4CTkoXV4wbN+7FSsfQgK2BpW0dBI6jlGqJxXGsr1rigOqJxXGsz3F8ULXEUi1xAOxYqjBLgrMlsBlJtRRAF6BbRKyVtKqVgitYCPQsWt4+LasTERMpPUdWm5I0vdQlMsfR9qolFsdRnXFA9cTiOBxHOdUSS7XE0ZgsCc73gRmSHiaZg+qzwEWSugAPtHI8TwH9JPUmSWyOBI5u5WOYmZlZB1c2wYmI6yTdA+yVFv1fRPwj/fus1gwmIt6TdBpwH1ADXB8Rz7fmMczMzKzjy3IFB+BdYBFJg+O+kvpGxJ/yCCgi7gHuyeOxc1Yt1WaO44OqJRbHsb5qiQOqJxbHsT7H8UHVEku1xNGgLN3EvwR8laQ9zAxgb+CJiBiWe3RmZmZmzZClm/hXgT2BeRExFBgILMszKDMzM7OWyJLgvBsR7wJI6hwRLwA75xtWdZPUS9LsaoxB0mckPS9phqRN2yI2qy6Sukr63yqIo6HP7OmSPtwWMVUDSV+RNFfS2205crukx9vq2MUkrWjrGKxjaDDBkXRR+ucCSV2BO4BpkqYC8/IPzZrpv4GLI2JARKxs62CqUTolyIakK9DmCU4jTgc22ASH5L3ZH/gNyRQ1bSIiPt1WxzbLQ2NXcD4PEBGHRMSyiDgf+DZwHXBw/qFVvY0l3Zj+5/VbSR+WtKekxyU9J+mvkjavcAxfAcYA303Le0j6U3o1Z7akz+QViKRjJc1Mn/uvJG0r6fZ0+TlJFTl5plcJXijx3rwu6VJJzwCHt+Lxuki6O32OsyUdIekSSXPS1+PydLvD0/XPSfpTWjZW0lRJD0v6m6S85h25BOiTfg4uk3S2pFlpLJfkdMyGlPrMfhR4SNJDlQigxGe1j6Qn09fke5W8giDpZ8BOwGvAccBl6fvUp1IxFMWyIr2v2HmjTDy1ku4qWr5K0tgcj1c4d0yW9FL6OR0u6bH0+7mXpO6SpqVXya+VNE/S1jnFU+rc8rqk76ef1b9K6pvHsevFsd6VV0lfl3S+pBMlPZXG9ztV41XYiCh5A54jGeSvW6lbQ/ttCDegFxAkIzwDXA98A3gV2DMt+wiwcYVj+DowGTgsLfsa8M307xpg85xi2Q14Cdg6Xe4G/Bo4vejYW7The/N14HXgGzkc74vApKLlHYEXeb8Bf9f0fhawXb2ysSS9E7cCNgVmA4Nyek1mp3+PAB4HPlx4ryrxvmR4b7auUAylPqt3AUely6cAKyr1mqTHfJ1kVNi6725b3ArPu1LnjQxx1AJ3FZVfBYzN8bi9gPeA/iT//D+dfkYFjCapxbgKmJBu//n085zLZ7fEuWWL9LNSeG+OLX59cn5dZhctfx04H9iqqOx7wJcr+TnJcmvsCs5/pW9w8W160f2Gbn5EPJb+PQU4AFgUEU8BRMRbEfFehWMYUm/9U8A4SecD/SPiPznFMQz4TUQsBYiIf6Vl16TLayNieSP7t7aGXpdf53CsWcD+6dWhz5AMUPkucJ2kQ4F30u0eAyZLOpHkR6NgWkS8GUl14m188D1sbcOBGyLiHah7ryqp3Gc2b6U+q/uQVA8B3FTheKpRpc4b1ei1iJgVEeuA54EHI/kFn0XyQz8EuAUgIu4F/p1jLOudW4rOoTcX3e+T4/HL2V3So5JmkTSN2K0NYympsQRnTkTsFBG9i26F5Z0qFmH1qt+//q0qiGG95UjGKvosyY/uZEnHViqwNtbQ6/J2qx8o4iVgD5KT0feA/yMZFPO3wBeAe9PtTgG+RTIVydOStioTa0e1oT3fdqeKzhvvsf5v1CYVOGbx9EPripbXkX3cuFZR/9wi6dzCquLNKhBKQ+/DZOC0iOgPXEBl3p8mydKLykrbQVIhez4aeBLoIWlPAEmbS8r7C1E/hj8Xr5S0I/BGREwCriX5suThj8DhhR9tSd2AB4FT0+UaSVvkdOxSGn1dWpOkjwLvRMQU4DKSH4YtIhmw8gzgE+l2fSLiLxFxLrCE9+dc219SNyU93g4mudLT2v4DFNqDTSP57/zDaVzdcjheY0q9N8Xx5a3UZ/VJkuoASKaHaSuVfB0aVMHzRjnzgF0ldVbS0WW/Noqj2GMk7RyR9DmSZhy5KHFuKbwPRxTdP5HX8Yu8AWwjaStJnUn+cYPks7pIUieSKzhVp7EE58cVi6J9ehEYL2kuyYf8JyQfuJ9Ieo7khyTvjLZ+DNfUW18LPCfp2TS2XN7TSKbTuBB4JH3uPyAZP2loevnyaSrbO6Tc69Ka+gN/lTQDOI/kP5m7JM0k+fE+M93usrRh4GySNjDPpeV/BX4HzAR+FxGtXv0bEW8Cj6XH3g+4E5iexvz11j5eGaXem4nAvZVoZNzAZ/V04Mz0PevL+xMLV9otwFmSnm2LRsZFaqnAeaOciJgP3ErSNu1W4Nm2iKOeC4DPpd+lw4F/kiSmeah/bvleWr5l+ln9Ksk/UbmKiDXAd0jOVdOAF9JV3wb+QpL0vVB677ZVdiRjs/ZEUi+Shne7t3Us5aQ9QgZFxGltHcuGLL2atTIiQtKRJA2OR7d1XFZ90isYayOZN3Ef4JqIGFDB479Ocs5YWqljtmcVrVM0M6tCnwSukiSSUdqPb9twrIrtANwqaSNgNXBiG8djjfAVHDMzM+twyl7BkXRlieLlwPSImNr6IZmZmZm1TJZeVJsAA4C/pbePk8wsfoKkH+UWmZmZmVkzla2ikvQkycija9PljYFHSQY8mhURbTZ3ipmZmVkpWa7gbAlsVrTchWR497WsPyiSWa6UzG91k6RXJT0t6QlJhxSt/5GkhWkDwELZWElLlMyrMycdSbh++fNK56xK1+0t6S/purnpiK6l4rlR0otK5om5Ph0PojCHzvJ0/xlFA3SZWQtJCklXFC1/vfAdVTJH0kK9P4/WqBLlL0i6pvg8Ue/x1xadF56T9LWGtrXqluVN+z4wQ9INkiaTjEVwmaQuwAN5BmdWkPZwuQP4Uzqi9idJBmXbPl2/EXAIMB/Yt97uv067ctYCF0natrg8InYj6RFRGEDrF8BJ6T67k4zBUcqNJFOa9CeZS+pLReseTR97QER8p1lP2sxKWQUcqoYnufxh+t09HLi+KDkplO9K8p2tf54oWFl0XtifZP62vCbCtRyVTXAi4jrg0yQ/LrcDQyLi2oh4OyLOyjk+s4JhwOqI+FmhICLmRcRP0sVakrljrgGOKvUAEbEYeIVkQsw6abVrF96fV2YbkkkwC/NozWng8e6JFMkgWNs376mZWRO8RzI4ZKOD3EXE3HTb+onQh0jalpadRyo9Z5wEnJb+k2XtSNkER9LvSX48HoiIqRHxj9yjMvug3YBnGll/FMnkc7cDIwvVRcUk7QTsBLycFh2RjhK6kGRW6d+n5T8EXpR0u6STJTU6InV6rP8hnXcqtU96efsPkqpuEjqzdu5q4L/VyBQwkj5FMofUkrTojPT7vgh4KSJmZDlQRLxKMkHuNi0J2CovSxXV5cBngDlpO4XDyp3wzfIm6eo0gXhK0oeAA4E7IuItkuHDDyjavJDI3AycXDSDdqHq6v+RTGh3FkBapTQIuJ9kvqTixKWUn5JUnT2aLj8D7BgRnyCZwuOOljxXM1tf+j3/JfCVEqsLiczlwBHxfk+aQhXVNkCXdNRq68CyVFE9EhH/S/Kf789JJhpbnHdgZvU8T9GkfxExnmRepe4kyUxXYFY6lPkQ1q+mKrS1+VRE3F7/gdMT4O9JJsoslL0SEdekx/iEkonm7ksbH15b2E7SeWkMZxbt+1ZErEj/vgfo1Eh7ATNrnh8BJ5BULxf7Yfp9/0zRPx110rmV7gU+K6lnUWeAU0odJL3yuxb/7rU7mVqGK5np+IvAKcCeJI0wzSrpj8Amkk4tKvtwen8U8KWI6BURvYDeJLN0f5jshpC0z0HSyKL69n4kJ7dlEXFAeuL8Urrdl0iSq6MiYl3hgST9v8L+kvYi+Z692bSna2aNSa/E3kqS5GSWfjcHA69ExPyizgA/K7Ftd+BnwFVFV4KsncgykvGtwF4kGe9VwCPFJ3OzSkgnQjwY+KGkb5DUq79N0rvhhyTJd2HbtyX9GTiozMMeIWkISQKyABiblv9Pepx3SBop/ndhHKh6fgbMA55I85nb0uqtw4BTJb0HrASO9MnRLBdXAFknqz1D0jFAJ2AmSdVyKZumVVydSL7/vyKZdd7amSwD/R1A0sC4MNDfEJL/WMdXID4zMzOzJit7BSci7pM0UNJRJO1vXgNuyz0yMzMzs2ZqMMGR9DGStg1HAUuBX5Nc8RlaodjMzMzMmqXBKipJ60jmnDohIl5Oy16NiJ0qGJ+ZmZlZkzXWi+pQkgGRHpI0SdJ+gEdyNDMzs6qXpZFxF2A0SVXVMJLBlW6PiPvzD8/MzMys6comOOttLG1JMoHZERGxX25RmZmZmbVAkxIcMzMzs/Yg00jGZmZmZu2JExwzMzPrcJzgmJmZWYfjBMfMzMw6HCc4ZmZm1uH8f3ePxT9+WZ5xAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_cas['app']\n", - "gap_22_cas = df_gap22_cas['avgTimeTagCheckResRd'].astype(float)\n", - "gap_22_ram = df_gap22_ram['avgTimeTagCheckResRd'].astype(float)\n", - "\n", - "\n", - "gap_25_cas = df_gap25_cas['avgTimeTagCheckResRd'].astype(float)\n", - "gap_25_ram = df_gap25_ram['avgTimeTagCheckResRd'].astype(float)\n", - "\n", - "\n", - "app_npb = df_npbC_cas['app']\n", - "npb_C_cas = df_npbC_cas['avgTimeTagCheckResRd'].astype(float)\n", - "npb_C_ram = df_npbC_ram['avgTimeTagCheckResRd'].astype(float)\n", - "\n", - "npb_D_cas = df_npbD_cas['avgTimeTagCheckResRd'].astype(float)\n", - "npb_D_ram = df_npbD_ram['avgTimeTagCheckResRd'].astype(float)\n", - "\n", - "\n", - "# Multi bar Chart1\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - " plt.bar(i*3+1, gap_22_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", - "\n", - "offset = i*3+2\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_C_cas[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*3+2, npb_C_ram[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Avg Tag Check Latency (reads) (ns)\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()\n", - "\n", - "# Multi bar Chart2\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - " plt.bar(i*3+1, gap_25_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", - "\n", - "offset = i*3+2\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_D_cas[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*3+2, npb_D_ram[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Avg Tag Check Latency (reads) (ns)\")\n", - "plt.legend(fontsize=9, ncol=2)\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAAClCAYAAABREodCAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAe0klEQVR4nO3deZgU1b3/8fcHRFCjEAUjigoaNaKICxhR1HEFlajEq8afjwvXXLKoiRtJ5CYajYoGl+TGLYpGE427JoG4BhkxRkVQEZTgzwWvCy64ICgiwvf+UdXYDD09NUt1zwyf1/P0M12nu6s+00v16VOnzlFEYGZmZtaedKh2ADMzM7OW5gqOmZmZtTuu4JiZmVm74wqOmZmZtTuu4JiZmVm74wqOmZmZtTuu4JiZmVm74wqOmZmZtTurNXQHSQOA3YENgUXATOChiPgw52xmZmZmTVJvC46kEZKeBs4E1gBmA+8Cg4F/SLpR0iaViWlmZmaWXbkWnDWB3SJiUakbJW0PbAH8bw65zMzMzJpMnovKzMzM2psGOxlL2kzSeEnzJL0r6a+SNqtEODMzM7OmyHIW1Z+B24ENSDoa3wHckmcoMzMzs+Zo8BCVpOciYrs6ZdMjon+uyczMzMyaKEsF5yLgQ+BWIIAjga8CYwEi4oOcM5qZmZk1SpYKzqtlbo6IcH8cMzMza1V8FpWZmZm1O1lGMu4IHAT0Lr5/RFyaXywzMzOzpmuwggOMBz4DZgDL8o1jZmZm1nxZKji96p5FlZfu3btH7969K7EpMytj9uzZAGy11VZVTmJmVt60adPmRUSPuuVZKjj3Sdo/Ih7MIdcKevfuzdSpU/PejJk1oKamBoDa2tqq5jAza4ik10qVZ6ngPAHcI6kDsAQQydlT67RgPjMzM7MWk6WCcykwCJgRPuXKzMzM2oAsFZzXgZnVqNx89NFHzJ07t9KbtXauS5cu9OrVi06dOlU7ipmZ5SRLBecVoFbSfcDiQmElThOfN28evXv3Zo011sh7U7aKiAjef/993njjDfr06VPtOGZmlpMsFZxX08vq6aVilixZQpcuXSq5SWvnJLHeeuvx3nvvVTuKmZnlqMHZxCPinFKXSoSD5AspbxMnTqSmpoY99tiD4cOH8/777+eynTlz5nD88cc3eL8bbriBcePGNXi/wYMHt0Cq6pg/fz41NTXU1NTQtWtXampqGDFiBP3792efffbhgAMOYNq0aUDyfGy11VbstddeHHrooXz++efL17PFFltw6623Ll+uqanh5JNPXr48bNiwlZ7zSrynzMysuhqs4EjqIWmspHslPVy4VCJcJbz33nuce+65jB8/nsmTJ3PRRRet8AVq+ejatSu1tbXU1tbSr18/amtr2XTTTbnkkkuYOHEi1157LSeeeCKffvopAKNGjWLSpEkMGDCABx9MRiyYPn06gwcPZvz48Sus+/XXXyciWLBgAfPnz6/4/2ZmZtWX5RDVzcBtwDDg+8BxQMXb93c5+4FmPf6Jc4aULL/33ns55phjWHvttQHYcsstAfjDH/7AjTfeyMKFC7ngggvYf//9GT16NJMnT6ZTp07cfPPNdOjQgREjRrBo0SIGDRrEmDFjOOKII3jnnXfo3Lkzd955J+ussw5nnXUWkyZNom/fvsu3O2HCBH7961/zxRdfcNZZZzF06NCy+UutF5I+JT/+8Y/Zdddd2WeffTjhhBNYsGABW2+9NVdeeWWznjOAg/9yULMe/7dD/96kx/Xq1YshQ4bw1FNPrVD+0UcfLb9+991388Mf/pALLriAxYsX07lzZwAGDhzIlClTePXVVznwwAOXD1pnZmarjgZbcID1IuI6YElEPBIR/wnsnXOuipk7dy49e/ZcqfzII4+ktraWiRMncvHFFwPw2GOPMXnyZCZNmkTPnj0ZM2YMp556KrW1tZx//vlAcjjlkUce4YgjjuC2225j7ty5TJkyhUcffZQ999wTgGXLlnHxxRfz8MMPU1tby9ixYxvMWXe9BaeccgqDBg3iO9/5DhdeeCFnnnkmkyZNYu211+bxxx9viaeoajbccEPefvttAMaOHUu/fv2YMmUKQ4YkldVnnnmGgQMHMnToUP7xj38sf9zw4cO55557uPfeeznooOZV0MzMrG3K0oKzJP07V9JBwFvAug09SFIXYDLQOd3OnRFxdlOD5qVnz5689dZbK5U/8MAD/Pa3vyUiePfddwH4yU9+wnHHHcd6663H+eefz4svvri8YtOhQweWLl3KqFGjmDFjBh9//DHDhw/ntddeY7vtkpkudtppJx588EHmzZvHrFmz2HfffQF49913iYh6+4aUWi/Aiy++SJcuXfjNb34DwKxZs/jZz36GJBYuXMjOO+/cos9Vpb355ptsvfXW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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAAClCAYAAABREodCAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAetElEQVR4nO3de7xc873/8dc7RIJGUhJtCEkoKkS0klQINkGCFKm6/XpccrSpFq1bnMpRShEEaU/dSigtdb+0SV0b2aKKSBChKT+XOC5xiUskRETyOX+sNTGJ2bPXvqyZvXfez8djHnvWd2bWeu+5rPnOd33X96uIwMzMzKwtaVftAGZmZmbNzRUcMzMza3NcwTEzM7M2xxUcMzMza3NcwTEzM7M2xxUcMzMza3NcwTEzM7M2xxUcMzMza3NWr+8OkvoDOwEbAIuAZ4EHIuKDnLOZmZmZNUqdLTiSRkp6EjgVWBN4HngHGAz8XdJ1kjauTEwzMzOz7Mq14KwF7BgRi0rdKGlbYDPgf3PIZWZmZtZo8lxUZmZm1tbU28lY0iaSJkqaJ+kdSX+RtEklwpmZmZk1RpazqP4M3AJ8naSj8a3AjXmGMjMzM2uKeg9RSXomIrZZqWxmRPTLNZmZmZlZI2Wp4JwPfADcBARwMPBVYBxARLyfc0YzMzOzBslSwXmlzM0REe6PY2ZmZi2Kz6IyMzOzNifLSMarAfsAvYrvHxEX5xfLzMzMrPHqreAAE4FPgVnAsnzjmJmZmTVdlgpOj5XPospL165do1evXpXYlJmV8fzzzwOwxRZbVDmJmVl5M2bMmBcR3VYuz1LBuUfSnhFxfw65VtCrVy+mT5+e92bMrB41NTUA1NbWVjWHmVl9JL1aqjxLBecx4E5J7YAlgEjOnlqnGfOZmZmZNZssFZyLgUHArPApV2ZmZtYKZKngvAY8W43KzYcffsjcuXMrvVlr4zp27EiPHj1o3759taOYmVlOslRwXgZqJd0DLC4UVuI08Xnz5tGrVy/WXHPNvDdlq4iI4L333uP111+nd+/e1Y5jZmY5yVLBeSW9rJFeKmbJkiV07Nixkpu0Nk4S6623Hu+++261o5iZWY7qnU08Is4sdalEOEi+kPI2efJkampq2HnnnRkxYgTvvfdeLtuZM2cORx55ZL33u/baa5kwYUK99xs8eHAzpKqO+fPnU1NTQ01NDZ07d6ampoaRI0fSr18/hgwZwl577cWMGTOA5PnYYost2HXXXdl///357LPPlq9ns80246abblq+XFNTw3HHHbd8efjw4V96zivxnjIzs+qqt4IjqZukcZLulvRg4VKJcJXw7rvvctZZZzFx4kSmTp3K+eefv8IXqOWjc+fO1NbWUltbS9++famtraVnz55cdNFFTJ48mauuuopjjjmGTz75BIDRo0czZcoU+vfvz/33JyMWzJw5k8GDBzNx4sQV1v3aa68RESxYsID58+dX/H8zM7Pqy3KI6gbgZmA4cDRwBFDx9v3tz7ivSY9/7MyhJcvvvvtuDjvsMDp16gTA5ptvDsAf/vAHrrvuOhYuXMi5557LnnvuyZgxY5g6dSrt27fnhhtuoF27dowcOZJFixYxaNAgxo4dy0EHHcTbb79Nhw4duO2221hnnXU4/fTTmTJlCn369Fm+3UmTJnHBBRfw+eefc/rppzNs2LCy+UutF5I+JT//+c/ZYYcdGDJkCEcddRQLFixgyy235LLLLmvScwaw7137NOnxf93/b416XI8ePRg6dChPPPHECuUffvjh8ut33HEHP/3pTzn33HNZvHgxHTp0AGDAgAFMmzaNV155hb333nv5oHVmZrbqqLcFB1gvIq4GlkTEQxHxn8BuOeeqmLlz59K9e/cvlR988MHU1tYyefJkLrzwQgAeeeQRpk6dypQpU+jevTtjx47lhBNOoLa2lnPOOQdIDqc89NBDHHTQQdx8883MnTuXadOm8fDDD7PLLrsAsGzZMi688EIefPBBamtrGTduXL05V15vwfHHH8+gQYM45JBDOO+88zj11FOZMmUKnTp14tFHH22Op6hqNthgA9566y0Axo0bR9++fZk2bRpDhyaV1aeeeooBAwYwbNgw/v73vy9/3IgRI7jzzju5++672WefplXQzMysdcrSgrMk/TtX0j7Am8C69T1IUkdgKtAh3c5tEXFGY4PmpXv37rz55ptfKr/vvvv47W9/S0TwzjvvAHDKKadwxBFHsN5663HOOefwwgsvLK/YtGvXjqVLlzJ69GhmzZrFRx99xIgRI3j11VfZZptkpovtttuO+++/n3nz5jF79mx23313AN555x0ios6+IaXWC/DCCy/QsWNHfvOb3wAwe/ZsfvGLXyCJhQsXMnDgwGZ9rirtjTfeYMstt+Tll19m9OjRjBw5kv3335/333+fBQsWMGvWLIYNG8bixYvZfPPNl1dmNt98c5577jnWXnvt5S1dZma2asnSgnO2pM7AScDJwATghAyPWwzsFhH9gG2BYZK2b2zQvOy9995cf/31LFiwAIAXX3yRuXPnMnbsWO655x7+8pe/0K5d8jTttttu/OlPf2L99ddn0qRJbLHFFjz22GNA0irz9NNP8/HHHzN16lSOOeYYIoKePXsya9YsIGlxAOjatSt9+/Zl8uTJ1NbWMnPmzLIdX0utF5Iv8kMPPZTRo0cDybxBF198MbW1tUyfPp399tsvnyetAt544w0eeOABBgwYsLxstdVW49hjj2X8+PHccccdTJgwgXvvvZcpU6Ywd+5cli37Yi7YAw44gMMOO6wa0c3MrAWotwUnIialV+cDu2ZdcTow4MJ0sX16aXEjIXfr1o1f/vKXDB8+nIhg3XXX5eqrr2b48OHsvPPODBw4kC5dugCw3377sWjRIgBuvfVWdtllF4444gjOPvtsdthhB8aMGcOLL77IsGHD2Gijjdhwww3p3r072223HTvttBP9+vUDktaeE088kSFDhiCJPn36cOmll66Q6+KLL15+dtD48eO/tN6Co446irFjx3L++eczZswYRo0axfz582nXrh0TJkygtU1eetJJJ9G1a1fWWGMNLrnkki+NgbTHHntw2mmnsfrqq69wtlSfPn14+OGHly8XzpyaM2dOJWKbmVkLozwHKJa0GjAD+AZwaUT8V7n79+/fP4on25w9ezZbbrllbvls1eX3VnmebNPMWgtJMyKi/8rlWQ5RNVpELI2IbYEewEBJW5cINkrSdEnTPfiamZmZNYdcKzgFEfEhMAX40rnQEXFlRPSPiP7dunWrRBwzMzNr4+rtgyPpXOCCtJKCpK8CJ0XEafU8rhvJqeUfSloT2AM4v+mRzayaGjomVV1jUFl+/BqZZTtNfK+IGFNYiIgPJO0NlK3gAN2B69J+OO2AW4o6LGdW7vRps8bIs9+Zma2oJVW2WlIWy1+WCs5qkjpExGKAtDWmQ30PiohngG81JVz79u359NNPPZu4NZvCbOKexNXMrG3LOlXDZEl/SJdHAtflF+kLXbt29Wm+1uw6duxIjx49qh3DzMxylGUcnPMlzQR2T4t+HRFNmxgqoy5duiwfg8bMrCXz4Q9rCL9f8pel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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_cas['app']\n", - "gap_22_cas = df_gap22_cas['BWBloat'].astype(float)\n", - "gap_22_ram = df_gap22_ram['BWBloat'].astype(float)\n", - "\n", - "\n", - "gap_25_cas = df_gap25_cas['BWBloat'].astype(float)\n", - "gap_25_ram = df_gap25_ram['BWBloat'].astype(float)\n", - "\n", - "app_npb = df_npbC_cas['app']\n", - "npb_C_cas = df_npbC_cas['BWBloat'].astype(float)\n", - "npb_C_ram = df_npbC_ram['BWBloat'].astype(float)\n", - "\n", - "npb_D_cas = df_npbD_cas['BWBloat'].astype(float)\n", - "npb_D_ram = df_npbD_ram['BWBloat'].astype(float)\n", - "\n", - "\n", - "# Multi bar Chart1\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,3.5])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - " plt.bar(i*3+1, gap_22_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", - "\n", - "offset = i*3+2\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_C_cas[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*3+2, npb_C_ram[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"BW Bloat (due to acc amp)\")\n", - "plt.legend(fontsize=8, ncol=2, loc='upper left')\n", - "plt.tight_layout()\n", - "\n", - "# Multi bar Chart2\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,3.5])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - " plt.bar(i*3+1, gap_25_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", - "\n", - "offset = i*3+2\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_D_cas[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*3+2, npb_D_ram[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"BW Bloat (due to acc amp)\")\n", - "plt.legend(fontsize=8, ncol=2, loc='upper left')\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Anything above is old results.\n", - "Tag probing results starts here:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/tmp/ipykernel_308484/3690351968.py:27: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " app_gap[len(app_gap)] = \"gmean\"\n", - "/tmp/ipykernel_308484/3690351968.py:30: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " app_npb[len(app_npb)] = \"gmean\"\n", - "/tmp/ipykernel_308484/3690351968.py:64: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " app_gap[len(app_gap)] = \"gmean\"\n", - "/tmp/ipykernel_308484/3690351968.py:67: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " app_npb[len(app_npb)] = \"gmean\"\n" - ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAlVElEQVR4nO3debxVZb3H8c83RI8DggN6TUSQtKtIoWLqRfMgdp3CoRuo5UBOOeaQOaRpdi3pdk1JuxqaF80JLU0UJbvGEdBUIAcQxExRMRSwBMkUgd/9Y6192BzPsM7ee51h832/Xue193r22uv5rT2s89vPetbzKCIwMzMzqyafau8AzMzMzCrNCY6ZmZlVHSc4ZmZmVnWc4JiZmVnVcYJjZmZmVWed9g6gHJtvvnn06dOnvcMwW+vNnTsXgM9+9rPtHImZrW1mzJixOCJ6Nizv1AlOnz59mD59enuHYbbWq62tBaCurq5d4zCztY+k1xsr9ykqMzMzqzpOcMzMzKzqOMExMzOzqtOp++A05uOPP2b+/Pl8+OGH7R2KWdWqqamhV69edO3atb1DMTNrVNUlOPPnz6dbt2706dMHSe0djlnViQjeffdd5s+fT9++fds7HDOzRlXdKaoPP/yQzTbbzMmNWU4ksdlmm7mV1Mw6tKpLcAAnN2Y583fMzDq6qjtFVWzPy39Xke08dcUBTT62ZMkSDjvsMACee+45dtxxR9Zbbz0WL15Mt27d6NKlCxHBySefzMiRIwHo27cv2267LStXrqRPnz6MHTuWLl26APCjH/2Im266iVdffbX+n0jfvn0ZOnQoN998MwC/+tWvOO6443jttddoONBhc9suuPLKK+nVq1d9PAUjR47k+eefZ+ONN2ajjTbijjvuoEePHi2+PmPHjmX+/PlceumlLa5bikN/e0hFtjP+8AlNPtbR3sfPfOYzvPLKKxXZ74Li9+mcc87hkksuoWfPT4yNZWZWFaqyBactde/enbq6Ourq6hg4cCD33nsvdXV1bL755tx7771MnTqVCRMmMHbsWCZNmgRAly5dqKurY8qUKXTt2pVHH320fnsPPfQQ++23H0888UR9WZcuXXjjjTf46KOPAPj1r3/Nbrvt1mg8zW07i+uuu47HH3+cwYMHc+ONN67x2MqVK1u1rc6ko72Pebv22mud3JhZVXOC0wZ69OjBJZdcwp133rlG+apVq3jvvfeICACeffZZ+vfvz2mnncbtt9++xroHHXQQEyZMYOHChXTt2rXFlpWG2548eTK77LILw4YN4+mnn24x5l133ZXXX3+dsWPHMnz4cA4//HBGjx7NTTfdxB577MEee+zBLbfcUr/+008/zbBhw9hll12YMmVKlpel02nr9/Hcc89l33335ZhjjmHVqlUsXryYoUOHUltby+DBg3n55ZcBOP/889lrr70YMmQI48aNA5JEdZ999mGvvfaqbzEqVltby/z585k3bx677bYbxxxzDLvuuivXXnstkLRojRgxgqFDh7LffvtVvDXJzCxvTnDayDbbbMNbb70FJC0htbW19OnTh5UrV3LAAckpsDvuuIPjjz+eQYMGMXv2bD7++OP65x911FGMGzeOcePGMWLEiCbraWrb5513Hg888ADjx4+vb0FozqOPPkr//v0BWLZsGffffz/HHnss119/PVOmTGHKlCmMHj2aRYsWAcnl+Q8++CD3338/5557bmkvUifQVu/jihUrGDFiBI8//jjrr78+48ePp3v37jzyyCPU1dVx6aWXMmrUKAAeeeQRpkyZwqRJkxg+fDhz5sxh4sSJTJ48malTp3LLLbfw7rvvNlnXggULGDNmDE8++SSjR48G4KqrruIrX/kKjz32GNdccw0XXXRR2a+dmVlbyi3BkbSNpEmSZkt6UdLZafmmkn4v6c/p7SZpuST9TNIrkl6QtGtesbWHN998k6233hpYfWpj5syZLFq0iPfee49Vq1bxwAMPcOWVV3LggQeycOFCHn744frnb7XVVixbtoy7776bYcOG1Zdff/311NbWctJJJzW5bYClS5fSu3dvJPGFL3wBgKlTp1JbW0ttbS3Lli0D4KyzzmLffffln//8Z/0299xzTyTx6quvMmDAANZdd13WXXddBgwYwGuvvQbA7rvvDiTzgy1ZsiTHV7J9tdX7WPw+7bHHHsydO5f33nuPY445hi9+8YtcccUVvPnmmwCMGjWKE044gZEjRzJnzhxmzZrF7NmzGTJkCEOHDmXp0qX16zZmxx13ZIMNNqCmpqa+D9HMmTMZPXo0tbW1nH322fWfIzOzziLPFpwVwLcjYidgT+AMSTsBFwGPRcT2wGPpMsBBwPbp3ynADTnG1qaWLFnCVVddxdFHH71Geffu3Tn11FP58Y9/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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "gap_22_prob = df_gap22_ram_prob['avgTimeTagCheckResRd'].astype(float)\n", - "gap_22_ram = df_gap22_ram['avgTimeTagCheckResRd'].astype(float)\n", - "gap_22_prob[len(gap_22_prob)] = statistics.geometric_mean(df_gap22_ram_prob['avgTimeTagCheckResRd'].astype(float))\n", - "gap_22_ram[len(gap_22_ram)] = statistics.geometric_mean(df_gap22_ram['avgTimeTagCheckResRd'].astype(float))\n", - "\n", - "\n", - "gap_25_prob = df_gap25_ram_prob['avgTimeTagCheckResRd'].astype(float)\n", - "gap_25_ram = df_gap25_ram['avgTimeTagCheckResRd'].astype(float)\n", - "gap_25_prob[len(gap_25_prob)] = statistics.geometric_mean(df_gap25_ram_prob['avgTimeTagCheckResRd'].astype(float))\n", - "gap_25_ram[len(gap_25_ram)] = statistics.geometric_mean(df_gap25_ram['avgTimeTagCheckResRd'].astype(float))\n", - "\n", - "npb_C_prob = df_npbC_ram_prob['avgTimeTagCheckResRd'].astype(float)\n", - "npb_C_ram = df_npbC_ram['avgTimeTagCheckResRd'].astype(float)\n", - "npb_C_prob[len(npb_C_prob)] = statistics.geometric_mean(df_npbC_ram_prob['avgTimeTagCheckResRd'].astype(float))\n", - "npb_C_ram[len(npb_C_ram)] = statistics.geometric_mean(df_npbC_ram['avgTimeTagCheckResRd'].astype(float))\n", - "\n", - "\n", - "\n", - "npb_D_prob = df_npbD_ram_prob['avgTimeTagCheckResRd'].astype(float)\n", - "npb_D_ram = df_npbD_ram['avgTimeTagCheckResRd'].astype(float)\n", - "npb_D_prob[len(npb_D_prob)] = statistics.geometric_mean(df_npbD_ram_prob['avgTimeTagCheckResRd'].astype(float))\n", - "npb_D_ram[len(npb_D_ram)] = statistics.geometric_mean(df_npbD_ram['avgTimeTagCheckResRd'].astype(float))\n", - "\n", - "################################## \n", - "# Multi bar Chart1\n", - "app_gap = df_gap22_ram_prob['app']\n", - "app_gap[len(app_gap)] = \"gmean\"\n", - "\n", - "app_npb = df_npbC_ram_prob['app']\n", - "app_npb[len(app_npb)] = \"gmean\"\n", - "\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,3)\n", - "plt.ylim([0,220])\n", - "barWidth = 1\n", - "tickSize = 3\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*tickSize-barWidth/2, gap_22_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", - " plt.bar(i*tickSize+barWidth/2, gap_22_ram[i], width=barWidth, color=cmap(2), label='TDRAM-baseline' if i==0 else None)\n", - "\n", - "offset = i+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar((offset+i)*tickSize-barWidth/2, npb_C_prob[i], width=1, color=cmap(1))\n", - " plt.bar((offset+i)*tickSize+barWidth/2, npb_C_ram[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.25, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.7, -0.01, \"NPB-C\")\n", - "\n", - "brLab = np.arange(len(app_gap)+len(app_npb))\n", - "plt.xticks(brLab*tickSize, list(app_gap)+list(app_npb))\n", - "\n", - "plt.axvline(x=(offset-0.5)*tickSize, color='black')\n", - "# plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Tag Comparison Latency (ns)\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()\n", - "\n", - "###############################################################################\n", - "# Multi bar Chart2\n", - "app_gap = df_gap25_ram_prob['app']\n", - "app_gap[len(app_gap)] = \"gmean\"\n", - "\n", - "app_npb = df_npbD_ram_prob['app']\n", - "app_npb[len(app_npb)] = \"gmean\"\n", - "\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,3)\n", - "plt.ylim([0,220])\n", - "barWidth = 1\n", - "tickSize = 3\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*tickSize-barWidth/2, gap_25_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Probe' if i==0 else None)\n", - " plt.bar(i*tickSize+barWidth/2, gap_25_ram[i], width=barWidth, color=cmap(2), label='TDRAM-baseline' if i==0 else None)\n", - "\n", - "offset = i+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar((offset+i)*tickSize-barWidth/2, npb_D_prob[i], width=1, color=cmap(1))\n", - " plt.bar((offset+i)*tickSize+barWidth/2, npb_D_ram[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.25, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.70, -0.01, \"NPB-D\")\n", - "\n", - "brLab = np.arange(len(app_gap)+len(app_npb))\n", - "plt.xticks(brLab*tickSize, list(app_gap)+list(app_npb))\n", - "\n", - "plt.axvline(x=(offset-0.5)*tickSize, color='black')\n", - "# plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Tag Comparison Latency (ns)\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/tmp/ipykernel_308484/1065878878.py:27: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " app_gap[len(app_gap)] = \"gmean\"\n", - "/tmp/ipykernel_308484/1065878878.py:30: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " app_npb[len(app_npb)] = \"gmean\"\n", - "/tmp/ipykernel_308484/1065878878.py:64: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " app_gap[len(app_gap)] = \"gmean\"\n", - "/tmp/ipykernel_308484/1065878878.py:67: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " app_npb[len(app_npb)] = \"gmean\"\n" - ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAnRklEQVR4nO3de5xVdb3/8dc7REeRS14Pgjh4KRVRUBQ9oI5geQtRCwLzwskkCyotT2n60+xY2kXRtOyAcjAviZcQVEzLQEBTAUOuYigoQyRgCmJeuHx+f6w142ac2bNnz+y57Hk/H4/9mL2+e+31/ax9WfPZ3/Vd368iAjMzM7Ni8qmmDsDMzMysoTnBMTMzs6LjBMfMzMyKjhMcMzMzKzpOcMzMzKzoOMExMzOzolOwBEdSiaQXJL0kaZGka9Ly7pKel7RM0kRJ26flO6TLy9LHSwsVm5mZmRW3QrbgfAgMiIjDgF7AyZKOBn4GjImI/YG3gQvS9S8A3k7Lx6TrmZmZmdVZwRKcSGxMF9umtwAGAA+m5XcCZ6T3B6fLpI8PlKRCxWdmZmbFa7tCblxSG2AusD/wa+BV4J2I2JyuUg50Se93AVYCRMRmSeuBXYF1VbY5EhgJ0K5duyMOPPDAQu6CmeVg6dKlAHz2s59t4kjMrLWZO3fuuojYvWp5QROciNgC9JLUCZgE1DsbiYixwFiAPn36xJw5c+q7STOrp7KyMgCmT5/epHGYWesj6fXqyhvlKqqIeAeYBhwDdJJUkVh1BVal91cBewOkj3cE3mqM+MzMzKy4FPIqqt3Tlhsk7Qh8DlhCkuh8KV3tfGByen9Kukz6+F/CM4GamZlZHgp5iqozcGfaD+dTwP0R8aikxcB9kq4F/gbcka5/B3CXpGXAv4BhBYzNzMzMiljBEpyImA/0rqb8NeCoaso/AIbUt95NmzZRXl7OBx98UN9NmVkNSkpK6Nq1K23btm3qUMzMqlXQTsZNoby8nPbt21NaWoqvMjdreBHBW2+9RXl5Od27d2/qcMzMqlV0UzV88MEH7Lrrrk5uzApEErvuuqtbSc2sWSu6BAdwcmNWYP6OmVlzV3SnqDIdffUTDbKd5645qcbH1q9fz+DBgwGYN28eBx10EDvssAPr1q2jffv2tGnThojgwgsvZMSIEQB0796dffbZhy1btlBaWsqECRNo06YNAD/96U8ZN24cr732WuU/ke7duzNw4EBuv/12AO666y7OO+88li9fTmlp6TbxZNt2hWuvvZauXbtWxlNhxIgRvPTSS3To0IGdd96Ze+65h06dOtX6+kyYMIHy8nKuvPLKWtfNx+kPn9Yg25lyxmM1Ptbc3sf999+fZcuWNch+V8h8ny6++GKuuOIKdt/9E2NjmZkVhaJswWlMHTt2ZPr06UyfPp1evXrxwAMPMH36dHbbbTceeOABZs2axWOPPcaECROYNm0aAG3atGH69OnMnDmTtm3b8uSTT1Zu79FHH2XAgAE888wzlWVt2rThjTfe4MMPPwTgwQcf5Igjjqg2nmzbzsUtt9zC008/Tb9+/fjtb3+7zWNbtmyp07Zakub2PhbaTTfd5OTGzIqaE5xG0KlTJ6644gruvffebcq3bt3KO++8Q8VwP3/729/o0aMH3/jGN7j77ru3WfeUU07hscceY82aNbRt27bWlpWq254xYwa9e/dm0KBBPP/887XGfPjhh/P6668zYcIEhgwZwhlnnMHNN9/MuHHj6Nu3L3379mX8+PGV6z///PMMGjSI3r17M3PmzFxelhansd/HSy65hOOPP55zzjmHrVu3sm7dOgYOHEhZWRn9+vXjlVdeAeDSSy/lmGOO4YQTTmDixIlAkqgee+yxHHPMMZUtRpnKysooLy9nxYoVHHHEEZxzzjkcfvjh3HTTTUDSojV06FAGDhzIgAEDGrw1ycys0JzgNJK9996bVauSQZu3bNlCWVkZpaWlbNmyhZNOSk6B3XPPPZx//vn06dOHxYsXs2nTpsrnDxs2jIkTJzJx4kSGDh1aYz01bfu73/0ukydPZsqUKZUtCNk8+eST9OjRA4CNGzcyadIkzj33XG699VZmzpzJzJkzufnmm1m7di2QXJ7/yCOPMGnSJC655JL8XqQWoLHex82bNzN06FCefvppdtxxR6ZMmULHjh15/PHHmT59OldeeSXXX389AI8//jgzZ85k2rRpDBkyhCVLlvDHP/6RGTNmMGvWLMaPH89bb9U8KPjq1asZO3Yszz77LDfffDMA1113HWeddRZPPfUUY8aM4bLLLqv3a2dm1pic4DSSlStX0qVLMq9oxamNBQsWsHbtWt555x22bt3K5MmTufbaazn55JNZs2YNU6dOrXx+586d2bhxI/fddx+DBg2qLL/11lspKyvja1/7Wo3bBtiwYQPdunVDEkcdlQxDNGvWLMrKyigrK2PjxmTi929961scf/zxvP/++5XbPProo5HEa6+9Rs+ePdl+++3Zfvvt6dmzJ8uXLwfgyCOPBKC0tJT169cX8JVsWo31Pma+T3379mXp0qW88847nHPOORx33HFcc801rFy5EoDrr7+er371q4wYMYIlS5awcOFCFi9ezAknnMDAgQPZsGFD5brVOeigg9hpp50oKSmp7EO0YMECbr75ZsrKyvjOd75T+TkyM2spirqTcXOxfv16rrvuuk90wu3YsSMXXXQRP/vZzzjppJMYPHgwv/zlLwF49dVXufzyyys7vgKMGjWKxYsXs+OOO1aWjR49mtGjR3+izsxt//znP6d9+/aUl5fTtWtXZs+ezf7770///v0/MTniLbfcQv/+/bcpq/in1717d+bPn89HH30EJP8Eu3fvzuLFi5k7dy4Ab7zxBh06dMjzlWreGvN9jAjmzJlD3759mT17NieffDJ33303vXv35vLLL2fq1KnceOONRAQnnngigwYNYtasWVx11VVcc8019O7dm4ceeghJbNq0ibZt2zJv3rxq96u6K6J69OjBMcccw5lnnglQ+Z6bmbUUTnAKaMiQIbRp04atW7fy1a9+lQEDBnxinWHDhtGzZ0/WrVvH2WefXVm+3377sWTJEjZs2FBZduqpp3LqqafmXH/Ftn/4wx9yww03MGjQIPbaay/at2+f1/7ssccefPOb36xMgEaPHl3ZUXWnnXbitNNO4x//+AdjxozJa/vNVVO8j9tttx0PPfQQ3//+9+nSpQunn346L7/8MmeffTYzZsyoPH24efNmTjnlFCAZA+qqq67ikEMO4cQTT+T444+nTZs2lae46uKKK67goosu4pZbbiEiOO2007j00kvrtA0zs6akljyfZZ8+fWLOnDnblC1ZsoSDDjqoiSIyaz0yv2tlZWUAn2gRNDMrNElzI6JP1XL3wTEzM7Oi4wTHzMzMik5RJjgt+bSbWUvg75iZNXdFl+CUlJTw1ltv+QBsViAVs4mXlJQ0dShmZjUququounbtSnl5eeUAdGbW8EpKSujatWtTh2FmVqOsCY6kEuALwLHAXsD7wELgsYhYVPjw6q5t27Z07969qcMwMzOzJlRjgiPpGpLkZjrwPLAGKAE+A1yfJj/fi4j5jRCn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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAmRklEQVR4nO3de7yVc97/8ddbotCBxJ1COYxDGkXEr4xUxmkSbqUcux0apmbGaebW8GPcY4aZQYxMfkV3xjGnFGLQlMoMKqKTSEWlEKOcO31+f1zX3pZtH9bee619WL2fj8d+rHV9r8P3c63DtT/r+72u66uIwMzMzKyQbFHbAZiZmZnlmhMcMzMzKzhOcMzMzKzgOMExMzOzguMEx8zMzAqOExwzMzMrOHlLcCQ1kvSKpNclzZN0bVreTtLLkhZJGitpq7R863R6UTq/bb5iMzMzs8KWzxacb4AeEXEg0BE4VtJhwB+BYRGxF/Bv4Lx0+fOAf6flw9LlzMzMzCotbwlOJD5PJxumfwH0AB5Jy+8GTkqf90mnSef3lKR8xWdmZmaFa8t8blxSA2AWsBdwO/AO8GlEbEgXWQ60Tp+3BpYBRMQGSWuAFsDqEtscBAwC2HbbbQ/ed99987kLZpaFhQsXArDPPvvUciRmtrmZNWvW6ohoWbI8rwlORGwEOkpqDowDqp2NRMRIYCRA586dY+bMmdXdpJlVU/fu3QGYMmVKrcZhZpsfSe+WVl4jV1FFxKfAZOBwoLmkosSqDbAifb4C2BUgnd8M+Lgm4jMzM7PCks+rqFqmLTdIagwcDSwgSXROTRc7BxifPp+QTpPO/0d4JFAzMzOrgnx2UbUC7k7Pw9kCeCginpQ0H3hQ0nXAa8Bd6fJ3AfdIWgR8AvTPY2xmZmZWwFSfG0lKOwdn/fr1LF++nK+//rqWojLb/KxatYqIoF27drRp04aGDRvWdkhmtpmQNCsiOpcsz+tJxrVh+fLlNGnShLZt2+KrzM1qxhZbbEFE0KRJE5YvX067du1qOyQz28wV3FANX3/9NS1atHByY1bDJNGiRQu3nppZnVBwCQ7g5Maslvi7Z2Z1RcF1UWU67Jq/52Q7L117TJnz1qxZQ58+fQCYPXs2++23H1tvvTWrV6+mSZMmNGjQgIjgggsuYODAgQC0a9eO3XffnY0bN9K2bVvGjBlDgwYNAPjDH/7AqFGjWLx4cfE/i3bt2tGzZ0/uvPNOAO655x7OPvtslixZQtu2bb8TT3nbLnLdddfRpk2b4niKDBw4kNdff52mTZuy3Xbbcd9999G8efMKX58xY8awfPlyrrrqqgqXzaUTHz8hJ9uZcNJTZc6ra+/vXnvtxaJFi3Ky30Uy37+LL76YK6+8kpYtv3fPLDOzeqUgW3BqUrNmzZgyZQpTpkyhY8eOPPzww0yZMoUdd9yRhx9+mOnTp/PUU08xZswYJk+eDECDBg2YMmUK06ZNo2HDhjz77LPF23vyySfp0aMHL774YnFZgwYNeO+99/jmm28AeOSRRzj44INLjae8bWfjtttu44UXXqBr167ccccd35m3cePGSm2rENS19zffbrnlFic3ZlYQnODUgObNm3PllVdy//33f6d806ZNfPrppxRdyfbaa6/Rvn17LrroIu69997vLHvcccfx1FNP8eGHH9KwYcMKW1ZKbnvq1Kl06tSJ3r178/LLL1cY80EHHcS7777LmDFj6Nu3LyeddBK33noro0aNokuXLnTp0oXRo0cXL//yyy/Tu3dvOnXqxLRp0wCYM2cOvXr1okePHvTr14+vvvqqwnrro5p+fy+55BKOPPJIzjzzTDZt2sTq1avp2bMn3bt3p2vXrrz11lsAXH755Rx++OEcddRRjB07FkgS2COOOILDDz+8uMUoU/fu3Vm+fDlLly7l4IMP5swzz+Sggw7illtuAZIWrX79+tGzZ0969OiR89YkM7NccYJTQ3bddVdWrEhu2rxx40a6d+9O27Zt2bhxI8cck3SB3XfffZxzzjl07tyZ+fPns379+uL1+/fvz9ixYxk7diz9+vUrs56ytn3ppZcyfvx4JkyYUNxSUJ5nn32W9u3bA/D5558zbtw4zjrrLIYPH860adOYNm0at956Kx999BGQXJ7/xBNPMG7cOC655BIABg8ezOjRo/nHP/5B165dueuuu8qsr76rqfd3w4YN9OvXjxdeeIHGjRszYcIEmjVrxtNPP82UKVO46qqruOGGGwB4+umnmTZtGpMnT6Zv374sWLCAZ555hqlTpzJ9+nRGjx7Nxx+XfbPwlStXMnLkSP75z39y6623AnD99ddzyimnMGnSJIYNG8YVV1xR7dfOzCwfCvocnLpk2bJltG6djCta1IWxZs0ajjvuOD799FO23357xo8fz9y5cwH48MMPmThxYvH5H61ateLzzz/nwQcf5Pnnn2fkyJEADB8+nEceeYS99tqLO++8s9Rtt2jRgrVr17LbbrsBcOihhwIwffr04vNmnnzySQB+/vOf07RpU/bff3/OP/98HnzwQQ477DAksXjxYjp06MBWW20FQIcOHViyZAkAhxxyCABt27ZlzZo1AMybN4+zzz4bSK5u69WrVx5f4dpVU++vpOL3r0uXLixcuJCuXbsyePBgVq1axbp162jSpAkAN9xwA+eeey5bbLEFv/rVr5g/fz7z58/nqKOOAmDt2rUsW7aszH3ab7/92GabbYr3CZJWuRdeeKG4+3LLLX0IMbO6yUenGrBmzRquv/76752E26xZMy688EL++Mc/cswxx9CnTx9uvPFGAN555x2GDh1a/A8QkhaR+fPn07hx4+KyIUOGMGTIkO/VmbntP/3pT8X3J2nTpg0zZsxgr732olu3bt8bHPG2226jW7du3ykr+ufWrl073njjDdatWwck/+zatWvH/PnzmTVrFgDvvfceTZs2BeCAAw7ggQceoFWrVgDF6xWamnx/I4KZM2fSpUsXZsyYwbHHHsu9995Lp06dGDp0KBMnTuTmm28mIujVqxe9e/dm+vTpXH311Vx77bV06tSJRx99FEmsX7+ehg0bMnv27FL3q7Qrotq3b8/hhx/OySefDBTue2pm9Z8TnDzq27cvDRo0YNOmTZx77rn06NHje8v079+fDh06sHr1ak4//fTi8j333JMFCxawdu3a4rLjjz+e448/Puv6i7b9m9/8hptuuonevXuzyy67FP/Cr6yddtqJn/3sZ8UJ0JAhQ4pPSN1mm2044YQTeP/99xk2bBgAt99+OwMHDizuihk6dChHH310lequi2rj/d1yyy159NFH+fWvf03r1q058cQTefPNNzn99NOZOnVqcbfihg0bOO6444Ck9ezqq6/mgAMOoFevXhx55JE0aNCguIurMq688kouvPBCbrvtNiKCE044gcsvv7xS2zAzqwkFN1TDggUL2G+//WopIrPN08KFCwHYZ599/B00sxpV1lANPsnYzMzMCo67qMzMrOBkeyPQ8m70afVbQbbg1OduN7P6zN89M6srCi7BadSoER9//LEPtGY1LCL4+OOPadSoUW2HYmZWeF1Ubdq0Yfny5cU3oDOz/Fu1ahURwdZb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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "gap_22_prob = df_gap22_ram_prob['avgPktRespTimeRd'].astype(float)\n", - "gap_22_ram = df_gap22_ram['avgPktRespTimeRd'].astype(float)\n", - "gap_22_prob[len(gap_22_prob)] = statistics.geometric_mean(df_gap22_ram_prob['avgPktRespTimeRd'].astype(float))\n", - "gap_22_ram[len(gap_22_ram)] = statistics.geometric_mean(df_gap22_ram['avgPktRespTimeRd'].astype(float))\n", - "\n", - "\n", - "gap_25_prob = df_gap25_ram_prob['avgPktRespTimeRd'].astype(float)\n", - "gap_25_ram = df_gap25_ram['avgPktRespTimeRd'].astype(float)\n", - "gap_25_prob[len(gap_25_prob)] = statistics.geometric_mean(df_gap25_ram_prob['avgPktRespTimeRd'].astype(float))\n", - "gap_25_ram[len(gap_25_ram)] = statistics.geometric_mean(df_gap25_ram['avgPktRespTimeRd'].astype(float))\n", - "\n", - "npb_C_prob = df_npbC_ram_prob['avgPktRespTimeRd'].astype(float)\n", - "npb_C_ram = df_npbC_ram['avgPktRespTimeRd'].astype(float)\n", - "npb_C_prob[len(npb_C_prob)] = statistics.geometric_mean(df_npbC_ram_prob['avgPktRespTimeRd'].astype(float))\n", - "npb_C_ram[len(npb_C_ram)] = statistics.geometric_mean(df_npbC_ram['avgPktRespTimeRd'].astype(float))\n", - "\n", - "\n", - "\n", - "npb_D_prob = df_npbD_ram_prob['avgPktRespTimeRd'].astype(float)\n", - "npb_D_ram = df_npbD_ram['avgPktRespTimeRd'].astype(float)\n", - "npb_D_prob[len(npb_D_prob)] = statistics.geometric_mean(df_npbD_ram_prob['avgPktRespTimeRd'].astype(float))\n", - "npb_D_ram[len(npb_D_ram)] = statistics.geometric_mean(df_npbD_ram['avgPktRespTimeRd'].astype(float))\n", - "\n", - "################################## \n", - "# Multi bar Chart1\n", - "app_gap = df_gap22_ram_prob['app']\n", - "app_gap[len(app_gap)] = \"gmean\"\n", - "\n", - "app_npb = df_npbC_ram_prob['app']\n", - "app_npb[len(app_npb)] = \"gmean\"\n", - "\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,3)\n", - "plt.ylim([0,300])\n", - "barWidth = 1\n", - "tickSize = 3\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*tickSize-barWidth/2, gap_22_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", - " plt.bar(i*tickSize+barWidth/2, gap_22_ram[i], width=barWidth, color=cmap(2), label='TDRAM-baseline' if i==0 else None)\n", - "\n", - "offset = i+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar((offset+i)*tickSize-barWidth/2, npb_C_prob[i], width=1, color=cmap(1))\n", - " plt.bar((offset+i)*tickSize+barWidth/2, npb_C_ram[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.25, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.7, -0.01, \"NPB-C\")\n", - "\n", - "brLab = np.arange(len(app_gap)+len(app_npb))\n", - "plt.xticks(brLab*tickSize, list(app_gap)+list(app_npb))\n", - "\n", - "plt.axvline(x=(offset-0.5)*tickSize, color='black')\n", - "# plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Avg Rd Resp Time (ns) (ns)\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()\n", - "\n", - "###############################################################################\n", - "# Multi bar Chart2\n", - "app_gap = df_gap25_ram_prob['app']\n", - "app_gap[len(app_gap)] = \"gmean\"\n", - "\n", - "app_npb = df_npbD_ram_prob['app']\n", - "app_npb[len(app_npb)] = \"gmean\"\n", - "\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,3)\n", - "plt.ylim([0,300])\n", - "barWidth = 1\n", - "tickSize = 3\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*tickSize-barWidth/2, gap_25_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Probe' if i==0 else None)\n", - " plt.bar(i*tickSize+barWidth/2, gap_25_ram[i], width=barWidth, color=cmap(2), label='TDRAM-baseline' if i==0 else None)\n", - "\n", - "offset = i+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar((offset+i)*tickSize-barWidth/2, npb_D_prob[i], width=1, color=cmap(1))\n", - " plt.bar((offset+i)*tickSize+barWidth/2, npb_D_ram[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.25, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.70, -0.01, \"NPB-D\")\n", - "\n", - "brLab = np.arange(len(app_gap)+len(app_npb))\n", - "plt.xticks(brLab*tickSize, list(app_gap)+list(app_npb))\n", - "\n", - "plt.axvline(x=(offset-0.5)*tickSize, color='black')\n", - "# plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Avg Rd Resp Time (ns)\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/tmp/ipykernel_308484/3412151829.py:27: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " app_gap[len(app_gap)] = \"gmean\"\n", - "/tmp/ipykernel_308484/3412151829.py:30: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " app_npb[len(app_npb)] = \"gmean\"\n", - "/tmp/ipykernel_308484/3412151829.py:64: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " app_gap[len(app_gap)] = \"gmean\"\n", - "/tmp/ipykernel_308484/3412151829.py:67: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " app_npb[len(app_npb)] = \"gmean\"\n" - ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAnRElEQVR4nO3de5xd0/3/8ddbgriEoPhqEhKXFkGFEH6CSaJuaSR8iVCXNC5fLSVUlWqpfv1Q1aJ8yzcujboUdUsQt5/SoKRJCImkNCIkaVSCJEKCJJ/fH3tNHJOZM2dmzjkzc+b9fDzOY85eZ5+9Pvtc9nzO2muvpYjAzMzMrJKs0dwBmJmZmRWbExwzMzOrOE5wzMzMrOI4wTEzM7OK4wTHzMzMKo4THDMzM6s4JUtwJN0q6X1JU3PKNpb0lKR/pr8bpXJJ+p2kGZJek7RbznNOTOv/U9KJpYrXzMzMKkcpW3BGAQfXKDsfeDoitgOeTssAhwDbpdupwA2QJUTAxUBvYE/g4uqkyMzMzKwuJUtwImIc8GGN4kHAben+bcDgnPI/RuYloJOkLYCDgKci4sOI+Ah4itWTJjMzM7OvaF/m+jaPiHnp/nvA5ul+Z2B2znpzUlld5auRdCpZ6w/rrbfe7ttvv30RwzazQr3xxhsAfPOb32zmSMysLZg0adKCiNi0Znm5E5xVIiIkFW2eiIgYCYwE6NWrV0ycOLFYmzazBqiqqgLg2WefbdY4zKxtkPRObeXlvorq3+nUE+nv+6l8LtA1Z70uqayucjMzM7M6lTvBGQNUXwl1IjA6p/yEdDXVXsCidCrrCeBASRulzsUHpjIzMzOzOpXsFJWkPwFVwNckzSG7GuoK4F5JJwHvAEPS6mOBQ4EZwKfA9wAi4kNJ/w1MSOv9MiJqdlw2MzMz+4qSJTgRcUwdD/WvZd0ATq9jO7cCtzY1ni+++II5c+awbNmypm7KzPLYaaedmDp1av0rmpmVULN1Mi63OXPm0LFjR7p164ak5g7HrCItXbqUAw880AmOmTW7NjNVw7Jly9hkk02c3JiVUIcOHejYsWNzh2Fm1nYSHMDJjVmJ+TtmZi1FmzlFlWuvi4tzIdZLlxyU9/FFixYxaNAgACZPnswOO+zA2muvzYIFC+jYsSPt2rUjIjjllFMYNmwYAN27d2errbZixYoVdOvWjVGjRtGuXTsALrvsMm666SZmzpy56h9J9+7d6d+/PzfffDMAt99+OyeccAJvv/023bp1+0o8+bZd7dJLL6VLly6r4qk2bNgwXn31VTbYYAPWX3997rzzTjp16lTvazRq1CjmzJnDz372s3rXbajDHhpQlO2MGfxonY+1tPdw2223ZcaMGUXZ72q579GIESO48MIL2XTT1cbMMjNrVdpkglMuG2644arBzqqqqrjjjjvo0qXLV+4vXLiQwYMHs9VWW9G3b1/atWu36jnDhw/nySef5JBDDgHgkUceoV+/frzwwgv06dMHgHbt2vHuu+/y2Wefsfbaa3Pfffex++671xpPvm0X4rrrrqNPnz5cdtll3HjjjZx//vmrHluxYsVqyVIlaGnvYaldc801zVKvVb5Cf5Dk+8Fh1hBt6hRVS9SpUycuvPBC7rrrrq+Ur1y5koULF5JdYAavvPIKPXr04Pvf/z533HHHV9Y95JBDePTRR3n//fdZc801621ZqbntcePG0bNnTwYOHMj48ePrjXm33XbjnXfeYdSoURx11FEMHjyYa6+9lptuuonevXvTu3dvbr31ywvfxo8fz8CBA+nZsyfPPfdcIS9Lq1Lu9/Dss89m//3357jjjmPlypUsWLCA/v37U1VVxT777MObb74JwLnnnsvee+9N3759ueeee4AsSd13333Ze++9V7UY5aqqqmLOnDnMmjWL3XffneOOO47ddtttVeKzaNEihgwZQv/+/enXr1/RW5PMzIrFLTgtQNeuXZk7NxugecWKFVRVVTFz5kx69uzJQQdlp8HuvPNOTjzxRHr16sU555zDF198wZprrgnA0KFDGTFiBHPnzmXIkCGMHDmy1nrq2vY555zD6NGj6dq166qyfJ588kl69OgBwJIlSxg7diwLFizggAMOYMKEbMiiPfbYg4EDBwLZJfqPP/44s2bN4sgjj6QSp9Eo13u4fPlyhgwZwtVXX80pp5zCmDFjGDBgAI899hhrrbUWjz32GFdccQW33norjz32GK+++irt27dn5cqVTJ8+nccff5xx48axcuVK9t13Xw4//PA692nevHk899xzrLHGGuywww6MGDGCyy+/nCOOOIKhQ4fy6quvcv7553PfffcV+dW01qTQU/6b9SxxIGY1uAWnBZg9ezadO2dziFaf3pgyZQrz589n4cKFrFy5ktGjR3PppZdy8MEH8/777zN27NhVz99iiy1YsmQJd99996qkAuD666+nqqqKk08+uc5tAyxevJgtt9wSSey5554APP/881RVVVFVVcWSJUsA+OEPf8j+++/P0qVLV21zr732QhIzZ85k5513Zq211mKttdZi55135u233wayZAegW7duLFq0qISvZPMp13uY+x717t2bN954g4ULF3Lcccex3377cckllzB7djY/7RVXXMHw4cMZNmwY06dPZ+rUqUybNo2+ffvSv39/Fi9evGrd2uywww6su+66dOjQYdXpxylTpnDttddSVVXFWWedteozZGbW0rgFp5ktWrSIyy+/fLVOuBtuuCGnnXYav/rVrzjooIMYNGgQV111FQBvvfUWF1xwwarOrwCnn34606ZNY5111llVdsYZZ3DGGWesVmfutq+88ko6duzInDlz6NKlCxMmTGDbbbelT58+q02WWN0HJ1f1P77u3bvz2muv8fnnnwPZP8Lu3bszbdo0Jk2aBMC7777LBhts0MhXquUq53sYEUycOJHevXszYcIEDj74YO644w569uzJBRdcwNixY/ntb39LRHDAAQcwcOBAnn/+eS666CIuueQSevbsyf3334+kVS1IkydPrnW/arsiqkePHuy9996rWn6q328zs5bGCU4zOeqoo2jXrh0rV65k+PDh9OvXb7V1hg4dys4778yCBQs49thjV5Vvs802TJ8+ncWLF68qO/TQQzn00EMLrr962z/96U/5zW9+w8CBA/n617/e6DFMNttsM37wgx+sSoDOOOOMVVfirLvuugwYMIB//etfXH311Y3afkvUHO9h+/btuf/++znvvPPo3Lkzhx12GP/4xz849thjGTdu3KpTh8uXL1/VsXnZsmVcdNFF7LTTThxwwAHsv//+tGvXjnXWWYcxY8Y0aJ8vvPBCTjvtNK677joiggEDBnDuuec2aBtmZuWg6g6QlaRXr15Rs5/H9OnT2WGHHZopIrO245lnnuGSSy5ZrQXQKlPhfXB+V9B6vorKGkrSpIjoVbPcfXDMzMys4jjBMTMzs4rTphKcSjwdZ9aS+DtmZi1Fm0lwOnTowAcffOADsFkJLVu2jI8//ri5wzAzaztXUXXp0oU5c+Ywf/785g7FrKI9+eSTzR2CmVnbSXDWXHNNunfv3txhmFW8qVOnNncIZmb1JziSNgP2Ab4O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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAmdklEQVR4nO3deZhU1bnv8e9PQBFlUESDoELEG+eIokjAiIAxahDNFRyiQtR4NJJEjTEhejQmOYkax2iOXlQOxnkWVDQaIwIaOYCiKIjiSBOIYBTizPDeP/bqtoTuorq7qofq3+d5+qnaq3bt9e4adr+11tp7KSIwMzMzKycbNHYAZmZmZsXmBMfMzMzKjhMcMzMzKztOcMzMzKzsOMExMzOzsuMEx8zMzMpOyRIcSeMkvSvppZyyzSU9Lum1dLtZKpekP0paIOlFSXvmPGdkWv81SSNLFa+ZmZmVj1K24IwHvr1W2S+AJyJiB+CJtAxwMLBD+jsFuBayhAi4AOgL7ANcUJkUmZmZmdWkZAlOREwB/rVW8TDgpnT/JuDwnPI/R+ZZoJOkrsBBwOMR8a+IeB94nHWTJjMzM7Mvad3A9W0VEYvT/SXAVul+N2BhznoVqaym8nVIOoWs9YdNNtlkrx133LGIYZtZoebPnw/A1772tUaOxMxaglmzZi2LiC5rlzd0glMlIkJS0eaJiIixwFiAPn36xMyZM4u1aTOrhYEDBwIwefLkRo3DzFoGSW9XV97QZ1H9M3U9kW7fTeWLgG1y1uueymoqNzMzM6tRQyc4E4HKM6FGAhNyyk9IZ1PtCyxPXVl/Ab4labM0uPhbqczMzMysRiXropJ0OzAQ2EJSBdnZUBcBd0k6CXgbGJFWnwQcAiwAPga+DxAR/5L0G2BGWu/XEbH2wGUzMzOzL1FE0YbBNBnVjcFZuXIlFRUVfPrpp40UlVnLsGTJEgC+8pWvVJW1bduW7t2706ZNm8YKy8zKlKRZEdFn7fJGG2Tc0CoqKmjfvj09evRAUmOHY1a2Ntgg6/muPIsqInjvvfeoqKigZ8+ejRmambUgLWaqhk8//ZTOnTs7uTFrYJLo3LmzW0/NrEG1mAQHcHJj1kj83TOzhtZiuqhy7XtBcU7EevbCg/I+vnz5coYNGwbA7Nmz2Wmnndhoo41YtmwZ7du3p1WrVkQEP/jBDxg1ahQAPXv2ZLvttmP16tX06NGD8ePH06pVKwB+97vfcf311/PGG29U/cPo2bMngwcP5oYbbgDg5ptv5oQTTuDNN9+kR48eX4on37Yr/fa3v6V79+5V8VQaNWoUL7zwAh06dGDTTTfl1ltvpVOnTut9jcaPH09FRQXnnXfeetctlsMeOLQo25l4+MM1PtbU3ttevXqxYMGCoux3pdz37owzzuDcc8+lS5d1rqVlZtYktagWnIbWsWNHJk+ezOTJk9ljjz24++67mTx5MltssQV3330306ZN4+GHH2b8+PE8+eSTALRq1YrJkyczdepU2rRpw2OPPVa1vYceeohBgwbx9NNPV5W1atWKd955h88++wyAe+65h7322qvaePJtuxBXX301Tz31FP379+e666770mOrV6+u1baau6b23pbalVde6eTGzJoVJziNrFOnTpx77rncdtttXypfs2YNH3zwAZVnuT3//PPssssunHbaadxyyy1fWvfggw/m4Ycf5t1336VNmzbrbVlZe9tTpkyhd+/eDB06lOnTp6835j333JO3336b8ePHM3z4cA4//HCuuuoqrr/+evr27Uvfvn0ZN25c1frTp09n6NCh9O7dm6lTpwIwZ84chgwZwqBBgxgxYgSffPLJeuttbhr6vT3zzDPZf//9Oe6441izZg3Lli1j8ODBDBw4kP79+/Pqq68CcPbZZ9OvXz8OOOAA7rzzTiBLXvfbbz/69etX1WKUa+DAgVRUVPDWW2+x1157cdxxx7Hnnnty5ZVXAlmL1ogRIxg8eDAjR47k7bervbComVmDcYLTBGyzzTYsWpRdoHn16tUMHDiQHj16sHr1ag46KOsGu/XWWxk5ciR9+vRh7ty5rFy5sur5Rx99NHfeeSd33nknI0aMqLaOfNs+66yzmDBhAhMnTqxqLcjnscceY5dddgHgww8/5P777+f444/nmmuuYerUqUydOpWrrrqKpUuXAtkp+g8++CD3338/Z555JgCnn34648aN429/+xv9+/fnxhtvrMMr1/Q11Hu7atUqRowYwVNPPcXGG2/MxIkT6dixI4888giTJ0/mvPPO46KLLgLgkUceYerUqTz55JMMHz6cefPm8eijjzJlyhSmTZvGuHHjeO+992qsa/HixYwdO5ZnnnmGq666CoDf//73fPe73+WJJ55gzJgxXHbZZfV+7czM6qNFjsFp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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "gap_22_prob = df_gap22_ram_prob['avgPktRespTimeWr'].astype(float)\n", - "gap_22_ram = df_gap22_ram['avgPktRespTimeWr'].astype(float)\n", - "gap_22_prob[len(gap_22_prob)] = statistics.geometric_mean(df_gap22_ram_prob['avgPktRespTimeWr'].astype(float))\n", - "gap_22_ram[len(gap_22_ram)] = statistics.geometric_mean(df_gap22_ram['avgPktRespTimeWr'].astype(float))\n", - "\n", - "\n", - "gap_25_prob = df_gap25_ram_prob['avgPktRespTimeWr'].astype(float)\n", - "gap_25_ram = df_gap25_ram['avgPktRespTimeWr'].astype(float)\n", - "gap_25_prob[len(gap_25_prob)] = statistics.geometric_mean(df_gap25_ram_prob['avgPktRespTimeWr'].astype(float))\n", - "gap_25_ram[len(gap_25_ram)] = statistics.geometric_mean(df_gap25_ram['avgPktRespTimeWr'].astype(float))\n", - "\n", - "npb_C_prob = df_npbC_ram_prob['avgPktRespTimeWr'].astype(float)\n", - "npb_C_ram = df_npbC_ram['avgPktRespTimeWr'].astype(float)\n", - "npb_C_prob[len(npb_C_prob)] = statistics.geometric_mean(df_npbC_ram_prob['avgPktRespTimeWr'].astype(float))\n", - "npb_C_ram[len(npb_C_ram)] = statistics.geometric_mean(df_npbC_ram['avgPktRespTimeWr'].astype(float))\n", - "\n", - "\n", - "\n", - "npb_D_prob = df_npbD_ram_prob['avgPktRespTimeWr'].astype(float)\n", - "npb_D_ram = df_npbD_ram['avgPktRespTimeWr'].astype(float)\n", - "npb_D_prob[len(npb_D_prob)] = statistics.geometric_mean(df_npbD_ram_prob['avgPktRespTimeWr'].astype(float))\n", - "npb_D_ram[len(npb_D_ram)] = statistics.geometric_mean(df_npbD_ram['avgPktRespTimeWr'].astype(float))\n", - "\n", - "################################## \n", - "# Multi bar Chart1\n", - "app_gap = df_gap22_ram_prob['app']\n", - "app_gap[len(app_gap)] = \"gmean\"\n", - "\n", - "app_npb = df_npbC_ram_prob['app']\n", - "app_npb[len(app_npb)] = \"gmean\"\n", - "\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,3)\n", - "plt.ylim([0,1000])\n", - "barWidth = 1\n", - "tickSize = 3\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*tickSize-barWidth/2, gap_22_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", - " plt.bar(i*tickSize+barWidth/2, gap_22_ram[i], width=barWidth, color=cmap(2), label='TDRAM-baseline' if i==0 else None)\n", - "\n", - "offset = i+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar((offset+i)*tickSize-barWidth/2, npb_C_prob[i], width=1, color=cmap(1))\n", - " plt.bar((offset+i)*tickSize+barWidth/2, npb_C_ram[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.25, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.7, -0.01, \"NPB-C\")\n", - "\n", - "brLab = np.arange(len(app_gap)+len(app_npb))\n", - "plt.xticks(brLab*tickSize, list(app_gap)+list(app_npb))\n", - "\n", - "plt.axvline(x=(offset-0.5)*tickSize, color='black')\n", - "# plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Avg Wr ORB Time (ns) (ns)\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()\n", - "\n", - "###############################################################################\n", - "# Multi bar Chart2\n", - "app_gap = df_gap25_ram_prob['app']\n", - "app_gap[len(app_gap)] = \"gmean\"\n", - "\n", - "app_npb = df_npbD_ram_prob['app']\n", - "app_npb[len(app_npb)] = \"gmean\"\n", - "\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,3)\n", - "plt.ylim([0,1000])\n", - "barWidth = 1\n", - "tickSize = 3\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*tickSize-barWidth/2, gap_25_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Probe' if i==0 else None)\n", - " plt.bar(i*tickSize+barWidth/2, gap_25_ram[i], width=barWidth, color=cmap(2), label='TDRAM-baseline' if i==0 else None)\n", - "\n", - "offset = i+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar((offset+i)*tickSize-barWidth/2, npb_D_prob[i], width=1, color=cmap(1))\n", - " plt.bar((offset+i)*tickSize+barWidth/2, npb_D_ram[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.25, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.70, -0.01, \"NPB-D\")\n", - "\n", - "brLab = np.arange(len(app_gap)+len(app_npb))\n", - "plt.xticks(brLab*tickSize, list(app_gap)+list(app_npb))\n", - "\n", - "plt.axvline(x=(offset-0.5)*tickSize, color='black')\n", - "# plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Avg Wr ORB time (ns)\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/tmp/ipykernel_308484/1314087200.py:35: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " app_gap[len(app_gap)] = \"gmean\"\n", - "/tmp/ipykernel_308484/1314087200.py:38: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " app_npb[len(app_npb)] = \"gmean\"\n", - "/tmp/ipykernel_308484/1314087200.py:72: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " app_gap[len(app_gap)] = \"gmean\"\n", - "/tmp/ipykernel_308484/1314087200.py:75: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " app_npb[len(app_npb)] = \"gmean\"\n" - ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAlkklEQVR4nO3de5xd873/8de7I8Ql4ri1mogZl1/rEhWGyAk1Ej2uoVUURUNRKnVrTlvlUD1OqVLyi5YTmqYqSBUVhPJTkYTSJIRIIg5CM6SHpJU0rUsun98fa+2xM2b2rJnZay573s/HYz9mr+9ae30/+7bms7/r+11fRQRmZmZmleQTnR2AmZmZWbk5wTEzM7OK4wTHzMzMKo4THDMzM6s4TnDMzMys4jjBMTMzs4qTW4IjaVtJj0uaL2mepPOa2KZO0nJJc9LbpXnFY2ZmZj3HejnuezXw7Yh4VlIfYLakRyNifqPtpkfEETnGYWZmZj1Mbi04EbEkIp5N7/8dWAD0y6s+MzMzs4I8W3AaSKoGBgHPNLF6iKTngbeA0RExr4nHnwmcCbDxxhvv9dnPfjbHaM0sq4ULFwLwmc98ppMjMbOeavbs2UsjYqvG5cp7qgZJmwBPAP8VEfc0WrcpsDYiVko6DBgTETuV2l9tbW3MmjUrv4DNLLO6ujoApk6d2qlxmFnPJWl2RNQ2Ls91FJWkXsDdwMTGyQ1ARKyIiJXp/SlAL0lb5hmTmZmZVb48R1EJ+AWwICJ+2sw2n0q3Q9I+aTzL8orJzMzMeoY8++AMBU4G5kqak5Z9HxgAEBE3AccAZ0taDbwHHB+e3tzMzMzaKbcEJyJmAGphmxuAG9pb16pVq6ivr+f9999v767MrBm9e/emf//+9OrVq7NDMTNrUYeMospbfX09ffr0obq6mvSMl5mVUUSwbNky6uvrqamp6exwzMxaVBFTNbz//vtsscUWTm7MciKJLbbYwq2kZtZtVESCAzi5McuZv2Nm1p1UxCmqYvte9vuy7Ofpyw9udt3y5cs56qijAJgzZw4777wzG2ywAUuXLqVPnz5UVVUREZxxxhmMHDkSgJqaGrbbbjvWrFlDdXU1EyZMoKqqCoAf/ehH3Hzzzbz22msN/0RqamoYPnw4t9xyCwC//vWvOeWUU1i0aBHV1dXrxFNq3wVXXHEF/fv3b4inYOTIkTz//PNsuummbLLJJkycOJHNNtusxddnwoQJ1NfXc8kll7S4bVsc+bvDy7KfyV98sNl1Xe193HHHHXnllVfK8rwLit+n888/n4svvpittvrY9bDMzCpOxbTgdKS+ffsydepUpk6dyh577MFdd93F1KlT2XLLLbnrrruYMWMGDz74IBMmTODxxx8HoKqqiqlTpzJ9+nR69erFI4880rC/Bx54gGHDhvHkk082lFVVVfHnP/+ZDz74AIDf/va37LXXXk3GU2rfWYwdO5YnnniCoUOHctNNN62zbs2aNa3aV3fS1d7HvF1//fVObsysx3CCk5PNNtuMiy++mNtvv32d8rVr1/Luu+9SGA3/3HPPseuuu3L22Wdz2223rbPtoYceyoMPPsjbb79Nr169WmxZabzvadOmMWjQIEaMGMEzzzQ1S8a69txzT9544w0mTJjAscceyxe/+EXGjBnDzTffzODBgxk8eDDjx49v2P6ZZ55hxIgRDBo0iOnTp2d5Wbqdjn4fL7jgAg444ABOOukk1q5dy9KlSxk+fDh1dXUMHTqUl19+GYDRo0czZMgQDjzwQCZNmgQkier+++/PkCFDGlqMitXV1VFfX8/rr7/OXnvtxUknncSee+7J9ddfDyQtWscddxzDhw9n2LBhZW9NMjPrSE5wcrTtttvy5ptvAklLSF1dHdXV1axZs4aDD05OgU2cOJGvfe1r1NbWMn/+fFatWtXw+OOPP55JkyYxadIkjjvuuGbraW7fF154Iffddx+TJ09uaEEo5ZFHHmHXXXcFYOXKldx7772cfPLJ3HDDDUyfPp3p06czZswY3nnnHSAZnn///fdz7733csEFF7TtReoGOup9XL16NccddxxPPPEEG264IZMnT6Zv37489NBDTJ06lUsuuYSrrroKgIceeojp06fz+OOPc+yxx7JgwQIefvhhpk2bxowZMxg/fjzLljV/zcwlS5Ywbtw4nnrqKcaMGQPAlVdeydFHH81jjz3Gddddx/e+9712v3ZmZp3FCU6OFi9eTL9+yQTqhVMbc+fO5Z133uHdd99l7dq13HfffVxxxRUccsghvP3220yZMqXh8dtssw0rV67kzjvvZMSIEQ3lN9xwA3V1dZx++unN7htgxYoVDBgwAEnss88+AMyYMYO6ujrq6upYuXIlAN/61rc44IADeO+99xr2ue+++yKJ1157jYEDB7L++uuz/vrrM3DgQBYtWgTA3nvvDUB1dTXLly/P8ZXsXB31Pha/T4MHD2bhwoW8++67nHTSSXz+85/n8ssvZ/HixQBcddVVnHbaaYwcOZIFCxbw4osvMn/+fA488ECGDx/OihUrGrZtys4778xGG21E7969G/oQzZ07lzFjxlBXV8d5553X8DkyM+uOKq6TcVexfPlyrrzyyo91wu3bty9nnXUWP/7xjzn44IM56qijuOaaawB49dVXueiiixo6vgKcc845zJ8/nw033LChbNSoUYwaNepjdRbv++qrr6ZPnz7U19fTv39/Zs6cyY477sh+++33sYkRx44dy3777bdOWeGfXk1NDS+88AIffvghkPwTrKmpYf78+cyePRuAP//5z2y66aZtfKW6to58HyOCWbNmMXjwYGbOnMkhhxzCbbfdxqBBg7jooouYMmUKP/3pT4kIDjroIEaMGMGMGTO49NJLufzyyxk0aBB33303kli1ahW9evVizpw5TT6vpkZE7brrrgwZMoQvfelLAA3vuZlZd+QEp8yOPfZYqqqqWLt2LaeddhrDhg372DbHH388AwcOZOnSpZx44okN5TvssAMLFixgxYoVDWWHHXYYhx12WOb6C/v+/ve/z7XXXsuIESP49Kc/TZ8+fdr0fLbeemu++c1vNiRAo0aNauioutFGG3H44Yfz1ltvcd1117Vp/11VZ7yP6623HnfffTff+c536NevH0ceeSQvvfQSJ554ItOmTWs4fbh69WoOPfRQILkG1KWXXspuu+3GQQcdxAEHHEBVVVXDKa7WuPjiiznrrLMYO3YsEcHhhx/O6NGjW7UPM7OuQt1t6qfa2tqYNWvWOmULFixg55137qSIzHqOxt+1uro6gI+1CpqZdRRJsyOitnG5++CYmZlZxXGCY2ZmZhWnYhKc7naqzay78XfMzLqTikhwevfuzbJly3wANstJYTbx3r17d3YoZmaZtDiKStJGwLeBARFxhqSdgM9ExAO5R5dR//79qa+vb7gAnZmVX+/evenfv39nh2FmlkmWYeK/BGYDQ9LlN4G7gC6T4PTq1YuamprODsPMzMy6iCynqHaIiKuBVQAR8U/g41cJMzMzM+sisiQ4H0raEAgASTsALU9sZGZmZtZJspyiugx4GNhW0kRgKDAyz6DMzMzM2qPFBCciHpX0LLAv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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAlhElEQVR4nO3de5xd873/8de7IySI5Li1KmLG5dG6RIUQOaFGonUNqiiKhqIuaV2ao1UO1ePUpW45ScsJTVN1S9UtCOWnIgmqSTSEBAehGdKStJKmbrl8fn+stcfOmNmzZmavuex5Px+P/Zi9vmvt9f3s25rP/q7v+n4VEZiZmZlVks90dABmZmZm5eYEx8zMzCqOExwzMzOrOE5wzMzMrOI4wTEzM7OK4wTHzMzMKk5uCY6kLSQ9LmmepBclndXINrWSlkqak94uyiseMzMz6z7WynHfK4HvR8SzknoDsyU9GhHzGmw3PSIOzjEOMzMz62Zya8GJiEUR8Wx6/5/AfGDzvOozMzMzK8izBaeepGpgIPBMI6uHSHoOeBsYHREvNvL4U4FTAdZbb71dv/jFL+YYrZll9fLLLwPwhS98oYMjMbPuavbs2YsjYpOG5cp7qgZJ6wNPAP8dEXc3WLcBsDoilks6EBgTEduW2t+gQYNi1qxZ+QVsZpnV1tYCMHXq1A6Nw8y6L0mzI2JQw/Jcr6KS1AO4C7i1YXIDEBHLImJ5en8K0EPSxnnGZGZmZpUvz6uoBPwSmB8R1zSxzefS7ZC0exrPkrxiMjMzs+4hzz44Q4HjgbmS5qRlPwL6A0TEDcARwOmSVgIfAEeHpzc3MzOzNsotwYmIGYCa2WYcMK6tda1YsYK6ujo+/PDDtu7KzJrQs2dP+vXrR48ePTo6FLOSDrn3oEzbTT7swZwjsY7ULldR5a2uro7evXtTXV1NesbLzMooIliyZAl1dXXU1NR0dDhmZs2qiKkaPvzwQzbaaCMnN2Y5kcRGG23kVlIz6zIqIsEBnNyY5czfMTPrSiriFFWxPS7+fVn288dL9mty3dKlSzn00EMBmDNnDttttx3rrLMOixcvpnfv3lRVVRERnHLKKYwcORKAmpoattxyS1atWkV1dTUTJ06kqqoKgJ/+9KfceOONvP766/X/RGpqahg+fDg33XQTAL/5zW844YQTWLBgAdXV1WvEU2rfBZdeein9+vWrj6dg5MiRPPfcc2ywwQasv/763HrrrfTt27fZ12fixInU1dVx4YUXNrtta2Q9h96cUufYO9v7uM022/Dqq6+W5XkXFL9PZ599NhdccAGbbPKp8bDMzCpOxbTgtKc+ffowdepUpk6dys4778ydd97J1KlT2XjjjbnzzjuZMWMGDz74IBMnTuTxxx8HoKqqiqlTpzJ9+nR69OjBI488Ur+/Bx54gGHDhvHkk0/Wl1VVVfGXv/yFjz76CIDf/e537Lrrro3GU2rfWYwdO5YnnniCoUOHcsMNN6yxbtWqVS3aV1fS2d7HvF133XVObsys23CCk5O+fftywQUXcNttt61Rvnr1at577z0KV8P/+c9/ZocdduD000/nlltuWWPbAw44gAcffJB33nmHHj16NNuy0nDf06ZNY+DAgYwYMYJnnmlslow17bLLLrz55ptMnDiRI488ksMOO4wxY8Zw4403MnjwYAYPHsyECRPqt3/mmWcYMWIEAwcOZPr06Vleli6nvd/Hc845h7333pvjjjuO1atXs3jxYoYPH05tbS1Dhw7llVdeAWD06NEMGTKEffbZh0mTJgFJorrXXnsxZMiQ+hajYrW1tdTV1fHGG2+w6667ctxxx7HLLrtw3XXXAUmL1lFHHcXw4cMZNmxY2VuTzMzakxOcHG2xxRa89dZbQNISUltbS3V1NatWrWK//ZJTYLfeeivf+ta3GDRoEPPmzWPFihX1jz/66KOZNGkSkyZN4qijjmqynqb2fe6553LfffcxefLk+haEUh555BF22GEHAJYvX84999zD8ccfz7hx45g+fTrTp09nzJgxvPvuu0Byef7999/PPffcwznnnNO6F6kLaK/3ceXKlRx11FE88cQT9OrVi8mTJ9OnTx8eeughpk6dyoUXXsjll18OwEMPPcT06dN5/PHHOfLII5k/fz4PP/ww06ZNY8aMGUyYMIElS5oeM3PRokWMHz+ep556ijFjxgBw2WWXcfjhh/PYY49x7bXX8sMf/rDNr52ZWUdxgpOjhQsXsvnmyQTqhVMbc+fO5d133+W9995j9erV3HfffVx66aXsv//+vPPOO0yZMqX+8ZttthnLly/njjvuYMSIEfXl48aNo7a2lpNPPrnJfQMsW7aM/v37I4ndd98dgBkzZlBbW0ttbS3Lly8H4Lvf/S577703H3zwQf0+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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "gap_22_prob = df_gap22_ram_prob['simSeconds'].astype(float)/df_gap22_noDC['simSeconds'].astype(float)\n", - "gap_22_ram = df_gap22_ram['simSeconds'].astype(float)/df_gap22_noDC['simSeconds'].astype(float)\n", - "geo_meanC = df_gap22_ram_prob['simSeconds'].astype(float)/df_gap22_noDC['simSeconds'].astype(float)\n", - "geo_meanR = df_gap22_ram['simSeconds'].astype(float)/df_gap22_noDC['simSeconds'].astype(float)\n", - "gap_22_prob[len(gap_22_prob)] = statistics.geometric_mean(geo_meanC)\n", - "gap_22_ram[len(gap_22_ram)] = statistics.geometric_mean(geo_meanR)\n", - "\n", - "\n", - "gap_25_prob = df_gap25_ram_prob['simSeconds'].astype(float)/df_gap25_noDC['simSeconds'].astype(float)\n", - "gap_25_ram = df_gap25_ram['simSeconds'].astype(float)/df_gap25_noDC['simSeconds'].astype(float)\n", - "geo_meanC = df_gap25_ram_prob['simSeconds'].astype(float)/df_gap25_noDC['simSeconds'].astype(float)\n", - "geo_meanR = df_gap25_ram['simSeconds'].astype(float)/df_gap25_noDC['simSeconds'].astype(float)\n", - "gap_25_prob[len(gap_25_prob)] = statistics.geometric_mean(geo_meanC)\n", - "gap_25_ram[len(gap_25_ram)] = statistics.geometric_mean(geo_meanR)\n", - "\n", - "npb_C_prob = df_npbC_ram_prob['simSeconds'].astype(float)/df_npbC_noDC['simSeconds'].astype(float)\n", - "npb_C_ram = df_npbC_ram['simSeconds'].astype(float)/df_npbC_noDC['simSeconds'].astype(float)\n", - "geo_meanC = df_npbC_ram_prob['simSeconds'].astype(float)/df_npbC_noDC['simSeconds'].astype(float)\n", - "geo_meanR = df_npbC_ram['simSeconds'].astype(float)/df_npbC_noDC['simSeconds'].astype(float)\n", - "npb_C_prob[len(npb_C_prob)] = statistics.geometric_mean(geo_meanC)\n", - "npb_C_ram[len(npb_C_ram)] = statistics.geometric_mean(geo_meanR)\n", - "\n", - "\n", - "\n", - "npb_D_prob = df_npbD_ram_prob['simSeconds'].astype(float)/df_npbD_noDC['simSeconds'].astype(float)\n", - "npb_D_ram = df_npbD_ram['simSeconds'].astype(float)/df_npbD_noDC['simSeconds'].astype(float)\n", - "geo_mean = df_npbD_ram_prob['simSeconds'].astype(float)/df_npbD_noDC['simSeconds'].astype(float)\n", - "geo_mean = df_npbD_ram['simSeconds'].astype(float)/df_npbD_noDC['simSeconds'].astype(float)\n", - "npb_D_prob[len(npb_D_prob)] = statistics.geometric_mean(geo_meanC)\n", - "npb_D_ram[len(npb_D_ram)] = statistics.geometric_mean(geo_meanR)\n", - "\n", - "################################## \n", - "# Multi bar Chart1\n", - "app_gap = df_gap22_ram_prob['app']\n", - "app_gap[len(app_gap)] = \"gmean\"\n", - "\n", - "app_npb = df_npbC_ram_prob['app']\n", - "app_npb[len(app_npb)] = \"gmean\"\n", - "\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,3)\n", - "plt.ylim([0,2.5])\n", - "barWidth = 1\n", - "tickSize = 3\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*tickSize-barWidth/2, gap_22_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", - " plt.bar(i*tickSize+barWidth/2, gap_22_ram[i], width=barWidth, color=cmap(2), label='TDRAM-baseline' if i==0 else None)\n", - "\n", - "offset = i+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar((offset+i)*tickSize-barWidth/2, npb_C_prob[i], width=1, color=cmap(1))\n", - " plt.bar((offset+i)*tickSize+barWidth/2, npb_C_ram[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.25, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.7, -0.01, \"NPB-C\")\n", - "\n", - "brLab = np.arange(len(app_gap)+len(app_npb))\n", - "plt.xticks(brLab*tickSize, list(app_gap)+list(app_npb))\n", - "\n", - "plt.axvline(x=(offset-0.5)*tickSize, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Normalized Execution Time\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()\n", - "\n", - "###############################################################################\n", - "# Multi bar Chart2\n", - "app_gap = df_gap25_ram_prob['app']\n", - "app_gap[len(app_gap)] = \"gmean\"\n", - "\n", - "app_npb = df_npbD_ram_prob['app']\n", - "app_npb[len(app_npb)] = \"gmean\"\n", - "\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,3)\n", - "plt.ylim([0,2.5])\n", - "barWidth = 1\n", - "tickSize = 3\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*tickSize-barWidth/2, gap_25_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", - " plt.bar(i*tickSize+barWidth/2, gap_25_ram[i], width=barWidth, color=cmap(2), label='TDRAM-baseline' if i==0 else None)\n", - "\n", - "offset = i+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar((offset+i)*tickSize-barWidth/2, npb_D_prob[i], width=1, color=cmap(1))\n", - " plt.bar((offset+i)*tickSize+barWidth/2, npb_D_ram[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.25, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.70, -0.01, \"NPB-D\")\n", - "\n", - "brLab = np.arange(len(app_gap)+len(app_npb))\n", - "plt.xticks(brLab*tickSize, list(app_gap)+list(app_npb))\n", - "\n", - "plt.axvline(x=(offset-0.5)*tickSize, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Normalized Execution Time\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAfFElEQVR4nO3debxVdb3/8de7I4oggwMaigqS15ESPU5XzKNWThHaT8zhqphDmpbDtSzrFw38SiuvebWLDzHDFBOHEBUv6TVOoiUKKoKgZeAAoUAFXhJF4fP7Y30Pbo77bM60Bxbv5+NxHnuv71p7r/fZwzqfs9Z3ra8iAjMzM7M8+Ui1A5iZmZl1Nhc4ZmZmljsucMzMzCx3XOCYmZlZ7rjAMTMzs9xxgWNmZma5U7YCR9ItkhZLml3QtpWkRyT9Od1umdol6T8lvSzpeUn7liuXmZmZ5V859+CMBY5u1vYN4NGI2BV4NE0DHAPsmn7OA0aXMZeZmZnlXNkKnIh4DPh7s+ZhwK3p/q3A8QXtv4rMk0BvSX3Llc3MzMzybZMKr2+7iFiU7r8BbJfu7wC8XrDcgtS2iGYknUe2l4fu3bvvt/vuu5cvrZl9yEsvvQTAbrvtVuUkZmYwY8aMpRHRp3l7pQuctSIiJLV5nIiIuAm4CaC+vj6mT5/e6dnMrGUNDQ0ANDY2VjWHmRmApFeLtVf6LKo3mw49pdvFqX0hsGPBcv1Sm5mZmVmbVbrAuR84M90/E5hY0H5GOpvqIGB5waEsMzMzszYp2yEqSb8GGoBtJC0ARgJXAXdJOht4FTgpLf4QcCzwMvA2cFa5cpmZmVn+la3AiYhTWph1ZJFlA7iwM9a7bNkyFi3yzp9a07dvX3r37l3tGGZmtpGoWifjclm6dCn9+/dn8803r3YUS1auXMnChQtd4JiZWcXkbqiG9957j65du1Y7hhXo2rUr7733XrVjmJnZRiR3BQ6ApGpHsAJ+P8zMrNJyd4iq0EEjf9spz/Pk945qcd7y5csZNmwYAM899xx77LEHm222GUuXLqVHjx7U1dUREZx77rmMGDECgAEDBrDzzjuzevVq+vfvz9ixY6mrqwPghz/8IWPGjGHevHlrC4MBAwZw5JFHcvPNNwNw2223ccYZZzB//nz69++/Tp5Sz91k1KhR9OvXb22eJiNGjGDmzJn07NmTLbbYgnHjxrXqsNLYsWNZsGAB3/72t9e7rJmZWSXkcg9OJfXq1YvGxkYaGxvZZ599uPvuu2lsbGSbbbbh7rvv5vHHH2fSpEmMHTuWKVOmAFBXV0djYyNTp06lS5cuPPzww2uf78EHH+SII47giSeeWNtWV1fHa6+9xrvvvgvAPffcw3777Vc0T6nnbo3rr7+e3//+9xxyyCHceOON68xbvXp1m57LzMysWlzgVEDv3r351re+xR133LFO+5o1a1i2bBnZSWTw7LPPstdee3HBBRdw++23r7PsMcccw6RJk1i8eDFdunRZ756V5s/92GOPMXjwYIYOHcq0adPWm3nffffl1VdfZezYsQwfPpzjjz+e6667jjFjxnDggQdy4IEHcsstt6xdftq0aQwdOpTBgwczderU1rwsZmZmZeMCp0J23HFHFi7MLs68evVqGhoa6N+/P6tXr+aoo7JDYOPGjePMM8+kvr6eOXPmrNMx9+STT2b8+PGMHz+ek046qeg6Sj33ZZddxsSJE7n//vvX7gkq5eGHH2avvfYCYMWKFUyYMIHTTz+dG264galTpzJ16lSuu+46lixZAmSdux944AEmTJjApZde2r4XyczMrJO4wKmQ119/nR122AH44DDSrFmzWLJkCcuWLWPNmjVMnDiRUaNGcfTRR7N48WIeeuihtY/v27cvK1as4M4772To0KFr22+44QYaGho455xzWnxugLfeeouddtoJSRxwwAEAPP744zQ0NNDQ0MCKFSsA+MpXvsJhhx3GypUr1z7nQQcdhCTmzZvHoEGD2HTTTdl0000ZNGgQ8+fPB2D//fcHoH///ixfvryMr6SZmdn6ucCpgOXLl/OjH/2IU05Z99qHvXr14vzzz+fqq69mypQpDBs2jMmTJzN58mQmTZrEuHHj1ln+wgsv5IQTTljnGj8XXXQRjY2NazsgF3tugB49erBgwQIAnn76aQCGDBmytv/QFltsAXzQB2f06NFrT7dv6qQ8YMAAnn/+eVatWsWqVauYNWsWAwYMAGDGjBkAvPbaa/Ts2bPjL5qZmVkH5PosqmobPnw4dXV1rFmzhi9+8YscccQRH1rm5JNPZtCgQSxdupRTTz11bfvAgQOZO3cub7311tq2Y489lmOPPbbV62967iuvvJJrrrmGoUOHsv3229OjR492/T7bbrstX/7ylxkyZAiQFVd9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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "gap_22_prob = 100* df_gap22_ram_prob['actDelayedDueToTagAct'].astype(float)/(df_gap22_ram_prob['numTotMisses'].astype(float)+df_gap22_ram_prob['numTotHits'].astype(float))\n", - "#gap_22_prob[len(gap_22_prob)] = statistics.geometric_mean(df_gap22_ram_prob['actDelayedDueToTagAct'].astype(float))\n", - "\n", - "\n", - "gap_25_prob = 100* df_gap25_ram_prob['actDelayedDueToTagAct'].astype(float)/(df_gap25_ram_prob['numTotMisses'].astype(float)+df_gap25_ram_prob['numTotHits'].astype(float))\n", - "#gap_25_prob[len(gap_25_prob)] = statistics.geometric_mean(df_gap25_ram_prob['actDelayedDueToTagAct'].astype(float))\n", - "\n", - "npb_C_prob = 100* df_npbC_ram_prob['actDelayedDueToTagAct'].astype(float)/(df_npbC_ram_prob['numTotMisses'].astype(float)+df_npbC_ram_prob['numTotHits'].astype(float))\n", - "#npb_C_prob[len(npb_C_prob)] = statistics.geometric_mean(df_npbC_ram_prob['actDelayedDueToTagAct'].astype(float))\n", - "\n", - "\n", - "\n", - "npb_D_prob = 100* df_npbD_ram_prob['actDelayedDueToTagAct'].astype(float)/(df_npbD_ram_prob['numTotMisses'].astype(float)+df_npbD_ram_prob['numTotHits'].astype(float))\n", - "#npb_D_prob[len(npb_D_prob)] = statistics.geometric_mean(df_npbD_ram_prob['actDelayedDueToTagAct'].astype(float))\n", - "\n", - "################################## \n", - "# Multi bar Chart1\n", - "app_gap = df_gap22_ram_prob['app']\n", - "#app_gap[len(app_gap)] = \"gmean\"\n", - "\n", - "app_npb = df_npbC_ram_prob['app']\n", - "#app_npb[len(app_npb)] = \"gmean\"\n", - "\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,3)\n", - "plt.ylim([0,100])\n", - "barWidth = 1\n", - "tickSize = 2\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*tickSize-barWidth/2, gap_22_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", - "\n", - "offset = i+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar((offset+i)*tickSize-barWidth/2, npb_C_prob[i], width=1, color=cmap(1))\n", - "\n", - "plt.figtext(0.25, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.7, -0.01, \"NPB-C\")\n", - "\n", - "brLab = np.arange(len(app_gap)+len(app_npb))\n", - "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", - "\n", - "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", - "# plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"ACT delayed (%)\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()\n", - "\n", - "###############################################################################\n", - "# Multi bar Chart2\n", - "app_gap = df_gap25_ram_prob['app']\n", - "#app_gap[len(app_gap)] = \"gmean\"\n", - "\n", - "app_npb = df_npbD_ram_prob['app']\n", - "#app_npb[len(app_npb)] = \"gmean\"\n", - "\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,3)\n", - "plt.ylim([0,100])\n", - "barWidth = 1\n", - "tickSize = 2\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*tickSize-barWidth/2, gap_25_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Probe' if i==0 else None)\n", - "offset = i+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar((offset+i)*tickSize-barWidth/2, npb_D_prob[i], width=1, color=cmap(1))\n", - "\n", - "plt.figtext(0.25, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.70, -0.01, \"NPB-D\")\n", - "\n", - "brLab = np.arange(len(app_gap)+len(app_npb))\n", - "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", - "\n", - "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", - "# plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"ACT delayed (%)\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "x1 = df_gap22_ram_prob['app']\n", - "y1 = 100 * df_gap22_ram_prob['noCandidBSlot'].astype(float)/(df_gap22_ram_prob['locMemReadBursts'].astype(float)+df_gap22_ram_prob['locMemWriteBursts'].astype(float))\n", - "y2 = 100 * df_gap22_ram_prob['foundCandidBSlotRH'].astype(float)/(df_gap22_ram_prob['locMemReadBursts'].astype(float)+df_gap22_ram_prob['locMemWriteBursts'].astype(float))\n", - "y3 = 100 * df_gap22_ram_prob['foundCandidBSlotRMC'].astype(float)/(df_gap22_ram_prob['locMemReadBursts'].astype(float)+df_gap22_ram_prob['locMemWriteBursts'].astype(float))\n", - "y4 = 100 * df_gap22_ram_prob['foundCandidBSlotRMD'].astype(float)/(df_gap22_ram_prob['locMemReadBursts'].astype(float)+df_gap22_ram_prob['locMemWriteBursts'].astype(float))\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(6,3)\n", - "plt.ylim([0,110])\n", - "\n", - "for i,app in enumerate(x1): \n", - " plt.bar(i*4, y1[i], width=3, color=cmap(1), label='Not Probed' if i==0 else None)\n", - " plt.bar(i*4, y2[i], bottom = y1[i], width=3, color=cmap(2), label='Read-Hit' if i==0 else None)\n", - " plt.bar(i*4, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3), label='Read-MC' if i==0 else None)\n", - " plt.bar(i*4, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4), label='Read-MD' if i==0 else None)\n", - "\n", - "offset = (i+1)*4\n", - "x2 = df_npbC_ram_prob['app']\n", - "y1 = 100 * df_npbC_ram_prob['noCandidBSlot'].astype(float)/(df_npbC_ram_prob['locMemReadBursts'].astype(float)+df_npbC_ram_prob['locMemWriteBursts'].astype(float))\n", - "y2 = 100 * df_npbC_ram_prob['foundCandidBSlotRH'].astype(float)/(df_npbC_ram_prob['locMemReadBursts'].astype(float)+df_npbC_ram_prob['locMemWriteBursts'].astype(float))\n", - "y3 = 100 * df_npbC_ram_prob['foundCandidBSlotRMC'].astype(float)/(df_npbC_ram_prob['locMemReadBursts'].astype(float)+df_npbC_ram_prob['locMemWriteBursts'].astype(float))\n", - "y4 = 100 * df_npbC_ram_prob['foundCandidBSlotRMD'].astype(float)/(df_npbC_ram_prob['locMemReadBursts'].astype(float)+df_npbC_ram_prob['locMemWriteBursts'].astype(float))\n", - "\n", - "for i,app in enumerate(x2): \n", - " plt.bar(i*4+offset, y1[i], width=3, color=cmap(1))\n", - " plt.bar(i*4+offset, y2[i], bottom = y1[i], width=3, color=cmap(2))\n", - " plt.bar(i*4+offset, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3))\n", - " plt.bar(i*4+offset, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*4, list(x1)+list(x2))\n", - "plt.axvline(x=offset-2, color='black')\n", - "plt.axhline(y=100, color='gray')\n", - "\n", - "plt.ylabel(\"Breakdown of B slots probing (%)\", fontsize=10)\n", - "plt.legend(fontsize=9, ncol=2, loc='lower right')\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_mpki.pdf\")\n", - "\n", - "x1 = df_gap25_ram_prob['app']\n", - "y1 = 100 * df_gap25_ram_prob['noCandidBSlot'].astype(float)/(df_gap25_ram_prob['locMemReadBursts'].astype(float)+df_gap25_ram_prob['locMemWriteBursts'].astype(float))\n", - "y2 = 100 * df_gap25_ram_prob['foundCandidBSlotRH'].astype(float)/(df_gap25_ram_prob['locMemReadBursts'].astype(float)+df_gap25_ram_prob['locMemWriteBursts'].astype(float))\n", - "y3 = 100 * df_gap25_ram_prob['foundCandidBSlotRMC'].astype(float)/(df_gap25_ram_prob['locMemReadBursts'].astype(float)+df_gap25_ram_prob['locMemWriteBursts'].astype(float))\n", - "y4 = 100 * df_gap25_ram_prob['foundCandidBSlotRMD'].astype(float)/(df_gap25_ram_prob['locMemReadBursts'].astype(float)+df_gap25_ram_prob['locMemWriteBursts'].astype(float))\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(6,3)\n", - "plt.ylim([0,110])\n", - "for i,app in enumerate(x1): \n", - " plt.bar(i*4, y1[i], width=3, color=cmap(1), label='Not Probed' if i==0 else None)\n", - " plt.bar(i*4, y2[i], bottom = y1[i], width=3, color=cmap(2), label='Read-Hit' if i==0 else None)\n", - " plt.bar(i*4, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3), label='Read-MC' if i==0 else None)\n", - " plt.bar(i*4, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4), label='Read-MD' if i==0 else None)\n", - "\n", - "offset = (i+1)*4\n", - "x2 = df_npbD_ram_prob['app']\n", - "y1 = 100 * df_npbD_ram_prob['noCandidBSlot'].astype(float)/(df_npbD_ram_prob['locMemReadBursts'].astype(float)+df_npbD_ram_prob['locMemWriteBursts'].astype(float))\n", - "y2 = 100 * df_npbD_ram_prob['foundCandidBSlotRH'].astype(float)/(df_npbD_ram_prob['locMemReadBursts'].astype(float)+df_npbD_ram_prob['locMemWriteBursts'].astype(float))\n", - "y3 = 100 * df_npbD_ram_prob['foundCandidBSlotRMC'].astype(float)/(df_npbD_ram_prob['locMemReadBursts'].astype(float)+df_npbD_ram_prob['locMemWriteBursts'].astype(float))\n", - "y4 = 100 * df_npbD_ram_prob['foundCandidBSlotRMD'].astype(float)/(df_npbD_ram_prob['locMemReadBursts'].astype(float)+df_npbD_ram_prob['locMemWriteBursts'].astype(float))\n", - "\n", - "for i,app in enumerate(x2): \n", - " plt.bar(i*4+offset, y1[i], width=3, color=cmap(1))\n", - " plt.bar(i*4+offset, y2[i], bottom = y1[i], width=3, color=cmap(2))\n", - " plt.bar(i*4+offset, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3))\n", - " plt.bar(i*4+offset, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*4, list(x1)+list(x2))\n", - "plt.axvline(x=offset-2, color='black')\n", - "plt.axhline(y=100, color='gray')\n", - "\n", - "plt.ylabel(\"Breakdown of B slots probing (%)\", fontsize=10)\n", - "plt.legend(fontsize=9, ncol=2, loc='lower right')\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/tmp/ipykernel_308484/3451258688.py:35: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " app_gap[len(app_gap)] = \"gmean\"\n", - "/tmp/ipykernel_308484/3451258688.py:38: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " app_npb[len(app_npb)] = \"gmean\"\n", - "/tmp/ipykernel_308484/3451258688.py:70: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " app_gap[len(app_gap)] = \"gmean\"\n", - "/tmp/ipykernel_308484/3451258688.py:73: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " app_npb[len(app_npb)] = \"gmean\"\n" - ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAfB0lEQVR4nO3de7xUdb3/8de7LYoKSiKWgbjR/KkZhroVPVputX7eIrK8YP1ULCWvpWank5ZmxzJ/HY/HIwWpcSjFS94ShWP6KLeCJQEGIhAexQtbLQETJC/cPuePtWY7jPsye+9Ze2DN+/l47MfM+s531ue71qxZ+zPfdfkqIjAzMzPLkw9UuwFmZmZmleYEx8zMzHLHCY6ZmZnljhMcMzMzyx0nOGZmZpY7TnDMzMwsdzJLcCTtJOkRSQskzZf0jVbqNEpaIWlO+ndZVu0xMzOz2rFZhvNeC3wzIp6U1BeYLenhiFhQUm9aRHw2w3aYmZlZjcmsByciXo2IJ9PnbwILgYFZxTMzMzMryLIHp4WkemAfYEYrLx8kaS7wCnBxRMxv5f1jgDEAW2+99X577LFHhq01s3ItWrQIgN13373KLTGzWjV79uxlETGgtFxZD9UgqQ/wKPDDiLin5LVtgPURsUrSMcB1EbFbe/NraGiIWbNmZddgMytbY2MjAE1NTVVth5nVLkmzI6KhtDzTq6gk9QLuBiaVJjcAEbEyIlalz6cCvSRtn2WbzMzMLP+yvIpKwC+AhRHx723U+XBaD0kHpO1ZnlWbzMzMrDZkeQ7OwcApwDxJc9KyS4DBABExHjgeOFvSWuBtYFR4eHMzMzPrpswSnIiYDqiDOmOBsd2NtWbNGpqbm3nnnXe6OyuroN69ezNo0CB69epV7aaYmVmN6ZGrqLLW3NxM3759qa+vJz3iZVUWESxfvpzm5maGDBlS7eaYmVmNycVQDe+88w79+/d3crMRkUT//v3dq2ZmZlWRiwQHcHKzEfJnYmZm1ZKLQ1TFDrz8txWZzxNXHNnmaytWrGDkyJEAzJkzhz333JMtttiCZcuW0bdvX+rq6ogIzjzzTEaPHg3AkCFD2HnnnVm3bh319fVMnDiRuro6AH70ox9x4403snjx4pakYMiQIRxxxBHcdNNNANx8882ceuqpPP/889TX12/QnvbmXXDllVcyaNCglvYUjB49mrlz57LNNtvQp08fJk2aRL9+/TpcPxMnTqS5uZnvfve7HdY1MzPrabnpwelJ2267LU1NTTQ1NTFs2DDuvPNOmpqa2H777bnzzjuZPn06U6ZMYeLEiTzyyCMA1NXV0dTUxLRp0+jVqxcPPfRQy/weeOABDj/8cB5//PGWsrq6Ol566SXeffddAO666y7222+/VtvT3rzLcf311/Poo49y8MEHM378+A1eW7duXafmZWZmtjFwgpORfv36cemll3LrrbduUL5+/XreeOMNClfD//nPf2avvfbi7LPP5pZbbtmg7tFHH82UKVN47bXX6NWrV4c9K6Xzfuyxx9hnn30YMWIEM2a0NkrGhvbdd19efPFFJk6cyAknnMDnP/95rrvuOm688UaGDx/O8OHDmTBhQkv9GTNmMGLECPbZZx+mTZtWzmoxMzPrEU5wMrTTTjvx8ssvA0lPSGNjI/X19axbt44jj0wOgU2aNInTTjuNhoYGFixYwJo1a1reP2rUKO644w7uuOMOTjzxxDbjtDXviy66iPvuu4/Jkye39AS156GHHmKvvfYCYNWqVdx7772ccsopjB07lmnTpjFt2jSuu+46li5dCiSX599///3ce++9XHjhhV1bSWZmZhlwgpOhJUuWMHBgMoB64TDSvHnzWLp0KW+88Qbr16/nvvvu48orr+Soo47itddeY+rUqS3v33HHHVm1ahW33347I0aMaCkfO3YsjY2NnHHGGW3OG2DlypUMHjwYSRxwwAEATJ8+ncbGRhobG1m1ahUA559/Poceeihvv/12yzwPPPBAJLF48WKGDh3K5ptvzuabb87QoUN5/vnnAdh///0BqK+vZ8WKFRmuSTMzs85xgpORFStWcNVVV3HyySdvUL7tttty1llncfXVV/PII48wcuRIHnzwQR588EGmTJnCpEmTNqh/7rnnctxxx7Hlllu2lJ133nk0NTW1nIDc2rwB+vbtS3NzMwAzZ84E4JBDDmk5f6hPnz7Ae+fgjBs3jt69ewO0nKQ8ZMgQnnrqKVavXs3q1auZN29ey31tZs+eDcBLL73ENtts0/2VZmZmViG5u4qq2k444QTq6upYv349X/nKVzj88MPfV2fUqFEMHTqUZcuW8aUvfamlfNddd2XhwoWsXLmypeyYY47hmGOOKTt+Yd6XXHIJ11xzDSNGjOAjH/kIffv27dLy7LDD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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAfDElEQVR4nO3de5xVdb3/8de7cRAVlFQ8GaiD5kONKNTxdrSa9PjzFpHlBeqoWEpeS81TJ63Ifnbx5zGORzqQGodSvOQtUcjLoxwFS+ISiEB0FC+MWgImSKLcPr8/1trjZpzLZmav2cPa7+fjMY+919rfvT6ftfbaaz573b6KCMzMzMzy5H2VTsDMzMys3FzgmJmZWe64wDEzM7PccYFjZmZmueMCx8zMzHLHBY6ZmZnlTmYFjqQ9JD0maZGkhZK+1kqbBkmrJM1L/76bVT5mZmZWPbbJcNobgK9HxFxJfYE5kh6NiEUt2k2PiE9nmIeZmZlVmcz24ETEqxExN33+JrAYGJBVPDMzM7OCLPfgNJNUBxwIzGzl5SMkzQdeAS6PiIWtvH80MBpghx12OHj//ffPMFszK9WSJUsA2G+//SqciZlVqzlz5qyIiP4txyvrrhok9QEeB34QEfe2eG1HYFNErJF0InB9ROzb3vTq6+tj9uzZ2SVsZiVraGgAoLGxsaJ5mFn1kjQnIupbjs/0KipJtcA9wOSWxQ1ARKyOiDXp82lAraRds8zJzMzM8i/Lq6gE/BxYHBE/aaPNB9J2SDo0zWdlVjmZmZlZdcjyHJwjgTOABZLmpeOuAPYEiIgJwCnA+ZI2AGuBEeHuzc3MzKyLMitwImIGoA7ajAPGdTXW+vXraWpq4u233+7qpKyMevfuzcCBA6mtra10KmZmVmW65SqqrDU1NdG3b1/q6upIj3hZhUUEK1eupKmpiUGDBlU6HTMzqzK56Krh7bffZpdddnFx04NIYpdddvFeNTMzq4hcFDiAi5seyJ+JmZlVSi4OURU7fMzDZZnOU1cd1+Zrq1atYvjw4QDMmzePAw44gG233ZYVK1bQt29fampqiAjOPfdcRo0aBcCgQYPYa6+92LhxI3V1dUyaNImamhoAfvjDH3LTTTexdOnS5qJg0KBBHHPMMdx8880A3HLLLZx55pk8//zz1NXVbZZPe9MuuPrqqxk4cGBzPgWjRo1i/vz57LjjjvTp04fJkyfTr1+/DpfPpEmTaGpq4tvf/naHbc3MzLpbbvbgdKeddtqJxsZGGhsbGTp0KHfddReNjY3suuuu3HXXXcyYMYOpU6cyadIkHnvsMQBqampobGxk+vTp1NbW8sgjjzRP78EHH+Too4/mySefbB5XU1PDSy+9xDvvvAPA3XffzcEHH9xqPu1NuxQ33HADjz/+OEceeSQTJkzY7LWNGzdu0bTMzMx6Ahc4GenXrx9XXnklt91222bjN23axBtvvEHhavg//elPDB48mPPPP59bb711s7YnnHACU6dO5bXXXqO2trbDPSstp/3EE09w4IEHMmzYMGbObK2XjM0ddNBBvPjii0yaNIlTTz2Vz372s1x//fXcdNNNHHbYYRx22GFMnDixuf3MmTMZNmwYBx54INOnTy9lsZiZmXULFzgZ2mOPPXj55ZeBZE9IQ0MDdXV1bNy4keOOSw6BTZ48mbPOOov6+noWLVrE+vXrm98/YsQI7rzzTu68805OO+20NuO0Ne3LLruM+++/nylTpjTvCWrPI488wuDBgwFYs2YN9913H2eccQbjxo1j+vTpTJ8+neuvv57ly5cDyeX5DzzwAPfddx+XXnpp5xaSmZlZBlzgZGjZsmUMGJB0oF44jLRgwQKWL1/OG2+8waZNm7j//vu5+uqrOf7443nttdeYNm1a8/t333131qxZwx133MGwYcOax48bN46GhgbOOeecNqcNsHr1avbcc08kceihhwIwY8YMGhoaaGhoYM2aNQBcfPHFfPKTn2Tt2rXN0zz88MORxNKlSxkyZAi9evWiV69eDBkyhOeffx6AQw45BIC6ujpWrVqV4ZI0MzPbMi5wMrJq1Sp+9KMfMXLkyM3G77TTTpx33nlcc801PPbYYwwfPpyHHnqIhx56iKlTpzJ58uTN2l944YWcfPLJbLfdds3jLrroIhobG5tPQG5t2gB9+/alqakJgFmzZgFw1FFHNZ8/1KdPH+Ddc3DGjx9P7969AZpPUh40aBBPP/0069atY926dSxYsKD5vjZz5swB4KWXXmLHHXfs+kIzMzMrk9xdRVVpp556KjU1NWzatIkvfelLHH300e9pM2LECIYMGcKKFSv4whe+0Dx+n332YfHixaxevbp53IknnsiJJ55YcvzCtK+44gquu+46hg0bxgc/+EH69u3bqfnZbbfd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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "gap_22_prob = df_gap22_ram_prob['simSeconds'].astype(float)\n", - "gap_22_ram = df_gap22_ram['simSeconds'].astype(float)\n", - "geo_meanC = df_gap22_ram_prob['simSeconds'].astype(float)\n", - "geo_meanR = df_gap22_ram['simSeconds'].astype(float)\n", - "gap_22_prob[len(gap_22_prob)] = statistics.geometric_mean(geo_meanC)\n", - "gap_22_ram[len(gap_22_ram)] = statistics.geometric_mean(geo_meanR)\n", - "\n", - "\n", - "gap_25_prob = df_gap25_ram_prob['simSeconds'].astype(float)\n", - "gap_25_ram = df_gap25_ram['simSeconds'].astype(float)\n", - "geo_meanC = df_gap25_ram_prob['simSeconds'].astype(float)\n", - "geo_meanR = df_gap25_ram['simSeconds'].astype(float)\n", - "gap_25_prob[len(gap_25_prob)] = statistics.geometric_mean(geo_meanC)\n", - "gap_25_ram[len(gap_25_ram)] = statistics.geometric_mean(geo_meanR)\n", - "\n", - "npb_C_prob = df_npbC_ram_prob['simSeconds'].astype(float)\n", - "npb_C_ram = df_npbC_ram['simSeconds'].astype(float)\n", - "geo_meanC = df_npbC_ram_prob['simSeconds'].astype(float)\n", - "geo_meanR = df_npbC_ram['simSeconds'].astype(float)\n", - "npb_C_prob[len(npb_C_prob)] = statistics.geometric_mean(geo_meanC)\n", - "npb_C_ram[len(npb_C_ram)] = statistics.geometric_mean(geo_meanR)\n", - "\n", - "\n", - "\n", - "npb_D_prob = df_npbD_ram_prob['simSeconds'].astype(float)\n", - "npb_D_ram = df_npbD_ram['simSeconds'].astype(float)\n", - "geo_mean = df_npbD_ram_prob['simSeconds'].astype(float)\n", - "geo_mean = df_npbD_ram['simSeconds'].astype(float)\n", - "npb_D_prob[len(npb_D_prob)] = statistics.geometric_mean(geo_meanC)\n", - "npb_D_ram[len(npb_D_ram)] = statistics.geometric_mean(geo_meanR)\n", - "\n", - "################################## \n", - "# Multi bar Chart1\n", - "app_gap = df_gap22_ram_prob['app']\n", - "app_gap[len(app_gap)] = \"gmean\"\n", - "\n", - "app_npb = df_npbC_ram_prob['app']\n", - "app_npb[len(app_npb)] = \"gmean\"\n", - "\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,3)\n", - "plt.ylim([0,2.5])\n", - "barWidth = 1\n", - "tickSize = 2\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*tickSize-barWidth/2, gap_22_ram[i]/gap_22_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", - "\n", - "offset = i+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar((offset+i)*tickSize-barWidth/2, npb_C_ram[i]/npb_C_prob[i], width=1, color=cmap(1))\n", - "\n", - "plt.figtext(0.25, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.7, -0.01, \"NPB-C\")\n", - "\n", - "brLab = np.arange(len(app_gap)+len(app_npb))\n", - "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", - "\n", - "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Speedup\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()\n", - "\n", - "###############################################################################\n", - "# Multi bar Chart2\n", - "app_gap = df_gap25_ram_prob['app']\n", - "app_gap[len(app_gap)] = \"gmean\"\n", - "\n", - "app_npb = df_npbD_ram_prob['app']\n", - "app_npb[len(app_npb)] = \"gmean\"\n", - "\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,3)\n", - "plt.ylim([0,2.5])\n", - "barWidth = 1\n", - "tickSize = 2\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*tickSize-barWidth/2, gap_25_ram[i]/gap_25_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", - " \n", - "offset = i+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar((offset+i)*tickSize-barWidth/2, npb_D_ram[i]/npb_D_prob[i], width=1, color=cmap(1))\n", - " \n", - "plt.figtext(0.25, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.70, -0.01, \"NPB-D\")\n", - "\n", - "brLab = np.arange(len(app_gap)+len(app_npb))\n", - "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", - "\n", - "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Speedup\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADoCAYAAADi1J7wAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAkyklEQVR4nO3deZxcVZn/8c+XJqxmEQhMBELCMighrAGioDQgskZwYf8hO4MQVhFF+RlR3FEGQWDYJojRsEgEA8MySCCgLAlbIBGFkAAxQDJDAiiQkDzzxz0VK0139e2qutWV7u/79apX1z11656na7n99LlnUURgZmZm1pOs1N0BmJmZmdWbExwzMzPrcZzgmJmZWY/jBMfMzMx6HCc4ZmZm1uM4wTEzM7MexwmOmZmZ9ThOcMzMzKzHWbmjBySdVemJEfGz+odjZmZmVrsOExygb/q5ObADcFvaHgU8WmRQZmZmZrVQZ0s1SHoA2C8i3krbfYHbI+JTDYjPzMzMrMvy9MFZD1hUtr0olZmZmZk1pUqXqEp+CTwqaULaPhAYW1RAZmZmZrXq9BIVgKTtgE+mzQci4olCozIzMzOrQYcJjqS1Kj0xIv63kIjMzMzMalQpwVkKvAK8XyoqezgiYuOKB5auBfYHXo+ILVPZWsANwBBgFnBwRLwhScDFwL7AP4CjI+LxKn8nMzMz6+UqdTL+OfAGcCdwFLBxRAxNt4rJTTIW2LtN2deBeyNiM+DetA2wD7BZup0IXJ77NzAzMzNro2IfnNSy0gocBuwI3A1cHhEv5jq4NASYWNaC8xzQGhFzJQ0CJkXE5pL+I93/Tdv9qv7NzMzMrNeqOIoqsuznPklPAIcC3wX+ClxVZX3rlSUtr/LP4ebrAy+X7fdKKvtAgiPpRLJWHtZcc83tP/rRj1YZiplV47nnngNg88037+ZIzMxg6tSp8yNiYNvySks1rAkcABwCDARuAbaPiJfqEVBEhKTOh3B98HlXAlcCjBgxIqZMmVKPcMwsp9bWVgAmTZrUrXGYmQFImt1eeaUWnNfJWmvGp58BjJA0AiAibqkijtckDSq7RPV6Kp8DbFi23wapzMzMzKzLKiU4N5ElNZunW7kga9HpqtvIOiz/MP28tax8tKTxwE7AQve/MTMzs2p1mOBExNG1HFjSb8g6KK8j6RVgDFlic6Ok44DZwMFp9zvIhog/TzZM/Jha6jYzM7PeLc9SDctImhgR++fZNyIO6+ChPdrZN4BTuhJLRxYsWMDcuW78aTaDBg1iwIAB3R2GmZn1El1KcMhGNjW1+fPnM2TIEFZfffXuDsWSd955hzlz5jjBMTOzhsmzmni5pl+DavHixay22mrdHYaVWW211Vi8eHF3h2FmZr1IlxKciDi2qEDqKZuf0JqF3w8zM2u0SvPgTCMbLdWuiNiqkIjqaOSYu+pynIfP36vDxxYuXMgBBxwAwJNPPsnHPvYxVl11VebPn0/fvn1paWkhIjjhhBM4+uijARg6dCgbbbQRS5YsYciQIYwdO5aWlhYAvv/973PVVVcxc+bMZYnB0KFD2WOPPbj66qsBuP766/nSl77Eiy++yJAhQ5aLp9KxSy644AI22GCDZfGUHH300Tz11FP069ePD33oQ4wbNy7XZaWxY8fyyiuvcN5553W6r5mZWSNUasHZHxhFthbVncAR6XZHuhnQv39/Jk2axKRJk9hmm2246aabmDRpEuussw433XQTDz74ILfffjtjx47lvvvuA6ClpYVJkyYxefJk+vTpw913373seBMnTmT33XfnoYceWlbW0tLCSy+9xHvvvQfAzTffzPbbb99uPJWOnccll1zC/fffz84778wVV1yx3GNLlizp0rHMzMy6S4cJTkTMjojZwJ4RcU5ETEu3rwOfaVyIK74BAwbwzW9+k1//+tfLlS9dupQFCxZQWg/siSeeYNiwYXz5y1/mV7/61XL77rPPPtx+++28/vrr9OnTp9OWlbbHfuCBB9h2220ZNWoUjzzySKcxb7fddsyePZuxY8dy0EEHceCBB3LxxRdz1VVXsdNOO7HTTjtx7bXXLtv/kUceYdSoUWy77bZMnjw5z8tiZmZWmDx9cCRp57KNT+R8npXZcMMNmTMnm5x5yZIltLa2MmTIEJYsWcJee2WXwMaNG8dRRx3FiBEjmD59+nIdcw899FBuuOEGbrjhBg4++OB266h07LPOOotbb72V2267bVlLUCV33303w4YNA+Dtt99mwoQJHHnkkVx66aVMnjyZyZMnc/HFFzNv3jwg69z9+9//ngkTJnDmmWdW9yKZmZnVSZ5E5TjgMkmzJM0CLgNWiM7GzeTll19m/fWzUfaly0jTpk1j3rx5LFiwgKVLl3LrrbdywQUXsPfee/P6669z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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "gap_22_prob = (df_gap22_ram_prob['foundCandidBSlotRMC'].astype(float)+df_gap22_ram_prob['foundCandidBSlotRMD'].astype(float))\n", - "gap_22 = (df_gap22_ram_prob['numRdMissClean'].astype(float)+df_gap22_ram_prob['numRdMissDirty'].astype(float))\n", - "\n", - "gap_25_prob = (df_gap25_ram_prob['foundCandidBSlotRMC'].astype(float)+df_gap25_ram_prob['foundCandidBSlotRMD'].astype(float))\n", - "gap_25 = (df_gap25_ram_prob['numRdMissClean'].astype(float)+df_gap25_ram_prob['numRdMissDirty'].astype(float))\n", - "\n", - "npb_C_prob = (df_npbC_ram_prob['foundCandidBSlotRMC'].astype(float)+df_npbC_ram_prob['foundCandidBSlotRMD'].astype(float))\n", - "npb_C = (df_npbC_ram_prob['numRdMissClean'].astype(float)+df_npbC_ram_prob['numRdMissDirty'].astype(float))\n", - "\n", - "npb_D_prob = (df_npbD_ram_prob['foundCandidBSlotRMC'].astype(float)+df_npbD_ram_prob['foundCandidBSlotRMD'].astype(float))\n", - "npb_D = (df_npbD_ram_prob['numRdMissClean'].astype(float)+df_npbD_ram_prob['numRdMissDirty'].astype(float))\n", - "\n", - "################################## \n", - "# Multi bar Chart1\n", - "app_gap = df_gap22_ram_prob['app']\n", - "\n", - "app_npb = df_npbC_ram_prob['app']\n", - "\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,3)\n", - "plt.ylim([0,100])\n", - "barWidth = 1\n", - "tickSize = 2\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*tickSize-barWidth/2, 100*gap_22_prob[i]/gap_22[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", - "\n", - "offset = i+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar((offset+i)*tickSize-barWidth/2, 100*npb_C_prob[i]/npb_C[i], width=1, color=cmap(1))\n", - "\n", - "plt.figtext(0.25, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.7, -0.01, \"NPB-C\")\n", - "\n", - "brLab = np.arange(len(app_gap)+len(app_npb))\n", - "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", - "\n", - "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", - "\n", - "plt.ylabel(\"Percentage of probed Rd-MC and Rd-Md\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()\n", - "\n", - "###############################################################################\n", - "# Multi bar Chart2\n", - "app_gap = df_gap25_ram_prob['app']\n", - "\n", - "app_npb = df_npbD_ram_prob['app']\n", - "\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,3)\n", - "plt.ylim([0,100])\n", - "barWidth = 1\n", - "tickSize = 2\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*tickSize-barWidth/2, 100*gap_25_prob[i]/gap_25[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", - " \n", - "offset = i+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar((offset+i)*tickSize-barWidth/2, 100*npb_D_prob[i]/npb_D[i], width=1, color=cmap(1))\n", - " \n", - "plt.figtext(0.25, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.70, -0.01, \"NPB-D\")\n", - "\n", - "brLab = np.arange(len(app_gap)+len(app_npb))\n", - "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", - "\n", - "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", - "\n", - "plt.ylabel(\"Percentage of probed Rd-MC and Rd-Md\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAh3UlEQVR4nO3deZxcVZ338c+XJmHNYiDwRCAkREYFIluAIKgN6LBNDDiE9WFRkUF2EXceI5pBHRcGQcMrLBPEKAEkgoRhGUxDAAkkbAEiiglLYiTJaBKiQLbf88c9HSptd6VSVbequvr7fr3qVXVP3b7n17Xc/vU5556jiMDMzMysmWxS7wDMzMzMqs0JjpmZmTUdJzhmZmbWdJzgmJmZWdNxgmNmZmZNxwmOmZmZNZ3cEhxJN0haJOm5grIBku6X9Id0/65ULkk/kvSSpGcl7ZNXXGZmZtb88mzBmQgc0aHsy8ADEbEr8EDaBjgS2DXdzgLG5xiXmZmZNbncEpyIeAj4S4fi0cCN6fGNwDEF5T+NzGNAf0mD8orNzMzMmtumNa5v+4hYmB7/Gdg+Pd4BeK1gv/mpbCEdSDqLrJWHrbbaat/3ve99+UVrZv/gxRdfBOC9731vnSMxM4NZs2YtiYiBHctrneCsExEhaaPXiYiICcAEgBEjRsTMmTOrHpuZda21tRWAtra2usZhZgYg6ZXOymt9FdXr7V1P6X5RKl8A7FSw346pzMzMzGyj1TrBuRM4PT0+HbijoPy0dDXVSGBZQVeWmZmZ2UbJrYtK0i+AVmBbSfOBscB3gFskfRp4BTg+7X43cBTwEvB34JN5xWVmZmbNL7cEJyJO6uKpwzrZN4Bzq1Hv0qVLWbjQjT+NZtCgQfTv37/eYZiZWQ9Rt0HGeVmyZAlDhgxhiy22qHcolrz55pssWLDACY6ZmdVM0y3VsGrVKjbffPN6h2EFNt98c1atWlXvMMzMrAdpugQHQFK9Q7ACfj/MzKzWmq6LqtDIsfdW5TiPXXZ4l88tW7aM0aNHA/D000/z/ve/n80224wlS5bQp08fWlpaiAg+85nPcMYZZwAwdOhQdt55Z9asWcOQIUOYOHEiLS0tAFx++eVce+21zJ07d11iMHToUA477DCuu+46AG666SZOO+005s2bx5AhQ9aLp9ix240bN44dd9xxXTztzjjjDJ555hn69u3L1ltvzaRJk0rqVpo4cSLz58/n0ksv3eC+ZmZmtdCULTi11K9fP9ra2mhra2Ovvfbi1ltvpa2tjW233ZZbb72Vhx9+mKlTpzJx4kSmTZsGQEtLC21tbUyfPp1evXpx3333rTveXXfdxaGHHsojjzyyrqylpYVXX32Vt99+G4DbbruNfffdt9N4ih27FFdddRUPPvggBx10ENdcc816z61Zs2ajjmVmZlYvTnBqoH///nzta1/j5z//+Xrla9euZenSpWQXkcFTTz3F7rvvzmc/+1l+9rOfrbfvkUceydSpU1m0aBG9evXaYMtKx2M/9NBD7L333owaNYoZM2ZsMOZ99tmHV155hYkTJzJmzBiOOeYYrrzySq699loOOOAADjjgAG644YZ1+8+YMYNRo0ax9957M3369FJeFjMzs9w4wamRnXbaiQULssmZ16xZQ2trK0OGDGHNmjUcfnjWBTZp0iROP/10RowYwQsvvLDewNwTTzyRyZMnM3nyZI4//vhO6yh27Isvvpg77riDO++8c11LUDH33Xcfu+++OwArVqxgypQpnHrqqVx99dVMnz6d6dOnc+WVV7J48WIgG9z961//milTpvC5z32uvBfJzMysSpzg1Mhrr73GDjvsALzTjTR79mwWL17M0qVLWbt2LXfccQfjxo3jiCOOYNGiRdx9993rfn7QoEGsWLGCm2++mVGjRq0rv/rqq2ltbeXMM8/s8tgAy5cvZ/DgwUhi//33B+Dhhx+mtbWV1tZWVqxYAcD555/PRz7yEd588811xxw5ciSSmDt3LsOHD6d379707t2b4cOHM2/ePAD2228/AIYMGcKyZctyfCXNzMw2zAlODSxbtoxvf/vbnHTS+nMf9uvXj7PPPpvvfve7TJs2jdGjR3PPPfdwzz33MHXqVCZNmrTe/ueeey7HHnvsenP8nHfeebS1ta0bgNzZsQH69OnD/PnzAXjiiScAOPjgg9eNH9p6662Bd8bgjB8/ft3l9u2DlIcOHcqzzz7LypUrWblyJbNnz2bo0KEAzJo1C4BXX32Vvn37Vv6imZmZVaCpr6KqtzFjxtDS0sLatWv51Kc+xaGHHvoP+5x44okMHz6cJUuWcPLJJ68rHzZsGHPmzGH58uXryo466iiOOuqokutvP/ZXv/pVfvCDHzBq1Cje/e5306dPn7J+n+22245zzjmH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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAh30lEQVR4nO3deZhcVZ3/8feHJmHNYiAwkRASkJ8KRrYAQVBbkGEzAg6BAMOiIiI7iDs/I04GdVwYBA1PWCaIUQJIBAnDMpiGgBJJ2AJElAkEEiNJ1CQEgWzf+eOeDpW2u7pSVbeqUv15PU89VffUrXu+XVV9+9vnnHuOIgIzMzOzZrJJvQMwMzMzqzYnOGZmZtZ0nOCYmZlZ03GCY2ZmZk3HCY6ZmZk1HSc4ZmZm1nRyS3Ak3SBpkaRnCsoGSLpf0h/T/TtSuST9UNILkp6WtHdecZmZmVnzy7MFZyJweIeyLwMPRMSuwANpG+AIYNd0OxMYn2NcZmZm1uRyS3Ai4iHgrx2KjwZuTI9vBI4pKP9JZB4F+ksalFdsZmZm1tw2rXF920fEwvT4z8D26fEOwCsF+81PZQvpQNKZZK08bLXVVvu85z3vyS9aM/sHzz//PADvfve76xyJmRnMmjVrSUQM7Fhe6wRnnYgISRu8TkRETAAmAIwYMSJmzpxZ9djMrGutra0AtLW11TUOMzMASfM6K6/1VVSvtnc9pftFqXwBsGPBfoNTmZmZmdkGq3WCcydwWnp8GnBHQfmp6WqqkcCygq4sMzMzsw2SWxeVpJ8DrcC2kuYDY4FvA7dI+jQwDzg+7X43cCTwAvB34JN5xWVmZmbNL7cEJyJO7OKpQzrZN4BzqlHv0qVLWbjQjT+NZtCgQfTv37/eYZiZWQ9Rt0HGeVmyZAlDhw5liy22qHcolrzxxhssWLDACY6ZmdVM0y3VsGrVKjbffPN6h2EFNt98c1atWlXvMMzMrAdpugQHQFK9Q7AC/jzMzKzWmq6LqtDIsfdW5TiPXnZYl88tW7aMo48+GoAnn3yS9773vWy22WYsWbKEPn360NLSQkTwmc98htNPPx2AYcOGsdNOO7FmzRqGDh3KxIkTaWlpAeDyyy/n2muvZe7cuesSg2HDhnHIIYdw3XXXAXDTTTdx6qmn8uKLLzJ06ND14il27Hbjxo1j8ODB6+Jpd/rpp/PUU0/Rt29ftt56ayZNmlRSt9LEiROZP38+l156abf7mpmZ1UJTtuDUUr9+/Whra6OtrY0999yTW2+9lba2NrbddltuvfVWHn74YaZOncrEiROZNm0aAC0tLbS1tTF9+nR69erFfffdt+54d911FwcffDCPPPLIurKWlhZefvll3nrrLQBuu+029tlnn07jKXbsUlx11VU8+OCDHHjggVxzzTXrPbdmzZoNOpaZmVm9OMGpgf79+/O1r32Nn/3sZ+uVr127lqVLl5JdRAZPPPEEu+++O5/73Of46U9/ut6+RxxxBFOnTmXRokX06tWr25aVjsd+6KGH2GuvvRg1ahQzZszoNua9996befPmMXHiREaPHs0xxxzDlVdeybXXXsv+++/P/vvvzw033LBu/xkzZjBq1Cj22msvpk+fXsrbYmZmlhsnODWy4447smBBNjnzmjVraG1tZejQoaxZs4bDDsu6wCZNmsRpp53GiBEjeO6559YbmDtmzBgmT57M5MmTOf744zuto9ixL774Yu644w7uvPPOdS1Bxdx3333svvvuAKxYsYIpU6ZwyimncPXVVzN9+nSmT5/OlVdeyeLFi4FscPevfvUrpkyZwkUXXVTem2RmZlYlTnBq5JVXXmGHHXYA3u5Gmj17NosXL2bp0qWsXbuWO+64g3HjxnH44YezaNEi7r777nWvHzRoECtWrODmm29m1KhR68qvvvpqWltbOeOMM7o8NsDy5csZMmQIkthvv/0AePjhh2ltbaW1tZUVK1YAcN555/HhD3+YN954Y90xR44ciSTmzp3L8OHD6d27N71792b48OG8+OKLAOy7774ADB06lGXLluX4TpqZmXXPCU4NLFu2jG9961uceOL6cx/269ePs846i+985ztMmzaNo48+mnvuuYd77rmHqVOnMmnSpPX2P+ecczj22GPXm+Pn3HPPpa2tbd0A5M6ODdCnTx/mz58PwGOPPQbAQQcdtG780NZbbw28PQZn/Pjx6y63bx+kPGzYMJ5++mlWrlzJypUrmT17NsOGDQNg1qxZALz88sv07du38jfNzMysAk19FVW9jR49mpaWFtauXcunPvUpDj744H/YZ8yYMQwfPpwlS5Zw0kknrSvfZZddmDNnDsuXL19XduSRR3LkkUeWXH/7sb/61a/y/e9/n1GjRvHOd76TPn36lPXzbLfddpx99tkc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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "gap_22_prob = (df_gap22_ram_prob['foundCandidBSlotRMC'].astype(float))\n", - "gap_22 = (df_gap22_ram_prob['numRdMissClean'].astype(float))\n", - "\n", - "gap_25_prob = (df_gap25_ram_prob['foundCandidBSlotRMC'].astype(float))\n", - "gap_25 = (df_gap25_ram_prob['numRdMissClean'].astype(float))\n", - "\n", - "npb_C_prob = (df_npbC_ram_prob['foundCandidBSlotRMC'].astype(float))\n", - "npb_C = (df_npbC_ram_prob['numRdMissClean'].astype(float))\n", - "\n", - "npb_D_prob = (df_npbD_ram_prob['foundCandidBSlotRMC'].astype(float))\n", - "npb_D = (df_npbD_ram_prob['numRdMissClean'].astype(float))\n", - "\n", - "################################## \n", - "# Multi bar Chart1\n", - "app_gap = df_gap22_ram_prob['app']\n", - "\n", - "app_npb = df_npbC_ram_prob['app']\n", - "\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,3)\n", - "plt.ylim([0,100])\n", - "barWidth = 1\n", - "tickSize = 2\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*tickSize-barWidth/2, 100*gap_22_prob[i]/gap_22[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", - "\n", - "offset = i+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar((offset+i)*tickSize-barWidth/2, 100*npb_C_prob[i]/npb_C[i], width=1, color=cmap(1))\n", - "\n", - "plt.figtext(0.25, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.7, -0.01, \"NPB-C\")\n", - "\n", - "brLab = np.arange(len(app_gap)+len(app_npb))\n", - "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", - "\n", - "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", - "\n", - "plt.ylabel(\"Percentage of probed Rd-MC\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()\n", - "\n", - "###############################################################################\n", - "# Multi bar Chart2\n", - "app_gap = df_gap25_ram_prob['app']\n", - "\n", - "app_npb = df_npbD_ram_prob['app']\n", - "\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,3)\n", - "plt.ylim([0,100])\n", - "barWidth = 1\n", - "tickSize = 2\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*tickSize-barWidth/2, 100*gap_25_prob[i]/gap_25[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", - " \n", - "offset = i+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar((offset+i)*tickSize-barWidth/2, 100*npb_D_prob[i]/npb_D[i], width=1, color=cmap(1))\n", - " \n", - "plt.figtext(0.25, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.70, -0.01, \"NPB-D\")\n", - "\n", - "brLab = np.arange(len(app_gap)+len(app_npb))\n", - "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", - "\n", - "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", - "\n", - "plt.ylabel(\"Percentage of probed Rd-MC\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/tmp/ipykernel_308484/3573616793.py:27: RuntimeWarning: invalid value encountered in double_scalars\n", - " plt.bar(i*tickSize-barWidth/2, 100*gap_22_prob[i]/gap_22[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", - "/tmp/ipykernel_308484/3573616793.py:31: RuntimeWarning: invalid value encountered in double_scalars\n", - " plt.bar((offset+i)*tickSize-barWidth/2, 100*npb_C_prob[i]/npb_C[i], width=1, color=cmap(1))\n" - ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAh0klEQVR4nO3deZhcVZ3/8feHJmHNYiAwEYgJkUHByNZAENQGdNiMAYew/lhUZJBdBnd+RjQijguDoOEJi2EwSgCJIGFYBtMQQAIJEAJEFBOWxEiS0SQEgWzf+eOeDpW2l9tVXUtXf17PU0/VPXXrnm9XVd/+9rlnUURgZmZmVk82qXYAZmZmZt3NCY6ZmZnVHSc4ZmZmVnec4JiZmVndcYJjZmZmdccJjpmZmdWdsiU4km6QtETSswVlgyTdL+mP6f5dqVySfizpRUnPSNq7XHGZmZlZ/StnC84k4PBWZV8BHoiIXYAH0jbAEcAu6XYmMKGMcZmZmVmdK1uCExEPAX9tVTwGuDE9vhE4uqD8vyLzGDBQ0pByxWZmZmb1bdMK17d9RCxOj/8CbJ8e7wC8WrDfwlS2mFYknUnWysNWW221z/ve977yRWtmJXnhhRcA2HXXXasciZn1ZLNnz14WEYO78ppKJzgbRERI6vI6ERExEZgI0NjYGLNmzer22MysezQ1NQHQ3Nxc1TjMrGeT9HJXX1PpUVSvtVx6SvdLUvkiYKeC/XZMZWZmZmZdVukE507gtPT4NOCOgvJT02iqUcCKgktZZmZmZl1StktUkn4JNAHbSloIjAMuB26R9FngZeC4tPvdwJHAi8DfgU+XKy4zMzOrf2VLcCLixHaeOrSNfQM4pzvqXb58OYsXu/Gn1gwZMoSBAwdWOwwzM+slqtbJuFyWLVvGsGHD2GKLLaodiiVvvvkmixYtcoJjZmYVU3dLNaxZs4bNN9+82mFYgc0335w1a9ZUOwwzM+tF6i7BAZBU7RCsgD8PMzOrtLq7RFVo1Lh7u+U4j116WLvPrVixgjFjxgDw9NNP8/73v5/NNtuMZcuW0a9fPxoaGogIPve5z3H66acDMHz4cN7znvewbt06hg0bxqRJk2hoaADgsssu49prr2X+/PkbEoPhw4dz6KGHct111wFw0003ceqpp7JgwQKGDRu2UTwdHbvF+PHj2XHHHTfE0+L0009nzpw59O/fn6233prJkyfnuqw0adIkFi5cyCWXXNLpvmZmZpVQly04lTRgwACam5tpbm5mzz335NZbb6W5uZltt92WW2+9lYcffphp06YxadIkpk+fDkBDQwPNzc3MmDGDPn36cN9992043l133cUhhxzCI488sqGsoaGBV155hbfffhuA2267jX322afNeDo6dh5XXXUVDz74IAceeCDXXHPNRs+tW7euS8cyMzOrFic4FTBw4EC+/vWv84tf/GKj8vXr17N8+XKyQWTw1FNPsfvuu/P5z3+en//85xvte8QRRzBt2jSWLFlCnz59Om1ZaX3shx56iL322ovRo0czc+bMTmPee++9efnll5k0aRJjx47l6KOP5sorr+Taa69l//33Z//99+eGG27YsP/MmTMZPXo0e+21FzNmzMjztpiZmZWNE5wK2WmnnVi0KJuced26dTQ1NTFs2DDWrVvHYYdll8AmT57MaaedRmNjI88///xGHXNPOOEEpkyZwpQpUzjuuOParKOjY1900UXccccd3HnnnRtagjpy3333sfvuuwOwatUqpk6dyimnnMLVV1/NjBkzmDFjBldeeSVLly4Fss7dv/nNb5g6dSpf+MIXinuTzMzMuokTnAp59dVX2WGHHYB3LiPNnTuXpUuXsnz5ctavX88dd9zB+PHjOfzww1myZAl33333htcPGTKEVatWcfPNNzN69OgN5VdffTVNTU2cccYZ7R4bYOXKlQwdOhRJ7LfffgA8/PDDNDU10dTUxKpVqwA477zz+OhHP8qbb7654ZijRo1CEvPnz2fkyJH07duXvn37MnLkSBYsWADAvvvuC8CwYcNYsWJFGd9JMzOzzjnBqYAVK1bw3e9+lxNP3HjuwwEDBnDWWWfxve99j+nTpzNmzBjuuece7rnnHqZNm8bkyZM32v+cc87hmGOO2WiOn3PPPZfm5uYNHZDbOjZAv379WLhwIQBPPPEEAAcddNCG/kNbb7018E4fnAkTJmwYbt/SSXn48OE888wzrF69mtWrVzN37lyGDx8OwOzZswF45ZVX6N+/f+lvmpmZWQnqehRVtY0dO5aGhgbWr1/PZz7zGQ455JB/2OeEE05g5MiRLFu2jJNOOmlD+YgRI5g3bx4rV67cUHbkkUdy5JFH5q6/5dhf+9rX+OEPf8jo0aN597vfTb9+/Yr6ebbbbjvOPvtsDjroICBLrgYPzlav33LLLTnqqKP485//zBVXXFHU8c3MzLqLWjqh9kSNjY0xa9asjcrmzZvH+9///ipFZO3x59I7NTU1AdDc3FzVOMysZ5M0OyIau/IaX6IyMzOzuuMEx8zMzOpOu31wJL0OtHv9KiJqtidpRHh5gBrSky+DmplZz9RughMR/QAkfRtYDNwECDgZGFKR6IrQp08f3nrrLa8mXkPeeust+vTpU+0wzMysF8kziuqTEbFHwfYESXOAb5QpppJsu+22vPTSS9UOw1oZMqRmc2IzM6tDeRKcNySdDNxMdsnqROCNskZVgoEDB+ZaINLMzMzqV55OxicBxwGvpdvYVGZmZmZWkzptwYmIl4Ax5Q/FzMzMrHt0NIrqxx29MCLO7/5wzMzMzErXUQvOWcCzwC3An8lGUJmZmZnVvI4SnCFk/W2OB9YCU4DbImJ5BeIyMzMzK1q7nYwj4n8j4pqIOBj4NDAQeF7SKZUKzszMzKwYnXYylrQ32dDwjwP/Dcwud1BmZmZmpeiok/G3gKOAeWRz4Hw1ItZWKjAzMzOzYnXUgnMJsADYI90uS+s7CYiI+GD5wzMzMzPruo4SnOHlqlTSF4AzyGZGnkvWx2cIWUvRNmSXwU6JiNXlisHMzMzqV0edjF9ufQNGFjwuiqQdgPOBxoj4ANAAnAB8D7giIt4L/A34bLF1mJmZWe+WZ6mGQt/qpno3BbaQtCmwJdlq5YcAt6XnbwSO7qa6zMzMrJfpaoJT8mR/EbEI+AHwCllis4LsktTygk7MC4Ed2gxAOlPSLEmzli5dWmo4ZmZmVoe6muD8W6kVSnoX2dpWw4F3A1sBh+d9fURMjIjGiGgcPHhwqeGYmZlZHepomPin2infESAibi+yzo8BCyJiaTre7cCBwEBJm6ZWnB2BRUUe38zMzHq5jkZRjU732wEfAn6btg8GHgWKTXBeAUZJ2hJ4EzgUmAVMB44lG0l1GnBHkcc3MzOzXq7dBCciPg0g6T5gt4hYnLaHAJOKrTAiZkq6DXiSbI2rp4CJwDTgZknjU9n1xdZhZmZmvVunSzUAO7UkN8lrwNBSKo2IccC4VsXzgf1KOa6ZmZkZ5EtwHpB0L/DLtH088D/lC8nMzMysNJ0mOBFxrqRjgI+kookRMbW8YZmZmZkVL08LDimhmQogaRNJJ0fE5LJGZmZmZlakdufBkdRf0lclXS3pX5Q5l6yvzHGVC9HMzMysazpqwbmJbE2o35EtjPk1spmMj46Ip8sfmpmZmVlxOkpwdo6IkQCSriNbVmFoRLxVkcjMzMzMitTRUg1rWh5ExDpgoZMbMzMz6wk6asHZQ9LK9Fhkq3+vTI8jIvqXPTozM7MebNS4e7vlOI9deli3HKc36Wgm44ZKBmJmZmbWXbq6mriZmZlZzXOCY2ZmZnXHCY6ZmZnVHSc4ZmZmVnfa7WQs6XUg2nveo6jMzMysVnU0iqofgKRvk03ydxPZEPGTgSEVic7MzMysCHkuUX0yIn4aEa9HxMqImACMKXdgZmZmZsXKk+C8IelkSQ0tK4kDb5Q7MDMzM7Ni5UlwTiJbPfy1dBubyszMzMxqUkdLNQAQES/hS1JmZmbWg3TagiPpnyU9IOnZtP1BSZeUPzQzMzOz4uS5RHUt8FXS6uIR8QxwQjmDMjMzMytFngRny4h4vFXZ2nIEY2ZmZtYd8iQ4yySNIE36J+lYsnlxzMzMzGpSp52MgXOAicD7JC0CFpBN9mdmZmZWk/KMopoPfEzSVsAmEfF6+cMyMzMzK16eUVTbSPoxMANolnSlpG3KH5qZmZlZcfL0wbkZWAr8K3BsejyllEolDZR0m6TfS5on6QBJgyTdL+mP6f5dpdRhZmZmvVeeBGdIRHw7Ihak23hg+xLrvRK4JyLeB+wBzAO+AjwQEbsAD6RtMzMzsy7Lk+DcJ+mEtA7VJpKOA+4ttkJJA4CPANcDRMTqiFhONlvyjWm3G4Gji63DzMzMerd2OxlLep1saLiAC4Gfp6c2AVYBFxdZ53Cyy1w/k7QHMBu4ANg+IlqGn/+FdlqJJJ0JnAkwdOjQIkMwM2vfqHFF/w/3Dx679LBuO5aZ5dduC05E9IuI/ul+k4jYNN02iYj+JdS5KbA3MCEi9iJbmXyjy1EREaR5d9qIa2JENEZE4+DBg0sIw8zMzOpVnnlwkPRJsstKAM0RcVcJdS4EFkbEzLR9G1mC85qkIRGxWNIQYEkJdZiZmVkvlmeY+OVkl5CeT7cLJH232Aoj4i/Aq5J2TUWHpuPeCZyWyk4D7ii2DjMzM+vd8rTgHAnsGRHrASTdCDxFtgBnsc4DJkvqC8wHPk2WbN0i6bPAy8BxJRzfzMzMerFcl6iAgcBf0+MBpVYaEU8DjW08dWipxzYzMzPLk+BcBjwlaTrZiKqP4DlqzMzMrIZ1mOBI2gRYD4wC9k3FX079aOpadw0T9RBRMzOzyuswwYmI9ZK+FBG3kHUCNjMzM6t5eWYy/h9JF0vaKa0XNUjSoLJHZmZmZlakPH1wjk/35xSUBbBz94djZmZmVrpOE5yIGF6JQMzMzMy6S6cJjqTNgbOBg8habmYA10TEW2WOzczKwB3ozaw3yHOJ6r+A14Gr0vZJwE3A2HIFZWZmZlaKPAnOByJit4Lt6ZKeL1dAZmZmZqXKM4rqSUmjWjYk7Q/MKl9IZmZmZqXJ04KzD/CopFfS9lDgBUlzgYiID5YtOjMzM7Mi5ElwDi97FGZmZlYRvWWgQZ5h4i9XIhAzMzOz7pKnD46ZmZlZj9JuC46kzSLi7UoGYx3rLc2KZmZmpeqoBed3AJJuqlAsZmZmZt2ioz44fSWdBHxI0qdaPxkRt5cvLDMzM7PidZTgnAWcDAwERrd6LgAnOGZmZlaT2k1wIuJh4GFJsyLi+grGZGZmZlaSPPPg3CTpfOAjaftBssU215QvLDMzM7Pi5Ulwfgr0SfcApwATgDPKFZSZmZlZKfIkOPtGxB4F27+VNKdcAZnVGw/vNzOrvDwT/a2TNKJlQ9LOwLryhWRmZmZWmjwtOF8EpkuaDwh4D/DpskZlZmZmVoI8a1E9IGkXYNdU9IJnODYzM7Nalmstqoh4OyKeSbduSW4kNUh6StJdaXu4pJmSXpQ0RVLf7qjHzMzMep9qLrZ5ATCvYPt7wBUR8V7gb8BnqxKVmZmZ9Xh5+uB0O0k7AkcB3wEukiTgEOCktMuNwDfJhqObmfV6Ho1n1jWdtuAo8/8kfSNtD5W0X4n1/ifwJWB92t4GWB4Ra9P2QmCHduI5U9IsSbOWLl1aYhhmZmZWj/JcovopcABwYtp+HfhJsRVK+gSwJCJmF/P6iJgYEY0R0Th48OBiwzAzM7M6lucS1f4RsbekpwAi4m8ldgA+EPikpCOBzYH+wJXAQEmbplacHYFFJdRhZmZmvVieFpw1khrIVhBH0mDeubTUZRHx1YjYMSKGAScAv42Ik4HpwLFpt9OAO4qtw8zMzHq3PAnOj4GpwHaSvgM8DFxWhli+TNbh+EWyPjlewdzMzMyKkmeiv8mSZgOHks1kfHREzOvkZblERDPQnB7PB0rtvGxmZhXikV1WyzpNcCQNApYAvywo6xMRa8oZmJmZmVmx8lyiehJYCvwB+GN6/JKkJyXtU87gzMzMzIqRJ8G5HzgyIraNiG2AI4C7gLPJhpCbmZmZ1ZQ8Cc6oiNhwoTUi7gMOiIjHgM3KFpmZmZlZkfLMg7NY0peBm9P28cBraeh40cPFzczMzMolTwvOSWQT7/063YamsgbguHIFZmZmZlasPMPElwHntfP0i90bjpmZmVnp8gwTH0y2MObuZEsrABARh5QxLjMzM7Oi5blENRn4PTAcuBR4CXiijDGZmZmZlSRPgrNNRFwPrImIByPiM4Bbb8zMzKxm5RlF1TJj8WJJRwF/BgaVLyQzMzOz0uRJcMZLGgD8O3AV0B+4sJxBmZmZmZUiT4Lzt4hYAawADgaQdGBZozIzMzMrQZ4+OFflLDMzMzOrCe224Eg6APgQMFjSRQVP9Seb5M/MzMysJnV0iaovsHXap19B+Urg2HIGZWZmZlaKdhOciHgQeFDSpIh4uYIxmZmZmZUkTyfjzSRNBIYV7u+ZjM3MzKxW5UlwbgWuAa4D1pU3HDMzM7PS5Ulw1kbEhLJHYmZmZtZN8gwT/42ksyUNkTSo5Vb2yMzMzMyKlKcF57R0/8WCsgB27v5wzMzMzErXaYITEcMrEYiZmZlZd+n0EpWkLSVdkkZSIWkXSZ8of2hmZmZmxcnTB+dnwGqyWY0BFgHjyxaRmZmZWYnyJDgjIuI/gDUAEfF3QGWNyszMzKwEeRKc1ZK2IOtYjKQRwNvFVihpJ0nTJT0v6TlJF6TyQZLul/THdP+uYuswMzOz3i3PKKpxwD3ATpImAwcCp5dQ51rg3yPiSUn9gNmS7k/HfCAiLpf0FeArwJdLqMfKbNS4e7vtWI9deli3HcvMzCzPKKr7JT0JjCK7NHVBRCwrtsKIWAwsTo9flzQP2AEYAzSl3W4EmnGCY2ZmZkXIM4rqGLLZjKdFxF3AWklHd0flkoYBewEzge1T8gPwF2D7dl5zpqRZkmYtXbq0O8IwMzOzOpOnD864iFjRshERy8kuW5VE0tbAr4ALI2Jl4XMREaQ+P61FxMSIaIyIxsGDB5cahpmZmdWhPAlOW/vk6bvTLkl9yJKbyRFxeyp+TdKQ9PwQYEkpdZiZmVnvlSfBmSXpR5JGpNuPgNnFVihJwPXAvIj4UcFTd/LOshCnAXcUW4eZmZn1bnkSnPPIJvqbAtwMvAWcU0KdBwKnAIdIejrdjgQuBz4u6Y/Ax9K2mZmZWZd1eKlJUgNwV0Qc3F0VRsTDtD9R4KHdVY+ZmZn1Xh224ETEOmC9pAEVisfMzMysZHk6C68C5qbJ+N5oKYyI88sWlZmZmVkJ8iQ4t6ebmZmZWY+QZybjG9NaVEMj4oUKxGRmZmZWkjwzGY8GniZbjwpJe0q6s8xxmZmZmRUtzzDxbwL7AcsBIuJpYOeyRWRmZmZWojwJzprCpRqS9eUIxszMzKw75Olk/Jykk4AGSbsA5wOPljcsMzMzs+Llncl4d+Bt4BfACuDCMsZkZmZmVpJ2W3AkbQ6cBbwXmAscEBFrKxWYmZmZWbE6asG5EWgkS26OAH5QkYjMzMzMStRRH5zdImIkgKTrgccrE5KZmZlZaTpqwVnT8sCXpszMzKwn6agFZw9JK9NjAVukbQEREf3LHp2ZmZlZEdpNcCKioZKBmJmZmXWXPMPEzczMzHoUJzhmZmZWd5zgmJmZWd1xgmNmZmZ1xwmOmZmZ1R0nOGZmZlZ3nOCYmZlZ3XGCY2ZmZnXHCY6ZmZnVHSc4ZmZmVnec4JiZmVndqakER9Lhkl6Q9KKkr1Q7HjMzM+uZaibBkdQA/AQ4AtgNOFHSbtWNyszMzHqimklwgP2AFyNifkSsBm4GxlQ5JjMzM+uBFBHVjgEASccCh0fEGWn7FGD/iDi31X5nAmemzV2BFyoa6Ma2BZZVsf621FpMtRYPOKY8ai0ecEx51Fo8UHsx1Vo84Jjy2DUi+nXlBZuWK5JyiYiJwMRqxwEgaVZENFY7jkK1FlOtxQOOKY9aiwccUx61Fg/UXky1Fg84pjwkzerqa2rpEtUiYKeC7R1TmZmZmVmX1FKC8wSwi6ThkvoCJwB3VjkmMzMz64Fq5hJVRKyVdC5wL9AA3BARz1U5rM7UxKWyVmotplqLBxxTHrUWDzimPGotHqi9mGotHnBMeXQ5nprpZGxmZmbWXWrpEpWZmZlZt3CCY2ZmZnXHCU5OkoZJerbacUD7sUj6sKTnJD0taYtqxGY9k6SBks6udhyFOvieXyhpy2rEVKsknS9pnqQ3amEGeEmPVjuGQpJWVTsGqzwnOPXlZOC7EbFnRLxZ7WB6krRUSG82EKipBKcDFwJOcDZ2NvBx4FaypW6qKiI+VO0YzJzgdM2mkian/5Ruk7SlpH0lPSppjqTHJXVppsVujOV84Djg26l8iKSHUmvOs5I+XImgJJ0q6Zn0ftwkaXtJU9P2HEkVP/GlloDft/HZvSTpe5KeBMaWod6tJE1LP/ezko6XdLmk59N79IO039j0/BxJD6Wy0yXdIalZ0h8ljevu+Fq5HBiRvi/fl/RlSXNTTJeXue6OtPU9fzcwXdL0SgbSxnd7hKTH0vs0vlqtBJKuAXYGFgCnAd9Pn+OIasSTYlqV7qtyHuogriZJdxVsXy3p9ArV3XIemiTpD+l7/TFJj6Tf8f0kDZZ0f2qJv07Sy5K2rUBsbZ2rXpL0H+n7/bik95Y7joJ4Nmq9lXSxpG9K+pykJ1Kcv1JnLbkR4VuOGzAMCODAtH0D8CVgPrBvKusPbFqlWC4GJgHHprJ/B76eHjcA/SoQ1+7AH4Bt0/YgYApwYUEcA2rks7sYeAn4Uhnr/Vfg2oLt95AtLdIyenFgup8L7NCq7HRgMbANsAXwLNBY5vfo2fT4COBRYMuWz7HSn1mOz23bCsfS1nf7LuDEtH0WsKoa71Oq/yWyqfU3nAOqeWt5L6pxHuoknibgroLyq4HTKxTDMGAtMJKscWF2+k6LbN3FX6d4vpr2Pzx9/8v+XW/jXDUgfadaPrtTC9+3Cr1XzxZsXwx8E9imoGw8cF5Hx3ELTte8GhGPpMc/Bw4DFkfEEwARsTIi1lYploNaPf8E8GlJ3wRGRsTrFYjpEODWiFgGEBF/TWUT0va6iFhRgTja0t77NaWMdc4FPp5aiT5MNjP3W8D1kj4F/D3t9wgwSdLnyP4ItLg/Iv43ssuNt/OPn3G5fAz4WUT8HTZ8jtXS2fe8Utr6bh9AdkkI4BdViqvWVeM8VMsWRMTciFgPPAc8ENlf67lkf9QPIltomoi4B/hbheLa6FxVcJ7+ZcH9ARWKpSMfkDRD0lyyLhm7d7SzE5yuaT1p0MqqRJFpHctG2xHxEPARsj+qkySdWqnAalR779cbZasw4g/A3mQnj/HA14D9gNuATwD3pP3OAi4hW6pktqRtOom5N/F70IPV4HloLRv/3du8wvW/XfB4fcH2eqo48W7rc5Wkb7Q8VbhbBUNq73OaBJwbESOBS+nk83OC0zVDJbVksScBjwFDJO0LIKmfpEp9SVvH8nDhk5LeA7wWEdcC15F9ecvtt8DYlj/QkgYBDwCfT9sNkgZUII62dPh+lYOkdwN/j4ifA98nO9EPiIi7gS8Ae6T9RkTEzIj4BrCUd9Zk+7ikQcpGxB1N1tJTLq8DLf3H7if7r3vLFN+gMtbbmbY+t8JYK6Wt7/ZjZE37kC0tUwuq8d60q0rnoY68DOwmaTNJA4FDqxxPa4+Q9aVE0r8A76pEpW2cq1o+p+ML7n9XiViS14DtJG0jaTOyfwgh+24vltSHrAWnQ05wuuYF4BxJ88i+eFeRffBXSZpD9oehUv8RtI5lQqvnm4A5kp5KMV5Z7oAiW1rjO8CD6f34EXABcHBqUpxN9UZ4dPZ+lcNI4HFJTwPjyP7juEvSM2R/qC9K+30/deR7lqzvy5xU/jjwK+AZ4FcR0eXVdPOKiP8FHkkxHEq2DtysFPvF5ao3h7Y+t4nAPZXsZNzOd/tC4KL0eb4XqNbl10I3A1+U9FQ1OxkXaKLC56GORMSrwC1kfdpuAZ6qZjxtuBT4l/R7OBb4C1nSWm6tz1XjU/m70vf7ArJ/yioiItYA3yI7B94P/D499f+BmWSJ4O/bfvU7vFSD1T1Jw8g6yH2g2rHklUZ2NEbEudWOxdqWWrjejIiQdAJZh+Mx1Y7Leq7UWrEusrUZDwAmRMSeVYrlJbJz0LJq1N8damaxTTOzHmYf4GpJApYDn6luOFYHhgK3SNoEWA18rsrx9GhuwTEzM7O64z44ZmZmVnec4JiZmVndcYJjZmZmdccJjpmZmdUdJzhWFGWLaP5C0nxJsyX9TtIxBc//p6RFaTRAS9npkpYqW3jv+bQ0Qevy55QWw0zPjZI0Mz03L0353lY8kyW9oGyhuBvSRFBIOlnZAolzlS2KukdZ3xizXkZSSPphwfbFLb+nyhZIXKR3Ftv8ZBvlv5c0ofBc0er4/yTpZkl/SueauyX9c0V+OOvRnOBYl6Vhsb8GHoqInSNiH7KZXHdMz28CHAO8Cny01cunpHkdmoDLJG1fWB4Ru5MNj2yZQfNG4Mz0mg+QTc7VlsnA+8gmrNoCOCOVLwA+mqb2/jbZJHFm1n3eBj6l9le9viL9/o4FbihIZFrKdyP7vW19rmg510wFmiNiRDrXfBXYvvW+Zq05wbFiHAKsjohrWgoi4uWIuCptNpEtJDcBOLGtA0TEEuBPZCtsb6BsqYuteGeRue3IVtVuWazz+XaOd3ckZLNf7pjKH42IlmM91lJuZt1mLdk/Dh3OdBsR89K+rROhvmQzwLe1sOTBwJpW55o5ETGjpIitV3CCY8XYHXiyg+dPJFt9dipwVMvlokKSdgZ2Bl5MRcenacIXAYOA36TyK4AXJE2V9G+SOlwKI9V1Cmkhy1Y+C/x3R683s6L8BDhZHaw1J2l/skUll6aiL6Tf+cXAHyLi6TZe9gGyJV7MuswJjpVM0k8kzZH0hKS+wJHAryNiJdm6IYcV7N6SyPwS+LeI+Gsqb7l09U9kK9p+ESAivgU0AveRLbbYVuJS6Kdkl842+g9P0sFkCc6Xi/5BzaxN6Xf9v4Dz23i6JZH5AXB8vDO7bMslqu2ArdJyF2bdxgmOFeM5ClYFjohzyBZoHEyWzAwE5qa1TA5i48tULX1t9o+Iqa0PnE5+vyFbebul7E8RMSHVsYeyFWbvTR0Ur2vZT9K4FMNFhceU9EGylYzHpEUlzaz7/SfZPxFbtSq/Iv3Of7itS0tpYcV7gI9I2in9Xj8t6Syyc80+5Q7c6pMTHCvGb4HNJX2+oGzLdH8icEZEDIuIYcBw4OMto6JyOoisfw6SjkodDQF2AdYByyPisHTSPCPtdwZZcnViRKxvOZCkocDtwCkR8Yeu/qBmlk9qjb2FLMnJLf1+Hwj8KSJeTb/Xe6Z+N78FNpN0ZsH+H5T04e6M3eqTExzrstTKcjTwUUkLJD1ONtppHHA4MK1g3zeAh4HRnRz2+PRf2zPAXmQjniDrT/NCauK+CTg5Ita18fpryEZW/C4d5xup/BvANsBPU/msLv/AZpbXD/nHTsTtabl09SzQQHZ5eSPpXHMM8LE0TPw54LvAX7onXKtnXmzTzMzM6o5bcMzMzKzuOMExMzOzuuMEx8zMzOqOExwzMzOrO05wzMzMrO44wTEzM7O64wTHzMzM6s7/Aaums6wM75eDAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAht0lEQVR4nO3de7hVVb3/8ffHLXjlIooeUhE0f5VG3raKabXTOt4itCOKelQqM/Ou2b0TWRyz08VMCx+8hBklapKmHi/H2IqWJKiISpahKEQCFSCmcvv+/phj42K3L4u11lxrsfbn9Tzr2WuOOfcc373W2nN/9xhjjqGIwMzMzKyRbFLrAMzMzMwqzQmOmZmZNRwnOGZmZtZwnOCYmZlZw3GCY2ZmZg3HCY6ZmZk1nNwSHEnXS1ok6emCsgGS7pf0p/R1m1QuST+U9LykpyTtm1dcZmZm1vjybMGZCBzRruyLwAMRsTvwQNoGOBLYPT3OAMbnGJeZmZk1uNwSnIh4CPh7u+KRwA3p+Q3AMQXlP43Mo0B/SYPyis3MzMwa26ZVrm+HiFiYnv8V2CE93xF4ueC4+alsIe1IOoOslYetttpqv3e+8535RWtm/+K5554D4B3veEeNIzEzg5kzZy6JiIHty6ud4KwTESFpg9eJiIgJwASA5ubmmDFjRsVjM7POtbS0ANDa2lrTOMzMACTN66i82ndRvdLW9ZS+LkrlC4CdC47bKZWZmZmZbbBqJzh3AKel56cBtxeUn5ruphoOLCvoyjIzMzPbILl1UUn6BdACbCdpPjAWuAy4WdIngXnA8enwu4GjgOeBfwIfzysuMzMza3y5JTgRcWInuw7r4NgAzq5EvUuXLmXhQjf+1JtBgwbRv3//WodhZmY9RM0GGedlyZIlDBkyhC222KLWoVjy+uuvs2DBAic4ZmZWNQ23VMOqVavYfPPNax2GFdh8881ZtWpVrcMwM7MepOESHABJtQ7BCvj9MDOzamu4LqpCw8feW5HzPHrJ4Z3uW7ZsGSNHjgTgySef5F3vehebbbYZS5YsoU+fPjQ1NRERfOpTn2LMmDEADB06lF122YU1a9YwZMgQJk6cSFNTEwCXXnop11xzDXPnzl2XGAwdOpTDDjuMa6+9FoAbb7yRU089lRdeeIEhQ4asF09X524zbtw4dtppp3XxtBkzZgyzZs2ib9++bL311kyaNKmobqWJEycyf/58vvrVr3Z7rJmZWTU0ZAtONfXr14/W1lZaW1vZe++9ueWWW2htbWW77bbjlltu4eGHH+auu+5i4sSJTJ06FYCmpiZaW1uZNm0avXr14r777lt3vjvvvJNDDz2URx55ZF1ZU1MTL730Em+++SYAt956K/vtt1+H8XR17mJceeWVPPjggxx88MFcffXV6+1bs2bNBp3LzMysVpzgVEH//v35yle+ws9//vP1yteuXcvSpUvJbiKDJ554gj333JPPfOYz/OxnP1vv2COPPJK77rqLRYsW0atXr25bVtqf+6GHHmKfffZhxIgRTJ8+vduY9913X+bNm8fEiRMZNWoUxxxzDFdccQXXXHMNBx54IAceeCDXX3/9uuOnT5/OiBEj2GeffZg2bVoxL4uZmVlunOBUyc4778yCBdnkzGvWrKGlpYUhQ4awZs0aDj886wKbNGkSp512Gs3NzTz77LPrDcwdPXo0kydPZvLkyRx//PEd1tHVuS+66CJuv/127rjjjnUtQV2577772HPPPQFYsWIFU6ZM4ZRTTuGqq65i2rRpTJs2jSuuuILFixcD2eDuX//610yZMoULL7ywtBfJzMysQpzgVMnLL7/MjjvuCLzVjTR79mwWL17M0qVLWbt2Lbfffjvjxo3jiCOOYNGiRdx9993rvn/QoEGsWLGCm266iREjRqwrv+qqq2hpaeH000/v9NwAy5cvZ/DgwUjigAMOAODhhx+mpaWFlpYWVqxYAcC5557LBz7wAV5//fV15xw+fDiSmDt3LsOGDaN379707t2bYcOG8cILLwCw//77AzBkyBCWLVuW4ytpZmbWPSc4VbBs2TK+9a1vceKJ68992K9fP84880y+/e1vM3XqVEaOHMk999zDPffcw1133cWkSZPWO/7ss8/m2GOPXW+On3POOYfW1tZ1A5A7OjdAnz59mD9/PgCPPfYYAIcccsi68UNbb7018NYYnPHjx6+73b5tkPLQoUN56qmnWLlyJStXrmT27NkMHToUgJkzZwLw0ksv0bdv3/JfNDMzszI09F1UtTZq1CiamppYu3Ytn/jEJzj00EP/5ZjRo0czbNgwlixZwkknnbSufLfddmPOnDksX758XdlRRx3FUUcdVXT9bef+8pe/zPe+9z1GjBjB2972Nvr06VPSz7P99ttz1llnccgh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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "gap_22_prob = (df_gap22_ram_prob['foundCandidBSlotRMD'].astype(float))\n", - "gap_22 = (df_gap22_ram_prob['numRdMissDirty'].astype(float))\n", - "\n", - "gap_25_prob = (df_gap25_ram_prob['foundCandidBSlotRMD'].astype(float))\n", - "gap_25 = (df_gap25_ram_prob['numRdMissDirty'].astype(float))\n", - "\n", - "npb_C_prob = (df_npbC_ram_prob['foundCandidBSlotRMD'].astype(float))\n", - "npb_C = (df_npbC_ram_prob['numRdMissDirty'].astype(float))\n", - "\n", - "npb_D_prob = (df_npbD_ram_prob['foundCandidBSlotRMD'].astype(float))\n", - "npb_D = (df_npbD_ram_prob['numRdMissDirty'].astype(float))\n", - "\n", - "################################## \n", - "# Multi bar Chart1\n", - "app_gap = df_gap22_ram_prob['app']\n", - "\n", - "app_npb = df_npbC_ram_prob['app']\n", - "\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,3)\n", - "plt.ylim([0,100])\n", - "barWidth = 1\n", - "tickSize = 2\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*tickSize-barWidth/2, 100*gap_22_prob[i]/gap_22[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", - "\n", - "offset = i+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar((offset+i)*tickSize-barWidth/2, 100*npb_C_prob[i]/npb_C[i], width=1, color=cmap(1))\n", - "\n", - "plt.figtext(0.25, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.7, -0.01, \"NPB-C\")\n", - "\n", - "brLab = np.arange(len(app_gap)+len(app_npb))\n", - "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", - "\n", - "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", - "\n", - "plt.ylabel(\"Percentage of probed Rd-Md\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()\n", - "\n", - "###############################################################################\n", - "# Multi bar Chart2\n", - "app_gap = df_gap25_ram_prob['app']\n", - "\n", - "app_npb = df_npbD_ram_prob['app']\n", - "\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,3)\n", - "plt.ylim([0,100])\n", - "barWidth = 1\n", - "tickSize = 2\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*tickSize-barWidth/2, 100*gap_25_prob[i]/gap_25[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", - " \n", - "offset = i+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar((offset+i)*tickSize-barWidth/2, 100*npb_D_prob[i]/npb_D[i], width=1, color=cmap(1))\n", - " \n", - "plt.figtext(0.25, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.70, -0.01, \"NPB-D\")\n", - "\n", - "brLab = np.arange(len(app_gap)+len(app_npb))\n", - "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", - "\n", - "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", - "\n", - "plt.ylabel(\"Percentage of probed Rd-Md\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjgAAADfCAYAAAD7q6nlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAhY0lEQVR4nO3de5xXVb3/8de7EUUMQWH0oIMyXn7mhZOXUTHpNEGGmoT1S4P8qVjGsaS8dNX6RZ4fp6sejkc9+gAlLElRi7zm5ZgkWpCgIgpahrchlMESI/ECfH5/7DX4dZj7zPfCnvfz8ZjHfPfa+7vXZ77f7+z5zFprr6WIwMzMzCxP3lPuAMzMzMx6mhMcMzMzyx0nOGZmZpY7TnDMzMwsd5zgmJmZWe5sU+4AumPw4MExbNiwcodh1qs8/fTTAOy3335ljsTMDBYvXrwmIqqbl2/VCc6wYcNYtGhRucMw61Xq6+sBmDdvXlnjMDMDkPR8S+XuojIzM7PccYJjZmZmueMEx8zMzHJnqx6D05K3336bhoYG3njjjXKHYu3o27cvNTU19OnTp9yhmJlZzuQuwWloaKB///4MGzYMSeUOx1oREbzyyis0NDRQW1tb7nDMzCxnctdF9cYbbzBo0CAnNxVOEoMGDXJLm5mZFUXuEhzAyc1Wwu+TmZkVS9G6qCTNBE4AVkfEQc32fQW4GKiOiDXK/tJdChwPvA5MjIhHuhvDiCl3d/cUACy4aEyr+9auXcu4ceMAeOyxx9h///3ZbrvtWLNmDf3796eqqoqI4POf/zwTJ04EoLa2lj333JONGzcybNgwZs2aRVVVFQDf+973mDFjBitWrNicANTW1jJ69GiuvvpqAH72s59x2mmn8eyzz9J8osO2zt1k6tSp1NTUbI6nycSJE1myZAk77rgj733ve5k9ezYDBw5s9/WZNWsWDQ0NfPvb3273WDMzs1IoZgvOLODY5oWShgIfBV4oKD4O2Dd9TQKuLGJcPWrAgAHMmzePefPmcfDBB3PTTTcxb948Bg8ezE033cSDDz7IHXfcwaxZs7j//vsBqKqqYt68ecyfP58+ffpwzz33bD7f7bffzqhRo3jooYc2l1VVVfHCCy/w5ptvAnDzzTdz2GGHtRhPW+fuiMsuu4zf/va3HH300Vx11VXv2rdx48ZOncvMzKxcipbgRMQDwF9b2DUN+DoQBWXjgJ9GZgEwUNKQYsVWagMHDuRb3/oWP//5z99VvmnTJl599VUispfi0Ucf5cADD+QLX/gC11133buOPe6447jjjjtYvXo1ffr0abdlpfm5H3jgAQ455BDGjh3LwoUL24350EMP5fnnn2fWrFmcdNJJnHjiiVx66aXMmDGDI488kiOPPJKZM2duPn7hwoWMHTuWQw45hPnz5wOwdOlSPvKRjzBq1ChOPvlk1q9f3269ZmZmPaGkY3AkjQNWRsSSZrt2B14s2G5IZS2dY5KkRZIWNTY2FinSnjd06FBWrlwJZC0h9fX1DBs2jI0bNzJmTNYFNnv2bE4//XTq6upYtmwZb7/99ubnjx8/njlz5jBnzhxOPvnkVutp7dznn38+t9xyC7feeuvmlqC23HPPPRx44IEArFu3jrlz53Lqqady+eWXM3/+fObPn8+ll15K03vw9ttvc9tttzF37lzOO+88AM4++2xmzpzJb37zG44++miuueaaLrxyZmZmnVeyBEdSP+BC4DvdOU9ETI+Iuoioq67eYm2tivXiiy+y++5ZztbUjbR06VIaGxt59dVX2bRpE7fccgtTp07l2GOPZfXq1dx5552bnz9kyBDWrVvHDTfcwNixYzeXX3755dTX13PmmWe2em6A1157jT322ANJHHHEEQA8+OCD1NfXU19fz7p16wD40pe+xIc+9CHWr1+/+ZwjRoxAEitWrGD48OFsu+22bLvttgwfPpxnn30WgMMPPxzI1gdbu3YtAE8++SSnnXYa9fX1XH/99bz00kvFennNzMzepZTz4OwN1AJL0uDZGuARSUcAK4GhBcfWpLJcWLt2Ld///ve3GIQ7YMAAzjrrLH74wx8yZswYxo0bx8UXXwzAn//8Zy644ILNA5ghaxFZtmwZ22+//eayyZMnM3ny5C3qLDz3j370I/r3709DQwM1NTU8/PDD7LPPPowcOXKLBRMvu+wyRo4c+a6ypkHKtbW1PP7447z11ltA1gVVW1vLsmXLWLx4MQAvvPACO+64IwAHHXQQ119/PUOGZL2NTc8zMzMrtpIlOBGxFNilaVvSc0BduovqVmCypBuAI4G1EbGqVLEVy0knnURVVRWbNm3is5/9LKNGjdrimPHjxzN8+HDWrFnDZz7zmc3le++9N8uXL+e1117bXHb88cdz/PHHd7j+pnNfeOGF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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "gap_22_prob = df_gap22_ram_prob['actDelayedDueToTagAct'].astype(float)/1000\n", - "gap_25_prob = df_gap25_ram_prob['actDelayedDueToTagAct'].astype(float)/1000\n", - "npb_C_prob = df_npbC_ram_prob['actDelayedDueToTagAct'].astype(float)/1000\n", - "npb_D_prob = df_npbD_ram_prob['actDelayedDueToTagAct'].astype(float)/1000\n", - "################################## \n", - "# Multi bar Chart1\n", - "app_gap = df_gap22_ram_prob['app']\n", - "#app_gap[len(app_gap)] = \"gmean\"\n", - "\n", - "app_npb = df_npbC_ram_prob['app']\n", - "#app_npb[len(app_npb)] = \"gmean\"\n", - "\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,3)\n", - "plt.ylim([0,150])\n", - "barWidth = 1\n", - "tickSize = 2\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*tickSize-barWidth/2, gap_22_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Prob' if i==0 else None)\n", - "\n", - "offset = i+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar((offset+i)*tickSize-barWidth/2, npb_C_prob[i], width=1, color=cmap(1))\n", - "\n", - "plt.figtext(0.25, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.7, -0.01, \"NPB-C\")\n", - "\n", - "brLab = np.arange(len(app_gap)+len(app_npb))\n", - "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", - "\n", - "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", - "# plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"ACT delayed (K)\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()\n", - "\n", - "###############################################################################\n", - "# Multi bar Chart2\n", - "app_gap = df_gap25_ram_prob['app']\n", - "#app_gap[len(app_gap)] = \"gmean\"\n", - "\n", - "app_npb = df_npbD_ram_prob['app']\n", - "#app_npb[len(app_npb)] = \"gmean\"\n", - "\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,3)\n", - "plt.ylim([0,150])\n", - "barWidth = 1\n", - "tickSize = 2\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*tickSize-barWidth/2, gap_25_prob[i], width=barWidth, color=cmap(1), label='TDRAM-Rd-Probe' if i==0 else None)\n", - "offset = i+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar((offset+i)*tickSize-barWidth/2, npb_D_prob[i], width=1, color=cmap(1))\n", - "\n", - "plt.figtext(0.25, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.70, -0.01, \"NPB-D\")\n", - "\n", - "brLab = np.arange(len(app_gap)+len(app_npb))\n", - "plt.xticks(brLab*tickSize-0.5, list(app_gap)+list(app_npb))\n", - "\n", - "plt.axvline(x=(offset-0.5)*tickSize-0.5, color='black')\n", - "# plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"ACT delayed (K)\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.10" - }, - "orig_nbformat": 4, - "vscode": { - "interpreter": { - "hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/data_plot_compare_hours.ipynb b/data_plot_compare_hours.ipynb deleted file mode 100644 index 78c19347e8..0000000000 --- a/data_plot_compare_hours.ipynb +++ /dev/null @@ -1,772 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "import numpy as np\n", - "import sys\n", - "from matplotlib import pyplot as plt\n", - "import os\n", - "\n", - "cmap = plt.get_cmap('Set1')\n", - "\n", - "Stats = ['simSeconds ',\n", - "'hostSeconds ',\n", - "'system.mem_ctrl.readReqs ',\n", - "'system.mem_ctrl.writeReqs ',\n", - "'system.mem_ctrl.servicedByWrQ ',\n", - "'system.mem_ctrl.mergedWrBursts ',\n", - "'system.mem_ctrl.numTotHits ',\n", - "'system.mem_ctrl.numTotMisses ',\n", - "'system.mem_ctrl.numColdMisses ',\n", - "'system.mem_ctrl.numHotMisses ',\n", - "'system.mem_ctrl.numRdMissClean ',\n", - "'system.mem_ctrl.numRdMissDirty ',\n", - "'system.mem_ctrl.numRdHit ',\n", - "'system.mem_ctrl.numWrMissClean ',\n", - "'system.mem_ctrl.numWrMissDirty ',\n", - "'system.mem_ctrl.numWrHit ',\n", - "'system.mem_ctrl.numRdHitDirty ',\n", - "'system.mem_ctrl.numRdHitClean ',\n", - "'system.mem_ctrl.numWrHitDirty ',\n", - "'system.mem_ctrl.numWrHitClean ',\n", - "'system.o3Cpu0.thread_0.numInsts ',\n", - "'system.o3Cpu1.thread_0.numInsts ',\n", - "'system.o3Cpu2.thread_0.numInsts ',\n", - "'system.o3Cpu3.thread_0.numInsts ',\n", - "'system.o3Cpu4.thread_0.numInsts ',\n", - "'system.o3Cpu5.thread_0.numInsts ',\n", - "'system.o3Cpu6.thread_0.numInsts ',\n", - "'system.o3Cpu7.thread_0.numInsts ',\n", - "'system.mem_ctrl.avgRdBWSys ',\n", - "'system.mem_ctrl.avgWrBWSys ',\n", - "'system.mem_ctrl.avgORBLen ',\n", - "'system.far_mem_ctrl.avgRdBWSys ',\n", - "'system.far_mem_ctrl.avgWrBWSys ',\n", - "'system.loc_mem_ctrl.avgRdBWSys ',\n", - "'system.loc_mem_ctrl.avgWrBWSys ',\n", - "'system.loc_mem_ctrl.dram.readBursts ',\n", - "'system.loc_mem_ctrl.dram.writeBursts ',\n", - "'system.loc_mem_ctrl.dram_2.readBursts ',\n", - "'system.loc_mem_ctrl.dram_2.writeBursts ',\n", - "'system.far_mem_ctrl.dram.readBursts ',\n", - "'system.far_mem_ctrl.dram.writeBursts ',\n", - "'system.loc_mem_ctrl.dram.avgRdBW ',\n", - "'system.loc_mem_ctrl.dram.avgWrBW ',\n", - "'system.loc_mem_ctrl.dram_2.avgRdBW ',\n", - "'system.loc_mem_ctrl.dram_2.avgWrBW ',\n", - "'system.far_mem_ctrl.dram.avgRdBW ',\n", - "'system.far_mem_ctrl.dram.avgWrBW ',\n", - "'system.loc_mem_ctrl.dram.busUtil ',\n", - "'system.loc_mem_ctrl.dram.busUtilRead ',\n", - "'system.loc_mem_ctrl.dram.busUtilWrite ',\n", - "'system.loc_mem_ctrl.dram_2.busUtil ',\n", - "'system.loc_mem_ctrl.dram_2.busUtilRead ',\n", - "'system.loc_mem_ctrl.dram_2.busUtilWrite ',\n", - "'system.far_mem_ctrl.dram.busUtil ',\n", - "'system.far_mem_ctrl.dram.busUtilRead ',\n", - "'system.far_mem_ctrl.dram.busUtilWrite ',\n", - "'system.far_mem_ctrl.dram.bytesRead ',\n", - "'system.far_mem_ctrl.dram.bytesWritten ',\n", - "'system.loc_mem_ctrl.dram.bytesRead ',\n", - "'system.loc_mem_ctrl.dram.bytesWritten ',\n", - "'system.loc_mem_ctrl.dram_2.bytesRead ',\n", - "'system.loc_mem_ctrl.dram_2.bytesWritten ',\n", - "'system.mem_ctrl.avgTimeTagCheckRes ',\n", - "'system.mem_ctrl.avgTimeTagCheckResRd ',\n", - "'system.mem_ctrl.avgTimeTagCheckResWr ',\n", - "'system.mem_ctrl.avgPktRespTimeRd ',\n", - "'system.mem_ctrl.avgPktRespTimeWr ',\n", - "'system.mem_ctrl.avgPktORBTime ',\n", - "'system.mem_ctrl.avgPktORBTimeRd ',\n", - "'system.mem_ctrl.avgPktORBTimeWr ',\n", - "'system.mem_ctrl.avgTimeInLocRead ',\n", - "'system.mem_ctrl.avgTimeInLocWrite ',\n", - "'system.mem_ctrl.avgTimeInFarRead '\n", - " ]\n", - "\n", - "dfCols = [\n", - " 'app',\n", - " 'simSeconds',\n", - " 'hostSeconds',\n", - " 'readReqs',\n", - " 'writeReqs',\n", - " 'servicedByWrQ',\n", - " 'mergedWrBursts',\n", - " 'numTotHits',\n", - " 'numTotMisses',\n", - " 'numColdMisses',\n", - " 'numHotMisses',\n", - " 'numRdMissClean',\n", - " 'numRdMissDirty',\n", - " 'numRdHit',\n", - " 'numWrMissClean',\n", - " 'numWrMissDirty',\n", - " 'numWrHit',\n", - " 'numRdHitDirty',\n", - " 'numRdHitClean',\n", - " 'numWrHitDirty',\n", - " 'numWrHitClean',\n", - " 'numInsts0',\n", - " 'numInsts1',\n", - " 'numInsts2',\n", - " 'numInsts3',\n", - " 'numInsts4',\n", - " 'numInsts5',\n", - " 'numInsts6',\n", - " 'numInsts7',\n", - " 'avgRdBWSys',\n", - " 'avgWrBWSys',\n", - " 'avgORBLen',\n", - " 'farAvgRdBWSys',\n", - " 'farAvgWrBWSys',\n", - " 'locAvgRdBWSys',\n", - " 'locAvgWrBWSys',\n", - " 'readBursts1',\n", - " 'writeBursts1',\n", - " 'readBursts2',\n", - " 'writeBursts2',\n", - " 'readBursts3',\n", - " 'writeBursts3',\n", - " 'loc1AvgRdBW',\n", - " 'loc1AvgWrBW',\n", - " 'loc2AvgRdBW',\n", - " 'loc2AvgWrBW',\n", - " 'farAvgRdBW',\n", - " 'farAvgWrBW',\n", - " 'loc1BusUtil',\n", - " 'loc1BusUtilRead',\n", - " 'loc1BusUtilWrite',\n", - " 'loc2BusUtil',\n", - " 'loc2BusUtilRead',\n", - " 'loc2BusUtilWrite',\n", - " 'farBusUtil',\n", - " 'farBusUtilRead',\n", - " 'farBusUtilWrite',\n", - " 'farBytesRead',\n", - " 'farBytesWritten',\n", - " 'loc1BytesRead',\n", - " 'loc1BytesWritten',\n", - " 'loc2BytesRead',\n", - " 'loc2BytesWritten',\n", - " 'avgTimeTagCheckRes',\n", - " 'avgTimeTagCheckResRd',\n", - " 'avgTimeTagCheckResWr',\n", - " 'avgPktRespTimeRd',\n", - " 'avgPktRespTimeWr',\n", - " 'avgPktORBTime',\n", - " 'avgPktORBTimeRd',\n", - " 'avgPktORBTimeWr',\n", - " 'avgTimeInLocRead',\n", - " 'avgTimeInLocWrite',\n", - " 'avgTimeInFarRead'\n", - "\n", - " ]\n", - "##########################################################\n", - "\n", - "def getStat(filename, stat):\n", - " filename = os.path.join(filename).replace('\\\\','/')\n", - " #print(stat)\n", - " #print(filename)\n", - " try:\n", - " with open(filename) as f:\n", - " readlines = f.readlines()\n", - " for l in readlines:\n", - " if stat in l:\n", - " return l\n", - " return 0.0 #for cases where stat was not found\n", - " except: #for cases where the file was not found\n", - " return 0.0\n", - "\n", - "##########################################################\n", - "\n", - "def creatDataFrame(dataDir, suite):\n", - " app = []\n", - " if suite == \"GAPBS\":\n", - " app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", - " if suite == \"NPB\":\n", - " app = ['bt', 'cg', 'ft', 'is', 'lu', 'mg', 'sp', 'ua']\n", - " rows = []\n", - " for a in app:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}/stats.txt'.format(dataDir, a)\n", - " ret_line = getStat(time_file_path, stat)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - " df = pd.DataFrame(rows, columns= dfCols)\n", - " df['totNumInsts'] = df['numInsts0'].astype(int)+df['numInsts1'].astype(int)+df['numInsts2'].astype(int)+df['numInsts3'].astype(int)+df['numInsts4'].astype(int)+df['numInsts5'].astype(int)+df['numInsts6'].astype(int)+df['numInsts7'].astype(int)\n", - " df['totBW'] = (df['avgRdBWSys'].astype(float)+df['avgWrBWSys'].astype(float))/1000000000\n", - " df['coldRate'] = (df['numColdMisses'].astype(float) / df['numTotMisses'].astype(float)) *100\n", - " df['injRate'] = (df['readReqs'].astype(float) + df['writeReqs'].astype(float))*64/1000000000 / df['simSeconds'].astype(float)\n", - " df['BIPS'] = (df['totNumInsts'].astype(float)/1000000000)/df['simSeconds'].astype(float)\n", - " \n", - " df['accAmp'] = (df['farBytesRead'].astype(float) + df['farBytesWritten'].astype(float) +\n", - " df['loc1BytesRead'].astype(float) + df['loc1BytesWritten'].astype(float) + \n", - " df['loc2BytesRead'].astype(float) + df['loc2BytesWritten'].astype(float)) / (df['readReqs'].astype(float) * 64 + df['writeReqs'].astype(float) * 64)\n", - " \n", - " df['BWBloat'] = (df['loc1AvgRdBW'].astype(float) + df['loc1AvgWrBW'].astype(float) +\n", - " df['loc2AvgRdBW'].astype(float) + df['loc2AvgWrBW'].astype(float) +\n", - " df['farAvgRdBW'].astype(float) + df['farAvgWrBW'].astype(float)) / ((df['avgRdBWSys'].astype(float) + df['avgWrBWSys'].astype(float)) / 1000000)\n", - " return df" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "df_gap22_dc_ram = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/rambus_g22_nC/GAPBS\", \"GAPBS\")\n", - "df_npbC_dc_ram = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/rambus_g22_nC/NPB\", \"NPB\")\n", - "df_gap22_dc_cas = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/cascade_g22_nC/GAPBS\", \"GAPBS\")\n", - "df_npbC_dc_cas = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/cascade_g22_nC/NPB\", \"NPB\")\n", - "df_gap22_dc_orc = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/oracle_g22_nC/GAPBS\", \"GAPBS\")\n", - "df_npbC_dc_orc = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/oracle_g22_nC/NPB\", \"NPB\")\n", - "df_gap22_noDC = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/noDC_g22_nC/GAPBS\", \"GAPBS\")\n", - "df_npbC_noDC = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/noDC_g22_nC/NPB\", \"NPB\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "df_gap22_dc_ram_3hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/3hrPC/rambus_g22_nC/GAPBS\", \"GAPBS\")\n", - "df_npbC_dc_ram_3hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/3hrPC/rambus_g22_nC/NPB\", \"NPB\")\n", - "df_gap22_dc_cas_3hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/3hrPC/cascade_g22_nC/GAPBS\", \"GAPBS\")\n", - "df_npbC_dc_cas_3hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/3hrPC/cascade_g22_nC/NPB\", \"NPB\")\n", - "df_gap22_dc_orc_3hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/3hrPC/oracle_g22_nC/GAPBS\", \"GAPBS\")\n", - "df_npbC_dc_orc_3hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/3hrPC/oracle_g22_nC/NPB\", \"NPB\")\n", - "df_gap22_noDC_3hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/3hrPC/noDC_g22_nC/GAPBS\", \"GAPBS\")\n", - "df_npbC_noDC_3hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/3hrPC/noDC_g22_nC/NPB\", \"NPB\")\n", - "\n", - "df_gap22_dc_ram_6hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/6hour/6hour/rambus_g22_nC/GAPBS\", \"GAPBS\")\n", - "df_npbC_dc_ram_6hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/6hour/6hour/rambus_g22_nC/NPB\", \"NPB\")\n", - "df_gap22_dc_cas_6hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/6hour/6hour/cascade_g22_nC/GAPBS\", \"GAPBS\")\n", - "df_npbC_dc_cas_6hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/6hour/6hour/cascade_g22_nC/NPB\", \"NPB\")\n", - "df_gap22_dc_orc_6hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/6hour/6hour/oracle_g22_nC/GAPBS\", \"GAPBS\")\n", - "df_npbC_dc_orc_6hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/6hour/6hour/oracle_g22_nC/NPB\", \"NPB\")\n", - "df_gap22_noDC_6hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/6hour/6hour/noDC_g22_nC/GAPBS\", \"GAPBS\")\n", - "df_npbC_noDC_6hr = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/analysisRestore/6hour/6hour/noDC_g22_nC/NPB\", \"NPB\")" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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KrQEarWat956i/bt23PixAnuueceHnnkEd59911bZ60iRdiNUaNGKd26dVNMJpNl2eLFi5Vu3bopR44cUQDl77//tmEOa1db/hVFUe6//35l1KhRlnU//PCD4uHhoeTm5jZ3VuuUm5ur6HQ65aOPPqqy7oMPPlDc3d2VjIwMG+SsYer6nYSFhSnTpk2zVfYaZNSoUcr9999v+bxkyRKlffv2il6vt12mytm9e7cCKCdPnqywPCMjQwGU6Ojoardzd3dXVq1aVe26lStXKoCybds2y7JDhw4pgLJ9+/amy3wD1Odv6o033rBJ3upS2/f6vffeU3x9fZWioiLLso8++kgBlL179zZjLhvmjTfeUMLCwiyfAeWnn36yWX4uRdl3257vCXUpf32q7nfg6emprFy5stnzVZNRo0Ypw4cPt3w2GAyKq6urctttt1mWpaWlKYASExOjLF68WOnRo0eFfTz++OMKoGRlZTVXtmtU0/VXURRl1qxZio+Pj1JQUGBZ9t577ylubm6K0WhszmzWqrprZ+/evZWnn3662vTff/+94uvra/2MNZA0hbIzgwcPrtB8YMiQIRw7doy9e/ei0WgYNWqUDXNXt5rybzQaq6SdMGECYWFhREREcNttt/HVV19RWFjYnNmt0aFDhygpKWHcuHFV1sXGxtKnT58W0y64rt9J//79bZW1RomNjWXEiBEVSvdtqXfv3owbN46ePXty/fXX89FHH5GVlYWPjw+zZ89m0qRJXHXVVbz55pukpaVZtlu0aBF33nkn48ePZ9myZVWacmm1WgYMGGD53LVrV7y8vDh06FCznVtlDfme25PavtdHjhyhV69eODk5WZYNHDiwObN32bPne0Jr1KtXL8t7jUaDr68vPXv2tCwLDAwE4OzZsxw5cqTCdQjs6/tR0/W3/HoXFxfL5yFDhpCfn2/zZqUN8c8//zBu3DjatGmDu7s7t912GxkZGXb3HZHAooUof7NrLdzd3dmzZw/ffPMNwcHBPPXUU/Tu3dsu2ms6Oztf0rqWyNXV1dZZuCT29nvQaDT8/fff/PHHH0RGRvL222/TpUsXEhMTWblyJTExMQwdOpRvv/2Wzp07s23bNgCWLl3KwYMHueKKK1i3bh2RkZH89NNPNj6b1sne/mZERfZ8T2gIlUplaYJTprS01Ea5qVnlQhmVSlVhWVnhgb02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EsKcOXPqNS+JXq9n+fLl9O7dGxcXF/z8/Bg2bBgrV660q8lEReslnbeFaGFOnDjBsGHD8PLy4sUXX6Rnz57odDri4uL48MMPadOmDVdffbUl/aeffsojjzzCp59+ysMPP1xlfx4eHhw5cgSTycS+ffu4/fbbSU1N5c8//7SkWblyJZMnT6a0tNSSxtXVleeeew6A6dOno9fr+eyzz4iIiODMmTOsXbuWjIyMGs/j8OHDmEwmPvjgAzp27MiBAweYO3cuBQUFlonJtm7dSq9evVi8eDGBgYH8+uuvzJw5E09PT6688sqm+pEKIUSTcHJy4uWXX+bf//433t7eNaY7cuQI7u7uHDt2jHnz5nHVVVexf/9+y4Rozz77LHPnzsVoNHL06FHmzZvHfffdxxdffFHjPvV6PZMmTWLfvn0899xzDBs2DA8PD7Zt28arr75Knz59iIqKaupTFqIi206jIYRoqEmTJilt27ZV8vPzq11fNlGZoihKdHS00qZNG0Wv1yshISHKli1bKqQtm4CtvBdeeEFRq9VKYWGhoigVJ0gqM2fOHGXq1KmKoihKVlaWAijR0dGNPDNFWb58udK+ffta00ydOlW5/fbbG30sIYRoSrNmzVKuvPJKpWvXrsrDDz9sWf7TTz9ZJotcv359lUnNvvrqqwoTMVY3Ud1zzz2nREZG1nr8l19+WVGr1cqePXuqrNPr9TXeM4RoStIUSogWJCMjg7/++ot7770XV1fXatOUVbkDfPLJJ9x88804ODhw880388knn9R5DGdnZ0wmEwaDodr1R48eZd26dQwaNAgANzc33NzcWL16dYXmUZciJycHHx+fRqcRQghb0Gg0vPjii7z99tucPn26XtuUzZNSvhloeSkpKfzyyy+Wa25NvvrqK8aPH0+fPn2qrHNwcKjxniFEU5LAQogW5Pjx4yiKQpcuXSos9/PzszzgL168GIDc3Fz++9//MmPGDABmzJjBd999R35+fo37P3bsGO+//z79+/fH3d3dsvzmm2/Gzc0NJycnunTpQvfu3S3jl2u1WlatWsVnn32Gl5cXw4YN47HHHmP//v0NPre3336bf//73zWm+e6779i5cye33357g/YthBDN5dprryUqKoqnn366zrRpaWm8+uqrtGnTpsJ1ffHixbi5ueHs7Ezbtm1RqVS8/vrrte7r2LFjdO3atdH5F6IxJLAQohXYsWMHsbGxdO/e3VJr8M0339ChQwd69+4NQFRUFGFhYXz77bcVts3JycHNzQ0XFxe6dOlCYGBglQ7Sb7zxBrGxsezbt49ff/2Vo0ePctttt1nWT58+ndTUVH7++WcmT55MdHQ0ffv2ZdWqVQDcddddlsDHzc2tSv5TUlKYPHky119/PXPnzq32HNevX8/tt9/ORx99RPfu3S/5ZyWEENb28ssv89lnn3Ho0KFq17dt2xZXV1dCQkIoKCjghx9+wNHR0bL+4YcfJjY2lv3797N27VoArrjiCoxGI0CF6+ldd90FgCLTkgk7IJ23hWhBOnbsiEql4siRIxWWR0REABer1MHcDOrgwYNotRe/5iaTiU8//ZQ5c+ZYlrm7u7Nnzx7UajXBwcEV9lEmKCiIjh07AtClSxfy8vK4+eabef755y3LnZycmDBhAhMmTODJJ5/kzjvv5Omnn2b27Nk8++yzPPTQQ9WeU2pqKmPGjGHo0KF8+OGH1abZsGEDV111FW+88QYzZ86sz49KCCFsZuTIkUyaNIklS5Ywe/bsKus3bdqEh4cHAQEBFWqHy/j5+VmurZ06dWLFihUMGTKE9evXM378eGJjYy1pPTw8AOjcuTOHDx+2yvkIUV8SWAjRgvj6+jJhwgT+85//sGDBghrbzMbFxbFr1y6io6Mr9EfIzMxk9OjRHD582FJlrlarLTew+iobuaSoqKjGNJGRkaxevRqAgIAAAgICqqRJSUlhzJgx9OvXj5UrV6JWV61EjY6O5sorr+Tll19m3rx5DcqnEELYyrJly4iKiqrSdBWgffv2eHl51Xtfla+51V2zb7nlFh577DH27t1bpZ9FaWkper1e+lkIq5PAQogW5t1332XYsGH079+fpUuX0qtXL9RqNTt37uTw4cP069ePTz75hIEDBzJy5Mgq2w8YMIBPPvmk2nktapKdnU16ejomk4ljx47x7LPP0rlzZ7p160ZGRgbXX389d9xxB7169cLd3Z1du3axfPlyrrnmmhr3mZKSwujRowkLC+PVV1/l3LlzlnVBQUGAufnTlVdeyf3338/06dNJT08HwNHRUTpwCyHsWs+ePbn11lt56623GrxtXl4e6enpKIrCqVOneOSRR/D392fo0KE1brNw4UJ+++03xo0bx3PPPcfw4cMt1+OXX36ZTz75RIabFdZn41GphBCXIDU1VZk/f77Svn17xcHBQXFzc1MGDhyovPLKK0pOTo7i6+urLF++vNptX375ZSUgIEDR6/XVDjdbGWB5qVQqJTg4WLnxxhuVhIQERVEUpbi4WHn00UeVvn37Kp6enoqLi4vSpUsX5YknnrAMWVudlStXVth3+VeZWbNmVbt+1KhRDf6ZCSGENc2aNUu55pprKixLTExUHB0dax1utrKwsLAK1zt/f39l6tSpyt69e+vMQ3FxsfLSSy8pPXv2VJycnBQfHx9l2LBhyqpVq5TS0tJGnJ0Q9aNSFOntI4QQQgghhGgcGRVKCCGEEEII0WgSWAghhBBCCCEaTQILIYQQQgghRKNJYCGEEEIIIYRoNAkshBBCCCGEEI0mgYUQQgghhBCi0SSwEEIIIYQQQjSaBBZCCCGEEEKIRpPAQgghhBBCCNFoElgIIYQQQgghGk0CCyGEEEIIIUSjSWAhhBBCCCGEaLT/B4jOIOIrwDjkAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_dc_cas['app']\n", - "gap = df_gap22_dc_cas['simSeconds'].astype(float) * 1000\n", - "gap_3hr = df_gap22_dc_cas_3hr['simSeconds'].astype(float) * 1000\n", - "gap_6hr = df_gap22_dc_cas_6hr['simSeconds'].astype(float) * 1000\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,1000])\n", - "\n", - "x = np.arange(6)*4+1\n", - "plt.plot(x, gap, label='1 hour', color=cmap(1))\n", - "plt.plot(x, gap_3hr, label='3 hour', color=cmap(2))\n", - "plt.plot(x, gap_6hr, label='6 hour', color=cmap(3))\n", - "plt.scatter(x, gap, color=cmap(1))\n", - "plt.scatter(x, gap_3hr, color=cmap(2))\n", - "plt.scatter(x, gap_6hr, color=cmap(3))\n", - "\n", - "app_npb = df_npbC_dc_cas['app']\n", - "npb = df_npbC_dc_cas['simSeconds'].astype(float) * 1000\n", - "npb_3hr = df_npbC_dc_cas_3hr['simSeconds'].astype(float) * 1000\n", - "npb_6hr = df_npbC_dc_cas_6hr['simSeconds'].astype(float) * 1000\n", - "x=np.arange(6,14)*4+1\n", - "plt.plot(x, npb, color=cmap(1))\n", - "plt.plot(x, npb_3hr, color=cmap(2))\n", - "plt.plot(x, npb_6hr, color=cmap(3))\n", - "plt.scatter(x, npb, color=cmap(1))\n", - "plt.scatter(x, npb_3hr, color=cmap(2))\n", - "plt.scatter(x, npb_6hr, color=cmap(3))\n", - "\n", - "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, 0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=23, color='black')\n", - "\n", - "plt.ylabel(\"Execution Time (ms)\")\n", - "plt.title(\"Cascade Lake\", fontsize = 9)\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_dc_cas['app']\n", - "gap = df_gap22_dc_cas['simSeconds'].astype(float) * 1000\n", - "gap_3h = df_gap22_dc_cas_3hr['simSeconds'].astype(float) * 1000\n", - "gap_6hr = df_gap22_dc_cas_6hr['simSeconds'].astype(float) * 1000\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,1000])\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*4, gap[i], width=1, color=cmap(1), label='1 hour' if i==0 else None)\n", - " plt.bar(i*4+1, gap_3h[i], width=1, color=cmap(2), label='3 hours' if i==0 else None)\n", - " plt.bar(i*4+2, gap_6hr[i], width=1, color=cmap(3), label='6 hours' if i==0 else None)\n", - "\n", - "offset = i*5-2\n", - "app_npb = df_npbC_dc_cas['app']\n", - "npb_cas = df_npbC_dc_cas['simSeconds'].astype(float) * 1000\n", - "npb_cas_3hr = df_npbC_dc_cas_3hr['simSeconds'].astype(float) * 1000\n", - "npb_cas_6hr = df_npbC_dc_cas_6hr['simSeconds'].astype(float) * 1000\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*4+1, npb_cas[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*4+2, npb_cas_3hr[i], width=1, color=cmap(2))\n", - " plt.bar(offset+i*4+3, npb_cas_6hr[i], width=1, color=cmap(3))\n", - "\n", - "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, 0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset-0.25, color='black')\n", - "\n", - "plt.ylabel(\"Execution Time (ms)\")\n", - "plt.title(\"Cascade Lake\", fontsize = 9)\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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Y8mSJbCzs4OTkxNef/111A7cpVAosHLlSnh6ekIikcDf3x+bNm0yc4r1NZX+UaNG4aOPPsLx48fB4/EwatQoAMCXX36JgIAASKVSuLq64oEHHjBvBurQarVYt24d/P39IZFI4OXlhXfffRcAcPPmTcycORMODg6wtrZG//79cebMGTOnuKFRo0ZhyZIlTf6f8vHxwdtvv425c+fC1tYWixcvNnOKGzd//nwcO3YMn3zyCTdZZ1paGq5cuYIpU6bA1tYWcrkcw4cPR0pKitnS+fvvvyM8PBxWVlZwdHTEuHHjUFFRgaNHj2LgwIGwtraGvb09hg0bhvT0dADApUuXMHr0aMjlctja2qJfv344d+4cAGDr1q2wt7fH7t27ud/JhAkTcOPGDbPlEWj+d56eno7nn3++0UlVLUFzv+tTp04hMjISUqkU/fv3x+7duy26edH8+fOxdOlSZGRkgMfjwcfHBwBw33336b23dHVrIy35mmAoHo/XoNbI3t4eW7duNUt6GjNq1CgsXboUy5YtQ7du3eDq6opvv/2WmzhYLpfD398ff/31F/eZPXv2cMdm9OjR2LZtm0U1a27q/Dt//nxMnz4db775JpydnWFra4snn3wSSqXS3EnW01htb2RkJNasWQMA+PjjjxEeHg5ra2t4enri6aefRnl5eccntAVUY2Fhtm3bhoULF+Ls2bM4d+4cFi9eDC8vLyxatAhz585FVFQUPv30U/Tu3Rupqam4deuWuZOsp6n079y5Ey+//DIuX76MnTt3QiwW49y5c3j22Wfx/fffY+jQoSgsLMSJEyfMnQXOqlWr8O2332L9+vW46667kJ2djYSEBJSXl2PkyJHo3r079uzZAzc3N1y4cAFardbcSW5Uc/+nAODDDz/EG2+8gdWrV5s5pU375JNPcO3aNYSFheGtt94CAGg0GowYMQKjRo3C4cOHYWtri5MnT0KtVpsljdnZ2Zg5cybWrVuH++67D2VlZThx4gQYY5g+fToWLVqEn3/+GUqlEmfPnuVuumfPno0+ffrgq6++gkAgQExMDEQiEbffyspKvPvuu9i+fTvEYjGefvppPPLIIzh58qRZ8gk0/zvv3bs3Fi9ezP3/sjRN/a5LS0sxdepUTJ48GT/99BPS09MtvundJ598gp49e+Kbb75BdHQ0BAIBXFxcsGXLFkycOBECgcDc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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_dc_ram['app']\n", - "gap = df_gap22_dc_ram['simSeconds'].astype(float) * 1000\n", - "gap_3hr = df_gap22_dc_ram_3hr['simSeconds'].astype(float) * 1000\n", - "gap_6hr = df_gap22_dc_ram_6hr['simSeconds'].astype(float) * 1000\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,1000])\n", - "\n", - "x = np.arange(6)*4+1\n", - "plt.plot(x, gap, label='1 hour', color=cmap(1))\n", - "plt.plot(x, gap_3hr, label='3 hour', color=cmap(2))\n", - "plt.plot(x, gap_6hr, label='6 hour', color=cmap(3))\n", - "plt.scatter(x, gap, color=cmap(1))\n", - "plt.scatter(x, gap_3hr, color=cmap(2))\n", - "plt.scatter(x, gap_6hr, color=cmap(3))\n", - "\n", - "app_npb = df_npbC_dc_ram['app']\n", - "npb = df_npbC_dc_ram['simSeconds'].astype(float) * 1000\n", - "npb_3hr = df_npbC_dc_ram_3hr['simSeconds'].astype(float) * 1000\n", - "npb_6hr = df_npbC_dc_ram_6hr['simSeconds'].astype(float) * 1000\n", - "x=np.arange(6,14)*4+1\n", - "plt.plot(x, npb, color=cmap(1))\n", - "plt.plot(x, npb_3hr, color=cmap(2))\n", - "plt.plot(x, npb_6hr, color=cmap(3))\n", - "plt.scatter(x, npb, color=cmap(1))\n", - "plt.scatter(x, npb_3hr, color=cmap(2))\n", - "plt.scatter(x, npb_6hr, color=cmap(3))\n", - "\n", - "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, 0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=23, color='black')\n", - "\n", - "plt.ylabel(\"Execution Time (ms)\")\n", - "plt.title(\"TDRAM\", fontsize = 9)\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_dc_ram['app']\n", - "gap = df_gap22_dc_ram['simSeconds'].astype(float) * 1000\n", - "gap_3hr = df_gap22_dc_ram_3hr['simSeconds'].astype(float) * 1000\n", - "gap_6hr = df_gap22_dc_ram_6hr['simSeconds'].astype(float) * 1000\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,1000])\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*4, gap[i], width=1, color=cmap(1), label='1 hour' if i==0 else None)\n", - " plt.bar(i*4+1, gap_3h[i], width=1, color=cmap(2), label='3 hours' if i==0 else None)\n", - " plt.bar(i*4+2, gap_6hr[i], width=1, color=cmap(3), label='6 hours' if i==0 else None)\n", - "\n", - "offset = i*5-2\n", - "app_npb = df_npbC_dc_ram['app']\n", - "npb = df_npbC_dc_ram['simSeconds'].astype(float) * 1000\n", - "npb_3hr = df_npbC_dc_ram_3hr['simSeconds'].astype(float) * 1000\n", - "npb_6hr = df_npbC_dc_ram_6hr['simSeconds'].astype(float) * 1000\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*4+1, npb[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*4+2, npb_3hr[i], width=1, color=cmap(2))\n", - " plt.bar(offset+i*4+3, npb_6hr[i], width=1, color=cmap(3))\n", - "\n", - "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, 0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset-0.25, color='black')\n", - "\n", - "plt.ylabel(\"Execution Time (ms)\")\n", - "plt.title(\"TDRAM\", fontsize = 9)\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_noDC['app']\n", - "gap = df_gap22_noDC['simSeconds'].astype(float) * 1000\n", - "gap_3hr = df_gap22_noDC_3hr['simSeconds'].astype(float) * 1000\n", - "gap_6hr = df_gap22_noDC_6hr['simSeconds'].astype(float) * 1000\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,1000])\n", - "\n", - "x = np.arange(6)*4+1\n", - "plt.plot(x, gap, label='1 hour', color=cmap(1))\n", - "plt.plot(x, gap_3hr, label='3 hour', color=cmap(2))\n", - "plt.plot(x, gap_6hr, label='6 hour', color=cmap(3))\n", - "plt.scatter(x, gap, color=cmap(1))\n", - "plt.scatter(x, gap_3hr, color=cmap(2))\n", - "plt.scatter(x, gap_6hr, color=cmap(3))\n", - "\n", - "app_npb = df_npbC_noDC['app']\n", - "npb = df_npbC_noDC['simSeconds'].astype(float) * 1000\n", - "npb_3hr = df_npbC_noDC_3hr['simSeconds'].astype(float) * 1000\n", - "npb_6hr = df_npbC_noDC_6hr['simSeconds'].astype(float) * 1000\n", - "x=np.arange(6,14)*4+1\n", - "plt.plot(x, npb, color=cmap(1))\n", - "plt.plot(x, npb_3hr, color=cmap(2))\n", - "plt.plot(x, npb_6hr, color=cmap(3))\n", - "plt.scatter(x, npb, color=cmap(1))\n", - "plt.scatter(x, npb_3hr, color=cmap(2))\n", - "plt.scatter(x, npb_6hr, color=cmap(3))\n", - "\n", - "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, 0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=23, color='black')\n", - "\n", - "plt.ylabel(\"Execution Time (ms)\")\n", - "plt.title(\"No DRAM $\", fontsize = 9)\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_noDC['app']\n", - "gap = df_gap22_noDC['simSeconds'].astype(float) * 1000\n", - "gap_3h = df_gap22_noDC_3hr['simSeconds'].astype(float) * 1000\n", - "gap_6hr = df_gap22_noDC_6hr['simSeconds'].astype(float) * 1000\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,1000])\n", - "\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*4, gap[i], width=1, color=cmap(1), label='1 hour' if i==0 else None)\n", - " plt.bar(i*4+1, gap_3h[i], width=1, color=cmap(2), label='3 hours' if i==0 else None)\n", - " plt.bar(i*4+2, gap_6hr[i], width=1, color=cmap(3), label='6 hours' if i==0 else None)\n", - "\n", - "offset = i*5-2\n", - "app_npb = df_npbC_noDC['app']\n", - "npb = df_npbC_noDC['simSeconds'].astype(float) * 1000\n", - "npb_3hr = df_npbC_noDC_3hr['simSeconds'].astype(float) * 1000\n", - "npb_6hr = df_npbC_noDC_6hr['simSeconds'].astype(float) * 1000\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*4+1, npb[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*4+2, npb_3hr[i], width=1, color=cmap(2))\n", - " plt.bar(offset+i*4+3, npb_6hr[i], width=1, color=cmap(3))\n", - "\n", - "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, 0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset-0.25, color='black')\n", - "\n", - "plt.ylabel(\"Execution Time (ms)\")\n", - "plt.title(\"No DRAM $\", fontsize = 9)\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAx4AAADOCAYAAACw7NSMAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAACWtUlEQVR4nOzdd1xTV//A8c9NQsLeWwFRHIAg4t5bq1Vr1bZ2qR3aPt3tYx9rl3ba5c9uW6t1dGuttlr3qHuBIiAORET23iNk3N8fUZQCisr2vF+vaHLvyc05AZL7veec75FkWZYRBEEQBEEQBEGoR4rGroAgCIIgCIIgCC2fCDwEQRAEQRAEQah3IvAQBEEQBEEQBKHeicBDEARBEARBEIR6JwIPQRAEQRAEQRDqnQg8BEEQBEEQBEGodyLwEARBEARBEASh3onAQxAEQRAEQRCEeicCD0EQBEEQBEEQ6p0IPARBEAShmZg+fXpjV0EQBOGmicBDEAShCbO2tq64KZVKNBpNxePRo0cDIEkSlpaW2Nra4ujoSJ8+ffj000/R6XQVx1m+fDlKpRJra2tsbGzw8/Nj4cKFVV6vuLgYW1tbevXqVWXf9OnTkSSJJUuWVNq+evVqJEliwoQJNbZDkiQiIiJu7k24VH9Jkpg1a1al7RMmTGDevHk3fdzp06ejVquxsbHBzs6ODh068OSTTxIfH1+p3OX32NraGjc3N6ZMmUJGRkaV4z366KNIksSpU6cqbf/nn3+QJIn+/ftX2q7VanFyckKSJPLy8m66HYIgCM2BCDwEQRCasKKioorbgAED+PDDDyseb9q0qaLcgQMHKCgoID09nQ8++IAVK1Ywbtw4ZFmuKBMUFERRURGFhYWsXLmS1157jZ07d1Z6vVWrVqFUKjl69CjR0dFV6tOxY0eWLVtWaduyZcvo1KlTHbe8KgcHBxYtWkRiYmKdHvepp56isLCQ/Px8tmzZglqtpmvXrlWChwMHDlBUVERMTAyZmZlVgqDCwkJWrVqFo6MjS5curfI6NjY2XLhwgdjY2Iptf/75J66urtet48qVK/H39+eXX37B1dWVQYMGkZube5MtFgRBaBwi8BAEQWhBzMzMGDRoEH/88Qe7d++uFJxcrW/fvgQGBhIeHl5p+9KlS3nkkUcYOHBgtSfPI0aMICEhgbNnzwKQkpLC0aNHr9nb0bNnz4rXtLa25v333wcgLCyMfv36YW9vT0BAAL/88ss12+bt7c2kSZOYO3dujWVu9Jj/5uvry+eff07v3r1rfB0nJycmTpxY5b377bffsLKy4sMPP+SHH36o1OMEoFAoePjhhysFbsuWLeORRx65Zp2Sk5N59NFH+b//+z/uv/9+EhISeP3111GpVDfUNkEQhMYmAg9BEIQWyNfXl27durF79+4q+2RZZs+ePURHR9OhQ4eK7WfOnGH//v1Mnz6dadOm8eOPP1JeXl7puUqlkqlTp/L9998DsGLFCu699140Gk2NdTly5Ahwpcfg1VdfJS8vjzvuuIMpU6aQmZnJokWLmDFjBvv3779mu95++21+++03YmJiquy72WNWZ/LkydW+dwDp6emsXr260nsHpqDtwQcfZMqUKRQXF7N+/foqz50+fTorV67EYDCQnJxMWFgYd9111zXrkpWVhSRJ9OvXDwALCwtGjBiBjY3NDbdLEAShMYnAQxAEoYVq1aoVOTk5FY+joqKwt7fH3NycQYMG8d///pfx48dX7F+6dCkhISEEBwczefJkSkpK+PPPP6scd/r06fzwww/o9XqWL19+3Sv21fn7779xcXHh2WefreileeCBB1ixYsU1n9emTRtmzpzJq6++WmfHrM6/3zuAAQMGYGNjg7u7O6WlpXz55ZcV+2JiYjh06BDTpk3D2tqau+++u9oeo44dO+Lj48PWrVtZsWIF99133zWDNjANkRs7dixBQUHs3r2bFStWkJWVdcNtEgRBaGwi8BAEQWihkpOTcXR0rHgcFBREXl4ehYWFvPHGG+zcuRO9Xg+AXq9n5cqVTJs2DTDNR6jp5LlDhw74+vry5ptvolar6d69+w3XLSkpiTZt2lTa1rZtW5KSkq773Ndee41du3Zx8ODBGzrm6NGjKybmXx7uVZN/v3cAe/fupbCwkIMHD5KUlERKSkrFvqVLl9KlSxe6dOkCwLRp09iyZQvJyclVjv3II4/w/fffVxu0Xbx4sVJCgYsXL6JQKFi7di1r166lVatWrFq1Cj8/vyrtFwRBaOpE4CEIgtACXbhwgfDwcAYPHlxln1qt5q233qK0tJSvv/4agA0bNpCens4777yDu7s77u7u/PXXX2zbtq3aydyPPPIIH3zwQa17OyRJqvS4devWXLhwoUqdW7dufd1jOTs78/LLLzN79uwbOuamTZsqJuZX12Nytd9//73a9w6gd+/ezJo1iyeeeAJZltHpdPzwww+cPXu24r178MEHMRgMLF++vMrz77vvPjZv3oyFhQXdunWrtM/b27tSQgFvb++KfaGhofj5+fH3339zzz33sHjx4mu2QRAEoakRgYcgCEILotPp2Lt3L5MmTWLQoEHccccd1ZaTJInXXnuN999/n5KSEpYuXcr48eM5efIkERERREREcPbsWfz8/KpksQJ44IEH2Lp1KzNmzKhVvdzc3IiLi6t4PGbMGDIyMvj666/R6/Xs3buXn376ialTp9bqeC+++CKxsbHs27evzo4JkJCQwIsvvsihQ4eumab3ySefJCkpiTVr1vDXX39RUFDAsWPHKt67EydO8MYbb/D9999XyiwGpt6kXbt2sWrVqlrVKTY2lo0bN2I0GgFTyuPY2Fg8PDxq3S5BEISmQAQegiAILUDfvn2xsbHB1dWVl19+mYceeoj169dX6Wm42sSJE3F0dOSTTz5h06ZNvPTSSxVX7C/fnn32WZYtW1bl5NnCwoLhw4fXeoLzO++8w3PPPYeDgwMffPABDg4ObNq0iR9//BEnJydmzpzJokWLqqxzURMrKyvefPNNsrOzK7bd7DG//vprbGxssLW1ZdiwYRQXF3Ps2DH8/f1rfI6FhQUvvvgi8+bNY+nSpdx///106tSp0nv33HPPkZKSwq5du6o8v3v37nTs2LFWbVWr1XzzzTf4+PiwZs0a2rdvj7u7O6+88kqtni8IgtBUSPK/v00EQRAEQWiSpk+fXu3wLUEQhOZA9HgIgiAIgiAIglDvRI+HIAiCIAiCIAj1TvR4CIIgCIIgCIJQ70TgIQiCIAiCIAhCvROBhyAIgiAIgiAI9U4EHoIgCIIgCIIg1DtVY1egKTIajaSkpGBjY3PNHPiCIAiCIAiCcLuTZZnCwkI8PT1RKGru1xCBRzVSUlLw8vJq7GoIgiAIgiAIQrORmJhI69ata9wvAo9qXF6JNzExEVtb20aujSAIws0rLi7G09MTMF1UsbKyauQaNV0G2cDp7FPkanNx0DjQyckfpaRs7GoJgiA0eQUFBXh5eVWcQ9dEBB7VuDy8ytbWVgQegiA0a0rllRNnW1tbEXjU4EDKfr6LXEx2WVbFNidzZ2YEz6SvZ79GrJkgCELzcb0pCmJyuSAIgnBbO5Cynw+OvF8p6ADILsvigyPvcyBlfyPVTBAEoWVp1MBj/vz59OjRAxsbG1xdXZkwYQJnzpy57vNWr15Np06dMDc3JygoiI0bN1baL8syb775Jh4eHlhYWDB8+HBiY2PrqxmCIAhCM2WQDXwXufiaZZZELcYgGxqoRoIgCC1Xow612r17N08//TQ9evRAr9fz6quvMnLkSGJiYmocDnDgwAHuv/9+5s+fz9ixY/n555+ZMGECx44do3PnzgB89NFHfP7556xYsQJfX1/eeOMNRo0aRUxMDObm5rdcb4PBgE6nu+XjtGRKpRKVSiWyggmC0KTFZJ2s0tPxb1mlWcRknSTIJbiBaiUIgtAySbIsy41dicsyMzNxdXVl9+7dDBw4sNoy9913H8XFxWzYsKFiW+/evQkJCeGbb75BlmU8PT3573//y6xZswDIz8/Hzc2N5cuXM2XKlOvWo6CgADs7O/Lz86vM8SgqKiIpKYkm9LY1WZaWlnh4eKBWqxu7KoJw2youLsba2howfX6JOR6V7U76hwVhH5seGAHJdFPoFRgVxopxAf/t/jKDWg9upFoKgiA0bdc6d75ak5pcnp+fD4Cjo2ONZQ4ePMhLL71UaduoUaNYt24dAPHx8aSlpTF8+PCK/XZ2dvTq1YuDBw9WG3hotVq0Wm3F44KCgmpf22AwkJSUhKWlJS4uLuJqfg1kWaa8vJzMzEzi4+Np3779NXM6C4IgNBZHjen7xjnZjTyXHPRqHchgVBnxOtMWnaactDZJFeUEQRCEm9dkAg+j0cgLL7xAv379KoZMVSctLQ03N7dK29zc3EhLS6vYf3lbTWX+bf78+bz11lvXraNOp0OWZVxcXLCwsLhu+duZhYUFZmZmJCQkUF5eXidD3ARBEOpagHMgvmkdSLNNRq/WYZ/hTLsof8KH7SWxfTx9/x6OjdqWAOfAxq6qIAhCs9dkLkM//fTTREdH8+uvvzb4a8+ZM4f8/PyKW2Ji4jXLi56O2hG9HIIgNHU6nY58sxxKbYqxLLCm+7YBuF9sTeuzvqCQiep3BP+jXZCM4nNfEAThVjWJM8NnnnmGDRs2sGvXrmuudgjg7u5Oenp6pW3p6em4u7tX7L+8raYy/6bRaCrW7Ghua3c899xztGnTBkmSiIiIqLHcvHnzeOGFFxqsXoIgCE2dUTby0Z4PyHHKQqU1o8e2QWjKTb2znQ/2QF2modAxn9Ne0aTFZDRybQVBEJq/Rg08ZFnmmWeeYe3atezcuRNfX9/rPqdPnz7s2LGj0rZt27bRp08fAHx9fXF3d69UpqCggMOHD1eUaUkmT57Mvn378PHxadR6GI1GjEZjo9ZBEAThRvx06gfCio4iGRR03zkA64IrF52URiWhO/sDcK7LSeKz4hurmoIgCC1Go87xePrpp/n555/5888/sbGxqZiDYWdnVzGHYurUqbRq1Yr58+cD8PzzzzNo0CAWLFjAnXfeya+//kpYWBiLF5vysEuSxAsvvMC7775L+/btK9Lpenp6MmHChDqruyzLlOnqN6+7uZnyusO6asr+VZ3U1FTGjRtHXFwc7u7u/P777zg6OmIwGHjllVfYtGkTAEOGDGHBggWo1WqmT59OSEhIRW/JrFmzsLa2Zt68ecybN4+oqCiKiopITExk27ZttGrV6qbbKwiC0FC2JWxl9dlVAAQf6IFTmluVMo7pLnjE+ZDaLoE12t/oI/dCITWJgQKCIAjNUqMGHosWLQJg8ODBlbYvW7aM6dOnA3Dx4sVKcwX69u3Lzz//zOuvv86rr75K+/btWbduXaUJ6f/73/8oLi5m5syZ5OXl0b9/fzZv3lynE5zLdAaGvLfj+gVvwa7XhmGhrrsf0eHDhwkPD8fJyYkpU6bw7bffMmfOHBYvXszRo0cJDw9HqVQyfvx4Fi5cyOzZs697zIMHD3L8+PEqk/kFQRCaqhOZEXwd8SUA97S/D+MfFpShrVJOQqLL/p5keqdwjlg2X9jEGN87G7q6giAILUajD7Wq7nY56AD4559/WL58eaXn3XPPPZw5cwatVkt0dDRjxoyptF+SJN5++23S0tIoKytj+/btdOjQoQFa1LTdcccdODk5AaYha3FxcQBs376d6dOno9FoUKlUzJgxg23bttXqmGPGjBFBhyAIzcbFgot8cPh9DLKBga0HMcnzHmRjzesyKQ0qxmZMBGDFyWVklV57sUFBEAShZk0mnW5zY26mZNdrw+r9Ner0eFf1+CiVSvR6fbXlrh7epVKpMBiuDCkrKyurWIwMqHRfEAShKcsty+XtQ/Mo1hfj7xjAM0HPsfXtPWgLy7F0tAAZSnJLK8qbWZqhK9Eh7dcQ+GAQJ3VRfHPiK17r9abIbigIgnATROBxkyRJqtNhUI1p+PDhrFy5kgceeACFQsGSJUsYOXIkAH5+fhw5cgSA7OxsNm7cyNSpUxuzuoIgCDdMa9Dy3uF3yChJx93Kg9d6vU74D9GkRmdgZmHG2HeGY+dhQ1pMBiW5pVg6WODa0Zm/Xt1GZmw23Q8O4Ez3UxxJO8L+lH30bzWgsZskCILQ7IhZcs3cE088QevWrUlKSmLUqFH4+fnd8DFmzpxJaGgooaGhhISE0KZNm4rJ5DNnziQzMxN/f3+mTp1K796967gFgiAI9csoG1kYvoCzuWewNrNmbp+3SDuYTfT60wAMeaEvDq3tUCgVeAa54zfQF88gd1RqFUOe74vSTEFWVC535d0LwLeR31BQXtCYTRIEQWiWJFmWax7cepsqKCjAzs6O/Pz8Smt6lJWVER8fj6+vr1iJuxbE+yUIja+4uLhiSGRRURFWVlaNXKOGt+LkMtbE/o5KUvF2v/dwL/Bk3ewtGMoNhN4bRI8Hu1zz+ZF/nuLg9+GozFVE33eIOEUsw7yH83zoiw3UAkEQhKatpnPnfxM9HoIgCEKLteXCZtbE/g7As12fp53ajy3zd2MoN+DdzZPu9wdf9xhB4zrhEeiKvkxPr4ODkYwKdlzczvGM4/VdfUEQhBZFBB6CIAhCi3Q84ziLTnwFwJSODzCo1WB2fLyPooxibD1sGPpSfyTFlUniBqNMeHwOW6NSCY/PwXAp25WkkBj8fF9U5iryzxYxJn0CAF9HfEGZvqzB2yUIgtBctYzZ0YIgCIJwlYsFCXx45H2MspHBrYdwf6cHOLT8GMmRaajMVYyaMwiNtbqi/K6YdBZuOkVGwZX1PFxtNbw42p8hAW7YulnT59Fu7P36MIodFnhNakMiF/jp1I88FvR4YzRREASh2RE9HoIgCEKLkluWw9sH51GiLyHAKZBnuz5P3N4EItedAmDIc31w9LGvKL8rJp05v0VUCjoAMgq0zPktgl0x6QD4j/TDK9QTo85I74NDkIwS6+P+JDb3bIO1TRAEoTkTgYcgCILQYmj1Zbx76B0ySjPwtPLk1V6vU5BYxO4vDwIQMimQtv18KsobjDILN5265jE/3XQag1FGkiQGPdMbtZWakoQyhl24EyNGvjj+OXpj9esiCYIgCFeIwEMQBEFoEYyykQXhnxCbdxYbMxve7DMPtVbD1vm70WsNtA7xqJLBKiIht0pPx7+lF5QRkZALgJWTJf2f6AGA+T5bPPJbc6Egnj9i19RPowRBEFoQEXgIgiAILcKKk8s4lHoQlULFq71ex93Cgx0L9lGQVoSNmzXDZvVHoaz8tZdVWLvJ4dlFV4ITv4Ft8O3jjWyQ6X1wCAqDgt/O/EJSYVKdtkcQBKGlEYFHMzdy5EiCg4MJCQlhwIABHD9efXrHefPmVSwKKAiC0NJsjt/E2nN/APB81xcJdO7M0Z9PkHQ8FZVayag5gzC30VR6TnRiHj/uv1Cr4ztZX3muJEkM+E9PLOzMKU/VM+DMCHRGHV9GfI5RNtZZmwRBEFoakdWqmVu1ahX29vYArF27lunTp3PixIkGr4fRaPqyVShELCsIQsM6lh7ON5FfA/BAp4cY5DWY8wcuEvH7SQAGPdsbJ1+HivLn0gv5dkcse89k1ur4rjYaQnwcKm2zsDNn4NO92PL+bqyPOOLm6kkMJ9l6YQt3+I6uo5YJgiC0LOIs8SbJskyZvqxeb7VZVP5y0AGQn5+PJEk1lk1NTWXcuHEEBAQwdOhQcnJyADAYDLz88st07tyZzp078+yzz1JeXg7A9OnT+fTTTyuOMWvWLObNmweYelEmTZrEqFGj6Ny5M6mpqTf+RgqCINyCC/kX+PDofIyykSFew7iv4xRyLuax67MDAARP8MdvoC8ASTklzF0TycOLDrD3TCYKCcaFtmL22IBrvkYvP2eUiqqfrW16edFhaFuQodeBwSh1Spaf/J7s0qy6b6ggCEILIHo8bpLWoOXeDZPq9TVWjV2Ducr8uuWmTp3Krl27ANi4cWON5Q4fPkx4eDhOTk5MmTKFb7/9ljlz5rB48WKOHj1KeHg4SqWS8ePHs3DhQmbPnn3d1z548CDHjx/Hzc2t9g0TBEGoAzllObx9aB6l+lI6OwXxTMizlBfrTJPJy/R4BrvTa2pXMgvK+H73ef46llSxKOCwQDdmDm2Pj7MVAPZW6irreNhoVBRq9WyOTOGeXt508LCtUoe+j3Un+UQaxdkl9I4azP7QHSw68TWv9XrjmheCBEEQbkeix6MFWLlyJYmJibz77rvXDBbuuOMOnJycAOjTpw9xcXEAbN++nenTp6PRaFCpVMyYMYNt27bV6rXHjBkjgg5BEBpcmb6Mdw+9RVZpJq2sWzGn12uoJBU7F+4nP6UQaxcrej7dk693xDL5872sDUvEYJTp7efM8if68N69IRVBB8CQADfWvjiIr6b34O3JwXw1vQebZg+hf0cXdAaZN36PpLS8aspcjbWawc/1AcD+hCuuKZ4cSTvMgZT9DfZeCIIgNBeix+MmaZQaVo2t3/SJGqXm+oWuMm3aNJ588kmys7MrAoyrmZtf6T1RKpXo9dXnnb/6Kp1KpcJgMFQ8Lisrw9rauuLx1fcFQRAagkE2sCDsY87lncNWbcubfd7CRm3D0Z9PcDEsGaWZkrKRbXng+6MUa02fc0Fe9jw1vD1d2zjWeFylQqKbb+X9r9/VmYe/OUBCVjELNp7m9QmdqzyvdYgHAaM7ELPpLD0PDWLz2N/5NnIRwS5dsFHb1G3jBUEQmjHR43GTJEnCXGVer7frddPn5eWRkpJS8XjdunU4OTnh6FjzF2t1hg8fzsqVKykvL0ev17NkyRJGjhwJgJ+fH0eOHAEgOzv7mkO5BEEQGsLy6GUcTjuEmcKMV3u9gYeVBxcOJ3LstygAjrSx5buTaRRr9fi5WbPgwVAWP9bzmkFHTeyt1Lw1KRiFBBuOJ7M1qvq5bL2nh2Lrbo2cDz2ODSBPm8ey6KW31E5BEISWRvR4NGP5+fncc889lJaWolAocHFxYcOGDTc8rnjmzJnExcURGhoKwODBgytS786cOZPJkyfj7+9P27Zt6d27d103QxAEodY2nt/An3FrAXg+9EUCnALISshl6yf7AIhxtiDSSkVrRwtmDm3P8EB3FNVMDL8RoW0ceWRgO5bujuOD9ScJaGVHa0fLSmXMzFUMeaEvf87ZiuMpN9w8WrOdbQzyGkwXl5Bben1BEISWQpJrkzrpNlNQUICdnR35+fnY2l6ZTFhWVkZ8fDy+vr6Vhi0J1RPvlyA0vuLi4oohkUVFRVhZWV3nGU1XWNpR3j30NkaMPOT/MPd0uI/tx5OJ+ng/ViU60qzMCA9x5ZEhfowLbYVKWXed+nqDkWdWhBGRkEtAK1u+fbQXZqqqxz+04hgn/ohBtjKyffw6HB0d+GLoV2hqkShEEAShuarp3PnfxFArQRAEocmLzz/Px2EfYsTIUK/heCuH8ei3B9n16QGsSnSUqBW0nR7CqhcHcncPrzoNOgBUSgVvTQrC1kJFTHIB3+yMrbZc9/u74OBth1SsoNvhfqQVp/Hz6Z/qtC6CIAjN1S19MmdkZLB371727t1LRkbGDT9/z549jBs3Dk9PTyRJYt26ddcsP336dCRJqnILDAysKDNv3rwq+zt16nTDdRMEQRCahuzSbN459Bal+lLa2gRwJrI3L/xwDPXxNHzyy0EpcffcoTw8siPmZsp6q4ebnQWv3WWaXP7T/gscOld1vQ6VWsmQF/qiUEo4nnfD87wPf55bx7m86gMVQRCE28lNBR6FhYU8/PDDtGrVikGDBjFo0CBatWrFQw89RH5+fq2PU1xcTJcuXfjqq69qVf6zzz4jNTW14paYmIijoyP33HNPpXKBgYGVyu3bt++G2icIgiA0DaX6Ut459BZZpVmojc4c3t+f4xcK8Ckqp2taCQCDnupFm87uDVKfQf5uTOrhBcBbf0SRXaitUsalnROh9wYBEHKkN2YlGr44/jl6Y/WZBAVBEG4XNxV4PP744xw+fJgNGzaQl5dHXl4eGzZsICwsjCeeeKLWxxk9ejTvvvsud999d63K29nZ4e7uXnELCwsjNzeXRx55pFI5lUpVqZyzs/MNtU8QBEFofAbZwLsH5nM+Pw6jzoKUU3ciGc25q50zI1NKkICA0R3oNNyvQev17KiOtHOzJre4nLfWRmE0Vp0qGTK5M87tHJHKFIQe6Et83nnWnfujQespCILQ1NxU4LFhwwa+//57Ro0aha2tLba2towaNYrvvvuO9evX13Uda7R06VKGDx+Oj49Ppe2xsbF4enrStm1bHnzwQS5evNhgdRIEQRBuXWZBGU//9RFROeHIRiV558cypH0HVj7Wi3ZHU9CX6HDr5ELfx7o1eN3MzZS8e08XNGYKjsRl8+P++CpllCoFQ1/oi9JMgWOiK15n2/HL6Z9JKUpu8PoKgiA0FTcVeDg5OWFnZ1dlu52dHQ4ODrdcqdpISUlh06ZNPP7445W29+rVi+XLl7N582YWLVpEfHw8AwYMoLCwsMZjabVaCgoKKt0EQRCEhpdfUs6XW8/wwI9fkCKbhsm6aSey5OG7efeeLsT/HEnuxXwsHSwYMXsAynqc03Etvi7WvDTaH4Bvd54jOimvShkHb3t6PBQCQOew7qjy1Xx5/AuMsrEBayoIgtB03FTg8frrr/PSSy+RlpZWsS0tLY2XX36ZN954o84qdy0rVqzA3t6eCRMmVNo+evRo7rnnHoKDgxk1ahQbN24kLy+PVatW1Xis+fPnY2dnV3Hz8vKq59rXHa1WyzPPPEP79u0JCgrioYceqrbcvHnzKtbmEARBaGpKtHqW7Y5j0md7WRW1C3OP3QAM87iXJfdPp5OnHSf+iOH8gYsoVApGzB6I1b/W0mho40NbMSzQHYNR5o3VkRSV6aqUCRrXCfcAVxTlCrru60N0VhTbErY2Qm0FQRAa300tILho0SLOnTuHt7c33t7eAFy8eBGNRkNmZibffvttRdljx47VTU2vIssy33//PQ8//DBqtfqaZe3t7enQoQPnzp2rscycOXN46aWXKh4XFBQ0m+DjlVdeQZIkzp49iyRJlYLBhmQ0mq7gKRQiQ7MgCLVXrjeyNiyR5XvOk1tcjsoiE0ffzSDJDPceybNdpwKQeDyFIz9GANBvRnfc/V0asdYmkiQxZ3wAMcn5pOaV8sH6GN6ZHFxpEVeFUsGQ5/uw+vm/cUhzoU1MR5abfU93tx44WTg1Yu0FQRAa3k0FHv/uZWhou3fv5ty5czz22GPXLVtUVERcXBwPP/xwjWU0Gg0ajaYuq9ggiouLWbp0KUlJSRVfdO7uNWd2SU1NZdy4ccTFxeHu7s7vv/+Oo6MjBoOBV155hU2bNgEwZMgQFixYgFqtZvr06YSEhFT0lsyaNQtra2vmzZvHvHnziIqKoqioiMTERLZt20arVq3qvd2CIDR/BqPMphMpLPnnHGl5ZQC0ctGh9tlEsUFHF5cuPBXyNJIkUZBWyI5P9iEbZTqN8MN/VPtGrv0V1uZmvDM5mCe+P8L26DR6tnVifLfWlcrYutvQ55FQ9i46gn94CJmtUvg2chGv9nq9kWotCILQOG4q8Jg7d26dvHhRUVGlnoj4+HgiIiJwdHTE29ubOXPmkJyczMqVKys9b+nSpfTq1YvOnTtXOeasWbMYN24cPj4+pKSkMHfuXJRKJffff3+d1PkyWZbRaw11esx/U2mUla6c/VtcXByOjo68//77bN++HQsLC+bNm8ewYcOqLX/48GHCw8NxcnJiypQpfPvtt8yZM4fFixdz9OhRwsPDUSqVjB8/noULFzJ79uzr1vHgwYMcP34cNze3m26nIAi3D1mW2XUqncU7z3EhsxgAFxsNDw9oxf7iz4kvyMPLxpvZPV5FpVChK9OzZf5utEXluLZ3ov8TPa75udgYOnvZ88RQP77eHsuCTacI8rbH18W6Uhn/Ue2JP5RI0vFUQvb24YDtNg6k7KevZ79GqrUg3DiDUSYiIZfsIi1O1hpCfBxQKprW36PQtN1U4FFXwsLCGDJkSMXjy8Odpk2bxvLly0lNTa2SkSo/P581a9bw2WefVXvMpKQk7r//frKzs3FxcaF///4cOnQIF5e67ZbXaw18f9+vdXrMf3v0tymYmdf8I9Lr9SQkJBAQEMAHH3zA8ePHGTFiBCdPnqw2ELjjjjtwcjJ17ffp04eoqCgAtm/fzvTp0yt6fWbMmMFXX31Vq8BjzJgxIugQBOG6ZFnmyPlsvtkey6kUUwIPWwszpvb35e4erVhw7H3iC85jp7Hnzd7zsFZbI8sye746RM6FPCzszBnxysBGm0x+PQ/18+Xo+RyOns/mjdUnWDqjN5qr6ipJEoOf7cOqZzdgn+VEu8gAvrVYRLBzMNZqm0asuSDUzq6YdBZuOkmuMR6FWTFGnRUOCl9eHB3IkIDmdx4ggqjGcVOBh0KhuOYVJ4Ohdj0BgwcPRpar5j+/bPny5VW22dnZUVJSUuNzfv21foOBpsTb2xuFQsGDDz4IQNeuXfH19SUqKqraYMDc3LzivlKpRK+vfjGrq3+2KpWq0s+zrKwMa+srV/Kuvi8Iwu3pel/g0Yl5fL39LMcu5AJgoVZyfx8fHujbBmtzMxZHfkNY+lHUCjWv93oDNyvT51fUX6c4t+cCCqXE8NkDsHa2apT21YZCITFvYhAPLTrAufQivth6hll3BlQqY+VkSb+Z3dm18AAdTnRmn1cyy08u45muzzVSrQWhdnbFpDNv8+9Yt9pDu1xLzEstKLMuJdNhK/M2DwQmN6vgwxREnSKj4MoCoK62Gl4c7d+s2tEc3VTgsXbt2kqPdTodx48fZ8WKFbz11lt1UrGmTqVR8uhvU+r9Na7F2dmZYcOGsWXLFsaMGUN8fDzx8fH4+/vf0OsMHz6clStX8sADD6BQKFiyZAkjR44EwM/PjyNHjgCQnZ3Nxo0bmTp16s01SBCEFudaX+DeTpZ8syOWvWcyATBTSkzs4cW0AW1xtDb1sK6P+4sN503rP73UbRYdHTsBkByZxqHlxwHo81h3PAOb/smAk42GuRODeOGHcH4/kkiPtk4M8q9c7/aDfLlwKJH4g4l02dOH7fZbGNh6EMEuXRqp1oJwbQajzMI9f9JBEUngn0OxKLlyAaDUspiTvY6xcI+agZ0ebxY9Brti0pnzW0SV7RkFWub8FsH8+0JE8FGPbirwuOuuu6psmzx5MoGBgfz222+1mvTd3EmSdM1hUA3lm2++4bHHHmP27NkoFAq+/fbbG57gPXPmTOLi4ggNDQVMPVGXJ5PPnDmTyZMn4+/vT9u2bendu3ddN0EQhGbqel/gEiADCgnuDGnFo4Pb4WFvUVHucOohlkQtBmB64KP0bWWa71CYUcT2j/ciG2U6DG1L4JgODdCautHbz5kH+7bhpwMXeO/PaDp52uJmd6XNkiQx4D+9SI3JgDx72h8P4kvbL/hi6FdolM0vyUl9M8gGYrJOkqPNwVHjSIBzIEqpaQ63a6mOXcjGtegk3fb2ByDRVk2kqyVGBUiyPYpET4rtCnjsu0M4WWtQKSSUCgmVUkKlUFTcVyoUpn1KCZXi0r5L95UKxaUyl/Ypr36eqez17185zpU6KCruKxUSRhkWbjp1zfZ+uuk0Azu5NosgqjmS5GuNdbpB58+fJzg4mKKioro6ZKMoKCjAzs6O/Px8bG1tK7aXlZURHx+Pr69vpWFLQvXE+yUIja+4uLhiSGRRURFWVnUzXMlglLl74e5KPR3VGRLgxhND/Wjzr8nW5/JimbN3NlqDllFt7uCpLs8gSRJ6rZ4/52wlKy4H53aO3DV/JCpN41/kuRE6vZEnvj9MTHIBIT4OfDmtOypl5VTj8YcS2Tp/N7Ikc3D0dob0H8T0wEcbqcZN04GU/XwXuZjssqyKbU7mzswInikm5TegpYd2UvhZLOYllpx3MOdISBL2TscoNdijLfChvKANRl3zmKekVEgYjNc/7f1qeg+6+To2QI1ajprOnf+tzj7NS0tL+fzzz0U6VUEQhNtARELudYMOgMk9vasEHZklmbx76G20Bi0hLl15Ivg/SJKELMvsXXSErLgczG01jHxlYLMLOgDMVArentyFqd8cICIhl2V7zjNjiF+lMr69vWg/2JfYf+Lpsrc3653+YkCrgbSz96vhqLeXAyn7+eDI+1W2Z5dl8cGR93ml56si+GggUkoBFiVWnHE056h/Hn0ysmm3axS5zlkkBMSS6r8bVbEt1iofercZgrOqHcgq9EYjeoOMwSijNxpN/xtk9EYZw6V9pvsyeoOxxvum58uXjmW86r5c9TWuOmZ1ahN0AGQXXf+zTbg5N/WJ7uDgUGkCsizLFBYWYmlpyY8//lhnlRMEQRCaptp+Mf+7XImuhHcOvUVOWQ7eNj7M7jkHlcL0VXTy7zOc3XUeSSEx/OUB2Lg23+QVrR0tmT02gLlroli2O45uvo6Etql8BbXfjB6kRKVDNrQPC+ILp89ZMGghSsXtPZTIIBv4LnLxNcssiVpML4/eYthVA/Axc+BPFwPhvnpCdKdpdzIEAIcsZxz2OON/pCsXO54joeNZNmacwFxpTrBLMKHu3enm2r0iWURDkmW5ImAxBSOmgOX4hVxeX33ius93shbDHuvLTQUeCxcurLwyq0KBi4sLvXr1wsHBoc4qJwiCIDRNtf1ivrqcwWjg47APuVAQj73Gnjf7zMPKzDT0K+VkOge/Dweg9/RQWgXXvBhqczEq2JMjcdn8HZHC3DWR/PifvthZqiv2a6zVDHq2Nxvn7cT3VEcOee9kXeu1TGo/uRFr3fhisk5WGl5VnazSLGKyThLkEtxAtbo9ybJMVIkdR73y6WCxh857ugFglIwoZNPwQU2ZOe1PdMYvKpBs3zTOdozmiP4IR9JMiWlaW7emm1t3Qt26EejUGbVSXePr1RVJujTHRAmYXdk+JMANV1vNdXtrw85n07m1XaWU2ELduKnAY/r06XVcDUEQBKE5CfFxuO4XuJutOSE+potRsiyzOOobwtPDUCs1vNF7Lq6WrgAUZRWz/cO9GA0yfgPbEDS+U4O0oSH8d4w/0Un5JGQV8866aD6+v2ulC3deXT0JGN2BmE1nCd7Xi9Wuv9HHoy+e1p6NWOvGlV2ac+WBDFx6u9Ql5pSbl4GimnJCnZNlmUXbY/k1JpXWLrvp8U8XFLICg1KP0nDl9FFGRqGSQC/hHOeBc5wHSk+JtKCLHHM7TFJREklFSfwZtw6NUkOQczDd3LrTza0b7lYeDdompULixdH+1SbFuNqyPefZFp3Gy2P96dXOuWEqd5uodeARGRlZ64MGB7fsKxB1OB+/RTMajY1dBUEQ6kltvsBfGN2pIjPMX3Hr2BS/EQmJ/3abRXsHU6YqfbmBbR/soTS/DCdfBwY+07vJrUx+Kyw1Kt6ZHMxj3x1i35lMVh++yL29fSqV6T2tK4nHUiAd/A4F8ZX7F7zb7/0W9T7ciIiUC1ceSCDltEa2T6bcsow2JztQZlVCWpsksvPNajyGcGuMRpmFm0+z+vBFHF0O0veQH2Y6NXqVDpX+yvsuIyMhMXzWQGzdrDn59xli91zAkGLAJcWLcdZtse1jQXLABY6Vh5FTlk1Y+lHC0o8C0Mq6FaGu3Qh160Zn56AGyew2JMCN+feFVEkD7mZrzvN3dARg4abTJOWU8PzKcEYGufP8qE442YjhV3Wh1lmtLi8aeLl4XSwg2FTVNDPfYDAQGxuLpaUlLi4ut+2XwvXIskx5eTmZmZkYDAbat2+PQqG4/hMFQahz9ZXV6rLq1vFwszXnhdGdKnLhH0o5yPwj7yEj80jgY9zdfiJg+qzY/eUhzmyPQ2OjZuKCMdi6Nd95Hdfy26EEFm46jZlSYumM3nTwqJz1JfVkBn+9thVkODpsN/eOn8zINqMaqbaNI6s0i8WR33Ao9SAAZsXW5CUPpri4LeaOJ7H12QFA0L4epLvnMnnk/7gjWCS0qWsGo8z8v06y4XgyVg7RDIuRcEp3RWErYa7UUJJbVlHWytmSvo93p20f74ptZQVaTm8/x8lNZynKKAZAUkj49GiF0xA7LjjGcizjGKdyYjDIV84X1UoNQc5BdHPtRqhb93rv9bvWwqfFZXq+3RnL70cuYpTB2lzFf4a1Z0J3L5Fmtwa1zWpV68AjISGh4v7x48eZNWsWL7/8Mn369AHg4MGDLFiwgI8++ogJEybcWu0b2bXevKKiIpKSkkSvRy1YWlri4eGBWl3/4zkFQahefQcecO0v8NjcWF7dZ0qbe0ebMfyny1MVF21iNp1l7zdHkBQSY+YOpXVIww67aEiyLPPyL8fZdyYTH2crlj/RGwt15UEHB5eFE7nuFGUWpYRP3s2nYz/H0bzlp/Q0GA1sOL+en0//SKm+FAVKNPEBJOT1A9Q4lugoUymQvI9i5XEEjBJBuwdw93OP072dU2NXv0XRG4zM+yOK7dFpqK2SGJSeQutzvqCBez8Zi10rW9JiMijJLcXSwQL3AFcUyuovLBoNRi6GJRO94QzJkWkV2x287Ai8syOt+7lzsiiKY+nhHMsIJ6u08rwedysPurl2o5tbd4Kcg9CoGj4t/+mUfD5cH8OplAIAAlrZMXtcAB09aj6xvl3VeeBxtZ49ezJv3jzGjBlTafvGjRt54403CA8Pv/EaNyHXe/MMBgM6na4RatZ8KJVKVCqV6BUShEbWEIFHTTJLMpi1+yVytbmEunbjjd5zKzI2pZ3KZP3r2zDqjfSa1pWQiYENVq/GkldczsOLDpBZqGVs11a8PqFzpf36cgNrXvqbvMQCUtokYPGgxCs9X22k2jaM2NxYvo74grj8OAD87DqSc2YAp1MtAQhOK6ZrWgl6hcSWtjZoA3Zj4XQaSa/ifz6v0q9Hr8asfoui1Rl4bfUJ9p3JRG2RTy/dCfzC/JElmTFvDsU79OZ7l3Iv5hG98Sxnd51HX6YHQG1lRseh7Qi8syO27tZcLEwgPD2c8PQwTmXHoJf1Fc83U5jR2TmI0EuBSCvrVg12fmEwyvxx9CKLdsRSojWgkODe3j7MGOKHVTNM911f6jXwsLCw4NixY/j7+1fafurUKUJDQyktLb3xGjchtX3zBEEQmrrGCjxKdCXM3juLhIIEfGzb8OGAj7E0M51MFmeX8Md/N1KSW0bbft4Mf3nAbXORIjw+h2dWHEWW4e3JwYwMqtzLk3kum7Uvb0I2wrFB+5k+5WH6ePZtpNrWnxJdCT+eWsnG839jxIiVmRXD3O/jz12OZBaWY11mYER8PvbaK0NxjMBuHwvyum9DbZuIymjNVyM/x8O64dO1tjSl5Xr+90sER89no1br6G63n47bTBcDes/oSpexdXNhQFtcztmd54n++wwFqYWmjRJ4h3oSeGdHvLp6IikkSnQlRGad4NilQCSzNLPScdws3S5NUO9OkHMw5g3QG5JZUMZnW86wPdrUe+Niq+Gl0f4M9ne9bT6/rqVeA4/Q0FA6d+7MkiVLKobRlJeX8/jjjxMdHc2xY8duvuZNgAg8BEFoKRoj8NAb9bxz6C2OZxzD0dyRjwf+Hy6WLgAYdAbWv7aN9DNZOPrYM+HDUZhZ3F6ThL/beY6lu+Ow1ChZ+WRfWjtaVtof9ssJwn+NolytJXLKARaO+wxrdcuY+yLLsmlF8qjF5JRlAzCo9WDsS0fx/c40lOUG+uSX45tYSHWncjJwvJWKxAEbUVlkY2Zw4euRn+JmY9+QzWhRisp0vPTTMSIv5mGhlujd9iBeq31QGlS0G+XD8KcG1PlrykaZxOMpRP99hsTwlIrtdp42BI7pSIehbdFYmc4vZVkmsTCR8PQwjmWEcTL7JHrjld4QlUJFoFPnikxZra29ahUIGGQDMVknydHm4KhxJMA5sFbrwhyMzeSTv0+RnGu6yN6vgwv/HeOPp4PFjb4NLUq9Bh5Hjhxh3LhxyLJckcEqMjISSZJYv349PXv2vPmaNwEi8BAEoaVokDkeV32BO6gd2JOyh60XNqNRapg/4EP87NtXlN276DAxm2NRW6mZuGA0dh42dV6fpk5vMPLMijAiEnIJaGXLt4/2wkx1ZZy8QW9k7cubyD6fS0brZBwft+Tprs82Yo3rRnpxOt9Gfk1YehgAHlaeTPd/gnX7lByITiMgs5SQ7DIUuutnREzwk4js/RcKsyIUZd58OvwD2jjb1XcTWpz8knJe+CGcUykFWJurGBl6Gs1yM8xLLHEMsmPSW3fWOIejzuqQWsjJv89wZkcc5SWmYewqcxUdhrSl850dcfCq/HMt1ZcSlRlJeEYY4enhZJSkV9rvauFK6KUgJNilCxaqqgHBgZT9fBe5uNJ6MU7mzswInklfz37XrXOZzsCKPef5YX88eoOMxkzBY4Pa8UDfNqjq+f1qquo18ADTl9lPP/3E6dOnAfD39+eBBx5o0PHD9UUEHoIgtBT1HXhU9wV+2au9Xqe3R5+Kx6e3nWP3l4dAgtGvD8G7++2bkSg9v5SHFx2goFTPg/3a8OzIjpX251zM4/cX/0bWy0T2O8x/Hp1JZ+egRqrtrdEb9fx5bi2/nPmFcoMWlULF5Pb30MX2Dt76LRrb2FyC0kswN5hORxx97PHq5smJP2JqPGaHoW2Rx9iwMOpNJEU5hoJOvDPwVULbiMnmtZVdqOW5lWHEZRRhb2nGA0MLSPv6InY5jmg8zLh/wd0VvQ4NQVeq4+w/8Zz8+wy5ifkV21sFu9N5bEe8u7eqEgTJskxyURLh6aYgJDo7qnJviKQiwCmQbm6muSFeNt4cTD3AB0fer7Eer/R8tVbBB0B8ZhEfbYjh+IVcANq6WvO/sQEV6xfdTuo98GjJROAhCEJLUZ+Bx4GU/bX+As84m8Wfc7Zi1Bvp8WAXQu9tnifRdWn3qXRm/xoBwKcPd6O3X+WFyk6sjeHQ8mPoVTrOPBDOxxMWNMg6B3XpVHYMX5/4koQCU2bMIOcgngx+ivBTsOHH4wSmFGOpN/Vw2Hna0P3+LrTr74OkkDh/8CIHvgujOLuk4nhmlmboLl0V7/9kTzL8c1l4/F2QjJRmdOf5HjMZ2/X2DWhrKz2/lGdWhJGYXYKzjYbnxllw6KtduCW0RrKCKQsnNFpqa1mWSY5M4+TfZ0g4moxsNJ2m2rhaETC6A51G+GFew5oaZfoyorIiCU8P51h6GGklaZX2O1s4U1hehNZQVu3zL5f5buT3tRp2dbm+m06k8PmWM+Rd+t0cF9qKZ0Z0wM7y9snqWe+Bxw8//MC3337L+fPnOXjwID4+PixcuJC2bdty11133XTFmwIReAiC0FLUV+BhkA08vuXRans6Lrv8Ba7NL+ePlzZRnF1Cm95ejJw9EEnkwgfg4w0xrDmaiIOVmh//07fSImVGg5F1r24h83Q22e7peD7jxPSg6Y1X2RtQWF7IipPL2JqwBQBbtS2Pdn6cXs4D+OrLAyiPpGB9aUiVlYsVPe4Ppv1g3ypXtI0GY6X0rW7+LoT9HEnEmpMADH6uD/G+cXwd+RkABReHMKnTOJ4a3kGst1CDpJwSnllxlLS8MtztzJl7rxe/f7cS7wg/ZKXMXe+OxCOgaUzYL0wv4uTms5zedg5tYTkASrWS9gPb0HlsJ5x8a+5ZkGWZlOIU09yQ9HCis6IoN5bX6nXf6zefIJcbWww7v6Scr7ad5a9jyQDYW5rx7KiOjOnieVtMPq/tufNNDURbtGgRL730EqNHjyY3N7diwUAHBwc+/fTTm6qwIAiC0HzEZJ28ZtABpgXhotOi2fbhXoqzS7BvbcuQ5/uIoOMqz47qSDs3a3KLy5n3RxRG45VrgQqlgmEv9EehlnBKc+P4+kjO58U1Ym2vT5ZldiXu5KntT1QEHcO9R/DV0G+wjGrF4sf+wG5/kinosDKj38we3L9oPB2Htat2LoFCqcAzyB2/gb54BrmjVCnp+XAIncd1AmD3l4fwS+rAlI4PAGDj9Q+ro3Yx+9fjFGv1VY53u4vPKOLJ74+QlleGl5MlC6d2Zs3aFXhH+AEw8OmeTSboALBxs6b3tFAeWjqRQc/0xsnXAUO5gdPb4/j9hb/5c85W4vYnYNBXnRckSRKtrFsxvt1dzOv7Nj+N+YWJ7SfV6nVztDk3XFc7SzWv3tWZbx/rSTtXa/JKdLyzNpqnlh8lPrPoho/XUt1U4PHFF1/w3Xff8dprr6FSXclh3L17d6KiouqscoIgCELTVNsv5jO/xJMWk4GZhRmj5gxCfRsNPagNczMl797TBY2ZgqPns/lxf3yl/XYeNvR9tAcAHcOC+XbHtxiMhuoO1eiSi5J588BrLAxfQH55Pl42Xrzf7wPGlU/ij+d2cmJxGJYlerQqBa3v6sRjyybR+c6OKM1qN6TlMkmS6PtYN/xHtUc2yuxcuJ/eeQMY5j0CSZKx893EoYvRzFx6mNS85p3evy6dTS3gP8uOkFWopZ2rNV9P78avOxbTamdbADrd3Y6AYR2vc5TGodKo6DTCj0kLxzB+/kja9jMNx0uLyWD7R3v5ZeY6jq2KojSv5iFUGpU53Vy71+r1zBU3n563i7cDK57sw9MjOqAxU3D8Qi4PLzrANztiKdM1zb/dhnRTgUd8fDxdu3atsl2j0VBcXHzLlRIEQRCaNkfN9VfUbnWuDbm7TVf6hr7YF/vWIutQdXxdrHlptGldrG93niM6Ka/S/oA72uMW7IzSoMJhkyd/nl3bCLWsmc6g49fTP/Pczqc5kXkCtULNg50eZpbdq5yZn8jW+bspTy9Gq5BI9XfinkXjufPR7qhuYfE1SZIY8GRPOgxpi2yU2fHJPsYbJtLVNRRJocfBbz3xuck8uvgQkRdz67C1zVN0Yh5PLz9KXomOTp62fP1ID/46/gvWa1xRGJW49nBk4NTejV3N65IkCY8AV0b8bwAPLrmb0Hs7Y2FnTnF2CUd/OsGPj/3BzoX7yYitvjc2wDkQJ3PnavddbUH4xyyNWkJ26bV7dWuiUip4uL8vvzzdn34dXNAbZJbvOc+DX+3nYGzm9Q/Qgt1U4OHr60tERESV7Zs3b66yqKAgCILQ8lzvC9w2y4HgA6bU6t2mBNGml1dDVa1ZGh/aimGB7hiMMm+sjqSoTFexT5Ikhj8/AIWFhEOmMwdWh5NanNqItb0iMvMEz+16hp9P/4TOqKOrayjzPN/DfIUDW9/ZQ1ZcDjoFnHCzRPVoV15/bxQernUzaVlSSAx6tjdt+/lg1BvZ8dF+ppo/hq+tL5KqBNeOG8grK+Dp5UfZdCLl+gdsocLjc3h2ZRiFZXqCve35clp3DiXsIm+pFrVWg7mPmrEvj2x2QyCtnCzp8WAIDy69myEv9sW1vRNGvZHYf+JZO2sza1/ezNl/zmO4qpdBKSmZETzT9MAo4Zjqiud5HxxTXU0rVAKulq6UGcr4M24tM7Y9xpfHPyelKPmm6ujpYMEnD3TlgykhuNqak5xbyos/HuO1VSfILKi5d6Ylu6nJ5UuWLGHevHksWLCAxx57jCVLlhAXF8f8+fNZsmQJU6ZMqdVx9uzZw8cff0x4eDipqamsXbuWCRMm1Fj+n3/+YciQIVW2p6am4u7uXvH4q6++4uOPPyYtLY0uXbrwxRdf3NDaImJyuSAILUVjZLVSl2no99coLIut8O7RijteHdzsTmoaQ1GZjocXHSQ1r5Thnd15Z3JwpUmpZ3bG8c9nBzEqDGQ8fIE3736z0Sat5mvz+T56KbsSdwDgoHHgQZtplG+VSD5hyiRkkOCUswXx3jbMvi+EAR1d66UuBr2R7R/t4cLhJFQaJf3ndOfDjHfJKs3CwuBDQtSdIKuYNsCXJ4a2R3Eb/S4eiM1kzq8RaPVGerR14qP7QziXc4q/3tqKc4obkh08+OlErP61iGVzlXE2i+i/zxC3LwHjpXkfFvbm+I9sT8Ad7bFyMrVz099bif3pIpriK0OqtFZltH/QmzvGjCA8PYzfY1cTk21KYqBAQd9W/Zjc/h7a2re7qboVa/Us2XWOVYcvYjDKWGqUPDm0PZN6ereIRAj1ntXqp59+Yt68ecTFmSa6eXp68tZbb/HYY4/V+hibNm1i//79dOvWjYkTJ9Y68Dhz5kylRrm6uqJQmDpvfvvtN6ZOnco333xDr169+PTTT1m9ejVnzpzB1bV2H3oi8BAEoaVokHU8IhYjJygwL7WgTFNGQHQIdimO2HnacPcnoxt0LYDmLjoxjye+P4LBKPPq+EDGd2tdsU+WZf56dytpYZkUOOQS8npHRviNbND6GWUj2xO2seLkMgp1hUhIjLYYi9cRP5LCLqUuVUicdtRwwtUS7zYOvH9vFzwd6vfE1qAzsPm9f0g6noqZhRndZgcwP/ltSvQleKi6cuJof0BikL8r8yYGYaG++WFezcWumHTe+P0EeoNMvw4uvH9vF3K0GXz77vd4nPJBNjMy6cM7cWnX8tY+Kckr5dSWWGI2x1KSY5rno1BK+PbxxrGNPUd/PFHjc0e8MpC2fbwBiMk+ye9nVxOWfrRif6hrNyZ3uJdAp8CbCvzPphbwwfoYYpJNa5V08rTllXEBdPJs3kNRG2wdj5KSEoqKimp9Ul9jRSSp1oFHbm4u9vb21Zbp1asXPXr04MsvvwTAaDTi5eXFs88+yyuvvFKruojAQxCElqK+Aw/TWgtHKc6uPIlXqVYyacFoHLzt6/T1bgcr957n6+2xaMwULH+iD74uV4YmleaV8cNTvyMXQ0LIWV6e8wIO5tefb1MXLhYk8PWJryquAnc0+NPn9BAyj1yaQyFBrpct261UFGmUTOzhxfOjOqK5wcnjN0un1bP57V2kRKejsVbT4b/efJI4H72sJ8RuFLv2dkJnkOngbsPHD3TFza7qitYtxaYTKby7LhqDUWZYoDtvTQqi3FjGR58vwGOPLzIyw2b3o33fto1d1Xpl0Bu5cCiR6L9PkxZTu7kVVs6WPLB4QqUsa/H58ayJXc2+pL0YL43J6uTozz0d7qW7W48bDkAMRpk/w5P4evtZisr0KCSY1NObJ4b6YW1udkPHairqNZ0ugF6vZ/v27fzwww9YWJj+eFNSUigqqv+UYSEhIXh4eDBixAj2799fsb28vJzw8HCGDx9esU2hUDB8+HAOHjxY7/USBEG4nZw/eJFtH+ypEnQAGMoN5CYXNEKtmr+H+vnSo60TWp2RN1afQHvVGHULe3OGPt0fAO8TfizdtKze66PVl7EyZgXP73qWmOyT2Jc4Min6Ydr/2LUi6HDs6sGuUDfWOWrQW6uZNymI/40NaLCgA8BMo+KO1wfj1tEZbVE5sQsTmen+FAAR+Vt4+M48HKzUnE0r5JHFh6pM4m8p1h5N5O21URiMMneGePL25GAkhcwXv32F+14fAIIf7NTigw4ApUpBu/4+3DV/FJMWjsG7m+d1n1OcVUJaTEalbb52vszq/j8WjVjMHW1Go1KoOJ1zincOvcVzu55hd+I/N5RtTqmQmNjDi9+e6c/IIA+MMqw+fJEpX+5nx8k0WvLa3jcVeCQkJBAUFMRdd93F008/TWamKYr88MMPmTVrVp1W8GoeHh588803rFmzhjVr1uDl5cXgwYM5duwYAFlZWRgMBtzcKuegdnNzIy0trbpDAqDVaikoKKh0EwRBEGpmNBg58F3YNcscWBKG0VA1v75wbQqFxLyJQThYqTmXXsQXW89U2u/Xrw3ufZ2RZAXSHxYcSNhfw5FuXXh6GM/sfIrfz65CVaRmaMSd9P/9DsqO6pGNMt49WmExPYRPJQMXDEZ8nK1YNrM3dwRf/wSvPphZmDF67lCc2zlSVqAlc1EhU5wfAmBj4g88P1FJOzdrcorKeWrZUbZGNY1J+nXllwMX+HBDDLIMk3t68dpdnVEqJJbvWInVOtPvjMdAZ/rcU7u0si2Jc1tH2g/2rVXZ7AvVZ0LzsPLgqZBnWDJyGXf7TcJCZUFCwQUWhH/Mf7bPZFP8RsoNtVukEMDJRsPbk4P5fGp3vJwsySrU8tqqE7z44zGSc0pqfZzm5KYCj+eff57u3buTm5tb0dsBcPfdd7Njx446q9y/dezYkSeeeIJu3brRt29fvv/+e/r27cvChQtv6bjz58/Hzs6u4ublJbKvCIIgXEtaTAbF2df+YqzuyqFQO042GuZODALg9yOJ7D6VXmn/HU8PAVsZ6wJbtn73D8W6uk1ln1OWw0dHP+Ctg3PJzckj9FhfRqy9G4vjtsgGmdYhHox8Zzj/+NnzdUQyBqPMyCB3ls3sjW8dZa26WRorNXfOG4ajjz0luWUYl2kYaTsaI0aWnPqU/01yoF8HF8r1Rt78PZLvdp6rtHBjcyTLMt//E8dnW0xB6kP92vDfMf4oFBJbojZTsEyLmc4My/Ya7nxuxG2xknZ1LB1qN7zuwJJwfnt6PQeXhZMSlVZlgUJHc0ce6fwoS0cu40H/h7FV25JWksaiE1/x+NZHWHN2NSW62gcOPds58eN/+vLY4HaYKSUOncviga/2s3zPeXTVLI7YnN1U4LF3715ef/111OrKEwbbtGlDcvLNpRy7WT179uTcuXMAODs7o1QqSU+v/AGdnp5eKevVv82ZM4f8/PyKW2JiYr3WWRAEobkrya3dwmy1LSdU1dvPmQf7tgHgvT+jSc+/8l5qrDWMeH4gAB5RPqzY8EOdvKZBNvD3+Q08tf0JDp0/RMfwYEasuRuPEz7IOhl3fxfGvTeC9k/24OVdZ9l9KgMzpcTLd/rz1qRgLG9hbY66ZG6rYezbw7FvbUtxVgmOv7aiu0Uvyg1aPgl/l5fGe/BgvzYALN0dxxu/n6CsvHku7ibLMl9tO8viXaZzoZlD/Hh6RAckSSI6LZqIz85gWWSN5CRzz9zxN7xgY0viHuBakdmqJgqVAkkhkZeUT+S6U6x/fTsrH17Ntg/3cGZHHCVXLUpprbbhvo5TWDpyGTOCnsDZwoU8bR4rYpbz2Jbp/BCzgjxtXq3qpjFTMmOIHz891Y/ubR3R6o18syOWh785wLELN76SelN1U4GH0WjEYKj6B5qUlISNjc0tV+pGRERE4OHhAYBaraZbt26Vel2MRiM7duygT58+NR5Do9Fga2tb6SYIgiDUrLZXDmtbTqjek8PaE9DKloJSPXPXRKG/auha2+4+uA0yTSzX/g4RiTVn6qmN83lxzN4ziyXh3+EZ3obhaybgFxkI5RLO7RwZPXco494fQZhWx+NLDpOUU4q7vTnfPtaLST29m9xVdAt7c8a+PRxbd2sK04tpvy6Y9qqO5Jfn8+7huUwb7MHrEzqjUkrsOJnOk8uOkNHM1lYwGmUWbDzFj/svAPDcqI48OrgdkiSRVpTG2o83Yp/phNHcwOS3x2Fuo2ncCjcyhVJB3xnXHmY2bFZ/pv1wD8NfHkCHIW0xt9NQXqLj/IGL/PP5QX6YtoY/Zm0i7NdIMmOzkY0yGpU549qNZ/GIJTwf+iKtrVtTrC9m9dlVPL71Ub49sYiMktr1/no7W/HF1O7Mm2Qabnkhs5inlh3l7bVR5BbXfhhXU3VTWa3uu+8+7OzsWLx4MTY2NkRGRuLi4sJdd92Ft7c3y5bVbrJbUVFRRW9F165d+b//+z+GDBmCo6Mj3t7ezJkzh+TkZFauXAnAp59+iq+vL4GBgZSVlbFkyRK++OILtm7dyrBhwwBTOt1p06bx7bff0rNnTz799FNWrVrF6dOnq8z9qInIaiUIQktRX1mtjAYjP89Yd83hVtVlhxFuXFJOCVO/OUCJ1sBjg9oxY6hfxb7yEh3f/+dnpDwl2QGpzHr3edTKG0tfXKov5edTP/H32Q14nWqLX1Qg6jLTCaqDtx09HuhCm95eaHVGPvo7ho0RpsX4+nVw4c27O2Nn2bTTJRdmFPHXq9soyizG1suaf0b8Taqcgr9jAG/3e5dTSSXM/vU4+SU6XGw0fPxA12aR2tRglHn/z2j+jkhBkmD22AAmdDcNFS/RlfDJJ5/hdsgLWWFk1JuD8e3q3cg1bjpM2fjCKn1+WTlb0vfx7hWpdC+TjTIZsdlcDEvmYngyWXGVex8s7M3xCvXEp3srWoV4oLFSY5SNHE49xO9nVxObdxYwLV44sPVgJrWfjLdt7X4WBaU6Fm2PZV14IrIMthZmPDOiA2O7tqpYj8ZglIlIyCW7SIuTtYYQH4dGWRekXtPpJiUlMWrUKGRZJjY2lu7duxMbG4uzszN79uypdWrdmhYEnDZtGsuXL2f69OlcuHCBf/75B4CPPvqIxYsXk5ycjKWlJcHBwbz55ptVjvHll19WLCAYEhLC559/Tq9evWrdPhF4CILQUtRnOt3LWa1qcnU+fOHWbIlMYe6aKBQSfDm9B6FtrqTQjYu4wLa5e5GQ0EwzMH3itFof91DqQb47vhiLSFvanwjEvMQ0DMXWw4bu9wfTrr8PCqWCi1nFzFkVQVx6EQrJ1BPzUD/fZrMYX35qIX/N2UpJbim2bazZOHAV+cp8+nr24389XiE1t4xZPx8jPrMYjZmCN+8OYlhgzUO0G5veYGTumih2nExDIcEbdwcxuotpQr9RNrJg2UJs/zRdbO06I5CeY7s2ZnWbJKPBSFpMBiW5pVg6WOAe4FqriyTFOSUkHkvhYlgySRFp6Ep1FfsUSgn3AFe8u7fCu1sr7FrZEJl1gjWxqzmReaVHsrdHHyZ3uIcODh1rVdfoxDw+3BBDbFohAF287fnf2AAuZpewcNMpMgq0FWVdbTW8ONqfIQG1u9heV+p9HQ+9Xs+vv/5KZGQkRUVFhIaG8uCDD1aabN5cicCjbjSVKFwQbmcNs45H7a4cCrfmnbVR/B2Rgouthh//07dST8Oaz/8ia0cBZRal3PHJQDq2vvYJTWZJJosjviF5fzrtIzpjWWT6HbF2saLbfUG0H9IWpcp0ErbjZBrv/RlNidaAo7WadyZ3oZtvw6wdUpdyE/P567WtlOVrsW5rybp+P6FVlXFXu7t5LOhxisv0vP77CQ7GZgGmuRKPDGrb5IaQaXUGXlt9gn1nMlEpJd6eHMzQgCtB0rJNyyn9TkJpUNJ6lBt3PjWiEWvbshl0BlJjMrgYlkxieAp5/0ohbuNmbQpCureiuFU+ay+s4VDqleUdgp27MLnDPXRxCbnu75neYGTV4Yt8t+scpeUGFBJcKyfC/PtCGjT4aLAFBFsiEXjcul0x6U0mCheEpupmr7jdiPoOPKBh2iFAiVbPI4sPkZBVTP+OLnx8f9eKkxV9uYHFT65Ama2moGM2z777BGGHj5GbnYeDkz29+vTATGWGwWjgr3N/snPjP7QJ74R1gek7zsLenNB7g/Af6Vcx+VinN/LltjP8dugiAF3bOPDO5C44N+N5Atnxuax/fRvaonIs/NT80edHjCoDM4KeYFy78RiMMl9sOcOvhxIAGNHZndcmdMa8iUzILi3X8/Ivxwk7n4NGpWD+lBD6tnep2L8lYiunP0jAvNQCq87mPPD2RPG32IDyUwtNQ7LCkkmJTsd4VUYqlVqJZxd3bDpbEG57iH8Kd2KQTfOl/ezbM7nDPfT26INCuvbPKy2vlP/bdJo9p689Z8TN1pw/XhzYYBd86z3wOHPmDF988QWnTp0CwN/fn2eeeYZOnTrdXI2bEBF43JpdMenM+S2ixv0NHYULQlNUbU+BkyV9Z9RtT0FDBB5CwzmbWsBj3x1CZ5B5aXQn7u3tU7EvNvo8O17fhyQrSGlzEc8LV36PtFZl2ExRcy7jHPb7XLHNtQfAzFpF6KQgAu/siNlVGanS8kp5ffUJopPyAZja35eZQ/1QtYCT2MzYbDa8uZ3yEh2q9hLre/+KrJKZ0/M1enuaEtGsC0vk479PYTDKBLSy46P7uzZ6wFVUpuOln44ReTEPC7WSTx4IrdTzFJUUxZY3dmOTY4/kLjN94RTUls1zFeyWQFeqIzkyjYvhyVwMS6kyH87Wy5qCNjkctTtIplMqskKmtXVrJrWfzECvwZgpav7Zhcfn8PTyo9etw1fTezRY72S9Bh5r1qxhypQpdO/evSJb1KFDhzh69Ci//vorkyZNuvmaNwEi8Lh5BqPM3Qt3V+rp+LeGjsIFoalpyLkRIvBoeX47lMDCTacxU0osndGbDh5Xvqe+mPct6uNWlKu16FV6LEus0KnKSfKLxz7LCYcsZwAkc4nQuzsTPN4f9b8mhx+MzWTeH1Hkl+iwMVfx5sQgBnSs3dzN5iLtVCZ/z9uBvkyP3FHHpl5/YGam4t3+8+nkaLqAGh6fw5zfIigo1eFqa87HD3Slo0fjnBPkl5Tz/A/hnE4pwNpcxacPdaOzl33F/vSidL5/9SccE1wxWhl48NOJ2Lo2bJZRoWayLJNzIY+ES70hGWezkK8eJ2Uhk+6ZTGqrRDJapWDnYMcEv7sZ6TMKc5V5leNtjUrlzd8jr/u6b08OZmSQR102pUb1Gni0a9eOBx98kLfffrvS9rlz5/Ljjz8SFxd34zVuQkTgcfOaYhQuCE1JQ2eDEoFHyyPLMi//cpx9ZzLxcbZi+RO9sVCr0Ol1fP3wcvQqHdYFtuQ6Z2Ew06PUq3DINAUcBoWBgLF+9L63e5XUqgajaRG67/fEIcvQydOW9+/tgqfDtdc9aK6SI9PY9M4uDOUGyjoWsbP3BmzMbfho4AI8rU0TtROzi5n183ESsooxN1Py1qQgBvk3bI99dqGW51aGEZdRhL2lGZ9N7V4pACrVl/J/736B83FPjEojd747DO+AVg1aR+HGlBVoTRPUw5NJPJ6CtvBKmlwZmTyXLDK8Uij2LWBwj0GMazcOa/WVQPLqcy1JlnEs0aOSZSQZ0q3NkC8NwWyKPR439a2WmprK1KlTq2x/6KGHSE1NvZlDCi1EdlHNPR1XyypsXrnSBaGuiBW/hVslSRKv39UZFxsNCVnFLNh4GoDDB49iXmKBwqDEqDDgkOWMc6o7DpnOGBUGSi2LURqVqDpIVYKOnCItL/wQztLdpqBjYg8vvn20Z4sNOgBaBbszcs4gFCoF5mes6Xd4OAXaAt46OJd8rWmImZeTFUse70Wvdk6U6QzM/jWClXvP01DTY9PySnni+yPEZRThbKNh0SM9KwUdRtnI10u+xfm4KVDq/XSICDqaAXNbDe0H+zLsv/2ZumIyd30wkpDJgTi2sUdCwiHThY7HuhC6ZgAZbxfx8eufsXTVMjLyTN8LIT4OuNpq8MnTck9MDuNj8xhzLp/RcfncE5ODT54WN1tzQnwcGrmlVd1U4DF48GD27t1bZfu+ffsYMGDALVdKaL7UtbxC+8XWs3y2+TQRCbkYrpWWQRBamILMwlqVK8oprueaCM2ZvZWaeZOCkSTYcDyZrVGp5GbnAWBZbEWuqykzk1EykueUjQxYlJh6uy6Xu+zExVymfXOQo+ezMTdTMm9SEP8bG4CmiUyork/eoZ6M+N8AJIWE3WlnehwZSGpRCu8eehutwXQhzcbCjAUPhjK5p2n449fbY3l7bTRaXf2udJ6YXcyT3x8hKacEd3tzvnm0J76u1pXKrFj/A5abTVe029ztSddhwfVaJ6HuKZQK3P1d6fVwV+75bCwPLrmbAU/1wrtHKyS1hHmJJZ5n2qD/yYw1j2xi0UvLOPTHEabbWTHkQj6W//o9tNQZGHIhn8e8mmYm0ZsaavXNN9/w5ptvcu+999K7d2/ANMdj9erVvPXWW3h6elaUHT9+fN3VtoGIoVY3zmiU+etYEl9tO0thmf6GnutgpWZgJ1cG+bvS3dcJtar5T14UhH8ryS0lZkssEX+dxFBs+qKQkSmyzyfDI412pyon5vCf5cvAAf1u+XXFUKuWbfHOWL7ffR5LjZLnupmT/vUF4NJwDecsNKUWWBZXPlkNnNWW/gP6IssyPx9I4OvtZzEYZXycrfjgvpAqJ7e3g3N7L7Dz//YjG2WSAs9zosdhenv2YXbPOSilKwHY70cusnDTaQxGmSAvez6YEoKTdd1POo/PKOLZlWFkFWrxcrLky2ndcbOrvFzBlrCtxH6YhFm5GpvuFtz/+sQml/pXuDX6cgMp0WmE7TlOyrF0zPL/NTxSYUBprHqBQEZG7aBi+tL7GiyrWb3O8VAoatcISZIwGOr3ikB9EIHHjYlNK+SjDTFEJeYB4GFvQWpeKWDEzDoFhVkxRp0VuiJPQMFbk4JQq5TsPpXO/rOZlQIVS42Svu1dGOTvSt/2LlhdlWVFEJqj9DNZRP99mvP7L1akVjQoDGR4JRPT8xhl1qVglBi2ajzmpZbIyJRZlWD3Uise6T72ll9fBB4tm95g5OnlRzlxMQ9/TxuCd8dgUaxBouoJqIxMuXUZ/1kxHa0e3lkXze5TpqEbI4PceWVcIJa38WfumZ1x/POZaY2F+KDTxHQ7zrh2dzEjeGalckfisnltVQSFZXrc7cz5+IFQ2rvX3UTu0ykFvPBDGHklOtq5WvP51O44/WtoXNTFaLa9therAhskb5lHFzyASt3ye6huZ7IsExYdzj8791J+yoBjmisK+drn42PeGYpXsOc1y9QVsY7HLRCBR+2UaPUs/SeOXw8lYDDKWKqVPDG0PZN6evF92GY2JKzAMdsS81ILyixKyXEqZazPVGb2GlNxDL3BSPiFHHafymDP6QyyCq/METFTSvRo68QgfzcGdHTBsR6uKglCfTDoDMTtT+DkhjNkxGZXbNf4qjjR9jjnW59EVpg+enUlLpRlBjH8sCtOl0ZXHRuyj959p/BozyG3XBcReLR86fmlPLzoAAWlevq6Q4fNpmDi6uBDxvT75jPTjXahvXl1VQRJOaWYKSVeuKMTE3t4iavlQMzms+xddASAsyFRxHaN5rHOM7jLb0KlcglZxcz6+RiJ2SVYqpW8NTm4TjJ/RSXm8eKP4RSV6fH3tOXTh7tVWigSIL0gjRX/+w27VCcMdjqmfXYfVi14Lo5Q1a/rV7H71B4MZnpckz1xSfJAkiUMSn2lHs72M7wYOnZQg9SptufON3Rp4+DBg2RnZzN27JWrcCtXrmTu3LkUFxczYcIEvvjiCzQacYLY0u05ncGCjadIzzdNEh8a4MYLozvhamvOgZT9hB38k6GHh1aMKQYotSwmrNefdPayo6+naQiJSqmgVztnerVzZtYYf2KS8/nnVDq7T2eQmF3CgdgsDsRm8aEEwd4ODOrkyiB/NzwdLKqtlyA0puKcEmI2x3JqSyyleaa/DYVKwhhUTpjPAdIdUgCQjQrKsjtSmhWMRa4zQxMKcS7RU2pVzMmex0jxzCPIOagxmyI0I252Frx2V2dm/xrBgTTwvdcV+e9ENMVX0nCWW5fhd783OvcAHl9ymHK9EXd7c96/N4SAVnaNWPumJeCODujLDRxcGk6HiCAMKgPfswQXCxf6troy9NHH2TTp/LVVJwiLz+F/vxznmREdeKBvm5sO4MLjs5n183FKyw108bZnwYOhWJtXXsuhVFfKsg9+xiHVFYNaz4R5o0XQcRuytbIlZH9vim0KOR90iujeR7HKs6Xfxsqr1JdZljZSDWt2Qz0eo0ePZvDgwcyePRuAqKgoQkNDmT59Ov7+/nz88cc88cQTzJs3r77q2yBEj0fNUvNKWbDxFPvOZAKmYVUv3+lP3w6mlVMNsoGXF71Chy2mCW7VXXGLHRXJR//5oNK42X+TZZn4zGL+OZXOntMZnE4pqLS/g7sNg/xdGdjJDT83a3GlTmg0siyTcTaL6A1nOL8/AaPB9HuuslOSFZTC0db7Kbcw9eQ5adwoyuhMUkJbZIMF5o7ReKtOY6k1o8yilGzXTFDISOkTWDvz8TqZGCh6PG4fH2+IYc3RRBys1Cx5vDt79h4mJzMXRxcHRg/vxxdbz/F3hCn47dfBhTfv7lzlarpgcvz3aI78EAHAyV7hJHeO591+7+PvFFCpnN5gZMHGU6wNSwJgbNdWzB4bgNkNzlU8cDaTOb9FoNUb6dHWiY/uD8FCXfnasFE28unnX2K10xFZkun7cijB/QJvvpFCsxWZfoKdLxzCvMQSCYkyixKK7ApxTjOler48ZHfowt4Eu3VpkDrVy1ArDw8P1q9fT/fu3QF47bXX2L17N/v27QNg9erVzJ07l5iYmFusfuMSgUdVeoORXw4msPSfOMp0BlRKiQf7+vLIwLaYXzWu9PIfg6bUnHSvFHLcMkEGTZk5zmlu2Gbbo7Usu+E/hrS8UnafzmD3qXQiEnK5OhFWa0cLBnZyY5C/K0Gt7VE0wSwOQstj0BmI25dA9IbTZJ7Lqdiu9IFTHSI453kaWSGjQEF3955YlHZn3V4FOgNYaVRolRex892MUl105Zjl1hQlDWTeHZMZElA3awWIwOP2UaYz8Nh3h4hLL8JMKaEzXPmgVCokDEYZhQRPDmvPQ/18xWfldRz96QTHVkUBENn3CHlBmXw08BNaWVdOVyvLMqsPX+TTzacxyqZUpx/cF4K9Ve2Cup0n03hzTSR6g0z/ji68d0+XajOKLf99JWU/SEhItLu/NcOnDL7lNgrNU11d5K1L9RJ4mJubExsbi5eXFwD9+/dn9OjRvPbaawBcuHCBoKAgCgtrly6yqRKBR2UnLuby0foY4jJMJ0hdfRz439iAajOf/LVjA4c3hVFqVUKr+DZY55veP6NkJN85m1yXbIxKAx69XJk+YhqO5je+sE1ecTn7zmbyz6l0jsRlU35pwi6Ao7WagR2vZMi60atOgnA9xdlXDae6NNRQUkmUBhQQ3uYgeU6mOR32GntG+txBN6fBfLkpjfB4U3DSr4MLr94VSOTFPBZuOkmuMb4iAYODoi0vjg6os6ADROBxu7m8qnlNZgxpx2OD/RqwRs2XLMscWn6MyHWnkJE5MfAQhqAyPhq0AHuNfZXyB2MzeX11JMVaPZ4OFnzyQChtr5MhbGNEMu+ui8Yow/DO7sybGISqmixEWw5s5dyCFFR6FXb9Lblv1t2ip/82dyBlP8tXrSTgcGjlYe1WxcT0PMb0e6dWDGtvCPUSePj4+PDDDz8wcOBAysvLsbe3Z/369QwbNgwwDb0aNGgQOTk51zlS0yYCD5P8knK+2naWv44lA2BvacazozoypotnlQ+8wvJCNhzfQNT603ic8UZdbprnY1AYkBVGVPrK41SNkpE8l2wMPuV4dHala/cQgjw6Y6asXO56SrR6Dp3L4p9TGRyIzaToqgxZVhoVfds7M8jfjT7tnUWGLOGmybJM+mlTdqr4AxcrhlMp7CSS/M9z0vc45eam4VSdnYIY0/ZOenn0Zmd0Jh//fYqiMj3mZkpeuKMjd3VrXfH3YzDKRCTkkl2kxclaQ4hP3eddF4HH7cNglLl74W4yCmpeyNXN1pw/XhzYJPP7N0WyLLN/8VFObjyLLMkcG7Qf21AL3us3H43KvEr5+IwiZv18jOTcUiw1St69pwt927tU+7f+Z3gSH20wjRAZ27UVc8YHVvtziYyLZNfrl4bV+Bl57MOHUIqLagKm4OO7iMXICYqKRD6KNkYe7zKzQYMOqKfA4z//+Q8nTpzgww8/ZN26daxYsYKUlBTUalN34k8//cSnn37K0aNHb70Fjeh2DzxkWebviBS+3HqGvBIdAONDW/H0iA5VxgNnlGSwbtdfpG3PwiXesyK1m86sHIVBWSm/tBEjOvNyFAYFZrrKxzEqDBS45KJqp8Cnixc9e3TDy/HGsqzo9EaOXcjhn1MZ7DmdTnZRecU+tUphypDVyZUBnVxxqGUXuHB705cbiNt3gegNZ8iKu3JBxeitI8ovnGSvC8gKGQuVBUO9hjHadwzetj4UlOr4eEMM26LTAAhsbcfciUF4OzX8Sb8IPG4f4fE5PL38+t+/X03vQTffG+9tvl3JRpk9Xx3i9PY4jJKR8KF78e3pzSu9Xq12GEtecTlzVkVw/EIuCglGd/HkSFwWmYVXvpOsNUqKtKblBib39Oal0Z2qHfqWmpvGzy+vwTrTDr1TOY98dj+WNiK5inCFQTYQk3WSHG0OjhpHApwDG2x41dXqJfDIyspi4sSJ7Nu3D2tra1asWMHdd99dsX/YsGH07t2b995779Zq38hu58AjPrOIj9bHcDwhF4B2rtb8b1wAXbwdKpU7lxXL339vpnSvAYdM54rtlu3VlKWUYyiWa8wjb2avZNL8sVyITOBUeCx5pwtRFFT+IzEqDBS7FWLdwZx2XX3p1aMntta1z5NuNMqcvJwh61QGSTklFfsUEnTxdqiYnH69DFkNcVVaaFqKs0s4ueksp7bGUpZvunosmUFuh0yi2oVR4JQHgK+tL6Pb3smg1oOxUJl+j8LOZ/P22mgyCspQKiQeGdiW6QPbVjt8okHaIgKP28bWqFTe/D3yuuXenhzMyCCPBqhRy2E0GNn16QHO7bmAUWHg6PA99OzfnSeCn6z2AplOb+Sjv2NYf2nEQE0GdXLlgykh1R6jtLyUL1/9DttYR/TmOiZ/ciduXreeslcQ6kO9ruORn5+PtbU1SmXlk8WcnBysra0rekCaq9sx8CgrN7Bsz3l+OhCP3iBjbqbk8cHtmNLHp+KESZZljl0IZ+favZgdtawYUygrjbj0cmTg5D64tHPi/MGLbPtgDzJylQlPEhIjXhlI2z7eV7bLMgVphUQePUnc8XiKz2pRFf1raJbCQLlnGQ6dbPDv3okuXTujNq/d75ksy5zPKGL3qQz+OZ3O2dTKc5A6eNgwuJMbA/1daedaOUPWrph0Fm46VWnogquthhdH+9fpOHyh8ZmGU2UStf4MFw5dGU6FrZHznU5zrt0pdOblqBQq+nsOYEzbO+no0Kni90WrM7BoRyy/HkwAwMvJkrkTg+jc2r6RWmQiAo/bh+jxqF9Gg5HtH+8l/mAiBqWeIyP/4a5h47i7/aRqy+sNRu74cGdFz0Z1XG00rH1pUJWLWUbZyOcfL8Jivx1GhZGBr/cksFunOm2PINQlsYDgLbjdAo8DZzP5ZOMpUnJN+Z77d3Thv2P88bA3XcE1GA3sPLaL8D9PYBPjhEpvmithtDLQboQP/e/uhaV95V6D8wcvcuC7oxRnX8khbeVsSd/Hu1cKOqojyzKZyVmEHTzOxchkdHFG1MWV14YxKg3IrQ24BjgR3LMzbTu3qfWqrSm5pew5bVor5EQ1GbIGXcqQlVmo5bVVJ2o8zvz7QkTw0QLoyw3E7b1A9IbTZJ3PrdiubV1MdPtjpHsnIytk3CzduMN3DMO9R2CnqbzuQWxaIfPWRFYkYLi7e2ueG9WxSjrMxiACj9uHmONR/ww6A1s/2MPFsGT0Kh2HR+1i5p0z6N9qQJWytxIILv/pB7SrTD+jDo95M2T8wLppgCDUExF43ILbJfDIKCjj002n2RmTDoCbnTn/HePPwE6mrtxSXSl/b99E3MaL2F+8MpwKNwNdJwQROrzLNU/2jQYjaTEZlOSWYulggXuAK4qbGG4iyzLn4uI4dvgEadEZSBdUaEoqBzpGpRGVj0Trzh507hGAp78bymrSEf5bbnE5+85k8M+pDI6er5whSyFRKSj5N/EF3rwVZRUTsynWNJzq8omaCjL8kjjdMYpCxzwkJLq79WC07xi6uoVWGTdrNMr8cvAC3+yIRWeQcbBS89pdgfSvgxWM64oIPG4vu2LSmfNbRI37xQWTW6cvN7D53V0kn0hDpy7n6Ojd/G/8ywQ6d65U7maHvm3evZXzn6aiNCqxH27Jfc9OrPM2CEJdE4HHLWjpgYfeYGTNkUS+3RlLSbkBpULivt4+PD64HZYaFdmFOaz/YyM5uwqxyjXNq5CRMQuQGHhPH/y6tm3UNH7l+nKOn4ogOiyG7Jg8NIlWmJdWDkRklRFzXzW+XbzpEOqHawen6wYixZcyZO0+lc6e05mU6WruHr/srUlBDPZ3qzbnutD0yLJMWkymKTvVwUTkS5GlwVbPuQ4xJLSPRWdejp3ajuE+I7mjzWjcrKo/SUvLK+XttVEcu2DqJRnQ0YU54wNxtNZUW76xiMDj9lPdEFE3W3NeGN1JBB11RFemZ+NbO0iLyaRcoyVy3EHmTphLaxuvijI30+Nx4swJ9rwZhrpMgxRgYMZ7U5HExS2hGRCBxy1oyYHHyaQ8PtwQUzHPIcjLnv+NDaC9uw3xSRfY8tsOdIdBrb2UDtdMj10fK0beOwQXL+drHbrRZJdmcyT6KGePnaPgTDG2KY5VAhFUMjbtrPDr2gavLq1xbX/tQGTjiWTe/iPa9ECW4TqBlr2lGS625rjamuNio8HFVmO6X/HYHBtzlci73kj0Wj3n9pqyU2XHXxlOVdQqjzMdoiqGUwU4BTK6zRj6evarMbWzLMtsiUrlk0tpci3USl64oxPjQ1s1yZ+vCDxuTyIpRv0rLyln/ZvbyYrNQWtextmJEbxz1zs4mJuSsdzo0Le07FR++e+fWOZao3PT8vhnD2Fu0bQuZAhCTZpF4LFnzx4+/vhjwsPDSU1NZe3atUyYMKHG8n/88QeLFi0iIiICrVZLYGAg8+bNY9SoURVl5s2bx1tvvVXpeR07duT06ZoXVPq3lhh4FJbq+GZHLH+EJSLLYGuh4qnhHRgf2prjEREcWHME1UmLK+lwbbW0HuHOqIlDsbBuPqn7DLKBuNxzhJ08xvmIBHRxRhzTXKoGImbg1MEO3y4+tAp2x8WvciBy+UqVT56WnslFFJspyLI0o8RMQYFGSbq1GVqVosrqwNdibqbExVaDi03loMTV7kpw4mStqbeTg9vxRKQos5iTm85yeus5ygpNX/6ySia53QXOdzpNoWMeFioLBrUewmjfMfja+V7zeAWlOj7aEMP2S2lyO19Kk+vVCGlya0sEHoJQf7RFWta9toW8CwWUWZaQcl8cb419C/NLa3zUduhbqbaERS8vwyrBDp2Vlin/NwFnd6cGaoUg3Lranjs36szH4uJiunTpwqOPPsrEidcfw7hnzx5GjBjB+++/j729PcuWLWPcuHEcPnyYrl27VpQLDAxk+/btFY9Vqsaf4NlYZFlmW3Qan24+Tc6ldS1Gd/HkqaHtOHHgEF88sxHzZCvUmE5GyluXEjSuEwOG90Wpan7Dh5SSkg6OHekwoCMMgKLyIk5kRnD8ZATJUamoL1rilOaGpsyc7JP5ZJ+MJOznSCQzCbdOznh1aYVnZzeC2joQXG4k9EI+ANY6I24lpsUJZUyBxrEAZ75+dxTFWj0ZBVoyC8vILNCSUVBGZkEZmYWX72spKNVRpjOQmF1CYnZJzfVXSDhaq3GxMcfVVvOv4MTc1JNiY455LSfSX7YrJp2FG6NR5yZgaSynRKGm3MGHF8d0bpZDL641f0iWZVJjMohef4YLh68Mp9LZajnXIYbEDufRacrxtvHhQd/7Gew1FEszy+u+5tHz2by9NorMAi1KhcRjg9oxdYBvo6XJFQSh8WmsNYx/ZyR/vLIRksF9tS8LzBfwyshXUCqUDAlwY/59Idcc+maUjXz30QqsEuwwqPQMf3WACDqEFqvJDLWSJOm6PR7VCQwM5L777uPNN98ETD0e69atIyIi4qbr0lJ6PC5mF/PxhlMcPZ8NgI+zFS8MbUPKkWOk7MhAXWi6ImOUjBg7a+k/uTddQoIas8r1SpZlkooSCU8LJ+pUNNkxedinOuGY6opGW3kFWoVagcFgAAM1rkci2SqYsfz+Wk2YL9MZKoKRzIIyU6Dyr8fZRVoM15rNfhVbC9WlQORKMHJleJcGFxtz7CzNkCSJXTHpLPlhHT0uKLC4alJ+qWUpR9sYefzhCc0q+Kg2Y5qTBb2mh2LQGojacJqcC3kV+/I8szjXKYZ0rxRUSiV9PPsyxvdOApwCazU0SqszsGh7LL8eMqXJ9XayZN6kYAJa2V3nmU2D6PEQhPpXklvK77M3UJqupdimEIsnZJ7s/5+Kz5hr9TgvX/oj2r9Mx+n0dBsGjezfWM0QhJvWLHo8bpXRaKSwsBBHx8pp6GJjY/H09MTc3Jw+ffowf/58vL2vncK1JdHqDPywL54Ve8+jM8hoVAoeCHLC/OxZjs89h1KnQo055Rotmt5K7rx3GN6tva5/4GZOkiS8bLzxsvFmQvu70d6pJSb7JOFp4cScPoYuzohTqitOaW6otZpq1yCpOBYSFMhsmb8bOw8blGolKjOl6X+16X/TfRVKtQKVWoWZmRJvjRJfBytUbrZXlVGiUCkwyqYsWxU9Jpd7TyqCE9P90nIDBaV6CkqLKtK3VketUuBsoyE/Nw/XYnei7A1YWclYlxvwKNRhXmLOgBj4ZdUGBr75aLMYdlXTGjFF2SXsXLC/4rGsMnKx7XkS/M9S6JiPi4ULD7V5mBE+IyvGX9dGbFoBc9dEcf7S+zyxhxfPjuzQJNLkCoLQdFg6WDDxvTGsmr0eq2wbCr/L53er1dwTei9g6s2ubu2UTVu2ULbeiIQCx3FWIugQWrxm3ePx0Ucf8cEHH3D69GlcXU3pKzdt2kRRUREdO3YkNTWVt956i+TkZKKjo7GxqX7la61Wi1Z7pQu0oKAALy+vZtnjcSQum4//jjEN55FlBtlDm9R0pLOKihO1YodCXIbZM27CaOxt7Bu1vk1JZkkmxzOOcSw9nFMxZ7FLtccxzQ2nNNeKyfb1RUYGlQxmpjkIqKh4LKkAMxlUEpJKRlaBXpLRK2V0yOgkA1pktLKBMtlIqdFAqWzEoACjQkavAMPlmwRGBUhGJfYlMi5FRmx0WgIn9aaTpxMqyQwzhQozhRozherSYzPMJJVpgv2ljwtZNv0jX2nAlX2X/qn00XLprlzxfPmq510ZvmZ63lXvinzluUaDkY3zd6AvMlTbCwVQalXMBf+zJHY4j16jo6trKGN876Sbe/cqqXCvxWCU+fnABb7dGYveIONoreb1uzrTt4NLrY/RVIgeD0FoOAXpRfz28p8Y82XyHXPp/kogQzsOrbZsRPQJ9s07hpnODKmrnhlzpzXJBBWCUBvNYnL51W408Pj555+ZMWMGf/75J8OHD6+xXF5eHj4+Pvzf//0fjz32WLVlqpuQDjSrwCO7UMtnW86wNSoVpVEmuLyAgKxi1FlXMvPk+2TT4U5fRg8bhUYlMmVcy4YdG4n69QxZnmlktkrFoDRgVWCD0qBEYVCa/tcrKz82KFDqVab/K21XotRX/7imE2jhxmS5p3Eh4CzpXilYqawY2XYUd/iOxsPK4/pP/pfUvFLe/iOK4wmm7FcDO7kyZ3wgDlbquq52gxCBhyA0rLzkAn77359QJJHvnMPIuQMJ9Azk8MGj5Gbn4eBkj1fb1qybvRnzQkvKvUp44v+mo1Y3z88YQYAWHnj8+uuvPProo6xevZo777zzuuV79OjB8OHDmT9/frX7m3OPh8Eosy4skUU7YjEUlhNQkIl/phGzMtNQEL1KT1FgLr0mhDKw6wAUkpgIWxuR6SfY+cIhzEsskZAo15jG7cqKS1fsJSNaizJCnu5EG/u2GGUDsiwjI2O4fF+WMWLEKBtN92UjRq7cN8gGZL2ModyIsdyAQS9jLDdi1Bkx6mSMOiNyuRGjDtN9nYyskzHqZGS9jKzj0k0Gven+1f+jB22xDkkroTAokGTFpf8rBzumh5c+Bi7fly5vka8qc2XflUfVPK44DsjS1R8vV/bJ1T4GpMofR7JU/ceTJEvIkkyWZxoX/M9S5FCAfYYTPqfbM2BIX0aOG1bt865FlmU2R5rS5BZrTWlyX7yjE+OaaJrc2hKBhyA0vMwL2fz+ygYUpUpyXbMwSjJO6aYeU4NCT5F9AXY5jmhtS3no08k4OtV+CKggNEUtdo7HL7/8wqOPPsqvv/5aq6CjqKiIuLg4Hn744RrLaDQaNJrm1wNwJrWAD9fHkBabRWh+Jr6ZShRGBaCg1LIYQ68yhk8cTLBXcLM+cWoMga6dWT7gRzpsCUZGRq3VVAy3unxyHTsqkvHtJ9zQEJ6Gtmfvfk59El/jfiOQYWVGzkBnTuVAYZm+Yp+3syUjO7sxONAJFzsV5QYt5UYd5YZydMZyyg26S/+Xo7u0vdxQTrmxHJ2h/JpltQYtOoOuUlldxXMvbTfqrts+pU6J5/k2hOzpg12Oafy0fuz1n/dv+SXlfLQhhh0n0wHT+jZzJwbR2vH62a4EQRD+zaWNE3e9M4q1r27GIcOZHNdMysxL0ZSZk+eSg1O6KzqzcpxH2oqgQ7itNGrgUVRUxLlz5yoex8fHExERgaOjI97e3syZM4fk5GRWrlwJmIZXTZs2jc8++4xevXqRlmbKpW9hYYGdnSnDzKxZsxg3bhw+Pj6kpKQwd+5clEol999/f8M3sJ4Ua/V8tz2Wg9tPE5iTS688NWAaUpXrmoX1QDUT7hxDG8c2jVrP5kwpKZk8YQLLy1cScDgUi5IrV4nLrEqI6XmM6ROmNumgA6BPn54ct4pBU2xe7bAuCRkHuYDXHpuIjJJD57LYEpnCvjOZXMwqYck/8Sz5J57A1naMCvJgWGd3Wtk1TJBulI3oKgISHZHpJ9j/XjgqnRpZacSoMGKbY4+ZzjQ8QUamzKqE1oE3lpntcFwW766NJrPwUprcwe2Y2l+kyRUE4da4+Dqh1ZSB0RzHDBdyXDMpcsjHOdUdo2SkxKoY42YDuvt1mKmqX7BUEFqaRg08wsLCGDJkSMXjl156CYBp06axfPlyUlNTuXjxYsX+xYsXo9frefrpp3n66acrtl8uD5CUlMT9999PdnY2Li4u9O/fn0OHDuHi0nwmhZaVl7N20x5yMnNxdHHg7tEDMVerkWWZ7ceTWf/TUXyS8xhaagaoMUpGMtum0HqkGzMGPYSTRdNcYby56evZD+6F7zosRk5QYF5qQZlFKYo2Rh7vMtO0v4kzU5nR4UEfEhanV8kEdbnnpsODPhVfegM7uTKwkyvFZXr+OZ3O1shUjp7P5mRSPieT8vl082l6tHViVLAHgzq5YWVefx8hCkmBRqlBozQFOgO8B/JXyEY6bAkGqLYtif3PEej6eK2OX6Yz8PW2s6w6bPqM8XG2Yt7EIPybSZpcQRCatsMHj2JVaE2pRQmSDI4ZV85D8pyzccx0qSjXf0DfxqqmIDSoJjPHoylpzHU8vl2xjtLNmVXWWzD0cUZ7EWzjCzDTm66yl6u1ZAamEHRnJ8aEjMHKTIzdrg8G2UBM1klytDk4ahwJcA5s8j0d/7bp763E/nQRTfGV9Uq01qW0f8CH0XeOvOZzswu1bD+ZxpbIVGKS8yu2a1QK+nd0ZVSwB739nFGr6r+H4EDKfpavqtoLVWpVbOqFundqrQLCM6kFzFsTSXxmMQCTenjx7MiON7wwY3Mg5ngIQuNYv24jKctyACi0zceyyBqlUUm2WwZO6a4V5TwfcWTchDGNVU1BqBPNbnJ5U9JYgce3K9Yh/1EIXLmaawAKLA3Yl1xJh1tkV0Be1wwG3tmXwX5DMFOILlrh+nR6XaWsKr369Ljh7v3E7GK2RaWxJSqVhKziiu22FiqGBLgzMsiDrj4OKOpxTZADKfv5LuLmeqEMRpmf9sezeNc59AYZJ2s1r03oTN/2zadH9EaJwEMQGse+vQc4+cn5iseFdvnoNOXYZzih4MqFmsBZbUWPh9DsicDjFjRG4FFWXs4301ZgXmIaiy8jo1UbMC+/MpQl0zOVku7FTBg9mu4ePUSGKqHRyLLMmdRCtkSmsD06jczCK1nhXGw1jOzswchgDzq429RLYoOb6YVKyS3l7bVRRFxKkzvI35U54wKxb6ZpcmtLBB6C0Dh0eh2Lpq5AXaypdo6djEy5dRn/WTFdzPEQmr0Wm9WqpVq7aU/F8KpCmyJsCq0xL1dhUOpJaneBDJdC2p31Isi5Pz09ezVybYXbnSRJdPK0pZOnLc+M7EhEQg6bI1PZFZNOZoGWnw5c4KcDF2jjYsXIIA9GBnnUaYYopaQkyCW4VmVlWWbjiRQWbDxFidaApVrJS2P8uTPEU2R7EwSh3pipzGj/oPc159i1f8BHBB3CbUUEHk1ETmZuxQ/jtE8RgRcgocN50m0g+IQvPmf9KsoJQlOiVEh083Wim68TL98ZwIHYTLZGprLvbCYXMotZvPMci3eeo3NrO0YGeTC8szuO1g2TGSu/pJwP1sewK8aUJjfY2565dwfRSqTJFQShAYy+cySbqDrHrty6rFZz7AShpRFDrarRGEOtfvlzOwXfm9IDlyuM7Ox/nqBoH1rlVL4SYvuoO/ffVfNK7YLQVBSV6fjnVAZbo1IJO5+N8dInjVIh0aOtIyODPBjk74aVpn6ufxw6l8W766LJupQmd8YQPx7u74uyHuefNEViqJUgNL66mGMnCE2ZmONxC5rCHI9/k5EpsyzjyRXTMFe37DHpQsuTVahlR7RpUnpNmbH6+DljVgeZscp0Br7adpbVV6XJfWtSEJ08b880uSLwEARBEOqbmOPRzJir1Vjc4YL8R2GNY0Et7nARQYfQLDnbaLivjw/39fHhYnYx26JS2RKZysXsEnacTGPHybSKzFijgj0I8b52ZiyDUSYiIZfsIi1O1hpCfBxQKiROpxQw749ILlxKkzu5pxfPjGiZaXIFQRAEobkRPR7VaIrreFjc4cIT0yY0aF0EoT6ZMmMVsDkyle3RaWRdlRnL1dacEUHujAryoP2/MmPtikln4aZTZBRclUnLRk1oGye2n0zDYJRxttHw2l2B9GnBaXJrS/R4CIIgCPVNDLW6BY0ZeEDNK5cLQktlMMocv5DDlshUdp1Kp6hMX7GvjYsVoy5lxjqbVsic3yKueawhAW68Mi4AO0vxNwMi8BAEQRDqnwg8bkFjBx6CcDvT6gwciM1ia1Qq+89mUq43VuxTKSX0hpo/smzNzdj4v8GolGKNm8tE4CEIgiDUNzHHQxCEZkljpmRIgBtDAtwqMmNtiUwlLD77mkEHQEGZjhMX8+jm69hAtRUEQRAEobbEZUFBEJosa3MzxnZtxRfTujNrjH+tnpNdpL1+IUEQBEEQGpwIPARBaBbauFjXqpxTAy1OKAiCIAjCjRGBhyAIzUKIjwOuttcOKtxszQnxcWigGgmCIAiCcCNE4CEIQrOgVEi8OPraw61eGN3ptluZXBAEQRCaCxF4CILQbAwJcGP+fSFVej7cbM2Zf18IQwLcGqlmgiAIgiBcj8hqVY3LGYYLCgoauSaCIPxbt9YWrHisK5EXc8kpLsfRSk2wt2nlcvE3W1VxcXHF/YKCAgwGQyPWRhAEQWiJLn//Xm+VDhF4VKOwsBAALy+vRq6JIAhC3fH09GzsKgiCIAgtWGFhIXZ2djXuFwsIVsNoNJKSkoKNjQ2S1DjjxQsKCvDy8iIxMbFZL2Io2tG0tJR2QMtpi2hH09JS2gEtpy2iHU1LS2kHtJy2NIV2yLJMYWEhnp6eKBQ1z+QQPR7VUCgUtG7durGrAYCtrW2z/mO4TLSjaWkp7YCW0xbRjqalpbQDWk5bRDualpbSDmg5bWnsdlyrp+MyMblcEARBEARBEIR6JwIPQRAEQRAEQRDqnQg8miiNRsPcuXPRaJr3KsyiHU1LS2kHtJy2iHY0LS2lHdBy2iLa0bS0lHZAy2lLc2qHmFwuCIIgCIIgCEK9Ez0egiAIgiAIgiDUOxF4CIIgCIIgCIJQ70TgIQiCIAiCIAhCvROBRyMbPHgwL7zwQmNX46Zdr/4lJSVMmjQJW1tbJEkiLy+vweomCEL9aO6fWy2ZLMvMnDkTR0dHJEkiIiKisat0U1rC71hLaIMg1DUReAj1asWKFezdu5cDBw6Qmppaq8VlBKE64ku8+WjTpg2ffvppY1fjtrR582aWL1/Ohg0bSE1NpWvXrqxbt66xq3XD/vjjD955553GroYgCHVMrFwu1Ku4uDj8/f3p3LlzY1dFuI7y8nLUanVjV0MQhFsQFxeHh4cHffv2beyq3BJHR8fGroIgCPVA9Hg0AXq9nmeeeQY7OzucnZ154403uJzlWKvVMnv2bLy8vNBoNPj5+bF06dJGrnFlNdV/8ODBLFiwgD179iBJEoMHDwbg66+/pn379pibm+Pm5sbkyZMbtwH/YjQa+eijj/Dz80Oj0eDt7c17770HQFJSEvfffz+Ojv/f3t1HRXWcfwD/Li/L664o8ibKmwiiskBEq6KCEYPHYMVSG0mCQBAkFoPaCMG2YkSNIJEqqRg5uLwc9GiDUmuTE1N0LQcBQQGN4a3yYspLYlBBEF1k5/dHfty4wIKosCt9Pud4jjsz9/Jc7p25zN6ZOxOgp6cHV1dXFBUVKTnigXl4eCA8PFzhtWVlZYXY2FisW7cOQqEQoaGhSo5YscDAQFy6dAkHDx4Ej8cDj8dDfX09bt68CW9vbwiFQggEAixatAi3bt1SaqxffPEFHB0doaOjA0NDQ3h6eqKzsxMSiQRz586Fnp4eDAwM4ObmhoaGBgBAeXk5lixZAoFAAKFQiNmzZ6OkpAQAkJaWBgMDA+Tk5HD1xsvLC99//70yD3PQet/Q0IAtW7Zw50pVDVbXL1++DGdnZ2hra8PV1RU5OTkqP3QpMDAQmzZtwu3bt8Hj8WBlZQUAWL16tdznV8HTTzhV/Z7xLHg8Xr8nTwYGBkhLS1NKPIPx8PDApk2bsHnzZowfPx4mJiZISUlBZ2cngoKCIBAIYGtri6+++orb5uzZs9w5WrJkCdLT01VqeLWidjkwMBA+Pj74+OOPYWRkBKFQiLCwMEilUmWH3M9AT5KdnZ2xc+dOAMCBAwfg6OgIPT09TJkyBRs3bkRHR8foBzoEeuKhAtLT0xEcHIwrV66gpKQEoaGhsLCwQEhICNatW4eCggIcOnQITk5OqKurw08//aTskOUoiv/06dP46KOP8O233+L06dPg8/koKSnBBx98gMzMTCxYsAB3795FXl6esg9BTnR0NFJSUpCYmIiFCxeiubkZlZWV6OjogLu7O8zNzXH27FmYmpri2rVrkMlkyg5ZocGuLQBISEjAjh07EBMTo+RIB3fw4EFUV1dj1qxZ2LVrFwCgp6cHixcvhoeHBy5cuAChUIj8/Hw8efJEaXE2NzfDz88P8fHxWL16NR48eIC8vDwwxuDj44OQkBCcOHECUqkUV65c4f4of+edd+Di4oLk5GSoq6ujrKwMmpqa3H4fPnyIPXv2ICMjA3w+Hxs3bsTatWuRn5+vrEMdtN47OTkhNDSUu85UlaK63t7ejpUrV2LFihU4fvw4GhoaXolhfgcPHsTUqVNx9OhRFBcXQ11dHcbGxhCLxVi+fDnU1dWVHeKwvQr3jLEoPT0dkZGRuHLlCk6ePIn3338fZ86cwerVq7F9+3YkJibC398ft2/fxg8//IDf/va3iIiIwPr161FaWooPP/xQ2YfAGaxdBoDc3Fxoa2tDIpGgvr4eQUFBMDQ05L6EeFWoqanh0KFDsLa2Rm1tLTZu3IjIyEgcPnxY2aHJY0Sp3N3dmYODA5PJZFxaVFQUc3BwYFVVVQwA++abb5QY4eAGi58xxiIiIpi7uzuXl52dzYRCIWtvbx/tUJ9Je3s709LSYikpKf3yPv/8cyYQCFhra6sSIhu+oc6NpaUl8/HxUVZ4w+bu7s4iIiK4z9HR0cza2ppJpVLlBdXH1atXGQBWX18vl97a2soAMIlEMuB2AoGApaWlDZgnFosZAFZYWMilVVRUMACsqKjo5QU/DM9ybSUmJioltmc1WF1PTk5mhoaGrKuri0tLSUlhAFhpaekoRjl8iYmJzNLSkvsMgJ05c0Zp8Tyv3vqu6veMwTzdZg10HsaNG8fEYvGoxzUUd3d3tnDhQu7zkydPmJ6eHvP39+fSmpubGQBWUFDAoqKi2KxZs+T28cc//pEBYPfu3RutsBVS1C4zxlhAQACbMGEC6+zs5NKSk5OZvr4+6+npGc0whzRQu+rk5MRiYmIGLP+3v/2NGRoajnxgw0RDrVTAvHnz5IYjzJ8/HzU1NSgtLYW6ujrc3d2VGN3QFMXf09PTr+yyZctgaWkJGxsb+Pv7IysrCw8fPhzNcAdVUVGBx48fY+nSpf3yysrK4OLi8kqNPR7q3Li6uiortBdWVlaGRYsWyT0ZUDYnJycsXboUjo6OWLNmDVJSUnDv3j1MmDABgYGB8PLywsqVK3Hw4EE0Nzdz223duhXr16+Hp6cn9u3b12+4mIaGBubMmcN9nj59OgwMDFBRUTFqx9bXcOq9KhqsrldVVUEkEkFbW5tLmzt37miGR/6fqt8zxiqRSMT9X11dHYaGhnB0dOTSTExMAAA//vgjqqqq5NonQLXqi6J2+el8XV1d7vP8+fPR0dGh9OGsw/Wvf/0LS5cuhbm5OQQCAfz9/dHa2qpy9YU6Hirs6ZveWCEQCHDt2jWcOHECZmZm2LFjB5ycnFRmHKiOjs5z5b2q9PT0lB3Cc1PF86Guro5vvvkGX331FWbMmIGkpCTY29ujrq4OYrEYBQUFWLBgAU6ePAk7OzsUFhYCAHbu3ImbN2/izTffxIULFzBjxgycOXNGyUcztqni9UP6U/V7xrPi8Xjc0J5e3d3dSopmaH2/0OHxeHJpvV86qPJQ416DtcuvEjU1NYXXUH19Pby9vSESiZCdnY2rV6/ir3/9KwCo3HwV6niogL6TkwsLCzFt2jQ4OTlBJpPh0qVLSors2SiKX9F4Yg0NDXh6eiI+Ph7Xr19HfX09Lly4MBqhDmnatGnQ0dFBbm5uvzyRSISysjLcvXtXCZE9n+GeG1XG5/Plvk0XiUTIy8tTuZs3j8eDm5sbPv74Y5SWloLP53OdCBcXF0RHR+Py5cuYNWsWjh8/zm1nZ2eHLVu24Pz58/jNb34DsVjM5T158oSbbA78/I38/fv34eDgMHoH1sdg11bfc6WKBqvr9vb2uHHjBh4/fsylFRcXj2Z4L42mpqbKn4uhqPI941kZGRnJPeWsqalRuW+in5e9vb1c+wSoXn0ZrF0uLy9HV1cXV7awsBD6+vqYMmWKssIdUN9rqL29nes8Xb16FTKZDJ9++inmzZsHOzs7NDU1KSvUQVHHQwXcvn0bW7duRVVVFU6cOIGkpCRERETAysoKAQEBeO+995CTk4O6ujpIJBKcOnVK2SHLURT/QM6dO4dDhw6hrKwMDQ0NyMjIgEwmg729/ShHPTBtbW1ERUUhMjISGRkZuHXrFgoLC5Gamgo/Pz+YmprCx8cH+fn5qK2tRXZ2NgoKCpQdtkLDOTeqzsrKCkVFRaivr8dPP/2E8PBwtLe3Y+3atSgpKUFNTQ0yMzNRVVWltBiLioqwd+9elJSU4Pbt2zh9+jTu3LkDHR0dREdHo6CgAA0NDTh//jxqamrg4OCArq4uhIeHQyKRoKGhAfn5+SguLpbrVGhqamLTpk0oKirC1atXERgYiHnz5il1OMNg15aVlRX+/e9/o7GxUeVehtFrsLr+9ttvQyaTITQ0FBUVFfj666+RkJAAACr9lq6BWFlZITc3Fy0tLXLDS14Vqn7PeFavv/46PvvsM5SWlqKkpARhYWEqNUz0RWzYsAGVlZWIiopCdXU1Tp06xb2tSxXqi6J2ubeNlUqlCA4OxnfffYcvv/wSMTExCA8Ph5qaav2J/PrrryMzMxN5eXm4ceMGAgICuC8RbW1t0d3djaSkJNTW1iIzMxNHjhxRcsQKKHuSyf86d3d3tnHjRhYWFsaEQiEbP3482759Ozdps6uri23ZsoWZmZkxPp/PbG1t2bFjx5Qc9S+Gir/v5PK8vDzm7u7Oxo8fz3R0dJhIJGInT55UUvQD6+npYbt372aWlpZMU1OTWVhYsL179zLGGKuvr2e+vr5MKBQyXV1d5urqqrQJvkMZ6ty8ChOAn1ZVVcXmzZvHdHR0GABWV1fHysvL2RtvvMF0dXWZQCBgixYtYrdu3VJajN999x3z8vJiRkZGTEtLi9nZ2bGkpCTW0tLCfHx8uHpsaWnJduzYwXp6etjjx4/Z2rVr2ZQpUxifz2eTJk1i4eHh3MRmsVjMxo0bx7Kzs5mNjQ3T0tJinp6erKGhQWnHOdS1VVBQwEQiEdPS0mKqfJsZrK7n5+czkUjE+Hw+mz17Njt+/DgDwCorK5Uc9eD6Ti4/e/Yss7W1ZRoaGnLpqq53YvarcM9Q5OnJ5Y2NjeyNN95genp6bNq0aezLL79U6cnlT7/Ig7GB7xd4asL83//+d2Zra8u0tLSYh4cHS05OZgDkXtCgLIraZcZ+nly+atUqtmPHDmZoaMj09fVZSEgIe/TokZKj7q+trY299dZbTCgUsilTprC0tDS5yeUHDhxgZmZmTEdHh3l5ebGMjAyVmeD/NB5jfQaMEULGBA8PDzg7O9MK0q+4tLQ0bN68+ZUb0z7WZGVlISgoCG1tbTQ/hJAh7NmzB0eOHFH5CdqBgYG4f/9+vzVWyMihdTwIIYSQPjIyMmBjYwNzc3OUl5cjKioKv/vd76jTQcgADh8+jDlz5sDQ0BD5+fnYv38/wsPDlR0WUUHU8SCEEEL6aGlpwY4dO9DS0gIzMzOsWbPmlVtQjJDRUlNTg927d+Pu3buwsLDAH/7wB0RHRys7LKKCaKgVIYQQQgghZMSp1pR9QgghhBBCyJhEHQ9CCCGEEELIiKOOByFjUEtLCyIiImBrawttbW2YmJjAzc0NycnJ/Rat+uSTT6Curo79+/f3209aWhp4PB54PB7U1NQwefJkBAUF4ccff+TK9ObzeDxoaGjAwsICW7dulVt87c6dO3j//fdhYWEBLS0tmJqawsvLC/n5+QqPob6+HsHBwbC2toaOjg6mTp2KmJgYuVVYJRIJVq1aBTMzM+jp6cHZ2RlZWVkv8qsjhJARExgYCB6Ph3379sml5+TkcGteSCQSuXbVxMQEvr6+qK2t5cpbWVlx+erq6pg0aRKCg4Ofaa0WqVSK+Ph4ODk5QVdXFxMnToSbmxvEYrHKLchKxh6aXE7IGFNbWws3NzcYGBhg7969cHR0hJaWFm7cuIGjR4/C3Nwcv/71r7nyx44dQ2RkJI4dO4Zt27b1259QKERVVRVkMhnKy8sRFBSEpqYmfP3111wZsViM5cuXo7u7myujp6eH2NhYAICvry+kUinS09NhY2ODH374Abm5uWhtbVV4HJWVlZDJZPj8889ha2uLb7/9FiEhIejs7OQWc7t8+TJEIhGioqJgYmKCc+fOYd26dRg3bhy8vb1f1q+UEEJeGm1tbcTFxWHDhg0YP368wnJVVVUQCASoqalBaGgoVq5cievXr3OLxu3atQshISHo6elBdXU1QkND8cEHHyAzM1PhPqVSKby8vFBeXo7Y2Fi4ublBKBSisLAQCQkJcHFxgbOz88s+ZEJ+odxlRAghL5uXlxebPHky6+joGDC/d5E3xhiTSCTM3NycSaVSNmnSJJafny9Xtnfxuqft2bOHqampsYcPHzLG5BeR6hUcHMxWrFjBGGPs3r17DACTSCQveGSMxcfHM2tr60HLrFixggUFBb3wzyKEkJctICCAeXt7s+nTp7Nt27Zx6WfOnOEW27x48WK/hd+ysrLkFrAcaEG/2NhYNmPGjEF/flxcHFNTU2PXrl3rlyeVShXeNwh5WWioFSFjSGtrK86fP4/f//730NPTG7BM7+N8AEhNTYWfnx80NTXh5+eH1NTUIX+Gjo4OZDIZnjx5MmB+dXU1Lly4gF/96lcAAH19fejr6yMnJ0du+NXzaGtrw4QJE164DCGEKIu6ujr27t2LpKQk/Pe//32mbXrXj3l6qOnTGhsb8Y9//INrdxXJysqCp6cnXFxc+uVpamoqvG8Q8rJQx4OQMeQ///kPGGOwt7eXS584cSLXAYiKigIAtLe344svvsC7774LAHj33Xdx6tQpdHR0KNx/TU0Njhw5AldXVwgEAi7dz88P+vr60NbWhr29PWbOnMm9w11DQwNpaWlIT0+HgYEB3NzcsH37dly/fn3Yx5aUlIQNGzYoLHPq1CkUFxcjKChoWPsmhJDRtHr1ajg7OyMmJmbIss3NzUhISIC5ublc2x4VFQV9fX3o6Ohg8uTJ4PF4OHDgwKD7qqmpwfTp0184fkKeF3U8CPkfcOXKFZSVlWHmzJncU4cTJ05g6tSpcHJyAgA4OzvD0tISJ0+elNu2ra0N+vr60NXVhb29PUxMTPpN4E5MTERZWRnKy8tx7tw5VFdXw9/fn8v39fVFU1MTzp49i+XLl0MikeC1115DWloaACAsLIzrGOnr6/eLv7GxEcuXL8eaNWsQEhIy4DFevHgRQUFBSElJwcyZM5/7d0UIIaMhLi4O6enpqKioGDB/8uTJ0NPTw6RJk9DZ2Yns7Gzw+Xwuf9u2bSgrK8P169eRm5sLAHjzzTfR09MDAHJtalhYGACA0dJtRMlocjkhY4itrS14PB6qqqrk0m1sbAD88rge+HmY1c2bN6Gh8UszIJPJcOzYMQQHB3NpAoEA165dg5qaGszMzOT20cvU1BS2trYAAHt7ezx48AB+fn7YvXs3l66trY1ly5Zh2bJl+POf/4z169cjJiYGgYGB2LVrFz788MMBj6mpqQlLlizBggULcPTo0QHLXLp0CStXrkRiYiLWrVv3LL8qQghRqsWLF8PLywvR0dEIDAzsl5+XlwehUAhjY2O5J8y9Jk6cyLWv06ZNw1/+8hfMnz8fFy9ehKenJ8rKyriyQqEQAGBnZ4fKysoROR5CngV1PAgZQwwNDbFs2TJ89tln2LRpk8Lxujdu3EBJSQkkEoncfIi7d+/Cw8MDlZWV3ON4NTU17ub2rHrfutLV1aWwzIwZM5CTkwMAMDY2hrGxcb8yjY2NWLJkCWbPng2xWAw1tf4PaSUSCby9vREXF4fQ0NBhxUkIIcq0b98+ODs79xseCwDW1tYwMDB45n31bXcHarfffvttbN++HaWlpf3meXR3d0MqldI8DzKiqONByBhz+PBhuLm5wdXVFTt37oRIJIKamhqKi4tRWVmJ2bNnIzU1FXPnzsXixYv7bT9nzhykpqYOuK6HIvfv30dLSwtkMhlqamqwa9cu2NnZwcHBAa2trVizZg3ee+89iEQiCAQClJSUID4+HqtWrVK4z8bGRnh4eMDS0hIJCQm4c+cOl2dqagrg5+FV3t7eiIiIgK+vL1paWgAAfD6fJpgTQlSeo6Mj3nnnHRw6dGjY2z548AAtLS1gjOH7779HZGQkjIyMsGDBAoXbbN68Gf/85z+xdOlSxMbGYuHChVybHBcXh9TUVHqdLhlZSn6rFiFkBDQ1NbHw8HBmbW3NNDU1mb6+Pps7dy7bv38/a2trY4aGhiw+Pn7AbePi4pixsTGTSqUDvk63LwDcPx6Px8zMzNhbb73Fbt26xRhj7NGjR+yjjz5ir732Ghs3bhzT1dVl9vb27E9/+hP3St6BiMViuX0//a9XQEDAgPnu7u7D/p0RQshICwgIYKtWrZJLq6urY3w+f9DX6fZlaWkp1+YZGRmxFStWsNLS0iFjePToEfvkk0+Yo6Mj09bWZhMmTGBubm4sLS2NdXd3v8DRETI0HmM004gQQgghhBAysuitVoQQQgghhJARRx0PQgghhBBCyIijjgchhBBCCCFkxFHHgxBCCCGEEDLiqONBCCGEEEIIGXHU8SCEEEIIIYSMOOp4EEIIIYQQQkYcdTwIIYQQQgghI446HoQQQgghhJARRx0PQgghhBBCyIijjgchhBBCCCFkxFHHgxBCCCGEEDLi/g8nRp3Geu4VagAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_noDC['app']\n", - "\n", - "gap_noDC = df_gap22_noDC['simSeconds'].astype(float) * 1000\n", - "gap_noDC_3hr = df_gap22_noDC_3hr['simSeconds'].astype(float) * 1000\n", - "gap_noDC_6hr = df_gap22_noDC_6hr['simSeconds'].astype(float) * 1000\n", - "\n", - "gap_ram = df_gap22_dc_ram['simSeconds'].astype(float) * 1000\n", - "gap_ram_3hr = df_gap22_dc_ram_3hr['simSeconds'].astype(float) * 1000\n", - "gap_ram_6hr = df_gap22_dc_ram_6hr['simSeconds'].astype(float) * 1000\n", - "\n", - "gap_cas = df_gap22_dc_cas['simSeconds'].astype(float) * 1000\n", - "gap_cas_3hr = df_gap22_dc_cas_3hr['simSeconds'].astype(float) * 1000\n", - "gap_cas_6hr = df_gap22_dc_cas_6hr['simSeconds'].astype(float) * 1000\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "\n", - "x = np.arange(6)*4+1\n", - "plt.plot(x, gap_ram/gap_noDC, label='1 hour', color=cmap(1))\n", - "plt.plot(x, gap_ram_3hr/gap_noDC_3hr, label='3 hour', color=cmap(2))\n", - "plt.plot(x, gap_ram_6hr/gap_noDC_6hr, label='6 hour', color=cmap(3))\n", - "plt.scatter(x, gap_ram/gap_noDC, color=cmap(1))\n", - "plt.scatter(x, gap_ram_3hr/gap_noDC_3hr, color=cmap(2))\n", - "plt.scatter(x, gap_ram_6hr/gap_noDC_6hr, color=cmap(3))\n", - "\n", - "app_npb = df_npbC_noDC['app']\n", - "\n", - "npb_noDC = df_npbC_noDC['simSeconds'].astype(float) * 1000\n", - "npb_noDC_3hr = df_npbC_noDC_3hr['simSeconds'].astype(float) * 1000\n", - "npb_noDC_6hr = df_npbC_noDC_6hr['simSeconds'].astype(float) * 1000\n", - "\n", - "npb_ram = df_npbC_dc_ram['simSeconds'].astype(float) * 1000\n", - "npb_ram_3hr = df_npbC_dc_ram_3hr['simSeconds'].astype(float) * 1000\n", - "npb_ram_6hr = df_npbC_dc_ram_6hr['simSeconds'].astype(float) * 1000\n", - "\n", - "npb_cas = df_npbC_dc_cas['simSeconds'].astype(float) * 1000\n", - "npb_cas_3hr = df_npbC_dc_cas_3hr['simSeconds'].astype(float) * 1000\n", - "npb_cas_6hr = df_npbC_dc_cas_6hr['simSeconds'].astype(float) * 1000\n", - "\n", - "x=np.arange(6,14)*4+1\n", - "plt.plot(x, npb_ram/npb_noDC, color=cmap(1))\n", - "plt.plot(x, npb_ram_3hr/npb_noDC_3hr, color=cmap(2))\n", - "plt.plot(x, npb_ram_6hr/npb_noDC_6hr, color=cmap(3))\n", - "plt.scatter(x, npb_ram/npb_noDC, color=cmap(1))\n", - "plt.scatter(x, npb_ram_3hr/npb_noDC_3hr, color=cmap(2))\n", - "plt.scatter(x, npb_ram_6hr/npb_noDC_6hr, color=cmap(3))\n", - "\n", - "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, 0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=23, color='black')\n", - "\n", - "plt.ylabel(\"Speedup\")\n", - "plt.title(\"TDRAM to No-DRAM-$\", fontsize = 9)\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "\n", - "x = np.arange(6)*4+1\n", - "plt.plot(x, gap_cas/gap_noDC, label='1 hour', color=cmap(1))\n", - "plt.plot(x, gap_cas_3hr/gap_noDC_3hr, label='3 hour', color=cmap(2))\n", - "plt.plot(x, gap_cas_6hr/gap_noDC_6hr, label='6 hour', color=cmap(3))\n", - "plt.scatter(x, gap_cas/gap_noDC, color=cmap(1))\n", - "plt.scatter(x, gap_cas_3hr/gap_noDC_3hr, color=cmap(2))\n", - "plt.scatter(x, gap_cas_6hr/gap_noDC_6hr, color=cmap(3))\n", - "\n", - "x=np.arange(6,14)*4+1\n", - "plt.plot(x, npb_cas/npb_noDC, color=cmap(1))\n", - "plt.plot(x, npb_cas_3hr/npb_noDC_3hr, color=cmap(2))\n", - "plt.plot(x, npb_cas_6hr/npb_noDC_6hr, color=cmap(3))\n", - "plt.scatter(x, npb_cas/npb_noDC, color=cmap(1))\n", - "plt.scatter(x, npb_cas_3hr/npb_noDC_3hr, color=cmap(2))\n", - "plt.scatter(x, npb_cas_6hr/npb_noDC_6hr, color=cmap(3))\n", - "\n", - "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, 0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=23, color='black')\n", - "\n", - "plt.ylabel(\"Speedup\")\n", - "plt.title(\"Cascade Lake to No-DRAM-$\", fontsize = 9)\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.6" - }, - "orig_nbformat": 4, - "vscode": { - "interpreter": { - "hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/defMemCtrlr.py b/defMemCtrlr.py deleted file mode 100644 index b7b2cac644..0000000000 --- a/defMemCtrlr.py +++ /dev/null @@ -1,77 +0,0 @@ -from m5.objects import * -import m5 -import argparse -from m5.objects.DRAMInterface import * -from m5.objects.NVMInterface import * - -args = argparse.ArgumentParser() - -args.add_argument( - "device", - type = str, - help = "Memory device to use as a dram cache (local memory)" -) - -args.add_argument( - "traffic_mode", - type = str, - help = "Traffic type to use" -) - -options = args.parse_args() - -system = System() -system.clk_domain = SrcClockDomain() -system.clk_domain.clock = "4GHz" -system.clk_domain.voltage_domain = VoltageDomain() -system.mem_mode = 'timing' - -system.generator = PyTrafficGen() - -system.mem_ctrl = MemCtrl() -system.mem_ctrl.dram = eval(options.device)(range=AddrRange('8GB')) - -system.mem_ranges = [AddrRange('8GB')] - -system.membus = SystemXBar() -system.membus.cpu_side_ports = system.generator.port -system.mem_ctrl.port = system.membus.mem_side_ports -system.membus.frontend_latency = 100 #options.xbarLatency -system.membus.response_latency = 100 #options.xbarLatency - -def createRandomTraffic(tgen): - yield tgen.createRandom(1000000000, # duration - 0, # min_addr - AddrRange("1GB").end, # max_adr - 64, # block_size - 1000, # min_period - 1000, # max_period - 0, # rd_perc - 0) # data_limit - yield tgen.createExit(0) - -def createLinearTraffic(tgen): - yield tgen.createLinear(0, # duration - 0, # min_addr - AddrRange("1GB").end, # max_adr - 64, # block_size - 1000, # min_period - 1000, # max_period - 100, # rd_perc - 104857600) # data_limit - yield tgen.createExit(0) - - -root = Root(full_system=False, system=system) - -m5.instantiate() - -if options.traffic_mode == 'linear': - system.generator.start(createLinearTraffic(system.generator)) -elif options.traffic_mode == 'random': - system.generator.start(createRandomTraffic(system.generator)) -else: - print('Wrong traffic type! Exiting!') - exit() - -exit_event = m5.simulate() \ No newline at end of file diff --git a/dr_trace_player.py b/dr_trace_player.py deleted file mode 100644 index 7eaac2a78d..0000000000 --- a/dr_trace_player.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright (c) 2021 The Regents of the University of California -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -from typing import Optional -from pathlib import Path - -from m5.objects import DRTraceReader -from gem5.utils.override import overrides - -from gem5.components.processors.abstract_generator import AbstractGenerator -from gem5.components.boards.abstract_board import AbstractBoard -from dr_trace_player_core import DRTracePlayerCore - - -class DRTracePlayerGenerator(AbstractGenerator): - def __init__( - self, - trace_directory: Path, - num_cores: int, - max_ipc: int, - max_outstanding_reqs: int, - clk_freq: Optional[str] = None, - ): - super().__init__( - cores=[ - DRTracePlayerCore( - max_ipc=max_ipc, - max_outstanding_reqs=max_outstanding_reqs, - clk_freq=clk_freq, - ) - for _ in range(num_cores) - ] - ) - - self.reader = DRTraceReader( - directory=trace_directory, num_players=num_cores - ) - - for core in self.get_cores(): - core.set_reader(self.reader) - - @overrides(AbstractGenerator) - def start_traffic(self): - """ - Since DRTracePlayer does not need a call to start_traffic to - start generation. This function is just pass. - """ - pass - - @overrides(AbstractGenerator) - def incorporate_processor(self, board: AbstractBoard) -> None: - super().incorporate_processor(board) - for core in self.get_cores(): - core.set_memory_range(board.mem_ranges[0]) diff --git a/dr_trace_player_core.py b/dr_trace_player_core.py deleted file mode 100644 index fd32a7ce4b..0000000000 --- a/dr_trace_player_core.py +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright (c) 2021 The Regents of the University of California -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -from typing import Optional - -from gem5.components.processors.abstract_generator_core import ( - AbstractGeneratorCore, -) -from gem5.components.processors.abstract_core import AbstractCore -from gem5.utils.override import overrides - -from m5.objects import ( - AddrRange, - DRTracePlayer, - DRTraceReader, - Port, - SrcClockDomain, - VoltageDomain, -) - - -class DRTracePlayerCore(AbstractGeneratorCore): - def __init__( - self, - max_ipc: int, - max_outstanding_reqs: int, - clk_freq: Optional[str] = None, - ): - super().__init__() - self.player = DRTracePlayer( - max_ipc=max_ipc, - max_outstanding_reqs=max_outstanding_reqs, - send_data=True, - ) - if clk_freq: - clock_domain = SrcClockDomain( - clock=clk_freq, voltage_domain=VoltageDomain() - ) - self.generator.clk_domain = clock_domain - - @overrides(AbstractCore) - def connect_dcache(self, port: Port) -> None: - self.player.port = port - - def set_reader(self, reader: DRTraceReader): - self.player.reader = reader - - def set_memory_range(self, range: AddrRange): - self.player.compress_address_range = range diff --git a/drtrace-stdlib.py b/drtrace-stdlib.py deleted file mode 100644 index c7625f7e9c..0000000000 --- a/drtrace-stdlib.py +++ /dev/null @@ -1,109 +0,0 @@ -import m5 -import argparse -from m5.objects import * - -from gem5.components.boards.test_board import TestBoard -from gem5.components.memory.hbm import HighBandwidthMemory -from gem5.components.memory.single_channel import SingleChannelDDR4_2400 -from gem5.components.memory.multi_channel import DualChannelDDR4_2400 -from gem5.components.memory.dram_interfaces.hbm import HBM_2000_4H_1x64 - -from gem5.components.cachehierarchies.ruby.mesi_two_level_cache_hierarchy import ( - MESITwoLevelCacheHierarchy, -) - -from gem5.components.cachehierarchies.classic.private_l1_shared_l2_cache_hierarchy import( - PrivateL1SharedL2CacheHierarchy, -) - -from gem5.simulate.simulator import Simulator - -from dr_trace_player import DRTracePlayerGenerator - -parser = argparse.ArgumentParser( - description="A script to run google traces." -) - -benchmark_choices = ["charlie", "delta", "merced", "whiskey"] - -parser.add_argument( - "--path", - type=str, - required=True, - help="Main directory containing the traces.", -) - -parser.add_argument( - "--workload", - type=str, - required=True, - help="Input the benchmark program to execute.", - choices=benchmark_choices, -) - -parser.add_argument( - "--players", - type=int, - required=True, - help="Input the number of players to use.", -) - -parser.add_argument( - "--ruby", - type=int, - required=True, - help="Use with ruby or classic caches", -) - - -args = parser.parse_args() - -generator = DRTracePlayerGenerator( - "{}/{}/".format(args.path, args.workload), - num_cores=8, - max_ipc=8, - max_outstanding_reqs=16, -) - -if args.ruby == 1: - cache_hierarchy = MESITwoLevelCacheHierarchy( - l1d_size="512kB", - l1d_assoc=8, - l1i_size="32kB", - l1i_assoc=2, - l2_size="1MB", - l2_assoc=16, - num_l2_banks=8, - ) -elif args.ruby == 0: - cache_hierarchy = PrivateL1SharedL2CacheHierarchy( - l1d_size="512kB", - l1d_assoc=8, - l1i_size="32kB", - l1i_assoc=2, - l2_size="1MB", - l2_assoc=16, - ) -else: - print("WRONG RUBY OPTION") - exit() - -memory = DualChannelDDR4_2400(size="3GB") - -board = TestBoard( - clk_freq="5GHz", # Ignored for these generators - generator=generator, # We pass the traffic generator as the processor. - memory=memory, - # With no cache hierarchy the test board will directly connect the - # generator to the memory - cache_hierarchy=cache_hierarchy, -) - -root = Root(full_system=False, system=board) - -board._pre_instantiate() -m5.instantiate() -exit_event = m5.simulate(100000000) - -#simulator = Simulator(board=board) -#simulator.run(100000000000) diff --git a/gapbs_checkpoint.sh b/gapbs_checkpoint.sh deleted file mode 100755 index 2ff694c74d..0000000000 --- a/gapbs_checkpoint.sh +++ /dev/null @@ -1,22 +0,0 @@ - -#!/bin/bash - -# $1 is the size of the gapbs to run - -if [ $1 != '22'] && [ $1 != '25'] -then - echo "Run with different size" - exit -fi - -bms=(bc bfs cc pr tc sssp) - -if [! -d checkpoints-gapbs]; then - mkdir -p checkpoints-gapbs; -fi - -for bm in "${bms[@]}" -do -echo $bm -build/RISCV/gem5.opt -re --outdir=$bm.timing Octopi-cache/riscv-2channel-1ccd-checkpoint-timing-gapbs.py --benchmark $bm --size $1 --ckpt_path checkpoints-gapbs/$bm.timing/$bm & -done diff --git a/gapbs_run.sh b/gapbs_run.sh deleted file mode 100755 index 6755d567eb..0000000000 --- a/gapbs_run.sh +++ /dev/null @@ -1,22 +0,0 @@ - -#!/bin/bash - -# $1 is the size of the gapbs to run - -if [ $1 != '22'] && [ $1 != '25'] -then - echo "Run with different size" - exit -fi - -bms=(bc bfs cc pr tc sssp) - -if [! -d GAPBS_Base]; then - mkdir -p GAPBS_Base; -fi - -for bm in "${bms[@]}" -do -echo $bm -M5_OVERRIDE_PY_SOURCE=TRUE build/RISCV/gem5.opt -re --outdir=GAPBS_Base/$bm.22.O3 Octopi-cache/restore-npb-gapbs-looppoint.py --benchmark $bm --size $1 --ckpt_path /projects/gem5/dramcache/jason-checkpoints/gapbs/$1/$bm/ckpt & -done diff --git a/googleTracesRun.sh b/googleTracesRun.sh deleted file mode 100755 index e9d125b202..0000000000 --- a/googleTracesRun.sh +++ /dev/null @@ -1,4 +0,0 @@ -build/X86_MESI_Two_Level/gem5.opt --outdir=gtResults/1/ram/charlie configs-drtrace/drtrace_new.py /projects/google-traces/ charlie 8 Rambus 1 1GiB 8GiB 0 0 & -build/X86_MESI_Two_Level/gem5.opt --outdir=gtResults/1/ram/delta configs-drtrace/drtrace_new.py /projects/google-traces/ delta 8 Rambus 1 1GiB 8GiB 0 0 & -build/X86_MESI_Two_Level/gem5.opt --outdir=gtResults/1/ram/merced configs-drtrace/drtrace_new.py /projects/google-traces/ merced 8 Rambus 1 1GiB 8GiB 0 0 & -build/X86_MESI_Two_Level/gem5.opt --outdir=gtResults/1/ram/whiskey configs-drtrace/drtrace_new.py /projects/google-traces/ whiskey 8 Rambus 1 1GiB 8GiB 0 0 & \ No newline at end of file diff --git a/link.ipynb b/link.ipynb deleted file mode 100644 index e0f8ddf91f..0000000000 --- a/link.ipynb +++ /dev/null @@ -1,1604 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 60, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "import numpy as np\n", - "import sys\n", - "from matplotlib import pyplot as plt\n", - "import os\n", - "\n", - "cmap = plt.get_cmap('Set1')\n", - "\n", - "def getStat(filename, stat, suite, app, i, j, k):\n", - " filename = os.path.join(filename).replace('\\\\','/')\n", - " #print(stat)\n", - " #print(filename)\n", - " try:\n", - " if suite==\"gapbs\" and app==\"bfs\" :\n", - " x = 0\n", - " with open(filename) as f:\n", - " readlines = f.readlines()\n", - " for l in readlines:\n", - " if stat in l and x < (i-1):\n", - " x = x+1\n", - " elif stat in l and x == (i-1):\n", - " return l\n", - " return 0.0 #for cases where stat was not found\n", - " elif suite==\"gapbs\" and app==\"cc\" :\n", - " x = 0\n", - " with open(filename) as f:\n", - " readlines = f.readlines()\n", - " for l in readlines:\n", - " if stat in l and x < (j-1):\n", - " x = x+1\n", - " elif stat in l and x == (j-1):\n", - " return l\n", - " return 0.0 #for cases where stat was not found\n", - " elif suite==\"gapbs\" and app==\"sssp\" :\n", - " x = 0\n", - " with open(filename) as f:\n", - " readlines = f.readlines()\n", - " for l in readlines:\n", - " if stat in l and x < (k-1):\n", - " x = x+1\n", - " elif stat in l and x == (k-1):\n", - " return l\n", - " return 0.0 #for cases where stat was not found\n", - " # elif suite==\"npb\" and app==\"ep\" :\n", - " # x = 0\n", - " # with open(filename) as f:\n", - " # readlines = f.readlines()\n", - " # for l in readlines:\n", - " # if stat in l and x < (3-1):\n", - " # x = x+1\n", - " # elif stat in l and x == (3-1):\n", - " # return l\n", - " # return 0.0 #for cases where stat was not found\n", - " else: \n", - " x = 0\n", - " with open(filename) as f:\n", - " readlines = f.readlines()\n", - " for l in readlines:\n", - " if stat in l and x < 9:\n", - " x = x+1\n", - " elif stat in l and x == 9:\n", - " return l\n", - " return 0.0 #for cases where stat was not found\n", - " except: #for cases where the file was not found\n", - " return 0.0\n", - "\n", - "Stats = ['simSeconds ',\n", - "'hostSeconds ',\n", - "'system.mem_ctrl.readReqs ',\n", - "'system.mem_ctrl.writeReqs ',\n", - "'system.mem_ctrl.servicedByWrQ ',\n", - "'system.mem_ctrl.mergedWrBursts ',\n", - "'system.mem_ctrl.numTotHits ',\n", - "'system.mem_ctrl.numTotMisses ',\n", - "'system.mem_ctrl.numColdMisses ',\n", - "'system.mem_ctrl.numHotMisses ',\n", - "'system.mem_ctrl.numRdMissClean ',\n", - "'system.mem_ctrl.numRdMissDirty ',\n", - "'system.mem_ctrl.numRdHit ',\n", - "'system.mem_ctrl.numWrMissClean ',\n", - "'system.mem_ctrl.numWrMissDirty ',\n", - "'system.mem_ctrl.numWrHit ',\n", - "'system.mem_ctrl.numRdHitDirty ',\n", - "'system.mem_ctrl.numRdHitClean ',\n", - "'system.mem_ctrl.numWrHitDirty ',\n", - "'system.mem_ctrl.numWrHitClean ',\n", - "'system.o3Cpu0.thread_0.numInsts ',\n", - "'system.o3Cpu1.thread_0.numInsts ',\n", - "'system.o3Cpu2.thread_0.numInsts ',\n", - "'system.o3Cpu3.thread_0.numInsts ',\n", - "'system.o3Cpu4.thread_0.numInsts ',\n", - "'system.o3Cpu5.thread_0.numInsts ',\n", - "'system.o3Cpu6.thread_0.numInsts ',\n", - "'system.o3Cpu7.thread_0.numInsts ',\n", - "'system.mem_ctrl.avgRdBWSys ',\n", - "'system.mem_ctrl.avgWrBWSys ',\n", - "'system.mem_ctrl.avgORBLen ',\n", - "'system.far_mem_ctrl.avgRdBWSys ',\n", - "'system.far_mem_ctrl.avgWrBWSys ',\n", - "'system.loc_mem_ctrl.avgRdBWSys ',\n", - "'system.loc_mem_ctrl.avgWrBWSys ',\n", - "'system.loc_mem_ctrl.dram.readBursts ',\n", - "'system.loc_mem_ctrl.dram.writeBursts ',\n", - "'system.loc_mem_ctrl.dram_2.readBursts ',\n", - "'system.loc_mem_ctrl.dram_2.writeBursts ',\n", - "'system.far_mem_ctrl.dram.readBursts ',\n", - "'system.far_mem_ctrl.dram.writeBursts ',\n", - "'system.loc_mem_ctrl.dram.avgRdBW ',\n", - "'system.loc_mem_ctrl.dram.avgWrBW ',\n", - "'system.loc_mem_ctrl.dram_2.avgRdBW ',\n", - "'system.loc_mem_ctrl.dram_2.avgWrBW ',\n", - "'system.far_mem_ctrl.dram.avgRdBW ',\n", - "'system.far_mem_ctrl.dram.avgWrBW ',\n", - "'system.loc_mem_ctrl.dram.busUtil ',\n", - "'system.loc_mem_ctrl.dram.busUtilRead ',\n", - "'system.loc_mem_ctrl.dram.busUtilWrite ',\n", - "'system.loc_mem_ctrl.dram_2.busUtil ',\n", - "'system.loc_mem_ctrl.dram_2.busUtilRead ',\n", - "'system.loc_mem_ctrl.dram_2.busUtilWrite ',\n", - "'system.far_mem_ctrl.dram.busUtil ',\n", - "'system.far_mem_ctrl.dram.busUtilRead ',\n", - "'system.far_mem_ctrl.dram.busUtilWrite ',\n", - "'system.far_mem_ctrl.dram.bytesRead ',\n", - "'system.far_mem_ctrl.dram.bytesWritten ',\n", - "'system.loc_mem_ctrl.dram.bytesRead ',\n", - "'system.loc_mem_ctrl.dram.bytesWritten ',\n", - "'system.loc_mem_ctrl.dram_2.bytesRead ',\n", - "'system.loc_mem_ctrl.dram_2.bytesWritten ',\n", - "'system.mem_ctrl.avgTimeTagCheckRes ',\n", - "'system.mem_ctrl.avgTimeTagCheckResRd ',\n", - "'system.mem_ctrl.avgTimeTagCheckResWr ',\n", - "'system.mem_ctrl.avgPktRespTimeRd ',\n", - "'system.mem_ctrl.avgPktRespTimeWr ',\n", - "'system.mem_ctrl.avgPktORBTime ',\n", - "'system.mem_ctrl.avgPktORBTimeRd ',\n", - "'system.mem_ctrl.avgPktORBTimeWr '\n", - " ]\n", - "\n", - "dfCols = [\n", - " 'app',\n", - " 'simSeconds',\n", - " 'hostSeconds',\n", - " 'readReqs',\n", - " 'writeReqs',\n", - " 'servicedByWrQ',\n", - " 'mergedWrBursts',\n", - " 'numTotHits',\n", - " 'numTotMisses',\n", - " 'numColdMisses',\n", - " 'numHotMisses',\n", - " 'numRdMissClean',\n", - " 'numRdMissDirty',\n", - " 'numRdHit',\n", - " 'numWrMissClean',\n", - " 'numWrMissDirty',\n", - " 'numWrHit',\n", - " 'numRdHitDirty',\n", - " 'numRdHitClean',\n", - " 'numWrHitDirty',\n", - " 'numWrHitClean',\n", - " 'numInsts0',\n", - " 'numInsts1',\n", - " 'numInsts2',\n", - " 'numInsts3',\n", - " 'numInsts4',\n", - " 'numInsts5',\n", - " 'numInsts6',\n", - " 'numInsts7',\n", - " 'avgRdBWSys',\n", - " 'avgWrBWSys',\n", - " 'avgORBLen',\n", - " 'farAvgRdBWSys',\n", - " 'farAvgWrBWSys',\n", - " 'locAvgRdBWSys',\n", - " 'locAvgWrBWSys',\n", - " 'readBursts1',\n", - " 'writeBursts1',\n", - " 'readBursts2',\n", - " 'writeBursts2',\n", - " 'readBursts3',\n", - " 'writeBursts3',\n", - " 'loc1AvgRdBW',\n", - " 'loc1AvgWrBW',\n", - " 'loc2AvgRdBW',\n", - " 'loc2AvgWrBW',\n", - " 'farAvgRdBW',\n", - " 'farAvgWrBW',\n", - " 'loc1BusUtil',\n", - " 'loc1BusUtilRead',\n", - " 'loc1BusUtilWrite',\n", - " 'loc2BusUtil',\n", - " 'loc2BusUtilRead',\n", - " 'loc2BusUtilWrite',\n", - " 'farBusUtil',\n", - " 'farBusUtilRead',\n", - " 'farBusUtilWrite',\n", - " 'farBytesRead',\n", - " 'farBytesWritten',\n", - " 'loc1BytesRead',\n", - " 'loc1BytesWritten',\n", - " 'loc2BytesRead',\n", - " 'loc2BytesWritten',\n", - " 'avgTimeTagCheckRes',\n", - " 'avgTimeTagCheckResRd',\n", - " 'avgTimeTagCheckResWr',\n", - " 'avgPktRespTimeRd',\n", - " 'avgPktRespTimeWr',\n", - " 'avgPktORBTime',\n", - " 'avgPktORBTimeRd',\n", - " 'avgPktORBTimeWr'\n", - "\n", - " ]\n", - "\n", - "def gmean(x, size):\n", - " y = 1\n", - " for i in range(size):\n", - " y = x[i] * y\n", - " return y**(1/size)" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/GAPBS/50ns'\n", - "\n", - "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 29, 28, 12)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_g_ram_50ns = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_g_ram_50ns['totNumInsts'] = df_g_ram_50ns['numInsts0'].astype(int)+df_g_ram_50ns['numInsts1'].astype(int)+df_g_ram_50ns['numInsts2'].astype(int)+df_g_ram_50ns['numInsts3'].astype(int)+df_g_ram_50ns['numInsts4'].astype(int)+df_g_ram_50ns['numInsts5'].astype(int)+df_g_ram_50ns['numInsts6'].astype(int)+df_g_ram_50ns['numInsts7'].astype(int)\n", - "df_g_ram_50ns['totBW'] = (df_g_ram_50ns['avgRdBWSys'].astype(float)+df_g_ram_50ns['avgWrBWSys'].astype(float))/1000000000\n", - "df_g_ram_50ns['coldRate'] = (df_g_ram_50ns['numColdMisses'].astype(float) / df_g_ram_50ns['numTotMisses'].astype(float)) *100\n", - "df_g_ram_50ns['injRate'] = (df_g_ram_50ns['readReqs'].astype(float) + df_g_ram_50ns['writeReqs'].astype(float))*64/1000000000 / df_g_ram_50ns['simSeconds'].astype(float)\n", - "df_g_ram_50ns['BIPS'] = (df_g_ram_50ns['totNumInsts'].astype(float)/1000000000)/df_g_ram_50ns['simSeconds'].astype(float)\n", - "\n", - "df_g_ram_50ns['accAmp'] = (df_g_ram_50ns['farBytesRead'].astype(float) + df_g_ram_50ns['farBytesWritten'].astype(float) +\n", - " df_g_ram_50ns['loc1BytesRead'].astype(float) + df_g_ram_50ns['loc1BytesWritten'].astype(float) + \n", - " df_g_ram_50ns['loc2BytesRead'].astype(float) + df_g_ram_50ns['loc2BytesWritten'].astype(float)) / (df_g_ram_50ns['readReqs'].astype(float) * 64 + df_g_ram_50ns['writeReqs'].astype(float) * 64)\n", - "\n", - "df_g_ram_50ns['BWBloat'] = (df_g_ram_50ns['loc1AvgRdBW'].astype(float) + df_g_ram_50ns['loc1AvgWrBW'].astype(float) +\n", - " df_g_ram_50ns['loc2AvgRdBW'].astype(float) + df_g_ram_50ns['loc2AvgWrBW'].astype(float) +\n", - " df_g_ram_50ns['farAvgRdBW'].astype(float) + df_g_ram_50ns['farAvgWrBW'].astype(float)) / ((df_g_ram_50ns['avgRdBWSys'].astype(float) + df_g_ram_50ns['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_g_ram_50ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_ram_50ns.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/NPB/50ns'\n", - "\n", - "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_n_ram_50ns = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_n_ram_50ns['totNumInsts'] = df_n_ram_50ns['numInsts0'].astype(int)+df_n_ram_50ns['numInsts1'].astype(int)+df_n_ram_50ns['numInsts2'].astype(int)+df_n_ram_50ns['numInsts3'].astype(int)+df_n_ram_50ns['numInsts4'].astype(int)+df_n_ram_50ns['numInsts5'].astype(int)+df_n_ram_50ns['numInsts6'].astype(int)+df_n_ram_50ns['numInsts7'].astype(int)\n", - "df_n_ram_50ns['totBW'] = (df_n_ram_50ns['avgRdBWSys'].astype(float)+df_n_ram_50ns['avgWrBWSys'].astype(float))/1000000000\n", - "df_n_ram_50ns['coldRate'] = (df_n_ram_50ns['numColdMisses'].astype(float) / df_n_ram_50ns['numTotMisses'].astype(float)) *100\n", - "df_n_ram_50ns['injRate'] = (df_n_ram_50ns['readReqs'].astype(float) + df_n_ram_50ns['writeReqs'].astype(float))*64/1000000000 / df_n_ram_50ns['simSeconds'].astype(float)\n", - "df_n_ram_50ns['BIPS'] = (df_n_ram_50ns['totNumInsts'].astype(float)/1000000000)/df_n_ram_50ns['simSeconds'].astype(float)\n", - "\n", - "df_n_ram_50ns['accAmp'] = (df_n_ram_50ns['farBytesRead'].astype(float) + df_n_ram_50ns['farBytesWritten'].astype(float) +\n", - " df_n_ram_50ns['loc1BytesRead'].astype(float) + df_n_ram_50ns['loc1BytesWritten'].astype(float) + \n", - " df_n_ram_50ns['loc2BytesRead'].astype(float) + df_n_ram_50ns['loc2BytesWritten'].astype(float)) / (df_n_ram_50ns['readReqs'].astype(float) * 64 + df_n_ram_50ns['writeReqs'].astype(float) * 64)\n", - "\n", - "df_n_ram_50ns['BWBloat'] = (df_n_ram_50ns['loc1AvgRdBW'].astype(float) + df_n_ram_50ns['loc1AvgWrBW'].astype(float) +\n", - " df_n_ram_50ns['loc2AvgRdBW'].astype(float) + df_n_ram_50ns['loc2AvgWrBW'].astype(float) +\n", - " df_n_ram_50ns['farAvgRdBW'].astype(float) + df_n_ram_50ns['farAvgWrBW'].astype(float)) / ((df_n_ram_50ns['avgRdBWSys'].astype(float) + df_n_ram_50ns['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_n_ram_50ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_ram_50ns.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/GAPBS/100ns'\n", - "\n", - "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 27, 27, 12)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_g_ram_100ns = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_g_ram_100ns['totNumInsts'] = df_g_ram_100ns['numInsts0'].astype(int)+df_g_ram_100ns['numInsts1'].astype(int)+df_g_ram_100ns['numInsts2'].astype(int)+df_g_ram_100ns['numInsts3'].astype(int)+df_g_ram_100ns['numInsts4'].astype(int)+df_g_ram_100ns['numInsts5'].astype(int)+df_g_ram_100ns['numInsts6'].astype(int)+df_g_ram_100ns['numInsts7'].astype(int)\n", - "df_g_ram_100ns['totBW'] = (df_g_ram_100ns['avgRdBWSys'].astype(float)+df_g_ram_100ns['avgWrBWSys'].astype(float))/1000000000\n", - "df_g_ram_100ns['coldRate'] = (df_g_ram_100ns['numColdMisses'].astype(float) / df_g_ram_100ns['numTotMisses'].astype(float)) *100\n", - "df_g_ram_100ns['injRate'] = (df_g_ram_100ns['readReqs'].astype(float) + df_g_ram_100ns['writeReqs'].astype(float))*64/1000000000 / df_g_ram_100ns['simSeconds'].astype(float)\n", - "df_g_ram_100ns['BIPS'] = (df_g_ram_100ns['totNumInsts'].astype(float)/1000000000)/df_g_ram_100ns['simSeconds'].astype(float)\n", - "\n", - "df_g_ram_100ns['accAmp'] = (df_g_ram_100ns['farBytesRead'].astype(float) + df_g_ram_100ns['farBytesWritten'].astype(float) +\n", - " df_g_ram_100ns['loc1BytesRead'].astype(float) + df_g_ram_100ns['loc1BytesWritten'].astype(float) + \n", - " df_g_ram_100ns['loc2BytesRead'].astype(float) + df_g_ram_100ns['loc2BytesWritten'].astype(float)) / (df_g_ram_100ns['readReqs'].astype(float) * 64 + df_g_ram_100ns['writeReqs'].astype(float) * 64)\n", - "\n", - "df_g_ram_100ns['BWBloat'] = (df_g_ram_100ns['loc1AvgRdBW'].astype(float) + df_g_ram_100ns['loc1AvgWrBW'].astype(float) +\n", - " df_g_ram_100ns['loc2AvgRdBW'].astype(float) + df_g_ram_100ns['loc2AvgWrBW'].astype(float) +\n", - " df_g_ram_100ns['farAvgRdBW'].astype(float) + df_g_ram_100ns['farAvgWrBW'].astype(float)) / ((df_g_ram_100ns['avgRdBWSys'].astype(float) + df_g_ram_100ns['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_g_ram_100ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_ram_100ns.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/NPB/100ns'\n", - "\n", - "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_n_ram_100ns = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_n_ram_100ns['totNumInsts'] = df_n_ram_100ns['numInsts0'].astype(int)+df_n_ram_100ns['numInsts1'].astype(int)+df_n_ram_100ns['numInsts2'].astype(int)+df_n_ram_100ns['numInsts3'].astype(int)+df_n_ram_100ns['numInsts4'].astype(int)+df_n_ram_100ns['numInsts5'].astype(int)+df_n_ram_100ns['numInsts6'].astype(int)+df_n_ram_100ns['numInsts7'].astype(int)\n", - "df_n_ram_100ns['totBW'] = (df_n_ram_100ns['avgRdBWSys'].astype(float)+df_n_ram_100ns['avgWrBWSys'].astype(float))/1000000000\n", - "df_n_ram_100ns['coldRate'] = (df_n_ram_100ns['numColdMisses'].astype(float) / df_n_ram_100ns['numTotMisses'].astype(float)) *100\n", - "df_n_ram_100ns['injRate'] = (df_n_ram_100ns['readReqs'].astype(float) + df_n_ram_100ns['writeReqs'].astype(float))*64/1000000000 / df_n_ram_100ns['simSeconds'].astype(float)\n", - "df_n_ram_100ns['BIPS'] = (df_n_ram_100ns['totNumInsts'].astype(float)/1000000000)/df_n_ram_100ns['simSeconds'].astype(float)\n", - "\n", - "df_n_ram_100ns['accAmp'] = (df_n_ram_100ns['farBytesRead'].astype(float) + df_n_ram_100ns['farBytesWritten'].astype(float) +\n", - " df_n_ram_100ns['loc1BytesRead'].astype(float) + df_n_ram_100ns['loc1BytesWritten'].astype(float) + \n", - " df_n_ram_100ns['loc2BytesRead'].astype(float) + df_n_ram_100ns['loc2BytesWritten'].astype(float)) / (df_n_ram_100ns['readReqs'].astype(float) * 64 + df_n_ram_100ns['writeReqs'].astype(float) * 64)\n", - "\n", - "df_n_ram_100ns['BWBloat'] = (df_n_ram_100ns['loc1AvgRdBW'].astype(float) + df_n_ram_100ns['loc1AvgWrBW'].astype(float) +\n", - " df_n_ram_100ns['loc2AvgRdBW'].astype(float) + df_n_ram_100ns['loc2AvgWrBW'].astype(float) +\n", - " df_n_ram_100ns['farAvgRdBW'].astype(float) + df_n_ram_100ns['farAvgWrBW'].astype(float)) / ((df_n_ram_100ns['avgRdBWSys'].astype(float) + df_n_ram_100ns['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_n_ram_100ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_ram_100ns.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/GAPBS/250ns'\n", - "\n", - "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 26, 21, 10)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_g_ram_250ns = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_g_ram_250ns['totNumInsts'] = df_g_ram_250ns['numInsts0'].astype(int)+df_g_ram_250ns['numInsts1'].astype(int)+df_g_ram_250ns['numInsts2'].astype(int)+df_g_ram_250ns['numInsts3'].astype(int)+df_g_ram_250ns['numInsts4'].astype(int)+df_g_ram_250ns['numInsts5'].astype(int)+df_g_ram_250ns['numInsts6'].astype(int)+df_g_ram_250ns['numInsts7'].astype(int)\n", - "df_g_ram_250ns['totBW'] = (df_g_ram_250ns['avgRdBWSys'].astype(float)+df_g_ram_250ns['avgWrBWSys'].astype(float))/1000000000\n", - "df_g_ram_250ns['coldRate'] = (df_g_ram_250ns['numColdMisses'].astype(float) / df_g_ram_250ns['numTotMisses'].astype(float)) *100\n", - "df_g_ram_250ns['injRate'] = (df_g_ram_250ns['readReqs'].astype(float) + df_g_ram_250ns['writeReqs'].astype(float))*64/1000000000 / df_g_ram_250ns['simSeconds'].astype(float)\n", - "df_g_ram_250ns['BIPS'] = (df_g_ram_250ns['totNumInsts'].astype(float)/1000000000)/df_g_ram_250ns['simSeconds'].astype(float)\n", - "\n", - "df_g_ram_250ns['accAmp'] = (df_g_ram_250ns['farBytesRead'].astype(float) + df_g_ram_250ns['farBytesWritten'].astype(float) +\n", - " df_g_ram_250ns['loc1BytesRead'].astype(float) + df_g_ram_250ns['loc1BytesWritten'].astype(float) + \n", - " df_g_ram_250ns['loc2BytesRead'].astype(float) + df_g_ram_250ns['loc2BytesWritten'].astype(float)) / (df_g_ram_250ns['readReqs'].astype(float) * 64 + df_g_ram_250ns['writeReqs'].astype(float) * 64)\n", - "\n", - "df_g_ram_250ns['BWBloat'] = (df_g_ram_250ns['loc1AvgRdBW'].astype(float) + df_g_ram_250ns['loc1AvgWrBW'].astype(float) +\n", - " df_g_ram_250ns['loc2AvgRdBW'].astype(float) + df_g_ram_250ns['loc2AvgWrBW'].astype(float) +\n", - " df_g_ram_250ns['farAvgRdBW'].astype(float) + df_g_ram_250ns['farAvgWrBW'].astype(float)) / ((df_g_ram_250ns['avgRdBWSys'].astype(float) + df_g_ram_250ns['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_g_ram_250ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_ram_250ns.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/NPB/250ns'\n", - "\n", - "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_n_ram_250ns = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_n_ram_250ns['totNumInsts'] = df_n_ram_250ns['numInsts0'].astype(int)+df_n_ram_250ns['numInsts1'].astype(int)+df_n_ram_250ns['numInsts2'].astype(int)+df_n_ram_250ns['numInsts3'].astype(int)+df_n_ram_250ns['numInsts4'].astype(int)+df_n_ram_250ns['numInsts5'].astype(int)+df_n_ram_250ns['numInsts6'].astype(int)+df_n_ram_250ns['numInsts7'].astype(int)\n", - "df_n_ram_250ns['totBW'] = (df_n_ram_250ns['avgRdBWSys'].astype(float)+df_n_ram_250ns['avgWrBWSys'].astype(float))/1000000000\n", - "df_n_ram_250ns['coldRate'] = (df_n_ram_250ns['numColdMisses'].astype(float) / df_n_ram_250ns['numTotMisses'].astype(float)) *100\n", - "df_n_ram_250ns['injRate'] = (df_n_ram_250ns['readReqs'].astype(float) + df_n_ram_250ns['writeReqs'].astype(float))*64/1000000000 / df_n_ram_250ns['simSeconds'].astype(float)\n", - "df_n_ram_250ns['BIPS'] = (df_n_ram_250ns['totNumInsts'].astype(float)/1000000000)/df_n_ram_250ns['simSeconds'].astype(float)\n", - "\n", - "df_n_ram_250ns['accAmp'] = (df_n_ram_250ns['farBytesRead'].astype(float) + df_n_ram_250ns['farBytesWritten'].astype(float) +\n", - " df_n_ram_250ns['loc1BytesRead'].astype(float) + df_n_ram_250ns['loc1BytesWritten'].astype(float) + \n", - " df_n_ram_250ns['loc2BytesRead'].astype(float) + df_n_ram_250ns['loc2BytesWritten'].astype(float)) / (df_n_ram_250ns['readReqs'].astype(float) * 64 + df_n_ram_250ns['writeReqs'].astype(float) * 64)\n", - "\n", - "df_n_ram_250ns['BWBloat'] = (df_n_ram_250ns['loc1AvgRdBW'].astype(float) + df_n_ram_250ns['loc1AvgWrBW'].astype(float) +\n", - " df_n_ram_250ns['loc2AvgRdBW'].astype(float) + df_n_ram_250ns['loc2AvgWrBW'].astype(float) +\n", - " df_n_ram_250ns['farAvgRdBW'].astype(float) + df_n_ram_250ns['farAvgWrBW'].astype(float)) / ((df_n_ram_250ns['avgRdBWSys'].astype(float) + df_n_ram_250ns['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_n_ram_250ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_ram_250ns.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/GAPBS/500ns'\n", - "\n", - "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 21, 20, 10)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_g_ram_500ns = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_g_ram_500ns['totNumInsts'] = df_g_ram_500ns['numInsts0'].astype(int)+df_g_ram_500ns['numInsts1'].astype(int)+df_g_ram_500ns['numInsts2'].astype(int)+df_g_ram_500ns['numInsts3'].astype(int)+df_g_ram_500ns['numInsts4'].astype(int)+df_g_ram_500ns['numInsts5'].astype(int)+df_g_ram_500ns['numInsts6'].astype(int)+df_g_ram_500ns['numInsts7'].astype(int)\n", - "df_g_ram_500ns['totBW'] = (df_g_ram_500ns['avgRdBWSys'].astype(float)+df_g_ram_500ns['avgWrBWSys'].astype(float))/1000000000\n", - "df_g_ram_500ns['coldRate'] = (df_g_ram_500ns['numColdMisses'].astype(float) / df_g_ram_500ns['numTotMisses'].astype(float)) *100\n", - "df_g_ram_500ns['injRate'] = (df_g_ram_500ns['readReqs'].astype(float) + df_g_ram_500ns['writeReqs'].astype(float))*64/1000000000 / df_g_ram_500ns['simSeconds'].astype(float)\n", - "df_g_ram_500ns['BIPS'] = (df_g_ram_500ns['totNumInsts'].astype(float)/1000000000)/df_g_ram_500ns['simSeconds'].astype(float)\n", - "\n", - "df_g_ram_500ns['accAmp'] = (df_g_ram_500ns['farBytesRead'].astype(float) + df_g_ram_500ns['farBytesWritten'].astype(float) +\n", - " df_g_ram_500ns['loc1BytesRead'].astype(float) + df_g_ram_500ns['loc1BytesWritten'].astype(float) + \n", - " df_g_ram_500ns['loc2BytesRead'].astype(float) + df_g_ram_500ns['loc2BytesWritten'].astype(float)) / (df_g_ram_500ns['readReqs'].astype(float) * 64 + df_g_ram_500ns['writeReqs'].astype(float) * 64)\n", - "\n", - "df_g_ram_500ns['BWBloat'] = (df_g_ram_500ns['loc1AvgRdBW'].astype(float) + df_g_ram_500ns['loc1AvgWrBW'].astype(float) +\n", - " df_g_ram_500ns['loc2AvgRdBW'].astype(float) + df_g_ram_500ns['loc2AvgWrBW'].astype(float) +\n", - " df_g_ram_500ns['farAvgRdBW'].astype(float) + df_g_ram_500ns['farAvgWrBW'].astype(float)) / ((df_g_ram_500ns['avgRdBWSys'].astype(float) + df_g_ram_500ns['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_g_ram_500ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_ram_500ns.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/NPB/500ns'\n", - "\n", - "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_n_ram_500ns = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_n_ram_500ns['totNumInsts'] = df_n_ram_500ns['numInsts0'].astype(int)+df_n_ram_500ns['numInsts1'].astype(int)+df_n_ram_500ns['numInsts2'].astype(int)+df_n_ram_500ns['numInsts3'].astype(int)+df_n_ram_500ns['numInsts4'].astype(int)+df_n_ram_500ns['numInsts5'].astype(int)+df_n_ram_500ns['numInsts6'].astype(int)+df_n_ram_500ns['numInsts7'].astype(int)\n", - "df_n_ram_500ns['totBW'] = (df_n_ram_500ns['avgRdBWSys'].astype(float)+df_n_ram_500ns['avgWrBWSys'].astype(float))/1000000000\n", - "df_n_ram_500ns['coldRate'] = (df_n_ram_500ns['numColdMisses'].astype(float) / df_n_ram_500ns['numTotMisses'].astype(float)) *100\n", - "df_n_ram_500ns['injRate'] = (df_n_ram_500ns['readReqs'].astype(float) + df_n_ram_500ns['writeReqs'].astype(float))*64/1000000000 / df_n_ram_500ns['simSeconds'].astype(float)\n", - "df_n_ram_500ns['BIPS'] = (df_n_ram_500ns['totNumInsts'].astype(float)/1000000000)/df_n_ram_500ns['simSeconds'].astype(float)\n", - "\n", - "df_n_ram_500ns['accAmp'] = (df_n_ram_500ns['farBytesRead'].astype(float) + df_n_ram_500ns['farBytesWritten'].astype(float) +\n", - " df_n_ram_500ns['loc1BytesRead'].astype(float) + df_n_ram_500ns['loc1BytesWritten'].astype(float) + \n", - " df_n_ram_500ns['loc2BytesRead'].astype(float) + df_n_ram_500ns['loc2BytesWritten'].astype(float)) / (df_n_ram_500ns['readReqs'].astype(float) * 64 + df_n_ram_500ns['writeReqs'].astype(float) * 64)\n", - "\n", - "df_n_ram_500ns['BWBloat'] = (df_n_ram_500ns['loc1AvgRdBW'].astype(float) + df_n_ram_500ns['loc1AvgWrBW'].astype(float) +\n", - " df_n_ram_500ns['loc2AvgRdBW'].astype(float) + df_n_ram_500ns['loc2AvgWrBW'].astype(float) +\n", - " df_n_ram_500ns['farAvgRdBW'].astype(float) + df_n_ram_500ns['farAvgWrBW'].astype(float)) / ((df_n_ram_500ns['avgRdBWSys'].astype(float) + df_n_ram_500ns['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_n_ram_500ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_ram_500ns.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 52, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/GAPBS/1us'\n", - "\n", - "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 18, 16, 10)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_g_ram_1us = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_g_ram_1us['totNumInsts'] = df_g_ram_1us['numInsts0'].astype(int)+df_g_ram_1us['numInsts1'].astype(int)+df_g_ram_1us['numInsts2'].astype(int)+df_g_ram_1us['numInsts3'].astype(int)+df_g_ram_1us['numInsts4'].astype(int)+df_g_ram_1us['numInsts5'].astype(int)+df_g_ram_1us['numInsts6'].astype(int)+df_g_ram_1us['numInsts7'].astype(int)\n", - "df_g_ram_1us['totBW'] = (df_g_ram_1us['avgRdBWSys'].astype(float)+df_g_ram_1us['avgWrBWSys'].astype(float))/1000000000\n", - "df_g_ram_1us['coldRate'] = (df_g_ram_1us['numColdMisses'].astype(float) / df_g_ram_1us['numTotMisses'].astype(float)) *100\n", - "df_g_ram_1us['injRate'] = (df_g_ram_1us['readReqs'].astype(float) + df_g_ram_1us['writeReqs'].astype(float))*64/1000000000 / df_g_ram_1us['simSeconds'].astype(float)\n", - "df_g_ram_1us['BIPS'] = (df_g_ram_1us['totNumInsts'].astype(float)/1000000000)/df_g_ram_1us['simSeconds'].astype(float)\n", - "\n", - "df_g_ram_1us['accAmp'] = (df_g_ram_1us['farBytesRead'].astype(float) + df_g_ram_1us['farBytesWritten'].astype(float) +\n", - " df_g_ram_1us['loc1BytesRead'].astype(float) + df_g_ram_1us['loc1BytesWritten'].astype(float) + \n", - " df_g_ram_1us['loc2BytesRead'].astype(float) + df_g_ram_1us['loc2BytesWritten'].astype(float)) / (df_g_ram_1us['readReqs'].astype(float) * 64 + df_g_ram_1us['writeReqs'].astype(float) * 64)\n", - "\n", - "df_g_ram_1us['BWBloat'] = (df_g_ram_1us['loc1AvgRdBW'].astype(float) + df_g_ram_1us['loc1AvgWrBW'].astype(float) +\n", - " df_g_ram_1us['loc2AvgRdBW'].astype(float) + df_g_ram_1us['loc2AvgWrBW'].astype(float) +\n", - " df_g_ram_1us['farAvgRdBW'].astype(float) + df_g_ram_1us['farAvgWrBW'].astype(float)) / ((df_g_ram_1us['avgRdBWSys'].astype(float) + df_g_ram_1us['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_g_ram_1us.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_ram_1us.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/NPB/1us'\n", - "\n", - "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_n_ram_1us = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_n_ram_1us['totNumInsts'] = df_n_ram_1us['numInsts0'].astype(int)+df_n_ram_1us['numInsts1'].astype(int)+df_n_ram_1us['numInsts2'].astype(int)+df_n_ram_1us['numInsts3'].astype(int)+df_n_ram_1us['numInsts4'].astype(int)+df_n_ram_1us['numInsts5'].astype(int)+df_n_ram_1us['numInsts6'].astype(int)+df_n_ram_1us['numInsts7'].astype(int)\n", - "df_n_ram_1us['totBW'] = (df_n_ram_1us['avgRdBWSys'].astype(float)+df_n_ram_1us['avgWrBWSys'].astype(float))/1000000000\n", - "df_n_ram_1us['coldRate'] = (df_n_ram_1us['numColdMisses'].astype(float) / df_n_ram_1us['numTotMisses'].astype(float)) *100\n", - "df_n_ram_1us['injRate'] = (df_n_ram_1us['readReqs'].astype(float) + df_n_ram_1us['writeReqs'].astype(float))*64/1000000000 / df_n_ram_1us['simSeconds'].astype(float)\n", - "df_n_ram_1us['BIPS'] = (df_n_ram_1us['totNumInsts'].astype(float)/1000000000)/df_n_ram_1us['simSeconds'].astype(float)\n", - "\n", - "df_n_ram_1us['accAmp'] = (df_n_ram_1us['farBytesRead'].astype(float) + df_n_ram_1us['farBytesWritten'].astype(float) +\n", - " df_n_ram_1us['loc1BytesRead'].astype(float) + df_n_ram_1us['loc1BytesWritten'].astype(float) + \n", - " df_n_ram_1us['loc2BytesRead'].astype(float) + df_n_ram_1us['loc2BytesWritten'].astype(float)) / (df_n_ram_1us['readReqs'].astype(float) * 64 + df_n_ram_1us['writeReqs'].astype(float) * 64)\n", - "\n", - "df_n_ram_1us['BWBloat'] = (df_n_ram_1us['loc1AvgRdBW'].astype(float) + df_n_ram_1us['loc1AvgWrBW'].astype(float) +\n", - " df_n_ram_1us['loc2AvgRdBW'].astype(float) + df_n_ram_1us['loc2AvgWrBW'].astype(float) +\n", - " df_n_ram_1us['farAvgRdBW'].astype(float) + df_n_ram_1us['farAvgWrBW'].astype(float)) / ((df_n_ram_1us['avgRdBWSys'].astype(float) + df_n_ram_1us['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_n_ram_1us.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_ram_1us.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 51, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/GAPBS/2us'\n", - "\n", - "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 15, 13, 10)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_g_ram_2us = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_g_ram_2us['totNumInsts'] = df_g_ram_2us['numInsts0'].astype(int)+df_g_ram_2us['numInsts1'].astype(int)+df_g_ram_2us['numInsts2'].astype(int)+df_g_ram_2us['numInsts3'].astype(int)+df_g_ram_2us['numInsts4'].astype(int)+df_g_ram_2us['numInsts5'].astype(int)+df_g_ram_2us['numInsts6'].astype(int)+df_g_ram_2us['numInsts7'].astype(int)\n", - "df_g_ram_2us['totBW'] = (df_g_ram_2us['avgRdBWSys'].astype(float)+df_g_ram_2us['avgWrBWSys'].astype(float))/1000000000\n", - "df_g_ram_2us['coldRate'] = (df_g_ram_2us['numColdMisses'].astype(float) / df_g_ram_2us['numTotMisses'].astype(float)) *100\n", - "df_g_ram_2us['injRate'] = (df_g_ram_2us['readReqs'].astype(float) + df_g_ram_2us['writeReqs'].astype(float))*64/1000000000 / df_g_ram_2us['simSeconds'].astype(float)\n", - "df_g_ram_2us['BIPS'] = (df_g_ram_2us['totNumInsts'].astype(float)/1000000000)/df_g_ram_2us['simSeconds'].astype(float)\n", - "\n", - "df_g_ram_2us['accAmp'] = (df_g_ram_2us['farBytesRead'].astype(float) + df_g_ram_2us['farBytesWritten'].astype(float) +\n", - " df_g_ram_2us['loc1BytesRead'].astype(float) + df_g_ram_2us['loc1BytesWritten'].astype(float) + \n", - " df_g_ram_2us['loc2BytesRead'].astype(float) + df_g_ram_2us['loc2BytesWritten'].astype(float)) / (df_g_ram_2us['readReqs'].astype(float) * 64 + df_g_ram_2us['writeReqs'].astype(float) * 64)\n", - "\n", - "df_g_ram_2us['BWBloat'] = (df_g_ram_2us['loc1AvgRdBW'].astype(float) + df_g_ram_2us['loc1AvgWrBW'].astype(float) +\n", - " df_g_ram_2us['loc2AvgRdBW'].astype(float) + df_g_ram_2us['loc2AvgWrBW'].astype(float) +\n", - " df_g_ram_2us['farAvgRdBW'].astype(float) + df_g_ram_2us['farAvgWrBW'].astype(float)) / ((df_g_ram_2us['avgRdBWSys'].astype(float) + df_g_ram_2us['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_g_ram_2us.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_ram_2us.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/rambus/NPB/2us'\n", - "\n", - "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_n_ram_2us = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_n_ram_2us['totNumInsts'] = df_n_ram_2us['numInsts0'].astype(int)+df_n_ram_2us['numInsts1'].astype(int)+df_n_ram_2us['numInsts2'].astype(int)+df_n_ram_2us['numInsts3'].astype(int)+df_n_ram_2us['numInsts4'].astype(int)+df_n_ram_2us['numInsts5'].astype(int)+df_n_ram_2us['numInsts6'].astype(int)+df_n_ram_2us['numInsts7'].astype(int)\n", - "df_n_ram_2us['totBW'] = (df_n_ram_2us['avgRdBWSys'].astype(float)+df_n_ram_2us['avgWrBWSys'].astype(float))/1000000000\n", - "df_n_ram_2us['coldRate'] = (df_n_ram_2us['numColdMisses'].astype(float) / df_n_ram_2us['numTotMisses'].astype(float)) *100\n", - "df_n_ram_2us['injRate'] = (df_n_ram_2us['readReqs'].astype(float) + df_n_ram_2us['writeReqs'].astype(float))*64/1000000000 / df_n_ram_2us['simSeconds'].astype(float)\n", - "df_n_ram_2us['BIPS'] = (df_n_ram_2us['totNumInsts'].astype(float)/1000000000)/df_n_ram_2us['simSeconds'].astype(float)\n", - "\n", - "df_n_ram_2us['accAmp'] = (df_n_ram_2us['farBytesRead'].astype(float) + df_n_ram_2us['farBytesWritten'].astype(float) +\n", - " df_n_ram_2us['loc1BytesRead'].astype(float) + df_n_ram_2us['loc1BytesWritten'].astype(float) + \n", - " df_n_ram_2us['loc2BytesRead'].astype(float) + df_n_ram_2us['loc2BytesWritten'].astype(float)) / (df_n_ram_2us['readReqs'].astype(float) * 64 + df_n_ram_2us['writeReqs'].astype(float) * 64)\n", - "\n", - "df_n_ram_2us['BWBloat'] = (df_n_ram_2us['loc1AvgRdBW'].astype(float) + df_n_ram_2us['loc1AvgWrBW'].astype(float) +\n", - " df_n_ram_2us['loc2AvgRdBW'].astype(float) + df_n_ram_2us['loc2AvgWrBW'].astype(float) +\n", - " df_n_ram_2us['farAvgRdBW'].astype(float) + df_n_ram_2us['farAvgWrBW'].astype(float)) / ((df_n_ram_2us['avgRdBWSys'].astype(float) + df_n_ram_2us['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_n_ram_2us.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_ram_2us.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 59, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/GAPBS/50ns'\n", - "\n", - "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 27, 25, 12)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_g_cas_50ns = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_g_cas_50ns['totNumInsts'] = df_g_cas_50ns['numInsts0'].astype(int)+df_g_cas_50ns['numInsts1'].astype(int)+df_g_cas_50ns['numInsts2'].astype(int)+df_g_cas_50ns['numInsts3'].astype(int)+df_g_cas_50ns['numInsts4'].astype(int)+df_g_cas_50ns['numInsts5'].astype(int)+df_g_cas_50ns['numInsts6'].astype(int)+df_g_cas_50ns['numInsts7'].astype(int)\n", - "df_g_cas_50ns['totBW'] = (df_g_cas_50ns['avgRdBWSys'].astype(float)+df_g_cas_50ns['avgWrBWSys'].astype(float))/1000000000\n", - "df_g_cas_50ns['coldRate'] = (df_g_cas_50ns['numColdMisses'].astype(float) / df_g_cas_50ns['numTotMisses'].astype(float)) *100\n", - "df_g_cas_50ns['injRate'] = (df_g_cas_50ns['readReqs'].astype(float) + df_g_cas_50ns['writeReqs'].astype(float))*64/1000000000 / df_g_cas_50ns['simSeconds'].astype(float)\n", - "df_g_cas_50ns['BIPS'] = (df_g_cas_50ns['totNumInsts'].astype(float)/1000000000)/df_g_cas_50ns['simSeconds'].astype(float)\n", - "\n", - "df_g_cas_50ns['accAmp'] = (df_g_cas_50ns['farBytesRead'].astype(float) + df_g_cas_50ns['farBytesWritten'].astype(float) +\n", - " df_g_cas_50ns['loc1BytesRead'].astype(float) + df_g_cas_50ns['loc1BytesWritten'].astype(float) + \n", - " df_g_cas_50ns['loc2BytesRead'].astype(float) + df_g_cas_50ns['loc2BytesWritten'].astype(float)) / (df_g_cas_50ns['readReqs'].astype(float) * 64 + df_g_cas_50ns['writeReqs'].astype(float) * 64)\n", - "\n", - "df_g_cas_50ns['BWBloat'] = (df_g_cas_50ns['loc1AvgRdBW'].astype(float) + df_g_cas_50ns['loc1AvgWrBW'].astype(float) +\n", - " df_g_cas_50ns['loc2AvgRdBW'].astype(float) + df_g_cas_50ns['loc2AvgWrBW'].astype(float) +\n", - " df_g_cas_50ns['farAvgRdBW'].astype(float) + df_g_cas_50ns['farAvgWrBW'].astype(float)) / ((df_g_cas_50ns['avgRdBWSys'].astype(float) + df_g_cas_50ns['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_g_cas_50ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_cas_50ns.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/NPB/50ns'\n", - "\n", - "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_n_cas_50ns = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_n_cas_50ns['totNumInsts'] = df_n_cas_50ns['numInsts0'].astype(int)+df_n_cas_50ns['numInsts1'].astype(int)+df_n_cas_50ns['numInsts2'].astype(int)+df_n_cas_50ns['numInsts3'].astype(int)+df_n_cas_50ns['numInsts4'].astype(int)+df_n_cas_50ns['numInsts5'].astype(int)+df_n_cas_50ns['numInsts6'].astype(int)+df_n_cas_50ns['numInsts7'].astype(int)\n", - "df_n_cas_50ns['totBW'] = (df_n_cas_50ns['avgRdBWSys'].astype(float)+df_n_cas_50ns['avgWrBWSys'].astype(float))/1000000000\n", - "df_n_cas_50ns['coldRate'] = (df_n_cas_50ns['numColdMisses'].astype(float) / df_n_cas_50ns['numTotMisses'].astype(float)) *100\n", - "df_n_cas_50ns['injRate'] = (df_n_cas_50ns['readReqs'].astype(float) + df_n_cas_50ns['writeReqs'].astype(float))*64/1000000000 / df_n_cas_50ns['simSeconds'].astype(float)\n", - "df_n_cas_50ns['BIPS'] = (df_n_cas_50ns['totNumInsts'].astype(float)/1000000000)/df_n_cas_50ns['simSeconds'].astype(float)\n", - "\n", - "df_n_cas_50ns['accAmp'] = (df_n_cas_50ns['farBytesRead'].astype(float) + df_n_cas_50ns['farBytesWritten'].astype(float) +\n", - " df_n_cas_50ns['loc1BytesRead'].astype(float) + df_n_cas_50ns['loc1BytesWritten'].astype(float) + \n", - " df_n_cas_50ns['loc2BytesRead'].astype(float) + df_n_cas_50ns['loc2BytesWritten'].astype(float)) / (df_n_cas_50ns['readReqs'].astype(float) * 64 + df_n_cas_50ns['writeReqs'].astype(float) * 64)\n", - "\n", - "df_n_cas_50ns['BWBloat'] = (df_n_cas_50ns['loc1AvgRdBW'].astype(float) + df_n_cas_50ns['loc1AvgWrBW'].astype(float) +\n", - " df_n_cas_50ns['loc2AvgRdBW'].astype(float) + df_n_cas_50ns['loc2AvgWrBW'].astype(float) +\n", - " df_n_cas_50ns['farAvgRdBW'].astype(float) + df_n_cas_50ns['farAvgWrBW'].astype(float)) / ((df_n_cas_50ns['avgRdBWSys'].astype(float) + df_n_cas_50ns['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_n_cas_50ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_cas_50ns.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 58, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/GAPBS/100ns'\n", - "\n", - "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 25, 24, 16)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_g_cas_100ns = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_g_cas_100ns['totNumInsts'] = df_g_cas_100ns['numInsts0'].astype(int)+df_g_cas_100ns['numInsts1'].astype(int)+df_g_cas_100ns['numInsts2'].astype(int)+df_g_cas_100ns['numInsts3'].astype(int)+df_g_cas_100ns['numInsts4'].astype(int)+df_g_cas_100ns['numInsts5'].astype(int)+df_g_cas_100ns['numInsts6'].astype(int)+df_g_cas_100ns['numInsts7'].astype(int)\n", - "df_g_cas_100ns['totBW'] = (df_g_cas_100ns['avgRdBWSys'].astype(float)+df_g_cas_100ns['avgWrBWSys'].astype(float))/1000000000\n", - "df_g_cas_100ns['coldRate'] = (df_g_cas_100ns['numColdMisses'].astype(float) / df_g_cas_100ns['numTotMisses'].astype(float)) *100\n", - "df_g_cas_100ns['injRate'] = (df_g_cas_100ns['readReqs'].astype(float) + df_g_cas_100ns['writeReqs'].astype(float))*64/1000000000 / df_g_cas_100ns['simSeconds'].astype(float)\n", - "df_g_cas_100ns['BIPS'] = (df_g_cas_100ns['totNumInsts'].astype(float)/1000000000)/df_g_cas_100ns['simSeconds'].astype(float)\n", - "\n", - "df_g_cas_100ns['accAmp'] = (df_g_cas_100ns['farBytesRead'].astype(float) + df_g_cas_100ns['farBytesWritten'].astype(float) +\n", - " df_g_cas_100ns['loc1BytesRead'].astype(float) + df_g_cas_100ns['loc1BytesWritten'].astype(float) + \n", - " df_g_cas_100ns['loc2BytesRead'].astype(float) + df_g_cas_100ns['loc2BytesWritten'].astype(float)) / (df_g_cas_100ns['readReqs'].astype(float) * 64 + df_g_cas_100ns['writeReqs'].astype(float) * 64)\n", - "\n", - "df_g_cas_100ns['BWBloat'] = (df_g_cas_100ns['loc1AvgRdBW'].astype(float) + df_g_cas_100ns['loc1AvgWrBW'].astype(float) +\n", - " df_g_cas_100ns['loc2AvgRdBW'].astype(float) + df_g_cas_100ns['loc2AvgWrBW'].astype(float) +\n", - " df_g_cas_100ns['farAvgRdBW'].astype(float) + df_g_cas_100ns['farAvgWrBW'].astype(float)) / ((df_g_cas_100ns['avgRdBWSys'].astype(float) + df_g_cas_100ns['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_g_cas_100ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_cas_100ns.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/NPB/100ns'\n", - "\n", - "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_n_cas_100ns = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_n_cas_100ns['totNumInsts'] = df_n_cas_100ns['numInsts0'].astype(int)+df_n_cas_100ns['numInsts1'].astype(int)+df_n_cas_100ns['numInsts2'].astype(int)+df_n_cas_100ns['numInsts3'].astype(int)+df_n_cas_100ns['numInsts4'].astype(int)+df_n_cas_100ns['numInsts5'].astype(int)+df_n_cas_100ns['numInsts6'].astype(int)+df_n_cas_100ns['numInsts7'].astype(int)\n", - "df_n_cas_100ns['totBW'] = (df_n_cas_100ns['avgRdBWSys'].astype(float)+df_n_cas_100ns['avgWrBWSys'].astype(float))/1000000000\n", - "df_n_cas_100ns['coldRate'] = (df_n_cas_100ns['numColdMisses'].astype(float) / df_n_cas_100ns['numTotMisses'].astype(float)) *100\n", - "df_n_cas_100ns['injRate'] = (df_n_cas_100ns['readReqs'].astype(float) + df_n_cas_100ns['writeReqs'].astype(float))*64/1000000000 / df_n_cas_100ns['simSeconds'].astype(float)\n", - "df_n_cas_100ns['BIPS'] = (df_n_cas_100ns['totNumInsts'].astype(float)/1000000000)/df_n_cas_100ns['simSeconds'].astype(float)\n", - "\n", - "df_n_cas_100ns['accAmp'] = (df_n_cas_100ns['farBytesRead'].astype(float) + df_n_cas_100ns['farBytesWritten'].astype(float) +\n", - " df_n_cas_100ns['loc1BytesRead'].astype(float) + df_n_cas_100ns['loc1BytesWritten'].astype(float) + \n", - " df_n_cas_100ns['loc2BytesRead'].astype(float) + df_n_cas_100ns['loc2BytesWritten'].astype(float)) / (df_n_cas_100ns['readReqs'].astype(float) * 64 + df_n_cas_100ns['writeReqs'].astype(float) * 64)\n", - "\n", - "df_n_cas_100ns['BWBloat'] = (df_n_cas_100ns['loc1AvgRdBW'].astype(float) + df_n_cas_100ns['loc1AvgWrBW'].astype(float) +\n", - " df_n_cas_100ns['loc2AvgRdBW'].astype(float) + df_n_cas_100ns['loc2AvgWrBW'].astype(float) +\n", - " df_n_cas_100ns['farAvgRdBW'].astype(float) + df_n_cas_100ns['farAvgWrBW'].astype(float)) / ((df_n_cas_100ns['avgRdBWSys'].astype(float) + df_n_cas_100ns['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_n_cas_100ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_cas_100ns.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 62, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/GAPBS/250ns'\n", - "\n", - "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 24, 19, 10)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_g_cas_250ns = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_g_cas_250ns['totNumInsts'] = df_g_cas_250ns['numInsts0'].astype(int)+df_g_cas_250ns['numInsts1'].astype(int)+df_g_cas_250ns['numInsts2'].astype(int)+df_g_cas_250ns['numInsts3'].astype(int)+df_g_cas_250ns['numInsts4'].astype(int)+df_g_cas_250ns['numInsts5'].astype(int)+df_g_cas_250ns['numInsts6'].astype(int)+df_g_cas_250ns['numInsts7'].astype(int)\n", - "df_g_cas_250ns['totBW'] = (df_g_cas_250ns['avgRdBWSys'].astype(float)+df_g_cas_250ns['avgWrBWSys'].astype(float))/1000000000\n", - "df_g_cas_250ns['coldRate'] = (df_g_cas_250ns['numColdMisses'].astype(float) / df_g_cas_250ns['numTotMisses'].astype(float)) *100\n", - "df_g_cas_250ns['injRate'] = (df_g_cas_250ns['readReqs'].astype(float) + df_g_cas_250ns['writeReqs'].astype(float))*64/1000000000 / df_g_cas_250ns['simSeconds'].astype(float)\n", - "df_g_cas_250ns['BIPS'] = (df_g_cas_250ns['totNumInsts'].astype(float)/1000000000)/df_g_cas_250ns['simSeconds'].astype(float)\n", - "\n", - "df_g_cas_250ns['accAmp'] = (df_g_cas_250ns['farBytesRead'].astype(float) + df_g_cas_250ns['farBytesWritten'].astype(float) +\n", - " df_g_cas_250ns['loc1BytesRead'].astype(float) + df_g_cas_250ns['loc1BytesWritten'].astype(float) + \n", - " df_g_cas_250ns['loc2BytesRead'].astype(float) + df_g_cas_250ns['loc2BytesWritten'].astype(float)) / (df_g_cas_250ns['readReqs'].astype(float) * 64 + df_g_cas_250ns['writeReqs'].astype(float) * 64)\n", - "\n", - "df_g_cas_250ns['BWBloat'] = (df_g_cas_250ns['loc1AvgRdBW'].astype(float) + df_g_cas_250ns['loc1AvgWrBW'].astype(float) +\n", - " df_g_cas_250ns['loc2AvgRdBW'].astype(float) + df_g_cas_250ns['loc2AvgWrBW'].astype(float) +\n", - " df_g_cas_250ns['farAvgRdBW'].astype(float) + df_g_cas_250ns['farAvgWrBW'].astype(float)) / ((df_g_cas_250ns['avgRdBWSys'].astype(float) + df_g_cas_250ns['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_g_cas_250ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_cas_250ns.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/NPB/250ns'\n", - "\n", - "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_n_cas_250ns = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_n_cas_250ns['totNumInsts'] = df_n_cas_250ns['numInsts0'].astype(int)+df_n_cas_250ns['numInsts1'].astype(int)+df_n_cas_250ns['numInsts2'].astype(int)+df_n_cas_250ns['numInsts3'].astype(int)+df_n_cas_250ns['numInsts4'].astype(int)+df_n_cas_250ns['numInsts5'].astype(int)+df_n_cas_250ns['numInsts6'].astype(int)+df_n_cas_250ns['numInsts7'].astype(int)\n", - "df_n_cas_250ns['totBW'] = (df_n_cas_250ns['avgRdBWSys'].astype(float)+df_n_cas_250ns['avgWrBWSys'].astype(float))/1000000000\n", - "df_n_cas_250ns['coldRate'] = (df_n_cas_250ns['numColdMisses'].astype(float) / df_n_cas_250ns['numTotMisses'].astype(float)) *100\n", - "df_n_cas_250ns['injRate'] = (df_n_cas_250ns['readReqs'].astype(float) + df_n_cas_250ns['writeReqs'].astype(float))*64/1000000000 / df_n_cas_250ns['simSeconds'].astype(float)\n", - "df_n_cas_250ns['BIPS'] = (df_n_cas_250ns['totNumInsts'].astype(float)/1000000000)/df_n_cas_250ns['simSeconds'].astype(float)\n", - "\n", - "df_n_cas_250ns['accAmp'] = (df_n_cas_250ns['farBytesRead'].astype(float) + df_n_cas_250ns['farBytesWritten'].astype(float) +\n", - " df_n_cas_250ns['loc1BytesRead'].astype(float) + df_n_cas_250ns['loc1BytesWritten'].astype(float) + \n", - " df_n_cas_250ns['loc2BytesRead'].astype(float) + df_n_cas_250ns['loc2BytesWritten'].astype(float)) / (df_n_cas_250ns['readReqs'].astype(float) * 64 + df_n_cas_250ns['writeReqs'].astype(float) * 64)\n", - "\n", - "df_n_cas_250ns['BWBloat'] = (df_n_cas_250ns['loc1AvgRdBW'].astype(float) + df_n_cas_250ns['loc1AvgWrBW'].astype(float) +\n", - " df_n_cas_250ns['loc2AvgRdBW'].astype(float) + df_n_cas_250ns['loc2AvgWrBW'].astype(float) +\n", - " df_n_cas_250ns['farAvgRdBW'].astype(float) + df_n_cas_250ns['farAvgWrBW'].astype(float)) / ((df_n_cas_250ns['avgRdBWSys'].astype(float) + df_n_cas_250ns['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_n_cas_250ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_cas_250ns.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/GAPBS/500ns'\n", - "\n", - "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 21, 19, 10)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_g_cas_500ns = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_g_cas_500ns['totNumInsts'] = df_g_cas_500ns['numInsts0'].astype(int)+df_g_cas_500ns['numInsts1'].astype(int)+df_g_cas_500ns['numInsts2'].astype(int)+df_g_cas_500ns['numInsts3'].astype(int)+df_g_cas_500ns['numInsts4'].astype(int)+df_g_cas_500ns['numInsts5'].astype(int)+df_g_cas_500ns['numInsts6'].astype(int)+df_g_cas_500ns['numInsts7'].astype(int)\n", - "df_g_cas_500ns['totBW'] = (df_g_cas_500ns['avgRdBWSys'].astype(float)+df_g_cas_500ns['avgWrBWSys'].astype(float))/1000000000\n", - "df_g_cas_500ns['coldRate'] = (df_g_cas_500ns['numColdMisses'].astype(float) / df_g_cas_500ns['numTotMisses'].astype(float)) *100\n", - "df_g_cas_500ns['injRate'] = (df_g_cas_500ns['readReqs'].astype(float) + df_g_cas_500ns['writeReqs'].astype(float))*64/1000000000 / df_g_cas_500ns['simSeconds'].astype(float)\n", - "df_g_cas_500ns['BIPS'] = (df_g_cas_500ns['totNumInsts'].astype(float)/1000000000)/df_g_cas_500ns['simSeconds'].astype(float)\n", - "\n", - "df_g_cas_500ns['accAmp'] = (df_g_cas_500ns['farBytesRead'].astype(float) + df_g_cas_500ns['farBytesWritten'].astype(float) +\n", - " df_g_cas_500ns['loc1BytesRead'].astype(float) + df_g_cas_500ns['loc1BytesWritten'].astype(float) + \n", - " df_g_cas_500ns['loc2BytesRead'].astype(float) + df_g_cas_500ns['loc2BytesWritten'].astype(float)) / (df_g_cas_500ns['readReqs'].astype(float) * 64 + df_g_cas_500ns['writeReqs'].astype(float) * 64)\n", - "\n", - "df_g_cas_500ns['BWBloat'] = (df_g_cas_500ns['loc1AvgRdBW'].astype(float) + df_g_cas_500ns['loc1AvgWrBW'].astype(float) +\n", - " df_g_cas_500ns['loc2AvgRdBW'].astype(float) + df_g_cas_500ns['loc2AvgWrBW'].astype(float) +\n", - " df_g_cas_500ns['farAvgRdBW'].astype(float) + df_g_cas_500ns['farAvgWrBW'].astype(float)) / ((df_g_cas_500ns['avgRdBWSys'].astype(float) + df_g_cas_500ns['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_g_cas_500ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_cas_500ns.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/NPB/500ns'\n", - "\n", - "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_n_cas_500ns = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_n_cas_500ns['totNumInsts'] = df_n_cas_500ns['numInsts0'].astype(int)+df_n_cas_500ns['numInsts1'].astype(int)+df_n_cas_500ns['numInsts2'].astype(int)+df_n_cas_500ns['numInsts3'].astype(int)+df_n_cas_500ns['numInsts4'].astype(int)+df_n_cas_500ns['numInsts5'].astype(int)+df_n_cas_500ns['numInsts6'].astype(int)+df_n_cas_500ns['numInsts7'].astype(int)\n", - "df_n_cas_500ns['totBW'] = (df_n_cas_500ns['avgRdBWSys'].astype(float)+df_n_cas_500ns['avgWrBWSys'].astype(float))/1000000000\n", - "df_n_cas_500ns['coldRate'] = (df_n_cas_500ns['numColdMisses'].astype(float) / df_n_cas_500ns['numTotMisses'].astype(float)) *100\n", - "df_n_cas_500ns['injRate'] = (df_n_cas_500ns['readReqs'].astype(float) + df_n_cas_500ns['writeReqs'].astype(float))*64/1000000000 / df_n_cas_500ns['simSeconds'].astype(float)\n", - "df_n_cas_500ns['BIPS'] = (df_n_cas_500ns['totNumInsts'].astype(float)/1000000000)/df_n_cas_500ns['simSeconds'].astype(float)\n", - "\n", - "df_n_cas_500ns['accAmp'] = (df_n_cas_500ns['farBytesRead'].astype(float) + df_n_cas_500ns['farBytesWritten'].astype(float) +\n", - " df_n_cas_500ns['loc1BytesRead'].astype(float) + df_n_cas_500ns['loc1BytesWritten'].astype(float) + \n", - " df_n_cas_500ns['loc2BytesRead'].astype(float) + df_n_cas_500ns['loc2BytesWritten'].astype(float)) / (df_n_cas_500ns['readReqs'].astype(float) * 64 + df_n_cas_500ns['writeReqs'].astype(float) * 64)\n", - "\n", - "df_n_cas_500ns['BWBloat'] = (df_n_cas_500ns['loc1AvgRdBW'].astype(float) + df_n_cas_500ns['loc1AvgWrBW'].astype(float) +\n", - " df_n_cas_500ns['loc2AvgRdBW'].astype(float) + df_n_cas_500ns['loc2AvgWrBW'].astype(float) +\n", - " df_n_cas_500ns['farAvgRdBW'].astype(float) + df_n_cas_500ns['farAvgWrBW'].astype(float)) / ((df_n_cas_500ns['avgRdBWSys'].astype(float) + df_n_cas_500ns['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_n_cas_500ns.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_cas_500ns.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/GAPBS/1us'\n", - "\n", - "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 17, 16, 10)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_g_cas_1us = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_g_cas_1us['totNumInsts'] = df_g_cas_1us['numInsts0'].astype(int)+df_g_cas_1us['numInsts1'].astype(int)+df_g_cas_1us['numInsts2'].astype(int)+df_g_cas_1us['numInsts3'].astype(int)+df_g_cas_1us['numInsts4'].astype(int)+df_g_cas_1us['numInsts5'].astype(int)+df_g_cas_1us['numInsts6'].astype(int)+df_g_cas_1us['numInsts7'].astype(int)\n", - "df_g_cas_1us['totBW'] = (df_g_cas_1us['avgRdBWSys'].astype(float)+df_g_cas_1us['avgWrBWSys'].astype(float))/1000000000\n", - "df_g_cas_1us['coldRate'] = (df_g_cas_1us['numColdMisses'].astype(float) / df_g_cas_1us['numTotMisses'].astype(float)) *100\n", - "df_g_cas_1us['injRate'] = (df_g_cas_1us['readReqs'].astype(float) + df_g_cas_1us['writeReqs'].astype(float))*64/1000000000 / df_g_cas_1us['simSeconds'].astype(float)\n", - "df_g_cas_1us['BIPS'] = (df_g_cas_1us['totNumInsts'].astype(float)/1000000000)/df_g_cas_1us['simSeconds'].astype(float)\n", - "\n", - "df_g_cas_1us['accAmp'] = (df_g_cas_1us['farBytesRead'].astype(float) + df_g_cas_1us['farBytesWritten'].astype(float) +\n", - " df_g_cas_1us['loc1BytesRead'].astype(float) + df_g_cas_1us['loc1BytesWritten'].astype(float) + \n", - " df_g_cas_1us['loc2BytesRead'].astype(float) + df_g_cas_1us['loc2BytesWritten'].astype(float)) / (df_g_cas_1us['readReqs'].astype(float) * 64 + df_g_cas_1us['writeReqs'].astype(float) * 64)\n", - "\n", - "df_g_cas_1us['BWBloat'] = (df_g_cas_1us['loc1AvgRdBW'].astype(float) + df_g_cas_1us['loc1AvgWrBW'].astype(float) +\n", - " df_g_cas_1us['loc2AvgRdBW'].astype(float) + df_g_cas_1us['loc2AvgWrBW'].astype(float) +\n", - " df_g_cas_1us['farAvgRdBW'].astype(float) + df_g_cas_1us['farAvgWrBW'].astype(float)) / ((df_g_cas_1us['avgRdBWSys'].astype(float) + df_g_cas_1us['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_g_cas_1us.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_cas_1us.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/NPB/1us'\n", - "\n", - "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_n_cas_1us = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_n_cas_1us['totNumInsts'] = df_n_cas_1us['numInsts0'].astype(int)+df_n_cas_1us['numInsts1'].astype(int)+df_n_cas_1us['numInsts2'].astype(int)+df_n_cas_1us['numInsts3'].astype(int)+df_n_cas_1us['numInsts4'].astype(int)+df_n_cas_1us['numInsts5'].astype(int)+df_n_cas_1us['numInsts6'].astype(int)+df_n_cas_1us['numInsts7'].astype(int)\n", - "df_n_cas_1us['totBW'] = (df_n_cas_1us['avgRdBWSys'].astype(float)+df_n_cas_1us['avgWrBWSys'].astype(float))/1000000000\n", - "df_n_cas_1us['coldRate'] = (df_n_cas_1us['numColdMisses'].astype(float) / df_n_cas_1us['numTotMisses'].astype(float)) *100\n", - "df_n_cas_1us['injRate'] = (df_n_cas_1us['readReqs'].astype(float) + df_n_cas_1us['writeReqs'].astype(float))*64/1000000000 / df_n_cas_1us['simSeconds'].astype(float)\n", - "df_n_cas_1us['BIPS'] = (df_n_cas_1us['totNumInsts'].astype(float)/1000000000)/df_n_cas_1us['simSeconds'].astype(float)\n", - "\n", - "df_n_cas_1us['accAmp'] = (df_n_cas_1us['farBytesRead'].astype(float) + df_n_cas_1us['farBytesWritten'].astype(float) +\n", - " df_n_cas_1us['loc1BytesRead'].astype(float) + df_n_cas_1us['loc1BytesWritten'].astype(float) + \n", - " df_n_cas_1us['loc2BytesRead'].astype(float) + df_n_cas_1us['loc2BytesWritten'].astype(float)) / (df_n_cas_1us['readReqs'].astype(float) * 64 + df_n_cas_1us['writeReqs'].astype(float) * 64)\n", - "\n", - "df_n_cas_1us['BWBloat'] = (df_n_cas_1us['loc1AvgRdBW'].astype(float) + df_n_cas_1us['loc1AvgWrBW'].astype(float) +\n", - " df_n_cas_1us['loc2AvgRdBW'].astype(float) + df_n_cas_1us['loc2AvgWrBW'].astype(float) +\n", - " df_n_cas_1us['farAvgRdBW'].astype(float) + df_n_cas_1us['farAvgWrBW'].astype(float)) / ((df_n_cas_1us['avgRdBWSys'].astype(float) + df_n_cas_1us['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_n_cas_1us.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_cas_1us.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 54, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/GAPBS/2us'\n", - "\n", - "app = ['bc', 'bfs', 'cc', 'pr', 'tc', 'sssp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_22/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"gapbs\", a, 15, 14, 10)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_g_cas_2us = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_g_cas_2us['totNumInsts'] = df_g_cas_2us['numInsts0'].astype(int)+df_g_cas_2us['numInsts1'].astype(int)+df_g_cas_2us['numInsts2'].astype(int)+df_g_cas_2us['numInsts3'].astype(int)+df_g_cas_2us['numInsts4'].astype(int)+df_g_cas_2us['numInsts5'].astype(int)+df_g_cas_2us['numInsts6'].astype(int)+df_g_cas_2us['numInsts7'].astype(int)\n", - "df_g_cas_2us['totBW'] = (df_g_cas_2us['avgRdBWSys'].astype(float)+df_g_cas_2us['avgWrBWSys'].astype(float))/1000000000\n", - "df_g_cas_2us['coldRate'] = (df_g_cas_2us['numColdMisses'].astype(float) / df_g_cas_2us['numTotMisses'].astype(float)) *100\n", - "df_g_cas_2us['injRate'] = (df_g_cas_2us['readReqs'].astype(float) + df_g_cas_2us['writeReqs'].astype(float))*64/1000000000 / df_g_cas_2us['simSeconds'].astype(float)\n", - "df_g_cas_2us['BIPS'] = (df_g_cas_2us['totNumInsts'].astype(float)/1000000000)/df_g_cas_2us['simSeconds'].astype(float)\n", - "\n", - "df_g_cas_2us['accAmp'] = (df_g_cas_2us['farBytesRead'].astype(float) + df_g_cas_2us['farBytesWritten'].astype(float) +\n", - " df_g_cas_2us['loc1BytesRead'].astype(float) + df_g_cas_2us['loc1BytesWritten'].astype(float) + \n", - " df_g_cas_2us['loc2BytesRead'].astype(float) + df_g_cas_2us['loc2BytesWritten'].astype(float)) / (df_g_cas_2us['readReqs'].astype(float) * 64 + df_g_cas_2us['writeReqs'].astype(float) * 64)\n", - "\n", - "df_g_cas_2us['BWBloat'] = (df_g_cas_2us['loc1AvgRdBW'].astype(float) + df_g_cas_2us['loc1AvgWrBW'].astype(float) +\n", - " df_g_cas_2us['loc2AvgRdBW'].astype(float) + df_g_cas_2us['loc2AvgWrBW'].astype(float) +\n", - " df_g_cas_2us['farAvgRdBW'].astype(float) + df_g_cas_2us['farAvgWrBW'].astype(float)) / ((df_g_cas_2us['avgRdBWSys'].astype(float) + df_g_cas_2us['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_g_cas_2us.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_g_cas_2us.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": {}, - "outputs": [], - "source": [ - "datadir = '/home/babaie/projects/rambusDesign/results/link/cascade/NPB/2us'\n", - "\n", - "app = ['bt', 'cg', 'is', 'lu', 'sp']\n", - "\n", - "rows = []\n", - "\n", - "for a in app:\n", - " #for t in time:\n", - " #for s in size:\n", - " #for c in cache:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}_C_x/stats.txt'.format(datadir, a)\n", - " ret_line = getStat(time_file_path,stat, \"npb\", a, -1, -1, -1)\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - "\n", - "#print(rows)\n", - "df_n_cas_2us = pd.DataFrame(rows, columns= dfCols)\n", - "\n", - "df_n_cas_2us['totNumInsts'] = df_n_cas_2us['numInsts0'].astype(int)+df_n_cas_2us['numInsts1'].astype(int)+df_n_cas_2us['numInsts2'].astype(int)+df_n_cas_2us['numInsts3'].astype(int)+df_n_cas_2us['numInsts4'].astype(int)+df_n_cas_2us['numInsts5'].astype(int)+df_n_cas_2us['numInsts6'].astype(int)+df_n_cas_2us['numInsts7'].astype(int)\n", - "df_n_cas_2us['totBW'] = (df_n_cas_2us['avgRdBWSys'].astype(float)+df_n_cas_2us['avgWrBWSys'].astype(float))/1000000000\n", - "df_n_cas_2us['coldRate'] = (df_n_cas_2us['numColdMisses'].astype(float) / df_n_cas_2us['numTotMisses'].astype(float)) *100\n", - "df_n_cas_2us['injRate'] = (df_n_cas_2us['readReqs'].astype(float) + df_n_cas_2us['writeReqs'].astype(float))*64/1000000000 / df_n_cas_2us['simSeconds'].astype(float)\n", - "df_n_cas_2us['BIPS'] = (df_n_cas_2us['totNumInsts'].astype(float)/1000000000)/df_n_cas_2us['simSeconds'].astype(float)\n", - "\n", - "df_n_cas_2us['accAmp'] = (df_n_cas_2us['farBytesRead'].astype(float) + df_n_cas_2us['farBytesWritten'].astype(float) +\n", - " df_n_cas_2us['loc1BytesRead'].astype(float) + df_n_cas_2us['loc1BytesWritten'].astype(float) + \n", - " df_n_cas_2us['loc2BytesRead'].astype(float) + df_n_cas_2us['loc2BytesWritten'].astype(float)) / (df_n_cas_2us['readReqs'].astype(float) * 64 + df_n_cas_2us['writeReqs'].astype(float) * 64)\n", - "\n", - "df_n_cas_2us['BWBloat'] = (df_n_cas_2us['loc1AvgRdBW'].astype(float) + df_n_cas_2us['loc1AvgWrBW'].astype(float) +\n", - " df_n_cas_2us['loc2AvgRdBW'].astype(float) + df_n_cas_2us['loc2AvgWrBW'].astype(float) +\n", - " df_n_cas_2us['farAvgRdBW'].astype(float) + df_n_cas_2us['farAvgWrBW'].astype(float)) / ((df_n_cas_2us['avgRdBWSys'].astype(float) + df_n_cas_2us['avgWrBWSys'].astype(float)) / 1000000)\n", - "\n", - "df_n_cas_2us.to_csv(\"/home/babaie/projects/rambusDesign/plots/df_n_cas_2us.csv\")" - ] - }, - { - "cell_type": "code", - "execution_count": 80, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYYAAAC+CAYAAAAx3qiRAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAn5UlEQVR4nO3de1xN+f4/8NeuVBwqFQmxUUq3vZNLNXKpnFy+bg3HYGbIZTDTcUy+ZphhGJzBV6OcwwyOaByXcRzDzDGGIWLOkclQYxg1olSkpKvul8/vj37WmTVdtNm1K6/n47EfD2utz+ez35+9l/3usz7rohBCCBAREf1/eroOgIiImhcmBiIikmFiICIiGSYGIiKSYWIgIiIZJgYiIpJhYiAiIhkmBiIikmFiICIiGSYGIiKSYWIgnVAqlbC3t4darUa/fv0wffp0FBYWIioqCmq1WiqnUCjg4uIClUoFFxcXHD58GABQXl6ORYsWwcnJCSqVCo6Ojti8ebNUr6ioCAMGDEBBQQHGjBkDtVoNtVottadWq+Ht7S17D1dXV/Tt2xfTpk3Dzz//LLW1evVqdOrUSYp1/PjxyMjIkPVnz549UCgU+O6772TrZ82aBYVCgdjYWGldQUEB2rdvL+snAISEhGDjxo0AgNu3b2Py5Mno1asX3N3dMWjQIOzatevZP3AtsLS0RHJy8lPLeXt7IykpqfEDosYjiHSgZ8+eIjY2VgghRGVlpRgzZozYunWrOHfunFCpVFI5ACInJ0cIIcTly5dF27ZtxcOHD8WmTZvEyy+/LMrLy4UQQhQXF4vr169L9TZu3CjWrFlT431/3V5t6yorK8Wnn34qzMzMxJ07d4QQQqxatUr86U9/krZPmTJFLFy4UNbGSy+9JHx9fcXMmTNl62fOnCnc3d1FUFCQtO5vf/ubGDBggKyfT9qIj48X6enpokuXLmLnzp3StuzsbPHpp5/W6E9TsrCwEElJSU8td/ToUfHaa681fkDUaDhiIJ0rKytDUVEROnbsWG+5AQMGoH379khOTkZaWho6d+4MAwMDAICxsTGcnJyksjt27MD06dM1jkVPTw8LFiyAv78/Pvnkk1q3jxgxAnfv3pXWJSQkICkpCXv37sWxY8eQn58vqxMQEIDjx4+jtLQUQPXoYvbs2bIyGRkZyM3Nhb29PbZt2wZvb2/MmzdP2t6xY0csWLAAAHDgwAEMHjwYbm5uUKlU+Ne//iWVW7duHfr16yeNkJ7EGR0djSFDhkClUsHV1RVffvklAOB///d/MXDgQKjVagwdOhQJCQlSW1999RX69esHV1dXvPPOO7J4b926hbFjx2LgwIFwdXXF1q1bpW1jx47FN998g7y8vAZ84tQs6Toz0YupZ8+eom/fvkKlUglTU1Ph4+MjysvL6x0xnD59WpiYmIjc3Fxx/fp10b17d+Hg4CDmzp0rDh48KCoqKoQQQqSkpAgLC4ta3xdPGTE8sXnzZjF69GghhHzEUFJSIsaMGSM+++wzqezSpUvFu+++K4QQYtKkSWLHjh3StpkzZ4rQ0FAxb9488fnnn4ubN28KT0/PGv3csWOHWL58uRBCiNGjR4vNmzfX+dllZWWJqqoqIYQQSUlJwsrKSpSUlIjs7GxhamoqioqKhBBCFBYWiuLiYvHo0SPRuXNnceHCBSFE9ajn0aNHQgghMjMzpXYPHjwo/P39hRBCZGRkCHNzc3Hjxg0pPgAiKSlJVFRUCHd3d3Hz5k3pfVxcXERMTIzU1ogRI8S//vWvOvtAzRtHDKQzhw4dQlxcHLKysqBUKvHuu+/WWs7b2xtqtRp//vOf8eWXX8LU1BROTk64ffs2tm3bhp49e2LVqlUYP348ACAtLQ1WVlbPFZv4zd3o9+/fD7VaDUtLS+Tk5OAPf/gDAKCiogJ79+5FYGAgAGD27NkIDw+v0d6T9eHh4VLZXzt27BgmTZrUoNiSkpIwevRoODs7Y+LEicjOzkZSUhJMTExgZ2eHV199FTt27EB2djaMjY0RHR0Ne3t7aU5FT08P5ubmAIDTp0/D09MTzs7OWLNmDeLi4gAAly5dgqurKxwdHQEAc+bMgaGhIYDqEdKNGzfwyiuvQK1Ww8vLCwUFBbJ5mS5duiAtLa1B/aHmx0DXARAZGBjg5ZdfxtKlSzFu3Lga27/77juYmZnVWG9oaAgfHx/4+Phg7ty5sLa2RnZ2Ntq1a4eSkpLniuny5ctwdnaWlmfMmIGwsDBkZ2dj5MiRWLVqFTZu3Ijjx48jNzcX/v7+AKoTyv3793H9+nVZfQ8PD9y/fx83b97Ezz//jCtXrkjbCgoKkJCQgAEDBgAA3N3dER0djbfffrvW2F555RVs2LABkydPBgCYm5ujpKQE+vr6uHTpEi5evIioqCh4eHjg4MGDdfYxJSUFQUFBuHz5Mvr06YNr165h6NChtZZVKBTSv4UQMDc3l5JIbUpKStC2bds6t1PzxhEDNQtnz56Fvb19g8tfuHAB6enp0vKVK1dgbm4OMzMz2NvbIzMzE8XFxRrHUVVVhb/97W84efIkFi5cWGO7ubk5du3ahW3btiE9PR3h4eEICwtDcnIykpOTcffuXQQHB9c6atiyZQtCQkLQoUMH2foTJ05g9OjR0o/vm2++ifPnz2PPnj1SmdzcXOzYsQMAkJOTg169egEA9u3bh5ycHADVCSYjIwPe3t5YuXIlhgwZgtjYWHh5eeHWrVvSGVNVVVXIzs5GXl4e2rRpA2trawghZPMEnp6euHbtGuLj4wEAu3fvRllZGQDA3t4eJiYmsvgSExORnZ0tLd+8eRMqlaqhHzs1MxwxkM5MnToVbdu2RUVFBXr27Int27fj9u3bDaqbkpKCxYsXo6SkBIaGhmjfvj2+/PJL6OnpwdjYGL///e9x9uxZjB07tkHteXt7Q6FQoKSkBP3798d//vMf6cf3t9zc3DBlyhR88MEHiIyMREREhGz7jBkz4OvrK516+oSvr2+t7R09ehRz586Vlq2trfHvf/8by5Ytw5o1a9ChQwe0adMGb731FoDqBDN58mSYmZnBx8cHPXr0AADk5eVh8uTJKCwshEKhgJ2dHWbOnAlTU1McPXoUS5YsQUFBAfT09LB27VqMGzcOr7zyCpycnGBhYYGJEydKMXTq1Am7d+/GpEmTYGhoiFGjRsHCwgJA9Qjv+PHjWLx4MUJDQ1FZWQlLS0scOHAAAJCcnIzKykomhhZMIX57MJWoFYiJicGaNWtw/PhxXYdSr7KyMvTt2xeJiYnSGVYt3bJly2BraytLdtSy8FAStUqDBg1CQEAACgoKdB1KvQwNDZGcnNxqkgIAdO3atcbpuNSycMRAREQyHDEQEZEMEwMREckwMRARkUzrmfGqQ1VVFe7fv48OHTrILtIhInqRCCFQUFCArl27Qk+v/jFBq08M9+/fh42Nja7DICJqFlJTU9G9e/d6y7T6xPDkKtPU1FSYmJjoOBoiIt3Iz8+HjY1NjSvva9PqE8OTw0cmJiZMDET0wmvIIXVOPhMRkQwTAxERybT6Q0lEzVFlZSXKy8t1HQa1Qm3atIG+vv5ztcHEQNTEHj9+jLS0tBoPAyLSBoVCge7du6N9+/bP3AYTA1ETqqysRFpaGtq1a4dOnTrx2hrSKiEEHj58iLS0NNjZ2T3zyIGJgagJlZeXQwiBTp068Qln1Cg6deqE5ORklJeXP3Ni4OQzkQ5wpECNRRv7VpMmhgsXLmDcuHHo2rUrFAoFjh07Vm/5qKgoKBSKGq8HDx40TcBEL4jy8nJ8+OGHcHBwgJOTE9zc3DBx4kTZc5337NkDhUIhPSL0iVmzZqFbt25Qq9VwcHDA/PnzpYl1pVIJe3t7qNVq9OvXD9OnT0dhYSGA6otOx48fDxcXF7i4uECtVuPs2bNN1mddUCqVcHBwQEVFhbRuwIABiIqKwurVq9GpUyfps5o6dar02Nbhw4ejV69eUKvVcHJywpgxY5CRkdFocTbpoaTCwkKoVCrMnj0bAQEBDa6XkJAguzitc+fOjREekU4ol33daG0nb2jYo00DAwPx+PFjREdHo2PHjgCAM2fOICEhAWq1GgAQHh4OX19fhIeHw9vbW1Z/6dKl0qNWhw0bhu3bt+OPf/wjAODQoUNQq9WoqqrCuHHjEBERgbfeegsLFy6Er68vvvrqKwBAVlYWioqKtNTzOqw2baR28xpctLS0FOHh4Zg/f36NbTNmzEBYWBgqKysxZcoUrFu3Dh9//DEAIDQ0VHr86sKFCxESEoJNmzZpJfzfatLEMHr0aIwePVrjep07d4aZmZn2AyIi3Lp1C0ePHkVqaqqUFADAz89P+ndCQgKSkpJw+fJlODo6Ij8/v9Y7CRgbG2PYsGFISEiosa2srAxFRUXSe6SlpaFbt27SdktLS212q9lavXo13n//fbz22mto165drWX09fXh5+eHEydO1NhWUVGBx48fN+o94FrEHINarYa1tTVGjhyJ//znP/WWLS0tRX5+vuxFRHWLjY2Fra0tzM3N6ywTHh6O1157DV27doWPjw8+//zzWsvl5OTg5MmTcHd3l9ZNnToVarUaXbp0gZ6eHv7whz8AAN59913MmTMHL730EpYsWYILFy5ot2PNlEqlwogRIxAaGlpnmeLiYhw7dkz2Ob799tvSb+GPP/6It956q9FibNaJwdraGtu3b8eRI0dw5MgR2NjYYPjw4bh69WqdddavXw9TU1PpxTurEmnm9u3bUKvVsLe3R2BgICoqKrB3714EBgYCAGbPno3w8HBZnU2bNkGtVsPX1xeTJ0/GrFmzpG2HDh1CXFwcsrKyoFQq8e677wIApk2bhpSUFCxZsgQAMGHChEY7NNLcrF27Flu2bMGjR49k6/fv3w83Nzd4eXnB0dERy5Ytk7aFhoYiLi4OmZmZmDRpUqM+V7tZn65qb28Pe3t7adnLywu3b99GaGgo/v73v9daZ/ny5QgODpaWn9xRkIhq5+bmhsTEROTk5KBjx47o06cP4uLiEBERgWPHjuH48ePIzc2Fv78/gOpz5e/fv4/r16/D2dkZwH/nGOpjYGCAl19+GUuXLpWOm3fs2BEBAQEICAjAwIED8dFHH2Hp0qWN2t/mQKlUYvr06Vi3bp1s/ZM5hvooFApMnToVISEhjRZfsx4x1GbQoEFITEysc7uRkZF0J1XeUZXo6ezs7DBhwgTMmTMHubm50vonZw+Fh4cjLCwMycnJSE5Oxt27dxEcHFxj1NAQZ8+elf7YO378uDTZLIRAbGws+vTp8/wdaiFWrFiBffv24f79+xrXjYyMlP3RrG0tLjHExcXB2tpa12EQtSoRERFwcXHB4MGD4eTkhCFDhuDMmTNYunQpIiMjMWXKFFn5GTNmYN++fSgrK3tq20/mGJydnXHz5k1s2bIFAHD+/Hm4u7tLp6smJiZi69atjdK/5sjS0hKLFi1Cenp6g8o/mWNwdXXFP//5T3z22WeNFptCNOENWx4/fiz9te/m5obNmzdjxIgRMDc3R48ePbB8+XLcu3cPe/fuBQCEhYWhV69ecHJyQklJCXbt2oW//vWv+Pbbb+Hr69ug98zPz4epqSny8vI4eiCdKykpQVJSEnr16gVjY2Ndh0OtUF37mCa/hU06x/DDDz9gxIgR0vKTuYCZM2ciIiIC6enpSElJkbaXlZVhyZIluHfvHtq1awdXV1ecOXNG1gYREWlXk44YdIEjBmpOOGKgxqaNEUOLm2MgIqLGxcRAREQyTAxEOtDKj+CSDmlj32rWF7gRtTZt2rSBQqHAw4cP+aAe0ronD+pRKBRo06bNM7fDxEDUhPT19dG9e3ekpaUhOTlZ1+FQK/Tk0Z7P89xnJgaiJta+fXvY2dlJzywg0qY2bdo8V1IAmBiIdEJfX/+5//MSNRZOPhMRkQwTAxERyTAxEBGRDBMDERHJMDEQEZEMEwMREckwMRARkQwTAxERyTAxEBGRzDNd+Xzp0iWcOXMGCoUCvr6+8PDw0HZcRESkIxqPGEJCQjB16lQ8evQIWVlZeOWVV7B58+bGiI2IiHRA40d79u3bF9HR0bCwsAAAZGdnw8PDA7/88kujBPi8+GhPIiLNfgs1PpRkYmIiJQUAMDc3b9U/uMplX2u1veQNY7XaniZaU1+IqPFonBh8fHwwa9YszJkzBwAQEREBPz8/XLt2DQDg6uqq3QiJiKhJaZwYDh8+DAA4f/68bP2hQ4egUChw584d7URGREQ6oXFiSEpKaow4qCVabarl9vK02x4RPRONE0NKSkqt63v06PHcwbwQ+GPa/Gj7OwH4vVCLpnFicHd3h0KhgBACJSUlKCoqgoWFBTIzM59a98KFC9i0aROuXLmC9PR0HD16FBMnTqy3TlRUFIKDg3Hjxg3Y2NhgxYoVmDVrlqZhUyui9Ul0Y602pxHt92W6VttjgnsxaZwYHj58KFv+4osv8OOPPzaobmFhIVQqFWbPno2AgICnlk9KSsLYsWOxYMEC7N+/H5GRkZg7dy6sra3h7++vaehE1Ei0neAAJjldeu5nPgcEBOCjjz7Chx9++NSyo0ePxujRoxvc9vbt29GrVy98/PHHAIB+/frh3//+N0JDQzVODGVlZSgrK9OoDgAYoFLjOvXGoe3HbGvQp9bSl2bfD6D19EVH/QB0+3+lNdLk90/jC9zy8/Olf1dWVuL777/HokWLNL7ATaFQPPVQ0tChQ9G/f3+EhYVJ6/bs2YPFixcjL6/27F9aWorS0lJZvDY2Nli2bBmMjXV4zICISIdKSkqwYcOGxrnAzczMTJpj0NfXh52dHf7yl788c7D1efDgAaysrGTrrKyskJ+fj+LiYrRt27ZGnfXr1zdo9EJERLXTODFUVVU1Rhxas3z5cgQHB0vLT0YMS5YseaYrtB0/OKnN8PCzcaBW28N76Q0u2lr60uz7AbSevuioH0Dr6Ysu/8//Wn5+PjZs2NCgso1wcFV7unTpgoyMDNm6jIwMmJiY1DpaAAAjIyMYGRnVWG9oaAhDQ0ONY6iAvsZ16mOICq22Bw361Fr60uz7AbSevuioH0Dr6Ysu/8/LqzW8XoMTg56eHhQKRZ3bKyu1P/nk6emJEydOyNadPn0anp6eWn8vIiKq1uDEUFBQACEEwsLCUFxcjIULFwKoPnOorr/ef+vx48dITEyUlpOSkhAXFwdzc3P06NEDy5cvx71797B3714AwIIFC7B161a88847mD17Ns6ePYt//OMf+Ppr7Z8aR0RE1RqcGH73u98BAI4ePYorV65I69etWwd3d3e8//77T23jhx9+wIgRI6TlJ3MBM2fOREREBNLT02VXVvfq1Qtff/013n77bWzZsgXdu3fHrl27eA0DEVEj0niOoaCgAJmZmejcuTMAIDMzEwUFBQ2qO3z4cNR3dmxEREStdWJjYzUNk4iInpHGiWHJkiVQqVQYM2YMAODkyZNYvXq1tuMiIiId0TgxzJ8/Hy+99BLOnTsHoPpwkJOTk9YDIyIi3Xim01UtLCzg4uKC4cOHo6KiAmVlZc90KigRETU/eppW+Oc//wkPDw8EBlZftHHjxo2n3iGViIhaDo0Tw/r163H16lWYmZkBAFQqFe7evavtuIiISEc0Tgz6+vqwsLCQreNhJCKi1kPjxNChQwdkZGRIV0FHRkbC3Nxc64EREZFuaDz5vHHjRowePRp37tzBkCFDkJSUxCuRiYhaEY0Tw4ABA3Du3DlcvHgRQgh4eXlJ8w1ERNTyaXwoCQASExORlZUlXeSWnv5st4ElIqLmR+PE8Mknn2D27NnS1c6PHj3C9OlafjYrERHpjMaJYefOnbh06ZL00Js+ffrg4cOHWg+MiIh0Q+PEYGRkVOM22wYGzfp5P0REpAGNE0OnTp3wyy+/SKerRkREoEePHloPjIiIdEPjP/XDwsIwbdo0xMfHw8bGBiYmJjh+/HhjxEZERDqgcWKwtbXF999/j4SEBAghYG9vD3197T/vlYiIdOOZJgdiYmJw5swZKBQK+Pn5YfDgwdqOi4iIdETjOYaQkBBMnToVjx49QlZWFqZOnYrNmzc3RmxERKQDGo8Ydu7ciatXr0o30lu5ciU8PDyk5zcTEVHLpvGIwcTERHZ3VXNzc+maBiIiavk0HjH4+Phg1qxZmDNnDoDq01X9/Pxw7do1AICrq6t2IyQioialcWI4fPgwAOD8+fNQKBQQQgAADh06BIVCgTt37mg3QiIialIaJ4akpCQAwO3bt/HVV1/B1tYW48aN03pgRESkGw2eY/Dz80NcXBwA4P79+xg4cCC+/fZbvPPOO9i4caNGb7pt2zYolUoYGxtj8ODBiImJqbNsREQEFAqF7GVsbKzR+xERUcM1ODHcu3cParUaAHDgwAEMGzYM33zzDS5evIj9+/c3+A0PHTqE4OBgrFq1ClevXoVKpYK/vz8yMzPrrGNiYoL09HTpxWdMExE1ngYnhl/fOO/ixYvSsxg6duyo0U30Nm/ejHnz5iEwMBCOjo7Yvn072rVrh927d9dZR6FQoEuXLtLLysqqwe9HRESaaXBi0NPTQ1paGh4/fozz589j2LBh0raioqIGtVFWVoYrV67Az89P1q6fnx+io6PrrPf48WP07NkTNjY2mDBhAm7cuNHQsImISEMN/lP/vffeg5ubGwwMDDBixAj07dsXQPXoQalUNqiNrKwsVFZW1viL38rKCvHx8bXWsbe3x+7du+Hq6oq8vDyEhITAy8sLN27cQPfu3WuULy0tRWlpqbScn5/fwB4SERGgQWIICAiAl5cXMjIyZNcqKJVK7Ny5s1GCAwBPT094enpKy15eXujXrx927NiBtWvX1ii/fv16fPjhh40WDxFRa6fRlc9dunSBSqWSnsUAAF27dm3w8xgsLS2hr6+PjIwM2fqMjAx06dKlQW20adMGbm5uSExMrHX78uXLkZeXJ71SU1Mb1C4REVXT+JYYz8PQ0BDu7u6IjIyU1lVVVSEyMlI2KqhPZWUlfvrpJ1hbW9e63cjICCYmJrIXERE1XJM/kzM4OBgzZ87EgAEDMGjQIISFhaGwsBCBgYEAgNdffx3dunXD+vXrAQBr1qyBh4cHbG1tkZubi02bNuHu3buYO3duU4dORPRCaPLEMHXqVDx8+BAffPABHjx4ALVajZMnT0oT0ikpKdDT++9AJicnB/PmzcODBw/QsWNHuLu74+LFi3B0dGzq0ImIXghNnhgAICgoCEFBQbVui4qKki2HhoYiNDS0CaIiIiKgiecYiIio+WNiICIiGSYGIiKSYWIgIiIZJgYiIpJhYiAiIhkmBiIikmFiICIiGSYGIiKSYWIgIiIZJgYiIpJhYiAiIhkmBiIikmFiICIiGSYGIiKSYWIgIiIZJgYiIpJhYiAiIhkmBiIikmFiICIiGSYGIiKSYWIgIiIZJgYiIpJhYiAiIhmdJIZt27ZBqVTC2NgYgwcPRkxMTL3lDx8+DAcHBxgbG8PFxQUnTpxookiJiF48TZ4YDh06hODgYKxatQpXr16FSqWCv78/MjMzay1/8eJFTJs2DXPmzEFsbCwmTpyIiRMn4vr1600cORHRi6HJE8PmzZsxb948BAYGwtHREdu3b0e7du2we/fuWstv2bIFo0aNwtKlS9GvXz+sXbsW/fv3x9atW5s4ciKiF0OTJoaysjJcuXIFfn5+/w1ATw9+fn6Ijo6utU50dLSsPAD4+/vXWZ6IiJ6PQVO+WVZWFiorK2FlZSVbb2Vlhfj4+FrrPHjwoNbyDx48qLV8aWkpSktLpeW8vDwAQH5+/jPFXFVa9Ez16pKvEFptDxr0q7X0pdn3A2g9fdFRP4DW0xdd/p+XV6uuJ8TT42nSxNAU1q9fjw8//LDGehsbGx1EU5OpthvcoPUWG6y19KVR3rW19IX713Nrbv0oKCiAqWn9bTRpYrC0tIS+vj4yMjJk6zMyMtClS5da63Tp0kWj8suXL0dwcLC0XFVVhezsbFhYWEChUDxnD55Pfn4+bGxskJqaChMTE53G8rxaS19aSz8A9qU5ak79EEKgoKAAXbt2fWrZJk0MhoaGcHd3R2RkJCZOnAig+oc7MjISQUFBtdbx9PREZGQkFi9eLK07ffo0PD09ay1vZGQEIyMj2TozMzNthK81JiYmOt9JtKW19KW19ANgX5qj5tKPp40UnmjyQ0nBwcGYOXMmBgwYgEGDBiEsLAyFhYUIDAwEALz++uvo1q0b1q9fDwD405/+hGHDhuHjjz/G2LFj8fnnn+OHH37Azp07mzp0IqIXQpMnhqlTp+Lhw4f44IMP8ODBA6jVapw8eVKaYE5JSYGe3n9PlvLy8sKBAwewYsUKvPfee7Czs8OxY8fg7Ozc1KETEb0QdDL5HBQUVOeho6ioqBrrpkyZgilTpjRyVI3PyMgIq1atqnGoqyVqLX1pLf0A2JfmqKX2QyEacu4SERG9MHgTPSIikmFiICIiGSYGLVAqlbC3t4darYZarcahQ4cAALdu3YKXlxf69u2LgQMH4saNGzqOVG7RokVQKpVQKBSIi4uT1tcXd3PsU0lJCSZOnIi+fftCpVJh5MiRSExMBAAMHz4cvXr1kr6b0NBQqV5mZiZGjRoFOzs7ODs748KFC7rqgsyz7E/N8XupT137XktT377Xogl6bj179hSxsbE11o8YMULs2bNHCCHE4cOHxYABA5o2sKc4f/68SE1NrRF/fXE3xz4VFxeLr7/+WlRVVQkhhPjrX/8qhg0bJoQQYtiwYeLo0aO11gsMDBSrVq0SQggRExMjunXrJsrKypog4vo9y/7UHL+X+tS177U09e17LRkTgxbUtnNnZGSIDh06iPLyciGEEFVVVcLKykrcunVLCCEEAPHnP/9ZDBw4UCiVSrF7924hhBCVlZXirbfeEg4ODsLV1VX0799fFBcXN1n89cXdUvp0+fJl0bNnTyFE/Ynhd7/7nUhPT5eWBw4cKE6fPi2EqP5MVq5cKTw8PIRSqRRr166Vyq1du1Y4ODgIlUolVCqVSE5O1mr8mu5PLeV7qc1v+wpA5OTkSMsWFhYiKSmpWcTaEL/e937bN3d3d3Hu3DkhROPvQ8+r1d0rSVdef/11CCEwaNAgbNiwAampqbC2toaBQfVHrFAo0KNHD6SkpMDW1hZA9alsMTExiI+Px8CBA/Haa6/hp59+QmRkJG7cuAE9PT3k5eXB0NCwyfpRX9ympqYtok9btmzBhAkTpOVly5Zh5cqVcHR0xPr169G7d288evQI5eXlslurKJVKpKSkSMu5ubmIjo5GVlYW+vTpg8DAQLRr1w4hISFIT09H27ZtUVRUJLvuRls02Z9ayvfyPH788ccWEetv973a5OTkNMk+9DyaVzQt1IULF3Dt2jVcvXoVlpaWmDlzZoPqzZgxAwDg4OAAAwMDPHjwAL1790ZFRQVmz56Nzz77DOXl5c1up6mPrvv00UcfITExUbpy/u9//zvi4+Nx7do1eHt743/+538a3Nb06dMBVN/jq3fv3khKSoKJiQns7Ozw6quvYseOHcjOzoaxsbFW+/Cs+1N9dP29PK+WEOtv9726NMU+9Lya1yfbQvXo0QMA0KZNGyxevBjfffcdbGxskJ6ejoqKCgDVN7BKSUmRygKQ7Qz6+vqoqKiAqakprl+/junTpyM+Ph6urq5NOplVX9zNvU8hISH44osv8M0336Bdu3ZSf4Dqv6KDgoJw584dPHr0CBYWFtIP5BPJyclP7Yu+vj4uXbqExYsXIzMzEx4eHvjuu++02g9N96fm/r1oQl9fH5WVldJySUkJADTLWH+ttn3PwMCg1r40xT70vJgYnlNhYSFyc3Ol5YMHD8LNzQ2dO3dG//79sW/fPgDAkSNH0L17d2loX5eHDx+isLAQv//97/HRRx9BqVTi559/bswuyNQXd3Pu0+bNm3Hw4EGcPn1aumliRUWF7M68R44cgZWVFSwsLABUX1G/fft2AMDly5dx7949DBs2rN73KSgoQEZGBry9vbFy5UoMGTIEsbGxWuvHs+xPzfl70ZStrS2+//57AMAXX3yBwsJCAM0z1idq2/cAeV9iYmKQkJAAoPH3Ia3Q4fxGq3D79m2hVquFi4uLcHZ2FuPHjxdJSUlCCCHi4+OFh4eHsLOzE+7u7uLatWtSPdQxyXblyhXRv39/4eLiIhwdHcW8efMa7UyZN954Q3Tr1k3o6+uLzp07iz59+jw17ubYp9TUVAFA9O7dW5rMGzRokHj8+LFwd3cXzs7OwtXVVfj4+Ii4uDip3oMHD8TIkSOFra2tcHR0FGfPnpW21TVxmJqaKgYPHiycnZ2Fi4uLCAgIELm5uVrry7PuT83xe6lPXfveiRMnhK2trXBzcxMrVqxoFrHWp659T4jqiWhHR0fh6uoq5s+fL1QqVZPsQ9rAW2IQEZEMDyUREZEMEwMREckwMRARkQwTAxERyTAxEBGRDBMDERHJMDEQEZEMEwO9EJRKZa33/Z87dy7OnTv31PqrV6/G4sWLtVYuKioKJ0+efGo5Il3g3VXphbZr1y6dvG9UVBRyc3MxatQonbw/UX04YqAX2vDhw3Hs2DEAwKxZszB//nz4+vqib9++CAgIQFlZWY06P//8M5ydnfHNN9/U2/ZPP/2EIUOGoH///nB0dMS6desAAHFxcdi+fTv2798PtVqNNWvWAABOnTqFIUOGwN3dHYMGDZJGMlFRUXB2dsabb74JlUoFJycn/PDDD9L7fP311xg4cCBUKhXUajW+//57hISE4I033pDK5ObmwtLSEtnZ2c/1edGLgSMGol+Ji4vDuXPnYGRkhKFDh+LIkSOYNm2atD0qKgpvvvkm9u3bh/79+9fbllKpRGRkJIyMjFBcXAwvLy/4+fnBw8MDCxYsQG5uLsLCwgAAd+7cwerVq3Hq1CmYmJggMTER3t7eSE5OBgDEx8cjPDwcn3zyCbZv3473338fp06dwi+//ILAwEBcuHABDg4OKC8vR1FREezt7dG3b1/83//9H8zMzLBnzx5MmDAB5ubmjfXRUSvCxED0K5MmTZJumzxo0CDcvn1b2nb27FmcPHkS3377reyW1nUpLi7Gm2++ibi4OOjp6SE1NRVxcXHw8PCoUfbkyZNITEzE0KFDpXV6enrSg4NsbW0xePBgAICnpydCQkIAAKdPn8aoUaPg4OAAoPpW3aampgCAyZMnY/fu3Xj77bfx6aefSs+OJnoaJgaiX6ntuQVP2NraIj4+HpcuXWpQYnjvvfdgaWmJ2NhYGBgYICAgQLon/28JITBy5EgcOHCgxrZ79+7VG1ddFi1ahPHjx6Nfv37o1KkT3NzcnlqHCOAcA1GD9ejRA5GRkVi3bh327Nnz1PI5OTno3r07DAwMkJCQgNOnT0vbTExMkJeXJy37+/vjzJkzuHbtmrQuJibmqe/h7++PU6dOIT4+HgBQXl4utevg4IDevXvjjTfeQFBQUIP7ScTEQC8Mf39/dO/eXXqlpaVp3Ia1tTXOnj2Lbdu24S9/+Uu9ZVesWIE9e/bA1dUVy5Ytg4+Pj7Rt0qRJiIuLkyafbW1tceDAAcyfPx8qlQr9+vWT5h/qY2triz179uDVV1+FSqXC4MGDpQfCAMC8efNQUVGByZMna9xXenHxeQxErVhQUBCsrKywcuVKXYdCLQjnGIhaofv378PHxwfm5uY4deqUrsOhFoYjBiIikuEcAxERyTAxEBGRDBMDERHJMDEQEZEMEwMREckwMRARkQwTAxERyTAxEBGRDBMDERHJ/D+Liv8AFzCCyQAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "\n", - "g = []\n", - "n = []\n", - "\n", - "bips_g_cas = df_g_cas_50ns['BIPS'].astype(float)\n", - "bips_g_ram = df_g_ram_50ns['BIPS'].astype(float)\n", - "bips_n_cas = df_n_cas_50ns['BIPS'].astype(float)\n", - "bips_n_ram = df_n_ram_50ns['BIPS'].astype(float)\n", - "\n", - "\n", - "g.append(gmean(bips_g_ram,6) / gmean(bips_g_cas, 6))\n", - "n.append(gmean(bips_n_ram,5) / gmean(bips_n_cas, 5))\n", - "\n", - "\n", - "bips_g_cas = df_g_cas_100ns['BIPS'].astype(float)\n", - "bips_g_ram = df_g_ram_100ns['BIPS'].astype(float)\n", - "bips_n_cas = df_n_cas_100ns['BIPS'].astype(float)\n", - "bips_n_ram = df_n_ram_100ns['BIPS'].astype(float)\n", - "\n", - "\n", - "g.append(gmean(bips_g_ram,6) / gmean(bips_g_cas, 6))\n", - "n.append(gmean(bips_n_ram,5) / gmean(bips_n_cas, 5))\n", - "\n", - "bips_g_cas = df_g_cas_250ns['BIPS'].astype(float)\n", - "bips_g_ram = df_g_ram_250ns['BIPS'].astype(float)\n", - "bips_n_cas = df_n_cas_250ns['BIPS'].astype(float)\n", - "bips_n_ram = df_n_ram_250ns['BIPS'].astype(float)\n", - "\n", - "\n", - "g.append(gmean(bips_g_ram,6) / gmean(bips_g_cas, 6))\n", - "n.append(gmean(bips_n_ram,5) / gmean(bips_n_cas, 5))\n", - "\n", - "bips_g_cas = df_g_cas_500ns['BIPS'].astype(float)\n", - "bips_g_ram = df_g_ram_500ns['BIPS'].astype(float)\n", - "bips_n_cas = df_n_cas_500ns['BIPS'].astype(float)\n", - "bips_n_ram = df_n_ram_500ns['BIPS'].astype(float)\n", - "\n", - "\n", - "g.append(gmean(bips_g_ram,6) / gmean(bips_g_cas, 6))\n", - "n.append(gmean(bips_n_ram,5) / gmean(bips_n_cas, 5))\n", - "\n", - "bips_g_cas = df_g_cas_1us['BIPS'].astype(float)\n", - "bips_g_ram = df_g_ram_1us['BIPS'].astype(float)\n", - "bips_n_cas = df_n_cas_1us['BIPS'].astype(float)\n", - "bips_n_ram = df_n_ram_1us['BIPS'].astype(float)\n", - "\n", - "\n", - "g.append(gmean(bips_g_ram,6) / gmean(bips_g_cas, 6))\n", - "n.append(gmean(bips_n_ram,5) / gmean(bips_n_cas, 5))\n", - "\n", - "bips_g_cas = df_g_cas_2us['BIPS'].astype(float)\n", - "bips_g_ram = df_g_ram_2us['BIPS'].astype(float)\n", - "bips_n_cas = df_n_cas_2us['BIPS'].astype(float)\n", - "bips_n_ram = df_n_ram_2us['BIPS'].astype(float)\n", - "\n", - "\n", - "g.append(gmean(bips_g_ram,6) / gmean(bips_g_cas, 6))\n", - "n.append(gmean(bips_n_ram,5) / gmean(bips_n_cas, 5))\n", - "\n", - "x = ['50ns', '100ns', '250ns', '500ns', '1us', '2us']\n", - "x_axis = np.arange(6)\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(4,2)\n", - "\n", - "plt.ylim([0,1.7])\n", - "len = 0.4\n", - "plt.bar(x_axis-len, g, width=len, label = 'GAPBS')\n", - "plt.bar(x_axis, n, width=len, label = 'NPB')\n", - "\n", - "plt.xticks(x_axis-(len/2), x, fontsize=8)\n", - "plt.axhline(y=1, color='gray')\n", - "\n", - "plt.title(\"BIPS(TDRAM/Cascade)\", fontsize=8)\n", - "plt.xlabel(\"Link latency\", fontsize=8)\n", - "plt.ylabel(\"Speedup\", fontsize=8)\n", - "plt.legend(fontsize=8, ncol=2)\n", - "plt.tight_layout()\n", - "plt.show()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.6" - }, - "orig_nbformat": 4, - "vscode": { - "interpreter": { - "hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/missRatio_swe.py b/missRatio_swe.py deleted file mode 100644 index 66704c5728..0000000000 --- a/missRatio_swe.py +++ /dev/null @@ -1,136 +0,0 @@ -from m5.objects import * -import m5 -import argparse -from m5.objects.DRAMInterface import * -from m5.objects.NVMInterface import * - -args = argparse.ArgumentParser() - -args.add_argument( - "traffic_mode", - type = str, - help = "Traffic type to use" -) - -args.add_argument( - "rd_prct", - type=int, - help="Read Percentage", -) - -args.add_argument( - "end_address", - type=str, - help="end address", -) - -options = args.parse_args() - -system = System() -system.clk_domain = SrcClockDomain() -system.clk_domain.clock = "4GHz" -system.clk_domain.voltage_domain = VoltageDomain() -system.mem_mode = 'timing' - -system.generator = PyTrafficGen() - -system.mem_ctrl = PolicyManager(range=AddrRange('3GiB')) - -system.mem_ctrl.orb_max_size = 128 -system.mem_ctrl.static_frontend_latency = "10ns" -system.mem_ctrl.static_backend_latency = "10ns" -#system.mem_ctrl.bypass_dcache = True - -system.loc_mem_ctrl = MemCtrl() -#system.loc_mem_ctrl.consider_oldest_write= True -system.loc_mem_ctrl.dram = TDRAM(range=AddrRange('3GiB'), in_addr_map=False, null=True) -system.mem_ctrl.loc_mem_policy = 'Rambus' - -# system.loc_mem_ctrl = MemCtrl() -# #system.loc_mem_ctrl.consider_oldest_write= True -# system.loc_mem_ctrl.dram = TDRAM_32(range=AddrRange('3GiB'), in_addr_map=False, null=True) -# system.loc_mem_ctrl.dram.activation_limit = 8 -# system.loc_mem_ctrl.dram.page_policy = "close_adaptive" -# system.mem_ctrl.loc_mem_policy = 'Rambus' -# system.loc_mem_ctrl.dram.read_buffer_size = 64 -# system.loc_mem_ctrl.dram.write_buffer_size = 64 - -# system.loc_mem_ctrl = HBMCtrl() -# system.loc_mem_ctrl.dram = HBM_2000_4H_1x64(range=AddrRange(start = '0', end = '3GiB', masks = [1 << 6], intlvMatch = 0), in_addr_map=False, kvm_map=False, null=True) -# system.loc_mem_ctrl.dram_2 = HBM_2000_4H_1x64(range=AddrRange(start = '0', end = '3GiB', masks = [1 << 6], intlvMatch = 1), in_addr_map=False, kvm_map=False, null=True) -# system.mem_ctrl.loc_mem_policy = 'CascadeLakeNoPartWrs' -# system.loc_mem_ctrl.dram.read_buffer_size = 32 -# system.loc_mem_ctrl.dram.write_buffer_size = 32 -# system.loc_mem_ctrl.dram_2.read_buffer_size = 32 -# system.loc_mem_ctrl.dram_2.write_buffer_size = 32 - -system.mem_ctrl.loc_mem = system.loc_mem_ctrl.dram -system.loc_mem_ctrl.static_frontend_latency = "2ns" -system.loc_mem_ctrl.static_backend_latency = "2ns" -system.loc_mem_ctrl.static_frontend_latency_tc = "1ns" -system.loc_mem_ctrl.static_backend_latency_tc = "1ns" - -system.far_mem_ctrl = MemCtrl() -system.far_mem_ctrl.dram = DDR4_2400_16x4(range=AddrRange('3GiB'),in_addr_map=False, null=True) -system.far_mem_ctrl.dram.read_buffer_size = 64 -system.far_mem_ctrl.dram.write_buffer_size = 64 -system.far_mem_ctrl.static_frontend_latency = "2ns" -system.far_mem_ctrl.static_backend_latency = "2ns" - -system.mem_ctrl.dram_cache_size = "1GiB" - -system.generator.port = system.mem_ctrl.port -system.loc_mem_ctrl.port = system.mem_ctrl.loc_req_port -system.far_mem_ctrl.port = system.mem_ctrl.far_req_port - -def createRandomTraffic(tgen): - yield tgen.createRandom(10000000000, # duration - 0, # min_addr - AddrRange(options.end_address).end, # max_adr - 64, # block_size - 1000, # min_period - 1000, # max_period - options.rd_prct, # rd_perc - 0) # data_limit - yield tgen.createExit(0) - -def createLinearTraffic(tgen): - yield tgen.createLinear(10000000000, # duration - 0, # min_addr - AddrRange('3GiB').end, # max_adr - 64, # block_size - 1000, # min_period - 1000, # max_period - options.rd_prct, # rd_perc - 0) # data_limit - yield tgen.createExit(0) - -root = Root(full_system=False, system=system) - -m5.instantiate() - -if options.traffic_mode == 'linear': - system.generator.start(createLinearTraffic(system.generator)) -elif options.traffic_mode == 'random': - system.generator.start(createRandomTraffic(system.generator)) -else: - print('Wrong traffic type! Exiting!') - exit() - -exit_event = m5.simulate() -print(f"Exit reason {exit_event.getCause()}") - -# for testing checkpointing -# exit_event = m5.simulate(1000000000) -# print(f"Exit reason {exit_event.getCause()}") - -# # print("Draining") -# # m5.drain() -# # print("Done draining!") -# m5.stats.dump() -# m5.checkpoint(m5.options.outdir + '/cpt-test') -# m5.stats.reset() - -# system.generator.start(createLinearTraffic(system.generator)) -# exit_event = m5.simulate() -# print(f"Exit reason {exit_event.getCause()}") diff --git a/npb_checkpoint.sh b/npb_checkpoint.sh deleted file mode 100755 index 51923fd558..0000000000 --- a/npb_checkpoint.sh +++ /dev/null @@ -1,22 +0,0 @@ - -#!/bin/bash - -# $1 is the class of the NPB to run - -if [ $1 != 'C'] && [ $1 != 'D'] -then - echo "Run with C or D Class" - exit -fi - -bms=(bt cg dc ep ft is lu mg sp ua) - -if [! -d checkpoints-npb]; then - mkdir -p checkpoints-npb; -fi - -for bm in "${bms[@]}" -do -echo $bm -build/RISCV/gem5.opt -re --outdir=$bm.timing Octopi-cache/riscv-2channel-1ccd-checkpoint-timing.py --benchmark $bm --size $1 --ckpt_path checkpoints-npb/$bm.timing/$bm & -done diff --git a/npb_checkpoint_c_class.sh b/npb_checkpoint_c_class.sh deleted file mode 100755 index c80d422ba9..0000000000 --- a/npb_checkpoint_c_class.sh +++ /dev/null @@ -1,22 +0,0 @@ - -#!/bin/bash - -# $1 is the class of the NPB to run - -if [ $1 != 'C'] && [ $1 != 'D'] -then - echo "Run with C or D Class" - exit -fi - -bms=(bt cg dc ep ft is lu mg sp ua) - -if [! -d /projects/gem5/npb-checkpoints]; then - mkdir -p /projects/gem5/npb-checkpoints; -fi - -for bm in "${bms[@]}" -do -echo $bm -M5_OVERRIDE_PY_SOURCE=TRUE build/RISCV/gem5.opt -re --outdir=/projects/gem5/npb-checkpoints/results/$bm.$1.timing Octopi-cache/riscv-2channel-1ccd-checkpoint-timing-npb-c.py --benchmark $bm --size $1 --ckpt_path /projects/gem5/npb-checkpoints/$bm.$1.timing/$bm.$1 & -done diff --git a/npb_run.sh b/npb_run.sh deleted file mode 100755 index 1596b924a2..0000000000 --- a/npb_run.sh +++ /dev/null @@ -1,22 +0,0 @@ - -#!/bin/bash - -# $1 is the class of the NPB to run - -if [ $1 != 'C'] && [ $1 != 'D'] -then - echo "Run with C or D Class" - exit -fi - -bms=(bt cg dc ep ft is lu mg sp ua) - -if [! -d results_npb]; then - mkdir -p results_npb; -fi - -for bm in "${bms[@]}" -do -echo $bm -M5_OVERRIDE_PY_SOURCE=TRUE build/RISCV/gem5.opt --debug-flags=O3LooppointAnalysis -re --outdir=results_npb/$bm.$1.O3 Octopi-cache/restore-npb-gapbs-looppoint.py --benchmark $bm.$1 --size $1 --ckpt_path /projects/gem5/dramcache/jason-checkpoints/npb/c/$bm/ckpt & -done diff --git a/npb_run_c.sh b/npb_run_c.sh deleted file mode 100755 index b778ec155f..0000000000 --- a/npb_run_c.sh +++ /dev/null @@ -1,22 +0,0 @@ - -#!/bin/bash - -# $1 is the class of the NPB to run - -if [ $1 != 'C'] && [ $1 != 'D'] -then - echo "Run with C or D Class" - exit -fi - -bms=(bt cg dc ep ft is lu mg sp ua) - -if [! -d NPB_Base]; then - mkdir -p NPB_Base; -fi - -for bm in "${bms[@]}" -do -echo $bm -M5_OVERRIDE_PY_SOURCE=TRUE build/RISCV/gem5.opt -re --outdir=NPB_Base/$bm.$1.O3 Octopi-cache/restore-npb-gapbs-looppoint.py --benchmark $bm.$1 --size $1 --ckpt_path /projects/gem5/dramcache/jason-checkpoints/npb/c/$bm/ckpt & -done diff --git a/plots_1GBdramCache/data-plots.ipynb b/plots_1GBdramCache/data-plots.ipynb deleted file mode 100644 index 2596a775b4..0000000000 --- a/plots_1GBdramCache/data-plots.ipynb +++ /dev/null @@ -1,1331 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 65, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "import numpy as np\n", - "import sys\n", - "from matplotlib import pyplot as plt\n", - "import os\n", - "import statistics\n", - "\n", - "cmap = plt.get_cmap('Set1')\n", - "\n", - "Stats = ['simSeconds ',\n", - "'hostSeconds ',\n", - "'system.mem_ctrl.readReqs ',\n", - "'system.mem_ctrl.writeReqs ',\n", - "'system.mem_ctrl.servicedByWrQ ',\n", - "'system.mem_ctrl.mergedWrBursts ',\n", - "'system.mem_ctrl.numTotHits ',\n", - "'system.mem_ctrl.numTotMisses ',\n", - "'system.mem_ctrl.numColdMisses ',\n", - "'system.mem_ctrl.numHotMisses ',\n", - "'system.mem_ctrl.numRdMissClean ',\n", - "'system.mem_ctrl.numRdMissDirty ',\n", - "'system.mem_ctrl.numRdHit ',\n", - "'system.mem_ctrl.numWrMissClean ',\n", - "'system.mem_ctrl.numWrMissDirty ',\n", - "'system.mem_ctrl.numWrHit ',\n", - "'system.mem_ctrl.numRdHitDirty ',\n", - "'system.mem_ctrl.numRdHitClean ',\n", - "'system.mem_ctrl.numWrHitDirty ',\n", - "'system.mem_ctrl.numWrHitClean ',\n", - "'system.o3Cpu0.thread_0.numInsts ',\n", - "'system.o3Cpu1.thread_0.numInsts ',\n", - "'system.o3Cpu2.thread_0.numInsts ',\n", - "'system.o3Cpu3.thread_0.numInsts ',\n", - "'system.o3Cpu4.thread_0.numInsts ',\n", - "'system.o3Cpu5.thread_0.numInsts ',\n", - "'system.o3Cpu6.thread_0.numInsts ',\n", - "'system.o3Cpu7.thread_0.numInsts ',\n", - "'system.mem_ctrl.avgRdBWSys ',\n", - "'system.mem_ctrl.avgWrBWSys ',\n", - "'system.mem_ctrl.avgORBLen ',\n", - "'system.far_mem_ctrl.avgRdBWSys ',\n", - "'system.far_mem_ctrl.avgWrBWSys ',\n", - "'system.loc_mem_ctrl.avgRdBWSys ',\n", - "'system.loc_mem_ctrl.avgWrBWSys ',\n", - "'system.loc_mem_ctrl.dram.readBursts ',\n", - "'system.loc_mem_ctrl.dram.writeBursts ',\n", - "'system.loc_mem_ctrl.dram_2.readBursts ',\n", - "'system.loc_mem_ctrl.dram_2.writeBursts ',\n", - "'system.far_mem_ctrl.dram.readBursts ',\n", - "'system.far_mem_ctrl.dram.writeBursts ',\n", - "'system.loc_mem_ctrl.dram.avgRdBW ',\n", - "'system.loc_mem_ctrl.dram.avgWrBW ',\n", - "'system.loc_mem_ctrl.dram_2.avgRdBW ',\n", - "'system.loc_mem_ctrl.dram_2.avgWrBW ',\n", - "'system.far_mem_ctrl.dram.avgRdBW ',\n", - "'system.far_mem_ctrl.dram.avgWrBW ',\n", - "'system.loc_mem_ctrl.dram.busUtil ',\n", - "'system.loc_mem_ctrl.dram.busUtilRead ',\n", - "'system.loc_mem_ctrl.dram.busUtilWrite ',\n", - "'system.loc_mem_ctrl.dram_2.busUtil ',\n", - "'system.loc_mem_ctrl.dram_2.busUtilRead ',\n", - "'system.loc_mem_ctrl.dram_2.busUtilWrite ',\n", - "'system.far_mem_ctrl.dram.busUtil ',\n", - "'system.far_mem_ctrl.dram.busUtilRead ',\n", - "'system.far_mem_ctrl.dram.busUtilWrite ',\n", - "'system.far_mem_ctrl.dram.bytesRead ',\n", - "'system.far_mem_ctrl.dram.bytesWritten ',\n", - "'system.loc_mem_ctrl.dram.bytesRead ',\n", - "'system.loc_mem_ctrl.dram.bytesWritten ',\n", - "'system.loc_mem_ctrl.dram_2.bytesRead ',\n", - "'system.loc_mem_ctrl.dram_2.bytesWritten ',\n", - "'system.mem_ctrl.avgTimeTagCheckRes ',\n", - "'system.mem_ctrl.avgTimeTagCheckResRd ',\n", - "'system.mem_ctrl.avgTimeTagCheckResWr ',\n", - "'system.mem_ctrl.avgPktRespTimeRd ',\n", - "'system.mem_ctrl.avgPktRespTimeWr ',\n", - "'system.mem_ctrl.avgPktORBTime ',\n", - "'system.mem_ctrl.avgPktORBTimeRd ',\n", - "'system.mem_ctrl.avgPktORBTimeWr ',\n", - "'system.mem_ctrl.avgTimeInLocRead ',\n", - "'system.mem_ctrl.avgTimeInLocWrite ',\n", - "'system.mem_ctrl.avgTimeInFarRead ',\n", - "'system.mem_ctrl.missRatio '\n", - " ]\n", - "\n", - "dfCols = [\n", - " 'app',\n", - " 'simSeconds',\n", - " 'hostSeconds',\n", - " 'readReqs',\n", - " 'writeReqs',\n", - " 'servicedByWrQ',\n", - " 'mergedWrBursts',\n", - " 'numTotHits',\n", - " 'numTotMisses',\n", - " 'numColdMisses',\n", - " 'numHotMisses',\n", - " 'numRdMissClean',\n", - " 'numRdMissDirty',\n", - " 'numRdHit',\n", - " 'numWrMissClean',\n", - " 'numWrMissDirty',\n", - " 'numWrHit',\n", - " 'numRdHitDirty',\n", - " 'numRdHitClean',\n", - " 'numWrHitDirty',\n", - " 'numWrHitClean',\n", - " 'numInsts0',\n", - " 'numInsts1',\n", - " 'numInsts2',\n", - " 'numInsts3',\n", - " 'numInsts4',\n", - " 'numInsts5',\n", - " 'numInsts6',\n", - " 'numInsts7',\n", - " 'avgRdBWSys',\n", - " 'avgWrBWSys',\n", - " 'avgORBLen',\n", - " 'farAvgRdBWSys',\n", - " 'farAvgWrBWSys',\n", - " 'locAvgRdBWSys',\n", - " 'locAvgWrBWSys',\n", - " 'readBursts1',\n", - " 'writeBursts1',\n", - " 'readBursts2',\n", - " 'writeBursts2',\n", - " 'readBursts3',\n", - " 'writeBursts3',\n", - " 'loc1AvgRdBW',\n", - " 'loc1AvgWrBW',\n", - " 'loc2AvgRdBW',\n", - " 'loc2AvgWrBW',\n", - " 'farAvgRdBW',\n", - " 'farAvgWrBW',\n", - " 'loc1BusUtil',\n", - " 'loc1BusUtilRead',\n", - " 'loc1BusUtilWrite',\n", - " 'loc2BusUtil',\n", - " 'loc2BusUtilRead',\n", - " 'loc2BusUtilWrite',\n", - " 'farBusUtil',\n", - " 'farBusUtilRead',\n", - " 'farBusUtilWrite',\n", - " 'farBytesRead',\n", - " 'farBytesWritten',\n", - " 'loc1BytesRead',\n", - " 'loc1BytesWritten',\n", - " 'loc2BytesRead',\n", - " 'loc2BytesWritten',\n", - " 'avgTimeTagCheckRes',\n", - " 'avgTimeTagCheckResRd',\n", - " 'avgTimeTagCheckResWr',\n", - " 'avgPktRespTimeRd',\n", - " 'avgPktRespTimeWr',\n", - " 'avgPktORBTime',\n", - " 'avgPktORBTimeRd',\n", - " 'avgPktORBTimeWr',\n", - " 'avgTimeInLocRead',\n", - " 'avgTimeInLocWrite',\n", - " 'avgTimeInFarRead',\n", - " 'missRatio'\n", - "\n", - " ]\n", - "##########################################################\n", - "\n", - "def getStat(filename, stat, index):\n", - " filename = os.path.join(filename).replace('\\\\','/')\n", - " #print(stat)\n", - " #print(filename)\n", - " try:\n", - " x = 0\n", - " with open(filename) as f:\n", - " readlines = f.readlines()\n", - " for l in readlines:\n", - " if stat in l and x < (index-1):\n", - " x = x+1\n", - " elif stat in l and x == (index-1):\n", - " return l\n", - " return 0.0 #for cases where stat was not found\n", - " except: #for cases where the file was not found\n", - " return 0.0\n", - "\n", - "##########################################################\n", - "\n", - "def creatDataFrame(dataDir, suite, index):\n", - " app = []\n", - " if suite == \"GAPBS\":\n", - " app = ['bc', 'bfs', 'cc', 'pr', 'sssp', 'tc']\n", - " if suite == \"NPB\":\n", - " app = ['bt', 'cg', 'ft', 'is', 'lu', 'mg', 'sp', 'ua']\n", - " rows = []\n", - " i = 0\n", - " for a in app:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}/stats.txt'.format(dataDir, a)\n", - " ret_line = getStat(time_file_path, stat, index[i])\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - " i = i+1\n", - " df = pd.DataFrame(rows, columns= dfCols)\n", - " df['totNumInsts'] = df['numInsts0'].astype(int)+df['numInsts1'].astype(int)+df['numInsts2'].astype(int)+df['numInsts3'].astype(int)+df['numInsts4'].astype(int)+df['numInsts5'].astype(int)+df['numInsts6'].astype(int)+df['numInsts7'].astype(int)\n", - " df['totBW'] = (df['avgRdBWSys'].astype(float)+df['avgWrBWSys'].astype(float))/1000000000\n", - " df['coldRate'] = (df['numColdMisses'].astype(float) / (df['numTotMisses'].astype(float)+df['numTotHits'].astype(float))) *100\n", - " df['injRate'] = (df['readReqs'].astype(float) + df['writeReqs'].astype(float))*64/1000000000 / df['simSeconds'].astype(float)\n", - " df['BIPS'] = (df['totNumInsts'].astype(float)/1000000000)/df['simSeconds'].astype(float)\n", - " \n", - " df['accAmp'] = (df['farBytesRead'].astype(float) + df['farBytesWritten'].astype(float) +\n", - " df['loc1BytesRead'].astype(float) + df['loc1BytesWritten'].astype(float) + \n", - " df['loc2BytesRead'].astype(float) + df['loc2BytesWritten'].astype(float)) / (df['readReqs'].astype(float) * 64 + df['writeReqs'].astype(float) * 64)\n", - " \n", - " df['BWBloat'] = (df['loc1AvgRdBW'].astype(float) + df['loc1AvgWrBW'].astype(float) +\n", - " df['loc2AvgRdBW'].astype(float) + df['loc2AvgWrBW'].astype(float) +\n", - " df['farAvgRdBW'].astype(float) + df['farAvgWrBW'].astype(float)) / ((df['avgRdBWSys'].astype(float) + df['avgWrBWSys'].astype(float)) / 1000000)\n", - " return df" - ] - }, - { - "cell_type": "code", - "execution_count": 66, - "metadata": {}, - "outputs": [], - "source": [ - "df_gap22_cas = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/cascade/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", - "df_npbC_cas = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/cascade/1GB_8GB_g22_nC/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", - "\n", - "df_gap25_cas = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/cascade/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", - "df_npbD_cas = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/cascade/1GB_85GB_g25_nD/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", - "\n", - "df_gap22_ram = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/rambus/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", - "df_npbC_ram = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/rambus/1GB_8GB_g22_nC/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", - "\n", - "df_gap25_ram = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/rambus/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", - "df_npbD_ram = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/rambus/1GB_85GB_g25_nD/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", - "\n", - "\n", - "df_gap22_orc = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/oracle/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", - "df_npbC_orc = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/oracle/1GB_8GB_g22_nC/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", - "\n", - "df_gap25_orc = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/oracle/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", - "df_npbD_orc = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/oracle/1GB_85GB_g25_nD/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", - "\n", - "df_gap22_noDC = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/noDC/1GB_8GB_g22_nC/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", - "df_npbC_noDC = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/noDC/1GB_8GB_g22_nC/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", - "\n", - "df_gap25_noDC = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/noDC/1GB_85GB_g25_nD/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", - "df_npbD_noDC = creatDataFrame(\"/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/baseline/noDC/1GB_85GB_g25_nD/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n" - ] - }, - { - "cell_type": "code", - "execution_count": 93, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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WoT33ntPyhIREYHZs2fDw8NDmm7W2dkZQ4YM0WgWIiIiIiKqXJULi5iYGAAPeyxWrVqlctmTiYkJmjZtilWrVmk03LJlyzBt2jSMHTsWN2/ehLOzMz744ANMnz5dajN58mQUFRVhzJgxyM/PR9euXbFz507ew4KIiIiIqA7JhJr37+7Zsye2bNkCW1vb2spU5xQKBaytrVFQUMDLoohIrxUVFUk9yoWFhbCwsNByIiIi0mfqfE9We1aoP/74o9rBiIiIiIjoxVSt6WavXbuG7du34+rVqygtLVVZ9+jmdURERERE9PJQu7BITEzEoEGD0KxZM6SlpcHb2xuXL1+GEAJt27atjYxERERERKTj1J5uNjo6GhMnTsTp06dhZmaGzZs3IysrC927d8ewYcNqIyMREREREek4tQuL8+fP49133wUAGBkZ4d69e7C0tMQXX3yB+fPnazwgERERERHpPrULCwsLC2lchZOTEy5evCit+/vvvzWXjIiIiIiI9IbaYyw6deqEP//8Ey1btkT//v3x6aef4vTp09iyZQs6depUGxmJiIiIiEjHqV1YLFq0CIWFhQCAmTNnorCwEBs3boSHhwdnhCIiIiIiekmpXVg0a9ZM+reFhYXG77ZNRERERET6R+0xFpXZsmULfHx8NLU7IiIiIiLSI2oVFt988w3efPNNvPPOO0hJSQEA7NmzB35+fhg5ciQCAgJqJSQREREREem2KhcW8+bNw7hx43D58mVs374dvXr1wpw5czBixAi8/fbbuHbtGmJjY2szKxERERER6agqj7GIj49HXFwcQkJCsH//fnTv3h0HDx7EX3/9BQsLi9rMSEREREREOq7KPRZXr15Fr169AACvvvoqjI2NMXPmTBYVRERERERU9cKipKQEZmZm0mMTExPY2dnVSigiIiIiItIvak03O23aNNSrVw8AUFpaitmzZ8Pa2lqlDe9lQURERET08qlyYdGtWzekp6dLj7t06YJLly6ptJHJZJpLRkREREREeqPKhUVSUlItxqjc9evXERUVhV9//RXFxcVwd3dHfHw8/P39AQBCCMyYMQNxcXHIz89HQEAAYmNj4eHhoZW8REREREQvI43dIK823LlzBwEBATA2Nsavv/6Kc+fO4euvv4atra3UZsGCBVi6dClWrVqFlJQUWFhYICgoCPfv39diciIiIiKil4taYyzq2vz58+Hi4oL4+HhpmZubm/RvIQQWL16MqVOnYvDgwQCAdevWwcHBAdu2bUNwcHCdZyYiIiIiehnpdI/F9u3b4e/vj2HDhqFhw4bw8/NDXFyctD4zMxM5OTkIDAyUlllbW6Njx45ITk7WRmQiIiIiopeSThcWly5dksZL7Nq1Cx999BE++eQTrF27FgCQk5MDAHBwcFDZzsHBQVpXkZKSEigUCpUfIiIiIiKqPp2+FEqpVMLf3x9z5swBAPj5+eHMmTNYtWoVQkJCqr3fuXPnYubMmZqKSURERET00lO7x2Lnzp34888/pccrVqyAr68v3nnnHdy5c0ej4ZycnNCqVSuVZS1btsTVq1cBAI6OjgCA3NxclTa5ubnSuopER0ejoKBA+snKytJobiIiIiKil43ahcWkSZOkS4dOnz6NTz/9FP3790dmZiYiIyM1Gi4gIEDl3hkAcOHCBbi6ugJ4OJDb0dERiYmJ0nqFQoGUlBR07ty50v2amppCLper/BARERERUfWpfSlUZmam1IuwefNmDBw4EHPmzMHx48fRv39/jYabMGECunTpgjlz5uCtt97C4cOH8e233+Lbb78F8PCGfBEREZg9ezY8PDzg5uaGadOmwdnZGUOGDNFoFiIiIiIiqpzahYWJiQmKi4sBAL///jveffddAICdnZ3GB0G3b98eW7duRXR0NL744gu4ublh8eLFGDFihNRm8uTJKCoqwpgxY5Cfn4+uXbti586dMDMz02gWIiIiIiKqnEwIIdTZYNCgQSgtLUVAQABmzZqFzMxMNGrUCL/99hvCw8Nx4cKF2spaaxQKBaytrVFQUMDLoohIrxUVFcHS0hIAUFhYCAsLCy0nIiIifabO92S1x1gsX74cRkZG+PnnnxEbG4tGjRoBAH799Vf069eveomJiIiIiEivqd1j8SJijwURvSjYY0FERJpUqz0Wx48fx+nTp6XH//73vzFkyBBMmTIFpaWl6qclIiIiIiK9p3Zh8cEHH0jjKC5duoTg4GDUq1cPmzZtwuTJkzUekIiIiIiIdJ/ahcWFCxfg6+sLANi0aRO6deuGDRs2ICEhAZs3b9Z0PiIiIiIi0gNqFxZCCCiVSgAPp5t9dO8KFxcX/P3335pNR0REREREekHtwsLf3x+zZ8/Gd999h71792LAgAEAHt44z8HBQeMBiYiIiIhI96ldWCxevBjHjx9HeHg4/vnPf8Ld3R0A8PPPP6NLly4aD0hERERERLpPY9PN3r9/H4aGhjA2NtbE7uoUp5slohcFp5slIiJNUud7spGmfqmZmZmmdkVERERERHqmSoWFnZ0dLly4gPr168PW1hYymazStnl5eRoLR0RERERE+qFKhUVMTAysrKwAPBxjQURERERE9DiNjbHQZxxjQUQvCo6xICIiTVLne7Las0IRERERERE9qcqDtw0NDavUrry8vNphiIiIiIhIP1W5sBBCwNXVFSEhIfDz86vNTEREREREpGeqXFgcPnwYq1evxpIlS+Dm5ob33nsPI0aMgK2tbW3mIyIiIiIiPVDlMRb+/v6IjY3FjRs3EBkZia1bt6Jx48YIDg7G7t27azOjZN68eZDJZIiIiJCW3b9/Hx9//DHs7e1haWmJoUOHIjc3t07yEBERERHRQ2oP3jYzM8M//vEPJCYm4syZM7h58yb69etX6/evOHLkCL755hv4+PioLJ8wYQJ++eUXbNq0CXv37kV2djbeeOONWs1CRERERESqqjUr1LVr1zB79mz06dMHaWlpmDRpUq1O01pYWIgRI0YgLi5O5dKrgoICrF69GosWLUKvXr3Qrl07xMfH4+DBgzh06FCt5SEiIiIiIlVVLixKS0uxceNG9O3bFx4eHjh+/DgWL16MrKwszJs3D0ZGVR6uobaPP/4YAwYMQGBgoMryY8eO4cGDByrLW7RogSZNmiA5ObnW8hARERERkaoqVwNOTk6wsrJCSEgIVq5ciYYNGwJ4eDOmx2m65+LHH3/E8ePHceTIkafW5eTkwMTEBDY2NirLHRwckJOTU+k+S0pKUFJSIj1WKBQay0tERERE9DKqco/FnTt3cPXqVcyaNQuenp6wtbVV+bGxsdH4DFFZWVkYP3481q9fDzMzM43td+7cubC2tpZ+XFxcNLZvIiIiIqKXUZV7LP7444/azFGhY8eO4ebNm2jbtq20rLy8HPv27cPy5cuxa9culJaWIj8/X6XXIjc3F46OjpXuNzo6GpGRkdJjhULB4oKIiIiIqAaqXFh07969NnNUqHfv3jh9+rTKstDQULRo0QJRUVFwcXGBsbExEhMTMXToUABAeno6rl69is6dO1e6X1NTU5iamtZqdiIiIiKil0ntjbjWACsrK3h7e6sss7CwgL29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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAxYAAADSCAYAAADXL1aYAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA5yElEQVR4nO3deVxU9f4/8NewIzBsKougYuAGKiiKW64ofrWUIrt4zdRIK8VUMghvai6hmYo7FCloV7tmLte8N1Mx1BRwxdzADUVl0UQYBQVlPr8//Hmuk6AzMDAz+no+HjwezOcs8zowc5g3n8/nHJkQQoCIiIiIiKgGjHQdgIiIiIiIDB8LCyIiIiIiqjEWFkREREREVGMsLIiIiIiIqMZYWBARERERUY2xsCAiIiIiohpjYUFERERERDXGwoKIiIiIiGqMhQUREREREdUYCwsiIiIiIqoxnRYW+/btw+uvvw5XV1fIZDJs3bpVZbkQAtOnT4eLiwssLS0RGBiI8+fPq6xTWFiI4cOHQy6Xw87ODmFhYbh7924dHgUREREREem0sCgpKUG7du2wYsWKSpfPnz8fS5cuRXx8PNLT02FlZYWgoCDcv39fWmf48OE4ffo0du3ahe3bt2Pfvn0YO3ZsXR0CEREREREBkAkhhK5DAIBMJsOWLVsQHBwM4FFvhaurKz755BNMmTIFAFBcXAwnJyckJSUhNDQUZ8+eRevWrXH48GH4+/sDAHbs2IGBAwfi2rVrcHV11dXhEBERERG9VPR2jkV2djby8/MRGBgotdna2iIgIACpqakAgNTUVNjZ2UlFBQAEBgbCyMgI6enpdZ6ZiIiIiOhlZaLrAFXJz88HADg5Oam0Ozk5Scvy8/PRsGFDleUmJiZwcHCQ1qlMWVkZysrKpMdKpRKFhYVwdHSETCbT1iEQERERERk0IQTu3LkDV1dXGBk9u09CbwuL2jR37lzMnDlT1zGIiIiIiAzC1atX4ebm9sx19LawcHZ2BgAUFBTAxcVFai8oKICvr6+0zo0bN1S2e/jwIQoLC6XtKxMdHY2IiAjpcXFxMRo3boyrV69CLpdr8SiIiOpWSUmJNL8sNzcXVlZWOk5ERESGTKFQwN3dHTY2Ns9dV28LCw8PDzg7OyM5OVkqJBQKBdLT0/HRRx8BALp06YKioiIcPXoUHTp0AADs2bMHSqUSAQEBVe7b3Nwc5ubmT7XL5XIWFkRk0IyNjaXv5XI5CwsiItIKdaYL6LSwuHv3Li5cuCA9zs7ORkZGBhwcHNC4cWNMmjQJc+bMgZeXFzw8PDBt2jS4urpKV45q1aoVBgwYgDFjxiA+Ph4PHjxAeHg4QkNDeUUoIiIiIqI6pNPC4siRI+jdu7f0+PHwpJEjRyIpKQmRkZEoKSnB2LFjUVRUhO7du2PHjh2wsLCQtlm3bh3Cw8PRt29fGBkZISQkBEuXLq3zYyEiIiJ62Qgh8PDhQ1RUVOg6CtWQqampSq93dejNfSx0SaFQwNbWFsXFxRwKRUQGraSkBNbW1gAe9QpzKBQR1Zby8nLk5eWhtLRU11FIC2QyGdzc3KS/IY9p8jlZb+dYEBEREZF+UiqVyM7OhrGxMVxdXWFmZsZL9hswIQRu3ryJa9euwcvLq9o9FywsiIiIiEgj5eXlUCqVcHd3R7169XQdh7SgQYMGuHz5Mh48eFDtwkJv77xNRERERPrteTdMI8OhjR4nvhqIiIiI6IXw8OFDzJw5Ey1btoSPjw98fX2liwDpypQpU/DFF19ovJ1MJtM4d3W20SYOhSIiIiIireg849da2W/azCC11gsLC0NhYSFSU1Nhb28PIQR++uknFBYWws7Orlay0f+wx4KIiIiIDN6FCxewceNGJCYmwt7eHsCj/+APHToUzZo1Q35+Pnr37o0OHTrA29sb4eHhUCqVAIC0tDR06NABvr6+8PHxQVxcHACguLgY77//Pnx8fNCuXTu89957AIDk5GR06dIFfn5+8Pb2xqpVq6QceXl5CAoKQuvWrREYGIhr165Jyx48eIDPPvsMnTp1gq+vL95++23cvn1bo+OcMmUKOnbsCF9fX/To0QNZWVlPrSOEQFRUFAYPHozS0lKcP38egwYNQseOHdG2bVssX75csx+umthjQUREREQG79ixY/Dy8kL9+vUrXW5nZ4eff/4Z1tbWqKiowJAhQ/Djjz8iNDQUc+fOxZQpUzBs2DAAkD7sT5o0CZaWlvjjjz9gZGSEmzdvAgDat2+P33//HcbGxigsLISfnx+CgoLg5uaGjz/+GJ06dcKvv/6K69evw9fXFy1btgQAfP3117CyssKhQ4cAALNnz8bnn3+OFStWqH2cUVFRWLBgAQDgX//6FyZOnIgdO3ZIy8vKyjBs2DA4Ojpiy5YtAIBhw4bhn//8J1q2bInS0lJ07twZAQEB6NixoyY/4udiYUFERERELzylUomoqCj8/vvvEELgxo0b8PHxQWhoKHr37o3Zs2fj/Pnz6NOnD7p37w4A2L59O9LT06VJ6g0aNAAA3Lp1C2FhYTh37hxMTExw69YtnDp1Cm5ubkhOTpY++Ddq1AiDBw+WMmzduhXFxcXYtGkTgEdX12ratKlGx7Fr1y4sW7YMd+7cgVKpRGFhocryQYMGYciQIZg2bRoA4MyZMzh9+jRCQ0Olde7cuYMzZ86wsCAiIiIi+qv27dvj/PnzuHXrFhwdHZ9avmjRIty4cQPp6emwsLBAREQE7t+/D+BRz8SQIUOwe/duTJ06FT4+Pli5cmWVz/Xhhx9i4MCB2LRpE2QyGdq3by/t66+evNqSEALLli1D//79q3WMOTk5CA8Px+HDh/HKK6/gjz/+QI8ePVTW6dOnD3bt2oWJEydCLpdDCAEHBwdkZGRU6zk1wTkWRERERGTwPD09ERISgrCwMOnKSEIIbNq0CZcuXcLt27fh7OwMCwsL5OfnY+PGjdK2WVlZ8PDwwJgxYzB16lSkpaUBAAYPHowFCxZIczEeD4W6ffs2mjRpAplMhn379uHEiRPSvgIDA7F69WoAj+ZbbNu2TVoWHByM2NhY6W7lpaWlOH36tNrHWFxcDFNTU7i4uEAIUelcialTp+LNN99EYGAgbt26hRYtWkAulyMxMVFa58KFC0/1dGgDeyyIiIiI6IWwevVqzJkzBwEBATAxMYFSqUSPHj3Qt29fTJw4EW+99Ra8vb3h6uqKwMBAabvly5djz549MDMzg7GxMRYuXAgAiI2NxeTJk9GmTRuYmpqiY8eOSEhIwLx58zBu3DjMnj0bvr6+CAgIkPa1ZMkSjBo1Cq1bt0ajRo3Qp08faVlUVBTKysoQEBAg9WRERUXB29u70uPx9vZW6fG4du0aQkND4e3tDUdHRwQHB1e63aRJk2BlZYU+ffrg119/xfbt2zFp0iTExsaioqIC9evXx/r166v9c66KTAghtL5XA6NQKGBra4vi4mLI5XJdxyEiqraSkhJYW1sDAO7evQsrKysdJyKiF9H9+/eRnZ0NDw8PWFhY6DoOaUFVv1NNPidzKBQREREREdUYCwsiIiIiIqqxahcW5eXlyMrKwsOHD7WZh4iIiIiIDJDGhUVpaSnCwsJQr149eHt7IycnBwAwYcIEzJs3T+sBiYiIiIhI/2lcWERHR+PEiRNISUlRmdgRGBiIDRs2aDUcEREREemvx5dhJcOnjes5aXy52a1bt2LDhg3o3LmzyuWvvL29cfHixRoHelJFRQW++OIL/POf/0R+fj5cXV0xatQofP7559JzCyEwY8YMJCQkoKioCN26dUNcXBy8vLy0moWIiIiIHjEzM4ORkRFyc3PRoEEDmJmZqXwuJMMihMDNmzchk8lgampa7f1oXFjcvHkTDRs2fKq9pKRE6y+or776CnFxcVizZg28vb1x5MgRjB49Gra2tvj4448BAPPnz8fSpUuxZs0aeHh4YNq0aQgKCsKZM2d4+TMiIiKiWmBkZAQPDw/k5eUhNzdX13FIC2QyGdzc3GBsbFztfWhcWPj7++M///kPJkyYIIUAgO+++w5dunSpdpDKHDx4EEOGDMGgQYMAAE2bNsUPP/yAQ4cOAXhUXS1evBiff/45hgwZAgBYu3YtnJycsHXrVoSGhmo1DxERERE9YmZmhsaNG+Phw4eoqKjQdRyqIVNT0xoVFUA1CouYmBj83//9H86cOYOHDx9iyZIlOHPmDA4ePIi9e/fWKMxfde3aFd9++y3OnTuH5s2b48SJE/j999+xaNEiAEB2djby8/NV7pxoa2uLgIAApKamsrAgIiIiqkWPh87UZPgMvTg0Liy6d++OjIwMzJs3D23atMHOnTvRvn17pKamok2bNloN99lnn0GhUKBly5YwNjZGRUUFvvzySwwfPhwAkJ+fDwBwcnJS2c7JyUlaVpmysjKUlZVJjxUKhVZzExERERG9bDQuLADglVdeQUJCgrazPOXHH3/EunXrsH79enh7eyMjIwOTJk2Cq6srRo4cWe39zp07FzNnztRiUiIiIiKil5vGl5s1NjbGjRs3nmq/detWjcdl/dWnn36Kzz77DKGhoWjTpg1GjBiByZMnY+7cuQAAZ2dnAEBBQYHKdgUFBdKyykRHR6O4uFj6unr1qlZzExERERG9bDQuLKq6xm1ZWRnMzMxqHOhJpaWlMDJSjWhsbCxdM9nDwwPOzs5ITk6WlisUCqSnpz9zIrm5uTnkcrnKFxERERERVZ/aQ6GWLl0K4NEkne+++w7W1tbSsoqKCuzbtw8tW7bUarjXX38dX375JRo3bgxvb28cP34cixYtwnvvvSdlmTRpEubMmQMvLy/pcrOurq4IDg7WahYiIiIiIqqa2oVFbGwsgEc9FvHx8SrDnszMzNC0aVPEx8drNdyyZcswbdo0jBs3Djdu3ICrqys++OADTJ8+XVonMjISJSUlGDt2LIqKitC9e3fs2LGD97AgIiIiIqpDMqHh/bt79+6NzZs3w97evrYy1TmFQgFbW1sUFxdzWBQRGbSSkhKpR/nu3buwsrLScSIiIjJkmnxO1viqUL/99lu1gxERERER0YupWpebvXbtGrZt24acnByUl5erLHt88zoiIiIiInp5aFxYJCcnY/DgwWjWrBkyMzPh4+ODy5cvQwiB9u3b10ZGIiIiIiLScxpfbjY6OhpTpkzByZMnYWFhgU2bNuHq1avo2bMnhg4dWhsZiYiIiIhIz2lcWJw9exbvvvsuAMDExAT37t2DtbU1Zs2aha+++krrAYmIiIiISP9pXFhYWVlJ8ypcXFxw8eJFadmff/6pvWRERERERGQwNJ5j0blzZ/z+++9o1aoVBg4ciE8++QQnT57E5s2b0blz59rISEREREREek7jwmLRokW4e/cuAGDmzJm4e/cuNmzYAC8vL14RioiIiIjoJaVxYdGsWTPpeysrK63fbZuIiIiIiAyPxnMsqrJ582a0bdtWW7sjIiIiIiIDolFh8c033+Ctt97C3//+d6SnpwMA9uzZAz8/P4wYMQLdunWrlZBERERERKTf1C4s5s2bhwkTJuDy5cvYtm0b+vTpg5iYGAwfPhx/+9vfcO3aNcTFxdVmViIiIiIi0lNqz7FITExEQkICRo4cif3796Nnz544ePAgLly4ACsrq9rMSEREREREek7tHoucnBz06dMHAPDqq6/C1NQUM2fOZFFBRERERETqFxZlZWWwsLCQHpuZmcHBwaFWQhERERERkWHR6HKz06ZNQ7169QAA5eXlmDNnDmxtbVXW4b0siIiIiIhePmoXFj169EBWVpb0uGvXrrh06ZLKOjKZTHvJiIiIiIjIYKhdWKSkpNRijKpdv34dUVFR+OWXX1BaWgpPT08kJibC398fACCEwIwZM5CQkICioiJ069YNcXFx8PLy0kleIiIiIqKXkdZukFcbbt++jW7dusHU1BS//PILzpw5g4ULF8Le3l5aZ/78+Vi6dCni4+ORnp4OKysrBAUF4f79+zpMTkRERET0ctFojkVd++qrr+Du7o7ExESpzcPDQ/peCIHFixfj888/x5AhQwAAa9euhZOTE7Zu3YrQ0NA6z0xERERE9DLS6x6Lbdu2wd/fH0OHDkXDhg3h5+eHhIQEaXl2djby8/MRGBgotdna2iIgIACpqam6iExERERE9FLS68Li0qVL0nyJX3/9FR999BE+/vhjrFmzBgCQn58PAHByclLZzsnJSVpWmbKyMigUCpUvIiIiIiKqPr0eCqVUKuHv74+YmBgAgJ+fH06dOoX4+HiMHDmy2vudO3cuZs6cqa2YREREREQvPY17LHbs2IHff/9derxixQr4+vri73//O27fvq3VcC4uLmjdurVKW6tWrZCTkwMAcHZ2BgAUFBSorFNQUCAtq0x0dDSKi4ulr6tXr2o1NxERERHRy0bjwuLTTz+Vhg6dPHkSn3zyCQYOHIjs7GxERERoNVy3bt1U7p0BAOfOnUOTJk0APJrI7ezsjOTkZGm5QqFAeno6unTpUuV+zc3NIZfLVb6IiIiIiKj6NB4KlZ2dLfUibNq0Ca+99hpiYmJw7NgxDBw4UKvhJk+ejK5duyImJgZvv/02Dh06hG+//RbffvstgEc35Js0aRLmzJkDLy8veHh4YNq0aXB1dUVwcLBWsxARERERUdU0LizMzMxQWloKANi9ezfeffddAICDg4PWJ0F37NgRW7ZsQXR0NGbNmgUPDw8sXrwYw4cPl9aJjIxESUkJxo4di6KiInTv3h07duyAhYWFVrMQEREREVHVZEIIockGgwcPRnl5Obp164bZs2cjOzsbjRo1ws6dOxEeHo5z587VVtZao1AoYGtri+LiYg6LIiKDVlJSAmtrawDA3bt3YWVlpeNERERkyDT5nKzxHIvly5fDxMQEP/30E+Li4tCoUSMAwC+//IIBAwZULzERERERERk0jXssXkTssSCiFwV7LIiISJtqtcfi2LFjOHnypPT43//+N4KDgzF16lSUl5drnpaIiIiIiAyexoXFBx98IM2juHTpEkJDQ1GvXj1s3LgRkZGRWg9IRERERET6T+PC4ty5c/D19QUAbNy4ET169MD69euRlJSETZs2aTsfEREREREZAI0LCyEElEolgEeXm3187wp3d3f8+eef2k1HREREREQGQePCwt/fH3PmzMH333+PvXv3YtCgQQAe3TjPyclJ6wGJiIiIiEj/aVxYLF68GMeOHUN4eDj+8Y9/wNPTEwDw008/oWvXrloPSERERERE+k9rl5u9f/8+jI2NYWpqqo3d1SlebpaIXhS83CwREWmTJp+TTbT1pBYWFtraFRERERERGRi1CgsHBwecO3cO9evXh729PWQyWZXrFhYWai0cEREREREZBrUKi9jYWNjY2AB4NMeCiIiIiIjoSVqbY2HIOMeCiF4UnGNBRETapMnnZI2vCkVERERERPRXak/eNjY2Vmu9ioqKaochIiIiIiLDpHZhIYRAkyZNMHLkSPj5+dVmJiIiIiIiMjBqFxaHDh3CqlWrsGTJEnh4eOC9997D8OHDYW9vX5v5iIiIiIjIAKg9x8Lf3x9xcXHIy8tDREQEtmzZAjc3N4SGhmLXrl21mVEyb948yGQyTJo0SWq7f/8+xo8fD0dHR1hbWyMkJAQFBQV1koeIiIiIiB7RePK2hYUF3nnnHSQnJ+PUqVO4ceMGBgwYUOv3rzh8+DC++eYbtG3bVqV98uTJ+Pnnn7Fx40bs3bsXubm5ePPNN2s1CxERERERqarWVaGuXbuGOXPmoF+/fsjMzMSnn35aq5dpvXv3LoYPH46EhASVoVfFxcVYtWoVFi1ahD59+qBDhw5ITEzEwYMHkZaWVmt5iIiIiIhIldqFRXl5OTZs2ID+/fvDy8sLx44dw+LFi3H16lXMmzcPJiZqT9fQ2Pjx4zFo0CAEBgaqtB89ehQPHjxQaW/ZsiUaN26M1NTUWstDRERERESq1K4GXFxcYGNjg5EjR2LlypVo2LAhgEc3Y3qStnsu/vWvf+HYsWM4fPjwU8vy8/NhZmYGOzs7lXYnJyfk5+dXuc+ysjKUlZVJjxUKhdbyEhERERG9jNTusbh9+zZycnIwe/ZstGjRAvb29ipfdnZ2Wr9C1NWrVzFx4kSsW7cOFhYWWtvv3LlzYWtrK325u7trbd9ERERERC8jtXssfvvtt9rMUamjR4/ixo0baN++vdRWUVGBffv2Yfny5fj1119RXl6OoqIilV6LgoICODs7V7nf6OhoRERESI8VCgWLCyIiIiKiGlC7sOjZs2dt5qhU3759cfLkSZW20aNHo2XLloiKioK7uztMTU2RnJyMkJAQAEBWVhZycnLQpUuXKvdrbm4Oc3PzWs1ORERERPQyqb0Z11pgY2MDHx8flTYrKys4OjpK7WFhYYiIiICDgwPkcjkmTJiALl26oHPnzrqITERERET0UtLrwkIdsbGxMDIyQkhICMrKyhAUFISVK1fqOhYRERER0UtFJoQQug6hawqFAra2tiguLq7V+3EQEdW2kpISWFtbA3h0DyArKysdJyIiIkOmyefkat0gj4iIiIiI6EksLIiIiIiIqMbUmmPx5ptvqr3DzZs3VzsMEREREZEh6Tzj11p/jrSZQbX+HNqgVo/FkzeTk8vlSE5OxpEjR6TlR48eRXJyMmxtbWstKBERERER6S+1eiwSExOl76OiovD2228jPj4exsbGAB7dtG7cuHGc+ExERERE9JLSeI7F6tWrMWXKFKmoAABjY2NERERg9erVWg1HRERERESGQePC4uHDh8jMzHyqPTMzE0qlUiuhiIiIiIjIsGh8g7zRo0cjLCwMFy9eRKdOnQAA6enpmDdvHkaPHq31gEREREREpP80LiwWLFgAZ2dnLFy4EHl5eQAAFxcXfPrpp/jkk0+0HpCIiIiIiPSfxoWFkZERIiMjERkZCYVCAQCctE1ERERE9JLTuLB4EgsKIiIiIiIC1Cws/Pz8IJPJ1NrhsWPHahSIiIiIiIgMj1qFRXBwcC3HICIiIiIiQ6ZWYTFjxozazkFERERERAas2nMsjh49irNnzwIAvL294efnp7VQRERERERkWDQuLG7cuIHQ0FCkpKTAzs4OAFBUVITevXvjX//6Fxo0aKDtjEREREREpOc0vvP2hAkTcOfOHZw+fRqFhYUoLCzEqVOnoFAo8PHHH9dGRiIiIiIi0nMa91js2LEDu3fvRqtWraS21q1bY8WKFejfv79WwxERERERkWHQuMdCqVTC1NT0qXZTU1MolUqthHps7ty56NixI2xsbNCwYUMEBwcjKytLZZ379+9j/PjxcHR0hLW1NUJCQlBQUKDVHERERERE9GwaFxZ9+vTBxIkTkZubK7Vdv34dkydPRt++fbUabu/evRg/fjzS0tKwa9cuPHjwAP3790dJSYm0zuTJk/Hzzz9j48aN2Lt3L3Jzc/Hmm29qNQcRERERET2bxkOhli9fjsGDB6Np06Zwd3cHAFy9ehU+Pj745z//qdVwO3bsUHmclJSEhg0b4ujRo+jRoweKi4uxatUqrF+/Hn369AEAJCYmolWrVkhLS0Pnzp21moeIiIiIiCqncWHh7u6OY8eOYffu3cjMzAQAtGrVCoGBgVoP91fFxcUAAAcHBwCPLnn74MEDledu2bIlGjdujNTU1CoLi7KyMpSVlUmPFQpFLaYmIiIiInrxVes+FjKZDP369UO/fv20nadKSqUSkyZNQrdu3eDj4wMAyM/Ph5mZmXTZ28ecnJyQn59f5b7mzp2LmTNn1mZcIiIitXWe8Wut7j9tZlCt7p+ICNCgsNizZw/Cw8ORlpYGuVyusqy4uBhdu3ZFfHw8Xn31Va2HBIDx48fj1KlT+P3332u8r+joaEREREiPFQqFNKyLiIiINMPCiIgADSZvL168GGPGjHmqqAAAW1tbfPDBB1i0aJFWwz0WHh6O7du347fffoObm5vU7uzsjPLychQVFamsX1BQAGdn5yr3Z25uDrlcrvJFRERERETVp3ZhceLECQwYMKDK5f3798fRo0e1EuoxIQTCw8OxZcsW7NmzBx4eHirLO3ToAFNTUyQnJ0ttWVlZyMnJQZcuXbSahYiIiIiIqqb2UKiCgoJK718h7cjEBDdv3tRKqMfGjx+P9evX49///jdsbGykeRO2trawtLSEra0twsLCEBERAQcHB8jlckyYMAFdunThFaGIiIiIiOqQ2oVFo0aNcOrUKXh6ela6/I8//oCLi4vWggFAXFwcAKBXr14q7YmJiRg1ahQAIDY2FkZGRggJCUFZWRmCgoKwcuVKreYgIiIiIqJnU7uwGDhwIKZNm4YBAwbAwsJCZdm9e/cwY8YMvPbaa1oNJ4R47joWFhZYsWIFVqxYodXnJiIiIiIi9aldWHz++efYvHkzmjdvjvDwcLRo0QIAkJmZiRUrVqCiogL/+Mc/ai0oERERERHpL7ULCycnJxw8eBAfffQRoqOjpd4EmUyGoKAgrFixAk5OTrUWlIiIiIiI9JdGN8hr0qQJ/vvf/+L27du4cOEChBDw8vKCvb19beUjIiIiIiIDUK07b9vb26Njx47azkJERERERAZK7ftYEBERERERVaVaPRYvqpKSEhgbG+s6BhFRtZWUlFT6Pem3ivL7tbr/2n4tGHp+opqo7dc/oNv3gCbPLRPqXNP1BadQKGBra6vrGEREREREeqm4uBhyufyZ63AoFBERERER1RiHQj0hNzf3uZUYEVFles3ZXav7T/k8UK31SkpKpEt/FxQUwMrKSq3t9CV/dTH/szE/6TNDf/3Udn5At+8BhUIBV1dXtdZlYfEEKysrtf8IExE9ydjMolb3X51zkybnNH3MrwnmfzbmJ31m6K+f2s4P6PY9UFFRofa6LCyIiIiIDFjnGb/W6v7TZgbV6v7pxcHCgoiIiF5q/GBOpB2cvE1ERERERDXGHgsi0gv8jyEREZFhY48FERERERHVGAsLIiIiIiKqMRYWRERERERUYy/MHIsVK1bg66+/Rn5+Ptq1a4dly5ahU6dOuo5FVCc4P4GIiIh07YUoLDZs2ICIiAjEx8cjICAAixcvRlBQELKystCwYUNdx1MLPxgSERERkSF7IYZCLVq0CGPGjMHo0aPRunVrxMfHo169eli9erWuoxERERERvRQMvseivLwcR48eRXR0tNRmZGSEwMBApKamVrpNWVkZysrKpMfFxcUAAIVCUbthn+FhWUmt7l+Xx0a170V4/Rj6MehL/pKS/+VQKBSoqKhQazt9yV9dzP9szP9szP9szP9stZ0f0O3nuMfPLYR47royoc5aeiw3NxeNGjXCwYMH0aVLF6k9MjISe/fuRXp6+lPbfPHFF5g5c2ZdxiQiIiIiMlhXr16Fm5vbM9cx+B6L6oiOjkZERIT0WKlUorCwEI6OjpDJZDpMph6FQgF3d3dcvXoVcrlc13E0xvy6Zej5AcM/BubXLebXLebXLebXPUM7BiEE7ty5A1dX1+eua/CFRf369WFsbIyCggKV9oKCAjg7O1e6jbm5OczNzVXa7OzsaitirZHL5QbxgqwK8+uWoecHDP8YmF+3mF+3mF+3mF/3DOkYbG1t1VrP4Cdvm5mZoUOHDkhOTpbalEolkpOTVYZGERERERFR7TH4HgsAiIiIwMiRI+Hv749OnTph8eLFKCkpwejRo3UdjYiIiIjopfBCFBZ/+9vfcPPmTUyfPh35+fnw9fXFjh074OTkpOtotcLc3BwzZsx4ajiXoWB+3TL0/IDhHwPz6xbz6xbz6xbz696LcAxVMfirQhERERERke4Z/BwLIiIiIiLSPRYWRERERERUYywsiIiIiIioxlhY6LFevXph0qRJuo6hseflLi0tRUhICORyOWQyGYqKiuosGxFpxlDPQy8aIQTGjh0LBwcHyGQyZGRk6DqSRgz5dWTI2YnqGgsLqnNr1qzB/v37cfDgQeTl5al90xUiQ/Sifyhp2rQpFi9erOsYL7wdO3YgKSkJ27dvR15eHvz8/LB161Zdx1Lb5s2bMXv2bF3HIKJa9kJcbpYMy8WLF9GqVSv4+PjoOgr9RXl5OczMzHQdg4j+4uLFi3BxcUHXrl11HaVaHBwcdB2BiOoAeyz03MOHDxEeHg5bW1vUr18f06ZNw+MrBJeVlSEqKgru7u4wNzeHp6cnVq1apePEj1SVu1evXli4cCH27dsHmUyGXr16AQBWrlwJLy8vWFhYwMnJCW+99ZZuD+D/UyqVmD9/Pjw9PWFubo7GjRvjyy+/BABcu3YNw4YNg4ODA6ysrODv74/09HQdJ1bVq1cvhIeHV/kaatq0KWbPno13330XcrkcY8eOrfOMP/30E9q0aQNLS0s4OjoiMDAQJSUlSElJQadOnWBlZQU7Ozt069YNV65cAQCcOHECvXv3ho2NDeRyOTp06IAjR44AAJKSkmBnZ4etW7dKr6mgoCBcvXq1zo9t1KhR2Lt3L5YsWQKZTAaZTIbLly/j9OnTeO211yCXy2FjY4NXX30VFy9erPN86nrW+/nKlSuYPHmydHz65Fnv34MHD8LX1xcWFhbw9/fH1q1b9XaI0ahRozBhwgTk5ORAJpOhadOmAIA33nhD5bE+e7LnTl/P9+qQyWRP9RTZ2dkhKSlJJ3n+qlevXpgwYQImTZoEe3t7ODk5ISEhQbppsI2NDTw9PfHLL79I22zbtk36ffTu3Rtr1qzRm2HKVf19GDVqFIKDgzFz5kw0aNAAcrkcH374IcrLy3UdWVJZb66vry+++OILAMCiRYvQpk0bWFlZwd3dHePGjcPdu3frPqiWscdCz61ZswZhYWE4dOgQjhw5grFjx6Jx48YYM2YM3n33XaSmpmLp0qVo164dsrOz8eeff+o6MoCqc2/evBmfffYZTp06hc2bN8PMzAxHjhzBxx9/jO+//x5du3ZFYWEh9u/fr+tDAABER0cjISEBsbGx6N69O/Ly8pCZmYm7d++iZ8+eaNSoEbZt2wZnZ2ccO3YMSqVS15Gf8qzXEAAsWLAA06dPx4wZM+o8W15eHoYNG4b58+fjjTfewJ07d7B//34IIRAcHIwxY8bghx9+QHl5OQ4dOiR9cB0+fDj8/PwQFxcHY2NjZGRkwNTUVNpvaWkpvvzyS6xduxZmZmYYN24cQkNDceDAgTo9viVLluDcuXPw8fHBrFmzAAAVFRXo0aMHevXqhT179kAul+PAgQN4+PBhnWbTxLPez+3atcPYsWOl15M+qer9q1Ao8Prrr2PgwIFYv349rly5otfD1ZYsWYJXXnkF3377LQ4fPgxjY2M0bNgQiYmJGDBgAIyNjXUdUW36fL5/UaxZswaRkZE4dOgQNmzYgI8++ghbtmzBG2+8galTpyI2NhYjRoxATk4OCgoK8NZbb2HixIl4//33cfz4cUyZMkXXhwDg2X8fACA5ORkWFhZISUnB5cuXMXr0aDg6Okr/PNB3RkZGWLp0KTw8PHDp0iWMGzcOkZGRWLlypa6j1YwgvdWzZ0/RqlUroVQqpbaoqCjRqlUrkZWVJQCIXbt26TBh5Z6VWwghJk6cKHr27Ckt27Rpk5DL5UKhUNR11GdSKBTC3NxcJCQkPLXsm2++ETY2NuLWrVs6SKa+5/0umjRpIoKDg3UVTxw9elQAEJcvX1Zpv3XrlgAgUlJSKt3OxsZGJCUlVbosMTFRABBpaWlS29mzZwUAkZ6err3waurZs6eYOHGi9Dg6Olp4eHiI8vLyOs9SHeq8hmJjY3WUrmrPev/GxcUJR0dHce/ePaktISFBABDHjx+vw5Tqi42NFU2aNJEeAxBbtmzRWR5NPX4f6Ov5/lmefA9X9nO3tbUViYmJdZ6rMj179hTdu3eXHj98+FBYWVmJESNGSG15eXkCgEhNTRVRUVHCx8dHZR//+Mc/BABx+/btuopdqar+PgghxMiRI4WDg4MoKSmR2uLi4oS1tbWoqKioy5hVquzc2K5dOzFjxoxK19+4caNwdHSs/WC1jEOh9Fznzp1Vhhd06dIF58+fx/Hjx2FsbIyePXvqMF3VqspdUVHx1Lr9+vVDkyZN0KxZM4wYMQLr1q1DaWlpXcat1NmzZ1FWVoa+ffs+tSwjIwN+fn4GMW74eb8Lf39/XUVDu3bt0LdvX7Rp0wZDhw5FQkICbt++DQcHB4waNQpBQUF4/fXXsWTJEuTl5UnbRURE4P3330dgYCDmzZv31DAiExMTdOzYUXrcsmVL2NnZ4ezZs3V2bFXJyMjAq6++qtLDou80eT/ri2e9f7OystC2bVtYWFhIbZ06darLeC8tfT3fv0jatm0rfW9sbAxHR0e0adNGanNycgIA3LhxA1lZWSrnSkB/3gtV/X14cnm9evWkx126dMHdu3d1Muy1Onbv3o2+ffuiUaNGsLGxwYgRI3Dr1i2Dfz+wsDBQT/5BNHQ2NjY4duwYfvjhB7i4uGD69Olo166dzsd3WlpaVmuZobGystLZcxsbG2PXrl345Zdf0Lp1ayxbtgwtWrRAdnY2EhMTkZqaiq5du2LDhg1o3rw50tLSAABffPEFTp8+jUGDBmHPnj1o3bo1tmzZorPj0MSL9NrRZ/w56yd9Pd+rSyaTSUNxHnvw4IGO0lTur/+0kMlkKm2P/0mgj0N3n/Ssvw+GwMjIqMrXyuXLl/Haa6+hbdu22LRpE44ePYoVK1YAgF7NE6kOFhZ67q+TgdPS0uDl5YV27dpBqVRi7969Okr2bFXlrmossImJCQIDAzF//nz88ccfuHz5Mvbs2VMXUavk5eUFS0tLJCcnP7Wsbdu2yMjIQGFhoQ6SaUbT30Vdk8lk6NatG2bOnInjx4/DzMxMKhL8/PwQHR2NgwcPwsfHB+vXr5e2a968OSZPnoydO3fizTffRGJiorTs4cOH0mRu4NF/qIuKitCqVau6O7D/z8zMTOU/+23btsX+/fv17sPIszzrNfTX49MXz3r/tmjRAidPnkRZWZnUdvjw4bqMV2OmpqZ6+XNXhz6e79XVoEEDld7T8+fPG/R/mFu0aKFyrgT0673wrL8PJ06cwL1796R109LSYG1tDXd3d13FVfHX14pCoZCKoqNHj0KpVGLhwoXo3LkzmjdvjtzcXF1F1SoWFnouJycHERERyMrKwg8//IBly5Zh4sSJaNq0KUaOHIn33nsPW7duRXZ2NlJSUvDjjz/qOjKAqnNXZvv27Vi6dCkyMjJw5coVrF27FkqlEi1atKjj1KosLCwQFRWFyMhIrF27FhcvXkRaWhpWrVqFYcOGwdnZGcHBwThw4AAuXbqETZs2ITU1VaeZK6PJ76KupaenIyYmBkeOHEFOTg42b96MmzdvwtLSEtHR0UhNTcWVK1ewc+dOnD9/Hq1atcK9e/cQHh6OlJQUXLlyBQcOHMDhw4dVigZTU1NMmDAB6enpOHr0KEaNGoXOnTvrpIu/adOmSE9Px+XLl/Hnn38iPDwcCoUCoaGhOHLkCM6fP4/vv/8eWVlZdZ5NXc96DTVt2hT79u3D9evX9ebiEcCz379///vfoVQqMXbsWJw9exa//vorFixYAAB6d2WrqjRt2hTJycnIz89XGR6i7/T1fK+uPn36YPny5Th+/DiOHDmCDz/80KCGNf7VBx98gMzMTERFReHcuXP48ccfpStc6fq9UNXfh8fn+vLycoSFheHMmTP473//ixkzZiA8PBxGRvrx0bZPnz74/vvvsX//fpw8eRIjR46U/qHn6emJBw8eYNmyZbh06RK+//57xMfH6zixluh6kgdVrWfPnmLcuHHiww8/FHK5XNjb24upU6dKkyjv3bsnJk+eLFxcXISZmZnw9PQUq1ev1nHq5+f+6+Tt/fv3i549ewp7e3thaWkp2rZtKzZs2KCj9KoqKirEnDlzRJMmTYSpqalo3LixiImJEUIIcfnyZRESEiLkcrmoV6+e8Pf318nk4Gd53u9C1xNvz5w5I4KCgkSDBg2Eubm5aN68uVi2bJnIz88XwcHB0mu7SZMmYvr06aKiokKUlZWJ0NBQ4e7uLszMzISrq6sIDw+XJuImJiYKW1tbsWnTJtGsWTNhbm4uAgMDxZUrV3RyjFlZWaJz587C0tJSABDZ2dnixIkTon///qJevXrCxsZGvPrqq+LixYs6yfc8z3sNpaamirZt2wpzc3Ohb39SnvX+PXDggGjbtq0wMzMTHTp0EOvXrxcARGZmpo5TV+6vk7e3bdsmPD09hYmJiUq7vno8AVqfz/dVeXLy9vXr10X//v2FlZWV8PLyEv/973/1bvL2kxeLEKLy8zyemIT+73//W3h6egpzc3PRq1cvERcXJwCoXNxAF6r6+yDEo8nbQ4YMEdOnTxeOjo7C2tpajBkzRty/f1+nmZ9UXFws/va3vwm5XC7c3d1FUlKSyuTtRYsWCRcXF2FpaSmCgoLE2rVr9WLSfE3JhPjLADAiemH06tULvr6+L9WdkZOSkjBp0iSDGbNN+mHdunUYPXo0iouLOT+DXmpffvkl4uPj9XoS9KhRo1BUVGRQd59/WfA+FkRE9NJZu3YtmjVrhkaNGuHEiROIiorC22+/zaKCXjorV65Ex44d4ejoiAMHDuDrr79GeHi4rmORgWJhQUREL538/HxMnz4d+fn5cHFxwdChQw3mxlpE2nT+/HnMmTMHhYWFaNy4MT755BNER0frOhYZKA6FIiIiIiKiGtOPqfNERERERGTQWFgQEREREVGNsbAgIiIiIqIaY2FBREREREQ1xsKCiIiIiIhqjIUFERERERHVGAsLIgOUn5+PiRMnwtPTExYWFnByckK3bt0QFxeH0tJSlXXnzp0LY2NjfP3110/tJykpCTKZDDKZDEZGRnBzc8Po0aNx48YNaZ3Hy2UyGUxMTNC4cWNERESgrKxMWufmzZv46KOP0LhxY5ibm8PZ2RlBQUE4cOBAlcdw+fJlhIWFwcPDA5aWlnjllVcwY8YMlJeXq6zz5PM//kpLS6vJj4+ISOtGjRoFmUyGefPmqbRv3boVMpkMAJCSkqJyLnNyckJISAguXbokrd+0aVNpubGxMVxdXREWFobbt28/8/mfPJ8bGxvD3t4eAQEBmDVrFoqLi7V/wESVYGFBZGAuXboEPz8/7Ny5EzExMTh+/DhSU1MRGRmJ7du3Y/fu3Srrr169GpGRkVi9enWl+5PL5cjLy8O1a9eQkJCAX375BSNGjFBZJzExEXl5ecjOzsbKlSvx/fffY86cOdLykJAQHD9+HGvWrMG5c+ewbds29OrVC7du3aryODIzM6FUKvHNN9/g9OnTiI2NRXx8PKZOnfrUurt370ZeXp701aFDB01+ZEREdcLCwgJfffXVc4uArKws5ObmYuPGjTh9+jRef/11VFRUSMtnzZqFvLw85OTkYN26ddi3bx8+/vjj5z7/k+fzgwcPYuzYsVi7di18fX2Rm5tb4+Mjei5BRAYlKChIuLm5ibt371a6XKlUSt+npKSIRo0aifLycuHq6ioOHDigsm5iYqKwtbVVafvyyy+FkZGRKC0tFUIIAUBs2bJFZZ2wsDAxcOBAIYQQt2/fFgBESkpKDY9MiPnz5wsPDw/pcXZ2tgAgjh8/XuN9ExHVppEjR4rXXntNtGzZUnz66adS+5YtW8Tjj1u//fabACBu374tLV+3bp0AIDIzM4UQQjRp0kTExsaq7Hv27NmidevWz3z+ys7nQghRUFAg6tevL4YPH169AyPSAHssiAzIrVu3sHPnTowfPx5WVlaVrvO4yx0AVq1ahWHDhsHU1BTDhg3DqlWrnvsclpaWUCqVePjwYaXLz507hz179iAgIAAAYG1tDWtra2zdulVleFR1FBcXw8HB4an2wYMHo2HDhujevTu2bdtWo+cgIqotxsbGiImJwbJly3Dt2jW1trG0tAQAlWGgT7p+/Tp+/vln6ZyrqYYNG2L48OHYtm2bSq8IUW1gYUFkQC5cuAAhBFq0aKHSXr9+fekDflRUFABAoVDgp59+wjvvvAMAeOedd/Djjz/i7t27Ve7//PnziI+Ph7+/P2xsbKT2YcOGwdraGhYWFmjRogW8vb0RHR0NADAxMUFSUhLWrFkDOzs7dOvWDVOnTsUff/yh8bEtW7YMH3zwgdRmbW2NhQsXYuPGjfjPf/6D7t27Izg4mMUFEemtN954A76+vpgxY8Zz183Ly8OCBQvQqFEjlfN6VFQUrK2tYWlpCTc3N8hkMixatKjamVq2bIk7d+48c3gqkTawsCB6ARw6dAgZGRnw9vaWeg1++OEHvPLKK2jXrh0AwNfXF02aNMGGDRtUti0uLoa1tTXq1auHFi1awMnJCevWrVNZJzY2FhkZGThx4gS2b9+Oc+fOqczDCAkJQW5uLrZt24YBAwYgJSUF7du3R1JSEgDgww8/lAofa2vrp/Jfv34dAwYMwNChQzFmzBipvX79+oiIiEBAQAA6duyIefPm4Z133ql0IjoRkb746quvsGbNGpw9e7bS5W5ubrCysoKrqytKSkqwadMmmJmZScs//fRTZGRk4I8//kBycjIAYNCgQVKPw5Pn0w8//PC5eYQQAFR7tIlqg4muAxCR+jw9PSGTyZCVlaXS3qxZMwD/61IHHg2DOn36NExM/vc2VyqVWL16NcLCwqQ2GxsbHDt2DEZGRnBxcVHZx2POzs7w9PQEALRo0QJ37tzBsGHDMGfOHKndwsIC/fr1Q79+/TBt2jS8//77mDFjBkaNGoVZs2ZhypQplR5Tbm4uevfuja5du+Lbb7997s8gICAAu3bteu56RES60qNHDwQFBSE6OhqjRo16avn+/fshl8vRsGFDld7hx+rXry+dW728vLB48WJ06dIFv/32GwIDA5GRkSGtK5fLn5vn7NmzkMvlcHR0rPYxEamDhQWRAXF0dES/fv2wfPlyTJgwocp5FidPnsSRI0eQkpKiMmehsLAQvXr1QmZmJlq2bAkAMDIykv6AqcvY2BgAcO/evSrXad26NbZu3Qrg0Rjfhg0bPrXO9evX0bt3b3To0AGJiYkwMnp+J2pGRgZcXFw0yktEVNfmzZsHX1/fp4auAoCHhwfs7OzU3tdfz7manLNv3LiB9evXIzg4WK1zLFFNsLAgMjArV65Et27d4O/vjy+++AJt27aFkZERDh8+jMzMTHTo0AGrVq1Cp06d0KNHj6e279ixI1atWqXRcKKioiLk5+dDqVTi/PnzmDVrFpo3b45WrVrh1q1bGDp0KN577z20bdsWNjY2OHLkCObPn48hQ4ZUuc/r16+jV69eaNKkCRYsWICbN29Ky5ydnQEAa9asgZmZGfz8/AAAmzdvxurVq/Hdd9+pnZ2ISBfatGmD4cOHY+nSpRpve+fOHeTn50MIgatXryIyMhINGjRA165dn7mdEELarqioCKmpqYiJiYGtre1T99cgqg0sLIgMzCuvvILjx48jJiYG0dHRuHbtGszNzdG6dWtMmTIFY8eORbNmzaRJ3H8VEhKChQsXIiYmRu3nHD16NIBH43OdnZ3Ro0cPxMTEwMTEBNbW1ggICEBsbCwuXryIBw8ewN3dHWPGjKn0nhSP7dq1CxcuXMCFCxfg5uamsuzxeGAAmD17Nq5cuQITExO0bNkSGzZswFtvvaV2diIiXZk1a9ZT89rUMX36dEyfPh0A0KBBA3Ts2BE7d+587lAmhUIBFxcXyGQyyOVytGjRAiNHjsTEiRPVGjJFVFMy8eRfcCIiIiIiomrgYDsiIiIiIqoxFhZERERERFRjLCyIiIiIiKjGWFgQEREREVGNsbAgIiIiIqIaY2FBREREREQ1xsKCiIiIiIhqjIUFERERERHVGAsLIiIiIiKqMRYWRERERERUYywsiIiIiIioxlhYEBERERFRjf0/MTVOUfE9LGEAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_cas['app']\n", - "gap_22_cas = df_gap22_cas['coldRate'].astype(float)\n", - "\n", - "gap_25_cas = df_gap25_cas['coldRate'].astype(float)\n", - "\n", - "app_npb = df_npbC_cas['app']\n", - "npb_C_cas = df_npbC_cas['coldRate'].astype(float)\n", - "\n", - "npb_D_cas = df_npbD_cas['coldRate'].astype(float)\n", - "\n", - "# Multi bar Chart1\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,100])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*2, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - "\n", - "offset = i*2+1\n", - "for i,app in enumerate(app_npb):\n", - " plt.bar(offset+i*2+1, npb_C_cas[i], width=1, color=cmap(1))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=10, color='black')\n", - "\n", - "plt.ylabel(\"Cold Miss Rate\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "\n", - "# Multi bar Chart2\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,100])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*2, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - "\n", - "offset = i*2+1\n", - "for i,app in enumerate(app_npb):\n", - " plt.bar(offset+i*2+1, npb_D_cas[i], width=1, color=cmap(1))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=10, color='black')\n", - "\n", - "plt.ylabel(\"Cold Miss Rate\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 90, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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u4kdERERERG9X5QuLFavXo3u3bvD398f/v7+svaCggJs2LABffr0KdeARERERESk+ZQuLPr27Yu2bdvCyspKrv3+/fvo27cvCwsiIiIiUgiHZr5blL6PhRACEonklfYbN27A3Ny8XEIREREREZF2UbjHwtPTExKJBBKJBK1bt4ae3v82LSwsRGpqKtq2bauSkEREREREpNkULiye35AuOTkZgYGBMDU1lS0zMDCAo6NjqS43S0RERERE2k/hwmL8+PEAAEdHR3Tv3p03qCMiIiKi9x7nifyP0pO3Q0JCVJGDiIiIiIi0mNKFRWFhIaKjo7Fp0yZcv34dBQUFcsuzsrLKLRwREREREWkHpa8KFRUVhTlz5qB79+7IyclBeHg4OnfuDB0dHUyYMEEFEYmIiIiISNMpXVisXbsWy5cvx1dffQU9PT307NkTP/74I8aNG4fExERVZCQiIiIiIg2ndGGRkZGB+vXrAwBMTU2Rk5MDAGjfvj1+++238k1HRERERERaQenCwt7eHunp6QCAmjVrYs+ePQCAY8eOwdDQsHzTERERERGRVlC6sPjkk08QHx8PABg6dCjGjh0LFxcX9OnTB/369Sv3gEREREREpPmUvirU9OnTZd93794d1atXx5EjR+Di4oIOHTqUazgiIiIiItIOShcWL/P19YWvry8A4Pjx4/Dy8ipzKCIiIiIi0i5KD4V68OABHj16JNeWnJyMDh06wMfHp9yCERERERGR9lC4sEhLS4Ofnx/Mzc1hbm6O8PBw5OXloU+fPvDx8YGJiQmOHDmiyqxERERERKShFB4K9fXXX+Px48eYN28e4uLiMG/ePBw6dAg+Pj64fPky7O3tVZmTiIiIiIg0mMKFxcGDBxEXFwdfX19069YNNjY26NWrF0aMGKHCeEREREREpA0UHgqVmZkJJycnAICVlRUqVKiAjz76SGXBiIiIiIhIeyg1eVtHR0fuewMDg3IPRERERERE2kfhoVBCCNSqVQsSiQTAs6tDeXp6yhUbAJCVlVW+CYnKie/43So/RmJUoMqPQURE5UPVnwv8TKD3jcKFRUxMjCpzEBERERGRFlO4sAgJCVFlDkyfPh2RkZEYPnw45s6dCwB4/PgxvvrqK2zYsAH5+fkIDAzE4sWLYW1trdIsRERERESkHKVvkKcKx44dww8//AB3d3e59pEjR+LX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ZGdny/VaZGZmwsbGpth9GRoawtDQsFQ5iIiIiIiodBQuLObPnw/g2U3wfvzxR5iamsqWFRYW4uDBg6hTp45SBxdCYOjQodi6dSv2798PJycnueWNGjWCvr4+4uPjERwcDABISUnB9evX4efnp9SxiIiIiIhIdRQuLKKjowE8KwaWLl0qN+zJwMAAjo6OWLp0qVIHHzx4MNatW4dffvkFZmZmsnkT5ubmMDY2hrm5OcLCwhAeHo5KlSpBKpVi6NCh8PPz4xWhiIiIiIg0iMKFRWpqKgCgZcuWiIuLQ8WKFct88CVLlgAAWrRoIdceExOD0NBQAM8KGh0dHQQHByM/Px+BgYFYvHhxmY9NRERERETlR+k5Fn/++afs++fzLSQSSakOXtJ8jRcZGRlh0aJFWLRoUamOQUREREREqleq+1isXr0a9evXh7GxMYyNjeHu7o41a9aUdzYiIiIiItISSvdYzJkzB2PHjsWQIUPg7+8PAPjrr78wcOBA/Pfffxg5cmS5hyQiIiIiIs2mdGGxYMECLFmyBH369JG1dezYEW5ubpgwYQILCyIiIiKi95DSQ6HS09PRpEmTV9qbNGmC9PT0cglFRERERETaRenCwtnZGZs2bXqlfePGjXBxcSmXUEREREREpF2UHgoVFRWF7t274+DBg7I5FocPH0Z8fHyxBQcREREREb37lC4sgoODkZSUhOjoaGzbtg0AULduXRw9ehSenp7lnY+IXuA7frdK958YFajS/RMREdG7S+nCAgAaNWqEn376qbyzEBERERGRllK4sMjNzVVoPalUWuowRERERESknRQuLCwsLF57h20hBCQSCQoLC8slGBG9mzici4iI6N2kcGHx559/yr4XQuDjjz/Gjz/+iKpVq6okGBERERERaQ+FC4vmzZvLPdbV1YWvry9q1KhR7qGIiIiIiEi7KH0fCyIiIiIiopexsCAiIiIiojIrU2HxusncRERERET0/lB4jkXnzp3lHj9+/BgDBw6EiYmJXHtcXFz5JCMiIiIiIq2hcGFhbm4u97h3797lHoaIiIiIiLSTwoVFTEyMKnMQEREREZEWU7iwoLLhTcGIiIiI6F3Gq0IREREREVGZsbAgIiIiIqIyY2FBRERERERlxsKCiIiIiIjKjIUFERERERGVmVYUFosWLYKjoyOMjIzg4+ODo0ePqjsSERER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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_cas['app']\n", - "gap_22_cas = df_gap22_cas['missRatio'].astype(float)-df_gap22_cas['coldRate'].astype(float)\n", - "\n", - "gap_25_cas = df_gap25_cas['missRatio'].astype(float)-df_gap25_cas['coldRate'].astype(float)\n", - "\n", - "app_npb = df_npbC_cas['app']\n", - "npb_C_cas = df_npbC_cas['missRatio'].astype(float)-df_npbC_cas['coldRate'].astype(float)\n", - "\n", - "npb_D_cas = df_npbD_cas['missRatio'].astype(float)-df_npbD_cas['coldRate'].astype(float)\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,100])\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*2, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - "\n", - "offset = i*2+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*2+1, npb_C_cas[i], width=1, color=cmap(1))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "\n", - "plt.ylabel(\"Hot Miss Rate (%)\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "#plt.ylim([0,55])\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*2, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - "\n", - "offset = i*2+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*2+1, npb_D_cas[i], width=1, color=cmap(1))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "\n", - "plt.ylabel(\"Hot Miss Rate (%)\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 91, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_cas['app']\n", - "gap_22_cas = df_gap22_cas['missRatio'].astype(float)\n", - "\n", - "gap_25_cas = df_gap25_cas['missRatio'].astype(float)\n", - "\n", - "app_npb = df_npbC_cas['app']\n", - "npb_C_cas = df_npbC_cas['missRatio'].astype(float)\n", - "\n", - "npb_D_cas = df_npbD_cas['missRatio'].astype(float)\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,100])\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*2, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - "\n", - "offset = i*2+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*2+1, npb_C_cas[i], width=1, color=cmap(1))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "\n", - "plt.ylabel(\"Total Miss Rate (%)\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "#plt.ylim([0,55])\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*2, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - "\n", - "offset = i*2+1\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*2+1, npb_D_cas[i], width=1, color=cmap(1))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*2, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "\n", - "plt.ylabel(\"Total Miss Rate (%)\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 70, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAxYAAADSCAYAAADXL1aYAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAABBOklEQVR4nO3dd3gUVfs38O+kbPomJJCQQBqETgJIJ0roTYg0RVoKCKJAgCglICDwUMUgoIJiSEBFUSmiwqOPIaGEIpJCDzX0EkoqkLbn/YOX/bGk7WaTLfD9XNdeV/bMnDP3bGZn9945Z44khBDQkfnz58PKygpTp04FAMTFxaFXr16ws7NDZmYmYmJiMHz4cF2FQ0RERERElcRElxv75Zdf0LhxY+XzhQsXIiwsDHfv3sXnn3+ORYsW6TIcIiIiIiKqJGa62MjGjRshhEBaWhqSk5Nx7949CCGQkJCA1157DRs3boRCocDFixexceNGAEBQUJAuQiMiIiIiokqgk8TC09MTACCTyeDi4gJPT08kJydDLpejc+fOEEIgLy8PkiTBy8sLOuydRURERERElUDS5RiLHj16wNraGtOnT8f8+fNRs2ZNREdHAwCOHz+OwYMHIzU1VVfhEBERERFRJdFpYpGSkoI33ngDV65cQcOGDfHnn3/C3d0dAPDBBx+gsLAQK1eu1FU4RERERERUSXSaWDx17949ODk5qZTdvHkTcrkcNjY2ug6HiIiIiIi0pJfE4qlr167Bzc0NJiY6vTkVERERERFVMr1+o2/cuDHS0tL0GQIREREREVUCvSYWvPsTEREREdGLgX2QiIiIiIhIa3pNLGbOnAlHR8cK11+zZg38/Pwgl8shl8vRvn177Nq1qxIjJCIiIiIideh18La2fvvtN5iamqJevXoQQmDDhg345JNPkJSUhCZNmug7PCIiIiKil4bOEov58+ertd6cOXO02o6joyM++eQTjB49Wqt2iIiIiIhIfTpLLExMTODm5gZnZ+dSB21LkoTExMQKtV9UVISff/4ZwcHBSEpKQuPGjbUJl4iIiIiINGCmqw317t0bu3fvRqtWrTBq1Cj07du3UuavOH78ONq3b4/Hjx/D1tYW27ZtKzWpyMvLQ15envK5QqHA/fv34eTkBEmStI6FiIiIiOhFIoRAdna2WnPP6XSMxY0bN7BhwwbExMQgKysLQUFBGDVqFBo0aFDhNvPz83HlyhVkZmbil19+wTfffIM9e/aUmFx8/PHHmDdvnja7QERERET00rl69Spq165d5jp6G7y9d+9eREdHY8uWLfD19cXff/8NKysrrdvt1q0b6tati6+++qrYsuevWGRmZsLDwwNXr16FXC7XettERPqWm5sLNzc3AE9+zLGxsdFzREREZMyysrLg7u6OjIwM2Nvbl7muzrpCPa9169ZIS0vDqVOnkJSUhIKCgkpJLBQKhUry8CwLCwtYWFgUK396u1oiImNnamqq/FsulzOxICKiSqHOsAGdJxYHDx7E+vXr8dNPP6F+/foIDQ3FsGHDKvTFPiIiAr1794aHhweys7OxadMmxMfH488//6yCyImIiIiIqDQ6SyyWLVuGmJgY3L17F8OHD8e+ffvg5+enVZt37txBUFAQbt68CXt7e/j5+eHPP/9E9+7dKylqIiIiIiJSh05vN+vh4YG+fftCJpOVul5kZKQuwgHwpM+Yvb09MjMzS71iUlRUhIKCAp3FRKRP5ubmKl1pyPjk5ubC1tYWAJCTk8OuUEREpBV1vi8/pbMrFh07doQkSTh58qSuNqm1nJwcXLt2rdR5N4heNJIkoXbt2sovpkRERETq0lliER8fr6tNVYqioiJcu3YN1tbWqFGjBue5oBeeEALp6em4du0a6tWrxysXREREpBG93RXqeadPn0ZUVBSWL1+u71AAAAUFBRBCoEaNGpVytyoiY1CjRg2kpaWhoKCAiQURERFpRPupr7WQm5uLqKgodOjQAU2aNMF///tffYZTIl6poJcJj3ciIiKqKL0kFgkJCRg1ahRcXFwwduxYdOjQAadOncKJEyf0EQ4REREREWlJZ4nFnTt3sGzZMjRs2BCDBw+Gg4MD4uPjYWJiglGjRqFhw4a6CoXohZaWlgZJkpCRkaHvUIiIiOglorMxFp6enhg8eDBWrlyJ7t27w8REr72wKqzd3KqffO/QvJ5qrffsnXsePXoEMzMzmJubAwBee+017Nq1C5IkwcrKCmZmZjAzM0ODBg0wZMgQjB8/XrluTEwMRo8eDSsrK0iSBBcXF4wfPx5TpkxR2V5ubi5cXV3RqFEjHD58WGVZSEgINmzYgHXr1uGdd95Rlv/8889466238MYbb2D79u0VeTk0Erj99Srfxo7+f2hc5++//8a8efOQ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/v374evrW2zwdlhYmNpt+fr6YufOnXB3d9c0DCIiIiIiMiAaT5Dn7e1demOShIsXL6rdlp2dHVJSUvQ227YmE34QERkDTpBHRESVqUonyONYCSIiIiIiep7GE+RVptdeew1WVlb6DIGIiIiIiCqBWlcswsPDsWDBAtjY2CA8PLzMdSMjI9Xe+M6dO9VetySLFy/G1q1bcebMGVhZWaFDhw5YunQpGjRooFW7RERERESkGbUSi6SkJBQUFCj/1lZRURG2b9+O06dPAwCaNGmCwMBAmJqaatTOnj17MH78eLRu3RqFhYWYOXMmevTogVOnTrFfMRERERGRDmk8eFtb58+fx+uvv45r164pryykpqbC3d0df/zxh8a3sX1Weno6nJ2dsWfPHnTs2LHc9Tl4m4heNBy8TURElUmT78saj7EYNWoUsrOzi5Xn5uZi1KhR5dYPCwtDnTp1cPXqVSQmJiIxMRFXrlyBt7e3RreqLUlmZiYAwNHRscTleXl5yMrKUnkQEREREZH2NL5iYWpqips3b8LZ2Vml/O7du6hZsyYKCwvLrG9jY4NDhw7B19dXpTwlJQX+/v7IycnRJBwlhUKBwMBAZGRkYP/+/SWu8/HHH2PevHnFynnFgoheFLxiQURElalKbjeblZUFIQSEEMjOzoalpaVyWVFREXbu3Fks2SiJhYVFiVc8cnJyIJPJ1A2nmPHjx+PEiROlJhUAEBERoTL4PCsri5PzERERERFVArUTCwcHB0iSBEmSUL9+/WLLJUkq8WrA8/r27YuxY8ciKioKbdq0AQAcPnwY48aNQ2BgoAah/58JEybg999/x969e1G7du1S17OwsICFhUWFtkFERERERKVTO7GIi4uDEAJdunTBli1bVMYxyGQyeHp6ws3Nrdx2Vq1aheDgYLRv3x7m5uYAgMLCQgQGBmLlypUaBS+EwMSJE7Ft2zbEx8eXOSs4ERERERFVHbUTi4CAAABPZt728PCAJEkV2qCDgwN+/fVXnDt3DmfOnAEANGrUCD4+Phq3NX78eGzatAm//vor7OzscOvWLQCAvb09J94jIiIiItIhnd9utjKVltxER0cjJCSk3Pq83SwRvWg4eJuIiCpTlQzerixFRUWIiYlBbGws7ty5A4VCobJ89+7dardlxDkREREREdELReeJxaRJkxATE4PXX38dTZs2rXCXKiIiIiIiMhw6Tyx+/PFH/PTTT+jTp4+uN01ERERERFVE45m3tSWTySo0UJuIiIiIiAyXxonF7du3MXLkSLi5ucHMzAympqYqj/J88MEHWLlyJcdHEBERERG9QDTuChUSEoIrV65g9uzZcHV11XiMxP79+xEXF4ddu3ahSZMmyrksntq6daumIRERERERkZ5pnFjs378f+/btQ/PmzSu0QQcHBwwYMKBCdYmIiIiIyDBpnFi4u7tr1Y0pOjq6wnWJiIjazf1Tq/qH5vWspEiIdEubY5/HPemCxmMsPvvsM8yYMQNpaWlVEA4RERERERkjja9YDBkyBA8fPkTdunVhbW1dbIzE/fv3Ky04IiIiIiIyDhonFp999lkVhEFERERERMZM48QiODi4KuIgIiIiIiIjVqGZt4uKirB9+3acPn0aANCkSRMEBgaqNY8FERERERG9eDQevH3+/Hk0atQIQUFB2Lp1K7Zu3YoRI0agSZMmuHDhglpt7NmzB/369YOPjw98fHwQGBiIffv2aRw8EREREREZBo0Ti7CwMNStWxdXr15FYmIiEhMTceXKFXh7eyMsLKzc+t999x26desGa2trhIWFISwsDFZWVujatSs2bdpUoZ0gIiIiIiL90rgr1J49e3Do0CE4Ojoqy5ycnLBkyRL4+/uXW3/hwoVYtmwZpkyZoiwLCwtDZGQkFixYgGHDhmkaEhEREVG5OAcKUdXS+IqFhYUFsrOzi5Xn5ORAJpOVW//ixYvo169fsfLAwEBcunRJ03CIiIiIiMgAaJxY9O3bF2PHjsXhw4chhIAQAocOHcK4ceMQGBhYbn13d3fExsYWK//777/h7u6uaThERERERGQANO4KtWrVKgQHB6N9+/bKyfEKCwsRGBiIlStXllv/gw8+QFhYGJKTk9GhQwcAQEJCAmJiYtSqT0RERKQPgdtf16r+jv5/VFIkRIZJ48TCwcEBv/76K86dO4czZ84AABo1agQfHx+16r/33nuoWbMmPv30U/z000/K+ps3b8Ybb7yhaThERERERGQAKjSPBQDUq1cP9erVq1DdAQMGYMCAARXdNBERERERGRi1Eovw8HAsWLAANjY2CA8PL3PdyMjIMpfXqVMHR44cgZOTk0p5RkYGXnnlFVy8eFGdkIiIiIiIyIColVgkJSWhoKBA+bc20tLSUFRUVKw8Ly8P169f16ptIiIiIiLSD7USi7i4uBL/1sSOHTuUf//555+wt7dXPi8qKkJsbCy8vLwq1DYREREREemXxmMsRo0ahZUrV8LOzk6lPDc3FxMnTsT69etLrNe/f38AgCRJCA4OVllmbm4OLy8vfPrpp5qGQ3rGyYaIiIiICKhAYrFhwwYsWbKkWGLx6NEjbNy4sdTEQqFQAAC8vb1x5MgRVK9evQLhEtGLgkkpvax47BPRi0rtxCIrK0s5IV52djYsLS2Vy4qKirBz5044OzuX2w5n1y6OHzJERKQubeZS4DwKRFSV1E4sHBwcIEkSJElC/fr1iy2XJAnz5s2r1OCIiIiIiMg4qJ1YxMXFQQiBLl26YMuWLXB0dFQuk8lk8PT0hJubW5UESUREREREhk3txCIgIADAk65MHh4ekCSpyoIiIiIiIiLjovHg7cuXL+Py5culLu/YsaNWARERERFR5dJmbA7A8TmkHo0Ti06dOhUre/bqRUmT32VlZandvlwu1zQkogrjwHkiIvXxnElEZdE4sXjw4IHK84KCAiQlJWH27NlYuHBhiXWeDvxWR0mJCRERERERGTaNE4tnZ8x+qnv37pDJZAgPD8fRo0eLLX92tu60tDTMmDEDISEhaN++PQDg4MGD2LBhAxYvXqxpOET0kuJlfSIiIsOicWJRGhcXF6Smppa47OnAbwCYP38+IiMjMXToUGVZYGAgfH198fXXXxeblZvKxy9YLy92SyAiIiJDoXFicezYMZXnQgjcvHkTS5YsQfPmzcutf/DgQaxdu7ZYeatWrfDOO+9oGg4RERERERkAjROL5s2bQ5IkCCFUytu1a4f169eXW9/d3R3r1q3DsmXLVMq/+eYbuLu7axoOERGRRniVl4ioamicWFy6dEnluYmJCWrUqAFLS0u16q9YsQKDBg3Crl270LZtWwDAP//8g3PnzmHLli0axbJ371588sknOHr0KG7evIlt27ahf//+GrVBRFQR7IZGRESkSuPEwtPTU6sN9unTB2fPnsWaNWtw5swZAEC/fv0wbtw4ja9Y5ObmolmzZhg1ahQGDhyoVVykH/zlkIiIiOjFoHFiERYWBh8fH4SFhamUf/755zh//jw+++yzcttwd3fHokWLNN10Mb1790bv3r21bic/Px/5+flat1NRptDuFrsmRSZa1ddm3405dkD7+PV53ADG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ebGuqwDg7e0NBwcHtdt6/pxb0jl72LBhmDlzJpKSkoqNsygoKEB+fj7HWVCVY2JBZGS+/PJL+Pv7o1WrVvj444/h5+cHExMTHDlyBGfOnEHLli0RFRWFNm3aoGPHjsXqt27dGlFRUSXOa1GajIwM3Lp1CwqFAufOncP8+fNRv359NGrUCPfu3cObb76JUaNGwc/PD3Z2dvj333+xbNkyvPHGG6W2ef36dXTq1Amenp5Yvnw50tPTlctq1qwJ4En3p759+2LSpEkYNGgQbt26BQCQyWQcwE1EBs3X1xfDhw/HqlWrNK6bnZ2NW7duQQiBq1evYtq0aahRowY6dOhQap3Jkyfjjz/+QNeuXbFgwQK8+uqryvPx0qVLERUVxdvNUtXT812piKgCbty4ISZMmCC8vb2Fubm5sLW1FW3atBGffPKJyMzMFE5OTmLZsmUl1l26dKlwdnYW+fn5Jd5u9nkAlA9JkoSrq6sYMmSIuHDhghBCiMePH4sZM2aIV155Rdjb2wtra2vRoEED8dFHHylvWVuS6OholbaffTwVHBxc4vKAgACNXzMioqoUHBws3njjDZWyS5cuCZlMVubtZp/n6empcr6rUaOG6NOnj0hKSio3hsePH4vFixcLX19fYWlpKRwdHYW/v7+IiYkRBQUFWuwdkXokITjah4iIiIiItMO7QhERERERkdaYWBARERERkdaYWBARERERkdaYWBARERERkdaYWBARERERkdaYWBARERERkdaYWBARERERkdaYWBARERERkdaYWBARERERkdaYWBARERERkdaYWBARERERkdaYWBARERERkdb+H7nyKaLPkc3SAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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qU9yYaGpkpISREdHIy4uDunp6VAoFCrz9+zZo/a6tHwJDiIiIiIiKofWC4vJkycjOjoab775Jpo3b17lLlVERERERKQ/tF5Y/PTTT/j555/Rr18/bW+aiIiIiIheEMkXyNOUTCar0kBtIiIiIiLSX5ILi7t372LkyJFwcXGBiYkJjI2NVW6V+fjjj7Fy5UqOjyAiIiIieolI7goVFBSEGzduYNasWXB2dpY8RuLgwYPYu3cvdu7ciWbNmimvZfHU1q1bpUYiIiIiIiIdk1xYHDx4EAcOHEDLli2rtEE7OzsMHDiwSm2JiIiIiEg/SS4sXF1dNerGFBUVVeW2RERERESknySPsVixYgU+/fRTpKSkvIA4RERERERkiCQfsXj33Xfx6NEjNGjQAJaWlqXGSDx48KDawhER0YvRIezPKrc9Mqd3NSYhIqKXheTCYsWKFS8gBhERERG9rDT5MQPgDxqGQnJhERgY+CJyEBERERGRAavSlbdLSkqwfft2nD9/HgDQrFkz+Pv7q3UdCyIiIiIievlIHrx9+fJlNGnSBKNGjcLWrVuxdetWjBgxAs2aNcOVK1fUWse+ffswYMAAeHp6wtPTE/7+/jhw4IDk8EREREREpB8kH7EIDg5GgwYNcOTIEdjb2wMA7t+/jxEjRiA4OBh//PFHhe2///57jB49GoMGDUJwcDAAICEhAd27d0d0dDSGDRtWhd0gXWGfSSIielX4b39To/axARV/RyIydJILi3379qkUFQDg4OCARYsWoXPnzpW2nz9/PpYsWYKpU6cqpwUHByM8PBzz5s1jYUFEREREZIAkd4UyMzNDTk5Oqem5ubmQyWSVtr969SoGDBhQarq/vz+uXbsmNQ4REREREekByUcs+vfvj/HjxyMiIgLt2rUDABw9ehQTJkyAv79/pe1dXV0RFxcHT09Plem7d++Gq6ur1DhEREREatG0+65jq2oKQvSSklxYrFq1CoGBgejYsaPy4njFxcXw9/fHypUrK23/8ccfIzg4GElJSejUqROAJ2MsoqOj1WpPRERERET6R3JhYWdnh19//RWXLl3ChQsXAABNmjQpdQSiPB988AFq166NZcuW4eeff1a237RpE9566y2pcYiIiIiISA9U6ToWAODl5QUvL68qtR04cCAGDhxY1U0TEREREZGeUauwCAkJwbx582BlZYWQkJAKlw0PD69wfv369fH333/DwcFBZXpmZiZee+01XL16VZ1IRERERESkR9QqLBITE1FUVKT8WxMpKSkoKSkpNb2goAC3bt3SaN1ERET6jtf/IaKXlVqFxd69e8v8W4rY2Fjl33/++SdsbW2V90tKShAXFwcPD48qrZuIiIiIiHRL8hiLMWPGYOXKlbCxsVGZnpeXh0mTJiEyMrLMdgEBAQAAQRAQGBioMs/U1BQeHh5YtmyZ1DhERERERKQHJF8gLyYmBvn5+aWm5+fnY8OGDeW2UygUUCgUcHNzQ3p6uvK+QqFAQUEBkpOT0b9/f6lxiIiIiIhID6h9xCI7OxuiKEIUReTk5MDc3Fw5r6SkBDt27ICjo2Ol6+HVtUmfsK8zERERUfVQu7Cws7ODIAgQBAENGzYsNV8QBMyZM6dawxERERERkWFQu7DYu3cvRFFEt27dsGXLFtjb2yvnyWQyuLu7w8XF5YWEJCIioif8t79Z5baxAX9UYxIiIlVqFxa+vr4AnnRlcnNzgyAILywUEb382A3NcGnyxRbgl1siopeV5LNCXb9+HdevXy93fpcuXTQKREREREREhkdyYeHn51dq2rNHL8q6+F12drba65fL5VIjERERERGRjkkuLB4+fKhyv6ioCImJiZg1axbmz59fZpunA7/VUVZhQkRE9BS70RkudqMjerlJLiyevWL2Uz179oRMJkNISAiOHz9eav6zV+tOSUnBp59+iqCgIHTs2BEAcPjwYcTExGDhwoVS45CB44cMGSp+uSUiIlIlubAoj5OTE5KTk8uc93TgNwDMnTsX4eHhGDp0qHKav78/vL298Z///KfUVbmJiIiI6NXGHyINg+TC4tSpUyr3RVFEWloaFi1ahJYtW1ba/vDhw1i3bl2p6W3atMH7778vNQ4RkUHihyQRkeHgUWr1SC4sWrZsCUEQIIqiyvQOHTogMjKy0vaurq5Yv349lixZojL922+/haurq9Q4RDrFL4dERGQI+HlF2iC5sLh27ZrKfSMjI9SqVQvm5uZqtV++fDkGDx6MnTt3on379gCAY8eO4dKlS9iyZYukLPv378eXX36J48ePIy0tDdu2bUNAQICkdRARERERkeYkFxbu7u4abbBfv364ePEi1q5diwsXLgAABgwYgAkTJkg+YpGXl4cWLVpgzJgxGDRokEa5dImH14ik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kz6+jo6OpZa5desWunbtitatWyMqKgpGRpUfRE1KSoKzs7OkvERE2rZo0SK0bNmyVNdVAKhXrx7s7OzUXtfz77lS3rPT09OxceNGBAQEqPUeS6QJFhZEBubrr79G586d0aZNG3z++efw8fGBkZER/v77b1y4cAGtW7dGREQE2rVrhy5dupRq37ZtW0REREjqTpSZmYk7d+5AoVDg0qVLmDt3Lho2bIgmTZrg/v37ePvttzFmzBj4+PjAxsYG//zzD5YsWYK33nqr3HXeunULfn5+cHd3x9KlS5GRkaGcV7t2bQBATEwMZDIZWrVqBQDYunUrIiMj8e2336qdnYhIF7y9vTF8+HCsWrVKctucnBzcuXMHoiji5s2bmD59OmrVqoVOnTpV2E4URWW7zMxMHD58GAsWLICtrW2p62sQvQgsLIgMTIMGDZCYmIgFCxYgNDQUqampMDMzQ9OmTfHJJ59g/PjxqF+/vnIQ9/MGDx6MZcuWYcGCBWpvc/To0QCe9M+tXbs2unTpggULFsDExATW1tZo3749li9fjitXrqCoqAiurq4YN25cmdekeOqvv/7C5cuXcfnyZdStW1dl3tP+wAAwb948XL9+HSYmJmjcuDE2bdqEIUOGqJ2diEhX5s6dW2pcmzpmz56N2bNnAwBq1aqFtm3bYteuXZV2ZcrOzoazszMEQYBcLkejRo0QGBiIyZMnq9VlikhTgvjsJzgREREREVEVsLMdERERERFpjIUFERERERFpjIUFERERERFpjIUFERERERFpjIUFERERERFpjIUFERERERFpjIUFERERERFpjIUFERERERFpjIUFERERERFpjIUFERERERFpjIUFERERERFpjIUFERERERFp7P8AIFyMpvbAIY4AAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_ram['app']\n", - "gap_22_ram = df_gap22_ram['simSeconds'].astype(float)*1000\n", - "gap_22_orc = df_gap22_orc['simSeconds'].astype(float)*1000\n", - "gap_22_noDC = df_gap22_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "\n", - "gap_25_ram = df_gap25_ram['simSeconds'].astype(float)*1000\n", - "gap_25_orc = df_gap25_orc['simSeconds'].astype(float)*1000\n", - "gap_25_noDC = df_gap25_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "\n", - "app_npb = df_npbC_ram['app']\n", - "npb_C_ram = df_npbC_ram['simSeconds'].astype(float)*1000\n", - "npb_C_orc = df_npbC_orc['simSeconds'].astype(float)*1000\n", - "npb_C_noDC = df_npbC_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "npb_D_ram = df_npbD_ram['simSeconds'].astype(float)*1000\n", - "npb_D_orc = df_npbD_orc['simSeconds'].astype(float)*1000\n", - "npb_D_noDC = df_npbD_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "\n", - "# Multi bar Chart1\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,3])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_22_ram[i]/gap_22_noDC[i], width=1, color=cmap(1), label='TDRAM' if i==0 else None)\n", - " plt.bar(i*3+1, gap_22_orc[i]/gap_22_noDC[i], width=1, color=cmap(2), label='Oracle' if i==0 else None)\n", - "\n", - "offset = i*3+2\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_C_ram[i]/npb_C_noDC[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*3+2, npb_C_orc[i]/npb_C_noDC[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()\n", - "\n", - "# Multi bar Chart2\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,3])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_25_ram[i]/gap_25_noDC[i], width=1, color=cmap(1), label='TDRAM' if i==0 else None)\n", - " plt.bar(i*3+1, gap_25_orc[i]/gap_25_noDC[i], width=1, color=cmap(2), label='Oracle' if i==0 else None)\n", - "\n", - "offset = i*3+2\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_D_ram[i]/npb_D_noDC[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*3+2, npb_D_orc[i]/npb_D_noDC[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", - "plt.legend(fontsize=9, ncol=2)\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 71, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAxYAAADSCAYAAADXL1aYAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAABCpElEQVR4nO3deVhUZf8G8HvY1wFBQJBVUZRNTMFdcc+NMK00FxDTrBSVTMJeJTWXTCGXN+01Aa0sM9R4szJFcd8BNbdERcQNRWVT2eb8/vDnvI6sh4FZ7P5cF9fFPOc859wHmGG+c57nHIkgCAJUZN68eTA2NsZHH30EANizZw9effVVmJubIy8vDwkJCRg1apSq4hARERERUT3RUeXOfv75Z3h6esofL1iwAOHh4bh37x5WrVqFhQsXqjIOERERERHVEz1V7GTDhg0QBAGZmZlIT09Hbm4uBEHAwYMH0a1bN2zYsAEymQxXrlzBhg0bAABjx45VRTQiIiIiIqoHKiksXFxcAAAGBgaws7ODi4sL0tPTIZVK0bNnTwiCgOLiYkgkEri6ukKFo7OIiIiIiKgeSFQ5x6Jfv34wMTFBZGQk5s2bhyZNmiA+Ph4AcObMGQwfPhwXL15UVRwiIiIiIqonKi0sTp06hddeew1ZWVlo1aoVduzYAScnJwDAhx9+iLKyMixfvlxVcYiIiIiIqJ6otLB4Jjc3F9bW1gptt27dglQqhampqarjEBERERGRktRSWDyTnZ0NBwcH6Oio9OJURERERERUz9T6jt7T0xOZmZnqjEBERERERPVArYUFr/5ERERERPRy4BgkIiIiIiJSmloLi1mzZsHKyqrO/VevXg1fX19IpVJIpVJ06tQJv//+ez0mJCIiIiKi2lDr5G1l/fe//4Wuri5atGgBQRCwfv16fPHFF0hLS4OXl5e64xERERER/WOorLCYN29erdabM2eOUvuxsrLCF198gfHjxyu1HSIiIiIiqj2VFRY6OjpwcHCAra1tlZO2JRIJUlNT67T98vJybN68GSEhIUhLS4Onp6cycYmIiIiISAQ9Ve1owIAB2L17N9q3b4+wsDAMHjy4Xu5fcebMGXTq1AlPnjyBmZkZtm7dWmVRUVxcjOLiYvljmUyG+/fvw9raGhKJROksREREREQvE0EQUFBQUKt7z6l0jsXNmzexfv16JCQkID8/H2PHjkVYWBg8PDzqvM2SkhJkZWUhLy8PP//8M7755hvs3bu30uLi008/xdy5c5U5BCIiIiKif5zr16/D0dGx2nXUNnl73759iI+PR2JiInx8fLBr1y4YGxsrvd0+ffqgefPm+Prrrysse/GMRV5eHpydnXH9+nVIpVKl901EpG5FRUVwcHAA8PTDHFNTUzUnIiIibZafnw8nJyc8fPgQFhYW1a6rsqFQL/L390dmZibOnTuHtLQ0lJaW1kthIZPJFIqH5xkaGsLQ0LBC+7PL1RIRaTtdXV3591KplIUFERHVi9pMG1B5YXH48GHExcXhp59+QsuWLTFu3Di8/fbbdXpjHxUVhQEDBsDZ2RkFBQXYuHEjUlJSsGPHjgZITkREREREVVFZYbFkyRIkJCTg3r17GDVqFPbv3w9fX1+ltpmTk4OxY8fi1q1bsLCwgK+vL3bs2IG+ffvWS+by8nKUlpbWy7ZIvfT19RU+ySUiIiKi+qXSy806Oztj8ODBMDAwqHK9mJgYVcQB8HTMmIWFBfLy8iqcMSksLER2dnaVl8Yl7SKRSODo6AgzMzN1RyFqUEVFRfK/88LCQg6FIiIipVT3fvlFKjtj0b17d0gkEpw9e1ZVu6yz8vJyZGdnw8TEBDY2NrwUrZYTBAF3795FdnY2WrRowTMXRERERA1AZYVFSkqKqnaltNLSUgiCABsbm3qZUE7qZ2Njg8zMTJSWlrKwICIiImoAyt+hrp6cP38eM2bMUHcMBTxT8fLg75KIiIioYam1sCgqKsK6devQuXNneHl54Y8//lBnHCIiIiIiqiO13Mfi4MGDWLduHX766Sc8fvwY06dPR1xcHFq1aqWOOLXSMbrhLmF7ZG7/GtcpKyvDggUL8MMPP0BPTw96enoICAjAkiVLYGlp2WDZqjNjxgyYmZnh008/FdVPIpHgwYMHonLXpQ8RERERqY7Kzljk5ORgyZIlaNWqFYYPHw5LS0ukpKRAR0cHYWFhGl1UaILx48fjxIkTOHz4MP766y+kpaWhb9++uH//vrqjERERERGprrBwcXHBmTNnsHz5cty4cQMxMTFo3769qnav1TIyMrB582bEx8ejUaNGAJ5+gv/GG2+gWbNmuH37Nnr27Il27drBy8sLkydPhkwmAwAcOXIE7dq1g5+fH7y9vbF69WoAQF5eHt555x14e3ujTZs2CAsLAwAkJyejU6dOaNu2Lby8vLBu3Tp5jlu3bqF///7w9PREnz59kJ2dLV9WWlqKjz/+GAEBAfDz88Obb76JBw8eiDrOGTNmwN/fH35+fujevTsuXrxYYR1BEBAZGYmgoCA8evQIly5dwqBBg+Dv7w9fX1+sWrVK3A+XiIiIiOqFyoZCubi44MCBA3B2doaLiwvPUIiQmpqKFi1aoHHjxpUut7S0xH//+1+YmZmhvLwcr732Gn766SeMGDECixYtwowZMzBy5EgAkL/ZnzZtGoyNjXH69Gno6Ojg7t27AIBXXnkFBw4cgK6uLu7fv4+2bduif//+cHR0RHh4OAICArBjxw7cuHEDfn5+8t/jF198AVNTUxw7dgwAMH/+fPzrX//Cv//971ofZ2RkJJYuXQoA+PHHHzF16lSFeTfFxcUYOXIkrK2tsXXrVgDAyJEj8d1336FVq1Z49OgROnbsiA4dOsDf31/Mj5iIiIiIlKSywuLChQvyuRX+/v5o2bIlRo8eDYBX7FGWTCZDZGQkDhw4AEEQkJOTA29vb4wYMQI9e/bE/PnzcenSJfTq1Qtdu3YFAPz66684evQodHSenrSysbEBAOTm5mL8+PH4+++/oaenh9zcXPz1119wdHREcnKy/I1/06ZNERQUJM+wbds25OXlITExEQBQUlICV1dXUcexc+dOrFy5EgUFBZDJZBWGeQ0aNAivvfYaZs+eDQA4d+4czp49ixEjRsjXKSgowLlz51hYEBEREamYSidvd+nSBV26dMGKFSvwww8/ID4+HuXl5Xj//ffx9ttvIzg4WP4Gl/7nlVdewaVLl5Cbmwtra+sKy2NiYpCTk4OjR4/CyMgIERERePLkCYCnZyZee+017Nq1C7NmzYK3tze++uqrKvc1adIkDBw4EImJiZBIJHjllVfk23rR8wWhIAhYuXIl+vXrV6djzMrKwuTJk3H8+HE0b94cp0+fRvfu3RXW6dWrF3bu3ImpU6dCKpVCEARYWVkhPT29TvskIiIiovqjlsvNmpmZYcKECTh06BDOnj2Ldu3a4V//+hccHBzUEUfjubu7Y9iwYRg/fjwePnwI4Okb+cTERFy5cgUPHjxAkyZNYGRkhNu3b2Pz5s3yvhcvXoSbmxsmTJiAWbNm4ciRIwCAoKAgLF26VD4X49lQqAcPHsDFxQUSiQT79u3DqVOn5Nvq06cP4uLiADydb5GUlCRfFhwcjNjYWDx69AgA8OjRI1F3Wc/Ly4O+vj7s7e0hCEKlcyVmzZqF119/HX369EFubi48PDwglUoRHx8vXycjI4MT2omIiIjUQC2Xm31e69atsXTpUixevBgxMTHqjqOx4uLi8Nlnn6FDhw7Q09ODTCZD9+7d0bt3b0ydOhXDhw+Hl5cXHBwc0KdPH3m/VatWYffu3TAwMICuri6WLVsGAIiNjcX06dPh4+MDfX19+Pv7Y+3atVi8eDHef/99zJ8/H35+fujQoYN8W8uXL0doaCg8PT3RtGlT9OrVS74sMjISxcXF6NChg/xMRmRkJLy8vCo9Hi8vL4UzHtnZ2RgxYgS8vLxgbW2N4ODgSvtNmzYNpqam6NWrF3bs2IFff/0V06ZNQ2xsLMrLy9G4cWNs3Lixzj9nIiIiIqobiSAIgip3WFhYCF1dXRgbG8vb0tPTMWfOHGzfvh3l5eUqy5Kfnw8LCwvk5eVBKpXK2588eYKrV6/Czc0NRkZGKstDDYe/U/qnKCoqgpmZGYCnr7empqZqTkRERNqsqvfLlanzUKiSkhJcvHgRZWVltVr/+vXr6NSpEywsLGBhYYGIiAg8evQIY8eORYcOHWBiYoJDhw7VNQ4REREREamR6MLi0aNHGD9+PExMTODl5YWsrCwAwJQpU7B48eIq+3300Ud48uQJli9fjq5du2L58uXo0aMHpFIpLl++jB9//FFh2A0REREREWkP0YVFVFQUTp06hZSUFIUhJX369MGmTZuq7Ldv3z6sXr0akydPxo8//ghBEDBq1CisWrUKjo6OdUtPREREREQaQfTk7W3btmHTpk3o2LGjwuRbLy8vXL58ucp+d+7cgZubGwDA1tYWJiYmGDBgQB0iExERERGRphF9xuLu3buwtbWt0F5UVFTjje6e3Yzt2fcGBgZid09ERERERBpIdGHRvn17bN++Xf74WTHxzTffoFOnTlX2EwQBLVu2hJWVFaysrFBYWIi2bdvKHz/7IiIiIiIi7SN6KNTChQsxYMAAnDt3DmVlZVi+fDnOnTuHQ4cOYe/evVX2e/4mZtooaNugBtt2UvD2apf7+fkB+N+VuHx8fAAAHh4e+Pzzz9G8eXP4+PigvLwcpaWl6NatG6Kjo+VzV0JDQ7Fz507Y2NjgyZMn8Pf3x9dffw0TExP5PqKjo/HZZ5/hypUrcHFxkbcHBgbi0KFDyM7Olp+punLlCtzd3REUFIRt27bV40+CiIiIiLSV6MKia9euSE9Px+LFi+Hj44M///wTr7zyCg4fPix/w1uZkJAQpYL+k6WnpwMAMjMz4efnJ3/8rM3c3FzeVlJSgs8++wydO3fGmTNnYGFhAeDpVbmmTZuG4uJi9OrVC6tWrcLMmTMBADKZDAkJCQgMDER8fDw+/fRThf37+vri22+/xYcffgjg6c362rVr16DHTERERPVH2Q9Ia/oQlAio430smjdvjrVr1+LYsWM4d+4cvvvuu2qLiucJgoATJ07g559/RmJiIlJTU6Hie/S91AwMDDBv3jw0bdoU3333XYXlhoaG6Nq1K65duyZv27lzJ+zs7LB06VLEx8dDJpMp9AkJCcH69esBPC1CNm3ahLfffrthD4SIiIiItIroMxbP5OTkICcnp8KbUF9f3yr77NmzB+PHj8e1a9fkxYREIoGbmxvi4uLQvXv3usahFwQEBODs2bMV2vPy8pCSkoJFixbJ29atW4ewsDC0bdsW1tbW2LVrF/r16ydf7uTkhCZNmuDo0aN48OAB2rdvj0aNGqnkOIiIiIhIO4g+Y3Hy5El4e3vD3t4evr6+8PPzk3+1bdu2yn4ZGRkYPHgwXF1dsWXLFpw/fx7nzp3D5s2b4ejoiIEDB+LKlStKHQz9z4tngb744gv4+vrCzs4Ojo6O6NmzJwAgNzcXf/75J0aOHAkACAsLw7p16yps71n7syKEiIiIiOh5os9YhIWFoWXLlli3bh3s7OxqvMTsM19++SU6duyI5ORkhfZWrVph6NCh6NOnD2JjY7Fy5UqxkagSx48fx5gxY+SPn82xyMrKQrdu3bBmzRq89957+Pbbb1FWVoY2bdoAAMrLy5Gbm4vc3FxYW1vL+wcHByMyMhKGhobo3bs3NmzYoPJjIiIiIiLNJbqwuHLlChITE+Hu7i6q34vDb54nkUgwbdo0REVFiY1DLygpKcGiRYuQnZ2NUaNGVVju7OyMlStX4t1330VoaCjWrVuHn3/+Ga+++qp8nbfeegvfffcdpk6dKm8zMjJCbGwsTExMFO5HQkREREQE1GEoVO/evXHq1CnRO8rKyqp2gre3t7fChGKqvYKCAvj5+cHb2xs+Pj64fv06Dh06JL8i1IuCgoLQqlUrrFixAjk5OejTp4/C8lGjRlU6HOr1119XKECIiIiIiJ6RCCIvyXTv3j2EhIQgICAA3t7e0NfXV1geFBRUaT8dHR3cvn270rt2A8CdO3fg4OCA8vJyMXGUkp+fDwsLC+Tl5UEqlcrbnzx5gqtXr8LNzQ1GRkYqy0MNh79T+qcoKiqCmZkZAKCwsBCmpqZqTkREmoCXm6W6qur9cmVED4U6fPgwDh48iN9//73CMolEUm1hcO7cOdy+fbvSZffu3RMbhYiIiIiINITowmLKlCkYPXo0Zs+eDTs7O1F9e/fuXek9KyQSCQRBqPVEcCIiIiLSHh2jdyjV/8jc/vWUhBqS6MIiNzcX06dPF11UXL16VeyuiIiogSjzT57/4ImIqDKiC4vXX38de/bsQfPmzUX1c3FxEbsrteMdwV8e/F0SERE/NSdqWKILi5YtWyIqKgoHDhyAj49Phcnb4eHhtd6Wj48PfvvtNzg5OYmN0aB0dXUBPL10q7GxsZrTUH0oKSkB8L/fLRERERHVL9GFxTfffAMzMzPs3bsXe/fuVVgmkUhEFRaZmZkoLS0VG6HB6enpwcTEBHfv3oW+vj7v26DlZDIZ7t69CxMTE+jpif6TJyKi/8dP/ImoOqLfZf0T5kpIJBLY29vj6tWrvLfGS0JHRwfOzs68QAAREWktZQo727b1GISoCmr9+LZbt24aO9TIwMAALVq0kA+hIe1mYGDAM09EREREDahWhUVERATmz58PU1NTREREVLtuTExMrXf+22+/1XrdyixatAhbtmzBhQsXYGxsjM6dO+Pzzz+Hh4eHUtt9RkdHhzdTIyIiIiKqhVoVFmlpafK5EGlpaUrvtLy8HNu2bcP58+cBAF5eXggKChI9sXbv3r344IMP4O/vj7KyMsyaNQv9+vXDuXPneLdZIiIiIiIVqlVhsWfPnkq/r4uMjAwMGjQI2dnZ8jMLixYtgpOTE7Zv3y7qMrZ//PGHwuOEhATY2tri5MmT6N69u1I5iYiIiIio9kQPOg8LC0NBQUGF9qKiIoSFhdXYPzw8HM2aNcP169eRmpqK1NRUZGVlwc3NTdQVpSqTl5cHALCysqp0eXFxMfLz8xW+iIiIiIhIeaILi/Xr1+Px48cV2h8/fowNGzbU2H/v3r1YsmSJwpt/a2trLF68uMLla8WQyWSYNm0aunTpAm9v70rXWbRoESwsLORfmnb/DCIiIiIibVXrq0Ll5+dDEAQIgoCCggKFSc3l5eX47bffYGtrW+N2DA0NKz3jUVhYCAMDg9rGqeCDDz7AX3/9hQMHDlS5TlRUlMLk8/z8fBYXREREKhK0bZBS/ZOCt9dTEiJqCLUuLCwtLSGRSCCRSNCyZcsKyyUSCebOnVvjdgYPHoyJEydi3bp1CAgIAAAcPXoUkyZNQlBQkIjo/zN58mT8+uuv2LdvHxwdHatcz9DQEIaGhnXaBxERERERVa3WhcWePXsgCAJ69eqFxMREhaFMBgYGcHFxgYODQ43bWbFiBUJCQtCpUyfo6+sDAMrKyhAUFITly5eLCi8IAqZMmYKtW7ciJSUFbm5uovoTERGpGu9eTUQvq1oXFj169ADw9M7bytzB2NLSEr/88gsuXbqECxcuAABat24Nd3d30dv64IMPsHHjRvzyyy8wNzfH7du3AQAWFhYae+M9IiIiIqKXkeg7b7u4uNTLjlu0aIEWLVootY3Vq1cDAAIDAxXa4+PjERoaqtS2iYiIiIio9kQXFsoqLy9HQkICkpOTkZOTA5lMprB89+7dtd6WIAj1HY+IiIiIiOpA5YXF1KlTkZCQgEGDBsHb27vOQ6qIiIiIiEhzqLyw+PHHH/HTTz9h4MCBqt41ERERERE1EJUXFgYGBnWaqE2aiVc3ISIiIiKgDnfevnPnDsaMGQMHBwfo6elBV1dX4asmH374IZYvX875EURERERELxHRZyxCQ0ORlZWF2bNnw97eXvQciQMHDmDPnj34/fff4eXlJb+XxTNbtmwRG4mIiIiIiNRMdGFx4MAB7N+/H35+fnXaoaWlJYYOHVqnvkREREREpJlEFxZOTk5KDWOKj4+vc18iIiIiItJMoudYfPnll/j444+RmZnZAHGIiIiIiEgbiT5j8dZbb+HRo0do3rw5TExMKsyRuH//fr2FIyIizRO0bZBS/ZOCt9dTEiIi0iSiC4svv/yyAWIQEREREVWOH2hoB9GFRUhISEPkICIiIiIiLVanG+SVl5dj27ZtOH/+PADAy8sLQUFBtbqPBZEm4Q3+iIiIiOqH6MIiIyMDAwcOxI0bN+Dh4QEAWLRoEZycnLB9+3Y0b968xm3s3bsXS5culRcmnp6e+Oijj9CtWzexcYiI1IJFKRERkSLRhUV4eDiaN2+OI0eOwMrKCgCQm5uL0aNHIzw8HNu3Vz+G7bvvvsO4cePw+uuvIzw8HABw8OBB9O7dGwkJCXj77bfrcBja7Z/8BoVjJomIiIheDqILi7179yoUFQBgbW2NxYsXo0uXLjX2X7BgAZYsWYLp06fL28LDwxETE4P58+f/IwsLIiIiIiJtJ/o+FoaGhigoKKjQXlhYCAMDgxr7X7lyBUOGDKnQHhQUhKtXr4qNQ0REREREGkD0GYvBgwdj4sSJWLduHQICAgAAR48exaRJkxAUFFRjfycnJyQnJ8Pd3V2hfdeuXXBychIbh4iIiEglOHyXqHqiC4sVK1YgJCQEnTp1kt8cr6ysDEFBQVi+fHmN/T/88EOEh4cjPT0dnTt3BvB0jkVCQkKt+hMRERERkeYRXVhYWlril19+waVLl3DhwgUAQOvWrSucgajKe++9hyZNmmDZsmX46aef5P03bdqE1157TWwcIiIiIiLSAHW6jwUAtGjRAi1atKhT36FDh2Lo0KF13TUREREREWmYWhUWERERmD9/PkxNTREREVHtujExMdUub9asGY4fPw5ra2uF9ocPH+KVV17BlStXahOJiIiIiIg0SK0Ki7S0NJSWlsq/V0ZmZibKy8srtBcXF+PGjRtKbZuItMc/+f4tRMpQZgIxJw8TUUOqVWGxZ8+eSr8XIykpSf79jh07YGFhIX9cXl6O5ORkuLq61mnbRERERESkXqLnWISFhWH58uUwNzdXaC8qKsKUKVMQFxdXab/g4GAAgEQiQUhIiMIyfX19uLq6YtmyZWLjEBERERGRBhBdWKxfvx6LFy+uUFg8fvwYGzZsqLKwkMlkAAA3NzccP34cjRs3rkNcIiIiIiLV4vDd2ql1YZGfnw9BECAIAgoKCmBkZCRfVl5ejt9++w22trY1bod316aXCW+WRERERPRUrQsLS0tLSCQSSCQStGzZssJyiUSCuXPn1ms4IiIiIiLSDrUuLPbs2QNBENCrVy8kJibCyspKvszAwAAuLi5wcHBokJBERERERKTZal1Y9OjRA8DToUzOzs6QSCQNFoqIqCYchkZERKRZRE/evnbtGq5du1bl8u7duysViIiIiIiItI/owiIwMLBC2/NnLyq7+V1+fn6tty+VSsVGIiKifxBenYWISDOJLiwePHig8Li0tBRpaWmYPXs2FixYUGmfZxO/a6OywoSIiKi+cBgdEVHDEF1YPH/H7Gf69u0LAwMDRERE4OTJkxWWP3+37szMTHz88ccIDQ1Fp06dAACHDx/G+vXrsWjRIrFxiIi0Et/cEhHRy0Z0YVEVOzs7XLx4sdJlzyZ+A8C8efMQExODkSNHytuCgoLg4+OD//znPxXuyk1ERERERJpPdGFx+vRphceCIODWrVtYvHgx/Pz8aux/+PBhrFmzpkJ7+/bt8c4774iNQ0RERESk0ZQ5S61NZ6hFFxZ+fn6QSCQQBEGhvWPHjoiLi6uxv5OTE9auXYslS5YotH/zzTdwcnISG4eIiIiIiDSA6MLi6tWrCo91dHRgY2MDIyOjWvWPjY3FsGHD8Pvvv6NDhw4AgGPHjuHSpUtITEwUlWXfvn344osvcPLkSdy6dQtbt25FcHCwqG0QEREREZHyRBcWLi4uSu1w4MCB+Pvvv7F69WpcuHABADBkyBBMmjRJ9BmLoqIitGnTBmFhYXj99deVyqXNOAmUiIiIiNRNdGERHh4Od3d3hIeHK7SvWrUKGRkZ+PLLL2vchpOTExYuXCh21xUMGDAAAwYMUHo7JSUlKCkpUXo7daUL5S6xq1Ouo1R/ZY5dm7MD2p9fm2n7z15T85eUlEBfX7/C9y9SJj9/9tqbX5uzA8zP523daXN+db9XELN/ifDiZIkaNG3aFElJSWjXrp1Ce2pqKoKCgpCdnV3jNvbv34+vv/4aV65cwebNm9G0aVN8++23cHNzQ9euXcXEkZNIJDUOhSouLkZxcbH8cX5+PpycnPDxxx/XeigXEREREdE/xZMnT7B48WLk5eXVeCNr0eVTbm5upfeykEqluHfvXo39ExMT0b9/fxgbGyM1NVX+Rj8vL69ezmJUZ9GiRbCwsJB/cbI4EREREVH9EH3GwtvbG5MmTcLkyZMV2leuXInVq1fj3Llz1fZv27Ytpk+fjrFjx8Lc3BynTp1Cs2bNkJaWhgEDBuD27dvijwLKnbG4e/dujRVYQ+q5YJdS/W18VyvV/6ch4ibNP0+bswPan1+bafvPXlPzFxUVwc7ODgBw584dmJqaVrqeMvn5s9fe/NqcHWB+Pm/rTpvzq/u9Qn5+PmxsbGp1xkL0HIuIiAhMnjwZd+/eRa9evQAAycnJWLZsWa3mV1y8eBHdu3ev0G5hYYGHDx+KjSOKoaEhDA0NK7QbGBjAwMCgQfddnXLoKtVfpitTqr8yx67N2QHtz6/NtP1nr6n5S0tLUVpaKl+nqvWUyc+fvfbm1+bsAPPzeVt32pxf3e8VxOxfdGERFhaG4uJiLFiwAPPnzwcAuLq6YvXq1Rg7dmyN/Zs0aYKMjAy4uroqtB84cADNmjUTG4eIiIiIiDSA6MICAN577z289957uHv3LoyNjWFmZlbrvhMmTMDUqVMRFxcHiUSCmzdv4vDhw5gxYwZmz54tKkdhYSEyMjLkj69evYr09HRYWVnB2dlZ1LaIiIiIiKju6lRYlJWVISUlBZcvX8bbb78NALh58yakUmmNRcbHH38MmUyG3r1749GjR+jevTsMDQ0xY8YMTJkyRVSOEydOoGfPnvLHERERAICQkBAkJCSIOygiLdQxeodS/Y/M7V9PSYiIiOifTnRhce3aNbz66qvIyspCcXEx+vbtC3Nzc3z++ecoLi7GmjVrqu0vkUjwySef4KOPPkJGRgYKCwvh6ekp6qzHM4GBgRA595yInqPMzRV5Y0UiIiJ6nujLzU6dOhXt27fHgwcPYGxsLG8fOnQokpOTa+y/YcMGnD9/HgYGBvD09ERAQADMzMzw5MkTbNiwQWwcIiIiIiLSAKILi/379+Nf//pXhRnirq6uuHHjRo39Q0NDERAQgMRExUtn5eXlYdy4cWLjEBERERGRBhBdWMhkMpSXV7yteXZ2NszNzWu1jblz52LMmDH49NNPxe6eiIiIiIg0kOjCol+/fgr3q5BIJCgsLER0dDQGDhxYq22MHj0au3fvxtdff43hw4fj8ePHYmMQEREREZEGEV1YLFu2DAcPHoSnpyeePHmCt99+Wz4M6vPPP6+xv0QiAQB07NgRR48eRUZGBjp37ozMzEzR4YmIiIiISDOIviqUo6MjTp06hU2bNuHUqVMoLCzE+PHjMWrUKIXJ3FV5/ipOzs7OOHToEEaNGoW+ffuKjUJERERERBpCdGFx9+5d2NjYYNSoURg1apTCsjNnzsDHx6fa/tHR0QqXljUxMcHWrVsRHR2Nffv2iY1DREREREQaQPRQKB8fH2zfXvH69UuXLkVAQECN/aOjo2FiYlKhfe7cudizZ4/YOEREREREpAFEn7GIiIjAsGHDMG7cOMTExOD+/fsYO3Yszpw5g40bN1baJykpCQMGDIC+vj6SkpKq3LZEIsGQIUPERiIiIiIiIjUTXVjMnDkTffv2xZgxY+Dr64v79++jQ4cOOH36NJo0aVJpn+DgYNy+fRu2trYIDg6uctsSiaTSS9kSEREREZFmEz0UCgDc3d3h7e2NzMxM5Ofn46233qqyqACe3vvC1tZW/n1VXywqiIiIiIi0k+jC4uDBg/D19cWlS5dw+vRprF69GlOmTMFbb72FBw8eNERGIiIiIiLScKKHQvXq1QvTp0/H/Pnzoa+vj9atW6Nnz54YPXo0fHx8kJ2dXaHPihUrar398PBwsZGIiIiIiEjNRBcWf/75J3r06KHQ1rx5cxw8eBALFiyotE9sbGytti2RSFhYEBERERFpIdGFxYtFxTM6OjqYPXt2pcuuXr0qdjdERERERKRFaj3HYuDAgcjLy5M/Xrx4MR4+fCh/nJubC09Pz3oNR0RERERE2qHWZyx27NiB4uJi+eOFCxfizTffhKWlJQCgrKwMFy9erNW2srOzkZSUhKysLJSUlCgsi4mJqW0kIiIiIiLSELUuLARBqPZxbSUnJyMoKAjNmjXDhQsX5JetFQQBr7zySp22SURERERE6lWn+1goIyoqCjNmzMCZM2dgZGSExMREXL9+HT169MAbb7yh6jhERERERFQPal1YSCQSSCSSCm1inT9/HmPHjgUA6Onp4fHjxzAzM8O8efPw+eefi94eERERERGpn6ihUKGhoTA0NAQAPHnyBJMmTYKpqSkAKMy/qI6pqal8XoW9vT0uX74MLy8vAMC9e/dEhSciIiIiIs1Q68IiJCRE4fHo0aMrrPPsTER1OnbsiAMHDqB169YYOHAgPvzwQ5w5cwZbtmxBx44daxuHiIiIiIg0SK0Li/j4+HrZYUxMDAoLCwEAc+fORWFhITZt2oQWLVrwilBERERERFpK9A3ylNWsWTP596amplizZo2qIxARERERUT1TeWHxvMLCQshkMoU2qVSqpjRERERERFRXKr/c7NWrVzFo0CCYmprCwsICjRo1QqNGjWBpaYlGjRqpOg4REREREdUDlZ+xGD16NARBQFxcHOzs7Op0yVoiIiIiItIsKi8sTp06hZMnT8LDw0PVuyYiIiIiogai8qFQ/v7+uH79uqp3S0REREREDUjlZyy++eYbTJo0CTdu3IC3tzf09fUVlvv6+qo6EhERERERKUnlhcXdu3dx+fJljBs3Tt4mkUggCAIkEgnKy8tVHYmIiIiIiJSk8sIiLCwMbdu2xQ8//MDJ20RERERELwmVFxbXrl1DUlIS3N3dVb1rIiIiIiJqICqfvN2rVy+cOnVK1bslIiIiIqIGpPIzFkOGDMH06dNx5swZ+Pj4VJi8HRQUpOpIRERERESkJJUXFpMmTQIAzJs3r8IyTt4mIiIiItJOKh8KJZPJqvyqa1Hx73//G66urjAyMkKHDh1w7Nixek5NRERERETVUWlhUVpaCj09Pfz111/1ts1NmzYhIiIC0dHRSE1NRZs2bdC/f3/k5OTU2z6IiIiIiKh6Ki0s9PX14ezsXK/DnWJiYjBhwgSMGzcOnp6eWLNmDUxMTBAXF1dv+yAiIiIiouqpfI7FJ598glmzZuHbb7+FlZWVUtsqKSnByZMnERUVJW/T0dFBnz59cPjw4QrrFxcXo7i4WP44Ly8PAJCfn69UDmWVFRcp1b/0UalS/ZU5fm3ODjC/Mvm1OTvw8uYvKipSWKeqD3KUyc+fvfbm1+bsAPPzeVt32pxf3e9Tn+1fEIQa11V5YbFq1SpkZGTAwcEBLi4uMDU1VViemppa623du3cP5eXlsLOzU2i3s7PDhQsXKqy/aNEizJ07t0K7k5NTrff5MrKAhboj1Jk2Zwe0O782Zwf+GfkdHBxUkES8f8LPXlNpc3aA+dVJm7MD2p1fU7IXFBTAwqL6LCovLIKDg1W9S7moqChERETIH8tkMty/fx/W1tZaewfw/Px8ODk54fr165BKpeqOI4o2ZweYX520OTug3fm1OTvA/OqkzdkB7c6vzdkB5lc3QRBQUFBQqw+rVF5YREdH19u2GjduDF1dXdy5c0eh/c6dO2jSpEmF9Q0NDWFoaKjQZmlpWW951EkqlWrlHyug3dkB5lcnbc4OaHd+bc4OML86aXN2QLvza3N2gPnVqaYzFc+o/HKzz5w8eRLfffcdvvvuO6SlpdVpGwYGBmjXrh2Sk5PlbTKZDMnJyejUqVN9RSUiIiIiohqo/IxFTk4ORowYgZSUFPnZgocPH6Jnz5748ccfYWNjI2p7ERERCAkJQfv27REQEIAvv/wSRUVFGDduXAOkJyIiIiKiyqj8jMWUKVNQUFCAs2fP4v79+7h//z7++usv5OfnIzw8XPT23nrrLSxduhRz5syBn58f0tPT8ccff1SY0P2yMjQ0RHR0dIUhXtpAm7MDzK9O2pwd0O782pwdYH510ubsgHbn1+bsAPNrE4lQm2tH1SMLCwvs2rUL/v7+Cu3Hjh1Dv3798PDhQ1XGISIiIiKieqDyMxYymQz6+voV2vX19SGTyVQdh4iIiIiI6oHKC4tevXph6tSpuHnzprztxo0bmD59Onr37q3qOEREREREVA9UPhTq+vXrCAoKwtmzZ+U3prt+/Tq8vb2RlJQER0dHVcYhIiIiIqJ6oPIzFk5OTkhNTcX27dsxbdo0TJs2Db/99htSU1NZVFQjMDAQ06ZNU3cMUWrK/OjRIwwbNgxSqRQSiYTza4g0jDa+7ryMBEHAxIkTYWVlBYlEgvT0dHVHqjVt/hvS5uxE6qLyy80CgEQiQd++fdG3b1917J40xPr167F//34cOnQIjRs3rvXNV4i0TWBgIPz8/PDll1+qO0q9cnV1lX9ARA3njz/+QEJCAlJSUtCsWTPY29tj69atCA4OVne0Gm3ZsqXSeZVE9HJSS2GRnJyM5ORk5OTkVJiwHRcXp45IpAaXL19G69at4e3tre4o9JySkhIYGBioOwYR/b/Lly/D3t4enTt3VncU0aysrNQdgYhUSOVDoebOnYt+/fohOTkZ9+7dw4MHDxS+qGplZWWYPHkyLCws0LhxY8yePRvPpsgUFxcjMjISTk5OMDQ0hLu7O9atW6fmxFVnDgwMxLJly7Bv3z5IJBIEBgYCAL766iu0aNECRkZGsLOzw/Dhw9V7AP9PJpNhyZIlcHd3h6GhIZydnbFgwQIAQHZ2NkaOHAkrKyuYmpqiffv2OHr0qJoT/09gYCAmT55c5d+Oq6sr5s+fj7Fjx0IqlWLixIkqz/jzzz/Dx8cHxsbGsLa2Rp8+fVBUVISUlBQEBATA1NQUlpaW6NKlC65duwYAOHXqFHr27Alzc3NIpVK0a9cOJ06cAAAkJCTA0tIS27Ztk/899e/fH9evX1f5sYWGhmLv3r1Yvnw5JBIJJBIJMjMzcfbsWQwePBhSqRTm5ubo1q0bLl++rPJ8NanuOXzt2jVMnz5dflyapLrn7KFDh+Dn5wcjIyO0b98e27Zt09ghRqGhoZgyZQqysrIgkUjg6uoKABg6dKjCY031/HAiTX19rw2JRIJt27YptFlaWiIhIUEteZ4XGBiIKVOmYNq0aWjUqBHs7Oywdu1a+c2Czc3N4e7ujt9//13eJykpSf676NmzJ9avX68xQ5Kr+n8QGhqK4OBgzJ07FzY2NpBKpZg0aRJKSkrUHRnA0/+lL56V9vPzw6effgoAiImJgY+PD0xNTeHk5IT3338fhYWFqg/awFR+xmLNmjVISEjAmDFjVL1rrbd+/XqMHz8ex44dw4kTJzBx4kQ4OztjwoQJGDt2LA4fPowVK1agTZs2uHr1Ku7du6fuyFVm3rJlCz7++GP89ddf2LJlCwwMDHDixAmEh4fj22+/RefOnXH//n3s379f3YcAAIiKisLatWsRGxuLrl274tatW7hw4QIKCwvRo0cPNG3aFElJSWjSpAlSU1M17tLJ1f3tAJDfZDI6Olrl2W7duoWRI0diyZIlGDp0KAoKCrB//34IgoDg4GBMmDABP/zwA0pKSnDs2DH5G9hRo0ahbdu2WL16NXR1dZGenq4w5OLRo0dYsGABNmzYAAMDA7z//vsYMWIEDh48qNLjW758Of7++294e3tj3rx5AIDy8nJ0794dgYGB2L17N6RSKQ4ePIiysjKVZquN6p7Dbdq0wcSJE+V/R5qkqudsfn4+hgwZgoEDB2Ljxo24du2aRg/lWr58OZo3b47//Oc/OH78OHR1dWFra4v4+Hi8+uqr0NXVVXfEWtHk1/eXwfr16zFz5kwcO3YMmzZtwnvvvYetW7di6NChmDVrFmJjYzFmzBhkZWXhzp07GD58OKZOnYp33nkHaWlpmDFjhroPAUD1/w+ApyNejIyMkJKSgszMTIwbNw7W1tbyDw00mY6ODlasWAE3NzdcuXIF77//PmbOnImvvvpK3dHql6BiVlZWQkZGhqp3q/V69OghtG7dWpDJZPK2yMhIoXXr1sLFixcFAMLOnTvVmLCi6jILgiBMnTpV6NGjh3xZYmKiIJVKhfz8fFVHrVZ+fr5gaGgorF27tsKyr7/+WjA3Nxdyc3PVkKx2avo9uLi4CMHBweqKJ5w8eVIAIGRmZiq05+bmCgCElJSUSvuZm5sLCQkJlS6Lj48XAAhHjhyRt50/f14AIBw9erT+wtdSjx49hKlTp8ofR0VFCW5ubkJJSYnKs4hRm7+d2NhYNaWrWnXP2dWrVwvW1tbC48eP5W1r164VAAhpaWkqTFl7sbGxgouLi/wxAGHr1q1qyyPGs799TX19r87zz9vKfuYWFhZCfHy8ynO9qEePHkLXrl3lj8vKygRTU1NhzJgx8rZbt24JAITDhw8LkZGRgre3t8I2PvnkEwGA8ODBA1XFrlRV/w8EQRBCQkIEKysroaioSN62evVqwczMTCgvL1dlzEpV9nrYpk0bITo6utL1N2/eLFhbWzd8MBVT+VCod955Bxs3blT1bl8KHTt2VBhu0KlTJ1y6dAlpaWnQ1dVFjx491JiuclVlLi8vr7Bu37594eLigmbNmmHMmDH4/vvv8ejRI1XGrdT58+dRXFxc6X1W0tPT0bZtW40fR1zT76F9+/bqioY2bdqgd+/e8PHxwRtvvIG1a9fiwYMHsLKyQmhoKPr3748hQ4Zg+fLluHXrlrxfREQE3nnnHfTp0weLFy+uMIxIT08P/v7+8setWrWCpaUlzp8/r7Jjq0p6ejq6deumFZNaxTyHNUV1z9mLFy/C19cXRkZG8raAgABVxvtH0tTX95eFr6+v/HtdXV1YW1vDx8dH3mZnZwcAyMnJwcWLFxVeGwHNeQ5U9f/g+eUmJibyx506dUJhYaFahrmKtWvXLvTu3RtNmzaFubk5xowZg9zc3JfueaDywuLJkyeIiYlBjx49MGXKFERERCh8kXjP/4PUZubm5khNTcUPP/wAe3t7zJkzB23atFH7mE9jY+M6LdMmpqamatu3rq4udu7cid9//x2enp5YuXIlPDw8cPXqVcTHx+Pw4cPo3LkzNm3ahJYtW+LIkSMAgE8//RRnz57FoEGDsHv3bnh6emLr1q1qOw4xXpa/G03Fn6/m0dTX99qSSCTy4TjPlJaWqilNRS9+SCGRSBTann04oGnDdF9U3f8DTaejo1Pl30hmZiYGDx4MX19fJCYm4uTJk/j3v/8NABozR6S+qLywOH36NPz8/KCjo4O//voLaWlp8i9NnDinSV6cEHzkyBG0aNECbdq0gUwmw969e9WUrGpVZa5qXLCenh769OmDJUuW4PTp08jMzMTu3btVEbVKLVq0gLGxMZKTkyss8/X1RXp6Ou7fv6+GZLUn9vegahKJBF26dMHcuXORlpYGAwMDeZHQtm1bREVF4dChQ/D29lY449myZUtMnz4df/75J15//XXEx8fLl5WVlckncwNPP6l++PAhWrdurboD+38GBgYKn/D7+vpi//79GvXGpCrV/e28eFyaorrnrIeHB86cOYPi4mJ52/Hjx1UZT2n6+voa+XOviSa+vteWjY2NwhnTS5cuae0nzR4eHgqvjYBmPQeq+39w6tQpPH78WL7ukSNHYGZmJr/hsjq9+DeSn58vL4hOnjwJmUyGZcuWoWPHjmjZsiVu3ryprqgNSuWTt/fs2aPqXb40srKyEBERgXfffRepqalYuXIlli1bBldXV4SEhCAsLEw+efvatWvIycnBm2++qZGZK/Prr7/iypUr6N69Oxo1aoTffvsNMpkMHh4eKk6tyMjICJGRkZg5cyYMDAzQpUsX3L17F2fPnsWYMWOwcOFCBAcHY9GiRbC3t0daWhocHBzQqVMnteZ+npjfg6odPXoUycnJ6NevH2xtbXH06FHcvXsXxsbGiIqKQlBQEBwcHHDx4kVcunQJY8eOxePHj/HRRx9h+PDhcHNzQ3Z2No4fP45hw4bJt6uvr48pU6ZgxYoV0NPTw+TJk9GxY0e1nPJ3dXXF0aNHkZmZCTMzM0yePBkrV67EiBEjEBUVBQsLCxw5cgQBAQFq/3t/UXV/O66urti3bx9GjBgBQ0NDNG7cWM1pn6ruOfv222/jk08+wcSJE/Hxxx8jKysLS5cuBQCNu7JVVVxdXZGcnIwuXbrA0NAQjRo1UnekGmnq63tt9erVC6tWrUKnTp1QXl6OyMhIrRjKWJl3330XMTExiIyMxPjx45Geni6/upW6nwNV/T9o3bo1Tp8+jZKSEowfPx7/+te/kJmZiejoaEyePBk6Oir/nLyCXr16ISEhAUOGDIGlpSXmzJkj//DO3d0dpaWlWLlyJYYMGYKDBw9izZo1ak7cQNQ9yYNqp0ePHsL7778vTJo0SZBKpUKjRo2EWbNmySdVPn78WJg+fbpgb28vGBgYCO7u7kJcXJxGZ35x8vb+/fuFHj16CI0aNRKMjY0FX19fYdOmTWpKr6i8vFz47LPPBBcXF0FfX19wdnYWFi5cKAiCIGRmZgrDhg0TpFKpYGJiIrRv314tE4SrUtPvQd0TcM+dOyf0799fsLGxEQwNDYWWLVsKK1euFG7fvi0EBwfL/6ZdXFyEOXPmCOXl5UJxcbEwYsQIwcnJSTAwMBAcHByEyZMnyyfkxsfHCxYWFkJiYqLQrFkzwdDQUOjTp49w7do1tRzjxYsXhY4dOwrGxsYCAOHq1avCqVOnhH79+gkmJiaCubm50K1bN+Hy5ctqyVeVmv52Dh8+LPj6+gqGhoaCpv07qe45e/DgQcHX11cwMDAQ2rVrJ2zcuFEAIFy4cEHNqSv34uTtpKQkwd3dXdDT01No10TPJkBr8ut7VZ6fvH3jxg2hX79+gqmpqdCiRQvht99+06jJ289fHEIQKn9dx3MT0H/55RfB3d1dMDQ0FAIDA4XVq1cLABQuaqAOVf0/EISnk7dfe+01Yc6cOYK1tbVgZmYmTJgwQXjy5IlaMz+Tl5cnvPXWW4JUKhWcnJyEhIQEhcnbMTExgr29vWBsbCz0799f2LBhg0ZMmK9vEkF4YUAYEb1UXta7PlcnISEB06ZN05rx26Re33//PcaNG4e8vDzOz6B/pAULFmDNmjUaPQk6NDQUDx8+rHA/EdIsarnzNhERkbps2LABzZo1Q9OmTXHq1ClERkbizTffZFFB/xhfffUV/P39YW1tjYMHD+KLL77A5MmT1R2LXgIsLIiI6B/l9u3bmDNnDm7fvg17e3u88cYbWnGDLaL6cunSJXz22We4f/8+nJ2d8eGHHyIqKkrdseglwKFQRERERESkNPVPoyciIiIiIq3HwoKIiIiIiJTGwoKIiIiIiJTGwoKIiIiIiJTGwoKIiIiIiJTGwoKIiIiIiJTGwoJIC92+fRtTp06Fu7s7jIyMYGdnhy5dumD16tV49OiRwrqLFi2Crq4uvvjiiwrbSUhIgEQigUQigY6ODhwdHTFu3Djk5OTI13m2XCKRQE9PD87OzoiIiEBxcbF8nbt37+K9996Ds7MzDA0N0aRJE/Tv3x8HDx6s8hgyMzMxfvx4uLm5wdjYGM2bN0d0dDRKSkoU1nl+/8++jhw5osyPj4io3oWGhkIikWDx4sUK7du2bYNEIgEApKSkKLyW2dnZYdiwYbhy5Yp8fVdXV/lyXV1dODg4YPz48Xjw4EG1+3/+9VxXVxeNGjVChw4dMG/ePOTl5dX/ARNVgoUFkZa5cuUK2rZtiz///BMLFy5EWloaDh8+jJkzZ+LXX3/Frl27FNaPi4vDzJkzERcXV+n2pFIpbt26hezsbKxduxa///47xowZo7BOfHw8bt26hatXr+Krr77Ct99+i88++0y+fNiwYUhLS8P69evx999/IykpCYGBgcjNza3yOC5cuACZTIavv/4aZ8+eRWxsLNasWYNZs2ZVWHfXrl24deuW/Ktdu3ZifmRERCphZGSEzz//vMYi4OLFi7h58yY2b96Ms2fPYsiQISgvL5cvnzdvHm7duoWsrCx8//332LdvH8LDw2vc//Ov54cOHcLEiROxYcMG+Pn54ebNm0ofH1GNBCLSKv379xccHR2FwsLCSpfLZDL59ykpKULTpk2FkpISwcHBQTh48KDCuvHx8YKFhYVC24IFCwQdHR3h0aNHgiAIAgBh69atCuuMHz9eGDhwoCAIgvDgwQMBgJCSkqLkkQnCkiVLBDc3N/njq1evCgCEtLQ0pbdNRNSQQkJChMGDBwutWrUSPvroI3n71q1bhWdvt/bs2SMAEB48eCBf/v333wsAhAsXLgiCIAguLi5CbGyswrbnz58veHp6Vrv/yl7PBUEQ7ty5IzRu3FgYNWpU3Q6MSASesSDSIrm5ufjzzz/xwQcfwNTUtNJ1np1yB4B169Zh5MiR0NfXx8iRI7Fu3boa92FsbAyZTIaysrJKl//999/YvXs3OnToAAAwMzODmZkZtm3bpjA8qi7y8vJgZWVVoT0oKAi2trbo2rUrkpKSlNoHEVFD0dXVxcKFC7Fy5UpkZ2fXqo+xsTEAKAwDfd6NGzfw3//+V/6aK5atrS1GjRqFpKQkhbMiRA2BhQWRFsnIyIAgCPDw8FBob9y4sfwNfmRkJAAgPz8fP//8M0aPHg0AGD16NH766ScUFhZWuf1Lly5hzZo1aN++PczNzeXtI0eOhJmZGYyMjODh4QEvLy9ERUUBAPT09JCQkID169fD0tISXbp0waxZs3D69GnRx7Zy5Uq8++678jYzMzMsW7YMmzdvxvbt29G1a1cEBwezuCAijTV06FD4+fkhOjq6xnVv3bqFpUuXomnTpgqv65GRkTAzM4OxsTEcHR0hkUgQExNT50ytWrVCQUFBtcNTieoDCwuil8CxY8eQnp4OLy8v+VmDH374Ac2bN0ebNm0AAH5+fnBxccGmTZsU+ubl5cHMzAwmJibw8PCAnZ0dvv/+e4V1YmNjkZ6ejlOnTuHXX3/F33//rTAPY9iwYbh58yaSkpLw6quvIiUlBa+88goSEhIAAJMmTZIXPmZmZhXy37hxA6+++ireeOMNTJgwQd7euHFjREREoEOHDvD398fixYsxevToSieiExFpis8//xzr16/H+fPnK13u6OgIU1NTODg4oKioCImJiTAwMJAv/+ijj5Ceno7Tp08jOTkZADBo0CD5GYfnX08nTZpUYx5BEAAontEmagh66g5ARLXn7u4OiUSCixcvKrQ3a9YMwP9OqQNPh0GdPXsWenr/e5rLZDLExcVh/Pjx8jZzc3OkpqZCR0cH9vb2Ctt4pkmTJnB3dwcAeHh4oKCgACNHjsRnn30mbzcyMkLfvn3Rt29fzJ49G++88w6io6MRGhqKefPmYcaMGZUe082bN9GzZ0907twZ//nPf2r8GXTo0AE7d+6scT0iInXp3r07+vfvj6ioKISGhlZYvn//fkilUtja2iqcHX6mcePG8tfWFi1a4Msvv0SnTp2wZ88e9OnTB+np6fJ1pVJpjXnOnz8PqVQKa2vrOh8TUW2wsCDSItbW1ujbty9WrVqFKVOmVDnP4syZMzhx4gRSUlIU5izcv38fgYGBuHDhAlq1agUA0NHRkf8Dqy1dXV0AwOPHj6tcx9PTE9u2bQPwdIyvra1thXVu3LiBnj17ol27doiPj4eOTs0nUdPT02Fvby8qLxGRqi1evBh+fn4Vhq4CgJubGywtLWu9rRdfc8W8Zufk5GDjxo0IDg6u1WsskTJYWBBpma+++gpdunRB+/bt8emnn8LX1xc6Ojo4fvw4Lly4gHbt2mHdunUICAhA9+7dK/T39/fHunXrRA0nevjwIW7fvg2ZTIZLly5h3rx5aNmyJVq3bo3c3Fy88cYbCAsLg6+vL8zNzXHixAksWbIEr732WpXbvHHjBgIDA+Hi4oKlS5fi7t278mVNmjQBAKxfvx4GBgZo27YtAGDLli2Ii4vDN998U+vsRETq4OPjg1GjRmHFihWi+xYUFOD27dsQBAHXr1/HzJkzYWNjg86dO1fbTxAEeb+HDx/i8OHDWLhwISwsLCrcX4OoIbCwINIyzZs3R1paGhYuXIioqChkZ2fD0NAQnp6emDFjBiZOnIhmzZrJJ3G/aNiwYVi2bBkWLlxY632OGzcOwNPxuU2aNEH37t2xcOFC6OnpwczMDB06dEBsbCwuX76M0tJSODk5YcKECZXek+KZnTt3IiMjAxkZGXB0dFRY9mw8MADMnz8f165dg56eHlq1aoVNmzZh+PDhtc5ORKQu8+bNqzCvrTbmzJmDOXPmAABsbGzg7++PP//8s8ahTPn5+bC3t4dEIoFUKoWHhwdCQkIwderUWg2ZIlKWRHj+PzgREREREVEdcLAdEREREREpjYUFEREREREpjYUFEREREREpjYUFEREREREpjYUFEREREREpjYUFEREREREpjYUFEREREREpjYUFEREREREpjYUFEREREREpjYUFEREREREpjYUFEREREREpjYUFEREREREp7f8AfzIHJr3KeNAAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_cas['app']\n", - "gap_22_cas = df_gap22_cas['simSeconds'].astype(float)*1000\n", - "gap_22_ram = df_gap22_ram['simSeconds'].astype(float)*1000\n", - "gap_22_noDC = df_gap22_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "\n", - "gap_25_cas = df_gap25_cas['simSeconds'].astype(float)*1000\n", - "gap_25_ram = df_gap25_ram['simSeconds'].astype(float)*1000\n", - "gap_25_noDC = df_gap25_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "\n", - "app_npb = df_npbC_cas['app']\n", - "npb_C_cas = df_npbC_cas['simSeconds'].astype(float)*1000\n", - "npb_C_ram = df_npbC_ram['simSeconds'].astype(float)*1000\n", - "npb_C_noDC = df_npbC_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "npb_D_cas = df_npbD_cas['simSeconds'].astype(float)*1000\n", - "npb_D_ram = df_npbD_ram['simSeconds'].astype(float)*1000\n", - "npb_D_noDC = df_npbD_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "\n", - "# Multi bar Chart1\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,3])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_22_cas[i]/gap_22_noDC[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - " plt.bar(i*3+1, gap_22_ram[i]/gap_22_noDC[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", - "\n", - "offset = i*3+2\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_C_cas[i]/npb_C_noDC[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*3+2, npb_C_ram[i]/npb_C_noDC[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "\n", - "# Multi bar Chart2\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,3])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_25_cas[i]/gap_25_noDC[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - " plt.bar(i*3+1, gap_25_ram[i]/gap_25_noDC[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", - "\n", - "offset = i*3+2\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_D_cas[i]/npb_D_noDC[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*3+2, npb_D_ram[i]/npb_D_noDC[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 72, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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LyoqgoeHR6XJUDgRDRERPU80NTVhaWmJzMxMpKenqzocIqIqSSQSWFpaQlNTs85tiE4sli1bhsGDB+P8+fMoKytDdHQ0zp8/jyNHjmD//v3Vrvf0TJZEREQvEiMjIzg4OKC0tFTVoRARVUlbW7teSQVQxwnyrly5ghUrViA1NRVFRUV46aWXEBYWBldX13oFo2ycII+InjecII/oxeW3e6io+gn+exopEnqeiPm+LPqKBQC0b98emzZtqlNwgiDg1KlTSE9Ph0QiQbt27eDh4cE+p0RERERETVidEgsAyM7ORnZ2NioqKuTK3dzcql1n3759CA4OxvXr12Ujz58kFzExMejdu3ddwyEiIiIiIhUSnVicOnUKAQEBuHDhQqXbUkkkEpSXl1e5XlpaGoYNGwYvLy9ERUXB0dERgiDg/PnzWLt2LYYMGYIzZ87Azs6ubntCREREREQqIzqxCAoKQocOHbB582a0bNlS4S5Ma9asQffu3ZGYmChX7ujoiJEjR6J///6IiorCunXrxIZEREREREQqJjqxuHr1KuLj42Fvby9qvaSkJCxfvrzKZRKJBDNnzkR4eLjYcIiIiIiISA1o1F5FXr9+/ZCamip6QxkZGTXeNcrFxQXXr18X3S4REREREame6CsWX375JQICAvDPP//AxcWl0ux8fn5+Va5XVFQEAwODats1MDDAgwcPxIZDRERERERqQHRicfToURw+fBi//vprpWU1Dd4GgPPnz+P27dtVLrtz547YUIiIiIiISE2ITiymT5+O8ePHY8GCBWjZsqWodfv161fpTlLA44REEATOZUFERET0nOge8bvCdY8tGtSIkZCyiE4scnNzMWvWLNFJxbVr18RuioiIGpiYD3qAH/ZERKQ40YnFq6++in379qF9+/ai1rOxsRG7KSIiIqJ6YTJNpDyiE4sOHTogPDwchw4dgqura6XB2yEhIQq35erqil9++QVWVlZiwyAiIiIiIjVSp7tCGRkZYf/+/di/f7/cMolEIiqxSE9PR2lpqdgQiIiISIn4qz8RKUJ0YsGxEkRERESNT2xC18KjkQIhUpDoCfIa0ssvvwx9fX1VhkBERERERA1AoSsWoaGhWLJkCQwNDREaGlpj3cjISIU3/ssvvyhctyrLly/Hzp07cfHiRejr66NHjx745JNP0LFjx3q1S0RERERE4iiUWCQnJ8vGQiQnJ9d7o+Xl5di9ezcuXLgAAHB2doafnx80NTVFtbN//36899578PT0RFlZGebPn4+BAwfi/PnzMDQ0rHecRERERESkGIUSi3379lX5d12kpaVh6NChyMzMlF1ZWL58OaysrLBnzx5Rt7H97bff5J7HxcWhRYsWOHXqFHr37l2vOImIiIiISHGix1gEBQWhsLCwUvn9+/cRFBRU6/ohISGws7PDjRs3cPr0aZw+fRoZGRlo166dqDtKVSU/Px8AYGZmVuXy4uJiFBQUyD2IiIiIiKj+RCcWW7ZswcOHDyuVP3z4EFu3bq11/f3792PlypVyX/7Nzc2xYsWKSrevFaOiogIzZ85Ez5494eLiUmWd5cuXw8TERPbg/BlERERERA1D4dvNFhQUQBAECIKAwsJC6OnpyZaVl5fjl19+QYsWLWptR1dXt8orHkVFRdDR0VE0nEree+89/PPPPzh06FC1dcLDw+UGnxcUFDC5ICIiamB+u4cqXDfBf08jRkJEyqRwYmFqagqJRAKJRIIOHTpUWi6RSLBo0aJa2xk2bBimTJmCzZs3o1u3bgCA48ePY+rUqfDz8xMR+v+ZNm0afv75Zxw4cACWlpbV1tPV1YWurm6dtkFERERERNVTOLHYt28fBEFA3759ER8fL9eVSUdHBzY2NmjTpk2t7axduxYBAQHw9vaGtrY2AKCsrAx+fn6Ijo4WFbwgCJg+fTp27dqFpKQktGvXTtT6REREysCZq4noRaBwYuHj4wPg8czb1tbWkEgkddqgqakpfvzxR1y+fBkXL14EAHTq1An29vai23rvvfewbds2/PjjjzA2Nsbt27cBACYmJpx4j4iIiIhIiRROLJ6wsbFpkA07ODjAwcGhXm1s2LABAODr6ytXHhsbi8DAwHq1TUREREREihOdWNRXeXk54uLikJiYiOzsbFRUVMgt/+uvvxRuSxCEhg6PiIiIiIjqQOmJxYwZMxAXF4ehQ4fCxcWlzl2qiIiIiIhIfSg9sfjuu+/w/fffY8iQIcreNBERERERNRKlJxY6Ojp1GqhN6ol3OiEiIiIioA4zb//333+YMGEC2rRpAy0tLWhqaso9avP+++8jOjqa4yOIiIiIiJ4joq9YBAYGIiMjAwsWLEDr1q1Fj5E4dOgQ9u3bh19//RXOzs6yuSye2Llzp9iQiIiIiIhIxUQnFocOHcLBgwfh7u5epw2amppi5MiRdVqXiIiIiIjUk+jEwsrKql7dmGJjY+u8LhERERERqSfRYyzWrFmDefPmIT09vRHCISIiIiKipkj0FYs33ngDDx48QPv27WFgYFBpjEReXl6DBUdERKrlt3uownUT/Pc0YiRERKTuRCcWa9asaYQwiIiIiOhFJeZHDIA/ZKgr0YlFQEBAY8RBRERERERNWJ0myCsvL8fu3btx4cIFAICzszP8/PwUmseCSJ2ImeCPk/sRERERVU90YpGWloYhQ4bg5s2b6NixIwBg+fLlsLKywp49e9C+ffta29i/fz9WrVolS0ycnJwwZ84cvPzyy2LDISJSKs42T0REVDXRiUVISAjat2+PY8eOwczMDACQm5uL8ePHIyQkBHv21Nzn7euvv8akSZPw6quvIiQkBABw+PBh9OvXD3FxcXjzzTfrsBtN24v0RYV9KImI6Hny+YivRdV/+8fxjRQJkeqJTiz2798vl1QAgLm5OVasWIGePXvWuv7SpUuxcuVKzJo1S1YWEhKCyMhILFmy5IVMLIiIiIiImjrR81jo6uqisLCwUnlRURF0dHRqXf/q1asYPnx4pXI/Pz9cu3ZNbDhERERERKQGRF+xGDZsGKZMmYLNmzejW7duAIDjx49j6tSp8PPzq3V9KysrJCYmwt7eXq587969sLKyEhsOERERUYMR22V3KMY2UiRETY/oxGLt2rUICAiAt7e3bHK8srIy+Pn5ITo6utb133//fYSEhCAlJQU9evQA8HiMRVxcnELrExERERGR+hGdWJiamuLHH3/E5cuXcfHiRQBAp06dKl2BqM4777yDVq1aYfXq1fj+++9l62/fvh0jRowQGw4REREREamBOs1jAQAODg5wcHCo07ojR47EyJEj67ppIiIiIiJSMwolFqGhoViyZAkMDQ0RGhpaY93IyMgal9vZ2eHkyZMwNzeXK7937x5eeuklXL16VZGQiIiIiIhIjSiUWCQnJ6O0tFT2d32kp6ejvLy8UnlxcTFu3rxZr7aJqGl4keZuIaoLzvlDRE2RQonFvn37qvxbjISEBNnfv//+O0xMTGTPy8vLkZiYCFtb2zq1TUREREREqiV6jEVQUBCio6NhbGwsV37//n1Mnz4dMTExVa7n7+8PAJBIJAgICJBbpq2tDVtbW6xevVpsOEREREREpAZEJxZbtmzBihUrKiUWDx8+xNatW6tNLCoqKgAA7dq1w8mTJ9G8efM6hEtERERE1LjYZbduFE4sCgoKIAgCBEFAYWEh9PT0ZMvKy8vxyy+/oEWLFrW2w9m1qalin2ciIiKi6imcWJiamkIikUAikaBDhw6VlkskEixatKhBgyMiIiIioqZB4cRi3759EAQBffv2RXx8PMzMzGTLdHR0YGNjgzZt2jRKkERERFS9z0d8Lar+2z+Ob6RIiOhFpnBi4ePjA+BxVyZra2tIJJJGC4qI6GnshtY08MstEdGLTfTg7evXr+P69evVLu/du3e9AiIiIiIioqZHdGLh6+tbqezpqxdVTX5XUFCgcPtSqVRsSERE9ALgXVqIiNSb6MTi7t27cs9LS0uRnJyMBQsWYOnSpVWu82TgtyKqSkyIiIjEYhe6poFd6IieH6ITi6dnzH5iwIAB0NHRQWhoKE6dOlVp+dOzdaenp2PevHkIDAyEt7c3AODo0aPYsmULli9fLjYces7xA4eaOn65JSKiF4XoxKI6LVu2xKVLl6pc9mTgNwAsXrwYkZGRGDt2rKzMz88Prq6u+OKLLyrNyk1ERERE9DT+8KieRCcWZ86ckXsuCAKysrKwYsUKuLu717r+0aNHsXHjxkrlXbt2xVtvvSU2HCKi5wo/LImImh5enX5MdGLh7u4OiUQCQRDkyrt3746YmJha17eyssKmTZuwcuVKufIvv/wSVlZWYsMhUlv8gkhEROqMn1PU0EQnFteuXZN7rqGhAQsLC+jp6Sm0flRUFEaNGoVff/0VXl5eAIATJ07g8uXLiI+PFxXLgQMH8Omnn+LUqVPIysrCrl274O/vL6oNIiIiIiKqP9GJhY2NTb02OGTIEPz777/YsGEDLl68CAAYPnw4pk6dKvqKxf3799G5c2cEBQXh1VdfrVdcTQkvtxHVjL/CERGROhPzOdWUPqNEJxYhISGwt7dHSEiIXPn69euRlpaGNWvW1NqGlZUVli1bJnbTlQwePBiDBw+udzslJSUoKSmpdzt1pQlxt9jVKNcQVX/DyK0K1w3ePkZU240de4VGhaj6Yv+PYuJXt9ibsqZ83Kh77CUlJdDW1q709xONGb86vV8B8a99Y74H1f24qQ2Pm+q9yOeb2jTlz1h1eu1V/f1AzPYlwrODJWrRtm1bJCQkoEuXLnLlp0+fhp+fHzIzM2tt4+DBg/j8889x9epV7NixA23btsVXX32Fdu3aoVevXmLCkZFIJLV2hSouLkZxcbHseUFBAaysrDBv3jyFu3IREREREb0oHj16hBUrViA/P7/WiazFpVcAcnNzq5zLQiqV4s6dO7WuHx8fj0GDBkFfXx+nT5+WfdHPz89vkKsYNVm+fDlMTExkDw4WJyIiIiJqGKKvWLi4uGDq1KmYNm2aXPm6deuwYcMGnD9/vsb1PTw8MGvWLEycOBHGxsZITU2FnZ0dkpOTMXjwYNy+fVv8XqB+VyxycnJqzcAaU5+le0XVt3DbIKr+oK9fU7iu2K5Q6hQ70Ljxq1vsTVlTPm7UPfb79++jZcuWAID//vsPhoaGcssbM351er8C4l/774eLu4GIGOp+3NSGx031XuTzTW2a8mesOr32qv5+UFBQAAsLC4WuWIgeYxEaGopp06YhJycHffv2BQAkJiZi9erVCo2vuHTpEnr37l2p3MTEBPfu3RMbjii6urrQ1dWtVK6jowMdHZ1G3XZNyqEpqn6Fprh+hRoVil+YEvs6qFPsQOPGr26xN2VN+bhR99hLS0tRWloqW/bs8saMX53er4D4174x34PqftzUhsdN9V7k801tmvJnrDq99qr+fiBm+6ITi6CgIBQXF2Pp0qVYsmQJAMDW1hYbNmzAxIkTa12/VatWSEtLg62trVz5oUOHYGdnJzYcIiKiBsG7iRER1Y/oxAIA3nnnHbzzzjvIycmBvr4+jIyMFF538uTJmDFjBmJiYiCRSHDr1i0cPXoUs2fPxoIFC0TFUVRUhLS0NNnza9euISUlBWZmZrC2thbVFhERERER1V2dEouysjIkJSXhypUrePPNNwEAt27dglQqrTXJmDdvHioqKtCvXz88ePAAvXv3hq6uLmbPno3p06eLiuPvv/9Gnz59ZM9DQ0MBAAEBAYiLixO3U0RNTPeI30XVP7ZoUCNFQkRERFSHxOL69et45ZVXkJGRgeLiYgwYMADGxsb45JNPUFxcjI0bN9a4vkQiwQcffIA5c+YgLS0NRUVFcHJyEnXV4wlfX1+IHHtO9MISM7EiJ1UkIiIisUTfbnbGjBno2rUr7t69C319fVn5yJEjkZiYWOv6W7duxYULF6CjowMnJyd069YNRkZGePToEbZuVXwiNyIiIiIiUh+iE4uDBw/iww8/rDRC3NbWFjdv3qx1/cDAQHTr1g3x8fK39cvPz8ekSZPEhkNERERERGpAdGJRUVGB8vLK05xnZmbC2NhYoTYWLVqECRMm4KOPPhK7eSIiIiIiUkOiE4uBAwfKzVchkUhQVFSEiIgIDBkyRKE2xo8fj7/++guff/45Ro8ejYcPH4oNg4iIiIiI1IjoxGL16tU4fPgwnJyc8OjRI7z55puyblCffPJJretLJBIAQPfu3XH8+HGkpaWhR48eSE9PFx08ERERERGpB9F3hbK0tERqaiq2b9+O1NRUFBUVITg4GOPGjZMbzF2dp+/iZG1tjSNHjmDcuHEYMGCA2FCIqJFwojAiIiISS3RikZOTAwsLC4wbNw7jxo2TW3b27Fm4urrWuH5ERITcrWUNDAywa9cuRERE4MCBA2LDISIiIiIiNSC6K5Srqyv27Kl8j/tVq1ahW7duta4fEREBAwODSuWLFi3Cvn37xIZDRERERERqQPQVi9DQUIwaNQqTJk1CZGQk8vLyMHHiRJw9exbbtm2rcp2EhAQMHjwY2traSEhIqLZtiUSC4cOHiw2JiIiIiIhUTHRiMXfuXAwYMAATJkyAm5sb8vLy4OXlhTNnzqBVq1ZVruPv74/bt2+jRYsW8Pf3r7ZtiURS5a1siYiIiIhIvYnuCgUA9vb2cHFxQXp6OgoKCvDGG29Um1QAj+e+aNGihezv6h5MKoiIiIiImibRicXhw4fh5uaGy5cv48yZM9iwYQOmT5+ON954A3fv3m2MGImIiIiISM2J7grVt29fzJo1C0uWLIG2tjY6deqEPn36YPz48XB1dUVmZmalddauXatw+yEhIWJDIiIiIiIiFROdWPzxxx/w8fGRK2vfvj0OHz6MpUuXVrlOVFSUQm1LJBImFkRERERETZDoxOLZpOIJDQ0NLFiwoMpl165dE7sZIiIiIiJqQhQeYzFkyBDk5+fLnq9YsQL37t2TPc/NzYWTk1ODBkdERERERE2Dwlcsfv/9dxQXF8ueL1u2DK+//jpMTU0BAGVlZbh06ZJCbWVmZiIhIQEZGRkoKSmRWxYZGaloSEREREREpCYUTiwEQajxuaISExPh5+cHOzs7XLx4UXbbWkEQ8NJLL9WpTSIiIiIiUq06zWNRH+Hh4Zg9ezbOnj0LPT09xMfH48aNG/Dx8cFrr72m7HCIiIiIiKgBKJxYSCQSSCSSSmViXbhwARMnTgQAaGlp4eHDhzAyMsLixYvxySefiG6PiIiIiIhUT1RXqMDAQOjq6gIAHj16hKlTp8LQ0BAA5MZf1MTQ0FA2rqJ169a4cuUKnJ2dAQB37twRFTwREREREakHhROLgIAAuefjx4+vVOfJlYiadO/eHYcOHUKnTp0wZMgQvP/++zh79ix27tyJ7t27KxoOERERERGpEYUTi9jY2AbZYGRkJIqKigAAixYtQlFREbZv3w4HBwfeEYqIiIiIqIkSPUFefdnZ2cn+NjQ0xMaNG5UdAhERERERNTClJxZPKyoqQkVFhVyZVCpVUTRERERERFRXSr/d7LVr1zB06FAYGhrCxMQEzZo1Q7NmzWBqaopmzZopOxwiIiIiImoASr9iMX78eAiCgJiYGLRs2bJOt6wlIiIiIiL1ovTEIjU1FadOnULHjh2VvWkiIiIiImokSu8K5enpiRs3bih7s0RERERE1IiUfsXiyy+/xNSpU3Hz5k24uLhAW1tbbrmbm5uyQyIiIiIionpSemKRk5ODK1euYNKkSbIyiUQCQRAgkUhQXl6u7JCIiIiIiKielJ5YBAUFwcPDA99++y0HbxMRERERPSeUnlhcv34dCQkJsLe3V/amiYiIiIiokSh98Hbfvn2Rmpqq7M0SEREREVEjUvoVi+HDh2PWrFk4e/YsXF1dKw3e9vPzU3ZIRERERERUT0pPLKZOnQoAWLx4caVlHLxNRERERNQ0Kb0rVEVFRbWPuiYV//vf/2Braws9PT14eXnhxIkTDRw1ERERERHVRKmJRWlpKbS0tPDPP/80WJvbt29HaGgoIiIicPr0aXTu3BmDBg1CdnZ2g22DiIiIiIhqptTEQltbG9bW1g3a3SkyMhKTJ0/GpEmT4OTkhI0bN8LAwAAxMTENtg0iIiIiIqqZ0sdYfPDBB5g/fz6++uormJmZ1autkpISnDp1CuHh4bIyDQ0N9O/fH0ePHq1Uv7i4GMXFxbLn+fn5AICCgoJ6xVFfZcX3RdUvfVAqqv7D0ocK1xX7WqhT7EDjxt+UYwfExd+UYwcaN351j/3+/ftyy579IYfHTfVe5OOmNjxuqsfjpnr8jK1eY343a2hPti8IQq11JYIitRqQh4cH0tLSUFpaChsbGxgaGsotP336tMJt3bp1C23btsWRI0fg7e0tK587dy7279+P48ePy9X/6KOPsGjRovrtABERERHRC+bGjRuwtLSssY7Sr1j4+/sre5My4eHhCA0NlT2vqKhAXl4ezM3Nm/wM4AUFBbCyssKNGzcglUpVHY4ojF11mnL8jF11mnL8jF01mnLsQNOOn7GrTlOP/wlBEFBYWIg2bdrUWlfpiUVERESDtdW8eXNoamriv//+kyv/77//0KpVq0r1dXV1oaurK1dmamraYPGoA6lU2mQPXsauOk05fsauOk05fsauGk05dqBpx8/YVaepxw8AJiYmCtVT+u1mnzh16hS+/vprfP3110hOTq5TGzo6OujSpQsSExNlZRUVFUhMTJTrGkVERERERI1L6VcssrOzMWbMGCQlJcmuFty7dw99+vTBd999BwsLC1HthYaGIiAgAF27dkW3bt2wZs0a3L9/H5MmTWqE6ImIiIiIqCpKv2Ixffp0FBYW4ty5c8jLy0NeXh7++ecfFBQUICQkRHR7b7zxBlatWoWFCxfC3d0dKSkp+O2339CyZctGiF596erqIiIiolJXr6aAsatOU46fsatOU46fsatGU44daNrxM3bVaerx14XS7wplYmKCvXv3wtPTU678xIkTGDhwIO7du6fMcIiIiIiIqAEo/YpFRUUFtLW1K5Vra2ujoqJC2eEQEREREVEDUHpi0bdvX8yYMQO3bt2Sld28eROzZs1Cv379lB0OERERERE1AKV3hbpx4wb8/Pxw7tw5WFlZycpcXFyQkJBQ68QbRERERESkfpR+xcLKygqnT5/Gnj17MHPmTMycORO//PILTp8+zaRCAb6+vpg5c6aqwxCltpgfPHiAUaNGQSqVQiKRcJwNkRppiuec54kgCJgyZQrMzMwgkUiQkpKi6pAU1pSPnaYcO5EqKf12swAgkUgwYMAADBgwQBWbJzWzZcsWHDx4EEeOHEHz5s0VnoSFqKnw9fWFu7s71qxZo+pQGpytra3sRyJqeL/99hvi4uKQlJQEOzs7tG7dGrt27YK/v7+qQ6vVzp07qxxTSUTPL5UkFomJiUhMTER2dnalAdsxMTGqCIlU6MqVK+jUqRNcXFxUHQo9paSkBDo6OqoOg+iFduXKFbRu3Ro9evRQdSiimZmZqToEIlIypXeFWrRoEQYOHIjExETcuXMHd+/elXtQ7crKyjBt2jSYmJigefPmWLBgAZ4MlSkuLkZYWBisrKygq6sLe3t7bN68WcURVx+zr68vVq9ejQMHDkAikcDX1xcA8Nlnn8HBwQF6enpo2bIlRo8erdodwOM7mq1cuRL29vbQ1dWFtbU1li5dCgDIzMzE2LFjYWZmBkNDQ3Tt2hXHjx9XccTyfH19MW3atGqPHVtbWyxZsgQTJ06EVCrFlClTlBbbDz/8AFdXV+jr68Pc3Bz9+/fH/fv3kZSUhG7dusHQ0BCmpqbo2bMnrl+/DgBITU1Fnz59YGxsDKlUii5duuDvv/8GAMTFxcHU1BS7d++WHUeDBg3CjRs3lLZPTwQGBmL//v2Ijo6GRCKBRCJBeno6zp07h2HDhkEqlcLY2Bgvv/wyrly5ovT4FFHT+/f69euYNWuWbN/URU3v1yNHjsDd3R16enro2rUrdu/erZbdjAIDAzF9+nRkZGRAIpHA1tYWADBy5Ei55+rq6e5E6nhOV5REIsHu3bvlykxNTREXF6eSeJ7m6+uL6dOnY+bMmWjWrBlatmyJTZs2ySYKNjY2hr29PX799VfZOgkJCbL/RZ8+fbBlyxa16IZc3edAYGAg/P39sWjRIlhYWEAqlWLq1KkoKSlRabxP2NraVroa7e7ujo8++ggAEBkZCVdXVxgaGsLKygrvvvsuioqKlB+okij9isXGjRsRFxeHCRMmKHvTz40tW7YgODgYJ06cwN9//40pU6bA2toakydPxsSJE3H06FGsXbsWnTt3xrVr13Dnzh1Vh1xtzDt37sS8efPwzz//YOfOndDR0cHff/+NkJAQfPXVV+jRowfy8vJw8OBBVe8CwsPDsWnTJkRFRaFXr17IysrCxYsXUVRUBB8fH7Rt2xYJCQlo1aoVTp8+rZa3T67p2AEgm2wyIiJCaTFlZWVh7NixWLlyJUaOHInCwkIcPHgQgiDA398fkydPxrfffouSkhKcOHFC9uV13Lhx8PDwwIYNG6CpqYmUlBS5bhcPHjzA0qVLsXXrVujo6ODdd9/FmDFjcPjwYaXtGwBER0fj33//hYuLCxYvXgwAKC8vR+/eveHr64u//voLUqkUhw8fRllZmVJjU1RN79/OnTtjypQpsmNIXVT3fi0oKMDw4cMxZMgQbNu2DdevX1fbblzR0dFo3749vvjiC5w8eRKamppo0aIFYmNj8corr0BTU1PVISpEXc/pz4stW7Zg7ty5OHHiBLZv34533nkHu3btwsiRIzF//nxERUVhwoQJyMjIwH///YfRo0djxowZeOutt5CcnIzZs2erehdq/BwAHvd00dPTQ1JSEtLT0zFp0iSYm5vLfixQZxoaGli7di3atWuHq1ev4t1338XcuXPx2WefqTq0xiEomZmZmZCWlqbszT43fHx8hE6dOgkVFRWysrCwMKFTp07CpUuXBADCn3/+qcIIK6spZkEQhBkzZgg+Pj6yZfHx8YJUKhUKCgqUHWq1CgoKBF1dXWHTpk2Vln3++eeCsbGxkJubq4LIFFfb/8HGxkbw9/dXelynTp0SAAjp6ely5bm5uQIAISkpqcr1jI2Nhbi4uCqXxcbGCgCEY8eOycouXLggABCOHz/ecMEryMfHR5gxY4bseXh4uNCuXTuhpKRE6bGIpchxExUVpaLoqlbT+3XDhg2Cubm58PDhQ1nZpk2bBABCcnKyEqNUTFRUlGBjYyN7DkDYtWuXyuIR48lxr47n9No8/Z6t6jU3MTERYmNjlR7Xs3x8fIRevXrJnpeVlQmGhobChAkTZGVZWVkCAOHo0aNCWFiY4OLiItfGBx98IAAQ7t69q6ywK6nuc0AQBCEgIEAwMzMT7t+/LyvbsGGDYGRkJJSXlyszzCpVdQ7s3LmzEBERUWX9HTt2CObm5o0fmIoovSvUW2+9hW3btil7s8+V7t27y3U58Pb2xuXLl5GcnAxNTU34+PioMLqqVRdzeXl5pboDBgyAjY0N7OzsMGHCBHzzzTd48OCBMsOt5MKFCyguLq5yrpWUlBR4eHg0if7Etf0funbtqvSYOnfujH79+sHV1RWvvfYaNm3ahLt378LMzAyBgYEYNGgQhg8fjujoaGRlZcnWCw0NxVtvvYX+/ftjxYoVlboRaWlpwdPTU/bc0dERpqamuHDhgtL2rTopKSl4+eWXm8zAVjHvX3VQ0/v10qVLcHNzg56enqysW7duygzvhaOO5/TniZubm+xvTU1NmJubw9XVVVbWsmVLAEB2djYuXbokd14E1OP4r+5z4OnlBgYGsufe3t4oKipSSfdWsfbu3Yt+/fqhbdu2MDY2xoQJE5Cbm/vcvgeUnlg8evQIkZGR8PHxwfTp0xEaGir3oLp7+oOyKTM2Nsbp06fx7bffonXr1li4cCE6d+6s0v6f+vr6dVrW1BgaGip9m5qamvjzzz/x66+/wsnJCevWrUPHjh1x7do1xMbG4ujRo+jRowe2b9+ODh064NixYwCAjz76COfOncPQoUPx119/wcnJCbt27VJ6/HXxPB0z6oivr3pRx3O6GBKJRNYl54nS0lIVRVPZsz9QSCQSubInPwqoY/fcJ2r6HFB3Ghoa1R4f6enpGDZsGNzc3BAfH49Tp07hf//7HwCozRiRhqb0xOLMmTNwd3eHhoYG/vnnHyQnJ8se6jZwTl09Oyj42LFjcHBwQOfOnVFRUYH9+/erKLLqVRdzdX2EtbS00L9/f6xcuRJnzpxBeno6/vrrL2WEWiUHBwfo6+sjMTGx0jI3NzekpKQgLy9PBZGJI/b/oCwSiQQ9e/bEokWLkJycDB0dHVmS4OHhgfDwcBw5cgQuLi5yVzw7dOiAWbNm4Y8//sCrr76K2NhY2bKysjLZYG7g8S/V9+7dQ6dOnZS3Y/+fjo6O3K/7bm5uOHjwoFp9OalJTcfNs/umDmp6v3bs2BFnz55FcXGxrOzkyZPKDK9etLW11e71VoS6ndPFsLCwkLtaevny5Sb7a3PHjh3lzouA+hz/NX0OpKam4uHDh7K6x44dg5GRkWyiZVV69vgoKCiQJUSnTp1CRUUFVq9eje7du6NDhw64deuWqkJVCqUP3t63b5+yN/ncycjIQGhoKN5++22cPn0a69atw+rVq2Fra4uAgAAEBQXJBm9fv34d2dnZeP3119Uy5qr8/PPPuHr1Knr37o1mzZrhl19+QUVFBTp27KjkqP+Pnp4ewsLCMHfuXOjo6KBnz57IycnBuXPnMGHCBCxbtgz+/v5Yvnw5WrdujeTkZLRp0wbe3t4qi7kqYv4PynL8+HEkJiZi4MCBaNGiBY4fP46cnBzo6+sjPDwcfn5+aNOmDS5duoTLly9j4sSJePjwIebMmYPRo0ejXbt2yMzMxMmTJzFq1ChZu9ra2pg+fTrWrl0LLS0tTJs2Dd27d1fJZX9bW1scP34c6enpMDIywrRp07Bu3TqMGTMG4eHhMDExwbFjx9CtWzeVHufVqem4sbW1xYEDBzBmzBjo6uqiefPmKo625vfrm2++iQ8++ABTpkzBvHnzkJGRgVWrVgGAWt3Vqjq2trZITExEz549oauri2bNmqk6pFqp4zldjL59+2L9+vXw9vZGeXk5wsLCmkw3xme9/fbbiIyMRFhYGIKDg5GSkiK7u5Uqj//qPgc6deqEM2fOoKSkBMHBwfjwww+Rnp6OiIgITJs2DRoaSv99vJK+ffsiLi4Ow4cPh6mpKRYuXCj7sc7e3h6lpaVYt24dhg8fjsOHD2Pjxo0qjriRqXqQB4nj4+MjvPvuu8LUqVMFqVQqNGvWTJg/f75sYOXDhw+FWbNmCa1btxZ0dHQEe3t7ISYmRq1jfnbw9sGDBwUfHx+hWbNmgr6+vuDm5iZs375dRdH/n/LycuHjjz8WbGxsBG1tbcHa2lpYtmyZIAiCkJ6eLowaNUqQSqWCgYGB0LVrV5UMEq5Jbf8HVQ3CPX/+vDBo0CDBwsJC0NXVFTp06CCsW7dOuH37tuDv7y87lm1sbISFCxcK5eXlQnFxsTBmzBjByspK0NHREdq0aSNMmzZNNiA3NjZWMDExEeLj4wU7OztBV1dX6N+/v3D9+nWl758gCMKlS5eE7t27C/r6+gIA4dq1a0JqaqowcOBAwcDAQDA2NhZefvll4cqVKyqJrya1HTdHjx4V3NzcBF1dXUGdPlJqer8ePnxYcHNzE3R0dIQuXboI27ZtEwAIFy9eVHHUlT07eDshIUGwt7cXtLS05MrV0ZMB0Op6Tq/J04O3b968KQwcOFAwNDQUHBwchF9++UWtBm8/fWMIQaj6XI6nBqD/+OOPgr29vaCrqyv4+voKGzZsEADI3dBA2ar7HBCEx4O3R4wYISxcuFAwNzcXjIyMhMmTJwuPHj1SWbxPy8/PF9544w1BKpUKVlZWQlxcnNzg7cjISKF169aCvr6+MGjQIGHr1q0qHyzfmCSC8EzHMCJ6Lj3Psz8/Ky4uDjNnzmwyfbhJtb755htMmjQJ+fn5HJ9BL5ylS5di48aNajsQOjAwEPfu3as0lwipJ5XMvE1ERKQqW7duhZ2dHdq2bYvU1FSEhYXh9ddfZ1JBL4TPPvsMnp6eMDc3x+HDh/Hpp59i2rRpqg6LnhNMLIiI6IVy+/ZtLFy4ELdv30br1q3x2muvNYmJtogawuXLl/Hxxx8jLy8P1tbWeP/99xEeHq7qsOg5wa5QRERERERUb6ofTk9ERERERE0eEwsiIiIiIqo3JhZERERERFRvTCyIiIiIiKjemFgQEREREVG9MbEgIiIiIqJ6Y2JB1ATdvn0bM2bMgL29PfT09NCyZUv07NkTGzZswIMHD+TqLl++HJqamvj0008rtRMXFweJRAKJRAINDQ1YWlpi0qRJyM7OltV5slwikUBLSwvW1tYIDQ1FcXGxrE5OTg7eeecdWFtbQ1dXF61atcKgQYNw+PDhavchPT0dwcHBaNeuHfT19dG+fXtERESgpKRErs7T23/yOHbsWH1ePiKiBhcYGAiJRIIVK1bIle/evRsSiQQAkJSUJHcua9myJUaNGoWrV6/K6tva2sqWa2pqok2bNggODsbdu3dr3P7T53NNTU00a9YMXl5eWLx4MfLz8xt+h4mqwMSCqIm5evUqPDw88Mcff2DZsmVITk7G0aNHMXfuXPz888/Yu3evXP2YmBjMnTsXMTExVbYnlUqRlZWFzMxMbNq0Cb/++ismTJggVyc2NhZZWVm4du0aPvvsM3z11Vf4+OOPZctHjRqF5ORkbNmyBf/++y8SEhLg6+uL3Nzcavfj4sWLqKiowOeff45z584hKioKGzduxPz58yvV3bt3L7KysmSPLl26iHnJiIiUQk9PD5988kmtScClS5dw69Yt7NixA+fOncPw4cNRXl4uW7548WJkZWUhIyMD33zzDQ4cOICQkJBat//0+fzIkSOYMmUKtm7dCnd3d9y6dave+0dUK4GImpRBgwYJlpaWQlFRUZXLKyoqZH8nJSUJbdu2FUpKSoQ2bdoIhw8flqsbGxsrmJiYyJUtXbpU0NDQEB48eCAIgiAAEHbt2iVXJzg4WBgyZIggCIJw9+5dAYCQlJRUzz0ThJUrVwrt2rWTPb927ZoAQEhOTq5320REjSkgIEAYNmyY4OjoKMyZM0dWvmvXLuHJ1619+/YJAIS7d+/Kln/zzTcCAOHixYuCIAiCjY2NEBUVJdf2kiVLBCcnpxq3X9X5XBAE4b///hOaN28ujBs3rm47RiQCr1gQNSG5ubn4448/8N5778HQ0LDKOk8uuQPA5s2bMXbsWGhra2Ps2LHYvHlzrdvQ19dHRUUFysrKqlz+77//4q+//oKXlxcAwMjICEZGRti9e7dc96i6yM/Ph5mZWaVyPz8/tGjRAr169UJCQkK9tkFE1Fg0NTWxbNkyrFu3DpmZmQqto6+vDwBy3UCfdvPmTfz000+yc65YLVq0wLhx45CQkCB3VYSoMTCxIGpC0tLSIAgCOnbsKFfevHlz2Rf8sLAwAEBBQQF++OEHjB8/HgAwfvx4fP/99ygqKqq2/cuXL2Pjxo3o2rUrjI2NZeVjx46FkZER9PT00LFjRzg7OyM8PBwAoKWlhbi4OGzZsgWmpqbo2bMn5s+fjzNnzojet3Xr1uHtt9+WlRkZGWH16tXYsWMH9uzZg169esHf35/JBRGprZEjR8Ld3R0RERG11s3KysKqVavQtm1bufN6WFgYjIyMoK+vD0tLS0gkEkRGRtY5JkdHRxQWFtbYPZWoITCxIHoOnDhxAikpKXB2dpZdNfj222/Rvn17dO7cGQDg7u4OGxsbbN++XW7d/Px8GBkZwcDAAB07dkTLli3xzTffyNWJiopCSkoKUlNT8fPPP+Pff/+VG4cxatQo3Lp1CwkJCXjllVeQlJSEl156CXFxcQCAqVOnyhIfIyOjSvHfvHkTr7zyCl577TVMnjxZVt68eXOEhobCy8sLnp6eWLFiBcaPH1/lQHQiInXxySefYMuWLbhw4UKVyy0tLWFoaIg2bdrg/v37iI+Ph46Ojmz5nDlzkJKSgjNnziAxMREAMHToUNkVh6fPp1OnTq01HkEQAMhf0SZqDFqqDoCIFGdvbw+JRIJLly7JldvZ2QH4v0vqwONuUOfOnYOW1v+9zSsqKhATE4Pg4GBZmbGxMU6fPg0NDQ20bt1aro0nWrVqBXt7ewBAx44dUVhYiLFjx+Ljjz+Wlevp6WHAgAEYMGAAFixYgLfeegsREREIDAzE4sWLMXv27Cr36datW+jTpw969OiBL774otbXwMvLC3/++Wet9YiIVKV3794YNGgQwsPDERgYWGn5wYMHIZVK0aJFC7mrw080b95cdm51cHDAmjVr4O3tjX379qF///5ISUmR1ZVKpbXGc+HCBUilUpibm9d5n4gUwcSCqAkxNzfHgAEDsH79ekyfPr3acRZnz57F33//jaSkJLkxC3l5efD19cXFixfh6OgIANDQ0JB9gClKU1MTAPDw4cNq6zg5OWH37t0AHvfxbdGiRaU6N2/eRJ8+fdClSxfExsZCQ6P2i6gpKSlo3bq1qHiJiJRtxYoVcHd3r9R1FQDatWsHU1NThdt69pwr5pydnZ2Nbdu2wd/fX6FzLFF9MLEgamI+++wz9OzZE127dsVHH30ENzc3aGho4OTJk7h48SK6dOmCzZs3o1u3bujdu3el9T09PbF582ZR3Ynu3buH27dvo6KiApcvX8bixYvRoUMHdOrUCbm5uXjttdcQFBQENzc3GBsb4++//8bKlSsxYsSIatu8efMmfH19YWNjg1WrViEnJ0e2rFWrVgCALVu2QEdHBx4eHgCAnTt3IiYmBl9++aXCsRMRqYKrqyvGjRuHtWvXil63sLAQt2/fhiAIuHHjBubOnQsLCwv06NGjxvUEQZCtd+/ePRw9ehTLli2DiYlJpfk1iBoDEwuiJqZ9+/ZITk7GsmXLEB4ejszMTOjq6sLJyQmzZ8/GlClTYGdnJxvE/axRo0Zh9erVWLZsmcLbnDRpEoDH/XNbtWqF3r17Y9myZdDS0oKRkRG8vLwQFRWFK1euoLS0FFZWVpg8eXKVc1I88eeffyItLQ1paWmwtLSUW/akPzAALFmyBNevX4eWlhYcHR2xfft2jB49WuHYiYhUZfHixZXGtSli4cKFWLhwIQDAwsICnp6e+OOPP2rtylRQUIDWrVtDIpFAKpWiY8eOCAgIwIwZMxTqMkVUXxLh6U9wIiIiIiKiOmBnOyIiIiIiqjcmFkREREREVG9MLIiIiIiIqN6YWBARERERUb0xsSAiIiIionpjYkFERERERPXGxIKIiIiIiOqNiQUREREREdUbEwsiIiIiIqo3JhZERERERFRvTCyIiIiIiKjemFgQEREREVG9/T9kJ08gfyKUDAAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_cas['app']\n", - "gap_22_cas = df_gap22_cas['simSeconds'].astype(float)*1000\n", - "gap_22_ram = df_gap22_ram['simSeconds'].astype(float)*1000\n", - "gap_22_orc = df_gap22_orc['simSeconds'].astype(float)*1000\n", - "gap_22_noDC = df_gap22_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "\n", - "gap_25_cas = df_gap25_cas['simSeconds'].astype(float)*1000\n", - "gap_25_ram = df_gap25_ram['simSeconds'].astype(float)*1000\n", - "gap_25_orc = df_gap25_orc['simSeconds'].astype(float)*1000\n", - "gap_25_noDC = df_gap25_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "\n", - "app_npb = df_npbC_cas['app']\n", - "npb_C_cas = df_npbC_cas['simSeconds'].astype(float)*1000\n", - "npb_C_ram = df_npbC_ram['simSeconds'].astype(float)*1000\n", - "npb_C_orc = df_npbC_orc['simSeconds'].astype(float)*1000\n", - "npb_C_noDC = df_npbC_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "npb_D_cas = df_npbD_cas['simSeconds'].astype(float)*1000\n", - "npb_D_ram = df_npbD_ram['simSeconds'].astype(float)*1000\n", - "npb_D_orc = df_npbD_orc['simSeconds'].astype(float)*1000\n", - "npb_D_noDC = df_npbD_noDC['simSeconds'].astype(float)*1000\n", - "\n", - "\n", - "# Multi bar Chart1\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,3])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*4, gap_22_cas[i]/gap_22_noDC[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - " plt.bar(i*4+1, gap_22_ram[i]/gap_22_noDC[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", - " plt.bar(i*4+2, gap_22_orc[i]/gap_22_noDC[i], width=1, color=cmap(3), label='Oracle' if i==0 else None)\n", - "\n", - "offset = i*4+3\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*4+1, npb_C_cas[i]/npb_C_noDC[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*4+2, npb_C_ram[i]/npb_C_noDC[i], width=1, color=cmap(2))\n", - " plt.bar(offset+i*4+3, npb_C_orc[i]/npb_C_noDC[i], width=1, color=cmap(3))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", - "plt.legend(fontsize=8, ncol=3)\n", - "plt.tight_layout()\n", - "\n", - "# Multi bar Chart2\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,3])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*4, gap_25_cas[i]/gap_25_noDC[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - " plt.bar(i*4+1, gap_25_ram[i]/gap_25_noDC[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", - " plt.bar(i*4+2, gap_25_orc[i]/gap_25_noDC[i], width=1, color=cmap(3), label='Oracle' if i==0 else None)\n", - "\n", - "offset = i*4+3\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*4+1, npb_D_cas[i]/npb_D_noDC[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*4+2, npb_D_ram[i]/npb_D_noDC[i], width=1, color=cmap(2))\n", - " plt.bar(offset+i*4+3, npb_D_orc[i]/npb_D_noDC[i], width=1, color=cmap(3))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*4+1, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Execution time\\nnormalized to no-DRAM-$\")\n", - "plt.legend(fontsize=8, ncol=3)\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 73, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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69bFxIkTcfjwYXz66acICwuTthUUFEgHcwOvv6FOT0+XjgV7n3R0dIp9u+/h4YETJ06o3YeRspT3/Hn73NRJea9fV1dXXL16FXl5edJl586de5/xKq1q1apq+7svjzq+18ujZs2axa6eJiQkaPQ3zK6ursXeKwH1ei2U9/fh8uXLePHihXTdmJgYGBkZwd7eXlVxi3n7uZKZmSktii5cuICioiL897//RcuWLVG3bl08efJEVVGVSubCwtfXF99++22plVVeXh5mzpyJbt26KTTcx+jBgweYNGkS4uPjsW3bNqxcuRLjx4+Hk5MThg0bhhEjRiAyMhKJiYmIjo7Gzp07VR0ZQNm5S3PgwAGsWLECsbGxuH//Pn755RcUFRXB1dX1PacuTk9PD0FBQZg6dSp++eUX3LlzBzExMdiwYQP8/f1hZWWFvn374uTJk7h79y52796N06dPqzRzaeT5v3jfzpw5g4ULF+L8+fN48OAB9uzZg+fPn0NfXx/BwcE4ffo07t+/j8OHDyMhIQH169fHixcvEBgYiOjoaNy/fx8nT57EuXPnihUNVatWxddff40zZ87gwoULCAgIQMuWLVVyid/JyQlnzpzBvXv38M8//yAwMBCZmZkYNGgQzp8/j4SEBGzatAnx8fHvPZssynv+ODk54fjx43j8+LHa3DjijfJev59//jmKioowevRo3Lx5E4cOHcKyZcsAQC3vblUaJycnREVFITk5uVj3EHWmru/18ujUqRNWrVqFS5cu4fz58xgzZozGdGsszZdffom4uDgEBQXh1q1b2Llzp/QOV6p+LZT19+HNe31+fj5GjhyJGzdu4Pfff0dISAgCAwOhpSXXDU6VplOnTti0aRNOnDiBq1evYtiwYdIv9FxcXPDq1SusXLkSd+/exaZNm/Djjz+qOLGSyDoY4+HDh8LS0lI4ODiIxYsXi19//VVERkaKRYsWCXt7e2FhYSEePHigvNEgH4EOHTqIsWPHijFjxggTExNhamoqpk+fLh1I+eLFCzFx4kRhbW0tdHR0hIuLi9i4caOKU78799uDt0+cOCE6dOggTE1Nhb6+vvDw8BA7duxQUfriCgsLxfz584Wjo6OoWrWqcHBwEAsXLhRCCHHv3j3Rr18/YWJiIgwMDETTpk1VMji4PO/6v1D14NsbN24IX19fUbNmTaGrqyvq1q0r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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAxYAAADSCAYAAADXL1aYAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA+fUlEQVR4nO3deVxN+f8H8NettGjTnjaVKFrt61BE1mSMpTEIwxgy4mskg+zbmGnsxlYY61iamBlbhKFsI3uE7EXTvlCq8/vDw/25Wtxbt27xej4ePR7O+Zxz7uvk3tt938/5nI9IEAQBMtizZw++/PJLFBYWonPnzjhy5AgAYOHChTh16hT+/vtvWQ5HREREREQfAZGshQUAJCUlITExEa6urlBSUgIAnD9/Hjo6OnBwcJB7SCIiIiIiqt6kLiysrKzg7e0Nb29vdOrUCSoqKpWdjYiIiIiIagglaTfcunUr1NTUMG7cOBgaGmLgwIHYtm0b0tPTKzEeERERERHVBOW6FOrGjRuIiIjAH3/8gdjYWLRt21bcm2Fra1sZOYmIiIiIqBorV2HxrsTERBw8eBARERGIjIyEra0tFi9ejJ49e8orIxERERERVXMVLizelZubi8OHD0NbWxuenp7yOiwREREREVVzFSosBEHAiRMn8PLlS7Rt2xZ6enryzEZERERERDWE1IO309PTMWzYMDg7O2PUqFHIzMzEZ599Bk9PT/Tu3RuNGjXC1atXKzMrERERERFVU1L3WHz99dc4deoUhg0bhgMHDkBJSQmCIOCXX36BkpISpkyZAi0tLRw4cKCyM8ukqKgIz549g7a2NkQikaLjEBERERHVGIIgICsrC2ZmZuL560ojdWFhbm6O7du3o2PHjnj69CksLS1x/PhxuLu7A3gzQZ63tzeSkpIqfALy9OTJE1haWio6BhERERFRjfX48WNYWFiUuY3Us9w9f/4cDRs2BPCmyFBXV5f4wG5lZYXk5ORyRq082traAN78MnR0dBSchohIfnJycmBmZgYAePbsGTQ1NRWciIiIPjaZmZmwtLQUf6Yui9SFRVFREZSVlcXLysrKEpcWVdfLjN7m0tHRYWFBRB+Vd9+TdXR0WFgQEVGlkeazvtSFBQBs2LABWlpaAICCggKEhYXB0NAQAJCVlVWOiERERERE9DGQeoyFtbW1VJVKQkJChUPJU2ZmJnR1dZGRkcEeCyL6qOTk5Ii/7MnOzmaPBRERyZ0sn6Wl7rF48OBBRXMVs3DhQuzbtw9xcXHQ0NBA27ZtsXjxYtjb24u3efXqFf73v/9h586dyMvLg5eXF1avXg0TExO55yEiIiIi6QmCgIKCAhQWFio6ClVQrVq1JC6xLQ+ZLoWSt5MnT2LcuHFo0aIFCgoKMG3aNHTt2hU3b94Uf/M2ceJE/Pnnn/j999+hq6sLf39/fP755zhz5owioxMRERF90vLz85GYmIjc3FxFRyE5EIlEsLCwEPeEl+sY0l4K9fLlS0RGRqJXr14AgKCgIOTl5YnblZWVMXfuXKirq5c7THJyMoyNjXHy5El06NABGRkZMDIywvbt2/HFF18AAOLi4tCoUSNER0ejdevWHzwmL4UiArzDe1Zo/wifP+WUhOSJl0IRkaIUFRUhPj4eysrKMDIygqqqarW9kQ99mCAISE5ORm5uLho0aCDRc1Epl0Jt3rwZf/75p7iwWLlyJRwdHaGhoQHgzQd+MzMzTJw4sTznAwDIyMgAAOjr6wMALl26hNevX8PT01O8jYODA6ysrKQuLIiIiIhIvvLz81FUVARLS0vUrl1b0XFIDoyMjPDgwQO8fv263JdESV1YbNu2DVOmTJFYt337dtja2gIAfvvtN6xatarchUVRURECAgLQrl07ODk5AQCSkpKgqqqKOnXqSGxrYmJS6kR8eXl5Ej0pmZmZ5cpDRERERGX70EzMVHPIo8dJ6sLi7t27cHZ2Fi+rq6tLPJlatmyJcePGlTvIuHHjcP36dfzzzz/lPgbwZkD47NmzK3QMouqmdfDhCu1v3EROQYiIiMpQ0b9XpYmZ7SXVdgUFBZg/fz527NgBFRUVqKiooGXLlliyZEmxL6qryuTJk6GlpYVZs2bJtJ9IJEJaWppMucuzjzxJXVikp6dL9AS8P8t2UVGRRLss/P39cfDgQZw6dUpiqnBTU1Pk5+cjPT1d4hf0/PlzmJqalnisoKAgTJo0Sbz8drZAIiIiIvq4jRw5EqmpqYiOjoaenh4EQcCePXuQmpqqsA/bnxKp+68sLCxw/fr1UtuvXr0qURRIQxAE+Pv7Y//+/Th+/DhsbGwk2ps1a4ZatWohMjJSvO727dt49OgR2rRpU+Ix1dTUxLNsc7ZtIiIiok/D3bt38fvvvyM0NBR6enoA3nyD379/f9ja2iIpKQkeHh5o1qwZHB0d4e/vj6KiIgBATEwMmjVrBjc3Nzg5OWHNmjUA3oz//frrr+Hk5ARXV1eMGDECABAZGYk2bdqgSZMmcHR0xMaNG8U5EhMT4eXlhcaNG8PT0xNPnjwRt71+/RpTp05Fy5Yt4ebmhgEDBiAtLU2m85w8eTJatGgBNzc3dOjQAbdv3y62jSAICAwMhLe3N3JzcxEfH4+ePXuiRYsWcHFxwcqVK2X75UpJ6h6LHj16YObMmejZs2exOz+9fPkSs2fPRs+est15Zty4cdi+fTv++OMPaGtri8dN6OrqQkNDA7q6uhg5ciQmTZoEfX196OjoYPz48WjTpg0HbhMRERGR2L///osGDRrA0NCwxPY6dergwIED0NLSQmFhIfr06YPdu3dj0KBBWLhwISZPngxfX18AEH/YDwgIgIaGBq5evQolJSXxFTtNmzbFP//8A2VlZaSmpqJJkybw8vKChYUFvvvuO7Rs2RKHDx/G06dP4ebmBgcHBwDAjz/+CE1NTZw/fx4AMHfuXEyfPh2rVq2S+jwDAwOxdOlSAMDOnTsxYcIEHDp0SNyel5cHX19fGBgYYP/+/QAAX19f/Pbbb3BwcEBubi5at26NVq1aoUWLFrL8ij9I6sJi2rRp2L17N+zt7eHv74+GDRsCeNODsHLlSvE8FLJ4Ww26u7tLrA8NDYWfnx8AICQkBEpKSujXr5/EBHlERERERNIqKipCYGAg/vnnHwiCgBcvXsDJyQmDBg2Ch4cH5s6di/j4eHTq1Ant27cHABw8eBDnzp0Tjys2MjICAKSkpGDkyJG4c+cOVFRUkJKSguvXr8PCwgKRkZHiD/7m5ubw9vYWZwgPD0dGRgb27t0L4M3dtaytrWU6j6NHj2LFihXIyspCUVERUlNTJdp79uyJPn36YMaMGQCAmzdv4saNGxg0aJB4m6ysLNy8eVNxhYWJiQnOnj2Lb7/9FlOnTsXb6S9EIhG6dOlSrtmwpZlCQ11dHatWrZKpkiMiIiKiT0vTpk0RHx+PlJQUGBgYFGv/+eef8eLFC5w7dw7q6uqYNGkSXr16BeBNz0SfPn1w7NgxTJs2DU5OTmV+kT1mzBj06NEDe/fuhUgkQtOmTcXHet+7d1sSBAErVqxA165dy3WOjx49gr+/Py5cuID69evj6tWr6NChg8Q2nTp1wtGjRzFhwgTo6OhAEATo6+sjNja2XI8pC5nuEWZjY4NDhw4hOTkZMTExiImJQXJyMg4dOiS+7SwRERERUVWzs7NDv379MHLkSKSnpwN480F+7969uH//PtLS0mBqagp1dXUkJSXh999/F+97+/Zt2NjYYNSoUZg2bRpiYmIAAN7e3li6dKl4LMbbS6HS0tJQr149iEQinDp1CleuXBEfy9PTE5s2bQLwZrxFRESEuM3HxwchISHi2cpzc3Nx48YNqc8xIyMDtWrVQt26dSEIQoljJaZNm4bPP/8cnp6eSElJgb29PXR0dBAaGire5u7du8V6OuRB6h6Ld+nr66Nly5byzkJEREREVG6bNm3CvHnz0KpVK6ioqKCoqAgdOnRA586dMWHCBHzxxRdwdHSEmZmZxATMK1euxPHjx6GqqgplZWX89NNPAN5ckj9x4kQ4OzujVq1aaNGiBdavX49FixZh7NixmDt3Ltzc3NCqVSvxsZYtWwY/Pz80btwY5ubm6NSpk7gtMDAQeXl5aNWqlbgnIzAwEI6OjiWej6Ojo0SPx5MnTzBo0CA4OjrCwMAAPj4+Je4XEBAATU1NdOrUCYcPH8bBgwcREBCAkJAQFBYWwtDQENu3by/377k0IkGK65HGjBmD6dOnS3XXp127dqGgoACDBw+WS8CKkmUacqLqquLzWCyv0P4RPn9WaH+qHDk5OdDS0gIAZGdnQ1NTU8GJiOhT8erVKyQkJMDGxqbYTX2oZirt/1SWz9JS9VgYGRnB0dER7dq1Q+/evdG8eXOYmZlBXV0daWlpuHnzJv755x/s3LkTZmZmWLduXcXOjIiIiIiIahSpCou5c+fC398fGzZswOrVq3Hz5k2Jdm1tbXh6emLdunXo1q1bpQQlIiIiIqLqS6a7Qv3www/44YcfkJaWhkePHuHly5cwNDRE/fr1Ja7/IiIiIiKiT0u5Bm/r6emJZzQkIiIiIiKS6XazREREREREJWFhQUREREREFcbCgoiIiIiIKqxcYyyIiIiIiN7nHd6zUo4rzXxKbm5uAID8/Hzcvn0bzs7OAAB7e3ssXrwY9evXh7OzMwoLC/H69Wt89tlnCA4OFs/T5ufnh6NHj8LIyAivXr1CixYt8Ouvv6J27drixwgODsa8efNw//591KtXT7ze3d0dZ8+exZMnT2BsbAwAuH//Puzs7ODt7Y3w8HA5/SaqN6l7LF6+fImIiAhkZWUVa8vMzERERATy8vLkGo6IiIiISBqxsbGIjY3FX3/9BW1tbfHyrl27AEC87tq1a7h69Srq1q2Ltm3bIiMjQ3yM77//HrGxsbhy5Qru37+PlStXituKiooQFhYGd3d3hIaGFnt8FxcXbN26Vby8adMmNGvWrBLPuPqRurBYt24dli1bBm1t7WJtOjo6WL58OTZs2CDXcERERERE8qaqqoo5c+bA3Nwcv/32W7F2NTU1tG/fHg8fPhSvO3r0KExMTLB06VKEhoaiqKhIYp9hw4Zh8+bNAN4UIbt27cKXX35ZuSdSzUhdWGzbtg0BAQGltgcEBIh/mURERERE1V3Lli1x48aNYuszMjIQFRWFfv36iddt3LgRI0aMQJMmTWBgYIBjx45J7GNpaQlTU1OcO3cOR44cQfPmzT+56RmkLizi4+Ph6upaaruLiwvi4+PlEoqIiIiIqLIJgiCx/OOPP8LFxQUmJiawsLCAh4cHACAlJQVHjhyBr68vAGDEiBHYuHFjseO9Xf+2CPnUSF1YFBQUIDk5udT25ORkFBQUyCUUEREREVFlu3DhApycnMTL33//Pa5evYo7d+7g4sWLWLt2LQBg69atKCgogKurK6ytrbF48WIcOHAAKSkpEsfz8fHB4cOHceXKFXTu3LlKz6U6kLqwcHR0LNbl864jR47A0dFRLqGIiIiIiCpLfn4+Zs+ejSdPnmDw4MHF2q2srLBixQrMmTMHL1++xMaNG7Fnzx48ePAADx48wOPHj9G7d+9i4zPU1dUREhKC5cuXQ0np05vVQeozHjFiBObOnYuDBw8Waztw4ADmz5//SXb5EBEREVH1l5WVBTc3Nzg5OcHZ2RmPHz/G2bNnoaurW+L23t7ecHBwwPLly/HixQt4enpKtA8ePLjEy6E+//xzdOvWrVLOoboTCe9fXFaGr776Ctu3b4eDgwPs7e0BAHFxcbhz5w4GDBiAHTt2VFrQ8srMzISuri4yMjKgo6Oj6DhE5dI6+HCF9jdusrxC+0tz/3Cqejk5OdDS0gIAZGdnQ1NTU8GJiOhT8erVKyQkJMDGxgbq6uqKjkNyUNr/qSyfpWXqo/ntt9+wc+dONGzYEHfu3MHt27dhb2+PHTt2VMuigoiIiIiIqobMM28PGDAAAwYMKLb+5cuXuHz5Mtq2bSuXYEREREREVHPIbVTJnTt38Nlnn8nrcEREREREVIN8esPViYiIiEgu3p99mmouGYZdl0rmS6Hk6dSpU/jxxx9x6dIlJCYmYv/+/fDx8RG3+/n5FZvN28vLC4cOHaripERERET0lqqqKpSUlPDs2TMYGRlBVVUVIpFI0bGonARBQHJyMkQiEWrVqlXu4yi0sMjJyYGrqytGjBiBzz//vMRtunXrhtDQUPGymppaVcUjIiIiohIoKSnBxsYGiYmJePbsmaLjkByIRCJYWFhAWVm53MeQurCIiIgosz0hIUHmB+/evTu6d+9e5jZqamowNTWV+dhEREREVHlUVVVhZWWFgoICFBYWKjoOVVCtWrUqVFQAMhQW716iVJWioqJgbGwMPT09dOrUCfPmzYOBgYFCshARERHR/3t76UxFLp+hj4fUhYUiBud069YNn3/+OWxsbHDv3j1MmzYN3bt3R3R0dKkVVV5eHvLy8sTLmZmZVRWXiIiIiOiTJbe7Qr148QILFiyQ1+EAAIMGDYK3tzecnZ3h4+ODgwcP4sKFC4iKiip1n4ULF0JXV1f8Y2lpKddMRERERERUnNwKi8TERMyYMUNehyuRra0tDA0Ncffu3VK3CQoKQkZGhvjn8ePHlZqJiIiIiIgUfFcoWT158gQpKSmoW7duqduoqanxzlFERERERFVMoYVFdna2RO9DQkICYmNjoa+vD319fcyePRv9+vWDqakp7t27hylTpsDOzg5eXl4KTE1ERDWNd3jPCu0f4fOnnJIQEX28FFpYXLx4ER4eHuLlSZMmAQCGDRuGNWvW4OrVq9i8eTPS09NhZmaGrl27Yu7cueyRICIiIiKqZqQuLN5+6C9NcnKyzA/u7u5e5vThhw8flvmYRERERERU9aQuLC5fvvzBbTp06FChMERERO9rHVzxL5mMm8ghCBERlUnqwuLEiROVmYOIiIiIiGowud1uloiIiIiIPl0sLIiIiIiIqMJYWBARERERUYWxsCAiIiIiogqTubB49OhRibeIFQQBjx49kksoIiIiIiKqWWQuLGxsbEqcsyI1NRU2NjZyCUVERERERDWLzIWFIAgQiUTF1mdnZ0NdXV0uoYiIiIiIqGaReeZtkUiEGTNmoHbt2uK2wsJCnDt3Dm5ubnIPSERERERE1Z/MM28LgoBr165BVVVV3KaqqgpXV1dMnjxZ/gmJiIiIiKjak3nm7eHDh2PZsmXQ0dGptFBERERERFSzSF1YvBUaGloZOYiIiIiIqAaTubAAgIsXL2L37t149OgR8vPzJdr27dsnl2BERERERFRzyFxY7Ny5E0OHDoWXlxeOHDmCrl274s6dO3j+/Dn69u1bGRmJ6BPnHd6zQvtH+PwppyRERERUGplvN7tgwQKEhITgwIEDUFVVxbJlyxAXF4cBAwbAysqqMjISEREREVE1J3Nhce/ePfTs+ebbQ1VVVeTk5EAkEmHixIlYt26d3AMSEREREVH1J3Nhoaenh6ysLACAubk5rl+/DgBIT09Hbm6ufNMREREREVGNIPMYiw4dOuDo0aNwdnZG//79MWHCBBw/fhxHjx5F586dKyMjERERERFVczIXFitXrsSrV68AAD/88ANq1aqFs2fPol+/fpg+fbrcAxIRERERUfUnc2Ghr68v/reSkhKmTp0q10BERERERFTzyDzGgoiIiIiI6H0sLIiIiIiIqMLKNfO2vJw6dQo//vgjLl26hMTEROzfvx8+Pj7idkEQEBwcjPXr1yM9PR3t2rXDmjVr0KBBA8WFJiKZtQ4+XKH9jZvIKQgRERFVGoX2WOTk5MDV1RWrVq0qsX3JkiVYvnw51q5di3PnzkFTUxNeXl7iweNERERERFQ9SN1jERoaik6dOqFevXpye/Du3buje/fuJbYJgoBffvkF06dPR58+fQAAW7ZsgYmJCcLDwzFo0CC55SAiIiIiooqRusdi7NixsLW1ha2tLUaOHInffvsNT58+rbRgCQkJSEpKgqenp3idrq4uWrVqhejo6Ep7XCIiIiIikp3UPRbp6ek4e/YsTp48iRMnTmD79u3Iz8+HnZ0dPDw84OHhAXd3d5iYmMglWFJSEgAUO56JiYm4rSR5eXnIy8sTL2dmZsolDxERERERlU7qHgs1NTV4eHhg1qxZOHnyJNLS0nDs2DEMHDgQN2/ehJ+fH8zNzSszq1QWLlwIXV1d8Y+lpaWiIxERERERffTKPXhbSUkJSkpKEIlEEIlEEAQBVlZWcgtmamoKAHj+/LnE+ufPn4vbShIUFISMjAzxz+PHj+WWiYiIiIiISiZ1YZGfn49Tp05hzpw5cHd3h66uLr755hskJiZi1KhRiI+Px/379+UWzMbGBqampoiMjBSvy8zMxLlz59CmTZtS91NTU4OOjo7EDxERERERVS6px1jo6urC2NgYvXv3xrhx47Bz584yew6kkZ2djbt374qXExISEBsbC319fVhZWSEgIADz5s1DgwYNYGNjgxkzZsDMzExirgsiIiIiIlI8qQsLV1dXXL58GadOnRJfBuXu7g4DA4NyP/jFixfh4eEhXp40aRIAYNiwYQgLC8OUKVOQk5OD0aNHIz09He3bt8ehQ4egrq5e7sckIiIiIiL5k7qwiImJQXZ2Nv755x+cOHECS5Ysga+vLxo2bAh3d3d07NgRHTt2hLGxsdQP7u7uDkEQSm0XiUSYM2cO5syZI/UxiYiIiIio6kldWACAlpYWunXrhm7dugEAsrKycPr0aRw9ehSjRo1CdnY2CgoKKiUoERERERFVXzIVFm8VFRXhwoULiIqKwokTJ3DmzBnk5OTIdVZuIiIiIiKqOaQuLM6fP4+oqChERUXhn3/+QXZ2NiwsLODu7o7ly5fDw8MD1tbWlRiViIiIiIiqK6kLi9atW8PU1BQeHh74+eef4eHhgfr161dmNiKij4J3eM8K7R/h86eckhAREVUeqQuLW7duwd7evjKzEBERERFRDSX1BHn29vbIysrCpUuXkJ2dDQD4999/MXToUPTv3x/btm2rtJBERERERFS9Sd1jcerUKfTq1QvZ2dnQ09PDjh078MUXX8Dc3BzKysrYt28fcnNzMWrUqMrMS0RERERE1ZDUPRbTp09H//798fjxYwQEBGDgwIHw9/fHrVu3cP36dcyePRurVq2qzKxERERERFRNSd1jcfXqVaxbtw7m5uYIDAzErFmzMHDgQHH7oEGDsHjx4koJSRz8SURERETVm9Q9FpmZmdDX1wcAqKqqonbt2tDW1ha3a2trIzc3V/4JiYiIiIio2pO6sBCJRBCJRKUuExERERHRp0vqS6EEQUDnzp2hovJml9zcXPTu3RuqqqoAgIKCgspJSB8FXspFRERE9HGTurAIDg6WWO7Tp0+xbfr161fxREREVK3wiwEiUiS+B9Uc5S4siIiIiIiI3pK6sCAiIiIqD37jTPRpYGFBREREVAYWRkTSkfquUERERERERKVhYUFERERERBXGS6FIKq2DD1dof+MmcgpCpAB8/tOnjq8BIpKGVIXF8uXLpT7gd999V+4wRERERERUM0lVWISEhEgsJycnIzc3F3Xq1AEApKeno3bt2jA2NmZhQR8lDtwjIiIiKptUYywSEhLEP/Pnz4ebmxtu3bqF1NRUpKam4tatW2jatCnmzp1b2XmJiIiIiKgaknnw9owZM7BixQrY29uL19nb2yMkJATTp0+XazgiIiIiIqoZZC4sEhMTUVBQUGx9YWEhnj9/LpdQRERERERUs8h8V6jOnTvjm2++wYYNG9C0aVMAwKVLl/Dtt9/C09NTruFmzZqF2bNnS6yzt7dHXFycXB+HiOhjxjv6EBFRVZC5sNi0aROGDRuG5s2bo1atWgCAgoICeHl5YcOGDXIP6OjoiGPHjomXVVR4h1wiIiKimoJfbnw6ZP6UbmRkhL/++gt37twR9xw4ODigYcOGcg8HvCkkTE1NK+XYVYkvKiIiIiqPin6GiJntJackRGUr99f/1tbWEAQB9evXr9RehPj4eJiZmUFdXR1t2rTBwoULYWVlVer2eXl5yMvLEy9nZmZWWjYiIqKqwFteE1FNIHNFkJubi/Hjx2Pz5s0AgDt37sDW1hbjx4+Hubk5pk6dKrdwrVq1QlhYGOzt7ZGYmIjZs2fjs88+w/Xr16GtrV3iPgsXLiw2LoOIPUZERERElUvmwiIoKAhXrlxBVFQUunXrJl7v6emJWbNmybWw6N69u/jfLi4uaNWqFerVq4fdu3dj5MiRpeabNGmSeDkzMxOWlpZyy0REREQ1C79cIqoaMhcW4eHh2LVrF1q3bg2RSCRe7+joiHv37sk13Pvq1KmDhg0b4u7du6Vuo6amBjU1tUrNQUREREREkmQuLJKTk2FsbFxsfU5OjkShURmys7Nx7949DBkypFIfh4iIiOhjwTE6VFVkniCvefPm+PPP/3+CvS0mNmzYgDZt2sgvGYDJkyfj5MmTePDgAc6ePYu+fftCWVkZvr6+cn0cIiIiIiKqGJl7LBYsWIDu3bvj5s2bKCgowLJly3Dz5k2cPXsWJ0+elGu4J0+ewNfXFykpKTAyMkL79u0RExMDIyMjuT4OERERERFVjMyFRfv27REbG4tFixbB2dkZR44cQdOmTREdHQ1nZ2e5htu5c6dcj0dERERERJWjXBNQ1K9fH+vXr5d3FiIiIiIiqqFkHmPh6emJsLAwTjxHRERERERiMvdYODo6IigoCGPHjkXPnj3x1VdfoUePHqhVq1Zl5CMiIqrxOI8CEX0KZO6xWLZsGZ4+fYrw8HBoampi6NChMDExwejRo+U+eJuIiIiIiGoGmQsLAFBSUkLXrl0RFhaG58+f49dff8X58+fRqVMneecjIiIiIqIaoFyDt99KSkrCzp078dtvv+Hq1ato2bKlvHIREREREVENInOPRWZmJkJDQ9GlSxdYWlpizZo18Pb2Rnx8PGJiYiojIxERERERVXMy91iYmJhAT08PAwcOxMKFC9G8efPKyEVERERERDWITIWFIAhYvnw5Bg8ejNq1a1dWJiIiIiIiqmFkuhRKEASMGzcOT58+raw8RERERERUA8nUY6GkpIQGDRogJSUFDRo0qKxMREREREQfBe/wnhXaP8LnTzklqXwyD95etGgRvv/+e1y/fr0y8hARERERUQ0k8+DtoUOHIjc3F66urlBVVYWGhoZEe2pqqtzCEREREREpUuvgwxXa37iJnILUADIXFr/88kslxCAiIiIioppM5sJi2LBhlZGDiIiIiIhqMJnHWADAvXv3MH36dPj6+uLFixcAgL///hs3btyQazgiIiIiIqoZZC4sTp48CWdnZ5w7dw779u1DdnY2AODKlSsIDg6We0AiIiIiIqr+ZC4spk6dinnz5uHo0aNQVVUVr+/UqRNiYmLkGo6IiIiIiGoGmQuLa9euoW/fvsXWGxsb47///pNLKCIiIiIiqllkLizq1KmDxMTEYusvX74Mc3NzuYQiIiIiIqKaRebCYtCgQQgMDERSUhJEIhGKiopw5swZTJ48GUOHDq2MjEREREREVM3JXFgsWLAADg4OsLS0RHZ2Nho3bowOHTqgbdu2mD59emVkJCIiIiKiak7meSxUVVWxfv16zJw5E9euXUN2djaaNGmCBg0aVEY+IiIiIiKqAco1jwUAWFpaokePHujXrx9ycnKQlpYmz1wSVq1aBWtra6irq6NVq1Y4f/58pT0WERERERHJTubCIiAgABs3bgQAFBYWomPHjmjatCksLS0RFRUl73zYtWsXJk2ahODgYPz7779wdXWFl5eXeGI+IiIiIiJSPJkLiz179sDV1RUAcODAAdy/fx9xcXGYOHEifvjhB7kH/PnnnzFq1CgMHz4cjRs3xtq1a1G7dm1s2rRJ7o9FRERERETlI/MYi//++w+mpqYAgL/++gsDBgxAw4YNMWLECCxbtkyu4fLz83Hp0iUEBQWJ1ykpKcHT0xPR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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_cas['app']\n", - "gap_22_cas = df_gap22_cas['totBW'].astype(float)\n", - "gap_22_ram = df_gap22_ram['totBW'].astype(float)\n", - "gap_22_noDC = (df_gap22_noDC['farAvgRdBWSys'].astype(float)+df_gap22_noDC['farAvgWrBWSys'].astype(float))/1000000000\n", - "\n", - "\n", - "gap_25_cas = df_gap25_cas['totBW'].astype(float)\n", - "gap_25_ram = df_gap25_ram['totBW'].astype(float)\n", - "gap_25_noDC = (df_gap25_noDC['farAvgRdBWSys'].astype(float)+df_gap25_noDC['farAvgWrBWSys'].astype(float))/1000000000\n", - "\n", - "app_npb = df_npbC_cas['app']\n", - "npb_C_cas = df_npbC_cas['totBW'].astype(float)\n", - "npb_C_ram = df_npbC_ram['totBW'].astype(float)\n", - "npb_C_noDC = (df_npbC_noDC['farAvgRdBWSys'].astype(float)+df_npbC_noDC['farAvgWrBWSys'].astype(float))/1000000000\n", - "\n", - "npb_D_cas = df_npbD_cas['totBW'].astype(float)\n", - "npb_D_ram = df_npbD_ram['totBW'].astype(float)\n", - "npb_D_noDC = (df_npbD_noDC['farAvgRdBWSys'].astype(float)+df_npbD_noDC['farAvgWrBWSys'].astype(float))/1000000000\n", - "\n", - "\n", - "# Multi bar Chart1\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "#plt.ylim([0,2.5])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - " plt.bar(i*3+1, gap_22_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", - "\n", - "offset = i*3+2\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_C_cas[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*3+2, npb_C_ram[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "#plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Observed BW at LLC (GB/s)\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "\n", - "# Multi bar Chart2\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "#plt.ylim([0,2.5])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - " plt.bar(i*3+1, gap_25_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", - "\n", - "offset = i*3+2\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_D_cas[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*3+2, npb_D_ram[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "#plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Observed BW at LLC (GB/s)\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 86, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "x1 = df_gap22_cas['app']\n", - "y1 = 100 * df_gap22_cas['numRdMissClean'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", - "y2 = 100 * df_gap22_cas['numRdMissDirty'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", - "y3 = 100 * df_gap22_cas['numWrMissClean'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", - "y4 = 100 * df_gap22_cas['numWrMissDirty'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(6,3)\n", - "plt.ylim([0,110])\n", - "\n", - "for i,app in enumerate(x1): \n", - " plt.bar(i*4, y1[i], width=3, color=cmap(1), label='Read/Clean' if i==0 else None)\n", - " plt.bar(i*4, y2[i], bottom = y1[i], width=3, color=cmap(2), label='Read/Dirty' if i==0 else None)\n", - " plt.bar(i*4, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3), label='Write/Clean' if i==0 else None)\n", - " plt.bar(i*4, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4), label='Write/Dirty' if i==0 else None)\n", - "\n", - "offset = (i+1)*4\n", - "x2 = df_npbC_cas['app']\n", - "y1 = 100 * df_npbC_cas['numRdMissClean'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", - "y2 = 100 * df_npbC_cas['numRdMissDirty'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", - "y3 = 100 * df_npbC_cas['numWrMissClean'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", - "y4 = 100 * df_npbC_cas['numWrMissDirty'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", - "\n", - "for i,app in enumerate(x2): \n", - " plt.bar(i*4+offset, y1[i], width=3, color=cmap(1))\n", - " plt.bar(i*4+offset, y2[i], bottom = y1[i], width=3, color=cmap(2))\n", - " plt.bar(i*4+offset, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3))\n", - " plt.bar(i*4+offset, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*4, list(x1)+list(x2))\n", - "plt.axvline(x=offset-2, color='black')\n", - "\n", - "plt.ylabel(\"DRAM Cache Miss Rate (%)\", fontsize=10)\n", - "plt.legend(fontsize=9, ncol=1)\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_mpki.pdf\")\n", - "\n", - "x1 = df_gap25_cas['app']\n", - "y1 = 100 * df_gap25_cas['numRdMissClean'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", - "y2 = 100 * df_gap25_cas['numRdMissDirty'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", - "y3 = 100 * df_gap25_cas['numWrMissClean'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", - "y4 = 100 * df_gap25_cas['numWrMissDirty'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(6,3)\n", - "plt.ylim([0,110])\n", - "for i,app in enumerate(x1): \n", - " plt.bar(i*4, y1[i], width=3, color=cmap(1), label='Read/Clean' if i==0 else None)\n", - " plt.bar(i*4, y2[i], bottom = y1[i], width=3, color=cmap(2), label='Read/Dirty' if i==0 else None)\n", - " plt.bar(i*4, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3), label='Write/Clean' if i==0 else None)\n", - " plt.bar(i*4, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4), label='Write/Dirty' if i==0 else None)\n", - "\n", - "offset = (i+1)*4\n", - "x2 = df_npbD_cas['app']\n", - "y1 = 100 * df_npbD_cas['numRdMissClean'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", - "y2 = 100 * df_npbD_cas['numRdMissDirty'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", - "y3 = 100 * df_npbD_cas['numWrMissClean'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", - "y4 = 100 * df_npbD_cas['numWrMissDirty'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", - "\n", - "for i,app in enumerate(x2): \n", - " plt.bar(i*4+offset, y1[i], width=3, color=cmap(1))\n", - " plt.bar(i*4+offset, y2[i], bottom = y1[i], width=3, color=cmap(2))\n", - " plt.bar(i*4+offset, y3[i], bottom = y1[i]+y2[i], width=3, color=cmap(3))\n", - " plt.bar(i*4+offset, y4[i], bottom = y1[i]+y2[i]+y3[i], width=3, color=cmap(4))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*4, list(x1)+list(x2))\n", - "plt.axvline(x=offset-2, color='black')\n", - "\n", - "plt.ylabel(\"DRAM Cache Miss Rate (%)\", fontsize=10)\n", - "plt.legend(fontsize=9, ncol=1)\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 85, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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KSnazFGqli1bYtu2bQgLC8P06dPh6uqKxYsXY+DAgcp9JkyYgIKCAowYMQI5OTlo3749du3apVNrON1K1Fwx+UKB5dMNERHR20qnJ4cDQLdu3dCtW7cyt8tkMkyfPh3Tp08vx1RERET0NtLpyeFEREREukTnR5yo8ukR07Vc+okN3FEu/RAR0duDI05EREREErFwIiIiIpKIhRMRERGRRCyciIiIiCRi4UREREQkEQsnIiIiIoleuXD6559/sHv3bjx8+BAAIITQWCgiIiIiXaR24XT37l34+/ujXr166NKlCzIyMgAAw4YNwxdffKHxgERERES6Qu3Cady4cTAwMEBaWhpMTU2V7R9++CF27dql0XBEREREukTtlcP37NmD3bt3o2bNmirtbm5uuHbtmsaCEREREekatUecCgoKVEaansrOzoaRkZFGQhERERHpIrULpw4dOmDDhg3K+zKZDAqFAuHh4fD19dVoOCIiIiJdovapuvDwcLz77rtISEhAUVERJkyYgPPnzyM7OxuHDx/WRkYiIiIinaD2iFPjxo1x+fJltG/fHj179kRBQQF69+6NxMRE1KlTRxsZiYiIiHSC2iNOAGBpaYmvv/5a01mIiIiIdNorFU45OTk4ceIEbt26BYVCobLt448/1kgwIiKif+sR07Vc+okN3FEu/dCbR+3C6bfffsPAgQORn58PuVwOmUym3CaTyVg4ERERUaWl9hynL774AkOHDkV+fj5ycnJw79495S07O1sbGYmIiIh0gtqF040bNzBmzJhS13IiIiIiqszULpwCAgKQkJCgjSxEREREOk3SHKfY2Fjlv7t27Yrx48fjwoULcHd3R5UqVVT27dGjh2YTEhEREekISYVTYGDgc23Tp09/rk0mk6GkpOS1QxERERHpIkmF07+XHCAiIiJ6G6k9x4mIiIjobaV24TRmzBgsXbr0ufbly5dj7NixmshEREREpJPULpx++eUXtGvX7rn2tm3b4ueff9ZIKCIiIiJdpHbhdPfuXVhaWj7XLpfLcefOHY2EIiIiItJFahdOdevWxa5du55r//3331G7dm2NhCIiIiLSRWp/V11oaChCQkJw+/Zt+Pn5AQDi4uLw7bffYvHixZrOR0RERKQz1C6chg4disLCQsyaNQszZswAANSqVQurVq3iF/wSERFRpaZ24QQAn376KT79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FStWaKxfIiIiotJInuO0ZcsWfPXVV88VTQDg5+eHSZMmYdOmTRoNR0RERKRLJBdOf//9N95///0yt3fu3BlnzpzRSCgiIiIiXSS5cMrOzoadnV2Z2+3s7HDv3j2NhCIiIiLSRZILp5KSEhgYlD0lSl9fH8XFxRoJRURERKSL1LqqLjg4GEZGRqVuf/YrTIiIiIgqI8mFU1BQ0Ev30eQVdURERES6RnLhFBkZqc0cRERERDpPp79yhYiIiEiXqPWVK0RERET/9jatpM4RJyIiIiKJWDgRERERScTCiYiIiEgiFk5EREREErFwIiIiIpKIhRMRERGRRCyciIiIiCRi4UREREQkEQsnIiIiIolYOBERERFJxMKJiIiISCIWTkREREQSsXAiIiIikoiFExEREZFELJyIiIiIJGLhRERERCQRCyciIiIiiVg4EREREUnEwomIiIhIIhZORERERBKxcCIiIiKSiIUTERERkUQsnIiIiIgkYuFEREREJBELJyIiIiKJDCo6gKasWLEC8+fPR2ZmJpo2bYply5ahVatWFR2LiIgqoVuJY8qno8Dy6YakqxSF048//ojQ0FBERESgdevWWLx4MQICApCUlARbW9uKjkdE9MbrEdO1XPqJDdxRLv0QvapKUTgtXLgQw4cPx5AhQwAAERER2LFjB9atW4dJkyZVcDoiojefroyw6EoOenu98YVTUVERTp06hbCwMGWbnp4e/P39cfTo0VIfU1hYiMLCQuX93NxcAEBeXp5WMhYXFmjluP/2svzMwRy6lKOgoEClraSkBADw+MHjcs1RFl35ufD1YI4X0ZX3x81jw8onh592/p9++vyEEC/fWbzhbty4IQCII0eOqLSPHz9etGrVqtTHTJ06VQDgjTfeeOONN954U97S09NfWne88SNOryIsLAyhoaHK+wqFAtnZ2bCxsYFMJqvAZE/k5eXByckJ6enpkMvlzMEczMEczMEczKFFQgjcv38fjo6OL933jS+cqlWrBn19fWRlZam0Z2Vlwd7evtTHGBkZwcjISKXNyspKWxFfmVwu14k3FHMwB3MwB3MwR2XOAQCWlpaS9nvj13EyNDRE8+bNERcXp2xTKBSIi4uDl5dXBSYjIiKiyuaNH3ECgNDQUAQFBaFFixZo1aoVFi9ejIKCAuVVdkRERESaUCkKpw8//BC3b9/GlClT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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "x1 = df_gap22_cas['app']\n", - "y1 = 100 * df_gap22_cas['numRdHit'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", - "y2 = 100 * df_gap22_cas['numWrHit'].astype(float)/(df_gap22_cas['numTotMisses'].astype(float)+df_gap22_cas['numTotHits'].astype(float))\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(6,3)\n", - "plt.ylim([0,110])\n", - "\n", - "for i,app in enumerate(x1): \n", - " plt.bar(i*4, y1[i], width=3, color=cmap(1), label='Read' if i==0 else None)\n", - " plt.bar(i*4, y2[i], bottom = y1[i], width=3, color=cmap(2), label='Write' if i==0 else None)\n", - "\n", - "offset = (i+1)*4\n", - "x2 = df_npbC_cas['app']\n", - "y1 = 100 * df_npbC_cas['numRdHit'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", - "y2 = 100 * df_npbC_cas['numWrHit'].astype(float)/(df_npbC_cas['numTotMisses'].astype(float)+df_npbC_cas['numTotHits'].astype(float))\n", - "\n", - "for i,app in enumerate(x2): \n", - " plt.bar(i*4+offset, y1[i], width=3, color=cmap(1))\n", - " plt.bar(i*4+offset, y2[i], bottom = y1[i], width=3, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*4, list(x1)+list(x2))\n", - "plt.axvline(x=offset-2, color='black')\n", - "\n", - "plt.ylabel(\"DRAM Cache Hit Rate (%)\", fontsize=10)\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_mpki.pdf\")\n", - "\n", - "x1 = df_gap25_cas['app']\n", - "y1 = 100 * df_gap25_cas['numRdHit'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", - "y2 = 100 * df_gap25_cas['numWrHit'].astype(float)/(df_gap25_cas['numTotMisses'].astype(float)+df_gap25_cas['numTotHits'].astype(float))\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(6,3)\n", - "plt.ylim([0,110])\n", - "\n", - "for i,app in enumerate(x1): \n", - " plt.bar(i*4, y1[i], width=3, color=cmap(1), label='Read' if i==0 else None)\n", - " plt.bar(i*4, y2[i], bottom = y1[i], width=3, color=cmap(2), label='Write' if i==0 else None)\n", - "\n", - "offset = (i+1)*4\n", - "x2 = df_npbD_cas['app']\n", - "y1 = 100 * df_npbD_cas['numRdHit'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", - "y2 = 100 * df_npbD_cas['numWrHit'].astype(float)/(df_npbD_cas['numTotMisses'].astype(float)+df_npbD_cas['numTotHits'].astype(float))\n", - "\n", - "for i,app in enumerate(x2): \n", - " plt.bar(i*4+offset, y1[i], width=3, color=cmap(1))\n", - " plt.bar(i*4+offset, y2[i], bottom = y1[i], width=3, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*4, list(x1)+list(x2))\n", - "plt.axvline(x=offset-2, color='black')\n", - "\n", - "plt.ylabel(\"DRAM Cache Hit Rate (%)\", fontsize=10)\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_mpki.pdf\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": 76, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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6v379/H777+rPnNLsmnTJvj4+KBly5ZF1unr65f4N4NIk0QXFuPHj4elpSUGDx6M/fv3o7CwsDJyEVEx/v77bwiCoLqGzCt16tRR/YM/efJkAIBCocCvv/6Kjz76CADw0UcfYfv27cjKyirx+AkJCVixYgVatWoFMzMz1fJBgwbB1NQURkZGcHJygouLC0JDQwG87AoZERGBdevWQS6Xw8vLC19//TUuXbok+tyWLFmCTz/9tMRttm/fjrNnzyIoKEjUsYmIqsrAgQPh4eGBadOm/ee2qampmD9/PurVq6f2uT558mSYmprC2NgY9evXh0QiwYIFC0o9VkJCApydnSucn6giRBcWqamp2Lp1KyQSCT744APY2Nhg9OjROHXqVGXkI6IyOHPmDGJjY+Hi4qJqNdiyZQsaN24Md3d3AICHhwccHBywbds2tX0zMzNhamqKmjVrwsnJCVZWVkUGSIeFhSE2NhZxcXHYu3cvbt68iaFDh6rW+/n5ISUlBXv27EGPHj0QFRWFt956CxEREQCAkSNHqgqf4lo479+/jx49euD999/H8OHDiz3Ho0ePIigoCKtWrYKLi0u5nysiosr2/fffY926dbh+/Xqx6+vXrw8TExPY2toiOzsbO3bsgIGBgWr9pEmTEBsbi0uXLiEyMhIA0Lt3b9WXuf/8PB05ciQAQBB39QCiylGRflTZ2dnCxo0bhV69egkGBgZCo0aNNNNBi4iK9ejRI0EikQhz5swpdn2nTp2EsWPHCoIgCK1btxYkEokglUpVN4lEInTo0EG1fXh4uGBmZiYkJCQIiYmJqnEV/4Rixlhs2bJFACAkJCSUmDU4OFiwt7cXBEEQ0tPThYSEBNXtn+7fvy80adJEGDp0qFBYWFjssaKiogQTExPh559/LvHxiIi0KSAgQOjfv7/qfq9evYT+/fsXO8biwoULwt9//y0oFIoixylujEV0dLQAQDh8+LAgCILa52l6erogCILg5uYmdO/evXJOjqiMRM8K9U81a9aEr68vnj59ijt37pRYmRORZtSuXRvdunXDTz/9hDFjxpTYZ/by5cs4d+4coqKi1MYjPHnyBN7e3rhx44aqyVxPTw+Ojo6icryaueT58+clbtO8eXPs3r0bAGBpaQlLS8si29y/fx+dO3eGp6cnwsPDoadXtBE1KioKffr0wffff48RI0aIyklEpC1z586Fh4dHka6rANCwYUPI5fIyH+vfn7nFfWYPHjwYX3/9NS5evFhknEV+fj7y8vI4zoIqneiuUACQk5ODTZs2oVevXqhXrx4WLlyIgQMH4urVq5rOR0T/smzZMhQUFKBVq1bYtm0brl+/jvj4eGzcuBE3btyAVCrFmjVr0KZNG3Ts2BEtWrRQ3Tp27IjWrVuXaRD3P2VkZCAtLQ0pKSk4duwYZsyYgaZNm6JZs2Z4/PgxunTpgo0bN+LSpUtISkrCL7/8gnnz5qF///4lHvP+/fvw9vaGvb095s+fj4cPHyItLQ1paWmqbY4ePYrevXvj888/h5+fn2r9kydPyv38ERFVBVdXVwwZMgSLFy8Wve+zZ8+QlpaG1NRUnDlzBpMmTULdunXRoUOHEvcZN24cvLy80LVrVyxduhRxcXG4desWtm/fjnbt2iEhIaEip0NUNmKbOD788EPBxMREqFu3rjB69Gjh1KlTldGSQkSlSElJEUJCQoSGDRsK+vr6gqmpqdCmTRvhhx9+EDIzM4XatWsL8+bNK3bf77//XrC0tBTy8vKKnW723wCobhKJRLCxsRE+/PBDITExURAEQXjx4oXw1VdfCW+99ZZgbm4u1KxZU3BychL+97//Fdu16pXw8HC1Y//z9kpAQECx6zt16iT6OSMiqkz/7golCIKQlJQkGBgYlDrd7L85ODiofd7VrVtX6NWrl3Dx4sX/zPDixQthzpw5gqurq2BkZCRYWFgIXl5eQkREhJCfn1+BsyMqG4kgiBvtM2TIEAwZMgS+vr6qprlXrly5ghYtWpS/yiEiIiIiIp0kurD4t2fPnmHLli1YvXo1zp8/z+lniYiIiIjeQOUaYwEAx48fR0BAAGxsbDB//nx06dIFp0+f1mQ2IiIiIiLSEaJmhUpLS0NERATWrFkDhUKBDz74ALm5udi9ezeaN29eWRmJiIiIiKiaK3OLRd++feHk5IRLly5h4cKFSElJwZIlSyozGxERERER6Ygyt1gcOHAAn3/+OUaNGoUmTZpUZiYiIiIiItIxZW6x+Ouvv/Ds2TN4enqibdu2+Omnn/Do0aPKzEZERERERDpC9KxQ2dnZ2LZtG9auXYszZ86gsLAQCxYswMcffwwzM7PKyklERERERNVYhaabjY+Px5o1a7BhwwZkZGSgW7du2LNnjybzERERERGRDqjwdSwAoLCwEL///jvWrl3LwoKIiIiI6A2kkcKCiIiIiIjebOW+QB4REREREdErLCyIiIiIiKjC/h93Oh1K/dn24AAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAxYAAADSCAYAAADXL1aYAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAABGE0lEQVR4nO3deViN+f8/8OfptKpOR9FmKhGyhckWhhDZxzJmihmVPgwjgwwmZhjGYDAazGBshbGPZQzDILJmi7IWkxJaZGmn7dy/P/zcX2dadOq0HJ6P6zrX5dz3fe6ed845ndd5bxJBEASowNLSEv/88w9atGiBLVu2YNasWYiMjMSGDRuwevVqXLlyRZXTERERERHRW0BL1QekpaXB1NQUAHDo0CEMGTIENWrUQN++fXHnzh21ByQiIiIioupP5cLCxsYGYWFhyMrKwqFDh9CzZ08AwLNnz6Cvr6/2gEREREREVP1pq/qAiRMnYvjw4TAyMoKdnR1cXV0BACdPnkTz5s3VnY+IiIiIiDSARNUxFgBw6dIl3L9/Hz169ICRkREA4MCBA5DL5ejYsaPaQxIRERERUfVWpsKCiIiIiIjodaXqCuXv71/qEy5ZsqTMYYiIiIiISDOVqrD47xSyly9fRn5+Pho1agQAuH37NqRSKZydndWfkIiIiIiIqr1SFRbHjx8X/71kyRIYGxtjw4YNqFmzJoCXM0L5+Pjggw8+qJiURERERERUrak8xqJOnTo4fPgwmjZtqrT9+vXr6NmzJxISEtQasDIoFAokJCTA2NgYEomkquMQEREREVULgiAgIyMD1tbW0NIqeaUKlaebTU9PR0pKSqHtKSkpyMjIUPV01UJCQgJsbGyqOgYRERERUbV0//59vPfeeyUeo3JhMWjQIPj4+OCnn35C27ZtAQDnz5/HlClTMHjw4LIlrWLGxsYAXv7CZDJZFachIiq7rKwsWFtbA3j5pYmhoWEVJyIiIk2Wnp4OGxsb8fNySVQuLFatWoWvvvoKw4YNQ15e3suTaGvD19cXixYtUj1tNfCq+5NMJmNhQUQaTSqViv+WyWQsLIiISC1KM1ygzOtYZGVlISYmBgBQv359jf7jlZ6eDhMTE6SlpbGwICKNlpWVJS5cmpmZqdHvzUREVPVU+ZyscovFK4aGhnBycirrw4mIiIiI6C1SpsLi0qVL2LFjB+Lj45Gbm6u0b/fu3aU+z/z587F7925ERUXBwMAAHTp0wI8//iiujwEAL168wOTJk7Ft2zbk5OTA3d0dK1asgIWFhXhMfHw8xo4di+PHj8PIyAheXl6YP38+tLXLXDcpUSgUha6TiKoXHR0dpW5AREREVLlU/uS9bds2jBgxAu7u7jh8+DB69uyJ27dvIzk5GYMGDVLpXCdOnMC4cePQpk0b5OfnY/r06ejZsydu3rwpNt9PmjQJBw4cwM6dO2FiYgI/Pz8MHjwYZ86cAQAUFBSgb9++sLS0xNmzZ5GYmIgRI0ZAR0cH8+bNU/XyCsnNzUVsbCwUCkW5z0VEFUsul8PS0pLTRhMREVUBlcdYODk54fPPP8e4ceNgbGyMyMhI2Nvb4/PPP4eVlRVmz55d5jApKSkwNzfHiRMn0LlzZ6SlpaF27drYsmULPvroIwBAVFQUGjdujLCwMLRv3x4HDx5Ev379kJCQILZirFq1CtOmTUNKSgp0dXXf+HOL6zsmCALi4+ORl5dXqrl7iahqCIKA7OxsPHr0CHK5HFZWVlUdqcpwjAURFWfA3r5lfuy+gQfUmIQ0SYWOsYiJiUHfvi+fmLq6usjKyoJEIsGkSZPQrVu3chUWaWlpAABTU1MAQHh4OPLy8uDm5iYe4+joCFtbW7GwCAsLQ/PmzZW6Rrm7u2Ps2LG4ceMGWrVqVeY8+fn5yM7OhrW1NWrUqFHm8xBRxTMwMAAAPHr0CObm5uwWRUREVMlU/gq+Zs2a4kJ4derUwfXr1wEAqampyM7OLnMQhUKBiRMnomPHjmjWrBkAICkpCbq6upDL5UrHWlhYICkpSTzm9aLi1f5X+4qSk5OD9PR0pVtRCgoKAKBUrR5EVPVefQHwaipsIiIiqjwqFxadO3fGkSNHAABDhw7FhAkTMGrUKHh6eqJ79+5lDjJu3Dhcv34d27ZtK/M5Smv+/PkwMTERb29adZv9tYk0A1+rREREVUflwuKXX36Bh4cHAGDGjBnw9/dHcnIyhgwZgnXr1pUphJ+fH/bv34/jx48rLRVuaWmJ3NxcpKamKh2fnJwMS0tL8Zjk5ORC+1/tK0pAQADS0tLE2/3798uUm1QzceJEeHt7V/rP9fb2xsSJEyv95xIRERG9S1QuLExNTWFtbf3ywVpa+Prrr7Fv3z789NNPqFmzpkrnEgQBfn5+2LNnD44dOwZ7e3ul/c7OztDR0UFISIi4LTo6GvHx8XBxcQEAuLi44Nq1a3j06JF4zJEjRyCTydCkSZMif66enp64yvbbstr26dOn0bt3b9SsWRNyuRwtWrTAwoUL35ppckNDQwt1iSP1MjIyEm9SqRR6enri/d69ewN42SJQo0YNyGQymJqawsXFBT///LNS16Pg4GBIpVIYGRnB2NgYDg4OCAwMLPTzsrKyIJPJ0K5du0L7vL29IZFIsHbtWqXtO3fuhEQiwcCBA9V78URERFRuZVroISYmBkFBQYiJicHSpUthbm6OgwcPwtbWFk2bNi31ecaNG4ctW7bgzz//hLGxsTgmwsTEBAYGBjAxMYGvry/8/f1hamoKmUyG8ePHw8XFBe3btwcA9OzZE02aNMFnn32GhQsXIikpCd988w3GjRsHPT29slzeG7Wf9U+FnPd152a7l/rY/fv3w9PTE99//z02bdqEWrVqISoqCgsWLEBiYiLs7OwqMCmVR3lm6Cit0s7kkZmZKf7b1dUVAwcOLLKl5+zZs2jZsiXy8vJw9uxZTJw4EYcOHcLBgwfFrkjNmzdHRESEeLybmxtatGiBbt26iefZsWMHpFIpLl68iOvXr4tjq15p1KgRgoKC8L///U/cFhQUBEdHx9JeOhEREVUilVssTpw4gebNm+P8+fPYvXu3+GEkMjISs2bNUulcK1euRFpaGlxdXWFlZSXetm/fLh4TGBiIfv36YciQIejcuTMsLS2VFuGTSqXYv38/pFIpXFxc8Omnn2LEiBGYM2eOqpemkQRBwJdffolp06Zh4sSJqFWrFoCXs2cFBweLRcWnn34Ka2tryGQyODs74/jx4+I5YmNj4ebmBhMTE5iamqJjx47iQPz09HT4+fnBzs4OMpkMbdq0EbuOLVmyBA0aNICxsTHq16+PX375RSnbyZMn0bx5cxgZGWHw4MHioP9XYmJi0L9/f9SuXRt2dnaYO3dumdYLiY+PR48ePVC7dm3UrFkTffv2RVxcXJHH5ufnw9vbG25ubsjIyEBmZib8/Pxga2sLc3NzjBgxQpydjEqmo6ODLl26YPfu3Thx4gQOHjxY5HEdOnRA06ZNER4errR93bp18PHxQefOnYvsRtmjRw/cu3cPt2/fBgAkJCTg4sWLbK0gIiKqplQuLL7++mvMnTsXR44cUZotqVu3bjh37pxK5xIEocjb6/3w9fX18euvv+Lp06fIysrC7t27C42dsLOzw99//43s7GykpKRg8eLFalt1u7q7c+cOYmNj4enpWeJx3bt3x61bt/DkyRN4eHjgo48+Ej/oz5gxAw4ODnj8+DGSk5OxaNEi8ffn7e2Nf//9F2FhYUhNTcXq1avFaT3t7Oxw7NgxpKenY+3atZgyZYq4cOGzZ88wYMAA+Pn5ITU1FT4+Pvj999/FPNnZ2ejevTu6d++Ohw8f4tSpU9i2bRuCgoJU/h0oFAr4+/vj/v37uHfvHmrUqIFRo0YVOi4rKwsDBgzA8+fP8ffff8PY2BgjR47E06dPcfXqVcTGxiIvLw9+fn4qZ3iX2dvbw9nZGSdOnCi0TxAEnDx5EtevX0fDhg3F7dHR0Thz5gy8vb3h5eWF33//vVC3PalUihEjRmD9+vUAgA0bNuDjjz+usJZIIiIiKh+VC4tr164VucK2ubk5Hj9+rJZQVHopKSkAXk79WxIfHx+YmJhAR0cHU6ZMgUKhwNWrVwG8/OY5MTERcXFx0NHRQYcOHaCrq4vk5GTs2bMHq1evFhcIbNWqldgqMmTIENjY2EAikaBr165wd3dHaGgogJfds6ytrfH5559DW1sb/fv3V+oGc+DAAdSsWRMTJ06Erq4ubG1tMWHCBGzZskXl30HdunXRu3dv6OvrQyaTYcaMGTh16pRS68fjx4/RrVs3ODg4YOvWrdDV1UVKSgp27dqFX3/9FXK5HIaGhpgzZw62b98uTjVMpVOnTh08ffpUvH/t2jXI5XLo6+ujS5cumDx5MgYMGCDuX7duHVq2bAknJyd89NFHyM7Oxp9//lnovN7e3ti0aRPy8/MRHBwMHx+fSrkeIiIiUp3KhYVcLkdiYmKh7VeuXHnjh1tSv1cf8h8+fFjsMQqFAjNmzECDBg0gk8kgl8uRlpYmFoKLFi1CnTp14Obmhrp16+K7776DQqHAvXv3oKenB1tb2yLPu3nzZrz//vswNTWFXC7H33//LZ4zISGh0NiO1+/HxcXh+vXrkMvl4m3y5MnFrj1SkpSUFAwbNgw2NjaQyWTo3LkzcnJylLpeHT16FDExMQgICBBXUI+Li4NCoYC9vb2YoU2bNtDS0ipTjnfZw4cPxYUtgZdjLFJTU5GRkYFvv/0Wx44dQ35+PoCX3dE2btwILy8vAICxsTEGDRpUZHeohg0bwt7eHjNnzoSuri5at25dORdEREREKlO5sPDw8MC0adOQlJQEiUQChUKBM2fO4KuvvsKIESMqIiOVoGHDhqhbt26J639s2bIFW7ZswYEDB5CWlobU1FSYmJhAEAQAL1ubVqxYgXv37uGvv/7CqlWrsGfPHtjZ2SEnJ6fI6Xjj4+Ph5eWFhQsX4tGjR0hNTUWfPn3Ec1pbW+PevXuFHvOKjY0NnJ2dkZqaKt7S09Nx48YNlX8HAQEByM7OxuXLl5Geno6TJ08CgJgFePm8HTduHFxdXcUizMbGBlpaWkhISFDK8eLFCxbJKoiLi0N4eDhcXV0L7dPV1cXs2bPx/PlzrFixAsDL1qzk5GR8//33sLS0hKWlJfbt24cjR44U+Vzz8fHBggUL2FpBRERUzalcWMybNw+Ojo6wsbFBZmYmmjRpgs6dO6NDhw745ptvKiIjlUAikWD58uVYsGABli9fjidPngAAbt++DV9fX9y7dw/p6enQ1dVFrVq1kJubizlz5ih9m79jxw7Ex8dDEATI5XJIpVJoa2vDwsICH374IcaMGYPExEQoFApcuXIFT548QWZmJgRBgLm5ObS0tPD333/j8OHD4jn79u2Lhw8fYs2aNcjPz8eBAwdw7NgxcX+/fv2QnJyMFStW4MWLFygoKEB0dLTYlao4L168ULoVFBQgPT0dNWrUgFwux5MnTzB79uwiHzt79mwMHz4crq6uuH//PiwtLTFw4ED4+fmJLS1JSUnYs2dPWf873il5eXk4deoUhgwZgi5duqBXr15FHieRSDBjxgzMmzcP2dnZWLduHQYMGIAbN24gIiICERERuH37NhwcHIocYzNs2DAcPny4yHEzREREVH2oVFgIgoCkpCQsW7YMd+/exf79+/H7778jKioKmzZtglQqraicVIJ+/frh4MGDOHDgAOrXrw+5XI6PPvoIjo6OsLKygpeXF5o2bQo7OzvUq1cPBgYGSgsRhoeHo0OHDjAyMoKLiwt8fX3F/vAbNmyAjY0NWrduDblcjjFjxuD58+do0qQJZsyYgW7dusHMzAzbt29X6kNvamqKP//8E0uXLoVcLsfatWsxfPhwcb+RkRGOHj2KkJAQ1K1bF2ZmZhg2bFiJXZDS0tJgYGCgdNu0aRNmz56Nf//9FzVr1kTHjh3FNReKMnPmTPj4+MDV1RX37t1DcHCw2AVKJpPhgw8+KDR7ESnr0KEDjI2NYW5ujilTpuDTTz/FX3/9VeKq14MHD4apqSkWL16MgwcPwt/fX2yteHUbP348goKClFqaAMDAwABubm4wNjau6EsjIiKicpAI//0rXgKFQgF9fX3cuHEDDRo0qMhclSo9PR0mJiZIS0tTWizvxYsXiI2Nhb29PfT19aswIRGVBl+zL2c/MzIyAvBybRJDQ8MqTkRE1UV51k4q7ZpI9PYp7nNyUVRqsdDS0kKDBg3E7jZERERERERAGcZYLFiwAFOmTMH169crIg8REREREWkglVeRGzFiBLKzs9GiRQvo6uqKi6W98vpc9kRERERE9G5QubD4+eefKyAGERERERFpMpULi1eLWhEREREREb1SqjEWWVlZKp1U1eOrOxUmziKiKqRQKKo6AhER0TurVC0WDg4OmDBhAry8vGBlZVXkMYIg4OjRo1iyZAk6d+6MgIAAtQatCjo6OpBIJEhJSUHt2rVLnKefiKqOIAjIzc1FSkoKtLS0oKurW9WRiIiI3jmlKixCQ0Mxffp0fPfdd2jRogVat24Na2tr6Ovr49mzZ7h58ybCwsKgra2NgIAAfP755xWdu1JIpVK89957ePDgAeLi4qo6DhG9QY0aNWBrawstLZUnvCMiIqJyKlVh0ahRI+zatQvx8fHYuXMnTp06hbNnz+L58+eoVasWWrVqhTVr1qB3795v3erbRkZGaNCgAfLy8qo6ChGVQCqVQltbmy2LREREVUSlwdu2traYPHkyJk+eXFF5qiWpVPrWFUxEREREROrE/gJERERERFRuLCyIiIiIiKjcWFgQEREREVG5sbAgIiIiIqJyY2FBRERERETlpnJhUbduXcyZMwfx8fEVkYeIiIiIiDSQyoXFxIkTsXv3btSrVw89evTAtm3bkJOTUxHZiIiIiIhIQ5SpsIiIiMCFCxfQuHFjjB8/HlZWVvDz88Ply5dVOtfJkyfRv39/WFtbQyKRYO/evUr7vb29IZFIlG69evVSOubp06cYPnw4ZDIZ5HI5fH19kZmZqeplERERERFROZR5jMX777+PZcuWISEhAbNmzcLatWvRpk0btGzZEuvXr4cgCG88R1ZWFlq0aIFff/212GN69eqFxMRE8bZ161al/cOHD8eNGzdw5MgR7N+/HydPnsTo0aPLellERERERFQG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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_cas['app']\n", - "gap_22_cas = df_gap22_cas['avgTimeTagCheckResRd'].astype(float)\n", - "gap_22_ram = df_gap22_ram['avgTimeTagCheckResRd'].astype(float)\n", - "\n", - "\n", - "gap_25_cas = df_gap25_cas['avgTimeTagCheckResRd'].astype(float)\n", - "gap_25_ram = df_gap25_ram['avgTimeTagCheckResRd'].astype(float)\n", - "\n", - "\n", - "app_npb = df_npbC_cas['app']\n", - "npb_C_cas = df_npbC_cas['avgTimeTagCheckResRd'].astype(float)\n", - "npb_C_ram = df_npbC_ram['avgTimeTagCheckResRd'].astype(float)\n", - "\n", - "npb_D_cas = df_npbD_cas['avgTimeTagCheckResRd'].astype(float)\n", - "npb_D_ram = df_npbD_ram['avgTimeTagCheckResRd'].astype(float)\n", - "\n", - "\n", - "# Multi bar Chart1\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - " plt.bar(i*3+1, gap_22_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", - "\n", - "offset = i*3+2\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_C_cas[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*3+2, npb_C_ram[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Avg Tag Check Latency (reads) (ns)\")\n", - "plt.legend(fontsize=9, ncol=2, loc='upper left')\n", - "plt.tight_layout()\n", - "\n", - "# Multi bar Chart2\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - " plt.bar(i*3+1, gap_25_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", - "\n", - "offset = i*3+2\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_D_cas[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*3+2, npb_D_ram[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"Avg Tag Check Latency (reads) (ns)\")\n", - "plt.legend(fontsize=9, ncol=2)\n", - "plt.tight_layout()" - ] - }, - { - "cell_type": "code", - "execution_count": 77, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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Ktq2bStu3bolMjMzRXx8vDA0NBSbNm0S6enp4tSpU2L58uXa7obSp59+KmrVqiViYmLExYsXxaFDh8TatWtFbm6u8PDwEB06dBCHDh0SaWlpYvPmzeLo0aPajlzKq7YlV1dXIZfLxeLFi8XFixfFxYsXqzTfzZs3hZGRkVi6dKm4cuWKSE5OFt98843Izc0VNjY2YtKkSeLixYvi3LlzIiYmRly9elUIIYSPj4/44IMPxPnz58WFCxfEli1bRGJiohBCiOjoaGFsbCwCAwPF0aNHxYkTJ0RQUJBo165dlfbtuYcPH4q2bduKoUOHilu3bolbt26JjIwMYWdnJ95++20RHx8vUlNTxfr160VKSopWMr7Kq17b9evXF7NmzVL2T9eU91rOzs4WdnZ24oMPPhBnz54Vf/zxh2jcuLEAIBISErQdu5SHDx+KWbNmifr164tbt26Ju3fvCgAiOjpa+VgfdOrUSYwbN07n9wFleZ5dCCEAlPo8Y2NjI6Kjo6s8V3k6deokrK2txezZs8WFCxfE7NmzhaGhoXj99dfFmjVrxIULF8TIkSOFvb29yMvLE5cvXxbGxsZi0qRJIiUlRfz444+iXr16AoDIysrSdndeus+IjIwUVlZW4t133xVnzpwRO3fuFA4ODmLatGnajq3k6uoqli1bVqKtefPmYsaMGUIIIZYtWyb2798vrly5ImJjY4WXl5cYOXJk1QetAioXFq+99pro3r27OHz4sBg+fLioV6+eGDx4sCguLhbFxcVi1KhRonXr1pWZVe916tRJeHt7C4VCoWyLiooS3t7eIjU1VQAQe/fu1WLCsr0stxBCjBs3TnTq1Ek5bevWrUIul4ucnJyqjvpKOTk5wtTUVKxdu7bUtO+++05YW1uLzMxMLSST5lX/E1dXV9GrVy9txRMnT54UAER6enqJ9szMTAFAxMXFlbmctbW1iImJKXNadHS0ACCOHTumbDt//rwAII4fP6658BL888OIEEJMnTpVuLu7i8LCQq3kkUqV7ejFnaWueNlredWqVcLe3l48efJE2bZ27VqdLSyEePbBw9XVVfm4rA+3uu7560GX9wHl0cfCon379srHT58+FZaWluLDDz9Utt26dUsAEH///beIiooSzZo1K7GOzz77TGcKi/L2GUIIERkZKezs7EReXp6ybdWqVcLKykoUFxdXZcxy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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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3Lgx3nrrLXz++ec4c+YMNm/ejLZt25ZHRiIiIiIi0nOSC4vFixcjLy8PADB9+nTk5eVh/fr18PT05BWhiIiIiIiqKMmFhbu7u/J3KysryXfbJiIiIiKiyqdM97EAgJMnT+L8+fMAgKZNm8LPz09roYiIiIiIyLBILizS09MxYMAAxMbGonr16gCArKwsBAUF4ffff4eDg4O2MxIRERERkZ6TfFWoMWPGIDc3F0lJSXjw4AEePHiAs2fPIicnB2PHji2PjEREREREpOckH7H4559/sGfPHjRu3FjZ1qRJE/zwww/o3r27VsMREREREZFhkHzEQqFQwNTUtES7qakpFAqFVkIREREREZFhkVxYdOnSBePGjcPt27eVbbdu3cKECRPQtWtXrYYjIiIiIiLDILmwWLZsGXJycuDm5oYGDRqgQYMGqF+/PnJycrB06dLyyEhERERERHpO8hgLFxcXnDp1Cnv27EFycjIAoHHjxggODtZ6OCIiIiIiMgxluo+FTCZDt27d0K1bN23nISIiIiIiA6RWYfH999+rvUBecpaIiIiIqOpRq7CIiIhQa2EymYyFBRERERFRFaRWYXHt2rXyzkFERERERAZM8lWhiIiIiIiIXiSpsLh06RI2bdqkPILx119/oVOnTvD398fs2bMhhCiXkEREREREpN/UvirUli1b0L9/fxgZGUEmk2HlypX49NNPERgYCLlcjm+//RYmJiYIDw8vz7xERERERKSH1D5iMXv2bHz55Zd4/Pgxli9fjhEjRmDu3LnYsWMHtm/fjh9++AHR0dHlGJWIiIiIiPSV2oXFhQsXMHToUMhkMoSGhqKwsFDlpnjdu3fH9evXyyUkERERERHpN7ULi/z8fNjY2Dx9kpERLC0tUa1aNeV0S0tLFBQUaD8hERERERHpPbULC5lMBplMVupjIiIiIiKqutQevC2EQMOGDZXFRF5eHvz8/GBkZKScTkREREREVZPahUVUVFR55iAiIiIiIgOmdmERGhpanjmIiIiIiMiA8c7bRERERESkMb0oLH744Qe4ubnBwsICbdq0wX//+19dRyIiIiIiIgl0XlisX78eYWFhmDZtGk6dOoXmzZujR48eSE9P13U0IiIiIiJSk84Li8WLF2P48OEYMmQImjRpghUrVqBatWqIjIzUdTQiIiIiIlKT2oO39+3bh4CAAJiZ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UgeengaVlJQEE5P/vcwVCgUiIyMxbNgwZZuNjQ1OnToFIyMjODk5qSzjmdq1a8PDwwMA4OXlhdzcXAwcOBCzZs1StltYWKBbt27o1q0bvvnmG3z88ceYNm0aBg8ejBkzZmDixIkv7dPt27cRFBSE9u3bY+XKla/9G7Rp0wa7d+9+7XxERLrSqVMn9OjRA5MnT8bgwYNLTD948CDkcjkcHR1Vjg4/U7NmTeV7q6enJ/7973+jXbt22LdvH4KDg5GQkKCcVy6XvzbP+fPnIZfLYW9vX+Y+EamDhQWRAbG3t0e3bt2wbNkyjBkzptRxFmfOnMGJEycQGxurMmbhwYMHCAwMRHJyMho1agQAMDIyUu7A1GVsbAwAePToUanzNGnSBFu3bgXw9BxfR0fHEvPcunULQUFBaNmyJaKiomBk9PqDqAkJCXBycpKUl4ioos2bNw++vr4lTl0FgPr166N69epqL+vF91wp79np6elYt24dQkJC1HqPJdIECwsiA/Pjjz8iICAArVq1wrfffgsfHx8YGRkhLi4OycnJaNmyJVavXo3WrVujU6dOJZ7v7++P1atXSzqdKCsrC3fu3IFCocClS5cwY8YMNGzYEI0bN0ZGRgb69euHoUOHwsfHBzY2Njhx4gQWLFiAPn36lLrMW7duITAwEK6urli4cCHu3bunnFa7dm0AwJo1a2BmZgY/Pz8AwObNmxEZGYn//Oc/amcnItIFb29vfPDBB/j+++8lPzc3Nxd37tyBEAI3b97El19+CQcHB7Rv3/6VzxNCKJ+XlZWFo0ePYs6cObC1tS1xfw2i8sDCgsjANGjQAPHx8ZgzZw4mT56M1NRUmJubo0mTJpg4cSI++eQTuLu7Kwdxv6hv375YtGgR5syZo/Y6hwwZAuDp+bm1a9dGp06dMGfOHJiYmMDa2hpt2rRBREQErly5gqKiIri4uGD48OEvvSfFM7t378bly5dx+fJlODs7q0x7dj4wAMycORPXr1+HiYkJGjVqhPXr1+O9995TOzsRka7MmDGjxLg2dUydOhVTp04FADg4OMDf3x+7du167alMOTk5cHJygkwmg1wuh5eXF0JDQzFu3Di1Tpki0pRMPL8HJyIiIiIiKgOebEdERERERBpjYUFERERERBpjYUFERERERBpjYUFERERERBpjYUFERERERBpjYUFERERERBpjYUFERERERBpjYUFERERERBpjYUFERERERBpjYUFERERERBpjYUFERERERBpjYUFERERERBr7f1lfDq65aiLxAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_cas['app']\n", - "gap_22_cas = df_gap22_cas['BWBloat'].astype(float)\n", - "gap_22_ram = df_gap22_ram['BWBloat'].astype(float)\n", - "\n", - "\n", - "gap_25_cas = df_gap25_cas['BWBloat'].astype(float)\n", - "gap_25_ram = df_gap25_ram['BWBloat'].astype(float)\n", - "\n", - "app_npb = df_npbC_cas['app']\n", - "npb_C_cas = df_npbC_cas['BWBloat'].astype(float)\n", - "npb_C_ram = df_npbC_ram['BWBloat'].astype(float)\n", - "\n", - "npb_D_cas = df_npbD_cas['BWBloat'].astype(float)\n", - "npb_D_ram = df_npbD_ram['BWBloat'].astype(float)\n", - "\n", - "\n", - "# Multi bar Chart1\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,3.5])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_22_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - " plt.bar(i*3+1, gap_22_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", - "\n", - "offset = i*3+2\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_C_cas[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*3+2, npb_C_ram[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, -0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"BW Bloat (due to acc amp)\")\n", - "plt.legend(fontsize=8, ncol=2, loc='upper left')\n", - "plt.tight_layout()\n", - "\n", - "# Multi bar Chart2\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "plt.ylim([0,3.5])\n", - "\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*3, gap_25_cas[i], width=1, color=cmap(1), label='Cascade Lake' if i==0 else None)\n", - " plt.bar(i*3+1, gap_25_ram[i], width=1, color=cmap(2), label='TDRAM' if i==0 else None)\n", - "\n", - "offset = i*3+2\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*3+1, npb_D_cas[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*3+2, npb_D_ram[i], width=1, color=cmap(2))\n", - "\n", - "plt.figtext(0.3, -0.01, \"GAPBS-25\")\n", - "plt.figtext(0.75, -0.01, \"NPB-D\")\n", - "\n", - "plt.xticks(np.arange(14)*3+0.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1, color='grey')\n", - "\n", - "plt.ylabel(\"BW Bloat (due to acc amp)\")\n", - "plt.legend(fontsize=8, ncol=2, loc='upper left')\n", - "plt.tight_layout()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.6" - }, - "orig_nbformat": 4, - "vscode": { - "interpreter": { - "hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/realAppRun.sh b/realAppRun.sh deleted file mode 100755 index 3aca47a56e..0000000000 --- a/realAppRun.sh +++ /dev/null @@ -1,32 +0,0 @@ -# script #App #Policy #Assoc #EnableLinkLatency #LinkLatency #EnableBypassDRAM$ -# # configs-npb-gapbs/restore_both.py bt.D.x Rambus 1 0 0 0 - -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/NPB/bt configs-npb-gapbs/restore_both.py bt.D.x RambusTagProbOpt 1 1 1250 0 7.5ns & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/NPB/cg configs-npb-gapbs/restore_both.py cg.D.x RambusTagProbOpt 1 1 1250 0 7.5ns & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/NPB/ft configs-npb-gapbs/restore_both.py ft.D.x RambusTagProbOpt 1 1 1250 0 7.5ns & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/NPB/is configs-npb-gapbs/restore_both.py is.D.x RambusTagProbOpt 1 1 1250 0 7.5ns & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/NPB/lu configs-npb-gapbs/restore_both.py lu.D.x RambusTagProbOpt 1 1 1250 0 7.5ns & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/NPB/mg configs-npb-gapbs/restore_both.py mg.D.x RambusTagProbOpt 1 1 1250 0 7.5ns & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/NPB/sp configs-npb-gapbs/restore_both.py sp.D.x RambusTagProbOpt 1 1 1250 0 7.5ns & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/NPB/ua configs-npb-gapbs/restore_both.py ua.D.x RambusTagProbOpt 1 1 1250 0 7.5ns & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/GAPBS/bc configs-npb-gapbs/restore_both.py bc-25 RambusTagProbOpt 1 1 1250 0 7.5ns & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/GAPBS/bfs configs-npb-gapbs/restore_both.py bfs-25 RambusTagProbOpt 1 1 1250 0 7.5ns & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/GAPBS/cc configs-npb-gapbs/restore_both.py cc-25 RambusTagProbOpt 1 1 1250 0 7.5ns & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/GAPBS/pr configs-npb-gapbs/restore_both.py pr-25 RambusTagProbOpt 1 1 1250 0 7.5ns & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/GAPBS/tc configs-npb-gapbs/restore_both.py tc-25 RambusTagProbOpt 1 1 1250 0 7.5ns & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_85GB_g25_nD/GAPBS/sssp configs-npb-gapbs/restore_both.py sssp-25 RambusTagProbOpt 1 1 1250 0 7.5ns & - -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/NPB/bt configs-npb-gapbs/restore_both.py bt.C.x RambusTagProbOpt 1 1 1250 0 7.5ns & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/NPB/cg configs-npb-gapbs/restore_both.py cg.C.x RambusTagProbOpt 1 1 1250 0 7.5ns & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/NPB/ft configs-npb-gapbs/restore_both.py ft.C.x RambusTagProbOpt 1 1 1250 0 7.5ns & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/NPB/is configs-npb-gapbs/restore_both.py is.C.x RambusTagProbOpt 1 1 1250 0 7.5ns & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/NPB/lu configs-npb-gapbs/restore_both.py lu.C.x RambusTagProbOpt 1 1 1250 0 7.5ns & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/NPB/mg configs-npb-gapbs/restore_both.py mg.C.x RambusTagProbOpt 1 1 1250 0 7.5ns & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/NPB/sp configs-npb-gapbs/restore_both.py sp.C.x RambusTagProbOpt 1 1 1250 0 7.5ns & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/NPB/ua configs-npb-gapbs/restore_both.py ua.C.x RambusTagProbOpt 1 1 1250 0 7.5ns & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/GAPBS/bc configs-npb-gapbs/restore_both.py bc-22 RambusTagProbOpt 1 1 1250 0 7.5ns & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/GAPBS/bfs configs-npb-gapbs/restore_both.py bfs-22 RambusTagProbOpt 1 1 1250 0 7.5ns & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/GAPBS/cc configs-npb-gapbs/restore_both.py cc-22 RambusTagProbOpt 1 1 1250 0 7.5ns & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/GAPBS/pr configs-npb-gapbs/restore_both.py pr-22 RambusTagProbOpt 1 1 1250 0 7.5ns & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/GAPBS/tc configs-npb-gapbs/restore_both.py tc-22 RambusTagProbOpt 1 1 1250 0 7.5ns & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/remote_homes/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/newResults/link/500/rambusTagPr/1GB_8GB_g22_nC/GAPBS/sssp configs-npb-gapbs/restore_both.py sssp-22 RambusTagProbOpt 1 1 1250 0 7.5ns & diff --git a/set-associative-data-plots.ipynb b/set-associative-data-plots.ipynb deleted file mode 100644 index 79cb41287d..0000000000 --- a/set-associative-data-plots.ipynb +++ /dev/null @@ -1,513 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "import numpy as np\n", - "import sys\n", - "from matplotlib import pyplot as plt\n", - "import os\n", - "\n", - "cmap = plt.get_cmap('Set1')\n", - "\n", - "Stats = ['simSeconds ',\n", - "'hostSeconds ',\n", - "'system.mem_ctrl.readReqs ',\n", - "'system.mem_ctrl.writeReqs ',\n", - "'system.mem_ctrl.servicedByWrQ ',\n", - "'system.mem_ctrl.mergedWrBursts ',\n", - "'system.mem_ctrl.numTotHits ',\n", - "'system.mem_ctrl.numTotMisses ',\n", - "'system.mem_ctrl.numColdMisses ',\n", - "'system.mem_ctrl.numHotMisses ',\n", - "'system.mem_ctrl.numRdMissClean ',\n", - "'system.mem_ctrl.numRdMissDirty ',\n", - "'system.mem_ctrl.numRdHit ',\n", - "'system.mem_ctrl.numWrMissClean ',\n", - "'system.mem_ctrl.numWrMissDirty ',\n", - "'system.mem_ctrl.numWrHit ',\n", - "'system.mem_ctrl.numRdHitDirty ',\n", - "'system.mem_ctrl.numRdHitClean ',\n", - "'system.mem_ctrl.numWrHitDirty ',\n", - "'system.mem_ctrl.numWrHitClean ',\n", - "'system.o3Cpu0.thread_0.numInsts ',\n", - "'system.o3Cpu1.thread_0.numInsts ',\n", - "'system.o3Cpu2.thread_0.numInsts ',\n", - "'system.o3Cpu3.thread_0.numInsts ',\n", - "'system.o3Cpu4.thread_0.numInsts ',\n", - "'system.o3Cpu5.thread_0.numInsts ',\n", - "'system.o3Cpu6.thread_0.numInsts ',\n", - "'system.o3Cpu7.thread_0.numInsts ',\n", - "'system.mem_ctrl.avgRdBWSys ',\n", - "'system.mem_ctrl.avgWrBWSys ',\n", - "'system.mem_ctrl.avgORBLen ',\n", - "'system.far_mem_ctrl.avgRdBWSys ',\n", - "'system.far_mem_ctrl.avgWrBWSys ',\n", - "'system.loc_mem_ctrl.avgRdBWSys ',\n", - "'system.loc_mem_ctrl.avgWrBWSys ',\n", - "'system.loc_mem_ctrl.dram.readBursts ',\n", - "'system.loc_mem_ctrl.dram.writeBursts ',\n", - "'system.loc_mem_ctrl.dram_2.readBursts ',\n", - "'system.loc_mem_ctrl.dram_2.writeBursts ',\n", - "'system.far_mem_ctrl.dram.readBursts ',\n", - "'system.far_mem_ctrl.dram.writeBursts ',\n", - "'system.loc_mem_ctrl.dram.avgRdBW ',\n", - "'system.loc_mem_ctrl.dram.avgWrBW ',\n", - "'system.loc_mem_ctrl.dram_2.avgRdBW ',\n", - "'system.loc_mem_ctrl.dram_2.avgWrBW ',\n", - "'system.far_mem_ctrl.dram.avgRdBW ',\n", - "'system.far_mem_ctrl.dram.avgWrBW ',\n", - "'system.loc_mem_ctrl.dram.busUtil ',\n", - "'system.loc_mem_ctrl.dram.busUtilRead ',\n", - "'system.loc_mem_ctrl.dram.busUtilWrite ',\n", - "'system.loc_mem_ctrl.dram_2.busUtil ',\n", - "'system.loc_mem_ctrl.dram_2.busUtilRead ',\n", - "'system.loc_mem_ctrl.dram_2.busUtilWrite ',\n", - "'system.far_mem_ctrl.dram.busUtil ',\n", - "'system.far_mem_ctrl.dram.busUtilRead ',\n", - "'system.far_mem_ctrl.dram.busUtilWrite ',\n", - "'system.far_mem_ctrl.dram.bytesRead ',\n", - "'system.far_mem_ctrl.dram.bytesWritten ',\n", - "'system.loc_mem_ctrl.dram.bytesRead ',\n", - "'system.loc_mem_ctrl.dram.bytesWritten ',\n", - "'system.loc_mem_ctrl.dram_2.bytesRead ',\n", - "'system.loc_mem_ctrl.dram_2.bytesWritten ',\n", - "'system.mem_ctrl.avgTimeTagCheckRes ',\n", - "'system.mem_ctrl.avgTimeTagCheckResRd ',\n", - "'system.mem_ctrl.avgTimeTagCheckResWr ',\n", - "'system.mem_ctrl.avgPktRespTimeRd ',\n", - "'system.mem_ctrl.avgPktRespTimeWr ',\n", - "'system.mem_ctrl.avgPktORBTime ',\n", - "'system.mem_ctrl.avgPktORBTimeRd ',\n", - "'system.mem_ctrl.avgPktORBTimeWr ',\n", - "'system.mem_ctrl.avgTimeInLocRead ',\n", - "'system.mem_ctrl.avgTimeInLocWrite ',\n", - "'system.mem_ctrl.avgTimeInFarRead '\n", - " ]\n", - "\n", - "dfCols = [\n", - " 'app',\n", - " 'simSeconds',\n", - " 'hostSeconds',\n", - " 'readReqs',\n", - " 'writeReqs',\n", - " 'servicedByWrQ',\n", - " 'mergedWrBursts',\n", - " 'numTotHits',\n", - " 'numTotMisses',\n", - " 'numColdMisses',\n", - " 'numHotMisses',\n", - " 'numRdMissClean',\n", - " 'numRdMissDirty',\n", - " 'numRdHit',\n", - " 'numWrMissClean',\n", - " 'numWrMissDirty',\n", - " 'numWrHit',\n", - " 'numRdHitDirty',\n", - " 'numRdHitClean',\n", - " 'numWrHitDirty',\n", - " 'numWrHitClean',\n", - " 'numInsts0',\n", - " 'numInsts1',\n", - " 'numInsts2',\n", - " 'numInsts3',\n", - " 'numInsts4',\n", - " 'numInsts5',\n", - " 'numInsts6',\n", - " 'numInsts7',\n", - " 'avgRdBWSys',\n", - " 'avgWrBWSys',\n", - " 'avgORBLen',\n", - " 'farAvgRdBWSys',\n", - " 'farAvgWrBWSys',\n", - " 'locAvgRdBWSys',\n", - " 'locAvgWrBWSys',\n", - " 'readBursts1',\n", - " 'writeBursts1',\n", - " 'readBursts2',\n", - " 'writeBursts2',\n", - " 'readBursts3',\n", - " 'writeBursts3',\n", - " 'loc1AvgRdBW',\n", - " 'loc1AvgWrBW',\n", - " 'loc2AvgRdBW',\n", - " 'loc2AvgWrBW',\n", - " 'farAvgRdBW',\n", - " 'farAvgWrBW',\n", - " 'loc1BusUtil',\n", - " 'loc1BusUtilRead',\n", - " 'loc1BusUtilWrite',\n", - " 'loc2BusUtil',\n", - " 'loc2BusUtilRead',\n", - " 'loc2BusUtilWrite',\n", - " 'farBusUtil',\n", - " 'farBusUtilRead',\n", - " 'farBusUtilWrite',\n", - " 'farBytesRead',\n", - " 'farBytesWritten',\n", - " 'loc1BytesRead',\n", - " 'loc1BytesWritten',\n", - " 'loc2BytesRead',\n", - " 'loc2BytesWritten',\n", - " 'avgTimeTagCheckRes',\n", - " 'avgTimeTagCheckResRd',\n", - " 'avgTimeTagCheckResWr',\n", - " 'avgPktRespTimeRd',\n", - " 'avgPktRespTimeWr',\n", - " 'avgPktORBTime',\n", - " 'avgPktORBTimeRd',\n", - " 'avgPktORBTimeWr',\n", - " 'avgTimeInLocRead',\n", - " 'avgTimeInLocWrite',\n", - " 'avgTimeInFarRead'\n", - "\n", - " ]\n", - "##########################################################\n", - "\n", - "def getStat(filename, stat, index):\n", - " filename = os.path.join(filename).replace('\\\\','/')\n", - " #print(stat)\n", - " #print(filename)\n", - " try:\n", - " x = 0\n", - " with open(filename) as f:\n", - " readlines = f.readlines()\n", - " for l in readlines:\n", - " if stat in l and x < (index-1):\n", - " x = x+1\n", - " elif stat in l and x == (index-1):\n", - " return l\n", - " return 0.0 #for cases where stat was not found\n", - " except: #for cases where the file was not found\n", - " return 0.0\n", - "\n", - "##########################################################\n", - "\n", - "def creatDataFrame(dataDir, suite, index):\n", - " app = []\n", - " if suite == \"GAPBS\":\n", - " app = ['bc', 'bfs', 'cc', 'pr', 'sssp', 'tc']\n", - " if suite == \"NPB\":\n", - " app = ['bt', 'cg', 'ft', 'is', 'lu', 'mg', 'sp', 'ua']\n", - " rows = []\n", - " i = 0\n", - " for a in app:\n", - " stats = [a]\n", - " for stat in Stats:\n", - " time_file_path = '{}/{}/stats.txt'.format(dataDir, a)\n", - " ret_line = getStat(time_file_path, stat, index[i])\n", - "\n", - " if ret_line != 0:\n", - " #if ret_line=='nan' :\n", - " # stat_val = 0\n", - " #else:\n", - " stat_val = ret_line.split()[1]\n", - " else:\n", - " stat_val = 0\n", - " stats.append(stat_val)\n", - "\n", - " rows.append(stats)\n", - " i = i+1\n", - " df = pd.DataFrame(rows, columns= dfCols)\n", - " df['totNumInsts'] = df['numInsts0'].astype(int)+df['numInsts1'].astype(int)+df['numInsts2'].astype(int)+df['numInsts3'].astype(int)+df['numInsts4'].astype(int)+df['numInsts5'].astype(int)+df['numInsts6'].astype(int)+df['numInsts7'].astype(int)\n", - " df['totBW'] = (df['avgRdBWSys'].astype(float)+df['avgWrBWSys'].astype(float))/1000000000\n", - " df['coldRate'] = (df['numColdMisses'].astype(float) / df['numTotMisses'].astype(float)) *100\n", - " df['injRate'] = (df['readReqs'].astype(float) + df['writeReqs'].astype(float))*64/1000000000 / df['simSeconds'].astype(float)\n", - " df['BIPS'] = (df['totNumInsts'].astype(float)/1000000000)/df['simSeconds'].astype(float)\n", - " \n", - " df['accAmp'] = (df['farBytesRead'].astype(float) + df['farBytesWritten'].astype(float) +\n", - " df['loc1BytesRead'].astype(float) + df['loc1BytesWritten'].astype(float) + \n", - " df['loc2BytesRead'].astype(float) + df['loc2BytesWritten'].astype(float)) / (df['readReqs'].astype(float) * 64 + df['writeReqs'].astype(float) * 64)\n", - " \n", - " df['BWBloat'] = (df['loc1AvgRdBW'].astype(float) + df['loc1AvgWrBW'].astype(float) +\n", - " df['loc2AvgRdBW'].astype(float) + df['loc2AvgWrBW'].astype(float) +\n", - " df['farAvgRdBW'].astype(float) + df['farAvgWrBW'].astype(float)) / ((df['avgRdBWSys'].astype(float) + df['avgWrBWSys'].astype(float)) / 1000000)\n", - " return df" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "df_gap22_dc_1 = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/set-Assoc-Res-Correct2/128MiB_16GB_g22_nC/1/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", - "df_npbC_dc_1 = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/set-Assoc-Res-Correct2/128MiB_16GB_g22_nC/1/NPB\", \"NPB\", [1,1,1,1,1,1,1,1])\n", - "df_gap22_dc_2 = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/set-Assoc-Res-Correct2/128MiB_16GB_g22_nC/2/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", - "df_npbC_dc_2 = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/set-Assoc-Res-Correct2/128MiB_16GB_g22_nC/2/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", - "df_gap22_dc_8 = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/set-Assoc-Res-Correct2/128MiB_16GB_g22_nC/8/GAPBS\", \"GAPBS\", [1,1,1,1,1,1])\n", - "df_npbC_dc_8 = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/set-Assoc-Res-Correct2/128MiB_16GB_g22_nC/8/NPB\", \"NPB\",[1,1,1,1,1,1,1,1])\n", - "df_gap22_dc_16 = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/set-Assoc-Res-Correct2/128MiB_16GB_g22_nC/16/GAPBS\", \"GAPBS\", [1,1,1,1,1,1,1,1])\n", - "df_npbC_dc_16 = creatDataFrame(\"/home/babaie/projects/rambusDesign/x86Fixed/set-Assoc-Res-Correct2/128MiB_16GB_g22_nC/16/NPB\", \"NPB\", [1,1,1,1,1,1,1,1])" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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AKxbtw49e/bE8uXL4ezsrJGcRERERER1mampKXr27Cm/3a5dOyxfvlyrGZQeY1FQUFCjA9e0/T+lp6cjJycHXbt2lW+ztrZG27ZtkZiYCABITEyEjY2NvKgAgK5du8LAwACnT5+u9NhFRUXIy8tT+CIiIiIielGsWbNG/uG8tihdWHh5eWHJkiXIzs6utI0QAj/++CN69OiBtWvXqhUsJycHAODo6Kiw3dHRUb4vJycHDg4OCvvr1asHW1tbeZuKLF68GNbW1vIvV1dXtbISEREREdUVixYtwrVr17B48WKtPq7SXaHi4+Mxc+ZMzJkzB35+fggICICzszNMTU3x4MED/PHHH0hMTES9evUwY8YMjBkzpjZzq2XGjBmIioqS387Ly2NxQURERER6b/ny5di3bx+OHTsGc3NzrT620oWFt7c39u7dixs3buDrr79GQkICTp06hcLCQtSvXx+tWrXC5s2b0aNHDxgaGqodzMnJCQBw584dNGjQQL79zp078Pf3l7e5e/euwv1KS0uRm5srv39FTExMYGJionZGIiIiIqK6YuXKldi9ezeOHTsGGxsbrT9+jQdvu7m5YfLkyZg8eXJt5JFr1KgRnJycEBcXJy8k8vLycPr0aYwbNw4A0L59ezx8+BDnzp1D69atAQDHjx+HTCZD27ZtazUfEREREVFdcevWLUyePBmenp544403APz9YXpV4441TaVZoTQlPz8f165dk99OT09HSkoKbG1t4ebmhkmTJmHBggVo0qSJfLpZZ2dn+VoXPj4+6N69O0aPHo2NGzeipKQEkZGRGDRoEGeEIiIiIiKtUXa9idri4uICIYROM+i0sDh79qy8ogIgH/cQHh6O2NhYTJ06FQUFBYiIiMDDhw/RsWNHHD58WL6GBQDs3LkTkZGR6NKli3yBPHUHjhMRERERUc3otLAIDg6usrKSSCSYN28e5s2bV2kbW1tbLoZHRERERKRjSk83S0REREREVBkWFkREREREpDaVC4uEhAQMGTIE7du3x+3btwEAO3bswC+//KKxcEREREREpB9UKiz27t2LkJAQmJmZITk5GUVFRQCAR48eYdGiRRoNSEREREREdZ9Kg7cXLFiAjRs3YtiwYfjyyy/l2wMDA7FgwQKNhSMiIiIi0geb+v2nVo475tshSrf9/vvv8cknn0Amk6G0tBQfffQRwsPDayVXRVQqLFJTU9GpU6dy262trfHw4UN1MxERERERUQ0IITBkyBDEx8fD19cXGRkZaNasGd566y1YWVlpJYNKXaGcnJwUFrZ75pdffoGnp6faoYiIiIiIqGYkEon8Q/68vDzY2dnBxMREa4+v0hWL0aNHY+LEidi6dSskEgmysrKQmJiIKVOmYNasWZrOSEREREREVZBIJNizZw/eeustWFhY4MGDB9i3bx+MjY21lkGlwmL69OmQyWTo0qULnjx5gk6dOsHExARTpkzB+PHjNZ2RiIiIiIiqUFpaigULFmDfvn3o1KkTzpw5g759++LSpUuoX7++VjKo1BVKIpHg448/Rm5uLn777TckJSXh3r17mD9/vqbzERERERFRNVJSUpCVlSUfB/3aa6/BxcUFycnJWsug0hWLZ4yNjdG8eXNNZSEiIiIiIhW4uroiOzsbly9fho+PD65du4br16/D29tbaxlUKiyePn2KdevW4cSJE7h79y5kMpnC/vPnz2skHBERERERVc/R0RFffPEF3n33XRgYGEAmk2H9+vVwc3PTWgaVCotRo0bh6NGjePvtt9GmTRtIJBJN5yIiIiIi0hs1WW+itoSFhSEsLExnj69SYfHdd9/h+++/R2BgoKbzEBERERGRHlJp8HbDhg21ttAGERERERHVfSoVFitWrMC0adOQmZmp6TxERERERKSHVOoKFRAQgKdPn8LT0xPm5uYwMjJS2J+bm6uRcERERET04ul7oJdS7Q72P1TLSUiTVCoswsLCcPv2bSxatAiOjo4cvE1EREREGrep33+qbTOm1dDqDzRHaCANVUelwuLUqVNITEyEn5+fpvMQERERkR5rF32k2jYOrbQQhLROpTEWzZo1Q2FhoaazEBERERGRnlLpisWSJUswefJkLFy4EC1btiw3xkIqlWokHBERERGRXphTS0MDlOzGNWHCBBw8eBCZmZlITk6Gv78/AKCoqAiTJ0/GkSNHYGpqCj8/P/znP9V3MVOFSoVF9+7dAQBdunRR2C6EgEQiQVlZmfrJiIiIiIhIKW+//TamTp2Kjh07KmyfPn06JBIJrl69ColEgpycnFrLoFJhceLECU3nICIiIiIiFXXq1KnctoKCAmzZsgW3bt2ST7bk5ORUaxlUKiyCgoI0nYOIiIiIiDTo+vXrsLW1xaJFi3Ds2DGYmZlh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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_dc_1['app']\n", - "gap_1 = df_gap22_dc_1['simSeconds'].astype(float)*1000\n", - "gap_2 = df_gap22_dc_2['simSeconds'].astype(float)*1000\n", - "gap_8 = df_gap22_dc_8['simSeconds'].astype(float)*1000\n", - "gap_16 = df_gap22_dc_16['simSeconds'].astype(float)*1000\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "\n", - "#plt.ylim([0,200])\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*5, gap_1[i], width=1, color=cmap(1), label='1' if i==0 else None)\n", - " plt.bar(i*5+1, gap_2[i], width=1, color=cmap(2), label='2' if i==0 else None)\n", - " plt.bar(i*5+2, gap_8[i], width=1, color=cmap(3), label='8' if i==0 else None)\n", - " plt.bar(i*5+3, gap_16[i], width=1, color=cmap(4), label='16' if i==0 else None)\n", - "\n", - "offset = i*6-1\n", - "app_npb = df_npbC_dc_1['app']\n", - "npb_1 = df_npbC_dc_1['simSeconds'].astype(float)*1000\n", - "npb_2 = df_npbC_dc_2['simSeconds'].astype(float)*1000\n", - "npb_8 = df_npbC_dc_8['simSeconds'].astype(float)*1000\n", - "npb_16 = df_npbC_dc_16['simSeconds'].astype(float)*1000\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*5+1, npb_1[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*5+2, npb_2[i], width=1, color=cmap(2))\n", - " plt.bar(offset+i*5+3, npb_8[i], width=1, color=cmap(3))\n", - " plt.bar(offset+i*5+4, npb_16[i], width=1, color=cmap(4))\n", - "\n", - "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, 0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*5+1.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "\n", - "plt.ylabel(\"Execution Time (ms)\")\n", - "plt.legend(fontsize=8, ncol=1)\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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SrIKi8WLF2Pq1KmYMmVKiQPiLVmyROvBiIiIiIjIcMgqLB6fZn9VO74QEREREVHZZBUWY8eOBQD069cPvr6+GstOnz6t/VREREREZFB4p1DDpo3/P0V9LIYPH474+PjnziMiIiKiV4OJiQkkScKtW7dQvXr1Ei+bp8pNCIFbt25BkiSYmJi88HZkFRY3b95ERkYGHjx4gKSkJHVFk52djby8vBfeOREREREZNmNjY9SuXRvXrl3DlStX9B2HXpAkSahduzaMjY1feBuyCovt27dj2bJlSE9PR+/evdXz7ezsEBYW9sI7JyIiIiLDZ21tjbp166KwsFDfUegFmZiYlKuoABSOYzF37lzMmDGjXDusaBzHgoheZhzHgoiIdEln41gMGzYMV69efWa+m5ubsoRERERERPRSUVRYNGvWDJIkQQiBhw8f4v79+3B0dMTNmzd1lY+IiIiIiAyAosLi1q1bGtO7d+/GqVOntBqIiIiIiIgMj1F5Vu7fvz/279+vrSxERERERGSgFJ2xyMnJUf+7uLgYx44d05hHRERERESvJkWFhb29vbqPhbGxMerWrYsVK1boKhsRERERERkIRYWFSqXSVQ4iIiIiIjJgivpYnDhxAvfu3VNP37t3D3FxcVoPRUREREREhkXRGYuxY8fixIkT6mkLCwuMGzeOxQUREVVa6/psldVu7HeDdZyEiOjlpuiMhUql0hjqu0qVKigqKtJ6KCIiIiIiMiyKCgtTU1OkpKSopy9cuAATExOthyIiIiIiIsOi6FKoWbNmoV27dujWrRsA4ODBg4iIiNBJMCIiIlJwKVeTIc9vNFuUMw0RUekUFRY9evTAH3/8gZ9//hkAMGPGDLz22ms6CUZERERERIZD8cjb1tbWaNCgASZMmAB3d3cUFBTIXvf3339Hr169ULNmTUiShL179z53nejoaDRt2hRmZmbw8vJCZGSk0shERERERKRjis5YfPvtt5g6dSqMjIyQmpqKM2fOIDw8HAcOHJC1fl5eHvz8/DBixAj079//ue1TU1PRo0cPjBs3Dtu2bUNUVBRGjRoFFxcXBAUFKYlORERE9EqRcxkd74ZG2qSosPj0008RHx+PwMBAAICfnx/S0tJkr9+tWzd1/ww51q5dC09PTyxevBgA4OPjgz/++ANLly5VXFjcLyhClQLewYqIXi73C4ohmZg9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AwCWLVumyyxERERERGSgZBUWzZo1AwB06NABf//9N4BHg90REREREREBCsaxWLZsGZydneHk5AQnJye4uLi88FgWRERERET0cpFVWGzduhVr167Fpk2bcPv2bfz999+IjIzEunXrsG3bNl1nJCIiIiKiSk5WYfHll19ix44dCAoKgr29PapWrYqgoCB88803WLduna4zEhERERFRJSersMjIyICfn98z8319fZGZman1UEREREREZFhkFRY2NjalLrOystJaGCIiIiIiMkyy7gqVmZmJFStWlLjs1q1bWg1ERERERESGR1Zh0blzZyQkJJS4LDAwUKuBiIiIiIjI8MgqLCIiInSdg4iIiIiIDJjscSyIiIiIiIhKw8KCiIiIiIjKjYUFERERERGV2wsVFunp6UhPT9d2FiIiIiIiMlCKCotz586hYcOG6kfjxo1x/vx5XWUjIiIiIiIDoaiwmDBhAj788ENkZWUhKysLH374IcaPH6+rbEREREREZCAUFRZZWVl4++231dODBg1CVlaW1kMREREREZFhUVRYGBsb4+zZs+rps2fPwtjYWOuhiIiIiIjIsMgaIO+x+fPno3379vD19QUAJCUlYdu2bToJRkREREREhkNRYREUFIRz587h2LFjAIBWrVqhWrVqOglGRERERESGQ3Hn7erVq6Nnz57o2bMnqlWrhgkTJugqGxERERERGQhFhcXRo0efmXfkyBGthSEiIiIiIsMk61KoHTt24JtvvkFqair69++vnp+dnQ1ra2udhSMiIiIiIsMgq7CoX78++vTpg/j4ePTp00c939bWFp06ddJZOCIiIiIiMgyyCgs/Pz/4+fmhR48eqF69uq4zERERERGRgVHUx4JFBRERERERlURRYUFERERERFQSFhZERERERFRuiguLXbt2Yf78+QCA69evIykpSeuhiIiIiIjIsCgqLGbOnImvvvoKkZGRj1Y2MsLYsWMV73T16tXw8PCAubk5Xn/9dRw/frzM9v/+979Rv359mJubo3Hjxjhw4IDifRIRERERke4oKiy+++47fP/997CysgIAuLi4IDc3V9EOd+zYgdDQUMyaNQvx8fHw8/NDUFAQbt68WWL7I0eOIDg4GCNHjkRCQgL69u2Lvn374s8//1S0XyIiIiIi0h1FhYWFhQWMjY015gkhFO1wyZIlGD16NEJC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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_dc_1['app']\n", - "gap_1 = df_gap22_dc_1['simSeconds'].astype(float)*1000\n", - "gap_2 = df_gap22_dc_2['simSeconds'].astype(float)*1000\n", - "gap_8 = df_gap22_dc_8['simSeconds'].astype(float)*1000\n", - "gap_16 = df_gap22_dc_16['simSeconds'].astype(float)*1000\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "\n", - "plt.ylim([0,1.7])\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*5, gap_1[i]/gap_1[i], width=1, color=cmap(1), label='1' if i==0 else None)\n", - " plt.bar(i*5+1, gap_2[i]/gap_1[i], width=1, color=cmap(2), label='2' if i==0 else None)\n", - " plt.bar(i*5+2, gap_8[i]/gap_1[i], width=1, color=cmap(3), label='8' if i==0 else None)\n", - " plt.bar(i*5+3, gap_16[i]/gap_1[i], width=1, color=cmap(4), label='16' if i==0 else None)\n", - "\n", - "offset = i*6-1\n", - "app_npb = df_npbC_dc_1['app']\n", - "npb_1 = df_npbC_dc_1['simSeconds'].astype(float)*1000\n", - "npb_2 = df_npbC_dc_2['simSeconds'].astype(float)*1000\n", - "npb_8 = df_npbC_dc_8['simSeconds'].astype(float)*1000\n", - "npb_16 = df_npbC_dc_16['simSeconds'].astype(float)*1000\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*5+1, npb_1[i]/npb_1[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*5+2, npb_2[i]/npb_1[i], width=1, color=cmap(2))\n", - " plt.bar(offset+i*5+3, npb_8[i]/npb_1[i], width=1, color=cmap(3))\n", - " plt.bar(offset+i*5+4, npb_16[i]/npb_1[i], width=1, color=cmap(4))\n", - "\n", - "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, 0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*5+1.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "plt.axhline(y=1)\n", - "\n", - "plt.ylabel(\"Relative to Dir-Map Execution Time (ms)\", fontsize=8)\n", - "plt.legend(fontsize=8, ncol=2)\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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3rC3t8fy5ctx//596T5LS0sAry5/6t27N6ZOnQo/Pz9kZWUBALS1tTmAm4hqtBYtWmDo0KFYs2ZNpe/75MkTZGVlQQiBW7duYcaMGTA3N0e7du3KvM+0adNw6NAh+Pj4YMGCBWjfvr30fLx06VJs2bKF081S9VPxrFREVAV3794VQUFBokGDBkJLS0sYGhqKVq1aia+//lo8fvxYmJmZiWXLlpV636VLl4p69eqJ/Pz8Uqeb/TcA0i+JRCKsrKzERx99JFJTU4UQQrx48UJ88cUX4r333hO1a9cW+vr6wsXFRcyaNUs6ZW1pwsPDix37za/XRo4cWer+Tp06VfpnRkRUnUaOHCn69etXbFtaWprQ1tYud7rZf7O3ty92vjM3Nxc9e/YUCQkJFWZ48eKFWLx4sWjRooXQ1dUVpqamwsvLS0RERIiCggI5nh2RbCRCcLQPERERERHJh7NCERERERGR3FhYEBERERGR3FhYEBERERGR3FhYEBERERGR3FhYEBERERGR3FhYEBERERGR3FhYEBERERGR3FhYEBERERGR3FhYEBERERGR3FhYEBERERGR3FhYEBERERGR3FhYEBERERGR3P4/AQ8cUghOIeAAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_dc_1['app']\n", - "gap_1 = 100 * df_gap22_dc_1['numTotMisses'].astype(float) / (df_gap22_dc_1['numTotMisses'].astype(float)+df_gap22_dc_1['numTotHits'].astype(float))\n", - "gap_2 = 100 * df_gap22_dc_2['numTotMisses'].astype(float) / (df_gap22_dc_2['numTotMisses'].astype(float)+df_gap22_dc_2['numTotHits'].astype(float))\n", - "gap_8 = 100 * df_gap22_dc_8['numTotMisses'].astype(float) / (df_gap22_dc_8['numTotMisses'].astype(float)+df_gap22_dc_8['numTotHits'].astype(float))\n", - "gap_16 = 100 * df_gap22_dc_16['numTotMisses'].astype(float) / (df_gap22_dc_16['numTotMisses'].astype(float)+df_gap22_dc_16['numTotHits'].astype(float))\n", - "\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "\n", - "plt.ylim([0,110])\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*5, gap_1[i], width=1, color=cmap(1), label='1' if i==0 else None)\n", - " plt.bar(i*5+1, gap_2[i], width=1, color=cmap(2), label='2' if i==0 else None)\n", - " plt.bar(i*5+2, gap_8[i], width=1, color=cmap(3), label='8' if i==0 else None)\n", - " plt.bar(i*5+3, gap_16[i], width=1, color=cmap(4), label='16' if i==0 else None)\n", - "\n", - "offset = i*6-1\n", - "app_npb = df_npbC_dc_1['app']\n", - "npb_1 = 100 * df_npbC_dc_1['numTotMisses'].astype(float) / (df_npbC_dc_1['numTotMisses'].astype(float)+df_npbC_dc_1['numTotHits'].astype(float))\n", - "npb_2 = 100 * df_npbC_dc_2['numTotMisses'].astype(float) / (df_npbC_dc_2['numTotMisses'].astype(float)+df_npbC_dc_2['numTotHits'].astype(float))\n", - "npb_8 = 100 * df_npbC_dc_8['numTotMisses'].astype(float) / (df_npbC_dc_8['numTotMisses'].astype(float)+df_npbC_dc_8['numTotHits'].astype(float))\n", - "npb_16 = 100 * df_npbC_dc_16['numTotMisses'].astype(float) / (df_npbC_dc_16['numTotMisses'].astype(float)+df_npbC_dc_16['numTotHits'].astype(float))\n", - "\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*5+1, npb_1[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*5+2, npb_2[i], width=1, color=cmap(2))\n", - " plt.bar(offset+i*5+3, npb_8[i], width=1, color=cmap(3))\n", - " plt.bar(offset+i*5+4, npb_16[i], width=1, color=cmap(4))\n", - "\n", - "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, 0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*5+1.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "\n", - "plt.ylabel(\"Miss Ratio (%)\")\n", - "plt.legend(fontsize=8, ncol=2)\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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IiLSPkobY1ERnTp1QqdOncrcJ4TA0qVL8dVXX6FHjx4AgE2bNsHGxga7du1Cv379qjIqERERERG9htzTzerq6sr1T1nS0tKQmZmJgIAA2TZzc3N88MEHSEhIKPd++fn5yMnJKfGPiIiIiIhUS+4eCyEEnJycEBwcDG9vb1VmAgBkZmYCQKlF92xsbGT7yjJv3jzMmDFDpdmIiIiIiKgkuQuLEydOYP369Vi2bBmcnZ3xySefYODAgahevboq8yksPDwcoaGhsts5OTlwcHBQYyIiIiIioref3IWFj48PfHx8EBERge3btyMqKgpTpkxBt27dMHz4cLRv316pwWxtbQEA9+7dg52dnWz7vXv34OXlVe79DAwMYGBgoNQspAbTy5/SuGQ7odocRERERCQXhQdvGxoaYtCgQRg0aBDS0tIwfPhwdOzYEffv34elpaXSgjk7O8PW1haxsbGyQiInJwfHjx/H6NGjlfY4VLXW9vhernajVH+1HREREREpUYVmhbp9+zaio6MRHR2NJ0+eYPLkyZBKpQofJzc3F1evXpXdTktLQ1JSEiwtLeHo6IgJEyZg9uzZcHV1lU03W6tWrRJrXRARERERkfrJXVgUFBRg586dWL9+PeLj49GpUycsXboUnTp1qvBsUKdOnULbtm1lt1+OjQgODkZ0dDTCwsKQl5eHkSNHIisrCy1btsS+ffu4hgURERERkYaRu7Cws7ODmZkZgoODsXr1atSsWRPAi0XuXqVIz0WbNm0gRPnXyEskEsycORMzZ86U+5hERERERFT15C4sHj16hEePHmHWrFmYPXt2qf1CCEgkEhQVFSk1IBERERERaT65C4uDBw+qMgcREREREWkxuQsLf39/VeYgIiIiIiItpqPuAEREREREpP1YWBARERERUaWxsCAiIiIiokpjYUFERERERJXGwoKIiIiIiCpNrlmhevfuLfcBY2JiKhyGiIiIiIi0k1yFhbm5uez/Qgjs3LkT5ubm8PHxAQCcPn0aWVlZChUg9PbpvqvLG9t0Qf8qSEJEREREVU2uwiIqKkr2/ylTpuDjjz/GmjVroKurCwAoKirC559/DqlUqpqURERERESk0RQeY7FhwwZ88cUXsqICAHR1dREaGooNGzYoNRwREREREWkHuVfefun58+dITk6Gm5tbie3JyckoLi5WWjAiIiIC1vb4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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "app_gap = df_gap22_dc_1['app']\n", - "gap_1 = 100 * df_gap22_dc_1['numColdMisses'].astype(float) / (df_gap22_dc_1['numTotMisses'].astype(float)+df_gap22_dc_1['numTotHits'].astype(float))\n", - "gap_2 = 100 * df_gap22_dc_2['numColdMisses'].astype(float) / (df_gap22_dc_2['numTotMisses'].astype(float)+df_gap22_dc_2['numTotHits'].astype(float))\n", - "gap_8 = 100 * df_gap22_dc_8['numColdMisses'].astype(float) / (df_gap22_dc_8['numTotMisses'].astype(float)+df_gap22_dc_8['numTotHits'].astype(float))\n", - "gap_16 = 100 * df_gap22_dc_16['numColdMisses'].astype(float) / (df_gap22_dc_16['numTotMisses'].astype(float)+df_gap22_dc_16['numTotHits'].astype(float))\n", - "\n", - "\n", - "# Multi bar Chart\n", - "fig = plt.figure()\n", - "fig.set_size_inches(8,2)\n", - "\n", - "plt.ylim([0,30])\n", - "for i,app in enumerate(app_gap):\n", - " plt.bar(i*5, gap_1[i], width=1, color=cmap(1), label='1' if i==0 else None)\n", - " plt.bar(i*5+1, gap_2[i], width=1, color=cmap(2), label='2' if i==0 else None)\n", - " plt.bar(i*5+2, gap_8[i], width=1, color=cmap(3), label='8' if i==0 else None)\n", - " plt.bar(i*5+3, gap_16[i], width=1, color=cmap(4), label='16' if i==0 else None)\n", - "\n", - "offset = i*6-1\n", - "app_npb = df_npbC_dc_1['app']\n", - "npb_1 = 100 * df_npbC_dc_1['numColdMisses'].astype(float) / (df_npbC_dc_1['numTotMisses'].astype(float)+df_npbC_dc_1['numTotHits'].astype(float))\n", - "npb_2 = 100 * df_npbC_dc_2['numColdMisses'].astype(float) / (df_npbC_dc_2['numTotMisses'].astype(float)+df_npbC_dc_2['numTotHits'].astype(float))\n", - "npb_8 = 100 * df_npbC_dc_8['numColdMisses'].astype(float) / (df_npbC_dc_8['numTotMisses'].astype(float)+df_npbC_dc_8['numTotHits'].astype(float))\n", - "npb_16 = 100 * df_npbC_dc_16['numColdMisses'].astype(float) / (df_npbC_dc_16['numTotMisses'].astype(float)+df_npbC_dc_16['numTotHits'].astype(float))\n", - "\n", - "for i,app in enumerate(app_npb): \n", - " plt.bar(offset+i*5+1, npb_1[i], width=1, color=cmap(1))\n", - " plt.bar(offset+i*5+2, npb_2[i], width=1, color=cmap(2))\n", - " plt.bar(offset+i*5+3, npb_8[i], width=1, color=cmap(3))\n", - " plt.bar(offset+i*5+4, npb_16[i], width=1, color=cmap(4))\n", - "\n", - "plt.figtext(0.3, 0.01, \"GAPBS-22\")\n", - "plt.figtext(0.75, 0.01, \"NPB-C\")\n", - "\n", - "plt.xticks(np.arange(14)*5+1.5, list(app_gap)+list(app_npb))\n", - "plt.axvline(x=offset, color='black')\n", - "\n", - "plt.ylabel(\"Cold Miss Ratio (%)\")\n", - "plt.legend(fontsize=8, ncol=2)\n", - "plt.tight_layout()\n", - "#plt.savefig(\"../figures/cs1_all_bips.pdf\")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.6" - }, - "orig_nbformat": 4, - "vscode": { - "interpreter": { - "hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/src/mem/nvm_interface.cc b/src/mem/nvm_interface.cc index 366f71d56a..2c684edc19 100644 --- a/src/mem/nvm_interface.cc +++ b/src/mem/nvm_interface.cc @@ -402,9 +402,9 @@ NVMInterface::processReadReadyEvent() bool NVMInterface::burstReady(MemPacket* pkt) const { - bool read_rdy = pkt->isRead() && (ctrl->inReadBusState(true, this)) && + bool read_rdy = pkt->isRead() && (ctrl->inReadBusState(true, (MemInterface*)this)) && (pkt->readyTime <= curTick()) && (numReadDataReady > 0); - bool write_rdy = !pkt->isRead() && !ctrl->inReadBusState(true, this) && + bool write_rdy = !pkt->isRead() && !ctrl->inReadBusState(true, (MemInterface*)this) && !writeRespQueueFull(); return (read_rdy || write_rdy); } diff --git a/traffGen_def.py b/traffGen_def.py deleted file mode 100644 index 19468d670e..0000000000 --- a/traffGen_def.py +++ /dev/null @@ -1,131 +0,0 @@ -from m5.objects import * -import m5 -import argparse -from m5.objects.DRAMInterface import * -from m5.objects.NVMInterface import * - -args = argparse.ArgumentParser() - -args.add_argument( - "traffic_mode", - type = str, - help = "Traffic type to use" -) - -args.add_argument( - "rd_prct", - type=int, - help="Read Percentage", -) - -args.add_argument( - "extreme", - type=int, - help="extreme", -) - -args.add_argument( - "hit_miss", - type=int, - help="hit_miss", -) - -args.add_argument( - "clean_dirty", - type=int, - help="clean_dirty", -) - -options = args.parse_args() - -system = System() -system.clk_domain = SrcClockDomain() -system.clk_domain.clock = "4GHz" -system.clk_domain.voltage_domain = VoltageDomain() -system.mem_mode = 'timing' - -system.generator = PyTrafficGen() - -system.mem_ctrl = PolicyManager(range=AddrRange('3GiB')) - -system.mem_ctrl.orb_max_size = 128 -system.mem_ctrl.assoc = 1 -system.mem_ctrl.static_frontend_latency = "10ns" -system.mem_ctrl.static_backend_latency = "10ns" - -system.loc_mem_ctrl = MemCtrl() -system.loc_mem_ctrl.dram = TDRAM_32(range=AddrRange('3GiB'), in_addr_map=False, null=True) -system.mem_ctrl.loc_mem_policy = 'RambusTagProbOpt' - -system.mem_ctrl.loc_mem = system.loc_mem_ctrl.dram -system.loc_mem_ctrl.static_frontend_latency = "1ns" -system.loc_mem_ctrl.static_backend_latency = "1ns" -system.loc_mem_ctrl.static_frontend_latency_tc = "0ns" -system.loc_mem_ctrl.static_backend_latency_tc = "0ns" -system.loc_mem_ctrl.consider_oldest_write = True -system.loc_mem_ctrl.oldest_write_age_threshold = 2500000 - -system.far_mem_ctrl = MemCtrl() -system.far_mem_ctrl.dram = DDR4_2400_16x4(range=AddrRange('3GiB'),in_addr_map=False, null=True) -system.far_mem_ctrl.dram.read_buffer_size = 64 -system.far_mem_ctrl.dram.write_buffer_size = 64 -system.far_mem_ctrl.static_frontend_latency = "1ns" -system.far_mem_ctrl.static_backend_latency = "1ns" - -if options.extreme == 1: - system.mem_ctrl.extreme = True -else : - system.mem_ctrl.extreme = False - -if options.hit_miss == 1: - system.mem_ctrl.always_hit = True -else : - system.mem_ctrl.always_hit = False - -if options.clean_dirty == 1: - system.mem_ctrl.always_dirty = True -else : - system.mem_ctrl.always_dirty = False - -system.mem_ctrl.dram_cache_size = "128MiB" - -system.generator.port = system.mem_ctrl.port -system.loc_mem_ctrl.port = system.mem_ctrl.loc_req_port -system.far_mem_ctrl.port = system.mem_ctrl.far_req_port - -def createRandomTraffic(tgen): - yield tgen.createRandom(10000000000, # duration - 0, # min_addr - AddrRange('3GiB').end, # max_adr - 64, # block_size - 1000, # min_period - 1000, # max_period - options.rd_prct, # rd_perc - 0) # data_limit - yield tgen.createExit(0) - -def createLinearTraffic(tgen): - yield tgen.createLinear(10000000000, # duration - 0, # min_addr - AddrRange('3GiB').end, # max_adr - 64, # block_size - 1000, # min_period - 1000, # max_period - options.rd_prct, # rd_perc - 0) # data_limit - yield tgen.createExit(0) - -root = Root(full_system=False, system=system) - -m5.instantiate() - -if options.traffic_mode == 'linear': - system.generator.start(createLinearTraffic(system.generator)) -elif options.traffic_mode == 'random': - system.generator.start(createRandomTraffic(system.generator)) -else: - print('Wrong traffic type! Exiting!') - exit() - -exit_event = m5.simulate() -print(f"Exit reason {exit_event.getCause()}") diff --git a/traffGen_mem.py b/traffGen_mem.py deleted file mode 100644 index e108b40981..0000000000 --- a/traffGen_mem.py +++ /dev/null @@ -1,88 +0,0 @@ -from m5.objects import * -import m5 -import argparse -from m5.objects.DRAMInterface import * -from m5.objects.NVMInterface import * - -args = argparse.ArgumentParser() - -args.add_argument( - "traffic_mode", - type = str, - help = "Traffic type to use" -) - -args.add_argument( - "rd_prct", - type=int, - help="Read Percentage", -) - -options = args.parse_args() - -system = System() -system.clk_domain = SrcClockDomain() -system.clk_domain.clock = "4GHz" -system.clk_domain.voltage_domain = VoltageDomain() -system.mem_mode = 'timing' - -system.generator = PyTrafficGen() - -system.mem_ctrl = MemCtrl() -system.mem_ctrl.dram = TDRAM_32(range=AddrRange('3GiB')) -system.mem_ctrl.dram.activation_limit = 8 -system.mem_ctrl.dram.addr_mapping = 'RoCoRaBaCh' - -# DDR4 Alloy -# system.mem_ctrl.dram = DDR4_2400_16x4(range=AddrRange('3GiB')) -# system.mem_ctrl.dram.burst_length = 10 -# system.mem_ctrl.dram.tBURST = "4.165ns" -# system.mem_ctrl.dram.tCCD_L = "5ns" "6.25ns" -# system.mem_ctrl.dram.is_alloy = True - -# HBM2 1 PC Alloy -# system.mem_ctrl.dram = HBM_2000_4H_1x64(range=AddrRange('3GiB')) -# system.mem_ctrl.dram.burst_length = 10 -# system.mem_ctrl.dram.tBURST = "5ns" -# #system.mem_ctrl.dram.tCCD_L = "7ns" -# system.mem_ctrl.dram.is_alloy = True - - -system.generator.port = system.mem_ctrl.port - -def createRandomTraffic(tgen): - yield tgen.createRandom(10000000000, # duration - 0, # min_addr - AddrRange('3GiB').end, # max_adr - 64, # block_size - 1000, # min_period - 1000, # max_period - options.rd_prct, # rd_perc - 0) # data_limit - yield tgen.createExit(0) - -def createLinearTraffic(tgen): - yield tgen.createLinear(10000000000, # duration - 0, # min_addr - AddrRange('3GiB').end, # max_adr - 64, # block_size - 1000, # min_period - 1000, # max_period - options.rd_prct, # rd_perc - 0) # data_limit - yield tgen.createExit(0) - -root = Root(full_system=False, system=system) - -m5.instantiate() - -if options.traffic_mode == 'linear': - system.generator.start(createLinearTraffic(system.generator)) -elif options.traffic_mode == 'random': - system.generator.start(createRandomTraffic(system.generator)) -else: - print('Wrong traffic type! Exiting!') - exit() - -exit_event = m5.simulate() -print(f"Exit reason {exit_event.getCause()}") \ No newline at end of file From 09e9b5f93928a227f4c3b310d448e89000f61863 Mon Sep 17 00:00:00 2001 From: mbabaie <43761552+mbabaie@users.noreply.github.com> Date: Mon, 9 Oct 2023 18:34:03 -0700 Subject: [PATCH 04/28] Removed importing old RubySystem --- configs-npb-gapbs/system/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/configs-npb-gapbs/system/__init__.py b/configs-npb-gapbs/system/__init__.py index 33cc74a09a..7ef9c5dadd 100755 --- a/configs-npb-gapbs/system/__init__.py +++ b/configs-npb-gapbs/system/__init__.py @@ -28,5 +28,4 @@ # Authors: Jason Lowe-Power from .system import MySystem -from .ruby_system import MyRubySystemOld from .ruby_system_new import MyRubySystem From ef68c0aca6ec54dab6ff3086aafd4ffd7b87da91 Mon Sep 17 00:00:00 2001 From: mbabaie Date: Sun, 22 Oct 2023 16:08:31 -0700 Subject: [PATCH 05/28] mem: revert the last 2 commits with stats changes --- configs-npb-gapbs/restore_both.py | 6 +- src/mem/hbm_ctrl.cc | 2 +- src/mem/mem_ctrl.cc | 12 ++- src/mem/mem_ctrl.hh | 3 +- src/mem/policy_manager.cc | 15 +++- src/mem/policy_manager.hh | 4 +- state_machine | 32 +++++++ traffGen.py | 137 ++++++++++++++++++++++++++++++ traffGen_stateMachine.py | 83 ++++++++++++++++++ 9 files changed, 285 insertions(+), 9 deletions(-) create mode 100644 state_machine create mode 100644 traffGen.py create mode 100644 traffGen_stateMachine.py diff --git a/configs-npb-gapbs/restore_both.py b/configs-npb-gapbs/restore_both.py index feb0984399..b661bcacd2 100755 --- a/configs-npb-gapbs/restore_both.py +++ b/configs-npb-gapbs/restore_both.py @@ -203,9 +203,9 @@ def run(): if __name__ == "__m5_main__": args = parse_options() - kernel = "/fullSystemDisksKernel/x86-linux-kernel-4.19.83" - disk = "/fullSystemDisksKernel/x86-npb" - ckpt_base = "/chkpt1GigDC/" + kernel = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-linux-kernel-4.19.83" + disk = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-npb" + ckpt_base = "/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/chkpt1GigDC/" num_cpus = 8 cpu_type = "Timing" diff --git a/src/mem/hbm_ctrl.cc b/src/mem/hbm_ctrl.cc index 95e607b17d..ccecdefb4a 100644 --- a/src/mem/hbm_ctrl.cc +++ b/src/mem/hbm_ctrl.cc @@ -47,7 +47,7 @@ HBMCtrl::HBMCtrl(const HBMCtrlParams &p) : MemCtrl(p), retryRdReqPC1(false), retryWrReqPC1(false), nextReqEventPC1([this] {processNextReqEvent(pc1Int, respQueuePC1, - respondEventPC1, nextReqEventPC1, retryWrReqPC1);}, + respondEventPC1, nextReqEventPC1, retryWrReqPC1, retryRdReqPC1);}, name()), respondEventPC1([this] {processRespondEvent(pc1Int, respQueuePC1, respondEventPC1, retryRdReqPC1); }, name()), diff --git a/src/mem/mem_ctrl.cc b/src/mem/mem_ctrl.cc index e1935f4590..61c13bc080 100644 --- a/src/mem/mem_ctrl.cc +++ b/src/mem/mem_ctrl.cc @@ -63,7 +63,7 @@ MemCtrl::MemCtrl(const MemCtrlParams &p) : port(name() + ".port", *this), isTimingMode(false), retryRdReq(false), retryWrReq(false), nextReqEvent([this] {processNextReqEvent(dram, respQueue, - respondEvent, nextReqEvent, retryWrReq);}, name()), + respondEvent, nextReqEvent, retryWrReq, retryRdReq);}, name()), respondEvent([this] {processRespondEvent(dram, respQueue, respondEvent, retryRdReq); }, name()), dram(p.dram), @@ -1004,7 +1004,8 @@ MemCtrl::processNextReqEvent(MemInterface* mem_intr, MemPacketQueue& resp_queue, EventFunctionWrapper& resp_event, EventFunctionWrapper& next_req_event, - bool& retry_wr_req) { + bool& retry_wr_req, + bool& retry_rd_req) { DPRINTF(MemCtrl, "processNextReqEvent: readQueueSize: %d, writeQueueSize:%d, readQ: %d, writeQ: %d, respQ: %d\n", mem_intr->readQueueSize, mem_intr->writeQueueSize, readQueue[0].size(), writeQueue[0].size(), respQueue.size()); @@ -1353,6 +1354,12 @@ MemCtrl::processNextReqEvent(MemInterface* mem_intr, // case, which eventually will check for any draining and // also pause any further scheduling if there is really // nothing to do + + + if (retry_rd_req) { + retry_rd_req = false; + port.sendRetryReq(); + } } } // It is possible that a refresh to another rank kicks things back into @@ -1364,6 +1371,7 @@ MemCtrl::processNextReqEvent(MemInterface* mem_intr, retry_wr_req = false; port.sendRetryReq(); } + } bool diff --git a/src/mem/mem_ctrl.hh b/src/mem/mem_ctrl.hh index 1e175f22ef..c65296ecb3 100644 --- a/src/mem/mem_ctrl.hh +++ b/src/mem/mem_ctrl.hh @@ -332,7 +332,8 @@ class MemCtrl : public qos::MemCtrl MemPacketQueue& resp_queue, EventFunctionWrapper& resp_event, EventFunctionWrapper& next_req_event, - bool& retry_wr_req); + bool& retry_wr_req, + bool& retry_rd_req); EventFunctionWrapper nextReqEvent; virtual void processRespondEvent(MemInterface* mem_intr, diff --git a/src/mem/policy_manager.cc b/src/mem/policy_manager.cc index b28fb785fb..d16cb5e511 100644 --- a/src/mem/policy_manager.cc +++ b/src/mem/policy_manager.cc @@ -38,7 +38,7 @@ PolicyManager::PolicyManager(const PolicyManagerParams &p): infoCacheWarmupRatio(0.05), resetStatsWarmup(false), prevArrival(0), - retryLLC(false), retryLLCFarMemWr(false), + retryLLC(false), retryLLCRepetitive(false), retryLLCFarMemWr(false), retryTagCheck(false), retryLocMemRead(false), retryFarMemRead(false), retryLocMemWrite(false), retryFarMemWrite(false), maxConf(0), @@ -413,6 +413,13 @@ PolicyManager::recvTimingReq(PacketPtr pkt) return false; } + // This should only happen in traffic generator tests. + if (findInORB(pkt->getAddr())) { + ORB.at(pkt->getAddr())->repetitiveReqRcvd = true; + retryLLCRepetitive = true; + return false; + } + // if none of the above cases happens, // add it to the ORB handleRequestorPkt(pkt); @@ -2624,6 +2631,12 @@ PolicyManager::resumeConflictingReq(reqBufferEntry* orbEntry) } } + if (retryLLCRepetitive) { + DPRINTF(PolicyManager, "retryLLCRepetitive: sent\n"); + retryLLCRepetitive = false; + port.sendRetryReq(); + } + return conflictFound; } diff --git a/src/mem/policy_manager.hh b/src/mem/policy_manager.hh index c9b6979251..ab5f49e0a2 100644 --- a/src/mem/policy_manager.hh +++ b/src/mem/policy_manager.hh @@ -220,6 +220,7 @@ class PolicyManager : public AbstractMemory bool rcvdFarRdResp; Addr dirtyLineAddr; bool handleDirtyLine; + bool repetitiveReqRcvd; // recording the tick when the req transitions into a new stats. @@ -259,7 +260,7 @@ class PolicyManager : public AbstractMemory pol(_pol), state(_state), issued(_issued), isHit(_isHit), conflict(_conflict), prevDirty(_prevDirty), rcvdLocRdResp(_rcvdLocRdResp), rcvdFarRdResp(_rcvdFarRdResp), - dirtyLineAddr(_dirtyLineAddr), handleDirtyLine(_handleDirtyLine), + dirtyLineAddr(_dirtyLineAddr), handleDirtyLine(_handleDirtyLine), repetitiveReqRcvd(false), tagCheckEntered(_tagCheckEntered), tagCheckIssued(_tagCheckIssued), tagCheckExit(_tagCheckExit), locRdEntered(_locRdEntered), locRdIssued(_locRdIssued), locRdExit(_locRdExit), locWrEntered(_locWrEntered), locWrIssued(_locWrIssued), locWrExit(_locWrExit), @@ -297,6 +298,7 @@ class PolicyManager : public AbstractMemory * It helps remember if we have to retry a request when available. */ bool retryLLC; + bool retryLLCRepetitive; bool retryLLCFarMemWr; bool retryTagCheck; bool retryLocMemRead; diff --git a/state_machine b/state_machine new file mode 100644 index 0000000000..52c47aa220 --- /dev/null +++ b/state_machine @@ -0,0 +1,32 @@ +# STATE 0 0 LINEAR 70 0 33554368 64 500 500 33554368 +# STATE 1 1000000 IDLE +# STATE 2 0 EXIT +# STATE 3 0 LINEAR 70 0 67108800 64 500 500 67108800 +# STATE 4 1000000 IDLE +# STATE 5 0 EXIT +# STATE 6 1000000 IDLE +# INIT 0 +# TRANSITION 0 1 1 +# TRANSITION 1 2 1 +# TRANSITION 2 3 1 +# TRANSITION 3 4 1 +# TRANSITION 4 5 1 +# TRANSITION 5 6 1 +# TRANSITION 6 6 1 + +STATE 0 0 LINEAR 50 0 960 64 500 500 1024 +STATE 1 1000000 IDLE +STATE 2 0 EXIT +STATE 3 0 RANDOM 50 0 33554432 64 500 500 16777216 +STATE 4 1000000 IDLE +STATE 5 0 EXIT +STATE 6 1000000 IDLE +INIT 0 +TRANSITION 0 1 1 +TRANSITION 1 2 1 +TRANSITION 2 3 1 +TRANSITION 3 4 1 +TRANSITION 4 5 1 +TRANSITION 5 6 1 +TRANSITION 6 6 1 + diff --git a/traffGen.py b/traffGen.py new file mode 100644 index 0000000000..4d9db569a3 --- /dev/null +++ b/traffGen.py @@ -0,0 +1,137 @@ +from m5.objects import * +import m5 +import argparse +from m5.objects.DRAMInterface import * +from m5.objects.NVMInterface import * + +args = argparse.ArgumentParser() + +args.add_argument( + "traffic_mode", + type = str, + help = "Traffic type to use" +) + +args.add_argument( + "rd_prct", + type=int, + help="Read Percentage", +) + +args.add_argument( + "extreme", + type=int, + help="extreme", +) + +args.add_argument( + "hit_miss", + type=int, + help="hit_miss", +) + +args.add_argument( + "clean_dirty", + type=int, + help="clean_dirty", +) + +options = args.parse_args() + +system = System() +system.clk_domain = SrcClockDomain() +system.clk_domain.clock = "4GHz" +system.clk_domain.voltage_domain = VoltageDomain() +system.mem_mode = 'timing' + +system.generator = PyTrafficGen() + + +system.mem_ctrl = PolicyManager(range=AddrRange('3GiB')) + +system.mem_ctrl.orb_max_size = 128 +system.mem_ctrl.assoc = 4 +system.mem_ctrl.static_frontend_latency = "10ns" +system.mem_ctrl.static_backend_latency = "10ns" +system.mem_ctrl.loc_mem_policy = 'RambusTagProbOpt' + +system.loc_mem_ctrl = MemCtrl() +system.loc_mem_ctrl.dram = TDRAM(range=AddrRange('3GiB'), in_addr_map=False, null=True) +system.loc_mem_ctrl.dram.read_buffer_size = 64 +system.loc_mem_ctrl.dram.write_buffer_size = 64 +system.mem_ctrl.loc_mem = system.loc_mem_ctrl.dram +system.loc_mem_ctrl.static_frontend_latency = "1ns" +system.loc_mem_ctrl.static_backend_latency = "1ns" +system.loc_mem_ctrl.static_frontend_latency_tc = "0ns" +system.loc_mem_ctrl.static_backend_latency_tc = "0ns" +system.loc_mem_ctrl.consider_oldest_write = True +system.loc_mem_ctrl.oldest_write_age_threshold = 2500000 + +system.far_mem_ctrl = MemCtrl() +system.far_mem_ctrl.dram = DDR4_2400_16x4(range=AddrRange('3GiB'),in_addr_map=False, null=True) +system.far_mem_ctrl.dram.read_buffer_size = 64 +system.far_mem_ctrl.dram.write_buffer_size = 64 +system.far_mem_ctrl.static_frontend_latency = "1ns" +system.far_mem_ctrl.static_backend_latency = "1ns" + +if options.extreme == 1: + system.mem_ctrl.extreme = True +else : + system.mem_ctrl.extreme = False + +if options.hit_miss == 1: + system.mem_ctrl.always_hit = True +else : + system.mem_ctrl.always_hit = False + +if options.clean_dirty == 1: + system.mem_ctrl.always_dirty = True +else : + system.mem_ctrl.always_dirty = False + +system.mem_ctrl.dram_cache_size = "16MiB" + +system.generator.port = system.mem_ctrl.port +system.loc_mem_ctrl.port = system.mem_ctrl.loc_req_port +system.far_mem_ctrl.port = system.mem_ctrl.far_req_port + +def createRandomTraffic(tgen): + yield tgen.createRandom(1000000000, # duration + 0, # min_addr + AddrRange('1KiB').end, # max_adr + 64, # block_size + 500, # min_period + 500, # max_period + 50, # rd_perc + 0) # data_limit + yield tgen.createExit(0) + +def createLinearTraffic(tgen): + yield tgen.createLinear(1000000000, # duration + 0, # min_addr + AddrRange('1KiB').end, # max_adr + 64, # block_size + 500, # min_period + 500, # max_period + 50, # rd_perc + 0) # data_limit + yield tgen.createExit(0) + +root = Root(full_system=False, system=system) + +m5.instantiate() + +if options.traffic_mode == 'linear': + system.generator.start(createLinearTraffic(system.generator)) +elif options.traffic_mode == 'random': + system.generator.start(createRandomTraffic(system.generator)) +else: + print('Wrong traffic type! Exiting!') + exit() + +exit_event = m5.simulate() +if exit_event.getCause() == "cacheIsWarmedup": + print("Caught cacheIsWarmedup exit event!") + m5.stats.reset() +exit_event = m5.simulate() +print(f"Exit reason {exit_event.getCause()}") diff --git a/traffGen_stateMachine.py b/traffGen_stateMachine.py new file mode 100644 index 0000000000..0577fb7a0b --- /dev/null +++ b/traffGen_stateMachine.py @@ -0,0 +1,83 @@ +from m5.objects import * +import m5 +import argparse +from m5.objects.DRAMInterface import * +from m5.objects.NVMInterface import * + +args = argparse.ArgumentParser() + +args.add_argument( + "associativity", + type=int, + help="associativity", +) + +options = args.parse_args() + +system = System() +system.clk_domain = SrcClockDomain() +system.clk_domain.clock = "4GHz" +system.clk_domain.voltage_domain = VoltageDomain() +system.mem_mode = 'timing' + +system.generator = TrafficGen(config_file="state_machine") +system.generator.progress_check = "2ms" + +system.mem_ctrl = PolicyManager(range=AddrRange('4GiB')) + +system.mem_ctrl.orb_max_size = 8 +system.mem_ctrl.assoc = options.associativity +system.mem_ctrl.static_frontend_latency = "10ns" +system.mem_ctrl.static_backend_latency = "10ns" + +system.loc_mem_ctrl = MemCtrl() +system.loc_mem_ctrl.dram = TDRAM(range=AddrRange('4GiB'), in_addr_map=False, null=True) +system.mem_ctrl.loc_mem_policy = 'RambusTagProbOpt' + +system.mem_ctrl.loc_mem = system.loc_mem_ctrl.dram +system.loc_mem_ctrl.dram.read_buffer_size = 4 +system.loc_mem_ctrl.dram.write_buffer_size = 4 +system.loc_mem_ctrl.static_frontend_latency = "1ns" +system.loc_mem_ctrl.static_backend_latency = "1ns" +system.loc_mem_ctrl.static_frontend_latency_tc = "0ns" +system.loc_mem_ctrl.static_backend_latency_tc = "0ns" +system.loc_mem_ctrl.consider_oldest_write = True +system.loc_mem_ctrl.oldest_write_age_threshold = 2500000 +# system.loc_mem_ctrl.dram.tRLFAST = "32ns" +# system.loc_mem_ctrl.dram.tRCD_FAST = "32ns" + +system.far_mem_ctrl = MemCtrl() +system.far_mem_ctrl.dram = DDR4_2400_16x4(range=AddrRange('4GiB'),in_addr_map=False, null=True) +system.far_mem_ctrl.dram.read_buffer_size = 4 +system.far_mem_ctrl.dram.write_buffer_size = 4 +system.far_mem_ctrl.static_frontend_latency = "1ns" +system.far_mem_ctrl.static_backend_latency = "1ns" + +system.mem_ctrl.dram_cache_size = "16MiB" + +system.generator.port = system.mem_ctrl.port +system.loc_mem_ctrl.port = system.mem_ctrl.loc_req_port +system.far_mem_ctrl.port = system.mem_ctrl.far_req_port + +root = Root(full_system=False, system=system) + +m5.instantiate() + +exitSimCount = 0 + +while True: + exit_event = m5.simulate() + print(f"Exit reason {exit_event.getCause()}") + if exit_event.getCause().endswith("will terminate the simulation.\n") and exitSimCount == 0: + print("here0") + m5.stats.dump() + m5.stats.reset() + exitSimCount = exitSimCount + 1 + + elif exit_event.getCause().endswith("will terminate the simulation.\n") and exitSimCount == 1: + print("here1") + break + +print(f"Exit reason {exit_event.getCause()}") +print("here2") + From e7fda6ee147205a3b8483e5a847ac3f93ce9a974 Mon Sep 17 00:00:00 2001 From: mbabaie Date: Sun, 22 Oct 2023 18:16:07 -0700 Subject: [PATCH 06/28] fixed the repetitive req sent by traff gen --- configs-npb-gapbs/system/ruby_system_new.py | 2 +- src/mem/DRAMInterface.py | 92 +------------------ .../replacement_policies/replaceable_entry.hh | 4 +- src/mem/policy_manager.cc | 7 +- traffGen.py | 2 +- 5 files changed, 11 insertions(+), 96 deletions(-) diff --git a/configs-npb-gapbs/system/ruby_system_new.py b/configs-npb-gapbs/system/ruby_system_new.py index 96711da955..8f204a2327 100644 --- a/configs-npb-gapbs/system/ruby_system_new.py +++ b/configs-npb-gapbs/system/ruby_system_new.py @@ -217,7 +217,7 @@ def _createMemoryControllers( self.loc_mem_ctrl = MemCtrl() self.loc_mem_ctrl.consider_oldest_write = True self.loc_mem_ctrl.oldest_write_age_threshold = 2500000 - self.loc_mem_ctrl.dram = TDRAM_32( + self.loc_mem_ctrl.dram = TDRAM( range=self.mem_ranges[2], in_addr_map=False, kvm_map=False ) diff --git a/src/mem/DRAMInterface.py b/src/mem/DRAMInterface.py index d1f472015f..6417aca443 100644 --- a/src/mem/DRAMInterface.py +++ b/src/mem/DRAMInterface.py @@ -1272,98 +1272,8 @@ class HBM_2000_4H_1x64(DRAMInterface): two_cycle_activate = True -# A single HBM2 x64 interface (tested with HBMCtrl in gem5) -# to be used as a single pseudo channel. The timings are based -# on HBM gen2 specifications. 4H stack, 8Gb per die and total capacity -# of 4GiB. -class TDRAM(DRAMInterface): - - # 64-bit interface for a single pseudo channel - device_bus_width = 64 - - # HBM2 supports BL4 - burst_length = 8 - - # size of channel in bytes, 4H stack of 8Gb dies is 4GiB per stack; - # with 16 pseudo channels, 256MiB per pseudo channel - device_size = "256MiB" - - device_rowbuffer_size = "1KiB" - - # 1x128 configuration - devices_per_rank = 1 - - ranks_per_channel = 1 - - banks_per_rank = 32 - - bank_groups_per_rank = 8 - - # 1000 MHz for 2Gbps DDR data rate - tCK = "1ns" - - # new - tTAGBURST = "1ns" - tRL_FAST = "1ns" - tHM2DQ = "1ns" - tRTW_int = "2ns" - tRFBD = "2ns" - tRCD_FAST = "7.5ns" - tRC_FAST = "10.5ns" - enable_read_flush_buffer = True - flushBuffer_high_thresh_perc = 80 - - tRP = "14ns" - - tCCD_L = "4ns" - - tRCD = "12ns" - tRCD_WR = "6ns" - tCL = "18ns" - tCWL = "7ns" - tRAS = "28ns" - - tBURST = "4ns" - # value for 2Gb device from JEDEC spec - tRFC = "220ns" - - # value for 2Gb device from JEDEC spec - tREFI = "3.9us" - - tWR = "14ns" - tRTP = "5ns" - tWTR = "4ns" - tWTR_L = "9ns" - tRTW = "18ns" - - #tAAD from RBus - tAAD = "1ns" - - # single rank device, set to 0 - tCS = "0ns" - - tRRD = "3ns" - tRRD_L = "4ns" - - # for a single pseudo channel - tXAW = "16ns" - activation_limit = 4 - - # 4tCK - tXP = "8ns" - - # start with tRFC + tXP -> 160ns + 8ns = 168ns - tXS = "216ns" - - page_policy = 'close' - - read_buffer_size = 64 - write_buffer_size = 64 - - two_cycle_activate = True - -class TDRAM_32(DRAMInterface): +class TDRAM(DRAMInterface): # 64-bit interface for a single pseudo channel device_bus_width = 32 diff --git a/src/mem/cache/replacement_policies/replaceable_entry.hh b/src/mem/cache/replacement_policies/replaceable_entry.hh index cf31130399..c51881ee27 100644 --- a/src/mem/cache/replacement_policies/replaceable_entry.hh +++ b/src/mem/cache/replacement_policies/replaceable_entry.hh @@ -70,13 +70,15 @@ class ReplaceableEntry // constant to indicate that the cache line is dirty bool dirtyLine; Addr farMemAddr; + unsigned counter; ReplaceableEntry(Addr _tagDC, Addr _indexDC, bool _validLine, bool _dirtyLine, Addr _farMemAddr) : tagDC(_tagDC), indexDC(_indexDC), validLine(_validLine), dirtyLine(_dirtyLine), - farMemAddr(_farMemAddr) + farMemAddr(_farMemAddr), + counter(0) { } protected: diff --git a/src/mem/policy_manager.cc b/src/mem/policy_manager.cc index d16cb5e511..6277377854 100644 --- a/src/mem/policy_manager.cc +++ b/src/mem/policy_manager.cc @@ -2346,8 +2346,11 @@ PolicyManager::handleRequestorPkt(PacketPtr pkt) orbEntry->owPkt->getAddr(); } - // tagMetadataStore.at(orbEntry->indexDC).farMemAddr = - // orbEntry->owPkt->getAddr(); + if (orbEntry->isHit) { + tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->counter++; + } else { + tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->counter = 1; + } DPRINTF(PolicyManager, "ORB+: adr= %d, index= %d, tag= %d, cmd= %s, isHit= %d, wasDirty= %d, dirtyAddr= %d\n", orbEntry->owPkt->getAddr(), orbEntry->indexDC, orbEntry->tagDC, orbEntry->owPkt->cmdString(), orbEntry->isHit, orbEntry->prevDirty, orbEntry->dirtyLineAddr); } diff --git a/traffGen.py b/traffGen.py index 4d9db569a3..6437a1ebe7 100644 --- a/traffGen.py +++ b/traffGen.py @@ -59,7 +59,7 @@ system.loc_mem_ctrl.dram = TDRAM(range=AddrRange('3GiB'), in_addr_map=False, null=True) system.loc_mem_ctrl.dram.read_buffer_size = 64 system.loc_mem_ctrl.dram.write_buffer_size = 64 -system.mem_ctrl.loc_mem = system.loc_mem_ctrl.dram +system.loc_mem_ctrl.dram = system.mem_ctrl.loc_mem system.loc_mem_ctrl.static_frontend_latency = "1ns" system.loc_mem_ctrl.static_backend_latency = "1ns" system.loc_mem_ctrl.static_frontend_latency_tc = "0ns" From 6859ad20ade1c440055929d2c987330b6a64a2f1 Mon Sep 17 00:00:00 2001 From: mbabaie Date: Mon, 23 Oct 2023 09:52:45 -0700 Subject: [PATCH 07/28] fixed the stats pointer issue --- src/mem/mem_ctrl.cc | 20 +++++++++++++------- traffGen.py | 36 +++++++++++++++--------------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/mem/mem_ctrl.cc b/src/mem/mem_ctrl.cc index 61c13bc080..8cbd203246 100644 --- a/src/mem/mem_ctrl.cc +++ b/src/mem/mem_ctrl.cc @@ -1430,13 +1430,13 @@ MemCtrl::findCandidateForBSlot(MemPacket* AslotPkt) handleTCforBSlotPkt(BslotPktIt, AslotPkt->BSlotBusyUntil); - if (BslotPkt->pkt->owIsRead && BslotPkt->pkt->isHit) { - stats.foundCandidBSlotRH++; - } else if (BslotPkt->pkt->owIsRead && !BslotPkt->pkt->isHit && !BslotPkt->pkt->isDirty) { - stats.foundCandidBSlotRMC++; - } else if (BslotPkt->pkt->owIsRead && !BslotPkt->pkt->isHit && BslotPkt->pkt->isDirty) { - stats.foundCandidBSlotRMD++; - } + // if (BslotPkt->pkt->owIsRead && BslotPkt->pkt->isHit) { + // stats.foundCandidBSlotRH++; + // } else if (BslotPkt->pkt->owIsRead && !BslotPkt->pkt->isHit && !BslotPkt->pkt->isDirty) { + // stats.foundCandidBSlotRMC++; + // } else if (BslotPkt->pkt->owIsRead && !BslotPkt->pkt->isHit && BslotPkt->pkt->isDirty) { + // stats.foundCandidBSlotRMD++; + // } return true; } } @@ -1488,6 +1488,8 @@ MemCtrl::handleTCforBSlotPkt(MemPacketQueue::iterator BslotPktIt, Tick BSlotTagB assert(!BslotPkt->probedRdH); BslotPkt->probedRdH = true; + stats.foundCandidBSlotRH++; + return; } @@ -1520,6 +1522,8 @@ MemCtrl::handleTCforBSlotPkt(MemPacketQueue::iterator BslotPktIt, Tick BSlotTagB assert(!BslotPkt->probedRdMC); BslotPkt->probedRdMC = true; + stats.foundCandidBSlotRMC++; + delete BslotPkt->pkt; delete BslotPkt; return; @@ -1537,6 +1541,8 @@ MemCtrl::handleTCforBSlotPkt(MemPacketQueue::iterator BslotPktIt, Tick BSlotTagB assert(!BslotPkt->probedRdMD); BslotPkt->probedRdMD = true; + stats.foundCandidBSlotRMD++; + return; } diff --git a/traffGen.py b/traffGen.py index 6437a1ebe7..80c65a32d7 100644 --- a/traffGen.py +++ b/traffGen.py @@ -46,20 +46,18 @@ system.generator = PyTrafficGen() - system.mem_ctrl = PolicyManager(range=AddrRange('3GiB')) system.mem_ctrl.orb_max_size = 128 -system.mem_ctrl.assoc = 4 +system.mem_ctrl.assoc = 8 system.mem_ctrl.static_frontend_latency = "10ns" system.mem_ctrl.static_backend_latency = "10ns" -system.mem_ctrl.loc_mem_policy = 'RambusTagProbOpt' system.loc_mem_ctrl = MemCtrl() system.loc_mem_ctrl.dram = TDRAM(range=AddrRange('3GiB'), in_addr_map=False, null=True) -system.loc_mem_ctrl.dram.read_buffer_size = 64 -system.loc_mem_ctrl.dram.write_buffer_size = 64 -system.loc_mem_ctrl.dram = system.mem_ctrl.loc_mem +system.mem_ctrl.loc_mem_policy = 'RambusTagProbOpt' + +system.mem_ctrl.loc_mem = system.loc_mem_ctrl.dram system.loc_mem_ctrl.static_frontend_latency = "1ns" system.loc_mem_ctrl.static_backend_latency = "1ns" system.loc_mem_ctrl.static_frontend_latency_tc = "0ns" @@ -89,31 +87,31 @@ else : system.mem_ctrl.always_dirty = False -system.mem_ctrl.dram_cache_size = "16MiB" +system.mem_ctrl.dram_cache_size = "128MiB" system.generator.port = system.mem_ctrl.port system.loc_mem_ctrl.port = system.mem_ctrl.loc_req_port system.far_mem_ctrl.port = system.mem_ctrl.far_req_port def createRandomTraffic(tgen): - yield tgen.createRandom(1000000000, # duration + yield tgen.createRandom(10000000000, # duration 0, # min_addr - AddrRange('1KiB').end, # max_adr + AddrRange('3GiB').end, # max_adr 64, # block_size - 500, # min_period - 500, # max_period - 50, # rd_perc + 1000, # min_period + 1000, # max_period + options.rd_prct, # rd_perc 0) # data_limit yield tgen.createExit(0) def createLinearTraffic(tgen): - yield tgen.createLinear(1000000000, # duration + yield tgen.createLinear(10000000000, # duration 0, # min_addr - AddrRange('1KiB').end, # max_adr + AddrRange('3GiB').end, # max_adr 64, # block_size - 500, # min_period - 500, # max_period - 50, # rd_perc + 1000, # min_period + 1000, # max_period + options.rd_prct, # rd_perc 0) # data_limit yield tgen.createExit(0) @@ -130,8 +128,4 @@ def createLinearTraffic(tgen): exit() exit_event = m5.simulate() -if exit_event.getCause() == "cacheIsWarmedup": - print("Caught cacheIsWarmedup exit event!") - m5.stats.reset() -exit_event = m5.simulate() print(f"Exit reason {exit_event.getCause()}") From 19d7764c9fc5765050b9b46bb8785ec1d7db314d Mon Sep 17 00:00:00 2001 From: mbabaie Date: Thu, 26 Oct 2023 11:13:10 -0700 Subject: [PATCH 08/28] fixed some stats --- src/mem/policy_manager.cc | 29 ++++++++++++++++++++++++++++- src/mem/policy_manager.hh | 5 +++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/mem/policy_manager.cc b/src/mem/policy_manager.cc index 6277377854..52fe8c1036 100644 --- a/src/mem/policy_manager.cc +++ b/src/mem/policy_manager.cc @@ -38,6 +38,7 @@ PolicyManager::PolicyManager(const PolicyManagerParams &p): infoCacheWarmupRatio(0.05), resetStatsWarmup(false), prevArrival(0), + blksInserted(0), retryLLC(false), retryLLCRepetitive(false), retryLLCFarMemWr(false), retryTagCheck(false), retryLocMemRead(false), retryFarMemRead(false), retryLocMemWrite(false), retryFarMemWrite(false), @@ -2222,6 +2223,12 @@ PolicyManager::handleRequestorPkt(PacketPtr pkt) if (way == noMatchingWay) { // MISSED! Candidate = Either there's an empty way to fill in or a victim will be selected. way = getCandidateWay(index); + + // This is the current resident that is about to leave. + if (tagMetadataStore.at(index).at(way)->validLine) { + capacityTracker[tagMetadataStore.at(index).at(way)->farMemAddr] = blksInserted; + polManStats.blkReuse.sample(tagMetadataStore.at(index).at(way)->counter); + } } assert(way < assoc); @@ -2350,6 +2357,13 @@ PolicyManager::handleRequestorPkt(PacketPtr pkt) tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->counter++; } else { tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->counter = 1; + + blksInserted++; + + if (capacityTracker.find(orbEntry->owPkt->getAddr()) != capacityTracker.end()) { + polManStats.missDistance.sample(blksInserted - capacityTracker[orbEntry->owPkt->getAddr()]); + capacityTracker.erase(orbEntry->owPkt->getAddr()); + } } DPRINTF(PolicyManager, "ORB+: adr= %d, index= %d, tag= %d, cmd= %s, isHit= %d, wasDirty= %d, dirtyAddr= %d\n", orbEntry->owPkt->getAddr(), orbEntry->indexDC, orbEntry->tagDC, orbEntry->owPkt->cmdString(), orbEntry->isHit, orbEntry->prevDirty, orbEntry->dirtyLineAddr); @@ -3148,7 +3162,11 @@ PolicyManager::PolicyManagerStats::PolicyManagerStats(PolicyManager &_polMan) ADD_STAT(missRatio, statistics::units::Rate< statistics::units::Count, statistics::units::Count>::get(), "stat"), ADD_STAT(dirtyRatio, statistics::units::Rate< - statistics::units::Count, statistics::units::Count>::get(), "stat") + statistics::units::Count, statistics::units::Count>::get(), "stat"), + ADD_STAT(missDistance, statistics::units::Count::get(), + "Miss distance, to track capacity misses"), + ADD_STAT(blkReuse, statistics::units::Count::get(), + "cache line block reuse before eviction") { } @@ -3201,6 +3219,14 @@ PolicyManager::PolicyManagerStats::regStats() missRatio.precision(2); dirtyRatio.precision(2); + missDistance + .init(2048) + .flags(pdf | nozero); + + blkReuse + .init(128) + .flags(pdf | nozero); + // Formula stats avgRdBWSys = (bytesReadSys) / simSeconds; avgWrBWSys = (bytesWrittenSys) / simSeconds; @@ -3330,6 +3356,7 @@ PolicyManager::unserialize(CheckpointIn &cp) paramIn(cp, "dirtyLine", dirty); paramIn(cp, "farMemAddr", far_addr); Addr newIndex = index % numOfSets; + if (newIndex < tagMetadataStore.size()) { // Only insert if this entry fits into the current store. // tagMetadataStore.at(newIndex).at(i / numOfSets)->tagDC = tag; diff --git a/src/mem/policy_manager.hh b/src/mem/policy_manager.hh index ab5f49e0a2..6f5819d0a8 100644 --- a/src/mem/policy_manager.hh +++ b/src/mem/policy_manager.hh @@ -293,6 +293,9 @@ class PolicyManager : public AbstractMemory */ std::vector CRB; + std::unordered_map capacityTracker; + uint64_t blksInserted; + /** * This is a unified retry flag for both reads and writes. * It helps remember if we have to retry a request when available. @@ -509,6 +512,8 @@ class PolicyManager : public AbstractMemory statistics::Formula missRatio; statistics::Formula dirtyRatio; + statistics::Histogram missDistance; + statistics::Histogram blkReuse; }; From 264d4ae329b0f83be307087d9af3fc6f1345e4fe Mon Sep 17 00:00:00 2001 From: mbabaie Date: Fri, 27 Oct 2023 05:22:29 -0700 Subject: [PATCH 09/28] added new stats --- .../replacement_policies/replaceable_entry.hh | 6 +++- src/mem/policy_manager.cc | 31 +++++++++++++++++-- src/mem/policy_manager.hh | 4 +++ test.sh | 30 ++++++++++++++++++ 4 files changed, 67 insertions(+), 4 deletions(-) create mode 100755 test.sh diff --git a/src/mem/cache/replacement_policies/replaceable_entry.hh b/src/mem/cache/replacement_policies/replaceable_entry.hh index c51881ee27..26d8f44845 100644 --- a/src/mem/cache/replacement_policies/replaceable_entry.hh +++ b/src/mem/cache/replacement_policies/replaceable_entry.hh @@ -71,6 +71,8 @@ class ReplaceableEntry bool dirtyLine; Addr farMemAddr; unsigned counter; + uint64_t blksAccessedEntered; + uint64_t tickEntered; ReplaceableEntry(Addr _tagDC, Addr _indexDC, bool _validLine, bool _dirtyLine, Addr _farMemAddr) : tagDC(_tagDC), @@ -78,7 +80,9 @@ class ReplaceableEntry validLine(_validLine), dirtyLine(_dirtyLine), farMemAddr(_farMemAddr), - counter(0) + counter(0), + blksAccessedEntered(0), + tickEntered(MaxTick) { } protected: diff --git a/src/mem/policy_manager.cc b/src/mem/policy_manager.cc index 52fe8c1036..52254d694e 100644 --- a/src/mem/policy_manager.cc +++ b/src/mem/policy_manager.cc @@ -38,7 +38,7 @@ PolicyManager::PolicyManager(const PolicyManagerParams &p): infoCacheWarmupRatio(0.05), resetStatsWarmup(false), prevArrival(0), - blksInserted(0), + blksInserted(0), blksAccessed(0), retryLLC(false), retryLLCRepetitive(false), retryLLCFarMemWr(false), retryTagCheck(false), retryLocMemRead(false), retryFarMemRead(false), retryLocMemWrite(false), retryFarMemWrite(false), @@ -241,6 +241,7 @@ PolicyManager::recvTimingReq(PacketPtr pkt) // sendRespondToRequestor(pkt, frontendLatency); accessAndRespond(pkt, frontendLatency); + blksAccessed++; return true; } @@ -341,6 +342,7 @@ PolicyManager::recvTimingReq(PacketPtr pkt) // sendRespondToRequestor(pkt, frontendLatency); accessAndRespond(pkt, frontendLatency); + blksAccessed++; return true; } } @@ -2221,6 +2223,8 @@ PolicyManager::handleRequestorPkt(PacketPtr pkt) Addr index = returnIndexDC(pkt->getAddr(), pkt->getSize()); Addr way = findMatchingWay(index, tag); + blksAccessed++; + if (way == noMatchingWay) { // MISSED! Candidate = Either there's an empty way to fill in or a victim will be selected. way = getCandidateWay(index); @@ -2228,6 +2232,9 @@ PolicyManager::handleRequestorPkt(PacketPtr pkt) if (tagMetadataStore.at(index).at(way)->validLine) { capacityTracker[tagMetadataStore.at(index).at(way)->farMemAddr] = blksInserted; polManStats.blkReuse.sample(tagMetadataStore.at(index).at(way)->counter); + polManStats.blksAccBeforeEvict.sample(blksAccessed - + tagMetadataStore.at(index).at(way)->blksAccessedEntered); + polManStats.ticksBeforeEviction.sample(curTick() - tagMetadataStore.at(index).at(way)->tickEntered); } } @@ -2357,6 +2364,8 @@ PolicyManager::handleRequestorPkt(PacketPtr pkt) tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->counter++; } else { tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->counter = 1; + tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->blksAccessedEntered = blksAccessed; + tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->tickEntered = curTick(); blksInserted++; @@ -3166,7 +3175,11 @@ PolicyManager::PolicyManagerStats::PolicyManagerStats(PolicyManager &_polMan) ADD_STAT(missDistance, statistics::units::Count::get(), "Miss distance, to track capacity misses"), ADD_STAT(blkReuse, statistics::units::Count::get(), - "cache line block reuse before eviction") + "cache line block reuse before eviction"), + ADD_STAT(blksAccBeforeEvict, statistics::units::Count::get(), + "# of accesses addressed before eviction of this blk"), + ADD_STAT(ticksBeforeEviction, statistics::units::Count::get(), + "how long the blk was in the cache") { } @@ -3222,11 +3235,19 @@ PolicyManager::PolicyManagerStats::regStats() missDistance .init(2048) .flags(pdf | nozero); - + blkReuse .init(128) .flags(pdf | nozero); + blksAccBeforeEvict + .init(1024) + .flags(pdf | nozero); + + ticksBeforeEviction + .init(1024) + .flags(pdf | nozero); + // Formula stats avgRdBWSys = (bytesReadSys) / simSeconds; avgWrBWSys = (bytesWrittenSys) / simSeconds; @@ -3365,6 +3386,10 @@ PolicyManager::unserialize(CheckpointIn &cp) // tagMetadataStore.at(newIndex).at(i / numOfSets)->dirtyLine = dirty; // tagMetadataStore.at(newIndex).at(i / numOfSets)->farMemAddr = far_addr; int way = findEmptyWay(newIndex); + + if (way ==-1) { + way = 0; + } tagMetadataStore.at(newIndex).at(way)->tagDC = returnTagDC(far_addr, blockSize); // = tag; tagMetadataStore.at(newIndex).at(way)->indexDC = newIndex; tagMetadataStore.at(newIndex).at(way)->validLine = valid; diff --git a/src/mem/policy_manager.hh b/src/mem/policy_manager.hh index 6f5819d0a8..834afdabaf 100644 --- a/src/mem/policy_manager.hh +++ b/src/mem/policy_manager.hh @@ -295,6 +295,8 @@ class PolicyManager : public AbstractMemory std::unordered_map capacityTracker; uint64_t blksInserted; + uint64_t blksAccessed; + /** * This is a unified retry flag for both reads and writes. @@ -514,6 +516,8 @@ class PolicyManager : public AbstractMemory statistics::Formula dirtyRatio; statistics::Histogram missDistance; statistics::Histogram blkReuse; + statistics::Histogram blksAccBeforeEvict; + statistics::Histogram ticksBeforeEviction; }; diff --git a/test.sh b/test.sh new file mode 100755 index 0000000000..96ff021425 --- /dev/null +++ b/test.sh @@ -0,0 +1,30 @@ + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/bt configs-npb-gapbs/restore_both.py bt.C.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/cg configs-npb-gapbs/restore_both.py cg.C.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/ft configs-npb-gapbs/restore_both.py ft.C.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/is configs-npb-gapbs/restore_both.py is.C.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/lu configs-npb-gapbs/restore_both.py lu.C.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/mg configs-npb-gapbs/restore_both.py mg.C.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/sp configs-npb-gapbs/restore_both.py sp.C.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/ua configs-npb-gapbs/restore_both.py ua.C.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/bc configs-npb-gapbs/restore_both.py bc-22 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/bfs configs-npb-gapbs/restore_both.py bfs-22 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/cc configs-npb-gapbs/restore_both.py cc-22 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/pr configs-npb-gapbs/restore_both.py pr-22 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/tc configs-npb-gapbs/restore_both.py tc-22 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/sssp configs-npb-gapbs/restore_both.py sssp-22 RambusTagProbOpt 1 0 0 0 & + +build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/NPB/bt configs-npb-gapbs/restore_both.py bt.D.x RambusTagProbOpt 1 0 0 0 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/NPB/cg configs-npb-gapbs/restore_both.py cg.D.x RambusTagProbOpt 1 0 0 0 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/NPB/ft configs-npb-gapbs/restore_both.py ft.D.x RambusTagProbOpt 1 0 0 0 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/NPB/is configs-npb-gapbs/restore_both.py is.D.x RambusTagProbOpt 1 0 0 0 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/NPB/lu configs-npb-gapbs/restore_both.py lu.D.x RambusTagProbOpt 1 0 0 0 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/NPB/mg configs-npb-gapbs/restore_both.py mg.D.x RambusTagProbOpt 1 0 0 0 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/NPB/sp configs-npb-gapbs/restore_both.py sp.D.x RambusTagProbOpt 1 0 0 0 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/NPB/ua configs-npb-gapbs/restore_both.py ua.D.x RambusTagProbOpt 1 0 0 0 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/GAPBS/bc configs-npb-gapbs/restore_both.py bc-25 RambusTagProbOpt 1 0 0 0 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/GAPBS/bfs configs-npb-gapbs/restore_both.py bfs-25 RambusTagProbOpt 1 0 0 0 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/GAPBS/cc configs-npb-gapbs/restore_both.py cc-25 RambusTagProbOpt 1 0 0 0 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/GAPBS/pr configs-npb-gapbs/restore_both.py pr-25 RambusTagProbOpt 1 0 0 0 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/GAPBS/tc configs-npb-gapbs/restore_both.py tc-25 RambusTagProbOpt 1 0 0 0 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/GAPBS/sssp configs-npb-gapbs/restore_both.py sssp-25 RambusTagProbOpt 1 0 0 0 & \ No newline at end of file From 1cff8833e17d17f5abf29fbaf2ea7de6606331be Mon Sep 17 00:00:00 2001 From: mbabaie Date: Fri, 27 Oct 2023 11:34:02 -0700 Subject: [PATCH 10/28] fixed a stat --- src/mem/policy_manager.cc | 11 +++++--- state_machine | 36 ++++++++++++------------- test.sh | 56 +++++++++++++++++++-------------------- 3 files changed, 53 insertions(+), 50 deletions(-) diff --git a/src/mem/policy_manager.cc b/src/mem/policy_manager.cc index 52254d694e..aa260b6a2d 100644 --- a/src/mem/policy_manager.cc +++ b/src/mem/policy_manager.cc @@ -2231,10 +2231,13 @@ PolicyManager::handleRequestorPkt(PacketPtr pkt) // This is the current resident that is about to leave. if (tagMetadataStore.at(index).at(way)->validLine) { capacityTracker[tagMetadataStore.at(index).at(way)->farMemAddr] = blksInserted; - polManStats.blkReuse.sample(tagMetadataStore.at(index).at(way)->counter); - polManStats.blksAccBeforeEvict.sample(blksAccessed - - tagMetadataStore.at(index).at(way)->blksAccessedEntered); - polManStats.ticksBeforeEviction.sample(curTick() - tagMetadataStore.at(index).at(way)->tickEntered); + if (tagMetadataStore.at(index).at(way)->tickEntered != MaxTick) { + polManStats.blkReuse.sample(tagMetadataStore.at(index).at(way)->counter); + polManStats.blksAccBeforeEvict.sample(blksAccessed - + tagMetadataStore.at(index).at(way)->blksAccessedEntered); + assert(curTick() >= tagMetadataStore.at(index).at(way)->tickEntered); + polManStats.ticksBeforeEviction.sample(curTick() - tagMetadataStore.at(index).at(way)->tickEntered); + } } } diff --git a/state_machine b/state_machine index 52c47aa220..3c8e45e42b 100644 --- a/state_machine +++ b/state_machine @@ -1,23 +1,7 @@ -# STATE 0 0 LINEAR 70 0 33554368 64 500 500 33554368 -# STATE 1 1000000 IDLE -# STATE 2 0 EXIT -# STATE 3 0 LINEAR 70 0 67108800 64 500 500 67108800 -# STATE 4 1000000 IDLE -# STATE 5 0 EXIT -# STATE 6 1000000 IDLE -# INIT 0 -# TRANSITION 0 1 1 -# TRANSITION 1 2 1 -# TRANSITION 2 3 1 -# TRANSITION 3 4 1 -# TRANSITION 4 5 1 -# TRANSITION 5 6 1 -# TRANSITION 6 6 1 - -STATE 0 0 LINEAR 50 0 960 64 500 500 1024 +STATE 0 0 LINEAR 70 0 33554368 64 500 500 33554368 STATE 1 1000000 IDLE STATE 2 0 EXIT -STATE 3 0 RANDOM 50 0 33554432 64 500 500 16777216 +STATE 3 0 LINEAR 70 0 67108800 64 500 500 67108800 STATE 4 1000000 IDLE STATE 5 0 EXIT STATE 6 1000000 IDLE @@ -30,3 +14,19 @@ TRANSITION 4 5 1 TRANSITION 5 6 1 TRANSITION 6 6 1 +# STATE 0 0 LINEAR 50 0 960 64 500 500 1024 +# STATE 1 1000000 IDLE +# STATE 2 0 EXIT +# STATE 3 0 RANDOM 50 0 33554432 64 500 500 16777216 +# STATE 4 1000000 IDLE +# STATE 5 0 EXIT +# STATE 6 1000000 IDLE +# INIT 0 +# TRANSITION 0 1 1 +# TRANSITION 1 2 1 +# TRANSITION 2 3 1 +# TRANSITION 3 4 1 +# TRANSITION 4 5 1 +# TRANSITION 5 6 1 +# TRANSITION 6 6 1 + diff --git a/test.sh b/test.sh index 96ff021425..6eaa69ffad 100755 --- a/test.sh +++ b/test.sh @@ -1,30 +1,30 @@ -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/bt configs-npb-gapbs/restore_both.py bt.C.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/cg configs-npb-gapbs/restore_both.py cg.C.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/ft configs-npb-gapbs/restore_both.py ft.C.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/is configs-npb-gapbs/restore_both.py is.C.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/lu configs-npb-gapbs/restore_both.py lu.C.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/mg configs-npb-gapbs/restore_both.py mg.C.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/sp configs-npb-gapbs/restore_both.py sp.C.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/ua configs-npb-gapbs/restore_both.py ua.C.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/bc configs-npb-gapbs/restore_both.py bc-22 RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/bfs configs-npb-gapbs/restore_both.py bfs-22 RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/cc configs-npb-gapbs/restore_both.py cc-22 RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/pr configs-npb-gapbs/restore_both.py pr-22 RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/tc configs-npb-gapbs/restore_both.py tc-22 RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults5/baseline/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/sssp configs-npb-gapbs/restore_both.py sssp-22 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/bt configs-npb-gapbs/restore_both.py bt.C.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/cg configs-npb-gapbs/restore_both.py cg.C.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/ft configs-npb-gapbs/restore_both.py ft.C.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/is configs-npb-gapbs/restore_both.py is.C.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/lu configs-npb-gapbs/restore_both.py lu.C.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/mg configs-npb-gapbs/restore_both.py mg.C.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/sp configs-npb-gapbs/restore_both.py sp.C.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/ua configs-npb-gapbs/restore_both.py ua.C.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/bc configs-npb-gapbs/restore_both.py bc-22 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/bfs configs-npb-gapbs/restore_both.py bfs-22 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/cc configs-npb-gapbs/restore_both.py cc-22 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/pr configs-npb-gapbs/restore_both.py pr-22 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/tc configs-npb-gapbs/restore_both.py tc-22 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/sssp configs-npb-gapbs/restore_both.py sssp-22 RambusTagProbOpt 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/NPB/bt configs-npb-gapbs/restore_both.py bt.D.x RambusTagProbOpt 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/NPB/cg configs-npb-gapbs/restore_both.py cg.D.x RambusTagProbOpt 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/NPB/ft configs-npb-gapbs/restore_both.py ft.D.x RambusTagProbOpt 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/NPB/is configs-npb-gapbs/restore_both.py is.D.x RambusTagProbOpt 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/NPB/lu configs-npb-gapbs/restore_both.py lu.D.x RambusTagProbOpt 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/NPB/mg configs-npb-gapbs/restore_both.py mg.D.x RambusTagProbOpt 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/NPB/sp configs-npb-gapbs/restore_both.py sp.D.x RambusTagProbOpt 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/NPB/ua configs-npb-gapbs/restore_both.py ua.D.x RambusTagProbOpt 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/GAPBS/bc configs-npb-gapbs/restore_both.py bc-25 RambusTagProbOpt 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/GAPBS/bfs configs-npb-gapbs/restore_both.py bfs-25 RambusTagProbOpt 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/GAPBS/cc configs-npb-gapbs/restore_both.py cc-25 RambusTagProbOpt 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/GAPBS/pr configs-npb-gapbs/restore_both.py pr-25 RambusTagProbOpt 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/GAPBS/tc configs-npb-gapbs/restore_both.py tc-25 RambusTagProbOpt 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults/baseline/noDC/1GB_85GB_g25_nD/GAPBS/sssp configs-npb-gapbs/restore_both.py sssp-25 RambusTagProbOpt 1 0 0 0 & \ No newline at end of file +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/NPB/bt configs-npb-gapbs/restore_both.py bt.D.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/NPB/cg configs-npb-gapbs/restore_both.py cg.D.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/NPB/ft configs-npb-gapbs/restore_both.py ft.D.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/NPB/is configs-npb-gapbs/restore_both.py is.D.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/NPB/lu configs-npb-gapbs/restore_both.py lu.D.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/NPB/mg configs-npb-gapbs/restore_both.py mg.D.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/NPB/sp configs-npb-gapbs/restore_both.py sp.D.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/NPB/ua configs-npb-gapbs/restore_both.py ua.D.x RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/GAPBS/bc configs-npb-gapbs/restore_both.py bc-25 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/GAPBS/bfs configs-npb-gapbs/restore_both.py bfs-25 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/GAPBS/cc configs-npb-gapbs/restore_both.py cc-25 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/GAPBS/pr configs-npb-gapbs/restore_both.py pr-25 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/GAPBS/tc configs-npb-gapbs/restore_both.py tc-25 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/GAPBS/sssp configs-npb-gapbs/restore_both.py sssp-25 RambusTagProbOpt 1 0 0 0 & \ No newline at end of file From 5a61397d9c0c2ea6f573aa149f6003b32a90c760 Mon Sep 17 00:00:00 2001 From: mbabaie Date: Fri, 27 Oct 2023 14:03:35 -0700 Subject: [PATCH 11/28] new configs for 8 chnnels of HBM --- .../gapbs_checkpoint.py | 188 ++++++++ configs-npb-gapbs-8Channel/info.py | 325 ++++++++++++++ configs-npb-gapbs-8Channel/npb_checkpoint.py | 251 +++++++++++ configs-npb-gapbs-8Channel/restore_both.py | 333 ++++++++++++++ .../system/MESI_Two_Level.py | 335 ++++++++++++++ .../system/MI_example_caches.py | 275 ++++++++++++ .../system/MOESI_CMP_directory.py | 350 +++++++++++++++ configs-npb-gapbs-8Channel/system/__init__.py | 31 ++ configs-npb-gapbs-8Channel/system/caches.py | 173 ++++++++ configs-npb-gapbs-8Channel/system/fs_tools.py | 39 ++ .../system/ruby_system_new.py | 386 ++++++++++++++++ configs-npb-gapbs-8Channel/system/system.py | 414 ++++++++++++++++++ .../system/system_back.py | 397 +++++++++++++++++ configs-npb-gapbs/system/ruby_system_new.py | 2 +- test.sh | 4 +- 15 files changed, 3501 insertions(+), 2 deletions(-) create mode 100755 configs-npb-gapbs-8Channel/gapbs_checkpoint.py create mode 100644 configs-npb-gapbs-8Channel/info.py create mode 100755 configs-npb-gapbs-8Channel/npb_checkpoint.py create mode 100755 configs-npb-gapbs-8Channel/restore_both.py create mode 100755 configs-npb-gapbs-8Channel/system/MESI_Two_Level.py create mode 100755 configs-npb-gapbs-8Channel/system/MI_example_caches.py create mode 100755 configs-npb-gapbs-8Channel/system/MOESI_CMP_directory.py create mode 100755 configs-npb-gapbs-8Channel/system/__init__.py create mode 100755 configs-npb-gapbs-8Channel/system/caches.py create mode 100755 configs-npb-gapbs-8Channel/system/fs_tools.py create mode 100644 configs-npb-gapbs-8Channel/system/ruby_system_new.py create mode 100755 configs-npb-gapbs-8Channel/system/system.py create mode 100755 configs-npb-gapbs-8Channel/system/system_back.py diff --git a/configs-npb-gapbs-8Channel/gapbs_checkpoint.py b/configs-npb-gapbs-8Channel/gapbs_checkpoint.py new file mode 100755 index 0000000000..a21710cace --- /dev/null +++ b/configs-npb-gapbs-8Channel/gapbs_checkpoint.py @@ -0,0 +1,188 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2019 The Regents of the University of California. +# All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power, Ayaz Akram + +""" Script to run GAP Benchmark suites workloads. + The workloads have two modes: synthetic and real graphs. +""" +import argparse +import time +import m5 +import m5.ticks +from m5.objects import * + +from system import * + +supported_protocols = ["MESI_Two_Level"] +supported_cpu_types = ["kvm", "atomic", "timing"] + + +def writeBenchScript(dir, benchmark_name, size, synthetic): + """ + This method creates a script in dir which will be eventually + passed to the simulated system (to run a specific benchmark + at bootup). + """ + input_file_name = "{}/run_{}_{}".format(dir, benchmark_name, size) + if synthetic: + with open(input_file_name, "w") as f: + f.write("./{} -g {}\n".format(benchmark_name, size)) + elif synthetic == 0: + with open(input_file_name, "w") as f: + # The workloads that are copied to the disk image using Packer + # should be located in /home/gem5/. + # Since the command running the workload will be executed with + # pwd = /home/gem5/gapbs, the path to the copied workload is + # ../{workload-name} + f.write("./{} -sf ../{}".format(benchmark_name, size)) + + return input_file_name + + +def parse_options(): + + parser = argparse.ArgumentParser( + description="For use with gem5. This " + "runs a GAPBS applications. This only works " + "with x86 ISA." + ) + + # The manditry position arguments. + parser.add_argument( + "benchmark", type=str, help="The GAPBS application to run" + ) + parser.add_argument("graph", type=str, help="The GAPBS application to run") + parser.add_argument( + "dcache_policy", + type=str, + help="The architecture of DRAM cache: " + "CascadeLakeNoPartWrs, Oracle, BearWriteOpt, Rambus", + ) + + return parser.parse_args() + + +if __name__ == "__m5_main__": + args = parse_options() + + + kernel = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-linux-kernel-4.19.83" + disk = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-npb" + + num_cpus = 8 + cpu_type = "Timing" + mem_sys = "MESI_Two_Level" + synthetic = 1 + + dcache_size = "1GiB" # size of each channel + mem_size = "128GiB" + mem_size_per_channel = "64GiB" + assoc = 1 + # create the system we are going to simulate + system = MyRubySystem( + kernel, + disk, + mem_sys, + num_cpus, + assoc, + dcache_size, + mem_size, + mem_size_per_channel, + args.dcache_policy, + 0, + 0, + 0, + args, + ) + + system.m5ops_base = 0xFFFF0000 + + # Exit from guest on workbegin/workend + system.exit_on_work_items = True + + # Create and pass a script to the simulated system to run the reuired + # benchmark + system.readfile = writeBenchScript( + m5.options.outdir, args.benchmark, args.graph, synthetic + ) + + # set up the root SimObject and start the simulation + root = Root(full_system=True, system=system) + + if system.getHostParallel(): + # Required for running kvm on multiple host cores. + # Uses gem5's parallel event queue feature + # Note: The simulator is quite picky about this number! + root.sim_quantum = int(1e9) # 1 ms + + # needed for long running jobs + # m5.disableAllListeners() + + # instantiate all of the objects we've created above + m5.instantiate() + + globalStart = time.time() + + print("Running the simulation") + print("Using cpu: {}".format(cpu_type)) + exit_event = m5.simulate() + + if exit_event.getCause() == "workbegin": + print("Done booting Linux") + # Reached the start of ROI + # start of ROI is marked by an + # m5_work_begin() call + print("Resetting stats at the start of ROI!") + m5.stats.reset() + start_tick = m5.curTick() + start_insts = system.totalInsts() + # switching CPU to timing + system.switchCpus(system.cpu, system.timingCpu) + else: + print("Unexpected termination of simulation !") + exit() + + m5.stats.reset() + print( + "After reset ************************************************ statring smiulation:\n" + ) + for interval_number in range(0,1): + print("Interval number: {} \n".format(interval_number)) + exit_event = m5.simulate(1000000000) + if exit_event.getCause() == "cacheIsWarmedup": + print("Caught cacheIsWarmedup exit event!") + break + print( + "-------------------------------------------------------------------" + ) + + print( + "After sim ************************************************ End of warm-up \n" + ) + m5.stats.dump() + system.switchCpus(system.timingCpu, system.o3Cpu) + m5.checkpoint(m5.options.outdir + "/cpt") diff --git a/configs-npb-gapbs-8Channel/info.py b/configs-npb-gapbs-8Channel/info.py new file mode 100644 index 0000000000..7547fb421a --- /dev/null +++ b/configs-npb-gapbs-8Channel/info.py @@ -0,0 +1,325 @@ +text_info = { + # exe size start + "bt.A.x": (0x00018402, 0x0000000000400E50), + "bt.B.x": (0x000183E2, 0x0000000000400E50), + "bt.C.x": (0x00018342, 0x0000000000400E50), + "bt.D.x": (0x00018562, 0x0000000000400E50), + "cg.A.x": (0x00005D22, 0x0000000000400F60), + "cg.B.x": (0x00005DC2, 0x0000000000400F60), + "cg.C.x": (0x00005E32, 0x0000000000400F60), + "cg.D.x": (0x00005AC2, 0x0000000000400F60), + "ep.A.x": (0x00001E52, 0x0000000000400DB0), + "ep.B.x": (0x00001E52, 0x0000000000400DB0), + "ep.C.x": (0x00001E52, 0x0000000000400DB0), + "ep.D.x": (0x00001E52, 0x0000000000400DB0), + "ft.A.x": (0x00005202, 0x0000000000400F60), + "ft.B.x": (0x00005752, 0x0000000000400F60), + "ft.C.x": (0x00005762, 0x0000000000400F60), + "ft.D.x": (0x00005772, 0x0000000000400F60), + "is.A.x": (0x000020B2, 0x0000000000400BE0), + "is.B.x": (0x000020C2, 0x0000000000400BE0), + "is.C.x": (0x000020B2, 0x0000000000400BE0), + "is.D.x": (0x00001EB2, 0x0000000000400BE0), + "lu.A.x": (0x00016A82, 0x0000000000400F50), + "lu.B.x": (0x00016A52, 0x0000000000400F50), + "lu.C.x": (0x000169C2, 0x0000000000400F50), + "lu.D.x": (0x00016DD2, 0x0000000000400F50), + "mg.A.x": (0x0000B4A2, 0x00000000004010F0), + "mg.B.x": (0x0000B4A2, 0x00000000004010F0), + "mg.C.x": (0x0000B5E2, 0x00000000004010F0), + "mg.D.x": (0x0000B772, 0x00000000004010F0), + "sp.A.x": (0x00014162, 0x0000000000400EB0), + "sp.B.x": (0x00014162, 0x0000000000400EB0), + "sp.C.x": (0x00014052, 0x0000000000400EB0), + "sp.D.x": (0x000141B2, 0x0000000000400EB0), + "ua.A.x": (0x000274E2, 0x00000000004010C0), + "ua.B.x": (0x00027612, 0x00000000004010C0), + "ua.C.x": (0x00027552, 0x00000000004010C0), + "ua.D.x": (0x000274C2, 0x00000000004010C0), + "bc-22": (0x0000EFD2, 0x00000000004029F0), + "bfs-22": (0x0000DCF2, 0x00000000004028A0), + "cc-22": (0x0000E4C2, 0x0000000000402BE0), + "cc_sv-22": (0x0000DF12, 0x0000000000402970), + "pr-22": (0x0000E022, 0x0000000000402A10), + "sssp-22": (0x0000E692, 0x00000000004029C0), + "tc-22": (0x0000DEE2, 0x0000000000402890), + "bc-25": (0x0000EFD2, 0x00000000004029F0), + "bfs-25": (0x0000DCF2, 0x00000000004028A0), + "cc-25": (0x0000E4C2, 0x0000000000402BE0), + "cc_sv-25": (0x0000DF12, 0x0000000000402970), + "pr-25": (0x0000E022, 0x0000000000402A10), + "sssp-25": (0x0000E692, 0x00000000004029C0), + "tc-25": (0x0000DEE2, 0x0000000000402890), +} + +interval_info_1hr = { + # exe pc count + "bc-22": (0x404E08, 5409997), + "bfs-22": (0x403790, 3930710), + "bt.C.x": (0x4080E0, 1270955), + "cc-22": (0x4037B0, 8388093), + "cg.C.x": (0x4019D8, 29870850), + "pr-22": (0x4036C0, 25174574), + "ft.C.x": (0x400D70, 6760163), + "ua.C.x": (0x406B00, 344413), + "mg.C.x": (0x401B08, 4467087), + "sp.C.x": (0x409170, 1569121), + "lu.C.x": (0x402980, 5146555), + "is.C.x": (0x4017C9, 48480186), + "tc-22": (0x4052E0, 240202), + "sssp-22": (0x405441, 12651169), + "bc-25": (0x404E1A, 2192896), + "bfs-25": (0x4038E0, 11170933), + "bt.D.x": (0x407FD0, 3729824), + "cc-25": (0x404688, 6506055), + "cg.D.x": (0x4019D8, 17675668), + "pr-25": (0x4036C0, 19663604), + "ft.D.x": (0x400D70, 6498319), + "ua.D.x": (0x400F30, 2709903), + "mg.D.x": (0x401920, 3670463), + "sp.D.x": (0x409000, 3786010), + "lu.D.x": (0x402600, 116), + "is.D.x": (0x401661, 42645519), + "tc-25": (0x4030A0, 5800667), + "sssp-25": (0x405418, 979358), +} + +interval_info_3hr = { + # exe pc count + "bc-22": (0x404E08, 14968517), + "bfs-22": (0x403790, 12277309), + "bt.C.x": (0x408600, 1906919), + "cc-22": (0x404238, 5701575), + "cg.C.x": (0x4019D8, 73121983), + "pr-22": (0x4036C0, 69152771), + "ft.C.x": (0x400D70, 16530458), + "ua.C.x": (0x41D080, 4205282), + "mg.C.x": (0x401920, 12053283), + "sp.C.x": (0x409668, 2192349), + "lu.C.x": (0x402980, 9952905), + "is.C.x": (0x401955, 12922496), + "tc-22": (0x4034E0, 1507255), + "sssp-22": (0x405441, 33740179), + "bc-25": (0x404E08, 6310746), + "bfs-25": (0x4045D0, 2021755), + "bt.D.x": (0x407FD0, 10661006), + "cc-25": (0x4037B0, 31963857), + "cg.D.x": (0x4019D8, 45636549), + "pr-25": (0x4036C0, 51691344), + "ft.D.x": (0x400D70, 13065409), + "ua.D.x": (0x400F30, 8415248), + "mg.D.x": (0x401920, 11871798), + "sp.D.x": (0x409000, 9962530), + "lu.D.x": (0x4027F8, 32448), + "is.D.x": (0x401661, 119913839), + "tc-25": (0x4030A0, 30335985), + "sssp-25": (0x405441, 19973164), +} + +interval_info_6hr = { + # exe pc count + "bc-22": (0x404E08, 29440776), + "bfs-22": (0x4045D0, 3029875), + "bt.C.x": (0x409A20, 1173559), + "cc-22": (0x4037B0, 33552375), + "cg.C.x": (0x4019D8, 148363776), + "pr-22": (0x4036C0, 138691628), + "ft.C.x": (0x400D70, 30067439), + "ua.C.x": (0x405757, 134017), + "mg.C.x": (0x401920, 23222866), + "sp.C.x": (0x40AA60, 1691001), + "lu.C.x": (0x402980, 9952905), + "is.C.x": (0x401955, 79966814), + "tc-22": (0x405800, 516587), + "sssp-22": (0x405441, 67113550), + "bc-25": (0x404E08, 12151937), + "bfs-25": (0x403790, 8317180), + "bt.D.x": (0x407FD0, 21901834), + "cc-25": (0x404238, 32589977), + "cg.D.x": (0x4019D8, 91326969), + "pr-25": (0x4036C0, 99790518), + "ft.D.x": (0x400D70, 26209008), + "ua.D.x": (0x400F30, 13977417), + "mg.D.x": (0x401B08, 24048507), + "sp.D.x": (0x409000, 19860707), + "lu.D.x": (0x4027F8, 100054), + "is.D.x": (0x401661, 241880887), + "tc-25": (0x40CA70, 19083641), + "sssp-25": (0x405441, 42573632), +} + +interval_info_12hr = { + # exe pc count + "bc-22": (0x4036F0, 48778942), + "bfs-22": (0x403790, 54892278), + "bt.C.x": (0x40BF58, 611768), + "cc-22": (0x404688, 39592660), + "cg.C.x": (0x4019D8, 294906202), + "pr-22": (0x4036C0, 271266245), + "ft.C.x": (0x400D70, 56313323), + "ua.C.x": (0x41DCA0, 21222925), + "mg.C.x": (0x401B08, 45327484), + "sp.C.x": (0x40CFA0, 1219582), + "lu.C.x": (0x405C00, 72382), + "is.C.x": (0x401AF0, 129738785), + "tc-22": (0x4054A0, 87026806), + "sssp-22": (0x405441, 89183250), + "bc-25": (0x404E08, 25995768), + "bfs-25": (0x4038E0, 36114591), + "bt.D.x": (0x407FD0, 44658580), + "cc-25": (0x404688, 31320744), + "cg.D.x": (0x4019D8, 19366202), + "pr-25": (0x4036C0, 204816690), + "ft.D.x": (0x401C10, 56461566), + "ua.D.x": (0x4044C4, 6852508), + "mg.D.x": (0x401B08, 47676346), + "sp.D.x": (0x409000, 39454655), + "lu.D.x": (0x4029A0, 10268832), + "is.D.x": (0x401661, 481770516), + "tc-25": (0x40CA70, 19083641), + "sssp-25": (0x405441, 89681018), +} + +interval_info_24hr = { + # exe pc count + "bt.C.x": (0x40D230, 2377023), + "cg.C.x": (0x4019D8, 578428198), + "ft.C.x": (0x405830, 58382196), + "is.C.x": (0x401AF0, 184476965), + "lu.C.x": (0x40D4C0, 1146276), + "mg.C.x": (0x4012F8, 121010179), + "sp.C.x": (0x40EEE8, 3428040), + "ua.C.x": (0x41DCA0, 39733523), + "bc-22": (0x404E1A, 11556233), + "bfs-22": (0x401028, 65), + "cc-22": (0x404238, 39015034), + "pr-22": (0x4036C0, 530256860), + "tc-22": (0x405390, 7008077), + "sssp-22": (0x4054A0, 212570793), + "bc-25": (0x404E08, 44535390), + "bfs-25": (0x403988, 87740083), + "bt.D.x": (0x407FD0, 53208177), + "cc-25": (0x4037B0, 133906775), + "cg.D.x": (0x4019D8, 351587199), + "pr-25": (0x4036C0, 401728224), + "ft.D.x": (0x400D70, 110793818), + "ua.D.x": (0x4039C4, 12695182), ### + "mg.D.x": (0x401B08, 75633571), + "sp.D.x": (0x409000, 47034804), + "lu.D.x": (0x4029A0, 53146691), + "is.D.x": (0x401661, 858226422), + "tc-25": (0x40CA70, 19083641), + "sssp-25": (0x405441, 169473207), +} + +benchmark_choices_npb = [ + "bt.A.x", + "cg.A.x", + "ep.A.x", + "ft.A.x", + "is.A.x", + "lu.A.x", + "mg.A.x", + "sp.A.x", + "ua.A.x", + "bt.B.x", + "cg.B.x", + "ep.B.x", + "ft.B.x", + "is.B.x", + "lu.B.x", + "mg.B.x", + "sp.B.x", + "ua.B.x", + "bt.C.x", + "cg.C.x", + "ep.C.x", + "ft.C.x", + "is.C.x", + "lu.C.x", + "mg.C.x", + "sp.C.x", + "ua.C.x", + "bt.D.x", + "cg.D.x", + "ep.D.x", + "ft.D.x", + "is.D.x", + "lu.D.x", + "mg.D.x", + "sp.D.x", + "ua.D.x", + "bt.F.x", + "cg.F.x", + "ep.F.x", + "ft.F.x", + "is.F.x", + "lu.F.x", + "mg.F.x", + "sp.F.x", + "ua.F.x", +] +benchmark_choices_gapbs = [ + "bfs-22", + "bc-22", + "cc-22", + "pr-22", + "sssp-22", + "tc-22", + "bfs-25", + "bc-25", + "cc-25", + "pr-25", + "sssp-25", + "tc-25", +] + +interval_info_1hr_512MiB = { + # exe pc count + "bc-22": (0x404E08, 4355635), + "bfs-22": (0x403790, 3210973), + "bt.C.x": (0x408600, 623227), + "cc-22": (0x404688, 2218838), + "cg.C.x": (0x4019D8, 8334402), + "pr-22": (0x4036C0, 6426778), + "ft.C.x": (0x405830, 11202023), + "ua.C.x": (0x421ff6, 182749), + "mg.C.x": (0x401920, 1886013), + "sp.C.x": (0x409668, 445619), + "lu.C.x": (0x404160, 457680), + "is.C.x": (0x401955, 12277189), + "tc-22": (0x4052E0, 1059969), + "sssp-22": (0x405441, 4457679), +} + +interval_info_1GBdramCache_3hr = { + # exe pc count + "bt.C.x": (0x40f3d8,244911), + "cg.C.x": (0x4019d8,42463422), + "ft.C.x": (0x401c00,7146042), + "is.C.x": (0x401af0,46965216), + "lu.C.x": (0x40abf8,764707), + "mg.C.x": (0x401b08,6680641), + "sp.C.x": (0x40e2e0,441148), + "ua.C.x": (0x41dca0,1351162), + "bc-22": (0x4036f0,1315303), + "bfs-22": (0x403790,6915678), + "cc-22": (0x4037b0,8303408), + "pr-22": (0x4036c0,35167103), + "tc-22": (0x405640,760), + "sssp-22": (0x405390,2908597), + "bc-25": (0x404e1a,1578848), + "bfs-25": (0x403790,5365971), + "bt.D.x": (0x407fd0,4048773), + "cc-25": (0x404688,5396243), + "cg.D.x": (0x4019d8,13523512), + "pr-25": (0x4036c0,15770394), + "ft.D.x": (0x401c10,4648334), + "ua.D.x": (0x403f30,31180), + "mg.D.x": (0x401920,4263169), + "sp.D.x": (0x409000,3544598), + "lu.D.x": (0x4027f8,27621), + "is.D.x": (0x401661,31545953), + "tc-25": (0x4030a0,15958999), + "sssp-25": (0x405441,7679886), +} \ No newline at end of file diff --git a/configs-npb-gapbs-8Channel/npb_checkpoint.py b/configs-npb-gapbs-8Channel/npb_checkpoint.py new file mode 100755 index 0000000000..6488a76db4 --- /dev/null +++ b/configs-npb-gapbs-8Channel/npb_checkpoint.py @@ -0,0 +1,251 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2019 The Regents of the University of California. +# All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power, Ayaz Akram + +""" Script to run NAS parallel benchmarks with gem5. + The script expects kernel, diskimage, mem_sys, + cpu (kvm, atomic, or timing), benchmark to run + and number of cpus as arguments. + + If your application has ROI annotations, this script will count the total + number of instructions executed in the ROI. It also tracks how much + wallclock and simulated time. +""" +import argparse +import time +import m5 +import m5.ticks +from m5.objects import * + +from system import * + + +def writeBenchScript(dir, bench): + """ + This method creates a script in dir which will be eventually + passed to the simulated system (to run a specific benchmark + at bootup). + """ + file_name = "{}/run_{}".format(dir, bench) + bench_file = open(file_name, "w+") + bench_file.write("/home/gem5/NPB3.3-OMP/bin/{} \n".format(bench)) + + # sleeping for sometime (5 seconds here) makes sure + # that the benchmark's output has been + # printed to the console + bench_file.write("sleep 5 \n") + bench_file.write("m5 exit \n") + bench_file.close() + return file_name + + +supported_protocols = [ + "classic", + "MI_example", + "MESI_Two_Level", + "MOESI_CMP_directory", +] +supported_cpu_types = ["kvm", "atomic", "timing"] +benchmark_choices = [ + "bt.A.x", + "cg.A.x", + "ep.A.x", + "ft.A.x", + "is.A.x", + "lu.A.x", + "mg.A.x", + "sp.A.x", + "bt.B.x", + "cg.B.x", + "ep.B.x", + "ft.B.x", + "is.B.x", + "lu.B.x", + "mg.B.x", + "sp.B.x", + "bt.C.x", + "cg.C.x", + "ep.C.x", + "ft.C.x", + "is.C.x", + "lu.C.x", + "mg.C.x", + "sp.C.x", + "bt.D.x", + "cg.D.x", + "ep.D.x", + "ft.D.x", + "is.D.x", + "lu.D.x", + "mg.D.x", + "sp.D.x", + "bt.F.x", + "cg.F.x", + "ep.F.x", + "ft.F.x", + "is.F.x", + "lu.F.x", + "mg.F.x", + "sp.F.x", + "ua.C.x", + "ua.D.x", +] + + +def parse_options(): + + parser = argparse.ArgumentParser( + description="For use with gem5. This " + "runs a NAS Parallel Benchmark application. This only works " + "with x86 ISA." + ) + + # The manditry position arguments. + parser.add_argument( + "benchmark", + type=str, # choices=benchmark_choices, + help="The NPB application to run", + ) + parser.add_argument( + "class_size", type=str, help="The NPB application class to run" + ) + parser.add_argument( + "dcache_policy", + type=str, + help="The architecture of DRAM cache: " + "CascadeLakeNoPartWrs, Oracle, BearWriteOpt, Rambus, RambusTagProbOpt", + ) + parser.add_argument( + "is_link", + type=int, + help="whether to use a link for backing store or not", + ) + parser.add_argument( + "link_lat", type=str, help="latency of the link to backing store" + ) + + return parser.parse_args() + + +if __name__ == "__m5_main__": + args = parse_options() + + kernel = "/home/mbabaie/code-review/dramCacheController/fs-resources/x86-linux-kernel-4.19.83" + disk = "/home/mbabaie/code-review/dramCacheController/fs-resources/x86-npb" + num_cpus = 8 + cpu_type = "Timing" + mem_sys = "MESI_Two_Level" + + dcache_size = "1GiB" + mem_size = "128GiB" + mem_size_per_channel = "64GiB" + assoc = 1 + benchmark = args.benchmark + + # create the system we are going to simulate + system = MyRubySystem( + kernel, + disk, + mem_sys, + num_cpus, + assoc, + dcache_size, + mem_size, + mem_size_per_channel, + args.dcache_policy, + args.is_link, + args.link_lat, + 0, + args, + ) + + system.m5ops_base = 0xFFFF0000 + + # Exit from guest on workbegin/workend + system.exit_on_work_items = True + + # Create and pass a script to the simulated system to run the reuired + # benchmark + system.readfile = writeBenchScript(m5.options.outdir, benchmark) + + # set up the root SimObject and start the simulation + root = Root(full_system=True, system=system) + + if system.getHostParallel(): + # Required for running kvm on multiple host cores. + # Uses gem5's parallel event queue feature + # Note: The simulator is quite picky about this number! + root.sim_quantum = int(1e9) # 1 ms + + # needed for long running jobs + # m5.disableAllListeners() + + # instantiate all of the objects we've created above + m5.instantiate() + + globalStart = time.time() + + print("Running the simulation") + print("Using cpu: {}".format(cpu_type)) + exit_event = m5.simulate() + + if exit_event.getCause() == "workbegin": + print("Done booting Linux") + # Reached the start of ROI + # start of ROI is marked by an + # m5_work_begin() call + print("Resetting stats at the start of ROI!") + m5.stats.reset() + start_tick = m5.curTick() + start_insts = system.totalInsts() + # switching CPU to timing + system.switchCpus(system.cpu, system.timingCpu) + else: + print(exit_event.getCause()) + print("Unexpected termination of simulation !") + exit() + + m5.stats.reset() + print( + "After reset ************************************************ statring smiulation:\n" + ) + for interval_number in range(0,1): + print("Interval number: {} \n".format(interval_number)) + exit_event = m5.simulate(1000000000) + if exit_event.getCause() == "cacheIsWarmedup": + print("Caught cacheIsWarmedup exit event!") + break + print( + "-------------------------------------------------------------------" + ) + + print( + "After sim ************************************************ End of warm-up \n" + ) + m5.stats.dump() + system.switchCpus(system.timingCpu, system.o3Cpu) + m5.checkpoint(m5.options.outdir + "/cpt") diff --git a/configs-npb-gapbs-8Channel/restore_both.py b/configs-npb-gapbs-8Channel/restore_both.py new file mode 100755 index 0000000000..f2175b951e --- /dev/null +++ b/configs-npb-gapbs-8Channel/restore_both.py @@ -0,0 +1,333 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2019 The Regents of the University of California. +# All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power, Ayaz Akram + +""" Script to run NAS parallel benchmarks with gem5. + The script expects kernel, diskimage, mem_sys, + cpu (kvm, atomic, or timing), benchmark to run + and number of cpus as arguments. + + If your application has ROI annotations, this script will count the total + number of instructions executed in the ROI. It also tracks how much + wallclock and simulated time. +""" +import argparse +import time +import m5 +import m5.ticks +from m5.objects import * + +from system import * +from info import ( + text_info, + interval_info_1hr, + interval_info_3hr, + interval_info_6hr, + interval_info_12hr, + interval_info_24hr, + benchmark_choices_gapbs, + benchmark_choices_npb, + interval_info_1hr_512MiB, + interval_info_1GBdramCache_3hr, +) + + +def writeBenchScriptNPB(dir, bench): + """ + This method creates a script in dir which will be eventually + passed to the simulated system (to run a specific benchmark + at bootup). + """ + file_name = "{}/run_{}".format(dir, bench) + bench_file = open(file_name, "w+") + bench_file.write("/home/gem5/NPB3.3-OMP/bin/{} \n".format(bench)) + + # sleeping for sometime (5 seconds here) makes sure + # that the benchmark's output has been + # printed to the console + bench_file.write("sleep 5 \n") + bench_file.write("m5 exit \n") + bench_file.close() + return file_name + + +def writeBenchScriptGAPBS(dir, benchmark_name): + """ + This method creates a script in dir which will be eventually + passed to the simulated system (to run a specific benchmark + at bootup). + """ + synthetic = True + benchmark, size = benchmark_name.split("-") + input_file_name = "{}/run_{}_{}".format(dir, benchmark, size) + if synthetic: + with open(input_file_name, "w") as f: + f.write("./{} -g {}\n".format(benchmark, size)) + elif synthetic == 0: + with open(input_file_name, "w") as f: + # The workloads that are copied to the disk image using Packer + # should be located in /home/gem5/. + # Since the command running the workload will be executed with + # pwd = /home/gem5/gapbs, the path to the copied workload is + # ../{workload-name} + f.write("./{} -sf ../{}".format(benchmark, size)) + + return input_file_name + + +supported_protocols = [ + "classic", + "MI_example", + "MESI_Two_Level", + "MOESI_CMP_directory", +] +supported_cpu_types = ["kvm", "atomic", "timing"] + + +def parse_options(): + parser = argparse.ArgumentParser( + description="For use with gem5. This " + "runs a NAS Parallel Benchmark application. This only works " + "with x86 ISA." + ) + + # The manditry position arguments. + parser.add_argument( + "benchmark", + type=str, + choices=benchmark_choices_npb + benchmark_choices_gapbs, + help="The NPB application to run", + ) + parser.add_argument( + "dcache_policy", + type=str, + help="The architecture of DRAM cache: " + "CascadeLakeNoPartWrs, Oracle, BearWriteOpt, Rambus", + ) + parser.add_argument( + "assoc", + type=int, + help="THe associativity of the DRAM cache", + ) + parser.add_argument( + "is_link", + type=int, + help="whether to use a link for backing store or not", + ) + parser.add_argument( + "link_lat", type=str, help="latency of the link to backing store" + ) + parser.add_argument( + "bypass", + type=int, + help="bypass DRAM cache", + ) + parser.add_argument("--do_analysis", action="store_true", default=False) + return parser.parse_args() + + +def do_analysis(): + print( + "**************** Doing analysis! Simulating 100 intervals of 10ms each! ********************\n" + ) + start = time.time() + + for interval_number in range(100): + print(f"Working on interval number: {interval_number}") + exit_event = m5.simulate(10_000_000_000) # 10 ms + m5.stats.dump() + + print( + f"Done with interval {interval_number} at {(time.time() - start)/60:0.2f}" + ) + mostRecentPc = lpmanager.getMostRecentPc() + print(f"Exit because {exit_event.getCause()}, before for") + for pc, tick in mostRecentPc: + count = lpmanager.getPcCount(pc) + print("in for loop") + print(f"{hex(pc)},{count[0]},{count[1]}") + if exit_event.getCause() != "simulate() limit reached": + if ( + exit_event.getCause() == "workend" + or exit_event.getCause() == "workbegin" + ): + print(f"Exit because {exit_event.getCause()}, continuing...") + else: + print(f"Exiting because {exit_event.getCause()}") + break + + +def run(): + print("Simulating 100 intervals of 10ms each! \n") + + for interval_number in range(100): + print("Interval number: {}".format(interval_number)) + exit_event = m5.simulate(10_000_000_000) # 10 ms + # m5.stats.dump() + + if exit_event.getCause() != "simulate() limit reached": + if ( + exit_event.getCause() == "workend" + or exit_event.getCause() == "workbegin" + ): + print("Workload finished, continuing...") + else: + print(f"Exiting because {exit_event.getCause()}") + break + + +if __name__ == "__m5_main__": + args = parse_options() + + kernel = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-linux-kernel-4.19.83" + disk = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-npb" + ckpt_base = "/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/chkpt1GigDC/" + + num_cpus = 8 + cpu_type = "Timing" + mem_sys = "MESI_Two_Level" + + dcache_size = "1GB" + mem_size = "" + mem_size_per_channel = "64GiB" + checkpoint_dir = "" + + if args.benchmark in benchmark_choices_npb: + if args.benchmark.split(".")[1] == "C": + checkpoint_dir = ( + ckpt_base + + "1GB_8GB_g22_nC_1halfSec/NPB/" + + args.benchmark.split(".")[0] + + "/cpt" + ) + mem_size = "8GiB" + elif args.benchmark.split(".")[1] == "D": + checkpoint_dir = ( + ckpt_base + + "1GB_85GB_g25_nD_1halfSec/NPB/" + + args.benchmark.split(".")[0] + + "/cpt" + ) + mem_size = "85GiB" + else: + if args.benchmark.split("-")[1] == "22": + checkpoint_dir = ( + ckpt_base + + "1GB_8GB_g22_nC_1halfSec/GAPBS/" + + args.benchmark.split("-")[0] + + "/cpt" + ) + mem_size = "8GiB" + elif args.benchmark.split("-")[1] == "25": + checkpoint_dir = ( + ckpt_base + + "1GB_85GB_g25_nD_1halfSec/GAPBS/" + + args.benchmark.split("-")[0] + + "/cpt" + ) + mem_size = "85GiB" + + benchmark = args.benchmark + + system = MyRubySystem( + kernel, + disk, + mem_sys, + num_cpus, + args.assoc, + dcache_size, + mem_size_per_channel, + mem_size, + args.dcache_policy, + args.is_link, + args.link_lat, + args.bypass, + args, + restore=True, + ) + + if args.do_analysis: + lpmanager = O3LooppointAnalysisManager() + + for core in system.o3Cpu: + lplistener = O3LooppointAnalysis() + lplistener.ptmanager = lpmanager + lplistener.validAddrRangeStart = text_info[args.benchmark][1] + lplistener.validAddrRangeSize = text_info[args.benchmark][0] + core.probeListener = lplistener + else: + pc, count = interval_info_1GBdramCache_3hr[args.benchmark] + system.global_tracker = PcCountTrackerManager( + targets=[PcCountPair(pc, count)] + ) + + for core in system.o3Cpu: + core.core_tracker = PcCountTracker( + targets=[PcCountPair(pc, count)], + core=core, + ptmanager=system.global_tracker, + ) + + system.m5ops_base = 0xFFFF0000 + + # Exit from guest on workbegin/workend + system.exit_on_work_items = True + + # Create and pass a script to the simulated system to run the reuired + # benchmark + if args.benchmark in benchmark_choices_npb: + system.readfile = writeBenchScriptNPB( + m5.options.outdir, args.benchmark + ) + else: + system.readfile = writeBenchScriptGAPBS( + m5.options.outdir, args.benchmark + ) + + # set up the root SimObject and start the simulation + root = Root(full_system=True, system=system) + + if system.getHostParallel(): + # Required for running kvm on multiple host cores. + # Uses gem5's parallel event queue feature + # Note: The simulator is quite picky about this number! + root.sim_quantum = int(1e9) # 1 ms + + # needed for long running jobs + m5.disableAllListeners() + + # instantiate all of the objects we've created above + m5.instantiate(checkpoint_dir) + + print("Running the simulation ************************************** \n") + + if args.do_analysis: + do_analysis() + else: + run() + + print("End of simulation ******************************************** \n") diff --git a/configs-npb-gapbs-8Channel/system/MESI_Two_Level.py b/configs-npb-gapbs-8Channel/system/MESI_Two_Level.py new file mode 100755 index 0000000000..86ea0411f0 --- /dev/null +++ b/configs-npb-gapbs-8Channel/system/MESI_Two_Level.py @@ -0,0 +1,335 @@ +#Copyright (c) 2020 The Regents of the University of California. +#All Rights Reserved +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + + +""" This file creates a set of Ruby caches for the MESI TWO Level protocol +This protocol models two level cache hierarchy. The L1 cache is split into +instruction and data cache. + +This system support the memory size of up to 3GB. + +""" + +import math + +from m5.defines import buildEnv +from m5.util import fatal, panic + +from m5.objects import * + +class MESITwoLevelCache(RubySystem): + + def __init__(self): + if buildEnv['PROTOCOL'] != 'MESI_Two_Level': + fatal("This system assumes MESI_Two_Level!") + + super(MESITwoLevelCache, self).__init__() + + self._numL2Caches = 8 + + def setup(self, system, cpus, mem_ctrls, mem_ranges, dma_ports, iobus): + """Set up the Ruby cache subsystem. Note: This can't be done in the + constructor because many of these items require a pointer to the + ruby system (self). This causes infinite recursion in initialize() + if we do this in the __init__. + """ + # Ruby's global network. + self.network = MyNetwork(self) + + # MESI_Two_Level example uses 5 virtual networks + self.number_of_virtual_networks = 5 + self.network.number_of_virtual_networks = 5 + + # There is a single global list of all of the controllers to make it + # easier to connect everything to the global network. This can be + # customized depending on the topology/network requirements. + # L1 caches are private to a core, hence there are one L1 cache per CPU + # core. The number of L2 caches are dependent to the architecture. + print("1:" , len(mem_ranges)) + print("2:" , len(mem_ctrls[1])) + self.controllers = \ + [L1Cache(system, self, cpu, self._numL2Caches) for cpu in cpus] + \ + [L2Cache(system, self, self._numL2Caches) for num in \ + range(self._numL2Caches)] + \ + [DirController(self, rng, mem_ctrl) for rng,mem_ctrl in zip(mem_ranges,mem_ctrls)] + \ + [DMAController(self) for i in range(len(dma_ports))] + + # Create one sequencer per CPU and dma controller. + # Sequencers for other controllers can be here here. + self.sequencers = [RubySequencer(version = i, + # Grab dcache from ctrl + dcache = self.controllers[i].L1Dcache, + clk_domain = self.controllers[i].clk_domain, + pio_request_port = iobus.cpu_side_ports, + mem_request_port = iobus.cpu_side_ports, + pio_response_port = iobus.mem_side_ports + ) for i in range(len(cpus))] + \ + [DMASequencer(version = i, + in_ports = port) + for i,port in enumerate(dma_ports) + ] + + for i,c in enumerate(self.controllers[:len(cpus)]): + c.sequencer = self.sequencers[i] + + #Connecting the DMA sequencer to DMA controller + for i,d in enumerate(self.controllers[-len(dma_ports):]): + i += len(cpus) + d.dma_sequencer = self.sequencers[i] + + self.num_of_sequencers = len(self.sequencers) + + # Create the network and connect the controllers. + # NOTE: This is quite different if using Garnet! + self.network.connectControllers(self.controllers) + self.network.setup_buffers() + + # Set up a proxy port for the system_port. Used for load binaries and + # other functional-only things. + self.sys_port_proxy = RubyPortProxy() + system.system_port = self.sys_port_proxy.in_ports + self.sys_port_proxy.pio_request_port = iobus.cpu_side_ports + + # Connect the cpu's cache, interrupt, and TLB ports to Ruby + for i,cpu in enumerate(cpus): + cpu.icache_port = self.sequencers[i].in_ports + cpu.dcache_port = self.sequencers[i].in_ports + cpu.createInterruptController() + cpu.interrupts[0].pio = self.sequencers[i].interrupt_out_port + cpu.interrupts[0].int_requestor = self.sequencers[i].in_ports + cpu.interrupts[0].int_responder = self.sequencers[i].interrupt_out_port + cpu.mmu.connectWalkerPorts( + self.sequencers[i].in_ports, self.sequencers[i].in_ports) +class L1Cache(L1Cache_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, system, ruby_system, cpu, num_l2Caches): + """Creating L1 cache controller. Consist of both instruction + and data cache. The size of data cache is 512KB and + 8-way set associative. The instruction cache is 32KB, + 2-way set associative. + """ + super(L1Cache, self).__init__() + + self.version = self.versionCount() + block_size_bits = int(math.log(system.cache_line_size, 2)) + l1i_size = '32kB' + l1i_assoc = '2' + l1d_size = '512kB' + l1d_assoc = '8' + # This is the cache memory object that stores the cache data and tags + self.L1Icache = RubyCache(size = l1i_size, + assoc = l1i_assoc, + start_index_bit = block_size_bits , + is_icache = True) + self.L1Dcache = RubyCache(size = l1d_size, + assoc = l1d_assoc, + start_index_bit = block_size_bits, + is_icache = False) + self.l2_select_num_bits = int(math.log(num_l2Caches , 2)) + self.clk_domain = cpu.clk_domain + self.prefetcher = RubyPrefetcher() + self.send_evictions = self.sendEvicts(cpu) + self.transitions_per_cycle = 4 + self.enable_prefetch = False + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def getBlockSizeBits(self, system): + bits = int(math.log(system.cache_line_size, 2)) + if 2**bits != system.cache_line_size.value: + panic("Cache line size not a power of 2!") + return bits + + def sendEvicts(self, cpu): + """True if the CPU model or ISA requires sending evictions from caches + to the CPU. Two scenarios warrant forwarding evictions to the CPU: + 1. The O3 model must keep the LSQ coherent with the caches + 2. The x86 mwait instruction is built on top of coherence + 3. The local exclusive monitor in ARM systems + """ + if type(cpu) is X86O3CPU: + return True + return False + + def connectQueues(self, ruby_system): + """Connect all of the queues for this controller. + """ + self.mandatoryQueue = MessageBuffer() + self.requestFromL1Cache = MessageBuffer() + self.requestFromL1Cache.out_port = ruby_system.network.in_port + self.responseFromL1Cache = MessageBuffer() + self.responseFromL1Cache.out_port = ruby_system.network.in_port + self.unblockFromL1Cache = MessageBuffer() + self.unblockFromL1Cache.out_port = ruby_system.network.in_port + + self.optionalQueue = MessageBuffer() + + self.requestToL1Cache = MessageBuffer() + self.requestToL1Cache.in_port = ruby_system.network.out_port + self.responseToL1Cache = MessageBuffer() + self.responseToL1Cache.in_port = ruby_system.network.out_port + +class L2Cache(L2Cache_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, system, ruby_system, num_l2Caches): + + super(L2Cache, self).__init__() + + self.version = self.versionCount() + # This is the cache memory object that stores the cache data and tags + self.L2cache = RubyCache(size = '1 MB', + assoc = 16, + start_index_bit = self.getBlockSizeBits(system, + num_l2Caches)) + + self.transitions_per_cycle = '4' + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def getBlockSizeBits(self, system, num_l2caches): + l2_bits = int(math.log(num_l2caches, 2)) + bits = int(math.log(system.cache_line_size, 2)) + l2_bits + return bits + + + def connectQueues(self, ruby_system): + """Connect all of the queues for this controller. + """ + self.DirRequestFromL2Cache = MessageBuffer() + self.DirRequestFromL2Cache.out_port = ruby_system.network.in_port + self.L1RequestFromL2Cache = MessageBuffer() + self.L1RequestFromL2Cache.out_port = ruby_system.network.in_port + self.responseFromL2Cache = MessageBuffer() + self.responseFromL2Cache.out_port = ruby_system.network.in_port + self.unblockToL2Cache = MessageBuffer() + self.unblockToL2Cache.in_port = ruby_system.network.out_port + self.L1RequestToL2Cache = MessageBuffer() + self.L1RequestToL2Cache.in_port = ruby_system.network.out_port + self.responseToL2Cache = MessageBuffer() + self.responseToL2Cache.in_port = ruby_system.network.out_port + + +class DirController(Directory_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, ruby_system, ranges, mem_ctrls): + """ranges are the memory ranges assigned to this controller. + """ + if len(mem_ctrls) > 1: + print("3:" , len(mem_ctrls)) + panic("This cache system can only be connected to one mem ctrl") + super(DirController, self).__init__() + self.version = self.versionCount() + self.addr_ranges = ranges + self.ruby_system = ruby_system + self.directory = RubyDirectoryMemory() + # Connect this directory to the memory side. + self.memory_out_port = mem_ctrls[0].port + self.connectQueues(ruby_system) + + def connectQueues(self, ruby_system): + self.requestToDir = MessageBuffer() + self.requestToDir.in_port = ruby_system.network.out_port + self.responseToDir = MessageBuffer() + self.responseToDir.in_port = ruby_system.network.out_port + self.responseFromDir = MessageBuffer() + self.responseFromDir.out_port = ruby_system.network.in_port + self.requestToMemory = MessageBuffer() + self.responseFromMemory = MessageBuffer() + +class DMAController(DMA_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, ruby_system): + super(DMAController, self).__init__() + self.version = self.versionCount() + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def connectQueues(self, ruby_system): + self.mandatoryQueue = MessageBuffer() + self.responseFromDir = MessageBuffer(ordered = True) + self.responseFromDir.in_port = ruby_system.network.out_port + self.requestToDir = MessageBuffer() + self.requestToDir.out_port = ruby_system.network.in_port + + +class MyNetwork(SimpleNetwork): + """A simple point-to-point network. This doesn't not use garnet. + """ + + def __init__(self, ruby_system): + super(MyNetwork, self).__init__() + self.netifs = [] + self.ruby_system = ruby_system + + def connectControllers(self, controllers): + """Connect all of the controllers to routers and connec the routers + together in a point-to-point network. + """ + # Create one router/switch per controller in the system + self.routers = [Switch(router_id = i) for i in range(len(controllers))] + + # Make a link from each controller to the router. The link goes + # externally to the network. + self.ext_links = [SimpleExtLink(link_id=i, ext_node=c, + int_node=self.routers[i]) + for i, c in enumerate(controllers)] + + # Make an "internal" link (internal to the network) between every pair + # of routers. + link_count = 0 + self.int_links = [] + for ri in self.routers: + for rj in self.routers: + if ri == rj: continue # Don't connect a router to itself! + link_count += 1 + self.int_links.append(SimpleIntLink(link_id = link_count, + src_node = ri, + dst_node = rj)) diff --git a/configs-npb-gapbs-8Channel/system/MI_example_caches.py b/configs-npb-gapbs-8Channel/system/MI_example_caches.py new file mode 100755 index 0000000000..3c7a71d7b1 --- /dev/null +++ b/configs-npb-gapbs-8Channel/system/MI_example_caches.py @@ -0,0 +1,275 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2015 Jason Power +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Power + +""" This file creates a set of Ruby caches, the Ruby network, and a simple +point-to-point topology. +See Part 3 in the Learning gem5 book: learning.gem5.org/book/part3 +You can change simple_ruby to import from this file instead of from msi_caches +to use the MI_example protocol instead of MSI. + +IMPORTANT: If you modify this file, it's likely that the Learning gem5 book + also needs to be updated. For now, email Jason + +""" + +import math + +from m5.defines import buildEnv +from m5.util import fatal, panic + +from m5.objects import * + +class MIExampleSystem(RubySystem): + + def __init__(self): + if buildEnv['PROTOCOL'] != 'MI_example': + fatal("This system assumes MI_example!") + + super(MIExampleSystem, self).__init__() + + def setup(self, system, cpus, mem_ctrls, dma_ports, iobus): + """Set up the Ruby cache subsystem. Note: This can't be done in the + constructor because many of these items require a pointer to the + ruby system (self). This causes infinite recursion in initialize() + if we do this in the __init__. + """ + # Ruby's global network. + self.network = MyNetwork(self) + + # MI example uses 5 virtual networks + self.number_of_virtual_networks = 5 + self.network.number_of_virtual_networks = 5 + + # There is a single global list of all of the controllers to make it + # easier to connect everything to the global network. This can be + # customized depending on the topology/network requirements. + # Create one controller for each L1 cache (and the cache mem obj.) + # Create a single directory controller (Really the memory cntrl) + self.controllers = \ + [L1Cache(system, self, cpu) for cpu in cpus] + \ + [DirController(self, system.mem_ranges, mem_ctrls)] + \ + [DMAController(self) for i in range(len(dma_ports))] + + # Create one sequencer per CPU. In many systems this is more + # complicated since you have to create sequencers for DMA controllers + # and other controllers, too. + self.sequencers = [RubySequencer(version = i, + # Grab dcache from ctrl + dcache = self.controllers[i].cacheMemory, + clk_domain = self.controllers[i].clk_domain, + pio_request_port = iobus.cpu_side_ports, + mem_request_port = iobus.cpu_side_ports, + pio_response_port = iobus.mem_side_ports + ) for i in range(len(cpus))] + \ + [DMASequencer(version = i, + in_ports = port) + for i,port in enumerate(dma_ports) + ] + + for i,c in enumerate(self.controllers[0:len(cpus)]): + c.sequencer = self.sequencers[i] + + for i,d in enumerate(self.controllers[-len(dma_ports):]): + i += len(cpus) + d.dma_sequencer = self.sequencers[i] + + self.num_of_sequencers = len(self.sequencers) + + # Create the network and connect the controllers. + # NOTE: This is quite different if using Garnet! + self.network.connectControllers(self.controllers) + self.network.setup_buffers() + + # Set up a proxy port for the system_port. Used for load binaries and + # other functional-only things. + self.sys_port_proxy = RubyPortProxy() + system.system_port = self.sys_port_proxy.in_ports + self.sys_port_proxy.pio_request_port = iobus.cpu_side_ports + + # Connect the cpu's cache, interrupt, and TLB ports to Ruby + for i,cpu in enumerate(cpus): + cpu.icache_port = self.sequencers[i].in_ports + cpu.dcache_port = self.sequencers[i].in_ports + cpu.createInterruptController() + isa = buildEnv['TARGET_ISA'] + if isa == 'x86': + cpu.interrupts[0].pio = self.sequencers[i].interrupt_out_port + cpu.interrupts[0].int_requestor = self.sequencers[i].in_ports + cpu.interrupts[0].int_responder = self.sequencers[i].interrupt_out_port + if isa == 'x86' or isa == 'arm': + cpu.mmu.connectWalkerPorts( + self.sequencers[i].in_ports, self.sequencers[i].in_ports) + +class L1Cache(L1Cache_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, system, ruby_system, cpu): + """CPUs are needed to grab the clock domain and system is needed for + the cache block size. + """ + super(L1Cache, self).__init__() + + self.version = self.versionCount() + # This is the cache memory object that stores the cache data and tags + self.cacheMemory = RubyCache(size = '16kB', + assoc = 8, + start_index_bit = self.getBlockSizeBits(system)) + self.clk_domain = cpu.clk_domain + self.send_evictions = self.sendEvicts(cpu) + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def getBlockSizeBits(self, system): + bits = int(math.log(system.cache_line_size, 2)) + if 2**bits != system.cache_line_size.value: + panic("Cache line size not a power of 2!") + return bits + + def sendEvicts(self, cpu): + """True if the CPU model or ISA requires sending evictions from caches + to the CPU. Two scenarios warrant forwarding evictions to the CPU: + 1. The O3 model must keep the LSQ coherent with the caches + 2. The x86 mwait instruction is built on top of coherence + 3. The local exclusive monitor in ARM systems + """ + if type(cpu) is DerivO3CPU or \ + buildEnv['TARGET_ISA'] in ('x86', 'arm'): + return True + return False + + def connectQueues(self, ruby_system): + """Connect all of the queues for this controller. + """ + self.mandatoryQueue = MessageBuffer() + self.requestFromCache = MessageBuffer(ordered = True) + self.requestFromCache.out_port = ruby_system.network.in_port + self.responseFromCache = MessageBuffer(ordered = True) + self.responseFromCache.out_port = ruby_system.network.in_port + self.forwardToCache = MessageBuffer(ordered = True) + self.forwardToCache.in_port = ruby_system.network.out_port + self.responseToCache = MessageBuffer(ordered = True) + self.responseToCache.in_port = ruby_system.network.out_port + +class DirController(Directory_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, ruby_system, ranges, mem_ctrls): + """ranges are the memory ranges assigned to this controller. + """ + if len(mem_ctrls) > 1: + panic("This cache system can only be connected to one mem ctrl") + super(DirController, self).__init__() + self.version = self.versionCount() + self.addr_ranges = ranges + self.ruby_system = ruby_system + self.directory = RubyDirectoryMemory() + # Connect this directory to the memory side. + self.memory_out_port = mem_ctrls[0].port + self.connectQueues(ruby_system) + + def connectQueues(self, ruby_system): + self.requestToDir = MessageBuffer(ordered = True) + self.requestToDir.in_port = ruby_system.network.out_port + self.dmaRequestToDir = MessageBuffer(ordered = True) + self.dmaRequestToDir.in_port = ruby_system.network.out_port + + self.responseFromDir = MessageBuffer() + self.responseFromDir.out_port = ruby_system.network.in_port + self.dmaResponseFromDir = MessageBuffer(ordered = True) + self.dmaResponseFromDir.out_port = ruby_system.network.in_port + self.forwardFromDir = MessageBuffer() + self.forwardFromDir.out_port = ruby_system.network.in_port + self.requestToMemory = MessageBuffer() + self.responseFromMemory = MessageBuffer() + +class DMAController(DMA_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, ruby_system): + super(DMAController, self).__init__() + self.version = self.versionCount() + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def connectQueues(self, ruby_system): + self.mandatoryQueue = MessageBuffer() + self.requestToDir = MessageBuffer() + self.requestToDir.out_port = ruby_system.network.in_port + self.responseFromDir = MessageBuffer(ordered = True) + self.responseFromDir.in_port = ruby_system.network.out_port + + +class MyNetwork(SimpleNetwork): + """A simple point-to-point network. This doesn't not use garnet. + """ + + def __init__(self, ruby_system): + super(MyNetwork, self).__init__() + self.netifs = [] + self.ruby_system = ruby_system + + def connectControllers(self, controllers): + """Connect all of the controllers to routers and connec the routers + together in a point-to-point network. + """ + # Create one router/switch per controller in the system + self.routers = [Switch(router_id = i) for i in range(len(controllers))] + + # Make a link from each controller to the router. The link goes + # externally to the network. + self.ext_links = [SimpleExtLink(link_id=i, ext_node=c, + int_node=self.routers[i]) + for i, c in enumerate(controllers)] + + # Make an "internal" link (internal to the network) between every pair + # of routers. + link_count = 0 + self.int_links = [] + for ri in self.routers: + for rj in self.routers: + if ri == rj: continue # Don't connect a router to itself! + link_count += 1 + self.int_links.append(SimpleIntLink(link_id = link_count, + src_node = ri, + dst_node = rj)) diff --git a/configs-npb-gapbs-8Channel/system/MOESI_CMP_directory.py b/configs-npb-gapbs-8Channel/system/MOESI_CMP_directory.py new file mode 100755 index 0000000000..33f9f47e74 --- /dev/null +++ b/configs-npb-gapbs-8Channel/system/MOESI_CMP_directory.py @@ -0,0 +1,350 @@ +#Copyright (c) 2020 The Regents of the University of California. +#All Rights Reserved +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + + +""" This file creates a set of Ruby caches for the MOESI CMP directory +protocol. +This protocol models two level cache hierarchy. The L1 cache is split into +instruction and data cache. + +This system support the memory size of up to 3GB. + +""" + +from __future__ import print_function +from __future__ import absolute_import + +import math + +from m5.defines import buildEnv +from m5.util import fatal, panic + +from m5.objects import * + +class MOESICMPDirCache(RubySystem): + + def __init__(self): + if buildEnv['PROTOCOL'] != 'MOESI_CMP_directory': + fatal("This system assumes MOESI_CMP_directory!") + + super(MOESICMPDirCache, self).__init__() + + self._numL2Caches = 8 + + def setup(self, system, cpus, mem_ctrls, dma_ports, iobus): + """Set up the Ruby cache subsystem. Note: This can't be done in the + constructor because many of these items require a pointer to the + ruby system (self). This causes infinite recursion in initialize() + if we do this in the __init__. + """ + # Ruby's global network. + self.network = MyNetwork(self) + + # MOESI_CMP_directory example uses 3 virtual networks + self.number_of_virtual_networks = 3 + self.network.number_of_virtual_networks = 3 + + # There is a single global list of all of the controllers to make it + # easier to connect everything to the global network. This can be + # customized depending on the topology/network requirements. + # L1 caches are private to a core, hence there are one L1 cache per CPU + # core. The number of L2 caches are dependent to the architecture. + self.controllers = \ + [L1Cache(system, self, cpu, self._numL2Caches) for cpu in cpus] + \ + [L2Cache(system, self, self._numL2Caches) for num in \ + range(self._numL2Caches)] + [DirController(self, \ + system.mem_ranges, mem_ctrls)] + [DMAController(self) for i \ + in range(len(dma_ports))] + + # Create one sequencer per CPU and dma controller. + # Sequencers for other controllers can be here here. + self.sequencers = [RubySequencer(version = i, + # Grab dcache from ctrl + dcache = self.controllers[i].L1Dcache, + clk_domain = self.controllers[i].clk_domain, + pio_request_port = iobus.cpu_side_ports, + mem_request_port = iobus.cpu_side_ports, + pio_response_port = iobus.mem_side_ports + ) for i in range(len(cpus))] + \ + [DMASequencer(version = i, + in_ports = port) + for i,port in enumerate(dma_ports) + ] + + for i,c in enumerate(self.controllers[:len(cpus)]): + c.sequencer = self.sequencers[i] + + #Connecting the DMA sequencer to DMA controller + for i,d in enumerate(self.controllers[-len(dma_ports):]): + i += len(cpus) + d.dma_sequencer = self.sequencers[i] + + self.num_of_sequencers = len(self.sequencers) + + # Create the network and connect the controllers. + # NOTE: This is quite different if using Garnet! + self.network.connectControllers(self.controllers) + self.network.setup_buffers() + + # Set up a proxy port for the system_port. Used for load binaries and + # other functional-only things. + self.sys_port_proxy = RubyPortProxy() + system.system_port = self.sys_port_proxy.in_ports + self.sys_port_proxy.pio_request_port = iobus.cpu_side_ports + + # Connect the cpu's cache, interrupt, and TLB ports to Ruby + for i,cpu in enumerate(cpus): + cpu.icache_port = self.sequencers[i].in_ports + cpu.dcache_port = self.sequencers[i].in_ports + cpu.createInterruptController() + isa = buildEnv['TARGET_ISA'] + if isa == 'x86': + cpu.interrupts[0].pio = self.sequencers[i].interrupt_out_port + cpu.interrupts[0].int_requestor = self.sequencers[i].in_ports + cpu.interrupts[0].int_responder = self.sequencers[i].interrupt_out_port + if isa == 'x86' or isa == 'arm': + cpu.mmu.connectWalkerPorts( + self.sequencers[i].in_ports, self.sequencers[i].in_ports) + +class L1Cache(L1Cache_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, system, ruby_system, cpu, num_l2Caches): + """Creating L1 cache controller. Consist of both instruction + and data cache. The size of data cache is 512KB and + 8-way set associative. The instruction cache is 32KB, + 2-way set associative. + """ + super(L1Cache, self).__init__() + + self.version = self.versionCount() + block_size_bits = int(math.log(system.cache_line_size, 2)) + l1i_size = '32kB' + l1i_assoc = '2' + l1d_size = '512kB' + l1d_assoc = '8' + # This is the cache memory object that stores the cache data and tags + self.L1Icache = RubyCache(size = l1i_size, + assoc = l1i_assoc, + start_index_bit = block_size_bits , + is_icache = True, + dataAccessLatency = 1, + tagAccessLatency = 1) + self.L1Dcache = RubyCache(size = l1d_size, + assoc = l1d_assoc, + start_index_bit = block_size_bits, + is_icache = False, + dataAccessLatency = 1, + tagAccessLatency = 1) + self.clk_domain = cpu.clk_domain + self.prefetcher = RubyPrefetcher() + self.send_evictions = self.sendEvicts(cpu) + self.transitions_per_cycle = 4 + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def getBlockSizeBits(self, system): + bits = int(math.log(system.cache_line_size, 2)) + if 2**bits != system.cache_line_size.value: + panic("Cache line size not a power of 2!") + return bits + + def sendEvicts(self, cpu): + """True if the CPU model or ISA requires sending evictions from caches + to the CPU. Two scenarios warrant forwarding evictions to the CPU: + 1. The O3 model must keep the LSQ coherent with the caches + 2. The x86 mwait instruction is built on top of coherence + 3. The local exclusive monitor in ARM systems + """ + if type(cpu) is DerivO3CPU or \ + buildEnv['TARGET_ISA'] in ('x86', 'arm'): + return True + return False + + def connectQueues(self, ruby_system): + """Connect all of the queues for this controller. + """ + self.mandatoryQueue = MessageBuffer() + self.requestFromL1Cache = MessageBuffer() + self.requestFromL1Cache.out_port = ruby_system.network.in_port + self.responseFromL1Cache = MessageBuffer() + self.responseFromL1Cache.out_port = ruby_system.network.in_port + self.requestToL1Cache = MessageBuffer() + self.requestToL1Cache.in_port = ruby_system.network.out_port + self.responseToL1Cache = MessageBuffer() + self.responseToL1Cache.in_port = ruby_system.network.out_port + self.triggerQueue = MessageBuffer(ordered = True) + +class L2Cache(L2Cache_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, system, ruby_system, num_l2Caches): + + super(L2Cache, self).__init__() + + self.version = self.versionCount() + # This is the cache memory object that stores the cache data and tags + self.L2cache = RubyCache(size = '1 MB', + assoc = 16, + start_index_bit = self.getL2StartIdx(system, + num_l2Caches), + dataAccessLatency = 20, + tagAccessLatency = 20) + + self.transitions_per_cycle = '4' + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def getL2StartIdx(self, system, num_l2caches): + l2_bits = int(math.log(num_l2caches, 2)) + bits = int(math.log(system.cache_line_size, 2)) + l2_bits + return bits + + + def connectQueues(self, ruby_system): + """Connect all of the queues for this controller. + """ + self.GlobalRequestFromL2Cache = MessageBuffer() + self.GlobalRequestFromL2Cache.out_port = ruby_system.network.in_port + self.L1RequestFromL2Cache = MessageBuffer() + self.L1RequestFromL2Cache.out_port = ruby_system.network.in_port + self.responseFromL2Cache = MessageBuffer() + self.responseFromL2Cache.out_port = ruby_system.network.in_port + + self.GlobalRequestToL2Cache = MessageBuffer() + self.GlobalRequestToL2Cache.in_port = ruby_system.network.out_port + self.L1RequestToL2Cache = MessageBuffer() + self.L1RequestToL2Cache.in_port = ruby_system.network.out_port + self.responseToL2Cache = MessageBuffer() + self.responseToL2Cache.in_port = ruby_system.network.out_port + self.triggerQueue = MessageBuffer(ordered = True) + + + +class DirController(Directory_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, ruby_system, ranges, mem_ctrls): + """ranges are the memory ranges assigned to this controller. + """ + if len(mem_ctrls) > 1: + panic("This cache system can only be connected to one mem ctrl") + super(DirController, self).__init__() + self.version = self.versionCount() + self.addr_ranges = ranges + self.ruby_system = ruby_system + self.directory = RubyDirectoryMemory() + # Connect this directory to the memory side. + self.memory_out_port = mem_ctrls[0].port + self.connectQueues(ruby_system) + + def connectQueues(self, ruby_system): + self.requestToDir = MessageBuffer() + self.requestToDir.in_port = ruby_system.network.out_port + self.responseToDir = MessageBuffer() + self.responseToDir.in_port = ruby_system.network.out_port + self.responseFromDir = MessageBuffer() + self.responseFromDir.out_port = ruby_system.network.in_port + self.forwardFromDir = MessageBuffer() + self.forwardFromDir.out_port = ruby_system.network.in_port + self.requestToMemory = MessageBuffer() + self.responseFromMemory = MessageBuffer() + self.triggerQueue = MessageBuffer(ordered = True) + +class DMAController(DMA_Controller): + + _version = 0 + @classmethod + def versionCount(cls): + cls._version += 1 # Use count for this particular type + return cls._version - 1 + + def __init__(self, ruby_system): + super(DMAController, self).__init__() + self.version = self.versionCount() + self.ruby_system = ruby_system + self.connectQueues(ruby_system) + + def connectQueues(self, ruby_system): + self.mandatoryQueue = MessageBuffer() + self.responseFromDir = MessageBuffer() + self.responseFromDir.in_port = ruby_system.network.out_port + self.reqToDir = MessageBuffer() + self.reqToDir.out_port = ruby_system.network.in_port + self.respToDir = MessageBuffer() + self.respToDir.out_port = ruby_system.network.in_port + self.triggerQueue = MessageBuffer(ordered = True) + + +class MyNetwork(SimpleNetwork): + """A simple point-to-point network. This doesn't not use garnet. + """ + + def __init__(self, ruby_system): + super(MyNetwork, self).__init__() + self.netifs = [] + self.ruby_system = ruby_system + + def connectControllers(self, controllers): + """Connect all of the controllers to routers and connec the routers + together in a point-to-point network. + """ + # Create one router/switch per controller in the system + self.routers = [Switch(router_id = i) for i in range(len(controllers))] + + # Make a link from each controller to the router. The link goes + # externally to the network. + self.ext_links = [SimpleExtLink(link_id=i, ext_node=c, + int_node=self.routers[i]) + for i, c in enumerate(controllers)] + + # Make an "internal" link (internal to the network) between every pair + # of routers. + link_count = 0 + self.int_links = [] + for ri in self.routers: + for rj in self.routers: + if ri == rj: continue # Don't connect a router to itself! + link_count += 1 + self.int_links.append(SimpleIntLink(link_id = link_count, + src_node = ri, + dst_node = rj)) diff --git a/configs-npb-gapbs-8Channel/system/__init__.py b/configs-npb-gapbs-8Channel/system/__init__.py new file mode 100755 index 0000000000..7ef9c5dadd --- /dev/null +++ b/configs-npb-gapbs-8Channel/system/__init__.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2016 Jason Lowe-Power +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power + +from .system import MySystem +from .ruby_system_new import MyRubySystem diff --git a/configs-npb-gapbs-8Channel/system/caches.py b/configs-npb-gapbs-8Channel/system/caches.py new file mode 100755 index 0000000000..9e44211111 --- /dev/null +++ b/configs-npb-gapbs-8Channel/system/caches.py @@ -0,0 +1,173 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2016 Jason Lowe-Power +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power + +""" Caches with options for a simple gem5 configuration script + +This file contains L1 I/D and L2 caches to be used in the simple +gem5 configuration script. +""" + +from m5.objects import Cache, L2XBar, StridePrefetcher + +# Some specific options for caches +# For all options see src/mem/cache/BaseCache.py + +class PrefetchCache(Cache): + + def __init__(self, options): + super(PrefetchCache, self).__init__() + if not options or options.no_prefetchers: + return + self.prefetcher = StridePrefetcher() + +class L1Cache(PrefetchCache): + """Simple L1 Cache with default values""" + + assoc = 8 + tag_latency = 1 + data_latency = 1 + response_latency = 1 + mshrs = 16 + tgts_per_mshr = 20 + writeback_clean = True + + def __init__(self, options=None): + super(L1Cache, self).__init__(options) + pass + + def connectBus(self, bus): + """Connect this cache to a memory-side bus""" + self.mem_side = bus.cpu_side_ports + + def connectCPU(self, cpu): + """Connect this cache's port to a CPU-side port + This must be defined in a subclass""" + raise NotImplementedError + +class L1ICache(L1Cache): + """Simple L1 instruction cache with default values""" + + def __init__(self, opts=None): + super(L1ICache, self).__init__(opts) + if not opts or not opts.l1i_size: + return + self.size = opts.l1i_size + + def connectCPU(self, cpu): + """Connect this cache's port to a CPU icache port""" + self.cpu_side = cpu.icache_port + +class L1DCache(L1Cache): + """Simple L1 data cache with default values""" + + def __init__(self, opts=None): + super(L1DCache, self).__init__(opts) + if not opts or not opts.l1d_size: + return + self.size = opts.l1d_size + + def connectCPU(self, cpu): + """Connect this cache's port to a CPU dcache port""" + self.cpu_side = cpu.dcache_port + +class MMUCache(Cache): + # Default parameters + size = '8kB' + assoc = 4 + tag_latency = 1 + data_latency = 1 + response_latency = 1 + mshrs = 20 + tgts_per_mshr = 12 + writeback_clean = True + + def __init__(self): + super(MMUCache, self).__init__() + + def connectCPU(self, cpu): + """Connect the CPU itb and dtb to the cache + Note: This creates a new crossbar + """ + self.mmubus = L2XBar() + self.cpu_side = self.mmubus.mem_side_ports + cpu.mmu.connectWalkerPorts( + self.mmubus.cpu_side_ports, self.mmubus.cpu_side_ports) + + def connectBus(self, bus): + """Connect this cache to a memory-side bus""" + self.mem_side = bus.cpu_side_ports + +class L2Cache(PrefetchCache): + """Simple L2 Cache with default values""" + + # Default parameters + assoc = 16 + tag_latency = 10 + data_latency = 10 + response_latency = 1 + mshrs = 20 + tgts_per_mshr = 12 + writeback_clean = True + + def __init__(self, opts=None): + super(L2Cache, self).__init__(opts) + if not opts or not opts.l2_size: + return + self.size = opts.l2_size + + def connectCPUSideBus(self, bus): + self.cpu_side = bus.mem_side_ports + + def connectMemSideBus(self, bus): + self.mem_side = bus.cpu_side_ports + +class L3Cache(Cache): + """Simple L3 Cache bank with default values + This assumes that the L3 is made up of multiple banks. This cannot + be used as a standalone L3 cache. + """ + + # Default parameters + assoc = 32 + tag_latency = 40 + data_latency = 40 + response_latency = 10 + mshrs = 256 + tgts_per_mshr = 12 + clusivity = 'mostly_excl' + + def __init__(self, opts): + super(L3Cache, self).__init__() + self.size = (opts.l3_size) + + def connectCPUSideBus(self, bus): + self.cpu_side = bus.mem_side_ports + + def connectMemSideBus(self, bus): + self.mem_side = bus.cpu_side_ports diff --git a/configs-npb-gapbs-8Channel/system/fs_tools.py b/configs-npb-gapbs-8Channel/system/fs_tools.py new file mode 100755 index 0000000000..5e5e2df6e4 --- /dev/null +++ b/configs-npb-gapbs-8Channel/system/fs_tools.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2016 Jason Lowe-Power +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power + +from m5.objects import IdeDisk, CowDiskImage, RawDiskImage + +class CowDisk(IdeDisk): + + def __init__(self, filename): + super(CowDisk, self).__init__() + self.driveID = 'device0' + self.image = CowDiskImage(child=RawDiskImage(read_only=True), + read_only=False) + self.image.child.image_file = filename diff --git a/configs-npb-gapbs-8Channel/system/ruby_system_new.py b/configs-npb-gapbs-8Channel/system/ruby_system_new.py new file mode 100644 index 0000000000..c5d4f14baf --- /dev/null +++ b/configs-npb-gapbs-8Channel/system/ruby_system_new.py @@ -0,0 +1,386 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2016 Jason Lowe-Power +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power + +import m5 +from m5.objects import * +from .fs_tools import * + + +class MyRubySystem(System): + def __init__( + self, + kernel, + disk, + mem_sys, + num_cpus, + assoc, + dcache_size, # size of 1 channel + main_mem_size, + mem_size_per_channel, + policy, + is_link, + link_lat, + bypass, + opts, + restore=False, + ): + super(MyRubySystem, self).__init__() + print("Creating MyRubySystem") + self._opts = opts + + # Use parallel if using KVM. Don't use parallel is restoring cpt + self._host_parallel = not restore + self._restore = restore + + # Set up the clock domain and the voltage domain + self.clk_domain = SrcClockDomain() + self.clk_domain.clock = "5GHz" + self.clk_domain.voltage_domain = VoltageDomain() + + self.mem_ranges = [ + AddrRange(Addr("128MiB")), # kernel data + AddrRange(0xC0000000, size=0x100000), # For I/0 + # AddrRange( + # 0x100000000, size=main_mem_size + # ), # starting at 4GiB for main_mem_size GiB + AddrRange(start = 0x100000000, size = main_mem_size, masks = [1 << 6, 1 << 7, 1 << 8], intlvMatch = 0), + AddrRange(start = 0x100000000, size = main_mem_size, masks = [1 << 6, 1 << 7, 1 << 8], intlvMatch = 1), + AddrRange(start = 0x100000000, size = main_mem_size, masks = [1 << 6, 1 << 7, 1 << 8], intlvMatch = 2), + AddrRange(start = 0x100000000, size = main_mem_size, masks = [1 << 6, 1 << 7, 1 << 8], intlvMatch = 3), + AddrRange(start = 0x100000000, size = main_mem_size, masks = [1 << 6, 1 << 7, 1 << 8], intlvMatch = 4), + AddrRange(start = 0x100000000, size = main_mem_size, masks = [1 << 6, 1 << 7, 1 << 8], intlvMatch = 5), + AddrRange(start = 0x100000000, size = main_mem_size, masks = [1 << 6, 1 << 7, 1 << 8], intlvMatch = 6), + AddrRange(start = 0x100000000, size = main_mem_size, masks = [1 << 6, 1 << 7, 1 << 8], intlvMatch = 7), + AddrRange(start = 0x100000000, size = main_mem_size, masks = [1 << 6], intlvMatch = 0), + AddrRange(start = 0x100000000, size = main_mem_size, masks = [1 << 6], intlvMatch = 1) + ] + + self.initFS(num_cpus) + + # Replace these paths with the path to your disk images. + # The first disk is the root disk. The second could be used for swap + # or anything else. + self.setDiskImages(disk, disk) + + # Change this path to point to the kernel you want to use + self.workload.object_file = kernel + # Options specified on the kernel command line + boot_options = [ + "earlyprintk=ttyS0", + "console=ttyS0", + "lpj=7999923", + "root=/dev/hda1", + ] + + self.workload.command_line = " ".join(boot_options) + + # Create the CPUs for our system. + self.createCPU(num_cpus) + + # self.intrctrl = IntrControl() + self._createMemoryControllers( + assoc, dcache_size, mem_size_per_channel, policy, is_link, link_lat, bypass + ) + + # Create the cache hierarchy for the system. + if mem_sys == "MI_example": + from .MI_example_caches import MIExampleSystem + + self.caches = MIExampleSystem() + elif mem_sys == "MESI_Two_Level": + from .MESI_Two_Level import MESITwoLevelCache + + self.caches = MESITwoLevelCache() + elif mem_sys == "MOESI_CMP_directory": + from .MOESI_CMP_directory import MOESICMPDirCache + + self.caches = MOESICMPDirCache() + if self._restore: + cpus = self.o3Cpu + else: + cpus = self.cpu + self.caches.setup( + self, + cpus, + [self.kernel_mem_ctrl, + self.mem_ctrl[0], self.mem_ctrl[1], + self.mem_ctrl[2], self.mem_ctrl[3], + self.mem_ctrl[4], self.mem_ctrl[5], + self.mem_ctrl[6], self.mem_ctrl[7]], + + [self.mem_ranges[0], + self.mem_ranges[2], self.mem_ranges[3], + self.mem_ranges[4], self.mem_ranges[5], + self.mem_ranges[6], self.mem_ranges[7], + self.mem_ranges[8], self.mem_ranges[9]], + [self.pc.south_bridge.ide.dma, self.iobus.mem_side_ports], + self.iobus, + ) + + self.caches.access_backing_store = True + self.caches.phys_mem = [ + SimpleMemory(range=self.mem_ranges[0], in_addr_map=True), + SimpleMemory(range=self.mem_ranges[2], in_addr_map=True), + SimpleMemory(range=self.mem_ranges[3], in_addr_map=True), + SimpleMemory(range=self.mem_ranges[4], in_addr_map=True), + SimpleMemory(range=self.mem_ranges[5], in_addr_map=True), + SimpleMemory(range=self.mem_ranges[6], in_addr_map=True), + SimpleMemory(range=self.mem_ranges[7], in_addr_map=True), + SimpleMemory(range=self.mem_ranges[8], in_addr_map=True), + SimpleMemory(range=self.mem_ranges[9], in_addr_map=True) + ] + + if self._host_parallel: + # To get the KVM CPUs to run on different host CPUs + # Specify a different event queue for each CPU + for i, cpu in enumerate(self.cpu): + for obj in cpu.descendants(): + obj.eventq_index = 0 + + # the number of eventqs are set based + # on experiments with few benchmarks + + cpu.eventq_index = i + 1 + + def getHostParallel(self): + return self._host_parallel + + def totalInsts(self): + return sum([cpu.totalInsts() for cpu in self.cpu]) + + def createCPUThreads(self, cpu): + for c in cpu: + c.createThreads() + + def createCPU(self, num_cpus): + + if not self._restore: + # Note KVM needs a VM and atomic_noncaching + self.cpu = [X86KvmCPU(cpu_id=i) for i in range(num_cpus)] + self.kvm_vm = KvmVM() + self.mem_mode = "atomic_noncaching" + self.createCPUThreads(self.cpu) + + self.atomicCpu = [ + X86AtomicSimpleCPU(cpu_id=i, switched_out=True) + for i in range(num_cpus) + ] + self.createCPUThreads(self.atomicCpu) + + self.timingCpu = [ + X86TimingSimpleCPU(cpu_id=i, switched_out=True) + for i in range(num_cpus) + ] + self.createCPUThreads(self.timingCpu) + + self.o3Cpu = [ + X86O3CPU(cpu_id=i, switched_out=True) for i in range(num_cpus) + ] + self.createCPUThreads(self.o3Cpu) + else: + self.o3Cpu = [X86O3CPU(cpu_id=i) for i in range(num_cpus)] + self.mem_mode = "timing" + self.createCPUThreads(self.o3Cpu) + + def switchCpus(self, old, new): + assert new[0].switchedOut() + m5.switchCpus(self, list(zip(old, new))) + + def setDiskImages(self, img_path_1, img_path_2): + disk0 = CowDisk(img_path_1) + disk2 = CowDisk(img_path_2) + self.pc.south_bridge.ide.disks = [disk0, disk2] + + def _createKernelMemoryController(self, cls): + return MemCtrl(dram=cls(range=self.mem_ranges[0], kvm_map=False)) + + def _createMemoryControllers( + self, assoc, dcache_size, mem_size_per_channel, policy, is_link, link_lat, bypass + ): + self.kernel_mem_ctrl = self._createKernelMemoryController( + DDR3_1600_8x8 + ) + + self.mem_ctrl = [PolicyManager(range=self.mem_ranges[i], kvm_map=False) for i in range(2,10)] + print("0: " , len(self.mem_ctrl)) + self.loc_mem_ctrl = [MemCtrl() for i in range(0,8)] + self.far_mem_ctrl = [MemCtrl() for i in range(0,2)] + + self.membusPolManFarMem = L2XBar(width=64) + self.membusPolManFarMem.frontend_latency = link_lat + self.membusPolManFarMem.response_latency = link_lat + + for i in range(0,8): + self.mem_ctrl[i].static_frontend_latency = "10ns" + self.mem_ctrl[i].static_backend_latency = "10ns" + self.mem_ctrl[i].loc_mem_policy = policy + self.mem_ctrl[i].assoc = assoc + self.mem_ctrl[i].orb_max_size = 128 + self.mem_ctrl[i].dram_cache_size = dcache_size + if bypass == 0: + self.mem_ctrl[i].bypass_dcache = False + elif bypass == 1: + self.mem_ctrl[i].bypass_dcache = True + + # TDRAM cache + for i in range(0,8): + self.loc_mem_ctrl[i].consider_oldest_write = True + self.loc_mem_ctrl[i].oldest_write_age_threshold = 2500000 + self.loc_mem_ctrl[i].dram = TDRAM(range=self.mem_ranges[i+2], in_addr_map=False, kvm_map=False) + self.loc_mem_ctrl[i].dram.device_size = dcache_size + self.mem_ctrl[i].loc_mem = self.loc_mem_ctrl[i].dram + self.loc_mem_ctrl[i].static_frontend_latency = "1ns" + self.loc_mem_ctrl[i].static_backend_latency = "1ns" + self.loc_mem_ctrl[i].static_frontend_latency_tc = "0ns" + self.loc_mem_ctrl[i].static_backend_latency_tc = "0ns" + self.loc_mem_ctrl[i].dram.read_buffer_size = 64 + self.loc_mem_ctrl[i].dram.write_buffer_size = 64 + self.loc_mem_ctrl[i].port = self.mem_ctrl[i].loc_req_port + + # main memory + for i in range(0,2): + self.far_mem_ctrl[i] = MemCtrl() + self.far_mem_ctrl[i].dram = DDR5_4400_4x8(range=self.mem_ranges[i+10], in_addr_map=True, kvm_map=False) + self.far_mem_ctrl[i].dram.device_size = mem_size_per_channel + self.far_mem_ctrl[i].static_frontend_latency = "1ns" + self.far_mem_ctrl[i].static_backend_latency = "1ns" + self.far_mem_ctrl[i].dram.read_buffer_size = 64 + self.far_mem_ctrl[i].dram.write_buffer_size = 64 + self.membusPolManFarMem.mem_side_ports = self.far_mem_ctrl[i].port + + # far backing store + for i in range(0,8): + self.membusPolManFarMem.cpu_side_ports = self.mem_ctrl[i].far_req_port + + + def initFS(self, cpus): + self.pc = Pc() + + self.workload = X86FsLinux() + + # North Bridge + self.iobus = IOXBar() + + # connect the io bus + # Note: pass in a reference to where Ruby will connect to in the future + # so the port isn't connected twice. + self.pc.attachIO(self.iobus, [self.pc.south_bridge.ide.dma]) + + ############################################### + + # Add in a Bios information structure. + self.workload.smbios_table.structures = [X86SMBiosBiosInformation()] + + # Set up the Intel MP table + base_entries = [] + ext_entries = [] + for i in range(cpus): + bp = X86IntelMPProcessor( + local_apic_id=i, + local_apic_version=0x14, + enable=True, + bootstrap=(i == 0), + ) + base_entries.append(bp) + io_apic = X86IntelMPIOAPIC( + id=cpus, version=0x11, enable=True, address=0xFEC00000 + ) + self.pc.south_bridge.io_apic.apic_id = io_apic.id + base_entries.append(io_apic) + pci_bus = X86IntelMPBus(bus_id=0, bus_type="PCI ") + base_entries.append(pci_bus) + isa_bus = X86IntelMPBus(bus_id=1, bus_type="ISA ") + base_entries.append(isa_bus) + connect_busses = X86IntelMPBusHierarchy( + bus_id=1, subtractive_decode=True, parent_bus=0 + ) + ext_entries.append(connect_busses) + pci_dev4_inta = X86IntelMPIOIntAssignment( + interrupt_type="INT", + polarity="ConformPolarity", + trigger="ConformTrigger", + source_bus_id=0, + source_bus_irq=0 + (4 << 2), + dest_io_apic_id=io_apic.id, + dest_io_apic_intin=16, + ) + base_entries.append(pci_dev4_inta) + + def assignISAInt(irq, apicPin): + assign_8259_to_apic = X86IntelMPIOIntAssignment( + interrupt_type="ExtInt", + polarity="ConformPolarity", + trigger="ConformTrigger", + source_bus_id=1, + source_bus_irq=irq, + dest_io_apic_id=io_apic.id, + dest_io_apic_intin=0, + ) + base_entries.append(assign_8259_to_apic) + assign_to_apic = X86IntelMPIOIntAssignment( + interrupt_type="INT", + polarity="ConformPolarity", + trigger="ConformTrigger", + source_bus_id=1, + source_bus_irq=irq, + dest_io_apic_id=io_apic.id, + dest_io_apic_intin=apicPin, + ) + base_entries.append(assign_to_apic) + + assignISAInt(0, 2) + assignISAInt(1, 1) + for i in range(3, 15): + assignISAInt(i, i) + self.workload.intel_mp_table.base_entries = base_entries + self.workload.intel_mp_table.ext_entries = ext_entries + + entries = [ + # Mark the first megabyte of memory as reserved + X86E820Entry(addr=0, size="639kB", range_type=1), + X86E820Entry(addr=0x9FC00, size="385kB", range_type=2), + # Mark the rest of physical memory as available + X86E820Entry( + addr=0x100000, + size="%dB" % (self.mem_ranges[0].size() - 0x100000), + range_type=1, + ), + X86E820Entry( + addr=0x100000000, + size="%dB" % (self.mem_ranges[2].size()), + range_type=1, + ), + ] + + # Reserve the last 16kB of the 32-bit address space for m5ops + entries.append( + X86E820Entry(addr=0xFFFF0000, size="64kB", range_type=2) + ) + + self.workload.e820_table.entries = entries diff --git a/configs-npb-gapbs-8Channel/system/system.py b/configs-npb-gapbs-8Channel/system/system.py new file mode 100755 index 0000000000..6365b39d63 --- /dev/null +++ b/configs-npb-gapbs-8Channel/system/system.py @@ -0,0 +1,414 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2018 The Regents of the University of California +# All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power + +import m5 +from m5.objects import * +from .fs_tools import * +from .caches import * + + +class MySystem(System): + + def __init__(self, kernel, disk, num_cpus, opts, no_kvm=False): + super(MySystem, self).__init__() + self._opts = opts + self._no_kvm = no_kvm + + self._host_parallel = not self._opts.no_host_parallel + + # Set up the clock domain and the voltage domain + self.clk_domain = SrcClockDomain() + self.clk_domain.clock = '2.3GHz' + self.clk_domain.voltage_domain = VoltageDomain() + + #mem_size = '32GB' + #self.mem_ranges = [AddrRange('100MB'), # For kernel + # AddrRange(0xC0000000, size=0x100000), # For I/0 + # AddrRange(Addr('4GB'), size = mem_size) # All data + # ] + + + self.mem_ranges = [AddrRange(Addr('2GiB')), # All data + AddrRange(0xC0000000, size=0x100000), # For I/0 + ] + + # Create the main memory bus + # This connects to main memory + self.membus = SystemXBar(width = 64) # 64-byte width + self.membus.badaddr_responder = BadAddr() + self.membus.default = Self.badaddr_responder.pio + + # Set up the system port for functional access from the simulator + self.system_port = self.membus.cpu_side_ports + + self.initFS(self.membus, num_cpus) + + + # Replace these paths with the path to your disk images. + # The first disk is the root disk. The second could be used for swap + # or anything else. + + self.setDiskImages(disk, disk) + + if opts.second_disk: + self.setDiskImages(disk, opts.second_disk) + else: + self.setDiskImages(disk, disk) + + # Change this path to point to the kernel you want to use + self.workload.object_file = kernel + # Options specified on the kernel command line + boot_options = ['earlyprintk=ttyS0', 'console=ttyS0', 'lpj=7999923', + 'root=/dev/hda1'] + + self.workload.command_line = ' '.join(boot_options) + + # Create the CPUs for our system. + self.createCPU(num_cpus) + + # Create the cache heirarchy for the system. + self.createCacheHierarchy() + + # Set up the interrupt controllers for the system (x86 specific) + self.setupInterrupts() + + # self.intrctrl = IntrControl() + + self.createMemoryControllersDDR4() + + if self._host_parallel: + # To get the KVM CPUs to run on different host CPUs + # Specify a different event queue for each CPU + for i,cpu in enumerate(self.cpu): + for obj in cpu.descendants(): + obj.eventq_index = 0 + + # the number of eventqs are set based + # on experiments with few benchmarks + + if len(self.cpu) > 16: + cpu.eventq_index = (i/4) + 1 + else: + cpu.eventq_index = (i/2) + 1 + def getHostParallel(self): + return self._host_parallel + + def totalInsts(self): + return sum([cpu.totalInsts() for cpu in self.cpu]) + + def createCPUThreads(self, cpu): + for c in cpu: + c.createThreads() + + def createCPU(self, num_cpus): + if self._no_kvm: + self.cpu = [AtomicSimpleCPU(cpu_id = i, switched_out = False) + for i in range(num_cpus)] + self.createCPUThreads(self.cpu) + self.mem_mode = 'timing' + + else: + # Note KVM needs a VM and atomic_noncaching + self.cpu = [X86KvmCPU(cpu_id = i) + for i in range(num_cpus)] + self.createCPUThreads(self.cpu) + self.kvm_vm = KvmVM() + self.mem_mode = 'atomic_noncaching' + + self.atomicCpu = [AtomicSimpleCPU(cpu_id = i, + switched_out = True) + for i in range(num_cpus)] + self.createCPUThreads(self.atomicCpu) + + self.timingCpu = [TimingSimpleCPU(cpu_id = i, + switched_out = True) + for i in range(num_cpus)] + + self.createCPUThreads(self.timingCpu) + + def switchCpus(self, old, new): + assert(new[0].switchedOut()) + m5.switchCpus(self, list(zip(old, new))) + + def setDiskImages(self, img_path_1, img_path_2): + disk0 = CowDisk(img_path_1) + disk2 = CowDisk(img_path_2) + self.pc.south_bridge.ide.disks = [disk0, disk2] + + def createCacheHierarchy(self): + # Create an L3 cache (with crossbar) + self.l3bus = L2XBar(width = 64, + snoop_filter = SnoopFilter(max_capacity='32MB')) + + for cpu in self.cpu: + # Create a memory bus, a coherent crossbar, in this case + cpu.l2bus = L2XBar() + + # Create an L1 instruction and data cache + cpu.icache = L1ICache(self._opts) + cpu.dcache = L1DCache(self._opts) + cpu.mmucache = MMUCache() + + # Connect the instruction and data caches to the CPU + cpu.icache.connectCPU(cpu) + cpu.dcache.connectCPU(cpu) + cpu.mmucache.connectCPU(cpu) + + # Hook the CPU ports up to the l2bus + cpu.icache.connectBus(cpu.l2bus) + cpu.dcache.connectBus(cpu.l2bus) + cpu.mmucache.connectBus(cpu.l2bus) + + # Create an L2 cache and connect it to the l2bus + cpu.l2cache = L2Cache(self._opts) + cpu.l2cache.connectCPUSideBus(cpu.l2bus) + + # Connect the L2 cache to the L3 bus + cpu.l2cache.connectMemSideBus(self.l3bus) + + self.l3cache = L3Cache(self._opts) + self.l3cache.connectCPUSideBus(self.l3bus) + + # Connect the L3 cache to the membus + self.l3cache.connectMemSideBus(self.membus) + + def setupInterrupts(self): + for cpu in self.cpu: + # create the interrupt controller CPU and connect to the membus + cpu.createInterruptController() + + # For x86 only, connect interrupts to the memory + # Note: these are directly connected to the memory bus and + # not cached + cpu.interrupts[0].pio = self.membus.mem_side_ports + cpu.interrupts[0].int_requestor = self.membus.cpu_side_ports + cpu.interrupts[0].int_responder = self.membus.mem_side_ports + + # Memory latency: Using the smaller number from [3]: 96ns + def createMemoryControllersDDR4(self): + self._createMemoryControllers(1, DDR4_2400_16x4) + + def _createMemoryControllers(self, num, cls): + + self.mem_ctrl = PolicyManager(range=self.mem_ranges[0]) + # FOR DDR4 + # self.mem_ctrl.tRP = '14.16ns' + # self.mem_ctrl.tRCD_RD = '14.16ns' + # self.mem_ctrl.tRL = '14.16ns' + + # self.loc_mem_ctrl = HBMCtrl() + # self.loc_mem_ctrl.dram = HBM_2000_4H_1x64(range=AddrRange(start = '0', end = '1GiB', masks = [1 << 6], intlvMatch = 0), in_addr_map=False, kvm_map=False, null=True) + # self.loc_mem_ctrl.dram_2 = HBM_2000_4H_1x64(range=AddrRange(start = '0', end = '1GiB', masks = [1 << 6], intlvMatch = 1), in_addr_map=False, kvm_map=False, null=True) + + self.loc_mem_ctrl = MemCtrl() + self.loc_mem_ctrl.dram = DDR4_2400_16x4(range=self.mem_ranges[0], in_addr_map=False, kvm_map=False) + + self.far_mem_ctrl = MemCtrl() + self.far_mem_ctrl.dram = DDR4_2400_16x4(range=self.mem_ranges[0], in_addr_map=False, kvm_map=False) + + self.loc_mem_ctrl.port = self.mem_ctrl.loc_req_port + self.far_mem_ctrl.port = self.mem_ctrl.far_req_port + + self.mem_ctrl.dram_cache_size = "128MiB" + + # self.mem_ctrl = MemCtrl() + # self.mem_ctrl.dram = DDR4_2400_16x4(range=self.mem_ranges[0]) + + def _createKernelMemoryController(self, cls): + return MemCtrl(dram = cls(range = self.mem_ranges[0]), + port = self.membus.mem_side_ports) + + def _getInterleaveRanges(self, rng, num, intlv_low_bit, xor_low_bit): + from math import log + bits = int(log(num, 2)) + if 2**bits != num: + m5.fatal("Non-power of two number of memory controllers") + + intlv_bits = bits + ranges = [ + AddrRange(start=rng.start, + end=rng.end, + intlvHighBit = intlv_low_bit + intlv_bits - 1, + xorHighBit = xor_low_bit + intlv_bits - 1, + intlvBits = intlv_bits, + intlvMatch = i) + for i in range(num) + ] + + return ranges + + def initFS(self, membus, cpus): + self.pc = Pc() + self.workload = X86FsLinux() + + # Constants similar to x86_traits.hh + IO_address_space_base = 0x8000000000000000 + pci_config_address_space_base = 0xc000000000000000 + interrupts_address_space_base = 0xa000000000000000 + APIC_range_size = 1 << 12 + + # North Bridge + self.iobus = IOXBar() + self.bridge = Bridge(delay='50ns') + self.bridge.mem_side_port = self.iobus.cpu_side_ports + self.bridge.cpu_side_port = membus.mem_side_ports + # Allow the bridge to pass through: + # 1) kernel configured PCI device memory map address: address range + # [0xC0000000, 0xFFFF0000). (The upper 64kB are reserved for m5ops.) + # 2) the bridge to pass through the IO APIC (two pages, already + # contained in 1), + # 3) everything in the IO address range up to the local APIC, and + # 4) then the entire PCI address space and beyond. + self.bridge.ranges = \ + [ + AddrRange(0xC0000000, 0xFFFF0000), + AddrRange(IO_address_space_base, + interrupts_address_space_base - 1), + AddrRange(pci_config_address_space_base, + Addr.max) + ] + + # Create a bridge from the IO bus to the memory bus to allow access + # to the local APIC (two pages) + self.apicbridge = Bridge(delay='50ns') + self.apicbridge.cpu_side_port = self.iobus.mem_side_ports + self.apicbridge.mem_side_port = membus.cpu_side_ports + self.apicbridge.ranges = [AddrRange(interrupts_address_space_base, + interrupts_address_space_base + + cpus * APIC_range_size + - 1)] + + # connect the io bus + self.pc.attachIO(self.iobus) + + # Add a tiny cache to the IO bus. + # This cache is required for the classic memory model for coherence + self.iocache = Cache(assoc=8, + tag_latency = 50, + data_latency = 50, + response_latency = 50, + mshrs = 20, + size = '1kB', + tgts_per_mshr = 12, + addr_ranges = self.mem_ranges) + self.iocache.cpu_side = self.iobus.mem_side_ports + self.iocache.mem_side = self.membus.cpu_side_ports + + ############################################### + + # Add in a Bios information structure. + self.workload.smbios_table.structures = [X86SMBiosBiosInformation()] + + # Set up the Intel MP table + base_entries = [] + ext_entries = [] + for i in range(cpus): + bp = X86IntelMPProcessor( + local_apic_id = i, + local_apic_version = 0x14, + enable = True, + bootstrap = (i ==0)) + base_entries.append(bp) + io_apic = X86IntelMPIOAPIC( + id = cpus, + version = 0x11, + enable = True, + address = 0xfec00000) + self.pc.south_bridge.io_apic.apic_id = io_apic.id + base_entries.append(io_apic) + pci_bus = X86IntelMPBus(bus_id = 0, bus_type='PCI ') + base_entries.append(pci_bus) + isa_bus = X86IntelMPBus(bus_id = 1, bus_type='ISA ') + base_entries.append(isa_bus) + connect_busses = X86IntelMPBusHierarchy(bus_id=1, + subtractive_decode=True, parent_bus=0) + ext_entries.append(connect_busses) + pci_dev4_inta = X86IntelMPIOIntAssignment( + interrupt_type = 'INT', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 0, + source_bus_irq = 0 + (4 << 2), + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = 16) + base_entries.append(pci_dev4_inta) + def assignISAInt(irq, apicPin): + assign_8259_to_apic = X86IntelMPIOIntAssignment( + interrupt_type = 'ExtInt', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 1, + source_bus_irq = irq, + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = 0) + base_entries.append(assign_8259_to_apic) + assign_to_apic = X86IntelMPIOIntAssignment( + interrupt_type = 'INT', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 1, + source_bus_irq = irq, + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = apicPin) + base_entries.append(assign_to_apic) + assignISAInt(0, 2) + assignISAInt(1, 1) + for i in range(3, 15): + assignISAInt(i, i) + self.workload.intel_mp_table.base_entries = base_entries + self.workload.intel_mp_table.ext_entries = ext_entries + + entries = \ + [ + # Mark the first megabyte of memory as reserved + X86E820Entry(addr = 0, size = '639kB', range_type = 1), + X86E820Entry(addr = 0x9fc00, size = '385kB', range_type = 2), + # Mark the rest of physical memory as available + X86E820Entry(addr = 0x100000, + size = '%dB' % (self.mem_ranges[0].size() - 0x100000), + range_type = 1), + ] + # Mark [mem_size, 3GB) as reserved if memory less than 3GB, which + # force IO devices to be mapped to [0xC0000000, 0xFFFF0000). Requests + # to this specific range can pass though bridge to iobus. + #entries.append(X86E820Entry(addr = self.mem_ranges[0].size(), + # size='%dB' % (0xC0000000 - self.mem_ranges[0].size()), + # range_type=2)) + + # Reserve the last 16kB of the 32-bit address space for m5ops + entries.append(X86E820Entry(addr = 0xFFFF0000, size = '64kB', + range_type=2)) + + # Add the rest of memory. This is where all the actual data is + #entries.append(X86E820Entry(addr = self.mem_ranges[-1].start, + # size='%dB' % (self.mem_ranges[-1].size()), + # range_type=1)) + + self.workload.e820_table.entries = entries + diff --git a/configs-npb-gapbs-8Channel/system/system_back.py b/configs-npb-gapbs-8Channel/system/system_back.py new file mode 100755 index 0000000000..8a645b918f --- /dev/null +++ b/configs-npb-gapbs-8Channel/system/system_back.py @@ -0,0 +1,397 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2018 The Regents of the University of California +# All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Jason Lowe-Power + +import m5 +from m5.objects import * +from .fs_tools import * +from .caches import * + + +class MySystem(System): + + def __init__(self, kernel, disk, num_cpus, opts, no_kvm=False): + super(MySystem, self).__init__() + self._opts = opts + self._no_kvm = no_kvm + + self._host_parallel = not self._opts.no_host_parallel + + # Set up the clock domain and the voltage domain + self.clk_domain = SrcClockDomain() + self.clk_domain.clock = '2.3GHz' + self.clk_domain.voltage_domain = VoltageDomain() + + mem_size = '32GB' + self.mem_ranges = [AddrRange('100MB'), # For kernel + AddrRange(0xC0000000, size=0x100000), # For I/0 + AddrRange(Addr('4GB'), size = mem_size) # All data + ] + + + self.mem_ranges = [AddrRange(Addr('3GB')), # All data + AddrRange(0xC0000000, size=0x100000), # For I/0 + ] + + # Create the main memory bus + # This connects to main memory + self.membus = SystemXBar(width = 64) # 64-byte width + self.membus.badaddr_responder = BadAddr() + self.membus.default = Self.badaddr_responder.pio + + # Set up the system port for functional access from the simulator + self.system_port = self.membus.cpu_side_ports + + self.initFS(self.membus, num_cpus) + + + # Replace these paths with the path to your disk images. + # The first disk is the root disk. The second could be used for swap + # or anything else. + + self.setDiskImages(disk, disk) + + if opts.second_disk: + self.setDiskImages(disk, opts.second_disk) + else: + self.setDiskImages(disk, disk) + + # Change this path to point to the kernel you want to use + self.workload.object_file = kernel + # Options specified on the kernel command line + boot_options = ['earlyprintk=ttyS0', 'console=ttyS0', 'lpj=7999923', + 'root=/dev/hda1'] + + self.workload.command_line = ' '.join(boot_options) + + # Create the CPUs for our system. + self.createCPU(num_cpus) + + # Create the cache heirarchy for the system. + self.createCacheHierarchy() + + # Set up the interrupt controllers for the system (x86 specific) + self.setupInterrupts() + + self.createMemoryControllersDDR4() + + if self._host_parallel: + # To get the KVM CPUs to run on different host CPUs + # Specify a different event queue for each CPU + for i,cpu in enumerate(self.cpu): + for obj in cpu.descendants(): + obj.eventq_index = 0 + + # the number of eventqs are set based + # on experiments with few benchmarks + + if len(self.cpu) > 16: + cpu.eventq_index = (i/4) + 1 + else: + cpu.eventq_index = (i/2) + 1 + def getHostParallel(self): + return self._host_parallel + + def totalInsts(self): + return sum([cpu.totalInsts() for cpu in self.cpu]) + + def createCPUThreads(self, cpu): + for c in cpu: + c.createThreads() + + def createCPU(self, num_cpus): + if self._no_kvm: + self.cpu = [AtomicSimpleCPU(cpu_id = i, switched_out = False) + for i in range(num_cpus)] + self.createCPUThreads(self.cpu) + self.mem_mode = 'timing' + + else: + # Note KVM needs a VM and atomic_noncaching + self.cpu = [X86KvmCPU(cpu_id = i) + for i in range(num_cpus)] + self.createCPUThreads(self.cpu) + self.kvm_vm = KvmVM() + self.mem_mode = 'atomic_noncaching' + + self.atomicCpu = [AtomicSimpleCPU(cpu_id = i, + switched_out = True) + for i in range(num_cpus)] + self.createCPUThreads(self.atomicCpu) + + self.timingCpu = [TimingSimpleCPU(cpu_id = i, + switched_out = True) + for i in range(num_cpus)] + + self.createCPUThreads(self.timingCpu) + + def switchCpus(self, old, new): + assert(new[0].switchedOut()) + m5.switchCpus(self, list(zip(old, new))) + + def setDiskImages(self, img_path_1, img_path_2): + disk0 = CowDisk(img_path_1) + disk2 = CowDisk(img_path_2) + self.pc.south_bridge.ide.disks = [disk0, disk2] + + def createCacheHierarchy(self): + # Create an L3 cache (with crossbar) + self.l3bus = L2XBar(width = 64, + snoop_filter = SnoopFilter(max_capacity='32MB')) + + for cpu in self.cpu: + # Create a memory bus, a coherent crossbar, in this case + cpu.l2bus = L2XBar() + + # Create an L1 instruction and data cache + cpu.icache = L1ICache(self._opts) + cpu.dcache = L1DCache(self._opts) + cpu.mmucache = MMUCache() + + # Connect the instruction and data caches to the CPU + cpu.icache.connectCPU(cpu) + cpu.dcache.connectCPU(cpu) + cpu.mmucache.connectCPU(cpu) + + # Hook the CPU ports up to the l2bus + cpu.icache.connectBus(cpu.l2bus) + cpu.dcache.connectBus(cpu.l2bus) + cpu.mmucache.connectBus(cpu.l2bus) + + # Create an L2 cache and connect it to the l2bus + cpu.l2cache = L2Cache(self._opts) + cpu.l2cache.connectCPUSideBus(cpu.l2bus) + + # Connect the L2 cache to the L3 bus + cpu.l2cache.connectMemSideBus(self.l3bus) + + self.l3cache = L3Cache(self._opts) + self.l3cache.connectCPUSideBus(self.l3bus) + + # Connect the L3 cache to the membus + self.l3cache.connectMemSideBus(self.membus) + + def setupInterrupts(self): + for cpu in self.cpu: + # create the interrupt controller CPU and connect to the membus + cpu.createInterruptController() + + # For x86 only, connect interrupts to the memory + # Note: these are directly connected to the memory bus and + # not cached + cpu.interrupts[0].pio = self.membus.mem_side_ports + cpu.interrupts[0].int_requestor = self.membus.cpu_side_ports + cpu.interrupts[0].int_responder = self.membus.mem_side_ports + + # Memory latency: Using the smaller number from [3]: 96ns + def createMemoryControllersDDR4(self): + self._createMemoryControllers(8, DDR4_2400_16x4) + + def _createMemoryControllers(self, num, cls): + kernel_controller = self._createKernelMemoryController(cls) + + ranges = self._getInterleaveRanges(self.mem_ranges[-1], num, 7, 20) + + self.mem_cntrls = [ + MemCtrl(dram = cls(range = ranges[i]), + port = self.membus.mem_side_ports) + for i in range(num) + ] + [kernel_controller] + + def _createKernelMemoryController(self, cls): + return MemCtrl(dram = cls(range = self.mem_ranges[0]), + port = self.membus.mem_side_ports) + + def _getInterleaveRanges(self, rng, num, intlv_low_bit, xor_low_bit): + from math import log + bits = int(log(num, 2)) + if 2**bits != num: + m5.fatal("Non-power of two number of memory controllers") + + intlv_bits = bits + ranges = [ + AddrRange(start=rng.start, + end=rng.end, + intlvHighBit = intlv_low_bit + intlv_bits - 1, + xorHighBit = xor_low_bit + intlv_bits - 1, + intlvBits = intlv_bits, + intlvMatch = i) + for i in range(num) + ] + + return ranges + + def initFS(self, membus, cpus): + self.pc = Pc() + self.workload = X86FsLinux() + + # Constants similar to x86_traits.hh + IO_address_space_base = 0x8000000000000000 + pci_config_address_space_base = 0xc000000000000000 + interrupts_address_space_base = 0xa000000000000000 + APIC_range_size = 1 << 12; + + # North Bridge + self.iobus = IOXBar() + self.bridge = Bridge(delay='50ns') + self.bridge.mem_side_port = self.iobus.cpu_side_ports + self.bridge.cpu_side_port = membus.mem_side_ports + # Allow the bridge to pass through: + # 1) kernel configured PCI device memory map address: address range + # [0xC0000000, 0xFFFF0000). (The upper 64kB are reserved for m5ops.) + # 2) the bridge to pass through the IO APIC (two pages, already + # contained in 1), + # 3) everything in the IO address range up to the local APIC, and + # 4) then the entire PCI address space and beyond. + self.bridge.ranges = \ + [ + AddrRange(0xC0000000, 0xFFFF0000), + AddrRange(IO_address_space_base, + interrupts_address_space_base - 1), + AddrRange(pci_config_address_space_base, + Addr.max) + ] + + # Create a bridge from the IO bus to the memory bus to allow access + # to the local APIC (two pages) + self.apicbridge = Bridge(delay='50ns') + self.apicbridge.cpu_side_port = self.iobus.mem_side_ports + self.apicbridge.mem_side_port = membus.cpu_side_ports + self.apicbridge.ranges = [AddrRange(interrupts_address_space_base, + interrupts_address_space_base + + cpus * APIC_range_size + - 1)] + + # connect the io bus + self.pc.attachIO(self.iobus) + + # Add a tiny cache to the IO bus. + # This cache is required for the classic memory model for coherence + self.iocache = Cache(assoc=8, + tag_latency = 50, + data_latency = 50, + response_latency = 50, + mshrs = 20, + size = '1kB', + tgts_per_mshr = 12, + addr_ranges = self.mem_ranges) + self.iocache.cpu_side = self.iobus.mem_side_ports + self.iocache.mem_side = self.membus.cpu_side_ports + + ############################################### + + # Add in a Bios information structure. + self.workload.smbios_table.structures = [X86SMBiosBiosInformation()] + + # Set up the Intel MP table + base_entries = [] + ext_entries = [] + for i in range(cpus): + bp = X86IntelMPProcessor( + local_apic_id = i, + local_apic_version = 0x14, + enable = True, + bootstrap = (i ==0)) + base_entries.append(bp) + io_apic = X86IntelMPIOAPIC( + id = cpus, + version = 0x11, + enable = True, + address = 0xfec00000) + self.pc.south_bridge.io_apic.apic_id = io_apic.id + base_entries.append(io_apic) + pci_bus = X86IntelMPBus(bus_id = 0, bus_type='PCI ') + base_entries.append(pci_bus) + isa_bus = X86IntelMPBus(bus_id = 1, bus_type='ISA ') + base_entries.append(isa_bus) + connect_busses = X86IntelMPBusHierarchy(bus_id=1, + subtractive_decode=True, parent_bus=0) + ext_entries.append(connect_busses) + pci_dev4_inta = X86IntelMPIOIntAssignment( + interrupt_type = 'INT', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 0, + source_bus_irq = 0 + (4 << 2), + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = 16) + base_entries.append(pci_dev4_inta) + def assignISAInt(irq, apicPin): + assign_8259_to_apic = X86IntelMPIOIntAssignment( + interrupt_type = 'ExtInt', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 1, + source_bus_irq = irq, + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = 0) + base_entries.append(assign_8259_to_apic) + assign_to_apic = X86IntelMPIOIntAssignment( + interrupt_type = 'INT', + polarity = 'ConformPolarity', + trigger = 'ConformTrigger', + source_bus_id = 1, + source_bus_irq = irq, + dest_io_apic_id = io_apic.id, + dest_io_apic_intin = apicPin) + base_entries.append(assign_to_apic) + assignISAInt(0, 2) + assignISAInt(1, 1) + for i in range(3, 15): + assignISAInt(i, i) + self.workload.intel_mp_table.base_entries = base_entries + self.workload.intel_mp_table.ext_entries = ext_entries + + entries = \ + [ + # Mark the first megabyte of memory as reserved + X86E820Entry(addr = 0, size = '639kB', range_type = 1), + X86E820Entry(addr = 0x9fc00, size = '385kB', range_type = 2), + # Mark the rest of physical memory as available + X86E820Entry(addr = 0x100000, + size = '%dB' % (self.mem_ranges[0].size() - 0x100000), + range_type = 1), + ] + # Mark [mem_size, 3GB) as reserved if memory less than 3GB, which + # force IO devices to be mapped to [0xC0000000, 0xFFFF0000). Requests + # to this specific range can pass though bridge to iobus. + entries.append(X86E820Entry(addr = self.mem_ranges[0].size(), + size='%dB' % (0xC0000000 - self.mem_ranges[0].size()), + range_type=2)) + + # Reserve the last 16kB of the 32-bit address space for m5ops + entries.append(X86E820Entry(addr = 0xFFFF0000, size = '64kB', + range_type=2)) + + # Add the rest of memory. This is where all the actual data is + entries.append(X86E820Entry(addr = self.mem_ranges[-1].start, + size='%dB' % (self.mem_ranges[-1].size()), + range_type=1)) + + self.workload.e820_table.entries = entries + diff --git a/configs-npb-gapbs/system/ruby_system_new.py b/configs-npb-gapbs/system/ruby_system_new.py index 8f204a2327..3643d9dea4 100644 --- a/configs-npb-gapbs/system/ruby_system_new.py +++ b/configs-npb-gapbs/system/ruby_system_new.py @@ -67,7 +67,7 @@ def __init__( AddrRange(0xC0000000, size=0x100000), # For I/0 AddrRange( 0x100000000, size=main_mem_size - ), # starting at 4GiB for 16 GiB + ), # starting at 4GiB for main_mem_size ] self.initFS(num_cpus) diff --git a/test.sh b/test.sh index 6eaa69ffad..a37f167b60 100755 --- a/test.sh +++ b/test.sh @@ -27,4 +27,6 @@ # build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/GAPBS/cc configs-npb-gapbs/restore_both.py cc-25 RambusTagProbOpt 1 0 0 0 & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/GAPBS/pr configs-npb-gapbs/restore_both.py pr-25 RambusTagProbOpt 1 0 0 0 & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/GAPBS/tc configs-npb-gapbs/restore_both.py tc-25 RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/GAPBS/sssp configs-npb-gapbs/restore_both.py sssp-25 RambusTagProbOpt 1 0 0 0 & \ No newline at end of file +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/GAPBS/sssp configs-npb-gapbs/restore_both.py sssp-25 RambusTagProbOpt 1 0 0 0 & + +build/X86_MESI_Two_Level/gem5.opt --outdir=cptTest/gapbs/22/pr configs-npb-gapbs/gapbs_checkpoint.py pr 22 RambusTagProbOpt & \ No newline at end of file From b8c5dfbee12e9f160b564db1e0884bc7c0ddc8b2 Mon Sep 17 00:00:00 2001 From: Jason Lowe-Power Date: Fri, 27 Oct 2023 14:31:46 -0700 Subject: [PATCH 12/28] configs: Jason's changes Change-Id: I2f94d6f2aababb678c8f8d11b307bd91bc217d6b Signed-off-by: Jason Lowe-Power --- .../system/ruby_system_new.py | 159 ++++++++++++------ 1 file changed, 108 insertions(+), 51 deletions(-) diff --git a/configs-npb-gapbs-8Channel/system/ruby_system_new.py b/configs-npb-gapbs-8Channel/system/ruby_system_new.py index c5d4f14baf..5a9fea4015 100644 --- a/configs-npb-gapbs-8Channel/system/ruby_system_new.py +++ b/configs-npb-gapbs-8Channel/system/ruby_system_new.py @@ -40,7 +40,7 @@ def __init__( mem_sys, num_cpus, assoc, - dcache_size, # size of 1 channel + dcache_size, # size of 1 channel main_mem_size, mem_size_per_channel, policy, @@ -62,24 +62,63 @@ def __init__( self.clk_domain = SrcClockDomain() self.clk_domain.clock = "5GHz" self.clk_domain.voltage_domain = VoltageDomain() + self._main_mem_size = main_mem_size + + self._data_ranges = [ + AddrRange( + start=0x100000000, + size=main_mem_size, + masks=[1 << 6, 1 << 7, 1 << 8], + intlvMatch=0, + ), + AddrRange( + start=0x100000000, + size=main_mem_size, + masks=[1 << 6, 1 << 7, 1 << 8], + intlvMatch=1, + ), + AddrRange( + start=0x100000000, + size=main_mem_size, + masks=[1 << 6, 1 << 7, 1 << 8], + intlvMatch=2, + ), + AddrRange( + start=0x100000000, + size=main_mem_size, + masks=[1 << 6, 1 << 7, 1 << 8], + intlvMatch=3, + ), + AddrRange( + start=0x100000000, + size=main_mem_size, + masks=[1 << 6, 1 << 7, 1 << 8], + intlvMatch=4, + ), + AddrRange( + start=0x100000000, + size=main_mem_size, + masks=[1 << 6, 1 << 7, 1 << 8], + intlvMatch=5, + ), + AddrRange( + start=0x100000000, + size=main_mem_size, + masks=[1 << 6, 1 << 7, 1 << 8], + intlvMatch=6, + ), + AddrRange( + start=0x100000000, + size=main_mem_size, + masks=[1 << 6, 1 << 7, 1 << 8], + intlvMatch=7, + ), + ] self.mem_ranges = [ AddrRange(Addr("128MiB")), # kernel data AddrRange(0xC0000000, size=0x100000), # For I/0 - # AddrRange( - # 0x100000000, size=main_mem_size - # ), # starting at 4GiB for main_mem_size GiB - AddrRange(start = 0x100000000, size = main_mem_size, masks = [1 << 6, 1 << 7, 1 << 8], intlvMatch = 0), - AddrRange(start = 0x100000000, size = main_mem_size, masks = [1 << 6, 1 << 7, 1 << 8], intlvMatch = 1), - AddrRange(start = 0x100000000, size = main_mem_size, masks = [1 << 6, 1 << 7, 1 << 8], intlvMatch = 2), - AddrRange(start = 0x100000000, size = main_mem_size, masks = [1 << 6, 1 << 7, 1 << 8], intlvMatch = 3), - AddrRange(start = 0x100000000, size = main_mem_size, masks = [1 << 6, 1 << 7, 1 << 8], intlvMatch = 4), - AddrRange(start = 0x100000000, size = main_mem_size, masks = [1 << 6, 1 << 7, 1 << 8], intlvMatch = 5), - AddrRange(start = 0x100000000, size = main_mem_size, masks = [1 << 6, 1 << 7, 1 << 8], intlvMatch = 6), - AddrRange(start = 0x100000000, size = main_mem_size, masks = [1 << 6, 1 << 7, 1 << 8], intlvMatch = 7), - AddrRange(start = 0x100000000, size = main_mem_size, masks = [1 << 6], intlvMatch = 0), - AddrRange(start = 0x100000000, size = main_mem_size, masks = [1 << 6], intlvMatch = 1) - ] + ] + self._data_ranges self.initFS(num_cpus) @@ -105,7 +144,13 @@ def __init__( # self.intrctrl = IntrControl() self._createMemoryControllers( - assoc, dcache_size, mem_size_per_channel, policy, is_link, link_lat, bypass + assoc, + dcache_size, + mem_size_per_channel, + policy, + is_link, + link_lat, + bypass, ) # Create the cache hierarchy for the system. @@ -128,17 +173,18 @@ def __init__( self.caches.setup( self, cpus, - [self.kernel_mem_ctrl, - self.mem_ctrl[0], self.mem_ctrl[1], - self.mem_ctrl[2], self.mem_ctrl[3], - self.mem_ctrl[4], self.mem_ctrl[5], - self.mem_ctrl[6], self.mem_ctrl[7]], - - [self.mem_ranges[0], - self.mem_ranges[2], self.mem_ranges[3], - self.mem_ranges[4], self.mem_ranges[5], - self.mem_ranges[6], self.mem_ranges[7], - self.mem_ranges[8], self.mem_ranges[9]], + [ + self.kernel_mem_ctrl, + self.mem_ctrl[0], + self.mem_ctrl[1], + self.mem_ctrl[2], + self.mem_ctrl[3], + self.mem_ctrl[4], + self.mem_ctrl[5], + self.mem_ctrl[6], + self.mem_ctrl[7], + ], + [self.mem_ranges[0]] + self._data_ranges, [self.pc.south_bridge.ide.dma, self.iobus.mem_side_ports], self.iobus, ) @@ -146,14 +192,7 @@ def __init__( self.caches.access_backing_store = True self.caches.phys_mem = [ SimpleMemory(range=self.mem_ranges[0], in_addr_map=True), - SimpleMemory(range=self.mem_ranges[2], in_addr_map=True), - SimpleMemory(range=self.mem_ranges[3], in_addr_map=True), - SimpleMemory(range=self.mem_ranges[4], in_addr_map=True), - SimpleMemory(range=self.mem_ranges[5], in_addr_map=True), - SimpleMemory(range=self.mem_ranges[6], in_addr_map=True), - SimpleMemory(range=self.mem_ranges[7], in_addr_map=True), - SimpleMemory(range=self.mem_ranges[8], in_addr_map=True), - SimpleMemory(range=self.mem_ranges[9], in_addr_map=True) + SimpleMemory(range=0x100000000, size=main_mem_size), ] if self._host_parallel: @@ -221,22 +260,31 @@ def _createKernelMemoryController(self, cls): return MemCtrl(dram=cls(range=self.mem_ranges[0], kvm_map=False)) def _createMemoryControllers( - self, assoc, dcache_size, mem_size_per_channel, policy, is_link, link_lat, bypass + self, + assoc, + dcache_size, + mem_size_per_channel, + policy, + is_link, + link_lat, + bypass, ): self.kernel_mem_ctrl = self._createKernelMemoryController( DDR3_1600_8x8 ) - self.mem_ctrl = [PolicyManager(range=self.mem_ranges[i], kvm_map=False) for i in range(2,10)] - print("0: " , len(self.mem_ctrl)) - self.loc_mem_ctrl = [MemCtrl() for i in range(0,8)] - self.far_mem_ctrl = [MemCtrl() for i in range(0,2)] + self.mem_ctrl = [ + PolicyManager(range=r, kvm_map=False) for r in self.mem_ranges[2:] + ] + print("0: ", len(self.mem_ctrl)) + self.loc_mem_ctrl = [MemCtrl() for i in range(0, 8)] + self.far_mem_ctrl = [MemCtrl() for i in range(0, 2)] self.membusPolManFarMem = L2XBar(width=64) self.membusPolManFarMem.frontend_latency = link_lat self.membusPolManFarMem.response_latency = link_lat - - for i in range(0,8): + + for i in range(0, 8): self.mem_ctrl[i].static_frontend_latency = "10ns" self.mem_ctrl[i].static_backend_latency = "10ns" self.mem_ctrl[i].loc_mem_policy = policy @@ -247,12 +295,17 @@ def _createMemoryControllers( self.mem_ctrl[i].bypass_dcache = False elif bypass == 1: self.mem_ctrl[i].bypass_dcache = True + self.membusPolManFarMem.cpu_side_ports = self.mem_ctrl[ + i + ].far_req_port # TDRAM cache - for i in range(0,8): + for i in range(8): self.loc_mem_ctrl[i].consider_oldest_write = True self.loc_mem_ctrl[i].oldest_write_age_threshold = 2500000 - self.loc_mem_ctrl[i].dram = TDRAM(range=self.mem_ranges[i+2], in_addr_map=False, kvm_map=False) + self.loc_mem_ctrl[i].dram = TDRAM( + range=self._data_ranges[i], in_addr_map=False, kvm_map=False + ) self.loc_mem_ctrl[i].dram.device_size = dcache_size self.mem_ctrl[i].loc_mem = self.loc_mem_ctrl[i].dram self.loc_mem_ctrl[i].static_frontend_latency = "1ns" @@ -264,20 +317,24 @@ def _createMemoryControllers( self.loc_mem_ctrl[i].port = self.mem_ctrl[i].loc_req_port # main memory - for i in range(0,2): + for i in range(2): self.far_mem_ctrl[i] = MemCtrl() - self.far_mem_ctrl[i].dram = DDR5_4400_4x8(range=self.mem_ranges[i+10], in_addr_map=True, kvm_map=False) + self.far_mem_ctrl[i].dram = DDR5_4400_4x8( + range=AddrRange( + start=0x100000000, + size=self._main_mem_size, + masks=[1 << 6], + intlvMatch=i, + ), + in_addr_map=False, + kvm_map=False, + ) self.far_mem_ctrl[i].dram.device_size = mem_size_per_channel self.far_mem_ctrl[i].static_frontend_latency = "1ns" self.far_mem_ctrl[i].static_backend_latency = "1ns" self.far_mem_ctrl[i].dram.read_buffer_size = 64 self.far_mem_ctrl[i].dram.write_buffer_size = 64 self.membusPolManFarMem.mem_side_ports = self.far_mem_ctrl[i].port - - # far backing store - for i in range(0,8): - self.membusPolManFarMem.cpu_side_ports = self.mem_ctrl[i].far_req_port - def initFS(self, cpus): self.pc = Pc() From f5f39866dc06f7662557af0fcdc659a9dbb0bda8 Mon Sep 17 00:00:00 2001 From: mbabaie Date: Fri, 27 Oct 2023 16:51:33 -0700 Subject: [PATCH 13/28] some updates to the configs --- .../gapbs_checkpoint.py | 3 +- .../system/MESI_Two_Level.py | 3 -- .../system/ruby_system_new.py | 43 +++++-------------- test.sh | 2 +- 4 files changed, 14 insertions(+), 37 deletions(-) diff --git a/configs-npb-gapbs-8Channel/gapbs_checkpoint.py b/configs-npb-gapbs-8Channel/gapbs_checkpoint.py index a21710cace..e04c84504d 100755 --- a/configs-npb-gapbs-8Channel/gapbs_checkpoint.py +++ b/configs-npb-gapbs-8Channel/gapbs_checkpoint.py @@ -163,8 +163,9 @@ def parse_options(): # switching CPU to timing system.switchCpus(system.cpu, system.timingCpu) else: + print(exit_event.getCause()) print("Unexpected termination of simulation !") - exit() + exit(1) m5.stats.reset() print( diff --git a/configs-npb-gapbs-8Channel/system/MESI_Two_Level.py b/configs-npb-gapbs-8Channel/system/MESI_Two_Level.py index 86ea0411f0..8307e74634 100755 --- a/configs-npb-gapbs-8Channel/system/MESI_Two_Level.py +++ b/configs-npb-gapbs-8Channel/system/MESI_Two_Level.py @@ -69,8 +69,6 @@ def setup(self, system, cpus, mem_ctrls, mem_ranges, dma_ports, iobus): # customized depending on the topology/network requirements. # L1 caches are private to a core, hence there are one L1 cache per CPU # core. The number of L2 caches are dependent to the architecture. - print("1:" , len(mem_ranges)) - print("2:" , len(mem_ctrls[1])) self.controllers = \ [L1Cache(system, self, cpu, self._numL2Caches) for cpu in cpus] + \ [L2Cache(system, self, self._numL2Caches) for num in \ @@ -257,7 +255,6 @@ def __init__(self, ruby_system, ranges, mem_ctrls): """ranges are the memory ranges assigned to this controller. """ if len(mem_ctrls) > 1: - print("3:" , len(mem_ctrls)) panic("This cache system can only be connected to one mem ctrl") super(DirController, self).__init__() self.version = self.versionCount() diff --git a/configs-npb-gapbs-8Channel/system/ruby_system_new.py b/configs-npb-gapbs-8Channel/system/ruby_system_new.py index 5a9fea4015..73d675be4a 100644 --- a/configs-npb-gapbs-8Channel/system/ruby_system_new.py +++ b/configs-npb-gapbs-8Channel/system/ruby_system_new.py @@ -30,6 +30,7 @@ import m5 from m5.objects import * from .fs_tools import * +from .MESI_Two_Level import MESITwoLevelCache class MyRubySystem(System): @@ -153,37 +154,17 @@ def __init__( bypass, ) - # Create the cache hierarchy for the system. - if mem_sys == "MI_example": - from .MI_example_caches import MIExampleSystem - - self.caches = MIExampleSystem() - elif mem_sys == "MESI_Two_Level": - from .MESI_Two_Level import MESITwoLevelCache - - self.caches = MESITwoLevelCache() - elif mem_sys == "MOESI_CMP_directory": - from .MOESI_CMP_directory import MOESICMPDirCache - - self.caches = MOESICMPDirCache() if self._restore: cpus = self.o3Cpu else: cpus = self.cpu + + # Create the cache hierarchy for the system. + self.caches = MESITwoLevelCache() self.caches.setup( self, cpus, - [ - self.kernel_mem_ctrl, - self.mem_ctrl[0], - self.mem_ctrl[1], - self.mem_ctrl[2], - self.mem_ctrl[3], - self.mem_ctrl[4], - self.mem_ctrl[5], - self.mem_ctrl[6], - self.mem_ctrl[7], - ], + [self.kernel_mem_ctrl] + self.mem_ctrl, [self.mem_ranges[0]] + self._data_ranges, [self.pc.south_bridge.ide.dma, self.iobus.mem_side_ports], self.iobus, @@ -191,8 +172,8 @@ def __init__( self.caches.access_backing_store = True self.caches.phys_mem = [ - SimpleMemory(range=self.mem_ranges[0], in_addr_map=True), - SimpleMemory(range=0x100000000, size=main_mem_size), + SimpleMemory(range=self.mem_ranges[0], in_addr_map=False), + SimpleMemory(range=AddrRange(0x100000000, size=main_mem_size), in_addr_map=False), ] if self._host_parallel: @@ -276,9 +257,8 @@ def _createMemoryControllers( self.mem_ctrl = [ PolicyManager(range=r, kvm_map=False) for r in self.mem_ranges[2:] ] - print("0: ", len(self.mem_ctrl)) - self.loc_mem_ctrl = [MemCtrl() for i in range(0, 8)] - self.far_mem_ctrl = [MemCtrl() for i in range(0, 2)] + self.loc_mem_ctrl = [MemCtrl() for i in range(8)] + self.far_mem_ctrl = [MemCtrl() for i in range(2)] self.membusPolManFarMem = L2XBar(width=64) self.membusPolManFarMem.frontend_latency = link_lat @@ -304,7 +284,7 @@ def _createMemoryControllers( self.loc_mem_ctrl[i].consider_oldest_write = True self.loc_mem_ctrl[i].oldest_write_age_threshold = 2500000 self.loc_mem_ctrl[i].dram = TDRAM( - range=self._data_ranges[i], in_addr_map=False, kvm_map=False + range=self._data_ranges[i], in_addr_map=False, kvm_map=False, null = True ) self.loc_mem_ctrl[i].dram.device_size = dcache_size self.mem_ctrl[i].loc_mem = self.loc_mem_ctrl[i].dram @@ -326,8 +306,7 @@ def _createMemoryControllers( masks=[1 << 6], intlvMatch=i, ), - in_addr_map=False, - kvm_map=False, + in_addr_map=False, kvm_map=False, null = True ) self.far_mem_ctrl[i].dram.device_size = mem_size_per_channel self.far_mem_ctrl[i].static_frontend_latency = "1ns" diff --git a/test.sh b/test.sh index a37f167b60..144c08e0ec 100755 --- a/test.sh +++ b/test.sh @@ -29,4 +29,4 @@ # build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/GAPBS/tc configs-npb-gapbs/restore_both.py tc-25 RambusTagProbOpt 1 0 0 0 & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/GAPBS/sssp configs-npb-gapbs/restore_both.py sssp-25 RambusTagProbOpt 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt --outdir=cptTest/gapbs/22/pr configs-npb-gapbs/gapbs_checkpoint.py pr 22 RambusTagProbOpt & \ No newline at end of file +build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/gapbs/22/pr configs-npb-gapbs/gapbs_checkpoint.py pr 22 RambusTagProbOpt & \ No newline at end of file From e332ba5bd88e139912a242d2d329ff7400eea835 Mon Sep 17 00:00:00 2001 From: mbabaie Date: Fri, 27 Oct 2023 17:00:37 -0700 Subject: [PATCH 14/28] small update to the path of disk image --- configs-npb-gapbs-8Channel/gapbs_checkpoint.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs-npb-gapbs-8Channel/gapbs_checkpoint.py b/configs-npb-gapbs-8Channel/gapbs_checkpoint.py index e04c84504d..870dcac0c8 100755 --- a/configs-npb-gapbs-8Channel/gapbs_checkpoint.py +++ b/configs-npb-gapbs-8Channel/gapbs_checkpoint.py @@ -91,7 +91,7 @@ def parse_options(): kernel = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-linux-kernel-4.19.83" - disk = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-npb" + disk = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-gapbs" num_cpus = 8 cpu_type = "Timing" From 2062611db105ae176a632b3bd4456ebd692db18e Mon Sep 17 00:00:00 2001 From: mbabaie Date: Sun, 29 Oct 2023 00:15:59 -0700 Subject: [PATCH 15/28] unified the scripts for gapbs and npb --- configs-npb-gapbs-8Channel/npb_checkpoint.py | 251 ----------- configs-npb-gapbs-8Channel/system/__init__.py | 31 -- .../checkpoint_both.py | 70 ++- .../info.py | 0 .../restore_both.py | 125 +++--- .../system/MESI_Two_Level.py | 0 .../system/MI_example_caches.py | 0 .../system/MOESI_CMP_directory.py | 0 .../system/__init__.py | 3 +- .../system/caches.py | 0 .../system/fs_tools.py | 0 .../system/ruby_system_1channel.py | 5 +- .../system/ruby_system_8channel.py | 5 +- .../system/system.py | 0 .../system/system_back.py | 0 configs-npb-gapbs/gapbs_checkpoint.py | 199 --------- configs-npb-gapbs/info.py | 325 -------------- configs-npb-gapbs/npb_checkpoint.py | 255 ----------- configs-npb-gapbs/restore_both.py | 331 -------------- configs-npb-gapbs/system/MESI_Two_Level.py | 332 -------------- configs-npb-gapbs/system/MI_example_caches.py | 275 ------------ .../system/MOESI_CMP_directory.py | 350 --------------- configs-npb-gapbs/system/caches.py | 173 -------- configs-npb-gapbs/system/fs_tools.py | 39 -- configs-npb-gapbs/system/system.py | 414 ------------------ configs-npb-gapbs/system/system_back.py | 397 ----------------- 26 files changed, 121 insertions(+), 3459 deletions(-) delete mode 100755 configs-npb-gapbs-8Channel/npb_checkpoint.py delete mode 100755 configs-npb-gapbs-8Channel/system/__init__.py rename configs-npb-gapbs-8Channel/gapbs_checkpoint.py => configs-npb-gapbs-chkpt-restore/checkpoint_both.py (76%) mode change 100755 => 100644 rename {configs-npb-gapbs-8Channel => configs-npb-gapbs-chkpt-restore}/info.py (100%) rename {configs-npb-gapbs-8Channel => configs-npb-gapbs-chkpt-restore}/restore_both.py (85%) rename {configs-npb-gapbs-8Channel => configs-npb-gapbs-chkpt-restore}/system/MESI_Two_Level.py (100%) rename {configs-npb-gapbs-8Channel => configs-npb-gapbs-chkpt-restore}/system/MI_example_caches.py (100%) rename {configs-npb-gapbs-8Channel => configs-npb-gapbs-chkpt-restore}/system/MOESI_CMP_directory.py (100%) rename {configs-npb-gapbs => configs-npb-gapbs-chkpt-restore}/system/__init__.py (93%) rename {configs-npb-gapbs-8Channel => configs-npb-gapbs-chkpt-restore}/system/caches.py (100%) rename {configs-npb-gapbs-8Channel => configs-npb-gapbs-chkpt-restore}/system/fs_tools.py (100%) rename configs-npb-gapbs/system/ruby_system_new.py => configs-npb-gapbs-chkpt-restore/system/ruby_system_1channel.py (99%) rename configs-npb-gapbs-8Channel/system/ruby_system_new.py => configs-npb-gapbs-chkpt-restore/system/ruby_system_8channel.py (99%) rename {configs-npb-gapbs-8Channel => configs-npb-gapbs-chkpt-restore}/system/system.py (100%) rename {configs-npb-gapbs-8Channel => configs-npb-gapbs-chkpt-restore}/system/system_back.py (100%) delete mode 100755 configs-npb-gapbs/gapbs_checkpoint.py delete mode 100644 configs-npb-gapbs/info.py delete mode 100755 configs-npb-gapbs/npb_checkpoint.py delete mode 100755 configs-npb-gapbs/restore_both.py delete mode 100755 configs-npb-gapbs/system/MESI_Two_Level.py delete mode 100755 configs-npb-gapbs/system/MI_example_caches.py delete mode 100755 configs-npb-gapbs/system/MOESI_CMP_directory.py delete mode 100755 configs-npb-gapbs/system/caches.py delete mode 100755 configs-npb-gapbs/system/fs_tools.py delete mode 100755 configs-npb-gapbs/system/system.py delete mode 100755 configs-npb-gapbs/system/system_back.py diff --git a/configs-npb-gapbs-8Channel/npb_checkpoint.py b/configs-npb-gapbs-8Channel/npb_checkpoint.py deleted file mode 100755 index 6488a76db4..0000000000 --- a/configs-npb-gapbs-8Channel/npb_checkpoint.py +++ /dev/null @@ -1,251 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2019 The Regents of the University of California. -# All rights reserved. -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Jason Lowe-Power, Ayaz Akram - -""" Script to run NAS parallel benchmarks with gem5. - The script expects kernel, diskimage, mem_sys, - cpu (kvm, atomic, or timing), benchmark to run - and number of cpus as arguments. - - If your application has ROI annotations, this script will count the total - number of instructions executed in the ROI. It also tracks how much - wallclock and simulated time. -""" -import argparse -import time -import m5 -import m5.ticks -from m5.objects import * - -from system import * - - -def writeBenchScript(dir, bench): - """ - This method creates a script in dir which will be eventually - passed to the simulated system (to run a specific benchmark - at bootup). - """ - file_name = "{}/run_{}".format(dir, bench) - bench_file = open(file_name, "w+") - bench_file.write("/home/gem5/NPB3.3-OMP/bin/{} \n".format(bench)) - - # sleeping for sometime (5 seconds here) makes sure - # that the benchmark's output has been - # printed to the console - bench_file.write("sleep 5 \n") - bench_file.write("m5 exit \n") - bench_file.close() - return file_name - - -supported_protocols = [ - "classic", - "MI_example", - "MESI_Two_Level", - "MOESI_CMP_directory", -] -supported_cpu_types = ["kvm", "atomic", "timing"] -benchmark_choices = [ - "bt.A.x", - "cg.A.x", - "ep.A.x", - "ft.A.x", - "is.A.x", - "lu.A.x", - "mg.A.x", - "sp.A.x", - "bt.B.x", - "cg.B.x", - "ep.B.x", - "ft.B.x", - "is.B.x", - "lu.B.x", - "mg.B.x", - "sp.B.x", - "bt.C.x", - "cg.C.x", - "ep.C.x", - "ft.C.x", - "is.C.x", - "lu.C.x", - "mg.C.x", - "sp.C.x", - "bt.D.x", - "cg.D.x", - "ep.D.x", - "ft.D.x", - "is.D.x", - "lu.D.x", - "mg.D.x", - "sp.D.x", - "bt.F.x", - "cg.F.x", - "ep.F.x", - "ft.F.x", - "is.F.x", - "lu.F.x", - "mg.F.x", - "sp.F.x", - "ua.C.x", - "ua.D.x", -] - - -def parse_options(): - - parser = argparse.ArgumentParser( - description="For use with gem5. This " - "runs a NAS Parallel Benchmark application. This only works " - "with x86 ISA." - ) - - # The manditry position arguments. - parser.add_argument( - "benchmark", - type=str, # choices=benchmark_choices, - help="The NPB application to run", - ) - parser.add_argument( - "class_size", type=str, help="The NPB application class to run" - ) - parser.add_argument( - "dcache_policy", - type=str, - help="The architecture of DRAM cache: " - "CascadeLakeNoPartWrs, Oracle, BearWriteOpt, Rambus, RambusTagProbOpt", - ) - parser.add_argument( - "is_link", - type=int, - help="whether to use a link for backing store or not", - ) - parser.add_argument( - "link_lat", type=str, help="latency of the link to backing store" - ) - - return parser.parse_args() - - -if __name__ == "__m5_main__": - args = parse_options() - - kernel = "/home/mbabaie/code-review/dramCacheController/fs-resources/x86-linux-kernel-4.19.83" - disk = "/home/mbabaie/code-review/dramCacheController/fs-resources/x86-npb" - num_cpus = 8 - cpu_type = "Timing" - mem_sys = "MESI_Two_Level" - - dcache_size = "1GiB" - mem_size = "128GiB" - mem_size_per_channel = "64GiB" - assoc = 1 - benchmark = args.benchmark - - # create the system we are going to simulate - system = MyRubySystem( - kernel, - disk, - mem_sys, - num_cpus, - assoc, - dcache_size, - mem_size, - mem_size_per_channel, - args.dcache_policy, - args.is_link, - args.link_lat, - 0, - args, - ) - - system.m5ops_base = 0xFFFF0000 - - # Exit from guest on workbegin/workend - system.exit_on_work_items = True - - # Create and pass a script to the simulated system to run the reuired - # benchmark - system.readfile = writeBenchScript(m5.options.outdir, benchmark) - - # set up the root SimObject and start the simulation - root = Root(full_system=True, system=system) - - if system.getHostParallel(): - # Required for running kvm on multiple host cores. - # Uses gem5's parallel event queue feature - # Note: The simulator is quite picky about this number! - root.sim_quantum = int(1e9) # 1 ms - - # needed for long running jobs - # m5.disableAllListeners() - - # instantiate all of the objects we've created above - m5.instantiate() - - globalStart = time.time() - - print("Running the simulation") - print("Using cpu: {}".format(cpu_type)) - exit_event = m5.simulate() - - if exit_event.getCause() == "workbegin": - print("Done booting Linux") - # Reached the start of ROI - # start of ROI is marked by an - # m5_work_begin() call - print("Resetting stats at the start of ROI!") - m5.stats.reset() - start_tick = m5.curTick() - start_insts = system.totalInsts() - # switching CPU to timing - system.switchCpus(system.cpu, system.timingCpu) - else: - print(exit_event.getCause()) - print("Unexpected termination of simulation !") - exit() - - m5.stats.reset() - print( - "After reset ************************************************ statring smiulation:\n" - ) - for interval_number in range(0,1): - print("Interval number: {} \n".format(interval_number)) - exit_event = m5.simulate(1000000000) - if exit_event.getCause() == "cacheIsWarmedup": - print("Caught cacheIsWarmedup exit event!") - break - print( - "-------------------------------------------------------------------" - ) - - print( - "After sim ************************************************ End of warm-up \n" - ) - m5.stats.dump() - system.switchCpus(system.timingCpu, system.o3Cpu) - m5.checkpoint(m5.options.outdir + "/cpt") diff --git a/configs-npb-gapbs-8Channel/system/__init__.py b/configs-npb-gapbs-8Channel/system/__init__.py deleted file mode 100755 index 7ef9c5dadd..0000000000 --- a/configs-npb-gapbs-8Channel/system/__init__.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2016 Jason Lowe-Power -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Jason Lowe-Power - -from .system import MySystem -from .ruby_system_new import MyRubySystem diff --git a/configs-npb-gapbs-8Channel/gapbs_checkpoint.py b/configs-npb-gapbs-chkpt-restore/checkpoint_both.py old mode 100755 new mode 100644 similarity index 76% rename from configs-npb-gapbs-8Channel/gapbs_checkpoint.py rename to configs-npb-gapbs-chkpt-restore/checkpoint_both.py index 870dcac0c8..bc260886a7 --- a/configs-npb-gapbs-8Channel/gapbs_checkpoint.py +++ b/configs-npb-gapbs-chkpt-restore/checkpoint_both.py @@ -34,14 +34,9 @@ import m5 import m5.ticks from m5.objects import * - from system import * -supported_protocols = ["MESI_Two_Level"] -supported_cpu_types = ["kvm", "atomic", "timing"] - - -def writeBenchScript(dir, benchmark_name, size, synthetic): +def writeBenchScript_GAPBS(dir, benchmark_name, size, synthetic): """ This method creates a script in dir which will be eventually passed to the simulated system (to run a specific benchmark @@ -62,20 +57,39 @@ def writeBenchScript(dir, benchmark_name, size, synthetic): return input_file_name +def writeBenchScript_NPB(dir, bench): + """ + This method creates a script in dir which will be eventually + passed to the simulated system (to run a specific benchmark + at bootup). + """ + file_name = "{}/run_{}".format(dir, bench) + bench_file = open(file_name, "w+") + bench_file.write("/home/gem5/NPB3.3-OMP/bin/{} \n".format(bench)) + + # sleeping for sometime (5 seconds here) makes sure + # that the benchmark's output has been + # printed to the console + bench_file.write("sleep 5 \n") + bench_file.write("m5 exit \n") + bench_file.close() + return file_name def parse_options(): - parser = argparse.ArgumentParser( - description="For use with gem5. This " - "runs a GAPBS applications. This only works " + description="For use with gem5. This script " + "runs a GAPBS/NPB application and only works " "with x86 ISA." ) - - # The manditry position arguments. parser.add_argument( - "benchmark", type=str, help="The GAPBS application to run" + "isGAPBS", type=int, help="GAPBS (1) application to run or NPB (0)" + ) + parser.add_argument( + "benchmark", type=str, help="The application to run" + ) + parser.add_argument( + "size", type=str, help="The problem size to run" ) - parser.add_argument("graph", type=str, help="The GAPBS application to run") parser.add_argument( "dcache_policy", type=str, @@ -89,21 +103,25 @@ def parse_options(): if __name__ == "__m5_main__": args = parse_options() - kernel = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-linux-kernel-4.19.83" - disk = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-gapbs" + disk = "" + if args.isGAPBS == 1: + disk = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-gapbs" + elif args.isGAPBS == 0: + disk = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-npb" + num_cpus = 8 cpu_type = "Timing" mem_sys = "MESI_Two_Level" synthetic = 1 - dcache_size = "1GiB" # size of each channel mem_size = "128GiB" mem_size_per_channel = "64GiB" assoc = 1 + # create the system we are going to simulate - system = MyRubySystem( + system = RubySystem8Channel( kernel, disk, mem_sys, @@ -126,9 +144,18 @@ def parse_options(): # Create and pass a script to the simulated system to run the reuired # benchmark - system.readfile = writeBenchScript( - m5.options.outdir, args.benchmark, args.graph, synthetic - ) + if args.isGAPBS == 1: + system.readfile = writeBenchScript_GAPBS( + m5.options.outdir, + args.benchmark, + args.size, + synthetic + ) + elif args.isGAPBS == 0: + system.readfile = writeBenchScript_NPB( + m5.options.outdir, + args.benchmark+"."+args.size+".x" + ) # set up the root SimObject and start the simulation root = Root(full_system=True, system=system) @@ -171,7 +198,7 @@ def parse_options(): print( "After reset ************************************************ statring smiulation:\n" ) - for interval_number in range(0,1): + for interval_number in range(1): print("Interval number: {} \n".format(interval_number)) exit_event = m5.simulate(1000000000) if exit_event.getCause() == "cacheIsWarmedup": @@ -186,4 +213,5 @@ def parse_options(): ) m5.stats.dump() system.switchCpus(system.timingCpu, system.o3Cpu) + print("switched from timing to O3") m5.checkpoint(m5.options.outdir + "/cpt") diff --git a/configs-npb-gapbs-8Channel/info.py b/configs-npb-gapbs-chkpt-restore/info.py similarity index 100% rename from configs-npb-gapbs-8Channel/info.py rename to configs-npb-gapbs-chkpt-restore/info.py diff --git a/configs-npb-gapbs-8Channel/restore_both.py b/configs-npb-gapbs-chkpt-restore/restore_both.py similarity index 85% rename from configs-npb-gapbs-8Channel/restore_both.py rename to configs-npb-gapbs-chkpt-restore/restore_both.py index f2175b951e..ee3902aef6 100755 --- a/configs-npb-gapbs-8Channel/restore_both.py +++ b/configs-npb-gapbs-chkpt-restore/restore_both.py @@ -56,37 +56,16 @@ ) -def writeBenchScriptNPB(dir, bench): +def writeBenchScript_GAPBS(dir, benchmark_name, size, synthetic): """ This method creates a script in dir which will be eventually passed to the simulated system (to run a specific benchmark at bootup). """ - file_name = "{}/run_{}".format(dir, bench) - bench_file = open(file_name, "w+") - bench_file.write("/home/gem5/NPB3.3-OMP/bin/{} \n".format(bench)) - - # sleeping for sometime (5 seconds here) makes sure - # that the benchmark's output has been - # printed to the console - bench_file.write("sleep 5 \n") - bench_file.write("m5 exit \n") - bench_file.close() - return file_name - - -def writeBenchScriptGAPBS(dir, benchmark_name): - """ - This method creates a script in dir which will be eventually - passed to the simulated system (to run a specific benchmark - at bootup). - """ - synthetic = True - benchmark, size = benchmark_name.split("-") - input_file_name = "{}/run_{}_{}".format(dir, benchmark, size) + input_file_name = "{}/run_{}_{}".format(dir, benchmark_name, size) if synthetic: with open(input_file_name, "w") as f: - f.write("./{} -g {}\n".format(benchmark, size)) + f.write("./{} -g {}\n".format(benchmark_name, size)) elif synthetic == 0: with open(input_file_name, "w") as f: # The workloads that are copied to the disk image using Packer @@ -94,18 +73,27 @@ def writeBenchScriptGAPBS(dir, benchmark_name): # Since the command running the workload will be executed with # pwd = /home/gem5/gapbs, the path to the copied workload is # ../{workload-name} - f.write("./{} -sf ../{}".format(benchmark, size)) + f.write("./{} -sf ../{}".format(benchmark_name, size)) return input_file_name +def writeBenchScript_NPB(dir, bench): + """ + This method creates a script in dir which will be eventually + passed to the simulated system (to run a specific benchmark + at bootup). + """ + file_name = "{}/run_{}".format(dir, bench) + bench_file = open(file_name, "w+") + bench_file.write("/home/gem5/NPB3.3-OMP/bin/{} \n".format(bench)) -supported_protocols = [ - "classic", - "MI_example", - "MESI_Two_Level", - "MOESI_CMP_directory", -] -supported_cpu_types = ["kvm", "atomic", "timing"] + # sleeping for sometime (5 seconds here) makes sure + # that the benchmark's output has been + # printed to the console + bench_file.write("sleep 5 \n") + bench_file.write("m5 exit \n") + bench_file.close() + return file_name def parse_options(): @@ -114,13 +102,9 @@ def parse_options(): "runs a NAS Parallel Benchmark application. This only works " "with x86 ISA." ) - # The manditry position arguments. parser.add_argument( - "benchmark", - type=str, - choices=benchmark_choices_npb + benchmark_choices_gapbs, - help="The NPB application to run", + "isGAPBS", type=int, help="GAPBS (1) application to run or NPB (0)" ) parser.add_argument( "dcache_policy", @@ -204,16 +188,21 @@ def run(): args = parse_options() kernel = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-linux-kernel-4.19.83" - disk = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-npb" + disk = "" + if args.isGAPBS == 1: + disk = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-gapbs" + elif args.isGAPBS == 0: + disk = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-npb" ckpt_base = "/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/chkpt1GigDC/" num_cpus = 8 cpu_type = "Timing" mem_sys = "MESI_Two_Level" - - dcache_size = "1GB" - mem_size = "" + synthetic = 1 + dcache_size = "1GiB" # size of each channel + mem_size = "128GiB" mem_size_per_channel = "64GiB" + single_channel_HBM = False checkpoint_dir = "" if args.benchmark in benchmark_choices_npb: @@ -253,22 +242,40 @@ def run(): benchmark = args.benchmark - system = MyRubySystem( - kernel, - disk, - mem_sys, - num_cpus, - args.assoc, - dcache_size, - mem_size_per_channel, - mem_size, - args.dcache_policy, - args.is_link, - args.link_lat, - args.bypass, - args, - restore=True, - ) + if single_channel_HBM: + system = RubySystem1Channel( + kernel, + disk, + mem_sys, + num_cpus, + args.assoc, + dcache_size, + mem_size, + mem_size_per_channel, + args.dcache_policy, + args.is_link, + args.link_lat, + args.bypass, + args, + restore=True, + ) + else: + system = RubySystem8Channel( + kernel, + disk, + mem_sys, + num_cpus, + args.assoc, + dcache_size, + mem_size, + mem_size_per_channel, + args.dcache_policy, + args.is_link, + args.link_lat, + args.bypass, + args, + restore=True, + ) if args.do_analysis: lpmanager = O3LooppointAnalysisManager() @@ -300,11 +307,11 @@ def run(): # Create and pass a script to the simulated system to run the reuired # benchmark if args.benchmark in benchmark_choices_npb: - system.readfile = writeBenchScriptNPB( + system.readfile = writeBenchScript_NPB( m5.options.outdir, args.benchmark ) else: - system.readfile = writeBenchScriptGAPBS( + system.readfile = writeBenchScript_GAPBS( m5.options.outdir, args.benchmark ) diff --git a/configs-npb-gapbs-8Channel/system/MESI_Two_Level.py b/configs-npb-gapbs-chkpt-restore/system/MESI_Two_Level.py similarity index 100% rename from configs-npb-gapbs-8Channel/system/MESI_Two_Level.py rename to configs-npb-gapbs-chkpt-restore/system/MESI_Two_Level.py diff --git a/configs-npb-gapbs-8Channel/system/MI_example_caches.py b/configs-npb-gapbs-chkpt-restore/system/MI_example_caches.py similarity index 100% rename from configs-npb-gapbs-8Channel/system/MI_example_caches.py rename to configs-npb-gapbs-chkpt-restore/system/MI_example_caches.py diff --git a/configs-npb-gapbs-8Channel/system/MOESI_CMP_directory.py b/configs-npb-gapbs-chkpt-restore/system/MOESI_CMP_directory.py similarity index 100% rename from configs-npb-gapbs-8Channel/system/MOESI_CMP_directory.py rename to configs-npb-gapbs-chkpt-restore/system/MOESI_CMP_directory.py diff --git a/configs-npb-gapbs/system/__init__.py b/configs-npb-gapbs-chkpt-restore/system/__init__.py similarity index 93% rename from configs-npb-gapbs/system/__init__.py rename to configs-npb-gapbs-chkpt-restore/system/__init__.py index 7ef9c5dadd..f5c653b06d 100755 --- a/configs-npb-gapbs/system/__init__.py +++ b/configs-npb-gapbs-chkpt-restore/system/__init__.py @@ -28,4 +28,5 @@ # Authors: Jason Lowe-Power from .system import MySystem -from .ruby_system_new import MyRubySystem +from .ruby_system_1channel import RubySystem1Channel +from .ruby_system_8channel import RubySystem8Channel diff --git a/configs-npb-gapbs-8Channel/system/caches.py b/configs-npb-gapbs-chkpt-restore/system/caches.py similarity index 100% rename from configs-npb-gapbs-8Channel/system/caches.py rename to configs-npb-gapbs-chkpt-restore/system/caches.py diff --git a/configs-npb-gapbs-8Channel/system/fs_tools.py b/configs-npb-gapbs-chkpt-restore/system/fs_tools.py similarity index 100% rename from configs-npb-gapbs-8Channel/system/fs_tools.py rename to configs-npb-gapbs-chkpt-restore/system/fs_tools.py diff --git a/configs-npb-gapbs/system/ruby_system_new.py b/configs-npb-gapbs-chkpt-restore/system/ruby_system_1channel.py similarity index 99% rename from configs-npb-gapbs/system/ruby_system_new.py rename to configs-npb-gapbs-chkpt-restore/system/ruby_system_1channel.py index 3643d9dea4..c0e0d83f0f 100644 --- a/configs-npb-gapbs/system/ruby_system_new.py +++ b/configs-npb-gapbs-chkpt-restore/system/ruby_system_1channel.py @@ -32,7 +32,7 @@ from .fs_tools import * -class MyRubySystem(System): +class RubySystem1Channel(System): def __init__( self, kernel, @@ -49,8 +49,7 @@ def __init__( opts, restore=False, ): - super(MyRubySystem, self).__init__() - print("Creating MyRubySystem") + super(RubySystem1Channel, self).__init__() self._opts = opts # Use parallel if using KVM. Don't use parallel is restoring cpt diff --git a/configs-npb-gapbs-8Channel/system/ruby_system_new.py b/configs-npb-gapbs-chkpt-restore/system/ruby_system_8channel.py similarity index 99% rename from configs-npb-gapbs-8Channel/system/ruby_system_new.py rename to configs-npb-gapbs-chkpt-restore/system/ruby_system_8channel.py index 73d675be4a..093dc6fcb8 100644 --- a/configs-npb-gapbs-8Channel/system/ruby_system_new.py +++ b/configs-npb-gapbs-chkpt-restore/system/ruby_system_8channel.py @@ -33,7 +33,7 @@ from .MESI_Two_Level import MESITwoLevelCache -class MyRubySystem(System): +class RubySystem8Channel(System): def __init__( self, kernel, @@ -51,8 +51,7 @@ def __init__( opts, restore=False, ): - super(MyRubySystem, self).__init__() - print("Creating MyRubySystem") + super(RubySystem8Channel, self).__init__() self._opts = opts # Use parallel if using KVM. Don't use parallel is restoring cpt diff --git a/configs-npb-gapbs-8Channel/system/system.py b/configs-npb-gapbs-chkpt-restore/system/system.py similarity index 100% rename from configs-npb-gapbs-8Channel/system/system.py rename to configs-npb-gapbs-chkpt-restore/system/system.py diff --git a/configs-npb-gapbs-8Channel/system/system_back.py b/configs-npb-gapbs-chkpt-restore/system/system_back.py similarity index 100% rename from configs-npb-gapbs-8Channel/system/system_back.py rename to configs-npb-gapbs-chkpt-restore/system/system_back.py diff --git a/configs-npb-gapbs/gapbs_checkpoint.py b/configs-npb-gapbs/gapbs_checkpoint.py deleted file mode 100755 index c41abac760..0000000000 --- a/configs-npb-gapbs/gapbs_checkpoint.py +++ /dev/null @@ -1,199 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2019 The Regents of the University of California. -# All rights reserved. -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Jason Lowe-Power, Ayaz Akram - -""" Script to run GAP Benchmark suites workloads. - The workloads have two modes: synthetic and real graphs. -""" -import argparse -import time -import m5 -import m5.ticks -from m5.objects import * - -from system import * - -supported_protocols = ["MESI_Two_Level"] -supported_cpu_types = ["kvm", "atomic", "timing"] - - -def writeBenchScript(dir, benchmark_name, size, synthetic): - """ - This method creates a script in dir which will be eventually - passed to the simulated system (to run a specific benchmark - at bootup). - """ - input_file_name = "{}/run_{}_{}".format(dir, benchmark_name, size) - if synthetic: - with open(input_file_name, "w") as f: - f.write("./{} -g {}\n".format(benchmark_name, size)) - elif synthetic == 0: - with open(input_file_name, "w") as f: - # The workloads that are copied to the disk image using Packer - # should be located in /home/gem5/. - # Since the command running the workload will be executed with - # pwd = /home/gem5/gapbs, the path to the copied workload is - # ../{workload-name} - f.write("./{} -sf ../{}".format(benchmark_name, size)) - - return input_file_name - - -def parse_options(): - - parser = argparse.ArgumentParser( - description="For use with gem5. This " - "runs a GAPBS applications. This only works " - "with x86 ISA." - ) - - # The manditry position arguments. - parser.add_argument( - "benchmark", type=str, help="The GAPBS application to run" - ) - parser.add_argument("graph", type=str, help="The GAPBS application to run") - parser.add_argument( - "dcache_policy", - type=str, - help="The architecture of DRAM cache: " - "CascadeLakeNoPartWrs, Oracle, BearWriteOpt, Rambus", - ) - parser.add_argument( - "is_link", - type=int, - help="whether to use a link for backing store or not", - ) - parser.add_argument( - "link_lat", type=str, help="latency of the link to backing store" - ) - return parser.parse_args() - - -if __name__ == "__m5_main__": - args = parse_options() - - kernel = "/home/mbabaie/code-review/dramCacheController/fs-resources/x86-linux-kernel-4.19.83" - disk = ( - "/home/mbabaie/code-review/dramCacheController/fs-resources/x86-gapbs" - ) - num_cpus = 8 - cpu_type = "Timing" - mem_sys = "MESI_Two_Level" - synthetic = 1 - - dcache_size = "" - mem_size = "" - if args.graph == "22": - dcache_size = "1GiB" - mem_size = "8GiB" - elif args.graph == "25": - dcache_size = "1GiB" - mem_size = "85GiB" - assoc = 1 - # create the system we are going to simulate - system = MyRubySystem( - kernel, - disk, - mem_sys, - num_cpus, - assoc, - dcache_size, - mem_size, - args.dcache_policy, - args.is_link, - args.link_lat, - 0, - args, - ) - - system.m5ops_base = 0xFFFF0000 - - # Exit from guest on workbegin/workend - system.exit_on_work_items = True - - # Create and pass a script to the simulated system to run the reuired - # benchmark - system.readfile = writeBenchScript( - m5.options.outdir, args.benchmark, args.graph, synthetic - ) - - # set up the root SimObject and start the simulation - root = Root(full_system=True, system=system) - - if system.getHostParallel(): - # Required for running kvm on multiple host cores. - # Uses gem5's parallel event queue feature - # Note: The simulator is quite picky about this number! - root.sim_quantum = int(1e9) # 1 ms - - # needed for long running jobs - # m5.disableAllListeners() - - # instantiate all of the objects we've created above - m5.instantiate() - - globalStart = time.time() - - print("Running the simulation") - print("Using cpu: {}".format(cpu_type)) - exit_event = m5.simulate() - - if exit_event.getCause() == "workbegin": - print("Done booting Linux") - # Reached the start of ROI - # start of ROI is marked by an - # m5_work_begin() call - print("Resetting stats at the start of ROI!") - m5.stats.reset() - start_tick = m5.curTick() - start_insts = system.totalInsts() - # switching CPU to timing - system.switchCpus(system.cpu, system.timingCpu) - else: - print("Unexpected termination of simulation !") - exit() - - m5.stats.reset() - print( - "After reset ************************************************ statring smiulation:\n" - ) - for interval_number in range(150): - print("Interval number: {} \n".format(interval_number)) - exit_event = m5.simulate(10000000000) - if exit_event.getCause() == "cacheIsWarmedup": - print("Caught cacheIsWarmedup exit event!") - break - print( - "-------------------------------------------------------------------" - ) - - print( - "After sim ************************************************ End of warm-up \n" - ) - m5.stats.dump() - system.switchCpus(system.timingCpu, system.o3Cpu) - m5.checkpoint(m5.options.outdir + "/cpt") diff --git a/configs-npb-gapbs/info.py b/configs-npb-gapbs/info.py deleted file mode 100644 index 7547fb421a..0000000000 --- a/configs-npb-gapbs/info.py +++ /dev/null @@ -1,325 +0,0 @@ -text_info = { - # exe size start - "bt.A.x": (0x00018402, 0x0000000000400E50), - "bt.B.x": (0x000183E2, 0x0000000000400E50), - "bt.C.x": (0x00018342, 0x0000000000400E50), - "bt.D.x": (0x00018562, 0x0000000000400E50), - "cg.A.x": (0x00005D22, 0x0000000000400F60), - "cg.B.x": (0x00005DC2, 0x0000000000400F60), - "cg.C.x": (0x00005E32, 0x0000000000400F60), - "cg.D.x": (0x00005AC2, 0x0000000000400F60), - "ep.A.x": (0x00001E52, 0x0000000000400DB0), - "ep.B.x": (0x00001E52, 0x0000000000400DB0), - "ep.C.x": (0x00001E52, 0x0000000000400DB0), - "ep.D.x": (0x00001E52, 0x0000000000400DB0), - "ft.A.x": (0x00005202, 0x0000000000400F60), - "ft.B.x": (0x00005752, 0x0000000000400F60), - "ft.C.x": (0x00005762, 0x0000000000400F60), - "ft.D.x": (0x00005772, 0x0000000000400F60), - "is.A.x": (0x000020B2, 0x0000000000400BE0), - "is.B.x": (0x000020C2, 0x0000000000400BE0), - "is.C.x": (0x000020B2, 0x0000000000400BE0), - "is.D.x": (0x00001EB2, 0x0000000000400BE0), - "lu.A.x": (0x00016A82, 0x0000000000400F50), - "lu.B.x": (0x00016A52, 0x0000000000400F50), - "lu.C.x": (0x000169C2, 0x0000000000400F50), - "lu.D.x": (0x00016DD2, 0x0000000000400F50), - "mg.A.x": (0x0000B4A2, 0x00000000004010F0), - "mg.B.x": (0x0000B4A2, 0x00000000004010F0), - "mg.C.x": (0x0000B5E2, 0x00000000004010F0), - "mg.D.x": (0x0000B772, 0x00000000004010F0), - "sp.A.x": (0x00014162, 0x0000000000400EB0), - "sp.B.x": (0x00014162, 0x0000000000400EB0), - "sp.C.x": (0x00014052, 0x0000000000400EB0), - "sp.D.x": (0x000141B2, 0x0000000000400EB0), - "ua.A.x": (0x000274E2, 0x00000000004010C0), - "ua.B.x": (0x00027612, 0x00000000004010C0), - "ua.C.x": (0x00027552, 0x00000000004010C0), - "ua.D.x": (0x000274C2, 0x00000000004010C0), - "bc-22": (0x0000EFD2, 0x00000000004029F0), - "bfs-22": (0x0000DCF2, 0x00000000004028A0), - "cc-22": (0x0000E4C2, 0x0000000000402BE0), - "cc_sv-22": (0x0000DF12, 0x0000000000402970), - "pr-22": (0x0000E022, 0x0000000000402A10), - "sssp-22": (0x0000E692, 0x00000000004029C0), - "tc-22": (0x0000DEE2, 0x0000000000402890), - "bc-25": (0x0000EFD2, 0x00000000004029F0), - "bfs-25": (0x0000DCF2, 0x00000000004028A0), - "cc-25": (0x0000E4C2, 0x0000000000402BE0), - "cc_sv-25": (0x0000DF12, 0x0000000000402970), - "pr-25": (0x0000E022, 0x0000000000402A10), - "sssp-25": (0x0000E692, 0x00000000004029C0), - "tc-25": (0x0000DEE2, 0x0000000000402890), -} - -interval_info_1hr = { - # exe pc count - "bc-22": (0x404E08, 5409997), - "bfs-22": (0x403790, 3930710), - "bt.C.x": (0x4080E0, 1270955), - "cc-22": (0x4037B0, 8388093), - "cg.C.x": (0x4019D8, 29870850), - "pr-22": (0x4036C0, 25174574), - "ft.C.x": (0x400D70, 6760163), - "ua.C.x": (0x406B00, 344413), - "mg.C.x": (0x401B08, 4467087), - "sp.C.x": (0x409170, 1569121), - "lu.C.x": (0x402980, 5146555), - "is.C.x": (0x4017C9, 48480186), - "tc-22": (0x4052E0, 240202), - "sssp-22": (0x405441, 12651169), - "bc-25": (0x404E1A, 2192896), - "bfs-25": (0x4038E0, 11170933), - "bt.D.x": (0x407FD0, 3729824), - "cc-25": (0x404688, 6506055), - "cg.D.x": (0x4019D8, 17675668), - "pr-25": (0x4036C0, 19663604), - "ft.D.x": (0x400D70, 6498319), - "ua.D.x": (0x400F30, 2709903), - "mg.D.x": (0x401920, 3670463), - "sp.D.x": (0x409000, 3786010), - "lu.D.x": (0x402600, 116), - "is.D.x": (0x401661, 42645519), - "tc-25": (0x4030A0, 5800667), - "sssp-25": (0x405418, 979358), -} - -interval_info_3hr = { - # exe pc count - "bc-22": (0x404E08, 14968517), - "bfs-22": (0x403790, 12277309), - "bt.C.x": (0x408600, 1906919), - "cc-22": (0x404238, 5701575), - "cg.C.x": (0x4019D8, 73121983), - "pr-22": (0x4036C0, 69152771), - "ft.C.x": (0x400D70, 16530458), - "ua.C.x": (0x41D080, 4205282), - "mg.C.x": (0x401920, 12053283), - "sp.C.x": (0x409668, 2192349), - "lu.C.x": (0x402980, 9952905), - "is.C.x": (0x401955, 12922496), - "tc-22": (0x4034E0, 1507255), - "sssp-22": (0x405441, 33740179), - "bc-25": (0x404E08, 6310746), - "bfs-25": (0x4045D0, 2021755), - "bt.D.x": (0x407FD0, 10661006), - "cc-25": (0x4037B0, 31963857), - "cg.D.x": (0x4019D8, 45636549), - "pr-25": (0x4036C0, 51691344), - "ft.D.x": (0x400D70, 13065409), - "ua.D.x": (0x400F30, 8415248), - "mg.D.x": (0x401920, 11871798), - "sp.D.x": (0x409000, 9962530), - "lu.D.x": (0x4027F8, 32448), - "is.D.x": (0x401661, 119913839), - "tc-25": (0x4030A0, 30335985), - "sssp-25": (0x405441, 19973164), -} - -interval_info_6hr = { - # exe pc count - "bc-22": (0x404E08, 29440776), - "bfs-22": (0x4045D0, 3029875), - "bt.C.x": (0x409A20, 1173559), - "cc-22": (0x4037B0, 33552375), - "cg.C.x": (0x4019D8, 148363776), - "pr-22": (0x4036C0, 138691628), - "ft.C.x": (0x400D70, 30067439), - "ua.C.x": (0x405757, 134017), - "mg.C.x": (0x401920, 23222866), - "sp.C.x": (0x40AA60, 1691001), - "lu.C.x": (0x402980, 9952905), - "is.C.x": (0x401955, 79966814), - "tc-22": (0x405800, 516587), - "sssp-22": (0x405441, 67113550), - "bc-25": (0x404E08, 12151937), - "bfs-25": (0x403790, 8317180), - "bt.D.x": (0x407FD0, 21901834), - "cc-25": (0x404238, 32589977), - "cg.D.x": (0x4019D8, 91326969), - "pr-25": (0x4036C0, 99790518), - "ft.D.x": (0x400D70, 26209008), - "ua.D.x": (0x400F30, 13977417), - "mg.D.x": (0x401B08, 24048507), - "sp.D.x": (0x409000, 19860707), - "lu.D.x": (0x4027F8, 100054), - "is.D.x": (0x401661, 241880887), - "tc-25": (0x40CA70, 19083641), - "sssp-25": (0x405441, 42573632), -} - -interval_info_12hr = { - # exe pc count - "bc-22": (0x4036F0, 48778942), - "bfs-22": (0x403790, 54892278), - "bt.C.x": (0x40BF58, 611768), - "cc-22": (0x404688, 39592660), - "cg.C.x": (0x4019D8, 294906202), - "pr-22": (0x4036C0, 271266245), - "ft.C.x": (0x400D70, 56313323), - "ua.C.x": (0x41DCA0, 21222925), - "mg.C.x": (0x401B08, 45327484), - "sp.C.x": (0x40CFA0, 1219582), - "lu.C.x": (0x405C00, 72382), - "is.C.x": (0x401AF0, 129738785), - "tc-22": (0x4054A0, 87026806), - "sssp-22": (0x405441, 89183250), - "bc-25": (0x404E08, 25995768), - "bfs-25": (0x4038E0, 36114591), - "bt.D.x": (0x407FD0, 44658580), - "cc-25": (0x404688, 31320744), - "cg.D.x": (0x4019D8, 19366202), - "pr-25": (0x4036C0, 204816690), - "ft.D.x": (0x401C10, 56461566), - "ua.D.x": (0x4044C4, 6852508), - "mg.D.x": (0x401B08, 47676346), - "sp.D.x": (0x409000, 39454655), - "lu.D.x": (0x4029A0, 10268832), - "is.D.x": (0x401661, 481770516), - "tc-25": (0x40CA70, 19083641), - "sssp-25": (0x405441, 89681018), -} - -interval_info_24hr = { - # exe pc count - "bt.C.x": (0x40D230, 2377023), - "cg.C.x": (0x4019D8, 578428198), - "ft.C.x": (0x405830, 58382196), - "is.C.x": (0x401AF0, 184476965), - "lu.C.x": (0x40D4C0, 1146276), - "mg.C.x": (0x4012F8, 121010179), - "sp.C.x": (0x40EEE8, 3428040), - "ua.C.x": (0x41DCA0, 39733523), - "bc-22": (0x404E1A, 11556233), - "bfs-22": (0x401028, 65), - "cc-22": (0x404238, 39015034), - "pr-22": (0x4036C0, 530256860), - "tc-22": (0x405390, 7008077), - "sssp-22": (0x4054A0, 212570793), - "bc-25": (0x404E08, 44535390), - "bfs-25": (0x403988, 87740083), - "bt.D.x": (0x407FD0, 53208177), - "cc-25": (0x4037B0, 133906775), - "cg.D.x": (0x4019D8, 351587199), - "pr-25": (0x4036C0, 401728224), - "ft.D.x": (0x400D70, 110793818), - "ua.D.x": (0x4039C4, 12695182), ### - "mg.D.x": (0x401B08, 75633571), - "sp.D.x": (0x409000, 47034804), - "lu.D.x": (0x4029A0, 53146691), - "is.D.x": (0x401661, 858226422), - "tc-25": (0x40CA70, 19083641), - "sssp-25": (0x405441, 169473207), -} - -benchmark_choices_npb = [ - "bt.A.x", - "cg.A.x", - "ep.A.x", - "ft.A.x", - "is.A.x", - "lu.A.x", - "mg.A.x", - "sp.A.x", - "ua.A.x", - "bt.B.x", - "cg.B.x", - "ep.B.x", - "ft.B.x", - "is.B.x", - "lu.B.x", - "mg.B.x", - "sp.B.x", - "ua.B.x", - "bt.C.x", - "cg.C.x", - "ep.C.x", - "ft.C.x", - "is.C.x", - "lu.C.x", - "mg.C.x", - "sp.C.x", - "ua.C.x", - "bt.D.x", - "cg.D.x", - "ep.D.x", - "ft.D.x", - "is.D.x", - "lu.D.x", - "mg.D.x", - "sp.D.x", - "ua.D.x", - "bt.F.x", - "cg.F.x", - "ep.F.x", - "ft.F.x", - "is.F.x", - "lu.F.x", - "mg.F.x", - "sp.F.x", - "ua.F.x", -] -benchmark_choices_gapbs = [ - "bfs-22", - "bc-22", - "cc-22", - "pr-22", - "sssp-22", - "tc-22", - "bfs-25", - "bc-25", - "cc-25", - "pr-25", - "sssp-25", - "tc-25", -] - -interval_info_1hr_512MiB = { - # exe pc count - "bc-22": (0x404E08, 4355635), - "bfs-22": (0x403790, 3210973), - "bt.C.x": (0x408600, 623227), - "cc-22": (0x404688, 2218838), - "cg.C.x": (0x4019D8, 8334402), - "pr-22": (0x4036C0, 6426778), - "ft.C.x": (0x405830, 11202023), - "ua.C.x": (0x421ff6, 182749), - "mg.C.x": (0x401920, 1886013), - "sp.C.x": (0x409668, 445619), - "lu.C.x": (0x404160, 457680), - "is.C.x": (0x401955, 12277189), - "tc-22": (0x4052E0, 1059969), - "sssp-22": (0x405441, 4457679), -} - -interval_info_1GBdramCache_3hr = { - # exe pc count - "bt.C.x": (0x40f3d8,244911), - "cg.C.x": (0x4019d8,42463422), - "ft.C.x": (0x401c00,7146042), - "is.C.x": (0x401af0,46965216), - "lu.C.x": (0x40abf8,764707), - "mg.C.x": (0x401b08,6680641), - "sp.C.x": (0x40e2e0,441148), - "ua.C.x": (0x41dca0,1351162), - "bc-22": (0x4036f0,1315303), - "bfs-22": (0x403790,6915678), - "cc-22": (0x4037b0,8303408), - "pr-22": (0x4036c0,35167103), - "tc-22": (0x405640,760), - "sssp-22": (0x405390,2908597), - "bc-25": (0x404e1a,1578848), - "bfs-25": (0x403790,5365971), - "bt.D.x": (0x407fd0,4048773), - "cc-25": (0x404688,5396243), - "cg.D.x": (0x4019d8,13523512), - "pr-25": (0x4036c0,15770394), - "ft.D.x": (0x401c10,4648334), - "ua.D.x": (0x403f30,31180), - "mg.D.x": (0x401920,4263169), - "sp.D.x": (0x409000,3544598), - "lu.D.x": (0x4027f8,27621), - "is.D.x": (0x401661,31545953), - "tc-25": (0x4030a0,15958999), - "sssp-25": (0x405441,7679886), -} \ No newline at end of file diff --git a/configs-npb-gapbs/npb_checkpoint.py b/configs-npb-gapbs/npb_checkpoint.py deleted file mode 100755 index 6300d56441..0000000000 --- a/configs-npb-gapbs/npb_checkpoint.py +++ /dev/null @@ -1,255 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2019 The Regents of the University of California. -# All rights reserved. -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Jason Lowe-Power, Ayaz Akram - -""" Script to run NAS parallel benchmarks with gem5. - The script expects kernel, diskimage, mem_sys, - cpu (kvm, atomic, or timing), benchmark to run - and number of cpus as arguments. - - If your application has ROI annotations, this script will count the total - number of instructions executed in the ROI. It also tracks how much - wallclock and simulated time. -""" -import argparse -import time -import m5 -import m5.ticks -from m5.objects import * - -from system import * - - -def writeBenchScript(dir, bench): - """ - This method creates a script in dir which will be eventually - passed to the simulated system (to run a specific benchmark - at bootup). - """ - file_name = "{}/run_{}".format(dir, bench) - bench_file = open(file_name, "w+") - bench_file.write("/home/gem5/NPB3.3-OMP/bin/{} \n".format(bench)) - - # sleeping for sometime (5 seconds here) makes sure - # that the benchmark's output has been - # printed to the console - bench_file.write("sleep 5 \n") - bench_file.write("m5 exit \n") - bench_file.close() - return file_name - - -supported_protocols = [ - "classic", - "MI_example", - "MESI_Two_Level", - "MOESI_CMP_directory", -] -supported_cpu_types = ["kvm", "atomic", "timing"] -benchmark_choices = [ - "bt.A.x", - "cg.A.x", - "ep.A.x", - "ft.A.x", - "is.A.x", - "lu.A.x", - "mg.A.x", - "sp.A.x", - "bt.B.x", - "cg.B.x", - "ep.B.x", - "ft.B.x", - "is.B.x", - "lu.B.x", - "mg.B.x", - "sp.B.x", - "bt.C.x", - "cg.C.x", - "ep.C.x", - "ft.C.x", - "is.C.x", - "lu.C.x", - "mg.C.x", - "sp.C.x", - "bt.D.x", - "cg.D.x", - "ep.D.x", - "ft.D.x", - "is.D.x", - "lu.D.x", - "mg.D.x", - "sp.D.x", - "bt.F.x", - "cg.F.x", - "ep.F.x", - "ft.F.x", - "is.F.x", - "lu.F.x", - "mg.F.x", - "sp.F.x", - "ua.C.x", - "ua.D.x", -] - - -def parse_options(): - - parser = argparse.ArgumentParser( - description="For use with gem5. This " - "runs a NAS Parallel Benchmark application. This only works " - "with x86 ISA." - ) - - # The manditry position arguments. - parser.add_argument( - "benchmark", - type=str, # choices=benchmark_choices, - help="The NPB application to run", - ) - parser.add_argument( - "class_size", type=str, help="The NPB application class to run" - ) - parser.add_argument( - "dcache_policy", - type=str, - help="The architecture of DRAM cache: " - "CascadeLakeNoPartWrs, Oracle, BearWriteOpt, Rambus, RambusTagProbOpt", - ) - parser.add_argument( - "is_link", - type=int, - help="whether to use a link for backing store or not", - ) - parser.add_argument( - "link_lat", type=str, help="latency of the link to backing store" - ) - - return parser.parse_args() - - -if __name__ == "__m5_main__": - args = parse_options() - - kernel = "/home/mbabaie/code-review/dramCacheController/fs-resources/x86-linux-kernel-4.19.83" - disk = "/home/mbabaie/code-review/dramCacheController/fs-resources/x86-npb" - num_cpus = 8 - cpu_type = "Timing" - mem_sys = "MESI_Two_Level" - - dcache_size = "" - mem_size = "" - if args.class_size == "C": - dcache_size = "1GiB" - mem_size = "8GiB" - elif args.class_size == "D": - dcache_size = "1GiB" - mem_size = "85GiB" - assoc = 1 - benchmark = args.benchmark - - # create the system we are going to simulate - system = MyRubySystem( - kernel, - disk, - mem_sys, - num_cpus, - assoc, - dcache_size, - mem_size, - args.dcache_policy, - args.is_link, - args.link_lat, - 0, - args, - ) - - system.m5ops_base = 0xFFFF0000 - - # Exit from guest on workbegin/workend - system.exit_on_work_items = True - - # Create and pass a script to the simulated system to run the reuired - # benchmark - system.readfile = writeBenchScript(m5.options.outdir, benchmark) - - # set up the root SimObject and start the simulation - root = Root(full_system=True, system=system) - - if system.getHostParallel(): - # Required for running kvm on multiple host cores. - # Uses gem5's parallel event queue feature - # Note: The simulator is quite picky about this number! - root.sim_quantum = int(1e9) # 1 ms - - # needed for long running jobs - # m5.disableAllListeners() - - # instantiate all of the objects we've created above - m5.instantiate() - - globalStart = time.time() - - print("Running the simulation") - print("Using cpu: {}".format(cpu_type)) - exit_event = m5.simulate() - - if exit_event.getCause() == "workbegin": - print("Done booting Linux") - # Reached the start of ROI - # start of ROI is marked by an - # m5_work_begin() call - print("Resetting stats at the start of ROI!") - m5.stats.reset() - start_tick = m5.curTick() - start_insts = system.totalInsts() - # switching CPU to timing - system.switchCpus(system.cpu, system.timingCpu) - else: - print(exit_event.getCause()) - print("Unexpected termination of simulation !") - exit() - - m5.stats.reset() - print( - "After reset ************************************************ statring smiulation:\n" - ) - for interval_number in range(105): - print("Interval number: {} \n".format(interval_number)) - exit_event = m5.simulate(10000000000) - if exit_event.getCause() == "cacheIsWarmedup": - print("Caught cacheIsWarmedup exit event!") - break - print( - "-------------------------------------------------------------------" - ) - - print( - "After sim ************************************************ End of warm-up \n" - ) - m5.stats.dump() - system.switchCpus(system.timingCpu, system.o3Cpu) - m5.checkpoint(m5.options.outdir + "/cpt") diff --git a/configs-npb-gapbs/restore_both.py b/configs-npb-gapbs/restore_both.py deleted file mode 100755 index b661bcacd2..0000000000 --- a/configs-npb-gapbs/restore_both.py +++ /dev/null @@ -1,331 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2019 The Regents of the University of California. -# All rights reserved. -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Jason Lowe-Power, Ayaz Akram - -""" Script to run NAS parallel benchmarks with gem5. - The script expects kernel, diskimage, mem_sys, - cpu (kvm, atomic, or timing), benchmark to run - and number of cpus as arguments. - - If your application has ROI annotations, this script will count the total - number of instructions executed in the ROI. It also tracks how much - wallclock and simulated time. -""" -import argparse -import time -import m5 -import m5.ticks -from m5.objects import * - -from system import * -from info import ( - text_info, - interval_info_1hr, - interval_info_3hr, - interval_info_6hr, - interval_info_12hr, - interval_info_24hr, - benchmark_choices_gapbs, - benchmark_choices_npb, - interval_info_1hr_512MiB, - interval_info_1GBdramCache_3hr, -) - - -def writeBenchScriptNPB(dir, bench): - """ - This method creates a script in dir which will be eventually - passed to the simulated system (to run a specific benchmark - at bootup). - """ - file_name = "{}/run_{}".format(dir, bench) - bench_file = open(file_name, "w+") - bench_file.write("/home/gem5/NPB3.3-OMP/bin/{} \n".format(bench)) - - # sleeping for sometime (5 seconds here) makes sure - # that the benchmark's output has been - # printed to the console - bench_file.write("sleep 5 \n") - bench_file.write("m5 exit \n") - bench_file.close() - return file_name - - -def writeBenchScriptGAPBS(dir, benchmark_name): - """ - This method creates a script in dir which will be eventually - passed to the simulated system (to run a specific benchmark - at bootup). - """ - synthetic = True - benchmark, size = benchmark_name.split("-") - input_file_name = "{}/run_{}_{}".format(dir, benchmark, size) - if synthetic: - with open(input_file_name, "w") as f: - f.write("./{} -g {}\n".format(benchmark, size)) - elif synthetic == 0: - with open(input_file_name, "w") as f: - # The workloads that are copied to the disk image using Packer - # should be located in /home/gem5/. - # Since the command running the workload will be executed with - # pwd = /home/gem5/gapbs, the path to the copied workload is - # ../{workload-name} - f.write("./{} -sf ../{}".format(benchmark, size)) - - return input_file_name - - -supported_protocols = [ - "classic", - "MI_example", - "MESI_Two_Level", - "MOESI_CMP_directory", -] -supported_cpu_types = ["kvm", "atomic", "timing"] - - -def parse_options(): - parser = argparse.ArgumentParser( - description="For use with gem5. This " - "runs a NAS Parallel Benchmark application. This only works " - "with x86 ISA." - ) - - # The manditry position arguments. - parser.add_argument( - "benchmark", - type=str, - choices=benchmark_choices_npb + benchmark_choices_gapbs, - help="The NPB application to run", - ) - parser.add_argument( - "dcache_policy", - type=str, - help="The architecture of DRAM cache: " - "CascadeLakeNoPartWrs, Oracle, BearWriteOpt, Rambus", - ) - parser.add_argument( - "assoc", - type=int, - help="THe associativity of the DRAM cache", - ) - parser.add_argument( - "is_link", - type=int, - help="whether to use a link for backing store or not", - ) - parser.add_argument( - "link_lat", type=str, help="latency of the link to backing store" - ) - parser.add_argument( - "bypass", - type=int, - help="bypass DRAM cache", - ) - parser.add_argument("--do_analysis", action="store_true", default=False) - return parser.parse_args() - - -def do_analysis(): - print( - "**************** Doing analysis! Simulating 100 intervals of 10ms each! ********************\n" - ) - start = time.time() - - for interval_number in range(100): - print(f"Working on interval number: {interval_number}") - exit_event = m5.simulate(10_000_000_000) # 10 ms - m5.stats.dump() - - print( - f"Done with interval {interval_number} at {(time.time() - start)/60:0.2f}" - ) - mostRecentPc = lpmanager.getMostRecentPc() - print(f"Exit because {exit_event.getCause()}, before for") - for pc, tick in mostRecentPc: - count = lpmanager.getPcCount(pc) - print("in for loop") - print(f"{hex(pc)},{count[0]},{count[1]}") - if exit_event.getCause() != "simulate() limit reached": - if ( - exit_event.getCause() == "workend" - or exit_event.getCause() == "workbegin" - ): - print(f"Exit because {exit_event.getCause()}, continuing...") - else: - print(f"Exiting because {exit_event.getCause()}") - break - - -def run(): - print("Simulating 100 intervals of 10ms each! \n") - - for interval_number in range(100): - print("Interval number: {}".format(interval_number)) - exit_event = m5.simulate(10_000_000_000) # 10 ms - # m5.stats.dump() - - if exit_event.getCause() != "simulate() limit reached": - if ( - exit_event.getCause() == "workend" - or exit_event.getCause() == "workbegin" - ): - print("Workload finished, continuing...") - else: - print(f"Exiting because {exit_event.getCause()}") - break - - -if __name__ == "__m5_main__": - args = parse_options() - - kernel = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-linux-kernel-4.19.83" - disk = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-npb" - ckpt_base = "/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/chkpt1GigDC/" - - num_cpus = 8 - cpu_type = "Timing" - mem_sys = "MESI_Two_Level" - - dcache_size = "1GB" - mem_size = "" - checkpoint_dir = "" - - if args.benchmark in benchmark_choices_npb: - if args.benchmark.split(".")[1] == "C": - checkpoint_dir = ( - ckpt_base - + "1GB_8GB_g22_nC_1halfSec/NPB/" - + args.benchmark.split(".")[0] - + "/cpt" - ) - mem_size = "8GiB" - elif args.benchmark.split(".")[1] == "D": - checkpoint_dir = ( - ckpt_base - + "1GB_85GB_g25_nD_1halfSec/NPB/" - + args.benchmark.split(".")[0] - + "/cpt" - ) - mem_size = "85GiB" - else: - if args.benchmark.split("-")[1] == "22": - checkpoint_dir = ( - ckpt_base - + "1GB_8GB_g22_nC_1halfSec/GAPBS/" - + args.benchmark.split("-")[0] - + "/cpt" - ) - mem_size = "8GiB" - elif args.benchmark.split("-")[1] == "25": - checkpoint_dir = ( - ckpt_base - + "1GB_85GB_g25_nD_1halfSec/GAPBS/" - + args.benchmark.split("-")[0] - + "/cpt" - ) - mem_size = "85GiB" - - benchmark = args.benchmark - - system = MyRubySystem( - kernel, - disk, - mem_sys, - num_cpus, - args.assoc, - dcache_size, - mem_size, - args.dcache_policy, - args.is_link, - args.link_lat, - args.bypass, - args, - restore=True, - ) - - if args.do_analysis: - lpmanager = O3LooppointAnalysisManager() - - for core in system.o3Cpu: - lplistener = O3LooppointAnalysis() - lplistener.ptmanager = lpmanager - lplistener.validAddrRangeStart = text_info[args.benchmark][1] - lplistener.validAddrRangeSize = text_info[args.benchmark][0] - core.probeListener = lplistener - else: - pc, count = interval_info_1GBdramCache_3hr[args.benchmark] - system.global_tracker = PcCountTrackerManager( - targets=[PcCountPair(pc, count)] - ) - - for core in system.o3Cpu: - core.core_tracker = PcCountTracker( - targets=[PcCountPair(pc, count)], - core=core, - ptmanager=system.global_tracker, - ) - - system.m5ops_base = 0xFFFF0000 - - # Exit from guest on workbegin/workend - system.exit_on_work_items = True - - # Create and pass a script to the simulated system to run the reuired - # benchmark - if args.benchmark in benchmark_choices_npb: - system.readfile = writeBenchScriptNPB( - m5.options.outdir, args.benchmark - ) - else: - system.readfile = writeBenchScriptGAPBS( - m5.options.outdir, args.benchmark - ) - - # set up the root SimObject and start the simulation - root = Root(full_system=True, system=system) - - if system.getHostParallel(): - # Required for running kvm on multiple host cores. - # Uses gem5's parallel event queue feature - # Note: The simulator is quite picky about this number! - root.sim_quantum = int(1e9) # 1 ms - - # needed for long running jobs - m5.disableAllListeners() - - # instantiate all of the objects we've created above - m5.instantiate(checkpoint_dir) - - print("Running the simulation ************************************** \n") - - if args.do_analysis: - do_analysis() - else: - run() - - print("End of simulation ******************************************** \n") diff --git a/configs-npb-gapbs/system/MESI_Two_Level.py b/configs-npb-gapbs/system/MESI_Two_Level.py deleted file mode 100755 index 8307e74634..0000000000 --- a/configs-npb-gapbs/system/MESI_Two_Level.py +++ /dev/null @@ -1,332 +0,0 @@ -#Copyright (c) 2020 The Regents of the University of California. -#All Rights Reserved -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - - -""" This file creates a set of Ruby caches for the MESI TWO Level protocol -This protocol models two level cache hierarchy. The L1 cache is split into -instruction and data cache. - -This system support the memory size of up to 3GB. - -""" - -import math - -from m5.defines import buildEnv -from m5.util import fatal, panic - -from m5.objects import * - -class MESITwoLevelCache(RubySystem): - - def __init__(self): - if buildEnv['PROTOCOL'] != 'MESI_Two_Level': - fatal("This system assumes MESI_Two_Level!") - - super(MESITwoLevelCache, self).__init__() - - self._numL2Caches = 8 - - def setup(self, system, cpus, mem_ctrls, mem_ranges, dma_ports, iobus): - """Set up the Ruby cache subsystem. Note: This can't be done in the - constructor because many of these items require a pointer to the - ruby system (self). This causes infinite recursion in initialize() - if we do this in the __init__. - """ - # Ruby's global network. - self.network = MyNetwork(self) - - # MESI_Two_Level example uses 5 virtual networks - self.number_of_virtual_networks = 5 - self.network.number_of_virtual_networks = 5 - - # There is a single global list of all of the controllers to make it - # easier to connect everything to the global network. This can be - # customized depending on the topology/network requirements. - # L1 caches are private to a core, hence there are one L1 cache per CPU - # core. The number of L2 caches are dependent to the architecture. - self.controllers = \ - [L1Cache(system, self, cpu, self._numL2Caches) for cpu in cpus] + \ - [L2Cache(system, self, self._numL2Caches) for num in \ - range(self._numL2Caches)] + \ - [DirController(self, rng, mem_ctrl) for rng,mem_ctrl in zip(mem_ranges,mem_ctrls)] + \ - [DMAController(self) for i in range(len(dma_ports))] - - # Create one sequencer per CPU and dma controller. - # Sequencers for other controllers can be here here. - self.sequencers = [RubySequencer(version = i, - # Grab dcache from ctrl - dcache = self.controllers[i].L1Dcache, - clk_domain = self.controllers[i].clk_domain, - pio_request_port = iobus.cpu_side_ports, - mem_request_port = iobus.cpu_side_ports, - pio_response_port = iobus.mem_side_ports - ) for i in range(len(cpus))] + \ - [DMASequencer(version = i, - in_ports = port) - for i,port in enumerate(dma_ports) - ] - - for i,c in enumerate(self.controllers[:len(cpus)]): - c.sequencer = self.sequencers[i] - - #Connecting the DMA sequencer to DMA controller - for i,d in enumerate(self.controllers[-len(dma_ports):]): - i += len(cpus) - d.dma_sequencer = self.sequencers[i] - - self.num_of_sequencers = len(self.sequencers) - - # Create the network and connect the controllers. - # NOTE: This is quite different if using Garnet! - self.network.connectControllers(self.controllers) - self.network.setup_buffers() - - # Set up a proxy port for the system_port. Used for load binaries and - # other functional-only things. - self.sys_port_proxy = RubyPortProxy() - system.system_port = self.sys_port_proxy.in_ports - self.sys_port_proxy.pio_request_port = iobus.cpu_side_ports - - # Connect the cpu's cache, interrupt, and TLB ports to Ruby - for i,cpu in enumerate(cpus): - cpu.icache_port = self.sequencers[i].in_ports - cpu.dcache_port = self.sequencers[i].in_ports - cpu.createInterruptController() - cpu.interrupts[0].pio = self.sequencers[i].interrupt_out_port - cpu.interrupts[0].int_requestor = self.sequencers[i].in_ports - cpu.interrupts[0].int_responder = self.sequencers[i].interrupt_out_port - cpu.mmu.connectWalkerPorts( - self.sequencers[i].in_ports, self.sequencers[i].in_ports) -class L1Cache(L1Cache_Controller): - - _version = 0 - @classmethod - def versionCount(cls): - cls._version += 1 # Use count for this particular type - return cls._version - 1 - - def __init__(self, system, ruby_system, cpu, num_l2Caches): - """Creating L1 cache controller. Consist of both instruction - and data cache. The size of data cache is 512KB and - 8-way set associative. The instruction cache is 32KB, - 2-way set associative. - """ - super(L1Cache, self).__init__() - - self.version = self.versionCount() - block_size_bits = int(math.log(system.cache_line_size, 2)) - l1i_size = '32kB' - l1i_assoc = '2' - l1d_size = '512kB' - l1d_assoc = '8' - # This is the cache memory object that stores the cache data and tags - self.L1Icache = RubyCache(size = l1i_size, - assoc = l1i_assoc, - start_index_bit = block_size_bits , - is_icache = True) - self.L1Dcache = RubyCache(size = l1d_size, - assoc = l1d_assoc, - start_index_bit = block_size_bits, - is_icache = False) - self.l2_select_num_bits = int(math.log(num_l2Caches , 2)) - self.clk_domain = cpu.clk_domain - self.prefetcher = RubyPrefetcher() - self.send_evictions = self.sendEvicts(cpu) - self.transitions_per_cycle = 4 - self.enable_prefetch = False - self.ruby_system = ruby_system - self.connectQueues(ruby_system) - - def getBlockSizeBits(self, system): - bits = int(math.log(system.cache_line_size, 2)) - if 2**bits != system.cache_line_size.value: - panic("Cache line size not a power of 2!") - return bits - - def sendEvicts(self, cpu): - """True if the CPU model or ISA requires sending evictions from caches - to the CPU. Two scenarios warrant forwarding evictions to the CPU: - 1. The O3 model must keep the LSQ coherent with the caches - 2. The x86 mwait instruction is built on top of coherence - 3. The local exclusive monitor in ARM systems - """ - if type(cpu) is X86O3CPU: - return True - return False - - def connectQueues(self, ruby_system): - """Connect all of the queues for this controller. - """ - self.mandatoryQueue = MessageBuffer() - self.requestFromL1Cache = MessageBuffer() - self.requestFromL1Cache.out_port = ruby_system.network.in_port - self.responseFromL1Cache = MessageBuffer() - self.responseFromL1Cache.out_port = ruby_system.network.in_port - self.unblockFromL1Cache = MessageBuffer() - self.unblockFromL1Cache.out_port = ruby_system.network.in_port - - self.optionalQueue = MessageBuffer() - - self.requestToL1Cache = MessageBuffer() - self.requestToL1Cache.in_port = ruby_system.network.out_port - self.responseToL1Cache = MessageBuffer() - self.responseToL1Cache.in_port = ruby_system.network.out_port - -class L2Cache(L2Cache_Controller): - - _version = 0 - @classmethod - def versionCount(cls): - cls._version += 1 # Use count for this particular type - return cls._version - 1 - - def __init__(self, system, ruby_system, num_l2Caches): - - super(L2Cache, self).__init__() - - self.version = self.versionCount() - # This is the cache memory object that stores the cache data and tags - self.L2cache = RubyCache(size = '1 MB', - assoc = 16, - start_index_bit = self.getBlockSizeBits(system, - num_l2Caches)) - - self.transitions_per_cycle = '4' - self.ruby_system = ruby_system - self.connectQueues(ruby_system) - - def getBlockSizeBits(self, system, num_l2caches): - l2_bits = int(math.log(num_l2caches, 2)) - bits = int(math.log(system.cache_line_size, 2)) + l2_bits - return bits - - - def connectQueues(self, ruby_system): - """Connect all of the queues for this controller. - """ - self.DirRequestFromL2Cache = MessageBuffer() - self.DirRequestFromL2Cache.out_port = ruby_system.network.in_port - self.L1RequestFromL2Cache = MessageBuffer() - self.L1RequestFromL2Cache.out_port = ruby_system.network.in_port - self.responseFromL2Cache = MessageBuffer() - self.responseFromL2Cache.out_port = ruby_system.network.in_port - self.unblockToL2Cache = MessageBuffer() - self.unblockToL2Cache.in_port = ruby_system.network.out_port - self.L1RequestToL2Cache = MessageBuffer() - self.L1RequestToL2Cache.in_port = ruby_system.network.out_port - self.responseToL2Cache = MessageBuffer() - self.responseToL2Cache.in_port = ruby_system.network.out_port - - -class DirController(Directory_Controller): - - _version = 0 - @classmethod - def versionCount(cls): - cls._version += 1 # Use count for this particular type - return cls._version - 1 - - def __init__(self, ruby_system, ranges, mem_ctrls): - """ranges are the memory ranges assigned to this controller. - """ - if len(mem_ctrls) > 1: - panic("This cache system can only be connected to one mem ctrl") - super(DirController, self).__init__() - self.version = self.versionCount() - self.addr_ranges = ranges - self.ruby_system = ruby_system - self.directory = RubyDirectoryMemory() - # Connect this directory to the memory side. - self.memory_out_port = mem_ctrls[0].port - self.connectQueues(ruby_system) - - def connectQueues(self, ruby_system): - self.requestToDir = MessageBuffer() - self.requestToDir.in_port = ruby_system.network.out_port - self.responseToDir = MessageBuffer() - self.responseToDir.in_port = ruby_system.network.out_port - self.responseFromDir = MessageBuffer() - self.responseFromDir.out_port = ruby_system.network.in_port - self.requestToMemory = MessageBuffer() - self.responseFromMemory = MessageBuffer() - -class DMAController(DMA_Controller): - - _version = 0 - @classmethod - def versionCount(cls): - cls._version += 1 # Use count for this particular type - return cls._version - 1 - - def __init__(self, ruby_system): - super(DMAController, self).__init__() - self.version = self.versionCount() - self.ruby_system = ruby_system - self.connectQueues(ruby_system) - - def connectQueues(self, ruby_system): - self.mandatoryQueue = MessageBuffer() - self.responseFromDir = MessageBuffer(ordered = True) - self.responseFromDir.in_port = ruby_system.network.out_port - self.requestToDir = MessageBuffer() - self.requestToDir.out_port = ruby_system.network.in_port - - -class MyNetwork(SimpleNetwork): - """A simple point-to-point network. This doesn't not use garnet. - """ - - def __init__(self, ruby_system): - super(MyNetwork, self).__init__() - self.netifs = [] - self.ruby_system = ruby_system - - def connectControllers(self, controllers): - """Connect all of the controllers to routers and connec the routers - together in a point-to-point network. - """ - # Create one router/switch per controller in the system - self.routers = [Switch(router_id = i) for i in range(len(controllers))] - - # Make a link from each controller to the router. The link goes - # externally to the network. - self.ext_links = [SimpleExtLink(link_id=i, ext_node=c, - int_node=self.routers[i]) - for i, c in enumerate(controllers)] - - # Make an "internal" link (internal to the network) between every pair - # of routers. - link_count = 0 - self.int_links = [] - for ri in self.routers: - for rj in self.routers: - if ri == rj: continue # Don't connect a router to itself! - link_count += 1 - self.int_links.append(SimpleIntLink(link_id = link_count, - src_node = ri, - dst_node = rj)) diff --git a/configs-npb-gapbs/system/MI_example_caches.py b/configs-npb-gapbs/system/MI_example_caches.py deleted file mode 100755 index 3c7a71d7b1..0000000000 --- a/configs-npb-gapbs/system/MI_example_caches.py +++ /dev/null @@ -1,275 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2015 Jason Power -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Jason Power - -""" This file creates a set of Ruby caches, the Ruby network, and a simple -point-to-point topology. -See Part 3 in the Learning gem5 book: learning.gem5.org/book/part3 -You can change simple_ruby to import from this file instead of from msi_caches -to use the MI_example protocol instead of MSI. - -IMPORTANT: If you modify this file, it's likely that the Learning gem5 book - also needs to be updated. For now, email Jason - -""" - -import math - -from m5.defines import buildEnv -from m5.util import fatal, panic - -from m5.objects import * - -class MIExampleSystem(RubySystem): - - def __init__(self): - if buildEnv['PROTOCOL'] != 'MI_example': - fatal("This system assumes MI_example!") - - super(MIExampleSystem, self).__init__() - - def setup(self, system, cpus, mem_ctrls, dma_ports, iobus): - """Set up the Ruby cache subsystem. Note: This can't be done in the - constructor because many of these items require a pointer to the - ruby system (self). This causes infinite recursion in initialize() - if we do this in the __init__. - """ - # Ruby's global network. - self.network = MyNetwork(self) - - # MI example uses 5 virtual networks - self.number_of_virtual_networks = 5 - self.network.number_of_virtual_networks = 5 - - # There is a single global list of all of the controllers to make it - # easier to connect everything to the global network. This can be - # customized depending on the topology/network requirements. - # Create one controller for each L1 cache (and the cache mem obj.) - # Create a single directory controller (Really the memory cntrl) - self.controllers = \ - [L1Cache(system, self, cpu) for cpu in cpus] + \ - [DirController(self, system.mem_ranges, mem_ctrls)] + \ - [DMAController(self) for i in range(len(dma_ports))] - - # Create one sequencer per CPU. In many systems this is more - # complicated since you have to create sequencers for DMA controllers - # and other controllers, too. - self.sequencers = [RubySequencer(version = i, - # Grab dcache from ctrl - dcache = self.controllers[i].cacheMemory, - clk_domain = self.controllers[i].clk_domain, - pio_request_port = iobus.cpu_side_ports, - mem_request_port = iobus.cpu_side_ports, - pio_response_port = iobus.mem_side_ports - ) for i in range(len(cpus))] + \ - [DMASequencer(version = i, - in_ports = port) - for i,port in enumerate(dma_ports) - ] - - for i,c in enumerate(self.controllers[0:len(cpus)]): - c.sequencer = self.sequencers[i] - - for i,d in enumerate(self.controllers[-len(dma_ports):]): - i += len(cpus) - d.dma_sequencer = self.sequencers[i] - - self.num_of_sequencers = len(self.sequencers) - - # Create the network and connect the controllers. - # NOTE: This is quite different if using Garnet! - self.network.connectControllers(self.controllers) - self.network.setup_buffers() - - # Set up a proxy port for the system_port. Used for load binaries and - # other functional-only things. - self.sys_port_proxy = RubyPortProxy() - system.system_port = self.sys_port_proxy.in_ports - self.sys_port_proxy.pio_request_port = iobus.cpu_side_ports - - # Connect the cpu's cache, interrupt, and TLB ports to Ruby - for i,cpu in enumerate(cpus): - cpu.icache_port = self.sequencers[i].in_ports - cpu.dcache_port = self.sequencers[i].in_ports - cpu.createInterruptController() - isa = buildEnv['TARGET_ISA'] - if isa == 'x86': - cpu.interrupts[0].pio = self.sequencers[i].interrupt_out_port - cpu.interrupts[0].int_requestor = self.sequencers[i].in_ports - cpu.interrupts[0].int_responder = self.sequencers[i].interrupt_out_port - if isa == 'x86' or isa == 'arm': - cpu.mmu.connectWalkerPorts( - self.sequencers[i].in_ports, self.sequencers[i].in_ports) - -class L1Cache(L1Cache_Controller): - - _version = 0 - @classmethod - def versionCount(cls): - cls._version += 1 # Use count for this particular type - return cls._version - 1 - - def __init__(self, system, ruby_system, cpu): - """CPUs are needed to grab the clock domain and system is needed for - the cache block size. - """ - super(L1Cache, self).__init__() - - self.version = self.versionCount() - # This is the cache memory object that stores the cache data and tags - self.cacheMemory = RubyCache(size = '16kB', - assoc = 8, - start_index_bit = self.getBlockSizeBits(system)) - self.clk_domain = cpu.clk_domain - self.send_evictions = self.sendEvicts(cpu) - self.ruby_system = ruby_system - self.connectQueues(ruby_system) - - def getBlockSizeBits(self, system): - bits = int(math.log(system.cache_line_size, 2)) - if 2**bits != system.cache_line_size.value: - panic("Cache line size not a power of 2!") - return bits - - def sendEvicts(self, cpu): - """True if the CPU model or ISA requires sending evictions from caches - to the CPU. Two scenarios warrant forwarding evictions to the CPU: - 1. The O3 model must keep the LSQ coherent with the caches - 2. The x86 mwait instruction is built on top of coherence - 3. The local exclusive monitor in ARM systems - """ - if type(cpu) is DerivO3CPU or \ - buildEnv['TARGET_ISA'] in ('x86', 'arm'): - return True - return False - - def connectQueues(self, ruby_system): - """Connect all of the queues for this controller. - """ - self.mandatoryQueue = MessageBuffer() - self.requestFromCache = MessageBuffer(ordered = True) - self.requestFromCache.out_port = ruby_system.network.in_port - self.responseFromCache = MessageBuffer(ordered = True) - self.responseFromCache.out_port = ruby_system.network.in_port - self.forwardToCache = MessageBuffer(ordered = True) - self.forwardToCache.in_port = ruby_system.network.out_port - self.responseToCache = MessageBuffer(ordered = True) - self.responseToCache.in_port = ruby_system.network.out_port - -class DirController(Directory_Controller): - - _version = 0 - @classmethod - def versionCount(cls): - cls._version += 1 # Use count for this particular type - return cls._version - 1 - - def __init__(self, ruby_system, ranges, mem_ctrls): - """ranges are the memory ranges assigned to this controller. - """ - if len(mem_ctrls) > 1: - panic("This cache system can only be connected to one mem ctrl") - super(DirController, self).__init__() - self.version = self.versionCount() - self.addr_ranges = ranges - self.ruby_system = ruby_system - self.directory = RubyDirectoryMemory() - # Connect this directory to the memory side. - self.memory_out_port = mem_ctrls[0].port - self.connectQueues(ruby_system) - - def connectQueues(self, ruby_system): - self.requestToDir = MessageBuffer(ordered = True) - self.requestToDir.in_port = ruby_system.network.out_port - self.dmaRequestToDir = MessageBuffer(ordered = True) - self.dmaRequestToDir.in_port = ruby_system.network.out_port - - self.responseFromDir = MessageBuffer() - self.responseFromDir.out_port = ruby_system.network.in_port - self.dmaResponseFromDir = MessageBuffer(ordered = True) - self.dmaResponseFromDir.out_port = ruby_system.network.in_port - self.forwardFromDir = MessageBuffer() - self.forwardFromDir.out_port = ruby_system.network.in_port - self.requestToMemory = MessageBuffer() - self.responseFromMemory = MessageBuffer() - -class DMAController(DMA_Controller): - - _version = 0 - @classmethod - def versionCount(cls): - cls._version += 1 # Use count for this particular type - return cls._version - 1 - - def __init__(self, ruby_system): - super(DMAController, self).__init__() - self.version = self.versionCount() - self.ruby_system = ruby_system - self.connectQueues(ruby_system) - - def connectQueues(self, ruby_system): - self.mandatoryQueue = MessageBuffer() - self.requestToDir = MessageBuffer() - self.requestToDir.out_port = ruby_system.network.in_port - self.responseFromDir = MessageBuffer(ordered = True) - self.responseFromDir.in_port = ruby_system.network.out_port - - -class MyNetwork(SimpleNetwork): - """A simple point-to-point network. This doesn't not use garnet. - """ - - def __init__(self, ruby_system): - super(MyNetwork, self).__init__() - self.netifs = [] - self.ruby_system = ruby_system - - def connectControllers(self, controllers): - """Connect all of the controllers to routers and connec the routers - together in a point-to-point network. - """ - # Create one router/switch per controller in the system - self.routers = [Switch(router_id = i) for i in range(len(controllers))] - - # Make a link from each controller to the router. The link goes - # externally to the network. - self.ext_links = [SimpleExtLink(link_id=i, ext_node=c, - int_node=self.routers[i]) - for i, c in enumerate(controllers)] - - # Make an "internal" link (internal to the network) between every pair - # of routers. - link_count = 0 - self.int_links = [] - for ri in self.routers: - for rj in self.routers: - if ri == rj: continue # Don't connect a router to itself! - link_count += 1 - self.int_links.append(SimpleIntLink(link_id = link_count, - src_node = ri, - dst_node = rj)) diff --git a/configs-npb-gapbs/system/MOESI_CMP_directory.py b/configs-npb-gapbs/system/MOESI_CMP_directory.py deleted file mode 100755 index 33f9f47e74..0000000000 --- a/configs-npb-gapbs/system/MOESI_CMP_directory.py +++ /dev/null @@ -1,350 +0,0 @@ -#Copyright (c) 2020 The Regents of the University of California. -#All Rights Reserved -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - - -""" This file creates a set of Ruby caches for the MOESI CMP directory -protocol. -This protocol models two level cache hierarchy. The L1 cache is split into -instruction and data cache. - -This system support the memory size of up to 3GB. - -""" - -from __future__ import print_function -from __future__ import absolute_import - -import math - -from m5.defines import buildEnv -from m5.util import fatal, panic - -from m5.objects import * - -class MOESICMPDirCache(RubySystem): - - def __init__(self): - if buildEnv['PROTOCOL'] != 'MOESI_CMP_directory': - fatal("This system assumes MOESI_CMP_directory!") - - super(MOESICMPDirCache, self).__init__() - - self._numL2Caches = 8 - - def setup(self, system, cpus, mem_ctrls, dma_ports, iobus): - """Set up the Ruby cache subsystem. Note: This can't be done in the - constructor because many of these items require a pointer to the - ruby system (self). This causes infinite recursion in initialize() - if we do this in the __init__. - """ - # Ruby's global network. - self.network = MyNetwork(self) - - # MOESI_CMP_directory example uses 3 virtual networks - self.number_of_virtual_networks = 3 - self.network.number_of_virtual_networks = 3 - - # There is a single global list of all of the controllers to make it - # easier to connect everything to the global network. This can be - # customized depending on the topology/network requirements. - # L1 caches are private to a core, hence there are one L1 cache per CPU - # core. The number of L2 caches are dependent to the architecture. - self.controllers = \ - [L1Cache(system, self, cpu, self._numL2Caches) for cpu in cpus] + \ - [L2Cache(system, self, self._numL2Caches) for num in \ - range(self._numL2Caches)] + [DirController(self, \ - system.mem_ranges, mem_ctrls)] + [DMAController(self) for i \ - in range(len(dma_ports))] - - # Create one sequencer per CPU and dma controller. - # Sequencers for other controllers can be here here. - self.sequencers = [RubySequencer(version = i, - # Grab dcache from ctrl - dcache = self.controllers[i].L1Dcache, - clk_domain = self.controllers[i].clk_domain, - pio_request_port = iobus.cpu_side_ports, - mem_request_port = iobus.cpu_side_ports, - pio_response_port = iobus.mem_side_ports - ) for i in range(len(cpus))] + \ - [DMASequencer(version = i, - in_ports = port) - for i,port in enumerate(dma_ports) - ] - - for i,c in enumerate(self.controllers[:len(cpus)]): - c.sequencer = self.sequencers[i] - - #Connecting the DMA sequencer to DMA controller - for i,d in enumerate(self.controllers[-len(dma_ports):]): - i += len(cpus) - d.dma_sequencer = self.sequencers[i] - - self.num_of_sequencers = len(self.sequencers) - - # Create the network and connect the controllers. - # NOTE: This is quite different if using Garnet! - self.network.connectControllers(self.controllers) - self.network.setup_buffers() - - # Set up a proxy port for the system_port. Used for load binaries and - # other functional-only things. - self.sys_port_proxy = RubyPortProxy() - system.system_port = self.sys_port_proxy.in_ports - self.sys_port_proxy.pio_request_port = iobus.cpu_side_ports - - # Connect the cpu's cache, interrupt, and TLB ports to Ruby - for i,cpu in enumerate(cpus): - cpu.icache_port = self.sequencers[i].in_ports - cpu.dcache_port = self.sequencers[i].in_ports - cpu.createInterruptController() - isa = buildEnv['TARGET_ISA'] - if isa == 'x86': - cpu.interrupts[0].pio = self.sequencers[i].interrupt_out_port - cpu.interrupts[0].int_requestor = self.sequencers[i].in_ports - cpu.interrupts[0].int_responder = self.sequencers[i].interrupt_out_port - if isa == 'x86' or isa == 'arm': - cpu.mmu.connectWalkerPorts( - self.sequencers[i].in_ports, self.sequencers[i].in_ports) - -class L1Cache(L1Cache_Controller): - - _version = 0 - @classmethod - def versionCount(cls): - cls._version += 1 # Use count for this particular type - return cls._version - 1 - - def __init__(self, system, ruby_system, cpu, num_l2Caches): - """Creating L1 cache controller. Consist of both instruction - and data cache. The size of data cache is 512KB and - 8-way set associative. The instruction cache is 32KB, - 2-way set associative. - """ - super(L1Cache, self).__init__() - - self.version = self.versionCount() - block_size_bits = int(math.log(system.cache_line_size, 2)) - l1i_size = '32kB' - l1i_assoc = '2' - l1d_size = '512kB' - l1d_assoc = '8' - # This is the cache memory object that stores the cache data and tags - self.L1Icache = RubyCache(size = l1i_size, - assoc = l1i_assoc, - start_index_bit = block_size_bits , - is_icache = True, - dataAccessLatency = 1, - tagAccessLatency = 1) - self.L1Dcache = RubyCache(size = l1d_size, - assoc = l1d_assoc, - start_index_bit = block_size_bits, - is_icache = False, - dataAccessLatency = 1, - tagAccessLatency = 1) - self.clk_domain = cpu.clk_domain - self.prefetcher = RubyPrefetcher() - self.send_evictions = self.sendEvicts(cpu) - self.transitions_per_cycle = 4 - self.ruby_system = ruby_system - self.connectQueues(ruby_system) - - def getBlockSizeBits(self, system): - bits = int(math.log(system.cache_line_size, 2)) - if 2**bits != system.cache_line_size.value: - panic("Cache line size not a power of 2!") - return bits - - def sendEvicts(self, cpu): - """True if the CPU model or ISA requires sending evictions from caches - to the CPU. Two scenarios warrant forwarding evictions to the CPU: - 1. The O3 model must keep the LSQ coherent with the caches - 2. The x86 mwait instruction is built on top of coherence - 3. The local exclusive monitor in ARM systems - """ - if type(cpu) is DerivO3CPU or \ - buildEnv['TARGET_ISA'] in ('x86', 'arm'): - return True - return False - - def connectQueues(self, ruby_system): - """Connect all of the queues for this controller. - """ - self.mandatoryQueue = MessageBuffer() - self.requestFromL1Cache = MessageBuffer() - self.requestFromL1Cache.out_port = ruby_system.network.in_port - self.responseFromL1Cache = MessageBuffer() - self.responseFromL1Cache.out_port = ruby_system.network.in_port - self.requestToL1Cache = MessageBuffer() - self.requestToL1Cache.in_port = ruby_system.network.out_port - self.responseToL1Cache = MessageBuffer() - self.responseToL1Cache.in_port = ruby_system.network.out_port - self.triggerQueue = MessageBuffer(ordered = True) - -class L2Cache(L2Cache_Controller): - - _version = 0 - @classmethod - def versionCount(cls): - cls._version += 1 # Use count for this particular type - return cls._version - 1 - - def __init__(self, system, ruby_system, num_l2Caches): - - super(L2Cache, self).__init__() - - self.version = self.versionCount() - # This is the cache memory object that stores the cache data and tags - self.L2cache = RubyCache(size = '1 MB', - assoc = 16, - start_index_bit = self.getL2StartIdx(system, - num_l2Caches), - dataAccessLatency = 20, - tagAccessLatency = 20) - - self.transitions_per_cycle = '4' - self.ruby_system = ruby_system - self.connectQueues(ruby_system) - - def getL2StartIdx(self, system, num_l2caches): - l2_bits = int(math.log(num_l2caches, 2)) - bits = int(math.log(system.cache_line_size, 2)) + l2_bits - return bits - - - def connectQueues(self, ruby_system): - """Connect all of the queues for this controller. - """ - self.GlobalRequestFromL2Cache = MessageBuffer() - self.GlobalRequestFromL2Cache.out_port = ruby_system.network.in_port - self.L1RequestFromL2Cache = MessageBuffer() - self.L1RequestFromL2Cache.out_port = ruby_system.network.in_port - self.responseFromL2Cache = MessageBuffer() - self.responseFromL2Cache.out_port = ruby_system.network.in_port - - self.GlobalRequestToL2Cache = MessageBuffer() - self.GlobalRequestToL2Cache.in_port = ruby_system.network.out_port - self.L1RequestToL2Cache = MessageBuffer() - self.L1RequestToL2Cache.in_port = ruby_system.network.out_port - self.responseToL2Cache = MessageBuffer() - self.responseToL2Cache.in_port = ruby_system.network.out_port - self.triggerQueue = MessageBuffer(ordered = True) - - - -class DirController(Directory_Controller): - - _version = 0 - @classmethod - def versionCount(cls): - cls._version += 1 # Use count for this particular type - return cls._version - 1 - - def __init__(self, ruby_system, ranges, mem_ctrls): - """ranges are the memory ranges assigned to this controller. - """ - if len(mem_ctrls) > 1: - panic("This cache system can only be connected to one mem ctrl") - super(DirController, self).__init__() - self.version = self.versionCount() - self.addr_ranges = ranges - self.ruby_system = ruby_system - self.directory = RubyDirectoryMemory() - # Connect this directory to the memory side. - self.memory_out_port = mem_ctrls[0].port - self.connectQueues(ruby_system) - - def connectQueues(self, ruby_system): - self.requestToDir = MessageBuffer() - self.requestToDir.in_port = ruby_system.network.out_port - self.responseToDir = MessageBuffer() - self.responseToDir.in_port = ruby_system.network.out_port - self.responseFromDir = MessageBuffer() - self.responseFromDir.out_port = ruby_system.network.in_port - self.forwardFromDir = MessageBuffer() - self.forwardFromDir.out_port = ruby_system.network.in_port - self.requestToMemory = MessageBuffer() - self.responseFromMemory = MessageBuffer() - self.triggerQueue = MessageBuffer(ordered = True) - -class DMAController(DMA_Controller): - - _version = 0 - @classmethod - def versionCount(cls): - cls._version += 1 # Use count for this particular type - return cls._version - 1 - - def __init__(self, ruby_system): - super(DMAController, self).__init__() - self.version = self.versionCount() - self.ruby_system = ruby_system - self.connectQueues(ruby_system) - - def connectQueues(self, ruby_system): - self.mandatoryQueue = MessageBuffer() - self.responseFromDir = MessageBuffer() - self.responseFromDir.in_port = ruby_system.network.out_port - self.reqToDir = MessageBuffer() - self.reqToDir.out_port = ruby_system.network.in_port - self.respToDir = MessageBuffer() - self.respToDir.out_port = ruby_system.network.in_port - self.triggerQueue = MessageBuffer(ordered = True) - - -class MyNetwork(SimpleNetwork): - """A simple point-to-point network. This doesn't not use garnet. - """ - - def __init__(self, ruby_system): - super(MyNetwork, self).__init__() - self.netifs = [] - self.ruby_system = ruby_system - - def connectControllers(self, controllers): - """Connect all of the controllers to routers and connec the routers - together in a point-to-point network. - """ - # Create one router/switch per controller in the system - self.routers = [Switch(router_id = i) for i in range(len(controllers))] - - # Make a link from each controller to the router. The link goes - # externally to the network. - self.ext_links = [SimpleExtLink(link_id=i, ext_node=c, - int_node=self.routers[i]) - for i, c in enumerate(controllers)] - - # Make an "internal" link (internal to the network) between every pair - # of routers. - link_count = 0 - self.int_links = [] - for ri in self.routers: - for rj in self.routers: - if ri == rj: continue # Don't connect a router to itself! - link_count += 1 - self.int_links.append(SimpleIntLink(link_id = link_count, - src_node = ri, - dst_node = rj)) diff --git a/configs-npb-gapbs/system/caches.py b/configs-npb-gapbs/system/caches.py deleted file mode 100755 index 9e44211111..0000000000 --- a/configs-npb-gapbs/system/caches.py +++ /dev/null @@ -1,173 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2016 Jason Lowe-Power -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Jason Lowe-Power - -""" Caches with options for a simple gem5 configuration script - -This file contains L1 I/D and L2 caches to be used in the simple -gem5 configuration script. -""" - -from m5.objects import Cache, L2XBar, StridePrefetcher - -# Some specific options for caches -# For all options see src/mem/cache/BaseCache.py - -class PrefetchCache(Cache): - - def __init__(self, options): - super(PrefetchCache, self).__init__() - if not options or options.no_prefetchers: - return - self.prefetcher = StridePrefetcher() - -class L1Cache(PrefetchCache): - """Simple L1 Cache with default values""" - - assoc = 8 - tag_latency = 1 - data_latency = 1 - response_latency = 1 - mshrs = 16 - tgts_per_mshr = 20 - writeback_clean = True - - def __init__(self, options=None): - super(L1Cache, self).__init__(options) - pass - - def connectBus(self, bus): - """Connect this cache to a memory-side bus""" - self.mem_side = bus.cpu_side_ports - - def connectCPU(self, cpu): - """Connect this cache's port to a CPU-side port - This must be defined in a subclass""" - raise NotImplementedError - -class L1ICache(L1Cache): - """Simple L1 instruction cache with default values""" - - def __init__(self, opts=None): - super(L1ICache, self).__init__(opts) - if not opts or not opts.l1i_size: - return - self.size = opts.l1i_size - - def connectCPU(self, cpu): - """Connect this cache's port to a CPU icache port""" - self.cpu_side = cpu.icache_port - -class L1DCache(L1Cache): - """Simple L1 data cache with default values""" - - def __init__(self, opts=None): - super(L1DCache, self).__init__(opts) - if not opts or not opts.l1d_size: - return - self.size = opts.l1d_size - - def connectCPU(self, cpu): - """Connect this cache's port to a CPU dcache port""" - self.cpu_side = cpu.dcache_port - -class MMUCache(Cache): - # Default parameters - size = '8kB' - assoc = 4 - tag_latency = 1 - data_latency = 1 - response_latency = 1 - mshrs = 20 - tgts_per_mshr = 12 - writeback_clean = True - - def __init__(self): - super(MMUCache, self).__init__() - - def connectCPU(self, cpu): - """Connect the CPU itb and dtb to the cache - Note: This creates a new crossbar - """ - self.mmubus = L2XBar() - self.cpu_side = self.mmubus.mem_side_ports - cpu.mmu.connectWalkerPorts( - self.mmubus.cpu_side_ports, self.mmubus.cpu_side_ports) - - def connectBus(self, bus): - """Connect this cache to a memory-side bus""" - self.mem_side = bus.cpu_side_ports - -class L2Cache(PrefetchCache): - """Simple L2 Cache with default values""" - - # Default parameters - assoc = 16 - tag_latency = 10 - data_latency = 10 - response_latency = 1 - mshrs = 20 - tgts_per_mshr = 12 - writeback_clean = True - - def __init__(self, opts=None): - super(L2Cache, self).__init__(opts) - if not opts or not opts.l2_size: - return - self.size = opts.l2_size - - def connectCPUSideBus(self, bus): - self.cpu_side = bus.mem_side_ports - - def connectMemSideBus(self, bus): - self.mem_side = bus.cpu_side_ports - -class L3Cache(Cache): - """Simple L3 Cache bank with default values - This assumes that the L3 is made up of multiple banks. This cannot - be used as a standalone L3 cache. - """ - - # Default parameters - assoc = 32 - tag_latency = 40 - data_latency = 40 - response_latency = 10 - mshrs = 256 - tgts_per_mshr = 12 - clusivity = 'mostly_excl' - - def __init__(self, opts): - super(L3Cache, self).__init__() - self.size = (opts.l3_size) - - def connectCPUSideBus(self, bus): - self.cpu_side = bus.mem_side_ports - - def connectMemSideBus(self, bus): - self.mem_side = bus.cpu_side_ports diff --git a/configs-npb-gapbs/system/fs_tools.py b/configs-npb-gapbs/system/fs_tools.py deleted file mode 100755 index 5e5e2df6e4..0000000000 --- a/configs-npb-gapbs/system/fs_tools.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2016 Jason Lowe-Power -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Jason Lowe-Power - -from m5.objects import IdeDisk, CowDiskImage, RawDiskImage - -class CowDisk(IdeDisk): - - def __init__(self, filename): - super(CowDisk, self).__init__() - self.driveID = 'device0' - self.image = CowDiskImage(child=RawDiskImage(read_only=True), - read_only=False) - self.image.child.image_file = filename diff --git a/configs-npb-gapbs/system/system.py b/configs-npb-gapbs/system/system.py deleted file mode 100755 index 6365b39d63..0000000000 --- a/configs-npb-gapbs/system/system.py +++ /dev/null @@ -1,414 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018 The Regents of the University of California -# All Rights Reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Jason Lowe-Power - -import m5 -from m5.objects import * -from .fs_tools import * -from .caches import * - - -class MySystem(System): - - def __init__(self, kernel, disk, num_cpus, opts, no_kvm=False): - super(MySystem, self).__init__() - self._opts = opts - self._no_kvm = no_kvm - - self._host_parallel = not self._opts.no_host_parallel - - # Set up the clock domain and the voltage domain - self.clk_domain = SrcClockDomain() - self.clk_domain.clock = '2.3GHz' - self.clk_domain.voltage_domain = VoltageDomain() - - #mem_size = '32GB' - #self.mem_ranges = [AddrRange('100MB'), # For kernel - # AddrRange(0xC0000000, size=0x100000), # For I/0 - # AddrRange(Addr('4GB'), size = mem_size) # All data - # ] - - - self.mem_ranges = [AddrRange(Addr('2GiB')), # All data - AddrRange(0xC0000000, size=0x100000), # For I/0 - ] - - # Create the main memory bus - # This connects to main memory - self.membus = SystemXBar(width = 64) # 64-byte width - self.membus.badaddr_responder = BadAddr() - self.membus.default = Self.badaddr_responder.pio - - # Set up the system port for functional access from the simulator - self.system_port = self.membus.cpu_side_ports - - self.initFS(self.membus, num_cpus) - - - # Replace these paths with the path to your disk images. - # The first disk is the root disk. The second could be used for swap - # or anything else. - - self.setDiskImages(disk, disk) - - if opts.second_disk: - self.setDiskImages(disk, opts.second_disk) - else: - self.setDiskImages(disk, disk) - - # Change this path to point to the kernel you want to use - self.workload.object_file = kernel - # Options specified on the kernel command line - boot_options = ['earlyprintk=ttyS0', 'console=ttyS0', 'lpj=7999923', - 'root=/dev/hda1'] - - self.workload.command_line = ' '.join(boot_options) - - # Create the CPUs for our system. - self.createCPU(num_cpus) - - # Create the cache heirarchy for the system. - self.createCacheHierarchy() - - # Set up the interrupt controllers for the system (x86 specific) - self.setupInterrupts() - - # self.intrctrl = IntrControl() - - self.createMemoryControllersDDR4() - - if self._host_parallel: - # To get the KVM CPUs to run on different host CPUs - # Specify a different event queue for each CPU - for i,cpu in enumerate(self.cpu): - for obj in cpu.descendants(): - obj.eventq_index = 0 - - # the number of eventqs are set based - # on experiments with few benchmarks - - if len(self.cpu) > 16: - cpu.eventq_index = (i/4) + 1 - else: - cpu.eventq_index = (i/2) + 1 - def getHostParallel(self): - return self._host_parallel - - def totalInsts(self): - return sum([cpu.totalInsts() for cpu in self.cpu]) - - def createCPUThreads(self, cpu): - for c in cpu: - c.createThreads() - - def createCPU(self, num_cpus): - if self._no_kvm: - self.cpu = [AtomicSimpleCPU(cpu_id = i, switched_out = False) - for i in range(num_cpus)] - self.createCPUThreads(self.cpu) - self.mem_mode = 'timing' - - else: - # Note KVM needs a VM and atomic_noncaching - self.cpu = [X86KvmCPU(cpu_id = i) - for i in range(num_cpus)] - self.createCPUThreads(self.cpu) - self.kvm_vm = KvmVM() - self.mem_mode = 'atomic_noncaching' - - self.atomicCpu = [AtomicSimpleCPU(cpu_id = i, - switched_out = True) - for i in range(num_cpus)] - self.createCPUThreads(self.atomicCpu) - - self.timingCpu = [TimingSimpleCPU(cpu_id = i, - switched_out = True) - for i in range(num_cpus)] - - self.createCPUThreads(self.timingCpu) - - def switchCpus(self, old, new): - assert(new[0].switchedOut()) - m5.switchCpus(self, list(zip(old, new))) - - def setDiskImages(self, img_path_1, img_path_2): - disk0 = CowDisk(img_path_1) - disk2 = CowDisk(img_path_2) - self.pc.south_bridge.ide.disks = [disk0, disk2] - - def createCacheHierarchy(self): - # Create an L3 cache (with crossbar) - self.l3bus = L2XBar(width = 64, - snoop_filter = SnoopFilter(max_capacity='32MB')) - - for cpu in self.cpu: - # Create a memory bus, a coherent crossbar, in this case - cpu.l2bus = L2XBar() - - # Create an L1 instruction and data cache - cpu.icache = L1ICache(self._opts) - cpu.dcache = L1DCache(self._opts) - cpu.mmucache = MMUCache() - - # Connect the instruction and data caches to the CPU - cpu.icache.connectCPU(cpu) - cpu.dcache.connectCPU(cpu) - cpu.mmucache.connectCPU(cpu) - - # Hook the CPU ports up to the l2bus - cpu.icache.connectBus(cpu.l2bus) - cpu.dcache.connectBus(cpu.l2bus) - cpu.mmucache.connectBus(cpu.l2bus) - - # Create an L2 cache and connect it to the l2bus - cpu.l2cache = L2Cache(self._opts) - cpu.l2cache.connectCPUSideBus(cpu.l2bus) - - # Connect the L2 cache to the L3 bus - cpu.l2cache.connectMemSideBus(self.l3bus) - - self.l3cache = L3Cache(self._opts) - self.l3cache.connectCPUSideBus(self.l3bus) - - # Connect the L3 cache to the membus - self.l3cache.connectMemSideBus(self.membus) - - def setupInterrupts(self): - for cpu in self.cpu: - # create the interrupt controller CPU and connect to the membus - cpu.createInterruptController() - - # For x86 only, connect interrupts to the memory - # Note: these are directly connected to the memory bus and - # not cached - cpu.interrupts[0].pio = self.membus.mem_side_ports - cpu.interrupts[0].int_requestor = self.membus.cpu_side_ports - cpu.interrupts[0].int_responder = self.membus.mem_side_ports - - # Memory latency: Using the smaller number from [3]: 96ns - def createMemoryControllersDDR4(self): - self._createMemoryControllers(1, DDR4_2400_16x4) - - def _createMemoryControllers(self, num, cls): - - self.mem_ctrl = PolicyManager(range=self.mem_ranges[0]) - # FOR DDR4 - # self.mem_ctrl.tRP = '14.16ns' - # self.mem_ctrl.tRCD_RD = '14.16ns' - # self.mem_ctrl.tRL = '14.16ns' - - # self.loc_mem_ctrl = HBMCtrl() - # self.loc_mem_ctrl.dram = HBM_2000_4H_1x64(range=AddrRange(start = '0', end = '1GiB', masks = [1 << 6], intlvMatch = 0), in_addr_map=False, kvm_map=False, null=True) - # self.loc_mem_ctrl.dram_2 = HBM_2000_4H_1x64(range=AddrRange(start = '0', end = '1GiB', masks = [1 << 6], intlvMatch = 1), in_addr_map=False, kvm_map=False, null=True) - - self.loc_mem_ctrl = MemCtrl() - self.loc_mem_ctrl.dram = DDR4_2400_16x4(range=self.mem_ranges[0], in_addr_map=False, kvm_map=False) - - self.far_mem_ctrl = MemCtrl() - self.far_mem_ctrl.dram = DDR4_2400_16x4(range=self.mem_ranges[0], in_addr_map=False, kvm_map=False) - - self.loc_mem_ctrl.port = self.mem_ctrl.loc_req_port - self.far_mem_ctrl.port = self.mem_ctrl.far_req_port - - self.mem_ctrl.dram_cache_size = "128MiB" - - # self.mem_ctrl = MemCtrl() - # self.mem_ctrl.dram = DDR4_2400_16x4(range=self.mem_ranges[0]) - - def _createKernelMemoryController(self, cls): - return MemCtrl(dram = cls(range = self.mem_ranges[0]), - port = self.membus.mem_side_ports) - - def _getInterleaveRanges(self, rng, num, intlv_low_bit, xor_low_bit): - from math import log - bits = int(log(num, 2)) - if 2**bits != num: - m5.fatal("Non-power of two number of memory controllers") - - intlv_bits = bits - ranges = [ - AddrRange(start=rng.start, - end=rng.end, - intlvHighBit = intlv_low_bit + intlv_bits - 1, - xorHighBit = xor_low_bit + intlv_bits - 1, - intlvBits = intlv_bits, - intlvMatch = i) - for i in range(num) - ] - - return ranges - - def initFS(self, membus, cpus): - self.pc = Pc() - self.workload = X86FsLinux() - - # Constants similar to x86_traits.hh - IO_address_space_base = 0x8000000000000000 - pci_config_address_space_base = 0xc000000000000000 - interrupts_address_space_base = 0xa000000000000000 - APIC_range_size = 1 << 12 - - # North Bridge - self.iobus = IOXBar() - self.bridge = Bridge(delay='50ns') - self.bridge.mem_side_port = self.iobus.cpu_side_ports - self.bridge.cpu_side_port = membus.mem_side_ports - # Allow the bridge to pass through: - # 1) kernel configured PCI device memory map address: address range - # [0xC0000000, 0xFFFF0000). (The upper 64kB are reserved for m5ops.) - # 2) the bridge to pass through the IO APIC (two pages, already - # contained in 1), - # 3) everything in the IO address range up to the local APIC, and - # 4) then the entire PCI address space and beyond. - self.bridge.ranges = \ - [ - AddrRange(0xC0000000, 0xFFFF0000), - AddrRange(IO_address_space_base, - interrupts_address_space_base - 1), - AddrRange(pci_config_address_space_base, - Addr.max) - ] - - # Create a bridge from the IO bus to the memory bus to allow access - # to the local APIC (two pages) - self.apicbridge = Bridge(delay='50ns') - self.apicbridge.cpu_side_port = self.iobus.mem_side_ports - self.apicbridge.mem_side_port = membus.cpu_side_ports - self.apicbridge.ranges = [AddrRange(interrupts_address_space_base, - interrupts_address_space_base + - cpus * APIC_range_size - - 1)] - - # connect the io bus - self.pc.attachIO(self.iobus) - - # Add a tiny cache to the IO bus. - # This cache is required for the classic memory model for coherence - self.iocache = Cache(assoc=8, - tag_latency = 50, - data_latency = 50, - response_latency = 50, - mshrs = 20, - size = '1kB', - tgts_per_mshr = 12, - addr_ranges = self.mem_ranges) - self.iocache.cpu_side = self.iobus.mem_side_ports - self.iocache.mem_side = self.membus.cpu_side_ports - - ############################################### - - # Add in a Bios information structure. - self.workload.smbios_table.structures = [X86SMBiosBiosInformation()] - - # Set up the Intel MP table - base_entries = [] - ext_entries = [] - for i in range(cpus): - bp = X86IntelMPProcessor( - local_apic_id = i, - local_apic_version = 0x14, - enable = True, - bootstrap = (i ==0)) - base_entries.append(bp) - io_apic = X86IntelMPIOAPIC( - id = cpus, - version = 0x11, - enable = True, - address = 0xfec00000) - self.pc.south_bridge.io_apic.apic_id = io_apic.id - base_entries.append(io_apic) - pci_bus = X86IntelMPBus(bus_id = 0, bus_type='PCI ') - base_entries.append(pci_bus) - isa_bus = X86IntelMPBus(bus_id = 1, bus_type='ISA ') - base_entries.append(isa_bus) - connect_busses = X86IntelMPBusHierarchy(bus_id=1, - subtractive_decode=True, parent_bus=0) - ext_entries.append(connect_busses) - pci_dev4_inta = X86IntelMPIOIntAssignment( - interrupt_type = 'INT', - polarity = 'ConformPolarity', - trigger = 'ConformTrigger', - source_bus_id = 0, - source_bus_irq = 0 + (4 << 2), - dest_io_apic_id = io_apic.id, - dest_io_apic_intin = 16) - base_entries.append(pci_dev4_inta) - def assignISAInt(irq, apicPin): - assign_8259_to_apic = X86IntelMPIOIntAssignment( - interrupt_type = 'ExtInt', - polarity = 'ConformPolarity', - trigger = 'ConformTrigger', - source_bus_id = 1, - source_bus_irq = irq, - dest_io_apic_id = io_apic.id, - dest_io_apic_intin = 0) - base_entries.append(assign_8259_to_apic) - assign_to_apic = X86IntelMPIOIntAssignment( - interrupt_type = 'INT', - polarity = 'ConformPolarity', - trigger = 'ConformTrigger', - source_bus_id = 1, - source_bus_irq = irq, - dest_io_apic_id = io_apic.id, - dest_io_apic_intin = apicPin) - base_entries.append(assign_to_apic) - assignISAInt(0, 2) - assignISAInt(1, 1) - for i in range(3, 15): - assignISAInt(i, i) - self.workload.intel_mp_table.base_entries = base_entries - self.workload.intel_mp_table.ext_entries = ext_entries - - entries = \ - [ - # Mark the first megabyte of memory as reserved - X86E820Entry(addr = 0, size = '639kB', range_type = 1), - X86E820Entry(addr = 0x9fc00, size = '385kB', range_type = 2), - # Mark the rest of physical memory as available - X86E820Entry(addr = 0x100000, - size = '%dB' % (self.mem_ranges[0].size() - 0x100000), - range_type = 1), - ] - # Mark [mem_size, 3GB) as reserved if memory less than 3GB, which - # force IO devices to be mapped to [0xC0000000, 0xFFFF0000). Requests - # to this specific range can pass though bridge to iobus. - #entries.append(X86E820Entry(addr = self.mem_ranges[0].size(), - # size='%dB' % (0xC0000000 - self.mem_ranges[0].size()), - # range_type=2)) - - # Reserve the last 16kB of the 32-bit address space for m5ops - entries.append(X86E820Entry(addr = 0xFFFF0000, size = '64kB', - range_type=2)) - - # Add the rest of memory. This is where all the actual data is - #entries.append(X86E820Entry(addr = self.mem_ranges[-1].start, - # size='%dB' % (self.mem_ranges[-1].size()), - # range_type=1)) - - self.workload.e820_table.entries = entries - diff --git a/configs-npb-gapbs/system/system_back.py b/configs-npb-gapbs/system/system_back.py deleted file mode 100755 index 8a645b918f..0000000000 --- a/configs-npb-gapbs/system/system_back.py +++ /dev/null @@ -1,397 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2018 The Regents of the University of California -# All Rights Reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Jason Lowe-Power - -import m5 -from m5.objects import * -from .fs_tools import * -from .caches import * - - -class MySystem(System): - - def __init__(self, kernel, disk, num_cpus, opts, no_kvm=False): - super(MySystem, self).__init__() - self._opts = opts - self._no_kvm = no_kvm - - self._host_parallel = not self._opts.no_host_parallel - - # Set up the clock domain and the voltage domain - self.clk_domain = SrcClockDomain() - self.clk_domain.clock = '2.3GHz' - self.clk_domain.voltage_domain = VoltageDomain() - - mem_size = '32GB' - self.mem_ranges = [AddrRange('100MB'), # For kernel - AddrRange(0xC0000000, size=0x100000), # For I/0 - AddrRange(Addr('4GB'), size = mem_size) # All data - ] - - - self.mem_ranges = [AddrRange(Addr('3GB')), # All data - AddrRange(0xC0000000, size=0x100000), # For I/0 - ] - - # Create the main memory bus - # This connects to main memory - self.membus = SystemXBar(width = 64) # 64-byte width - self.membus.badaddr_responder = BadAddr() - self.membus.default = Self.badaddr_responder.pio - - # Set up the system port for functional access from the simulator - self.system_port = self.membus.cpu_side_ports - - self.initFS(self.membus, num_cpus) - - - # Replace these paths with the path to your disk images. - # The first disk is the root disk. The second could be used for swap - # or anything else. - - self.setDiskImages(disk, disk) - - if opts.second_disk: - self.setDiskImages(disk, opts.second_disk) - else: - self.setDiskImages(disk, disk) - - # Change this path to point to the kernel you want to use - self.workload.object_file = kernel - # Options specified on the kernel command line - boot_options = ['earlyprintk=ttyS0', 'console=ttyS0', 'lpj=7999923', - 'root=/dev/hda1'] - - self.workload.command_line = ' '.join(boot_options) - - # Create the CPUs for our system. - self.createCPU(num_cpus) - - # Create the cache heirarchy for the system. - self.createCacheHierarchy() - - # Set up the interrupt controllers for the system (x86 specific) - self.setupInterrupts() - - self.createMemoryControllersDDR4() - - if self._host_parallel: - # To get the KVM CPUs to run on different host CPUs - # Specify a different event queue for each CPU - for i,cpu in enumerate(self.cpu): - for obj in cpu.descendants(): - obj.eventq_index = 0 - - # the number of eventqs are set based - # on experiments with few benchmarks - - if len(self.cpu) > 16: - cpu.eventq_index = (i/4) + 1 - else: - cpu.eventq_index = (i/2) + 1 - def getHostParallel(self): - return self._host_parallel - - def totalInsts(self): - return sum([cpu.totalInsts() for cpu in self.cpu]) - - def createCPUThreads(self, cpu): - for c in cpu: - c.createThreads() - - def createCPU(self, num_cpus): - if self._no_kvm: - self.cpu = [AtomicSimpleCPU(cpu_id = i, switched_out = False) - for i in range(num_cpus)] - self.createCPUThreads(self.cpu) - self.mem_mode = 'timing' - - else: - # Note KVM needs a VM and atomic_noncaching - self.cpu = [X86KvmCPU(cpu_id = i) - for i in range(num_cpus)] - self.createCPUThreads(self.cpu) - self.kvm_vm = KvmVM() - self.mem_mode = 'atomic_noncaching' - - self.atomicCpu = [AtomicSimpleCPU(cpu_id = i, - switched_out = True) - for i in range(num_cpus)] - self.createCPUThreads(self.atomicCpu) - - self.timingCpu = [TimingSimpleCPU(cpu_id = i, - switched_out = True) - for i in range(num_cpus)] - - self.createCPUThreads(self.timingCpu) - - def switchCpus(self, old, new): - assert(new[0].switchedOut()) - m5.switchCpus(self, list(zip(old, new))) - - def setDiskImages(self, img_path_1, img_path_2): - disk0 = CowDisk(img_path_1) - disk2 = CowDisk(img_path_2) - self.pc.south_bridge.ide.disks = [disk0, disk2] - - def createCacheHierarchy(self): - # Create an L3 cache (with crossbar) - self.l3bus = L2XBar(width = 64, - snoop_filter = SnoopFilter(max_capacity='32MB')) - - for cpu in self.cpu: - # Create a memory bus, a coherent crossbar, in this case - cpu.l2bus = L2XBar() - - # Create an L1 instruction and data cache - cpu.icache = L1ICache(self._opts) - cpu.dcache = L1DCache(self._opts) - cpu.mmucache = MMUCache() - - # Connect the instruction and data caches to the CPU - cpu.icache.connectCPU(cpu) - cpu.dcache.connectCPU(cpu) - cpu.mmucache.connectCPU(cpu) - - # Hook the CPU ports up to the l2bus - cpu.icache.connectBus(cpu.l2bus) - cpu.dcache.connectBus(cpu.l2bus) - cpu.mmucache.connectBus(cpu.l2bus) - - # Create an L2 cache and connect it to the l2bus - cpu.l2cache = L2Cache(self._opts) - cpu.l2cache.connectCPUSideBus(cpu.l2bus) - - # Connect the L2 cache to the L3 bus - cpu.l2cache.connectMemSideBus(self.l3bus) - - self.l3cache = L3Cache(self._opts) - self.l3cache.connectCPUSideBus(self.l3bus) - - # Connect the L3 cache to the membus - self.l3cache.connectMemSideBus(self.membus) - - def setupInterrupts(self): - for cpu in self.cpu: - # create the interrupt controller CPU and connect to the membus - cpu.createInterruptController() - - # For x86 only, connect interrupts to the memory - # Note: these are directly connected to the memory bus and - # not cached - cpu.interrupts[0].pio = self.membus.mem_side_ports - cpu.interrupts[0].int_requestor = self.membus.cpu_side_ports - cpu.interrupts[0].int_responder = self.membus.mem_side_ports - - # Memory latency: Using the smaller number from [3]: 96ns - def createMemoryControllersDDR4(self): - self._createMemoryControllers(8, DDR4_2400_16x4) - - def _createMemoryControllers(self, num, cls): - kernel_controller = self._createKernelMemoryController(cls) - - ranges = self._getInterleaveRanges(self.mem_ranges[-1], num, 7, 20) - - self.mem_cntrls = [ - MemCtrl(dram = cls(range = ranges[i]), - port = self.membus.mem_side_ports) - for i in range(num) - ] + [kernel_controller] - - def _createKernelMemoryController(self, cls): - return MemCtrl(dram = cls(range = self.mem_ranges[0]), - port = self.membus.mem_side_ports) - - def _getInterleaveRanges(self, rng, num, intlv_low_bit, xor_low_bit): - from math import log - bits = int(log(num, 2)) - if 2**bits != num: - m5.fatal("Non-power of two number of memory controllers") - - intlv_bits = bits - ranges = [ - AddrRange(start=rng.start, - end=rng.end, - intlvHighBit = intlv_low_bit + intlv_bits - 1, - xorHighBit = xor_low_bit + intlv_bits - 1, - intlvBits = intlv_bits, - intlvMatch = i) - for i in range(num) - ] - - return ranges - - def initFS(self, membus, cpus): - self.pc = Pc() - self.workload = X86FsLinux() - - # Constants similar to x86_traits.hh - IO_address_space_base = 0x8000000000000000 - pci_config_address_space_base = 0xc000000000000000 - interrupts_address_space_base = 0xa000000000000000 - APIC_range_size = 1 << 12; - - # North Bridge - self.iobus = IOXBar() - self.bridge = Bridge(delay='50ns') - self.bridge.mem_side_port = self.iobus.cpu_side_ports - self.bridge.cpu_side_port = membus.mem_side_ports - # Allow the bridge to pass through: - # 1) kernel configured PCI device memory map address: address range - # [0xC0000000, 0xFFFF0000). (The upper 64kB are reserved for m5ops.) - # 2) the bridge to pass through the IO APIC (two pages, already - # contained in 1), - # 3) everything in the IO address range up to the local APIC, and - # 4) then the entire PCI address space and beyond. - self.bridge.ranges = \ - [ - AddrRange(0xC0000000, 0xFFFF0000), - AddrRange(IO_address_space_base, - interrupts_address_space_base - 1), - AddrRange(pci_config_address_space_base, - Addr.max) - ] - - # Create a bridge from the IO bus to the memory bus to allow access - # to the local APIC (two pages) - self.apicbridge = Bridge(delay='50ns') - self.apicbridge.cpu_side_port = self.iobus.mem_side_ports - self.apicbridge.mem_side_port = membus.cpu_side_ports - self.apicbridge.ranges = [AddrRange(interrupts_address_space_base, - interrupts_address_space_base + - cpus * APIC_range_size - - 1)] - - # connect the io bus - self.pc.attachIO(self.iobus) - - # Add a tiny cache to the IO bus. - # This cache is required for the classic memory model for coherence - self.iocache = Cache(assoc=8, - tag_latency = 50, - data_latency = 50, - response_latency = 50, - mshrs = 20, - size = '1kB', - tgts_per_mshr = 12, - addr_ranges = self.mem_ranges) - self.iocache.cpu_side = self.iobus.mem_side_ports - self.iocache.mem_side = self.membus.cpu_side_ports - - ############################################### - - # Add in a Bios information structure. - self.workload.smbios_table.structures = [X86SMBiosBiosInformation()] - - # Set up the Intel MP table - base_entries = [] - ext_entries = [] - for i in range(cpus): - bp = X86IntelMPProcessor( - local_apic_id = i, - local_apic_version = 0x14, - enable = True, - bootstrap = (i ==0)) - base_entries.append(bp) - io_apic = X86IntelMPIOAPIC( - id = cpus, - version = 0x11, - enable = True, - address = 0xfec00000) - self.pc.south_bridge.io_apic.apic_id = io_apic.id - base_entries.append(io_apic) - pci_bus = X86IntelMPBus(bus_id = 0, bus_type='PCI ') - base_entries.append(pci_bus) - isa_bus = X86IntelMPBus(bus_id = 1, bus_type='ISA ') - base_entries.append(isa_bus) - connect_busses = X86IntelMPBusHierarchy(bus_id=1, - subtractive_decode=True, parent_bus=0) - ext_entries.append(connect_busses) - pci_dev4_inta = X86IntelMPIOIntAssignment( - interrupt_type = 'INT', - polarity = 'ConformPolarity', - trigger = 'ConformTrigger', - source_bus_id = 0, - source_bus_irq = 0 + (4 << 2), - dest_io_apic_id = io_apic.id, - dest_io_apic_intin = 16) - base_entries.append(pci_dev4_inta) - def assignISAInt(irq, apicPin): - assign_8259_to_apic = X86IntelMPIOIntAssignment( - interrupt_type = 'ExtInt', - polarity = 'ConformPolarity', - trigger = 'ConformTrigger', - source_bus_id = 1, - source_bus_irq = irq, - dest_io_apic_id = io_apic.id, - dest_io_apic_intin = 0) - base_entries.append(assign_8259_to_apic) - assign_to_apic = X86IntelMPIOIntAssignment( - interrupt_type = 'INT', - polarity = 'ConformPolarity', - trigger = 'ConformTrigger', - source_bus_id = 1, - source_bus_irq = irq, - dest_io_apic_id = io_apic.id, - dest_io_apic_intin = apicPin) - base_entries.append(assign_to_apic) - assignISAInt(0, 2) - assignISAInt(1, 1) - for i in range(3, 15): - assignISAInt(i, i) - self.workload.intel_mp_table.base_entries = base_entries - self.workload.intel_mp_table.ext_entries = ext_entries - - entries = \ - [ - # Mark the first megabyte of memory as reserved - X86E820Entry(addr = 0, size = '639kB', range_type = 1), - X86E820Entry(addr = 0x9fc00, size = '385kB', range_type = 2), - # Mark the rest of physical memory as available - X86E820Entry(addr = 0x100000, - size = '%dB' % (self.mem_ranges[0].size() - 0x100000), - range_type = 1), - ] - # Mark [mem_size, 3GB) as reserved if memory less than 3GB, which - # force IO devices to be mapped to [0xC0000000, 0xFFFF0000). Requests - # to this specific range can pass though bridge to iobus. - entries.append(X86E820Entry(addr = self.mem_ranges[0].size(), - size='%dB' % (0xC0000000 - self.mem_ranges[0].size()), - range_type=2)) - - # Reserve the last 16kB of the 32-bit address space for m5ops - entries.append(X86E820Entry(addr = 0xFFFF0000, size = '64kB', - range_type=2)) - - # Add the rest of memory. This is where all the actual data is - entries.append(X86E820Entry(addr = self.mem_ranges[-1].start, - size='%dB' % (self.mem_ranges[-1].size()), - range_type=1)) - - self.workload.e820_table.entries = entries - From 126e158d3cb6700b058f61379b08069472664f0d Mon Sep 17 00:00:00 2001 From: mbabaie Date: Thu, 2 Nov 2023 13:11:38 -0700 Subject: [PATCH 16/28] fixed the checkpoint Ruby flush issue and tested chkpts and rstrs worked --- .../checkpoint_both.py | 26 ++---- .../restore_both.py | 82 ++++++------------ src/mem/SConscript | 1 + .../replacement_policies/replaceable_entry.hh | 2 - src/mem/policy_manager.cc | 84 +++++++++---------- src/mem/ruby/system/RubySystem.cc | 6 +- test.sh | 35 +------- 7 files changed, 80 insertions(+), 156 deletions(-) diff --git a/configs-npb-gapbs-chkpt-restore/checkpoint_both.py b/configs-npb-gapbs-chkpt-restore/checkpoint_both.py index bc260886a7..c93f0fb5d0 100644 --- a/configs-npb-gapbs-chkpt-restore/checkpoint_both.py +++ b/configs-npb-gapbs-chkpt-restore/checkpoint_both.py @@ -26,8 +26,7 @@ # # Authors: Jason Lowe-Power, Ayaz Akram -""" Script to run GAP Benchmark suites workloads. - The workloads have two modes: synthetic and real graphs. +""" Script to run and take checkpoints for both GAPBS and NPB """ import argparse import time @@ -179,38 +178,31 @@ def parse_options(): exit_event = m5.simulate() if exit_event.getCause() == "workbegin": - print("Done booting Linux") # Reached the start of ROI # start of ROI is marked by an # m5_work_begin() call - print("Resetting stats at the start of ROI!") + print("Done booting Linux and reached to ROI") m5.stats.reset() + print("Reset stats at the start of ROI") start_tick = m5.curTick() start_insts = system.totalInsts() # switching CPU to timing system.switchCpus(system.cpu, system.timingCpu) + print("Switched CPU from KVM to Timing!") else: print(exit_event.getCause()) print("Unexpected termination of simulation !") exit(1) - m5.stats.reset() - print( - "After reset ************************************************ statring smiulation:\n" - ) - for interval_number in range(1): + print("Start to running intervals!") + for interval_number in range(300): # 3 seconds print("Interval number: {} \n".format(interval_number)) - exit_event = m5.simulate(1000000000) + exit_event = m5.simulate(10_000_000_000) # 10 ms if exit_event.getCause() == "cacheIsWarmedup": print("Caught cacheIsWarmedup exit event!") break - print( - "-------------------------------------------------------------------" - ) - - print( - "After sim ************************************************ End of warm-up \n" - ) + if interval_number == 299 : + print("TIMEOUT!") m5.stats.dump() system.switchCpus(system.timingCpu, system.o3Cpu) print("switched from timing to O3") diff --git a/configs-npb-gapbs-chkpt-restore/restore_both.py b/configs-npb-gapbs-chkpt-restore/restore_both.py index ee3902aef6..8175611ee0 100755 --- a/configs-npb-gapbs-chkpt-restore/restore_both.py +++ b/configs-npb-gapbs-chkpt-restore/restore_both.py @@ -26,14 +26,7 @@ # # Authors: Jason Lowe-Power, Ayaz Akram -""" Script to run NAS parallel benchmarks with gem5. - The script expects kernel, diskimage, mem_sys, - cpu (kvm, atomic, or timing), benchmark to run - and number of cpus as arguments. - - If your application has ROI annotations, this script will count the total - number of instructions executed in the ROI. It also tracks how much - wallclock and simulated time. +""" Script to restore both GAPBS and NPB with a checkpoint """ import argparse import time @@ -98,14 +91,18 @@ def writeBenchScript_NPB(dir, bench): def parse_options(): parser = argparse.ArgumentParser( - description="For use with gem5. This " - "runs a NAS Parallel Benchmark application. This only works " - "with x86 ISA." + description="Restores a checkpoint for NPB and GAPBS" ) # The manditry position arguments. parser.add_argument( "isGAPBS", type=int, help="GAPBS (1) application to run or NPB (0)" ) + parser.add_argument( + "benchmark", type=str, help="The application to run" + ) + parser.add_argument( + "size", type=str, help="The problem size to run" + ) parser.add_argument( "dcache_policy", type=str, @@ -203,44 +200,12 @@ def run(): mem_size = "128GiB" mem_size_per_channel = "64GiB" single_channel_HBM = False - checkpoint_dir = "" - - if args.benchmark in benchmark_choices_npb: - if args.benchmark.split(".")[1] == "C": - checkpoint_dir = ( - ckpt_base - + "1GB_8GB_g22_nC_1halfSec/NPB/" - + args.benchmark.split(".")[0] - + "/cpt" - ) - mem_size = "8GiB" - elif args.benchmark.split(".")[1] == "D": - checkpoint_dir = ( - ckpt_base - + "1GB_85GB_g25_nD_1halfSec/NPB/" - + args.benchmark.split(".")[0] - + "/cpt" - ) - mem_size = "85GiB" - else: - if args.benchmark.split("-")[1] == "22": - checkpoint_dir = ( - ckpt_base - + "1GB_8GB_g22_nC_1halfSec/GAPBS/" - + args.benchmark.split("-")[0] - + "/cpt" - ) - mem_size = "8GiB" - elif args.benchmark.split("-")[1] == "25": - checkpoint_dir = ( - ckpt_base - + "1GB_85GB_g25_nD_1halfSec/GAPBS/" - + args.benchmark.split("-")[0] - + "/cpt" - ) - mem_size = "85GiB" + checkpoint_dir = "/home/babaie/projects/TDRAM-resubmission/8channelConfig/dramCacheController/cptTest/gapbs/bfs3/cpt" - benchmark = args.benchmark + if args.isGAPBS == 1: + benchmark = args.benchmark + else: + benchmark = args.benchmark+"."+args.size+".x" if single_channel_HBM: system = RubySystem1Channel( @@ -277,17 +242,20 @@ def run(): restore=True, ) + app = benchmark + if args.isGAPBS: + app = benchmark+"-"+args.size + if args.do_analysis: lpmanager = O3LooppointAnalysisManager() - for core in system.o3Cpu: lplistener = O3LooppointAnalysis() lplistener.ptmanager = lpmanager - lplistener.validAddrRangeStart = text_info[args.benchmark][1] - lplistener.validAddrRangeSize = text_info[args.benchmark][0] + lplistener.validAddrRangeStart = text_info[app][1] + lplistener.validAddrRangeSize = text_info[app][0] core.probeListener = lplistener else: - pc, count = interval_info_1GBdramCache_3hr[args.benchmark] + pc, count = interval_info_1GBdramCache_3hr[app] system.global_tracker = PcCountTrackerManager( targets=[PcCountPair(pc, count)] ) @@ -306,13 +274,13 @@ def run(): # Create and pass a script to the simulated system to run the reuired # benchmark - if args.benchmark in benchmark_choices_npb: - system.readfile = writeBenchScript_NPB( - m5.options.outdir, args.benchmark + if args.isGAPBS: + system.readfile = writeBenchScript_GAPBS( + m5.options.outdir, benchmark, args.size, synthetic ) else: - system.readfile = writeBenchScript_GAPBS( - m5.options.outdir, args.benchmark + system.readfile = writeBenchScript_NPB( + m5.options.outdir, benchmark ) # set up the root SimObject and start the simulation diff --git a/src/mem/SConscript b/src/mem/SConscript index 6e8beaa8c9..52cbe7f95e 100644 --- a/src/mem/SConscript +++ b/src/mem/SConscript @@ -159,6 +159,7 @@ DebugFlag('LLSC') DebugFlag('MemCtrl') DebugFlag('DCacheCtrl') DebugFlag('PolicyManager') +DebugFlag('ChkptRstrTest') DebugFlag('MMU') DebugFlag('MemoryAccess') DebugFlag('PacketQueue') diff --git a/src/mem/cache/replacement_policies/replaceable_entry.hh b/src/mem/cache/replacement_policies/replaceable_entry.hh index 26d8f44845..5619429258 100644 --- a/src/mem/cache/replacement_policies/replaceable_entry.hh +++ b/src/mem/cache/replacement_policies/replaceable_entry.hh @@ -65,9 +65,7 @@ class ReplaceableEntry public: Addr tagDC; Addr indexDC; - // constant to indicate that the cache line is valid bool validLine; - // constant to indicate that the cache line is dirty bool dirtyLine; Addr farMemAddr; unsigned counter; diff --git a/src/mem/policy_manager.cc b/src/mem/policy_manager.cc index aa260b6a2d..43f1df6da8 100644 --- a/src/mem/policy_manager.cc +++ b/src/mem/policy_manager.cc @@ -1,6 +1,7 @@ #include "mem/policy_manager.hh" #include "base/trace.hh" +#include "debug/ChkptRstrTest.hh" #include "debug/PolicyManager.hh" #include "debug/Drain.hh" #include "mem/dram_interface.hh" @@ -2341,26 +2342,22 @@ PolicyManager::handleRequestorPkt(PacketPtr pkt) if (extreme) { orbEntry->prevDirty = alwaysDirty; } else { - orbEntry->prevDirty = tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->dirtyLine; + orbEntry->prevDirty = tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->validLine && + tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->dirtyLine; } // Updating Tag & Metadata tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->tagDC = orbEntry->tagDC; tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->indexDC = orbEntry->indexDC; tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->validLine = true; + tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->farMemAddr = orbEntry->owPkt->getAddr(); replacementPolicy->touch(tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->replacementData, pkt); - if (orbEntry->owPkt->isRead()) { - if (orbEntry->isHit) { - tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->dirtyLine = - tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->dirtyLine; - } else { - tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->dirtyLine = false; - } - } else { // write + if (orbEntry->owPkt->isRead() && !orbEntry->isHit) { + tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->dirtyLine = false; + } + if (!orbEntry->owPkt->isRead()) { // write tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->dirtyLine = true; - tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->farMemAddr = - orbEntry->owPkt->getAddr(); } if (orbEntry->isHit) { @@ -3333,20 +3330,25 @@ PolicyManager::serialize(CheckpointOut &cp) const ScopedCheckpointSection sec(cp, "tagMetadataStore"); paramOut(cp, "numEntries", tagMetadataStore.size()*assoc); int count = 0; + int invalids = 0; for (auto const &set : tagMetadataStore) { for (auto const way : set) { ScopedCheckpointSection sec_entry(cp,csprintf("Entry%d", count++)); if (way->validLine) { paramOut(cp, "validLine", way->validLine); - paramOut(cp, "tagDC", way->tagDC); - paramOut(cp, "indexDC", way->indexDC); paramOut(cp, "dirtyLine", way->dirtyLine); paramOut(cp, "farMemAddr", way->farMemAddr); + DPRINTF(ChkptRstrTest, "v: %d, %d, %d, %d, %d\n", + way->farMemAddr, + way->indexDC, way->tagDC, + way->validLine, way->dirtyLine); } else { paramOut(cp, "validLine", way->validLine); + invalids++; } } } + DPRINTF(ChkptRstrTest, "invalids: %d\n", invalids); } void @@ -3354,9 +3356,7 @@ PolicyManager::unserialize(CheckpointIn &cp) { ScopedCheckpointSection sec(cp, "tagMetadataStore"); int num_entries = 0; - unsigned countValid = 0; - unsigned countInvalid = 0; - unsigned numOfSets = dramCacheSize / (blockSize * assoc); + int countValid = 0; paramIn(cp, "numEntries", num_entries); warn_if(num_entries > tagMetadataStore.size()*assoc, "Unserializing larger tag " "store into a smaller tag store. Stopping when index doesn't fit"); @@ -3365,42 +3365,36 @@ PolicyManager::unserialize(CheckpointIn &cp) for (int i = 0; i < num_entries; i++) { ScopedCheckpointSection sec_entry(cp,csprintf("Entry%d", i)); bool valid = false; + Addr far_addr = -1; paramIn(cp, "validLine", valid); - if (!valid){ - countInvalid++; - } - if (valid) { + paramIn(cp, "farMemAddr", far_addr); + if (valid && getAddrRange().contains(far_addr)) { countValid++; - Addr tag = 0; - Addr index = 0; bool dirty = false; - Addr far_addr = 0; - paramIn(cp, "tagDC", tag); - paramIn(cp, "indexDC", index); paramIn(cp, "dirtyLine", dirty); - paramIn(cp, "farMemAddr", far_addr); - Addr newIndex = index % numOfSets; - - if (newIndex < tagMetadataStore.size()) { - // Only insert if this entry fits into the current store. - // tagMetadataStore.at(newIndex).at(i / numOfSets)->tagDC = tag; - // tagMetadataStore.at(newIndex).at(i / numOfSets)->indexDC = newIndex; - // tagMetadataStore.at(newIndex).at(i / numOfSets)->validLine = valid; - // tagMetadataStore.at(newIndex).at(i / numOfSets)->dirtyLine = dirty; - // tagMetadataStore.at(newIndex).at(i / numOfSets)->farMemAddr = far_addr; - int way = findEmptyWay(newIndex); - - if (way ==-1) { - way = 0; - } - tagMetadataStore.at(newIndex).at(way)->tagDC = returnTagDC(far_addr, blockSize); // = tag; - tagMetadataStore.at(newIndex).at(way)->indexDC = newIndex; - tagMetadataStore.at(newIndex).at(way)->validLine = valid; - tagMetadataStore.at(newIndex).at(way)->dirtyLine = dirty; - tagMetadataStore.at(newIndex).at(way)->farMemAddr = far_addr; + + Addr index = returnIndexDC(far_addr, blockSize); + Addr tag = returnTagDC(far_addr, blockSize); + int way = findEmptyWay(index); + // once you stored LRU, come back here and call it instead of putting 0; + if (way ==-1) { + way = 0; // so it always works for direct-mapped } + tagMetadataStore.at(index).at(way)->tagDC = tag; + tagMetadataStore.at(index).at(way)->indexDC = index; + tagMetadataStore.at(index).at(way)->validLine = valid; + tagMetadataStore.at(index).at(way)->dirtyLine = dirty; + tagMetadataStore.at(index).at(way)->farMemAddr = far_addr; + + DPRINTF(ChkptRstrTest, "%d, %d, %d, %d, %d\n", + tagMetadataStore.at(index).at(way)->farMemAddr, + tagMetadataStore.at(index).at(way)->tagDC, + tagMetadataStore.at(index).at(way)->indexDC, + tagMetadataStore.at(index).at(way)->validLine, + tagMetadataStore.at(index).at(way)->dirtyLine); } } + DPRINTF(ChkptRstrTest, "valid: %d\n", countValid); } int diff --git a/src/mem/ruby/system/RubySystem.cc b/src/mem/ruby/system/RubySystem.cc index 7370023249..e30804df35 100644 --- a/src/mem/ruby/system/RubySystem.cc +++ b/src/mem/ruby/system/RubySystem.cc @@ -226,10 +226,8 @@ RubySystem::memWriteback() } DPRINTF(RubyCacheTrace, "Cache Trace Complete\n"); - // If there is no dirty block, we don't need to flush the cache - if (m_cache_recorder->getNumRecords() == 0) - { - m_cooldown_enabled = false; + if (m_access_backing_store) { + // Nothing to flush if we're using access backing store. return; } diff --git a/test.sh b/test.sh index 144c08e0ec..ac609f7206 100755 --- a/test.sh +++ b/test.sh @@ -1,32 +1,5 @@ +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/npb/bt3 --debug-flags=ChkptRstrTest configs-npb-gapbs-chkpt-restore/checkpoint_both.py 0 bt C RambusTagProbOpt & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/gapbs/bfs3 --debug-flags=ChkptRstrTest configs-npb-gapbs-chkpt-restore/checkpoint_both.py 1 bfs 22 RambusTagProbOpt & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/bt configs-npb-gapbs/restore_both.py bt.C.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/cg configs-npb-gapbs/restore_both.py cg.C.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/ft configs-npb-gapbs/restore_both.py ft.C.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/is configs-npb-gapbs/restore_both.py is.C.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/lu configs-npb-gapbs/restore_both.py lu.C.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/mg configs-npb-gapbs/restore_both.py mg.C.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/sp configs-npb-gapbs/restore_both.py sp.C.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/NPB/ua configs-npb-gapbs/restore_both.py ua.C.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/bc configs-npb-gapbs/restore_both.py bc-22 RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/bfs configs-npb-gapbs/restore_both.py bfs-22 RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/cc configs-npb-gapbs/restore_both.py cc-22 RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/pr configs-npb-gapbs/restore_both.py pr-22 RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/tc configs-npb-gapbs/restore_both.py tc-22 RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_8GB_g22_nC/GAPBS/sssp configs-npb-gapbs/restore_both.py sssp-22 RambusTagProbOpt 1 0 0 0 & - -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/NPB/bt configs-npb-gapbs/restore_both.py bt.D.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/NPB/cg configs-npb-gapbs/restore_both.py cg.D.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/NPB/ft configs-npb-gapbs/restore_both.py ft.D.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/NPB/is configs-npb-gapbs/restore_both.py is.D.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/NPB/lu configs-npb-gapbs/restore_both.py lu.D.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/NPB/mg configs-npb-gapbs/restore_both.py mg.D.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/NPB/sp configs-npb-gapbs/restore_both.py sp.D.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/NPB/ua configs-npb-gapbs/restore_both.py ua.D.x RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/GAPBS/bc configs-npb-gapbs/restore_both.py bc-25 RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/GAPBS/bfs configs-npb-gapbs/restore_both.py bfs-25 RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/GAPBS/cc configs-npb-gapbs/restore_both.py cc-25 RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/GAPBS/pr configs-npb-gapbs/restore_both.py pr-25 RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/GAPBS/tc configs-npb-gapbs/restore_both.py tc-25 RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=newResults6/dirMap/RambusTagProbOpt/1GB_85GB_g25_nD/GAPBS/sssp configs-npb-gapbs/restore_both.py sssp-25 RambusTagProbOpt 1 0 0 0 & - -build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/gapbs/22/pr configs-npb-gapbs/gapbs_checkpoint.py pr 22 RambusTagProbOpt & \ No newline at end of file +# build/X86_MESI_Two_Level/gem5.debug -re --outdir=rstrTest/npb/bt3 --debug-flags=ChkptRstrTest configs-npb-gapbs-chkpt-restore/restore_both.py 0 bt C RambusTagProbOpt 1 0 0 0 & +build/X86_MESI_Two_Level/gem5.debug -re --outdir=rstrTest/gapbs/bfs3 --debug-flags=ChkptRstrTest configs-npb-gapbs-chkpt-restore/restore_both.py 1 bfs 22 RambusTagProbOpt 1 0 0 0 & \ No newline at end of file From 06a768715cd3e4712fed4401600a6eca230e8afe Mon Sep 17 00:00:00 2001 From: mbabaie Date: Sat, 4 Nov 2023 19:21:18 -0700 Subject: [PATCH 17/28] unified scripts for multi channel checkpoints tested, restore not tested yet --- .../checkpoint_both.py | 152 ++++++++++++------ configs-npb-gapbs-chkpt-restore/info.py | 19 +++ .../restore_both.py | 32 ++-- .../system/ruby_system_1channel.py | 7 +- .../system/ruby_system_8channel.py | 2 +- src/mem/PolicyManager.py | 2 + .../replacement_policies/replaceable_entry.hh | 2 - src/mem/policy_manager.cc | 117 +++++++------- src/mem/policy_manager.hh | 3 +- .../components/memory/dram_interfaces/hbm.py | 2 +- test.sh | 10 +- 11 files changed, 204 insertions(+), 144 deletions(-) diff --git a/configs-npb-gapbs-chkpt-restore/checkpoint_both.py b/configs-npb-gapbs-chkpt-restore/checkpoint_both.py index c93f0fb5d0..2d50956e5b 100644 --- a/configs-npb-gapbs-chkpt-restore/checkpoint_both.py +++ b/configs-npb-gapbs-chkpt-restore/checkpoint_both.py @@ -34,6 +34,12 @@ import m5.ticks from m5.objects import * from system import * +from m5.stats.gem5stats import get_simstat + +from info import ( + gapbs_benchmarks, + npb_benchmarks, +) def writeBenchScript_GAPBS(dir, benchmark_name, size, synthetic): """ @@ -80,61 +86,71 @@ def parse_options(): "runs a GAPBS/NPB application and only works " "with x86 ISA." ) - parser.add_argument( - "isGAPBS", type=int, help="GAPBS (1) application to run or NPB (0)" - ) parser.add_argument( "benchmark", type=str, help="The application to run" ) parser.add_argument( "size", type=str, help="The problem size to run" ) - parser.add_argument( - "dcache_policy", - type=str, - help="The architecture of DRAM cache: " - "CascadeLakeNoPartWrs, Oracle, BearWriteOpt, Rambus", - ) - return parser.parse_args() if __name__ == "__m5_main__": args = parse_options() - kernel = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-linux-kernel-4.19.83" + kernel = "/home/babaie/projects/TDRAM-resubmission/fsTools/x86-linux-kernel-4.19.83" disk = "" - if args.isGAPBS == 1: - disk = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-gapbs" - elif args.isGAPBS == 0: - disk = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-npb" - + if args.benchmark in gapbs_benchmarks: + disk = "/home/babaie/projects/TDRAM-resubmission/fsTools/x86-gapbs" + elif args.benchmark in npb_benchmarks: + disk = "/home/babaie/projects/TDRAM-resubmission/fsTools/x86-npb" + else: + print("Wrong benchmark choice!") + exit(1) + synthetic = 1 num_cpus = 8 - cpu_type = "Timing" mem_sys = "MESI_Two_Level" - synthetic = 1 + dcache_policy = "RambusTagProbOpt" dcache_size = "1GiB" # size of each channel - mem_size = "128GiB" - mem_size_per_channel = "64GiB" + mem_size = "8GiB" # size of total main memory + mem_size_per_channel = "8GiB" assoc = 1 + singleChannel = True # create the system we are going to simulate - system = RubySystem8Channel( - kernel, - disk, - mem_sys, - num_cpus, - assoc, - dcache_size, - mem_size, - mem_size_per_channel, - args.dcache_policy, - 0, - 0, - 0, - args, - ) + if singleChannel: + system = RubySystem1Channel( + kernel, + disk, + mem_sys, + num_cpus, + assoc, + dcache_size, + mem_size, + mem_size_per_channel, + dcache_policy, + 0, + 0, + 0, + args, + ) + else: + system = RubySystem8Channel( + kernel, + disk, + mem_sys, + num_cpus, + assoc, + dcache_size, + mem_size, + mem_size_per_channel, + dcache_policy, + 0, + 0, + 0, + args, + ) system.m5ops_base = 0xFFFF0000 @@ -143,14 +159,14 @@ def parse_options(): # Create and pass a script to the simulated system to run the reuired # benchmark - if args.isGAPBS == 1: + if args.benchmark in gapbs_benchmarks: system.readfile = writeBenchScript_GAPBS( m5.options.outdir, args.benchmark, args.size, synthetic ) - elif args.isGAPBS == 0: + elif args.benchmark in npb_benchmarks: system.readfile = writeBenchScript_NPB( m5.options.outdir, args.benchmark+"."+args.size+".x" @@ -165,16 +181,10 @@ def parse_options(): # Note: The simulator is quite picky about this number! root.sim_quantum = int(1e9) # 1 ms - # needed for long running jobs - # m5.disableAllListeners() - # instantiate all of the objects we've created above m5.instantiate() - globalStart = time.time() - print("Running the simulation") - print("Using cpu: {}".format(cpu_type)) exit_event = m5.simulate() if exit_event.getCause() == "workbegin": @@ -195,15 +205,55 @@ def parse_options(): exit(1) print("Start to running intervals!") - for interval_number in range(300): # 3 seconds - print("Interval number: {} \n".format(interval_number)) - exit_event = m5.simulate(10_000_000_000) # 10 ms - if exit_event.getCause() == "cacheIsWarmedup": - print("Caught cacheIsWarmedup exit event!") - break - if interval_number == 299 : - print("TIMEOUT!") + totalColdMisses = 0 + numOfCacheBlks = 0 + if singleChannel: + numOfCacheBlks = system.mem_ctrl.dram_cache_size / system.mem_ctrl.block_size + else: + numOfCacheBlks = num_cpus * system.mem_ctrl[0].dram_cache_size / system.mem_ctrl[0].block_size + print(numOfCacheBlks) + + for interval_number in range(1): # 2.5 seconds + print("Interval number: {}\n".format(interval_number)) + intervalColdMisses = 0 + intervalTotalReqs = 0 + + exit_event = m5.simulate(100000000) # 100 ms + #if exit_event.getCause() != "simulate() limit reached": + # if ( + # exit_event.getCause() == "workend" + # or exit_event.getCause() == "workbegin" + # ): + # print("ROI bounds, continuing to stats ...") + # else: + # print(f"Exiting because {exit_event.getCause()}") + # exit(1) + # + #simstats = get_simstat([polMan for polMan in system.mem_ctrl], prepare_stats=True) + #for i in range(num_cpus): + # ctrl = simstats.__dict__[f"mem_ctrl{i}"] + # intervalColdMisses += ctrl.numColdMisses.value + # intervalTotalReqs += (ctrl.readReqs.value + ctrl.writeReqs.value) +# + #totalColdMisses += intervalColdMisses +# + #if totalColdMisses >= (numOfCacheBlks*0.95): + # print("95%% of system's total DRAM cache is warmed up") + # break + #elif (interval_number >= 150 and + # float(intervalColdMisses/intervalTotalReqs) <= 0.05 and + # exit_event.getCause() == "simulate() limit reached"): + # print("Have run at about 1.5 sec and cold misses in a 100 ms" + # "interval has been less than 5%%") + # break + #m5.stats.reset() + #print("Warmup ratio so far: {}\n".format(float(totalColdMisses/numOfCacheBlks))) + + print("Exited warmup iterations") + if interval_number == 249 : + print("TIMEOUT!\n") m5.stats.dump() system.switchCpus(system.timingCpu, system.o3Cpu) print("switched from timing to O3") m5.checkpoint(m5.options.outdir + "/cpt") + diff --git a/configs-npb-gapbs-chkpt-restore/info.py b/configs-npb-gapbs-chkpt-restore/info.py index 7547fb421a..ea0a6b867c 100644 --- a/configs-npb-gapbs-chkpt-restore/info.py +++ b/configs-npb-gapbs-chkpt-restore/info.py @@ -274,6 +274,25 @@ "tc-25", ] +npb_benchmarks = [ + "bt", + "cg", + "ep", + "ft", + "is", + "lu", + "mg", + "sp", + "ua", +] +gapbs_benchmarks = [ + "bfs", + "bc", + "cc", + "pr", + "sssp", + "tc", +] interval_info_1hr_512MiB = { # exe pc count "bc-22": (0x404E08, 4355635), diff --git a/configs-npb-gapbs-chkpt-restore/restore_both.py b/configs-npb-gapbs-chkpt-restore/restore_both.py index 8175611ee0..b9076a6a1a 100755 --- a/configs-npb-gapbs-chkpt-restore/restore_both.py +++ b/configs-npb-gapbs-chkpt-restore/restore_both.py @@ -35,20 +35,12 @@ from m5.objects import * from system import * + from info import ( - text_info, - interval_info_1hr, - interval_info_3hr, - interval_info_6hr, - interval_info_12hr, - interval_info_24hr, - benchmark_choices_gapbs, - benchmark_choices_npb, - interval_info_1hr_512MiB, - interval_info_1GBdramCache_3hr, + gapbs_benchmarks, + npb_benchmarks, ) - def writeBenchScript_GAPBS(dir, benchmark_name, size, synthetic): """ This method creates a script in dir which will be eventually @@ -93,10 +85,6 @@ def parse_options(): parser = argparse.ArgumentParser( description="Restores a checkpoint for NPB and GAPBS" ) - # The manditry position arguments. - parser.add_argument( - "isGAPBS", type=int, help="GAPBS (1) application to run or NPB (0)" - ) parser.add_argument( "benchmark", type=str, help="The application to run" ) @@ -184,13 +172,15 @@ def run(): if __name__ == "__m5_main__": args = parse_options() - kernel = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-linux-kernel-4.19.83" + kernel = "/home/babaie/projects/TDRAM-resubmission/fsTools/x86-linux-kernel-4.19.83" disk = "" - if args.isGAPBS == 1: - disk = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-gapbs" - elif args.isGAPBS == 0: - disk = "/home/babaie/projects/ispass2023/runs/hbmCtrlrTest/dramCacheController/fullSystemDisksKernel/x86-npb" - ckpt_base = "/home/babaie/projects/rambusDesign/1gigDRAMCache/dramCacheController/chkpt1GigDC/" + if args.benchmark in gapbs_benchmarks: + disk = "/home/babaie/projects/TDRAM-resubmission/fsTools/x86-gapbs" + elif args.benchmark in npb_benchmarks: + disk = "/home/babaie/projects/TDRAM-resubmission/fsTools/x86-npb" + else: + print("wrong benchmark choice!") + exit(1) num_cpus = 8 cpu_type = "Timing" diff --git a/configs-npb-gapbs-chkpt-restore/system/ruby_system_1channel.py b/configs-npb-gapbs-chkpt-restore/system/ruby_system_1channel.py index c0e0d83f0f..c87d0860b7 100644 --- a/configs-npb-gapbs-chkpt-restore/system/ruby_system_1channel.py +++ b/configs-npb-gapbs-chkpt-restore/system/ruby_system_1channel.py @@ -41,7 +41,8 @@ def __init__( num_cpus, assoc, dcache_size, - main_mem_size, + mem_size, + mem_size_per_channel, policy, is_link, link_lat, @@ -65,8 +66,8 @@ def __init__( AddrRange(Addr("128MiB")), # kernel data AddrRange(0xC0000000, size=0x100000), # For I/0 AddrRange( - 0x100000000, size=main_mem_size - ), # starting at 4GiB for main_mem_size + 0x100000000, size=mem_size + ), ] self.initFS(num_cpus) diff --git a/configs-npb-gapbs-chkpt-restore/system/ruby_system_8channel.py b/configs-npb-gapbs-chkpt-restore/system/ruby_system_8channel.py index 093dc6fcb8..1b148523e2 100644 --- a/configs-npb-gapbs-chkpt-restore/system/ruby_system_8channel.py +++ b/configs-npb-gapbs-chkpt-restore/system/ruby_system_8channel.py @@ -254,7 +254,7 @@ def _createMemoryControllers( ) self.mem_ctrl = [ - PolicyManager(range=r, kvm_map=False) for r in self.mem_ranges[2:] + PolicyManager(range=r, kvm_map=False, channel_index=str(i)) for i, r in enumerate(self.mem_ranges[2:]) ] self.loc_mem_ctrl = [MemCtrl() for i in range(8)] self.far_mem_ctrl = [MemCtrl() for i in range(2)] diff --git a/src/mem/PolicyManager.py b/src/mem/PolicyManager.py index 0483d0cfce..14dfb4363b 100644 --- a/src/mem/PolicyManager.py +++ b/src/mem/PolicyManager.py @@ -43,4 +43,6 @@ class PolicyManager(AbstractMemory): bypass_dcache = Param.Bool(False, "if the DRAM cache needs to be bypassed") + channel_index = Param.String("0","number of DRAM cache channels in the system") + diff --git a/src/mem/cache/replacement_policies/replaceable_entry.hh b/src/mem/cache/replacement_policies/replaceable_entry.hh index 5619429258..d8424c2cc7 100644 --- a/src/mem/cache/replacement_policies/replaceable_entry.hh +++ b/src/mem/cache/replacement_policies/replaceable_entry.hh @@ -69,7 +69,6 @@ class ReplaceableEntry bool dirtyLine; Addr farMemAddr; unsigned counter; - uint64_t blksAccessedEntered; uint64_t tickEntered; ReplaceableEntry(Addr _tagDC, Addr _indexDC, bool _validLine, bool _dirtyLine, Addr _farMemAddr) : @@ -79,7 +78,6 @@ class ReplaceableEntry dirtyLine(_dirtyLine), farMemAddr(_farMemAddr), counter(0), - blksAccessedEntered(0), tickEntered(MaxTick) { } diff --git a/src/mem/policy_manager.cc b/src/mem/policy_manager.cc index 43f1df6da8..f96cd3fd2e 100644 --- a/src/mem/policy_manager.cc +++ b/src/mem/policy_manager.cc @@ -32,6 +32,7 @@ PolicyManager::PolicyManager(const PolicyManagerParams &p): extreme(p.extreme), alwaysHit(p.always_hit), alwaysDirty(p.always_dirty), bypassDcache(p.bypass_dcache), + channelIndex(p.channel_index), frontendLatency(p.static_frontend_latency), backendLatency(p.static_backend_latency), numColdMisses(0), @@ -39,7 +40,7 @@ PolicyManager::PolicyManager(const PolicyManagerParams &p): infoCacheWarmupRatio(0.05), resetStatsWarmup(false), prevArrival(0), - blksInserted(0), blksAccessed(0), + blksInserted(0), retryLLC(false), retryLLCRepetitive(false), retryLLCFarMemWr(false), retryTagCheck(false), retryLocMemRead(false), retryFarMemRead(false), retryLocMemWrite(false), retryFarMemWrite(false), @@ -68,6 +69,7 @@ PolicyManager::PolicyManager(const PolicyManagerParams &p): } tagMetadataStore.push_back(tempSet); } + DPRINTF(PolicyManager, "policy manager initialized\n"); } Tick @@ -101,6 +103,8 @@ PolicyManager::recvAtomic(PacketPtr pkt) Tick PolicyManager::recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &backdoor) { + DPRINTF(PolicyManager, "recvAtomicBackdoor: %s %d\n", + pkt->cmdString(), pkt->getAddr()); Tick latency = recvAtomic(pkt); getBackdoor(backdoor); return latency; @@ -121,6 +125,10 @@ PolicyManager::recvFunctional(PacketPtr pkt) panic_if(!found, "Can't handle address range for packet %s\n", pkt->print()); + + DPRINTF(PolicyManager, "recvFunctional: %s %d\n", + pkt->cmdString(), pkt->getAddr()); + } Tick @@ -242,7 +250,6 @@ PolicyManager::recvTimingReq(PacketPtr pkt) // sendRespondToRequestor(pkt, frontendLatency); accessAndRespond(pkt, frontendLatency); - blksAccessed++; return true; } @@ -343,7 +350,6 @@ PolicyManager::recvTimingReq(PacketPtr pkt) // sendRespondToRequestor(pkt, frontendLatency); accessAndRespond(pkt, frontendLatency); - blksAccessed++; return true; } } @@ -2224,8 +2230,6 @@ PolicyManager::handleRequestorPkt(PacketPtr pkt) Addr index = returnIndexDC(pkt->getAddr(), pkt->getSize()); Addr way = findMatchingWay(index, tag); - blksAccessed++; - if (way == noMatchingWay) { // MISSED! Candidate = Either there's an empty way to fill in or a victim will be selected. way = getCandidateWay(index); @@ -2234,8 +2238,6 @@ PolicyManager::handleRequestorPkt(PacketPtr pkt) capacityTracker[tagMetadataStore.at(index).at(way)->farMemAddr] = blksInserted; if (tagMetadataStore.at(index).at(way)->tickEntered != MaxTick) { polManStats.blkReuse.sample(tagMetadataStore.at(index).at(way)->counter); - polManStats.blksAccBeforeEvict.sample(blksAccessed - - tagMetadataStore.at(index).at(way)->blksAccessedEntered); assert(curTick() >= tagMetadataStore.at(index).at(way)->tickEntered); polManStats.ticksBeforeEviction.sample(curTick() - tagMetadataStore.at(index).at(way)->tickEntered); } @@ -2364,7 +2366,6 @@ PolicyManager::handleRequestorPkt(PacketPtr pkt) tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->counter++; } else { tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->counter = 1; - tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->blksAccessedEntered = blksAccessed; tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->tickEntered = curTick(); blksInserted++; @@ -3176,8 +3177,6 @@ PolicyManager::PolicyManagerStats::PolicyManagerStats(PolicyManager &_polMan) "Miss distance, to track capacity misses"), ADD_STAT(blkReuse, statistics::units::Count::get(), "cache line block reuse before eviction"), - ADD_STAT(blksAccBeforeEvict, statistics::units::Count::get(), - "# of accesses addressed before eviction of this blk"), ADD_STAT(ticksBeforeEviction, statistics::units::Count::get(), "how long the blk was in the cache") @@ -3240,10 +3239,6 @@ PolicyManager::PolicyManagerStats::regStats() .init(128) .flags(pdf | nozero); - blksAccBeforeEvict - .init(1024) - .flags(pdf | nozero); - ticksBeforeEviction .init(1024) .flags(pdf | nozero); @@ -3327,74 +3322,78 @@ PolicyManager::drain() void PolicyManager::serialize(CheckpointOut &cp) const { - ScopedCheckpointSection sec(cp, "tagMetadataStore"); - paramOut(cp, "numEntries", tagMetadataStore.size()*assoc); + warn_if(numColdMisses > tagMetadataStore.size()*assoc, "numColdMisses is more than the total blocks!"); + DPRINTF(ChkptRstrTest, "name: %s\n", "tagMetadataStore"+channelIndex); + + ScopedCheckpointSection sec(cp, "tagMetadataStore"+channelIndex); + paramOut(cp, "numValidEntries", numColdMisses); int count = 0; int invalids = 0; for (auto const &set : tagMetadataStore) { for (auto const way : set) { ScopedCheckpointSection sec_entry(cp,csprintf("Entry%d", count++)); if (way->validLine) { - paramOut(cp, "validLine", way->validLine); paramOut(cp, "dirtyLine", way->dirtyLine); paramOut(cp, "farMemAddr", way->farMemAddr); - DPRINTF(ChkptRstrTest, "v: %d, %d, %d, %d, %d\n", - way->farMemAddr, - way->indexDC, way->tagDC, - way->validLine, way->dirtyLine); + paramOut(cp, "counter", way->counter); + paramOut(cp, "tickEntered", way->tickEntered); + // DPRINTF(ChkptRstrTest, "v: %d, %d, %d, %d, %d\n", + // way->farMemAddr, + // way->indexDC, way->tagDC, + // way->validLine, way->dirtyLine); } else { - paramOut(cp, "validLine", way->validLine); + // paramOut(cp, "validLine", way->validLine); invalids++; } } } + warn_if((tagMetadataStore.size()*assoc - numColdMisses) != invalids, "Number of invalids did not match\n"); DPRINTF(ChkptRstrTest, "invalids: %d\n", invalids); } void PolicyManager::unserialize(CheckpointIn &cp) -{ - ScopedCheckpointSection sec(cp, "tagMetadataStore"); +{ + DPRINTF(ChkptRstrTest, "name: %s\n", "tagMetadataStore"+channelIndex); + + ScopedCheckpointSection sec(cp, "tagMetadataStore"+channelIndex); int num_entries = 0; int countValid = 0; - paramIn(cp, "numEntries", num_entries); - warn_if(num_entries > tagMetadataStore.size()*assoc, "Unserializing larger tag " - "store into a smaller tag store. Stopping when index doesn't fit"); - warn_if(num_entries < tagMetadataStore.size()*assoc, "Unserializing smaller " - "tag store into a larger tag store. Not fully warmed up."); + paramIn(cp, "numValidEntries", num_entries); for (int i = 0; i < num_entries; i++) { ScopedCheckpointSection sec_entry(cp,csprintf("Entry%d", i)); - bool valid = false; - Addr far_addr = -1; - paramIn(cp, "validLine", valid); - paramIn(cp, "farMemAddr", far_addr); - if (valid && getAddrRange().contains(far_addr)) { - countValid++; - bool dirty = false; - paramIn(cp, "dirtyLine", dirty); - - Addr index = returnIndexDC(far_addr, blockSize); - Addr tag = returnTagDC(far_addr, blockSize); - int way = findEmptyWay(index); - // once you stored LRU, come back here and call it instead of putting 0; - if (way ==-1) { - way = 0; // so it always works for direct-mapped - } - tagMetadataStore.at(index).at(way)->tagDC = tag; - tagMetadataStore.at(index).at(way)->indexDC = index; - tagMetadataStore.at(index).at(way)->validLine = valid; - tagMetadataStore.at(index).at(way)->dirtyLine = dirty; - tagMetadataStore.at(index).at(way)->farMemAddr = far_addr; - - DPRINTF(ChkptRstrTest, "%d, %d, %d, %d, %d\n", - tagMetadataStore.at(index).at(way)->farMemAddr, - tagMetadataStore.at(index).at(way)->tagDC, - tagMetadataStore.at(index).at(way)->indexDC, - tagMetadataStore.at(index).at(way)->validLine, - tagMetadataStore.at(index).at(way)->dirtyLine); - } + bool dirty; + Addr farAddr; + unsigned counter; + uint64_t tickEntered; + + paramIn(cp, "dirtyLine", dirty); + paramIn(cp, "farMemAddr",farAddr); + paramIn(cp, "counter", counter); + paramIn(cp, "tickEntered", tickEntered); + + assert(getAddrRange().contains(farAddr)); + countValid++; + Addr index = returnIndexDC(farAddr, blockSize); + Addr tag = returnTagDC(farAddr, blockSize); + int way = findEmptyWay(index); + // once you stored LRU, come back here and call it instead of putting 0; + if (way ==-1) { + way = 0; // so it always works for direct-mapped + } + tagMetadataStore.at(index).at(way)->tagDC = tag; + tagMetadataStore.at(index).at(way)->indexDC = index; + tagMetadataStore.at(index).at(way)->validLine = true; + tagMetadataStore.at(index).at(way)->dirtyLine = dirty; + tagMetadataStore.at(index).at(way)->farMemAddr = farAddr; + + // DPRINTF(ChkptRstrTest, "%d, %d, %d, %d, %d\n", + // tagMetadataStore.at(index).at(way)->farMemAddr, + // tagMetadataStore.at(index).at(way)->tagDC, + // tagMetadataStore.at(index).at(way)->indexDC, + // tagMetadataStore.at(index).at(way)->validLine, + // tagMetadataStore.at(index).at(way)->dirtyLine); } - DPRINTF(ChkptRstrTest, "valid: %d\n", countValid); } int diff --git a/src/mem/policy_manager.hh b/src/mem/policy_manager.hh index 834afdabaf..eae9a22f3d 100644 --- a/src/mem/policy_manager.hh +++ b/src/mem/policy_manager.hh @@ -139,6 +139,7 @@ class PolicyManager : public AbstractMemory bool alwaysHit; bool alwaysDirty; bool bypassDcache; + std::string channelIndex; /** * Pipeline latency of the controller frontend. The frontend @@ -295,7 +296,6 @@ class PolicyManager : public AbstractMemory std::unordered_map capacityTracker; uint64_t blksInserted; - uint64_t blksAccessed; /** @@ -516,7 +516,6 @@ class PolicyManager : public AbstractMemory statistics::Formula dirtyRatio; statistics::Histogram missDistance; statistics::Histogram blkReuse; - statistics::Histogram blksAccBeforeEvict; statistics::Histogram ticksBeforeEviction; }; diff --git a/src/python/gem5/components/memory/dram_interfaces/hbm.py b/src/python/gem5/components/memory/dram_interfaces/hbm.py index b6c0d1790f..daece11fad 100644 --- a/src/python/gem5/components/memory/dram_interfaces/hbm.py +++ b/src/python/gem5/components/memory/dram_interfaces/hbm.py @@ -277,7 +277,7 @@ class HBM_2000_4H_1x64(DRAMInterface): two_cycle_activate = True -class TDRAM_32(DRAMInterface): +class TDRAM(DRAMInterface): # 64-bit interface for a single pseudo channel device_bus_width = 32 diff --git a/test.sh b/test.sh index ac609f7206..ec94078f7d 100755 --- a/test.sh +++ b/test.sh @@ -1,5 +1,7 @@ -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/npb/bt3 --debug-flags=ChkptRstrTest configs-npb-gapbs-chkpt-restore/checkpoint_both.py 0 bt C RambusTagProbOpt & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/gapbs/bfs3 --debug-flags=ChkptRstrTest configs-npb-gapbs-chkpt-restore/checkpoint_both.py 1 bfs 22 RambusTagProbOpt & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/npb/bt4 --debug-flags=ChkptRstrTest configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C RambusTagProbOpt & +# build/X86_MESI_Two_Level/gem5.opt --outdir=cptTest/gapbs/bfs13 configs-npb-gapbs-archive/gapbs_checkpoint.py bfs 22 0 0 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/gapbs/bfs15-single --debug-flags=ChkptRstrTest configs-npb-gapbs-chkpt-restore/checkpoint_both.py bfs 22 +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/gapbs/bfs8 --debug-flags=PolicyManager configs-npb-gapbs-archive/gapbs_checkpoint.py bfs 22 RambusTagProbOpt 0 0 & -# build/X86_MESI_Two_Level/gem5.debug -re --outdir=rstrTest/npb/bt3 --debug-flags=ChkptRstrTest configs-npb-gapbs-chkpt-restore/restore_both.py 0 bt C RambusTagProbOpt 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.debug -re --outdir=rstrTest/gapbs/bfs3 --debug-flags=ChkptRstrTest configs-npb-gapbs-chkpt-restore/restore_both.py 1 bfs 22 RambusTagProbOpt 1 0 0 0 & \ No newline at end of file +# build/X86_MESI_Two_Level/gem5.debug -re --outdir=rstrTest/npb/bt3 --debug-flags=ChkptRstrTest configs-npb-gapbs-chkpt-restore/restore_both.py bt C RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.debug -re --outdir=rstrTest/gapbs/bfs3 --debug-flags=ChkptRstrTest configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 RambusTagProbOpt 1 0 0 0 & \ No newline at end of file From 91408e4e00b1a3fd3744ea4db30b31771aec5366 Mon Sep 17 00:00:00 2001 From: mbabaie Date: Mon, 6 Nov 2023 15:01:15 -0800 Subject: [PATCH 18/28] tested cpt and rstr worked, updated: serialize name and entry bug, added LRU to serialize, added atomicNonCache --- .../checkpoint_both.py | 142 ++++++++++-------- .../restore_both.py | 41 ++--- .../system/ruby_system_1channel.py | 6 + .../system/ruby_system_8channel.py | 6 + src/mem/cache/replacement_policies/base.hh | 6 + src/mem/cache/replacement_policies/lru_rp.cc | 16 ++ src/mem/cache/replacement_policies/lru_rp.hh | 7 + src/mem/policy_manager.cc | 51 ++++--- test.sh | 26 +++- 9 files changed, 199 insertions(+), 102 deletions(-) diff --git a/configs-npb-gapbs-chkpt-restore/checkpoint_both.py b/configs-npb-gapbs-chkpt-restore/checkpoint_both.py index 2d50956e5b..76d0992957 100644 --- a/configs-npb-gapbs-chkpt-restore/checkpoint_both.py +++ b/configs-npb-gapbs-chkpt-restore/checkpoint_both.py @@ -41,6 +41,7 @@ npb_benchmarks, ) + def writeBenchScript_GAPBS(dir, benchmark_name, size, synthetic): """ This method creates a script in dir which will be eventually @@ -62,6 +63,7 @@ def writeBenchScript_GAPBS(dir, benchmark_name, size, synthetic): return input_file_name + def writeBenchScript_NPB(dir, bench): """ This method creates a script in dir which will be eventually @@ -80,6 +82,76 @@ def writeBenchScript_NPB(dir, bench): bench_file.close() return file_name + +def do_warmup(): + prevTotalColdMisses = 0 + prevTotalMemReqs = 0 + numOfCacheBlks = 0 + if single_channel: + numOfCacheBlks = float(system.mem_ctrl.dram_cache_size / system.mem_ctrl.block_size) + else: + numOfCacheBlks = float(num_cpus * system.mem_ctrl[0].dram_cache_size / system.mem_ctrl[0].block_size) + print("Number of total cache blocks: {}".format(numOfCacheBlks)) + + iteration_duration = 100_000_000_000 # 100 ms + + for interval_number in range(30): # ~3 seconds + print("Interval number: {}".format(interval_number)) + intervalColdMisses = 0 + intervalMemReqs = 0 + currentColdMisses = 0 + currentMemReqs = 0 + start_tick = m5.curTick() + exit_event = m5.simulate(iteration_duration) + end_tick = m5.curTick() + + if exit_event.getCause() != "simulate() limit reached": + if ( + exit_event.getCause() == "workend" + or exit_event.getCause() == "workbegin" + ): + print("ROI bounds, continuing to stats ...") + else: + print(f"Exiting because {exit_event.getCause()}") + exit(1) + + simstats = get_simstat([polMan for polMan in system.mem_ctrl], prepare_stats=True) + for i in range(num_cpus): + ctrl = simstats.__dict__[f"mem_ctrl{i}"] + currentColdMisses += ctrl.numColdMisses.value + currentMemReqs += (ctrl.readReqs.value + ctrl.writeReqs.value) + + print(exit_event.getCause()+" /// new iter nums: {}, {}, {}, {}".format(currentColdMisses, + prevTotalColdMisses, currentMemReqs, prevTotalMemReqs)) + + assert currentColdMisses >= prevTotalColdMisses, "Number of total cold misses is wrong!" + assert currentMemReqs >= prevTotalMemReqs, "Number of total memory requests is wrong!" + intervalColdMisses = currentColdMisses - prevTotalColdMisses + intervalMemReqs = currentMemReqs - prevTotalMemReqs + + if currentColdMisses >= (numOfCacheBlks*0.95): + print("95%% of system's total DRAM cache is warmed up") + break + elif (interval_number >= 20 and + float(intervalColdMisses/intervalMemReqs) <= 0.06 and + (end_tick - start_tick) == iteration_duration): + print("Have run about 2 sec and cold misses " + "in 100 ms interval has been less than 6%%") + break + # m5.stats.dump() + # m5.stats.reset() + prevTotalColdMisses = currentColdMisses + prevTotalMemReqs = currentMemReqs + print("tot warmup: {}, iter warmup: {}, iter len: {}".format(float(currentColdMisses/numOfCacheBlks), + float(intervalColdMisses/intervalMemReqs), end_tick - start_tick)) + print("----------------------------------------------------------------------------------\n") + + print("\n") + if interval_number == 29 : + print("TIMEOUT!\n") + m5.stats.dump() + + def parse_options(): parser = argparse.ArgumentParser( description="For use with gem5. This script " @@ -108,18 +180,19 @@ def parse_options(): print("Wrong benchmark choice!") exit(1) + # These are constant across tests, no need to put them in the args synthetic = 1 num_cpus = 8 mem_sys = "MESI_Two_Level" - dcache_policy = "RambusTagProbOpt" + dcache_policy = "CascadeLakeNoPartWrs" dcache_size = "1GiB" # size of each channel - mem_size = "8GiB" # size of total main memory - mem_size_per_channel = "8GiB" + mem_size = "128GiB" # size of total main memory + mem_size_per_channel = "64GiB" assoc = 1 - singleChannel = True + single_channel = False # create the system we are going to simulate - if singleChannel: + if single_channel: system = RubySystem1Channel( kernel, disk, @@ -194,66 +267,17 @@ def parse_options(): print("Done booting Linux and reached to ROI") m5.stats.reset() print("Reset stats at the start of ROI") - start_tick = m5.curTick() - start_insts = system.totalInsts() # switching CPU to timing system.switchCpus(system.cpu, system.timingCpu) - print("Switched CPU from KVM to Timing!") + print("Switched CPU from KVM to timingCpu!") else: print(exit_event.getCause()) print("Unexpected termination of simulation !") exit(1) - print("Start to running intervals!") - totalColdMisses = 0 - numOfCacheBlks = 0 - if singleChannel: - numOfCacheBlks = system.mem_ctrl.dram_cache_size / system.mem_ctrl.block_size - else: - numOfCacheBlks = num_cpus * system.mem_ctrl[0].dram_cache_size / system.mem_ctrl[0].block_size - print(numOfCacheBlks) - - for interval_number in range(1): # 2.5 seconds - print("Interval number: {}\n".format(interval_number)) - intervalColdMisses = 0 - intervalTotalReqs = 0 - - exit_event = m5.simulate(100000000) # 100 ms - #if exit_event.getCause() != "simulate() limit reached": - # if ( - # exit_event.getCause() == "workend" - # or exit_event.getCause() == "workbegin" - # ): - # print("ROI bounds, continuing to stats ...") - # else: - # print(f"Exiting because {exit_event.getCause()}") - # exit(1) - # - #simstats = get_simstat([polMan for polMan in system.mem_ctrl], prepare_stats=True) - #for i in range(num_cpus): - # ctrl = simstats.__dict__[f"mem_ctrl{i}"] - # intervalColdMisses += ctrl.numColdMisses.value - # intervalTotalReqs += (ctrl.readReqs.value + ctrl.writeReqs.value) -# - #totalColdMisses += intervalColdMisses -# - #if totalColdMisses >= (numOfCacheBlks*0.95): - # print("95%% of system's total DRAM cache is warmed up") - # break - #elif (interval_number >= 150 and - # float(intervalColdMisses/intervalTotalReqs) <= 0.05 and - # exit_event.getCause() == "simulate() limit reached"): - # print("Have run at about 1.5 sec and cold misses in a 100 ms" - # "interval has been less than 5%%") - # break - #m5.stats.reset() - #print("Warmup ratio so far: {}\n".format(float(totalColdMisses/numOfCacheBlks))) - - print("Exited warmup iterations") - if interval_number == 249 : - print("TIMEOUT!\n") - m5.stats.dump() + print("Start to run intervals!") + do_warmup() + print("Finished warmup iterations") system.switchCpus(system.timingCpu, system.o3Cpu) print("switched from timing to O3") - m5.checkpoint(m5.options.outdir + "/cpt") - + m5.checkpoint(m5.options.outdir + "/cpt") \ No newline at end of file diff --git a/configs-npb-gapbs-chkpt-restore/restore_both.py b/configs-npb-gapbs-chkpt-restore/restore_both.py index b9076a6a1a..56722d0eec 100755 --- a/configs-npb-gapbs-chkpt-restore/restore_both.py +++ b/configs-npb-gapbs-chkpt-restore/restore_both.py @@ -37,6 +37,10 @@ from system import * from info import ( + text_info, + interval_info_1GBdramCache_3hr, + benchmark_choices_gapbs, + benchmark_choices_npb, gapbs_benchmarks, npb_benchmarks, ) @@ -182,22 +186,17 @@ def run(): print("wrong benchmark choice!") exit(1) + synthetic = 1 num_cpus = 8 - cpu_type = "Timing" mem_sys = "MESI_Two_Level" - synthetic = 1 dcache_size = "1GiB" # size of each channel - mem_size = "128GiB" + mem_size = "128GiB" # size of total main memory mem_size_per_channel = "64GiB" - single_channel_HBM = False - checkpoint_dir = "/home/babaie/projects/TDRAM-resubmission/8channelConfig/dramCacheController/cptTest/gapbs/bfs3/cpt" + single_channel = False - if args.isGAPBS == 1: - benchmark = args.benchmark - else: - benchmark = args.benchmark+"."+args.size+".x" - - if single_channel_HBM: + checkpoint_dir = "" + + if single_channel: system = RubySystem1Channel( kernel, disk, @@ -232,9 +231,11 @@ def run(): restore=True, ) - app = benchmark - if args.isGAPBS: - app = benchmark+"-"+args.size + app = "" + if args.benchmark in gapbs_benchmarks: + app = args.benchmark + "-" + args.size + elif args.benchmark in npb_benchmarks: + app = args.benchmark+"."+args.size+".x" if args.do_analysis: lpmanager = O3LooppointAnalysisManager() @@ -264,13 +265,17 @@ def run(): # Create and pass a script to the simulated system to run the reuired # benchmark - if args.isGAPBS: + if args.benchmark in gapbs_benchmarks: system.readfile = writeBenchScript_GAPBS( - m5.options.outdir, benchmark, args.size, synthetic + m5.options.outdir, + args.benchmark, + args.size, + synthetic ) - else: + elif args.benchmark in npb_benchmarks: system.readfile = writeBenchScript_NPB( - m5.options.outdir, benchmark + m5.options.outdir, + app ) # set up the root SimObject and start the simulation diff --git a/configs-npb-gapbs-chkpt-restore/system/ruby_system_1channel.py b/configs-npb-gapbs-chkpt-restore/system/ruby_system_1channel.py index c87d0860b7..da61e0dff1 100644 --- a/configs-npb-gapbs-chkpt-restore/system/ruby_system_1channel.py +++ b/configs-npb-gapbs-chkpt-restore/system/ruby_system_1channel.py @@ -160,6 +160,12 @@ def createCPU(self, num_cpus): self.mem_mode = "atomic_noncaching" self.createCPUThreads(self.cpu) + self.atomicNoncachingCpu = [ + X86NonCachingSimpleCPU(cpu_id=i, switched_out=True) + for i in range(num_cpus) + ] + self.createCPUThreads(self.atomicNoncachingCpu) + self.atomicCpu = [ X86AtomicSimpleCPU(cpu_id=i, switched_out=True) for i in range(num_cpus) diff --git a/configs-npb-gapbs-chkpt-restore/system/ruby_system_8channel.py b/configs-npb-gapbs-chkpt-restore/system/ruby_system_8channel.py index 1b148523e2..716017117c 100644 --- a/configs-npb-gapbs-chkpt-restore/system/ruby_system_8channel.py +++ b/configs-npb-gapbs-chkpt-restore/system/ruby_system_8channel.py @@ -206,6 +206,12 @@ def createCPU(self, num_cpus): self.mem_mode = "atomic_noncaching" self.createCPUThreads(self.cpu) + self.atomicNoncachingCpu = [ + X86NonCachingSimpleCPU(cpu_id=i, switched_out=True) + for i in range(num_cpus) + ] + self.createCPUThreads(self.atomicNoncachingCpu) + self.atomicCpu = [ X86AtomicSimpleCPU(cpu_id=i, switched_out=True) for i in range(num_cpus) diff --git a/src/mem/cache/replacement_policies/base.hh b/src/mem/cache/replacement_policies/base.hh index 2c23c950b2..fbd855985b 100644 --- a/src/mem/cache/replacement_policies/base.hh +++ b/src/mem/cache/replacement_policies/base.hh @@ -58,6 +58,12 @@ class Base : public SimObject Base(const Params &p) : SimObject(p) {} virtual ~Base() = default; + virtual Tick getLastTouchTick(const std::shared_ptr& + replacement_data) { return MaxTick; } + + virtual void setLastTouchTick(const std::shared_ptr& + replacement_data, Tick tick) {} + /** * Invalidate replacement data to set it as the next probable victim. * diff --git a/src/mem/cache/replacement_policies/lru_rp.cc b/src/mem/cache/replacement_policies/lru_rp.cc index cbec50eb73..f9a00c6705 100644 --- a/src/mem/cache/replacement_policies/lru_rp.cc +++ b/src/mem/cache/replacement_policies/lru_rp.cc @@ -45,6 +45,22 @@ LRU::LRU(const Params &p) { } +Tick +LRU::getLastTouchTick(const std::shared_ptr& + replacement_data) +{ + return std::static_pointer_cast(replacement_data)->lastTouchTick; +} + +void +LRU::setLastTouchTick(const std::shared_ptr& replacement_data, + Tick tick) +{ + // used for unserialization of a checkpoint + std::static_pointer_cast( + replacement_data)->lastTouchTick = tick; +} + void LRU::invalidate(const std::shared_ptr& replacement_data) { diff --git a/src/mem/cache/replacement_policies/lru_rp.hh b/src/mem/cache/replacement_policies/lru_rp.hh index 6feaa4f73d..af734518f0 100644 --- a/src/mem/cache/replacement_policies/lru_rp.hh +++ b/src/mem/cache/replacement_policies/lru_rp.hh @@ -65,6 +65,13 @@ class LRU : public Base LRU(const Params &p); ~LRU() = default; + Tick getLastTouchTick(const std::shared_ptr& + replacement_data) override; + + void setLastTouchTick(const std::shared_ptr& + replacement_data, Tick tick) override; + + /** * Invalidate replacement data to set it as the next probable victim. * Sets its last touch tick as the starting tick. diff --git a/src/mem/policy_manager.cc b/src/mem/policy_manager.cc index f96cd3fd2e..25264efa60 100644 --- a/src/mem/policy_manager.cc +++ b/src/mem/policy_manager.cc @@ -75,13 +75,13 @@ PolicyManager::PolicyManager(const PolicyManagerParams &p): Tick PolicyManager::recvAtomic(PacketPtr pkt) { + DPRINTF(PolicyManager, "recvAtomic: %s %d\n", + pkt->cmdString(), pkt->getAddr()); + if (!getAddrRange().contains(pkt->getAddr())) { panic("Can't handle address range for packet %s\n", pkt->print()); } - DPRINTF(PolicyManager, "recvAtomic: %s %d\n", - pkt->cmdString(), pkt->getAddr()); - panic_if(pkt->cacheResponding(), "Should not see packets where cache " "is responding"); @@ -3322,7 +3322,8 @@ PolicyManager::drain() void PolicyManager::serialize(CheckpointOut &cp) const { - warn_if(numColdMisses > tagMetadataStore.size()*assoc, "numColdMisses is more than the total blocks!"); + warn_if(numColdMisses > tagMetadataStore.size()*assoc, + "numColdMisses is more than the total blocks!"); DPRINTF(ChkptRstrTest, "name: %s\n", "tagMetadataStore"+channelIndex); ScopedCheckpointSection sec(cp, "tagMetadataStore"+channelIndex); @@ -3331,29 +3332,28 @@ PolicyManager::serialize(CheckpointOut &cp) const int invalids = 0; for (auto const &set : tagMetadataStore) { for (auto const way : set) { - ScopedCheckpointSection sec_entry(cp,csprintf("Entry%d", count++)); if (way->validLine) { + ScopedCheckpointSection sec_entry(cp,csprintf("Entry%d", count++)); paramOut(cp, "dirtyLine", way->dirtyLine); paramOut(cp, "farMemAddr", way->farMemAddr); paramOut(cp, "counter", way->counter); paramOut(cp, "tickEntered", way->tickEntered); - // DPRINTF(ChkptRstrTest, "v: %d, %d, %d, %d, %d\n", - // way->farMemAddr, - // way->indexDC, way->tagDC, - // way->validLine, way->dirtyLine); + Tick lastTouchTick = replacementPolicy->getLastTouchTick(way->replacementData); + assert(lastTouchTick != MaxTick); + paramOut(cp, "lastTouchTick", lastTouchTick); } else { - // paramOut(cp, "validLine", way->validLine); invalids++; } } } - warn_if((tagMetadataStore.size()*assoc - numColdMisses) != invalids, "Number of invalids did not match\n"); + warn_if((tagMetadataStore.size()*assoc - numColdMisses) != invalids, + "Number of invalids did not match\n"); DPRINTF(ChkptRstrTest, "invalids: %d\n", invalids); } void PolicyManager::unserialize(CheckpointIn &cp) -{ +{ DPRINTF(ChkptRstrTest, "name: %s\n", "tagMetadataStore"+channelIndex); ScopedCheckpointSection sec(cp, "tagMetadataStore"+channelIndex); @@ -3366,11 +3366,13 @@ PolicyManager::unserialize(CheckpointIn &cp) Addr farAddr; unsigned counter; uint64_t tickEntered; + Tick lastTouchTick; paramIn(cp, "dirtyLine", dirty); paramIn(cp, "farMemAddr",farAddr); paramIn(cp, "counter", counter); paramIn(cp, "tickEntered", tickEntered); + paramIn(cp, "lastTouchTick", lastTouchTick); assert(getAddrRange().contains(farAddr)); countValid++; @@ -3381,18 +3383,29 @@ PolicyManager::unserialize(CheckpointIn &cp) if (way ==-1) { way = 0; // so it always works for direct-mapped } + tagMetadataStore.at(index).at(way)->tagDC = tag; tagMetadataStore.at(index).at(way)->indexDC = index; tagMetadataStore.at(index).at(way)->validLine = true; tagMetadataStore.at(index).at(way)->dirtyLine = dirty; tagMetadataStore.at(index).at(way)->farMemAddr = farAddr; - - // DPRINTF(ChkptRstrTest, "%d, %d, %d, %d, %d\n", - // tagMetadataStore.at(index).at(way)->farMemAddr, - // tagMetadataStore.at(index).at(way)->tagDC, - // tagMetadataStore.at(index).at(way)->indexDC, - // tagMetadataStore.at(index).at(way)->validLine, - // tagMetadataStore.at(index).at(way)->dirtyLine); + tagMetadataStore.at(index).at(way)->counter = counter; + tagMetadataStore.at(index).at(way)->tickEntered = tickEntered; + replacementPolicy->setLastTouchTick( + tagMetadataStore.at(index).at(way)->replacementData, + lastTouchTick); + + DPRINTF(ChkptRstrTest, "%d, %d, %d, %d, %d, %d, %d, %d\n", + tagMetadataStore.at(index).at(way)->tagDC, + tagMetadataStore.at(index).at(way)->indexDC, + tagMetadataStore.at(index).at(way)->validLine, + tagMetadataStore.at(index).at(way)->dirtyLine, + tagMetadataStore.at(index).at(way)->farMemAddr, + tagMetadataStore.at(index).at(way)->counter, + tagMetadataStore.at(index).at(way)->tickEntered, + replacementPolicy->getLastTouchTick( + tagMetadataStore.at(index).at(way)->replacementData)); + } } diff --git a/test.sh b/test.sh index ec94078f7d..94e7533b2d 100755 --- a/test.sh +++ b/test.sh @@ -1,7 +1,21 @@ -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/npb/bt4 --debug-flags=ChkptRstrTest configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C RambusTagProbOpt & -# build/X86_MESI_Two_Level/gem5.opt --outdir=cptTest/gapbs/bfs13 configs-npb-gapbs-archive/gapbs_checkpoint.py bfs 22 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/gapbs/bfs15-single --debug-flags=ChkptRstrTest configs-npb-gapbs-chkpt-restore/checkpoint_both.py bfs 22 -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/gapbs/bfs8 --debug-flags=PolicyManager configs-npb-gapbs-archive/gapbs_checkpoint.py bfs 22 RambusTagProbOpt 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/gapbs/22/bc configs-npb-gapbs-chkpt-restore/checkpoint_both.py bc 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/checkpoint_both.py bfs 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/gapbs/22/cc configs-npb-gapbs-chkpt-restore/checkpoint_both.py cc 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/gapbs/22/pr configs-npb-gapbs-chkpt-restore/checkpoint_both.py pr 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sssp 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/gapbs/22/tc configs-npb-gapbs-chkpt-restore/checkpoint_both.py tc 22 & -# build/X86_MESI_Two_Level/gem5.debug -re --outdir=rstrTest/npb/bt3 --debug-flags=ChkptRstrTest configs-npb-gapbs-chkpt-restore/restore_both.py bt C RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.debug -re --outdir=rstrTest/gapbs/bfs3 --debug-flags=ChkptRstrTest configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 RambusTagProbOpt 1 0 0 0 & \ No newline at end of file +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/npb/C/bt configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/npb/C/cg configs-npb-gapbs-chkpt-restore/checkpoint_both.py cg C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/npb/C/ft configs-npb-gapbs-chkpt-restore/checkpoint_both.py ft C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/npb/C/is configs-npb-gapbs-chkpt-restore/checkpoint_both.py is C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/npb/C/lu configs-npb-gapbs-chkpt-restore/checkpoint_both.py lu C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/npb/C/mg configs-npb-gapbs-chkpt-restore/checkpoint_both.py mg C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/npb/C/sp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sp C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/npb/C/ua configs-npb-gapbs-chkpt-restore/checkpoint_both.py ua C & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/chkpt-timing-gap configs-npb-gapbs-chkpt-restore/checkpoint_both.py bfs 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/chkpt-timing-npb configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C & + +# build/X86_MESI_Two_Level/gem5.opt -re --debug-flags=ChkptRstrTest --outdir=rstrTest/gap/bfs-22-dirmap configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 RambusTagProbOpt 1 0 0 0 & +build/X86_MESI_Two_Level/gem5.opt -re --debug-flags=ChkptRstrTest --outdir=rstrTest/npb/bt-C-dirmap configs-npb-gapbs-chkpt-restore/restore_both.py bt C RambusTagProbOpt 1 0 0 0 & From 23b497ef7834075b8aba90068d1d39ae068584a2 Mon Sep 17 00:00:00 2001 From: mbabaie Date: Tue, 7 Nov 2023 18:46:34 -0800 Subject: [PATCH 19/28] modified the DRAM cache code and the scripts for atomic --- .../checkpoint_both.py | 31 +-- src/mem/policy_manager.cc | 180 +++++++++++++++++- src/mem/policy_manager.hh | 2 + src/mem/ruby/system/RubyPort.cc | 17 +- test.sh | 34 ++-- 5 files changed, 226 insertions(+), 38 deletions(-) diff --git a/configs-npb-gapbs-chkpt-restore/checkpoint_both.py b/configs-npb-gapbs-chkpt-restore/checkpoint_both.py index 76d0992957..0f8a17f42a 100644 --- a/configs-npb-gapbs-chkpt-restore/checkpoint_both.py +++ b/configs-npb-gapbs-chkpt-restore/checkpoint_both.py @@ -83,7 +83,7 @@ def writeBenchScript_NPB(dir, bench): return file_name -def do_warmup(): +def do_warmup(system, single_channel): prevTotalColdMisses = 0 prevTotalMemReqs = 0 numOfCacheBlks = 0 @@ -95,7 +95,7 @@ def do_warmup(): iteration_duration = 100_000_000_000 # 100 ms - for interval_number in range(30): # ~3 seconds + for interval_number in range(40): # ~4 seconds print("Interval number: {}".format(interval_number)) intervalColdMisses = 0 intervalMemReqs = 0 @@ -130,13 +130,20 @@ def do_warmup(): intervalMemReqs = currentMemReqs - prevTotalMemReqs if currentColdMisses >= (numOfCacheBlks*0.95): - print("95%% of system's total DRAM cache is warmed up") + print("95% of system's total DRAM cache is warmed up") break - elif (interval_number >= 20 and - float(intervalColdMisses/intervalMemReqs) <= 0.06 and + elif (interval_number >= 20 and interval_number < 30 and + float(intervalColdMisses/intervalMemReqs) <= 0.05 and + float(currentColdMisses/currentMemReqs) <= 0.01 and (end_tick - start_tick) == iteration_duration): print("Have run about 2 sec and cold misses " - "in 100 ms interval has been less than 6%%") + "in 100 ms interval has been less than 5% and" + "total cold misses is less than 1%") + break + elif (interval_number >= 30 and + float(currentColdMisses/currentMemReqs) <= 0.01): + print("Have run about 3 sec and total cold misses " + "are less than 1%") break # m5.stats.dump() # m5.stats.reset() @@ -186,8 +193,8 @@ def parse_options(): mem_sys = "MESI_Two_Level" dcache_policy = "CascadeLakeNoPartWrs" dcache_size = "1GiB" # size of each channel - mem_size = "128GiB" # size of total main memory - mem_size_per_channel = "64GiB" + mem_size = "8GiB" # size of total main memory + mem_size_per_channel = "4GiB" assoc = 1 single_channel = False @@ -268,16 +275,16 @@ def parse_options(): m5.stats.reset() print("Reset stats at the start of ROI") # switching CPU to timing - system.switchCpus(system.cpu, system.timingCpu) - print("Switched CPU from KVM to timingCpu!") + system.switchCpus(system.cpu, system.atomicNoncachingCpu) + print("Switched CPU from KVM to atomicNoncachingCpu!") else: print(exit_event.getCause()) print("Unexpected termination of simulation !") exit(1) print("Start to run intervals!") - do_warmup() + do_warmup(system,single_channel) print("Finished warmup iterations") - system.switchCpus(system.timingCpu, system.o3Cpu) + system.switchCpus(system.atomicNoncachingCpu, system.o3Cpu) print("switched from timing to O3") m5.checkpoint(m5.options.outdir + "/cpt") \ No newline at end of file diff --git a/src/mem/policy_manager.cc b/src/mem/policy_manager.cc index 25264efa60..59a345f264 100644 --- a/src/mem/policy_manager.cc +++ b/src/mem/policy_manager.cc @@ -86,7 +86,9 @@ PolicyManager::recvAtomic(PacketPtr pkt) "is responding"); // do the actual memory access and turn the packet into a response - access(pkt); + // access(pkt); + + handleRequestorPktAtomic(pkt); if (pkt->hasData()) { // this value is not supposed to be accurate, just enough to @@ -2223,6 +2225,92 @@ PolicyManager::handleNextState(reqBufferEntry* orbEntry) } } +void +PolicyManager::handleRequestorPktAtomic(PacketPtr pkt) +{ + Addr tag = returnTagDC(pkt->getAddr(), pkt->getSize()); + Addr index = returnIndexDC(pkt->getAddr(), pkt->getSize()); + Addr way = findMatchingWay(index, tag); + + if (way == noMatchingWay) { + // MISSED! Candidate = Either there's an empty way to + // fill in or a victim will be selected. + way = getCandidateWay(index); + + // This is the current resident that is about to leave. + if (tagMetadataStore.at(index).at(way)->validLine) { + capacityTracker[tagMetadataStore.at(index).at(way)->farMemAddr] = blksInserted; + polManStats.blkReuse.sample(tagMetadataStore.at(index).at(way)->counter); + assert(tagMetadataStore.at(index).at(way)->tickEntered != MaxTick); + assert(curTick() >= tagMetadataStore.at(index).at(way)->tickEntered); + polManStats.ticksBeforeEviction.sample( + curTick() - tagMetadataStore.at(index).at(way)->tickEntered + ); + } + } + + assert(way < assoc); + + polManStats.avgORBLen = ORB.size(); + polManStats.avgTagCheckQLenStrt = countTagCheckInORB(); + polManStats.avgLocRdQLenStrt = countLocRdInORB(); + polManStats.avgFarRdQLenStrt = countFarRdInORB(); + polManStats.avgLocWrQLenStrt = countLocWrInORB(); + polManStats.avgFarWrQLenStrt = countFarWr(); + + Addr addr = pkt->getAddr(); + unsigned burst_size = locBurstSize; + unsigned size = std::min((addr | (burst_size - 1)) + 1, + addr + pkt->getSize()) - addr; + + if(pkt->isRead()) { + polManStats.bytesReadSys += size; + polManStats.readPktSize[ceilLog2(size)]++; + polManStats.readReqs++; + } else { + polManStats.bytesWrittenSys += size; + polManStats.writePktSize[ceilLog2(size)]++; + polManStats.writeReqs++; + } + + bool isHit = checkHitOrMissAtomic(index, way, pkt); + bool wasDirty = tagMetadataStore.at(index).at(way)->validLine && + tagMetadataStore.at(index).at(way)->dirtyLine; + + // Updating Tag & Metadata + tagMetadataStore.at(index).at(way)->tagDC = tag; + tagMetadataStore.at(index).at(way)->indexDC = index; + tagMetadataStore.at(index).at(way)->validLine = true; + tagMetadataStore.at(index).at(way)->farMemAddr = pkt->getAddr(); + replacementPolicy->touch(tagMetadataStore.at(index).at(way)->replacementData, pkt); + + if (pkt->isRead() && !isHit) { + tagMetadataStore.at(index).at(way)->dirtyLine = false; + } + if (!pkt->isRead()) { // write + tagMetadataStore.at(index).at(way)->dirtyLine = true; + } + + if (isHit) { + tagMetadataStore.at(index).at(way)->counter++; + } else { + tagMetadataStore.at(index).at(way)->counter = 0; + tagMetadataStore.at(index).at(way)->tickEntered = curTick(); + + if (capacityTracker.find(pkt->getAddr()) != capacityTracker.end()) { + polManStats.missDistance.sample(blksInserted - capacityTracker[pkt->getAddr()]); + capacityTracker.erase(pkt->getAddr()); + } + + blksInserted++; + } + + DPRINTF(PolicyManager, "ORB+: adr= %d, index= %d, tag= %d, cmd= %s, isHit= %d, wasDirty= %d\n", + pkt->getAddr(), index, tag, pkt->cmdString(), + isHit, wasDirty); + +} + void PolicyManager::handleRequestorPkt(PacketPtr pkt) { @@ -2344,8 +2432,7 @@ PolicyManager::handleRequestorPkt(PacketPtr pkt) if (extreme) { orbEntry->prevDirty = alwaysDirty; } else { - orbEntry->prevDirty = tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->validLine && - tagMetadataStore.at(orbEntry->indexDC).at(orbEntry->wayNum)->dirtyLine; + orbEntry->prevDirty = checkDirty(orbEntry->indexDC, orbEntry->wayNum); } // Updating Tag & Metadata @@ -2401,6 +2488,91 @@ PolicyManager::checkConflictInORB(PacketPtr pkt) return false; } +bool +PolicyManager::checkHitOrMissAtomic(unsigned index, unsigned way, PacketPtr pkt) +{ + // look up the tagMetadataStore data structure to + // check if it's hit or miss + + bool currValid = tagMetadataStore.at(index).at(way)->validLine; + bool currDirty = tagMetadataStore.at(index).at(way)->dirtyLine; + + Addr tag = returnTagDC(pkt->getAddr(), blockSize); + + bool isHit = currValid && (tag == tagMetadataStore.at(index).at(way)->tagDC); + + if (isHit) { + + polManStats.numTotHits++; + + if (pkt->isRead()) { + polManStats.numRdHit++; + if (currDirty) { + polManStats.numRdHitDirty++; + } else { + polManStats.numRdHitClean++; + } + } else { + polManStats.numWrHit++; + if (currDirty) { + polManStats.numWrHitDirty++; + } else { + polManStats.numWrHitClean++; + } + } + + } else { + + polManStats.numTotMisses++; + + unsigned invalidBlocks = 0; + for (int i = 0; i < assoc; i++) { + if (!tagMetadataStore.at(index).at(i)->validLine) { + invalidBlocks++; + } + } + + if (invalidBlocks == assoc) { + polManStats.numColdMissesSet++; + } + + if (currValid) { + polManStats.numHotMisses++; + } else { + polManStats.numColdMisses++; + numColdMisses++; + } + + if (pkt->isRead()) { + if (currDirty && currValid) { + polManStats.numRdMissDirty++; + } else { + polManStats.numRdMissClean++; + } + } else { + if (currDirty && currValid) { + polManStats.numWrMissDirty++; + } else { + polManStats.numWrMissClean++; + } + + } + } + + if ((numColdMisses >= (unsigned)(infoCacheWarmupRatio * dramCacheSize/blockSize)) && !resetStatsWarmup) { + inform("DRAM cache warm up percentage : %f, @ %d .. \n", infoCacheWarmupRatio*100.0, curTick()); + infoCacheWarmupRatio = infoCacheWarmupRatio + 0.05; + } + + if ((numColdMisses >= (unsigned)(cacheWarmupRatio * dramCacheSize/blockSize)) && !resetStatsWarmup) { + inform("DRAM cache fully warmed up @ %d .. \n", curTick()); + // exitSimLoop("cacheIsWarmedup",0); + resetStatsWarmup = true; + } + + return isHit; +} + void PolicyManager::checkHitOrMiss(reqBufferEntry* orbEntry) { @@ -2483,7 +2655,7 @@ PolicyManager::checkHitOrMiss(reqBufferEntry* orbEntry) if ((numColdMisses >= (unsigned)(cacheWarmupRatio * dramCacheSize/blockSize)) && !resetStatsWarmup) { inform("DRAM cache fully warmed up @ %d .. \n", curTick()); - exitSimLoop("cacheIsWarmedup",0); + // exitSimLoop("cacheIsWarmedup",0); resetStatsWarmup = true; } } diff --git a/src/mem/policy_manager.hh b/src/mem/policy_manager.hh index eae9a22f3d..a00ee3f5d8 100644 --- a/src/mem/policy_manager.hh +++ b/src/mem/policy_manager.hh @@ -353,7 +353,9 @@ class PolicyManager : public AbstractMemory void sendRespondToRequestor(PacketPtr pkt, Tick static_latency); void printQSizes() {} void handleRequestorPkt(PacketPtr pkt); + void handleRequestorPktAtomic(PacketPtr pkt); void checkHitOrMiss(reqBufferEntry* orbEntry); + bool checkHitOrMissAtomic(unsigned index, unsigned way, PacketPtr pkt); bool checkDirty(Addr index, int way); void handleDirtyCacheLine(Addr dirtyLineAddr); bool checkConflictInORB(PacketPtr pkt); diff --git a/src/mem/ruby/system/RubyPort.cc b/src/mem/ruby/system/RubyPort.cc index 2e41c2f6cc..69177c0e08 100644 --- a/src/mem/ruby/system/RubyPort.cc +++ b/src/mem/ruby/system/RubyPort.cc @@ -367,13 +367,18 @@ RubyPort::MemResponsePort::recvAtomic(PacketPtr pkt) pkt->getAddr(), (MachineType)mem_interface_type); AbstractController *mem_interface = rs->m_abstract_controls[mem_interface_type][id.getNum()]; - Tick latency; - if (access_backing_store) { + // Tick latency; + // if (access_backing_store) { + // rs->getPhysMem(pkt->getAddr())->access(pkt); + // latency = 1000; + // } else { + // latency = mem_interface->recvAtomic(pkt); + // } + + Tick latency = mem_interface->recvAtomic(pkt); + if (access_backing_store) rs->getPhysMem(pkt->getAddr())->access(pkt); - latency = 1000; - } else { - latency = mem_interface->recvAtomic(pkt); - } + return latency; } diff --git a/test.sh b/test.sh index 94e7533b2d..af3c89f4bb 100755 --- a/test.sh +++ b/test.sh @@ -1,21 +1,23 @@ -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/gapbs/22/bc configs-npb-gapbs-chkpt-restore/checkpoint_both.py bc 22 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/checkpoint_both.py bfs 22 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/gapbs/22/cc configs-npb-gapbs-chkpt-restore/checkpoint_both.py cc 22 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/gapbs/22/pr configs-npb-gapbs-chkpt-restore/checkpoint_both.py pr 22 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sssp 22 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/gapbs/22/tc configs-npb-gapbs-chkpt-restore/checkpoint_both.py tc 22 & - -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/npb/C/bt configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/npb/C/cg configs-npb-gapbs-chkpt-restore/checkpoint_both.py cg C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/npb/C/ft configs-npb-gapbs-chkpt-restore/checkpoint_both.py ft C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/npb/C/is configs-npb-gapbs-chkpt-restore/checkpoint_both.py is C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/npb/C/lu configs-npb-gapbs-chkpt-restore/checkpoint_both.py lu C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/npb/C/mg configs-npb-gapbs-chkpt-restore/checkpoint_both.py mg C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/npb/C/sp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sp C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-timing/npb/C/ua configs-npb-gapbs-chkpt-restore/checkpoint_both.py ua C & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/bc configs-npb-gapbs-chkpt-restore/checkpoint_both.py bc 22 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/checkpoint_both.py bfs 22 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/cc configs-npb-gapbs-chkpt-restore/checkpoint_both.py cc 22 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/pr configs-npb-gapbs-chkpt-restore/checkpoint_both.py pr 22 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sssp 22 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/tc configs-npb-gapbs-chkpt-restore/checkpoint_both.py tc 22 & +## build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/bt configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C & +## build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/cg configs-npb-gapbs-chkpt-restore/checkpoint_both.py cg C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/ft configs-npb-gapbs-chkpt-restore/checkpoint_both.py ft C & +## build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/is configs-npb-gapbs-chkpt-restore/checkpoint_both.py is C & +## build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/lu configs-npb-gapbs-chkpt-restore/checkpoint_both.py lu C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/mg configs-npb-gapbs-chkpt-restore/checkpoint_both.py mg C & +## build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/sp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sp C & +## build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/ua configs-npb-gapbs-chkpt-restore/checkpoint_both.py ua C & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/chkpt-timing-gap configs-npb-gapbs-chkpt-restore/checkpoint_both.py bfs 22 & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/chkpt-timing-npb configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/chkpt-atomic-gap configs-npb-gapbs-chkpt-restore/checkpoint_both.py bfs 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/chkpt-atomic-npb configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C & + # build/X86_MESI_Two_Level/gem5.opt -re --debug-flags=ChkptRstrTest --outdir=rstrTest/gap/bfs-22-dirmap configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 RambusTagProbOpt 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --debug-flags=ChkptRstrTest --outdir=rstrTest/npb/bt-C-dirmap configs-npb-gapbs-chkpt-restore/restore_both.py bt C RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --debug-flags=ChkptRstrTest --outdir=rstrTest/npb/bt-C-dirmap configs-npb-gapbs-chkpt-restore/restore_both.py bt C RambusTagProbOpt 1 0 0 0 & From 2610d6a274a3aee58e4bf4ddc20cda877fd852a9 Mon Sep 17 00:00:00 2001 From: mbabaie Date: Fri, 10 Nov 2023 13:42:51 -0800 Subject: [PATCH 20/28] fixed the memory range issue and made the main memory single channel --- .../checkpoint_both.py | 25 +++-------- .../system/ruby_system_8channel.py | 42 +++++++++---------- test.sh | 24 +++++------ 3 files changed, 38 insertions(+), 53 deletions(-) diff --git a/configs-npb-gapbs-chkpt-restore/checkpoint_both.py b/configs-npb-gapbs-chkpt-restore/checkpoint_both.py index 0f8a17f42a..d462e08d8b 100644 --- a/configs-npb-gapbs-chkpt-restore/checkpoint_both.py +++ b/configs-npb-gapbs-chkpt-restore/checkpoint_both.py @@ -95,7 +95,7 @@ def do_warmup(system, single_channel): iteration_duration = 100_000_000_000 # 100 ms - for interval_number in range(40): # ~4 seconds + for interval_number in range(10): print("Interval number: {}".format(interval_number)) intervalColdMisses = 0 intervalMemReqs = 0 @@ -132,18 +132,8 @@ def do_warmup(system, single_channel): if currentColdMisses >= (numOfCacheBlks*0.95): print("95% of system's total DRAM cache is warmed up") break - elif (interval_number >= 20 and interval_number < 30 and - float(intervalColdMisses/intervalMemReqs) <= 0.05 and - float(currentColdMisses/currentMemReqs) <= 0.01 and - (end_tick - start_tick) == iteration_duration): - print("Have run about 2 sec and cold misses " - "in 100 ms interval has been less than 5% and" - "total cold misses is less than 1%") - break - elif (interval_number >= 30 and - float(currentColdMisses/currentMemReqs) <= 0.01): - print("Have run about 3 sec and total cold misses " - "are less than 1%") + elif (float(currentColdMisses/currentMemReqs) <= 0.01): + print("Total cold misses is less than 1% of the total mem requests") break # m5.stats.dump() # m5.stats.reset() @@ -154,7 +144,7 @@ def do_warmup(system, single_channel): print("----------------------------------------------------------------------------------\n") print("\n") - if interval_number == 29 : + if interval_number == 9: print("TIMEOUT!\n") m5.stats.dump() @@ -193,8 +183,7 @@ def parse_options(): mem_sys = "MESI_Two_Level" dcache_policy = "CascadeLakeNoPartWrs" dcache_size = "1GiB" # size of each channel - mem_size = "8GiB" # size of total main memory - mem_size_per_channel = "4GiB" + mem_size = "5GiB" # size of total main memory assoc = 1 single_channel = False @@ -208,7 +197,6 @@ def parse_options(): assoc, dcache_size, mem_size, - mem_size_per_channel, dcache_policy, 0, 0, @@ -224,7 +212,6 @@ def parse_options(): assoc, dcache_size, mem_size, - mem_size_per_channel, dcache_policy, 0, 0, @@ -286,5 +273,5 @@ def parse_options(): do_warmup(system,single_channel) print("Finished warmup iterations") system.switchCpus(system.atomicNoncachingCpu, system.o3Cpu) - print("switched from timing to O3") + print("switched from atomicNoncachingCpu to O3") m5.checkpoint(m5.options.outdir + "/cpt") \ No newline at end of file diff --git a/configs-npb-gapbs-chkpt-restore/system/ruby_system_8channel.py b/configs-npb-gapbs-chkpt-restore/system/ruby_system_8channel.py index 716017117c..fb28e1ec20 100644 --- a/configs-npb-gapbs-chkpt-restore/system/ruby_system_8channel.py +++ b/configs-npb-gapbs-chkpt-restore/system/ruby_system_8channel.py @@ -43,7 +43,6 @@ def __init__( assoc, dcache_size, # size of 1 channel main_mem_size, - mem_size_per_channel, policy, is_link, link_lat, @@ -119,6 +118,9 @@ def __init__( AddrRange(Addr("128MiB")), # kernel data AddrRange(0xC0000000, size=0x100000), # For I/0 ] + self._data_ranges + + self._total_data_range=[AddrRange( + 0x100000000, size=main_mem_size)] self.initFS(num_cpus) @@ -146,7 +148,6 @@ def __init__( self._createMemoryControllers( assoc, dcache_size, - mem_size_per_channel, policy, is_link, link_lat, @@ -249,7 +250,6 @@ def _createMemoryControllers( self, assoc, dcache_size, - mem_size_per_channel, policy, is_link, link_lat, @@ -263,7 +263,6 @@ def _createMemoryControllers( PolicyManager(range=r, kvm_map=False, channel_index=str(i)) for i, r in enumerate(self.mem_ranges[2:]) ] self.loc_mem_ctrl = [MemCtrl() for i in range(8)] - self.far_mem_ctrl = [MemCtrl() for i in range(2)] self.membusPolManFarMem = L2XBar(width=64) self.membusPolManFarMem.frontend_latency = link_lat @@ -302,23 +301,22 @@ def _createMemoryControllers( self.loc_mem_ctrl[i].port = self.mem_ctrl[i].loc_req_port # main memory - for i in range(2): - self.far_mem_ctrl[i] = MemCtrl() - self.far_mem_ctrl[i].dram = DDR5_4400_4x8( - range=AddrRange( - start=0x100000000, - size=self._main_mem_size, - masks=[1 << 6], - intlvMatch=i, - ), - in_addr_map=False, kvm_map=False, null = True - ) - self.far_mem_ctrl[i].dram.device_size = mem_size_per_channel - self.far_mem_ctrl[i].static_frontend_latency = "1ns" - self.far_mem_ctrl[i].static_backend_latency = "1ns" - self.far_mem_ctrl[i].dram.read_buffer_size = 64 - self.far_mem_ctrl[i].dram.write_buffer_size = 64 - self.membusPolManFarMem.mem_side_ports = self.far_mem_ctrl[i].port + self.far_mem_ctrl = MemCtrl() + self.far_mem_ctrl.dram = DDR5_4400_4x8( + range=AddrRange( + start=0x100000000, + size=self._main_mem_size, + # masks=[1 << 6], + # intlvMatch=i, + ), + in_addr_map=False, kvm_map=False, null = True + ) + self.far_mem_ctrl.dram.device_size = self._main_mem_size + self.far_mem_ctrl.static_frontend_latency = "1ns" + self.far_mem_ctrl.static_backend_latency = "1ns" + self.far_mem_ctrl.dram.read_buffer_size = 64 + self.far_mem_ctrl.dram.write_buffer_size = 64 + self.membusPolManFarMem.mem_side_ports = self.far_mem_ctrl.port def initFS(self, cpus): self.pc = Pc() @@ -414,7 +412,7 @@ def assignISAInt(irq, apicPin): ), X86E820Entry( addr=0x100000000, - size="%dB" % (self.mem_ranges[2].size()), + size="%dB" % (self._total_data_range[0].size()), range_type=1, ), ] diff --git a/test.sh b/test.sh index af3c89f4bb..118de0b604 100755 --- a/test.sh +++ b/test.sh @@ -1,17 +1,17 @@ -build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/bc configs-npb-gapbs-chkpt-restore/checkpoint_both.py bc 22 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/checkpoint_both.py bfs 22 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/cc configs-npb-gapbs-chkpt-restore/checkpoint_both.py cc 22 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/pr configs-npb-gapbs-chkpt-restore/checkpoint_both.py pr 22 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sssp 22 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/tc configs-npb-gapbs-chkpt-restore/checkpoint_both.py tc 22 & -## build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/bt configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C & -## build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/cg configs-npb-gapbs-chkpt-restore/checkpoint_both.py cg C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/bc configs-npb-gapbs-chkpt-restore/checkpoint_both.py bc 22 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/bfs2 configs-npb-gapbs-chkpt-restore/checkpoint_both.py bfs 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/cc configs-npb-gapbs-chkpt-restore/checkpoint_both.py cc 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/pr configs-npb-gapbs-chkpt-restore/checkpoint_both.py pr 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sssp 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/tc configs-npb-gapbs-chkpt-restore/checkpoint_both.py tc 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/bt configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/cg configs-npb-gapbs-chkpt-restore/checkpoint_both.py cg C & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/ft configs-npb-gapbs-chkpt-restore/checkpoint_both.py ft C & -## build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/is configs-npb-gapbs-chkpt-restore/checkpoint_both.py is C & -## build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/lu configs-npb-gapbs-chkpt-restore/checkpoint_both.py lu C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/is configs-npb-gapbs-chkpt-restore/checkpoint_both.py is C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/lu configs-npb-gapbs-chkpt-restore/checkpoint_both.py lu C & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/mg configs-npb-gapbs-chkpt-restore/checkpoint_both.py mg C & -## build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/sp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sp C & -## build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/ua configs-npb-gapbs-chkpt-restore/checkpoint_both.py ua C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/sp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sp C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/ua configs-npb-gapbs-chkpt-restore/checkpoint_both.py ua C & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/chkpt-timing-gap configs-npb-gapbs-chkpt-restore/checkpoint_both.py bfs 22 & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/chkpt-timing-npb configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C & From b8f7f0f81806ce0b2bbf651372ad03c245b0cfe0 Mon Sep 17 00:00:00 2001 From: mbabaie Date: Sun, 12 Nov 2023 14:55:25 -0800 Subject: [PATCH 21/28] fixed the packet size in tag and index calc and made main mem size specific to each app in the scripts --- .../checkpoint_both.py | 7 ++- configs-npb-gapbs-chkpt-restore/info.py | 31 ++++++++++++ .../restore_both.py | 8 +-- src/mem/policy_manager.cc | 18 ++++--- test.sh | 49 +++++++++++-------- 5 files changed, 76 insertions(+), 37 deletions(-) diff --git a/configs-npb-gapbs-chkpt-restore/checkpoint_both.py b/configs-npb-gapbs-chkpt-restore/checkpoint_both.py index d462e08d8b..0660b8c16e 100644 --- a/configs-npb-gapbs-chkpt-restore/checkpoint_both.py +++ b/configs-npb-gapbs-chkpt-restore/checkpoint_both.py @@ -39,6 +39,7 @@ from info import ( gapbs_benchmarks, npb_benchmarks, + main_mem_size, ) @@ -135,7 +136,7 @@ def do_warmup(system, single_channel): elif (float(currentColdMisses/currentMemReqs) <= 0.01): print("Total cold misses is less than 1% of the total mem requests") break - # m5.stats.dump() + m5.stats.dump() # m5.stats.reset() prevTotalColdMisses = currentColdMisses prevTotalMemReqs = currentMemReqs @@ -183,10 +184,12 @@ def parse_options(): mem_sys = "MESI_Two_Level" dcache_policy = "CascadeLakeNoPartWrs" dcache_size = "1GiB" # size of each channel - mem_size = "5GiB" # size of total main memory assoc = 1 single_channel = False + mem_size = main_mem_size(args.benchmark + "-" + args.size) # size of total main memory + print("main memory size: ", mem_size) + # create the system we are going to simulate if single_channel: system = RubySystem1Channel( diff --git a/configs-npb-gapbs-chkpt-restore/info.py b/configs-npb-gapbs-chkpt-restore/info.py index ea0a6b867c..cebceaeb3d 100644 --- a/configs-npb-gapbs-chkpt-restore/info.py +++ b/configs-npb-gapbs-chkpt-restore/info.py @@ -1,3 +1,34 @@ +main_mem_size = { + "bfs-22": ("2GiB"), + "bc-22": ("2GiB"), + "cc-22": ("2GiB"), + "pr-22": ("2GiB"), + "sssp-22": ("5GiB"), + "tc-22": ("2GiB"), + "bfs-25": ("10GiB"), + "bc-25": ("10GiB"), + "cc-25": ("10GiB"), + "pr-25": ("10GiB"), + "sssp-25": ("18GiB"), + "tc-25": ("10GiB"), + "bt-C": ("1GiB"), + "cg-C": ("1GiB"), + "ft-C": ("5GiB"), + "is-C": ("1GiB"), + "lu-C": ("1GiB"), + "mg-C": ("4GiB"), + "sp-C": ("1GiB"), + "ua-C": ("1GiB"), + "bt-D": ("11GiB"), + "cg-D": ("17GiB"), + "ft-D": ("85GiB"), + "is-D": ("34GiB"), + "lu-D": ("9GiB"), + "mg-D": ("27GiB"), + "sp-D": ("12GiB"), + "ua-D": ("8GiB"), +} + text_info = { # exe size start "bt.A.x": (0x00018402, 0x0000000000400E50), diff --git a/configs-npb-gapbs-chkpt-restore/restore_both.py b/configs-npb-gapbs-chkpt-restore/restore_both.py index 56722d0eec..5dee7e97a2 100755 --- a/configs-npb-gapbs-chkpt-restore/restore_both.py +++ b/configs-npb-gapbs-chkpt-restore/restore_both.py @@ -39,10 +39,9 @@ from info import ( text_info, interval_info_1GBdramCache_3hr, - benchmark_choices_gapbs, - benchmark_choices_npb, gapbs_benchmarks, npb_benchmarks, + main_mem_size, ) def writeBenchScript_GAPBS(dir, benchmark_name, size, synthetic): @@ -190,8 +189,7 @@ def run(): num_cpus = 8 mem_sys = "MESI_Two_Level" dcache_size = "1GiB" # size of each channel - mem_size = "128GiB" # size of total main memory - mem_size_per_channel = "64GiB" + mem_size = main_mem_size(args.benchmark + "-" + args.size) # size of total main memory single_channel = False checkpoint_dir = "" @@ -205,7 +203,6 @@ def run(): args.assoc, dcache_size, mem_size, - mem_size_per_channel, args.dcache_policy, args.is_link, args.link_lat, @@ -222,7 +219,6 @@ def run(): args.assoc, dcache_size, mem_size, - mem_size_per_channel, args.dcache_policy, args.is_link, args.link_lat, diff --git a/src/mem/policy_manager.cc b/src/mem/policy_manager.cc index 59a345f264..64f003e631 100644 --- a/src/mem/policy_manager.cc +++ b/src/mem/policy_manager.cc @@ -75,8 +75,8 @@ PolicyManager::PolicyManager(const PolicyManagerParams &p): Tick PolicyManager::recvAtomic(PacketPtr pkt) { - DPRINTF(PolicyManager, "recvAtomic: %s %d\n", - pkt->cmdString(), pkt->getAddr()); + DPRINTF(PolicyManager, "recvAtomic: %s %d %d\n", + pkt->cmdString(), pkt->getAddr(), pkt->getSize()); if (!getAddrRange().contains(pkt->getAddr())) { panic("Can't handle address range for packet %s\n", pkt->print()); @@ -2497,7 +2497,7 @@ PolicyManager::checkHitOrMissAtomic(unsigned index, unsigned way, PacketPtr pkt) bool currValid = tagMetadataStore.at(index).at(way)->validLine; bool currDirty = tagMetadataStore.at(index).at(way)->dirtyLine; - Addr tag = returnTagDC(pkt->getAddr(), blockSize); + Addr tag = returnTagDC(pkt->getAddr(), pkt->getSize()); bool isHit = currValid && (tag == tagMetadataStore.at(index).at(way)->tagDC); @@ -2663,8 +2663,6 @@ PolicyManager::checkHitOrMiss(reqBufferEntry* orbEntry) bool PolicyManager::checkDirty(Addr index, int way) { - // Addr index = returnIndexDC(addr, blockSize); - // Addr tag = returnTagDC(addr, blockSize); assert(way >= 0); if (extreme) { return alwaysDirty; @@ -3508,6 +3506,8 @@ PolicyManager::serialize(CheckpointOut &cp) const ScopedCheckpointSection sec_entry(cp,csprintf("Entry%d", count++)); paramOut(cp, "dirtyLine", way->dirtyLine); paramOut(cp, "farMemAddr", way->farMemAddr); + paramOut(cp, "tag", way->tagDC); + paramOut(cp, "index", way->indexDC); paramOut(cp, "counter", way->counter); paramOut(cp, "tickEntered", way->tickEntered); Tick lastTouchTick = replacementPolicy->getLastTouchTick(way->replacementData); @@ -3536,20 +3536,22 @@ PolicyManager::unserialize(CheckpointIn &cp) ScopedCheckpointSection sec_entry(cp,csprintf("Entry%d", i)); bool dirty; Addr farAddr; + Addr tag; + Addr index; unsigned counter; uint64_t tickEntered; Tick lastTouchTick; paramIn(cp, "dirtyLine", dirty); - paramIn(cp, "farMemAddr",farAddr); + paramIn(cp, "farMemAddr", farAddr); + paramIn(cp, "tag", tag); + paramIn(cp, "index", index); paramIn(cp, "counter", counter); paramIn(cp, "tickEntered", tickEntered); paramIn(cp, "lastTouchTick", lastTouchTick); assert(getAddrRange().contains(farAddr)); countValid++; - Addr index = returnIndexDC(farAddr, blockSize); - Addr tag = returnTagDC(farAddr, blockSize); int way = findEmptyWay(index); // once you stored LRU, come back here and call it instead of putting 0; if (way ==-1) { diff --git a/test.sh b/test.sh index 118de0b604..6f38b39a3d 100755 --- a/test.sh +++ b/test.sh @@ -1,23 +1,30 @@ -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/bc configs-npb-gapbs-chkpt-restore/checkpoint_both.py bc 22 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/bfs2 configs-npb-gapbs-chkpt-restore/checkpoint_both.py bfs 22 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/cc configs-npb-gapbs-chkpt-restore/checkpoint_both.py cc 22 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/pr configs-npb-gapbs-chkpt-restore/checkpoint_both.py pr 22 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sssp 22 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/22/tc configs-npb-gapbs-chkpt-restore/checkpoint_both.py tc 22 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/bt configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/cg configs-npb-gapbs-chkpt-restore/checkpoint_both.py cg C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/ft configs-npb-gapbs-chkpt-restore/checkpoint_both.py ft C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/is configs-npb-gapbs-chkpt-restore/checkpoint_both.py is C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/lu configs-npb-gapbs-chkpt-restore/checkpoint_both.py lu C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/mg configs-npb-gapbs-chkpt-restore/checkpoint_both.py mg C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/sp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sp C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/C/ua configs-npb-gapbs-chkpt-restore/checkpoint_both.py ua C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/25/bc configs-npb-gapbs-chkpt-restore/checkpoint_both.py bc 25 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/checkpoint_both.py bfs 25 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/25/cc configs-npb-gapbs-chkpt-restore/checkpoint_both.py cc 25 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/25/pr configs-npb-gapbs-chkpt-restore/checkpoint_both.py pr 25 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sssp 25 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/25/tc configs-npb-gapbs-chkpt-restore/checkpoint_both.py tc 25 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/D/bt configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt D & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/D/cg configs-npb-gapbs-chkpt-restore/checkpoint_both.py cg D & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/D/ft configs-npb-gapbs-chkpt-restore/checkpoint_both.py ft D & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/D/is configs-npb-gapbs-chkpt-restore/checkpoint_both.py is D & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/D/lu configs-npb-gapbs-chkpt-restore/checkpoint_both.py lu D & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/D/mg configs-npb-gapbs-chkpt-restore/checkpoint_both.py mg D & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/D/sp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sp D & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/D/ua configs-npb-gapbs-chkpt-restore/checkpoint_both.py ua D & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/chkpt-timing-gap configs-npb-gapbs-chkpt-restore/checkpoint_both.py bfs 22 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/chkpt-timing-npb configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/chkpt-atomic-gap configs-npb-gapbs-chkpt-restore/checkpoint_both.py bfs 22 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cptTest/chkpt-atomic-npb configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C & - -# build/X86_MESI_Two_Level/gem5.opt -re --debug-flags=ChkptRstrTest --outdir=rstrTest/gap/bfs-22-dirmap configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 RambusTagProbOpt 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --debug-flags=ChkptRstrTest --outdir=rstrTest/npb/bt-C-dirmap configs-npb-gapbs-chkpt-restore/restore_both.py bt C RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/gapbs/22/bc configs-npb-gapbs-chkpt-restore/checkpoint_both.py bc 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/checkpoint_both.py bfs 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/gapbs/22/cc configs-npb-gapbs-chkpt-restore/checkpoint_both.py cc 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/gapbs/22/pr configs-npb-gapbs-chkpt-restore/checkpoint_both.py pr 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sssp 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/gapbs/22/tc configs-npb-gapbs-chkpt-restore/checkpoint_both.py tc 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/npb/C/bt configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/npb/C/cg configs-npb-gapbs-chkpt-restore/checkpoint_both.py cg C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/npb/C/ft configs-npb-gapbs-chkpt-restore/checkpoint_both.py ft C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/npb/C/is configs-npb-gapbs-chkpt-restore/checkpoint_both.py is C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/npb/C/lu configs-npb-gapbs-chkpt-restore/checkpoint_both.py lu C & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/npb/C/mg configs-npb-gapbs-chkpt-restore/checkpoint_both.py mg C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/npb/C/sp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sp C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/npb/C/ua configs-npb-gapbs-chkpt-restore/checkpoint_both.py ua C & From 8638ba6d37ca0dce59f84923834cbc16e6dbc437 Mon Sep 17 00:00:00 2001 From: mbabaie Date: Sun, 12 Nov 2023 15:18:18 -0800 Subject: [PATCH 22/28] fixed the main mem size line in the scripts for the dictionary to read from --- configs-npb-gapbs-chkpt-restore/checkpoint_both.py | 2 +- configs-npb-gapbs-chkpt-restore/restore_both.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configs-npb-gapbs-chkpt-restore/checkpoint_both.py b/configs-npb-gapbs-chkpt-restore/checkpoint_both.py index 0660b8c16e..df5310e377 100644 --- a/configs-npb-gapbs-chkpt-restore/checkpoint_both.py +++ b/configs-npb-gapbs-chkpt-restore/checkpoint_both.py @@ -187,7 +187,7 @@ def parse_options(): assoc = 1 single_channel = False - mem_size = main_mem_size(args.benchmark + "-" + args.size) # size of total main memory + mem_size = main_mem_size[args.benchmark + "-" + args.size] # size of total main memory print("main memory size: ", mem_size) # create the system we are going to simulate diff --git a/configs-npb-gapbs-chkpt-restore/restore_both.py b/configs-npb-gapbs-chkpt-restore/restore_both.py index 5dee7e97a2..7e71cd7919 100755 --- a/configs-npb-gapbs-chkpt-restore/restore_both.py +++ b/configs-npb-gapbs-chkpt-restore/restore_both.py @@ -189,7 +189,7 @@ def run(): num_cpus = 8 mem_sys = "MESI_Two_Level" dcache_size = "1GiB" # size of each channel - mem_size = main_mem_size(args.benchmark + "-" + args.size) # size of total main memory + mem_size = main_mem_size[args.benchmark + "-" + args.size] # size of total main memory single_channel = False checkpoint_dir = "" From 81cbe2a2dc4e7044e30edffd7e74de93b3ea0a4d Mon Sep 17 00:00:00 2001 From: mbabaie Date: Mon, 13 Nov 2023 11:15:26 -0800 Subject: [PATCH 23/28] added a check point directory for restore --- .../restore_both.py | 18 +++-- test.sh | 74 ++++++++++++------- 2 files changed, 58 insertions(+), 34 deletions(-) diff --git a/configs-npb-gapbs-chkpt-restore/restore_both.py b/configs-npb-gapbs-chkpt-restore/restore_both.py index 7e71cd7919..5e67c09eb9 100755 --- a/configs-npb-gapbs-chkpt-restore/restore_both.py +++ b/configs-npb-gapbs-chkpt-restore/restore_both.py @@ -118,13 +118,14 @@ def parse_options(): type=int, help="bypass DRAM cache", ) - parser.add_argument("--do_analysis", action="store_true", default=False) + parser.add_argument("--do_analysis", action="store_true", default=True) return parser.parse_args() def do_analysis(): print( - "**************** Doing analysis! Simulating 100 intervals of 10ms each! ********************\n" + "**************** Doing analysis! Simulating " + "100 intervals of 10ms each! ********************\n" ) start = time.time() @@ -177,10 +178,13 @@ def run(): kernel = "/home/babaie/projects/TDRAM-resubmission/fsTools/x86-linux-kernel-4.19.83" disk = "" + suite = "" if args.benchmark in gapbs_benchmarks: disk = "/home/babaie/projects/TDRAM-resubmission/fsTools/x86-gapbs" + suite = "gapbs" elif args.benchmark in npb_benchmarks: disk = "/home/babaie/projects/TDRAM-resubmission/fsTools/x86-npb" + suite = "npb" else: print("wrong benchmark choice!") exit(1) @@ -192,8 +196,10 @@ def run(): mem_size = main_mem_size[args.benchmark + "-" + args.size] # size of total main memory single_channel = False - checkpoint_dir = "" - + checkpoint_dir = "/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/" + \ + suite + "/" + args.size + "/" + args.benchmark + "/" + "cpt" + print("Checkpoint dir: ", checkpoint_dir) + if single_channel: system = RubySystem1Channel( kernel, @@ -289,11 +295,11 @@ def run(): # instantiate all of the objects we've created above m5.instantiate(checkpoint_dir) - print("Running the simulation ************************************** \n") + print("Read the checkpoint. Now, running the simulation\n") if args.do_analysis: do_analysis() else: run() - print("End of simulation ******************************************** \n") + print("End of simulation\n") diff --git a/test.sh b/test.sh index 6f38b39a3d..86278cc2ee 100755 --- a/test.sh +++ b/test.sh @@ -1,30 +1,48 @@ -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/25/bc configs-npb-gapbs-chkpt-restore/checkpoint_both.py bc 25 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/checkpoint_both.py bfs 25 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/25/cc configs-npb-gapbs-chkpt-restore/checkpoint_both.py cc 25 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/25/pr configs-npb-gapbs-chkpt-restore/checkpoint_both.py pr 25 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sssp 25 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/gapbs/25/tc configs-npb-gapbs-chkpt-restore/checkpoint_both.py tc 25 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/D/bt configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt D & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/D/cg configs-npb-gapbs-chkpt-restore/checkpoint_both.py cg D & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/D/ft configs-npb-gapbs-chkpt-restore/checkpoint_both.py ft D & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/D/is configs-npb-gapbs-chkpt-restore/checkpoint_both.py is D & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/D/lu configs-npb-gapbs-chkpt-restore/checkpoint_both.py lu D & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/D/mg configs-npb-gapbs-chkpt-restore/checkpoint_both.py mg D & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/D/sp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sp D & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/8ch/chkpt-atomic/npb/D/ua configs-npb-gapbs-chkpt-restore/checkpoint_both.py ua D & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 CascadeLakeNoPartWrs 1 0 0 0 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 CascadeLakeNoPartWrs 1 0 0 0 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 CascadeLakeNoPartWrs 1 0 0 0 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 CascadeLakeNoPartWrs 1 0 0 0 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 CascadeLakeNoPartWrs 1 0 0 0 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C CascadeLakeNoPartWrs 1 0 0 0 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/gapbs/22/bc configs-npb-gapbs-chkpt-restore/checkpoint_both.py bc 22 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/checkpoint_both.py bfs 22 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/gapbs/22/cc configs-npb-gapbs-chkpt-restore/checkpoint_both.py cc 22 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/gapbs/22/pr configs-npb-gapbs-chkpt-restore/checkpoint_both.py pr 22 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sssp 22 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/gapbs/22/tc configs-npb-gapbs-chkpt-restore/checkpoint_both.py tc 22 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/npb/C/bt configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/npb/C/cg configs-npb-gapbs-chkpt-restore/checkpoint_both.py cg C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/npb/C/ft configs-npb-gapbs-chkpt-restore/checkpoint_both.py ft C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/npb/C/is configs-npb-gapbs-chkpt-restore/checkpoint_both.py is C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/npb/C/lu configs-npb-gapbs-chkpt-restore/checkpoint_both.py lu C & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/npb/C/mg configs-npb-gapbs-chkpt-restore/checkpoint_both.py mg C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/npb/C/sp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sp C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=cpt-resub/test/npb/C/ua configs-npb-gapbs-chkpt-restore/checkpoint_both.py ua C & +######## checkpoints ######## + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/25/bc configs-npb-gapbs-chkpt-restore/checkpoint_both.py bc 25 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/checkpoint_both.py bfs 25 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/25/cc configs-npb-gapbs-chkpt-restore/checkpoint_both.py cc 25 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/25/pr configs-npb-gapbs-chkpt-restore/checkpoint_both.py pr 25 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sssp 25 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/25/tc configs-npb-gapbs-chkpt-restore/checkpoint_both.py tc 25 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/D/bt configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt D & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/D/cg configs-npb-gapbs-chkpt-restore/checkpoint_both.py cg D & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/D/ft configs-npb-gapbs-chkpt-restore/checkpoint_both.py ft D & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/D/is configs-npb-gapbs-chkpt-restore/checkpoint_both.py is D & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/D/lu configs-npb-gapbs-chkpt-restore/checkpoint_both.py lu D & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/D/mg configs-npb-gapbs-chkpt-restore/checkpoint_both.py mg D & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/D/sp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sp D & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/D/ua configs-npb-gapbs-chkpt-restore/checkpoint_both.py ua D & + + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/22/bc configs-npb-gapbs-chkpt-restore/checkpoint_both.py bc 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/checkpoint_both.py bfs 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/22/cc configs-npb-gapbs-chkpt-restore/checkpoint_both.py cc 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/22/pr configs-npb-gapbs-chkpt-restore/checkpoint_both.py pr 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sssp 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/22/tc configs-npb-gapbs-chkpt-restore/checkpoint_both.py tc 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/bt configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/cg configs-npb-gapbs-chkpt-restore/checkpoint_both.py cg C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/ft configs-npb-gapbs-chkpt-restore/checkpoint_both.py ft C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/is configs-npb-gapbs-chkpt-restore/checkpoint_both.py is C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/lu configs-npb-gapbs-chkpt-restore/checkpoint_both.py lu C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/mg configs-npb-gapbs-chkpt-restore/checkpoint_both.py mg C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/sp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sp C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/ua configs-npb-gapbs-chkpt-restore/checkpoint_both.py ua C & From 295c7266d18cfa8f343f96d27ccd5c627c203caa Mon Sep 17 00:00:00 2001 From: mbabaie Date: Mon, 13 Nov 2023 22:51:50 -0800 Subject: [PATCH 24/28] aligned addresses to block size when the packet size is less than block size, only for atomic --- src/mem/policy_manager.cc | 24 +++++++++++++----------- test.sh | 24 ++++++++++++------------ 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/mem/policy_manager.cc b/src/mem/policy_manager.cc index 64f003e631..f956bf2070 100644 --- a/src/mem/policy_manager.cc +++ b/src/mem/policy_manager.cc @@ -75,15 +75,17 @@ PolicyManager::PolicyManager(const PolicyManagerParams &p): Tick PolicyManager::recvAtomic(PacketPtr pkt) { - DPRINTF(PolicyManager, "recvAtomic: %s %d %d\n", - pkt->cmdString(), pkt->getAddr(), pkt->getSize()); + DPRINTF(PolicyManager, "recvAtomic: %s %d %d %d\n", + pkt->cmdString(), pkt->getAddr(), pkt->getSize(), pkt->getBlockAddr(blockSize)); - if (!getAddrRange().contains(pkt->getAddr())) { + if (!getAddrRange().contains(pkt->getBlockAddr(blockSize))) { panic("Can't handle address range for packet %s\n", pkt->print()); } panic_if(pkt->cacheResponding(), "Should not see packets where cache " "is responding"); + + panic_if(pkt->getSize()==0, "Packet size should not be 0.\n"); // do the actual memory access and turn the packet into a response // access(pkt); @@ -2228,8 +2230,8 @@ PolicyManager::handleNextState(reqBufferEntry* orbEntry) void PolicyManager::handleRequestorPktAtomic(PacketPtr pkt) { - Addr tag = returnTagDC(pkt->getAddr(), pkt->getSize()); - Addr index = returnIndexDC(pkt->getAddr(), pkt->getSize()); + Addr tag = returnTagDC(pkt->getBlockAddr(blockSize), blockSize); + Addr index = returnIndexDC(pkt->getBlockAddr(blockSize), blockSize); Addr way = findMatchingWay(index, tag); if (way == noMatchingWay) { @@ -2281,7 +2283,7 @@ PolicyManager::handleRequestorPktAtomic(PacketPtr pkt) tagMetadataStore.at(index).at(way)->tagDC = tag; tagMetadataStore.at(index).at(way)->indexDC = index; tagMetadataStore.at(index).at(way)->validLine = true; - tagMetadataStore.at(index).at(way)->farMemAddr = pkt->getAddr(); + tagMetadataStore.at(index).at(way)->farMemAddr = pkt->getBlockAddr(blockSize); replacementPolicy->touch(tagMetadataStore.at(index).at(way)->replacementData, pkt); if (pkt->isRead() && !isHit) { @@ -2297,16 +2299,16 @@ PolicyManager::handleRequestorPktAtomic(PacketPtr pkt) tagMetadataStore.at(index).at(way)->counter = 0; tagMetadataStore.at(index).at(way)->tickEntered = curTick(); - if (capacityTracker.find(pkt->getAddr()) != capacityTracker.end()) { - polManStats.missDistance.sample(blksInserted - capacityTracker[pkt->getAddr()]); - capacityTracker.erase(pkt->getAddr()); + if (capacityTracker.find(pkt->getBlockAddr(blockSize)) != capacityTracker.end()) { + polManStats.missDistance.sample(blksInserted - capacityTracker[pkt->getBlockAddr(blockSize)]); + capacityTracker.erase(pkt->getBlockAddr(blockSize)); } blksInserted++; } - DPRINTF(PolicyManager, "ORB+: adr= %d, index= %d, tag= %d, cmd= %s, isHit= %d, wasDirty= %d\n", - pkt->getAddr(), index, tag, pkt->cmdString(), + DPRINTF(PolicyManager, "ORB+: adr= %d-> %d, index= %d, tag= %d, cmd= %s, isHit= %d, wasDirty= %d\n", + pkt->getAddr(), pkt->getBlockAddr(blockSize), index, tag, pkt->cmdString(), isHit, wasDirty); } diff --git a/test.sh b/test.sh index 86278cc2ee..20ad4bf14d 100755 --- a/test.sh +++ b/test.sh @@ -1,9 +1,9 @@ # build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 CascadeLakeNoPartWrs 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 CascadeLakeNoPartWrs 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 CascadeLakeNoPartWrs 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 CascadeLakeNoPartWrs 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 CascadeLakeNoPartWrs 1 0 0 0 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 CascadeLakeNoPartWrs 1 0 0 0 & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C CascadeLakeNoPartWrs 1 0 0 0 & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C CascadeLakeNoPartWrs 1 0 0 0 & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C CascadeLakeNoPartWrs 1 0 0 0 & @@ -37,12 +37,12 @@ build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resub # build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/22/cc configs-npb-gapbs-chkpt-restore/checkpoint_both.py cc 22 & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/22/pr configs-npb-gapbs-chkpt-restore/checkpoint_both.py pr 22 & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sssp 22 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/22/tc configs-npb-gapbs-chkpt-restore/checkpoint_both.py tc 22 & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/bt configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/cg configs-npb-gapbs-chkpt-restore/checkpoint_both.py cg C & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/22/tc configs-npb-gapbs-chkpt-restore/checkpoint_both.py tc 22 & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/bt configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/cg configs-npb-gapbs-chkpt-restore/checkpoint_both.py cg C & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/ft configs-npb-gapbs-chkpt-restore/checkpoint_both.py ft C & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/is configs-npb-gapbs-chkpt-restore/checkpoint_both.py is C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/lu configs-npb-gapbs-chkpt-restore/checkpoint_both.py lu C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/mg configs-npb-gapbs-chkpt-restore/checkpoint_both.py mg C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/sp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sp C & -# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/ua configs-npb-gapbs-chkpt-restore/checkpoint_both.py ua C & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/lu configs-npb-gapbs-chkpt-restore/checkpoint_both.py lu C & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/mg configs-npb-gapbs-chkpt-restore/checkpoint_both.py mg C & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/sp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sp C & +build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/ua configs-npb-gapbs-chkpt-restore/checkpoint_both.py ua C & From 1f1d6b1c5d70a485666c60fdc6651d9ef8f497fd Mon Sep 17 00:00:00 2001 From: mbabaie Date: Tue, 14 Nov 2023 11:12:55 -0800 Subject: [PATCH 25/28] fixed the address alignment tag check + added benchmark/size for checkpoint iterations --- configs-npb-gapbs-chkpt-restore/checkpoint_both.py | 13 +++++++++---- src/mem/policy_manager.cc | 4 ++-- test.sh | 14 +++++++------- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/configs-npb-gapbs-chkpt-restore/checkpoint_both.py b/configs-npb-gapbs-chkpt-restore/checkpoint_both.py index df5310e377..41a305609b 100644 --- a/configs-npb-gapbs-chkpt-restore/checkpoint_both.py +++ b/configs-npb-gapbs-chkpt-restore/checkpoint_both.py @@ -84,7 +84,7 @@ def writeBenchScript_NPB(dir, bench): return file_name -def do_warmup(system, single_channel): +def do_warmup(system, single_channel, benchmark, size): prevTotalColdMisses = 0 prevTotalMemReqs = 0 numOfCacheBlks = 0 @@ -95,8 +95,13 @@ def do_warmup(system, single_channel): print("Number of total cache blocks: {}".format(numOfCacheBlks)) iteration_duration = 100_000_000_000 # 100 ms + num_of_iterations = 10 + if benchmark == "is" and size == "C": + num_of_iterations = 4 - for interval_number in range(10): + print("Doing {} iterations of {} ps for DRAM $ warmup".format(num_of_iterations, iteration_duration)) + + for interval_number in range(num_of_iterations): print("Interval number: {}".format(interval_number)) intervalColdMisses = 0 intervalMemReqs = 0 @@ -145,7 +150,7 @@ def do_warmup(system, single_channel): print("----------------------------------------------------------------------------------\n") print("\n") - if interval_number == 9: + if interval_number == (num_of_iterations-1): print("TIMEOUT!\n") m5.stats.dump() @@ -273,7 +278,7 @@ def parse_options(): exit(1) print("Start to run intervals!") - do_warmup(system,single_channel) + do_warmup(system,single_channel, args.benchmark, args.size) print("Finished warmup iterations") system.switchCpus(system.atomicNoncachingCpu, system.o3Cpu) print("switched from atomicNoncachingCpu to O3") diff --git a/src/mem/policy_manager.cc b/src/mem/policy_manager.cc index f956bf2070..482563312b 100644 --- a/src/mem/policy_manager.cc +++ b/src/mem/policy_manager.cc @@ -2307,7 +2307,7 @@ PolicyManager::handleRequestorPktAtomic(PacketPtr pkt) blksInserted++; } - DPRINTF(PolicyManager, "ORB+: adr= %d-> %d, index= %d, tag= %d, cmd= %s, isHit= %d, wasDirty= %d\n", + DPRINTF(PolicyManager, "ORB+: adr= %d -> %d, index= %d, tag= %d, cmd= %s, isHit= %d, wasDirty= %d\n", pkt->getAddr(), pkt->getBlockAddr(blockSize), index, tag, pkt->cmdString(), isHit, wasDirty); @@ -2499,7 +2499,7 @@ PolicyManager::checkHitOrMissAtomic(unsigned index, unsigned way, PacketPtr pkt) bool currValid = tagMetadataStore.at(index).at(way)->validLine; bool currDirty = tagMetadataStore.at(index).at(way)->dirtyLine; - Addr tag = returnTagDC(pkt->getAddr(), pkt->getSize()); + Addr tag = returnTagDC(pkt->getBlockAddr(blockSize), blockSize); bool isHit = currValid && (tag == tagMetadataStore.at(index).at(way)->tagDC); diff --git a/test.sh b/test.sh index 20ad4bf14d..1ce9ee231b 100755 --- a/test.sh +++ b/test.sh @@ -37,12 +37,12 @@ # build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/22/cc configs-npb-gapbs-chkpt-restore/checkpoint_both.py cc 22 & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/22/pr configs-npb-gapbs-chkpt-restore/checkpoint_both.py pr 22 & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sssp 22 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/22/tc configs-npb-gapbs-chkpt-restore/checkpoint_both.py tc 22 & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/bt configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/cg configs-npb-gapbs-chkpt-restore/checkpoint_both.py cg C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/gapbs/22/tc configs-npb-gapbs-chkpt-restore/checkpoint_both.py tc 22 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/bt configs-npb-gapbs-chkpt-restore/checkpoint_both.py bt C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/cg configs-npb-gapbs-chkpt-restore/checkpoint_both.py cg C & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/ft configs-npb-gapbs-chkpt-restore/checkpoint_both.py ft C & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/is configs-npb-gapbs-chkpt-restore/checkpoint_both.py is C & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/lu configs-npb-gapbs-chkpt-restore/checkpoint_both.py lu C & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/mg configs-npb-gapbs-chkpt-restore/checkpoint_both.py mg C & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/sp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sp C & -build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/ua configs-npb-gapbs-chkpt-restore/checkpoint_both.py ua C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/lu configs-npb-gapbs-chkpt-restore/checkpoint_both.py lu C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/mg configs-npb-gapbs-chkpt-restore/checkpoint_both.py mg C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/sp configs-npb-gapbs-chkpt-restore/checkpoint_both.py sp C & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/cpt-resub/8-ch/atomic/npb/C/ua configs-npb-gapbs-chkpt-restore/checkpoint_both.py ua C & From 77a527617a12424c449bfbee55e9d8b9cc4cfb4d Mon Sep 17 00:00:00 2001 From: mbabaie Date: Wed, 15 Nov 2023 00:33:43 -0800 Subject: [PATCH 26/28] collected pc-count and updated scripts with them --- configs-npb-gapbs-chkpt-restore/info.py | 30 +++++++++++ .../restore_both.py | 6 +-- test.sh | 50 +++++++++++++++++++ 3 files changed, 83 insertions(+), 3 deletions(-) diff --git a/configs-npb-gapbs-chkpt-restore/info.py b/configs-npb-gapbs-chkpt-restore/info.py index cebceaeb3d..8104951103 100644 --- a/configs-npb-gapbs-chkpt-restore/info.py +++ b/configs-npb-gapbs-chkpt-restore/info.py @@ -82,6 +82,36 @@ "sssp-25": (0x0000E692, 0x00000000004029C0), "tc-25": (0x0000DEE2, 0x0000000000402890), } +interval_info_3hr_8ch = { + "bt.C.x": (0x40b1d8,2957134), + "cg.C.x": (0x4019d8,60153824), + "ft.C.x": (0x400d70,11454498), + "is.C.x": (0x4017c9,52612048), + "lu.C.x": (0x402980,8470596), + "mg.C.x": (0x401b08,9190341), + "sp.C.x": (0x40c210,2945981), + "ua.C.x": (0x400f30,4947911), + "bc-22": (0x404e08,4540370), + "bfs-22": (0x4045a0,120090), + "cc-22": (0x404688,7166714), + "pr-22": (0x4036c0,39736389), + "sssp-22": (0x405390,2180804), + "tc-22": (0x40ca60,21336889), + "bc-25": (0x404e1a,4400725), + "bfs-25": (0x4038e0,13721118), + "cc-25": (0x4037b0,32296930), + "pr-25": (0x4036a0,1313177), + "sssp-25": (0x405441,17780676), + "tc-25": (0x40ca88,11859294), + "bt.D.x": (0x408148,2990727), + "cg.D.x": (0x4019d8,38877453), + "ft.D.x": (0x400d70,5825365), + "is.D.x": (0x401661,49311978), + "lu.D.x": (0x402da0,1468532), + "mg.D.x": (0x401920,4260635), + "sp.D.x": (0x409000,8073528), + "ua.D.x": (0x4039c4,1197504), +} interval_info_1hr = { # exe pc count diff --git a/configs-npb-gapbs-chkpt-restore/restore_both.py b/configs-npb-gapbs-chkpt-restore/restore_both.py index 5e67c09eb9..e614871b75 100755 --- a/configs-npb-gapbs-chkpt-restore/restore_both.py +++ b/configs-npb-gapbs-chkpt-restore/restore_both.py @@ -38,7 +38,7 @@ from info import ( text_info, - interval_info_1GBdramCache_3hr, + interval_info_3hr_8ch, gapbs_benchmarks, npb_benchmarks, main_mem_size, @@ -118,7 +118,7 @@ def parse_options(): type=int, help="bypass DRAM cache", ) - parser.add_argument("--do_analysis", action="store_true", default=True) + parser.add_argument("--do_analysis", action="store_true", default=False) return parser.parse_args() @@ -248,7 +248,7 @@ def run(): lplistener.validAddrRangeSize = text_info[app][0] core.probeListener = lplistener else: - pc, count = interval_info_1GBdramCache_3hr[app] + pc, count = interval_info_3hr_8ch[app] system.global_tracker = PcCountTrackerManager( targets=[PcCountPair(pc, count)] ) diff --git a/test.sh b/test.sh index 1ce9ee231b..5cae968de3 100755 --- a/test.sh +++ b/test.sh @@ -1,3 +1,53 @@ + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D RambusTagProbOpt 1 0 0 0 & + + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C RambusTagProbOpt 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C RambusTagProbOpt 1 0 0 0 & + +######## count pc ######## + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D CascadeLakeNoPartWrs 1 0 0 0 & + + # build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 CascadeLakeNoPartWrs 1 0 0 0 & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 CascadeLakeNoPartWrs 1 0 0 0 & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/pcCount-resub/8-ch/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 CascadeLakeNoPartWrs 1 0 0 0 & From e4de8ad8f8d7c47a4dd915bda9ec19672b801ba8 Mon Sep 17 00:00:00 2001 From: mbabaie Date: Thu, 30 Nov 2023 10:28:57 -0800 Subject: [PATCH 27/28] fixed serial/unserialization for set-associativity --- src/mem/policy_manager.cc | 24 +- test.sh | 839 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 859 insertions(+), 4 deletions(-) diff --git a/src/mem/policy_manager.cc b/src/mem/policy_manager.cc index 482563312b..156e423fad 100644 --- a/src/mem/policy_manager.cc +++ b/src/mem/policy_manager.cc @@ -3554,10 +3554,26 @@ PolicyManager::unserialize(CheckpointIn &cp) assert(getAddrRange().contains(farAddr)); countValid++; - int way = findEmptyWay(index); - // once you stored LRU, come back here and call it instead of putting 0; - if (way ==-1) { - way = 0; // so it always works for direct-mapped + int way = -1; + + if (assoc == 1) { + way = findEmptyWay(index); + // once you stored LRU, come back here and call it instead of putting 0; + if (way ==-1) { + way = 0; // so it always works for direct-mapped + } + } + if (assoc > 1) { + Addr indexNew = returnIndexDC(farAddr, blockSize); + Addr tagNew = returnTagDC(farAddr, blockSize); + way = findMatchingWay(indexNew, tagNew); + if (way == noMatchingWay) { + way = getCandidateWay(indexNew); + } + assert(way != -1); + assert(way < assoc); + index = indexNew; + tag = tagNew; } tagMetadataStore.at(index).at(way)->tagDC = tag; diff --git a/test.sh b/test.sh index 5cae968de3..73ac2bc2fc 100755 --- a/test.sh +++ b/test.sh @@ -1,4 +1,843 @@ + + +######### no-dc + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D CascadeLakeNoPartWrs 1 0 0 1 & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/qdel/no-dc/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C CascadeLakeNoPartWrs 1 0 0 1 & + + +######### no-dc link 750 + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D CascadeLakeNoPartWrs 1 1 1875 1 & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C CascadeLakeNoPartWrs 1 1 1875 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/no-dc/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C CascadeLakeNoPartWrs 1 1 1875 1 & + + +######### tdram link 750 + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D RambusTagProbOpt 1 1 1875 0 & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C RambusTagProbOpt 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/tdram/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C RambusTagProbOpt 1 1 1875 0 & + +######### cascade link 750 + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D CascadeLakeNoPartWrs 1 1 1875 0 & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C CascadeLakeNoPartWrs 1 1 1875 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/750/cascade/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C CascadeLakeNoPartWrs 1 1 1875 0 & + + +######### tdram 32 way + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D RambusTagProbOpt 32 0 0 0 & + + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C RambusTagProbOpt 32 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/32/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C RambusTagProbOpt 32 0 0 0 & + +######### tdram 4 way + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D RambusTagProbOpt 4 0 0 0 & + + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C RambusTagProbOpt 4 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/4/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C RambusTagProbOpt 4 0 0 0 & + +######### tdram 2 way + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D RambusTagProbOpt 2 0 0 0 & + + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C RambusTagProbOpt 2 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/2/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C RambusTagProbOpt 2 0 0 0 & + + +######### tdram 16 way + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D RambusTagProbOpt 16 0 0 0 & + + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C RambusTagProbOpt 16 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/16/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C RambusTagProbOpt 16 0 0 0 & + + + +######### tdram 8 way + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D RambusTagProbOpt 8 0 0 0 & + + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C RambusTagProbOpt 8 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/set-assoc/tdram/8/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C RambusTagProbOpt 8 0 0 0 & + +######### no-dc link 500 + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D CascadeLakeNoPartWrs 1 1 1250 1 & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C CascadeLakeNoPartWrs 1 1 1250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/no-dc/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C CascadeLakeNoPartWrs 1 1 1250 1 & + + +######### tdram link 500 + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D RambusTagProbOpt 1 1 1250 0 & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C RambusTagProbOpt 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/tdram/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C RambusTagProbOpt 1 1 1250 0 & + +######### cascade link 500 + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D CascadeLakeNoPartWrs 1 1 1250 0 & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C CascadeLakeNoPartWrs 1 1 1250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/500/cascade/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C CascadeLakeNoPartWrs 1 1 1250 0 & + + +######### no-dc link 250 + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D CascadeLakeNoPartWrs 1 1 625 1 & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C CascadeLakeNoPartWrs 1 1 625 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/no-dc/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C CascadeLakeNoPartWrs 1 1 625 1 & + + + +######### tdram link 250 + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D RambusTagProbOpt 1 1 625 0 & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C RambusTagProbOpt 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/tdram/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C RambusTagProbOpt 1 1 625 0 & + + + +######### cascade link 250 + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D CascadeLakeNoPartWrs 1 1 625 0 & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C CascadeLakeNoPartWrs 1 1 625 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/250/cascade/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C CascadeLakeNoPartWrs 1 1 625 0 & + + + +######### no-dc link 100 + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D CascadeLakeNoPartWrs 1 1 250 1 & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C CascadeLakeNoPartWrs 1 1 250 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/no-dc/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C CascadeLakeNoPartWrs 1 1 250 1 & + + +######### tdram link 100 + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D RambusTagProbOpt 1 1 250 0 & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C RambusTagProbOpt 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/tdram/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C RambusTagProbOpt 1 1 250 0 & + + +######### cascade link 100 + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D CascadeLakeNoPartWrs 1 1 250 0 & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C CascadeLakeNoPartWrs 1 1 250 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/100/cascade/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C CascadeLakeNoPartWrs 1 1 250 0 & + + + + +######### no-dc link 50 + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D CascadeLakeNoPartWrs 1 1 125 1 & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C CascadeLakeNoPartWrs 1 1 125 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/no-dc/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C CascadeLakeNoPartWrs 1 1 125 1 & + + +######### tdram link 50 + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D RambusTagProbOpt 1 1 125 0 & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C RambusTagProbOpt 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/tdram/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C RambusTagProbOpt 1 1 125 0 & + + + +######### cascade link 50 + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D CascadeLakeNoPartWrs 1 1 125 0 & +#build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D CascadeLakeNoPartWrs 1 1 125 0 & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C CascadeLakeNoPartWrs 1 1 125 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/link/50/cascade/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C CascadeLakeNoPartWrs 1 1 125 0 & + + +######### no-dc + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D CascadeLakeNoPartWrs 1 0 0 1 & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C CascadeLakeNoPartWrs 1 0 0 1 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/no-dc/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C CascadeLakeNoPartWrs 1 0 0 1 & + + + +######### cascade + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D CascadeLakeNoPartWrs 1 0 0 0 & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C CascadeLakeNoPartWrs 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/cascade/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C CascadeLakeNoPartWrs 1 0 0 0 & + + + +######### TDRAM-NP + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D Rambus 1 0 0 0 & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C Rambus 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram-np/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C Rambus 1 0 0 0 & + + +######### oracle + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/gapbs/25/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 25 Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/gapbs/25/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 25 Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/gapbs/25/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 25 Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/npb/D/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt D Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/npb/D/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg D Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/npb/D/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft D Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/npb/D/is configs-npb-gapbs-chkpt-restore/restore_both.py is D Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/npb/D/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu D Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/npb/D/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg D Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/npb/D/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp D Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/npb/D/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua D Oracle 1 0 0 0 & + +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/gapbs/22/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 22 Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/gapbs/22/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 22 Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/gapbs/22/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 22 Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/gapbs/22/pr configs-npb-gapbs-chkpt-restore/restore_both.py pr 22 Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/gapbs/22/sssp configs-npb-gapbs-chkpt-restore/restore_both.py sssp 22 Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/gapbs/22/tc configs-npb-gapbs-chkpt-restore/restore_both.py tc 22 Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/npb/C/bt configs-npb-gapbs-chkpt-restore/restore_both.py bt C Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/npb/C/cg configs-npb-gapbs-chkpt-restore/restore_both.py cg C Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/npb/C/ft configs-npb-gapbs-chkpt-restore/restore_both.py ft C Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/npb/C/is configs-npb-gapbs-chkpt-restore/restore_both.py is C Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/npb/C/lu configs-npb-gapbs-chkpt-restore/restore_both.py lu C Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/npb/C/mg configs-npb-gapbs-chkpt-restore/restore_both.py mg C Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/npb/C/sp configs-npb-gapbs-chkpt-restore/restore_both.py sp C Oracle 1 0 0 0 & +# build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/oracle/npb/C/ua configs-npb-gapbs-chkpt-restore/restore_both.py ua C Oracle 1 0 0 0 & + + + +####### tdram + # build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/gapbs/25/bc configs-npb-gapbs-chkpt-restore/restore_both.py bc 25 RambusTagProbOpt 1 0 0 0 & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/gapbs/25/bfs configs-npb-gapbs-chkpt-restore/restore_both.py bfs 25 RambusTagProbOpt 1 0 0 0 & # build/X86_MESI_Two_Level/gem5.opt -re --outdir=/home/babaie/projects/TDRAM-resubmission/result-resub/8-ch/baseline/tdram/gapbs/25/cc configs-npb-gapbs-chkpt-restore/restore_both.py cc 25 RambusTagProbOpt 1 0 0 0 & From 943106eaf0bf06e9870b8091fbb7975049efc18f Mon Sep 17 00:00:00 2001 From: mbabaie Date: Thu, 30 Nov 2023 11:24:58 -0800 Subject: [PATCH 28/28] fixed standard library so it has updated TDRAM, previoulsy had the older version name --- src/python/gem5/components/memory/dcache.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/python/gem5/components/memory/dcache.py b/src/python/gem5/components/memory/dcache.py index 7fe326cffc..56915f04a0 100644 --- a/src/python/gem5/components/memory/dcache.py +++ b/src/python/gem5/components/memory/dcache.py @@ -36,7 +36,7 @@ from m5.objects import AddrRange, DRAMInterface, Port, PolicyManager, L2XBar, IOXBar from typing import Type, Optional, Union, Sequence, Tuple, List from .memory import _try_convert -from .dram_interfaces.hbm import TDRAM_32 +from .dram_interfaces.hbm import TDRAM from .dram_interfaces.ddr4 import DDR4_2400_8x8 from .multi_channel import DualChannelDDR4_2400 from .single_channel import SingleChannelDDR4_2400 @@ -152,13 +152,13 @@ def get_memory_controllers(self): def get_mem_ports(self) -> Sequence[Tuple[AddrRange, Port]]: return [(self.policy_manager.range, self.policy_manager.port)] -def SingleChannelTDRAM32( +def SingleChannelTDRAM( size: Optional[str] = None, ) -> AbstractMemorySystem: if not size: size = "256MiB" return ChanneledMemory( - TDRAM_32, + TDRAM, 1, 64, size=size @@ -167,7 +167,7 @@ def SingleChannelTDRAM32( def CascadeLakeCache(cache_size) -> AbstractMemorySystem: return DCacheSystem( - SingleChannelTDRAM32, + SingleChannelTDRAM, SingleChannelDDR4_2400, 'CascadeLakeNoPartWrs', size='64GiB', @@ -175,7 +175,7 @@ def CascadeLakeCache(cache_size) -> AbstractMemorySystem: def OracleCache(cache_size) -> AbstractMemorySystem: return DCacheSystem( - SingleChannelTDRAM32, + SingleChannelTDRAM, SingleChannelDDR4_2400, 'Oracle', size='64GiB', @@ -183,7 +183,7 @@ def OracleCache(cache_size) -> AbstractMemorySystem: def RambusCache(cache_size) -> AbstractMemorySystem: return DCacheSystem( - SingleChannelTDRAM32, + SingleChannelTDRAM, SingleChannelDDR4_2400, 'Rambus', size='64GiB',