65.9K
CodeProject 正在变化。 阅读更多。
Home

超级计算机的构建 - 架构和设计

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (45投票s)

2016年4月10日

CPOL

67分钟阅读

viewsIcon

83556

在本文中,我们将深入探讨一台跻身 TOP 500 排行榜的高效超级计算机 QPACE 2 的开发过程。

QPACE2 KNC Mars

目录

  1. 引言
  2. 背景
  3. 架构
    1. 高层设计
    2. Intel Xeon Phi
    3. PCIe 通信
    4. 网络架构
    5. 机架构建
    6. 监控与维护
  4. 热水冷却
    1. 快速接头与集管
    2. 滚压成型板和衬垫
    3. 管道、胶水和导热膏
  5. 软件堆栈
    1. 操作系统和配置
    2. 编译器和工具
    3. 固件和驱动程序
    4. 通信库
    5. 关键基准测试
  6. 关注点
  7. 参考文献
  8. 历史

引言

有时人们会问我做什么。我想我做的事情很多,也许太多了。但老实说,.NET 和 Web 是很好的伙伴,我永远不会背叛它们。因此,我将大部分时间投入到另一个但密切相关的领域:高性能计算(HPC)。HPC 是一个致力于开发更大、更高效系统的行业。世界上最大的模拟都是在 HPC 系统上运行的。HPC 行业的现状体现在两个非常重要的列表中:TOP 500,包含当前地球上最快的 500 台超级计算机,以及 Green 500。如果一台机器列在 TOP 500 中,它就有资格进入 Green 500。Green 500 关注的是每瓦特计算量。如果一台机器能够运行最多的计算,但需要最多的能量,那么它可能不如第二台系统高效,后者几乎可以执行相同数量的计算,但能耗要少得多。

超级计算机非常昂贵。设计、购买和建造系统的单次价格实际上相当低,与其运行系统所产生的经常性成本相比。标准的 HPC 系统很容易消耗数百千瓦的电力。因此,出现了节能计算的强烈趋势。幸运的是,芯片供应商也跟上了这一趋势,并为我们提供了新的、令人兴奋的可能性。如今,ARM 是未来节能系统的一个有力候选者。但谁知道未来会发生什么?设计可能性似乎无穷无尽。然而,好的想法仍然稀缺。

引入热水冷却是一个绝妙的主意。常规(冷水)冷却已经存在一段时间了,但效率并非最大化。当然,它比标准的空气冷却效率高得多,但冷水机组的运行和维护是真正的障碍。它们需要大量能源。热水冷却有望实现全年无冷水机组(即免费)的冷却。基本原理与血液在我们体内的流动方式相似。

在本文中,我将尝试讨论设计最先进的超级计算机背后的思想和原则。我将概述一些关键决策,并讨论一台真实机器的整个过程:QPACE 2。这台小型机器足够快,可以轻松跻身 TOP 500。它也足够高效,是目前已知宇宙中效率最高的二十台系统之一。原型机安装在雷根斯堡大学。也可以购买为该项目创建的技术。EuroTech 的 Aurora Hive 系列 是该项目衍生出的商业化产品。

背景

很久以前,我意识到我想为 CodeProject 写一篇独特的文章。一篇涵盖了很少解释的主题的文章,并且不是产生非常广泛和笼统的解释,而是更专业和可能有趣的东西。只有一个主题:超级计算!

过去,我们看过一些很棒的文章,例如 Nick Kopp 的《使用 Cudafy 进行 .NET 中的 GPGPU 编程》(Using Cudafy for GPGPU Programming in .NET)(别忘了也看看他相关的文章 CUDA Programming Model on AMD GPUs and Intel CPUs),以及一些经典的文章,例如《从 C++ 到 MMX 的高性能计算》(High performance computing from C++ to MMX)。同样,微软 Azure IoT 大赛期间无数精彩的 IoT 文章也不应被遗忘。

所以,我想做的是对该领域进行广泛概述,然后更详细地深入研究非常专业的主题。特别是关于热水冷却的部分应该引起兴趣。整篇文章都围绕着高效高性能计算的主题。该领域研究的后果尤其有趣。它们将为未来的数据中心、移动设备和个人计算提供动力。能源需求的增长必须停止。但计算需求不会消失。这场危机只能通过改进的技术和更智能的算法来解决。我们需要用更少的资源做更多的事情。

我希望您喜欢这次旅程。我包含了很多图片来可视化这个过程,尽管我的写作技巧有限。

架构

当启动一个 HPC 项目时,必须要有一定的需求。通常会选择一个特定的应用程序来利用即将推出的机器的能力。这台机器的设计和架构必须针对该特定应用程序进行调整。

有时有许多选项可以实现所需应用程序的目标。在这里,我们需要考虑次要参数。在我们的案例中,我们追求创新的冷却、高计算密度和卓越的效率。这使得选项减少到两个候选者,两者都是加速器。一个是高端 Nvidia GPU,另一个选项是 Intel 的一款全新产品,称为协处理器。它基本上是“打了肾上腺素的 CPU”。它包含比标准 Xeon 处理器更多的核心。这些核心相当弱,但拥有强大的矢量单元。这是一种 x86 兼容的微架构。

此时,回头看看应用程序会比较好。对于应用程序来说,什么会更好?我们的应用程序已经针对 x86(类似)处理器进行了调整。虽然也可以调整为 GPU 卡,但当时创建另一个工作项似乎没有必要。而且使用 Xeon Phi 似乎很具创新性。好了,所以我们的架构将围绕 Intel Xeon Phi——代号 KNC(*Knights Corner*)展开,这是第一个公开可用的 MIC 产品(*Many Integrated Cores*)。

这就是实际设计和架构的开始。在以下子节中,我们将讨论查找组件的过程,例如

  • 电源 (PSU)
  • 电源分配 (PDU)
  • 冷却(节点内)
  • 封装密度(节点)
  • 主机处理器 (CPU)
  • 主板管理 (BMC)
  • 网络 (NWP)
  • PCIe 通信(节点内)
  • 网络拓扑(节点间)
  • 机箱(机架)
  • 远程电源控制
  • 紧急关机
  • 监控系统

这有很多东西,我希望能给大部分部分应有的空间。

高层设计

从效率的角度来看,很明显设计应该是以加速器为中心。加速器比普通 CPU 具有更好的运行/能量比。我们希望修改应用程序的设计,基本上绕过 CPU 的使用(除了简单的任务,例如分发任务或发出 IO 写入)。将此目标反映在设计中的方式是通过减少 CPU 数量并最大化协处理器数量。

Xeon Phi 不是独立系统。它需要一个真正的 CPU 才能启动。毕竟,它只是一个扩展板。因此,我们需要至少 1 个 CPU 在整个系统中。现在关键问题是如何一个 CPU 可以支持多少协处理器?CPU 的要求是什么?我们可以使用任何 CPU(x86、ARM...)吗?事实证明,有很多选择,但大多数都有明显的缺点。

失败可能性最小的选项是购买标准的 Intel 服务器 CPU。Intel 推荐使用这些 CPU 与 Xeon Phi 协处理器配合使用。有一些最低要求需要遵守。标准解决方案将包含两个协处理器。2:1 的比例听起来不错,但远未达到我们想要的密度。除了尽可能多地使用协处理器的要求外,我们仍然需要确保能够支持高速网络连接。

最终,我们得出的架构如下所示。我们在 PCIe 总线上有 6 个卡,其中一张包含 CPU,另一张用于网络连接。其余四个插槽分配给 Xeon Phi 协处理器。

QPACE2 Node Design

CPU 板的设计和架构已外包给一家日本专业公司。他们只需要知道主板的规格。它的尺寸是多少?它应该使用/兼容多少 PCIe 通道和什么代?应该集成什么处理器?主板管理控制器怎么样?需要添加哪些类型的外围设备?

最终,完成的卡包含了我们关心的所有内容。它甚至还有一个 VGA 连接器,尽管我们通常不会连接显示器。但这样的小连接器对于调试至关重要。

CPU 板名为 Juno。它配备了一个低功耗 CPU。Intel Xeon E3-1230L v3 非常适合我们的需求。它支持我们设想的设置。

Juno CPU Card QPACE2

谈到调试:CPU 卡本身没有足够的空间来提供所有调试可能性。相反,提供了一系列插槽,可以与子板上的引脚阵列结合使用。这个子板包含另一个以太网和 USB 连接器,以及另一系列插槽。后者可与 UART 一起使用。UART 允许我们做很多有趣的事情,例如刷新 BMC 固件或进行 BIOS 更新。

Juno Subboard QPACE2

UART 也可用于连接到 BMC 或接收其调试输出。如果没有网络连接,UART 可能是联系机器的唯一方式。

内部所有事情都取决于两件事:电力和通过 PCIe 总线的通信。这两项任务都由中板管理,可以将其视为主板。此组件的设计和建造已外包给一家意大利公司。特别是正确实现 PLX 芯片的规格非常庞大。有很多边缘情况,需要对 PCIe 总线系统有大量的了解。

PLX 芯片是 PEX 8796。它是一款 96 通道、24 端口的 PCIe Gen3 交换芯片,采用 40nm 技术开发。因此,它足以满足我们的需求。下图显示了没有附加设备的中板。PCIe 交换芯片上方的无源散热片未安装在最终设计中。

Mars Card Midplane QPACE2

中板名为 Mars。它无疑是 QPACE 2 节点中最长的组件。它通过三个 LED 显示系统的基本信息。它包含六个 PCIe 插槽。它具有热插拔控制器,可实现热插拔功能。热插拔控制器最基本的功能包括控制电流和提供故障隔离。

该板还具有 I²C 扩展器和 I²C 交换器。这使得整体设计非常容易扩展。内部的 BMC(主板管理控制器)负责连接到 I²C 设备。因此,BMC 映像需要我们自定义。BMC 还提供 IPMI 接口,允许其他设备获取系统状态信息。

为 BMC 设置的一个关键任务是监控系统的温度。虽然我们稍后会看到整个机架已经建立了一个完整的监控基础设施,但节点需要能够检测异常的持续温度尖峰,这可能需要完全关闭节点。

同样,集成了高效的漏水传感器,以防止单个泄漏未被发现。在发生局部泄漏的情况下,节点需要关闭以防止进一步损坏。漏水也应通过冷却回路中的压力损失来检测。

Intel Xeon Phi

Intel Xeon Phi 是第一款基于 Intel 的 Many Integrated Cores 架构的公开产品。它有几种版本。为了我们的目的,我们决定使用带有 61 个核心、16 GB GDDR5 内存和 1.2 GHz 的版本。确切的版本是 7120X。X 表示该产品出厂时不带任何散热片。下图显示了一个带有主动散热底座的 Intel Xeon Phi 封装。

Intel Xeon Phi Package

我们可以将 Intel Xeon Phi 称为协处理器、加速器、处理器卡、KNC 或仅称为 MIC。尽管如此,需要注意的是,每个术语都有细微的差别。例如,加速器可能是最广泛的术语。它也可以指 GPU。MIC 也可能指另一代协处理器,例如 KNL(KNC 的后继者,即将上市)或 KNF(前代,我们可以称之为 KNC 的原型或测试版)。

让我们深入了解 Xeon Phi 的一些细节。毕竟,我们需要了解其架构的所有细节。它将是我们工作的主要单元,我们的应用程序需要完美地调整才能从该设备获得最大数量的操作。否则,我们会损失效率,而这是我们最后想减少的东西。

以下两张图片分别展示了组装好的 KNC PCB 的两面。我们从背面开始。

Intel Xeon Phi Back Details

KNC 包含一个小型闪存单元,可用于更改硬件设置、访问内部错误缓冲区或进行固件升级。它是一个或多或少独立的系统。因此,它需要一个 SMC 单元。SMC 单元还管理系统的各种计数器。它聚合并分发从各种传感器接收到的数据。

该板非常密集,很难弄清楚重要的组件分布在哪一面。例如,GDDR 内存芯片肯定放置在两面。它们围绕芯片形成一个环。我们稍后将看到,内部布线也反映了这一点。

前面也显示了相同的 GDDR 环。

Intel Xeon Phi Front Details

前面似乎有很多事情在发生。我们有两个电源连接器、各种温度传感器(总共有七个)以及电子元件,如稳压器。最重要的是,我们不仅看到了硅的通孔,还看到了芯片本身。这是一个巨大的芯片——它承载着 61 个核心。

单个 KNC 在压力下可能消耗高达 300W 的功率。空闲时功耗可能低至 50W,但如果没有一些技巧,我们可能会徘徊在 100W 左右。一个不错的功能是蓝色的状态 LED。它可能是最没用的 LED 之一。事实上,我从未从中获得任何有用的信息。如果 KNC 在启动过程中失败,它会闪烁。如果成功,它也会闪烁。不用说,工作 LED 的唯一条件是 PCIe 连接。即使没有连接电源,LED 也会通过 PCIe 连接器传输的电流闪烁。

在内部,KNC 的核心通过环总线系统相互连接。每个核心都有一个共享的 L2 缓存,该缓存连接到一个分布式标签目录。KNC 核心的缓存一致性协议是 MESI。最多有 6 个内存控制器,也可以通过环总线访问。最后,环总线代理与 PCIe 树的连接。

下图说明了环总线的概念。

Intel Xeon Phi Architecture

比理解核心之间的通信更重要的是了解核心的内部架构。了解缓存层次结构并避免缓存未命中至关重要。持续使用浮点单元而不是等待数据传输可确保高性能。

我们关心两件事:组件提供的带宽(以 GB/s 为单位)和访问设备的延迟(这里我们计算时钟周期)。总的来说,观察到的行为与常识相似。这些基本上是每个程序员都应该知道的数字。

有趣的是,访问另一个核心的 L2 缓存比读取其自身的 L2 缓存要昂贵一个数量级。但仍然比访问内存控制器控制的数据便宜一个数量级。

下一张图给出了一些准确的数字,让我们对内部工作有一个更好的印象。我们使用 2 个线程而不是 4 个线程,因为在一个周期内只运行 2 个线程。线程仅在其他周期运行,实际上将所有四个线程的频率减半。

Intel Xeon Phi Memory Hierarchy

相当低的内存带宽是一个大问题。有些应用程序不是真正的内存密集型,但对于我们在 Lattice QCD 中的应用程序,我们肯定会受到内存带宽的限制。一旦我们达到内存限制,我们的优化基本上就完成了。下一步是寻找更好的算法,这些算法可能会降低内存带宽要求。这可以通过更好的数据结构、更多的数据重用或对需要解决的问题更有效的近似来实现。

QPACE 2 的模块化设计使得理论上可以更换 KNC,例如 KNL。唯一的实际要求是 PCIe 芯片和主机 CPU 能够管理新卡。但除此之外,没有其他真正的限制因素。

PCIe 通信

CPU 作为 PCIe 根复合体。协处理器和 Connect-IB 卡是 PCIe 端点。通过交换机可以实现任何一对端点之间的点对点(P2P)通信。此节点设计背后的原理是高性能网络通常相当昂贵。一个拥有多个处理单元和廉价内部通信(在此情况下通过 PCIe)的“胖”节点具有更小的表面积与体积比,因此每浮点性能所需的网络带宽更少。这降低了网络的相对成本。

PCIe 交换机上的 KNC 和 InfiniBand 卡数量取决于商用交换机支持的通道数以及节点内部和外部的通信要求。我们使用的是最大的可用交换机,它支持 96 个 PCIe Gen3 通道。每个 Intel Xeon Phi 都有一个 16 通道的 Gen2 接口。这对应于 8 GB/s 的带宽。CPU 和 Connect-IB 卡都有一个 16 通道的 Gen3 接口,即每个近 16 GB/s。两个 FDR 端口的外部 InfiniBand 带宽为 13.6 GB/s。这种内部和外部带宽的平衡符合我们目标应用程序的通信要求。

下图显示了我们的 PCIe 测试板。它配备了 PLX 芯片,并包含 PCIe 插槽,就像普通的 ATX 主板一样。此外,它还配有大量跳线,用于根据我们的需求设置总线。此外,我们通过集成 LCD 显示屏显示了一些调试信息。

Test Setup PCIe

PCIe 总线是机器整体设计中的关键组件。节点内通信完全通过 PCIe 总线完成。因此,要求具备尽可能好的信号质量。我们进行了许多测量,并确保了链路训练尽可能顺利进行。信号质量通过标准的眼图进行控制。尽管每个 PCIe 通道都应该发挥最佳性能,但无法像期望的那样对每个通道进行详尽测试。我们不得不推断或根据有限的信息得出结论。然而,结果相当不错。总的来说,我们只看到很少的 PCIe 错误,如果有的话。我们偶尔检测到的少数错误都是可纠正的,并且不影响整体性能。

网络架构

InfiniBand 网络被选为我们网络架构的骨干。这种解决方案肯定可以被认为是保守的。在 TOP 500 超级计算机中,InfiniBand 是大多数安装中使用的互连技术。不过,以太网仍然相当流行。我们可以将 224 个 InfiniBand 安装与 100 个使用 Gb/s 以太网连接的安装以及 88 个使用 10 Gb/s 的安装进行比较。

合适的网络拓扑必须确保需要更少的线缆(以及更少的连接器),同时最大程度地减少对交换机的需求并提高通信的直接性。最简单但昂贵且不切实际的方法是连接每个节点与所有其他节点。然而,在这里,每个节点需要 N-1 个端口。这些端口需要正确布线。大量的线缆和大量的端口,通常会导致大量的卡。

因此,我们需要一种更智能的方式来实现我们的目标。一种好的方法是首先查看可能的端口数量。在我们的案例中,决定是在单端口解决方案和双端口解决方案之间进行选择。两个单端口卡不是一个合适的解决方案,因为这样的解决方案会占用过多的 PCIe 插槽。自然,一个显而易见的解决方案是仅连接最近的邻居。

环形网络描述了这种网格互连。我们可以将节点排列在 N > 1 个维度的直线阵列中,处理器连接到它们最近的邻居,并且阵列相对边缘的相应处理器连接起来。这里每个节点有 2N 个连接。再次,我们每个节点没有足够的端口。最少的数量将是四个。有了两个端口,我们只能创建一个环总线。

最终,我们决定可能的最佳选择是使用超交叉结构拓扑。这之前已经被使用过,例如由日本 CP-PACS 合作项目。基本上,我们通过将节点数量的两倍(即每个节点 2 个端口)除以每个交换机的端口数量来计算交换机的数量。在我们的案例中,每个交换机有 36 个端口,剩下 4 个交换机。我们使用每个交换机的 32 个端口用于节点,额外的端口分配给将机器连接到存储系统。超交叉结构解决方案是二维的,这意味着我们在 x 方向上有 2 个交换机,在 y 方向上也有相同数量的交换机。

Hyper-Crossbar Network Topology

上一张图显示了我们场景中的超交叉结构拓扑。x 方向的交换机用红色矩形标记,y 方向的交换机用蓝色矩形标记。每个节点由一个黑色轮廓的椭圆表示。两个端口的分配由圆点指示。圆点以其分配的交换机的相应颜色绘制。

对于超交叉结构,我们需要一个双端口连接器。另一个要求是支持 FDR 数据速率。FDR 代表十四数据速率。FDR 启用了一个合适的候选者,可以使用 Mellanox 的 Connect-IB 卡。该卡每个端口提供 56 Gb/s,总计高达 112 Gb/s。

此外,Connect-IB 在小消息方面也很出色。单卡每秒可处理至少 1.3 亿条消息。延迟测量约为一微秒。对于我们来说,该卡特别有趣,因为它允许 CPU 卸载传输操作。这是硬件增强传输,或 DMA。无需 CPU 即可将字节传输到设备。最终,我们将特别受益于我们的协处理器。

下图显示了一张 Connect-IB 卡,已安装无源散热片。我们还保留了安装面板。

Mellanox Connect-IB Card

选择 Connect-IB 卡还有其他原因。它是 Mellanox 的第四代 IB 卡。此外,它也非常节能。实际上,带有 Connect-IB 卡的网络可以轻松扩展到数万个节点。可扩展性是现代 HPC 系统的另一个重要特性。

机架构建

在决定单个节点的尺寸之前,我们应该确定我们想要的机架尺寸或我们的限制。在我们的案例中,我们很早就决定使用标准的 42U 机架。这是当前数据中心中最常见的机架尺寸。EIA(电子行业联盟)标准服务器机架(1U)是 19 英寸宽的机架外壳,机架安装导轨之间的距离为 17 3/4 英寸(450.85 毫米),其高度以 1.75 英寸(44.45 毫米)的增量测量。因此,我们的机架高度约为 2 米。

机架设计除了标准的机架外,还引入了一套管道和导电导轨。每个节点的高度测量为 3U。每层我们可以放置 8 个这样的节点。此外,我们需要一些空间来分配线缆以满足网络和电源需求。还需要额外的空间用于一些管理电子设备。单个机架最多可以容纳 64 个节点。

下图显示了机架前面底部一层的 CAD 渲染图。我们只看到一个节点正在安装。安装导轨以粉红色显示。电源导轨以深灰色和红色绘制。每个节点的进水和出水管位于绿色电源旁边。

Rack Rendering QPACE2

节点通过杠杆插入和取出。最终,节点被拉出以断开快速接头连接。快速接头稍后将进行解释。插入节点是通过将其推入快速接头完成的。

整个电源分配和电源系统必须经过广泛的测试。我们知道最多可能使用 75 kW 的电力,因为我们预计每个节点最多使用 1.2 kW(64 个节点)。这对这样的系统来说负荷相当大。高密度也带来了非常高的每机架功耗要求。

与导电导轨的连接非常重要。我们使用大量的铜来无问题地承载电流。电源单元也通过铜连接到导轨。下图显示了第一次测试之前的连接。

Test Setup PSU

模拟适当的负载非常困难。如何产生 75 kW?尽管如此,我们找到了一种方法进行高达几千瓦的测试。该设置足以对 PSU 进行单元测试,然后可以轻松扩展。

我们的测试设置非常壮观。我们使用了从电水壶借来的浸入式加热器。我们将它们汇集起来以提供最大功率。关键问题是连接的 PSU 是否可以分摊负载。单个 PSU 的功率可能高达 2 kW。它们加起来应该远超 2 kW。总共我们可以达到 96 kW。我们使用 6 个 PSU(最多 12 kW)为 8 个节点(最多需要 9.6 kW)供电。因此,我们有一个 5+1 系统,即 5 个 PSU 需要在极端条件下工作,还有一个 PSU 的冗余。

PSU 到节点的组合构成了一个电源域。总共有 8 个这样的电源域。电源域与输入电流的相位有关。与电源域无关的是电源管理。在雷根斯堡设计的 PSU 控制板通过 PMBus 监控和控制 PSU。我们使用一个 BeagleBone Black 单板计算机,它插入主控制板,我们称之为 Heinzelmann。一个 PSU 控制板服务于 16 个 PSU。因此,整个机架需要 3 个控制板。

当然,还有其他问题,这些问题已经过本次或类似测试的主题。最终,我们得出结论,提供的规格并不完全准确,但我们可以解决观察到的问题。

Test Setup Power

机架顶部预留给 PSU 设备。机架两侧各有 24 个 PSU。在节点(底部)和 PSU(顶部)之间,我们还有额外的空间用于辅助设备,例如以太网交换机或 Heinzelmann 组件。与节点不同,所有这些组件都不是水冷。大部分使用主动空气冷却,有些则满足于被动冷却。

PSU 组件还需要 PDU 设备。它们是 1U 大小,以非托管配置提供。我们选择拥有 12 个符合 IEC 60320 C13 标准的插座。这是一个极化的三极插头。我们的 PDU 在 3 相中为每个插座分配 10A 电流。

水路安装的一个著名原理是 Tichelmann 原理。它规定必须以这样的方式选择路径,使得每个交互点的水压相等。在我们的案例中,交互点是与节点的耦合。由于路径不等长,因此未选择 Tichelmann 原理。

一种可能的解决方法是为距离原点较长的交互点设计不同的管道。我们也可以人为地延长每个节点耦合的路径,使其尽可能长。这听起来都很难设计、控制和建造。而且相当昂贵。

由于管道相当大,我们估计水流阻力的影响太小,不会在实际中产生负面影响。我们预计最长路径和最短路径上的流量几乎相同。节点内的阻力远大于穿越更长路径所增加的阻力。

下图显示了 QPACE 2 系统的空机架。管道系统已经安装好。

QPACE Empty Rack

上一张图包含导电导轨、大部分电源连接器和安装导轨。辅助设备,例如管理组件、InfiniBand 和以太网交换机,以及线缆和其他电线此时尚未组装。

组装机架实际上是分阶段进行的。我们从内部开始。首先,需要调整和准备所有可能的位置。然后需要安装 InfiniBand 交换机。需要安装电源单元。需要插入托盘。现在布线。应该正确标记。最后一步是插入节点。

最后,我们拥有组装好的、也非常密集的机架。下图显示了 QPACE 2 机架的前面。此时所有节点都可用。布线和管理已完全激活。底部的 LED 显示了机架中每分钟的水流量(升)。

QPACE2 Full Rack

总的来说,QPACE 2 的机架设计不像整个机器那样具有创新性,但它是一个可靠的结构,实现了其承诺。忽略 Tichelmann 原理的原因已经得到了证实。插入和移除节点的杠杆按预期工作。

监控与维护

HPC 系统开发中另一个有趣的部分是其监控系统。幸运的是,我们已经有一个可扩展的解决方案,可以对其进行修改以包含 QPACE 2 系统。

一个真正优秀的监控大型计算机系统中心架构围绕着一个可扩展的、分布式的数据库系统。我们选择 Cassandra。Cassandra 使得高频写入操作(许多小型日志)和出色的读取性能成为可能。缺点是我们对修改有限(反正也不需要),并且我们需要智能分区。

本文将不讨论显式日志记录和数据库基础设施的详细信息。相反,我想带大家浏览一个 Web 应用程序,该应用程序允许系统的任何用户获取有关其状态的信息。该 Web 应用程序的数据源是 Cassandra 数据库。补充的其他数据点,例如当前的 ping 信息也被使用。总而言之,该 Web 应用程序也是可扩展的。

例如,下图显示了一个 Kiviat 图,用于观察机架内所有节点当前的(峰值)温度。

Monitoring Kiviat Temperature Rack

所有温度传感器都在机器 JSON 文件中指定。该文件具有与以下代码片段类似的结构。我们指定有关系统的基本信息,例如名称、年份和节点数。此外,还定义了特殊的查询等(此处未显示)。最后,提供了一个包含温度传感器的数组。

每个传感器的 `id` 映射到 Cassandra 数据库系统中的列。名称代表显示在网页上的传感器描述。

{
  "qpace2": {
    "name": "QPACE 2",
    "year": 2015,
    "nodes": 64,
    "temperatures": [
      { "id": "cpinlet", "name": "Water inlet" },
      { "id": "cpoutlet", "name": "Water outlet" },
      { "id": "core_0", "name": "Intel E3 CPU Core 1" },
      { "id": "core_1", "name": "Intel E3 CPU Core 2" },
      { "id": "core_2", "name": "Intel E3 CPU Core 3" },
      { "id": "core_3", "name": "Intel E3 CPU Core 4" },
      { "id": "mic0_temp", "name": "Intel Xeon Phi 1" },
      { "id": "mic1_temp", "name": "Intel Xeon Phi 2" },
      { "id": "mic2_temp", "name": "Intel Xeon Phi 3" },
      { "id": "mic3_temp", "name": "Intel Xeon Phi 4" },
      { "id": "pex_temp", "name": "PLX PCIe Chip" },
      { "id": "ib_temp", "name": "Mellanox ConnectIB" }
    ]
  },
}

读取每个节点的峰值温度是通过取所有当前传感器读数的最大值来实现的。但是获得的视图仅适用于快速获得良好概览。从长远来看,我们需要为每个节点提供更详细的图表。

在这里,我们使用经典的散点图。我们将点连接起来以指示一些趋势。下图显示了一个节点的演示图。涵盖的时间范围是 last day。我们看到不同组件的不同温度水平。四个协处理器的温度测量值大致相同。

CPU 核心以及水的进出口温度较低。PLX 芯片和 Mellanox Connect-IB 卡在空闲进程中的温度稍高。然而,它们不会像 Xeon Phi 协处理器那样扩展。因此,根据观察到的情况,不会出现潜在问题。

Monitoring Scatter Temperature Node

Web 前端究竟是如何构建的?毕竟,这只是一个简单的 Node.js 应用程序。主入口点如下所示。最重要的是,它获取一些控制器并将它们连接到某些 URL。配置带来了一些其他有用的设置,例如提供静态文件或使用的协议(http 或 https)。

var express = require('express');
var readline = require('readline');
var settings = require('./settings');
var site = require('./site');
var server = require('./server');

var homeController = require('./controllers/home');
var machineController = require('./controllers/machine');
// ... others

var app = express();

settings.directories.assets.forEach(function (directory) {
	app.use(express.static(directory));
});

app.set('views', settings.directories.views);
app.set('view engine', settings.engine);

app.use('/', homeController(site));
app.use('/machine', machineController(site));
// ... others

app.use(function(req, res, next) {
	res.status(404).send(settings.messages.notfound);
});

var instance = server.create(settings, app, function () {
	var address = server.address(instance)
	console.log(settings.messages.start, address.full);
});

if (process.platform === 'win32') {
	readline.createInterface({
		input: process.stdin,
		output: process.stdout
	}).on(settings.cancel, function () {
		process.emit(settings.cancel);
	});
}

process.on(settings.cancel, function () {
	console.log(settings.messages.exit)
	process.exit();
});

我们对连接使用 https。该页面不包含任何敏感数据,我们也没有签名证书。那么目的是什么?嗯,https 没有坏处,只是未来的趋势。我们都应该到处使用 https。服务器负载并没有真正受到影响,客户端反正也能处理。

在上面的代码中包含的 `server.js` 文件中,提供了从 http 切换到 https 或反之亦然的敏捷性。在这里,我们再次考虑一些选项。设置被传递给导出的 `create` 函数,该函数设置并启动服务器,在适当的端口上监听并使用选定的协议。

var fs = require('fs');

var scheme = 'http';
var secure = false;
var options = { };

function setup (ssl) {
	secure = ssl && ssl.active;
	scheme = secure ? 'https' : 'http';

	if (secure) {
		options.key = fs.readFileSync(ssl.key);
		options.cert = fs.readFileSync(ssl.certificate);
	}
}

function start (app) {
	if (secure) {
		return require(scheme).createServer(options, app);
	} else {
		return require(scheme).createServer(app);
	}
}

module.exports = {
	create: function (settings, app, cb) {
		setup(settings.ssl);
		return start(app).listen(settings.port, cb);
	},
	address: function (instance) {
		var host = instance.address().address;
		var port = instance.address().port;
		return {
			host: host,
			port: port,
			scheme: scheme,
			full: [scheme, '://', host, ':', port].join('')
		};
	}
};

对系统标准用户最重要的数量是可用性。用户必须能够看到机器在线的比例以及是否有可分配的资源。可用性对于想要运行大型作业的用户尤其重要。这些用户特别关注机器的正常运行时间。

有许多图表可以说明可用性。最直接的是一个简单的甜甜圈图,显示在线节点与离线节点的比例。图表是通过使用 `Chart.js` 库和一些自定义增强功能以及进一步定制来实现的。没有 `Chart.Scatter.js` 扩展,大多数图表不会如此好/有用/快速。一个好的散点图仍然是最自然的显示方式。

同样,我们也为可用性提供了一个散点图。散点图仅显示了可用性和随时间的使用情况。有许多不同的时间选项。其中大多数与在 Cassandra 数据库系统中设置的某些聚合选项有关。

Monitoring Availability

由于我们的前端 Web 应用程序自然遵循 MVC 模式,因此我们需要一个适当的设计来集成控制器。我们选择导出一个构造函数,它将操作一个 `site` 对象。`site` 包含有用的信息,例如设置或函数。例如,`site` 包含一个特殊的 `render` 函数,用于渲染视图。视图通过其 sitename 指定。sitename 在内部映射到视图的名称。因此,我们可以随意更改文件名——只需要一个更改。

内部,站点地图用于各种目的。如前所述,视图是通过站点地图的 ID 选择的。链接也使用站点地图一致地生成。此实现的详细信息仍被披露,但应指出的是,我们还可以使用站点地图生成面包屑导航或网站的任何其他分层视图。

闲话少说,这是 `HomeController` 的代码。它已被剥离,只显示两个页面。一个是登陆页面,它获取一些数据来填补空白,然后将模型和数据传输到视图。第二个是根据德国法律要求的版面说明页面。在这里,维护者列表从 `site` 对象中读取。然后通过模型传输这些部分。

var express = require('express');
var router = express.Router();

module.exports = function (site) {
	router.get('/', function (req, res) {
		// Get data for default route ...

		site.render(res, 'index', { 
			title: 'Overview',
			machines: machines,
			powerStations: powerStations,
			frontends: frontends,
		});
	});

	router.get('/imprint', function (req, res) {
		var sections = Object.keys(site.maintainers).map(function (id) {
			var maintainers = site.maintainers[id];
			return {
				id: id,
				persons: maintainers,
			};
		});

		site.render(res, 'imprint', {
			title: 'Imprint',
			sections: sections
		});
	});

	return router;
};

图表的数据在渲染时从不聚合。相反,传输占位符。所有图表将通过进一步的 AJAX 请求并行加载。有专门的 API 函数将返回 JSON 格式的所需图表数据。

利用率显示已分配节点的数量。分配由作业提交排队系统管理。正如我们稍后将看到的,我们的选择是 SLURM。用户应该了解系统的当前(和/或过去)利用率。如果提交了大型作业,我们需要知道作业初始化的平均时间。网页上显示的图表为用户提供了提示,帮助他们选择合适的作业大小或估算开始时间。

再次,我们使用甜甜圈图进行快速查看。

Monitoring Utilization

该站点使用查询生成器构建必要的 Cassandra 数据库查询。这是一个非常简单的对象,它允许我们将原始文本 CQL 替换为对象和含义。而不是可能出现查询失败(并返回无)的问题,我们可能会在代码中出现错误,从而导致应用程序崩溃。最大的区别在于后者可以更容易地检测到,甚至可以自动检测到,并且我们可以确信传输的查询的完整性。如果做得对,就不存在 CQL 注入的可能性。

在我们的案例中,我们根本不必担心 CQL 注入。用户无法指定用于查询的参数。此外,数据库仅被读取——Web 应用程序不提供任何插入或修改 Cassandra 中数据的可能性。

以下代码显示了 `SelectBuilder` 的构造。它是唯一导出的 `builder` 类型。为了简洁起见,未显示 CQL 字段和值的转义。

var SelectBuilder = function (fields) {
	this.conditions = [];
	this.tables = [];
	this.fields = fields;
	this.filtering = false;
};

function conditionOperator (operator, condition) {
	if (this.fields.indexOf(condition.field) === -1)
		this.fields.push(condition.field);

	return [
		condition.field,
		condition.value
	].join(operator);
}

var conditionCreators = {
	delta: function (condition) {
		if (this.fields.indexOf(condition.field) === -1)
			this.fields.push(condition.field);

		return [
			'token(',
			condition.field,
			') > token(',
			Date.now().valueOf() - condition.value * 1000,
			')'
		].join('');
	},
	eq: function (condition) {
		return conditionOperator.apply(this, ['=', condition]);
	},
	gt: function (condition) {
		return conditionOperator.apply(this, ['>', condition]);
	},
	lt: function (condition) {
		return conditionOperator.apply(this, ['<', condition]);
	},
	standard: function (condition) {
		return condition.toString();
	}
};

SelectBuilder.prototype.from = function () {
	for (var i = 0; i < arguments.length; i++) {
		var table;

		if (typeof(arguments[i]) === 'string') {
			table = arguments[i];
		} else if (typeof(arguments[i]) === 'object') {
			table = [arguments[i].keyspace, arguments[i].name].join('.');
		} else {
			continue;
		}

		this.tables.push(table);
	}

	return this;
};

SelectBuilder.prototype.where = function () {
	for (var i = 0; i < arguments.length; i++) {
		var condition;

		if (typeof(arguments[i]) === 'string') {
			condition = arguments[i];
		} else if (typeof(arguments[i]) === 'object') {
			var creator = conditionCreators[arguments[i].type] || conditionCreators.standard;
			condition = creator.call(this, arguments[i]);
		} else {
			continue;
		}

		this.conditions.push(condition);
	}

	return this;
};

SelectBuilder.prototype.filter = function () {
	this.filtering = true;
	return this;
};

SelectBuilder.prototype.toString = function() {
	return [
		'SELECT',
			this.fields.length > 0 ? this.fields.join(', ') : '*',
		'FROM',
			this.tables.join(', '),
		'WHERE',
			this.conditions.join(' AND '),
			this.filtering ? 'ALLOW FILTERING' : '',
	].join(' ');
};

var builder = {
	select: function (fields) {
		fields = fields || '*';
		return new SelectBuilder(Array.isArray(fields) ? fields : [fields]);
	},
};

module.exports = builder;

当然,这样的 `SelectBuilder` 可以复杂得多。这里显示的只是一个非常轻量级的版本,无需太多麻烦即可使用。它提供了我们期望从用于表达 CQL 查询的 DSL 中获得的大部分好处,而无需使用纯文本或直接字符串操作。

监控功耗也可能很有趣。这也是衡量机器状态的好指标。它是否在运行?现在负载有多大?监控功耗对于效率也很重要。空闲时,我们希望消耗最少的能量。在高负载下,我们希望尽可能高效。每瓦特计算量最大化是关键。

我们有几个散点图来显示功耗随时间的变化。下面显示了特定电力线的可能变体。

Monitoring Power Consumption

这些图表是如何生成的?如前所述,客户端仅使用 `Chart.js` 库。在服务器端,我们与 API 通信,该 API 最终调用 `charts` 模块中的方法。该模块带有每个支持的图表类型的函数。例如,`scatter` 函数生成 JSON 输出,以便在客户端生成 JSON 图表。因此,视图与图表的具体类型无关。它将根据数据选择正确的图表类型。

示例代码执行两项操作。它迭代呈现的数据并从中提取系列信息。最后,它创建一个包含客户端可能需要或相关的所有信息的对象。

// ...

function withAlpha (color, alpha) {
	var r = parseInt(color.substr(1, 2), 16);
	var g = parseInt(color.substr(3, 2), 16);
	var b = parseInt(color.substr(5, 2), 16);
	return [
		'rgba(',
		[r, g, b, alpha].join(', '),
		')'
	].join('');
}

var charts = {
	// ...
	scatter: function (data) {
		for (var i = data.length - 1; i >= 0; i--) {
			var series = data[i];
			series.strokeColor = withAlpha(series.pointColor, 0.2);
		}

		return {
			data: data,
			containsData: data.length > 0,
			type: 'Scatter',
			options: {
				scaleType: 'date',
				datasetStroke: true,
			}
		};
	},
	// ...
};

module.exports = charts;

`withAlpha` 函数是一个辅助函数,用于将十六进制表示中的标准颜色更改为 RGBA 颜色函数字符串。例如,使用比填充颜色自动定义的更亮的描边颜色非常有用。

总而言之,监控系统拥有成熟的后端和有用的统计数据收集。它自主地执行一些重要任务,并在出现警告时发送电子邮件。在紧急情况下,它可能会启动关机序列。Web 界面使用户和管理员能够快速了解最重要的数据点。Web 应用程序易于维护和扩展。它已被设计成适用于桌面和智能手机的尺寸。

热水冷却

水冷是大多数 HPC 系统的实际标准。有理由使用水而不是空气。水的比热容是空气的比热容的许多倍。更重要的是,水的密度是空气的三个数量级。因此,我们具有更高的效率。运行大型风扇仅仅是为了放大一些气流,这可能是效率最低的过程之一。

为什么热水冷却比标准水冷更有效?嗯,标准水冷需要冷水。冷却水是一个非常耗能的过程。如果我们能节省这些能源,就已经有所收获了。是的,热水冷却模仿了血液在我们体内的流动方式。该过程不需要任何冷却,但仍然能够冷却/保持一定温度。当我们在小的 `ΔT`(水温与组件温度之间的差值)下运行时,热水冷却效率最高。

热水冷却不需要任何特殊的冷却设备。不需要冷水机组。我们只需要一个泵来驱动水路中的流动。有一些要求,因为热水冷却依赖于湍流。湍流是随机且无组织的。它会自相互作用,为混合和导热提供良好的基础。相反,层流会趋于分离并沿着边界层平滑流动。因此,热传递不会太大,即使有,也只会采取某些路径。混合特性不明显。

我们的热水冷却基础设施的设计必须分成几个部分。我们必须

  • 建立一个合适的冷却回路
  • 选择合适的泵(多少水?所需流量?)
  • 选择合适的管道
  • 为组件设计冷却包
  • 设计机架
  • 决定在机架冷却回路、节点-机架和节点-组件之间使用何种类型的连接

关于机架设计的讨论已经进行。在所有事情都决定之后,我们需要进行一些测试。我们使用了一个简单的桌式水冷器,以查看协处理器冷却包是否正常工作。

Table Cooler Test

便携式桌式水冷器为我们提供了一个功能齐全的水冷回路。我们有一个泵,其流量为每分钟 6.8 升。该桌式水冷器使用标准电源插座的电流运行。最多可容纳 2.5 升水。总的来说,桌式水冷器可处理 2700 瓦的冷却能力。

在我们的设置中,我们通过一些透明管道将冷却包(也称为冷板)连接到桌式水冷器。本次测试使用的管道并非我们之后想要使用的管道。此外,管道已直接连接到桌式水冷器。在此过程中,我们仍然需要决定一些特殊的分配/汇集单元。

下图显示了协处理器冷板的测试。我们使用了一个标准的 Intel 服务器主板 (S1200V3RP)。这足以测试单个 KNC,而不会遇到不兼容性,例如与主机 CPU 或芯片组不兼容。在此测试中,我们关心 `ΔT`。它通过桌式水冷器和协处理器的峰值温度进行测量。后者可以使用 Intel 的 MPSS 软件堆栈进行读出。

Test Setup Cooling

真正的装置当然比单个桌式水冷器大得多。我们使用了一个大型泵,并结合了一个热交换器和一个复杂的过滤系统。水冷的主要问题之一是细菌和泄漏的潜在威胁。虽然泄漏对组件和基础设施都具有破坏性,但细菌的生长会降低冷却效率并堵塞我们冷板中的通道。

因此,一个好的过滤器是必要的,但不能保证防止细菌生长。此外,我们所有的管道都完全不透明。我们不希望通过外部能量鼓励繁殖。但对抗细菌最重要的措施是使用冷却水中的特殊杀菌剂。

下图显示了计算中心下方的地板布线安装情况。

QPACE2 Cooling Backend

如前所述,冷却回路只是开始。更关键的是冷板和连接器的正确设计选择。我们需要非常小心可能的泄漏。整个系统应该尽可能坚固、高效且易于维护。此外,我们还需要一定的灵活性,并且预算有限。我们能做什么?

显然,我们不能接受固定管道。我们需要节点内部的一些管道。否则,我们就没有内部组件的容差。固定管道需要一个非常固定的底盘。我们的底盘在模块化和可维护性方面进行了构建。可能存在几毫米的偏差,不在规范范围内。

让我们从介绍正确的连接器开始讨论。

快速接头与集管

节点与机架的连接通过快速接头完成。快速接头提供了一种高质量的机制,用于完美可控地传输水流。如果不连接,快速接头会完美密封。没有泄漏。如果连接,调校良好的快速接头连接工作是二元的。要么连接正常,我们观察到最大流量传输,要么我们根本看不到任何传输(障碍物仍然密封)。

下图显示了一个可能的快速接头。我们选择了不同的型号,但主要原理和设计特征保持不变。

Quick Coupling

必须向后拉动快速接头才能释放已安装的连接器。这意味着在我们的案例中我们需要另一个机制。最简单的解决方案是修改快速接头头,使其在施加足够力的情况下始终释放已安装的连接器。此方法的缺点是现在可能发生部分安装。部分安装意味着只有一部分通量流经连接的连接器。我们实际上打破了二元行为。

连接到快速接头的两个连接器分别是机架和节点。节点上的连接器充当水流向分配单元(称为集管)的桥梁。集管也可以用作汇集单元,这是其他连接器(出水)的情况。进水集管的工作是将水从一根管道分配到六根管道。

这六根管道最终连接到六个冷板。在这里,我们有

  • 四个 Intel Xeon Phi 冷板
  • 一个用于冷却 CPU 板的冷板
  • 一个用于冷却 PLX 芯片和 InfiniBand 卡的冷板

选择用于将管道连接到集管(和冷板)的卡箍尤其有趣。事实证明,实际上有一个最佳选择。所有其他选择可能立即有问题,或者具有可能随时间(或在某些情况下)导致泄漏的特性。

下图显示了一个带有透明管道的集管连接到节点。管道和卡箍仅用于测试目的。它们未在生产中使用。

Manifold QPACE2

选择合适的管道和卡箍可能是防止泄漏方面最重要的决定之一。如果我们选择错误的管道,我们可能会加剧细菌生长,在安装过程中遇到问题,或者仅仅是流量不佳。卡箍也可能令人头痛。在这里做出错误的决定会给我们留下一个脆弱的解决方案,无法增强我们的信心。最佳选择是使用适合管道直径的卡箍。唯一符合此标准的是带有特殊触发器(需要特殊工具)的卡箍。在我们的案例中,卡箍来自一家名为 Oetiker 的公司。

这些耳式卡箍(PG 167 系列)也用于其他超级计算机,例如 SuperMUC。在我们的安装过程中,我们在管道上添加了一个额外的接头。接头在 800°C 的温度下加工。然后将接头放在管道上,并用热风枪(100°C)加热。结果,管道实际上变得更厚了。它们的壁厚外强度也得到了提高。因此,卡箍的贴合度比没有接头时更好。

最后,我们还必须讨论冷板。Intel Xeon Phi 的冷板是一个很好的代表。不仅冷板必须显示最佳的热性能,而且它是产量最大的冷板。

滚压成型板和衬垫

快速接头和集管仅提供连接和分配单元。现在的关键问题是:组件是如何精确冷却的?如前所述,我们使用特殊的冷板将热量从设备传输到流动的水中。冷板由三部分组成。一个背面(底盘)、一个连接器(衬垫)和一个通道(滚压成型板)。背面不太有趣。它可能会将一些热量传递到前面,但其主要目的是固定前面,使其处于正确的位置。

衬垫是中间部分。它位于滚压成型板和设备之间。衬垫的要求之一是它足够灵活,可以适应设备上的可能公差,并且足够坚固,能够良好接触以实现最大导热性。衬垫具有一些巧妙的特征,例如位于芯片上的腔。然后用大块铜填充间隙。这里的想法是拥有比铝具有更高导热性的材料。主要原因是放大关键区域的热传递。铜块必须比可用空间稍小。这样,我们就为不同的热膨胀做好了准备。

最后,我们有滚压成型板。它通过一些胶水连接到衬垫,胶水在下一节中讨论。滚压成型板已进行了修改,以便在板内提供一种管道。该管道沿着特定的路径,该路径已选择为最大化从衬垫到水的可能热传递。

下图展示了上述组件的概述。

QPACE2 Interposer Rollbond Cooling

图显示了底盘(顶部)、滚压成型板(右侧)、插入的铜块(左下方)和衬垫(底部)。所有冷却组件都围绕着 Intel Xeon Phi 协处理器板。

图中的黄色条带是热界面材料(TIM)。TIM 是先进高密度电子封装的关键组件,对于散热至关重要,以防止电子元件因过热而发生故障。我们使用的传统 TIM 是通过将高导热填料(如金属或金属氧化物微粒)引入聚合物基体来制造的。我们需要它们来确保良好的热传递,同时提供足够的绝缘。

滚压成型板的设计旨在确保在我们的流量下已经出现湍流。此外,必须最大化传热面积而不降低有效水流量。最后,冷板必须可靠。任何泄漏都将是灾难。

管道、胶水和导热膏

最初选择合适的管道似乎是一个微不足道的问题。水冷可能出现的问题之一是由于管道的长期侵蚀效应而导致的泄漏。其他问题包括维护成本增加以及前面提到的细菌威胁。使用合适的管道可以缓解其中许多问题。我们对管道有几项要求。它们的直径应约为 10.5 毫米。它们必须完全不透明。最后,它们应该尽可能柔软。僵硬的管道使维护更加困难——字面意义上。

我们选择了三元乙丙橡胶(EPDM)管道。这些管道相当柔软,并且可以在很宽的温度范围内运行,从 -50°C 开始到 150°C。25 MPa 的高抗拉强度使其也成为我们目的的良好选择。此外,管道足够承受我们 10 bar 的压力要求。

下图显示了一个典型的 EPDM 管道。

EPDM Tube

对于导热膏,我们要求最高的导热性,同时不导电。在实践中,这很难实现。电子迁移是导体的原因,也是热传输的好机制。然而,在晶格振动中可以找到另一种机制。这里声子是载体。

我们找到了几种满足我们标准的导热膏。为了找出在所示热性能方面最佳的选择,我们准备了一些样品。然后使用 Burn-MIC 运行来对每个样品进行基准测试,Burn-MIC 是一种几乎将 Xeon Phi 推向其最高温度的自定义应用程序。然后使用最高温度创建以下分布。

Thermal Pastes Comparison

我们看到 Prolimatech 的 PK1 绝对是最佳选择。它不是最贵的,但肯定也不便宜。30 克需要支付 30 欧元。其他一些选择也不错。最便宜的 Keratherm 的 KP98 仍然是一个足够好的选择。我们对最贵的 Fischer 的 WLPK 感到失望。然而,即使 WLPK 在这里没有表现出出色的性能,这可能是由于与其他相比,它的形态更像液体。在我们的设置中,我们因此得到了一个不理想的接触面积。

现在我们的系统已经冷却并且设计完成,我们需要处理软件方面的事情。HPC 不需要庞大的软件堆栈,只需要合适的软件。我们希望尽可能接近硬件,所以任何开销通常都是不受欢迎的。尽管如此,我们还是需要一定的兼容性,因此我们将看到 QPACE 2 系统中使用了许多标准工具。

软件堆栈

选择正确的软件堆栈很重要。我想不用说。需要评估的是系统用户期望什么样的标准软件。我们在科学领域有应用程序,特别是在 Lattice QCD 领域进行粒子物理模拟。因此,提供大多数应用程序使用的大部分基本库至关重要。还必须提供一些标准软件。更重要的是,它必须针对我们的系统进行了优化。最后,我们还必须提供对系统进行工作很重要的一些工具和软件包。

与大多数Top 500系统一样,我们使用Linux作为我们的操作系统。这一选择有很多原因。但无论我们对系统本身有什么理由,从我们系统用户的角度来看,这也是有道理的。Linux是大多数物理学家的标准操作系统,并支持命令行工具,这对HPC应用非常有用。此外,作业提交系统和评估工具最好与基于Linux的操作系统结合使用。

以下各小节讨论了我们的操作系统及其发行版、我们选择的编译器以及专用固件和通信库等主题。我们将简要讨论一些最佳实践。让我们从QPACE 2操作系统开始。

操作系统和配置

每个节点没有一个单一的操作系统。相反,每个节点运行多个操作系统。一种是运行在CPU板处理器上的操作系统。这是主操作系统,尽管它不是第一个启动的。第一个是U-Boot中嵌入的操作系统。U-Boot在BMC上运行,在BMC的实际操作系统启动之前。可以说,它是一个操作系统引导程序。最后,每个协处理器也有自己的操作系统。

CPU卡上的BMC运行嵌入式Linux版本,并在接通电源后立即从闪存启动。它支持主板管理控制器的一般功能,例如,它可以使节点中的其他设备保持复位或释放它们。此外,它还可以监控电压、电流和温度传感器并采取相应措施。例如,在严重的情况下可以启动紧急关机。它还可以通过I2C总线访问PCIe交换机中的寄存器。

我们的节点是无盘的。一旦CPU从复位中释放,它就会通过以太网网络PXE引导一个最小的Linux镜像。完整的Linux操作系统(目前是CentOS 7.0)使用NFS挂载的根文件系统。KNC通过Intel的KNC软件栈MPSS由CPU引导和控制。KNC支持我们主存储系统的Lustre文件系统,该系统通过InfiniBand访问。此外,为了我们的用例,HDF5文件系统也必须得到支持。

各种系统监控工具运行在BMC或CPU上,它们会定期检查所有主要设备(KNC、CPU、IB HCA、PCIe交换机)的温度以及各种错误计数器(ECC、PCIe、InfiniBand)。一个前端服务器用于NFS导出操作系统。前端服务器也用于与节点通信并监控它们。此外,系统还可以登录到机器,并控制批处理队列。

编译器和工具

在HPC中,选择正确的编译器非常重要。有时几个月的优化将毫无价值,如果我们不花几天时间评估可用的编译器及其编译标志。最佳选择可以产生巨大的差异。理想情况下,我们无需任何代码调整就能受益。尽管最佳编译器通常与可用硬件相关,但也可能存在例外。

在我们的例子中,我们实际上没有太多选择。能够为KNC编译的编译器并不多。尽管协处理器据说与x86兼容,但它并非在二进制级别上兼容。第一个后果是我们需要为Intel Xeon Phi重新编译我们的应用程序。这种奇怪的不兼容性的第二个结果是需要一个特殊的编译器。有一个GCC编译器版本能够为Xeon Phi生成二进制文件。这个版本用于为KNC操作系统生成内核模块。然而,这个版本不了解任何优化,特别是SIMD相关的优化,因此对于HPC来说是一个非常糟糕的选择。

显而易见的解决方案是使用Intel编译器。在某种程度上,这使得Intel Xeon Phi变得更糟。虽然整个CUDA堆栈可以免费获得,但Intel编译器的许可却相当昂贵。考虑到可用的KNC产品都非常昂贵,仍然没有合适的软件来编写应用程序,这真是令人遗憾。除了这种非常令人讨厌的模型,任何人都不应该支持它之外,我们可以肯定地说,Intel编译器提供了出色的性能。

除了Intel编译器,我们还从Intel那里获得了一些相当有用的工具,其中大多数工具来自Intel的Parallel Studio,这是Intel的IDE。在这里,我们还得到了臭名昭著的VTune。此外,我们还获得了一些性能计数器、调试器、大量的分析器、Intel MPI(某些版本,例如5.0.3)用于分布式计算,整个MPSS软件栈(包括硬件分析器、传感器应用程序等)以及更多好东西。对我们来说,命令行工具仍然是做事的方式。因此,一项关键的(且非常基础的)任务是找出这些工具中某些工具的最佳参数。如前所述,需要确定最佳编译器标志。Intel MPI运行时也需要仔细检查。我们想要最好的配置。

Intel VTune Amplifier

Intel编译器不仅使我们能够生成与KNC兼容的代码,还可以利用三种不同的编程模式

  • 直接(在加速器上执行加载和执行)
  • 卸载(将数据从主机加载,在KNC上执行)
  • 本机(从主机加载应用程序,其余在协处理器上运行)

虽然第一种和第三种模式在编译方面相似,但第二种模式则相当不同。在这里,我们生成一个必须从主机运行的二进制文件,其中包含通过在协处理器上启动进程来执行的卸载部分。协处理器上的进程由原始二进制文件的一个子集提供,该子集是使用不同的汇编器生成的。因此,我们的原始二进制文件实际上是主机和MIC兼容代码的混合体。此外,这个二进制文件还包含与协处理器通信的指令。

本机执行需要一个名为micnativeloadex的工具,该工具也包含在MPSS软件栈中。

那么我们应该使用什么编译标志呢?事实证明有很多,而且为了让事情更复杂——它们也取决于我们的应用程序。尽管-O3是最高的优化级别,但我们有时可能会遇到奇怪的结果。因此,它被认为不可靠。在大多数情况下,-O2已经足够了。尽管如此,在选择其中一个之前,我们应该始终关注性能和可靠性。为了直接针对MIC架构,我们需要-mmic机器说明符。

还有其他有趣的标志。在此简要列出

  • -no-prec-div除法优化,但精度会降低。
  • -ansi-alias如果程序遵循ISO C标准别名规则,则可以带来巨大的性能提升。
  • -ipo过程间优化在文件之间执行优化。这肯定会增加所需的编译时间。

前面没有列出的另一种可能性是渐进式优化(PGO)的能力。PGO通过减少分支预测、缩小代码大小从而消除大多数指令缓存问题来提高性能。为了有效使用,我们需要提前进行一些采样。我们首先使用-prof-gen-prof-dir=p标志编译我们的程序,其中p是生成的分析器的路径。运行程序后,我们将在之前指定的路径中找到采样结果。最后,我们可以再次编译我们的应用程序,这次使用-prof-use而不是-prof-gen标志。

编译器并非一切。我们还需要合适的框架。否则,我们就必须自己编写它们,这可能会很繁琐,并导致解决方案不够通用、不够可移植、维护性较差。以下库或框架对我们来说很有趣。

HPC Frameworks Threading Vectorization SIMD Distribution

其中一些框架至少部分地排斥了彼此。例如,我们不能将Cilk Plus的线程功能与OpenMP一起使用。原因是它们都带有一个运行时来管理线程池,该线程池(默认情况下)包含尽可能多的SMT线程。对于我们的协处理器,我们将有244或240个(带/不带为操作系统保留的核心)。这里我们遇到了一个经典的资源限制,两个框架都在争夺可用资源。这肯定是不利的。

我们不使用OpenACC,尽管它无疑是一个编写可移植代码的有趣选项,这些代码可以在协处理器和GPU上运行。Intel编译器带有自己的专用pragma指令集,可触发卸载。此外,我们可能需要使用编译器内建函数。编译器内建函数可以使用一种准可移植的方式来实现。Vc库提供了一个示例实现。Vc为我们提供了一个通用的数据抽象,结合C++运算符重载,使得SIMD不仅可移植,而且编程效率高。

最终,我们主要剩下经典的选项。SIMD将通过使用内建函数(不可移植性较差)或Cilk Plus(可移植性稍好,对程序员非常友好)来实现。多线程将交给OpenMP。如果我们只需要卸载,我们将使用Intel编译器内建函数。我们还可能希望使用OpenMP,因为最新版本已添加了一组初始的卸载方法。我们的MPI框架也由Intel提供,尽管也应评估替代选项,例如Open MPI。

另一个有趣的软件主题是使用的固件和驱动程序堆栈。

固件和驱动程序

尽管我们的硬件堆栈几乎全部由商业上可用的(至少在HPC标准下)组件组成,但我们以非标准的方式使用它们。这些组件需要特殊的固件

  • 用作引导加载程序的复杂可编程逻辑器件(CPLD)
  • 运行BMC的微控制器
  • BIOS
  • PLX芯片
  • Intel Xeon Phi
  • Mellanox Connect-IB卡

后两者还需要一些通信驱动程序。驱动程序和固件版本通常必须匹配。此外,我们还需要连接到我们的I/O系统(Lustre)的驱动程序,以及可能从PLX芯片读取值的驱动程序。PLX芯片在检查信号质量或检测一般性错误方面非常有趣。

离开节点,我们需要驱动程序来访问连接到BeagleBone Black(BBB)的电源控制板上的连接器。其中大多数驱动程序需要连接到我们的Cassandra系统。因此,它们要么需要与某种可用的Web API通信,要么需要直接访问Cassandra。

通过I2C或GPIO与设备通信对于BMC也是至关重要的。在这里,我们需要提供自己的系统,其中包含一组辅助程序和实用程序。这些应用程序可以很简单,例如启用或禁用连接的LED,也可以很复杂,例如与热插拔控制器通信。

定制驱动程序在节点初始引导期间就已经启动。我们设置了一些位置引脚,可以通过BMC读取。当节点启动时,我们读取这些引脚并将其与全局设置进行比较。如果引脚已知,我们继续,否则,我们不会将正确的IP地址分配给给定的位置引脚和MAC地址。现在我们必须重新启动节点。

整个过程可以用一个简单的流程图来概括。

Location Pin Boot QPACE2

总的来说,驱动程序和固件软件的设计旨在实现任何可能的通信,并以最高的性能和最低的错误率进行。这也促使我们创建定制的通信库。

通信库

在HPC领域,通信非常重要。即使是最简单的程序也是分布式的。标准的框架是MPI。由于摩尔定律的经典时代已经结束,我们还需要考虑同步多线程(SMT)。这通常由OpenMP处理。对于GPU和协处理器,我们也可能需要考虑卸载。最后,我们拥有相当强大的核心,它们实现了70年代最流行的向量机的基本原理。SIMD功能也需要被利用。此时,我们有4个级别(分布式、卸载、多线程、矢量化)。这些级别对不同的节点也可能不同。异构计算正在到来。

我们需要非常关注我们节点之间的通信。通信可能通过PCIe,或者通过InfiniBand网络。也可能发生在同一协处理器上的工作线程之间。显然,区分不同的连接很重要。例如,如果两个协处理器在同一个节点中,我们应该确保它们比与其他不在同一个节点的协处理器进行更频繁的通信。

此外,我们需要非常高效地使用Connect-IB卡的双端口。因此,我们得出结论,绝对有必要提供自己的MPI包装器(例如,基于Intel MPI),它直接使用IBverbs。这一点得到了Intel的支持。在MPSS 3.2的版本说明中,有一条注释说,

mic上没有libibumad。
状态:不会修复

 

原则上,MPI实现可以考虑拓扑(例如我们使用每个节点2个端口的超交叉开关拓扑)。然而,这通常需要libibumad。由于该库不适用于KNC,我们最好提供自己的实现。

该库不仅能了解我们的拓扑,而且能以最高效率、最低开销地使用它。拥有一个真正高效的allreduce例程绝对是好的。这样的例程只有在拥有最好的拓扑信息时才可能实现。

有效的同步方法也很重要。最初,我们应该尽量避免同步。但有时没有稳健或可靠的方法来找到我们当前算法的无锁替代方案。这时,我们就需要以最低的开销进行同步。例如,在MPI调用中,我们倾向于异步发送操作和可能的同步接收。然而,根据具体情况,我们可能已经对算法进行了优化,以至于我们可以确保一个有效的应用程序而不需要任何等待或锁定操作。

在开始考虑针对特定架构进行优化或其他特殊实现优化之前,我们应该找到最佳算法。一般而言,最优算法无法被智能实现所超越。在非常特殊的情况下,使用较差算法的特定于机器的实现可能会做得更好,但其工作量和可伸缩性肯定有限。此外,如此高度特定的优化也并非非常可移植。

我们肯定希望两者兼顾——使用最佳算法,然后通过关注特定于机器的属性来榨取最后可能的优化。一个很好的例子是我们对同步屏障的实现。朴素地,我们可以只使用互斥锁的组合来实现一个完整的屏障。但通常互斥锁是一种非常慢的同步机制。屏障有多种类型。我们有一个集中式屏障,它的伸缩性是线性的。集中式屏障可能适合少数线程,如果它们都共享同一个处理单元,但对于分布在五十多个核心上的百多个线程来说,它肯定很慢。

还有两种更有效的屏障。一种是分散式屏障(有时称为蝴蝶屏障),它将线程分组,防止全双工通信。类似地,锦标赛(或树)屏障将两个线程分组,形成一个树状结构。基本思想如下图所示。我们有两个阶段,比赛和释放。在第一阶段进行比赛,每个选手(线程)必须等待对手到达才能进入下一轮。每轮比赛的“失败者”必须等待释放。获胜者稍后必须释放失败者。只有锦标赛的冠军才能将比赛阶段从比赛切换到释放。

Tournament Barrier Synchronization

作为起点,我们可以尽可能简单地实现算法。因此,没有特定于设备的优化。没有人工填充或特殊指令。我们创建一个包含屏障特定信息的结构。屏障必须携带有关每轮比赛的信息。可能的配对和即将产生的结果。整个锦标赛本质上是预先确定的。结果可以有5种不同的状态:获胜者、失败者、冠军、淘汰者和轮空。前两种状态很明显。冠军是不会晋级的获胜者,而是触发状态变更。可以看作是一个具有附加责任的获胜者。淘汰者是虚位以待的占位符。轮空也是如此:这意味着获胜者不必通知(释放)潜在的失败者,因为没有失败者。

以下代码显示了C++中的一个标准实现。Barrier类必须用参与屏障的线程数进行初始化。每个线程必须调用await方法,并提供自己的唯一标识符(范围从0N-1,其中N是线程数)。提供的版本使用一个静态数组,最多支持256个线程。动态内存管理也是可能的,但我们应该考虑对齐和填充(所有平台都特定于平台)。

废话不多说,让我们看看锦标赛屏障的样本可移植实现。

#include <cmath>

class Barrier final {
public:
	Barrier(unsigned int threads) : 
		threads(threads), 
		rounds(std::ceil(std::log(threads) / std::log(2u))) {
		for (auto thread = 0u; thread < threads; ++thread) {
			for (auto rnd = 0u; rnd <= rounds; ++rnd) {
				array[thread][rnd].previous = false;
				array[thread][rnd].flag = false;
				array[thread][rnd].role = BarrierRole::Dropout;
				array[thread][rnd].threadId = thread;
				array[thread][rnd].roundNum = rnd;
				array[thread][rnd].opponent = nullptr;
			}
		}

		for (auto thread = 0u; thread < threads; ++thread) {
			auto current = 1u;
			auto previous = 1u;

			for (auto rnd = 0u; rnd <= rounds; ++rnd) {
				const auto left = thread - previous;
				const auto right = thread + previous;

				if (rnd > 0u) {
					const auto temp = thread % current;

					if (temp == 0u && right < threads && current < threads) {
						array[thread][rnd].role = BarrierRole::Winner;
						array[thread][rnd].opponent = &array[right][rnd].flag;
					}

					if (temp == 0u && right >= threads) {
						array[thread][rnd].role = BarrierRole::Bye;
					}

					if (temp == previous) {
						array[thread][rnd].role = BarrierRole::Loser;
						array[thread][rnd].opponent = &array[left][rnd].flag;
					}

					if (thread == 0u && current >= threads) {
						array[thread][rnd].role = BarrierRole::Champion;
						array[thread][rnd].opponent = &array[right][rnd].flag;
					}
				}

				previous = current;
				current *= 2u;
			}
		}
	}

	bool status(unsigned int pid) const {
		return array[pid][0].previous;
	}

	void await(unsigned int pid) {
		if (threads > 1u) {
			auto sense = !status(pid);
			block(pid, sense);
			status(pid, sense);
		}
	}

protected:
	void status(unsigned int pid, bool value) {
		array[pid][0].previous = value;
	}

