2012年6月30日 星期六

用 /etc/hosts.allow 設定允許的連線

man hosts.allow 有說明, 或直接看這篇的說明, 寫這篇只是強化自己記下關鍵字。

現在設定允許的網段連線實在太簡單了, 記得十多年前好像很複雜, 然後記憶就停在十多年前的情況, 一直懶得看怎麼弄 ...

2012年6月28日 星期四

no space left on device

今天踏到 inode 用完的雷, "no space left on device" 除用完空間外, 也有可能是用完 inode , df 看還有剩空間時, 記得用df -i 檢查。

若要個別檢查那個目錄占掉最多 inode, 不知有沒有適當的指令, 我是用 "find DIR | wc -l" 來粗估那個目錄占掉最多個 inode。

2012年6月16日 星期六

如何監控和測量網路流量

兩個月前做的事, 現在已忘了細節, 留些連結備忘。

從 system call 下手

networking - How to measure network performance (how to benchmark network protocol) 提到可以用 strace 抓網路相關的 system call 來了解傳輸量。概念不錯, 但實作用起來很麻煩, 有以下的問題:

  • socket 也是 file descriptor, 不只可以用 send/recv 相關函式, 也可以用 read/write。要做到完全正確, 要追蹤開啟的 fd 是否為 socket
  • 這個傳輸量不等於真正的傳輸量, 因為 TCP 有可能重傳 packet。

優點大概是可以量得很細, 像是各 thread 的傳輸量如何。若 thread 各自有特定的工作, 也許會有幫助。

從網卡下手

tcdpdump:

看完的感覺是, wireshark 似乎不如 tcpdump 強? 附帶一提, tcpdump 名為 "tcp"dump, 但是是監控網卡, 實際上可看各種不同 protocol, 不只 tcp, 滿容易使用的。

IPTraf

附 screenshot 的簡短介紹: 唉呦~MIS先生: 好用的流量監控程式--IPTraf, 可觀看即時流量。很容易操作, 功能也很彈性。不過若要用在反覆執行的測量程式, 可能還是配合 tcpdump 再寫分析的 script 比較方便。

使用 Mac 產品觸控輸入的心得

和 MacBook Air 以及 iPad、iPhone 相處的時間多了一些後, 覺得 Apple 在輸入方式下的工夫真是相當深。

一樣是觸控的輸入方式, 可分成考慮螢幕所在位置和不考慮兩種用法, 比方說 MacBook 的 mouse pad 可用三指向左右滑, 切換畫面; 還有用兩指上下左右滑, 以捲動視窗。前者沒考慮螢幕游標的位置, 後者有。

在 iPad 上可用四指左右滑切換 App, 但在 iPhone 上找不到開啟這功能的選項, 也許是覺得在 iPhone 上用四指不合一般使用電話的姿勢, 寧願讓使用者透過 home 鍵切 app。

題外話, 使用這些裝置的過程中我也才明白實體鍵盤設計的巧妙之處。實體鍵盤的觸感讓我 100% 確定手指在的位置, 還有敲鍵的次數。所以我可以安心地看著另一個裝置的網址, 盲打一串長網址而不會輸入錯。

但反過來要用 iPad / iPhone 輸入網址時, 成功率實在太低, 以致於我寧願先用縮網址服務, 再回到 iPad / iPhone 上輸入縮址。若這個「將桌機的網址「傳到」行動裝置」的使用情境很廣的話, 也許值得針對此點寫個功能, 目前是覺得不值得就是了

寫 linux daemon 的注意事項

一直以來都很納悶為什麼寫 daemon 時需要 double fork, double fork 是必要的嗎? 最後才發覺我問錯問題了, 而問錯問題永遠不會得到對的答案。我該問的問題是, 成為一個 daemon, 必須該做那些事?

答案是:

  1. chdir("/"): 避免有任何目錄因為還有 process 在路徑內, 使得目錄已被移除, 卻無法釋放空間。
  2. 避免成為 zombie: 若 daemon 的 parent process 是 init 的話, daemon 結束時 init 會自動 wait 它, 避免成為 zombie。反之, 則有這點顧慮。
  3. 脫離 terminal: 因為關閉 terminal 的時候, kernel 會送 SIGHUP 給 session leader [*1]。以 shell 的實作來說, shell 是 session leader, 它在收到 SIGHUP 時, 會送 SIGHUP 給它所產生的所有 process group, 而 SIGHUP 預設行為是 terminate。但這不是 daemon 希望的行為, 相較於因此改變 SIGHUP 的行為, 不如脫離 terminal 更省事, 還可視需要保留 SIGHUP 做別的用途 [*2]
  4. 同上, 脫離 terminal 可避免不小心讀寫到 terminal 而收到 SIGTTIN 和 SIGTTOU。它們是 background process 讀寫 terminal 時觸發的, 藉由這樣告知 process 它目前是 background process 並嘗試要讀寫 terminal。雖然也可以改變這兩個 signal 的處理行為 (預設為 stopped), 但是不如完全不會發生來得省事。

有了以上需求, 就有不同的作法。POSIX 沒有定義 daemon() 函式, 不過 BSD 體系包含 Linux 裡有 daemon() 函式, 用來成為 daemon。eglibc 的實作方式如下:

  1. fork 一次, 讓 parent process 掛掉, 以滿足 (2)
  2. 呼叫 setsid() 成為新的 session leader
  3. chdir("/"), 以滿足 (1)
  4. 重導 0, 1, 2 到 /dev/null 以滿足 (3、4)

但 daemon() 沒有做第二次 fork(), 所以它仍是 session leader, 有機會開啟新的 terminal。若要避免這種可能, 呼叫完 daemon() 後再呼叫一次 fork(), 並讓原本的 parent process 離開, 這樣 daemon process 就會處在一個沒有 terminal 也沒有 session leader 的情況, 會更安全。

從再呼叫一次 fork() 來看, 會更能理解為什麼 daemon() 要開新的 session, 這樣在呼叫完 daemon() 後有比較大的主導權, 看是自己想開新的 terminal, 或是再做一次 fork() 確保不存在 session leader, 都沒有問題。

PS

  • *1 看了一些文件, 感覺上 session 是針對 terminal 而有的概念。而 process group 則和使用 signal 有關。
  • *2 有些 daemon 收到 SIGHUP 會重讀設定檔。由於 daemon 不可能觸發原本 SIGHUP 的使用情境, 可以安心拿它來做自己的用途。

2012年6月13日 星期三

在 Linux 上找執行時間的瓶頸

記錄一下自己加速程式的心得。重點是: 有個可靠且易於重覆執行的方式, 來計算執行時間。

logging

我最常用的方法是手動 logging 計算函式的執行時間。通常我有兩種作法

  • 在函式的開頭取得系統時間, 離開時再最得系統時間, 兩者相減得到執行的時間。 [*1]
  • 使用一個會自動附上 timestamp 的 logging function, 會記錄這次到上次 log 的時間差, 或事後用外部 script 算出各筆 log 之間的時間差。這樣可以在懷疑的函式不同地方做 log, 了解各區塊的執行時間。

PS *1 實作細節

  • 像 Python 有 decorator 的語法, 可以寫個 log_time(), 內容是「取得時間、執行目標函式、取得時間並記錄相減結果、傳回目標函式的傳回值」, 再用 decorator 的語法加到有興趣的函式上。
  • C++ 的話, 可以寫個 class LogTime, 在 constructor 以及 destructor 計時, 達到同樣效果。然後在目標函式的第一行宣告 LogTime log。

優點

  • 可以明確抓出函式花的時間, 對於「加快程式」來說, 是最確實的反應。不論是真的 CPU bound 或 lock 或 I/O 導致緩慢, 都會反應在 log 裡。
  • 可自行控制 log 函式的細膩度, 比方說先抓出 sort() 最花時間, 再來到 sort 裡放 log, 觀察在 sort 的那部份最花時間。

缺點

  • 得自己手動在懷疑的部份加上 log 函式, 不方便大範圍無腦偵查。

使用 profiler

linux - Alternatives to gprof 列了不少工具, 大概掃過了這篇, 也試了一下, 這部份的經驗很淺, 下面可能會有些錯誤, 像是對工具的錯誤認知, 或少用了什麼功能而覺得不好用。

感覺上這類工具只能反應出真的 CPU bound, 若原因是 lock 或 I/O 拖慢效能, 需要用其它管道查明源頭。

我是在 VirtualBox 裡的 Ubuntu 11.04 試用。選用的前提是對實際執行的負擔要低, 愈接近原本情況愈好。

perf

perf 很容易使用, 基本指令:

  • perf record CMD # 執行並記錄 CMD
  • perf record -p PID # 記錄 process PID
  • perf report # 看報告
  • sudo perf top # 顯示即時全系統狀況

但不知為啥占最多時間的總是奇怪的東西, 我寫個 for-loop 一直做加法, 結果部份時間花在 snd_ac97_codec (聲音?)。移除 PulseAudio 後, 變成花在 binfmt_misc。對於其它不是像 busy loop 的程式, 有可能最花時間的部份變成 snd_ac97_codec 或 binfmt_misc。讓我不知是否能相信它的結果。

2013-04-17 更新

在實體機器 (非VM) 上執行 perf 後, 就沒有一堆怪東西了。試用的結果相當滿意, perf 明顯的好處有兩點:

大概會讀一些組語的話, 用 perf 的效果更好, 可以在 perf report 後再觀看各函式最花時間的位置, perf 會嘗試對回組語附近的原始碼。注意 perf 觀察到的是 sample 結果, sample 量愈多, 可以採信的程度愈深。比方說 sample 量「不夠多」的話, 可以參考那個函式最花時間, 但可能不適合參考函式內最花時間的程式是那幾行。

oprofile

oprofile 也不難用, 但在 VM 裡會有些問題, 且無法發揮完整功能。解決的方法是在啟動 oprofile daemon 前就執行 sudo modprobe oprofile timer=1。若有先執行過 oprofile, 即使照著上面說的執行 --deinit, 結果在執行 modprobe 時會卡住。用 strace 看的結果, 像在 busy-waiting oprofile 結束。重開機後, 在執行 oprofile 前先執行 modprobe 就 ok。

小結相關指令如下:

  • sudo modprobe oprofile timer=1 # 可配合 dmesg | grep oprofile 看目前是否有用 timer interrupt
  • sudo opcontrol --start --verbose --no-vmlinux # 見後面的說明
  • sudo opcontrol --reset # 將記錄歸零
  • sudo opcontrol --dump # 將記錄寫到硬碟
  • opreport # 顯示整體摘要
  • opreport -l PROGRAM # 顯示 PROGRAM 的取樣情況
  • opreport -l PROGRAM -g # 加上原始碼位置和行號
  • sudo opcontrol --shutdown # 結束 daemon

啟動 daemon 後, 之後就是一直

  • ./PROG
  • sudo opcontrol --dump
  • opreport -l ./PROG
  • sudo opcontrol --reset

但是在沒有 vmlinux 的情況, 會看到有大部份時間花在 no-vmlinux (kernel 裡)。所以除非自己寫的部份真的相當忙, 幫助也是有限。我在 Ubuntu 上找了一陣子, 有文章提到裝別人弄好的 vmlinux, 不過沒有成功, 就先忽略這件事了。

對照 perfoprofile 反應的數據, 兩者各有一塊不明的部份占去最多時間, 其它項目的相對大小很接近, 多少算是提示。但我會懷疑數據反應出的實際影響。同一個函式, perf 可能說 20%, 但 oprofile 說 15%, 結果我也無法明白它們實際的執行時間有多長。

GooglePerformanceTools

gperftools 看起來也滿不錯的 --- 直到我抓下來看到 INSTALL 裡對於 x86-64 的注意事項後。於是我決定之後再來試用它, 至少先玩過 tcmalloc 後, 再回來看這個吧。

2012年6月11日 星期一

注意 ptrace 的權限設定

gdb、strace 都是用 ptrace 來監控另一個 process 的情況, 經 wens 提醒關於權限設定的事。

基於安全考量, Ubuntu 10.10 開始, 即使 effective uid 相同, 預設只能對後代 process 用 ptrace。其它情況得用 root 權限執行才可以。在自己的開發機上, 為了方便起見, 可以取消這個限制:

  • 更改目前設定: echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope sysctl
  • 開機後自動生效: 改 /etc/sysctl.d/10-ptrace.conf

C++ 能否用 memcpy 複製 class / struct 的資料?

答案是: POD (plain old data) type 可以。POD type 可和 C 互通, CPP Reference POD Type 的介紹: Specifies that the type is POD (Plain Old Data) type. Thi...