[Linux Kernel Block Layer第一篇] block layer架构设计

目录

1. single queue架构

2. multi-queue架构(blk-mq) 

3. 问题


随着SSD快速存储设备的发展,内核社区越发发现,存储的性能瓶颈从硬件存储设备转移到了内核block layer,主要因为当时的内核block layer是single hw queue的架构,导致cpu锁竞争问题严重,本文先提纲挈领的介绍内核block layer的架构演进,然后根据最新的架构研究内核源码的实现细节,直击内核block layer本质原理。

1. single queue架构

可以看到整个block layer只有一个硬件派发队列(相对于软件派发队列而言,下面讲到multi-queue架构就知道了),太多了竞争导致性能下降:

2. multi-queue架构(blk-mq) 

为了避免多cpu导致的锁竞争,当前内核引入了multi-queue架构,有几层含义:

1. 两层的queue架构

        per-cpu的software queue,避免cpu锁竞争

2. hardware queue

        充分发挥快速存储设备的并发能力,块设备驱动支持配置多个hardware queue

3. 问题

看到上面架构图之后我们会想到很多的问题:

  1. block layer怎么支持配置hardware queue的数量和队列深度?
  2. 如果存在多个hardware queue时,怎么管理software queue和hardware queue的映射关系
  3. block layer什么时候将software queue数据转发到hardware queue,以及hardware queue是怎么转发数据到block driver
  4. blk-mq架构内核是支持io scheduler算法的:比如kyber或者mq-deadline,这种调度算法引入之后,调度算法内部的队列和上图中software queue是什么关系?

上述问题在后续的分析文章当中都会一一得到答案。

好的,以下是使用 PyTorch 实现的 ResNet18 模型,其中第一层 layer 使用了 nn.Sequential: ```python import torch import torch.nn as nn class ResNetBlock(nn.Module): def __init__(self, in_channels, out_channels, stride=1): super(ResNetBlock, self).__init__() self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False) self.bn1 = nn.BatchNorm2d(out_channels) self.relu = nn.ReLU(inplace=True) self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False) self.bn2 = nn.BatchNorm2d(out_channels) self.stride = stride self.downsample = nn.Sequential( nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False), nn.BatchNorm2d(out_channels) ) if stride != 1 or in_channels != out_channels else None def forward(self, x): identity = x out = self.conv1(x) out = self.bn1(out) out = self.relu(out) out = self.conv2(out) out = self.bn2(out) if self.downsample is not None: identity = self.downsample(x) out += identity out = self.relu(out) return out class ResNet18(nn.Module): def __init__(self, num_classes=1000): super(ResNet18, self).__init__() self.conv1 = nn.Sequential( nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False), nn.BatchNorm2d(64), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=3, stride=2, padding=1) ) self.layer1 = nn.Sequential( ResNetBlock(64, 64), ResNetBlock(64, 64) ) self.layer2 = nn.Sequential( ResNetBlock(64, 128, stride=2), ResNetBlock(128, 128) ) self.layer3 = nn.Sequential( ResNetBlock(128, 256, stride=2), ResNetBlock(256, 256) ) self.layer4 = nn.Sequential( ResNetBlock(256, 512, stride=2), ResNetBlock(512, 512) ) self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) self.fc = nn.Linear(512, num_classes) def forward(self, x): x = self.conv1(x) x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) x = self.layer4(x) x = self.avgpool(x) x = torch.flatten(x, 1) x = self.fc(x) return x ``` 其中 `ResNetBlock` 是 ResNet 中的一个基本块,实现了两个卷积层和一个残差连接,与 BasicBlock 的功能类似。`ResNet18` 是整个 ResNet18 模型,由多个 ResNetBlock 组成的不同层级和一个全连接层组成。在 `ResNet18` 中,第一层使用了 nn.Sequential 实现,而其他层则是使用多个 ResNetBlock 组成的 nn.Sequential 实现的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值