linux - 在 linux 中计算页面错误的结果令人困惑

标签 linux kernel virtual-memory

我正在编写程序来计算 linux 系统中页面错误的时间。更准确地说,时间内核执行函数__do_page_fault
不知何故,我写了两个全局变量,分别命名为pfcount_at_begpfcount_at_end,当函数__do_page_fault 在函数的不同位置执行时,它们会增加一次。

为了说明,修改后的函数如下:

unsigned long pfcount_at_beg = 0;
unsigned long pfcount_at_end = 0;
static void __kprobes
__do_page_fault(...)
{
    struct vm_area_sruct *vma;
    ...    // VARIABLES DEFINITION 
    unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;   
    pfcount_at_beg++;        // I add THIS
    ...
    ... 
    // ORIGINAL CODE OF THE FUNCTION
    ...
    pfcount_at_end++;        // I add THIS
}

我预计 pfcount_at_end 的值小于 pfcount_at_beg 的值。

因为,我认为,每次内核执行代码pfcount_at_end++的指令时,它必须执行pfcount_at_beg++(每个函数都从代码的最开头开始)。
另一方面,由于这两行代码之间有很多条件return

然而,结果恰恰相反。 pfcount_at_end的值大于pfcount_at_beg的值。
我使用 printk 通过自定义的 syscall 打印这些内核变量。我编写了用户级程序来调用系统调用

这是我的简单系统调用和用户级程序:

// syscall
asmlinkage int sys_mysyscall(void)
{
    printk( KERN_INFO "total pf_at_beg%lu\ntotal pf_at_end%lu\n", pfcount_at_beg, pfcount_at_end)
    return 0;
}

// user-level program
#include<linux/unistd.h>
#include<sys/syscall.h>
#define __NR_mysyscall 223
int main()
{
    syscall(__NR_mysyscall);
    return 0;
}

有没有人知道这期间到底发生了什么?

刚才我修改了代码,使pfcount_at_begpfcount_at_end static。然而结果并没有改变,即pfcount_at_end的值大于pfcount_at_beg的值。 所以可能它可能是由增量的原子操作引起的。如果我使用读写锁会更好吗?

最佳答案

++运算符不保证是原子的,因此您的计数器可能会受到并发访问并具有不正确的值。你应该保护你的增量作为关键部分,或者使用 atomic_t <asm/atomic.h> 中定义的类型, 及其相关 atomic_set()atomic_add()功能(以及更多)。

与您的问题没有直接关系,但使用特定的系统调用有点矫枉过正(但这也许是一种练习)。一个较轻的解决方案可能是使用 /proc输入(也是一个有趣的练习)。

关于linux - 在 linux 中计算页面错误的结果令人困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27642340/

相关文章:

Android 清理虚拟内存

assembly - 在 x86 32 位中禁用分页

linux - Linux 中 CPU 使用率最高的进程

c++ - 与 Thrift Hook

linux - linux 上的 qt openGL 支持

macos - Darwin 内核架构和 OS X,32 位内核上的 64 位,这是如何工作的?

c - 预处理Linux源代码并保存到另一个目录

c++ - "virtual memory exhausted"构建 Docker 镜像时

linux - Lisp 工具包 (ltk) : Cannot get SCALE :variable value

c - 运行时可加载内核模块如何知道核心内核函数的地址?