Android NDK r5 と armeabi, 浮動小数命令の種類

Android 端末 ZEN Touch2 は低価格ながら i.MX51 を搭載しており
CPU core は ARM Cortex-A8 であることがわかりました。
ARMv7 アーキテクチャなので ARM11 (ARMv6) 系のスマートフォンより高速に
動作すると考えられます。

Creative ZEN Touch 2

ところが ZENTouch2 は armeabi-v7a で build した NDK のアプリケーションを
インストールすることができませんでした。
armeabi なら OpenGL ES 2.0 を使っていても実行出来ることが分かっています。

●NDK とアーキテクチャ

現在の Android NDK r5 は 2つの ARM アーキテクチャに対応しています。

・armeabi      ARMv5TE
・armeabi-v7a  ARMv7

armeabi (ARMv5TE) と比べた場合 armeabi-v7a (ARMv7) のメリットは下記の通り。

・1. VFP (fpu) が使用可能。ハードウエアによる浮動小数演算
・2. Thumb-2 命令セット対応
・3. NEON (SIMD) 命令を利用可能。
・4. ARMv6 以降の新しい命令が使用可能。

4. でいえば、例えばスレッド間の同期に使う ldrex, strex 命令があります。
Compare And Swap 等のアトミック命令を作成できるので、これを使って
様々な同期オブジェクトを作ります。

Thumb-2 は Thumb 同様コード容量を抑えつつも、浮動小数演算など ARM (32bit)
相当の命令が利用出来るよう拡張されています。

特にメリットあるのは VFP/NEON かもしれません。
Android でも VFP 前提でネイティブなコードを書くことが可能となります。

●NDK と ARMv7 の浮動小数演算

NDK では armeabi-v7a (ARMv7) の場合少なくとも VFPv3-D16 対応であると
みなしています。

VFPv3 には 2つのバリエーションがあります。

 ・VFPv3-D16
 ・VFPv3-D32

VFPv3 は 32個の単精度浮動小数レジスタを持っています。

・単精度 32bit レジスタ s0~s31
・倍精度 64bit レジスタ d0~d15

+---------+---------+---------+-  -+---------+
| d0      | d1      | d2      |    | d15     |
+----+----+----+----+----+----+ ~ +----+----+
| s0 | s1 | s2 | s3 | s4 | s5 |    | s30| s31|
+----+----+----+----+----+----+-  -+----+----+

↑倍精度レジスタと単精度レジスタは上記のように共有されます。

倍精度レジスタは 16個ですがレジスタフィールドは 5bit あるため
命令上は倍精度レジスタを 2倍に増やすことが可能です。

+---------+---------+-  -+---------+-   -+---------+---------+
| d0      | d1      |    | d15     |     | d30     | d31     |
+----+----+----+----+ ~ +----+----+ ~ -+---------+---------+
| s0 | s1 | s2 | s3 |    | s30| s31|
+----+----+----+----+-  -+----+----+

↑このように倍精度レジスタを 2倍に増やしたのが VFPv3-D32 となります。

NEON 命令を実装している場合 128bit の SIMD レジスタが 16個あります。
レジスタは VFP と共有されるため、NEON 命令が使える CPU では自然に
VFPv3-D32 相当となります。

+-------------------+-  -+-------------------+-  -+-------------------+
| q0                |    | q7                |    | q15               |
+---------+---------+    +---------+---------+    +---------+---------+
| d0      | d1      | ~ | d14     | d15     | ~ | d30     | d31     |
+----+----+----+----+    +----+----+----+----+   -+---------+---------+
| s0 | s1 | s2 | s3 |    | s28| s29| s30| s31|
+----+----+----+----+-  -+----+----+----+----+

よって Android NDK の場合は armeabi-v7a 選択時は下記の 2種類存在して
いることになります。

(1) VFP のみの場合は VFPv3-D16
(2) NEON 対応時の VFP は VFPv3-D32

実際に調べた結果は下記のとおり

(1) VFP のみ (VFPv3-D16)
 ・Tegra2 Cortex-A9 MPCore

(2) VFP+NEON (VFPv3-D32)
 ・Cortex-A8 各種
 ・Scorpion (Snapdragon)

●armeabi まとめ

abi          arch     浮動小数       SIMD
--------------------------------------------------
armeabi      ARMv5TE  なし           なし
armeabi-v7a  ARMv7    VFPv3-D16      なし
armeabi-v7a  ARMv7    VFPv3-D32      NEON

armeabi と armeabi-v7a はバイナリを分けることが可能です。
両方のバイナリを含んでいる実行ファイルは fat binary と呼ばれているようです。
ARMv7 時に NEON 命令対応かどうかの判定は x86 の SSE のように実行時に行います。

●abi の指定方法

NDK を使ったコードは、プロジェクトの jni フォルダに配置します。
ここに c/cpp コードと Android.mk を置いて NDK 付属の ndk-build コマンドを
実行します。

例えば NDK 付属サンプルをビルドするなら下記のように実行します。
(Windows + cygwin 利用時に NDK を c:/sdk/android-ndk-r5 に展開したと仮定)

 $ cd /cygdrive/c/sdk/android-ndk-r5
 $ cd samples/hello-gl2
 $ ../../ndk-build

armeabi-v7a を指定するには下記のようにします。

 $ ../../ndk-build TARGET_ARCH_ABI=armeabi-v7a

jni フォルダに Application.mk を作成し、下記の 1行を書いておけば
無指定でも armeabi-v7a になります。

# Application.mk

APP_ABI := armeabi-v7a

下記のように記述すれば両対応の fat binary になります。

# Application.mk

APP_ABI := armeabi armeabi-v7a

NEON 対応で build するには Android.mk に “LOCAL_ARM_NEON := true” を加えます。

Windows 上の cygwin 経由だと make が遅いので、自分で build system を
構築するのもありかもしれません。

●互換性

ARMv7 アーキテクチャの端末でも ARMv5TE の armeabi のバイナリを実行できます。
上位互換性が保たれています。

1. もし armeabi-v7a の lib があればそれを使う。
2. なければ armeabi の lib を読み込む。

ARM11 のように ARMv6 アーキテクチャの場合は常に armeabi (ARMv5TE) が
選択されます。残念ながら ARMv6 の命令や機能は利用できません。

例えば ARM11 の CPU Core で VFP を搭載していたとしても VFP 命令を
活用できないことになります。

同じ ARM11 で比べた場合、c/cpp コード移植時は VFP が使える iOS の方が
高速に動作する可能性があります。

ただしこれはあくまで Android の NDK を使ったアプリケーションの話です。
カーネルや Java コードが ARMv6/VFP の機能を活用していないわけではありません。

●CPU Features

NDK には ARMv7 向けに NEON 対応などの CPU Feature を判定するコードが
付属しています。

ソースを見ると、単に /proc/cpuinfo を読み出して Features の行を見ているだけ
であることがわかります。
“vfp” や “neon” といった文字列そのもので判断しています。

●ZEN Touch2

ZEN Touch2 は Cortex-A8 搭載ですが cpuinfo の Features に “vfp” は
あるものの “neon” が含まれていません。

同じ i.MX51 を搭載している NetWalker も全く同様で “neon” がありませんが
NEON 命令をコンパイルすると実行することが出来ます。
(過去のエントリ参照)

よって ZEN Touch 2 も NEON 命令自体には対応していると考えられます。
Features に “neon” が含まれていないのは i.MX51 の何らかの事情によるもの
でしょうか。

また ZENTouch2 で armeabi-v7a のバイナリを install 出来ない理由も
分かっていません。

関連エントリ
Android ZEN Touch 2 の CPU/GPU その2
Creative ZiiO 7 ZMS-08 GPU と OpenGL ES 2.0
Tegra2 Cortex-A9 と浮動小数演算
Snapdragon と浮動小数演算速度
ARM Cortex-A8 の NEON と浮動小数演算最適化
NetWalker PC-Z1 Cortex-A8 (ARM) 浮動小数演算の実行速度