From 6c0027dd31fa88c287e0605934e65aecccc8ced3 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Mon, 2 Oct 2023 11:00:00 -0700 Subject: [PATCH 1/4] 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 bd8dded4b5f..82f1a9dd9f7 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 29415ff842e..57deb72365e 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); From 3a58a9549d46bfd25f9bbc1196ed0d50aa7f6c48 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Mon, 2 Oct 2023 11:05:04 -0700 Subject: [PATCH 2/4] Update comment. --- kernel/yosys.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/yosys.h b/kernel/yosys.h index 57deb72365e..5ee5eb75f30 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -275,8 +275,8 @@ int ceil_log2(int x) YS_ATTRIBUTE(const); 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. + // For the common case of strings shorter than 128, save a heap + // allocation by using a stack allocated buffer. const int kBufSize = 128; char buf[kBufSize]; buf[0] = '\0'; From 31c334e8d5db6eae50bf6b4c4d504ab7fe58fb3d Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Mon, 2 Oct 2023 11:07:28 -0700 Subject: [PATCH 3/4] Remove local modifications. --- kernel/yosys.cc | 4 +--- kernel/yosys.h | 5 ----- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 82f1a9dd9f7..559ce872cad 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -74,7 +74,6 @@ #include #include "libs/json11/json11.hpp" -#include "devtools/build/runtime/get_runfiles_dir.h" YOSYS_NAMESPACE_BEGIN @@ -984,8 +983,7 @@ void init_share_dirname() return; } # ifdef YOSYS_DATDIR - proc_share_path = devtools_build::GetRunfilesDir() + "/"; - proc_share_path += YOSYS_DATDIR "/"; + 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 5ee5eb75f30..99edfb70036 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -343,11 +343,6 @@ 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); From 5739174968f04c1448e93ce5f5da15b9bab75643 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Mon, 2 Oct 2023 11:24:53 -0700 Subject: [PATCH 4/4] Fix compiler warnings from GCC. --- kernel/yosys.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/yosys.h b/kernel/yosys.h index 99edfb70036..97a79861e15 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -316,7 +316,9 @@ inline std::string vstringf(const char *fmt, va_list ap) #endif } -inline std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)) +std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)); + +inline std::string stringf(const char *fmt, ...) { std::string string; va_list ap;