mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-25 12:43:09 +00:00
profile support skynet coroutine
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
#include <stdio.h>
|
||||||
#include <lua.h>
|
#include <lua.h>
|
||||||
#include <lauxlib.h>
|
#include <lauxlib.h>
|
||||||
|
|
||||||
@@ -11,6 +12,8 @@
|
|||||||
#define NANOSEC 1000000000
|
#define NANOSEC 1000000000
|
||||||
#define MICROSEC 1000000
|
#define MICROSEC 1000000
|
||||||
|
|
||||||
|
// #define DEBUG_LOG
|
||||||
|
|
||||||
static double
|
static double
|
||||||
get_time() {
|
get_time() {
|
||||||
#if !defined(__APPLE__)
|
#if !defined(__APPLE__)
|
||||||
@@ -47,7 +50,11 @@ diff_time(double start) {
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
lstart(lua_State *L) {
|
lstart(lua_State *L) {
|
||||||
lua_pushthread(L);
|
if (lua_type(L,1) == LUA_TTHREAD) {
|
||||||
|
lua_settop(L,1);
|
||||||
|
} else {
|
||||||
|
lua_pushthread(L);
|
||||||
|
}
|
||||||
lua_rawget(L, lua_upvalueindex(2));
|
lua_rawget(L, lua_upvalueindex(2));
|
||||||
if (!lua_isnil(L, -1)) {
|
if (!lua_isnil(L, -1)) {
|
||||||
return luaL_error(L, "Thread %p start profile more than once", lua_topointer(L, 1));
|
return luaL_error(L, "Thread %p start profile more than once", lua_topointer(L, 1));
|
||||||
@@ -57,7 +64,11 @@ lstart(lua_State *L) {
|
|||||||
lua_rawset(L, lua_upvalueindex(2));
|
lua_rawset(L, lua_upvalueindex(2));
|
||||||
|
|
||||||
lua_pushthread(L);
|
lua_pushthread(L);
|
||||||
lua_pushnumber(L, get_time());
|
double ti = get_time();
|
||||||
|
#ifdef DEBUG_LOG
|
||||||
|
fprintf(stderr, "PROFILE [%p] start\n", L);
|
||||||
|
#endif
|
||||||
|
lua_pushnumber(L, ti);
|
||||||
lua_rawset(L, lua_upvalueindex(1));
|
lua_rawset(L, lua_upvalueindex(1));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -65,9 +76,15 @@ lstart(lua_State *L) {
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
lstop(lua_State *L) {
|
lstop(lua_State *L) {
|
||||||
lua_pushthread(L);
|
if (lua_type(L,1) == LUA_TTHREAD) {
|
||||||
|
lua_settop(L,1);
|
||||||
|
} else {
|
||||||
|
lua_pushthread(L);
|
||||||
|
}
|
||||||
lua_rawget(L, lua_upvalueindex(1));
|
lua_rawget(L, lua_upvalueindex(1));
|
||||||
luaL_checktype(L, -1, LUA_TNUMBER);
|
if (lua_type(L, -1) != LUA_TNUMBER) {
|
||||||
|
return luaL_error(L, "Call profile.start() before profile.stop()");
|
||||||
|
}
|
||||||
double ti = diff_time(lua_tonumber(L, -1));
|
double ti = diff_time(lua_tonumber(L, -1));
|
||||||
lua_pushthread(L);
|
lua_pushthread(L);
|
||||||
lua_rawget(L, lua_upvalueindex(2));
|
lua_rawget(L, lua_upvalueindex(2));
|
||||||
@@ -81,14 +98,20 @@ lstop(lua_State *L) {
|
|||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_rawset(L, lua_upvalueindex(2));
|
lua_rawset(L, lua_upvalueindex(2));
|
||||||
|
|
||||||
lua_pushnumber(L, ti + total_time);
|
total_time += ti;
|
||||||
|
lua_pushnumber(L, total_time);
|
||||||
|
#ifdef DEBUG_LOG
|
||||||
|
fprintf(stderr, "PROFILE [%p] stop (%lf / %lf)\n", L, ti, total_time);
|
||||||
|
#endif
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lresume(lua_State *L) {
|
timing_resume(lua_State *L) {
|
||||||
lua_pushvalue(L,1);
|
#ifdef DEBUG_LOG
|
||||||
|
lua_State *from = lua_tothread(L, -1);
|
||||||
|
#endif
|
||||||
lua_rawget(L, lua_upvalueindex(2));
|
lua_rawget(L, lua_upvalueindex(2));
|
||||||
if (lua_isnil(L, -1)) { // check total time
|
if (lua_isnil(L, -1)) { // check total time
|
||||||
lua_pop(L,1);
|
lua_pop(L,1);
|
||||||
@@ -96,6 +119,9 @@ lresume(lua_State *L) {
|
|||||||
lua_pop(L,1);
|
lua_pop(L,1);
|
||||||
lua_pushvalue(L,1);
|
lua_pushvalue(L,1);
|
||||||
double ti = get_time();
|
double ti = get_time();
|
||||||
|
#ifdef DEBUG_LOG
|
||||||
|
fprintf(stderr, "PROFILE [%p] resume\n", from);
|
||||||
|
#endif
|
||||||
lua_pushnumber(L, ti);
|
lua_pushnumber(L, ti);
|
||||||
lua_rawset(L, lua_upvalueindex(1)); // set start time
|
lua_rawset(L, lua_upvalueindex(1)); // set start time
|
||||||
}
|
}
|
||||||
@@ -106,8 +132,25 @@ lresume(lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lyield(lua_State *L) {
|
lresume(lua_State *L) {
|
||||||
lua_pushthread(L);
|
lua_pushvalue(L,1);
|
||||||
|
|
||||||
|
return timing_resume(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lresume_co(lua_State *L) {
|
||||||
|
luaL_checktype(L, 2, LUA_TTHREAD);
|
||||||
|
lua_rotate(L, 2, -1);
|
||||||
|
|
||||||
|
return timing_resume(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
timing_yield(lua_State *L) {
|
||||||
|
#ifdef DEBUG_LOG
|
||||||
|
lua_State *from = lua_tothread(L, -1);
|
||||||
|
#endif
|
||||||
lua_rawget(L, lua_upvalueindex(2)); // check total time
|
lua_rawget(L, lua_upvalueindex(2)); // check total time
|
||||||
if (lua_isnil(L, -1)) {
|
if (lua_isnil(L, -1)) {
|
||||||
lua_pop(L,1);
|
lua_pop(L,1);
|
||||||
@@ -120,7 +163,11 @@ lyield(lua_State *L) {
|
|||||||
double starttime = lua_tonumber(L, -1);
|
double starttime = lua_tonumber(L, -1);
|
||||||
lua_pop(L,1);
|
lua_pop(L,1);
|
||||||
|
|
||||||
ti += diff_time(starttime);
|
double diff = diff_time(starttime);
|
||||||
|
ti += diff;
|
||||||
|
#ifdef DEBUG_LOG
|
||||||
|
fprintf(stderr, "PROFILE [%p] yield (%lf/%lf)\n", from, diff, ti);
|
||||||
|
#endif
|
||||||
|
|
||||||
lua_pushthread(L);
|
lua_pushthread(L);
|
||||||
lua_pushnumber(L, ti);
|
lua_pushnumber(L, ti);
|
||||||
@@ -132,6 +179,21 @@ lyield(lua_State *L) {
|
|||||||
return co_yield(L);
|
return co_yield(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lyield(lua_State *L) {
|
||||||
|
lua_pushthread(L);
|
||||||
|
|
||||||
|
return timing_yield(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lyield_co(lua_State *L) {
|
||||||
|
luaL_checktype(L, 1, LUA_TTHREAD);
|
||||||
|
lua_rotate(L, 1, -1);
|
||||||
|
|
||||||
|
return timing_yield(L);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
luaopen_profile(lua_State *L) {
|
luaopen_profile(lua_State *L) {
|
||||||
luaL_checkversion(L);
|
luaL_checkversion(L);
|
||||||
@@ -140,6 +202,8 @@ luaopen_profile(lua_State *L) {
|
|||||||
{ "stop", lstop },
|
{ "stop", lstop },
|
||||||
{ "resume", lresume },
|
{ "resume", lresume },
|
||||||
{ "yield", lyield },
|
{ "yield", lyield },
|
||||||
|
{ "resume_co", lresume_co },
|
||||||
|
{ "yield_co", lyield_co },
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
luaL_newlibtable(L,l);
|
luaL_newlibtable(L,l);
|
||||||
@@ -154,7 +218,7 @@ luaopen_profile(lua_State *L) {
|
|||||||
lua_setmetatable(L, -3);
|
lua_setmetatable(L, -3);
|
||||||
lua_setmetatable(L, -3);
|
lua_setmetatable(L, -3);
|
||||||
|
|
||||||
lua_pushnil(L);
|
lua_pushnil(L); // cfunction (coroutine.resume or coroutine.yield)
|
||||||
luaL_setfuncs(L,l,3);
|
luaL_setfuncs(L,l,3);
|
||||||
|
|
||||||
int libtable = lua_gettop(L);
|
int libtable = lua_gettop(L);
|
||||||
@@ -166,20 +230,33 @@ luaopen_profile(lua_State *L) {
|
|||||||
if (co_resume == NULL)
|
if (co_resume == NULL)
|
||||||
return luaL_error(L, "Can't get coroutine.resume");
|
return luaL_error(L, "Can't get coroutine.resume");
|
||||||
lua_pop(L,1);
|
lua_pop(L,1);
|
||||||
|
|
||||||
lua_getfield(L, libtable, "resume");
|
lua_getfield(L, libtable, "resume");
|
||||||
lua_pushcfunction(L, co_resume);
|
lua_pushcfunction(L, co_resume);
|
||||||
lua_setupvalue(L, -2, 3);
|
lua_setupvalue(L, -2, 3);
|
||||||
lua_pop(L,1);
|
lua_pop(L,1);
|
||||||
|
|
||||||
|
lua_getfield(L, libtable, "resume_co");
|
||||||
|
lua_pushcfunction(L, co_resume);
|
||||||
|
lua_setupvalue(L, -2, 3);
|
||||||
|
lua_pop(L,1);
|
||||||
|
|
||||||
lua_getfield(L, -1, "yield");
|
lua_getfield(L, -1, "yield");
|
||||||
|
|
||||||
lua_CFunction co_yield = lua_tocfunction(L, -1);
|
lua_CFunction co_yield = lua_tocfunction(L, -1);
|
||||||
if (co_yield == NULL)
|
if (co_yield == NULL)
|
||||||
return luaL_error(L, "Can't get coroutine.yield");
|
return luaL_error(L, "Can't get coroutine.yield");
|
||||||
lua_pop(L,1);
|
lua_pop(L,1);
|
||||||
|
|
||||||
lua_getfield(L, libtable, "yield");
|
lua_getfield(L, libtable, "yield");
|
||||||
lua_pushcfunction(L, co_yield);
|
lua_pushcfunction(L, co_yield);
|
||||||
lua_setupvalue(L, -2, 3);
|
lua_setupvalue(L, -2, 3);
|
||||||
|
lua_pop(L,1);
|
||||||
|
|
||||||
|
lua_getfield(L, libtable, "yield_co");
|
||||||
|
lua_pushcfunction(L, co_yield);
|
||||||
|
lua_setupvalue(L, -2, 3);
|
||||||
|
lua_pop(L,1);
|
||||||
|
|
||||||
lua_settop(L, libtable);
|
lua_settop(L, libtable);
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ local coroutine = coroutine
|
|||||||
local coroutine_resume = coroutine.resume
|
local coroutine_resume = coroutine.resume
|
||||||
local coroutine_yield = coroutine.yield
|
local coroutine_yield = coroutine.yield
|
||||||
local coroutine_status = coroutine.status
|
local coroutine_status = coroutine.status
|
||||||
|
local coroutine_running = coroutine.running
|
||||||
|
|
||||||
local select = select
|
local select = select
|
||||||
local skynetco = {}
|
local skynetco = {}
|
||||||
@@ -23,30 +24,25 @@ function skynetco.create(f)
|
|||||||
return co
|
return co
|
||||||
end
|
end
|
||||||
|
|
||||||
function skynetco.isskynetcoroutine(co)
|
|
||||||
co = co or coroutine.running()
|
|
||||||
return skynet_coroutines[co] ~= nil
|
|
||||||
end
|
|
||||||
|
|
||||||
do -- begin skynetco.resume
|
do -- begin skynetco.resume
|
||||||
|
|
||||||
local profile = require "profile"
|
local profile = require "profile"
|
||||||
-- skynet use profile.resume/yield instead of coroutine.resume/yield
|
-- skynet use profile.resume_co/yield_co instead of coroutine.resume/yield
|
||||||
-- read skynet.lua for detail
|
|
||||||
local skynet_resume = profile.resume
|
local skynet_resume = profile.resume_co
|
||||||
local skynet_yield = profile.yield
|
local skynet_yield = profile.yield_co
|
||||||
|
|
||||||
local function unlock(co, ...)
|
local function unlock(co, ...)
|
||||||
skynet_coroutines[co] = true
|
skynet_coroutines[co] = true
|
||||||
return ...
|
return ...
|
||||||
end
|
end
|
||||||
|
|
||||||
local function skynet_yielding(co, ...)
|
local function skynet_yielding(co, from, ...)
|
||||||
skynet_coroutines[co] = false
|
skynet_coroutines[co] = false
|
||||||
return unlock(co, skynet_resume(co, skynet_yield(...)))
|
return unlock(co, skynet_resume(co, from, skynet_yield(from, ...)))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function resume(co, ok, ...)
|
local function resume(co, from, ok, ...)
|
||||||
if not ok then
|
if not ok then
|
||||||
return ok, ...
|
return ok, ...
|
||||||
elseif coroutine_status(co) == "dead" then
|
elseif coroutine_status(co) == "dead" then
|
||||||
@@ -57,10 +53,13 @@ do -- begin skynetco.resume
|
|||||||
return true, select(2, ...)
|
return true, select(2, ...)
|
||||||
else
|
else
|
||||||
-- blocked in skynet framework, so raise the yielding message
|
-- blocked in skynet framework, so raise the yielding message
|
||||||
return resume(co, skynet_yielding(co, ...))
|
return resume(co, from, skynet_yielding(co, from, ...))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- record the root of coroutine caller (It should be a skynet thread)
|
||||||
|
local coroutine_caller = setmetatable({} , { __mode = "kv" })
|
||||||
|
|
||||||
function skynetco.resume(co, ...)
|
function skynetco.resume(co, ...)
|
||||||
local co_status = skynet_coroutines[co]
|
local co_status = skynet_coroutines[co]
|
||||||
if not co_status then
|
if not co_status then
|
||||||
@@ -75,7 +74,19 @@ function skynetco.resume(co, ...)
|
|||||||
return false, "cannot resume none skynet coroutine"
|
return false, "cannot resume none skynet coroutine"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return resume(co, coroutine_resume(co, ...))
|
local from = coroutine_running()
|
||||||
|
local caller = coroutine_caller[from] or from
|
||||||
|
coroutine_caller[co] = caller
|
||||||
|
return resume(co, caller, coroutine_resume(co, ...))
|
||||||
|
end
|
||||||
|
|
||||||
|
function skynetco.thread(co)
|
||||||
|
co = co or coroutine_running()
|
||||||
|
if skynet_coroutines[co] ~= nil then
|
||||||
|
return coroutine_caller[co] , false
|
||||||
|
else
|
||||||
|
return co, true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end -- end of skynetco.resume
|
end -- end of skynetco.resume
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
local skynet = require "skynet"
|
local skynet = require "skynet"
|
||||||
-- You should use skynet.coroutine instead of origin coroutine in skynet
|
-- You should use skynet.coroutine instead of origin coroutine in skynet
|
||||||
local coroutine = require "skynet.coroutine"
|
local coroutine = require "skynet.coroutine"
|
||||||
|
local profile = require "profile"
|
||||||
|
|
||||||
local function status(co)
|
local function status(co)
|
||||||
repeat
|
repeat
|
||||||
@@ -18,21 +19,35 @@ end
|
|||||||
|
|
||||||
local function test(n)
|
local function test(n)
|
||||||
local co = coroutine.running()
|
local co = coroutine.running()
|
||||||
print ("begin", coroutine.isskynetcoroutine(co))
|
print ("begin", co, coroutine.thread(co)) -- false
|
||||||
skynet.fork(status, co)
|
skynet.fork(status, co)
|
||||||
for i=1,n do
|
for i=1,n do
|
||||||
skynet.sleep(100)
|
skynet.sleep(100)
|
||||||
coroutine.yield(i)
|
coroutine.yield(i)
|
||||||
end
|
end
|
||||||
print "end"
|
print ("end", co)
|
||||||
end
|
end
|
||||||
|
|
||||||
skynet.start(function()
|
local function main()
|
||||||
print("Is the main thead a skynet coroutine ?", coroutine.isskynetcoroutine()) -- always false
|
|
||||||
print(coroutine.resume(coroutine.running())) -- always return false
|
|
||||||
local f = coroutine.wrap(test)
|
local f = coroutine.wrap(test)
|
||||||
|
coroutine.yield "begin"
|
||||||
for i=1,3 do
|
for i=1,3 do
|
||||||
local n = f(5)
|
local n = f(5)
|
||||||
print("main thread",n)
|
print("main thread",n)
|
||||||
end
|
end
|
||||||
|
coroutine.yield "end"
|
||||||
|
print("main thread time:", profile.stop(coroutine.thread()))
|
||||||
|
end
|
||||||
|
|
||||||
|
skynet.start(function()
|
||||||
|
print("Main thead :", coroutine.thread()) -- true
|
||||||
|
print(coroutine.resume(coroutine.running())) -- always return false
|
||||||
|
|
||||||
|
profile.start()
|
||||||
|
|
||||||
|
local f = coroutine.wrap(main)
|
||||||
|
print("main step", f())
|
||||||
|
print("main step", f())
|
||||||
|
print("main step", f())
|
||||||
|
-- print("main thread time:", profile.stop())
|
||||||
end)
|
end)
|
||||||
|
|||||||
Reference in New Issue
Block a user