LINUX.ORG.RU

История изменений

Исправление kilokolyan, (текущая версия) :

Про стек - да. Во многих случаях так.

Про копирование. Замерял тут время работы ::read() внезапно.

Код получения текущего времени:

uint64_t curr_nano_mono() {
  timespec ts;
  if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
    return ts.tv_sec * 1000000000L + ts.tv_nsec;
  }
  return 0;
}

Мерял так:

  auto t1 = curr_nano_mono();
  int rd = ::read(socket, ptr, size);
  auto t2 = curr_nano_mono();
  printf("read time %lu ns\n", t2 - t1);

И получилось такое:

// браузер присылает нам по websocket короткие посылки с интервалом в секунду примерно
    1 read time 26576 ns
    2 read time 23573 ns
    3 read time 23166 ns
    4 read time 19196 ns
    5 read time 16056 ns
    6 read time 22784 ns
    7 read time 18044 ns
    8 read time 23853 ns
    9 read time 24285 ns
   10 read time 18270 ns
   11 // брайзер начал посылать посылки чуть длиннее и сильно часто: read стал возвращаться быстрее (видимо что-то прогрето)
   12 read time 7085 ns
   13 read time 3573 ns
   14 read time 3815 ns
   15 read time 4042 ns
   16 read time 3456 ns
   17 read time 3815 ns
   18 read time 6751 ns
   19 read time 12444 ns
   20 read time 9010 ns
   21 read time 23797 ns
   22 // браузер снова начал слать что-то мелкое раз в секунду (байт 16 payload) как в начале
   23 read time 18039 ns 
   24 read time 15884 ns
   25 read time 19076 ns
   26 read time 18059 ns
   27 read time 22291 ns
   28 read time 18965 ns
   29 read time 17606 ns
   30 read time 17034 ns
   31 read time 16870 ns
   32 read time 12785 ns
   33 read time 23127 ns
   34 read time 17811 ns
   35 read time 18065 ns
   36 read time 17959 ns

Потом померял сколько у меня выжимает memcpy() вот таким методом. Возможно метод дебилен:


#include <iostream>
#include <vector>
#include <string.h>

uint64_t curr_nano_mono() {
  timespec ts;
  if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
    return ts.tv_sec * 1000000000L + ts.tv_nsec;
  }
  return 0;
}

struct Measure {
  uint64_t start_{};
  const char *name_{};

  explicit Measure(const char *_name)
  : start_(curr_nano_mono())
  , name_(_name)
  {
  }

  uint64_t elapsed() {
    return curr_nano_mono() - start_;
  }
  ~Measure() {
    printf("%s: %lu ns\n", name_, elapsed());
  }
};


int main() {

  const auto BUFFS = 32;
  const auto BS = 1024 * 1024 * 8;
  std::vector<char*> vect(BUFFS, nullptr);

  srand(time(nullptr));

  {
    Measure me("alloc");
    for (auto &p : vect) {
      p = new char[BS];
    }
  }

  {
    Measure me("fill");
    for (auto &buff : vect) {
      for (char *p = buff, *end = buff + BS; p < end; ++p) {
        *p = reinterpret_cast<size_t>(p) % 256;
      }
    }
  }

  {
    Measure me("copy");
    const auto ITERS = 1024;
    size_t bytes = 0;
    // Copy some bytes from random "from" to random "to" with random offset in "from".
    for (auto iter = ITERS; iter >= 0; --iter) {
      auto from = 0;
      auto to = 0;
      // this loop makes sure we use different buffers
      while (from == to) {
        from = rand() % BUFFS;
        to = rand() % BUFFS;
      }

      // small random offset
      auto offset = rand() % (1024*16);
      bytes += (BS - offset);

      ::memcpy(vect[to], vect[from] + offset, BS - offset);
    }

    auto elapsed = me.elapsed();
    double seconds = static_cast<double>(elapsed) / 1000000000.0;
    double cost = ((1024.0 * 1024.0) / (double)bytes);

    printf("Memcpy %.2lf byte/sec, took %.2lf sec, %lu ns\n", bytes / seconds, seconds, elapsed);
    printf("1MB copy time cost: %.2lf ns\n", elapsed * cost);
  }

  return 0;
}

