Hello!
2012/8/9 Chaos Wang <chaos...@gmail.com>
> coroutine分支平均比master慢2%
>
我又在我的机器上重新进行了多组测试,发现我的机器确实会随机地提升 20%
的性能,不清楚是什么原因导致的(或许是因为我使用两种不同型号的内存条,抑或是 CPU cache 完整命中?),但确实与使用 master
还是 coroutine 分支无关。
在平均条件下,二者确实几乎没有可以测量的区别,即使是在 mockeagain 模式下。
>
> 从代码来说,对于此处的测试用例,coroutine分支并未引入太多额外处理逻辑,你所说的请求处理结束时coroutine分支在注册表
> 中查找的逻辑也不可能产生上封信中如此之大的性能差异,加载mockeagain.s后callgrind profiling的结果可以佐证这一点:
>
callgrind 真是极好的工具!我喜欢它为每个函数生成的 IR (Instruction Reads) 指标!我这里使用
mockeagain 运行最初的 lua-resty-mysql 用例,同时连续请求 nginx 10 次的测量结果是:
master 分支:
ngx_http_lua_run_thread:
12,420 (--inclusive=no)
7,001,944 (--inclusive=yes)
coroutine 分支:
ngx_http_lua_run_thread:
14,866 (--inclusive=no)
6,922,811 (--inclusive=yes)
我在针对 entry coroutine 进行优化之后(补丁见附件或信尾,尚未提交到 GitHub),coroutine 分支的结果变为了:
ngx_http_lua_run_thread:
14,284 (--inclusive=no)
6,918,866 (--inclusive=yes)
以上结果都是使用的 Nginx 默认的 gcc -O1 优化级别。
使用 gcc -O2 后,优化后的 coroutine 分支的结果是:
ngx_http_lua_run_thread:
13,470 (--inclusive=no)
7,056,177 (--inclusive=yes)
而 gcc -O3 则为
ngx_http_lua_run_thread:
13,384 (--inclusive=no)
7,037,605 (--inclusive=yes)
如此看来,性能上似乎已经足够好了 :)
Best regards,
-agentzh
diff --git a/src/ngx_http_lua_accessby.c b/src/ngx_http_lua_accessby.c
index 211ac2f..946dc54 100644
--- a/src/ngx_http_lua_accessby.c
+++ b/src/ngx_http_lua_accessby.c
@@ -263,6 +263,7 @@ ngx_http_lua_access_by_chunk(lua_State *L,
ngx_http_request_t *r)
ctx->entered_access_phase = 1;
+ ctx->entry = cc;
ctx->cc = cc;
ctx->cc_ref = cc_ref;
diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h
index f571900..693874c 100644
--- a/src/ngx_http_lua_common.h
+++ b/src/ngx_http_lua_common.h
@@ -210,6 +210,9 @@ typedef struct {
not necessarily to be the
request's entry coroutine */
+ lua_State *entry; /* the entry Lua coroutine */
+
+
int cc_ref; /* reference to anchor coroutine in
the lua registry. it always
ref to the entry coroutine of the
diff --git a/src/ngx_http_lua_contentby.c b/src/ngx_http_lua_contentby.c
index d727108..989bc48 100644
--- a/src/ngx_http_lua_contentby.c
+++ b/src/ngx_http_lua_contentby.c
@@ -70,6 +70,7 @@ ngx_http_lua_content_by_chunk(lua_State *L,
ngx_http_request_t *r)
lua_rawset(cc, LUA_GLOBALSINDEX);
/* }}} */
+ ctx->entry = cc;
ctx->cc = cc;
ctx->cc_ref = cc_ref;
diff --git a/src/ngx_http_lua_rewriteby.c b/src/ngx_http_lua_rewriteby.c
index 6915747..7f0508a 100644
--- a/src/ngx_http_lua_rewriteby.c
+++ b/src/ngx_http_lua_rewriteby.c
@@ -264,6 +264,7 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L,
ngx_http_request_t *r)
ctx->entered_rewrite_phase = 1;
+ ctx->entry = cc;
ctx->cc = cc;
ctx->cc_ref = cc_ref;
diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c
index 811681b..cf57121 100644
--- a/src/ngx_http_lua_util.c
+++ b/src/ngx_http_lua_util.c
@@ -913,6 +913,12 @@ ngx_http_lua_run_thread(lua_State *L,
ngx_http_request_t *r,
* lua_yield()
*/
switch(ctx->cc_op) {
+ case NGX_HTTP_LUA_USER_CORO_NOP:
+ dd("hit! it is the API yield");
+
+ lua_settop(cc, 0);
+ return NGX_AGAIN;
+
case NGX_HTTP_LUA_USER_CORO_RESUME:
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"lua coroutine: resume");
@@ -934,28 +940,19 @@ ngx_http_lua_run_thread(lua_State *L,
ngx_http_request_t *r,
cc = next_cc;
ctx->cc = cc;
- continue;
+ break;
+
+ default:
+ /* NGX_HTTP_LUA_USER_CORO_YIELD */
- case NGX_HTTP_LUA_USER_CORO_YIELD:
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"lua coroutine: yield");
- /*
- * here we need to find the parent coroutine of the
- * yield coroutine in the weak table(in registry)
- */
ctx->cc_op = NGX_HTTP_LUA_USER_CORO_NOP;
- nrets = lua_gettop(cc);
-
- /* find parent coroutine in weak ref table */
- ngx_http_lua_get_coroutine_parents(L);
- lua_pushthread(cc);
- lua_xmove(cc, L, 1);
- lua_rawget(L, -2);
+ if (cc == ctx->entry) {
+ /* entry coroutine can not yield */
- /* entry coroutine can not yield */
- if (!lua_isthread(L, -1)) {
lua_settop(L, 0);
ngx_http_lua_del_thread(r, L, cc_ref);
@@ -971,6 +968,16 @@ ngx_http_lua_run_thread(lua_State *L,
ngx_http_request_t *r,
NGX_HTTP_INTERNAL_SERVER_ERROR;
}
+ /* being a user coroutine that has a parent */
+
+ nrets = lua_gettop(cc);
+
+ /* find parent coroutine in weak ref table */
+ ngx_http_lua_get_coroutine_parents(L);
+ lua_pushthread(cc);
+ lua_xmove(cc, L, 1);
+ lua_rawget(L, -2);
+
next_cc = lua_tothread(L, -1);
lua_pop(L, 2);
@@ -988,73 +995,73 @@ ngx_http_lua_run_thread(lua_State *L,
ngx_http_request_t *r,
cc = next_cc;
ctx->cc = cc;
- continue;
-
- default:
- /* NGX_HTTP_LUA_USER_CORO_NOP */
break;
}
- lua_settop(cc, 0);
-
- return NGX_AGAIN;
+ /* try resuming on the new coroutine again */
+ continue;
case 0:
#if 0
ngx_http_lua_dump_postponed(r);
#endif
- /* check if the dead coroutine has a parent coroutine */
- nrets = lua_gettop(cc);
+ if (cc == ctx->entry) {
+ dd("hit! it is the entry");
- ngx_http_lua_get_coroutine_parents(L);
- lua_pushthread(cc);
- lua_xmove(cc, L, 1);
- lua_rawget(L, -2);
+ lua_settop(L, 0);
- /* resume the parent coroutine */
- if (lua_isthread(L, -1)) {
- next_cc = lua_tothread(L, -1);
- lua_pop(L, 2);
-
- /*
- * ended successful, coroutine.resume returns true plus
- * any return values
- */
- lua_pushboolean(next_cc, 1);
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "lua entry thread ended normally");
- if (nrets) {
- lua_xmove(cc, next_cc, nrets);
- }
+ /* the entry thread was dead, delete it */
+ ngx_http_lua_del_thread(r, L, cc_ref);
+ ctx->cc_ref = LUA_NOREF;
- nrets++;
- ctx->cc = cc = next_cc;
+ if (ctx->entered_content_phase) {
+ rc = ngx_http_lua_send_chain_link(r, ctx,
+ NULL /* last_buf */);
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "lua coroutine: lua thread ended normally");
+ if (rc == NGX_ERROR
+ || rc >= NGX_HTTP_SPECIAL_RESPONSE)
+ {
+ return rc;
+ }
+ }
- continue;
+ return NGX_OK;
}
- lua_settop(L, 0);
+ /* being a user coroutine that has a parent */
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "lua entry thread ended normally");
+ nrets = lua_gettop(cc);
- /* the entry thread was dead, delete it */
- ngx_http_lua_del_thread(r, L, cc_ref);
- ctx->cc_ref = LUA_NOREF;
+ ngx_http_lua_get_coroutine_parents(L);
+ lua_pushthread(cc);
+ lua_xmove(cc, L, 1);
+ lua_rawget(L, -2);
- if (ctx->entered_content_phase) {
- rc = ngx_http_lua_send_chain_link(r, ctx,
- NULL /* last_buf */);
+ next_cc = lua_tothread(L, -1);
+ lua_pop(L, 2);
- if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
- return rc;
- }
+ /*
+ * ended successful, coroutine.resume returns true plus
+ * any return values
+ */
+ lua_pushboolean(next_cc, 1);
+
+ if (nrets) {
+ lua_xmove(cc, next_cc, nrets);
}
- return NGX_OK;
+ nrets++;
+ cc = next_cc;
+ ctx->cc = cc;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "lua coroutine: lua user thread ended
normally");
+
+ continue;
case LUA_ERRRUN:
err = "runtime error";
@@ -1089,46 +1096,50 @@ ngx_http_lua_run_thread(lua_State *L,
ngx_http_request_t *r,
trace = lua_tostring(L, -1);
lua_pop(L, 1);
- /* check if the dead coroutine has a parent coroutine*/
- ngx_http_lua_get_coroutine_parents(L);
- lua_pushthread(cc);
- lua_xmove(cc, L, 1);
- lua_rawget(L, -2);
+ if (cc == ctx->entry) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "lua handler aborted: %s: %s\n%s", err, msg,
+ trace);
- if (lua_isthread(L, -1)) {
- next_cc = lua_tothread(L, -1);
- lua_pop(L, 2);
+ lua_settop(L, 0);
- /*
- * ended with error, coroutine.resume returns false plus
- * err msg
- */
- lua_pushboolean(next_cc, 0);
- lua_xmove(cc, next_cc, 1);
- nrets = 2;
+ ngx_http_lua_del_thread(r, L, cc_ref);
+ ctx->cc_ref = LUA_NOREF;
- ctx->cc = cc = next_cc;
+ ngx_http_lua_request_cleanup(r);
- ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "lua coroutine: %s: %s\n%s", err, msg, trace);
+ dd("headers sent? %d", ctx->headers_sent ? 1 : 0);
- continue;
+ return ctx->headers_sent ? NGX_ERROR :
+ NGX_HTTP_INTERNAL_SERVER_ERROR;
}
- ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "lua handler aborted: %s: %s\n%s", err, msg, trace);
+ /* being a user coroutine that has a parent */
+
+ ngx_http_lua_get_coroutine_parents(L);
+ lua_pushthread(cc);
+ lua_xmove(cc, L, 1);
+ lua_rawget(L, -2);
+ next_cc = lua_tothread(L, -1);
lua_pop(L, 2);
- ngx_http_lua_del_thread(r, L, cc_ref);
- ctx->cc_ref = LUA_NOREF;
+ /*
+ * ended with error, coroutine.resume returns false plus
+ * err msg
+ */
+ lua_pushboolean(next_cc, 0);
+ lua_xmove(cc, next_cc, 1);
+ nrets = 2;
- ngx_http_lua_request_cleanup(r);
+ cc = next_cc;
+ ctx->cc = cc;
- dd("headers sent? %d", ctx->headers_sent ? 1 : 0);
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "lua coroutine: %s: %s\n%s", err, msg, trace);
- return ctx->headers_sent ? NGX_ERROR :
- NGX_HTTP_INTERNAL_SERVER_ERROR;
+ /* try resuming on the new coroutine again */
+ continue;
}
} NGX_LUA_EXCEPTION_CATCH {
Attachment:
optimizing-entry-coroutines.patch
Description: Binary data