[pypy-commit] pypy default: Move the _flush_codes logic to C

arigo noreply at buildbot.pypy.org
Tue Aug 18 19:30:46 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r79045:a5241c131e2a
Date: 2015-08-18 19:30 +0200
http://bitbucket.org/pypy/pypy/changeset/a5241c131e2a/

Log:	Move the _flush_codes logic to C

diff --git a/rpython/rlib/rvmprof/cintf.py b/rpython/rlib/rvmprof/cintf.py
--- a/rpython/rlib/rvmprof/cintf.py
+++ b/rpython/rlib/rvmprof/cintf.py
@@ -49,9 +49,10 @@
     vmprof_disable = rffi.llexternal("vmprof_disable", [], rffi.INT,
                                      compilation_info=eci,
                                      save_err=rffi.RFFI_SAVE_ERRNO)
-    vmprof_write_buf = rffi.llexternal("vmprof_write_buf",
-                                       [rffi.CCHARP, rffi.LONG],
-                                       lltype.Void, compilation_info=eci)
+    vmprof_register_virtual_function = rffi.llexternal(
+                                           "vmprof_register_virtual_function",
+                                           [rffi.CCHARP, rffi.LONG, rffi.INT],
+                                           rffi.INT, compilation_info=eci)
     vmprof_ignore_signals = rffi.llexternal("vmprof_ignore_signals",
                                             [rffi.INT], lltype.Void,
                                             compilation_info=eci)
diff --git a/rpython/rlib/rvmprof/rvmprof.py b/rpython/rlib/rvmprof/rvmprof.py
--- a/rpython/rlib/rvmprof/rvmprof.py
+++ b/rpython/rlib/rvmprof/rvmprof.py
@@ -1,14 +1,12 @@
 import sys, os
 from rpython.rlib.objectmodel import specialize, we_are_translated
-from rpython.rlib.rstring import StringBuilder
 from rpython.rlib import jit, rgc, rposix
 from rpython.rlib.rvmprof import cintf
 from rpython.rtyper.annlowlevel import cast_instance_to_gcref
 from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance
 from rpython.rtyper.lltypesystem import rffi
 
-MAX_CODES = 8000 - 255
-MAX_FUNC_NAME = 255
+MAX_FUNC_NAME = 1023
 
 # ____________________________________________________________
 
@@ -34,8 +32,6 @@
 
     def _cleanup_(self):
         self.is_enabled = False
-        self.fileno = -1
-        self._current_codes = None
 
     @specialize.argtype(1)
     def register_code(self, code, full_name_func):
@@ -107,7 +103,6 @@
         if p_error:
             raise VMProfError(rffi.charp2str(p_error))
 
-        self.fileno = fileno
         self._gather_all_code_objs()
         res = self.cintf.vmprof_enable()
         if res < 0:
@@ -121,9 +116,6 @@
         if not self.is_enabled:
             raise VMProfError("vmprof is not enabled")
         self.is_enabled = False
-        if self._current_codes is not None:
-            self._flush_codes()
-        self.fileno = -1
         res = self.cintf.vmprof_disable()
         if res < 0:
             raise VMProfError(os.strerror(rposix.get_saved_errno()))
@@ -132,35 +124,8 @@
         assert name.count(':') == 3 and len(name) <= MAX_FUNC_NAME, (
             "the name must be 'class:func_name:func_line:filename' "
             "and at most %d characters; got '%s'" % (MAX_FUNC_NAME, name))
-        b = self._current_codes
-        if b is None:
-            b = self._current_codes = StringBuilder()
-        b.append('\x02')
-        _write_long_to_string_builder(uid, b)
-        _write_long_to_string_builder(len(name), b)
-        b.append(name)
-        if b.getlength() >= MAX_CODES:
-            self._flush_codes()
-
-    def _flush_codes(self):
-        buf = self._current_codes.build()
-        self._current_codes = None
-        self.cintf.vmprof_write_buf(buf, len(buf))
-        # NOTE: keep in mind that vmprof_write_buf() can only write
-        # a maximum of 8184 bytes.  This should be guaranteed here because:
-        assert MAX_CODES + 17 + MAX_FUNC_NAME <= 8184
-
-
-def _write_long_to_string_builder(l, b):
-    b.append(chr(l & 0xff))
-    b.append(chr((l >> 8) & 0xff))
-    b.append(chr((l >> 16) & 0xff))
-    b.append(chr((l >> 24) & 0xff))
-    if sys.maxint > 2147483647:
-        b.append(chr((l >> 32) & 0xff))
-        b.append(chr((l >> 40) & 0xff))
-        b.append(chr((l >> 48) & 0xff))
-        b.append(chr((l >> 56) & 0xff))
+        if self.cintf.vmprof_register_virtual_function(name, uid, 500000) < 0:
+            raise VMProfError("vmprof buffers full!  disk full or too slow")
 
 
 def vmprof_execute_code(name, get_code_fn, result_class=None):
diff --git a/rpython/rlib/rvmprof/src/rvmprof.h b/rpython/rlib/rvmprof/src/rvmprof.h
--- a/rpython/rlib/rvmprof/src/rvmprof.h
+++ b/rpython/rlib/rvmprof/src/rvmprof.h
@@ -1,6 +1,6 @@
 
-RPY_EXTERN char *vmprof_init(int, double, const char *);
+RPY_EXTERN char *vmprof_init(int, double, char *);
 RPY_EXTERN void vmprof_ignore_signals(int);
 RPY_EXTERN int vmprof_enable(void);
 RPY_EXTERN int vmprof_disable(void);
-RPY_EXTERN void vmprof_write_buf(char *, long);
+RPY_EXTERN int vmprof_register_virtual_function(char *, long, int);
diff --git a/rpython/rlib/rvmprof/src/vmprof_main.h b/rpython/rlib/rvmprof/src/vmprof_main.h
--- a/rpython/rlib/rvmprof/src/vmprof_main.h
+++ b/rpython/rlib/rvmprof/src/vmprof_main.h
@@ -45,11 +45,13 @@
 
 static int profile_file = -1;
 static long prepare_interval_usec;
+static struct profbuf_s *volatile current_codes;
 
-static int opened_profile(const char *interp_name);
+static int opened_profile(char *interp_name);
+static void flush_codes(void);
 
 RPY_EXTERN
-char *vmprof_init(int fd, double interval, const char *interp_name)
+char *vmprof_init(int fd, double interval, char *interp_name)
 {
     if (interval < 1e-6 || interval >= 1.0)
         return "bad value for 'interval'";
@@ -404,15 +406,15 @@
     return 0;
 }
 
-static int opened_profile(const char *interp_name)
+static int opened_profile(char *interp_name)
 {
     struct {
         long hdr[5];
         char interp_name[259];
     } header;
 
-    size_t namelen = strlen(interp_name);
-    assert(namelen <= 255);
+    size_t namelen = strnlen(interp_name, 255);
+    current_codes = NULL;
 
     header.hdr[0] = 0;
     header.hdr[1] = 3;
@@ -480,26 +482,76 @@
         return -1;
     if (remove_sigprof_handler() == -1)
         return -1;
+    flush_codes();
     if (shutdown_concurrent_bufs(profile_file) < 0)
         return -1;
     return close_profile();
 }
 
 RPY_EXTERN
-void vmprof_write_buf(char *buf, long size)
+int vmprof_register_virtual_function(char *code_name, long code_uid,
+                                     int auto_retry)
 {
+    long namelen = strnlen(code_name, 1023);
+    long blocklen = 1 + 2 * sizeof(long) + namelen;
     struct profbuf_s *p;
+    char *t;
 
-    while ((p = reserve_buffer(profile_file)) == NULL) {
-        /* spin loop waiting for a buffer to be ready; should almost never
-           be the case */
-        usleep(1);
+ retry:
+    p = current_codes;
+    if (p != NULL) {
+        if (__sync_bool_compare_and_swap(&current_codes, p, NULL)) {
+            /* grabbed 'current_codes': we will append the current block
+               to it if it contains enough room */
+            size_t freesize = SINGLE_BUF_SIZE - p->data_size;
+            if (freesize < blocklen) {
+                /* full: flush it */
+                commit_buffer(profile_file, p);
+                p = NULL;
+            }
+        }
+        else {
+            /* compare-and-swap failed, don't try again */
+            p = NULL;
+        }
     }
 
-    if (size > SINGLE_BUF_SIZE)
-        size = SINGLE_BUF_SIZE;
-    memcpy(p->data, buf, size);
-    p->data_size = size;
+    if (p == NULL) {
+        p = reserve_buffer(profile_file);
+        if (p == NULL) {
+            /* can't get a free block; should almost never be the
+               case.  Spin loop if allowed, or return a failure code
+               if not (e.g. we're in a signal handler) */
+            if (auto_retry > 0) {
+                auto_retry--;
+                usleep(1);
+                goto retry;
+            }
+            return -1;
+        }
+    }
 
-    commit_buffer(profile_file, p);
+    t = p->data + p->data_size;
+    p->data_size += blocklen;
+    assert(p->data_size <= SINGLE_BUF_SIZE);
+    *t++ = MARKER_VIRTUAL_IP;
+    memcpy(t, &code_uid, sizeof(long)); t += sizeof(long);
+    memcpy(t, &namelen, sizeof(long)); t += sizeof(long);
+    memcpy(t, code_name, namelen);
+
+    /* try to reattach 'p' to 'current_codes' */
+    if (!__sync_bool_compare_and_swap(&current_codes, NULL, p)) {
+        /* failed, flush it */
+        commit_buffer(profile_file, p);
+    }
+    return 0;
 }
+
+static void flush_codes(void)
+{
+    struct profbuf_s *p = current_codes;
+    if (p != NULL) {
+        current_codes = NULL;
+        commit_buffer(profile_file, p);
+    }
+}
diff --git a/rpython/rlib/rvmprof/src/vmprof_mt.h b/rpython/rlib/rvmprof/src/vmprof_mt.h
--- a/rpython/rlib/rvmprof/src/vmprof_mt.h
+++ b/rpython/rlib/rvmprof/src/vmprof_mt.h
@@ -190,6 +190,13 @@
     }
 }
 
+static void cancel_buffer(struct profbuf_s *buf)
+{
+    long i = buf - profbuf_all_buffers;
+    assert(profbuf_state[i] == PROFBUF_FILLING);
+    profbuf_state[i] = PROFBUF_UNUSED;
+}
+
 static int shutdown_concurrent_bufs(int fd)
 {
     /* no signal handler can be running concurrently here, because we


More information about the pypy-commit mailing list