Skip to content

docs: memoryUsage() documentation and memory patterns benchmark#47

Merged
orieg merged 2 commits intomainfrom
docs/memory-patterns
Feb 28, 2026
Merged

docs: memoryUsage() documentation and memory patterns benchmark#47
orieg merged 2 commits intomainfrom
docs/memory-patterns

Conversation

@orieg
Copy link
Owner

@orieg orieg commented Feb 28, 2026

Summary

  • Add "Understanding Judy::memoryUsage()" section to BENCHMARK.md — documents return values per type (int for BITSET/INT_TO_INT/INT_TO_MIXED, NULL for STRING types), explains the internal O(1) mechanism (JPM TotalMemWords counter), and provides guidance on when Judy saves memory vs when PHP arrays win
  • Add examples/judy-bench-memory-patterns.php — benchmark script comparing Judy vs PHP arrays at 1K–1M elements for INT_TO_INT, BITSET, and STRING_TO_INT insertion throughput, with sparse key memory comparison
  • Documents why STRING_TO_* types return NULL (no JudySLMemUsed macro in the C library)
  • Documents that JudySL uses C malloc (invisible to PHP's memory_get_usage())

Phase 2 of the plan from #43.

Test plan

  • Benchmark script runs without errors: php examples/judy-bench-memory-patterns.php
  • All 118 existing tests pass
  • pecl package package.xml produces valid .tgz
  • CI matrix (Linux + Windows, PHP 8.1-8.5) passes

Add a new section to BENCHMARK.md documenting Judy::memoryUsage() behavior
per type (which types return int vs NULL, why, and how it works internally).
Include guidance on when Judy saves memory vs when PHP arrays win, with
concrete examples for sparse keys, dense counters, and bitset tracking.

Add examples/judy-bench-memory-patterns.php benchmark script comparing Judy
vs PHP arrays for memory footprint at 1K-1M elements (INT_TO_INT, BITSET),
insertion throughput, and sparse key scenarios.
@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves the understanding of Judy array memory management by providing detailed documentation for the Judy::memoryUsage() method and introducing a new benchmark script. The new benchmark allows users to directly compare the memory consumption and insertion performance of Judy arrays against native PHP arrays under various conditions, helping users make informed decisions about when to leverage Judy for memory optimization.

Highlights

  • Enhanced Judy::memoryUsage() Documentation: Added a comprehensive section to BENCHMARK.md detailing the behavior of Judy::memoryUsage() across different Judy types, explaining its internal O(1) mechanism, and providing guidance on memory efficiency comparisons with PHP arrays.
  • New Memory Patterns Benchmark Script: Introduced examples/judy-bench-memory-patterns.php, a new benchmark script that compares Judy arrays (INT_TO_INT, BITSET, STRING_TO_INT) against native PHP arrays for memory footprint and insertion throughput across various dataset sizes, including sparse key scenarios.
  • Clarification on STRING_TO_* Memory Reporting: Documented why Judy::memoryUsage() returns NULL for STRING_TO_* types (due to the absence of a JudySLMemUsed macro in the C library) and noted that JudySL uses C malloc, which is invisible to PHP's memory_get_usage().
  • Updated Benchmark Instructions: The BENCHMARK.md file was updated to include instructions for running the newly added memory patterns benchmark.
Changelog
  • BENCHMARK.md
    • Added a new section 'Understanding Judy::memoryUsage()' with detailed explanations of return values by type, internal workings, and scenarios where Judy or PHP arrays are more memory-efficient.
    • Updated the 'Running the Benchmarks' section to include the new judy-bench-memory-patterns.php script.
  • examples/judy-bench-memory-patterns.php
    • Added a new PHP script to benchmark Judy array memory usage patterns and insertion throughput against PHP arrays for INT_TO_INT, BITSET, and STRING_TO_INT types.
  • package.xml
    • Included the new examples/judy-bench-memory-patterns.php file in the package manifest.
Activity
  • The author, orieg, is implementing 'Phase 2 of the plan from [Proposal] Advanced Performance: Batching, Atomics, and GC Optimization #43', indicating a structured approach to feature development.
  • A detailed test plan is outlined in the PR description, covering benchmark script execution, existing test suite pass, package validity, and CI matrix checks, suggesting thorough validation is intended.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions
Copy link

github-actions bot commented Feb 28, 2026

Test Results

PHP Platform Arch TS Tests Pass Fail Skip Duration
8.1 Linux x64 - 114 114 0 0 0.9s
8.2 Linux x64 - 114 114 0 0 1.2s
8.3 Linux x64 - 114 114 0 0 1.2s
8.4 Linux x64 - 114 114 0 0 1.2s
8.5 Linux x64 - 114 114 0 0 1.3s
8.1 Windows x64 nts 114 114 0 0 6.3s
8.2 Windows x64 nts 114 114 0 0 5.4s
8.3 Windows x64 nts 114 114 0 0 5.4s
8.4 Windows x64 nts 114 114 0 0 5.4s
8.5 Windows x64 nts 114 114 0 0 5.5s
Total 1140 1140 0 0

Benchmark Summary (Judy vs PHP Array)

Ratio = Judy / Array. Bold = Judy wins (≤0.95x). Plain = Array is faster/smaller.

Time (Write / Read) — Linux

Scenario PHP 8.1 PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
Sparse Int 100K 3.1x / 2.6x 3.0x / 2.8x 3.1x / 2.6x 2.9x / 2.8x 3.0x / 2.7x
Sparse Int 500K 3.6x / 2.8x 4.1x / 2.5x 3.5x / 3.1x 3.7x / 5.0x 3.4x / 2.8x
Sparse Int 1M 3.5x / 2.2x 3.4x / 2.9x 3.3x / 2.3x 3.7x / 3.5x 3.6x / 2.6x
Sparse Int 10M 2.2x / 2.5x 1.8x / 2.3x 2.0x / 2.5x 2.0x / 2.8x 2.0x / 2.5x
String 100K 3.1x / 3.2x 2.6x / 4.0x 2.2x / 2.5x 2.9x / 3.4x 2.8x / 3.7x
String 500K 2.3x / 2.3x 2.5x / 2.3x 2.3x / 2.1x 3.0x / 3.0x 2.5x / 2.6x
String 1M 2.5x / 2.3x 2.3x / 1.6x 2.5x / 2.0x 3.1x / 2.3x 2.8x / 2.3x
String 10M 2.7x / 2.3x 2.6x / 2.3x 2.8x / 2.5x 2.9x / 2.4x 2.7x / 2.3x

Memory — Linux

Scenario PHP 8.1 PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
Sparse Int 100K 0.26x 0.26x 0.26x 0.26x 0.26x
Sparse Int 500K 0.46x 0.46x 0.46x 0.46x 0.46x
Sparse Int 1M 0.46x 0.46x 0.46x 0.46x 0.46x
Sparse Int 10M 0.29x 0.29x 0.29x 0.29x 0.29x
String 100K 0.61x 0.61x 0.61x 0.61x 0.61x
String 500K 0.76x 0.76x 0.76x 0.76x 0.76x
String 1M 0.76x 0.76x 0.76x 0.76x 0.76x
String 10M 0.48x 0.48x 0.48x 0.48x 0.48x

Time (Write / Read) — Windows

Scenario PHP 8.1 PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
Sparse Int 100K 4.8x / 2.8x 5.3x / 3.0x 4.1x / 2.7x 5.1x / 3.0x 5.4x / 3.3x
Sparse Int 500K 3.5x / 2.0x 5.0x / 2.7x 4.1x / 2.4x 4.9x / 2.7x 4.8x / 2.5x
Sparse Int 1M 3.6x / 1.9x 4.2x / 2.8x 3.6x / 2.0x 4.2x / 2.8x 4.6x / 3.1x
Sparse Int 10M 2.4x / 2.3x 2.4x / 2.1x 2.5x / 2.3x 2.4x / 2.2x 3.0x / 2.3x
String 100K 3.6x / 2.6x 5.1x / 4.0x 3.8x / 4.1x 4.1x / 4.2x 4.4x / 5.2x
String 500K 3.6x / 2.3x 3.6x / 2.7x 4.0x / 2.2x 3.6x / 2.9x 3.9x / 2.9x
String 1M 3.2x / 2.0x 3.4x / 2.5x 3.4x / 2.2x 3.2x / 2.5x 3.5x / 2.1x
String 10M 3.8x / 2.8x 3.4x / 2.3x 3.5x / 2.2x 3.3x / 2.3x 3.6x / 2.3x

Memory — Windows

Scenario PHP 8.1 PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
Sparse Int 100K 0.23x 0.23x 0.23x 0.23x 0.23x
Sparse Int 500K 0.46x 0.46x 0.46x 0.46x 0.46x
Sparse Int 1M 0.46x 0.46x 0.46x 0.46x 0.46x
Sparse Int 10M 0.29x 0.29x 0.29x 0.29x 0.29x
String 100K 0.51x 0.51x 0.51x 0.51x 0.51x
String 500K 0.76x 0.76x 0.76x 0.76x 0.76x
String 1M 0.76x 0.76x 0.76x 0.76x 0.76x
String 10M 0.48x 0.48x 0.48x 0.48x 0.48x
Raw benchmark data

Write Time — Linux

Scenario Subject PHP 8.1 PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
Sparse Int 100K Judy 0.0120s 0.0124s 0.0122s 0.0121s 0.0122s
Sparse Int 100K PHP Array 0.0039s 0.0042s 0.0040s 0.0042s 0.0041s
Sparse Int 500K Judy 0.0670s 0.0849s 0.0674s 0.0780s 0.0692s
Sparse Int 500K PHP Array 0.0188s 0.0207s 0.0195s 0.0212s 0.0204s
Sparse Int 1M Judy 0.1677s 0.2198s 0.1708s 0.2264s 0.1954s
Sparse Int 1M PHP Array 0.0482s 0.0650s 0.0517s 0.0605s 0.0539s
Sparse Int 10M Judy 2.7755s 2.7191s 3.0067s 3.4165s 3.1684s
Sparse Int 10M PHP Array 1.2707s 1.5192s 1.4795s 1.6897s 1.5507s
String 100K Judy 0.0206s 0.0286s 0.0239s 0.0257s 0.0269s
String 100K PHP Array 0.0066s 0.0111s 0.0108s 0.0090s 0.0095s
String 500K Judy 0.1549s 0.1861s 0.1662s 0.2229s 0.1780s
String 500K PHP Array 0.0683s 0.0743s 0.0726s 0.0739s 0.0714s
String 1M Judy 0.3499s 0.3972s 0.3888s 0.5019s 0.4197s
String 1M PHP Array 0.1407s 0.1733s 0.1563s 0.1598s 0.1503s
String 10M Judy 5.2368s 5.5148s 5.5445s 6.2970s 5.5311s
String 10M PHP Array 1.9296s 2.1148s 1.9533s 2.1946s 2.0311s

Read Time — Linux

Scenario Subject PHP 8.1 PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
Sparse Int 100K Judy 0.0095s 0.0102s 0.0094s 0.0099s 0.0096s
Sparse Int 100K PHP Array 0.0036s 0.0036s 0.0036s 0.0036s 0.0036s
Sparse Int 500K Judy 0.0565s 0.1137s 0.0697s 0.1222s 0.0696s
Sparse Int 500K PHP Array 0.0200s 0.0455s 0.0223s 0.0246s 0.0253s
Sparse Int 1M Judy 0.1315s 0.3027s 0.1774s 0.2414s 0.2066s
Sparse Int 1M PHP Array 0.0611s 0.1040s 0.0783s 0.0697s 0.0807s
Sparse Int 10M Judy 3.2054s 3.1647s 3.4815s 3.9158s 3.5454s
Sparse Int 10M PHP Array 1.2740s 1.3538s 1.3888s 1.4220s 1.3988s
String 100K Judy 0.0161s 0.0222s 0.0174s 0.0191s 0.0194s
String 100K PHP Array 0.0051s 0.0055s 0.0069s 0.0057s 0.0053s
String 500K Judy 0.1512s 0.2332s 0.1774s 0.2490s 0.1945s
String 500K PHP Array 0.0645s 0.1004s 0.0829s 0.0838s 0.0757s
String 1M Judy 0.3613s 0.3953s 0.4197s 0.4509s 0.4222s
String 1M PHP Array 0.1542s 0.2438s 0.2078s 0.1979s 0.1864s
String 10M Judy 5.5570s 6.0841s 6.0411s 6.3622s 5.8439s
String 10M PHP Array 2.3747s 2.6382s 2.4346s 2.6100s 2.5044s

Memory — Linux

Scenario Subject PHP 8.1 PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
Sparse Int 100K Judy 1.84 mb 1.84 mb 1.85 mb 1.85 mb 1.85 mb
Sparse Int 100K PHP Array 7 mb 7 mb 7 mb 7 mb 7 mb
Sparse Int 500K Judy 9.19 mb 9.19 mb 9.19 mb 9.19 mb 9.19 mb
Sparse Int 500K PHP Array 20 mb 20 mb 20 mb 20 mb 20 mb
Sparse Int 1M Judy 18.36 mb 18.35 mb 18.34 mb 18.37 mb 18.38 mb
Sparse Int 1M PHP Array 40 mb 40 mb 40 mb 40 mb 40 mb
Sparse Int 10M Judy 183.57 mb 183.61 mb 183.69 mb 183.62 mb 183.56 mb
Sparse Int 10M PHP Array 640 mb 640 mb 640 mb 640 mb 640 mb
String 100K Judy 3.05 mb 3.05 mb 3.05 mb 3.05 mb 3.05 mb
String 100K PHP Array 5 mb 5 mb 5 mb 5 mb 5 mb
String 500K Judy 15.26 mb 15.26 mb 15.26 mb 15.26 mb 15.26 mb
String 500K PHP Array 20 mb 20 mb 20 mb 20 mb 20 mb
String 1M Judy 30.52 mb 30.52 mb 30.52 mb 30.52 mb 30.52 mb
String 1M PHP Array 40 mb 40 mb 40 mb 40 mb 40 mb
String 10M Judy 305.18 mb 305.18 mb 305.18 mb 305.18 mb 305.18 mb
String 10M PHP Array 640 mb 640 mb 640 mb 640 mb 640 mb

Write Time — Windows

Scenario Subject PHP 8.1 PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
Sparse Int 100K Judy 0.0301s 0.0293s 0.0293s 0.0288s 0.0287s
Sparse Int 100K PHP Array 0.0063s 0.0055s 0.0071s 0.0056s 0.0053s
Sparse Int 500K Judy 0.1643s 0.1487s 0.1564s 0.1494s 0.1482s
Sparse Int 500K PHP Array 0.0463s 0.0296s 0.0380s 0.0305s 0.0307s
Sparse Int 1M Judy 0.3941s 0.3119s 0.3210s 0.3117s 0.3186s
Sparse Int 1M PHP Array 0.1102s 0.0750s 0.0904s 0.0747s 0.0697s
Sparse Int 10M Judy 6.1135s 4.5880s 5.3355s 4.8273s 4.9941s
Sparse Int 10M PHP Array 2.5405s 1.9051s 2.1453s 2.0476s 1.6482s
String 100K Judy 0.0574s 0.0487s 0.0521s 0.0487s 0.0513s
String 100K PHP Array 0.0158s 0.0095s 0.0138s 0.0120s 0.0117s
String 500K Judy 0.3640s 0.2934s 0.3571s 0.3025s 0.3074s
String 500K PHP Array 0.1004s 0.0813s 0.0900s 0.0845s 0.0798s
String 1M Judy 0.8056s 0.6214s 0.7438s 0.6535s 0.6435s
String 1M PHP Array 0.2495s 0.1821s 0.2188s 0.2020s 0.1863s
String 10M Judy 11.3522s 8.4644s 9.2228s 8.8973s 9.1311s
String 10M PHP Array 2.9637s 2.5266s 2.6338s 2.7025s 2.5637s

Read Time — Windows

Scenario Subject PHP 8.1 PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
Sparse Int 100K Judy 0.0172s 0.0159s 0.0171s 0.0154s 0.0152s
Sparse Int 100K PHP Array 0.0061s 0.0053s 0.0064s 0.0051s 0.0046s
Sparse Int 500K Judy 0.1395s 0.0846s 0.1040s 0.0847s 0.0861s
Sparse Int 500K PHP Array 0.0689s 0.0308s 0.0427s 0.0318s 0.0346s
Sparse Int 1M Judy 0.2979s 0.2133s 0.2534s 0.2134s 0.2236s
Sparse Int 1M PHP Array 0.1582s 0.0773s 0.1248s 0.0750s 0.0728s
Sparse Int 10M Judy 4.8945s 3.6376s 4.3317s 3.9552s 4.0333s
Sparse Int 10M PHP Array 2.0911s 1.7024s 1.8541s 1.7830s 1.7801s
String 100K Judy 0.0407s 0.0271s 0.0316s 0.0275s 0.0323s
String 100K PHP Array 0.0157s 0.0067s 0.0077s 0.0066s 0.0062s
String 500K Judy 0.2962s 0.2023s 0.2421s 0.2093s 0.2203s
String 500K PHP Array 0.1315s 0.0750s 0.1086s 0.0720s 0.0756s
String 1M Judy 0.6360s 0.4771s 0.5558s 0.5145s 0.5028s
String 1M PHP Array 0.3241s 0.1944s 0.2579s 0.2035s 0.2403s
String 10M Judy 9.8792s 6.7885s 7.3179s 7.2906s 7.3173s
String 10M PHP Array 3.5794s 2.9591s 3.3091s 3.1431s 3.1215s

Memory — Windows

Scenario Subject PHP 8.1 PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
Sparse Int 100K Judy 1.86 mb 1.84 mb 1.84 mb 1.84 mb 1.84 mb
Sparse Int 100K PHP Array 8 mb 8 mb 8 mb 8 mb 8 mb
Sparse Int 500K Judy 9.19 mb 9.17 mb 9.18 mb 9.17 mb 9.19 mb
Sparse Int 500K PHP Array 20 mb 20 mb 20 mb 20 mb 20 mb
Sparse Int 1M Judy 18.38 mb 18.39 mb 18.38 mb 18.37 mb 18.35 mb
Sparse Int 1M PHP Array 40 mb 40 mb 40 mb 40 mb 40 mb
Sparse Int 10M Judy 183.57 mb 183.65 mb 183.6 mb 183.54 mb 183.56 mb
Sparse Int 10M PHP Array 640 mb 640 mb 640 mb 640 mb 640 mb
String 100K Judy 3.05 mb 3.05 mb 3.05 mb 3.05 mb 3.05 mb
String 100K PHP Array 6 mb 6 mb 6 mb 6 mb 6 mb
String 500K Judy 15.26 mb 15.26 mb 15.26 mb 15.26 mb 15.26 mb
String 500K PHP Array 20 mb 20 mb 20 mb 20 mb 20 mb
String 1M Judy 30.52 mb 30.52 mb 30.52 mb 30.52 mb 30.52 mb
String 1M PHP Array 40 mb 40 mb 40 mb 40 mb 40 mb
String 10M Judy 305.18 mb 305.18 mb 305.18 mb 305.18 mb 305.18 mb
String 10M PHP Array 640 mb 640 mb 640 mb 640 mb 640 mb

Batch & Set Operations Benchmarks

Benchmarks for putAll(), fromArray(), getAll(), toArray(), increment(), and BITSET set operations (union, intersect, diff, xor).

Batch Operations — PHP 8.5 (Linux)
=============================================================
  Judy Batch Operations & Increment Benchmark
=============================================================
  PHP 8.5.3 | Judy ext 2.3.0
  Iterations: 5 (median of each)
=============================================================

===========================================================
  INT_TO_INT — 10,000 elements
===========================================================

  [1. Bulk Add: populate 10000 elements]
  PHP array (foreach assign)                            0.220 ms
  Judy individual $j[$k] = $v                           0.505 ms
  Judy putAll()                                         0.383 ms
  Judy::fromArray()                                     0.387 ms
  putAll() vs individual Judy                        1.32x
  fromArray() vs individual Judy                     1.30x
  Judy putAll() vs PHP array                         1.74x
  Judy fromArray() vs PHP array                      1.76x

  [2. Bulk Get: fetch 1100 keys (incl. 100 missing)]
  PHP array ($a[$k] ?? null)                            0.029 ms
  Judy individual $j[$k]                                0.067 ms
  Judy getAll()                                         0.043 ms
  getAll() vs individual Judy                        1.56x
  Judy getAll() vs PHP array                         1.48x

  [3. Conversion: Judy to PHP array]
  Judy toArray()                                        0.440 ms
  Judy manual foreach loop                              2.257 ms
  toArray() vs manual foreach                        5.13x

  [4. Increment: 10000 ops on 1000 unique keys]
  PHP array $a[$k]++                                    0.208 ms
  Judy $j[$k] = $j[$k] + 1                              0.680 ms
  Judy increment()                                      0.469 ms
  increment() vs manual Judy                         1.45x
  Judy increment() vs PHP array                      2.26x

===========================================================
  STRING_TO_INT — 10,000 elements
===========================================================

  [1. Bulk Add: populate 10000 elements]
  PHP array (foreach assign)                            0.287 ms
  Judy individual $j[$k] = $v                           1.907 ms
  Judy putAll()                                         1.788 ms
  Judy::fromArray()                                     1.769 ms
  putAll() vs individual Judy                        1.07x
  fromArray() vs individual Judy                     1.08x
  Judy putAll() vs PHP array                         6.22x
  Judy fromArray() vs PHP array                      6.16x

  [2. Bulk Get: fetch 1100 keys (incl. 100 missing)]
  PHP array ($a[$k] ?? null)                            0.038 ms
  Judy individual $j[$k]                                0.099 ms
  Judy getAll()                                         0.094 ms
  getAll() vs individual Judy                        1.05x
  Judy getAll() vs PHP array                         2.48x

  [3. Conversion: Judy to PHP array]
  Judy toArray()                                        1.097 ms
  Judy manual foreach loop                              3.708 ms
  toArray() vs manual foreach                        3.38x

  [4. Increment: 10000 ops on 1000 unique keys]
  PHP array $a[$k]++                                    0.310 ms
  Judy $j[$k] = $j[$k] + 1                              1.801 ms
  Judy increment()                                      1.288 ms
  increment() vs manual Judy                         1.40x
  Judy increment() vs PHP array                      4.15x

===========================================================
  INT_TO_INT — 100,000 elements
===========================================================

  [1. Bulk Add: populate 100000 elements]
  PHP array (foreach assign)                            2.784 ms
  Judy individual $j[$k] = $v                           5.423 ms
  Judy putAll()                                         4.252 ms
  Judy::fromArray()                                     4.293 ms
  putAll() vs individual Judy                        1.28x
  fromArray() vs individual Judy                     1.26x
  Judy putAll() vs PHP array                         1.53x
  Judy fromArray() vs PHP array                      1.54x

  [2. Bulk Get: fetch 10100 keys (incl. 100 missing)]
  PHP array ($a[$k] ?? null)                            0.265 ms
  Judy individual $j[$k]                                0.436 ms
  Judy getAll()                                         0.252 ms
  getAll() vs individual Judy                        1.73x
  Judy getAll() vs PHP array                         0.95x

  [3. Conversion: Judy to PHP array]
  Judy toArray()                                        5.042 ms
  Judy manual foreach loop                             22.833 ms
  toArray() vs manual foreach                        4.53x

  [4. Increment: 100000 ops on 1000 unique keys]
  PHP array $a[$k]++                                    2.132 ms
  Judy $j[$k] = $j[$k] + 1                              6.659 ms
  Judy increment()                                      4.560 ms
  increment() vs manual Judy                         1.46x
  Judy increment() vs PHP array                      2.14x

===========================================================
  STRING_TO_INT — 100,000 elements
===========================================================

  [1. Bulk Add: populate 100000 elements]
  PHP array (foreach assign)                            3.461 ms
  Judy individual $j[$k] = $v                          20.372 ms
  Judy putAll()                                        19.158 ms
  Judy::fromArray()                                    19.217 ms
  putAll() vs individual Judy                        1.06x
  fromArray() vs individual Judy                     1.06x
  Judy putAll() vs PHP array                         5.54x
  Judy fromArray() vs PHP array                      5.55x

  [2. Bulk Get: fetch 10100 keys (incl. 100 missing)]
  PHP array ($a[$k] ?? null)                            0.359 ms
  Judy individual $j[$k]                                1.013 ms
  Judy getAll()                                         0.951 ms
  getAll() vs individual Judy                        1.07x
  Judy getAll() vs PHP array                         2.65x

  [3. Conversion: Judy to PHP array]
  Judy toArray()                                       11.908 ms
  Judy manual foreach loop                             38.857 ms
  toArray() vs manual foreach                        3.26x

  [4. Increment: 100000 ops on 1000 unique keys]
  PHP array $a[$k]++                                    3.013 ms
  Judy $j[$k] = $j[$k] + 1                             17.437 ms
  Judy increment()                                     12.272 ms
  increment() vs manual Judy                         1.42x
  Judy increment() vs PHP array                      4.07x

===========================================================
  INT_TO_INT — 500,000 elements
===========================================================

  [1. Bulk Add: populate 500000 elements]
  PHP array (foreach assign)                           12.848 ms
  Judy individual $j[$k] = $v                          27.566 ms
  Judy putAll()                                        21.772 ms
  Judy::fromArray()                                    21.919 ms
  putAll() vs individual Judy                        1.27x
  fromArray() vs individual Judy                     1.26x
  Judy putAll() vs PHP array                         1.69x
  Judy fromArray() vs PHP array                      1.71x

  [2. Bulk Get: fetch 50100 keys (incl. 100 missing)]
  PHP array ($a[$k] ?? null)                            1.594 ms
  Judy individual $j[$k]                                2.444 ms
  Judy getAll()                                         1.538 ms
  getAll() vs individual Judy                        1.59x
  Judy getAll() vs PHP array                         0.96x

  [3. Conversion: Judy to PHP array]
  Judy toArray()                                       25.162 ms
  Judy manual foreach loop                            114.016 ms
  toArray() vs manual foreach                        4.53x

  [4. Increment: 500000 ops on 1000 unique keys]
  PHP array $a[$k]++                                   10.638 ms
  Judy $j[$k] = $j[$k] + 1                             33.684 ms
  Judy increment()                                     23.443 ms
  increment() vs manual Judy                         1.44x
  Judy increment() vs PHP array                      2.20x

===========================================================
  STRING_TO_INT — 500,000 elements
===========================================================

  [1. Bulk Add: populate 500000 elements]
  PHP array (foreach assign)                           16.949 ms
  Judy individual $j[$k] = $v                         104.089 ms
  Judy putAll()                                        96.599 ms
  Judy::fromArray()                                    96.349 ms
  putAll() vs individual Judy                        1.08x
  fromArray() vs individual Judy                     1.08x
  Judy putAll() vs PHP array                         5.70x
  Judy fromArray() vs PHP array                      5.68x

  [2. Bulk Get: fetch 50100 keys (incl. 100 missing)]
  PHP array ($a[$k] ?? null)                            1.890 ms
  Judy individual $j[$k]                                5.267 ms
  Judy getAll()                                         5.027 ms
  getAll() vs individual Judy                        1.05x
  Judy getAll() vs PHP array                         2.66x

  [3. Conversion: Judy to PHP array]
  Judy toArray()                                       60.232 ms
  Judy manual foreach loop                            195.706 ms
  toArray() vs manual foreach                        3.25x

  [4. Increment: 500000 ops on 1000 unique keys]
  PHP array $a[$k]++                                   15.117 ms
  Judy $j[$k] = $j[$k] + 1                             87.845 ms
  Judy increment()                                     61.228 ms
  increment() vs manual Judy                         1.43x
  Judy increment() vs PHP array                      4.05x

=============================================================
  Benchmark complete.
=============================================================
Set Operations — PHP 8.5 (Linux)
=============================================================
  Judy BITSET Set Operations Benchmark
=============================================================
  PHP 8.5.3 | Judy ext 2.3.0
  Overlap: 50% between sets A and B
=============================================================

--- Size: 1,000 indices per set (500 unique + 500 shared) ---

  [Union]
  Judy::union()                                    0.088 ms (median of 5)
  array_replace() keys                             0.008 ms (median of 5)
  Speedup: 0.1x

  [Intersect]
  Judy::intersect()                                0.072 ms (median of 5)
  array_intersect_key()                            0.017 ms (median of 5)
  Speedup: 0.2x

  [Diff]
  Judy::diff()                                     0.072 ms (median of 5)
  array_diff_key()                                 0.012 ms (median of 5)
  Speedup: 0.2x

  [XOR (symmetric difference)]
  Judy::xor()                                      0.085 ms (median of 5)
  array_diff_key() x2 + array_replace()            0.031 ms (median of 5)
  Speedup: 0.4x

  [Memory: union result]
  Judy memoryUsage()                            8.08 kb
  PHP array memory delta                        36.05 kb
  Ratio: PHP uses 4.5x more memory

--- Size: 10,000 indices per set (5000 unique + 5000 shared) ---

  [Union]
  Judy::union()                                    0.596 ms (median of 5)
  array_replace() keys                             0.068 ms (median of 5)
  Speedup: 0.1x

  [Intersect]
  Judy::intersect()                                0.271 ms (median of 5)
  array_intersect_key()                            0.088 ms (median of 5)
  Speedup: 0.3x

  [Diff]
  Judy::diff()                                     0.269 ms (median of 5)
  array_diff_key()                                 0.069 ms (median of 5)
  Speedup: 0.3x

  [XOR (symmetric difference)]
  Judy::xor()                                      0.533 ms (median of 5)
  array_diff_key() x2 + array_replace()            0.163 ms (median of 5)
  Speedup: 0.3x

  [Memory: union result]
  Judy memoryUsage()                            8.08 kb
  PHP array memory delta                        260.05 kb
  Ratio: PHP uses 32.2x more memory

--- Size: 100,000 indices per set (50000 unique + 50000 shared) ---

  [Union]
  Judy::union()                                    7.091 ms (median of 5)
  array_replace() keys                             1.435 ms (median of 5)
  Speedup: 0.2x

  [Intersect]
  Judy::intersect()                                3.354 ms (median of 5)
  array_intersect_key()                            0.990 ms (median of 5)
  Speedup: 0.3x

  [Diff]
  Judy::diff()                                     3.167 ms (median of 5)
  array_diff_key()                                 0.560 ms (median of 5)
  Speedup: 0.2x

  [XOR (symmetric difference)]
  Judy::xor()                                      6.642 ms (median of 5)
  array_diff_key() x2 + array_replace()            2.127 ms (median of 5)
  Speedup: 0.3x

  [Memory: union result]
  Judy memoryUsage()                            20.08 kb
  PHP array memory delta                        4 mb
  Ratio: PHP uses 204.2x more memory

--- Size: 500,000 indices per set (250000 unique + 250000 shared) ---

  [Union]
  Judy::union()                                   37.131 ms (median of 5)
  array_replace() keys                             4.804 ms (median of 5)
  Speedup: 0.1x

  [Intersect]
  Judy::intersect()                               16.730 ms (median of 5)
  array_intersect_key()                            5.622 ms (median of 5)
  Speedup: 0.3x

  [Diff]
  Judy::diff()                                    16.652 ms (median of 5)
  array_diff_key()                                 3.181 ms (median of 5)
  Speedup: 0.2x

  [XOR (symmetric difference)]
  Judy::xor()                                     33.619 ms (median of 5)
  array_diff_key() x2 + array_replace()           12.089 ms (median of 5)
  Speedup: 0.4x

  [Memory: union result]
  Judy memoryUsage()                            56.08 kb
  PHP array memory delta                        16 mb
  Ratio: PHP uses 292.2x more memory

=============================================================
  Benchmark complete.
=============================================================

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds valuable documentation for Judy::memoryUsage() and a new benchmark script to compare memory usage patterns between Judy and PHP arrays. The documentation is clear and the benchmark script is well-structured. I have two suggestions for improvement: one to clarify a point in the documentation and another to refactor some duplicated code in the new benchmark script for better maintainability.

…put code

- Reword "allocates a full hash table" to avoid mischaracterizing PHP
  array behavior for sparse keys
- Extract run_throughput_bench() helper to eliminate duplicated
  INT_TO_INT / BITSET / STRING_TO_INT printing blocks
- Update file header comment to reflect that STRING types are only in
  throughput section, not memory footprint
@orieg orieg merged commit 3f37cf9 into main Feb 28, 2026
13 checks passed
@orieg orieg deleted the docs/memory-patterns branch February 28, 2026 07:30
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.

1 participant