Skip to content

Commit

Permalink
chore: add profiler for performance analysis
Browse files Browse the repository at this point in the history
Adding some tooling to analyze how long specific parts of our code take
to complete. A summary is printed at the end of unit and integ test
runs, which should help us where we can make optimizations.

Note that the syntax for wrapping/profiling individual functions is
slightly odd, simply because there isn't any native support for
function decorators in JS. Other ideas are welcome, but I think this
is fine for now.
  • Loading branch information
edvald committed Mar 19, 2020
1 parent e3060b9 commit f99b546
Show file tree
Hide file tree
Showing 21 changed files with 366 additions and 8 deletions.
2 changes: 2 additions & 0 deletions garden-service/src/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ import { getArtifactKey } from "./util/artifacts"
import { AugmentGraphResult, AugmentGraphParams } from "./types/plugin/provider/augmentGraph"
import { DeployTask } from "./tasks/deploy"
import { BuildDependencyConfig } from "./config/module"
import { Profile } from "./util/profiling"

const maxArtifactLogLines = 5 // max number of artifacts to list in console after task+test runs

Expand All @@ -120,6 +121,7 @@ export interface DeployServicesParams {
* Each plugin and module action has a corresponding method on this class (aside from configureProvider, which
* is handled especially elsewhere).
*/
@Profile()
export class ActionRouter implements TypeGuard {
private readonly actionHandlers: WrappedPluginActionMap
private readonly moduleActionHandlers: WrappedModuleActionMap
Expand Down
3 changes: 2 additions & 1 deletion garden-service/src/build-dir.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { ConfigGraph } from "./config-graph"
import { exec } from "./util/util"
import { LogLevel } from "./logger/log-node"
import { deline } from "./util/string"
import { Profile } from "./util/profiling"

const minRsyncVersion = "3.1.0"
const versionRegex = /rsync version ([\d\.]+) /
Expand All @@ -39,7 +40,7 @@ const versionDetectFailure = new RuntimeError(
)

// Lazily construct a directory of modules inside which all build steps are performed.

@Profile()
export class BuildDir {
constructor(private projectRoot: string, public buildDirPath: string, public buildMetadataDirPath: string) {}

Expand Down
2 changes: 2 additions & 0 deletions garden-service/src/garden.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import { loadPlugins, getDependencyOrder, getModuleTypes } from "./plugins"
import { deline, naturalList } from "./util/string"
import { ensureConnected } from "./db/connection"
import { DependencyValidationGraph } from "./util/validate-dependencies"
import { Profile } from "./util/profiling"

export interface ActionHandlerMap<T extends keyof PluginActionHandlers> {
[actionName: string]: PluginActionHandlers[T]
Expand Down Expand Up @@ -115,6 +116,7 @@ export interface GardenParams {
workingCopyId: string
}

@Profile()
export class Garden {
public readonly log: LogEntry
private loadedPlugins: GardenPlugin[]
Expand Down
5 changes: 3 additions & 2 deletions garden-service/src/resolve-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ import { deline } from "./util/string"
import { getModuleKey } from "./types/module"
import { getModuleTypeBases } from "./plugins"
import { ModuleConfig, moduleConfigSchema } from "./config/module"
import { profileAsync } from "./util/profiling"

export interface ModuleConfigResolveOpts extends ContextResolveOpts {
configContext?: ModuleConfigContext
}

export async function resolveModuleConfig(
export const resolveModuleConfig = profileAsync(async function $resolveModuleConfig(
garden: Garden,
config: ModuleConfig,
opts: ModuleConfigResolveOpts
Expand Down Expand Up @@ -159,4 +160,4 @@ export async function resolveModuleConfig(
}

return config
}
})
2 changes: 2 additions & 0 deletions garden-service/src/task-graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { dedent } from "./util/string"
import { defer, relationshipClasses, uuidv4 } from "./util/util"
import { renderError } from "./logger/renderers"
import { DependencyValidationGraph } from "./util/validate-dependencies"
import { Profile } from "./util/profiling"

class TaskGraphError extends GardenBaseError {
type = "task-graph"
Expand Down Expand Up @@ -55,6 +56,7 @@ export interface ProcessTasksOpts {
unlimitedConcurrency?: boolean
}

@Profile()
export class TaskGraph {
private roots: TaskNodeMap
private index: TaskNodeMap
Expand Down
2 changes: 2 additions & 0 deletions garden-service/src/tasks/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { pickBy, mapValues, mapKeys } from "lodash"
import { ServiceStatus } from "../types/service"
import { RunTaskResult } from "../types/plugin/task/runTask"
import { splitLast } from "../util/util"
import { Profile } from "../util/profiling"

export type TaskType =
| "build"
Expand Down Expand Up @@ -42,6 +43,7 @@ export interface TaskParams {
version: ModuleVersion
}

@Profile()
export abstract class BaseTask {
abstract type: TaskType
garden: Garden
Expand Down
2 changes: 2 additions & 0 deletions garden-service/src/tasks/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { Garden } from "../garden"
import { LogEntry } from "../logger/log-entry"
import { StageBuildTask } from "./stage-build"
import { flatten } from "lodash"
import { Profile } from "../util/profiling"

export interface BuildTaskParams {
garden: Garden
Expand All @@ -23,6 +24,7 @@ export interface BuildTaskParams {
force: boolean
}

@Profile()
export class BuildTask extends BaseTask {
type: TaskType = "build"

Expand Down
2 changes: 2 additions & 0 deletions garden-service/src/tasks/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { TaskResults } from "../task-graph"
import { prepareRuntimeContext } from "../runtime-context"
import { GetServiceStatusTask } from "./get-service-status"
import { GetTaskResultTask } from "./get-task-result"
import { Profile } from "../util/profiling"

export interface DeployTaskParams {
garden: Garden
Expand All @@ -33,6 +34,7 @@ export interface DeployTaskParams {
hotReloadServiceNames?: string[]
}

@Profile()
export class DeployTask extends BaseTask {
type: TaskType = "deploy"

Expand Down
2 changes: 2 additions & 0 deletions garden-service/src/tasks/get-service-status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { getTaskVersion } from "./task"
import Bluebird from "bluebird"
import { GetTaskResultTask } from "./get-task-result"
import chalk from "chalk"
import { Profile } from "../util/profiling"

export interface GetServiceStatusTaskParams {
garden: Garden
Expand All @@ -28,6 +29,7 @@ export interface GetServiceStatusTaskParams {
hotReloadServiceNames?: string[]
}

@Profile()
export class GetServiceStatusTask extends BaseTask {
type: TaskType = "get-service-status"

Expand Down
2 changes: 2 additions & 0 deletions garden-service/src/tasks/get-task-result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { Garden } from "../garden"
import { Task } from "../types/task"
import { RunTaskResult } from "../types/plugin/task/runTask"
import { ModuleVersion } from "../vcs/vcs"
import { Profile } from "../util/profiling"

export interface GetTaskResultTaskParams {
force: boolean
Expand All @@ -22,6 +23,7 @@ export interface GetTaskResultTaskParams {
version: ModuleVersion
}

@Profile()
export class GetTaskResultTask extends BaseTask {
type: TaskType = "get-task-result"

Expand Down
2 changes: 2 additions & 0 deletions garden-service/src/tasks/hot-reload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { BaseTask, TaskType } from "./base"
import { Service } from "../types/service"
import { Garden } from "../garden"
import { ConfigGraph } from "../config-graph"
import { Profile } from "../util/profiling"

interface Params {
force: boolean
Expand All @@ -22,6 +23,7 @@ interface Params {
service: Service
}

@Profile()
export class HotReloadTask extends BaseTask {
type: TaskType = "hot-reload"

Expand Down
2 changes: 2 additions & 0 deletions garden-service/src/tasks/resolve-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { validateWithPath } from "../config/validation"
import Bluebird from "bluebird"
import { defaultEnvironmentStatus } from "../types/plugin/provider/getEnvironmentStatus"
import { getPluginBases, getPluginBaseNames } from "../plugins"
import { Profile } from "../util/profiling"

interface Params extends TaskParams {
plugin: GardenPlugin
Expand All @@ -31,6 +32,7 @@ interface Params extends TaskParams {
/**
* Resolves the configuration for the specified provider.
*/
@Profile()
export class ResolveProviderTask extends BaseTask {
type: TaskType = "resolve-provider"

Expand Down
2 changes: 2 additions & 0 deletions garden-service/src/tasks/stage-build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { BuildResult } from "../types/plugin/module/build"
import { BaseTask, TaskType } from "../tasks/base"
import { Garden } from "../garden"
import { LogEntry } from "../logger/log-entry"
import { Profile } from "../util/profiling"

export interface StageBuildTaskParams {
garden: Garden
Expand All @@ -23,6 +24,7 @@ export interface StageBuildTaskParams {
dependencies?: BaseTask[]
}

@Profile()
export class StageBuildTask extends BaseTask {
type: TaskType = "stage-build"

Expand Down
2 changes: 2 additions & 0 deletions garden-service/src/tasks/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { BuildTask } from "./build"
import { RunTaskResult } from "../types/plugin/task/runTask"
import { TaskResults } from "../task-graph"
import { GetTaskResultTask } from "./get-task-result"
import { Profile } from "../util/profiling"

export interface TaskTaskParams {
garden: Garden
Expand All @@ -36,6 +37,7 @@ class RunTaskError extends Error {
}
}

@Profile()
export class TaskTask extends BaseTask {
// ... to be renamed soon.
type: TaskType = "task"
Expand Down
2 changes: 2 additions & 0 deletions garden-service/src/tasks/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { makeTestTaskName } from "./helpers"
import { BuildTask } from "./build"
import { TaskTask } from "./task"
import { TaskResults } from "../task-graph"
import { Profile } from "../util/profiling"

class TestError extends Error {
toString() {
Expand All @@ -43,6 +44,7 @@ export interface TestTaskParams {
hotReloadServiceNames?: string[]
}

@Profile()
export class TestTask extends BaseTask {
type: TaskType = "test"

Expand Down
5 changes: 3 additions & 2 deletions garden-service/src/template-string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { GardenBaseError, ConfigurationError } from "./exceptions"
import { ConfigContext, ContextResolveOpts, ScanContext, ContextResolveOutput } from "./config/config-context"
import { uniq, isPlainObject, isNumber } from "lodash"
import { Primitive, isPrimitive } from "./config/common"
import { profileAsync } from "./util/profiling"

export type StringOrStringPromise = Promise<string> | string

Expand Down Expand Up @@ -119,7 +120,7 @@ export async function resolveTemplateString(
/**
* Recursively parses and resolves all templated strings in the given object.
*/
export async function resolveTemplateStrings<T extends object>(
export const resolveTemplateStrings = profileAsync(async function $resolveTemplateStrings<T extends object>(
obj: T,
context: ConfigContext,
opts: ContextResolveOpts = {}
Expand All @@ -130,7 +131,7 @@ export async function resolveTemplateStrings<T extends object>(
// need to iterate sequentially to catch potential circular dependencies
{ concurrency: 1 }
)
}
})

/**
* Scans for all template strings in the given object and lists the referenced keys.
Expand Down
Loading

0 comments on commit f99b546

Please sign in to comment.