[vim/vim] Use hashtable for syn_name2id() lookup (PR #19788)

8 views
Skip to first unread message

mattn

unread,
Mar 22, 2026, 12:31:06 PM (2 days ago) Mar 22
to vim/vim, Subscribed

In modern Vim usage with plugins and colorschemes, syn_name2id() is one of the most called functions during startup. In my environment, it is called roughly 4,800 times before Vim finishes starting up.

However, the implementation of syn_name2id() uses a linear scan over a growarray, making each lookup O(n) in the number of highlight groups. This results in over 3.4 million STRCMP() calls just during startup.

This change replaces the linear search with a hashtab_T-based lookup, reducing the cost to O(1). The hashtable is maintained alongside the existing growarray using the same offsetof pattern as signgroup_T / HI2SG.

Benchmark (User time, vim -c quit):

  • Before: 0.189s
  • After: 0.171s (-9.5%)

The more highlight groups are defined, the greater the benefit of this change.


You can view, comment on, or merge this pull request online at:

  https://github.com/vim/vim/pull/19788

Commit Summary

  • 084319d Use hashtable for syn_name2id() lookup

File Changes

(1 file)

Patch Links:


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19788@github.com>

mattn

unread,
Mar 22, 2026, 12:43:31 PM (2 days ago) Mar 22
to vim/vim, Subscribed
mattn left a comment (vim/vim#19788)

For reference, here is the benchmark result when opening a file (mbyte.c) with syntax highlighting:

Benchmark 1: ./vim_old mbyte.c -c quit
  Time (mean ± σ):      2.357 s ±  0.020 s    [User: 0.248 s, System: 0.067 s]

Benchmark 2: ./vim_new mbyte.c -c quit
  Time (mean ± σ):      2.329 s ±  0.018 s    [User: 0.220 s, System: 0.066 s]

User time improved by 11.3% (0.248s → 0.220s). The benefit grows when syntax highlighting is involved, since syn_name2id() is called more frequently.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19788/c4106569413@github.com>

mattn

unread,
Mar 23, 2026, 12:17:55 AM (yesterday) Mar 23
to vim/vim, Subscribed
mattn left a comment (vim/vim#19788)

Here are realistic benchmark results excluding startup time.

The scenario simulates colorscheme re-application + highlight link + hlID() lookups with 541 highlight groups (82 base + 200 treesitter-style + 256 plugin-style), performing 17,640 name lookups.

master (linear scan):  0.084 sec (~210,000 lookups/sec)
hashtable branch:      0.062 sec (~284,000 lookups/sec)
speedup:               ~1.35x

Since the benchmark includes the overhead of execute 'highlight ...' command parsing, the actual improvement in syn_name2id() itself is likely higher. The O(n) → O(1) difference also grows with group count — environments with 800–1000+ groups (e.g., treesitter plugins) will see a larger speedup.

For reference, a microbenchmark with 2000 groups using only hlID() showed ~2.5x speedup.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19788/c4107868492@github.com>

mattn

unread,
Mar 23, 2026, 10:31:26 AM (yesterday) Mar 23
to vim/vim, Push

@mattn pushed 2 commits.

  • 37aca65 Skip redundant highlight_changed() loop when 'highlight' matches default
  • f33a2b2 Avoid unnecessary alloc/free in syn_name2id_len()


View it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19788/before/084319d8bd9f2c0346eb0ff7bffb9b32619de1e3/after/f33a2b2c1cd506d455a6aed97b7285d106ba5bd8@github.com>

Christian Brabandt

unread,
Mar 23, 2026, 4:36:16 PM (yesterday) Mar 23
to vim/vim, Subscribed

@chrisbra commented on this pull request.


In src/highlight.c:

> @@ -207,6 +207,21 @@ static int hl_flags[HLF_COUNT] = HL_FLAGS;
 static garray_T highlight_ga;
 #define HL_TABLE()	((hl_group_T *)((highlight_ga.ga_data)))
 
+// Wrapper struct for hashtable entries: stores the highlight group ID alongside
+// the uppercase name used as a hash key.  Uses the same offsetof pattern as
+// signgroup_T / HI2SG.
+typedef struct {
+    int		hn_id;		// highlight group ID (1-based)
+    char_u	hn_key[1];	// uppercase name (stretchable array)
+} hlname_T;
+
+#define HLNAME_KEY_OFF	offsetof(hlname_T, hn_key)
+#define HI2HLNAME(hi)	((hlname_T *)((hi)->hi_key - HLNAME_KEY_OFF))
+
+// hashtable for quick highlight group name lookup
+static hashtab_T highlight_ht;
+static int	 highlight_ht_inited = FALSE;

bool?


In src/highlight.c:

>      }
     ga_clear(&highlight_ga);
+    hash_clear(&highlight_ht);

this frees all memory, but highlight_ht_inited isn't reset to false


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19788/review/3994443470@github.com>

mattn

unread,
Mar 23, 2026, 8:02:30 PM (yesterday) Mar 23
to vim/vim, Push

@mattn pushed 1 commit.

  • afc005a Address review feedback: use bool for highlight_ht_inited and reset on free


View it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19788/before/f33a2b2c1cd506d455a6aed97b7285d106ba5bd8/after/afc005acd8ed925cedd5574aa14a7f0ba9f398c4@github.com>

Christian Brabandt

unread,
4:51 PM (6 hours ago) 4:51 PM
to vim/vim, Subscribed
chrisbra left a comment (vim/vim#19788)

thanks


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19788/c4121278869@github.com>

Christian Brabandt

unread,
4:51 PM (6 hours ago) 4:51 PM
to vim/vim, Subscribed

Closed #19788 via b435da0.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/19788/issue_event/23866965511@github.com>

Reply all
Reply to author
Forward
0 new messages