Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

DarkBASIC Professional Discussion / Pro Tip: Reduce Power Consumption...

Author
Message
Mage
17
Years of Service
User Offline
Joined: 3rd Feb 2007
Location: Canada
Posted: 10th Jan 2013 07:46 Edited at: 22nd May 2013 16:12
I am working on a rather large (and very far along) game off and on in my spare time. I make use of a lot of editors made in DBP to enhance and package together media like sounds, textures, objects in ways that make it easier for the game to organize and load them.

For Example: My Character Editor loads and saves Character files that store texture and object path names along side inventory lists and stats.



I realized that I was only getting about 50 minutes of battery life with the editor open. The old familiar DBP performance behavior was to blame. The frame rate was probably in the high 800's and nothing was happening 99% of the time on screen. A massive astronomical waste of resources.

I managed with just two techniques to reduce the footprint of the editor from the level of "Call of Duty", to something approaching "Notepad".


Problem 1:
Runaway frame rate way higher than anything the screen needed was solved by implementing a frame limiter. This ensures any time the screen is rendering, it's at least reasonably efficient.

Processor Friendly Frame Limiter Example:



Problem 2:
99% of the time nothing is happening and drawing the screen over and over is a waste. This was solved by implementing a Standby Mode feature.
We've all checked task manager. Games run at 100% of 1 CPU core, in some cases with plugins or sound maybe a bit more. Pointless if the screen isn't changing.

Standby Mode Example:



The usage of these functions is as follows:





Now the CPU level stays at 0%. The program from the perspective of the user operates exactly the same without any hint of disruption or removal of functionality.


The Principle Behind The Idea:
When the program isn't doing anything it checks to see if the keyboard and mouse are idle and loops into a processor friendly sleep, where it keeps checking the inputs. If an input changes then it exits the loop, and allows the program to continue. Since this happens so fast, it doesn't disturb the user. Because the screen contents aren't changing when the user isn't moving the mouse or typing, having the program do "nothing" doesn't look or feel any different and is about several million times less workload.


The result? Laptop battery lasts over 3 hours. The fans don't turn on. It doesn't get hot.


See my previous tip here...
http://forum.thegamecreators.com/?m=forum_view&t=199942&b=1


Edit: Made a code correction above, and added a demo. No media required.


Green Gandalf
VIP Member
19
Years of Service
User Offline
Joined: 3rd Jan 2005
Playing: Malevolence:Sword of Ahkranox, Skyrim, Civ6.
Posted: 10th Jan 2013 17:02
Sounds good. I'll give that a try in my next demo.

From the sound of things I know a few commercial games that could do with something similar.
MrValentine
AGK Backer
13
Years of Service
User Offline
Joined: 5th Dec 2010
Playing: FFVII
Posted: 10th Jan 2013 19:33
hmm... can you put op a demo of this? would like to see exactly how it works... a video at the least

I just cannot see this not creating a multitude of issues...

[Various time dependent effects and such]

Chris Tate
DBPro Master
15
Years of Service
User Offline
Joined: 29th Aug 2008
Location: London, England
Posted: 10th Jan 2013 22:59
Good points

Mage
17
Years of Service
User Offline
Joined: 3rd Feb 2007
Location: Canada
Posted: 11th Jan 2013 03:53 Edited at: 11th Jan 2013 04:01
Here's a working Demo that will compare No Optimizations, Sync Rate 30, CPU Frame Limiter, and Standby Mode.



Also I made a code correction in my initial post. The CPU Friendly Frame Limiter now works correctly. There was a problem with undocumented command behavior.

Phaelax
DBPro Master
20
Years of Service
User Offline
Joined: 16th Apr 2003
Location: Metropia
Posted: 11th Jan 2013 22:34
Wouldn't it be easier just to plugin your laptop?

"You're not going crazy. You're going sane in a crazy world!" ~Tick
Chris Tate
DBPro Master
15
Years of Service
User Offline
Joined: 29th Aug 2008
Location: London, England
Posted: 11th Jan 2013 22:50 Edited at: 11th Jan 2013 22:50
There's no socket outside

James H
16
Years of Service
User Offline
Joined: 21st Apr 2007
Location: St Helens
Posted: 12th Jan 2013 02:43
Nice tip, will do nicely for when I get my own place which will have an electric meter, so usefull for desktops too
Phaelax
DBPro Master
20
Years of Service
User Offline
Joined: 16th Apr 2003
Location: Metropia
Posted: 12th Jan 2013 04:12
Laptop screens are visible outside in the sunlight silly!

"You're not going crazy. You're going sane in a crazy world!" ~Tick
Chris Tate
DBPro Master
15
Years of Service
User Offline
Joined: 29th Aug 2008
Location: London, England
Posted: 12th Jan 2013 04:43
lol

Mage
17
Years of Service
User Offline
Joined: 3rd Feb 2007
Location: Canada
Posted: 12th Jan 2013 08:24 Edited at: 12th Jan 2013 08:32
Just a couple of points to convey how important a concept like this is and to explain some key areas where I think it matters most...




Desktops Need This Too:
It's not just a Laptop battery...

Computers heat up. The fans get louder. Some of them even overheat. Then there's the whole thing about multi-tasking. Having a program that sucks 100% of the GPU and CPU because it lacks any efficiency, sucks. Why use resources if you don't need them?
If you are using a laptop or a tablet, you get a short lived battery and sweaty hands as the heat pours out of the thing.
Desktop computers get hot enough to crash.


Everybody Needs A Proper Frame Limiter:
The idea here is that if your program is performing above the 30 or 60 or whatever frames per second you feel is ideal, you can convert that extra time into rest periods for the CPU and GPU. This technique won't drag on the performance if you are under the target frame rate. So it's an all around win.
If you are exceeding your target performance, give the hardware the spare time to rest.


Standby Mode Isn't For Every Situation:
If you have a game that is input driven like a card game or Sudoku, once you draw the screen, you don't need to draw it again until the user does something. So you can effectively put the thing into a looped CPU friendly sleep checking for conditions periodically.
If you are like me with an Editor, the screen stays the same until I press a button. So why keep drawing it over and over?
This doesn't even need to be user input based. You could rig this to wake up when network signals are received, or some other condition.


Designing Modern Software:
This is about designing modern software. I could ask why not use dark basic pro to make a card game, or mine sweeper, or a non-game application. It's unsuitable. The thing would have 100% CPU utilization at all time. People would consider it a complete joke. But if you apply a technique like the one I've displayed above, then you can write professional software on a level that is competitive. Being Dark Basic is no longer such a limiting factor.


Action Games:
It's true that games like "Call of Duty" or "Skyrim" don't get a lot of opportunity to have use of a Standby Mode. The screen is always changing. These types of games greatly benefit from a CPU Friendly Frame Limiter. Let's say you decide 30 Frames Per second is ideal for your game (like XBox Games). If your game is hitting 60 frames a second, then with a proper CPU frame limiter you can drop that to 30 frames a second, and spend half the time resting the hardware. Literally cut the hardware workload in half. This is on a per frame basis, so it's smooth. If you are at 500 frames per second then dropping to 30 you get the performance you want, and the computer is resting almost all the time.


Crappy Frame Limiters:
If you use Do Loop, While EndWhile, Sleep, Sync Rate the CPU is going to stay maxed out. You'll give the GPU a break but not the CPU. You'll be selling yourself short. These methods just run the CPU in a loop instead of resting. Use Sync Sleep or IAN M's plugin's CPU friendly sleep.


Using Spare Time To Process More
When you have a needlessly high frame rate, it means you have a lot of spare time, and the program is simply using it to draw frames more or at a higher rate.
It's been argued before that you can use this time to do more work, like physics, etc. To literally use all the spare time, no matter how much, doing extra work. This has it's benefits in exceptional cases. However this concept is about 10 years out of date. If you are already hitting your performance targets, that extra processing is largely pointless. It's just not worth having a CPU at 100% instead of 50%, or a having a battery last a fraction of the time. You trade away too much for too little.


I hope this contribution helps improve things across the community.

Morcilla
21
Years of Service
User Offline
Joined: 1st Dec 2002
Location: Spain
Posted: 12th Jan 2013 11:38
Yop, great contribution in my opinion

