-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Closed
Description
Assignment to result variables generate calls to genericReset becoming ~5x slower than raw field assignment, the test case:
import times
type Foo = object
val: int
s: seq[int]
proc newFoo(): Foo =
result.val = 1
proc boo(): Foo =
result = newFoo()
proc boo2(): Foo =
let a = newFoo()
result.s = a.s
result.val = a.val
proc main() =
block:
let start = epochTime()
for i in 0..<1000000000:
let a = boo()
echo "boo ", epochTime() - start
block:
let start = epochTime()
for i in 0..<1000000000:
let a = boo2()
echo "boo2 ", epochTime() - start
main()Outputs:
elapsed 14.58154105735779
elapsed 3.642938910873413As you can see boo2 that assigns each field separately is faster than boo. The problem is that boo generate genericReset calls which causes the slow down:
boo generates
N_NIMCALL(void, boo_9aSl0jzccntfjPB4osXEnHA)(tyObject_Foo_Bsmztv1sSxNkRrfi5afFAg* Result) {
genericReset((void*)Result, (&NTI_Bsmztv1sSxNkRrfi5afFAg_));
newFoo_9aSl0jzccntfjPB4osXEnHA_2(Result);
}boo2 generates:
N_NIMCALL(void, boo2_9aSl0jzccntfjPB4osXEnHA_3)(tyObject_Foo_Bsmztv1sSxNkRrfi5afFAg* Result) {
tyObject_Foo_Bsmztv1sSxNkRrfi5afFAg a;
memset((void*)(&a), 0, sizeof(a));
memset((void*)(&a), 0, sizeof(a));
newFoo_9aSl0jzccntfjPB4osXEnHA_2((&a));
genericSeqAssign((&(*Result).s), a.s, (&NTI_qwqHTkRvwhrRyENtudHQ7g_));
(*Result).val = a.val;
}In the boo genericReset call could be avoided and a memset called just like boo2
Workaround: Assign each field separately.
Why is this a problem? As my code is full of returns via result assignment, it's also full of genericReset calls and when profiling genericReset does show on perf with high CPU usage.
mratsim