Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix dhat support for turbo dev #67166

Merged
merged 1 commit into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Fix dhat support for turbo dev and build
  • Loading branch information
bgw committed Jan 16, 2025
commit caa317ee3b39f645067b7a10ab522a051baa9a0c
12 changes: 10 additions & 2 deletions crates/napi/src/next_api/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
NextTurboTasks, RootTask, TurbopackResult, VcArc,
},
};
use crate::register;
use crate::{register, util::DhatProfilerGuard};

/// Used by [`benchmark_file_io`]. This is a noisy benchmark, so set the
/// threshold high.
Expand Down Expand Up @@ -295,11 +295,19 @@
turbo_engine_options: NapiTurboEngineOptions,
) -> napi::Result<External<ProjectInstance>> {
register();
let (exit, exit_receiver) = ExitHandler::new_receiver();

if let Some(dhat_profiler) = DhatProfilerGuard::try_init() {
exit.on_exit(async move {
tokio::task::spawn_blocking(move || drop(dhat_profiler))
.await
.unwrap()
});
}

let mut trace = std::env::var("NEXT_TURBOPACK_TRACING")
.ok()
.filter(|v| !v.is_empty());
let (exit, exit_receiver) = ExitHandler::new_receiver();

if cfg!(feature = "tokio-console") && trace.is_none() {
// ensure `trace` is set to *something* so that the `tokio-console` feature works, otherwise
Expand Down Expand Up @@ -994,7 +1002,7 @@
}
}

/// Subscribes to lifecycle events of the compilation.

Check warning on line 1005 in crates/napi/src/next_api/project.rs

View workflow job for this annotation

GitHub Actions / rustdoc check / build

public documentation for `project_update_info_subscribe` links to private item `UpdateMessage::Start`

Check warning on line 1005 in crates/napi/src/next_api/project.rs

View workflow job for this annotation

GitHub Actions / rustdoc check / build

public documentation for `project_update_info_subscribe` links to private item `UpdateMessage::End`

Check warning on line 1005 in crates/napi/src/next_api/project.rs

View workflow job for this annotation

GitHub Actions / rustdoc check / build

public documentation for `project_update_info_subscribe` links to private item `UpdateMessage::End`

Check warning on line 1005 in crates/napi/src/next_api/project.rs

View workflow job for this annotation

GitHub Actions / rustdoc check / build

public documentation for `project_update_info_subscribe` links to private item `UpdateMessage::Start`
///
/// Emits an [UpdateMessage::Start] event when any computation starts.
/// Emits an [UpdateMessage::End] event when there was no computation for the
Expand Down
62 changes: 32 additions & 30 deletions crates/napi/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,45 +138,47 @@ pub trait MapErr<T>: Into<Result<T, anyhow::Error>> {

impl<T> MapErr<T> for Result<T, anyhow::Error> {}

/// An opaque type potentially wrapping a [`dhat::Profiler`] instance. If we
/// were not compiled with dhat support, this is an empty struct.
#[cfg(any(feature = "__internal_dhat-heap", feature = "__internal_dhat-ad-hoc"))]
#[napi]
pub fn init_heap_profiler() -> napi::Result<External<RefCell<Option<dhat::Profiler>>>> {
#[cfg(feature = "__internal_dhat-heap")]
{
println!("[dhat-heap]: Initializing heap profiler");
let _profiler = dhat::Profiler::new_heap();
return Ok(External::new(RefCell::new(Some(_profiler))));
}
#[non_exhaustive]
pub struct DhatProfilerGuard(dhat::Profiler);

#[cfg(feature = "__internal_dhat-ad-hoc")]
{
println!("[dhat-ad-hoc]: Initializing ad-hoc profiler");
let _profiler = dhat::Profiler::new_ad_hoc();
return Ok(External::new(RefCell::new(Some(_profiler))));
/// An opaque type potentially wrapping a [`dhat::Profiler`] instance. If we
/// were not compiled with dhat support, this is an empty struct.
///
/// [`dhat::Profiler`]: https://docs.rs/dhat/latest/dhat/struct.Profiler.html
#[cfg(not(any(feature = "__internal_dhat-heap", feature = "__internal_dhat-ad-hoc")))]
#[non_exhaustive]
pub struct DhatProfilerGuard;

impl DhatProfilerGuard {
/// Constructs an instance if we were compiled with dhat support.
pub fn try_init() -> Option<Self> {
#[cfg(feature = "__internal_dhat-heap")]
{
println!("[dhat-heap]: Initializing heap profiler");
Some(Self(dhat::Profiler::new_heap()))
}
#[cfg(feature = "__internal_dhat-ad-hoc")]
{
println!("[dhat-ad-hoc]: Initializing ad-hoc profiler");
Some(Self(dhat::Profiler::new_ad_hoc()))
}
#[cfg(not(any(feature = "__internal_dhat-heap", feature = "__internal_dhat-ad-hoc")))]
{
None
}
}
}

#[cfg(any(feature = "__internal_dhat-heap", feature = "__internal_dhat-ad-hoc"))]
#[napi]
pub fn teardown_heap_profiler(guard_external: External<RefCell<Option<dhat::Profiler>>>) {
let guard_cell = &*guard_external;

if let Some(guard) = guard_cell.take() {
impl Drop for DhatProfilerGuard {
fn drop(&mut self) {
#[cfg(any(feature = "__internal_dhat-heap", feature = "__internal_dhat-ad-hoc"))]
println!("[dhat]: Teardown profiler");
drop(guard);
}
}

#[cfg(not(any(feature = "__internal_dhat-heap", feature = "__internal_dhat-ad-hoc")))]
#[napi]
pub fn init_heap_profiler() -> napi::Result<External<RefCell<Option<u32>>>> {
Ok(External::new(RefCell::new(Some(0))))
}

#[cfg(not(any(feature = "__internal_dhat-heap", feature = "__internal_dhat-ad-hoc")))]
#[napi]
pub fn teardown_heap_profiler(_guard_external: External<RefCell<Option<u32>>>) {}

/// Initialize tracing subscriber to emit traces. This configures subscribers
/// for Trace Event Format <https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview>.
#[napi]
Expand Down
2 changes: 0 additions & 2 deletions packages/next/src/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ import {
loadBindings,
lockfilePatchPromise,
teardownTraceSubscriber,
teardownHeapProfiler,
createDefineEnv,
} from './swc'
import { getNamedRouteRegex } from '../shared/lib/router/utils/route-regex'
Expand Down Expand Up @@ -3796,7 +3795,6 @@ export default async function build(
// Ensure all traces are flushed before finishing the command
await flushAllTraces()
teardownTraceSubscriber()
teardownHeapProfiler()

if (traceUploadUrl && loadedConfig) {
uploadTrace({
Expand Down
5 changes: 1 addition & 4 deletions packages/next/src/build/output/store.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import createStore from 'next/dist/compiled/unistore'
import stripAnsi from 'next/dist/compiled/strip-ansi'
import { type Span, flushAllTraces, trace } from '../../trace'
import { teardownHeapProfiler, teardownTraceSubscriber } from '../swc'
import { teardownTraceSubscriber } from '../swc'
import * as Log from './log'

const MAX_LOG_SKIP_DURATION = 500 // 500ms
Expand Down Expand Up @@ -152,7 +152,6 @@ store.subscribe((state) => {
// Ensure traces are flushed after each compile in development mode
flushAllTraces()
teardownTraceSubscriber()
teardownHeapProfiler()
return
}

Expand All @@ -176,7 +175,6 @@ store.subscribe((state) => {
// Ensure traces are flushed after each compile in development mode
flushAllTraces()
teardownTraceSubscriber()
teardownHeapProfiler()
return
}

Expand Down Expand Up @@ -207,5 +205,4 @@ store.subscribe((state) => {
// Ensure traces are flushed after each compile in development mode
flushAllTraces()
teardownTraceSubscriber()
teardownHeapProfiler()
})
4 changes: 0 additions & 4 deletions packages/next/src/build/swc/generated-native.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,10 +381,6 @@ export interface NapiRewrite {
missing?: Array<NapiRouteHas>
}
export declare function getTargetTriple(): string
export declare function initHeapProfiler(): ExternalObject<RefCell>
export declare function teardownHeapProfiler(
guardExternal: ExternalObject<RefCell>
): void
/**
* Initialize tracing subscriber to emit traces. This configures subscribers
* for Trace Event Format <https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview>.
Expand Down
39 changes: 1 addition & 38 deletions packages/next/src/build/swc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ let wasmBindings: Binding
let downloadWasmPromise: any
let pendingBindings: any
let swcTraceFlushGuard: any
let swcHeapProfilerFlushGuard: any
let downloadNativeBindingsPromise: Promise<void> | undefined = undefined

export const lockfilePatchPromise: { cur?: Promise<void> } = {}
Expand Down Expand Up @@ -1225,8 +1224,6 @@ function loadNative(importPath?: string) {
getTargetTriple: bindings.getTargetTriple,
initCustomTraceSubscriber: bindings.initCustomTraceSubscriber,
teardownTraceSubscriber: bindings.teardownTraceSubscriber,
initHeapProfiler: bindings.initHeapProfiler,
teardownHeapProfiler: bindings.teardownHeapProfiler,
turbo: {
createProject: bindingToApi(customBindings ?? bindings, false),
startTurbopackTraceServer(traceFilePath) {
Expand Down Expand Up @@ -1324,30 +1321,13 @@ export function getBinaryMetadata() {
*
*/
export function initCustomTraceSubscriber(traceFileName?: string) {
if (!swcTraceFlushGuard) {
if (swcTraceFlushGuard) {
// Wasm binary doesn't support trace emission
let bindings = loadNative()
swcTraceFlushGuard = bindings.initCustomTraceSubscriber?.(traceFileName)
}
}

/**
* Initialize heap profiler, if possible.
* Note this is not available in release build of next-swc by default,
* only available by manually building next-swc with specific flags.
* Calling in release build will not do anything.
*/
export function initHeapProfiler() {
try {
if (!swcHeapProfilerFlushGuard) {
let bindings = loadNative()
swcHeapProfilerFlushGuard = bindings.initHeapProfiler?.()
}
} catch (_) {
// Suppress exceptions, this fn allows to fail to load native bindings
}
}

function once(fn: () => void): () => void {
let executed = false

Expand All @@ -1360,23 +1340,6 @@ function once(fn: () => void): () => void {
}
}

/**
* Teardown heap profiler, if possible.
*
* Same as initialization, this is not available in release build of next-swc by default
* and calling it will not do anything.
*/
export const teardownHeapProfiler = once(() => {
try {
let bindings = loadNative()
if (swcHeapProfilerFlushGuard) {
bindings.teardownHeapProfiler?.(swcHeapProfilerFlushGuard)
}
} catch (e) {
// Suppress exceptions, this fn allows to fail to load native bindings
}
})

/**
* Teardown swc's trace subscriber if there's an initialized flush guard exists.
*
Expand Down
2 changes: 0 additions & 2 deletions packages/next/src/build/swc/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ export interface Binding {

initCustomTraceSubscriber?(traceOutFilePath?: string): ExternalObject<RefCell>
teardownTraceSubscriber?(guardExternal: ExternalObject<RefCell>): void
initHeapProfiler?(): ExternalObject<RefCell>
teardownHeapProfiler?(guardExternal: ExternalObject<RefCell>): void
css: {
lightning: {
transform(transformOptions: any): Promise<any>
Expand Down
1 change: 1 addition & 0 deletions turbopack/crates/turbo-tasks/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ bench = false
default = []
tokio_tracing = ["tokio/tracing"]
hanging_detection = []
local_resolution = []

[lints]
workspace = true
Expand Down
Loading