Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion profiling/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ libdd-profiling = { path = "../libdatadog/libdd-profiling" }
libdd-common = { path = "../libdatadog/libdd-common" }
libdd-library-config-ffi = { path = "../libdatadog/libdd-library-config-ffi" }
env_logger = { version = "0.11", default-features = false }
lazy_static = { version = "1.4" }
libc = "0.2"
# TRACE set to max to support runtime configuration.
log = { version = "0.4", features = ["max_level_trace", "release_max_level_trace"]}
Expand Down
6 changes: 2 additions & 4 deletions profiling/src/allocation/allocation_ge84.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use crate::allocation::{
use crate::bindings as zend;
use crate::PROFILER_NAME;
use core::ptr;
use lazy_static::lazy_static;
use libc::{c_char, c_int, c_void, size_t};
use log::{debug, trace, warn};
use std::sync::atomic::Ordering::Relaxed;
use std::sync::LazyLock;

#[cfg(php_debug)]
use libc::c_uint;
Expand Down Expand Up @@ -94,9 +94,7 @@ fn alloc_prof_needs_disabled_for_jit(version: u32) -> bool {
(80400..80407).contains(&version)
}

lazy_static! {
static ref JIT_ENABLED: bool = unsafe { zend::ddog_php_jit_enabled() };
}
static JIT_ENABLED: LazyLock<bool> = LazyLock::new(|| unsafe { zend::ddog_php_jit_enabled() });

pub fn alloc_prof_ginit() {
unsafe { zend::ddog_php_opcache_init_handle() };
Expand Down
6 changes: 2 additions & 4 deletions profiling/src/allocation/allocation_le83.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ use crate::bindings::{
};
use crate::{RefCellExt, PROFILER_NAME, REQUEST_LOCALS};
use core::ptr;
use lazy_static::lazy_static;
use libc::{c_char, c_int, c_void, size_t};
use log::{debug, trace, warn};
use std::sync::atomic::Ordering::Relaxed;
use std::sync::LazyLock;

#[cfg(feature = "debug_stats")]
use crate::allocation::{ALLOCATION_PROFILING_COUNT, ALLOCATION_PROFILING_SIZE};
Expand Down Expand Up @@ -77,9 +77,7 @@ fn alloc_prof_needs_disabled_for_jit(version: u32) -> bool {
|| (80400..80407).contains(&version)
}

lazy_static! {
static ref JIT_ENABLED: bool = unsafe { zend::ddog_php_jit_enabled() };
}
static JIT_ENABLED: LazyLock<bool> = LazyLock::new(|| unsafe { zend::ddog_php_jit_enabled() });

pub fn alloc_prof_ginit() {
unsafe { zend::ddog_php_opcache_init_handle() };
Expand Down
127 changes: 65 additions & 62 deletions profiling/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ use bindings::{
use clocks::*;
use core::ffi::{c_char, c_int, CStr};
use core::ptr;
use lazy_static::lazy_static;
use libdd_common::{cstr, tag, tag::Tag};
use log::{debug, error, info, trace, warn};
use profiling::{LocalRootSpanResourceMessage, Profiler, VmInterrupt};
Expand All @@ -44,7 +43,7 @@ use std::borrow::Cow;
use std::cell::{BorrowError, BorrowMutError, RefCell};
use std::ops::{Deref, DerefMut};
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
use std::sync::{Arc, Once, OnceLock};
use std::sync::{Arc, LazyLock, Once, OnceLock};
use std::thread::{AccessError, LocalKey};
use std::time::{Duration, Instant};
use uuid::Uuid;
Expand Down Expand Up @@ -75,73 +74,73 @@ static mut RUNTIME_PHP_VERSION: &str = {
}
};

lazy_static! {
/// # Safety
/// The first time this is accessed must be after config is initialized in
/// the first RINIT and before mshutdown!
static ref GLOBAL_TAGS: Vec<Tag> = {
let mut tags = vec![
tag!("language", "php"),
tag!("profiler_version", env!("PROFILER_VERSION")),
// SAFETY: calling getpid() is safe.
Tag::new("process_id", unsafe { libc::getpid() }.to_string())
.expect("process_id tag to be valid"),
Tag::new("runtime-id", runtime_id().to_string()).expect("runtime-id tag to be valid"),
];

// This should probably be "language_version", but this is the
// standardized tag name.
// SAFETY: PHP_VERSION is safe to access in rinit (only
// mutated during minit).
add_tag(&mut tags, "runtime_version", unsafe { RUNTIME_PHP_VERSION });
add_tag(&mut tags, "php.sapi", SAPI.as_ref());
// In case we ever add PHP debug build support, we should add `zend-zts-debug` and
// `zend-nts-debug`. For the time being we only support `zend-zts-ndebug` and
// `zend-nts-ndebug`
let runtime_engine = if cfg!(php_zts) {
"zend-zts-ndebug"
} else {
"zend-nts-ndebug"
};
add_tag(&mut tags, "runtime_engine", runtime_engine);
tags
/// # Safety
/// The first time this is accessed must be after config is initialized in
/// the first RINIT and before mshutdown!
static GLOBAL_TAGS: LazyLock<Vec<Tag>> = LazyLock::new(|| {
let mut tags = vec![
tag!("language", "php"),
tag!("profiler_version", env!("PROFILER_VERSION")),
// SAFETY: calling getpid() is safe.
Tag::new("process_id", unsafe { libc::getpid() }.to_string())
.expect("process_id tag to be valid"),
Tag::new("runtime-id", runtime_id().to_string()).expect("runtime-id tag to be valid"),
];

// This should probably be "language_version", but this is the
// standardized tag name.
// SAFETY: PHP_VERSION is safe to access in rinit (only
// mutated during minit).
add_tag(&mut tags, "runtime_version", unsafe { RUNTIME_PHP_VERSION });
add_tag(&mut tags, "php.sapi", SAPI.as_ref());
// In case we ever add PHP debug build support, we should add `zend-zts-debug` and
// `zend-nts-debug`. For the time being we only support `zend-zts-ndebug` and
// `zend-nts-ndebug`
let runtime_engine = if cfg!(php_zts) {
"zend-zts-ndebug"
} else {
"zend-nts-ndebug"
};
add_tag(&mut tags, "runtime_engine", runtime_engine);
tags
});

/// The Server API the profiler is running under.
static ref SAPI: Sapi = {
#[cfg(not(test))]
{
// SAFETY: sapi_module is initialized before minit and there should be
// no concurrent threads.
let sapi_module = unsafe { zend::sapi_module };
if sapi_module.name.is_null() {
panic!("the sapi_module's name is a null pointer");
}

// SAFETY: value has been checked for NULL; I haven't checked that the
// engine ensures its length is less than `isize::MAX`, but it is a
// risk I'm willing to take.
let sapi_name = unsafe { CStr::from_ptr(sapi_module.name) };
Sapi::from_name(sapi_name.to_string_lossy().as_ref())
}
// When running `cargo test` we do not link against PHP, so `zend::sapi_name` is not
// available and we just return `Sapi::Unkown`
#[cfg(test)]
{
Sapi::Unknown
/// The Server API the profiler is running under.
static SAPI: LazyLock<Sapi> = LazyLock::new(|| {
#[cfg(not(test))]
{
// SAFETY: sapi_module is initialized before minit and there should be
// no concurrent threads.
let sapi_module = unsafe { zend::sapi_module };
if sapi_module.name.is_null() {
panic!("the sapi_module's name is a null pointer");
}
};

// SAFETY: PROFILER_NAME is a byte slice that satisfies the safety requirements.
// Panic: we own this string and it should be UTF8 (see PROFILER_NAME above).
static ref PROFILER_NAME_STR: &'static str = PROFILER_NAME.to_str().unwrap();
// SAFETY: value has been checked for NULL; I haven't checked that the
// engine ensures its length is less than `isize::MAX`, but it is a
// risk I'm willing to take.
let sapi_name = unsafe { CStr::from_ptr(sapi_module.name) };
Sapi::from_name(sapi_name.to_string_lossy().as_ref())
}
// When running `cargo test` we do not link against PHP, so `zend::sapi_name` is not
// available and we just return `Sapi::Unkown`
#[cfg(test)]
{
Sapi::Unknown
}
});

// SAFETY: PROFILER_NAME is a byte slice that satisfies the safety requirements.
// Panic: we own this string and it should be UTF8 (see PROFILER_NAME above).
static PROFILER_NAME_STR: LazyLock<&'static str> = LazyLock::new(|| PROFILER_NAME.to_str().unwrap());

// SAFETY: PROFILER_VERSION is a byte slice that satisfies the safety requirements.
static ref PROFILER_VERSION_STR: &'static str = unsafe { CStr::from_ptr(PROFILER_VERSION.as_ptr() as *const c_char) }
// SAFETY: PROFILER_VERSION is a byte slice that satisfies the safety requirements.
static PROFILER_VERSION_STR: LazyLock<&'static str> = LazyLock::new(|| {
unsafe { CStr::from_ptr(PROFILER_VERSION.as_ptr() as *const c_char) }
.to_str()
// Panic: we own this string and it should be UTF8 (see PROFILER_VERSION above).
.unwrap();
}
.unwrap()
});

/// The runtime ID, which is basically a universally unique "pid". This makes
/// it almost const, the exception being to re-initialize it from a child fork
Expand Down Expand Up @@ -472,13 +471,15 @@ trait RefCellExt<T> {
where
F: FnOnce(&mut T) -> R;

#[inline]
fn borrow_or_false<F>(&'static self, f: F) -> bool
where
F: FnOnce(&T) -> bool,
{
self.try_with_borrow(f).unwrap_or(false)
}

#[inline]
fn borrow_mut_or_false<F>(&'static self, f: F) -> bool
where
F: FnOnce(&mut T) -> bool,
Expand All @@ -488,6 +489,7 @@ trait RefCellExt<T> {
}

impl<T> RefCellExt<T> for LocalKey<RefCell<T>> {
#[inline]
fn try_with_borrow<F, R>(&'static self, f: F) -> Result<R, RefCellExtError>
where
F: FnOnce(&T) -> R,
Expand All @@ -497,6 +499,7 @@ impl<T> RefCellExt<T> for LocalKey<RefCell<T>> {
})??)
}

#[inline]
fn try_with_borrow_mut<F, R>(&'static self, f: F) -> Result<R, RefCellExtError>
where
F: FnOnce(&mut T) -> R,
Expand Down
33 changes: 12 additions & 21 deletions profiling/src/sapi.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use crate::zend::sapi_request_info;
use log::warn;
use std::borrow::Cow;
use std::collections::HashMap;
use std::ffi::{CStr, OsStr};
use std::fmt::{Display, Formatter};
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use std::sync::OnceLock;

// todo: unify with ../component/sapi
#[derive(Copy, Clone, Eq, PartialEq)]
Expand All @@ -27,25 +25,18 @@ pub enum Sapi {

impl Sapi {
pub fn from_name(name: &str) -> Sapi {
static SAPIS: OnceLock<HashMap<&str, Sapi>> = OnceLock::new();
let sapis = SAPIS.get_or_init(|| {
HashMap::from_iter([
("apache2handler", Sapi::Apache2Handler),
("cgi-fcgi", Sapi::CgiFcgi),
("cli", Sapi::Cli),
("cli-server", Sapi::CliServer),
("embed", Sapi::Embed),
("frankenphp", Sapi::FrankenPHP),
("fpm-fcgi", Sapi::FpmFcgi),
("litespeed", Sapi::Litespeed),
("phpdbg", Sapi::PhpDbg),
("tea", Sapi::Tea),
])
});

match sapis.get(name) {
None => Sapi::Unknown,
Some(sapi) => *sapi,
match name {
"apache2handler" => Sapi::Apache2Handler,
"cgi-fcgi" => Sapi::CgiFcgi,
"cli" => Sapi::Cli,
"cli-server" => Sapi::CliServer,
"embed" => Sapi::Embed,
"frankenphp" => Sapi::FrankenPHP,
"fpm-fcgi" => Sapi::FpmFcgi,
"litespeed" => Sapi::Litespeed,
"phpdbg" => Sapi::PhpDbg,
"tea" => Sapi::Tea,
_ => Sapi::Unknown,
}
}

Expand Down
Loading