Skip to content

perf(policy): add fast paths to AdminAction.IsValid and HasResource - #11

Merged
Vonng merged 1 commit into
pgsty:mainfrom
botdeniska:perf/admin-action-fast-path
Oct 17, 2026
Merged

Vonng merged 1 commit into
pgsty:mainfrom
botdeniska:perf/admin-action-fast-path

Conversation

@botdeniska

Copy link
Copy Markdown

Contribution Licensing (no CLA, inbound=outbound, DCO required)

This pull request contributes to PGSTY SILO Shared Packages (pgsty/silo-pkg).
Code contributions are accepted under
GNU AGPL v3.0 or later
(AGPL-3.0-or-later), the same license as this package.
By submitting this pull request I represent that I have the right to contribute
the changes under that license and retain copyright in my original work.
No CLA, copyright assignment, or separate Apache-2.0 license grant is required.
Existing copyright and license notices remain intact; separately licensed
material keeps its applicable terms. Every commit must carry a DCO
Signed-off-by trailer (git commit -s); see
CONTRIBUTING.md.

Description and motivation

For every statement whose actions match the request, Statement.IsAllowedPtr
calls isAdmin() and hasAdminResource(). These run AdminAction.IsValid()
and HasResource() on each action, and both scanned the whole admin action map
with wildcard.Match. That is about 100 matches per action just to learn that
s3:GetObject is not an admin action. The scan has been on the per-request
path since 8c45d07 (wildcard admin actions, inherited from minio/pkg).

Take a user with 1000 s3:GetObject/s3:PutObject statements on different
buckets, with the matching grant last. Policy.IsAllowed takes 1.7 ms for that
user, and 71% of the CPU goes to AdminAction.IsValid.

This ports the fast path from
minio/pkg#261 by @klauspost. #4
already took the wildcard part of that PR. The fast path:

  • tries an exact map lookup first;
  • stops there for a pattern without * or ?;
  • in IsValid, also stops when the text before the first wildcard cannot agree
    with admin:. The check works both ways, so adm* and a*d*m*i*n* stay
    valid.

Patterns that can still match go through the old scan, so no result changes.
TestAdminActionNamespacePrefix pins the admin: invariant that the fast
path relies on.

I left out the rest of the performance part of minio#261 to keep this PR
small. That covers the cached statement classification, the action index fix
and building the resource string once per request. I can send it as a
follow-up.

Test changes:

  • policy/admin-action_test.go is adapted from Fix policy validation & improve speed minio/pkg#261. It has trap
    tables, an equivalence check against the old scan over 921 patterns, a fuzz
    target and the prefix invariant.
  • BenchmarkIsAllowed gets a ManyBucketGrants scenario. In it, every
    statement matches the action but not the bucket, which no existing scenario
    covers.

Validation

  • make test passes: lint reports 0 issues, and go test -race -tags kqueue ./...
    is green. go mod tidy -diff and git diff --check are clean.
  • FuzzAdminActionIsValid ran for 60s: 10.7M executions, no divergence.
  • I compared v3.14.2 and this branch locally on 800k random policies and random
    requests. The policies mix Allow/Deny, NotAction, NotResource, conditions,
    and s3/admin/sts/kms actions with wildcards. Both versions accept and reject
    the same policies in ParseConfig, and ~6M IsAllowed decisions match,
    including on merged policies. This check is not committed.
  • If the two-way prefix check is replaced with a plain HasPrefix, both the
    new tests and the local comparison fail.

Benchmarks were run on an Apple M4 Pro, alternating the old and new binaries
for 10 rounds. The change adds no allocations. BDP/1x1000/... is an
out-of-tree benchmark of the 1000-statement case above.

                                                          │    v3.14.2    │               this-PR                │
                                                          │    sec/op     │    sec/op     vs base                │
IsAllowed/SingleStatementAllow-12                           1922.0n ±  4%   516.2n ±  3%  -73.14% (p=0.000 n=10)
IsAllowed/MultipleStatements-12                              6.303µ ±  2%   4.780µ ±  2%  -24.17% (p=0.000 n=10)
IsAllowed/ManyBucketGrants-12                               350.79µ ±  5%   60.96µ ±  2%  -82.62% (p=0.000 n=10)
IsAllowed/DenyRule-12                                       2887.5n ±  2%   768.6n ±  1%  -73.38% (p=0.000 n=10)
IsAllowed/WildcardMatching-12                                958.9n ±  2%   255.9n ±  2%  -73.32% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_5_128p_10a/SerialEval-12       1691.4µ ±  6%   336.9µ ±  1%  -80.08% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_7_1024p_10a/SerialEval-12      13.472m ±  2%   2.725m ±  8%  -79.77% (p=0.000 n=10)
BDP/1x1000/s3:GetObject/isallowed-12                        1705.4µ ±  3%   295.3µ ±  4%  -82.69% (p=0.000 n=10)
BDP/1x1000/s3:Get*/isallowed-12                             3457.3µ ±  4%   584.4µ ±  4%  -83.10% (p=0.000 n=10)
Full benchstat output
goos: darwin
goarch: arm64
pkg: github.com/pgsty/silo-pkg/v3/policy
cpu: Apple M4 Pro
                                                          │    v3.14.2    │               this-PR                │
                                                          │    sec/op     │    sec/op     vs base                │
IsAllowed/SingleStatementAllow-12                           1922.0n ±  4%   516.2n ±  3%  -73.14% (p=0.000 n=10)
IsAllowed/MultipleStatements-12                              6.303µ ±  2%   4.780µ ±  2%  -24.17% (p=0.000 n=10)
IsAllowed/ManyBucketGrants-12                               350.79µ ±  5%   60.96µ ±  2%  -82.62% (p=0.000 n=10)
IsAllowed/DenyRule-12                                       2887.5n ±  2%   768.6n ±  1%  -73.38% (p=0.000 n=10)
IsAllowed/WildcardMatching-12                                958.9n ±  2%   255.9n ±  2%  -73.32% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_0_1p_10a/ParallelEval-12        1.255µ ±  2%   1.256µ ±  1%        ~ (p=0.643 n=10)
SerialEvalVsParEval/TestCase_0_1p_10a/SerialEval-12          961.5n ±  3%   960.0n ±  1%        ~ (p=0.617 n=10)
SerialEvalVsParEval/TestCase_1_2p_10a/ParallelEval-12        42.94µ ±  7%   16.83µ ± 11%  -60.81% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_1_2p_10a/SerialEval-12         26.640µ ±  4%   5.173µ ±  1%  -80.58% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_2_4p_10a/ParallelEval-12        73.53µ ±  2%   22.86µ ±  7%  -68.91% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_2_4p_10a/SerialEval-12          52.38µ ±  3%   10.31µ ±  3%  -80.32% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_3_8p_10a/ParallelEval-12       130.31µ ±  5%   37.78µ ±  2%  -71.01% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_3_8p_10a/SerialEval-12         106.27µ ±  3%   20.52µ ±  5%  -80.70% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_4_64p_10a/ParallelEval-12       426.5µ ±  5%   140.5µ ±  7%  -67.05% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_4_64p_10a/SerialEval-12         841.1µ ±  3%   163.8µ ±  2%  -80.53% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_5_128p_10a/ParallelEval-12      675.0µ ±  2%   228.6µ ±  2%  -66.13% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_5_128p_10a/SerialEval-12       1691.4µ ±  6%   336.9µ ±  1%  -80.08% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_6_512p_10a/ParallelEval-12     1432.9µ ± 16%   477.4µ ±  4%  -66.68% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_6_512p_10a/SerialEval-12        6.751m ±  4%   1.349m ±  3%  -80.01% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_7_1024p_10a/ParallelEval-12    2433.7µ ± 10%   790.4µ ±  9%  -67.52% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_7_1024p_10a/SerialEval-12      13.472m ±  2%   2.725m ±  8%  -79.77% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_8_4096p_10a/ParallelEval-12     7.396m ± 17%   2.371m ±  6%  -67.94% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_8_4096p_10a/SerialEval-12       54.10m ±  2%   10.97m ±  2%  -79.72% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_9_16384p_10a/ParallelEval-12   27.727m ±  6%   7.742m ±  5%  -72.08% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_9_16384p_10a/SerialEval-12     219.17m ±  3%   44.10m ±  3%  -79.88% (p=0.000 n=10)
BDP/1x100/s3:GetObject/merge-12                              2.791n ±  2%   2.807n ±  0%        ~ (p=0.085 n=10)
BDP/1x100/s3:GetObject/isallowed-12                         166.07µ ±  6%   28.60µ ±  2%  -82.78% (p=0.000 n=10)
BDP/1x100/s3:GetObject/merge+isallowed-12                   169.94µ ±  5%   28.47µ ±  2%  -83.25% (p=0.000 n=10)
BDP/1x100/s3:Get*/merge-12                                   2.603n ±  0%   2.620n ±  1%   +0.67% (p=0.005 n=10)
BDP/1x100/s3:Get*/isallowed-12                              335.18µ ±  4%   55.23µ ±  7%  -83.52% (p=0.000 n=10)
BDP/1x100/s3:Get*/merge+isallowed-12                        338.31µ ±  2%   55.18µ ±  5%  -83.69% (p=0.000 n=10)
BDP/3x30/s3:GetObject/merge-12                               20.88µ ±  2%   20.92µ ±  2%        ~ (p=0.912 n=10)
BDP/3x30/s3:GetObject/isallowed-12                          152.54µ ±  3%   24.99µ ±  4%  -83.61% (p=0.000 n=10)
BDP/3x30/s3:GetObject/merge+isallowed-12                    174.33µ ±  4%   46.89µ ± 21%  -73.10% (p=0.000 n=10)
BDP/3x30/s3:Get*/merge-12                                    20.75µ ±  3%   21.06µ ±  6%        ~ (p=0.190 n=10)
BDP/3x30/s3:Get*/isallowed-12                               301.82µ ±  3%   50.55µ ±  4%  -83.25% (p=0.000 n=10)
BDP/3x30/s3:Get*/merge+isallowed-12                         324.29µ ±  4%   71.79µ ±  2%  -77.86% (p=0.000 n=10)
BDP/10x100/s3:GetObject/merge-12                             244.5µ ±  3%   241.3µ ± 11%        ~ (p=0.190 n=10)
BDP/10x100/s3:GetObject/isallowed-12                        1689.6µ ±  2%   301.2µ ±  5%  -82.17% (p=0.000 n=10)
BDP/10x100/s3:GetObject/merge+isallowed-12                  1965.4µ ±  2%   540.6µ ± 12%  -72.49% (p=0.000 n=10)
BDP/10x100/s3:Get*/merge-12                                  241.9µ ±  1%   242.4µ ± 14%        ~ (p=0.684 n=10)
BDP/10x100/s3:Get*/isallowed-12                             3424.4µ ±  3%   592.7µ ± 12%  -82.69% (p=0.000 n=10)
BDP/10x100/s3:Get*/merge+isallowed-12                       3684.2µ ±  2%   838.0µ ±  8%  -77.26% (p=0.000 n=10)
BDP/1x1000/s3:GetObject/merge-12                             2.782n ± 10%   2.533n ± 10%        ~ (p=0.271 n=10)
BDP/1x1000/s3:GetObject/isallowed-12                        1705.4µ ±  3%   295.3µ ±  4%  -82.69% (p=0.000 n=10)
BDP/1x1000/s3:GetObject/merge+isallowed-12                  1689.8µ ±  2%   296.2µ ±  6%  -82.47% (p=0.000 n=10)
BDP/1x1000/s3:Get*/merge-12                                  2.635n ±  5%   2.771n ±  5%   +5.18% (p=0.005 n=10)
BDP/1x1000/s3:Get*/isallowed-12                             3457.3µ ±  4%   584.4µ ±  4%  -83.10% (p=0.000 n=10)
BDP/1x1000/s3:Get*/merge+isallowed-12                       3393.0µ ±  2%   587.2µ ±  4%  -82.69% (p=0.000 n=10)
BDP/3x333/s3:GetObject/merge-12                              241.2µ ±  4%   241.5µ ±  2%        ~ (p=0.971 n=10)
BDP/3x333/s3:GetObject/isallowed-12                         1688.3µ ±  2%   297.5µ ±  2%  -82.38% (p=0.000 n=10)
BDP/3x333/s3:GetObject/merge+isallowed-12                   1956.6µ ±  2%   543.8µ ±  2%  -72.21% (p=0.000 n=10)
BDP/3x333/s3:Get*/merge-12                                   241.8µ ±  1%   241.4µ ±  4%        ~ (p=0.853 n=10)
BDP/3x333/s3:Get*/isallowed-12                              3409.1µ ±  3%   593.8µ ±  3%  -82.58% (p=0.000 n=10)
BDP/3x333/s3:Get*/merge+isallowed-12                        3657.2µ ±  4%   851.0µ ± 11%  -76.73% (p=0.000 n=10)
geomean                                                      158.6µ         49.71µ        -68.67%

                                                          │     v3.14.2     │                   this-PR                   │
                                                          │      B/op       │      B/op       vs base                     │
