Hi,
I am a developper of the Enlightenment project, and during my work
on optimising it, I did find that _XimParseStringFile was accounting
for more than 30% of the time needed to get a window to show (under
valgrind). I am using an Ubuntu Intrepid and it provide a 630KB
"/usr/share/X11/locale/en_US.UTF-8/Compose". So it take a lot of time
to read and parse. I did write a small patch, attached, that use mmap
to read the file, this make _XimParseStringFile only account for 14%
of the time, a little bit better. I think that if it's a normal
behaviour to provide a 630KB file to parse (and it sounds like it is
as the last size from libX11 git is around 670KB), changing this file
to precompiled binary file format would be a better patch, sadly I
don't have the needed time to write it right now.
Regards,
--
Cedric BAIL
diff --git a/modules/im/ximcp/imLcPrs.c b/modules/im/ximcp/imLcPrs.c
index aa52c20..c136814 100644
--- a/modules/im/ximcp/imLcPrs.c
+++ b/modules/im/ximcp/imLcPrs.c
@@ -42,6 +42,7 @@ OR PERFORMANCE OF THIS SOFTWARE.
#include "Xlcint.h"
#include "Ximint.h"
#include <sys/stat.h>
+#include <sys/mman.h>
#include <stdio.h>
extern int _Xmbstowcs(
@@ -79,36 +80,41 @@ extern int _Xmbstoutf8(
*/
static int
+getic(const char *map,
+ unsigned long *position,
+ unsigned long max)
+{
+ if (*position < max)
+ return map[(*position)++];
+ return EOF;
+}
+
+static int
nextch(
- FILE *fp,
- int *lastch)
+ const char *map,
+ unsigned long *position,
+ unsigned long max)
{
int c;
- if (*lastch != 0) {
- c = *lastch;
- *lastch = 0;
- } else {
- c = getc(fp);
- if (c == '\\') {
- c = getc(fp);
- if (c == '\n') {
- c = getc(fp);
- } else {
- ungetc(c, fp);
- c = '\\';
- }
- }
+ c = getic(map, position, max);
+ if (c == '\\') {
+ c = getic(map, position, max);
+ if (c == '\n') {
+ c = getic(map, position, max);
+ } else {
+ (*position)--;
+ c = '\\';
+ }
}
return(c);
}
static void
-putbackch(
- int c,
- int *lastch)
+putbackch(unsigned long *position)
{
- *lastch = c;
+ if (*position <= 0) return;
+ (*position)--;
}
#define ENDOFFILE 0
@@ -131,17 +137,29 @@ putbackch(
static int
nexttoken(
- FILE *fp,
char *tokenbuf,
- int *lastch)
+ unsigned long *tokenlength,
+ const char *map,
+ unsigned long *position,
+ unsigned long max)
{
+ unsigned long l = 0;
int c;
int token;
char *p;
int i, j;
- while ((c = nextch(fp, lastch)) == ' ' || c == '\t') {
- }
+ c = EOF;
+ while (*position < max)
+ {
+ c = map[(*position)++];
+ if (c != ' '
+ && c != '\t')
+ break;
+ }
+ if (*position == max)
+ c = EOF;
+
switch (c) {
case EOF:
token = ENDOFFILE;
@@ -166,26 +184,31 @@ nexttoken(
break;
case '"':
p = tokenbuf;
- while ((c = nextch(fp, lastch)) != '"') {
+ l = 0;
+ while ((c = nextch(map, position, max)) != '"') {
if (c == '\n' || c == EOF) {
- putbackch(c, lastch);
+ putbackch(position);
token = ERROR;
goto string_error;
} else if (c == '\\') {
- c = nextch(fp, lastch);
+ c = nextch(map, position, max);
switch (c) {
case '\\':
case '"':
*p++ = c;
+ l++;
break;
case 'n':
*p++ = '\n';
+ l++;
break;
case 'r':
*p++ = '\r';
+ l++;
break;
case 't':
*p++ = '\t';
+ l++;
break;
case '0':
case '1':
@@ -196,20 +219,21 @@ nexttoken(
case '6':
case '7':
i = c - '0';
- c = nextch(fp, lastch);
+ c = nextch(map, position, max);
for (j = 0; j < 2 && c >= '0' && c <= '7'; j++) {
i <<= 3;
i += c - '0';
- c = nextch(fp, lastch);
+ c = nextch(map, position, max);
}
- putbackch(c, lastch);
+ putbackch(position);
*p++ = (char)i;
+ l++;
break;
case 'X':
case 'x':
i = 0;
for (j = 0; j < 2; j++) {
- c = nextch(fp, lastch);
+ c = nextch(map, position, max);
i <<= 4;
if (c >= '0' && c <= '9') {
i += c - '0';
@@ -218,7 +242,7 @@ nexttoken(
} else if (c >= 'a' && c <= 'f') {
i += c - 'a' + 10;
} else {
- putbackch(c, lastch);
+ putbackch(position);
i >>= 4;
break;
}
@@ -228,25 +252,35 @@ nexttoken(
goto string_error;
}
*p++ = (char)i;
+ l++;
break;
case EOF:
- putbackch(c, lastch);
+ putbackch(position);
token = ERROR;
goto string_error;
default:
*p++ = c;
+ l++;
break;
}
} else {
*p++ = c;
+ l++;
}
}
*p = '\0';
+ l++;
token = STRING;
break;
case '#':
- while ((c = nextch(fp, lastch)) != '\n' && c != EOF) {
+ c = EOF;
+ while (*position < max) {
+ c = map[(*position)++];
+ if (c == '\n')
+ break;
}
+ if (*position == max)
+ c = EOF;
if (c == '\n') {
token = ENDOFLINE;
} else {
@@ -256,20 +290,24 @@ nexttoken(
default:
if (isalnum(c) || c == '_' || c == '-') {
p = tokenbuf;
+ l = 1;
*p++ = c;
- c = nextch(fp, lastch);
+ c = nextch(map, position, max);
while (isalnum(c) || c == '_' || c == '-') {
*p++ = c;
- c = nextch(fp, lastch);
+ l++;
+ c = nextch(map, position, max);
}
*p = '\0';
- putbackch(c, lastch);
+ l++;
+ putbackch(position);
token = KEY;
} else {
token = ERROR;
}
break;
}
+ *tokenlength = l;
string_error:
return(token);
}
@@ -411,11 +449,14 @@ get_mb_string (Xim im, char *buf, KeySym ks)
static int
parseline(
- FILE *fp,
Xim im,
- char* tokenbuf)
+ char* tokenbuf,
+ const char *map,
+ unsigned long *position,
+ unsigned long max)
{
int token;
+ unsigned long tokenlength;
DTModifier modifier_mask;
DTModifier modifier;
DTModifier tmp;
@@ -428,7 +469,6 @@ parseline(
KeySym rhs_keysym = 0;
char *rhs_string_mb;
int l;
- int lastch = 0;
char local_mb_buf[MB_LEN_MAX+1];
wchar_t local_wc_buf[LOCAL_WC_BUFSIZE], *rhs_string_wc;
char local_utf8_buf[LOCAL_UTF8_BUFSIZE], *rhs_string_utf8;
@@ -443,7 +483,7 @@ parseline(
int i, n;
do {
- token = nexttoken(fp, tokenbuf, &lastch);
+ token = nexttoken(tokenbuf, &tokenlength, map, position, max);
} while (token == ENDOFLINE);
if (token == ENDOFFILE) {
@@ -455,7 +495,7 @@ parseline(
if ((token == KEY) && (strcmp("include", tokenbuf) == 0)) {
char *filename;
FILE *infp;
- token = nexttoken(fp, tokenbuf, &lastch);
+ token = nexttoken(tokenbuf, &tokenlength, map, position, max);
if (token != KEY && token != STRING)
goto error;
if ((filename = TransFileName(im, tokenbuf)) == NULL)
@@ -470,19 +510,19 @@ parseline(
} else if ((token == KEY) && (strcmp("None", tokenbuf) == 0)) {
modifier = 0;
modifier_mask = AllMask;
- token = nexttoken(fp, tokenbuf, &lastch);
+ token = nexttoken(tokenbuf, &tokenlength, map, position, max);
} else {
modifier_mask = modifier = 0;
exclam = False;
if (token == EXCLAM) {
exclam = True;
- token = nexttoken(fp, tokenbuf, &lastch);
+ token = nexttoken(tokenbuf, &tokenlength, map, position, max);
}
while (token == TILDE || token == KEY) {
tilde = False;
if (token == TILDE) {
tilde = True;
- token = nexttoken(fp, tokenbuf, &lastch);
+ token = nexttoken(tokenbuf, &tokenlength, map, position, max);
if (token != KEY)
goto error;
}
@@ -496,7 +536,7 @@ parseline(
} else {
modifier |= tmp;
}
- token = nexttoken(fp, tokenbuf, &lastch);
+ token = nexttoken(tokenbuf, &tokenlength, map, position, max);
}
if (exclam) {
modifier_mask = AllMask;
@@ -507,12 +547,12 @@ parseline(
goto error;
}
- token = nexttoken(fp, tokenbuf, &lastch);
+ token = nexttoken(tokenbuf, &tokenlength, map, position, max);
if (token != KEY) {
goto error;
}
- token = nexttoken(fp, tokenbuf, &lastch);
+ token = nexttoken(tokenbuf, &tokenlength, map, position, max);
if (token != GREATER) {
goto error;
}
@@ -528,12 +568,12 @@ parseline(
n++;
if( n >= SEQUENCE_MAX )
goto error;
- token = nexttoken(fp, tokenbuf, &lastch);
+ token = nexttoken(tokenbuf, &tokenlength, map, position, max);
} while (token != COLON);
- token = nexttoken(fp, tokenbuf, &lastch);
+ token = nexttoken(tokenbuf, &tokenlength, map, position, max);
if (token == STRING) {
- l = strlen(tokenbuf) + 1;
+ l = tokenlength;
while (b->mbused + l > b->mbsize) {
b->mbsize = b->mbsize ? b->mbsize * 1.5 : 1024;
if (! (b->mb = Xrealloc (b->mb, b->mbsize)) )
@@ -542,13 +582,13 @@ parseline(
rhs_string_mb = &b->mb[b->mbused];
b->mbused += l;
strcpy(rhs_string_mb, tokenbuf);
- token = nexttoken(fp, tokenbuf, &lastch);
+ token = nexttoken(tokenbuf, &tokenlength, map, position, max);
if (token == KEY) {
rhs_keysym = XStringToKeysym(tokenbuf);
if (rhs_keysym == NoSymbol) {
goto error;
}
- token = nexttoken(fp, tokenbuf, &lastch);
+ token = nexttoken(tokenbuf, &tokenlength, map, position, max);
}
if (token != ENDOFLINE && token != ENDOFFILE) {
goto error;
@@ -558,7 +598,7 @@ parseline(
if (rhs_keysym == NoSymbol) {
goto error;
}
- token = nexttoken(fp, tokenbuf, &lastch);
+ token = nexttoken(tokenbuf, &tokenlength, map, position, max);
if (token != ENDOFLINE && token != ENDOFFILE) {
goto error;
}
@@ -648,7 +688,7 @@ parseline(
return(n);
error:
while (token != ENDOFLINE && token != ENDOFFILE) {
- token = nexttoken(fp, tokenbuf, &lastch);
+ token = nexttoken(tokenbuf, &tokenlength, map, position, max);
}
return(0);
}
@@ -658,18 +698,26 @@ _XimParseStringFile(
FILE *fp,
Xim im)
{
- char tb[8192];
char* tbp;
+ char* map;
struct stat st;
if (fstat (fileno (fp), &st) != -1) {
unsigned long size = (unsigned long) st.st_size;
+ unsigned long position = 0;
+ char tb[8192];
+
if (size <= sizeof tb) tbp = tb;
else tbp = malloc (size);
- if (tbp != NULL) {
- while (parseline(fp, im, tbp) >= 0) {}
- if (tbp != tb) free (tbp);
+ map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fileno (fp), 0);
+
+ if (map != MAP_FAILED) {
+ if (tbp != NULL) {
+ while (parseline(im, tbp, map, &position, size) >= 0) {}
+ if (tbp != tb) free (tbp);
+ }
+ munmap(map, st.st_size);
}
}
}
_______________________________________________
xorg-devel mailing list
[email protected]
http://lists.x.org/mailman/listinfo/xorg-devel