<commit_before>// Copyright 2016 The rustc-perf Project Developers. See the COPYRIGHT
// file at the top-level directory.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::str;
use std::fs::File;
use std::io::{Read, Write};
use std::sync::Arc;
use std::collections::HashMap;
use std::path::Path;
use std::net::SocketAddr;
use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
use std::cmp::Ordering;

use serde::Serialize;
use serde::de::DeserializeOwned;
use serde_json;
use rmp_serde;
use futures::{self, Future, Stream};
use futures_cpupool::CpuPool;
use hyper::{self, Get, Post, StatusCode};
use hyper::header::{AcceptEncoding, CacheControl, CacheDirective, Encoding};
use hyper::header::{ContentEncoding, ContentLength, ContentType};
use hyper::mime;
use hyper::server::{Http, Request, Response, Service};
use url::Url;
use flate2::Compression;
use flate2::write::GzEncoder;
use semver::Version;

use git;
use util::{self, get_repo_path};
pub use api::{self, dashboard, data, days, graph, info, CommitResponse, ServerResult};
use collector::{Date, Run};
use load::{CommitData, InputData};
use antidote::RwLock;

use errors::*;

/// Data associated with a specific date
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct DateData {
    pub date: Date,
    pub commit: String,
    pub data: HashMap<String, Vec<(String, Run, f64)>>,
}

impl DateData {
    pub fn for_day(commit: &CommitData, stat: &str) -> DateData {
        let benchmarks = commit.benchmarks.values().filter_map(|v| v.as_ref().ok());
        let mut out = HashMap::with_capacity(commit.benchmarks.len() * 3);
        for benchmark in benchmarks {
            let mut runs_check = Vec::with_capacity(benchmark.runs.len() / 3);
            let mut runs_opt = Vec::with_capacity(benchmark.runs.len() / 3);
            let mut runs = Vec::with_capacity(benchmark.runs.len() / 3);
            for run in &benchmark.runs {
                let v = if run.release {
                    &mut runs_opt
                } else if run.check {
                    &mut runs_check
                } else {
                    &mut runs
                };
                if let Some(mut value) = run.get_stat(stat) {
                    if stat == "cpu-clock" {
                        // convert to seconds; perf records it in milliseconds
                        value /= 1000.0;
                    }
                    v.push((run.name(), run.clone(), value));
                }
            }
            if !runs_opt.is_empty() {
                out.insert(benchmark.name.clone() + "-opt", runs_opt);
            }
            if !runs_check.is_empty() {
                out.insert(benchmark.name.clone() + "-check", runs_check);
            }
            if !runs.is_empty() {
                out.insert(benchmark.name.clone(), runs);
            }
        }

        DateData {
            date: commit.commit.date,
            commit: commit.commit.sha.clone(),
            data: out,
        }
    }
}

pub fn handle_info(data: &InputData) -> info::Response {
    info::Response {
        crates: data.crate_list.clone(),
        stats: data.stats_list.clone(),
        as_of: data.last_date,
    }
}

fn average(v: &[f64]) -> f64 {
    v.iter().sum::<f64>() / v.len() as f64
}

pub fn handle_dashboard(data: &InputData) -> dashboard::Response {
    let mut versions = data.artifact_data.keys().cloned().collect::<Vec<_>>();
    versions.sort_by(|a, b| {
        match (a.parse::<Version>().ok(), b.parse::<Version>().ok()) {
            (Some(a), Some(b)) => a.cmp(&b),
            (_, _) => {
                if a == "beta" {
                    Ordering::Greater
                } else if b == "beta" {
                    Ordering::Less<commit_msg>Round to one decimal place on dashboard<commit_after>// Copyright 2016 The rustc-perf Project Developers. See the COPYRIGHT
// file at the top-level directory.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::str;
use std::fs::File;
use std::io::{Read, Write};
use std::sync::Arc;
use std::collections::HashMap;
use std::path::Path;
use std::net::SocketAddr;
use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
use std::cmp::Ordering;

use serde::Serialize;
use serde::de::DeserializeOwned;
use serde_json;
use rmp_serde;
use futures::{self, Future, Stream};
use futures_cpupool::CpuPool;
use hyper::{self, Get, Post, StatusCode};
use hyper::header::{AcceptEncoding, CacheControl, CacheDirective, Encoding};
use hyper::header::{ContentEncoding, ContentLength, ContentType};
use hyper::mime;
use hyper::server::{Http, Request, Response, Service};
use url::Url;
use flate2::Compression;
use flate2::write::GzEncoder;
use semver::Version;

use git;
use util::{self, get_repo_path};
pub use api::{self, dashboard, data, days, graph, info, CommitResponse, ServerResult};
use collector::{Date, Run};
use load::{CommitData, InputData};
use antidote::RwLock;

use errors::*;

/// Data associated with a specific date
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct DateData {
    pub date: Date,
    pub commit: String,
    pub data: HashMap<String, Vec<(String, Run, f64)>>,
}

impl DateData {
    pub fn for_day(commit: &CommitData, stat: &str) -> DateData {
        let benchmarks = commit.benchmarks.values().filter_map(|v| v.as_ref().ok());
        let mut out = HashMap::with_capacity(commit.benchmarks.len() * 3);
        for benchmark in benchmarks {
            let mut runs_check = Vec::with_capacity(benchmark.runs.len() / 3);
            let mut runs_opt = Vec::with_capacity(benchmark.runs.len() / 3);
            let mut runs = Vec::with_capacity(benchmark.runs.len() / 3);
            for run in &benchmark.runs {
                let v = if run.release {
                    &mut runs_opt
                } else if run.check {
                    &mut runs_check
                } else {
                    &mut runs
                };
                if let Some(mut value) = run.get_stat(stat) {
                    if stat == "cpu-clock" {
                        // convert to seconds; perf records it in milliseconds
                        value /= 1000.0;
                    }
                    v.push((run.name(), run.clone(), value));
                }
            }
            if !runs_opt.is_empty() {
                out.insert(benchmark.name.clone() + "-opt", runs_opt);
            }
            if !runs_check.is_empty() {
                out.insert(benchmark.name.clone() + "-check", runs_check);
            }
            if !runs.is_empty() {
                out.insert(benchmark.name.clone(), runs);
            }
        }

        DateData {
            date: commit.commit.date,
            commit: commit.commit.sha.clone(),
            data: out,
        }
    }
}

pub fn handle_info(data: &InputData) -> info::Response {
    info::Response {
        crates: data.crate_list.clone(),
        stats: data.stats_list.clone(),
        as_of: data.last_date,
    }
}

fn average(v: &[f64]) -> f64 {
    (v.iter().sum::<f64>() / v.len() as f64 * 10.0).round() / 10.0
}

pub fn handle_dashboard(data: &InputData) -> dashboard::Response {
    let mut versions = data.artifact_data.keys().cloned().collect::<Vec<_>>();
    versions.sort_by(|a, b| {
        match (a.parse::<Version>().ok(), b.parse::<Version>().ok()) {
            (Some(a), Some(b)) => a.cmp(&b),
            (_, _) => {
                if a == "beta" {
                    Ordering::Greater
                } else if b == "beta" {
                    Ordering::Less
{'fraction_non_alphanumeric': 0.14602427545206836, 'fraction_numerical': 0.007926678226405746, 'mean_word_length': 2.3409184940008276, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3904027', 'n_tokens_mistral': 2506, 'n_tokens_neox': 2442, 'n_words': 623}