2015-06-09 83 views
4

我想計算單個進程的內存使用情況。所以經過一些研究之後,我發現了一些關於smaps和statm的內容。Linux操作系統:/ proc/[pid]/smaps vs/proc/[pid]/statm

首先什麼是smaps和statm?有什麼不同?

statm有一個字段RSS和smaps我總結了所有的RSS值。但是對於相同的過程,這些值是不同的。我知道頁面中的statm度量。爲了比較的目的,我將這個值轉換爲kb,如smaps。但是這些價值觀並不相同。 爲什麼這兩個值不同,即使它們代表同一過程的rss值?

statm 
232214 80703 7168 27 0 161967 0 (measured in pages, pages size is 4096) 

smaps 
Rss 1956 

我的目標是計算單個進程的內存使用情況。我對兩個價值觀感興趣。 USS和PSS。 我可以通過使用smaps獲得這兩個值嗎?這個值是否正確? 另外,我想以百分比形式返回該值。

+0

沒有人有任何有用的答案嗎? – tumbler

回答

0

我會建議尋找'頂部'的命令行源代碼。它從/ proc獲取所有信息,所以jt可能是一個很好的參考。

4

我認爲statm是一個近似的簡化smaps,這是更昂貴的得到。我來到這個結論我看着源後:

smaps

smaps看到/fs/proc/task_mmu.c定義的信息:

static int show_smap(struct seq_file *m, void *v, int is_pid) 
{ 
     (...) 

     struct mm_walk smaps_walk = { 
       .pmd_entry = smaps_pte_range, 
       .mm = vma->vm_mm, 
       .private = &mss, 
     }; 

     memset(&mss, 0, sizeof mss); 
     walk_page_vma(vma, &smaps_walk); 
     show_map_vma(m, vma, is_pid); 

     seq_printf(m, 
       (...) 
       "Rss:   %8lu kB\n" 
       (...) 
       mss.resident >> 10, 

/mm/pagewalk.c定義的使用walk_page_vmamss信息。然而,mss成員resident不填寫walk_page_vma - 相反,walk_page_vma調用回調smaps_walk規定:

.pmd_entry = smaps_pte_range, 
.private = &mss, 

這樣的:

if (walk->pmd_entry) 
     err = walk->pmd_entry(pmd, addr, next, walk); 

那麼什麼是我們的回調,smaps_pte_range/fs/proc/task_mmu.c,做? 它在某些情況下調用smaps_pte_entrysmaps_pmd_entry,其中兩個都叫statm_account(),反過來......升級resident大小!所有這些功能都在已經鏈接的task_mmu.c中定義,所以我沒有發佈相關的代碼片段,因爲它們可以在鏈接的源代碼中輕鬆查看。

PTE代表Page Table Entry,PMD是Page Middle Directory。所以基本上我們遍歷與給定進程相關聯的頁面條目並根據情況更新RAM使用情況。

statm

statm看到的信息在/fs/proc/array.c定義:

int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns, 
       struct pid *pid, struct task_struct *task) 
{ 
     unsigned long size = 0, resident = 0, shared = 0, text = 0, data = 0; 
     struct mm_struct *mm = get_task_mm(task); 

     if (mm) { 
       size = task_statm(mm, &shared, &text, &data, &resident); 
       mmput(mm); 
     } 
     seq_put_decimal_ull(m, 0, size); 
     seq_put_decimal_ull(m, ' ', resident); 
     seq_put_decimal_ull(m, ' ', shared); 
     seq_put_decimal_ull(m, ' ', text); 
     seq_put_decimal_ull(m, ' ', 0); 
     seq_put_decimal_ull(m, ' ', data); 
     seq_put_decimal_ull(m, ' ', 0); 
     seq_putc(m, '\n'); 
     return 0; 
} 

這一次,residenttask_statm填補。這個有兩個實現,一個在/fs/proc/task_mmu.c,另一個在/fs/proc/task_nomm.c。由於它們幾乎肯定是互斥的,因此我將重點介紹task_mmu.c(其中還包含task_smaps)中的實現。在此實現,我們看到

unsigned long task_statm(struct mm_struct *mm, 
        unsigned long *shared, unsigned long *text, 
        unsigned long *data, unsigned long *resident) 
{ 
     *shared = get_mm_counter(mm, MM_FILEPAGES); 
     (...) 
     *resident = *shared + get_mm_counter(mm, MM_ANONPAGES); 
     return mm->total_vm; 
} 

它查詢一些櫃檯,即MM_FILEPAGESMM_ANONPAGES。這些計數器在內存上的不同操作期間被修改,例如在/mm/memory.c處定義的do_wp_page。所有的修改似乎都是通過位於/mm/的文件完成的,而且似乎有相當多的修改,所以我沒有在這裏包括它們。

結論

smaps並通過所有被引用的內存區域和更新resident大小使用收集到的信息複雜的迭代。 statm使用已由其他人計算的數據。

最重要的部分是,雖然smaps每次都以獨立的方式收集數據,但statm使用在流程生命週期中增加或減少的計數器。有很多地方需要做簿記,也許有些地方不會像他們應該那樣升級櫃檯。這就是爲什麼IMO statm低於smaps,即使它需要更少的CPU週期來完成。

請注意,這是我根據常識得出的結論,但我可能是錯的 - 或許在計數器遞減和遞增時沒有內部不一致,相反,它們可能與smaps不同。在這一點上,我認爲把它交給一些有經驗的內核維護者是明智的。