1

I have a cpu that have multiple A72 cores.

I am trying to bench an algorithm and I want to count the number of core cycles that elapsed during the execution of a thread.

I've cross-compiled two kernel objects to configure properly the registers in order to access PMCCNTR_EL0 : https://github.com/rdolbeau/enable_arm_pmu

https://github.com/jerinjacobk/armv8_pmu_cycle_counter_el0

Obviously, both should do the same stuff so I only load one at a time, I have compiled both because I haven't found a solution that works perfectly at the time being.

Here is the code I am trying to bench (for example purpose, just to try the register read).

#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sched.h> 
#include "armpmu_lib.h"

uint64_t tmp = 35000;
uint64_t t0_start = 0;
uint64_t t0_stop = 0;
uint64_t t1_start = 0;
uint64_t t1_stop = 0;
uint64_t t2_start = 0;
uint64_t t2_stop = 0;

void * thread_1(){
    //Set core affinity and priority
    cpu_set_t my_set;
    CPU_ZERO(&my_set);
    CPU_SET(1,&my_set);
    sched_setaffinity(0,sizeof(cpu_set_t),&my_set);
    struct sched_param param= {
        .sched_priority=99
    };
    sched_setscheduler(0,SCHED_FIFO,&param);
    sleep(1);
    //Bench
    asm volatile("mrs %0, PMCCNTR_EL0" : "=r"(t1_start));
    for(int i=0; i<4000; i++){
        tmp+=1;
        //printf("Thread 1\n");
    }
    asm volatile("mrs %0, PMCCNTR_EL0" : "=r"(t1_stop));
    return NULL;
}

void * thread_2(){
    //Set core affinity and priority
    cpu_set_t my_set;
    CPU_ZERO(&my_set);
    CPU_SET(8,&my_set);
    sched_setaffinity(0,sizeof(cpu_set_t),&my_set);
    struct sched_param param= {
        .sched_priority=0
    };
    sched_setscheduler(0,SCHED_FIFO,&param);
    //Bench
    sleep(1);
    asm volatile("mrs %0, PMCCNTR_EL0" : "=r"(t2_start));
    for(int i=0; i<4000; i++){
        //printf("Thread 2\n");
        tmp+=5;
    }
    asm volatile("mrs %0, PMCCNTR_EL0" : "=r"(t2_stop));
    return NULL;
}

int main(){
    //Get the starting point cycle number
    asm volatile("mrs %0, PMCCNTR_EL0" : "=r"(t0_start));

    //Creates threads
    pthread_t thread_id_1;
    pthread_t thread_id_2;
    pthread_create(&thread_id_1, NULL, thread_1, NULL);
    pthread_create(&thread_id_2, NULL, thread_2, NULL);

    //Wait termination
    pthread_join(thread_id_1, NULL);
    pthread_join(thread_id_2, NULL);
    
    //Read number of cycles at the end of execution
    asm volatile("mrs %0, PMCCNTR_EL0" : "=r"(t0_stop));
    
    printf("T0 Execution cycles : %lu\n",t0_stop - t0_start); //Main thread number of cycles
    printf("T1 Execution cycles : %lu\n",t1_stop - t1_start); //Thread 1 number of cycles
    printf("T2 Execution cycles : %lu\n",t2_stop - t2_start); //Thread 2 number of cycles
        
    return 0;
}

When I use this kernel module : enable_arm_pmu

If not loaded, I have an illegal instruction error, that's expected When I run the test code given on the repo, It works correctly (I have consistent non zero values). If loaded then I run my code once, I have extreme values (FFFFFFFFFFDDA4A0 or O) for Main thread and values that seems correct for the rest of the threads (between 10 and 25us).

However, If I run my bench several times without unloading, reloading the kernel module, all the following executions measures 0 cycles for Thread 1 and Thread 2.

Am I missing some point in the configuration of the registers ?

When using armv8_pmu_cycle_counter_el0 kernel object, the value of the number of cycles for main thread seems correct (5 to 10 ms) however both threads returns 0 cycles of execution.

JacobB
  • 15
  • 2

0 Answers0