リンクフリーを近日中にとりやめる予定です

すでにリンクを貼っていただいている方、ご一報頂きたくお願い申し上げます。


ごく少数ですが、リンクをお断りする場合があります



ブログ内 風景光景カテゴリー

続編記事などをご希望の方は こちらへどうぞ

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

[未掲載分] 車輪の再発明 (11)

元来、好ましい意味で用いられない「車輪の再発明」。



筆者は、そのような行為を肯定的に捉えている。
なぜならば、新しい技術や文化が芽生えるきっかけは、一見無駄と思われることへの挑戦である・・・


お知らせ
活動休止にともない、この記事を事前に予約投稿してあります。
トップ記事の固定を目的としています


この題目は2012年暮れ頃に掲載しようと下書きし、諸事情により掲載却下とした分です。
前話、車輪の再発明 (10)にひきつづき、利用環境を OS はWindows , CPU は Intel 製、いわゆるウィンテル機を前提に綴ります。

この種のお題、鋭いヒトを対象に限定して綴るならば1話簡潔型に進めることも可能。・・・当ブログにたびたびお越しいただいたブロガーさんの中で、プログラミング技術の向上を目指している方々もちらほらと。中でも、学生の方々、学業の合間をみて、向上しようという意欲に心を動かされた・・・というのがこのお題の発端である。
さらに、この題目のきっかけとなったブロガーさんを見るかぎり、「まだ実戦ではなく、C/C++ 言語の習得に奮闘している段階」とのこと。たしかに、不慣れなヒトがつまづきそうな点は多々あり、ひとつひとつ綴ってゆくとかなりの分量となる。どこまでも綴るのは不可能なので、今回をもって一応のピリオドとしたい。

さてさて、Visual Studio を起動してからここまで小一時間。
「高速化のために改良したい」と考えるのは結構なことだが、それに膨大な時間を費したのでは本末転倒。
そもそも、記事にまとめるコト自体が時間のロスと言われそう・・・

環境など
OS は Windows 7 x64、CPU は Core i3 3220T、メモリは DDR3-1333 8GB (4GB 2枚) を搭載した PC 。アプリの作成に関しては、C/C++ 言語、Visual Studio 2008 を用いて x64 向けにビルドした。

筆者がこれを下書きしたのは2012 年暮れのこと。店頭に並んでいる PC を見るかぎり、Intel 製の CPU は「第 3世代 Intel Coreプロセッサー」( 通称 Ivy Bridge ) が一般的であった。なかでも、筆者が所有していた CPU は Core i7-3770 、同 3770T と i3-3220 、同 3220 T 。キャッシュやターボブーストが効かないほうが中立的な結果をえられると考え、i3-3220T を選択した。

車輪の再発明 (6)の終盤で触れたように、結果がバラつく要因を減らしたい。よって、OS を再起動後、省電力状態に突入しない段階で速度を測った。ひとつのパターンにつき10回行った平均値とした。また、極端に値が偏った場合は除いた。

結果を画像として載せる。多少見辛いかもしれない。結果を一覧表としてアップしたほうが読み易い。
以前、別のテーマにて細かい件を綴ったことがあった。結果として、筆者の許可なく転用され、悪用された。
誰しもピックアップされることは嬉しい。反面、濫りに用いられるのは不愉快でもある・・・



右側の列はパターン、手法などを記した。左側の列、縦方向は要した時間。単位はミリ秒。1000 ミリ秒で1秒。
要した時間の中には、残り回数の減算とゼロ確認、ポインタを加算、繰り返しの先頭へのジャンプが含まれている。
ロード、ストア部だけの純粋な数値ではないことに用心いただきたい。

コード等は車輪の再発明 (9)

1番目は OS に備っているメモリ転送関数を呼び出すパターン。
2番目以降は 32 ビット幅や 64 ビット幅の汎用レジスタにロードされた値がストアされる命令が生成されるように手を加えたパターン。

なお、アプリをビルドするにあたり、ターゲットを x64 (64ビット版向け)に設定している。車輪の再発明 (9)で触れた通り、32ビット版をターゲットにビルドした場合、32ビット幅を持つレジスタへのロード、ストアを2回行うように翻訳されてしまう。

汎用レジスタにロードされた値がストアされる命令が生成されたことをアセンブリ言語で出力されたファイルで確認した。アセンブリファイルを出力する方法については車輪の再発明 (7)で触れた。

