@@ -68,6 +68,7 @@ static sycl::unittest::PiImageArray<2> ImgArray{Img};
68
68
69
69
static int nProgramCreate = 0 ;
70
70
static volatile bool outOfResourcesToggle = false ;
71
+ static volatile bool outOfHostMemoryToggle = false ;
71
72
72
73
static pi_result redefinedProgramCreate (pi_context context, const void *il,
73
74
size_t length,
@@ -80,6 +81,17 @@ static pi_result redefinedProgramCreate(pi_context context, const void *il,
80
81
return PI_SUCCESS;
81
82
}
82
83
84
+ static pi_result
85
+ redefinedProgramCreateOutOfHostMemory (pi_context context, const void *il,
86
+ size_t length, pi_program *res_program) {
87
+ ++nProgramCreate;
88
+ if (outOfHostMemoryToggle) {
89
+ outOfHostMemoryToggle = false ;
90
+ return PI_ERROR_OUT_OF_HOST_MEMORY;
91
+ }
92
+ return PI_SUCCESS;
93
+ }
94
+
83
95
TEST (OutOfResourcesTest, piProgramCreate) {
84
96
sycl::unittest::PiMock Mock;
85
97
Mock.redefineBefore <detail::PiApiKind::piProgramCreate>(
@@ -141,6 +153,70 @@ TEST(OutOfResourcesTest, piProgramCreate) {
141
153
}
142
154
}
143
155
156
+ TEST (OutOfHostMemoryTest, piProgramCreate) {
157
+ // Reset to zero.
158
+ nProgramCreate = 0 ;
159
+
160
+ sycl::unittest::PiMock Mock;
161
+ Mock.redefineBefore <detail::PiApiKind::piProgramCreate>(
162
+ redefinedProgramCreateOutOfHostMemory);
163
+
164
+ sycl::platform Plt{Mock.getPlatform ()};
165
+ sycl::context Ctx{Plt};
166
+ auto CtxImpl = detail::getSyclObjImpl (Ctx);
167
+ queue q (Ctx, default_selector_v);
168
+
169
+ int runningTotal = 0 ;
170
+ // Cache is empty, so one piProgramCreate call.
171
+ q.single_task <class OutOfResourcesKernel1 >([] {});
172
+ EXPECT_EQ (nProgramCreate, runningTotal += 1 );
173
+
174
+ // Now, we make the next piProgramCreate call fail with
175
+ // PI_ERROR_OUT_OF_HOST_MEMORY. The caching mechanism should catch this,
176
+ // clear the cache, and retry the piProgramCreate.
177
+ outOfHostMemoryToggle = true ;
178
+ q.single_task <class OutOfResourcesKernel2 >([] {});
179
+ EXPECT_FALSE (outOfHostMemoryToggle);
180
+ EXPECT_EQ (nProgramCreate, runningTotal += 2 );
181
+ {
182
+ detail::KernelProgramCache::ProgramCache &Cache =
183
+ CtxImpl->getKernelProgramCache ().acquireCachedPrograms ().get ();
184
+ EXPECT_EQ (Cache.size (), 1U ) << " Expected 1 program in the cache" ;
185
+ }
186
+
187
+ // The next piProgramCreate call will fail with
188
+ // PI_ERROR_OUT_OF_HOST_MEMORY. But OutOfResourcesKernel2 is in
189
+ // the cache, so we expect no new piProgramCreate calls.
190
+ outOfHostMemoryToggle = true ;
191
+ q.single_task <class OutOfResourcesKernel2 >([] {});
192
+ EXPECT_TRUE (outOfHostMemoryToggle);
193
+ EXPECT_EQ (nProgramCreate, runningTotal);
194
+
195
+ // OutOfResourcesKernel1 is not in the cache, so we have to
196
+ // build it. From what we set before, this call will fail,
197
+ // the cache will clear out, and will try again.
198
+ q.single_task <class OutOfResourcesKernel1 >([] {});
199
+ EXPECT_FALSE (outOfHostMemoryToggle);
200
+ EXPECT_EQ (nProgramCreate, runningTotal += 2 );
201
+ {
202
+ detail::KernelProgramCache::ProgramCache &Cache =
203
+ CtxImpl->getKernelProgramCache ().acquireCachedPrograms ().get ();
204
+ EXPECT_EQ (Cache.size (), 1U ) << " Expected 1 program in the cache" ;
205
+ }
206
+
207
+ // Finally, OutOfResourcesKernel1 will be in the cache, but
208
+ // OutOfResourceKenel2 will not, so one more piProgramCreate.
209
+ // Toggle is not set, so this should succeed.
210
+ q.single_task <class OutOfResourcesKernel1 >([] {});
211
+ q.single_task <class OutOfResourcesKernel2 >([] {});
212
+ EXPECT_EQ (nProgramCreate, runningTotal += 1 );
213
+ {
214
+ detail::KernelProgramCache::ProgramCache &Cache =
215
+ CtxImpl->getKernelProgramCache ().acquireCachedPrograms ().get ();
216
+ EXPECT_EQ (Cache.size (), 2U ) << " Expected 2 program in the cache" ;
217
+ }
218
+ }
219
+
144
220
static int nProgramLink = 0 ;
145
221
146
222
static pi_result
@@ -158,6 +234,20 @@ redefinedProgramLink(pi_context context, pi_uint32 num_devices,
158
234
return PI_SUCCESS;
159
235
}
160
236
237
+ static pi_result redefinedProgramLinkOutOfHostMemory (
238
+ pi_context context, pi_uint32 num_devices, const pi_device *device_list,
239
+ const char *options, pi_uint32 num_input_programs,
240
+ const pi_program *input_programs,
241
+ void (*pfn_notify)(pi_program program, void *user_data), void *user_data,
242
+ pi_program *ret_program) {
243
+ ++nProgramLink;
244
+ if (outOfHostMemoryToggle) {
245
+ outOfHostMemoryToggle = false ;
246
+ return PI_ERROR_OUT_OF_HOST_MEMORY;
247
+ }
248
+ return PI_SUCCESS;
249
+ }
250
+
161
251
TEST (OutOfResourcesTest, piProgramLink) {
162
252
sycl::unittest::PiMock Mock;
163
253
Mock.redefineBefore <detail::PiApiKind::piProgramLink>(redefinedProgramLink);
@@ -191,4 +281,43 @@ TEST(OutOfResourcesTest, piProgramLink) {
191
281
CtxImpl->getKernelProgramCache ().acquireCachedPrograms ().get ();
192
282
EXPECT_EQ (Cache.size (), 0u ) << " Expect no programs in the cache" ;
193
283
}
194
- }
284
+ }
285
+
286
+ TEST (OutOfHostMemoryTest, piProgramLink) {
287
+ // Reset to zero.
288
+ nProgramLink = 0 ;
289
+
290
+ sycl::unittest::PiMock Mock;
291
+ Mock.redefineBefore <detail::PiApiKind::piProgramLink>(
292
+ redefinedProgramLinkOutOfHostMemory);
293
+
294
+ sycl::platform Plt{Mock.getPlatform ()};
295
+ sycl::context Ctx{Plt};
296
+ auto CtxImpl = detail::getSyclObjImpl (Ctx);
297
+ queue q (Ctx, default_selector_v);
298
+ // Put some programs in the cache
299
+ q.single_task <class OutOfResourcesKernel1 >([] {});
300
+ q.single_task <class OutOfResourcesKernel2 >([] {});
301
+ {
302
+ detail::KernelProgramCache::ProgramCache &Cache =
303
+ CtxImpl->getKernelProgramCache ().acquireCachedPrograms ().get ();
304
+ EXPECT_EQ (Cache.size (), 2U ) << " Expect 2 programs in the cache" ;
305
+ }
306
+
307
+ auto b1 = sycl::get_kernel_bundle<OutOfResourcesKernel1,
308
+ sycl::bundle_state::object>(Ctx);
309
+ auto b2 = sycl::get_kernel_bundle<OutOfResourcesKernel2,
310
+ sycl::bundle_state::object>(Ctx);
311
+ outOfHostMemoryToggle = true ;
312
+ EXPECT_EQ (nProgramLink, 0 );
313
+ auto b3 = sycl::link ({b1, b2});
314
+ EXPECT_FALSE (outOfHostMemoryToggle);
315
+ // one restart due to out of resources, one link per each of b1 and b2.
316
+ EXPECT_EQ (nProgramLink, 3 );
317
+ // no programs should be in the cache due to out of resources.
318
+ {
319
+ detail::KernelProgramCache::ProgramCache &Cache =
320
+ CtxImpl->getKernelProgramCache ().acquireCachedPrograms ().get ();
321
+ EXPECT_EQ (Cache.size (), 0u ) << " Expect no programs in the cache" ;
322
+ }
323
+ }
0 commit comments