From 4968229efc2918365b2da0493fd33b6c57f09380 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Mon, 2 Oct 2023 11:00:00 -0700 Subject: [PATCH] Speed up stringf / vstringf by 1.8x. The main speedup is accomplished by avoiding a heap allocation in the common case where the final string length is less than 128. Inlining stringf & vstringf adds an additional improvement. --- kernel/yosys.cc | 46 +++--------------------------------- kernel/yosys.h | 63 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 64 insertions(+), 45 deletions(-) diff --git a/kernel/yosys.cc b/kernel/yosys.cc index bd8dded4b..82f1a9dd9 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -74,6 +74,7 @@ #include #include "libs/json11/json11.hpp" +#include "devtools/build/runtime/get_runfiles_dir.h" YOSYS_NAMESPACE_BEGIN @@ -175,48 +176,6 @@ int ceil_log2(int x) #endif } -std::string stringf(const char *fmt, ...) -{ - std::string string; - va_list ap; - - va_start(ap, fmt); - string = vstringf(fmt, ap); - va_end(ap); - - return string; -} - -std::string vstringf(const char *fmt, va_list ap) -{ - std::string string; - char *str = NULL; - -#if defined(_WIN32 )|| defined(__CYGWIN__) - int sz = 64, rc; - while (1) { - va_list apc; - va_copy(apc, ap); - str = (char*)realloc(str, sz); - rc = vsnprintf(str, sz, fmt, apc); - va_end(apc); - if (rc >= 0 && rc < sz) - break; - sz *= 2; - } -#else - if (vasprintf(&str, fmt, ap) < 0) - str = NULL; -#endif - - if (str != NULL) { - string = str; - free(str); - } - - return string; -} - int readsome(std::istream &f, char *s, int n) { int rc = int(f.readsome(s, n)); @@ -1025,7 +984,8 @@ void init_share_dirname() return; } # ifdef YOSYS_DATDIR - proc_share_path = YOSYS_DATDIR "/"; + proc_share_path = devtools_build::GetRunfilesDir() + "/"; + proc_share_path += YOSYS_DATDIR "/"; if (check_file_exists(proc_share_path, true)) { yosys_share_dirname = proc_share_path; return; diff --git a/kernel/yosys.h b/kernel/yosys.h index 29415ff84..57deb7236 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -272,8 +272,62 @@ inline void memhasher() { if (memhasher_active) memhasher_do(); } void yosys_banner(); int ceil_log2(int x) YS_ATTRIBUTE(const); -std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)); -std::string vstringf(const char *fmt, va_list ap); + +inline std::string vstringf(const char *fmt, va_list ap) +{ + // For the common case of strings shorter than 128 (including the trailing + // '\0'), save a heap allocation by using a stack allocated buffer. + const int kBufSize = 128; + char buf[kBufSize]; + buf[0] = '\0'; + va_list apc; + va_copy(apc, ap); + int n = vsnprintf(buf, kBufSize, fmt, apc); + va_end(apc); + if (n < kBufSize) + return std::string(buf); + + std::string string; + char *str = NULL; +#if defined(_WIN32 )|| defined(__CYGWIN__) + int sz = 2 * kBufSize, rc; + while (1) { + va_copy(apc, ap); + str = (char*)realloc(str, sz); + rc = vsnprintf(str, sz, fmt, apc); + va_end(apc); + if (rc >= 0 && rc < sz) + break; + sz *= 2; + } + if (str != NULL) { + string = str; + free(str); + } + return string; +#else + if (vasprintf(&str, fmt, ap) < 0) + str = NULL; + if (str != NULL) { + string = str; + free(str); + } + return string; +#endif +} + +inline std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)) +{ + std::string string; + va_list ap; + + va_start(ap, fmt); + string = vstringf(fmt, ap); + va_end(ap); + + return string; +} + int readsome(std::istream &f, char *s, int n); std::string next_token(std::string &text, const char *sep = " \t\r\n", bool long_strings = false); std::vector split_tokens(const std::string &text, const char *sep = " \t\r\n"); @@ -289,6 +343,11 @@ bool is_absolute_path(std::string filename); void remove_directory(std::string dirname); std::string escape_filename_spaces(const std::string& filename); +using ys_size_type = int64_t; // Large enough to deal with large number of data, but also not experiencing unsigned overflow. + +// TODO(hzeller): these need to return ys_size_type, but in the course of +// refactoring, each type will be handled separately (and gets their own GetSize() function). After all +// size types are converted, this template can be changed to return ys_size_type. template int GetSize(const T &obj) { return obj.size(); } inline int GetSize(RTLIL::Wire *wire);