1 //===---------------- Utils.cpp - Utilities for Remote RTL ----------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Utilities for data movement and debugging.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "Utils.h"
14 #include "omptarget.h"
15 
16 namespace RemoteOffloading {
17 void parseEnvironment(RPCConfig &Config) {
18   // TODO: Error handle for incorrect inputs
19   if (const char *Env = std::getenv("LIBOMPTARGET_RPC_ADDRESS")) {
20     Config.ServerAddresses.clear();
21     std::string AddressString = Env;
22     const std::string Delimiter = ",";
23 
24     size_t Pos = 0;
25     std::string Token;
26     while ((Pos = AddressString.find(Delimiter)) != std::string::npos) {
27       Token = AddressString.substr(0, Pos);
28       Config.ServerAddresses.push_back(Token);
29       AddressString.erase(0, Pos + Delimiter.length());
30     }
31     Config.ServerAddresses.push_back(AddressString);
32   }
33   if (const char *Env = std::getenv("LIBOMPTARGET_RPC_ALLOCATOR_MAX"))
34     Config.MaxSize = std::stoi(Env);
35   if (const char *Env = std::getenv("LIBOMPTARGET_RPC_BLOCK_SIZE"))
36     Config.BlockSize = std::stoi(Env);
37 }
38 
39 void loadTargetBinaryDescription(const __tgt_bin_desc *Desc,
40                                  TargetBinaryDescription &Request) {
41   // Keeps track of entries which have already been deep copied.
42   std::vector<void *> DeepCopiedEntryAddrs;
43 
44   // Copy Global Offload Entries
45   for (auto *CurEntry = Desc->HostEntriesBegin;
46        CurEntry != Desc->HostEntriesEnd; CurEntry++) {
47     auto *NewEntry = Request.add_entries();
48     copyOffloadEntry(CurEntry, NewEntry);
49 
50     // Copy the pointer of the offload entry of the image into the Request
51     Request.add_entry_ptrs((uint64_t)CurEntry);
52     DeepCopiedEntryAddrs.push_back(CurEntry);
53   }
54 
55   // Copy Device Images and Device Offload Entries
56   __tgt_device_image *CurImage = Desc->DeviceImages;
57   for (auto I = 0; I < Desc->NumDeviceImages; I++, CurImage++) {
58     auto *Image = Request.add_images();
59     auto Size = (char *)CurImage->ImageEnd - (char *)CurImage->ImageStart;
60     Image->set_binary(CurImage->ImageStart, Size);
61 
62     // Copy the pointer of the image into the Request
63     auto *NewImagePtr = Request.add_image_ptrs();
64     NewImagePtr->set_img_ptr((uint64_t)CurImage->ImageStart);
65 
66     // Copy Device Offload Entries
67     for (auto *CurEntry = CurImage->EntriesBegin;
68          CurEntry != CurImage->EntriesEnd; CurEntry++) {
69       auto *NewEntry = Image->add_entries();
70 
71       auto Entry = std::find(DeepCopiedEntryAddrs.begin(),
72                              DeepCopiedEntryAddrs.end(), CurEntry);
73       if (Entry != DeepCopiedEntryAddrs.end()) {
74         // Offload entry has already been loaded
75         shallowCopyOffloadEntry(CurEntry, NewEntry);
76       } else { // Offload Entry has not been loaded into the Request
77         copyOffloadEntry(CurEntry, NewEntry);
78         DeepCopiedEntryAddrs.push_back(CurEntry);
79       }
80 
81       // Copy the pointer of the offload entry of the image into the Request
82       NewImagePtr->add_entry_ptrs((uint64_t)CurEntry);
83     }
84   }
85 }
86 
87 void unloadTargetBinaryDescription(
88     const TargetBinaryDescription *Request, __tgt_bin_desc *Desc,
89     std::unordered_map<const void *, __tgt_device_image *>
90         &HostToRemoteDeviceImage) {
91   std::unordered_map<const void *, __tgt_offload_entry *> CopiedOffloadEntries;
92   Desc->NumDeviceImages = Request->images_size();
93   Desc->DeviceImages = new __tgt_device_image[Desc->NumDeviceImages];
94 
95   if (Request->entries_size())
96     Desc->HostEntriesBegin = new __tgt_offload_entry[Request->entries_size()];
97   else {
98     Desc->HostEntriesBegin = nullptr;
99     Desc->HostEntriesEnd = nullptr;
100   }
101 
102   // Copy Global Offload Entries
103   __tgt_offload_entry *CurEntry = Desc->HostEntriesBegin;
104   for (int i = 0; i < Request->entries_size(); i++) {
105     copyOffloadEntry(Request->entries()[i], CurEntry);
106     CopiedOffloadEntries[(void *)Request->entry_ptrs()[i]] = CurEntry;
107     CurEntry++;
108   }
109   Desc->HostEntriesEnd = CurEntry;
110 
111   // Copy Device Images and Device Offload Entries
112   __tgt_device_image *CurImage = Desc->DeviceImages;
113   auto ImageItr = Request->image_ptrs().begin();
114   for (auto Image : Request->images()) {
115     // Copy Device Offload Entries
116     auto *CurEntry = Desc->HostEntriesBegin;
117     bool Found = false;
118 
119     if (!Desc->HostEntriesBegin) {
120       CurImage->EntriesBegin = nullptr;
121       CurImage->EntriesEnd = nullptr;
122     }
123 
124     for (int i = 0; i < Image.entries_size(); i++) {
125       auto TgtEntry =
126           CopiedOffloadEntries.find((void *)Request->entry_ptrs()[i]);
127       if (TgtEntry != CopiedOffloadEntries.end()) {
128         if (!Found)
129           CurImage->EntriesBegin = CurEntry;
130 
131         Found = true;
132         if (Found) {
133           CurImage->EntriesEnd = CurEntry + 1;
134         }
135       } else {
136         Found = false;
137         copyOffloadEntry(Image.entries()[i], CurEntry);
138         CopiedOffloadEntries[(void *)(Request->entry_ptrs()[i])] = CurEntry;
139       }
140       CurEntry++;
141     }
142 
143     // Copy Device Image
144     CurImage->ImageStart = new uint8_t[Image.binary().size()];
145     memcpy(CurImage->ImageStart,
146            static_cast<const void *>(Image.binary().data()),
147            Image.binary().size());
148     CurImage->ImageEnd =
149         (void *)((char *)CurImage->ImageStart + Image.binary().size());
150 
151     HostToRemoteDeviceImage[(void *)ImageItr->img_ptr()] = CurImage;
152     CurImage++;
153     ImageItr++;
154   }
155 }
156 
157 void freeTargetBinaryDescription(__tgt_bin_desc *Desc) {
158   __tgt_device_image *CurImage = Desc->DeviceImages;
159   for (auto I = 0; I < Desc->NumDeviceImages; I++, CurImage++)
160     delete[](uint64_t *) CurImage->ImageStart;
161 
162   delete[] Desc->DeviceImages;
163 
164   for (auto *Entry = Desc->HostEntriesBegin; Entry != Desc->HostEntriesEnd;
165        Entry++) {
166     free(Entry->name);
167     free(Entry->addr);
168   }
169 
170   delete[] Desc->HostEntriesBegin;
171 }
172 
173 void freeTargetTable(__tgt_target_table *Table) {
174   for (auto *Entry = Table->EntriesBegin; Entry != Table->EntriesEnd; Entry++)
175     free(Entry->name);
176 
177   delete[] Table->EntriesBegin;
178 }
179 
180 void loadTargetTable(__tgt_target_table *Table, TargetTable &TableResponse,
181                      __tgt_device_image *Image) {
182   auto *ImageEntry = Image->EntriesBegin;
183   for (__tgt_offload_entry *CurEntry = Table->EntriesBegin;
184        CurEntry != Table->EntriesEnd; CurEntry++, ImageEntry++) {
185     // TODO: This can probably be trimmed substantially.
186     auto *NewEntry = TableResponse.add_entries();
187     NewEntry->set_name(CurEntry->name);
188     NewEntry->set_addr((uint64_t)CurEntry->addr);
189     NewEntry->set_flags(CurEntry->flags);
190     NewEntry->set_reserved(CurEntry->reserved);
191     NewEntry->set_size(CurEntry->size);
192     TableResponse.add_entry_ptrs((int64_t)CurEntry);
193   }
194 }
195 
196 void unloadTargetTable(
197     TargetTable &TableResponse, __tgt_target_table *Table,
198     std::unordered_map<void *, void *> &HostToRemoteTargetTableMap) {
199   Table->EntriesBegin = new __tgt_offload_entry[TableResponse.entries_size()];
200 
201   auto *CurEntry = Table->EntriesBegin;
202   for (int i = 0; i < TableResponse.entries_size(); i++) {
203     copyOffloadEntry(TableResponse.entries()[i], CurEntry);
204     HostToRemoteTargetTableMap[CurEntry->addr] =
205         (void *)TableResponse.entry_ptrs()[i];
206     CurEntry++;
207   }
208   Table->EntriesEnd = CurEntry;
209 }
210 
211 void copyOffloadEntry(const TargetOffloadEntry &EntryResponse,
212                       __tgt_offload_entry *Entry) {
213   Entry->name = strdup(EntryResponse.name().c_str());
214   Entry->reserved = EntryResponse.reserved();
215   Entry->flags = EntryResponse.flags();
216   Entry->addr = strdup(EntryResponse.data().c_str());
217   Entry->size = EntryResponse.data().size();
218 }
219 
220 void copyOffloadEntry(const DeviceOffloadEntry &EntryResponse,
221                       __tgt_offload_entry *Entry) {
222   Entry->name = strdup(EntryResponse.name().c_str());
223   Entry->reserved = EntryResponse.reserved();
224   Entry->flags = EntryResponse.flags();
225   Entry->addr = (void *)EntryResponse.addr();
226   Entry->size = EntryResponse.size();
227 }
228 
229 /// We shallow copy with just the name because it is a convenient identifier, we
230 /// do actually just match off of the address.
231 void shallowCopyOffloadEntry(const __tgt_offload_entry *Entry,
232                              TargetOffloadEntry *EntryResponse) {
233   EntryResponse->set_name(Entry->name);
234 }
235 
236 void copyOffloadEntry(const __tgt_offload_entry *Entry,
237                       TargetOffloadEntry *EntryResponse) {
238   shallowCopyOffloadEntry(Entry, EntryResponse);
239   EntryResponse->set_reserved(Entry->reserved);
240   EntryResponse->set_flags(Entry->flags);
241   EntryResponse->set_data(Entry->addr, Entry->size);
242 }
243 
244 /// Dumps the memory region from Start to End in order to debug memory transfer
245 /// errors within the plugin
246 void dump(const void *Start, const void *End) {
247   unsigned char Line[17];
248   const unsigned char *PrintCharacter = (const unsigned char *)Start;
249 
250   unsigned int I = 0;
251   for (; I < ((const int *)End - (const int *)Start); I++) {
252     if ((I % 16) == 0) {
253       if (I != 0)
254         printf("  %s\n", Line);
255 
256       printf("  %04x ", I);
257     }
258 
259     printf(" %02x", PrintCharacter[I]);
260 
261     if ((PrintCharacter[I] < 0x20) || (PrintCharacter[I] > 0x7e))
262       Line[I % 16] = '.';
263     else
264       Line[I % 16] = PrintCharacter[I];
265 
266     Line[(I % 16) + 1] = '\0';
267   }
268 
269   while ((I % 16) != 0) {
270     printf("   ");
271     I++;
272   }
273 
274   printf("  %s\n", Line);
275 }
276 
277 void dump(__tgt_offload_entry *Entry) {
278   fprintf(stderr, "Entry (%p):\n", (void *)Entry);
279   fprintf(stderr, "  Name: %s (%p)\n", Entry->name, (void *)&Entry->name);
280   fprintf(stderr, "  Reserved: %d (%p)\n", Entry->reserved,
281           (void *)&Entry->reserved);
282   fprintf(stderr, "  Flags: %d (%p)\n", Entry->flags, (void *)&Entry->flags);
283   fprintf(stderr, "  Addr: %p\n", Entry->addr);
284   fprintf(stderr, "  Size: %lu\n", Entry->size);
285 }
286 
287 void dump(__tgt_target_table *Table) {
288   for (auto *CurEntry = Table->EntriesBegin; CurEntry != Table->EntriesEnd;
289        CurEntry++)
290     dump(CurEntry);
291 }
292 
293 void dump(TargetOffloadEntry Entry) {
294   fprintf(stderr, "Entry: ");
295   fprintf(stderr, "    %s\n", Entry.name().c_str());
296   fprintf(stderr, "    %d\n", Entry.reserved());
297   fprintf(stderr, "    %d\n", Entry.flags());
298   fprintf(stderr, "    %ld\n", Entry.data().size());
299   dump(static_cast<const void *>(Entry.data().data()),
300        static_cast<const void *>((Entry.data().c_str() + Entry.data().size())));
301 }
302 
303 void dump(__tgt_device_image *Image) {
304   dump(Image->ImageStart, Image->ImageEnd);
305   __tgt_offload_entry *EntryItr = Image->EntriesBegin;
306   for (; EntryItr != Image->EntriesEnd; EntryItr++)
307     dump(EntryItr);
308 }
309 
310 void dump(std::unordered_map<void *, __tgt_offload_entry *> &Map) {
311   fprintf(stderr, "Host to Remote Entry Map:\n");
312   for (auto Entry : Map)
313     fprintf(stderr, "  Host (%p) -> Tgt (%p): Addr((%p))\n", Entry.first,
314             (void *)Entry.second, (void *)Entry.second->addr);
315 }
316 } // namespace RemoteOffloading