deepseek-ai / deepseek-ai/DeepEP
`EP_BUFFER_DEBUG=0` enables Python-side debug output because the env var is tested as a raw string
- Dominant language
- Cuda
- Stars
- 10.1k
- Forks
- 1.4k
- Avg merge
- 4d 1h
- Merged PRs (30d)
- 2
Description
## Summary
`EP_BUFFER_DEBUG=0` — the value the README documents as "off" — turns the **Python-side** debug output **on**, while the C++ side correctly stays off. The Python code tests the raw environment string for truthiness, and the string `'0'` is truthy in Python.
## Details
The README documents the flag as a `0`/`1` toggle, defaulting to `0`:
> - `EP_BUFFER_DEBUG`: `0` or `1`, print buffer initialization, SM approximation, and backend debugging information, `0` by default
The C++ side honors that contract — it parses the value as an `int` before testing it:
```cpp
// csrc/kernels/backend/nccl.cu:38, :45, :79
// csrc/elastic/buffer.hpp:865, :1055
if (get_env("EP_BUFFER_DEBUG"))
```
`get_env` runs the value through `sscanf(c_str, "%d", &value)` (`csrc/utils/system.hpp:28-31`), so `"0"` becomes `0` — falsy. Correct.
The Python side never converts, and tests the string directly:
```python
# deep_ep/buffers/elastic.py:311
if os.environ.get('EP_BUFFER_DEBUG', 0):
print(f'Initializing EP elastic buffer with {num_bytes} bytes ...')
# deep_ep/buffers/elastic.py:828
if os.environ.get('EP_BUFFER_DEBUG', 0):
print(f'EP SM approximation: ...')
```
With `EP_BUFFER_DEBUG=0`, `os.environ.get(...)` returns the string `'0'`, which is truthy — so both `print` calls fire.
Note the default value `0` (an `int`) is never actually what gets tested when the variable is set; it only applies when the variable is absent. That is why the unset case behaves correctly and only the explicitly-disabled case misbehaves.
## Reproduction
```python
import os
os.environ['EP_BUFFER_DEBUG'] = '0'
print('python side ->', bool(os.environ.get('EP_BUFFER_DEBUG', 0))) # matches elastic.py
print('cpp side ->', bool(int(os.environ.get('EP_BUFFER_DEBUG', 0)))) # matches get_env
```
```
python side -> True
cpp side -> False
```
Any non-empty value behaves the same way, so `EP_BUFFER_DEBUG=false` and `EP_BUFFER_DEBUG=off` also enable the Python output.
## Expected vs. actual
| `EP_BUFFER_DEBUG` | Expected | Python actual | C++ actual |
|---|---|---|---|
| unset | off | off | off |
| `0` | off | **on** | off |
| `1` | on | on | on |
The two halves of a single documented flag disagree, and explicitly disabling it is the one case that breaks.
## Impact
Minor but user-visible: a user who explicitly disables the flag gets per-rank `print` output on every `ElasticBuffer` construction and every `get_theoretical_num_sms` call, with no way to turn it off short of unsetting the variable. Explicitly setting a flag to its documented off value is a common thing to do in launcher scripts and config templates, where variables are usually set unconditionally rather than conditionally omitted.
## Suggested fix
Convert before testing, which is the idiom this repo already uses at every other `EP_*` boolean flag:
```python
if int(os.environ.get('EP_BUFFER_DEBUG', 0)):
```
For reference, the existing call sites that already do this:
- `deep_ep/__init__.py:51` — `int(os.environ.get('EP_SUPPRESS_NCCL_CHECK', 0))`
- `deep_ep/utils/testing.py:143` — `int(os.environ.get('EP_USE_NVIDIA_TOOLS', 0))`
- `deep_ep/utils/testing.py:152` — `int(os.environ.get('EP_DISABLE_BARRIER_PROFILING', 0))`
- `deep_ep/utils/comm.py:62` — `int(os.getenv('EP_REUSE_NCCL_COMM', '1'))`
- `setup.py:130`, `setup.py:153` — same pattern
`EP_BUFFER_DEBUG` at `elastic.py:311` and `elastic.py:828` are the only two boolean env reads in the package that omit the conversion.
I'd be happy to send a PR for this.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.