Skip to content

Instantly share code, notes, and snippets.

@jcsahnwaldt
Created March 10, 2015 04:38
Show Gist options
  • Save jcsahnwaldt/09061501791257a3dff2 to your computer and use it in GitHub Desktop.
Save jcsahnwaldt/09061501791257a3dff2 to your computer and use it in GitHub Desktop.
Microbenchmark: procedural vs functional extraction of error lines. See https://twitter.com/jcsahnwaldt/status/574705132555923456
import java.util.*;
import java.util.stream.*;
import static java.util.stream.Collectors.*;
import java.io.*;
import java.nio.file.*;
public class ProcFunc {
public static <T> Iterator<T> limit(Iterator<? extends T> it, int max) {
return new Iterator<T>() {
private int remaining = max;
public boolean hasNext() {
return remaining > 0 && it.hasNext();
}
public T next() {
if (remaining <= 0) throw new NoSuchElementException();
--remaining;
return it.next();
}
};
}
public static <T> Iterable<T> limit(Iterable<? extends T> itbl, int max) {
return () -> limit(itbl.iterator(), max);
}
private static Exception usage(String[] args) {
return new IllegalArgumentException("expected args: [(p|f), file name, number of runs, size of runs]; found: "+Arrays.toString(args));
}
public static void main(String[] args) throws Exception {
if (args == null || args.length != 4) throw usage(args);
boolean proc;
if (args[0].equals("p")) proc = true;
else if (args[0].equals("f")) proc = false;
else throw usage(args);
String file = args[1];
int N, C;
try {
N = Integer.parseInt(args[2]);
C = Integer.parseInt(args[3]);
} catch (NumberFormatException e) {
throw usage(args);
}
/*
List<String> lines;
try (Stream<String> stream = Files.lines(Paths.get(file))) {
lines = stream.collect(toList());
}
*/
long total = System.nanoTime();
List<String[]> errors = null;
for (int n = 0; n < N; n++)
{
long nanos = System.nanoTime();
for (int c = 0; c < C; c++) {
if (proc) {
errors = proc(file, 40);
}
else {
errors = func(file, 40);
}
}
nanos = System.nanoTime() - nanos;
System.out.println("micros: " + nanos / 1000F / C);
}
total = System.nanoTime() - total;
for (String[] pair: errors) System.out.println(Arrays.toString(pair));
System.out.println("total: " + total / 1000F / C / N);
}
public static List<String[]> proc(String fileName, int count) throws IOException {
List<String[]> errors = new ArrayList<>();
Buffer<String> buf = new Buffer<>(2);
try (Stream<String> lines = Files.lines(Paths.get(fileName))) {
for(String line: (Iterable<String>)lines::iterator) {
buf.push(line);
if (line.startsWith("ERROR")) {
errors.add(new String[]{buf.peek(1), line});
if (--count <= 0) break;
}
}
}
return errors;
}
public static List<String[]> func(String fileName, int count) throws IOException {
Buffer<String> buf = new Buffer<>(2);
try (Stream<String> lines = Files.lines(Paths.get(fileName))) {
return lines
.peek(line -> buf.push(line))
.filter(line -> line.startsWith("ERROR"))
.limit(count)
.map(line -> new String[]{buf.peek(1), line} )
.collect(toList());
}
}
}
class Buffer<E> {
private final E[] a;
private int p = 0;
@SuppressWarnings("unchecked")
public Buffer(int size) {
a = (E[]) new Object[size];
}
public void push(E e) {
if (p == 0) p = a.length;
--p;
a[p] = e;
}
public E pop() {
E e = a[p];
a[p] = null;
++p;
if (p == a.length) p = 0;
return e;
}
public E peek(int o) {
if (o < 0 || o >= a.length) throw new IndexOutOfBoundsException("size: "+a.length+" offset: "+o);
return a[(p + o) % a.length]; // FIXME: p + o may overflow
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment