diff --git a/pom.xml b/pom.xml index bb334f750..a05b1dcde 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.xceptance xlt - 8.4.0 + 8.4.1 jar XLT @@ -322,7 +322,7 @@ org.jfree jfreechart - 1.5.4 + 1.5.5 diff --git a/src/main/java/com/xceptance/xlt/report/DataParserThread.java b/src/main/java/com/xceptance/xlt/report/DataParserThread.java index babbdeb6f..5ff89f1a2 100644 --- a/src/main/java/com/xceptance/xlt/report/DataParserThread.java +++ b/src/main/java/com/xceptance/xlt/report/DataParserThread.java @@ -80,21 +80,25 @@ class DataParserThread implements Runnable */ private final ReportGeneratorConfiguration config; + /** + * The request processing rules for this thread. Each parser thread gets its own copy of the rule set. This way, + * there is no shared state between threads, hence we can more efficiently cache and process stuff. + */ + private final List requestProcessingRules; + /** * Constructor. * + * @param dispatcher + * the dispatcher that coordinates result processing * @param dataRecordFactory * the data record factory * @param fromTime * the start time * @param toTime * the end time - * @param requestProcessingRules - * the request processing rules - * @param dispatcher - * the dispatcher that coordinates result processing - * @param removeIndexesFromRequestNames - * whether to automatically remove any indexes from request names + * @param config + * the report generator settings */ public DataParserThread(final Dispatcher dispatcher, final DataRecordFactory dataRecordFactory, final long fromTime, final long toTime, final ReportGeneratorConfiguration config) @@ -104,6 +108,8 @@ public DataParserThread(final Dispatcher dispatcher, final DataRecordFactory dat this.toTime = toTime; this.dispatcher = dispatcher; this.config = config; + + requestProcessingRules = config.getRequestProcessingRules(); } /** @@ -112,9 +118,6 @@ public DataParserThread(final Dispatcher dispatcher, final DataRecordFactory dat @Override public void run() { - // each parser gets its own rules. They are all identical, but don't share state, hence we can more - // efficiently cache and process - final List requestProcessingRules = config.getRequestProcessingRules(); final boolean removeIndexes = config.getRemoveIndexesFromRequestNames(); final double SAMPLELIMIT = 1 / ((double) config.dataSampleFactor); @@ -218,7 +221,8 @@ public void run() } catch (final Exception ex) { - final String msg = String.format("Failed to parse data record at line %,d in file '%s': %s\nLine is: ", lineNumber, file, ex, lines.get(i).toString()); + final String msg = String.format("Failed to parse data record at line %,d in file '%s': %s\nLine is: ", lineNumber, + file, ex, lines.get(i).toString()); LOG.error(msg, ex); continue; @@ -295,16 +299,14 @@ else if (adjustTimerName && (data instanceof RequestData || data instanceof Page * discarding requests. * * @param requestData - * the request data record + * the request data record * @param requestProcessingRules - * the rules to apply + * the rules to apply * @param removeIndexesFromRequestNames - * in case we want to clean the name too - * + * in case we want to clean the name too * @return the processed request data record, or null if the data record is to be discarded */ - private RequestData postprocess(final RequestData requestData, - final List requestProcessingRules, + private RequestData postprocess(final RequestData requestData, final List requestProcessingRules, final boolean removeIndexesFromRequestNames) { // fix up the name first (Product.1.2 -> Product) if so configured @@ -356,12 +358,11 @@ else if (state == ReturnState.STOP) } } - // ok, we processed all rules for this dataset, get us the final hashcode for the name, because we need that later + // ok, we processed all rules for this dataset, get us the final hashcode for the name, because we need that + // later // here the cache is likely still hot, so this is less expensive requestData.getName().hashCode(); return requestData; } - - } diff --git a/src/main/java/com/xceptance/xlt/report/ReportGeneratorConfiguration.java b/src/main/java/com/xceptance/xlt/report/ReportGeneratorConfiguration.java index 9201f5994..6053ed03d 100644 --- a/src/main/java/com/xceptance/xlt/report/ReportGeneratorConfiguration.java +++ b/src/main/java/com/xceptance/xlt/report/ReportGeneratorConfiguration.java @@ -39,7 +39,6 @@ import com.xceptance.xlt.api.report.ReportProvider; import com.xceptance.xlt.api.report.ReportProviderConfiguration; import com.xceptance.xlt.api.util.XltException; -import com.xceptance.xlt.api.util.XltLogger; import com.xceptance.xlt.api.util.XltProperties; import com.xceptance.xlt.common.XltConstants; import com.xceptance.xlt.common.XltPropertyNames; @@ -79,14 +78,14 @@ public static class ChartCappingInfo */ public enum ChartCappingMethod { - /** No capping (default). */ - NONE, + /** No capping (default). */ + NONE, - /** Cap at an absolute value. */ - ABSOLUTE, + /** Cap at an absolute value. */ + ABSOLUTE, - /** Cap at the n-fold of the average value. */ - NFOLD_OF_AVERAGE + /** Cap at the n-fold of the average value. */ + NFOLD_OF_AVERAGE }; /** @@ -94,11 +93,11 @@ public enum ChartCappingMethod */ public enum ChartCappingMode { - /** Cap the chart at the capping value only if necessary. */ - SMART, + /** Cap the chart at the capping value only if necessary. */ + SMART, - /** Always cap the chart at the capping value even if the maximum values are below the capping value. */ - ALWAYS + /** Always cap the chart at the capping value even if the maximum values are below the capping value. */ + ALWAYS }; /** @@ -163,9 +162,13 @@ public enum ChartCappingMode // Special settings for profiling and debugging private static final String PROP_PARSER_THREAD_COUNT = PROP_PREFIX + "parser.threads"; + private static final String PROP_READER_THREAD_COUNT = PROP_PREFIX + "reader.threads"; + private static final String PROP_THREAD_QUEUE_SIZE = PROP_PREFIX + "queue.bucketsize"; + private static final String PROP_THREAD_QUEUE_LENGTH = PROP_PREFIX + "queue.length"; + private static final String PROP_DATA_SAMPLE_FACTOR = PROP_PREFIX + "data.sampleFactor"; private static final String PROP_TRANSFORMATIONS_PREFIX = PROP_PREFIX + "transformations."; @@ -243,8 +246,11 @@ public enum ChartCappingMode private boolean noAgentCharts; public final int readerThreadCount; + public final int parserThreadCount; + public final int threadQueueBucketSize; + public final int threadQueueLength; public final int dataSampleFactor; @@ -276,11 +282,11 @@ public enum ChartCappingMode private final int transactionErrorOverviewChartLimit; private final int errorDetailsChartLimit; - + private final int directoryLimitPerError; - + private final double directoryReplacementChance; - + private final int stackTracesLimit; private final Map apdexThresholdsByActionNamePattern = new HashMap<>(); @@ -408,9 +414,9 @@ public ReportGeneratorConfiguration(Properties xltProperties, final File overrid directoryLimitPerError = getIntProperty(XltPropertyNames.ReportGenerator.Errors.DIRECTORY_LIMIT_PER_ERROR, 10); directoryReplacementChance = getDoubleProperty(XltPropertyNames.ReportGenerator.Errors.DIRECTORY_REPLACEMENT_CHANCE, 0.1); - + stackTracesLimit = getIntProperty(XltPropertyNames.ReportGenerator.Errors.STACKTRACES_LIMIT, 500); - + // event settings groupEventsByTestCase = getBooleanProperty(PROP_PREFIX + "events.groupByTestCase", true); eventLimit = getIntProperty(PROP_PREFIX + "events.eventLimit", 100); @@ -483,7 +489,7 @@ private void checkForLeadingZeros(final String s) } sb.append("\n"); - throw new RuntimeException(sb.toString()); + throw new XltException(sb.toString()); } } @@ -791,7 +797,7 @@ public int getErrorDetailsChartLimit() { return errorDetailsChartLimit; } - + /** * The maximum number of directory hints remembered for a certain error (stack trace). * @@ -801,9 +807,10 @@ public int getDirectoryLimitPerError() { return directoryLimitPerError; } - + /** - * The chance to replace directory hints remembered for a certain error (stack trace) when the maximum number is reached. + * The chance to replace directory hints remembered for a certain error (stack trace) when the maximum number is + * reached. * * @return the chance to replace listed directory hints */ @@ -811,7 +818,7 @@ public double getDirectoryReplacementChance() { return directoryReplacementChance; } - + /** * The maximum number of errors that will be saved complete with their stack trace. * @@ -1001,7 +1008,6 @@ public int getEventLimitPerTestCase() return eventLimit; } - /** * Indicates whether or not to group events by test case. * @@ -1012,7 +1018,6 @@ public int getEventMessageLimitPerEvent() return eventMessageLimit; } - /** * Returns whether to automatically remove any indexes from the request name (i.e. "HomePage.1.27" -> "HomePage"). * @@ -1491,15 +1496,15 @@ public List getRequestProcessingRules() // ensure that either newName or dropOnMatch is set if (StringUtils.isNotBlank(newName) == dropOnMatch) { - throw new RuntimeException(String.format("Either specify property '%s' or set property '%s' to true", - basePropertyName + ".newName", basePropertyName + ".dropOnMatch")); + throw new XltException(String.format("Either specify property '%s' or set property '%s' to true", + basePropertyName + ".newName", basePropertyName + ".dropOnMatch")); } // ensure that dropOnMatch and stopOnMatch are not contradicting if (dropOnMatch && !stopOnMatch) { - throw new RuntimeException(String.format("If property '%s' is true, property '%s' cannot be false", - basePropertyName + ".dropOnMatch", basePropertyName + ".stopOnMatch")); + throw new XltException(String.format("If property '%s' is true, property '%s' cannot be false", + basePropertyName + ".dropOnMatch", basePropertyName + ".stopOnMatch")); } // create and validate the rules @@ -1518,7 +1523,6 @@ public List getRequestProcessingRules() { // Log it and continue with next rule. final String errMsg = "Request processing rule '" + basePropertyName + "' is invalid. " + imre.getMessage(); - XltLogger.reportLogger.error(errMsg, imre); System.err.println(errMsg); // remember that we encountered an invalid merge rule invalidRulePresent = true; @@ -1527,7 +1531,7 @@ public List getRequestProcessingRules() if (invalidRulePresent) { - throw new RuntimeException("Please check your configuration. At least one request processing rule is invalid and needs to be fixed."); + throw new XltException("Please check your configuration. At least one request processing rule is invalid and needs to be fixed."); } return requestProcessingRules;