Monday 13 March 2017

A few notes on Dave Thomas' "Agile is Dead" talk


The talk:  Agile is Dead

A forty minute talk compressed for quick reading.


  • The title is designed to be provocative.  The actual message is a simple grip at the industries trend of turning an adjective into a noun.  Which was done partly to sell you something, training, consulting, books, conferences, ..
  • Dave Thomas was part of the original meetup that produced the agile manifesto.
  • The talk is mostly a rallying call to remember that the original agile manifesto was focused on principles/values and not techniques.  It was called the 'Manifesto for Agile Software Development' and not the agile manifesto for a reason.
  • He points out that every rule/recommendation/advice will fail in some circumstances.  Thus beware of anybody who says 'always do X'.
  • The core technique within agile is simply the 'do/measure/adapt' cycle, with one caveat that is sometimes forgotten.  When two or more options exist that appear equal, choose the one that is more open to change.


Sunday 25 May 2014

Alternative Log Level Structure


Over the years I have become increasingly dissatisfied with the standard log levels used in Java.  The main problem being that I find with them is that they can be unclear as to where a specific log message belongs: trace, debug, info, warn, error, fatal.

At first glance it appears very straight forward, however after working with many talented teams of developers I have observed that the log levels take effort to standardise across the team and that each team has had their own subtly different guidelines.   Essentially it takes effort to disambiguate edge cases; is a message info or warn? trace or debug? warn or error?  It becomes grey because the level changes based on who the audience is for the message, and typically developers will answer that question from their own view point. 

Previously I posted some guidelines on how we used those log levels; a few years on, I am both older and have less hair.  I have just found it easier to rename each of the log levels and be done with it.  Previously the desire to be a good log4j citizen stopped me, however being somewhat older I am less tolerant of conventions that cause me to loose my hair.  I just don’t have much hair left, and so I need to be more protective of it.   ;)


Here are the log levels that I currently use, I find them to be much more intuitive.

Audit (record of what happened, useful when investigating what the system did and why)

    dev   - diagnostic information useful for developers 
    ops   - diagnostic information useful for people who maintain the system 
    user  - diagnostic information about a user, and if ever seen by a savvy user would be meaningful to them  e.g. ‘CK created account’, and ‘CK logged in'

Alerts (requires action)

    warn - a problem has been detected and mitigated or a potential problem has been detected that does not yet affect users; (action: notify ops/review during office hours to help pre-empt fires/raise awareness of what the state of the system is)
    fatal  - the preverbal has hit the fan, progress can not be made by users (action: wake everybody up)


Alerts are special in two ways, firstly they are raising awareness of an ongoing problem that has a start and hopefully (eventually) an end.  Thus they need to make it clear that yes, we still have a problem or yay the problem has ended.  Secondly, they are a call to action.  Somebody needs to pay attention to alerts, either just by being aware that the system is at reduced capacity (warn) or get out of bed and sound the alarms, round up the troops etc;  the entire system is down (fatal).

Clearly we do not want many alerts.  If there are too many red herrings then people will ignore them, thus the alerts need to be very clear, complete and as rare and accurate as possible.   Thus most messages will be informative/audits and not alerts at all, in which case it must be very clear who the target audience is.  If that audience turn around and say, I do not understand or care then the message comes out entirely.   


I have found that agreeing in a team of developers who a message is for, and whether they need to take action or not to have a lot less grey areas than agreeing what the severity of that message is in relation to another message.  The relative comparison becomes a lot less important.  Thus once a scheme like this is in place, enforcing the rules becomes a lot easier.  The usage is intuitive, so there is little need to keep reminding people (myself included).   


Saturday 10 May 2014

Which is faster in Java, Reflection or MethodHandle?


2014 has been shaping up to be an awesome year so far.  London is a great place to work, especially when it has given me a lot of opportunities to figure out how to make Java run faster.  

For Reflection vs MethodHandles, lets jump straight to some numbers.  The code used to create these benchmark numbers is included at the end.


Direct Method Call0.1ns
Reflection4ns
MethodHandle0.1ns - 110ns
Measurements taken running Java 7 on a shiny OSX laptop


Huh?  Why the huge range of values for MethodHandle?  The reason is that it depends on how the MethodHandle is created and used.  Being a richer API than reflection, it can either run like a farm pig ready for Christmas or become optimised down to being the same as a direct method call.  Awesome.  Thus this post shows how to avoid the costs, and stream line the use of MethodHandle.


Unreflect87ns
Lookup then bind105ns
Unreflect then bind 111ns
Invoke exact 11ns
Unreflect invokeExact 6ns
Store MethodHandle in private static final field 0.1ns
Method in private static final field 4ns

These numbers show that some care needs to be taken with MethodHandle, but treat it well and store it in a private static final field and then Hotspot can optimise the reflection out entirely.   Pretty awesome. 




package reports.signals;

import com.softwaremosaic.junit.JUnitMosaicRunner;
import com.softwaremosaic.junit.annotations.Benchmark;
import org.junit.runner.RunWith;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


/**
 *
 */
@RunWith(JUnitMosaicRunner.class)
public class SignalManagerExperimentalTest {

    private int i=0;

    public void m() {
        i += 1;
    }

    private static final int NUMITS = 10000;

/*
    6.61ns per call
    4.95ns per call
    4.08ns per call
    3.95ns per call
    3.93ns per call
    3.88ns per call
     */
    @Benchmark( value=1000, durationResultMultiplier = 1.0/NUMITS )
    public int fooRef() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method f = this.getClass().getMethod( "m" );

        for ( int i=0;i
            f.invoke( this );
        }

        return i;
    }

    private static final Method pf = getF();

    private static Method getF() {
        try {
            return SignalManagerExperimentalTest.class.getMethod( "m" );
        } catch ( NoSuchMethodException e ) {
            e.printStackTrace();
        }

        return null;
    }

/*
    7.27ns per call
    4.75ns per call
    3.79ns per call
    3.72ns per call
    3.71ns per call
    4.29ns per call
     */
    @Benchmark( value=1000, durationResultMultiplier = 1.0/NUMITS )
    public int fooRefPF() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        for ( int i=0;i
            pf.invoke( this );
        }

        return i;
    }

/*
    0.09ns per call
    0.12ns per call
    0.10ns per call
    0.11ns per call
    0.10ns per call
    0.10ns per call
     */
    @Benchmark( value=1000, durationResultMultiplier = 1.0/NUMITS )
    public int fooDirect() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        for ( int i=0;i
            m();
        }

        return i;
    }

/*
unreflect
    87.07ns per call
    87.38ns per call
    87.39ns per call
    87.98ns per call
    86.89ns per call
    88.20ns per call
*/
@Benchmark( value=1000, durationResultMultiplier = 1.0/NUMITS )
public int unreflect() throws Throwable {
    Method f = this.getClass().getMethod( "m" );
    MethodHandle h = MethodHandles.lookup().unreflect( f );

    for ( int i=0;i
        h.invoke(this);
    }

    return i;
}

/*
lookup then bind
    110.45ns per call
    106.48ns per call
    106.04ns per call
    106.15ns per call
    105.20ns per call
    105.13ns per call
*/
@Benchmark( value=1000, durationResultMultiplier = 1.0/NUMITS )
public int lookupBind() throws Throwable {
    MethodHandle h = MethodHandles.lookup().bind( this, "m", MethodType.methodType(Void.TYPE) );

    for ( int i=0;i
        h.invoke();
    }

    return i;
}
/*
unreflect then bind
    112.95ns per call
    110.62ns per call
    112.70ns per call
    112.77ns per call
    111.10ns per call
    111.64ns per call
*/
@Benchmark( value=1000, durationResultMultiplier = 1.0/NUMITS )
public int unreflectBind() throws Throwable {
    Method f = this.getClass().getMethod( "m" );
    MethodHandle h = MethodHandles.lookup().unreflect( f ).bindTo( this );

    for ( int i=0;i
        h.invoke();
    }

    return i;
}

    /*
    invoke exact
        12.65ns per call
        12.03ns per call
        11.17ns per call
        10.46ns per call
        10.36ns per call
        10.18ns per call
*/
    @Benchmark( value=1000, durationResultMultiplier = 1.0/NUMITS )
    public int invokeExact() throws Throwable {
        MethodHandle h = MethodHandles.lookup().bind( this, "m", MethodType.methodType(Void.TYPE) );

        for ( int i=0;i
            h.invokeExact();
        }

        return i;
    }

    /*
        unreflect invokeExact
            7.49ns per call
            7.12ns per call
            6.75ns per call
            6.72ns per call
            6.22ns per call
            5.92ns per call
             */
    @Benchmark( value=1000, durationResultMultiplier = 1.0/NUMITS )
    public int unreflectInvokeExact() throws Throwable {
        Method f = this.getClass().getMethod( "m" );
        MethodHandle h = MethodHandles.lookup().unreflect( f );

        for ( int i=0;i
            h.invokeExact(this);
        }

        return i;
    }


    private static final MethodHandle mh = lookupViaFindVirtual();

    private static MethodHandle lookupViaFindVirtual() {
        try {
            return MethodHandles.lookup().findVirtual( SignalManagerExperimentalTest.class, "m" , MethodType.methodType(Void.TYPE));
        } catch ( Throwable e ) {
            e.printStackTrace();

            return null;
        }
    }


