Author: Armin Rigo <ar...@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 _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit