Commits

Sümer Cip committed 34a8149

nactuallcall field added for child function stats. needed for pstat format.

Comments (0)

Files changed (4)

 [+] stats.py can generate the sort error write a TC for that.
 [+] make full_name like : module:lineno function, maybe use same syntax in callgrind output.
 [+] add support for using wall time for profiling. Lots of people download v0.53.
-[-] clock type shall be saved in save(), merging two different profile results with different clock types is
+[+] clock type shall be saved in save(), merging two different profile results with different clock types is
     ambigous, prevent that.
+[-] maybe add a pause/resume functionality for _yappi. When wee retrieve the stats and the profiler is on user is
+    shown the internal functions used by yappi. These should be discarded?
 [-] Test debug build after merging the wackou branch.
 [-] add saving as pstat format.
 [-] add stat tests and re-TEST again. add pstat tests.
 typedef struct {
     unsigned int index;
     unsigned long callcount;
+    unsigned long nonrecursive_callcount; // holds the number of actual calls when the function is recursive.
     long long ttotal;
     struct _pit_children_info *next;
 } _pit_children_info;
     PyObject *modname;
     unsigned long lineno;
     unsigned long callcount;
-    unsigned long nonrecursive_callcount; // used in pstats, holds the number of actual calls when the function is recursive.
+    unsigned long nonrecursive_callcount; // holds the number of actual calls when the function is recursive.
     long long tsubtotal;
     long long ttotal;
     unsigned int builtin; // 0 for normal, 1 for ccall
     _pit_children_info *pci,*ppci,*newpci;
     _cstackitem *ci,*pi;
     long long elapsed;
+    int is_recursive;
 
     ci = spop(current_ctx->cs);
     if (!ci) {
 
     // are we leaving a recursive function that is already in the callstack?
     // then extract the elapsed from subtotal of the the current pit(profile item).
+    is_recursive = 0;
     if (scount(current_ctx->cs, cp) > 0) {
         cp->tsubtotal -= elapsed;
+        is_recursive = 1;
     } else {
         cp->ttotal += elapsed;
-        cp->nonrecursive_callcount++;
     }
 
     // update parent's sub total if recursive above code will extract the subtotal and
         newpci = ymalloc(sizeof(_pit_children_info));
         newpci->index = cp->index;
         newpci->callcount = 0;
+        newpci->nonrecursive_callcount = 0;
         newpci->ttotal = 0;
         newpci->next = NULL;
         if (!ppci) {
     }
     pci->callcount++;
     pci->ttotal += elapsed;
+    
+    // if function is not recursive (or in other words _currently_ _not_ found on the stack more than once)
+    // increment the relevant nactualcall param.
+    if (!is_recursive) 
+    {
+        cp->nonrecursive_callcount++;
+        pci->nonrecursive_callcount++;
+    }    
 }
 
 // context will be cleared by the free list. we do not free it here.
     children = PyList_New(0);
     pci = pt->children;
     while(pci) {
-        PyList_Append(children, Py_BuildValue("Ikf", pci->index, pci->callcount,
+        PyList_Append(children, Py_BuildValue("Ikkf", pci->index, pci->callcount, pci->nonrecursive_callcount,
                                               pci->ttotal * tickfactor()));
         pci = (_pit_children_info *)pci->next;
     }
     exc = PyObject_CallFunction(efn, "((OOkkkIffIO))", pt->name, pt->modname, pt->lineno, pt->callcount,
                         pt->nonrecursive_callcount, pt->builtin, pt->ttotal * tickfactor(), cumdiff * tickfactor(), 
                         pt->index, children);
-    // TODO: ref leak on children???
     if (!exc) {
         PyErr_Print();
         return 1; // abort enumeration
-
    def bar(self):
        pass
    def inner_foo():
        pass
    import time
    time.sleep(2.0)
    for i in range(20000000):
        pass
    a = A()
    a.bar()
    inner_foo()
    
+
    def bar(self):
        pass
    def inner_foo():
        pass
    import time
    time.sleep(2.0)
    for i in range(20000000):
        pass
    a = A()
    a.bar()
    inner_foo()
    
     """
     Class holding information for children function stats.
     """
-    _KEYS = ('index', 'ncall', 'ttot', 'full_name')
+    _KEYS = ('index', 'ncall', 'nactualcall', 'ttot', 'full_name')
     
     def __eq__(self, other):
         if other is None:
         
     def __add__(self, other):
         if other is None:
-            return self       
+            return self
+        self.nactualcall += other.nactualcall
         self.ncall += other.ncall
         self.ttot += other.ttot
              
                 console.write("full_name: %s" % child_stat.full_name)
                 console.write(CRLF)
                 console.write(" " * CHILD_STATS_LEFT_MARGIN)
-                console.write("ncall: %d" % child_stat.ncall)
+                console.write("ncall: %d/%d" % child_stat.ncall, child_stat.nactualcall)
                 console.write(CRLF)
                 console.write(" " * CHILD_STATS_LEFT_MARGIN)
                 console.write("ttot: %0.6f" % child_stat.ttot)
     """
     Gets the function profiler results with given filters and returns an iterable.
     """
-    
     stats = YFuncStats().get()
     return stats
 
     """
     Gets the thread profiler results with given filters and returns an iterable.
     """
-    
     stats = YThreadStats().get()
     return stats