2013年1月28日 星期一

Linux Control Group 介紹

Control Group 簡稱 cgroup,是 linux kernel 裡的一個功能, 用來限制、記錄、隔離資源使用。
最早於 2006 年由 google 工程師開發,後來合併到 kernel 2.6.24 中。

cgroup 的特點有以下幾種:

1. 限制資源的使用:執行某個應用程式,卻佔掉大部份的系統資源,導致別的程式根本無法執行,或在多核心的機器上,讓某應用程式只能使用某些核心,保留一些給其他程式用,或限制某程式最多使用 2G 的記憶體。

2. 使用資源的優先權:有沒有辦法調整讓 A 程式比 B 程式多用一些 cpu 呢?

3. 記錄 cpu 使用量以收取費用:對某些公司來說,cpu 的使用是要收費的,但要如何算出使用者到底使用了多少 cpu 呢? 早期這類的工作是很繁雜的,一般是透過 psacct 來收取整個系統上所有指令使用的 cpu 時間,再寫一些 scripts 來分析出各個使用者的 cpu 使用量,產生報表,現在透過 cgroup 可以很容易的抓出資料。

4. 隔離不同群組的 process:對於不同群組的 process 做到隔離,可用於 lxc (linux container)。

5. freezing groufreezing groups or checkpointing and restarting: 假設一個程式執行要 8 小時 cpu 時間才能完成,但跑到 7.3 小時卻因為某狀況導致失敗,等故障排除後,要再重頭開始跑 8 小時,這樣很沒效率。若在中間有做 checkpoint,假設每小時一次,則可以從 7 小時的部份接續下去跑,理論上是很完美,只是不知道現在 cgroup 能做到什麼程度就是。

這邊以實例來操作 cgroup ,目前在 debian wheezy 上有遇到一些問題,只能使用 root 使用者來分配資源,而無法以一般使用者,還沒找出問題在哪,所以先用 arch linux 為例,基本上,目前 cgroup 的實作,試過幾個 distribution,都大同小異,fedora、ubuntu、arch linux,都是類似,試過都沒問題,但 debian wheezy 則有點不同。


進入系統後,首先檢查 cgroup 是否有掛載起來:
$ mount | grep cgroup
tmpfs on /sys/fs/cgroup type tmpfs (rw,nosuid,nodev,noexec,mode=755)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct,cpu)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/net_cls type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)

在 arch linux 中,可看到 cgroup 掛載於 /sys/fs/cgroup/ 底下,接著檢查系統的 cgroup 支援哪些 controller.

$ cat /proc/cgroups
#subsys_name hierarchy num_cgroups enabled
cpuset      2     3     1
cpu           3     14   1
cpuacct    3     14   1
memory    4     1     1
devices     5     1     1
freezer     6     1     1
net_cls     7     1     1
blkio         8     1     1

debian wheezy 預設 memory 是沒啟動的,可在開機時 grub 加入 cgroup_enable=memory 來開啟。

由於 cgroup 的 controller 滿多,功能也很廣,這邊只針對幾個做說明。
cpuset: 設定使用那幾個 cpu core.
cpu 和 cpuacct 是同一個:設定 cpu shares,share 值越大,能用 cpu 的時間越多。
memory:限制記憶體使用量。


要使用 cgroup,可透過底下幾個方法:
1. 直接以命令列指令存取 /sys/fs/cgroup 來達到。
2. 使用 libcgroup 的一些指令,像 cgcreate, cgexec, cgclassify 來操作。
3. 透過 LXC 來實作。

這邊介紹 1, 2 種方法,lxc 則留著以後再分享。


以命令列指令存取 cgroup:

操作前準備:
以 root 來建立 low 群組,low 繼承了 cpu controller 的所有屬性
$ sudo mkdir /sys/fs/cgroup/cpu/low

將權限開給 behappy 使用者
$ sudo chown behappy:users -R /sys/fs/cgroup/cpu/low

cpu share 預設為 1024
$ cat /sys/fs/cgroup/cpu/low/cpu.shares
1024

以一般使用者將之 low 群組設成 512
$ echo 512 > /sys/fs/cgroup/cpu/low/cpu.shares

重覆上面,建立 high 群組,cpu share 設為 2048
$ sudo mkdir /sys/fs/cgroup/cpu/high
$ sudo chown behappy:users -R /sys/fs/cgroup/cpu/high
$ echo 2048 > /sys/fs/cgroup/cpu/high/cpu.shares

另外建立 first_core、second_core 群組,為 cpu 第一個核心及第二核心,位於 cpuset controller 底下。
$ sudo mkdir /sys/fs/cgroup/cpuset/first_core
$ sudo chown behappy:users -R /sys/fs/cgroup/first_core

$ sudo mkdir /sys/fs/cgroup/cpuset/second_core
$ sudo chown behappy:users -R /sys/fs/cgroup/second_core

