[PATCH] kernelbase: Cache last used locale->sortguid mapping.

Torge Matthies openglfreak at googlemail.com
Sun Apr 4 23:24:04 CDT 2021


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 <openglfreak at googlemail.com>
---
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




More information about the wine-devel mailing list