Cybozu Inside Out | サイボウズエンジニアのブログ

 

サイボウズQAの紹介

こんにちは。 今年の1/4が終わってしまったことが信じられない東京品質保証部の新関です。 今日はサイボウズの品質保証部の取組みと組織紹介をさせていただきます。

その歴史

サイボウズのQA組織の歴史は、2000年に開発部内でQAグループを形成したのがスタート地点です。 当時は人数も少なく、1人で複数の製品の品質保証責任者を担う事が多かったです。現在は東京以外に松山、上海、ベトナム(ホーチミン)にQAの部署が存在し、サイボウズ製品を手厚く試験する体制となっています。

品質保証部の主要なロール(役割)

品質保証部のミッションは、その名の通り製品の品質を保証することです。製品を担当するチームと横断的な活動をするチームが協力する体制です。

QA

プロダクトのテストプロジェクト全般を担当しています。試験計画立案からリリース、お客様からのお問い合わせに至るまで、製品のライフサイクルすべてに関わります。 blog.cybozu.io blog.cybozu.io

TE(Test Engineering Team)

品質と生産性の向上をミッションとしたチームです。開発とQAのジョイント組織で、兼務のメンバーもいます。 blog.cybozu.io blog.cybozu.io

4/16(月)に社外向けイベントとしてMeetupを開催します。 cybozu.connpass.com

PSIRT(Product Security Incident Response Team)

セキュリティ試験を担当しています。脆弱性報奨金制度の運営、その一環としてバグハンター合宿の開催、社外イベントでの講演などを行っています。 blog.cybozu.io blog.cybozu.io

Performance

主に性能試験を担当しています。パフォーマンスチューニングの成果を確認し、ボトルネックの調査も行います。

その他

OSやブラウザの新バージョンで動作検証を行うチーム、通訳/資料の翻訳を担当するコミュニケーターチーム、海外拠点メンバーとのコミュニケーションについてエンジニアリング観点からサポートするチームなどがあります。これらについては、近いうちに別のエントリで紹介しようと思います。

仕事の進め方について

海外を含め、拠点をまたぐ形でチームを組んでいるので、普段はTV会議やグループウェアを駆使して仕事を進めています。 それだけではなく、定期的に1箇所に集まり、他拠点のチームメンバーと顔をあわせてコミュニケーションを図ることにしています。直近の活動内容を報告する社内イベント、相互のスキルアップを目的とした勉強会、チームの親睦を深めるイベントなどを開催し、より強いチームを育てるためです。

また、どの拠点にも主要なロールのメンバーを育成する取り組みを進めています。現在は拠点ごとに役割が偏っているのですが、様々な場所で様々な働き方をしているメンバーが増えているので、場所にとらわれずにチームを組めるように、という目標をたてたのです。 拠点間でナレッジを共有してゆくことで、サイボウズのQA全体を強く成長させていきたいという期待もあります。

サイボウズQAのこれから

PSIRTやTEのように専門性をもった役割以外に、スクラムマスターにチャレンジするQAメンバーも出てきました。 品質を保証するミッションは勿論ですが、メンバーそれぞれの強みを活かし、これまで以上の価値を提供できるようになっていけるとよいと思っています。 また、クラウドベンダーとして、Pre ProductionのQAだけでなく、In ProductionでのQAの取り組みについてが今後の課題となっていくと認識しています。

というわけで、一緒に働いてくれる仲間を募集しています。

ご応募お待ちしております!

 

EPYCマシンの検証(3) - ビルドマシンとしての実力を見る

はじめに

技術顧問のsatです。EPYCマシンの検証についての3回目の記事です。前回の記事はこちらです。

今回はこのマシンのビルドマシンとしての実力を見てみます。これまでの記事と異なり、手元にあったXeonのマシンとの性能比較をしています。

検証環境

  • サーバ(EPYCマシンと記載): Super Micro AS-1023US-TR4

    • CPU: EPYC 7451 x 2 (48コア、96スレッド)
    • メモリ: MEM-DR432L-HL01-ER26(32GB * 16, 合計 512GB)
    • OS: Ubuntu 16.04.4
    • カーネル: 4.13.0-37-generic
  • サーバ(Xeonマシンと記載): DELL PowerEdge R640

    • CPU: Xeon Gold 5120 x 2 (28コア、56スレッド)
    • メモリ: M393A4K40BB2-CTD(32GB * 16, 合計 512GB)
    • OS: Container Linux by CoreOS stable (1632.3.0)
    • カーネル: 4.14.19-coreos

どちらもおおよそ中位モデルのサーバ(およびCPU)です。

検証方法

ビルド負荷の一例として、Linuxカーネルのビルド速度を比較しました。このときビルドの並列度に伴ってビルド速度がどのように変わるかを確認しました。いずれのマシンもSMT*1は有効にしています。

検証結果のサマリ

検証の結果をまとめると、おおよそ次のようなことが言えます。

  • 並列度が低いうちはXeonマシンのほうがビルド速度が高い
  • 並列度が高くなるにつれてEPYCマシンのビルド速度がXeonマシンを追い越して、最終的にEPYCマシンのほうが1.4倍高速になる
  • EPYCマシンは並列度が低い場合に性能がばらつく

検証方法

linux v4.15.7をデフォルト設定(defconfig)でビルドした場合の所要時間*2を測定しました。この際、-jオプションによって並列度を1からEPYCマシンのスレッド数である96まで変化させてデータを採取しました。

検証手順は次の通りです。

1) ソースのダウンロードと設定

$ wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.15.7.tar.xz
$ tar xf linux-4.15.7.tar.xz
$ cd linux-4.15.7
$ make defconfig
...
$ 

2) ビルド(ビルドに必要なパッケージはインストール済みとします)

$ cat build.sh
#!/bin/bash

NCPU=$(grep -c processor /proc/cpuinfo)

make clean >/dev/null 2>>err.txt
for ((i=0; i<$NCPU; i++)) ; do
        time make -j$((i+1)) >/dev/null 2>>err.txt
        make clean >/dev/null 2>>err.txt
done >/dev/null 2>>res.txt
$ ./build.sh

検証結果

横軸に並列度を、縦軸にビルド所要時間をプロットした図を以下に示します。

f:id:cybozuinsideout:20180405152458p:plain

一見して並列度が低い場合はXeonマシンのほうが、並列度が高い場合はEPYCマシンのほうが所要時間が短いことがわかります。では、縦軸を速度(所要時間の逆数)にしてみるとどうなるでしょうか。

f:id:cybozuinsideout:20180405152510p:plain

並列度20あたりまでのデータを見るとスレッドあたりの速度はXeonマシンのほうが高いものの、その後は次第にEPYCのビルド速度が上がってきて、最終的にすべてのEPYCマシンのスレッド数である96並列ビルドになった際はEPYCマシンのほうが1.4倍高速であるということがわかります。

Xeonマシンのビルド速度の伸びは並列度28を超えた段階で鈍化しています。これは、並列度28以前は並列化された各処理*3がコアのリソースを占有できていたのに対して、並列度28以降はコアのリソースを2つのスレッド間で共有しなくてはいけない場合が出てくるからです。さらにその後並列度が56を超えた後はビルド速度が頭打ちになることがわかります。これは並列度56の時点でCPU資源を使い切っているため、それ以上並列度を上げてもスループットが上がらないことによります*4

このデータにはもう一点気になることがあります。それはEPYCマシンの低並列度におけるビルド速度がXeonマシンに比べてばらつくこと、もっというと悪い方向にのみばらつくことです。この傾向はデータを何度測定しても変わりませんでした。これについては次節以降において考察しました。

EPYCマシンにおけるビルド速度ばらつき問題の調査

最新カーネルへのアップデート

本記事の検証に使ったカーネルはUbuntu16.04において使える最新カーネルであるv4.13(正確には4.13.0-37-generic)ですが、カーネルv4.15にはプロセススケジューラにEPYC対応のパッチが入っています。このパッチによって問題が解消するのではないかと推測して、より新しいUbuntuからカーネル4.15.0-13-genericを借りてきて、このカーネルにおけるデータも採取しました。

f:id:cybozuinsideout:20180405152522p:plain

しかし推測は外れていました。カーネルをv4.15系にしても性能がばらつく問題は解消しないことがわかりました。

SMTの無効化

EPYCマシンの性能がばらつくのは並列度が低いとき、とくにEPYCマシンのコア数48を下回るときだったため、SMTが有効なとき、かつ、同時に実行中のプロセス数が少ない場合に何か問題があるのではないかと疑って、SMTを無効化した状態でデータを採取してみました。

f:id:cybozuinsideout:20180405152535p:plain

この結果、SMTを無効化した場合はEPYCマシンにおける性能のばらつきが無くなることがわかりました。

最後に、EPYCマシンはSMTを無効化するとXeonマシンのSMT有効/無効時いずれの場合よりもビルド速度が高くなったことも見逃せません。LinuxにおけるEPYCマシンの性能にはさらなる伸びしろがあると言えるでしょう。

おわりに

EPYCマシンをビルドマシンとして見ると、スレッドあたりの性能はXeonマシンに遅れをとるものの、スレッド数が相対的に多いことを武器にして、全CPU資源を使い切ったときの性能は上回ることがわかりました。並列化された個々の処理がほとんど独立しているカーネルビルド処理ではこのような結果になりましたが、個々の処理の間で排他制御が必要な処理においても同じことが言えるのかについては別途検証が必要です。

もう一点、EPYCサーバはハイパースレッド有効時、かつ、並列度が低い場合に性能がばらつく問題があることがわかりました。このようなことになる原因にはLinuxのプロセススケジューラやプロセッサそのものなど色々なものが考えられますが、現時点では不明です。こちらについても今後の原因究明、および問題の改善についてはさらなる検証が必要でしょう。

*1:Xeonの場合はハイパースレッディングテクノロジーと呼びます

*2:timeコマンドのrealフィールドの値

*3:ほとんどはCコンパイラによる個々のファイルのコンパイル処理

*4:ここでは詳細については触れませんが、このビルド処理においては、入力であるソースファイルも出力であるカーネルイメージおよびオブジェクトファイルは全てページキャッシュに乗るため、処理の最中にI/Oがほとんど発生しません

 

「第7期サイボウズ・ラボユース成果発表会」開催

こんにちは、サイボウズ・ラボの光成です。

今回は3/30にあった第7期サイボウズ・ラボユース成果発表会の模様を紹介します。

サイボウズ・ラボユース

毎度おなじみの紹介になりますが、サイボウズ・ラボユースとは日本の若手エンジニアを発掘し、育成する場を提供する制度です。

ラボユース生が作りたいものをサイボウズ・ラボの社員がメンターとしてサポートします。 開発物をオープンソースとして公開するという条件の下で著作権は開発者本人に帰属します。

今期はラボユース生6名、研究生2名が卒業されました。

前半の発表

高品佑也さん

高品さんの発表は「確率変数間のグラフ構造推定手法の提案と実装」でメンターは中谷さんでした。

f:id:cybozuinsideout:20180402155441j:plain

多次元のデータが与えられたときに、そのデータのどこに関係があるかを推定するグラフィカルモデルの構造推定の話です。 今回の成果は論文にまとめて投稿中で、結果が出たら詳細な解説や紹介記事を書きたいとのことです。 ラボユースはやりたいことに集中でき、夏の合宿も楽しく、中谷さんの愛あるツッコミがためになったそうです(depynd)。

川田恵さん(研究生)

川田さんの発表は「Exploitの旅2018」でメンターは星野さんでした。

f:id:cybozuinsideout:20180402155411j:plain

CTFの問題の作り方の紹介で、脆弱性を持つプログラムを作るにはコンパイラやコンパイルオプションに気を付けてテストをしっかりしなければなりません。 できれば他のチームに依頼できるとよいとのことです。 自分の意図した通りに挑戦者が問題を解いてくれるとうれしいそうです。

黒岩将平さん

黒岩さんの発表は「Return Oriented Programmingの自動化」でメンターは私でした。

f:id:cybozuinsideout:20180402155416j:plain

ROPはCTFでよく使われるテクニックの一つで夏のラボユース合宿のときはPythonで作っていたのをC++17を使って作り直しました。 CTFの問題の中には機械じゃないと解けないのもあるので、そういうのには有用だろうとのことです(ropchain)。

渡部恭久さん

渡部さんの発表は「拡張可能インタプリタのための構文解析フレームワーク」でメンターは川合さんでした。

f:id:cybozuinsideout:20180402155419j:plain

目標はきれいなプログラミング言語処理の開発です。 構文解析器とプリンタ(構文木を文字列にする変換器)を同時に定義するInvertible Syntaxというアイデアを元にしました。 構文を拡張したときに、追加した構文にマッチするよう最長一致の構文解析を導入しました。 左再帰への問題は将来対応したいとのことです(finale)。

後半の発表

増田健太さん

増田さんの発表は「制約と手続きを用いた作図用プログラミング言語Pitaの開発」でメンターは星野さんでした。

f:id:cybozuinsideout:20180402155423j:plain

図形を表現する文法と、図形の演算、図形同士の制約処理を記述して図形を出力する処理系です。 ローカル変数や再帰表現などをサポートし、円と長方形が接したままサイズを変更するといった記述ができます。 内部的には記号計算ではなく制約を満たす最適化問題に変換して解きます(Pita)。

類似のツールがないのでこのツールの特長が分かりにくかったのですが、デモを見るとみなさん驚きの声があがりました。

西田耀さん

西田さんの発表は「人間にも読み書きしやすいx86アセンブラをつくってみた」でメンターは川合さんでした。

f:id:cybozuinsideout:20180402155428j:plain

x86のIntel形式とAT&T形式のmovはどちらからどちらに代入するかすぐ分からなくなるので自分で作ることにしたそうです。 他にも自作OSのために自由度の高いアセンブラが欲しくなるという理由もあります(asmium)。

坂本優太さん(研究生)

坂本さんの発表は「続 自作エミュレータで学ぶx86アーキテクチャ」でメンターは私でした。

f:id:cybozuinsideout:20180402155430j:plain

はりぼてOSという小さいOSを動かすために『自作エミュレータで学ぶx86アーキテクチャ』を参考にしながらx86エミュレータを作りました。 まだまだ機能不足ですがブートして画面に文字が出るところまではできるようになりました。 セグメンテーションまわりの実装はこれからとのことです(emu)。

make_now_justさん

make_now_justさんの発表は「先読み・後読みをもつ正規表現の有限状態オートマトンへの変換」でメンターは西尾さんでした。

f:id:cybozuinsideout:20180402155433j:plain

正規表現の後読みは速度が遅かったり機能に制約があるものが多いので理論からきちんと攻めてみました。 ScalaやGoで実装し、あるパターンでGoogleのV8エンジンで53秒かかっていたものが1秒(以内?)に高速化されたようです。 ドメイン付きクリーネ代数を勉強し、理論的な意味づけをしていきたいとのことです。

LT&懇親会

@KageShironさんが「Headless Chromeを活用したCTF Web問題の作問」のLTをされました。

f:id:cybozuinsideout:20180402163830j:plain

CTFでXSSなどの問題を提供しようとするとアプリの難読化や環境の違いでうまくいかないことが多いのでGUIがないheadlessブラウザを使う方法を紹介しました。 APIを使ってブラウザを制御できるのでいろいろ便利です。

懇親会では発表に関する活発なやりとりがあり面白かったです。

f:id:cybozuinsideout:20180402155435j:plain

まもなく今年度の応募が始まりますので興味ある方はしばらくお待ちください。

 

サイバーセキュリティ小説コンテストに協賛しました。

セキュリティ室の明尾です。

3/31(土) 12:00 ~ カクヨム様で、サイバーセキュリティ小説コンテストが開催されます。

 カクヨムからのお知らせ  kakuyomu.jp

サイボウズは、サイバーセキュリティ小説コンテストのプラチナスポンサーとして協賛をさせていただきました。 本エントリで、コンテストの趣旨とスポンサーとしての思いをお伝えし、素晴らしい作品が数多く投稿されるよう期待をしたいと思います。

サイバーセキュリティ小説コンテストとは?

JNSA(特定非営利活動法人 日本ネットワークセキュリティ協会)様が主催されたコンテストです。 JNSAとは、情報セキュリティに関する普及啓発活動、教育、調査研究などの活動を通じて、ネットワークセキュリティの安全を守る社会貢献をしている団体です。

サイバーセキュリティに関する小説を通じて、サイバーセキュリティに関心を持っていただき、安全安心を高めていきたいと考えられ、このような企画を検討されました。

あっさりOK

JNSA様より、協賛の依頼が来てこのコンテストの説明を受けました。 プラチナスポンサーになるには、相当のコストが掛かり本当に費用対効果があるのか、など悩みましたが、コンテストの趣旨に共感したこと、他に例がない楽しそうな事案 であること、コンテストにより大ヒット小説が生まれた場合に悔しい思いをしたくなかったことから、協賛を社長に提案することにしました。

