如何使用其 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()
,这正是我们想要的。
注意:
- 从
get_mm_counter()
或get_mm_rss()
获得的值是页数,你必须将它乘以页面大小(只需左移通过 PAGE_SHIFT
).
- 如果您的内核编译时支持 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
我对这个内核的东西真的很陌生。我去了 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()
,这正是我们想要的。
注意:
- 从
get_mm_counter()
或get_mm_rss()
获得的值是页数,你必须将它乘以页面大小(只需左移通过PAGE_SHIFT
). - 如果您的内核编译时支持 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