Add: record scalar_count in the ChipCallable header - #2064
Draft
sunkaixuan2018 wants to merge 1 commit into
Draft
Conversation
A ChipCallable records its tensor signature but not how many scalar arguments its orchestration expects, so an argument list cannot be checked against the artifact. Store the count in the header and thread it through the factory and the binding, changing no byte of the existing layout: - scalar_count_ occupies four bytes of the padding between config_name_len_ and the 16-byte-aligned storage_, so every historical field offset, offsetof(storage_), and sizeof stay unchanged, and a legacy zero-initialized blob reads as 0 (legacy artifact and no-scalar orchestration are indistinguishable by design). - make_callable takes the count after sig_count and rejects values outside [0, CHIP_MAX_SCALAR_ARGS], naming the value and the limit. - ChipCallable.build gains a trailing scalar_count keyword defaulting to 0 and the binding exposes a read-only scalar_count property, so every existing caller keeps working unchanged. - static_asserts pin every field offset, sizeof, and POD-ness of both ChipCallable and CoreCallable. CoreCallable carries no scalar_count: its leaf header packs exactly to storage_ with no padding, so the field cannot be added there without moving the wire layout, and the chip-level artifact is where callers look the count up. - Tests cover factory round-trip, bounds rejection, legacy blobs reading 0, and that two builds differing only in scalar_count differ only in that field's four bytes.
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: trueThanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
A ChipCallable is the self-describing compiled artifact (header + payload) whose bytes travel through L3/L4 IPC and the on-disk kernel cache. The header records the tensor signature (
signature_[]+sig_count_) but not how many scalar arguments the orchestration expects, so the two sides of a call rely on an implicit convention. This PR makes the artifact record its scalar count. It only adds the data and the write path — no code consumes or validates the field yet.How it serves the overall goal: the compiled artifact now fully records how many tensors and scalars it needs, which is the data a future call-entry argument check will read.
Design
int32_t scalar_count_occupies four bytes of the historical padding betweenconfig_name_len_and the 16-byte-alignedstorage_, so:offsetof(storage_)(9376), andsizeof(ChipCallable)(9376) are unchanged;make_callabletakes the count right aftersig_countand rejects values outside[0, CHIP_MAX_SCALAR_ARGS(=128)], naming the value and the limit;ChipCallable.build(...)gains a trailing keywordscalar_count=0and a read-onlyscalar_countproperty — every existing Python caller (including downstream repos) keeps working unchanged;scalar_count == 0means either a legacy artifact that never recorded the count or an orchestration that takes no scalars; the two are indistinguishable by design (no version bit).CoreCallable carries no scalar_count: on current main its leaf header packs exactly to
storage_with zero padding (128+4+4+8 = 144,resolved_addr_naturally aligned), so the field cannot be added there without moving the wire layout. The chip-level artifact is where a call entry looks the count up; the CoreCallable layout is instead pinned byte-for-byte by the new asserts.Compatibility matrix
make_callable, soscalar_count() == 0(legacy semantics)scalar_count=0is byte-identical to a pre-change build, so existingbuild/cache/kernelsentries and the_chip_callable_abi_tokenstay validcallable_blob_sha256already covers the full bytes, so it automatically covers the field; the versionedCHIP_SIGNATURE_SCHEMA_V1is untouchedStatic assert inventory (compile-time, callable.h)
signature_(0),sig_count_(1024),binary_size_(1028),func_name_(1032),func_name_len_(1096),child_func_ids_(1100),child_offsets_(5196),child_count_(9292),config_name_(9296),config_name_len_(9360),scalar_count_(9364),storage_(9376);sizeof == 9376signature_(0),sig_count_(128),binary_size_(132),resolved_addr_(136),storage_(144);sizeof == 144;binary_data_offset() == 192is_trivially_copyable && is_standard_layout; existingCALLABLE_CHILD_ALIGNalignment asserts retainedWrite chain
All in-repo C++
make_callablecall sites pass their real count (0 — none of them takes scalars). The scene-test path keeps the binding default of 0: theCALLABLEdeclaration carries no scalar information (scalars appear only per-case ingenerate_args()), so a real value is not derivable at callable-compile time and is not guessed. Callers that know their count can start passingChipCallable.build(scalar_count=...).Tests
tests/ut/cpp/types/test_callable_scalar_count.cpp, new): factory round-trip (0/1/7/128), out-of-range rejection with value+limit in the message (-1, 129), a legacy blob (field bytes zeroed) reads 0 with all other accessors intact, and a byte-level proof that two builds differing only in scalar_count differ only in that field's four bytes.tests/ut/py/test_task_interface.py): default path reads 0, keyword round-trip,from_bytesround-trip, out-of-range raisesValueErrornaming value and limit.tests/ut/cpp: 124/124 pass (Linux, default build type). Fulltests/ut/py: 1976 passed / 15 skipped; the only failures are the torch-less-host environment set (every one fails atimport torch), identical on a clean base.