Part 6 extra: the decision table measured on real data
This commit is contained in:
@@ -0,0 +1,101 @@
|
|||||||
|
package com.ankurm.jackson3.part6streaming;
|
||||||
|
|
||||||
|
import tools.jackson.core.JsonParser;
|
||||||
|
import tools.jackson.core.JsonToken;
|
||||||
|
import tools.jackson.core.json.JsonFactory;
|
||||||
|
import tools.jackson.core.type.TypeReference;
|
||||||
|
import tools.jackson.databind.JsonNode;
|
||||||
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BEYOND THE POST — the decision table, measured.
|
||||||
|
*
|
||||||
|
* The post ends with a table claiming data binding "loads full object", tree model
|
||||||
|
* "loads full tree", and streaming uses "constant" memory. This generates a real
|
||||||
|
* file and measures all three so the table has numbers behind it.
|
||||||
|
*
|
||||||
|
* These are indicative single-shot measurements on one JVM, not JMH benchmarks —
|
||||||
|
* the ordering is the point, not the absolute figures.
|
||||||
|
*/
|
||||||
|
public class G04ThreeApproachesMeasured {
|
||||||
|
|
||||||
|
public record LogEntry(long id, String level, String message) { }
|
||||||
|
|
||||||
|
private static final int ENTRIES = 200_000;
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
File file = generate();
|
||||||
|
System.out.println("input file : " + (file.length() / 1024 / 1024) + " MB, "
|
||||||
|
+ ENTRIES + " entries");
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
JsonMapper mapper = JsonMapper.builder().build();
|
||||||
|
|
||||||
|
measure("data binding (readValue)", () -> {
|
||||||
|
List<LogEntry> all = mapper.readValue(file, new TypeReference<List<LogEntry>>() { });
|
||||||
|
return all.stream().filter(e -> e.level().equals("ERROR")).count();
|
||||||
|
});
|
||||||
|
|
||||||
|
measure("tree model (readTree)", () -> {
|
||||||
|
JsonNode root = mapper.readTree(file);
|
||||||
|
long n = 0;
|
||||||
|
for (JsonNode node : root) if ("ERROR".equals(node.path("level").asString())) n++;
|
||||||
|
return n;
|
||||||
|
});
|
||||||
|
|
||||||
|
measure("streaming (JsonParser)", () -> {
|
||||||
|
long n = 0;
|
||||||
|
JsonFactory factory = new JsonFactory();
|
||||||
|
try (JsonParser p = factory.createParser(tools.jackson.core.ObjectReadContext.empty(), file)) {
|
||||||
|
p.nextToken();
|
||||||
|
while (p.nextToken() != JsonToken.END_ARRAY) {
|
||||||
|
String level = null;
|
||||||
|
while (p.nextToken() != JsonToken.END_OBJECT) {
|
||||||
|
String f = p.currentName();
|
||||||
|
p.nextToken();
|
||||||
|
if ("level".equals(f)) level = p.getString();
|
||||||
|
}
|
||||||
|
if ("ERROR".equals(level)) n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
});
|
||||||
|
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface Counter { long count() throws Exception; }
|
||||||
|
|
||||||
|
private static void measure(String label, Counter counter) throws Exception {
|
||||||
|
Runtime rt = Runtime.getRuntime();
|
||||||
|
System.gc();
|
||||||
|
Thread.sleep(120);
|
||||||
|
long heapBefore = rt.totalMemory() - rt.freeMemory();
|
||||||
|
long start = System.nanoTime();
|
||||||
|
long errors = counter.count();
|
||||||
|
long ms = (System.nanoTime() - start) / 1_000_000;
|
||||||
|
long heapAfter = rt.totalMemory() - rt.freeMemory();
|
||||||
|
System.out.printf("%-28s errors=%-6d %5d ms heap delta %5d MB%n",
|
||||||
|
label, errors, ms, (heapAfter - heapBefore) / 1024 / 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static File generate() throws Exception {
|
||||||
|
File f = File.createTempFile("logs", ".json");
|
||||||
|
f.deleteOnExit();
|
||||||
|
StringBuilder sb = new StringBuilder("[");
|
||||||
|
for (int i = 0; i < ENTRIES; i++) {
|
||||||
|
if (i > 0) sb.append(',');
|
||||||
|
sb.append("{\"id\":").append(i)
|
||||||
|
.append(",\"level\":\"").append(i % 50 == 0 ? "ERROR" : "INFO")
|
||||||
|
.append("\",\"message\":\"event number ").append(i)
|
||||||
|
.append(" with some padding to make the payload realistic\"}");
|
||||||
|
}
|
||||||
|
sb.append(']');
|
||||||
|
Files.writeString(f.toPath(), sb);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user