ほか、ループ ( 繰り返し ) 部を
・特定の回数に達するまで繰り返す
・残りがゼロになるまで繰り返す
と変えたり、複数の汎用レジスタを用いてのロード、ストアを試みた。

ループ数の大小、つまり「何回繰り返すか?」といった部分の差は車輪の再発明 (10)で触れたように、「複数の実行ユニット」で分散する仕組みにより吸収されているようだ。
ストアと並行して残り回数の減算や確認を行っていると推測できる。

この段階で論じるならば、高速化を期待して手を加えたにも関わらず、遅くなるパターンも見受けられる。
ゆえに、OS に標準で備わっているメモリ管理系の関数や古典的な関数を用いるのが無難。

たしかに、昨今でも
「関数呼び出しはオーバーヘッドのため遅くなる。」
等の文言が唱えられている。
オーバーヘッドという表現が難しいだろうか。スポーツの分野では宙返りしながら空中のボールを蹴るコトを指したり、音を楽しむ場ではヘッドフォンを指す。ここでは、ある関数を呼び出す、その中から別の関数を呼び出すこと意図している。
例えば、実生活の場において何らか作業を依頼する場合、元請け・下請け・孫請け・ひ孫請け・やしゃご請け ~~ といった事態に陥ることがある。
依頼者からみれば、丸投げ、中抜きされた分だけ余分なコストが生じる。もし、作業にあたるヒトに直接頼むことができれば「余分なコスト」を省ける。「余分なコストを省きたい」と考えるのは自然なことである。

多段に渡る呼び出しはオーバーヘッド、つまり余分な手間、コストがかかると考えられている。
今回測った数値をみるかぎり、
関数呼び出しに要する余分なコストを差し引いてもOS に備わっているメモリ管理系の関数や古典的な関数速くなることを期待して手を加えたつもりコードとの差は微々たるもの。

次に、SSE2 命令を使うように手を加えた諸々のパターン。


コード等は車輪の再発明 (10)

1番目と2番目はロード、ストアの対象アドレスが16バイトの倍数でなくともエラーが生じないように、C/C++ 言語の組み込み関数として _mm_loadu_si128_mm_storeu_si128を用いた。
16バイトの整列、非整列に関しては車輪の再発明 (8)で触れた。
コンパイル時に出力されたアセンブリ言語のファイルを確認すれば ロードとストアの部分が MOVDQU

1番目のパターンはひとつの XMM レジスタでロード、ストアを繰り返す。
2番目は4本の XMM レジスタを用いてロード、ストアと変更した。繰り返し回数は 1/4に減る。

3番目は ロード、ストア に _mm_load_si128_mm_store_si128を用いた。
アセンブリ言語で出力されたファイルを確認すると、ロードとストアが MOVDQU から MOVDQA に変わる。

4番目、5番目 はストアをキャッシュを介さないように変更。_mm_store_si128の部分を _mm_stream_si128に変更した。
アセンブリ言語でのロードとストアが MOVDQA から MOVNTDQA に変わる。
4番目は4本の XMM レジスタを使うのに対し、5番目は8本の XMM レジスタを使う。

把握し辛いかもしれないので、簡単な棒グラフで示す。





SSE2 を使うように手を加えた段階でも、パターン1からパターン3は、SSE2 命令を使わないパターンや古典的な関数を用いた場合と大差ないように見える。
アドレスが16バイトに揃った状況ゆえに、MOVDQU と MOVDQA どちらも似通った結果が出た。
明らかに向上したのはパターン4とパターン5で、これらはストアをキャッシュを介さないに変更した効果と考えてよさそうだ。
ちなみに、車輪の再発明 (9)で触れたように、SSE4.1 以降では ロードに関してもキャッシュを介さない命令が加わっている。
※ SSE4.1 の命令が使えるのは 第2世代 の Core2 Duo , Core2 Quad 以降。

局所的に使う XMM レジスタの本数を増やす効果はどうだろう。
1本から4本に増やした場合、わずかながら効果があるようだ。一方、4本から8本に増やしても効果が無いようだ。
これは伝送路、通路や廊下が詰まってしまい効果が得られないと考えられる。むしろ、混雑により待たされるかもしれない。混んでいる間に別のコトを進める方が有利ということだ・・・

効果はいかに!?

OS に備わっている CopyMemory 関数を使う場合と手を加えた場合の差は 35 から 38 %。
この数字を見るかぎり、細工により高速化したかという面で疑問・・・



