Timing measurements on ARM v8 platform running Linux

Hi Everyone,

i need help about timing measurements on Cortex-A72 (Arm v8) 64-bit running Linux.

i have been trying to read cycle counter (i have got root priviledges on machine), but i can't.

my c code is :


#define _GNU_SOURCE
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <unistd.h>
#include <inttypes.h>
#include <getopt.h>
#include <sched.h>
#include <assert.h>
#include <sys/stat.h>
#include <fcntl.h>

#define ARMV8_PMCR_E            (1 << 0) /* Enable all counters */
#define ARMV8_PMCR_P            (1 << 1) /* Reset all counters */
#define ARMV8_PMCR_C            (1 << 2) /* Cycle counter reset */

#define ARMV8_PMUSERENR_EN      (1 << 0) /* EL0 access enable */
#define ARMV8_PMUSERENR_CR      (1 << 2) /* Cycle counter read enable */
#define ARMV8_PMUSERENR_ER      (1 << 3) /* Event counter read enable */

#define ARMV8_PMCNTENSET_EL0_EN (1 << 31) /* Performance Monitors Count Enable Set register */


void arm_v8_flush(void* address)
{
  asm volatile ("DC CIVAC, %0" :: "r"(address));
  asm volatile ("DSB ISH");
  asm volatile ("ISB");
}


void arm_v8_access_memory(void* pointer)
{
  volatile uint32_t value;
  asm volatile ("LDR %0, [%1]\n\t"
      : "=r" (value)
      : "r" (pointer)
      );
}

void arm_v8_memory_barrier(void)
{
  asm volatile ("DSB SY");
  asm volatile ("ISB");
}

void arm_v8_prefetch(void* pointer)
{
  asm volatile ("PRFM PLDL3KEEP, [%x0]" :: "p" (pointer));
  asm volatile ("PRFM PLDL2KEEP, [%x0]" :: "p" (pointer));
  asm volatile ("PRFM PLDL1KEEP, [%x0]" :: "p" (pointer));
}


uint64_t arm_v8_get_timing(void) {
  uint64_t result = 0;

  asm volatile("MRS %0, PMCCNTR_EL0" : "=r" (result));

  return result;
}

void arm_v8_timing_init(void) {
  uint32_t value = 0;

  /* Enable Performance Counter */
  asm volatile("MRS %0, PMCR_EL0" : "=r" (value));
  value |= ARMV8_PMCR_E; /* Enable */
  value |= ARMV8_PMCR_C; /* Cycle counter reset */
  value |= ARMV8_PMCR_P; /* Reset all counters */
  asm volatile("MSR PMCR_EL0, %0" : : "r" (value));

  /* Enable cycle counter register */
  asm volatile("MRS %0, PMCNTENSET_EL0" : "=r" (value));
  value |= ARMV8_PMCNTENSET_EL0_EN;
  asm volatile("MSR PMCNTENSET_EL0, %0" : : "r" (value));
}

void arm_v8_timing_terminate(void){
  uint32_t value = 0;
  uint32_t mask = 0;

  /* Disable Performance Counter */
  asm volatile("MRS %0, PMCR_EL0" : "=r" (value));
  mask = 0;
  mask |= ARMV8_PMCR_E; /* Enable */
  mask |= ARMV8_PMCR_C; /* Cycle counter reset */
  mask |= ARMV8_PMCR_P; /* Reset all counters */
  asm volatile("MSR PMCR_EL0, %0" : : "r" (value & ~mask));

  /* Disable cycle counter register */
  asm volatile("MRS %0, PMCNTENSET_EL0" : "=r" (value));
  mask = 0;
  mask |= ARMV8_PMCNTENSET_EL0_EN;
  asm volatile("MSR PMCNTENSET_EL0, %0" : : "r" (value & ~mask));
}

 void arm_v8_reset_timing(void) {
  uint32_t value = 0;
  asm volatile("MRS %0, PMCR_EL0" : "=r" (value));
  value |= ARMV8_PMCR_C; /* Cycle counter reset */
  asm volatile("MSR PMCR_EL0, %0" : : "r" (value));
}

int main(){

    int x =10;
    arm_v8_timing_init();
    arm_v8_memory_barrier();
    uint64_t time = arm_v8_get_timing();
    arm_v8_memory_barrier();
    
    arm_v8_access_memory(&x);
    
    arm_v8_memory_barrier();
    uint64_t time2 = arm_v8_get_timing();
    arm_v8_memory_barrier();
    
    uint64_t delta =  time2 - time;
    
    arm_v8_timing_terminate();
    
}

Running the code with root priviledges the compiler gives me :  Ilegal instruction.

why ?

thank you.

Parents
  • Hello, 

    Even if you run your application as root account in Linux OS, it still executes within user CPU mode. 

    The PMU registers are core registers only accessible in PL1 or PL2 modes namely system or supervisor CPU modes.

    Supervisor mode is where Linux kernel runs. System mode is only used for bare metal application. 

    So from my understanding you need to build your application or part of it as a kernel submodule and insmod it. Then when needed you shall make a system call so that the user space program switches to supervisor mode and executes your kernel submodule.

    Florian

Reply
  • Hello, 

    Even if you run your application as root account in Linux OS, it still executes within user CPU mode. 

    The PMU registers are core registers only accessible in PL1 or PL2 modes namely system or supervisor CPU modes.

    Supervisor mode is where Linux kernel runs. System mode is only used for bare metal application. 

    So from my understanding you need to build your application or part of it as a kernel submodule and insmod it. Then when needed you shall make a system call so that the user space program switches to supervisor mode and executes your kernel submodule.

    Florian

Children
No data
More questions in this forum