HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2024
0206
buhio関数一つをdllにするのは高速化する?意味ない?15解決


buhio

リンク

2024/2/6(Tue) 17:20:57|NO.101165

連投すいません。

 C++は全く素人の素人ですが、3Dまわりのクオータニオンの乗算や4×4マトリックスの関数は、内容的には四則演算の組み合わせだと思います。

 現状はHSPのモジュールとしてこれらの関数を作成して使用していますが、例えばこれらの関数を
 C++でコンパイルしてdll化すれば、速度は速くなるものでしょうか?
 それともかえってオーバーヘッドが増える的な感じで効果は薄いものでしょうか。。
 
 試してみればいいことですが、もし知ってたら教えてほしいなぁと、、、



この記事に返信する


youdai

リンク

2024/2/7(Wed) 20:08:12|NO.101173

>C++は全く素人の素人ですが、3Dまわりのクオータニオンの乗算や4×4マトリックスの関数は、内容的には四則演算の組み合わせだと思います。
>現状はHSPのモジュールとしてこれらの関数を作成して使用していますが、例えばこれらの関数を
>C++でコンパイルしてdll化すれば、速度は速くなるものでしょうか?

4*4マトリクス等の行列演算であれば、最速なのはおそらくC++ではなく、GPU演算ができるOpenCL等だと思います。
HSP3上でOpenCLが扱えるモジュールがあります。

HSPCL32N(32bit版HSP3用。HGIMG4でも扱える)
https://github.com/toropippi/HSPCL32N

HSPCL64(64bit版HSP3用。将来HGIMG4の64bit版がリリースされれば、HGIMG4でも使えるかも)
https://github.com/toropippi/HSPCL64

例えC++で普通にコンパイルしても処理されるのは結局CPU上でだと思うので、マトリクス系を処理したいのであれば、GPU上で並列演算できるOpenCL等の方がいいのではないかと思います。



buhio

リンク

2024/2/8(Thu) 19:42:27|NO.101175

>>youdaiさん

ありがとうございます。
前から気になっていましたopencl。

しかしレベルがついていかない。。
じっくりやらんと沼にはまりそうです。



usagi

リンク

2024/2/14(Wed) 19:38:41|NO.101218

こんにちわ
書き方にもよると思いますが、基本的に速度は速くなるのではないですかね。

少し前に流行ったPythonなどはHSPよりとても遅いですが、
numpyというライブラリを使う事によって早くなり数学計算によく使われたらしいです。
このnumpyはCだかFortranで書かれてたと記憶してます(違ったらすみません)

大量の計算部分を高速な言語(書くのは面倒だけど)書いておいて、
結果の表示や編集を簡単な言語(HSP)などで組むことはよくあると思います。

CPU使う利点もあると思うので(ハードウェアが使えない環境とか、熱の問題とかいろいろ。。。)
dll化する簡単なサンプル書きましたのでどうぞ。
試しに1万の変数の掛算を千回試行したら、私の環境だと100倍くらい早くなりました。

1)オープンソースC,C++コンパイラのMigWinを"C:\mingw32"にインストと仮定

2)Cソース"accelerate.c" (配列の四則演算:エラーチェックなどはしてない)

int accaddi(int *res, int *x, int *y, int len){ for (int i = 0; i < len; i++) { res[i] = x[i] + y[i]; } return 0; } int accsubi(int *res, int *x, int *y, int len){ for (int i = 0; i < len; i++) { res[i] = x[i] - y[i]; } return 0; } int accmuli(int *res, int *x, int *y, int len){ for (int i = 0; i < len; i++) { res[i] = x[i] * y[i]; } return 0; } int accdivi(int *res, int *x, int *y, int len){ for (int i = 0; i < len; i++) { res[i] = x[i] / y[i]; } return 0; }

3)コンパイル用バッチ "accelerate.bat"

C:\mingw32\bin\gcc -c accelerate.c C:\mingw32\bin\gcc -shared -o accelerate.dll accelerate.o

4)HSPで実行

; 自作ライブラリ #uselib "accelerate.dll" #func accaddi "accaddi" var, var, var, int #func accsubi "accsubi" var, var, var, int #func accmuli "accmuli" var, var, var, int #func accdivi "accdivi" var, var, var, int ; 自作HSP関数 (取りあえず一個だけ) #module #deffunc myaddi array res, array x, array y, int num repeat num : res.cnt = x.cnt + y.cnt : loop : return 0 #global ; 簡易計測 #uselib "winmm.dll" #cfunc timeGetTime "timeGetTime" ; 適当に初期化 trials = 1000 num = 10000 dim a, num : dim x, num : dim y, num repeat num x.cnt = rnd(32768) : y.cnt = rnd(32768) loop ; 速度比較 time = timeGetTime() repeat trials accaddi a, x, y, length(a) loop time = timeGetTime() - time mes "Cライブラリ時間:"+time+"ms" time = timeGetTime() repeat trials myaddi a, x, y, length(a) loop time = timeGetTime() - time mes "HSPモジュール時間:"+time+"ms"



usagi

リンク

2024/2/14(Wed) 19:46:12|NO.101219

あっ、一応コンパイラはこちらを使い確認しました。
(dllが作れれば何でもいいです)

・32bit
i686-12.2.0-release-win32-dwarf-msvcrt-rt_v10-rev2.7z

・64bit
x86_64-12.2.0-release-win32-seh-msvcrt-rt_v10-rev2.7z

上記のサンプルの様な感じで、3D計算部分だけ外部に置き換えて
試してみてはいかがでしょうか。



buhio

リンク

2024/2/14(Wed) 22:14:28|NO.101221

>>師匠!!!

 界王拳100倍、、!

 か、勝てる、、!
 これでフリーザに勝てる、、、!

 (試したい!だが繁忙期)m(_ _)m
そのうち必ず!感謝!!!



usagi

リンク

2024/2/15(Thu) 02:30:02|NO.101224

すみません誤字でした。MigWinではなくMingwコンパイラ使いました。
あと質問はC++でしたね。Cの方が簡単かと思いますので、まずはそれからをオススメしてみます。

hspのお作法にあわせるならhspsdk熟読する必要がありますし、
Windowの機能使うならAPIを調べる必要があるので大変ですが、
計算用の関数だけのdllはシンプルで、hspは凄い事に簡単に呼び出せちゃいます。

最近は割とdll作るの簡単で、Cの計算ならHSPとそこまで書き方違わないので敷居は高くないですよ。
お時間ある時にまったりお気楽にどうぞ。

★オマケ★
折角ですから、4x4行列1回の計算だけを愚直に呼び出してみました。
私の環境では80〜60倍速くなったので、オーバーヘッド考えても、計算がボトルネックであれば行う価値はあると思いました。

1)Cソース"accelerate.c"

int accMulMtx(double *m1, double *m2, double *dst) { dst[0] = m1[0] * m2[0] + m1[4] * m2[1] + m1[8] * m2[2] + m1[12] * m2[3]; dst[1] = m1[1] * m2[0] + m1[5] * m2[1] + m1[9] * m2[2] + m1[13] * m2[3]; dst[2] = m1[2] * m2[0] + m1[6] * m2[1] + m1[10] * m2[2] + m1[14] * m2[3]; dst[3] = m1[3] * m2[0] + m1[7] * m2[1] + m1[11] * m2[2] + m1[15] * m2[3]; dst[4] = m1[0] * m2[4] + m1[4] * m2[5] + m1[8] * m2[6] + m1[12] * m2[7]; dst[5] = m1[1] * m2[4] + m1[5] * m2[5] + m1[9] * m2[6] + m1[13] * m2[7]; dst[6] = m1[2] * m2[4] + m1[6] * m2[5] + m1[10] * m2[6] + m1[14] * m2[7]; dst[7] = m1[3] * m2[4] + m1[7] * m2[5] + m1[11] * m2[6] + m1[15] * m2[7]; dst[8] = m1[0] * m2[8] + m1[4] * m2[9] + m1[8] * m2[10] + m1[12] * m2[11]; dst[9] = m1[1] * m2[8] + m1[5] * m2[9] + m1[9] * m2[10] + m1[13] * m2[11]; dst[10] = m1[2] * m2[8] + m1[6] * m2[9] + m1[10] * m2[10] + m1[14] * m2[11]; dst[11] = m1[3] * m2[8] + m1[7] * m2[9] + m1[11] * m2[10] + m1[15] * m2[11]; dst[12] = m1[0] * m2[12] + m1[4] * m2[13] + m1[8] * m2[14] + m1[12] * m2[15]; dst[13] = m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13] * m2[15]; dst[14] = m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14] * m2[15]; dst[15] = m1[3] * m2[12] + m1[7] * m2[13] + m1[11] * m2[14] + m1[15] * m2[15]; return 0; }
2)さっきと同じバッチでコンパイル
3)HSPで実行(ちょっと書き方変えました)

