program story

rdtscp, rdtsc : 메모리와 CPUID / rdtsc의 차이점은 무엇입니까?

inputbox 2020. 12. 2. 21:03
반응형

rdtscp, rdtsc : 메모리와 CPUID / rdtsc의 차이점은 무엇입니까?


성능 모니터링을 위해 tsc를 사용하고 명령 재정렬을 방지하려고한다고 가정합니다.

옵션은 다음과 같습니다.

1 : rdtscp 직렬화 호출입니다. rdtscp에 대한 호출을 중심으로 재정렬하는 것을 방지합니다.

__asm__ __volatile__("rdtscp; "         // serializing read of tsc
                     "shl $32,%%rdx; "  // shift higher 32 bits stored in rdx up
                     "or %%rdx,%%rax"   // and or onto rax
                     : "=a"(tsc)        // output to tsc variable
                     :
                     : "%rcx", "%rdx"); // rcx and rdx are clobbered

그러나 rdtscp최신 CPU에서만 사용할 수 있습니다. 그래서이 경우 우리는 rdtsc. 그러나 rdtsc비 직렬화이므로 단독으로 사용하더라도 CPU가 다시 정렬하는 것을 막지는 않습니다.

따라서 재정렬을 방지하기 위해 다음 두 옵션 중 하나를 사용할 수 있습니다.

2 : 이것은에 전화입니다 cpuid다음과 rdtsc. cpuid직렬화 호출입니다.

volatile int dont_remove __attribute__((unused)); // volatile to stop optimizing
unsigned tmp;
__cpuid(0, tmp, tmp, tmp, tmp);                   // cpuid is a serialising call
dont_remove = tmp;                                // prevent optimizing out cpuid

__asm__ __volatile__("rdtsc; "          // read of tsc
                     "shl $32,%%rdx; "  // shift higher 32 bits stored in rdx up
                     "or %%rdx,%%rax"   // and or onto rax
                     : "=a"(tsc)        // output to tsc
                     :
                     : "%rcx", "%rdx"); // rcx and rdx are clobbered

3 : 이것은 재주문을 방지하는 clobber 목록에서 rdtscwith memory대한 호출입니다.

__asm__ __volatile__("rdtsc; "          // read of tsc
                     "shl $32,%%rdx; "  // shift higher 32 bits stored in rdx up
                     "or %%rdx,%%rax"   // and or onto rax
                     : "=a"(tsc)        // output to tsc
                     :
                     : "%rcx", "%rdx", "memory"); // rcx and rdx are clobbered
                                                  // memory to prevent reordering

세 번째 옵션에 대한 나의 이해는 다음과 같습니다.

호출을 수행 __volatile__하면 옵티마이 저가 asm을 제거하거나 asm의 결과 (또는 입력 변경)를 필요로 할 수있는 명령간에이를 이동하지 못합니다. 그러나 관련되지 않은 작업과 관련하여 여전히 이동할 수 있습니다. 그래서 __volatile__충분하지 않습니다.

컴파일러 메모리가 손상되고 있음을 알립니다 : "memory").. "memory"GCC는 주변에 의지하지 재정렬하여 메모리 내용이 ASM에서 동일한 나머지에 대해 어떤 가정을하고, 할 수없는 소지품 수단.

그래서 내 질문은 다음과 같습니다.

  • 1 : 내 이해가 __volatile__"memory"올바른?
  • 2 : 두 번째 두 번의 호출이 같은 일을합니까?
  • 3 : 사용 "memory"은 다른 직렬화 명령어를 사용하는 것보다 훨씬 간단 해 보입니다. 왜 두 번째 옵션보다 세 번째 옵션을 사용합니까?

주석에서 언급했듯이 컴파일러 장벽프로세서 장벽 사이에는 차이가 있습니다. volatile그리고 memory컴파일러 장벽으로 asm 문 법하지만, 프로세서에 여전히 재주문 지침에게 무료로 제공됩니다.

프로세서 장벽은 명시 적으로 제공되어야하는 특수 명령입니다 (예 : rdtscp, cpuid메모리 차단 명령 ( mfence, lfence,...) 등).

제쳐두고, cpuid이전에 장벽으로 사용 하는 rdtsc것이 일반적이지만 성능 관점에서 매우 나쁠 수 있습니다. 가상 머신 플랫폼은 종종 cpuid클러스터의 여러 머신에 공통 CPU 기능 세트를 적용하기 위해 명령을 트랩하고 에뮬레이트 하기 때문입니다. (실시간 마이그레이션이 작동하는지 확인하기 위해). 따라서 메모리 펜스 명령 중 하나를 사용하는 것이 좋습니다.

Linux 커널은 mfence;rdtscAMD 플랫폼과 lfence;rdtscIntel에서 사용합니다. 이 둘을 구별하는 데 신경 쓰지 않으려면 .NET 보다 강한 장벽이므로 mfence;rdtsc약간 느리지 만 둘 다 에서 작동합니다 .mfencelfence


아래와 같이 사용할 수 있습니다.

asm volatile (
"CPUID\n\t"/*serialize*/
"RDTSC\n\t"/*read the clock*/
"mov %%edx, %0\n\t"
"mov %%eax, %1\n\t": "=r" (cycles_high), "=r"
(cycles_low):: "%rax", "%rbx", "%rcx", "%rdx");
/*
Call the function to benchmark
*/
asm volatile (
"RDTSCP\n\t"/*read the clock*/
"mov %%edx, %0\n\t"
"mov %%eax, %1\n\t"
"CPUID\n\t": "=r" (cycles_high1), "=r"
(cycles_low1):: "%rax", "%rbx", "%rcx", "%rdx");

In the code above, the first CPUID call implements a barrier to avoid out-of-order execution of the instructions above and below the RDTSC instruction. With this method we avoid to call a CPUID instruction in between the reads of the real-time registers

The first RDTSC then reads the timestamp register and the value is stored in memory. Then the code that we want to measure is executed. The RDTSCP instruction reads the timestamp register for the second time and guarantees that the execution of all the code we wanted to measure is completed. The two “mov” instructions coming afterwards store the edx and eax registers values into memory. Finally a CPUID call guarantees that a barrier is implemented again so that it is impossible that any instruction coming afterwards is executed before CPUID itself.

참고URL : https://stackoverflow.com/questions/12631856/difference-between-rdtscp-rdtsc-memory-and-cpuid-rdtsc

반응형