D perfomance
Steven Schveighoffer
schveiguy at gmail.com
Sun Apr 26 16:20:19 UTC 2020
On 4/25/20 6:34 AM, Joseph Rushton Wakeling wrote:
> On Saturday, 25 April 2020 at 10:15:33 UTC, Walter Bright wrote:
>> On 4/24/2020 12:27 PM, Arine wrote:
>>> There most definitely is a difference and the assembly generated with
>>> rust is better.
>> D's @live functions can indeed do such optimizations, though I haven't
>> got around to implementing them in DMD's optimizer. There's nothing
>> particularly difficult about it.
>
> In any case, I seriously doubt those kinds of optimization have anything
> to do with the web framework performance differences.
>
> My experience of writing number-crunching stuff in D and Rust is that
> Rust seems to have a small but consistent performance edge that could
> quite possibly be down the kind of optimizations that Arine mentions
> (that's speculation: I haven't verified). However, it's small
> differences, not order-of-magnitude stuff.
>
> I suppose that in a more complicated app there could be some
> multiplicative impact, but where high-throughput web frameworks are
> concerned I'm pretty sure that the memory allocation and reuse strategy
> is going to be what makes 99% of the difference.
>
> There may also be a bit of an impact from the choice of futures vs.
> fibers for managing asynchronous tasks (there's a context switching cost
> for fibers), but I would expect that to only make a difference at the
> extreme upper end of performance, once other design factors have been
> addressed.
>
> BTW, on the memory allocation front, Mathias Lang has pointed out that
> there is quite a nasty impact from `assumeSafeAppend`. Imagine that your
> request processing looks something like this:
>
> // extract array instance from reusable pool,
> // and set its length to zero so that you can
> // write into it from the start
> x = buffer_pool.get();
> x.length = 0;
> assumeSafeAppend(x); // a cost each time you do this
>
> // now append stuff into x to
> // create your response
>
> // now publish your response
>
> // with the response published, clean
> // up by recycling the buffer back into
> // the pool
> buffer_pool.recycle(x);
>
> This is the kind of pattern that Sociomantic used a lot. In D1 it was
> easy because there was no array stomping prevention -- you could just
> set length == 0 and start appending. But having to call
> `assumeSafeAppend` each time does carry a performance cost.
In terms of performance, depending on the task at hand, D1 code is
slower than D2 appending, by the fact that there's a thread-local cache
for appending for D2, and D1 only has a global one-array cache for the
same. However, I'm assuming that since you were focused on D1, your
usage naturally was written to take advantage of what D1 has to offer.
The assumeSafeAppend call also uses this cache, and so it should be
quite fast. But setting length to 0 is a ton faster, because you aren't
calling an opaque function.
So depending on the usage pattern, D2 with assumeSafeAppend can be
faster, or it could be slower.
>
> IIRC Mathias has suggested that it should be possible to tag arrays as
> intended for this kind of re-use, so that stomping prevention will never
> trigger, and you don't have to `assumeSafeAppend` each time you reduce
> the length.
I spoke for a while with Dicebot at Dconf 2016 or 17 about this issue.
IIRC, I suggested either using a custom type or custom runtime. He was
not interested in either of these ideas, and it makes sense (large
existing code base, didn't want to stray from mainline D).
By far, the best mechanism to use is a custom type. Not only will that
fix this problem as you can implement whatever behavior you want, but
you also do not need to call opaque functions for appending either. It
should outperform everything you could do in a generic runtime.
Note that this was before (I think) destructor calls were added. The
destructor calls are something that assumeSafeAppend is going to do, and
won't be done with just setting length to 0.
However, there are other options. We could introduce a druntime
configuration option so when this specific situation happens (slice
points at start of block and has 0 length), assumeSafeAppend is called
automatically on the first append. Jonathan is right that this is not
@safe, but it could be an opt-in configuration option.
I don't think configuring specific arrays makes a lot of sense, as this
would require yet another optional bit that would have to be checked and
allocated for all arrays.
-Steve
More information about the Digitalmars-d
mailing list