It is currently February 27th, 2021, 10:32 pm

[Trick | Guide] Performance: another update principle - the mechanism within

Tips and Tricks from the Rainmeter Community
User avatar
deflore08
Posts: 129
Joined: July 12th, 2020, 7:47 am

[Trick | Guide] Performance: another update principle - the mechanism within

Post by deflore08 »

Hey there! I haven't been a long time here, but i'm sure, you didn't missed me so much. :D Happy new year!

Today i want to share a thing that saved me once. I am pretty sure, it might help you with biiiig stuff.

If you working with big skins, early or lately you will find your skin as fat turtle, what causes you system to be freezed. My own opinion Rainmeter isn't good platform for writing an endpoint applications (like microsoft office, for example), so we can't really get good performance in a huge skins (only if are not from Terra Incognita and you don't speak Lingua Incognita, of course :welcome: :D) with usual update mechanism.

I suggest you another way to manage updates cycles inside your skins.

First we have to realize how standart mechanism works. For example, if you have Update rate 1000ms, then each 1000ms Rainmeter updates everything inside. Each measures, each meter, resolving each dynamic variable and so on. Sure, we can avoid general update cycle by using positive or negative dividers, but look where we are: imagine your CPU in the moment as bottle neck. The bottle is wide (2 liter, for example), but the neck is narrow. While a stuff that you want to put inside bottle through the neck is not wider than neck all is ok. When stuff is bigger than neck - we getting some freezes, because CPU cannot resolve all things instantly. The main problem in general update cycle - it cannot be managed. You cannot handle how many stuff put at a time, Rainmeter always trying to put all at once. You may have even Update = 24 hours, once per day you'll get a freeze, because.. In addition, every update calls [!Redraw] function, so we've got additional pressure on hardware.

Thus, as we understand the problem now, we can think how to fix that. Rainmeter allows us to use negative update time (Update = -1) and negative dividers (DefaultUpdateDivider = -1), so we can freeze a skin. Also we can invent something like cycle inside, based on.. CALC measure. Let's see:

Code: Select all

[Rainmeter]
 Update = -1
 DefaultUpdateDivider = -1

 OnRefreshAction = [!SetVariable Cycle "0"][!Delay 400][!SetVariable Cycle "1"][!UpdateMeasure Update_Cycle]
 
[Variables]
 Cycle = 0
 Delay = 16
 
[Update_Cycle]
 Measure = CALC
 Formula = #Cycle#
 DynamicVariables = 1
 Disabled = 0
    ifCondition = #CURRENTSECTION# = 1
        ifTrueAction = DO SOMETHING [!SetVariable Cycle "(#Cycle# + 1)"]#Delay#[!UpdateMeasure #CURRENTSECTION#]

    ifCondition2 = #CURRENTSECTION# = 2
        ifTrueAction2 = DO SOMETHING [!SetVariable Cycle "(#Cycle# + 1)"]#Delay#[!UpdateMeasure #CURRENTSECTION#]

    ifCondition3 = #CURRENTSECTION# = 3
        ifTrueAction3 = DO SOMETHING [!SetVariable Cycle "(#Cycle# + 1)"]#Delay#[!UpdateMeasure #CURRENTSECTION#]

    ifCondition4 = #CURRENTSECTION# = 4
        ifTrueAction4 = DO SOMETHING [!SetVariable Cycle "(#Cycle# + 1)"]#Delay#[!UpdateMeasure #CURRENTSECTION#]

    ifCondition5 = #CURRENTSECTION# = 5
        ifTrueAction5 = DO SOMETHING [!SetVariable Cycle "1"]#Delay#[!UpdateMeasure #CURRENTSECTION#][!Redraw]

As we have got a static skin, we should animate it. On refresh (and on load) the #Cycle# variable will be set to 0 and after short delay (it's better to have delay here, trust me) it will be set to 1 and then our cycle will start count. On every step #Cycle# will be grow by 1 and each cycle's step we can use to DO SOMETHING (update some groups, meters and so on). On 5th step #Cycle# will set to 1 and cycle will become a LOOP, and skinn will be redrawed. #Delay# set to 16 and mean 16s delaying after each action. As you know, it's a real minimum delay between two actions in Rainmeter. Now we've got control on updates, because we can manage how many groups, meters, variables, measures and other things we want to refresh on each step, so we could to put in bottleneck as many as we want, and finally avoid freezes. How to count a real update interval? Multiple your delay on cycle's steps - 16x5 = 80ms in this test case.

Also you can use more that 1 cycle and make an dividers analog, to avoid unnecessary updates for some things like weather, for example.

The next step i recommend to use is a OnChangeAction dependency chains. There is no reasons to update 10-100 meters, if nothing changed, yeah? ;)

As you can guess, this method is not perfect by some reasons:

1) General update have big priority in Rainmeter, so even you have system lags - you have miminal freezes inside skin. The mechanism mentioned above have no priority and executing like any other thing inside a skin. What is this means? Activating an animation or something else enough "hard weighted" will cause your SKIN to be freezed while processing. Also it means, your skin lose priority before other loaded skins. Remember this moment.

2) It's hard to manage. You must have a good organisation inside your skin, good group-targeting and fine logic, before you will be able to completely replace standart mechanism.

However it's a great solution when:

A) Your skin has grown so big and you feel sorry for your PC and your users;

B) You are just crazy and want to be not as everyone. :D

In my case this approach let me lower CPU utilization from 12% to 0.8%, avoid freezes, to become successful, to buy a lamborghini and to heal hemorrhoids, haha! Happy new year! :) *beer grabbing sounds*