Associative Array potential performance pitfall?
H. S. Teoh
hsteoh at quickfur.ath.cx
Fri Mar 13 09:24:43 UTC 2020
On Fri, Mar 13, 2020 at 03:40:11AM +0000, Adnan via Digitalmars-d-learn wrote:
> In my machine the following D code compiled with release flag and LDC
> performs over 230ms while the similar Go code performs under 120ms.
>
> string smallestRepr(const string arg) {
> import std.format : format;
>
> const repeated = format!"%s%s"(arg, arg);
.format is dog slow, and not exactly something you want to be calling
every iteration. Try instead:
auto repeated = arg ~ arg;
> string result;
> result.reserve(arg.length);
> result = arg;
This does not do what you think it does. Assigning to a string is a
shallow copy; the call to .reserve is superfluous. In fact, it's
triggering another allocation, only to throw it away immediately. Just
write:
auto result = arg;
> foreach (i; 1 .. arg.length) {
> const slice = repeated[i .. i + arg.length];
> if (slice < result)
> result = slice;
> }
> return result;
> }
[...]
> Where am I losing performance?
1) Calling .format -- it's dog slow. Just use ~.
2) Calling .reserve only to throw away the results immediately. Just
skip it.
I doubt your AA is the performance bottleneck here.
Try the following implementation of .smallestRepr that avoids (1) and
(2):
string smallestRepr(const string arg) {
auto repeated = arg ~ arg;
string result = arg;
foreach (i; 1 .. arg.length) {
const slice = repeated[i .. i + arg.length];
if (slice < result)
result = slice;
}
return result;
}
Note that `arg ~ arg` may allocate, but it also may not if the current
buffer for `arg` is big enough to accomodate both. So you might actually
save on some allocations here, that you lose out from calling .format.
On my machine, a quick benchmark shows a 2x performance boost.
T
--
That's not a bug; that's a feature!
More information about the Digitalmars-d-learn
mailing list