Android* アプリケーション向けにインテル® C++ コンパイラーの高度な機能を利用する
この記事は、インテル® Developer Zone に公開されている「Using Advanced Intel® C++ Compiler Features for Android* Applications」の参考訳です。
目次
Android 上でアプリケーションをマルチスレッド化するため、インテル® Cilk™ Plus ランタイムを使用する。
インテル® Cilk™ Plus は、マルチコア・プロセッサーでプログラムのパフォーマンスを向上させ、迅速、容易、かつ信頼性の高い方法を提供する、C および C++ の言語拡張です。インテル® Cilk™ Plus の 3 つのキーワードは、並列プログラミング用の単純で非常に強力なモデルを提供します。その一方で、ランタイム・ライブラリーとテンプレート・ライブラリーは、並列アプリケーションの実行向けにきめ細やかにチューニングされた環境を提供します。
アプリケーションをマルチスレッド化するためインテル® Cilk™ Plus を使用すると、Cilk ランタイム・ライブラリー(libcilkrts.so) にリンクする必要があります。
インテル® C++ コンパイラーを NDK ツール (ndk-build) と統合して開発を行う。
NDK ビルドシステムは、C で記述された C モジュールに C++ ライブラリーをリンクしないため、コンパイラーはリンク時に Cilk Plus ライブラリーを検出できないため、リンクエラーとなる可能性があります。
- NDK ビルドシステムで C++ のリンクを有効にするには、空の C++ ソースファイルを追加します。
- Application.mk ファイルに C++ との互換性実装を指定します。
- ‘APP_STL:=stlport_shared’ もしくは
- ‘APP_STL:=gnustl_static’ または
- ‘APP_STL:=gnustl_shared’
- 以下の “JNI 呼び出しの用意” の節で説明するように Java コードを修正します。
NDK ビルドシステム (ndk-build) を利用せずインテル® C++ コンパイラーを単独で使用して開発を行う。
C++ コードから成る開発環境は、明示的に GNU_STL ライブラリーもしくは stlport ライブラリーにリンクする必要があります。
次の手順に従ってください:
- NDK に含まれる C++ の実装をコンパイルしてリンクするには、次のオプションを指定します:
- コンパイル・オプション:
-I$ANDROID_GNU_LIBSTDCPP/include
-I$ANDROID_GNU_LIBSTDCPP/libs/x86/include - リンクオプション(gnustl_shared):
-L$ANDROID_GNU_LIBSTDCPP/libs/x86 -lgnustl_shared -lsupc++ - リンクオプション(gnustl_static):
-L$ANDROID_GNU_LIBSTDCPP/libs/x86 -lgnustl_static -lsupc++
ANDROID_GNU_LIBSTDCPP には、ANDROID_GNU_LIBSTDCPP=$NDK/sources/cxx-stl/gnu-libstdc++/4.6 を想定します。 4.6 は、ANDROID_GNU_X86_TOOLCHAIN が示す GCC のバージョンで置き換えます。
例えば、ANDROID_GNU_X86_TOOLCHAIN が $NDK/toolchains/x86-4.8/prebuilt/linux-x86 を指していれば、4.6 は 4.8 に置き換えます。
インテル® Cilk™ Plus を使用する場合、さらに libcilkrts.so もリンクします。このライブラリーは、 /compiler/lib/ia32/gnustl ディレクトリーにあります。
- コンパイル・オプション:
- stlport_shared C++ ライブラリー(最新の NDK-r9 で必要)が使用されている場合、次のオプションを追加します:
- コンパイル・オプション:
-I$ANDROID_STLPORT_LIBSTDCPP/stlport - リンクオプション:
-L$ANDROID_STLPORT_LIBSTDCPP/libs/x86 -lstlport_shared
ANDROID_STLPORT_LIBSTDCPP は、ANDROID_STLPORT_LIBSTDCPP=$NDK/sources/cxx-stl/stlport に設定します。
インテル® Cilk™ Plus を使用する場合、対応する libcilkrts.so ライブラリー は、/compiler/lib/ia32/stlport ディレクトリーにあります。
- コンパイル・オプション:
JNI 呼び出しの用意
インテル® Cilk™ Plus を使用するには、JNI 呼び出しが必要です。 ‘libcilkrts.so’ ライブラリーは、次の API 呼び出しによって Java コードから呼び出す必要があります:
アプリケーションが動的な C++ の実装に依存している場合、libcilkrts.so 以外の必要なライブラリーをロードしなければいけません。
System.loadLibrary("gnustl_shared"); System.loadLibrary("cilkrts");
もしくは、
System.loadLibrary("stlport_shared"); System.loadLibrary("cilkrts");
Androif* OS アプリケーションのパフォーマンスを改善するため PGO を使用する。
プロファイルに基づく最適化 (PGO) では、命令キャッシュの問題を軽減させるコードの再構成、コードサイズの減少、分岐予測ミスの減少などによりアプリケーション・パフォーマンスの向上を図ることができます。PGO を行うと、アプリケーションで最も頻繁に実行される領域に関する情報がコンパイラーに伝えられます。この領域を知ることで、コンパイラーは、より慎重かつ明確にアプリケーションの最適化を行います。
Android 上で PGO を利用すると、他のオペレーティング・システム比べ追加の手順が必要です。
- jni/Android.mk ファイルの C フラグに次のオプションを追加します:
LOCAL_CFLAGS:= -prof-gen -prof-dir /sdcard - アプリケーションが PGO の出力を sdcard フォルダーに書き込めるよう、WRITE_EXTERNAL_STORAGE パーミッションを追加します。AndroidManifest.xml ファイルに次のコードを追加します。
<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE” \> - プロファイル・データが書き込まれていることを確認します。
プロファイル・データは、デフォルト・モードではアプリケーションが exit した時にのみ書き込まれます。通常 Android* 上のアプリケーションは exit しません。アプリケーションに exit を強制するかこの問題の解決策を適用するには、次の選択肢があります。a. 選択肢 1:
JAVA コードから exit を呼び出す。
System.exit(0);
b. 選択肢 2:
ネイティブコードから明示的に PGO データの書き出しを行う。
#include <pgouser.h> _PGOPTI_Prof_Dump_All();
c. 選択肢 3:
アプリケーションの実行中にパフォーマンス・データが sdcard に書き込まれるよう、環境変数を設定する。全てのアプリケーションに環境変数が適用されるように、 Android イメージの init.rc ファイルにそれらを追加します。
export INTEL_PROF_DUMP_INTERVAL 5000 export INTEL_PROF_DUMP_CUMULATIVE 1
注:
INTEL_PROF_DUMP_INTERVAL 値はマイクロ秒で測定され、INT_MAX を超えることはできません。
- ターゲットで生成された dyn ファイルをホストのソースコードと同じディレクトリーへコピーします。
adb pull ...
-
Android.mk ファイルの C フラグを生成された dyn ファイルを使用するよう変更します。-prof-dir 引数を使用して異なる場所の dyn ファイルを参照できます。
LOCAL_CFLAGS := -prof-use
Linux*、Windows*、そして OS X* 上でインテル® C++ コンパイラーの PGO を使用してアプリケーションを最適化する際の詳細情報は、パッケージに含まれるインテル® C++ コンパイラー XE 14.0 のユーザーおよびリファレンスガイドのプロファイル・ガイド最適化の節を参照してください。
コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください。