Subject: bug#78340: closed (Re: bug#78340: [PATCH] New option for comp *.eln file name by the file timestamp of *.el)

From: [email-masked] (GNU bug Tracking System)
Date: Sat, 24 May 2025 09:03:02 +0000

Your bug report

#78340: [PATCH] New option for comp *.eln file name by the file timestamp of *.el

which was filed against the emacs package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
78340: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=78340
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: bug#78340: [PATCH] New option for comp *.eln file name by the file timestamp of *.el
From: Eli Zaretskii <[email-masked]>
To: [email-masked]
Cc: [email-masked], [email-masked], [email-masked]
Date: Sat, 24 May 2025 12:01:59 +0300
List-Id: <debbugs-submit.debbugs.gnu.org>

> Cc: [email-masked], [email-masked], [email-masked]
> Date: Mon, 12 May 2025 22:11:02 +0300
> From: Eli Zaretskii <[email-masked]>
> 
> > From: Lin Sun <[email-masked]>
> > CC: "[email-masked]" <[email-masked]>, "[email-masked]"
> > 	<[email-masked]>
> > Date: Mon, 12 May 2025 16:38:06 +0000
> > msip_labels:
> > 
> > From: Eli Zaretskii <[email-masked]>
> > Sent: Monday, May 12, 2025 02:24 PM
> > > ... which will probably be slow on Windows
> > > for the same reason computing the content hash is slow...
> > 
> > I want highlight reading a .el file will call windows api OpenFile/ReadFile.../CloseFile.
> > Here is an example that Emacs try to read the .el file to calculate the .eln name, it had called "ReadFile()" 6 time to read full content.
> 
> Yes, because Emacs reads files in chunks of 32KB.
> 
> > If Emacs uses timestamp, just call Getattribute() function, will reduce counts on windows file api calling.
> 
> I tried to explain why relying on time stamps is not reliable enough
> in this case, it brings too high risk of loading an incompatible .eln
> file.
> 
> In Emacs, we value correctness before speed.

No further comments, so I'm now closing this bug.

Subject: [PATCH] New option for comp *.eln file name by the file timestamp of *.el
From: Lin Sun <[email-masked]>
To: "[email-masked]" <[email-masked]>
Date: Sat, 10 May 2025 00:07:52 +0000
List-Id: <debbugs-submit.debbugs.gnu.org>

Hi,

Currently Emacs with native comp will comp .eln file name by the full context of the .el or .el.gz file in function "comp-el-to-eln-rel-filename".
For example, emacs startup will require the simple.elc, then have to read full of simple.el.gz to calculate the name simple-X-Y.eln. 

That's slow on Windows.

This patch introduced a new option "fts" (file time stamp) for "--with-native-compile", it will let the function "comp-el-to-eln-rel-filename" to get the .eln name by reading the .el/.el.gz file timestamp, make emacs faster on Windows. On my Windows testing env, the  Emacs startup up time was reduced from 8s to 6.5s with 386 packages, speedup ~20%.

The option can be combined with the exists option "aot", like "--with-native-compile=aot,fts".

This patch is safe for Emacs Windows release, which building with native compile enabled, but does not ship the libgccjit.dll. So the shipped *.eln is like constant files, user won't be able to recompile one; then this patch is safe for the scenario. 

Please help review this new option. Thanks

Best Regards
Lin

From a898a3c2cfec857a677ef54fd4c4e49e4ec6bacb Mon Sep 17 00:00:00 2001
From: Lin Sun <[email-masked]>
Date: Mon, 5 May 2025 06:30:02 +0000
Subject: [PATCH] New option for comp *.eln file name by the file timestamp of
 *.el

* configure.ac: New option "fts" for native compilation
* src/comp.c: Hash the file time stamp instead of file full content
---
 configure.ac | 38 ++++++++++++++++++++++++++++----------
 src/comp.c   | 14 ++++++++++++++
 2 files changed, 42 insertions(+), 10 deletions(-)

diff --git a/configure.ac b/configure.ac
index fddb2b9be3c..7da31718926 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1732,6 +1732,7 @@ AC_DEFUN
 	   [gl_GCC_VERSION_IFELSE([5], [3], [gl_gcc_warnings=warn-only])])])])])
 
 NATIVE_COMPILATION_AOT=no
