[pypy-svn] r34886 - in pypy/branch/mininal-c-backend/pypy/translator: . c c/src c/test

ale at codespeak.net ale at codespeak.net
Thu Nov 23 12:03:15 CET 2006


Author: ale
Date: Thu Nov 23 12:03:10 2006
New Revision: 34886

Added:
   pypy/branch/mininal-c-backend/pypy/translator/c/src/instrument.h
      - copied unchanged from r34885, pypy/dist/pypy/translator/c/src/instrument.h
Modified:
   pypy/branch/mininal-c-backend/pypy/translator/c/database.py
   pypy/branch/mininal-c-backend/pypy/translator/c/exceptiontransform.py
   pypy/branch/mininal-c-backend/pypy/translator/c/extfunc.py
   pypy/branch/mininal-c-backend/pypy/translator/c/funcgen.py
   pypy/branch/mininal-c-backend/pypy/translator/c/genc.py
   pypy/branch/mininal-c-backend/pypy/translator/c/node.py
   pypy/branch/mininal-c-backend/pypy/translator/c/src/exception.h
   pypy/branch/mininal-c-backend/pypy/translator/c/src/g_include.h
   pypy/branch/mininal-c-backend/pypy/translator/c/src/main.h
   pypy/branch/mininal-c-backend/pypy/translator/c/src/obmalloc.c
   pypy/branch/mininal-c-backend/pypy/translator/c/src/standalone.h
   pypy/branch/mininal-c-backend/pypy/translator/c/src/support.h
   pypy/branch/mininal-c-backend/pypy/translator/c/test/test_standalone.py
   pypy/branch/mininal-c-backend/pypy/translator/driver.py
Log:
svn merge -r 34627:HEAD


Modified: pypy/branch/mininal-c-backend/pypy/translator/c/database.py
==============================================================================
--- pypy/branch/mininal-c-backend/pypy/translator/c/database.py	(original)
+++ pypy/branch/mininal-c-backend/pypy/translator/c/database.py	Thu Nov 23 12:03:10 2006
@@ -62,6 +62,8 @@
             self.gctransformer = self.gcpolicy.transformerclass(translator)
         self.completed = False
 
+        self.instrument_ncounter = 0
+
     def gettypedefnode(self, T, varlength=1):
         if varlength <= 1:
             varlength = 1   # it's C after all

Modified: pypy/branch/mininal-c-backend/pypy/translator/c/exceptiontransform.py
==============================================================================
--- pypy/branch/mininal-c-backend/pypy/translator/c/exceptiontransform.py	(original)
+++ pypy/branch/mininal-c-backend/pypy/translator/c/exceptiontransform.py	Thu Nov 23 12:03:10 2006
@@ -56,7 +56,6 @@
         
         def rpyexc_occured():
             exc_type = exc_data.exc_type
-            lloperation.llop.debug_log_exc(lltype.Void, exc_type)
             return exc_type is not null_type
 
         # XXX tmp HACK for genllvm
@@ -64,7 +63,6 @@
         # calling rpyexc_occured() from c code with lltype.Bool
         def _rpyexc_occured():
             exc_type = exc_data.exc_type
-            lloperation.llop.debug_log_exc(lltype.Void, exc_type)
             return exc_type is not null_type
 
         def rpyexc_fetch_type():
@@ -87,7 +85,8 @@
             rpyexc_occured, [], l2a(lltype.Bool))
         self.rpyexc_occured_ptr = Constant(lltype.functionptr(
             RPYEXC_OCCURED_TYPE, "RPyExceptionOccurred",
-            graph=rpyexc_occured_graph),
+            graph=rpyexc_occured_graph,
+            exception_policy="exc_helper"),
             lltype.Ptr(RPYEXC_OCCURED_TYPE))
 
         # XXX tmp HACK for genllvm
@@ -96,7 +95,8 @@
             _rpyexc_occured, [], l2a(lltype.Signed))
         self._rpyexc_occured_ptr = Constant(lltype.functionptr(
             _RPYEXC_OCCURED_TYPE, "_RPyExceptionOccurred",
-            graph=_rpyexc_occured_graph),
+            graph=_rpyexc_occured_graph,
+            exception_policy="exc_helper"),
             lltype.Ptr(_RPYEXC_OCCURED_TYPE))
         
         RPYEXC_FETCH_TYPE_TYPE = lltype.FuncType([], self.lltype_of_exception_type)
@@ -105,7 +105,8 @@
             l2a(self.lltype_of_exception_type))
         self.rpyexc_fetch_type_ptr = Constant(lltype.functionptr(
             RPYEXC_FETCH_TYPE_TYPE, "RPyFetchExceptionType",
-            graph=rpyexc_fetch_type_graph),
+            graph=rpyexc_fetch_type_graph,
+            exception_policy="exc_helper"),
             lltype.Ptr(RPYEXC_FETCH_TYPE_TYPE))
         
         RPYEXC_FETCH_VALUE_TYPE = lltype.FuncType([], self.lltype_of_exception_value)
@@ -114,7 +115,8 @@
             l2a(self.lltype_of_exception_value))
         self.rpyexc_fetch_value_ptr = Constant(lltype.functionptr(
             RPYEXC_FETCH_VALUE_TYPE, "RPyFetchExceptionValue",
-            graph=rpyexc_fetch_value_graph),
+            graph=rpyexc_fetch_value_graph,
+            exception_policy="exc_helper"),
             lltype.Ptr(RPYEXC_FETCH_VALUE_TYPE))
 
         RPYEXC_CLEAR = lltype.FuncType([], lltype.Void)
@@ -122,7 +124,8 @@
             rpyexc_clear, [], l2a(lltype.Void))
         self.rpyexc_clear_ptr = Constant(lltype.functionptr(
             RPYEXC_CLEAR, "RPyClearException",
-            graph=rpyexc_clear_graph),
+            graph=rpyexc_clear_graph,
+            exception_policy="exc_helper"),
             lltype.Ptr(RPYEXC_CLEAR))
 
         RPYEXC_RAISE = lltype.FuncType([self.lltype_of_exception_type,
@@ -134,7 +137,8 @@
             l2a(lltype.Void))
         self.rpyexc_raise_ptr = Constant(lltype.functionptr(
             RPYEXC_RAISE, "RPyRaiseException",
-            graph=rpyexc_raise_graph),
+            graph=rpyexc_raise_graph,
+            exception_policy="exc_helper"),
             lltype.Ptr(RPYEXC_RAISE))
 
         mixlevelannotator.finish()
@@ -321,7 +325,6 @@
                                           lltype.Bool)            
         else:
             v_exc_type = self.ExcData_repr.getfield(self.cexcdata, 'exc_type', llops)
-            llops.genop('debug_log_exc', [v_exc_type], lltype.Void)
             var_exc_occured = llops.genop('ptr_nonzero', [v_exc_type],
                                           lltype.Bool)
 

Modified: pypy/branch/mininal-c-backend/pypy/translator/c/extfunc.py
==============================================================================
--- pypy/branch/mininal-c-backend/pypy/translator/c/extfunc.py	(original)
+++ pypy/branch/mininal-c-backend/pypy/translator/c/extfunc.py	Thu Nov 23 12:03:10 2006
@@ -208,7 +208,7 @@
         yield ('RPYTHON_PYEXCCLASS2EXC', exceptiondata.fn_pyexcclass2exc)
 
     yield ('_RPyExceptionOccurred',    exctransformer._rpyexc_occured_ptr.value)
-    yield ('RPyExceptionOccurred',     exctransformer.rpyexc_occured_ptr.value)
+    yield ('RPyExceptionOccurred1',    exctransformer.rpyexc_occured_ptr.value)
     yield ('RPyFetchExceptionType',    exctransformer.rpyexc_fetch_type_ptr.value)
     yield ('RPyFetchExceptionValue',   exctransformer.rpyexc_fetch_value_ptr.value)
     yield ('RPyClearException',        exctransformer.rpyexc_clear_ptr.value)

Modified: pypy/branch/mininal-c-backend/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/branch/mininal-c-backend/pypy/translator/c/funcgen.py	(original)
+++ pypy/branch/mininal-c-backend/pypy/translator/c/funcgen.py	Thu Nov 23 12:03:10 2006
@@ -27,7 +27,7 @@
 
     if USESLOTS:
         __slots__ = """graph db gcpolicy
-                       cpython_exc
+                       exception_policy
                        more_ll_values
                        vars
                        lltypes
@@ -36,11 +36,11 @@
                        blocknum
                        oldgraph""".split()
 
-    def __init__(self, graph, db, cpython_exc=False, functionname=None):
+    def __init__(self, graph, db, exception_policy=None, functionname=None):
         self.graph = graph
         self.db = db
         self.gcpolicy = db.gcpolicy
-        self.cpython_exc = cpython_exc
+        self.exception_policy = exception_policy
         self.functionname = functionname
         # apply the stackless transformation
         if db.stacklesstransformer:
@@ -85,7 +85,7 @@
                     self.more_ll_values.append(link.llexitcase)
                 elif link.exitcase is not None:
                     mix.append(Constant(link.exitcase))
-        if self.cpython_exc:
+        if self.exception_policy == "CPython":
             v, exc_cleanup_ops = self.graph.exc_cleanup
             mix.append(v)
             for cleanupop in exc_cleanup_ops:
@@ -179,7 +179,7 @@
         return self.db.get(ErrorValue(returnlltype))
 
     def return_with_error(self):
-        if self.cpython_exc:
+        if self.exception_policy == "CPython":
             assert self.lltypemap(self.graph.getreturnvar()) == PyObjPtr
             v, exc_cleanup_ops = self.graph.exc_cleanup
             vanishing_exc_value = self.expr(v)
@@ -226,13 +226,15 @@
             if len(block.exits) == 0:
                 assert len(block.inputargs) == 1
                 # regular return block
-                if self.cpython_exc:
+                if self.exception_policy == "CPython":
                     assert self.lltypemap(self.graph.getreturnvar()) == PyObjPtr
                     yield 'if (RPyExceptionOccurred()) {'
                     yield '\tRPyConvertExceptionToCPython();'
                     yield '\treturn NULL;'
                     yield '}'
                 retval = self.expr(block.inputargs[0])
+                if self.exception_policy != "exc_helper":
+                    yield 'RPY_DEBUG_RETURN();'
                 yield 'return %s;' % retval
                 continue
             elif block.exitswitch is None:
@@ -717,12 +719,9 @@
             c_string_constant(' '.join(format) + '\n\000'),
             ''.join([', ' + s for s in argv]))
 
-    def OP_DEBUG_LOG_EXC(self, op):
-        exc_type = self.expr(op.args[0])
-        return 'RPY_LOG_EXC(%s);' % exc_type
-
     def OP_DEBUG_ASSERT(self, op):
-        return '/* debug_assert removed */'
+        return 'RPyAssert(%s, %s);' % (self.expr(op.args[0]),
+                                       c_string_constant(op.args[1].value))
 
     def OP_DEBUG_FATALERROR(self, op):
         # XXX
@@ -736,6 +735,13 @@
             msg = 'RPyString_AsString(%s)' % self.expr(msg)
 
         return 'fprintf(stderr, "%%s\\n", %s); abort();' % msg
+
+    def OP_INSTRUMENT_COUNT(self, op):
+        counter_label = op.args[1].value
+        self.db.instrument_ncounter = max(self.db.instrument_ncounter,
+                                          counter_label+1)
+        counter_label = self.expr(op.args[1])
+        return 'INSTRUMENT_COUNT(%s);' % counter_label
             
 
 assert not USESLOTS or '__dict__' not in dir(FunctionCodeGenerator)

Modified: pypy/branch/mininal-c-backend/pypy/translator/c/genc.py
==============================================================================
--- pypy/branch/mininal-c-backend/pypy/translator/c/genc.py	(original)
+++ pypy/branch/mininal-c-backend/pypy/translator/c/genc.py	Thu Nov 23 12:03:10 2006
@@ -5,7 +5,7 @@
 from pypy.translator.c.extfunc import pre_include_code_lines
 from pypy.translator.gensupp import uniquemodulename, NameManager
 from pypy.translator.tool.cbuild import compile_c_module
-from pypy.translator.tool.cbuild import build_executable, CCompiler
+from pypy.translator.tool.cbuild import build_executable, CCompiler, ProfOpt
 from pypy.translator.tool.cbuild import import_module_from_directory
 from pypy.translator.tool.cbuild import check_under_under_thread
 from pypy.rpython.lltypesystem import lltype
@@ -132,6 +132,7 @@
         if CBuilder.have___thread is None:
             CBuilder.have___thread = check_under_under_thread()
         if not self.standalone:
+            assert not self.config.translation.instrument
             from pypy.translator.c.symboltable import SymbolTable
             # XXX fix symboltable
             #self.symboltable = SymbolTable()
@@ -140,6 +141,8 @@
                                       exports = self.exports,
                                       symboltable = self.symboltable)
         else:
+            if self.config.translation.instrument:
+                defines['INSTRUMENT'] = 1
             if CBuilder.have___thread:
                 if not self.config.translation.no__thread:
                     defines['USE___THREAD'] = 1
@@ -224,12 +227,19 @@
         from distutils import sysconfig
         python_inc = sysconfig.get_python_inc()
         cc = self.config.translation.cc
-        profopt = self.config.translation.profopt
+        profbased = None
+        if self.config.translation.instrumentctl is not None:
+            profbased = self.config.translation.instrumentctl
+        else:
+            profopt = self.config.translation.profopt
+            if profopt is not None:
+                profbased = (ProfOpt, profopt)
+
         return CCompiler(
             [self.c_source_filename] + self.extrafiles,
             include_dirs = [autopath.this_dir, python_inc] + extra_includes,
             libraries    = self.libraries,
-            compiler_exe = cc, profopt = profopt)
+            compiler_exe = cc, profbased = profbased)
 
     def compile(self):
         assert self.c_source_filename
@@ -641,6 +651,13 @@
     gen_startupcode(f, database)
 
     f.close()
+
+    if 'INSTRUMENT' in defines:
+        fi = incfilename.open('a')
+        n = database.instrument_ncounter
+        print >>fi, "#define INSTRUMENT_NCOUNTER %d" % n
+        fi.close()
+    
     return filename, sg.getextrafiles()
 
 
@@ -842,10 +859,13 @@
 \trm -f $(OBJECTS) $(TARGET)
 
 debug:
-\tmake CFLAGS="-g"
+\tmake CFLAGS="-g -DRPY_ASSERT"
 
 debug_exc:
-\tmake CFLAGS="-g -DDO_LOG_EXC"
+\tmake CFLAGS="-g -DRPY_ASSERT -DDO_LOG_EXC"
+
+debug_mem:
+\tmake CFLAGS="-g -DRPY_ASSERT -DNO_OBMALLOC"
 
 profile:
 \tmake CFLAGS="-pg $(CFLAGS)" LDFLAGS="-pg $(LDFLAGS)"

Modified: pypy/branch/mininal-c-backend/pypy/translator/c/node.py
==============================================================================
--- pypy/branch/mininal-c-backend/pypy/translator/c/node.py	(original)
+++ pypy/branch/mininal-c-backend/pypy/translator/c/node.py	Thu Nov 23 12:03:10 2006
@@ -698,8 +698,9 @@
         raise ValueError, "trying to compile suggested primitive %r" % (
             fnobj._callable,)
     elif hasattr(fnobj, 'graph'):
-        cpython_exc = getattr(fnobj, 'exception_policy', None) == "CPython"
-        return [FunctionCodeGenerator(fnobj.graph, db, cpython_exc, functionname)]
+        exception_policy = getattr(fnobj, 'exception_policy', None)
+        return [FunctionCodeGenerator(fnobj.graph, db, exception_policy,
+                                      functionname)]
     elif getattr(fnobj, 'external', None) == 'C':
         # deprecated case
         if hasattr(fnobj, 'includes'):

Modified: pypy/branch/mininal-c-backend/pypy/translator/c/src/exception.h
==============================================================================
--- pypy/branch/mininal-c-backend/pypy/translator/c/src/exception.h	(original)
+++ pypy/branch/mininal-c-backend/pypy/translator/c/src/exception.h	Thu Nov 23 12:03:10 2006
@@ -6,7 +6,9 @@
    PyObject *RPythonError;
 #endif 
 
-#define RPY_LOG_EXC(exc_type)
+/* just a renaming, unless DO_LOG_EXC is set */
+#define RPyExceptionOccurred RPyExceptionOccurred1
+#define RPY_DEBUG_RETURN()   /* nothing */
 
 #ifndef PyExceptionClass_Check    /* Python < 2.5 */
 # define PyExceptionClass_Check(x)	PyClass_Check(x)
@@ -21,13 +23,27 @@
 /******************************************************************/
 
 #ifdef DO_LOG_EXC
