拡張ライブラリ作成による高速化   城 一統
自己紹介●  城 一統●  いとおちゃん● @i315●  高校にいけるか微妙なので応募資格を  失う前に応募したら言語組受かった●  おめでとうございます
そもそも
個別課題第1希望: CTF 第2希望: 文法ハック 第3希望:可視化・可聴化
その結果
拡張ライブラリ作成による高速化     に選ばれた
こんなの希望してない
希望に入れてないのに勝手に決められた
竹迫さんが責任を取ると言って強制的に ライブラリ作りへ
何を作ったか
文字列の中でbitが1になっている数を超高   速に数える  (PopCount)
なんだそれ
だいたいPopCountって  なんだ!!!!
例 “A”.bytes.to_a[0] # => 6565.to_s(2) # => “1000010”“100010”.count(“1”) # => 2
そもそもそれで何ができるのですか
何かいいことはあるのだろうか
画像認識とかその辺  で便利らしい(ソースは竹迫さん)
まずやったこと
String#each_chardef popcount_each_char  count = 0  self.bytes.each do |byte|     byte.to_s(2).each_char do |bit|       cou...
遅い
String#count知りませんでした
mapしてString#countdef popcount_count  arr = self.bytes.map do |byte|    byte.to_s(2)  end  returnarr.join.count("1")end
そうだHashに入れてみよう
Hashで   def popcount_hash     hash = {x00 => 0, x01       => 1, x02 => 1, x03 => 2, x04 => 1, x05 => 2, x06 =>2, a => 3, b...
これはそこそこ速いです
別にHashでやる必要      はなくてString#each_byteでArrayから持ってきたほうが速くね?というツッコミを頂いた
それもそうですね
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, ...
いろいろとひどいけ どこれが結構速い
How to usestr = ”takesako”str.popcount# => 36
ベンチマーク
bench.rbrequire “benchmark” …arr = ["t", "a", "k", "e", "s", "a", "k", "o"]str = ""50000.times do  str << arr.shuffle.join...
結果% ruby bench.rb           user      system      total            realeach_char: 10.630000    0.020000 10.650000    (   1...
これは速い
そしてこれをCで書いてみた
popcount.c#include <ruby.h>VALUE popcount_m(VALUE);VALUE popcount_cpu_m(VALUE);void Init_popcount(void) {   VALUE cString ...
VALUE popcount_m(VALUE self)VALUE popcount_m(VALUE self) {  int count = 0;  int i;  char *ptr;     static int array[256] =...
VALUE popcount_cpu_m(VALUE)VALUE popcount_cpu_m(VALUE self) {  int count = 0;  int i;  long long *ptrll;    ptrll = (long ...
ベンチマーク
% ruby bench.rb           user       system     total      realeach_char: 8.100000   0.000000   8.100000   ( 8.120804)coun...
速い!!!!!
正直速くても自分は使いそう にないのでわりとどうでも   いい
少なくとも僕は使い道が全くわ かりません
まとめ●   Rubyはちょっとしたさほど負荷のかからない    処理なら他の言語と比べても実用的なレベル●    負荷のかかることをやるとどうしても差が出る●   誰かRubyをもっと速くしてください
ご清聴ありがとうございました
Upcoming SlideShare
Loading in …5
×

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

6,033 views

Published on

セプキャン2011 プログラミング言語クラス 個別演習課題 文字列の中でbitが1になっている数を超高速に数える(PopCount)

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
6,033
On SlideShare
0
From Embeds
0
Number of Embeds
1,660
Actions
Shares
0
Downloads
8
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

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

  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] # => 6565.to_s(2) # => “1000010”“100010”.count(“1”) # => 2
  15. 15. そもそもそれで何ができるのですか
  16. 16. 何かいいことはあるのだろうか
  17. 17. 画像認識とかその辺 で便利らしい(ソースは竹迫さん)
  18. 18. まずやったこと
  19. 19. String#each_chardef popcount_each_char count = 0 self.bytes.each do |byte| byte.to_s(2).each_char do |bit| count += 1 if bit == "1" end endend
  20. 20. 遅い
  21. 21. String#count知りませんでした
  22. 22. mapしてString#countdef popcount_count arr = self.bytes.map do |byte| byte.to_s(2) end returnarr.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 countend
  29. 29. いろいろとひどいけ どこれが結構速い
  30. 30. How to usestr = ”takesako”str.popcount# => 36
  31. 31. ベンチマーク
  32. 32. bench.rbrequire “benchmark” …arr = ["t", "a", "k", "e", "s", "a", "k", "o"]str = ""50000.times do str << arr.shuffle.joinendBenchmark.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 realeach_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 realeach_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. ご清聴ありがとうございました

×