日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

DTRACE简介(2)

發布時間:2024/4/15 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 DTRACE简介(2) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

?

? ? ? 通過上一次的介紹,相信大家對DTRACE已經有了一個初步的認識。上一次結束時專門留了一個例子,可能大家第一次看有很多不明白的地方,沒有關系,隨著我們對DTRACE更多的介紹,很快就會”云開霧散“了。

????? D語言作為一種編程語言,自然就有其語法、關鍵字、數據結構、運算符、函數等,我將一一介紹。

????? D語言中標志符名稱與C語言類似,由字母、數字和下劃線組成,其中第一個字符必須是字母或者下劃線。D語言預留了一些關鍵字供DTRACE本身使用,關鍵字不能用做D變量的名稱。D關鍵字列表參閱《Solaris動態跟蹤指南》,這里只列出一些常用的。
?????

???????表1 - 常用DTRACE關鍵字

?

關鍵字?描述
inline?編譯期間將指定的D變量替換為預定義的值或者表達式,inline可以申明類型
sizeof?計算對象的大小
self?表示將D變量存放在線程(thread)的私有空間里
this?表示D變量的有效范圍在this所在的子句內
?

?

????

?

?

????? D語言中定義了整數類型和浮點類型,以及用于表示ASCII字符串的string類型。整數類型隨機器字長的不同而不同。機器字長可以用命令isainfo -b來查看。

???????表2 - D整數類型

?

?類型名稱32位機器字長
64位機器字長
?char1個字節??1個字節
?short2個字節?2個字節
?int4個字節?4個字節
?long4個字節?8個字節
?longlong8個字節?8個字節

?

?

?

?

?

?

?????? 一點小知識,C語言中有ILP32和LP64兩種數據模型,ILP32指的就是int/long/pointer(指針)是32位,LP64指的是long/pointer是64位。

?????? 對于整數類型,又分為帶符號(signed)和無符號(unsigned)兩種,因為是否帶符號決定了對其最高位(most-significant)的解釋。無符號整型通常是在相應的整型前面添加unsigned或者u限定符。

????????表3 - D整數類型別名

?????

?類型名稱說明?
?int8_t / uint8_t1字節帶符號整數 / 1字節無符號整數
?int16_t / uint16_t2字節帶符號整數 / 2字節無符號整數
?int32_t / uint32_t4字節帶符號整數 / 4字節無符號整數
?int64_t / uint64_t8字節帶符號整數 / 8字節無符號整數
?intptr_t / uintptr_t大小等于指針的帶符號整數 / 大小等于指針的無符號整數

?

?

?

?

?

?

????? D語言中也定義了轉義序列如'\\n'表示回車。

????? D語言中定義了算術運算符、關系運算符、邏輯運算符、按位運算符、賦值運算符、遞增和遞減運算符、條件表達式(即 ? : 運算符),由于這些運算符及其優先級與C語言基本相同,就不在這里占用篇幅了。D語言也支持”強制類型轉換“,即把一種類型轉換為另一種兼容類型,比如將指針轉換為整數。

????? 除了上面的數據類型,D語言還提供有數組(array)關聯數組(associative array),關聯數組中有一種特殊類型叫做聚合(aggregation),在后面會看到。關聯數組通過一個稱為鍵(key)的名稱來檢索數據,用過Perl的朋友相信不會陌生。定義關聯數組,只需作以下賦值操作即可:

??????name[key]=expression;

????? 例如: people["sam.wan",30]=100

????? D語言中的變量是不需要預定義就可以直接使用的。但是在沒有賦值之前,是不能出現在謂詞中和賦值運算等號右側。請看下面的3個例子:

例子1
# dtrace -n 'BEGIN{a=1;exit(0);}END{printf("a=%d\\n",a);}'
dtrace: description 'BEGIN' matched 2 probes
CPU???? ID??????????????????? FUNCTION:NAME
? 0????? 1?????????????????????????? :BEGIN
? 0????? 2???????????????????????????? :END?a=1

