拡張ライブラリ作成による高速化
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

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

on

  • 6,004 views

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

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

Statistics

Views

Total Views
6,004
Views on SlideShare
4,359
Embed Views
1,645

Actions

Likes
1
Downloads
7
Comments
0

14 Embeds 1,645

http://blog.ito315.com 1598
http://tweetedtimes.com 13
http://twitter.com 11
https://twitter.com 7
http://kana.ito315.com 3
http://nuevospowerpoints.blogspot.com 3
http://www1079uc.sakura.ne.jp 2
http://karuran.com 2
http://tc.yumesv.com 1
http://i.yumesv.com 1
http://tumblrview.yumesv.com 1
http://wl.ito315.com 1
http://apeta.yumesv.com 1
http://webcache.googleusercontent.com 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

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

  • 1. 拡張ライブラリ作成による高速化 城 一統
  • 2. 自己紹介● 城 一統● いとおちゃん● @i315● 高校にいけるか微妙なので応募資格を 失う前に応募したら言語組受かった● おめでとうございます
  • 3. そもそも
  • 4. 個別課題第1希望: CTF 第2希望: 文法ハック 第3希望:可視化・可聴化
  • 5. その結果
  • 6. 拡張ライブラリ作成による高速化 に選ばれた
  • 7. こんなの希望してない
  • 8. 希望に入れてないのに勝手に決められた
  • 9. 竹迫さんが責任を取ると言って強制的に ライブラリ作りへ
  • 10. 何を作ったか
  • 11. 文字列の中でbitが1になっている数を超高 速に数える (PopCount)
  • 12. なんだそれ
  • 13. だいたいPopCountって なんだ!!!!
  • 14. 例 “A”.bytes.to_a[0] # => 6565.to_s(2) # => “1000010”“100010”.count(“1”) # => 2
  • 15. そもそもそれで何ができるのですか
  • 16. 何かいいことはあるのだろうか
  • 17. 画像認識とかその辺 で便利らしい(ソースは竹迫さん)
  • 18. まずやったこと
  • 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. 遅い
  • 21. String#count知りませんでした
  • 22. mapしてString#countdef popcount_count arr = self.bytes.map do |byte| byte.to_s(2) end returnarr.join.count("1")end
  • 23. そうだHashに入れてみよう
  • 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. これはそこそこ速いです
  • 26. 別にHashでやる必要 はなくてString#each_byteでArrayから持ってきたほうが速くね?というツッコミを頂いた
  • 27. それもそうですね
  • 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. いろいろとひどいけ どこれが結構速い
  • 30. How to usestr = ”takesako”str.popcount# => 36
  • 31. ベンチマーク
  • 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. 結果% 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. これは速い
  • 35. そしてこれをCで書いてみた
  • 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. 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. 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. ベンチマーク
  • 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. 速い!!!!!
  • 42. 正直速くても自分は使いそう にないのでわりとどうでも いい
  • 43. 少なくとも僕は使い道が全くわ かりません
  • 44. まとめ● Rubyはちょっとしたさほど負荷のかからない 処理なら他の言語と比べても実用的なレベル● 負荷のかかることをやるとどうしても差が出る● 誰かRubyをもっと速くしてください
  • 45. ご清聴ありがとうございました