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

Commit0bd6735

Browse files
committed
pythonGH-93516: Speedup line number checks when tracing. (pythonGH-93763)
* Use a lookup table to reduce overhead of getting line numbers during tracing.
1 parent81686e7 commit0bd6735

File tree

6 files changed

+101
-8
lines changed

6 files changed

+101
-8
lines changed

‎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);
@@ -1534,6 +1583,9 @@ code_dealloc(PyCodeObject *co)
15341583
if (co->co_weakreflist!=NULL) {
15351584
PyObject_ClearWeakRefs((PyObject*)co);
15361585
}
1586+
if (co->_co_linearray) {
1587+
PyMem_Free(co->_co_linearray);
1588+
}
15371589
if (co->co_warmup==0) {
15381590
_Py_QuickenedCount--;
15391591
}
@@ -2090,6 +2142,10 @@ _PyStaticCode_Dealloc(PyCodeObject *co)
20902142
PyObject_ClearWeakRefs((PyObject*)co);
20912143
co->co_weakreflist=NULL;
20922144
}
2145+
if (co->_co_linearray) {
2146+
PyMem_Free(co->_co_linearray);
2147+
co->_co_linearray=NULL;
2148+
}
20932149
}
20942150

20952151
int

‎Python/ceval.c‎

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6854,9 +6854,10 @@ call_trace(Py_tracefunc func, PyObject *obj,
68546854
tstate->tracing_what=what;
68556855
PyThreadState_EnterTracing(tstate);
68566856
assert(_PyInterpreterFrame_LASTI(frame) >=0);
6857-
initialize_trace_info(&tstate->trace_info,frame);
6858-
intaddr=_PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT);
6859-
f->f_lineno=_PyCode_CheckLineNumber(addr,&tstate->trace_info.bounds);
6857+
if (_PyCode_InitLineArray(frame->f_code)) {
6858+
return-1;
6859+
}
6860+
f->f_lineno=_PyCode_LineNumberFromArray(frame->f_code,_PyInterpreterFrame_LASTI(frame));
68606861
result=func(obj,f,what,arg);
68616862
f->f_lineno=0;
68626863
PyThreadState_LeaveTracing(tstate);
@@ -6893,7 +6894,9 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
68936894
represents a jump backwards, update the frame's line number and
68946895
then call the trace function if we're tracing source lines.
68956896
*/
6896-
initialize_trace_info(&tstate->trace_info,frame);
6897+
if (_PyCode_InitLineArray(frame->f_code)) {
6898+
return-1;
6899+
}
68976900
intentry_point=0;
68986901
_Py_CODEUNIT*code=_PyCode_CODE(frame->f_code);
68996902
while (_PyOpcode_Deopt[_Py_OPCODE(code[entry_point])]!=RESUME) {
@@ -6904,10 +6907,9 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
69046907
lastline=-1;
69056908
}
69066909
else {
6907-
lastline=_PyCode_CheckLineNumber(instr_prev*sizeof(_Py_CODEUNIT),&tstate->trace_info.bounds);
6910+
lastline=_PyCode_LineNumberFromArray(frame->f_code,instr_prev);
69086911
}
6909-
intaddr=_PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT);
6910-
intline=_PyCode_CheckLineNumber(addr,&tstate->trace_info.bounds);
6912+
intline=_PyCode_LineNumberFromArray(frame->f_code,_PyInterpreterFrame_LASTI(frame));
69116913
PyFrameObject*f=_PyFrame_GetFrameObject(frame);
69126914
if (f==NULL) {
69136915
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