[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