aboutsummaryrefslogtreecommitdiffstats
path: root/src/alloc.c
diff options
context:
space:
mode:
authorPaul Eggert2020-01-02 18:02:32 -0800
committerPaul Eggert2020-01-02 18:11:25 -0800
commitdd0e4d4e16fbbba6189610c7abb73d8b0efc6e5e (patch)
treee085817d80d71e20ec7230c9ed59a4793174f4d5 /src/alloc.c
parentd36adb544d984b91c70f6194da01344e4b2b6fc9 (diff)
downloademacs-dd0e4d4e16fbbba6189610c7abb73d8b0efc6e5e.tar.gz
emacs-dd0e4d4e16fbbba6189610c7abb73d8b0efc6e5e.zip
Let the OS clear large new objects
Prefer calloc to malloc+memset when allocating large zeroed objects. This avoids page thrashing when (make-vector 1000000000 nil) allocates a large nil vector, as Emacs need not touch the vector’s pages. This wins on platforms like GNU/Linux where calloc can fiddle with page tables to create a block of memory that is lazily zeroed. * src/alloc.c (lisp_malloc, lmalloc, allocate_vectorlike): New arg CLEARIT to tell callee whether to use malloc or calloc. All callers changed. (allocate_clear_vector, allocate_nil_vector): New functions. * src/alloc.c (xzalloc, make_vector): * src/lisp.h (make_nil_vector): Prefer calloc to malloc + memset(...,0,...).
Diffstat (limited to 'src/alloc.c')
-rw-r--r--src/alloc.c87
1 files changed, 57 insertions, 30 deletions
diff --git a/src/alloc.c b/src/alloc.c
index 1c6b664b220..dbe37f44d7c 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -694,7 +694,7 @@ malloc_unblock_input (void)
694 malloc_probe (size); \ 694 malloc_probe (size); \
695 } while (0) 695 } while (0)
696 696
697static void *lmalloc (size_t) ATTRIBUTE_MALLOC_SIZE ((1)); 697static void *lmalloc (size_t, bool) ATTRIBUTE_MALLOC_SIZE ((1));
698static void *lrealloc (void *, size_t); 698static void *lrealloc (void *, size_t);
699 699
700/* Like malloc but check for no memory and block interrupt input. */ 700/* Like malloc but check for no memory and block interrupt input. */
@@ -705,7 +705,7 @@ xmalloc (size_t size)
705 void *val; 705 void *val;
706 706
707 MALLOC_BLOCK_INPUT; 707 MALLOC_BLOCK_INPUT;
708 val = lmalloc (size); 708 val = lmalloc (size, false);
709 MALLOC_UNBLOCK_INPUT; 709 MALLOC_UNBLOCK_INPUT;
710 710
711 if (!val && size) 711 if (!val && size)
@@ -722,12 +722,11 @@ xzalloc (size_t size)
722 void *val; 722 void *val;
723 723
724 MALLOC_BLOCK_INPUT; 724 MALLOC_BLOCK_INPUT;
725 val = lmalloc (size); 725 val = lmalloc (size, true);
726 MALLOC_UNBLOCK_INPUT; 726 MALLOC_UNBLOCK_INPUT;
727 727
728 if (!val && size) 728 if (!val && size)
729 memory_full (size); 729 memory_full (size);
730 memset (val, 0, size);
731 MALLOC_PROBE (size); 730 MALLOC_PROBE (size);
732 return val; 731 return val;
733} 732}
@@ -743,7 +742,7 @@ xrealloc (void *block, size_t size)
743 /* We must call malloc explicitly when BLOCK is 0, since some 742 /* We must call malloc explicitly when BLOCK is 0, since some
744 reallocs don't do this. */ 743 reallocs don't do this. */
745 if (! block) 744 if (! block)
746 val = lmalloc (size); 745 val = lmalloc (size, false);
747 else 746 else
748 val = lrealloc (block, size); 747 val = lrealloc (block, size);
749 MALLOC_UNBLOCK_INPUT; 748 MALLOC_UNBLOCK_INPUT;
@@ -939,7 +938,7 @@ void *lisp_malloc_loser EXTERNALLY_VISIBLE;
939#endif 938#endif
940 939
941static void * 940static void *
942lisp_malloc (size_t nbytes, enum mem_type type) 941lisp_malloc (size_t nbytes, bool clearit, enum mem_type type)
943{ 942{
944 register void *val; 943 register void *val;
945 944
@@ -949,7 +948,7 @@ lisp_malloc (size_t nbytes, enum mem_type type)
949 allocated_mem_type = type; 948 allocated_mem_type = type;
950#endif 949#endif
951 950
952 val = lmalloc (nbytes); 951 val = lmalloc (nbytes, clearit);
953 952
954#if ! USE_LSB_TAG 953#if ! USE_LSB_TAG
955 /* If the memory just allocated cannot be addressed thru a Lisp 954 /* If the memory just allocated cannot be addressed thru a Lisp
@@ -1290,16 +1289,21 @@ laligned (void *p, size_t size)
1290 that's never really exercised) for little benefit. */ 1289 that's never really exercised) for little benefit. */
1291 1290
1292static void * 1291static void *
1293lmalloc (size_t size) 1292lmalloc (size_t size, bool clearit)
1294{ 1293{
1295#ifdef USE_ALIGNED_ALLOC 1294#ifdef USE_ALIGNED_ALLOC
1296 if (! MALLOC_IS_LISP_ALIGNED && size % LISP_ALIGNMENT == 0) 1295 if (! MALLOC_IS_LISP_ALIGNED && size % LISP_ALIGNMENT == 0)
1297 return aligned_alloc (LISP_ALIGNMENT, size); 1296 {
1297 void *p = aligned_alloc (LISP_ALIGNMENT, size);
1298 if (clearit && p)
1299 memclear (p, size);
1300 return p;
1301 }
1298#endif 1302#endif
1299 1303
1300 while (true) 1304 while (true)
1301 { 1305 {
1302 void *p = malloc (size); 1306 void *p = clearit ? calloc (1, size) : malloc (size);
1303 if (laligned (p, size)) 1307 if (laligned (p, size))
1304 return p; 1308 return p;
1305 free (p); 1309 free (p);
@@ -1377,7 +1381,7 @@ make_interval (void)
1377 if (interval_block_index == INTERVAL_BLOCK_SIZE) 1381 if (interval_block_index == INTERVAL_BLOCK_SIZE)
1378 { 1382 {
1379 struct interval_block *newi 1383 struct interval_block *newi
1380 = lisp_malloc (sizeof *newi, MEM_TYPE_NON_LISP); 1384 = lisp_malloc (sizeof *newi, false, MEM_TYPE_NON_LISP);
1381 1385
1382 newi->next = interval_block; 1386 newi->next = interval_block;
1383 interval_block = newi; 1387 interval_block = newi;
@@ -1730,7 +1734,7 @@ allocate_string (void)
1730 add all the Lisp_Strings in it to the free-list. */ 1734 add all the Lisp_Strings in it to the free-list. */
1731 if (string_free_list == NULL) 1735 if (string_free_list == NULL)
1732 { 1736 {
1733 struct string_block *b = lisp_malloc (sizeof *b, MEM_TYPE_STRING); 1737 struct string_block *b = lisp_malloc (sizeof *b, false, MEM_TYPE_STRING);
1734 int i; 1738 int i;
1735 1739
1736 b->next = string_blocks; 1740 b->next = string_blocks;
@@ -1813,7 +1817,7 @@ allocate_string_data (struct Lisp_String *s,
1813 mallopt (M_MMAP_MAX, 0); 1817 mallopt (M_MMAP_MAX, 0);
1814#endif 1818#endif
1815 1819
1816 b = lisp_malloc (size + GC_STRING_EXTRA, MEM_TYPE_NON_LISP); 1820 b = lisp_malloc (size + GC_STRING_EXTRA, false, MEM_TYPE_NON_LISP);
1817 1821
1818#ifdef DOUG_LEA_MALLOC 1822#ifdef DOUG_LEA_MALLOC
1819 if (!mmap_lisp_allowed_p ()) 1823 if (!mmap_lisp_allowed_p ())
@@ -1831,7 +1835,7 @@ allocate_string_data (struct Lisp_String *s,
1831 < (needed + GC_STRING_EXTRA))) 1835 < (needed + GC_STRING_EXTRA)))
1832 { 1836 {
1833 /* Not enough room in the current sblock. */ 1837 /* Not enough room in the current sblock. */
1834 b = lisp_malloc (SBLOCK_SIZE, MEM_TYPE_NON_LISP); 1838 b = lisp_malloc (SBLOCK_SIZE, false, MEM_TYPE_NON_LISP);
1835 data = b->data; 1839 data = b->data;
1836 b->next = NULL; 1840 b->next = NULL;
1837 b->next_free = data; 1841 b->next_free = data;
@@ -3137,7 +3141,7 @@ sweep_vectors (void)
3137 at most VECTOR_ELTS_MAX. */ 3141 at most VECTOR_ELTS_MAX. */
3138 3142
3139static struct Lisp_Vector * 3143static struct Lisp_Vector *
3140allocate_vectorlike (ptrdiff_t len) 3144allocate_vectorlike (ptrdiff_t len, bool clearit)
3141{ 3145{
3142 eassert (0 < len && len <= VECTOR_ELTS_MAX); 3146 eassert (0 < len && len <= VECTOR_ELTS_MAX);
3143 ptrdiff_t nbytes = header_size + len * word_size; 3147 ptrdiff_t nbytes = header_size + len * word_size;
@@ -3151,11 +3155,15 @@ allocate_vectorlike (ptrdiff_t len)
3151#endif 3155#endif
3152 3156
3153 if (nbytes <= VBLOCK_BYTES_MAX) 3157 if (nbytes <= VBLOCK_BYTES_MAX)
3154 p = allocate_vector_from_block (vroundup (nbytes)); 3158 {
3159 p = allocate_vector_from_block (vroundup (nbytes));
3160 if (clearit)
3161 memclear (p, nbytes);
3162 }
3155 else 3163 else
3156 { 3164 {
3157 struct large_vector *lv = lisp_malloc (large_vector_offset + nbytes, 3165 struct large_vector *lv = lisp_malloc (large_vector_offset + nbytes,
3158 MEM_TYPE_VECTORLIKE); 3166 clearit, MEM_TYPE_VECTORLIKE);
3159 lv->next = large_vectors; 3167 lv->next = large_vectors;
3160 large_vectors = lv; 3168 large_vectors = lv;
3161 p = large_vector_vec (lv); 3169 p = large_vector_vec (lv);
@@ -3178,20 +3186,37 @@ allocate_vectorlike (ptrdiff_t len)
3178} 3186}
3179 3187
3180 3188
3181/* Allocate a vector with LEN slots. */ 3189/* Allocate a vector with LEN slots. If CLEARIT, clear its slots;
3190 otherwise the vector's slots are uninitialized. */
3182 3191
3183struct Lisp_Vector * 3192static struct Lisp_Vector *
3184allocate_vector (ptrdiff_t len) 3193allocate_clear_vector (ptrdiff_t len, bool clearit)
3185{ 3194{
3186 if (len == 0) 3195 if (len == 0)
3187 return XVECTOR (zero_vector); 3196 return XVECTOR (zero_vector);
3188 if (VECTOR_ELTS_MAX < len) 3197 if (VECTOR_ELTS_MAX < len)
3189 memory_full (SIZE_MAX); 3198 memory_full (SIZE_MAX);
3190 struct Lisp_Vector *v = allocate_vectorlike (len); 3199 struct Lisp_Vector *v = allocate_vectorlike (len, clearit);
3191 v->header.size = len; 3200 v->header.size = len;
3192 return v; 3201 return v;
3193} 3202}
3194 3203
3204/* Allocate a vector with LEN uninitialized slots. */
3205
3206struct Lisp_Vector *
3207allocate_vector (ptrdiff_t len)
3208{
3209 return allocate_clear_vector (len, false);
3210}
3211
3212/* Allocate a vector with LEN nil slots. */
3213
3214struct Lisp_Vector *
3215allocate_nil_vector (ptrdiff_t len)
3216{
3217 return allocate_clear_vector (len, true);
3218}
3219
3195 3220
3196/* Allocate other vector-like structures. */ 3221/* Allocate other vector-like structures. */
3197 3222
@@ -3208,7 +3233,7 @@ allocate_pseudovector (int memlen, int lisplen,
3208 eassert (lisplen <= size_max); 3233 eassert (lisplen <= size_max);
3209 eassert (memlen <= size_max + rest_max); 3234 eassert (memlen <= size_max + rest_max);
3210 3235
3211 struct Lisp_Vector *v = allocate_vectorlike (memlen); 3236 struct Lisp_Vector *v = allocate_vectorlike (memlen, false);
3212 /* Only the first LISPLEN slots will be traced normally by the GC. */ 3237 /* Only the first LISPLEN slots will be traced normally by the GC. */
3213 memclear (v->contents, zerolen * word_size); 3238 memclear (v->contents, zerolen * word_size);
3214 XSETPVECTYPESIZE (v, tag, lisplen, memlen - lisplen); 3239 XSETPVECTYPESIZE (v, tag, lisplen, memlen - lisplen);
@@ -3218,7 +3243,7 @@ allocate_pseudovector (int memlen, int lisplen,
3218struct buffer * 3243struct buffer *
3219allocate_buffer (void) 3244allocate_buffer (void)
3220{ 3245{
3221 struct buffer *b = lisp_malloc (sizeof *b, MEM_TYPE_BUFFER); 3246 struct buffer *b = lisp_malloc (sizeof *b, false, MEM_TYPE_BUFFER);
3222 3247
3223 BUFFER_PVEC_INIT (b); 3248 BUFFER_PVEC_INIT (b);
3224 /* Put B on the chain of all buffers including killed ones. */ 3249 /* Put B on the chain of all buffers including killed ones. */
@@ -3238,7 +3263,7 @@ allocate_record (EMACS_INT count)
3238 if (count > PSEUDOVECTOR_SIZE_MASK) 3263 if (count > PSEUDOVECTOR_SIZE_MASK)
3239 error ("Attempt to allocate a record of %"pI"d slots; max is %d", 3264 error ("Attempt to allocate a record of %"pI"d slots; max is %d",
3240 count, PSEUDOVECTOR_SIZE_MASK); 3265 count, PSEUDOVECTOR_SIZE_MASK);
3241 struct Lisp_Vector *p = allocate_vectorlike (count); 3266 struct Lisp_Vector *p = allocate_vectorlike (count, false);
3242 p->header.size = count; 3267 p->header.size = count;
3243 XSETPVECTYPE (p, PVEC_RECORD); 3268 XSETPVECTYPE (p, PVEC_RECORD);
3244 return p; 3269 return p;
@@ -3291,9 +3316,11 @@ See also the function `vector'. */)
3291Lisp_Object 3316Lisp_Object
3292make_vector (ptrdiff_t length, Lisp_Object init) 3317make_vector (ptrdiff_t length, Lisp_Object init)
3293{ 3318{
3294 struct Lisp_Vector *p = allocate_vector (length); 3319 bool clearit = NIL_IS_ZERO && NILP (init);
3295 for (ptrdiff_t i = 0; i < length; i++) 3320 struct Lisp_Vector *p = allocate_clear_vector (length, clearit);
3296 p->contents[i] = init; 3321 if (!clearit)
3322 for (ptrdiff_t i = 0; i < length; i++)
3323 p->contents[i] = init;
3297 return make_lisp_ptr (p, Lisp_Vectorlike); 3324 return make_lisp_ptr (p, Lisp_Vectorlike);
3298} 3325}
3299 3326
@@ -3442,7 +3469,7 @@ Its value is void, and its function definition and property list are nil. */)
3442 if (symbol_block_index == SYMBOL_BLOCK_SIZE) 3469 if (symbol_block_index == SYMBOL_BLOCK_SIZE)
3443 { 3470 {
3444 struct symbol_block *new 3471 struct symbol_block *new
3445 = lisp_malloc (sizeof *new, MEM_TYPE_SYMBOL); 3472 = lisp_malloc (sizeof *new, false, MEM_TYPE_SYMBOL);
3446 new->next = symbol_block; 3473 new->next = symbol_block;
3447 symbol_block = new; 3474 symbol_block = new;
3448 symbol_block_index = 0; 3475 symbol_block_index = 0;
@@ -3904,10 +3931,10 @@ refill_memory_reserve (void)
3904 MEM_TYPE_SPARE); 3931 MEM_TYPE_SPARE);
3905 if (spare_memory[5] == 0) 3932 if (spare_memory[5] == 0)
3906 spare_memory[5] = lisp_malloc (sizeof (struct string_block), 3933 spare_memory[5] = lisp_malloc (sizeof (struct string_block),
3907 MEM_TYPE_SPARE); 3934 false, MEM_TYPE_SPARE);
3908 if (spare_memory[6] == 0) 3935 if (spare_memory[6] == 0)
3909 spare_memory[6] = lisp_malloc (sizeof (struct string_block), 3936 spare_memory[6] = lisp_malloc (sizeof (struct string_block),
3910 MEM_TYPE_SPARE); 3937 false, MEM_TYPE_SPARE);
3911 if (spare_memory[0] && spare_memory[1] && spare_memory[5]) 3938 if (spare_memory[0] && spare_memory[1] && spare_memory[5])
3912 Vmemory_full = Qnil; 3939 Vmemory_full = Qnil;
3913#endif 3940#endif