diff options
| author | Paul Eggert | 2020-01-02 18:02:32 -0800 |
|---|---|---|
| committer | Paul Eggert | 2020-01-02 18:11:25 -0800 |
| commit | dd0e4d4e16fbbba6189610c7abb73d8b0efc6e5e (patch) | |
| tree | e085817d80d71e20ec7230c9ed59a4793174f4d5 /src/alloc.c | |
| parent | d36adb544d984b91c70f6194da01344e4b2b6fc9 (diff) | |
| download | emacs-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.c | 87 |
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 | ||
| 697 | static void *lmalloc (size_t) ATTRIBUTE_MALLOC_SIZE ((1)); | 697 | static void *lmalloc (size_t, bool) ATTRIBUTE_MALLOC_SIZE ((1)); |
| 698 | static void *lrealloc (void *, size_t); | 698 | static 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 | ||
| 941 | static void * | 940 | static void * |
| 942 | lisp_malloc (size_t nbytes, enum mem_type type) | 941 | lisp_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 | ||
| 1292 | static void * | 1291 | static void * |
| 1293 | lmalloc (size_t size) | 1292 | lmalloc (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 | ||
| 3139 | static struct Lisp_Vector * | 3143 | static struct Lisp_Vector * |
| 3140 | allocate_vectorlike (ptrdiff_t len) | 3144 | allocate_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 | ||
| 3183 | struct Lisp_Vector * | 3192 | static struct Lisp_Vector * |
| 3184 | allocate_vector (ptrdiff_t len) | 3193 | allocate_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 | |||
| 3206 | struct Lisp_Vector * | ||
| 3207 | allocate_vector (ptrdiff_t len) | ||
| 3208 | { | ||
| 3209 | return allocate_clear_vector (len, false); | ||
| 3210 | } | ||
| 3211 | |||
| 3212 | /* Allocate a vector with LEN nil slots. */ | ||
| 3213 | |||
| 3214 | struct Lisp_Vector * | ||
| 3215 | allocate_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, | |||
| 3218 | struct buffer * | 3243 | struct buffer * |
| 3219 | allocate_buffer (void) | 3244 | allocate_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'. */) | |||
| 3291 | Lisp_Object | 3316 | Lisp_Object |
| 3292 | make_vector (ptrdiff_t length, Lisp_Object init) | 3317 | make_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 |