diff --git a/.github/workflows/plinth-plugin-benchmark.yml b/.github/workflows/plinth-plugin-benchmark.yml
new file mode 100644
index 00000000000..40c875db1e9
--- /dev/null
+++ b/.github/workflows/plinth-plugin-benchmark.yml
@@ -0,0 +1,45 @@
+name: "ƛ Plinth Plugin Benchmark"
+
+on:
+  workflow_dispatch:
+  push:
+    branches:
+      - master
+  pull_request:
+    branches:
+      - 'release/*'
+
+permissions:
+  deployments: write
+  contents: write
+
+jobs:
+  run:
+    if: !always()
+    name: Run
+    runs-on: [self-hosted, plutus-benchmark]
+    steps:
+      - name: Checkout 
+        uses: actions/checkout@main 
+
+      - name: Run Benchmarks
+        run: nix develop --no-warn-dirty --accept-flake-config --command \
+          bash ./scripts/run-plinth-plugin-benchmarks.sh
+
+      # We need this otherwise the next step will fail with:
+      # `pre-commit` not found. Did you forget to activate your virtualenv?
+      # This is because github-action-benchmark will call git commit outside nix develop.
+      - name: Disable Git Hooks
+        run: git config core.hooksPath no-hooks
+
+      - name: Deploy Results
+        uses: benchmark-action/github-action-benchmark@v1.20.4
+        with:
+          name: Plutus Benchmarks
+          tool: 'customSmallerIsBetter'
+          output-file-path: output.json
+          github-token: ${{ secrets.GITHUB_TOKEN }}
+          auto-push: true
+          comment-on-alert: true
+          alert-comment-cc-users: '@IntersectMBO/plutus-core'
+          alert-threshold: '105%'
diff --git a/plutus-tx-plugin/src/PlutusTx/Plugin.hs b/plutus-tx-plugin/src/PlutusTx/Plugin.hs
index b3f5bb2b13a..83b6c083fce 100644
--- a/plutus-tx-plugin/src/PlutusTx/Plugin.hs
+++ b/plutus-tx-plugin/src/PlutusTx/Plugin.hs
@@ -560,18 +560,21 @@ runCompiler moduleName opts expr = do
                 (opts ^. posInlineConstants)
 
     -- GHC.Core -> Pir translation.
-    pirT <- original <$> (PIR.runDefT annMayInline $ compileExprWithDefs expr)
+    pirT <- {-# SCC "plinth-plugin-core-to-pir-step" #-}
+        original <$> (PIR.runDefT annMayInline $ compileExprWithDefs expr)
     let pirP = PIR.Program noProvenance plcVersion pirT
     when (opts ^. posDumpPir) . liftIO $
         dumpFlat (void pirP) "initial PIR program" (moduleName ++ "_initial.pir-flat")
 
     -- Pir -> (Simplified) Pir pass. We can then dump/store a more legible PIR program.
-    spirP <- flip runReaderT pirCtx $ PIR.compileToReadable pirP
+    spirP <- {-# SCC "plinth-plugin-pir-to-simp-step" #-}
+        flip runReaderT pirCtx $ PIR.compileToReadable pirP
     when (opts ^. posDumpPir) . liftIO $
         dumpFlat (void spirP) "simplified PIR program" (moduleName ++ "_simplified.pir-flat")
 
     -- (Simplified) Pir -> Plc translation.
-    plcP <- flip runReaderT pirCtx $ PIR.compileReadableToPlc spirP
+    plcP <- {-# SCC "plinth-plugin-simp-to-plc-step" #-}
+        flip runReaderT pirCtx $ PIR.compileReadableToPlc spirP
     when (opts ^. posDumpPlc) . liftIO $
         dumpFlat (void plcP) "typed PLC program" (moduleName ++ ".tplc-flat")
 
@@ -579,7 +582,8 @@ runCompiler moduleName opts expr = do
     when (opts ^. posDoTypecheck) . void $
         liftExcept $ PLC.inferTypeOfProgram plcTcConfig (plcP $> annMayInline)
 
-    uplcP <- flip runReaderT plcOpts $ PLC.compileProgram plcP
+    uplcP <- {-# SCC "plinth-plugin-plc-to-uplc-step" #-}
+        flip runReaderT plcOpts $ PLC.compileProgram plcP
     dbP <- liftExcept $ traverseOf UPLC.progTerm UPLC.deBruijnTerm uplcP
     when (opts ^. posDumpUPlc) . liftIO $
         dumpFlat
diff --git a/scripts/run-plinth-plugin-benchmarks.sh b/scripts/run-plinth-plugin-benchmarks.sh
new file mode 100755
index 00000000000..ee9f4cb6b90
--- /dev/null
+++ b/scripts/run-plinth-plugin-benchmarks.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+cabal clean 
+cabal update
+cabal build all --enable-profiling --enable-library-profiling
+