Skip to content

Commit

Permalink
rebased Profiler
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonwilliams committed May 25, 2020
1 parent 4beadfc commit 7e764b5
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 15 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,9 @@ yarn-error.log

# tests/js/test.js is used for testing changes locally
tests/js/test.js

# Profiling
*.string_data
*.string_index
*.events
chrome_profiler.json
89 changes: 89 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions boa/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ num-bigint = { version = "0.2.6", features = ["serde"] }
# Optional Dependencies
serde = { version = "1.0.110", features = ["derive"], optional = true }
bitflags = "1.2.1"
measureme = { version = "0.7.1" }
once_cell = "1.4.0"

[dev-dependencies]
criterion = "0.3.2"
Expand Down
14 changes: 12 additions & 2 deletions boa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,14 @@
pub mod builtins;
pub mod environment;
pub mod exec;
pub mod profiler;
pub mod realm;
pub mod syntax;

use crate::{builtins::value::ResultValue, syntax::ast::node::StatementList};
pub use crate::{
exec::{Executable, Interpreter},
profiler::BoaProfiler,
realm::Realm,
syntax::{lexer::Lexer, parser::Parser},
};
Expand Down Expand Up @@ -72,14 +74,22 @@ pub fn forward(engine: &mut Interpreter, src: &str) -> String {
/// Similar to `forward`, except the current value is returned instad of the string
/// If the interpreter fails parsing an error value is returned instead (error object)
pub fn forward_val(engine: &mut Interpreter, src: &str) -> ResultValue {
BoaProfiler::init();
let main_timer = BoaProfiler::global().start_event("Main", "Main");
// Setup executor
match parser_expr(src) {
let result = match parser_expr(src) {
Ok(expr) => expr.run(engine),
Err(e) => {
eprintln!("{}", e);
std::process::exit(1);
}
}
};

// The main_timer needs to be dropped before the BoaProfiler is.
drop(main_timer);
BoaProfiler::global().drop();

result
}

/// Create a clean Interpreter and execute the code
Expand Down
77 changes: 77 additions & 0 deletions boa/src/profiler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#![allow(missing_copy_implementations, missing_debug_implementations)]

use measureme::{EventId, Profiler, TimingGuard};
use once_cell::sync::OnceCell;
use std::fmt::{self, Debug};
use std::{
path::Path,
thread::{current, ThreadId},
};

/// MmapSerializatioSink is faster on macOS and Linux
/// but FileSerializationSink is faster on Windows
#[cfg(not(windows))]
type SerializationSink = measureme::MmapSerializationSink;
#[cfg(windows)]
type SerializationSink = measureme::FileSerializationSink;

pub struct BoaProfiler {
profiler: Profiler<SerializationSink>,
}

pub static mut INSTANCE: OnceCell<BoaProfiler> = OnceCell::new();

impl BoaProfiler {
pub fn start_event(&self, label: &str, category: &str) -> TimingGuard<'_, SerializationSink> {
let kind = self.profiler.alloc_string(category);
let id = EventId::from_label(self.profiler.alloc_string(label));
let thread_id = Self::thread_id_to_u32(current().id());
self.profiler
.start_recording_interval_event(kind, id, thread_id)
}

pub fn default() -> BoaProfiler {
let profiler = Profiler::new(Path::new("./my_trace")).unwrap();
BoaProfiler { profiler }
}

// init creates a global instance of BoaProfiler which can be used across the whole application
pub fn init() {
let profiler = Self::default();
unsafe {
INSTANCE
.set(profiler)
.expect("Failed to set BoaProfiler globally");
}
}

pub fn global() -> &'static BoaProfiler {
unsafe { INSTANCE.get().expect("Profiler is not initialized") }
}

