Skip to content

Commit

Permalink
refactor: share the same TLS string across the C API to save memory
Browse files Browse the repository at this point in the history
  • Loading branch information
edubart committed Oct 8, 2024
1 parent c6a52ed commit e66a9fa
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 50 deletions.
16 changes: 4 additions & 12 deletions src/jsonrpc-machine-c-api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,7 @@ cm_error cm_jsonrpc_get_default_config(const cm_jsonrpc_mgr *mgr, const char **c
}
const auto *cpp_mgr = convert_from_c(mgr);
const cartesi::machine_config cpp_config = cartesi::jsonrpc_virtual_machine::get_default_config(*cpp_mgr);
static THREAD_LOCAL std::string config_storage;
config_storage = cartesi::to_json(cpp_config).dump();
*config = config_storage.c_str();
*config = cm_set_temp_string(cartesi::to_json(cpp_config).dump());
return cm_result_success();
} catch (...) {
if (config) {
Expand Down Expand Up @@ -169,9 +167,7 @@ cm_error cm_jsonrpc_fork(const cm_jsonrpc_mgr *mgr, const char **address, int32_
}
const auto *cpp_mgr = convert_from_c(mgr);
const auto result = cartesi::jsonrpc_virtual_machine::fork(*cpp_mgr);
static THREAD_LOCAL std::string address_storage;
address_storage = result.address;
*address = address_storage.c_str();
*address = cm_set_temp_string(result.address);
if (pid) {
*pid = static_cast<int>(result.pid);
}
Expand All @@ -190,9 +186,7 @@ cm_error cm_jsonrpc_rebind(const cm_jsonrpc_mgr *mgr, const char *address, const
const auto *cpp_mgr = convert_from_c(mgr);
const std::string cpp_new_address = cartesi::jsonrpc_virtual_machine::rebind(*cpp_mgr, address);
if (new_address) {
static THREAD_LOCAL std::string new_address_storage;
new_address_storage = cpp_new_address;
*new_address = new_address_storage.c_str();
*new_address = cm_set_temp_string(cpp_new_address);
}
return cm_result_success();
} catch (...) {
Expand Down Expand Up @@ -223,9 +217,7 @@ cm_error cm_jsonrpc_get_version(const cm_jsonrpc_mgr *mgr, const char **version)
}
const auto *cpp_mgr = convert_from_c(mgr);
const cartesi::semantic_version cpp_version = cartesi::jsonrpc_virtual_machine::get_version(*cpp_mgr);
static THREAD_LOCAL std::string version_storage;
version_storage = cartesi::to_json(cpp_version).dump();
*version = version_storage.c_str();
*version = cm_set_temp_string(cartesi::to_json(cpp_version).dump());
return cm_result_success();
} catch (...) {
if (version) {
Expand Down
8 changes: 4 additions & 4 deletions src/jsonrpc-machine-c-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ CM_API void cm_jsonrpc_destroy_mgr(const cm_jsonrpc_mgr *mgr);
/// \brief Forks the remote server.
/// \param mgr Pointer to a valid JSONRPC connection manager.
/// \param address Receives address of new server if function execution succeeds or NULL otherwise,
/// remains valid until the next time this same function is called on the same thread.
/// guaranteed to remain valid only until the next C API is called from the same thread.
/// \param pid Receives the forked child process id if function execution succeeds or 0 otherwise.
/// \returns 0 for success, non zero code for error.
CM_API cm_error cm_jsonrpc_fork(const cm_jsonrpc_mgr *mgr, const char **address, int32_t *pid);
Expand All @@ -54,7 +54,7 @@ CM_API cm_error cm_jsonrpc_fork(const cm_jsonrpc_mgr *mgr, const char **address,
/// \param mgr Pointer to a valid JSONRPC connection manager.
/// \param address New address that the remote server should bind to.
/// \param new_address Receives the new address that the remote server actually bound to,
/// remains valid until the next time this same function is called on the same thread.
/// guaranteed to remain valid only until the next C API is called from the same thread.
/// \returns 0 for success, non zero code for error.
CM_API cm_error cm_jsonrpc_rebind(const cm_jsonrpc_mgr *mgr, const char *address, const char **new_address);

Expand All @@ -66,14 +66,14 @@ CM_API cm_error cm_jsonrpc_shutdown(const cm_jsonrpc_mgr *mgr);
/// \brief Gets the semantic version of the remote server.
/// \param mgr Pointer to a valid JSONRPC connection manager.
/// \param semantic_version Receives the semantic version as a JSON string,
/// remains valid until the next time this same function is called on the same thread.
/// guaranteed to remain valid only until the next C API is called from the same thread.
/// \returns 0 for success, non zero code for error.
CM_API cm_error cm_jsonrpc_get_version(const cm_jsonrpc_mgr *mgr, const char **version);

/// \brief Gets a JSON string for the default machine config from the remote server.
/// \param mgr Pointer to a valid JSONRPC connection manager.
/// \param config Receives the default configuration,
/// remains valid until the next time this same function is called on the same thread.
/// guaranteed to remain valid only until the next C API is called from the same thread.
/// \returns 0 for success, non zero code for error.
CM_API cm_error cm_jsonrpc_get_default_config(const cm_jsonrpc_mgr *mgr, const char **config);

Expand Down
3 changes: 3 additions & 0 deletions src/machine-c-api-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,7 @@ cm_error cm_result_success();
/// \brief Helper function that parses hash from C api structure
cartesi::machine_merkle_tree::hash_type convert_from_c(const cm_hash *c_hash);

/// \brief Helper function that stores a string to a temporary thread local.
const char *cm_set_temp_string(const std::string &s);

#endif // CM_C_API_INTERNAL_H
34 changes: 13 additions & 21 deletions src/machine-c-api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ const char *cm_get_last_error_message() {
return last_err_msg.c_str();
}

const char *cm_set_temp_string(const std::string &s) {
static THREAD_LOCAL std::string temp_string;
temp_string = s;
return temp_string.c_str();
}

cm_error cm_result_failure() try { throw; } catch (std::exception &e) {
try {
last_err_msg = e.what();
Expand Down Expand Up @@ -245,9 +251,7 @@ cm_error cm_log_reset_uarch(cm_machine *m, int32_t log_type, const char **log) t
auto *cpp_machine = convert_from_c(m);
cartesi::access_log::type cpp_log_type(log_type);
cartesi::access_log cpp_log = cpp_machine->log_reset_uarch(cpp_log_type);
static THREAD_LOCAL std::string access_log_storage;
access_log_storage = cartesi::to_json(cpp_log).dump();
*log = access_log_storage.c_str();
*log = cm_set_temp_string(cartesi::to_json(cpp_log).dump());
return cm_result_success();
} catch (...) {
if (log) {
Expand Down Expand Up @@ -277,9 +281,7 @@ cm_error cm_log_step_uarch(cm_machine *m, int32_t log_type, const char **log) tr
auto *cpp_machine = convert_from_c(m);
cartesi::access_log::type cpp_log_type(log_type);
cartesi::access_log cpp_log = cpp_machine->log_step_uarch(cpp_log_type);
static THREAD_LOCAL std::string access_log_storage;
access_log_storage = cartesi::to_json(cpp_log).dump();
*log = access_log_storage.c_str();
*log = cm_set_temp_string(cartesi::to_json(cpp_log).dump());
return cm_result_success();
} catch (...) {
if (log) {
Expand Down Expand Up @@ -322,9 +324,7 @@ cm_error cm_get_proof(const cm_machine *m, uint64_t address, int32_t log2_size,
}
const auto *cpp_machine = convert_from_c(m);
const cartesi::machine_merkle_tree::proof_type cpp_proof = cpp_machine->get_proof(address, log2_size);
static THREAD_LOCAL std::string proof_storage;
proof_storage = cartesi::to_json(cpp_proof).dump();
*proof = proof_storage.c_str();
*proof = cm_set_temp_string(cartesi::to_json(cpp_proof).dump());
return cm_result_success();
} catch (...) {
if (proof) {
Expand Down Expand Up @@ -561,9 +561,7 @@ cm_error cm_get_initial_config(const cm_machine *m, const char **config) try {
}
const auto *cpp_machine = convert_from_c(m);
const cartesi::machine_config cpp_config = cpp_machine->get_initial_config();
static THREAD_LOCAL std::string config_storage;
config_storage = cartesi::to_json(cpp_config).dump();
*config = config_storage.c_str();
*config = cm_set_temp_string(cartesi::to_json(cpp_config).dump());
return cm_result_success();
} catch (...) {
if (config) {
Expand All @@ -577,9 +575,7 @@ cm_error cm_get_default_config(const char **config) try {
throw std::invalid_argument("invalid config output");
}
const cartesi::machine_config cpp_config = cartesi::machine::get_default_config();
static THREAD_LOCAL std::string config_storage;
config_storage = cartesi::to_json(cpp_config).dump();
*config = config_storage.c_str();
*config = cm_set_temp_string(cartesi::to_json(cpp_config).dump());
return cm_result_success();
} catch (...) {
if (config) {
Expand Down Expand Up @@ -645,9 +641,7 @@ cm_error cm_get_memory_ranges(const cm_machine *m, const char **ranges) try {
}
const auto *cpp_machine = convert_from_c(m);
const cartesi::machine_memory_range_descrs cpp_ranges = cpp_machine->get_memory_ranges();
static THREAD_LOCAL std::string ranges_storage;
ranges_storage = cartesi::to_json(cpp_ranges).dump();
*ranges = ranges_storage.c_str();
*ranges = cm_set_temp_string(cartesi::to_json(cpp_ranges).dump());
return cm_result_success();
} catch (...) {
if (ranges) {
Expand Down Expand Up @@ -731,9 +725,7 @@ cm_error cm_log_send_cmio_response(cm_machine *m, uint16_t reason, const uint8_t
auto *cpp_machine = convert_from_c(m);
cartesi::access_log::type cpp_log_type(log_type);
cartesi::access_log cpp_log = cpp_machine->log_send_cmio_response(reason, data, length, cpp_log_type);
static THREAD_LOCAL std::string access_log_storage;
access_log_storage = cartesi::to_json(cpp_log).dump();
*log = access_log_storage.c_str();
*log = cm_set_temp_string(cartesi::to_json(cpp_log).dump());
return cm_result_success();
} catch (...) {
if (log) {
Expand Down
22 changes: 9 additions & 13 deletions src/machine-c-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,7 @@ CM_API const char *cm_get_last_error_message();

/// \brief Obtains a JSON object with the default machine config as a string.
/// \param config Receives the default configuration as a JSON object in a string,
/// guaranteed to remain valid only until the the next time this same function
/// is called again on the same thread.
/// guaranteed to remain valid only until the next C API is called from the same thread.
/// \returns 0 for success, non zero code for error.
/// \details The returned config is not sufficient to run a machine.
/// Additional configurations, such as RAM length, RAM image, flash drives,
Expand Down Expand Up @@ -381,17 +380,15 @@ CM_API cm_error cm_replace_memory_range(cm_machine *m, uint64_t start, uint64_t

/// \brief Obtains a JSON object with the machine config used to initialize the machine.
/// \param m Pointer to a valid machine instance.
/// \param config Receives the initial configuration as a JSON object in a
/// string, guaranteed to remain valid only until the the next time this same function
/// is called again on the same thread.
/// \param config Receives the initial configuration as a JSON object in a string,
/// guaranteed to remain valid only until the next C API is called from the same thread.
/// \returns 0 for success, non zero code for error.
CM_API cm_error cm_get_initial_config(const cm_machine *m, const char **config);

/// \brief Obtains a list with all memory ranges in the machine.
/// \param m Pointer to a valid machine instance.
/// \param ranges Receives the memory ranges as a JSON object in a string,
/// guaranteed to remain valid only until the the next time this same function is
/// called again on the same thread.
/// guaranteed to remain valid only until the next C API is called from the same thread.
/// \returns 0 for success, non zero code for error.
CM_API cm_error cm_get_memory_ranges(const cm_machine *m, const char **ranges);

Expand All @@ -407,9 +404,8 @@ CM_API cm_error cm_get_root_hash(const cm_machine *m, cm_hash *hash);
/// \param log2_size The log base 2 of the size subtended by target node.
/// Must be between CM_TREE_LOG2_WORD_SIZE (for a word) and CM_TREE_LOG2_ROOT_SIZE
/// (for the entire address space), inclusive.
/// \param proof Receives the proof as a JSON object in a string, guaranteed to
/// remain valid only until the the next time this same function is called again on
/// the same thread.
/// \param proof Receives the proof as a JSON object in a string,
/// guaranteed to remain valid only until the next C API is called from the same thread.
/// \returns 0 for success, non zero code for error.
CM_API cm_error cm_get_proof(const cm_machine *m, uint64_t address, int32_t log2_size, const char **proof);

Expand Down Expand Up @@ -616,15 +612,15 @@ CM_API cm_error cm_send_cmio_response(cm_machine *m, uint16_t reason, const uint
/// \param m Pointer to valid machine instance.
/// \param log_type Type of access log to generate.
/// \param log Receives the state access log as a JSON object in a string,
/// remains valid until the next time this same function is called on the same thread.
/// guaranteed to remain valid only until the next C API is called from the same thread.
/// \returns 0 for success, non zero code for error.
CM_API cm_error cm_log_step_uarch(cm_machine *m, int32_t log_type, const char **log);

/// \brief Resets the entire microarchitecture state to pristine values logging all accesses to the state.
/// \param m Pointer to valid machine instance.
/// \param log_type Type of access log to generate.
/// \param log Receives the state access log as a JSON object in a string,
/// remains valid until the next time this same function is called on the same thread.
/// guaranteed to remain valid only until the next C API is called from the same thread.
/// \returns 0 for success, non zero code for error.
CM_API cm_error cm_log_reset_uarch(cm_machine *m, int32_t log_type, const char **log);

Expand All @@ -635,7 +631,7 @@ CM_API cm_error cm_log_reset_uarch(cm_machine *m, int32_t log_type, const char *
/// \param length Length of response data.
/// \param log_type Type of access log to generate.
/// \param log Receives the state access log as a JSON object in a string,
/// remains valid until the next time this same function is called on the same thread.
/// guaranteed to remain valid only until the next C API is called from the same thread.
/// \returns 0 for success, non zero code for error.
CM_API cm_error cm_log_send_cmio_response(cm_machine *m, uint16_t reason, const uint8_t *data, uint64_t length,
int32_t log_type, const char **log);
Expand Down

0 comments on commit e66a9fa

Please sign in to comment.