From: Torge Matthies Subject: [PATCH] kernelbase: Cache last used locale->sortguid mapping. Message-Id: <20210405042404.279850-1-openglfreak@googlemail.com> Date: Mon, 5 Apr 2021 06:24:04 +0200 get_language_sort reads from the registry, which is not particularly fast. Staging's implementation of CompareStringEx calls this function, and if CompareStringEx is used in a loop over many elements, it will slow down the application by a lot (> 30 seconds vs a few hundred ms in osu!, depends on the CPU and the number of installed beatmaps). Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50923 Signed-off-by: Torge Matthies --- This could be put into the Staging patchset libs-Unicode_Collation, if deemed not appropriate for vanilla. I could also make it cache all requested locales in an rbtree, if desired. However most applications should only ever need one locale. dlls/kernelbase/locale.c | 42 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/dlls/kernelbase/locale.c b/dlls/kernelbase/locale.c index c58c2cbe434..3b4191078ad 100644 --- a/dlls/kernelbase/locale.c +++ b/dlls/kernelbase/locale.c @@ -618,6 +618,21 @@ static CRITICAL_SECTION_DEBUG critsect_debug = }; static CRITICAL_SECTION locale_section = { &critsect_debug, -1, 0, 0, 0, 0 }; +static struct +{ + WCHAR locale[LOCALE_NAME_MAX_LENGTH]; /* The locale name */ + const struct sortguid *guid; /* The cached associated GUID */ +} sortguid_cache; + +static CRITICAL_SECTION sortguid_cache_section; +static CRITICAL_SECTION_DEBUG sortguid_cache_section_debug = +{ + 0, 0, &sortguid_cache_section, + { &sortguid_cache_section_debug.ProcessLocksList, &sortguid_cache_section_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": sortguid_cache_section") } +}; +static CRITICAL_SECTION sortguid_cache_section = { &sortguid_cache_section_debug, -1, 0, 0, 0, 0 }; + static void init_sortkeys( DWORD *ptr ) { @@ -655,7 +670,7 @@ static const struct sortguid *find_sortguid( const GUID *guid ) } -static const struct sortguid *get_language_sort( const WCHAR *locale ) +static const struct sortguid *get_language_sort_uncached( const WCHAR *locale ) { WCHAR *p, *end, buffer[LOCALE_NAME_MAX_LENGTH], guidstr[39]; const struct sortguid *ret; @@ -698,6 +713,31 @@ done: } +static const struct sortguid *get_language_sort( const WCHAR *locale ) +{ + const struct sortguid *ret = NULL; + + if (!locale) return get_language_sort_uncached( locale ); + + RtlEnterCriticalSection( &sortguid_cache_section ); + + if (sortguid_cache.guid && !wcsncmp( sortguid_cache.locale, locale, LOCALE_NAME_MAX_LENGTH )) + { + ret = sortguid_cache.guid; + goto done; + } + + ret = get_language_sort_uncached( locale ); + + lstrcpynW( sortguid_cache.locale, locale, LOCALE_NAME_MAX_LENGTH ); + sortguid_cache.guid = ret; + +done: + RtlLeaveCriticalSection( &sortguid_cache_section ); + return ret; +} + + static LCID locale_to_lcid( WCHAR *win_name ) { WCHAR *p; -- 2.31.1