/* * 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"); }