-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
make unzip faster: seq[i]=val can be 7X faster than seq.add(val) #13448
Conversation
d36b121
to
e9f426b
Compare
Wow, TIL. edit:
phew, ok... Now I'm a little bit relieved. :P |
e9f426b
to
9864156
Compare
newSeq(n)/seq[i]=elem
is 5-15X faster than newSeqOfCap(n)/seq.add(elem)
in general9864156
to
ef460da
Compare
not so quick: see benchmark above, showing 7X speedup |
TIL.. may the fastest implementation win! |
failure unrelated (see #13449) but will re-run CI |
I mean yeah, definitely. I'm just a little shocked, that's all. |
same in C++ std::vector although less drastic (but it's not apples to apples comparison, the tests are a bit different):
#include <iostream>
#include <stdio.h>
#include <vector>
static const int n = 1000000;
int total = 0;
void fun1(){
std::vector<int> x;
x.reserve(n);
for(int i=0;i<n;i++){
x.push_back(i);
}
total+=x[n/2];
}
void fun2(){
std::vector<int> x(n);
for(int i=0;i<n;i++){
x[i]=i;
}
total+=x[n/2];
}
int main (int argc, char *argv[]) {
int numIter = 10000;
for(int i=0;i<numIter;i++){
fun1();
// fun2();
}
std::cout << total << std::endl;
return 0;
} |
this PR makes unzip (#13429) up to 7X faster by simply using
[]=
instead ofadd
general performance note: avoid
newSeqOfCap
anti-patternwhen the final size is known in advance,
newSeqOfCap(n) + seq.add(elem)
should not be used; it can be 7X slower than this pattern:newSeq(n) + seq[i]=elem
.and it makes sense, because
add
has to do more work (both with and without-d:danger
): to increment length, and also to compare new length against capacity. So while reallocation is avoided in both newSeq(n) and newSeqOfCap(n) cases thanks to preallocation, the 1st pattern is a lot slower because of the extra work.benchmark code
benchmark times
nim c -r main.nim
nim c -r -d:danger main.nim
note
i haven't tried with
{.noinit.}
; this could have potential concerns depending on the type (eg if it's a reference type and something throws in the middle); this is very related to this: dlang/phobos#6178 (comment) from an old D PR: