Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 叉子漏水?花越来越长的时间来完成一个简单的过程_C_Linux_Linux Kernel_Fork - Fatal编程技术网

C 叉子漏水?花越来越长的时间来完成一个简单的过程

C 叉子漏水?花越来越长的时间来完成一个简单的过程,c,linux,linux-kernel,fork,C,Linux,Linux Kernel,Fork,我有一个系统,其中运行两个相同的进程(让我们称它们为副本)。当发出信号时,副本将使用fork()调用复制自身。第三个进程选择其中一个进程随机终止,然后向另一个进程发出信号以创建替换进程。在功能上,系统运行良好;它可以全天杀死/恢复副本,但性能问题除外 fork()调用花费的时间越来越长。以下是仍然显示问题的最简单设置。正时将显示在下图中: 复制副本的代码如下所示: void restartHandler(int signo) { // fork timestamp_t last = gene

我有一个系统,其中运行两个相同的进程(让我们称它们为副本)。当发出信号时,副本将使用
fork()
调用复制自身。第三个进程选择其中一个进程随机终止,然后向另一个进程发出信号以创建替换进程。在功能上,系统运行良好;它可以全天杀死/恢复副本,但性能问题除外

fork()
调用花费的时间越来越长。以下是仍然显示问题的最简单设置。正时将显示在下图中:

复制副本的代码如下所示:

void restartHandler(int signo) {
// fork
  timestamp_t last = generate_timestamp();
  pid_t currentPID = fork();


  if (currentPID >= 0) { // Successful fork
    if (currentPID == 0) { // Child process
      timestamp_t current = generate_timestamp();
      printf("%lld\n", current - last);

      // unblock the signal
      sigset_t signal_set;
      sigemptyset(&signal_set);
      sigaddset(&signal_set, SIGUSR1);
      sigprocmask(SIG_UNBLOCK, &signal_set, NULL);

      return;
    } else {   // Parent just returns
      waitpid(-1, NULL, WNOHANG);
      return;
    }
  } else {
    printf("Fork error!\n");
    return;
  }
}

int main(int argc, const char **argv) {
  if (signal(SIGUSR1, restartHandler) == SIG_ERR) {
    perror("Failed to register the restart handler");
    return -1;
  }

  while(1) {
    sleep(1);
  }

  return 0;
}
系统运行的时间越长,情况就越糟

很抱歉,缺少一个具体的问题,但是有人对正在发生的事情有任何想法/线索吗?在我看来,内核中似乎存在资源泄漏(因此linux内核标签),但我不知道从哪里开始查找

我所尝试的:

  • 试过了,什么也没钓到。这意味着,如果存在一些内存“泄漏”,那么它仍然是可访问的
  • /proc//maps
    没有增长
  • 目前正在运行带有RT补丁的3.14内核(注意,这种情况发生在非RT和RT进程上),并且已经在3.2上进行了尝试
  • 僵尸进程不是问题。我试过一个版本,在这个版本中,我使用
  • 我首先在一个系统中注意到这种减速,在这个系统中,定时测量值在重新启动的进程之外下降;同样的行为

有什么提示吗?有什么我能帮忙的吗?谢谢

只是一个想法:可能与MMU或缓存有关?据我所知,在fork()上,内核用对相同物理RAM页面的引用填充适当的表条目。您编写了,您正在进行虚拟写入,但您是否正在对可执行segmen执行这些操作(如果是,如何执行,因为这些应该是写保护的)?从图中可以看出,性能在某些点上有所提高(512?512*3?512*4?)。这让我怀疑系统(内核?、硬件?)意识到了这个问题,并使用了一些解决方法(在MMU上为同一物理页复制antries?一些数据结构被拆分?。

也许您可以尝试使用通用的wait()调用,而不是waitpid()?这只是一个猜测,但我从一个大学教授那里听说更好。还有,你试过使用吗

此外,您还可以使用GDB调试子进程(如果您还没有尝试过的话)。您可以使用follow fork模式:

set follow-fork-mode child
但这只能调试父级。通过获取子进程的pid,在分叉后调用sleep(),可以调试这两个进程:

attach <child process pid>
这很有用,因为您可以将内存泄漏转储到valgrind中。打电话给valgrind

valgrind --vgdb-error=0...<executable>
然后:

监视器块列表

减速是由匿名VMA的累积造成的,这是一个已知的问题。当有大量的
fork()
调用并且父类在子类之前退出时,问题就很明显了。以下代码重新创建了问题():

#包括
int main(int argc,char*argv[])
{
pid_t pid;
而(1){
pid=fork();
如果(pid==-1){
/*错误*/
返回1;
}
如果(pid){
/*母公司*/
睡眠(2);
打破
}
否则{
/*孩子*/
睡眠(1);
}
}
返回0;
}
可以通过在
/proc/slabinfo
中检查
anon_vma
来确认该行为

有一个补丁()将复制的
anon_vma_链的长度限制为5。我可以确认修补程序修复了问题

至于我最终是如何发现问题的,我最终开始在
fork
代码中放置
printk
调用,检查
dmesg
中显示的时间。最后,我发现调用anon_vma_fork花费的时间越来越长。然后是谷歌搜索的快速问题


这花了相当长的时间,所以我仍然希望有人能提出更好的方法来追踪这个问题。对于所有已经花时间试图帮助我的人,谢谢。

在新进程开始执行之前,或者更确切地说,在第一条存储指令之前,子进程只是一个精确的副本。在整个系统中,我通过使用mlockall,然后遍历/proc/pid/maps进行虚拟写入来解决这个问题。在完整的系统和我在这里提供的代码中,fork的性能问题仍然存在。您是否使用ps命令查看正在运行的内容(通常“top”实用程序会重复执行此操作)以及在每个运行过程中花费了多少时间?在您的代码中,我看不到任何user1信号的传递,因此怀疑是否有任何子进程被终止。您是否可以尝试使用vWork或clone而不是Fork?您发布的图是众所周知的posix Fork行为(即,Fork计数越大,性能越慢)这是因为每次分叉时,它都会复制页表。请参阅优秀书籍《Linux编程接口》@user3629249中的此表。有一个单独的进程将
kill-9
发送到其中一个副本,并将
kill-s USR1
发送到另一个副本。
valgrind --vgdb-error=0...<executable>
monitor leak_check full reachable any
monitor block_list <loss_record_nr>
#include <unistd.h>

int main(int argc, char *argv[])
{
  pid_t pid;
  while (1) {
    pid = fork();
    if (pid == -1) {
      /* error */
      return 1;
    }
    if (pid) {
      /* parent */
      sleep(2);
      break;
    }
    else {
      /* child */
      sleep(1);
    }
  }
  return 0;
}