/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.jmeter.samplers; import java.io.Serializable; /** * Aggregates sample results for use by the Statistical remote batch mode. * Samples are aggregated by the key defined by getKey(). * TODO: merge error count into parent class? */ public class StatisticalSampleResult extends SampleResult implements Serializable { private static final long serialVersionUID = 240L; private int errorCount; // Need to maintain our own elapsed timer to ensure more accurate aggregation private long elapsed; public StatisticalSampleResult(){// May be called by XStream } /** * Allow CsvSaveService to generate a suitable result when sample/error counts have been saved. * * @deprecated Needs to be replaced when multiple sample results are sorted out * * @param stamp this may be a start time or an end time (both in milliseconds) * @param elapsed time in milliseconds */ @Deprecated public StatisticalSampleResult(long stamp, long elapsed) { super(stamp, elapsed); this.elapsed = elapsed; } /** * Create a statistical sample result from an ordinary sample result. * * @param res the sample result */ public StatisticalSampleResult(SampleResult res) { // Copy data that is shared between samples (i.e. the key items): setSampleLabel(res.getSampleLabel()); setThreadName(res.getThreadName()); setSuccessful(true); // Assume result is OK setSampleCount(0); // because we add the sample count in later elapsed = 0; } public void add(SampleResult res) { // Add Sample Counter setSampleCount(getSampleCount() + res.getSampleCount()); setBytes(getBytesAsLong() + res.getBytesAsLong()); setSentBytes(getSentBytes() + res.getSentBytes()); // Add Error Counter if (!res.isSuccessful()) { errorCount++; this.setSuccessful(false); } // Set start/end times if (getStartTime()==0){ // Bug 40954 - ensure start time gets started! this.setStartTime(res.getStartTime()); } else { this.setStartTime(Math.min(getStartTime(), res.getStartTime())); } this.setEndTime(Math.max(getEndTime(), res.getEndTime())); setLatency(getLatency()+ res.getLatency()); setConnectTime(getConnectTime()+ res.getConnectTime()); elapsed += res.getTime(); } @Override public long getTime() { return elapsed; } @Override public long getTimeStamp() { return getEndTime(); } @Override public int getErrorCount() {// Overrides SampleResult return errorCount; } @Override public void setErrorCount(int e) {// for reading CSV files errorCount = e; } /** * Generates the key to be used for aggregating samples as follows:<br> * <code>sampleLabel</code> "-" <code>[threadName|threadGroup]</code> * <p> * N.B. the key should agree with the fixed items that are saved in the sample. * * @param event sample event whose key is to be calculated * @param keyOnThreadName true if key should use thread name, otherwise use thread group * @return the key to use for aggregating samples */ public static String getKey(SampleEvent event, boolean keyOnThreadName) { StringBuilder sb = new StringBuilder(80); sb.append(event.getResult().getSampleLabel()); if (keyOnThreadName){ sb.append('-').append(event.getResult().getThreadName()); } else { sb.append('-').append(event.getThreadGroup()); } return sb.toString(); } }