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

Form analysis 1 forms found in the DOM

GET 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