Skip to content

Optimizing compiler is too clever #1

Open
@JakubVanek

Description

@JakubVanek

Hi,

I've tried using System.nanoTime and I still get negative durations on my machine (OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode):

GeneralBench 1.2
[...]
  200000 byte add:                          1926082 ns    103837738 ops/sec
  200000 byte sub:                          -847484 ns   -235992655 ops/sec
  200000 byte mul:                          -818918 ns   -244224696 ops/sec
  200000 byte div:                          -597373 ns   -334799195 ops/sec
[...]

The compiler (source → bytecode or bytecode → x86) must be somehow reordering the program flow.

private static int benchArithByte(int count)
{
    byte a, b, c;

    long nullTime = BenchUtils.getIterationTime(count);
    long start, end;

    // Add
    a = (byte)0x77;
    b = (byte)0x11;
    start = System.nanoTime();
    for (int i = 0; i < count; i++)
        c = (byte) (a + b);
    end = System.nanoTime();
    report(count, "byte add", count, "ops", end - start - nullTime);

    // sub
    a = (byte) 0x88;
    b = (byte) 0x11;
    start = System.nanoTime();
    for (int i = 0; i < count; i++)
        c = (byte) (a - b);
    end = System.nanoTime();
    report(count, "byte sub", count, "ops", end - start - nullTime);

    // Mul
    a = (byte) 0x0F;
    b = (byte) 0x11;
    start = System.nanoTime();
    for (int i = 0; i < count; i++)
        c = (byte) (a * b);
    end = System.nanoTime();
    report(count, "byte mul", count, "ops", end - start - nullTime);

    // Div
    a = (byte) 0xFE;
    b = (byte) 0x0E;
    start = System.nanoTime();
    for (int i = 0; i < count; i++)
        c = (byte) (a / b);
    end = System.nanoTime();
    report(count, "byte div", count, "ops", end - start - nullTime);
    
    return count * 4;
}

The same thing happens on the brick with OpenJDK 9, with the exception that it's in the float benchmark.

GeneralBench 1.2
[...]
  200000 float add:                       153755469 ns      1300766 ops/sec
  200000 float sub:                          723385 ns    276477947 ops/sec
  200000 float mul:                         -891574 ns   -224322378 ops/sec
  200000 float div:                          -79218 ns  -2524678734 ops/sec
[...]

Well, I know of two possible solutions. One is to try to isolate benchmarks to their own functions and somehow limit the optimizer, the second is to use Java Microbenchmark Harness - I've read on StackOverflow that it is the recommended way of running tests like this.

Jakub Vaněk

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions