deepseek-ai / deepseek-ai/DeepEP

`EP_BUFFER_DEBUG=0` enables Python-side debug output because the env var is tested as a raw string

Open
#718 0 comments 0 reactions 0 assignees View on GitHub
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.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.