@@ -74,6 +74,10 @@ class MethodMetaTest : public ::testing::Test {
7474 void SetUp () override {
7575 load_program (std::getenv (" ET_MODULE_ADD_PATH" ), " add" );
7676 load_program (std::getenv (" ET_MODULE_STATEFUL_PATH" ), " stateful" );
77+ const char * device_path = std::getenv (" ET_MODULE_ADD_WITH_DEVICE_PATH" );
78+ if (device_path != nullptr ) {
79+ load_program (device_path, " add_with_device" );
80+ }
7781 }
7882
7983 private:
@@ -192,6 +196,27 @@ TEST_F(MethodMetaTest, MethodMetaAttribute) {
192196 ASSERT_EQ (bad_access.error (), Error::InvalidArgument);
193197}
194198
199+ TEST_F (MethodMetaTest, MemoryPlannedBufferDeviceDefaultsCpu) {
200+ Result<MethodMeta> method_meta = programs_[" add" ]->method_meta (" forward" );
201+ ASSERT_EQ (method_meta.error (), Error::Ok);
202+
203+ // CPU-only model: all buffers should default to CPU device.
204+ size_t num_buffers = method_meta->num_memory_planned_buffers ();
205+ ASSERT_GT (num_buffers, 0 );
206+
207+ for (size_t i = 0 ; i < num_buffers; ++i) {
208+ auto device = method_meta->memory_planned_buffer_device (i);
209+ ASSERT_TRUE (device.ok ());
210+ EXPECT_EQ (device->type (), executorch::runtime::etensor::DeviceType::CPU );
211+ EXPECT_EQ (device->index (), 0 );
212+ }
213+
214+ // Out of range returns error.
215+ EXPECT_EQ (
216+ method_meta->memory_planned_buffer_device (num_buffers).error (),
217+ Error::InvalidArgument);
218+ }
219+
195220TEST_F (MethodMetaTest, TensorInfoSizeOverflow) {
196221 // Create sizes that will cause overflow when multiplied
197222 std::vector<int32_t > overflow_sizes = {
@@ -214,3 +239,30 @@ TEST_F(MethodMetaTest, TensorInfoSizeOverflow) {
214239 executorch::aten::string_view{nullptr , 0 }),
215240 " " );
216241}
242+
243+ TEST_F (MethodMetaTest, MethodMetaBufferDeviceReturnsCudaForDeviceBuffer) {
244+ ASSERT_NE (programs_.find (" add_with_device" ), programs_.end ())
245+ << " ET_MODULE_ADD_WITH_DEVICE_PATH env var not set" ;
246+ Result<MethodMeta> method_meta =
247+ programs_[" add_with_device" ]->method_meta (" forward" );
248+ ASSERT_EQ (method_meta.error (), Error::Ok);
249+
250+ // ModuleAddWithDevice exports with enable_non_cpu_memory_planning=True.
251+ // The model delegates add(a,b) to CUDA, producing:
252+ // non_const_buffer_sizes: [0, 48] (index 0 reserved)
253+ // non_const_buffer_device: [{buffer_idx=1, device_type=CUDA,
254+ // device_index=0}]
255+ // So there is exactly 1 planned buffer (user-facing index 0), on CUDA.
256+ ASSERT_EQ (method_meta->num_memory_planned_buffers (), 1 );
257+
258+ // Buffer 0 should be CUDA device.
259+ auto device = method_meta->memory_planned_buffer_device (0 );
260+ ASSERT_TRUE (device.ok ());
261+ EXPECT_EQ (device->type (), executorch::runtime::etensor::DeviceType::CUDA );
262+ EXPECT_EQ (device->index (), 0 );
263+
264+ // Out of range should return error.
265+ EXPECT_EQ (
266+ method_meta->memory_planned_buffer_device (1 ).error (),
267+ Error::InvalidArgument);
268+ }
0 commit comments