Reputation: 147
I've written my own math parser and for some reason it takes increasing amounts of time to parse when I tried to profile the parser.
For testing I used this input: Cmd.NUM_9,Cmd.NUM_0,Cmd.NUM_0,Cmd.DIV,Cmd.NUM_2,Cmd.ADD,Cmd.NUM_6,Cmd.MULT,Cmd.NUM_3
Single execution ~1.7ms
3000 repeats ~ 1,360ms
6000 repeats ~ 5,290ms
9000 repeats ~11,800ms
The profiler says 64% of the time was spent on this function: this is my function to allow implicit multiplications.
private void enableImplicitMultiplication(ArrayList<Cmd> input) {
int input_size = input.size();
if (input_size<2) return;
for (int i=0; i<input_size; i++) {
Cmd cmd = input.get(i);
if (i>0) {
Cmd last = input.get(i-1);
// [EXPR1, EXPR2] => [EXPR1, MULT, EXPR2]
boolean criteria1 = Cmd.exprnCmds.contains(cmd) && Cmd.exprnCmds.contains(last);
// [CBRAC, OBRAC] => [CBRAC, MULT, OBRAC]
// [NUM_X, OBRAC] => [NUM_X, MULT, OBRAC]
boolean criteria2 = cmd==Cmd.OBRAC && (last==Cmd.CBRAC || Cmd.constantCmds.contains(last));
// [CBRAC, NUM_X] => [CBRAC, MULT, NUM_X]
boolean criteria3 = last==Cmd.CBRAC && Cmd.constantCmds.contains(cmd);
if (criteria1 || criteria2 || criteria3) {
input.add(i++, Cmd.MULT);
}
}
}
}
What's going on here??
I executed the repeats like this:
public static void main(String[] args) {
Cmd[] iArray = {
Cmd.NUM_9,Cmd.NUM_0,Cmd.NUM_0,Cmd.DIV,Cmd.NUM_2,Cmd.ADD,Cmd.NUM_6,Cmd.MULT,Cmd.NUM_3
};
ArrayList<Cmd> inputArray = new ArrayList<Cmd>(Arrays.asList(iArray));
DirtyExpressionParser parser = null;
int repeat=9000;
double starttime = System.nanoTime();
for (int i=0; i<repeat; i++) {
parser = new DirtyExpressionParser(inputArray);
}
double endtime = System.nanoTime();
System.out.printf("Duration: %.2f ms%n",(endtime-starttime)/1000000);
System.out.println(parser.getResult());
}
Constructor looks like this:
public DirtyExpressionParser(ArrayList<Cmd> inputArray) {
enableImplicitMultiplication(inputArray); //executed once for each repeat
splitOnBrackets(inputArray); //resolves inputArray into Expr objects for each bracket-group
for (Expr expr:exprArray) {
mergeAndSolve(expr);
}
}
Upvotes: 0
Views: 184
Reputation: 200158
Your microbenchmark code is altogether wrong: microbenchmarking on the JVM is a craft in its own right and is best left to dedicated tools such as jmh or Google Caliper. You don't warm up the code, don't control for GC pauses, and so on.
One detail which does come out by analyzing your code is this:
ArrayList
for all repetitions of the function call;ArrayList
: the whole contents of the list after the inserted element must be copied.You should at least create a fresh ArrayList
for each invocation, but that will not make your whole methodology correct.
From our discussion in the comments I diagnose the following issue you may have with understanding your code:
In Java there is no such thing as a variable whose value is an object. The value of the variable is a reference to the object. Therefore when you say new DirtyExpressionParser(inputArray)
, the constructor does not receive its own private copy of the list, but rather a reference to the one and only ArrayList
you have instantiated in your main
method. The next constructor call gets this same list, but now modified by the earlier invocation. This is why your list is growing all the time.
Upvotes: 3