Skip to content

Commit c7000de

Browse files
committed
Add function to generate valid JSON
This also made the generators public static methods, so they can be used. I had to correct a previous mistake, that the memory regions also need to be passed into the the function so it doesn't depend on a local existing object (as then you couldn't pass in own functions).
1 parent a6247e6 commit c7000de

3 files changed

Lines changed: 93 additions & 22 deletions

File tree

examples/basic/normal.cu

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ int main(){
4747
checkCudaError(cudaGetLastError());
4848
cudaDeviceSynchronize();
4949

50-
memAccessStorage.generateOutput("../../../html/basic_template.html", "../../../out/basic.html");
50+
memAccessStorage.generateOutput("../../../html/template.json", "../../../out/basic.json", CudaMemAccessStorage<int>::parseDataForJSPage);
5151

5252
checkCudaError(cudaMemcpy(h_output.data(), d_output, sizeof(int)*prob_size, cudaMemcpyDeviceToHost));
5353

html/template.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// JS_TEMPLATE

include/cuda_mav.cuh

Lines changed: 91 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)