profiling.C 9 KB
Newer Older
1
2
3
4
5
/*---------------------------------------------------------------------------*\
  =========                 |
  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
   \\    /   O peration     |
    \\  /    A nd           | Copyright (C) 2009-2016 Bernhard Gschaider
6
     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
-------------------------------------------------------------------------------
License
    This file is part of OpenFOAM.

    OpenFOAM is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    for more details.

    You should have received a copy of the GNU General Public License
    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.

\*---------------------------------------------------------------------------*/

26
#include "argList.H"
mark's avatar
mark committed
27
#include "profiling.H"
28
#include "profilingInformation.H"
mark's avatar
mark committed
29
#include "profilingSysInfo.H"
30
31
32
#include "cpuInfo.H"
#include "memInfo.H"
#include "demandDrivenData.H"
33
34
35

// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //

36
37
38
39
int Foam::profiling::allowed
(
    Foam::debug::infoSwitch("allowProfiling", 1)
);
40

41
Foam::profiling* Foam::profiling::pool_(nullptr);
42

43
44
// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //

45
46
47
48
49
Foam::profilingInformation* Foam::profiling::find
(
    const string& descr,
    const label parentId
)
50
{
51
    return hash_.lookup(Key(descr, parentId), nullptr);
52
}
53
54


55
Foam::profilingInformation* Foam::profiling::store(profilingInformation *info)
56
{
57
58
    // Profile information lookup is qualified by parent id
    hash_.insert(Key(info->description(), info->parent().id()), info);
59
    return info;
60
61
62
}


63
void Foam::profiling::push(profilingInformation *info, clockTime& timer)
64
{
65
66
67
68
69
70
71
72
73
74
75
76
77
    stack_.push(info);
    timers_.set(info->id(), &timer);
    info->push();                       // mark as on stack
}


Foam::profilingInformation* Foam::profiling::pop()
{
    profilingInformation *info = stack_.pop();
    timers_.erase(info->id());
    info->pop();                        // mark as off stack

    return info;
78
79
80
}


81
82
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //

mark's avatar
mark committed
83
bool Foam::profiling::active()
84
{
85
86
87
88
89
90
91
    return allowed && pool_;
}


void Foam::profiling::disable()
{
    allowed = 0;
92
93
94
}


95
96
bool Foam::profiling::print(Ostream& os)
{
97
    if (active())
98
99
100
101
102
103
104
105
106
107
    {
        return pool_->writeData(os);
    }
    else
    {
        return false;
    }
}


mark's avatar
mark committed
108
bool Foam::profiling::writeNow()
109
{
110
    if (active())
111
112
113
114
115
116
117
118
119
120
    {
        return pool_->write();
    }
    else
    {
        return false;
    }
}


mark's avatar
mark committed
121
void Foam::profiling::initialize
122
123
124
125
126
(
    const IOobject& ioObj,
    const Time& owner
)
{
127
    if (allowed && !pool_)
128
    {
mark's avatar
mark committed
129
        pool_ = new profiling(ioObj, owner);
130

131
        profilingInformation *info = pool_->store
132
        (
133
            new profilingInformation()
134
135
136
        );

        pool_->push(info, pool_->clockTime_);
137
138
139
140
        if (argList::bannerEnabled())
        {
            Info<< "profiling initialized" << nl;
        }
141
    }
142

143
144
    // silently ignore multiple initializations
    // eg, decomposePar uses multiple simultaneous Times
145
146
147
}


mark's avatar
mark committed
148
void Foam::profiling::initialize
149
150
151
152
153
154
(
    const dictionary& dict,
    const IOobject& ioObj,
    const Time& owner
)
{
155
    if (allowed && !pool_)
156
    {
mark's avatar
mark committed
157
        pool_ = new profiling(dict, ioObj, owner);
158

159
        profilingInformation *info = pool_->store
160
        (
161
            new profilingInformation()
162
163
164
        );

        pool_->push(info, pool_->clockTime_);
165
166
167
168
        if (argList::bannerEnabled())
        {
            Info<< "profiling initialized" << nl;
        }
169
    }
170

171
172
    // silently ignore multiple initializations
    // eg, decomposePar uses multiple simultaneous Times
173
174
175
}


mark's avatar
mark committed
176
void Foam::profiling::stop(const Time& owner)
177
178
179
180
{
    if (pool_ && &owner == &(pool_->owner_))
    {
        delete pool_;
181
        pool_ = nullptr;
182
183
184
185
    }
}


186
Foam::profilingInformation* Foam::profiling::New
187
(
188
    const string& descr,
189
190
191
    clockTime& timer
)
{
192
    profilingInformation *info = 0;
193

194
    if (active())
195
    {
196
197
        profilingInformation *parent = pool_->stack_.top();

198
        info = pool_->find(descr, parent->id());
199
200
        if (!info)
        {
201
            info = pool_->store(new profilingInformation(descr, parent));
202
203
204
        }

        pool_->push(info, timer);
205
206
207
208
209
210
211
212
213

        if (pool_->memInfo_)
        {
            info->maxMem_ = Foam::max
            (
                info->maxMem_,
                pool_->memInfo_->update().size()
            );
        }
214
215
216
217
218
219
    }

    return info;
}


220
void Foam::profiling::unstack(const profilingInformation *info)
221
{
222
    if (active() && info)
223
    {
224
        profilingInformation *top = pool_->pop();
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242

        if (info->id() != top->id())
        {
            FatalErrorInFunction
                << "The profiling information to unstack has different"
                << " id than on the top of the profiling stack" << nl
                << "  info: " << info->id() << " (" << info->description()
                << ")\n"
                << "  top:  " << top->id()  << " (" << top->description()
                << ")\n" << endl
                << abort(FatalError);
        }
    }
}


// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //

mark's avatar
mark committed
243
Foam::profiling::profiling
244
245
246
247
248
249
250
251
252
253
(
    const IOobject& io,
    const Time& owner
)
:
    regIOobject(io),
    owner_(owner),
    clockTime_(),
    hash_(),
    stack_(),
254
    timers_(),
255
    sysInfo_(new profilingSysInfo()),
256
257
258
259
260
    cpuInfo_(new cpuInfo()),
    memInfo_(new memInfo())
{}


mark's avatar
mark committed
261
Foam::profiling::profiling
262
263
264
265
266
267
268
269
270
271
272
273
274
275
(
    const dictionary& dict,
    const IOobject& io,
    const Time& owner
)
:
    regIOobject(io),
    owner_(owner),
    clockTime_(),
    hash_(),
    stack_(),
    timers_(),
    sysInfo_
    (
276
277
        dict.lookupOrDefault<bool>("sysInfo", false)
      ? new profilingSysInfo() : nullptr
278
279
280
    ),
    cpuInfo_
    (
281
282
        dict.lookupOrDefault<bool>("cpuInfo", false)
      ? new cpuInfo() : nullptr
283
284
285
    ),
    memInfo_
    (
286
287
        dict.lookupOrDefault<bool>("memInfo", false)
      ? new memInfo() : nullptr
288
    )
289
290
291
292
293
{}


// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //

mark's avatar
mark committed
294
Foam::profiling::~profiling()
295
{
296
297
298
299
    deleteDemandDrivenData(sysInfo_);
    deleteDemandDrivenData(cpuInfo_);
    deleteDemandDrivenData(memInfo_);

300
301
    if (pool_ == this)
    {
302
        pool_ = nullptr;
303
        profilingInformation::nextId_ = 0;
304
305
306
307
308
309
    }
}


// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //

mark's avatar
mark committed
310
const Foam::Time& Foam::profiling::owner() const
311
312
313
314
{
    return owner_;
}

315

mark's avatar
mark committed
316
Foam::label Foam::profiling::size() const
317
318
319
320
321
{
    return stack_.size();
}


mark's avatar
mark committed
322
bool Foam::profiling::writeData(Ostream& os) const
323
{
324
    os.beginBlock("profiling");
325
326
327

    // Add extra new line between entries
    label nTrigger = 0;
328
329
330
331
332
333
334
335

    // write on-stack items
    // newest is first on the stack, top-level is at the end
    // this is how the child times are summed
    {
        scalar oldElapsed = 0;
        forAllConstIter(StackContainer, stack_, iter)
        {
336
            const profilingInformation *info = *iter;
337
338
            scalar elapsed = timers_[info->id()]->elapsedTime();

339
340
341
342
            if (nTrigger++)
            {
                os << nl;
            }
343
344
345
346
347
348
349
350
351
352
353
354
355
356
            info->write(os, true, elapsed, oldElapsed);
            oldElapsed = elapsed;
        }
    }


    // write off-stack items
    // using an additional Map to sort by Id
    {
        typedef Map<const Information*> LookupContainer;
        LookupContainer lookup;

        forAllConstIter(StorageContainer, hash_, iter)
        {
357
            const profilingInformation *info = iter();
358
359
360
361
362
363
364
365
366

            if (!info->onStack())
            {
                lookup.set(info->id(), info);
            }
        }

        forAllConstIter(LookupContainer, lookup, iter)
        {
367
368
369
370
            if (nTrigger++)
            {
                os << nl;
            }
371
372
373
374
            iter()->write(os);
        }
    }

375
    os.endBlock();
376
377
378
379

    if (sysInfo_)
    {
        os << nl;
380
        os.beginBlock("sysInfo");
381
        sysInfo_->write(os);
382
        os.endBlock();
383
384
385
386
387
    }

    if (cpuInfo_)
    {
        os << nl;
388
        os.beginBlock("cpuInfo");
389
        cpuInfo_->write(os);
390
        os.endBlock();
391
392
393
394
395
396
397
    }

    if (memInfo_)
    {
        memInfo_->update();

        os << nl;
398
        os.beginBlock("memInfo");
399
        memInfo_->write(os);
400
401
        os.writeEntry("units", "kB");
        os.endBlock();
402
403
    }

404
405
406
407
    return os;
}


408
409
410
411
bool Foam::profiling::writeObject
(
    IOstream::streamFormat,
    IOstream::versionNumber ver,
412
413
    IOstream::compressionType,
    const bool valid
414
415
416
417
418
419
) const
{
    return regIOobject::writeObject
    (
        IOstream::ASCII,
        ver,
420
421
        IOstream::UNCOMPRESSED,
        true
422
423
424
425
    );
}


426
// ************************************************************************* //