Conversation
|
✨ Fix all issues with BitsAI or with Cursor
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3670 +/- ##
==========================================
+ Coverage 62.39% 62.40% +0.01%
==========================================
Files 142 142
Lines 13586 13586
Branches 1775 1775
==========================================
+ Hits 8477 8479 +2
+ Misses 4304 4301 -3
- Partials 805 806 +1 see 1 file with indirect coverage changes Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
Benchmarks [ tracer ]Benchmark execution time: 2026-03-13 16:43:19 Comparing candidate commit a12cb93 in PR branch Found 5 performance improvements and 0 performance regressions! Performance is the same for 189 metrics, 0 unstable metrics. scenario:EmptyFileBench/benchEmptyFileDdprof-opcache
scenario:SymfonyBench/benchSymfonyBaseline-opcache
scenario:SymfonyBench/benchSymfonyOverhead
scenario:TraceSerializationBench/benchSerializeTrace
scenario:TraceSerializationBench/benchSerializeTrace-opcache
|
5a292ea to
e26db1d
Compare
| (void)in_request; | ||
| #endif | ||
|
|
||
| if (in_request) { |
There was a problem hiding this comment.
We only need it for FPM, right? So let's add a sapi_module check here?
Saving some minor time on CLI scripts.
There was a problem hiding this comment.
I'm not sure what litespeed does, and IIRC we did have a customer using it. How about a not-CLI SAPI check instead? That way web SAPIs stay consistent, but it's skipped on CLI where it's unnecessary.
There was a problem hiding this comment.
I think it's reasonably clearer now. Patch is smaller, at least xD
There was a problem hiding this comment.
A non cli sapi check would be fine by me too. Just let's not eat the cost for cli.
| if (!cached->ptr) return false; | ||
| if (cached->len >= buf.len) return false; | ||
|
|
||
| memcpy(buf.ptr, cached->ptr, cached->len + 1); |
There was a problem hiding this comment.
There's not really an intrinsic need to copy. The copying in zai_getenv_ex is also unnecessary, but here we very clearly don't need it (but yeah, you'll have to duplicate branches then).
I'd personally return a simple zai_str instead of zai_env_buffer.
| typedef struct { | ||
| // ptr == NULL means env var was unset at MINIT. | ||
| // ptr != NULL with len == 0 means env var was set to an empty string. | ||
| char *ptr; | ||
| size_t len; | ||
| } zai_config_cached_env_value; | ||
|
|
||
| static zai_config_cached_env_value zai_config_cached_env_values[ZAI_CONFIG_ENTRIES_COUNT_MAX][ZAI_CONFIG_NAMES_COUNT_MAX]; |
There was a problem hiding this comment.
| typedef struct { | |
| // ptr == NULL means env var was unset at MINIT. | |
| // ptr != NULL with len == 0 means env var was set to an empty string. | |
| char *ptr; | |
| size_t len; | |
| } zai_config_cached_env_value; | |
| static zai_config_cached_env_value zai_config_cached_env_values[ZAI_CONFIG_ENTRIES_COUNT_MAX][ZAI_CONFIG_NAMES_COUNT_MAX]; | |
| static zai_string zai_config_cached_env_values[ZAI_CONFIG_ENTRIES_COUNT_MAX][ZAI_CONFIG_NAMES_COUNT_MAX]; |
Simply?
There was a problem hiding this comment.
zai_string isn't supposed to have a null pointer, right? IIRC that's why I did this. This distinguishes between unset and null. But there is a zai_option_str, and I think using a zai_option_str except actually owning it is better than putting null into zai_string. So I'll experiment with that.
58b7933 to
091c262
Compare
| // We want to explicitly allow pre-RINIT access to env vars here. So that callers can have an early view at config. | ||
| // But in general allmost all configurations shall only be accessed after first RINIT. (the trivial getter will | ||
| return zai_getenv_ex(name, buf, true) == ZAI_ENV_SUCCESS; | ||
| if (zai_getenv(name, buf) == ZAI_ENV_SUCCESS) { |
There was a problem hiding this comment.
| if (zai_getenv(name, buf) == ZAI_ENV_SUCCESS) { | |
| if (zai_getenv_ex(name, buf, false, false) == ZAI_ENV_SUCCESS) { |
? Because you defined zai_getenv() as always accessing the process env.
There was a problem hiding this comment.
zai_config_find_and_set_value is called only by zai_config_first_time_rinit. At this time, we do want to get the process environment, yes?
29395b8 to
5890581
Compare
In rinit, calling system getenv when a SAPI env var isn't found is slow enough it shows up in profiles. glibc's getenv does a linear scan on the environ and does strncmp on the members, so we can definitely do better. We save it in minit so it's available for SYSTEM_INI variables and again on the first request. This is also arguably more correct: system environment variables map to a system INI setting, which shouldn't change at runtime.
54de6fc to
41fc47c
Compare
Replace zai_getenv_ex/zai_getenv with two focused functions: - zai_sapi_getenv: borrows value from the SAPI environment - zai_sys_getenv: borrows value from the process environment Both return zai_option_str instead of writing into a caller-supplied buffer, eliminating the ZAI_ENV_BUFFER_* error codes and the scratch buffer indirection throughout callers. Update config, config_ini, and otel_config to use the new API. Rename zai_config_get_cached_env_value to zai_config_sys_getenv_cached to return zai_option_str directly. Add ZAI_OPTION_STRL macro and zai_option_str_eq helper to string.h. Remove now-obsolete error.cc env tests.
| // +1 to hold the null terminator. | ||
| char *dst = pemalloc(len + 1, 1); | ||
| // +1 to include the null terminator in the copy. | ||
| memcpy(dst, val.ptr, len + 1); |
There was a problem hiding this comment.
| // +1 to hold the null terminator. | |
| char *dst = pemalloc(len + 1, 1); | |
| // +1 to include the null terminator in the copy. | |
| memcpy(dst, val.ptr, len + 1); | |
| char *dst = zend_strndup(val.ptr, len); |
Background
In request initialization aka rinit/activate, calling the system
getenvwhen a SAPI env var isn't found is slow enough it shows up in profiles:Note that glibc's
getenvdoes a linear scan on the environ and doesstrncmpon the members, so we can definitely do better.Description
Caches libc's
getenvin minit and again in first rinit. Note that php-fpm'senvdirective actually changes the system env var, it doesn't include it in the fastcgi environment. This change is also more correct: system environment variables map to a system INI setting, which shouldn't change at runtime, so if they do, we shouldn't really respect it.Here's an example diff from the profiling comparison view:
Reviewer checklist