Hi Tigran,

Thanks for your interest on OpenJDK.

I think the timing difference makes sense as the principals are stored in a 
special set inside the subject so subjectByPassingSet adds each twice and the 
subjectByAddingToSet only once. As for why we don't just use the pre-populated 
set as-is since it's already immutable, I think the major reason that we do the 
wrapping here is to make sure the read-only flag is correctly honored and the 
correct type of exception is thrown. I admit there is room for optimization 
when the input is already immutable and the read-only flag is also set, but 
it’s unclear whether the benefit is worth the complexity.

Best regards,
Weijun

> On Jun 25, 2025, at 03:59, Mkrtchyan, Tigran <tigran.mkrtch...@desy.de> wrote:
> 
> 
> Dear security-devs,
> 
> While benchmarking various parts of our code, I noticed unexpected (but fully 
> explainable) behavior of how an instance of the Subject class can be created.
> 
> The intuitive one is to create a set of Principals and then pass it to the 
> constructor. However, it turned out that creating an empty subject and 
> populating it with desire principles is much faster:
> 
> 
>    Benchmark                               Mode  Cnt        Score       Error 
>  Units
>    SubjectBenchmark.subjectByAddingToSet  thrpt    9  2061025.436 ± 24807.881 
>  ops/s
>    SubjectBenchmark.subjectByPassingSet   thrpt    9  1341492.178 ± 34701.882 
>  ops/s
> 
> 
> The reason is that the Subject class performs extra checks on the provided 
> set, which first creates a null-clean LinkedList copy of the collection. 
> Makes sense.
> However, `Set#of` returns immutable, null clean sets, so there is no reason 
> for an extra copy.
> 
> 
> Best regards,
>   Tigran.
> 
> 
> The benchmark code:
> 
> ```
> @BenchmarkMode(Mode.Throughput)
> @State(Scope.Benchmark)
> public class SubjectBenchmark {
> 
> 
>    @Benchmark
>    public Subject subjectByAddingToSet() {
>        Subject subject = new Subject();
>        subject.getPrincipals().add(new UnixNumericUserPrincipal(0));
>        subject.getPrincipals().add(new UnixNumericGroupPrincipal(0, true));
>        subject.getPrincipals().add(new UnixNumericGroupPrincipal(1, false));
>        subject.getPrincipals().add(new UnixNumericGroupPrincipal(2, false));
>        subject.getPrincipals().add(new UnixNumericGroupPrincipal(3, false));
>        subject.getPrincipals().add(new UnixNumericGroupPrincipal(4, false));
>        subject.getPrincipals().add(new UnixNumericGroupPrincipal(5, false));
>        subject.getPrincipals().add(new UnixNumericGroupPrincipal(6, false));
>        subject.setReadOnly();
>        return subject;
>    }
> 
> 
>    @Benchmark
>    public Subject subjectByPassingSet() {
> 
>        Principal[] principals = new Principal[]{
>              new UnixNumericUserPrincipal(0),
>              new UnixNumericGroupPrincipal(0, true),
>              new UnixNumericGroupPrincipal(1, false),
>              new UnixNumericGroupPrincipal(2, false),
>              new UnixNumericGroupPrincipal(3, false),
>              new UnixNumericGroupPrincipal(4, false),
>              new UnixNumericGroupPrincipal(5, false),
>              new UnixNumericGroupPrincipal(6, false)
>        };
> 
>        return new Subject(true, Set.of(principals), Set.of(), Set.of());
>    }
> }
> ```


Reply via email to