all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Dmitry Antipov <dmantipov@yandex.ru>
To: Paul Eggert <eggert@cs.ucla.edu>
Cc: Stefan Monnier <monnier@IRO.UMontreal.CA>,
	Emacs development discussions <emacs-devel@gnu.org>
Subject: Re: Benchmarking temporary Lisp objects [Was: Re: [RFC] temporary Lisp_Strings]
Date: Fri, 05 Sep 2014 08:00:33 +0400	[thread overview]
Message-ID: <54093561.2010507@yandex.ru> (raw)
In-Reply-To: <54088D63.8010406@cs.ucla.edu>

[-- Attachment #1: Type: text/plain, Size: 803 bytes --]

On 09/04/2014 08:03 PM, Paul Eggert wrote:

> For vectors the macro needs to generate a series of declarations and
> statements  rather than an expression.  It's less clean, but it's good
> enough.  Something like the attached, say.

IMO this is a bit overengineered.  In particular, the whole thing is to
allocate short-lived objects which are usually small. This means that
!issmall branch is unlikely to be taken but requires SAFE_xxx anyway.
Moreover, I think we need a very special benchmark to see a difference
between alloca and VLA (if any), thus using the latter at any cost doesn't
worth an extra complexity.  So, although I have no strong objections
about your version, I'm voting for simpler and cleaner version with
alloca/fallback to regular GC for vectors and strings.  Stefan?

Dmitry



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: local_objects.patch --]
[-- Type: text/x-patch; name="local_objects.patch", Size: 6654 bytes --]

=== modified file 'src/alloc.c'
--- src/alloc.c	2014-08-29 07:29:47 +0000
+++ src/alloc.c	2014-09-05 02:43:56 +0000
@@ -7118,8 +7118,29 @@
 	   file, line, msg);
   terminate_due_to_signal (SIGABRT, INT_MAX);
 }
-#endif
-\f
+
+/* Stress alloca with inconveniently sized requests and check
+   whether all allocated areas may be used for Lisp_Object.  */
+
+NO_INLINE static void
+verify_alloca (void)
+{
+  int i;
+  enum { ALLOCA_CHECK_MAX = 256 };
+  /* Start from size of the smallest Lisp object.  */
+  for (i = sizeof (struct Lisp_Cons); i <= ALLOCA_CHECK_MAX; i++)
+    {
+      char *ptr = alloca (i);
+      eassert (pointer_valid_for_lisp_object (ptr));
+    }
+}
+
+#else /* not ENABLE_CHECKING */
+
+#define verify_alloca() ((void) 0)
+
+#endif /* ENABLE_CHECKING */
+
 /* Initialization.  */
 
 void
@@ -7129,6 +7150,8 @@
   purebeg = PUREBEG;
   pure_size = PURESIZE;
 
+  verify_alloca ();
+
 #if GC_MARK_STACK || defined GC_MALLOC_CHECK
   mem_init ();
   Vdead = make_pure_string ("DEAD", 4, 4, 0);

=== modified file 'src/character.h'
--- src/character.h	2014-07-08 07:17:04 +0000
+++ src/character.h	2014-09-04 16:18:48 +0000
@@ -644,8 +644,6 @@
                         const unsigned char **, int *);
 
 extern int translate_char (Lisp_Object, int c);
-extern void parse_str_as_multibyte (const unsigned char *,
-				    ptrdiff_t, ptrdiff_t *, ptrdiff_t *);
 extern ptrdiff_t count_size_as_multibyte (const unsigned char *, ptrdiff_t);
 extern ptrdiff_t str_as_multibyte (unsigned char *, ptrdiff_t, ptrdiff_t,
 				   ptrdiff_t *);

=== modified file 'src/lisp.h'
--- src/lisp.h	2014-09-02 18:05:00 +0000
+++ src/lisp.h	2014-09-05 02:45:18 +0000
@@ -298,6 +298,13 @@
 # endif
 #endif
 
+/* Stolen from gnulib.  */
+#if (__GNUC__ || __HP_cc || __HP_aCC || __IBMC__	\
+     || __IBMCPP__ || __ICC || 0x5110 <= __SUNPRO_C)
+#define GCALIGNED __attribute__ ((aligned (GCALIGNMENT)))
+#else
+#define GCALIGNED /* empty */
+#endif
 
 /* Some operations are so commonly executed that they are implemented
    as macros, not functions, because otherwise runtime performance would
@@ -1016,7 +1023,7 @@
 
 typedef struct interval *INTERVAL;
 
-struct Lisp_Cons
+struct GCALIGNED Lisp_Cons
   {
     /* Car of this cons cell.  */
     Lisp_Object car;
@@ -3622,6 +3629,10 @@
 /* Defined in vm-limit.c.  */
 extern void memory_warnings (void *, void (*warnfun) (const char *));
 
+/* Defined in character.c.  */
+extern void parse_str_as_multibyte (const unsigned char *, ptrdiff_t,
+				    ptrdiff_t *, ptrdiff_t *);
+
 /* Defined in alloc.c.  */
 extern void check_pure_size (void);
 extern void free_misc (Lisp_Object);
@@ -4533,6 +4544,111 @@
       memory_full (SIZE_MAX);				       \
   } while (false)
 
+/* Use the following functions to allocate temporary (function-
+   or block-scoped) conses, vectors, and strings.  These objects
+   are not managed by GC, and passing them out of their scope
+   causes an immediate crash in GC.  */
+
+#if (__GNUC__ || __HP_cc || __HP_aCC || __IBMC__	\
+     || __IBMCPP__ || __ICC || 0x5110 <= __SUNPRO_C)
+
+/* Allocate temporary block-scoped cons.  This version assumes
+   that stack-allocated Lisp_Cons is always aligned properly.  */
+
+#define scoped_cons(car, cdr)						\
+  make_lisp_ptr (&((struct Lisp_Cons) { car, { cdr } }), Lisp_Cons)
+
+#else /* not __GNUC__ etc... */
+
+/* Helper function for an alternate scoped cons, see below.  */				     
+
+INLINE Lisp_Object
+scoped_cons_init (void *ptr, Lisp_Object x, Lisp_Object y)
+{
+  struct Lisp_Cons *c = (struct Lisp_Cons *)
+    (((uintptr_t) ptr + (GCALIGNMENT - 1)) & ~(GCALIGNMENT - 1));
+  c->car = x;
+  c->u.cdr = y;
+  return make_lisp_ptr (c, Lisp_Cons);
+}
+
+/* This version uses explicit alignment.  */
+
+#define scoped_cons(car, cdr)						\
+  scoped_cons_init ((char[sizeof (struct Lisp_Cons)			\
+			  + (GCALIGNMENT - 1)]) {}, (car), (cdr))
+
+#endif /* __GNUC__ etc... */
+
+/* True if Lisp_Object may be placed at P.  Used only
+   under ENABLE_CHECKING and optimized away otherwise.  */
+
+INLINE bool
+pointer_valid_for_lisp_object (void *p)
+{
+  uintptr_t v = (uintptr_t) p;
+  return !(USE_LSB_TAG ? (v & ~VALMASK) : v >> VALBITS);
+}
+
+/* Helper function for build_local_vector, see below.  */
+
+INLINE Lisp_Object
+local_vector_init (uintptr_t addr, ptrdiff_t length, Lisp_Object init)
+{
+  ptrdiff_t i;
+  struct Lisp_Vector *v = (struct Lisp_Vector *) addr;
+
+  eassert (pointer_valid_for_lisp_object (v));
+  v->header.size = length;
+  for (i = 0; i < length; i++)
+    v->contents[i] = init;
+  return make_lisp_ptr (v, Lisp_Vectorlike);
+}
+
+/* If size permits, create temporary function-scoped vector OBJ of
+   length SIZE, with each element being INIT.  Otherwise create
+   regular GC-managed vector.  */
+
+#define build_local_vector(obj, size, init)				\
+  (MAX_ALLOCA < (size) * word_size + header_size			\
+   ? obj = Fmake_vector (make_number (size), (init))			\
+   : (obj = XIL ((uintptr_t) alloca					\
+		 ((size) * word_size + header_size)),			\
+      obj = local_vector_init ((uintptr_t) XLI (obj), (size), (init))))
+
+/* Helper function for build_local_string, see below.  */
+
+INLINE Lisp_Object
+local_string_init (uintptr_t addr, const char *data, ptrdiff_t size)
+{
+  ptrdiff_t nchars, nbytes;
+  struct Lisp_String *s = (struct Lisp_String *) addr;
+
+  eassert (pointer_valid_for_lisp_object (s));
+  parse_str_as_multibyte ((const unsigned char *) data,
+			  size, &nchars, &nbytes);
+  s->data = (unsigned char *) (addr + sizeof *s);
+  s->intervals = NULL;
+  memcpy (s->data, data, size);
+  s->data[size] = '\0';
+  if (size == nchars || size != nbytes)
+    s->size = size, s->size_byte = -1;
+  else
+    s->size = nchars, s->size_byte = nbytes;
+  return make_lisp_ptr (s, Lisp_String);
+}
+
+/* If size permits, create temporary function-scoped string OBJ
+   with contents DATA of length NBYTES.  Otherwise create regular
+   GC-managed string.  */
+
+#define build_local_string(obj, data, nbytes)				\
+  (MAX_ALLOCA < (nbytes) + sizeof (struct Lisp_String)			\
+   ? obj = make_string ((data), (nbytes))				\
+   : (obj = XIL ((uintptr_t) alloca					\
+		 ((nbytes) + sizeof (struct Lisp_String))),		\
+      obj = local_string_init ((uintptr_t) XLI (obj), data, nbytes)))
+
 /* Loop over all tails of a list, checking for cycles.
    FIXME: Make tortoise and n internal declarations.
    FIXME: Unroll the loop body so we don't need `n'.  */


  reply	other threads:[~2014-09-05  4:00 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-09-02 12:55 [RFC] temporary Lisp_Strings Dmitry Antipov
2014-09-02 13:21 ` Andreas Schwab
2014-09-02 13:47   ` Dmitry Antipov
2014-09-02 14:14     ` Andreas Schwab
2014-09-02 15:00     ` Eli Zaretskii
2014-09-02 14:00 ` Stefan Monnier
2014-09-02 15:13   ` Dmitry Antipov
2014-09-02 17:32     ` Stefan Monnier
2014-09-03 10:23       ` Benchmarking temporary Lisp objects [Was: Re: [RFC] temporary Lisp_Strings] Dmitry Antipov
2014-09-03 13:14         ` Stefan Monnier
2014-09-03 14:39         ` Paul Eggert
2014-09-03 15:39           ` Dmitry Antipov
2014-09-03 16:42             ` Paul Eggert
2014-09-03 17:47               ` Stefan Monnier
2014-09-03 18:00                 ` Paul Eggert
2014-09-04  4:59               ` Dmitry Antipov
2014-09-04  5:13                 ` Paul Eggert
2014-09-04  5:51                   ` Dmitry Antipov
2014-09-04  6:45                     ` Paul Eggert
2014-09-04 13:11                     ` Stefan Monnier
2014-09-04 13:37                       ` Dmitry Antipov
2014-09-04 14:46                         ` Dmitry Antipov
2014-09-04 16:03                           ` Paul Eggert
2014-09-05  4:00                             ` Dmitry Antipov [this message]
2014-09-05  4:24                               ` Stefan Monnier
2014-09-05  9:28                                 ` Dmitry Antipov
2014-09-05  7:15                               ` Paul Eggert
2014-09-05  9:16                                 ` Dmitry Antipov
2014-09-05 14:35                                   ` Paul Eggert
2014-09-05 15:35                                 ` Stefan Monnier
2014-09-08 10:33                                   ` Dmitry Antipov
2014-09-08 12:01                                     ` Dmitry Antipov
2014-09-08 13:30                                       ` Stefan Monnier
2014-09-08 12:44                                     ` Stefan Monnier
2014-09-08 13:30                                       ` Stefan Monnier
2014-09-02 14:37 ` [RFC] temporary Lisp_Strings Paul Eggert
2014-09-02 15:24   ` Dmitry Antipov
2014-09-02 15:28   ` Dmitry Antipov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=54093561.2010507@yandex.ru \
    --to=dmantipov@yandex.ru \
    --cc=eggert@cs.ucla.edu \
    --cc=emacs-devel@gnu.org \
    --cc=monnier@IRO.UMontreal.CA \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.