10000 Move 'use_tracing' from tstate onto C stack, for fastest possible che… · python/cpython@6458071 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6458071

Browse files
committed
Move 'use_tracing' from tstate onto C stack, for fastest possible checking in dispatch logic.
1 parent 88fc80c commit 6458071

File tree

4 files changed

+43
-23
lines changed

4 files changed

+43
-23
lines changed

Include/cpython/pystate.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ typedef int (*Py_tracefunc)(PyObject *, PyFrameObject *, int, PyObject *);
2929
#define PyTrace_OPCODE 7
3030

3131

32+
typedef struct _cframe {
33+
/* This struct will be threaded through the C stack
34+
* allowing faster access to state that must can be modified
35+
* outside of the interpreter must be accessed within it */
36+
int use_tracing;
37+
struct _cframe *previous;
38+
} CFrame;
39+
3240
typedef struct _err_stackitem {
3341
/* This struct represents an entry on the exception stack, which is a
3442
* per-coroutine state. (Coroutine in the computer science sense,
@@ -61,7 +69,7 @@ struct _ts {
6169
This is to prevent the actual trace/profile code from being recorded in
6270
the trace/profile. */
6371
int tracing;
64-
int use_tracing;
72+
CFrame *cframe;
6573

6674
Py_tracefunc c_profilefunc;
6775
Py_tracefunc c_tracefunc;
@@ -128,6 +136,7 @@ struct _ts {
128136

129137
/* Unique thread state id. */
130138
uint64_t id;
139+
CFrame root_cframe;
131140

132141
/* XXX signal handlers should also be here */
133142

Python/ceval.c

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ typedef struct {
3838
PyCodeObject *code; // The code object for the bounds. May be NULL.
3939
int instr_prev; // Only valid if code != NULL.
4040
PyCodeAddressRange bounds; // Only valid if code != NULL.
41+
CFrame cframe;
4142
} PyTraceInfo;
4243

4344

@@ -1306,7 +1307,7 @@ eval_frame_handle_pending(PyThreadState *tstate)
13061307

13071308
#define DISPATCH() \
13081309
{ \
1309-
if (tstate->use_tracing OR_DTRACE_LINE OR_LLTRACE) { \
1310+
if (trace_info.cframe.use_tracing OR_DTRACE_LINE OR_LLTRACE) { \
13101311
goto tracing_dispatch; \
13111312
} \
13121313
f->f_lasti = INSTR_OFFSET(); \
@@ -1614,11 +1615,16 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
16141615
/* Mark trace_info as uninitialized */
16151616
trace_info.code = NULL;
16161617

1618+
CFrame *prev_cframe = tstate->cframe;
1619+
trace_info.cframe.use_tracing = prev_cframe->use_tracing;
1620+
trace_info.cframe.previous = prev_cframe;
1621+
tstate->cframe = &trace_info.cframe;
1622+
16171623
/* push frame */
16181624
tstate->frame = f;
16191625
co = f->f_code;
16201626

1621-
if (tstate->use_tracing) {
1627+
if (trace_info.cframe.use_tracing) {
16221628
if (tstate->c_tracefunc != NULL) {
16231629
/* tstate->c_tracefunc, if defined, is a
16241630
function that will be called on *every* entry
@@ -1780,7 +1786,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
17801786

17811787
/* line-by-line tracing support */
17821788

1783-
if (tstate->use_tracing &&
1789+
if (trace_info.cframe.use_tracing &&
17841790
tstate->c_tracefunc != NULL && !tstate->tracing) {
17851791
int err;
17861792
/* see maybe_call_line_trace()
@@ -4541,7 +4547,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
45414547
PUSH(val);
45424548
PUSH(exc);
45434549
JUMPTO(handler);
4544-
if (tstate->use_tracing) {
4550+
if (trace_info.cframe.use_tracing) {
45454551
trace_info.instr_prev = INT_MAX;
45464552
}
45474553
/* Resume normal execution */
@@ -4565,7 +4571,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
45654571
f->f_stackdepth = 0;
45664572
f->f_state = FRAME_RAISED;
45674573
exiting:
4568-
if (tstate->use_tracing) {
4574+
if (trace_info.cframe.use_tracing) {
45694575
if (tstate->c_tracefunc) {
45704576
if (call_trace_protected(tstate->c_tracefunc, tstate->c_traceobj,
45714577
tstate, f, &trace_info, PyTrace_RETURN, retval)) {
@@ -4582,6 +4588,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
45824588

45834589
/* pop frame */
45844590
exit_eval_frame:
4591+
4592+
tstate->cframe = trace_info.cframe.previous;
4593+
tstate->cframe->use_tracing = trace_info.cframe.use_tracing;
4594+
45854595
if (PyDTrace_FUNCTION_RETURN_ENABLED())
45864596
dtrace_function_return(f);
45874597
_Py_LeaveRecursiveCall(tstate);
@@ -5505,7 +5515,7 @@ call_trace(Py_tracefunc func, PyObject *obj,
55055515
if (tstate->tracing)
55065516
return 0;
55075517
tstate->tracing++;
5508-
tstate->use_tracing = 0;
5518+
tstate->cframe->use_tracing = 0;
55095519
if (frame->f_lasti < 0) {
55105520
frame->f_lineno = frame->f_code->co_firstlineno;
55115521
}
@@ -5515,7 +5525,7 @@ call_trace(Py_tracefunc func, PyObject *obj,
55155525
}
55165526
result = func(obj, frame, what, arg);
55175527
frame->f_lineno = 0;
5518-
tstate->use_tracing = ((tstate->c_tracefunc != NULL)
5528+
tstate->cframe->use_tracing = ((tstate->c_tracefunc != NULL)
55195529
|| (tstate->c_profilefunc != NULL));
55205530
tstate->tracing--;
55215531
return result;
@@ -5526,15 +5536,15 @@ _PyEval_CallTracing(PyObject *func, PyObject *args)
55265536
{
55275537
PyThreadState *tstate = _PyThreadState_GET();
55285538
int save_tracing = tstate->tracing;
5529-
int save_use_tracing = tstate->use_tracing;
5539+
int save_use_tracing = tstate->cframe->use_tracing;
55305540
PyObject *result;
55315541

55325542
tstate->tracing = 0;
5533-
tstate->use_tracing = ((tstate->c_tracefunc != NULL)
5543+
tstate->cframe->use_tracing = ((tstate->c_tracefunc != NULL)
55345544
|| (tstate->c_profilefunc != NULL));
55355545
result = PyObject_Call(func, args, NULL);
55365546
tstate->tracing = save_tracing;
5537-
tstate->use_tracing = save_use_tracing;
5547+
tstate->cframe->use_tracing = save_use_tracing;
55385548
return result;
55395549
}
55405550

@@ -5588,15 +5598,15 @@ _PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
55885598
tstate->c_profilefunc = NULL;
55895599
tstate->c_profileobj = NULL;
55905600
/* Must make sure that tracing is not ignored if 'profileobj' is freed */
5591-
tstate->use_tracing = tstate->c_tracefunc != NULL;
5601+
tstate->cframe->use_tracing = tstate->c_tracefunc != NULL;
55925602
Py_XDECREF(profileobj);
55935603

55945604
Py_XINCREF(arg);
55955605
tstate->c_profileobj = arg;
55965606
tstate->c_profilefunc = func;
55975607

55985608
/* Flag that tracing or profiling is turned on */
5599-
tstate->use_tracing = (func != NULL) || (tstate->c_tracefunc != NULL);
5609+
tstate->cframe->use_tracing = (func != NULL) || (tstate->c_tracefunc != NULL);
56005610
return 0;
56015611
}
56025612

@@ -5629,15 +5639,15 @@ _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
56295639
tstate->c_tracefunc = NULL;
56305640
tstate->c_traceobj = NULL;
56315641
/* Must make sure that profiling is not ignored if 'traceobj' is freed */
5632-
tstate->use_tracing = (tstate->c_profilefunc != NULL);
5642+
tstate->cframe->use_tracing = (tstate->c_profilefunc != NULL);
56335643
Py_XDECREF(traceobj);
56345644

56355645
Py_XINCREF(arg);
56365646
tstate->c_traceobj = arg;
56375647
tstate->c_tracefunc = func;
56385648

56395649
/* Flag that tracing or profiling is turned on */
5640-
tstate->use_tracing = ((func != NULL)
5650+
tstate->cframe->use_tracing = ((func != NULL)
56415651
|| (tstate->c_profilefunc != NULL));
56425652

56435653
return 0;
@@ -5832,7 +5842,7 @@ PyEval_GetFuncDesc(PyObject *func)
58325842
}
58335843

58345844
#define C_TRACE(x, call) \
5835-
if (tstate->use_tracing && tstate->c_profilefunc) { \
5845+
if (trace_info->cframe.use_tracing && tstate->c_profilefunc) { \
58365846
if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, \
58375847
tstate, tstate->frame, trace_info, \
58385848
PyTrace_C_CALL, func)) { \
@@ -5913,7 +5923,7 @@ call_function(PyThreadState *tstate,
59135923
Py_ssize_t nargs = oparg - nkwargs;
59145924
PyObject **stack = (*pp_stack) - nargs - nkwargs;
59155925

5916-
if (tstate->use_tracing) {
5926+
if (trace_info->cframe.use_tracing) {
59175927
x = trace_call_function(tstate, trace_info, func, stack, nargs, kwnames);
59185928
}
59195929
else {
@@ -5946,7 +5956,7 @@ do_call_core(PyThreadState *tstate,
59465956
}
59475957
else if (Py_IS_TYPE(func, &PyMethodDescr_Type)) {
59485958
Py_ssize_t nargs = PyTuple_GET_SIZE(callargs);
5949-
if (nargs > 0 && tstate->use_tracing) {
5959+
if (nargs > 0 && trace_info->cframe.use_tracing) {
59505960
/* We need to create a temporary bound method as argument
59515961
for profiling.
59525962

Python/pystate.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,8 @@ new_threadstate(PyInterpreterState *interp, int init)
624624
tstate->recursion_headroom = 0;
625625
tstate->stackcheck_counter = 0;
626626
tstate->tracing = 0;
627-
tstate->use_tracing = 0;
627+
tstate->root_cframe.use_tracing = 0;
628+
tstate->cframe = &tstate->root_cframe;
628629
tstate->gilstate_counter = 0;
629630
tstate->async_exc = NULL;
630631
tstate->thread_id = PyThread_get_thread_ident();

Python/sysmodule.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ sys_audit_tstate(PyThreadState *ts, const char *event,
252252

253253
/* Disallow tracing in hooks unless explicitly enabled */
254254
ts->tracing++;
255-
ts->use_tracing = 0;
255+
ts->cframe->use_tracing = 0;
256256
while ((hook = PyIter_Next(hooks)) != NULL) {
257257
_Py_IDENTIFIER(__cantrace__);
258258
PyObject *o;
@@ -265,22 +265,22 @@ sys_audit_tstate(PyThreadState *ts, const char *event,
265265
break;
266266
}
267267
if (canTrace) {
268-
ts->use_tracing = (ts->c_tracefunc || ts->c_profilefunc);
268+
ts->cframe->use_tracing = (ts->c_tracefunc || ts->c_profilefunc);
269269
ts->tracing--;
270270
}
271271
PyObject* args[2] = {eventName, eventArgs};
272272
o = _PyObject_FastCallTstate(ts, hook, args, 2);
273273
if (canTrace) {
274274
ts->tracing++;
275-
ts->use_tracing = 0;
275+
ts->cframe->use_tracing = 0;
276276
}
277277
if (!o) {
278278
break;
279279
}
280280
Py_DECREF(o);
281281
Py_CLEAR(hook);
282282
}
283-
ts->use_tracing = (ts->c_tracefunc || ts->c_profilefunc);
283+
ts->cframe->use_tracing = (ts->c_tracefunc || ts->c_profilefunc);
284284
ts->tracing--;
285285
if (_PyErr_Occurred(ts)) {
286286
goto exit;

0 commit comments

Comments
 (0)
0