Собрать и запустить так: rm a.out; g++ -std=c++11 -O3 memcpy-measure.cpp; ./a.out

И на моём lenovo carbon X1 gen 7 получил такое:

alloc: 53937 ns
fill: 769249218 ns
Memcpy 10147233381.31 byte/sec, took 0.85 sec, 846528728 ns
1MB copy time cost: 103336.15 ns
copy: 846548979 ns

Железо ноута:

i7-8565U
Type: LPDDR3
Type Detail: Synchronous
Speed: 2133 MT/s

Отсюда 1MB copy time cost: 103336.15 ns и из времени syscall ::read() в районе 5-25 ns можно сказать, что syscall мне сильно дешевле, чем мегабайт памяти копировать. Т.е. если у меня в сокет не влез мегабайт, то мне проще подарить указатель на буфер сетевой подсистеме и забыть, чем копировать.

Исправление kilokolyan, :

Про стек - да. Во многих случаях так.

Про копирование. Замерял тут время работы ::read() внезапно.

Код получения текущего времени:

uint64_t curr_nano_mono() {
  timespec ts;
  if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
    return ts.tv_sec * 1000000000L + ts.tv_nsec;
  }
  return 0;
}

Мерял так:

  auto t1 = curr_nano_mono();
  int rd = ::read(socket, ptr, size);
  auto t2 = curr_nano_mono();
  printf("read time %lu ns\n", t2 - t1);

И получилось такое:

// браузер присылает нам по websocket короткие посылки с интервалом в секунду примерно
    1 read time 26576 ns
    2 read time 23573 ns
    3 read time 23166 ns
    4 read time 19196 ns
    5 read time 16056 ns
    6 read time 22784 ns
    7 read time 18044 ns
    8 read time 23853 ns
    9 read time 24285 ns
   10 read time 18270 ns
   11 // брайзер начал посылать посылки чуть длиннее и сильно часто: read стал возвращаться быстрее (видимо что-то прогрето)
   12 read time 7085 ns
   13 read time 3573 ns
   14 read time 3815 ns
   15 read time 4042 ns
   16 read time 3456 ns
   17 read time 3815 ns
   18 read time 6751 ns
   19 read time 12444 ns
   20 read time 9010 ns
   21 read time 23797 ns
   22 // браузер снова начал слать что-то мелкое раз в секунду (байт 16 payload) как в начале
   23 read time 18039 ns 
   24 read time 15884 ns
   25 read time 19076 ns
   26 read time 18059 ns
   27 read time 22291 ns
   28 read time 18965 ns
   29 read time 17606 ns
   30 read time 17034 ns
   31 read time 16870 ns
   32 read time 12785 ns
   33 read time 23127 ns
   34 read time 17811 ns
   35 read time 18065 ns
   36 read time 17959 ns

Потом померял сколько у меня выжимает memcpy() вот таким методом. Возможно метод дебилен:


#include <iostream>
#include <vector>
#include <string.h>

uint64_t curr_nano_mono() {
  timespec ts;
  if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
    return ts.tv_sec * 1000000000L + ts.tv_nsec;
  }
  return 0;
}

struct Measure {
  uint64_t start_{};
  const char *name_{};

  explicit Measure(const char *_name)
  : start_(curr_nano_mono())
  , name_(_name)
  {
  }

  uint64_t elapsed() {
    return curr_nano_mono() - start_;
  }
  ~Measure() {
    printf("%s: %lu ns\n", name_, elapsed());
  }
};


