//===---------------- Utils.cpp - Utilities for Remote RTL ----------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Utilities for data movement and debugging. // //===----------------------------------------------------------------------===// #include "Utils.h" #include "omptarget.h" namespace RemoteOffloading { void loadTargetBinaryDescription(const __tgt_bin_desc *Desc, TargetBinaryDescription &Request) { // Keeps track of entries which have already been deep copied. std::vector DeepCopiedEntryAddrs; // Copy Global Offload Entries for (auto *CurEntry = Desc->HostEntriesBegin; CurEntry != Desc->HostEntriesEnd; CurEntry++) { auto *NewEntry = Request.add_entries(); copyOffloadEntry(CurEntry, NewEntry); // Copy the pointer of the offload entry of the image into the Request Request.add_entry_ptrs((uint64_t)CurEntry); DeepCopiedEntryAddrs.push_back(CurEntry); } // Copy Device Images and Device Offload Entries __tgt_device_image *CurImage = Desc->DeviceImages; for (auto I = 0; I < Desc->NumDeviceImages; I++, CurImage++) { auto *Image = Request.add_images(); auto Size = (char *)CurImage->ImageEnd - (char *)CurImage->ImageStart; Image->set_binary(CurImage->ImageStart, Size); // Copy the pointer of the image into the Request auto *NewImagePtr = Request.add_image_ptrs(); NewImagePtr->set_img_ptr((uint64_t)CurImage->ImageStart); // Copy Device Offload Entries for (auto *CurEntry = CurImage->EntriesBegin; CurEntry != CurImage->EntriesEnd; CurEntry++) { auto *NewEntry = Image->add_entries(); auto Entry = std::find(DeepCopiedEntryAddrs.begin(), DeepCopiedEntryAddrs.end(), CurEntry); if (Entry != DeepCopiedEntryAddrs.end()) { // Offload entry has already been loaded shallowCopyOffloadEntry(CurEntry, NewEntry); } else { // Offload Entry has not been loaded into the Request copyOffloadEntry(CurEntry, NewEntry); DeepCopiedEntryAddrs.push_back(CurEntry); } // Copy the pointer of the offload entry of the image into the Request NewImagePtr->add_entry_ptrs((uint64_t)CurEntry); } } } void unloadTargetBinaryDescription( const TargetBinaryDescription *Request, __tgt_bin_desc *Desc, std::unordered_map &HostToRemoteDeviceImage) { std::unordered_map CopiedOffloadEntries; Desc->NumDeviceImages = Request->images_size(); Desc->DeviceImages = new __tgt_device_image[Desc->NumDeviceImages]; if (Request->entries_size()) Desc->HostEntriesBegin = new __tgt_offload_entry[Request->entries_size()]; else { Desc->HostEntriesBegin = nullptr; Desc->HostEntriesEnd = nullptr; } // Copy Global Offload Entries __tgt_offload_entry *CurEntry = Desc->HostEntriesBegin; size_t I = 0; for (auto &Entry : Request->entries()) { copyOffloadEntry(Entry, CurEntry); CopiedOffloadEntries[(void *)Request->entry_ptrs()[I]] = CurEntry; CurEntry++; I++; } Desc->HostEntriesEnd = CurEntry; // Copy Device Images and Device Offload Entries __tgt_device_image *CurImage = Desc->DeviceImages; auto ImageItr = Request->image_ptrs().begin(); for (auto Image : Request->images()) { // Copy Device Offload Entries CurEntry = Desc->HostEntriesBegin; bool Found = false; if (!Desc->HostEntriesBegin) { CurImage->EntriesBegin = nullptr; CurImage->EntriesEnd = nullptr; } for (size_t I = 0; I < Image.entries_size(); I++) { auto TgtEntry = CopiedOffloadEntries.find((void *)Request->entry_ptrs()[I]); if (TgtEntry != CopiedOffloadEntries.end()) { if (!Found) CurImage->EntriesBegin = CurEntry; CurImage->EntriesEnd = CurEntry + 1; Found = true; } else { Found = false; copyOffloadEntry(Image.entries()[I], CurEntry); CopiedOffloadEntries[(void *)(Request->entry_ptrs()[I])] = CurEntry; } CurEntry++; } // Copy Device Image CurImage->ImageStart = new uint8_t[Image.binary().size()]; memcpy(CurImage->ImageStart, static_cast(Image.binary().data()), Image.binary().size()); CurImage->ImageEnd = (void *)((char *)CurImage->ImageStart + Image.binary().size()); HostToRemoteDeviceImage[(void *)ImageItr->img_ptr()] = CurImage; CurImage++; ImageItr++; } } void freeTargetBinaryDescription(__tgt_bin_desc *Desc) { __tgt_device_image *CurImage = Desc->DeviceImages; for (auto I = 0; I < Desc->NumDeviceImages; I++, CurImage++) delete[](uint64_t *) CurImage->ImageStart; delete[] Desc->DeviceImages; for (auto *Entry = Desc->HostEntriesBegin; Entry != Desc->HostEntriesEnd; Entry++) { free(Entry->name); free(Entry->addr); } delete[] Desc->HostEntriesBegin; } void freeTargetTable(__tgt_target_table *Table) { for (auto *Entry = Table->EntriesBegin; Entry != Table->EntriesEnd; Entry++) free(Entry->name); delete[] Table->EntriesBegin; } void loadTargetTable(__tgt_target_table *Table, TargetTable &TableResponse, __tgt_device_image *Image) { auto *ImageEntry = Image->EntriesBegin; for (__tgt_offload_entry *CurEntry = Table->EntriesBegin; CurEntry != Table->EntriesEnd; CurEntry++, ImageEntry++) { // TODO: This can probably be trimmed substantially. auto *NewEntry = TableResponse.add_entries(); NewEntry->set_name(CurEntry->name); NewEntry->set_addr((uint64_t)CurEntry->addr); NewEntry->set_flags(CurEntry->flags); NewEntry->set_reserved(CurEntry->reserved); NewEntry->set_size(CurEntry->size); TableResponse.add_entry_ptrs((int64_t)CurEntry); } } void unloadTargetTable( TargetTable &TableResponse, __tgt_target_table *Table, std::unordered_map &HostToRemoteTargetTableMap) { Table->EntriesBegin = new __tgt_offload_entry[TableResponse.entries_size()]; auto *CurEntry = Table->EntriesBegin; for (size_t I = 0; I < TableResponse.entries_size(); I++) { copyOffloadEntry(TableResponse.entries()[I], CurEntry); HostToRemoteTargetTableMap[CurEntry->addr] = (void *)TableResponse.entry_ptrs()[I]; CurEntry++; } Table->EntriesEnd = CurEntry; } void copyOffloadEntry(const TargetOffloadEntry &EntryResponse, __tgt_offload_entry *Entry) { Entry->name = strdup(EntryResponse.name().c_str()); Entry->reserved = EntryResponse.reserved(); Entry->flags = EntryResponse.flags(); Entry->addr = strdup(EntryResponse.data().c_str()); Entry->size = EntryResponse.data().size(); } void copyOffloadEntry(const DeviceOffloadEntry &EntryResponse, __tgt_offload_entry *Entry) { Entry->name = strdup(EntryResponse.name().c_str()); Entry->reserved = EntryResponse.reserved(); Entry->flags = EntryResponse.flags(); Entry->addr = (void *)EntryResponse.addr(); Entry->size = EntryResponse.size(); } /// We shallow copy with just the name because it is a convenient identifier, we /// do actually just match off of the address. void shallowCopyOffloadEntry(const __tgt_offload_entry *Entry, TargetOffloadEntry *EntryResponse) { EntryResponse->set_name(Entry->name); } void copyOffloadEntry(const __tgt_offload_entry *Entry, TargetOffloadEntry *EntryResponse) { shallowCopyOffloadEntry(Entry, EntryResponse); EntryResponse->set_reserved(Entry->reserved); EntryResponse->set_flags(Entry->flags); EntryResponse->set_data(Entry->addr, Entry->size); } /// Dumps the memory region from Start to End in order to debug memory transfer /// errors within the plugin void dump(const void *Start, const void *End) { unsigned char Line[17]; const unsigned char *PrintCharacter = (const unsigned char *)Start; unsigned int I = 0; for (; I < ((const int *)End - (const int *)Start); I++) { if ((I % 16) == 0) { if (I != 0) printf(" %s\n", Line); printf(" %04x ", I); } printf(" %02x", PrintCharacter[I]); if ((PrintCharacter[I] < 0x20) || (PrintCharacter[I] > 0x7e)) Line[I % 16] = '.'; else Line[I % 16] = PrintCharacter[I]; Line[(I % 16) + 1] = '\0'; } while ((I % 16) != 0) { printf(" "); I++; } printf(" %s\n", Line); } void dump(__tgt_offload_entry *Entry) { fprintf(stderr, "Entry (%p):\n", (void *)Entry); fprintf(stderr, " Name: %s (%p)\n", Entry->name, (void *)&Entry->name); fprintf(stderr, " Reserved: %d (%p)\n", Entry->reserved, (void *)&Entry->reserved); fprintf(stderr, " Flags: %d (%p)\n", Entry->flags, (void *)&Entry->flags); fprintf(stderr, " Addr: %p\n", Entry->addr); fprintf(stderr, " Size: %lu\n", Entry->size); } void dump(__tgt_target_table *Table) { for (auto *CurEntry = Table->EntriesBegin; CurEntry != Table->EntriesEnd; CurEntry++) dump(CurEntry); } void dump(TargetOffloadEntry Entry) { fprintf(stderr, "Entry: "); fprintf(stderr, " Name: %s\n", Entry.name().c_str()); fprintf(stderr, " Reserved: %d\n", Entry.reserved()); fprintf(stderr, " Flags: %d\n", Entry.flags()); fprintf(stderr, " Size: %ld\n", Entry.data().size()); dump(static_cast(Entry.data().data()), static_cast((Entry.data().c_str() + Entry.data().size()))); } void dump(__tgt_device_image *Image) { dump(Image->ImageStart, Image->ImageEnd); __tgt_offload_entry *EntryItr = Image->EntriesBegin; for (; EntryItr != Image->EntriesEnd; EntryItr++) dump(EntryItr); } void dump(std::unordered_map &Map) { fprintf(stderr, "Host to Remote Entry Map:\n"); for (auto Entry : Map) fprintf(stderr, " Host (%p) -> Tgt (%p): Addr((%p))\n", Entry.first, (void *)Entry.second, (void *)Entry.second->addr); } } // namespace RemoteOffloading