已剪辑自: 链接
图1 分层的API调用
通常,如图1,一个复杂的系统都是分层的:
调用,是软硬件系统设计的基础。通过不同层次的模块间的调用,把各自不同的简单的模块,连接成一个庞大而复杂的整体系统。
2 软件调用
在高级语言编程里,如果我们把一个函数当做一个“模块”的话,那么从一个“模块”调用另一个“模块”就是我们通常非常熟悉的函数调用。
在x86的计算机系统中,一切的函数调用都要将不同的数据、地址压入或者弹出栈。我们直接通过实例来看函数是如何调用的。我们先来看看此时的栈是什么样的:
图2 被调用者栈帧的生成
此时调用者做了两件事情:
被调用者也做了两件事情:
这时,它成了是函数 MyFunction() 栈帧的栈底。这样,我们就保存了“调用者”函数的 %ebp,并且建立了一个新的栈帧。
下面的操作就好理解了。在 %ebp 更新后,我们先分配一块0x12字节的空间用于存放本地变量,这步一般都是用 sub 或者 mov 指令实现。在这里使用的是 movl。通过使用 mov 配合 -4(%ebp), -8(%ebp) 和 -12(%ebp) 我们便可以给 a, b 和 c 赋值了。
图3 本地变量赋值后的栈帧
接下来我们来看看函数是如何返回的。从下面这个例子我们可以看出,和调用函数时正好相反。当函数完成自己的任务后,它会将 %esp 移到 %ebp 处,然后再弹出旧的 %ebp 的值到 %ebp。这样,%ebp 就恢复到了函数调用前的状态了。
我们注意到最后有一个 ret 指令,它首先将数据(返回地址)弹出栈并保存到 %eip 中,然后处理器根据这个地址无条件地跳到相应位置获取新的指令。
图4 被调用者返回后的栈帧
函数的调用其实不难,只要搞懂了如何保存以及还原 %ebp 和 %esp,就能明白函数是如何通过栈帧进行调用和返回的了。
参考文献:
https://www.cnblogs.com/sddai/p/9762968.html
一般来说,linux下的进程包含以下几个关键要素:
在软件层面,进程和线程有时候并不完全区分,而往往根据上下文理解其含义。而在硬件层面,进程和线程最大的区别在于存储空间,每个进程都有一个独立的存储空间,而同一个进程中线程,大家共享的是同一个存储空间。
进程间通信的目的:
Linux操作系统下进程间通信的主要方式:
参考文献:
https://oxnz.github.io/2014/03/31/linux-IPC/
https://www.jianshu.com/p/758c7e0df40d
RPC(Remote Procedure Call):远程过程调用,它是一种通过网络从远程计算机程序上请求服务。目前流行的开源 RPC 框架还是比较多的,有阿里巴巴的 Dubbo、Facebook 的 Thrift、Google 的 gRPC、Twitter 的 Finagle 等。
图5 RPC 核心功能图
一个 RPC 的核心功能主要有 5 个部分组成,分别是:
图6 gRPC原理图
gRPC是一个高性能、通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发,且支持众多开发语言。gRPC提供了一种简单的方法来精确地定义服务和为iOS、Android和后台支持服务自动生成可靠性很强的客户端功能库。客户端充分利用高级流和链接功能,从而有助于节省带宽、降低的TCP链接次数、节省CPU使用、和电池寿命。
gRPC具有以下重要特征:
参考文献:
https://developer.51cto.com/art/201906/597963.htm
https://colobu.com/2017/04/06/dive-into-gRPC-streaming/
REST, resource REpresentational State Transfer, 资源表现状态转移。REST描述的是在网络中Client和Server的一种交互形式;RESTful API是REST的具体实现。Server提供的RESTful API中,URL中只使用名词来指定资源,原则上不使用动词。“资源”是REST架构或者说整个网络处理的核心。
图7 REST API的操作
用HTTP协议里的动词来实现资源的添加,修改,删除等操作。即通过HTTP动词来实现资源的状态扭转:
Server和Client之间传递某资源的一个表现形式,比如用JSON,XML传输文本,或者用JPG,WebP传输图片等。
为什么要用RESTful结构呢?最开始的时候网页是前端后端融在一起的,比如PHP,JSP等。在桌面时代问题不大,但是随着移动互联网的发展,各种类型的Client层出不穷,RESTful可以通过一套统一的接口为 Web,iOS和Android提供服务。另外对于广大平台来说,比如Facebook platform,微博开放平台,微信公共平台等,它们不需要有显式的前端,只需要一套提供服务的接口,于是RESTful成为它们最好的选择。
Restful和RPC有哪些区别?
参考文献:
https://www.zhihu.com/question/28557115/answer/48094438
https://blog.csdn.net/John_ToStr/article/details/103473077
已剪辑自: https://mp.weixin.qq.com/s?__biz=MzkxMDE3MDQxMA==&mid=2247483928&idx=1&sn=b5baad5156be66d2e7dcbd256fee61e6&chksm=c12ec25df6594b4ba4bac11ea8bd486aaf9f0761fa95ec7bd4df51676ee1a326439d0fd1b285&scene=178&cur_album_id=1809060064821903360#rd
图8 总线系统示意图,包含主模块、从模块和Interconnect
芯片是由多个不同模块组成的,每个模块之间通过一些自定义的或标准的多根线连接到一起。为了更好的标准化和设计服用,模块之间通常都采用标准的总线连接。总线是符合特定协议的一组线的集合。
通过总线把不同的看连接到一起之后,有的模块会主动发起访问Request,这些我们称之为总线Master模块;有的模块则是被动的接收访问并返回响应Response结果,这些模块我们称之为总线Slave模块。Master模块和Slave模块并不一定是直接连接到一起的,一般需要有特殊的总线Interconnect专门来连接。
类似软件的CS架构,硬件的Slave相当于Server,Master相当于Client。
总线的分层
可以把总线访问理解成三个层次:
总线的拓扑
图9 常见的总线互联拓扑
总线Interconnect常见有三类:
总线的分类
通过总线,把多个模块连接到一起,根据Master和Slave的对应关系,我们把总线分为如下类型:
按照连接的Hierarchy,我们把硬件之间的总线连接分为:
片内总线常见的是ARM主导的AMBA(Advanced Microcontroller Bus Architecture )系列总线,AMBA是一种开放标准的、片内互联的总线协议,为了管理系统芯片(SoC)设计中功能模块的互联规范。如今,AMBA已广泛用于各种ASIC和SoC部件。
图10 AMBA总线的发展历程
AMBA是ARM公司在1995年推出的芯片内互联系列总线。AMBA 1总线是ASB(Advanced System Bus,高级系统总线)和APB(Advanced Peripheral Bus,高级外围设备总线)。在1999年发布的AMBA 2中,ARM添加了AHB(AMBA High-performance Bus,AMBA高性能总线)。2003年,ARM推出了第三代产品AMBA 3,其中包括可实现更高性能互连的AXI(Advanced eXtensible Interface,高级可扩展接口)和作为CoreSight片上调试和跟踪解决方案一部分的ATB(Advanced Trace Bus,高级跟踪总线)。在2010年,从AXI4开始引入AMBA 4规范,然后在2011年通过AMBA 4 ACE(AXI Coherency Extensions,AXI一致性扩展)扩展了系统范围内的一致性。2013年引入了AMBA 5 CHI(Coherent Hub Interface,一致性集线器接口)规范,重新设计了高速传输层,并设计了可减少拥塞的功能(CHI因为属于NOC的范畴,将在下一节NOC总线介绍)。
AMBA协议的主要设计目标是实现一种标准有效的方法来互连芯片内部的模块,并且这些模块可以在多个设计中重复使用。如今,AMBA协议已成为SOC及嵌入式处理器总线体系结构的事实上的标准,可以免费使用。
各个总线详细的介绍不在此一一列举,感兴趣的朋友可以去ARM官网下载相关的技术文档学习,网上也可以找到非常多的相关资料。
Chiplet(翻译成小芯片或芯粒)技术通过把不同的裸DIE封装在一起。Chiplet有很多好处:
Chiplet技术当前还在发展过程中,还没有形成主流的标准。
DARPA的CHIPS项目,跟Intel合作,开源了AIB(Advanced Interface Bus),AIB是一种免费的DIE-to-DIE物理层接口标准,Intel® Stratix® 10 FPGA 用的就是AIB 接口。
图11 ODSA 分层架构
OCP的ODSA工作组相对平民化很多,ODSA关注die-to-die的层次,并且提出chiplet marketplace的口号。ODSA 的接口标准,分层概念提的很清晰,但是如果试图包括一切,标准的统一性就不会好。
还有一些公司,就不搞什么标准,直接上产品,例如Cadence Ultralink D2D PHY IP ,Synopsys 新出的 DesignWare die to die PHY IP 简单,高效。
物理层,把chiplet 对接在一起。而在物理层之上,有两种类型倾向的语以接口,I/O类型的和memory类型的。保持一致性,以硬件复杂换取软件简单?还是不保持一种性追求高效。
Chiplet是未来发展的热点方向,哪个总线能最终成为chiplet DIE-to – chiplet DIE的主流标准?目前尚未有结论。我们大家一起,持续关注。
参考文献:
https://mp.weixin.qq.com/s/IsHItdTYnnDL7KGlVwlA6w
PCIe是当前主流的片间互联高速总线,而通过SR-IOV技术扩展了PCIe的功能,使得单组PCIe可以更好地支持逻辑隔离的许多虚拟设备。
PCI是一种并行总线,随着频率的提高,PCI并行传输遇到了干扰的问题。长距离高速传输的时候,并行的连线直接干扰异常严重,而且随着频率的提高,干扰(EMI)越来越不可跨越。PCIe和PCI最大的改变是由并行改为串行,通过使用差分信号传输,干扰可以很快被发现和纠正,从而可以将传输频率大幅提升。加上PCI原来基本是半双工的(地址/数据线太多,不得不复用线路),而串行可以全双工。综合下来,从频率提高得到的收益大于一次传输多个bit的收益。还得到了另外的好处,例如布线简单,线路可以加长,甚至变成线缆连出机箱,多个Lane还可以整合成为更高带宽的线路等。
图12 PCIe示例拓扑图
如图12所示,不考虑Switch的影响,PCIe根节点是跟PCIe终端节点(End Point)是直接相连的。
图13 PCIe版本的带宽比较
如图13所示,我们可以看到,PCIe从1.0发展到了5.0,每一代的带宽大致上翻倍。到PCIe 5.0,通过x16组总线,可以支持双向共约128GB/s的数据带宽,可以支持高达400Gb的网络带宽。
PCIe SR-IOV (Single Root I/O Virtualization)是一项I/O硬件虚拟化技术,可提升I/O设备的性能和可伸缩性。如图14所示,SR-IOV标准允许在虚拟机之间高效共享PCIe设备,并且共享是在硬件中实现的,可以获得与硬件一致的I/O性能。SR-IOV引入了两种新的功能类型:
图14 支持SR-IOV技术的Intel网卡技术原理图
每个SR-IOV设备可有一个或多个物理功能(Physical Function, PF),并且每个PF最多可有若干个与其关联的虚拟功能(Virtual Function, VF),PF可以通过寄存器配置创建与自己关联的VF。一旦在PF中启用了SR-IOV,就可以通过PF的总线、设备和功能编号访问各个VF的PCI配置空间。
数据中心高速网络,本质上和全球互联网络是不同层次的网络,原因如下:
因此,数据中心需要轻量的高性能网络协议,当前主流的方案是RoCEv2的RDMA技术。RDMA(Remote Direct Memory Access,远程直接内存访问)是一种高带宽、低延迟、低CPU消耗的网络互联技术,克服了传统TCP/IP网络的许多困难。RDMA技术体现在:
图15 RDMA所使用的InfiniBand、RoCEv1/v2、iWARP技术对比
如图15所示,RoCE(RDMA over Converaged Ethernet)v1是基于现有Ethernet网络实现RDMA的一项技术。RoCEv1允许在现有以太网基础上实现RDMA技术,实现接近InfiniBand的性能和延迟指标,但不需要将现有网络基础设施升级成昂贵的InfiniBand,节约了大量的支出。RoCEv2基于标准网络的以太网(Ethernet PHY/MAC)、网络层(IP)和传输层(UDP)协议,这可以使得RoCEv2的网络流量可以经过传统的网络路由器路由。
3.6 全球互联网络
全球互联网络,这个话题有点大,关于网络的内容太多太多,很难面面俱到。
首先,我们介绍下最流行的五层网络协议模型。OSI参考模型具有七层,分别是物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。TCP/IP参考模型精简了OSI模型,只有链路层、网络层、传输层、应用层。OSI参考模型的影响力在于模型本身(去掉会话层和表示层),它已被证明对于讨论计算机网络非常有价值;而TCP/IP参考模型的优势体现在协议,这些协议已经被广泛应用许多年,证明了自身在各种复杂网络条件下的稳定性。
结合二者的特点,现在大家讨论的网络分层模型如图16所示的五层参考模型:
图16 TCP/IP网络协议栈
如图16所示,一般情况下,网络协议栈各层分别实现在硬件、内核态软件和用户态。物理层和网络链路层是由以太网和802.11标准所定义的,比较稳定,因此物理层和网络链路层一般实现在硬件里;网络层和传输层作为系统共用的组件,一般是作为TCP/IP协议栈集成在操作系统内核里;而应用层的任务则一般交给用户态的程序去实现。
图17 全球Internet接入示意图
如图17,我们可以看到,每个局域网内部,通过有线或无线的方式把各种类型的设备接入到局域网。而全球互联网其实是由无数多个局域网互联组成的。每个局域网通过一个或多个路由器接入互联网,ISP就是专门提供互联网接入服务的供应商,ISP之上,还有国家级的ISP接入网络。
已剪辑自: https://mp.weixin.qq.com/s?__biz=MzkxMDE3MDQxMA==&mid=2247483942&idx=1&sn=e2c79a6ba46d791c3fe7bdcc25ff3d84&chksm=c12ec263f6594b752e048ca4851782b4a0dd6c8cebb104a27b2b0ca154b8cced7c32147ddcb5&scene=178&cur_album_id=1809060064821903360#rd
生产者消费者问题(Producer-Consumer Problem)是多进程同步问题的经典案例之一,描述了共享固定大小缓冲区的两个进程,即所谓的“生产者”和“消费者”,在实际运行时如何处理交互的问题。
如图18所示,生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者不会在缓冲区中空时消耗数据。
图18 经典生产者消费者模型
解决问题的基本办法是:让生产者在缓冲区满时休眠,等到消费者消耗缓冲区中的数据,从而缓冲区有了空闲区域的时候,生产者才能被唤醒,开始继续往缓冲区添加数据;同样,也需要让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者继续消耗数据。
粗略地说,软硬件接口是由驱动(Driver)和设备(Device)组成,驱动和设备的交互也即软件和硬件的交互。更确切一些地说,软硬件接口包括交互的驱动软件、硬件设备的接口部分逻辑,也包括内存中的共享队列,还包括传输控制和数据信息的总线。
图19 软硬件接口硬件架构示意模型
如图19所示,是软硬件接口硬件架构的示意模型。软硬件接口的组件详细介绍如下:
软硬件接口是在I/O接口基础上的扩展,结合I/O交互的四种模式,重新梳理一下软硬件接口的演进:
NVMe(Non-Volatile Memory Express)是经过优化的、高性能的、可扩展的主机控制器接口,专为非易失性存储器(NVM)技术而设计。NVMe解决了如下一些性能问题:
NVMe协议支持多个深度队列,这是对传统SAS和SATA协议的改进。典型的SAS设备在单个队列中最多支持256个命令,而SATA设备最多支持32个命令。这些队列深度对于传统的硬盘驱动器技术已经足够,但不能充分利用NVM技术的性能。
相比之下,图20所示的NVMe多队列,每个队列支持64K命令,最多支持64K队列。这些队列的设计使得I/O命令和对命令的处理不仅可以在同一处理器内核上运行,也可以充分利用多核处理器的并行处理能力。每个应用程序或线程可以有自己的独立队列,因此不需要I/O锁定。NVMe还支持MSI-X和中断控制,避免了CPU中断处理的瓶颈,实现了系统扩展的可伸缩性。NVMe采用简化的命令集,相比SAS或SATA,NVMe命令集使用的处理I/O请求的指令数量减少了一半,从而在单位CPU指令周期内可以提供更高的IOPS,并且降低主机中I/O软件堆栈的处理延迟。
图20 NVMe多队列
NVMe的驱动和设备交互跟Virtio不同:Virtio是在通过一个队列完成双向通知交互;而NVMe则采用提交队列和完成队列配合完成双向交互的方式。
如图21所示,NVMe队列处理流程如下(其中主机为软件驱动,控制器为硬件设备):
图21 NVMe队列处理流程
NVMe是为了高速非易失性存储定制的存储接口访问协议,定向优化了存储的主要性能指标:带宽、延迟和IOPS。NVMe最重要的特征体现在:
我们以分层的任务之间调用为例,分层的部分任务是在硬件中完成,构建任务分层软硬件执行的模型,要求其相互之间的调用关系和接口保持不变。
图22 把任务卸载到硬件的简化模型
如图22所示,为分层任务调用的系统。通过把部分任务卸载(相对于在软件执行)到硬件中,来加速系统的运行。其中,双向箭头的上方为调用方,箭头的下方为被调用方。这样,系统任务在软硬件执行,涉及到的调用有四类:
一个复杂的系统,通过分解成简单的模块或层次(软件实现或硬件实现),再通过基于各种连接的调用把他们重新连接成一个整体。
软件中有调用,硬件中也有调用,软件和硬件之间也需要通过调用来进行通信和交互。
调用无处不在!