Created
March 7, 2013 18:43
-
-
Save anonymous/5110608 to your computer and use it in GitHub Desktop.
Microbenchmark for http://stackoverflow.com/questions/15165293/efficiency-of-guava-table-vs-multiple-hash-maps
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.google.common.collect.HashBasedTable; | |
import com.google.common.collect.Table; | |
import java.util.HashMap; | |
import java.util.Map; | |
import java.util.Set; | |
public class MicroBenchmark { | |
public static final int ITERATIONS = 100000; | |
public static final int SIZE = 10; | |
public static final StringBuffer stash1 = new StringBuffer(SIZE*22); | |
public static final StringBuffer stash2 = new StringBuffer(SIZE*22); | |
public static void main(String[] args) throws InterruptedException { | |
System.gc(); | |
Thread.sleep(1000); | |
long mapTime = 0; | |
for (int i = 0; i < ITERATIONS; i++) { | |
mapTime += maps(SIZE); | |
} | |
System.gc(); | |
Thread.sleep(1000); | |
long tableTime = 0; | |
for (int i = 0; i < ITERATIONS; i++) { | |
tableTime += table(SIZE); | |
} | |
System.out.println("Maps took (ms):" + mapTime); | |
System.out.println("Table took (ms):" + tableTime); | |
} | |
public static long maps(int size) { | |
long start = System.currentTimeMillis(); | |
DataSet data = buildData(size); | |
Map<String, String> fullNameById = buildMap1(data); | |
Map<String, String> nameById = buildMap2(data); | |
Map<String, String> nameByFullName = new HashMap<String, String>(); | |
Map<String, String> idByName = new HashMap<String, String>(); | |
Set<String> ids = fullNameById.keySet(); | |
for (String nextId : ids) { | |
String name = nameById.get(nextId); | |
String fullName = fullNameById.get(nextId); | |
nameByFullName.put(fullName, name); | |
idByName.put(name, nextId); | |
} | |
// Prevent compiler from throwing away code that isn't used. | |
stash1.append(nameByFullName.get(data.ids[0])); | |
stash1.append(idByName.get(data.names[0])); | |
long end = System.currentTimeMillis(); | |
return end - start; | |
} | |
public static long table(int size) { | |
long start = System.currentTimeMillis(); | |
Table<String, String, String> relations = HashBasedTable.create(); | |
DataSet data = buildData(size); | |
addRelationships1(relations, data); | |
addRelationships2(relations, data); | |
Map<String, String> idByName = relations.column("hasId"); | |
Map<String, String> nameByFullName = relations.column("hasName"); | |
// Prevent compiler from throwing away code that isn't used. | |
stash2.append(nameByFullName.get(data.ids[0])); | |
stash2.append(idByName.get(data.names[0])); | |
long end = System.currentTimeMillis(); | |
return end - start; | |
} | |
private static void addRelationships1(Table<String, String, String> rels, DataSet data) { | |
for (int i = 0; i < data.size; i++) { | |
rels.put(data.ids[i], "hasFullName", data.fullNames[i]); | |
} | |
} | |
public static Map<String, String> buildMap1(DataSet data) { | |
HashMap<String, String> result = new HashMap<String, String>(); | |
for (int i = 0; i < data.size; i++) { | |
result.put(data.ids[i], data.fullNames[i]); | |
} | |
return result; | |
} | |
public static Map<String, String> buildMap2(DataSet data) { | |
HashMap<String, String> result = new HashMap<String, String>(); | |
for (int i = 0; i < data.size; i++) { | |
result.put(data.ids2[i], data.names[i]); | |
} | |
return result; | |
} | |
public static void addRelationships2(Table<String, String, String> rels, DataSet data) { | |
for (int i = 0; i < data.size; i++) { | |
String name = data.names[i]; | |
String id = data.ids2[i]; | |
rels.put(rels.remove(id, "hasFullName"), "hasName", name); | |
rels.put(name, "hasId", id); | |
} | |
} | |
private static String get10digitoctal() { | |
// format as octal to avoid localization overhead, 10 digits zero padded to provide consistent data size | |
// important to generate new unique strings to avoid caching of hashcode value. | |
return String.format("%010o", (long) (Math.random() * Long.MAX_VALUE)); | |
} | |
public static DataSet buildData(int size) { | |
DataSet result = new DataSet(size); | |
for (int i = 0; i < size; i++) { | |
result.names[i] = get10digitoctal(); | |
} | |
for (int i = 0; i < size; i++) { | |
result.fullNames[i] = get10digitoctal(); | |
} | |
for (int i = 0; i < size; i++) { | |
result.ids[i] = get10digitoctal(); | |
} | |
// must be the same values, but new string objects with uncached hash codes, simulating data | |
// read from a different connection. | |
for (int i = 0; i < size; i++) { | |
result.ids2[i] = new String(result.ids[i]); | |
} | |
return result; | |
} | |
public static class DataSet { | |
public int size; | |
public String[] names; | |
public String[] fullNames; | |
public String[] ids; | |
public String[] ids2; | |
public DataSet(int size) { | |
this.size = size; | |
this.names = new String[size]; | |
this.fullNames = new String[size]; | |
this.ids = new String[size]; | |
this.ids2 = new String[size]; | |
} | |
} | |
} | |
/* | |
Case Maps (ms) Tables (ms) Tables vs Maps | |
100000 runs of size 10 2931 3035 104% | |
10000 runs of size 100 2989 3033 101% | |
1000 runs of size 1000 3129 3160 101% | |
100 runs of size 10000 4126 4429 107% | |
10 runs of size 100000 5081 5866 115% | |
1 run of size 1000000 5489 5160 94% | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment