Add xdebug integration with slow query breakpoint detection#21
Conversation
Adds two key features to the MariaDB profiler:
1. Query execution time measurement: All mysqlnd hooks (query,
send_query, prepare, execute) now measure wall-clock duration
using gettimeofday. Duration is recorded in both JSONL logs
(as "duration_ms" field) and raw logs (as [X.XXXms] column).
2. xdebug slow query breakpoint: When xdebug is loaded with
step-debug mode active, queries exceeding the configured
threshold automatically trigger xdebug_break(), pausing the
debugger at the exact point of a slow query for interactive
inspection.
New INI setting:
mariadb_profiler.xdebug_break_threshold = 0
Threshold in seconds (e.g. 0.5). Set to 0 to disable.
PHP_INI_ALL so it can be changed per-request via ini_set().
New files:
profiler_xdebug.c - xdebug detection (module registry + mode
check) with per-request caching, and xdebug_break() caller
profiler_xdebug.h - public API declarations
Compatible with PHP 5.3-8.4+ and xdebug 2.x/3.x.
https://claude.ai/code/session_01Ku8336fyCEdnwAVszkVmFS
WalkthroughMariaDBプロファイラーにXDebug統合とクエリ実行時間計測を追加。ビルド設定に新ソースを追加し、閾値付きのXDebugブレーク呼び出し、ログへのduration_ms伝搬、リクエスト単位のXDebug検出/リセットを導入します。 Changes
Sequence Diagram(s)sequenceDiagram
participant PHP as PHP Engine
participant Profiler as Profiler\n(mysqlnd_plugin)
participant Logger as Logging System
participant XDebug as XDebug Extension
PHP->>Profiler: Execute query
Profiler->>Profiler: Measure start (microtime)
Profiler->>PHP: Forward query to DB / mysqlnd
PHP-->>Profiler: Query result
Profiler->>Profiler: Measure end, compute duration_ms
Profiler->>XDebug: Check profiler_xdebug_is_debugger_active()
XDebug-->>Profiler: active / inactive
Profiler->>Profiler: Compare duration_ms to xdebug_break_threshold
alt threshold exceeded & debugger active
Profiler->>XDebug: profiler_xdebug_break()
XDebug->>PHP: Break execution
end
Profiler->>Logger: Log query with duration_ms
PHP->>Profiler: Request shutdown
Profiler->>XDebug: profiler_xdebug_request_shutdown()
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 509c25971a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| mode_val = zend_ini_str("xdebug.mode", sizeof("xdebug.mode") - 1, 0); | ||
| if (mode_val && Z_TYPE_P(mode_val) == IS_STRING) { | ||
| /* xdebug 3.x: check for "debug" in the mode string */ | ||
| if (strstr(Z_STRVAL_P(mode_val), "debug") != NULL) { |
There was a problem hiding this comment.
Use zend_string API when reading xdebug.mode
In PHP 8.3+ zend_ini_str() returns a zend_string*, but this code stores it as zval* and then applies Z_TYPE_P/Z_STRVAL_P, which reads the wrong memory layout. When xdebug.mode is present, this can mis-detect debug mode and may dereference invalid data while checking for "debug", causing unstable behavior in requests that execute slow-query checks.
Useful? React with 👍 / 👎.
| } else if (result != PASS && profiler_job_is_any_active()) { | ||
| /* Failed prepare has no subsequent execute(); log immediately with err status */ | ||
| profiler_log_query(query, query_len, "err"); | ||
| profiler_log_query(query, query_len, "err", duration_ms); | ||
| profiler_check_slow_query(duration_ms); | ||
| } |
There was a problem hiding this comment.
Run slow-query check for successful prepare on PHP 7+
In the PHP 7+ profiler_stmt::prepare() path, profiler_check_slow_query(duration_ms) is only called inside the result != PASS branch, so a successful but slow prepare() never triggers the configured xdebug breakpoint even though duration is measured. This drops slow-prepare detection on modern PHP versions and is inconsistent with the PHP 5 branch, which performs the check unconditionally.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (2)
ext/mariadb_profiler/profiler_xdebug.c (1)
107-107: 未使用変数retval_ptr。
retval_ptrは宣言されていますが、一度も使用されていません。パイプライン警告こそ出ていませんが、コードの清潔さのために削除してください。♻️ 修正案
`#else` - zval *retval_ptr = NULL; zval *fname; zval retval;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ext/mariadb_profiler/profiler_xdebug.c` at line 107, Remove the unused local variable retval_ptr from profiler_xdebug.c: locate the declaration "zval *retval_ptr = NULL;" (symbol retval_ptr) and delete it; ensure there are no remaining references to retval_ptr in the surrounding function so the build and behavior remain unchanged.ext/mariadb_profiler/php_mariadb_profiler.h (1)
128-131: xdebug関数の宣言がprofiler_xdebug.hと重複しています。
profiler_xdebug_is_debugger_active、profiler_xdebug_break、profiler_xdebug_request_shutdownの宣言はprofiler_xdebug.h(Lines 19, 29, 35)にも存在します。シグネチャが乖離するメンテナンスリスクがあります。このヘッダーから削除して
#include "profiler_xdebug.h"に委譲するか、一箇所にまとめることを検討してください。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ext/mariadb_profiler/php_mariadb_profiler.h` around lines 128 - 131, The three xdebug function declarations profiler_xdebug_is_debugger_active, profiler_xdebug_break, and profiler_xdebug_request_shutdown are duplicated here and in profiler_xdebug.h; remove these declarations from php_mariadb_profiler.h and delegate to the single authoritative header by adding `#include` "profiler_xdebug.h" (or alternatively move the declarations into php_mariadb_profiler.h and update profiler_xdebug.h to include it) so the symbols are declared in one place to avoid signature drift.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@ext/mariadb_profiler/profiler_log.c`:
- Around line 278-280: Add a nullable, serializable durationMs property to the
JetBrains plugin's QueryEntry data class so the JSONL "duration_ms" field is
preserved; specifically, in QueryEntry declare something like
`@SerialName`("duration_ms") val durationMs: Double? = null (or equivalent
nullable numeric type) so missing fields deserialize safely and present values
are captured.
In `@ext/mariadb_profiler/profiler_mysqlnd_plugin.c`:
- Around line 19-30: profiler_get_microtime currently calls gettimeofday
unconditionally which breaks Windows builds; add a Windows-compatible
implementation (or a compatibility shim) and use it from profiler_get_microtime,
profiler_log_get_timestamp, and profiler_log_get_microtime. Create a small
cross-platform utility (e.g., profiler_time.h/.c) that defines a portable
function (e.g., profiler_gettimeofday or profiler_get_microtime_impl) which uses
gettimeofday on POSIX and QueryPerformanceCounter/QueryPerformanceFrequency or
Windows equivalents on PHP_WIN32, update profiler_mysqlnd_plugin.c,
profiler_log.c to include and call that portable function, and guard includes
with `#ifdef` PHP_WIN32 so builds succeed on both platforms.
In `@ext/mariadb_profiler/profiler_xdebug.c`:
- Line 24: The global static variable xdebug_detected causes data races in ZTS
builds; move it into the module globals (PROFILER_G) so each thread has its own
copy: add an int xdebug_detected (0=unchecked,1=active,-1=inactive) to the
global struct in php_mariadb_profiler.h, replace references to the file-scope
xdebug_detected in profiler_xdebug_is_debugger_active() and
profiler_xdebug_request_shutdown() (and any other uses) to use
PROFILER_G->xdebug_detected (or the appropriate macro accessor), and remove the
static declaration from profiler_xdebug.c to avoid cross-thread sharing.
- Around line 30-77: The code in profiler_xdebug_detect incorrectly treats
zend_ini_str() as returning a zval*; replace that usage with zend_ini_string()
which returns a char* on PHP 7+, change the local variable mode_val from zval *
to char *mode_val, check for NULL and use strstr(mode_val, "debug") for the
"debug" check, and ensure you release the returned string (efree/ appropriate
API) after use; keep the existing fallback that checks for xdebug_break via
zend_string and EG(function_table) in the same function.
---
Nitpick comments:
In `@ext/mariadb_profiler/php_mariadb_profiler.h`:
- Around line 128-131: The three xdebug function declarations
profiler_xdebug_is_debugger_active, profiler_xdebug_break, and
profiler_xdebug_request_shutdown are duplicated here and in profiler_xdebug.h;
remove these declarations from php_mariadb_profiler.h and delegate to the single
authoritative header by adding `#include` "profiler_xdebug.h" (or alternatively
move the declarations into php_mariadb_profiler.h and update profiler_xdebug.h
to include it) so the symbols are declared in one place to avoid signature
drift.
In `@ext/mariadb_profiler/profiler_xdebug.c`:
- Line 107: Remove the unused local variable retval_ptr from profiler_xdebug.c:
locate the declaration "zval *retval_ptr = NULL;" (symbol retval_ptr) and delete
it; ensure there are no remaining references to retval_ptr in the surrounding
function so the build and behavior remain unchanged.
| if (duration_ms >= 0) { | ||
| fprintf(fp, ",\"duration_ms\":%.3f", duration_ms); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for QueryEntry.kt and check if it contains duration_ms or durationMs
fd "QueryEntry.kt" -x grep -n "duration" {} \; || echo "File not found or no duration references"Repository: 39ff/php-ext-mariadb-salvage
Length of output: 112
🏁 Script executed:
#!/bin/bash
# Also check the directory structure to understand the layout
find . -name "*.kt" -type f | head -20Repository: 39ff/php-ext-mariadb-salvage
Length of output: 1837
🏁 Script executed:
#!/bin/bash
# Check the profiler_log.c file around lines 278-280
if [ -f "ext/mariadb_profiler/profiler_log.c" ]; then
sed -n '275,285p' ext/mariadb_profiler/profiler_log.c
else
echo "File not found"
fiRepository: 39ff/php-ext-mariadb-salvage
Length of output: 309
🏁 Script executed:
#!/bin/bash
# Read the QueryEntry.kt file to see its current structure
cat -n ./jetbrains-plugin/src/main/kotlin/com/mariadbprofiler/plugin/model/QueryEntry.ktRepository: 39ff/php-ext-mariadb-salvage
Length of output: 9818
🏁 Script executed:
#!/bin/bash
# Check the git status or recent changes to see if QueryEntry.kt was supposed to be modified
git log --oneline -20Repository: 39ff/php-ext-mariadb-salvage
Length of output: 143
🏁 Script executed:
#!/bin/bash
# Search for any recent mentions of durationMs or duration_ms in the codebase
rg "durationMs|duration_ms" --max-count=20Repository: 39ff/php-ext-mariadb-salvage
Length of output: 4438
LGTM!
JSONL出力の duration_ms フィールドは計測済みの場合のみ出力され、%.3f フォーマットでミリ秒精度を保持しています。ただし、JetBrains プラグイン側の QueryEntry データクラスに durationMs フィールド(@SerialName("duration_ms") 付き)の追加がまだ必要です。このフィールドなしではJSON逆シリアル化時に値が失われます。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@ext/mariadb_profiler/profiler_log.c` around lines 278 - 280, Add a nullable,
serializable durationMs property to the JetBrains plugin's QueryEntry data class
so the JSONL "duration_ms" field is preserved; specifically, in QueryEntry
declare something like `@SerialName`("duration_ms") val durationMs: Double? = null
(or equivalent nullable numeric type) so missing fields deserialize safely and
present values are captured.
| #ifndef PHP_WIN32 | ||
| # include <sys/time.h> | ||
| #endif | ||
|
|
||
| /* {{{ profiler_get_microtime | ||
| * Get current time in seconds with microsecond precision. */ | ||
| static double profiler_get_microtime(void) | ||
| { | ||
| struct timeval tv; | ||
| gettimeofday(&tv, NULL); | ||
| return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; | ||
| } |
There was a problem hiding this comment.
Windowsビルドで gettimeofday() が未定義になります。
<sys/time.h> のインクルードは #ifndef PHP_WIN32 でガードされていますが、profiler_get_microtime() は gettimeofday() を無条件に呼び出しています。Windows には gettimeofday() が存在しないため、Windowsビルドで警告/エラーが発生します(パイプラインの警告でも確認済み)。
Windows互換の実装を追加するか、互換レイヤーを使用してください。
🔧 Windows互換の実装案
`#ifndef` PHP_WIN32
# include <sys/time.h>
`#endif`
+#ifdef PHP_WIN32
+# include <windows.h>
+static int profiler_win_gettimeofday(struct timeval *tv)
+{
+ FILETIME ft;
+ unsigned __int64 tmpres = 0;
+ GetSystemTimeAsFileTime(&ft);
+ tmpres |= ft.dwHighDateTime;
+ tmpres <<= 32;
+ tmpres |= ft.dwLowDateTime;
+ /* FILETIME epoch is 1601-01-01; convert to Unix epoch */
+ tmpres -= 116444736000000000ULL;
+ tmpres /= 10; /* to microseconds */
+ tv->tv_sec = (long)(tmpres / 1000000UL);
+ tv->tv_usec = (long)(tmpres % 1000000UL);
+ return 0;
+}
+# define gettimeofday(tv, tz) profiler_win_gettimeofday(tv)
+#endif
+
/* {{{ profiler_get_microtimeなお、同じ問題は profiler_log.c の profiler_log_get_timestamp() と profiler_log_get_microtime() にも存在します。共通のユーティリティヘッダーに gettimeofday の互換実装をまとめることを推奨します。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@ext/mariadb_profiler/profiler_mysqlnd_plugin.c` around lines 19 - 30,
profiler_get_microtime currently calls gettimeofday unconditionally which breaks
Windows builds; add a Windows-compatible implementation (or a compatibility
shim) and use it from profiler_get_microtime, profiler_log_get_timestamp, and
profiler_log_get_microtime. Create a small cross-platform utility (e.g.,
profiler_time.h/.c) that defines a portable function (e.g.,
profiler_gettimeofday or profiler_get_microtime_impl) which uses gettimeofday on
POSIX and QueryPerformanceCounter/QueryPerformanceFrequency or Windows
equivalents on PHP_WIN32, update profiler_mysqlnd_plugin.c, profiler_log.c to
include and call that portable function, and guard includes with `#ifdef`
PHP_WIN32 so builds succeed on both platforms.
| * 1 = xdebug step-debug is available | ||
| * -1 = xdebug not available / no step-debug | ||
| */ | ||
| static int xdebug_detected = 0; |
There was a problem hiding this comment.
xdebug_detected はZTS(スレッドセーフ)ビルドでデータ競合が発生します。
static int xdebug_detected はファイルスコープのグローバル変数であり、ZTSビルドでは全スレッドで共有されます。複数のリクエストが並行して処理される場合、profiler_xdebug_is_debugger_active() での読み書きと profiler_xdebug_request_shutdown() でのリセットが競合し、不正な値を読み取る可能性があります。
モジュールグローバル(PROFILER_G)に移動させるべきです。
🔧 修正案: モジュールグローバルに移動
php_mariadb_profiler.h のグローバル構造体に追加:
int xdebug_detected; /* 0=unchecked, 1=active, -1=inactive */profiler_xdebug.c での変更:
-static int xdebug_detected = 0;
-
/* ... */
int profiler_xdebug_is_debugger_active(void)
{
+ TSRMLS_FETCH();
- if (xdebug_detected == 0) {
- xdebug_detected = profiler_xdebug_detect() ? 1 : -1;
+ if (PROFILER_G(xdebug_detected) == 0) {
+ PROFILER_G(xdebug_detected) = profiler_xdebug_detect() ? 1 : -1;
}
- return (xdebug_detected == 1);
+ return (PROFILER_G(xdebug_detected) == 1);
}
void profiler_xdebug_request_shutdown(void)
{
- xdebug_detected = 0;
+ TSRMLS_FETCH();
+ PROFILER_G(xdebug_detected) = 0;
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@ext/mariadb_profiler/profiler_xdebug.c` at line 24, The global static
variable xdebug_detected causes data races in ZTS builds; move it into the
module globals (PROFILER_G) so each thread has its own copy: add an int
xdebug_detected (0=unchecked,1=active,-1=inactive) to the global struct in
php_mariadb_profiler.h, replace references to the file-scope xdebug_detected in
profiler_xdebug_is_debugger_active() and profiler_xdebug_request_shutdown() (and
any other uses) to use PROFILER_G->xdebug_detected (or the appropriate macro
accessor), and remove the static declaration from profiler_xdebug.c to avoid
cross-thread sharing.
zend_ini_str() does not exist in any PHP version. The correct API is zend_ini_string() which returns char* (NULL if setting absent). Also removes an unused variable in the PHP 5.x code path. https://claude.ai/code/session_01Ku8336fyCEdnwAVszkVmFS
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1fa4ce8a7c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (strstr(mode_str, "debug") != NULL) { | ||
| return 1; |
There was a problem hiding this comment.
Verify debugger session before treating debug mode as active
This branch returns active as soon as xdebug.mode contains debug, but that only means step-debug functionality is enabled, not that an IDE session is connected. In environments with xdebug.mode=debug and no attached client (for example start_with_request=trigger with no trigger), slow queries will still call xdebug_break(), which repeatedly attempts to connect and emits "Could not connect to debugging client" warnings, adding avoidable latency and log noise.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
🧹 Nitpick comments (2)
ext/mariadb_profiler/profiler_xdebug.c (2)
103-103: PHP 7.1 以降、call_user_functionのfunction_table引数は使用されず、NULLを渡すべきですPHP 7.1.0 以降、
call_user_functionのfunction_table引数は使用されず、常にNULLを渡すべきとされています。EG(function_table)を渡してもエラーにはなりませんが、PHP 7.1+ では無視されます。なお、このブランチはPHP_VERSION_ID >= 70000で囲まれており、PHP 7.0 では引数が使用されていた可能性があるため、厳密には7.1以降でのみ適用される点に注意してください。♻️ 変更案
- if (call_user_function(EG(function_table), NULL, &fname, &retval, 0, NULL) == SUCCESS) { + if (call_user_function(NULL, NULL, &fname, &retval, 0, NULL) == SUCCESS) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ext/mariadb_profiler/profiler_xdebug.c` at line 103, The call to call_user_function currently passes EG(function_table) but per PHP 7.1+ the function_table argument must be NULL; update the invocation in profiler_xdebug.c to pass NULL instead of EG(function_table) and adjust the surrounding preprocessor guards so this change applies only for PHP_VERSION_ID >= 70100 (keep the original behavior for older PHP versions where function_table was used); the symbol to update is the call_user_function(...) call that currently uses EG(function_table).
103-103: PHP 8.0 以降ではcall_user_functionの第1引数function_tableは無視されますPHP 8.0+では、
call_user_function()のfunction_tableパラメータは使用されず、NULLを渡すことが推奨されます。一方、PHP 7.x ではNULLを渡すと既定のグローバル関数テーブルへのフォールバックが発生します。このコードは PHP 5.x と PHP 7+ の両方に対応しているため、
NULLは両方のバージョンで動作し、PHP 8.0+ ではより明確で将来互換性の高い記述となります。♻️ 変更案
- if (call_user_function(EG(function_table), NULL, &fname, &retval, 0, NULL) == SUCCESS) { + if (call_user_function(NULL, NULL, &fname, &retval, 0, NULL) == SUCCESS) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ext/mariadb_profiler/profiler_xdebug.c` at line 103, The call to call_user_function currently passes EG(function_table) which is ignored on PHP 8+; update the invocation to pass NULL instead so it works correctly on PHP 8+ while still falling back on PHP 7.x/5.x behavior—locate the call_user_function usage that passes EG(function_table) (the call referencing fname and retval) and replace the first argument with NULL.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@ext/mariadb_profiler/profiler_xdebug.c`:
- Around line 126-130: profiler_xdebug_request_shutdown currently resets the
global xdebug_detected directly which causes ZTS data races; replace the direct
write with the thread-safe PHP extension globals accessor by setting
PROFILER_G(xdebug_detected) = 0 inside profiler_xdebug_request_shutdown (and
remove/replace any other direct uses of the xdebug_detected global), ensuring
you include the proper header/externs so PROFILER_G is available and maintain
consistent use of PROFILER_G(xdebug_detected) across functions that read or
write this flag.
- Line 24: グローバルな static int xdebug_detected は
ZTS(マルチスレッド)ビルドでスレッド間共有されデータ競合を起こすため、スレッドローカル化して競合を防いでください: ファイル内の宣言を static int
xdebug_detected = 0; から ZEND_TLS int xdebug_detected = 0;
のようにスレッドローカルストレージに置き換え(またはプロジェクトで使っている PHP/TSSM の TLS
マクロに合わせて適切なマクロを使用)し、profiler_xdebug_is_debugger_active() と
profiler_xdebug_request_shutdown() は既存の参照をそのまま使って TLS 変数を読み書きするようにしてください(もし TLS
が使えない環境があるなら代替として mutex/スピンロックでアクセスを保護してください)。
---
Nitpick comments:
In `@ext/mariadb_profiler/profiler_xdebug.c`:
- Line 103: The call to call_user_function currently passes EG(function_table)
but per PHP 7.1+ the function_table argument must be NULL; update the invocation
in profiler_xdebug.c to pass NULL instead of EG(function_table) and adjust the
surrounding preprocessor guards so this change applies only for PHP_VERSION_ID
>= 70100 (keep the original behavior for older PHP versions where function_table
was used); the symbol to update is the call_user_function(...) call that
currently uses EG(function_table).
- Line 103: The call to call_user_function currently passes EG(function_table)
which is ignored on PHP 8+; update the invocation to pass NULL instead so it
works correctly on PHP 8+ while still falling back on PHP 7.x/5.x
behavior—locate the call_user_function usage that passes EG(function_table) (the
call referencing fname and retval) and replace the first argument with NULL.
Summary
This PR adds xdebug integration to the MariaDB Query Profiler, enabling automatic debugger breakpoints when queries exceed a configurable duration threshold. This allows developers to interactively inspect slow queries in their IDE debugger.
Key Changes
New xdebug integration module (
profiler_xdebug.candprofiler_xdebug.h):xdebug_break()invocation via PHP function tableQuery duration measurement:
profiler_get_microtime()) to all query execution pathsquery(),send_query(),prepare(), andexecute()methodsSlow query detection:
profiler_check_slow_query()function checks if query duration exceeds thresholdxdebug_break()when threshold is exceeded and debugger is activeConfiguration:
mariadb_profiler.xdebug_break_threshold(in seconds, default 0 = disabled)Logging enhancements:
duration_msparameter[%.3fms]formatduration_msfieldBuild system updates:
config.m4andconfig.w32to include new source filesImplementation Details
xdebug.modesettingxdebug_breakfunction existence check for edge casesgettimeofday()for cross-platform compatibilityhttps://claude.ai/code/session_01Ku8336fyCEdnwAVszkVmFS
Summary by CodeRabbit