檢視原本 cpuset 裡的設定:
$ cat /sys/fs/cgroup/cpuset/cpuset.cpus
0-1
有二個 cpu core 0 和 1

而我們建立的 first_core 及 second_core 裡的設定是空的
$ cat /sys/fs/cgroup/cpuset/first_core/cpuset.cpus

將 first_core 群組設成第一個 cpu core:
$ echo 0 > /sys/fs/cgroup/cpuset/first_core/cpuset.cpus

將 second_core 群組設成第二個 cpu core:
$ echo 1 > /sys/fs/cgroup/cpuset/second_core/cpuset.cpus

這樣大致上準備完成,接著開始試驗。

拿 /usr/bin/yes 這指令來操 cpu,為了易於閱讀,設置二個執行檔:
$ cp /usr/bin/yes /tmp/yes_low
$ cp /usr/bin/yes /tmp/yes_high

另外開個 top 在旁邊觀看 cpu 使用情形,按 1 來顯示各別 cpu core 使用情形
$ /tmp/yes_low &>/dev/null &
$ /tmp/yes_high &>/dev/null &

$ top
top - 13:14:41 up 3:34, 2 users, load average: 0.85, 0.34, 0.16
Tasks: 119 total, 3 running, 114 sleeping, 2 stopped, 0 zombie
%Cpu0 : 99.3 us, 0.7 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 99.7 us, 0.3 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem: 3951368 total, 1223052 used, 2728316 free, 150640 buffers
KiB Swap: 3145724 total, 0 used, 3145724 free, 531504 cached

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
9860 behappy 20 0 7120 356 284 R 99.9 0.0 0:11.32 yes_low
9861 behappy 20 0 7120 356 284 R 98.6 0.0 0:08.98 yes_hig

下方可看到二個程式,各佔 cpu 99%,而上面則顯示目前二個 cpu core 都是 99% 使用率,這是正常的狀況下。

接著我們將 yes_low 加入到 low 群組
$ echo 9860 > /sys/fs/cgroup/cpu/low/tasks

將 yes_high 加入到 high 群組
$ echo 9861 > /sys/fs/cgroup/cpu/low/tasks

理論上 top 所看到的 cpu 使用狀況應該有變化,但是並沒有,因為有二個 cpu core,而使用 cpu 的程式也是二個而已,所以在夠用的情況下,二個程式都可以取得所需的資源,因此一樣佔用 99%,所以我們要讓二個程式使用同一個 cpu core 才行。

$ echo 9860 > /sys/fs/cgroup/cpuset/first_core/tasks
-bash: echo: write error: No space left on device

哦哦,失敗,要先設定 cpuset.mems 才行,不知道為什麼 :)
$ echo 0 > /sys/fs/cgroup/cpuset/first_core/cpuset.mems

再設定一次就可成功
$ echo 9860 > /sys/fs/cgroup/cpuset/first_core/tasks

將 yes_high 也加入 first_core 群組
$ echo 9861 > /sys/fs/cgroup/cpuset/first_core/tasks

過個三秒後,應該可看到 top 上的變化
$ top
top - 13:14:41 up 3:34, 2 users, load average: 0.85, 0.34, 0.16
Tasks: 119 total, 3 running, 114 sleeping, 2 stopped, 0 zombie
%Cpu0 : 99.8 us, 0.7 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 1.7 us, 0.3 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem: 3951368 total, 1223052 used, 2728316 free, 150640 buffers
KiB Swap: 3145724 total, 0 used, 3145724 free, 531504 cached

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
9861 behappy 20 0 7120 356 284 R 79.9 0.0 0:11.32 yes_high
9860 behappy 20 0 7120 356 284 R 20.2 0.0 0:08.98 yes_low

很明顯上方可看到,第一個 cpu core 用了 99.8%,而第二個就只有 1.7%,因為我們設定 yes_high 及 yes_low 都只使用第一個 cpu core;接著下方,由於 yes_low 比重是 512,yes_high 是 2048,為 1:4,因此 cpu loading 也趨近於 1:4 ( 20.2 : 79.9 )。

這樣空下一顆 cpu core 可以用來做其他事情,而不會導致系統變得很頓。

cpuacct 的部份,在剛建立一個 cpu 或 cpuacct 群組時,cpuacct.usage 為 0,像剛才建立的 high 群組
$ cat /sys/fs/cgroup/cpu/high/cpuacct.usage
0

經過執行了 yes_high 並加入 high 群組後,cpuacct.usage 就會開始累計,所以看內容就可知道用了多少 cpu time,單位為 ns (nano second,十的負九次方秒)。
$ cat /sys/fs/cgroup/cpu/high/cpuacct.usage
22493005441
這樣大概就是 22.5 秒,但觀察 cpuacct.stat 可看到,這 22.5 秒是 user + system 全部總合,因此要看 cpuacct.stat 裡面 user 的部份才是真正 user 使用的 cpu time,約 22.44 秒。

$ cat /sys/fs/cgroup/cpu/high/cpuacct.stat
user 2244
system 7

另外,由於只用到第一個 cpu core,因此在 cpuacct.usage_percpu 中看到第二個 cpu core cpu time 為 0
$ cat /sys/fs/cgroup/cpu/high/cpuacct.usage_percpu
22493005441 0

memory 的部份,一樣先建立一個群組,設定好限制,再將程式加入此群組即可。
以 root 建立一個 mymemory 群組
$ sudo mkdir /sys/fs/cgroup/memory/mymemory
$ sudo chown -R behappy:users /sys/fs/cgroup/memory/mymemory

用一般使用者設定記憶體上限為 10M Bytes
$ echo 10000000 > /sys/fs/cgroup/memory/mymemory/memory.limit_in_bytes

在旁邊先開個 terminal 來監控記憶體運作情形,使用 free,來觀察記憶體變化
$ watch free

然後開啟一個 shell,並將 shell 加入 mymemory 群組,這樣從這個 shell 裡所執行的程式,都屬於 mymemory 群組。
$ bash

找出剛才執行 bash 的 pid
$ echo $$
5312

將 bash 加入 mymemory 群組
$ echo 5312 > /sys/fs/cgroup/memory/mymemory/tasks

加入後,執行一個超過 10M 記憶體的程式,如 libreoffice、或看看影片,可立刻看到記憶體監控視窗中,已開始用到 swap 了,因為只給 10M,但不夠用,會自動使用 swap,印證我們限制記憶體使用是成功的。

操作上大致是如此,但是若每次都以存取 /sys 來動作,似乎很麻煩,因此有 libcgroup 的工具可用。


以 libcgroup 存取 cgroup:


fedora 是 libcgroup,直接裝上即可,而 debian 及 ubuntu 除了安裝 libcgroup1 還要再加上 cgroup-bin。

arch linux 從 AUR 中裝上:
$ yaourt -S libcgroup

以 libcgroup 來重覆上面建立 first_core, second_core, high, low 群組的指令。
建立 first_core 群組
$ sudo cgcreate -a behappy:users -t behappy:users -g cpuset:/first_core

建立 second_core 群組
$ sudo cgcreate -a behappy:users -t behappy:users -g cpuset:/second_core

建立 high 群組
$ sudo cgcreate -a behappy:users -t behappy:users -g cpu:/high

建立 low 群組
$ sudo cgcreate -a behappy:users -t behappy:users -g cpu:/low

設定 first_core 群組的 cpuset.cpus 為第一個 cpu core
$ cgset -r cpuset.cpus=0 /first_core

設定 second_core 群組的 cpuset.cpus 為第二個 cpu core
$ cgset -r cpuset.cpus=1 /second_core

設定 high 群組的 cpu.shares 為 2048
$ cgset -r cpu.shares=2048 /high

設定 low 群組的 cpu.shares 為 512
$ cgset -r cpu.shares=512 /low

指定 yes_high 到 first_core 群組
$ cgclassify -g cpuset:/first_core 9861

指定 yes_low 到 first_core 群組
$ cgclassify -g cpuset:/first_core 9860

指定 yes_high 到 high 群組
$ cgclassify -g cpu:/high 9861

指定 yes_low 到 low 群組
$ cgclassify -g cpu:/low 9860

cgclassify 是用於將已執行中的程式指到一個群組,而 cgexec 則用來執行一個程式,並將之加入一個群組。
執行 /tmp/yes_high &>/dev/null & 這指令,並將之加入 first_core 及 high 群組
$ cgexec -g cpu:/high -g cpuset:/first_core /tmp/yes_high &>/dev/null &

執行 /tmp/yes_low &>/dev/null & 這指令,並將之加入 first_core 及 low 群組
$ cgexec -g cpu:/low -g cpuset:/first_core /tmp/yes_low &>/dev/null &

檢視 yes_low 使用了多少 cpu time:
$ cgget -r cpuacct.usage /low
/low:
 cpuacct.usage: 22493005441

memory 的部份:
$ sudo cgcreate -a behappy:users -t behappy:users -g memory:/mymemory
$ cgset -r memory.limit_in_bytes=10000000 /mymemory


還不錯用,至少比 echo xx > 什麼的方便多了不是嗎?


但我們建立的群組,重新開機後就會不見,因此要寫在 /etc/cgconfig.conf 中,然後開機時啟動 cgconfig service
$ cat /etc/cgconfig.conf
group first_core {
        perm {
                task {
                      uid = behappy;
                }
                admin {
                      uid = behappy;
                }
        }
        cpuset {
                cpuset.mems = "0";
                cpuset.cpus = "0";
        }
}

group second_core {
         perm {
                task {
                        uid = behappy;
                }
                admin {
                        uid = behappy;
                }
         }
         cpuset {
                  cpuset.mems = "0";
                  cpuset.cpus = "1";
         }
}

group low {
         perm {
                   task {
                           uid = behappy;
                   }
                   admin {
                            uid = behappy;
                   }
          }
           cpu {
                  cpu.shares = "512";
           }
}

group high {
           perm {
                     task {
                               uid = behappy;
                     }
                     admin {
                               uid = behappy;
                     }
            }
            cpu {
                     cpu.shares = "2048";
            }
}

group mymemory {
            perm {
                       task {
                               uid = 1000;
                       }
                       admin {
                               uid = 1000;
                        }
             }
             memory {
                        memory.limit_in_bytes = "10000000";
             }
}

$ sudo systemctl start cgconfig

可是,若每次執行程式,都要手動加入到某個群組,還是很麻煩啊?沒問題,有 cgrulesengd 這個 daemon 來幫助我們,依照 /etc/cgrules.conf 所指定的,自動在程式執行後加入群組中,開機時要啟動 cgred service。
$ cat /etc/cgrules.conf
#《user》                                  《controllers》《destination》
#《user》:《process name》   《controllers》《destination》
behappy:yes_high                      cpuset              first_core
%                                                  cpu,cpuacct     high

behappy:/tmp/yes_low                cpuset              first_core
%                                                  cpu,cpuacct     low


$ sudo systemctl start cgred

排除註解總共 4 行,第 1 行是將使用者 behappy 執行的 yes_high 加入 cpuset controller 中的 first_core 群組
第 2 行前面是 %,表示接續第一行過來,若前面寫得和第一行一樣,則在找到第一行符合條件套用後就會離開,加 % 表示第 2 行和第 1 行是同一行指令,所以會 1,2 行都套用後才離開。

所以 1,2 行一組,表示將 behappy 的 yes_high 加入 first_core 及 high 群組。
3,4 行表示將 behappy 的 yes_low 加入 first_core 及 low 群組。

記得,在 cgrulesengd 啟動後,先前已執行的程式並不會變動,只有從 cgrulesengd 啟動後才執行的程式會自動加入群組。

另外,libcgroup 還有幾個指令:
$ cgdelete: 刪除某個群組
$ sudo cgdelete -g cpuset:first_core

cgclear: 清除所有群組 (這指令儘量不要下,否則全空了),若全部不見了,寫個 /tmp/cgconfig.conf,內容如下,並以 cgconfigparser 來載入:
mount {
     cpuset = /sys/fs/cgroup/cpuset;
     cpu = /sys/fs/cgroup/cpu,cpuacct;
     cpuacct = /sys/fs/cgroup/cpu,cpuacct;
     memory = /sys/fs/cgroup/memory;
     devices = /sys/fs/cgroup/devices;
     freezer = /sys/fs/cgroup/freezer;
     net_cls = /sys/fs/cgroup/net_cls;
     blkio = /sys/fs/cgroup/blkio;
}

cgconfigparser: 檢查 cgconfig.conf 設定檔的格式錯誤,若沒問題則載入。
$ cgconfigparser -l /tmp/cgconfig.conf

cgsnapshot: 將目前 cgroup 狀態 dump 下來,可存成設定檔。
$ cgsnapshot > /tmp/cgconfig.conf


總結:
Cgroup 是非常複雜的東東,這邊只做基本介紹,有興趣可到 /sys/fs/cgroup 裡去看看每個檔案的內容。
現在 linux 有了 cgroup 後,簡直是如虎添翼,擁有早期只有大型主機 + 商用unix 才有的功能,現在 linux + PC 就可達到,真是越來越強了。


參考文件:
1. http://en.wikipedia.org/wiki/Cgroup
2. https://wiki.archlinux.org/index.php/Cgroups
3. http://www.kernel.org/doc/Documentation/cgroups/cgroups.txt
4.  https://access.redhat.com/knowledge/docs/en-US/Red_Hat_Enterprise_Linux/6/html/Resource_Management_Guide/index.html

2013年1月12日 星期六

MagicScroll - 網頁如何捲動 (scrolling) 才不會破壞閱讀的節奏

很有趣的研究,的確如作者說的,scrolling 對瀏覽地圖或試算表來說,是很聰明的方式,但是對於文字來說,會破壞了閱讀的節奏。

直接看網站就知道是如何運作:
http://www.magicscroll.net/ScrollTheWeb.html

底下有 chrome 的外掛可安裝。

若是 firefox 則將最下方連結直接拖拉到 firefox 的 "書籤工具列" 上,然後開啟要閱讀的網站,按下書籤工具列上的 "Read With MagicScroll",即可開始舒服的閱讀。

2013年1月11日 星期五

使用工具來調整螢幕色溫,讓眼睛不容易疲勞

由於長時間在電腦螢幕前,有時候越看越覺得刺眼,因此都會手動調整亮度,尤其是白天和晚上的亮度都要調,有點麻煩。

最近看到了可調整螢幕的色溫來讓眼睛不容易疲勞,而且有 linux 的版本可用,因此試了一下,果然非常好用,雖然調整色溫可從螢幕的設定裡面改,但是一天若要調好幾次還是很麻煩,若用程式隨時調整不是更方便。

目前有看到二套,一套是 flux (註1),支援多平台。flux 是 command line 工具,有另一個 gui 介面可使用 fluxgui (註2)

另一套叫 redshift (註3),也支援多個平台,一樣是 command line 工具,也有另一個 gui 可用,叫 gtk-redshift。

這類軟體都是用所在經緯度來判斷目前是白天或晚上,然後套用預設的色溫,就僅僅如此而已。

由於要知道是白天或晚上,所以要自行設定所在經緯度,可從 google map 以中文地址來查詢 (註4),或是由另一個網頁直接以中文地址查詢 (註5),比用 google map 還方便

debian 只包 redshift 及 gtk-redshift,所以就介紹 redshift。

$ sudo apt-get install redshift gtk-redshift

執行:
$ gtk-redshift  -l  緯度:經度

例如台中二中:
$ gtk-redshift  -l  24.15220:120.67541

基本上整個台灣的白天和晚上切換都差不了幾分鐘,所以指向台北也沒關係。


redshift 預設色溫,白天為 5500K,晚上為 3700K。若是預設的不喜歡,可自行以 -t 調整。

gtk-redshift 似乎沒有使用設定檔,所以每次都要下這個指令來啟動。


而在 arch linux 下的 redshiftgui (註6) 就更好用了,除了可儲存設定,還可以直接用滑鼠來隨時調整色溫,可從 aur 中安裝。

不過要特別注意,redshiftgui 的官方網站已變成廣告網站,不要到處抓 redshiftgui binary 執行檔,只從 github 中抓原始檔自己編就好,否則有可能抓到有的沒的。


參考連結:
1. http://stereopsis.com/flux/
2. https://github.com/Kilian/f.lux-indicator-applet
3. http://jonls.dk/redshift/
4. http://blog.soft.idv.tw/?p=1190
5. http://universimmedia.pagesperso-orange.fr/geo/loc.htm 
6. https://github.com/maoserr/redshiftgui

2012年12月22日 星期六

檢查磁碟使用量的工具


通常 notebook 的硬碟都不會太大,再加上使用 lvm 裝了七、八個 OS,所以很快就滿了,因此常常處於需要清理磁碟空間的狀況,但是這卻不是件容易的事,要找出哪些該清、哪些能清要耗掉滿多時間的。

當然,能用的工具多不勝數,底下只介紹幾個工具:

一、du 指令:

$ du -hax --max-depth=1 ./ | sort -h
7.9M ./Fonts
54M ./Scratch
352M ./nitdroid
398M ./proxmox-ve_2.2-7f9cfa4c-28.iso
3.8G ./raspberrypi
6.1G ./

檢查目前目錄中所有檔案的使用情形,只列出第一層目錄,並將結果由小到大排列。
這樣就可以很容易的看出哪些檔案或目錄佔掉大部份的磁碟空間。
假設我們要再檢查 ./raspberrypi 裡的資料, 要再下一次指令:
$ du -hax --max-depth=1 ./raspberrypi | sort -h
2.8M ./raspberrypi/apps
149M ./raspberrypi/games
160M ./raspberrypi/archlinux
273M ./raspberrypi/gentoo-raspberry
279M ./raspberrypi/opensuse
539M ./raspberrypi/raspbian
575M ./raspberrypi/fedora
659M ./raspberrypi/xbian
742M ./raspberrypi/qtonpi
3.8G ./raspberrypi

加 --time 可顯示最後修改時間

二、ncdu:

$ ncdu -x ./
--- /media/share/download
3.8GiB [##########] /raspberrypi
397.4MiB [# ] proxmox-ve_2.2-7f9cfa4c-28.iso
384.6MiB [ ] RacyPy2.iso
351.6MiB [ ] /nitdroid
70.5MiB [ ] /wine
53.6MiB [ ] /Scratch
47.1MiB [ ] GIMP+Magazine+Issue+1.pdf
46.5MiB [ ] slitaz-armhf-mini-2012-12-14.zip

非常直覺,以上下左右鍵來移動光棒,在目錄上按 Enter 即可進入下層目錄,一目瞭然。


三、 xdiskusage:

上二個都是在命令列或終端機執行,有些人看到醜醜的就不想用,沒關係,有圖形介面的。
$ xdiskusage -a ./
出現一個視窗,最左方是第一層起始目錄,右方則是裡面的子目錄,也是滿直覺的,一看就知道哪個目錄佔掉大部份空間。


圖1 顯示 ./ 使用 6.052G,而中間 raspberrypi 用掉 3.797G,接著看到 raspberrypi 裡最下層子目錄 games 佔掉 148.5M,可是再下去太小了,看不清楚,以滑鼠左鍵點 games 二下即可以 games 為第一層目錄,這樣就全部跟著放大,不會看不清楚了。也可以用上下左右鍵來移動,Enter 來進入該層目錄,左鍵回上一層。


圖2為 games 裡的資料,經過放大後看得很清楚。


xdiskusage 還可以從 standard input 來輸入 du 的資料:
$ du -k . | xdiskusage


四、agedu:

先掃描要檢查的目錄,並記錄在 ./agedu.dat 中
$ agedu -s ./

讀入 ./agedu.dat 並 listen localhost tcp port 34769
$ agedu --files -w
Using Linux /proc/net magic authentication
URL: http://localhost:34769/


以瀏覽器打開 http://localhost:34769 即可,如圖3。
agedu 有一項別套沒有的特點,就是可直接看顏色來判斷這個目錄有多久前存取,紅色表示二個月以上沒修改,對於我們判斷要不要清除很好用的。滑鼠移至顏色上方,能看見這目錄多久前存取過。

agedu 預設只能看目錄,無法看到各個檔案大小,可加 --files 來看所有檔案。
$ agedu --files -w

也可以像 du 指令一樣在 terminal 中使用
$ agedu -t ./

還有滿多參數的,請自行參考
$ man agedu


有了這些工具後,對於清理磁碟榨出空間的工作,不再是那麼煩人了。

2012年12月5日 星期三

Raspberry Pi GPIO 介紹及基本使用

開始要玩 gpio 時,才發現買的外殼不合,要拆開蓋子才能插排線,所以若有買殼時要注意一下,若不合不如不要用外殼。不過,最近看新版的壓克力殼有在上方開一條縫能走 gpio 排線就是。最好買只有上下二片的外殼最適合玩 gpio(註1)。

樹莓派連麵包板的 gpio 排線,可以拿現成的磁碟機或硬碟排線來改,不過要注意,有些排線中間是有跳過的(註2)。小弟本身是用硬碟排線來改,花了些錢買一堆小零件,加工了好幾個小時,終於做好,結果拍賣上賣的一條也不過 70 元,又精緻又美觀(註3),光買零件就花了大概 30 元,弄了好久,後來還發現有時會接觸不良,實在不划算,因此建議直接買現成的就好。

一開始看文件時,由於型號分成 model A、model B,然後版本又分 rev 1、rev 2,版本間的 port 又有小部份修改,有些文章寫出要接在哪個 port,甚至連圖都有,但麵包板插好還是不會動,而且很多網頁都有提到要小心,否則會將 Raspberry Pi 給燒掉,所以文件 k 到第三天後才敢開始在麵包板上插零件。而且一開始還鬼打牆真的弄錯,上下顛倒,還好沒燒掉。最主要不要去接到 5V 就好。
建議先做個保護電路來用(註4),否則燒掉了可惜,但是,完全看不懂啦,只好小心點就是。

gpio 腳位:
P1: The Main GPIO connector:

wiringPi Pin BCM GPIO Name Header Name BCM GPIO wiringPi Pin
– – 3.3v 1 | 2 5v – –
8 R1:0/R2:2 SDA0 3 | 4 DNC – –
9 R1:1/R2:3 SCL0 5 | 6 0v – –
7 4 GPIO7 7 | 8 TxD 14 15
– - DNC 9 | 10 RxD 15 16
0 17 GPIO0 11 | 12 GPIO1 18 1
2 R1:21/R2:27 GPIO2 13 | 14 DNC – –
3 22 GPIO3 15 | 16 GPIO4 23 4
– – DNC 17 | 18 GPIO5 24 5
12 10 MOSI 19 | 20 DNC – –
13 9 MISO 21 | 22 GPIO6 25 6
14 11 SCLK 23 | 24 CE0 8 10
– – DNC 25 | 26 CE1 7 11


P5: The auxilliary GPIO connector on Rev. 2 boards:

wiringPi Pin BCM GPIO Name Header Name BCM GPIO wiringPi Pin

– – 5v 1 | 2 3.3v – –
17 28 GPIO8 3 | 4 GPIO9 29 18
19 30 GPIO10 5 | 6 GPIO11 31 20
– – 0v 7 | 8 0v – –
表1

其中 DNC -> Do Not Connect 接腳就是不要使用的意思,因為未來可能會改變配置。

P1 總共有 26 支腳,有 8 個 GPIO port,其他的有 i2c, UART, SPI, 3.3V, 5V, GND 等等。

其中 2 個 5V、2 個 3.3 V、5 個 GND,除了這 9 個以外,其他都可以設定成 GPIO 來使用,加起來共有 17 個。

rev 2 則多加了 P5,只要焊上針腳,又多了4個 gpio 可使用,總共 21 個。


如何控制 gpio port

- 從命令列直接控制
- 使用 WiringPi
- 使用 python
- 使用 Webiopi
- 多種語言範例(註5)


從命令列操作 :


$ ls -l /sys/class/gpio/
--w------- 1 root root 4096 Nov 30 19:37 export
lrwxrwxrwx 1 root root 0 Nov 30 19:34 gpiochip0 -> ../../devices/virtual/gpio/gpiochip0
--w------- 1 root root 4096 Nov 30 19:34 unexport

假設要使用 gpio17,送出一個 port number 到 export 即可起始這個 port
$ sudo sh -c “echo 17 > /sys/class/gpio/export”

由於使用到輸出入轉向,又用 sudo 的話,命令變得不易閱讀,所以乾脆切到 root 去
$ sudo su -

重覆剛才指令
# echo 17 > /sys/class/gpio/export

# ls -l /sys/class/gpio/
total 0
--w------- 1 root root 4096 Nov 30 19:37 export
lrwxrwxrwx 1 root root 0 Nov 30 19:38 gpio17 -> ../../devices/virtual/gpio/gpio17
lrwxrwxrwx 1 root root 0 Nov 30 19:34 gpiochip0 -> ../../devices/virtual/gpio/gpiochip0
--w------- 1 root root 4096 Nov 30 19:34 unexport
執行完就可看到多出一個 gpio17 連結

# ls -l /sys/class/gpio/gpio17/
total 0
-rw-r--r-- 1 root root 4096 Nov 30 19:58 active_low
-rw-r--r-- 1 root root 4096 Nov 30 19:58 direction
-rw-r--r-- 1 root root 4096 Nov 30 19:58 edge
drwxr-xr-x 2 root root 0 Nov 30 19:58 power
lrwxrwxrwx 1 root root 0 Nov 30 19:37 subsystem -> ../../../../class/gpio
-rw-r--r-- 1 root root 4096 Nov 30 19:37 uevent
-rw-r--r-- 1 root root 4096 Nov 30 19:58 value

顯示目前 gpio17 是輸入或輸出
# cat /sys/class/gpio/gpio17/direction
in

將方向改成輸出
# echo out > /sys/class/gpio/gpio17/direction

已改變為輸出
# cat /sys/class/gpio/gpio17/direction
out

顯示目前 gpio17 的值
# cat /sys/class/gpio/gpio17/value
0

更改 gpio17 的值
# echo 1 > /sys/class/gpio/gpio17/value

檢查看是否有改過
# cat /sys/class/gpio/gpio17/value
1


使用 WiringPi:

看過上面直接在 console 下指令由 /sys 對 gpio 做修改,是不是覺得滿麻煩的,所以有人寫出 Wiring 來簡化整個設定過程。

由於 gpio 編號並沒有按照順序排,跳來跳去的,初學者根本弄不清楚,常常會搞錯。
Wiring,原本是 Arduino 系統在用的,將 gpio 重新編號,由 0 開始,循序往上的命名方式的工具,好處是若哪天板子改版,gpio 編號有跳動,wiring 編號也是不變。

後來樹莓派出來後,移植到樹莓派的版本就叫 WiringPi。當然,也支援原本的編號方式。

網頁:
https://projects.drogon.net/raspberry-pi/wiringpi/

安裝:
https://projects.drogon.net/raspberry-pi/wiringpi/download-and-install/

$ tar xvf wiringPi.tgz
$ cd wiringPi
$ sudo ./build

可直接下載 tarball 安裝,完成後在命令列下就有 gpio 這指令可用。

由於使用及存取 gpio port 都必需有 root 權限,但 gpio 這指令有 setuid,所以用一般使用者來執行即可。

檢查這塊板子的版本是 rev 1 或 rev 2
$ gpio -v
gpio version: 1.4
Copyright (c) 2012 Gordon Henderson
This is free software with ABSOLUTELY NO WARRANTY.
For details type: gpio -warranty

This Raspberry Pi is a revision 2 board.


$ gpio readall
+-----------------+--------+------------+-----------+
| wiringPi | GPIO | Name | Value |
+-----------------+--------+------------+-----------+
| 0 | 17 | GPIO 0 | Low |
| 1 | 18 | GPIO 1 | High |
| 2 | 27 | GPIO 2 | Low |
| 3 | 22 | GPIO 3 | Low |
| 4 | 23 | GPIO 4 | Low |
| 5 | 24 | GPIO 5 | Low |
| 6 | 25 | GPIO 6 | Low |
| 7 | 4 | GPIO 7 | High |
| 8 | 2 | SDA | High |
| 9 | 3 | SCL | High |
| 10 | 8 | CE0 | Low |
| 11 | 7 | CE1 | Low |
| 12 | 10 | MOSI | Low |
| 13 | 9 | MISO | Low |
| 14 | 11 | SCLK | Low |
| 15 | 14 | TxD | High |
| 16 | 15 | RxD | High |
+----------------+---------+------------+------------+
| 17 | 28 | GPIO 8 | Low |
| 18 | 29 | GPIO 9 | Low |
| 19 | 30 | GPIO10 | Low |
| 20 | 31 | GPIO11 | Low |
+----------------+---------+-------------+----------+

顯示所有 port 的目前狀況(板子上的 P1),0 - 16 共 17 port,最後面 4 個為 P5 (rev 2 才有) 在板子上 P1 的旁邊有 8 個小洞,要使用自己焊。聽說未來的板子,連現在的 P1 的 26 port 出廠都不會焊好,使用者買回家後,要直的、彎的接腳都可以自己來,以後要玩樹莓派 gpio 要先準備好烙鐵和吸鍚器了。

第一列為 wiring 的編號,第二列為 broadcom 的 BCM_GPIO 編號方式,第三列為原本每個 port 的名稱,最後一行為目前的值。

存取方式:(預設為 wiring 編號模式)
$ gpio read 0
0

以 BCM_GPIO 編號來讀取( -g):
$ gpio -g read 17
0

二個指令都讀取同一個 port

將 17 port mode 改成輸出
$ gpio -g mode 17 out

寫入:
$ gpio -g write 17 1

檢查值果然改變為 1
$ gpio -g read 17
1

好像沒參數可看目前是輸出或輸入,不過沒關係,每次要用前都直接先設定一次就好。



使用 python:

檢查看看 Python GPIO module for Raspberry Pi 有沒有安裝,若是官方的 rasbian 已經安裝好,其他的可能要檢查看看。

$ dpkg --list|grep gpio
ii python-rpi.gpio 0.4.1a-1 armhf Python GPIO module for Raspberry Pi
ii python3-rpi.gpio 0.4.1a-1 armhf Python 3 GPIO module for Raspberry Pi

python-rpi.gpio 為 python 2.6 及 2.7 版
python3-rpi.gpio 為 python 3.x 版


若沒有則手動安裝:
$ sudo apt-get install python-pip
$ sudo pip install rpi.gpio


範例: test.py
import RPi.GPIO as GPIO, time
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT)

try:
while True:
GPIO.output(17, True)
time.sleep(2)

GPIO.output(17, False)
time.sleep(2)
except KeyboardInterrupt:
GPIO.cleanup()

執行:
$ sudo python test.py
執行後,GPIO 17 上的 led 就會閃二秒、滅二秒,一直重覆,按 Ctrl-C 結束程式。



使用 Webiopi:

http://code.google.com/p/webiopi/

下載並安裝:
$ tar xvf WebIOPi-0.5.1.tar.gz
$ cd WebIOPi-0.5.1
$ sudo ./setup.sh

執行
$ sudo /etc/init.d/webiopi start
$ sudo python -m webiopi [port]


開機就啟動:
$ sudo update-rc.d webiopi defaults


以瀏覽器開啟:
http://192.168.1.105:8000

預設帳號 "webiopi" 及密碼 "raspberry"


實作:


- 紅綠燈模擬

http://www.skpang.co.uk/blog/archives/656

$ wget http://skpang.co.uk/dl/traffic_light.py
由於 rev 1 和 rev 2 腳位有改變,所以這裡的 code 也要跟著改
$ vi traffic_light.py
第9 行 21 → 27 即可

$ chmod +x traffic_light.py
$ sudo ./traffic_light.py


- Ladder Game

http://www.youtube.com/watch?v=35YXhS-NfPM
https://projects.drogon.net/raspberry-pi/gpio-examples/ladder-game/

下載並編譯,不過系統上要有裝 wiringPi 才行
$ wget http://project-downloads.drogon.net/files/gpioExamples/ladder.c
$ cc -o ladder -Wall -I/usr/local/include -L/usr/local/lib ladder.c -lwiringPi -lm
$ sudo ./ladder




參考連結:


1. http://moebiuslinux.sourceforge.net/hardwarehacks/raspberry-pi-barebone-development-case/
2. http://www.drobe.co.uk/extra/usbmedia/cable1.jpg
3. http://search.ruten.com.tw/search/s000.php?searchfrom=indexbar&k=gpio+%B1%C6%BDu&t=0
4. http://elinux.org/RPi_Tutorial_EGHS:GPIO_Protection_Circuits
5. http://elinux.org/Rpi_Low-level_peripherals