perf: achieve measured 1:1 standard Perl throughput after #1850
Mantenedores costumam responder em até 1 dia
Ninguém assumiu esta issue ainda.
Avaliação
- Dificuldade
- 5/5
- Tempo estimado
- Mais de uma semana
- Facilidade para iniciantes
- 20/100
- Tipo de issue
- Funcionalidade
- Clareza
- Claramente especificada
- Status de atividade
- Ativa
- Domínio
- performance, testing-qa
Direção de pesquisa
Start with #1846, #1196, and #1850, then inspect the design documents under dev/design/ and the benchmark and test entry points named in those issues or PRs. First establish the durable benchmark baseline and pinned Perl references described here; the recent runner and raw results are only noted as residing under /private/tmp. Done means each fixed workload meets its stated parity criterion, memory use is quantified, regression coverage and the full make gate pass, and reproducible evidence is published.
Escrita pelo modelo de indexação a partir do texto da issue.
Descrição
Goal
Reach at least 1.00x standard Perl throughput on a reproducible portfolio of method calls, closure calls, and bit-packed Life workloads while preserving Perl semantics and controlling memory use. Continue #1846 and #1196 after the focused memory improvements in PR #1850.
Parity must describe the measured workloads and configuration. It does not establish equal performance for every Perl program. Keep #1846 open until its method-call acceptance criterion is met.
Starting point and evidence
PR #1850 is currently open. Its reviewed candidate is 46ca082dacb6991edaf530d36e94749715f286f1, based on master 8bc1c9d1708de1381be6c042d6530c0c318e24f4. Treat this as a candidate baseline until the PR is merged; record the eventual merge commit separately.
The candidate retains four changes:
- Pack method-cache guard keys into one array, removing one array header per code object while retaining the same 32 KiB payload.
- Move rare scalar watcher and live-substring metadata into lazy extension state.
- Prevent shared immutable primitive scalars from retaining their last container, fixing the branch's reproduced retention failure.
- Store common zero- and one-argument JVM method-call arguments in two inline slots, promoting to ordinary storage when needed.
A matched candidate-versus-master method_anchor run on 2026-10-22 produced 1.03685x throughput, or 3.68% faster, across six stable pairs out of seven. The 95% bootstrap interval was 1.02495–1.04924x. All six included pairs favored the candidate; one pair was excluded because the master measurement failed stability. See the measurement report.
This comparison measures improvement over master, not parity with standard Perl. The historical 0.786x system-Perl result in #1846 was a single run on older code and must not be presented as the current gap. Obtain a new stable reference before estimating the remaining work.
Earlier short JFR evidence for the compact argument change estimated roughly 161 to 151 allocated bytes per method call, about 6.6% less. That was sampled evidence from an earlier candidate, not a matched total-memory comparison of the final pruned branch with master. Current peak RSS, live heap, and allocation savings versus master remain unquantified. Passing the full build without heap exhaustion is correctness evidence, not proof of reduced memory use.
Phase 1: establish a durable baseline
- Check in a reproducible runner and workload definitions. The recent matched runner and raw results currently reside under
/private/tmp; local temporary files are not durable review evidence. Recover the corrected stability logic from the preserved pre-prune history as needed, review it independently, and record its source hash. - Pin the standard Perl reference by source revision, configure options, compiler and optimization flags. Preserve #1846's optimized blead comparison as the primary method acceptance reference; also report a pinned stable Perl release so users can interpret the result. Do not silently substitute the installed Perl or compare threaded and unthreaded builds without documenting the difference.
- Record candidate/master source commits and JAR hashes, JDK, JVM flags, heap limits, OS/CPU, environment, workload hashes, commands, checksums, operation counts, and host load. Archive a reproducible Perl build recipe.
- Measure three distinct comparisons: candidate versus its exact parent for attribution, integrated candidate versus master for release value, and integrated candidate versus pinned standard Perl for parity.
- Use deterministic equal work, warmup to stability, balanced randomized launch order, at least seven requested pairs, and confidence intervals calculated over independent pairs. Predeclare stability thresholds, minimum accepted pairs, exclusion rules, and the statistical method; report every attempted pair and rejection. Do not treat windows from one process as independent runs.
- Define a fixed acceptance portfolio before optimization: the original method benchmark, the closure benchmark, and bit-packed Life with rendering disabled. Keep diagnostic variants separate. Ensure results cannot be explained by eliminated work or a changed checksum.
Report throughput, CPU time, elapsed time, allocated bytes per operation, GC time/counts, live heap after equivalent collection points, and peak RSS. Normalize allocation by completed work: allocation per second can rise when a faster program completes more operations. Use identical JVM memory settings for candidate/master comparisons and distinguish Java heap from total process memory.
Phase 2: identify the remaining dominant costs
- Split diagnostics into empty/trivial calls, ordinary direct subroutine calls, method calls, coderef/closure calls, argument aliasing/mutation, scalar/list/void returns, hash-field reads, integer updates, and equivalent inline bodies. Exercise both backends and include observable
caller/argument cases. - Profile the stable acceptance workloads using JFR CPU/allocation/GC evidence and HotSpot inlining/deoptimization evidence. Separate dispatch, frame bookkeeping, argument storage, scalar construction/coercion, and body execution. Report inclusive and exclusive costs.
- Estimate the maximum end-to-end benefit of each proposed change from its measured share. Prioritize costs that explain a material part of the remaining gap across ordinary programs.
Phase 3: implement general call and allocation improvements
The leading hypothesis is that the size and bookkeeping in RuntimeCode.apply() prevent efficient HotSpot inlining even for ordinary calls. A signature check inside the same large method may not address that limitation.
- Separate dispatch resolution from a small ordinary invocation path. Outline uncommon signature, warning, debugger, closure, and exceptional work only where metadata and runtime guards prove that work is unnecessary. Preserve a complete general fallback.
- Preserve required argument, caller, recursion, warning, and return-context behavior on ordinary calls. Generate direct invocation where justified, and verify actual JIT inlining rather than assuming smaller source code guarantees it.
- Guard callee identity and invalidate cached assumptions when subroutines or methods are redefined, including glob assignment. Cover changes during loops, inheritance/MRO changes, lookup and AUTOLOAD behavior, and aliased code references. Compile-time knowledge alone cannot freeze a Perl call target.
- Investigate lazy frame/materialization and scalar/primitive-result allocation only after profiles justify them. Define how observable state is materialized and how escaping values retain valid lifetime and aliasing.
- Evaluate ordinary scalar footprint and cache locality, small argument containers, and unnecessary intermediate arrays/lists. Account for padding, compressed-reference settings, and cold extension overhead. Avoid unbounded caches or pools that trade allocation reductions for retention.
Target ordinary call shapes broadly. Do not restrict the project to bodies containing only literal returns or hashes containing only plain integer cells. Such diagnostics may isolate costs; they do not satisfy the general goal.
Required semantic and memory regression coverage
Add focused permanent tests before each behavior-changing optimization. Validate Perl-level tests with system Perl first; retain failure evidence on the unfixed parent for reproduced regressions, then require JVM and interpreter success.
Coverage must include @_ aliases, mutation and escape; caller, recursion and wantarray; scalar/list/void context and lvalue returns; closures and captured lexical lifetime; named signatures; lexical/dynamic warnings; eval, exceptions and non-local control flow; debugger hooks; tied/overloaded values; dynamic lookup/AUTOLOAD; and glob-based subroutine/method redefinition. Test fallback transitions in the same running program.
Master did not exhibit the branch's heap-exhaustion problem. Treat recurrence as a regression to fix, not a reason to increase the heap or skip the workload. Include repeated calls and escaping/released argument containers under a fixed heap budget, checking bounded live state and collection of released owners. Keep the ownership regression coverage from #1850.
Acceptance and review gates
- For the original method anchor, achieve at least 1.00x pinned optimized blead Perl, with the lower bound of the 95% throughput-ratio interval at least 1.00x, as required by #1846.
- Apply the same criterion to each predeclared portfolio workload before claiming portfolio parity. Publish each result and the portfolio geometric mean; an average must not hide a workload below parity. Report stable-release comparisons separately.
- Quantify allocation, live heap and peak RSS versus master. Demonstrate no unbounded retention or heap exhaustion under the fixed acceptance budget; investigate material memory regressions even if throughput improves.
- Retain optimizations only with reproducible throughput or memory benefit. Keep the tests and correctness fixes required to make those retained changes safe; they do not need independent throughput gains. Document memory/throughput tradeoffs explicitly.
- Pass focused system-Perl/JVM/interpreter checks and the full repository
makegate on the immutable final source commit. Preserve full logs and update the design document underdev/design/, including completed phases and next steps. - Publish raw pair/window data, excluded runs and reasons, environment/build manifests, workload commands, profile summaries and final validation evidence as durable repository or issue/PR artifacts.
Shared-host execution
Bundle related fixes before expensive builds. Reuse verified artifacts when source/JAR hashes match. Run builds with nice -n 19, verify priority changes actually succeed, and wrap every investigative jperl/jcpan/prove run in timeout. Keep benchmark runs sequential, record competing host load, and schedule measurements when the host is quiet. Poll long-running jobs no more often than every ten minutes unless intervention is required. Do not mutate a checkout while its build or validation gate runs.
Related work
- #1846 — method-call throughput parity
- #1196 — closure calls and bit-packed Life
- #1850 — current memory/allocation improvements and regression coverage
- Linguagem predominante
- Perl
- Estrelas
- 64
- Forks
- 8
- Merge médio
- 5h 42min
- PRs com merge (30d)
- 205
Preparar o ambiente
- Inclui um Dockerfile ou arquivo Docker Compose
- Sem modelo de pull request
- Ler o guia de contribuição
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Mais de fglock/PerlOnJava
-
bug
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 72/100
fglock/PerlOnJava#1579 ·
Mantenedores costumam responder em até 1 dia
-
area:memory area:performance area:runtime bug
Dificuldade 4/5 3-5 dias Facilidade para iniciantes 52/100
fglock/PerlOnJava#1860 ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 5/5 Mais de uma semana Facilidade para iniciantes 38/100
fglock/PerlOnJava#1854 ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 3/5 1-2 dias Facilidade para iniciantes 56/100
fglock/PerlOnJava#1851 ·
Mantenedores costumam responder em até 1 dia
-
area:performance enhancement
Dificuldade 5/5 Mais de uma semana Facilidade para iniciantes 25/100
fglock/PerlOnJava#1846 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
Todas as issues de fglock/PerlOnJava
Issues semelhantes
-
observablt-ci
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 86/100
elastic/golang-crossbuild#840 ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 68/100
LMS-Community/slimserver#1701 · 6 comentários ·
Mantenedores costumam responder em até 1 dia
-
bug
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 72/100
RotherOSS/otobo#6286 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 76/100
-
fix(api): API v3 Product Read ignores request language (lc) for sample products and image URLsTalvez já em andamento @muntasir-396 assumiu há 4 dias. Aberta
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 88/100
openfoodfacts/openfoodfacts-server#15042 · 1 comentário ·
Mantenedores costumam responder em até 1 dia