diff --git a/emper/Context.hpp b/emper/Context.hpp
index f0482de4edd84e3a9c67d461ab25b6cfc836f01d..b6424faedb70dac35daa7adb6dbfeacf3636ca45 100644
--- a/emper/Context.hpp
+++ b/emper/Context.hpp
@@ -30,11 +30,12 @@ extern "C" void save_and_switch_context(void** toTos, void** fromTos);
 extern "C" [[noreturn]] void switch_context(void** toTos);
 
 class EMPER_CONTEXT_ALIGNAS Context : Logger<LogSubsystem::C> {
- private:
+ public:
 	static constexpr size_t PAGE_SIZE = emper::ASSUME_PAGE_SIZE;
 
 	static constexpr size_t CONTEXT_SIZE = em::roundUp(emper::MIN_CONTEXT_STACK_SIZE, PAGE_SIZE);
 
+ private:
 	static thread_local Context* currentContext;
 
 	AbstractFiber* currentFiber = nullptr;
diff --git a/emper/Emper.cpp b/emper/Emper.cpp
index 72a6d51cce512eef653a10714743d06dd8b99786..a508a0ed8253089fc756104d900cd341e24140d4 100644
--- a/emper/Emper.cpp
+++ b/emper/Emper.cpp
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: LGPL-3.0-or-later
-// Copyright © 2020-2021 Florian Schmaus
+// Copyright © 2020-2022 Florian Schmaus
 #include "Emper.hpp"
 
 #include <cassert>
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "Common.hpp"
+#include "Context.hpp"
 #include "Fiber.hpp"
 #include "Runtime.hpp"
 #include "emper-common.h"
@@ -16,6 +17,9 @@
 #include "emper.hpp"
 #include "io/Future.hpp"
 #include "lib/LinuxVersion.hpp"
+#include "lib/util.hpp"
+
+namespace eu = emper::lib::util;
 
 void async(Fiber* fiber) {
 	assert(fiber != nullptr);
@@ -45,6 +49,14 @@ void async(const Fiber::fiber_fun0_t& function, workeraffinity_t* affinity) {
 
 namespace emper {
 
+void printInfo(std::ostream strm) {
+	// clang-format: off
+	strm << "Extensible Massive-Parallelism Execution Realm (EMPER)" << std::endl
+			 << "Version: " << getFullVersion() << std::endl
+			 << "Context Size: " << eu::bytesToHumanReadableString(Context::CONTEXT_SIZE) << std::endl;
+	// clang-format: on
+}
+
 const bool IO_MUST_INVALIDATE_BROKEN_CHAIN = EMPER_LINUX_LT("5.15.0");
 
 auto getFullVersion() -> std::string { return EMPER_FULL_VERSION; }
diff --git a/emper/Emper.hpp b/emper/Emper.hpp
index 960a7d5963d5c95fe3bc69e13035b9124e065610..1add14fc78b50c24aab57f91ff505e7557d16e34 100644
--- a/emper/Emper.hpp
+++ b/emper/Emper.hpp
@@ -1,9 +1,10 @@
 // SPDX-License-Identifier: LGPL-3.0-or-later
-// Copyright © 2020-2021 Florian Schmaus
+// Copyright © 2020-2022 Florian Schmaus
 #pragma once
 
 #include <cassert>
 #include <cstddef>
+#include <iostream>
 #include <string>
 
 #include "Worker.hpp"
@@ -19,6 +20,8 @@ struct Emper {
 constexpr auto assertInRuntime = Emper::assertInRuntime;
 constexpr auto inRuntime = Emper::inRuntime;
 
+void printInfo(std::ostream& strm = std::cout);
+
 static const size_t WS_VICTIM_COUNT = EMPER_WS_VICTIM_COUNT;
 static const size_t WS_VICTIM_DENOMINATOR = EMPER_WS_VICTIM_DENOMINATOR;
 
diff --git a/emper/lib/meson.build b/emper/lib/meson.build
index e59bfa43c5742beb9d27d5f1fed7eb659fb7e46f..0fd7650423bd2f515dec7203102b84dd053c4ed1 100644
--- a/emper/lib/meson.build
+++ b/emper/lib/meson.build
@@ -1,6 +1,7 @@
 emper_cpp_sources += files(
   'DebugUtil.cpp',
   'LinuxVersion.cpp',
+  'util.cpp',
 )
 
 subdir('sync')
diff --git a/emper/lib/template_util.hpp b/emper/lib/template_util.hpp
index 830b1745ca3beed9daae91730fe9761b3e564efd..a3c04f803a06ffbcb292db2eaf64a55e4ecc6b54 100644
--- a/emper/lib/template_util.hpp
+++ b/emper/lib/template_util.hpp
@@ -1,6 +1,11 @@
 // SPDX-License-Identifier: LGPL-3.0-or-later
-// Copyright © 2020 Florian Schmaus
+// Copyright © 2020-2022 Florian Schmaus
+#pragma once
+
 #include <cstddef>
+#include <utility>
+
+#include "Common.hpp"
 
 namespace emper::lib::template_util {
 
@@ -13,4 +18,18 @@ auto getSize(T& t) -> size_t {
 	return size * value_type_size;
 }
 
+template <typename T, std::enable_if_t<std::is_integral<T>::value, bool> = true>
+std::pair<T, std::string> toHumanReadableBytes(T bytes) {
+	// TODO: Ideally the std::string would be const.
+	const static std::vector<std::string> SI_BYTES = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"};
+
+	for (auto unit : SI_BYTES) {
+		if (bytes < 1024) return std::make_pair(bytes, unit);
+
+		bytes >>= 10;
+	}
+
+	DIE;
+}
+
 }	 // namespace emper::lib::template_util
diff --git a/emper/lib/util.cpp b/emper/lib/util.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..935750231356abe227cfd3e0674eaf4080e52187
--- /dev/null
+++ b/emper/lib/util.cpp
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: LGPL-3.0-or-later
+// Copyright © 2022 Florian Schmaus
+#include "lib/util.hpp"
+
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include "lib/template_util.hpp"
+
+namespace tu = emper::lib::template_util;
+
+namespace emper::lib::util {
+
+auto bytesToHumanReadableString(uintptr_t bytes) -> std::string {
+	auto res = tu::toHumanReadableBytes(bytes);
+
+	std::stringstream sstrm;
+	sstrm << res.first << " " << res.second << " (" << bytes << " B)";
+	return sstrm.str();
+}
+
+}	 // namespace emper::lib::util
diff --git a/emper/lib/util.hpp b/emper/lib/util.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..7be7de4c30c516491ff2414c17c59d18f73e1482
--- /dev/null
+++ b/emper/lib/util.hpp
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: LGPL-3.0-or-later
+// Copyright © 2022 Florian Schmaus
+#pragma once
+
+#include <cstdint>
+#include <string>
+
+namespace emper::lib::util {
+
+auto bytesToHumanReadableString(uintptr_t bytes) -> std::string;
+
+}
diff --git a/tests/lib/TemplateUtilTest.cpp b/tests/lib/TemplateUtilTest.cpp
index 87698495bc4a710d5ea06b1d52abf5840f1ec089..17a59ae2b0974927d96022206cc15c01e6863dd8 100644
--- a/tests/lib/TemplateUtilTest.cpp
+++ b/tests/lib/TemplateUtilTest.cpp
@@ -1,11 +1,12 @@
 // SPDX-License-Identifier: LGPL-3.0-or-later
-// Copyright © 2021 Florian Schmaus
+// Copyright © 2021-2022 Florian Schmaus
 #include <gtest/gtest.h>
 
 #include <array>
 #include <cstddef>
 #include <cstdint>
-#include <memory>
+#include <utility>
+#include <vector>
 
 #include "lib/template_util.hpp"
 
@@ -30,3 +31,18 @@ TEST(getSize, simple_uint32_t) {
 	std::array<uint32_t, elements> array;
 	test_getSize(array, elements * 4);
 }
+
+// NOLINTNEXTLINE(modernize-use-trailing-return-type)
+TEST(toHumandReadableBytes, simple) {
+	auto res = tu::toHumanReadableBytes(42);
+	ASSERT_EQ(res.first, 42);
+	ASSERT_EQ(res.second, "B");
+
+	res = tu::toHumanReadableBytes(1024);
+	ASSERT_EQ(res.first, 1);
+	ASSERT_EQ(res.second, "KiB");
+
+	res = tu::toHumanReadableBytes(2049);
+	ASSERT_EQ(res.first, 2);
+	ASSERT_EQ(res.second, "KiB");
+}
diff --git a/tests/lib/UtilTest.cpp b/tests/lib/UtilTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c1a1210f21f127f82f228e6d3ebeb6600e8f40cf
--- /dev/null
+++ b/tests/lib/UtilTest.cpp
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: LGPL-3.0-or-later
+// Copyright © 2022 Florian Schmaus
+#include <gtest/gtest.h>
+
+#include <memory>
+
+#include "lib/util.hpp"
+
+// NOLINTNEXTLINE(modernize-use-trailing-return-type)
+TEST(bytesToHumanReadableString, simple) {
+	constexpr auto toHrStr = emper::lib::util::bytesToHumanReadableString;
+
+	EXPECT_EQ(toHrStr(1024), "1 KiB (1024 B)");
+	EXPECT_EQ(toHrStr(1025), "1 KiB (1025 B)");
+	EXPECT_EQ(toHrStr(65536), "64 KiB (65536 B)");
+	EXPECT_EQ(toHrStr(65552), "64 KiB (65552 B)");
+}
diff --git a/tests/lib/meson.build b/tests/lib/meson.build
index 1bba5e4047080b36fe6547b7d3ddfabc9babd718..d2835bbeafdd33cd3d48d346251a5bc14f46291a 100644
--- a/tests/lib/meson.build
+++ b/tests/lib/meson.build
@@ -21,4 +21,12 @@ tests += [
 		'gtest': true,
 		'is_parallel': true,
 	},
+
+	{
+		'source': files('UtilTest.cpp'),
+		'name': 'UtilTest',
+		'description': 'Tests EMPER\'s util.hpp',
+		'gtest': true,
+		'is_parallel': true,
+	},
 ]