pub fn drop(&self) {
// In order to drop the INSTANCE we need to get ownership of it, which isn't possible on a static unless you make it a mutable static
// mutating statics is unsafe, so we need to wrap it as so.
// This is actually safe though because init and drop are only called at the beginning and end of the application
unsafe {
INSTANCE
.take()
.expect("Could not take back profiler instance");
}
}

// Sadly we need to use the unsafe method until this is resolved:
// https://github.com/rust-lang/rust/issues/67939
// Once `as_64()` is in stable we can do this:
// https://github.com/rust-lang/rust/pull/68531/commits/ea42b1c5b85f649728e3a3b334489bac6dce890a
// Until then our options are: use rust-nightly or use unsafe {}
fn thread_id_to_u32(tid: ThreadId) -> u32 {
unsafe { std::mem::transmute::<ThreadId, u64>(tid) as u32 }
}
}

impl Debug for BoaProfiler {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt("no debug implemented", f)
}
}
2 changes: 2 additions & 0 deletions boa/src/realm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::{
lexical_environment::LexicalEnvironment,
object_environment_record::ObjectEnvironmentRecord,
},
BoaProfiler,
};
use gc::{Gc, GcCell};
use rustc_hash::{FxHashMap, FxHashSet};
Expand All @@ -32,6 +33,7 @@ pub struct Realm {

impl Realm {
pub fn create() -> Self {
let _timer = BoaProfiler::global().start_event("Realm::create", "Realm");
// Create brand new global object
// Global has no prototype to pass None to new_obj
let global = Value::new_object(None);
Expand Down
10 changes: 7 additions & 3 deletions boa/src/syntax/lexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
mod tests;

use crate::syntax::ast::bigint::BigInt;
use crate::syntax::ast::{
token::{NumericLiteral, Token, TokenKind},
Position, Punctuator, Span,
use crate::{
syntax::ast::{
token::{NumericLiteral, Token, TokenKind},
Position, Punctuator, Span,
},
BoaProfiler,
};
use std::{
char::{decode_utf16, from_u32},
Expand Down Expand Up @@ -486,6 +489,7 @@ impl<'a> Lexer<'a> {
/// }
/// ```
pub fn lex(&mut self) -> Result<(), LexerError> {
let _timer = BoaProfiler::global().start_event("lex", "lexing");
loop {
// Check if we've reached the end
if self.preview_next().is_none() {
Expand Down
24 changes: 14 additions & 10 deletions boa/src/syntax/parser/expression/assignment/arrow_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,20 @@
//! [spec]: https://tc39.es/ecma262/#sec-arrow-function-definitions

use super::AssignmentExpression;
use crate::syntax::{
ast::{
node::{ArrowFunctionDecl, FormalParameter, Node, StatementList},
Punctuator, TokenKind,
},
parser::{
error::{ErrorContext, ParseError, ParseResult},
function::{FormalParameters, FunctionBody},
statement::BindingIdentifier,
AllowAwait, AllowIn, AllowYield, Cursor, TokenParser,
use crate::{
syntax::{
ast::{
node::{ArrowFunctionDecl, FormalParameter, Node, StatementList},
Punctuator, TokenKind,
},
parser::{
error::{ErrorContext, ParseError, ParseResult},
function::{FormalParameters, FunctionBody},
statement::BindingIdentifier,
AllowAwait, AllowIn, AllowYield, Cursor, TokenParser,
},
},
BoaProfiler,
};

/// Arrow function parsing.
Expand Down Expand Up @@ -60,6 +63,7 @@ impl TokenParser for ArrowFunction {
type Output = ArrowFunctionDecl;

fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> {
let _timer = BoaProfiler::global().start_event("ArrowFunction", "Parsing");
let next_token = cursor.peek(0).ok_or(ParseError::AbruptEnd)?;
let params = if let TokenKind::Punctuator(Punctuator::OpenParen) = &next_token.kind {
// CoverParenthesizedExpressionAndArrowParameterList
Expand Down

0 comments on commit 7e764b5

Please sign in to comment.