From ca5bcf5c5945dc298a29c59abd446e4b5505db4f Mon Sep 17 00:00:00 2001
From: Florian Schmaus <flow@cs.fau.de>
Date: Tue, 22 Feb 2022 18:43:02 +0100
Subject: [PATCH] [apps]: Modernize 'fib' app

---
 apps/FibChildStealing.cpp | 122 ++++++++++++++++++++++++++++++++++++++
 apps/Main.cpp             |  90 ----------------------------
 apps/fsearch/meson.build  |  14 -----
 apps/meson.build          |  28 +++++++--
 iwyu-mappings.imp         |   1 +
 5 files changed, 145 insertions(+), 110 deletions(-)
 create mode 100644 apps/FibChildStealing.cpp
 delete mode 100644 apps/Main.cpp

diff --git a/apps/FibChildStealing.cpp b/apps/FibChildStealing.cpp
new file mode 100644
index 00000000..d4aad54b
--- /dev/null
+++ b/apps/FibChildStealing.cpp
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: LGPL-3.0-or-later
+// Copyright © 2020-2022 Florian Schmaus
+#include <boost/program_options.hpp>
+#include <cstdint>
+#include <iostream>	 // for basic_ostream::operator<<
+#include <memory>
+#include <thread>
+
+#include "BinaryPrivateSemaphore.hpp"		 // for BPS
+#include "CountingPrivateSemaphore.hpp"	 // for CPS
+#include "Debug.hpp"										 // for DBG
+#include "Fiber.hpp"										 // for Fiber
+#include "PrivateSemaphore.hpp"					 // for PS
+#include "Runtime.hpp"									 // for Runtime
+#include "lib/sync/Semaphore.hpp"
+
+namespace po = boost::program_options;
+
+using fibParams = struct {
+	uint64_t n;
+	uint64_t* result;
+	PS* sem;
+};
+
+static void fib(void* voidParams) {
+	auto* params = static_cast<fibParams*>(voidParams);
+	uint64_t n = params->n;
+	auto* result = params->result;
+	PS* sem = params->sem;
+
+	if (n < 2) {
+		*result = n;
+	} else {
+		CPS newSem(2);
+
+		uint64_t a, b;
+
+		fibParams newParams1;
+		newParams1.n = n - 1;
+		newParams1.result = &a;
+		newParams1.sem = &newSem;
+
+		// Note that this is the inefficient spawn/sync variant, we
+		// usually would compute one previous fib number without spawning.
+		fibParams newParams2;
+		newParams2.n = n - 2;
+		newParams2.result = &b;
+		newParams2.sem = &newSem;
+
+		Fiber* f1 = Fiber::from(&fib, &newParams1);
+		Fiber* f2 = Fiber::from(&fib, &newParams2);
+
+		Runtime* runtime = Runtime::getRuntime();
+		runtime->schedule(*f1);
+		runtime->schedule(*f2);
+
+		DBG("fib: Calling wait for n=" << n);
+		newSem.wait();
+
+		*result = a + b;
+	}
+
+	DBG("fib: Calling signalAndExit for n=" << n);
+	sem->signalAndExit();
+}
+
+// NOLINTNEXTLINE(bugprone-exception-escape)
+auto main(int argc, char* argv[]) -> int {
+	uint64_t fibNum = -1;
+	po::options_description desc("Allowed options");
+	// clang-format off
+	desc.add_options()
+		("help", "Show help")
+		("nthreads", po::value<unsigned int>()->default_value(std::thread::hardware_concurrency()), "Number of worker threads used by EMPER's runtime system")
+		("fibnum", po::value<uint64_t>(&fibNum)->default_value(12), "The Fibonacci number to compute")
+		;
+	// clang-format on
+
+	// Make 'fibnum' a positional option.
+	po::positional_options_description pos_desc;
+	pos_desc.add("fibnum", -1);
+
+	// clang-format off
+	auto parse_result = po::command_line_parser(argc, argv)
+		.options(desc)
+		.positional(pos_desc)
+		.run()
+		;
+	// clang-format on
+
+	po::variables_map vm;
+	po::store(parse_result, vm);
+	po::notify(vm);
+
+	const unsigned nthreads = vm["nthreads"].as<unsigned int>();
+
+	std::cout << "Number of threads: " << nthreads << std::endl;
+
+	Runtime runtime(nthreads);
+
+	emper::lib::sync::Semaphore semaphore;
+
+	Fiber* fibFiber = Fiber::from([&] {
+		uint64_t result;
+		BPS sem;
+		fibParams params = {fibNum, &result, &sem};
+
+		fib(&params);
+
+		sem.wait();
+
+		std::cout << "fib(" << fibNum << ") = " << result << std::endl;
+
+		semaphore.notify();
+	});
+
+	runtime.scheduleFromAnywhere(*fibFiber);
+
+	semaphore.wait();
+
+	return 0;
+}
diff --git a/apps/Main.cpp b/apps/Main.cpp
deleted file mode 100644
index b2df11bd..00000000
--- a/apps/Main.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-// SPDX-License-Identifier: LGPL-3.0-or-later
-// Copyright © 2020 Florian Schmaus
-#include <cstdlib>	 // for exit, EXIT_SUCCESS
-#include <iostream>	 // for basic_ostream::operator<<
-
-#include "BinaryPrivateSemaphore.hpp"		 // for BPS
-#include "CountingPrivateSemaphore.hpp"	 // for CPS
-#include "Debug.hpp"										 // for DBG
-#include "Fiber.hpp"										 // for Fiber
-#include "PrivateSemaphore.hpp"					 // for PS
-#include "Runtime.hpp"									 // for Runtime
-#include "emper-common.h"								 // for UNUSED_ARG
-
-using fibParams = struct {
-	int n;
-	int* result;
-	PS* sem;
-};
-
-static void fib(void* voidParams) {
-	auto* params = static_cast<fibParams*>(voidParams);
-	int n = params->n;
-	int* result = params->result;
-	PS* sem = params->sem;
-
-	if (n < 2) {
-		*result = n;
-	} else {
-		CPS newSem(2);
-
-		int a, b;
-
-		fibParams newParams1;
-		newParams1.n = n - 1;
-		newParams1.result = &a;
-		newParams1.sem = &newSem;
-		fibParams newParams2;
-		newParams2.n = n - 2;
-		newParams2.result = &b;
-		newParams2.sem = &newSem;
-
-		Fiber* f1 = Fiber::from(&fib, &newParams1);
-		Fiber* f2 = Fiber::from(&fib, &newParams2);
-
-		Runtime* runtime = Runtime::getRuntime();
-		runtime->schedule(*f1);
-		runtime->schedule(*f2);
-
-		DBG("fib: Calling wait for n=" << n);
-		newSem.wait();
-
-		*result = a + b;
-	}
-
-	DBG("fib: Calling signalAndExit for n=" << n);
-	sem->signalAndExit();
-}
-
-static void fibKickoff() {
-	const int fibNum = 4;
-	int result;
-	BPS sem;
-	fibParams params = {fibNum, &result, &sem};
-
-	fib(&params);
-
-	sem.wait();
-
-	std::cout << "fib(" << fibNum << ") = " << result << std::endl;
-	exit(EXIT_SUCCESS);
-}
-
-auto main(UNUSED_ARG int argc, UNUSED_ARG char* argv[]) -> int {
-	// const unsigned nthreads = std::thread::hardware_concurrency();
-	const unsigned nthreads = 2;
-
-	std::cout << "Number of threads: " << nthreads << std::endl;
-
-	Runtime runtime(nthreads);
-
-	Fiber* fibFiber = Fiber::from(&fibKickoff);
-
-	std::cout << "Just alloacted alpha fiber at " << fibFiber << std::endl;
-
-	runtime.scheduleFromAnywhere(*fibFiber);
-
-	runtime.waitUntilFinished();
-
-	return 0;
-}
diff --git a/apps/fsearch/meson.build b/apps/fsearch/meson.build
index 0a55f035..80b1147d 100644
--- a/apps/fsearch/meson.build
+++ b/apps/fsearch/meson.build
@@ -1,17 +1,3 @@
-boost_program_options_dep = dependency('boost', modules: ['program_options'])
-
-boost_program_options_code = '''
-#include <boost/program_options.hpp>
-int main(int argc, char* argv[]) {
-    boost::program_options::options_description desc("Allowed options");
-}
-'''
-cpp_can_link_with_boost_program_options = cpp_compiler.links(
-  boost_program_options_code,
-  name: 'boost_progam_options',
-  dependencies: boost_program_options_dep,
-)
-
 if cpp_has_fs_recursive_directory_iterator and cpp_can_link_with_boost_program_options
 	fsearch_exe = executable(
 	  'fsearch',
diff --git a/apps/meson.build b/apps/meson.build
index 6ee5a2d1..edc239dc 100644
--- a/apps/meson.build
+++ b/apps/meson.build
@@ -1,9 +1,3 @@
-fib_exe = executable(
-  'fib',
-  'Main.cpp',
-  dependencies: emper_dep,
-)
-
 worker_sleep_example_exe = executable(
   'worker_sleep_example',
   'WorkerSleepExample.cpp',
@@ -40,4 +34,26 @@ qsort = executable(
   dependencies: emper_dep,
 )
 
+boost_program_options_dep = dependency('boost', modules: ['program_options'])
+
+boost_program_options_code = '''
+#include <boost/program_options.hpp>
+int main(int argc, char* argv[]) {
+    boost::program_options::options_description desc("Allowed options");
+}
+'''
+cpp_can_link_with_boost_program_options = cpp_compiler.links(
+  boost_program_options_code,
+  name: 'boost_progam_options',
+  dependencies: boost_program_options_dep,
+)
+
+if cpp_can_link_with_boost_program_options
+  fib_child_stealing_exe = executable(
+    'fib-child-stealing',
+    'FibChildStealing.cpp',
+    dependencies: [emper_dep, boost_program_options_dep],
+  )
+endif
+
 subdir('fsearch')
diff --git a/iwyu-mappings.imp b/iwyu-mappings.imp
index 25cb6087..bbe2308c 100644
--- a/iwyu-mappings.imp
+++ b/iwyu-mappings.imp
@@ -20,6 +20,7 @@
 	{ include: ["<boost/program_options/parsers.hpp>", "private", "<boost/program_options.hpp>", "public"], },
 	{ include: ["<boost/program_options/positional_options.hpp>", "private", "<boost/program_options.hpp>", "public"], },
 	{ include: ["<boost/type_index/type_index_facade.hpp>", "private", "<boost/program_options.hpp>", "public"], },
+	{ include: ["<boost/cstdint.hpp>", "private", "<cstdint>", "public"], },
 
 	{ symbol: ["__kernel_timespec", "private", "<liburing.h>", "public" ] },
 	{ symbol: ["std::filesystem", "private", "<filesystem>", "public" ] },
-- 
GitLab