如何使用其 ID 查找进程的 RAM 使用情况?

How do I find the RAM usage of a process using its ID?

我对这个内核的东西真的很陌生。我去了 here,我发现这段代码输出进程信息,比如它的 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)

代码:

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

我查找了如何查找一个进程使用了​​多少内存,然后发现了这个问题:Memory usage of current process in C

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

你显然可以使用:

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

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

虽然技术上您可以从内核 space 打开和读取文件,但出于多种原因,这通常不是一个好主意。 /proc下提供的任何信息,内核都已经可以使用了,你只需要弄清楚它在哪里以及如何获取它,你就可以在不读取任何文件的情况下完成模块中的所有操作。

您有兴趣了解特定进程在给定其 PID 时使用了多少 RAM,并且您认为此统计数据在 /proc/<PID>/status 中可用是正确的:事实上,它被标记为“VmRSS”,这意味着“虚拟内存 resident set size”。如果我们看一下内核源代码,我们可以确切地知道这个数字是如何计算的:

读取/proc/<PID>/status时调用的核函数为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 字段,例如 include/linux/mm.h 中的 get_mm_counter() does, or simply using get_mm_rss(),这正是我们想要的。

注意:

  1. get_mm_counter()get_mm_rss()获得的值是页数,你必须将它乘以页面大小(只需左移通过 PAGE_SHIFT).
  2. 如果您的内核编译时支持 MMU (CONFIG_MMU=y),您将只能执行此操作,您可以在模块代码中使用简单的 #ifdef#ifndef.

这是一个工作示例模块,可以为所有进程执行此操作:

// 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/sched/mm.h>     // get_task_mm(), mmput()
#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;
    struct mm_struct *mm;
    unsigned long rss;
    char comm[TASK_COMM_LEN];

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

    for_each_process(tsk) {
        get_task_struct(tsk);
        get_task_comm(comm, tsk);
        mm = get_task_mm(tsk);

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

/ # 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