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
Allow typed arrays over 64KB #2036
Comments
I had a play with this yesterday and it wasn't as easy as hoped. You could get the extra bits into the enum, but then a few bits of code have to have the direct reference to array size changed in them. |
BTW just tried strings over 64K in LINUX build and looks like
|
Another case of this limitation https://forum.espruino.com/comments/16824971/ |
I know... I did attempt to get a fix in for this, but it didn't appear to be working... The idea was to increase the length to 24 where we thought we had enough memory for it:
IMO that'd be preferable to the other option (of trying to poke the top bits into the ArrayBuffer enum) |
Thanks for the patch. Tried in on linux build (which also has this limit even in 64bit) and it helps partially. THe example from above is better.
|
so when removing extra check from here Espruino/src/jswrap_arraybuffer.c Line 240 in 7277a8d
it got better for arraybuffer but still wrong for arrays
|
will test on nrf52 later but anyway even if it worked just for ArrayBuffer type it would be improvement as this works now
|
also this works
so you can't have index array over 16 bits but the underlying buffer seems to work over 64K with 16bit type |
Maybe I got it, this line Espruino/src/jswrap_arraybuffer.c Line 545 in 7277a8d
|
Ahh, great! maybe you could run a build with that for a while? I think I was a bit concerned that it might have meant that some references got overwritten, so when it gets freed things could potentially get unstable |
OK, I will. So far this was from linux build but I needed this for framebuffer on 52840 watches like 240x320 in 256 colors or even 12bit. Also the G5 watch https://forum.espruino.com/conversations/373361/ which even in 4 bits is over 64K. So I will test this however in this use case I will never free the buffer. Do you suppose this may happen when just smaller stuff around it gets freed and allocated over time? Otherwise maybe some random size allocation/free test that runs continuously would be better. |
Well, testing like that is still definitely better than nothing - if it can survive an E.defrag and garbage collect then there's a good chance it's ok. I had actually made the change for a high res LCD too, but it didn't seem stable for me (but I can't remember why now though!) |
In the linux build (without RELEASE=1) I am running this for quite some time function randAlloc(){var r=Math.random()*2*65535|0;var a=new Uint8Array(r);for(var i=0;i<r;i+=10)a[i]=i;return a;}
var a,b;
setInterval(()=>{a=randAlloc();},3000);
setInterval(()=>{b=randAlloc();},5000);
setInterval(()=>{var x=5;E.defrag();},4000); and so far the console works, no error messages/crashes, looks good so far EDIT: also added setInterval(()=>{print(process.memory());},5500);
function check(arr){var r=arr.length;for(var i=0;i<r;i+=10) if(arr[i]!=i%256) print("error ",i);}
setInterval(()=>{Math.round(Math.random())?check(a):check(b);},3600); just to see some output and everything is still good. |
tested a bit over weekend but testing is a bit tricky, the stuff above is too slow and gives out of memory and freezes quickly. var ratio=1.5;
function randAlloc(){var r=Math.random()*ratio*65535|0;ratio=1/ratio;var t=getTime();var a=Uint8Array(r);print(r,"took",(getTime()-t)*1E3,"ms"); t=getTime();for(var i=0;i<r;i+=100)a[i]=i%256;print(r,"iteration step",(getTime()-t)*1E5/r,"ms, addr",E.getAddressOf(a,true).toString(16)); return a;}
var a,b;
setInterval(()=>{a=Uint8Array(1);a=randAlloc();},6000);
setInterval(()=>{b=Uint8Array(1);b=randAlloc();},5000); example output attached Overall it works, I saw no corruption but lot of out of memory situations (see end of the log), with shorter intervals even freeze (as the code inside took longer than next interval came?). It was surprising that allocation of the array always depends on the size (even for case with flat array = one block). Also what is strange is that tab completion on the array properties also depend on size. var a=new Uint8Array(10), then typing a.le+tab fills 'length' immediately but when the array is larger it take more and more time, for 60000 array it is significant. It is same even right after |
Interesting, thanks! What could be happening with the test is that the memory is getting fragmented and then it's not able to allocate a flat area of memory for the array - so instead it allocates it as a normal string, which would be slow to access, as you need to iterate to the correct point inside them. Allocation will be slow too since it's having to iterate to find a free area - but the idea is that especially for big arrays you allocate once and then re-use it.
That is interesting! I guess it's not surprising in retrospect - we have a function that iterates over all fields inside an object (jswrap_object_keys_or_property_names_cb) that is used for Object.keys/for..in/etc. Tab complete just uses that so I guess it checks every array element! I've stuck a fix in for that now. Where are your changes to enable this? Is it literally just what I posted plus the two changes you mentioned above? |
Yes. In both cases I just removed it
the
Yes, indeed, I just grab one big buffer at the beginning. It makes sense that in case of fragmented space it takes time to fit the fragmented string into holes, however if just allocating one piece why it takes longer to grab it. Maybe clearing to zero take 21ms here?
BTW this doesn't look OK, shouldn't |
Ok, great - I think it's good to error if an arraybuffer is too big, and now we have a define for the max size so I'll just tweak that.
Maybe it's worth statically allocating it, and then using
Because it still has to check every JsVar in the line is empty before allocating, and then as you say it must clear it. I think that's probably it.
Yes, it should do - that looks very strange... |
Ok, just merged in 35e8f24 |
Great, I just synced with your changes and it still works. However even with recent fix you did, the
Like hardcoding in the firmware build and reducing variables? I wanted flexibility of selecting bit depth at boot time to have more colors or more free memory. |
oh, sorry, no, just after I wrote it I got it again :-(
|
Ahh, ok. But yes, hard-coding it would make life easier probably. The I think you will still get the MEMORY area for the reasons I mentioned before (fragmentation) if you keep allocating alternately though. You could try running |
only after memory error. I have replicated it also with clean older build before arrays over 64KB were added in LINUX build.
|
Thanks! Just fixed this with 90d13c1 - I'd been imagining it was |
So... do we think this one is actually closed now? I think we're probably good... |
Yes it is the
this is still without the fix, after updating to your fix both var and without var works fine |
as per http://forum.espruino.com/conversations/366505/#16122927
Array index for typed arrays is now 16 bit so one cannot make arrays over 64k
Couple of targets now have SRAM >=128KB so bigger arrays can be practical for data or framebuffer
It would be nice to add at least a bit or two so arrays up to 128/256KB are possible. LINUX target could use even more.
The text was updated successfully, but these errors were encountered: