<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div><div>On Feb 9, 2012, at 10:31 AM, Marco Leise wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div>Am 09.02.2012, 18:35 Uhr, schrieb Andrei Alexandrescu <<a href="mailto:SeeWebsiteForEmail@erdani.org">SeeWebsiteForEmail@erdani.org</a>>:<br><br><blockquote type="cite">On 2/9/12 6:10 AM, Gor Gyolchanyan wrote:<br></blockquote><blockquote type="cite"><blockquote type="cite">Generally, D's message passing is implemented in quite easy-to-use<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">way, but far from being fast.<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">I dislike the Variant structure, because it adds a huge overhead. I'd<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">rather have a templated message passing system with type-safe message<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">queue, so no Variant is necessary.<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">In specific cases Messages can be polymorphic objects. This will be<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">way faster, then Variant.<br></blockquote></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">cc Sean Kelly<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">I haven't looked at the implementation, but one possible liability is that large messages don't fit in a Variant and must use dynamic allocation under the wraps. There are a number of ways to avoid that, such as parallel arrays (one array per type for data and one for the additional tags).<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">We must make the message passing subsystem to not use any memory allocation in the quiescent state. If we're doing one allocation per message passed, that might explain the 4x performance difference (I have no trouble figuring Java's allocator is this much faster than D's).</blockquote><br>Well, what does +1 Variant and +1 LinkedListNode sum up to?<br></div></blockquote><br></div><div>FWIW, you can use DMD's built in profiler so long as the receiving thread is the same as the sending thread:</div><div><br></div><div><font class="Apple-style-span" face="'Courier New'">import std.concurrency;<br><br>void main() {<br> for(int i = 0; i < 1_000_000; i++) {<br> send(thisTid, 12345);<br> auto x = receiveOnly!int();<br> }<br>}</font><br><br></div><div><br></div><div>I generated timings for this both before and after adding "scope" to mbox.get():</div><div><div><div><br></div><div><font class="Apple-style-span" face="'Courier New'">$ dmd -release -inline -O abc</font></div><div><div><font class="Apple-style-span" face="'Courier New'">$ time abc</font></div><div><font class="Apple-style-span" face="'Courier New'"><br></font></div><div><font class="Apple-style-span" face="'Courier New'">real<span class="Apple-tab-span" style="white-space: pre; "> </span>0m0.831s</font></div><div><font class="Apple-style-span" face="'Courier New'">user<span class="Apple-tab-span" style="white-space: pre; "> </span>0m0.829s</font></div><div><font class="Apple-style-span" face="'Courier New'">sys<span class="Apple-tab-span" style="white-space: pre; "> </span>0m0.002s</font></div></div><div><br></div><div>… add "scope" to mbox.get()</div><div><br></div><div><font class="Apple-style-span" face="'Courier New'">$ dmd -release -inline -O abc</font></div><div><div><font class="Apple-style-span" face="'Courier New'">$ time abc</font></div><div><font class="Apple-style-span" face="'Courier New'"><br></font></div><div><font class="Apple-style-span" face="'Courier New'">real<span class="Apple-tab-span" style="white-space: pre; "> </span>0m0.653s</font></div><div><font class="Apple-style-span" face="'Courier New'">user<span class="Apple-tab-span" style="white-space: pre; "> </span>0m0.649s</font></div><div><font class="Apple-style-span" face="'Courier New'">sys<span class="Apple-tab-span" style="white-space: pre; "> </span>0m0.003s</font></div></div><div><br></div><div><br></div></div></div><div>And here's the trace log after "scope" was added. Notice that there were 61 calls to GCX.fullcollect(). We can also see that there was 1 allocation per send/receive operation, so only an alloc for the message list node.</div><div><br></div><div><div><font class="Apple-style-span" face="'Courier New'">$ dmd -O -release -profile abc</font></div><div><font class="Apple-style-span" face="'Courier New'">gladsheim:misc sean$ time abc</font></div><div><font class="Apple-style-span" face="'Courier New'"><br></font></div><div><font class="Apple-style-span" face="'Courier New'">real<span class="Apple-tab-span" style="white-space:pre"> </span>0m11.348s</font></div><div><font class="Apple-style-span" face="'Courier New'">user<span class="Apple-tab-span" style="white-space:pre"> </span>0m11.331s</font></div><div><font class="Apple-style-span" face="'Courier New'">sys<span class="Apple-tab-span" style="white-space:pre"> </span>0m0.015s</font></div><div><br></div></div><div><br></div><div><div><font class="Apple-style-span" face="'Courier New'">======== Timer Is 3579545 Ticks/Sec, Times are in Microsecs ========</font></div><div><font class="Apple-style-span" face="'Courier New'"><br></font></div><div><font class="Apple-style-span" face="'Courier New'"> Num Tree Func Per</font></div><div><font class="Apple-style-span" face="'Courier New'"> Calls Time Time Call</font></div><div><font class="Apple-style-span" face="'Courier New'"><br></font></div><div><font class="Apple-style-span" face="'Courier New'">1000000 437709765 220179413 220 void std.concurrency._send!(int)._send(std.concurrency.MsgType, std.concurrency.Tid, int)</font></div><div><font class="Apple-style-span" face="'Courier New'">1000000 300987757 140736393 140 bool std.concurrency.MessageBox.get!(nothrow @safe void delegate(int), pure @safe void function(std.concurrency.LinkTerminated)*, pure @safe void function(std.concurrency.OwnerTerminated)*, pure @safe void function(std.variant.VariantN!(32u).VariantN)*).get(scope nothrow @safe void delegate(int), scope pure @safe void function(std.concurrency.LinkTerminated)*, scope pure @safe void function(std.concurrency.OwnerTerminated)*, scope pure @safe void function(std.variant.VariantN!(32u).VariantN)*)</font></div><div><font class="Apple-style-span" face="'Courier New'">1000000 202131609 89479808 89 void* gc.gcx.GC.malloc(uint, uint, uint*)</font></div><div><font class="Apple-style-span" face="'Courier New'"> 1 825045422 57556501 57556501 _Dmain</font></div><div><font class="Apple-style-span" face="'Courier New'">1000033 112651800 52026745 52 void* gc.gcx.GC.mallocNoSync(uint, uint, uint*)</font></div><div><font class="Apple-style-span" face="'Courier New'"> 61 53422342 49606106 813214 uint gc.gcx.Gcx.fullcollect(void*)</font></div><div><font class="Apple-style-span" face="'Courier New'">2000000 160103753 42531732 21 bool std.concurrency.MessageBox.get!(nothrow @safe void delegate(int), pure @safe void function(std.concurrency.LinkTerminated)*, pure @safe void function(std.concurrency.OwnerTerminated)*, pure @safe void function(std.variant.VariantN!(32u).VariantN)*).get(scope nothrow @safe void delegate(int), scope pure @safe void function(std.concurrency.LinkTerminated)*, scope pure @safe void function(std.concurrency.OwnerTerminated)*, scope pure @safe void function(std.variant.VariantN!(32u).VariantN)*).bool scan(ref std.concurrency.List!(std.concurrency.Message).List)</font></div><div><font class="Apple-style-span" face="'Courier New'">2000000 42018612 39837170 19 int std.variant.VariantN!(32u).VariantN.handler!(int).handler(std.variant.VariantN!(32u).VariantN.OpID, ubyte[32]*, void*)</font></div><div><font class="Apple-style-span" face="'Courier New'">1000000 117572021 24641771 24 bool std.concurrency.MessageBox.get!(nothrow @safe void delegate(int), pure @safe void function(std.concurrency.LinkTerminated)*, pure @safe void function(std.concurrency.OwnerTerminated)*, pure @safe void function(std.variant.VariantN!(32u).VariantN)*).get(scope nothrow @safe void delegate(int), scope pure @safe void function(std.concurrency.LinkTerminated)*, scope pure @safe void function(std.concurrency.OwnerTerminated)*, scope pure @safe void function(std.variant.VariantN!(32u).VariantN)*).bool onStandardMsg(ref std.concurrency.Message)</font></div><div><font class="Apple-style-span" face="'Courier New'">1000000 47280794 20418675 20 void std.concurrency.Message.map!(nothrow @safe void delegate(int)).map(nothrow @safe void delegate(int))</font></div><div><font class="Apple-style-span" face="'Courier New'">1000000 316556767 15569009 15 int std.concurrency.receiveOnly!(int).receiveOnly()</font></div><div><font class="Apple-style-span" face="'Courier New'">1000000 36317362 13212905 13 @property bool std.variant.VariantN!(32u).VariantN.convertsTo!(int).convertsTo()</font></div><div><font class="Apple-style-span" face="'Courier New'">1000000 15445906 10879089 10 std.concurrency.Message std.concurrency.Message.__ctor!(int).__ctor(std.concurrency.MsgType, int)</font></div><div><font class="Apple-style-span" face="'Courier New'">1000000 45649454 9332092 9 @property bool std.concurrency.Message.convertsTo!(int).convertsTo()</font></div><div><font class="Apple-style-span" face="'Courier New'">1000000 26790032 7875877 7 @property int std.variant.VariantN!(32u).VariantN.get!(int).get()</font></div><div><font class="Apple-style-span" face="'Courier New'">1000000 444757778 7048013 7 void std.concurrency._send!(int)._send(std.concurrency.Tid, int)</font></div><div><font class="Apple-style-span" face="'Courier New'"> 15512 6681162 6657279 429 int gc.gcx.Gcx.allocPage(ubyte)</font></div><div><font class="Apple-style-span" face="'Courier New'">1000000 450932153 6174374 6 void std.concurrency.send!(int).send(std.concurrency.Tid, int)</font></div><div><font class="Apple-style-span" face="'Courier New'">1000000 4566817 4566817 4 std.variant.VariantN!(32u).VariantN std.variant.VariantN!(32u).VariantN.opAssign!(int).opAssign(int)</font></div><div><font class="Apple-style-span" face="'Courier New'"> 4087 3635735 3518353 860 void gc.gcx.Gcx.mark(void*, void*, int)</font></div><div><font class="Apple-style-span" face="'Courier New'">2000000 2069965 2069965 1 int std.variant.VariantN!(32u).VariantN.handler!(int).handler(std.variant.VariantN!(32u).VariantN.OpID, ubyte[32]*, void*).bool tryPutting(int*, TypeInfo, void*)</font></div><div><font class="Apple-style-span" face="'Courier New'">2990271 195287 195287 0 void* gc.gcx.sentinel_add(void*)</font></div><div><font class="Apple-style-span" face="'Courier New'">1000000 147610 147610 0 bool std.concurrency.MessageBox.get!(nothrow @safe void delegate(int), pure @safe void function(std.concurrency.LinkTerminated)*, pure @safe void function(std.concurrency.OwnerTerminated)*, pure @safe void function(std.variant.VariantN!(32u).VariantN)*).get(scope nothrow @safe void delegate(int), scope pure @safe void function(std.concurrency.LinkTerminated)*, scope pure @safe void function(std.concurrency.OwnerTerminated)*, scope pure @safe void function(std.variant.VariantN!(32u).VariantN)*).bool pty(ref std.concurrency.List!(std.concurrency.Message).List)</font></div><div><font class="Apple-style-span" face="'Courier New'">1000032 121459 121459 0 void gc.gcx.Gcx.setBits(gc.gcx.Pool*, uint, uint)</font></div><div><font class="Apple-style-span" face="'Courier New'">2000000 111475 111475 0 int std.variant.VariantN!(32u).VariantN.handler!(int).handler(std.variant.VariantN!(32u).VariantN.OpID, ubyte[32]*, void*).int* getPtr(void*)</font></div><div><font class="Apple-style-span" face="'Courier New'">1000033 102413 102413 0 ubyte gc.gcx.Gcx.findBin(uint)</font></div><div><font class="Apple-style-span" face="'Courier New'">1002228 94742 94742 0 @property uint gc.gcx.Pool.shiftBy()</font></div><div><font class="Apple-style-span" face="'Courier New'">1000000 72086 72086 0 int std.concurrency.receiveOnly!(int).receiveOnly().nothrow @safe void __lambda17(int)</font></div><div><font class="Apple-style-span" face="'Courier New'"> 995119 70854 70854 0 void gc.gcx.Gcx.log_free(void*)</font></div><div><font class="Apple-style-span" face="'Courier New'">1000033 61505 61505 0 void gc.gcx.sentinel_init(void*, uint)</font></div><div><font class="Apple-style-span" face="'Courier New'">1000033 55070 55070 0 void gc.gcx.Gcx.log_malloc(void*, uint)</font></div><div><font class="Apple-style-span" face="'Courier New'"> 995119 51748 51748 0 void gc.gcx.sentinel_Invariant(const(void*))</font></div><div><font class="Apple-style-span" face="'Courier New'"> 1 24692 24692 24692 void gc.gcx.Pool.initialize(uint, bool)</font></div><div><font class="Apple-style-span" face="'Courier New'"> 3538 3544517 24525 6 void gc.gcx.Gcx.mark(void*, void*)</font></div><div><font class="Apple-style-span" face="'Courier New'"> 15511 23883 23522 1 uint gc.gcx.Pool.allocPages(uint)</font></div><div><font class="Apple-style-span" face="'Courier New'"> 124447 11615 11615 0 void gc.gcx.Gcx.clrBitsSmallSweep(gc.gcx.Pool*, uint, uint)</font></div><div><font class="Apple-style-span" face="'Courier New'"> 1 7051 5921 5921 void gc.gcx.GC.initialize()</font></div><div><font class="Apple-style-span" face="'Courier New'"> 1 27490 2797 2797 gc.gcx.Pool* gc.gcx.Gcx.newPool(uint, bool)</font></div><div><font class="Apple-style-span" face="'Courier New'"> 61 53424783 2441 40 uint gc.gcx.Gcx.fullcollectshell()</font></div><div><font class="Apple-style-span" face="'Courier New'"> 55 2227 2227 40 void gc.gcx.Gcx.addRange(void*, void*)</font></div><div><font class="Apple-style-span" face="'Courier New'"> 1 1129 1119 1119 void gc.gcx.Gcx.initialize()</font></div><div><font class="Apple-style-span" face="'Courier New'"> 16 360 360 22 uint gc.gcx.Pool.extendPages(uint)</font></div><div><font class="Apple-style-span" face="'Courier New'"> 1 2547 319 319 void gc.gcx.GC.addRange(void*, uint)</font></div><div><font class="Apple-style-span" face="'Courier New'"> 2196 278 278 0 gc.gcx.Pool* gc.gcx.Gcx.findPool(void*)</font></div><div><font class="Apple-style-span" face="'Courier New'"> 1 65 65 65 void gc.gcx.GC.disable()</font></div><div><font class="Apple-style-span" face="'Courier New'"> 1 9 9 9 void gc.gcx.Gcx.log_init()</font></div><div><font class="Apple-style-span" face="'Courier New'"> 1 5 5 5 void gc.gcx.GC.enable()</font></div><div><font class="Apple-style-span" face="'Courier New'"> 1 0 0 0 void gc.gcx.GC.setStackBottom(void*)</font></div><div><font class="Apple-style-span" face="'Courier New'"> 1 0 0 0 @property uint gc.gcx.Pool.divisor()</font></div><div><br></div></div></body></html>