зеркало из https://github.com/github/ruby.git
thread.c: micro-optimize thread create/join
* thread.c (struct join_arg): restructure and make smaller (thread_join_sleep): avoid timeofday() call if forever (thread_join): pass join_arg.delay directly (rb_thread_inspect_msg): remove, inline into rb_thread_inspect (rb_thread_inspect): reduce branching and string creation * thread_pthread.c (native_set_thread_name): create string directly to avoid reparsing. [Misc #10723] This reduces time in benchmark/bm_vm_thread_create_join.rb by a few percent. Minor improvements only: target 0: 2.1.5 (ruby 2.1.5p273 (2014-11-13 revision 48405) [x86_64-linux]) target 1: trunk (ruby 2.3.0dev (2015-01-16 trunk 49282) [x86_64-linux]) target 2: built (ruby 2.3.0dev (2015-01-16 trunk 49282) [x86_64-linux]) benchmark results: minimum results in each 3 measurements. Execution time (sec) name 2.1.5 trunk built vm_thread_create_join 1.049 1.242 1.138 Speedup ratio: compare with the result of `2.1.5' (greater is better) name trunk built vm_thread_create_join 0.845 0.923 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@49430 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
05afc8a9d7
Коммит
8341136f07
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
||||||
|
Thu Jan 29 02:06:09 2015 Eric Wong <e@80x24.org>
|
||||||
|
|
||||||
|
* thread.c (struct join_arg): restructure and make smaller
|
||||||
|
(thread_join_sleep): avoid timeofday() call if forever
|
||||||
|
(thread_join): pass join_arg.delay directly
|
||||||
|
(rb_thread_inspect_msg): remove, inline into rb_thread_inspect
|
||||||
|
(rb_thread_inspect): reduce branching and string creation
|
||||||
|
* thread_pthread.c (native_set_thread_name): create string directly
|
||||||
|
to avoid reparsing. [Misc #10723]
|
||||||
|
|
||||||
Wed Jan 28 21:32:24 2015 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
|
Wed Jan 28 21:32:24 2015 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
|
||||||
|
|
||||||
* thread.c: Improve documentation for Thread#value
|
* thread.c: Improve documentation for Thread#value
|
||||||
|
|
68
thread.c
68
thread.c
|
@ -796,8 +796,7 @@ rb_thread_create(VALUE (*fn)(ANYARGS), void *arg)
|
||||||
|
|
||||||
struct join_arg {
|
struct join_arg {
|
||||||
rb_thread_t *target, *waiting;
|
rb_thread_t *target, *waiting;
|
||||||
double limit;
|
double delay;
|
||||||
int forever;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
|
@ -826,14 +825,15 @@ thread_join_sleep(VALUE arg)
|
||||||
{
|
{
|
||||||
struct join_arg *p = (struct join_arg *)arg;
|
struct join_arg *p = (struct join_arg *)arg;
|
||||||
rb_thread_t *target_th = p->target, *th = p->waiting;
|
rb_thread_t *target_th = p->target, *th = p->waiting;
|
||||||
double now, limit = p->limit;
|
const int forever = p->delay == DELAY_INFTY;
|
||||||
|
const double limit = forever ? 0 : timeofday() + p->delay;
|
||||||
|
|
||||||
while (target_th->status != THREAD_KILLED) {
|
while (target_th->status != THREAD_KILLED) {
|
||||||
if (p->forever) {
|
if (forever) {
|
||||||
sleep_forever(th, 1, 0);
|
sleep_forever(th, 1, 0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
now = timeofday();
|
double now = timeofday();
|
||||||
if (now > limit) {
|
if (now > limit) {
|
||||||
thread_debug("thread_join: timeout (thid: %"PRI_THREAD_ID")\n",
|
thread_debug("thread_join: timeout (thid: %"PRI_THREAD_ID")\n",
|
||||||
thread_id_str(target_th));
|
thread_id_str(target_th));
|
||||||
|
@ -862,8 +862,7 @@ thread_join(rb_thread_t *target_th, double delay)
|
||||||
|
|
||||||
arg.target = target_th;
|
arg.target = target_th;
|
||||||
arg.waiting = th;
|
arg.waiting = th;
|
||||||
arg.limit = timeofday() + delay;
|
arg.delay = delay;
|
||||||
arg.forever = delay == DELAY_INFTY;
|
|
||||||
|
|
||||||
thread_debug("thread_join (thid: %"PRI_THREAD_ID")\n", thread_id_str(target_th));
|
thread_debug("thread_join (thid: %"PRI_THREAD_ID")\n", thread_id_str(target_th));
|
||||||
|
|
||||||
|
@ -2711,40 +2710,6 @@ rb_thread_safe_level(VALUE thread)
|
||||||
return INT2NUM(th->safe_level);
|
return INT2NUM(th->safe_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
|
||||||
rb_thread_inspect_msg(VALUE thread, int show_enclosure, int show_location, int show_status)
|
|
||||||
{
|
|
||||||
VALUE cname = rb_class_path(rb_obj_class(thread));
|
|
||||||
rb_thread_t *th;
|
|
||||||
const char *status;
|
|
||||||
VALUE str;
|
|
||||||
|
|
||||||
GetThreadPtr(thread, th);
|
|
||||||
status = thread_status_name(th);
|
|
||||||
if (show_enclosure)
|
|
||||||
str = rb_sprintf("#<%"PRIsVALUE":%p", cname, (void *)thread);
|
|
||||||
else
|
|
||||||
str = rb_str_new(NULL, 0);
|
|
||||||
if (show_location && !th->first_func && th->first_proc) {
|
|
||||||
long i;
|
|
||||||
VALUE v, loc = rb_proc_location(th->first_proc);
|
|
||||||
if (!NIL_P(loc)) {
|
|
||||||
char sep = '@';
|
|
||||||
for (i = 0; i < RARRAY_LEN(loc) && !NIL_P(v = RARRAY_AREF(loc, i)); ++i) {
|
|
||||||
rb_str_catf(str, "%c%"PRIsVALUE, sep, v);
|
|
||||||
sep = ':';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (show_status || show_enclosure)
|
|
||||||
rb_str_catf(str, " %s%s",
|
|
||||||
show_status ? status : "",
|
|
||||||
show_enclosure ? ">" : "");
|
|
||||||
OBJ_INFECT(str, thread);
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* thr.inspect -> string
|
* thr.inspect -> string
|
||||||
|
@ -2755,7 +2720,26 @@ rb_thread_inspect_msg(VALUE thread, int show_enclosure, int show_location, int s
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_thread_inspect(VALUE thread)
|
rb_thread_inspect(VALUE thread)
|
||||||
{
|
{
|
||||||
return rb_thread_inspect_msg(thread, 1, 1, 1);
|
VALUE cname = rb_class_path(rb_obj_class(thread));
|
||||||
|
rb_thread_t *th;
|
||||||
|
const char *status;
|
||||||
|
VALUE str;
|
||||||
|
|
||||||
|
GetThreadPtr(thread, th);
|
||||||
|
status = thread_status_name(th);
|
||||||
|
str = rb_sprintf("#<%"PRIsVALUE":%p", cname, (void *)thread);
|
||||||
|
if (!th->first_func && th->first_proc) {
|
||||||
|
VALUE loc = rb_proc_location(th->first_proc);
|
||||||
|
if (!NIL_P(loc)) {
|
||||||
|
const VALUE *ptr = RARRAY_CONST_PTR(loc);
|
||||||
|
rb_str_catf(str, "@%"PRIsVALUE":%"PRIsVALUE, ptr[0], ptr[1]);
|
||||||
|
rb_gc_force_recycle(loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rb_str_catf(str, " %s>", status);
|
||||||
|
OBJ_INFECT(str, thread);
|
||||||
|
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* variables for recursive traversals */
|
/* variables for recursive traversals */
|
||||||
|
|
|
@ -1447,36 +1447,35 @@ timer_thread_sleep(rb_global_vm_lock_t* unused)
|
||||||
# define SET_THREAD_NAME(name) (void)0
|
# define SET_THREAD_NAME(name) (void)0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static VALUE rb_thread_inspect_msg(VALUE thread, int show_enclosure, int show_location, int show_status);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
native_set_thread_name(rb_thread_t *th)
|
native_set_thread_name(rb_thread_t *th)
|
||||||
{
|
{
|
||||||
#if defined(__linux__) && defined(PR_SET_NAME)
|
#if defined(__linux__) && defined(PR_SET_NAME)
|
||||||
VALUE str;
|
if (!th->first_func && th->first_proc) {
|
||||||
char *name, *p;
|
VALUE loc = rb_proc_location(th->first_proc);
|
||||||
char buf[16];
|
if (!NIL_P(loc)) {
|
||||||
size_t len;
|
const VALUE *ptr = RARRAY_CONST_PTR(loc); /* [ String, Fixnum ] */
|
||||||
|
char *name, *p;
|
||||||
|
char buf[16];
|
||||||
|
size_t len;
|
||||||
|
int n;
|
||||||
|
|
||||||
str = rb_thread_inspect_msg(th->self, 0, 1, 0);
|
name = RSTRING_PTR(ptr[0]);
|
||||||
name = StringValueCStr(str);
|
p = strrchr(name, '/'); /* show only the basename of the path. */
|
||||||
if (*name == '@')
|
if (p && p[1])
|
||||||
name++;
|
name = p + 1;
|
||||||
p = strrchr(name, '/'); /* show only the basename of the path. */
|
|
||||||
if (p && p[1])
|
|
||||||
name = p + 1;
|
|
||||||
|
|
||||||
len = strlen(name);
|
n = snprintf(buf, sizeof(buf), "%s:%d", name, NUM2INT(ptr[1]));
|
||||||
if (len < sizeof(buf)) {
|
rb_gc_force_recycle(loc); /* acts as a GC guard, too */
|
||||||
memcpy(buf, name, len);
|
|
||||||
buf[len] = '\0';
|
len = (size_t)n;
|
||||||
|
if (len >= sizeof(buf)) {
|
||||||
|
buf[sizeof(buf)-2] = '*';
|
||||||
|
buf[sizeof(buf)-1] = '\0';
|
||||||
|
}
|
||||||
|
SET_THREAD_NAME(buf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
memcpy(buf, name, sizeof(buf)-2);
|
|
||||||
buf[sizeof(buf)-2] = '*';
|
|
||||||
buf[sizeof(buf)-1] = '\0';
|
|
||||||
}
|
|
||||||
SET_THREAD_NAME(buf);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче