[Erp5-report] r25367 - in /erp5/trunk/utils/tiny_profiler: ./ __init__.py profiler.py

nobody at svn.erp5.org nobody at svn.erp5.org
Thu Jan 29 17:56:05 CET 2009


Author: vincent
Date: Thu Jan 29 17:56:05 2009
New Revision: 25367

URL: http://svn.erp5.org?rev=25367&view=rev
Log:
Initial import.

Added:
    erp5/trunk/utils/tiny_profiler/
    erp5/trunk/utils/tiny_profiler/__init__.py
    erp5/trunk/utils/tiny_profiler/profiler.py

Added: erp5/trunk/utils/tiny_profiler/__init__.py
URL: http://svn.erp5.org/erp5/trunk/utils/tiny_profiler/__init__.py?rev=25367&view=auto
==============================================================================
--- erp5/trunk/utils/tiny_profiler/__init__.py (added)
+++ erp5/trunk/utils/tiny_profiler/__init__.py [utf8] Thu Jan 29 17:56:05 2009
@@ -1,0 +1,2 @@
+from profiler import profiler_decorator, profiler_report, profiler_reset
+

Added: erp5/trunk/utils/tiny_profiler/profiler.py
URL: http://svn.erp5.org/erp5/trunk/utils/tiny_profiler/profiler.py?rev=25367&view=auto
==============================================================================
--- erp5/trunk/utils/tiny_profiler/profiler.py (added)
+++ erp5/trunk/utils/tiny_profiler/profiler.py [utf8] Thu Jan 29 17:56:05 2009
@@ -1,0 +1,118 @@
+#!/usr/bin/python
+##############################################################################
+#
+# Copyright (c) 2009 Nexedi SA and Contributors. All Rights Reserved.
+#                    Vincent Pelletier <vincent at nexedi.com>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+##############################################################################
+
+"""
+  Simple thread-safe python profiler.
+
+  Typical use:
+  - Wrap functions/methods to monitor in profiler_decorator
+  - Execute code
+  - Call profiler_report
+
+  Using a decorator to mark the functions to profile allows a slight overhead
+  at startup time when profiler is disabled and no run-time overhead at all.
+  When enabled, typical overhead is around 100% (wall clock code execution
+  takes twice the time when profiling is enabled), although it depends heavily
+  on the number of profiled function enter/exit.
+"""
+
+import sys
+from time import time
+from thread import get_ident
+
+profiler_globals = {}
+
+# PROFILER_STACK
+# list of 2-tuples
+#  method_id
+#  time at which that stack level was entered
+
+# PROFILER_STAT_DICT
+# key:
+#  method_id
+# value:
+#  2-tuple:
+#   total time
+#   call count
+
+def profiler_decorator(method):
+  func_code = method.func_code
+  method_id = '%s:%s %s' % (func_code.co_filename, func_code.co_firstlineno, func_code.co_name)
+  def wrapped(*args, **kw):
+    PROFILER_STACK, PROFILER_STAT_DICT = profiler_globals.setdefault(get_ident(), ([], {}))
+    try:
+      caller_id, since = PROFILER_STACK[-1]
+    except IndexError:
+      caller_id = None
+    else:
+      PROFILER_STAT_DICT[caller_id][0] += time() - since
+    entry = PROFILER_STAT_DICT.setdefault(method_id, [0, 0])
+    entry[1] += 1
+    PROFILER_STACK.append((method_id, time()))
+    try:
+      result = method(*args, **kw)
+    finally:
+      entry[0] += time() - PROFILER_STACK.pop()[1]
+      if caller_id is not None:
+        PROFILER_STACK[-1] = (caller_id, time())
+    return result
+  return wrapped
+
+def sort_key(a):
+  return a[1]
+
+def profiler_report():
+  # TODO: Allow user-provider sorting mechanism.
+  global_stat_dict = {}
+  total_time = 0
+  result_list = []
+  append = result_list.append
+
+  for (PROFILER_STACK, PROFILER_STAT_DICT) in profiler_globals.itervalues():
+    for key, (time, count) in PROFILER_STAT_DICT.iteritems():
+      c_time, c_count = global_stat_dict.get(key, (0, 0))
+      global_stat_dict[key] = (c_time + time, c_count + count)
+      total_time += time
+
+  profile_list = [(key, time / count)
+                  for key, (time, count) in global_stat_dict.iteritems()]
+  profile_list.sort(key=sort_key)
+
+  append('Avg     \tTotal   \t% of all\tCount   \tID')
+  for key, average in profile_list:
+    total,  count = global_stat_dict[key]
+    append('%.6fs\t%.6fs\t%.04f%% \t%7i\t%s' % (average, total, total * 100.0 / total_time, count, key))
+
+  return '\n'.join(result_list)
+
+def profiler_reset():
+  # XXX: If any thread has entered profiled code when this function is called,
+  # it will raise upon function return.
+  profiler_globals.clear()
+




More information about the Erp5-report mailing list