Commit ef34e60e authored by Mark Olesen's avatar Mark Olesen
Browse files

ENH: add profiling code from Bernhard Gschaider

- activate via the case's <system/controlDict>:

      profiling   yes;
parent 9ab102bc
......@@ -3,6 +3,7 @@ global/global.Cver
/* global/constants/dimensionedConstants.C in global.Cver */
global/argList/argList.C
global/clock/clock.C
global/profiling/Profiling.C
bools = primitives/bools
$(bools)/bool/bool.C
......
......@@ -27,6 +27,7 @@ License
#include "PstreamReduceOps.H"
#include "argList.H"
#include "HashSet.H"
#include "Profiling.H"
#include <sstream>
......@@ -335,6 +336,24 @@ void Foam::Time::setControls()
void Foam::Time::setMonitoring()
{
// initialize profiling on request
if (controlDict_.lookupOrDefault<Switch>("profiling", false))
{
Profiling::initialize
(
IOobject
(
"profiling",
timeName(),
"uniform",
*this,
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
*this
);
}
// Time objects not registered so do like objectRegistry::checkIn ourselves.
if (runTimeModifiable_)
{
......@@ -651,6 +670,9 @@ Foam::Time::~Time()
// destroy function objects first
functionObjects_.clear();
// cleanup profiling
Profiling::stop(*this);
}
......@@ -892,9 +914,13 @@ bool Foam::Time::run() const
{
// Ensure functionObjects execute on last time step
// (and hence write uptodate functionObjectProperties)
addProfiling(foExec, "functionObjects.execute()");
functionObjects_.execute();
endProfiling(foExec);
addProfiling(foEnd, "functionObjects.end()");
functionObjects_.end();
endProfiling(foEnd);
}
}
......@@ -906,10 +932,12 @@ bool Foam::Time::run() const
if (timeIndex_ == startTimeIndex_)
{
addProfiling(functionObjects, "functionObjects.start()");
functionObjects_.start();
}
else
{
addProfiling(functionObjects, "functionObjects.execute()");
functionObjects_.execute();
}
}
......
......@@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
\\/ M anipulation |
\\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -27,6 +27,7 @@ License
#include "Pstream.H"
#include "simpleObjectRegistry.H"
#include "dimensionedConstants.H"
#include "Profiling.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
......@@ -518,6 +519,8 @@ bool Foam::Time::writeObject
{
if (outputTime())
{
addProfiling(writing, "objectRegistry::writeObject");
const word tmName(timeName());
IOdictionary timeDict
......
......@@ -26,6 +26,7 @@ License
#include "functionObjectList.H"
#include "Time.H"
#include "mapPolyMesh.H"
#include "Profiling.H"
// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
......@@ -220,6 +221,12 @@ bool Foam::functionObjectList::execute(const bool forceWrite)
forAll(*this, objectI)
{
addProfiling
(
fo,
"functionObject::" + operator[](objectI).name() + "::execute"
);
ok = operator[](objectI).execute(forceWrite) && ok;
}
}
......@@ -257,6 +264,12 @@ bool Foam::functionObjectList::end()
forAll(*this, objectI)
{
addProfiling
(
fo,
"functionObject::" + operator[](objectI).name() + "::end"
);
ok = operator[](objectI).end() && ok;
}
}
......@@ -339,6 +352,8 @@ bool Foam::functionObjectList::read()
label nFunc = 0;
addProfiling(fo,"functionObjects::read");
if (entryPtr->isDict())
{
// A dictionary of functionObjects
......@@ -366,12 +381,24 @@ bool Foam::functionObjectList::read()
// An existing functionObject, and dictionary changed
if (newDigs[nFunc] != digests_[oldIndex])
{
addProfiling
(
fo2,
"functionObject::" + objPtr->name() + "::read"
);
ok = objPtr->read(dict) && ok;
}
}
else
{
// New functionObject
addProfiling
(
fo2,
"functionObject::" + key + "::start"
);
objPtr = functionObject::New(key, time_, dict).ptr();
ok = objPtr->start() && ok;
}
......
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2009-2016 Bernhard Gschaider
\\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
-------------------------------------------------------------------------------
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/>.
\*---------------------------------------------------------------------------*/
#include "Profiling.H"
#include "dictionary.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
Foam::Profiling* Foam::Profiling::pool_(0);
Foam::label Foam::Profiling::Information::nextId_(0);
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
Foam::label Foam::Profiling::Information::getNextId()
{
return nextId_++;
}
void Foam::Profiling::Information::raiseID(label maxVal)
{
if (nextId_ < maxVal)
{
nextId_ = maxVal;
}
}
void Foam::Profiling::initialize
(
const IOobject& ioObj,
const Time& owner
)
{
if (pool_)
{
WarningInFunction
<< "Already initialized" << endl;
}
else
{
pool_ = new Profiling(ioObj, owner);
Information *info = pool_->store
(
new Information()
);
pool_->push(info, pool_->clockTime_);
info->push(); // mark as on stack
}
}
void Foam::Profiling::stop(const Time& owner)
{
if (pool_ && &owner == &(pool_->owner_))
{
delete pool_;
pool_ = 0;
}
}
Foam::Profiling::Information* Foam::Profiling::New
(
const string& name,
clockTime& timer
)
{
Information *info = 0;
if (pool_)
{
info = pool_->find(name);
if (!info)
{
info = pool_->store
(
new Information(pool_->stack_.top(), name)
);
}
pool_->push(info, timer);
info->push(); // mark as on stack
}
return info;
}
void Foam::Profiling::unstack(const Information *info)
{
if (pool_ && info)
{
Information *top = pool_->stack_.pop();
top->pop(); // mark as off stack
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 * * * * * * * * * * * * * * //
Foam::Profiling::Profiling
(
const IOobject& io,
const Time& owner
)
:
regIOobject(io),
owner_(owner),
clockTime_(),
hash_(),
stack_(),
timers_()
{}
Foam::Profiling::Information::Information()
:
id_(getNextId()),
description_("application::main"),
parent_(this),
calls_(0),
totalTime_(0),
childTime_(0),
onStack_(false)
{}
Foam::Profiling::Information::Information
(
Information *parent,
const string& descr
)
:
id_(getNextId()),
description_(descr),
parent_(parent),
calls_(0),
totalTime_(0),
childTime_(0),
onStack_(false)
{}
Foam::Profiling::Trigger::Trigger(const char* name)
:
clock_(),
ptr_(Profiling::New(name, clock_))
{}
Foam::Profiling::Trigger::Trigger(const string& name)
:
clock_(),
ptr_(Profiling::New(name, clock_))
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::Profiling::~Profiling()
{
if (pool_ == this)
{
pool_ = 0;
Information::nextId_ = 0;
}
}
Foam::Profiling::Information::~Information()
{}
Foam::Profiling::Trigger::~Trigger()
{
stop();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::Profiling::Information* Foam::Profiling::find(const string& name)
{
StorageContainer::iterator iter = hash_.find(name);
return (iter != hash_.end() ? iter() : 0);
}
void Foam::Profiling::Information::update(const scalar& elapsed)
{
++calls_;
totalTime_ += elapsed;
if (id_ != parent().id())
{
parent().childTime_ += elapsed;
}
}
bool Foam::Profiling::writeData(Ostream& os) const
{
os << indent << "profiling" << nl
<< indent << token::BEGIN_LIST << incrIndent << nl;
// 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)
{
const Information *info = *iter;
scalar elapsed = timers_[info->id()]->elapsedTime();
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)
{
const Information *info = iter();
if (!info->onStack())
{
lookup.set(info->id(), info);
}
}
forAllConstIter(LookupContainer, lookup, iter)
{
iter()->write(os);
}
}
os << decrIndent
<< indent << token::END_LIST << token::END_STATEMENT << nl;
return os;
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::Profiling::Information* Foam::Profiling::store(Information *info)
{
hash_.insert(info->description(), info);
return info;
}
void Foam::Profiling::push(Information *info, clockTime& timer)
{
stack_.push(info);
timers_.insert(info->id(), &timer);
}
void Foam::Profiling::Trigger::stop()
{
if (ptr_)
{
ptr_->update(clock_.elapsedTime());
Profiling::unstack(ptr_);
// pointer is managed by pool storage -> thus no delete here
}
ptr_ = 0;
}
// file-scope function
template<class T>
inline static void writeEntry
(
Foam::Ostream& os, const Foam::word& key, const T& value
)
{
os.writeKeyword(key) << value << Foam::token::END_STATEMENT << '\n';
}
Foam::Ostream& Foam::Profiling::Information::write
(
Ostream& os,
const bool offset,
const scalar& elapsedTime,
const scalar& childTimes
) const
{
// write in dictionary format
// os.beginBlock("_" + Foam::name(id_)) << nl;
os.beginBlock() << nl; // FUTURE: without nl
// FUTURE: os.writeEntry(key, value);
writeEntry(os, "id", id_);
if (id_ != parent().id())
{
writeEntry(os, "parentId", parent().id());
}
writeEntry(os, "description", description());
writeEntry(os, "calls", calls() + (offset ? 1 : 0));
writeEntry(os, "totalTime", totalTime() + elapsedTime);
writeEntry(os, "childTime", childTime() + childTimes);
writeEntry(os, "onStack", Switch(onStack()));
os.endBlock() << nl; // FUTURE: without nl
return os;
}
// * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
Foam::Ostream& Foam::operator<<
(
Ostream& os,
const Profiling::Information& info
)
{
return info.write(os);
}
// ************************************************************************* //
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2009-2016 Bernhard Gschaider
\\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
-------------------------------------------------------------------------------
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/>.
Class
Foam::Profiling
Description
Code profiling.
SourceFiles
Profiling.C
\*---------------------------------------------------------------------------*/
#ifndef Profiling_H
#define Profiling_H
#include "HashPtrTable.H"
#include "LIFOStack.H"
#include "Map.H"
#include "Time.H"
#include "clockTime.H"
namespace Foam
{
// Forward declaration of classes
class Ostream;
/*---------------------------------------------------------------------------*\
Class Profiling Declaration
\*---------------------------------------------------------------------------*/
class Profiling
:
public regIOobject
{
public:
// Forward declarations of components
class Information;
class Trigger;
private:
// Private Static Data Members
//- Only one global pool object is possible
static Profiling *pool_;
// Private Data Members
typedef HashPtrTable<Information, string> StorageContainer;
typedef LIFOStack<Information*> StackContainer;
//- The owner of the profiling
const Time& owner_;
//- A global timer for the profiling