Subject: Re: bug#19393: 25.0.50; Emacs cannot determine coding system of ISO-8859 encoded files

From: Wolfgang Jenkner <[email-masked]>
Date: Tue, 13 Jan 2015 15:06:01 +0100

Here's a simple change in src/buffer.c that reduces the time to six
seconds or so, but only for newer versions of FreeBSD.

It takes advantage of the MAP_EXCL flag for mmap(2), which has been
recently added[1] and is also available in 10-STABLE and 10.1-RELEASE.

In percentage of user CPU time, the hotuser script[2] from the dtrace
toolkit shows a change from

[...]
emacs-25.0.50.1`decode_coding                             537   0.1%
emacs-25.0.50.1`produce_chars                            2109   0.4%
emacs-25.0.50.1`decode_coding_charset                    2544   0.5%
libc.so.7`memcpy                                       516884  98.9%

to

[...]
libc.so.7`memcpy                                          220   4.1%
bootstrap-emacs`decode_coding                             488   9.0%
bootstrap-emacs`produce_chars                            2100  38.8%
bootstrap-emacs`decode_coding_charset                    2501  46.2%

(the second column counts sample points, of which there are 1001 per
second for each CPU core)

The numbers are for the system compiler (clang 3.4.1) with default
optimizations, though they are even a bit better for gcc 4.9.

However, if the file in question is compressed
revert-buffer-with-coding-system still takes 4 minutes (the user time
being dominated to 98% by memmove).

[1] https://svnweb.freebsd.org/base?view=revision&revision=267630
[2] https://svnweb.freebsd.org/base/stable/10/cddl/contrib/dtracetoolkit/hotuser?revision=256281&view=co

>From b0233ff2274e554339da3c4606ff7fb5fc961e82 Mon Sep 17 00:00:00 2001
From: Wolfgang Jenkner <[email-masked]>
Date: Tue, 23 Dec 2014 01:50:10 +0100
Subject: [PATCH] Actually use mmap_enlarge for FreeBSD 10.1 or newer.

* src/buffer.c (MAP_EXCL): Make sure it is always defined.
(MMAP_ALLOCATED_P, mmap_enlarge): Use it.
This alleviates a performance problem due to excessive use of
memcpy(3). (Bug#19393)
---
 src/ChangeLog |  8 ++++++++
 src/buffer.c  | 15 ++++++++++++---
 2 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/src/ChangeLog b/src/ChangeLog
index 252dfd3..b526e28 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,11 @@
+2014-12-24  Wolfgang Jenkner  <[email-masked]>
+
+	Actually use mmap_enlarge for FreeBSD 10.1 or newer.
+	* buffer.c (MAP_EXCL): Make sure it is always defined.
+	(MMAP_ALLOCATED_P, mmap_enlarge): Use it.
+	This alleviates a performance problem due to excessive use of
+	memcpy(3). (Bug#19393)
+
 2015-01-12  Paul Eggert  <[email-masked]>
 
 	Port to 32-bit MingGW --with-wide-int
diff --git a/src/buffer.c b/src/buffer.c
index d0ffe67d9..8a97f3d 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -4683,10 +4683,19 @@ static bool mmap_initialized_p;
 
    Default is to conservatively assume the address range is occupied by
    something else.  This can be overridden by system configuration
-   files if system-specific means to determine this exists.  */
+   files if system-specific means to determine this exists.
+
+   However, if MAP_EXCL is defined assume that it is an mmap flag
+   which, combined with MAP_FIXED, has FreeBSD semantics, viz., the
+   mapping request will fail if a mapping already exists within the
+   range (the flag was first present in release 10.1).  */
+
+#ifndef MAP_EXCL
+#define MAP_EXCL 0
+#endif
 
 #ifndef MMAP_ALLOCATED_P
-#define MMAP_ALLOCATED_P(start, end) 1
+#define MMAP_ALLOCATED_P(start, end) (!MAP_EXCL)
 #endif
 
 /* Perform necessary initializations for the use of mmap.  */
@@ -4770,7 +4779,7 @@ mmap_enlarge (struct mmap_region *r, int npages)
 	  void *p;
 
 	  p = mmap (region_end, nbytes, PROT_READ | PROT_WRITE,
-		    MAP_ANON | MAP_PRIVATE | MAP_FIXED, mmap_fd, 0);
+		    MAP_ANON | MAP_EXCL | MAP_PRIVATE | MAP_FIXED, mmap_fd, 0);
 	  if (p == MAP_FAILED)
 	    ; /* fprintf (stderr, "mmap: %s\n", emacs_strerror (errno)); */
 	  else if (p != region_end)
-- 
2.2.1