diff --git a/Makefile b/Makefile
index 224d698fedcdb1135d80f62c6830772c66bc7863..f3b6d5b11e9fa797ba5a02f99f2bce02aa9eb5ab 100644
--- a/Makefile
+++ b/Makefile
@@ -121,13 +121,15 @@ LDSCRIPT= $(STARTUPLD)/STM32F411xE.ld
 
 # C sources that can be compiled in ARM or THUMB mode depending on the global
 # setting.
-CSRC = $(ALLCSRC)            \
-         $(SRCDIR)/crc32.c   \
-         $(SRCDIR)/main.c    \
-	 $(SRCDIR)/random.c  \
-	 $(SRCDIR)/serial.c  \
-	 $(SRCDIR)/usb.c     \
-	 $(SRCDIR)/tests.c
+CSRC = $(ALLCSRC)                      \
+         $(SRCDIR)/crc32.c             \
+         $(SRCDIR)/benchmarks.c        \
+         $(SRCDIR)/benchmarks/memory.c \
+         $(SRCDIR)/main.c              \
+	 $(SRCDIR)/random.c            \
+	 $(SRCDIR)/serial.c            \
+	 $(SRCDIR)/tests.c             \
+	 $(SRCDIR)/usb.c
 
 # C++ sources that can be compiled in ARM or THUMB mode depending on the global
 # setting.
diff --git a/src/benchmarks.c b/src/benchmarks.c
new file mode 100644
index 0000000000000000000000000000000000000000..549024721c4db8d58368ad35cdbd578b2efd2351
--- /dev/null
+++ b/src/benchmarks.c
@@ -0,0 +1,40 @@
+// This file is part of the execution-time evaluation for the qronos observer abstractions.
+// Copyright (C) 2022-2023  Tim Rheinfels  <tim.rheinfels@fau.de>
+// See https://gitlab.cs.fau.de/qronos-state-abstractions/execution-time
+//
+// 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 <https://www.gnu.org/licenses/>.
+
+///
+///  @file  benchmarks.c
+///
+///  @brief  Provides the implementation for running all execution time benchmarks
+///
+///  @author  Tim Rheinfels  <tim.rheinfels@fau.de>
+///
+
+#include "benchmarks.h"
+
+#include <benchmarks/campaign.h>
+
+void benchmarks_run(void)
+{
+
+    // Basic campaigns
+    BENCHMARKS_CAMPAIGN("overhead", {}, {}, {}, 10u, 10u);
+    BENCHMARKS_CAMPAIGN("chSysPolledDelayX_10", chSysPolledDelayX(10u), {}, {}, 10u, 10u);
+    BENCHMARKS_CAMPAIGN("chSysPolledDelayX_100", chSysPolledDelayX(100u), {}, {}, 10u, 10u);
+    BENCHMARKS_CAMPAIGN("chSysPolledDelayX_1000", chSysPolledDelayX(1000u), {}, {}, 10u, 10u);
+    BENCHMARKS_CAMPAIGN("chSysPolledDelayX_10000", chSysPolledDelayX(10000u), {}, {}, 10u, 10u);
+
+}
diff --git a/src/benchmarks.h b/src/benchmarks.h
new file mode 100644
index 0000000000000000000000000000000000000000..5da4fe9bfeda347dbb506ab6443525187286c43e
--- /dev/null
+++ b/src/benchmarks.h
@@ -0,0 +1,34 @@
+// This file is part of the execution-time evaluation for the qronos observer abstractions.
+// Copyright (C) 2022-2023  Tim Rheinfels  <tim.rheinfels@fau.de>
+// See https://gitlab.cs.fau.de/qronos-state-abstractions/execution-time
+//
+// 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 <https://www.gnu.org/licenses/>.
+
+///
+///  @file  benchmarks.h
+///
+///  @brief  Provides the interface for running all execution time benchmarks
+///
+///  @author  Tim Rheinfels  <tim.rheinfels@fau.de>
+///
+
+#ifndef BENCHMARKS_H
+#define BENCHMARKS_H
+
+///
+///  @brief  Runs all execution time benchmarks outputting the results via serial ove r USB
+///
+void benchmarks_run(void);
+
+#endif // BENCHMARKS_H
diff --git a/src/benchmarks/campaign.h b/src/benchmarks/campaign.h
new file mode 100644
index 0000000000000000000000000000000000000000..9c245adc57739bf680fdf48c20c1bb808489c9ab
--- /dev/null
+++ b/src/benchmarks/campaign.h
@@ -0,0 +1,125 @@
+// This file is part of the execution-time evaluation for the qronos observer abstractions.
+// Copyright (C) 2022-2023  Tim Rheinfels  <tim.rheinfels@fau.de>
+// See https://gitlab.cs.fau.de/qronos-state-abstractions/execution-time
+//
+// 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 <https://www.gnu.org/licenses/>.
+
+///
+///  @file  benchmarks/campaign.h
+///
+///  @brief  Provides the interface for execution time measurement campaigns
+///
+///  @author  Tim Rheinfels  <tim.rheinfels@fau.de>
+///
+
+#ifndef BENCHMARKS_CAMPAIGN_H
+#define BENCHMARKS_CAMPAIGN_H
+
+#include <ch.h>
+#include <hal.h>
+
+#include <serial.h>
+
+///
+///  @brief  Performs a single execution time measurement called @p name by counting the number of @p cycles the execution of @p func takes
+///
+///  @param[in]   name    Name of the measurement
+///  @param[out]  cycles  Variable of type rtcnt_t to store the measurement in
+///  @param[in]   func    Code to execute
+///
+#define _BENCHMARKS_MEASUREMENT(name, cycles, func) {    \
+        /* Disable interrupts */                         \
+        chSysDisable();                                  \
+        /* Flush caches */                               \
+        FLASH->ACR &= ~FLASH_ACR_DCEN;                   \
+        FLASH->ACR &= ~FLASH_ACR_ICEN;                   \
+        FLASH->ACR &= ~FLASH_ACR_PRFTEN;                 \
+        FLASH->ACR |= FLASH_ACR_DCRST;                   \
+        FLASH->ACR |= FLASH_ACR_ICRST;                   \
+        FLASH->ACR |= FLASH_ACR_DCEN;                    \
+        FLASH->ACR |= FLASH_ACR_ICEN;                    \
+        FLASH->ACR |= FLASH_ACR_PRFTEN;                  \
+        /* NOP slide for consistent pipeline state */    \
+        asm volatile("nop");                             \
+        asm volatile("nop");                             \
+        asm volatile("nop");                             \
+        asm volatile("nop");                             \
+        asm volatile("nop");                             \
+        asm volatile("nop");                             \
+        asm volatile("nop");                             \
+        asm volatile("nop");                             \
+        asm volatile("nop");                             \
+        asm volatile("nop");                             \
+        /* Get start time */                             \
+        rtcnt_t start = chSysGetRealtimeCounterX();      \
+        /* Just a label for inspecting disassembly */    \
+        asm volatile(".in_et_" name ":");                \
+        /* Run actual code */                            \
+        (void) (func);                                   \
+        /* Another label marking the end */              \
+        asm volatile(".out_et_" name ":");               \
+        /* Get end time */                               \
+        rtcnt_t end = chSysGetRealtimeCounterX();        \
+        /* Reenable interrupts */                        \
+        chSysEnable();                                   \
+        /* Store measurement */                          \
+        (cycles) = end - start;                          \
+    }
+
+///
+///  @brief  Runs the execution time campaign called @p name calling @p func
+///
+///  @param[in]  name      Campaign's name
+///  @param[in]  func      Code to measure
+///  @param[in]  setup     Code called before all @p N tests
+///  @param[in]  teardown  Code called after all @p N tests
+///  @param[in]  N         Number of tests to run
+///  @param[in]  M         Number of repetitions per test
+///
+#define BENCHMARKS_CAMPAIGN(name, func, setup, teardown, N, M) {  \
+        serial_printf("{\n");                                     \
+        serial_printf("  \"name\": \"%s\",\n", (name));           \
+        serial_printf("  \"test_count\": %u,\n", (N));            \
+        serial_printf("  \"repetition_count\": %u,\n", (M));      \
+        serial_printf("  \"tests\": [\n");                        \
+        for(size_t i = 0u; i < (N); ++i) {                        \
+            serial_printf("    {\n");                             \
+            serial_printf("    \"setup\": {\n");                  \
+            (setup);                                              \
+            serial_printf("    },\n");                            \
+            serial_printf("    \"repetitions\": [");              \
+            for(size_t j = 0u; j < (M); ++j) {                    \
+                rtcnt_t cycles = (rtcnt_t) -1;                    \
+                _BENCHMARKS_MEASUREMENT(name, cycles, (func));    \
+                if(cycles == (rtcnt_t) -1) {                      \
+                    serial_printf("null");                        \
+                } else {                                          \
+                    serial_printf("%u", cycles);                  \
+                }                                                 \
+                if(j < (M)-1u) {                                  \
+                    serial_printf(", ");                          \
+                } else {                                          \
+                    serial_printf("],\n");                        \
+                }                                                 \
+            }                                                     \
+            serial_printf("    \"teardown\": {\n");               \
+            (teardown);                                           \
+            serial_printf("    },\n");                            \
+            serial_printf("  },\n");                              \
+        }                                                         \
+        serial_printf("  ],\n");                                  \
+        serial_printf("},\n");                                    \
+    }
+
+#endif // BENCHMARKS_CAMPAIGN_H
diff --git a/src/benchmarks/memory.c b/src/benchmarks/memory.c
new file mode 100644
index 0000000000000000000000000000000000000000..7df4b0246f9d1222571011e95128e7e8144043ae
--- /dev/null
+++ b/src/benchmarks/memory.c
@@ -0,0 +1,69 @@
+// This file is part of the execution-time evaluation for the qronos observer abstractions.
+// Copyright (C) 2022-2023  Tim Rheinfels  <tim.rheinfels@fau.de>
+// See https://gitlab.cs.fau.de/qronos-state-abstractions/execution-time
+//
+// 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 <https://www.gnu.org/licenses/>.
+
+///
+///  @file  benchmarks/memory.c
+///
+///  @brief  Provides the implementation for accessing the statically allocated memory for all execution time measurements
+///
+///  @author  Tim Rheinfels  <tim.rheinfels@fau.de>
+///
+
+#include "memory.h"
+
+#include <stdint.h>
+#include <string.h>
+
+///
+///  @brief  Size of the padding in bytes used for checking memory violations
+///
+#define PADDING 16u
+
+///
+///  @brief  Computes the maximum of the operands @p a and @p b
+///
+///  @param[in]  a  First operand
+///  @param[in]  b  Second operand
+///
+///  @returns  Maximum of @p a and @p b
+///
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+///
+///  @brief  Actual benchmark memory
+///
+static float work[2u * PADDING];
+
+float * const benchmarks_memory = work + PADDING;
+
+void benchmarks_memory_init(void)
+{
+    memset(work, 0xA5, sizeof(work));
+}
+
+void benchmarks_memory_check(void)
+{
+    const uint8_t *p1 = (const uint8_t *) work;
+    const uint8_t *p2 = ((const uint8_t *) work) + sizeof(work) - PADDING * sizeof(float);
+    for(size_t i = 0u; i < PADDING; ++i)
+    {
+        if(*(p1++) != 0xA5u || *(p2++) != 0xA5u)
+        {
+            while(1);
+        }
+    }
+}
diff --git a/src/benchmarks/memory.h b/src/benchmarks/memory.h
new file mode 100644
index 0000000000000000000000000000000000000000..945427a8c1a573d03177a6623fe27a433d4e00ee
--- /dev/null
+++ b/src/benchmarks/memory.h
@@ -0,0 +1,49 @@
+// This file is part of the execution-time evaluation for the qronos observer abstractions.
+// Copyright (C) 2022-2023  Tim Rheinfels  <tim.rheinfels@fau.de>
+// See https://gitlab.cs.fau.de/qronos-state-abstractions/execution-time
+//
+// 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 <https://www.gnu.org/licenses/>.
+
+///
+///  @file  benchmarks/memory.h
+///
+///  @brief  Provides the interface for accessing the statically allocated memory for all execution time measurements
+///
+///  @author  Tim Rheinfels  <tim.rheinfels@fau.de>
+///
+
+#ifndef BENCHMARKS_MEMORY_H
+#define BENCHMARKS_MEMORY_H
+
+///
+///  @brief  Maximum number of measurement outputs for all experiments
+///
+#define N_Y_MAX 60u
+
+///
+///  @brief  Pointer to the benchmark working area
+///
+extern float * const benchmarks_memory;
+
+///
+///  @brief  Sets up sufficient memory space for running all execution time benchmarks individually
+///
+void benchmarks_memory_init(void);
+
+///
+///  @brief  Checks that the benchmarks did not use more space than allocated in @ref memory.c
+///
+void benchmarks_memory_check(void);
+
+#endif // BENCHMARKS_MEMORY_H
diff --git a/src/main.c b/src/main.c
index aa02838256b61279fbe44743d44e17ea2fc94071..0781937dd647657d7d9ea7097b277e4ae4a8cafa 100644
--- a/src/main.c
+++ b/src/main.c
@@ -29,6 +29,8 @@
 #include <ch.h>
 #include <hal.h>
 
+#include <benchmarks.h>
+#include <benchmarks/memory.h>
 #include <config.h>
 #include <crc32.h>
 #include <linalg.h>
@@ -55,6 +57,9 @@ static THD_FUNCTION(benchmark_entry, arg)
     usb_init();
     serial_init();
 
+    // Colour memory region for tests
+    benchmarks_memory_init();
+
     // Wait for active USB connection
     while(!usb_active())
     {
@@ -95,6 +100,14 @@ static THD_FUNCTION(benchmark_entry, arg)
         goto end;
     }
 
+    // Perform execution time measurements
+    serial_printf("  \"execution_time_measurements\": [\n");
+    benchmarks_run();
+    serial_printf("  ],\n");
+
+    // Check if memory region was exceeded
+    benchmarks_memory_check();
+
     // We're done -> Clean up and wait forever
 end:
     serial_printf("}\n");