2014年6月22日 星期日

Skia debugger

Skia is 2D graphics library, they provide a debugger to provide step-by-step drawing command.

Sync skia

https://sites.google.com/site/skiadocs/developer-documentation/contributing-code/downloading

Build skia

https://sites.google.com/site/skiadocs/user-documentation/quick-start-guides/linux
https://sites.google.com/site/skiadocs/developer-documentation/skia-debugger


git log to find out the match commit whose PICTURE_VERSION match android/chromium skia
PICTURE_VERSION = 10 --> 2cf444f7040614b43af67e368f3aa636ebeaa45a

# sync to specific revision
# edit .gclient
modify "safesync_url": "rev",

# create file rev and copy sha2 hash to this file
# sync
$ gclient sync
$ ./gyp_skia
# then you can build debugger & tools

Generate .skp file which is used for skia debugger

   SkPicture *pict = new SkPicture;
   SkCanvas *picCanvas = pict->beginRecording(width, height, 0);
   // do your skia drawing ...
   pict->endRecording();
   SkString path(".skp file path");
   SkFILEWStream stream(path.c_str());
   pict->serialize(&stream);
   delete pict;

Note

Make sure SkPicture.h PICTURE_VERSION is match Skia debugger

Android touch event system

Overview

Touch event start from top to bottom (each view can decide whether to intercept event), then back up from bottom to top until some view consumed it!

Overview Flow

Activity.dispatchTouchEvent -> Root View. dispatchTouchEvent
                                                       -> .... -> bottom view.dispatchTouchEvent
   (back up) -> ... -> Root View.onTouchEvent -> Activity.onTouchEvent


Detail flow inside UI view

ViewGroup.dispatchTouchEvent()

  • onInterceptTouchEvent()
    • Check if it should supersede children
    • Return true once consumes all subsequent events
  • For each child view, in reverse order they were added
    • If touch is relevant (inside view), child.dispatchTouchEvent()
    • If not handled by previous, dispatch to next view
  • If no children handle event, listener gets a chance
    • OnTouchListener.onTouch()
  • If no listener, or not handled by child
    • OnTouchEvent

Intercept touch event


  • Override ViewGropu.onInterceptHoverEvent and return true
  • After return true, all subsequent events for the current gesture will come to your onTouchEvent() directly
  • onInterceptHoverEvent  will not be called for input event of current gesture  
  • Current target view will receive ACTION_CANCEL
  • Intercept cannot be reversed until the next gesture

Misc

  • use TouchDelegate if you want to touch area different from view bounding

Reference

2014年1月27日 星期一

[Android] CPU profiler

Android 有提供java level的profiler
詳情請看 http://developer.android.com/tools/debugging/debugging-tracing.html

使用方法很簡單, 開始跟結束加上以下的程式, 就會在/sdcard/.trace, 可以用adb pull /sdcard/.trace 把檔案取出來~ 接著就可以用traceview打開
    
    // start tracing to "/sdcard/calc.trace"
    Debug.startMethodTracing("");
    // ...
    // stop tracing
    Debug.stopMethodTracing();

但是沒辦法看到native code (JNI)以下的部分, 我測試了android-ndk-profiler, 按照說明的方式修改你的Android.mk, 然後把下載後的android-ndk-profiler 放到你的$NDK_MODULE_PATH 下面, 記得要profiling的library都要加上-pg 來compile
# add at beginning
LOCAL_CFLAGS := -pg
LOCAL_STATIC_LIBRARIES := android-ndk-profiler

# at the end of Android.mk
$(call import-module,android-ndk-profiler)
接著在你想要開始跟結束的地方加上profiling method, 跑完就會產生/sdcard/gmon.out.
/* in the start-up code */
monstartup("your_lib.so");

/* in the onPause or shutdown code */
moncleanup();

接著就可以用gprof 解開檔案
# find gprof under android sdk folder
$ find $ANDROID_NDK | grep gprof
# put gmon.out under your project top folder
$ $ANDROID_NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86/bin/arm-linux-androideabi-gprof obj/local/armeabi-v7/your_lib.so > a.log
$ cat a.log
Flat profile:

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total           
 time   seconds   seconds    calls  ms/call  ms/call  name    
 17.46      9.07     9.07                             S32_opaque_D32_filter_DX(SkBitmapProcState const&, unsigned int const*, int, unsigned int*)
  8.86     13.67     4.60                             boxBlurInterp(unsigned char const*, int, unsigned char*, int, int, int, bool, unsigned char)
  7.37     17.50     3.83                             S32A_Opaque_BlitRow32_arm(unsigned int*, unsigned int const*, int, unsigned int)
  7.32     21.30     3.80                             D32_A8_Color(void*, unsigned int, void const*, unsigned int, unsigned int, int, int)
  3.60     23.17     1.87                             arm_memset32
  2.89     24.67     1.50                             RepeatX_RepeatY_filter_scale(SkBitmapProcState const&, unsigned int*, int, int, int)
  1.66     25.53     0.86                             __gnu_mcount_nc
  1.46     26.29     0.76                             S32A_Blend_BlitRow32_arm(unsigned int*, unsigned int const*, int, unsigned int)
  1.08     26.85     0.56                             D32_A8_Opaque(void*, unsigned int, void const*, unsigned int, unsigned int, int, int)
  1.06     27.40     0.55                             profCount
....



android-ndk-profiler 原理, 其實就是利用compiler -pg 會插入__gnu_mcount_nc method, 所以他就去implemnent __gnu_mcount_nc 來對method invoke 計數~ 經過fcamel 提醒, 這類安插code進去的profiling 是屬於Instrumentation (有可能影響程式流程), 像是我用android-ndk-profiler 有些static library 就不能加-pg, 不然程式會hang住, 另外像是oprofile 則是sampling的方式, 透過CPU interrupt 去sample (比較不會影響程式進行), 不過目前我沒有找到其他方式來做native code profiling ... Profiler wiki