-#undef RPY_LOG_EXC
-#define RPY_LOG_EXC(exc_type)  if(exc_type) { \
-	fprintf(stderr, "propagating %s:%ld %s %s\n", \
-		__FILE__, __LINE__, __FUNCTION__, \
-		exc_type->ov_name->items); \
+#undef RPyExceptionOccurred
+#undef RPY_DEBUG_RETURN
+#define RPyExceptionOccurred()  RPyDebugException("  noticing a")
+#define RPY_DEBUG_RETURN()      RPyDebugException("leaving with")
+#define RPyDebugException(msg)  (                                       \
+  RPyExceptionOccurred1()                                               \
+    ? (RPyDebugReturnShowException(msg, __FILE__, __LINE__, __FUNCTION__), 1) \
+    : 0                                                                 \
+  )
+void RPyDebugReturnShowException(const char *msg, const char *filename,
+                                 long lineno, const char *functionname);
+#ifndef PYPY_NOT_MAIN_FILE
+void RPyDebugReturnShowException(const char *msg, const char *filename,
+                                 long lineno, const char *functionname)
+{
+  fprintf(stderr, "%s %s: %s:%ld %s\n", msg,
+          RPyFetchExceptionType()->ov_name->items,
+          filename, lineno, functionname);
 }
 #endif
+#endif  /* DO_LOG_EXC */
 
 /* Hint: functions and macros not defined here, like RPyRaiseException,
    come from exctransformer via the table in extfunc.py. */
@@ -109,7 +125,7 @@
 #else    /* non-RPython version of exceptions, using CPython only */
 /******************************************************************/
 
-#define RPyExceptionOccurred()           PyErr_Occurred()
+#define RPyExceptionOccurred1()          PyErr_Occurred()
 #define RPyRaiseException(etype, evalue) PyErr_Restore(etype, evalue, NULL)
 #define RPyFetchException(etypevar, evaluevar, ignored)  do {	\
 		PyObject *__tb;					\

Modified: pypy/branch/mininal-c-backend/pypy/translator/c/src/g_include.h
==============================================================================
--- pypy/branch/mininal-c-backend/pypy/translator/c/src/g_include.h	(original)
+++ pypy/branch/mininal-c-backend/pypy/translator/c/src/g_include.h	Thu Nov 23 12:03:10 2006
@@ -30,6 +30,8 @@
 #include "src/float.h"
 #include "src/address.h"
 
+#include "src/instrument.h"
+
 /* optional assembler bits */
 #if defined(__GNUC__) && defined(__i386__)
 #  include "src/asm_gcc_x86.h"

Modified: pypy/branch/mininal-c-backend/pypy/translator/c/src/main.h
==============================================================================
--- pypy/branch/mininal-c-backend/pypy/translator/c/src/main.h	(original)
+++ pypy/branch/mininal-c-backend/pypy/translator/c/src/main.h	Thu Nov 23 12:03:10 2006
@@ -20,6 +20,9 @@
     char *errmsg;
     int i, exitcode;
     RPyListOfString *list;
+
+    instrument_setup();
+
     errmsg = RPython_StartupCode();
     if (errmsg) goto error;
 

Modified: pypy/branch/mininal-c-backend/pypy/translator/c/src/obmalloc.c
==============================================================================
--- pypy/branch/mininal-c-backend/pypy/translator/c/src/obmalloc.c	(original)
+++ pypy/branch/mininal-c-backend/pypy/translator/c/src/obmalloc.c	Thu Nov 23 12:03:10 2006
@@ -430,7 +430,7 @@
 	if (bp == NULL)
 		return NULL;
 
-#ifdef PYMALLOC_DEBUG
+#if 0   /* XXX removed for PyPy - #ifdef PYMALLOC_DEBUG */
 	if (Py_GETENV("PYTHONMALLOCSTATS"))
 		_PyObject_DebugMallocStats();
 #endif
@@ -894,6 +894,16 @@
  * it wraps a real allocator, adding extra debugging info to the memory blocks.
  */
 
+/* XXX added for PyPy for stand-alone usage */
+void Py_FatalError(const char *msg)
+{
+  fprintf(stderr, "Py_FatalError() called in obmalloc!\n%s\n", msg);
+  exit(1);
+}
+#define PyOS_snprintf snprintf
+/* end of XXX */
+
+
 /* Special bytes broadcast into debug memory blocks at appropriate times.
  * Strings of these are unlikely to be valid addresses, floats, ints or
  * 7-bit ASCII.

Modified: pypy/branch/mininal-c-backend/pypy/translator/c/src/standalone.h
==============================================================================
--- pypy/branch/mininal-c-backend/pypy/translator/c/src/standalone.h	(original)
+++ pypy/branch/mininal-c-backend/pypy/translator/c/src/standalone.h	Thu Nov 23 12:03:10 2006
@@ -5,8 +5,16 @@
 #include <math.h>
 
 #ifndef PYPY_NOT_MAIN_FILE
-#ifndef WITH_PYMALLOC
-#define WITH_PYMALLOC
+
+#ifdef NO_OBMALLOC
+void *PyObject_Malloc(size_t n) { return malloc(n); }
+void *PyObject_Realloc(void *p, size_t n) { return realloc(p, n); }
+void PyObject_Free(void *p) { if (p) { *((int*)p) = 0xDDDDDDDD; } free(p); }
+#else
+#  ifndef WITH_PYMALLOC
+#    define WITH_PYMALLOC
+#  endif
+#  include "obmalloc.c"
 #endif
-#include "obmalloc.c"
+
 #endif

Modified: pypy/branch/mininal-c-backend/pypy/translator/c/src/support.h
==============================================================================
--- pypy/branch/mininal-c-backend/pypy/translator/c/src/support.h	(original)
+++ pypy/branch/mininal-c-backend/pypy/translator/c/src/support.h	Thu Nov 23 12:03:10 2006
@@ -25,6 +25,26 @@
 		memcpy(itemsarray->items, PyString_AS_STRING(s),        \
                        itemsarray->length)
 
+#ifdef RPY_ASSERT
+#  define RPyAssert(x, msg)                                             \
+     if (!(x)) RPyAssertFailed(__FILE__, __LINE__, __FUNCTION__, msg)
+
+void RPyAssertFailed(const char* filename, long lineno,
+                     const char* function, const char *msg);
+#  ifndef PYPY_NOT_MAIN_FILE
+void RPyAssertFailed(const char* filename, long lineno,
+                     const char* function, const char *msg) {
+  fprintf(stderr,
+          "PyPy assertion failed at %s:%d:\n"
+          "in %s: %s\n",
+          filename, lineno, function, msg);
+  abort();
+}
+#  endif
+#else
+#  define RPyAssert(x, msg)   /* nothing */
+#endif
+
 #ifdef __RPyListOfString_New     /*  :-(  */
 #  define HAVE_RPY_LIST_OF_STRING
 #endif

Modified: pypy/branch/mininal-c-backend/pypy/translator/c/test/test_standalone.py
==============================================================================
--- pypy/branch/mininal-c-backend/pypy/translator/c/test/test_standalone.py	(original)
+++ pypy/branch/mininal-c-backend/pypy/translator/c/test/test_standalone.py	Thu Nov 23 12:03:10 2006
@@ -1,7 +1,10 @@
+import py
+import sys, os
+
 from pypy.translator.translator import TranslationContext
 from pypy.translator.c.genc import CStandaloneBuilder
 from pypy.annotation.listdef import s_list_of_strings
-import os
+from pypy.tool.udir import udir
 
 
 def test_hello_world():
@@ -47,3 +50,61 @@
                            '''argument lengths: [2, 5]\n''')
     # NB. RPython has only str, not repr, so str() on a list of strings
     # gives the strings unquoted in the list
+
+def test_counters():
+    if sys.platform == 'win32':
+        py.test.skip("instrument counters support is unix only for now")
+    from pypy.rpython.lltypesystem import lltype
+    from pypy.rpython.lltypesystem.lloperation import llop
+    def entry_point(argv):
+        llop.instrument_count(lltype.Void, 'test', 2)
+        llop.instrument_count(lltype.Void, 'test', 1)
+        llop.instrument_count(lltype.Void, 'test', 1)
+        llop.instrument_count(lltype.Void, 'test', 2)
+        llop.instrument_count(lltype.Void, 'test', 1)        
+        return 0
+    t = TranslationContext()
+    t.config.translation.instrument = True
+    t.buildannotator().build_types(entry_point, [s_list_of_strings])
+    t.buildrtyper().specialize()
+
+    cbuilder = CStandaloneBuilder(t, entry_point, config=t.config) # xxx
+    cbuilder.generate_source()
+    cbuilder.compile()
+
+    counters_fname = udir.join("_counters_")
+    os.putenv('_INSTRUMENT_COUNTERS', str(counters_fname))
+    try:
+        data = cbuilder.cmdexec()
+    finally:
+        os.unsetenv('_INSTRUMENT_COUNTERS')
+
+    f = counters_fname.open('rb')
+    counters_data = f.read()
+    f.close()
+
+    import struct
+    counters = struct.unpack("LLL", counters_data)
+
+    assert counters == (0,3,2)
+
+def test_prof_inline():
+    if sys.platform == 'win32':
+        py.test.skip("instrumentation support is unix only for now")
+    def add(a,b):
+        return a + b - b + b - b + b - b + b - b + b - b + b - b + b
+    def entry_point(argv):
+        tot =  0
+        x = int(argv[1])
+        while x > 0:
+            tot = add(tot, x)
+            x -= 1
+        os.write(1, str(tot))
+        return 0
+    from pypy.translator.interactive import Translation
+    t = Translation(entry_point, backend='c', standalone=True)
+    t.backendopt(profile_based_inline="500")
+    exe = t.compile()
+    out = py.process.cmdexec("%s 500" % exe)
+    assert int(out) == 500*501/2
+    

Modified: pypy/branch/mininal-c-backend/pypy/translator/driver.py
==============================================================================
--- pypy/branch/mininal-c-backend/pypy/translator/driver.py	(original)
+++ pypy/branch/mininal-c-backend/pypy/translator/driver.py	Thu Nov 23 12:03:10 2006
@@ -51,6 +51,31 @@
 def backend_to_typesystem(backend):
     return _BACKEND_TO_TYPESYSTEM.get(backend, 'ootype')
 
+
+class Instrument(Exception):
+    pass
+
+
+class ProfInstrument(object):
+    name = "profinstrument"
+    def __init__(self, datafile, compiler):
+        self.datafile = datafile
+        self.compiler = compiler
+
+    def first(self):
+        self.compiler._build()
+
+    def probe(self, exe, args):
+        from py.compat import subprocess
+        env = os.environ.copy()
+        env['_INSTRUMENT_COUNTERS'] = str(self.datafile)
+        subprocess.call([exe, args], env=env)
+        
+    def after(self):
+        # xxx
+        os._exit(0)
+
+
 class TranslationDriver(SimpleTaskEngine):
 
     def __init__(self, setopts=None, default_goal=None, disable=[],
@@ -183,6 +208,40 @@
         self.entry_point = entry_point
         self.translator = translator
 
+        self.translator.driver_instrument_result = self.instrument_result
+
+    def instrument_result(self, args):
+        backend, ts = self.get_backend_and_type_system()
+        if backend != 'c' or sys.platform == 'win32':
+            raise Exception("instrumentation requires the c backend"
+                            " and unix for now")
+        from pypy.tool.udir import udir
+        
+        datafile = udir.join('_instrument_counters')
+        makeProfInstrument = lambda compiler: ProfInstrument(datafile, compiler)
+
+        pid = os.fork()
+        if pid == 0:
+            # child compiling and running with instrumentation
+            self.config.translation.instrument = True
+            self.config.translation.instrumentctl = (makeProfInstrument,
+                                                     args)
+            raise Instrument
+        else:
+            pid, status = os.waitpid(pid, 0)
+            if os.WIFEXITED(status):
+                status = os.WEXITSTATUS(status)
+                if status != 0:
+                    raise Exception, "instrumentation child failed: %d" % status
+            else:
+                raise Exception, "instrumentation child aborted"
+            import array, struct
+            n = datafile.size()//struct.calcsize('L')
+            datafile = datafile.open('rb')
+            counters = array.array('L')
+            counters.fromfile(datafile, n)
+            datafile.close()
+            return counters
 
     def info(self, msg):
         log.info(msg)
@@ -194,9 +253,16 @@
             return
         else:
             self.log.info("%s..." % title)
-        res = func()
+        instrument = False
+        try:
+            res = func()
+        except Instrument:
+            instrument = True
         if not func.task_idempotent:
             self.done[goal] = True
+        if instrument:
+            self.proceed('compile')
+            assert False, 'we should not get here'
         return res
 
     def task_annotate(self):



More information about the Pypy-commit mailing list