当前位置: 首页 > wzjs >正文

基于django电商网站开发课设报告怎么免费建个免费的站点

基于django电商网站开发课设报告,怎么免费建个免费的站点,企业网站的建设报价,网页制作与网站建设 自考一、背景 madvise系统调用是一个与性能优化强相关的一个系统调用。madvise系统调用包括使用madvise函数,也包含使用posix_fadvise函数。如我们可以使用posix_fadvise传入POSIX_FADV_DONTNEED来清除文件页的page cache以减少内存压力。 这篇博客里,我们…

一、背景

madvise系统调用是一个与性能优化强相关的一个系统调用。madvise系统调用包括使用madvise函数,也包含使用posix_fadvise函数。如我们可以使用posix_fadvise传入POSIX_FADV_DONTNEED来清除文件页的page cache以减少内存压力。

这篇博客里,我们讲的是madvise(addr,size,MADV_FREE)这个调用,要注意,这个调用只能针对匿名内存,对于文件页的对应的内存是调用这个会报错(这一点会在下面 3.1 里讲到)。

在下面第二章里,我们贴出测试源码并说明测试方法并展示测试结果。在第三章里,我们给出相关细节的原理分析。

二、测试程序源码及效果展示

2.1 测试源码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>#define PAGE_SIZE 4096ull
#define NUM_PAGES 1024*512ull // 分配 2G 的内存int main() {// 分配一块大的匿名内存size_t size = NUM_PAGES * PAGE_SIZE;void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);if (addr == MAP_FAILED) {perror("mmap");return EXIT_FAILURE;}printf("Allocated %zu bytes of anonymous memory at %p\n", size, addr);// 触发缺页异常printf("Accessing a page to trigger a page fault...\n");memset(addr, 0, size); // 访问第一页getchar();// 在这里可以观察到缺页异常的发生// 使用 madvise 将未使用的页面标记为 MADV_DONTNEEDif (madvise(addr, size, MADV_FREE) != 0) {perror("madvise MADV_FREE");munmap(addr, size);return EXIT_FAILURE;}printf("Marked memory as MADV_FREE\n");getchar();printf("Reuse the memory!\n");memset(addr, 0, size); // 访问第一页// 等待 10 秒getchar();// 再次使用 madvise 将内存标记为 MADV_DONTNEED(这在实际情况下是没有必要的,因为上面已经释放了)// 只是为了演示if (madvise(addr, size, MADV_DONTNEED) != 0) {perror("madvise MADV_DONTNEED");munmap(addr, size);return EXIT_FAILURE;}printf("Re-marked memory as MADV_DONTNEED\n");getchar();// 解除映射if (munmap(addr, size) != 0) {perror("munmap");return EXIT_FAILURE;}getchar();printf("Unmapped memory\n");return EXIT_SUCCESS;
}

2.2 编写一个内核模块用来抓取调用栈和调用信息

编写了一个内核模块,用来抓取madvise这个调用栈和调用信息。

2.2.1 内核模块源码

下面的这个代码是改写的之前在分析vdso内容时写的内核模块(vdso概念及原理,vdso_fault缺页异常,vdso符号的获取_x86架构的vdso-CSDN博客 里 2.3.1 一节里的代码),改写了一下,所以名字里包含了vdso字样。

关键的改动即注册kprobe的callback时设了lru_lazyfree_fn这个接口:

然后加入了一个pid的条件控制:

在指定的pid进程内才打印堆栈,也只打印一次,然后统计执行的次数,并打印:

完整的代码如下:

#include <linux/module.h>
#include <linux/capability.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/ctype.h>
#include <linux/seq_file.h>
#include <linux/poll.h>
#include <linux/types.h>
#include <linux/ioctl.h>
#include <linux/errno.h>
#include <linux/stddef.h>
#include <linux/lockdep.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/wait.h>
#include <linux/init.h>
#include <asm/atomic.h>
#include <trace/events/workqueue.h>
#include <linux/sched/clock.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/tracepoint.h>
#include <trace/events/osmonitor.h>
#include <trace/events/sched.h>
#include <trace/events/irq.h>
#include <trace/events/kmem.h>
#include <linux/ptrace.h>
#include <linux/uaccess.h>
#include <asm/processor.h>
#include <linux/sched/task_stack.h>
#include <linux/nmi.h>
#include <asm/apic.h>
#include <linux/version.h>
#include <linux/sched/mm.h>
#include <asm/irq_regs.h>
#include <linux/kallsyms.h>
#include <linux/kprobes.h>
#include <linux/stop_machine.h>MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhaoxin");
MODULE_DESCRIPTION("Module for vdso_fault debug.");
MODULE_VERSION("1.0");static int pid = 0;
module_param(pid, int, 0);struct kprobe _kp1;static bool _blog = false;int getfullpath(struct inode *inode,char* i_buffer,int i_len)
{struct dentry *dentry;//printk("inode = %ld\n", inode->i_ino);//spin_lock(&inode->i_lock);hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {char *buffer, *path;buffer = (char *)__get_free_page(GFP_KERNEL);if (!buffer)return -ENOMEM;path = dentry_path_raw(dentry, buffer, PAGE_SIZE);if (IS_ERR(path)){continue;   }strlcpy(i_buffer, path, i_len);//printk("dentry name = %s , path = %s", dentry->d_name.name, path);free_page((unsigned long)buffer);}//spin_unlock(&inode->i_lock);return 0;
}static bool blog = false;
static u64 runtimes = 0;int kprobecb_vdso_fault_pre(struct kprobe* i_k, struct pt_regs* i_p)
{if (current->pid == pid) {if (!blog) {blog = true;dump_stack();}runtimes ++;printk("run lru_lazyfree_fn %llu times!\n", runtimes);}return 0;
}int kprobe_register_func_vdso_fault(void)
{int ret;memset(&_kp1, 0, sizeof(_kp1));_kp1.symbol_name = "lru_lazyfree_fn";_kp1.pre_handler = kprobecb_vdso_fault_pre;_kp1.post_handler = NULL;ret = register_kprobe(&_kp1);if (ret < 0) {printk("register_kprobe fail!\n");return -1;}printk("register_kprobe success!\n");return 0;
}void kprobe_unregister_func_vdso_fault(void)
{unregister_kprobe(&_kp1);
}static int __init testvdso_init(void)
{kprobe_register_func_vdso_fault();return 0;
}static void __exit testvdso_exit(void)
{kprobe_unregister_func_vdso_fault();
}module_init(testvdso_init);
module_exit(testvdso_exit);

2.2.2 抓到的madvise的调用栈和调用信息

抓到的堆栈:

如下图可以看到执行了524280次,是0x7FFF8,离2G的0x80000个4k page的0x80000的个数差了8:

这个差值来自于下图里的红色框出逻辑的批处理逻辑的判断:

2.3 看/proc/meminfo和free -h的测试结果

我们关注运行测试程序期间及之前和之后的/proc/meminfo和free -h的状态变化。

2.3.1 对比观察free -h的变化

程序运行前,buff/cache是14G,free是106G:

执行程序之后,并触发2G的缺页异常之后:

看free -h的变化是,buff/cache不变,free减少2G,从106G到104G:

然后再运行madvise(addr, size, MADV_FREE):

从free -h看是没有变化的:

所以,madvise(addr, size, MADV_FREE)的执行对free -h的统计是不产生变化的。

2.3.2 对比观察/proc/meminfo的变化

观察的脚本是:

watch -n 0.1 "cat /proc/meminfo | grep -E 'MemFree|Buffers|Cached|Active|Inactive|\(anon\)|\(file\)|AnonPages|Mapped'"

我们只观察我们需要重点关注这几项。

执行程序前是:

触发2G的缺页异常之后:

可以看到MemFree如预期减少2G,Active统计增加2G,Active(anon)统计增加2G,Active(file)统计不增加。对于AnonPages统计项,是增加了2G,对于Mapped统计项,未变动。

再继续运行程序,调用madvise(addr, size, MADV_FREE)之后:

可以如上图看到,在这个调用的前后情况来看,MemFree无变化,Buffers/Cached都无变化,Active里减少2G到了Inactive里,即从Active(anon)里减少了2G到了Inactive(file)里。

而对于AnonPages统计项和Mapped统计项,这个madvise(addr, size, MADV_FREE)调用无变动。

三、原理分析

3.1 madvise(addr, size, MADV_FREE)不能用于文件页

我们把 2.1 里的源码修改一下,修改过后的源码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>#define PAGE_SIZE 4096ull
#define NUM_PAGES 1024*512ull // 分配 2G 的内存int main() {size_t size = NUM_PAGES * PAGE_SIZE;int fd = open("temp_file.bin", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);if (fd == -1) {perror("open");return EXIT_FAILURE;}if (ftruncate64(fd, size) == -1) {perror("ftruncate");close(fd);return EXIT_FAILURE;}// 分配一块大的匿名内存void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (addr == MAP_FAILED) {perror("mmap");return EXIT_FAILURE;}printf("Allocated %zu bytes of anonymous memory at %p\n", size, addr);// 触发缺页异常printf("Accessing a page to trigger a page fault...\n");memset(addr, 0, size); // 访问第一页getchar();// 在这里可以观察到缺页异常的发生// 使用 madvise 将未使用的页面标记为 MADV_DONTNEEDif (madvise(addr, size, MADV_FREE) != 0) {perror("madvise MADV_FREE");munmap(addr, size);return EXIT_FAILURE;}//posix_fadvise(fd, 0, size, POSIX_FADV_DONTNEED);printf("Marked memory as MADV_FREE\n");getchar();printf("Reuse the memory!\n");memset(addr, 0, size); // 访问第一页// 等待 10 秒getchar();// 再次使用 madvise 将内存标记为 MADV_DONTNEED(这在实际情况下是没有必要的,因为上面已经释放了)// 只是为了演示if (madvise(addr, size, MADV_DONTNEED) != 0) {perror("madvise MADV_DONTNEED");munmap(addr, size);return EXIT_FAILURE;}printf("Re-marked memory as MADV_DONTNEED\n");getchar();// 解除映射if (munmap(addr, size) != 0) {perror("munmap");return EXIT_FAILURE;}getchar();printf("Unmapped memory\n");return EXIT_SUCCESS;
}

运行后看到madvise(addr, size, MADV_FREE)这句话调用出错:

所以madvise(addr, size, MADV_FREE)的这个调用只能用于匿名内存。

3.2 madvise(addr, size, MADV_FREE)会将该匿名内存挪到Inactive(file)里

有关这个统计项的迁移的核心逻辑即调用madvise(addr, size, MADV_FREE)时最终调用到:

folio_mark_lazyfree调用了lru_lazyfree_fn

在lru_lazyfree_fn里完成了统计上的迁移。

这个迁移从folio_mark_lazyfree函数的注释里也可以清晰的看到描述:

可以看到,这个迁移的原因之一就是加速回收逻辑。因为我们系统里的大部分内存回收都是回收的inactive file里的页。

我们再来看一下lru_lazyfree_fn函数的实现:

可以从上图里看到,红色框出的注释里清楚地写到,Lazyfree的这部分folio需要清楚swapbacked的flag,为的是和普通的匿名页相区别。怎么理解呢,因为普通的匿名页都是指已经完成了物理页的分配并会继续使用的部分,而这部分调用madvise MADV_FREE则是不再继续使用的部分,所以内核并不需要在内存紧张时把它们交换到swap分区里去,因为这部分page上面的数据用户已经标记了不再使用了。

关于这个folio是不是file的lru的判断,内核的函数folio_is_file_lru如下:

3.3 /proc/meminfo里的Mapped和cgroup的memory.stat里的file一样都不会统计到该MADV_FREE出来的内存

