30
30
#include < cstdlib>
31
31
#include < cstring>
32
32
#include < fstream>
33
+ #include < functional>
34
+ #include < libgen.h>
33
35
#include < memory>
34
36
#include < mutex>
35
37
#include < sstream>
38
+ #include < stdio.h>
39
+ #include < stdlib.h>
40
+ #include < string.h>
36
41
#include < string>
42
+ #include < sys/stat.h>
43
+ #include < sys/types.h>
44
+ #include < unistd.h>
37
45
38
46
__SYCL_INLINE_NAMESPACE (cl) {
39
47
namespace sycl {
40
48
namespace detail {
41
49
42
50
using ContextImplPtr = std::shared_ptr<cl::sycl::detail::context_impl>;
43
51
44
- static constexpr int DbgProgMgr = 1 ;
52
+ static constexpr int DbgProgMgr = 2 ;
45
53
46
54
enum BuildState { BS_InProgress, BS_Done, BS_Failed };
47
55
@@ -182,6 +190,7 @@ getOrBuild(KernelProgramCache &KPCache, KeyT &&CacheKey, AcquireFT &&Acquire,
182
190
183
191
// only the building thread will run this
184
192
try {
193
+
185
194
RetT *Desired = Build ();
186
195
187
196
#ifndef NDEBUG
@@ -346,6 +355,204 @@ RT::PiProgram ProgramManager::createPIProgram(const RTDeviceBinaryImage &Img,
346
355
return Res;
347
356
}
348
357
358
+ long GetFileSize (const char *FileName) {
359
+ struct stat Stat;
360
+ if (!stat (FileName, &Stat))
361
+ return Stat.st_size ;
362
+ return -1 ;
363
+ }
364
+
365
+ inline bool IsFSEntryPresent (const char *Path) {
366
+ struct stat Stat;
367
+ return !stat (Path, &Stat);
368
+ }
369
+
370
+ int MakePathRecur (const char *Dir, mode_t Mode) {
371
+ assert ((Dir != nullptr ) && " Passed null-pointer as directory name." );
372
+
373
+ // Directory is present - do nothing
374
+ if (IsFSEntryPresent (Dir))
375
+ return 0 ;
376
+
377
+ char *CurDir = strdup (Dir);
378
+ MakePathRecur (dirname (CurDir), Mode);
379
+ if (DbgProgMgr > 1 )
380
+ std::cerr << " Created directory: " << CurDir << std::endl;
381
+
382
+ free (CurDir);
383
+ return mkdir (Dir, Mode);
384
+ }
385
+
386
+ void WriteCacheItem (const std::string &FileName,
387
+ const std::vector<std::vector<char >> &Data) {
388
+ std::ofstream FileStream{FileName, std::ios::binary};
389
+ if (DbgProgMgr > 1 ) {
390
+ std::cerr << " ####Writing programs built for " << std::dec << Data.size ()
391
+ << " devices:\n " ;
392
+ }
393
+
394
+ size_t Size = Data.size ();
395
+ FileStream.write ((char *)&Size, sizeof (Size));
396
+ for (size_t i = 0 ; i < Data.size (); ++i) {
397
+ if (DbgProgMgr > 1 ) {
398
+ std::cerr << " \t Write " << i << " -th image of size " << std::dec
399
+ << Data[i].size () << " \n " ;
400
+ }
401
+ Size = Data[i].size ();
402
+ FileStream.write ((char *)&Size, sizeof (Size));
403
+ FileStream.write (Data[i].data (), Size);
404
+ }
405
+ FileStream.close ();
406
+ }
407
+
408
+ std::vector<std::vector<char >> ReadCacheItem (const std::string &FileName) {
409
+ std::vector<std::vector<char >> Res;
410
+ std::ifstream FileStream{FileName, std::ios::binary};
411
+ size_t ImgNum, ImgSize;
412
+ FileStream.read ((char *)&ImgNum, sizeof (ImgNum));
413
+ if (DbgProgMgr > 1 ) {
414
+ std::cerr << " ####Reading programs built for " << std::dec << ImgNum
415
+ << " devices:\n " ;
416
+ }
417
+
418
+ Res.resize (ImgNum);
419
+
420
+ for (size_t i = 0 ; i < ImgNum; ++i) {
421
+ FileStream.read ((char *)&ImgSize, sizeof (ImgSize));
422
+ if (DbgProgMgr > 1 ) {
423
+ std::cerr << " \t Read " << i << " -th image of size " << std::dec << ImgSize
424
+ << " \n " ;
425
+ }
426
+
427
+ Res[i].resize (ImgSize);
428
+ FileStream.read (Res[i].data (), ImgSize);
429
+ }
430
+
431
+ return Res;
432
+ }
433
+
434
+ std::string getDeviceString (const device &Device) {
435
+ return {Device.get_platform ().get_info <sycl::info::platform::name>() +
436
+ Device.get_info <sycl::info::device::name>() +
437
+ Device.get_info <sycl::info::device::version>() +
438
+ Device.get_info <sycl::info::device::driver_version>()};
439
+ }
440
+
441
+ std::string DumpBinData (const unsigned char *Data, size_t Size) {
442
+ if (!Size)
443
+ return " NONE" ;
444
+ std::stringstream ss;
445
+ for (size_t i = 0 ; i < Size; i++) {
446
+ ss << std::hex << (int )Data[i];
447
+ }
448
+ return ss.str ();
449
+ }
450
+
451
+ std::string GetCacheItemDirName (const device &Device,
452
+ const RTDeviceBinaryImage &Img,
453
+ const SerializedObj SpecConsts,
454
+ const std::string &BuildOptionsString) {
455
+ static std::string cache_root{detail::OSUtil::getCacheRoot ()};
456
+
457
+ std::string ImgString{
458
+ DumpBinData (Img.getRawData ().BinaryStart , Img.getSize ())};
459
+ std::string DeviceString{getDeviceString (Device)};
460
+ std::string SpecConstsString{
461
+ DumpBinData (SpecConsts.data (), SpecConsts.size ())};
462
+ std::hash<std::string> StringHasher{};
463
+ return {cache_root + " /" + std::to_string (StringHasher (DeviceString)) + " /" +
464
+ std::to_string (StringHasher (ImgString)) + " /" +
465
+ std::to_string (StringHasher (SpecConstsString)) + " /" +
466
+ std::to_string (StringHasher (BuildOptionsString))};
467
+ }
468
+
469
+ bool IsPersistentCacheEnabled () {
470
+ static const char *PersistenCacheDisabled =
471
+ SYCLConfig<SYCL_CACHE_DISABLE_PERSISTENT>::get ();
472
+
473
+ if (DbgProgMgr > 0 )
474
+ std::cerr << " Persistent cache "
475
+ << (PersistenCacheDisabled ? " disabled." : " enabled." )
476
+ << std::endl;
477
+ return !PersistenCacheDisabled;
478
+ }
479
+
480
+ void ProgramManager::putPIProgramToDisc (const detail::plugin &Plugin,
481
+ const device &Device,
482
+ const RTDeviceBinaryImage &Img,
483
+ const SerializedObj SpecConsts,
484
+ const std::string &BuildOptionsString,
485
+ const RT::PiProgram &Program) {
486
+ if (!IsPersistentCacheEnabled ()) {
487
+ return ;
488
+ }
489
+
490
+ static std::string DirName =
491
+ GetCacheItemDirName (Device, Img, SpecConsts, BuildOptionsString);
492
+
493
+ size_t i = 0 ;
494
+ std::string FileName;
495
+ do {
496
+ FileName = DirName + " /" + std::to_string (i++) + " .bin" ;
497
+ } while (IsFSEntryPresent (FileName.c_str ()));
498
+
499
+ size_t DeviceNum;
500
+ Plugin.call <PiApiKind::piProgramGetInfo>(Program, PI_PROGRAM_INFO_NUM_DEVICES,
501
+ sizeof (DeviceNum), &DeviceNum,
502
+ nullptr );
503
+ std::vector<size_t > BinarySizes (DeviceNum);
504
+ Plugin.call <PiApiKind::piProgramGetInfo>(
505
+ Program, PI_PROGRAM_INFO_BINARY_SIZES,
506
+ sizeof (size_t ) * BinarySizes.size (), BinarySizes.data (), nullptr );
507
+
508
+ std::vector<std::vector<char >> Result;
509
+ std::vector<char *> Pointers;
510
+ for (size_t I = 0 ; I < BinarySizes.size (); ++I) {
511
+ Result.emplace_back (BinarySizes[I]);
512
+ Pointers.push_back (Result[I].data ());
513
+ }
514
+
515
+ Plugin.call <PiApiKind::piProgramGetInfo>(Program, PI_PROGRAM_INFO_BINARIES,
516
+ sizeof (char *) * Pointers.size (),
517
+ Pointers.data (), nullptr );
518
+
519
+ MakePathRecur (DirName.c_str (), 0777 );
520
+ WriteCacheItem (FileName, Result);
521
+ }
522
+
523
+ bool ProgramManager::getPIProgramFromDisc (ContextImplPtr ContextImpl,
524
+ const device &Device,
525
+ const RTDeviceBinaryImage &Img,
526
+ const SerializedObj SpecConsts,
527
+ const std::string &BuildOptionsString,
528
+ RT::PiProgram &NativePrg) {
529
+
530
+ if (!IsPersistentCacheEnabled ())
531
+ return false ;
532
+
533
+ std::string Path{
534
+ GetCacheItemDirName (Device, Img, SpecConsts, BuildOptionsString)};
535
+
536
+ if (!IsFSEntryPresent (Path.c_str ()))
537
+ return false ;
538
+
539
+ int i = 0 ;
540
+ std::string BinFileName{Path + " /" + std::to_string (i) + " .bin" };
541
+ while (IsFSEntryPresent (BinFileName.c_str ())) {
542
+ auto BinDataItem = ReadCacheItem (BinFileName);
543
+ if (BinDataItem.size ()) {
544
+ // TODO: Build for multiple devices once supported by program manager
545
+ NativePrg = createBinaryProgram (
546
+ ContextImpl, Device, (const unsigned char *)BinDataItem[0 ].data (),
547
+ BinDataItem[0 ].size ());
548
+ return true ;
549
+ }
550
+ BinFileName = Path + " /" + std::to_string (++i) + " .bin" ;
551
+ }
552
+
553
+ return false ;
554
+ }
555
+
349
556
RT::PiProgram ProgramManager::getBuiltPIProgram (OSModuleHandle M,
350
557
const context &Context,
351
558
const device &Device,
@@ -390,9 +597,12 @@ RT::PiProgram ProgramManager::getBuiltPIProgram(OSModuleHandle M,
390
597
if (LinkOptsEnv) {
391
598
LinkOpts = LinkOptsEnv;
392
599
}
600
+ SerializedObj SpecConsts;
601
+ if (Prg)
602
+ Prg->stableSerializeSpecConstRegistry (SpecConsts);
393
603
394
604
auto BuildF = [this , &M, &KSId, &Context, &Device, Prg, &CompileOpts,
395
- &LinkOpts, &JITCompilationIsRequired] {
605
+ &LinkOpts, &JITCompilationIsRequired, SpecConsts ] {
396
606
const RTDeviceBinaryImage &Img =
397
607
getDeviceImage (M, KSId, Context, Device, JITCompilationIsRequired);
398
608
// Update only if compile options are not overwritten by environment
@@ -413,19 +623,28 @@ RT::PiProgram ProgramManager::getBuiltPIProgram(OSModuleHandle M,
413
623
LinkOpts += Img.getLinkOptions ();
414
624
ContextImplPtr ContextImpl = getSyclObjImpl (Context);
415
625
const detail::plugin &Plugin = ContextImpl->getPlugin ();
416
- RT::PiProgram NativePrg = createPIProgram (Img, Context, Device);
417
- if (Prg)
418
- flushSpecConstants (*Prg, NativePrg, &Img);
626
+ RT::PiProgram NativePrg;
627
+ bool LoadedFromDiskCache =
628
+ getPIProgramFromDisc (ContextImpl, Device, Img, SpecConsts,
629
+ CompileOpts + LinkOpts, NativePrg);
630
+ if (!LoadedFromDiskCache) {
631
+ NativePrg = createPIProgram (Img, Context, Device);
632
+ if (Prg)
633
+ flushSpecConstants (*Prg, NativePrg, &Img);
634
+ }
635
+
419
636
ProgramPtr ProgramManaged (
420
637
NativePrg, Plugin.getPiPlugin ().PiFunctionTable .piProgramRelease );
421
638
422
639
// Link a fallback implementation of device libraries if they are not
423
640
// supported by a device compiler.
424
- // Pre-compiled programs are supposed to be already linked.
641
+ // Pre-compiled programs (after AOT compilation or read from persitent
642
+ // cache) are supposed to be already linked.
425
643
// If device image is not SPIR-V, DeviceLibReqMask will be 0 which means
426
644
// no fallback device library will be linked.
427
645
uint32_t DeviceLibReqMask = 0 ;
428
- if (Img.getFormat () == PI_DEVICE_BINARY_TYPE_SPIRV &&
646
+ if (!LoadedFromDiskCache &&
647
+ Img.getFormat () == PI_DEVICE_BINARY_TYPE_SPIRV &&
429
648
!SYCLConfig<SYCL_DEVICELIB_NO_FALLBACK>::get ())
430
649
DeviceLibReqMask = getDeviceLibReqMask (Img);
431
650
@@ -438,13 +657,12 @@ RT::PiProgram ProgramManager::getBuiltPIProgram(OSModuleHandle M,
438
657
std::lock_guard<std::mutex> Lock (MNativeProgramsMutex);
439
658
NativePrograms[BuiltProgram.get ()] = &Img;
440
659
}
660
+ if (!LoadedFromDiskCache)
661
+ putPIProgramToDisc (Plugin, Device, Img, SpecConsts,
662
+ CompileOpts + LinkOpts, BuiltProgram.get ());
441
663
return BuiltProgram.release ();
442
664
};
443
665
444
- SerializedObj SpecConsts;
445
- if (Prg)
446
- Prg->stableSerializeSpecConstRegistry (SpecConsts);
447
-
448
666
const RT::PiDevice PiDevice = getRawSyclObjImpl (Device)->getHandleRef ();
449
667
auto BuildResult = getOrBuild<PiProgramT, compile_program_error>(
450
668
Cache,
0 commit comments