Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dce0d161ea | |||
| 853a62bc5b | |||
| 1927614803 | |||
| 75a5192c6d | |||
| 25ad0920cf | |||
| a4c6f51fe0 |
Generated
+34
@@ -4294,6 +4294,9 @@ dependencies = [
|
||||
"tap",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"tikv-jemalloc-ctl",
|
||||
"tikv-jemalloc-sys",
|
||||
"tikv-jemallocator",
|
||||
"time",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
@@ -9132,6 +9135,37 @@ dependencies = [
|
||||
"threadpool",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tikv-jemalloc-ctl"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f21f216790c8df74ce3ab25b534e0718da5a1916719771d3fec23315c99e468b"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"paste",
|
||||
"tikv-jemalloc-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tikv-jemalloc-sys"
|
||||
version = "0.6.0+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd3c60906412afa9c2b5b5a48ca6a5abe5736aec9eb48ad05037a677e52e4e2d"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tikv-jemallocator"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cec5ff18518d81584f477e9bfdf957f5bb0979b0bac3af4ca30b5b3ae2d2865"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"tikv-jemalloc-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.36"
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
panic = "abort"
|
||||
opt-level = "s"
|
||||
overflow-checks = true
|
||||
debug = true
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
@@ -39,7 +39,8 @@ impl<St: Storage + Clone + 'static> PeerHandle<St> {
|
||||
let timeout_check_interval = tokio_stream::wrappers::IntervalStream::new(
|
||||
tokio::time::interval(DEFAULT_PEER_TIMEOUT_CHECK),
|
||||
);
|
||||
let task_client = task_client.fork(format!("peer{public_key}"));
|
||||
let mut task_client = task_client.fork(format!("peer-{public_key}"));
|
||||
task_client.disarm();
|
||||
PeerHandle {
|
||||
storage,
|
||||
public_key,
|
||||
|
||||
@@ -73,6 +73,9 @@ pub(crate) enum InitialAuthenticationError {
|
||||
#[error("Only 'Register' or 'Authenticate' requests are allowed")]
|
||||
InvalidRequest,
|
||||
|
||||
#[error("received a Message of type {typ} which was not expected in this context")]
|
||||
UnexpectedMessageType { typ: String },
|
||||
|
||||
#[error("Experienced connection error: {0}")]
|
||||
ConnectionError(#[from] WsError),
|
||||
|
||||
@@ -861,9 +864,27 @@ where
|
||||
Message::Binary(_) => {
|
||||
return Err(InitialAuthenticationError::BinaryRequestWithoutAuthentication);
|
||||
}
|
||||
_ => unreachable!(
|
||||
"the underlying tunsgenite stream should be handling other message types"
|
||||
),
|
||||
other => {
|
||||
if other.is_ping() {
|
||||
debug!("unexpected ping message!");
|
||||
return Err(InitialAuthenticationError::UnexpectedMessageType {
|
||||
typ: "ping".to_string(),
|
||||
});
|
||||
} else if other.is_pong() {
|
||||
debug!("unexpected pong message!");
|
||||
return Err(InitialAuthenticationError::UnexpectedMessageType {
|
||||
typ: "pong".to_string(),
|
||||
});
|
||||
} else if other.is_close() {
|
||||
debug!("unexpected close message!");
|
||||
return Err(InitialAuthenticationError::UnexpectedMessageType {
|
||||
typ: "close".to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
// at this point this is definitely unreachable, but just in case, let's not panic...
|
||||
return Err(InitialAuthenticationError::InvalidRequest);
|
||||
}
|
||||
};
|
||||
|
||||
text.parse()
|
||||
|
||||
+7
-2
@@ -76,7 +76,7 @@ axum = { workspace = true, features = ["tokio"], optional = true }
|
||||
axum-extra = { workspace = true, features = ["typed-header"], optional = true }
|
||||
tower-http = { workspace = true, features = ["cors", "trace"], optional = true }
|
||||
utoipa = { workspace = true, features = ["axum_extras", "time"], optional = true }
|
||||
utoipa-swagger-ui = { workspace = true, features = ["axum"], optional = true}
|
||||
utoipa-swagger-ui = { workspace = true, features = ["axum"], optional = true }
|
||||
utoipauto = { workspace = true, optional = true }
|
||||
tracing-subscriber = { workspace = true, features = ["env-filter"], optional = true }
|
||||
tracing = { workspace = true, optional = true }
|
||||
@@ -112,7 +112,7 @@ cw4 = { workspace = true }
|
||||
nym-dkg = { path = "../common/dkg", features = ["cw-types"] }
|
||||
nym-gateway-client = { path = "../common/client-libs/gateway-client" }
|
||||
nym-inclusion-probability = { path = "../common/inclusion-probability" }
|
||||
nym-mixnet-contract-common = { path = "../common/cosmwasm-smart-contracts/mixnet-contract", features = ["utoipa"]}
|
||||
nym-mixnet-contract-common = { path = "../common/cosmwasm-smart-contracts/mixnet-contract", features = ["utoipa"] }
|
||||
nym-vesting-contract-common = { path = "../common/cosmwasm-smart-contracts/vesting-contract" }
|
||||
nym-contracts-common = { path = "../common/cosmwasm-smart-contracts/contracts-common" }
|
||||
nym-multisig-contract-common = { path = "../common/cosmwasm-smart-contracts/multisig-contract" }
|
||||
@@ -129,6 +129,10 @@ nym-node-requests = { path = "../nym-node/nym-node-requests" }
|
||||
nym-types = { path = "../common/types" }
|
||||
nym-http-api-common = { path = "../common/http-api-common", features = ["utoipa"] }
|
||||
|
||||
tikv-jemallocator = { version = "0.6", optional = true, features = ["profiling"] }
|
||||
tikv-jemalloc-sys = { version = "0.6", optional = true, features = ["stats", "profiling", "unprefixed_malloc_on_supported_platforms"] }
|
||||
tikv-jemalloc-ctl = { version = "0.6", optional = true, features = ["use_std", "stats", "profiling"] }
|
||||
|
||||
[features]
|
||||
no-reward = []
|
||||
generate-ts = ["ts-rs"]
|
||||
@@ -143,6 +147,7 @@ axum = ["dep:axum",
|
||||
"nym-http-api-common/utoipa",
|
||||
"nym-mixnet-contract-common/utoipa"
|
||||
]
|
||||
memory-prof = ["tikv-jemallocator", "tikv-jemalloc-ctl", "tikv-jemalloc-sys"]
|
||||
|
||||
[build-dependencies]
|
||||
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
|
||||
|
||||
+13
-2
@@ -24,7 +24,7 @@ use circulating_supply_api::cache::CirculatingSupplyCache;
|
||||
use clap::Parser;
|
||||
use ecash::dkg::controller::DkgController;
|
||||
use node_status_api::NodeStatusCache;
|
||||
use nym_bin_common::logging::setup_logging;
|
||||
use nym_bin_common::logging::{setup_logging, setup_tracing_logger};
|
||||
use nym_config::defaults::NymNetworkDetails;
|
||||
use nym_contract_cache::cache::NymContractCache;
|
||||
use nym_sphinx::receiver::SphinxMessageReceiver;
|
||||
@@ -44,6 +44,10 @@ pub(crate) mod nym_nodes;
|
||||
mod status;
|
||||
pub(crate) mod support;
|
||||
|
||||
#[cfg(feature = "memory-prof")]
|
||||
#[global_allocator]
|
||||
static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
|
||||
|
||||
#[cfg(feature = "axum")]
|
||||
mod v2;
|
||||
|
||||
@@ -58,9 +62,16 @@ async fn main() -> Result<(), anyhow::Error> {
|
||||
cfg_if::cfg_if! {if #[cfg(feature = "console-subscriber")] {
|
||||
// instrument tokio console subscriber needs RUSTFLAGS="--cfg tokio_unstable" at build time
|
||||
console_subscriber::init();
|
||||
} else {
|
||||
setup_tracing_logger();
|
||||
}}
|
||||
|
||||
setup_logging();
|
||||
// setup_tracing_logger();
|
||||
|
||||
|
||||
// std::env::set_var("MALLOC_CONF", "prof:true,lg_prof_interval:28");
|
||||
|
||||
// setup_tracing_logger();
|
||||
// TODO rocket: replace with tracing logger once rocket is eliminated from code
|
||||
|
||||
info!("Starting nym api...");
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::node_status_api::models::RocketErrorResponse;
|
||||
use okapi::openapi3::{OpenApi, Responses};
|
||||
use rocket::http::Status;
|
||||
use rocket::response::Responder;
|
||||
use rocket::{response, Request, Route};
|
||||
use rocket_okapi::gen::OpenApiGenerator;
|
||||
use rocket_okapi::response::OpenApiResponderInner;
|
||||
use rocket_okapi::settings::OpenApiSettings;
|
||||
use rocket_okapi::util::ensure_status_code_exists;
|
||||
use rocket_okapi::{openapi, openapi_get_routes_spec};
|
||||
|
||||
// code taken from https://github.dev/GreptimeTeam/greptimedb/blob/develop/src/cmd/src/bin/greptime.rs
|
||||
|
||||
#[cfg(feature = "memory-prof")]
|
||||
pub mod memory_prof {
|
||||
const PROF_DUMP: &[u8] = b"prof.dump\0";
|
||||
// const OPT_PROF: &[u8] = b"opt.prof\0";
|
||||
|
||||
use anyhow::{bail, Context};
|
||||
use nym_config::{must_get_home, DEFAULT_NYM_APIS_DIR, NYM_DIR};
|
||||
use std::ffi::{c_char, CString};
|
||||
use time::OffsetDateTime;
|
||||
use tokio::fs::create_dir_all;
|
||||
use tokio::io::AsyncReadExt;
|
||||
|
||||
pub async fn dump_profile() -> anyhow::Result<Vec<u8>> {
|
||||
if !is_prof_enabled()? {
|
||||
bail!("memory profiling is not enabled")
|
||||
}
|
||||
|
||||
let now = OffsetDateTime::now_utc();
|
||||
let dump_path = must_get_home()
|
||||
.join(NYM_DIR)
|
||||
.join(DEFAULT_NYM_APIS_DIR)
|
||||
.join("memory_dumps")
|
||||
.join(format!("{}", now.unix_timestamp()))
|
||||
.join("nym-api.hprof");
|
||||
|
||||
let parent = dump_path.parent().unwrap();
|
||||
create_dir_all(&parent).await?;
|
||||
|
||||
info!("using {} for the memory dump", dump_path.display());
|
||||
|
||||
let path = dump_path
|
||||
.to_str()
|
||||
.context("the temp dir contained invalid characters")?
|
||||
.to_string();
|
||||
|
||||
let mut bytes = CString::new(path.as_str())
|
||||
.context("could not construct a CString out of the path")?
|
||||
.into_bytes_with_nul();
|
||||
|
||||
{
|
||||
// #safety: we always expect a valid temp file path to write profiling data to.
|
||||
let ptr = bytes.as_mut_ptr() as *mut c_char;
|
||||
unsafe {
|
||||
tikv_jemalloc_ctl::raw::write(PROF_DUMP, ptr).context(format!(
|
||||
"failed to dump profiling data to {}",
|
||||
dump_path.display()
|
||||
))?
|
||||
}
|
||||
}
|
||||
|
||||
let mut f = tokio::fs::File::open(path.as_str())
|
||||
.await
|
||||
.context("failed to open the dump file")?;
|
||||
let mut buf = vec![];
|
||||
let _ = f
|
||||
.read_to_end(&mut buf)
|
||||
.await
|
||||
.context("failed to read the dump file")?;
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
fn is_prof_enabled() -> anyhow::Result<bool> {
|
||||
Ok(tikv_jemalloc_ctl::profiling::prof::read()?)
|
||||
// Ok(unsafe {
|
||||
// tikv_jemalloc_ctl::raw::read::<bool>(OPT_PROF)
|
||||
// .context("failed to check the OPT_PROF")?
|
||||
// })
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BinaryResponse {
|
||||
inner: Vec<u8>,
|
||||
}
|
||||
|
||||
impl<'r, 'o: 'r> Responder<'r, 'o> for BinaryResponse {
|
||||
fn respond_to(self, _req: &'r Request<'_>) -> response::Result<'o> {
|
||||
let mut res = rocket::Response::new();
|
||||
res.set_sized_body(self.inner.len(), std::io::Cursor::new(self.inner));
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl OpenApiResponderInner for BinaryResponse {
|
||||
fn responses(_gen: &mut OpenApiGenerator) -> rocket_okapi::Result<Responses> {
|
||||
let mut responses = Responses::default();
|
||||
ensure_status_code_exists(&mut responses, 200);
|
||||
Ok(responses)
|
||||
}
|
||||
}
|
||||
|
||||
/// foomp
|
||||
#[cfg(feature = "memory-prof")]
|
||||
#[openapi(tag = "profiling")]
|
||||
#[get("/mem")]
|
||||
pub async fn mem_prof_handler() -> Result<BinaryResponse, RocketErrorResponse> {
|
||||
let dump_data = memory_prof::dump_profile()
|
||||
.await
|
||||
.map_err(|err| RocketErrorResponse::new(err.to_string(), Status::InternalServerError))?;
|
||||
|
||||
Ok(BinaryResponse { inner: dump_data })
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "memory-prof"))]
|
||||
#[openapi(tag = "profiling")]
|
||||
#[get("/mem")]
|
||||
pub async fn mem_prof_handler() -> RocketErrorResponse {
|
||||
RocketErrorResponse::new("The 'mem-prof' feature is disabled", Status::NotImplemented)
|
||||
}
|
||||
|
||||
pub(crate) fn api_status_routes(settings: &OpenApiSettings) -> (Vec<Route>, OpenApi) {
|
||||
openapi_get_routes_spec![
|
||||
settings:
|
||||
mem_prof_handler
|
||||
]
|
||||
}
|
||||
@@ -28,6 +28,8 @@ use rocket_okapi::swagger_ui::make_swagger_ui;
|
||||
pub(crate) mod helpers;
|
||||
pub(crate) mod openapi;
|
||||
|
||||
pub(crate) mod mem_prof;
|
||||
|
||||
pub(crate) async fn setup_rocket(
|
||||
config: &Config,
|
||||
network_details: NetworkDetails,
|
||||
@@ -52,6 +54,7 @@ pub(crate) async fn setup_rocket(
|
||||
"/api-status" => api_status_routes(&openapi_settings),
|
||||
"/ecash" => ecash::routes_open_api(&openapi_settings, config.coconut_signer.enabled),
|
||||
"" => nym_node_routes_deprecated(&openapi_settings),
|
||||
"/prof" => mem_prof::api_status_routes(&openapi_settings),
|
||||
|
||||
// => when we move those routes, we'll need to add a redirection for backwards compatibility
|
||||
"/unstable/nym-nodes" => nym_node_routes_next(&openapi_settings)
|
||||
|
||||
Reference in New Issue
Block a user