-
-
Save ishitatsuyuki/0f8acbd9e00f82820573921e8907baea to your computer and use it in GitHub Desktop.
Grafana/InfluxDB experiment
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "perf-influxdb" | |
version = "0.1.0" | |
authors = ["Tatsuyuki Ishi <ishitatsuyuki@gmail.com>"] | |
[dependencies] | |
serde = "1.0.75" | |
serde_derive = "1.0.75" | |
influx_db_client = "0.3.4" | |
serde_json = "1.0.26" | |
chrono = {version = "0.4.6", features = ["serde"]} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"annotations": { | |
"list": [ | |
{ | |
"builtIn": 1, | |
"datasource": "-- Grafana --", | |
"enable": true, | |
"hide": true, | |
"iconColor": "rgba(0, 211, 255, 1)", | |
"name": "Annotations & Alerts", | |
"type": "dashboard" | |
} | |
] | |
}, | |
"editable": true, | |
"gnetId": null, | |
"graphTooltip": 0, | |
"id": 1, | |
"iteration": 1535808279921, | |
"links": [], | |
"panels": [ | |
{ | |
"aliasColors": {}, | |
"bars": false, | |
"dashLength": 10, | |
"dashes": false, | |
"datasource": null, | |
"fill": 1, | |
"gridPos": { | |
"h": 9, | |
"w": 24, | |
"x": 0, | |
"y": 0 | |
}, | |
"id": 2, | |
"legend": { | |
"avg": false, | |
"current": false, | |
"max": false, | |
"min": false, | |
"show": true, | |
"total": false, | |
"values": false | |
}, | |
"lines": true, | |
"linewidth": 1, | |
"links": [], | |
"minSpan": 8, | |
"nullPointMode": "null", | |
"percentage": false, | |
"pointradius": 5, | |
"points": false, | |
"renderer": "flot", | |
"repeat": "bench", | |
"repeatDirection": "h", | |
"scopedVars": { | |
"bench": { | |
"selected": true, | |
"text": "cargo", | |
"value": "cargo" | |
} | |
}, | |
"seriesOverrides": [], | |
"spaceLength": 10, | |
"stack": false, | |
"steppedLine": false, | |
"targets": [ | |
{ | |
"groupBy": [ | |
{ | |
"params": [ | |
"state" | |
], | |
"type": "tag" | |
} | |
], | |
"measurement": "rustc_perf", | |
"orderByTime": "ASC", | |
"policy": "default", | |
"refId": "A", | |
"resultFormat": "time_series", | |
"select": [ | |
[ | |
{ | |
"params": [ | |
"instructions:u" | |
], | |
"type": "field" | |
} | |
] | |
], | |
"tags": [ | |
{ | |
"key": "build", | |
"operator": "=~", | |
"value": "/^$build$/" | |
}, | |
{ | |
"condition": "AND", | |
"key": "bench", | |
"operator": "=~", | |
"value": "/^$bench$/" | |
} | |
] | |
} | |
], | |
"thresholds": [], | |
"timeFrom": null, | |
"timeShift": null, | |
"title": "$bench $build", | |
"tooltip": { | |
"shared": true, | |
"sort": 0, | |
"value_type": "individual" | |
}, | |
"type": "graph", | |
"xaxis": { | |
"buckets": null, | |
"mode": "time", | |
"name": null, | |
"show": true, | |
"values": [] | |
}, | |
"yaxes": [ | |
{ | |
"format": "short", | |
"label": null, | |
"logBase": 1, | |
"max": null, | |
"min": null, | |
"show": true | |
}, | |
{ | |
"format": "short", | |
"label": null, | |
"logBase": 1, | |
"max": null, | |
"min": null, | |
"show": true | |
} | |
], | |
"yaxis": { | |
"align": false, | |
"alignLevel": null | |
} | |
} | |
], | |
"refresh": false, | |
"schemaVersion": 16, | |
"style": "dark", | |
"tags": [], | |
"templating": { | |
"list": [ | |
{ | |
"allValue": null, | |
"current": { | |
"selected": true, | |
"text": "check", | |
"value": "check" | |
}, | |
"datasource": "Default", | |
"hide": 0, | |
"includeAll": false, | |
"label": null, | |
"multi": false, | |
"name": "build", | |
"options": [ | |
{ | |
"selected": true, | |
"text": "check", | |
"value": "check" | |
}, | |
{ | |
"selected": false, | |
"text": "debug", | |
"value": "debug" | |
}, | |
{ | |
"selected": false, | |
"text": "release", | |
"value": "release" | |
} | |
], | |
"query": "SHOW TAG VALUES WITH KEY = build", | |
"refresh": 0, | |
"regex": "", | |
"sort": 0, | |
"tagValuesQuery": "", | |
"tags": [], | |
"tagsQuery": "", | |
"type": "query", | |
"useTags": false | |
}, | |
{ | |
"allValue": null, | |
"current": { | |
"selected": true, | |
"tags": [], | |
"text": "cargo", | |
"value": [ | |
"cargo" | |
] | |
}, | |
"datasource": "Default", | |
"hide": 0, | |
"includeAll": true, | |
"label": null, | |
"multi": true, | |
"name": "bench", | |
"options": [ | |
{ | |
"selected": false, | |
"text": "All", | |
"value": "$__all" | |
}, | |
{ | |
"selected": true, | |
"text": "cargo", | |
"value": "cargo" | |
}, | |
{ | |
"selected": false, | |
"text": "clap-rs", | |
"value": "clap-rs" | |
}, | |
{ | |
"selected": false, | |
"text": "coercions", | |
"value": "coercions" | |
}, | |
{ | |
"selected": false, | |
"text": "crates.io", | |
"value": "crates.io" | |
}, | |
{ | |
"selected": false, | |
"text": "ctfe-stress", | |
"value": "ctfe-stress" | |
}, | |
{ | |
"selected": false, | |
"text": "ctfe-stress-cast", | |
"value": "ctfe-stress-cast" | |
}, | |
{ | |
"selected": false, | |
"text": "ctfe-stress-const-fn", | |
"value": "ctfe-stress-const-fn" | |
}, | |
{ | |
"selected": false, | |
"text": "ctfe-stress-force-alloc", | |
"value": "ctfe-stress-force-alloc" | |
}, | |
{ | |
"selected": false, | |
"text": "ctfe-stress-index-check", | |
"value": "ctfe-stress-index-check" | |
}, | |
{ | |
"selected": false, | |
"text": "ctfe-stress-ops", | |
"value": "ctfe-stress-ops" | |
}, | |
{ | |
"selected": false, | |
"text": "ctfe-stress-reloc", | |
"value": "ctfe-stress-reloc" | |
}, | |
{ | |
"selected": false, | |
"text": "ctfe-stress-unsize-slice", | |
"value": "ctfe-stress-unsize-slice" | |
}, | |
{ | |
"selected": false, | |
"text": "deep-vector", | |
"value": "deep-vector" | |
}, | |
{ | |
"selected": false, | |
"text": "deeply-nested", | |
"value": "deeply-nested" | |
}, | |
{ | |
"selected": false, | |
"text": "encoding", | |
"value": "encoding" | |
}, | |
{ | |
"selected": false, | |
"text": "futures", | |
"value": "futures" | |
}, | |
{ | |
"selected": false, | |
"text": "helloworld", | |
"value": "helloworld" | |
}, | |
{ | |
"selected": false, | |
"text": "html5ever", | |
"value": "html5ever" | |
}, | |
{ | |
"selected": false, | |
"text": "hyper", | |
"value": "hyper" | |
}, | |
{ | |
"selected": false, | |
"text": "inflate", | |
"value": "inflate" | |
}, | |
{ | |
"selected": false, | |
"text": "issue-46449", | |
"value": "issue-46449" | |
}, | |
{ | |
"selected": false, | |
"text": "keccak", | |
"value": "keccak" | |
}, | |
{ | |
"selected": false, | |
"text": "piston-image", | |
"value": "piston-image" | |
}, | |
{ | |
"selected": false, | |
"text": "regex", | |
"value": "regex" | |
}, | |
{ | |
"selected": false, | |
"text": "regression-31157", | |
"value": "regression-31157" | |
}, | |
{ | |
"selected": false, | |
"text": "ripgrep", | |
"value": "ripgrep" | |
}, | |
{ | |
"selected": false, | |
"text": "script-servo", | |
"value": "script-servo" | |
}, | |
{ | |
"selected": false, | |
"text": "sentry-cli", | |
"value": "sentry-cli" | |
}, | |
{ | |
"selected": false, | |
"text": "serde", | |
"value": "serde" | |
}, | |
{ | |
"selected": false, | |
"text": "style-servo", | |
"value": "style-servo" | |
}, | |
{ | |
"selected": false, | |
"text": "syn", | |
"value": "syn" | |
}, | |
{ | |
"selected": false, | |
"text": "tokio-webpush-simple", | |
"value": "tokio-webpush-simple" | |
}, | |
{ | |
"selected": false, | |
"text": "tuple-stress", | |
"value": "tuple-stress" | |
}, | |
{ | |
"selected": false, | |
"text": "ucd", | |
"value": "ucd" | |
}, | |
{ | |
"selected": false, | |
"text": "unify-linearly", | |
"value": "unify-linearly" | |
}, | |
{ | |
"selected": false, | |
"text": "unused-warnings", | |
"value": "unused-warnings" | |
}, | |
{ | |
"selected": false, | |
"text": "webrender", | |
"value": "webrender" | |
} | |
], | |
"query": "SHOW TAG VALUES WITH KEY = bench", | |
"refresh": 0, | |
"regex": "", | |
"sort": 0, | |
"tagValuesQuery": "", | |
"tags": [], | |
"tagsQuery": "", | |
"type": "query", | |
"useTags": false | |
} | |
] | |
}, | |
"time": { | |
"from": "now-90d", | |
"to": "now" | |
}, | |
"timepicker": { | |
"refresh_intervals": [ | |
"5s", | |
"10s", | |
"30s", | |
"1m", | |
"5m", | |
"15m", | |
"30m", | |
"1h", | |
"2h", | |
"1d" | |
], | |
"time_options": [ | |
"5m", | |
"15m", | |
"1h", | |
"6h", | |
"12h", | |
"24h", | |
"2d", | |
"7d", | |
"30d" | |
] | |
}, | |
"timezone": "", | |
"title": "Graph", | |
"uid": "-QhIRphmz", | |
"version": 5 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::cmp::Ordering; | |
use std::collections::BTreeMap; | |
use std::env; | |
use std::fmt; | |
use std::fs; | |
use std::path::PathBuf; | |
use std::str::FromStr; | |
extern crate serde; | |
use serde::{Deserialize, Serialize}; | |
#[macro_use] | |
extern crate serde_derive; | |
extern crate chrono; | |
extern crate serde_json; | |
use chrono::prelude::*; | |
extern crate influx_db_client; | |
use influx_db_client::{Client, Point, Points, Precision, Value}; | |
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] | |
pub struct Date(pub DateTime<Utc>); | |
#[derive(Debug, Clone, PartialEq, Eq)] | |
pub struct DateParseError { | |
pub input: String, | |
pub format: String, | |
pub error: chrono::ParseError, | |
} | |
impl FromStr for Date { | |
type Err = DateParseError; | |
fn from_str(s: &str) -> Result<Date, DateParseError> { | |
match DateTime::parse_from_rfc3339(s) { | |
Ok(value) => Ok(Date(value.with_timezone(&Utc))), | |
Err(error) => Err(DateParseError { | |
input: s.to_string(), | |
format: format!("RFC 3339"), | |
error, | |
}), | |
} | |
} | |
} | |
impl Serialize for Date { | |
fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error> | |
where | |
S: serde::ser::Serializer, | |
{ | |
serializer.serialize_str(&self.0.to_rfc3339()) | |
} | |
} | |
impl<'de> Deserialize<'de> for Date { | |
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Date, D::Error> | |
where | |
D: serde::de::Deserializer<'de>, | |
{ | |
struct DateVisitor; | |
impl<'de> serde::de::Visitor<'de> for DateVisitor { | |
type Value = Date; | |
fn visit_str<E>(self, value: &str) -> ::std::result::Result<Date, E> | |
where | |
E: serde::de::Error, | |
{ | |
Date::from_str(value).map_err(|_| { | |
serde::de::Error::invalid_value(serde::de::Unexpected::Str(value), &self) | |
}) | |
} | |
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
f.write_str("an RFC 3339 date") | |
} | |
} | |
deserializer.deserialize_str(DateVisitor) | |
} | |
} | |
#[derive(Debug, Clone, Deserialize, Serialize)] | |
pub struct Commit { | |
pub sha: String, | |
pub date: Date, | |
} | |
impl Commit { | |
pub fn is_try(&self) -> bool { | |
self.date.0.naive_utc().date() == NaiveDate::from_ymd(2000, 1, 1) | |
} | |
} | |
impl std::hash::Hash for Commit { | |
fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) { | |
self.sha.hash(hasher); | |
} | |
} | |
impl PartialEq for Commit { | |
fn eq(&self, other: &Self) -> bool { | |
self.sha == other.sha | |
} | |
} | |
impl Eq for Commit {} | |
impl PartialOrd for Commit { | |
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | |
Some(self.cmp(&other)) | |
} | |
} | |
impl Ord for Commit { | |
fn cmp(&self, other: &Self) -> Ordering { | |
self.date | |
.cmp(&other.date) | |
.then_with(|| self.sha.cmp(&other.sha)) | |
} | |
} | |
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)] | |
pub struct Patch { | |
index: usize, | |
pub name: String, | |
path: PathBuf, | |
} | |
#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize, Serialize)] | |
pub enum BenchmarkState { | |
Clean, | |
Nll, | |
IncrementalStart, | |
IncrementalClean, | |
IncrementalPatched(Patch), | |
} | |
impl BenchmarkState { | |
pub fn is_base_compile(&self) -> bool { | |
if let BenchmarkState::Clean = *self { | |
true | |
} else { | |
false | |
} | |
} | |
pub fn is_patch(&self) -> bool { | |
if let BenchmarkState::IncrementalPatched(_) = *self { | |
true | |
} else { | |
false | |
} | |
} | |
pub fn name(&self) -> String { | |
match *self { | |
BenchmarkState::Clean => format!("clean"), | |
BenchmarkState::Nll => format!("nll"), | |
BenchmarkState::IncrementalStart => format!("baseline incremental"), | |
BenchmarkState::IncrementalClean => format!("clean incremental"), | |
BenchmarkState::IncrementalPatched(ref patch) => { | |
format!("patched incremental: {}", patch.name) | |
} | |
} | |
} | |
// Otherwise we end up with "equivalent benchmarks" looking different, | |
// e.g. 8-println.patch vs. 0-println.patch | |
pub fn erase_path(mut self) -> Self { | |
match &mut self { | |
BenchmarkState::IncrementalPatched(patch) => { | |
patch.index = 0; | |
patch.path = PathBuf::new(); | |
} | |
_ => {} | |
} | |
self | |
} | |
} | |
#[derive(Debug, Clone, Deserialize, Serialize)] | |
pub struct Benchmark { | |
pub runs: Vec<Run>, | |
pub name: String, | |
} | |
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] | |
pub struct Stat { | |
pub name: String, | |
pub cnt: f64, | |
} | |
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] | |
pub struct Run { | |
pub stats: Vec<Stat>, | |
#[serde(default)] | |
pub check: bool, | |
pub release: bool, | |
pub state: BenchmarkState, | |
} | |
#[derive(Debug, Clone, Deserialize, Serialize)] | |
pub struct CommitData { | |
pub commit: Commit, | |
// String in Result is the output of the command that failed | |
pub benchmarks: BTreeMap<String, Result<Benchmark, String>>, | |
pub triple: String, | |
} | |
fn main() -> Result<(), std::io::Error> { | |
let client = Client::new("http://localhost:8086", "rust"); | |
for arg in env::args().skip(1) { | |
let file = fs::read(arg)?; | |
let parsed: CommitData = serde_json::from_slice(&file)?; | |
let mut points = Vec::new(); | |
for (bench, result) in parsed.benchmarks { | |
if let Ok(Benchmark { runs, .. }) = result { | |
for run in runs { | |
let mut point = Point::new("rustc_perf"); | |
point.add_tag("bench", Value::String(bench.clone())); | |
point.add_tag("state", Value::String(run.state.name().to_owned())); | |
point.add_field("commit", Value::String(parsed.commit.sha.clone())); | |
if run.check { | |
point.add_tag("build", Value::String("check".to_owned())); | |
} else if run.release { | |
point.add_tag("build", Value::String("release".to_owned())); | |
} else { | |
point.add_tag("build", Value::String("debug".to_owned())); | |
} | |
for stat in run.stats { | |
point.add_field(stat.name, Value::Float(stat.cnt)); | |
} | |
point.add_timestamp(parsed.commit.date.0.timestamp()); | |
points.push(point); | |
} | |
} | |
} | |
client.write_points(Points::create_new(points), Some(Precision::Seconds), None).unwrap(); | |
} | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment