Skip to content

Conversation

@gpkc
Copy link

@gpkc gpkc commented Aug 12, 2025

Added piecewise linear workloads. Example:

name: 'bell-throughput'

topics: 1
partitionsPerTopic: 60
messageSize: 1024
subscriptionsPerTopic: 3
consumerPerSubscription: 6
producersPerTopic: 12

consumerBacklogSizeGB: 0
testDurationMinutes: 30

useRandomizedPayloads: true
randomBytesRatio: 0.8
randomizedPayloadPoolSize: 1000

producerRate: 10000
producerRateTimeline:
  - { timeSeconds: 1, rate: 10000 }
  - { timeSeconds: 33, rate: 10526 }
  - { timeSeconds: 73, rate: 12602 }
  - { timeSeconds: 129, rate: 17917 }
  - { timeSeconds: 198, rate: 28215 }
  - { timeSeconds: 280, rate: 44610 }
  - { timeSeconds: 372, rate: 66724 }
  - { timeSeconds: 474, rate: 92070 }
  - { timeSeconds: 582, rate: 116159 }
  - { timeSeconds: 695, rate: 133611 }
  - { timeSeconds: 810, rate: 140000 }
  - { timeSeconds: 990, rate: 140000 }
  - { timeSeconds: 1105, rate: 133611 }
  - { timeSeconds: 1218, rate: 116159 }
  - { timeSeconds: 1326, rate: 92070 }
  - { timeSeconds: 1428, rate: 66724 }
  - { timeSeconds: 1520, rate: 44610 }
  - { timeSeconds: 1602, rate: 28215 }
  - { timeSeconds: 1671, rate: 17917 }
  - { timeSeconds: 1727, rate: 12602 }
  - { timeSeconds: 1767, rate: 10526 }
  - { timeSeconds: 1800, rate: 10000 }

Workload would look like:
image

I've added changes also to WorkloadSetTemplate and the WorkloadGenerator tool, 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).

@gpkc gpkc requested review from Copilot and jeqo August 12, 2025 14:30
Copy link

Copilot AI left a 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

(workload.producerRateTimelineIntervalSeconds != null)
? Math.max(1, workload.producerRateTimelineIntervalSeconds)
: 1;
final double initialRate = Math.max(1.0, workload.producerRate);
Copy link

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.

Copy link
Author

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 using producerRateTimeline and producerRate will then be ignored
  • we use producerInitialRate now also for the probe mode (find max throughput)

workload.testDurationMinutes = template.testDurationMinutes;
workload.warmupDurationMinutes = template.warmupDurationMinutes;
workload.useRandomizedPayloads = template.useRandomizedPayloads;
if (template.producerRateTimeline != null && !template.producerRateTimeline.isEmpty()) {
Copy link

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

Copy link
Author

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!

@gpkc gpkc force-pushed the gpkc-piecewise-linear-workloads branch from 96c3baf to b663d22 Compare August 18, 2025 15:02
@gpkc gpkc requested a review from jeqo August 19, 2025 07:44
if (workload.consumerBacklogSizeGB > 0 && workload.producerRate == 0) {
if (workload.consumerBacklogSizeGB > 0
&& workload.producerRate == 0
&& workload.producerRateTimeline.isEmpty()) {
Copy link

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.

Comment on lines +84 to +87
if (workload.producerInitialRate == null || workload.producerInitialRate <= 0) {
throw new IllegalArgumentException(
"producerInitialRate must be > 0 when producerRateTimeline is configured");
}
Copy link

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

Comment on lines +93 to +96
if (workload.producerInitialRate == null || workload.producerInitialRate <= 0) {
throw new IllegalArgumentException(
"producerInitialRate must be > 0 when probing maximum sustainable rate "
+ "(producerRate == 0 and no timeline)");
Copy link

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;
Copy link

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants