Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Calls

Introduction

In Turbo-Engine, calls to turbo task functions are central to the operation of the system. This section explains how calls work within the Turbo-Engine framework, including the concepts of unresolved and resolved Vc<T>.

Making Calls

#![allow(unused)]
fn main() {
let vc: Vc<T> = some_turbo_tasks_function();
}

When you invoke a Turbo-Tasks Function, it returns a Vc<T>, which is a pointer to the task's return value. Here's what happens during a call:

  • Immediate Return: The call returns instantly, and the task is queued for computation.
  • Unresolved Vc: The returned Vc is a so called "unresolved" Vc, meaning it points to a return value that may not yet be computed.

Resolved vs Unresolved Vcs

  • Unresolved Vc: An "unresolved" Vc points to a return value of a Task
  • Resolved Vc: A "resolved" Vc points to a cell computed by a Task.

Resolving Vcs

To compare Vc values or ensure they are ready for use, you can resolve them:

#![allow(unused)]
fn main() {
let resolved = vc.resolve().await?;
}
  • Reading: It's not mandatory to resolve Vcs before reading them. Reading Vcs will first resolve it and then read the cell value.
  • Dependency Registration: Resolving a Vc registers the current task as a dependent of the task output, ensuring that the task is recomputed if the return value changes.
  • Usage as Key: Resolving Vcs is mandatory when using them as keys of HashMap or HashSet for the cell identity.

Importance of Resolution

Resolution is crucial for the memoization process:

  • Memoization: Vcs used as arguments are identified by their pointer.
  • Automatic Resolution: Unresolved Vcs passed to turbo task functions are resolved automatically, ensuring that functions receive resolved Vcs for memoization.
    • Intermediate Task: An intermediate task is created internally to handle the resolution of arguments.

Performance Considerations

While automatic resolution is convenient, it introduces the slight overhead of the intermediate Task:

  • Manual Resolution: In performance-critical scenarios, resolving Vcs manually may be beneficial to reduce overhead.

Code Example

Here's an example of calling a turbo task function and resolving its Vc:

#![allow(unused)]
fn main() {
// Calling a turbo task function
let vc: Vc<MyType> = compute_something();

// Resolving the Vc for direct comparison or use
let resolved_vc: MyType = vc.resolve().await?;
}