https://mp.weixin.qq.com/s/kNQrhlf33AErK7IzalnUDw

 
简单介绍Fragmenter的实现。
 
 
1. 基本介绍
 
用于把上游节点地址空间范围比较大的访问请求,拆分成下游支持的多个地址空间范围较小的访问请求。
 
1) 类参数
 
a. minSize:向下游节点发起的最小的访问大小;
b. maxSize:上游节点可以下发的最大的访问大小;
c. alwaysMin:是否把所有上游节点的请求,都拆分成minSize大小的访问请求:
- 如果为真:把所有上游节点的请求,都拆分成minSize大小的访问请求;
- 如果为假:根据下游节点的能力大小来拆分上游节点的访问请求;
d. earlyAck:针对一个Put burst,是在第一个beat回复响应消息,还是再最后一个beat回复响应消息;
e. holdFirstDeny:针对一个Get burst,在出现denied时就一直保持,直到整个burst结束;
 
2) 参数限制
 
要求minSize/maxSize都是2的幂,并且minSize小于等于maxSize:
 
3) minSize/maxSize
 
a. 实例
其中:ramBeatBytes是RAM支持的访问大小的物理能力。而maxSize是Fragmenter能拆分的最大访问请求的大小。
 
b. minSize
 
minSize实际上更多的指代下游节点的物理能力,比如说总线宽度。
 
c. 实际访问大小
 
但上游节点的访问请求,可能会小于minSize。此时不需要拆分,直接以原请求大小透传即可。
比如:minSize = ramBeatBytes = 4,而Get请求的大小为2,即读取两个字节。
 
2. diplomacy node
 
1) 添加的编码位
 
a. fragmentBits:分片编号所需要占用的比特数;
b. fullBits:是否需要earlyAck所需要占用的比特数,All和None都不需要这个比特:
c. toggleBits:用于区分两个连续的burst请求的比特位;
d. addedBits:上面加在一起就是需要添加的全部比特位的数目;
 
2) expandTransfer
 
扩展Transfer x的大小:
a. 如果x为none,则不进行扩展;
b. 把x.max扩展为maxSize,即Fragmenter支持的最大传输大小;
c. x.min不变;
 
3) shrinkTransfer
 
缩小transfer x的大小:
A. 如果不要求把所有的请求都拆分成minSize大小,则不需要缩小x;
B. 如果要求把所有的请求都拆分成minSize大小:
a. 如果x.min大于minSize,那么该传输不支持;
b. 如果x.min小于等于minSize,则把x.max限定在不大于minSize;
 
总结:缩小的意思是把传输大小的最大值限定在minSize以下。
 
4) mapManager
 
放大或缩小manager支持的各项操作的传输大小:
a. 对Atomic操作的大小进行缩小;
b. 对Get/Put/Hint操作的大小进行放大;
 
根据注释:
a. Arithmetic操作透传:数学运算需要提供操作数,而操作数不能分片,所以只能透传;
b. Get/Put/Hint/Logical操作可以分片:相较之下,位运算的结果只与当前位相关,所以可以分片进行运算;
c. 不支持Acquire操作;
 
Arithmetic操作要把传输大小缩小可以理解,因为其不支持分片。Logical操作呢?可以把传输大小放大吗?我认为是可以的,所以这里针对supportsLogical,应该是expandTransfer,而不是shrinkTransfer。
 
但考虑到Logical操作是原子操作,分片后的多个Logical请求之间,是否会被插入其他的请求消息呢?有可能,为了避免这种情况,还是shrinkTransfer较为妥当,毕竟Fragmenter不处理这种同步问题。
 
5) diplomacy node
 
A. clientFn:把Fragmenter看到的上游节点的参数,转换为下游节点看到的Fragmenter的参数。
 
这里进行了如下调整:
a. name:名称为TLFragmenter;
b. sourceId:需要把分片号等信息编码进sourceId中,所以其范围扩大了;
c. requestFifo:需要下游节点实现按请求顺序返回响应信息;
 