例子2
# dtrace -n 'BEGIN/a==0/{exit(0);}END{printf("a=%d\\n",a);}'
dtrace: invalid probe specifier BEGIN/a==0/{exit(0);}END{printf("a=%d\\n",a);}:?in predicate: failed to resolve a: Unknown variable name


例子3
# dtrace -n 'BEGIN{a=a+1;exit(0);}END{printf("a=%d\\n",a);}'
dtrace: invalid probe specifier BEGIN{a=a+1;exit(0);}END{printf("a=%d\\n",a);}:?in action list: a has not yet been declared or assigned

????? 缺省情況下,D語言中定義的變量是全局范圍的。在多線程環境中,全局變量是不安全的,因為可能多個線程都會進行訪問,因此,D語言引入了線程局部變量標志符self。通過在一個變量前面添加self->修飾,可以將該變量存放在線程自己的局部空間中,這樣不會受到其它線程的影響,這種方法對于現在越來越多的并發操作環境十分有利。線程局部變量與全局變量在不同的名稱空間(name space)中,因此即使名字相同也不會沖突,比如self->aaa和aaa是兩個不同的變量。

?????? 特別需要提醒注意的是,在使用完一個變量之后,要將該標量賦值為'0',這樣DTRACE就會回收釋放其所占用的內存空間。對用一個好的程序員來說,釋放空間和分配空間同樣重要。

????? D語言中還有一種特殊的變量叫“子句局部變量(Clause Local)”,通過在變量名前添加this->修飾符完成。子句局部變量的作用域只在其定義的子句內有效。D語言中的變量缺省情況下會被賦值為0,但是子句局部變量除外。

????? 除用戶定義的變量外,D語言本身提供了一些非常有用的內置變量,所有這些內置變量都是全局變量。

??????表4 - DTrace內置變量

?

?類型和名稱說明?
int64_t arg0,...,arg9?探測器的前10個輸入參數(64位整數)。如果當前探測器參數個數少于10,則未定義的參數值不確定?
args[]與arg0...arg9不同,args[]是有類型的,其類型對應與當前探測器的參數類型。
uintptr_t caller進入當前探測器之前的當前線程的程序計數器(PC)位置
chipid_t chip當前物理芯片的CPU芯片標志符
processorid_t cpu當前CPU的編號
cpuinfo_t \*curcpu當前CPU的信息(具體結構后面會講到)
lwpsinfo_t \*curlwpsinfo與當前線程關聯的輕量進程(LightWeight Process,LWP)的信息(具體結構見后)
psinfo_t \*curpsinfo與當前線程關聯的進程的信息
kthread_t \*curthread當前線程在內核中的數據結構(kthread_t)的地址,kthread_t的定義在<sys/thread.h>中。
string cwd當前進程的工作路徑(Current Working Directory)
uint_t epid當前探測器的已啟用的探測器ID號。
int errno當前線程最后一次執行的系統調用的返回錯誤值
string execname當前進程的名稱
gid_t gid組ID
uint_t id當前探測器的唯一ID號,dtrace -l的第一列
uint_t ipl觸發探測器時當前CPU的中斷優先級(Interrupt Priority Level,IPL)。
lgrp_id_t lgrp當前CPU所屬的延遲組(Latency Group)的ID
pid_t pid當前進程號
pid_t ppid當前進程的父進程
string probefunc當前探測器的函數名
string probemod當前探測器的模塊名
string probename當前探測器的名字
string probeprov當前探測器的提供器名
psetid_t pset當前CPU所屬的處理器集(Processor Set)的ID
string root當前進程的根目錄名
uint_t stackdepth當前線程的棧幀(Stack Frame)的深度。即其調用的函數的層次數。
id_t tid當前線程的線程ID
uint64_t timestamp以納秒(ns)為單位的時間計數器。此計數器從過去的任意點遞增,僅用于相對計算中。
uid_t uid當前進程的實際用戶ID
uint64_t uregs[]當前線程的用戶寄存器值
uint64_t vtimestamp以納秒(ns)為單位的時間計數器,實際是當前線程在CPU中已運行的時間減去DTrace謂詞和操作所花費的時間。同timestamp一樣,僅用于相對計算。
uint64_t walltimestamp自1970年1月1日00:00世界標準時間以來的納秒數。