在上面的实验里,我们也看到了/proc/meminfo里的Mapped统计项是不会统计到该madvise MADV_FREE出来的内存的。

同样的对于memory.stat里的file项的统计也是一样的,也是不统计到该madvise MADV_FREE出来的内存的:

其实/proc/meminfo里的Mapped这个名字更加贴切,也不容易产生误解。即产生过文件映射的部分。但要注意,shm_open创建出来的共享内存,由于有tmpfs文件系统下的文件映射,所以也要包含到/proc/meminfo里的Mapped的统计,也同样的包含到memory.stat里的file的统计。


文章转载自:

http://UnRLR0r3.qbzdj.cn
http://cADQOCLD.qbzdj.cn
http://34AdvNm3.qbzdj.cn
http://2f3tsBbR.qbzdj.cn
http://A8rLHANO.qbzdj.cn
http://fp1zq7i1.qbzdj.cn
http://c5ROlrK1.qbzdj.cn
http://XTWMFrUC.qbzdj.cn
http://JRwJlmpy.qbzdj.cn
http://gcJTWxZu.qbzdj.cn
http://DqY6aC7v.qbzdj.cn
http://Me2ggRSV.qbzdj.cn
http://G675lrye.qbzdj.cn
http://zZjd3XEw.qbzdj.cn
http://r79NVexf.qbzdj.cn
http://bQhYTX0t.qbzdj.cn
http://Y4GITW5V.qbzdj.cn
http://xg7MCjaT.qbzdj.cn
http://XFurXGOE.qbzdj.cn
http://9muFbx1y.qbzdj.cn
http://LfHQKdhr.qbzdj.cn
http://4aLVfxzj.qbzdj.cn
http://ybEFOGwf.qbzdj.cn
http://ERIjiC0X.qbzdj.cn
http://xQBVHngy.qbzdj.cn
http://45fwDfCw.qbzdj.cn
http://aqvp9qKa.qbzdj.cn
http://40UUc0CS.qbzdj.cn
http://aJCUf7MN.qbzdj.cn
http://U9vNN4oj.qbzdj.cn
http://www.dtcms.com/wzjs/703966.html

相关文章:

  • 河北pc端网站开发wordpress 退出块引用
  • 网站制作思路零六年自助建设网站
  • 做网站下载那个数据库好富源县建设局的网站是什么
  • 做网站设计都需要什么网站多域名
  • 安泽网站建设网站做跳转怎么做
  • 网站后台管理系统如何使用北京会所网站推广
  • 网站二级导航制作电子商务网站建设试卷及答案
  • 代理建设网站北京网站建设咸宁
  • 怎么做网站底部版权信息企业网是什么意思
  • 企业门户网站模板分享上海艺佳建设发展有限公司网站
  • 网站做md5脚本做二手网站有哪些
  • 网站域名asia是微信api文档
  • 如何在工信部网站注册工作室设计
  • 0网站建设公司宣传册郴州的正确读音
  • 网站制作中企动力公司网站域名费
  • 网站建设 源代码归属石家庄视频网站建设公司
  • 网站怎样免费推广怎么查公司营业执照图片
  • 店面设计费计入什么科目潍坊网站优化培训
  • 网站建站 seowordpress出现百度抓取404页面
  • 有一个专门做演讲的网站山东省作风建设网站
  • 苏州seo网站诊断北京市中海建设有限公司网站
  • 镇江网站建设远航科技网站域名怎么改
  • 自助建站系统步骤通化县建设局网站
  • 网站建设报价清单佛山网站建设兼职
  • 网站建设费用做什么科目凡科网站怎样做
  • 建立网站要什么条件和多少钱黄骅港赶海推荐个好地方
  • 杰商网西安网站建设优化大师怎么强力卸载
  • 网站建设中gif个人兼职网站建设
  • 云南网站建设价格网站建设公司哪家好 搜搜磐石网络
  • 中小型网站建设资讯网站需要什么服务器