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

FiberRefs perf work #3518

Merged
merged 1 commit into from
Sep 3, 2024
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
6 changes: 6 additions & 0 deletions .changeset/twelve-dingos-destroy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@effect/opentelemetry": minor
"effect": minor
---

Cache some fiber references in the runtime to optimize reading in hot-paths
35 changes: 35 additions & 0 deletions packages/effect/src/Fiber.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
* @since 2.0.0
*/
import type * as Cause from "./Cause.js"
import type { Context } from "./Context.js"
import type { DefaultServices } from "./DefaultServices.js"
import type * as Effect from "./Effect.js"
import type * as Either from "./Either.js"
import type * as Exit from "./Exit.js"
Expand All @@ -18,7 +20,10 @@ import type * as Option from "./Option.js"
import type * as order from "./Order.js"
import type { Pipeable } from "./Pipeable.js"
import type * as RuntimeFlags from "./RuntimeFlags.js"
import type { Scheduler } from "./Scheduler.js"
import type * as Scope from "./Scope.js"
import type { Supervisor } from "./Supervisor.js"
import type { AnySpan, Tracer } from "./Tracer.js"
import type * as Types from "./Types.js"

/**
Expand Down Expand Up @@ -155,6 +160,36 @@ export interface RuntimeFiber<out A, out E = never> extends Fiber<A, E>, Fiber.R
* resume immediately. Otherwise, the effect will resume when the fiber exits.
*/
unsafeInterruptAsFork(fiberId: FiberId.FiberId): void

/**
* Gets the current context
*/
get currentContext(): Context<never>

/**
* Gets the current context
*/
get currentDefaultServices(): Context<DefaultServices>

/**
* Gets the current scheduler
*/
get currentScheduler(): Scheduler

/**
* Gets the current tracer
*/
get currentTracer(): Tracer

/**
* Gets the current span
*/
get currentSpan(): AnySpan | undefined

/**
* Gets the current supervisor
*/
get currentSupervisor(): Supervisor<unknown>
}

/**
Expand Down
9 changes: 3 additions & 6 deletions packages/effect/src/internal/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ import * as DeferredOpCodes from "./opCodes/deferred.js"
import * as OpCodes from "./opCodes/effect.js"
import * as _runtimeFlags from "./runtimeFlags.js"
import { SingleShotGen } from "./singleShotGen.js"
import * as internalTracer from "./tracer.js"

// -----------------------------------------------------------------------------
// Effect
Expand Down Expand Up @@ -1684,7 +1683,7 @@ const fiberRefVariance = {

/* @internal */
export const fiberRefGet = <A>(self: FiberRef.FiberRef<A>): Effect.Effect<A> =>
fiberRefModify(self, (a) => [a, a] as const)
withFiberRuntime((fiber) => exitSucceed(fiber.getFiberRef(self)))

/* @internal */
export const fiberRefGetAndSet = dual<
Expand Down Expand Up @@ -2966,7 +2965,7 @@ const deferredInterruptJoiner = <A, E>(
// Context
// -----------------------------------------------------------------------------

const constContext = fiberRefGet(currentContext)
const constContext = withFiberRuntime((fiber) => exitSucceed(fiber.currentContext))

/* @internal */
export const context = <R>(): Effect.Effect<Context.Context<R>, never, R> => constContext as any
Expand Down Expand Up @@ -3021,9 +3020,7 @@ export const mapInputContext = dual<

/** @internal */
export const currentSpanFromFiber = <A, E>(fiber: Fiber.RuntimeFiber<A, E>): Option.Option<Tracer.Span> => {
const span = fiber.getFiberRef(currentContext).unsafeMap.get(internalTracer.spanTag.key) as
| Tracer.AnySpan
| undefined
const span = fiber.currentSpan
return span !== undefined && span._tag === "Span" ? Option.some(span) : Option.none()
}

Expand Down
19 changes: 9 additions & 10 deletions packages/effect/src/internal/defaultServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,14 @@ export const sleep = (duration: Duration.DurationInput): Effect.Effect<void> =>
return clockWith((clock) => clock.sleep(decodedDuration))
}

/** @internal */
export const defaultServicesWith = <A, E, R>(
f: (services: Context.Context<DefaultServices.DefaultServices>) => Effect.Effect<A, E, R>
) => core.withFiberRuntime<A, E, R>((fiber) => f(fiber.currentDefaultServices))

/** @internal */
export const clockWith = <A, E, R>(f: (clock: Clock.Clock) => Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
core.fiberRefGetWith(currentServices, (services) => f(Context.get(services, clock.clockTag)))
defaultServicesWith((services) => f(services.unsafeMap.get(clock.clockTag.key)))

/** @internal */
export const currentTimeMillis: Effect.Effect<number> = clockWith((clock) => clock.currentTimeMillis)
Expand Down Expand Up @@ -83,10 +88,7 @@ export const withConfigProvider = dual<
export const configProviderWith = <A, E, R>(
f: (configProvider: ConfigProvider.ConfigProvider) => Effect.Effect<A, E, R>
): Effect.Effect<A, E, R> =>
core.fiberRefGetWith(
currentServices,
(services) => f(Context.get(services, configProvider.configProviderTag))
)
defaultServicesWith((services) => f(services.unsafeMap.get(configProvider.configProviderTag.key)))

/** @internal */
export const config = <A>(config: Config.Config<A>) => configProviderWith((_) => _.load(config))
Expand All @@ -98,10 +100,7 @@ export const configOrDie = <A>(config: Config.Config<A>) => core.orDie(configPro

/** @internal */
export const randomWith = <A, E, R>(f: (random: Random.Random) => Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
core.fiberRefGetWith(
currentServices,
(services) => f(Context.get(services, random.randomTag))
)
defaultServicesWith((services) => f(services.unsafeMap.get(random.randomTag.key)))

/** @internal */
export const withRandom = dual<
Expand Down Expand Up @@ -151,7 +150,7 @@ export const choice = <Self extends Iterable<unknown>>(

/** @internal */
export const tracerWith = <A, E, R>(f: (tracer: Tracer.Tracer) => Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
core.fiberRefGetWith(currentServices, (services) => f(Context.get(services, tracer.tracerTag)))
defaultServicesWith((services) => f(services.unsafeMap.get(tracer.tracerTag.key)))

/** @internal */
export const withTracer = dual<
Expand Down
3 changes: 1 addition & 2 deletions packages/effect/src/internal/fiberRefs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ export class FiberRefsImpl implements FiberRefs.FiberRefs {
FiberRef.FiberRef<any>,
Arr.NonEmptyReadonlyArray<readonly [FiberId.Single, any]>
>
) {
}
) {}
pipe() {
return pipeArguments(this, arguments)
}
Expand Down
Loading