123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- #define LUA_LIB
- #include <stdio.h>
- #include <lua.h>
- #include <lauxlib.h>
- #include <time.h>
- #if defined(__APPLE__)
- #include <mach/task.h>
- #include <mach/mach.h>
- #endif
- #define NANOSEC 1000000000
- #define MICROSEC 1000000
- // #define DEBUG_LOG
- static double
- get_time() {
- #if !defined(__APPLE__)
- struct timespec ti;
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ti);
- int sec = ti.tv_sec & 0xffff;
- int nsec = ti.tv_nsec;
- return (double)sec + (double)nsec / NANOSEC;
- #else
- struct task_thread_times_info aTaskInfo;
- mach_msg_type_number_t aTaskInfoCount = TASK_THREAD_TIMES_INFO_COUNT;
- if (KERN_SUCCESS != task_info(mach_task_self(), TASK_THREAD_TIMES_INFO, (task_info_t )&aTaskInfo, &aTaskInfoCount)) {
- return 0;
- }
- int sec = aTaskInfo.user_time.seconds & 0xffff;
- int msec = aTaskInfo.user_time.microseconds;
- return (double)sec + (double)msec / MICROSEC;
- #endif
- }
- static inline double
- diff_time(double start) {
- double now = get_time();
- if (now < start) {
- return now + 0x10000 - start;
- } else {
- return now - start;
- }
- }
- static int
- lstart(lua_State *L) {
- if (lua_gettop(L) != 0) {
- lua_settop(L,1);
- luaL_checktype(L, 1, LUA_TTHREAD);
- } else {
- lua_pushthread(L);
- }
- lua_pushvalue(L, 1); // push coroutine
- lua_rawget(L, lua_upvalueindex(2));
- if (!lua_isnil(L, -1)) {
- return luaL_error(L, "Thread %p start profile more than once", lua_topointer(L, 1));
- }
- lua_pushvalue(L, 1); // push coroutine
- lua_pushnumber(L, 0);
- lua_rawset(L, lua_upvalueindex(2));
- lua_pushvalue(L, 1); // push coroutine
- 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));
- return 0;
- }
- static int
- lstop(lua_State *L) {
- if (lua_gettop(L) != 0) {
- lua_settop(L,1);
- luaL_checktype(L, 1, LUA_TTHREAD);
- } else {
- lua_pushthread(L);
- }
- lua_pushvalue(L, 1); // push coroutine
- lua_rawget(L, lua_upvalueindex(1));
- 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));
- lua_pushvalue(L, 1); // push coroutine
- lua_rawget(L, lua_upvalueindex(2));
- double total_time = lua_tonumber(L, -1);
- lua_pushvalue(L, 1); // push coroutine
- lua_pushnil(L);
- lua_rawset(L, lua_upvalueindex(1));
- lua_pushvalue(L, 1); // push coroutine
- lua_pushnil(L);
- lua_rawset(L, lua_upvalueindex(2));
- total_time += ti;
- lua_pushnumber(L, total_time);
- #ifdef DEBUG_LOG
- fprintf(stderr, "PROFILE [%p] stop (%lf/%lf)\n", lua_tothread(L,1), ti, total_time);
- #endif
- return 1;
- }
- static int
- timing_resume(lua_State *L) {
- lua_pushvalue(L, -1);
- lua_rawget(L, lua_upvalueindex(2));
- if (lua_isnil(L, -1)) { // check total time
- lua_pop(L,2); // pop from coroutine
- } else {
- lua_pop(L,1);
- double ti = get_time();
- #ifdef DEBUG_LOG
- fprintf(stderr, "PROFILE [%p] resume %lf\n", lua_tothread(L, -1), ti);
- #endif
- lua_pushnumber(L, ti);
- lua_rawset(L, lua_upvalueindex(1)); // set start time
- }
- lua_CFunction co_resume = lua_tocfunction(L, lua_upvalueindex(3));
- return co_resume(L);
- }
- static int
- lresume(lua_State *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); // 'from' coroutine rotate to the top(index -1)
- return timing_resume(L);
- }
- static int
- timing_yield(lua_State *L) {
- #ifdef DEBUG_LOG
- lua_State *from = lua_tothread(L, -1);
- #endif
- lua_pushvalue(L, -1);
- lua_rawget(L, lua_upvalueindex(2)); // check total time
- if (lua_isnil(L, -1)) {
- lua_pop(L,2);
- } else {
- double ti = lua_tonumber(L, -1);
- lua_pop(L,1);
- lua_pushvalue(L, -1); // push coroutine
- lua_rawget(L, lua_upvalueindex(1));
- double starttime = lua_tonumber(L, -1);
- lua_pop(L,1);
- double diff = diff_time(starttime);
- ti += diff;
- #ifdef DEBUG_LOG
- fprintf(stderr, "PROFILE [%p] yield (%lf/%lf)\n", from, diff, ti);
- #endif
- lua_pushvalue(L, -1); // push coroutine
- lua_pushnumber(L, ti);
- lua_rawset(L, lua_upvalueindex(2));
- lua_pop(L, 1); // pop coroutine
- }
- lua_CFunction co_yield = lua_tocfunction(L, lua_upvalueindex(3));
- 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);
- }
- LUAMOD_API int
- luaopen_skynet_profile(lua_State *L) {
- luaL_checkversion(L);
- luaL_Reg l[] = {
- { "start", lstart },
- { "stop", lstop },
- { "resume", lresume },
- { "yield", lyield },
- { "resume_co", lresume_co },
- { "yield_co", lyield_co },
- { NULL, NULL },
- };
- luaL_newlibtable(L,l);
- lua_newtable(L); // table thread->start time
- lua_newtable(L); // table thread->total time
- lua_newtable(L); // weak table
- lua_pushliteral(L, "kv");
- lua_setfield(L, -2, "__mode");
- lua_pushvalue(L, -1);
- lua_setmetatable(L, -3);
- lua_setmetatable(L, -3);
- lua_pushnil(L); // cfunction (coroutine.resume or coroutine.yield)
- luaL_setfuncs(L,l,3);
- int libtable = lua_gettop(L);
- lua_getglobal(L, "coroutine");
- lua_getfield(L, -1, "resume");
- lua_CFunction co_resume = lua_tocfunction(L, -1);
- if (co_resume == NULL)
- return luaL_error(L, "Can't get coroutine.resume");
- lua_pop(L,1);
- lua_getfield(L, libtable, "resume");
- lua_pushcfunction(L, co_resume);
- lua_setupvalue(L, -2, 3);
- 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_CFunction co_yield = lua_tocfunction(L, -1);
- if (co_yield == NULL)
- return luaL_error(L, "Can't get coroutine.yield");
- lua_pop(L,1);
- lua_getfield(L, libtable, "yield");
- lua_pushcfunction(L, co_yield);
- 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);
- return 1;
- }
|