+ENABLE_NATIVE_COMP_FTS=no
 AC_ARG_WITH([native-compilation],
   [AS_HELP_STRING([--with-native-compilation@<:@=TYPE@:>@],
                   [compile with Emacs Lisp native compiler support.  The TYPE
@@ -1739,20 +1740,33 @@ AC_DEFUN
 		   preloaded Lisp files; 'no' means to disable it;
 		   'aot' will make the build process compile all the Lisp
 		   files in the tree natively ahead of time.  (This will
-		   usually be quite slow.)])],
+		   usually be quite slow.) Addtional 'fts' will let the Emacs
+		   locate a eln file based on file time stamp otherthan
+		   default full content of a elc file.])],
   [
-  case $withval in
-     aot)
-       withval=yes
-       NATIVE_COMPILATION_AOT=yes
-       ;;
-     yes|no) ;;
-     *)      AC_MSG_ERROR([bad value $withval for native-compilation option]) ;;
-   esac
-   with_native_compilation=$withval],
+  IFS="${IFS=	}"; ac_save_IFS="$IFS"; IFS="$IFS,"
+  for val in $withval; do
+    case $val in
+      aot) NATIVE_COMPILATION_AOT=yes ;;
+      fts) ENABLE_NATIVE_COMP_FTS=yes ;;
+      yes|no) ;;
+      *)      AC_MSG_ERROR([bad value $withval for native-compilation option]) ;;
+    esac
+    IFS="$ac_save_IFS"
+    if test "$ENABLE_NATIVE_COMP_FTS" = "yes" \
+      || test "ENABLE_NATIVE_COMP_FTS" = "yes"; then
+      if test "$with_native_compilation" = "no"; then
+	  AC_MSG_ERROR([bad value $withval for native-compilation option])
+      else
+	  with_native_compilation=yes
+      fi
+    fi
+  done
+  ],
   [with_native_compilation=default]
 )
 AC_SUBST([NATIVE_COMPILATION_AOT])
+AC_SUBST([ENABLE_NATIVE_COMP_FTS])
 
 AC_ARG_ENABLE([check-lisp-object-type],
   [AS_HELP_STRING([--enable-check-lisp-object-type],
@@ -5273,6 +5287,10 @@ AC_DEFUN
     AC_DEFINE([HAVE_NATIVE_COMP], [1],
       [Define to 1 if native compiler is available.])
 
+    if test "$ENABLE_NATIVE_COMP_FTS" = "yes"; then
+      AC_DEFINE([ENABLE_NATIVE_COMP_FTS], [1],
+        [Define to 1 if native-compilation based on file timestamp.])
+    fi
     CFLAGS=$SAVE_CFLAGS
     LIBS=$SAVE_LIBS
 fi
diff --git a/src/comp.c b/src/comp.c
index 219a482931e..94fb77a6c30 100644
--- a/src/comp.c
+++ b/src/comp.c
@@ -30,6 +30,7 @@
 #include <signal.h>
 #include <libgccjit.h>
 #include <epaths.h>
+#include <stat-time.h>
 
 #include "window.h"
 #include "dynlib.h"
@@ -738,6 +739,18 @@ comp_hash_source_file (Lisp_Object filename)
 	      filename);
 #endif
   Lisp_Object encoded_filename = ENCODE_FILE (filename);
+#ifdef ENABLE_NATIVE_COMP_FTS
+  struct stat st1;
+  Lisp_Object digest = make_uninit_string (MD5_DIGEST_SIZE * 2);
+  (void)is_gz;			/* USUED */
+  if (emacs_fstatat (AT_FDCWD, SSDATA (encoded_filename), &st1, 0) == 0)
+    {
+      struct timespec ts = get_stat_mtime(&st1);
+      md5_buffer ((char *)&ts, sizeof (ts), SSDATA (digest));
+    }
+  else
+    xsignal2 (Qfile_notify_error, build_string ("hashing failed"), filename);
+#else
   FILE *f = emacs_fopen (SSDATA (encoded_filename), is_gz ? "rb" : "r");
 
   if (!f)
@@ -756,6 +769,7 @@ comp_hash_source_file (Lisp_Object filename)
 
   if (res)
     xsignal2 (Qfile_notify_error, build_string ("hashing failed"), filename);
+#endif
 
   hexbuf_digest (SSDATA (digest), SSDATA (digest), MD5_DIGEST_SIZE);
 
-- 
2.34.1