Skip to content

Commit

Permalink
#58: introduce ResolveMapCache and trigger force cook on RPK change
Browse files Browse the repository at this point in the history
* allowing the pldAssign params to have values other than in the dropdowns (easier to debug the values when the RPK changes)
* the RPK change detection can be triggered by toggling a pldAssign parameter or by clicking on the parameter dropdowns of start rule, style or rule file.
  • Loading branch information
mistafunk committed Mar 3, 2018
1 parent 9f20fab commit f325176
Show file tree
Hide file tree
Showing 10 changed files with 161 additions and 79 deletions.
1 change: 1 addition & 0 deletions src/palladio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ add_library(${PROJECT_NAME} SHARED
ShapeGenerator.cpp
NodeParameter.cpp
PRTContext.cpp
ResolveMapCache.cpp
SOPAssign.cpp
SOPGenerate.cpp
PrimitivePartition.cpp
Expand Down
6 changes: 0 additions & 6 deletions src/palladio/NodeParameter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,6 @@ int updateRPK(void* data, int, fpreal32 time, const PRM_Template*) {
node->evalString(utNextRPKStr, AssignNodeParams::RPK.getToken(), 0, time);
const boost::filesystem::path nextRPK(utNextRPKStr.toStdString());

// -- early exit if rpk path is not valid
if (!boost::filesystem::exists(nextRPK)) {
LOG_WRN << "non-existent rpk";
return NOT_CHANGED;
}

const ResolveMapUPtr& resolveMap = prtCtx->getResolveMap(nextRPK);
if (!resolveMap ) {
LOG_WRN << "invalid resolve map";
Expand Down
9 changes: 3 additions & 6 deletions src/palladio/NodeParameter.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,7 @@ const std::string RULE_FILE_HELP = "Sets value for primitive attribute '" + PLD_

void buildRuleFileMenu(void *data, PRM_Name *theMenu, int theMaxSize, const PRM_SpareData *, const PRM_Parm *);

static PRM_ChoiceList ruleFileMenu(static_cast<PRM_ChoiceListType>(PRM_CHOICELIST_EXCLUSIVE | PRM_CHOICELIST_REPLACE),
&buildRuleFileMenu);
static PRM_ChoiceList ruleFileMenu(static_cast<PRM_ChoiceListType>(PRM_CHOICELIST_REPLACE), &buildRuleFileMenu);

auto getRuleFile = [](const OP_Node* node, fpreal t) -> std::wstring {
UT_String s;
Expand All @@ -91,8 +90,7 @@ const std::string STYLE_HELP = "Sets value for primitive attribute '" + PLD_STYL

void buildStyleMenu(void *data, PRM_Name *theMenu, int theMaxSize, const PRM_SpareData *, const PRM_Parm *);

static PRM_ChoiceList styleMenu(static_cast<PRM_ChoiceListType>(PRM_CHOICELIST_EXCLUSIVE | PRM_CHOICELIST_REPLACE),
&buildStyleMenu);
static PRM_ChoiceList styleMenu(static_cast<PRM_ChoiceListType>(PRM_CHOICELIST_REPLACE), &buildStyleMenu);

auto getStyle = [](const OP_Node* node, fpreal t) -> std::wstring {
UT_String s;
Expand All @@ -112,8 +110,7 @@ const std::string START_RULE_HELP = "Sets value for primitive attribute '" + PLD

void buildStartRuleMenu(void *data, PRM_Name *theMenu, int theMaxSize, const PRM_SpareData *, const PRM_Parm *);

static PRM_ChoiceList startRuleMenu(static_cast<PRM_ChoiceListType>(PRM_CHOICELIST_EXCLUSIVE | PRM_CHOICELIST_REPLACE),
&buildStartRuleMenu);
static PRM_ChoiceList startRuleMenu(static_cast<PRM_ChoiceListType>(PRM_CHOICELIST_REPLACE), &buildStartRuleMenu);

auto getStartRule = [](const OP_Node* node, fpreal t) -> std::wstring {
UT_String s;
Expand Down
90 changes: 35 additions & 55 deletions src/palladio/PRTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@
*/

#include "PRTContext.h"
#include "PalladioMain.h"
#include "LogHandler.h"
#include "SOPAssign.h"

#include "OP/OP_Node.h"
#include "OP/OP_Director.h"
#include "OP/OP_Network.h"

#include <thread>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef WIN32
# include <unistd.h>
#endif


namespace {
Expand Down Expand Up @@ -97,15 +98,24 @@ uint32_t getNumCores() {
return n > 0 ? n : 1;
}

const timespec NO_MODIFICATION_TIME{0, 0};
/**
* schedule recook of all assign nodes with matching rpk
*/
void scheduleRecook(const boost::filesystem::path& rpk) {
auto visit = [](OP_Node& n, void* data) -> bool {
if (n.getOperator()->getName().equal(OP_PLD_ASSIGN)) {
auto rpk = reinterpret_cast<boost::filesystem::path*>(data);
SOPAssign& sa = static_cast<SOPAssign&>(n);
if (sa.getRPK() == *rpk) {
LOG_DBG << "forcing recook of: " << n.getName() << ", " << n.getOpType() << ", " << n.getOperator()->getName();
sa.forceRecook();
}
}
return false;
};

timespec getFileModificationTime(const boost::filesystem::path& p) {
struct stat result;
if (stat(p.c_str(), &result) == 0) {
return result.st_mtim;
}
else
return NO_MODIFICATION_TIME;
OP_Network* objMgr = OPgetDirector()->getManager("obj");
objMgr->traverseChildren(visit, const_cast<void*>(reinterpret_cast<const void*>(&rpk)), true);
}

} // namespace
Expand All @@ -115,8 +125,8 @@ PRTContext::PRTContext(const std::vector<boost::filesystem::path>& addExtDirs)
: mLogHandler(new logging::LogHandler(PLD_LOG_PREFIX)),
mLicHandle{nullptr},
mPRTCache{prt::CacheObject::create(prt::CacheObject::CACHE_TYPE_DEFAULT)},
mRPKUnpackPath{boost::filesystem::temp_directory_path() / (PLD_TMP_PREFIX + std::to_string(::getpid()))},
mCores{getNumCores()}
mCores{getNumCores()},
mResolveMapCache{new ResolveMapCache(boost::filesystem::temp_directory_path() / (PLD_TMP_PREFIX + std::to_string(::getpid())))}
{
const prt::LogLevel logLevel = getLogLevel();
prt::setLogLevel(logLevel);
Expand Down Expand Up @@ -162,53 +172,23 @@ PRTContext::PRTContext(const std::vector<boost::filesystem::path>& addExtDirs)
}

PRTContext::~PRTContext() {
mPRTCache.reset();
mResolveMapCache.reset();
LOG_INF << "Released RPK Cache";

mPRTCache.reset(); // calling reset manually to ensure order
LOG_INF << "Released PRT cache";

mLicHandle.reset();
mLicHandle.reset(); // same here
LOG_INF << "Shutdown PRT & returned license";

boost::filesystem::remove_all(mRPKUnpackPath);
LOG_INF << "Removed RPK unpack directory";

prt::removeLogHandler(mLogHandler.get());
}

const ResolveMapUPtr& PRTContext::getResolveMap(const boost::filesystem::path& rpk) {
if (rpk.empty())
return mResolveMapNone;

const auto timeStamp = getFileModificationTime(rpk);
LOG_DBG << "rpk: current timestamp: " << timeStamp.tv_sec << "s " << timeStamp.tv_nsec << "ns";

bool reload = false;
auto it = mResolveMapCache.find(rpk);
if (it != mResolveMapCache.end()) {
LOG_DBG << "rpk: cache timestamp: " << it->second.mTimeStamp.tv_sec << "s " << it->second.mTimeStamp.tv_nsec << "ns";
if (it->second.mTimeStamp.tv_sec != timeStamp.tv_sec || it->second.mTimeStamp.tv_nsec != timeStamp.tv_nsec) {
mResolveMapCache.erase(it);
const auto cnt = boost::filesystem::remove_all(mRPKUnpackPath / rpk.leaf());
mPRTCache->flushAll(); // TODO: or do we need to explicitely remove cgbs from cache?
LOG_DBG << "RPK change detected, refreshing unpack cache: " << rpk << "( removed " << cnt << " files)";
reload = true;
}
auto lookupResult = mResolveMapCache->get(rpk);
if (lookupResult.second == ResolveMapCache::CacheStatus::MISS) {
mPRTCache->flushAll();
scheduleRecook(rpk);
}
else
reload = true;

if (reload) {
const auto rpkURI = toFileURI(rpk);

ResolveMapCacheEntry rmce;
rmce.mTimeStamp = timeStamp;

prt::Status status = prt::STATUS_UNSPECIFIED_ERROR;
rmce.mResolveMap.reset(prt::createResolveMap(rpkURI.c_str(), mRPKUnpackPath.wstring().c_str(), &status));
if (status != prt::STATUS_OK)
return mResolveMapNone;

it = mResolveMapCache.emplace(rpk, std::move(rmce)).first;
}

return it->second.mResolveMap;
return lookupResult.first;
}
11 changes: 2 additions & 9 deletions src/palladio/PRTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#pragma once

#include "ResolveMapCache.h"
#include "Utils.h"

#include "prt/Object.h"
Expand Down Expand Up @@ -47,16 +48,8 @@ struct PRTContext final {
logging::LogHandlerPtr mLogHandler;
ObjectUPtr mLicHandle;
CacheObjectUPtr mPRTCache;
boost::filesystem::path mRPKUnpackPath;
const uint32_t mCores;

struct ResolveMapCacheEntry {
ResolveMapUPtr mResolveMap;
timespec mTimeStamp;
};
using ResolveMapCache = std::map<boost::filesystem::path, ResolveMapCacheEntry>;
ResolveMapCache mResolveMapCache;
const ResolveMapUPtr mResolveMapNone;
ResolveMapCacheUPtr mResolveMapCache;
};

using PRTContextUPtr = std::unique_ptr<PRTContext>;
8 changes: 5 additions & 3 deletions src/palladio/PalladioMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
* limitations under the License.
*/

#include "PalladioMain.h"

#include "PRTContext.h"
#include "SOPAssign.h"
#include "SOPGenerate.h"
#include "PRTContext.h"
#include "NodeParameter.h"

#include "OP/OP_OperatorTable.h"
Expand Down Expand Up @@ -47,15 +49,15 @@ void newSopOperator(OP_OperatorTable *table) {
auto createSOPAssign = [](OP_Network *net, const char *name, OP_Operator *op) -> OP_Node* {
return new SOPAssign(prtCtx, net, name, op);
};
table->addOperator(new OP_Operator("pldAssign", "pldAssign", createSOPAssign,
table->addOperator(new OP_Operator(OP_PLD_ASSIGN, OP_PLD_ASSIGN, createSOPAssign,
AssignNodeParams::PARAM_TEMPLATES, 1, 1, nullptr, OP_FLAG_GENERATOR
));

// instantiate generator sop
auto createSOPGenerate = [](OP_Network *net, const char *name, OP_Operator *op) -> OP_Node* {
return new SOPGenerate(prtCtx, net, name, op);
};
table->addOperator(new OP_Operator("pldGenerate", "pldGenerate", createSOPGenerate,
table->addOperator(new OP_Operator(OP_PLD_GENERATE, OP_PLD_GENERATE, createSOPGenerate,
GenerateNodeParams::PARAM_TEMPLATES, 1, 1, nullptr, OP_FLAG_GENERATOR
));
}
4 changes: 4 additions & 0 deletions src/palladio/PalladioMain.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#pragma once

constexpr const char* OP_PLD_ASSIGN = "pldAssign";
constexpr const char* OP_PLD_GENERATE = "pldGenerate";
73 changes: 73 additions & 0 deletions src/palladio/ResolveMapCache.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//
// Created by shaegler on 3/3/18.
//

#include "ResolveMapCache.h"
#include "LogHandler.h"


namespace {

const ResolveMapUPtr RESOLVE_MAP_NONE;
const timespec NO_MODIFICATION_TIME{0, 0};

timespec getFileModificationTime(const boost::filesystem::path& p) {
struct stat result;
if (stat(p.c_str(), &result) == 0) {
return result.st_mtim;
}
else
return NO_MODIFICATION_TIME;
}

} // namespace


ResolveMapCache::~ResolveMapCache() {
boost::filesystem::remove_all(mRPKUnpackPath);
LOG_INF << "Removed RPK unpack directory";
}

ResolveMapCache::LookupResult ResolveMapCache::get(const boost::filesystem::path& rpk) {
if (rpk.empty())
return { RESOLVE_MAP_NONE, CacheStatus::MISS };

if (!boost::filesystem::exists(rpk))
return { RESOLVE_MAP_NONE, CacheStatus::MISS };

const auto timeStamp = getFileModificationTime(rpk);
LOG_DBG << "rpk: current timestamp: " << timeStamp.tv_sec << "s " << timeStamp.tv_nsec << "ns";

CacheStatus cs = CacheStatus::HIT;
auto it = mCache.find(rpk);
if (it != mCache.end()) {
LOG_DBG << "rpk: cache timestamp: " << it->second.mTimeStamp.tv_sec << "s " << it->second.mTimeStamp.tv_nsec << "ns";
if (it->second.mTimeStamp.tv_sec != timeStamp.tv_sec || it->second.mTimeStamp.tv_nsec != timeStamp.tv_nsec) {
mCache.erase(it);
const auto cnt = boost::filesystem::remove_all(mRPKUnpackPath / rpk.leaf());
LOG_INF << "RPK change detected, forcing reload and clearing cache for " << rpk << " (removed " << cnt << " files)";
cs = CacheStatus::MISS;
}
}
else
cs = CacheStatus::MISS;

if (cs == CacheStatus::MISS) {
const auto rpkURI = toFileURI(rpk);

ResolveMapCacheEntry rmce;
rmce.mTimeStamp = timeStamp;

prt::Status status = prt::STATUS_UNSPECIFIED_ERROR;
rmce.mResolveMap.reset(prt::createResolveMap(rpkURI.c_str(), mRPKUnpackPath.wstring().c_str(), &status));
if (status != prt::STATUS_OK)
return { RESOLVE_MAP_NONE, CacheStatus::MISS };

it = mCache.emplace(rpk, std::move(rmce)).first;
LOG_INF << "Upacked RPK " << rpk << " to " << mRPKUnpackPath;
}

return { it->second.mResolveMap, cs };

}

37 changes: 37 additions & 0 deletions src/palladio/ResolveMapCache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#pragma once

#include "Utils.h"

#include "boost/filesystem.hpp"

#include <sys/types.h>
#include <sys/stat.h>
#ifndef WIN32
# include <unistd.h>
#endif


class ResolveMapCache {
public:
ResolveMapCache(const boost::filesystem::path& unpackPath) : mRPKUnpackPath{unpackPath} { }
ResolveMapCache(const ResolveMapCache&) = delete;
ResolveMapCache(ResolveMapCache&&) = delete;
ResolveMapCache& operator=(ResolveMapCache&) = delete;
~ResolveMapCache();

enum class CacheStatus { HIT, MISS };
using LookupResult = std::pair<const ResolveMapUPtr&, CacheStatus>;
LookupResult get(const boost::filesystem::path& rpk);

private:
struct ResolveMapCacheEntry {
ResolveMapUPtr mResolveMap;
timespec mTimeStamp;
};
using Cache = std::map<boost::filesystem::path, ResolveMapCacheEntry>;
Cache mCache;

const boost::filesystem::path mRPKUnpackPath;
};

using ResolveMapCacheUPtr = std::unique_ptr<ResolveMapCache>;
1 change: 1 addition & 0 deletions src/palladio/SOPAssign.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class SOPAssign : public SOP_Node {
~SOPAssign() override = default;

const PRTContextUPtr& getPRTCtx() const { return mPRTCtx; }
const boost::filesystem::path& getRPK() const { return mShapeConverter->mRPK; }

void opChanged(OP_EventType reason, void* data = nullptr) override;

Expand Down

0 comments on commit f325176

Please sign in to comment.