Skip to content

Commit 8be8d7d

Browse files
committed
gh-149584: Track live remote page cache entries
The profiler clears the page cache between samples, so live entries are always packed at the front. Track the live count and only clear/search that prefix instead of scanning all 1024 slots on the hot path.
1 parent c5520d3 commit 8be8d7d

1 file changed

Lines changed: 29 additions & 26 deletions

File tree

Python/remote_debug.h

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ typedef struct {
147147
int memfd;
148148
#endif
149149
page_cache_entry_t pages[MAX_PAGES];
150+
int page_cache_count;
150151
Py_ssize_t page_size;
151152
} proc_handle_t;
152153

@@ -185,14 +186,16 @@ _Py_RemoteDebug_FreePageCache(proc_handle_t *handle)
185186
handle->pages[i].data = NULL;
186187
handle->pages[i].valid = 0;
187188
}
189+
handle->page_cache_count = 0;
188190
}
189191

190192
UNUSED static void
191193
_Py_RemoteDebug_ClearCache(proc_handle_t *handle)
192194
{
193-
for (int i = 0; i < MAX_PAGES; i++) {
195+
for (int i = 0; i < handle->page_cache_count; i++) {
194196
handle->pages[i].valid = 0;
195197
}
198+
handle->page_cache_count = 0;
196199
}
197200

198201
#if defined(__APPLE__) && defined(TARGET_OS_OSX) && TARGET_OS_OSX
@@ -222,6 +225,7 @@ _Py_RemoteDebug_InitProcHandle(proc_handle_t *handle, pid_t pid) {
222225
handle->memfd = -1;
223226
#endif
224227
handle->page_size = get_page_size();
228+
handle->page_cache_count = 0;
225229
for (int i = 0; i < MAX_PAGES; i++) {
226230
handle->pages[i].data = NULL;
227231
handle->pages[i].valid = 0;
@@ -1287,42 +1291,41 @@ _Py_RemoteDebug_PagedReadRemoteMemory(proc_handle_t *handle,
12871291
return _Py_RemoteDebug_ReadRemoteMemory(handle, addr, size, out);
12881292
}
12891293

1290-
// Search for valid cached page
1291-
for (int i = 0; i < MAX_PAGES; i++) {
1294+
// Search only the pages used since the last clear. The cache is cleared
1295+
// between profiler samples, so entries are packed at the front.
1296+
for (int i = 0; i < handle->page_cache_count; i++) {
12921297
page_cache_entry_t *entry = &handle->pages[i];
12931298
if (entry->valid && entry->page_addr == page_base) {
12941299
memcpy(out, entry->data + offset_in_page, size);
12951300
return 0;
12961301
}
12971302
}
12981303

1299-
// Find reusable slot
1300-
for (int i = 0; i < MAX_PAGES; i++) {
1301-
page_cache_entry_t *entry = &handle->pages[i];
1302-
if (!entry->valid) {
1304+
if (handle->page_cache_count < MAX_PAGES) {
1305+
page_cache_entry_t *entry = &handle->pages[handle->page_cache_count];
1306+
if (entry->data == NULL) {
1307+
entry->data = PyMem_RawMalloc(page_size);
13031308
if (entry->data == NULL) {
1304-
entry->data = PyMem_RawMalloc(page_size);
1305-
if (entry->data == NULL) {
1306-
PyErr_NoMemory();
1307-
_set_debug_exception_cause(PyExc_MemoryError,
1308-
"Cannot allocate %zu bytes for page cache entry "
1309-
"during read from PID %d at address 0x%lx",
1310-
page_size, handle->pid, addr);
1311-
return -1;
1312-
}
1313-
}
1314-
1315-
if (_Py_RemoteDebug_ReadRemoteMemory(handle, page_base, page_size, entry->data) < 0) {
1316-
// Try to just copy the exact amount as a fallback
1317-
PyErr_Clear();
1318-
goto fallback;
1309+
PyErr_NoMemory();
1310+
_set_debug_exception_cause(PyExc_MemoryError,
1311+
"Cannot allocate %zu bytes for page cache entry "
1312+
"during read from PID %d at address 0x%lx",
1313+
page_size, handle->pid, addr);
1314+
return -1;
13191315
}
1316+
}
13201317

1321-
entry->page_addr = page_base;
1322-
entry->valid = 1;
1323-
memcpy(out, entry->data + offset_in_page, size);
1324-
return 0;
1318+
if (_Py_RemoteDebug_ReadRemoteMemory(handle, page_base, page_size, entry->data) < 0) {
1319+
// Try to just copy the exact amount as a fallback
1320+
PyErr_Clear();
1321+
goto fallback;
13251322
}
1323+
1324+
entry->page_addr = page_base;
1325+
entry->valid = 1;
1326+
handle->page_cache_count++;
1327+
memcpy(out, entry->data + offset_in_page, size);
1328+
return 0;
13261329
}
13271330

13281331
fallback:

0 commit comments

Comments
 (0)