筆者は以前も同じような試みをした。Pentium 4 が全盛の頃、Core 2 Quad / Core 2 Duo が登場した頃、そして今回。

Pentium 4 が全盛の頃、ストリーミング・ストアとソフトウェア・プリフェッチをうまく組み合わせることで4倍から5倍、もしくは、それ以上の高速化を見込めた。
結果を図表に載せていないが、今回もストリーミング・ストアとソフトウェア・プリフェッチの組み合わせも試した。しかし、大幅な速度向上とはならなかった。むしろ、プリフェッチ命令が挿入された分、遅れるようにも感じる。
もしかすると、筆者の組み方が悪いのかもしれない・・・

違う視点から考えてみよう。
「Pentium 4 の頃と比べ相対的な数値が伸びなかった」
という点は否めない。一方、同じクロックの CPU として比べれば
「絶対的な数値は大幅に向上している」と解釈できる。

Pentium 4 ( Prescott 世代 ) と同じクロックの Core i3-3220 ( Ivy Bridge 世代 ) で同じベンチマークテストを行ってみた。
おおむね、メモリ操作を中心としたもので 3.5 倍、シングルスレッドの演算で約 3 倍、マルチスレッドでは 6 倍から8 倍ほどの差が出た。
大雑把に言えば基礎体力が違う。別の言い方をすれば、フットワークが軽くなっている。

フットワークの差を単純に3倍と捉えて考えてみよう。
不慣れな作業員とベテランの作業員がいるとして、同じ時間でこなせる仕事量が3倍違うと仮定する。
前者に、もともと60分かかる作業を任されたとする。本気で挑み15分で終わるようになると、かなり短縮されたと実感できる。本気で作業するにあたり、細々と指示が与えられた。
一方、後者は基礎的な力が3倍。ということは要する時間が1/3。前者が60分かかる作業、細々と指示を与えずとも20分で完了するだろうと期待される。こちらも本気で挑むとして、作業時間が20分から15分や10分と短くなったとしよう。相対的な評価となれば「かなり短縮された」とは扱われないものだ。
とはいえ、無限に短縮できるものではない。どのような分野でも超えられないカベがある。
要は伸び代がある、ない。この例で、不慣れな作業員は伸び代があるに対しベテランの作業員は伸び代がないと言える。

技術競争が活発な分野では、現状の弱点を克服しようと常に改良・改善が施される。また、新しい技法も編み出される・・・

アプリ作成、とりわけ速度に話を絞ろう。
旧来はソフトウェアレベルで人間があれこれ指示する必要があった。やがて、ハードウェアレベルで進化したことにより、細々と指示が与えなくともよくなった。
と言える。たしかに、
「現時点で遅いから何とかしたい」という希望を抱くのは良いことだ。
もちろん、ハードウェアレベルでの改良作業に携わっているならば・・・
しかし、ソフトウェアレベル、というよりアプリを組む側ならば
「現在の弱点は将来、機材の進化で解消されるかもしれない。」
と割り切って考えるべきだろう。

実際、永く続いているアプリはいくつものバージョンがリリースされてきた。機材の世代に応じた最適化が施されてきた。偏った最適化の弊害として、機材の世代によっては能力を発揮できないかもしれない。
商用としては、それも一理ある。新世代向けの新製品をリリースすれば、消費者の購買意欲を高めることができるであろう。

仮に、アプリ作成に不慣れな段階であっても、「最適化」や「高速化」に興味を持つのは多いに結構。それらを扱った文献も多い。しかし、優先すべき課題は、完走すること。ゴールまでたどり着くことだ。
ゴールと表現しているのは、アプリ、つまり作品を完成させることではない。
「実行中に暴走したり、リタイヤするような、残念なアプリを組まない」ことを目標に進むべきではないか・・・

ここから先、載せるべきか迷った。この題目のきっかけとなったブロガーさんは、2012年暮れの段階で Windows XP を利用しているとのこと。「32ビット版 のプラットフォームを利用しているヒトはまだまだいる」との判断から載せることにする。あくまでも参考程度・・・

プラットフォームを x86 、つまり 32ビット版の Windows 向けに切り替えた結果は以下の通り。



ほぼ、64ビット版のプラットフォームで試した際と同じ傾向であった。興味深い点もちらほらと。

まず、MOVSD を用いた場合の結果は 478。車輪の再発明 (9)の終盤で触れたように MOVSD は複数の意味があり、ここでは Move data from String to string 「ストリングの移動」を指す。
32ビット版の CopyMemory 関数を呼び出す場合より遅くならない、というより 15% ほど速い