int main() {

  const auto BUFFS = 32;
  const auto BS = 1024 * 1024 * 8;
  std::vector<char*> vect(BUFFS, nullptr);

  srand(time(nullptr));

  {
    Measure me("alloc");
    for (auto &p : vect) {
      p = new char[BS];
    }
  }

  {
    Measure me("fill");
    for (auto &buff : vect) {
      for (char *p = buff, *end = buff + BS; p < end; ++p) {
        *p = reinterpret_cast<size_t>(p) % 256;
      }
    }
  }

  {
    Measure me("copy");
    const auto ITERS = 1024;
    size_t bytes = 0;
    // Copy some bytes from random "from" to random "to" with random offset in "from".
    for (auto iter = ITERS; iter >= 0; --iter) {
      auto from = 0;
      auto to = 0;
      // this loop makes sure we use different buffers
      while (from == to) {
        from = rand() % BUFFS;
        to = rand() % BUFFS;
      }

      // small random offset
      auto offset = rand() % (1024*16);
      bytes += (BS - offset);

      ::memcpy(vect[to], vect[from] + offset, BS - offset);
    }

    auto elapsed = me.elapsed();
    double seconds = static_cast<double>(elapsed) / 1000000000.0;
    double cost = ((1024.0 * 1024.0) / (double)bytes);

    printf("Memcpy %.2lf byte/sec, took %.2lf sec, %lu ns\n", bytes / seconds, seconds, elapsed);
    printf("1MB copy time cost: %.2lf ns\n", elapsed * cost);
  }

  return 0;
}

Собрать и запустить так: rm a.out; g++ -std=c++11 -O3 memcpy-measure.cpp; ./a.out

И на моём lenovo carbon X1 gen 7 получил такое:

alloc: 53937 ns
fill: 769249218 ns
Memcpy 10147233381.31 byte/sec, took 0.85 sec, 846528728 ns
1MB copy time cost: 103336.15 ns
copy: 846548979 ns

Железо ноута:

i7-8565U
Type: LPDDR3
Type Detail: Synchronous
Speed: 2133 MT/s

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

Исправление kilokolyan, :

Про стек - да. Во многих случаях так.

Про копирование. Замерял тут время работы ::read() внезапно.

Код получения текущего времени:

uint64_t curr_nano_mono() {
  timespec ts;
  if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
    return ts.tv_sec * 1000000000L + ts.tv_nsec;
  }
  return 0;
}

Мерял так:

  auto t1 = curr_nano_mono();
  int rd = ::read(socket, ptr, size);
  auto t2 = curr_nano_mono();
  printf("read time %lu ns\n", t2 - t1);

И получилось такое:

// браузер присылает нам по websocket короткие посылки с интервалом в секунду примерно
    1 read time 26576 ns
    2 read time 23573 ns
    3 read time 23166 ns
    4 read time 19196 ns
    5 read time 16056 ns
    6 read time 22784 ns
    7 read time 18044 ns
    8 read time 23853 ns
    9 read time 24285 ns
   10 read time 18270 ns
   11 // брайзер начал посылать посылки чуть длиннее и сильно часто: read стал возвращаться быстрее (видимо что-то прогрето)
   12 read time 7085 ns
   13 read time 3573 ns
   14 read time 3815 ns
   15 read time 4042 ns
   16 read time 3456 ns
   17 read time 3815 ns
   18 read time 6751 ns
   19 read time 12444 ns
   20 read time 9010 ns
   21 read time 23797 ns
   22 // браузер снова начал слать что-то мелкое раз в секунду (байт 16 payload) как в начале
   23 read time 18039 ns 
   24 read time 15884 ns
   25 read time 19076 ns
   26 read time 18059 ns
   27 read time 22291 ns
   28 read time 18965 ns
   29 read time 17606 ns
   30 read time 17034 ns
   31 read time 16870 ns
   32 read time 12785 ns
   33 read time 23127 ns
   34 read time 17811 ns
   35 read time 18065 ns
   36 read time 17959 ns

Потом померял сколько у меня выжимает memcpy() вот таким методом. Возможно метод дебилен:


#include <iostream>
#include <vector>
#include <string.h>

uint64_t curr_nano_mono() {
  timespec ts;
  if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
    return ts.tv_sec * 1000000000L + ts.tv_nsec;
  }
  return 0;
}

struct Measure {
  uint64_t start_{};
  const char *name_{};

