/*
* Copyright (c) 2014 Remy Noel.
* Copyright (c) 2014 Richard Braun.
*
* This program 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.
*
* This program 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 this program. If not, see .
*
*
* Here, we test the perfmon module for cross CPU performances monitoring.
*/
#include
#include
#include
#include
#include
#include
#include
#define WAIT_DELAY_USEC 1000000
static volatile bool stop;
static void
test_do_nothing(void* arg)
{
(void)arg;
while (!stop);
}
static void
test_report_event(const struct perfmon_event *event, const char *name)
{
unsigned long long count;
count = perfmon_event_read(event);
printf("test: %s: %llu\n", name, count);
}
static uint64_t
test_get_pre_overflow_value(uint64_t value)
{
uint64_t pmc_max;
unsigned int pmc_width;
pmc_width = perfmon_get_pmc_width();
pmc_max = (1ULL << pmc_width) - 1;
pmc_max &= 0xffffffff80000000;
/* XXX: workaround most processor not allowing full width writes */
return ((~value + 1) & 0x7fffffff) | pmc_max;
}
static void
test_run(void *arg)
{
struct perfmon_event *ev_cycle, *ev_instruction;
struct perfmon_group *group;
int error;
uint64_t value;
(void)arg;
error = perfmon_group_create(&group);
error_check(error, "perfmon_group_create");
error = perfmon_event_create(&ev_cycle, PERFMON_ET_GENERIC,
PERFMON_EV_CYCLE, PERFMON_EF_KERN);
error_check(error, "perfmon_event_create");
perfmon_group_add(group, ev_cycle);
error = perfmon_event_create(&ev_instruction, PERFMON_ET_GENERIC,
PERFMON_EV_INSTRUCTION, PERFMON_EF_KERN);
error_check(error, "perfmon_event_create");
perfmon_group_add(group, ev_instruction);
error = perfmon_group_attach_cpu(group, 1);
error_check(error, "perfmon_group_attach_cpu 1");
error = perfmon_group_start(group);
error_check(error, "perfmon_group_start");
cpu_delay(WAIT_DELAY_USEC);
error = perfmon_group_stop(group);
error_check(error, "perfmon_group_stop");
test_report_event(ev_cycle, "cycle");
test_report_event(ev_instruction, "instruction");
printf("checking with overflow ...\n");
value = test_get_pre_overflow_value( perfmon_event_read(ev_cycle) / 2);
error = perfmon_event_write(ev_cycle, value);
error_check(error, "perfmon_event_write");
value = test_get_pre_overflow_value(perfmon_event_read(ev_instruction) / 3);
error = perfmon_event_write(ev_instruction, value);
error_check(error, "perfmon_event_write");
perfmon_event_reset(ev_cycle);
perfmon_event_reset(ev_instruction);
error = perfmon_group_start(group);
error_check(error, "perfmon_group_start");
cpu_delay(WAIT_DELAY_USEC);
error = perfmon_group_stop(group);
error_check(error, "perfmon_group_stop");
test_report_event(ev_cycle, "cycle");
test_report_event(ev_instruction, "instruction");
error = perfmon_group_detach(group);
error_check(error, "perfmon_group_detach");
error = perfmon_group_destroy(group);
error_check(error, "perfmon_group_destroy");
stop = true;
}
void
test_setup(void)
{
struct thread_attr attr;
struct thread *thread0, *thread1;
struct cpumap *cpumap;
int error;
error = cpumap_create(&cpumap);
error_check(error, "cpumap_create 0");
cpumap_zero(cpumap);
cpumap_set(cpumap, 0);
thread_attr_init(&attr, "x15_test_run");
thread_attr_set_detached(&attr);
thread_attr_set_cpumap(&attr, cpumap);
error = thread_create(&thread0, &attr, test_run, NULL);
error_check(error, "thread_create 0");
cpumap_zero(cpumap);
cpumap_set(cpumap, 1);
thread_attr_init(&attr, "x15_test_do_nothing");
thread_attr_set_detached(&attr);
thread_attr_set_cpumap(&attr, cpumap);
error = thread_create(&thread1, &attr, test_do_nothing, NULL);
error_check(error, "thread_create 1");
}