Closed notEvil closed 1 year ago
I just started to have a look at this again and I thought: how does this get called usually?
It seems jsvMakeIntoVariableName(jsvNewFromString
is pretty common (or jsvMakeIntoVariableName(jslGetTokenValueAsVar
which is basically the same).
I'm not sure if you have any thoughts on this but I'm wondering if it makes sense to just skip out the middle man and add a jsvNewVariableName
function? It would avoid this little shuffle, and should provide a nice speed boost too
Not really, except that it would be nice to get rid of this part :) Performance wise I have no clue how it would pan out
Ok, just done - but at the same time I can't easily get rid of jsvMakeIntoVariableName as it's used in a bunch of places.
I'd be interested to see what you find fragmentation-wise with master
now - I'd imagine that for the majority of code now, jsvMakeIntoVariableName never gets called with a string
On my Bangle 1, clock face, few widgets
jsvMakeIntoVariableName
(~40% by the new function)Wow, thanks - that's really handy. Way more than I thought still using jsvMakeIntoVariableName
~60% are too big (previously 50%)
I'm not sure I understand this one? Or you mean that now 40% of the names are made using jsvNewNameFromString, now more of the calls to jsvMakeIntoVariableName are for oversize strings?
It is ext_count / make_count
, so how often is the string longer than 4 bytes given it is transformed by jsvMakeIntoVariableName
.
Ok, thanks - so it's not like my recent changes made it worse, it's just there are less calls in total but a slightly higher proportion are long?
I just pushed some changes - maybe try now? I started dumping the variable name and it seems it was getting called for most property accesses of builtins (we pass the name back so they're l-values). There was no need to convert those either so there should be a significant improvement now.
Where I do still see it is object definitions like {hello : 42}
for instance which is a bit of a pain, but the amount of times MakeInto is called has dropped right off.
I think it's still worth merging this in though - but in general the less random shifting around of stuff we can do the better :)
Ok, thanks - so it's not like my recent changes made it worse, it's just there are less calls in total but a slightly higher proportion are long?
yes
I just tried master with improved counting (individual make_count
per line number)
and the counts are
1318: 6509 (jsvMakeFunctionParameter
)
2922: 1103 (jsvAsName
first use)
144: 164 (not in jsvar.c)
2925: 39 (jsvAsName
second use)
Unfortunately there is a serious memory leak now, running GC doesn't help. My previous experiments were done on 2v16 with some changes cherry picked (https://gitlab.com/notEvil/cyclometer/-/blob/master/Bangle.js/Espruino/build.py), so I don't know where this was introduced.
And fyi, I've reverted the branch so the build for my project wouldn't break. It should be fine since the PR is already merged. I've created a copy called adjust_string_merge
which is where you left it.
Ok, thanks. Do you have any more info about the memory leak and how to cause it? I'm not really seeing anything on my Bangle.js 2 now - just flipping between clock and launcher and I'm not seeing memory usage rising at all?
Also the command-line tests for Linux should really pick up any obvious leaks since it's one of the things they check for after every test
Yes, its the patch above. Without it, everything is fine. Its not supposed to mess with JS memory but somehow does.
edit: and now I know why: the #define
needs a temporary variable, otherwise it will execute a
twice ... Sry for the distraction!
now with a non-broken counting build, for future reference or improvement attempts:
name_count
: 58471
make_count
: 19679 (~25% of name_count + make_count
)
ext_count
: 11716 (~60% of make_count
)
gap_count
: 95 (~0.008 on average, if it were the old algorithm)
L1318: 16970 (jsvMakeFunctionParameter
)
L2922: 2381 (jsvAsName
first use)
L144: 315 (somewhere else)
L2925: 13 (jsvAsName
second use)
Yes, its the patch above.
Ahh! you mean your counting patch? Not this PR itself? Sorry - got confused as the PR itself seems to work fine.
Thanks for those stats. L1318 is an odd one as it would appear that only applies for getters and setters which we don't actually use all that much from code in BangleApps (I thought!). Do you have any custom code you're using or is what you're debugging with pretty much standard?
Thanks again for your work on this - poking around in the internals and instrumenting things is super helpful. The interpreter itself is quite old now and there are definitely some non-optimal things happening. While when I get time I do try and take a look, as this shows there's plenty of stuff I miss!
Ahh! you mean your counting patch? Not this PR itself?
Yes, should have stated this more clearly
Do you have any custom code you're using or is what you're debugging with pretty much standard?
Again for reference, I used https://github.com/espruino/Espruino/commit/95e8a321d24f3ad0d710c82c75678676bce0ac76 with the following patch (counting)
and the following list of apps which might ran in the background (didn't start any of them from the launcher)
about (0.14) accelrec (0.02) alarm (0.38) boldclk (0.07) boot (0.56) chargent (0.03) dtlaunch (0.22) fileman (0.03) files (0.08) health (0.22) hrm (0.11) notify (0.12) sched (0.21) setting (0.58) wid_edit (0.02) widalarm (0.01) widchime (0.02) widdevst (0.02) widminbat (0.02) widram (0.03)
So nothing out of the ordinary I'd say
Thanks again for your work on this - poking around in the internals and instrumenting things is super helpful. The interpreter itself is quite old now and there are definitely some non-optimal things happening. While when I get time I do try and take a look, as this shows there's plenty of stuff I miss!
You are welcome! I learned a lot about development on a constrained platform and the codebase is a pleasure to work with. Reliability beats optimality imo. What would be nice though is call site profiling :) But thats difficult to achieve I'd assume
Thanks!
As far as call profiling, the best I've got really is compiling and running for Linux on a Raspberry Pi with gprof. Although that generates standard ARM code rather than Thumb (and the Pi has a more complicated processor) I thought it provided a good indication.
It looks like on Rasperry Pi 2+ it's possible to compile to thumb2 with "-mthumb" but it looks like they don't include the stdlib for that so it would actually be a bit more involved to get it building fully.
I have occasionally had runs through trying to find obvious time sinks, but that's all been with reasonably basic code like the stuff in the benchmarks
directory. There would be a lot to be said for using the BANGLEJS2_LINUX
Linux Bangle-emulation build (a bit like we do for emscripten) and then trying to run through a pre-programmed set of tasks and then using that as a basis for benchmarking.
Currently, when converting strings to names, existing StringExt are replaced by new ones. This introduces gaps, e.g.
1: String 2: StringExt 3: first empty 4: second empty
may become either 1 -> 3 (new StringExt) and 2 (first empty) -> 4, or 1 -> 3 -> 4 and 2 -> 5.
This PR changes the algorithm to reuse the existing StringExt by increasing the length of the string and shifting the characters. On my Bangle ~50% of the strings enter this part, each adding ~0.15 gaps on average (~4000 in ~30min).
I don't expect this to hit master anytime soon because it doesn't solve an actual issue and its value is debatable. The only real gain is potentially more space for flat strings and less GC.