diff --git a/d/.gitignore b/d/.gitignore new file mode 100644 index 0000000..5e56e04 --- /dev/null +++ b/d/.gitignore @@ -0,0 +1 @@ +/bin diff --git a/d/Makefile b/d/Makefile new file mode 100644 index 0000000..4c3170f --- /dev/null +++ b/d/Makefile @@ -0,0 +1,50 @@ +DMD=bin/dmd2/linux/bin64/dmd +DMD_VERSION=2.074.0 +LDC=bin/ldc2-$(LDC_VERSION)-linux-$(PLATFORM)/bin/ldc2 +LDC_VERSION=1.3.0 +DFLAGS=-g +PLATFORM=x86_64 + +all: bin/serial_opt bin/async_opt bin/async_queue_opt bin/async_atomic_opt + +################################################################################ +# Auto-bootstrap DMD & LDC for outdated Debian/Ubuntu +################################################################################ + +bin: + mkdir -p $@ + +bin/dmd2: | bin + curl -fSL --retry 3 "http://downloads.dlang.org/releases/2.x/$(DMD_VERSION)/dmd.$(DMD_VERSION).linux.tar.xz" | tar -Jxf - -C $| +bin/dmd2/linux/bin64/dmd: | bin/dmd2 + +bin/ldc2-$(LDC_VERSION)-linux-$(PLATFORM): | bin + curl -fSL --retry 3 "https://github.com/ldc-developers/ldc/releases/download/v$(LDC_VERSION)/ldc2-$(LDC_VERSION)-linux-$(PLATFORM).tar.xz" \ + | tar -Jxf - -C $| + +bin/ldc2-$(LDC_VERSION)-linux-$(PLATFORM)/bin/ldc2: | bin/ldc2-$(LDC_VERSION)-linux-$(PLATFORM) + +bin/%_opt: %.d $(LDC) | bin + $(LDC) -g -O4 -mcpu=native -release $(DFLAGS) $< -of$@ + +bin/%: %.d $(DMD) | bin + $(DMD) $(DFLAGS) $< -of$@ + +################################################################################ +# Programs +################################################################################ + +BENCHMARK=../async-io/benchmark.sh +TEST=../async-io/test.sh + +benchmark: bin/serial_opt bin/async_opt + $(BENCHMARK) $< $(word 2, $^) + +benchmark_queue: bin/serial_opt bin/async_queue_opt + $(BENCHMARK) $< $(word 2, $^) + +benchmark_atomic: bin/serial_opt bin/async_atomic_opt + $(BENCHMARK) $< $(word 2, $^) + +test: bin/async_opt + $(TEST) $< diff --git a/d/README.md b/d/README.md new file mode 100644 index 0000000..04791a0 --- /dev/null +++ b/d/README.md @@ -0,0 +1,6 @@ + +Async implementations: + +- `async.d` -> Out of the box [`std.concurrency`](https://dlang.org/phobos/std_concurrency.html) +- `async_queue.d` -> Locking queue +- `async_atomic.d` -> Atomic version (cheated) diff --git a/d/async.d b/d/async.d new file mode 100644 index 0000000..a3984a2 --- /dev/null +++ b/d/async.d @@ -0,0 +1,26 @@ +#!/usr/bin/env rdmd + +__gshared int maxInt; +__gshared int currentInt; + +void main(string[] args) +{ + import std.conv, std.stdio; + import std.concurrency; + auto pid = spawn({ + for (;;) + { + if (receiveOnly!bool) + printf("%d", currentInt++); + else + goto end; + } +end: + }); + auto n = args[1].to!int; + pid.setMaxMailboxSize(n + 10, OnCrowding.ignore); + foreach (i; 0..n) + pid.send(true); + + pid.send(false); +} diff --git a/d/async_atomic.d b/d/async_atomic.d new file mode 100644 index 0000000..dd8bbf7 --- /dev/null +++ b/d/async_atomic.d @@ -0,0 +1,49 @@ +#!/usr/bin/env rdmd + +__gshared int currentInt; + +enum States { + pending, + printInt, + exit +} +shared States state; + +import core.sync.mutex; + +void main(string[] args) +{ + import std.conv, std.stdio; + import std.concurrency; + import core.atomic; + auto pid = spawn({ + with (States) + for_label: for (;;) { + final switch (state.atomicLoad) { + case printInt: + currentInt.write; + state.atomicStore(States.pending); + goto for_label; + case pending: + goto for_label; + case exit: + goto end; + } + } + end: + }); + auto n = args[1].to!int; + foreach (i; 0..n) + { + state.atomicStore(States.printInt); + for (;;) { + if (state.atomicLoad != States.printInt) { + currentInt++; + goto end; + } + } + end: + } + + state.atomicStore(States.exit); +} diff --git a/d/async_queue.d b/d/async_queue.d new file mode 100644 index 0000000..82404ab --- /dev/null +++ b/d/async_queue.d @@ -0,0 +1,67 @@ +#!/usr/bin/env dub +/+dub.sdl: +name "async_queue" +dependency "emsi_containers" version="~>0.5.3" ++/ + +import core.sync.mutex : Mutex; + +// this isn't faster than Mutex +class SpinLock : Object.Monitor +{ + import core.atomic, core.thread; + void lock() { while (!cas(&locked, false, true)) { Thread.yield(); } } + void unlock() { atomicStore!(MemoryOrder.rel)(locked, false); } + shared bool locked; +} + +void main(string[] args) +//@nogc +{ + import std.conv, std.stdio; + import std.concurrency; + import core.memory; + GC.disable(); + + auto n = args[1].to!int; + + import std.experimental.allocator : make; + import std.experimental.allocator.mallocator: Mallocator; + alias alloc = Mallocator.instance; + + __gshared Mutex mutex; + //__gshared SpinLock mutex; + mutex = alloc.make!(typeof(mutex)); + + import std.container.dlist; + //__gshared DList!(void function() @safe) queue; + __gshared DList!int queue; + + __gshared bool done; + scope(exit) done = true; + + auto pid = spawn({ + typeof(queue) localQueue; + for (;;) { + synchronized(mutex) { + if (!queue.empty) { + localQueue = queue; + queue = typeof(queue).init; + } + } + + foreach (e; localQueue[]) + "%d".printf(e); + //e(); + + if (done) + goto end; + } +end: + }); + + foreach (i; 0..n) + synchronized(mutex) + queue ~= i; + //queue ~= { 0.write; }; +} diff --git a/d/serial.d b/d/serial.d new file mode 100644 index 0000000..24e88dc --- /dev/null +++ b/d/serial.d @@ -0,0 +1,8 @@ +#!/usr/bin/env rdmd + +void main(string[] args) +{ + import std.conv, std.stdio; + foreach (i; 0..args[1].to!int) + "%d".printf(i); +}