Skip to content

[Web] Decode packed BF16 tensor records in place - #20167

Open
akaashrp wants to merge 2 commits into
apache:mainfrom
akaashrp:memory/04-inplace-bf16-decode
Open

[Web] Decode packed BF16 tensor records in place#20167
akaashrp wants to merge 2 commits into
apache:mainfrom
akaashrp:memory/04-inplace-bf16-decode

Conversation

@akaashrp

@akaashrp akaashrp commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Reduce peak WASM memory during BF16 tensor-cache loading by decoding directly in the final float32 CPU tensor allocation. The packed BF16 input is copied into the lower half of the destination tensor and expanded backward, preventing output writes from overwriting unread input. This removes the separate FFI byte-array allocation previously required during decoding. Leave the existing decoder as a fallback when the new WASM entry point is unavailable.

Packed BF16 decoding currently uses separate input and output storage. Add a Wasm entry point that expands values backward in the destination buffer after the packed bytes have been copied into its lower half.

Use the in-place path when the entry point is available and keep the existing decoder otherwise. Both paths account for DLTensor byte_offset.
@akaashrp
akaashrp force-pushed the memory/04-inplace-bf16-decode branch from acae0af to d6cbf31 Compare August 24, 2026 08:43
@akaashrp
akaashrp requested a review from guan404ming August 25, 2026 02:42

@guan404ming guan404ming left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! Built with emsdk 4.0.23 and ran tests/node locally: all 83 tests pass, including the 20 new/updated ones. The backward in-place expansion looks correct to me. A few small suggestions below, none blocking.

Comment thread web/emcc/wasm_runtime.cc
Comment thread web/emcc/wasm_runtime.cc
});
}

size_t GetCheckedTensorElementCount(const Tensor& tensor) {

@guan404ming guan404ming Aug 25, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a plain product over shape would be enough here. tensor shapes are already validated at allocation time, so the overflow checks feel a little heavier than needed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find shape validation in the allocation path. ffi::GetDataSize multiplies dimensions as size_t without checking negative values or overflow. This matters on wasm32, where an int64_t dimension could truncate before allocation. Since this function is also callable directly through FFI, I think the checks should remain unless validation is added to the common tensor construction path.

Comment thread web/src/runtime.ts
}

/** Return the exact byte size of a packed BF16 tensor. */
private getPackedBF16Bytes(shape: Array<number>): number {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could drop this helper, since ArrayDecodeBF16ToF32Inplace already rejects a size mismatch via TVM_FFI_ICHECK_EQ. Keeping the check in one place would be a bit simpler to maintain.

@akaashrp akaashrp Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The C++ check only runs after storeRawBytes has copied the packed data into tensor memory, so it cannot protect that copy. I think the JS check is needed before the write. Passing the bytes through ArrayDecodeStorage would reintroduce the temporary allocation this path removes. I prefer to keep the C++ check as validation of the newly exposed FFI entry point itself since it can be invoked independently of the tensor-cache loader.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants