-
-
Notifications
You must be signed in to change notification settings - Fork 30.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gh-103092: Add a mutex to make the random state of rotatingtree concurrent-safe #115301
Conversation
Codesimport sys
import threading
import _xxsubinterpreters
import cProfile
code = """
def f():
import re
import json
import pickle
d = {str(x): {x: x} for x in range(1000)}
for _ in range(100):
re.compile("foo|bar")
json.loads(json.dumps(d))
pickle.loads(pickle.dumps(d))
"""
def run_single():
ctx = {}
exec(code, ctx)
cProfile.runctx("f()", ctx, {})
def run_multi():
ts = []
interps = []
for _ in range(4):
interp = _xxsubinterpreters.create(isolated=1)
interps.append(interp)
c = code + "import cProfile; cProfile.run('f()')"
t = threading.Thread(target=_xxsubinterpreters.run_string, args=[int(interp), c])
t.start()
ts.append(t)
for t in ts:
t.join()
for interp in interps:
_xxsubinterpreters.destroy(int(interp))
if len(sys.argv) > 1 and sys.argv[1] == 'multi':
run_multi()
else:
run_single() Single interpreter:base (b104360):
current:
Multiple interpreters:I'm using a 4 physical core Intel MacBook. As the code above shows, 4 isolated interpreters are used for this benchmark. base (b104360):With Lines 1008 to 1009 in b104360
PER_INTERPRETER_GIL_SUPPORTED .
Although this is not safe, I think it doesn't matter for this microbenchmark.
All 4 interpreter finished in the same seconds (+-0.x seconds). current:
SummaryOn my machine, the execution time of the code before and after the modification varies, sometimes better and sometimes worse. I believe that the introduced performance difference falls within the observable error range. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAICS, it should be ok to share the pseudo-random generator between interpreters. @ericsnowcurrently, thouhts?
(Needs a NEWS entry, though.) |
I'll land this sometime next week, to give @ericsnowcurrently a chance to chime in. |
I'll take a look in the next couple days. Thanks for the heads-up! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Thanks for the PR, @aisk, and thanks for the review, @ericsnowcurrently 🎉 |
The only two static variables,
random_value
andrandom_stream
, inrotatingtree.c
(which is only used by_lsprof
module) are just the state of a pseudo-random generator. They can be shared between interpreters if we add a mutex to make them concurrent-safe. And this work can be done easily, and make the_lsprofile
module isolated.Another way to isolate
_lsprof
is to store the two variables in module state. This will involve more work and review of modifications to existing functions to pass the module state. See #115130.Adding the mutex does not introduce a noticeable performance decrease. See the comment below for a micro benchmark.
@erlend-aasland