Posts

Showing posts from February, 2013

Closing Notes

Closing Notes The best way to write good, efficient code for embedded  systems  is to understand what  the  code  you write really does. If you really want to allocate an iterator, by all means use enhanced for loop syntax on a List; just make it a deliberate choice, not an inadvertent side effect. Forewarned is forearmed! Know what you're getting into! Insert your favorite maxim here, but always think carefully about what your code is doing, and be on the lookout for ways to speed it up.

Some Sample Performance Numbers

Some Sample Performance Numbers To illustrate some of our ideas, here is a table listing the approximate run times for a few basic actions. Note that these values should NOT be taken as absolute numbers: they are a combination of CPU and wall  clock  time, and will change as improvements are made to the  system . However, it is worth noting how these values apply relative to each other — for example, adding a member variable currently takes about four times as long as adding a local variable. Action Time Add a local variable 1 Add a member variable 4 Call String.length() 5 Call empty static native method 5 Call empty static method 12 Call empty virtual method 12.5 Call empty  interface  method 15 Call Iterator:next() on a HashMap 165 Call put() on a HashMap 600 Inflate 1 View from  XML 22,000 Inflate 1 LinearLayout containing 1 TextView 25,000 Inflate 1 LinearLayout containing 6 View objects 100,000 Inflate 1 LinearLayout containing 6 TextView objects 135,000 Launch

Avoid Float

Avoid Float Before the release of the  Pentium  CPU, it was common for game authors to do as much as possible with integer math. With the Pentium, the floating point math co-processor became a built-in feature, and by interleaving integer and floating- point  operations  your game would actually go faster than it would with purely integer math. The common practice on  desktop  systems  is to use floating point freely. Unfortunately,  embedded  processors  frequently do not have hardware floating point support, so all operations on "float" and "double" are performed in  software . Some basic floating point operations can take on the order of a millisecond to complete. Also, even for integers, some chips have hardware multiply but lack hardware divide. In such cases, integer division and modulus operations are performed in software — something to think about if you're designing a hash table or doing lots of math.

Use Package Scope with Inner Classes

Use Package Scope with Inner Classes Consider the following class definition: public class Foo { private int mValue; public void run() { Inner in = new Inner(); mValue = 27; in.stuff(); } private void doStuff(int value) { System.out.println("Value is " + value); } private class Inner { void stuff() { Foo.this.doStuff(Foo.this.mValue); } } } The  key  things to note here are that we define an inner class (Foo$Inner) that directly accesses a private method and a private instance field in the outer class. This is legal, and  the  code  prints "Value is 27" as expected. The problem is that Foo$Inner is technically (behind the scenes) a totally separate class, which makes direct access to Foo's private members illegal. To bridge that gap, the  compiler  generates a couple of synthetic methods: /*package*/ static int Foo.access$100(Foo foo) { return foo.mValue; } /*

Avoid Enums

Avoid Enums Enums are very convenient, but unfortunately can be painful when size and speed matter. For example, this: public class Foo { public enum Shrubbery { GROUND, CRAWLING, HANGING } } turns into a 900 byte .class  file  (Foo$Shrubbery.class). On first use, the class initializer invokes the <init> method on objects representing each of the enumerated values. Each object gets its own static field, and the full set is stored in an array (a static field called "$VALUES"). That's a lot of code and  data , just for three integers. This: Shrubbery shrub = Shrubbery.GROUND; causes a static field lookup. If "GROUND" were a static final int, the  compiler  would treat it as a known constant and inline it. The flip side, of course, is that with enums you get nicer APIs and some  compile -time value checking. So, the usual trade-off applies: you should by all means use enums for public APIs, but try to avoid them when  performance  matters. I

Use Enhanced For Loop Syntax With Caution

Use Enhanced For Loop Syntax With Caution The enhanced for loop (also sometimes known as "for-each" loop) can be used for collections that implement the Iterable  interface . With these objects, an iterator is allocated to make interface calls to hasNext() and next(). With an ArrayList, you're better off walking through it directly, but for other collections the enhanced for loop syntax will be equivalent to explicit iterator usage. Nevertheless, the following  code  shows  an acceptable use of the enhanced for loop: public class Foo { int mSplat; static Foo mArray[] = new Foo[27]; public static void zero() { int sum = 0; for (int i = 0; i < mArray.length; i++) { sum += mArray[i].mSplat; } } public static void one() { int sum = 0; Foo[] localArray = mArray; int len = localArray.length; for (int i = 0; i < len; i++) { sum += localArray[i].mSplat; }

Declare Constants Final

Declare Constants Final Consider the following declaration at the top of a class: static int intVal = 42; static String strVal = "Hello, world!"; The  compiler  generates a class initializer method, called  <clinit> , that is executed when the class is first used. The method stores the value 42 into intVal , and  extracts  a reference from the classfile string constant table for  strVal . When these values are referenced later on, they are accessed with field lookups. We can improve matters with the "final"  keyword : static final int intVal = 42; static final String strVal = "Hello, world!"; The class no longer requires a  <clinit>  method, because the constants go into classfile static field initializers, which are handled directly by the VM. Code accessing  intVal  will use the integer value 42 directly, and accesses to  strVal  will use a relatively inexpensive "string constant" instruction instead of a field lookup.

