16 #if defined(_WIN32) && !defined(__MINGW32__)
46 static std::atomic<size_t> NumErrors;
53 const char *PluginList = getenv(
"TALVOS_PLUGINS");
56 std::istringstream SS(PluginList);
58 while (std::getline(SS, LibPath,
';'))
60 #if defined(_WIN32) && !defined(__MINGW32__)
62 HMODULE Library = LoadLibraryA(LibPath.c_str());
65 std::cerr <<
"Talvos: Failed to load plugin '" << LibPath <<
"' - "
66 << GetLastError() << std::endl;
71 void *Create = GetProcAddress(Library,
"talvosCreatePlugin");
74 std::cerr <<
"Talvos: Failed to load plugin '" << LibPath <<
"' - "
75 << GetLastError() << std::endl;
80 void *Library = dlopen(LibPath.c_str(), RTLD_NOW);
83 std::cerr <<
"Talvos: Failed to load plugin '" << LibPath <<
"' - "
84 << dlerror() << std::endl;
89 void *Create = dlsym(Library,
"talvosCreatePlugin");
92 std::cerr <<
"Talvos: Failed to load plugin '" << LibPath <<
"' - "
93 << dlerror() << std::endl;
100 Plugins.push_back({Library, P});
115 #if defined(_WIN32) && !defined(__MINGW32__)
116 void *Destroy = GetProcAddress((HMODULE)P.first,
"talvosDestroyPlugin");
119 FreeLibrary((HMODULE)P.first);
121 void *Destroy = dlsym(P.first,
"talvosDestroyPlugin");
135 if (!P.second->isThreadSafe())
142 std::unique_lock<std::mutex> Lock(
FenceMutex);
149 size_t ErrorIdx = NumErrors++;
154 static std::mutex ErrorMutex;
155 std::lock_guard<std::mutex> Lock(ErrorMutex);
157 std::cerr << std::endl;
158 std::cerr << Error << std::endl;
165 std::cerr <<
" Entry point:";
166 std::cerr <<
" %" << EP->
getId();
167 std::cerr <<
" " << EP->
getName();
168 std::cerr << std::endl;
175 std::cerr <<
" Invocation:";
185 std::cerr <<
" Group: " << Group->
getGroupId();
189 std::cerr <<
" <entity unknown>";
191 std::cerr << std::endl;
201 std::cerr <<
" <location unknown>";
204 std::cerr << std::endl;
208 std::cerr <<
" <origin unknown>" << std::endl;
211 std::cerr << std::endl;
216 std::cerr <<
"WARNING: " <<
MaxErrors <<
" errors reported - "
217 <<
"suppressing further errors" << std::endl;
218 std::cerr <<
"(configure this limit with TALVOS_MAX_ERRORS)" << std::endl;
219 std::cerr << std::endl;
228 #define REPORT(func, ...) \
229 for (auto &P : Plugins) \
231 P.second->func(__VA_ARGS__); \
235 uint64_t NumBytes, uint32_t Opcode,
236 uint32_t Scope, uint32_t Semantics)
240 REPORT(atomicAccess, Mem, Address, NumBytes, Opcode, Scope, Semantics, Invoc);
245 REPORT(commandBegin, Cmd);
250 REPORT(commandComplete, Cmd);
256 REPORT(instructionExecuted, Invoc, Inst);
261 REPORT(invocationBegin, Invoc);
266 REPORT(invocationComplete, Invoc);
277 REPORT(memoryLoad, Mem, Address, NumBytes, I);
281 REPORT(hostMemoryLoad, Mem, Address, NumBytes);
286 uint64_t Offset, uint64_t NumBytes)
288 REPORT(memoryMap, Memory, Base, Offset, NumBytes);
292 uint64_t NumBytes,
const uint8_t *Data)
299 REPORT(memoryStore, Mem, Address, NumBytes, Data, I);
303 REPORT(hostMemoryStore, Mem, Address, NumBytes, Data);
309 REPORT(memoryUnmap, Memory, Base);
314 REPORT(workgroupBegin, Group);
319 REPORT(workgroupBarrier, Group);
324 REPORT(workgroupComplete, Group);
330 bool WaitAll, uint64_t Timeout)
const
333 auto Start = std::chrono::system_clock::now();
337 std::unique_lock<std::mutex> Lock(
FenceMutex);
340 uint32_t SignalCount = 0;
341 for (
const auto Fence : Fences)
346 if (WaitAll ? SignalCount == (uint32_t)(Fences.size()) : SignalCount > 0)
350 auto Duration = std::chrono::system_clock::now() - Start;
351 auto DurationNanoseconds =
352 std::chrono::duration_cast<std::chrono::nanoseconds>(Duration);
353 uint64_t ElapsedTime = DurationNanoseconds.count();
354 if (ElapsedTime >= Timeout)
359 Lock, std::chrono::nanoseconds((uint64_t)(Timeout - ElapsedTime)));
This file declares the Workgroup class.
This file declares the ComputePipeline class.
void reportError(const std::string &Error, bool Fatal=false)
Report an error that has occurred during emulation.
unsigned long getEnvUInt(const char *Name, unsigned Default)
Returns the integer value for the environment variable Name, or Default if it is not set...
This file declares the Device class.
Dim3 getGroupId() const
Returns the group ID of this workgroup.
Only allow Device objects to create PipelineExecutor instances.
bool isWorkerThread() const
Returns true if the calling thread is a PipelineExecutor worker thread.
Base class for Talvos plugins.
void notifyFenceSignaled()
Notify the device that a fence was signaled.
This file declares the Module class.
std::vector< std::pair< void *, Plugin * > > Plugins
List of plugins that are currently loaded.
uint32_t getId() const
Returns the SPIR-V result ID of this entry point.
This file declares the EntryPoint class.
const Invocation * getCurrentInvocation() const
Returns the current invocation being executed.
void reportMemoryMap(const Memory *Mem, uint64_t Base, uint64_t Offset, uint64_t NumBytes)
void signalError()
Signal that an error has occurred, breaking the interactive debugger.
Plugin *(* CreatePluginFunc)(const Device *)
const EntryPoint * getEntryPoint() const
Return the entry point this pipeline stage will invoke.
void reportInvocationComplete(const Invocation *Invoc)
void reportWorkgroupComplete(const Workgroup *Group)
const PipelineStage & getCurrentStage() const
Returns the pipeline stage that is currently being executed.
const Workgroup * getCurrentWorkgroup() const
Returns the current workgroup being executed.
std::condition_variable FenceSignaled
Condition variable to notify threads waiting on fence signals.
This class is a base class for all commands.
This class represents a single execution of a SPIR-V entry point.
This file declares the Plugin class.
PipelineExecutor * Executor
The pipeline executor instance.
This file declares miscellaneous utilities used internally by libtalvos.
Memory * GlobalMemory
The global memory of this device.
This file declares the Instruction class.
size_t MaxErrors
The maximum number of errors to report.
const std::string & getName() const
Returns the name of this entry point.
void reportCommandBegin(const Command *Cmd)
This file declares the PipelineExecutor class.
This class represents an address space in the virtual device.
void print(std::ostream &O, bool Align=true) const
Print a human-readable form of this instruction to O.
MemoryScope getScope() const
Get the scope of this memory instance.
This file declares the PipelineStage class.
An internal class that handles pipeline execution, including the interactive debugger.
bool waitForFences(const std::vector< const bool * > &Fences, bool WaitAll, uint64_t Timeout) const
Wait for fences to signal.
void reportWorkgroupBarrier(const Workgroup *Group)
std::mutex FenceMutex
A mutex for synchronizing threads waiting on fence signals.
A Device instance encapsulates properties and state for the virtual device.
This class represents a workgroup executing a compute command.
This class encapsulates information about a pipeline stage.
void reportInvocationBegin(const Invocation *Invoc)
This file declares the Memory class.
void reportMemoryStore(const Memory *Mem, uint64_t Address, uint64_t NumBytes, const uint8_t *Data)
const Instruction * getCurrentInstruction() const
Returns the instruction that this invocation is executing.
Dim3 getGroupSize() const
Return the workgroup size.
void reportAtomicAccess(const Memory *Mem, uint64_t Address, uint64_t NumBytes, uint32_t Opcode, uint32_t Scope, uint32_t Semantics)
This file declares the Command base class and its subclasses.
bool isThreadSafe() const
Returns true if all of the loaded plugins are thread-safe.
This file declares the Function class.
This file declares the Invocation class.
Dim3 getGlobalId() const
Returns the global invocation ID.
void reportCommandComplete(const Command *Cmd)
void reportMemoryLoad(const Memory *Mem, uint64_t Address, uint64_t NumBytes)
This class represents a SPIR-V instruction.
void reportWorkgroupBegin(const Workgroup *Group)
void reportMemoryUnmap(const Memory *Mem, uint64_t Base)
void(* DestroyPluginFunc)(Plugin *)
This class represents a shader entry point.
void reportInstructionExecuted(const Invocation *Invoc, const Instruction *Inst)