<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>