gem5学习——存储系统(memory system)

 (本文是对官方教程gem5: Memory system的学习记录)

目录

MemObjects

Ports

Connections

Request

Packet

Access Types

Packet allocation protocol

 Timing Flow control

Response and Snoop ranges

总结


MemObjects

所有连接到存储系统对象的父类

包含2个纯虚函数,返回相应的连接端口,用于在结构上将MemObjects连接在一起。

  • getMasterPort(const std::string &name, PortID idx)
  • getSlavePort(const std::string &name, PortID idx)

Ports

存储对象互连的接口

以对的形式出现,任何一个存储对象都至少含有一个有用的端口。

  • MasterPort
  • SlavePort

函数(仍然以对的形式出现)

  • send*:被包含该端口的对象调用。例如:CPU调用myPort->sendTimingReq(pkt)来发送消息
  • recv:每一个send函数都有一个对应的recv函数,由接收端口调用。例如:在接收CPU消息的端口上将调用peer->recvTimingReq(pkt)

Connections

在Python文件中,使用赋值语句表示端口的连接。

例如:将CPU的端口连接到存储总线上

system.cpu.icache_port = system.membus.cpu_side_ports
system.cpu.dcache_port = system.membus.cpu_side_ports

在C++文件中,只需要实例化所有对象,其存储端口的连接在python文件中实现,在C++文件中不需要考虑互连。

Request

用于封装CPU或I/O设备提出的原始请求。

请求对象的参数一般只可修改一次,然后在整个传输过程中保持不变。请求对象的字段通常对实际系统中的设备不可用,因此它们通常只能用于统计或调试,而不能用作架构的值。(这句话不知道如何理解)

字段包括:

  • 虚地址。当请求直接在一个物理地址上(例如:DMA I/O设备)提出时,该字段无效。
  • 物理地址
  • 数据大小
  • 创建的时间和请求
  • 产生该请求的CPU/线程的ID。当该请求不是由CPU提出时,该字段无效。
  • 产生该请求的PC。当该请求不是由CPU提出时,该字段无效。

Packet

用于封装存储系统中两个对象之间的传输(例如:L1和L2 cache)。

与request的区别:单个request从请求者一路传输到最终目的地,然后返回,可能一路上由多个不同的packet传输。

packet字段的读取访问是通过存取器方法提供,这些方法可以验证正在读取的字段中的数据是否有效。包含以下内容:

  • 地址。用于在目标处路由和处理packet。
  • 大小
  • 处理数据的指针。处理函数包括:dataStatic(), dataDynamic(), dataDynamicArray(), allocate(), getPtr(), get(), set()
  • 状态。包括:Success, BadAddress, Not Acknowleged, and Unknown。
  • 与packet相关的命令属性列表
  • SenderState指针。一个虚拟的且不透明的结构,用于保存与packet相关但特定于发送设备(例如:MSHR)的状态。
  • CoherenceState指针。一个虚拟的且不透明的结构,用于保存与一致性相关的状态。
  • 指向请求的指针。

Access Types

端口支持3种访问类型:

  • Timing

最细节的访问类型,包含排队延迟资源冲突模型。一旦timing request在未来的某个时间点成功发送,发送请求的设备将获得响应或NACK(请求无法完成)。

  •  Atomic

一种快速的访问类型。用于快速转发和预热cache,并返回在没有任何资源争用和排队延迟的情况下完成请求的大致时间。当发送atomic访问时,函数返回时提供响应。

注意:Timing和Atomic访问在存储系统中不能共存。

  • Functional

与Atomic访问类似,Functional访问也是瞬时发生的(无资源争用和排队延迟)。但能与Timing或Atomic访问共存。

用于加载二进制文件、在仿真系统中检查/修改变量,并且允许将远程调试器附加到模拟器上。当设备接收到一个Functional访问时,如果它包含一个packet队列,则必须搜索所有packet以查找该访问正在影响的请求或响应,并且必须适当的更新它们。与Packet::intersect()fixPacket()两个函数相关。

Packet allocation protocol

packet对象的分配和释放协议与访问类型相关(这里讨论的是底层C++中的new/delete问题)

  • Atomic/Functional

packet对象由请求者拥有,响应者必须用响应覆盖请求包(通常使用Packet::makeResponse()方法)。无需为单个请求提供多个响应者。

由于响应总是在sendAtomic()或sendFunctional()返回之前生成,所以请求者可以静态的或在堆栈上分配packet对象

  •  Timing

Timing消息传输过程由两个单向消息组成,一个请求和一个响应。两种packet对象必须由发送者动态分配。接收者负责释放。(可选的优化:请求的接收者选择复用请求packet作为响应,可以消除由于调用delete和new而带来的开销)

 Timing Flow control

由于Timing请求不是瞬时的,需要流量控制。

过程:通过sendTiming()发送timing packet,返回true/false表示请求是否被接收。如果返回的是false,则对象不应该再尝试发送任何packet,直到接收到recvRetry()的调用。然后再尝试调用sendTiming()。对于需要响应的packet(pkt->needsResponse()被设置为true),任何存储对象可以通过将其结果修改为NACK并将其发送回来源地来拒绝确认(若为响应packet,将不能这么做)。

true/false返回值用于本地流量控制,NACK用于全局流量控制。

Response and Snoop ranges

响应和侦听范围

存储系统中的范围是通过让对地址范围敏感的设备在其从端口对象中实现getAddrRanges来处理。该方法返回一个它响应的地址范围表AddrRangeList。当这些范围发生变化时(例如:PCI配置发生),设备应该在其从端口上调用sendRangeChange(),以便新的范围被传播到整个层次结构。这正是init()期间发生的事情,所有内存对象都调用sendRangeChange(),然后一系列范围更新发生,直到所有的范围都被传播到系统中的所有总线。

总结

这一部分主要介绍了gem5存储系统中消息传输过程的实现,包括对象和协议控制。其中应该重点关注Timing访问类型,涉及到排队延迟和资源冲突。相关函数基本上在packet对象中实现(gem5/src/mem/packet.hh),可以进一步研究。

参考链接

gem5: Memory system

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值