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.zip;
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.zip.ZipEntry;
35 import java.util.zip.ZipFile;
36 import java.util.zip.ZipOutputStream;
37 
38 /**
39  * Simple benchmark measuring cost of looking up entries in a zip file.
40  *
41  * Uncached variants create a new String before lookup. Intent is to have
42  * every String's hashCode cache be uninitialized, in case the implementation
43  * uses it internally.
44  *
45  * Pre-JDK-8243469:
46  * Benchmark                             (size)  Mode  Cnt    Score   Error  Units
47  * ZipFileGetEntry.getEntryHit              512  avgt   15  126.264   5.297  ns/op
48  * ZipFileGetEntry.getEntryHit             1024  avgt   15  130.823   7.212  ns/op
49  * ZipFileGetEntry.getEntryHitUncached      512  avgt   15  152.149   4.978  ns/op
50  * ZipFileGetEntry.getEntryHitUncached     1024  avgt   15  151.527   4.054  ns/op
51  * ZipFileGetEntry.getEntryMiss             512  avgt   15   73.242   3.218  ns/op
52  * ZipFileGetEntry.getEntryMiss            1024  avgt   15   82.115   5.961  ns/op
53  * ZipFileGetEntry.getEntryMissUncached     512  avgt   15   94.313   5.533  ns/op
54  * ZipFileGetEntry.getEntryMissUncached    1024  avgt   15   99.135   4.422  ns/op
55  *
56  * JDK-8243469:
57  * Benchmark                             (size)  Mode  Cnt    Score   Error  Units
58  * ZipFileGetEntry.getEntryHit              512  avgt   15   84.450   5.474  ns/op
59  * ZipFileGetEntry.getEntryHit             1024  avgt   15   85.224   3.776  ns/op
60  * ZipFileGetEntry.getEntryHitUncached      512  avgt   15  140.448   4.667  ns/op
61  * ZipFileGetEntry.getEntryHitUncached     1024  avgt   15  145.046   7.363  ns/op
62  * ZipFileGetEntry.getEntryMiss             512  avgt   15   19.093   0.169  ns/op
63  * ZipFileGetEntry.getEntryMiss            1024  avgt   15   21.460   0.522  ns/op
64  * ZipFileGetEntry.getEntryMissUncached     512  avgt   15   74.982   3.363  ns/op
65  * ZipFileGetEntry.getEntryMissUncached    1024  avgt   15   81.856   3.648  ns/op
66  */
67 @BenchmarkMode(Mode.AverageTime)
68 @OutputTimeUnit(TimeUnit.NANOSECONDS)
69 @State(Scope.Thread)
70 @Warmup(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
71 @Measurement(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
72 @Fork(3)
73 public class ZipFileGetEntry {
74 
75     @Param({"512", "1024"})
76     private int size;
77 
78     public ZipFile          zipFile;
79     public String[]         entryNames;
80     public String[]         missingEntryNames;
81     public StringBuilder[]  entryNameBuilders;
82     public StringBuilder[]  missingEntryNameBuilders;
83 
84     public int index = 0;
85 
86     @Setup(Level.Trial)
beforeRun()87     public void beforeRun() throws IOException {
88         // Create a test Zip file with the number of entries.
89         File tempFile = Files.createTempFile("zip-micro", ".zip").toFile();
90         tempFile.deleteOnExit();
91 
92         entryNameBuilders = new StringBuilder[size];
93         missingEntryNameBuilders = new StringBuilder[size];
94 
95         entryNames = new String[size];
96         missingEntryNames = new String[size];
97         try (FileOutputStream fos = new FileOutputStream(tempFile);
98              ZipOutputStream zos = new ZipOutputStream(fos)) {
99 
100             Random random = new Random(4711);
101             for (int i = 0; i < size; i++) {
102                 String ename = "directory-" + (random.nextInt(90000) + 10000) + "-" + i + "/";
103                 zos.putNextEntry(new ZipEntry(ename));
104 
105                 ename += "entry-"  + (random.nextInt(90000) + 10000)  + "-" + i;
106                 zos.putNextEntry(new ZipEntry(ename));
107 
108                 entryNames[i] = ename;
109                 entryNameBuilders[i] = new StringBuilder(ename);
110 
111                 missingEntryNames[i] = ename + "-";
112                 missingEntryNameBuilders[i] = new StringBuilder(missingEntryNames[i]);
113             }
114         }
115         zipFile = new ZipFile(tempFile);
116     }
117 
118     @Benchmark
getEntryHit()119     public void getEntryHit() {
120         if (index >= size) {
121             index = 0;
122         }
123         zipFile.getEntry(entryNames[index++]);
124     }
125 
126     @Benchmark
getEntryMiss()127     public void getEntryMiss() {
128         if (index >= size) {
129             index = 0;
130         }
131         zipFile.getEntry(missingEntryNames[index++]);
132     }
133 
134     @Benchmark
getEntryHitUncached()135     public void getEntryHitUncached() {
136         if (index >= size) {
137             index = 0;
138         }
139         zipFile.getEntry(entryNameBuilders[index++].toString());
140     }
141 
142     @Benchmark
getEntryMissUncached()143     public void getEntryMissUncached() {
144         if (index >= size) {
145             index = 0;
146         }
147         zipFile.getEntry(missingEntryNameBuilders[index++].toString());
148     }
149 }
150