jmeter-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sebb <seb...@gmail.com>
Subject Re: curiosities in SampleSender
Date Tue, 26 Mar 2013 10:56:18 GMT
On 26 March 2013 08:35, Danny Lade <D.Lade@bigpoint.net> wrote:
> Sorry guys,
>
> I've found the error in the code itself and not in the handling of sample senders.
>
> Hint: Never use static ThreadLocal (statisticalMapSelector) AND non-static attributes
(statisticalMaps) to store data for threads.
> (removing the "static" from the ThreadLocal solved all the problems)
>
> One simple question is still open, when and why does JMeter opens different instances
of SampleSender?

If you want to know when your class is instatiated, add the logging to it.
I tend to use something like:

log.debug("N", new Throwable());

where N is a unique number or string within the class.

> Tracking the data that had been processed at the instances gave me no clue about a logic
behind it.
>
> G Danny
>
> -----original message-----
> Von: Danny Lade [mailto:D.Lade@bigpoint.net]
> Gesendet: Dienstag, 19. März 2013 10:45
> An: dev@jmeter.apache.org
> Betreff: curiosities in SampleSender
>
> Dear JMeter-Community,
>
> there are two things I don't get using my own SampleSender (see attachement).
>
> 1.  if I initialize the "statisticalMapSelector" (ThreadLocal) static I get no results
at the client shown and the jmeter-server.log looks like :
>
>     2013/03/19 09:45:28 INFO  - net.bigpoint.jmeter.samplers.StatisticalHoldSampleSender:
Test Ended on host: 10.188.26.243
>     2013/03/19 09:45:28 INFO  - net.bigpoint.jmeter.samplers.StatisticalHoldSampleSender:
Process 110 events
>     2013/03/19 09:45:28 INFO  - net.bigpoint.jmeter.samplers.StatisticalHoldSampleSender:
Test Ended on host: 10.188.26.243
>     2013/03/19 09:45:28 INFO  - net.bigpoint.jmeter.samplers.StatisticalHoldSampleSender:
Process 0 events
>     2013/03/19 09:45:28 INFO  - jmeter.engine.StandardJMeterEngine: Test has ended on
host 10.188.26.243
>
> 2. if I clean up the data at testEnded() using "finally { statisticalMaps.clear(); }"
I get no results at the client shown and the jmeter-server.log looks like above
>
> In all other cases this code works fine (as attached)
> -----source-----
> package net.bigpoint.jmeter.samplers;
>
> import static com.google.common.base.Objects.firstNonNull;
> import static com.google.common.base.Objects.toStringHelper;
> import static com.google.common.base.Preconditions.checkNotNull;
> import static com.google.common.base.Strings.emptyToNull;
>
> import java.io.ObjectStreamException;
> import java.io.Serializable;
> import java.rmi.RemoteException;
> import java.util.List;
> import java.util.Map;
>
> import org.apache.jmeter.samplers.AbstractSampleSender;
> import org.apache.jmeter.samplers.RemoteSampleListener;
> import org.apache.jmeter.samplers.SampleEvent;
> import org.apache.jmeter.samplers.SampleResult;
> import org.apache.jmeter.save.SaveService;
> import org.apache.jorphan.logging.LoggingManager;
> import org.apache.log.Logger;
>
> import com.google.common.base.Objects;
> import com.google.common.collect.Lists;
> import com.google.common.collect.Maps;
>
> public class StatisticalHoldSampleSender extends AbstractSampleSender implements Serializable
{
>
>     private static final long serialVersionUID = 1167910624585715712L;
>
>     private static final Logger log = LoggingManager.getLoggerForClass();
>
>     private final RemoteSampleListener listener;
>
>     // note: it is necessary to initialize this value at readResolve() and NOT statically
>     private static transient ThreadLocal<Map<StatisticalResult, StatisticalResult>>
statisticalMapSelector;
>
>     private transient List<Map<StatisticalResult, StatisticalResult>> statisticalMaps;
>
>     /**
>      * Constructor, only called by client code.
>      *
>      * @param listener that the List of sample events will be sent to.
>      */
>     public StatisticalHoldSampleSender(RemoteSampleListener listener) {
>         this.listener = listener;
>     }
>
>     /**
>      * @param event a Sample Event
>      */
>     @Override
>     public void sampleOccurred(SampleEvent event) {
>         StatisticalResult key = new StatisticalResult(event);
>         StatisticalResult result = putIfAbsent(statisticalMapSelector.get(), key, key);
>         result.update(event);
>     }
>
>     /**
>      * Checks if any sample events are still present in the sampleStore and
>      * sends them to the listener. Informs the listener of the testended.
>      *
>      * @param host the hostname that the test has ended on.
>      */
>     @Override
>     public void testEnded(String host) {
>         final String threadName = Thread.currentThread().getName();
>         log.info("Test Ended on host: " + host);
>         try {
>             List<SampleEvent> events = Lists.newArrayList();
>             for (Map<StatisticalResult, StatisticalResult> statisticalResultMap
: statisticalMaps) {
>                 for (StatisticalResult statisticalResult : statisticalResultMap.values())
{
>                     if (log.isDebugEnabled()) {
>                         log.debug("# " + threadName + " - Add event for: " + statisticalResult);
>                     }
>                     events.add(createSampleEvent(statisticalResult));
>                 }
>                 statisticalResultMap.clear();
>             }
>             log.info("Process " + events.size() + " events");
>             listener.processBatch(events);
>             listener.testEnded(host);
>         } catch (RemoteException err) {
>             log.error("testEnded(hostname)", err);
>         }
>     }
>
>     private static <K, V> V putIfAbsent(Map<K, V> map, K key, V value) {
>         V originalValue = map.get(key);
>         if (originalValue == null) {
>             map.put(key, value);
>             originalValue = value;
>             if (log.isDebugEnabled()) {
>                 log.debug("# Add object to map: " + value);
>             }
>         }
>         return originalValue;
>     }
>
>     static SampleEvent createSampleEvent(StatisticalResult statResult) {
>         SampleResult sampleResult = new SampleResult(statResult.startTime, statResult.elapsed);
>
>         sampleResult.setThreadName(statResult.threadName);
>         sampleResult.setSampleLabel(statResult.label);
>         sampleResult.setSampleCount(statResult.sampleCount);
>         sampleResult.setDataType(statResult.sampleType);
>         sampleResult.setBytes(statResult.requestSize);
>         sampleResult.setErrorCount(statResult.errorCount);
>         sampleResult.setResponseCode(statResult.responseCode);
>         sampleResult.setLatency(statResult.latency);
>         sampleResult.setEndTime(statResult.endTime);
>
>         return new SampleEvent(sampleResult, statResult.threadGroup);
>     }
>
>     /**
>      * Processed by the RMI server code; acts as testStarted().
>      *
>      * @throws ObjectStreamException
>      */
>     @SuppressWarnings("static-access")
>     private Object readResolve() throws ObjectStreamException {
>         this.statisticalMaps = Lists.newArrayList();
>         this.statisticalMapSelector = new ThreadLocal<Map<StatisticalResult, StatisticalResult>>()
{
>             @Override
>             protected java.util.Map<StatisticalResult, StatisticalResult> initialValue()
{
>                 final Map<StatisticalResult, StatisticalResult> statisticalMap
= Maps.newHashMap();
>
>                 statisticalMaps.add(statisticalMap);
>                 return statisticalMap;
>             };
>         };
>
>         log.info(toStringHelper("running with ").toString());
>         return this;
>     }
>
>     static class StatisticalResult {
>
>         final String threadGroup;
>
>         final String threadName;
>
>         final String label;
>
>         final String responseCode;
>
>         final String sampleType;
>
>         int sampleCount = 0;
>
>         int errorCount = 0;
>
>         int requestSize = 0;
>
>         long startTime = Long.MAX_VALUE; // guarantee it is set with the first update()
>
>         long endTime = 0;
>
>         long latency = 0;
>
>         long elapsed = 0;
>
>         /**
>          * Create a statistical sample result.
>          */
>         StatisticalResult(SampleEvent event) {
>             // using of intern string pool guarantees precalculated hashes and less memory
usage
>             checkNotNull(event);
>             SampleResult result = checkNotNull(event.getResult());
>             this.threadGroup = firstNonNull(emptyToNull(event.getThreadGroup()), "<unknown
group>").intern();
>             this.threadName = firstNonNull(emptyToNull(result.getThreadName()), "<unknown
thread>").intern();
>             this.label = firstNonNull(emptyToNull(result.getSampleLabel()), "<unknown
label>").intern();
>             this.responseCode = firstNonNull(emptyToNull(result.getResponseCode()), "<unknown
response code>").intern();
>             this.sampleType = SaveService.classToAlias(result.getClass().getName());
>         }
>
>         void update(SampleEvent event) {
>             checkNotNull(event);
>             SampleResult result = checkNotNull(event.getResult());
>             if (!result.isSuccessful()) {
>                 errorCount++;
>             }
>             sampleCount += result.getSampleCount();
>             requestSize += result.getBytes();
>             startTime = Math.min(startTime, result.getStartTime());
>             endTime = Math.max(endTime, result.getEndTime());
>             latency += result.getLatency();
>             elapsed += result.getTime();
>         }
>
>         @Override
>         public int hashCode() {
>             return Objects.hashCode(responseCode, label, sampleType);
>         }
>
>         @Override
>         public boolean equals(Object obj) {
>             if (obj == null || this.getClass() != obj.getClass()) {
>                 return false;
>             }
>             final StatisticalResult other = (StatisticalResult) obj;
>             return Objects.equal(this.responseCode, other.responseCode) && Objects.equal(this.label,
other.label)
>                     && Objects.equal(this.sampleType, other.sampleType);
>         }
>
>         @Override
>         public String toString() {
>             return toStringHelper(this).add("sampleType", sampleType).add("threadGroup",
threadGroup).add("threadName", threadName).add("label", label)
>                     .add("responseCode", responseCode).add("sampleCount", sampleCount).add("errorCount",
errorCount).add("requestSize", requestSize)
>                     .add("startTime", startTime).add("endTime", endTime).add("latency",
latency).add("elapsedTime", elapsed).toString();
>         }
>     }
> }

Mime
View raw message