유니티 공식 가이드

유니티에서 제공하는 문서의 내용을 참조

에디터 로그

  • 빌드 후 콘솔 창 오른쪽 상단의 드롭다운 메뉴 클릭 후 Open Editor 선택
  • 로그 파일을 보면서 필요없는 파일이나 제대로 조정되지 않은 리소스가 포함되지 않았는지 확인

텍스처

  • 텍스처 원본의 사이즈를 줄일 필요는 없고, 인스펙터의 임포트 세팅에서 사이즈를 변경
  • 플랫폼 별로 알맞은 압축 방식을 지정. 유니티에서 사용되는 텍스처 포맷에 대한 설명은 이 문서를 참조

DLL

  • Stripping Level의 설정을 Strip Assemblies 이하로 설정 시 사용하지 않는 어셈블리(dll 파일)을 빌드파일에 포함하지 않음.
  • 문서를 보면 특정 컨테이너는 System.dll에 포함되므로 그런 컨테이너를 피하라고 적혀있음.
  • 정확하게는 List, Dictionary와 그에 관련된 컬렉션 컨테이너 이외에는 모두 System.dll에 포함(LinkcedList, Stack, Queue, SortedDictionary 등)
  • 하지만 Unity 5 이후에는 UnityEngine.dll이 System.dll과 System.Core.dll을 참조하므로 빈 프로젝트를 빌드해도 두 어셈블리가 포함되는 것을 막을 수 없음.
  • 실제로 빌드해보면 어셈블리 자체는 들어가있으나, Stripping Level을 설정하는 경우 Disabled로 설정했을 때보다 확실히 작아진 어셈블리가 포함됨[각주:1]

다중 APK 지원 이용

대상 디바이스로 FAT(arm + x86)을 지정하면 두 플랫폼용 라이브러리가 같이 들어가서 용량이 커짐. 조금이라도 용량을 줄이고 싶다면, 플랫폼별로 따로 빌드하는 것도 고려해볼 수 있음. 다행히 구글 플레이에서는 한 앱에 기능별로 다른 APK를 제공할 수 있는 기능이 있음.

다중 APK 지원을 위한 기본 규칙

  1. 모든 APK는 패키지 명이 같아야 하고, 같은 인증키를 사용하여 사인되어야 함.
  2. APK 별로 버전 코드가 서로 달라야 함.
  3. API level이 높을수록 버전 코드가 높아야 함.
  4. 높은 버전 코드에서 낮은 버전 코드로 업데이트할 수 없음.

이상의 규칙으로 인해 구글 측에서는 다음과 같은 버전 코드 규칙을 가이드라인으로 제시하고 있음.

위와 같이 API level을 가장 앞에, 앱 버전을 가장 뒤에 두고 그 사이에 플랫폼이나 OpenGL ES 버전, 텍스처 포맷 등의 구분자를 넣어 작성하는 것을 추천.

관련 문서


  1. 유니티 2017.1에서 테스트 [본문으로]

※ 이 글은 오가사와라 히로유키(小笠原博之) 씨가 블로그에 적은 글을 번역한 것입니다. 사정에 따라 예고없이 삭제될 수 있으므로 양해부탁드립니다.

Nexus 10 CPU Cortex-A15의 부동소수점 연산속도

(원문 : 3DMark Android 版の結果から)

Nexus10을 입수하여 ARMv7A의 새로운 CPU core 3종류가 갖춰졌기에 Apple Swift, Qualcomm Krait, ARM Cortex-A15를 비교해보겠습니다. 동작 클럭이 가장 높다는 것도 있지만, Cortex-A15의 동작은 Swift보다도 고속이었습니다.

                (1)     (2)     (3)     (4)     (5)     (6)     (7)
               iPad3   Nexus7  EVO 3D iPhone5  iPad4   HTL21  Nexus10
                A5X    Tegra3 MSM8660   A6      A6X   APQ8064 Exynos5D
               ARM A9  ARM A9 Scorpion Swift   Swift   Krait  ARM A15
               1.0GHz  1.2GHz  1.2GHz  1.3GHz? 1.4GHz? 1.5GHz  1.7GHz
               VFPv3   VFPv3   VFPv3   VFPv4   VFPv4   VFPv4   VFPv4
----------------------------------------------------------------------
a:m44 vmla_AQ  4.784   3.959   2.859   1.293   1.204   1.337   0.619
b:m44 vmla_BQ  2.408   2.002   1.136   1.359   1.266   0.931   0.569
c:m44 vmla_AD  4.781   3.980   3.053   1.669   1.554   1.889   0.557
d:m44 vmla_BD  2.406   2.003   1.434   1.329   1.238   1.532   0.568
A:m44 vfma_AQ  -----   -----   -----   1.632   1.519   1.882   0.746
B:m44 vfma_BQ  -----   -----   -----   1.594   1.484   0.695   0.840
e:fadds     A  4.010   3.343   3.383   3.090   2.878   2.774   2.383
f:fmuls     A  4.010   3.337   3.383   3.167   2.953   2.747   2.369
g:fmacs     A  4.012   3.337   3.379   6.180   5.757   5.574   2.956
h:vfma.f32  A  -----   -----   -----   6.180   5.756   2.747   2.957
i:vadd.f32 DA  4.111   3.426   3.377   3.091   2.877   2.762   1.183
j:vmul.f32 DA  4.110   3.421   3.383   3.168   2.950   2.746   1.478
k:vmla.f32 DA  4.512   3.792   3.380   3.166   2.951   5.604   1.480
l:vadd.f32 QA  8.023   6.688   3.377   3.090   2.878   2.801   2.365
m:vmul.f32 QA  8.022   6.681   3.384   3.166   2.952   2.761   2.364
n:vmla.f32 QA  8.025   6.681   3.380   3.167   2.950   5.606   2.367
o:vfma.f32 DA  -----   -----   -----   3.167   2.494   2.833   1.479
p:fadds     B  4.014   3.347   5.917   6.181   5.756   3.467   2.956
q:fmuls     B  5.013   4.195   5.917   6.180   5.756   3.556   3.558
r:fmacs     B  8.023   6.688   8.451  12.361  11.514   6.298   5.912
s:vfma.f32  B  -----   -----   -----  12.363  11.513   3.430   5.910
t:vadd.f32 DB  4.113   3.421   5.916   3.090   2.881   3.529   2.958
u:vmul.f32 DB  4.118   3.422   5.073   3.169   2.949   3.447   2.364
v:vmla.f32 DB  9.027   7.561   8.451   6.180   5.755   6.293   4.728
w:vadd.f32 QB  8.021   6.705   5.916   3.090   2.879   3.457   2.961
x:vmul.f32 QB  8.029   6.683   5.074   3.167   2.950   3.428   2.363
y:vmla.f32 QB  9.026   7.532   8.457   6.179   5.759   6.372   4.729
z:vfma.f32 DB  -----   -----   -----   6.181   5.755   3.437   4.730
----------------------------------------------------------------------
↑수치는 실행시간(초) 수치가 작을 수록 빠름

(1)=Apple iPad 3          A5X      Cortex-A9  x2 1.0GHz  VFPv3 i6.1
(2)=ASUS Nexus 7          Tegra 3  Cortex-A9  x4 1.2GHz  VFPv3 A4.2
(3)=HTC EVO 3D ISW12HT    MSM8660  Scorpion   x2 1.2GHz  VFPv3 A4.0
(4)=Apple iPhone 5        A6       Swift      x2 1.3GHz? VFPv4 i6.1
(5)=Apple iPad 4          A6X      Swift      x2 1.4GHz? VFPv4 i6.1
(6)=HTC J butterfly HTL21 APQ8064  Krait      x4 1.5GHz  VFPv4 A4.1
(7)=Samsung Nexus 10      Exynos5D Cortex-A15 x2 1.7GHz  VFPv4 A4.2

테스트 항목에 대한 자세한 내용은 아래를 참조(a:~z:)

iPad4/EVO 3D/Butterfly는 다시 측정해서 예전보다 수치가 올라가있습니다.

a:~d: 를 보면, 1.7GHz의 Cortex-A15는 Swift의 2배 가까운 수치입니다. 명령 단독으로도 효율이 올라가, Krait와 비교해도 64bit D(float2) 명령의 속도차는 클럭의 차이 이상입니다.

64bit D(float2)와 128bit Q(float4)에 차이가 있는 것을 보면, 아마도 Cortex-A15은 64bit 단위의 ALU가 2 파이프 존재하고 있는게 아닐까 합니다. 128bit Q(float4)의 속도는 Swift/Krait와 큰 차이가 없으므로 연산능력의 피크 속도 자체는 Swift/Krait와 동일한 듯 합니다. D, Q의 차가 없는 Scorpion/Swift/Krait는 128bit 단위라 생각할 수 있습니다.

(1)~(3) Cortex-A9/Scorpion의 a:~d:에서는 AQ/AD와 BQ/BD의 결과에 큰 차이가 납니다. 이것이 CPU 세대간의 차이로, (4)~(7)의 Swift/Krait/Cortex-A15에서는 명령순에 의존하지 않고 일정한 효율로 실행되고 있음을 알 수 있습니다.

이전에도 적었던 대로 Swift는 스칼라의 덧곱셈[각주:1] 명령만 느립니다. NEON의 벡터에서는 덧곱셈이라도 딱히 속도가 떨어지진 않으므로, 무언가 구조적인 이유에 의한 것이라 생각됩니다.

마찬가지로 Krait에도 귀찮은 패턴이 있습니다. ARM에서는 VFPv4 이후 FMA(Fused Multiply add) 명령이 추가되었습니다. Krait는 vfma(FMA)보다도 종래의 vmla 명령이 2배 가까이 느립니다. 반올림처리할 vmul[각주:2] + vadd[각주:3]로 전개될 가능성이 있습니다.

Krait 최적화

a:~d: 의 연산은 vmla[각주:4]를 사용하지만, Krait에서는 이 명령이 느립니다. vfma[각주:5]로 바꿈으로서 고속화할 가능성이 있기에 시험해봤습니다.

// A: mat44 neon_AQ의 vfma화

   vmul.f32  q8, q0, d8[0]
   vlma.f32  q8, q1, d8[1]
   vlma.f32  q8, q2, d9[0]
   vlma.f32  q8, q3, d9[1]
    :
↓
   vmul.f32  q8, q0, d8[0]
   vdup.f32  q9,  d8[1]
   vfma.f32  q8, q1, q9
   vdup.f32  q10, d9[0]
   vfma.f32  q8, q2, q10
   vdup.f32  q11, d9[1]
   vfma.f32  q8, q3, q11
    :


// B: mat44 neon_AQ의 vfma화

   vmul.f32  q8,  q0, d8[0]
   vmul.f32  q9,  q0, d10[0]
   vmul.f32  q10, q0, d12[0]
   vmul.f32  q11, q0, d14[0]
   vmla.f32  q8,  q1, d8[1]
   vmla.f32  q9,  q1, d10[1]
   vmla.f32  q10, q1, d12[1]
   vmla.f32  q11, q1, d14[1]
    :
↓
   vmul.f32  q8,  q0, d8[0]
   vmul.f32  q9,  q0, d10[0]
   vmul.f32  q10, q0, d12[0]
   vmul.f32  q11, q0, d14[0]
   vdup.32   q12, d8[1]
   vdup.32   q13, d10[1]
   vdup.32   q14, d12[1]
   vdup.32   q15, d14[1]
   vfma.f32  q8,  q1, q12
   vfma.f32  q9,  q1, q13
   vfma.f32  q10, q1, q14
   vfma.f32  q11, q1, q15
    :

vfma는 vmla와 달리 vector * scalar가 안되므로 그냥 바꾸는 것만으로는 동작하지 않습니다. SSE와 마찬가지로 데이터 복사가 필요하므로 vdup[각주:6]를 삽입했습니다.

               ARM A9  ARM A9 Scorpion Swift   Swift   Krait  ARM A15
----------------------------------------------------------------------
a:m44 vmla_AQ  4.784   3.959   2.859   1.293   1.204   1.337   0.619
b:m44 vmla_BQ  2.408   2.002   1.136   1.359   1.266   0.931   0.569
    ↓
A:m44 vfma_AQ  -----   -----   -----   1.632   1.519   1.882   0.746
B:m44 vfma_BQ  -----   -----   -----   1.594   1.484   0.695   0.840

A: 는 상당히 느리지만 B: 는 효과가 있었습니다. 이 케이스에서는 Krait가 Cortex-A15을 넘어섰습니다.

예상대로 Swift, Cortex-A15에서는 역효과로, vdup가 늘어난 만큼 느려졌습니다.

참고로 vmla과 vfma는 반올림 타이밍이 다르므로 엄밀하게 말하자면 결과가 일치하지 않습니다. vfma 쪽은 오차가 적지만, C의 코드에서 보통으로 쓰면 fmacs[각주:7]가 되므로 검증코드에서 멋지게 assert에 걸렸습니다.

  1. 積和의 의역. 값을 곱하고 난 후 목표값에 더하는 명령. vmla, vfla등. [본문으로]
  2. 스칼라 부동소수점 곱셈 [본문으로]
  3. 스칼라 부동소수점 덧셈 [본문으로]
  4. 스칼라 부동소수점의 덧곱셈. 각주 1을 참고 [본문으로]
  5. vmla와 마찬가지로 스칼라 부동소수점의 덧곱셈 명령이지만 목표값에 더하기 전에 반올림하지 않음 [본문으로]
  6. 벡터 레지스터의 각 요소를 스칼라 값으로 채우는 명령 [본문으로]
  7. 구버전의 단정밀도 스칼라 덧곱셈 명령 [본문으로]

+ Recent posts