1

Recently I have been revising some of my old python codes, which are essentially loops of algebra, in order to have them execute faster, generally by eliminating some un-necessary operations. Often, changing the value of an entry in a list from 0 (as a python float, which I believe is a double by default) to the same value, which is obviously not necessary. Or, checking if a float is equal to something, when it MUST be that thing, because a preceeding "if" would not have triggered if it wasn't, or some other extraneous operation. This got me wondering about what will preserve my battery more, as I do a some of my coding on the bus where I can't plug my laptop in.

For example, which of the following two operations would be expected to use less battery power?

if b != 0: #b was assigned previously, and I know it is zero already
    b = 0

or:

b = 0

The first one checks if b is zero, and it is, so it doesn't do the next part. The second one just assigns b to zero without bothering to check. I believe the first one is more time-efficient, as you don't have to change anything in memory. Is that correct, and if so, would it also be more power-efficient? Does "more time efficient" always imply "more power efficient"?

Lundin
  • 195,001
  • 40
  • 254
  • 396
iammax
  • 453
  • 2
  • 5
  • 18
  • Honestly such tiny change will make absolutely no noticeable difference. I don't know what kind of changes you were hoping for? Maybe a few extra milliseconds of battery life? Any changes you make that provide even significant energy savings will be dwarfed by the energy cost of running your laptop, screen, os etc. If you want noticeable efficiency then code your own os in assembler or c to meet your own specific needs. – Paul Rooney Jun 26 '17 at 23:25

4 Answers4

1

I suggest watching this talk by Chandler Carruth: "Efficiency with Algorithms, Performance with Data Structures" He addresses the idea of "Power efficient instructions" at 4m 49s in the video. I agree with him, thinking about how much watt particular code consumes is useless. As he put it

Q: "How to save battery life?"

A: "Finish ruining the program".

Also, in Python you do not have low level control to be even thinking about low level problems like this. Use appropriate data structures and algorithms, and pray that Python interpreter will give you well optimized byte-code.

0

Does every simple mathematical operation use the same amount of power (as in, battery power)?

No. It's not the same to compute a two number addition than a fourier transform of a 20 megapixel photo.

I believe the first one is more time-efficient, as you don't have to change anything in memory. Is that correct, and if so, would it also be more power-efficient? Does "more time efficient" always imply "more power efficient"?

Yes. You are right on your intuitions but these are very trivial examples. And if you dig deeper you will get into uncharted territory of weird optimization that's quite difficult to grasp (e.g., see this question: Times two faster than bit shift?)

Josep Valls
  • 5,483
  • 2
  • 33
  • 67
  • 1
    The key point being "simple", like a single peration. Adding two numbers is probably one operation in your CPU. A fourier transform of a giant photo is going to be a large number of them. – iammax Jun 26 '17 at 22:36
  • Do you have any particular reason to believe the questioner's intuition is correct? – user2357112 Jun 26 '17 at 22:37
0

In general the more your code utilizes system resources the greater power those resources would use. However it is more useful to optimize your code based on time or size constraints instead of thinking about high level code in terms of power draw.

One way of doing this is Big O notation. In essence, Big O notation is a way of comparing the size and or runtime complexity of an algorithm. https://rob-bell.net/2009/06/a-beginners-guide-to-big-o-notation/

A computer at its lowest level is large quantity of transistors which require power to change and maintain their state. It would be extremely difficult to anticipate how much power any one line of python code would draw.

J. Clark
  • 179
  • 1
  • 11
0

I once had questions like this. Still do sometimes. Here's the answer I wish someone told me earlier.

Summary

You are correct that generally, if your computer does less work, it'll use less power.

But we have to be really careful in figuring out which logical operations involve more work and which ones involve less work - in this case:

  1. Reading vs writing memory is usually the same amount of work.
  2. if and any other conditional execution also costs work.
  3. Python's "simple operations" are not "simple operations" for the CPU.
  4. But the idea you had is probably correct for some cases you had in mind.
  5. If you're concerned about power consumption, measure where power is being used.

For some perspective: You're asking about which Python code costs you one more drop of water, but really in Python every operation costs a bucket and your whole Python program is using a river and your computer as a whole is using an ocean.

Direct Answers

Don't apply these answers to Python yet. Read the rest of the answer first, because there's so much indirection between Python and the CPU that you'll mislead yourself about how they're connected if you don't take that into account.

I believe the first one is more time-efficient, as you don't have to change anything in memory.

As a general rule, reading memory is just as slow as writing to memory, or even slower depending on exactly what your computer is doing. For further reading you'll want to look into CPU memory cache levels, memory access times, and how out-of-order execution and data dependencies factor into modern CPU architectures.

As a general rule, the if statement in a language is itself an operation which can have a non-negligible cost. For further reading you should look into how CPU pipelining relates to branch prediction and branch penalties. Also look into how if statements are implemented in typical CPU instruction sets.

Does "more time efficient" always imply "more power efficient"?

As a general rule, more work efficient (doing less work - less machine instructions, for example) implies more power efficient, because on modern hardware (this wasn't always this way) your hardware will use less power when it's not doing anything.

You should be careful about the idea of "more time efficient" though, because modern hardware doesn't always execute the same amount of work in the same amount of time: for further reading you'll want to look into CPU frequency scaling, ARM's big.LITTLE architectures, and discussions about the "Race to Idle" concept as a starting point.

"One Simple Operation" - CPU vs. Python

Your question is about Python, so it's important to realize that Python's x != 0, if, and x = 0 do not map directly to simple operations in the CPU.

For further reading, especially if you're familiar with C, I would recommend taking a long look at how Python is implemented. There are many implementations - the main one is CPython, which is a C program that reads and interprets Python source, converts it into Python "bytecode" and then when running interprets that bytecode one by one.

As a baseline, if you're using Python, any one "simple" operation is actually a lot of CPU operations, as each step in the Python interpreter is multiple CPU operations, but which ones cost more might be surprising.

Let's break down the three used in our example (I'm primarily describing this from the perspective of the main Python implementation written in C, called "CPython", which I am the most closely familiar with, but in general this explanation is roughly applicable to all of them, though some will be able to optimize out certain steps):

x != 0

It looks like a simple operation, and if this was C and x was an int it would be just one machine instruction - but Python allows for operator overloading, so first Python has to:

  1. look up x (at least one memory read, but may involve one or more hashmap lookups in Python's internals, which is many machine operations),
  2. check the type of x (more memory reading),
  3. based on the type look up a function pointer that implements the not-equality operation (one or arbitrarily many memory reads and one or more arbitrarily many conditional branches, with data dependencies between them),
  4. only then it can finally call that function with references to Python objects holding the values of x and 0 (which is also not "free" - look up function calling ABI for more on that).

All that and more has to be done by the CPU even if x is a Python int or float mapping closely to the CPU's native numerical data types.

x = 0

An assignment is actually far cheaper in Python (though still not trivial): it only has to get as far as step 1 above, because once it knows "where" x is, it can just overwrite that pointer with the pointer to the Python object representing 0.

if

Abstractly speaking, the Python if statement has to be able to handle "truthy" and "falsey" values, which in the most naive implementation would involves running through more CPU instructions to evaluate what result of the condition is according to Python's semantics of what's true and what's false.

Sidenote About Optimizations

Different Python implementations go to different lengths to get Python operations closer to as few CPU operations in possible. For example, an optimizing JIT (Just In Time) compiler might notice that, inside some loop on an array, all elements of the array are native integers and actually reduce the if x != 0 and x = 0 parts into their respective minimal machine instructions, but that only happens in very specific circumstances when the optimizing logic can prove that it can safely bypass a lot of the behavior it would normally need to do.

The biggest thing here is this: a high-level language like Python is so removed from the hardware that "simple" operations are often complex "under the covers".

What You Asked vs. What I Think You Wanted To Ask

Correct me if I'm wrong, but I suspect the use-case you actually had in mind was this:

if x != 0:
    # some code
    x = 0

vs. this:

if x != 0:
    # some code
x = 0

In that case, the first option is superior to the second, because you are already paying the cost of if x != 0 anyway.

Last Point of Emphasis

The hardest breakthrough for me was moving away from trying to reason about individual instructions in my head, and instead switching into looking at how things work and measuring real systems.

Looking at how things work will teach you how to optimize, but measuring will show you where to optimize.

This question is great for exploring the former, but for your stated motivation of reducing power consumption on your laptop, you would benefit more from the latter.

mtraceur
  • 3,254
  • 24
  • 33