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, &times, 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, &times[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: }