精华内容
下载资源
问答
  • 论文研究-基于知识元的应急管理案例情景化表示及存储模式研究.pdf, 应急管理案例蕴含了大量的应急管理知识, 如何有效利用这些知识, 提高应急管理案例的应用价值, 是当前...
  • 基于案例推理中案例修正的研究,张涛,刘厚泉,基于案例推理分为案例检索、案例修正、案例重用和案例存储四个基本步骤。实际应用中,检索到的案例往往不能直接重用,需要进行修
  • 该系统使用Access作为应用程序的数据库,建立了有6张数据表:Lb_Admin表用于存储帐户的信息,Lb_Class表用于存储新闻分类信息,Lb_Links表用于存储友情链接信息, Lb_News表用于存储新闻内容, Lb_Setup表用于存储系统...
  • 基于本体的案例推理系统模型的研究,张涛,刘厚泉,基于案例推理包括案例检索、案例修正、案例重用、案例存储四个部分。案例的表示方式在案例存储案例库索引的建立中起到很重要
  • 基于聚类分析的案例库分层组织结构,张涛,刘厚泉,基于案例推理包括案例检索、案例重用、案例修正、案例存储四个基本步骤。案例检索是案例推理中最重要的一个步骤。为了提高案例
  • 关于此存储库 这个软件库包含从数据,也数据和代码,以适应“的回顾性贝叶斯模型上观察COVID-19试验和病例数测量协变量效应”描述的模型,。 首先是带有数据字典的CoronaNet项目的数据列表,然后是与“用于测量对...
  • 它们不仅用于在相关各方之间传递信息,而且还用于处理数据和存储可供批准的订户访问的关键信息。 保护关键数据,确保机密性和阻止非法访问是此类组织的主要关注点。 此案例研究为任何此类组织提供了安全建议,以...
  • 第4节是对其他存储库位置的引用,以进行数据分析等。 第5节包含其他注释。 2.待办事项 折叠无关部分 重写概述以正确识别部分 3.按学期进行工作证明 2018年Spring 收集原始数据。 通常在GitHub上的../udacity-...
  • 并利用潜在语义分析(latent semantic analysis,LSA)对网络爬取的语料库进行筛选,利用过滤后的语料库对模型进行训练,最后提出一种基于三元组的评估方法,对生成案例进行评估和存储,从而实现CBR推理机的自主学习...
  • 自动转报系统数据库进程异常的现象及处置过程的案例分析论文 摘要本文详细描述了自动转报系统数据库进程异常的现象及处置过程总结了类似故障的处理方法及预防措施 关键词自动转报系统数据库操作处理进程DMHSMON压报 ...
  • DL之HNN:Hopfield神经网络(HNN之DHNN、CHNN)的相关论文、简介、使用案例之详细攻略 导读:Hopfield神经网络(HNN)是一种具有循环、递归特性,结合存储和二元系统的神经网络。由约翰·霍普菲尔德在1982年发明。...

    DL之HNN:Hopfield神经网络(HNN之DHNN、CHNN)的相关论文、简介、使用案例之详细攻略

    导读:Hopfield神经网络(HNN)是一种具有循环、递归特性,结合存储和二元系统的神经网络。由约翰·霍普菲尔德在1982年发明。对于一个Hopfield神经网络来说,关键在于确定它在稳定条件下的权系数。Hopfield神经网络分为离散型和连续型两种,主要差别在于激活函数的不同。Hopfield神经网络(HNN)提供了模拟人类记忆的模型。       

     

     

    目录

    HNN

    1、Hopfield神经网络应用

    一、HNN之DHNN

    1、DHNN

    2、DHNN网络权值的选取

    二、HNN之CHNN


     

     

    相关文章
    DL之HNN:基于HNN(subplot)将凌乱数字矩阵图像(模拟手写数字图片)实现转为最相近的阿拉伯数字

    HNN

           1982年,美国加州工学院生物物理学家约翰·霍普菲尔德Hopfield开创性地提出了一种新型的连续时间递归神经网络模型(原始的Hopfield模型)。1982年,约翰·霍普菲尔德认识到如果这种连接是对称的,那就存在一个全局的能量函数。整个网络每个二进制单元的“配置”都对应了能量的多与少,二进制单元的阈值决策规则会让网络的配置朝着能量函数最小化的方向进行。 使用这种类型的计算的一种简洁方法是使用存储器作为神经网络的能量最小值,使用能量极小值的记忆提供了一个内存关联存储器(CAM) 。

            Hopfield神经网络HNN(Hopfiled Neural Network)是一种结合存储系统和二元系统的神经网络。它保证了向局部极小的收敛,但收敛到错误的局部极小值,而非全局极小的情况也可能发生。Hopfield神经网络也提供了模拟人类记忆的模型。

            Hopfield神经网络是一种循环神经网络,每个节点的输出都是其他节点的输入(但不存在自反馈),下边的T代表阈值(类似NN的偏置)。Hopfield网络是一种结合存储系统和二元系统的神经网络。它保证了向局部极小的收敛,但收敛到错误的局部极小值(local minimum),而非全局极小(global minimum)的情况也可能发生。Hopfield网络也提供了模拟人类记忆的模型。

     

    1、Hopfield神经网络应用

             Hopfield神经网络早期应用包括按内容寻址存储器模数转换优化组合计算解决TSP问题等。具有代表意义的是解决TSP问题,1985年Hopfield和Tank用Hopfield网络求解N=30的TSP问题,从而创建了神经网络优化的新途径。除此之外,Hopfield 神经网络在人工智能之机器学习、联想记忆、模式识别、优化计算、VLSI和光学设备的并行实现等方面有着广泛应用。

     

    一、HNN之DHNN

    1、DHNN

    DHNN—离散型Hopfield神经网络:Hopfield最早提出的网络是二值神经网络,各神经元的激励函数为阶跃函数或双极值函数,神经元的输入、输出只取{0,1}或者{ -1,1},所以也称为离散型Hopfield神经网络DHNN(Discrete Hopfiled Neural Network)。在DHNN中,所采用的神经元是二值神经元;因此,所输出的离散值1和0或者1和-1分别表示神经元处于激活状态和抑制状态。
            离散Hopfield神经网络DHNN是一个单层网络,有n个神经元节点,每个神经元的输出均接到其它神经元的输入。各节点没有自反馈。每个节点都可处于一种可能的状态(1或-1),即当该神经元所受的刺激超过其阀值时,神经元就处于一种状态(比如1),否则神经元就始终处于另一状态(比如-1)。

    DHNN的特点

    • DHNN是一种多输入、含有阈值的二值非线性动态系统—能量函数。在动态系统中,平衡稳定状态可以理解为系统某种形式的能量函数(energy function)在系统运行过程中,其能量不断减少,最后处于最小值。
    • DHNN稳定的充分条件是权重系数矩阵W是一个对称矩阵且对角线元素为0:如果DHNN的权系数矩阵W是一个对称矩阵,并且对角线元素为0,则这个网络是稳定的。W是一个对称矩阵仅是充分条件,不是必要条件。
    • DHNN的类人类的联想记忆功能:DHNN一个重要功能是可以用于联想记忆,即联想存储器,这是人类的智能特点之一。
      DHNN实现联想记忆过程分为两个阶段:
      1)、学习记忆阶段: 设计者通过某一设计方法确定一组合适的权值,使DHNN记忆期望的稳定平衡点。
      2)、联想回忆阶段: DHNN的工作过程。


    DHNN局限性

    • DHNN记忆容量的有限性—无混沌状态:由于网络状态是有限的,不可能出现混沌状态。
    • DHNN的伪稳定点的联想与记忆
    • DHNN对于近似样本容易出错:当记忆样本较接近时,网络不能始终回忆出正确的记忆等;
    • DHNN平衡稳定点不可以任意设置:也没有一个通用的方式来事先知道平衡稳定点。

     


    激活函数:DHNN中采用的是sgn函数
    阈值Tj:以前是加偏置,但现在是减阈值,其实思想是一样的。t是迭代次数。


     

    2、DHNN网络权值的选取

     

    二、HNN之CHNN

           连续Hopfield神经网络CHNN(Continuous Hopfield Neural Network)与DHNN在拓扑结构上是一致的。

    • HNN与DHNN的主要区别—CHNN采用S型连续的Sigmoid函数:CHNN与DHNN不同之处在于其函数g不是阶跃函数,而是S型的连续函数。
      (1)、CHNN与DHNN的主要差别在于:CHNN神经元激活函数使用Sigmoid函数,而DHNN神经元激活函数使用了硬极限函数。
    • CHNN的各个神经元同步式工作:CHNN在时间上是连续的,所以CHNN网络中各个神经元是处于同步方式工作的。
    • CHNN网络是稳定的条件—函数连续且有界+权值 系数矩阵对称:当CHNN网络的神经元传递函数g是连续且有界的(如Sigmoid函数),并且CHNN网络的权值系数矩阵对称,则这个CHNN网络是稳定的。

    1、优化问题

            在实际应用中的系统,如果其优化问题可以用能量函数E(t)作为目标函数,那么CHNN网络和优化问题直接对应。这样,大量优化问题都可以用CHNN网络来求解。这也是Hopfield网络用于神经计算的基本原因。

     

     

     

    展开全文
  • 存储库包含人工注释的合成语料库和论文代码:合成临床笔记对真正的自然语言处理任务有用:临床实体识别的案例研究。 要求 安装python,tensorflow。 我们使用Python 3.6,Tensorflow 1.15.2。 如果计划使用GPU...
  • 最近一直在研究案例推理,看到好多论文都在大谈...不过一直有一个问题没有搞懂,就是案例(case)到底是怎么存储的呢? CBR的大师们如Schank、Koldner等人一般用动态存储模型Normal07.8 磅02falsefalsefalseEN-USZH-CNX
       最近一直在研究案例推理,看到好多论文都在大谈CBR理论,很是崇拜。不过一直有一个问题没有搞懂,就是案例(case)到底是怎么存储的呢?

           CBR的大师们如Schank、Koldner等人一般用动态存储模型
    href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_filelist.xml" rel="File-List" /> href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_themedata.thmx" rel="themeData" /> href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_colorschememapping.xml" rel="colorSchemeMapping" />Dynamic Memory Model,如 href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_filelist.xml" rel="File-List" /> href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_themedata.thmx" rel="themeData" /> href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_colorschememapping.xml" rel="colorSchemeMapping" />Ray Bareiss者一般采用 类别&案例模型(The Category & Exemplar Model),中科院史忠植教授也提出了自己的一种由于以网络发展而来的方法。大师们的境界非我一AI菜鸟所能领悟,大师们的方法也非我能够掌握。幸好看到国内外有几篇论文比较浅显,说可以用关系型数据库来存储,一笔带过,很是潇洒,但我更加一头雾水了。

           迷糊了半个月,在高济教授等编著的《人工智能基础》(高等教育出版社,2002)第三章看到了语义网络表示方法,文中同时给出了如何将语义网络转换为一阶 谓词表示的方法,因此茅塞顿开,有了《EMC-CBR故障诊断研究(一)》一文中的成果。但一阶谓词逻辑又该如何存储到数据库呢?

            在《人工智能基础》一书的第122页作者给出了一个简单的语义网络和该语义网络的一阶谓词表示,书中阐述了一种将谓词作为数据表的列的一种存储方法。但是 思来想去该方法存在一个问题,一旦语义网络比较复杂(显示问题中随便一个问题的语义网络表示都很复杂),数据表中的列将迅速膨胀;更严重的问题是,对于不 同的EMC故障案例而言,用于描述该案例的谓词数目是不确定的,因此数据表的列数也无法确定,这在关系型数据库中是不可能实现的!我再次陷入迷茫。

           God bless us!今天终于想出一种存储方法。思路就是将一阶谓词作为一个对象来进行存储。一阶谓词的属性可以作为数据表中的列,而谓词函数以及谓词的参数作为行来存储。表的设计如下:

    href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_filelist.xml" rel="File-List" /> href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_themedata.thmx" rel="themeData" /> href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_colorschememapping.xml" rel="colorSchemeMapping" />

    CBR

    列号

    列名

    数据类型

    能否为NULL

    说明

    1

    predicate_no

    smallint

    Not Null

    谓词编号,主键,标识,种子1,增量1

    2

    case_no

    varchar(15)

    Not Null

    案例号,一般为case+数字

    3

    predicate

    varchar(30)

    Not Null

    谓词

    4

    predicate_property

    varchar(30)

    Not Null

    谓词属性,取值范围fault_character, phisical_structure, causation, settlement

    5

    param_nums

    tinyint

    Not Null

    谓词参数的个数,取值范围12,默认为2

    6

    param1

    varchar(50)

    Null

    谓词函数的第一个参数

    7

    is_param1_digit

    bit

    Null

    param1是否为数字类型,默认0

    8

    param1_unit

    varchar(8)

    Null

    param1的单位,如果param1为数字类型,则该项一般不为Null

    9

    param2

    varchar(50)

    Null

    谓词函数的第二个参数

    10

    is_param2_digit

    bit

    Null

    param2是否为数字类型,默认0

    11

    param2_unit

    varchar(8)

    Null

    param2的单位,如果param2为数字类型,则该项一般不为Null

    12

    has_sub_predicate

    bit

    Null

    谓词函数是否以别的谓词作为参数,默认为0

    13

    sub_predicate_no

    smallint

    Null

    作为参数的谓词的编号


    本案例库采用SQL Server2005 Express Edition来实现:

    href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_filelist.xml" rel="File-List" /> href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_themedata.thmx" rel="themeData" /> href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtmlclip1%5C01%5Cclip_colorschememapping.xml" rel="colorSchemeMapping" />

    如果要查询案例6EUT的物理结构特征,可以用如下查询语句:

    SELECT predicate, param1, param2

    FROM Cases

    WHERE (predicate_property = 'phisical_structure') AND (case_no = 'case6')

    查询结果如下:



    【注】:版权归作者所有,转载或引用请注明出处。

    展开全文
  • 智能卡是一种安全地持有私钥而不会将其从存储中放出的设备。 信用卡上的芯片是“智能卡”(是的,术语不明确-卡和芯片可互换地称为“智能卡”)。 有较小的USB可插拔硬件读取器,仅可容纳芯片(没有实际的卡,例如...

    中本聪论文

    智能卡是一种安全地持有私钥而不会将其从存储中放出的设备。 信用卡上的芯片是“智能卡”(是的,术语不明确-卡和芯片可互换地称为“智能卡”)。 有较小的USB可插拔硬件读取器,仅可容纳芯片(没有实际的卡,例如卡)。

    但是有什么用? 几年前的w3c研讨会概述了其中的一些内容:多因素身份验证, 状态接受的电子标识 ,数字签名。 所有这些都是更大范围的一部分–使用互联网现在是主要的通信手段。 我们正在将大多数现实活动在线上转移,因此,有一种方法可以识别我们在线的人(例如,到政府,银行),或者能够在线(具有法律价值)签署文件。

    因此,欧盟引入了eIDAS法规 ,该法规定义(除其他事项外)电子标识和数字签名。 在那里建立的框架旨在具有法律约束力的电子通信,这在许多情况下都很重要。 您是否进行过打印符号扫描练习? 未经授权的人可以访问您的电子银行吗? 好吧,该法规应该解决这些以及更多问题。

    两因素身份验证是另一个更广泛的概念,它具有大量次优解决方案。 OTP令牌,Google身份验证器,短信代码确认。 所有这些都有问题(例如时钟同步,短信拦截,费用)。 有类似YubiKey的硬件令牌,但它们仅提供智能卡具有的功能的子集。

    但这不仅仅涉及法律上认可的在线行动和两因素身份验证。 它开辟了其他可能性,例如更安全的在线信用卡付款-例如,将卡放在阅读器中并输入PIN,而不是输入卡号,CVC,日期,名称,3d密码等。

    经过这么长时间的介绍,我发现了一个问题:浏览器不支持智能卡。 在法律认可电子签名的欧盟中,始终很难使它们与浏览器一起使用。 到目前为止的解决方案:Java applet。 Java applet可以通过java crypto API与智能卡进行交互,从而提供签名功能。 但是,随着Java applet的弃用,这个持续不断的奋斗时代将很快结束(这是一个奋斗-必须至少单击两次确认并保持Java处于最新状态,即使对于开发人员来说也是麻烦的)。 几年前,在Firefox和IE中曾经有一种使用window.crypto和CAPICOM API做到这一点的方法,但这些方法已被弃用。

    最近的趋势是使用“基于云”的方法,其中密钥位于HSM上。 这当然很有用,但是身份识别问题仍然存在–要访问HSM上的密钥,同样需要两步验证。 拥有硬件令牌“在您手中”可以增加安全性。

    爱沙尼亚(世界上数字政府最多)的聪明人比Java或HSM拥有更好的解决方案-允许与自己的ID卡(即具有智能卡)进行交互的浏览器插件。 解决方案在这里这里 效果很好–您可以安装一个插件(一个多功能安装程序),并可以使用javascript签署文档。 您还将安装正确的PKCS库,以及允许使用硬件令牌进行TLS 1.2身份验证(标识和身份验证与签名)所需的根证书。 这种方法的缺点是,它有些脆弱,并且依赖于浏览器的异想天开-如果某些浏览器决定弃用某些插件API,则必须不断升级插件,并且有被完全破坏的风险。

    另一种方法是“本地服务”方法,它有两种风格。 一种是–安装一个公开应用程序的本地应用程序,该应用程序公开一个HTTP接口,并使用javascript和正确的同源配置将您签名所需的文件发送到该服务,然后将结果作为HTTP响应获取,然后可以再次使用javascript,附加到请求签名的页面。 不利之处–安装服务以监听没有管理员权限的给定端口。 另一种方法是让应用程序挂接到自定义协议(例如signature://)。 因此,每当页面要用户签名时,它都会打开signnature:// path-to-document-to-sign,由本地安装的应用程序拦截,执行数字签名,并将结果推送到(one-时间)在文档的元数据中指定的URL以进行签名。 像这样的事情是由4identity.eu实现的,并且确实有效。

    现在,签名是一回事,标识(TLS客户端身份验证)是另一回事。 据称,一切都应该在这里进行– PKCS#11是一个标准,应该允许使用智能卡进行TLS客户端身份验证。 现实是-事实并非如此。 您通常需要特定于供应商的PKCS#11库。 OpenSC是一个很酷的工具,可与许多智能卡一起使用,仅可与Firefox和Safari一起使用。 Charismatics commercial是一种软件,应该可以与所有智能卡一起使用-嗯,它并不总是如此。

    而这里的问题是智能卡供应商。 之所以需要OpenSC和Charismatics,是因为即使有一些PKCS标准,智能卡还是一团糟。 这不仅是一团糟,而且是封闭的,秘密的一团糟。 在大多数情况下,APDU(发送到智能卡以与其进行通信的命令)都是秘密的。 即使您购买了成千上万张卡,也不会了解它们-您只会获得了解它们的定制供应商软件。 然后,您必须对他们进行反向工程,才能知道如何与他们实际交谈​​。 它们不仅在供应商之间不同,而且在不同供应商的卡型号之间也不同。 因此,爱沙尼亚的方法实施起来比较简单-他们只有一种类型的智能卡,发给所有公民,而且他们大多处于控制之下。 在其他国家,这真是一团糟。 至少支持十二种不同类型的卡。

    因此,我的首要要求是向智能卡供应商(数量不多)提供服务-请修复您的混乱情况。 摆脱多余的“通过模糊处理获得安全性”,使浏览器无需额外的欺骗就可以与您通信。

    我的第二个请求是对浏览器供应商的请求–请本机支持智能卡加密。 不幸的是,由于上述智能卡混乱(除其他事项外),硬件加密已明确从Web加密API中排除。 作为后续措施,有一个硬件安全工作组 ,但据信它仍在“进行中”,我的感觉还不是很多。 在w3c中,重要的是,浏览器供应商必须同意在其成为标准之前实现某些东西,而且我听说有些人反对智能卡集成。 由于上述混乱,我猜是。

    您可能会说–标准化将解决此问题。 好吧,到目前为止还没有。 欧盟官员已经意识到了这个问题,eIDAS法规可能会受到这些技术问题的阻碍,但它们无能为力,因为欧盟不是一个标准化机构。

    因此,归根结底是浏览器和智能卡供应商共同努力一劳永逸地解决此问题。 因此,请这样做以启用更安全和合法合规的网站。

    翻译自: https://www.javacodegeeks.com/2017/02/case-native-smart-card-support-browsers.html

    中本聪论文

    展开全文
  • 设计模式实例是从这些开源软件项目的源代码存储库中提取的。 软件缺陷度量是从这些项目的错误跟踪系统中提取的。 通过对提取的数据进行相关性和回归分析,我们研究了设计模式与软件缺陷之间的关系。 我们的发现表明...
  • 因此,传统的存储和分析数据的方式使数据保持隔离状态,从而导致管理系统效率低下。 这项研究旨在利用GIS优化城市垃圾箱的管理。 选择Nuseirat City作为案例研究,以评估回收箱的SWM,以使收集过程获得更少的成本和...
  • 本文是对论文Dissecting a Small InfiniBand Application Using the Verbs API所做的中英文对照翻译 Dissecting a Small InfiniBand Application Using the Verbs API Gregory Kerr∗ College of Computer ...
    本文是对论文Dissecting a Small InfiniBand Application Using the Verbs API所做的中英文对照翻译

    Dissecting a Small InfiniBand Application Using the Verbs API

                 Gregory Kerr∗
    College of Computer and Information Science
               Northeastern University
                 Boston, MA
               kerrg@ccs.neu.edu

    Abstract | 摘要

    InfiniBand is a switched fabric interconnect. The InfiniBand specification does not define an API. However the OFED package, libibverbs, has become the default API on Linux and Solaris systems. Sparse documentation exists for the verbs API. The simplest InfiniBand program provided by OFED, ibv_rc_pingpong, is about 800 lines long. The semantics of using the verbs API for this program is not obvious to the first time reader. This paper will dissect the ibv_rc_pingpong program in an attempt to make clear to users how to interact with verbs. This work was motivated by an ongoing project to include direct InfiniBand support for the DMTCP checkpointing package.
    InfiniBand是一种基于交换结构的网络互连方式。InfiniBand标准并没有定义API。然而,OFED软件包(libibverbs)已经成为了Linux和Solaris系统默认的API。一些稀疏的文档存在于verbs API中。OFED提供了一个最简单的IB程序(ibv_rc_pingpong),约800行代码。在这个程序中,使用的API的语义对第一次接触verbs的读者来说并不那么容易理解。本文将剖析ibv_rc_pingpong程序,以帮助读者弄清楚如何与verbs打交道。之所以写作本文,是因为一个正在进行的项目,该项目将在DMTCP检查点软件包中包含对IB的直接支持。

    1 Introduction | 概述

    The program ibv_rc_pingpong can be found at openfabrics.org, under the "examples/" directory of the OFED tarball. The source code used for this document is from version 1.1.4. The ibv_rc_pingpong program sets up a connection between two nodes running InfiniBand adapters and transfers data. Let's begin by looking at the program in action. In this paper, I will refer to two nodes: client and server. There are various command line flags that may be set when running the program. It is important to note that the information contained within this document is based on the assumption that the program has been run with no command line flags configured. Configuring these flags will alter much of the program's behavior.
    程序ibv_rc_pingpong可以在penfabrics.org上找到,位于OFED压缩包的"examples/"目录下面。本文使用的源代码版本是1.1.4。程序ibv_rc_pingpong在两个具有IB适配器的节点之间建立连接并进行数据传输。让我们从看程序代码开始。在本文中,我将提及两个结点:client和server。当运行程序的时候,可以设置各种命令行标志。值得注意的是,本文中包含的信息基于一个假定,即该程序在运行时没有配置命令行标志。如果配置这些标志的话,将改变程序的许多行为。

    Since both nodes run the same executable, the "client" is the instance that is launched with a hostname as an argument. The LID, QPN, and PSN will be explained later.
    由于两个节点都运行相同的可执行文件,"client"是一个使用主机名作为参数的启动的实例。有关LID、QPN和PSN将稍后做解释。

    [user@server]$ ibv_rc_pingpong
    local address:  LID 0x0008, QPN 0x580048, PSN 0x2a166f, GID ::
    remote address: LID 0x0003, QPN 0x580048, PSN 0x5c3f21, GID ::
    8192000 bytes in 0.01 seconds = 5167.64 Mbit/sec
    1000 iters in 0.01 seconds = 12.68 usec/iter
    
    [user@client]$ ibv_rc_pingpong server
    local address:  LID 0x0003, QPN 0x580048, PSN 0x5c3f21, GID ::
    remote address: LID 0x0008, QPN 0x580048, PSN 0x2a166f, GID ::
    8192000 bytes in 0.01 seconds = 5217.83 Mbit/sec
    1000 iters in 0.01 seconds = 12.56 usec/iter

    Before we delve into the actual code, please look at a list of all verbs API functions which will be used for our purposes. I encourage the reader to pause and read the man page for each of these.
    在深入研究实际代码之前,请看一下我们将用到的verbs API列表。读者朋友不妨暂停一下,先阅读一下这些API的man页面。

     1 ibv_get_device_list(3) 
     2 ibv_open_device(3) 
     3 ibv_alloc_pd(3)
     4 ibv_reg_mr(3)
     5 ibv_create_cq(3) 
     6 ibv_create_qp(3) 
     7 ibv_modify_qp(3)
     8 ibv_post_recv(3) 
     9 ibv_post_send(3) 
    10 ibv_poll_cq(3)
    11 ibv_ack_cq_events(3)

    2 Layers | 分层

    There are multiple drivers, existing in kernel and userspace, involved in a connection. See Figure 2a. To explain it simply, much of the connection setup work goes through the kernel driver, as speed is not a critical concern in that area.
    在内核和用户空间,有多个驱动参与连接。请参见图2a。简单地说,大部分连接安装工作都是通过内核驱动完成,因为速度对建立连接来说并不关键。

    The user space drivers are involved in function calls such as ibv_post_send and ibv_post_recv. Instead of going through kernel space, they interact directly with the hardware by writing to a segment of mapped memory. Avoiding kernel traps is one way to decrease the overall latency of each operation.
    用户空间设备驱动参与到函数调用之中,例如ibv_post_send和ibv_post_recv。它们不经过内核空间,而是通过对内存映射段执行写操作来直接与硬件打交道。避免陷入内核是降低单个操作的总时延的一种方法。

    3 Remote Direct Memory Access | RDMA(远程直接内存访问)

    One of the key concepts in InfiniBand is Remote Direct Memory Access (RDMA). This allows a node to directly access the memory of another node on the subnet, without involving the remote CPU or software layers.
    IB的核心概念之一就是RDMA(远程直接内存访问)。这允许一个结点直接访问子网内的另一个结点的系统内存,而不需要远端CPU或者软件层的干预。

    Remember the key concepts of Direct Memory Access (DMA) as illustrated by Figure 2b.
    图2b演示了DMA(直接内存访问)的核心概念。

    In the DMA, the CPU sends a command to the hardware to begin a DMA operation. When the operation finishes, the DMA hardware raises an interrupt with the CPU, signaling completion. The RDMA concept used in InfiniBand is similar to DMA, except with two nodes accessing each other's memory; one node is the sender and one is the receiver.
    在DMA中,CPU给硬件发送一个开始DMA操作的命令。当操作完成后,DMA硬件引发一个中断高速CPU, DMA操作已经完成。用在InfiniBand中RDMA概念与DMA类似,两个节点相互访问对方的系统内存,一个结点为sender(发送方), 另一个结点为receiver(接收方)。

    Figure 3 illustrates an InfiniBand connection. In this case the DMA Hardware is the Host Channel Adapter (HCA), and the two HCAs are connected, through a switch, to each other. The HCA is InfiniBand's version of a network card; it is the hardware local to each node that facilitates communications. This allows an HCA on one node to use another HCA to perform DMA operations on a remote node.
    图3演示了IB连接。在这个示例中,DMA硬件是HCA(主机通道适配器)。两个结点各有一个HCA,通过交换机互联。HCA就是InfiniBand的网卡。它是每个结点用来通信的硬件。这允许一个节点上的HCA使用另一个结点上的HCA来在远程节点上执行DMA操作。

    4 Overview | 概要

    The ibv_rc_pingpong program does the following.
    程序ibv_rc_pingpong做了如下6件事情。

    1. Reserves memory from the operating system for sending and receiving data 在操作系统中申请内存,为发送和接收数据做准备
    2. Allocates resources from the verbs API 从verbs API中申请资源
    3. Uses a TCP socket to exchange InfiniBand connection information 使用TCP socket交换IB连接信息
    4. Creates a connection between two InfiniBand ports 在两个IB端口中创建一个连接
    5. Transfers data over the connection 在连接上传输数据
    6. Acknowledges the successful completion of the transfer 在传输成功完成后给一个ACK


    5 Data Transfer Modes | 数据传输模型

    The InfiniBand specification states four different connection types: Reliable Connection (RC), Unreliable Connection (UC), Reliable Datagram (RD), Unreliable Datagram (UD). This program, ibv_rc_pingpong uses a simple RC model. RD is not supported by current hardware.
    InfiniBand技术规范定义了四种不同的连接类型:可靠连接(RC)、不可靠连接(UC)、可靠数据报(RD)和不可靠数据报(UD)。ibv_rc_pingpong程序使用的是简单的可靠连接(RC)。目前硬件不支持可靠数据报(RD)。

    The difference between reliable and unreliable is predictable -- in a reliable connection data is transferred in order and guaranteed to arrive. In an unreliable connection neither of those guarantees is made.
    可靠与不可靠的区别在于是否可预测 -- 在可靠连接中,数据按顺序到达并保证能够到达。在不可靠连接中,这两项都保证不了。

    A connection type is an association strictly between two hosts. In a datagram, a host is free to communicate with any other host on the subnet.
    连接类型是主机之间的严格关联。在数据报中,主机可以自由地与子网上的任何其他主机进行通信。

    6 Queue Based Model | 基于队列的模型

    The InfiniBand hardware processes requests from the client software through requests, which are placed into queues. To send messages between nodes, each node must have at minimum three queues: a Send Queue (SQ), Receive Queue (RQ), and Completion Queue (CQ).
    IB硬件处理来自client的请求是通过把请求放置到队列上。在两个结点之间发送数据,每一个结点至少包含3个队列:发送队列(SQ)、接收队列(RQ)和完成队列(CQ)。

    In a reliable connection, used in the ibv_rc_pingpong program, queue pairs on two distinct hosts compromise an end-to-end context. They send messages to each other, and only each other. This paper restricts itself to this mode.
    在用于ibv_rc_pingpong程序的可靠连接中,两个独立的主机之间的QP(队列对)协商一个端到端的上下文。他们互相传递信息,而且只在彼此之间。本文的讨论仅限于这一模式。

    The queues themselves exist on the HCA. However the libibverbs will return to the user a data structure which corresponds with the QP. While the library will create the QP, the user assumes the responsibility of "connecting" the QP with the remote node. This is generally done by opening an out-of-band socket connection, trading the identification numbers for the queues, and then updating the hardware with the information.
    队列本身存在于HCA硬件上。libibverbs将返回一个跟QP一致关联的数据结构给用户。QP的创建由libibverbs函数库负责,但连接远端结点的QP则由用户自己负责。通常的实现是打开一个带外socket连接,为队列交换标识符,然后把信息更新到硬件上。

    More recently, librdma_cm (an OFED library for connection management) allows a user to create and connect QPs through library calls reminiscent of POSIX sockets. Those calls are outside the scope of this document.
    最近,librdma_cm(OFED针对连接管理发布的函数库)允许用户创建和连接QP, 通过调用POSIX socket。这些调用不在本文的讨论范围之内。

    6.1 Posting Work Requests to Queues | 给队列里放置工作请求

    To send and receive data in the InfiniBand connection (end-to-end context), work requests, which become Work Queue Entries (WQE, pronounced "wookie") are posted to the appropriate queue. These work requests point to lists of scatter/gather elements (each element has an address and size associated with it). This is a means of writing to and reading from buffers which are non-contiguous in memory.
    在InfiniBand连接(即是端到端的上下文)中发送和接收数据,工作请求(即工作队列元素,WQE,发音为wookie)被放置到相应的队列中。这些工作请求指向一个分散/聚合元素(SGE)的列表(每个元素都有一个虚拟内存地址和与之相关联的缓冲区大小)。这是一种在非连续的内存缓冲区中写入和读取数据的方法。

    The memory buffers must be registered with the hardware; that process is explained later. Memory buffers must be posted to the receive queue before the remote host can post any sends. The ibv_rc_pingpong program posts numerous buffers to the receive queue at the beginning of execution, and then repopulates the queue as necessary. A receive queue entry is processed when the remote host posts a send operation.
    内存缓冲区必须在硬件中注册,注册过程稍后予以解释。在远程主机放置任何发送请求到发送队列之前,内存缓冲区必须在放置到接收队列。ibv_rc_pingpong程序在开始执行的时候放置大量的缓存区到发送队列,然后在必要的时候重新填充队列。当远程主机放置一个发送操作的时候,接收队列条目将被处理。

    When the hardware processes the work request, a Completion Queue Entry (CQE, pronounced "cookie") is placed on the CQ. There is a sample of code showing how to handle completion events in ibv_ack_cq_events(3).
    当硬件处理一个工作请求(WR)的时候,一个完成队列条目(CQE,发音为cookie)被放置到完成队列(CQ)中。在ibv_ack_cq_events(3)中,有样本代码演示如何处理完成事件。

    7 Connecting the Calls | 连接使用的函数调用

    The table below which the function calls used in ibv_rc_pingpong to create a connection, and the order in which they are called.
    在下表中,列出了ibv_rc_pingpong创建一个连接使用的函数以及调用顺序。

    This table introduces the resources which are allocated in the process of creating a connection. These resources will be explained in detail later.
    上面的表格也介绍了在创建一个连接中分配的资源,对这些资源稍后做解释。

    8 Allocating Resources | 分配资源

    8.1 Creating a Context | 创建上下文

    The first function call to the verbs API made by the ibv_rc_pingpong source code is here:

    619         dev_list = ibv_get_device_list(NULL);

    As the man page states, this function returns a list of available HCAs.
    ibv_rc_pingpong源代码调用的第一个verbs API就是ibv_get_device_list(), 该函数在手册里有明确说明,返回一个可用的HCA列表。

    The argument to the function is an optional pointer to an int, which the library uses to specify the size of the list.
    该函数的参数是一个可选的执行int的指针,用来指定列表的长度。

    Next it populates the pingpong_context structure with the function pp_init_ctx.
    接下来,在函数pp_init_ctx填充pingpong_context结构体。

    The pingpong_context structure wraps all the resources associated with a connection into one unit.
    pingpong_context结构体包装了与连接相关联的所有分配的资源。

    /* Listing 1: struct pingpong context */
    
    59 struct pingpong_context {
    60         struct ibv_context      *context;
    61         struct ibv_comp_channel *channel;
    62         struct ibv_pd           *pd;
    63         struct ibv_mr           *mr;
    64         struct ibv_cq           *cq;
    65         struct ibv_qp           *qp;
    66         void                    *buf;
    67         int                      size;
    68         int                      rx_depth;
    69         int                      pending;
    70         struct ibv_port_attr     portinfo;
    71 };
    /* Listing 2:  Initializing the struct pingpong context */
    
    643         ctx = pp_init_ctx(ib_dev, size, rx_depth, ib_port, use_event, !servername);

    The ib_dev argument is a struct device * and comes from dev_list. The argument size specifies the size of the message to be sent (4096 bytes by default), rx_depth sets the number of receives to post at a time, ib_port is the port of the HCA and use_event specifies whether to sleep on CQ events or poll for them.
    参数ib_dev来自于dev_list, 类型为struct device *。参数size指定发送的消息长度(默认4096字节),rx_depth设置一次放置到接收队列的接收请求的个数(即接收队列深度),ib_port是HCA的port,use_event指定是在CQ事件上睡眠或还是进行轮询。

    The function pp_init_ctx first allocates a buffer of memory, which will be used to send and receive data. Note that the buffer is memalign-ed to a page, since it is pinned (see section 8.3 for a definition of pinning).
    函数pp_init_ctx首先分配内存缓冲区,用于发送和接收数据。注意缓冲区是按页对齐的,由于该缓冲区是需要被凝固的(有关pinning的定义,请参见8.3节)。

    /* Listing 3: Allocating a Buffer */
    
    320         ctx->buf = memalign(page_size, size);
    321         if (!ctx->buf) {
    322                 fprintf(stderr, "Couldn't allocate work buf.\n");
    323                 return NULL;
    324         }
    325
    326         memset(ctx->buf, 0x7b + is_server, size);

    Next the ibv_context pointer is populated with a call to ibv_open_device. The ibv_context is a structure which encapsulates information about the device opened for the connection.
    接下来,ibv_context指针被赋值,通过调用ibv_open_device()。ibv_context是一个结构体,封装了为建立连接而打开的设备信息。

    /* Listing 4: Opening a Context */
    
    328         ctx->context = ibv_open_device(ib_dev);
    329         if (!ctx->context) {
    330                 fprintf(stderr, "Couldn't get context for %s\n",
    331                         ibv_get_device_name(ib_dev));
    332                 return NULL;
    333         }

    From the "infiniband/verbs.h" header, the struct ibv_context is as follows:
    结构体ibv_context来自头文件"infiniband/verbs.h",如下所示:

    /* Listing 5: struct ibv_context */
    
    766 struct ibv_context {
    767         struct ibv_device      *device;
    768         struct ibv_context_ops  ops;
    769         int                     cmd_fd;
    770         int                     async_fd;
    771         int                     num_comp_vectors;
    772         pthread_mutex_t         mutex;
    773         void                   *abi_compat;
    774         struct ibv_more_ops     *more_ops;
    775 };

    The struct ibv_device * is a pointer to the device opened for this connection. The struct ibv_context_ops ops field contains function pointers to driver specific functions, which the user need not access directly.
    结构ibv_device *是一个指向为建立连接而打开的设备的指针。结构ibv_context_ops ops域包含了一系列函数指针,这些函数指针执行驱动程序的具体功能,用户不需要直接访问这些函数指针。

    8.2 Protection Domain | 保护域

    After the device is opened and the context is created, the program allocates a protection domain.
    在设备被打开和上下文创建完毕之后,程序分配一个保护域(PD)。

    /* Listing 6: Opening a Protection Domain */
    
    344         ctx->pd = ibv_alloc_pd(ctx->context);
    345         if (!ctx->pd) {
    346                 fprintf(stderr, "Couldn't allocate PD\n");
    347                 return NULL;
    348         }

    A protection domain, according to the InfiniBand specification, allows the client to control which remote computers can access its memory regions during InfiniBand sends and receives.
    根据IB的技术规范,保护域(PD)允许cient在IB发送和接收过程中,控制它的内存区域,该内存取可以被远程电脑访问。

    The protection domain mostly exists on the hardware itself. Its user-space data structure is sparse:
    保护域(PD)主要存在于硬件本身。其用户空间数据结构实为稀疏:

    /* Listing 7: struct ibv_pd from "infiniband/verbs.h" */
    
    308 struct ibv_pd {
    309         struct ibv_context     *context;
    310         uint32_t                handle;
    311 };

    8.3 Memory Region | 内存区域

    The ibv_rc_pingpong program next registers one memory region with the hardware.
    接下来ibv_rc_pingpong程序注册一段内存区域(MR),该区域将被硬件访问。

    When the memory region is registered, two things happen. The memory is pinned by the kernel, which prevents the physical address from being swapped to disk. On Linux operating systems, a call to mlock is used to perform this operation. In addition, a translation of the virtual address to the physical address is given to the HCA.
    当内存区域(MR)注册了,有两件事情将发生。(首先,) 内存被内核锁定,防止物理地址(内存里存放的数据)被交换到硬盘上。在Linux操作系统中,使用mlock调用来执行这一操作。其次,(HCA驱动)将虚拟内存地址转换为物理内存地址,然后将这一对应关系交给HCA硬件去使用。

    /* Listing 8: Registering a Memory Region */
    350         ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size, IBV_ACCESS_LOCAL_WRITE);
    351         if (!ctx->mr) {
    352                 fprintf(stderr, "Couldn't register MR\n");
    353                 return NULL;
    354         }

    The arguments are the protection domain with which to associate the memory region, the address of the region itself, the size, and the flags. The options for the flags are defined in "infiniband/verbs.h".
    参数是与MR相关联的PD, MR本身的地址,大小和标志。标志选项的定义在文件"infiniband/verbs.h"里。

    /* Listing 9: Access Flags */
    
    300 enum ibv_access_flags {
    301         IBV_ACCESS_LOCAL_WRITE          = 1,
    302         IBV_ACCESS_REMOTE_WRITE         = (1<<1),
    303         IBV_ACCESS_REMOTE_READ          = (1<<2),
    304         IBV_ACCESS_REMOTE_ATOMIC        = (1<<3),
    305         IBV_ACCESS_MW_BIND              = (1<<4)
    306 };

    When the memory registration is complete, an lkey field or Local Key is created. According to the InfiniBand Technical Specification the lkey is used to identify the appropriate memory addresses and provide authorization to access them.
    当内存注册(MR)完成的时候,lkey(或Local Key)字段就创建好了。根据IB的技术规范,lkey用来确定合适的内存地址和提供访问授权。

    8.4 Completion Queue | 完成队列

    The next part of the connection is the completion queue (CQ), where work completion queue entries are posted. Please note that you must create the CQ before the QP. As stated previously, ibv_ack_cq_events(3) has helpful examples of how to manage completion events.
    建立连接的接下来的一部分是创建完成队列(CQ),工作完成条目(CQE)被放置到完成队列(CQ)上。请注意,必须在创建QP之前创建CQ。如何管理完成事件,前面提及的ibv_ack_cq_events(3)中例子可供参考。

    /* Listing 10: Creating a CQ */
    
    356         ctx->cq = ibv_create_cq(ctx->context, rx_depth + 1, NULL,
    357                                 ctx->channel, 0);
    358         if (!ctx->cq) {
    359                 fprintf(stderr, "Couldn't create CQ\n");
    360                 return NULL;
    361         }

    8.5 Queue Pairs | 队列对

    Communication in InfiniBand is based on the concept of queue pairs. Each queue pair contains a send queue and a receive queue, and must be associated with at least one completion queue. The queues themselves exist on the HCA. A data structure containing a reference to the hardware queue pair resources is returned to the user.
    在IB中,通信是基于队列对(QP)的概念而实现。每一个队列对(QP)包含有一个发送队列(SQ)和接收队列(RQ),并且必须与至少一个完成队列(CQ)相关联(换言之,一个QP中的SQ和RQ可以关联到同一个CQ上)。这些队列(SQ, RQ和CQ)都存在于HCA硬件上。一个包含有对硬件QP资源的引用的数据结构,被返回给用户使用。

    First, look at the code to create a QP.
    首先,让我们看看创建一个QP的源代码。

    /* Listing 11: Creating a QP */
    
    364                 struct ibv_qp_init_attr attr = {
    365                         .send_cq = ctx->cq,
    366                         .recv_cq = ctx->cq,
    367                         .cap     = {
    368                                 .max_send_wr  = 1,
    369                                 .max_recv_wr  = rx_depth,
    370                                 .max_send_sge = 1,
    371                                 .max_recv_sge = 1
    372                         },
    373                         .qp_type = IBV_QPT_RC
    374                 };
    375
    376                 ctx->qp = ibv_create_qp(ctx->pd, &attr);
    377                 if (!ctx->qp)  {
    378                         fprintf(stderr, "Couldn't create QP\n");
    379                         return NULL;
    380                 }

    Notice that a data structure which defines the initial attributes of the QP must be given as an argument. There are a few other elements in the data structure, which are optional to define.
    注意,定义QP初始属性的数据结构必须作为一个参数传递。在这个数据结构中,有一些元素是可选的。

    The first two elements, send_cq and recv_cq, associate the QP with a CQ as stated earlier. The send and receive queue may be associated with the same completion queue.
    前两个元素是send_cq和recv_cq,(如前面所说)是与QP相关联的完成队列(CQ)。发送队列和接收队列可能关联到同一个完成队列上。

    The cap field points to a struct ibv_qp_cap and specifies how many send and receive work requests the queues can hold. The max_{send, recv}_sge field specifies the maximum number of scatter/gather elements that each work request will be able to hold. A scatter gather element is used in a direct memory access (DMA) operation, and each SGE points to a buffer in memory to be used in the read or write. In this case, the attributes state that only one buffer may be pointed to at any given time.
    字段cap指向一个结构体struct ibv_qp_cap, 指定可以容纳的发送和接收工作请求的个数。max_{send, recv}_sge字段指定了每一个工作请求能够容纳的最大的SGE数目。一个SGE用来做DMA操作,每一个SGE指向一个可用于读/写的内存缓冲区。在这个例子中,属性状态说明了在任何给定的时间内仅指向一个缓冲区。

    The qp_type field specifies what type of connection is to be used, in this case a reliable connection.
    qp_type字段指定了使用的连接类型,在这里是可靠连接(RC)。

    Now the queue pair has been created. It must be moved into the initialized state, which involves a library call. In the initialized state, the QP will silently drop any incoming packets and no work requests can be posted to the send queue.
    现在QP已经创建好了。必须通过库函数调用将它的状态设置为初始化状态。在初始化状态下,任何传入的数据包将被QP悄悄地丢弃,并且工作请求不能够被放置到发送队列上。

    /* Listing 12: Setting QP to INIT */
    
    384                 struct ibv_qp_attr attr = {
    385                         .qp_state        = IBV_QPS_INIT,
    386                         .pkey_index      = 0,
    387                         .port_num        = port,
    388                         .qp_access_flags = 0
    389                 };
    390
    391                 if (ibv_modify_qp(ctx->qp, &attr,
    392                                   IBV_QP_STATE              |
    393                                   IBV_QP_PKEY_INDEX         |
    394                                   IBV_QP_PORT               |
    395                                   IBV_QP_ACCESS_FLAGS)) {
    396                         fprintf(stderr, "Failed to modify QP to INIT\n");
    397                         return NULL;
    398                 }

    The third argument to ibv_modify_qp is a bitmask stating which options should be configured. The flags are specified in enum ibv_qp_attr_mask in "infiniband/verbs.h".
    ibv_modify_qp()的第3个参数是一个位掩码,说明应该配置的选项。flags在头文件"infiniband/verbs.h"的枚举体ibv_qp_attr_mask中定义。

    At this point the ibv_rc_pingpong program posts a receive work request to the QP.
    在这里,ibv_rc_pingpong程序放置一个接收工作请求到QP上。

    650         routs = pp_post_recv(ctx, ctx->rx_depth);

    Look at the definition of pp_post_recv.
    看一下pp_post_recv的定义。

    /* Listing 13: Posting Recv Requests */
    
    444 static int pp_post_recv(struct pingpong_context *ctx, int n)
    445 {
    446         struct ibv_sge list = {
    447                 .addr   = (uintptr_t) ctx->buf,
    448                 .length = ctx->size,
    449                 .lkey   = ctx->mr->lkey
    450         };
    451         struct ibv_recv_wr wr = {
    452                 .wr_id      = PINGPONG_RECV_WRID,
    453                 .sg_list    = &list,
    454                 .num_sge    = 1,
    455         };
    456         struct ibv_recv_wr *bad_wr;
    457         int i;
    458
    459         for (i = 0; i < n; ++i)
    460                 if (ibv_post_recv(ctx->qp, &wr, &bad_wr))
    461                         break;
    462
    463         return i;
    464 }

    The ibv_sge list is the list pointing to the scatter/gather elements (in this case, a list of size 1). To review, the SGE is a pointer to a memory region which the HCA can read to or write from.
    ibv_sge列表是指向SGE数组的列表(在这里,列表长度为1)。SGE指向一个内存区域,该区域能被HCA读写。

    Next is the ibv_recv_wr structure. The first field, wr_id, is a field set by the program to identify the work request. This is needed when checking the completion queue elements; it specifies which work request completed.
    下一个结构体是ibv_recv_wr。第一个字段wr_id由应用程序设置,以标识对应的WR。在检查完成队列元素时需要wr_id,它指定了哪一个WR已经完成了。

    The work request given to ibv_post_recv is actually a linked list, of length 1.
    传给ibv_post_recv()的WR实际上是一个长度为1的链表。

    /* Listing 14: Linked List */
    
    451         struct ibv_recv_wr wr = {
    452                 .wr_id      = PINGPONG_RECV_WRID,
    453                 .sg_list    = &list,
    454                 .num_sge    = 1,
    455         };

    If one of the work requests fails, the library will set the bad_wr pointer to the failed wr in the linked list.
    如果一个WR执行失败了,那么库函数就将bad_wr指向在此链表中失败的那个wr

    Receive buffers must be posted before any sends. It is common practice to loop over the ibv_post_recv call to post numerous buffers at the beginning of execution. Eventually these buffers will be used up; internal flow control must be implemented by the applications to ensure that sends are not posted without corresponding receives.
    接收缓冲区必须在发送之前放置到SQ上。 通常的做法是在执行开始的时候循环调用ibv_post_recv()将多个buffer放置到接收队列上。最终这些buffer将被全部消耗掉。应用程序必须实现内部的流量控制,以确保在远端没有准备好接收的情况下不放置任何发送请求到SQ上。

    8.6 Connecting | 连接

    The next step occurs in pp_client_exch_dest and pp_server_exch_dest. The QPs need to be configured to point to a matching QP on a remote node. However, the QPs currently have no means of locating each other. The processes open an out-of-band TCP socket and transmit the needed information. That information, once manually communicated, is given to the driver and then each side's QP is configured to point at the other. (The OFED librdma_cm library is an alternative to explicit out-of-band TCP.)
    下一步发生在pp_client_exch_dest和pp_server_exch_dest中。QP需要配置一下,指向远端结点的QP。然而,目前QP没有定位对方的方法。进程打开带外TCP socket并传输所需要的信息。这些信息传递给驱动,然后每一方的QP就被配置为指向另一方的QP。(使用OFED的librdma_cm库,可以用来替代显式的TCP带外数据。)

    So what information needs to be exchanged/configured? Mainly the LID, QPN, and PSN. The LID is the "Local Identifier" and it is a unique number given to each port when it becomes active. The QPN is the Queue Pair Number, and it is the identifier assigned to each queue on the HCA. This is used to specify to what queue messages should be sent. Finally, the destinations must share their PSNs.
    那么,哪些信息需要交换和配置? LID, QPN和PSN。 LID是本地ID的缩写,当一个port变成活跃状态的时候,port就被分配了一个独一无二的数字。QPN是QP Number的缩写,是在HCA上分配给每一个队列的标识符。QPN用来指定消息发送到哪个队列上去。最后,目标必须共享它们的PSN。

    The PSN stands for Packet Sequence Number. In a reliable connection it is used by the HCA to verify that packets are coming in order and that packets are not missing. The initial PSN, for the first packet, must be specified by the user code. If it is too similar to a recently used PSN, the hardware will assume that the incoming packets are stale packets from an old connection and reject them.
    PSN代表的是包序列号。在可靠连接中,HCA用PSN来保证一个个数据包是有序到达的而且没有丢包。第一个数据包最初的PSN,必须由用户代码指定。如果PSN与最近使用的一个PSN很相似的话,硬件就假定传入的数据包是一个陈腐的包,来自一个旧连接,然后予以拒绝。

    The GID, seen in the code sample below, is a 128-bit unicast or multicast identifier used to identify an endport. The link layer specifies which interconnect the software is running on; there are other interconnects that OFED supports, though that is not within the scope of this paper.
    在下面的代码示例中,GID是一个128位的单播或者多播的标识符,用来标识一个终端端口。链路层指定了软件在哪种互联协议上运行。OFED还支持除IB之外的其他互联协议,那些协议不在本论文的讨论范围之内。

    Within pp_connect_ctx the information, once transmitted, is used to connect the QPs into an end-to-end context.
    在pp_connect_ctx之中的信息,一旦传输完成,就用于连接QP对到一个端到端的上下文中。

    /* Listing 15: Setting Up Destination Information */
    
    665         my_dest.lid = ctx->portinfo.lid;
    666         if (ctx->portinfo.link_layer == IBV_LINK_LAYER_INFINIBAND && !my_dest.lid) {
    667                 fprintf(stderr, "Couldn't get local LID\n");
    668                 return 1;
    669         }
    670
    671         if (gidx >= 0) {
    672                 if (ibv_query_gid(ctx->context, ib_port, gidx, &my_dest.gid)) {
    673                         fprintf(stderr, "Could not get local gid for gid index %d\n", gidx);
    674                         return 1;
    675                 }
    676         } else
    677                 memset(&my_dest.gid, 0, sizeof my_dest.gid);
    678
    679         my_dest.qpn = ctx->qp->qp_num;
    680         my_dest.psn = lrand48() & 0xffffff;

    The my_dest data structure is filled and then transmitted via TCP. Figure 4 illustrates this data transfer.
    数据结构my_dest被填充,然后通过TCP传送。图4显示了这一数据传送。

    8.6.1 Modifying QPs | 修改QP

    Look at the attributes given to the ibv_modify_qp call.
    让我们看一看传递给ibv_modify_qp()调用的属性。

    /* Listing 16: Moving QP to Ready to Recv */
    
     84         struct ibv_qp_attr attr = {
     85                 .qp_state               = IBV_QPS_RTR,
     86                 .path_mtu               = mtu,
     87                 .dest_qp_num            = dest->qpn,
     88                 .rq_psn                 = dest->psn,
     89                 .max_dest_rd_atomic     = 1,
     90                 .min_rnr_timer          = 12,
     91                 .ah_attr                = {
     92                         .is_global      = 0,
     93                         .dlid           = dest->lid,
     94                         .sl             = sl,
     95                         .src_path_bits  = 0,
     96                         .port_num       = port
     97                 }
     98         };
    ...
    106         if (ibv_modify_qp(ctx->qp, &attr,
    107                           IBV_QP_STATE              |
    108                           IBV_QP_AV                 |
    109                           IBV_QP_PATH_MTU           |
    110                           IBV_QP_DEST_QPN           |
    111                           IBV_QP_RQ_PSN             |
    112                           IBV_QP_MAX_DEST_RD_ATOMIC |
    113                           IBV_QP_MIN_RNR_TIMER)) {
    114                 fprintf(stderr, "Failed to modify QP to RTR\n");
    115                 return 1;
    116         }

    As you can see .qp_state is set to IBV_QPS_RTR, or Ready-To-Receive. The three fields swapped over TCP, the PSN, QPN, and LID, are now given to the hardware. With this information, the QPs are registered with each other by the hardware, but are not ready to begin exchanging messages. The min_rnr_timer is the time, in seconds, between retries before a timeout occurs.
    正如你所看到的,.qp_state被设置为IBV_QPS_RTR或Ready-To-Receive(接收就绪)。通过TCP交换到的三个字段(PSN, QPN和LID),现在传给硬件。有了这些信息,彼此的QP被注册到对方的硬件上,但还没有为开始消息交换准备就绪。min_rnr_timer是重试的时间间隔(以秒为单位),在发生超时的时候。

    The QP must be moved into the Ready-To-Send state before the "connection" process is complete.
    在连接过程完成之前,QP状态必须被改变到Ready-To-Send(发送就绪)状态。

    /* Listing 17: Moving QP to Ready to Send */
    
    118         attr.qp_state       = IBV_QPS_RTS;
    119         attr.timeout        = 14;
    120         attr.retry_cnt      = 7;
    121         attr.rnr_retry      = 7;
    122         attr.sq_psn         = my_psn;
    123         attr.max_rd_atomic  = 1;
    124         if (ibv_modify_qp(ctx->qp, &attr,
    125                           IBV_QP_STATE              |
    126                           IBV_QP_TIMEOUT            |
    127                           IBV_QP_RETRY_CNT          |
    128                           IBV_QP_RNR_RETRY          |
    129                           IBV_QP_SQ_PSN             |
    130                           IBV_QP_MAX_QP_RD_ATOMIC)) {
    131                 fprintf(stderr, "Failed to modify QP to RTS\n");
    132                 return 1;
    133         }

    The attr used to move the QP into IBV_QPS_RTS is the same attr used in the previous call. There is no need to zero out the structure because the bitmask, given as the third argument, specifies which fields should be set.
    用来将QP状态改变到IBV_QPS_RTS的attr跟前面调用使用的attr是一模一样的。没有必要将数据结构初始化为0, 因为第三个参数bitmask指定了哪些字段需要被设置。

    After the QP is moved into the Ready-To-Send state, the connection (end-to-end context) is ready.
    当QP状态处于Ready-to-Send的时候,端到端的连接就准备好了。

    8.7 Sending Data | 数据发送

    Since the server already posted receive buffers, the client will now post a "send" work request.
    既然服务器端已经放置了接收缓冲区,那么客户端即将放置一个“发送”工作请求。

    /* Listing 18: Client Posting Send */
    
    468         struct ibv_sge list = {
    469                 .addr   = (uintptr_t) ctx->buf,
    470                 .length = ctx->size,
    471                 .lkey   = ctx->mr->lkey
    472         };
    473         struct ibv_send_wr wr = {
    474                 .wr_id      = PINGPONG_SEND_WRID,
    475                 .sg_list    = &list,
    476                 .num_sge    = 1,
    477                 .opcode     = IBV_WR_SEND,
    478                 .send_flags = IBV_SEND_SIGNALED,
    479         };
    480         struct ibv_send_wr *bad_wr;
    481
    482         return ibv_post_send(ctx->qp, &wr, &bad_wr);

    The wr_id is an ID specified by the programmer to identify the completion notification corresponding with this work request. In addition, the flag IBV_SEND_SIGNALED sets the completion notification indicator. According to ibv_post_send(3), it is only relevant if the QP is created with sq_sig_all = 0.
    wr_id是由程序员指定的ID,用来识别与这个WR相对应的完成通知。另外,标志IBV_SEND_SIGNALED设置了完成通知指示灯。根据ibv_post_send(3),只有当QP创建的时候设置了sq_sig_all等于0时才相关。

    8.8 Flow Control | 流量控制

    Programmers must implement their own flow control when working with the verbs API. Let us examine the flow control used in ibv_rc_pingpong. Remember from earlier that a client cannot post a send if its remote node does not have a buffer waiting to receive the data.
    当使用verbs API的时候,程序员必须自己实现流量控制。让我们看看ibv_rc_pingpong里的流量控制。记住我们在前面强调的,如果远端结点没有准备好等待接收数据的缓冲区,client就不能够发送数据。

    Flow control must be used to ensure that receivers do not exhaust their supply of posted receives. Furthermore, the CQ must not overflow. If the client does not pull CQEs off the queue fast enough, the CQ is thrown into an error state, and can no longer be used.
    使用流量控制是必须的,以确保接收端不会耗尽它所提供的接收资源。此外,CQ必须不能够溢出。如果client不能足够快地把CQE从CQ上拉取下来的话,那么CQ就会陷入错误状态以致于不能再被使用。

    You can see at the top of the loop, which will send/recv the data, that ibv_rc_pingpong tracks the send and recv count.
    可以看到,发送/接收数据位于循环的顶部,ibv_rc_pingpong跟踪了发送和接收的计数器。

    /* Listing 19: Flow Control */
    
    717         rcnt = scnt = 0;
    718         while (rcnt < iters || scnt < iters) {

    Now the code will poll the CQ for two completions; a send completion and a receive completion.
    现在,代码将为发送完成(SC)和接收完成(RC)轮询CQ。

    /* Listing 20: Polling the CQ */
    
    745                         do {
    746                                 ne = ibv_poll_cq(ctx->cq, 2, wc);
    747                                 if (ne < 0) {
    748                                         fprintf(stderr, "poll CQ failed %d\n", ne);
    749                                         return 1;
    750                                 }
    751
    752                         } while (!use_event && ne < 1);

    The use_event variable specifies whether or not the program should sleep on CQ events. By default, ibv_rc_pingpong will poll. Hence the while-loop. On success, ibv_poll_cq returns the number of completions found.
    变量use_event指定是否在CQ时间上进行sleep。默认地,ibv_rc_pingpong进行轮询。因此使用了while循环。轮询成功后,ibv_poll_cq()返回工作完成(WC)的数量。

    Next, the program must account for how many sends and receives have been posted.
    接下来,程序必须统计放置的发送请求和接受工作请求的个数。

    /* Listing 21: Flow Control Accounting */
    
    762                                 switch ((int) wc[i].wr_id) {
    763                                 case PINGPONG_SEND_WRID:
    764                                         ++scnt;
    765                                         break;
    766
    767                                 case PINGPONG_RECV_WRID:
    768                                         if (--routs <= 1) {
    769                                                 routs += pp_post_recv(ctx, ctx->rx_depth - routs);
    770                                                 if (routs < ctx->rx_depth) {
    771                                                         fprintf(stderr,
    772                                                                 "Couldn't post receive (%d)\n",
    773                                                                 routs);
    774                                                         return 1;
    775                                                 }
    776                                         }
    777
    778                                         ++rcnt;
    779                                         break;
    780
    781                                 default:
    782                                         fprintf(stderr, "Completion for unknown wr_id %d\n",
    783                                                 (int) wc[i].wr_id);
    784                                         return 1;
    785                                 }

    The ID given to the work request is also given to its associated work completion, so that the client knows what WQE the CQE is associated with. In this case, if it finds a completion for a send event, it increments the send counter and moves on.
    给WR使用的ID也被给到相关联的WC上,于是client就知道CQE是关联到那一个WQE上。在这个案例中,如果为一个发送事件找到了一个工作完成,就增加发送计数器然后继续。

    The case for PINGPONG_RECV_WRID is more interesting, because it must make sure that receive buffers are always available. In this case the routs variable indicates how many recv buffers are available. So if only one buffer remains available, ibv_rc_pingpong will post more recv buffers. In this case, it calls pp_post_recv again, which will post another 500 (by default). After that it increments the recv counter.
    PINGPONG_RECV_WRID的案例更有趣,因为它必须确保接收缓冲区总是可用的。在这种情况下,变量routs表示有多少接收缓冲区可用。所以,如果只有一个缓冲仍然可用,ibv_rc_pingpong将会放置更多的接收缓冲区。在这种情况下,它要求pp_post_recv再放置500(默认值)个接收缓冲区,然后增加recv计数器。

    Finally, if more sends need to be posted, the program will post another send before continuing the loop.
    最后,如果需要放置更多的发送请求,程序将在继续循环之前放置另一个发送请求。

    /* Listing 22: Posting Another Send */
    
    787                                 ctx->pending &= ~(int) wc[i].wr_id;
    788                                 if (scnt < iters && !ctx->pending) {
    789                                         if (pp_post_send(ctx)) {
    790                                                 fprintf(stderr, "Couldn't post send\n");
    791                                                 return 1;
    792                                         }
    793                                         ctx->pending = PINGPONG_RECV_WRID |
    794                                                        PINGPONG_SEND_WRID;
    795                                 }

    8.9 ACK

    The ibv_rc_pingpong program will now ack the completion events with a call to ibv_ack_cq_events. To avoid races, the CQ destroy operation will wait for all completion events returned by ibv_get_cq_event to be acknowledged. The call to ibv_ack_cq_events must take a mutex internally, so it is best to ack multiple events at once.
    程序ibv_rc_pingpong将调用ibv_ack_cq_events()对完成的事件进行确认。为了避免竞态,CQ的destroy操作将等待所有完成事件并确认。调用ibv_ack_cq_events()必须持有内部的互斥锁,所以最好是一次确认多个事件。

    816         ibv_ack_cq_events(ctx->cq, num_cq_events);

    As a reminder, ibv_ack_cq_events(3) has helpful sample code.
    友情提醒一下,ibv_ack_cq_events(3)有提供帮助性的示例代码。

    9 Conclusion | 结束语

    InfiniBand is the growing standard for supercomputer interconnects, even appearing in departmental clusters. The API is complicated and sparsely documented, and the sample program provided by OFED, ibv_rc_pingpong, does not fully explain the functionality of the verbs. This paper will hopefully enable the reader to better understand the verbs interface.
    在超级计算机互联标准中,IB正在蓬勃生长,已经出现在集群中。由于verbs的API较为复杂,而且文档记录比较稀疏。OFED提供的示例程序ibv_rc_pingpong并不能完全解释verbs的功能。本文希望读者在阅读之后,能够更好地理解verbs的用户接口。

    10 Acknowledgements | 致谢

    Gene Cooperman (Northeastern University) and Jeff Squyres (Cisco) contributed substantially to the organization, structure, and content of this document. Jeff also took the time to discuss the details of InfiniBand with me. Josh Hursey (Oak Ridge National Laboratory) shared his knowledge of InfiniBand with me along the way. Roland Dreier (PureStorage) pointed out, and corrected, a mistake in my explanation of acks.
    东北大学的Gene Cooperman和思科的Jeff Squyres对此文档的结构,内容做出了重大贡献。Jeff还花了不少时间和我讨论IB的细节。橡树岭国家实验室的John Hursey跟我分享了有关IB的知识。Pure存储的Roland Dreier指出和纠正了我在解释ACK时存在的错误。

    References | 参考文献

    • [1] Jason Ansel, Gene Cooperman, and Kapil Arya. DMTCP: Scalable user-level transparent checkpointing for cluster computations and the desktop. In Proc. of IEEE International Parallel and Distributed Processing Symposium (IPDPS-09, systems track). IEEE Press, 2009. published on CD; software available at http://dmtcp.sourceforge.net.
    • [2] InfiniBand Trade Assocation. InfiniBand Architecture Specification Volume 1, Release 1.2.1, November 2007. http://www.infinibandta.org/content/pages.php? pg=technology_download.

     

    Do one thing at a time, and do well. | 一次只做一件事,做到最好!

     

    转载于:https://www.cnblogs.com/vlhn/p/8010701.html

    展开全文
  • Badush大坝是部分完成的大坝,也是防洪大坝的独特案例。 其预期的主要功能是在其使用寿命内执行一次防洪; 那就是摩苏尔大坝倒塌了。 在这种情况下,巴杜什(Badush)大坝将暂时存储整个洪水波,并将其安全地路由到...
  • 在该存储库中,您可以找到(i)本文第4节的流程图,(ii)关于第一个测试用例的数据陈述和有关数据,第5.1节,关于Quine的认识,以及(iii)数据陈述和有关第二个测试案例5.2节中的数据,有关《哲学史》的文献...
  • 公认的是,勘探是发现有利可图的经济原材料之前的第一步... 因此,GIS具有存储,更新,修改,显示,检索,处理,操纵和集成不同地理空间数据的功能。 到本研究结束时,我们将能够节省时间和金钱,并提高利润率和功效。
  • 1. 2019年上半年真题 1.1. 上午综合知识真题 1、RFID射频技术多应用于物联网的()。 A、网络层 B、感知层 C、应用层 D、传输层 ...B、计算与存储层 C、物联感知层 D、数据及服务支撑层 参考答案:D 3...
  • 先了解一下大数据的发展史通常认为2003年google发表的那“三篇经典论文”是大数据技术的开端,之后不久便诞生了开源的map-reduce的计算框架,hdfs文件存储系统,hbase数据存储系统;2010年spark开源,并逐渐替代...
  • 存储案例知识的案例知识库是基于案例推理的基础和必要条件,案例知识库的研究有深远意义。 本文重点研究基于本体和句子向量空间模型(SVSM,Sentence Vecter Space Model)的案例知识库关键技术,完成的主要工作如下:...
  • 为了解决低碳经济环境下闭环物流网络设计问题,在碳排放权交易的约束下,以排队计算逆向物流节点的存储量,考虑物流网络的运输成本、存储成本、建设成本、时间惩罚成本及碳交易成本,建立了以总成本最低为目标的...
  • 个人之前总结过两篇文章,都是在工作中遇到相关案例后的一个简单总结。当初的经验不足,认知有限,所以现在来看来,当初的博文确实显得浅析和不够全面,这个也没有办法,当时有些环境或案例没有涉及过,所以文章很难...
  • 文本挖掘过程及案例

    千次阅读 2013-05-30 13:45:04
    一个文本挖掘过程及案例 [Nirvana 发表于 2007-4-23 23:34:00] 一、文本挖掘概念  在现实世界中,可获取的大部信息是以文本形式存储在文本数据库中的,由来自各种数据源的大量文档...
  • 空间预测模型的适用范围 论文“在未知空间中进行预测?估计空间预测模型的适用范围”的案例研究... 结果存储在“ data /”中。 “ CaseStudyScenarios_figures.R”可用于分析不同方案的结果并创建本文中使用的数字。
  • 目录论文背景SPADE是什么案例研究比特币挑战收集/查询集成存储扩展基于内容的集成仓储筛选结论 论文背景 起源中间件(如SPADE)允许个人和应用程序使用一个公共框架来报告、存储和查询记录,这些记录描述了计算过程和...
  • 数据挖掘:大数据智能分析方案及案例分析(ppt) 数据是新型石油未开采的石油没有什么价值 加工及提炼后将助力世界对大数据的处理分析正成为新一代信息技术融合应用的结点移动互联网物联网社交网络数字家庭电子商务等是...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 146
精华内容 58
关键字:

存储论案例