stap監控IO指令碼

myownstars發表於2013-06-02

IO相關

ioblock.request--沒有引數,當產生IO請求時出發

ioblock.end--沒有引數,在1個IO塊請求transfer後出發

ioblock_trace.request--對bio產生一個IO請求時觸發

ioblock_trace.end--IO塊傳輸完畢後觸發

vfs.read

vfs.write


例1

io/eatmydata.stp 

禁止fsync/fdatasync呼叫

# stap -g eatmydata.stp -c 'strace ls || true'

global dummy_fd =1 #stdout,也可透過stap -G dummy_fd=xxx覆蓋此設定

global guilt,agony,piety

probe syscall.fsync, syscall.fdatasync {

#實際上我們無法禁止呼叫這兩個函式,但可以透過改變其fd間接達到這一效果

  if( pid() == target()) {

    try {

      $fd = dummy_fd

      guilt ++

    } catch {

      agnoy ++

    }

  } 

  else

    piety ++

}

probe syscall.fsync.return, syscall.fdatasync.return {

#在函式呼叫返回時覆蓋其返回狀態

  if (pid() == target()) 

    try {$return =0} catch{}

}

probe begin {

  printf("redirecting f*sync by pid %d to fd %d\n", target(), dummy_fd)

}

probe error,end {

  printf("redirected  f*sync by pid %d to fd %d, success %d times, failed %d times.\n", target(),dummy_fd,guilt,agnoy)

  printf("preserved f*sync by other processes %d times.\n", piety)

}

注:target()用於返回程式id,通常和-x PID或-c CMD一起使用




例2

io/inodewatch.stp

檢測裝置的讀寫

stap inodewatch.stp 0x08 0x01 100 -c "sleep 0.2"

#! /usr/bin/env stap

probe vfs.write, vfs.read

{

  # dev and ino are defined by vfs.write and vfs.read

  if (dev == MKDEV($1,$2)  && ino == $3)

    printf ("%s(%d) %s 0x%x/%u\n", execname(), pid(), probefunc(), dev, ino)

}



例3

io/iodevstats.stp

按讀寫資料量列舉裝置名

# stap iodevstats.stp -c "sleep 0.2"

#! /usr/bin/env stap

global reads, writes, totals

global vfs.read.return {

  if($return > 0) {

    reads[execname(),dev] <<

    totals[execname(),dev] += $retrun

  }

}

global vfs.write.return {

  if($return > 0) {

   writes[execname(),dev] <<

   totals[execname(),dev] += $return

  }

}

probe end {

  printf("\n%16s %8s %8s %8s %8s %8s %8s %8s\n","", "", "", "read", "read", "", "write", "write")

  printf("%16s %8s %8s %8s %8s %8s %8s %8s\n","name", "device", "read", "KB tot", "B avg", "write", "KB tot", "B avg")

  foreach([name,dev] in totals- limit 20) {

    printf("%16s %3d, %4d %8d %8d %8d %8d %8d %8d\n",name, MAJOR(dev), MINOR(dev),

      @count(reads[name,dev]),(@count(reads[name,dev]) ? @sum(reads[name,dev])>>10 : 0 ),(@count(reads[name,dev]) ? @avg(reads[name,dev]) : 0 ),

      @count(writes[name,dev]),(@count(writes[name,dev]) ? @sum(writes[name,dev])>>10 : 0 ),(@count(writes[name,dev]) ? @avg(writes[name,dev]) : 0 ))

  }

}



例4

io/ioblktime.stp

IO請求在佇列的等待時間,如果系統當前IO過於繁忙可能會超過maxmapentries設定,呼叫時可指定引數-DMAXMAPENTRIES=10000

# stap ioblktime.stp -c "sleep 0.2"

#! /usr/bin/env stap

global req_time, etimes

probe ioblock.request {

  req_time[$bio] = gettimeofday_us()

}

probe ioblock.end {

  t = gettimeofday_us()

  s = req_time[$bio]

  delete req_time[$bio] --如果系統IO繁忙則req_time陣列會很大,因此每次處理完都將其釋放

  if (s) {

    etimes[devname, bio_rw_str(rw)] <

  }  

}

/* for time being delete things that get merged with others */

probe kernel.trace("block_bio_frontmerge"),kernel.trace("block_bio_backmerge")

{

  delete req_time[$bio]

}

probe timer.s(10), end {

  ansi_clear_screen()

  printf("%10s %3s %10s %10s %10s\n","device", "rw", "total (us)", "count", "avg (us)")

  foreach ([dev,rw] in etimes - limit 20) {

    printf("%10s %3s %10d %10d %10d\n", dev, rw, @sum(etimes[dev,rw]), @count(etimes[dev,rw]), @avg(etimes[dev,rw]))

  }

  delete etimes

}


例5

io/disktop.stp

每5秒總結IO讀寫資訊,包括平均每秒讀寫KB數量以及呼叫次數排名前10的程式

# stap disktop.stp -c "sleep 0.2"

global readbytes,writebytes

global io_stat,device

probe vfs.read.return {

  if ($return > 0) {

    if (devname != "N/A" ) { /* 跳過cache read */

      io_stat[pid(),execname(),uid(),ppid(),"R"] += $return

      device[pid(),execname(),uid(),ppid(),"R"] = devname

      readbytes += $return

    }

  }

}

--vfs.write.return處理邏輯類似

probe vfs.write.return {

  if($return > 0) {

    if(devname != "N/A") {/*跳過cache write*/

      io_stat[pid(),execname(),uid(),ppid(),"W"] += $return

      device[pid(),execname(),uid(),ppid(),"W"] += devname

      writebytes += $return

    }

  }

}

probe timer.ms(5000) {--每5秒呼叫一次

  if ( readbytes + writebytes ) {

    printf("%-25s,%4dKb/sec,%6dKb,%6dkb\n",ctime(gettimeofday_s()),(readbytes+writebytes)/5,readbytes/1024,writebytes/1024)

  }

  foreach ([process,cmd,userid,parent,action] in io_stat- limit 10) /* 列印前10位*/

    printf("%8d %8d %8d %25s %8s %4s %12d\n",

           userid,process,parent,cmd,

           device[process,cmd,userid,parent,action],

           action,io_stat[process,cmd,userid,parent,action])

  --刪除陣列

  delete io_stat

  delete device

  read_bytes = 0

  write_bytes = 0  

}

probe end{

  delete io_stat

  delete device

  delete read_bytes

  delete write_bytes

}

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/15480802/viewspace-762765/,如需轉載,請註明出處,否則將追究法律責任。

相關文章