Skip to content
Snippets Groups Projects
SpawnALot.cpp 5.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • // SPDX-License-Identifier: LGPL-3.0-or-later
    // Copyright © 2020 Florian Schmaus
    
    #include <chrono>		 // for nanoseconds, time_point, dur...
    
    #include <cstdint>	 // for uint8_t, uint64_t
    #include <cstdlib>	 // for EXIT_SUCCESS
    
    #include <iostream>	 // for operator<<, basic_ostream
    #include <thread>		 // for thread
    
    #include "BinaryPrivateSemaphore.hpp"		 // for BPS
    #include "CountingPrivateSemaphore.hpp"	 // for CPS
    #include "Fiber.hpp"										 // for Fiber
    #include "PrivateSemaphore.hpp"					 // for PS
    #include "Runtime.hpp"									 // for Runtime
    #include "emper-common.h"								 // for UNUSED_ARG
    #include "lib/DebugUtil.hpp"						 // for enableStacktraceOnAborts
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    
    #define CACHE_LINE_SIZE 64
    
    
    static void spawnALotThreadsRecursiveTFun(unsigned int depth, unsigned int width,
    																					unsigned int current_depth) {
    	if (current_depth == depth) return;
    
    	auto* threads = new std::thread[width];
    
    	const unsigned int new_depth = current_depth + 1;
    	for (unsigned int i = 0; i < width; ++i) {
    		threads[i] = std::thread(spawnALotThreadsRecursiveTFun, depth, width, new_depth);
    	}
    	for (unsigned int i = 0; i < width; ++i) {
    		threads[i].join();
    	}
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    }
    
    static void spawnALotThreadsRecursive(unsigned int depth, unsigned int width) {
    	std::thread thread(spawnALotThreadsRecursiveTFun, depth, width, 0);
    	thread.join();
    }
    
    static void spawnALotThreadsNonRecursive(uint64_t count) {
    
    	auto* flags = new uint8_t[count * CACHE_LINE_SIZE];
    	auto* threads = new std::thread[count];
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    	for (uint64_t i = 0; i < count; ++i) {
    
    		threads[i] = std::thread([&flags, i] { flags[i * CACHE_LINE_SIZE] = 1; });
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    	}
    
    	for (uint64_t i = 0; i < count; ++i) {
    		threads[i].join();
    	}
    
    	delete[] flags;
    	delete[] threads;
    }
    
    struct SpawnALotFibersData {
    	Runtime& runtime;
    	const unsigned int depth;
    	const unsigned int width;
    	PS& ps;
    	unsigned int current_depth;
    
    	SpawnALotFibersData(SpawnALotFibersData* oldData, PS& ps)
    
    			: runtime(oldData->runtime),
    				depth(oldData->depth),
    				width(oldData->width),
    				ps(ps),
    				current_depth(oldData->current_depth + 1) {}
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    
    	SpawnALotFibersData(Runtime& runtime, unsigned int depth, unsigned int width, PS& ps)
    
    			: runtime(runtime), depth(depth), width(width), ps(ps), current_depth(0) {}
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    };
    
    static void spawnALotFibersRecursiveFFun(void* dataPtr) {
    
    	auto* data = (SpawnALotFibersData*)dataPtr;
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    	if (data->current_depth < data->depth) {
    		CPS childSem(data->width);
    		SpawnALotFibersData newData(data, childSem);
    
    		for (unsigned int i = 0; i < data->width; ++i) {
    
    			Fiber* fiber = Fiber::from(spawnALotFibersRecursiveFFun, (void*)&newData);
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    			data->runtime.schedule(*fiber);
    		}
    
    		childSem.wait();
    	}
    
    	data->ps.signal();
    }
    
    static void spawnALotFibersRecursive(Runtime& runtime, unsigned int depth, unsigned int width) {
    	BPS bps;
    	SpawnALotFibersData data(runtime, depth, width, bps);
    
    
    	Fiber* fiber = Fiber::from(spawnALotFibersRecursiveFFun, (void*)&data);
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    	runtime.schedule(*fiber);
    
    	bps.wait();
    }
    
    static void spawnALotFibersNonRecursive(Runtime& runtime, uint64_t count) {
    
    	auto* flags = new uint8_t[count * CACHE_LINE_SIZE];
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    	CPS cps(count);
    
    	for (uint64_t i = 0; i < count; ++i) {
    		Fiber* fiber = Fiber::from([i, &cps, flags] {
    
    			flags[i * CACHE_LINE_SIZE] = 1;
    			cps.signal();
    		});
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    		runtime.schedule(*fiber);
    	}
    
    	cps.wait();
    
    	delete[] flags;
    }
    
    
    auto main(UNUSED_ARG int argc, UNUSED_ARG char* argv[]) -> int {
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    	enableStacktraceOnAborts();
    	const uint64_t count = 1024;
    
    	const unsigned int depth = 10;
    	const unsigned int width = 2;
    
    	std::chrono::time_point<std::chrono::high_resolution_clock> start, end;
    	std::chrono::nanoseconds diff;
    
    	start = std::chrono::high_resolution_clock::now();
    	spawnALotThreadsRecursive(depth, width);
    	end = std::chrono::high_resolution_clock::now();
    
    	diff = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);
    	std::cout << "Spawn a lot of threads recursive (depth=" << depth << ", width=" << width
    						<< ") took " << std::endl
    						<< diff.count() << " ns" << std::endl;
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    
    	start = std::chrono::high_resolution_clock::now();
    	spawnALotThreadsNonRecursive(count);
    	end = std::chrono::high_resolution_clock::now();
    
    	diff = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);
    	std::cout << "Spawn a lot of threads non-recursive (count=" << count << ") took " << std::endl
    						<< diff.count() << " ns"
    						<< " (" << diff.count() / count << " ns/thread)" << std::endl;
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    
    	Runtime runtime;
    
    	runtime.executeAndWait([&] {
    
    		start = std::chrono::high_resolution_clock::now();
    		spawnALotFibersRecursive(runtime, depth, width);
    		end = std::chrono::high_resolution_clock::now();
    		diff = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);
    		std::cout << "Spawn a lot of fibers recursive (depth=" << depth << ", width=" << width
    							<< ") took " << std::endl
    							<< diff.count() << " ns" << std::endl;
    
    		start = std::chrono::high_resolution_clock::now();
    		spawnALotFibersNonRecursive(runtime, count);
    		end = std::chrono::high_resolution_clock::now();
    		diff = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);
    		std::cout << "Spawn a lot of fibers non-recursive (count=" << count << ") took " << std::endl
    							<< diff.count() << " ns"
    							<< " (" << diff.count() / count << " ns/fiber)" << std::endl;
    	});
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    
    	return EXIT_SUCCESS;
    }