?

?

? ?? Dtrace還可以使用反引號(backquote `)訪問操作系統內核中定義的變量,但不能進行修改。

???? 內核中定義的變量可以通過查看內核的變量符號表(Name Symbol)來找到。

?????#echo "::nm"|mdb -k|more

???? 比如我們想通過DTrace來查看每秒鐘freemem的值。freemem表示當前系統中可用的內存頁數

???? #dtrace -qn 'tick-1sec{printf("%d pages of freemem\\n",`freemem)}'

???? 由于Solaris可用動態加載模塊,各個模塊可能有相同的變量名,為了避免沖突,可用使用模塊名來區分,比如訪問a模塊的x變量:a`x

? ? ? DTrace還提供操作和子例程。

???? 如果DTrace子句為空,則會采用缺省操作。缺省操作即顯示已啟用的探測器的標志符。
?

?????數據記錄操作

????? 數據記錄操作總會往指定的緩沖區中放入數據。?
????? void trace(expression) 將expression的結果放到指定的緩沖區(在后面會提到)。

????? void tracemem(address,size_t nbytes),從address地址復制nbytes的內容到指定緩沖區。

????? void printf(string format,...) 格式化輸出。具體格式可用參見printf(3C)手冊頁。

????? void printa(aggregation)/void printa(string format,aggregation) 顯示及格式化聚合(在后面會提到)

????? void stack(void)/void stack(int nframes) 將指定長度的棧幀記錄拷貝到指定的緩沖區。

? ? ? void ustack(int nframes,int size)/void ustack(int nframes)/void ustack(void),同上,只是操作的是用戶棧?? ?

??????破壞性操作

?????? void stop(void) 停止觸發當前探測器的進程

?????? void raise(int signal) 將指定的信號signal發送至觸發當前探測器的進程

?????? void copyout(void \*buf,uintptr_t addr,size_t nbytes) 從buf地址拷貝nbytes字節到當前進程的addr地址處。

?????? void copyoutstr(string str,uintptr_t addr,size_t maxlen) 將字符串string拷貝到當前進程的addr地址處

?????? void system(string program,..) 執行程序

???????內核破壞性操作(下面的操作將會影響整個系統的運行)

?????? void breakpoint(void) 發生一個內核斷點

?????? void panic(void) 觸發panic()操作(這個相信大家都再熟悉不過了)

?????? void chill(int nanoseconds) DTrace執行nanoseconds時間的spin操作(循環),如果nanoseconds> 500milliseconds,則會失敗。

????????特殊操作

??????? 推測性操作(Speculative Actions),有speculate(),commit(),discard(),在后面會提到。

??????? void exit(int status) 立即停止DTrace跟蹤。

????????子例程

??????? 與操作不同,子例程只會影響DTrace的內部狀態。

? ? ? ? void \*alloca(size_t size)? 分配size字節的臨時空間,返回一個8字節對齊的指針。

??????? string basename(char \*str)? 從str中去除前綴和目錄名

??????? void bcopy(void \*src,void \*dest,sizt_t size) 從src拷貝size字節到dest。

??????? string cleanpath(char \*str) 去除str中的/./和/../等

??????? void \*copyin(uintptr_t addr,size_t size) 從用戶地址空間addr處拷貝size字節到Dtrace臨時緩沖區中,并返回緩沖區地址。

??????? string \*copyinstr(uintptr_t addr) 從用戶地址空間addr除拷貝已null結尾的ASCII字符串到Dtrace臨時緩沖區,并返回緩沖區地址。

???????? void copyinto(uintptr_t addr,size_t size,void \*dest) 從用戶地址空間addr處拷貝size字節到Dtrace臨時緩沖區的dest處。

????????? string dirname(char \*str) 返回str的目錄名

????????? size_t msgdsize(mblk_t \*mp) 返回mp指向的數據消息的字節數

????????? size_t msgsize(mblk_t \*mp) 返回mp消息字節數

????????? int mutex_owned(kmutex_t \*mutex) 如果當前線程擁有互斥鎖mutex,則返回非零;否則返回0

????????? kthread_t \*mutex_owner(kmutex_t \*mutex) 返回mutex互斥鎖的屬主的線程數據結構kthread_t的指針。如果沒有屬主或者該互斥鎖是自旋鎖(Spin Mutex),則返回null。

???????? int mutex_type_adaptive(kmutex_t \*mutex) 如果mutex是自適應互斥鎖(MUTEX_ADAPTIVE類型),則返回非0,否則返回0。

???????? int progenyof(pid_t pid) 如果觸發當前探測器的進程是指定進程的子孫,則返回非0

???????? int rand(void) 返回一個偽隨機整數

???????? int rw_iswriter(krwlock_t \*rwlock) 如果指定的讀寫鎖rwlock被一個寫入者占有或者要求獲得,則返回非0,否則返回0

???????? int rw_write_held(krwlock_t \*rwlock) 如果指定的讀寫鎖當前被一個寫入者占有,則返回非0,否則返回0

???????? int speculation(void) 為speculate()操作預留一個推測性跟蹤緩沖區,并返回這個緩沖區的標志符。

???????? string strjoin(char \*str1,char \*str2) 串聯str1和str2到臨時空間,并返回其地址。

???????? size_t strlen(string str) 返回指定字串的長度(不包括結尾的空字節null)

????? 看了這么多操作和子例程,是不是有點受打擊了?沒有關系,慢慢來,先熟悉一下,在今后具體使用時,就會印象深刻。

????? 關于前面的copyin/copyinstr/copyinto子例程再多作一點說明:

????? 在Solaris(UNIX)系統中,用戶程序是運行在用戶地址空間里面,當用戶程序執行系統調用比如open(2)時,才會進入到內核空間執行(我們通常稱之為"陷入trap",為了訪問用戶地址空間的字符串,就必須將其拷貝到內核空間里面來,否則內核找不到相應的地址,就會報錯。看下面的一個例子。

????? 我們想知道是什么程序在調用open(2),以及打開什么文件。這里很自然我們會用到syscall提供器的open:entry探測器。此探測器的參數可用從open(2)的手冊頁查到(所有的syscall提供器提供的探測器都可用在相對應的系統調用手冊中查到)

?

????? int open(const char \*path, int oflag, /\* mode_t mode \*/);

????? 我們只關心第一個參數arg0,這是一個字符串指針(即將要打開的文件名)。對于字符串指針,可以使用"%s"進行格式化輸出。

#!/usr/sbin/dtrace -qs syscall::open:entry, syscall::open64:entry { printf("%s[%d] opened %s\\n",execname,pid,arg0); }

?????? 運行一下看看


?# ./who_open_what.d
dtrace: failed to compile script ./who_open_what.d: line 5: printf( ) argument #4 is incompatible with conversion #3 prototype:
??????? conversion: %s
???????? prototype: char [] or string (or use stringof)
????????? argument: int64_t


?????? 錯誤,為什么,因為傳遞給內核的是一個用戶地址空間的指針,內核無法訪問該地址,內核只看到一個指針,因此Dtrace認為格式化用的是"%s",但是傳遞的卻是一個int64_t類型,不匹配。

?????? 正確的程序應該是:

?

#!/usr/sbin/dtrace -qs syscall::open:entry, syscall::open64:entry { printf("%s[%d] opened %s\\n",execname,pid,copyinstr(arg0)); }

??????? 再來看看

?


# ./who_open_what.d
nfsmapid[272] opened /etc/default/nfs
nfsmapid[272] opened /etc/resolv.conf
init[1] opened /etc/inittab
init[1] opened /etc/svc/volatile/init-next.state
init[1] opened /etc/svc/volatile/init-next.state
init[1] opened /etc/inittab
...

?

轉載于:https://www.cnblogs.com/zengkefu/p/5971490.html

總結

以上是生活随笔為你收集整理的DTRACE简介(2)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。