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