1 /* 2 * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package org.openjdk.bench.java.util.jar; 25 26 import org.openjdk.jmh.annotations.*; 27 28 import java.io.File; 29 import java.io.FileOutputStream; 30 import java.io.IOException; 31 import java.nio.file.Files; 32 import java.util.Random; 33 import java.util.concurrent.TimeUnit; 34 import java.util.jar.Attributes; 35 import java.util.jar.JarEntry; 36 import java.util.jar.JarFile; 37 import java.util.jar.JarOutputStream; 38 import java.util.jar.Manifest; 39 import java.util.zip.ZipEntry; 40 import java.util.zip.ZipFile; 41 42 /** 43 * Simple benchmark measuring cost of looking up versioned entries in a zip 44 * file. 45 * 46 * Before JDK-XXXXXXX 47 * Benchmark (size) Mode Cnt Score Error Units 48 * JarFileGetVersionedEntry.getEntryHit 1024 avgt 5 211.543 25.846 ns/op 49 * gc.alloc.rate.norm 1024 avgt 5 232.020 0.011 B/op 50 * JarFileGetVersionedEntry.getEntryHitUncached 1024 avgt 5 233.740 40.079 ns/op 51 * gc.alloc.rate.norm 1024 avgt 5 288.025 0.004 B/op 52 * JarFileGetVersionedEntry.getEntryMiss 1024 avgt 5 174.355 30.211 ns/op 53 * gc.alloc.rate.norm 1024 avgt 5 72.007 0.010 B/op 54 * JarFileGetVersionedEntry.getEntryMissUncached 1024 avgt 5 202.069 52.302 ns/op 55 * gc.alloc.rate.norm 1024 avgt 5 128.199 0.007 B/op 56 * 57 * After JDK-XXXXXXX 58 * Benchmark (size) Mode Cnt Score Error Units 59 * JarFileGetVersionedEntry.getEntryHit 1024 avgt 5 153.930 24.785 ns/op 60 * gc.alloc.rate.norm 1024 avgt 5 144.012 0.002 B/op 61 * JarFileGetVersionedEntry.getEntryHitUncached 1024 avgt 5 205.168 26.654 ns/op 62 * gc.alloc.rate.norm 1024 avgt 5 200.016 0.002 B/op 63 * JarFileGetVersionedEntry.getEntryMiss 1024 avgt 5 57.551 23.338 ns/op 64 * gc.alloc.rate.norm 1024 avgt 5 16.001 0.003 B/op 65 * JarFileGetVersionedEntry.getEntryMissUncached 1024 avgt 5 116.451 28.830 ns/op 66 * gc.alloc.rate.norm 1024 avgt 5 72.194 0.002 B/op 67 */ 68 @BenchmarkMode(Mode.AverageTime) 69 @OutputTimeUnit(TimeUnit.NANOSECONDS) 70 @State(Scope.Thread) 71 @Warmup(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) 72 @Measurement(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS) 73 @Fork(3) 74 public class JarFileGetVersionedEntry { 75 76 @Param({"512", "1024"}) 77 private int size; 78 79 public JarFile jarFile; 80 public String[] entryNames; 81 public String[] missingEntryNames; 82 public StringBuilder[] entryNameBuilders; 83 public StringBuilder[] missingEntryNameBuilders; 84 85 public int index = 0; 86 87 @Setup(Level.Trial) 88 public void beforeRun() throws IOException { 89 // Create a test Zip file with the number of entries. 90 File tempFile = Files.createTempFile("jar-mr-micro", ".jar").toFile(); 91 tempFile.deleteOnExit(); 92 93 entryNameBuilders = new StringBuilder[size]; 94 missingEntryNameBuilders = new StringBuilder[size]; 95 96 entryNames = new String[size]; 97 missingEntryNames = new String[size]; 98 99 Attributes attributes = new Attributes(); 100 attributes.putValue("Manifest-Version", "1.0"); 101 attributes.putValue("Created-By", "1.9.0-internal (Oracle Corporation)"); 102 attributes.putValue("Multi-Release", "true"); 103 try (FileOutputStream fos = new FileOutputStream(tempFile); 104 JarOutputStream jos = new JarOutputStream(fos)) { 105 106 JarEntry me = new JarEntry("META-INF/MANIFEST.MF"); 107 jos.putNextEntry(me); 108 Manifest manifest = new Manifest(); 109 manifest.getMainAttributes().putAll(attributes); 110 manifest.write(jos); 111 jos.closeEntry(); 112 113 Random random = new Random(4711); 114 for (int i = 0; i < size; i++) { 115 String ename = "entry-" + (random.nextInt(90000) + 10000) + "-" + i; 116 jos.putNextEntry(new ZipEntry(ename)); 117 118 entryNames[i] = ename; 119 entryNameBuilders[i] = new StringBuilder(ename); 120 121 missingEntryNames[i] = ename + "-"; 122 missingEntryNameBuilders[i] = new StringBuilder(missingEntryNames[i]); 123 124 ename = "META-INF/versions/" + JarFile.runtimeVersion().feature() + "/" + ename; 125 jos.putNextEntry(new ZipEntry(ename)); 126 } 127 } 128 129 jarFile = new JarFile(tempFile, true, ZipFile.OPEN_READ, 130 JarFile.runtimeVersion()); 131 } 132 133 @Benchmark 134 public void getEntryHit() { 135 if (index >= size) { 136 index = 0; 137 } 138 jarFile.getEntry(entryNames[index++]); 139 } 140 141 @Benchmark 142 public void getEntryMiss() { 143 if (index >= size) { 144 index = 0; 145 } 146 jarFile.getEntry(missingEntryNames[index++]); 147 } 148 149 @Benchmark 150 public void getEntryHitUncached() { 151 if (index >= size) { 152 index = 0; 153 } 154 jarFile.getEntry(entryNameBuilders[index++].toString()); 155 } 156 157 @Benchmark 158 public void getEntryMissUncached() { 159 if (index >= size) { 160 index = 0; 161 } 162 jarFile.getEntry(missingEntryNameBuilders[index++].toString()); 163 } 164 }