Cache Field Lookups

Cache Field Lookups Accessing object fields is much slower than accessing local variables. Instead of writing: for (int i = 0; i < this.mCount; i++) dumpItem(this.mItems[i]); You should write: int count = this.mCount; Item[] items = this.mItems; for (int i = 0; i < count; i++) dumpItems(items[i]); (We're using an explicit "this" to make it clear that these are member variables.) A similar guideline is never call a method in the second clause of a "for" statement. For example, the following code will  execute  the getCount() method once per iteration, which is a huge waste when you could have simply cached the value as an int: for (int i = 0; i < this.getCount(); i++) dumpItems(this.getItem(i)); It's also usually a good idea to create a local variable if you're going to be accessing an instance field more than once. For example: protected void drawHorizontalScrollBar(Canvas canvas, int width, int height)

Avoid Internal Getters/Setters

Avoid Internal Getters/Setters In native languages like C++ it's common practice to use getters (e.g.  i = getCount() ) instead of accessing the field directly ( i = mCount ). This is an excellent habit for C++, because the  compiler  can usually inline the access, and if you need to restrict or  debug  field access you can add  the  code  at any time. On  Android , this is a bad idea. Virtual method calls are expensive, much more so than instance field lookups. It's reasonable to follow common object-oriented  programming  practices and have getters and setters in the public  interface , but within a class you should always access fields directly.

Prefer Static Over Virtual

Prefer Static Over Virtual If you don't need to access an object's fields, make your method static. It can be called faster, because it doesn't require a virtual method table indirection. It's also good practice, because you can tell from the method signature that calling the method can't alter the object's state.

Prefer Virtual Over Interface

Prefer Virtual Over Interface Suppose you have a HashMap object. You can declare it as a HashMap or as a generic Map: Map myMap1 = new HashMap(); HashMap myMap2 = new HashMap(); Which is better? Conventional wisdom says that you should prefer Map, because it allows you to change the underlying implementation to anything that implements the Map interface. Conventional wisdom is correct for conventional  programming , but isn't so great for embedded  systems . Calling through an interface reference can take  2x  longer than a virtual method call through a concrete reference. If you have chosen a HashMap because it fits what you're doing, there is little value in calling it a Map. Given the availability of IDEs that refactor your code for you, there's not much value in calling it a Map even if you're not sure where  the  code  is headed. (Again, though, public APIs are an exception: a good 

Use Native Methods

Use Native Methods When processing strings, don't hesitate to use specialty methods like String.indexOf(), String.lastIndexOf(), and their cousins. These are typically implemented in C/C++ code that easily runs 10-100x faster than doing the same thing in a  Java  loop. The flip side of that advice is that punching through to a native method is more expensive than calling an interpreted method. Don't use native methods for trivial computation, if you can avoid it.

Avoid Creating Objects

Avoid Creating Objects Object creation is never free. A generational GC with per-thread allocation pools for temporary objects can make allocation  cheaper , but allocating memory is always more expensive than not allocating  memory . If you allocate objects in a  user  interface  loop, you will force a periodic garbage collection, creating little "hiccups" in the  user  experience . Thus, you should avoid creating object instances you don't need to. Some examples of things that can help: When extracting strings from a set of input data, try to return a substring of the original data, instead of creating a copy. You will create a new String object, but it will share the char[] with the data. If you have a method returning a string, and you know that its result will always be appended to a StringBuffer anyway, change your signature and implementation so that the function does the append directly, instead of creating a short-lived temporary object. A somewhat m

Introduction

Introduction There are two basic rules for resource-constrained systems: Don't do work that you don't need to do. Don't allocate  memory  if you can avoid it. All the tips below follow from these two basic tenets. Some would argue that much of the advice on this page amounts to "premature optimization." While it's true that micro-optimizations sometimes make it harder to develop efficient data structures and algorithms, on embedded devices like handsets you often simply have no choice. For instance, if you bring your assumptions about VM performance on  desktop  machines to Android, you're quite likely to write code that exhausts  system  memory . This will bring  your  application  to a crawl — let alone what it will do to other programs running on the system! That's why these guidelines are important.  Android's  success depends on the  user  experience  that your applications provide, and that user experience depends in part on whet

Designing for Performance

Designing for Performance An  Android  application should be fast. Well, it's probably more accurate to say that it should be  efficient . That is, it should execute as efficiently as possible in the mobile  device  environment, with its limited  computing  power and data storage, smaller  screen , and constrained battery life. As you develop your  application , keep in mind that, while the application may perform well enough in your  emulator , running on your dual-core development computer, it will not perform that well when run a  mobile  device — even the most powerful mobile device can't match the capabilities of a typical desktop system. For that reason, you should strive to write efficient code, to ensure the best possible performance on a variety of mobile devices. Generally speaking, writing fast or efficient code means keeping memory allocations to a minimum, writing tight code, and avoiding certain language and  programming  idioms that can subtly cripple per