IsAllowed/SingleStatementAllow-12                             0.000 ±  0%       0.000 ±   0%         ~ (p=1.000 n=10) ¹
IsAllowed/MultipleStatements-12                               0.000 ±  0%       0.000 ±   0%         ~ (p=1.000 n=10) ¹
IsAllowed/ManyBucketGrants-12                                 1.000 ±  0%       0.000 ±   0%  -100.00% (p=0.000 n=10)
IsAllowed/DenyRule-12                                         0.000 ±  0%       0.000 ±   0%         ~ (p=1.000 n=10) ¹
IsAllowed/WildcardMatching-12                                 0.000 ±  0%       0.000 ±   0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_0_1p_10a/ParallelEval-12       1.406Ki ±  0%     1.406Ki ±   0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_0_1p_10a/SerialEval-12           0.000 ±  0%       0.000 ±   0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_1_2p_10a/ParallelEval-12       6.875Ki ±  0%     6.875Ki ±   0%         ~ (p=0.474 n=10)
SerialEvalVsParEval/TestCase_1_2p_10a/SerialEval-12           0.000 ±  0%       0.000 ±   0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_2_4p_10a/ParallelEval-12       6.875Ki ±  0%     6.875Ki ±   0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_2_4p_10a/SerialEval-12           0.000 ±  0%       0.000 ±   0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_3_8p_10a/ParallelEval-12       6.875Ki ±  0%     6.875Ki ±   0%         ~ (p=1.000 n=10)
SerialEvalVsParEval/TestCase_3_8p_10a/SerialEval-12           0.000 ±  0%       0.000 ±   0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_4_64p_10a/ParallelEval-12      9.091Ki ±  0%     9.079Ki ±   0%    -0.13% (p=0.010 n=10)
SerialEvalVsParEval/TestCase_4_64p_10a/SerialEval-12          2.000 ±  0%       0.000 ±   0%  -100.00% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_5_128p_10a/ParallelEval-12     12.22Ki ±  0%     12.20Ki ±   0%    -0.19% (p=0.003 n=10)
SerialEvalVsParEval/TestCase_5_128p_10a/SerialEval-12         5.000 ±  0%       1.000 ±   0%   -80.00% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_6_512p_10a/ParallelEval-12     22.07Ki ±  0%     22.05Ki ±   0%    -0.06% (p=0.045 n=10)
SerialEvalVsParEval/TestCase_6_512p_10a/SerialEval-12        21.000 ±  5%       4.000 ±   0%   -80.95% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_7_1024p_10a/ParallelEval-12    28.60Ki ±  0%     28.61Ki ±   0%         ~ (p=0.927 n=10)
SerialEvalVsParEval/TestCase_7_1024p_10a/SerialEval-12       44.000 ±  5%       8.000 ±  12%   -81.82% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_8_4096p_10a/ParallelEval-12    75.49Ki ±  0%     75.48Ki ±   0%    -0.02% (p=0.001 n=10)
SerialEvalVsParEval/TestCase_8_4096p_10a/SerialEval-12       191.00 ±  0%       36.00 ±  11%   -81.15% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_9_16384p_10a/ParallelEval-12   245.5Ki ±  0%     245.5Ki ±   0%    -0.02% (p=0.000 n=10)
SerialEvalVsParEval/TestCase_9_16384p_10a/SerialEval-12       637.0 ±  0%       155.0 ±   6%   -75.67% (p=0.000 n=10)
BDP/1x100/s3:GetObject/merge-12                               0.000 ±  0%       0.000 ±   0%         ~ (p=1.000 n=10) ¹
BDP/1x100/s3:GetObject/isallowed-12                           0.000 ±  0%       0.000 ±   0%         ~ (p=1.000 n=10) ¹
BDP/1x100/s3:GetObject/merge+isallowed-12                     0.000 ±  0%       0.000 ±   0%         ~ (p=1.000 n=10) ¹
BDP/1x100/s3:Get*/merge-12                                    0.000 ±  0%       0.000 ±   0%         ~ (p=1.000 n=10) ¹
BDP/1x100/s3:Get*/isallowed-12                                1.000 ±  0%       0.000 ±   0%  -100.00% (p=0.000 n=10)
BDP/1x100/s3:Get*/merge+isallowed-12                          1.000 ±  0%       0.000 ±   0%  -100.00% (p=0.000 n=10)
BDP/3x30/s3:GetObject/merge-12                              19.61Ki ±  0%     19.61Ki ±   0%         ~ (p=1.000 n=10) ¹
BDP/3x30/s3:GetObject/isallowed-12                            0.000 ±  0%       0.000 ±   0%         ~ (p=1.000 n=10) ¹
BDP/3x30/s3:GetObject/merge+isallowed-12                    19.62Ki ±  0%     19.62Ki ±   0%     0.00% (p=0.033 n=10)
BDP/3x30/s3:Get*/merge-12                                   19.61Ki ±  0%     19.61Ki ±   0%         ~ (p=1.000 n=10) ¹
BDP/3x30/s3:Get*/isallowed-12                                 0.000 ±   ?       0.000 ±   0%         ~ (p=0.087 n=10)
BDP/3x30/s3:Get*/merge+isallowed-12                         19.62Ki ±  0%     19.62Ki ±   0%         ~ (p=0.474 n=10)
BDP/10x100/s3:GetObject/merge-12                            269.4Ki ±  0%     269.4Ki ±   0%         ~ (p=0.105 n=10)
BDP/10x100/s3:GetObject/isallowed-12                          5.000 ±  0%       0.000 ±   0%  -100.00% (p=0.000 n=10)
BDP/10x100/s3:GetObject/merge+isallowed-12                  269.7Ki ±  0%     269.7Ki ±   0%         ~ (p=0.181 n=10)
BDP/10x100/s3:Get*/merge-12                                 269.4Ki ±  0%     269.4Ki ±   0%         ~ (p=0.154 n=10)
BDP/10x100/s3:Get*/isallowed-12                              10.000 ±  0%       1.000 ± 100%   -90.00% (p=0.000 n=10)
BDP/10x100/s3:Get*/merge+isallowed-12                       269.7Ki ±  0%     269.7Ki ±   0%    -0.00% (p=0.005 n=10)
BDP/1x1000/s3:GetObject/merge-12                              0.000 ±  0%       0.000 ±   0%         ~ (p=1.000 n=10) ¹
BDP/1x1000/s3:GetObject/isallowed-12                          5.000 ±  0%       0.000 ±   0%  -100.00% (p=0.000 n=10)
BDP/1x1000/s3:GetObject/merge+isallowed-12                    5.000 ±  0%       0.000 ±   0%  -100.00% (p=0.000 n=10)
BDP/1x1000/s3:Get*/merge-12                                   0.000 ±  0%       0.000 ±   0%         ~ (p=1.000 n=10) ¹
BDP/1x1000/s3:Get*/isallowed-12                              10.000 ± 10%       1.000 ±   0%   -90.00% (p=0.000 n=10)
BDP/1x1000/s3:Get*/merge+isallowed-12                        10.000 ± 10%       1.000 ± 100%   -90.00% (p=0.000 n=10)
BDP/3x333/s3:GetObject/merge-12                             269.4Ki ±  0%     269.4Ki ±   0%         ~ (p=0.070 n=10)
BDP/3x333/s3:GetObject/isallowed-12                           5.000 ±  0%       0.000 ±   0%  -100.00% (p=0.000 n=10)
BDP/3x333/s3:GetObject/merge+isallowed-12                   269.7Ki ±  0%     269.7Ki ±   0%    -0.00% (p=0.044 n=10)
BDP/3x333/s3:Get*/merge-12                                  269.4Ki ±  0%     269.4Ki ±   0%         ~ (p=0.120 n=10)
BDP/3x333/s3:Get*/isallowed-12                               10.000 ± 10%       1.000 ± 100%   -90.00% (p=0.000 n=10)
BDP/3x333/s3:Get*/merge+isallowed-12                        269.7Ki ±  0%     269.7Ki ±   0%    -0.00% (p=0.006 n=10)
geomean                                                                   ²                   ?                       ² ³
¹ all samples are equal
² summaries must be >0 to compute geomean
³ ratios must be >0 to compute geomean

                                                          │   v3.14.2    │                 this-PR                 │
                                                          │  allocs/op   │ allocs/op   vs base                     │
IsAllowed/SingleStatementAllow-12                           0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
IsAllowed/MultipleStatements-12                             0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
IsAllowed/ManyBucketGrants-12                               0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
IsAllowed/DenyRule-12                                       0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
IsAllowed/WildcardMatching-12                               0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_0_1p_10a/ParallelEval-12       10.00 ± 0%     10.00 ± 0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_0_1p_10a/SerialEval-12         0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_1_2p_10a/ParallelEval-12       80.00 ± 0%     80.00 ± 0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_1_2p_10a/SerialEval-12         0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_2_4p_10a/ParallelEval-12       80.00 ± 0%     80.00 ± 0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_2_4p_10a/SerialEval-12         0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_3_8p_10a/ParallelEval-12       80.00 ± 0%     80.00 ± 0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_3_8p_10a/SerialEval-12         0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_4_64p_10a/ParallelEval-12      100.0 ± 0%     100.0 ± 0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_4_64p_10a/SerialEval-12        0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_5_128p_10a/ParallelEval-12     130.0 ± 0%     130.0 ± 0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_5_128p_10a/SerialEval-12       0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_6_512p_10a/ParallelEval-12     190.0 ± 0%     190.0 ± 0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_6_512p_10a/SerialEval-12       0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_7_1024p_10a/ParallelEval-12    190.0 ± 0%     190.0 ± 0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_7_1024p_10a/SerialEval-12      0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_8_4096p_10a/ParallelEval-12    190.0 ± 0%     190.0 ± 0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_8_4096p_10a/SerialEval-12      0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_9_16384p_10a/ParallelEval-12   190.0 ± 0%     190.0 ± 0%         ~ (p=1.000 n=10) ¹
SerialEvalVsParEval/TestCase_9_16384p_10a/SerialEval-12     1.000 ± 0%     0.000 ± 0%  -100.00% (p=0.000 n=10)
BDP/1x100/s3:GetObject/merge-12                             0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
BDP/1x100/s3:GetObject/isallowed-12                         0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
BDP/1x100/s3:GetObject/merge+isallowed-12                   0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
BDP/1x100/s3:Get*/merge-12                                  0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
BDP/1x100/s3:Get*/isallowed-12                              0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
BDP/1x100/s3:Get*/merge+isallowed-12                        0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
BDP/3x30/s3:GetObject/merge-12                              24.00 ± 0%     24.00 ± 0%         ~ (p=1.000 n=10) ¹
BDP/3x30/s3:GetObject/isallowed-12                          0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
BDP/3x30/s3:GetObject/merge+isallowed-12                    24.00 ± 0%     24.00 ± 0%         ~ (p=1.000 n=10) ¹
BDP/3x30/s3:Get*/merge-12                                   24.00 ± 0%     24.00 ± 0%         ~ (p=1.000 n=10) ¹
BDP/3x30/s3:Get*/isallowed-12                               0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
BDP/3x30/s3:Get*/merge+isallowed-12                         24.00 ± 0%     24.00 ± 0%         ~ (p=1.000 n=10) ¹
BDP/10x100/s3:GetObject/merge-12                            36.00 ± 0%     36.00 ± 0%         ~ (p=1.000 n=10) ¹
BDP/10x100/s3:GetObject/isallowed-12                        0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
BDP/10x100/s3:GetObject/merge+isallowed-12                  36.00 ± 0%     36.00 ± 0%         ~ (p=1.000 n=10) ¹
BDP/10x100/s3:Get*/merge-12                                 36.00 ± 0%     36.00 ± 0%         ~ (p=1.000 n=10) ¹
BDP/10x100/s3:Get*/isallowed-12                             0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
BDP/10x100/s3:Get*/merge+isallowed-12                       36.00 ± 0%     36.00 ± 0%         ~ (p=1.000 n=10) ¹
BDP/1x1000/s3:GetObject/merge-12                            0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
BDP/1x1000/s3:GetObject/isallowed-12                        0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
BDP/1x1000/s3:GetObject/merge+isallowed-12                  0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
BDP/1x1000/s3:Get*/merge-12                                 0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
BDP/1x1000/s3:Get*/isallowed-12                             0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
BDP/1x1000/s3:Get*/merge+isallowed-12                       0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
BDP/3x333/s3:GetObject/merge-12                             36.00 ± 0%     36.00 ± 0%         ~ (p=1.000 n=10) ¹
BDP/3x333/s3:GetObject/isallowed-12                         0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
BDP/3x333/s3:GetObject/merge+isallowed-12                   36.00 ± 0%     36.00 ± 0%         ~ (p=1.000 n=10) ¹
BDP/3x333/s3:Get*/merge-12                                  36.00 ± 0%     36.00 ± 0%         ~ (p=1.000 n=10) ¹
BDP/3x333/s3:Get*/isallowed-12                              0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
BDP/3x333/s3:Get*/merge+isallowed-12                        36.00 ± 0%     36.00 ± 0%         ~ (p=1.000 n=10) ¹
geomean                                                                ²               ?                       ² ³
¹ all samples are equal
² summaries must be >0 to compute geomean
³ ratios must be >0 to compute geomean

Downstream impact

None. There is no API or behaviour change; the server, Console and mcli pick
this up with the next release.

Checklist

  • All commits are signed off (git commit -s) per the DCO
  • Relevant tests and checks pass
  • Breaking changes coordinated with affected SILO components (none)
  • Public documentation update opened in pgsty/silo.pgsty.com, if needed (not needed)

Co-authored-by: Klaus Post <klauspost@gmail.com>
Signed-off-by: Denis Babchuk <babchukdenis@icloud.com>
@Vonng

Vonng commented Oct 17, 2026

Copy link
Copy Markdown
Member

Thanks, @botdeniska, for the focused optimization and careful regression coverage, and @klauspost for the original work.

We independently reproduced the performance improvement: about 82% less evaluation time in the many-bucket benchmark, with no extra allocations. Full race tests, fuzzing, and a second comparison of 50,000 policies found no behavior differences. Integration checks with the published mcli also matched the v3.14.2 baseline. CI is green on Go 1.26 and 1.27, including LDAP and vulnerability checks.

Merging this for silo-pkg v3.14.3. Thanks for the contribution!

@Vonng
Vonng merged commit 907903b into pgsty:main Oct 17, 2026
4 checks passed
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.

2 participants