Skip to content

Commit

Permalink
Merge pull request #454 from gofractally/cpu-billing
Browse files Browse the repository at this point in the history
Add CPU billing
  • Loading branch information
swatanabe authored Jul 13, 2023
2 parents cf6e3d2 + d9755e4 commit 0d9c79b
Show file tree
Hide file tree
Showing 42 changed files with 884 additions and 112 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ if(BUILD_RUST)
COMMAND cp -a ${CMAKE_CURRENT_BINARY_DIR}/AuthInviteSys.wasm ${BOOT_IMAGE}
COMMAND cp -a ${CMAKE_CURRENT_BINARY_DIR}/CommonSys.wasm ${BOOT_IMAGE}
COMMAND cp -a ${CMAKE_CURRENT_BINARY_DIR}/CoreFractalSys.wasm ${BOOT_IMAGE}
COMMAND cp -a ${CMAKE_CURRENT_BINARY_DIR}/CpuSys.wasm ${BOOT_IMAGE}
COMMAND cp -a ${CMAKE_CURRENT_BINARY_DIR}/ExploreSys.wasm ${BOOT_IMAGE}
COMMAND cp -a ${CMAKE_CURRENT_BINARY_DIR}/FractalSys.wasm ${BOOT_IMAGE}
COMMAND cp -a ${CMAKE_CURRENT_BINARY_DIR}/InviteSys.wasm ${BOOT_IMAGE}
Expand Down
1 change: 1 addition & 0 deletions doc/psidk/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
- [Web Services](services/cpp-service/reference/web-services.md)
- [Magic Numbers](services/cpp-service/reference/magic-numbers.md)
- [Native Functions](services/cpp-service/reference/native-functions.md)
- [System Functions](services/cpp-service/reference/system.md)
- [CMake Support](services/cpp-service/reference/cmake.md)
- [Rust Services](services/rust-service.md)
- [Basic Service](services/rust-service/basic.md)
Expand Down
1 change: 1 addition & 0 deletions doc/psidk/src/services/cpp-service/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
- [Web Services](reference/web-services.md)
- [Magic Numbers](reference/magic-numbers.md)
- [Native Functions](reference/native-functions.md)
- [System Functions](reference/system.md)
- [CMake Support](reference/cmake.md)
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ This is the set of raw native functions (wasm imports). They are available for s

- [psibase::raw::abortMessage]
- [psibase::raw::call]
- [psibase::raw::clockTimeGet]
- [psibase::raw::getCurrentAction]
- [psibase::raw::getKey]
- [psibase::raw::getResult]
Expand All @@ -100,6 +101,7 @@ This is the set of raw native functions (wasm imports). They are available for s

{{#cpp-doc ::psibase::raw::abortMessage}}
{{#cpp-doc ::psibase::raw::call}}
{{#cpp-doc ::psibase::raw::clockTimeGet}}
{{#cpp-doc ::psibase::raw::getCurrentAction}}
{{#cpp-doc ::psibase::raw::getKey}}
{{#cpp-doc ::psibase::raw::getResult}}
Expand Down
32 changes: 32 additions & 0 deletions doc/psidk/src/services/cpp-service/reference/system.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# System Functions

Some parts of the C++ standard library that interact with the host system are restricted or unavailable in services.

## I/O

Only stdout and stderr are available. They both write to a single merged stream which is in included the transaction trace. stdin is not supported.

Supported APIs:
- `write`
- `printf` family
- `std::cout`, `std::cerr`, `std::clog`

## Clocks

UTC, monotonic, and CPU clocks are available to subjective services. The monotonic clock is only guaranteed to be monotonic within a block. The CPU clock measures CPU time spent on the current transaction.

Supported APIs:
- `clock_gettime` with `CLOCK_REALITME`, `CLOCK_MONOTONIC`, or `CLOCK_PROCESS_CPUTIME_ID`
- `clock`
- `time`
- `std::chrono::system_clock`
- `std::chrono::monotonic_clock`
- `std::chrono::high_resolution_clock`

## Unavailable Functionality

- Filesystem
- Nondeterministic random numbers
- Concurrency
- Exceptions
- `setjmp`/`longjmp`
8 changes: 8 additions & 0 deletions libraries/net/test/test_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <services/system/AccountSys.hpp>
#include <services/system/AuthAnySys.hpp>
#include <services/system/CpuSys.hpp>
#include <services/system/ProducerSys.hpp>
#include <services/system/TransactionSys.hpp>
#include <services/system/VerifyEcSys.hpp>
Expand Down Expand Up @@ -80,6 +81,11 @@ void boot(BlockContext* ctx, const Consensus& producers, bool ec)
.flags = TransactionSys::serviceFlags,
.code = readWholeFile("TransactionSys.wasm"),
},
{
.service = CpuSys::service,
.flags = CpuSys::serviceFlags,
.code = readWholeFile("CpuSys.wasm"),
},
{
.service = AccountSys::service,
.flags = 0,
Expand Down Expand Up @@ -219,6 +225,8 @@ BlockMessage makeBlock(const BlockInfo& info,
}
}
trx.subjectiveData.emplace();
trx.subjectiveData->emplace_back();
trx.subjectiveData->push_back(psio::to_frac(std::chrono::nanoseconds(100000)));
m.push(TransactionInfo{trx});
}
newBlock.block.transactions = std::move(trxs);
Expand Down
8 changes: 7 additions & 1 deletion libraries/psibase/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function(add suffix)

if(DEFINED IS_WASM)
target_link_libraries(psibase${suffix} PUBLIC wasm-base${suffix})
target_mapped_include_directories(psibase${suffix} PUBLIC common/include)
target_mapped_include_directories(psibase${suffix} PUBLIC common/include wasm32-wasi)

add_library(simple-malloc-objects${suffix} OBJECT service/src/simple_malloc.cpp)
target_link_libraries(simple-malloc-objects${suffix} PUBLIC wasm-base${suffix})
Expand Down Expand Up @@ -42,6 +42,7 @@ function(add suffix)
target_link_libraries(psibase-service-wasi-polyfill${suffix} PUBLIC wasm-base${suffix})
target_sources(psibase-service-wasi-polyfill${suffix} PRIVATE
service/src/ossl.c
service/src/time.c
service/src/wasi-polyfill/__wasi_clock_time_get.cpp
service/src/wasi-polyfill/__wasi_environ_get.cpp
service/src/wasi-polyfill/__wasi_environ_sizes_get.cpp
Expand Down Expand Up @@ -109,6 +110,7 @@ function(add suffix)
tester/src/testUtils.cpp
service/src/intrinsic.cpp
service/src/ossl.c
service/src/time.c
tester/src/tester_intrinsics.cpp
tester/src/wasi_polyfill/__wasi_args_get.cpp
tester/src/wasi_polyfill/__wasi_args_sizes_get.cpp
Expand Down Expand Up @@ -150,6 +152,7 @@ function(add suffix)
../../services/system/ProducerSys/include
../../services/system/AuthEcSys/include
../../services/system/AuthAnySys/include
../../services/system/CpuSys/include
../../services/system/ProxySys/include
../../services/system/SetCodeSys/include
../../services/system/TransactionSys/include
Expand Down Expand Up @@ -191,8 +194,10 @@ function(add suffix)
native/src/TransactionContext.cpp
native/src/useTriedent.cpp
native/src/VerifyProver.cpp
native/src/Watchdog.cpp
)

add_subdirectory(native/tests)
add_subdirectory(common/tests)
endif()
endfunction()
Expand All @@ -205,6 +210,7 @@ endif()
if(IS_WASM)
install(DIRECTORY common/include/psibase TYPE INCLUDE COMPONENT libpsibase FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY tester/include/psibase TYPE INCLUDE COMPONENT libpsibase FILES_MATCHING PATTERN "*.hpp")
install(DIRECTORY wasm32-wasi TYPE INCLUDE COMPONENT libpsibase FILES_MATCHING PATTERN "*.h")
install(PROGRAMS sdk/psidk-cmake-args TYPE BIN COMPONENT libpsibase)
install(FILES sdk/psibase-config.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/psidk COMPONENT libpsibase)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libc++abi-replacements.a ${CMAKE_CURRENT_BINARY_DIR}/libc++abi-replacements-debug.a TYPE LIB COMPONENT libpsibase)
Expand Down
21 changes: 21 additions & 0 deletions libraries/psibase/common/include/psibase/nativeFunctions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,27 @@ namespace psibase
/// Otherwise returns `-1` and clears result. Use [getResult] to get result
/// and [getKey] to get found key.
PSIBASE_NATIVE(kvMax) uint32_t kvMax(DbId db, const char* key, uint32_t keyLen);

/// Gets the current value of a clock in nanoseconds.
///
/// This function is non-deterministic and is only available in subjective services.
///
/// The following clocks are supported
/// - `__WASI_CLOCKID_REALTIME` returns wall-clock time since the unix epoch.
/// - `__WASI_CLOCKID_MONOTONIC` returns monotonic time since an unspecified epoch.
/// All uses of CLOCK_MONOTONIC within the same block use the same epoch.
/// - `__WASI_CLOCKID_PROCESS_CPUTIME_ID` measures CPU time spent executing the
/// current transaction.
///
/// Returns 0 on success or an error code on failure.
///
/// Errors:
/// - `EINVAL`: the clock id is not supported
int32_t clockTimeGet(uint32_t id, uint64_t* time);

/// Sets the transaction timer to expire a given number of nanoseconds
/// after the beginning of the current transaction.
PSIBASE_NATIVE(setMaxTransactionTime) void setMaxTransactionTime(uint64_t ns);
} // namespace raw

/// Get result
Expand Down
3 changes: 2 additions & 1 deletion libraries/psibase/native/include/psibase/NativeFunctions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <psibase/ExecutionContext.hpp>

#include <eosio/vm/argument_proxy.hpp>
#include <eosio/vm/span.hpp>
#include <psibase/nativeTables.hpp>

Expand Down Expand Up @@ -37,7 +38,7 @@ namespace psibase
uint32_t getKey(eosio::vm::span<char> dest);
void writeConsole(eosio::vm::span<const char> str);
void abortMessage(eosio::vm::span<const char> str);
uint64_t getBillableTime();
int32_t clockTimeGet(uint32_t id, eosio::vm::argument_proxy<uint64_t*> time);
void setMaxTransactionTime(uint64_t nanoseconds);
uint32_t getCurrentAction();
uint32_t call(eosio::vm::span<const char> data);
Expand Down
9 changes: 6 additions & 3 deletions libraries/psibase/native/include/psibase/SystemContext.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@

namespace psibase
{
struct WatchdogManager;

struct SystemContext
{
SharedDatabase sharedDatabase;
WasmCache wasmCache;
std::vector<ExecutionMemory> executionMemories;
SharedDatabase sharedDatabase;
WasmCache wasmCache;
std::vector<ExecutionMemory> executionMemories;
std::shared_ptr<WatchdogManager> watchdogManager;

void setNumMemories(size_t n)
{
Expand Down
25 changes: 12 additions & 13 deletions libraries/psibase/native/include/psibase/TransactionContext.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,18 @@ namespace psibase
// Might be redundant elsewhere?
struct TransactionContext
{
BlockContext& blockContext;
const SignedTransaction& signedTransaction;
TransactionTrace& transactionTrace;
ConfigRow config;
KvResourceMap kvResourceDeltas;
std::uint32_t remainingStack = 0;
const std::chrono::steady_clock::time_point startTime;
std::chrono::steady_clock::duration databaseTime;
bool allowDbRead;
bool allowDbWrite;
bool allowDbReadSubjective;
std::vector<std::vector<char>> subjectiveData;
size_t nextSubjectiveRead = 0;
BlockContext& blockContext;
const SignedTransaction& signedTransaction;
TransactionTrace& transactionTrace;
ConfigRow config;
KvResourceMap kvResourceDeltas;
std::uint32_t remainingStack = 0;
std::chrono::steady_clock::duration databaseTime;
bool allowDbRead;
bool allowDbWrite;
bool allowDbReadSubjective;
std::vector<std::vector<char>> subjectiveData;
size_t nextSubjectiveRead = 0;

TransactionContext(BlockContext& blockContext,
const SignedTransaction& signedTransaction,
Expand Down
68 changes: 68 additions & 0 deletions libraries/psibase/native/include/psibase/Watchdog.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#pragma once

#include <chrono>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <thread>
#include <vector>

#include <time.h>

namespace psibase
{

struct CpuClock
{
using rep = std::int64_t;
using period = std::ratio<1, 1000000000>;
using duration = std::chrono::duration<rep, period>;
using time_point = std::chrono::time_point<CpuClock>;
static constexpr bool is_steady = false;
static time_point now(clockid_t clock = CLOCK_THREAD_CPUTIME_ID);
};

class Watchdog;

class WatchdogManager
{
public:
WatchdogManager();
~WatchdogManager();

private:
friend class Watchdog;
void add(Watchdog* wd);
void remove(Watchdog* wd);
void run();
std::mutex mutex;
std::condition_variable cond;
std::vector<Watchdog*> children;
bool done = false;
std::thread worker;
};

class Watchdog
{
public:
Watchdog(WatchdogManager& m, std::function<void()> f);
~Watchdog();
void setLimit(CpuClock::duration dur);
void pause();
void resume();
CpuClock::duration elapsed();
void interrupt();

private:
friend class WatchdogManager;
// Called with manager mutex held
CpuClock::duration wait_duration();
WatchdogManager* manager;
bool paused;
CpuClock::duration elapsedOrStart;
CpuClock::duration limit = CpuClock::duration::max();
clockid_t cpuclock;
std::function<void()> handler;
};

} // namespace psibase
10 changes: 4 additions & 6 deletions libraries/psibase/native/src/ExecutionContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,8 @@ namespace psibase
rhf_t::add<&ExecutionContextImpl::getKey>("env", "getKey");
rhf_t::add<&ExecutionContextImpl::writeConsole>("env", "writeConsole");
rhf_t::add<&ExecutionContextImpl::abortMessage>("env", "abortMessage");
// rhf_t::add<&ExecutionContextImpl::getBillableTime>("env", "getBillableTime");
// rhf_t::add<&ExecutionContextImpl::setMaxTransactionTime>("env", "setMaxTransactionTime");
rhf_t::add<&ExecutionContextImpl::clockTimeGet>("env", "clockTimeGet");
rhf_t::add<&ExecutionContextImpl::setMaxTransactionTime>("env", "setMaxTransactionTime");
rhf_t::add<&ExecutionContextImpl::getCurrentAction>("env", "getCurrentAction");
rhf_t::add<&ExecutionContextImpl::call>("env", "call");
rhf_t::add<&ExecutionContextImpl::setRetval>("env", "setRetval");
Expand Down Expand Up @@ -343,8 +343,7 @@ namespace psibase
auto& ctx = impl->transactionContext;
const auto& tx = ctx.signedTransaction;
check(ctx.nextSubjectiveRead < tx.subjectiveData->size(), "missing subjective data");
impl->currentActContext->actionTrace.rawRetval =
(*tx.subjectiveData)[ctx.nextSubjectiveRead++];
actionContext.actionTrace.rawRetval = (*tx.subjectiveData)[ctx.nextSubjectiveRead++];
return;
}

Expand All @@ -355,8 +354,7 @@ namespace psibase
});

if ((impl->code.flags & CodeRow::isSubjective) && !(callerFlags & CodeRow::isSubjective))
impl->transactionContext.subjectiveData.push_back(
impl->currentActContext->actionTrace.rawRetval);
impl->transactionContext.subjectiveData.push_back(actionContext.actionTrace.rawRetval);
}

void ExecutionContext::execVerify(ActionContext& actionContext)
Expand Down
Loading

0 comments on commit 0d9c79b

Please sign in to comment.