Repository: open-telemetry/opentelemetry-java
File: sdk/all/src/jmh/java/io/opentelemetry/sdk/SpanRecordBenchmark.java (Java)

Code before:
import org.openjdk.jmh.annotations.GroupThreads;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
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.TearDown;
import org.openjdk.jmh.annotations.Warmup;

/**
 * This benchmark measures the performance of recording spans and includes the following dimensions:
 *
 * <ul>
 *   <li>{@link BenchmarkState#spanSize}: the size of the span, which is a composite of the number
 *       of attributes, events, and links attached to the span.
 * </ul>
 *
 * <p>Each operation consists of recording {@link SpanRecordBenchmark#RECORDS_PER_INVOCATION} spans.
 *
 * <p>In order to isolate the record path while remaining realistic, the benchmark uses a {@link
 * BatchSpanProcessor} paired with a noop {@link SpanExporter}. In order to avoid quickly outpacing
 * the batch processor queue and dropping spans, the processor is configured with a queue size of
 * {@link SpanRecordBenchmark#RECORDS_PER_INVOCATION} * {@link SpanRecordBenchmark#MAX_THREADS} and
 * is flushed after each invocation.
 */
public class SpanRecordBenchmark {

  private static final int RECORDS_PER_INVOCATION = BenchmarkUtils.RECORDS_PER_INVOCATION;
  private static final int MAX_THREADS = 4;
  private static final int QUEUE_SIZE = RECORDS_PER_INVOCATION * MAX_THREADS;

  @State(Scope.Benchmark)
  public static class BenchmarkState {

    // Encode a variety of dimensions (# attributes, # events, # links) into a single enum to
    // benchmark various shapes of spans without combinatorial explosion.
    @Param SpanSize spanSize;

    SdkTracerProvider tracerProvider;
    Tracer tracer;
    List<AttributeKey<String>> attributeKeys;
    List<String> attributeValues;
    List<Exception> exceptions;
    List<SpanContext> linkContexts;

    @Setup
    public void setup() {
      tracerProvider =
          SdkTracerProvider.builder()
              // Configure a batch processor with a noop exporter (SpanExporter.composite() is a

Review comment (performance):
This is a key aspect to a useful span record benchmark (and log record benchmark) IMO. We need to isolate from the export path, which is noisy due to the network dependency, while also being realistic. My definition of realistic is a batch span processor and a harness that makes sure that spans aren't just being dropped on the floor from a full queue. 

Code after:
import org.openjdk.jmh.annotations.GroupThreads;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.OperationsPerInvocation;
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.TearDown;
import org.openjdk.jmh.annotations.Warmup;

/**
 * This benchmark measures the performance of recording spans. It includes the following dimensions:
 *
 * <ul>
 *   <li>{@link BenchmarkState#spanSize}: the size of the span, which is a composite of the number
 *       of attributes, events, and links attached to the span.
 * </ul>
 *
 * <p>Each operation consists of recording {@link SpanRecordBenchmark#RECORDS_PER_INVOCATION} spans.
 *
 * <p>In order to isolate the record path while remaining realistic, the benchmark uses a {@link
 * BatchSpanProcessor} paired with a noop {@link SpanExporter}. In order to avoid quickly outpacing
 * the batch processor queue and dropping spans, the processor is configured with a queue size of
 * {@link SpanRecordBenchmark#RECORDS_PER_INVOCATION} * {@link SpanRecordBenchmark#MAX_THREADS} and
 * is flushed after each invocation.
 */
public class SpanRecordBenchmark {

  private static final int RECORDS_PER_INVOCATION = BenchmarkUtils.RECORDS_PER_INVOCATION;
  private static final int MAX_THREADS = 4;
  private static final int QUEUE_SIZE = RECORDS_PER_INVOCATION * MAX_THREADS;

  @State(Scope.Benchmark)
  public static class BenchmarkState {

    // Encode a variety of dimensions (# attributes, # events, # links) into a single enum to
    // benchmark various shapes of spans without combinatorial explosion.
    @Param SpanSize spanSize;

    SdkTracerProvider tracerProvider;
    Tracer tracer;
    List<AttributeKey<String>> attributeKeys;
    List<String> attributeValues;
    List<Exception> exceptions;
    List<SpanContext> linkContexts;

    @Setup
    public void setup() {
      tracerProvider =
          SdkTracerProvider.builder()