mirror of https://github.com/boa-dev/boa.git
Jason Williams
5 years ago
committed by
GitHub
68 changed files with 645 additions and 177 deletions
@ -0,0 +1,95 @@
|
||||
#![allow(missing_copy_implementations, missing_debug_implementations)] |
||||
|
||||
#[cfg(feature = "profiler")] |
||||
use measureme::{EventId, Profiler, TimingGuard}; |
||||
#[cfg(feature = "profiler")] |
||||
use once_cell::sync::OnceCell; |
||||
use std::fmt::{self, Debug}; |
||||
#[cfg(feature = "profiler")] |
||||
use std::{ |
||||
path::Path, |
||||
thread::{current, ThreadId}, |
||||
}; |
||||
|
||||
/// MmapSerializatioSink is faster on macOS and Linux
|
||||
/// but FileSerializationSink is faster on Windows
|
||||
#[cfg(not(windows))] |
||||
#[cfg(feature = "profiler")] |
||||
type SerializationSink = measureme::MmapSerializationSink; |
||||
#[cfg(windows)] |
||||
#[cfg(feature = "profiler")] |
||||
type SerializationSink = measureme::FileSerializationSink; |
||||
#[cfg(feature = "profiler")] |
||||
pub struct BoaProfiler { |
||||
profiler: Profiler<SerializationSink>, |
||||
} |
||||
|
||||
/// This static instance should never be public, and its only access should be done through the `global()` and `drop()` methods
|
||||
/// This is because `get_or_init` manages synchronisation and the case of an empty value
|
||||
#[cfg(feature = "profiler")] |
||||
static mut INSTANCE: OnceCell<BoaProfiler> = OnceCell::new(); |
||||
|
||||
#[cfg(feature = "profiler")] |
||||
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 } |
||||
} |
||||
|
||||
pub fn global() -> &'static BoaProfiler { |
||||
unsafe { INSTANCE.get_or_init(Self::default) } |
||||
} |
||||
|
||||
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) |
||||
} |
||||
} |
||||
|
||||
#[cfg(not(feature = "profiler"))] |
||||
pub struct BoaProfiler; |
||||
|
||||
#[allow(clippy::unused_unit)] |
||||
#[cfg(not(feature = "profiler"))] |
||||
impl BoaProfiler { |
||||
pub fn start_event(&self, _label: &str, _category: &str) -> () { |
||||
() |
||||
} |
||||
|
||||
pub fn drop(&self) { |
||||
() |
||||
} |
||||
|
||||
pub fn global() -> BoaProfiler { |
||||
BoaProfiler |
||||
} |
||||
} |
After Width: | Height: | Size: 98 KiB |
@ -0,0 +1,30 @@
|
||||
# Profiling |
||||
|
||||
![Example](img/profiler.png) |
||||
|
||||
It's possible to get a full profile of Boa in action. |
||||
Sometimes this is needed to figure out where it is spending most of it's time. |
||||
|
||||
We use a crate called [measureme](https://github.com/rust-lang/measureme), which helps us keep track of timing functions during runtime. |
||||
|
||||
When the "profiler" flag is enabled, you compile with the profiler and it is called throughout the interpreter. |
||||
when the feature flag is not enabled, you have an empty dummy implementation that is just no ops. rustc should completely optimize that away. So there should be no performance downgrade from these changes |
||||
|
||||
## Prerequesites |
||||
|
||||
- [Crox](https://github.com/rust-lang/measureme/blob/master/crox/Readme.md) |
||||
|
||||
## How To Use |
||||
|
||||
You can run boa using the "profiler" feature flag to enable profiling. Seeing as you'll most likely be using boa_cli you can pass this through, like so: |
||||
|
||||
`cargo run --features Boa/profiler ../tests/js/test.js` |
||||
|
||||
Once finished you should see some trace files left in the directory (boa_cli in this case). |
||||
In the same directory as the `.events, string_data, string_index` files run `crox my_trace` or whatever the name of the files are. This will generate a chrome_profiler.json file, you can load this into Chrome Dev tools. |
||||
|
||||
## More Info |
||||
|
||||
- https://blog.rust-lang.org/inside-rust/2020/02/25/intro-rustc-self-profile.html |
||||
- https://github.com/rust-lang/measureme |
||||
- https://github.com/rust-lang/measureme/blob/master/crox/Readme.md |
Loading…
Reference in new issue