/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2009-2016 Bernhard Gschaider Copyright (C) 2016-2022 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 . \*---------------------------------------------------------------------------*/ #include "argList.H" #include "profiling.H" #include "profilingInformation.H" #include "profilingSysInfo.H" #include "cpuInfo.H" #include "memInfo.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // int Foam::profiling::allowed(Foam::debug::infoSwitch("allowProfiling", 1)); std::unique_ptr Foam::profiling::singleton_(nullptr); // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // Foam::profilingInformation* Foam::profiling::create() { // Top-level entry: reset everything pool_.clear(); children_.clear(); stack_.clear(); times_.clear(); Information* info = new Information; pool_.push_back(info); children_.resize(pool_.size()); children_.back().clear(); // safety return info; } Foam::profilingInformation* Foam::profiling::create ( profilingInformation *parent, const string& descr ) { const label parentId = parent->id(); for (Information* child : children_[parentId]) { if (descr == child->description()) { return child; // Found existing } } Information* info = new Information(parent, descr, pool_.size()); pool_.push_back(info); children_.resize(pool_.size()); children_.back().clear(); // safety children_[parentId].push_back(info); return info; } void Foam::profiling::beginTimer(profilingInformation *info) { stack_.push_back(info); times_.push_back(clockValue::now()); info->setActive(true); // Mark as on stack } Foam::profilingInformation* Foam::profiling::endTimer() { Information *info = stack_.back(); clockValue clockval = times_.back(); stack_.pop_back(); times_.pop_back(); info->update(clockval.elapsed()); // Update elapsed time info->setActive(false); // Mark as off stack return info; } // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // bool Foam::profiling::active() { return allowed && singleton_; } void Foam::profiling::disable() { allowed = 0; } bool Foam::profiling::print(Ostream& os) { if (active()) { return singleton_->writeData(os); } return false; } bool Foam::profiling::writeNow() { if (active()) { return singleton_->regIOobject::write(); } return false; } void Foam::profiling::initialize ( const IOobject& ioObj, const Time& owner ) { if (allowed && !singleton_) { singleton_.reset(new profiling(ioObj, owner)); } } void Foam::profiling::initialize ( const dictionary& dict, const IOobject& ioObj, const Time& owner ) { if (allowed && !singleton_) { singleton_.reset(new profiling(dict, ioObj, owner)); } } void Foam::profiling::stop(const Time& owner) { if (singleton_ && &owner == &(singleton_->owner_)) { singleton_.reset(nullptr); } } Foam::profilingInformation* Foam::profiling::New(const string& descr) { Information *info = nullptr; if (active()) { Information *parent = singleton_->stack_.back(); info = singleton_->create(parent, descr); singleton_->beginTimer(info); if (singleton_->memInfo_) { info->maxMem_ = Foam::max ( info->maxMem_, singleton_->memInfo_->update().size() ); } } return info; } void Foam::profiling::unstack(const profilingInformation *info) { if (active() && info) { Information *top = singleton_->endTimer(); if (info->id() != top->id()) { FatalErrorInFunction << "Profiling information to unstack has different id than" << " 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, const bool allEnabled ) : IOdictionary(io), owner_(owner), pool_(), children_(), stack_(), times_(), sysInfo_(nullptr), cpuInfo_(nullptr), memInfo_(nullptr) { if (allEnabled) { sysInfo_.reset(new profilingSysInfo); cpuInfo_.reset(new cpuInfo); memInfo_.reset(new memInfo); } Information *info = this->create(); this->beginTimer(info); DetailInfo << "profiling initialized" << nl; } Foam::profiling::profiling ( const dictionary& dict, const IOobject& io, const Time& owner ) : profiling(io, owner, false) { if (dict.getOrDefault("sysInfo", false)) { sysInfo_.reset(new profilingSysInfo); } if (dict.getOrDefault("cpuInfo", false)) { cpuInfo_.reset(new cpuInfo); } if (dict.getOrDefault("memInfo", false)) { memInfo_.reset(new memInfo); } } // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // Foam::profiling::~profiling() { if (this == singleton_.get()) { singleton_.reset(nullptr); } } // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // const Foam::Time& Foam::profiling::owner() const { return owner_; } Foam::label Foam::profiling::size() const noexcept { return stack_.size(); } bool Foam::profiling::writeData(Ostream& os) const { static DynamicList elapsed; const clockValue now(clockValue::now()); const label nstack = stack_.size(); elapsed.resize(nstack+1); // extend for last entry, which has no child. for (label stacki=0; stacki < nstack; ++stacki) { elapsed[stacki] = (now - times_[stacki]); } elapsed.back() = 0; os.beginBlock("profiling"); // Active items for (label stacki=0; stacki < nstack; ++stacki) { if (stacki) os << nl; // Extra line between entries stack_[stacki]->write ( os, true, elapsed[stacki], // elapsedTime elapsed[stacki+1] // childTimes ); } // Non-active items for (const Information& info : pool_) { if (!info.active()) { os << nl; info.write(os); } } os.endBlock(); if (sysInfo_) { os << nl; os.beginBlock("sysInfo"); sysInfo_->write(os); os.endBlock(); } if (cpuInfo_) { os << nl; os.beginBlock("cpuInfo"); cpuInfo_->write(os); os.endBlock(); } if (memInfo_) { memInfo_->update(); os << nl; os.beginBlock("memInfo"); memInfo_->write(os); os.writeEntry("units", "kB"); os.endBlock(); } return os.good(); } bool Foam::profiling::writeObject ( IOstreamOption, const bool valid ) const { return regIOobject::writeObject ( IOstreamOption(IOstreamOption::ASCII), true ); } // ************************************************************************* //