3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-04-08 18:31:51 +00:00

Liberty file caching with new libcache command

This adds optional in-memory caching of parsed liberty files to speed up
flows that repeatedly parse the same liberty files. To avoid increasing
the memory overhead by default, the caching is disabled by default. The
caching can be controlled globally or on a per path basis using the new
`libcache` command, which also allows purging cached data.
This commit is contained in:
Jannis Harder 2025-04-03 13:11:48 +02:00
parent 26a4b9b0c6
commit 0f13b55173
9 changed files with 253 additions and 17 deletions

View file

@ -539,7 +539,7 @@ struct LibertyFrontend : public Frontend {
log_header(design, "Executing Liberty frontend: %s\n", filename.c_str());
LibertyParser parser(*f);
LibertyParser parser(*f, filename);
int cell_count = 0;
std::map<std::string, std::tuple<int, int, bool>> global_type_map;

View file

@ -352,7 +352,7 @@ void read_liberty_cellarea(dict<IdString, cell_area_t> &cell_area, string libert
yosys_input_files.insert(liberty_file);
if (f->fail())
log_cmd_error("Can't open liberty file `%s': %s\n", liberty_file.c_str(), strerror(errno));
LibertyParser libparser(*f);
LibertyParser libparser(*f, liberty_file);
delete f;
for (auto cell : libparser.ast->children)

View file

@ -6,6 +6,7 @@ OBJS += passes/techmap/dfflibmap.o
OBJS += passes/techmap/maccmap.o
OBJS += passes/techmap/booth.o
OBJS += passes/techmap/libparse.o
OBJS += passes/techmap/libcache.o
ifeq ($(ENABLE_ABC),1)
OBJS += passes/techmap/abc.o

View file

@ -312,7 +312,7 @@ struct ClockgatePass : public Pass {
std::istream* f = uncompressed(path);
if (f->fail())
log_cmd_error("Can't open liberty file `%s': %s\n", path.c_str(), strerror(errno));
LibertyParser p(*f);
LibertyParser p(*f, path);
merged.merge(p);
delete f;
}

View file

@ -634,7 +634,7 @@ struct DfflibmapPass : public Pass {
std::istream* f = uncompressed(path);
if (f->fail())
log_cmd_error("Can't open liberty file `%s': %s\n", path.c_str(), strerror(errno));
LibertyParser p(*f);
LibertyParser p(*f, path);
merged.merge(p);
delete f;
}

130
passes/techmap/libcache.cc Normal file
View file

@ -0,0 +1,130 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2025 Jannis Harder <jix@yosyshq.com> <me@jix.one>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "passes/techmap/libparse.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct LibcachePass : public Pass {
LibcachePass() : Pass("libcache", "control caching of technology library data parsed from liberty files") { }
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" libcache {-enable|-disable|-purge} { -all | [path]... }\n");
log("\n");
log("Controls the default and per path caching of liberty file data.\n");
log("\n");
log(" -enable Enable caching.\n");
log(" -disable Disable caching.\n");
log(" -purge Reset cache setting and forget cached data.\n");
log("\n");
log("This mode takes a list of paths as argument. If no paths are provided, this\n");
log("command does nothing. The -all option can be used to change the default cache\n");
log("setting for -enable/-disable or to reset and forget about all paths.\n");
log("\n");
log("By default caching is disabled.\n");
log("\n");
log(" libcache -list\n");
log("\n");
log("Displays the current cache settings and cached paths.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *) override
{
bool enable = false;
bool disable = false;
bool purge = false;
bool all = false;
bool list = false;
std::vector<std::string> paths;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-enable") {
enable = true;
continue;
}
if (args[argidx] == "-disable") {
enable = true;
continue;
}
if (args[argidx] == "-purge") {
purge = true;
continue;
}
if (args[argidx] == "-all") {
all = true;
continue;
}
if (args[argidx] == "-list") {
list = true;
continue;
}
std::string fname = args[argidx];
rewrite_filename(fname);
paths.push_back(fname);
break;
}
int modes = enable + disable + purge + list;
if (modes == 0)
log_cmd_error("At least one of -enable, -disable, -purge or -list is required.\n");
if (modes > 1)
log_cmd_error("Only one of -enable, -disable, -purge or -list may be present.\n");
if (all && !paths.empty())
log_cmd_error("The -all option cannot be combined with a list of paths.\n");
if (list && (all || !paths.empty()))
log_cmd_error("The -list mode takes no further options.\n");
if (!list && !all && paths.empty())
log("No paths specified, use -all to %s\n", purge ? "purge all paths" : "change the default setting");
if (list) {
log("Caching is %s by default.\n", LibertyAstCache::instance.cache_by_default ? "enabled" : "disabled");
for (auto const &entry : LibertyAstCache::instance.cache_path)
log("Caching is %s for `%s'.\n", entry.second ? "enabled" : "disabled", entry.first.c_str());
for (auto const &entry : LibertyAstCache::instance.cached)
log("Data for `%s' is currently cached.\n", entry.first.c_str());
} else if (enable || disable) {
if (all) {
LibertyAstCache::instance.cache_by_default = enable;
} else {
for (auto const &path : paths) {
LibertyAstCache::instance.cache_path[path] = enable;
}
}
} else if (purge) {
if (all) {
LibertyAstCache::instance.cached.clear();
LibertyAstCache::instance.cache_path.clear();
} else {
for (auto const &path : paths) {
LibertyAstCache::instance.cached.erase(path);
LibertyAstCache::instance.cache_path.erase(path);
}
}
} else {
log_assert(false);
}
}
} LibcachePass;
PRIVATE_NAMESPACE_END

View file

@ -32,6 +32,31 @@
using namespace Yosys;
#ifndef FILTERLIB
LibertyAstCache LibertyAstCache::instance;
std::shared_ptr<const LibertyAst> LibertyAstCache::cached_ast(const std::string &fname)
{
auto it = cached.find(fname);
if (it == cached.end())
return nullptr;
log("Using cached data for liberty file `%s'\n", fname.c_str());
return it->second;
}
void LibertyAstCache::parsed_ast(const std::string &fname, const std::shared_ptr<const LibertyAst> &ast)
{
auto it = cache_path.find(fname);
bool should_cache = it == cache_path.end() ? cache_by_default : it->second;
if (!should_cache)
return;
log("Caching data for liberty file `%s'\n", fname.c_str());
cached.emplace(fname, ast);
}
#endif
bool LibertyInputStream::extend_buffer_once()
{
if (eof)

View file

@ -132,6 +132,22 @@ namespace Yosys
}
};
#ifndef FILTERLIB
class LibertyAstCache {
LibertyAstCache() {};
~LibertyAstCache() {};
public:
dict<std::string, std::shared_ptr<const LibertyAst>> cached;
bool cache_by_default = false;
dict<std::string, bool> cache_path;
std::shared_ptr<const LibertyAst> cached_ast(const std::string &fname);
void parsed_ast(const std::string &fname, const std::shared_ptr<const LibertyAst> &ast);
static LibertyAstCache instance;
};
#endif
class LibertyMergedCells;
class LibertyParser
{
@ -152,15 +168,29 @@ namespace Yosys
void error(const std::string &str) const;
public:
const LibertyAst *ast;
std::shared_ptr<const LibertyAst> shared_ast;
const LibertyAst *ast = nullptr;
LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {}
~LibertyParser() { if (ast) delete ast; }
LibertyParser(std::istream &f) : f(f), line(1) {
shared_ast.reset(parse());
ast = shared_ast.get();
}
#ifndef FILTERLIB
LibertyParser(std::istream &f, const std::string &fname) : f(f), line(1) {
shared_ast = LibertyAstCache::instance.cached_ast(fname);
if (!shared_ast) {
shared_ast.reset(parse());
LibertyAstCache::instance.parsed_ast(fname, shared_ast);
}
ast = shared_ast.get();
}
#endif
};
class LibertyMergedCells
{
std::vector<const LibertyAst *> asts;
std::vector<std::shared_ptr<const LibertyAst>> asts;
public:
std::vector<const LibertyAst *> cells;
@ -168,10 +198,7 @@ namespace Yosys
{
if (parser.ast) {
const LibertyAst *ast = parser.ast;
asts.push_back(ast);
// The parser no longer owns its top level ast, but we do.
// sketchy zone
parser.ast = nullptr;
asts.push_back(parser.shared_ast);
if (ast->id != "library")
parser.error("Top level entity isn't \"library\".\n");
for (const LibertyAst *cell : ast->children)
@ -179,11 +206,6 @@ namespace Yosys
cells.push_back(cell);
}
}
~LibertyMergedCells()
{
for (auto ast : asts)
delete ast;
}
};
}

58
tests/liberty/libcache.ys Normal file
View file

@ -0,0 +1,58 @@
libcache -enable busdef.lib
logger -expect log "Caching is disabled by default." 1
logger -expect log "Caching is enabled for `busdef.lib'." 1
libcache -list
logger -check-expected
logger -expect log "Caching data" 1
log Caching data
read_liberty normal.lib; design -reset
logger -check-expected
logger -expect log "Caching data" 1
read_liberty -lib busdef.lib; design -reset
logger -check-expected
logger -expect log "Using caching data" 1
log Using caching data
read_liberty normal.lib; design -reset
logger -check-expected
logger -expect log "Using cached data" 1
read_liberty -lib busdef.lib; design -reset
logger -check-expected
libcache -purge busdef.lib
logger -expect log "Caching is disabled by default." 1
logger -expect log "Caching is enabled for `busdef.lib'." 1
log Caching is enabled for `busdef.lib'.
libcache -list
logger -check-expected
libcache -enable -all
logger -expect log "Caching is enabled by default." 1
libcache -list
logger -check-expected
logger -expect log "Caching data" 1
read_liberty normal.lib; design -reset
logger -check-expected
logger -expect log "Caching data" 1
read_liberty -lib busdef.lib; design -reset
logger -check-expected
logger -expect log "Using cached data" 1
read_liberty -lib busdef.lib; design -reset
logger -check-expected
logger -expect log "Using cached data" 1
read_liberty normal.lib; design -reset
logger -check-expected
logger -expect log "Using cached data" 1
dfflibmap -liberty normal.lib
logger -check-expected