xref: /petsc/src/sys/info/verboseinfo.c (revision 8b86dd2ee2f9cfc0672efa8d65ff1071d586f9de)
1 /*
2       PetscInfo() is contained in a different file from the other profiling to
3    allow it to be replaced at link time by an alternative routine.
4 */
5 #include <petsc/private/petscimpl.h> /*I    "petscsys.h"   I*/
6 
7 /*
8   The next set of variables determine which, if any, PetscInfo() calls are used.
9   If PetscLogPrintInfo is false, no info messages are printed.
10 
11   If PetscInfoFlags[OBJECT_CLASSID - PETSC_SMALLEST_CLASSID] is zero, no messages related
12   to that object are printed. OBJECT_CLASSID is, for example, MAT_CLASSID.
13   Note for developers: the PetscInfoFlags array is currently 160 entries large, to ensure headroom. Perhaps it is worth
14   dynamically allocating this array intelligently rather than just some big number.
15 
16   PetscInfoFilename determines where PetscInfo() output is piped.
17   PetscInfoClassnames holds a char array of classes which are filtered out/for in PetscInfo() calls.
18 */
19 const char *const        PetscInfoCommFlags[]   = {"all", "no_self", "only_self", "PetscInfoCommFlag", "PETSC_INFO_COMM_", NULL};
20 static PetscBool         PetscInfoClassesLocked = PETSC_FALSE, PetscInfoInvertClasses = PETSC_FALSE, PetscInfoClassesSet = PETSC_FALSE;
21 static char            **PetscInfoClassnames = NULL;
22 static char             *PetscInfoFilename   = NULL;
23 static PetscInt          PetscInfoNumClasses = -1;
24 static PetscInfoCommFlag PetscInfoCommFilter = PETSC_INFO_COMM_ALL;
25 static int               PetscInfoFlags[]    = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
26                                                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
27                                                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
28 PetscBool                PetscLogPrintInfo   = PETSC_FALSE;
29 FILE                    *PetscInfoFile       = NULL;
30 
31 /*@
32     PetscInfoEnabled - Checks whether a given OBJECT_CLASSID is allowed to print using `PetscInfo()`
33 
34     Not Collective
35 
36     Input Parameters:
37 .   classid - `PetscClassid` retrieved from a `PetscObject` e.g. `VEC_CLASSID`
38 
39     Output Parameter:
40 .   enabled - `PetscBool` indicating whether this classid is allowed to print
41 
42     Note:
43     Use `PETSC_SMALLEST_CLASSID` to check if "sys" `PetscInfo()` calls are enabled. When PETSc is configured with debugging
44     support this function checks if classid >= `PETSC_SMALLEST_CLASSID`, otherwise it assumes valid classid.
45 
46     Level: advanced
47 
48 .seealso: `PetscInfo()`, `PetscInfoAllow()`, `PetscInfoGetInfo()`, `PetscObjectGetClassid()`
49 @*/
50 PetscErrorCode PetscInfoEnabled(PetscClassId classid, PetscBool *enabled) {
51   PetscFunctionBegin;
52   PetscValidBoolPointer(enabled, 2);
53   PetscCheck(classid >= PETSC_SMALLEST_CLASSID, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Classid (current: %d) must be equal to or greater than PETSC_SMALLEST_CLASSID", classid);
54   *enabled = (PetscBool)(PetscLogPrintInfo && PetscInfoFlags[classid - PETSC_SMALLEST_CLASSID]);
55   PetscFunctionReturn(0);
56 }
57 
58 /*@
59     PetscInfoAllow - Enables/disables `PetscInfo()` messages
60 
61     Not Collective
62 
63     Input Parameter:
64 .   flag - `PETSC_TRUE` or `PETSC_FALSE`
65 
66     Level: advanced
67 
68 .seealso: `PetscInfo()`, `PetscInfoEnabled()`, `PetscInfoGetInfo()`, `PetscInfoSetFromOptions()`
69 @*/
70 PetscErrorCode PetscInfoAllow(PetscBool flag) {
71   PetscFunctionBegin;
72   PetscLogPrintInfo = flag;
73   PetscFunctionReturn(0);
74 }
75 
76 /*@C
77     PetscInfoSetFile - Sets the printing destination for all `PetscInfo()` calls
78 
79     Not Collective
80 
81     Input Parameters:
82 +   filename - Name of the file where `PetscInfo()` will print to
83 -   mode - Write mode passed to PetscFOpen()`
84 
85     Note:
86     Use filename = NULL to set `PetscInfo()` to write to `PETSC_STDOUT`.
87 
88     Level: advanced
89 
90 .seealso: `PetscInfo()`, `PetscInfoSetFile()`, `PetscInfoSetFromOptions()`, `PetscFOpen()`
91 @*/
92 PetscErrorCode PetscInfoSetFile(const char filename[], const char mode[]) {
93   PetscFunctionBegin;
94   if (!PetscInfoFile) PetscInfoFile = PETSC_STDOUT;
95   PetscCall(PetscFree(PetscInfoFilename));
96   if (filename) {
97     PetscMPIInt rank;
98     char        fname[PETSC_MAX_PATH_LEN], tname[11];
99 
100     PetscValidCharPointer(filename, 1);
101     PetscValidCharPointer(mode, 2);
102     PetscCall(PetscFixFilename(filename, fname));
103     PetscCall(PetscStrallocpy(fname, &PetscInfoFilename));
104     PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
105     PetscCall(PetscSNPrintf(tname, PETSC_STATIC_ARRAY_LENGTH(tname), ".%d", rank));
106     PetscCall(PetscStrlcat(fname, tname, PETSC_STATIC_ARRAY_LENGTH(fname)));
107     {
108       const PetscBool oldflag = PetscLogPrintInfo;
109 
110       PetscLogPrintInfo = PETSC_FALSE;
111       PetscCall(PetscFOpen(PETSC_COMM_SELF, fname, mode, &PetscInfoFile));
112       PetscLogPrintInfo = oldflag;
113       /*
114         PetscFOpen will write to PETSC_STDOUT and not PetscInfoFile here, so we disable the
115         PetscInfo call inside it, and call it afterwards so that it actually writes to file
116       */
117     }
118     PetscCall(PetscInfo(NULL, "Opened PetscInfo file %s\n", fname));
119   }
120   PetscFunctionReturn(0);
121 }
122 
123 /*@C
124     PetscInfoGetFile - Gets the name and FILE pointer of the file where `PetscInfo()` prints to
125 
126     Not Collective
127 
128     Output Parameters:
129 +   filename - The name of the output file
130 -   InfoFile - The FILE pointer for the output file
131 
132     Level: advanced
133 
134     Note:
135     This routine allocates and copies the filename so that the filename survives `PetscInfoDestroy()`. The user is
136     therefore responsible for freeing the allocated filename pointer afterwards.
137 
138     Fortran Note:
139     This routine is not supported in Fortran.
140 
141 .seealso: `PetscInfo()`, `PetscInfoSetFile()`, `PetscInfoSetFromOptions()`, `PetscInfoDestroy()`
142 @*/
143 PetscErrorCode PetscInfoGetFile(char **filename, FILE **InfoFile) {
144   PetscFunctionBegin;
145   PetscValidPointer(filename, 1);
146   PetscValidPointer(InfoFile, 2);
147   PetscCall(PetscStrallocpy(PetscInfoFilename, filename));
148   *InfoFile = PetscInfoFile;
149   PetscFunctionReturn(0);
150 }
151 
152 /*@C
153     PetscInfoSetClasses - Sets the classes which `PetscInfo()` is filtered for/against
154 
155     Not Collective
156 
157     Input Parameters:
158 +   exclude - Whether or not to invert the filter, i.e. if exclude is true, `PetscInfo()` will print from every class that
159     is NOT one of the classes specified
160 .   n - Number of classes to filter for (size of classnames)
161 -   classnames - String array containing the names of classes to filter for, e.g. "vec"
162 
163     Notes:
164     This function CANNOT be called after `PetscInfoGetClass()` or `PetscInfoProcessClass()` has been called.
165 
166     Names in the classnames list should correspond to the names returned by `PetscObjectGetClassName()`.
167 
168     This function only sets the list of class names.
169     The actual filtering is deferred to `PetscInfoProcessClass()`, except of sys which is processed right away.
170     The reason for this is that we need to set the list of included/excluded classes before their classids are known.
171     Typically the classid is assigned and `PetscInfoProcessClass()` called in <Class>InitializePackage() (e.g. `VecInitializePackage()`).
172 
173     Fortran Note:
174     Not for use in Fortran
175 
176     Level: developer
177 
178 .seealso: `PetscInfo()`, `PetscInfoGetClass()`, `PetscInfoProcessClass()`, `PetscInfoSetFromOptions()`, `PetscStrToArray()`, `PetscObjectGetName()`
179 @*/
180 PetscErrorCode PetscInfoSetClasses(PetscBool exclude, PetscInt n, const char *const *classnames) {
181   PetscFunctionBegin;
182   PetscCheck(!PetscInfoClassesLocked, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscInfoSetClasses() cannot be called after PetscInfoGetClass() or PetscInfoProcessClass()");
183   PetscCall(PetscStrNArrayDestroy(PetscInfoNumClasses, &PetscInfoClassnames));
184   PetscCall(PetscStrNArrayallocpy(n, classnames, &PetscInfoClassnames));
185   PetscInfoNumClasses    = n;
186   PetscInfoInvertClasses = exclude;
187   /* Process sys class right away */
188   {
189     const PetscClassId id = PETSC_SMALLEST_CLASSID;
190 
191     PetscCall(PetscInfoProcessClass("sys", 1, &id));
192   }
193   PetscInfoClassesSet = PETSC_TRUE;
194   PetscFunctionReturn(0);
195 }
196 
197 /*@C
198     PetscInfoGetClass - Indicates whether the provided classname is marked as a filter in `PetscInfo()` as set by `PetscInfoSetClasses()`
199 
200     Not Collective
201 
202     Input Parameter:
203 .   classname - Name of the class to search for
204 
205     Output Parameter:
206 .   found - `PetscBool` indicating whether the classname was found
207 
208     Note:
209     Use `PetscObjectGetName()` to retrieve an appropriate classname
210 
211     Level: developer
212 
213 .seealso: `PetscInfo()`, `PetscInfoSetClasses()`, `PetscInfoSetFromOptions()`, `PetscObjectGetName()`
214 @*/
215 PetscErrorCode PetscInfoGetClass(const char *classname, PetscBool *found) {
216   PetscInt unused;
217 
218   PetscFunctionBegin;
219   PetscValidCharPointer(classname, 1);
220   PetscValidBoolPointer(found, 2);
221   PetscCall(PetscEListFind(PetscInfoNumClasses, (const char *const *)PetscInfoClassnames, classname ? classname : "sys", &unused, found));
222   PetscInfoClassesLocked = PETSC_TRUE;
223   PetscFunctionReturn(0);
224 }
225 
226 /*@
227     PetscInfoGetInfo - Returns the current state of several important flags for `PetscInfo()`
228 
229     Not Collective
230 
231     Output Parameters:
232 +   infoEnabled - `PETSC_TRUE` if `PetscInfoAllow`(`PETSC_TRUE`) has been called
233 .   classesSet - `PETSC_TRUE` if the list of classes to filter for has been set
234 .   exclude - `PETSC_TRUE` if the class filtering for `PetscInfo()` is inverted
235 .   locked - `PETSC_TRUE` if the list of classes to filter for has been locked
236 -   commSelfFlag - Enum indicating whether `PetscInfo()` will print for communicators of size 1, any size != 1, or all
237     communicators
238 
239     Note:
240     Initially commSelfFlag = `PETSC_INFO_COMM_ALL`
241 
242     Level: developer
243 
244 .seealso: `PetscInfo()`, `PetscInfoAllow()`, `PetscInfoSetFilterCommSelf`, `PetscInfoSetFromOptions()`
245 @*/
246 PetscErrorCode PetscInfoGetInfo(PetscBool *infoEnabled, PetscBool *classesSet, PetscBool *exclude, PetscBool *locked, PetscInfoCommFlag *commSelfFlag) {
247   PetscFunctionBegin;
248   if (infoEnabled) PetscValidBoolPointer(infoEnabled, 1);
249   if (classesSet) PetscValidBoolPointer(classesSet, 2);
250   if (exclude) PetscValidBoolPointer(exclude, 3);
251   if (locked) PetscValidBoolPointer(locked, 4);
252   if (commSelfFlag) PetscValidPointer(commSelfFlag, 5);
253   if (infoEnabled) *infoEnabled = PetscLogPrintInfo;
254   if (classesSet) *classesSet = PetscInfoClassesSet;
255   if (exclude) *exclude = PetscInfoInvertClasses;
256   if (locked) *locked = PetscInfoClassesLocked;
257   if (commSelfFlag) *commSelfFlag = PetscInfoCommFilter;
258   PetscFunctionReturn(0);
259 }
260 
261 /*@C
262     PetscInfoProcessClass - Activates or deactivates a class based on the filtering status of `PetscInfo()`
263 
264     Not Collective
265 
266     Input Parameters:
267 +   classname - Name of the class to activate/deactivate `PetscInfo()` for
268 .   numClassID - Number of entries in classIDs
269 -   classIDs - Array containing all of the PetscClassids associated with classname
270 
271     Level: developer
272 
273 .seealso: `PetscInfo()`, `PetscInfoActivateClass()`, `PetscInfoDeactivateClass()`, `PetscInfoSetFromOptions()`
274 @*/
275 PetscErrorCode PetscInfoProcessClass(const char classname[], PetscInt numClassID, const PetscClassId classIDs[]) {
276   PetscBool enabled, exclude, found, opt;
277   char      logList[256];
278 
279   PetscFunctionBegin;
280   PetscValidCharPointer(classname, 1);
281   PetscAssert(numClassID > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of classids %" PetscInt_FMT " <= 0", numClassID);
282   if (numClassID) PetscValidPointer(classIDs, 3);
283   PetscCall(PetscInfoGetInfo(&enabled, NULL, &exclude, NULL, NULL));
284   /* -info_exclude is DEPRECATED */
285   PetscCall(PetscOptionsGetString(NULL, NULL, "-info_exclude", logList, sizeof(logList), &opt));
286   if (opt) {
287     PetscBool pkg;
288 
289     PetscCall(PetscStrInList(classname, logList, ',', &pkg));
290     if (pkg) {
291       for (PetscInt i = 0; i < numClassID; ++i) PetscCall(PetscInfoDeactivateClass(classIDs[i]));
292     }
293   }
294   PetscCall(PetscInfoGetClass(classname, &found));
295   if ((found && exclude) || (!found && !exclude)) {
296     if (PetscInfoNumClasses > 0) {
297       /* Check if -info was called empty */
298       for (PetscInt i = 0; i < numClassID; ++i) PetscCall(PetscInfoDeactivateClass(classIDs[i]));
299     }
300   } else {
301     for (PetscInt i = 0; i < numClassID; ++i) PetscCall(PetscInfoActivateClass(classIDs[i]));
302   }
303   PetscFunctionReturn(0);
304 }
305 
306 /*@
307     PetscInfoSetFilterCommSelf - Sets `PetscInfoCommFlag` enum to determine communicator filtering for `PetscInfo()`
308 
309     Not Collective
310 
311     Input Parameter:
312 .   commSelfFlag - Enum value indicating method with which to filter `PetscInfo()` based on the size of the communicator of the object calling `PetscInfo()`
313 
314     Level: advanced
315 
316 .seealso: `PetscInfo()`, `PetscInfoGetInfo()`
317 @*/
318 PetscErrorCode PetscInfoSetFilterCommSelf(PetscInfoCommFlag commSelfFlag) {
319   PetscFunctionBegin;
320   PetscInfoCommFilter = commSelfFlag;
321   PetscFunctionReturn(0);
322 }
323 
324 /*@
325     PetscInfoSetFromOptions - Configure `PetscInfo()` using command line options, enabling or disabling various calls to `PetscInfo()`
326 
327     Not Collective
328 
329     Input Parameter:
330 .   options - Options database, use NULL for default global database
331 
332     Options Database Keys:
333 .   -info [filename][:[~]<list,of,classnames>[:[~]self]] - specify which informative messages are printed, See PetscInfo().
334 
335     Note:
336     This function is called automatically during `PetscInitialize()` so users usually do not need to call it themselves.
337 
338     Level: advanced
339 
340 .seealso: `PetscInfo()`, `PetscInfoAllow()`, `PetscInfoSetFile()`, `PetscInfoSetClasses()`, `PetscInfoSetFilterCommSelf()`, `PetscInfoDestroy()`
341 @*/
342 PetscErrorCode PetscInfoSetFromOptions(PetscOptions options) {
343   char      optstring[PETSC_MAX_PATH_LEN];
344   PetscBool set;
345 
346   PetscFunctionBegin;
347   PetscCall(PetscOptionsDeprecated_Private(NULL, "-info_exclude", NULL, "3.13", "Use -info instead"));
348   PetscCall(PetscOptionsGetString(options, NULL, "-info", optstring, PETSC_STATIC_ARRAY_LENGTH(optstring), &set));
349   if (set) {
350     size_t            size_loc0_, size_loc1_, size_loc2_;
351     char             *loc0_ = NULL, *loc1_ = NULL, *loc2_ = NULL;
352     char            **loc1_array  = NULL;
353     PetscBool         loc1_invert = PETSC_FALSE, loc2_invert = PETSC_FALSE;
354     int               nLoc1_       = 0;
355     PetscInfoCommFlag commSelfFlag = PETSC_INFO_COMM_ALL;
356 
357     PetscInfoClassesSet = PETSC_TRUE;
358     PetscCall(PetscInfoAllow(PETSC_TRUE));
359     PetscCall(PetscStrallocpy(optstring, &loc0_));
360     PetscCall(PetscStrchr(loc0_, ':', &loc1_));
361     if (loc1_) {
362       *loc1_++ = 0;
363       if (*loc1_ == '~') {
364         loc1_invert = PETSC_TRUE;
365         ++loc1_;
366       }
367       PetscCall(PetscStrchr(loc1_, ':', &loc2_));
368     }
369     if (loc2_) {
370       *loc2_++ = 0;
371       if (*loc2_ == '~') {
372         loc2_invert = PETSC_TRUE;
373         ++loc2_;
374       }
375     }
376     PetscCall(PetscStrlen(loc0_, &size_loc0_));
377     PetscCall(PetscStrlen(loc1_, &size_loc1_));
378     PetscCall(PetscStrlen(loc2_, &size_loc2_));
379     if (size_loc1_) {
380       PetscCall(PetscStrtolower(loc1_));
381       PetscCall(PetscStrToArray(loc1_, ',', &nLoc1_, &loc1_array));
382     }
383     if (size_loc2_) {
384       PetscBool foundSelf;
385 
386       PetscCall(PetscStrtolower(loc2_));
387       PetscCall(PetscStrcmp("self", loc2_, &foundSelf));
388       if (foundSelf) commSelfFlag = loc2_invert ? PETSC_INFO_COMM_NO_SELF : PETSC_INFO_COMM_ONLY_SELF;
389     }
390     PetscCall(PetscInfoSetFile(size_loc0_ ? loc0_ : NULL, "w"));
391     PetscCall(PetscInfoSetClasses(loc1_invert, (PetscInt)nLoc1_, (const char *const *)loc1_array));
392     PetscCall(PetscInfoSetFilterCommSelf(commSelfFlag));
393     PetscCall(PetscStrToArrayDestroy(nLoc1_, loc1_array));
394     PetscCall(PetscFree(loc0_));
395   }
396   PetscFunctionReturn(0);
397 }
398 
399 /*@
400   PetscInfoDestroy - Destroys and resets internal `PetscInfo()` data structures.
401 
402   Not Collective
403 
404   Note:
405   This is automatically called in `PetscFinalize()`. Useful for changing filters mid-program, or culling subsequent
406   `PetscInfo()` calls down the line.
407 
408   Level: developer
409 
410 .seealso: `PetscInfo()`, `PetscInfoSetFromOptions()`
411 @*/
412 PetscErrorCode PetscInfoDestroy(void) {
413   int err;
414 
415   PetscFunctionBegin;
416   PetscCall(PetscInfoAllow(PETSC_FALSE));
417   PetscCall(PetscStrNArrayDestroy(PetscInfoNumClasses, &PetscInfoClassnames));
418   err = fflush(PetscInfoFile);
419   PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fflush() failed on file");
420   if (PetscInfoFilename) PetscCall(PetscFClose(PETSC_COMM_SELF, PetscInfoFile));
421   PetscCall(PetscFree(PetscInfoFilename));
422   for (size_t i = 0; i < PETSC_STATIC_ARRAY_LENGTH(PetscInfoFlags); ++i) PetscInfoFlags[i] = 1;
423   PetscInfoClassesLocked = PETSC_FALSE;
424   PetscInfoInvertClasses = PETSC_FALSE;
425   PetscInfoClassesSet    = PETSC_FALSE;
426   PetscInfoNumClasses    = -1;
427   PetscInfoCommFilter    = PETSC_INFO_COMM_ALL;
428   PetscFunctionReturn(0);
429 }
430 
431 static PetscErrorCode PetscInfoSetClassActivation_Private(PetscClassId classid, int value) {
432   PetscFunctionBegin;
433   if (!classid) classid = PETSC_SMALLEST_CLASSID;
434   PetscInfoFlags[classid - PETSC_SMALLEST_CLASSID] = value;
435   PetscFunctionReturn(0);
436 }
437 
438 /*@
439   PetscInfoDeactivateClass - Deactivates `PetscInfo()` messages for a PETSc object class.
440 
441   Not Collective
442 
443   Input Parameter:
444 . classid - The object class,  e.g., `MAT_CLASSID`, `SNES_CLASSID`, etc.
445 
446   Note:
447   One can pass 0 to deactivate all messages that are not associated with an object.
448 
449   Level: developer
450 
451 .seealso: `PetscInfoActivateClass()`, `PetscInfo()`, `PetscInfoAllow()`, `PetscInfoSetFromOptions()`
452 @*/
453 PetscErrorCode PetscInfoDeactivateClass(PetscClassId classid) {
454   PetscFunctionBegin;
455   PetscCall(PetscInfoSetClassActivation_Private(classid, 0));
456   PetscFunctionReturn(0);
457 }
458 
459 /*@
460   PetscInfoActivateClass - Activates `PetscInfo()` messages for a PETSc object class.
461 
462   Not Collective
463 
464   Input Parameter:
465 . classid - The object class, e.g., `MAT_CLASSID`, `SNES_CLASSID`, etc.
466 
467   Note:
468   One can pass 0 to activate all messages that are not associated with an object.
469 
470   Level: developer
471 
472 .seealso: `PetscInfoDeactivateClass()`, `PetscInfo()`, `PetscInfoAllow()`, `PetscInfoSetFromOptions()`
473 @*/
474 PetscErrorCode PetscInfoActivateClass(PetscClassId classid) {
475   PetscFunctionBegin;
476   PetscCall(PetscInfoSetClassActivation_Private(classid, 1));
477   PetscFunctionReturn(0);
478 }
479 
480 /*
481    If the option -history was used, then all printed PetscInfo()
482   messages are also printed to the history file, called by default
483   .petschistory in ones home directory.
484 */
485 PETSC_INTERN FILE *petsc_history;
486 
487 /*MC
488     PetscInfo - Logs informative data
489 
490    Synopsis:
491        #include <petscsys.h>
492        PetscErrorCode PetscInfo(PetscObject obj, const char message[])
493        PetscErrorCode PetscInfo(PetscObject obj, const char formatmessage[],arg1)
494        PetscErrorCode PetscInfo(PetscObject obj, const char formatmessage[],arg1,arg2)
495        ...
496 
497     Collective on obj
498 
499     Input Parameters:
500 +   obj - object most closely associated with the logging statement or NULL
501 .   message - logging message
502 .   formatmessage - logging message using standard "printf" format
503 -   arg1, arg2, ... - arguments of the format
504 
505     Notes:
506     `PetscInfo()` prints only from the first processor in the communicator of obj.
507     If obj is NULL, the `PETSC_COMM_SELF` communicator is used, i.e. every rank of `PETSC_COMM_WORLD` prints the message.
508 
509     Extent of the printed messages can be controlled using the option database key -info as follows.
510 
511 $   -info [filename][:[~]<list,of,classnames>[:[~]self]]
512 
513     No filename means standard output `PETSC_STDOUT` is used.
514 
515     The optional <list,of,classnames> is a comma separated list of enabled classes, e.g. vec,mat,ksp.
516     If this list is not specified, all classes are enabled.
517     Prepending the list with ~ means inverted selection, i.e. all classes except the listed are enabled.
518     A special classname sys relates to PetscInfo() with obj being NULL.
519 
520     The optional self keyword specifies that PetscInfo() is enabled only for communicator size = 1 (e.g. `PETSC_COMM_SELF`), i.e. only `PetscInfo()` calls which print from every rank of `PETSC_COMM_WORLD` are enabled.
521     By contrast, ~self means that PetscInfo() is enabled only for communicator size > 1 (e.g. `PETSC_COMM_WORLD`), i.e. those `PetscInfo()` calls which print from every rank of `PETSC_COMM_WORLD` are disabled.
522 
523     All classname/self matching is case insensitive. Filename is case sensitive.
524 
525     Example of Usage:
526 $     Mat A;
527 $     PetscInt alpha;
528 $     ...
529 $     PetscInfo(A,"Matrix uses parameter alpha=%" PetscInt_FMT "\n",alpha);
530 
531     Options Examples:
532     Each call of the form
533 $     PetscInfo(obj, msg);
534 $     PetscInfo(obj, msg, arg1);
535 $     PetscInfo(obj, msg, arg1, arg2);
536     is evaluated as follows.
537 $     -info or -info :: prints msg to PETSC_STDOUT, for any obj regardless class or communicator
538 $     -info :mat:self prints msg to PETSC_STDOUT only if class of obj is Mat, and its communicator has size = 1
539 $     -info myInfoFileName:~vec:~self prints msg to file named myInfoFileName, only if the obj's class is NULL or other than Vec, and obj's communicator has size > 1
540 $     -info :sys prints to PETSC_STDOUT only if obj is NULL
541     Note that
542 $     -info :sys:~self
543     deactivates all info messages because sys means obj = NULL which implies PETSC_COMM_SELF but ~self filters out everything on PETSC_COMM_SELF.
544 
545     Fortran Note:
546     This function does not take the obj argument, there is only the `PetscInfo()`
547      version, not `PetscInfo()` etc.
548 
549     Level: intermediate
550 
551 .seealso: `PetscInfoAllow()`, `PetscInfoSetFromOptions()`
552 M*/
553 PetscErrorCode PetscInfo_Private(const char func[], PetscObject obj, const char message[], ...) {
554   PetscClassId classid = PETSC_SMALLEST_CLASSID;
555   PetscBool    enabled = PETSC_FALSE;
556   MPI_Comm     comm    = PETSC_COMM_SELF;
557   PetscMPIInt  rank;
558 
559   PetscFunctionBegin;
560   if (obj) {
561     PetscValidHeader(obj, 2);
562     classid = obj->classid;
563   }
564   PetscValidCharPointer(message, 3);
565   PetscCall(PetscInfoEnabled(classid, &enabled));
566   if (!enabled) PetscFunctionReturn(0);
567   if (obj) PetscCall(PetscObjectGetComm(obj, &comm));
568   PetscCallMPI(MPI_Comm_rank(comm, &rank));
569   /* rank > 0 always jumps out */
570   if (rank) PetscFunctionReturn(0);
571   else {
572     PetscMPIInt size;
573 
574     PetscCallMPI(MPI_Comm_size(comm, &size));
575     /* If no self printing is allowed, and size too small, get out */
576     if ((PetscInfoCommFilter == PETSC_INFO_COMM_NO_SELF) && (size < 2)) PetscFunctionReturn(0);
577     /* If ONLY self printing, and size too big, get out */
578     if ((PetscInfoCommFilter == PETSC_INFO_COMM_ONLY_SELF) && (size > 1)) PetscFunctionReturn(0);
579   }
580   /* Mute info messages within this function */
581   {
582     const PetscBool oldflag = PetscLogPrintInfo;
583     va_list         Argp;
584     PetscMPIInt     urank;
585     int             err;
586     char            string[8 * 1024];
587     size_t          fullLength, len;
588 
589     PetscLogPrintInfo = PETSC_FALSE;
590     PetscCallMPI(MPI_Comm_rank(MPI_COMM_WORLD, &urank));
591     va_start(Argp, message);
592     PetscCall(PetscSNPrintf(string, PETSC_STATIC_ARRAY_LENGTH(string), "[%d] %s(): ", urank, func));
593     PetscCall(PetscStrlen(string, &len));
594     PetscCall(PetscVSNPrintf(string + len, 8 * 1024 - len, message, &fullLength, Argp));
595     PetscCall(PetscFPrintf(PETSC_COMM_SELF, PetscInfoFile, "%s", string));
596     err = fflush(PetscInfoFile);
597     PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fflush() failed on file");
598     if (petsc_history) {
599       va_start(Argp, message);
600       PetscCall((*PetscVFPrintf)(petsc_history, message, Argp));
601     }
602     va_end(Argp);
603     PetscLogPrintInfo = oldflag;
604   }
605   PetscFunctionReturn(0);
606 }
607