Showing posts with label math package. Show all posts
Showing posts with label math package. Show all posts

Monday, June 9, 2014

Bitwise Operators

Manipulating bits, directly, to perform arithmetic is a skill that all advanced programmers need to be familiar with. By 'advanced' programmers, I refer to programmers who mostly perform low-level programming and for whom a 'bit' is not merely an abstraction or an arcana. When performance is of critical importance and precise optimizations are absolutely necessary, bitwise operators and bit shifts may usually - but not always - be able to provide the extra boost in efficiency that is desired.

For those unfamiliar with bitwise operators and bit shifts, Wikipedia is a more than sufficient introduction to the topic. For useful tips on how bitwise operators and bitshifts can be utilized, the site Bit Twiddling Hacks and the book Hacker's Delight are great resources.

In the past, bitwise operators and bit shifts were used out of pure necessity. Their use was justified mostly by the performance gains they brought about for the severely underpowered, resource-constrained machines of the time. However, in this day and age when , their exact purpose is somewhat difficult to determine, especially considering how much better compilers are these days at what they do. In most cases, it is very unlikely that bitwise operators will result in an increase in efficiency that is significant enough to warrant their use. Additionally, bitwise operators pose a serious threat to the readability of a program. It is all too easy for a clever and overzealous programmer to obfuscate some code by exploiting unnecessary 'bit-twiddling hacks'.

Also, even though bitwise operators are - at least in principle - largely 'language agnostic', there's still the fact that they are legacies of a much older set of languages (Assembly, C). As a result, while they may be accessible in more modern high-level languages like Java and Python, the consequences of their use may not be similar, at least in spirit. For example, in Java, the JVM adds an extra layer that makes it difficult for precise optimizations to be made. The final performance of a piece of code is largely dependent on the internal architecture of the JVM on which it is ran, and this, evidently, varies from vendor to vendor. Having this aspect of a project, not being under the auspices of the programmer makes it difficult to make any sort of sensible prediction as to what kind of performance hit you can expect when using regular operators as opposed to bitwise operators.

Anyways, the purpose of this entry was not to venerate or lambast bitwise operators as such, but rather to examine whether or not they could be used in the JSBML math package.

The simulation of biological models typically results in the performance of repetitive arithmetic operations, numerous times. Individually these operations have an insignificant time cost, but performed a lot and performed repetitively, these times may stack up to a significant cost. In a previous entry we looked at how performance is affected when class identity detection is handled through instanceof as opposed to the regular relational equality operator. As is typically the case with tests of this sort, they turned out inconclusive results.

Overall, the role of instanceof or any of its more syntax heavy siblings was merely incidental. Neither play an actual role in the calculations involved. It is an operation that is tied to the Java language. Compared to the previous approach, the new approach is more language agnostic. In order to validate any improvements brought about by the use of bitwise operators, the following, hopefully representative tests were done:

import java.util.concurrent.TimeUnit;


public class BitwiseBenchmark {

  /**
   * Comparing times with bitwise operators
   * and without bitwise operators
   * 
   * @param String[] args
   */
  public static void main(String[] args) {
    long a = 1, c = 0, start = 0, end = 0, bitwiseLength = 0, 
         operatorLength = 0, MAX = Long.parseLong(args[0]),
         MAX2 = Long.parseLong(args[1]);
    
    for (int b = 0; b < MAX2; b++) {
    
        for (int j = 0; j < MAX; j++) {
          start = System.nanoTime();
          c = a << 1;
          end = System.nanoTime();
          operatorLength += end - start;
        }
        
        a = 1;
        
        for (int i = 0; i < MAX; i++) {
          start = System.nanoTime();
          c = a * 2;
          end = System.nanoTime();
          bitwiseLength += end - start;
        }
        
    }
    
    String results = String.format("\tRESULTS\t\nBitwise: %dms\nOperator: %dms\n", 
                                   TimeUnit.NANOSECONDS.toMillis(bitwiseLength/MAX2), 
                                   TimeUnit.NANOSECONDS.toMillis(operatorLength/MAX2));
    System.out.print(results);
  }
  
}

Ran with this command:
java BitwiseBenchmark 100000000 40

To give these results:
RESULTS
Bitwise: 6248ms
Operator: 5798ms
On face value, these results are enough to firmly discredit any claims that bitwise operators are a better, more efficient alternative to regular operators. However, from past experience, I know that there's more that's going on here, than meets the eye. Flipping the positioning of the two loops for example, results in the regular operator taking a longer time than the bitwise operator. This is an issue that I encountered when I first tried to test the instanceof operator, and there's still no clear explanation for it. Again, I suspect that it has something to do with the JVM, but since this is not my area of expertise, there's really not much I can say aside from that.

Ultimately, the conclusions I've been able to draw from my readings and doing this little experiment are that (1) Manipulating bits directly should be avoided, unless there is clear justification for using them. This 'clear justification' may take the form of a necessary but probably marginal increase in efficiency, for which a fall in the readability of the code is a small price to pay. (2) Efficiency gains from using bitwise operators are insignificant in most cases.

Tuesday, May 20, 2014

Efficiency of instanceof operator (revisited)

For the previous test, all conclusions had to be prefaced with a disclaimer because the test suite's configuration  made it difficult to accurately determine instanceof's efficiency relative to the alternatives (i.e. .getClass().equals()). The test suite's inability to generate average values for each test turned out to be the biggest stumbling block. This flaw in the test's design meant that the values gotten from each test varied, sometimes drastically, making it difficult to pin down an accurate relationship. With the new test suite it is possible to specify how many times each test should run. For example, to test every method fifty times at a hundred iterations, the following command can be used:

java PerformanceTest 50 100

Hence, the general command is:

java PerformanceTest [# of repetitions] [# of iterations]

Once the repetition value is supplied, the test suite repeats each test for the specified amount of time and then automatically generates the average values. Unsurprisingly, the average times for each test are more consistent than the individual values (which could have a 10-20 ms margin of error).

On my aging core i3 machine, testing each operation fifty times for one million iterations yielded the following times:

.getClass.getName().equals("A"): 48ms
.getClass().getName() == "A": 65ms
a.equals(Type.A): 48ms
a == Type.A: 58ms
a instanceof A: 58ms

Testing each operation 50 times for ten million iterations yielded the following times:

.getClass.getName().equals("A"): 441ms
.getClass().getName() == "A": 624ms
a.equals(Type.A): 451ms
a == Type.A: 536ms
a instanceof A: 539ms

(Note how increasing the # of iterations by ten increased the running times by ten as well)

With reliable data in hand, it's now reasonable to conclude that:
1. Trying to elucidate a class' identity using .getClass().getName() == will far and away take the longest amount of time.
2. Conversely, using .getClass.getName().equals("A") for the same purpose will take the least amount of time.
3. Using the equals method associated with the enum (i.e. a.equals(Type.A)), will result in a relatively short running time.
4. instanceof and a == Type.A are neither the slowest nor the fastest ways to determine class identity.

Representing the relative efficiency of all five options visually you get (from least efficient to most efficient):
.getClass().getName() == "A" > a instanceof A > a == Type.A > a.equals(Type.A) > .getClass.getName().equals("A")

Thus, the data favours a class hierarchy design in which every entity (i.e. operation, integer, function) is represented by its own class (Category A in the previous entry). From an efficiency standpoint, the current system is not the worst. However, letting a full fledged math library handle all of the ASTNode operations will result in a marginal increase in efficiency, which is the end-goal of this project.