CPU ベンチに Snapdragon 800 MSM8974 Krait 400 の結果を追加しました。
・ARM CPU core 毎の浮動小数点演算速度の比較 (VFP/NEON)
・CPU benchmark
浮動小数点演算命令毎の実行速度
Krait 400 は動作 clock が高いこともあり非常に高速です。
上の結果では同じ ARMv7A VFPv4 世代の Cortex-A15 に匹敵し、
実行効率の差を動作クロックが十分補っていることがわかります。
またここでの Quad core は Cortex-A9, Krait, Krait 400 だけなので、
総合的なパフォーマンスでは高クロックかつ Quad core の Krait 400 が
最も高いスコアになることが予想できます。
NEON 命令は 64bit と 128bit の差がなく、Cortex-A15 と違い 128bit
単位となっています。
vfma (FMA) よりも vmla が 2倍遅かった Krait 無印 (3) と比べて、
Krait 400 (7) では vmla も vfma に近い速度が出ています。
同じ Krait でも傾向が異なっており、様々な改良が施されているようです。
同時にあらためて A7 Cyclone の単 core 性能が非常に高いこともわかります。
A7 Cyclone の結果は 2個ありますが、
(5) は ARMv8 AArch32 (armv7) 32bit モードの結果で
(6) は ARMv8 AArch64 (arm64) 64bit モードでの結果です。
以下テスト端末の詳細
下記はもうひとつのCPUベンチの結果です。
専用命令を使っている 1. が一桁高速なのは当然ですが、64bit アーキテクチャ
の A7 も十分高速です。
新 core + クロック数が最も高い Krait 400 はそれらに次ぐ速度となりました。
テスト内容の詳細はこちらから。
テストに使った Kindle Fire HDX 7 のデータは下記にも追加しました。
・CPU/GPU OpenGL ES Extension (Mobile GPU)
関連エントリ
・iPhone 5s A7 CPU の浮動小数点演算速度 (2) (arm64/AArch64/64bit)
・iPhone 5s A7 CPU の浮動小数点演算速度 (32bit)
・Nexus 10 CPU Cortex-A15 の速度
・Qualcomm APQ8064 GPU Adreno 320 の速度
・Qualcomm APQ8064 Krait/A6 swift の浮動小数点演算能力
・ARM CPU core 毎の浮動小数点演算速度の比較 (VFP/NEON)
・CPU benchmark
浮動小数点演算命令毎の実行速度
(1) (2) (3) (4) (5) (6) (7) Nexus7 iPad4 HTL21 Nexus10 iPhone5s iPhone5s KindleHDX7 Cortex-A9 Swift Krait Cortex-A15 Cyclone Cyclone Krait4 Tegra3 A6X APQ8064 Exynos5D A7 32 A7 64 MSM8974 1.2GHz 1.4GHz 1.5GHz 1.7GHz 1.3GHz 1.3GHz 2.2GHz ------------------------------------------------------------------------------ a:m44 vmla_AQ 3.959 1.204 1.337 0.619 0.700 ----- 0.661 b:m44 vmla_BQ 2.002 1.266 0.931 0.569 0.670 ----- 0.542 c:m44 vmla_AD 3.980 1.554 1.889 0.557 0.649 ----- 0.888 d:m44 vmla_BD 2.003 1.238 1.532 0.568 0.745 ----- 0.768 A:m44 vfma_AQ ----- 1.519 1.882 0.746 0.707 0.692 1.178 B:m44 vfma_BQ ----- 1.484 0.695 0.840 0.699 0.696 0.463 e:fadds A 3.343 2.878 2.774 2.383 3.551 1.043 1.864 f:fmuls A 3.337 2.953 2.747 2.369 3.475 1.548 1.867 g:fmacs A 3.337 5.757 5.574 2.956 3.480 ----- 2.052 h:vfma.f32 A ----- 5.756 2.747 2.957 3.480 3.185 1.864 i:vadd.f32 DA 3.426 2.877 2.762 1.183 1.031 1.031 1.866 j:vmul.f32 DA 3.421 2.950 2.746 1.478 1.545 1.545 1.864 k:vmla.f32 DA 3.792 2.951 5.604 1.480 1.567 ----- 2.051 o:vfma.f32 DA ----- 2.494 2.833 1.479 1.574 1.753 1.871 l:vadd.f32 QA 6.688 2.878 2.801 2.365 1.031 1.039 1.872 m:vmul.f32 QA 6.681 2.952 2.761 2.364 1.548 1.548 1.879 n:vmla.f32 QA 6.681 2.950 5.606 2.367 1.574 ----- 2.059 N:vfma.f32 QA ----- ----- ----- ----- ----- 1.696 ----- p:fadds B 3.347 5.756 3.467 2.956 6.953 3.663 ----- q:fmuls B 4.195 5.756 3.556 3.558 6.652 3.296 ----- r:fmacs B 6.688 11.514 6.298 5.912 9.867 ----- ----- s:vfma.f32 B ----- 11.513 3.430 5.910 9.859 3.292 ----- t:vadd.f32 DB 3.421 2.881 3.529 2.958 3.663 3.643 1.865 u:vmul.f32 DB 3.422 2.949 3.447 2.364 3.114 3.289 2.339 v:vmla.f32 DB 7.561 5.755 6.293 4.728 6.185 ----- 3.773 z:vfma.f32 DB ----- 5.755 3.437 4.730 6.188 6.237 2.340 w:vadd.f32 QB 6.705 2.879 3.457 2.961 3.659 3.641 1.875 x:vmul.f32 QB 6.683 2.950 3.428 2.363 3.101 3.276 2.340 y:vmla.f32 QB 7.532 5.759 6.372 4.729 6.199 ----- 3.746 Y:vfma.f32 QB ----- ----- ----- ----- ----- 6.226 ----- ・↑数値は実行時間(秒) 数値が小さい方が高速。single thread ・すべて単精度 32bit float の演算です。
Krait 400 は動作 clock が高いこともあり非常に高速です。
上の結果では同じ ARMv7A VFPv4 世代の Cortex-A15 に匹敵し、
実行効率の差を動作クロックが十分補っていることがわかります。
またここでの Quad core は Cortex-A9, Krait, Krait 400 だけなので、
総合的なパフォーマンスでは高クロックかつ Quad core の Krait 400 が
最も高いスコアになることが予想できます。
NEON 命令は 64bit と 128bit の差がなく、Cortex-A15 と違い 128bit
単位となっています。
vfma (FMA) よりも vmla が 2倍遅かった Krait 無印 (3) と比べて、
Krait 400 (7) では vmla も vfma に近い速度が出ています。
同じ Krait でも傾向が異なっており、様々な改良が施されているようです。
同時にあらためて A7 Cyclone の単 core 性能が非常に高いこともわかります。
A7 Cyclone の結果は 2個ありますが、
(5) は ARMv8 AArch32 (armv7) 32bit モードの結果で
(6) は ARMv8 AArch64 (arm64) 64bit モードでの結果です。
以下テスト端末の詳細
device OS SoC CPU core clock Arch VFP ---------------------------------------------------------------------------- (1)ASUS Nexus 7 (2012) A4.2 Tegra 3 Cortex-A9 x4 1.2GHz ARMv7A 32bit v3 (2)Apple iPad 4 i6.1 A6X Swift x2 1.4GHz ARMv7A 32bit v4 (3)HTC J butterfly HTL21 A4.1 APQ8064 Krait x4 1.5GHz ARMv7A 32bit v4 (4)Samsung Nexus 10 A4.2 Exynos5D Cortex-A15x2 1.7GHz ARMv7A 32bit v4 (5)Apple iPhone 5s i7.0 A7 Cyclone x2 1.3GHz ARMv8A 32bit v4 (6)Apple iPhone 5s i7.0 A7 Cyclone x2 1.3GHz ARMv8A 64bit Ad (7)Amazon Kindle Fire HDX7 A4.2 MSM8974 Krait 400 x4 2.2GHz ARMv7A 32bit v4
下記はもうひとつのCPUベンチの結果です。
SoC CPU clock compiler arch time MB/s MBS/GHz ------------------------------------------------------------------- 1.A7 Cyclone + AES 1.3GHz clang 5.0 arm64 0.129 837.54 644.26 2.A7 Cyclone 1.3GHz clang 5.0 arm64 1.04 104.27 80.21 3.A7 Cyclone 1.3GHz clang 5.0 armv7 1.16 93.04 71.57 4.MSM8974 Krait 400 2.2GHz gcc 4.8 armv7 1.41 76.67 34.85 5.Exynos 5D Cortex-A15 1.7GHz gcc 4.6 armv7 1.49 72.61 42.71 6.A6X Swift 1.4GHz clang 4.2 armv7 1.75 61.82 44.16 7.APQ8064 Krait 1.5GHz gcc 4.6 armv7 2.28 47.64 31.82 8.Tegra3 Cortex-A9 1.3GHz gcc 4.4.3 armv7 3.00 36.15 25.82 ・time の単位は秒 ・MB/s が大きいほうが高速 ・MBS/GHz = 1GHz あたりの処理速度
専用命令を使っている 1. が一桁高速なのは当然ですが、64bit アーキテクチャ
の A7 も十分高速です。
新 core + クロック数が最も高い Krait 400 はそれらに次ぐ速度となりました。
テスト内容の詳細はこちらから。
テストに使った Kindle Fire HDX 7 のデータは下記にも追加しました。
・CPU/GPU OpenGL ES Extension (Mobile GPU)
関連エントリ
・iPhone 5s A7 CPU の浮動小数点演算速度 (2) (arm64/AArch64/64bit)
・iPhone 5s A7 CPU の浮動小数点演算速度 (32bit)
・Nexus 10 CPU Cortex-A15 の速度
・Qualcomm APQ8064 GPU Adreno 320 の速度
・Qualcomm APQ8064 Krait/A6 swift の浮動小数点演算能力
2013/12/23
Android OpenGL ES 2.0 と 3.0 の切り替え
Desktop の OpenGL 4.x との互換性を考えるならば、
OpenGL ES 3.0 の方が圧倒的に相性が良いです。
DirectX で例えるなら Direct3D11/10 と Direct3D9 を比べるようなもの。
Direct3D11 (OpenGL4) と Direct3D10 (OpenGL ES 3.0) は同じ API 構造を
保っていますが Direct3D9 (OpenGL ES 2.0) は大きく異なります。
OpenGL は DirectX ほどの違いはなく API 上は上位互換性を保っています。
ですが Shader の構文や描画パイプラインの設計は、やはりどちらかに
合わせる必要があります。
設計が大きく異なるならば、OpenGL ES 2.0 と OpenGL ES 3.0 のバイナリを
完全に分けてしまった方が良いのかもしれません。
以前 NDK の dll を分離する方法を紹介しました。
・Android NDK の初期化と dll の分離
もし dll を分割して 2段階で読み込んでいるなら、同じ方法で
バイナリを切り替えることができます。
例えば下記のように。
・libjniproxy.so
・libappmain_es2.so
・libappmain_es3.so
関連エントリ
・Android OpenGL ES 3.0 対応 GPU を判定する方法
・Android 4.4 Adreno 320 の OpenGL ES 3.0 と Version 判定
・Android NDK の初期化と dll の分離
OpenGL ES 3.0 の方が圧倒的に相性が良いです。
DirectX で例えるなら Direct3D11/10 と Direct3D9 を比べるようなもの。
Direct3D11 (OpenGL4) と Direct3D10 (OpenGL ES 3.0) は同じ API 構造を
保っていますが Direct3D9 (OpenGL ES 2.0) は大きく異なります。
OpenGL は DirectX ほどの違いはなく API 上は上位互換性を保っています。
ですが Shader の構文や描画パイプラインの設計は、やはりどちらかに
合わせる必要があります。
設計が大きく異なるならば、OpenGL ES 2.0 と OpenGL ES 3.0 のバイナリを
完全に分けてしまった方が良いのかもしれません。
以前 NDK の dll を分離する方法を紹介しました。
・Android NDK の初期化と dll の分離
もし dll を分割して 2段階で読み込んでいるなら、同じ方法で
バイナリを切り替えることができます。
例えば下記のように。
・libjniproxy.so
・libappmain_es2.so
・libappmain_es3.so
関連エントリ
・Android OpenGL ES 3.0 対応 GPU を判定する方法
・Android 4.4 Adreno 320 の OpenGL ES 3.0 と Version 判定
・Android NDK の初期化と dll の分離
2013/12/22
Android OpenGL ES 3.0 対応 GPU を判定する方法
Android 4.3 から OpenGL ES 3.0 が使えるようになりました。
対応 GPU も順調に増えていますが、Android 4.3/4.4 が動く端末自体が
まだあまり多くありません。
GPU によっては OpenGL ES 3.0 の動作で問題が生じるものもあり、
互換性の意味でも OpenGL ES 2.0/3.0 両対応が望ましいでしょう。
iOS の方は比較的簡単で、今のところ 64bit 対応 (ARMv8 arm64) なら
OpenGL ES 3.0 にも対応しています。
Android 端末が OpenGL ES 3.0 に対応してるかどうか調べる方法は
ドキュメントに記載されています。
・OpenGL ES : Checking OpenGL ES Version
ただしこの方法は以前も書いたように必ずしもうまく行きません。
1. 及びサンプルコードは OpenGL ES 3.0 の Context を作成し、
エラーかどうかで判断しています。
実際にいくつかの端末を調べてみると、GPU ドライバは未対応でも
エラーを返さない場合がほとんどです。
version != 2.0 で判定している GPU は OpenGL ES 1.1 の context を返しますし、
version < 2.0 で判定している GPU は OpenGL ES 2.0 の context になります。
2. の方法はうまく行きますが、一旦ダミーの Context を作成するため複雑です。
またこの判定方法は Android 限定です。
以下その具体的な方法
GPUType.update() でデータを集めて isGLES3() で結果がわかります。
Android 3.0 API Level 11 以降でないと動きませんが、
Android 4.2 (API Level 17) 以前は OpenGL ES 2.0 と決め打ちできるため
特に問題ないはずです。
同じ理由で、EGL10 の代わりに EGL14 を使うこともできます。
EGL14 は API Level 17 以降の API です。
Android 4.3 + Adreno 320 の OpenGL ES 3.0 には問題があるので、
この組み合わせでは OpenGL ES 2.0 を返すようにしています。
関連エントリ
・Android 4.4 Adreno 320 の OpenGL ES 3.0 と Version 判定
・iPhone 5s の Apple A7 GPU
・Adreno 320 の OpenGL ES 3.0 と Uniform Block
・Nexus 7 (2013) の Adreno 320 と OpenGL ES 3.0 (Android 4.3)
対応 GPU も順調に増えていますが、Android 4.3/4.4 が動く端末自体が
まだあまり多くありません。
GPU によっては OpenGL ES 3.0 の動作で問題が生じるものもあり、
互換性の意味でも OpenGL ES 2.0/3.0 両対応が望ましいでしょう。
iOS の方は比較的簡単で、今のところ 64bit 対応 (ARMv8 arm64) なら
OpenGL ES 3.0 にも対応しています。
Android 端末が OpenGL ES 3.0 に対応してるかどうか調べる方法は
ドキュメントに記載されています。
・OpenGL ES : Checking OpenGL ES Version
ただしこの方法は以前も書いたように必ずしもうまく行きません。
1. 及びサンプルコードは OpenGL ES 3.0 の Context を作成し、
エラーかどうかで判断しています。
実際にいくつかの端末を調べてみると、GPU ドライバは未対応でも
エラーを返さない場合がほとんどです。
version != 2.0 で判定している GPU は OpenGL ES 1.1 の context を返しますし、
version < 2.0 で判定している GPU は OpenGL ES 2.0 の context になります。
2. の方法はうまく行きますが、一旦ダミーの Context を作成するため複雑です。
またこの判定方法は Android 限定です。
以下その具体的な方法
package jp.flatlib.gw; import android.opengl.GLES20; import android.os.Build; import android.graphics.SurfaceTexture; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.egl.EGLSurface; import android.util.Log; public class GPUType { public static int VersionCode= 0; // 200 or 300 public static String VersionString; public static String RendererString; private static int AdrenoID= 0; public static boolean isGLES3() { return VersionCode == 300; } public static boolean isAdreno300s() { return AdrenoID >= 300 && AdrenoID < 400; } private static int decodeAdrenoID( String gpu_name ) { if( gpu_name.equals( "Adreno" ) || gpu_name.indexOf( "AMD Z430" ) >= 0 ){ return 200; }else if( gpu_name.indexOf( "Adreno" ) >= 0 ){ return getAdrenoNumber( gpu_name ); } return 0; } public static void update() { EGL10 egl= (EGL10)EGLContext.getEGL(); int[] iparam= new int[8]; if( Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB ){ VersionCode= 200; return; } // Initialize EGLDisplay display= egl.eglGetDisplay( EGL10.EGL_DEFAULT_DISPLAY ); egl.eglInitialize( display, iparam ); // Config int[] config_attr= { EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL10.EGL_NONE }; final int CONFIG_SIZE= 1; EGLConfig[] config_array= new EGLConfig[CONFIG_SIZE]; egl.eglChooseConfig( display, config_attr, config_array, CONFIG_SIZE, iparam ); EGLConfig config= config_array[0]; // Surface SurfaceTexture surfaceTexture= new SurfaceTexture( 0 ); // API Level 11 EGLSurface surface= egl.eglCreateWindowSurface( display, config, surfaceTexture, null ); // Context int[] context_attr= { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; EGLContext context= egl.eglCreateContext( display, config, EGL10.EGL_NO_CONTEXT, context_attr ); // Make Current egl.eglMakeCurrent( display, surface, surface, context ); // Query VersionString= GLES20.glGetString( GLES20.GL_VERSION ); RendererString= GLES20.glGetString( GLES20.GL_RENDERER ); VersionCode= getGLVersionString( VersionString ); AdrenoID= decodeAdrenoID( RendererString ); // Special if( isAdreno300s() ){ if( Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR2 ){ // .. Android 4.3 VersionCode= 200; // GLES 2.0 } } // Release egl.eglMakeCurrent( display, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT ); egl.eglDestroyContext( display, context ); egl.eglDestroySurface( display, surface ); } private static int getGLVersionString( String version_string ) { int length= version_string.length(); int ci= 0; for(; ci < length ; ci++ ){ char ch= version_string.charAt( ci ); if( ch >= '0' && ch <= '9' ){ break; } } int version= 0; int num_shift= 100; for(; num_shift > 0 && ci < length ;){ char ch= version_string.charAt( ci++ ); if( ch >= '0' && ch <= '9' ){ if( num_shift == 100 ){ if( version_string.charAt( ci ) == '.' ){ ci++; } } version+= (ch - '0') * num_shift; num_shift/= 10; }else{ break; } } return version; } private static int getAdrenoNumber( String text ) { int length= text.length(); int num= 0; boolean is_num= false; for( int i= 0 ; i< length ; i++ ){ char ch= text.charAt( i ); if( is_num ){ if( ch >= '0' && ch <= '9' ){ num*= 10; num+= ch - '0'; }else{ break; } }else{ if( ch >= '0' && ch <= '9' ){ is_num= true; num= ch - '0'; } } } return num; } }
GPUType.update() でデータを集めて isGLES3() で結果がわかります。
Android 3.0 API Level 11 以降でないと動きませんが、
Android 4.2 (API Level 17) 以前は OpenGL ES 2.0 と決め打ちできるため
特に問題ないはずです。
同じ理由で、EGL10 の代わりに EGL14 を使うこともできます。
EGL14 は API Level 17 以降の API です。
Android 4.3 + Adreno 320 の OpenGL ES 3.0 には問題があるので、
この組み合わせでは OpenGL ES 2.0 を返すようにしています。
関連エントリ
・Android 4.4 Adreno 320 の OpenGL ES 3.0 と Version 判定
・iPhone 5s の Apple A7 GPU
・Adreno 320 の OpenGL ES 3.0 と Uniform Block
・Nexus 7 (2013) の Adreno 320 と OpenGL ES 3.0 (Android 4.3)
2013/12/21
Android OpenGL ES と V-Sync (eglSwapInterval)
Android の描画も V-Sync に依存しており、一部デバイスを除いておよそ
60fps が上限となっています。
Android 4.1 Jelly Bean (API Level 17) 以降は SwapInterval で
0 を設定することができます。
desktop 版 OpenGL 同様、Interval=0 に設定すると非同期になります。
実際の画面に反映されているかどうかを考えなければ、
GPU の描画ループも 60fps を超えることが可能です。
EGLDisplay, EGLContext, EGLConfig, EGLSurface は android.opengl と
javax.microedition.khronos.egl の両方に存在します。
EGL14 を用いる場合は android.opengl の方を使用。
ベンチマークで便利。
関連エントリ
・iOS CADisplayLink とフレームレート
・OpenGL の同期と描画速度の測定
60fps が上限となっています。
Android 4.1 Jelly Bean (API Level 17) 以降は SwapInterval で
0 を設定することができます。
desktop 版 OpenGL 同様、Interval=0 に設定すると非同期になります。
実際の画面に反映されているかどうかを考えなければ、
GPU の描画ループも 60fps を超えることが可能です。
// Java import android.opengl.EGL14; import android.opengl.EGLDisplay; ~ EGLDisplay display14= EGL14.eglGetDisplay( EGL14.EGL_DEFAULT_DISPLAY ); EGL14.eglSwapInterval( display14, 0 );
EGLDisplay, EGLContext, EGLConfig, EGLSurface は android.opengl と
javax.microedition.khronos.egl の両方に存在します。
EGL14 を用いる場合は android.opengl の方を使用。
// NDK NativeActivity eglSwapInterval( display, 0 );
// NDK + GLSurfaceView EGLDisplay display= eglGetDisplay( EGL_DEFAULT_DISPLAY ); eglSwapInterval( display, 0 );
ベンチマークで便利。
関連エントリ
・iOS CADisplayLink とフレームレート
・OpenGL の同期と描画速度の測定