; 自作ライブラリ #uselib "accelerate.dll" #func accMulMtx "accMulMtx" var, var, var ; 自作HSP関数 #module #deffunc myMulMtx array m1, array m2, array dst dst.0 = m1.0 * m2.0 + m1.4 * m2.1 + m1.8 * m2.2 + m1.12 * m2.3 dst.1 = m1.1 * m2.0 + m1.5 * m2.1 + m1.9 * m2.2 + m1.13 * m2.3 dst.2 = m1.2 * m2.0 + m1.6 * m2.1 + m1.10 * m2.2 + m1.14 * m2.3 dst.3 = m1.3 * m2.0 + m1.7 * m2.1 + m1.11 * m2.2 + m1.15 * m2.3 dst.4 = m1.0 * m2.4 + m1.4 * m2.5 + m1.8 * m2.6 + m1.12 * m2.7 dst.5 = m1.1 * m2.4 + m1.5 * m2.5 + m1.9 * m2.6 + m1.13 * m2.7 dst.6 = m1.2 * m2.4 + m1.6 * m2.5 + m1.10 * m2.6 + m1.14 * m2.7 dst.7 = m1.3 * m2.4 + m1.7 * m2.5 + m1.11 * m2.6 + m1.15 * m2.7 dst.8 = m1.0 * m2.8 + m1.4 * m2.9 + m1.8 * m2.10 + m1.12 * m2.11 dst.9 = m1.1 * m2.8 + m1.5 * m2.9 + m1.9 * m2.10 + m1.13 * m2.11 dst.10 = m1.2 * m2.8 + m1.6 * m2.9 + m1.10 * m2.10 + m1.14 * m2.11 dst.11 = m1.3 * m2.8 + m1.7 * m2.9 + m1.11 * m2.10 + m1.15 * m2.11 dst.12 = m1.0 * m2.12 + m1.4 * m2.13 + m1.8 * m2.14 + m1.12 * m2.15 dst.13 = m1.1 * m2.12 + m1.5 * m2.13 + m1.9 * m2.14 + m1.13 * m2.15 dst.14 = m1.2 * m2.12 + m1.6 * m2.13 + m1.10 * m2.14 + m1.14 * m2.15 dst.15 = m1.3 * m2.12 + m1.7 * m2.13 + m1.11 * m2.14 + m1.15 * m2.15 return #global ; 簡易計測 #uselib "winmm.dll" #cfunc timeGetTime "timeGetTime" ; 適当に初期化 trials = 100000 ddim out, 16 : ddim m1, 16 : ddim m2, 16 repeat 16 m1.cnt = 0.00003*rnd(32768) : m2.cnt = 0.00003*rnd(32768) loop ; 速度比較 sum_timeA = 0.0 : sum_timeB = 0.0 repeat 5 mes "計測開始。。。" timeA = timeGetTime() repeat trials accMulMtx m1, m2, out loop timeA = double(timeGetTime() - timeA) / trials sum_timeA += timeA mes "Cライブラリ時間(1回あたり): "+timeA+"ms" timeB = timeGetTime() repeat trials myMulMtx m1, m2, out loop timeB = double(timeGetTime() - timeB) / trials mes "HSPモジュール時間(1回あたり): "+timeB+"ms" sum_timeB += timeB mes ""+(double(double(timeB) / double(timeA)))+"倍早い!\n" wait loop ave_timeA = sum_timeA / 5 ave_timeB = sum_timeB / 5 mes strf("終了: [C 平均: %fms, HSP 平均: %fms]", ave_timeA, ave_timeB)

60FPSのゲームが4800FPSでちゃうーー(ウソ)
慣れてきたら、必要に応じて最適化したりC++,OpenCLなどに進むのが初めは良いかもしれません。
そこまでせずとも、特殊な事でなければボトルネックになるような事は無いかとは考えてます。
(2048*2048テクセルの水面の波紋を波動方程式で求めたいとか。。。そうであればおとなしくGPU(シェーダー)使います。。。)

それでは、長文失礼いたしました。



buhio

リンク

2024/2/15(Thu) 14:05:03|NO.101225

>>usagi師匠

 忙しいのでスキマ時間で(嘘です仕事してるふり)。VisualStudio2019でビルドしました。
 https://qiita.com/AmefuriTell/items/6530371adf16bf5f2063
 (こちらを参考にビルドしました。全然意味は分からないが、動いた。仕事しろ)

 回数を10万回にすると、初回は速いのですが後は遅くて安定しません。
 100万回にすると割と60〜80倍で安定するようです。

 以上、報告です。次の作品で活かしたい。
 
●10万回trial
 計測開始。。。
Cライブラリ時間(1回あたり): 0.000090ms
HSPモジュール時間(1回あたり): 0.008260ms
91.777778倍早い!

計測開始。。。
Cライブラリ時間(1回あたり): 0.000400ms
HSPモジュール時間(1回あたり): 0.008300ms
20.750000倍早い!

計測開始。。。
Cライブラリ時間(1回あたり): 0.000320ms
HSPモジュール時間(1回あたり): 0.008210ms
25.656250倍早い!

計測開始。。。
Cライブラリ時間(1回あたり): 0.000330ms
HSPモジュール時間(1回あたり): 0.008210ms
24.878788倍早い!

計測開始。。。
Cライブラリ時間(1回あたり): 0.000360ms
HSPモジュール時間(1回あたり): 0.008220ms
22.833333倍早い!

終了: [C 平均: 0.000300ms, HSP 平均: 0.008240ms]

●100万回trial

計測開始。。。
Cライブラリ時間(1回あたり): 0.000105ms
HSPモジュール時間(1回あたり): 0.008171ms
77.819048倍早い!

計測開始。。。
Cライブラリ時間(1回あたり): 0.000128ms
HSPモジュール時間(1回あたり): 0.008150ms
63.671875倍早い!

計測開始。。。
Cライブラリ時間(1回あたり): 0.000132ms
HSPモジュール時間(1回あたり): 0.008128ms
61.575758倍早い!

計測開始。。。
Cライブラリ時間(1回あたり): 0.000101ms
HSPモジュール時間(1回あたり): 0.008136ms
80.554455倍早い!

計測開始。。。
Cライブラリ時間(1回あたり): 0.000128ms
HSPモジュール時間(1回あたり): 0.008180ms
63.906250倍早い!

終了: [C 平均: 0.000119ms, HSP 平均: 0.008153ms]



buhio

リンク

2024/2/15(Thu) 14:07:30|NO.101226

 いや待て、師匠のCでのビルドの方が簡単かも。。
 また挑戦する宿題が増える。。



usagi

リンク

2024/2/15(Thu) 17:35:02|NO.101232

あっすみません。たぶんこれwaitとtimeGetTimeのせいでしょうね。
"; 簡易計測"コメント以下を置き換えて頂ければ、安定するかと思います。
取り急ぎ、こちらでは安定しました。

; 簡易計測(パワーアップ) #module #uselib "kernel32.dll" #func QueryPerformanceCounter "QueryPerformanceCounter" var #func QueryPerformanceFrequency "QueryPerformanceFrequency" var #deffunc startTimer freq = 0 : start_time = 0 : end_time = 0 QueryPerformanceFrequency freq QueryPerformanceCounter start_time return #defcfunc stopTimer QueryPerformanceCounter end_time return double(end_time - start_time) * 1000 / double(freq) #global ; 適当に初期化 trials = 100000 ddim out, 16 : ddim m1, 16 : ddim m2, 16 repeat 16 m1.cnt = 0.00003*rnd(32768) : m2.cnt = 0.00003*rnd(32768) loop ; 速度比較 sum_timeA = 0.0 : sum_timeB = 0.0 repeat 5 mes "計測開始。。。" startTimer repeat trials accMulMtx m1, m2, out loop timeA = stopTimer() / trials sum_timeA += timeA mes "Cライブラリ時間(1回あたり): "+timeA+"ms" startTimer repeat trials myMulMtx m1, m2, out loop timeB = stopTimer() / trials mes "HSPモジュール時間(1回あたり): "+timeB+"ms" sum_timeB += timeB speed = timeB / timeA mes ""+speed+"倍早い!\n" loop ave_timeA = sum_timeA / 5 ave_timeB = sum_timeB / 5 mes strf("終了: [C 平均: %fms, HSP 平均: %fms]", ave_timeA, ave_timeB)



usagi

リンク

2024/2/15(Thu) 17:49:00|NO.101233

>VisualStudio2019でビルドしました。
>Cでのビルドの方が簡単かも。。

おぉ、VisualStudioの様なIDEをお持ちですでにdllが作成で出来ているなら十分だと思いますよ。

私のは、ちょろっとテストしてみるだけの簡易的なものなので、
規模の大きい事を行おうとしたら大変かもしれませんので、IDE使った方が良いです。

あえて、良い点をあげるとしたら

・C++だとオーバライドあるので勝手に関数名が変わってしまいますから、
 defファイルの様な物が必要になってきますが、Cだと関数書いてdll出すだけで簡単。

・統合開発環境ってシンプルな事をするには九龍城砦の様なカオス感があるので、
 何だかよく分からないとこが多い。
 (最適化とか、マルチコアのオプションとかどうするの。。。どこさわるの。。。)

・なんか自分で管理出来てる感がある。

とかですかね。。。無理に挑戦する必要はなく、使える物を使えば良いかと思いますよ。

たびたび、しつれいしました。



zakki

リンク

2024/2/15(Thu) 18:47:39|NO.101234

名前修飾と関数エクスポートなら
extern "C" __declspec(dllexport) int WINAPI foo(int a);
とか書けばC++でdefファイル書かなくても大丈夫かも。

あとOpenCLというかGPU処理は処理の中味は高速ですが呼び出しごとのオーバーヘッドが大きいので
大きめの配列処理のような結構重め処理じゃないとむしろ遅くなることが多いです。



buhio

リンク

2024/2/16(Fri) 13:06:43|NO.101243

 皆さんありがとうございます。
 なんだかレベルアップした気分です。(あくまで気分)

 ちょっとC言語の本買うかぁ、、
 



buhio

リンク

2024/2/16(Fri) 17:12:15|NO.101244

>>追伸 usagi師匠

 提示いただいたもので、こちらも安定して計測されました。
 いつも大変勉強になります。
 

 



youdai

リンク

2024/2/16(Fri) 18:31:16|NO.101246

> buhio さん

大事なことを書き忘れてました。
OepnCLの場合、非対応のグラボだと動作しません。またOpenCLは、nVidiaとAMDの両方に対応していますが、対応している機能が違います。
C++でdllを出力する場合でも、新しいコンパイラでコンパイルすると古いOSでは動作しません。
HSP3でスクリプトを記述すれば、win98等の古い環境やandroid等のOSでも動作します。そういった保守性や互換性の高さがHSP3で記述するメリットだと思います。

>zakki さん

>あとOpenCLというかGPU処理は処理の中味は高速ですが呼び出しごとのオーバーヘッドが大きいので
>大きめの配列処理のような結構重め処理じゃないとむしろ遅くなることが多いです。

その通りです。OpenCLは、画像加工等や大規模並列演算に向いていると思います。
3Dではパーティクルの制御や、特殊なフラグメントシェーダーのような制御、3Dモデルの頂点制御等に向いていると思います。
逆にzakkiさんの言うとおり、オーバーヘッドが大きいので小さく細かく呼び出すのには不向きです。



usagi

リンク

2024/2/16(Fri) 20:46:18|NO.101247

わわわ、HSP界の神であるzakkiさんからのコメントが!
もろもろ、おっしゃられる通りでございます。

>buhioさん
安定した様で良かったです。

※余談※
zakkiさんからもご指摘ありましたが、
丁度、"並列計算"の話題も出てたのでGPUではないですが、
OpenMPで簡単に上記のコード組み替えられるので、
試してみたら遅くなりました。。。

1回のコールで行うバッチ処理などが向いているかと思いますし、
ちゃんと考えて自身の用途に合わせなて組まないとダメですね。

結果としては単体で何度も呼び出す3D用計算の関数をdll化すると
その部分は80倍くらい早くなりそうって感じでしょうか。
速度アップ的に十分な気もしました。
(buhioさんの環境の方がベンチ結果よさげでしたが)

※OpenMpは余談なので抜粋

■バッチはこんな雰囲気 C:\mingw64\bin\gcc -shared -fopenmp -O3 accelerate_single.c -o accelerate.dll ■ソースはこんな雰囲気(参考にならない愚直なもの) #include<omp.h> int accaddi(int *res, int *x, int *y, int len) { #pragma omp parallel for for (int i = 0; i < len; i++) { res[i] = x[i] + y[i]; } return 0; } int accMulMtx(double *m1, double *m2, double *dst) { #pragma omp parallel sections { #pragma omp section { dst[0] = m1[0] * m2[0] + m1[4] * m2[1] + m1[8] * m2[2] + m1[12] * m2[3]; 以下続く....



記事削除

記事NO.パスワード
(質問が解決したスレッドは他の利用者に活用してもらうため、削除しないようお願いします)

NO.101165への返信

マスコット

好きなマスコットを選んでください。

名前

e-mail
HOME
  1. 初めて利用する方は、HSP3掲示板の使い方をお読みください。
  2. 不要部分の多い長いスクリプトの投稿は ご遠慮ください。
  3. 書き込みは自動改行されません。適度に改行を入れてください。
  4. スクリプトは小文字の<pre>〜</pre>で囲むと見やすく表示できます。

削除用パスワード

解決したら質問者本人がここをチェックしてください。

エラー発生時、再送信すると二重送信になることがあります。
回答が得られたら、お礼書き込み時に[解決]チェックしてください。
SPAM防止のためURLから始まる文章は投稿できません。
SPAM防止のため英文字のみの本文を投稿することはできません。

ONION software Copyright 1997-2023(c) All rights reserved.