
com.xceptance.xlt.report.providers.AgentDataProcessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xlt Show documentation
Show all versions of xlt Show documentation
XLT (Xceptance LoadTest) is an extensive load and performance test tool developed and maintained by Xceptance.
/*
* Copyright (c) 2005-2023 Xceptance Software Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.xceptance.xlt.report.providers;
import java.io.File;
import org.jfree.chart.JFreeChart;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import com.xceptance.xlt.agent.JvmResourceUsageData;
import com.xceptance.xlt.api.engine.Data;
import com.xceptance.xlt.api.report.AbstractReportProvider;
import com.xceptance.xlt.report.ReportGeneratorConfiguration;
import com.xceptance.xlt.report.util.ArithmeticMean;
import com.xceptance.xlt.report.util.DoubleMinMaxValueSet;
import com.xceptance.xlt.report.util.DoubleSummaryStatistics;
import com.xceptance.xlt.report.util.JFreeChartUtils;
import com.xceptance.xlt.report.util.MinMaxTimeSeriesCollection;
import com.xceptance.xlt.report.util.IntMinMaxValueSet;
import com.xceptance.xlt.report.util.ReportUtils;
import com.xceptance.xlt.report.util.TaskManager;
/**
* The {@link AgentDataProcessor} is responsible to calculate statistic information for exactly one agent.
*/
public class AgentDataProcessor extends AbstractDataProcessor
{
private final IntMinMaxValueSet blockedThreadsValueSet;
private final DoubleMinMaxValueSet cpuUsageValueSet;
private long fullGcCount;
private final ArithmeticMean fullGcCpuUsageMean = new ArithmeticMean();
private long fullGcTime;
private final DoubleMinMaxValueSet gcCpuUsageValueSet;
private long minorGcCount;
private final ArithmeticMean minorGcCpuUsageMean = new ArithmeticMean();
private long minorGcTime;
private final IntMinMaxValueSet runnableThreadsValueSet;
private final IntMinMaxValueSet totalHeapValueSet;
private final IntMinMaxValueSet totalThreadsValueSet;
private final IntMinMaxValueSet usedHeapValueSet;
// private final MinMaxValueSet usedMemValueSet;
private final IntMinMaxValueSet waitingThreadsValueSet;
private final IntMinMaxValueSet minorGcTimeValueSet;
private final IntMinMaxValueSet fullGcTimeValueSet;
private final DoubleMinMaxValueSet totalCpuUsageValueSet;
private int transactions;
private int transactionErrors;
/**
* Creates a new {@link AbstractDataProcessor} instance.
*
* @param name
* the agent name
* @param provider
* the report provider owning this data processor
*/
public AgentDataProcessor(final String name, final AbstractReportProvider provider)
{
super(name, provider);
setChartDir(new File(getChartDir(), "agents"));
setCsvDir(new File(getCsvDir(), "agents"));
final int minMaxValueSetSize = getChartWidth();
cpuUsageValueSet = new DoubleMinMaxValueSet(minMaxValueSetSize);
totalCpuUsageValueSet = new DoubleMinMaxValueSet(minMaxValueSetSize);
gcCpuUsageValueSet = new DoubleMinMaxValueSet(minMaxValueSetSize);
usedHeapValueSet = new IntMinMaxValueSet(minMaxValueSetSize);
// usedMemValueSet = new MinMaxValueSet(minMaxValueSetSize);
totalHeapValueSet = new IntMinMaxValueSet(minMaxValueSetSize);
runnableThreadsValueSet = new IntMinMaxValueSet(minMaxValueSetSize);
blockedThreadsValueSet = new IntMinMaxValueSet(minMaxValueSetSize);
waitingThreadsValueSet = new IntMinMaxValueSet(minMaxValueSetSize);
totalThreadsValueSet = new IntMinMaxValueSet(minMaxValueSetSize);
minorGcTimeValueSet = new IntMinMaxValueSet(minMaxValueSetSize);
fullGcTimeValueSet = new IntMinMaxValueSet(minMaxValueSetSize);
}
/**
* Generates an agent report for the agent for which this data processor is responsible.
*
* @return the agent report
*/
public AgentReport createAgentReport()
{
final String name = getName();
// create the charts
if (((ReportGeneratorConfiguration) getConfiguration()).agentChartsEnabled())
{
final File agentChartDir = new File(getChartDir(), name);
agentChartDir.mkdirs();
final TaskManager taskManager = TaskManager.getInstance();
taskManager.addTask(() -> createMemoryUsageChart(name, agentChartDir));
taskManager.addTask(() -> createCpuUsageChart(name, agentChartDir));
taskManager.addTask(() -> createThreadsChart(name, agentChartDir));
}
// get statistics from value sets
final DoubleSummaryStatistics cpuUsageStats = ReportUtils.toSummaryStatistics(cpuUsageValueSet);
final DoubleSummaryStatistics totalCpuUsageStats = ReportUtils.toSummaryStatistics(totalCpuUsageValueSet);
// create the agent report
final AgentReport agentReport = new AgentReport();
agentReport.name = name;
agentReport.minorGcCount = minorGcCount;
agentReport.minorGcTime = minorGcTime;
agentReport.minorGcCpuUsage = ReportUtils.convertToBigDecimal(minorGcCpuUsageMean.getMean());
agentReport.fullGcCount = fullGcCount;
agentReport.fullGcTime = fullGcTime;
agentReport.fullGcCpuUsage = ReportUtils.convertToBigDecimal(fullGcCpuUsageMean.getMean());
agentReport.cpuUsage = createStatisticsReport(cpuUsageStats);
agentReport.totalCpuUsage = createStatisticsReport(totalCpuUsageStats);
agentReport.transactions = transactions;
agentReport.transactionErrors = transactionErrors;
return agentReport;
}
private DoubleStatisticsReport createStatisticsReport(final DoubleSummaryStatistics statistics)
{
final DoubleStatisticsReport statisticsReport = new DoubleStatisticsReport();
statisticsReport.mean = ReportUtils.convertToBigDecimal(statistics.getMean());
statisticsReport.min = ReportUtils.convertToBigDecimal(statistics.getMinimum());
statisticsReport.max = ReportUtils.convertToBigDecimal(statistics.getMaximum());
statisticsReport.deviation = ReportUtils.convertToBigDecimal(statistics.getStandardDeviation());
return statisticsReport;
}
/**
* {@inheritDoc}
*/
@Override
public void processDataRecord(final Data stat)
{
final JvmResourceUsageData usageStats = (JvmResourceUsageData) stat;
final long time = usageStats.getTime();
// memory
totalHeapValueSet.addOrUpdateValue(time, (int) (usageStats.getTotalHeapSize() / 1024 / 1024));
usedHeapValueSet.addOrUpdateValue(time, (int) (usageStats.getUsedHeapSize() / 1024 / 1024));
// usedMemValueSet.addOrUpdateValue(time, (int) (usageStats.getCommittedMemorySize() / 1024 / 1024));
// CPU
final double cpuUsage = usageStats.getCpuUsage();
cpuUsageValueSet.addOrUpdateValue(time, cpuUsage);
final double totalCpuUsage = usageStats.getTotalCpuUsage();
totalCpuUsageValueSet.addOrUpdateValue(time, totalCpuUsage);
// threads
final int runnable = usageStats.getRunnableThreadCount();
final int blocked = usageStats.getBlockedThreadCount();
final int waiting = usageStats.getWaitingThreadCount();
final int total = runnable + blocked + waiting;
totalThreadsValueSet.addOrUpdateValue(time, total);
waitingThreadsValueSet.addOrUpdateValue(time, waiting);
blockedThreadsValueSet.addOrUpdateValue(time, blocked);
runnableThreadsValueSet.addOrUpdateValue(time, runnable);
// GC
final double minorGcCpuUsage = usageStats.getMinorGcCpuUsage();
final double fullGcCpuUsage = usageStats.getFullGcCpuUsage();
gcCpuUsageValueSet.addOrUpdateValue(time, (minorGcCpuUsage + fullGcCpuUsage));
minorGcCpuUsageMean.addValue(minorGcCpuUsage);
fullGcCpuUsageMean.addValue(fullGcCpuUsage);
minorGcTimeValueSet.addOrUpdateValue(time, (int) Math.round(usageStats.getMinorGcTimeDiff() /
Math.max(1.0, usageStats.getMinorGcCountDiff())));
fullGcTimeValueSet.addOrUpdateValue(time, (int) Math.round(usageStats.getFullGcTimeDiff() /
Math.max(1.0, usageStats.getFullGcCountDiff())));
minorGcCount = Math.max(minorGcCount, usageStats.getMinorGcCount());
minorGcTime = Math.max(minorGcTime, usageStats.getMinorGcTime());
fullGcCount = Math.max(fullGcCount, usageStats.getFullGcCount());
fullGcTime = Math.max(fullGcTime, usageStats.getFullGcTime());
}
/**
* Increments the transaction counter (and maybe the transaction error counter) of the agent this data processor is
* responsible for.
*
* @param failed
* whether the transaction to be added has failed
*/
void incrementTransactionCounters(final boolean failed)
{
transactions++;
if (failed)
{
transactionErrors++;
}
}
/**
* Creates a CPU usage chart with the given title and stores it to the passed directory.
*
* @param agentName
* the agent name
* @param outputDir
* the target directory
*/
protected void createCpuUsageChart(final String agentName, final File outputDir)
{
// System.out.println("Creating CPU usage chart for agent '" + agentName + "'... ");
// final long start = TimerUtils.getTime();
final TimeSeriesCollection cpuTimeSeriesCollection = new TimeSeriesCollection();
final TimeSeries cpuTimeSeries = JFreeChartUtils.toMinMaxTimeSeries(cpuUsageValueSet, "Agent CPU Usage");
final TimeSeries avgCpuTimeSeries = JFreeChartUtils.createMovingAverageTimeSeries(cpuTimeSeries, getMovingAveragePercentage());
final TimeSeries gcCpuTimeSeries = JFreeChartUtils.toMinMaxTimeSeries(gcCpuUsageValueSet, "Agent GC CPU Usage");
final TimeSeries totalCpuUsageTimeSeries = JFreeChartUtils.toMinMaxTimeSeries(totalCpuUsageValueSet, "Total CPU Usage");
cpuTimeSeriesCollection.addSeries(avgCpuTimeSeries);
cpuTimeSeriesCollection.addSeries(cpuTimeSeries);
cpuTimeSeriesCollection.addSeries(gcCpuTimeSeries);
cpuTimeSeriesCollection.addSeries(totalCpuUsageTimeSeries);
final JFreeChart chart = JFreeChartUtils.createLineChart(agentName + " -- CPU Usage", "CPU Usage [%]", cpuTimeSeriesCollection,
getStartTime(), getEndTime());
JFreeChartUtils.saveChart(chart, "CpuUsage", outputDir, getChartWidth(), getChartHeight());
// System.out.printf("OK (%,d ms)\n", TimerUtils.getTime() - start);
}
/**
* Creates a memory chart from the given timer list and stores it to the passed directory.
*
* @param name
* the chart title
* @param outputDir
* the target directory
*/
protected void createMemoryUsageChart(final String name, final File outputDir)
{
// System.out.println("Creating memory usage chart for agent '" + name + "'... ");
// final long start = TimerUtils.getTime();
final MinMaxTimeSeriesCollection memoryCollection = new MinMaxTimeSeriesCollection();
final TimeSeries usedHeapSeries = JFreeChartUtils.toMinMaxTimeSeries(usedHeapValueSet, "Used Heap");
final TimeSeries totalHeapSeries = JFreeChartUtils.toMinMaxTimeSeries(totalHeapValueSet, "Total Heap");
// final TimeSeries usedMemSeries = JFreeChartUtils.toMinMaxTimeSeries(usedMemValueSet, "Used Physical Memory");
final TimeSeries usedHeapAvgSeries = JFreeChartUtils.createMovingAverageTimeSeries(usedHeapSeries, getMovingAveragePercentage());
memoryCollection.addSeries(usedHeapAvgSeries);
memoryCollection.addSeries(usedHeapSeries);
memoryCollection.addSeries(totalHeapSeries);
// memoryCollection.addSeries(usedMemSeries);
final TimeSeriesCollection fullGcCollection = new TimeSeriesCollection();
fullGcCollection.addSeries(JFreeChartUtils.toMinMaxTimeSeries(fullGcTimeValueSet, "Full GC time"));
final TimeSeriesCollection minorGcCollection = new TimeSeriesCollection();
minorGcCollection.addSeries(JFreeChartUtils.toMinMaxTimeSeries(minorGcTimeValueSet, "Minor GC time"));
final JFreeChart chart = JFreeChartUtils.createCombinedPlotChart(name + " -- Memory Usage and Garbage Collection Time",
getStartTime(), getEndTime());
JFreeChartUtils.addLinePlotToCombinedPlotChart(chart, "Memory Usage [MB]", memoryCollection);
JFreeChartUtils.addLinePlotToCombinedPlotChart(chart, "Full GC Time [ms]", fullGcCollection);
JFreeChartUtils.addLinePlotToCombinedPlotChart(chart, "Minor GC Time [ms]", minorGcCollection);
JFreeChartUtils.saveChart(chart, "MemoryUsage", outputDir, getChartWidth(), (int) (getChartHeight() * 2.3));
// System.out.printf("OK (%,d ms)\n", TimerUtils.getTime() - start);
}
/**
* Creates a threads chart from the given timer list and stores it to the passed directory.
*
* @param name
* the chart title
* @param outputDir
* the target directory
*/
protected void createThreadsChart(final String name, final File outputDir)
{
// System.out.println("Creating threads chart for agent '" + name + "'... ");
// final long start = TimerUtils.getTime();
final TimeSeries totalThreadsTimeSeries = JFreeChartUtils.toMinMaxTimeSeries(totalThreadsValueSet, "Total Threads");
final TimeSeries runnableThreadsTimeSeries = JFreeChartUtils.toMinMaxTimeSeries(runnableThreadsValueSet, "Runnable Threads");
final TimeSeries blockedThreadsTimeSeries = JFreeChartUtils.toMinMaxTimeSeries(blockedThreadsValueSet, "Blocked Threads");
final TimeSeries waitingThreadsTimeSeries = JFreeChartUtils.toMinMaxTimeSeries(waitingThreadsValueSet, "Waiting Threads");
final MinMaxTimeSeriesCollection collection = new MinMaxTimeSeriesCollection();
collection.addSeries(totalThreadsTimeSeries);
collection.addSeries(runnableThreadsTimeSeries);
collection.addSeries(blockedThreadsTimeSeries);
collection.addSeries(waitingThreadsTimeSeries);
final JFreeChart chart = JFreeChartUtils.createLineChart(name + " -- Threads", "Threads", collection, getStartTime(), getEndTime());
JFreeChartUtils.saveChart(chart, "Threads", outputDir, getChartWidth(), getChartHeight());
// System.out.printf("OK (%,d ms)\n", TimerUtils.getTime() - start);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy