CALL GLOP()

Andy Malakov software blog

Friday, December 11, 2009

Old trap

I was puzzled why one of my objects had incorrect toString()

class Foo { 
private long id;
private String name;

Foo(
long id, String name) {
this.id = id;
this.name = name;
}

public String toString () {
return id + ' ' + name;
}
}


The statement new Foo(123, "Hello") prints something like "155Hello" instead of "123 Hello". Of course the reason is pretty simple:

 
public String toString2() {
return new StringBuilder().append(id + 32L).append(name.toString()).toString();
}

Wednesday, November 11, 2009

Stack allocation in Java is still a myth

There were rumors that Mustang will have on stack allocation as a part of hot spot optimization.

Four+ years later this :


public long encode (String input) {
final byte [] buffer = new byte [8];

.. encode input into buffer

.. convert buffer into LONG

return result;
}


I was hoping JVM will allocate buffer on stack based on the fact that it does not escape from this method. Running this test 10M times with -verbosegc shows extensive GC work (1.6.0_16-b01 64 bit server JVM with -XX:+DoEscapeAnalysis option).



On the positive side. GC is very fast. Consider three functions:

  1. encodeNewBuffer () uses new byte array to encode input string.

  2. encodeSynchronizedField () uses private field, guarded by synchronized{} block

  3. encodeThreadLocalField () uses ThreadLocal cache to encode input string



Here is the code:

long encodeNewBuffer (String input) {
final byte [] buffer = new byte [8];

return f (buffer);
}

/////////////

private final byte [] buffer = new byte [8];

synchronized long encodeSynchronizedField (String input) {
return f (buffer);
}

/////////////

ThreadLocal<byte[]> threadLocal = new ThreadLocal<byte[]>();
{
threadLocal.set(new byte [8]);
}

long encodeThreadLocalField (String input) {
byte [] buffer = threadLocal.get();
return f (buffer);
}


GC-based method is a winner:


encodeNewBuffer(): 4,108 sec.
encodeSynchronizedField(): 5,322 sec.
encodeThreadLocalField() : 5,411 sec

Monday, November 9, 2009

Multi-threaded testing with JUnit. Switch to ConcJUnit .

Our JUnit tests deal with components that use multiple threads. Unfortunately JUnit has no built-in support for this kind of testing.

Lets consider a simple thread that interprets commands from input queue. In this example it can only understand "exit" command. All other inputs trigger an error.

 

abstract class MainLoop extends Thread {

private Queue<String> commands = new LinkedBlockingDeque<String>();


public void run () {
while (true) {
String command = commands.poll();
if (command.equals ("exit"))
break;

else
reportError (
"Unknown command: " + command);
}
}

public void add (String command) {
commands.add(command);

}

abstract void reportError (String error);
}

public class MyTest {

@Test
public void test() {
MainLoop thread =
new MainLoop() {

void reportError(String error) {
Assert.fail (error);
}
};
thread.start();
thread.add (
"quit"); // sic! shoudl be "exit"

}
}



If we run the above test, JUnit completely ignores failure of "Commands Interpreter" thread (Although default uncaughtExceptionHandler prints exception to standard output):


[junit] Running test.MyTest
[junit] Exception in thread "Commands Interpreter": java.lang.AssertionError: Unknown command: quit
[junit] at org.junit.Assert.fail(Assert.java:91)
[junit] at test.MyTest$1.reportError(MyTest.java:36)
[junit] at test.MainLoop.run(MyTest.java:19)
[junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.422 sec


As you can see JUnit detected 0 errors. JUnit has at least two problems when it comes to multi-threaded tests:

  1. JUnit only cares about errors in its own thread. It completely ignores exceptions or assertion failures in child threads.

  2. Left over child threads may produce side effect on subsequent tests. In some cases failures in child threads may happen after the main thread is finished.



We used various custom workarounds until it was clear that we need a generic solution for growing number of multi-threaded tests. Luckily we found an excellent tool - ConcJUnit (AKA ConcuTest) written by Mathias Ricken.

a) ConcJUnit is a drop-in replacement of JUnit. It includes standard JUnit classes and introduces own test runners. Just replace junit.jar by concutest.jar .

b) ConcJUnit detects both failures in child threads and leftover threads.

Switching to ConcJUnit produces expected result:


java.lang.AssertionError: Unknown command: quit
at org.junit.Assert.fail(Assert.java:91)
at test.MyTest$1.reportError(MyTest.java:36)
at test.MainLoop.run(MyTest.java:19)
at test.MainLoop.run(MyTest.java:19)


If you want to know more about ConcJUnit, read materials from introduction page. For example, the following presentation.

Thursday, November 5, 2009

GLOP

"Consider a program — any program; let us call it GLOP. We begin designing our program by imagining that we have a machine with a hardware instruction that will perform GLOP (an idea that is not beyond the realm of possibility with today's microprogrammable computers) Thus, to write program GLOP, we merely write the instruction
GLOP
and we are done! Not only are we finished, but we are relatively certain that the resulting program is correct — assuming that the hardware primitive GLOP performs correctly (and if it doesn't, we can always blame it on the vendor)."

Edward Yourdon "Techniques of program structure and design‎" 1975.

Tuesday, November 3, 2009

2:5020/236.23 :-)

Thursday, October 8, 2009

sizeof and object padding in Java

Consider the following classes:


class Struct1 {
byte b1;
}

class Struct2 extends Struct1 {
byte b2;
}

class Struct3 extends Struct2 {
byte b3;
}

class Struct4 extends Struct3 {
byte b4;
}

class Struct5 extends Struct4 {
byte b5;
}

class Struct6 extends Struct5 {
byte b6;
}

class Struct7 extends Struct6 {
byte b7;
}

class Struct8 extends Struct7 {
byte b8;
}


class FlatStruct8 {
byte b1, b2, b3, b4, b5, b6, b7, b8;
}



On my JVM (1.6.0_16 64-bit):


sizeof (new Struct8()) = 80 (sic!)
sizeof (new FlatStruct8()) = 24


Now, 24 makes sense (8 bytes of data + 2 x 8 bytes of object overhead). In case of Struct8, we can see that Java pads fields declared in each class to so that total block size will be multiple of 8.

I used both Instrumentation-based and GC-based sizeof () implementations to confirm this.

On 32-bit JVM (1.6.0_04-b12) blocks are padded to multiple of 4.


sizeof (new Struct8()) = 40
sizeof (new FlatStruct8()) = 24


More about padding.

Monday, July 27, 2009

Faster JUL logging

Here are the steps we followed to improve java.util.logging performance:


  1. Switched from SimpleFormatter to our custom formatter. It boosted performance up to 6 times. Our formatter prints only time-of-day portion of timestamp (using custom formatting function). Our log files also omit class/method/thread context for each log message. It also uses custom MessageFormatter (based on StringBuilder).


  2. Tweaked FileHandler to flush every 8K rather than after each message. This boosts performance up to 2.5 times.


  3. We tried using Java7 logger package. We didn't notice considerable improvements for our usage patterns.



Credit for much of this work goes to my colleague Nikolay Dul.

Wednesday, July 22, 2009

Java logging

Am I the only one who misses


public void log (Level level, String msg, Object ... params)


Instead of existing


public void log (Level level, String msg, Object [] params)


in java.util.logging.Logger ?

P.S. Apparently not: enhancement request was filed back in 2004. I will see what I can do...

Saturday, June 13, 2009

Writing game bot in Java

Can Java be used to write a simple MMORPG game bots?

Easily. Java has a class java.awt.Robot that is intended for writing automated tests and provides just what we need.

First, lets create a bot that will keep an eye on your character's health status. The basic idea is very simple - when health status is running low, drink a healing potion. Repeat. This simple script covers your back and releases your mind from some routine actions. You will concentrate on attacking your opponent ;-)

import java.awt.Color;
import java.awt.Robot;
import java.awt.Toolkit;
import static java.awt.event.KeyEvent.*;

private Toolkit toolkit = Toolkit.getDefaultToolkit();
private Robot robot = new Robot();


We need two type of things:

  1. Inspect some area of the screen that shows your character health's status (usually appears as some sort of progress bar). We just need to know when some pixel inside the bar is getting black:
    boolean isBlack (int x, int y) {
    Color c = robot.getPixelColor (x, y);
    return c.getRed() < 16 && c.getGreen() < 16 && c.getBlue() < 16;
    }

  2. Simulating keyboard action is also easy (we need to press a hotkey for your healing potions)
    void key (int keyCode, long duration) throws InterruptedException {
    robot.keyPress(keyCode);
    Thread.sleep(duration);
    robot.keyRelease(keyCode);
    }

Now the program itself is trivial:
while (true) {
if (isBlack (90, 760))
key (VK_F1, 500);

Thread.sleep (50);
}


Here I assume that your healing potions are assigned to hotkey F1 (KeyEvent.VK_F1) and coordinates {90, 760} show your health status and become black when health is below 25% (your can use Paint or some other program to analyze game's screen shot).


Similar approach can be used to automate other tedious MMORPG tasks (mining gold, fishing, or gaining experience).


P.S. Take a look at this guy's screen (like a Boeing cockpit).



DISCLAIMER:Check your game's license before using this technique. It may be prohibited as something that gives unfair advantage over other players.

Wednesday, December 24, 2008

My favorite features in Scala



  • Tupples in function results

    def f(a: int, b: int) : (int, int) = (a/b, a%b)


  • type Nothing and Null (like NONE and ANY in Eiffel)
  • Object definitions
    object Singleton { }

  • Parameterless methods, that can be overridden by fields and vice versa.

    class Circle(radius:double) {
    def diameter = 2*radius
    }
    ...
    new Circle(5).diameter


  • Subtyping of generics (so-called co-variant subtyping). I miss this feature in Java:

    def Iterator[+E] ...
    now Iterator[String] will assign to Iterator[AnyObj].


  • Pattern-matching expressions? Need to try it.


Some of these I was missing since I programmed in Eiffel back in 1995.

Features I am not so fond of:

  • Case classes (a-la subtyped enums?)