如何实现从一个进程到另一个进程的快速上下文切换?

2024-03-26

我需要在沙箱进程上运行不安全的本机代码,并且需要减少进程切换的瓶颈。两个进程(控制器和沙箱)共享两个自动重置events http://msdn.microsoft.com/en-us/library/windows/desktop/aa964766(v=vs.85).aspx以及用于通信的映射文件(共享内存)的连贯视图。

为了使本文更精简,我从示例代码中删除了初始化,但事件由控制器创建,使用 DuplicateHandle 进行复制,然后在工作之前发送到沙箱进程。

控制器来源:

void inSandbox(HANDLE hNewRequest, HANDLE hAnswer, volatile int *shared) {
  int before = *shared;
  for (int i = 0; i < 100000; ++i) {
    // Notify sandbox of a new request and wait for answer.
    SignalObjectAndWait(hNewRequest, hAnswer, INFINITE, FALSE);
  }
  assert(*shared == before + 100000);
}

void inProcess(volatile int *shared) {
  int before = *shared;
  for (int i = 0; i < 100000; ++i) {
    newRequest(shared);
  }
  assert(*shared == before + 100000);
}

void newRequest(volatile int *shared) {
  // In this test, the request only increments an int.
  (*shared)++;
}

沙箱来源:

void sandboxLoop(HANDLE hNewRequest, HANDLE hAnswer, volatile int *shared) {
  // Wait for the first request from controller.
  assert(WaitForSingleObject(hNewRequest, INFINITE) == WAIT_OBJECT_0);
  for(;;) {
    // Perform request.
    newRequest(shared);
    // Notify controller and wait for next request.
    SignalObjectAndWait(hAnswer, hNewRequest, INFINITE, FALSE);
  }
}

void newRequest(volatile int *shared) {
  // In this test, the request only increments an int.
  (*shared)++;
}

测量:

  • inSandbox()- 550ms,~350k 上下文切换,42% CPU(25% 内核,17% 用户)。
  • inProcess()- 20ms,~2k 上下文切换,55% CPU(2% 内核,53% 用户)。

该机器是Windows 7 Pro、Core 2 Duo P9700、8GB内存。

一个有趣的事实是,沙箱解决方案使用了 42% 的 CPU,而进程内解决方案则使用了 55%。另一个值得注意的事实是,沙箱解决方案包含 350k 上下文切换,这比我们从源代码推断的 200k 上下文切换要多得多。

我需要知道是否有办法减少将控制权转移到另一个进程的开销。我已经尝试过使用管道而不是事件,结果更糟糕。我还尝试通过进行沙箱调用来根本不使用任何事件SuspendThread(GetCurrentThread())并使控制器调用ResumeThread(hSandboxThread)对每个请求,但性能与使用事件类似。

如果您有使用程序集(例如执行手动上下文切换)或 Windows 驱动程序工具包的解决方案,也请告诉我。我不介意必须安装驱动程序才能加快速度。

我听说Google Native Client做了类似的事情,但我只发现本文档 https://sites.google.com/a/chromium.org/dev/nativeclient/reference/anatomy-of-a-sys。如果您有更多信息,请告诉我。


首先要尝试的是提高等待线程的优先级。这应该减少无关上下文切换的数量。

或者,由于您使用的是 2 核系统,因此使用自旋锁 http://en.wikipedia.org/wiki/Spinlock而不是事件会让你的代码更快,但代价是系统性能和功耗:

void inSandbox(volatile int *lock, volatile int *shared) 
{
  int i, before = *shared;
  for (i = 0; i < 100000; ++i) {
    *lock = 1;
    while (*lock != 0) { }
  }
  assert(*shared == before + 100000);
}

void newRequest(volatile int *shared) {
  // In this test, the request only increments an int.
  (*shared)++;
}

void sandboxLoop(volatile int *lock, volatile int * shared)
{
  for(;;) {
    while (*lock != 1) { }
    newRequest(shared);
    *lock = 0;
  }
}

在这种情况下,您可能应该设置线程关联掩码和/或降低旋转线程的优先级,以便它不会与繁忙的线程竞争 CPU 时间。

理想情况下,您应该使用混合方法。当一侧要忙一段时间时,让另一侧等待某个事件,以便其他进程可以获得一些 CPU 时间。您可以提前一点触发该事件(使用自旋锁来保持同步),以便其他线程在您准备好时准备好。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何实现从一个进程到另一个进程的快速上下文切换? 的相关文章

随机推荐