Android SDKとNDK-同様のコードセクションのパフォーマンス比較

Androidでのアプリケーションのパフォーマンスを向上させるために、彼はコードの重要なセクションをJava(SDK)からC ++(NDK)に徐々に書き直し始めました。 結果は、ターボパスカルコードにアセンブラーを挿入して、数十年前に得たものに匹敵することが判明しました。

Android NDKで作業を説明するタスクを自分で設定するわけではありません-エクスペリエンス自体では十分ではありません。 興味のある方はこのリンクから始めてください。
この短い記事の目的は、Javaで記述されてからC ++で書き直された特定の関数の実行時間を比較することにより、経験的に得たいくつかの図を提供することです。 そして、おそらく、これらの数字は誰かがこの問題をより深く研究するように動機付けます。

私のアプリケーションは写真処理に関連しているため、ボトルネックは画像​​のピクセルとそれらに対する特定のアクションをバイパスするサイクルでした。 実際のデバイス-Nexus OneおよびNexus 7(2012)でテストしました。 実験結果(ミリ秒)を表にまとめます:

レイヤーオーバーレイ(発光モード、カラー描画)

ネクサスワンNexus 7
SDKNdkSDKNdk
2563120485090
21221004520190
21621104330100

Nexus 7の場合、Nexus Oneの平均速度は21倍、36倍です。

レイヤーオーバーレイ(カラー覆い焼きモード、モノクロ)

ネクサスワンNexus 7
SDKNdkSDKNdk
267330572080
257220623070
257320611070

Nexus Oneの速度向上は平均で112倍、Nexus 7の場合は82倍です。

透明度のグラデーションをオーバーレイ

ネクサスワンNexus 7
SDKNdkSDKNdk
13013213010470
12213302670620
12113002770610

Nexus Oneの速度向上は平均で4倍、Nexus 7の場合は5倍です。

ご覧のとおり、結果は1桁または2桁も異なります。 NDKの使用による作業の実際の加速を確認できるように、数値を絶対値で具体的に引用しました。 最後のテストの比較的控えめな結果は、非常に最適化されたOpenCVライブラリの標準関数がオーバーレイの計算に使用されたためです。 したがって、このテストは、アプリケーション全体の実際の加速を明確に示しています。

OpenCVライブラリのアプリケーションに触れます。 予想どおり、ライブラリのJava部分はNDKの通常のラッパーです。 それでも、彼は上記の実験をかなり重くて長時間のアルゴリズムで実行しました-画像の特徴点を見つける、グラブカット-などの方法。 JavaとNDKの速度の違いは最大10%でしたが、これはエラーが原因である可能性があります。その時点ではまったく同じ画像を取得できなかったためです。

更新する 自分の間違いを認めるのはやや不快ですが、どうすればいいのでしょう。
そこで、OpenCVライブラリのJava実装のパフォーマンスを評価したサンプルコードを次に示します。
for (int i=0; i<mat.rows(); i++){ for (int j=0; j<mat.cols(); j++) { double[] matPix = mat.get(i, j); double[] topPix = top.get(i, j); if (matPix[0]+topPix[0]>255){ matPix[0] = 255.; } else { matPix[0] = (255. * matPix[0]) / (256. - topPix[0]); } mat.put(i, j, matPix); } } 

同じサイズの2つのマトリックスをピクセルごとに渡し、一方と他方のマトリックスの対応するピクセルの値に応じて、結果のピクセルを計算します。
記事へのコメント内のコメントのおかげで、コードは次のように最適化されました(図は単色です)。
 int size = mat.cols(); byte[] matPix = new byte[size]; byte[] topPix = new byte[size]; for (int i=0; i<mat.rows(); i++){ mat.get(i, 0, matPix); top.get(i, 0, topPix); for (int j=0; j<size; j++) { int mp = (matPix[j] & 0xFF); int tp = (topPix[j] & 0xFF); if (mp+tp>255){ mp = 255; } else { mp = (255 * mp) / (256 - tp); } matPix[j] = (byte) mp; } mat.put(i, 0, matPix); } 

テストでは、実際のNexus OneおよびNexus 7デバイスを再び使用しましたが、どちらの場合も3メガピクセルの写真を入力に送りました。デバイスのパフォーマンスを一緒に比較したかったのです。 結果(平均、ミリ秒)は、表にまとめられています。

ネクサスワンNexus 7
SDKNdkSDKNdk
最適化なし3540424522755160
最適化あり340205210120

誰もが自分で結論を出すことができます。 C ++のコード最適化は、Javaと同じ原理で実行されました。 コードは提供していませんが、上記と同じです。

Source: https://habr.com/ru/post/J215647/


All Articles