Сравнение скорости канала STDI и Memcpy - PullRequest
0 голосов
/ 25 июня 2019

У меня есть проблема, когда я генерирую большие объемы данных, а затем обрабатываю эти данные.

Концептуально, я думал, что создам одну программу для генерации данных, а затем другую для ее обработки, но я беспокоился о времени передачи данных из одной программы в другую.

Таким образом, я решил оценить, какие издержки у меня были бы, если бы я разделил эти два процесса по сравнению с включением генерации и обработки данных в одной программе.

Код ниже довольно длинный, все, что он делает, это генерирует случайные данные, затем сравнивает stdio::pipe с std::memcpy с точки зрения копирования случайных данных в другой вектор.

Однако я получаю результаты, которые не имеют смысла, когда конвейер + генерация данных не только быстрее, чем memcpy, но и быстрее, чем генерация данных в одиночку.

Что я неправильно понимаю?

Генерация данных:

#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <array>
#include <vector>
#include <cstring>
#include <ctime>

#define BUFFER_SIZE 1000
#define MYDATA_SIZE 100000000 // ~400 MB

std::vector<int> makeData() {
  std::srand(std::time(nullptr));
  std::vector<int> data(MYDATA_SIZE);
  std::generate(data.begin(), data.end(), std::rand);
  return data;
}

int main() {
  auto data = makeData();
  fwrite(data.data(), 4, data.size(), stdout);
  return 0;
}
// g++ -std=c++11 -O3 test2.cpp -o test2

Обработка данных:

#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <array>
#include <vector>
#include <cstring>
#include <ctime>
#include <numeric>
#include <random>

#define BUFFER_SIZE 1000
#define MYDATA_SIZE 100000000 // ~400 MB

std::vector<int> makeData() {
  std::srand(std::time(nullptr));
  std::vector<int> data(MYDATA_SIZE);
  std::generate(data.begin(), data.end(), std::rand);
  return data;
}

std::vector<int> copyDataFromProcess(std::string cmd) {
  std::vector<int> buffer(BUFFER_SIZE);
  std::vector<int> result;
  std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
  if (!pipe) {
    throw std::runtime_error("popen() failed!");
  }
  size_t bytes_read;
  while ( (bytes_read = fread(buffer.data(), 4, buffer.size(), pipe.get())) ) {
    result.insert(result.end(), buffer.begin(), buffer.begin() + bytes_read);
  }
  return result;
}

std::vector<int> copyDataFromInternal() {
  std::vector<int> mydata = makeData();
  std::vector<int> result(MYDATA_SIZE);
  std::memcpy(result.data(), mydata.data(), MYDATA_SIZE);
  return result;
}

int main() {
  std::clock_t start;

  start = std::clock();
  auto ret1 = copyDataFromProcess("./test2");
  std::cout << "Copy From Process: " << (std::clock() - start) / (double)(CLOCKS_PER_SEC / 1000) << " ms" << std::endl;

  start = std::clock();
  auto ret2 = copyDataFromInternal();
  std::cout << "Copy From Internal: " << (std::clock() - start) / (double)(CLOCKS_PER_SEC / 1000) << " ms" << std::endl;

  start = std::clock();
  auto ret3 = makeData();
  std::cout << "Make Data Time: " << (std::clock() - start) / (double)(CLOCKS_PER_SEC / 1000) << " ms" << std::endl;


  std::cout << std::accumulate(ret1.begin(), ret1.end(), 0) << " " << ret1.size() << std::endl;
  std::cout << std::accumulate(ret2.begin(), ret2.end(), 0) << " " << ret2.size() << std::endl;
  std::cout << std::accumulate(ret3.begin(), ret3.end(), 0) << " " << ret3.size() << std::endl;

  return 0;
}

// g++ -std=c++11 -O3 test.cpp -o test

Результаты:

Copy From Process: 718.696 ms
Copy From Internal: 1104.66 ms
Make Data Time: 868.188 ms
2092103051 100000000
-638719098 100000000
-1973221745 100000000
...