1 #include <petscviewer.h> 2 #include "lognested.h" 3 #include "xmlviewer.h" 4 5 PETSC_INTERN PetscErrorCode PetscLogHandlerNestedSetThreshold(PetscLogHandler h, PetscLogDouble newThresh, PetscLogDouble *oldThresh) 6 { 7 PetscLogHandler_Nested nested = (PetscLogHandler_Nested)h->data; 8 9 PetscFunctionBegin; 10 if (oldThresh) *oldThresh = nested->threshold; 11 if (newThresh == (PetscLogDouble)PETSC_DECIDE) newThresh = 0.01; 12 if (newThresh == (PetscLogDouble)PETSC_DEFAULT) newThresh = 0.01; 13 nested->threshold = PetscMax(newThresh, 0.0); 14 PetscFunctionReturn(PETSC_SUCCESS); 15 } 16 17 static PetscErrorCode PetscLogEventGetNestedEvent(PetscLogHandler h, PetscLogEvent e, PetscLogEvent *nested_event) 18 { 19 PetscLogHandler_Nested nested = (PetscLogHandler_Nested)h->data; 20 NestedIdPair key; 21 PetscHashIter iter; 22 PetscBool missing; 23 PetscLogState state; 24 25 PetscFunctionBegin; 26 PetscCall(PetscLogHandlerGetState(h, &state)); 27 PetscCall(PetscIntStackTop(nested->nested_stack, &(key.root))); 28 key.leaf = NestedIdFromEvent(e); 29 PetscCall(PetscNestedHashPut(nested->pair_map, key, &iter, &missing)); 30 if (missing) { 31 // register a new nested event 32 char name[BUFSIZ]; 33 PetscLogEventInfo event_info; 34 PetscLogEventInfo nested_event_info; 35 36 PetscCall(PetscLogStateEventGetInfo(state, e, &event_info)); 37 PetscCall(PetscLogStateEventGetInfo(nested->state, key.root, &nested_event_info)); 38 PetscCall(PetscSNPrintf(name, sizeof(name) - 1, "%s;%s", nested_event_info.name, event_info.name)); 39 PetscCall(PetscLogStateEventRegister(nested->state, name, event_info.classid, nested_event)); 40 PetscCall(PetscNestedHashIterSet(nested->pair_map, iter, *nested_event)); 41 } else { 42 PetscCall(PetscNestedHashIterGet(nested->pair_map, iter, nested_event)); 43 } 44 PetscFunctionReturn(PETSC_SUCCESS); 45 } 46 47 static PetscErrorCode PetscLogStageGetNestedEvent(PetscLogHandler h, PetscLogStage stage, PetscLogEvent *nested_event) 48 { 49 PetscLogHandler_Nested nested = (PetscLogHandler_Nested)h->data; 50 NestedIdPair key; 51 PetscHashIter iter; 52 PetscBool missing; 53 PetscLogState state; 54 55 PetscFunctionBegin; 56 PetscCall(PetscLogHandlerGetState(h, &state)); 57 PetscCall(PetscIntStackTop(nested->nested_stack, &(key.root))); 58 key.leaf = NestedIdFromStage(stage); 59 PetscCall(PetscNestedHashPut(nested->pair_map, key, &iter, &missing)); 60 if (missing) { 61 PetscLogStageInfo stage_info; 62 char name[BUFSIZ]; 63 64 PetscCall(PetscLogStateStageGetInfo(state, stage, &stage_info)); 65 if (key.root >= 0) { 66 PetscLogEventInfo nested_event_info; 67 68 PetscCall(PetscLogStateEventGetInfo(nested->state, key.root, &nested_event_info)); 69 PetscCall(PetscSNPrintf(name, sizeof(name) - 1, "%s;%s", nested_event_info.name, stage_info.name)); 70 } else { 71 PetscCall(PetscSNPrintf(name, sizeof(name) - 1, "%s", stage_info.name)); 72 } 73 PetscCall(PetscLogStateEventRegister(nested->state, name, nested->nested_stage_id, nested_event)); 74 PetscCall(PetscNestedHashIterSet(nested->pair_map, iter, *nested_event)); 75 } else { 76 PetscCall(PetscNestedHashIterGet(nested->pair_map, iter, nested_event)); 77 } 78 PetscFunctionReturn(PETSC_SUCCESS); 79 } 80 81 static PetscErrorCode PetscLogNestedFindNestedId(PetscLogHandler h, NestedId orig_id, PetscInt *pop_count) 82 { 83 PetscLogHandler_Nested nested = (PetscLogHandler_Nested)h->data; 84 PetscInt count, i; 85 86 PetscFunctionBegin; 87 // stop before zero cause there is a null event at the bottom of the stack 88 for (i = nested->orig_stack->top, count = 0; i > 0; i--) { 89 count++; 90 if (nested->orig_stack->stack[i] == orig_id) break; 91 } 92 *pop_count = count; 93 if (count == 1) PetscFunctionReturn(PETSC_SUCCESS); // Normal function, just the top of the stack is being popped. 94 if (orig_id > 0) { 95 PetscLogEvent event_id = NestedIdToEvent(orig_id); 96 PetscLogState state; 97 PetscLogEventInfo event_info; 98 99 PetscCall(PetscLogHandlerGetState(h, &state)); 100 PetscCall(PetscLogStateEventGetInfo(state, event_id, &event_info)); 101 PetscCheck(i > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Tried to end event %s, but it is not in the event stack\n", event_info.name); 102 } else { 103 PetscLogStage stage_id = NestedIdToStage(orig_id); 104 PetscLogState state; 105 PetscLogStageInfo stage_info; 106 107 PetscCall(PetscLogHandlerGetState(h, &state)); 108 PetscCall(PetscLogStateStageGetInfo(state, stage_id, &stage_info)); 109 PetscCheck(i > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Tried to pop stage %s, but it is not in the stage stack\n", stage_info.name); 110 } 111 PetscFunctionReturn(PETSC_SUCCESS); 112 } 113 114 static PetscErrorCode PetscLogNestedCheckNested(PetscLogHandler h, NestedId leaf, PetscLogEvent nested_event) 115 { 116 PetscLogHandler_Nested nested = (PetscLogHandler_Nested)h->data; 117 NestedIdPair key; 118 NestedId val; 119 120 PetscFunctionBegin; 121 PetscCall(PetscIntStackTop(nested->nested_stack, &(key.root))); 122 key.leaf = leaf; 123 PetscCall(PetscNestedHashGet(nested->pair_map, key, &val)); 124 PetscCheck(val == nested_event, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Logging events and stages are not nested, nested logging cannot be used"); 125 PetscFunctionReturn(PETSC_SUCCESS); 126 } 127 128 static PetscErrorCode PetscLogHandlerEventBegin_Nested(PetscLogHandler h, PetscLogEvent e, PetscObject o1, PetscObject o2, PetscObject o3, PetscObject o4) 129 { 130 PetscLogHandler_Nested nested = (PetscLogHandler_Nested)h->data; 131 PetscLogEvent nested_event; 132 133 PetscFunctionBegin; 134 PetscCall(PetscLogEventGetNestedEvent(h, e, &nested_event)); 135 PetscCall(PetscLogHandlerEventBegin(nested->handler, nested_event, o1, o2, o3, o4)); 136 PetscCall(PetscIntStackPush(nested->nested_stack, nested_event)); 137 PetscCall(PetscIntStackPush(nested->orig_stack, NestedIdFromEvent(e))); 138 PetscFunctionReturn(PETSC_SUCCESS); 139 } 140 141 static PetscErrorCode PetscLogHandlerNestedEventEnd(PetscLogHandler h, NestedId id, PetscObject o1, PetscObject o2, PetscObject o3, PetscObject o4) 142 { 143 PetscLogHandler_Nested nested = (PetscLogHandler_Nested)h->data; 144 PetscInt pop_count; 145 146 PetscFunctionBegin; 147 PetscCall(PetscLogNestedFindNestedId(h, id, &pop_count)); 148 for (PetscInt c = 0; c < pop_count; c++) { 149 PetscLogEvent nested_event; 150 PetscLogEvent nested_id; 151 152 PetscCall(PetscIntStackPop(nested->nested_stack, &nested_event)); 153 PetscCall(PetscIntStackPop(nested->orig_stack, &nested_id)); 154 if (PetscDefined(USE_DEBUG)) PetscCall(PetscLogNestedCheckNested(h, nested_id, nested_event)); 155 if ((pop_count > 1) && (c + 1 < pop_count)) { 156 if (nested_id > 0) { 157 PetscLogEvent event_id = NestedIdToEvent(nested_id); 158 PetscLogState state; 159 PetscLogEventInfo event_info; 160 161 PetscCall(PetscLogHandlerGetState(h, &state)); 162 PetscCall(PetscLogStateEventGetInfo(state, event_id, &event_info)); 163 PetscCall(PetscInfo(h, "Log event %s wasn't ended, ending it to maintain stack property for nested log handler\n", event_info.name)); 164 } 165 } 166 PetscCall(PetscLogHandlerEventEnd(nested->handler, nested_event, o1, o2, o3, o4)); 167 } 168 PetscFunctionReturn(PETSC_SUCCESS); 169 } 170 171 static PetscErrorCode PetscLogHandlerEventEnd_Nested(PetscLogHandler h, PetscLogEvent e, PetscObject o1, PetscObject o2, PetscObject o3, PetscObject o4) 172 { 173 PetscFunctionBegin; 174 PetscCall(PetscLogHandlerNestedEventEnd(h, NestedIdFromEvent(e), o1, o2, o3, o4)); 175 PetscFunctionReturn(PETSC_SUCCESS); 176 } 177 178 static PetscErrorCode PetscLogHandlerEventSync_Nested(PetscLogHandler h, PetscLogEvent e, MPI_Comm comm) 179 { 180 PetscLogHandler_Nested nested = (PetscLogHandler_Nested)h->data; 181 PetscLogEvent nested_event; 182 183 PetscFunctionBegin; 184 PetscCall(PetscLogEventGetNestedEvent(h, e, &nested_event)); 185 PetscCall(PetscLogHandlerEventSync(nested->handler, nested_event, comm)); 186 PetscFunctionReturn(PETSC_SUCCESS); 187 } 188 189 static PetscErrorCode PetscLogHandlerStagePush_Nested(PetscLogHandler h, PetscLogStage stage) 190 { 191 PetscLogHandler_Nested nested = (PetscLogHandler_Nested)h->data; 192 PetscLogEvent nested_event; 193 194 PetscFunctionBegin; 195 if (nested->nested_stage_id == -1) PetscCall(PetscClassIdRegister("LogNestedStage", &nested->nested_stage_id)); 196 PetscCall(PetscLogStageGetNestedEvent(h, stage, &nested_event)); 197 PetscCall(PetscLogHandlerEventBegin(nested->handler, nested_event, NULL, NULL, NULL, NULL)); 198 PetscCall(PetscIntStackPush(nested->nested_stack, nested_event)); 199 PetscCall(PetscIntStackPush(nested->orig_stack, NestedIdFromStage(stage))); 200 PetscFunctionReturn(PETSC_SUCCESS); 201 } 202 203 static PetscErrorCode PetscLogHandlerStagePop_Nested(PetscLogHandler h, PetscLogStage stage) 204 { 205 PetscFunctionBegin; 206 PetscCall(PetscLogHandlerNestedEventEnd(h, NestedIdFromStage(stage), NULL, NULL, NULL, NULL)); 207 PetscFunctionReturn(PETSC_SUCCESS); 208 } 209 210 static PetscErrorCode PetscLogHandlerContextCreate_Nested(MPI_Comm comm, PetscLogHandler_Nested *nested_p) 211 { 212 PetscLogStage root_stage; 213 PetscLogHandler_Nested nested; 214 215 PetscFunctionBegin; 216 PetscCall(PetscNew(nested_p)); 217 nested = *nested_p; 218 PetscCall(PetscLogStateCreate(&nested->state)); 219 PetscCall(PetscIntStackCreate(&nested->nested_stack)); 220 PetscCall(PetscIntStackCreate(&nested->orig_stack)); 221 nested->nested_stage_id = -1; 222 nested->threshold = 0.01; 223 PetscCall(PetscNestedHashCreate(&nested->pair_map)); 224 PetscCall(PetscLogHandlerCreate(comm, &nested->handler)); 225 PetscCall(PetscLogHandlerSetType(nested->handler, PETSCLOGHANDLERDEFAULT)); 226 PetscCall(PetscLogHandlerSetState(nested->handler, nested->state)); 227 PetscCall(PetscLogStateStageRegister(nested->state, "", &root_stage)); 228 PetscAssert(root_stage == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "root stage not zero"); 229 PetscCall(PetscLogHandlerStagePush(nested->handler, root_stage)); 230 PetscCall(PetscLogStateStagePush(nested->state, root_stage)); 231 PetscCall(PetscIntStackPush(nested->nested_stack, -1)); 232 PetscCall(PetscIntStackPush(nested->orig_stack, -1)); 233 PetscFunctionReturn(PETSC_SUCCESS); 234 } 235 236 static PetscErrorCode PetscLogHandlerObjectCreate_Nested(PetscLogHandler h, PetscObject obj) 237 { 238 PetscClassId classid; 239 PetscInt num_registered, num_nested_registered; 240 PetscLogState state; 241 PetscLogHandler_Nested nested = (PetscLogHandler_Nested)h->data; 242 243 PetscFunctionBegin; 244 // register missing objects 245 PetscCall(PetscObjectGetClassId(obj, &classid)); 246 PetscCall(PetscLogHandlerGetState(h, &state)); 247 PetscCall(PetscLogStateGetNumClasses(nested->state, &num_nested_registered)); 248 PetscCall(PetscLogStateGetNumClasses(state, &num_registered)); 249 for (PetscLogClass c = num_nested_registered; c < num_registered; c++) { 250 PetscLogClassInfo class_info; 251 PetscLogClass nested_c; 252 253 PetscCall(PetscLogStateClassGetInfo(state, c, &class_info)); 254 PetscCall(PetscLogStateClassRegister(nested->state, class_info.name, class_info.classid, &nested_c)); 255 } 256 PetscCall(PetscLogHandlerObjectCreate(nested->handler, obj)); 257 PetscFunctionReturn(PETSC_SUCCESS); 258 } 259 260 static PetscErrorCode PetscLogHandlerObjectDestroy_Nested(PetscLogHandler h, PetscObject obj) 261 { 262 PetscLogHandler_Nested nested = (PetscLogHandler_Nested)h->data; 263 264 PetscFunctionBegin; 265 PetscCall(PetscLogHandlerObjectDestroy(nested->handler, obj)); 266 PetscFunctionReturn(PETSC_SUCCESS); 267 } 268 269 static PetscErrorCode PetscLogHandlerDestroy_Nested(PetscLogHandler h) 270 { 271 PetscLogHandler_Nested nested = (PetscLogHandler_Nested)h->data; 272 273 PetscFunctionBegin; 274 PetscCall(PetscLogStateStagePop(nested->state)); 275 PetscCall(PetscLogHandlerStagePop(nested->handler, 0)); 276 PetscCall(PetscLogStateDestroy(&nested->state)); 277 PetscCall(PetscIntStackDestroy(nested->nested_stack)); 278 PetscCall(PetscIntStackDestroy(nested->orig_stack)); 279 PetscCall(PetscNestedHashDestroy(&nested->pair_map)); 280 PetscCall(PetscLogHandlerDestroy(&nested->handler)); 281 PetscCall(PetscFree(nested)); 282 PetscFunctionReturn(PETSC_SUCCESS); 283 } 284 285 static PetscErrorCode PetscLogNestedEventNodesOrderDepthFirst(PetscInt num_nodes, PetscInt parent, PetscNestedEventNode tree[], PetscInt *num_descendants) 286 { 287 PetscInt node, start_loc; 288 PetscFunctionBegin; 289 290 node = 0; 291 start_loc = 0; 292 while (node < num_nodes) { 293 if (tree[node].parent == parent) { 294 PetscInt num_this_descendants = 0; 295 PetscNestedEventNode tmp = tree[start_loc]; 296 tree[start_loc] = tree[node]; 297 tree[node] = tmp; 298 PetscCall(PetscLogNestedEventNodesOrderDepthFirst(num_nodes - start_loc - 1, tree[start_loc].id, &tree[start_loc + 1], &num_this_descendants)); 299 tree[start_loc].num_descendants = num_this_descendants; 300 *num_descendants += 1 + num_this_descendants; 301 start_loc += 1 + num_this_descendants; 302 node = start_loc; 303 } else { 304 node++; 305 } 306 } 307 PetscFunctionReturn(PETSC_SUCCESS); 308 } 309 310 static PetscErrorCode PetscLogNestedCreatePerfNodes(MPI_Comm comm, PetscLogHandler_Nested nested, PetscLogGlobalNames global_events, PetscNestedEventNode **tree_p, PetscEventPerfInfo **perf_p) 311 { 312 PetscMPIInt size; 313 PetscInt num_nodes; 314 PetscInt num_map_entries; 315 PetscEventPerfInfo *perf; 316 NestedIdPair *keys; 317 NestedId *vals; 318 PetscInt offset; 319 PetscInt num_descendants; 320 PetscNestedEventNode *tree; 321 322 PetscFunctionBegin; 323 PetscCall(PetscLogGlobalNamesGetSize(global_events, NULL, &num_nodes)); 324 PetscCall(PetscCalloc1(num_nodes, &tree)); 325 for (PetscInt node = 0; node < num_nodes; node++) { 326 tree[node].id = node; 327 PetscCall(PetscLogGlobalNamesGlobalGetName(global_events, node, &tree[node].name)); 328 tree[node].parent = -1; 329 } 330 PetscCall(PetscNestedHashGetSize(nested->pair_map, &num_map_entries)); 331 PetscCall(PetscMalloc2(num_map_entries, &keys, num_map_entries, &vals)); 332 offset = 0; 333 PetscCall(PetscNestedHashGetPairs(nested->pair_map, &offset, keys, vals)); 334 for (PetscInt k = 0; k < num_map_entries; k++) { 335 NestedId root_local = keys[k].root; 336 NestedId leaf_local = vals[k]; 337 PetscInt root_global; 338 PetscInt leaf_global; 339 340 PetscCall(PetscLogGlobalNamesLocalGetGlobal(global_events, leaf_local, &leaf_global)); 341 if (root_local >= 0) { 342 PetscCall(PetscLogGlobalNamesLocalGetGlobal(global_events, root_local, &root_global)); 343 tree[leaf_global].parent = root_global; 344 } 345 } 346 PetscCall(PetscFree2(keys, vals)); 347 PetscCallMPI(MPI_Comm_size(comm, &size)); 348 if (size > 1) { // get missing parents from other processes 349 PetscInt *parents; 350 351 PetscCall(PetscMalloc1(num_nodes, &parents)); 352 for (PetscInt node = 0; node < num_nodes; node++) parents[node] = tree[node].parent; 353 PetscCall(MPIU_Allreduce(MPI_IN_PLACE, parents, num_nodes, MPIU_INT, MPI_MAX, comm)); 354 for (PetscInt node = 0; node < num_nodes; node++) tree[node].parent = parents[node]; 355 PetscCall(PetscFree(parents)); 356 } 357 358 num_descendants = 0; 359 PetscCall(PetscLogNestedEventNodesOrderDepthFirst(num_nodes, -1, tree, &num_descendants)); 360 PetscAssert(num_descendants == num_nodes, comm, PETSC_ERR_PLIB, "Failed tree ordering invariant"); 361 362 PetscCall(PetscCalloc1(num_nodes, &perf)); 363 for (PetscInt tree_node = 0; tree_node < num_nodes; tree_node++) { 364 PetscInt global_id = tree[tree_node].id; 365 PetscInt event_id; 366 367 PetscCall(PetscLogGlobalNamesGlobalGetLocal(global_events, global_id, &event_id)); 368 if (event_id >= 0) { 369 PetscEventPerfInfo *event_info; 370 371 PetscCall(PetscLogHandlerGetEventPerfInfo(nested->handler, 0, event_id, &event_info)); 372 perf[tree_node] = *event_info; 373 } else { 374 PetscCall(PetscArrayzero(&perf[tree_node], 1)); 375 } 376 } 377 *tree_p = tree; 378 *perf_p = perf; 379 PetscFunctionReturn(PETSC_SUCCESS); 380 } 381 382 static PetscErrorCode PetscLogHandlerView_Nested(PetscLogHandler handler, PetscViewer viewer) 383 { 384 PetscLogHandler_Nested nested = (PetscLogHandler_Nested)handler->data; 385 PetscNestedEventNode *nodes; 386 PetscEventPerfInfo *perf; 387 PetscLogGlobalNames global_events; 388 PetscNestedEventTree tree; 389 PetscViewerFormat format; 390 MPI_Comm comm = PetscObjectComm((PetscObject)viewer); 391 392 PetscFunctionBegin; 393 PetscCall(PetscLogRegistryCreateGlobalEventNames(comm, nested->state->registry, &global_events)); 394 PetscCall(PetscLogNestedCreatePerfNodes(comm, nested, global_events, &nodes, &perf)); 395 tree.comm = comm; 396 tree.global_events = global_events; 397 tree.perf = perf; 398 tree.nodes = nodes; 399 PetscCall(PetscViewerGetFormat(viewer, &format)); 400 if (format == PETSC_VIEWER_ASCII_XML) { 401 PetscCall(PetscLogHandlerView_Nested_XML(nested, &tree, viewer)); 402 } else if (format == PETSC_VIEWER_ASCII_FLAMEGRAPH) { 403 PetscCall(PetscLogHandlerView_Nested_Flamegraph(nested, &tree, viewer)); 404 } else SETERRQ(comm, PETSC_ERR_ARG_INCOMP, "No nested viewer for this format"); 405 PetscCall(PetscLogGlobalNamesDestroy(&global_events)); 406 PetscCall(PetscFree(tree.nodes)); 407 PetscCall(PetscFree(tree.perf)); 408 PetscFunctionReturn(PETSC_SUCCESS); 409 } 410 411 /*MC 412 PETSCLOGHANDLERNESTED - PETSCLOGHANDLERNESTED = "nested" - A `PetscLogHandler` that collects data for PETSc's 413 XML and flamegraph profiling log viewers. A log handler of this type is created and started by 414 by `PetscLogNestedBegin()`. 415 416 Level: developer 417 418 .seealso: [](ch_profiling), `PetscLogHandler` 419 M*/ 420 421 PETSC_INTERN PetscErrorCode PetscLogHandlerCreate_Nested(PetscLogHandler handler) 422 { 423 PetscFunctionBegin; 424 PetscCall(PetscLogHandlerContextCreate_Nested(PetscObjectComm((PetscObject)handler), (PetscLogHandler_Nested *)&handler->data)); 425 handler->ops->destroy = PetscLogHandlerDestroy_Nested; 426 handler->ops->stagepush = PetscLogHandlerStagePush_Nested; 427 handler->ops->stagepop = PetscLogHandlerStagePop_Nested; 428 handler->ops->eventbegin = PetscLogHandlerEventBegin_Nested; 429 handler->ops->eventend = PetscLogHandlerEventEnd_Nested; 430 handler->ops->eventsync = PetscLogHandlerEventSync_Nested; 431 handler->ops->objectcreate = PetscLogHandlerObjectCreate_Nested; 432 handler->ops->objectdestroy = PetscLogHandlerObjectDestroy_Nested; 433 handler->ops->view = PetscLogHandlerView_Nested; 434 PetscFunctionReturn(PETSC_SUCCESS); 435 } 436