gh-96143: Allow Linux perf profiler to see Python calls (GH-96123)

⚠️  ⚠️ Note for reviewers, hackers and fellow systems/low-level/compiler engineers ⚠️ ⚠️ 

If you have a lot of experience with this kind of shenanigans and want to improve the **first** version, **please make a PR against my branch** or **reach out by email** or **suggest code changes directly on GitHub**. 

If you have any **refinements or optimizations** please, wait until the first version is merged before starting hacking or proposing those so we can keep this PR productive.
This commit is contained in:
Pablo Galindo Salgado 2022-08-30 18:11:18 +01:00 committed by GitHub
parent 0f733fffe8
commit 6d791a9736
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 1412 additions and 2 deletions

View file

@ -118,6 +118,11 @@ The following implementation-specific options are available:\n\
files are desired as well as suppressing the extra visual location indicators \n\
when the interpreter displays tracebacks.\n\
\n\
-X perf: activate support for the Linux \"perf\" profiler by activating the \"perf\"\n\
trampoline. When this option is activated, the Linux \"perf\" profiler will be \n\
able to report Python calls. This option is only available on some platforms and will \n\
do nothing if is not supported on the current system. The default value is \"off\".\n\
\n\
-X frozen_modules=[on|off]: whether or not frozen modules should be used.\n\
The default is \"on\" (or \"off\" if you are running a local build).";
@ -745,6 +750,7 @@ _PyConfig_InitCompatConfig(PyConfig *config)
config->use_hash_seed = -1;
config->faulthandler = -1;
config->tracemalloc = -1;
config->perf_profiling = -1;
config->module_search_paths_set = 0;
config->parse_argv = 0;
config->site_import = -1;
@ -829,6 +835,7 @@ PyConfig_InitIsolatedConfig(PyConfig *config)
config->use_hash_seed = 0;
config->faulthandler = 0;
config->tracemalloc = 0;
config->perf_profiling = 0;
config->safe_path = 1;
config->pathconfig_warnings = 0;
#ifdef MS_WINDOWS
@ -940,6 +947,7 @@ _PyConfig_Copy(PyConfig *config, const PyConfig *config2)
COPY_ATTR(_install_importlib);
COPY_ATTR(faulthandler);
COPY_ATTR(tracemalloc);
COPY_ATTR(perf_profiling);
COPY_ATTR(import_time);
COPY_ATTR(code_debug_ranges);
COPY_ATTR(show_ref_count);
@ -1050,6 +1058,7 @@ _PyConfig_AsDict(const PyConfig *config)
SET_ITEM_UINT(hash_seed);
SET_ITEM_INT(faulthandler);
SET_ITEM_INT(tracemalloc);
SET_ITEM_INT(perf_profiling);
SET_ITEM_INT(import_time);
SET_ITEM_INT(code_debug_ranges);
SET_ITEM_INT(show_ref_count);
@ -1331,6 +1340,7 @@ _PyConfig_FromDict(PyConfig *config, PyObject *dict)
CHECK_VALUE("hash_seed", config->hash_seed <= MAX_HASH_SEED);
GET_UINT(faulthandler);
GET_UINT(tracemalloc);
GET_UINT(perf_profiling);
GET_UINT(import_time);
GET_UINT(code_debug_ranges);
GET_UINT(show_ref_count);
@ -1687,6 +1697,26 @@ config_read_env_vars(PyConfig *config)
return _PyStatus_OK();
}
static PyStatus
config_init_perf_profiling(PyConfig *config)
{
int active = 0;
const char *env = config_get_env(config, "PYTHONPERFSUPPORT");
if (env) {
if (_Py_str_to_int(env, &active) != 0) {
active = 0;
}
if (active) {
config->perf_profiling = 1;
}
}
const wchar_t *xoption = config_get_xoption(config, L"perf");
if (xoption) {
config->perf_profiling = 1;
}
return _PyStatus_OK();
}
static PyStatus
config_init_tracemalloc(PyConfig *config)
@ -1788,6 +1818,12 @@ config_read_complex_options(PyConfig *config)
return status;
}
}
if (config->perf_profiling < 0) {
status = config_init_perf_profiling(config);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
}
if (config->pycache_prefix == NULL) {
status = config_init_pycache_prefix(config);
@ -2104,6 +2140,9 @@ config_read(PyConfig *config, int compute_path_config)
if (config->tracemalloc < 0) {
config->tracemalloc = 0;
}
if (config->perf_profiling < 0) {
config->perf_profiling = 0;
}
if (config->use_hash_seed < 0) {
config->use_hash_seed = 0;
config->hash_seed = 0;