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