functiontrace 0.5.2__tar.gz → 0.5.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {functiontrace-0.5.2/functiontrace.egg-info → functiontrace-0.5.3}/PKG-INFO +1 -1
- {functiontrace-0.5.2 → functiontrace-0.5.3/functiontrace.egg-info}/PKG-INFO +1 -1
- {functiontrace-0.5.2 → functiontrace-0.5.3}/functiontrace.egg-info/SOURCES.txt +2 -1
- {functiontrace-0.5.2 → functiontrace-0.5.3}/pyproject.toml +1 -1
- {functiontrace-0.5.2 → functiontrace-0.5.3}/rust/lib.rs +67 -1
- functiontrace-0.5.3/rust/multiprocessing.sh.tpl +53 -0
- {functiontrace-0.5.2 → functiontrace-0.5.3}/Cargo.toml +0 -0
- {functiontrace-0.5.2 → functiontrace-0.5.3}/LICENSE.md +0 -0
- {functiontrace-0.5.2 → functiontrace-0.5.3}/MANIFEST.in +0 -0
- {functiontrace-0.5.2 → functiontrace-0.5.3}/README.rst +0 -0
- {functiontrace-0.5.2 → functiontrace-0.5.3}/build.rs +0 -0
- {functiontrace-0.5.2 → functiontrace-0.5.3}/functiontrace.egg-info/dependency_links.txt +0 -0
- {functiontrace-0.5.2 → functiontrace-0.5.3}/functiontrace.egg-info/entry_points.txt +0 -0
- {functiontrace-0.5.2 → functiontrace-0.5.3}/functiontrace.egg-info/top_level.txt +0 -0
- {functiontrace-0.5.2 → functiontrace-0.5.3}/functiontrace.py +0 -0
- {functiontrace-0.5.2 → functiontrace-0.5.3}/setup.cfg +0 -0
- {functiontrace-0.5.2 → functiontrace-0.5.3}/setup.py +0 -0
|
@@ -241,6 +241,8 @@ mod _functiontrace_rs {
|
|
|
241
241
|
module: &Bound<'_, PyModule>,
|
|
242
242
|
output_directory: OsString,
|
|
243
243
|
) -> Result<()> {
|
|
244
|
+
use std::os::unix::fs::{DirBuilderExt, PermissionsExt};
|
|
245
|
+
|
|
244
246
|
// The name of the env var we use to notify subprocesses that there's a trace in progress.
|
|
245
247
|
const BREADCRUMB: &str = "FUNCTIONTRACE_LIVE";
|
|
246
248
|
|
|
@@ -337,7 +339,16 @@ mod _functiontrace_rs {
|
|
|
337
339
|
e => e.wrap_err("Failed to launch functiontrace-server")?,
|
|
338
340
|
};
|
|
339
341
|
|
|
340
|
-
format!("/tmp/functiontrace-server.sock.{}", server.id())
|
|
342
|
+
let sockaddr = format!("/tmp/functiontrace-server.sock.{}", server.id());
|
|
343
|
+
|
|
344
|
+
// Also allocate a directory for storing wrappers (multiprocessing.set_executable,
|
|
345
|
+
// etc) we may need.
|
|
346
|
+
std::fs::DirBuilder::new()
|
|
347
|
+
.recursive(true)
|
|
348
|
+
.mode(0o700)
|
|
349
|
+
.create(format!("{sockaddr}.wrappers"))
|
|
350
|
+
.wrap_err("Failed to create wrapper directory")?;
|
|
351
|
+
sockaddr.into()
|
|
341
352
|
};
|
|
342
353
|
|
|
343
354
|
Python::attach(|_| {
|
|
@@ -414,6 +425,61 @@ mod _functiontrace_rs {
|
|
|
414
425
|
.wrap_err("Failed to close initialization socket")?;
|
|
415
426
|
}
|
|
416
427
|
|
|
428
|
+
// `multiprocessing` uses an absolute path to an executable to launch forkserver workers
|
|
429
|
+
// using `-c` for the actual code,
|
|
430
|
+
// Override this with our own wrapper that also sets up functiontrace.
|
|
431
|
+
Python::attach(|py| -> Result<()> {
|
|
432
|
+
let executable: String = py.import("sys")?.getattr("executable")?.extract()?;
|
|
433
|
+
let wrapper = {
|
|
434
|
+
// We'll store the wrappers next to the socket.
|
|
435
|
+
// TODO: Ideally we'd have these all in the same tmpdir, but that requires changing
|
|
436
|
+
// client and server code so would be a breaking change.
|
|
437
|
+
let mut directory = SOCKADDR
|
|
438
|
+
.get()
|
|
439
|
+
.expect("sockaddr is set during server initialization")
|
|
440
|
+
.clone();
|
|
441
|
+
directory.push(".wrappers");
|
|
442
|
+
|
|
443
|
+
std::path::PathBuf::from(directory)
|
|
444
|
+
.join("multiprocessing")
|
|
445
|
+
.join(executable.strip_prefix("/").unwrap_or(&executable))
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
// Create a multiprocessing wrapper for the current executable if it doesn't exist yet.
|
|
449
|
+
std::fs::create_dir_all(
|
|
450
|
+
wrapper
|
|
451
|
+
.parent()
|
|
452
|
+
.expect("Wrappers are always in a subdirectory"),
|
|
453
|
+
)
|
|
454
|
+
.wrap_err("Failed to create multiprocessing wrapper directories")?;
|
|
455
|
+
|
|
456
|
+
match std::fs::OpenOptions::new()
|
|
457
|
+
.write(true)
|
|
458
|
+
.create_new(true)
|
|
459
|
+
.open(&wrapper)
|
|
460
|
+
{
|
|
461
|
+
Ok(mut file) => {
|
|
462
|
+
let script = include_str!("multiprocessing.sh.tpl").replace(
|
|
463
|
+
"@PYTHON_INTERPRETER@",
|
|
464
|
+
// NOTE: This is equivalent to shlex.quote
|
|
465
|
+
&format!("'{}'", executable.replace('\'', "'\"'\"'")),
|
|
466
|
+
);
|
|
467
|
+
|
|
468
|
+
file.write_all(script.as_bytes())
|
|
469
|
+
.wrap_err("Failed to write multiprocessing wrapper")?;
|
|
470
|
+
file.set_permissions(std::fs::Permissions::from_mode(0o700))
|
|
471
|
+
.wrap_err("Failed to `chmod +x` multiprocessing wrapper")?;
|
|
472
|
+
}
|
|
473
|
+
Err(err) if err.kind() == std::io::ErrorKind::AlreadyExists => {}
|
|
474
|
+
Err(err) => return Err(err).wrap_err("Failed to create multiprocessing wrapper"),
|
|
475
|
+
}
|
|
476
|
+
py.import("multiprocessing")?
|
|
477
|
+
.getattr("set_executable")?
|
|
478
|
+
.call1((wrapper,))?;
|
|
479
|
+
Ok(())
|
|
480
|
+
})
|
|
481
|
+
.wrap_err("Failed to configure multiprocessing tracing")?;
|
|
482
|
+
|
|
417
483
|
////////////////////////////////////////////////////////////////////////////
|
|
418
484
|
// Teardown Configuration
|
|
419
485
|
////////////////////////////////////////////////////////////////////////////
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
# Multiprocessing passes the code to execute in workers as `-c <code>`.
|
|
4
|
+
# Strip that out and run tracing setup first, maintaining the order of arguments just in case.
|
|
5
|
+
|
|
6
|
+
remaining=$#
|
|
7
|
+
while [ "$remaining" -gt 0 ]; do
|
|
8
|
+
arg=$1
|
|
9
|
+
shift
|
|
10
|
+
remaining=$((remaining - 1))
|
|
11
|
+
case "$arg" in
|
|
12
|
+
-W|-X)
|
|
13
|
+
# These arguments can consume other arguments. Skip them so we don't parse the wrong `-c`.
|
|
14
|
+
value=$1
|
|
15
|
+
shift
|
|
16
|
+
remaining=$((remaining - 1))
|
|
17
|
+
set -- "$@" "$arg" "$value"
|
|
18
|
+
;;
|
|
19
|
+
-c)
|
|
20
|
+
code=$1
|
|
21
|
+
shift
|
|
22
|
+
remaining=$((remaining - 1))
|
|
23
|
+
set -- "$@" -c '
|
|
24
|
+
exec(
|
|
25
|
+
(
|
|
26
|
+
compile(
|
|
27
|
+
__import__("sys").argv.pop(1),
|
|
28
|
+
"<string>",
|
|
29
|
+
"exec",
|
|
30
|
+
dont_inherit=True,
|
|
31
|
+
),
|
|
32
|
+
# Start tracing before exec runs the compiled code.
|
|
33
|
+
__import__("_functiontrace_rs").begin_tracing("."),
|
|
34
|
+
)[0]
|
|
35
|
+
)
|
|
36
|
+
' "$code"
|
|
37
|
+
break
|
|
38
|
+
;;
|
|
39
|
+
*)
|
|
40
|
+
set -- "$@" "$arg"
|
|
41
|
+
;;
|
|
42
|
+
esac
|
|
43
|
+
done
|
|
44
|
+
|
|
45
|
+
# Consume the rest of the args without looking.
|
|
46
|
+
while [ "$remaining" -gt 0 ]; do
|
|
47
|
+
arg=$1
|
|
48
|
+
shift
|
|
49
|
+
remaining=$((remaining - 1))
|
|
50
|
+
set -- "$@" "$arg"
|
|
51
|
+
done
|
|
52
|
+
|
|
53
|
+
exec @PYTHON_INTERPRETER@ "$@"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|