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.io.InputStream; 32 import java.nio.file.Files; 33 import java.util.Random; 34 import java.util.concurrent.TimeUnit; 35 import java.util.jar.JarFile; 36 import java.util.jar.JarOutputStream; 37 import java.util.jar.Manifest; 38 import java.util.zip.ZipEntry; 39 40 /** 41 * Simple benchmark measuring cost of various operations relating to jar 42 * meta-inf and manifests, especially costs incurred during opening of the 43 * file, and when opening an input stream (which runs 44 * JarFile.maybeInstantiateVerifier) 45 * 46 * Before JDK-8244624: 47 * Benchmark (size) Mode Cnt Score Error Units 48 * getManifestFromJarWithManifest 1024 avgt 5 232.437 31.535 us/op 49 * gc.alloc.rate.norm 1024 avgt 5 206410.627 2.833 B/op 50 * getStreamFromJarWithManifest 1024 avgt 5 277.696 32.078 us/op 51 * gc.alloc.rate.norm 1024 avgt 5 250454.252 2.452 B/op 52 * getStreamFromJarWithNoManifest 1024 avgt 5 312.432 58.663 us/op 53 * gc.alloc.rate.norm 1024 avgt 5 301802.644 13.276 B/op 54 * getStreamFromJarWithSignatureFiles 1024 avgt 5 315.752 55.048 us/op 55 * gc.alloc.rate.norm 1024 avgt 5 305354.934 14.093 B/op 56 * 57 * With JDK-8244624: 58 * Benchmark (size) Mode Cnt Score Error Units 59 * getManifestFromJarWithManifest 1024 avgt 5 215.242 32.085 us/op 60 * gc.alloc.rate.norm 1024 avgt 5 196609.220 14.788 B/op 61 * getStreamFromJarWithManifest 1024 avgt 5 216.435 10.876 us/op 62 * gc.alloc.rate.norm 1024 avgt 5 187960.147 9.026 B/op 63 * getStreamFromJarWithNoManifest 1024 avgt 5 204.256 25.744 us/op 64 * gc.alloc.rate.norm 1024 avgt 5 186784.347 1.841 B/op 65 * getStreamFromJarWithSignatureFiles 1024 avgt 5 247.972 38.574 us/op 66 * gc.alloc.rate.norm 1024 avgt 5 211577.268 15.109 B/op 67 */ 68 @BenchmarkMode(Mode.AverageTime) 69 @OutputTimeUnit(TimeUnit.MICROSECONDS) 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 JarFileMeta { 75 76 @Param({"512", "1024"}) 77 private int size; 78 79 public File jarManifest; 80 public File jarNoManifest; 81 public File jarManifestSignature; 82 83 public int index = 0; 84 85 @Setup(Level.Trial) beforeRun()86 public void beforeRun() throws IOException { 87 jarNoManifest = createJar(false, false); 88 jarManifest = createJar(true, false); 89 jarManifestSignature = createJar(true, true); 90 } 91 createJar(boolean manifest, boolean signatureFiles)92 private File createJar(boolean manifest, boolean signatureFiles) throws IOException { 93 // Create a test Zip file with the number of entries. 94 File tempFile = Files.createTempFile("jar-micro", ".jar").toFile(); 95 tempFile.deleteOnExit(); 96 97 try (FileOutputStream fos = new FileOutputStream(tempFile); 98 JarOutputStream zos = manifest 99 ? new JarOutputStream(fos, new Manifest()) 100 : new JarOutputStream(fos)) { 101 102 // Always add this 103 zos.putNextEntry(new ZipEntry("README")); 104 105 Random random = new Random(4711); 106 for (int i = 0; i < size; i++) { 107 String ename = "directory-" + (random.nextInt(90000) + 10000) + "-" + i + "/"; 108 if (random.nextInt(100) > 70) { 109 ename = "META-INF/" + ename; 110 111 } 112 zos.putNextEntry(new ZipEntry(ename)); 113 114 ename += "entry-" + (random.nextInt(90000) + 10000) + "-" + i; 115 if (signatureFiles && random.nextInt(100) > 95) { 116 ename += ".DSA"; 117 } 118 zos.putNextEntry(new ZipEntry(ename)); 119 } 120 } 121 return tempFile; 122 } 123 openGetStreamAndClose(File file)124 private InputStream openGetStreamAndClose(File file) throws IOException { 125 JarFile jf = new JarFile(file); 126 InputStream is = jf.getInputStream(jf.getEntry("README")); 127 jf.close(); 128 // we'll never actually read from the closed stream, rather just 129 // return it to avoid DCE 130 return is; 131 } 132 133 @Benchmark getStreamFromJarWithManifest()134 public InputStream getStreamFromJarWithManifest() throws IOException { 135 return openGetStreamAndClose(jarManifest); 136 } 137 138 @Benchmark getStreamFromJarWithNoManifest()139 public InputStream getStreamFromJarWithNoManifest() throws IOException { 140 return openGetStreamAndClose(jarNoManifest); 141 } 142 143 @Benchmark getStreamFromJarWithSignatureFiles()144 public InputStream getStreamFromJarWithSignatureFiles() throws IOException { 145 return openGetStreamAndClose(jarManifestSignature); 146 } 147 148 @Benchmark getManifestFromJarWithManifest()149 public Manifest getManifestFromJarWithManifest() throws IOException { 150 JarFile jf = new JarFile(jarManifest); 151 Manifest mf = jf.getManifest(); 152 jf.close(); 153 return mf; 154 } 155 } 156