Есть ли ограничение мультиплексирования для групп событий perf_event.h на Pi 3 - PullRequest
0 голосов
/ 29 мая 2020

Я пытаюсь выполнить некоторую аналитику событий оборудования PMU / кеширования на моем Pi, используя perf_event.h. Я получаю сообщение об ошибке всякий раз, когда пытаюсь добавить более 7 событий в группу событий. Есть несколько вещей, которые я не понимаю.

Основные вопросы заключаются в следующем:

  • Есть ли ограничение на количество событий, которые могут быть мультиплексированы на Pi (я полагаю, ARM cortex A53)? Как я уже сказал, у меня не получается 8, и это кажется низким.

  • При мультиплексировании событий perf_event.h определяет количество счетчиков PMU и использует их все?

  • Если есть ограничения на количество событий в группах событий, могу ли я получить доступ к этой информации с помощью возможностей perf_event.h?

  • Знаете ли вы какие-либо хорошие ресурсы для помогите мне лучше понять функциональность perf_event.h?

Я собираюсь включить весь файл, который пытаюсь запустить, потому что я новичок в этом, и я не уверен, какая часть будет быть значительным. Макросы N и M в верхней части кода - это количество используемых событий hw и событий кэша hw соответственно. Ошибка возникает всякий раз, когда N + M> 7

Я считаю, что этот код будет работать в любой системе Linux (используется стресс-пакет apt-get install stress)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/perf_event.h>
#include <linux/hw_breakpoint.h>
#include <asm/unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

#define N 0 // number of hw events to monitor
#define M 8 // number of hw events to monitor

int global_sigchld_trip = 0; // catch end child
void sighandler(int);

// function to add perf event to event list
// based on example from:
//     http://web.eece.maine.edu/~vweaver/projects/perf_events/perf_event_open.html
static long
perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
                    int cpu, int group_fd, unsigned long flags)
{
    int ret;
    ret = syscall(__NR_perf_event_open, hw_event, 
                    pid, cpu, group_fd, flags);
    return ret;
}

// no function for seeing if we can monitor kernel events
int no_function(int seconds)
{
    sleep(seconds);    
    printf("\n\n Start stress \n\n");
    system("stress -c 4 -t 10");
    return 0;
}



int
main(int argc, char **argv){

    signal(SIGCHLD, sighandler);

    int num_hw_events = N;
    uint pe_hw[7] = {
                        PERF_COUNT_HW_CPU_CYCLES,
                        PERF_COUNT_HW_INSTRUCTIONS,
                        PERF_COUNT_HW_CACHE_REFERENCES,
                        PERF_COUNT_HW_CACHE_MISSES,
                        PERF_COUNT_HW_BRANCH_INSTRUCTIONS,
                        PERF_COUNT_HW_BRANCH_MISSES,
                        PERF_COUNT_HW_BUS_CYCLES,
                    };

    char hw_name_arr[7][50] = {
                            "PERF_COUNT_HW_CPU_CYCLES",
                            "PERF_COUNT_HW_INSTRUCTIONS",
                            "PERF_COUNT_HW_CACHE_REFERENCES",
                            "PERF_COUNT_HW_CACHE_MISSES",
                            "PERF_COUNT_HW_BRANCH_INSTRUCTIONS",
                            "PERF_COUNT_HW_BRANCH_MISSES",
                            "PERF_COUNT_HW_BUS_CYCLES",
                           };


    // cache events
    int num_hw_cache_events = M;
    uint pe_hw_cache[12] = {
                    (PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), // 
                    (PERF_COUNT_HW_CACHE_L1I) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
                    (PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
                    (PERF_COUNT_HW_CACHE_BPU) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),

                    (PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_WRITE<< 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), // 
                    (PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_WRITE<< 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
                    (PERF_COUNT_HW_CACHE_BPU) | (PERF_COUNT_HW_CACHE_OP_WRITE<< 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
                    };

    char hw_cache_name_arr[12][50] = {
                    "PERF_COUNT_HW_CACHE_L1D_read_miss",
                    "PERF_COUNT_HW_CACHE_L1I_read_miss",
                    "PERF_COUNT_HW_CACHE_LL_read_miss",
                    "PERF_COUNT_HW_CACHE_BPU_read_miss",

                    "PERF_COUNT_HW_CACHE_L1D_write_miss",
                    "PERF_COUNT_HW_CACHE_LL_write_miss",
                    "PERF_COUNT_HW_CACHE_BPU_write_miss",
                    };


    struct perf_event_attr pat_arr[num_hw_events+num_hw_cache_events];

    long long counts[num_hw_events+num_hw_cache_events];
    int fd_arr[num_hw_events+num_hw_cache_events];


    // initialize hw events
    for(int i=0; i<num_hw_events; i++)
    {
        memset(&pat_arr[i], 0, sizeof(struct perf_event_attr));
        pat_arr[i].type = PERF_TYPE_HARDWARE;
        pat_arr[i].size = sizeof(struct perf_event_attr);
        pat_arr[i].config = pe_hw[i];
        if(i==0){pat_arr[i].disabled = 1;}
        else{pat_arr[i].disabled = 0;}
        pat_arr[i].exclude_kernel = 1;
        pat_arr[i].exclude_hv = 1;
        pat_arr[i].inherit = 1;

        if(i==0){fd_arr[i] = perf_event_open(&pat_arr[i],0,-1,-1,0);}
        else{fd_arr[i] = perf_event_open(&pat_arr[i],0,-1,fd_arr[0],0);}
        if (fd_arr[i] == -1){
            fprintf(stderr, "Error opening leader %llx\n", pat_arr[i].config);
            exit(EXIT_FAILURE);
        }
        printf("FD%d: %d \t ITEM: %s\n",i,fd_arr[i], hw_name_arr[i]);
    }

    // initialize hw cache events
    for(int i=0; i<num_hw_cache_events; i++)
    {
        memset(&pat_arr[i+num_hw_events], 0, sizeof(struct perf_event_attr));
        pat_arr[i+num_hw_events].type = PERF_TYPE_HW_CACHE;
        pat_arr[i+num_hw_events].size = sizeof(struct perf_event_attr);
        pat_arr[i+num_hw_events].config = pe_hw_cache[i];
        if(i+num_hw_events==0){printf("dis=1");pat_arr[i+num_hw_events].disabled = 1;}
        else{printf("dis=0");pat_arr[i+num_hw_events].disabled = 0;}
        pat_arr[i+num_hw_events].exclude_kernel = 1;
        pat_arr[i+num_hw_events].exclude_hv = 1;
        pat_arr[i+num_hw_events].inherit = 1;

        if(i+num_hw_events==0){fd_arr[i+num_hw_events] = perf_event_open(&pat_arr[i+num_hw_events],0,-1,-1,0);}
        else{fd_arr[i+num_hw_events] = perf_event_open(&pat_arr[i+num_hw_events],0,-1,fd_arr[0],0);}
        if (fd_arr[i+num_hw_events] == -1){
            printf("\ni: %d\nnhe:%d\n",i,num_hw_events);
            fprintf(stderr, "Error opening leader %llx\n", pat_arr[i+num_hw_events].config);
            exit(EXIT_FAILURE);
        }
        printf("FD%d: %d \t ITEM: %s\n",i+num_hw_events,fd_arr[i+num_hw_events], hw_cache_name_arr[i]);
    }


    // reset and enable counters
    for(int i=0; i<num_hw_events+num_hw_cache_events; i++){
        ioctl(fd_arr[i], PERF_EVENT_IOC_RESET,0);
        ioctl(fd_arr[i], PERF_EVENT_IOC_ENABLE,0);
    }

/////////////////// ACTION ///////////////////////////

    /*-------- CHILD PROCESS BEING REDORDED -------*/
    printf("\nSHOULD FORK RIGHTE HERE\n");
    pid_t proc = fork();
    if(proc==0){
        printf("entered child process\n");
        int no_sleep = 3;
        no_function(no_sleep);
        //x = silly_events(loop);
        printf("exiting child process\n");
        return 0;
    }
    /*-------- ACTION TAKEN DURRING REDORDING-------*/
    else{
        while(!global_sigchld_trip){
            sleep(1);
            for(int i=0;i<num_hw_events+num_hw_cache_events;i++){read(fd_arr[i], &counts[i], sizeof(long long));}
            for(int i=0;i<num_hw_events+num_hw_cache_events;i++){ioctl(fd_arr[i], PERF_EVENT_IOC_RESET,0);}
            for(int i=0;i<num_hw_events;i++){printf("%lld %s\t\n", counts[i], hw_name_arr[i]);}
            printf("--------------------------------------\n");
            for(int i=0;i<num_hw_cache_events;i++){printf("%lld %s\t\n", counts[i+num_hw_events], hw_cache_name_arr[i]);}
            printf("\n\n");
        }
    }


    for(int i=0;i<num_hw_events+num_hw_cache_events;i++){ioctl(fd_arr[i], PERF_EVENT_IOC_DISABLE,0);}
    for(int i=0;i<num_hw_events+num_hw_cache_events;i++){read(fd_arr[i], &counts[i], sizeof(long long));}
    for(int i=0;i<num_hw_events;i++){printf("Used %lld %s\t", counts[i], hw_name_arr[i]);}
    for(int i=0;i<num_hw_cache_events;i++){printf("Used %lld %s\t", counts[i+num_hw_events], hw_cache_name_arr[i]);}
    for(int i=0;i<num_hw_events;i++){close(fd_arr[i]);}
    return 0;
}

void sighandler(int signum) {
   printf("Caught signal %d, coming out...\n", signum);
   global_sigchld_trip = 1;
}

...