Index: TODO =================================================================== diff -u -r984a062f8f5693e249ef6fd36c863db2af6693a9 -rb14118b7068e3c1e903b9a516eef0c86101b24d9 --- TODO (.../TODO) (revision 984a062f8f5693e249ef6fd36c863db2af6693a9) +++ TODO (.../TODO) (revision b14118b7068e3c1e903b9a516eef0c86101b24d9) @@ -2399,8 +2399,16 @@ * make quality checks (missing documentation, ...) optional? how to deal with non-resolvable quality checks? * provide a renderer for XOTcl @-notation to produce object structure - for the new doctool (makes the old documentation usabel, eg. for XOTcl2) + for the new doctool (makes the old documentation usable, eg. for XOTcl2) +- first steps towards DTRACE support +- dtrace: + * track objects in method invocations + * trace result codes in method-return + * add some dtrace sample scripts + * add dtrace header file dependency + + TODO: - serializer: check, why catch is needed for object-level alias Index: dtrace/README =================================================================== diff -u --- dtrace/README (revision 0) +++ dtrace/README (revision b14118b7068e3c1e903b9a516eef0c86101b24d9) @@ -0,0 +1,15 @@ + +Run the script e.g. via the following command: + + sudo dtrace -q -F -s dtrace/timestamps.d -c "./nxsh tests/object-system.test" + +Hints: + +* Make sure that a "package require nx" works for root as well + (install nx, or provide a TCLLIBPATH, etc.). + +* If dtrace compliation fails (e.g. "... nsf*:::method-entry does not + match any probes", start an nxsh in a different window to make the + probes known to the kernel. + +-gustaf neumann \ No newline at end of file Index: dtrace/execution-flow.d =================================================================== diff -u --- dtrace/execution-flow.d (revision 0) +++ dtrace/execution-flow.d (revision b14118b7068e3c1e903b9a516eef0c86101b24d9) @@ -0,0 +1,9 @@ +nsf*:::method-entry +{ + printf("%s %s.%s\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +nsf*:::method-return +{ + printf("%s %s.%s\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} \ No newline at end of file Index: dtrace/timestamps-q.d =================================================================== diff -u --- dtrace/timestamps-q.d (revision 0) +++ dtrace/timestamps-q.d (revision b14118b7068e3c1e903b9a516eef0c86101b24d9) @@ -0,0 +1,12 @@ +nsf*:::method-entry +/copyinstr(arg1) == "::nx::Object"/ +{ + self->start = timestamp; +} + +nsf*:::method-return +/copyinstr(arg1) == "::nx::Object" && self->start/ +{ + @[copyinstr(arg1), copyinstr(arg2)] = quantize(timestamp - self->start); + self->start = 0; +} \ No newline at end of file Index: dtrace/timestamps.d =================================================================== diff -u --- dtrace/timestamps.d (revision 0) +++ dtrace/timestamps.d (revision b14118b7068e3c1e903b9a516eef0c86101b24d9) @@ -0,0 +1,11 @@ +nsf*:::method-entry +{ + self->start = timestamp; +} + +nsf*:::method-return +/self->start/ +{ + @[copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)] = avg(timestamp - self->start); + self->start = 0; +} \ No newline at end of file Index: generic/nsf.c =================================================================== diff -u -r19ef72a5f87241def42fa2a2ec15e28a8717b59b -rb14118b7068e3c1e903b9a516eef0c86101b24d9 --- generic/nsf.c (.../nsf.c) (revision 19ef72a5f87241def42fa2a2ec15e28a8717b59b) +++ generic/nsf.c (.../nsf.c) (revision b14118b7068e3c1e903b9a516eef0c86101b24d9) @@ -7475,7 +7475,7 @@ result = ObjectDispatchFinalize(interp, cscPtr, result /*, "NRE" , methodName*/); #endif - CscFinish(interp, cscPtr, "scripted finalize"); + CscFinish(interp, cscPtr, result, "scripted finalize"); } return result; @@ -7562,7 +7562,7 @@ */ #if defined(NRE) //CscListRemove(interp, cscPtr); - CscFinish(interp, cscPtr, "guard failed"); + CscFinish(interp, cscPtr, result, "guard failed"); #endif return result; } @@ -7641,7 +7641,7 @@ #endif } else /* result != OK */ { #if defined(NRE) - CscFinish(interp, cscPtr, "nre, prep failed"); + CscFinish(interp, cscPtr, result, "nre, prep failed"); #endif } @@ -7977,11 +7977,11 @@ #if defined(NRE) if ((cscPtr->flags & NSF_CSC_CALL_IS_NRE) == 0) { CscListRemove(interp, cscPtr); - CscFinish(interp, cscPtr, "csc cleanup"); + CscFinish(interp, cscPtr, result, "csc cleanup"); } #else CscListRemove(interp, cscPtr); - CscFinish(interp, cscPtr, "csc cleanup"); + CscFinish(interp, cscPtr, result, "csc cleanup"); #endif return result; @@ -8340,7 +8340,7 @@ if (!(cscPtr->flags & NSF_CSC_CALL_IS_NRE)) { result = ObjectDispatchFinalize(interp, cscPtr, result /*, "immediate" , methodName*/); CscListRemove(interp, cscPtr); - CscFinish(interp, cscPtr, "non-scripted finalize"); + CscFinish(interp, cscPtr, result, "non-scripted finalize"); } /*fprintf(stderr, "ObjectDispatch %s.%s returns %d\n", @@ -16899,7 +16899,7 @@ */ Nsf_PopFrameCsc(interp, framePtr2); CscListRemove(interp, cscPtr); - CscFinish(interp, cscPtr, "converter object frame"); + CscFinish(interp, cscPtr, result, "converter object frame"); Tcl_Interp_varFramePtr(interp) = varFramePtr; /*fprintf(stderr, "NsfOConfigureMethod_ attribute %s evaluated %s => (%d)\n", Index: generic/nsf.h =================================================================== diff -u -r0078146a2bcee10f8f7f65313b86b288f6d2f652 -rb14118b7068e3c1e903b9a516eef0c86101b24d9 --- generic/nsf.h (.../nsf.h) (revision 0078146a2bcee10f8f7f65313b86b288f6d2f652) +++ generic/nsf.h (.../nsf.h) (revision b14118b7068e3c1e903b9a516eef0c86101b24d9) @@ -138,23 +138,37 @@ # define DO_CLEANUP #endif +#ifdef NSF_DTRACE +# define NSF_DTRACE_METHOD_RETURN_PROBE(cscPtr,retCode) \ + if (cscPtr->cmdPtr && NSF_DTRACE_METHOD_RETURN_ENABLED()) { \ + NSF_DTRACE_METHOD_RETURN(ObjectName(cscPtr->self), \ + cscPtr->cl ? ClassName(cscPtr->cl) : ObjectName(cscPtr->self), \ + cscPtr->methodName, \ + retCode); \ + } +#else +# define NSF_DTRACE_METHOD_RETURN_PROBE(cscPtr,retCode) {} +#endif + #ifdef NSF_DEVELOPMENT # define CHECK_ACTIVATION_COUNTS 1 # define NsfCleanupObject(object,string) \ /*fprintf(stderr, "NsfCleanupObject %p %s\n",object,string);*/ \ NsfCleanupObject_(object) -# define CscFinish(interp,cscPtr,string) \ +# define CscFinish(interp,cscPtr,retCode,string) \ /*fprintf(stderr, "CscFinish %p %s\n",cscPtr,string);*/ \ + NSF_DTRACE_METHOD_RETURN_PROBE(cscPtr,retCode); \ CscFinish_(interp, cscPtr) #else # define NDEBUG 1 -# define NsfCleanupObject(object,string) \ +# define NsfCleanupObject(object,string) \ NsfCleanupObject_(object) -# define CscFinish(interp,cscPtr,string) \ +# define CscFinish(interp,cscPtr,retCode,string) \ + NSF_DTRACE_METHOD_RETURN_PROBE(cscPtr,retCode); \ CscFinish_(interp, cscPtr) #endif -#if defined(NSF_PROFILE) +#if defined(NSF_PROFILE) || defined(NSF_DTRACE) # define CscInit(cscPtr, object, cl, cmd, frametype, flags, method) \ CscInit_(cscPtr, object, cl, cmd, frametype, flags); cscPtr->methodName = (method); #else Index: generic/nsfDTrace.d =================================================================== diff -u -r0078146a2bcee10f8f7f65313b86b288f6d2f652 -rb14118b7068e3c1e903b9a516eef0c86101b24d9 --- generic/nsfDTrace.d (.../nsfDTrace.d) (revision 0078146a2bcee10f8f7f65313b86b288f6d2f652) +++ generic/nsfDTrace.d (.../nsfDTrace.d) (revision b14118b7068e3c1e903b9a516eef0c86101b24d9) @@ -23,20 +23,22 @@ /* * nsf*:::method-entry probe * triggered immediately before method bytecode execution - * arg0: class/object name (string) - * arg1: method name (string) - * arg2: number of arguments (int) - * arg3: array of proc argument objects (Tcl_Obj**) + * arg0: object name (string) + * arg1: class/object name (string) + * arg2: method name (string) + * arg3: number of arguments (int) + * arg4: array of proc argument objects (Tcl_Obj**) */ - probe method__entry(char *class, char* method, int objc, Tcl_Obj **objv); + probe method__entry(char* object, char *class, char* method, int objc, Tcl_Obj **objv); /* * nsf*:::proc-return probe * triggered immediately after proc bytecode execution - * arg0: class/object name (string) - * arg1: method name (string) - * arg2: return code (int) + * arg0: object name (string) + * arg1: class/object name (string) + * arg2: method name (string) + * arg3: return code (int) */ - probe method__return(char *class, char* name, int code); + probe method__return(char *object, char *class, char* name, int code); /* * tcl*:::proc-result probe * triggered after proc-return probe and result processing Index: generic/nsfDTrace.h =================================================================== diff -u -r0078146a2bcee10f8f7f65313b86b288f6d2f652 -rb14118b7068e3c1e903b9a516eef0c86101b24d9 --- generic/nsfDTrace.h (.../nsfDTrace.h) (revision 0078146a2bcee10f8f7f65313b86b288f6d2f652) +++ generic/nsfDTrace.h (.../nsfDTrace.h) (revision b14118b7068e3c1e903b9a516eef0c86101b24d9) @@ -15,18 +15,18 @@ #define NSF_TYPEDEFS "___dtrace_typedefs$nsf$v2$54636c5f4f626a" -#define NSF_METHOD_ENTRY(arg0, arg1, arg2, arg3) \ +#define NSF_METHOD_ENTRY(arg0, arg1, arg2, arg3, arg4) \ do { \ __asm__ volatile(".reference " NSF_TYPEDEFS); \ - __dtrace_probe$nsf$method__entry$v1$63686172202a$63686172202a$696e74$54636c5f4f626a202a2a(arg0, arg1, arg2, arg3); \ + __dtrace_probe$nsf$method__entry$v1$63686172202a$63686172202a$63686172202a$696e74$54636c5f4f626a202a2a(arg0, arg1, arg2, arg3, arg4); \ __asm__ volatile(".reference " NSF_STABILITY); \ } while (0) #define NSF_METHOD_ENTRY_ENABLED() \ __dtrace_isenabled$nsf$method__entry$v1() -#define NSF_METHOD_RETURN(arg0, arg1, arg2) \ +#define NSF_METHOD_RETURN(arg0, arg1, arg2, arg3) \ do { \ __asm__ volatile(".reference " NSF_TYPEDEFS); \ - __dtrace_probe$nsf$method__return$v1$63686172202a$63686172202a$696e74(arg0, arg1, arg2); \ + __dtrace_probe$nsf$method__return$v1$63686172202a$63686172202a$63686172202a$696e74(arg0, arg1, arg2, arg3); \ __asm__ volatile(".reference " NSF_STABILITY); \ } while (0) #define NSF_METHOD_RETURN_ENABLED() \ @@ -57,9 +57,9 @@ __dtrace_isenabled$nsf$object__destroy$v1() -extern void __dtrace_probe$nsf$method__entry$v1$63686172202a$63686172202a$696e74$54636c5f4f626a202a2a(char *, char *, int, Tcl_Obj **); +extern void __dtrace_probe$nsf$method__entry$v1$63686172202a$63686172202a$63686172202a$696e74$54636c5f4f626a202a2a(char *, char *, char *, int, Tcl_Obj **); extern int __dtrace_isenabled$nsf$method__entry$v1(void); -extern void __dtrace_probe$nsf$method__return$v1$63686172202a$63686172202a$696e74(char *, char *, int); +extern void __dtrace_probe$nsf$method__return$v1$63686172202a$63686172202a$63686172202a$696e74(char *, char *, char *, int); extern int __dtrace_isenabled$nsf$method__return$v1(void); extern void __dtrace_probe$nsf$object__create_end$v1$63686172202a$63686172202a(char *, char *); extern int __dtrace_isenabled$nsf$object__create_end$v1(void); Index: generic/nsfInt.h =================================================================== diff -u -r0078146a2bcee10f8f7f65313b86b288f6d2f652 -rb14118b7068e3c1e903b9a516eef0c86101b24d9 --- generic/nsfInt.h (.../nsfInt.h) (revision 0078146a2bcee10f8f7f65313b86b288f6d2f652) +++ generic/nsfInt.h (.../nsfInt.h) (revision b14118b7068e3c1e903b9a516eef0c86101b24d9) @@ -41,13 +41,13 @@ # endif # define NSF_DTRACE_METHOD_ENTRY_ENABLED() unlikely(NSF_METHOD_ENTRY_ENABLED()) # define NSF_DTRACE_METHOD_RETURN_ENABLED() unlikely(NSF_METHOD_RETURN_ENABLED()) -# define NSF_DTRACE_METHOD_ENTRY(a0, a1, a2, a3) NSF_METHOD_ENTRY(a0, a1, a2, a3) -# define NSF_DTRACE_METHOD_RETURN(a0, a1, a2) NSF_METHOD_RETURN(a0, a1, a2) +# define NSF_DTRACE_METHOD_ENTRY(a0, a1, a2, a3, a4) NSF_METHOD_ENTRY(a0, a1, a2, a3, a4) +# define NSF_DTRACE_METHOD_RETURN(a0, a1, a2, a3) NSF_METHOD_RETURN(a0, a1, a2, a3) #else # define NSF_DTRACE_METHOD_ENTRY_ENABLED() 0 # define NSF_DTRACE_METHOD_RETURN_ENABLED() 0 -# define NSF_DTRACE_METHOD_ENTRY(a0, a1, a2, a3) {} -# define NSF_DTRACE_METHOD_RETURN(a0, a1, a2) {} +# define NSF_DTRACE_METHOD_ENTRY(a0, a1, a2, a3, a4) {} +# define NSF_DTRACE_METHOD_RETURN(a0, a1, a2, a3) {} #endif @@ -671,7 +671,7 @@ int objc; unsigned short frameType; unsigned short flags; -#if defined(NSF_PROFILE) +#if defined(NSF_PROFILE) || defined(NSF_DTRACE) long int startUsec; long int startSec; CONST char *methodName; Index: generic/nsfStack.c =================================================================== diff -u -r0078146a2bcee10f8f7f65313b86b288f6d2f652 -rb14118b7068e3c1e903b9a516eef0c86101b24d9 --- generic/nsfStack.c (.../nsfStack.c) (revision 0078146a2bcee10f8f7f65313b86b288f6d2f652) +++ generic/nsfStack.c (.../nsfStack.c) (revision b14118b7068e3c1e903b9a516eef0c86101b24d9) @@ -727,7 +727,7 @@ /* Mask out IS_NRE, since Tcl_PopCallFrame takes care about TclStackFree */ cscPtr->flags &= ~NSF_CSC_CALL_IS_NRE; #endif - CscFinish(interp, cscPtr, "popall"); + CscFinish(interp, cscPtr, TCL_OK, "popall"); } else if (frameFlags & FRAME_IS_NSF_OBJECT) { Tcl_CallFrame_varTablePtr(framePtr) = NULL; } @@ -745,7 +745,7 @@ unstackedEntries = unstackedEntries->nextPtr, count ++) { NsfCallStackContent *cscPtr = (NsfCallStackContent *)unstackedEntries->cl; CscListRemove(interp, cscPtr); - CscFinish(interp, cscPtr, "unwind"); + CscFinish(interp, cscPtr, TCL_OK, "unwind"); } if (count>0 && RUNTIME_STATE(interp)->debugLevel > 0) { @@ -832,7 +832,8 @@ if (cmd) { if (NSF_DTRACE_METHOD_ENTRY_ENABLED()) { // TODO: missing arg list - NSF_DTRACE_METHOD_ENTRY(cl ? ClassName(cl) : ObjectName(object), + NSF_DTRACE_METHOD_ENTRY(ObjectName(object), + cl ? ClassName(cl) : ObjectName(object), Tcl_GetCommandName(object->teardown,cmd), 0, ""); } @@ -902,11 +903,6 @@ NsfProfileRecordMethodData(interp, cscPtr); } #endif - if (NSF_DTRACE_METHOD_RETURN_ENABLED()) { - // TODO: missing returcode handling, currently just when cmdPtr is set - NSF_DTRACE_METHOD_RETURN(cscPtr->cl ? ClassName(cscPtr->cl) : ObjectName(cscPtr->self), - cscPtr->methodName, TCL_OK); - } object = cscPtr->self;