bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Call to locale_charset within wcwidth


From: Daiki Ueno
Subject: Re: Call to locale_charset within wcwidth
Date: Tue, 27 Jan 2015 15:14:36 +0900
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/25.0.50 (gnu/linux)

Daiki Ueno <address@hidden> writes:

> Gavin Smith <address@hidden> writes:
>
>> It appears you can have thread-local variables with gcc using
>> "__thread", for example, "static __thread const char *encoding". (I
>> don't know about other compilers.) Would something like this work? As
>> well as threads, updating the cached encoding when the encoding
>> changes would be a problem.
>
> If the overhead of a single setlocale call is acceptable, how about
> using the return address of setlocale as a cache key and bypass the
> later part?
>
> Something like:

I took a bit more serious attempt to this, and ended up with the
attached patch.  Using the following test program:

  #include "config.h"
  #include "localcharset.h"
  #include <stdio.h>

  int main (void)
  {
    int i;

    printf ("%s\n", locale_charset ());
    for (i = 0; i < 1000000; i++)
      locale_charset ();
    printf ("%s\n", locale_charset ());

    return 0;
  }

it resulted in a significant performance improvement, although my test
environment is on Wine (I guess Eli could do testing under a more
practical setting).

Before:

  CP1252
  CP1252

  real    0m3.048s
  user    0m0.100s
  sys     0m0.070s

After:

  CP1252
  CP1252

  real    0m0.314s
  user    0m0.120s
  sys     0m0.050s

Regards,
--
Daiki Ueno
>From 6670a7c43dce4c7dc3c812af7e2bb493a0d3dc7c Mon Sep 17 00:00:00 2001
From: Daiki Ueno <address@hidden>
Date: Tue, 27 Jan 2015 14:56:30 +0900
Subject: [PATCH] localcharset: optimize on Windows

* lib/localcharset.c (locale_charset) [WINDOWS_NATIVE]: Bypass
GetACP and alias resolution by using thread-local cache.
Problem reported by Gavin Smith in:
https://lists.gnu.org/archive/html/bug-gnulib/2015-01/msg00040.html
---
 ChangeLog          |  8 ++++++++
 lib/localcharset.c | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 42 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index a57bdd0..162e534 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2015-01-27  Daiki Ueno  <address@hidden>
+
+       localcharset: optimize on Windows
+       * lib/localcharset.c (locale_charset) [WINDOWS_NATIVE]: Bypass
+       GetACP and alias resolution by using thread-local cache.
+       Problem reported by Gavin Smith in:
+       https://lists.gnu.org/archive/html/bug-gnulib/2015-01/msg00040.html
+
 2015-01-24  Daiki Ueno  <address@hidden>
 
        unictype: avoid undefined left-shift behavior
diff --git a/lib/localcharset.c b/lib/localcharset.c
index b4af28c..2eb4a5c 100644
--- a/lib/localcharset.c
+++ b/lib/localcharset.c
@@ -491,6 +491,9 @@ locale_charset (void)
 #elif defined WINDOWS_NATIVE
 
   static char buf[2 + 10 + 1];
+  static DWORD tls_locale_index;
+  static DWORD tls_codeset_index;
+  static int tls_initialized;
 
   /* The Windows API has a function returning the locale's codepage as
      a number, but the value doesn't change according to what the
@@ -506,6 +509,28 @@ locale_charset (void)
   if (strchr (current_locale, ';'))
     current_locale = setlocale (LC_CTYPE, NULL);
 
+  /* The 'GetACP' call and alias resolution below are costly.  Bypass
+     the rest of operations from the next call of this function, using
+     per-thread cache.  */
+  if (!tls_initialized)
+    {
+      tls_locale_index = TlsAlloc ();
+      tls_codeset_index = TlsAlloc ();
+      tls_initialized = 1;
+    }
+
+  if (tls_locale_index != TLS_OUT_OF_INDEXES
+      && tls_codeset_index != TLS_OUT_OF_INDEXES)
+    {
+      const char *tls_locale = TlsGetValue (tls_locale_index);
+      if (current_locale == tls_locale)
+       {
+         const char *tls_codeset = TlsGetValue (tls_codeset_index);
+         if (tls_codeset != NULL)
+           return tls_codeset;
+       }
+    }
+
   pdot = strrchr (current_locale, '.');
   if (pdot)
     sprintf (buf, "CP%s", pdot + 1);
@@ -609,5 +634,14 @@ locale_charset (void)
     codeset = "ASCII";
 #endif
 
+#ifdef WINDOWS_NATIVE
+  if (tls_locale_index != TLS_OUT_OF_INDEXES
+      && tls_codeset_index != TLS_OUT_OF_INDEXES)
+    {
+      TlsSetValue (tls_locale_index, (LPVOID) current_locale);
+      TlsSetValue (tls_codeset_index, (LPVOID) codeset);
+    }
+#endif
+
   return codeset;
 }
-- 
2.1.0


reply via email to

[Prev in Thread] Current Thread [Next in Thread]