Skip to content

Commit

Permalink
refactor: reimplement a portable OS time function
Browse files Browse the repository at this point in the history
  • Loading branch information
edubart committed Nov 11, 2023
1 parent 2a62108 commit 98f2234
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 47 deletions.
4 changes: 2 additions & 2 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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+= \
Expand Down Expand Up @@ -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)

Expand Down
2 changes: 1 addition & 1 deletion src/interpret.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
13 changes: 0 additions & 13 deletions src/machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<double>(duration_cast<microseconds>(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];
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}

Expand Down
92 changes: 68 additions & 24 deletions src/os.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -26,22 +30,23 @@
#define HAVE_MMAP
#endif

#if !defined(_WIN32) && !defined(NO_MKDIR)
#define HAVE_MKDIR
#endif

#include <array>
#include <chrono>
#include <cstdint>
#include <cstdio>
#include <iostream>
#include <string>
#include <system_error>

#include "os.h"
#include "unique-c-ptr.h"

#if defined(HAVE_TTY) || defined(HAVE_MMAP) || defined(HAVE_TERMIOS) || defined(_WIN32)
#include <fcntl.h> // open
#include <unistd.h> // write/read/close
#endif

#if defined(HAVE_TTY) && !defined(_WIN32)
#include <sys/select.h> // select
#include <fcntl.h> // open
#endif

#ifdef HAVE_TERMIOS
Expand All @@ -52,12 +57,31 @@
#include <sys/mman.h> // mmap/munmap
#endif

#if defined(HAVE_MMAP) || defined(HAVE_MKDIR) || defined(_WIN32)
#include <sys/stat.h> // fstat/mkdir
#endif

#ifdef _WIN32

#include <direct.h> // mkdir
#include <io.h> // _write/_close
#include <windows.h>

#ifndef STDOUT_FILENO
#define STDOUT_FILENO 0
#endif

#include <sys/stat.h> // fstat
#else // not _WIN32

#if defined(HAVE_TTY) || defined(HAVE_MMAP) || defined(HAVE_TERMIOS)
#include <unistd.h> // write/read/close
#endif

#if defined(HAVE_TTY)
#include <sys/select.h> // select
#endif

#endif // _WIN32

namespace cartesi {

Expand All @@ -68,8 +92,8 @@ using namespace std::string_literals;
struct tty_state {
bool initialized{false};
std::array<char, 1024> 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{};
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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<ssize_t>(numberOfCharsRead);
s->buf_len = static_cast<intptr_t>(numberOfCharsRead);
}
break;
} else {
Expand All @@ -254,7 +279,7 @@ void os_poll_tty(uint64_t wait) {
// Nothing to read
return;
}
s->buf_len = static_cast<ssize_t>(read(STDIN_FILENO, s->buf.data(), s->buf.size()));
s->buf_len = static_cast<intptr_t>(read(STDIN_FILENO, s->buf.data(), s->buf.size()));

#endif // _WIN32

Expand Down Expand Up @@ -306,22 +331,30 @@ 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);
#endif // HAVE_TTY
}

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) {
Expand Down Expand Up @@ -368,25 +401,25 @@ 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};
}

// 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<uint64_t>(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<uint64_t>(statbuf.st_size)) + ") does not match range length ("s +
std::to_string(length) + ")"s};
Expand All @@ -398,19 +431,19 @@ unsigned char *os_map_file(const char *path, uint64_t length, bool shared) {
HANDLE hFile = reinterpret_cast<HANDLE>(_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<unsigned char *>(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
Expand Down Expand Up @@ -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<std::chrono::high_resolution_clock> 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<int64_t>(std::chrono::duration_cast<std::chrono::microseconds>(end - start).count());
}

} // namespace cartesi
3 changes: 3 additions & 0 deletions src/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion src/riscv-constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 3 additions & 6 deletions src/state-access.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
/// \brief Fast state access implementation

#include <cassert>
#include <sys/time.h>

#include "device-state-access.h"
#include "i-state-access.h"
Expand Down Expand Up @@ -406,12 +405,10 @@ class state_access : public i_state_access<state_access, pma_entry> {
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<uint64_t>(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);
}
Expand Down

0 comments on commit 98f2234

Please sign in to comment.