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~