package rocks.inspectit.server.indexing; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Random; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.TimeUnit; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; import rocks.inspectit.server.indexing.impl.RootBranchFactory; import rocks.inspectit.server.indexing.impl.RootBranchFactory.RootBranch; import rocks.inspectit.server.processor.AbstractCmrDataProcessor; import rocks.inspectit.server.processor.impl.CacheIdGeneratorCmrProcessor; import rocks.inspectit.server.processor.impl.IndexerCmrProcessor; import rocks.inspectit.server.processor.impl.InvocationModifierCmrProcessor; import rocks.inspectit.server.util.CacheIdGenerator; import rocks.inspectit.shared.all.communication.DefaultData; import rocks.inspectit.shared.all.communication.data.ExceptionSensorData; import rocks.inspectit.shared.all.communication.data.HttpTimerData; import rocks.inspectit.shared.all.communication.data.InvocationSequenceData; import rocks.inspectit.shared.all.communication.data.SqlStatementData; import rocks.inspectit.shared.all.communication.data.TimerData; import rocks.inspectit.shared.cs.indexing.impl.IndexQuery; import rocks.inspectit.shared.cs.indexing.query.factory.impl.InvocationSequenceDataQueryFactory; import rocks.inspectit.shared.cs.indexing.query.factory.impl.TimerDataQueryFactory; import rocks.inspectit.shared.cs.indexing.query.provider.impl.IndexQueryProvider; import rocks.inspectit.shared.cs.indexing.restriction.IIndexQueryRestrictionProcessor; import rocks.inspectit.shared.cs.indexing.restriction.impl.CachingIndexQueryRestrictionProcessor; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MILLISECONDS) @Warmup(iterations = 10) @Measurement(iterations = 5) @Fork(2) @State(Scope.Thread) public class IndexingTreePerfTest { /** * Indexing tree under test. */ private RootBranch<DefaultData> indexingTree; /** * Number of invocations to be added to the indexing tree. */ @Param({ "1000", "10000" }) private int invocations; /** * Number of invocations to be added to the indexing tree. */ @Param({ "500", "1000" }) private int children; /** * Number of different agents to simulate. */ @Param({ "2" }) private int agents; /** * Number of different sensors to simulate. */ @Param({ "10" }) private int sensors; /** * Number of different methods to simulate. */ @Param({ "100" }) private int methods; /** * Spread of data in duration of 1 hour. */ @Param({ "3600000" }) private int timestampSpread; /** * Aggregated timer data query. */ private IndexQuery aggregatedTimerDataQuery; /** * Aggregated timer data query for specific time-frame. */ private IndexQuery aggregatedTimerDataQuery15MinsTimeframe; /** * Aggregated timer data query for single method id. */ private IndexQuery aggregatedTimerDataQueryMethod; /** * Invocation overview query. */ private IndexQuery invocationOverviewQuery; /** * ForkJoinPool */ private ForkJoinPool forkJoinPool; /** * Number of processors used by the forkJoinPool */ @Param({ "4", "8" }) private int numberOfProcessors; /** * Set up, prepare indexing tree. */ @Setup(Level.Trial) public void initIndexingTree() throws Exception { forkJoinPool = new ForkJoinPool(numberOfProcessors); RootBranchFactory rootBranchFactory = new RootBranchFactory(); indexingTree = rootBranchFactory.getObject(); CacheIdGeneratorCmrProcessor idProcessor = new CacheIdGeneratorCmrProcessor(); idProcessor.setCacheIdGenerator(new CacheIdGenerator()); IndexerCmrProcessor indexerProcessor = new IndexerCmrProcessor(); indexerProcessor.setIndexingTree(indexingTree); List<AbstractCmrDataProcessor> chained = new ArrayList<>(2); chained.add(idProcessor); chained.add(indexerProcessor); InvocationModifierCmrProcessor invocationProcessor = new InvocationModifierCmrProcessor(chained); for (int i = 0; i < invocations; i++) { InvocationSequenceData data = getInvocationSequenceDataInstance(children); Collection<DefaultData> toProcess = Collections.<DefaultData> singleton(data); idProcessor.process(toProcess, null); invocationProcessor.process(toProcess, null); indexingTree.put(data); } // prepare queries Random random = new Random(); long platformIdent = getRandomPlatformIdent(random); long methodIdent = getRandomMethodIdent(random); final IIndexQueryRestrictionProcessor restrictionProcessor = new CachingIndexQueryRestrictionProcessor(); IndexQueryProvider indexQueryProvider = new IndexQueryProvider() { @Override public IndexQuery createNewIndexQuery() { IndexQuery indexQuery = new IndexQuery(); indexQuery.setRestrictionProcessor(restrictionProcessor); return indexQuery; } }; // timer data TimerDataQueryFactory<IndexQuery> timerDataQueryFactory = new TimerDataQueryFactory<>(); timerDataQueryFactory.setIndexQueryProvider(indexQueryProvider); aggregatedTimerDataQuery = timerDataQueryFactory.getAggregatedTimerDataQuery(new TimerData(null, platformIdent, 0, 0), null, null); aggregatedTimerDataQueryMethod = timerDataQueryFactory.getAggregatedTimerDataQuery(new TimerData(null, platformIdent, 0, methodIdent), null, null); Date fromDate; Date toDate; long time15mins = 15000; Date date = new Date(getRandomTimestamp(random)); if (date.after(new Date(System.currentTimeMillis() - 15000))) { toDate = date; fromDate = new Date(date.getTime() - time15mins); } else { fromDate = date; toDate = new Date(date.getTime() + time15mins); } aggregatedTimerDataQuery15MinsTimeframe = timerDataQueryFactory.getAggregatedTimerDataQuery(new TimerData(null, platformIdent, 0, 0), fromDate, toDate); // invocation data InvocationSequenceDataQueryFactory<IndexQuery> invocationSequenceDataQueryFactory = new InvocationSequenceDataQueryFactory<>(); invocationSequenceDataQueryFactory.setIndexQueryProvider(indexQueryProvider); invocationOverviewQuery = invocationSequenceDataQueryFactory.getInvocationSequences(platformIdent, 0, null, null); } // Query fork&join benchmarks @Benchmark public List<DefaultData> queryTimerDataForkJoin() { return indexingTree.query(aggregatedTimerDataQuery, forkJoinPool); } @Benchmark public List<DefaultData> queryTimerData15MinsTimeframeForkJoin() { return indexingTree.query(aggregatedTimerDataQuery15MinsTimeframe, forkJoinPool); } @Benchmark public List<DefaultData> queryTimerDataMethodForkJoin() { return indexingTree.query(aggregatedTimerDataQueryMethod, forkJoinPool); } @Benchmark public List<DefaultData> queryInvocationOverviewForkJoin() { return indexingTree.query(invocationOverviewQuery, forkJoinPool); } // Query benchmarks without fork&join @Benchmark public List<DefaultData> queryTimerData() { return indexingTree.query(aggregatedTimerDataQuery); } @Benchmark public List<DefaultData> queryTimerData15MinsTimeframe() { return indexingTree.query(aggregatedTimerDataQuery15MinsTimeframe); } @Benchmark public List<DefaultData> queryTimerDataMethod() { return indexingTree.query(aggregatedTimerDataQueryMethod); } @Benchmark public List<DefaultData> queryInvocationOverview() { return indexingTree.query(invocationOverviewQuery); } // private helpers private InvocationSequenceData getInvocationSequenceDataInstance(int childCount) { Random random = new Random(); InvocationSequenceData invData = new InvocationSequenceData(new Timestamp(getRandomTimestamp(random)), getRandomPlatformIdent(random), getRandomSensorIdent(random), getRandomMethodIdent(random)); setRadnomDataObject(invData, random); if (childCount == 0) { return invData; } List<InvocationSequenceData> children = new ArrayList<>(); for (int i = 0; i < childCount;) { int childCountForChild = childCount / 10; if ((childCountForChild + i + 1) > childCount) { childCountForChild = childCount - i - 1; } InvocationSequenceData child = getInvocationSequenceDataInstance(childCountForChild); setRadnomDataObject(child, random); child.setParentSequence(invData); children.add(child); i += childCountForChild + 1; } invData.setChildCount(childCount); invData.setNestedSequences(children); return invData; } private long getRandomPlatformIdent(Random random) { return 1L + random.nextInt(agents); } private long getRandomSensorIdent(Random random) { return 1L + random.nextInt(sensors); } private long getRandomMethodIdent(Random random) { return 1L + random.nextInt(methods); } private long getRandomTimestamp(Random random) { return System.currentTimeMillis() - random.nextInt(timestampSpread); } private void setRadnomDataObject(InvocationSequenceData invocationSequenceData, Random random) { int objectSplit = random.nextInt(100); // http 5%, exceptions 5%, sqls 25%, timers 65% if (objectSplit < 5) { HttpTimerData httpTimerData = new HttpTimerData(new Timestamp(getRandomTimestamp(random)), getRandomPlatformIdent(random), getRandomSensorIdent(random), getRandomMethodIdent(random)); setTime(httpTimerData); invocationSequenceData.setTimerData(httpTimerData); } else if (objectSplit < 10) { ExceptionSensorData exData = new ExceptionSensorData(new Timestamp(getRandomTimestamp(random)), getRandomPlatformIdent(random), getRandomSensorIdent(random), getRandomMethodIdent(random)); invocationSequenceData.setExceptionSensorDataObjects(Collections.singletonList(exData)); } else if (objectSplit < 35) { SqlStatementData sqlData = new SqlStatementData(new Timestamp(getRandomTimestamp(random)), getRandomPlatformIdent(random), getRandomSensorIdent(random), getRandomMethodIdent(random)); setTime(sqlData); invocationSequenceData.setSqlStatementData(sqlData); } else { TimerData timerData = new TimerData(new Timestamp(getRandomTimestamp(random)), getRandomPlatformIdent(random), getRandomSensorIdent(random), getRandomMethodIdent(random)); setTime(timerData); invocationSequenceData.setTimerData(timerData); } } private void setTime(TimerData timerData) { timerData.setCount(1L); } }