Actual source code: xmlviewer.c
1: /*************************************************************************************
2: * M A R I T I M E R E S E A R C H I N S T I T U T E N E T H E R L A N D S *
3: *************************************************************************************
4: * authors: Koos Huijssen, Christiaan M. Klaij *
5: *************************************************************************************
6: * content: Viewer for writing XML output *
7: *************************************************************************************/
8: #include <petscviewer.h>
9: #include <petsc/private/logimpl.h>
10: #include "lognested.h"
12: static PetscErrorCode PetscViewerXMLStartSection(PetscViewer viewer, const char *name, const char *desc)
13: {
14: PetscInt XMLSectionDepthPetsc;
15: int XMLSectionDepth;
17: PetscFunctionBegin;
18: PetscCall(PetscViewerASCIIGetTab(viewer, &XMLSectionDepthPetsc));
19: PetscCall(PetscCIntCast(XMLSectionDepthPetsc, &XMLSectionDepth));
20: if (!desc) {
21: PetscCall(PetscViewerASCIIPrintf(viewer, "%*s<%s>\n", 2 * XMLSectionDepth, "", name));
22: } else {
23: PetscCall(PetscViewerASCIIPrintf(viewer, "%*s<%s desc=\"%s\">\n", 2 * XMLSectionDepth, "", name, desc));
24: }
25: PetscCall(PetscViewerASCIIPushTab(viewer));
26: PetscFunctionReturn(PETSC_SUCCESS);
27: }
29: /* Initialize a viewer to XML, and initialize the XMLDepth static parameter */
30: static PetscErrorCode PetscViewerInitASCII_XML(PetscViewer viewer)
31: {
32: MPI_Comm comm;
33: char PerfScript[PETSC_MAX_PATH_LEN + 40];
35: PetscFunctionBegin;
36: PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
37: PetscCall(PetscViewerASCIIPrintf(viewer, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"));
38: PetscCall(PetscStrreplace(comm, "<?xml-stylesheet type=\"text/xsl\" href=\"performance_xml2html.xsl\"?>", PerfScript, sizeof(PerfScript)));
39: PetscCall(PetscViewerASCIIPrintf(viewer, "%s\n", PerfScript));
40: PetscCall(PetscViewerXMLStartSection(viewer, "root", NULL));
41: PetscFunctionReturn(PETSC_SUCCESS);
42: }
44: static PetscErrorCode PetscViewerXMLEndSection(PetscViewer viewer, const char *name)
45: {
46: PetscInt XMLSectionDepthPetsc;
47: int XMLSectionDepth;
49: PetscFunctionBegin;
50: PetscCall(PetscViewerASCIIGetTab(viewer, &XMLSectionDepthPetsc));
51: PetscCall(PetscCIntCast(XMLSectionDepthPetsc, &XMLSectionDepth));
52: if (XMLSectionDepth > 0) PetscCall(PetscViewerASCIIPopTab(viewer));
53: PetscCall(PetscViewerASCIIGetTab(viewer, &XMLSectionDepthPetsc));
54: PetscCall(PetscCIntCast(XMLSectionDepthPetsc, &XMLSectionDepth));
55: PetscCall(PetscViewerASCIIPrintf(viewer, "%*s</%s>\n", 2 * XMLSectionDepth, "", name));
56: PetscFunctionReturn(PETSC_SUCCESS);
57: }
59: /* Initialize a viewer to XML, and initialize the XMLDepth static parameter */
60: static PetscErrorCode PetscViewerFinalASCII_XML(PetscViewer viewer)
61: {
62: PetscFunctionBegin;
63: PetscCall(PetscViewerXMLEndSection(viewer, "root"));
64: PetscFunctionReturn(PETSC_SUCCESS);
65: }
67: static PetscErrorCode PetscViewerXMLPutString(PetscViewer viewer, const char *name, const char *desc, const char *value)
68: {
69: PetscInt XMLSectionDepthPetsc;
70: int XMLSectionDepth;
72: PetscFunctionBegin;
73: PetscCall(PetscViewerASCIIGetTab(viewer, &XMLSectionDepthPetsc));
74: PetscCall(PetscCIntCast(XMLSectionDepthPetsc, &XMLSectionDepth));
75: if (!desc) {
76: PetscCall(PetscViewerASCIIPrintf(viewer, "%*s<%s>%s</%s>\n", 2 * XMLSectionDepth, "", name, value, name));
77: } else {
78: PetscCall(PetscViewerASCIIPrintf(viewer, "%*s<%s desc=\"%s\">%s</%s>\n", 2 * XMLSectionDepth, "", name, desc, value, name));
79: }
80: PetscFunctionReturn(PETSC_SUCCESS);
81: }
83: static PetscErrorCode PetscViewerXMLPutInt(PetscViewer viewer, const char *name, const char *desc, int value)
84: {
85: PetscInt XMLSectionDepthPetsc;
86: int XMLSectionDepth;
88: PetscFunctionBegin;
89: PetscCall(PetscViewerASCIIGetTab(viewer, &XMLSectionDepthPetsc));
90: PetscCall(PetscCIntCast(XMLSectionDepthPetsc, &XMLSectionDepth));
91: if (!desc) {
92: PetscCall(PetscViewerASCIIPrintf(viewer, "%*s<%s>%d</%s>\n", 2 * XMLSectionDepth, "", name, value, name));
93: } else {
94: PetscCall(PetscViewerASCIIPrintf(viewer, "%*s<%s desc=\"%s\">%d</%s>\n", 2 * XMLSectionDepth, "", name, desc, value, name));
95: }
96: PetscFunctionReturn(PETSC_SUCCESS);
97: }
99: static PetscErrorCode PetscViewerXMLPutDouble(PetscViewer viewer, const char *name, PetscLogDouble value, const char *format)
100: {
101: PetscInt XMLSectionDepthPetsc;
102: int XMLSectionDepth;
103: char buffer[1024];
105: PetscFunctionBegin;
106: PetscCall(PetscViewerASCIIGetTab(viewer, &XMLSectionDepthPetsc));
107: PetscCall(PetscCIntCast(XMLSectionDepthPetsc, &XMLSectionDepth));
108: PetscCall(PetscSNPrintf(buffer, sizeof(buffer), "%*s<%s>%s</%s>\n", 2 * XMLSectionDepth, "", name, format, name));
109: PetscCall(PetscViewerASCIIPrintf(viewer, buffer, value));
110: PetscFunctionReturn(PETSC_SUCCESS);
111: }
113: static PetscErrorCode PetscPrintExeSpecs(PetscViewer viewer)
114: {
115: char arch[128], hostname[128], username[128], pname[PETSC_MAX_PATH_LEN], date[128];
116: char version[256], buildoptions[128] = "";
117: PetscMPIInt size;
118: size_t len;
120: PetscFunctionBegin;
121: PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
122: PetscCall(PetscGetArchType(arch, sizeof(arch)));
123: PetscCall(PetscGetHostName(hostname, sizeof(hostname)));
124: PetscCall(PetscGetUserName(username, sizeof(username)));
125: PetscCall(PetscGetProgramName(pname, sizeof(pname)));
126: PetscCall(PetscGetDate(date, sizeof(date)));
127: PetscCall(PetscGetVersion(version, sizeof(version)));
129: PetscCall(PetscViewerXMLStartSection(viewer, "runspecification", "Run Specification"));
130: PetscCall(PetscViewerXMLPutString(viewer, "executable", "Executable", pname));
131: PetscCall(PetscViewerXMLPutString(viewer, "architecture", "Architecture", arch));
132: PetscCall(PetscViewerXMLPutString(viewer, "hostname", "Host", hostname));
133: PetscCall(PetscViewerXMLPutInt(viewer, "nprocesses", "Number of processes", size));
134: PetscCall(PetscViewerXMLPutString(viewer, "user", "Run by user", username));
135: PetscCall(PetscViewerXMLPutString(viewer, "date", "Started at", date));
136: PetscCall(PetscViewerXMLPutString(viewer, "petscrelease", "PETSc Release", version));
138: if (PetscDefined(USE_DEBUG)) PetscCall(PetscStrlcat(buildoptions, "Debug ", sizeof(buildoptions)));
139: if (PetscDefined(USE_COMPLEX)) PetscCall(PetscStrlcat(buildoptions, "Complex ", sizeof(buildoptions)));
140: if (PetscDefined(USE_REAL_SINGLE)) {
141: PetscCall(PetscStrlcat(buildoptions, "Single ", sizeof(buildoptions)));
142: } else if (PetscDefined(USE_REAL___FLOAT128)) {
143: PetscCall(PetscStrlcat(buildoptions, "Quadruple ", sizeof(buildoptions)));
144: } else if (PetscDefined(USE_REAL___FP16)) {
145: PetscCall(PetscStrlcat(buildoptions, "Half ", sizeof(buildoptions)));
146: }
147: if (PetscDefined(USE_64BIT_INDICES)) PetscCall(PetscStrlcat(buildoptions, "Int64 ", sizeof(buildoptions)));
148: #if defined(__cplusplus)
149: PetscCall(PetscStrlcat(buildoptions, "C++ ", sizeof(buildoptions)));
150: #endif
151: PetscCall(PetscStrlen(buildoptions, &len));
152: if (len) PetscCall(PetscViewerXMLPutString(viewer, "petscbuildoptions", "PETSc build options", buildoptions));
153: PetscCall(PetscViewerXMLEndSection(viewer, "runspecification"));
154: PetscFunctionReturn(PETSC_SUCCESS);
155: }
157: static PetscErrorCode PetscPrintXMLGlobalPerformanceElement(PetscViewer viewer, const char *name, const char *desc, PetscLogDouble local_val, const PetscBool print_average, const PetscBool print_total)
158: {
159: PetscLogDouble min, tot, ratio, avg;
160: MPI_Comm comm;
161: PetscMPIInt rank, size;
162: PetscLogDouble max[2];
164: PetscFunctionBegin;
165: PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
166: PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
167: PetscCallMPI(MPI_Comm_rank(comm, &rank));
169: max[0] = local_val;
170: max[1] = (PetscLogDouble)rank;
171: PetscCallMPI(MPIU_Allreduce(&local_val, &min, 1, MPIU_PETSCLOGDOUBLE, MPI_MIN, comm));
172: PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, max, 1, MPIU_2PETSCLOGDOUBLE, MPI_MAXLOC, comm));
173: PetscCallMPI(MPIU_Allreduce(&local_val, &tot, 1, MPIU_PETSCLOGDOUBLE, MPI_SUM, comm));
174: avg = tot / ((PetscLogDouble)size);
175: if (min != 0.0) ratio = max[0] / min;
176: else ratio = 0.0;
178: PetscCall(PetscViewerXMLStartSection(viewer, name, desc));
179: PetscCall(PetscViewerXMLPutDouble(viewer, "max", max[0], "%e"));
180: PetscCall(PetscViewerXMLPutInt(viewer, "maxrank", "rank at which max was found", (PetscMPIInt)max[1]));
181: PetscCall(PetscViewerXMLPutDouble(viewer, "ratio", ratio, "%f"));
182: if (print_average) PetscCall(PetscViewerXMLPutDouble(viewer, "average", avg, "%e"));
183: if (print_total) PetscCall(PetscViewerXMLPutDouble(viewer, "total", tot, "%e"));
184: PetscCall(PetscViewerXMLEndSection(viewer, name));
185: PetscFunctionReturn(PETSC_SUCCESS);
186: }
188: /* Print the global performance: max, max/min, average and total of
189: * time, objects, flops, flops/sec, memory, MPI messages, MPI message lengths, MPI reductions.
190: */
191: static PetscErrorCode PetscPrintGlobalPerformance(PetscViewer viewer, PetscLogDouble locTotalTime, PetscLogHandler default_handler)
192: {
193: PetscLogDouble flops, mem, red, mess;
194: PetscInt num_objects;
195: const PetscBool print_total_yes = PETSC_TRUE, print_total_no = PETSC_FALSE, print_average_no = PETSC_FALSE, print_average_yes = PETSC_TRUE;
197: PetscFunctionBegin;
198: /* Must preserve reduction count before we go on */
199: red = petsc_allreduce_ct + petsc_gather_ct + petsc_scatter_ct;
201: /* Calculate summary information */
202: PetscCall(PetscViewerXMLStartSection(viewer, "globalperformance", "Global performance"));
204: /* Time */
205: PetscCall(PetscPrintXMLGlobalPerformanceElement(viewer, "time", "Time (sec)", locTotalTime, print_average_yes, print_total_no));
207: /* Objects */
208: PetscCall(PetscLogHandlerGetNumObjects(default_handler, &num_objects));
209: PetscCall(PetscPrintXMLGlobalPerformanceElement(viewer, "objects", "Objects", (PetscLogDouble)num_objects, print_average_yes, print_total_no));
211: /* Flop */
212: PetscCall(PetscPrintXMLGlobalPerformanceElement(viewer, "mflop", "MFlop", petsc_TotalFlops / 1.0E6, print_average_yes, print_total_yes));
214: /* Flop/sec -- Must talk to Barry here */
215: if (locTotalTime != 0.0) flops = petsc_TotalFlops / locTotalTime;
216: else flops = 0.0;
217: PetscCall(PetscPrintXMLGlobalPerformanceElement(viewer, "mflops", "MFlop/sec", flops / 1.0E6, print_average_yes, print_total_yes));
219: /* Memory */
220: PetscCall(PetscMallocGetMaximumUsage(&mem));
221: if (mem > 0.0) PetscCall(PetscPrintXMLGlobalPerformanceElement(viewer, "memory", "Memory (MiB)", mem / 1024.0 / 1024.0, print_average_yes, print_total_yes));
222: /* Messages */
223: mess = 0.5 * (petsc_irecv_ct + petsc_isend_ct + petsc_recv_ct + petsc_send_ct);
224: PetscCall(PetscPrintXMLGlobalPerformanceElement(viewer, "messagetransfers", "MPI Message Transfers", mess, print_average_yes, print_total_yes));
226: /* Message Volume */
227: mess = 0.5 * (petsc_irecv_len + petsc_isend_len + petsc_recv_len + petsc_send_len);
228: PetscCall(PetscPrintXMLGlobalPerformanceElement(viewer, "messagevolume", "MPI Message Volume (MiB)", mess / 1024.0 / 1024.0, print_average_yes, print_total_yes));
230: /* Reductions */
231: PetscCall(PetscPrintXMLGlobalPerformanceElement(viewer, "reductions", "MPI Reductions", red, print_average_no, print_total_no));
232: PetscCall(PetscViewerXMLEndSection(viewer, "globalperformance"));
233: PetscFunctionReturn(PETSC_SUCCESS);
234: }
236: /* Print the global performance: max, max/min, average and total of
237: * time, objects, flops, flops/sec, memory, MPI messages, MPI message lengths, MPI reductions.
238: */
239: static PetscErrorCode PetscPrintXMLNestedLinePerfResults(PetscViewer viewer, const char *name, PetscLogDouble value, PetscLogDouble minthreshold, PetscLogDouble maxthreshold, PetscLogDouble minmaxtreshold)
240: {
241: MPI_Comm comm; /* MPI communicator in reduction */
242: PetscMPIInt rank; /* rank of this process */
243: PetscLogDouble max[2], min[2];
244: PetscLogDouble minvalue, maxvalue, tot;
245: PetscMPIInt size;
246: PetscMPIInt minLoc, maxLoc;
248: PetscFunctionBegin;
249: PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
250: PetscCallMPI(MPI_Comm_size(comm, &size));
251: PetscCallMPI(MPI_Comm_rank(comm, &rank));
252: max[0] = min[0] = value;
253: max[1] = min[1] = (PetscLogDouble)rank;
254: PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, max, 1, MPIU_2PETSCLOGDOUBLE, MPI_MAXLOC, comm));
255: PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, min, 1, MPIU_2PETSCLOGDOUBLE, MPI_MINLOC, comm));
256: maxvalue = max[0];
257: maxLoc = (PetscMPIInt)max[1];
258: minvalue = min[0];
259: minLoc = (PetscMPIInt)min[1];
260: PetscCallMPI(MPIU_Allreduce(&value, &tot, 1, MPIU_PETSCLOGDOUBLE, MPI_SUM, comm));
262: if (maxvalue < maxthreshold && minvalue >= minthreshold) {
263: /* One call per parent or NO value: don't print */
264: } else {
265: PetscCall(PetscViewerXMLStartSection(viewer, name, NULL));
266: if (maxvalue > minvalue * minmaxtreshold) {
267: PetscCall(PetscViewerXMLPutDouble(viewer, "avgvalue", tot / size, "%g"));
268: PetscCall(PetscViewerXMLPutDouble(viewer, "minvalue", minvalue, "%g"));
269: PetscCall(PetscViewerXMLPutDouble(viewer, "maxvalue", maxvalue, "%g"));
270: PetscCall(PetscViewerXMLPutInt(viewer, "minloc", NULL, minLoc));
271: PetscCall(PetscViewerXMLPutInt(viewer, "maxloc", NULL, maxLoc));
272: } else {
273: PetscCall(PetscViewerXMLPutDouble(viewer, "value", tot / size, "%g"));
274: }
275: PetscCall(PetscViewerXMLEndSection(viewer, name));
276: }
277: PetscFunctionReturn(PETSC_SUCCESS);
278: }
280: static PetscErrorCode PetscLogNestedTreePrintLine(PetscViewer viewer, const PetscEventPerfInfo *perfInfo, int childCount, int parentCount, const char *name, PetscLogDouble totalTime)
281: {
282: PetscLogDouble time = perfInfo->time;
283: PetscLogDouble timeMx;
284: MPI_Comm comm;
286: PetscFunctionBegin;
287: PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
288: PetscCallMPI(MPIU_Allreduce(&time, &timeMx, 1, MPIU_PETSCLOGDOUBLE, MPI_MAX, comm));
289: PetscCall(PetscViewerXMLPutString(viewer, "name", NULL, name));
290: PetscCall(PetscPrintXMLNestedLinePerfResults(viewer, "time", time / totalTime * 100.0, 0, 0, 1.02));
291: PetscCall(PetscPrintXMLNestedLinePerfResults(viewer, "ncalls", parentCount > 0 ? ((PetscLogDouble)childCount) / ((PetscLogDouble)parentCount) : 1.0, 0.99, 1.01, 1.02));
292: PetscCall(PetscPrintXMLNestedLinePerfResults(viewer, "mflops", time >= timeMx * 0.001 ? 1e-6 * perfInfo->flops / time : 0, 0, 0.01, 1.05));
293: PetscCall(PetscPrintXMLNestedLinePerfResults(viewer, "mbps", time >= timeMx * 0.001 ? perfInfo->messageLength / (1024 * 1024 * time) : 0, 0, 0.01, 1.05));
294: PetscCall(PetscPrintXMLNestedLinePerfResults(viewer, "nreductsps", time >= timeMx * 0.001 ? perfInfo->numReductions / time : 0, 0, 0.01, 1.05));
295: PetscFunctionReturn(PETSC_SUCCESS);
296: }
298: static PetscErrorCode PetscNestedNameGetBase(const char name[], const char *base[])
299: {
300: size_t n;
302: PetscFunctionBegin;
303: PetscCall(PetscStrlen(name, &n));
304: while (n > 0 && name[n - 1] != ';') n--;
305: *base = &name[n];
306: PetscFunctionReturn(PETSC_SUCCESS);
307: }
309: static PetscErrorCode PetscLogNestedTreePrint(PetscViewer viewer, double total_time, double threshold_time, const PetscNestedEventNode *parent_node, PetscEventPerfInfo *parent_info, const PetscNestedEventNode tree[], PetscEventPerfInfo perf[], PetscLogNestedType type, PetscBool print_events)
310: {
311: PetscInt num_children = 0, num_printed;
312: PetscInt num_nodes = parent_node->num_descendants;
313: PetscInt *perm;
314: PetscReal *times; // Not PetscLogDouble, to reuse PetscSortRealWithArrayInt() below
315: PetscEventPerfInfo other;
317: PetscFunctionBegin;
318: for (PetscInt node = 0; node < num_nodes; node += 1 + tree[node].num_descendants) {
319: PetscAssert(tree[node].parent == parent_node->id, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Failed tree invariant");
320: num_children++;
321: }
322: num_printed = num_children;
323: PetscCall(PetscMemzero(&other, sizeof(other)));
324: PetscCall(PetscMalloc2(num_children + 2, ×, num_children + 2, &perm));
325: for (PetscInt i = 0, node = 0; node < num_nodes; i++, node += 1 + tree[node].num_descendants) {
326: PetscLogDouble child_time = perf[node].time;
328: perm[i] = node;
329: PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &child_time, 1, MPIU_PETSCLOGDOUBLE, MPI_MAX, PetscObjectComm((PetscObject)viewer)));
330: times[i] = -child_time;
332: parent_info->time -= perf[node].time;
333: parent_info->flops -= perf[node].flops;
334: parent_info->numMessages -= perf[node].numMessages;
335: parent_info->messageLength -= perf[node].messageLength;
336: parent_info->numReductions -= perf[node].numReductions;
337: if (child_time < threshold_time) {
338: PetscEventPerfInfo *add_to = (type == PETSC_LOG_NESTED_XML) ? &other : parent_info;
340: add_to->time += perf[node].time;
341: add_to->flops += perf[node].flops;
342: add_to->numMessages += perf[node].numMessages;
343: add_to->messageLength += perf[node].messageLength;
344: add_to->numReductions += perf[node].numReductions;
345: add_to->count += perf[node].count;
346: num_printed--;
347: }
348: }
349: perm[num_children] = -1;
350: times[num_children] = -parent_info->time;
351: perm[num_children + 1] = -2;
352: times[num_children + 1] = -other.time;
353: PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, ×[num_children], 2, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)viewer)));
354: // Sync the time with allreduce results, otherwise it could result in code path divergence through num_printed and early return.
355: other.time = -times[num_children + 1];
356: if (type == PETSC_LOG_NESTED_FLAMEGRAPH) {
357: /* The output is given as an integer in microseconds because otherwise the file cannot be read
358: * by apps such as speedscope (https://speedscope.app/). */
359: PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt64_FMT "\n", parent_node->name, (PetscInt64)(-times[num_children] * 1e6)));
360: }
361: if (other.time > 0.0) num_printed++;
362: // number of items other than "self" that will be printed
363: if (num_printed == 0) {
364: PetscCall(PetscFree2(times, perm));
365: PetscFunctionReturn(PETSC_SUCCESS);
366: }
367: // sort descending by time
368: PetscCall(PetscSortRealWithArrayInt(num_children + 2, times, perm));
369: if (type == PETSC_LOG_NESTED_XML && print_events) PetscCall(PetscViewerXMLStartSection(viewer, "events", NULL));
370: for (PetscInt i = 0; i < num_children + 2; i++) {
371: PetscInt node = perm[i];
372: PetscLogDouble child_time = -times[i];
374: if (child_time >= threshold_time || (node < 0 && child_time > 0.0)) {
375: if (type == PETSC_LOG_NESTED_XML) {
376: PetscCall(PetscViewerXMLStartSection(viewer, "event", NULL));
377: if (node == -1) {
378: PetscCall(PetscLogNestedTreePrintLine(viewer, parent_info, 0, 0, "self", total_time));
379: } else if (node == -2) {
380: PetscCall(PetscLogNestedTreePrintLine(viewer, &other, other.count, parent_info->count, "other", total_time));
381: } else {
382: const char *base_name = NULL;
383: PetscCall(PetscNestedNameGetBase(tree[node].name, &base_name));
384: PetscCall(PetscLogNestedTreePrintLine(viewer, &perf[node], perf[node].count, parent_info->count, base_name, total_time));
385: PetscCall(PetscLogNestedTreePrint(viewer, total_time, threshold_time, &tree[node], &perf[node], &tree[node + 1], &perf[node + 1], type, PETSC_TRUE));
386: }
387: PetscCall(PetscViewerXMLEndSection(viewer, "event"));
388: } else if (node >= 0) {
389: PetscCall(PetscLogNestedTreePrint(viewer, total_time, threshold_time, &tree[node], &perf[node], &tree[node + 1], &perf[node + 1], type, PETSC_FALSE));
390: }
391: }
392: }
393: if (type == PETSC_LOG_NESTED_XML && print_events) PetscCall(PetscViewerXMLEndSection(viewer, "events"));
394: PetscCall(PetscFree2(times, perm));
395: PetscFunctionReturn(PETSC_SUCCESS);
396: }
398: static PetscErrorCode PetscLogNestedTreePrintTop(PetscViewer viewer, PetscNestedEventTree *tree, PetscLogDouble threshold, PetscLogNestedType type)
399: {
400: PetscNestedEventNode *main_stage;
401: PetscNestedEventNode *tree_rem;
402: PetscEventPerfInfo *main_stage_perf;
403: PetscEventPerfInfo *perf_rem;
404: PetscLogDouble time;
405: PetscLogDouble threshold_time;
407: PetscFunctionBegin;
408: main_stage = &tree->nodes[0];
409: tree_rem = &tree->nodes[1];
410: main_stage_perf = &tree->perf[0];
411: perf_rem = &tree->perf[1];
412: time = main_stage_perf->time;
413: PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &time, 1, MPIU_PETSCLOGDOUBLE, MPI_MAX, tree->comm));
414: /* Print (or ignore) the children in ascending order of total time */
415: if (type == PETSC_LOG_NESTED_XML) {
416: PetscCall(PetscViewerXMLStartSection(viewer, "timertree", "Timings tree"));
417: PetscCall(PetscViewerXMLPutDouble(viewer, "totaltime", time, "%f"));
418: PetscCall(PetscViewerXMLPutDouble(viewer, "timethreshold", threshold, "%f"));
419: }
420: threshold_time = time * (threshold / 100.0 + 1.e-12);
421: PetscCall(PetscLogNestedTreePrint(viewer, time, threshold_time, main_stage, main_stage_perf, tree_rem, perf_rem, type, PETSC_FALSE));
422: if (type == PETSC_LOG_NESTED_XML) PetscCall(PetscViewerXMLEndSection(viewer, "timertree"));
423: PetscFunctionReturn(PETSC_SUCCESS);
424: }
426: PETSC_INTERN PetscErrorCode PetscLogHandlerView_Nested_XML(PetscLogHandler_Nested nested, PetscNestedEventTree *tree, PetscViewer viewer)
427: {
428: PetscFunctionBegin;
429: PetscCall(PetscViewerInitASCII_XML(viewer));
430: PetscCall(PetscViewerASCIIPrintf(viewer, "<!-- PETSc Performance Summary: -->\n"));
431: PetscCall(PetscViewerXMLStartSection(viewer, "petscroot", NULL));
433: // Print global information about this run
434: PetscCall(PetscPrintExeSpecs(viewer));
436: if (PetscDefined(USE_LOG)) {
437: PetscEventPerfInfo *main_stage_info;
438: PetscLogDouble locTotalTime;
440: PetscCall(PetscLogHandlerGetEventPerfInfo(nested->handler, 0, 0, &main_stage_info));
441: locTotalTime = main_stage_info->time;
442: PetscCall(PetscPrintGlobalPerformance(viewer, locTotalTime, nested->handler));
443: }
444: PetscCall(PetscLogNestedTreePrintTop(viewer, tree, nested->threshold, PETSC_LOG_NESTED_XML));
445: PetscCall(PetscViewerXMLEndSection(viewer, "petscroot"));
446: PetscCall(PetscViewerFinalASCII_XML(viewer));
447: PetscFunctionReturn(PETSC_SUCCESS);
448: }
450: PETSC_INTERN PetscErrorCode PetscLogHandlerView_Nested_Flamegraph(PetscLogHandler_Nested nested, PetscNestedEventTree *tree, PetscViewer viewer)
451: {
452: PetscFunctionBegin;
453: PetscCall(PetscLogNestedTreePrintTop(viewer, tree, nested->threshold, PETSC_LOG_NESTED_FLAMEGRAPH));
454: PetscFunctionReturn(PETSC_SUCCESS);
455: }