Skip to content

Commit ec49560

Browse files
committed
Merge branch 'leo.romanovsky/milestone-1-runtime-evaluation' into leo.romanovsky/m2-m3-evaluation-completed-base
2 parents e9b713c + c2fb467 commit ec49560

12 files changed

Lines changed: 206 additions & 15 deletions

File tree

.github/workflows/prof_asan.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ on:
55

66
jobs:
77
prof-asan:
8+
name: PHP ${{ matrix.php-version }} ${{ matrix.php-build }} (${{ matrix.runner }})
89
runs-on: ${{ matrix.runner }}
910
strategy:
1011
matrix:
1112
php-version: [8.3, 8.4, 8.5]
13+
php-build: [nts-asan, debug-zts-asan]
1214
runner: [arm-8core-linux, ubuntu-8-core-latest]
1315
env:
1416
CARGO_HOME: /rust/cargo
@@ -42,12 +44,12 @@ jobs:
4244
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
4345
with:
4446
path: /tmp/build-cargo/
45-
key: ${{ runner.os }}-${{ runner.arch }}-cargo-target-asan-${{ matrix.php-version }}-${{ env.RUST_TOOLCHAIN }}-${{ github.sha }}-${{ hashFiles('.github/workflows/prof_asan.yml') }}
47+
key: ${{ runner.os }}-${{ runner.arch }}-cargo-target-asan-${{ matrix.php-version }}-${{ matrix.php-build }}-${{ env.RUST_TOOLCHAIN }}-${{ github.sha }}-${{ hashFiles('.github/workflows/prof_asan.yml') }}
4648

4749
- name: Build and install profiler
4850
run: |
4951
set -eux
50-
switch-php nts-asan
52+
switch-php ${{ matrix.php-build }}
5153
cd profiling
5254
export CC=clang-19
5355
export CFLAGS='-fsanitize=address -fno-omit-frame-pointer'
@@ -60,7 +62,7 @@ jobs:
6062
- name: Run phpt tests
6163
run: |
6264
set -eux
63-
switch-php nts-asan
65+
switch-php ${{ matrix.php-build }}
6466
cd profiling/tests
6567
cp -v $(php-config --prefix)/lib/php/build/run-tests.php .
6668
export DD_PROFILING_OUTPUT_PPROF=/tmp/pprof

.gitlab-ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ generate-templates:
4545
elif [ "${CI_COMMIT_BRANCH:-}" = "bot/libdatadog-latest" ]; then
4646
# Feedback run after a bot commit: the submodule already points to the tested SHA.
4747
# Don't export — generate-common.php must not inject fetch/checkout (no-op anyway).
48+
set -x
49+
apt update
50+
apt install -y git
4851
LIBDATADOG_SHA=$(git ls-tree HEAD libdatadog | awk '{print $3}')
4952
printf 'LIBDATADOG_OVERRIDE_SHA=%s\nLIBDATADOG_FEEDBACK_RUN=true\n' "$LIBDATADOG_SHA" >> libdatadog.env
5053
fi

.gitlab/generate-common.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ function windows_git_setup_with_packages() {
114114
}
115115

116116
$step = <<<STEP
117+
- git config --global --add safe.directory "\${CI_PROJECT_DIR}/libdatadog"
117118
- git -C libdatadog fetch --depth=1 origin "$_libdatadog_sha" 2>&1
118119
- git -C libdatadog checkout FETCH_HEAD
119120
STEP;

.gitlab/libdatadog-latest.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,10 @@ stages:
211211
# Install Claude (nvm — no root required)
212212
if ! command -v claude &>/dev/null; then
213213
export NVM_DIR="${HOME}/.nvm"
214-
curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash - 2>&1
215-
. "${NVM_DIR}/nvm.sh"
216-
nvm install --lts --no-progress 2>&1
217-
npm install -g @anthropic-ai/claude-code 2>&1
214+
curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash - >/dev/null 2>&1
215+
. "${NVM_DIR}/nvm.sh" >/dev/null 2>&1
216+
nvm install --lts --no-progress >/dev/null 2>&1
217+
npm install -g @anthropic-ai/claude-code >/dev/null 2>&1
218218
fi
219219
220220
AI_GATEWAY_TOKEN=$(_vault_jwt rapid-ai-platform) || {

ext/engine_hooks.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ static zend_op_array *_dd_compile_file(zend_file_handle *file_handle, int type)
7777
zend_op_array *res;
7878
uint64_t start = zend_hrtime();
7979
res = _prev_compile_file(file_handle, type);
80-
DDTRACE_G(compile_time_microseconds) += (int64_t)(zend_hrtime() - start);
80+
DDTRACE_G(compile_time_microseconds) += (int64_t)((zend_hrtime() - start) / 1000);
8181
return res;
8282
}
8383

profiling/build.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ fn main() {
5454
cfg_php_major_version(vernum);
5555
cfg_php_feature_flags(vernum);
5656
cfg_zts();
57+
cfg_php_debug();
5758
apple_linker_flags();
5859
}
5960

@@ -462,6 +463,71 @@ int main() {
462463
}
463464
}
464465

466+
fn cfg_php_debug() {
467+
println!("cargo::rustc-check-cfg=cfg(php_debug)");
468+
469+
let output = Command::new("php-config")
470+
.arg("--include-dir")
471+
.output()
472+
.expect("Unable to run `php-config`. Is it in your PATH?");
473+
474+
if !output.status.success() {
475+
match String::from_utf8(output.stderr) {
476+
Ok(stderr) => panic!("`php-config --include-dir` failed: {stderr}"),
477+
Err(err) => panic!("`php-config --include-dir` failed, not utf8: {err}"),
478+
}
479+
}
480+
481+
let include_dir = std::str::from_utf8(output.stdout.as_slice())
482+
.expect("`php-config`'s stdout to be valid utf8")
483+
.trim();
484+
485+
let out_dir = env::var("OUT_DIR").unwrap();
486+
let probe_path = Path::new(&out_dir).join("php_debug_probe.c");
487+
fs::write(
488+
&probe_path,
489+
r#"
490+
#include "main/php_config.h"
491+
#include <stdio.h>
492+
int main() {
493+
#if ZEND_DEBUG
494+
printf("1");
495+
#else
496+
printf("0");
497+
#endif
498+
return 0;
499+
}
500+
"#,
501+
)
502+
.expect("Failed to write PHP debug probe file");
503+
504+
let compiler = cc::Build::new().get_compiler();
505+
let probe_exe = Path::new(&out_dir).join("php_debug_probe");
506+
let compile_status = Command::new(compiler.path())
507+
.arg(format!("-I{}", include_dir))
508+
.arg(&probe_path)
509+
.arg("-o")
510+
.arg(&probe_exe)
511+
.status()
512+
.expect("Failed to compile PHP debug probe");
513+
514+
if !compile_status.success() {
515+
panic!("Failed to compile PHP debug probe");
516+
}
517+
518+
let probe_output = Command::new(&probe_exe)
519+
.output()
520+
.expect("Failed to run PHP debug probe");
521+
522+
let debug_value = std::str::from_utf8(&probe_output.stdout)
523+
.expect("PHP debug probe output not UTF-8")
524+
.trim();
525+
526+
if debug_value == "1" {
527+
println!("cargo:rustc-cfg=php_debug");
528+
}
529+
}
530+
465531
/// On macOS (Apple targets), the cdylib has undefined symbols that are
466532
/// resolved at load time by the PHP process. In debug builds, LTO is off
467533
/// which produces more unresolved symbols--we fall back to

profiling/src/allocation/allocation_ge84.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ use libc::{c_char, c_int, c_void, size_t};
77
use log::{debug, trace, warn};
88
use std::sync::atomic::Ordering::Relaxed;
99

10+
#[cfg(php_debug)]
11+
use libc::c_uint;
12+
1013
#[cfg(feature = "debug_stats")]
1114
use crate::allocation::{ALLOCATION_PROFILING_COUNT, ALLOCATION_PROFILING_SIZE};
1215

@@ -271,7 +274,24 @@ unsafe fn restore_zend_heap(heap: *mut zend::_zend_mm_heap, custom_heap: c_int)
271274
ptr::write(heap as *mut c_int, custom_heap);
272275
}
273276

277+
#[cfg(not(php_debug))]
274278
unsafe extern "C" fn alloc_prof_malloc(len: size_t) -> *mut c_void {
279+
alloc_prof_malloc_impl(len)
280+
}
281+
282+
#[cfg(php_debug)]
283+
unsafe extern "C" fn alloc_prof_malloc(
284+
len: size_t,
285+
_file: *const c_char,
286+
_line: c_uint,
287+
_orig_file: *const c_char,
288+
_orig_line: c_uint,
289+
) -> *mut c_void {
290+
alloc_prof_malloc_impl(len)
291+
}
292+
293+
#[inline(always)]
294+
unsafe fn alloc_prof_malloc_impl(len: size_t) -> *mut c_void {
275295
#[cfg(feature = "debug_stats")]
276296
ALLOCATION_PROFILING_COUNT.fetch_add(1, Relaxed);
277297
#[cfg(feature = "debug_stats")]
@@ -300,6 +320,11 @@ unsafe fn alloc_prof_prev_alloc(len: size_t) -> *mut c_void {
300320
// neighboring extension could misbehave. If that happens, we want a proper
301321
// panic with backtrace for debugging rather than undefined behavior.
302322
let alloc = tls_zend_mm_state_get!(prev_custom_mm_alloc).unwrap();
323+
#[cfg(php_debug)]
324+
{
325+
return alloc(len, ptr::null(), 0, ptr::null(), 0);
326+
}
327+
#[cfg(not(php_debug))]
303328
alloc(len)
304329
}
305330

@@ -308,14 +333,34 @@ unsafe fn alloc_prof_orig_alloc(len: size_t) -> *mut c_void {
308333
// handlers only point to this function after successful init. Using `unwrap_unchecked()` is
309334
// safe here as we have full control over ZendMM with no neighboring extensions.
310335
let heap = tls_zend_mm_state_get!(heap).unwrap_unchecked();
336+
#[cfg(php_debug)]
337+
return zend::_zend_mm_alloc(heap, len, ptr::null(), 0, ptr::null(), 0);
338+
#[cfg(not(php_debug))]
311339
zend::_zend_mm_alloc(heap, len)
312340
}
313341

314342
/// This function exists because when calling `zend_mm_set_custom_handlers()`,
315343
/// you need to pass a pointer to a `free()` function as well, otherwise your
316344
/// custom handlers won't be installed. We cannot just point to the original
317345
/// `zend::_zend_mm_free()` as the function definitions differ.
346+
#[cfg(not(php_debug))]
318347
unsafe extern "C" fn alloc_prof_free(ptr: *mut c_void) {
348+
alloc_prof_free_impl(ptr);
349+
}
350+
351+
#[cfg(php_debug)]
352+
unsafe extern "C" fn alloc_prof_free(
353+
ptr: *mut c_void,
354+
_file: *const c_char,
355+
_line: c_uint,
356+
_orig_file: *const c_char,
357+
_orig_line: c_uint,
358+
) {
359+
alloc_prof_free_impl(ptr);
360+
}
361+
362+
#[inline(always)]
363+
unsafe fn alloc_prof_free_impl(ptr: *mut c_void) {
319364
tls_zend_mm_state_get!(free)(ptr);
320365
}
321366

@@ -327,6 +372,11 @@ unsafe fn alloc_prof_prev_free(ptr: *mut c_void) {
327372
// neighboring extension could misbehave. If that happens, we want a proper
328373
// panic with backtrace for debugging rather than undefined behavior.
329374
let free = tls_zend_mm_state_get!(prev_custom_mm_free).unwrap();
375+
#[cfg(php_debug)]
376+
{
377+
return free(ptr, core::ptr::null(), 0, core::ptr::null(), 0);
378+
}
379+
#[cfg(not(php_debug))]
330380
free(ptr)
331381
}
332382

@@ -335,10 +385,31 @@ unsafe fn alloc_prof_orig_free(ptr: *mut c_void) {
335385
// handlers only point to this function after successful init. Using `unwrap_unchecked()` is
336386
// safe here as we have full control over ZendMM with no neighboring extensions.
337387
let heap = tls_zend_mm_state_get!(heap).unwrap_unchecked();
388+
#[cfg(php_debug)]
389+
return zend::_zend_mm_free(heap, ptr, core::ptr::null(), 0, core::ptr::null(), 0);
390+
#[cfg(not(php_debug))]
338391
zend::_zend_mm_free(heap, ptr);
339392
}
340393

394+
#[cfg(not(php_debug))]
341395
unsafe extern "C" fn alloc_prof_realloc(prev_ptr: *mut c_void, len: size_t) -> *mut c_void {
396+
alloc_prof_realloc_impl(prev_ptr, len)
397+
}
398+
399+
#[cfg(php_debug)]
400+
unsafe extern "C" fn alloc_prof_realloc(
401+
prev_ptr: *mut c_void,
402+
len: size_t,
403+
_file: *const c_char,
404+
_line: c_uint,
405+
_orig_file: *const c_char,
406+
_orig_line: c_uint,
407+
) -> *mut c_void {
408+
alloc_prof_realloc_impl(prev_ptr, len)
409+
}
410+
411+
#[inline(always)]
412+
unsafe fn alloc_prof_realloc_impl(prev_ptr: *mut c_void, len: size_t) -> *mut c_void {
342413
#[cfg(feature = "debug_stats")]
343414
ALLOCATION_PROFILING_COUNT.fetch_add(1, Relaxed);
344415
#[cfg(feature = "debug_stats")]
@@ -367,6 +438,11 @@ unsafe fn alloc_prof_prev_realloc(prev_ptr: *mut c_void, len: size_t) -> *mut c_
367438
// neighboring extension could misbehave. If that happens, we want a proper
368439
// panic with backtrace for debugging rather than undefined behavior.
369440
let realloc = tls_zend_mm_state_get!(prev_custom_mm_realloc).unwrap();
441+
#[cfg(php_debug)]
442+
{
443+
return realloc(prev_ptr, len, ptr::null(), 0, ptr::null(), 0);
444+
}
445+
#[cfg(not(php_debug))]
370446
realloc(prev_ptr, len)
371447
}
372448

@@ -375,6 +451,9 @@ unsafe fn alloc_prof_orig_realloc(prev_ptr: *mut c_void, len: size_t) -> *mut c_
375451
// handlers only point to this function after successful init. Using `unwrap_unchecked()` is
376452
// safe here as we have full control over ZendMM with no neighboring extensions.
377453
let heap = tls_zend_mm_state_get!(heap).unwrap_unchecked();
454+
#[cfg(php_debug)]
455+
return zend::_zend_mm_realloc(heap, prev_ptr, len, ptr::null(), 0, ptr::null(), 0);
456+
#[cfg(not(php_debug))]
378457
zend::_zend_mm_realloc(heap, prev_ptr, len)
379458
}
380459

profiling/src/allocation/allocation_le83.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,9 @@ unsafe fn alloc_prof_orig_alloc(len: size_t) -> *mut c_void {
320320
let heap = tls_zend_mm_state_get!(heap).unwrap_unchecked();
321321
let (prepare, restore) = tls_zend_mm_state_get!(prepare_restore_zend_heap);
322322
let custom_heap = prepare(heap);
323+
#[cfg(php_debug)]
324+
let ptr: *mut c_void = zend::_zend_mm_alloc(heap, len, ptr::null(), 0, ptr::null(), 0);
325+
#[cfg(not(php_debug))]
323326
let ptr: *mut c_void = zend::_zend_mm_alloc(heap, len);
324327
restore(heap, custom_heap);
325328
ptr
@@ -345,6 +348,9 @@ unsafe fn alloc_prof_orig_free(ptr: *mut c_void) {
345348
// Safety: `ZEND_MM_STATE.heap` will be initialised in `alloc_prof_rinit()` and custom ZendMM
346349
// handlers are only installed and pointing to this function if initialization was succesful.
347350
let heap = tls_zend_mm_state_get!(heap).unwrap_unchecked();
351+
#[cfg(php_debug)]
352+
zend::_zend_mm_free(heap, ptr, core::ptr::null(), 0, core::ptr::null(), 0);
353+
#[cfg(not(php_debug))]
348354
zend::_zend_mm_free(heap, ptr);
349355
}
350356

@@ -383,6 +389,10 @@ unsafe fn alloc_prof_orig_realloc(prev_ptr: *mut c_void, len: size_t) -> *mut c_
383389
let heap = tls_zend_mm_state_get!(heap).unwrap_unchecked();
384390
let (prepare, restore) = tls_zend_mm_state_get!(prepare_restore_zend_heap);
385391
let custom_heap = prepare(heap);
392+
#[cfg(php_debug)]
393+
let ptr: *mut c_void =
394+
zend::_zend_mm_realloc(heap, prev_ptr, len, ptr::null(), 0, ptr::null(), 0);
395+
#[cfg(not(php_debug))]
386396
let ptr: *mut c_void = zend::_zend_mm_realloc(heap, prev_ptr, len);
387397
restore(heap, custom_heap);
388398
ptr

profiling/src/bindings/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,27 @@ pub type VmZendThrowExceptionHook = unsafe extern "C" fn(*mut zval);
4040
#[cfg(php8)]
4141
pub type VmZendThrowExceptionHook = unsafe extern "C" fn(*mut zend_object);
4242

43+
#[cfg(not(all(php_debug, php_zend_mm_set_custom_handlers_ex)))]
4344
pub type VmMmCustomAllocFn = unsafe extern "C" fn(size_t) -> *mut c_void;
45+
#[cfg(all(php_debug, php_zend_mm_set_custom_handlers_ex))]
46+
pub type VmMmCustomAllocFn =
47+
unsafe extern "C" fn(size_t, *const c_char, c_uint, *const c_char, c_uint) -> *mut c_void;
48+
#[cfg(not(all(php_debug, php_zend_mm_set_custom_handlers_ex)))]
4449
pub type VmMmCustomReallocFn = unsafe extern "C" fn(*mut c_void, size_t) -> *mut c_void;
50+
#[cfg(all(php_debug, php_zend_mm_set_custom_handlers_ex))]
51+
pub type VmMmCustomReallocFn = unsafe extern "C" fn(
52+
*mut c_void,
53+
size_t,
54+
*const c_char,
55+
c_uint,
56+
*const c_char,
57+
c_uint,
58+
) -> *mut c_void;
59+
#[cfg(not(all(php_debug, php_zend_mm_set_custom_handlers_ex)))]
4560
pub type VmMmCustomFreeFn = unsafe extern "C" fn(*mut c_void);
61+
#[cfg(all(php_debug, php_zend_mm_set_custom_handlers_ex))]
62+
pub type VmMmCustomFreeFn =
63+
unsafe extern "C" fn(*mut c_void, *const c_char, c_uint, *const c_char, c_uint);
4664
#[cfg(php_zend_mm_set_custom_handlers_ex)]
4765
pub type VmMmCustomGcFn = unsafe extern "C" fn() -> size_t;
4866
#[cfg(php_zend_mm_set_custom_handlers_ex)]

profiling/src/php_ffi.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,9 +229,9 @@ void ddog_php_prof_copy_long_into_zval(zval *dest, long num) {
229229
}
230230

231231
void ddog_php_prof_zend_mm_set_custom_handlers(zend_mm_heap *heap,
232-
void* (*_malloc)(size_t),
233-
void (*_free)(void*),
234-
void* (*_realloc)(void*, size_t)) {
232+
ddog_php_prof_zend_mm_malloc _malloc,
233+
ddog_php_prof_zend_mm_free _free,
234+
ddog_php_prof_zend_mm_realloc _realloc) {
235235
zend_mm_set_custom_handlers(heap, _malloc, _free, _realloc);
236236
#if PHP_VERSION_ID < 70300
237237
if (!_malloc && !_free && !_realloc) {

0 commit comments

Comments
 (0)