Search code examples
javamicrobenchmarkjmh

How do I suppress the output of methods that print to the console inside jmh benchmarks?


I am using jmh to compare the performance of several methods that print a lot to the console. In fact, these are different solutions of a fizzbazz problem.

Each implementation of fizzbuzz is a class that implements the FizzBazz interface and has a print() method. All these implementations are compiled into a separate jar.

I am trying to suppress output of this method in my benchmarks. Thus, I need to replace the output stream with an array before running the benchmarks, and return it back after they finish.

If I do this inside each benchmark method, like this:

@Benchmark
public void naiveTest() {
    PrintStream originalOut = System.out;
    ByteArrayOutputStream outContent = new ByteArrayOutputStream();
    System.setOut(new PrintStream(outContent));

    new NaiveFizzBuzz().print(N); // N is upper limit
    
    System.setOut(originalOut);
}

then everything works fine. But this is a bunch of repetitive code, and I don't want to get rid of it. Besides, this code breaks measurements, as it is called every time the test is run.

I'm trying to use state for my task.

@State(Scope.Benchmark)
public static class MyState {
    private PrintStream originalOut;

    @Setup
    public void doSetup() {
        originalOut = System.out;
        ByteArrayOutputStream outContent = new ByteArrayOutputStream();
        System.setOut(new PrintStream(outContent));
    }

    @TearDown
    public void doTearDown() {
        System.setOut(originalOut);
    }
}

And my benchmarks looks like this:

@Benchmark
public void naiveTest() {
    new NaiveFizzBuzz().print(N);
}

// Lots of similar benchmarks here...

But it doesn't work.

How can I put all the code for replacing the output stream in one place so that it is automatically executed before each test run?


Solution

  • I found a solution to my problem. It consists in the fact that I need to pass my state object as an argument to each benchmark.

    @Benchmark
    public void naiveTest(MyState state) {
        new NaiveFizzBuzz().print(N);
    }
    

    works exactly as i need.

    Unfortunately, the documentation of jmh is not very user-friendly, so it took me a while to find this point.

    I have done a little research and I have come to the conclusion that it is OK to answer my own question. Please correct me if this is not the case. Then I'll edit the question.