Skip to content

Compile grammar objects directly when the cache has no result - #753

Closed
Ubospica wants to merge 1 commit into
mainfrom
perf/compile-grammar-direct-cache-miss
Closed

Ubospica wants to merge 1 commit into
mainfrom
perf/compile-grammar-direct-cache-miss

Conversation

@Ubospica

@Ubospica Ubospica commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

改动

  • 当语法缓存第一次插入某个键时,允许本次调用提供计算过程;保留现有的有限容量、无限容量和每个键只计算一次的行为。
  • 当缓存中找不到结果时,直接编译已有的 Grammar 语法对象,避免“语法对象 -> 扩展巴科斯范式文本 -> 语法对象”的多余往返。扩展巴科斯范式(Extended Backus-Naur Form,EBNF)是描述语法规则的文本表示。
  • 继续使用规范化文本作为缓存键,使语法对象和语法字符串仍能共享缓存结果。

性能

与主分支提交 c5717178 比较。输入是包含 400 个函数的结构化标签语法,使用 Qwen3-4B-Instruct-2507 语言模型的词表数据和 8 个固定处理器核心。两组交替运行,合计取 20 个样本。

  • 首次编译 Grammar 对象且缓存未命中:中位数从 453.99 毫秒降到 320.66 毫秒,降低 29.4%,快 1.42 倍。
  • 在已启动编译器中编译新语法:中位数从 441.83 毫秒降到 300.81 毫秒,降低 31.9%,快 1.47 倍。
  • 已启动环境下语法构造加编译的全流程:中位数从 513.79 毫秒降到 374.16 毫秒,降低 27.2%,快 1.37 倍。

另外进行 10 轮 XGrammar 与 LLGuidance 1.7.6 对照。XGrammar 是本仓库的语法约束生成库,LLGuidance 是另一个语法约束生成实现。改动后,已启动环境下的语法编译分别为 399.4 毫秒和 118.3 毫秒;单次词元允许集合生成的中位数分别为 2.6 微秒和 609.0 微秒。

验证

  • C++ 语言测试:62 项通过。
  • Python 语言的语法编译器测试:12 项通过,排除需要远程词表的测试。
  • 所有改动文件通过提交前格式检查。
  • 新增有限容量和无限容量缓存首次计算的覆盖测试。

Avoid serializing and reparsing an existing Grammar when populating the compiler cache while preserving shared cache keys and concurrent miss deduplication.
Copilot AI review requested due to automatic review settings July 28, 2026 13:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR improves grammar compilation performance by letting the grammar cache compute values per call on cache misses, enabling direct compilation of existing Grammar objects without an extra Grammar -> EBNF text -> Grammar round-trip while preserving the existing cache keying and bounded/unbounded behaviors.

Changes:

  • Extend ThreadSafeLRUCache::Get to accept an optional per-call “compute on miss” callable (while keeping the existing default-computer behavior).
  • Update GrammarCompiler::Impl::CompileGrammar(const Grammar&) to compile the passed Grammar object directly on cache misses, keyed by the canonical text/root tuple so object/string compilation shares cache entries.
  • Add C++ and Python tests covering per-call miss computation override and shared caching between Grammar objects and EBNF strings.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
cpp/support/thread_safe_cache.h Adds a Get(key, compute_on_miss) overload and threads it through the internal future computation path.
cpp/grammar_compiler.cc Uses per-call miss computation to compile a Grammar object directly when inserting a cache entry.
tests/cpp/test_thread_safe_cache.cc Adds coverage for the per-call compute-on-miss override behavior in both unlimited and bounded modes.
tests/python/test_grammar_compiler.py Adds coverage ensuring compile_grammar(Grammar) and compile_grammar(str(grammar)) share cache results and match no-cache output.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Ubospica Ubospica changed the title perf: compile grammar objects directly on cache misses Compile grammar objects directly when the cache has no result Jul 30, 2026
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.

3 participants