	void block(unsigned int vpid, const bool value) {
		auto rnd = 0u;

		//go sleep
		while (true) {
			if (array[vpid][rnd].role == BarrierRole::Loser) {
				*(array[vpid][rnd].opponent) = value;
				while(array[vpid][rnd].flag != value);
				break;
			}
			
			if (array[vpid][rnd].role == BarrierRole::Winner) {
				while(array[vpid][rnd].flag != value);
			}
			
			if (array[vpid][rnd].role == BarrierRole::Champion) {
				while(array[vpid][rnd].flag != value);
				*(array[vpid][rnd].opponent) = value;
				break;
			}

			if (rnd < rounds)
				rnd++;
		}

		//wake up
		while (rnd > 0u) {
			rnd--;

			if (array[vpid][rnd].role == BarrierRole::Winner)
				*(array[vpid][rnd].opponent) = value;
			
			if (array[vpid][rnd].role == BarrierRole::Dropout)
				break;
		}
	}

	enum class BarrierRole : unsigned int {
		Winner = 0u,
		Loser = 1u,
		Bye = 2u,
		Champion = 3u,
		Dropout = 4u
	};

	struct BarrierRound {
		BarrierRole    role;
		volatile bool* opponent;
		volatile bool  flag;
		int            threadId;
		int            roundNum;
		bool           previous;
	};
}

private:
	BarrierRound array[256][16];
	unsigned int threads;
	unsigned int rounds;
};

屏障实现(尤其是平台特定的一个)需要仔细基准测试。微基准测试可能导致错误的结论,并且必须非常小心地执行。尽管如此,它们对于产生有用的信息是必要的,这些信息用于决定如何在我们的代码中实现某些事情。例如,使用哪种屏障。以及管理单个协处理器上线程时应使用哪种运行时(例如OpenMP、Cilk Plus、TBB)。

屏障性能取决于线程数的良好度量可以通过提前放置一些虚拟屏障,测量每个线程的当前时间,执行屏障,然后再次测量时间来获得。最后到达屏障的线程和最后离开屏障的线程决定了屏障的开销。一个类比是与一群人一起乘坐公共汽车。这群人代表线程,乘车(或公共汽车)代表屏障。一旦小组中的每个人都上了公共汽车,我们就准备出发了。因此,公共汽车的出发时间仅由最后一个上车的人决定。类似地,一旦小组的最后一个人下车,我们就到达了目的地。我们又可以出发了。因此,最后一个离开的人给了我们释放时间。

关键基准测试

还有其他几个基准测试需要完成。我们不会详细介绍每个基准测试以及可能实现的每个性能改进。相反,我们将快速浏览一下基准测试系统。这是一个C++应用程序,它运行一个或多个小的子程序。程序可以使用任何多处理框架进行构建。目前它支持5个目标

  • 顺序执行
  • OpenMP指令
  • Cilk Plus
  • Intel Threading Building Blocks
  • PThreads / C++11特性

并非每个子程序都包含每个目标的基准测试。拥有多个目标而不是一个包含所有五个框架的程序的原因很简单:其中三个(OpenMP、Cilk Plus和TBB)都有自己的运行时。有时这些运行时会相互干扰。在这种情况下,结果可能不可靠,并且可能偏向于能够争夺线程资源的某个框架。

尽管框架是通过定义的符号在编译时选择的,但基准应用程序也带有一个运行时组件。运行时确定是必要的,以处理一些特殊的边缘情况。它已经使用C++11枚举类实现。下面的代码片段显示了枚举,它基本上是一个位标志枚举。因此,我们还定义了两个有用的函数,一个按位或运算符和一个按位与运算符。

enum class Threading : unsigned char {
	None = 1,
	OpenMP = 2,
	Tbb = 4,
	CilkPlus = 8,
	PThreads = 16,
	All = 30
};

inline Threading operator & (Threading lhs, Threading rhs) {
	using T = std::underlying_type<Threading>::type;
	return (Threading)(static_cast<T>(lhs) & static_cast<T>(rhs));
}

inline Threading operator | (Threading lhs, Threading rhs) {
	using T = std::underlying_type<Threading>::type;
	return (Threading)(static_cast<T>(lhs) | static_cast<T>(rhs));
}

基准实现还会自动执行其他一些操作。它重复测量以提高精度。它计算统计数据。它输出结果。所有这些都需要正确处理。一组脚本补充了基准应用程序。例如,有一个脚本可以运行相同的一个或多个基准测试来测试所有可能的框架。另一个脚本将分配一个作业到队列系统,然后在每个节点上为每个框架运行所需的基准测试。这样,我们就可以收集更多数据,从而获得更好的统计数据。

每个Benchmark的基类如下所示。我们只概述了头文件,因为实际实现并没有揭示特别有趣的内容。

class Benchmark {
public:
	Benchmark(const std::string& name, const std::string& desc, const Threading supports, const Config& config);
	virtual ~Benchmark();

	std::string name() const noexcept;
	std::string description() const noexcept;
	std::string output() const noexcept;
	bool is_supported() const noexcept;
	bool supports(Threading threading) const noexcept;
	unsigned int repeats() const noexcept;
	unsigned int warmups() const noexcept;
	virtual void run() const = 0;

protected:
	void warmup(std::function<void(void)> experiment) const noexcept;
	Statistic<double> repeat(std::function<double(void)> experiment) const noexcept;
	Statistic<double> warmup_and_repeat(std::function<double(void)> experiment) const noexcept;

	inline Statistic<double> measure(std::function<void(void)> experiment) const noexcept {
		warmup(experiment);

		return repeat([&](){
			const auto start = rdtsc();
			experiment();
			const auto end = rdtsc();
			return static_cast<double>(end - start);
		});
	}

	template<typename... Ts>
	inline Statistic<double> measure(const std::tuple<Ts...>& args, std::function<void(const std::tuple<Ts...>&)> experiment) const noexcept {
		warumup([&](){ experiment(args); });
		return measure([&](){ return experiment(args); });
	}

private:
	std::string _name;
	std::string _desc;
	Threading _supports;
	std::string _output;
	unsigned int _warmups;
	unsigned int _repeats;
};

如何将各种基准测试添加到应用程序中?有一个简单的工厂,它与Benchmark的概念松散耦合。基准测试通过模板方法添加,需要构造函数具有特定的签名。尽管如此,以下代码对(在头文件中未知)正确的基准容器(工厂)执行了一些魔术。

由于add()是一个模板方法,我们需要向编译器提供信息。因此,我们调用template add<T>()来确保没有编译错误。

#pragma once
#include "tests/barriers.h"
// ...

template<typename T>
static void setup_benchmarks(T& benchmarks) {
	benchmarks.template add<Barriers>();
	// ...
}

除了微基准测试,我们还非常关注温度基准测试。在这里,我们需要开发另一个应用程序来执行温度测量,并将它们与系统上的负载相关联。

总的来说,温度基准测试所需的架构如下图所示。

Distributed Benchmarks Architecture

在登录节点上,我们运行分发脚本,该脚本执行分配并最终调用运行器脚本。运行器通过ssh调用在特定节点上调用。我们将并行连接到N个节点,在每个节点上执行相同的脚本。然而,运行器脚本只运行测量应用程序,该应用程序会产生一些线程。

一个线程专门用于测量。它收集所有可能的温度数据,例如,各种KNC的温度和主机温度(例如CPU)。然后,每个KNC有四个线程。每个线程运行相同的脚本,但参数不同。脚本只连接到参数中指定的KNC,并在协处理器上运行一个可执行文件。

我们使用两个不同的应用程序进行此基准测试。我们有一个空闲测试,它只运行sleep应用程序。此外,我们还有一个压力测试,它运行适当的XHPL(High Performance Linpack)程序。前者运行一小时,后者运行10分钟。最终,我们收集了系统重要的温度分布特征。

兴趣点

不幸的是,我无法提供系统的测试帐户。它仅限于学术用途,特别是对于联合获得德国研究基金会资助的研究合作。通常,研究人员通过许多登录节点之一登录到系统。唯一的要求是拥有一个帐户(并分配计算时间,但通常这不是问题)。

监控系统还会向用户通报登录节点的状态。它们永远不应该宕机,但一个或另一个可能由于维护原因而离线。

QPACE2 Monitoring Login Nodes

整个项目持续了近3年。最初计划在2014年发布该系统,但我们的第一家工业合作伙伴遇到了美国政府的问题。由于政治原因,俄罗斯公司被列入贸易黑名单。因此,我们不得不结束合作关系。否则,整个项目的未来将受到威胁。尽管如此,我们及时找到了新合作伙伴,开发了新设计并完成了项目。最终,整个插曲花费了我们一年多的时间。教训很简单:你永远不知道会发生什么,但拥有一个好的B计划(甚至可能是C计划)可能至关重要。

原型机架看起来是什么样的?这是在其最终目的地,大学计算中心拍摄的照片。

QPACE2 Installation

通常,超级计算机的寿命在5到10年之间。计算效率的重大进步使得一台机器,即使它仍然是世界上最快的计算机之一,也很快变得效率低下。因此,维护成本很可能决定了大多数系统的终结。此外,新的应用程序和改进的基础设施组件,例如更快的网络互连,也可能需要升级。

对我们来说,未来是QPACE 3。它将基于KNC的继任者,速度应该会快一个数量级。此外,它的效率也应该是QPACE 2的四倍。

参考文献

历史

  • v1.0.0 | 初始发布 | 2016年4月10日
  • v1.0.1 | 修复了一些拼写错误 | 2016年4月15日
  • v1.0.2 | 修复了一些拼写错误 | 2016年4月23日
© . All rights reserved.