Merge pull request #1103 from DataDog/landerson/load-generator
Simple load generator tool
This commit is contained in:
commit
99acb52589
|
@ -9,3 +9,4 @@ logback.xml,net.logstash.logback,Apache-2.0,
|
||||||
import (test),org.junit,EPL-1.0,Copyright © 2002-2017 JUnit. All Rights Reserved.
|
import (test),org.junit,EPL-1.0,Copyright © 2002-2017 JUnit. All Rights Reserved.
|
||||||
import (test),org.assertj,Apache-2.0,Copyright 2012-2017 the original author or authors.
|
import (test),org.assertj,Apache-2.0,Copyright 2012-2017 the original author or authors.
|
||||||
import (test),org.mockito,MIT,Copyright (c) 2007 Mockito contributors
|
import (test),org.mockito,MIT,Copyright (c) 2007 Mockito contributors
|
||||||
|
import (test),info.picocli,Apache-2.0,
|
||||||
|
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
Load Generator
|
||||||
|
=====
|
||||||
|
|
||||||
|
Generates a simulated trace load. Run with
|
||||||
|
|
||||||
|
```
|
||||||
|
./gradlew launch --args='--rate 10'
|
||||||
|
```
|
||||||
|
|
||||||
|
**OR**
|
||||||
|
|
||||||
|
```
|
||||||
|
./gradlew :dd-java-agent:load-generator:launch --args='--rate 10'
|
||||||
|
```
|
||||||
|
|
||||||
|
from the root of the repo.
|
||||||
|
|
||||||
|
To print all options, use:
|
||||||
|
|
||||||
|
```
|
||||||
|
--args='--help'
|
||||||
|
```
|
|
@ -0,0 +1,18 @@
|
||||||
|
apply from: "${rootDir}/gradle/java.gradle"
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile project(':dd-trace-api')
|
||||||
|
compile project(':dd-trace-ot')
|
||||||
|
|
||||||
|
compile 'info.picocli:picocli:4.0.4'
|
||||||
|
compile deps.guava
|
||||||
|
}
|
||||||
|
|
||||||
|
task launch(type: JavaExec) {
|
||||||
|
classpath = sourceSets.main.runtimeClasspath
|
||||||
|
main = 'datadog.loadgenerator.LoadGenerator'
|
||||||
|
jvmArgs = ["-javaagent:${project(':dd-java-agent').shadowJar.archivePath}", "-Ddd.service.name=loadtest"]
|
||||||
|
systemProperties System.properties
|
||||||
|
|
||||||
|
dependsOn project(':dd-java-agent').shadowJar
|
||||||
|
}
|
|
@ -0,0 +1,124 @@
|
||||||
|
package datadog.loadgenerator;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.RateLimiter;
|
||||||
|
import io.opentracing.Scope;
|
||||||
|
import io.opentracing.Span;
|
||||||
|
import io.opentracing.Tracer;
|
||||||
|
import io.opentracing.util.GlobalTracer;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import picocli.CommandLine;
|
||||||
|
import picocli.CommandLine.Command;
|
||||||
|
import picocli.CommandLine.Option;
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
mixinStandardHelpOptions = true,
|
||||||
|
description = "Generates traces and spans at a specified rate")
|
||||||
|
public class LoadGenerator implements Callable<Integer> {
|
||||||
|
@Option(names = "--rate", required = true, description = "rate, per second, to generate traces")
|
||||||
|
private int rate;
|
||||||
|
|
||||||
|
@Option(
|
||||||
|
names = "--threads",
|
||||||
|
defaultValue = "6",
|
||||||
|
description = "Number of trace-generating threads (default: ${DEFAULT-VALUE})")
|
||||||
|
private int threads;
|
||||||
|
|
||||||
|
@Option(
|
||||||
|
names = "--width",
|
||||||
|
defaultValue = "2",
|
||||||
|
description = "Number of spans directly below the root (default: ${DEFAULT-VALUE})")
|
||||||
|
private int width;
|
||||||
|
|
||||||
|
@Option(
|
||||||
|
names = "--depth",
|
||||||
|
defaultValue = "3",
|
||||||
|
description = "Total spans deep per trace, including parent (default: ${DEFAULT-VALUE})")
|
||||||
|
private int depth;
|
||||||
|
|
||||||
|
@Option(
|
||||||
|
names = "--warmup",
|
||||||
|
defaultValue = "5",
|
||||||
|
description = "Time, in seconds, to ramp up to target rate (default: ${DEFAULT-VALUE})")
|
||||||
|
private int warmupPeriod;
|
||||||
|
|
||||||
|
@Option(
|
||||||
|
names = "--print-interval",
|
||||||
|
defaultValue = "20",
|
||||||
|
description = "Interval, in seconds, to print statistics (default: ${DEFAULT-VALUE})")
|
||||||
|
private int printInterval;
|
||||||
|
|
||||||
|
private RateLimiter rateLimiter;
|
||||||
|
private final AtomicLong tracesSent = new AtomicLong();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer call() throws Exception {
|
||||||
|
rateLimiter = RateLimiter.create(rate, warmupPeriod, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
long intervalStart = System.currentTimeMillis();
|
||||||
|
long tracesAtLastReport = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < threads; i++) {
|
||||||
|
final Thread workerThread = new Thread(new Worker(), "Worker-" + i);
|
||||||
|
workerThread.setDaemon(true);
|
||||||
|
workerThread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
Thread.sleep(printInterval * 1000);
|
||||||
|
|
||||||
|
final long currentTracesSent = tracesSent.get();
|
||||||
|
final long intervalEnd = System.currentTimeMillis();
|
||||||
|
|
||||||
|
final double currentRate =
|
||||||
|
(currentTracesSent - tracesAtLastReport) / ((intervalEnd - intervalStart) / 1000d);
|
||||||
|
|
||||||
|
System.out.println(
|
||||||
|
"Total Traces Sent: " + currentTracesSent + ", Rate this interval: " + currentRate);
|
||||||
|
intervalStart = System.currentTimeMillis();
|
||||||
|
tracesAtLastReport = currentTracesSent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(final String[] args) {
|
||||||
|
final int exitCode = new CommandLine(new LoadGenerator()).execute(args);
|
||||||
|
System.exit(exitCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Worker implements Runnable {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
final Tracer tracer = GlobalTracer.get();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
rateLimiter.acquire();
|
||||||
|
final Span parent = tracer.buildSpan("parentSpan").start();
|
||||||
|
|
||||||
|
try (final Scope scope = tracer.activateSpan(parent)) {
|
||||||
|
for (int i = 0; i < width; i++) {
|
||||||
|
final Span widthSpan = tracer.buildSpan("span-" + i).start();
|
||||||
|
try (final Scope widthScope = tracer.activateSpan(widthSpan)) {
|
||||||
|
for (int j = 0; j < depth - 2; j++) {
|
||||||
|
final Span depthSpan = tracer.buildSpan("span-" + i + "-" + j).start();
|
||||||
|
try (final Scope depthScope = tracer.activateSpan(depthSpan)) {
|
||||||
|
// do nothing. Maybe sleep? but that will mean we need more threads to keep the
|
||||||
|
// effective rate
|
||||||
|
} finally {
|
||||||
|
depthSpan.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
widthSpan.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
parent.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
tracesSent.getAndIncrement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,6 +27,7 @@ include ':dd-java-agent'
|
||||||
include ':dd-java-agent:agent-bootstrap'
|
include ':dd-java-agent:agent-bootstrap'
|
||||||
include ':dd-java-agent:agent-tooling'
|
include ':dd-java-agent:agent-tooling'
|
||||||
include ':dd-java-agent:agent-jmxfetch'
|
include ':dd-java-agent:agent-jmxfetch'
|
||||||
|
include ':dd-java-agent:load-generator'
|
||||||
|
|
||||||
// misc
|
// misc
|
||||||
include ':dd-java-agent:testing'
|
include ':dd-java-agent:testing'
|
||||||
|
|
Loading…
Reference in New Issue