Ⅰ linux:怎麼查看一個進程的詳細的啟動時間
在Linux下,如果需要查看進程的啟動時間, 常用ps aux命令,但是ps aux命令的缺陷在於只能顯示時間到年、日期、或者時間, 無法具體到年月日時分秒。如果需要查看某個進程的具體啟動時間, 使用 ps -p PID -o lstart, 其中,PID為某個進程的進程ID號。如下所示, 顯示系統中所有httpd進程的具體啟動時間。 1.for pid in $(pgrep httpd); do echo -n ${pid} ; ps -p ${pid} -o lstart | grep -v START ; done 2.301 Mon Aug 27 11:21:59 2012 3.344 Mon Aug 27 11:33:13 2012 12.27903 Wed Jun 20 22:50:47 2012
Ⅱ Handler消息機制(一):Linux的epoll機制
在linux 沒有實現epoll事件驅動機制之前,我們一般選擇用select或者poll等IO多路復用的方法來實現並發服務程序。在linux新的內核中,有了一種替換它的機制,就是epoll。
相比select模型, poll使用鏈表保存文件描述符,因此沒有了監視文件數量的限制 ,但其他三個缺點依然存在。
假設我們的伺服器需要支持100萬的並發連接,則在__FD_SETSIZE 為1024的情況下,則我們至少需要開辟1k個進程才能實現100萬的並發連接。除了進程間上下文切換的時間消耗外,從內核/用戶空間大量的無腦內存拷貝、數組輪詢等,是系統難以承受的。因此,基於select模型的伺服器程序,要達到10萬級別的並發訪問,是一個很難完成的任務。
由於epoll的實現機制與select/poll機制完全不同,上面所說的 select的缺點在epoll上不復存在。
設想一下如下場景:有100萬個客戶端同時與一個伺服器進程保持著TCP連接。而每一時刻,通常只有幾百上千個TCP連接是活躍的(事實上大部分場景都是這種情況)。如何實現這樣的高並發?
在select/poll時代,伺服器進程每次都把這100萬個連接告訴操作系統(從用戶態復制句柄數據結構到內核態),讓操作系統內核去查詢這些套接字上是否有事件發生,輪詢完後,再將句柄數據復制到用戶態,讓伺服器應用程序輪詢處理已發生的網路事件,這一過程資源消耗較大,因此,select/poll一般只能處理幾千的並發連接。
epoll的設計和實現與select完全不同。epoll通過在Linux內核中申請一個簡易的文件系統(文件系統一般用什麼數據結構實現?B+樹)。把原先的select/poll調用分成了3個部分:
1)調用epoll_create()建立一個epoll對象(在epoll文件系統中為這個句柄對象分配資源)
2)調用epoll_ctl向epoll對象中添加這100萬個連接的套接字
3)調用epoll_wait收集發生的事件的連接
如此一來,要實現上面說是的場景,只需要在進程啟動時建立一個epoll對象,然後在需要的時候向這個epoll對象中添加或者刪除連接。同時,epoll_wait的效率也非常高,因為調用epoll_wait時,並沒有一股腦的向操作系統復制這100萬個連接的句柄數據,內核也不需要去遍歷全部的連接。
當某一進程調用epoll_create方法時,Linux內核會創建一個eventpoll結構體,這個結構體中有兩個成員與epoll的使用方式密切相關。eventpoll結構體如下所示:
每一個epoll對象都有一個獨立的eventpoll結構體,用於存放通過epoll_ctl方法向epoll對象中添加進來的事件。這些事件都會掛載在紅黑樹中,如此,重復添加的事件就可以通過紅黑樹而高效的識別出來(紅黑樹的插入時間效率是lgn,其中n為樹的高度)。
而所有 添加到epoll中的事件都會與設備(網卡)驅動程序建立回調關系,也就是說,當相應的事件發生時會調用這個回調方法 。這個回調方法在內核中叫ep_poll_callback,它會將發生的事件添加到rdlist雙鏈表中。
在epoll中,對於每一個事件,都會建立一個epitem結構體,如下所示:
當調用epoll_wait檢查是否有事件發生時,只需要檢查eventpoll對象中的rdlist雙鏈表中是否有epitem元素即可。如果rdlist不為空,則把發生的事件復制到用戶態,同時將事件數量返回給用戶。
epoll結構示意圖
通過紅黑樹和雙鏈表數據結構,並結合回調機制,造就了epoll的高效。
events可以是以下幾個宏的集合:
EPOLLIN:觸發該事件,表示對應的文件描述符上有可讀數據。(包括對端SOCKET正常關閉);
EPOLLOUT:觸發該事件,表示對應的文件描述符上可以寫數據;
EPOLLPRI:表示對應的文件描述符有緊急的數據可讀(這里應該表示有帶外數據到來);
EPOLLERR:表示對應的文件描述符發生錯誤;
EPOLLHUP: 表示對應的文件描述符被掛斷;
EPOLLET:將EPOLL設為邊緣觸發(EdgeTriggered)模式,這是相對於水平觸發(Level Triggered)來說的。
EPOLLONESHOT: 只監聽一次事件,當監聽完這次事件之後,如果還需要繼續監聽這個socket的話,需要再次把這個socket加入到EPOLL隊列里。
示例:
ET(EdgeTriggered) :高速工作模式,只支持no_block(非阻塞模式)。在此模式下,當描述符從未就緒變為就緒時,內核通過epoll告知。然後它會假設用戶知道文件描述符已經就緒,並且不會再為那個文件描述符發送更多的就緒通知,直到某些操作導致那個文件描述符不再為就緒狀態了。(觸發模式只在數據就緒時通知一次,若數據沒有讀完,下一次不會通知,直到有新的就緒數據)
LT(LevelTriggered) :預設工作方式,支持blocksocket和no_blocksocket。在LT模式下內核會告知一個文件描述符是否就緒了,然後可以對這個就緒的fd進行IO操作。如果不作任何操作,內核還是會繼續通知!若數據沒有讀完,內核也會繼續通知,直至設備數據為空為止!
1.我們已經把一個用來從管道中讀取數據的文件句柄(RFD)添加到epoll描述符
2. 這個時候從管道的另一端被寫入了2KB的數據
3. 調用epoll_wait(2),並且它會返回RFD,說明它已經准備好讀取操作
4. 然後我們讀取了1KB的數據
5. 調用epoll_wait(2)……
ET工作模式:
如果我們在第1步將RFD添加到epoll描述符的時候使用了EPOLLET標志,在第2步執行了一個寫操作,第三步epoll_wait會返回同時通知的事件會銷毀。因為第4步的讀取操作沒有讀空文件輸入緩沖區內的數據,因此我們在第5步調用epoll_wait(2)完成後,是否掛起是不確定的。epoll工作在ET模式的時候,必須使用非阻塞套介面,以避免由於一個文件句柄的阻塞讀/阻塞寫操作把處理多個文件描述符的任務餓死。
只有當read(2)或者write(2)返回EAGAIN時(認為讀完)才需要掛起,等待。但這並不是說每次read()時都需要循環讀,直到讀到產生一個EAGAIN才認為此次事件處理完成,當read()返回的讀到的數據長度小於請求的數據長度時(即小於sizeof(buf)),就可以確定此時緩沖中已沒有數據了,也就可以認為此事讀事件已處理完成。
LT工作模式:
LT方式調用epoll介面的時候,它就相當於一個速度比較快的poll(2),並且無論後面的數據是否被使用,因此他們具有同樣的職能。
當調用 epoll_wait檢查是否有發生事件的連接時,只是檢查 eventpoll對象中的 rdllist雙向鏈表是否有 epitem元素而已,如果 rdllist鏈表不為空,則把這里的事件復制到用戶態內存中,同時將事件數量返回給用戶。因此,epoll_wait的效率非常高。epoll_ctl在向 epoll對象中添加、修改、刪除事件時,從 rbr紅黑樹中查找事件也非常快,也就是說,epoll是非常高效的,它可以輕易地處理百萬級別的並發連接。
1.減少用戶態和內核態之間的文件句柄拷貝;
2.減少對可讀可寫文件句柄的遍歷。
https://cloud.tencent.com/developer/information/linux%20epoll%E6%9C%BA%E5%88%B6
https://blog.csdn.net/u010657219/article/details/44061629
https://jiahao..com/s?id=1609322251459722004&wfr=spider&for=pc
Ⅲ 如何在Linux用戶和內核空間中進行動態跟蹤
你不記得如何在代碼中插入探針點了嗎? 沒問題!了解如何使用uprobe和kprobe來動態插入它們吧。 基本上,程序員需要在源代碼匯編指令的不同位置插入動態探針點。
探針點
探針點是一個調試語句,有助於探索軟體的執行特性(即,執行流程以及當探針語句執行時軟體數據結構的狀態)。printk是探針語句的最簡單形式,也是黑客用於內核攻擊的基礎工具之一。
因為它需要重新編譯源代碼,所以printk插入是靜態的探測方法。內核代碼中重要位置上還有許多其他靜態跟蹤點可以動態啟用或禁用。 Linux內核有一些框架可以幫助程序員探測內核或用戶空間應用程序,而無需重新編譯源代碼。Kprobe是在內核代碼中插入探針點的動態方法之一,並且uprobe在用戶應用程序中執行此操作。
使用uprobe跟蹤用戶空間
可以通過使用thesysfs介面或perf工具將uprobe跟蹤點插入用戶空間代碼。
使用sysfs介面插入uprobe
考慮以下簡單測試代碼,沒有列印語句,我們想在某個指令中插入探針:
[source,c\n.test.c
#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>
編譯代碼並找到要探測的指令地址:
# gcc -o test test.\n# objmp -d test
假設我們在ARM64平台上有以下目標代碼:
0000000000400620 <func_1>: 400620\t90000080\tadr\tx0, 410000 <__FRAME_END__+0xf6f8>
並且我們想在偏移量0x620和0x644之間插入探針。執行以下命令:
# echo 'p:func_2_entry test:0x620' > /sys/kernel/debug/tracing/uprobe_event\n# echo 'p:func_1_entry test:0x644' >> /sys/kernel/debug/tracing/uprobe_event\n# echo 1 > /sys/kernel/debug/tracing/events/uprobes/enable# ./test&
在上面的第一個和第二個echo語句中,p告訴我們這是一個簡單的測試。(探測器可以是簡單的或返回的。)func_n_entry是我們在跟蹤輸出中看到的名稱,名稱是可選欄位,如果沒有提供,我們應該期待像p_test_0x644這樣的名字。test 是我們要插入探針的可執行二進制文件。如果test 不在當前目錄中,則需要指定path_to_test / test。
0x620或0x640是從程序啟動開始的指令偏移量。請注意>>在第二個echo語句中,因為我們要再添加一個探針。所以,當我們在前兩個命令中插入探針點之後,我們啟用uprobe跟蹤,當我們寫入events/ uprobes / enable時,它將啟用所有的uprobe事件。程序員還可以通過寫入在該事件目錄中創建的特定事件文件來啟用單個事件。一旦探針點被插入和啟用,每當執行探測指令時,我們可以看到一個跟蹤條目。
讀取跟蹤文件以查看輸出:
# cat /sys/kernel/debug/tracing/trac\n# tracer: no\n\n# entries-in-buffer/entries-written: 8/8\n#P:\n\n# _-----=> irqs-of\n# / _----=> need-resche\n# | / _---=> hardirq/softir\n# || / _--=> preempt-dept\n# ||| / dela\n# TASK-PID CP\n# |||| TIMESTAMP FUNCTION# | | | |||| | |
我們可以看到哪個CPU完成了什麼任務,什麼時候執行了探測指令。
返回探針也可以插入指令。當返回該指令的函數時,將記錄一個條目:
# echo 0 > /sys/kernel/debug/tracing/events/uprobes/enabl\n# echo 'r:func_2_exit test:0x620' >> /sys/kernel/debug/tracing/uprobe_event\n# echo 'r:func_1_exit test:0x644' >> /sys/kernel/debug/tracing/uprobe_event\n# echo 1 > /sys/kernel/debug/tracing/events/uprobes/enable
這里我們使用r而不是p,所有其他參數是相同的。請注意,如果要插入新的探測點,需要禁用uprobe事件:
test-3009 [002] .... 4813.852674: func_1_entry: (0x400644)
上面的日誌表明,func_1返回到地址0x4006b0,時間戳為4813.852691。
# echo 0 > /sys/kernel/debug/tracing/events/uprobes/enabl\n# echo 'p:func_2_entry test:0x630' > /sys/kernel/debug/tracing/uprobe_events count=%x\n# echo 1 > /sys/kernel/debug/tracing/events/uprobes/enabl\n# echo > /sys/kernel/debug/tracing/trace# ./test&
當執行偏移量0x630的指令時,將列印ARM64 x1寄存器的值作為count =。
輸出如下所示:
test-3095 [003] .... 7918.629728: func_2_entry: (0x400630) count=0x1
使用perf插入uprobe
找到需要插入探針的指令或功能的偏移量很麻煩,而且需要知道分配給局部變數的CPU寄存器的名稱更為復雜。 perf是一個有用的工具,用於幫助引導探針插入源代碼中。
除了perf,還有一些其他工具,如SystemTap,DTrace和LTTng,可用於內核和用戶空間跟蹤;然而,perf與內核配合完美,所以它受到內核程序員的青睞。
# gcc -g -o test test.c# perf probe -x ./test func_2_entry=func_\n# perf probe -x ./test func_2_exit=func_2%retur\n# perf probe -x ./test test_15=test.c:1\n# perf probe -x ./test test_25=test.c:25 numbe\n# perf record -e probe_test:func_2_entry -e\nprobe_test:func_2_exit -e probe_test:test_15\n-e probe_test:test_25 ./test
如上所示,程序員可以將探針點直接插入函數start和return,源文件的特定行號等。可以獲取列印的局部變數,並擁有許多其他選項,例如調用函數的所有實例。 perf探針用於創建探針點事件,那麼在執行./testexecutable時,可以使用perf記錄來探測這些事件。當創建一個perf探測點時,可以使用其他錄音選項,例如perf stat,可以擁有許多後期分析選項,如perf腳本或perf報告。
使用perf腳本,上面的例子輸出如下:
# perf script
使用kprobe跟蹤內核空間
與uprobe一樣,可以使用sysfs介面或perf工具將kprobe跟蹤點插入到內核代碼中。
使用sysfs介面插入kprobe
程序員可以在/proc/kallsyms中的大多數符號中插入kprobe;其他符號已被列入內核的黑名單。還有一些與kprobe插入不兼容的符號,比如kprobe_events文件中的kprobe插入將導致寫入錯誤。 也可以在符號基礎的某個偏移處插入探針,像uprobe一樣,可以使用kretprobe跟蹤函數的返回,局部變數的值也可以列印在跟蹤輸出中。
以下是如何做:
; disable all events, just to insure that we see only kprobe output in trace\n# echo 0 > /sys/kernel/debug/tracing/events/enable; disable kprobe events until probe points are inseted\n# echo 0 > /sys/kernel/debug/tracing/events/kprobes/enable; clear out all the events from kprobe_events\n to insure that we see output for; only those for which we have enabled
[root@pratyush ~\n# more /sys/kernel/debug/tracing/trace# tracer: no\n\n# entries-in-buffer/entries-written: 9037/9037\n#P:8\n# _-----=> irqs-of\n# / _----=> need-resche\n# | / _---=> hardirq/softirq#\n|| / _--=> preempt-depth#\n ||| / delay# TASK-PID CPU#\n |||| TIMESTAMP FUNCTION#\n | | | |||| | |
使用perf插入kprobe
與uprobe一樣,程序員可以使用perf在內核代碼中插入一個kprobe,可以直接將探針點插入到函數start和return中,源文件的特定行號等。程序員可以向-k選項提供vmlinux,也可以為-s選項提供內核源代碼路徑:
# perf probe -k vmlinux kfree_entry=kfre\n# perf probe -k vmlinux kfree_exit=kfree%retur\n# perf probe -s ./ kfree_mid=mm/slub.c:3408 \n# perf record -e probe:kfree_entry -e probe:kfree_exit -e probe:kfree_mid sleep 10
使用perf腳本,以上示例的輸出:
關於Linux命令的介紹,看看《linux就該這么學》,具體關於這一章地址3w(dot)linuxprobe/chapter-02(dot)html
Ⅳ linux中進程 kacpid, kblockd是什麼
守護進程及調度進程,以下是摘錄的一些常用進程的說明:
/sbin/init 內核啟動的第一個用戶級進程,引導用戶空間服務
[kthreadd] 內核線程管理
[migration/0] 用於進程在不同的CPU間遷移
[ksoftirqd/0] 內核調度/管理第0個CPU軟中斷的守護進程
[migration/1] 管理多核心
[ksoftirqd/1] 內核調度/管理第1個CPU軟中斷的守護進程
[events/0] 處理內核事件守護進程
[events/1] 處理內核事件守護進程
[cpuset] 在每個處理器上單獨運行進程,通過文件系統實現
[khelper] 內核幫助進程
[netns] 網路模擬器,模擬網路環境
[async/mgr] 非同步加密管理進程
[pm] 包管理
[sync_supers] 特權同步,將緩沖區文件強制寫入硬碟
[bdi-default] JTAG調試器默認進程
[kintegrityd/0] 內核完整性檢查
[kintegrityd/1] 內核完整性檢查
[kblockd/0] 管理磁碟塊讀寫
[kblockd/1] 管理磁碟塊讀寫
[kacpid] 高級配置和電源管理介面
[kacpi_notify] acpi進程的通知進程
[kacpi_hotplug] acpi熱插拔管理
[ata/0] ATA硬碟介面管理
[ata/1] ATA硬碟介面管理
[ata_aux] ATA硬碟介面管理
[khubd] 內核的usb hub
[kseriod] 內核線程
[kswapd0] 內存回收,確保系統空閑物理內存的數量在一個合適的范圍
[ksmd] 作為內核中的守護進程存在,它定期執行頁面掃描,識別副本頁面並合並副本,釋放這些頁面以供它用
[aio/0] 代替用戶進程管理io
[aio/1] 代替用戶進程管理io
[ecryptfs-kthrea] 加密系統
[crypto/0] 提供加密解密相關函數
[crypto/1] 提供加密解密相關函數
[scsi_eh_0] scsi設備
[scsi_eh_1] scsi設備
[scsi_eh_2] scsi設備
[scsi_eh_3] scsi設備
[kpsmoused] 內核滑鼠支持
[kjournald] Ext3文件系統的日誌管理
[kjournald] Ext3文件系統的日誌管理
[flush-1:0] 釋放存儲在緩存區中的數據
[flush-1:1] 釋放存儲在緩存區中的數據
[flush-1:2] 釋放存儲在緩存區中的數據
[flush-1:3] 釋放存儲在緩存區中的數據
[flush-1:4] 釋放存儲在緩存區中的數據
[flush-1:5] 釋放存儲在緩存區中的數據
[flush-1:6] 釋放存儲在緩存區中的數據
[flush-1:7] 釋放存儲在緩存區中的數據
[flush-1:8] 釋放存儲在緩存區中的數據
[flush-1:9] 釋放存儲在緩存區中的數據
[flush-1:10] 釋放存儲在緩存區中的數據
[flush-1:11] 釋放存儲在緩存區中的數據
[flush-1:12] 釋放存儲在緩存區中的數據
[flush-1:13] 釋放存儲在緩存區中的數據
[flush-1:14] 釋放存儲在緩存區中的數據
[flush-1:15] 釋放存儲在緩存區中的數據
[flush-8:0] 釋放存儲在緩存區中的數據
[kjournald] Ext3文件系統的日誌管理
[loop0] 負責對loop設備進行操作
[loop1] 負責對loop設備進行操作
[loop2] 負責對loop設備進行操作
[kd] 內核拷貝線程
[ext4-dio-unwrit] Ext4文件系統相關線程
upstart-udev-bridge --daemon 一個守護進程,負責接收udev信息
udevd --daemon 一個守護進程,在向udev提交之前重新訂制熱插拔事件,從而避免各種各樣的競爭條件
/usr/sbin/restorecond 用於給SELinux監測和重新載入正確的文件上下文
/sbin/auditd 審計守護進程
/sbin/audispd 審計調度進程
[kauditd] 內核審核守護進程
/sbin/getty -8 38400 tty4 等待用戶從tty4登錄
/sbin/getty -8 38400 tty5 等待用戶從tty5登錄
/sbin/getty -8 38400 tty2 等待用戶從tty2登錄
/sbin/getty -8 38400 tty3 等待用戶從tty3登錄
/sbin/getty -8 38400 tty6 等待用戶從tty6登錄
acpid -c /etc/acpi/events -s /var/run/acpid.socket 一個用戶空間的服務進程,它充當Linux內核與應用程序之間通信的介面
cron 守護進程,周期地運行用戶調度的任務
/sbin/getty -8 38400 tty1 等待用戶從tty1登錄
X :0 -br vt7 -nolisten tcp Xsever
[flush-252:0] 釋放存儲在緩存區中的數據
lwm 窗口管理器
fcitx 輸入法
su 切換root用戶
bash 終端
ps x 查看當前用戶的進程
Ⅳ linux命令獲取進程運行時長,不足一小時,如何將時間輸出為:時分秒格式。
使用 ps命令 ,命令執行參數及運行結果如下:
#ps -A -opid,stime,etime,args
結果:
root:src# ps -A -opid,stime,etime,args
PID STIME ELAPSED COMMAND
1 09:21 08:56:14 init [3]
2 09:21 08:56:14 [migration/0]
3 09:21 08:56:14 [ksoftirqd/0]
4 09:21 08:56:14 [watchdog/0]
5 09:21 08:56:14 [events/0]
6 09:21 08:56:14 [khelper]
7 09:21 08:56:14 [kthread]
10 09:21 08:56:14 [kblockd/0]
11 09:21 08:56:14 [kacpid]
47 09:21 08:56:14 [cqueue/0]
說明:PID指的是進程ID號,STIME即啟動時間,ELAPSED 即運行時間。