/*
    0.12ns per call
    0.09ns per call
    0.12ns per call
    0.11ns per call
    0.10ns per call
    0.10ns per call
     */
    @Benchmark( value=1000, durationResultMultiplier = 1.0/NUMITS )
    public int fooHandleSF() throws Throwable {

        for ( int i=0;i
            mh.invokeExact( this );
        }

        return i;
    }
}



Sunday 2 March 2014

Java 9 Wish List

With the release of Java 8 close, it is time for me to update my Java wish list for Java.   (http://chriskirk.blogspot.com/2011/06/java-8-wishlist.html)


1. Support memory mapping of files greater than 2GB.  Memory mapping files is the fastest way to work with files in Java, and it is a technique that I am using more and more as I push for faster systems.  Having to work around the 2GB limit is tedious and unnecessary.

2. Big heap support.  Java Garbage Collectors are for the most part still stop the world collectors, which get slower as the heap size/live object count increases.  As memory is becoming so cheap, it is a shame to have to go off heap in order to maintain server performance.

3. Efficiently support primitives with Generics and polymorphic method dispatches.  It is a pain in the backside to have to duplicate methods just to support the different primitives efficiently.

4. Continuations is becoming increasingly mainstream now, and having clean ways to incrementally process large data sets asynchronously is very valuable.  It could be as simple as the Python 'yield' keyword, but ideally I want to be able to make synchronous code such as a db call not hold on to a thread, and yet be as maintainable as a normal synchronous call.

5.  File I/O still blocks.  That is why memory mapping is so valuable in Java as it does not block.  Please add true asynchronous file support.  The Async file I/O added to NIO is still implemented under the hood using the same blocking APIs, making it even slower than the synchronous apis. Shame on you Sun!  (may your rest in peace; and shame on Oracle for leaving it alone for so long).

6. Unsigned versions of short, int and long.  Java may not be C, but unsigned types are useful when working with positive numbers.

7.  Packed object arrays.  Currently Java arrays of objects are arrays of references, references have a cost to follow that is greater than many would assume (due to the way modern CPUs and cacheing subsystems work).  Thus support for arrays of structures, more like C would allow for more efficient Java code to be written.

8. Access to method parameter names at runtime.

9. Access to java docs at runtime.

10. Faster compiler.

11. Default parameter values.

12. Language support for reflection.

13. Drop the annoying diamond operator (<>).

14. Multi line string support.

15. Mix-in support.


What is on your wish lists?  Please share.

Wednesday 4 September 2013

What is a Java Safepoint?

This is the best description of the behaviours of a safepoint in Java  that I have come across, it was written by Gil Tene; CTO of Azul and posted to the mechanical sympathy mailing list run by Martin Thompson.  I capture it here for my own reference.

1. A thread can be at a safepoint or not be at a safepoint. When at a safepoint, the thread's representation of it's Java machine state is well described, and can be safely manipulated and observed by other threads in the JVM. When not at a safepoint, the thread's representation of the java machine state will NOT be manipulated by other threads in the JVM. [Note that other threads do not manipulate a thread's actual logical machine state, just it's representation of that state. A simple example of changing the representation of machine state is changing the virtual addresss that a java reference stack variable points to as a result of relocating that object. The logical state of the reference variable is not affected by this change, as the reference still refers to the same object, and two references variable referring to the same object will still be logically equal to each other even if they temporarily point to different virtual addresses].

2. "Being at a safepoint" does not mean "being blocked" (e.g. JNI code runs at a safepoint), but "being blocked" always happens at a safepoint.

3. The JVM may choose to reach a global safepoint (aka Stop-The-World), where all threads are at a safepoint and can't leave the safe point until the JVM decides to let it do so. This is useful for doing all sorts of work (like certain GC operations, deoptimization during class loading, etc.) that require ALL threads to be at a well described state.

4. Some JVMs can bring individual threads to safepoint without requiring a global safepoint. E.g. Zing uses the term Checkpoint (first published in [1]) to describe a JVM mechanism that individually passes threads through thread-specidfic safepoints to perform certain very short operations on individual thread state without requiring a Stop-The-Wolrd pause.

5. When you write Unsafe java code, you must assume that a safepoint MAY occur between any two bytecodes. 

6. Unsafe calls are not required to have safepoints within them (and many/most don't), but they MAY include one or more safepoints. E.g. an unsafe memoryCopy MAY include a periodic safepoint opportunities (e.g. take a safepoint every 16KB). Zing sure does, as we do a lot of under the hood work to keep TTSP in check.

7. All [practical] JVMs apply some highly efficient mechanism for frequently crossing safepoint opportunities, where the thread does not actually enter a safepoint unless someone else indicates the need to do so. E.g. most call sites and loop backedges in generated code will include some sort of safepoint polling sequence that amounts to "do I need to go to a safepoint now?". Many HotSpot variants (OpenJDK and Oracle JDK) currently use a simple global "go to safepoint" indicator in the form of a page that is protected when a safepoint is needed, and unprotected otherwise. The safepoint polling for this mechanism amounts to a load from a fixed address in that page. If the load traps with a SEGV, the thread knows it needs to go to enter a safepoint. Zing uses a different, per-thread go-to-safepoint indicator of similar efficiency.

8. All JNI code executes at a safepoint. No Java machine state of the executing thread can be changed or observed by it's JNI code while at a safepoint. Any manipulation or observation of Java state done by JNI code is achieved via JNI API calls that leave the safepoint for the duration of the API call, and then enter a safepoint again before returning to the calling JNI code. This "crossing of the JNI line" is where most of the JNI call and API overhead lies, but it's fairly quick (entering and leaving safepoint normally amounts to some CAS operations).

Friday 21 June 2013

How to install Siege for Mac OS X 10.8


Siege is a wonderful tool for benchmarking http urls.  Unfortunately since Mountain Lion it can be a bit fidly to install, the main download website has a dmg file that once downloaded says that ones version of OSX is not supported; so build from source.  And building from source has problems with X not being supplied by default.

Brew FTW.

So I resorted to bundled packagers, firstly fink but then Brew.  Brew worked first time with little effort.

http://mxcl.github.io/homebrew/


    ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"
    brew doctor

    brew install siege
    siege.config

Then edit the .siegerc file generated by siege.config, setting connection from 'close' to 'keep-alive'.  I also disable logging too.


Benchmarks can then be run as follows:

    siege -c 100 -b http://www.google.com > /dev/null

Press ctrl-c when you want to stop the test and see the stats.



Sunday 2 June 2013

Vagrant Script for compiling JDK 8 from source

I recently wanted to take a look at Java 8, without wanting to pollute my working environment. The JDK has a fair few dependencies that must be installed before it can be compiled. So I created the following Vagrantfile which I have chosen to share here.

Vagrant is a great wrapper for running virtual machines locally. After installing vagrant, to just type 'vagrant up' in the same directory as the following file and it will handle creating a 64bit Ubuntu VM locally, installing dependencies, checking out the head branch of JDK8 and compiling it.

After Vagrant has finished creating the VM, and compiling the JDK.  You can log in to the Ubuntu instance by typing 'vagrant ssh' and from there you will be able to use the compiled JDK, make changes, recompile and so forth.



# -*- mode: ruby -*-
# vi: set ft=ruby :

$checkoutAndCompileJDK = <<SCRIPT
  sudo vagrant
  cd ~

  sudo apt-get update

  sudo apt-get install -y mercurial
  sudo apt-get install -y make
  sudo apt-get install -y unzip
  sudo apt-get install -y zip
  sudo apt-get install -y openjdk-7-jdk
  sudo apt-get install -y build-essential
  sudo apt-get install -y libX11-dev libxext-dev libxrender-dev libxtst-dev
  sudo apt-get install -y libcups2-dev
  sudo apt-get install -y libfreetype6-dev
  sudo apt-get install -y libasound2-dev
  sudo apt-get install -y ccache

  sudo apt-get install -y alsa
  sudo apt-get install -y cups
  sudo apt-get install -y xrender

  sudo apt-get install -y libpng12-dev
  sudo apt-get install -y libgif-dev
  sudo apt-get install -y libfreetype6
  sudo apt-get install -y pkg-config


  hg clone http://hg.openjdk.java.net/jdk8/jdk8 jdk8

  cd jdk8

  bash ./get_source.sh

  bash ./configure
  make all
SCRIPT




Vagrant.configure("2") do |config|
  config.vm.box = "precise64"

  config.vm.box_url = "http://files.vagrantup.com/precise64.box"

  config.vm.provision :shell, :inline => $checkoutAndCompileJDK

  config.vm.provider :virtualbox do |vb|
    vb.customize ["modifyvm", :id, "--memory", "4096"]
  end

end