[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(¤t_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(¤t_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