硬件软件系统方案应用范例智能车大赛技术支持学习园地关于我们恩智浦官网

在云实验室开发板上实验task struct(3)

Linux进程task struct结构里有一个很重要的内存相关mm字段,本用例展示mm字段指向的mm struct的重要参数。其中pgd是页全局目录指针,可以追踪进程的虚拟地址到物理地址的映射关系,调试与页表相关的错误,例如页表项是否正确初始化。参数pgtables_bytes表示进程页表占用内存的大小,帮助评估进程页表的内存占用情况。参数total_vm表示进程虚拟内存总大小,通过监控total_vm的变化,可以发现进程是否过度申请虚拟内存,从而导致系统性能下降。参数stack_vm表示栈映射的页面数,通过监控栈的大小,可以发现栈溢出的风险。参数RSS表示进程实际占用的物理内存页数,通过监控RSS增长情况,可以发现内存泄露问题。

1.      在实验本节代码前,准备环境一个ubuntu物理机或者虚拟机,下载并使能交叉编译工具链,然后编译好内核源码,参考《编译内核镜像并在云实验室开发板运行》

2.      Linux kernel进程内存参数的示例代码:

在你要写代码的目录下用touch新建两个文件,一个源码文件,一个Makefile。如下

~/linux_driver/ 08_process_mem$ touch 08_process_mem.c

~/linux_driver/08_process_mem$ touch Makefile

~/linux_driver/08_process_mem$ vim 08_process_mem.c

将下面的代码复制到08_process_mem.c, 如下:

/*
* Copyright 2025 NXP
* SPDX-License-Identifier: GPL-2.0+
*/

 1 #include <linux/module.h>

 2 #include <linux/types.h>

 3 #include <linux/init.h>

 4 #include <linux/cdev.h>

 5 #include <linux/mm.h>

 6

 7

 8 MODULE_LICENSE("GPL");

 9 MODULE_AUTHOR("Cloud Lab");

10

11 #define BUF_LEN      0x1000

12 #define VIRTCHARDEV_NAME "virtdev"

13

14 struct virtchardev

15 {

16         dev_t virtdev_id;

17         struct cdev virtdev_cdev;

18         struct class *class;

19         struct device *device;

20         int virtdev_major;

21         int virtdev_minor;

22         struct semaphore sema;

23

24         struct cdev cdev;

25         unsigned char mem[BUF_LEN];

26

27 };

28

29 struct virtchardev *virtdev;

30

31

32 int virtdev_open(struct inode *inode, struct file *filp)

33 {

34         filp->private_data = virtdev;

35

36         down_interruptible(&virtdev->sema);

37         return 0;

38 }

39

40 int virtdev_release(struct inode *inode, struct file *filp)

41 {

42         struct virtchardev *dev = filp->private_data;

43

44         up(&dev->sema);

45         return 0;

46 }

47

48 static ssize_t virtdev_read(struct file *filp, char __user *buf,

49                         size_t size, loff_t *ppos)

50 {

51         unsigned long p =  *ppos;

52         unsigned int count = size;

53         int ret = 0;

54         struct virtchardev *dev = filp->private_data;

55

56         if (p >= BUF_LEN)

57         {

58                 printk("*ppos = %d\n", p);

59                 return count ? -ENXIO : 0;

60         }

61

62         if (count > BUF_LEN - p)

63         {

64                 count = BUF_LEN - p;

65         }

66         if (copy_to_user(buf, (void*)(dev->mem + p), count))

67         {

68                 ret =  - EFAULT;

69         }

70         else

71         {

72                 *ppos += count;

73                 ret = count;

74

75                 printk(KERN_INFO "read %d bytes(s) from %d\n", count, p);

76         }

77         printk("Process state,priority,schedule policy info::\n"

78                "module                                  : %s\n"

79                "process name                            : %s\n"

80                "PGD start addr                          : 0x%lx\n"

81                "PTE table pages number                  : %d\n"

82                "The pages total mapped                  : %d KB\n"

83                "Resident Set Size(RSS)                  : %d KB\n"

84                "Stack size(VM)                          : %d KB\n",

85                VIRTCHARDEV_NAME,

86                current->comm,

87                current->mm->pgd,

88                current->mm->pgtables_bytes,

89                current->mm->total_vm << (PAGE_SHIFT - 10),

90                get_mm_rss(current->mm) << (PAGE_SHIFT - 10),

91                current->mm->stack_vm << (PAGE_SHIFT - 10)

92         );

93

94         return ret;

95 }

96

97 static ssize_t virtdev_write(struct file *filp, const char __user   *buf,

98                         size_t size, loff_t *ppos)

99 {

100         unsigned long p =  *ppos;

101         unsigned int count = size;

102         int ret = 0;

103         void *kbuf = NULL;

104         struct virtchardev *dev = filp->private_data;

105

106         kbuf = kvmalloc(size, GFP_KERNEL);

107         memset(kbuf, 0, count);

108         if (copy_from_user(kbuf, buf, count) != 0){

109                 ret =  - EFAULT;

110         }

111         strscpy(dev->mem, kbuf, (count > BUF_LEN ? BUF_LEN : count));

112         ret = count;

113         printk("write bytes: %zu\n", count);

114         printk("Process state,priority,schedule policy info::\n"

115                "module                                  : %s\n"

116                "process name                            : %s\n"

117                "PGD start addr                          : 0x%lx\n"

118                "PTE table pages number                  : %d\n"

119                "The pages total mapped                  : %d KB\n"

120                "Resident Set Size(RSS)                  : %d KB\n"

121                "Stack size(VM)                          : %d KB\n",

122                VIRTCHARDEV_NAME,

123                current->comm,

124                current->mm->pgd,

125                current->mm->pgtables_bytes,

126                current->mm->total_vm << (PAGE_SHIFT - 10),

127                get_mm_rss(current->mm) << (PAGE_SHIFT - 10),

128                current->mm->stack_vm << (PAGE_SHIFT - 10)

129         );

130

131         return ret;

132 }

133

134 static const struct file_operations virtdev_fops =

135 {

136         .owner = THIS_MODULE,

137         .read = virtdev_read,

138         .write = virtdev_write,

139         .open = virtdev_open,

140         .release = virtdev_release,

141 };

142

143

144 int virtdev_init(void)

145 {

146         virtdev = kmalloc(sizeof(struct virtchardev), GFP_KERNEL);

147         memset(virtdev, 0, sizeof(struct virtchardev));

148         printk("%s %d\n", __func__, __LINE__);

149         sema_init(&virtdev->sema, 1);

150         alloc_chrdev_region(&virtdev->virtdev_id, 0, 1,

151                                 VIRTCHARDEV_NAME );

152         virtdev->virtdev_major = MAJOR(virtdev->virtdev_id);

153

154         cdev_init(&virtdev->virtdev_cdev, &virtdev_fops);

155

156         virtdev->virtdev_cdev.owner = THIS_MODULE;

157         virtdev->virtdev_cdev.ops = &virtdev_fops;

158

159         cdev_add(&virtdev->virtdev_cdev, virtdev->virtdev_id, 1);

160

161         printk("%s %d\n", __func__, __LINE__);

162         virtdev->class = class_create(/*THIS_MODULE,*/ VIRTCHARDEV_NAME);

163

164         device_create(virtdev->class, NULL, virtdev->virtdev_id,

165                         NULL, VIRTCHARDEV_NAME);

166         printk("Process state,priority,schedule policy info::\n"

167                "module                                  : %s\n"

168                "process name                            : %s\n"

169                "PGD start addr                          : 0x%lx\n"

170                "PTE table pages number                  : %d\n"

171                "The pages total mapped                  : %d KB\n"

172                "Resident Set Size(RSS)                  : %d KB\n"

173                "Stack size(VM)                          : %d KB\n",

174                VIRTCHARDEV_NAME,

175                current->comm,

176                current->mm->pgd,

177                current->mm->pgtables_bytes,

178                current->mm->total_vm << (PAGE_SHIFT - 10),

179                get_mm_rss(current->mm) << (PAGE_SHIFT - 10),

180                current->mm->stack_vm << (PAGE_SHIFT - 10)

181         );

182

183         return 0;

184 }

185

186 void virtdev_exit(void)

187 {

188         cdev_del(&virtdev->virtdev_cdev);

189         unregister_chrdev_region(virtdev->virtdev_id, 1);

190

191         device_destroy(virtdev->class, virtdev->virtdev_id);

192         class_destroy(virtdev->class);

193

194         kfree(virtdev);

195

196 }

197

198 module_init(virtdev_init);

199 module_exit(virtdev_exit);


编写Makefile:

PWD    := $(shell pwd)

KERDIR := /home/test/kernel_build/linux-imx

obj-m += 08_process_mem.o

all:

       make -C $(KERDIR) M=$(PWD) modules

clean:

       make -C $(KERDIR) M=$(PWD) clean

3.      编译:

~/linux_driver/08_process_mem$ export CROSS_COMPILE=~/toolchain/arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-

~/linux_driver/08_process_mem$ export ARCH=arm64

~/linux_driver/08_process_mem$ make

编译完成后当前目录会有如下文件

~/linux_driver/08_process_mem$ ls

08_process_mem.ko

4.      替换云实验室开发板镜像并重新启动

根据《编译内核镜像并在云实验室开发板运行》替换dtb和image,这里仍然需要这一步,因为内核模块在加载时需要和内核编译版本相匹配

上传并替换云实验室板子的dtb和Image,依次点击用户网页端下面1,2,3的位置,在点击位置2时,选择TFTP,点击3后选择文件~/kernel_build/linux-imx/arch/arm64/boot/dts/freescale/imx8mp-evk.dtb和~/kernel_build/linux-imx/arch/arm64/boot/Image

上传成功后,点击下方PowerReset EVK按钮,重启开发板。

至此,开发板开始运行自己修改编译的linux镜像。

5.      上传自己编译的字符驱动模块

在4中编译出了关于mutex应用的内核驱动程序08_process_mem.ko,通过一次点击下图中的1,2,3位置,然后切换到本地对应的文件目录上传。

6.      运行字符驱动模块

在执行下面的操作前要先使能串口终端的log打印,否则会看不到串口终端打印信息:

root@imx93evk:~# echo 8 > /proc/sys/kernel/printk

执行insmod加载模块,可以看到log里打印出了pgd,pgtables_byte,,total_vms,stack_vm,RSS等信息。

当向内核模块写入字符串,可以看到sh进程在工作,并打印了相关信息

然后读取刚才写入的信息时,可以看到cat进程的相关信息,log如下: