실행 파일이 한 번 실행되지 않고 연속으로 두 번 실행될 때 코어 간 대기 시간이 무작위인 이유는 무엇입니까?

실행 파일이 한 번 실행되지 않고 연속으로 두 번 실행될 때 코어 간 대기 시간이 무작위인 이유는 무엇입니까?

좋은 코어 상관 관계를 찾기 위해 서버에서 코어 간 대기 시간을 벤치마킹하고 있습니다.

두 스레드의 핵심 선호도를 서로 다른 CPU로 설정하고 스레드 간 메시지 대기 시간을 계산하려고 합니다. 메시지는 를 통해 전달됩니다 std::atomic. 실행 시간은 다음과 같이 계산됩니다.https://github.com/fuatu/core-latency-atomic

할당을 통한 핵심 선호도(POSIX)

void set_affinity(long cpu_num) {
  cpu_set_t cpuset;
  CPU_ZERO(&cpuset);
  CPU_SET(cpu_num, &cpuset);
  pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
}

런타임은 두 개의 스레드가 액세스하는 원자로 측정됩니다.

enum State
{
  Preparing,
  Ready,
  Ping,
  Pong,
  Finish,
};

class Sync
{
public:
  State wait_as_long_as(State wait_state)
  {
    State loaded_state = state.load();
    while (loaded_state == wait_state)
      loaded_state = state.load();
    return loaded_state;
  }

  void wait_until(State expected_state)
  {
    while (state.load() != expected_state)
    {
    }
  }

  void set(State new_state, State expected_state)
  {
    //state.store(new_state);
    state.compare_exchange_strong(expected_state, new_state);
  }

private:
  std::atomic<State> state{Preparing};
};

static void set_affinity(unsigned int cpu_num)
{
  cpu_set_t cpuset;
  CPU_ZERO(&cpuset);
  CPU_SET(cpu_num, &cpuset);
  pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
}

struct LatencyBench
{
  LatencyBench(long first_cpu_, long second_cpu_)
    : first_cpu{first_cpu_}
    , second_cpu{second_cpu_}
  {
  }

  void operator()(nonius::chronometer meter) const
  {
    Sync sync;

    set_affinity(first_cpu);

    std::thread t([&] {
      set_affinity(second_cpu);
      sync.set(Ready,Preparing);

      State state = sync.wait_as_long_as(Ready);
      while (state != Finish)
      {
        //if (state == Ping)
        sync.set(Pong,Ping);
        state = sync.wait_as_long_as(Pong);
      }
    });

    sync.wait_until(Ready);

    // start timer
    sync.set(Ping,Ready);
    sync.wait_until(Pong);
    // stop timer

    sync.set(Finish,Pong);
    t.join();
  }

  const long first_cpu;
  const long second_cpu;
};

./a.out런타임 시간은 스레드 통신 중에만 측정되며 시작 시간 이나 두 번째 스레드를 시작하는 시간은 포함되지 않습니다 .

측정된 대기 시간은 동일한 프로그램 내에서 반복된 실험에 대해 견고합니다. 낮잠을 자고 main두 번째로 분석을 실행해도 대기 시간은 여전히 ​​첫 번째 측정의 약 1나노초 내에 있습니다. 하지만 ./a.out다시 실행하면 측정된 대기 시간이 약 40나노초 정도 변경될 수 있습니다. 이는 또한 최상의 대기 시간으로 코어 쌍을 변경할 수도 있습니다.

동일한 실행 파일을 두 번 실행할 때 이러한 무작위 대기 시간 변경 뒤에 무엇이 있을 수 있는지 알고 계십니까?

추가 세부 사항:numactl -m 0 -N 0 ./a.outNUMA 노드 0 내의 코어 쌍을 사용 하고 집중해도 이러한 상황이 완화되지는 않습니다.

하위 NUMA 노드로 구성된 서버를 사용하고 하위 NUMA 노드 내에 남아 있어도 이 내용은 변경되지 않습니다. Xeon 및 EPYC 프로세서에는 지연 시간 변동성이 복제되었습니다.

main두 번째 분석에서는 아마도 모든 것을 캐시할 것이기 때문에 이러한 여러 분석을 통해 이것이 캐싱 문제가 아니라는 것을 나타낼 수 있기를 바랍니다 main.

관련 정보