@@ -89,9 +89,6 @@ private:
8989 // Store the memory regions by storing the starting address, the amount of elements, the size of a single element and a name
9090 std::vector<std::tuple<T*, size_t , size_t , std::string>> memoryRegions;
9191
92- // Store if memory was fetched from the device
93- bool fetchedFromDevice = false ;
94-
9592 // Helper function to format and throw CUDA errors
9693 void checkCudaError (cudaError_t err, std::string const &message = " Cuda Error." ) {
9794 if (err != cudaSuccess) {
@@ -100,11 +97,12 @@ private:
10097 }
10198 }
10299
100+ public:
103101 // Define the default function for basic HTML processing
104102 // The first element in the tuple is the HTML code, the second the JS code
105103 // For this function the second will be empty
106- std::tuple<std::string, std::string>
107- parseDataForStaticHTML (GlobalSettings settingsStruct, std::vector<MemoryAccessLog> accessLogs) {
104+ static std::tuple<std::string, std::string>
105+ parseDataForStaticHTML (GlobalSettings settingsStruct,std::vector<std::tuple<T*, size_t , size_t , std::string>> memoryRegions, std::vector<MemoryAccessLog> accessLogs) {
108106
109107 std::stringstream htmlStream;
110108
@@ -168,23 +166,98 @@ private:
168166 // Define the default function for basic HTML processing
169167 // The first element in the tuple is the HTML code, the second the JS code
170168 // For this function the first will be empty
171- std::tuple<std::string, std::string>
172- parseDataForJSPage (GlobalSettings settingsStruct, std::vector<MemoryAccessLog> accessLogs) {
169+ static std::tuple<std::string, std::string>
170+ parseDataForJSPage (GlobalSettings settingsStruct,std::vector<std::tuple<T*, size_t , size_t , std::string>> memoryRegions, std::vector<MemoryAccessLog> accessLogs) {
173171
174172 std::stringstream jsStream;
175173
174+ // Create a JSON object which describes all the available data
175+ // We will have one key GlobalSettings, one key MemoryRegions, and one key MemoryAccessLogs
176+
177+ // Start the JSON object
178+ jsStream << " {" ;
179+
180+ // Add the GlobalSettings key
181+ jsStream << " \" GlobalSettings\" : {" ;
182+
183+ // Store all settings
184+
185+ // First store the grid dimensions
186+ jsStream << " \" GridDimensions\" : {" ;
187+ jsStream << " \" x\" : " << settingsStruct.gridDimX << " ," ;
188+ jsStream << " \" y\" : " << settingsStruct.gridDimY << " ," ;
189+ jsStream << " \" z\" : " << settingsStruct.gridDimZ ;
190+ jsStream << " }," ;
191+
192+ // Then store the block dimensions
193+ jsStream << " \" BlockDimensions\" : {" ;
194+ jsStream << " \" x\" : " << settingsStruct.blockDimX << " ," ;
195+ jsStream << " \" y\" : " << settingsStruct.blockDimY << " ," ;
196+ jsStream << " \" z\" : " << settingsStruct.blockDimZ ;
197+ jsStream << " }," ;
198+
199+ // Then store the warp size
200+ jsStream << " \" WarpSize\" : " << settingsStruct.warpSize ;
201+
202+ // Close the GlobalSettings object
203+ jsStream << " }," ;
204+
205+ // Add the MemoryRegions key
206+ jsStream << " \" MemoryRegions\" : [" ;
207+
208+ // Loop through all memory regions and store them
209+ for (auto region : memoryRegions) {
210+ // Store the start address, number of elements and the size of a single element
211+ jsStream << " {" ;
212+ jsStream << " \" StartAddress\" : \" " << std::hex << std::get<0 >(region) << " \" ," ;
213+ jsStream << " \" EndAddress\" : \" " << std::get<0 >(region) + std::get<1 >(region) * std::get<2 >(region) << " \" ," ;
214+ jsStream << " \" NumberOfElements\" : " << std::dec << std::get<1 >(region) << " ," ;
215+ jsStream << " \" SizeOfSingleElement\" : " << std::get<2 >(region) << " ," ;
216+ jsStream << " \" Name\" : \" " << std::get<3 >(region) << " \" " ;
217+ jsStream << " }" ;
218+
219+ // If this is not the last element, add a comma
220+ if (region != memoryRegions.back ()) {
221+ jsStream << " ," ;
222+ }
223+ }
224+
225+ // Close the MemoryRegions array
226+ jsStream << " ]," ;
227+
228+ // Add the MemoryAccessLogs key
229+ jsStream << " \" MemoryAccessLogs\" : [" ;
230+
231+ // Loop through all memory access logs and store them
232+ // To save on storage space and parsing time (as this is the biggest part of the data) we store an array with the data
233+ // entries directly instead of using an object with names for each entry
234+ for (auto &log: accessLogs) {
235+ jsStream << " [" ;
236+ jsStream << " \" " << std::hex << log.Address () << " \" ," ;
237+ jsStream << std::dec << log.BlockId () << " ," ;
238+ jsStream << log.ThreadId () << " ," ;
239+ jsStream << (log.IsRead () ? " true" : " false" );
240+ jsStream << " ]" ;
241+
242+ // If this is not the last element, add a comma
243+ if (&log != &accessLogs.back ()) {
244+ jsStream << " ," ;
245+ }
246+ }
247+
248+ // Close the MemoryAccessLogs array
249+ jsStream << " ]" ;
250+
251+ // Close the JSON object
252+ jsStream << " }" ;
253+
254+ // Return the JS code
176255 return std::make_tuple (" " , jsStream.str ());
177256 }
178257
179-
258+ private:
180259 // Define function to load back data
181260 void fetchData () {
182- // Check if data was fetched from the device
183- if (fetchedFromDevice) {
184- // If so, return
185- return ;
186- }
187-
188261 // First fetch the h_constantData from the device
189262 checkCudaError (cudaMemcpy (h_constantData, d_constantData, sizeof (GlobalSettings), cudaMemcpyDeviceToHost),
190263 " Could not copy constant data from device." );
@@ -193,9 +266,6 @@ private:
193266 checkCudaError (
194267 cudaMemcpy (h_memoryAccessLog, d_memoryAccessLog, sizeof (MemoryAccessLog) * h_constantData->originalSize ,
195268 cudaMemcpyDeviceToHost), " Could not copy memory access logs from device." );
196-
197- // Set the fetched from device flag to true
198- fetchedFromDevice = true ;
199269 }
200270
201271 __device__ int getStorageIndex () {// Atomically increase the currentSize by 1
@@ -305,10 +375,10 @@ public:
305375 }
306376 }
307377
308- // Function to analyze the data which also frees up all used memory
378+ // Function to analyze the data which also frees up all used memory
309379 // As third parameter a function lambda can be passed which is called for each memory access
310380 void generateOutput (const std::string template_file, const std::string &output_path,
311- std::function<std::tuple<std::string, std::string>(GlobalSettings settingsStruct,
381+ std::function<std::tuple<std::string, std::string>(GlobalSettings settingsStruct, std::vector<std::tuple<T*, size_t , size_t , std::string>> memoryRegions,
312382 std::vector<MemoryAccessLog> accessLogs)> customGenerationFunction = nullptr) {
313383 // Fetch the data back from the device
314384 fetchData ();
@@ -339,11 +409,11 @@ public:
339409
340410 // Run the custom generation function, if one was passed
341411 if (customGenerationFunction != nullptr ) {
342- placeholderReplacement = customGenerationFunction (*h_constantData, accessLogs);
412+ placeholderReplacement = customGenerationFunction (*h_constantData, memoryRegions, accessLogs);
343413 }
344414 // If none was passed, use a default function
345415 else {
346- placeholderReplacement = parseDataForStaticHTML (*h_constantData, accessLogs);
416+ placeholderReplacement = parseDataForStaticHTML (*h_constantData, memoryRegions, accessLogs);
347417 }
348418
349419 // Replace "<!-- HTML_TEMPLATE -->" with the HTML template
0 commit comments