diff --git a/test/micro/org/openjdk/bench/java/net/URLEncodeDecode.java b/test/micro/org/openjdk/bench/java/net/URLEncodeDecode.java index 1bd98f9ed52..a599a68f924 100644 --- a/test/micro/org/openjdk/bench/java/net/URLEncodeDecode.java +++ b/test/micro/org/openjdk/bench/java/net/URLEncodeDecode.java @@ -37,6 +37,7 @@ import org.openjdk.jmh.infra.Blackhole; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.util.Random; import java.util.concurrent.TimeUnit; @@ -51,78 +52,140 @@ import java.util.concurrent.TimeUnit; @Fork(value = 3) public class URLEncodeDecode { - @Param("1024") - public int count; + private static final int COUNT = 1024; @Param("1024") public int maxLength; - @Param("3") - public long mySeed; + /** + * Percentage of strings that will remain unchanged by an encoding/decoding (0-100) + */ + @Param({"0", "75", "100"}) + public int unchanged; + + /** + * Percentage of chars in changed strings that cause encoding/decoding to happen (0-100) + */ + @Param({"6"}) + public int encodeChars; public String[] testStringsEncode; public String[] testStringsDecode; public String[] toStrings; - @Setup + @Setup() public void setupStrings() { - char[] tokens = new char[((int) 'Z' - (int) 'A' + 1) + ((int) 'z' - (int) 'a' + 1) + ((int) '9' - (int) '1' + 1) + 5]; + char[] encodeTokens = new char[] { '[', '(', ' ', '\u00E4', '\u00E5', '\u00F6', ')', '='}; + char[] tokens = new char[('Z' - 'A' + 1) + ('z' - 'a' + 1) + ('9' - '0' + 1) + 4]; int n = 0; - tokens[n++] = '0'; - for (int i = (int) '1'; i <= (int) '9'; i++) { - tokens[n++] = (char) i; + for (char c = '0'; c <= '9'; c++) { + tokens[n++] = c; } - for (int i = (int) 'A'; i <= (int) 'Z'; i++) { - tokens[n++] = (char) i; + for (char c = 'A'; c <= 'Z'; c++) { + tokens[n++] = c; } - for (int i = (int) 'a'; i <= (int) '<'; i++) { - tokens[n++] = (char) i; + for (char c = 'a'; c <= 'z'; c++) { + tokens[n++] = c; } tokens[n++] = '-'; tokens[n++] = '_'; tokens[n++] = '.'; - tokens[n++] = '*'; + tokens[n] = '*'; - Random r = new Random(mySeed); - testStringsEncode = new String[count]; - testStringsDecode = new String[count]; - toStrings = new String[count]; - for (int i = 0; i < count; i++) { + Random r = new Random(3); + testStringsEncode = new String[COUNT]; + testStringsDecode = new String[COUNT]; + toStrings = new String[COUNT]; + for (int i = 0; i < COUNT; i++) { int l = r.nextInt(maxLength); + boolean needEncoding = r.nextInt(100) >= unchanged; StringBuilder sb = new StringBuilder(); + boolean hasEncoded = false; for (int j = 0; j < l; j++) { - int c = r.nextInt(tokens.length); - sb.append(tokens[c]); + if (needEncoding && r.nextInt(100) < encodeChars) { + addToken(encodeTokens, r, sb); + hasEncoded = true; + } else { + addToken(tokens, r, sb); + } + } + if (needEncoding && !hasEncoded) { + addToken(encodeTokens, r, sb); } testStringsEncode[i] = sb.toString(); } - - for (int i = 0; i < count; i++) { - int l = r.nextInt(maxLength); - StringBuilder sb = new StringBuilder(); - for (int j = 0; j < l; j++) { - int c = r.nextInt(tokens.length + 5); - if (c >= tokens.length) { - sb.append("%").append(tokens[r.nextInt(16)]).append(tokens[r.nextInt(16)]); - } else { - sb.append(tokens[c]); + int countUnchanged = 0; + for (String s : testStringsEncode) { + if (s.equals(java.net.URLEncoder.encode(s, StandardCharsets.UTF_8))) { + countUnchanged++; + } else { + if (unchanged == 100) { + System.out.println("Unexpectedly needs encoding action: "); + System.out.println("\t" + s); + System.out.println("\t" + java.net.URLEncoder.encode(s, StandardCharsets.UTF_8)); } } + } + System.out.println(); + System.out.println("Generated " + testStringsEncode.length + " encodable strings, " + countUnchanged + " of which does not need encoding action"); + + for (int i = 0; i < COUNT; i++) { + int l = r.nextInt(maxLength); + boolean needDecoding = r.nextInt(100) >= unchanged; + StringBuilder sb = new StringBuilder(); + boolean hasDecoded = false; + for (int j = 0; j < l; j++) { + if (needDecoding && r.nextInt(100) < encodeChars) { + addDecodableChar(tokens, r, sb); + hasDecoded = true; + } else { + addToken(tokens, r, sb); + } + } + if (needDecoding && !hasDecoded) { + addDecodableChar(tokens, r, sb); + } testStringsDecode[i] = sb.toString(); } + countUnchanged = 0; + for (String s : testStringsDecode) { + if (s.equals(java.net.URLDecoder.decode(s, StandardCharsets.UTF_8))) { + countUnchanged++; + } else { + if (unchanged == 100) { + System.out.println("Unexpectedly needs encoding action: "); + System.out.println("\t" + s); + System.out.println("\t" + java.net.URLDecoder.decode(s, StandardCharsets.UTF_8)); + } + } + } + System.out.println("Generated " + testStringsDecode.length + " decodable strings, " + countUnchanged + " of which does not need decoding action"); + } + + private static void addToken(char[] tokens, Random r, StringBuilder sb) { + int c = r.nextInt(tokens.length); + sb.append(tokens[c]); + } + + private static void addDecodableChar(char[] tokens, Random r, StringBuilder sb) { + if (r.nextInt(100) < 15) { + sb.append('+'); // exercise '+' -> ' ' decoding paths. + } else { + sb.append("%").append(tokens[r.nextInt(16)]).append(tokens[r.nextInt(16)]); + } } @Benchmark public void testEncodeUTF8(Blackhole bh) throws UnsupportedEncodingException { for (String s : testStringsEncode) { - bh.consume(java.net.URLEncoder.encode(s, "UTF-8")); + bh.consume(java.net.URLEncoder.encode(s, StandardCharsets.UTF_8)); } } @Benchmark public void testDecodeUTF8(Blackhole bh) throws UnsupportedEncodingException { for (String s : testStringsDecode) { - bh.consume(URLDecoder.decode(s, "UTF-8")); + bh.consume(URLDecoder.decode(s, StandardCharsets.UTF_8)); } }