Инициализируйте FileInputStream в JMH @Setup и используйте в @Benchmark - PullRequest
0 голосов
/ 07 февраля 2019

InputStream инициализируется в @Setup, при попытке использовать его в @Benchmark закрыто.Изменение @State не работает.Я делаю это правильно?Есть ли способ избежать накладных расходов на инициализацию потока и сделать надлежащий тест?

Это также не работает для XMLStreamReader, я также делаю тест десериализации сериализации, где я хочу избежать затрат на чтение / инициализацию файла воценка производительности.

пример теста

@State( Scope.Thread )
public class DeserializationBenchMark
{
    @Param( { "1.xml", "10.xml", "100.xml" } )
    String file;

    private InputStream xmlFileInputStream;

    @Setup
    public void setup() throws JAXBException, IOException, SAXException, XMLStreamException
    {
        File xmlFile = new File( "src/main/resources/" + file );
        xmlFileInputStream = Files.newInputStream( xmlFile.toPath() );
    }

    @Benchmark
    public void jacksonDeserializeStreamTest( Blackhole bh ) throws IOException
    {
        bh.consume( objectMapper.readValue( xmlFileInputStream, Cat.class ) );
    }

}

бегун

public class BenchMarkRunner
{
    public static void main( String[] args ) throws RunnerException
    {
        Options opt = new OptionsBuilder()
                              .include( DeserializationBenchMark.class.getSimpleName() )
                              .forks( 1 )
                              .resultFormat( ResultFormatType.JSON )
                              .result( "deserialize-benchmark-report-" + LocalDateTime.now().format( DateTimeFormatter.ofPattern( "ddMMyyyy'T'hhmmss" ) ) + ".json" )
                              .mode( Mode.AverageTime )
                              .warmupIterations( 3 )
                              .measurementIterations( 5 )
                              .timeUnit( TimeUnit.MICROSECONDS )
                              .build();

        new Runner( opt ).run();
    }
}

Это дает

com.fasterxml.jackson.core.JsonParseException: N/A
    at com.fasterxml.jackson.dataformat.xml.util.StaxUtil.throwAsParseException(StaxUtil.java:37)
    at com.fasterxml.jackson.dataformat.xml.XmlFactory._createParser(XmlFactory.java:534)
    at com.fasterxml.jackson.dataformat.xml.XmlFactory._createParser(XmlFactory.java:29)
    at com.fasterxml.jackson.core.JsonFactory.createParser(JsonFactory.java:820)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3058)
    at com.example.DeserializationBenchMark.jacksonDeserializeStreamTest(DeserializationBenchMark.java:118)
    at com.example.generated.DeserializationBenchMark_jacksonDeserializeStreamTest_jmhTest.jacksonDeserializeStreamTest_avgt_jmhStub(DeserializationBenchMark_jacksonDeserializeStreamTest_jmhTest.java:186)
    at com.example.generated.DeserializationBenchMark_jacksonDeserializeStreamTest_jmhTest.jacksonDeserializeStreamTest_AverageTime(DeserializationBenchMark_jacksonDeserializeStreamTest_jmhTest.java:150)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.openjdk.jmh.runner.BenchmarkHandler$BenchmarkTask.call(BenchmarkHandler.java:453)
    at org.openjdk.jmh.runner.BenchmarkHandler$BenchmarkTask.call(BenchmarkHandler.java:437)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.nio.channels.ClosedChannelException
    at sun.nio.ch.FileChannelImpl.ensureOpen(FileChannelImpl.java:110)
    at sun.nio.ch.FileChannelImpl.read(FileChannelImpl.java:147)
    at sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:65)
    at sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:109)
    at sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:103)
    at com.ctc.wstx.io.StreamBootstrapper.ensureLoaded(StreamBootstrapper.java:482)
    at com.ctc.wstx.io.StreamBootstrapper.resolveStreamEncoding(StreamBootstrapper.java:306)
    at com.ctc.wstx.io.StreamBootstrapper.bootstrapInput(StreamBootstrapper.java:167)
    at com.ctc.wstx.stax.WstxInputFactory.doCreateSR(WstxInputFactory.java:573)
    at com.ctc.wstx.stax.WstxInputFactory.createSR(WstxInputFactory.java:633)
    at com.ctc.wstx.stax.WstxInputFactory.createSR(WstxInputFactory.java:647)
    at com.ctc.wstx.stax.WstxInputFactory.createXMLStreamReader(WstxInputFactory.java:334)
    at com.fasterxml.jackson.dataformat.xml.XmlFactory._createParser(XmlFactory.java:532)
    ... 18 more

Любое предложение будет замечательно!Спасибо.

PS:

Как уже упоминалось @dit Это должно быть закрыто потоком, любая идея, почему это происходит на первой итерации,

# Run progress: 0.00% complete, ETA 00:07:30
# Fork: 1 of 1
# Warmup Iteration   1: <failure>

com.fasterxml.jackson.core.JsonParseException: N/A
    at com.fasterxml.jackson.dataformat.xml.util.StaxUtil.throwAsParseException(StaxUtil.java:37)
    at com.fasterxml.jackson.dataformat.xml.XmlFactory._createParser(XmlFactory.java:534)
    at com.fasterxml.jackson.dataformat.xml.XmlFactory._createParser(XmlFactory.java:29)
    at com.fasterxml.jackson.core.JsonFactory.createParser(JsonFactory.java:820)

1 Ответ

0 голосов
/ 07 февраля 2019

TL; DR

Проблема в : первый вызов метода прогрева был успешным, но следующий - нет.попробуйте добавить System.out.println("method call");, и вы увидите, что я имею в виду:

> # Run progress: 0,00% complete, ETA 00:00:11
> # Fork: 1 of 1
> # Warmup Iteration   1: method call 
> method call
> <failure>

Каждый раз после вызова objectMapper.readValue(..) используемый InputStream будет закрыт и не может быть использованеще раз:

Причина: java.nio.channels.ClosedChannelException

Вы можете попробовать что-то вроде этого:

@Param( { "1.xml", "10.xml", "100.xml" } )
String file;

private String jsonData;

@Setup
public void setup() {
    jsonData = getContent(file);
}

@Benchmark
public void jacksonDeserializeStreamTest(Blackhole bh) throws IOException {
    bh.consume(objectMapper.readValue(jsonData, Cat.class));
}

private static String getContent(String fileName) {
    try {
        InputStream stream = PersonGenerator.class.getClassLoader().getResourceAsStream(fileName);
        ByteArrayOutputStream result = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int length;
        while ((length = stream.read(buffer)) != -1) {
            result.write(buffer, 0, length);
        }
        return result.toString("UTF-8");
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

Вы можете попробоватьаналогичный бенчмарк: Gson-vs-Jackson-Benchmark

EDIT

К сожалению, вы не можете использовать InputStream более чем на одном: JavaВ / В - повторно использовать объект InputStream

Но, возможно, вы можете попробовать это (псевдокод!):

String rawData = getContent("cats.json");
StringReader reader = new StringReader(rawData);

[...]
reader.mark(0); // reset
m.readValue(reader, type);
[...]
...