mirror of
https://github.com/neondatabase/neon.git
synced 2026-02-07 20:50:38 +00:00
Compare commits
4 Commits
release-pr
...
jemalloc-p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d2709f4a1 | ||
|
|
6e2c04bc48 | ||
|
|
76ae735a24 | ||
|
|
7be445f627 |
@@ -252,7 +252,7 @@ debug = true
|
|||||||
|
|
||||||
# disable debug symbols for all packages except this one to decrease binaries size
|
# disable debug symbols for all packages except this one to decrease binaries size
|
||||||
[profile.release.package."*"]
|
[profile.release.package."*"]
|
||||||
debug = false
|
debug = true
|
||||||
|
|
||||||
[profile.release-line-debug]
|
[profile.release-line-debug]
|
||||||
inherits = "release"
|
inherits = "release"
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ COPY --from=pg-build /home/nonroot/pg_install/v15/include/postgresql/server pg_i
|
|||||||
COPY --from=pg-build /home/nonroot/pg_install/v16/include/postgresql/server pg_install/v16/include/postgresql/server
|
COPY --from=pg-build /home/nonroot/pg_install/v16/include/postgresql/server pg_install/v16/include/postgresql/server
|
||||||
COPY --chown=nonroot . .
|
COPY --chown=nonroot . .
|
||||||
|
|
||||||
|
ENV _RJEM_MALLOC_CONF="prof:true"
|
||||||
# Show build caching stats to check if it was used in the end.
|
# Show build caching stats to check if it was used in the end.
|
||||||
# Has to be the part of the same RUN since cachepot daemon is killed in the end of this RUN, losing the compilation stats.
|
# Has to be the part of the same RUN since cachepot daemon is killed in the end of this RUN, losing the compilation stats.
|
||||||
RUN set -e \
|
RUN set -e \
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ base64.workspace = true
|
|||||||
bstr.workspace = true
|
bstr.workspace = true
|
||||||
bytes = { workspace = true, features = ["serde"] }
|
bytes = { workspace = true, features = ["serde"] }
|
||||||
camino.workspace = true
|
camino.workspace = true
|
||||||
|
camino-tempfile.workspace = true
|
||||||
chrono.workspace = true
|
chrono.workspace = true
|
||||||
clap.workspace = true
|
clap.workspace = true
|
||||||
consumption_metrics.workspace = true
|
consumption_metrics.workspace = true
|
||||||
@@ -78,7 +79,7 @@ subtle.workspace = true
|
|||||||
sync_wrapper.workspace = true
|
sync_wrapper.workspace = true
|
||||||
task-local-extensions.workspace = true
|
task-local-extensions.workspace = true
|
||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
tikv-jemallocator.workspace = true
|
tikv-jemallocator = { workspace = true, features = ["profiling"] }
|
||||||
tikv-jemalloc-ctl = { workspace = true, features = ["use_std"] }
|
tikv-jemalloc-ctl = { workspace = true, features = ["use_std"] }
|
||||||
tokio-postgres.workspace = true
|
tokio-postgres.workspace = true
|
||||||
tokio-rustls.workspace = true
|
tokio-rustls.workspace = true
|
||||||
@@ -102,7 +103,6 @@ redis.workspace = true
|
|||||||
workspace_hack.workspace = true
|
workspace_hack.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
camino-tempfile.workspace = true
|
|
||||||
fallible-iterator.workspace = true
|
fallible-iterator.workspace = true
|
||||||
rcgen.workspace = true
|
rcgen.workspace = true
|
||||||
rstest.workspace = true
|
rstest.workspace = true
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
use anyhow::{anyhow, bail};
|
use anyhow::{anyhow, bail};
|
||||||
|
use camino::Utf8PathBuf;
|
||||||
|
use camino_tempfile::Utf8TempDir;
|
||||||
use hyper::{header::CONTENT_TYPE, Body, Request, Response, StatusCode};
|
use hyper::{header::CONTENT_TYPE, Body, Request, Response, StatusCode};
|
||||||
use measured::{text::BufferedTextEncoder, MetricGroup};
|
use measured::{text::BufferedTextEncoder, MetricGroup};
|
||||||
use metrics::NeonMetrics;
|
use metrics::NeonMetrics;
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
use std::{
|
use std::{
|
||||||
convert::Infallible,
|
convert::Infallible,
|
||||||
|
ffi::CString,
|
||||||
net::TcpListener,
|
net::TcpListener,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
use tracing::{info, info_span};
|
use tracing::{info, info_span, warn};
|
||||||
use utils::http::{
|
use utils::http::{
|
||||||
endpoint::{self, request_span},
|
endpoint::{self, request_span},
|
||||||
error::ApiError,
|
error::ApiError,
|
||||||
@@ -21,18 +25,49 @@ async fn status_handler(_: Request<Body>) -> Result<Response<Body>, ApiError> {
|
|||||||
json_response(StatusCode::OK, "")
|
json_response(StatusCode::OK, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn prof_dump(_: Request<Body>) -> Result<Response<Body>, ApiError> {
|
||||||
|
static PROF_MIB: Lazy<jemalloc::dump_mib> =
|
||||||
|
Lazy::new(|| jemalloc::dump::mib().expect("could not create prof.dump MIB"));
|
||||||
|
static PROF_DIR: Lazy<Utf8TempDir> =
|
||||||
|
Lazy::new(|| camino_tempfile::tempdir().expect("could not create tempdir"));
|
||||||
|
static PROF_FILE: Lazy<Utf8PathBuf> = Lazy::new(|| PROF_DIR.path().join("prof.dump"));
|
||||||
|
static PROF_FILE0: Lazy<CString> = Lazy::new(|| CString::new(PROF_FILE.as_str()).unwrap());
|
||||||
|
static DUMP_LOCK: Mutex<()> = Mutex::new(());
|
||||||
|
|
||||||
|
tokio::task::spawn_blocking(|| {
|
||||||
|
let _guard = DUMP_LOCK.lock();
|
||||||
|
PROF_MIB
|
||||||
|
.write(&PROF_FILE0)
|
||||||
|
.expect("could not trigger prof.dump");
|
||||||
|
let prof_dump = std::fs::read_to_string(&*PROF_FILE).expect("could not open prof.dump");
|
||||||
|
|
||||||
|
Response::new(Body::from(prof_dump))
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.map_err(|e| ApiError::InternalServerError(e.into()))
|
||||||
|
}
|
||||||
|
|
||||||
fn make_router(metrics: AppMetrics) -> RouterBuilder<hyper::Body, ApiError> {
|
fn make_router(metrics: AppMetrics) -> RouterBuilder<hyper::Body, ApiError> {
|
||||||
let state = Arc::new(Mutex::new(PrometheusHandler {
|
let state = Arc::new(Mutex::new(PrometheusHandler {
|
||||||
encoder: BufferedTextEncoder::new(),
|
encoder: BufferedTextEncoder::new(),
|
||||||
metrics,
|
metrics,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
endpoint::make_router()
|
let mut router = endpoint::make_router()
|
||||||
.get("/metrics", move |r| {
|
.get("/metrics", move |r| {
|
||||||
let state = state.clone();
|
let state = state.clone();
|
||||||
request_span(r, move |b| prometheus_metrics_handler(b, state))
|
request_span(r, move |b| prometheus_metrics_handler(b, state))
|
||||||
})
|
})
|
||||||
.get("/v1/status", status_handler)
|
.get("/v1/status", status_handler);
|
||||||
|
|
||||||
|
let prof_enabled = jemalloc::prof::read().unwrap_or_default();
|
||||||
|
if prof_enabled {
|
||||||
|
warn!("activating jemalloc profiling");
|
||||||
|
jemalloc::active::write(true).unwrap();
|
||||||
|
router = router.get("/v1/jemalloc/prof.dump", prof_dump);
|
||||||
|
}
|
||||||
|
|
||||||
|
router
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn task_main(
|
pub async fn task_main(
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::marker::PhantomData;
|
use std::{ffi::CStr, marker::PhantomData};
|
||||||
|
|
||||||
use measured::{
|
use measured::{
|
||||||
label::NoLabels,
|
label::NoLabels,
|
||||||
@@ -9,7 +9,9 @@ use measured::{
|
|||||||
text::TextEncoder,
|
text::TextEncoder,
|
||||||
LabelGroup, MetricGroup,
|
LabelGroup, MetricGroup,
|
||||||
};
|
};
|
||||||
use tikv_jemalloc_ctl::{config, epoch, epoch_mib, stats, version};
|
use tikv_jemalloc_ctl::{
|
||||||
|
config, epoch, epoch_mib, raw, stats, version, Access, AsName, MibStr, Name,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct MetricRecorder {
|
pub struct MetricRecorder {
|
||||||
epoch: epoch_mib,
|
epoch: epoch_mib,
|
||||||
@@ -114,3 +116,59 @@ jemalloc_gauge!(mapped, mapped_mib);
|
|||||||
jemalloc_gauge!(metadata, metadata_mib);
|
jemalloc_gauge!(metadata, metadata_mib);
|
||||||
jemalloc_gauge!(resident, resident_mib);
|
jemalloc_gauge!(resident, resident_mib);
|
||||||
jemalloc_gauge!(retained, retained_mib);
|
jemalloc_gauge!(retained, retained_mib);
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub struct dump;
|
||||||
|
|
||||||
|
impl dump {
|
||||||
|
pub fn mib() -> tikv_jemalloc_ctl::Result<dump_mib> {
|
||||||
|
Ok(dump_mib(b"prof.dump\0".as_slice().name().mib_str()?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub struct dump_mib(pub MibStr<[usize; 2]>);
|
||||||
|
|
||||||
|
impl dump_mib {
|
||||||
|
pub fn write(self, value: &'static CStr) -> tikv_jemalloc_ctl::Result<()> {
|
||||||
|
// No support for Access<CStr> yet.
|
||||||
|
// self.0.write(value)
|
||||||
|
let mib = [self.0[0], self.0[1]];
|
||||||
|
raw::write_str_mib(&mib, value.to_bytes_with_nul())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub struct active;
|
||||||
|
|
||||||
|
impl active {
|
||||||
|
pub fn name() -> &'static Name {
|
||||||
|
b"prof.active\0".as_slice().name()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl active {
|
||||||
|
pub fn read() -> tikv_jemalloc_ctl::Result<bool> {
|
||||||
|
Self::name().read()
|
||||||
|
}
|
||||||
|
pub fn write(value: bool) -> tikv_jemalloc_ctl::Result<()> {
|
||||||
|
Self::name().write(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub struct prof;
|
||||||
|
|
||||||
|
impl prof {
|
||||||
|
pub fn name() -> &'static Name {
|
||||||
|
b"opt.prof\0".as_slice().name()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl prof {
|
||||||
|
pub fn read() -> tikv_jemalloc_ctl::Result<bool> {
|
||||||
|
Self::name().read()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user