Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files
8196334: Optimize UUID#fromString
Co-authored-by: Andriy Plokhotnyuk <plokhotnyuk@gmail.com>
Co-authored-by: Jon Chambers <jon.chambers@gmail.com>
Reviewed-by: igerasim, alanb
  • Loading branch information
3 people committed Mar 2, 2020
1 parent 751de03 commit ebadfaeb2e1cc7b5ce5f101cd8a539bc5478cf5b
Showing with 145 additions and 5 deletions.
  1. +65 −1 src/java.base/share/classes/java/util/UUID.java
  2. +5 −4 test/jdk/java/util/UUID/UUIDTest.java
  3. +75 −0 test/micro/org/openjdk/bench/java/util/UUIDBench.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -180,6 +180,45 @@ public static UUID nameUUIDFromBytes(byte[] name) {
return new UUID(md5Bytes);
}

private static final byte[] NIBBLES;
static {
byte[] ns = new byte[256];
Arrays.fill(ns, (byte) -1);
ns['0'] = 0;
ns['1'] = 1;
ns['2'] = 2;
ns['3'] = 3;
ns['4'] = 4;
ns['5'] = 5;
ns['6'] = 6;
ns['7'] = 7;
ns['8'] = 8;
ns['9'] = 9;
ns['A'] = 10;
ns['B'] = 11;
ns['C'] = 12;
ns['D'] = 13;
ns['E'] = 14;
ns['F'] = 15;
ns['a'] = 10;
ns['b'] = 11;
ns['c'] = 12;
ns['d'] = 13;
ns['e'] = 14;
ns['f'] = 15;
NIBBLES = ns;
}

private static long parse4Nibbles(String name, int pos) {
byte[] ns = NIBBLES;
char ch1 = name.charAt(pos);
char ch2 = name.charAt(pos + 1);
char ch3 = name.charAt(pos + 2);
char ch4 = name.charAt(pos + 3);
return (ch1 | ch2 | ch3 | ch4) > 0xff ?
-1 : ns[ch1] << 12 | ns[ch2] << 8 | ns[ch3] << 4 | ns[ch4];
}

/**
* Creates a {@code UUID} from the string standard representation as
* described in the {@link #toString} method.
@@ -195,6 +234,31 @@ public static UUID nameUUIDFromBytes(byte[] name) {
*
*/
public static UUID fromString(String name) {
if (name.length() == 36) {
char ch1 = name.charAt(8);
char ch2 = name.charAt(13);
char ch3 = name.charAt(18);
char ch4 = name.charAt(23);
if (ch1 == '-' && ch2 == '-' && ch3 == '-' && ch4 == '-') {
long msb1 = parse4Nibbles(name, 0);
long msb2 = parse4Nibbles(name, 4);
long msb3 = parse4Nibbles(name, 9);
long msb4 = parse4Nibbles(name, 14);
long lsb1 = parse4Nibbles(name, 19);
long lsb2 = parse4Nibbles(name, 24);
long lsb3 = parse4Nibbles(name, 28);
long lsb4 = parse4Nibbles(name, 32);
if ((msb1 | msb2 | msb3 | msb4 | lsb1 | lsb2 | lsb3 | lsb4) >= 0) {
return new UUID(
msb1 << 48 | msb2 << 32 | msb3 << 16 | msb4,
lsb1 << 48 | lsb2 << 32 | lsb3 << 16 | lsb4);
}
}
}
return fromString1(name);
}

private static UUID fromString1(String name) {
int len = name.length();
if (len > 36) {
throw new IllegalArgumentException("UUID string too large");
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,7 +22,7 @@
*/

/* @test
* @bug 4173528 5068772 8148936
* @bug 4173528 5068772 8148936 8196334
* @summary Unit tests for java.util.UUID
* @key randomness
* @run main/othervm -XX:+CompactStrings UUIDTest
@@ -95,8 +95,9 @@ private static void nameUUIDFromBytesTest() throws Exception {
private static void stringTest() throws Exception {
for (int i=0; i<100; i++) {
UUID u1 = UUID.randomUUID();
UUID u2 = UUID.fromString(u1.toString());
if (!u1.equals(u2))
UUID u2 = UUID.fromString(u1.toString().toLowerCase());
UUID u3 = UUID.fromString(u1.toString().toUpperCase());
if (!u1.equals(u2) || !u1.equals(u3))
throw new Exception("UUID -> string -> UUID failed");
}

@@ -0,0 +1,75 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.openjdk.bench.java.util;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

import org.openjdk.jmh.annotations.*;

@State(Scope.Thread)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Fork(value = 3)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)
public class UUIDBench {

@Param("20000")
private int size;

private UUID[] uuids;

private String[] uuidStrings;

private int index = 0;

@Setup
public void setup() {
uuids = new UUID[size];
uuidStrings = new String[size];
for (int i = 0; i < this.uuidStrings.length; i++) {
final UUID uuid = UUID.randomUUID();

this.uuids[i] = uuid;
this.uuidStrings[i] = uuid.toString();
}
}

@Setup(Level.Iteration)
public void setupIteration() {
index++;
if (index >= size) {
index = 0;
}
}

@Benchmark
public UUID fromString() {
return UUID.fromString(uuidStrings[index]);
}

@Benchmark
public String toString() {
return uuids[index].toString();
}
}

0 comments on commit ebadfae

Please sign in to comment.