  explicit Measure(const char *_name)
  : start_(curr_nano_mono())
  , name_(_name)
  {
  }

  uint64_t elapsed() {
    return curr_nano_mono() - start_;
  }
  ~Measure() {
    printf("%s: %lu ns\n", name_, elapsed());
  }
};


int main() {

  const auto BUFFS = 32;
  const auto BS = 1024 * 1024 * 8;
  std::vector<char*> vect(BUFFS, nullptr);

  srand(time(nullptr));

  {
    Measure me("alloc");
    for (auto &p : vect) {
      p = new char[BS];
    }
  }

  {
    Measure me("fill");
    for (auto &buff : vect) {
      for (char *p = buff, *end = buff + BS; p < end; ++p) {
        *p = reinterpret_cast<size_t>(p) % 256;
      }
    }
  }

  {
    Measure me("copy");
    const auto ITERS = 1024;
    size_t bytes = 0;
    // Copy some bytes from random "from" to random "to" with random offset in "from".
    for (auto iter = ITERS; iter >= 0; --iter) {
      auto from = 0;
      auto to = 0;
      // this loop makes sure we use different buffers
      while (from == to) {
        from = rand() % BUFFS;
        to = rand() % BUFFS;
      }

      // small random offset
      auto offset = rand() % (1024*16);
      bytes += (BS - offset);

      ::memcpy(vect[to], vect[from] + offset, BS - offset);
    }

    auto elapsed = me.elapsed();
    double seconds = static_cast<double>(elapsed) / 1000000000.0;
    double cost = ((1024.0 * 1024.0) / (double)bytes);

    printf("Memcpy %.2lf byte/sec, took %.2lf sec, %lu ns\n", bytes / seconds, seconds, elapsed);
    printf("1MB copy time cost: %.2lf ns\n", elapsed * cost);
  }

  return 0;
}

Собрать и запустить так: rm a.out; g++ -std=c++11 -O3 memcpy-measure.cpp; ./a.out

И на моём lenovo carbon X1 gen 7 получил такое:

alloc: 53937 ns
fill: 769249218 ns
Memcpy 10147233381.31 byte/sec, took 0.85 sec, 846528728 ns
1MB copy time cost: 103336.15 ns
copy: 846548979 ns

Железо ноута:

i7-8565U
Type: LPDDR3
Type Detail: Synchronous
Speed: 2133 MT/s

Исправление kilokolyan, :

Про стек - да. Во многих случаях так.

Про копирование. Замерял тут время работы ::read() внезапно.

Код получения текущего времени:

uint64_t curr_nano_mono() {
  timespec ts;
  if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
    return ts.tv_sec * 1000000000L + ts.tv_nsec;
  }
  return 0;
}

Мерял так:

  auto t1 = curr_nano_mono();
  int rd = ::read(socket, ptr, size);
  auto t2 = curr_nano_mono();
  printf("read time %lu ns\n", t2 - t1);

И получилось такое:

// браузер присылает нам по websocket короткие посылки с интервалом в секунду примерно
    1 read time 26576 ns
    2 read time 23573 ns
    3 read time 23166 ns
    4 read time 19196 ns
    5 read time 16056 ns
    6 read time 22784 ns
    7 read time 18044 ns
    8 read time 23853 ns
    9 read time 24285 ns
   10 read time 18270 ns
   11 // брайзер начал посылать посылки чуть длиннее и сильно часто: read стал возвращаться быстрее (видимо что-то прогрето)
   12 read time 7085 ns
   13 read time 3573 ns
   14 read time 3815 ns
   15 read time 4042 ns
   16 read time 3456 ns
   17 read time 3815 ns
   18 read time 6751 ns
   19 read time 12444 ns
   20 read time 9010 ns
   21 read time 23797 ns
   22 // браузер снова начал слать что-то мелкое (байт 16 payload) в секунду.
   23 read time 18039 ns 
   24 read time 15884 ns
   25 read time 19076 ns
   26 read time 18059 ns
   27 read time 22291 ns
   28 read time 18965 ns
   29 read time 17606 ns
   30 read time 17034 ns
   31 read time 16870 ns
   32 read time 12785 ns
   33 read time 23127 ns
   34 read time 17811 ns
   35 read time 18065 ns
   36 read time 17959 ns

Потом померял сколько у меня выжимает memcpy() вот таким методом. Возможно метод дебилен:


#include <iostream>
#include <vector>
#include <string.h>

uint64_t curr_nano_mono() {
  timespec ts;
  if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
    return ts.tv_sec * 1000000000L + ts.tv_nsec;
  }
  return 0;
}

struct Measure {
  uint64_t start_{};
  const char *name_{};

  explicit Measure(const char *_name)
  : start_(curr_nano_mono())
  , name_(_name)
  {
  }

  uint64_t elapsed() {
    return curr_nano_mono() - start_;
  }
  ~Measure() {
    printf("%s: %lu ns\n", name_, elapsed());
  }
};


int main() {

  const auto BUFFS = 32;
  const auto BS = 1024 * 1024 * 8;
  std::vector<char*> vect(BUFFS, nullptr);

  srand(time(nullptr));

  {
    Measure me("alloc");
    for (auto &p : vect) {
      p = new char[BS];
    }
  }

  {
    Measure me("fill");
    for (auto &buff : vect) {
      for (char *p = buff, *end = buff + BS; p < end; ++p) {
        *p = reinterpret_cast<size_t>(p) % 256;
      }
    }
  }

  {
    Measure me("copy");
    const auto ITERS = 1024;
    size_t bytes = 0;
    // Copy some bytes from random "from" to random "to" with random offset in "from".
    for (auto iter = ITERS; iter >= 0; --iter) {
      auto from = 0;
      auto to = 0;
      // this loop makes sure we use different buffers
      while (from == to) {
        from = rand() % BUFFS;
        to = rand() % BUFFS;
      }

      // small random offset
      auto offset = rand() % (1024*16);
      bytes += (BS - offset);

      ::memcpy(vect[to], vect[from] + offset, BS - offset);
    }

    auto elapsed = me.elapsed();
    double seconds = static_cast<double>(elapsed) / 1000000000.0;
    double cost = ((1024.0 * 1024.0) / (double)bytes);

    printf("Memcpy %.2lf byte/sec, took %.2lf sec, %lu ns\n", bytes / seconds, seconds, elapsed);
    printf("1MB copy time cost: %.2lf ns\n", elapsed * cost);
  }

  return 0;
}

Собрать и запустить так: rm a.out; g++ -std=c++11 -O3 memcpy-measure.cpp; ./a.out

И на моём lenovo carbon X1 gen 7 получил такое:

alloc: 53937 ns
fill: 769249218 ns
Memcpy 10147233381.31 byte/sec, took 0.85 sec, 846528728 ns
1MB copy time cost: 103336.15 ns
copy: 846548979 ns

Железо ноута:

i7-8565U
Type: LPDDR3
Type Detail: Synchronous
Speed: 2133 MT/s

Исправление kilokolyan, :

Про стек - да. Во многих случаях так.

Про копирование. Замерял тут время работы ::read() внезапно.

Код получения текущего времени:

uint64_t curr_nano_mono() {
  timespec ts;
  if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
    return ts.tv_sec * 1000000000L + ts.tv_nsec;
  }
  return 0;
}

Мерял так:

  auto t1 = curr_nano_mono();
  int rd = ::read(socket, ptr, size);
  auto t2 = curr_nano_mono();
  printf("read time %lu ns\n", t2 - t1);

