Global context performance and best practices

Hi folks… I have a question about using the global context.… I have a large-ish state vector which is an array of 55 elements each with a subarray of about seven elements that defines various characteristics of a 10 meter musical keyboard I'm (re)building. I currently am storing that array of a raise is a global context… Then transforming it by writing nodes that fetch the state array from the global context via
state= global.get("state")
, make some changes to the state vector and then re save it in the global context via a
global.set("state", state) .
I'm starting to notice some performance problems when calling lots of the transformation nodes while running on a RasPi 4. Eg. when I call a node that does some permutations to the state vector every 100ms that changes the lights on the keys of the instrument, I notice a lag in response

is that to be expected using a Raspi 4 ? .. Is there some better practice in passing global state vector around that might be faster ?

I know there's lots of 'depends' in the question I'm asking..
Any guidance much appreciated

-jc

I don't think the size is necessarily and issue - though check the OS to see if SWAP is being used. If it is then you need more RAM or need to remove other things from memory. Make sure you aren't running a desktop on the Pi.

I suspect that the 100ms is more of an issue.

There are lots of other things you could potentially do to optimise performance but it is hard to comment with such little to go on.

Lets start with the SWAP issue anyway, if you can report back on that, maybe we can help hone in on other things that could be optimised.

Hi, regarding "best practice" - I would recommend you store data in an object as a lookup instead of an array (saves CPU cycles by not having to scan the array each time I want to find an object).

e.g. storing data

{
  "device1": { "name" : "main light", "state": "on"}, 
  "device2": { "name" : "lamp", "state": "on", "ip": "123.123.123.123", "more-settings": [1,2,3,4,5] }, 
   // etc ...
   //etc ...
  "device9": { "name" : "hall light", "state": "off", "type": "not hue :)"}, 
}

accessing and updating is now a simple lookup....

var state = global.get("state");
var device = state["device9"]; 
device.state="on"; 
var state = global.set("state", state);

note: regarding your "state vector" of 55 elements, this is gonna be a huge difference (perhaps 1 or 2 milliseconds) but if you are also searching sub arrays and doing it often, it can add up.

You may find the https://flows.nodered.org/node/node-red-contrib-unsafe-function useful if overall processing time needed to be as low as possible.

1 Like

And to add to what @hotNipi said, if you are using JSONata, don't. JSONata is an order of magnitude slower than plain js.

So... if a flow context is created, for example;
flow.set('router',{"status":0,"reset":false});

Is it also correct to write context like;
flow.set('router.status', 4);
and
flow.set('router.reset', true);

The above example works, but I wondered if it's good practice to update a context object this way.
(of course in this example, the speed difference between an array & object would be negligible).

Is it already proven that it is limited by cpu power ? You can easily check this by monitoring the CPU (e.g. by the ‘top’ command). If it is cpu bound then one of the 4 cpus should run at 100%.

A good question. That I can't answer (Nick might have some future file writing optimisation that favours that method when persisting context to file).

I do know that I don't do that, I always go directly to the object. Probably because it's habit/direct/pure js.

Do you mean if you pass the full path to flow.get the difference is negligible? I agree but then updating an item in an array if you know it's index is likely faster than an object lookup. The point was searching an array vs an object lookup.

Hope that nonsensical rambling was of some use :wink:
Happy new year.

If it is cpu bound and a message is send every 100 ms then I would also expect that the lag will become greater and greater over time.

Thanks & happy new year.

One of the advantages I've found using Steve's lookup example above, is that name/value pairs make it very easy to avoid selecting or saving a value to the wrong index, [0], [1] etc.

And makes complete sense when looking at the context sidebar.

lookup

Hopefully you will find this thread useful as well - I started it as there are quite often discussions like this going on and I thought it would be useful to have everything in 1 place:

[Reference] Optimising Node-RED - General - Node-RED Forum

Please add to it with any new discoveries.

Nice work Julian!