diff --git a/repos/mml/run/hpc_test.run b/repos/mml/run/hpc_test.run
new file mode 100644
index 0000000000..11e9f26d63
--- /dev/null
+++ b/repos/mml/run/hpc_test.run
@@ -0,0 +1,80 @@
+set build_components {
+ core init timer app/hpc_test
+}
+
+source ${genode_dir}/repos/base/run/platform_drv.inc
+append_platform_drv_build_components
+
+build $build_components
+
+create_boot_directory
+
+set config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+append config {
+
+
+
+
+ 2022-07-20 14:30
+
+
+
+
+
+
+
+
+
+
+
+ 2022-07-20 14:30
+
+
+
+
+
+
+
+
+}
+
+install_config $config
+
+set boot_modules {
+ core init timer vfs.lib.so ld.lib.so posix.lib.so libc.lib.so libm.lib.so stdcxx.lib.so hpc_test
+}
+
+append_platform_drv_boot_modules
+
+build_boot_image $boot_modules
+append qemu_args "-nographic "
+
+run_genode_until forever
\ No newline at end of file
diff --git a/repos/mml/src/app/hpc_test/main.cc b/repos/mml/src/app/hpc_test/main.cc
new file mode 100644
index 0000000000..c23f10d69e
--- /dev/null
+++ b/repos/mml/src/app/hpc_test/main.cc
@@ -0,0 +1,89 @@
+/**
+ * @file main.cc
+ * @author Michael Müller (michael.mueller@uos.de)
+ * @brief Some test for programing hardware performance counters in NOVA
+ * @version 0.1
+ * @date 2022-12-14
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+int main(void)
+{
+ Nova::mword_t event = 0x26;
+ Nova::mword_t mask = 0x00;
+ Nova::mword_t flags = 0x70000;
+ Nova::uint8_t rc;
+
+ if ((rc = Nova::hpc_ctrl(Nova::HPC_SETUP, 0, 1, event, mask, flags)) != Nova::NOVA_OK) {
+ std::cerr << "Failed to setup performance counter 0" << std::endl;
+ return -1;
+ }
+
+ std::cout << "Counter 0 setup" << std::endl;
+ event = 0x60;
+ mask = 0xfe;
+ if ((rc = Nova::hpc_ctrl(Nova::HPC_SETUP, 1, 1, event, mask, flags)) != Nova::NOVA_OK)
+ {
+ std::cerr << "Failed to setup performance counter 1, rc = " << static_cast(rc) << std::endl;
+ return -1;
+ }
+
+ event = 0x62;
+ mask = 0x1;
+ if ((rc = Nova::hpc_ctrl(Nova::HPC_SETUP, 2, 1, event, mask, flags)) != Nova::NOVA_OK)
+ {
+ std::cerr << "Failed to setup performance counter 2, rc = " << static_cast(rc) << std::endl;
+ return -1;
+ }
+ if ((rc = Nova::hpc_start(0, 1)) != Nova::NOVA_OK) {
+ std::cerr << "Failed to start counter 0" << std::endl;
+ return -2;
+ }
+
+ if ((rc = Nova::hpc_start(1, 1)) != Nova::NOVA_OK) {
+ std::cerr << "Failed to start counter 0" << std::endl;
+ return -2;
+ }
+
+ if ((rc = Nova::hpc_start(2, 1)) != Nova::NOVA_OK) {
+ std::cerr << "Failed to start counter 0" << std::endl;
+ return -2;
+ }
+
+ for (;;) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(2000));
+ Nova::mword_t count = 0;
+
+ _mm_clflush(&count);
+ if ((rc = Nova::hpc_read(0, 1, count)) != Nova::NOVA_OK)
+ {
+ std::cerr << "Failed to read counter 0" << std::endl;
+ }
+ std::cout << count << " cache line flushes" << std::endl;
+
+ Nova::mword_t latency = 0;
+ if ((rc = Nova::hpc_read(2, 1, latency)) != Nova::NOVA_OK)
+ {
+ std::cerr << "Failed to read counter 1" << std::endl;
+ }
+ Nova::mword_t l2_requests = 0;
+ if ((rc = Nova::hpc_read(1, 1, l2_requests)) != Nova::NOVA_OK)
+ {
+ std::cerr << "Failed to read counter 1" << std::endl;
+ }
+ count = (latency * 4) / l2_requests;
+ std::cout << "L2 latency:" << count << " cycles" << std::endl;
+ }
+
+ return 0;
+}
diff --git a/repos/mml/src/app/hpc_test/target.mk b/repos/mml/src/app/hpc_test/target.mk
new file mode 100644
index 0000000000..0d72ae45a4
--- /dev/null
+++ b/repos/mml/src/app/hpc_test/target.mk
@@ -0,0 +1,5 @@
+TARGET = hpc_test
+SRC_CC = trace_pfc.cc
+LIBS += base posix libm libc stdcxx
+CC_OPT += -Wno-error -Wno-permissive -fpermissive -Wno-error=conversion
+
diff --git a/repos/mml/src/app/hpc_test/trace_pfc.cc b/repos/mml/src/app/hpc_test/trace_pfc.cc
new file mode 100644
index 0000000000..15fa27beb0
--- /dev/null
+++ b/repos/mml/src/app/hpc_test/trace_pfc.cc
@@ -0,0 +1,105 @@
+/**
+ * @file trace_pfc.cc
+ * @author Michael Müller (michael.mueller@uos.de)
+ * @brief Tests for Genode wrappers around Performance counter syscalls in NOVA
+ * @version 0.1
+ * @date 2022-12-15
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+
+using namespace Genode;
+
+int main(void)
+{
+ Trace::Performance_counter::Counter ctr_clflush, ctr_l2_latency, ctr_l2_requests, /*ctr_l3_miss,*/ ctr_l2_prefetch;
+
+ try {
+ ctr_clflush = Trace::Performance_counter::alloc_core();
+ ctr_l2_latency = Trace::Performance_counter::alloc_core();
+ ctr_l2_requests = Trace::Performance_counter::alloc_core();
+ ctr_l2_prefetch = Trace::Performance_counter::acquire(Trace::Performance_counter::Type::CORE);
+ // ctr_l3_miss = Trace::Performance_counter::alloc_cbo();
+ }
+ catch (Trace::Pfc_no_avail)
+ {
+ std::cout << "Unable to allocate performance counters." << std::endl;
+ return -1;
+ }
+
+ std::cout << "Performance counter allocation successful." << std::endl;
+
+ try {
+ Trace::Performance_counter::setup(ctr_clflush, 0x26, 0x00, 0x70000);
+ Trace::Performance_counter::setup(ctr_l2_latency, 0x62, 0x01, 0x30000);
+ Trace::Performance_counter::setup(ctr_l2_requests, 0x60, 0xfe, 0x30000);
+ Trace::Performance_counter::setup(ctr_l2_prefetch, 0xc0, 0x00, 0x30000);
+ //Trace::Performance_counter::setup(ctr_l3_miss, 0x6, 0xff, 0x550f000000000000);
+ } catch (Trace::Pfc_access_error &e) {
+ std::cerr << "PFC access failed. rc=" << e.error_code() << std::endl;
+ return -1;
+ }
+
+ std::cout << "Performance counters successfully set up." << std::endl;
+
+ try {
+ Trace::Performance_counter::start(ctr_clflush);
+ Trace::Performance_counter::start(ctr_l2_latency);
+ Trace::Performance_counter::start(ctr_l2_requests);
+ Trace::Performance_counter::start(ctr_l2_prefetch);
+ //Trace::Performance_counter::start(ctr_l3_miss);
+ } catch (Trace::Pfc_access_error &e) {
+ std::cerr << "PFC access failed. rc=" << e.error_code() << std::endl;
+ return -1;
+ }
+
+ std::cout << "Performance counters started." << std::endl;
+
+ for (;;) {
+ Genode::uint64_t clflushes, latency, requests, /*l3_misses,*/ l2_prefetches;
+ clflushes = latency = requests = l2_prefetches = 0;
+
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+ _mm_clflush(&clflushes);
+ _mm_clflush(&clflushes);
+
+ try {
+ clflushes = Trace::Performance_counter::read(ctr_clflush);
+ latency = Trace::Performance_counter::read(ctr_l2_latency);
+ requests = Trace::Performance_counter::read(ctr_l2_requests);
+ l2_prefetches = Trace::Performance_counter::read(ctr_l2_prefetch);
+ //l3_misses = Trace::Performance_counter::read(ctr_l3_miss);
+ } catch (Trace::Pfc_access_error &e) {
+ std::cerr << "PFC access failed. rc=" << e.error_code() << std::endl;
+ return 1;
+ }
+
+ std::cout << clflushes << " cache line flushes." << std::endl;
+ //std::cout << "L2 latency: " << (latency * 4) / requests << " cycles." << std::endl;
+ std::cout << l2_prefetches << " L2 prefetch requests." << std::endl;
+ /*
+ try {
+ Trace::Performance_counter::stop(ctr_l2_prefetch);
+ Trace::Performance_counter::reset(ctr_l2_prefetch, 0xdeadbeef);
+ Trace::Performance_counter::start(ctr_l2_prefetch);
+ std::cout << Trace::Performance_counter::read(ctr_l2_prefetch) << " L2 prefetches after context-switch" << std::endl;
+ Trace::Performance_counter::stop(ctr_l2_prefetch);
+ Trace::Performance_counter::reset(ctr_l2_prefetch, l2_prefetches);
+ Trace::Performance_counter::start(ctr_l2_prefetch);
+ } catch (Trace::Pfc_access_error &e) {
+ std::cerr << "PFC access failed. rc=" << e.error_code() << std::endl;
+ }
+*/
+ // std::cout << l3_misses << " L3 misses" << std::endl;
+ }
+
+ return 0;
+}
\ No newline at end of file