Skip to content

Commit 6357698

Browse files
committed
Address Pablo's feedback
1 parent bdc8d12 commit 6357698

File tree

12 files changed

+120
-93
lines changed

12 files changed

+120
-93
lines changed

Doc/c-api/perfmaps.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Note that holding an :term:`attached thread state` is not required for these API
3131
or ``-2`` on failure to create a lock. Check ``errno`` for more information
3232
about the cause of a failure.
3333

34-
.. c:function:: int PyUnstable_WritePerfMapEntry(const void *code_addr, unsigned int code_size, const char *entry_name)
34+
.. c:function:: int PyUnstable_WritePerfMapEntry(const void *code_addr, size_t code_size, const char *entry_name)
3535
3636
Write one single entry to the ``/tmp/perf-$pid.map`` file. This function is
3737
thread safe. Here is what an example entry looks like::

Include/cpython/ceval.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ typedef struct {
3838
PyAPI_FUNC(int) PyUnstable_PerfMapState_Init(void);
3939
PyAPI_FUNC(int) PyUnstable_WritePerfMapEntry(
4040
const void *code_addr,
41-
unsigned int code_size,
41+
size_t code_size,
4242
const char *entry_name);
4343
PyAPI_FUNC(void) PyUnstable_PerfMapState_Fini(void);
4444
PyAPI_FUNC(int) PyUnstable_CopyPerfMapFile(const char* parent_filename);
Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,39 @@
1-
#ifndef Py_CORE_JIT_UNWIND_H
2-
#define Py_CORE_JIT_UNWIND_H
1+
#ifndef Py_INTERNAL_JIT_UNWIND_H
2+
#define Py_INTERNAL_JIT_UNWIND_H
33

4-
#ifdef PY_HAVE_PERF_TRAMPOLINE
4+
#ifndef Py_BUILD_CORE
5+
# error "this header requires Py_BUILD_CORE define"
6+
#endif
7+
8+
#if defined(PY_HAVE_PERF_TRAMPOLINE) || (defined(__linux__) && defined(__ELF__))
59

610
#include <stddef.h>
711

12+
/* DWARF exception-handling pointer encodings shared by JIT unwind users. */
13+
enum {
14+
DWRF_EH_PE_absptr = 0x00,
15+
DWRF_EH_PE_omit = 0xff,
16+
17+
/* Data type encodings */
18+
DWRF_EH_PE_uleb128 = 0x01,
19+
DWRF_EH_PE_udata2 = 0x02,
20+
DWRF_EH_PE_udata4 = 0x03,
21+
DWRF_EH_PE_udata8 = 0x04,
22+
DWRF_EH_PE_sleb128 = 0x09,
23+
DWRF_EH_PE_sdata2 = 0x0a,
24+
DWRF_EH_PE_sdata4 = 0x0b,
25+
DWRF_EH_PE_sdata8 = 0x0c,
26+
DWRF_EH_PE_signed = 0x08,
27+
28+
/* Reference type encodings */
29+
DWRF_EH_PE_pcrel = 0x10,
30+
DWRF_EH_PE_textrel = 0x20,
31+
DWRF_EH_PE_datarel = 0x30,
32+
DWRF_EH_PE_funcrel = 0x40,
33+
DWRF_EH_PE_aligned = 0x50,
34+
DWRF_EH_PE_indirect = 0x80
35+
};
36+
837
/* Return the size of the generated .eh_frame data for the given encoding. */
938
size_t _PyJitUnwind_EhFrameSize(int absolute_addr);
1039

@@ -18,13 +47,13 @@ size_t _PyJitUnwind_BuildEhFrame(uint8_t *buffer, size_t buffer_size,
1847
const void *code_addr, size_t code_size,
1948
int absolute_addr);
2049

21-
void _PyJitUnwind_GdbRegisterCode(const void *code_addr,
50+
void *_PyJitUnwind_GdbRegisterCode(const void *code_addr,
2251
size_t code_size,
2352
const char *entry,
2453
const char *filename);
2554

26-
void _PyJitUnwind_GdbUnregisterCode(const void *code_addr);
55+
void _PyJitUnwind_GdbUnregisterCode(void *handle);
2756

28-
#endif // PY_HAVE_PERF_TRAMPOLINE
57+
#endif // defined(PY_HAVE_PERF_TRAMPOLINE) || (defined(__linux__) && defined(__ELF__))
2958

30-
#endif // Py_CORE_JIT_UNWIND_H
59+
#endif // Py_INTERNAL_JIT_UNWIND_H

Include/internal/pycore_optimizer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ typedef struct _PyExecutorObject {
151151
uint32_t code_size;
152152
size_t jit_size;
153153
void *jit_code;
154+
void *jit_gdb_handle;
154155
_PyExitData exits[1];
155156
} _PyExecutorObject;
156157

Lib/test/test_perfmaps.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import sys
23
import sysconfig
34
import unittest
45

@@ -17,11 +18,25 @@ def supports_trampoline_profiling():
1718
raise unittest.SkipTest("perf trampoline profiling not supported")
1819

1920
class TestPerfMapWriting(unittest.TestCase):
21+
def tearDown(self):
22+
perf_map_state_teardown()
23+
2024
def test_write_perf_map_entry(self):
2125
self.assertEqual(write_perf_map_entry(0x1234, 5678, "entry1"), 0)
2226
self.assertEqual(write_perf_map_entry(0x2345, 6789, "entry2"), 0)
2327
with open(f"/tmp/perf-{os.getpid()}.map") as f:
2428
perf_file_contents = f.read()
2529
self.assertIn("1234 162e entry1", perf_file_contents)
2630
self.assertIn("2345 1a85 entry2", perf_file_contents)
27-
perf_map_state_teardown()
31+
32+
@unittest.skipIf(sys.maxsize <= 2**32, "requires size_t wider than unsigned int")
33+
def test_write_perf_map_entry_large_size(self):
34+
code_addr = 0x3456
35+
code_size = 1 << 33
36+
entry_name = "entry_big"
37+
38+
self.assertEqual(write_perf_map_entry(code_addr, code_size, entry_name), 0)
39+
with open(f"/tmp/perf-{os.getpid()}.map") as f:
40+
perf_file_contents = f.read()
41+
self.assertIn(f"{code_addr:x} {code_size:x} {entry_name}",
42+
perf_file_contents)

Modules/_testinternalcapi.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,17 +1210,23 @@ write_perf_map_entry(PyObject *self, PyObject *args)
12101210
{
12111211
PyObject *code_addr_v;
12121212
const void *code_addr;
1213+
PyObject *code_size_s;
12131214
size_t code_size;
12141215
const char *entry_name;
12151216

1216-
if (!PyArg_ParseTuple(args, "OIs", &code_addr_v, &code_size, &entry_name))
1217+
if (!PyArg_ParseTuple(args, "OOs", &code_addr_v, &code_size_s, &entry_name))
12171218
return NULL;
12181219
code_addr = PyLong_AsVoidPtr(code_addr_v);
12191220
if (code_addr == NULL) {
12201221
return NULL;
12211222
}
12221223

1223-
int ret = PyUnstable_WritePerfMapEntry(code_addr, (unsigned int)code_size, entry_name);
1224+
code_size = PyLong_AsSize_t(code_size_s);
1225+
if (code_size == (size_t)-1 && PyErr_Occurred()) {
1226+
return NULL;
1227+
}
1228+
1229+
int ret = PyUnstable_WritePerfMapEntry(code_addr, code_size, entry_name);
12241230
if (ret < 0) {
12251231
PyErr_SetFromErrno(PyExc_OSError);
12261232
return NULL;

Python/jit.c

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ jit_error(const char *message)
6161
PyErr_Format(PyExc_RuntimeWarning, "JIT %s (%d)", message, hint);
6262
}
6363

64-
static void
64+
static void *
6565
jit_record_code(const void *code_addr, size_t code_size,
6666
const char *entry, const char *filename)
6767
{
@@ -71,19 +71,24 @@ jit_record_code(const void *code_addr, size_t code_size,
7171
if (callbacks.write_state == _Py_perfmap_jit_callbacks.write_state) {
7272
_PyPerfJit_WriteNamedCode(
7373
code_addr, code_size, entry, filename);
74-
return;
74+
return NULL;
7575
}
76-
_PyJitUnwind_GdbRegisterCode(
76+
#endif
77+
78+
#if defined(__linux__) && defined(__ELF__)
79+
return _PyJitUnwind_GdbRegisterCode(
7780
code_addr, code_size, entry, filename);
7881
#else
7982
(void)code_addr;
8083
(void)code_size;
8184
(void)entry;
8285
(void)filename;
86+
return NULL;
8387
#endif
8488
}
8589

8690
static size_t _Py_jit_shim_size = 0;
91+
static void *_Py_jit_shim_gdb_handle = NULL;
8792

8893
static int
8994
address_in_executor_array(_PyExecutorObject **ptrs, size_t count, uintptr_t addr)
@@ -754,7 +759,7 @@ _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction trace[], siz
754759
}
755760
executor->jit_code = memory;
756761
executor->jit_size = total_size;
757-
jit_record_code(memory,
762+
executor->jit_gdb_handle = jit_record_code(memory,
758763
code_size + state.trampolines.size,
759764
"jit_entry",
760765
"<jit>");
@@ -808,10 +813,10 @@ compile_shim(void)
808813
return NULL;
809814
}
810815
_Py_jit_shim_size = total_size;
811-
jit_record_code(memory,
812-
code_size + state.trampolines.size,
813-
"jit_entry",
814-
"<jit>");
816+
_Py_jit_shim_gdb_handle = jit_record_code(memory,
817+
code_size + state.trampolines.size,
818+
"jit_entry",
819+
"<jit>");
815820
return (_PyJitEntryFuncPtr)memory;
816821
}
817822

@@ -843,8 +848,11 @@ _PyJIT_Free(_PyExecutorObject *executor)
843848
if (memory) {
844849
executor->jit_code = NULL;
845850
executor->jit_size = 0;
846-
#ifdef PY_HAVE_PERF_TRAMPOLINE
847-
_PyJitUnwind_GdbUnregisterCode(memory);
851+
#if defined(__linux__) && defined(__ELF__)
852+
if (executor->jit_gdb_handle != NULL) {
853+
_PyJitUnwind_GdbUnregisterCode(executor->jit_gdb_handle);
854+
executor->jit_gdb_handle = NULL;
855+
}
848856
#endif
849857
if (jit_free(memory, size)) {
850858
PyErr_FormatUnraisable("Exception ignored while "
@@ -863,8 +871,11 @@ _PyJIT_Fini(void)
863871
if (size) {
864872
_Py_jit_entry = _Py_LazyJitShim;
865873
_Py_jit_shim_size = 0;
866-
#ifdef PY_HAVE_PERF_TRAMPOLINE
867-
_PyJitUnwind_GdbUnregisterCode(memory);
874+
#if defined(__linux__) && defined(__ELF__)
875+
if (_Py_jit_shim_gdb_handle != NULL) {
876+
_PyJitUnwind_GdbUnregisterCode(_Py_jit_shim_gdb_handle);
877+
_Py_jit_shim_gdb_handle = NULL;
878+
}
868879
#endif
869880
if (jit_free(memory, size)) {
870881
PyErr_FormatUnraisable("Exception ignored while "

0 commit comments

Comments
 (0)