mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
8351593: [JMH] test PhoneCode.Bulk reports NPE exception
Reviewed-by: redestad, drwhite
This commit is contained in:
parent
79824c344e
commit
50ac24eb0f
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 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.stream.tasks;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class DataProviders {
|
||||
public static Stream<String> dictionary() throws IOException {
|
||||
BufferedReader r = new BufferedReader(new InputStreamReader(DataProviders.class.getResourceAsStream("cmudict-0.7b.txt")));
|
||||
// Strip out the copyright notice and special chars
|
||||
return r.lines().filter(w -> w.charAt(0) >= 'A' && w.charAt(0) <= 'Z').map(w -> w.substring(0, w.indexOf(" "))).onClose(() -> {
|
||||
try {
|
||||
r.close();
|
||||
} catch (IOException e) {
|
||||
// swallow
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,150 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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.stream.tasks.DictionaryWordValue;
|
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.Level;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.RecursiveTask;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Function;
|
||||
|
||||
|
||||
/**
|
||||
* Bulk scenario: searching max "wordValue" through the dictionary (array of strings).
|
||||
*/
|
||||
@BenchmarkMode(Mode.Throughput)
|
||||
@Warmup(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS)
|
||||
@Measurement(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS)
|
||||
@Fork(value = 3)
|
||||
@OutputTimeUnit(TimeUnit.SECONDS)
|
||||
@State(Scope.Benchmark)
|
||||
public class Bulk {
|
||||
|
||||
@Setup(Level.Trial)
|
||||
public void loadData() {
|
||||
// cause classload and problem initialization
|
||||
DictionaryProblem.class.getName();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int hm_seq() {
|
||||
int max = 0;
|
||||
for (String s : DictionaryProblem.get()) {
|
||||
int v = DictionaryProblem.wordValue(s);
|
||||
if (v > max) {
|
||||
max = v;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int hm_par() {
|
||||
return new Task(DictionaryProblem.get(), 0, DictionaryProblem.get().length).invoke();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int bulk_seq_inner() {
|
||||
return Arrays.stream(DictionaryProblem.get())
|
||||
.map(new Function<String, Integer>() {
|
||||
@Override
|
||||
public Integer apply(String s) {
|
||||
return DictionaryProblem.wordValue(s);
|
||||
}
|
||||
})
|
||||
.reduce(0, new BinaryOperator<Integer>() {
|
||||
@Override
|
||||
public Integer apply(Integer l, Integer r) {
|
||||
return l > r ? l : r;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int bulk_par_inner() {
|
||||
return Arrays.stream(DictionaryProblem.get()).parallel()
|
||||
.map(new Function<String, Integer>() {
|
||||
@Override
|
||||
public Integer apply(String s) {
|
||||
return DictionaryProblem.wordValue(s);
|
||||
}
|
||||
})
|
||||
.reduce(0, new BinaryOperator<Integer>() {
|
||||
@Override
|
||||
public Integer apply(Integer l, Integer r) {
|
||||
return l > r ? l : r;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public static class Task extends RecursiveTask<Integer> {
|
||||
private static final int FORK_LIMIT = 500;
|
||||
|
||||
private final String[] words;
|
||||
private final int start, end;
|
||||
|
||||
Task(String[] w, int start, int end) {
|
||||
this.words = w;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer compute() {
|
||||
int size = end - start;
|
||||
if (size > FORK_LIMIT) {
|
||||
int mid = start + size / 2;
|
||||
Task t1 = new Task(words, start, mid);
|
||||
Task t2 = new Task(words, mid, end);
|
||||
t1.fork();
|
||||
Integer v2 = t2.invoke();
|
||||
Integer v1 = t1.join();
|
||||
return Math.max(v1, v2);
|
||||
} else {
|
||||
int max = 0;
|
||||
for (int i = start; i < end; i++) {
|
||||
int v = DictionaryProblem.wordValue(words[i]);
|
||||
if (v > max) {
|
||||
max = v;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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.stream.tasks.DictionaryWordValue;
|
||||
|
||||
import org.openjdk.bench.java.util.stream.tasks.DataProviders;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class DictionaryProblem {
|
||||
|
||||
private static final int DICTIONARY_REPEAT_RATE = 40;
|
||||
|
||||
private static final String[] dict;
|
||||
|
||||
static {
|
||||
int size;
|
||||
int idx = 0;
|
||||
List<String> d = Collections.emptyList();
|
||||
try (Stream<String> s = DataProviders.dictionary()) {
|
||||
d = s.collect(Collectors.<String>toList());
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
size = d.size() * DICTIONARY_REPEAT_RATE;
|
||||
dict = new String[size];
|
||||
for (int i = 0; i < DICTIONARY_REPEAT_RATE; i++) {
|
||||
d.sort(new IdxComparator(i));
|
||||
for (String s : d) {
|
||||
// copy the whole string
|
||||
dict[idx++] = new String(s.toCharArray());
|
||||
}
|
||||
}
|
||||
assert (idx == dict.length);
|
||||
}
|
||||
|
||||
public static String[] get() {
|
||||
return dict;
|
||||
}
|
||||
|
||||
/**
|
||||
* A word value is the sum of alphabet value of each characters in a word.
|
||||
*
|
||||
* @param word The word
|
||||
* @return The word value
|
||||
*/
|
||||
public static int wordValue(String word) {
|
||||
char[] ar = word.toLowerCase().toCharArray();
|
||||
int value = 0;
|
||||
for (char c: ar) {
|
||||
int v = c - 'a' + 1;
|
||||
if (v < 1 || v > 26) {
|
||||
// skip non-alphabet
|
||||
continue;
|
||||
}
|
||||
value += (c - 'a' + 1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static class IdxComparator implements Comparator<String> {
|
||||
private final int index;
|
||||
|
||||
public IdxComparator(int i) {
|
||||
index = i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(String a, String b) {
|
||||
if (a.length() > index && b.length() > index) {
|
||||
return (a.charAt(index) - b.charAt(index));
|
||||
} else {
|
||||
return (a.length() - b.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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.stream.tasks.DictionaryWordValue;
|
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.Level;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Bulk scenario: searching max "wordValue" through the dictionary (array of strings).
|
||||
*/
|
||||
@BenchmarkMode(Mode.Throughput)
|
||||
@Warmup(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS)
|
||||
@Measurement(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS)
|
||||
@Fork(value = 3)
|
||||
@OutputTimeUnit(TimeUnit.SECONDS)
|
||||
@State(Scope.Benchmark)
|
||||
public class Lambda {
|
||||
|
||||
@Setup(Level.Trial)
|
||||
public void loadData() {
|
||||
// cause classload and problem initialization
|
||||
DictionaryProblem.class.getName();
|
||||
}
|
||||
|
||||
public static Integer maxInt(Integer l, Integer r) {
|
||||
return l > r ? l : r;
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int bulk_seq_lambda() {
|
||||
return Arrays.stream(DictionaryProblem.get())
|
||||
.map(s -> DictionaryProblem.wordValue(s))
|
||||
.reduce(0, (l, r) -> l > r ? l : r);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int bulk_seq_mref() {
|
||||
return Arrays.stream(DictionaryProblem.get())
|
||||
.map(DictionaryProblem::wordValue)
|
||||
.reduce(0, Lambda::maxInt);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int bulk_par_lambda() {
|
||||
return Arrays.stream(DictionaryProblem.get()).parallel()
|
||||
.map(s -> DictionaryProblem.wordValue(s))
|
||||
.reduce(0, (l, r) -> l > r ? l : r);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int bulk_par_mref() {
|
||||
return Arrays.stream(DictionaryProblem.get()).parallel()
|
||||
.map(DictionaryProblem::wordValue)
|
||||
.reduce(0, Lambda::maxInt);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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.stream.tasks.DictionaryWordValue;
|
||||
|
||||
/**
|
||||
* Bulk scenario: searching max "wordValue" through the dictionary (array of strings).
|
||||
*/
|
||||
public class Xtras {
|
||||
|
||||
// no workloads yet
|
||||
|
||||
}
|
||||
@ -1,229 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 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.stream.tasks.PhoneCode;
|
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.openjdk.bench.java.util.stream.tasks.PhoneCode.PhoneCodeProblem.wordsForNumber;
|
||||
|
||||
/**
|
||||
* This benchmark compare various strategies solving the phone code problem.
|
||||
* The result should offer some insights on strength/drawbacks of underlying
|
||||
* implementation.
|
||||
*/
|
||||
@BenchmarkMode(Mode.Throughput)
|
||||
@Warmup(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS)
|
||||
@Measurement(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS)
|
||||
@Fork(value = 3)
|
||||
@OutputTimeUnit(TimeUnit.MINUTES)
|
||||
@State(Scope.Benchmark)
|
||||
public class Bulk {
|
||||
// several method choke up with 6-digit problem
|
||||
private final static int SIZE = 5;
|
||||
private Stream<String> join(String head,
|
||||
String tail,
|
||||
Function<String, Stream<String>> encoder)
|
||||
{
|
||||
Stream<String> s = wordsForNumber(head).stream();
|
||||
|
||||
if (! tail.isEmpty()) {
|
||||
s = s.flatMap(h -> encoder.apply(tail).map(t -> h + " " + t));
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private Stream<String> encode_par1(String number) {
|
||||
return IntStream.range(1, number.length() + 1)
|
||||
.parallel()
|
||||
.boxed()
|
||||
.flatMap(i -> join(number.substring(0, i),
|
||||
number.substring(i),
|
||||
this::encode_par1));
|
||||
}
|
||||
|
||||
private Stream<String> encode_par2(String number) {
|
||||
return IntStream.range(1, number.length() + 1)
|
||||
.boxed()
|
||||
.parallel()
|
||||
.flatMap(i -> join(number.substring(0, i),
|
||||
number.substring(i),
|
||||
this::encode_par2));
|
||||
}
|
||||
|
||||
private Stream<String> encode_ser(String number) {
|
||||
return IntStream.range(1, number.length() + 1)
|
||||
.boxed()
|
||||
.flatMap(i -> join(number.substring(0, i),
|
||||
number.substring(i),
|
||||
this::encode_ser));
|
||||
}
|
||||
|
||||
private Stream<String> encode_loop_concat(String number) {
|
||||
if (number.isEmpty()) {
|
||||
return Stream.empty();
|
||||
}
|
||||
// full number
|
||||
Stream<String> s = wordsForNumber(number).stream();
|
||||
// split
|
||||
for (int i = 1; i < number.length(); i++) {
|
||||
s = Stream.concat(s, join(number.substring(0, i),
|
||||
number.substring(i),
|
||||
this::encode_loop_concat));
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private Collection<String> encode_loop_collect(String number) {
|
||||
if (number.isEmpty()) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
Collection<String> rv = new HashSet<>();
|
||||
|
||||
for (int i = 1; i <= number.length(); i++) {
|
||||
join(number.substring(0, i),
|
||||
number.substring(i),
|
||||
s -> encode_loop_collect(s).stream()).forEach(rv::add);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
private Collection<String> encode_inline(String number) {
|
||||
if (number.isEmpty()) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
Collection<String> rv = new HashSet<>();
|
||||
|
||||
for (int i = 1; i < number.length(); i++) {
|
||||
String front = number.substring(0, i);
|
||||
String rest = number.substring(i);
|
||||
wordsForNumber(front).stream()
|
||||
.flatMap(h -> encode_inline(rest).stream().map(t -> h + " " + t))
|
||||
.forEach(rv::add);
|
||||
}
|
||||
|
||||
rv.addAll(wordsForNumber(number));
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int bulk_par_range_concurrent() {
|
||||
// force collect
|
||||
return PhoneCodeProblem.get(SIZE)
|
||||
.flatMap(this::encode_par1)
|
||||
.collect(Collectors.toConcurrentMap(
|
||||
Function.identity(),
|
||||
Function.identity(),
|
||||
(l, r) -> l))
|
||||
.keySet()
|
||||
.size();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int bulk_par_boxed_range_concurrent() {
|
||||
// force collect
|
||||
return PhoneCodeProblem.get(SIZE)
|
||||
.flatMap(this::encode_par2)
|
||||
.collect(Collectors.toConcurrentMap(
|
||||
Function.identity(),
|
||||
Function.identity(),
|
||||
(l, r) -> l))
|
||||
.keySet()
|
||||
.size();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int bulk_par_range() {
|
||||
// force collect
|
||||
return PhoneCodeProblem.get(SIZE)
|
||||
.flatMap(this::encode_par1)
|
||||
.collect(Collectors.toSet())
|
||||
.size();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int bulk_par_boxed_range() {
|
||||
// force collect
|
||||
return PhoneCodeProblem.get(SIZE)
|
||||
.flatMap(this::encode_par2)
|
||||
.collect(Collectors.toSet())
|
||||
.size();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int bulk_ser_range() {
|
||||
// force collect
|
||||
return PhoneCodeProblem.get(SIZE)
|
||||
.flatMap(this::encode_ser)
|
||||
.collect(Collectors.toSet())
|
||||
.size();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int bulk_ser_loop_concat() {
|
||||
// force collect
|
||||
return PhoneCodeProblem.get(SIZE)
|
||||
.flatMap(this::encode_loop_concat)
|
||||
.collect(Collectors.toSet())
|
||||
.size();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int bulk_ser_loop_collect() {
|
||||
return PhoneCodeProblem.get(SIZE)
|
||||
.map(this::encode_loop_collect)
|
||||
.map(Collection::size)
|
||||
.reduce(0, Integer::sum);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public int bulk_ser_inline() {
|
||||
return PhoneCodeProblem.get(SIZE)
|
||||
.map(this::encode_inline)
|
||||
.map(Collection::size)
|
||||
.reduce(0, Integer::sum);
|
||||
}
|
||||
}
|
||||
@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 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.stream.tasks.PhoneCode;
|
||||
|
||||
import org.openjdk.bench.java.util.stream.tasks.DataProviders;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* The phone coder problem is trying to find full list of possible
|
||||
* mnemonic combination of numbers.
|
||||
*
|
||||
* The solution is based on Martin Odersky's devoxx 2010 scala talk,
|
||||
* where numbers are not allowed in the result, which is not really
|
||||
* correct, but we don't care.
|
||||
*/
|
||||
public class PhoneCodeProblem {
|
||||
// Map Character 'A'-'Z' to digits "2"-"9", key is charCode
|
||||
private static final Map<Integer, String> CHAR_CODE;
|
||||
// Map a string of digits to a collection of dictionary words
|
||||
private static final Map<String, List<String>> WORD_CODES;
|
||||
|
||||
static {
|
||||
HashMap<String, String> mnemonics = new HashMap<>(8);
|
||||
mnemonics.put("2", "ABC");
|
||||
mnemonics.put("3", "DEF");
|
||||
mnemonics.put("4", "GHI");
|
||||
mnemonics.put("5", "JKL");
|
||||
mnemonics.put("6", "MNO");
|
||||
mnemonics.put("7", "PQRS");
|
||||
mnemonics.put("8", "TUV");
|
||||
mnemonics.put("9", "WXYZ");
|
||||
|
||||
CHAR_CODE = new ConcurrentHashMap<>();
|
||||
mnemonics.entrySet().stream().forEach(e ->
|
||||
e.getValue().chars().forEach(c ->
|
||||
{ CHAR_CODE.put(c, e.getKey()); } ));
|
||||
|
||||
WORD_CODES = loadDictionary();
|
||||
// System.out.println("Dictionary loaded with " + WORD_CODES.size() + " number entries");
|
||||
}
|
||||
|
||||
// Convert a word to its number form
|
||||
private static String wordToNumber(String word) {
|
||||
return word.chars().mapToObj(CHAR_CODE::get)
|
||||
.reduce("", String::concat);
|
||||
}
|
||||
|
||||
// Prepare number -> word lookup table
|
||||
private static Map<String, List<String>> loadDictionary() {
|
||||
try (Stream<String> s = DataProviders.dictionary()) {
|
||||
return s.filter(w -> w.length() > 1)
|
||||
.filter(w -> w.matches("[a-zA-Z]*"))
|
||||
.map(String::toUpperCase)
|
||||
.collect(Collectors.groupingBy(PhoneCodeProblem::wordToNumber));
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace(System.err);
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
|
||||
public static Collection<String> wordsForNumber(String number) {
|
||||
Collection<String> rv = WORD_CODES.get(number);
|
||||
return (null == rv) ? Collections.emptySet() : rv;
|
||||
}
|
||||
|
||||
public static Stream<String> get(int length) {
|
||||
String digits[] = { "2", "3", "4", "5", "6", "7", "8", "9" };
|
||||
|
||||
Stream<String> s = Arrays.stream(digits);
|
||||
for (int i = 1; i < length; i++) {
|
||||
s = s.flatMap(d1 -> Arrays.stream(digits).map(d2 -> d1 + d2));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user