naitoh.hatenablog.com
Open in
urlscan Pro
54.199.90.60
Public Scan
URL:
https://naitoh.hatenablog.com/
Submission: On June 16 via api from US — Scanned from JP
Submission: On June 16 via api from US — Scanned from JP
Form analysis
1 forms found in the DOMGET https://naitoh.hatenablog.com/search
<form class="search-form" role="search" action="https://naitoh.hatenablog.com/search" method="get">
<input type="text" name="q" class="search-module-input" value="" placeholder="記事を検索" required="">
<input type="submit" value="検索" class="search-module-button">
</form>
Text Content
@naitohの日記 読者になる @NAITOHの日記 2024-05-20 #RUBYKAIGI 2024 LTで「IMPROVED REXML XML PARSING PERFORMANCE USING STRINGSCANNER 」というタイトルで発表しました。 Ruby RubyKaigi 2024 LT で 6年振り にLT発表させて頂きました。 今回の内容は、おおよそ naitoh.hatenablog.com を5分に縮めた内容になります。 具体的には、下記になります。 * 自分が作成している RBPDF gem で SVG 画像(XMLで記述されています。)を処理したいので、XML処理ライブラリの中でインストールの容易な REXML を使いたい。 * REXML は C拡張の gem の libxml-ruby と比較して dom で65倍、sax でも 21倍遅いので、速くしたい。 * Ruby 3.3 で YJIT を有効にするだけで dom で65倍→44倍、sax で 21倍→14倍の性能差まで改善されるが、まだ遅いのでさらに改善したい。 * RubyKaigi 2019 の Better CSV processing with Ruby 2.6 で、StringScanner を用いって CSV gem を速くした話で REXML も速くしたいという話があった。 * REXML は Regexp クラスを用いて実装されているので、StringScanner で書き換えを実施すれば良いか検討。 * 単純なケースでは StringScanner は Regexp より 1.67 倍速い * StringScanner の処理手順(先頭文字列から順次処理)と Regexp の処理手順(複数一括マッチ)を考慮すると、性能の単純比較は無理だが、メモリの効率の観点から StringScanner の方が最適化され速そう。 * StringScanner への書き換えは下記の手順で実施。 1. ベンチマーク追加 2. プロファイラで最適化ポイントを調査し、XMLパース処理がボトルネックであることを確認 3. XMLパース処理をStringScannerで書き換え * StringScanner のバグ修正 * REXML の XML 仕様違反の修正 4. ベンチマークで効果を確認 5. 上記の繰り返し * 結果、下記まで性能改善することができた。 * YJIT無効状態で、dom: 65倍→60倍に短縮、sax: 21倍→17倍に短縮。 * YJIT有効状態で、dom: 44倍→25倍に短縮、sax: 14倍→8.6倍に短縮。🎉 speakerdeck.com ※ 資料で計測したコードは https://gist.github.com/naitoh/abc5134fdf37bb3952e36f1fb77163b0 になります。 (YJIT 無効時は、RubyVM::YJIT.enable の行をコメントアウトして計測。) Ruby 1.8.7 の頃の絶望的(300倍くらい?)なREXMLの遅さ から比較すると、同じオーダの性能差まで短縮できたので、用途によっては本番環境でも使えるのではないでしょうか。 今回のLTは無事、時間内に終わりましたが、緊張して声が震えてしまいました。いろんな場でLTして緊張しないようになりたいですね。 今年のRubyKaigi も楽しかったです。感謝! 内藤 (id:ju-na) 26日前 読者になる 広告を非表示にする * もっと読む コメントを書く 2024-02-25 RUBYKAIGI 2024 に出したCFP Ruby 久々にCFP出したけど通らなかったので公開します。 REXMLは Ruby 1.8.7 の頃に比べると本当に速くなってるし、YJITは Pure Ruby のライブラリにとってゲームチェンジャーだと思うんですよ。 ※ 実際に出したCFP は英語で記述しています。 TITLE REXMLのXML解析処理の改善 ABSTRACT REXML は Ruby で標準で使える XMLライブラリ(Bundled Gem)で、Ruby で実装されています。 Pure Ruby のためインストールし易い特徴があるのですが、逆に処理性能が遅いです。 今回、この REXML のパース処理を高速化したので、どのような手法を用いて実施したのかをお話しします。 DETAILS INTENDED AUDIENCE(対象読者) このトークは下記の方を対象に考えています。 * Pure Ruby でパース処理を書いてみたい人向け。 * インストールが容易なPure Ruby 環境でXMLを処理したい人向け * Ruby WASM 環境でXMLを処理したい人向け OUTCOMES(成果) REXML の XMLパース処理が正規表現(Regexp)で実装されているのを StringScanner (1) を用いたXMLパース処理に書き直し(2)、XML パース処理を最大 32%高速化(3)しました。 REXML と StringScanner の解説をまじえながら、私がどのような手法を用いてREXMLのXMLパース処理を高速化したのかを説明する事で、XMLの処理方法や StringScanner のパース処理方法を理解して欲しいと考えています。 1. https://docs.ruby-lang.org/ja/latest/class/StringScanner.html 2. PR * https://github.com/ruby/rexml/pull/105 * https://github.com/ruby/rexml/pull/106 * https://github.com/ruby/rexml/pull/107 * https://github.com/ruby/rexml/pull/108 * https://github.com/ruby/rexml/pull/109 3. https://github.com/ruby/rexml/actions/runs/7723085598/job/21052458823 ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-linux] Calculating ------------------------------------- rexml 3.2.6 master 3.2.6(YJIT) master(YJIT) dom 4.902 5.224 7.664 8.755 i/s - 100.000 times in 20.400673s 19.140694s 13.047998s 11.422036s sax 13.011 15.593 18.846 23.533 i/s - 100.000 times in 7.685622s 6.413001s 5.306133s 4.249434s pull 15.512 19.271 22.121 29.095 i/s - 100.000 times in 6.446480s 5.189123s 4.520615s 3.436964s stream 14.188 17.217 19.395 24.327 i/s - 100.000 times in 7.048419s 5.808095s 5.155877s 4.110616s Comparison: dom master(YJIT): 8.8 i/s 3.2.6(YJIT): 7.7 i/s - 1.14x slower master: 5.2 i/s - 1.68x slower rexml 3.2.6: 4.9 i/s - 1.79x slower sax master(YJIT): 23.5 i/s 3.2.6(YJIT): 18.8 i/s - 1.25x slower master: 15.6 i/s - 1.51x slower rexml 3.2.6: 13.0 i/s - 1.81x slower pull master(YJIT): 29.1 i/s 3.2.6(YJIT): 22.1 i/s - 1.32x slower master: 19.3 i/s - 1.51x slower rexml 3.2.6: 15.5 i/s - 1.88x slower stream master(YJIT): 24.3 i/s 3.2.6(YJIT): 19.4 i/s - 1.25x slower master: 17.2 i/s - 1.41x slower rexml 3.2.6: 14.2 i/s - 1.71x slower OUTLINES(概要) 1. 最初にXMLの概要とXMLの処理方式(DOM, SAX)の違いを説明します。 2. REXML の処理性能を他のRuby C拡張 gem と比較しながら現状の処理速度を説明します。 3. 文字列スキャナである StringScanner の使い方の説明をします。 4. 処理速度を改善するために行った事(ベンチマークの整備、プロファイラを用いたボトルネックの確認、StringScannerのバグ修正等、StringScannerを用いた処理の書き換え)を説明します。 5. まとめ PITCH EXPLAIN WHY THIS TALK SHOULD BE CONSIDERED (この講演を考慮すべき理由) Python や PHP などと比較して、Ruby の標準 XML パーサーが遅いのが気になっていました。 Ruby 1.8.7 の記事ですが、1万行程度のXMLの(DOM)パース処理 で C拡張gem の libxml-ruby と比較して数桁遅く、本番環境では使い物にならない状況でした。 https://suer.hatenablog.com/entry/20110126/xml_parse この当時と比較して、Ruby の高速化、YJIT による高速化、REXML 自身の高速化などにより状況が改善されつつあるため、Pure Ruby 実装である REXML を再評価できればと考えています。 WHAT MAKES YOU QUALIFIED TO SPEAK ON THE TOPIC. (このテーマを話す資格がある理由) 仕事(SMI-S XML, PubMed XML)やプライベート(SVG)でXMLを処理する事が多く、複数の種類のXMLファイルを処理した経験があります。 また、nokogiri, ox, REXML と複数の XMLパーサーを使用した経験があり、今回 REXML のパース処理をStringScannerを用い高速化できた事で、REXML や StringScanner について解説できると考えています。 1. Storage Management Initiative Specification (SMI-S) 2. https://www.nlm.nih.gov/bsd/licensee/data_elements_doc.html 3. https://developer.mozilla.org/en-US/docs/Web/SVG SPOKEN LANGUAGE IN YOUR TALK 日本語 内藤 (id:ju-na) 112日前 読者になる 広告を非表示にする * もっと読む コメントを書く 2019-06-01 RUBY 2.6 の新機能の ENDLESS RANGE と RANGE#% を NUMO::NARRAY と CUMO で対応しました。 Ruby 自分が参加している Red Data Tools の Element で @mrkn さんから、 > ArithmeticSequence と Range から begin, end, step, exclude_end を取り出す C API を > trunk に追加しました。 ruby/ruby@914a290 だれか、これを使って NArray などの slicing > に対応するプルリクエストを作ってみませんか? という提案を頂いたので、 Numo::NArray と Cumo (※ Numo::NArray のGPU 版)で 上記 C API を使用して Ruby 2.6 の新機能の endless range と Range#% に対応を実施しました。 endless range とは、下記のように 末端の "-1" 指摘を省略できる書き方です。 また、step の alias として % を使用できると、より直感的に書く事ができます。 * Ruby 2.5 > a = [0, 1, 2, 3, 4] => [0, 1, 2, 3, 4] > a[1..-1] => [1, 2, 3, 4] > a[1...-1] => [1, 2, 3] > (1..4).to_a => [1, 2, 3, 4] > (1..4).step(2).to_a => [1, 3] * Ruby 2.6 (endless range, Range#%) > a = [0, 1, 2, 3, 4] => [0, 1, 2, 3, 4] > a[1..] => [1, 2, 3, 4] > a[1...] => [1, 2, 3, 4] > (1..4).to_a => [1, 2, 3, 4] > ((1..4) % 2).to_a => [1, 3] このように便利な記法が Numo::NArray や Cumo でも使えると嬉しいので、Ruby 2.6 の環境で同様に書けるように対応しました。 * Numo::NArray > require 'numo/narray' > a = Numo::Int32.new(5).seq => Numo::Int32#shape=[5] [0, 1, 2, 3, 4] > a[1..] => Numo::Int32(view)#shape=[4] [1, 2, 3, 4] > a[1...] => Numo::Int32(view)#shape=[4] [1, 2, 3, 4] > a[(1..) % 2] => Numo::Int32(view)#shape=[2] [1, 3] * Cumo > require 'cumo' > a = Cumo::Int32.new(5).seq => Cumo::Int32#shape=[5] [0, 1, 2, 3, 4] > a[1..] => Cumo::Int32(view)#shape=[4] [1, 2, 3, 4] > a[1...] => Cumo::Int32(view)#shape=[4] [1, 2, 3, 4] > a[(1..) % 2] => Cumo::Int32(view)#shape=[2] [1, 3] numo-narray の endless range、Range#%の PR は master に 取り込まれている ので次のリリース(0.9.1.5以降?)で使用可能になると思われます。 cumo は リリース版ですでに 取り込まれている ので 0.2.5 以降で使用可能です。 Ruby 本体側でデータサイエンス向けの機能が取り込まれていくと、データサイエンス用ライブラリ側も便利になっていきますので嬉しいですよね。 内藤 (id:ju-na) 5年前 読者になる 広告を非表示にする * もっと読む コメントを書く 2018-12-13 REDMINEのPDF出力機能で使われているRBPDF GEM ライブラリについて Redmine Ruby (この記事は Redmine Advent Calendar 2018 - Adventar の13日目の記事です。) Redmine の PDF 出力機能で使われている 私が作成した RBPDF gem ライブラリについてのお話です。 github.com RBPDF は下記のような特徴があります。 * Pure Ruby * HTMLからのPDF変換対応 (CSS 一部サポート) * PNG/JPEG/GIF形式画像のPDF出力対応 (8bit PNG画像以外は RMagick が必要です。) * CJKV(中国語・日本語・朝鮮語・ベトナム語) 対応 * 組み込みサブセットFont対応 * アラビア語などのRTL (Right-To-Left) 言語サポート * 目次・しおり ※PDFへのリンクです。 * 図形 ※PDFへのリンクです。 * 円グラフ ※PDFへのリンクです。 実際にどのような事ができるかは Examples をご覧下さい。 なお、RBPDFは一から作成したものではなくPHPのPDF出力ライブラリTCPDFを、Redmineで使用するために Ruby に移植したものになります。 REDMINE の PDF出力機能の歴史 RBPDFを作成することになった経緯を Redmine の PDF出力機能の歴史と合わせてお話しします。 Redmine の PDF出力機能は 1.0 の頃は FPDF という PHPのライブラリを Ruby に移植した RFPDF が使われていました。 このころは日本語が文字化けするなど多くの問題を抱えていましたが、Defect #61: Broken character encoding in pdf export - Redmine のチケットで edwinmoss さんが開発された 同じくPHP由来のTCPDFベースの RFPDF に置き換え & 修正作業を行うことで無事、Redmine 1.2 で CJK(日本・韓国・中国語)と多くの言語の文字化けが解決しました。 github.com なお、これが私のRedmine での初の採用パッチになります。 詳細は、第2回勉強会 - redmine.tokyo (当時は shinagawa.redmine)で LTをさせて頂きました。 naitoh.hatenablog.com RFPDF(TCPDFベース)の機能で画像出力や(Textileから変換された)HTMLの変換などにも対応可能な事がわかったので、Redmine 1.3 で Textileによる書式設定 Feature #69: Textilized description in PDF - Redmine や画像出力 Feature #3261: support attachment images in PDF export - Redmine の対応を実施しました。 ただ、この対応時に多くの課題が見えてきたので、抜本的に解決を図るため edwinmoss さんから RFPDF の開発を引き継ぎ、ベースのTCPDFのバージョンを5.2まで上げる形でPHPからRubyへ移植を実施、RBPDF 1.18 として gem を作成しました。 これは Redmine 2.6 の PDFエクスポートの改善として取り込まれました。 TCPDFをベースとしてgem パッケージを開発した理由は下記になります。 * Redmine コミッターの @marutosijp さんから、PDF出力機能は複雑なので Redmine 本体から分離したいと伺っていた。 * Redmine にパッチが採用されるためにはWindows/Linux OS環境で動作しなければならない。 * Redmine のインストールは Rails アプリを配布する形式であるため Pure Ruby であればインストール(環境構築)のハードルを上げないため、採用される可能性がある。 * Ruby で HTML対応の PDF出力ライブラリで実用的なものは PDFKit ベースのライブラリがいくつかあったが WebKit に依存しているため採用されそうになかった。 * Redmine のライセンス(GPL2)と互換のあるLGPL 2.1ライセンスのTCPDF 5.2(PHP)をRubyに移植できれば、RTL言語対応や埋め込みフォント対応、HTMLサポートの改善などが見込める。 * Redmine を PHP に移植した CandyCane があるなら、その逆も可能と思った。 詳細は、LTthon | RubyHiroba 2014で発表させて頂きました。 Rbpdf gem library from Jun Naitoh www.slideshare.net その後、RBPDF 1.19 で埋め込みサブセットフォントをサポートし、Defect #19017: Wiki PDF Export: <pre> not rendered with monospaced font - Redmine で Redmine 3.2 で取り込まれCJK 以外の言語の PDFファイルで発生していた(対象言語の全フォント埋め込みによる)肥大化問題が解決されました。 これで自分の当初のゴールとしていた内容の対応は完了しました。 REDMINE の PDF出力機能で改善されるといいなと思っている点 PDF出力機能の基盤部分の改善は実施しましたが、使い勝手の部分では時間が取れず手が回っていないのですが、今後、下記が改善されるといいなと思いっています。 * Feature #6851: Change PDF page size - Redmine * Feature #13576: Setup page orientation for PDF export - Redmine * PDF出力は、現状A4サイズ固定ですが、A3とかになればチケット一覧が見やすくなります。 * Defect #19133: PDF Export loses {{toc}} - Redmine * しおりつけたいですね。 * Feature #11998: PDF export svg support - Redmine * RBPDF 側の対応が必要ですがSVGがサポートできれば、ガントチャートの残念なPDF出力が改善しやすくなると思っています。 以上です。 内藤 (id:ju-na) 5年前 読者になる 広告を非表示にする * もっと読む コメントを書く 2018-11-18 #RUBYDATA_TOKYO MEETUPで「USABILITY OF NUMO::NARRAY IN NUMERICAL COMPUTING OF RUBY.」というタイトルで発表してきました Ruby speee.connpass.com 上記のRubyData Tokyo Meetup で「Usability of Numo::NArray in Numerical Computing of Ruby.」というタイトルで発表してきました 発表資料は下記になります。 RubyData Tokyo Meetup 2018 naitoh from Jun Naitoh www.slideshare.net Red Chainer の開発中に気づいた Numo::NArray のわかりにくかった所や、Numo::NArray に対して自分が取り組んだ、Inplace/Broadcast性能改善、SIMD演算対応、dot(transpose)性能改善 などを踏まえ、現在の計算速度の改善状況などをお話しました。 自分でも驚きだったのが、ベンチマークの結果、 加算と減算 (Inplace計算は除く)は Numo::Narrayの方が numpy より計算が速い という事ですね。 資料中のベンチマークのコードと結果は下記にあります。 Numo::NArray vs numpy performance. (CentOS 7(x64) Ruby 2.5.3 Numo::NArray 0.9.1.3, Python 3.6.5 numpy 1.15.4) · GitHub ※ Deep Learning From Scratch 部分の測定内容(p26,p27)は資料中のURLを参照ください。 Numo::NArray の使い方で自分が理解できていなかったところが、今回の発表で整理できてスッキリしたので Red Chainer の開発に生かしていきたいと思います。 内藤 (id:ju-na) 5年前 読者になる 広告を非表示にする * もっと読む コメントを書く 2018-07-14 CENTOS7(X86_64) で WINDOWS版 NUMO-NARRAY (X86-MINGW32/X64-MINGW32)を BUILD する場合の手順 numo-narray の Windows 版は linux でクロスコンパイルし、そのまま配布する fat gem の作成が可能なのですが、 ただ、その方法でハマったので対処方法のメモです。 具体的には numo-narray の Windows 向けビルドで rake-compiler.gem, rake-compiler-dock.gem を使うようになっているのですが、 docker コマンドの操作に root権限が必要なため、sudo 経由で rbenv を実行しないと docker コマンドの操作でdocker グループにユーザーを追加しておかないと、docker のステータスを認識できずに処理が止まります。 rake-compiler/rake-compiler-dock の詳細は下記参照。 * Windows用バイナリGemをMacでクロスコンパイルする * Ruby 1.8.7/1.9.1どちらでも使えるWindows用バイナリ入りgemをDebian GNU/Linux上で作る方法 - ククログ(2010-04-21) 主な作業 * ruby 2.1 以上を rbenv でインストール (手順は割愛) * ここでハマったのですが、自分はホームディレクトリに rbenv を入れていたため sudo 実行時 rbenv コマンドを認識できませんでした。 * 今回のケースはシステム側に rbenv をインストールした方がいいと思います。(未確認) * sudo の secure_path 変更 $ sudo visudo 修正前 Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin * 修正後 Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/rbenv/bin:/usr/local/rbenv/shims:/home/ユーザー名/.rbenv/bin:/home/ユーザー名/.rbenv/shims /home/ユーザー名/.rbenv/bin:/home/ユーザー名/.rbenv/shims の部分は、gem env コマンドで SHELL PATHを確認。 * システム側に rbenv をインストールした場合は /home/ユーザー名/.rbenv/bin:/home/ユーザー名/.rbenv/shims 部分は不要なはず。 * Docker インストール & グループ追加 & 起動 & 一旦ログアウトして反映。 $ sudo yum install docker $ sudo groupadd docker $ sudo gpasswd -a $USER docker $ sudo systemctl start docker $ exit * Docker のサービス確認。 $ sudo systemctl status docker.service Docker のサービスがactive なのを確認する。 * Docker コマンド動作確認。 $ docker ps sudo なしに実行してエラーしないことを確認。 * gem インストール $ gem install rake-compiler $ gem install rake-compiler-dock * numo-narray を git clone $ git clone https://github.com/ruby-numo/numo-narray.git $ cd numo-narray sudo 経由で rake コマンドが動作することを確認。 * Windowsビルド 管理者権限でビルドを行います。(ここでハマっていた。) docker グループに入って入れば管理者権限は不要です。 $ rake build:windows ビルドが完了し、pkg 配下に numo-narray-x.x.x.x-x86-mingw32.gem, numo-narray-x.x.x.x-x64-mingw32.gem が作られたら成功。 追記 先ほど、@sonots さんから、docker グループに追加すべきとコメント頂き、sudo は不要でしたので記事を修正しました。手順がスッキリしました。ありがとうございます。 内藤 (id:ju-na) 5年前 読者になる 広告を非表示にする * もっと読む コメントを書く 2018-07-11 NUMO-NARRAY と BENCHMARK_DRIVER.GEM Ruby @watson1978 さんの blog で Mac 環境だと Linux 環境に比べて numo-narray が遅いというお話があったので調べてみました。 watson.hatenablog.com 今回の比較では、先日の Rubyアソシエーション開発助成成果報告会 で発表されていた www.ruby.or.jp @k0kubun さんの benchmark_driver.gem を使いました。 このベンチマークは、複数の Ruby バージョン間の比較や、同一 gem で複数のバージョン比較ができるという優れものです。 使い方は $ gem install benchmark_driver でインストールするだけです。 (rbenv を使用している場合、$ rbenv rehash で benchmark-driver コマンドを使用可能にする必要があります。) グラフ画像を出力する場合は $ gem install benchmark_driver-output-gruff で追加の plugin をインストールします。 (要 RMagick) 確認環境 * CentOS 7.3(x86_64) / macOS Sierra(x86_64) * Ruby 2.5.1 * benchmark_driver (0.14.3) * benchmark_driver-output-gruff (0.3.1) * numo-narray (0.9.1.2) * numo-narray (0.9.9.0) ※ numo-narray の master の2018/7/11時点の最新 (inplace 演算と ブロードキャスト演算時の省メモリによる高速化対応版)を gem pkg にしたもの。 ベンチマーク内容 @watson1978 さんのベンチマーク結果をベースに inplace 演算と ブロードキャスト演算を加えて比較してみました。 $ cat numo_N_fp.yaml contexts: - gems: { numo-narray: 0.9.1.2 } require: false prelude: require 'numo/narray' - gems: { numo-narray: 0.9.9.0 } require: false prelude: require 'numo/narray' loop_count: 10000 prelude: | N = 100000 xd = Numo::DFloat.new(N).seq yd = Numo::DFloat.new(N).seq xs = Numo::SFloat.new(N).seq ys = Numo::SFloat.new(N).seq benchmark: '[100000] + [100000] (fp64)' : xd + yd '[100000] + [100000] (fp32)' : xs + ys '[100000].inplace + [100000] (fp64)': xd.inplace + yd '[100000].inplace + [100000] (fp32)': xs.inplace + ys '[100000] + 1 (fp64)' : xd + 1 '[100000] + 1 (fp32)' : xs + 1 '[100000].inplace + 1 (fp64)' : xd.inplace + 1 '[100000].inplace + 1 (fp32)' : xs.inplace + 1 * inplace 演算は指定した変数のメモリ領域を書き換える形で演算するため、結果的に省メモリになります。0.9.9.0(省メモリによる高速化版)で省メモリ化しています。 * ブロードキャスト演算は指定した変数を全要素に対して同じ計算(上記の場合は+1)をします。0.9.9.0(省メモリによる高速化版)で省メモリ化しています。 上記を下記のように実行します。 * $ benchmark-driver numo_N_fp.yaml --output markdown (Markdown 出力) * $ benchmark-driver numo_N_fp.yaml --output gruff (PNG出力) CENTOS / MACOS の結果 (グラフ) CentOS (左) / macOS (右) の結果 * 1秒間あたりの処理数 (i/s)なので、数値が大きい方が速いことを意味します。 * 非inplace の場合、Linux と比較してMac は 3〜4倍遅い。 * 通常演算(非inplace & 非broadcast)から inplaceやbroadcastに変更した場合、Linuxは1.5〜2倍速くなりますが、Macは4〜11倍速くなりLinuxより速い。 * サンプルソースを作成してアセンブラ出力を確認したところ、Mac はコンパイラ(Clang)が自動ベクトル(SIMD)化している。 * Linux の場合、DFloat → SFloat or inplace & broadcast 改善版(0.9.9.0) で、省メモリになりキャッシュに乗ることで高速化。 * Mac の場合、inplace & broadcast 改善版(0.9.9.0) で、省メモリになりキャッシュに乗りSIMDが効果を発揮することで劇的に高速化。 * SIMDでは変数をまとめて演算するため、DFloat(8Byte)×2個=16Byte → SFloat(4Byte)×4個=16Byte となりメモリサイズは同一。(省メモリにはならない。) CENTOS 7 の結果 (数値) (※グラフ化とは別に再測定実施。) numo-narray 0.9.1.2 numo-narray 0.9.9.0 [100000] + [100000] (fp64) 7.150k 7.040k [100000] + [100000] (fp32) 12.768k 12.692k [100000].inplace + [100000] (fp64) 12.161k 11.572k [100000].inplace + [100000] (fp32) 17.069k 22.032k [100000] + 1 (fp64) 7.936k 8.045k [100000] + 1 (fp32) 9.273k 12.697k [100000].inplace + 1 (fp64) 11.570k 14.160k [100000].inplace + 1 (fp32) 12.875k 27.566k MACOS SIERRA の結果 (数値) (※グラフ化とは別に再測定実施。) numo-narray 0.9.1.2 numo-narray 0.9.9.0 (master) [100000] + [100000] (fp64) 1.897k 1.829k [100000] + [100000] (fp32) 3.867k 3.753k [100000].inplace + [100000] (fp64) 12.431k 15.041k [100000].inplace + [100000] (fp32) 17.005k 29.455k [100000] + 1 (fp64) 2.093k 2.126k [100000] + 1 (fp32) 3.664k 4.101k [100000].inplace + 1 (fp64) 13.843k 23.250k [100000].inplace + 1 (fp32) 14.338k 44.210k 以上より、 * Numo::NArrayが Mac で遅いケースがあるが自動ベクトル(SIMD)化とキャッシュの乗り方に起因する現象のように思われる。 * 可能なら inplace を使いましょう。 というところでしょうか。 四則演算のベンチマーク (おまけ) ついでに、RubyKaigi 2018 LT のベンチマーク結果を、非 inplace のケースも含めてbenchmark_driver.gem でベンチマーク化してみました。 ベンチマーク内容 $ cat broadcast_fp32.yaml contexts: - gems: { numo-narray: 0.9.1.2 } require: false prelude: require 'numo/narray' - gems: { numo-narray: 0.9.9.0 } require: false prelude: require 'numo/narray' loop_count: 5000 prelude: | x = Numo::SFloat.ones([1000,784]) y = Numo::SFloat.ones([1000,784]) z = Numo::SFloat.ones([1000,1]) benchmark: '[1000,784] + [1000,784]': x + y '[1000,784].inplace + [1000,784]': x.inplace + y '[1000,784] + [1000,1] ': x + z '[1000,784].inplace + [1000,1] ': x.inplace + z '[1000,784] + 1 ': x + 1 '[1000,784].inplace + 1 ': x.inplace + 1 '[1000,784] - [1000,784]': x - y '[1000,784].inplace - [1000,784]': x.inplace - y '[1000,784] - [1000,1] ': x - z '[1000,784].inplace - [1000,1] ': x.inplace - z '[1000,784] - 1 ': x - 1 '[1000,784].inplace - 1 ': x.inplace - 1 '[1000,784] * [1000,784]': x * y '[1000,784].inplace * [1000,784]': x.inplace * y '[1000,784] * [1000,1] ': x * z '[1000,784].inplace * [1000,1] ': x.inplace * z '[1000,784] * 1 ': x * 1 '[1000,784].inplace * 1 ': x.inplace * 1 '[1000,784] / [1000,784]': x / y '[1000,784].inplace / [1000,784]': x.inplace / y '[1000,784] / [1000,1] ': x / z '[1000,784].inplace / [1000,1] ': x.inplace / z '[1000,784] / 1 ': x / 1 '[1000,784].inplace / 1 ': x.inplace / 1 確認結果 CentOS (左) / macOS (右) の四則演算結果 0.9.9.0(inplace 演算と ブロードキャスト演算時の省メモリによる高速化対応版)の改善効果がよくわかります。 同一gem で複数のバージョン比較ができる benchmark_driver.gem は便利ですね。 内藤 (id:ju-na) 5年前 読者になる 広告を非表示にする * もっと読む コメントを書く 次のページ プロフィール 内藤 (id:ju-na) 読者です 読者をやめる 読者になる 読者になる 11 このブログについて 検索 リンク * はてなブログ * ブログをはじめる * 週刊はてなブログ * はてなブログPro 最新記事 * #RubyKaigi 2024 LTで「Improved REXML XML parsing performance using StringScanner 」というタイトルで発表しました。 * RubyKaigi 2024 に出したCFP * Ruby 2.6 の新機能の endless range と Range#% を Numo::NArray と Cumo で対応しました。 * Redmineのpdf出力機能で使われているRBPDF gem ライブラリについて * #RubyData_tokyo Meetupで「Usability of Numo::NArray in Numerical Computing of Ruby.」というタイトルで発表してきました 月別アーカイブ * ▼ ▶ 2024 (2) * 2024 / 5 (1) * 2024 / 2 (1) * ▼ ▶ 2019 (1) * 2019 / 6 (1) * ▼ ▶ 2018 (8) * 2018 / 12 (1) * 2018 / 11 (1) * 2018 / 7 (2) * 2018 / 6 (2) * 2018 / 5 (1) * 2018 / 1 (1) * ▼ ▶ 2017 (1) * 2017 / 8 (1) * ▼ ▶ 2014 (4) * 2014 / 2 (4) * ▼ ▶ 2012 (3) * 2012 / 8 (1) * 2012 / 3 (1) * 2012 / 1 (1) * ▼ ▶ 2011 (4) * 2011 / 12 (2) * 2011 / 7 (2) @naitohの日記 Powered by Hatena Blog | ブログを報告する 引用をストックしました ストック一覧を見る 閉じる 引用するにはまずログインしてください ログイン 閉じる 引用をストックできませんでした。再度お試しください 閉じる 限定公開記事のため引用できません。 読者です 読者をやめる 読者になる 読者になる 11