mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Make bulk_free() go faster
This commit is contained in:
parent
624573207e
commit
c8e10eef30
13 changed files with 54 additions and 36 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -15,3 +15,4 @@ __pycache__
|
||||||
/tool/emacs/*.elc
|
/tool/emacs/*.elc
|
||||||
/perf.data
|
/perf.data
|
||||||
/perf.data.old
|
/perf.data.old
|
||||||
|
/qemu*core
|
||||||
|
|
|
@ -25,8 +25,8 @@ int cosmo_futex_wake(_COSMO_ATOMIC(int) *, int, char);
|
||||||
int cosmo_futex_wait(_COSMO_ATOMIC(int) *, int, char, int,
|
int cosmo_futex_wait(_COSMO_ATOMIC(int) *, int, char, int,
|
||||||
const struct timespec *);
|
const struct timespec *);
|
||||||
|
|
||||||
errno_t cosmo_stack_alloc(size_t *, size_t *, void **) libcesque;
|
errno_t cosmo_stack_alloc(unsigned *, unsigned *, void **) libcesque;
|
||||||
errno_t cosmo_stack_free(void *, size_t, size_t) libcesque;
|
errno_t cosmo_stack_free(void *, unsigned, unsigned) libcesque;
|
||||||
void cosmo_stack_clear(void) libcesque;
|
void cosmo_stack_clear(void) libcesque;
|
||||||
void cosmo_stack_setmaxstacks(int) libcesque;
|
void cosmo_stack_setmaxstacks(int) libcesque;
|
||||||
int cosmo_stack_getmaxstacks(void) libcesque;
|
int cosmo_stack_getmaxstacks(void) libcesque;
|
||||||
|
|
|
@ -42,8 +42,8 @@
|
||||||
struct CosmoStack {
|
struct CosmoStack {
|
||||||
struct Dll elem;
|
struct Dll elem;
|
||||||
void *stackaddr;
|
void *stackaddr;
|
||||||
size_t stacksize;
|
unsigned stacksize;
|
||||||
size_t guardsize;
|
unsigned guardsize;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CosmoStacks {
|
struct CosmoStacks {
|
||||||
|
@ -215,13 +215,13 @@ void cosmo_stack_setmaxstacks(int maxstacks) {
|
||||||
* This function returns 0 on success, or an errno on error. See the
|
* This function returns 0 on success, or an errno on error. See the
|
||||||
* documentation of mmap() for a list possible errors that may occur.
|
* documentation of mmap() for a list possible errors that may occur.
|
||||||
*/
|
*/
|
||||||
errno_t cosmo_stack_alloc(size_t *inout_stacksize, //
|
errno_t cosmo_stack_alloc(unsigned *inout_stacksize, //
|
||||||
size_t *inout_guardsize, //
|
unsigned *inout_guardsize, //
|
||||||
void **out_addr) {
|
void **out_addr) {
|
||||||
|
|
||||||
// validate arguments
|
// validate arguments
|
||||||
size_t stacksize = *inout_stacksize;
|
unsigned stacksize = *inout_stacksize;
|
||||||
size_t guardsize = *inout_guardsize;
|
unsigned guardsize = *inout_guardsize;
|
||||||
stacksize = (stacksize + __gransize - 1) & -__gransize;
|
stacksize = (stacksize + __gransize - 1) & -__gransize;
|
||||||
guardsize = (guardsize + __pagesize - 1) & -__pagesize;
|
guardsize = (guardsize + __pagesize - 1) & -__pagesize;
|
||||||
if (guardsize + __pagesize > stacksize)
|
if (guardsize + __pagesize > stacksize)
|
||||||
|
@ -283,7 +283,8 @@ static void cosmo_stack_setup(void) {
|
||||||
* variable is never clobbered. You can only dependably count on this to
|
* variable is never clobbered. You can only dependably count on this to
|
||||||
* return an error on failure when you say `cosmo_stack_setmaxstacks(0)`
|
* return an error on failure when you say `cosmo_stack_setmaxstacks(0)`
|
||||||
*/
|
*/
|
||||||
errno_t cosmo_stack_free(void *stackaddr, size_t stacksize, size_t guardsize) {
|
errno_t cosmo_stack_free(void *stackaddr, unsigned stacksize,
|
||||||
|
unsigned guardsize) {
|
||||||
stacksize = (stacksize + __gransize - 1) & -__gransize;
|
stacksize = (stacksize + __gransize - 1) & -__gransize;
|
||||||
guardsize = (guardsize + __pagesize - 1) & -__pagesize;
|
guardsize = (guardsize + __pagesize - 1) & -__pagesize;
|
||||||
if (guardsize + __pagesize > stacksize)
|
if (guardsize + __pagesize > stacksize)
|
||||||
|
|
|
@ -35,8 +35,8 @@
|
||||||
*/
|
*/
|
||||||
void *NewCosmoStack(void) {
|
void *NewCosmoStack(void) {
|
||||||
void *stackaddr;
|
void *stackaddr;
|
||||||
size_t stacksize = GetStackSize();
|
unsigned stacksize = GetStackSize();
|
||||||
size_t guardsize = GetGuardSize();
|
unsigned guardsize = GetGuardSize();
|
||||||
errno_t err = cosmo_stack_alloc(&stacksize, &guardsize, &stackaddr);
|
errno_t err = cosmo_stack_alloc(&stacksize, &guardsize, &stackaddr);
|
||||||
if (!err)
|
if (!err)
|
||||||
return stackaddr;
|
return stackaddr;
|
||||||
|
|
|
@ -78,8 +78,7 @@ struct PosixThread {
|
||||||
atomic_int ptid; // transitions 0 → tid
|
atomic_int ptid; // transitions 0 → tid
|
||||||
atomic_int pt_refs; // prevents decimation
|
atomic_int pt_refs; // prevents decimation
|
||||||
void *(*pt_start)(void *); // creation callback
|
void *(*pt_start)(void *); // creation callback
|
||||||
void *pt_arg; // start's parameter
|
void *pt_val; // start param / return val
|
||||||
void *pt_rc; // start's return value
|
|
||||||
char *pt_tls; // bottom of tls allocation
|
char *pt_tls; // bottom of tls allocation
|
||||||
struct CosmoTib *tib; // middle of tls allocation
|
struct CosmoTib *tib; // middle of tls allocation
|
||||||
struct Dll list; // list of threads
|
struct Dll list; // list of threads
|
||||||
|
@ -105,7 +104,6 @@ int _pthread_tid(struct PosixThread *) libcesque;
|
||||||
intptr_t _pthread_syshand(struct PosixThread *) libcesque;
|
intptr_t _pthread_syshand(struct PosixThread *) libcesque;
|
||||||
long _pthread_cancel_ack(void) libcesque;
|
long _pthread_cancel_ack(void) libcesque;
|
||||||
void _pthread_decimate(void) libcesque;
|
void _pthread_decimate(void) libcesque;
|
||||||
void _pthread_free(struct PosixThread *) libcesque;
|
|
||||||
void _pthread_lock(void) libcesque;
|
void _pthread_lock(void) libcesque;
|
||||||
void _pthread_onfork_child(void) libcesque;
|
void _pthread_onfork_child(void) libcesque;
|
||||||
void _pthread_onfork_parent(void) libcesque;
|
void _pthread_onfork_parent(void) libcesque;
|
||||||
|
|
|
@ -63,11 +63,13 @@ static void _pthread_onfork(int i, const char *op) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _pthread_onfork_prepare(void) {
|
void _pthread_onfork_prepare(void) {
|
||||||
|
pthread_mutex_lock(&_atforks.lock);
|
||||||
_pthread_onfork(0, "prepare");
|
_pthread_onfork(0, "prepare");
|
||||||
}
|
}
|
||||||
|
|
||||||
void _pthread_onfork_parent(void) {
|
void _pthread_onfork_parent(void) {
|
||||||
_pthread_onfork(1, "parent");
|
_pthread_onfork(1, "parent");
|
||||||
|
pthread_mutex_unlock(&_atforks.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _pthread_onfork_child(void) {
|
void _pthread_onfork_child(void) {
|
||||||
|
|
|
@ -67,7 +67,7 @@ __static_yoink("_pthread_onfork_prepare");
|
||||||
__static_yoink("_pthread_onfork_parent");
|
__static_yoink("_pthread_onfork_parent");
|
||||||
__static_yoink("_pthread_onfork_child");
|
__static_yoink("_pthread_onfork_child");
|
||||||
|
|
||||||
void _pthread_free(struct PosixThread *pt) {
|
static void _pthread_free(struct PosixThread *pt) {
|
||||||
|
|
||||||
// thread must be removed from _pthread_list before calling
|
// thread must be removed from _pthread_list before calling
|
||||||
unassert(dll_is_alone(&pt->list) && &pt->list != _pthread_list);
|
unassert(dll_is_alone(&pt->list) && &pt->list != _pthread_list);
|
||||||
|
@ -93,10 +93,13 @@ void _pthread_free(struct PosixThread *pt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// free heap memory associated with thread
|
// free heap memory associated with thread
|
||||||
if (pt->pt_flags & PT_OWNSIGALTSTACK)
|
bulk_free(
|
||||||
free(pt->pt_attr.__sigaltstackaddr);
|
(void *[]){
|
||||||
free(pt->pt_tls);
|
pt->pt_flags & PT_OWNSIGALTSTACK ? pt->pt_attr.__sigaltstackaddr : 0,
|
||||||
free(pt);
|
pt->pt_tls,
|
||||||
|
pt,
|
||||||
|
},
|
||||||
|
3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _pthread_decimate(void) {
|
void _pthread_decimate(void) {
|
||||||
|
@ -137,7 +140,6 @@ void _pthread_decimate(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PosixThread(void *arg, int tid) {
|
static int PosixThread(void *arg, int tid) {
|
||||||
void *rc;
|
|
||||||
struct PosixThread *pt = arg;
|
struct PosixThread *pt = arg;
|
||||||
|
|
||||||
// setup scheduling
|
// setup scheduling
|
||||||
|
@ -167,11 +169,11 @@ static int PosixThread(void *arg, int tid) {
|
||||||
} else {
|
} else {
|
||||||
sys_sigprocmask(SIG_SETMASK, &pt->pt_attr.__sigmask, 0);
|
sys_sigprocmask(SIG_SETMASK, &pt->pt_attr.__sigmask, 0);
|
||||||
}
|
}
|
||||||
rc = pt->pt_start(pt->pt_arg);
|
void *ret = pt->pt_start(pt->pt_val);
|
||||||
// ensure pthread_cleanup_pop(), and pthread_exit() popped cleanup
|
// ensure pthread_cleanup_pop(), and pthread_exit() popped cleanup
|
||||||
unassert(!pt->pt_cleanup);
|
unassert(!pt->pt_cleanup);
|
||||||
// calling pthread_exit() will either jump back here, or call exit
|
// calling pthread_exit() will either jump back here, or call exit
|
||||||
pthread_exit(rc);
|
pthread_exit(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
// avoid signal handler being triggered after we trash our own stack
|
// avoid signal handler being triggered after we trash our own stack
|
||||||
|
@ -196,7 +198,7 @@ static errno_t pthread_create_impl(pthread_t *thread,
|
||||||
dll_init(&pt->list);
|
dll_init(&pt->list);
|
||||||
pt->pt_locale = &__global_locale;
|
pt->pt_locale = &__global_locale;
|
||||||
pt->pt_start = start_routine;
|
pt->pt_start = start_routine;
|
||||||
pt->pt_arg = arg;
|
pt->pt_val = arg;
|
||||||
|
|
||||||
// create thread local storage memory
|
// create thread local storage memory
|
||||||
if (!(pt->pt_tls = _mktls(&pt->tib))) {
|
if (!(pt->pt_tls = _mktls(&pt->tib))) {
|
||||||
|
|
|
@ -88,7 +88,7 @@ wontreturn void pthread_exit(void *rc) {
|
||||||
|
|
||||||
// set state
|
// set state
|
||||||
pt->pt_flags |= PT_NOCANCEL | PT_EXITING;
|
pt->pt_flags |= PT_NOCANCEL | PT_EXITING;
|
||||||
pt->pt_rc = rc;
|
pt->pt_val = rc;
|
||||||
|
|
||||||
// free resources
|
// free resources
|
||||||
__cxa_thread_finalize();
|
__cxa_thread_finalize();
|
||||||
|
|
|
@ -139,7 +139,7 @@ errno_t pthread_timedjoin_np(pthread_t thread, void **value_ptr,
|
||||||
memory_order_release);
|
memory_order_release);
|
||||||
_pthread_zombify(pt);
|
_pthread_zombify(pt);
|
||||||
if (value_ptr)
|
if (value_ptr)
|
||||||
*value_ptr = pt->pt_rc;
|
*value_ptr = pt->pt_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
_pthread_unref(pt);
|
_pthread_unref(pt);
|
||||||
|
|
|
@ -130,8 +130,8 @@ typedef struct pthread_attr_s {
|
||||||
int __contentionscope;
|
int __contentionscope;
|
||||||
int __sigaltstacksize;
|
int __sigaltstacksize;
|
||||||
uint64_t __sigmask;
|
uint64_t __sigmask;
|
||||||
size_t __guardsize;
|
unsigned __guardsize;
|
||||||
size_t __stacksize;
|
unsigned __stacksize;
|
||||||
void *__stackaddr;
|
void *__stackaddr;
|
||||||
void *__sigaltstackaddr;
|
void *__sigaltstackaddr;
|
||||||
} pthread_attr_t;
|
} pthread_attr_t;
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/intrin/cxaatexit.h"
|
#include "libc/intrin/cxaatexit.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
|
||||||
#include "libc/intrin/safemacros.h"
|
#include "libc/intrin/safemacros.h"
|
||||||
#include "libc/macros.h"
|
#include "libc/macros.h"
|
||||||
#include "libc/mem/gc.h"
|
#include "libc/mem/gc.h"
|
||||||
|
@ -162,7 +161,7 @@ void *bulk[1024];
|
||||||
void BulkFreeBenchSetup(void) {
|
void BulkFreeBenchSetup(void) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < ARRAYLEN(bulk); ++i) {
|
for (i = 0; i < ARRAYLEN(bulk); ++i) {
|
||||||
bulk[i] = malloc(rand() % 64);
|
bulk[i] = rand() % 64 ? malloc(rand() % 64) : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
10
third_party/dlmalloc/dlmalloc.c
vendored
10
third_party/dlmalloc/dlmalloc.c
vendored
|
@ -62,11 +62,6 @@
|
||||||
#include "locks.inc"
|
#include "locks.inc"
|
||||||
#include "chunks.inc"
|
#include "chunks.inc"
|
||||||
#include "headfoot.inc"
|
#include "headfoot.inc"
|
||||||
|
|
||||||
#if ONLY_MSPACES
|
|
||||||
#include "threaded.inc"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "global.inc"
|
#include "global.inc"
|
||||||
#include "system.inc"
|
#include "system.inc"
|
||||||
#include "hooks.inc"
|
#include "hooks.inc"
|
||||||
|
@ -74,6 +69,11 @@
|
||||||
#include "indexing.inc"
|
#include "indexing.inc"
|
||||||
#include "binmaps.inc"
|
#include "binmaps.inc"
|
||||||
#include "runtimechecks.inc"
|
#include "runtimechecks.inc"
|
||||||
|
|
||||||
|
#if ONLY_MSPACES
|
||||||
|
#include "threaded.inc"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "init.inc"
|
#include "init.inc"
|
||||||
#include "debuglib.inc"
|
#include "debuglib.inc"
|
||||||
#include "statistics.inc"
|
#include "statistics.inc"
|
||||||
|
|
19
third_party/dlmalloc/threaded.inc
vendored
19
third_party/dlmalloc/threaded.inc
vendored
|
@ -61,8 +61,23 @@ int dlmalloc_trim(size_t pad) {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t dlbulk_free(void *array[], size_t nelem) {
|
size_t dlbulk_free(void *array[], size_t nelem) {
|
||||||
for (size_t i = 0; i < nelem; ++i)
|
size_t j = 0;
|
||||||
mspace_free(0, array[i]);
|
mstate msp = (mstate)-1;
|
||||||
|
for (size_t i = 0; i < nelem; ++i) {
|
||||||
|
mstate next;
|
||||||
|
if (array[i]) {
|
||||||
|
next = get_mstate_for(mem2chunk(array[i]));
|
||||||
|
if (next != msp) {
|
||||||
|
if (j)
|
||||||
|
mspace_bulk_free(msp, array, j);
|
||||||
|
msp = next;
|
||||||
|
j = 0;
|
||||||
|
}
|
||||||
|
array[j++] = array[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j)
|
||||||
|
mspace_bulk_free(msp, array, j);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue