Successfully reported this slideshow.
Your SlideShare is downloading. ×

拡張ライブラリ作成による高速化

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad

Check these out next

1 of 45 Ad

More Related Content

Similar to 拡張ライブラリ作成による高速化 (20)

Advertisement

Recently uploaded (20)

拡張ライブラリ作成による高速化

  1. 1. 拡張ライブラリ作成による高速化 城 一統
  2. 2. 自己紹介 ● 城 一統 ● いとおちゃん ● @i315 ● 高校にいけるか微妙なので応募資格を 失う前に応募したら言語組受かった ● おめでとうございます
  3. 3. そもそも
  4. 4. 個別課題 第1希望: CTF 第2希望: 文法ハック 第3希望: 可視化・可聴化
  5. 5. その結果
  6. 6. 拡張ライブラリ作成による高速化 に選ばれた
  7. 7. こんなの 希望してない
  8. 8. 希望に入れてないの に勝手に決められた
  9. 9. 竹迫さんが責任を取 ると言って強制的に ライブラリ作りへ
  10. 10. 何を作ったか
  11. 11. 文字列の中でbitが1に なっている数を超高 速に数える (PopCount)
  12. 12. なんだそれ
  13. 13. だいたいPopCountって なんだ!!!!
  14. 14. 例 “A”.bytes.to_a[0] # => 65 65.to_s(2) # => “1000010” “100010”.count(“1”) # => 2
  15. 15. そもそもそれで 何ができるのですか
  16. 16. 何かいいことは あるのだろうか
  17. 17. 画像認識とかその辺 で便利らしい (ソースは竹迫さん)
  18. 18. まずやったこと
  19. 19. String#each_char def popcount_each_char count = 0 self.bytes.each do |byte| byte.to_s(2).each_char do | bit| count += 1 if bit == "1" end end end
  20. 20. 遅い
  21. 21. String#count 知りませんでした
  22. 22. mapしてString#count def popcount_count arr = self.bytes.map do | byte| byte.to_s(2) end return arr.join.count("1") end
  23. 23. そうだ Hashに入れてみよう
  24. 24. Hashで def popcount_hash hash = {'x00' => 0, 'x01' => 1, 'x02' => 1, 'x03' => 2, 'x04' => 1, 'x05' => 2, 'x06' => 2, 'a' => 3, 'b' => 1, 't' => 2, 'n' => 2, 'v' => 3, 'f' => 2, 'r' => 3, 'x0E' => 3, 'x0F' => 4, 'x10' => 1, 'x11' => 2, 'x12' => 2, 'x13' => 3, 'x14' => 2, 'x15' => 3, 'x16' => 3, 'x17' => 4, 'x18' => 2, 'x19' => 3, 'x1A' => 3, 'e' => 4, 'x1C' => 3, 'x1D' => 4, 'x1E' => 4, 'x1F' => 5, ' ' => 1, '!' => 2, '"' => 2, '#' => 3, '$' => 2, '%' => 3, '&' => 3, ''' => 4, '(' => 2, ')' => 3, '*' => 3, '+' => 4, ',' => 3, '-' => 4, '.' => 4, '/' => 5, '0' => 2, '1' => 3, '2' => 3, '3' => 4, '4' => 3, '5' => 4, '6' => 4, '7' => 5, '8' => 3, '9' => 4, ':' => 4, ';' => 5, '<' => 4, '=' => 5, '>' => 5, '?' => 6, '@' => 1, 'A' => 2, 'B' => 2, 'C' => 3, 'D' => 2, 'E' => 3, 'F' => 3, 'G' => 4, 'H' => 2, 'I' => 3, 'J' => 3, 'K' => 4, 'L' => 3, 'M' => 4, 'N' => 4, 'O' => 5, 'P' => 2, 'Q' => 3, 'R' => 3, 'S' => 4, 'T' => 3, 'U' => 4, 'V' => 4, 'W' => 5, 'X' => 3, 'Y' => 4, 'Z' => 4, '[' => 5, '' => 4, ']' => 5, '^' => 5, '_' => 6, '`' => 2, 'a' => 3, 'b' => 3, 'c' => 4, 'd' => 3, 'e' => 4, 'f' => 4, 'g' => 5, 'h' => 3, 'i' => 4, 'j' => 4, 'k' => 5, 'l' => 4, 'm' => 5, 'n' = > 5, 'o' => 6, 'p' => 3, 'q' => 4, 'r' => 4, 's' => 5, 't' => 4, 'u' => 5, 'v' => 5, 'w' => 6, 'x' => 4, 'y' => 5, 'z' => 5, '{' => 6, '|' => 5, '}' => 6, '~' => 6, 'x7F' => 7, 'x80' => 1, … , "xFE"=>7, "xFF"=>8} # ↑ココ重要 count = 0 self.each_char do |char| count += hash[char] end return count end
  25. 25. これはそこそこ速いです
  26. 26. 別にHashでやる必要 はなくて String#each_byteで Arrayから持ってきた ほうが速くね?とい うツッコミを頂いた
  27. 27. それもそうですね
  28. 28. String#each_byteしてArrayから def popcount_array array = [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, , 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, , 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, , 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8] count = 0 self.each_byte do |byte| count += array[byte] end return count end
  29. 29. いろいろとひどいけ どこれが結構速い
  30. 30. How to use str = ”takesako” str.popcount # => 36
  31. 31. ベンチマーク
  32. 32. bench.rb require “benchmark” … arr = ["t", "a", "k", "e", "s", "a", "k", "o"] str = "" 50000.times do str << arr.shuffle.join end Benchmark.bm do |x| bench_each_char = x.report("each_char:") do 10.times do str.popcount_each_char end end bench_count = ... bench_hash = ... bench_array = … bench_c = ... bench_c_cpu = … end
  33. 33. 結果 % ruby bench.rb user system total real each_char: 10.630000 0.020000 10.650000 ( 10.632659) count: 2.040000 0.050000 2.090000 ( 2.094404) hash: 1.120000 0.010000 1.130000 ( 1.137357) array: 0.380000 0.000000 0.380000 ( 0.379857)
  34. 34. これは速い
  35. 35. そしてこれを Cで書いてみた
  36. 36. popcount.c #include <ruby.h> VALUE popcount_m(VALUE); VALUE popcount_cpu_m(VALUE); void Init_popcount(void) { VALUE cString = rb_define_class("String", rb_cObject); rb_define_method(cString, "popcount", popcount_m, 0); rb_define_method(cString, "popcount_cpu", popcount_cpu_m, 0); } VALUE popcount_m(VALUE self) { … } VALUE popcount_cpu_m(VALUE self) { … }
  37. 37. VALUE popcount_m(VALUE self) VALUE popcount_m(VALUE self) { int count = 0; int i; char *ptr; static int array[256] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}; ptr = RSTRING_PTR(self); for (i = 0; i < RSTRING_LEN(self); i++) { count += array[ptr[i]]; } return INT2FIX(count); }
  38. 38. VALUE popcount_cpu_m(VALUE) VALUE popcount_cpu_m(VALUE self) { int count = 0; int i; long long *ptrll; ptrll = (long long *)RSTRING_PTR(self); for (i = 0; i < RSTRING_LEN(self); i += sizeof(long long)) { count += __builtin_popcountll(*ptrll++); } return INT2FIX(count); }
  39. 39. ベンチマーク
  40. 40. % ruby bench.rb user system total real each_char: 8.100000 0.000000 8.100000 ( 8.120804) count: 1.470000 0.200000 1.670000 ( 1.680836) hash: 0.800000 0.000000 0.800000 ( 0.802213) array: 0.310000 0.000000 0.310000 ( 0.308227) c: 0.000000 0.000000 0.000000 ( 0.003734) c_cpu: 0.000000 0.000000 0.000000 ( 0.000474) Cで書いたものがRubyで書いた ものより2桁程度高速化して Cで書いてPOPCNT命令を使用し たものがさらに1桁高速化
  41. 41. 速い!!!!!
  42. 42. 正直速くても 自分は使いそう にないので わりとどうでも いい
  43. 43. 少なくとも僕は 使い道が全くわ かりません
  44. 44. まとめ ● Rubyはちょっとしたさほど負荷のかからない 処理なら他の言語と比べても実用的なレベル ● 負荷のかかることをやるとどうしても差が出る ● 誰かRubyをもっと速くしてください
  45. 45. ご清聴ありがと うございました

×