Skip to content
Snippets Groups Projects
  • ghuter's avatar
    569f527a
    Add a generation system for README.md and doc/mojitos.1 · 569f527a
    ghuter authored
    - README.md can be updated via `make readme`
    - doc/mojitos.1 can be generated via `make man`
    - README.md is updated and doc/mojitos.1 generated on `make all`
    - correct wrong translation "captor", to "sensor"
    - update README.md build instructions
    - mv src/optparse.h and src/info_reader.h to ./lib/
    - add the possibility to execute an alternative function when parsing
      sensor options (other than `add_source()`)
    569f527a
    History
    Add a generation system for README.md and doc/mojitos.1
    ghuter authored
    - README.md can be updated via `make readme`
    - doc/mojitos.1 can be generated via `make man`
    - README.md is updated and doc/mojitos.1 generated on `make all`
    - correct wrong translation "captor", to "sensor"
    - update README.md build instructions
    - mv src/optparse.h and src/info_reader.h to ./lib/
    - add the possibility to execute an alternative function when parsing
      sensor options (other than `add_source()`)
counters.c 6.58 KiB
/*******************************************************
 Copyright (C) 2018-2021 Georges Da Costa <georges.da-costa@irit.fr>

    This file is part of Mojitos.

    Mojitos is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Mojitos is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MojitO/S.  If not, see <https://www.gnu.org/licenses/>.

 *******************************************************/

#include <linux/perf_event.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdint.h>
#include <asm/unistd.h>
#include <stdint.h>
#include "util.h"


struct _counter_t {
    int nbcores;
    int nbperf;
    int **counters;
    uint64_t *counters_values;
    uint64_t *tmp_counters_values;

    int *perf_indexes;

};
typedef struct _counter_t *counter_t;

#include "counters_option.h"

void *show_all_counters(void *none1, size_t none2)
{
    for (unsigned int i = 0; i < nb_counter_option; i++) {
        printf("%s\n", perf_static_info[i].name);
    }
    UNUSED(none1);
    UNUSED(none2);
    exit(EXIT_SUCCESS);
    return NULL;	/* not reached */
}

void perf_type_key(__u32 **perf_type, __u64 **perf_key, int *indexes, int nb)
{
    *perf_type = malloc(nb * sizeof(__u32));
    *perf_key  = malloc(nb * sizeof(__u64));

    for (int i = 0; i < nb; i++) {
        (*perf_key)[i]  = perf_static_info[indexes[i]].perf_key;
        (*perf_type)[i] = perf_static_info[indexes[i]].perf_type;
    }
}
void perf_event_list(char *perf_string, int *nb_perf, int **perf_indexes)
{
    char *token;
    *nb_perf = 0;
    *perf_indexes = NULL;

    while ((token = strtok(perf_string, ",")) != NULL) {
        perf_string = NULL;
        unsigned int i;

        for (i = 0; i < nb_counter_option; i++) {
            if (strcmp(perf_static_info[i].name, token) == 0) {
                (*nb_perf)++;
                (*perf_indexes) = realloc(*perf_indexes, sizeof(int) * (*nb_perf));
                (*perf_indexes)[*nb_perf - 1] = i;
                break;
            }
        }

        if (i == nb_counter_option) {
            fprintf(stderr, "Unknown performance counter: %s\n", token);
            exit(EXIT_FAILURE);
        }
    }
}

static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
                            int cpu, int group_fd, unsigned long flags)
{
    long res = syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);

    if (res == -1) {
        perror("perf_event_open");
        fprintf(stderr, "Error opening leader %llx\n", hw_event->config);
        exit(EXIT_FAILURE);
    }

    return res;
}

counter_t _init_counters(const int nb_perf, const __u32 *types, const __u64 *names)
{
    struct perf_event_attr pe;
    unsigned int nbcores = sysconf(_SC_NPROCESSORS_ONLN);
    memset(&pe, 0, sizeof(struct perf_event_attr));
    pe.size = sizeof(struct perf_event_attr);
    pe.disabled = 1;

    counter_t counters = malloc(sizeof(struct _counter_t));
    counters->nbperf = nb_perf;
    counters->nbcores = nbcores;
    counters->counters = malloc(nb_perf * sizeof(int *));

    for (int i = 0; i < nb_perf; i++) {
        pe.type = types[i];
        pe.config = names[i];
        counters->counters[i] = malloc(nbcores * sizeof(int));

        for (unsigned int core = 0; core < nbcores; core++) {
            counters->counters[i][core] = perf_event_open(&pe, -1, core, -1, PERF_FLAG_FD_CLOEXEC);
        }
    }

    return counters;
}

void clean_counters(void *ptr)
{
    counter_t counters = (counter_t) ptr;

    for (int counter = 0; counter < counters->nbperf; counter++) {
        for (int core = 0; core < counters->nbcores; core++) {
            close(counters->counters[counter][core]);
        }

        free(counters->counters[counter]);
    }

    free(counters->counters);
    free(counters->counters_values);
    free(counters->tmp_counters_values);
    free(counters->perf_indexes);

    free(counters);
}

void start_counters(counter_t counters)
{
    for (int counter = 0; counter < counters->nbperf; counter++) {
        for (int core = 0; core < counters->nbcores; core++) {
            ioctl(counters->counters[counter][core], PERF_EVENT_IOC_ENABLE, 0);
        }
    }
}

void reset_counters(counter_t counters)
{
    for (int counter = 0; counter < counters->nbperf; counter++) {
        for (int core = 0; core < counters->nbcores; core++) {
            ioctl(counters->counters[counter][core], PERF_EVENT_IOC_RESET, 0);
        }
    }
}

void _get_counters(counter_t counters, uint64_t *values)
{
    for (int i = 0; i < counters->nbperf; i++) {
        uint64_t accu = 0;
        uint64_t count = 0;

        for (int core = 0; core < counters->nbcores; core++) {
            if (-1 == read(counters->counters[i][core], &count, sizeof(uint64_t))) {
                fprintf(stderr, "Cannot read result");
                exit(EXIT_FAILURE);
            }
            accu += count;
        }

        values[i] = accu;
    }
}






unsigned int init_counters(char *args, void **state)
{
    int nb_perf;
    int *perf_indexes = NULL;

    perf_event_list(args, &nb_perf, &perf_indexes);

    __u32 *perf_type;
    __u64 *perf_key;
    perf_type_key(&perf_type, &perf_key, perf_indexes, nb_perf);
    counter_t fd = _init_counters(nb_perf, perf_type, perf_key);
    free(perf_type);
    free(perf_key);

    fd->perf_indexes = perf_indexes;
    fd->counters_values = malloc(nb_perf * sizeof(uint64_t));
    fd->tmp_counters_values = malloc(nb_perf * sizeof(uint64_t));
    start_counters(fd);
    _get_counters(fd, fd->counters_values);
    *state = (void *) fd;

    return nb_perf;
}

unsigned int get_counters(uint64_t *results, void *ptr)
{
    counter_t state = (counter_t) ptr;

    _get_counters(state, state->tmp_counters_values);

    for (int i = 0; i < state->nbperf; i++) {
        results[i] = modulo_substraction(state->tmp_counters_values[i], state->counters_values[i]);
    }

    memcpy(state->counters_values, state->tmp_counters_values, state->nbperf * sizeof(uint64_t));
    return state->nbperf;
}

void label_counters(char **labels, void *ptr)
{
    counter_t state = (counter_t) ptr;

    for (int i = 0; i < state->nbperf; i++) {
        labels[i] = perf_static_info[state->perf_indexes[i]].name;
    }
}