2013年8月12日 星期一

[Note] Why mobile web app are slow

Why mobile web apps are slow

這篇文章提到一些值得後續繼續觀察的地方, 記錄一下

  • JS 本身大概比 C/C++慢五倍
  • ARM 比x86 慢10倍, 所以在arm上面的mobile device上面跑js, 會比desktop上面還要慢50倍
  • 過去幾年JS的效率其實沒有多大提升, 主要可能都是硬體上效能的增進
  • GC (garbage collection) 對於效率上破壞很大, 尤其在記憶體限制的環境下, 下降的幅度可能是指數
  • iOS 上面, 單純的一張image都有可能會buffer多份
  • ARM架構上面使用POP (package on package), 這部分會影響ARM之後能夠使用更大的記憶體, 可能更困難 (相對於x86)
  • asm.js 或許是個解決方式, 但是或許chrome上面的NaCL,也是另一個方式, 畢竟asm.js 已經不算是寫js了
 不過mobile上面最佔資源的可能還試圖片或是影片, 這些部分的處理就算都用native code, 還是會因為記憶體上的限制, 所以我覺得如果ARM 架構, 能夠支援夠多的記憶體, 那JS慢也就比較無關緊要

[Font] Study note

建議把 FreeType tutorial 上面的文章看完,

下面的圖是從tutorial擷取, 在設定一些字形相關設定,可以了解關於字型的metrics:





除了glyph 本身的bitmap,有時某些字跟前文也有關係,像是當A後面接U的時候, 它們可以減少字距 (kerning), 所以glyph有些也會另外帶kerning tabl,來記錄前後文該有的間距

2013年6月25日 星期二

[Memory] heap profiling

當我們要找 memory usage 的話, 可以使用 Valgrind (Massif), 不過 valgrind有個很大的缺點, 就是他會讓你的程式慢個10倍以上...
今天發現 tcmalloc 也可以使用 heap profiler, 而且使用上也很簡單. 重點是 他沒有valgrind那麼慢!!

在 Ubuntu 12.04 上面, 按照下面步驟~
$ sudo apt-get install google-perftools
# link your program with "-ltcmalloc"
$ HEAPPROFILE=/tmp/profile.log ./program

另外他也提供可以讓你隨時產生 memory dump 的方式, 使用 HeapProfilerStart() and HeapProfilerStop() 來指定你甚麼時候要開始進行 heap profiling, HeapProfilerDump 則可以在你想要dump memory report的dump.

Note:
記得不要傻傻直接去裝 libtcmalloc-minimal0 這個套件, 這個套件沒有把 heap profiler 放進去, 我是在使用上述HeapProfiler function的時候 發現找不到symbol才發現有少裝套件...

查看report
當你跑完廁試之後, 接下來就是要讀懂產生出來的report, 在ubuntu 12.04 你需要安裝 google-perftools, 安裝完後, 會有 google-pprof 這個指令可以用
# 這個指令可以產生gv觀看的圖檔
$ google-pprof --gv program profile.log
# 或是 你只想看text
$ google-pprof program profile.log
Using local file program.
Using local file profile.log.0003.heap.
Welcome to pprof!  For help, type 'help'.
(pprof) top
Total: 21.3 MB
     8.6  40.5%  40.5%      8.6  40.5% Foo1
     7.2  33.7%  74.2%      7.2  33.9% Goo1 (inline)
     2.0   9.4%  83.6%      2.0   9.4% 00007f9f7c292daf
     0.8   3.7%  87.3%      0.8   3.7% 00007f9f7751424c
     0.4   1.8%  89.1%      0.7   3.2% Filter_32_alpha_portable (inline)
     0.3   1.4%  90.5%      0.3   1.4% 00007f9f806d3480
     0.2   1.0%  91.5%      0.6   2.6% ZZZ (inline)
     0.2   0.8%  92.3%      0.2   0.8% 00007f9f7f86b0ca
     0.2   0.8%  93.1%      0.2   0.8% 00007f9f718c673f
     0.1   0.7%  93.7%      0.1   0.7% 00007f9f7ecdb79d
     0.1   0.5%  94.3%      8.7  41.0% OOO
(pprof)

2013年6月14日 星期五

[Shared Memory] passing fd across processes

Posix shared memory 允許使用類似file descriptor的方式來操作, 當使用shm_open取出 FD 之後, 後面你可以使用傳統 file descriptor 相關的 system call, ex: ftruncate, fstat.

chromium 裡面也有提供shared memory的wrapper, 但是看到下面的code, 覺得怎麼可能這麼簡單, duplicate FD, 然後 IPC 送出去, 其他 process 就可以使用?!
bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
                                        SharedMemoryHandle *new_handle,
                                        bool close_self) {
  const int new_fd = dup(mapped_file_);
  if (new_fd < 0) {
    DPLOG(ERROR) << "dup() failed.";
    return false;
  }

  new_handle->fd = new_fd;
  new_handle->auto_close = true;

  if (close_self)
    Close();

  return true;
}


仔細 trace 了一下 code, 果然有些細節在裡面, 發現 chromium IPC 是用 socketpair, 這會create 一對 connected UNIX domain sockets 來做IPC, 但是在 serialize 的過程中還有一些 trick 要做, 不過細節上大概就跟 這邊這裡 (control message on UNIX domain socket) 提的一樣. chromium 是實做在 Channel::ChannelImpl::ProcessOutgoingMessages 跟 Channel::ChannelImpl::ExtractFileDescriptorsFromMsghdr 這邊. 基本上還是要讓 kernel 了解到 FD 實際對應到的 Open file table (參考TLPI ch5.4) 在不同 process 是一樣的.
所以 receiver process 拿到 FD 跟 memory size之後, 就可以使用 mmap, 來讀取memory~

2012年11月29日 星期四

[iOS] tweak project development


在jailed break的手機當中, 我們如果想要取代掉/新增一些原本apple提供的功能, 我們就必須要寫tweak(我自己理解就是寫hook, 然後讓系>統會自動呼叫到你寫的callback function).

要達到這件事情, 除了之前教的先安裝theos之外, 我們還必須使用ios private framework (也就是apple沒公開的SDK), 這邊有兩種方式


  1. generate header from class-dump or class-dump-z tool
    $ class-dump -H /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices
    $ ls
    BKSAccelerometerDelegate-Protocol.h              SBSCardItem.h
    CDStructures.h                                   SBSCardItemsController.h
    NSCoding-Protocol.h                              SBSCardItemsControllerRemoteInterface-Protocol.h
    NSCopying-Protocol.h                             SBSCompassAssertion.h
    NSObject-Protocol.h                              SBSLocalNotificationClient.h
    SBAppLaunchUtilities.h                           SBSPushStore.h
    SBCardItemsControllerRemoteInterface-Protocol.h  SBSRemoteNotificationClient.h
    SBLaunchAppListener.h                            XPCProxyTarget-Protocol.h
    SBSAccelerometer.h
    
  2. copy others from internet
    (1) https://github.com/nst/iOS-Runtime-Headers/tree/master/PrivateFrameworks
    (2) https://github.com/rpetrich/iphoneheaders
        這是我用的, 使用這個你必須要做一些額外的工作
        
$ find /Applications/Xcode.app/ -name IOSurfaceAPI.h
$ cp /Applications/Xcode.app//Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/IOSurface.framework/Versions/A/Headers/IOSurfaceAPI.h $THEOS/include/IOSurface/
Comment out the following line in this file (IOSurfaceAPI.h):

/* This call lets you get an xpc_object_t that holds a reference to the IOSurface.                                           
   Note: Any live XPC objects created from an IOSurfaceRef implicity increase the IOSurface's global use
   count by one until the object is destroyed. */
//xpc_object_t IOSurfaceCreateXPCObject(IOSurfaceRef aSurface)
//  IOSFC_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA);
                              
/* This call lets you take an xpc_object_t created via IOSurfaceCreatePort() and recreate an IOSurfaceRef from it. */
//IOSurfaceRef IOSurfaceLookupFromXPCObject(xpc_object_t xobj)
//  IOSFC_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA);


我自己是使用別人產生的header, 把這些header copy到$THEOS/include 下面, 接下來就可以進行tweak project了

$ /opt/theos/bin/nic.pl 
NIC 2.0 - New Instance Creator
------------------------------
  [1.] iphone/application
  [2.] iphone/library
  [3.] iphone/preference_bundle
  [4.] iphone/tool
  [5.] iphone/tweak
Choose a Template (required): 5
Project Name (required): ooooo
Package Name [com.yourcompany.ooooo]: 
Author/Maintainer Name [ytshen]:       
[iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]: 
Instantiating iphone/tweak in ooooo/...
Done.
$ ls ooooo/
Makefile    Tweak.xm    control     ooooo.plist theos


接下來你就可以進行tweak的實作, 這邊我在xcode 4.5 + mac os 10.8 lion下面會遇到一些問題, 像是找不到arm6 symbol, 這是因為後來只支援arm7.

要修改Makefile

export ARCHS=armv7
export TARGET=iphone:latest:4.3
SDKVERSION=6.0
 
include theos/makefiles/common.mk
   
TWEAK_NAME = ooooo
ooooo_FILES = Tweak.xm
   
include $(THEOS_MAKE_PATH)/tweak.mk


並且要設定environment $SYSROOT 到你sdk的目錄.

$ echo $SYSROOT 
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/
這邊使用一個很簡單的例子, 我們要改spring board一開始秀出一個alert (spring board就是iOS的桌面程式), 修改Tweak.xm:

#import 
 
%hook SpringBoard
 
-(void)applicationDidFinishLaunching:(id)application {
    %orig; // call the original method
    
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Welcome" 
        message:@"Welcome to your iPhone Brandon!" 
        delegate:nil 
        cancelButtonTitle:@"Thanks" 
        otherButtonTitles:nil];
    [alert show];
    [alert release];
}
%end
接下來就按照之前介紹的theos, make, make package, make package install. 就可以把這個tweak安裝在iPhone上面!

Reference

http://brandontreb.com/beginning-jailbroken-ios-development-your-first-tweak/
http://www.andyibanez.com/2012/07/02/create-a-mobilesubstrate-tweaks/
class-dump:
http://stevenygard.com/projects/class-dump/

2012年11月16日 星期五

[C++] static array size macro

We usually get array size by using the following macro.
#define count_of(arg) (sizeof(arg) / sizeof(arg[0]))
But this code would not get any compile error when we pass the pointer as argument like below:
void Test(int C[3])
{
  int A[3];
  int *B = Foo();
  size_t x = count_of(A); // Ok
  x = count_of(B); // Error
  x = count_of(C); // Error
}
One way is to declare like this: (pass the reference which indicate the number of array)
void Test(int (&C)[3])
{
  ...
}
// reference http://www.cplusplus.com/articles/D4SGz8AR/
Now the following code snippet is creating template function. The function template is named ArraySizeHelper, for a function that takes one argument, a reference to a T [N], and returns a reference to a char [N]. If you give it a non-array type (e.g. a T *), then the template parameter inference will fail.
// reference http://www.viva64.com/en/a/0074/
// http://stackoverflow.com/questions/6376000/how-does-this-array-size-template-work
template 
char (&ArraySizeHelper(T (&array)[N]))[N];
#define arraysize(array) (sizeof(ArraySizeHelper(array)))

2012年10月25日 星期四

[GCC] C++ compiler option for static analysis

GCC compiler option for some C++ checking.

==========================================


-Weffc++ (C++ and Objective-C++ only)                                                                                                                                                   
   Warn about violations of the following style guidelines from Scott Meyers' Effective C++ book:
   
   ·   Item 11:  Define a copy constructor and an assignment operator for classes with dynamically allocated memory.
   
   ·   Item 12:  Prefer initialization to assignment in constructors.
   
   ·   Item 14:  Make destructors virtual in base classes.
   
   ·   Item 15:  Have "operator=" return a reference to *this.
   
   ·   Item 23:  Don't try to return a reference when you must return an object.
   
   Also warn about violations of the following style guidelines from Scott Meyers' More Effective C++ book:
   
   ·   Item 6:  Distinguish between prefix and postfix forms of increment and decrement operators.
   
   ·   Item 7:  Never overload "&&", "||", or ",".
   
   When selecting this option, be aware that the standard library headers do not obey all of these guidelines; use grep -v to filter out those warnings.


-Woverloaded-virtual (C++ and Objective-C++ only)
    Warn when a function declaration hides virtual functions from a
    base class.

-Wsign-promo (C++ and Objective-C++ only)
    Warn when overload resolution chooses a promotion from unsigned or
    enumerated type to a signed type, over a conversion to an unsigned
    type of the same size.  Previous versions of G++ would try to
    preserve unsignedness, but the standard mandates the current
    behavior.

-Wextra
    This enables some extra warning flags that are not enabled by
    -Wall.