我要评分
获取效率
正确性
完整性
易理解

Replacing the x86 rdtsc Assembly Instruction

Symptom

Error: impossible constraint in 'asm'

__asm__ __volatile__("rdtsc" : "=a" (lo), "=d" (hi));

Cause

The Time Stamp Counter (TSC) is a counter in a Pentium-compatible processor and records the number of clock cycles consumed by the processor from the startup. The counter automatically increases by 1 for each cycle. The TSC changes with the processor cycle rate and provides extremely high accuracy. It is often used to analyze and check code. On the x86 platform, the rdtsc instruction is used to obtain the TSC value. On the Kunpeng platform, a similar algorithm is required.

Procedure

Example code on the x86 platform:

static inline uint64_t Rdtsc() 
{ 
    uint32_t lo, hi; 
    __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); 
    return (uint64_t)hi << 32 | lo; 
}

Example code on the Kunpeng platform:

  • Method 1: Use the clock_gettime function provided by Linux for approximate replacement.
    #include <time.h>
    static inline uint64_t Rdtsc() 
    { 
        struct timespec tmp; 
        clock_gettime(CLOCK_MONOTONIC, &tmp); 
        return tmp.tv_sec*2400000000+(uint64_t)tmp.tv_nsec*2.4; //2400000000 and 2.4 are determined based on the server frequency.
    }
  • Method 2: Kunpeng has the Performance Monitors Control Register (PMCR), among which PMCCNTR_EL0 is similar to the TSC register in x86. By default, the register is unreadable in user mode and can be read only after being enabled in kernel mode. Compile the kernel module by referring to GitHub and enable the access to the system register.
    1. Download the source code.
      git clone https://github.com/jerinjacobk/armv8_pmu_cycle_counter_el0
    2. Run the make command.
    3. Execute the insmod pmu_el0_cycle_counter.ko command to install the kernel module and enable the kernel mode (only required for the initial execution).
    4. Replace the code.
      static inline uint64_t
      read_pmccntr(void)
      {
      	uint64_t val;
      	asm volatile("mrs %0, pmccntr_el0" : "=r"(val));
      	return val;
      }