为什么我的过程需要很长时间才能死?

时间:2015-06-30 11:48:28

标签: linux memory-management process linux-kernel operating-system

基本上我在PowerPC上使用Linux 2.6.34(飞思卡尔e500mc)。我有一个进程(一种内部开发的VM),使用大约2.25 G的mlocked VM。当我杀了它时,我注意到终止需要2分钟。

我调查了一下。首先,我关闭了所有打开的文件描述符,但这似乎没有什么区别。然后我在内核中添加了一些printk,通过它我发现所有延迟都来自内核解锁我的VMA。页面的延迟是统一的,我通过反复检查/ proc / meminfo中的锁定页面计数来验证。我已经检查过那些分配了大量内存的程序,一旦我发出信号,它们就会全部死掉。

您认为我现在应该检查什么?谢谢你的回复。

编辑:我必须找到一种方法来分享有关该问题的更多信息,所以我在下面的程序中写了这个:

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/time.h>

#define MAP_PERM_1              (PROT_WRITE | PROT_READ | PROT_EXEC)
#define MAP_PERM_2              (PROT_WRITE | PROT_READ)

#define MAP_FLAGS               (MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE)

#define PG_LEN                  4096
#define align_pg_32(addr)       (addr & 0xFFFFF000)
#define num_pg_in_range(start, end)     ((end - start + 1) >> 12)

inline void __force_pgtbl_alloc(unsigned int start)
{
        volatile int *s = (int *) start;
        *s = *s;
}

int __map_a_page_at(unsigned int start, int whichperm)
{
        int perm = whichperm ? MAP_PERM_1 : MAP_PERM_2;

        if(MAP_FAILED == mmap((void *)start, PG_LEN, perm, MAP_FLAGS, 0, 0)){
                fprintf(stderr,
                        "mmap failed at 0x%x: %s.\n",
                        start, strerror(errno));
                return 0;
        }

        return 1;
}

int __mlock_page(unsigned int addr)
{
        if (mlock((void *)addr, (size_t)PG_LEN) < 0){
                fprintf(stderr,
                        "mlock failed on page: 0x%x: %s.\n",
                        addr, strerror(errno));
                return 0;
        }

        return 1;
}

void sigint_handler(int p)
{
        struct timeval start = {0 ,0}, end = {0, 0}, diff = {0, 0};
        gettimeofday(&start, NULL);
        munlockall();
        gettimeofday(&end, NULL);
        timersub(&end, &start, &diff);

        printf("Munlock'd entire VM in %u secs %u usecs.\n",
                diff.tv_sec, diff.tv_usec);

        exit(0);
}

int make_vma_map(unsigned int start, unsigned int end)
{
        int num_pg = num_pg_in_range(start, end);

        if (end < start){
                fprintf(stderr,
                        "Bad range: start: 0x%x end: 0x%x.\n",
                        start, end);
                return 0;
        }

        for (; num_pg; num_pg --, start += PG_LEN){
                if (__map_a_page_at(start, num_pg % 2) && __mlock_page(start))
                        __force_pgtbl_alloc(start);
                else
                        return 0;
        }

        return 1;
}

void display_banner()
{
        printf("-----------------------------------------\n");
        printf("Virtual memory allocator. Ctrl+C to exit.\n");
        printf("-----------------------------------------\n");
}

int main()
{
        unsigned int vma_start, vma_end, input = 0;
        int start_end = 0; // 0: start; 1: end;

        display_banner();

        // Bind SIGINT handler.
        signal(SIGINT, sigint_handler);

        while (1){
                if (!start_end)
                        printf("start:\t");
                else
                        printf("end:\t");

                scanf("%i", &input);

                if (start_end){
                        vma_end   = align_pg_32(input);
                        make_vma_map(vma_start, vma_end);
                }
                else{
                        vma_start = align_pg_32(input);
                }
                start_end = !start_end;
        }

        return 0;
}

如您所见,程序接受虚拟地址范围,每个范围由开始和结束定义。然后通过为相邻页面提供不同的权限,将每个范围进一步细分为页面大小的VMA。中断(使用SIGINT)程序触发对munlockall()的调用,并且适当地注意到所述过程完成的时间。

现在,当我在版本为0x30000000-0x35000000的Linux版本2.6.34的freescale e500mc上运行时,我得到的总munlockall()时间差不多是45秒。但是,如果我在随机顺序中使用较小的起始端范围(即,不一定增加地址)执行相同的操作,使得总页数(和锁定的VMA)大致相同,请观察总munlockall()时间到不超过4秒。

我在x86_64上使用Linux 2.6.34尝试了同样的事情,并且我的程序针对-m32参数进行了编译,看起来变化虽然不像ppc那样明显,但对于第一种情况仍然是8秒,并且在第二种情况下对于第二种情况。

我在Linux 2.6.10的一端和3.19上试过这个程序,另一方面看起来这些巨大的差异并不存在。而且,munlockall()总是在不到一秒钟内完成。

所以,似乎问题无论是什么,都只存在于2.6.34版本的Linux内核中。

1 个答案:

答案 0 :(得分:0)

你说VM是内部开发的。这是否意味着您可以访问来源?我首先检查它是否有什么可以阻止它立即终止以避免数据丢失。

否则,您是否可能尝试提供更多信息?您可能还想查看:https://unix.stackexchange.com/因为它们更适合帮助解决Linux内核可能遇到的任何问题。