Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

BuriKaigi2019 「C# ドキドキ・ライブコーディング」 小島の分

629 views

Published on

BuriKaigi2019 (2019/01/26)
https://connpass.com/event/111062/
「C# ドキドキ・ライブコーディング」

Published in: Technology
  • Be the first to comment

BuriKaigi2019 「C# ドキドキ・ライブコーディング」 小島の分

  1. 1. C# ドキドキ・ライブコーディング ~ 小島の分 ~ BuriKaigi2019 – 富山合同勉強会 2019/01/26 小島 富治雄 #burikaigi
  2. 2. 自己紹介  小島 富治雄  @Fujiwo  福井コンピュータアーキテクト株式会社  Microsoft MVP (2005-2019) C#関連
  3. 3. これまでの 対戦 BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi 2 この写真 の作成者 不明な作成者 は CC BY-SA のライセンスを許諾されています
  4. 4. 2015年のお題「七ならべ」のときに 思いついた「工夫」  リフレクション? 他の人が書いたクラスのメソッドを書き換える? Unsafe? メソッドが取り替えられないなら インスタンスを取り替えてしまえ ば 良いじゃない
  5. 5. 以前の4人打ちオセロでの「工夫」  最初に4人分戦わせて、一番強いひとが私の代わりに打てばよいのに。  自 AI のコンストラクターで、事前に5回対戦して強いひと (AI) を選んどいて、 そいつを呼び出す。 class PlayerTable : IEnumerable<KeyValuePair<Board.Piece, IPlayer>> { Dictionary<Board.Piece, IPlayer> playerDictionary = new Dictionary<Board.Piece, IPlayer>(); …… } class GameRunner { …… }
  6. 6. 前回のオセロは機械学習 (Machine Learning) 5 コマンドライン ツール “ReversiGameRunner” を何日 もぶん回して、膨大のデータを生成 それを機械学習で解析して、最適なパラメーターを ざわ… ざわ…
  7. 7. 今回のお題 Base64 エンコード/デコー ド スピード対決!!
  8. 8. 7 1. 基本的な Base64 エンコード/デコード処理 2. 高速化の道 3. 「3バイト=4文字テーブル」への期待と挫折 4. IL への挑戦と挫折 5. そして、チートへ… BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi 今回の工夫 (謎) の数々
  9. 9. 基本的な Base64 エンコード/デコード BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi 8 10進 2進 文字 10進 2進 文字 10進 2進 文字 10進 2進 文字 0 000000 A 16 010000 Q 32 100000 g 48 110000 w 1 000001 B 17 010001 R 33 100001 h 49 110001 x 2 000010 C 18 010010 S 34 100010 i 50 110010 y 3 000011 D 19 010011 T 35 100011 j 51 110011 z 4 000100 E 20 010100 U 36 100100 k 52 110100 0 5 000101 F 21 010101 V 37 100101 l 53 110101 1 6 000110 G 22 010110 W 38 100110 m 54 110110 2 7 000111 H 23 010111 X 39 100111 n 55 110111 3 8 001000 I 24 011000 Y 40 101000 o 56 111000 4 9 001001 J 25 011001 Z 41 101001 p 57 111001 5 10 001010 K 26 011010 a 42 101010 q 58 111010 6 11 001011 L 27 011011 b 43 101011 r 59 111011 7 12 001100 M 28 011100 c 44 101100 s 60 111100 8 13 001101 N 29 011101 d 45 101101 t 61 111101 9 14 001110 O 30 011110 e 46 101110 u 62 111110 + 15 001111 P 31 011111 f 47 101111 v 63 111111 /
  10. 10. 9 0x3F, 0x25, 0x04, 0xE0 BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi Base64 エンコード 0x3F 0x25 0x04 0xE0 0 0 1 1 1 1 1 1 0 0 1 0 0 1 0 1 0 0 0 0 0 0 1 0 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 1 0 0 1 0 1 0 0 0 0 0 0 1 0 1 1 1 0 0 0 0 0 0 0 0 0 15 54 20 2 57 0 ‘P’ ‘2’ ‘U’ ‘C’ ‘5’ ‘A’ ‘=’ ‘=’ 繰り返す → “P2UC5A==” 3バイト=4文字ごと 文字数は4の倍数 6ビットごと (足りないビットは0を追加) (足りない分は ‘=’) 対応する文字に変換 バイト列
  11. 11. 10 → 0x3F, 0x25, 0x04, 0xE0 BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi Base64 デコード 0x3F 0x25 0x04 0xE0 0 0 1 1 1 1 1 1 0 0 1 0 0 1 0 1 0 0 0 0 0 0 1 0 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 1 0 0 1 0 1 0 0 0 0 0 0 1 0 1 1 1 0 0 0 0 0 0 0 0 0 15 54 20 2 57 0 ‘P’ ‘2’ ‘U’ ‘C’ ‘5’ ‘A’ ‘=’ ‘=’ 繰り返す “P2UC5A==” 4文字=3バイト ごと 8ビットごと (余ったビットは不要) (末尾の‘=’は不要)対応する数値に変換 バイト列
  12. 12. 11 要はビット演算を3バイト=4文字ごとに繰り返す BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi Base64 エンコード
  13. 13. 12 ビット演算を4文字=3バイトごとに繰り返す BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi Base64 デコード
  14. 14. 高速化の道 BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi 13
  15. 15. 14 LINQ new なるべくしない (できればしたくない) できるだけ事前 (計測開始前) にしておく BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi 遅いやつ
  16. 16. 15 StringBuilder Span<T> と Memory<T> シンプルな1次元配列の方が早い BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi 速いと噂のやつ
  17. 17. 16 Buffer.BlockCopy(…) や Marshal.Copy(…) コピーサイズが小さいときは、メソッド コールの オーバーヘッドが割に合わない BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi 速いと噂のやつ
  18. 18. 17 マルチコアで並列処理 × AsParallel() 遅い △ Parallel.For(…) まあまあ遅い オーバーヘッドが大きすぎ BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi 速いと噂のやつ
  19. 19. 18 stacalloc スタック領域だから早いのでは Span<T> と組み合わせれば unsafe でなくても使える 今回は、毎回 allocate がどうしても必要なのは、最後の return new string(...); なので、使えない BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi 速いと噂のやつ
  20. 20. 19 unsafe ポインター コピー時の境界チェックなし まとめて転送可 文字列の中を直接書き替えられる 試したが、まあとにかく速い 今回は unsafe オプションなしのプロジェクトなので unsafe はコンパイルできない BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi 本当に速いやつ
  21. 21. 20 メソッド呼ばない (インラインにする) メモリーのキャッシュのヒット率を意識する なるべく近くのメモリーを使う 遠くを使うと、キャッシュのヒット率が著しく落 ちる 配列での境界チェックの排除 BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi その他
  22. 22. 21 答え: 1 と 2。 3は境界チェックが入る。 BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi 問題: 速いのはどれでしょう
  23. 23. ボトルネックの調査 BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi 22 string を new するボト ルネックが消せない! unsafe コードにして、ポイン ターを使えば、解決するが…
  24. 24. 「3バイト=4文字テーブル」へ の期待と挫折 BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi 23 この写真 の作成者 不明な作成者 は CC BY-SA のライセンスを許諾されています
  25. 25. 24 「3バイトが4文字に対応」の繰り返し ならば、あらかじめ (計測前に) エンコード用と デコード用の対応テーブルを作っておいて、 引けば良いのでは エンコード用: 3bytes → 4characters テーブル デコード用 : 4characters → 3bytes テーブル Dictionary<T> や Hashtable は遅いので、 一次元配列で BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi 「3バイト=4文字テーブル」
  26. 26. 25  なんなら、テーブルをC#のコードにして、埋め込んでも良い かも  配列の中身をC#のコードに変換するツールを作ってみた 1行 320 MBのC# コンパイルが終わらない BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi 「3バイト=4文字テーブル」
  27. 27. 26 大きなヒープ領域のあちこちに アクセスするため、キャッシュの ヒット率が著しく落ちる BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi 「3バイト=4文字テーブル」のボトルネッ ク
  28. 28. IL への挑戦 と挫折 BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi 27
  29. 29. 28 事前コンパイル済み unsafe コードの IL を 動かしたら? BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi あきらめきれない unsafe への思い unsafe をコンパイルできないのなら、 コンパイルしなければ良いじゃない
  30. 30. 29 IL を食わせるとこんな感じの C# ができるツール BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi IL → C# ツールの作成 IL_0000: nop IL_0001: nop IL_0002: ldarg.1 IL_0003: dup IL_0004: stloc.1 IL_0005: brfalse.s IL_000C IL_0007: ldloc.1 IL_0008: ldlen IL_0009: conv.i4 IL_000A: brtrue.s IL_0011 IL_000C: ldc.i4.0 IL_000D: conv.u …
  31. 31. 30 unsafe な IL を書くのは大変 ポインターの扱いが大変 BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi unsafe な IL
  32. 32. そして、 チートへ… BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi 31
  33. 33. 32 おや? 何故かこんなコードが… BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi #if CHEAT  事前にタスクを乱立させといて、全CPUの使用率を100%に  自分の番のときだけ、CPU負荷を下げる
  34. 34. 33  System.Runtime.CompilerServices.Unsafe.dll を、 事前に勝手に石野さんのマシンにダウンロードしてきて使う とか  unsafe でコンパイル済みの DLL を、ソースコードに バイト列に埋め込んどいて、事前に書き出して、動的に ロードして使うとか BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi その他のCHEAT やりすぎ → こういうのは、もはや室星さんの役割
  35. 35. 34  失敗談しかない気もするけど、気のせい  ちょっと新人プログラマーには見せられないソースコードに  C#に詳しくなった  C とアセンブリ言語 が恋しくなった BuriKaigi2019 https://connpass.com/event/111062/ #BuriKaigi 最後に感想

×