PC の中ではデータの移動やコピーは頻繁に行われる。これが短縮されることは大多数のヒトにとってメリットである。
かつては、メモリ間コピーを高速化しようとさまざまな技法が提唱、編み出されてきた。なかには、頭の体操というレベルを超え、アクロバティックな技法も存在した。
逆に言えば、メモリ間コピーが速ければこの種の試みは避けられていただろう。同様に筆者もMOVSD や MOVSB , MOVSW は速くないと思い込んでいた。昨今、MOVSD を用いても遅くならないようにハードウェアレベルで進化したと解釈できる。

ほかにも、32ビット版 に限られてしまう手法としては MMX レジスタを用いてキャッシュを介しないデータ移動が考えられる。こちらは 25 % ほど速い。かつて、2倍近く高速化される例も体験したことがある。その頃に比べ相対的な伸び代がないのかも。
ただし、高速化が見込めそうだというだけで期待しないほうがよい。なぜならば、64ビット版の Windows では FPU や MMX の利用がサポートされない。
※ 浮動小数演算を高速化するための FPU と MMX は表裏一体。

SSE 本来の使い道!?

最後に、誤解がないよう加えておく。今回の記事は 「2012年の暮れ時点でロードやストアの高速化に適さなかった」を旨としている。決して、SSE や AVX などの存在意義を否定するものではない。
車輪の再発明 (2)で述べた通り、SSE や AVX などの機能が追加された経緯としては、画像や音声などのデータ処理を効率的に行うためである。
SSE や AVX などの機能は、ロードやストアの高速化を目的に拡張されたのではない。画像や音声データを加工処理する際、同じような演算が繰り返される。これを同時に処理することで時間の短縮を狙いたい場合に適している。

ロード、演算、ストアをそれぞれ1ステップとするならば、旧来からの方法は4回繰り返せば 3ステップの4回分、12ステップ。
※ 必要なクロック数ではない。演算にかかるクロック数に興味があるヒトは2012年 8月13日掲載の除算が遅いをどうぞ。

SSE/SSE2/SSE4 などを用いれば、同時に4つ分をロード、同時に4つ分の演算、4つ分ストアの3ステップに減る。
ロードとストアに要する短縮は期待できないとしても演算3回分のステップが減り、4+1+4 、それ以前と比べ高速化が期待できる・・・

判り辛いだろうか。2012年 8月13日に掲載した記事のようにスイカを4等分する例で考えてみよう。



目の前にたくさんのスイカがあるとする。
今までの4倍、まな板の上にスイカを移動する。4等分したスイカをまな板の上から皿に移す。この辺の移動に要する時間はさほど変わらない。
まな板の上でスイカを切る、割る作業を担当するヒトを今までの4倍に増やす。それまでは一人で4等分していたとすれば、4人で同時に作業にあたる。よって、まな板の上で行う作業が4倍速くなる、作業時間が短縮される・・・のように想像すれば並列に実行するメリットが判るハズ・・・

本日も最後までご覧いただきありがとうございます。

「つまらなかった」「判り辛った」という方もご遠慮なくコメント欄へどうぞ

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

検索サイトからお越しの方へ
検索サイトからお越しの方は、ブラウザのアドレス欄vitalaboloveおよび、fc2.comが含まれているかご確認ください。
含まれていない場合、偽サイトを閲覧なされている可能性があります。

偽サイトは、当ブログの文字部分や画像部分が有害サイトへのバナーと置き換わっているようです。
プロフィール

Author:Vitalabolove
ご訪問ありがとうございます。
店長を任されておりますVitalaboloveです。

コメントはお気軽に。
今のところリンクフリーですが、あと数日でとりやめます。

画像データ、文言の引用は事前連絡くださるようお願い申し上げます。事前連絡の際は、左下、メールフォームを経由をご利用ください。

最新記事
カレンダー
06 | 2017/07 | 08
- - - - - - 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 - - - - -
カテゴリ
ランキング
いつも応援いただきありがとうございました。ただいま休養中につきランキングへ参加していません・・・

フリーエリア
内緒話などはおきてがみをご利用ください。
月別アーカイブ
メールフォーム
掲載された記事について、ご不明な点はここからお問い合わせください

名前:
メール:
件名:
本文:

最新コメント
最新トラックバック
スパムと思われるトラックバックは削除しました
QRコード
QR
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。