B. managerFn:把Fragmenter看到的下游节点的参数,转换为上游节点看到的Fragmenter的参数。
 
这里把下游节点各manager支持的传输能力大小进行了转换。
 
3. lazy module
 
1) 成对的输入边和输出边
 
 
2) 如果不需要分片,则直连即可:
 
 
3) 限定条件
 
a. 所有manager的fifoId都相同,因为需要manager按顺序返回响应消息:
 
b. manager不支持cache:
 
 
c. minSize >= beatBytes
 
这里的beatBytes是真正的总线宽度,虽然minSize经常被设置为与beatBytes相同,但也可以比其大。如果minSize = 2 * beatBytes,那么Fragmenter拆分后的请求基本上都是包含2个beat的burst。
 
d. 上下游节点都不支持Cache:
 
 
e. 如果可能拒绝Get请求,那么需要保持deny信号:
 
 
f. 如果可能拒绝Put请求,那么不能提早对其进行响应:
 
4) beat数目
 
beatBytes是Fragmenter与下游节点之间的总线宽度,maxSize是上游节点向Fragmenter发起的请求的最大传输大小。
 
两者的商是最大传输大小的请求,最终对应的针对下游节点的请求的beat数。
 
对比一下:
maxSize/minSize:最大传输大小的请求,转化为针对下游节点的请求的数目。
如果minSize == beatBytes,那么这个请求的数目即是beat的数目。
如果minSize > beatBytes,那么这个请求的数目是指burst请求的数目。每个burst请求中包含多少个beat,则由minSize/beatBytes的值决定。
 
即:
maxSize/minSize = 分片的数目 = (burst)请求的数目
maxSize/beatBytes = 所有请求中beat的数目之和
 
5) maxDownSize
 
向下游发送请求时能使用的最大传输大小:
 
6) 响应相关的变量
 
这里不再详细介绍。
 
7) 响应处理
 
A. out.d.fire()
 
记录如下信息:
a. ackNum:如果是第一个响应消息,那么响应编号(ackNum)= dFirst_AckNum,后面逐个递减ack_Decrement;
b. 记录dOrig;
c. 从source中取出编码进去的toggle位;
 
B. 计算是否要EarlyAck:
 
其中,如果earlyAck的类型为只针对PutFull,那么则从source中取出相应的编码位;
 
C. drop
 
是否丢弃这一个响应消息:
a. 如果有数据,则不能drop;
b. 如果要EarlyAck,那么不是第一个的响应消息,都应该丢弃;
c. 如果非EarlyAck,那么不是最后一个的响应消息,都应该丢弃;
 
D. 把out.d导向in.d
 
 
E. 处理针对Put的denied信号:
 
若出现denied信号,则保持住:
需要注意的是:这里的保持denied信号,不是指在单个burst请求的多个beat之间保持。而是指在多个分片请求的响应消息之间保持,每个分片请求都有可能是burst请求。
 
F. 处理针对Get的denied信号:
 
 
8) 请求分片
 
A. 计算每个manager针对每种操作的最大传输能力
 
 
并转换为lg值:
这里如果manager支持的最大能力为0,也就是manager不支持这种操作,使用lgMinSize代替。注释里的意思是:我们寄希望于client不对某个manager发出他不支持的request,所以这里无论是使用lgMinSize代替或者其他任何值,都没有意义。
 
根据请求访问的地址,确定地址所属的manager,进而确定支持的最大传输大小:
 
B. 确定分片的最大大小:
 
 
C. 请求分片相关的变量
 
这里不做详细介绍。
 
D. 使用repeater重复in.a的请求
 
a. 从in.a输入,输出到in_a:
 
b. 何时重复in.a?
 
需要同时满足一下条件:
- 请求消息中没有数据:如果有数据就透传;
- 分片编号不为0,为0代表最后一个分片;
 
如果没有数据的请求,即Get/Hint请求消息,则把in.a的数据保存到最后一个分片发出为止。
 
Arithmetic/Logical都带有数据,但是他们的传输大小是被缩小了的,所以下游节点可以支持透传。如果是Put请求呢?其传输大小是被放大了的。这个问题下面单独研究。
 
E. 组装各个编码位:
 
 
F. 两点优化
 
a. 直连in.a.bits.data到out.a.bits.data,不需要repeater中转
 
这个问题会在下面单独研究。
 
b. 如果repeater.io.full为真,则out.a.bits.mask应当为全1
 
意思是说,如果当前正在发送一个分片,那么这个分片的大小包含下游节点支持的beatBytes中的所有字节。
 
9) 不支持Cache
 
 
4. Put请求
 
首先,下游节点支持的Put请求的大小,被Fragmenter放大了。
其次,Put请求不经过repeater,而直接传递给out.a。
 
那么问题来了:
a. Put请求是否分片?如果分片,原始请求在哪里缓存或者说阻塞以等待所有分片请求发完?
b. 如果in.a.bits.data直连out.a.bits.data会不会丢失数据?
 
进而,针对Get请求:
c. out.d.bits.data直连in.d.bits.data,会不会丢失数据?
 
直接说结论:这三个问题,实际上都牵涉到数据的传输。数据的传输是由beatBytes也就是总线位宽限定的(而不是请求中的size域)。
 
那么Fragmenter改变了上游节点和下游节点的总线宽度了吗?答案是没有。
 
跟一下代码:
 
a. channel a的data域的宽度由参数params.dataBits决定:
 
b. params在创建TLBundle时传入:
 
c. 创建输入边和输出边的TLBundle,分别使用输入边和输出边中的bundle参数:
 
d. TLBundleParameters中的dataBits取决于manager的beatBytes:
 
e. 这个manager是指TLManagerPortParameters:
 
也就是说:
a. Fragmenter与下游节点之间数据总线的宽度,由下游节点的beatBytes参数决定;
b. Fragmenter与上游节点之间数据总线的宽度,由Fragmenter的beatBytes参数决定;
 
Fragmenter的beatBytes参数由下游节点使用managerFn转换而来:
 
这个managerFn只改变了支持的能力的大小,并没有改变beatBytes的大小:
也就是说,改变了可以填到channel a的size域的值的大小,并没有改变数据总线的宽度。
 
这下就好理解了:
a. Put请求,无论size多大,数据终究需要受数据总线的限制,一个beat一个beat的传输。在这种情况下Fragmenter逐个beat透传没有问题。
b. Get请求,无论size多大,返回的数据也终究需要收数据总线的限制,一个beat一个beat的传输。
 

Rocket - tilelink - Fragmenter的更多相关文章

  1. Rocket - tilelink - RegisterRouter

    https://mp.weixin.qq.com/s/DaJhf7hEoWsEi_AjwSrOfA   简单介绍RegisterRouter的实现.   ​​   1. 基本介绍   实现挂在Tile ...

  2. Rocket - tilelink - HintHandler

    https://mp.weixin.qq.com/s/MHW_aBSL72YNee9bVWWeaw   简单介绍HintHandler的实现.   ​​   1. 基本功能   实现Hint请求的处理 ...

  3. Rocket - tilelink - Nodes

    https://mp.weixin.qq.com/s/KJ8pVH76rdxPOZ1vE3QlKA   简单介绍tilelink对Diplomacy Nodes的实现.   ​​   1. TLImp ...

  4. Rocket - tilelink - AsyncCrossing

    https://mp.weixin.qq.com/s/v8plWCBD8vZkxykjJe4TCg   介绍AsyncCrossing的实现,主要介绍如何实现diplomacy Node和LazyMo ...

  5. Rocket - tilelink - mask

    https://mp.weixin.qq.com/s/Gqv09RIgSSg5VKe-wb4aGg   讨论tilelink中使用MaskGen生成mask的用法.   1. tilelink中的ma ...

  6. Rocket - tilelink - Parameters

    https://mp.weixin.qq.com/s/1I6DcONr0Mg7xiX8F1C7SQ   简单介绍TileLink相关的参数实现(具体问题暂时不展开,后续用到时再做分析).   ​​   ...

  7. Rocket - tilelink - Bundles

    https://mp.weixin.qq.com/s/jrqBg2AIpQogBrpwNXjmwg   简单介绍Bundles文件中对TileLink规范(1.7.1)的定义. 参考链接:https: ...

  8. Rocket - tilelink - TLBusWrapper.to

    https://mp.weixin.qq.com/s/jSnhBzU5_ayQCg5fWAcx-g 简单介绍TLBusWrapper.to()的实现.主要介绍确定this{...}对应代码的过程. 1 ...

  9. Rocket - tilelink - BusWrapper

    https://mp.weixin.qq.com/s/03BvgTNQtD75Guco6gUGQg   简单介绍BusWrapper的实现.   1. HasTLBusParams   定义SoC的挂 ...

随机推荐

  1. Spring Cloud 学习 之 Spring Cloud Ribbon(基础知识铺垫)

    文章目录 1.负载均衡: 2.RestTemplate详解: xxxForEntity/xxxForObject:主要介绍get跟post exchange: execute源码分析: 1.负载均衡: ...

  2. 使用天祥TX-1C调试DS18B20温度传感器的收获

    翻查DS18B20的DataSheet编写操作函数,其过程遇到了不少坎,记下来备查. 对于单总线的DS18B20芯片,首先严格按照时序图写出正确的“写0”.“写1”和“读0.1”的基础函数,再以此写出 ...

  3. 推荐算法_CIKM-2019-AnalytiCup 冠军源码解读

    最近在帮一初创app写推荐系统,顺便学习一波用户兴趣高速检索的冠军算法. 写总结前贴出冠军代码的git地址:https://github.com/ChuanyuXue/CIKM-2019-Analyt ...

  4. ReentrantLock源码解析

    ReentrantLock 1 数据结构 从上图可以看出,ReentrantLock的功能都是通过sync这个对象提供的. public class ReentrantLock implements ...

  5. Vue + Element-ui实现后台管理系统(3)---面包屑 + Tag标签切换功能

    面包屑 + Tag标签切换功能 有关后台管理系统之前写过两遍博客,看这篇之前最好先看下这两篇博客.另外这里只展示关键部分代码,项目代码放在github上: mall-manage-system 1.V ...

  6. Linux内核驱动学习(一)编写最简单Linux内核模块HelloWorld

    文章目录 准备工作 什么是内核模块 编写 hello.c 模块编译 相关指令 测试结果 模块加载 模块卸载 准备工作 在进行以下操作前,首先我准备了一台电脑,并且安装了虚拟机,系统是Ubuntu16. ...

  7. kubernetes部署redis主从高可用集群

    1.redis主从高可用集群结构 2.k8s部署有状态的服务选择 对于K8S集群有状态的服务,我们可以选择deployment和statefulset statefulset service& ...

  8. python --集合set的学习

    集合是一个无序的不重复的元素序列,一般我们使用set(value)函数来创建集合. 如下: 定义以及添加元素,以及注意点如下: 再如下:

  9. Gradle 多环境URL请求设置

    在开发过程中,多环境配置是经常遇到的,比如在Android开发过程中,在不同环境上请求服务器的URL是不同的,使用Gradle进行管理,是非常方便的. 首先查看工程目录结构: 使用AndroidStu ...

  10. 自动配置的Springboot内junit测试单元不能运行

    解决测试单元不能运行 问题:测试单元的 @Test 前面没有运行图标 解决 IDEA内:File - Setting - Plugins:搜到JUnitGenerator2.0,安装,重启IDEA 光 ...