mirror of
https://github.com/servo/servo.git
synced 2025-07-23 23:33:43 +01:00
Add option to write profiler output to InfluxDB
This commit is contained in:
parent
990c4091fe
commit
360f2cc492
5 changed files with 87 additions and 6 deletions
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -1309,6 +1309,15 @@ name = "inflate"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "influent"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"hyper 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "io-surface"
|
name = "io-surface"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
@ -2164,6 +2173,7 @@ name = "profile"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heartbeats-simple 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"heartbeats-simple 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"influent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -3637,6 +3647,7 @@ dependencies = [
|
||||||
"checksum image 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d95816db758249fe16f23a4e23f1a3a817fe11892dbfd1c5836f625324702158"
|
"checksum image 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d95816db758249fe16f23a4e23f1a3a817fe11892dbfd1c5836f625324702158"
|
||||||
"checksum immeta 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0b9260463a221bfe3f02100c56e2d14c050d5ffe7e44a43d0a1b2b1f2b523502"
|
"checksum immeta 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0b9260463a221bfe3f02100c56e2d14c050d5ffe7e44a43d0a1b2b1f2b523502"
|
||||||
"checksum inflate 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e7e0062d2dc2f17d2f13750d95316ae8a2ff909af0fda957084f5defd87c43bb"
|
"checksum inflate 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e7e0062d2dc2f17d2f13750d95316ae8a2ff909af0fda957084f5defd87c43bb"
|
||||||
|
"checksum influent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a22b311b83431be3ab9af96ca9ea41554bb4a8551ea871ae44c3ce0c57e55f2c"
|
||||||
"checksum io-surface 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c35a3278fa52fb070fdc874dfd057163e6c21e0a9295f87f54daee9dd5530b43"
|
"checksum io-surface 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c35a3278fa52fb070fdc874dfd057163e6c21e0a9295f87f54daee9dd5530b43"
|
||||||
"checksum iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29d062ee61fccdf25be172e70f34c9f6efc597e1fb8f6526e8437b2046ab26be"
|
"checksum iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29d062ee61fccdf25be172e70f34c9f6efc597e1fb8f6526e8437b2046ab26be"
|
||||||
"checksum ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a38ad662f104525ac57012e0b79aad07507e3fc11e3bae668bf416264e760ebb"
|
"checksum ipc-channel 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a38ad662f104525ac57012e0b79aad07507e3fc11e3bae668bf416264e760ebb"
|
||||||
|
|
|
@ -39,8 +39,13 @@ pub struct Opts {
|
||||||
/// platform default setting.
|
/// platform default setting.
|
||||||
pub device_pixels_per_px: Option<f32>,
|
pub device_pixels_per_px: Option<f32>,
|
||||||
|
|
||||||
/// `None` to disable the time profiler or `Some` with an interval in seconds to enable it and
|
/// `None` to disable the time profiler or `Some` to enable it with:
|
||||||
/// cause it to produce output on that interval (`-p`).
|
/// - an interval in seconds to cause it to produce output on that interval.
|
||||||
|
/// (`i.e. -p 5`).
|
||||||
|
/// - a file path to write profiling info to a TSV file upon Servo's termination.
|
||||||
|
/// (`i.e. -p out.tsv`).
|
||||||
|
/// - an InfluxDB hostname to store profiling info upon Servo's termination.
|
||||||
|
/// (`i.e. -p http://localhost:8086`)
|
||||||
pub time_profiling: Option<OutputOptions>,
|
pub time_profiling: Option<OutputOptions>,
|
||||||
|
|
||||||
/// When the profiler is enabled, this is an optional path to dump a self-contained HTML file
|
/// When the profiler is enabled, this is an optional path to dump a self-contained HTML file
|
||||||
|
@ -419,8 +424,10 @@ fn print_debug_usage(app: &str) -> ! {
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, Serialize)]
|
#[derive(Clone, Deserialize, Serialize)]
|
||||||
pub enum OutputOptions {
|
pub enum OutputOptions {
|
||||||
|
/// Database connection config (hostname, name, user, pass)
|
||||||
|
DB(ServoUrl, Option<String>, Option<String>, Option<String>),
|
||||||
FileName(String),
|
FileName(String),
|
||||||
Stdout(f64)
|
Stdout(f64),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn args_fail(msg: &str) -> ! {
|
fn args_fail(msg: &str) -> ! {
|
||||||
|
@ -598,6 +605,9 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult {
|
||||||
"config directory following xdg spec on linux platform", "");
|
"config directory following xdg spec on linux platform", "");
|
||||||
opts.optflag("v", "version", "Display servo version information");
|
opts.optflag("v", "version", "Display servo version information");
|
||||||
opts.optflag("", "unminify-js", "Unminify Javascript");
|
opts.optflag("", "unminify-js", "Unminify Javascript");
|
||||||
|
opts.optopt("", "profiler-db-user", "Profiler database user", "");
|
||||||
|
opts.optopt("", "profiler-db-pass", "Profiler database password", "");
|
||||||
|
opts.optopt("", "profiler-db-name", "Profiler database name", "");
|
||||||
|
|
||||||
let opt_match = match opts.parse(args) {
|
let opt_match = match opts.parse(args) {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
|
@ -666,7 +676,14 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult {
|
||||||
match opt_match.opt_str("p") {
|
match opt_match.opt_str("p") {
|
||||||
Some(argument) => match argument.parse::<f64>() {
|
Some(argument) => match argument.parse::<f64>() {
|
||||||
Ok(interval) => Some(OutputOptions::Stdout(interval)) ,
|
Ok(interval) => Some(OutputOptions::Stdout(interval)) ,
|
||||||
|
Err(_) => {
|
||||||
|
match ServoUrl::parse(&argument) {
|
||||||
|
Ok(url) => Some(OutputOptions::DB(url, opt_match.opt_str("profiler-db-name"),
|
||||||
|
opt_match.opt_str("profiler-db-user"),
|
||||||
|
opt_match.opt_str("profiler-db-pass"))),
|
||||||
Err(_) => Some(OutputOptions::FileName(argument)),
|
Err(_) => Some(OutputOptions::FileName(argument)),
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
None => Some(OutputOptions::Stdout(5.0 as f64)),
|
None => Some(OutputOptions::Stdout(5.0 as f64)),
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ path = "lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
profile_traits = {path = "../profile_traits"}
|
profile_traits = {path = "../profile_traits"}
|
||||||
|
influent = "0.4"
|
||||||
ipc-channel = "0.8"
|
ipc-channel = "0.8"
|
||||||
heartbeats-simple = "0.4"
|
heartbeats-simple = "0.4"
|
||||||
log = "0.3.5"
|
log = "0.3.5"
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
extern crate alloc_jemalloc;
|
extern crate alloc_jemalloc;
|
||||||
extern crate heartbeats_simple;
|
extern crate heartbeats_simple;
|
||||||
|
extern crate influent;
|
||||||
extern crate ipc_channel;
|
extern crate ipc_channel;
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
//! Timing functions.
|
//! Timing functions.
|
||||||
|
|
||||||
use heartbeats;
|
use heartbeats;
|
||||||
|
use influent::client::{Client, Credentials};
|
||||||
|
use influent::create_client;
|
||||||
|
use influent::measurement::{Measurement, Value};
|
||||||
use ipc_channel::ipc::{self, IpcReceiver};
|
use ipc_channel::ipc::{self, IpcReceiver};
|
||||||
use profile_traits::energy::{energy_interval_ms, read_energy_uj};
|
use profile_traits::energy::{energy_interval_ms, read_energy_uj};
|
||||||
use profile_traits::time::{ProfilerCategory, ProfilerChan, ProfilerMsg, TimerMetadata};
|
use profile_traits::time::{ProfilerCategory, ProfilerChan, ProfilerMsg, TimerMetadata};
|
||||||
|
@ -183,7 +186,8 @@ impl Profiler {
|
||||||
}).expect("Thread spawning failed");
|
}).expect("Thread spawning failed");
|
||||||
// decide if we need to spawn the timer thread
|
// decide if we need to spawn the timer thread
|
||||||
match option {
|
match option {
|
||||||
&OutputOptions::FileName(_) => { /* no timer thread needed */ },
|
&OutputOptions::FileName(_) |
|
||||||
|
&OutputOptions::DB(_, _, _, _) => { /* no timer thread needed */ },
|
||||||
&OutputOptions::Stdout(period) => {
|
&OutputOptions::Stdout(period) => {
|
||||||
// Spawn a timer thread
|
// Spawn a timer thread
|
||||||
let chan = chan.clone();
|
let chan = chan.clone();
|
||||||
|
@ -391,7 +395,54 @@ impl Profiler {
|
||||||
}
|
}
|
||||||
writeln!(&mut lock, "").unwrap();
|
writeln!(&mut lock, "").unwrap();
|
||||||
},
|
},
|
||||||
None => { /* Do nothing if not output option has been set */ },
|
Some(OutputOptions::DB(ref hostname, ref dbname, ref user, ref password)) => {
|
||||||
|
// Unfortunately, influent does not like hostnames ending with "/"
|
||||||
|
let mut hostname = hostname.to_string();
|
||||||
|
if hostname.ends_with("/") {
|
||||||
|
hostname.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
let empty = String::from("");
|
||||||
|
let username = user.as_ref().unwrap_or(&empty);
|
||||||
|
let password = password.as_ref().unwrap_or(&empty);
|
||||||
|
let database = dbname.as_ref().unwrap_or(&empty);
|
||||||
|
let credentials = Credentials {
|
||||||
|
username: username,
|
||||||
|
password: password,
|
||||||
|
database: database,
|
||||||
|
};
|
||||||
|
|
||||||
|
let hosts = vec![hostname.as_str()];
|
||||||
|
let client = create_client(credentials, hosts);
|
||||||
|
|
||||||
|
for (&(ref category, ref meta), ref mut data) in &mut self.buckets {
|
||||||
|
data.sort_by(|a, b| {
|
||||||
|
if a < b {
|
||||||
|
Ordering::Less
|
||||||
|
} else {
|
||||||
|
Ordering::Greater
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let data_len = data.len();
|
||||||
|
if data_len > 0 {
|
||||||
|
let (mean, median, min, max) = Self::get_statistics(data);
|
||||||
|
let category = category.format(&self.output);
|
||||||
|
let mut measurement = Measurement::new(&category);
|
||||||
|
measurement.add_field("mean", Value::Float(mean));
|
||||||
|
measurement.add_field("median", Value::Float(median));
|
||||||
|
measurement.add_field("min", Value::Float(min));
|
||||||
|
measurement.add_field("max", Value::Float(max));
|
||||||
|
if let Some(ref meta) = *meta {
|
||||||
|
measurement.add_tag("host", meta.url.as_str());
|
||||||
|
};
|
||||||
|
if client.write_one(measurement, None).is_err() {
|
||||||
|
warn!("Could not write measurement to profiler db");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
None => { /* Do nothing if no output option has been set */ },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue