2

我正在研究一些将用于测试其他可执行文件的代码。为方便起见,我将我的代码称为测试器,将被测试的代码称为客户端。测试器将生成客户端并向客户端的标准输入发送命令,并从客户端的标准输出接收结果。

我想先做一些性能测试,所以我写了一个非常简单的示例测试器和客户端。测试仪等待客户端将“READY”写入其标准输出,并作为响应将“GO”发送到客户端的标准输入。然后客户端将一些字节数写入标准输出,通过命令行标志配置,然后写入“\nREADY\n”,此时测试仪将再次写入“GO”。这会重复 10,000 次,然后我计算完成测试所需的时间和“吞吐量”,即 10,000 除以完成时间。

我运行了上述测试,让客户端在发送“READY”之前发送 0、10、100、1000、10000 和 100000 字节的数据。对于每个字节大小,我重复测试 10 次并取平均值。在我的笔记本电脑上运行 Ubuntu VMWare 实例时,我获得了每秒大约 100k GO/READY 对的吞吐量。性能相当稳定,几乎不依赖于客户端发送给测试仪的二进制字节数。然后我在运行 CentOS 的速度非常快的 24 核服务器上重复了测试。对于 0 字节有效负载,我观察到每秒只有大约 55k GO/READY 对,并且随着客户端发送的字节数增加,性能明显下降。当客户端在“GO”和“READY”之间发送 100k 字节时,吞吐量仅为每秒大约 6k 次操作。

所以我有三个问题

  1. 为什么相同的代码在更快的机器上运行得更慢
  2. 为什么虚拟机的性能与负载大小无关,而快速服务器上的性能却严重依赖负载大小?
  3. 我能做些什么来让服务器上的事情变得更快吗

一种可能的解释是我在快速服务器上重新编译了代码,并且它使用了不同版本的 C++ 库。VMWare 机器运行 Ubuntu 11.10,快速服务器运行 CentOS 6。两者都是 64 位机器。

相关测试器代码如下:

ios_base::sync_with_stdio(false);
const int BUFFER_SIZE = 2 << 20;
char buffer[BUFFER_SIZE];
process_stdout->rdbuf()->pubsetbuf(buffer, BUFFER_SIZE);
Timer timer;
// Wait until the process is ready
string line;
line.reserve(2 << 20);
getline(*process_stdout, line);
CHECK(line == "READY");
timer.Start();
for (int i = 0; i < num_trials; ++i) {
  *process_stdin << "GO\n";
  process_stdin->flush();
  line = "";
  while (line != "READY") {
    getline(*process_stdout, line);
  }
}
double elapsed = timer.Elapsed();
cout << "Done. Did " << num_trials << " iterations in "
     << elapsed << " seconds. Throughput: "
     << double(num_trials) / elapsed << " per second." << endl;

我还尝试了使用 read() 调用(来自 unistd.h)到 1MB 缓冲区并调用 memchr 以查找“\n”字符并查找 READY 的版本,但得到了相同的性能结果。

相关客户端代码如下:

// Create a vector of binary data. Some portion of the data will be sent 
// to stdout each time a "GO" is received before sending "READY"
vector<char> byte_source;
const int MAX_BYTES = 1 << 20;
for (int i = 0; i < MAX_BYTES; ++i) {
 byte_source.push_back(i % 256);
}

cout << "READY" << endl;
while (cin.good()) {
  string line;
  getline(cin, line);
  if (line == "GO") {
    // The value of response_bytes comes from a command line flag
    OutputData(response_bytes, byte_source);
    cout << "READY" << endl;
  }
}

// write bytes worth of data from byte_source to stdout
void OutputData(unsigned int bytes,
                const vector<char>& byte_source) {
  if (bytes == 0) {
    return;
  }
  cout.write(&byte_source[0], bytes);
  cout << "\n";
}

任何帮助将不胜感激!

4

1 回答 1

0

VM 中的速度与有效负载大小无关这一事实表明您做错了什么。这些不是完整的程序,因此很难确定是什么。使用 strace 查看发生了什么,即客户端是否确实发送了您认为的所有数据(并检查测试人员是否正在接收应有的所有数据)。

100k READY/GO 对太多了;它基本上接近每秒上下文切换次数的上限,没有做任何其他事情。

于 2012-06-01T18:39:46.227 回答