使用 gem5

在 gem5 中建模内存

DRAM 和其他内存设备!


内存系统

gem5 的内存系统由两个主要组件组成

  1. 内存控制器
  2. 内存接口

Diagram of the gem5 memory system


内存控制器

MemCtrl 接收到数据包时…

  1. 数据包被排入读队列和/或写队列
  2. 应用调度算法(FCFS、FR-FCFS 等)来发出读写请求

Diagram of the gem5 memory controller queues


内存接口

Diagram of the gem5 memory interface


gem5 的内存控制器

Hierarchy of gem5 memory controller classes


gem5 的内存接口

Hierarchy of gem5 memory interface classes


内存模型的工作原理

该模型不是”周期精确的”,但它是周期级别的,与 DRAMSim 和 DRAMSys 等其他 DRAM 模拟器相比相当准确。

你可以为新型内存设备(例如 DDR6)扩展接口,但通常你会使用已经实现的接口。

gem5 内存通常配置的主要方式是通道数和通道/rank/bank/行/列位数,因为系统很少使用定制内存设备。


标准库中的内存

标准库将 DRAM/内存模型封装到 MemorySystem 中。

标准库中已经为你实现了很多示例。

请参阅 gem5/src/python/gem5/components/memory/multi_channel.pygem5/src/python/gem5/components/memory/single_channel.py 作为示例。

此外,


使用标准库运行示例

打开 materials/02-Using-gem5/06-memory/run-mem.py

该文件使用流量生成器(在之前见过)在 64GiB 处生成内存流量。

让我们看看使用简单内存时会发生什么。为内存系统添加以下行。

memory = SingleChannelSimpleMemory(latency="50ns", bandwidth="32GiB/s", size="8GiB", latency_var="10ns")

使用以下命令运行。使用 -c <LinearGenerator,RandomGenerator> 指定流量生成器,使用 -r <read percentage> 指定读取百分比。

gem5 run-mem.py

改变延迟和带宽

使用 16 GiB/s、32 GiB/s、64 GiB/s,以及 100% 读取和 50% 读取的运行结果。

带宽 读取百分比 线性速度 (GB/s) 随机速度 (GB/s)
16 GiB/s 100% 17.180288 17.180288
  50% 17.180288 17.180288
32 GiB/s 100% 34.351296 34.351296
  50% 34.351296 34.351296
64 GiB/s 100% 34.351296 34.351296
  50% 34.351296 34.351296

使用 SimpleMemory 时,你不会看到内存模型中的任何复杂行为(但它确实很快)。


运行通道化内存

def SingleChannelDDR4_2400(
    size: Optional[str] = None,
) -> AbstractMemorySystem:
    """
    A single channel memory system using DDR4_2400_8x8 based DIMM.
    """
    return ChanneledMemory(DDR4_2400_8x8, 1, 64, size=size)

运行通道化内存

替换

SingleChannelSimpleMemory(latency="50ns", bandwidth="32GiB/s", size="8GiB", latency_var="10ns")

SingleChannelDDR4_2400()

让我们看看运行测试时会发生什么


改变延迟和带宽

使用 16 GiB/s、32 GiB/s,以及 100% 读取和 50% 读取的运行结果。

带宽 读取百分比 线性速度 (GB/s) 随机速度 (GB/s)
16 GiB/s 100% 13.85856 14.557056
  50% 13.003904 13.811776
32 GiB/s 100% 13.85856 14.541312
  50% 13.058112 13.919488

正如预期的那样,由于读转写的转换,100% 读取比 50% 读取更高效。 同样如预期,带宽低于 SimpleMemory(仅约 75% 利用率)。

有点令人惊讶的是,建模的内存有足够的 bank 来高效处理随机流量。


添加新的通道化内存


添加新的通道化内存

然后在 lpddr2.py 的主体中添加以下内容:

def SingleChannelLPDDR2(
    size: Optional[str] = None,
) -> AbstractMemorySystem:
    return ChanneledMemory(LPDDR2_S4_1066_1x32, 1, 64, size=size)

然后我们通过以下方式将此类导入到脚本中:

from lpddr2 import SingleChannelLPDDR2

让我们再次测试这个!


改变延迟和带宽

使用 16 GiB/s,以及 100% 读取和 50% 读取的运行结果。

带宽 读取百分比 线性速度 (GB/s) 随机速度 (GB/s)
16 GiB/s 100% 4.089408 4.079552
  50% 3.65664 3.58816

LPDDR2 的性能不如 DDR4。


CommMonitor


CommMonitor

要修改的简单系统

Simple system diagram

让我们进行模拟:

运行

gem5 comm_monitor.py

CommMonitor

让我们添加 CommMonitor

Simple system with CommMonitor diagram


CommMonitor


地址交错

想法:我们可以并行化内存访问


地址交错

例如…

Diagram showing an example of address interleaving


地址交错

在 gem5 中使用地址交错


地址交错

有两个构造函数

构造函数 1:

AddrRange(Addr _start,
          Addr _end,
          const std::vector<Addr> &_masks,
          uint8_t _intlv_match)

_masks:掩码数组,其中选择器的第 k 位是由 masks[k] 指定的所有位的异或


地址交错

有两个构造函数

构造函数 2(旧版):

AddrRange(Addr _start,
          Addr _end,
          uint8_t _intlv_high_bit,
          uint8_t _xor_high_bit,
          uint8_t _intlv_bits,
          uint8_t _intlv_match)

选择器定义为两个范围:

addr[_intlv_high_bit:_intlv_low_bit] XOR addr[_xor_high_bit:_xor_low_bit]