Skip to content

🌱 crd/markers: Emit cheaper CEL rules for oneOf markers - #1408

Merged
k8s-ci-robot merged 1 commit into
kubernetes-sigs:mainfrom
HadrienPatte:pr/HadrienPatte/cheaper-cel
May 18, 2026
Merged

🌱 crd/markers: Emit cheaper CEL rules for oneOf markers#1408
k8s-ci-robot merged 1 commit into
kubernetes-sigs:mainfrom
HadrienPatte:pr/HadrienPatte/cheaper-cel

Conversation

@HadrienPatte

Copy link
Copy Markdown
Contributor

Followup to #1212

AtMostOneOf, ExactlyOneOf, and AtLeastOneOf currently emit a CEL rule of the form:

[has(self.a), has(self.b), ...].filter(x, x == true).size() <op> N

This pays for list construction and a comprehension over the list. Two equivalent but cheaper forms work just as well:

  • AtMostOneOf/ExactlyOneOf: ternary-sum:

    (has(self.a)?1:0) + (has(self.b)?1:0) + ... <op> 1
    

    Constant-cost scalar arithmetic, no list, no iteration.

  • AtLeastOneOf: short-circuit OR:

    has(self.a) || has(self.b) || ...
    

    Already a boolean, no count/compare, short-circuits as soon as any field is set.

User-visible behavior is unchanged: violation messages are emitted from the marker's static Message field, not from the rule expression itself.

I did some benchmarking with github.com/google/cel-go/checker to measure the estimated cost of both the old and the new CEL expressions with a couple number of items:

  • estimated cost is from checker.EstimateCost: worst-case, what the apiserver budgets against the per-CRD limit at CRD-creation time
  • runtime cost is from interpreter ActualCost: what counts against the per-call budget at admission

Runtime input states:

  • none: no field set
  • one: only first field set
  • all: every field set
  • last: only last field set

ExactlyOneOf / AtMostOneOf (filter -> sum)

N est.min est.max rt.none rt.one rt.all
2 33 -> 6 57 -> 6 (−89%) 31 -> 6 44 -> 6 44 -> 6
3 38 -> 9 74 -> 9 (−88%) 35 -> 9 48 -> 9 48 -> 9
5 48 -> 15 108 -> 15 (−86%) 43 -> 15 56 -> 15 56 -> 15
10 73 -> 30 193 -> 30 (−84%) 63 -> 30 76 -> 30 76 -> 30

AtLeastOneOf (filter -> ||)

N est.min est.max rt.none rt.one rt.last
2 33 -> 2 57 -> 4 (−93%) 31 -> 4 44 -> 2 44 -> 4
3 38 -> 2 74 -> 6 (−92%) 35 -> 6 48 -> 2 48 -> 6
5 48 -> 2 108 -> 10 (−91%) 43 -> 10 56 -> 2 56 -> 10
10 73 -> 2 193 -> 20 (−90%) 63 -> 20 76 -> 2 76 -> 20

Note the rt.one column for AtLeastOneOf (cost 2 across all N): the || form short-circuits as soon as any field is found, so runtime cost is independent of how many fields the marker covers when any earlier one is set.

So these numbers show that:

Followup to kubernetes-sigs#1212

`AtMostOneOf`, `ExactlyOneOf`, and `AtLeastOneOf` currently emit a CEL rule of the form:

```cel
[has(self.a), has(self.b), ...].filter(x, x == true).size() <op> N
```

This pays for list construction and a comprehension over the list. Two equivalent but cheaper forms work just as well:

* `AtMostOneOf`/`ExactlyOneOf`: ternary-sum:
  ```cel
  (has(self.a)?1:0) + (has(self.b)?1:0) + ... <op> 1
  ```
  Constant-cost scalar arithmetic, no list, no iteration.

* `AtLeastOneOf`: short-circuit OR:
  ```cel
  has(self.a) || has(self.b) || ...
  ```
  Already a boolean, no count/compare, short-circuits as soon as any field is set.

User-visible behavior is unchanged: violation messages are emitted from the marker's static `Message` field, not from the rule expression itself.

I did some benchmarking with `github.com/google/cel-go/checker` to
measure the estimated cost of both the old and the new CEL expressions
with a couple number of items:
* estimated cost is from `checker.EstimateCost`: worst-case, what the apiserver budgets against the per-CRD limit at CRD-creation time
* runtime cost is from interpreter `ActualCost`: what counts against the per-call budget at admission

Runtime input states:
* `none`: no field set
* `one`: only first field set
* `all`: every field set
* `last`: only last field set

.### `ExactlyOneOf` / `AtMostOneOf` (filter -> sum)

| N  | est.min  | est.max           | rt.none  | rt.one   | rt.all   |
|----|----------|-------------------|----------|----------|----------|
| 2  | 33 -> 6  | 57 -> 6 (−89%)    | 31 -> 6  | 44 -> 6  | 44 -> 6  |
| 3  | 38 -> 9  | 74 -> 9 (−88%)    | 35 -> 9  | 48 -> 9  | 48 -> 9  |
| 5  | 48 -> 15 | 108 -> 15 (−86%)  | 43 -> 15 | 56 -> 15 | 56 -> 15 |
| 10 | 73 -> 30 | 193 -> 30 (−84%)  | 63 -> 30 | 76 -> 30 | 76 -> 30 |

.### `AtLeastOneOf` (filter -> `||`)

| N  | est.min  | est.max           | rt.none  | rt.one  | rt.last  |
|----|----------|-------------------|----------|---------|----------|
| 2  | 33 -> 2  | 57 -> 4 (−93%)    | 31 -> 4  | 44 -> 2 | 44 -> 4  |
| 3  | 38 -> 2  | 74 -> 6 (−92%)    | 35 -> 6  | 48 -> 2 | 48 -> 6  |
| 5  | 48 -> 2  | 108 -> 10 (−91%)  | 43 -> 10 | 56 -> 2 | 56 -> 10 |
| 10 | 73 -> 2  | 193 -> 20 (−90%)  | 63 -> 20 | 76 -> 2 | 76 -> 20 |

Note the `rt.one` column for `AtLeastOneOf` (cost `2` across all N): the `||` form short-circuits as soon as any field is found, so runtime cost is independent of how many fields the marker covers when any earlier one is set.

So these numbers show that:
* both estimated and runtime cost are always lower with the new
  expressions
* the maximum estimated cost, which as raised in kubernetes-sigs#1212 can
  quickly balloon when nested deep in layers of unbounded arrays is
  significantly reduced by about 90% in average
@k8s-ci-robot k8s-ci-robot added cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels May 8, 2026
@k8s-ci-robot

Copy link
Copy Markdown
Contributor

Hi @HadrienPatte. Thanks for your PR.

I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work.

Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@k8s-ci-robot k8s-ci-robot added the size/M Denotes a PR that changes 30-99 lines, ignoring generated files. label May 8, 2026

@JoelSpeed JoelSpeed left a comment

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.

Thanks for the analysis of the cost and the optimisation suggestions, LGTM
/lgtm
/approve

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label May 18, 2026
@k8s-ci-robot

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: HadrienPatte, JoelSpeed

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot

Copy link
Copy Markdown
Contributor

LGTM label has been added.

DetailsGit tree hash: 985e3d39ae4341373ea6b344e4e1c8c0306b5dec

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label May 18, 2026
@JoelSpeed

Copy link
Copy Markdown
Contributor

/ok-to-test

@k8s-ci-robot k8s-ci-robot added ok-to-test Indicates a non-member PR verified by an org member that is safe to test. and removed needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels May 18, 2026
@k8s-ci-robot
k8s-ci-robot merged commit e045852 into kubernetes-sigs:main May 18, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. ok-to-test Indicates a non-member PR verified by an org member that is safe to test. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants