Skip to content

Commit 976bc7d

Browse files
Update performance analysis section
1 parent 6cf3aa1 commit 976bc7d

File tree

1 file changed

+44
-111
lines changed
  • keps/sig-api-machinery/4595-cel-crd-additionalprintercolumns

1 file changed

+44
-111
lines changed

keps/sig-api-machinery/4595-cel-crd-additionalprintercolumns/README.md

Lines changed: 44 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -728,58 +728,53 @@ With all of this we can pass the CEL program to the TableConvertor's `ConvertToT
728728

729729
### CEL vs JSONPath Performance Analysis
730730

731-
A big part of the discussions for our proposal was the CEL cost limits since this is the first time CEL is added to the read path. As part of this we've done some benchmarking of the time it takes to parse and compile equivalent JSONPath and CEL expressions.
732-
733-
For the performance analysis, we introduced two new benchmark tests to the `tableconvertor_test.go` file – `Benchmark_CEL` and `Benchmark_JSONPath`.
734-
735-
Please find the raw output of the benchmark tests, as well as the code for executing them in the following gist:
736-
[https://gist.github.com/sreeram-venkitesh/f4aff1ae7957a5a3b9c6c53e869b7403](https://gist.github.com/sreeram-venkitesh/f4aff1ae7957a5a3b9c6c53e869b7403)
737-
738-
739-
Considering the following 10 iterations of the `Benchmark_CEL` and `Benchmark_JSONPath` tests:
740-
741-
```
742-
CEL Benchmark Results (10 runs):
743-
- Run 1: 2,772 iterations, 461,257 ns/op
744-
- Run 2: 3,070 iterations, 355,537 ns/op
745-
- Run 3: 3,247 iterations, 353,626 ns/op
746-
- Run 4: 3,090 iterations, 360,392 ns/op
747-
- Run 5: 3,249 iterations, 351,305 ns/op
748-
- Run 6: 2,942 iterations, 454,657 ns/op
749-
- Run 7: 3,379 iterations, 354,431 ns/op
750-
- Run 8: 2,858 iterations, 365,886 ns/op
751-
- Run 9: 3,374 iterations, 353,106 ns/op
752-
- Run 10: 3,130 iterations, 368,940 ns/op
753-
754-
JSONPath Benchmark Results (10 runs):
755-
- Run 1: 76,616 iterations, 19,376 ns/op
756-
- Run 2: 73,274 iterations, 15,761 ns/op
757-
- Run 3: 72,625 iterations, 18,572 ns/op
758-
- Run 4: 70,324 iterations, 15,896 ns/op
759-
- Run 5: 69,409 iterations, 15,892 ns/op
760-
- Run 6: 70,672 iterations, 17,888 ns/op
761-
- Run 7: 72,145 iterations, 16,176 ns/op
762-
- Run 8: 69,602 iterations, 16,203 ns/op
763-
- Run 9: 68,079 iterations, 24,558 ns/op
764-
- Run 10: 62,689 iterations, 16,214 ns/op
765-
```
766-
767-
The following table provides an average performance analysis across CEL and JSONPath based additionalPrinterColumns:
768-
769-
770-
| | CEL (Benchmark_CEL) | JSONPath (Benchmark_JSONPath) |
771-
|--------------------------------------|--------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------|
772-
| **Column Definition** | `self.spec.servers.map(s, s.hosts.filter(h, h == "prod.example.com"))` | `.spec.servers[*].hosts[?(@ == "prod.example.com")]` |
773-
| **Overall Performance**<br>(Compilation + Evaluation) | • Average iterations: 3,111 <br> • Average time per operation: **382,914 ns/op** (~383 µs per op) <br> • Standard deviation: ±42,087 ns (±11%) | • Average iterations: 70,542 iterations <br> • Average time per operation: **17,654 ns/op** (~17.7 µs per op) <br> • Standard deviation: ±2,846 ns (±16%) |
774-
| **Compilation Performance** | • Cold Start: 2.340 ms<br><br>• Warmed: 300–400 µs<br>&emsp;◦ Most Expensive / Consistent Phases:<br>&emsp;&emsp;• Env & Cost Estimator: 160–220 µs avg<br>&emsp;&emsp;• CEL Compilation: 60–120 µs avg<br>&emsp;&emsp;• Program Generation: 50–80 µs avg<br><br>• 83% improvement (2.34 ms → ~400 µs)| • Cold Start: ~85 µs<br><br>• Warmed: 5–8 µs<br>&emsp;◦ Most Expensive / Consistent Phases:<br>&emsp;&emsp;• JSONPath Parsing: 4–85 µs (occasional spikes)<br><br>• 90% improvement (85 µs → ~8 µs)|
775-
| **Evaluation Performance** | **FindResults** <br> • Cold: 103.5 µs <br> • Warmed: 13.5 µs <br> • 81% improvement (103.5 → 13.5 µs) <br><br> **PrintResults** <br> • Cold: 3.9 µs <br> • Warmed: 1.5 µs <br> • 70% improvement (3.9 → 1.5 µs) | **FindResults** <br> • Cold: 1.4 µs <br> • Warmed: 0.85 µs <br> • 29% improvement (1.4 → 0.85 µs) <br><br> **PrintResults** <br> • Cold: 0.29 µs <br> • Warmed: 0.18 µs <br> • 58% improvement (0.29 → 0.18 µs) |
731+
A big part of the discussions for our proposal was the CEL cost limits since this is the first time CEL is added to the read path. As part of this we've done benchmarking of the time it takes to parse and compile equivalent JSONPath and CEL expressions.
732+
733+
> **Note**: The following benchmark analysis statistics are only indicative of the performance. The actual numbers may vary across different runs of the same test.
734+
735+
Refer:
736+
- [Source code for the POC](https://github.com/sreeram-venkitesh/kubernetes/commits/kep-4595-poc/?since=2025-07-20&until=2025-07-22&author=sreeram-venkitesh)
737+
- Scenario 1: Benchmarking overall performance (compilation + evaluation + cost estimation bits et.al)
738+
<details>
739+
<summary>Details</summary>
740+
<br/>
741+
<p>Run on Apple M3 Pro with 12 cores, 18 GB RAM, arm64</p>
742+
<p>Find the raw output of the benchmark tests, as well as the source code: https://gist.github.com/sreeram-venkitesh/f4aff1ae7957a5a3b9c6c53e869b7403</p>
743+
<p>The following table provides an average performance analysis across CEL and JSONPath based additionalPrinterColumns:</p>
744+
745+
| | CEL ([BenchmarkNew_CEL](https://gist.github.com/sreeram-venkitesh/f4aff1ae7957a5a3b9c6c53e869b7403#file-tableconvertor_test-go-L36-L75)) | JSONPath ([BenchmarkNew_JSONPath](https://gist.github.com/sreeram-venkitesh/f4aff1ae7957a5a3b9c6c53e869b7403#file-tableconvertor_test-go-L77-L116)) |
746+
|--------------------------------------|--------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------|
747+
| **Column Definition** | `self.spec.servers.map(s, s.hosts.filter(h, h == "prod.example.com"))` | `.spec.servers[*].hosts[?(@ == "prod.example.com")]` |
748+
| **Overall Performance**<br>(Compilation + Evaluation) | • Average iterations: 3,111 <br> • Average time per operation: **382,914 ns/op** (~383 µs per op) <br> • Standard deviation: ±42,087 ns (±11%) | • Average iterations: 70,542 iterations <br> • Average time per operation: **17,654 ns/op** (~17.7 µs per op) <br> • Standard deviation: ±2,846 ns (±16%) |
749+
| **Compilation Performance** | • Cold Start: 2.340 ms<br><br>• Warmed: 300–400 µs<br>&emsp;◦ Most Expensive / Consistent Phases:<br>&emsp;&emsp;• Env & Cost Estimator: 160–220 µs avg<br>&emsp;&emsp;• CEL Compilation: 60–120 µs avg<br>&emsp;&emsp;• Program Generation: 50–80 µs avg<br><br>• 83% improvement (2.34 ms → ~400 µs)| • Cold Start: ~85 µs<br><br>• Warmed: 5–8 µs<br>&emsp;◦ Most Expensive / Consistent Phases:<br>&emsp;&emsp;• JSONPath Parsing: 4–85 µs (occasional spikes)<br><br>• 90% improvement (85 µs → ~8 µs)|
750+
| **Evaluation Performance** | **FindResults** <br> • Cold: 103.5 µs <br> • Warmed: 13.5 µs <br> • 81% improvement (103.5 → 13.5 µs) <br><br> **PrintResults** <br> • Cold: 3.9 µs <br> • Warmed: 1.5 µs <br> • 70% improvement (3.9 → 1.5 µs) | **FindResults** <br> • Cold: 1.4 µs <br> • Warmed: 0.85 µs <br> • 29% improvement (1.4 → 0.85 µs) <br><br> **PrintResults** <br> • Cold: 0.29 µs <br> • Warmed: 0.18 µs <br> • 58% improvement (0.29 → 0.18 µs) |
751+
752+
</details>
753+
- Scenario 2: Benchmarking evaluation (`findResults()`) performance.
754+
755+
Based on the review comment [here](https://github.com/kubernetes/enhancements/pull/4602#discussion_r2121919813) - `Benchmark an expensive JSON Path additionalPrinterColumns operation (just the part that finds a value using the JSON Path library)`.
756+
<details>
757+
<summary>Details</summary>
758+
<br/>
759+
<p>Run on a resource constraint VM - 11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz, 4 CPU, 4GB RAM, X86_64</p>
760+
<p>Find the raw output of the benchmark tests, as well as the source code: https://gist.github.com/Priyankasaggu11929/43cc9ece4d6215ee4cfe0d1523a919d6</p>
761+
<p>The following table provides an average performance analysis across CEL and JSONPath based additionalPrinterColumns (only for the `findResults()` execution durations across the benchmark test iterations, along with the min, max, avg indexes):</p>
762+
763+
| | CEL ([BenchmarkNew_CEL_DeepComplex](https://gist.github.com/Priyankasaggu11929/43cc9ece4d6215ee4cfe0d1523a919d6#file-tableconvertor_testgo)) | JSONPath ([BenchmarkNew_JSONPath_DeepComplex](https://gist.github.com/Priyankasaggu11929/43cc9ece4d6215ee4cfe0d1523a919d6#file-tableconvertor_testgo)) |
764+
|--------------------------------------|--------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------|
765+
| **Column Definition** | `self.spec.environments.map(e, e.clusters.map(c, c.nodes.filter(n, n.metrics.memory > 8000).map(n, n.id)))` | `.spec.environments[*].clusters[*].nodes[?(@.metrics.memory > 8000)].id` |
766+
| **Evaluation Performance** | **FindResults** <br> • Min: 30.91 µs <br> • Max: 1870.87 µs <br> • Average: 58.38 µs | **FindResults** <br> • Min: 2.19 µs <br> • Max: 1147.24 µs <br> • Average: 8.40 µs |
767+
768+
</details>
776769

770+
_**Conclusion**_
777771

778-
_**Conclusion**_ — Across the 10 runs of the benchmark tests, on average, CEL is 20x slower than JSONPath (383µs vs 18µs).
772+
Overall performance (compilation + evaluation + cost calculation et.al) of CEL across our two scenarios above, is that CEL is about 20x slower than JSONPath.
779773

780-
When running the benchmark tests individually, we observed that CEL was consistently ~20-50x slower than JSONPath.
774+
But since our focus for the performance analysis was to analyze the **evaluation cost** (refer scenario 2):
781775

782-
Based on these current findings, the end users should not find a noticeable difference in the performance when working with CEL for additionalPrinterColumns.
776+
- On average, CEL is about 7x slower than JSONPath (58.38 µs vs 8.40 µs)
777+
- In the worst cases scenario (most expensive run) CEL is 1.5x slower than JSONPath (1870.87 µs vs 1147.24 µs)
783778

784779
<!--
785780
@@ -893,72 +888,10 @@ We will test all cases in integration test and unit test. If needed, we can add
893888

894889
### Graduation Criteria
895890

896-
<!--
897-
**Note:** *Not required until targeted at a release.*
898-
899-
Define graduation milestones.
900-
901-
These may be defined in terms of API maturity, [feature gate] graduations, or as
902-
something else. The KEP should keep this high-level with a focus on what
903-
signals will be looked at to determine graduation.
904-
905-
Consider the following in developing the graduation criteria for this enhancement:
906-
- [Maturity levels (`alpha`, `beta`, `stable`)][maturity-levels]
907-
- [Feature gate][feature gate] lifecycle
908-
- [Deprecation policy][deprecation-policy]
909-
910-
Clearly define what graduation means by either linking to the [API doc
911-
definition](https://kubernetes.io/docs/concepts/overview/kubernetes-api/#api-versioning)
912-
or by redefining what graduation means.
913-
914-
In general we try to use the same stages (alpha, beta, GA), regardless of how the
915-
functionality is accessed.
916-
917-
[feature gate]: https://git.k8s.io/community/contributors/devel/sig-architecture/feature-gates.md
918-
[maturity-levels]: https://git.k8s.io/community/contributors/devel/sig-architecture/api_changes.md#alpha-beta-and-stable-versions
919-
[deprecation-policy]: https://kubernetes.io/docs/reference/using-api/deprecation-policy/
920-
921-
Below are some examples to consider, in addition to the aforementioned [maturity levels][maturity-levels].
922-
923-
#### Alpha
924-
925-
- Feature implemented behind a feature flag
926-
- Initial e2e tests completed and enabled
927-
928-
#### Beta
929-
930-
- Gather feedback from developers and surveys
931-
- Complete features A, B, C
932-
- Additional tests are in Testgrid and linked in KEP
933-
934-
#### GA
935-
936-
- N examples of real-world usage
937-
- N installs
938-
- More rigorous forms of testing—e.g., downgrade tests and scalability tests
939-
- Allowing time for feedback
940-
941-
**Note:** Generally we also wait at least two releases between beta and
942-
GA/stable, because there's no opportunity for user feedback, or even bug reports,
943-
in back-to-back releases.
944-
945-
**For non-optional features moving to GA, the graduation criteria must include
946-
[conformance tests].**
947-
948-
[conformance tests]: https://git.k8s.io/community/contributors/devel/sig-architecture/conformance-tests.md
949-
950-
#### Deprecation
951-
952-
- Announce deprecation and support policy of the existing flag
953-
- Two versions passed since introducing the functionality that deprecates the flag (to address version skew)
954-
- Address feedback on usage/changed behavior, provided on GitHub issues
955-
- Deprecate the flag
956-
-->
957-
958891
#### Alpha
959892

960893
- Feature implemented behind a feature flag
961-
- Initial benchmarks to compare performance of JSONPath with CEL columns and set an appropriate CEL cost
894+
- Initial benchmarks to compare performance of JSONPath with CEL columns and set an appropriate CEL cost (equivalent or at most 2x to the JSONPath cost - as discussed in the [June 11, 2025 SIG API Machinery meeting](https://docs.google.com/document/d/1x9RNaaysyO0gXHIr1y50QFbiL1x8OWnk2v3XnrdkT5Y/edit?tab=t.0#bookmark=id.epfys7yzizcn))
962895
- Unit tests and integration tests completed and enabled
963896

964897
#### Beta

0 commit comments

Comments
 (0)