Skip to content

Commit 15cf8d0

Browse files
committed
Merge pull request #838 from kmod/perf4
make `int("some_random_string")` faster
2 parents 27df1a7 + dba4dc7 commit 15cf8d0

File tree

5 files changed

+67
-48
lines changed

5 files changed

+67
-48
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ ExternalProject_Add(libunwind
173173
DEPENDS libunwind_patched
174174
UPDATE_COMMAND autoreconf -i
175175
CONFIGURE_COMMAND ${CMAKE_SOURCE_DIR}/build_deps/libunwind/configure ${LIBUNWIND_DEBUG_CFLAGS} --prefix=${CMAKE_BINARY_DIR}/build_deps/libunwind --enable-shared=0 --disable-block-signals ${LIBUNWIND_CONSERVATIVE_CHECKS} ${LIBUNWIND_DEBUG} ${LIBUNWIND_DEBUG_FRAME}
176+
BUILD_COMMAND make -j${TEST_THREADS}
176177
LOG_UPDATE ON
177178
LOG_CONFIGURE ON
178179
LOG_BUILD ON

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,9 @@ nosearch_dbgpy_% nosearch_pydbg_%: %.py ext_pythondbg
862862
$(call make_search,dbgpy_%)
863863
$(call make_search,pydbg_%)
864864

865+
pydbg: ext_pythondbg
866+
export PYTHON_VERSION=$$(python2.7-dbg -V 2>&1 | awk '{print $$2}'); PYTHONPATH=test/test_extension/build/lib.linux-x86_64-2.7-pydebug $(GDB) --ex "dir $(DEPS_DIR)/python-src/python2.7-$$PYTHON_VERSION/debian" $(GDB_CMDS) --args python2.7-dbg
867+
865868
# "kill valgrind":
866869
kv:
867870
ps aux | awk '/[v]algrind/ {print $$2}' | xargs kill -9; true

microbenchmarks/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
b.py
2+
b2.py
3+
b3.py

src/runtime/str.cpp

Lines changed: 54 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,63 +1293,68 @@ static bool _needs_escaping[256]
12931293
static char _hex[17] = "0123456789abcdef"; // really only needs to be 16 but clang will complain
12941294

12951295
extern "C" PyObject* PyString_Repr(PyObject* obj, int smartquotes) noexcept {
1296-
BoxedString* self = (BoxedString*)obj;
1297-
assert(PyString_Check(self));
1298-
1299-
std::ostringstream os("");
1300-
1301-
llvm::StringRef s(self->s());
1302-
char quote = '\'';
1303-
if (smartquotes && s.find('\'', 0) != std::string::npos && s.find('\"', 0) == std::string::npos) {
1304-
quote = '\"';
1296+
BoxedString* op = (BoxedString*)obj;
1297+
size_t newsize = 2 + 4 * Py_SIZE(op);
1298+
PyObject* v;
1299+
if (newsize > PY_SSIZE_T_MAX || newsize / 4 != Py_SIZE(op)) {
1300+
PyErr_SetString(PyExc_OverflowError, "string is too large to make repr");
1301+
return NULL;
13051302
}
1306-
os << quote;
1307-
for (int i = 0; i < s.size(); i++) {
1308-
char c = s[i];
1309-
if ((c == '\'' && quote == '\"') || !_needs_escaping[c & 0xff]) {
1310-
os << c;
1311-
} else {
1312-
char special = 0;
1313-
switch (c) {
1314-
case '\t':
1315-
special = 't';
1316-
break;
1317-
case '\n':
1318-
special = 'n';
1319-
break;
1320-
case '\r':
1321-
special = 'r';
1322-
break;
1323-
case '\'':
1324-
special = '\'';
1325-
break;
1326-
case '\"':
1327-
special = '\"';
1328-
break;
1329-
case '\\':
1330-
special = '\\';
1331-
break;
1332-
}
1333-
if (special) {
1334-
os << '\\';
1335-
os << special;
1336-
} else {
1337-
os << '\\';
1338-
os << 'x';
1339-
os << _hex[(c & 0xff) / 16];
1340-
os << _hex[(c & 0xff) % 16];
1341-
}
1303+
v = PyString_FromStringAndSize((char*)NULL, newsize);
1304+
if (v == NULL) {
1305+
return NULL;
1306+
} else {
1307+
Py_ssize_t i;
1308+
char c;
1309+
char* p;
1310+
int quote;
1311+
1312+
/* figure out which quote to use; single is preferred */
1313+
quote = '\'';
1314+
if (smartquotes && memchr(op->data(), '\'', Py_SIZE(op)) && !memchr(op->data(), '"', Py_SIZE(op)))
1315+
quote = '"';
1316+
1317+
p = PyString_AS_STRING(v);
1318+
*p++ = quote;
1319+
for (i = 0; i < Py_SIZE(op); i++) {
1320+
/* There's at least enough room for a hex escape
1321+
* and a closing quote. */
1322+
assert(newsize - (p - PyString_AS_STRING(v)) >= 5);
1323+
c = op->data()[i];
1324+
if (c == quote || c == '\\')
1325+
*p++ = '\\', *p++ = c;
1326+
else if (c == '\t')
1327+
*p++ = '\\', *p++ = 't';
1328+
else if (c == '\n')
1329+
*p++ = '\\', *p++ = 'n';
1330+
else if (c == '\r')
1331+
*p++ = '\\', *p++ = 'r';
1332+
else if (c < ' ' || c >= 0x7f) {
1333+
/* For performance, we don't want to call
1334+
* PyOS_snprintf here (extra layers of
1335+
* function call). */
1336+
sprintf(p, "\\x%02x", c & 0xff);
1337+
p += 4;
1338+
} else
1339+
*p++ = c;
13421340
}
1341+
assert(newsize - (p - PyString_AS_STRING(v)) >= 1);
1342+
*p++ = quote;
1343+
*p = '\0';
1344+
if (_PyString_Resize(&v, (p - PyString_AS_STRING(v))))
1345+
return NULL;
1346+
return v;
13431347
}
1344-
os << quote;
1345-
1346-
return boxString(os.str());
13471348
}
13481349

13491350
extern "C" Box* strRepr(BoxedString* self) {
13501351
return PyString_Repr(self, 1 /* smartquotes */);
13511352
}
13521353

1354+
extern "C" Box* str_repr(Box* self) noexcept {
1355+
return PyString_Repr(self, 1 /* smartquotes */);
1356+
}
1357+
13531358
/* Unescape a backslash-escaped string. If unicode is non-zero,
13541359
the string is a u-literal. If recode_encoding is non-zero,
13551360
the string is UTF-8 encoded and should be re-encoded in the
@@ -2882,6 +2887,7 @@ void setupStr() {
28822887
add_operators(str_cls);
28832888
str_cls->freeze();
28842889

2890+
str_cls->tp_repr = str_repr;
28852891
str_cls->tp_iter = (decltype(str_cls->tp_iter))strIter;
28862892
str_cls->tp_hash = (hashfunc)str_hash;
28872893
str_cls->tp_as_sequence->sq_length = str_length;

src/runtime/types.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,12 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
10731073
made = runtimeCallInternal<S>(new_attr, &srewrite_args, new_argspec, cls, arg2, arg3, args, keyword_names);
10741074
if (!made) {
10751075
assert(S == CAPI);
1076+
1077+
if (srewrite_args.out_success && why_rewrite_allowed == NO_INIT) {
1078+
rewrite_args->out_rtn = srewrite_args.out_rtn;
1079+
rewrite_args->out_success = true;
1080+
}
1081+
10761082
return NULL;
10771083
}
10781084

0 commit comments

Comments
 (0)