Skip to content

Add support for length-based scoring in prefix cache plugin#1459

Merged
liu-cong merged 1 commit into
llm-d:mainfrom
azamikram:prefix-cache-scorer
Jul 10, 2026
Merged

Add support for length-based scoring in prefix cache plugin#1459
liu-cong merged 1 commit into
llm-d:mainfrom
azamikram:prefix-cache-scorer

Conversation

@azamikram

@azamikram azamikram commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

What type of PR is this?

/kind feature

What this PR does / why we need it:

The current prefix scorer only considers the match ratio when scoring endpoints, treating all matched prefixes equally regardless of their absolute length.

This PR introduces matchLengthWeight and matchLengthScaleTokens parameters to the prefix scorer. The updated scoring function computes a weighted sum of the match ratio and the match length ratio. The match length ratio is non-linear to prioritize KV cache reuse for longer requests relative to the matchLengthScaleTokens.

To maintain backward compatibility, matchLengthWeight defaults to 0.0, preserving the current scoring behavior.

Benchmark results and detailed report

Macro Results (RatioOnlyScorer is the baseline and CostAwareScorer is the proposed function)

Use case 1: RatioOnlyScorer never migrates to a cold pod even when the load increases. CostAwareScorer migrates the short requests to a cold pod.
2-1

Use case 2: Even when RatioOnlyScorer migrates to a cold pod, it places both short and long request on the cold pod.
2-2

Use case 3: When the load increases so much that long requests also need to be migrates to a cold pod, both RatioOnlyScorer and CostAwareScorer converge.
none

Which issue(s) this PR fixes:

Fixes #1095

Release note (write NONE if no user-facing change):

Prefix cache scorer optionally considers absolute prefix match length. 

@github-actions github-actions Bot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Jun 2, 2026
@github-actions
github-actions Bot requested a review from ahg-g June 2, 2026 19:21
@github-actions github-actions Bot added the kind/bug Categorizes issue or PR as related to a bug. label Jun 2, 2026
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

🚨 Unsigned commits detected! Please sign your commits.

For instructions on how to set up GPG/SSH signing and verify your commits, please see GitHub Documentation.

@github-actions
github-actions Bot requested a review from liu-cong June 2, 2026 19:21
@github-actions github-actions Bot added kind/cleanup kind/documentation Categorizes issue or PR as related to documentation. kind/feature Categorizes issue or PR as related to a new feature. labels Jun 2, 2026
@azamikram
azamikram force-pushed the prefix-cache-scorer branch 2 times, most recently from da55286 to 33f74a1 Compare June 2, 2026 19:40
@github-actions github-actions Bot added kind/bug Categorizes issue or PR as related to a bug. kind/cleanup kind/documentation Categorizes issue or PR as related to documentation. kind/feature Categorizes issue or PR as related to a new feature. and removed kind/feature Categorizes issue or PR as related to a new feature. kind/bug Categorizes issue or PR as related to a bug. kind/documentation Categorizes issue or PR as related to documentation. kind/cleanup labels Jun 2, 2026
Comment thread pkg/epp/framework/plugins/scheduling/scorer/prefix/plugin.go Outdated
@azamikram
azamikram force-pushed the prefix-cache-scorer branch from c6b69f5 to c528524 Compare June 2, 2026 21:21

@liu-cong liu-cong left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you also add your benchmark results?

// The name of the data producer that produces PrefixCacheMatchInfo.
PrefixMatchInfoProducerName string `json:"prefixMatchInfoProducerName,omitempty"`
PrefixMatchInfoProducerName string `json:"prefixMatchInfoProducerName,omitempty"`
PrefixLengthWeight *float64 `json:"prefixLengthWeight,omitempty"`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use float and int instead of the pointers?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pointers are useful for differentiating between fields not in the JSON and fields in the JSON with the default value (0 or 0.0 in this case).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided to go with float and int to keep things simple. Let me know what you think.

Comment thread pkg/epp/framework/plugins/scheduling/scorer/prefix/README.md Outdated

- higher score: more of the request prefix is expected to be reusable from cache
- lower score: less prefix cache reuse is expected
If `prefixLengthWeight` is `0.0` (the default), the score simplifies to just the `matchRatio`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment should be included in the initial description of how the plugin computes the score.

## Configuration

This plugin does not define any plugin-specific parameters.
This plugin supports the following configuration parameters:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This plugin supports the following configuration parameters:
This plugin supports the following optional configuration parameters:

@liu-cong

liu-cong commented Jun 5, 2026

Copy link
Copy Markdown
Member

/hold until we get good benchmarking results

@github-actions github-actions Bot added the hold PRs that are blocked on design, other features, release cycle, etc. label Jun 5, 2026
@shmuelk

shmuelk commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

@azamikram Please rebase with main to solve the CI issues

@ahg-g ahg-g left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think another approach is to set a minimum for the denominator (8k tokens for example, but we need to do some testing), this will make it simpler since it is just one parameter, not two.

// The name of the data producer that produces PrefixCacheMatchInfo.
PrefixMatchInfoProducerName string `json:"prefixMatchInfoProducerName,omitempty"`
PrefixMatchInfoProducerName string `json:"prefixMatchInfoProducerName,omitempty"`
PrefixLengthWeight *float64 `json:"prefixLengthWeight,omitempty"`

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls clearly document the parameters

PrefixMatchInfoProducerName string `json:"prefixMatchInfoProducerName,omitempty"`
PrefixMatchInfoProducerName string `json:"prefixMatchInfoProducerName,omitempty"`
PrefixLengthWeight *float64 `json:"prefixLengthWeight,omitempty"`
MaxModelLen *int `json:"maxModelLen,omitempty"`

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MaxModelLen is confusing (I know vllm uses this name, but it is not accurate), probably MaxContextLength? also, what is the unit? please prefix it with the unit, if tokens, it would be MaxContextLengthTokens

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that MaxModelLen is a bit confusing and its purpose isn't set to a limit on the maximum number of tokens. The goal is to configure the point at which the requests become most important for KV cache usage. I ended up renaming it to prefillSaturationTokens, let me know what you think.

This produces a normalized score in the range `[0, 1]`:
Where:
- `matchRatio = matchBlocks / totalBlocks` (the fraction of the request prefix matched)
- `matchLengthRatio = min(1.0, matchedBlocks * blockSize / maxModelLen) ^ 2` (square of normalized matched blocks relative to `maxModelLen`)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

explain why this is applying a square

| Parameter | Type | Description | Default |
| :--- | :--- | :--- | :--- |
| `prefixLengthWeight` | float | Weight of the absolute prefix length in the score. Must be between `0.0` and `1.0`. | `0.0` |
| `maxModelLen` | integer | The maximum context length (in tokens) supported by the model. Required if `prefixLengthWeight` > `0.0`. | `8192` |

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is this default being applied?

@@ -115,8 +138,19 @@ func (p *Plugin) Score(ctx context.Context, _ *fwksched.InferenceRequest, endpoi
}

if prefixMatchInfo, ok := info.(*attrprefix.PrefixCacheMatchInfo); ok {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to reduce indentation, pls do the following:

if prefixMatchInfo, ok := info.(*attrprefix.PrefixCacheMatchInfo); !ok {
  logger.V(logutil.DEFAULT).Error(nil, "PrefixCacheMatchInfo has unexpected type, assigning score 0", "endpoint", endpoint)
  return scores
}

// reset of the scores calculations
return scores

@hexfusion

Copy link
Copy Markdown
Contributor

@azamikram we would like to get this into the release do you have cycles to address feedback?

zetxqx
zetxqx previously approved these changes Jul 2, 2026
Comment thread pkg/epp/framework/plugins/scheduling/scorer/prefix/plugin.go
Comment thread pkg/epp/framework/plugins/scheduling/scorer/prefix/plugin.go Outdated
```text
score = matchBlocks / totalBlocks
score = 0
score += matchLengthWeight * matchLengthRatio

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls also update the doc according with the renamed matchLengthScore and matchRatioScore.

Let's also have the formula in one line, score += add unnecessary cognitive overhead IMO.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the doc and the PR description as well. Also add main results in the PR from the doc.

@liu-cong liu-cong removed kind/bug Categorizes issue or PR as related to a bug. hold PRs that are blocked on design, other features, release cycle, etc. kind/cleanup labels Jul 9, 2026
@github-actions github-actions Bot added kind/bug Categorizes issue or PR as related to a bug. kind/cleanup kind/documentation Categorizes issue or PR as related to documentation. kind/feature Categorizes issue or PR as related to a new feature. and removed kind/feature Categorizes issue or PR as related to a new feature. kind/documentation Categorizes issue or PR as related to documentation. kind/bug Categorizes issue or PR as related to a bug. kind/cleanup labels Jul 9, 2026
@azamikram
azamikram force-pushed the prefix-cache-scorer branch from bf0865c to 0752452 Compare July 9, 2026 21:59
@azamikram
azamikram requested a review from liu-cong July 9, 2026 22:03
@github-actions github-actions Bot removed kind/feature Categorizes issue or PR as related to a new feature. kind/bug Categorizes issue or PR as related to a bug. labels Jul 9, 2026
Signed-off-by: Azam Ikram <azamikram@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/bug Categorizes issue or PR as related to a bug. kind/cleanup kind/documentation Categorizes issue or PR as related to documentation. kind/feature Categorizes issue or PR as related to a new feature. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

No open projects
Status: No status

Development

Successfully merging this pull request may close these issues.

Approximate prefix cache scorer should incorporate the absolute match length when calculating the score

6 participants