Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit3ece6e6

Browse files
[3.11]GH-93516: BackportGH-93769: Speedup line number checks when tracing (GH-94127)
Co-authored-by: Pablo Galindo <pablogsal@gmail.com>
1 parent8c2af49 commit3ece6e6

File tree

7 files changed

+409
-298
lines changed

7 files changed

+409
-298
lines changed

‎Doc/data/python3.11.abi‎

Lines changed: 308 additions & 290 deletions
Large diffs are not rendered by default.

‎Include/cpython/code.h‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ typedef uint16_t _Py_CODEUNIT;
6262
PyObject*co_exceptiontable;/* Byte string encoding exception handling \
6363
table */ \
6464
intco_flags;/* CO_..., see below */ \
65-
intco_warmup;/* Warmup counter for quickening */ \
65+
shortco_warmup;/* Warmup counter for quickening */ \
66+
short_co_linearray_entry_size;/* Size of each entry in _co_linearray */ \
6667
\
6768
/* The rest are not so impactful on performance. */ \
6869
intco_argcount;/* #arguments, except *args */ \
@@ -88,6 +89,7 @@ typedef uint16_t _Py_CODEUNIT;
8889
PyObject*co_qualname;/* unicode (qualname, for reference) */ \
8990
PyObject*co_linetable;/* bytes object that holds location info */ \
9091
PyObject*co_weakreflist;/* to support weakrefs to code objects */ \
92+
char*_co_linearray;/* array of line offsets */ \
9193
/* Scratch space for extra data relating to the code object. \
9294
Type is a void* to keep the format private in codeobject.c to force \
9395
people to go through the proper APIs. */ \

‎Include/internal/pycore_code.h‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,35 @@ write_location_entry_start(uint8_t *ptr, int code, int length)
475475
}
476476

477477

478+
/* Line array cache for tracing */
479+
480+
externint_PyCode_CreateLineArray(PyCodeObject*co);
481+
482+
staticinlineint
483+
_PyCode_InitLineArray(PyCodeObject*co)
484+
{
485+
if (co->_co_linearray) {
486+
return0;
487+
}
488+
return_PyCode_CreateLineArray(co);
489+
}
490+
491+
staticinlineint
492+
_PyCode_LineNumberFromArray(PyCodeObject*co,intindex)
493+
{
494+
assert(co->_co_linearray!=NULL);
495+
assert(index >=0);
496+
assert(index<Py_SIZE(co));
497+
if (co->_co_linearray_entry_size==2) {
498+
return ((int16_t*)co->_co_linearray)[index];
499+
}
500+
else {
501+
assert(co->_co_linearray_entry_size==4);
502+
return ((int32_t*)co->_co_linearray)[index];
503+
}
504+
}
505+
506+
478507
#ifdef__cplusplus
479508
}
480509
#endif
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Lazily create a table mapping bytecode offsets to line numbers to speed up
2+
calculation of line numbers when tracing.

‎Objects/codeobject.c‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,8 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
336336
co->co_extra=NULL;
337337

338338
co->co_warmup=QUICKENING_INITIAL_WARMUP_VALUE;
339+
co->_co_linearray_entry_size=0;
340+
co->_co_linearray=NULL;
339341
memcpy(_PyCode_CODE(co),PyBytes_AS_STRING(con->code),
340342
PyBytes_GET_SIZE(con->code));
341343
}
@@ -694,13 +696,60 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
694696
lnotab_notes.txt for the details of the lnotab representation.
695697
*/
696698

