我想计算单个进程的内存使用量。经过一些研究后,我发现了smaps和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 :(得分:7)
我认为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,
mss
中的信息由/mm/pagewalk.c
中定义的walk_page_vma
使用。但是,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);
那么/fs/proc/task_mmu.c
中的回调smaps_pte_range
是做什么的呢?
在某些情况下,它会调用smaps_pte_entry
和smaps_pmd_entry
,其中两个都会调用statm_account()
,而resident
会升级task_mmu.c
大小!所有这些功能都在已经链接的statm
中定义,因此我没有发布相关的代码片段,因为它们可以在链接的源中轻松查看。
PTE代表Page Table Entry,PMD代表Page Middle Directory。所以基本上我们遍历与给定进程关联的页面条目,并根据具体情况更新RAM使用情况。
statm
您在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;
}
中看到的信息在/fs/proc/array.c中定义:
resident
这一次,task_statm
由task_mmu.c
填充。这个有两个实现,一个在/fs/proc/task_mmu.c
,第二个在/fs/proc/task_nomm.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_FILEPAGES
它查询一些计数器,即MM_ANONPAGES
和do_wp_page
。这些计数器在内存的不同操作期间被修改,例如/mm/memory.c
定义的/mm/
。所有修改似乎都是由smaps
中的文件完成的,而且似乎有很多这些修改,所以我没有在这里包含它们。
resident
对所有引用的内存区域进行复杂的迭代,并使用收集的信息更新statm
大小。 smaps
使用已由其他人计算过的数据。
最重要的部分是,statm
每次以独立方式收集数据时,statm
使用在进程生命周期中递增或递减的计数器。有很多地方需要进行簿记,也许有些地方不会像他们应该那样升级柜台。这就是为什么IMO smaps
不如smaps
,即使它需要较少的CPU周期来完成。
请注意,这是我根据常识得出的结论,但我可能错了 - 也许在计数器递减和递增中没有内部不一致,相反,它们可能会计算某些页面的不同于$newArray = array();
$dates = array();
foreach($array as $entry) {
$newArray[$entry['id']][$entry['hour']][$entry['date']]= $entry['total'];
if(!in_array($entry['date'], $dates)) $dates[] = $entry['date'];
}
sort($dates);
echo "id hour ". $dates[0] . " " . $dates[1] . " " . "difference"."\n";
foreach($newArray as $id => $hours)
foreach($hours as $hour => $entry)
echo $id ." " . $hour . " "
. $entry[$dates[0]] . " "
. $entry[$dates[1]] . " "
. ($entry[$dates[1]] - $entry[$dates[0]]) . "\n";
。在这一点上,我认为将它带给一些经验丰富的内核维护者是明智的。
答案 1 :(得分:0)
我建议通过' top'命令行源代码。它从/ proc获取所有信息,因此jt可能是一个很好的参考。