Add profiling sources#1606
Conversation
bruceg
left a comment
There was a problem hiding this comment.
I don't have enough knowledge of the broader context to comment on the overall approach, so this review just reflects on the smaller details.
| } | ||
|
|
||
| pub fn stop(self) { | ||
| // todo: what should be done when a thread panics? |
There was a problem hiding this comment.
Yes, but also I really don't know what ought to be done. In general, I don't think anything can be done except to propagate the panic.
There was a problem hiding this comment.
FWIW this is a Hard™ problem, and we build Mork with panic=abort for that reason.
There was a problem hiding this comment.
panic=abort seems nice, but to really get it right you need the stdlib to be rebuilt with it. I couldn't get that to work on Alpine, at the very least, though I haven't tried the latest Alpine release.
mokomull
left a comment
There was a problem hiding this comment.
I didn't really get a chance to look too hard at profiling.rs, but a few comments nonetheless. Mostly style and "a crate already exists to do that" flavoured suggestions.
| // todo: this a lie on some PHP versions; is it a problem even though zend_bool | ||
| // was always supposed to be 0 or 1 anyway? |
There was a problem hiding this comment.
Perhaps: "A value other than false (0) or true (1) in a bool." (https://doc.rust-lang.org/beta/reference/behavior-considered-undefined.html)
| .output() | ||
| .expect("Unable to run `php-config`. Is it in your PATH?"); | ||
|
|
||
| let prefix = String::from_utf8(output.stdout).expect("only utf8 chars work"); |
There was a problem hiding this comment.
If you really wanted to support that you could use Path instead of Strings, but I'm pretty sure any user that's done that has already broken every ./configure script on their system :)
There was a problem hiding this comment.
I don't remember the details, but I actually tried to use Path and couldn't get all the plumbing I needed to work out. For instance, how do I convert the bytes from the output of php-config into a Path?
| // The strings will be interned but potentially only for the request, so be | ||
| // careful to not use them outside of a request (such as from other | ||
| // threads). | ||
| datadog_php_str env; | ||
| datadog_php_str service; | ||
| datadog_php_str version; | ||
| datadog_php_str trace_agent_host; | ||
| datadog_php_str trace_agent_port; | ||
| datadog_php_str trace_agent_url; |
There was a problem hiding this comment.
Can these change from request-to-request (particularly wondering about sapi_getenv() ... the libc getenv() shouldn't really change during execution).
If not, then perhaps we should hold a void* to a Box::into_raw() of a Rust structure so we don't have to bounce these strings through FFI so much just for them to end back up in a Vec<Tag>
There was a problem hiding this comment.
They can change from request to request, yes. For instance, in Apache you can configure env vars to have different values for different directories, think DD_SERVICE=myservice but in /admin it's DD_SERVICE=myservice-admin or something.
The code is partly set up the way it is because PHP's request globals have support for being tied to .ini configuration. I had previously tried to add .ini support, but hit an issue with certain configs like datadog.service being shared by the tracer and profiler, and the engine does not like this (it's not a C vs Rust issue, but a PHP extension issue). So, I pulled out all of the directly dead code but some of the influence is still there. I think I need to support .ini configuration so I'm not sure it's worth making the Rust side of things cleaner at the moment since I'm highly likely to undo that work for .ini. Dunno, I'll think about it.
|
|
||
| #[derive(Debug, Clone)] | ||
| pub enum LabelValue { | ||
| Str(Cow<'static, str>), |
There was a problem hiding this comment.
This seems to only ever be used for format!() so perhaps just take a String for simplicity?
| } | ||
|
|
||
| pub fn stop(self) { | ||
| // todo: what should be done when a thread panics? |
There was a problem hiding this comment.
FWIW this is a Hard™ problem, and we build Mork with panic=abort for that reason.
| static mut SAPIS: MaybeUninit<HashMap<&str, Sapi>> = MaybeUninit::uninit(); | ||
| static ONCE: Once = Once::new(); | ||
| ONCE.call_once(|| { | ||
| let sapis = HashMap::from([ | ||
| ("apache2handler", Sapi::Apache2Handler), | ||
| ("cgi-fcgi", Sapi::CgiFcgi), | ||
| ("cli", Sapi::Cli), | ||
| ("cli-server", Sapi::CliServer), | ||
| ("embed", Sapi::Embed), | ||
| ("fpm-fcgi", Sapi::FpmFcgi), | ||
| ("litespeed", Sapi::Litespeed), | ||
| ("phpdbg", Sapi::PhpDbg), | ||
| ("tea", Sapi::Tea), | ||
| ]); | ||
| unsafe { SAPIS.write(sapis) }; | ||
| }); |
There was a problem hiding this comment.
This seems like a job for the maplit crate.
There was a problem hiding this comment.
Thanks, I'll take a look at maplit.
There was a problem hiding this comment.
I think before Rust 1.56 that maplit would be nice, but since then we have from and from_iter for HashMap. Using maplit would be changing out the (_, _), structure for _ => _, via macro, and I'm not sure how that's better? If it could do it in const contexts that would be awesome, but it can't. Am I missing something?
e03cc07 to
3cc49a9
Compare
Also cleanup some type usage while I'm at it.
|
Added a CODEOWNERS file as requested, but it's currently invalid as |
bwoebi
left a comment
There was a problem hiding this comment.
I assume that before a GA, we will still see proper ini handling.
In general the code reads pretty clean. Looks good to me for initial inclusion.
This reverts commit 3cc49a9. This was only a temporary measure to not waste CI cycles.
Description
This PR does not:
profilingsubdirectory.cargo build. You have to check out Datadog/libdatadog's main branch toprofiling/libdatadog. I didn't want to add a git submodule without discussion and the crates for libdatadog are not yet published, so this is a compromise. Edit: libdatadog v0.7.0 has been released on github since then, so we can probably do something likelibdatadog = { git = "https://github.com/DataDog/libdatadog", tag = "v0.7.0" }. I'll look into this soon.This PR does:
Fixing these things shortcomings will likely come in further PRs, as this one is already at +2,481 additions and I expect it will take some time to be able to get it reviewed and merged, especially as it needs reviewed by both Rust and PHP experts who are busy working on their own things.
There are a variety of
todotasks that I do not expect to be handled in this PR, like unifyingcomponents/sapiwithprofiling/src/sapi.rs. However, there is one aboutzend_boolthat I still need to audit. Given that I expect this PR to take a while to get fully reviewed and that it hasn't caused observable issues yet, I decided to open the PR and do this audit concurrently (and hopefully take no action except remove the todo).Readiness checklist
Tests added for this feature/bug.Reviewer checklist
Changelog from v0.7
process_idandruntime_versiontags.trace, which is even more verbose thandebug.phpinfo()(or the equivalent command line option--ri datadog-profiling).