-
Notifications
You must be signed in to change notification settings - Fork 0
Piecewise linear workloads #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements piecewise linear workloads that allow dynamic producer rate changes over time through linear interpolation between defined rate points. The feature enables creating bell-curve or other complex rate patterns for more realistic load testing scenarios.
- Adds support for time-based producer rate timelines with linear interpolation between points
- Implements scheduling mechanism to adjust producer rates at configurable intervals
- Extends workload configuration to support rate point definitions and timeline intervals
Reviewed Changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| Workload.java | Adds RatePoint class and timeline fields to define piecewise linear rate schedules |
| WorkloadGenerator.java | Implements the core scheduling logic with linear interpolation and rate adjustment |
| WorkloadSetTemplate.java | Extends template configuration to support rate timeline definitions |
| tool/WorkloadGenerator.java | Adds timeline support to the workload generation tool |
| benchmark-framework/pom.xml | Downgrades jetty and async-http-client dependency versions |
benchmark-framework/src/main/java/io/openmessaging/benchmark/WorkloadGenerator.java
Show resolved
Hide resolved
benchmark-framework/src/main/java/io/openmessaging/benchmark/WorkloadGenerator.java
Show resolved
Hide resolved
benchmark-framework/src/main/java/io/openmessaging/benchmark/WorkloadGenerator.java
Show resolved
Hide resolved
benchmark-framework/src/main/java/io/openmessaging/benchmark/Workload.java
Outdated
Show resolved
Hide resolved
benchmark-framework/src/main/java/io/openmessaging/benchmark/Workload.java
Outdated
Show resolved
Hide resolved
| (workload.producerRateTimelineIntervalSeconds != null) | ||
| ? Math.max(1, workload.producerRateTimelineIntervalSeconds) | ||
| : 1; | ||
| final double initialRate = Math.max(1.0, workload.producerRate); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it's easier to have either a separate configuration, e.g. producerInitialRate, so it's known that this applies to this dynamic changes (we could reuse this on the find max throughput that is hardcoded at 10K); or use the first entry and enforce it starts at zero.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm good point
I'm changing it then:
- we now have
producerInitialRate, it is required if we are usingproducerRateTimelineandproducerRatewill then be ignored - we use
producerInitialRatenow also for the probe mode (find max throughput)
benchmark-framework/src/main/java/io/openmessaging/benchmark/WorkloadGenerator.java
Outdated
Show resolved
Hide resolved
| workload.testDurationMinutes = template.testDurationMinutes; | ||
| workload.warmupDurationMinutes = template.warmupDurationMinutes; | ||
| workload.useRandomizedPayloads = template.useRandomizedPayloads; | ||
| if (template.producerRateTimeline != null && !template.producerRateTimeline.isEmpty()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good finding! Wasn't aware of this tool. Will have a look
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me know if you find a good use case!
96c3baf to
b663d22
Compare
| if (workload.consumerBacklogSizeGB > 0 && workload.producerRate == 0) { | ||
| if (workload.consumerBacklogSizeGB > 0 | ||
| && workload.producerRate == 0 | ||
| && workload.producerRateTimeline.isEmpty()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a WorkloadGeneratorTest to test this validation?
Maybe these need to be separated checks: backlog cannot be defined if producerRate is zero. If producer rate is >0, then check that timeline and initial rate are not defined.
| if (workload.producerInitialRate == null || workload.producerInitialRate <= 0) { | ||
| throw new IllegalArgumentException( | ||
| "producerInitialRate must be > 0 when producerRateTimeline is configured"); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's move this to the constructor as well, and test the validation
| if (workload.producerInitialRate == null || workload.producerInitialRate <= 0) { | ||
| throw new IllegalArgumentException( | ||
| "producerInitialRate must be > 0 when probing maximum sustainable rate " | ||
| + "(producerRate == 0 and no timeline)"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, move this to constructor.
| "producerInitialRate must be > 0 when probing maximum sustainable rate " | ||
| + "(producerRate == 0 and no timeline)"); | ||
| } | ||
| targetPublishRate = workload.producerInitialRate; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wonder if we should default initial rate at 10K to have same default behavior as max throughput.
Would this make it harder to reuse with piecewise workload?
Added piecewise linear workloads. Example:
Workload would look like:

I've added changes also to
WorkloadSetTemplateand theWorkloadGeneratortool, even though we're not using those AFAIK, but we might in the future so the feature is there.The algorithm here basically will interpolate linearly the values between each point defined above. Sampling rate is optionally defined via
producerRateTimelineIntervalSeconds(defaults to 1s).