Of course I'll give this a try, DBPro is not power-save friendly by default and it is a very much needed feature nowadays.

Now, could you explain a little bit the insights of 'sync sleep'?
This function doesn't seem to be implemented in DGDK, and I'd like to give it an approach, if possible.

Thank you, and.. good job!

Libervurto
17
Years of Service
User Offline
Joined: 30th Jun 2006
Location: On Toast
Posted: 13th Jan 2013 04:52 Edited at: 13th Jan 2013 05:12
Quote: "Wouldn't it be easier just to plugin your laptop?"

We are coders not technicians!

@Mage
Nice suggestions, I hope you don't mind me having a poke around with the code.


There is no need to test the state of standby_level since it is boolean: when all the conditions are met standby_level is set to 1 so it makes no difference if it was 1 to begin with.
Having this first condition doesn't even save the processor from analysing the lower conditions because whenever standby_level=1 it will be stuck in the standby loop anyway.
You can replace conditions with maths logic if you're only assigning values and not executing commands on condition; I think it's neater and I believe it processes quicker too. (You just have to remember that "*" is AND and "+" is OR.)

I tried to make it as small as possible, not sure if recursion like this would cause a stack overflow though.

One-liner! Haven't tested it:


Shh... you're pretty.
Mage
17
Years of Service
User Offline
Joined: 3rd Feb 2007
Location: Canada
Posted: 13th Jan 2013 07:49 Edited at: 13th Jan 2013 08:22
Quote: "There is no need to test the state of standby_level since it is boolean: when all the conditions are met standby_level is set to 1 so it makes no difference if it was 1 to begin with.
Having this first condition doesn't even save the processor from analysing the lower conditions because whenever standby_level=1 it will be stuck in the standby loop anyway.
You can replace conditions with maths logic if you're only assigning values and not executing commands on condition; I think it's neater and I believe it processes quicker too. (You just have to remember that "*" is AND and "+" is OR.)"


With respect, I disagree.
The reason that test is there is because immediately before posting the code it wasn't boolean. I had set it to a 5 stage system. This caused the program to always draw 4 more times before entering into sleep. I had thought that this was needed in special case scenarios. After releasing a key press, programs would sometimes "Standby" before updating the screen. I refined the Standby_Clear() function to fix this problem, so I changed it to a boolean system . I didn't remove the test since it's proper form to keep it, and it's more efficient.

As for your more efficient notation, it reduces the amount of lines, but it slightly hurts active performance. I'll explain why. First I'll say I timed 1000000 loops on both methods and compared total time. In my method I check if standby_level is 0 and it skips a bunch of stuff. This is actually faster than the "maths logic" by about 6 times in this specific case. This is merely because I am skipping work that you are doing each and every time (a couple lines of code). Then the sleeping loop you are using is slightly more work. We're talking several millionths of a percent. We do the same work to exit the loop, almost. I basically removed the function call/jump in your method so i could do the timing, that might add some workload. I'm not liking the look of that thing in there.

(Also transplanting your first example into the demo crashes the demo.)

All in all it amounts to probably 2 seconds of battery life. I favored the easier to read approach for a demonstration.

By all means, take me to task. I want a method that is better than I can build myself. Thanks for looking into this.


Edit:
I built a better test, and added my ghetto Timing Demo here. I'm showing your second method outside of Standby as being roughly 600 times slower.



Edit: Okay I tested your first method outside of standby like I did originally and it's showing 6 times slower like originally mentioned.


I'm thinking that condensing stuff onto the same line, in this style is causing unnecessary workload. The program is able to skip less and less stuff so performance suffers.

BatVink
Moderator
20
Years of Service
User Offline
Joined: 4th Apr 2003
Location: Gods own County, UK
Posted: 13th Jan 2013 17:05 Edited at: 13th Jan 2013 17:06
You'll see my Enhanced for Intel Core accreditation in my signature. I got this by using NICE SLEEP, but essentially in conjunction with:

set timer resolution 1

This is the crux of better battery life. When the user starts working again:

set timer resolution 0

Without it, you wouldn't get the accreditation, as their benchmark tools would deem your app as not suitable for battery usage.

Mage
17
Years of Service
User Offline
Joined: 3rd Feb 2007
Location: Canada
Posted: 13th Jan 2013 21:21 Edited at: 13th Jan 2013 21:22
Thanks for the help.

Can you explain fundamentally what set timer resolution does to improve power consumption in this scenario?


Here is a version of the demo using Ian M's plugin and using your suggestion of Set Timer Resolution. I did not use set timer resolution with the frame limiter, as I can't verify if rapidly changing the setting would drag on performance.


Libervurto
17
Years of Service
User Offline
Joined: 30th Jun 2006
Location: On Toast
Posted: 13th Jan 2013 23:10 Edited at: 13th Jan 2013 23:15
@Mage
In your test your method never set the state to 1 so it never entered the while loop, i changed it but that loop slows it down so much I think it skewed the results in the other direction. So I decided to change all the conditions to ones and just compare the speed of pure conditions vs maths.

It's very close.

Two things that could speed it up: I think you could get away with just checking one axis on the mouse as it's pretty hard to move one independently, you could use mousemovex() too instead of storing another variable.

Shh... you're pretty.
Mage
17
Years of Service
User Offline
Joined: 3rd Feb 2007
Location: Canada
Posted: 14th Jan 2013 04:04 Edited at: 14th Jan 2013 04:09
Quote: "In your test your method never set the state to 1 so it never entered the while loop, i changed it but that loop slows it down so much I think it skewed the results in the other direction. So I decided to change all the conditions to ones and just compare the speed of pure conditions vs maths."


Yes that was the entire point. I deliberately forced it to avoid entering the loop to compare maths vs. conditions methods. The result was outside of the loop, conditions is 6 times faster and inside the loop where you can't skip any conditions it's faster by a much smaller amount. This difference is probably insignificant, likely several seconds of battery life realistically.

The one-liner version was incredibly slower however, and should be avoided.

Quote: "Two things that could speed it up: I think you could get away with just checking one axis on the mouse as it's pretty hard to move one independently, you could use mousemovex() too instead of storing another variable."


I think skipping the checking of both axis would be bad form. Also it's not that difficult to move the mouse along one axis. People who Photoshop are accustomed to doing this often. Additionally it's even easier at lower resolution, and with low DPI mice.
MouseMoveX(), MouseMoveY() excellent suggestion I'll update the code I posted to take advantage of this. They are ever so slightly faster, but have the advantage of not needing memory.
Thanks for the help.

Burning Feet Man
16
Years of Service
User Offline
Joined: 4th Jan 2008
Location: Sydney, Australia
Posted: 14th Jan 2013 06:02
Ahh sync sleep... There be dragons here. I remember I wrote down a bug that I finally figured out in a project from ages ago; it reads;