説明すると、面白そうだね、やろう!ということでプラチナスポンサーとして協賛をすることに決まりました。 迅速に意思決定することで機会損失せずにスポンサーに申し込みをさせていただけることになりました。

アナログハックを目撃せよ!2018 に登壇

プラチナスポンサーの特典として、3/4(日) に開催された「アナログハックを目撃せよ!2018」において、「サイバーセキュリティ小説コンテスト」開催記念トークイベントに セキュリティ室の伊藤が登壇させていただきました。

 イベントの様子はこちらです。(ASCII デジタルの記事となっております  ascii.jp

思った以上に大規模な会場でした。

スポンサーとしての思い

サイボウズはチームワークを大切にする会社で、社会にチームワークが広がることを目指している企業です。そのためのツールやメソッドの販売提供を事業の中核に据えています。

サイバーセキュリティ分野においては、チームワークが不可欠です。(すべてを理解し、すべて的確に判断できるひとはいないので) 攻撃者がサイバー犯罪を起こしにくい環境を作っていくためには、まずはセキュリティに関心を持ってもらう必要があります。 サイバーセキュリティは全員参加!というキャッチフレーズが、サイバーセキュリティ月間でも使われました。 ひとりひとりがサイバーセキュリティに対する正しい知識を身に着け、関心を持っていただける材料として素晴らしい小説ができることを期待しています。

また、企業でサイバーセキュリティと戦っているエンジニアも多数おられるのですが、世間的には決して高い評価が得られているとは思えないのです。(実は攻撃しているのではとか、セキュリティにうるさい人という評価があると思います。) セキュリティエンジニアの日常業務を知っていただき、実はセキュリティを守る正義感の強いカッコいい人たちであることも知ってほしいと思います。 知り合いの作家の方や、小説を書くことが好きな方にコンテストの存在をお伝えいただき、いい作品をどんどん投稿されることにご協力ください。 もちろん、ブログを見た方ご自身のご投稿もお待ちいたしております。

募集開始されました

3/31 より応募受付が開始されています。 ascii.jp

ASCII.jp のサイトでは、弊社青野からのメッセージも公開されています。 20年以上前に流行った映画への軽妙な批評もお楽しみください。

更新履歴

2018年 4月 2日 「募集開始されました」を追記しました。

 

EPYCマシンの検証(2) - NUMAノードをまたぐメモリアクセス速度

はじめに

技術顧問のsatです。前回に引き続き、EPYCマシンの検証についての話をします。手元のEPYCマシン(Super Micro AS-1023US-TR4)はNUMAアーキテクチャ(後述)を採用してます。今回はこのマシンにおけるNUMAノードをまたいだメモリアクセスに関するデータを採取しましたので、その結果をお伝えします。

NUMAについて知っているかた向けの結論

  • 2CPUパッケージから成るEPYCマシンにおいては、CPUパッケージごとに4つのノード、合計8つのノードがある
  • 同じCPUパッケージ上のリモートノード上のメモリへのアクセス速度はローカルノード上のメモリへのアクセス速度に比べて1.7倍程度遅い
  • 別のCPUパッケージ上のリモートノード上のメモリへのアクセス速度はローカルノード上のメモリへのアクセス速度に比べて3.3倍程度遅い
  • (記事では省略したが)"numactl --interleave all"した場合はローカルノード上のメモリへのアクセス速度に比べて2.2倍程度遅い

このデータだけで何ができるというわけではないですが、メモリアクセス速度がボトルネックになるようなシステムにおいては、この値が性能評価における一つの基準になるでしょう。

NUMAとは

本節ではNUMAという言葉についてなじみのないかたがたに向けて簡単にNUMAの説明をします。知っているかたは本節は読み飛ばしてください。NUMAとは複数のCPUコア(以下コアと記載)から成るシステムにおける次のようなアーキテクチャです。

  • システム内の1つないし複数のCPUコア(以下コアと記載)とメモリをひとまとめにしたものをノードと呼ぶ
  • システムは2つ以上のノードから構成される
  • ノード同士はインターコネクトと呼ばれる伝送路によって接続される
  • あるコアから見ると、自身が属するノードをローカルノード、そうでないノードをリモートノードと呼ぶ
  • ローカルノードに属するメモリをローカルメモリ、そうでないメモリをリモートメモリと呼ぶ
  • ローカルメモリへのアクセスはリモートメモリへのアクセスよりも早い

これだけでは難しいので、もっとも単純な次のようなNUMAシステムを考えます。

f:id:cybozuinsideout:20180327112014p:plain

このとき、メモリアクセスの速度は下図のようにどのノード上のコアからどのノード上のメモリにアクセスするかによって異なります。

f:id:cybozuinsideout:20180327112018p:plain

ハードウェアが提供する情報によって、この速度差がどれくらいのものかがわかります。具体的にはnumactlパッケージに含まれるnumactlコマンドを-Hオプション付きで実行します。とある2ノードシステムにおける結果は次のようになりました。

$ numactl -H
...
node distances:
node   0   1  
  0:  10  21
  1:  21  10
$ 

これは次のような意味です。

  • ノード0上のコアからローカルメモリへのアクセス速度は10(この数値の意味は後述)
  • ノード0上のコアからノード1上のリモートメモリへのアクセス速度は21
  • ノード1上のコアからノード0上のリモートメモリへのアクセス速度は21
  • ノード1上のコアからノード1上のローカルメモリへのアクセス速度は10

速度欄の10や21という値は「ナノ秒」などの具体的な単位付きのものではなく相対的なもので、「ノード0からノード1上のリモートメモリへのアクセスはローカルメモリへのアクセスよりも2.1倍遅い」という意味です。

ハードウェアが提供するNUMAノード間のメモリアクセス速度差

手元のEPYCマシンのNUMA構成は前節において記載したものよりもはるかに複雑です。

  • 2つの物理的なCPUパッケージを搭載
  • 1CPUの中にダイと呼ばれる4つの部品を搭載
  • 1ダイの中に6個のコア(12スレッド)を搭載
  • 1つのダイが1つのノードに対応

これを図示すると次のようになります。インターコネクトをすべて書くと図が非常に見づらくなるので、図でいうと一番左上のノードから他のノードにたどり着くためのものだけを記載しています。

f:id:cybozuinsideout:20180327112022p:plain

ではこのマシンのnumactl -Hの値を見てみましょう。

$ numactl -H
...
node distances:
node   0   1   2   3   4   5   6   7
  0:  10  16  16  16  32  32  32  32
  1:  16  10  16  16  32  32  32  32
  2:  16  16  10  16  32  32  32  32
  3:  16  16  16  10  32  32  32  32
  4:  32  32  32  32  10  16  16  16
  5:  32  32  32  32  16  10  16  16
  6:  32  32  32  32  16  16  10  16
  7:  32  32  32  32  16  16  16  10
$ 

ややこしいのでここではノード0からノード0-7へのアクセス速度のみに注目します。

...
node   0   1   2   3   4   5   6   7
  0:  10  16  16  16  32  32  32  32
...

詳細は省略しますが*1、node0-3はCPUパッケージ0上にあり、node4-7がCPUパッケージ1上にあります。これから次のことが言えます。

  • CPUパッケージ0上のリモートノード(ノード1-3)上からのリモートメモリへのアクセスはローカルメモリへのアクセスより1.6倍遅い
  • CPUパッケージ1上のリモートノード(ノード4-7)上のリモートメモリへのアクセスはローカルメモリへのアクセスより3.2倍遅い

ただし、ハードウェアが提供する情報と実際のメモリアクセス速度が異なることは珍しくないので、次節においてメモリアクセス速度を実測します。

実測

プログラム

実測には次のようなことをするプログラムを使います。

  • 適当なサイズのメモリバッファを獲得する
  • 上記バッファに所定の回数アクセスして、所要時間を計測する
  • 所要時間を出力する

これを実装したのが以下のmacccess.cプログラムです。

#include <unistd.h>
#include <sys/mman.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <err.h>

#define CACHE_LINE_SIZE 64
#define BUFFER_SIZE     (256*1024*1024)
#define NLOOP           256

#define NSECS_PER_SEC   1000000000UL

static inline long diff_nsec(struct timespec before, struct timespec after)
{
        return ((after.tv_sec * NSECS_PER_SEC + after.tv_nsec)
                - (before.tv_sec * NSECS_PER_SEC + before.tv_nsec));
}

int main(int argc, char *argv[])
{
        int size = BUFFER_SIZE;

        char *buffer;
        buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        if (buffer == (void *) -1)
                err(EXIT_FAILURE, "mmap() failed");

        struct timespec before, after_wo_access, after_w_access;
        int i;
        volatile int j;
        clock_gettime(CLOCK_MONOTONIC, &before);
        for (i = 0; i < NLOOP; i++)
                for (j = size - CACHE_LINE_SIZE; j >= 0; j -= CACHE_LINE_SIZE)
                        ;
        clock_gettime(CLOCK_MONOTONIC, &after_wo_access);
        double t_wo_access = (double)diff_nsec(before, after_wo_access);

        clock_gettime(CLOCK_MONOTONIC, &before);
        for (i = 0; i < NLOOP; i++)
                for (j = size - CACHE_LINE_SIZE; j >= 0; j -= CACHE_LINE_SIZE)
                        buffer[j] = 0;
        clock_gettime(CLOCK_MONOTONIC, &after_w_access);
        double t_w_access = (double)diff_nsec(after_wo_access, after_w_access);
        printf("%f\n", (t_w_access - t_wo_access)/NSECS_PER_SEC);

        if (munmap(buffer, size) == -1)
                err(EXIT_FAILURE, "munmap() failed");
        exit(EXIT_SUCCESS);
}

ビルド方法は次の通り。

$ cc -O3 -o meccess maccess.c
$ 

測定においてはnumactlコマンドを利用して以下2つの条件を満たすようにします。

  • ノード0に属するコア0上で処理を実行する(--physcpubind 0オプションを指定)
  • ノード0-7上でメモリバッファを獲得する(--membind <ノード番号>オプションを指定)

測定は次のように実行しました。

$ for ((i=0;i<8;i++)) ; do numactl --physcpubind=0 --membind $i ./maccess ; done

結果

$  for ((i=0;i<8;i++)) ; do numactl --physcpubind=0 --membind $i ./maccess ; done
2.492153
4.294302
4.232083
4.20949
8.459225
8.568392
7.946654
8.367991
$ 

所要時間をノード0からのアクセスにおける所要時間からの相対値にすると次のようになります

ノード番号 相対速度
0 1
1 1.72
2 1.69
3 1.68
4 3.39
5 3.43
6 3.18
7 3.35

グラフ化すると次のようになります。

f:id:cybozuinsideout:20180327112032p:plain

これから次のことが言えます。

  • 同じCPUパッケージ上のノード上のメモリに対するアクセスはローカルノード上のメモリへのアクセスよりも1.68-1.72倍程度遅い
  • 別のCPUパッケージ上のノード上のメモリに対するアクセスはローカルノード上のメモリへのアクセスよりも3.18-3.43倍程度遅い

ハードウェアが報告する値とまったく同じとはいえないものの、おおよそ似たような値になりました。

細かい考察(参考)

前節において示したデータを見ると、ノード0と異なるCPUパッケージに属するノード4-7のうち、ノード6上のメモリへのアクセス速度はノード4,5,7上のメモリへのアクセス速度に比べて5-8%程度速いことがわかりました。グラフで見ても同じとは言いにくい差が出ていますし、何度測定しても結果は同じでした。これより、2ソケットのEPYCマシンが次の図のような構造になっているのではないかと推測しました。

f:id:cybozuinsideout:20180327112028p:plain

この推測が正しければ、ノード0からノード6はインターコネクトを1つ通してメモリアクセスできるのに対して、ノード0からノード4,5,7はノード6を経由してインターコネクトを2つ通してメモリアクセスしなければいけないため、アクセス速度に違いが出ていると考えられます。ハードウェアはノード0からノード4-7上のメモリへのアクセス速度は同じと報告したものの、実際には少し違っていた、というわけです。

NUMAについてもっと知りたいかたに

NUMAについてさらに気になるかたは以下のキーワードで調べてみてください。

  • numactlの--interleaveオプション
  • set_mempolicy()システムコール
  • mbind()システムコール
  • LinuxカーネルのNUMA balancing機能

*1:numactl -Hの実行結果と/proc/cpuinfoの内容("processor"で始まる行とそれに対応する"physical id"で始まる行)を照らし合わせます