Sunday, 26 June 2016

JIT Fun Part 2: Throwing the JIT a curve ball

This post follows on from the previous post about visualising JIT.

Let's start with a simple, silly main method:

Plotting the elapsed time in ns:




We can see that:

Up to about the 70th run it is running in the interpreter
Then it drops into C1 until 200
At 200 it optimises again into C2

At 600 it hits our curve ball and deoptimises the method.
Method eventually drops back in C2 at around 800.

Curve ball:

The compiler thought that our String curveBall was always going to be null and it added that into the compiler. However, when we set it to something other than null the compiler realised that it has made a wrong assumption and had to deoptimise that compiled method. 

JIT Fun Part 1: Quick JIT visualisation of tiered compliation

See the following code:
It's not doing anything exciting, just running the same inner loop 1000 times.

I have taken those times and put them in a file called 'output.txt'.

See the following python function which reads in the numbers from output.txt and plots them on a graph:

Here is the graph that it produces:



At first the code is running in the interperter, then the C1 JIT, then it settles into the C2 JIT. A couple of spikes probably indicate GC.




Thursday, 14 April 2016

vcsh with myrepos (mr)

VCSH


Vcsh allows you to maintain multiple git repos in one directory. I use this for having separate git repos for dot config files that live in my home directory.

Setting up a new vcsh git repo for a a dot config file (eg .vimrc)


vcsh init vim
vcsh vim add ~/.vimrc
vcsh vim commit -m "first commit"
vcsh vim remote add origin git@github-personal:polyglotpiglet/vim.git

On github created a new repo called 'vim'

vcsh vim push -u origin master
vcsh vim push

MyRepos (MR)


I have several such vcsh repos. Wouldn't it be nice to bulk pull updates for all these repos? Or bulk check them out? 

With mr you define a ~/.mrconfig file which lists all the repos to manage.


I added the following configuration parameter to my git config:

git config --global push.default matching

This means that 'mr push' works. Mr push does 'git push' on each of the repos and by setting this config param it means that you push to the remote branch with the same name as the local branch by default. 




Java 8: Parallel Streams - Performance with ArrayList vs LinkedList

Consider the following function:
 public static int sum(List<Integer> values) {
    return values.parallelStream().mapToInt(i -> i).sum();
 }

It's using java 8 parallel streams to sum a list of Integers.

In this post we will demonstrate and explain the difference in the performance of this function when passing in a LinkedList vs an ArrayList.

Generate the lists to be tested


The following code creates an IntStream of random Integers.

 Random random = new Random();
 int n = 10000000;
 Stream<Integer> stream = IntStream.range(0, n)
        .map(i -> random.nextInt())
        .boxed();

Collect it into a list:
 List<Integer> list = stream.collect(Collectors.toList());

Here there are no guarantees about type (though it's probably an ArrayList) so let's create two lists, one LinkedList and one ArrayList.
 ArrayList<Integer> al = new ArrayList<>(list);
 LinkedList<Integer> ll = new LinkedList<>(list);

Benchmark


Cheeky little wrapper function to add the timing: 
 public static long timedSum(List<Integer> values){
    long startTime = System.nanoTime();
    sum(values);
    long endTime = System.nanoTime();
    return endTime - startTime;
 }

Note: Do not do benchmarking like this. Instead use JMH. I'm just a bad bad person. 

Running the Code


Let's run the code a few times for each type of list and take the average time (after a warm up, of course). 

 System.out.println("ArrayList " + 
        new Double(LongStream.range(0, 5)
                .map(i -> timedSum(al))
                .average()
                .getAsDouble()).intValue());
 System.out.println("LinkedList " + 
        new Double(LongStream.range(0, 5)
                .map(i -> timedSum(ll))
                .average()
                .getAsDouble()).intValue());

Results

ArrayList   17907140
LinkedList 160238673

The ArrayList performs about x10 better than the LinkedList. 

Analysis of Results


Parallel streams use a fork/join model when they execute. This means that the task is split into subtasks. Each subtask is executed and the results combined. In this example, the list is partitioned and each partition is summed. These partitions are then summed until we have one final answer. 

Clearly, this partitioning will be most effective when the partitions are roughly equal.  An ArrayList supports random access, so partitioning is much quicker and easier than with a LinkedList; decomposing the list into these partitions is O(n). 


Thursday, 31 March 2016

Java 8: Diamond Inference for methods

As of Java 8, we don't need to specify the types when we pass in typed parameters.


 public static void main(String... args) {
    operateOnHashMap(new HashMap<>()); // empty diamonds :D 
 }
 static void operateOnHashMap(Map<String, Integer> map) {
    // do stuff with map
 }

Java 8: Functional Interface

Definition: 

A function interface in java is an interface with a single abstract method. They are used to type lambda expressions.

Example: 

In the following example, 'Cat' is a functional interface.

 interface Cat {
    void meow();
 }

 public static void main(String... args) {
    Cat cat = () -> System.out.println("Meowwwwww");    
    cat.meow();
 }

It is good practice to annotate functional interfaces with the annotation @FunctionalInterface .

Java 8: Runnables with Lambdas

Old (anonymous inner classes)

 Runnable meow = new Runnable() {
    @Override    
    public void run() {
        System.out.println("meow");    
    }
 };
 meow.run();

Output: 
    meow

    Process finished with exit code 0


New.1 (lambda)

 Runnable rawr = () -> System.out.println("rawr");
 rawr.run();

Output: 
    rawr

    Process finished with exit code 0


New.2 (passing function call)

 public static void main(String... args) {
    Runnable lalala = Main::LaLaLa;    
    lalala.run();
 }

 public static void LaLaLa() {
    System.out.println("lalala");
 }

Output: 
    lalala

    Process finished with exit code 0


Scala with Cats: Answers to revision questions

I'm studying the 'Scala with Cats' book. I want the information to stick so I am applying a technique from 'Ultralearning...