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 목록에서 rdtsc
with 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;rdtsc
AMD 플랫폼과 lfence;rdtsc
Intel에서 사용합니다. 이 둘을 구별하는 데 신경 쓰지 않으려면 .NET 보다 강한 장벽이므로 mfence;rdtsc
약간 느리지 만 둘 다 에서 작동합니다 .mfence
lfence
아래와 같이 사용할 수 있습니다.
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
'program story' 카테고리의 다른 글
JavaScript가 브라우저에 구현 된 유일한 클라이언트 측 스크립팅 언어 인 이유는 무엇입니까? (0) | 2020.12.02 |
---|---|
Visual Studio 2012 및 Entity Framework 5에서 단위 테스트를 위해 LocalDb를 설정하는 방법 (0) | 2020.12.02 |
파이썬-모든 내장 데코레이터는 무엇입니까? (0) | 2020.12.02 |
Chromecast Receiver Emulator 또는 개발 용 수신기 역할을하는 대체 앱이 있습니까? (0) | 2020.12.02 |
CSS를 완벽하게 지원하는 오픈 소스 HTML-PDF 렌더러 (0) | 2020.12.02 |