[PATCH v5 0/2] MR10804: unicode: optimize memicmp_strW by doing case-sensitive comparision first
Call to slow `to_lower` can be avoided, if characters already match case-sensitive. Combined with an optimization for sorted data the time spent in `load_init_registry_from_file` for my 21MiB registry can be lowered. baseline: - 145ms, 147ms, 146ms insert-optimzation: - 120ms, 120ms, 117ms strcmpi-optimization: - 131ms, 131ms, 130ms insert+strcmpi: - 106ms, 110ms, 109ms, 110ms, 109ms Wine-bug: https://bugs.winehq.org/show_bug.cgi?id=59695 -- v5: registry: optimize `find_subkey` for sorted data unicode: optimize memicmp_strW by doing case-sensitive comparision first https://gitlab.winehq.org/wine/wine/-/merge_requests/10804
From: Stephan Seitz <stephan.seitz@fau.de> Call to slow `to_lower` can be avoided, if characters already match case-sensitive. For my 21MiB size registry this lowers the time spent in `load_init_registry_from_file` from 145ms to 130ms. Wine-bug: https://bugs.winehq.org/show_bug.cgi?id=59695 --- server/unicode.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server/unicode.c b/server/unicode.c index bb39b55e50c..62b52191610 100644 --- a/server/unicode.c +++ b/server/unicode.c @@ -75,8 +75,13 @@ int memicmp_strW( const WCHAR *str1, const WCHAR *str2, data_size_t len ) { int ret = 0; - for (len /= sizeof(WCHAR); len; str1++, str2++, len--) + for (len /= sizeof(WCHAR); len; str1++, str2++, len--) { + // when chars match case-sensitive, we can avoid slow to_lower + if (*str1 == *str2) { + continue; + } if ((ret = to_lower(*str1) - to_lower(*str2))) break; + } return ret; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10804
From: Stephan Seitz <stephan.seitz@fau.de> `load_init_registry_from_file` usually loads files with sorted keys to optimize for this case we should check for the append/last_subkey case first before continuing with normal binary search. For my 21MiB registry this loads the time for `load_init_registry_from_file` baseline: - 145ms, 147ms, 146ms insert-optimzation: - 120ms, 120ms, 117ms strcmpi-optimization in previous commit: - 131ms, 131ms, 130ms this commit combined with previous commit: - 106ms, 110ms, 109ms, 110ms, 109ms` Wine-bug: https://bugs.winehq.org/show_bug.cgi?id=59695 --- server/registry.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/registry.c b/server/registry.c index 91b3265e8f7..199e9a6d4ef 100644 --- a/server/registry.c +++ b/server/registry.c @@ -294,12 +294,15 @@ static struct key *find_subkey( const struct key *key, const struct unicode_str { int i, min, max, res; data_size_t len; + bool first_comparison = true; min = 0; max = key->last_subkey; while (min <= max) { - i = (min + max) / 2; + /* when loading from sorted data, most entries are inserted at the last position */ + i = first_comparison ? max : (min + max) / 2; + first_comparison = false; len = min( key->subkeys[i]->obj.name->len, name->len ); res = memicmp_strW( key->subkeys[i]->obj.name->name, name->str, len ); if (!res) res = key->subkeys[i]->obj.name->len - name->len; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10804
On Thu Jun 4 11:18:52 2026 +0000, Alfred Agrell wrote:
IMO the most important question here is what made your registry so chonky. "Wineserver startup takes 20 seconds after installing Contoso System Discombobulator 2028" is more a convincing usecase than "Wineserver startup takes 20 seconds if your registry is half a gigabyte". I'd also check server startup times for unpatched, case patch only, sort patch only, and both. If the latter two are almost the same, the case patch is probably not worth keeping; if noticably different, we now know it is worth keeping. But I'm not the wineserver maintainer, so my opinion isn't the important one. I measured again the speed-up for `load_init_registry_from_file` for my 21MiB registry which seems to be closer to a normal size
baseline: - 145ms, 147ms, 146ms insert-optimzation: - 120ms, 120ms, 117ms strcmpi-optimization: - 131ms, 131ms, 130ms insert+strcmpi: - 106ms, 110ms, 109ms, 110ms, 109ms I think my registry got corrupted by either the use of regedit.exe where I registered a DLL to provide an activatable class for `Microsoft.Windows.AI.MachineLearning.ExecutionProviderCatalog` or by the Microsoft DLL supposed to contain that activatable class. My registry got bloated by infinitely nested entries for Microsoft.Windows.AI. This is probably not a path a normal user might hit. My test exe only activated this class. I would see this now as an optimization for normal size registry. I updated the commit messages. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10804#note_146065
participants (2)
-
Stephan Seitz -
Stephan Seitz (@theHamsta)