Layer Debugger#
- static std::vector<std::vector<int32_t>> trt_edgellm::rt::readForcedTokensFromEnv(
Per-request debug dumper for 4-layer numeric validation.
When both environment variables below are set, the LLM runtime dumps, for every inference round (round 0 = prefill, round r = decode step r), the last-token logits, the per-layer combined KV cache (only the layers named in the env var), the per-sequence valid lengths, and the per-round generated token ids. Everything is buffered across rounds and written as a single safetensors file at request end so the comparison tool can reconcile it against the PyTorch golden.
EDGELLM_DUMP_LOGITS_KVCACHE_LAYERS number of leading decoder layers k -> dumps layers 0..k-1. EDGELLM_DUMP_LOGITS_KVCACHE_DIR output directory for the dump file.
The two variables are XOR-coupled: setting exactly one is an error.
Per-layer tensors are dumped full-length over the active-batch prefix (no truncation here); the comparison tool slices each sequence to its valid length in PyTorch using the dumped context_lengths.
Safetensors layout (single file, all rounds): round_{r}.logits [activeBatch, vocab] (native dtype) round_{r}.layer_{i}.kv [activeBatch, 2, kvHeads, maxSeqLen, headDim] (native dtype) dim 1: 0 = key, 1 = value round_{r}.context_lengths [activeBatch] int32 round_{r}.generated_token_ids [activeBatch] int32
Scope (POC): base model + vanilla decoding only. Hooked from
runBaseModelPrefill(round 0) andVanillaDecoder::decodeStep. ! ! Optionally also drives teacher-forcing: whenEDGELLM_FORCE_TOKENS_FILEis set the ! dumper overrides each step’s sampled token with the golden’s (see applyForcedTokens()), ! so the run follows the golden token-for-token. Only ever active alongside a dump. class LayerDebugger { public: ! Build a dumper from the environment, or return nullptr when disabled. !
! Accumulate one round’s tensors into the in-memory buffer. ! ! Synchronises
streamfirst, so the KV cache and logits are final. !
! Write all buffered rounds to a single safetensors file. !
! Teacher-forcing: overwrite each active sequence’s sampled token with the forced ! one for this step. No-op unlessEDGELLM_FORCE_TOKENS_FILEwas set at construction. ! ! Call afterdumpRoundso the dump still records the model’s own sampled token; the ! forced token (if any) is what the caller then commits. This decouples the numeric ! comparison from greedy argmax stability — a near-tie argmax flip no longer diverges the ! two sides, while the dump still surfaces where the runtime wouldhave diverged. !
private: LayerDebugger(std::set<int32_t> layers, std::string dir, std::vector<std::vector<int32_t>> forcedTokens);
! Read per-sequence forced token ids from
EDGELLM_FORCE_TOKENS_FILE(one line persequence, whitespace-separated ids), or an empty vector when the env var is unset. Emits a warning when forcing is enabled, since it overrides the model’s own sampled tokens.
- Throws:
std::runtime_error – if exactly one of the two env vars is set (XOR ! violation) or the layer spec is empty / malformed. static std::unique_ptr<LayerDebugger> fromEnv();
- Parameters:
cacheManager – Base-model KV cache manager. !
logits – Device logits tensor [activeBatch, vocab]. !
validLengths – Per-sequence valid KV/sequence length this round. !
generatedTokenIds – Host int32 [activeBatch] tokens sampled this round ! (may be nullptr to skip). !
activeBatchSize – Number of active sequences this round. !
stream –
CUDA stream. void dumpRound(HybridCacheManager& cacheManager, Tensor const& logits, std::vector<int32_t> const& validLengths,
int32_t const* generatedTokenIds, int32_t activeBatchSize, cudaStream_t stream);
stream – CUDA stream (forwarded to the safetensors writer). void flush(cudaStream_t stream);
genLengths – Per-sequence count of tokens generated so far (== the index to force). !
tokenIds – Host array [activeBatchSize] of sampled tokens, overwritten in place. !
activeBatchSize – Number of active sequences. void applyForcedTokens(std::vector<int32_t> const& genLengths, int32_t* tokenIds, int32_t activeBatchSize);
- Returns:
A dumper if both env vars are set; nullptr if neither is set. !