安利一個實用小工具 oscillo:幫助你觀察命令運行時在時間軸上的cpu和內存佔用率

demo

如果使用過glances,如果有一顆geek的心的話,一定會覺得不但酷炫而且十分實用。不過如果想觀察一個程序從運行開始到結束的cpu佔用率怎麼辦?好辦,利用python的psutil異步觀察就行。

介紹一下放在github上的一個項目: oscillo

使用方式

使用方式很簡單,直接 pip install oscillo即可安裝使用.

命令行參數的格式是 "<name>: <command [args]>"

  • name: 命令行的別名/id (任意字符串),當--commands/-c參數指定多個命令時,該值將作爲命令的唯一標識,不可重複
  • command [args]: 需要測試資源消耗的命令,比如 gzip file.ext

示例如下,監控gzip壓縮一個文件時耗費的cpu、memory和時間:

oscillo -c 'gzip: gzip file.ext' -o output-file
  • -c 代表將執行一個linux cmd 命令。參數後面可以跟以空格隔開的多個參數
  • -o 結果輸出文件:

命令執行完成後,會在當前目錄下生成一個<output-file>.log 文件。文本結構是json 格式. 數據結構如下

{
  "test": {
            "elapsed": 0.022143125534057617,  //總執行時間
            "cpu": [], 
            "memory": []
          }
}

同時會產生一個<output-file>.png文件,<output-file>-o參數指定,默認值爲metrix

在控制檯上,oscillo會打印summary信息,其中包含命令的耗時、最大內存使用、最大cpu使用、退出碼等在控制檯上,oscillo會打印summary信息,其中包含命令的耗時、最大內存使用、最大cpu使用、退出碼等

如果想對比多個命令對資源的消耗,可以使用 -c/--commands 選項指定多條命令, e.g.:

對比gziptar命令對資源的消耗:

oscillo -c 't1: gzip file.ext'  't2: tar czf target.tar.gz file1' -o output

效果如下:

demo

demo

實現原理

這個工具的原型,來自於一次爲了對比幾種客戶端性能而寫的一個腳本,它的原理就是:

  • 在程序中啓動一個子進程,獲取進程id
  • 通過psutil觀察該進程,每隔一段時間記錄一次cpu和內存的負載
  • 通過matplotlib畫圖

說一下其中碰到的一個坑:欲監控的子進程A在內部調用了另一個耗資源的子進程B,但是psutil只能觀察到子進程A的資源消耗情況,粗暴的解決辦法就是:觀察全局的資源消耗情況:

class Stopwatch(object):

    def __init__(self, pid):
        self.__is_run = False
        self.__start_time = 0
        self.__elapsed_times = 0
        self.memory_percent = []
        self.cpu_percent = []
        self.pid = pid

    def start(self):
        if self.__is_run:
            return False
        self.__is_run = True
        self.__start_time = time.time()

        if self.pid > 0:
            p = psutil.Process(self.pid)
        else:
            p = psutil
            p.memory_percent = lambda: p.virtual_memory().percent
        while self.__is_run:
            try:
                self.cpu_percent.append(p.cpu_percent(1))
                self.memory_percent.append(p.memory_percent())
            except psutil.NoSuchProcess:
                break

    @property
    def elapsed(self):

        if self.__is_run:
            return self.__elapsed_times + time.time() - self.__start_time
        return self.__elapsed_times

    def stop(self):
        self.__elapsed_times = self.elapsed
        self.__is_run = False

BTW

當前的功能比較簡單,可能有很多東西沒用想到,歡迎使用和完善

git倉庫: oscillo

原文地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章