Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CPU billing #454

Merged
merged 7 commits into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should define or link to something that defines "subjective services"

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't find any existing documentation for subjective services and it certainly doesn't belong here. Maybe under services/concepts?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps just in services itself

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be deferred to another PR. Documentation of subjective services is only incidentally related and this PR is already quite large.


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 @@ -292,8 +292,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 @@ -333,8 +333,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 @@ -345,8 +344,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
Loading