From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Dmitry Antipov Newsgroups: gmane.emacs.devel Subject: Re: Benchmarking temporary Lisp objects [Was: Re: [RFC] temporary Lisp_Strings] Date: Fri, 05 Sep 2014 08:00:33 +0400 Message-ID: <54093561.2010507@yandex.ru> References: <5405BE5D.1090003@yandex.ru> <5405DE8B.4050201@yandex.ru> <5406EC21.4060200@yandex.ru> <5407281C.3090302@cs.ucla.edu> <54073621.2040403@yandex.ru> <540744F5.2010804@cs.ucla.edu> <5407F1B7.6090704@yandex.ru> <5407F4E6.2040809@cs.ucla.edu> <5407FDF4.7020504@yandex.ru> <54086B1A.8070506@yandex.ru> <54087B5E.10402@yandex.ru> <54088D63.8010406@cs.ucla.edu> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------020605020603000701060900" X-Trace: ger.gmane.org 1409889673 6766 80.91.229.3 (5 Sep 2014 04:01:13 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Fri, 5 Sep 2014 04:01:13 +0000 (UTC) Cc: Stefan Monnier , Emacs development discussions To: Paul Eggert Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Fri Sep 05 06:01:07 2014 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1XPkhu-0006KN-4a for ged-emacs-devel@m.gmane.org; Fri, 05 Sep 2014 06:01:06 +0200 Original-Received: from localhost ([::1]:55320 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XPkht-0006hO-IK for ged-emacs-devel@m.gmane.org; Fri, 05 Sep 2014 00:01:05 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:34674) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XPkha-0006hI-8N for emacs-devel@gnu.org; Fri, 05 Sep 2014 00:00:53 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1XPkhT-0006GL-5T for emacs-devel@gnu.org; Fri, 05 Sep 2014 00:00:46 -0400 Original-Received: from forward3l.mail.yandex.net ([84.201.143.136]:46050) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XPkhS-0006Fk-ON for emacs-devel@gnu.org; Fri, 05 Sep 2014 00:00:39 -0400 Original-Received: from smtp4h.mail.yandex.net (smtp4h.mail.yandex.net [84.201.186.21]) by forward3l.mail.yandex.net (Yandex) with ESMTP id 781B91501340; Fri, 5 Sep 2014 08:00:35 +0400 (MSK) Original-Received: from smtp4h.mail.yandex.net (localhost [127.0.0.1]) by smtp4h.mail.yandex.net (Yandex) with ESMTP id B34302C4C92; Fri, 5 Sep 2014 08:00:34 +0400 (MSK) Original-Received: from unknown (unknown [37.139.80.10]) by smtp4h.mail.yandex.net (nwsmtp/Yandex) with ESMTPSA id 5LvhAyvO6n-0YmON61W; Fri, 5 Sep 2014 08:00:34 +0400 (using TLSv1.2 with cipher AES128-SHA (128/128 bits)) (Client certificate not present) X-Yandex-Uniq: 251093cd-5ef4-4810-a18c-9c6d89ab53bc DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex.ru; s=mail; t=1409889634; bh=r9Hrj4JoCBn2IJHiY5idQ8t0Gkok1dwt6iZuE+jDP+4=; h=Message-ID:Date:From:User-Agent:MIME-Version:To:CC:Subject: References:In-Reply-To:Content-Type; b=ps5berGgArkWn49tLYJu2Qgt8CNxPBlatdHFCApuI5AYMpwpUfwGeY0nfRIsqRH52 wMyGQGkTDXRwCOISDZvagcfi7xNo0AOjGVCJgClJO1jMpvUuwQeulpfCO10+3Q/YCa wb3S8Qnx4ZNl9UveD49AekKWxekQuoOSJA3M64iA= Authentication-Results: smtp4h.mail.yandex.net; dkim=pass header.i=@yandex.ru User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.0 In-Reply-To: <54088D63.8010406@cs.ucla.edu> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [generic] [fuzzy] X-Received-From: 84.201.143.136 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:174026 Archived-At: This is a multi-part message in MIME format. --------------020605020603000701060900 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit 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 --------------020605020603000701060900 Content-Type: text/x-patch; name="local_objects.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="local_objects.patch" =3D=3D=3D 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 -=0C + +/* 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 =3D 256 }; + /* Start from size of the smallest Lisp object. */ + for (i =3D sizeof (struct Lisp_Cons); i <=3D ALLOCA_CHECK_MAX; i++) + { + char *ptr =3D alloca (i); + eassert (pointer_valid_for_lisp_object (ptr)); + } +} + +#else /* not ENABLE_CHECKING */ + +#define verify_alloca() ((void) 0) + +#endif /* ENABLE_CHECKING */ + /* Initialization. */ =20 void @@ -7129,6 +7150,8 @@ purebeg =3D PUREBEG; pure_size =3D PURESIZE; =20 + verify_alloca (); + #if GC_MARK_STACK || defined GC_MALLOC_CHECK mem_init (); Vdead =3D make_pure_string ("DEAD", 4, 4, 0); =3D=3D=3D 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 *); =20 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 *); =3D=3D=3D 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 =20 +/* Stolen from gnulib. */ +#if (__GNUC__ || __HP_cc || __HP_aCC || __IBMC__ \ + || __IBMCPP__ || __ICC || 0x5110 <=3D __SUNPRO_C) +#define GCALIGNED __attribute__ ((aligned (GCALIGNMENT))) +#else +#define GCALIGNED /* empty */ +#endif =20 /* Some operations are so commonly executed that they are implemented as macros, not functions, because otherwise runtime performance would= @@ -1016,7 +1023,7 @@ =20 typedef struct interval *INTERVAL; =20 -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 *)); =20 +/* 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) =20 +/* 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 <=3D __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 =3D (struct Lisp_Cons *) + (((uintptr_t) ptr + (GCALIGNMENT - 1)) & ~(GCALIGNMENT - 1)); + c->car =3D x; + c->u.cdr =3D 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 =3D (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 =3D (struct Lisp_Vector *) addr; + + eassert (pointer_valid_for_lisp_object (v)); + v->header.size =3D length; + for (i =3D 0; i < length; i++) + v->contents[i] =3D 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 =3D Fmake_vector (make_number (size), (init)) \ + : (obj =3D XIL ((uintptr_t) alloca \ + ((size) * word_size + header_size)), \ + obj =3D 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 =3D (struct Lisp_String *) addr; + + eassert (pointer_valid_for_lisp_object (s)); + parse_str_as_multibyte ((const unsigned char *) data, + size, &nchars, &nbytes); + s->data =3D (unsigned char *) (addr + sizeof *s); + s->intervals =3D NULL; + memcpy (s->data, data, size); + s->data[size] =3D '\0'; + if (size =3D=3D nchars || size !=3D nbytes) + s->size =3D size, s->size_byte =3D -1; + else + s->size =3D nchars, s->size_byte =3D 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 =3D make_string ((data), (nbytes)) \ + : (obj =3D XIL ((uintptr_t) alloca \ + ((nbytes) + sizeof (struct Lisp_String))), \ + obj =3D 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'. */ --------------020605020603000701060900--