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

Log memory usage of the agent and the mapper #2693

Merged
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
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ c8y_http_proxy = { path = "crates/extensions/c8y_http_proxy" }
c8y_log_manager = { path = "crates/extensions/c8y_log_manager" }
c8y_mapper_ext = { path = "crates/extensions/c8y_mapper_ext" }
camino = "1.1"
cap = "0.1"
Copy link
Contributor

Choose a reason for hiding this comment

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

Side commentary: Came across this sysinfo crate that covers a lot more parameters like CPU usage. Something we can consider in the future, for advanced monitoring.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The purpose is different. Sysinfo observes the operating system, while here the point is to monitor the amount of memory actually allocated by tedge on the heap.

capture-logger = "0.1"
certificate = { path = "crates/common/certificate" }
clap = { version = "4.4", features = ["cargo", "derive"] }
Expand Down
6 changes: 6 additions & 0 deletions crates/common/tedge_config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,9 @@ pub fn get_new_tedge_config() -> Result<TEdgeConfig, TEdgeConfigError> {
let tedge_config_location = TEdgeConfigLocation::default();
TEdgeConfigRepository::new(tedge_config_location).load()
}

/// loads the tedge config from a config directory
pub fn load_tedge_config(config_dir: &Path) -> Result<TEdgeConfig, TEdgeConfigError> {
let tedge_config_location = TEdgeConfigLocation::from_custom_root(config_dir);
TEdgeConfigRepository::new(tedge_config_location).load()
}
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,10 @@ define_tedge_config! {
/// Whether to create a lock file or not
#[tedge_config(example = "true", default(value = true))]
lock_files: bool,

/// Interval at which the memory usage is logged (in seconds)
#[tedge_config(example = "60", default(value = 300_u64))]
log_memory_interval: Seconds,
},

logs: {
Expand Down
1 change: 1 addition & 0 deletions crates/core/tedge/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ base64 = { workspace = true }
c8y-firmware-plugin = { workspace = true }
c8y-remote-access-plugin = { workspace = true }
camino = { workspace = true }
cap = { workspace = true }
certificate = { workspace = true }
clap = { workspace = true, features = [
"cargo",
Expand Down
40 changes: 37 additions & 3 deletions crates/core/tedge/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,22 @@
#![deny(clippy::mem_forget)]

use anyhow::Context;
use cap::Cap;
use clap::Parser;
use std::alloc;
use std::future::Future;
use std::path::PathBuf;
use std::time::Duration;
use tedge::command::BuildCommand;
use tedge::command::BuildContext;
use tedge::Component;
use tedge::TEdgeOptMulticall;
use tedge_apt_plugin::AptCli;
use tedge_config::system_services::set_log_level;
use tracing::log;

#[global_allocator]
static ALLOCATOR: Cap<alloc::System> = Cap::new(alloc::System, usize::MAX);

fn main() -> anyhow::Result<()> {
let executable_name = executable_name();
Expand All @@ -22,10 +29,20 @@ fn main() -> anyhow::Result<()> {

let opt = parse_multicall_if_known(&executable_name);
match opt {
TEdgeOptMulticall::Component(Component::TedgeMapper(mapper_opt)) => {
block_on(tedge_mapper::run(mapper_opt))
TEdgeOptMulticall::Component(Component::TedgeMapper(opt)) => {
let tedge_config = tedge_config::load_tedge_config(&opt.config_dir)?;
block_on_with(
tedge_config.run.log_memory_interval.duration(),
tedge_mapper::run(opt),
)
Comment on lines +33 to +37
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not very happy with that, i.e. loading the config without passing it to tedge_mapper::run().

Doing so is not straightforward as each of the actors used by the mapper and the agent have specific way to load the config, with or without a reference to the config-dir and other weirdness including duplicated paths to the same setting. It would be good to simplify all that in a follow up PR.

}
TEdgeOptMulticall::Component(Component::TedgeAgent(opt)) => {
let tedge_config = tedge_config::load_tedge_config(&opt.config_dir)?;
block_on_with(
tedge_config.run.log_memory_interval.duration(),
tedge_agent::run(opt),
)
}
TEdgeOptMulticall::Component(Component::TedgeAgent(opt)) => block_on(tedge_agent::run(opt)),
TEdgeOptMulticall::Component(Component::C8yFirmwarePlugin(fp_opt)) => {
block_on(c8y_firmware_plugin::run(fp_opt))
}
Expand Down Expand Up @@ -63,6 +80,23 @@ fn block_on<T>(future: impl Future<Output = T>) -> T {
tokio::runtime::Runtime::new().unwrap().block_on(future)
}

fn block_on_with<T>(log_memory_interval: Duration, future: impl Future<Output = T>) -> T {
if log_memory_interval.is_zero() {
block_on(future)
} else {
block_on(async move {
tokio::spawn(async move {
loop {
log::info!("Allocated memory: {} Bytes", ALLOCATOR.allocated());
tokio::time::sleep(log_memory_interval).await;
}
});

future.await
})
}
}

fn executable_name() -> Option<String> {
Some(
PathBuf::from(std::env::args_os().next()?)
Expand Down
1 change: 1 addition & 0 deletions crates/core/tedge_agent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ axum = { workspace = true }
axum-server = { workspace = true }
axum_tls = { workspace = true }
camino = { workspace = true }
cap = { workspace = true }
clap = { workspace = true }
flockfile = { workspace = true }
futures = { workspace = true }
Expand Down
18 changes: 17 additions & 1 deletion crates/core/tedge_agent/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
use cap::Cap;
use clap::Parser;
use std::alloc;

#[global_allocator]
static ALLOCATOR: Cap<alloc::System> = Cap::new(alloc::System, usize::MAX);

#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {
async fn main() -> anyhow::Result<()> {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We have to consider deprecating this main and enforcing the use of a tedge -agent as a symlink to tedge.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here is a ticket for that: #2696

let agent_opt = tedge_agent::AgentOpt::parse();
let tedge_config = tedge_config::load_tedge_config(&agent_opt.config_dir)?;
let log_memory_interval = tedge_config.run.log_memory_interval.duration();
if !log_memory_interval.is_zero() {
tokio::spawn(async move {
loop {
log::info!("Allocated memory: {} Bytes", ALLOCATOR.allocated());
tokio::time::sleep(log_memory_interval).await;
}
});
}

tedge_agent::run(agent_opt).await
}
1 change: 1 addition & 0 deletions crates/core/tedge_mapper/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ c8y_api = { workspace = true }
c8y_auth_proxy = { workspace = true }
c8y_http_proxy = { workspace = true }
c8y_mapper_ext = { workspace = true }
cap = { workspace = true }
clap = { workspace = true }
clock = { workspace = true }
collectd_ext = { workspace = true }
Expand Down
6 changes: 4 additions & 2 deletions crates/core/tedge_mapper/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ use crate::core::component::TEdgeComponent;
use clap::Parser;
use flockfile::check_another_instance_is_not_running;
use std::fmt;
use std::path::PathBuf;
use tedge_config::system_services::get_log_level;
use tedge_config::system_services::set_log_level;
use tedge_config::PathBuf;
use tedge_config::DEFAULT_TEDGE_CONFIG_PATH;
use tracing::log::warn;

Expand Down Expand Up @@ -111,6 +111,8 @@ pub async fn run(mapper_opt: MapperOpt) -> anyhow::Result<()> {
warn!("This --clear option has been deprecated and will be removed in a future release");
Ok(())
} else {
component.start(config, &mapper_opt.config_dir).await
component
.start(config, mapper_opt.config_dir.as_ref())
.await
}
}
17 changes: 17 additions & 0 deletions crates/core/tedge_mapper/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
use cap::Cap;
use clap::Parser;
use std::alloc;
use tracing::log;

#[global_allocator]
static ALLOCATOR: Cap<alloc::System> = Cap::new(alloc::System, usize::MAX);

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let mapper_opt = tedge_mapper::MapperOpt::parse();
let tedge_config = tedge_config::load_tedge_config(&mapper_opt.config_dir)?;
let log_memory_interval = tedge_config.run.log_memory_interval.duration();
if !log_memory_interval.is_zero() {
tokio::spawn(async move {
loop {
log::info!("Allocated memory: {} Bytes", ALLOCATOR.allocated());
tokio::time::sleep(log_memory_interval).await;
}
});
}

tedge_mapper::run(mapper_opt).await
}