`Sync sleep causes instability with frame rate and timer base movement.

So, I guess from my note, sync sleep is OK to use, but when using both Sync Sleep & Timer Based movement, a strange distracting jitter can start occurring.

Can anyone else comment on the use of Sync Sleep and a TBM function?

Help build an online DarkBASIC Professional help archive.
DarkBasic Help Wikia
Mage
17
Years of Service
User Offline
Joined: 3rd Feb 2007
Location: Canada
Posted: 14th Jan 2013 09:39 Edited at: 14th Jan 2013 10:03
I haven't noticed any instability relating to timer based movement.

This might come down to something specific to your situation, for example I've seen jitter related to storing decimal numbers for rotations and position in integers unwittingly. This caused a slight and weird jitter until i discovered my mistake. Also I don't use a sleep value greater than 1. It appeared to be inaccurate as values increased. This could cause erratic frame rate.

As far as Sync Sleep goes, I don't fully trust it. I've noticed that some days the timing will be perfect, and then the next day the same code is consistently producing the wrong timing, to a small degree. It's rare, but I've seen it. I used Sync Sleep 1 to mitigate any possible problems and as result I haven't seen any. Sync Sleep 1 is placed inside of a loop that does it's own rapid time checks instead of passing the whole time block at once to the command. This means I rely as little as possible on the command to manage it's own timing. I'm starting to suspect that sometimes Windows has problems returning to the program in a timely manner, like being several percent off. My first attempt was to use Sync Sleep in the frame limiter for the exact time needed to sleep. The way I understand the issue Nice Sleep would see the exact same problem.

I tested Timer Based Movement just now and didn't experience any jittery feel. The Frame Rate appeared to be capped at a little under 60 frames per second.

If Sync Sleep / Nice Sleep turns out to be too unreliable. I will simply correct the problem by keeping track of how long Sync Sleep 1 is really taking and having the timing compensate accordingly. This is not a serious problem.

Burning Feet Man
16
Years of Service
User Offline
Joined: 4th Jan 2008
Location: Sydney, Australia
Posted: 14th Jan 2013 10:40
Just to clarify, Sync sleep works great, and Timer Based Movement works fine. It's the mixing of them together that causes a jitter, usually a jump every 2 seconds?

Help build an online DarkBASIC Professional help archive.
DarkBasic Help Wikia
Mage
17
Years of Service
User Offline
Joined: 3rd Feb 2007
Location: Canada
Posted: 14th Jan 2013 21:35
Clarification: I' ve never had any jitter using this method. It's probably the way i' m using Sync Sleep.

Burning Feet Man
16
Years of Service
User Offline
Joined: 4th Jan 2008
Location: Sydney, Australia
Posted: 14th Jan 2013 22:51 Edited at: 14th Jan 2013 23:08
I've sliced in a TBM subroutine and function. I get the following framerates for each test; 500+, 30, 12 & 6.

I believe the jerkiness I'm talking about isn't visible with this particular demo, as it's a simple spinning cube, but will become visible with a few cubes sliding around at different speeds.



Help build an online DarkBASIC Professional help archive.
DarkBasic Help Wikia
Mage
17
Years of Service
User Offline
Joined: 3rd Feb 2007
Location: Canada
Posted: 15th Jan 2013 06:32 Edited at: 15th Jan 2013 07:05
Quote: "I believe the jerkiness I'm talking about isn't visible with this particular demo, as it's a simple spinning cube, but will become visible with a few cubes sliding around at different speeds. "


First of all, watching the cube spin is a bad approach. Optical illusion effects and perspective are going to make it appear to slow and speed up. If you really want to know, measure the constant rate of speed based on time. Literally measure the angle every few ms and display the difference on screen. Measure how long each rotation takes. I did this and the rate is constant within several thousandths of a degree.


Timer Based Movement Smoothing Is Terrible...
Secondly, It's very interesting that you show me that timer based movement code. One of the great and epic 1v1 debates of this forum over the years was between me and a guy who wrote that timer based movement code.

You are "smoothing" your timer based movement across 30 frames. This makes the correction calculations of the timer based movement (literally the entire purpose of it) incredibly inaccurate when frame rate is erratic or changing. Literally your timer based movement code is providing the wrong corrections at times and because of this, objects appear to slow and speed up on screen. And that's the whole misguided point of smoothing.

You see people complained about jitteryness and lag spikes in their programs. "Smoothing" timer based movement was a "paint over the problem" approach. Rather than addressing the lag and jitter (rapid operations and inefficiency in the program taking too long) a broad brush shortcut was taken. The problem is if every several milliseconds you get a slow frame, or a particularly fast one, you get jitter because the gimmick fails. The program doesn't keep a constant speed. The averaged corrections no longer match the correct values. You didn't see this in my demo because the frame rate is nearly constant.

Normally frame rate goes up and down and the program changes speeds. Timer based movement corrects the speed of the program to remain constant. Program is moving at double speed? Move objects at half speed to compensate. You're only using an average value. So it's only ever going to be accurate if the frame rate is constant.

I am surprised more people haven't stepped in to correct people on this. Smoothing is really a terrible idea. You can prove this yourself, just add SLEEP RND(60) + 1 into the loop to make the frame rate erratic. Suddenly the cube isn't just getting choppy, it's literally changing speeds too.

Nothing is perfect, but this is a much better method:


Don't shortcut timer based movement, find the lag spikes and address them directly.

Login to post a reply

Server time is: 2024-03-19 02:25:41
Your offset time is: 2024-03-19 02:25:41