高速通信計算研究所

slankdevの報告

Thread Affinityによる性能実験

雑記状態なので、この記事もとても汚いことを了承してください。

DPDKはpthreadwを用いてスレッド操作を行っている。 内部でset affinityを行い、複数のCPUでスレッドを共有しないように固定している らしいが、実際に複数CPUで共有実行を行った場合と、単一CPUで動作をおこなった場合 どの程度性能に差がでるのかを検証してみた。

比較対象, 評価方法

比較対象

  • 単一CPUで固定して動作させるthread
  • 固定しないで動作させたthread

評価方法

  • thread遅延 (無限loopの一回の遅延[clock])

ソースコード

#include <slankdev/system.h>
#include <slankdev/cpuset.h>
#include <slankdev/thread.h>


uint64_t func(int loop_count, bool setaffinity_1core)
{
  if (setaffinity_1core) {
    slankdev::cpuset cpuset(0x2);
    slankdev::thread_self th;
    th.setaffinity_np(sizeof(cpu_set_t), cpuset.get_native());
  }

  uint64_t before = slankdev::rdtsc();
  for (size_t i=0; i<loop_count; i++) ;
  uint64_t latency = slankdev::rdtsc() - before;
  return latency;
}


int main()
{
  for (size_t i=0; i<10; i++) {
    printf("test%zd\n", i);
    uint64_t affinity_true  = func(1000000000, true);
    uint64_t affinity_false = func(1000000000, false);
    printf("+ affinity true : %lu \n", affinity_true );
    printf("+ affinity false: %lu \n", affinity_false);
  }
}

実験結果

以下に示す

test0
+ affinity true : 4681434790
+ affinity false: 4634806268
test1
+ affinity true : 4637598020
+ affinity false: 4663916764
test2
+ affinity true : 4591219566
+ affinity false: 4599745108
test3
+ affinity true : 4612664322
+ affinity false: 4619733254
test4
+ affinity true : 4570637696
+ affinity false: 4547641394
test5
+ affinity true : 4606940932
+ affinity false: 4582990918
test6
+ affinity true : 4576054526
+ affinity false: 4612506292
test7
+ affinity true : 4552900718
+ affinity false: 4551479516
test8
+ affinity true : 4559223794
+ affinity false: 4556642934
test9
+ affinity true : 4600009958
+ affinity false: 4597938462

空のループなので、とくに性能の変化は大きくは見えなかった。 メモリアクセスとかいろいろやったらもしかしたら変わるかもしれないので、 今後少しずつ結果を伸ばしていきたい.

Linux Network Stack Debugging using eBPF

とりあえずLinux Kernelのネットワークスタックのデバッグ/トレースをしてみようと思う。

Bccを用いたトレース手順

  1. デバッグ対象を決める
    • hookポイント
    • trace内容
  2. それに対して必要なスクリプトを書く (bcc, bpf, python, c)
  3. スクリプトを動かしてTraceを確認する

今回は例としてaf_packet socketで開いたsocketでのpacket送信をtraceして、どのようなpacketが 送信されているのかをしらべてみる. また, trace開始時からどれだけパケットを送信したかもカウントする。 まとめると以下ような内容になる。

  • packet_sendmsg関数にhook pointを仕掛ける
  • traceする関数では以下を行う
    • どのようなパケットが送られているかをprintkする
    • パケット送信回数をカウントする

パケット情報表示では、ほんとはバイナリ表示したかったが、packet長のみを表示することになってしまった。 (eBPFのスクリプトが大きくなりすぎて、エラーが出てしまいできなかった。今後もしらべて行きます。。。)

実践

今回traceする関数は以下の関数です。

github.com

トレースをするために動作確認用としてpacket socketを用いてパケット送信を行うsample programを用意しました。 このプログラムを実行するとpacket socketからarpパケットが一つだけ送信されます。 gist.github.com

このプログラムで用いるlibslankdevの使用方法はこちらを参照してください github.com

本題のトレーススクリプトは以下のようになります。

gist.github.com

実行結果を以下に示す。

$ sudo ./trace.py
[1]:
+ sock=ffff88030b9d2f80
+ msg=ffff8802daac7dc0
+ len=42
[2]:
+ sock=ffff88030b9d2f80
+ msg=ffff8802daac7dc0
+ len=42
[3]:
+ sock=ffff88030b9d2f80
+ msg=ffff8802daac7dc0
+ len=42
[4]:
+ sock=ffff88030b9d2f80
+ msg=ffff8802daac7dc0
+ len=42
^C%
$

今回は簡単なtraceのみだったが、もっと複雑なことができるはず、と信じてもっと勉強しよう。 デバイスドライバの関数とかもhookできるか時間があったらしらべたい。

参考文献

BccとBPFでTracing

Packetとはなんなのかを理解するためにBPFをかじり始めたら どつぼにハマってしまい、とりあえずどんなことができるのかを 簡単なスクリプトを書いて試した.

目次

  • bpfで関数callをhookする
  • bpfで関数callの引数をtraceする
  • bpfで関数呼び出しの回数を取り出す

本記事で行う作業の一般的な手順を以下に示す

  1. BccでBPF Bytecodeを生成する
  2. hook pointにBytecodeを設定する

今回はiovisor/bccを用いてtracingを行った。

bpfで関数callをhookする

以下のslankdev_test関数の呼び出しをhookしてtracesする。

gist.github.com

実行結果を以下に示す

bpfで関数callの引数をtrace

gist.github.com

bpfで関数呼び出しの回数を取り出す

