xref: /petsc/src/sys/logging/handler/impls/nested/lognested.c (revision 4ad8454beace47809662cdae21ee081016eaa39a)
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", 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", 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 
289   PetscFunctionBegin;
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