/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.trace;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import net.ranides.assira.trace.TraceUtils;
import net.ranides.benchmark.app.BenchmarkName;
import net.ranides.benchmark.app.BenchmarkRunner;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.runner.RunnerException;

/**
 * Benchmark for different methods of obtaining list of caller-classess.
 * 
 * SecurityManager creates list ~15 times faster than stacktrace.
 * SecurityManager gets caller ~2 times faster than stacktrace.
 * Best if you need all classes.
 * It's portable, but it won't work if you disable SecurityManager in JVM
 * 
 * 
 * SunReflection creates list ~3 times faster that stacktrace.
 * SunReflection gets caller ~10 times faster than stacktrace.
 * Best if you need first class.
 * It's nonportable, but it will work even if you disable SecurityManager.
 */
public class StackInspectorBenchmark {
    
    @Benchmark
    @BenchmarkName("frame[1]: native")
    public int frameNative() {
        return TraceUtils.getFrames().get(1).getLineNumber();
    }
    
    
    @Benchmark
    @BenchmarkName("frame[1]: default")
    public int frameDefault() {
        return getFramesArray().get(1).getLineNumber();
    }
    
    @Benchmark
    @BenchmarkName("frames: native")
    public int frameListNative() {
        int ret = 0;
        for(StackTraceElement e : TraceUtils.getFrames()) {
            ret += e.getLineNumber();
        }
        return ret;
    }
    
    @Benchmark
    @BenchmarkName("frames: default")
    public int frameListDefault() {
        int ret = 0;
        for(StackTraceElement e : getFramesArray()) {
            ret += e.getLineNumber();
        }
        return ret;
    }
    
    @Benchmark
    @BenchmarkName("names: SecurityManager")
    public int listSecurityManager() {
        return TraceUtils.test_getNames(TraceUtils.RESOLVER_SM).size();
    }
    
    @Benchmark
    @BenchmarkName("names: thread")
    public int listThread() {
        return TraceUtils.test_getNames(TraceUtils.RESOLVER_TS).size();
    }
    
    @Benchmark
    @BenchmarkName("names: sun.reflect")
    public int listSunReflect() {
        return TraceUtils.test_getNames(TraceUtils.RESOLVER_SR).size();
    }
    
    @Benchmark
    @BenchmarkName("names: exception")
    public int listException() {
        return TraceUtils.test_getNames(TraceUtils.RESOLVER_ES).size();
    }
    
    @Benchmark
    @BenchmarkName("callee: SecurityManager")
    public int calleeSecurityManager() {
        return TraceUtils.test_getCalleeName(TraceUtils.RESOLVER_SM).length();
    }
    
    @Benchmark
    @BenchmarkName("callee: thread")
    public int calleeThread() {
        return TraceUtils.test_getCalleeName(TraceUtils.RESOLVER_TS).length();
    }
    
    @Benchmark
    @BenchmarkName("callee: sun.reflect")
    public int calleeSunReflect() {
        return TraceUtils.test_getCalleeName(TraceUtils.RESOLVER_SR).length();
    }
    
    @Benchmark
    @BenchmarkName("callee: exception")
    public int calleeException() {
        return TraceUtils.test_getCalleeName(TraceUtils.RESOLVER_ES).length();
    }
    
    @Benchmark
    @BenchmarkName("caller: SecurityManager")
    public int callerSecurityManager() {
        return TraceUtils.test_getCallerName(TraceUtils.RESOLVER_SM).length();
    }
    
    @Benchmark
    @BenchmarkName("caller: thread")
    public int callerThread() {
        return TraceUtils.test_getCallerName(TraceUtils.RESOLVER_TS).length();
    }
    
    @Benchmark
    @BenchmarkName("caller: sun.reflect")
    public int callerSunReflect() {
        return TraceUtils.test_getCallerName(TraceUtils.RESOLVER_SR).length();
    }
    
    @Benchmark
    @BenchmarkName("caller: exception")
    public int callerException() {
        return TraceUtils.test_getCallerName(TraceUtils.RESOLVER_ES).length();
    }
        
    private static List<StackTraceElement> getFramesArray() {
        // we know that's incorrect, but we want to test performance, not semantic correctness
        // it will have few (2-3) items more than should be
        return Arrays.asList(new Exception().getStackTrace());
    }
    
    public static void main(String[] args) throws RunnerException, IOException {
        BenchmarkRunner.run(StackInspectorBenchmark.class);
    }
    
}
