Loading...
Searching...
No Matches
profilingSummary.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2017-2022 OpenCFD Ltd.
9-------------------------------------------------------------------------------
10License
11 This file is part of OpenFOAM.
12
13 OpenFOAM is free software: you can redistribute it and/or modify it
14 under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25
26Application
27 profilingSummary
28
29Group
30 grpMiscUtilities
31
32Description
33 Collects information from profiling files in the processor
34 sub-directories and summarizes the number of calls and time spent as
35 max/avg/min values. If the values are identical for all processes,
36 only a single value is written.
37
38\*---------------------------------------------------------------------------*/
39
40#include "Time.H"
41#include "polyMesh.H"
42#include "OSspecific.H"
43#include "IFstream.H"
44#include "OFstream.H"
45#include "argList.H"
46#include "stringOps.H"
47#include "timeSelector.H"
48#include "IOobjectList.H"
49#include "functionObject.H"
50
51using namespace Foam;
52
53// The name of the sub-dictionary entry for profiling fileName:
54static const word profilingFileName("profiling");
55
56// The name of the sub-dictionary entry for profiling:
57static const word blockNameProfiling("profiling");
58
59// The name of the sub-dictionary entry for profiling and tags of entries
60// that will be processed to determine (max,avg,min) values
61const HashTable<wordList> processing
62{
63 { "profiling", { "calls", "totalTime", "childTime", "maxMem" } },
64 { "memInfo", { "size", "free" } },
65};
66
67
68// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
69
70int main(int argc, char *argv[])
71{
73 (
74 "Collect profiling information from processor directories and"
75 " summarize time spent and number of calls as (max avg min) values."
76 );
77
78 timeSelector::addOptions(true, true); // constant(true), zero(true)
80 argList::noFunctionObjects(); // Never use function objects
81
82 // Note that this should work without problems when profiling is active,
83 // since we don't trigger it anywhere
84
85 #include "setRootCase.H"
86 #include "createTime.H"
87
88 // Determine the processor count
89 const label nProcs = fileHandler().nProcs(args.path());
90
91 // Create the processor databases
92 PtrList<Time> databases(nProcs);
93
94 forAll(databases, proci)
95 {
96 databases.set
97 (
98 proci,
99 new Time
100 (
102 args.rootPath(),
103 args.caseName()/("processor" + Foam::name(proci)),
104 args.allowFunctionObjects(),
105 args.allowLibs()
106 )
107 );
108 }
109
110 if (!nProcs)
111 {
113 << "No processor* directories found"
114 << exit(FatalError);
115 }
116
117
118 // Use the times list from the master processor
119 // and select a subset based on the command-line options
121 (
122 databases[0].times(),
123 args
124 );
125
126 if (timeDirs.empty())
127 {
129 << "No times selected" << nl << endl;
130 return 1;
131 }
132
133 // ----------------------------------------------------------------------
134
135 // Processor local profiling information
136 List<dictionary> profiles(nProcs);
137
138 // Loop over all times
139 forAll(timeDirs, timei)
140 {
141 // Set time for global database
142 runTime.setTime(timeDirs[timei], timei);
143
144 Info<< "Time = " << runTime.timeName() << endl;
145
146 // Name/location for the output summary
147 const fileName outputName
148 {
150 "profiling",
151 runTime.timeName(),
152 profilingFileName
153 };
154
155
156 label nDict = 0;
157
158 // Set time for all databases
159 forAll(databases, proci)
160 {
161 profiles[proci].clear();
162 databases[proci].setTime(timeDirs[timei], timei);
163
164 // Look for "uniform/profiling" in each processor directory
165 IOobjectList objects
166 (
167 databases[proci].time(),
168 databases[proci].timeName(),
169 "uniform"
170 );
171
172 const IOobject* ioptr = objects.findObject(profilingFileName);
173 if (ioptr)
174 {
175 IOdictionary dict(*ioptr);
176
177 // Full copy
178 profiles[proci] = dict;
179
180 // Assumed to be good if it has 'profiling' sub-dict
181
182 const dictionary* ptr = dict.findDict(blockNameProfiling);
183 if (ptr)
184 {
185 ++nDict;
186 }
187 }
188
189 if (nDict < proci)
190 {
191 break;
192 }
193 }
194
195 if (nDict != nProcs)
196 {
197 Info<< "found " << nDict << "/" << nProcs
198 << " profiling files" << nl << endl;
199 continue;
200 }
201
202
203 // Information seems to be there for all processors
204 // can do a summary
205
206 IOdictionary summary
207 (
209 (
210 runTime.path()/outputName,
211 runTime,
215 true // global-like
216 )
217 );
218
219 summary.note() =
220 (
221 "summarized (max avg min) values from "
222 + Foam::name(nProcs) + " processors"
223 );
224
225
226 // Accumulator for each tag
228
229 // Use first as 'master' to decide what others have
230 forAllConstIters(profiles.first(), mainIter)
231 {
232 const entry& mainEntry = mainIter();
233
234 // level1: eg, profiling {} or memInfo {}
235 const word& level1Name = mainEntry.keyword();
236
237 if
238 (
239 !processing.found(level1Name)
240 || !mainEntry.isDict()
241 || mainEntry.dict().empty()
242 )
243 {
244 continue; // Only process known types
245 }
246
247 const wordList& tags = processing[level1Name];
248
249 const dictionary& level1Dict = mainEntry.dict();
250
251 // We need to handle sub-dicts with other dicts
252 // Eg, trigger0 { .. } trigger1 { .. }
253 //
254 // and ones with primitives
255 // Eg, size xx; free yy;
256
257 // Decide based on the first entry:
258
259 // level2: eg, profiling { trigger0 { } }
260 // or simply itself it contains primitives only
261
262 wordList level2Names;
263
264 const bool hasDictEntries
265 = mainEntry.dict().first()->isDict();
266
267 if (hasDictEntries)
268 {
269 level2Names =
271 }
272 else
273 {
274 level2Names = {level1Name};
275 }
276
277 summary.set(level1Name, dictionary());
278
279 dictionary& outputDict = summary.subDict(level1Name);
280
281 for (const word& level2Name : level2Names)
282 {
283 // Presize everything
284 stats.clear();
285 for (const word& tag : tags)
286 {
287 stats(tag).reserve(nProcs);
288 }
289
290 label nEntry = 0;
291
292 for (const dictionary& procDict : profiles)
293 {
294 const dictionary* inDictPtr = procDict.findDict(level1Name);
295
296 if (inDictPtr && hasDictEntries)
297 {
298 // Descend to the next level as required
299 inDictPtr = inDictPtr->findDict(level2Name);
300 }
301
302 if (!inDictPtr)
303 {
304 break;
305 }
306
307 ++nEntry;
308
309 for (const word& tag : tags)
310 {
311 scalar val;
312
313 if
314 (
315 inDictPtr->readIfPresent(tag, val, keyType::LITERAL)
316 )
317 {
318 stats(tag).append(val);
319 }
320 }
321 }
322
323 if (nEntry != nProcs)
324 {
325 continue;
326 }
327
328 dictionary* outDictPtr = nullptr;
329
330 // Make a full copy of this entry prior to editing it
331 if (hasDictEntries)
332 {
333 outputDict.add(level2Name, level1Dict.subDict(level2Name));
334 outDictPtr = outputDict.findDict(level2Name);
335 }
336 else
337 {
338 // merge into existing (empty) dictionary
339 summary.add(level1Name, level1Dict, true);
340 outDictPtr = &outputDict;
341 }
342
343 dictionary& outSubDict = *outDictPtr;
344
345 // Remove trailing 'processor0' from any descriptions
346 // (looks nicer)
347 {
348 const word key("description");
349 string val;
350
351 if (outSubDict.readIfPresent(key, val))
352 {
353 if (val.removeEnd("processor0"))
354 {
355 outSubDict.set(key, val);
356 }
357 }
358 }
359
360 // Process each tag (calls, time etc)
361 for (const word& tag : tags)
362 {
363 DynamicList<scalar>& lst = stats(tag);
364
365 if (lst.size() == nProcs)
366 {
367 sort(lst);
368 const scalar avg = sum(lst) / nProcs;
369
370 if (lst.first() != lst.last())
371 {
372 outSubDict.set
373 (
374 tag,
376 {
377 lst.last(), avg, lst.first()
378 }
379 );
380 }
381 }
382 }
383 }
384 }
385
386
387 // Now write the summary
388 {
389 mkDir(summary.path());
390
391 OFstream os(summary.objectPath());
392
393 summary.writeHeader(os);
394 summary.writeData(os);
396
397 Info<< "Wrote to " << outputName << nl << endl;
398 }
399 }
400
401 Info<< "End\n" << endl;
402
403 return 0;
404}
405
406
407// ************************************************************************* //
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
bool empty() const noexcept
True if the list is empty.
Definition DLListBase.H:189
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
A 1D vector of objects of type <T> with a fixed length <N>.
Definition FixedList.H:73
A HashTable similar to std::unordered_map.
Definition HashTable.H:124
bool found(const Key &key) const
Same as contains().
Definition HashTable.H:1370
void reserve(label numEntries)
Reserve space for at least the specified number of elements (not the number of buckets) and regenerat...
Definition HashTable.C:729
void clear()
Remove all entries from table.
Definition HashTable.C:742
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
List of IOobjects with searching and retrieving facilities. Implemented as a HashTable,...
@ NO_REGISTER
Do not request registration (bool: false).
@ NO_READ
Nothing to be read.
@ NO_WRITE
Ignore writing from objectRegistry::writeObject().
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition IOobject.H:191
static Ostream & writeEndDivider(Ostream &os)
Write the standard end file divider.
Output to file stream as an OSstream, normally using std::ofstream for the actual output.
Definition OFstream.H:75
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers....
Definition PtrList.H:67
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition Time.H:75
static word controlDictName
The default control dictionary name (normally "controlDict").
Definition Time.H:267
T * first()
The first entry in the list.
Definition UILList.H:542
T & first()
Access first element of the list, position [0].
Definition UList.H:957
bool empty() const noexcept
True if List is empty (ie, size() is zero).
Definition UList.H:701
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
T & last()
Access last element of the list, position [size()-1].
Definition UList.H:971
static void noFunctionObjects(bool addWithOption=false)
Remove '-noFunctionObjects' option and ignore any occurrences.
Definition argList.C:562
static void noParallel()
Remove the parallel options.
Definition argList.C:599
static void addNote(const string &note)
Add extra notes for the usage information.
Definition argList.C:477
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
const dictionary * findDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary pointer if present (and it is a dictionary) otherwise return nullptr...
const dictionary & subDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary.
Definition dictionary.C:441
bool readIfPresent(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry if present, and assign to T val. FatalIOError if it is found and the number of tokens i...
wordList sortedToc() const
Return the sorted table of contents.
Definition dictionary.C:601
entry * add(entry *entryPtr, bool mergeEntry=false)
Add a new entry.
Definition dictionary.C:625
entry * set(entry *entryPtr)
Assign a new entry, overwriting any existing entry.
Definition dictionary.C:765
A keyword and a list of tokens is an 'entry'.
Definition entry.H:66
virtual bool isDict() const noexcept
True if this entry is a dictionary.
Definition entry.H:284
const keyType & keyword() const noexcept
Return keyword.
Definition entry.H:231
virtual const dictionary & dict() const =0
Return dictionary, if entry is a dictionary, otherwise Fatal.
A class for handling file names.
Definition fileName.H:75
static word outputPrefix
Directory prefix.
@ LITERAL
String literal.
Definition keyType.H:82
bool removeEnd(const std::string &text)
Remove the given text from the end of the string.
Definition string.C:222
static void addOptions(const bool constant=true, const bool withZero=false)
Add timeSelector options to argList::validOptions.
instantList select(const instantList &times) const
Select a list of Time values that are within the ranges.
A class for handling words, derived from Foam::string.
Definition word.H:66
engineTime & runTime
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
word outputName("finiteArea-edges.obj")
OBJstream os(runTime.globalPath()/outputName)
word timeName
Definition getTimeIndex.H:3
#define WarningInFunction
Report a warning using Foam::Warning.
constexpr auto key(const Type &t) noexcept
Helper function to return the enum value.
Namespace for OpenFOAM.
List< word > wordList
List of word.
Definition fileName.H:60
refPtr< fileOperation > fileHandler(std::nullptr_t)
Delete current file handler - forwards to fileOperation::handler().
messageStream Info
Information stream (stdout output on master, null elsewhere).
List< instant > instantList
List of instants.
Definition instantList.H:41
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
void sort(UList< T > &list)
Sort the list.
Definition UList.C:283
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &f1, const label comm)
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition exprTraits.C:127
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
dictionary dict
Foam::argList args(argc, argv)
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
#define forAllConstIters(container, iter)
Iterate across all elements of the container object with const access.
Definition stdFoam.H:235
Encapsulation of natural order sorting for algorithms.
mkDir(pdfPath)