И получилось такое:

    1 read time 26576 ns
    2 read time 23573 ns
    3 read time 23166 ns
    4 read time 19196 ns
    5 read time 16056 ns
    6 read time 22784 ns
    7 read time 18044 ns
    8 read time 23853 ns
    9 read time 24285 ns
   10 read time 18270 ns
   11 // брайзер начал посылать посылки чуть длиннее и сильно часто: read стал возвращаться быстрее (видимо что-то прогрето)
   12 read time 7085 ns
   13 read time 3573 ns
   14 read time 3815 ns
   15 read time 4042 ns
   16 read time 3456 ns
   17 read time 3815 ns
   18 read time 6751 ns
   19 read time 12444 ns
   20 read time 9010 ns
   21 read time 23797 ns
   22 // браузер снова начал слать что-то мелкое (байт 16 payload) в секунду.
   23 read time 18039 ns 
   24 read time 15884 ns
   25 read time 19076 ns
   26 read time 18059 ns
   27 read time 22291 ns
   28 read time 18965 ns
   29 read time 17606 ns
   30 read time 17034 ns
   31 read time 16870 ns
   32 read time 12785 ns
   33 read time 23127 ns
   34 read time 17811 ns
   35 read time 18065 ns
   36 read time 17959 ns

Потом померял сколько у меня выжимает memcpy() вот таким методом. Возможно метод дебилен:


#include <iostream>
#include <vector>
#include <string.h>

uint64_t curr_nano_mono() {
  timespec ts;
  if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
    return ts.tv_sec * 1000000000L + ts.tv_nsec;
  }
  return 0;
}

struct Measure {
  uint64_t start_{};
  const char *name_{};

  explicit Measure(const char *_name)
  : start_(curr_nano_mono())
  , name_(_name)
  {
  }

  uint64_t elapsed() {
    return curr_nano_mono() - start_;
  }
  ~Measure() {
    printf("%s: %lu ns\n", name_, elapsed());
  }
};


int main() {

  const auto BUFFS = 32;
  const auto BS = 1024 * 1024 * 8;
  std::vector<char*> vect(BUFFS, nullptr);

  srand(time(nullptr));

  {
    Measure me("alloc");
    for (auto &p : vect) {
      p = new char[BS];
    }
  }

  {
    Measure me("fill");
    for (auto &buff : vect) {
      for (char *p = buff, *end = buff + BS; p < end; ++p) {
        *p = reinterpret_cast<size_t>(p) % 256;
      }
    }
  }

  {
    Measure me("copy");
    const auto ITERS = 1024;
    size_t bytes = 0;
    // Copy some bytes from random "from" to random "to" with random offset in "from".
    for (auto iter = ITERS; iter >= 0; --iter) {
      auto from = 0;
      auto to = 0;
      // this loop makes sure we use different buffers
      while (from == to) {
        from = rand() % BUFFS;
        to = rand() % BUFFS;
      }

      // small random offset
      auto offset = rand() % (1024*16);
      bytes += (BS - offset);

      ::memcpy(vect[to], vect[from] + offset, BS - offset);
    }

    auto elapsed = me.elapsed();
    double seconds = static_cast<double>(elapsed) / 1000000000.0;
    double cost = ((1024.0 * 1024.0) / (double)bytes);

    printf("Memcpy %.2lf byte/sec, took %.2lf sec, %lu ns\n", bytes / seconds, seconds, elapsed);
    printf("1MB copy time cost: %.2lf ns\n", elapsed * cost);
  }

  return 0;
}

Собрать и запустить так: rm a.out; g++ -std=c++11 -O3 memcpy-measure.cpp; ./a.out

И на моём lenovo carbon X1 gen 7 получил такое:

alloc: 53937 ns
fill: 769249218 ns
Memcpy 10147233381.31 byte/sec, took 0.85 sec, 846528728 ns
1MB copy time cost: 103336.15 ns
copy: 846548979 ns

Железо ноута:

i7-8565U
Type: LPDDR3
Type Detail: Synchronous
Speed: 2133 MT/s

Исходная версия kilokolyan, :

Про стек - да. Во многих случаях так.

Про копирование. Замерял тут время работы ::read внезапно.

Код получения текущего времени:

uint64_t curr_nano_mono() {
  timespec ts;
  if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
    return ts.tv_sec * 1000000000L + ts.tv_nsec;
  }
  return 0;
}

Мерял так:

  auto t1 = curr_nano_mono();
  int rd = ::read(socket, ptr, size);
  auto t2 = curr_nano_mono();
  printf("read time %lu ns\n", t2 - t1);

И получилось такое:

    1 read time 26576 ns
    2 read time 23573 ns
    3 read time 23166 ns
    4 read time 19196 ns
    5 read time 16056 ns
    6 read time 22784 ns
    7 read time 18044 ns
    8 read time 23853 ns
    9 read time 24285 ns
   10 read time 18270 ns
   11 // брайзер начал посылать посылки чуть длиннее и сильно часто: read стал возвращаться быстрее (видимо что-то прогрето)
   12 read time 7085 ns
   13 read time 3573 ns
   14 read time 3815 ns
   15 read time 4042 ns
   16 read time 3456 ns
   17 read time 3815 ns
   18 read time 6751 ns
   19 read time 12444 ns
   20 read time 9010 ns
   21 read time 23797 ns
   22 // браузер снова начал слать что-то мелкое (байт 16 payload) в секунду.
   23 read time 18039 ns 
   24 read time 15884 ns
   25 read time 19076 ns
   26 read time 18059 ns
   27 read time 22291 ns
   28 read time 18965 ns
   29 read time 17606 ns
   30 read time 17034 ns
   31 read time 16870 ns
   32 read time 12785 ns
   33 read time 23127 ns
   34 read time 17811 ns
   35 read time 18065 ns
   36 read time 17959 ns

Потом померял сколько у меня выжимает memcpy() вот таким методом. Возможно метод дебилен:


#include <iostream>
#include <vector>
#include <string.h>

uint64_t curr_nano_mono() {
  timespec ts;
  if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
    return ts.tv_sec * 1000000000L + ts.tv_nsec;
  }
  return 0;
}

struct Measure {
  uint64_t start_{};
  const char *name_{};

  explicit Measure(const char *_name)
  : start_(curr_nano_mono())
  , name_(_name)
  {
  }

  uint64_t elapsed() {
    return curr_nano_mono() - start_;
  }
  ~Measure() {
    printf("%s: %lu ns\n", name_, elapsed());
  }
};


int main() {

  const auto BUFFS = 32;
  const auto BS = 1024 * 1024 * 8;
  std::vector<char*> vect(BUFFS, nullptr);

  srand(time(nullptr));

  {
    Measure me("alloc");
    for (auto &p : vect) {
      p = new char[BS];
    }
  }

  {
    Measure me("fill");
    for (auto &buff : vect) {
      for (char *p = buff, *end = buff + BS; p < end; ++p) {
        *p = reinterpret_cast<size_t>(p) % 256;
      }
    }
  }

  {
    Measure me("copy");
    const auto ITERS = 1024;
    size_t bytes = 0;
    // Copy some bytes from random "from" to random "to" with random offset in "from".
    for (auto iter = ITERS; iter >= 0; --iter) {
      auto from = 0;
      auto to = 0;
      // this loop makes sure we use different buffers
      while (from == to) {
        from = rand() % BUFFS;
        to = rand() % BUFFS;
      }

      // small random offset
      auto offset = rand() % (1024*16);
      bytes += (BS - offset);

      ::memcpy(vect[to], vect[from] + offset, BS - offset);
    }

    auto elapsed = me.elapsed();
    double seconds = static_cast<double>(elapsed) / 1000000000.0;
    double cost = ((1024.0 * 1024.0) / (double)bytes);

    printf("Memcpy %.2lf byte/sec, took %.2lf sec, %lu ns\n", bytes / seconds, seconds, elapsed);
    printf("1MB copy time cost: %.2lf ns\n", elapsed * cost);
  }

  return 0;
}

Собрать и запустить так: rm a.out; g++ -std=c++11 -O3 memcpy-measure.cpp; ./a.out

И на моём lenovo carbon X1 gen 7 получил такое:

alloc: 53937 ns
fill: 769249218 ns
Memcpy 10147233381.31 byte/sec, took 0.85 sec, 846528728 ns
1MB copy time cost: 103336.15 ns
copy: 846548979 ns

Железо ноута:

i7-8565U
Type: LPDDR3
Type Detail: Synchronous
Speed: 2133 MT/s