如何使用其ID查找进程的RAM使用情况? [英] How do I find the RAM usage of a process using its ID?

查看:82
本文介绍了如何使用其ID查找进程的RAM使用情况?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我真的很陌生.我在这里,我发现这段代码可以输出过程信息,例如其ID.

I am really new to this Kernel stuff. I went here and I found this code that outputs process information like its ID.

main.c :

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched/signal.h>
#include <linux/sched.h>
 
 
struct task_struct *task;        /*    Structure defined in sched.h for tasks/processes    */
struct task_struct *task_child;        /*    Structure needed to iterate through task children    */
struct list_head *list;            /*    Structure needed to iterate through the list in each task->children struct    */
 
int iterate_init(void)                    /*    Init Module    */
{
    printk(KERN_INFO "%s","LOADING MODULE\n");    /*    good practice to log when loading/removing modules    */
     
    for_each_process( task ){            /*    for_each_process() MACRO for iterating through each task in the os located in linux\sched\signal.h    */
        printk(KERN_INFO "\nPARENT PID: %d PROCESS: %s STATE: %ld",task->pid, task->comm, task->state);/*    log parent id/executable name/state    */
        list_for_each(list, &task->children){                        /*    list_for_each MACRO to iterate through task->children    */
 
            task_child = list_entry( list, struct task_struct, sibling );    /*    using list_entry to declare all vars in task_child struct    */
     
            printk(KERN_INFO "\nCHILD OF %s[%d] PID: %d PROCESS: %s STATE: %ld",task->comm, task->pid, /*    log child of and child pid/name/state    */
                task_child->pid, task_child->comm, task_child->state);
        }
        printk("-----------------------------------------------------");    /*for aesthetics*/
    }    
     
 
    return 0;
 
}                /*    End of Init Module    */
     
void cleanup_exit(void)        /*    Exit Module    */
{
 
 
    printk(KERN_INFO "%s","REMOVING MODULE\n");
 
}                /*    End of Exit Module    */
 
module_init(iterate_init);    /*    Load Module MACRO    */
module_exit(cleanup_exit);    /*    Remove Module MACRO    */
 
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("ITERATE THROUGH ALL PROCESSES/CHILD PROCESSES IN THE OS");
MODULE_AUTHOR("Laerehte");

Makefile :

obj-m += main.o
 
all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
 
clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

使用 ./ins (使用chmod + x)执行

Executed with ./ins (with chmod +x)

代码:

sudo insmod main.ko
sudo rmmod main
sudo dmesg -c

我查找了如何查找进程使用多少内存,然后发现了以下问题:

I looked up how to find how much memory a process uses, and I found this question: Memory usage of current process in C.

如果我错了,请纠正我,但是我认为您可以通过查看/proc/[process_id]/status 来读取这些进程的当前RAM使用情况.我从另一个地方(忘记了地方)发现,在此文件中,有一个名为VmRSS的东西可以保存当前进程的RAM使用情况.

Correct me if I'm wrong here, but I'm thinking that you can read the current RAM usage of these processes by looking in /proc/[process_id]/status. I found out from another place(forgot where) that within this file, there is something called VmRSS that would hold the current RAM usage of the process.

您显然可以使用:

ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos);

读取文件,但是我无法成功修改 main.c .我需要找到文件的大小,但我也无法正确使用 vfs_stat .当我只尝试一些常量整数时,无论如何我都会在缓冲区中获得全0.我不知道如何正确使用这些功能.我正在尝试修改main.c,以便我将看到这些进程的RAM使用情况以及其他信息.我发现的许多信息都是过时的.有人可以帮忙吗?

to read a file, but I have not been able to modify main.c with this successfully. I need to find the size of the file, but I also have not been able to use vfs_stat correctly. When I just try some constant integer, I get all 0s in the buffer anyway. I don't know how to use these functions properly. I'm trying to modify main.c so that I will see the RAM usage of these processes along with the other information. Much of the information I found was outdated. Can anyone help?

推荐答案

虽然从技术上讲您可以从内核空间打开和读取文件,但是出于多种原因,通常这是个坏主意.内核已经可以使用/proc 下提供的任何信息,您只需要弄清楚它在哪里以及如何获取它,就可以在模块中完成所有操作,而无需阅读任何内容.文件.

While you can technically open and read files from kernel space, it's usually a bad idea for multiple reasons. Whatever information is provided under /proc is already available to the kernel, you just need to figure out where it is and how to obtain it, and you will be able to do everything in your module without reading any file.

您有兴趣使用给定的PID来了解特定进程有多少RAM,并且您正确地知道此统计信息在/proc/< PID>/status 中可用:实际上,它被标记为"VmRSS".这表示虚拟内存居民集大小".如果我们看一下内核源代码,我们可以确切地看到该数字的计算方式:

You are interested in knowing how much RAM is a particular process using given its PID, and you are correct that this statistic is available in /proc/<PID>/status: in fact, it is labeled as "VmRSS" which means "virtual memory resident set size". If we take a look at the kernel source code, we can see exactly how that number is calculated:

读取/proc/< PID>/stats 时调用的内核函数是 task_mem() .

The kernel function called when reading /proc/<PID>/stats is proc_pid_status() in fs/proc/array.c, which then calls (among the other things) task_mem().

    // ...
    anon = get_mm_counter(mm, MM_ANONPAGES);
    file = get_mm_counter(mm, MM_FILEPAGES);
    shmem = get_mm_counter(mm, MM_SHMEMPAGES);
    // ...
    hiwater_rss = total_rss = anon + file + shmem;
    // ...
    SEQ_PUT_DEC(" kB\nVmHWM:\t", hiwater_rss);
    SEQ_PUT_DEC(" kB\nVmRSS:\t", total_rss); // <===== here it is
    SEQ_PUT_DEC(" kB\nRssAnon:\t", anon);
    // ...

因此,您可以通过相同的方式获得此信息.首先,确定要检查的进程的 task_struct ,然后检查-> mm 字段,例如 get_mm_rss() 来自 include/linux/mm.h ,这正是我们想要的.

You can therefore obtain this information in the same way. First get ahold of the task_struct of the process you want to check, then inspect the ->mm field like get_mm_counter() does, or simply using get_mm_rss() from include/linux/mm.h, which does exactly what we want.

请注意:

  1. get_mm_counter() get_mm_rss()获得的值是页数,您必须将其乘以页数大小(只需向左移 PAGE_SHIFT ).
  2. 仅当您的内核是在 MMU 支持下编译的,您才能执行此操作( CONFIG_MMU = y ),您可以使用简单的 #ifdef #ifndef 在模块代码中进行检查.
  1. The value obtained from get_mm_counter() or get_mm_rss() is the number of pages, you will have to multiply this by the page size (simply shift left by PAGE_SHIFT).
  2. You will only be able to do this if your kernel was compiled with MMU support (CONFIG_MMU=y), you can check this in your module code with a simple #ifdef or #ifndef.

这是一个适用于所有过程的示例模块:

Here's a working example module to do this for all processes:

// SPDX-License-Identifier: GPL-3.0
#include <linux/kernel.h>       // printk(), pr_*()
#include <linux/module.h>       // THIS_MODULE, MODULE_VERSION, ...
#include <linux/init.h>         // module_{init,exit}
#include <linux/sched/task.h>   // struct task_struct, {get,put}_task_struct()
#include <linux/sched/signal.h> // for_each_process()
#include <linux/mm.h>           // get_mm_rss()

/* Tested on kernel 5.6, qemu-system-aarch64
 * Usage: sudo insmod task_rss
 *        sudo modprobe task_rss
 */

#ifdef pr_fmt
#undef pr_fmt
#endif
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

static int __init modinit(void)
{
    struct task_struct *tsk;
    unsigned long rss;

#ifndef CONFIG_MMU
    pr_err("No MMU, cannot calculate RSS.\n");
    return -EINVAL;
#endif

    for_each_process(tsk) {
        get_task_struct(tsk);

        // https://www.kernel.org/doc/Documentation/vm/active_mm.rst
        if (tsk->mm) {
            rss = get_mm_rss(tsk->mm) << PAGE_SHIFT;
            pr_info("PID %d (\"%s\") VmRSS = %lu bytes\n", tsk->pid, tsk->comm, rss);
        } else {
            pr_info("PID %d (\"%s\") is an anonymous process\n", tsk->pid, tsk->comm);
        }

        put_task_struct(tsk);
    }

    return 0;
}

static void __exit modexit(void)
{
    // This function is only needed to be able to unload the module.
}

module_init(modinit);
module_exit(modexit);
MODULE_VERSION("0.1");
MODULE_DESCRIPTION("Silly test module to calculare task RSS of all running tasks.");
MODULE_AUTHOR("Marco Bonelli");
MODULE_LICENSE("GPL");

我的机器上的输出( qemu-system-aarch64 ):

Output on my machine (qemu-system-aarch64):

/ # insmod task_rss.ko
[    7.306284] task_rss: loading out-of-tree module taints kernel.
[    7.312912] task_rss: PID 1 ("init") VmRSS = 4096 bytes
[    7.313295] task_rss: PID 2 ("kthreadd") is an anonymous process
[    7.314039] task_rss: PID 3 ("rcu_gp") is an anonymous process
...
[    7.330169] task_rss: PID 146 ("sh") VmRSS = 1363968 bytes
[    7.330554] task_rss: PID 147 ("insmod") VmRSS = 1339392 bytes

这篇关于如何使用其ID查找进程的RAM使用情况?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