gist.github.com

bpf validationについて

bpfコンパイル時に実行ファイルが無限ループでない、とか不正アクセスしていない、とかをチェックしていいるのだが、 それがいまいちどの程度作業をしているのかがまだ明確でない。ドキュメントとかをみればしっかり書いてあるのだろうが、 今後しらべておきたい。

Slankdevなりのセキュリティ・キャンプの選考に通過するためのベストプラクティス

私は2015年のセキュリティキャンプの修了生で、2016年はチューターを担当しました。

セキュリティ・キャンプに通過するために何をすれば良いのか、というのを 私なりに簡単に考えました。

このリンク から申し込みができます。

もちろん、私個人の見解なので、所属する団体やセキュリティ・キャンプの 運営には一切関係がございません。ですが、私は以下に示すようなことが できる人材が セキュリティ・キャンプの選考を通過し、その後も成長しているような 気がします。 (もちろん私が尊敬する方もそうです)

ながくすると読みたくなくなるので、短くまとめました。

ぐちぐち言っていないで手を動かす

「まずは勉強してからそれから手を動かそうとおもいます」 というひとがいるのですが、私はそうは思いません。 「手を動かして、やっと勉強の仕方がわかる」というのが真実だと思います. めそめそしていてはおじいちゃんになってしまうので、どうせなら思い切って、 手を動かしてみましょう。楽しいことに気づくはずです。それから「もっとむずかしい、 奥が深い、もっと楽しい」というのに気づきます。キャンプの講師やチューターや 修了生はそれが楽しくてコンピュータをやっています。

やってみたけど、出来ない!!!!

じゃあ、どこまでやって出来なかったかをアウトプットしましょう。 キャンプの選考は問題の正解を重要視していません。問題に対してどのように アプローチして、どれだけたくさんチャレンジしたかをより重視しています。

  1. やれば、できるはずだ. でも面倒くさい.. -> これはダメです!!!
  2. やってみたけど、できない -> どこまでチャレンジしたかをしっかり整理しましょう
  3. できた -> すごい!! なんでできたか、ほかにはどんな考えがあるかを整理しましょう
  4. 余裕 -> こんなブログみてないで社会貢献してください!!

で、諦めてはいけません。自分のできる限り、たくさん考えて、 なんでも試してみましょう。そうすればいつかはできるはずです。

わからないからといって諦めない

世の中のほとんどのことが簡単にはうまくいかないことだと思います。 20年とちょっとしか生きていない僕がそうおもうので、年を重ねればもっと 実感するかもしれません。

キャンプの選考の問題も難しい問題がたくさんあります。 大事なことは問題の 正誤ではない。ようはどれだけその問題を解くために頑張ったか。 ということをしっかりと頭に叩き込んでください。

納得行かないことは試して納得

以前、@liva_jy氏(2017講師)から「ある定理や証明を考えるときに、それを他の モデルにも当てはめて試してみることが大事です!!」とアドバイスをいただきました. (こんなニュアンスだったと思います)

これはとても大事なことだと感じていて、何に対してもあてはめることができると 思います。(liva氏しゅごい)

満身せず、より深い理解をもとめて、いろいろと試すことが大事です。 トラブルがおきたとき、試行錯誤すればなおりますよね? じゃあ解決できたら、なぜ解決出来たか。をよく考えてください。

問題が難しすぎて本当にわけわかめな人

普通です。僕はそうでした。いまでもまだ完答できないかもしれません。 だから、これを機会に0から勉強を始めましょう。セキュリティ・キャンプは そういう人を歓迎します。

選考に通過できたら…

すごいです。でもそれはまだスタート地点。これからより一層楽しい生活が 待っています。同世代のプロの刺激をうけることになるでしょう。 中には「すごすぎて、どれくらいすごいか、よくわからん。。。」なんて人も います。でもセキュリティ・キャンプを起爆剤としてあなたもそのような 人になれるはずです。(私でもなれると信じています。)

最後にヒント

行き詰まったら,Googleで「セキュリティ・キャンプ 選考」と検索してみましょう。 これまでの先輩がどれだけ苦しんだかがわかります。 間違いだってたくさんあるはずです。でもみんなしっかり成長してプロになっています。

サイボウズ・ラボユース 第6期

2016/2/1から1年間、サイボウズ・ラボユースという制度で研究開発の支援を受けていた. 一年間、本当に強力なサポートをしていただき、我ながら圧倒的に成長した気がするので、 他の人にもぜひ体験していただきたく、ラボユースの紹介と報告をしようと思う。 ラボユースでは高性能なネットワークスタックの開発を行い、10GbE環境でLinuxよりPingの応答が 2倍早いネットワークスタックが出来上がった。

以下は成果報告会の発表資料である。

https://www.slideshare.net/mobile/slankdev/dpdk-74027268

サイボウズラボユースとは

http://labs.cybozu.co.jp/youth.html:tittle

引用: サイボウズ・ラボユースは、世界に通用する日本の若手エンジニアの発掘と育成を 目指すことを目的とし、学生の若手クリエイターに研究開発の機会を提供する(以下省略)

続きを読む

DPDKでremote_core_launchした処理が例外を投げた時の挙動について

上記について実際に動かして調べました。

パターン1: remote_core_launchをtryに囲む 

void func() /* user implementation */
{
    throw exception;
}

int main() /* developer implementation */
{
    dpdk_init();
    try {
        remote_core_launch(func);
    } catch (e) {
        printf(e.what());
    }
}
続きを読む