699+
int
700+
_PyCode_CreateLineArray(PyCodeObject*co)
701+
{
702+
assert(co->_co_linearray==NULL);
703+
PyCodeAddressRangebounds;
704+
intsize;
705+
intmax_line=0;
706+
_PyCode_InitAddressRange(co,&bounds);
707+
while(_PyLineTable_NextAddressRange(&bounds)) {
708+
if (bounds.ar_line>max_line) {
709+
max_line=bounds.ar_line;
710+
}
711+
}
712+
if (max_line< (1 <<15)) {
713+
size=2;
714+
}
715+
else {
716+
size=4;
717+
}
718+
co->_co_linearray=PyMem_Malloc(Py_SIZE(co)*size);
719+
if (co->_co_linearray==NULL) {
720+
PyErr_NoMemory();
721+
return-1;
722+
}
723+
co->_co_linearray_entry_size=size;
724+
_PyCode_InitAddressRange(co,&bounds);
725+
while(_PyLineTable_NextAddressRange(&bounds)) {
726+
intstart=bounds.ar_start /sizeof(_Py_CODEUNIT);
727+
intend=bounds.ar_end /sizeof(_Py_CODEUNIT);
728+
for (intindex=start;index<end;index++) {
729+
assert(index< (int)Py_SIZE(co));
730+
if (size==2) {
731+
assert(((int16_t)bounds.ar_line)==bounds.ar_line);
732+
((int16_t*)co->_co_linearray)[index]=bounds.ar_line;
733+
}
734+
else {
735+
assert(size==4);
736+
((int32_t*)co->_co_linearray)[index]=bounds.ar_line;
737+
}
738+
}
739+
}
740+
return0;
741+
}
742+
697743
int
698744
PyCode_Addr2Line(PyCodeObject*co,intaddrq)
699745
{
700746
if (addrq<0) {
701747
returnco->co_firstlineno;
702748
}
703749
assert(addrq >=0&&addrq<_PyCode_NBYTES(co));
750+
if (co->_co_linearray) {
751+
return_PyCode_LineNumberFromArray(co,addrq /sizeof(_Py_CODEUNIT));
752+
}
704753
PyCodeAddressRangebounds;
705754
_PyCode_InitAddressRange(co,&bounds);
706755
return_PyCode_CheckLineNumber(addrq,&bounds);
@@ -1539,6 +1588,9 @@ code_dealloc(PyCodeObject *co)
15391588
if (co->co_weakreflist!=NULL) {
15401589
PyObject_ClearWeakRefs((PyObject*)co);
15411590
}
1591+
if (co->_co_linearray) {
1592+
PyMem_Free(co->_co_linearray);
1593+
}
15421594
if (co->co_warmup==0) {
15431595
_Py_QuickenedCount--;
15441596
}
@@ -2095,6 +2147,10 @@ _PyStaticCode_Dealloc(PyCodeObject *co)
20952147
PyObject_ClearWeakRefs((PyObject*)co);
20962148
co->co_weakreflist=NULL;
20972149
}
2150+
if (co->_co_linearray) {
2151+
PyMem_Free(co->_co_linearray);
2152+
co->_co_linearray=NULL;
2153+
}
20982154
}
20992155

21002156
int

‎Python/ceval.c‎

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6853,9 +6853,10 @@ call_trace(Py_tracefunc func, PyObject *obj,
68536853
tstate->tracing_what=what;
68546854
PyThreadState_EnterTracing(tstate);
68556855
assert(_PyInterpreterFrame_LASTI(frame) >=0);
6856-
initialize_trace_info(&tstate->trace_info,frame);
6857-
intaddr=_PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT);
6858-
f->f_lineno=_PyCode_CheckLineNumber(addr,&tstate->trace_info.bounds);
6856+
if (_PyCode_InitLineArray(frame->f_code)) {
6857+
return-1;
6858+
}
6859+
f->f_lineno=_PyCode_LineNumberFromArray(frame->f_code,_PyInterpreterFrame_LASTI(frame));
68596860
result=func(obj,f,what,arg);
68606861
f->f_lineno=0;
68616862
PyThreadState_LeaveTracing(tstate);
@@ -6892,7 +6893,9 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
68926893
represents a jump backwards, update the frame's line number and
68936894
then call the trace function if we're tracing source lines.
68946895
*/
6895-
initialize_trace_info(&tstate->trace_info,frame);
6896+
if (_PyCode_InitLineArray(frame->f_code)) {
6897+
return-1;
6898+
}
68966899
intentry_point=0;
68976900
_Py_CODEUNIT*code=_PyCode_CODE(frame->f_code);
68986901
while (_PyOpcode_Deopt[_Py_OPCODE(code[entry_point])]!=RESUME) {
@@ -6903,10 +6906,9 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
69036906
lastline=-1;
69046907
}
69056908
else {
6906-
lastline=_PyCode_CheckLineNumber(instr_prev*sizeof(_Py_CODEUNIT),&tstate->trace_info.bounds);
6909+
lastline=_PyCode_LineNumberFromArray(frame->f_code,instr_prev);
69076910
}
6908-
intaddr=_PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT);
6909-
intline=_PyCode_CheckLineNumber(addr,&tstate->trace_info.bounds);
6911+
intline=_PyCode_LineNumberFromArray(frame->f_code,_PyInterpreterFrame_LASTI(frame));
69106912
PyFrameObject*f=_PyFrame_GetFrameObject(frame);
69116913
if (f==NULL) {
69126914
return-1;

‎Tools/scripts/deepfreeze.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ def generate_code(self, name: str, code: types.CodeType) -> str:
262262
self.write(f".co_exceptiontable ={co_exceptiontable},")
263263
self.field(code,"co_flags")
264264
self.write(".co_warmup = QUICKENING_INITIAL_WARMUP_VALUE,")
265+
self.write("._co_linearray_entry_size = 0,")
265266
self.field(code,"co_argcount")
266267
self.field(code,"co_posonlyargcount")
267268
self.field(code,"co_kwonlyargcount")
@@ -278,6 +279,7 @@ def generate_code(self, name: str, code: types.CodeType) -> str:
278279
self.write(f".co_name ={co_name},")
279280
self.write(f".co_qualname ={co_qualname},")
280281
self.write(f".co_linetable ={co_linetable},")
282+
self.write("._co_linearray = NULL,")
281283
self.write(f".co_code_adaptive ={co_code_adaptive},")
282284
name_as_code=f"(PyCodeObject *)&{name}"
283285
self.deallocs.append(f"_PyStaticCode_Dealloc({name_as_code});")

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp