Skip to content

Commit 056b0a5

Browse files
author
developer
committed
development: merge profile-pid-path — generalize %p to X87_PROFILE + X87_SAMPLE
Our horizonxi-x87 delta only had the X87_SAMPLE half of the %p work (the narrower expandSamplePid). PR athei#31 (profile-pid-path, filed athei#31) generalizes it: a shared expandTargetPid(path, targetPid, variable) covering both X87_PROFILE and X87_SAMPLE, plus the README docs. Adopt PR athei#31's form and drop the now-orphaned expandSamplePid so development carries all of our upstreamed %p work, not half of it. Sticky sampler is unchanged. Verified: cmake build clean; run_tests.sh test_arith 11/11 pass, 0 divergences. %p output-path expansion is config plumbing with no translation effect.
2 parents 38f418e + 243630d commit 056b0a5

2 files changed

Lines changed: 48 additions & 35 deletions

File tree

‎README.md‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,11 @@ achieved.
201201
| `X87_NO_UNWIND=1` | `--no-unwind` | off | leaf pcs only, about half the per-sample cost |
202202

203203
The environment wins over the flags, so an app bundle can enable sampling
204-
without touching argv.
204+
without touching argv. `%p` in the `X87_SAMPLE` or `X87_PROFILE` path expands
205+
to the pid of the process the sidecar is attached to, not the sidecar's own.
206+
Wine starts one cooperative sidecar per i386 process and all of them inherit
207+
the same environment, so a fixed path would let the injector's sidecar
208+
truncate the game's profile, or the reverse.
205209

206210
### Block profiler: what the x87 code costs
207211

‎rosetta_loader/src/sidecar.cpp‎

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2932,14 +2932,48 @@ bool installPortInParent(mach_port_t parentTaskPort, mach_port_t* outServicePort
29322932
return true;
29332933
}
29342934

2935+
// A launcher can start several independently wrapped processes with the same
2936+
// profiler environment. Expand against the process whose task port the
2937+
// sidecar received, not the sidecar's own pid, so they cannot truncate one
2938+
// another's output.
2939+
static bool expandTargetPid(std::string& path, pid_t targetPid, const char* variable) {
2940+
if (path.find("%p") == std::string::npos) {
2941+
return true;
2942+
}
2943+
if (targetPid <= 0) {
2944+
fprintf(stdout,
2945+
"[rosettax87] %s: cannot expand %%p because the target pid is unavailable; "
2946+
"profiling disabled\n",
2947+
variable);
2948+
return false;
2949+
}
2950+
2951+
const std::string replacement = std::to_string(targetPid);
2952+
size_t offset = 0;
2953+
while ((offset = path.find("%p", offset)) != std::string::npos) {
2954+
path.replace(offset, 2, replacement);
2955+
offset += replacement.size();
2956+
}
2957+
return true;
2958+
}
2959+
29352960
bool spawnReceiveThread(mach_port_t servicePort, mach_port_t parentTaskPort) {
29362961
if (g_rosetta_config != nullptr && !g_rosetta_config->profile_path.empty()) {
2937-
const char* path = g_rosetta_config->profile_path.c_str();
2938-
g_profile.file = std::fopen(path, "wb");
2962+
std::string path = g_rosetta_config->profile_path;
2963+
pid_t targetPid = 0;
2964+
pid_for_task(parentTaskPort, &targetPid);
2965+
if (!expandTargetPid(path, targetPid, "X87_PROFILE")) {
2966+
path.clear();
2967+
}
2968+
g_profile.file = path.empty() ? nullptr : std::fopen(path.c_str(), "wb");
29392969
if (g_profile.file == nullptr) {
2940-
fprintf(stdout, "[rosettax87] X87_PROFILE: failed to open '%s' for writing\n", path);
2970+
if (!path.empty()) {
2971+
fprintf(stdout, "[rosettax87] X87_PROFILE: failed to open '%s' for writing\n",
2972+
path.c_str());
2973+
}
29412974
} else {
2942-
fprintf(stdout, "[rosettax87] X87_PROFILE: dumping IR streams to '%s'\n", path);
2975+
fprintf(stdout, "[rosettax87] X87_PROFILE: dumping IR streams to '%s'\n",
2976+
path.c_str());
29432977
}
29442978
fflush(stdout);
29452979
}
@@ -3051,19 +3085,6 @@ void unlinkWindowSeries(const std::string& path) {
30513085
closedir(d);
30523086
}
30533087

3054-
// Several cooperative sidecars can inherit one X87_SAMPLE value from the same
3055-
// launcher. Expand against the process whose task port we received, not this
3056-
// sidecar's pid, so each profile names the process it actually sampled.
3057-
static std::string expandSamplePid(std::string path, pid_t targetPid) {
3058-
const std::string replacement = std::to_string(targetPid);
3059-
size_t offset = 0;
3060-
while ((offset = path.find("%p", offset)) != std::string::npos) {
3061-
path.replace(offset, 2, replacement);
3062-
offset += replacement.size();
3063-
}
3064-
return path;
3065-
}
3066-
30673088
void startSampler(mach_port_t parentTaskPort, uint64_t runtimeBase, const SamplerConfig& in) {
30683089
if (in.path.empty()) {
30693090
return;
@@ -3072,23 +3093,12 @@ void startSampler(mach_port_t parentTaskPort, uint64_t runtimeBase, const Sample
30723093
// Sweeping every thread faster than the sample rate is never what was
30733094
// meant: the sweep is the expensive mode and the rate is the cheap one.
30743095
cfg.sweep_interval_us = std::max(cfg.sweep_interval_us, cfg.interval_us);
3075-
if (cfg.guest_range_pinned) {
3076-
g_counters.guest_lo.store(cfg.guest_lo, std::memory_order_relaxed);
3077-
g_counters.guest_hi.store(cfg.guest_hi, std::memory_order_relaxed);
3078-
}
3079-
// Resolve the target before touching the output path. Wine starts one
3080-
// sidecar per i386 process, and all of them inherit the same environment.
3081-
// Expanding first keeps the injector from truncating the game's profile.
3096+
// The target's pid is needed by both threads and pid_for_task only answers
3097+
// while it is alive, so read it before touching the output path.
30823098
pid_t targetPid = 0;
3083-
if (pid_for_task(parentTaskPort, &targetPid) != KERN_SUCCESS || targetPid <= 0) {
3084-
if (cfg.path.find("%p") != std::string::npos) {
3085-
fprintf(stdout,
3086-
"[rosettax87] X87_SAMPLE: cannot expand %%p because the target pid is "
3087-
"unavailable; sampling disabled\n");
3088-
return;
3089-
}
3090-
} else {
3091-
cfg.path = expandSamplePid(cfg.path, targetPid);
3099+
pid_for_task(parentTaskPort, &targetPid);
3100+
if (!expandTargetPid(cfg.path, targetPid, "X87_SAMPLE")) {
3101+
return;
30923102
}
30933103
// Nothing from a previous run may survive into this one: a run that never
30943104
// latches writes no profile, and the absence has to be the answer rather
@@ -3101,7 +3111,6 @@ void startSampler(mach_port_t parentTaskPort, uint64_t runtimeBase, const Sample
31013111
unlink(cfg.path.c_str());
31023112
unlink((cfg.path + ".windows").c_str());
31033113
unlinkWindowSeries(cfg.path);
3104-
31053114
pthread_attr_t attr;
31063115
pthread_attr_init(&attr);
31073116
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

0 commit comments

Comments
 (0)