Skip to content

Commit

Permalink
FiberRefs perf work (#3518)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikearnaldi authored and tim-smart committed Sep 9, 2024
1 parent ce86193 commit f04640f
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 84 deletions.
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

0 comments on commit f04640f

Please sign in to comment.