@@ -4,6 +4,7 @@ This is the Cython backend used in :py:mod:`line_profiler.line_profiler`.
44"""
55from .python25 cimport PyFrameObject, PyObject, PyStringObject
66from sys import byteorder
7+ import sys
78cimport cython
89from cpython.version cimport PY_VERSION_HEX
910from libc.stdint cimport int64_t
@@ -106,8 +107,8 @@ cdef inline int64 compute_line_hash(uint64 block_hash, uint64 linenum):
106107 return block_hash ^ linenum
107108
108109def label (code ):
109- """ Return a (filename, first_lineno, func_name) tuple for a given code
110- object.
110+ """
111+ Return a (filename, first_lineno, func_name) tuple for a given code object.
111112
112113 This is the same labelling as used by the cProfile module in Python 2.5.
113114 """
@@ -142,17 +143,19 @@ cpdef _code_replace(func, co_code):
142143
143144# Note: this is a regular Python class to allow easy pickling.
144145class LineStats (object ):
145- """ Object to encapsulate line-profile statistics.
146-
147- Attributes
148- ----------
149- timings : dict
150- Mapping from (filename, first_lineno, function_name) of the profiled
151- function to a list of (lineno, nhits, total_time) tuples for each
152- profiled line. total_time is an integer in the native units of the
153- timer.
154- unit : float
155- The number of seconds per timer unit.
146+ """
147+ Object to encapsulate line-profile statistics.
148+
149+ Attributes:
150+
151+ timings (dict):
152+ Mapping from (filename, first_lineno, function_name) of the
153+ profiled function to a list of (lineno, nhits, total_time) tuples
154+ for each profiled line. total_time is an integer in the native
155+ units of the timer.
156+
157+ unit (float):
158+ The number of seconds per timer unit.
156159 """
157160 def __init__ (self , timings , unit ):
158161 self .timings = timings
@@ -225,7 +228,24 @@ cdef class LineProfiler:
225228 if code.co_code in self .dupes_map:
226229 self .dupes_map[code.co_code] += [code]
227230 # code hash already exists, so there must be a duplicate function. add no-op
228- co_code = code.co_code + (9 ).to_bytes(1 , byteorder = byteorder) * (len (self .dupes_map[code.co_code]))
231+ # co_code = code.co_code + (9).to_bytes(1, byteorder=byteorder) * (len(self.dupes_map[code.co_code]))
232+
233+ """
234+ # Code to lookup the NOP opcode, which we will just hard code here
235+ # instead of looking it up. Perhaps do a global lookup in the
236+ # future.
237+ NOP_VALUE: int = opcode.opmap['NOP']
238+ """
239+ NOP_VALUE: int = 9
240+ # Op code should be 2 bytes as stated in
241+ # https://docs.python.org/3/library/dis.html
242+ # if sys.version_info[0:2] >= (3, 11):
243+ NOP_BYTES = NOP_VALUE.to_bytes(2 , byteorder = byteorder)
244+ # else:
245+ # NOP_BYTES = NOP_VALUE.to_bytes(1, byteorder=byteorder)
246+
247+ co_padding = NOP_BYTES * (len (self .dupes_map[code.co_code]) + 1 )
248+ co_code = code.co_code + co_padding
229249 CodeType = type (code)
230250 code = _code_replace(func, co_code = co_code)
231251 try :
@@ -333,7 +353,8 @@ cdef class LineProfiler:
333353 unset_trace()
334354
335355 def get_stats (self ):
336- """ Return a LineStats object containing the timings.
356+ """
357+ Return a LineStats object containing the timings.
337358 """
338359 cdef dict cmap
339360
@@ -373,7 +394,8 @@ cdef class LineProfiler:
373394@ cython.wraparound (False )
374395cdef int python_trace_callback(object self_, PyFrameObject * py_frame, int what,
375396PyObject * arg):
376- """ The PyEval_SetTrace() callback.
397+ """
398+ The PyEval_SetTrace() callback.
377399 """
378400 cdef LineProfiler self
379401 cdef object code
0 commit comments