Skip to content

Execution Performance Dashboard

Execution dashboard overview

Overview

The Execution Performance Dashboard provides comprehensive visualization capabilities for monitoring duration and outcome statistics across various execution types in the continuous delivery pipeline. Each dashboard type includes:

Overview Section - High-level metrics at a glance:

  • Total Duration - Aggregate time spent across all executions
  • Average Runtime - Mean execution time
  • Average Queue Time - Mean time waiting to start (when applicable)
  • Failure Rate - Percentage of failed executions (fail, failure, error) with color-coded thresholds

Time Series Visualizations:

  • Total Duration per Day - Daily aggregated execution time
  • Total Number of Run per Day - Execution counts by outcome (success, fail, error, skip, cancelled)

Execution Table - Detailed per-entity analysis showing:

  • Name - Pipeline/task/test identifier
  • History - Sparkline visualization of recent execution outcomes
  • Last Outcome - Most recent execution status
  • Last Duration - Most recent execution time
  • Last Queue - Most recent queue time
  • P80 Duration - 80th percentile execution time
  • Total Runs - Count of executions in selected time range
  • Passed - Count of executions with outcome pass/success
  • Failed - Count of executions with outcome fail/failure/error
  • Skipped - Count of executions with outcome skip/skipped

Execution table detail

Dashboard Types

The execution dashboard generator creates dashboards for multiple execution types:

  • Pipeline executions - CI/CD pipeline runs
  • Task executions - Individual task runs
  • Test case runs - Individual test executions
  • Test suite runs - Test suite executions

Implementation Details

Overview Stat Panels

The overview section uses aggregation queries to calculate key metrics. Example query for average runtime:

sql
SELECT
  COALESCE(AVG(extract('epoch' from (finished_at - started_at))), 0) AS avg_runtime
FROM cdviz.pipelinerun
WHERE
  ($__timeFilter(queued_at) OR $__timeFilter(finished_at))
  AND last_payload -> 'subject' -> 'content' ->> 'pipelineName' = ANY(ARRAY[${selected_value:sqlstring}]::text[])
  AND finished_at IS NOT NULL

Time Series Queries

Daily aggregations use TimescaleDB's time_bucket function for efficient grouping:

sql
SELECT
  time_bucket('1 day', finished_at) AS time,
  SUM(extract('epoch' from (finished_at - started_at))) AS total_duration
FROM cdviz.pipelinerun
WHERE
  ($__timeFilter(queued_at) OR $__timeFilter(finished_at))
  AND last_payload -> 'subject' -> 'content' ->> 'pipelineName' = ANY(ARRAY[${selected_value:sqlstring}]::text[])
  AND finished_at IS NOT NULL
GROUP BY time
ORDER BY time

Execution Table Query

The table panel uses the custom cdviz-executiontable-panel plugin with a complex query that:

  • Aggregates execution history per entity name
  • Creates arrays of historical data for sparkline visualization
  • Calculates P80 duration and total run counts
  • Aggregates outcome counts (passed, failed, skipped) across all runs
  • Includes last execution details (outcome, duration, queue time)
sql
WITH
  execution_history AS (
    SELECT
      last_payload -> 'subject' -> 'content' ->> 'pipelineName' AS name,
      subject_id,
      outcome,
      extract('epoch' from (finished_at - started_at)) AS run_duration,
      extract('epoch' from (started_at - queued_at)) AS queue_duration,
      last_payload -> 'subject' -> 'content' ->> 'url' AS url,
      started_at,
      finished_at,
      queued_at,
      row_number() OVER (PARTITION BY last_payload -> 'subject' -> 'content' ->> 'pipelineName' ORDER BY finished_at DESC) AS rn
    FROM cdviz.pipelinerun
    WHERE
      ($__timeFilter(queued_at) OR $__timeFilter(finished_at))
      AND last_payload -> 'subject' -> 'content' ->> 'pipelineName' = ANY(ARRAY[${selected_value:sqlstring}]::text[])
      AND finished_at IS NOT NULL
  ),

  aggregated_stats AS (
    SELECT
      name,
      COALESCE(PERCENTILE_CONT(0.80) WITHIN GROUP (ORDER BY run_duration), 0) AS p80_duration,
      COUNT(*) AS total_runs
    FROM execution_history
    GROUP BY name
  ),

  history_arrays AS (
    SELECT
      name,
      COALESCE(array_agg(run_duration ORDER BY finished_at ASC) FILTER (WHERE rn <= 20), ARRAY[]::numeric[]) AS run_duration_history,
      COALESCE(array_agg(queue_duration ORDER BY finished_at ASC) FILTER (WHERE rn <= 20), ARRAY[]::numeric[]) AS queue_duration_history,
      COALESCE(array_agg(outcome ORDER BY finished_at ASC) FILTER (WHERE rn <= 20), ARRAY[]::text[]) AS outcome_history,
      COALESCE(array_agg(subject_id ORDER BY finished_at ASC) FILTER (WHERE rn <= 20), ARRAY[]::text[]) AS subject_id_history,
      COALESCE(array_agg(url ORDER BY finished_at ASC) FILTER (WHERE rn <= 20), ARRAY[]::text[]) AS url_history
    FROM execution_history
    WHERE rn <= 20
    GROUP BY name
  ),

  -- Aggregate outcome counts across all runs per name
  outcome_summary AS (
    SELECT
      name,
      COUNT(*) FILTER (WHERE outcome IN ('pass', 'success')) AS passed,
      COUNT(*) FILTER (WHERE outcome IN ('fail', 'failure', 'error')) AS failed,
      COUNT(*) FILTER (WHERE outcome IN ('skip', 'skipped')) AS skipped
    FROM execution_history
    GROUP BY name
  )

SELECT
  s.name AS "Name",
  h.run_duration_history AS "Run History (s)",
  h.outcome_history AS "Outcome History",
  h.subject_id_history AS "Run IDs",
  h.url_history AS "URLs",
  h.queue_duration_history AS "Queue History (s)",
  s.p80_duration AS "P80 Duration (s)",
  s.total_runs AS "Total Runs",
  COALESCE(o.passed, 0) AS "Passed",
  COALESCE(o.failed, 0) AS "Failed",
  COALESCE(o.skipped, 0) AS "Skipped"
FROM aggregated_stats s
LEFT JOIN history_arrays h ON s.name = h.name
LEFT JOIN outcome_summary o ON s.name = o.name
ORDER BY s.name

Technical Considerations

Database Views

  • The SQL queries utilize materialized views defined on the cdevents_lake table (e.g., cdviz.pipelinerun, cdviz.taskrun)
  • Each view provides denormalized access to execution data with fields like started_at, finished_at, queued_at, outcome
  • For missing views, consider:
    • Submitting a pull request to add the view to the database schema
    • Creating custom views in your environment
    • Using SQL WITH statements in your queries as a workaround

Queue Duration

  • Some execution types do not include queued duration metrics (e.g., task runs)
  • Dashboards conditionally display "Avg Queue Time" stat panels and queue history columns based on execution type
  • Pipeline runs, test case runs, and test suite runs track queue time; task runs do not

Custom Execution Table Panel

The dashboard uses the cdviz-executiontable-panel custom Grafana plugin for displaying execution history:

  • History Visualization - Sparkline charts showing execution outcome trends
  • Interactive Tooltips - Hover over sparklines for detailed execution information including timestamps, durations, and outcomes
  • Configurable Display - Adjustable history items (default: 20), bar height, and gap settings
  • Array Data Processing - Handles PostgreSQL array columns for efficient history storage

Execution table tooltip

Dashboard Variables

  • selected_value - Multi-select variable for filtering by pipeline/task/test name
  • limit - Hidden variable controlling the number of executions displayed in the table (default: 20)
  • Time Range - Standard Grafana time picker integration with $__timeFilter() function

Coming Soon

Future enhancements to the execution dashboards include:

  • Tag-based Filtering - Filter and group executions by:
    • Environment (dev, staging, production)
    • Artifacts (application versions, container images)
    • Teams (ownership and responsibility)
    • Custom metadata tags

Source Code References