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,¶m);
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,¶m);
//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.