From 98f2234523adf2d6dcd1b54f6713550bd6982c81 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Sat, 11 Nov 2023 08:28:44 -0300 Subject: [PATCH] refactor: reimplement a portable OS time function --- src/Makefile | 4 +- src/interpret.cpp | 2 +- src/machine.cpp | 13 ------ src/os.cpp | 92 ++++++++++++++++++++++++++++++++----------- src/os.h | 3 ++ src/riscv-constants.h | 2 +- src/state-access.h | 9 ++--- 7 files changed, 78 insertions(+), 47 deletions(-) diff --git a/src/Makefile b/src/Makefile index 3b6bdad6f..5f64c567c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -130,7 +130,7 @@ HASH_LIBS= #DEFS+= -DMT_ALL_DIRTY -WARNS=-W -Wall -pedantic +WARNS=-Wall -Wpedantic # Place our include directories before the system's INCS+= \ @@ -249,7 +249,7 @@ EMPTY:= SPACE:=$(EMPTY) $(EMPTY) CLANG_TIDY_HEADER_FILTER=$(PWD)/($(subst $(SPACE),|,$(LINTER_HEADERS))) -CXXFLAGS+=$(OPTFLAGS) -std=c++17 -fvisibility=hidden -fPIC -MMD $(CC_MARCH) $(INCS) $(GCFLAGS) $(UBFLAGS) $(DEFS) $(WARNS) +CXXFLAGS+=$(OPTFLAGS) -std=gnu++17 -fvisibility=hidden -fPIC -MMD $(CC_MARCH) $(INCS) $(GCFLAGS) $(UBFLAGS) $(DEFS) $(WARNS) CFLAGS+=$(OPTFLAGS) -std=gnu99 -fvisibility=hidden -fPIC -MMD $(CC_MARCH) $(INCS) $(GCFLAGS) $(UBFLAGS) $(DEFS) $(WARNS) LDFLAGS+=$(UBFLAGS) diff --git a/src/interpret.cpp b/src/interpret.cpp index d2c9db2c8..4e03b6849 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -5324,7 +5324,7 @@ static FORCE_INLINE execute_status execute_insn(STATE_ACCESS &a, uint64_t &pc, u return execute_ADDW_MULW_SUBW(a, pc, insn); case insn_funct3_00000_opcode::SRLW_DIVUW_SRAW: return execute_SRLW_DIVUW_SRAW(a, pc, insn); - case insn_funct3_00000_opcode::privileged: + case insn_funct3_00000_opcode::PRIVILEGED: return execute_privileged(a, pc, mcycle, insn); default: { // Here we are sure that the next instruction, at best, can only be a floating point instruction, diff --git a/src/machine.cpp b/src/machine.cpp index d8a0de245..05cd1e2a5 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -1388,14 +1388,6 @@ void machine::set_iflags_H(void) { m_s.iflags.H = true; } -#if 0 // Unused -static double now(void) { - using namespace std::chrono; - return static_cast(duration_cast(high_resolution_clock::now().time_since_epoch()).count()) * - 1.e-6; -} -#endif - void machine::mark_write_tlb_dirty_pages(void) const { for (uint64_t i = 0; i < PMA_TLB_SIZE; ++i) { const tlb_hot_entry &tlbhe = m_s.tlb.hot[TLB_WRITE][i]; @@ -1408,7 +1400,6 @@ void machine::mark_write_tlb_dirty_pages(void) const { } bool machine::verify_dirty_page_maps(void) const { - // double begin = now(); static_assert(PMA_PAGE_SIZE == machine_merkle_tree::get_page_size(), "PMA and machine_merkle_tree page sizes must match"); machine_merkle_tree::hasher_type h; @@ -1463,7 +1454,6 @@ static uint64_t get_task_concurrency(uint64_t value) { bool machine::update_merkle_tree(void) const { machine_merkle_tree::hasher_type gh; - // double begin = now(); static_assert(PMA_PAGE_SIZE == machine_merkle_tree::get_page_size(), "PMA and machine_merkle_tree page sizes must match"); // Go over the write TLB and mark as dirty all pages currently there @@ -1546,10 +1536,7 @@ bool machine::update_merkle_tree(void) const { // Otherwise, mark all pages in PMA as clean and move on to next pma->mark_pages_clean(); } - // std::cerr << "page updates done in " << now()-begin << "s\n"; - // begin = now(); const bool ret = m_t.end_update(gh); - // std::cerr << "inner tree updates done in " << now()-begin << "s\n"; return ret; } diff --git a/src/os.cpp b/src/os.cpp index dde065065..d302c9b27 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -18,6 +18,10 @@ #define HAVE_TTY #endif +#if !defined(NO_THREADS) +#define HAVE_THREADS +#endif + #if !defined(_WIN32) && !defined(__wasi__) && !defined(NO_TERMIOS) #define HAVE_TERMIOS #endif @@ -26,22 +30,23 @@ #define HAVE_MMAP #endif +#if !defined(_WIN32) && !defined(NO_MKDIR) +#define HAVE_MKDIR +#endif + #include +#include #include #include #include +#include #include #include "os.h" #include "unique-c-ptr.h" #if defined(HAVE_TTY) || defined(HAVE_MMAP) || defined(HAVE_TERMIOS) || defined(_WIN32) -#include // open -#include // write/read/close -#endif - -#if defined(HAVE_TTY) && !defined(_WIN32) -#include // select +#include // open #endif #ifdef HAVE_TERMIOS @@ -52,12 +57,31 @@ #include // mmap/munmap #endif +#if defined(HAVE_MMAP) || defined(HAVE_MKDIR) || defined(_WIN32) +#include // fstat/mkdir +#endif + #ifdef _WIN32 + #include // mkdir +#include // _write/_close #include + +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 0 #endif -#include // fstat +#else // not _WIN32 + +#if defined(HAVE_TTY) || defined(HAVE_MMAP) || defined(HAVE_TERMIOS) +#include // write/read/close +#endif + +#if defined(HAVE_TTY) +#include // select +#endif + +#endif // _WIN32 namespace cartesi { @@ -68,8 +92,8 @@ using namespace std::string_literals; struct tty_state { bool initialized{false}; std::array buf{}; // Characters in console input buffer - ssize_t buf_pos{}; - ssize_t buf_len{}; + intptr_t buf_pos{}; + intptr_t buf_len{}; #ifdef HAVE_TERMIOS int ttyfd{-1}; termios oldtty{}; @@ -183,21 +207,22 @@ void os_open_tty(void) { void os_close_tty(void) { #ifdef HAVE_TTY - auto *s = get_state(); - #ifdef HAVE_TERMIOS + auto *s = get_state(); if (s->ttyfd >= 0) { // Restore old mode tcsetattr(s->ttyfd, TCSANOW, &s->oldtty); close(s->ttyfd); s->ttyfd = 1; } + #elif defined(_WIN32) + auto *s = get_state(); if (s->hStdin) { SetConsoleMode(s->hStdin, s->dwOldStdinMode); s->hStdin = NULL; } -#endif // HAVE_TERMIOS +#endif // HAVE_TERMIOS #endif // HAVE_TTY } @@ -233,7 +258,7 @@ void os_poll_tty(uint64_t wait) { DWORD numberOfCharsRead = 0; // We must read input buffer through ReadConsole() to read raw terminal input if (ReadConsole(s->hStdin, s->buf.data(), s->buf.size(), &numberOfCharsRead, NULL)) { - s->buf_len = static_cast(numberOfCharsRead); + s->buf_len = static_cast(numberOfCharsRead); } break; } else { @@ -254,7 +279,7 @@ void os_poll_tty(uint64_t wait) { // Nothing to read return; } - s->buf_len = static_cast(read(STDIN_FILENO, s->buf.data(), s->buf.size())); + s->buf_len = static_cast(read(STDIN_FILENO, s->buf.data(), s->buf.size())); #endif // _WIN32 @@ -306,9 +331,15 @@ void os_putchar(uint8_t ch) { } else { // In interactive sessions we want to immediately write the character to stdout, // without any buffering. +#ifdef _WIN32 + if (_write(STDOUT_FILENO, &ch, 1) < 1) { + ; + } +#else if (write(STDOUT_FILENO, &ch, 1) < 1) { ; } +#endif } #else fputc_with_line_buffering(ch); @@ -316,12 +347,14 @@ void os_putchar(uint8_t ch) { } int os_mkdir(const char *path, int mode) { -#ifdef _WIN32 +#ifdef HAVE_MKDIR + return mkdir(path, mode); +#elif defined(_WIN32) (void) mode; return _mkdir(path); #else - return mkdir(path, mode); -#endif + return -1; +#endif // HAVE_MKDIR } unsigned char *os_map_file(const char *path, uint64_t length, bool shared) { @@ -368,10 +401,10 @@ unsigned char *os_map_file(const char *path, uint64_t length, bool shared) { return host_memory; #elif defined(_WIN32) - const int oflag = (shared ? O_RDWR : O_RDONLY) | O_BINARY; + const int oflag = (shared ? _O_RDWR : _O_RDONLY) | _O_BINARY; // Try to open image file - const int backing_file = open(path, oflag); + const int backing_file = _open(path, oflag); if (backing_file < 0) { throw std::system_error{errno, std::generic_category(), "could not open image file '"s + path + "'"s}; } @@ -379,14 +412,14 @@ unsigned char *os_map_file(const char *path, uint64_t length, bool shared) { // Try to get file size struct __stat64 statbuf {}; if (_fstat64(backing_file, &statbuf) < 0) { - close(backing_file); + _close(backing_file); throw std::system_error{errno, std::generic_category(), "unable to obtain length of image file '"s + path + "'"s}; } // Check that it matches range length if (static_cast(statbuf.st_size) != length) { - close(backing_file); + _close(backing_file); throw std::invalid_argument{"image file '"s + path + "' size ("s + std::to_string(static_cast(statbuf.st_size)) + ") does not match range length ("s + std::to_string(length) + ")"s}; @@ -398,19 +431,19 @@ unsigned char *os_map_file(const char *path, uint64_t length, bool shared) { HANDLE hFile = reinterpret_cast(_get_osfhandle(backing_file)); HANDLE hFileMappingObject = CreateFileMapping(hFile, NULL, flProtect, length >> 32, length & 0xffffffff, NULL); if (!hFileMappingObject) { - close(backing_file); + _close(backing_file); throw std::system_error{errno, std::generic_category(), "could not map image file '"s + path + "' to memory"s}; } DWORD dwDesiredAccess = shared ? FILE_MAP_WRITE : FILE_MAP_COPY; auto *host_memory = static_cast(MapViewOfFile(hFileMappingObject, dwDesiredAccess, 0, 0, length)); if (!host_memory) { - close(backing_file); + _close(backing_file); throw std::system_error{errno, std::generic_category(), "could not map image file '"s + path + "' to memory"s}; } // We can close the file after mapping it, because the OS will retain a reference of the file on its own - close(backing_file); + _close(backing_file); return host_memory; #else @@ -470,4 +503,15 @@ void os_unmap_file(unsigned char *host_memory, uint64_t length) { #endif // HAVE_MMAP } +int64_t os_now_us() { + std::chrono::time_point start{}; + static bool started = false; + if (!started) { + started = true; + start = std::chrono::high_resolution_clock::now(); + } + auto end = std::chrono::high_resolution_clock::now(); + return static_cast(std::chrono::duration_cast(end - start).count()); +} + } // namespace cartesi diff --git a/src/os.h b/src/os.h index 71750a738..a6d67aeb0 100644 --- a/src/os.h +++ b/src/os.h @@ -52,6 +52,9 @@ unsigned char *os_map_file(const char *path, uint64_t length, bool shared); /// \brief Unmaps a file from memory void os_unmap_file(unsigned char *host_memory, uint64_t length); +/// \brief Get time elapsed since its first call with microsecond precision +int64_t os_now_us(); + } // namespace cartesi #endif diff --git a/src/riscv-constants.h b/src/riscv-constants.h index 4749d3d63..93da6680e 100644 --- a/src/riscv-constants.h +++ b/src/riscv-constants.h @@ -793,7 +793,7 @@ enum class insn_funct3_00000_opcode : uint32_t { AND_REMU = 0b111000000110011, ADDW_MULW_SUBW = 0b000000000111011, SRLW_DIVUW_SRAW = 0b101000000111011, - privileged = 0b000000001110011, + PRIVILEGED = 0b000000001110011, }; /// \brief The result of insn >> 26 (6 most significant bits of funct7) can be diff --git a/src/state-access.h b/src/state-access.h index 5449afa3d..fecb938ca 100644 --- a/src/state-access.h +++ b/src/state-access.h @@ -21,7 +21,6 @@ /// \brief Fast state access implementation #include -#include #include "device-state-access.h" #include "i-state-access.h" @@ -406,12 +405,10 @@ class state_access : public i_state_access { if (warp_cycle > mcycle) { constexpr uint64_t cycles_per_us = RTC_CLOCK_FREQ / 1000000; // CLOCK_FREQ / 10^6 const uint64_t wait = (warp_cycle - mcycle) / cycles_per_us; - timeval start{}; - timeval end{}; - gettimeofday(&start, nullptr); + const int64_t start = os_now_us(); os_poll_tty(wait); - gettimeofday(&end, nullptr); - const uint64_t elapsed_us = (end.tv_sec - start.tv_sec) * 1000000 + end.tv_usec - start.tv_usec; + const int64_t end = os_now_us(); + const uint64_t elapsed_us = static_cast(std::max(end - start, INT64_C(0))); const uint64_t tty_cycle = mcycle + (elapsed_us * cycles_per_us); mcycle = std::min(std::max(tty_cycle, mcycle), warp_cycle); }