You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by ha...@apache.org on 2026/08/09 12:30:51 UTC

(skywalking-banyandb) branch perf/trace-merge-skywalking-plugin created (now 3a93a0a8a)

This is an automated email from the ASF dual-hosted git repository.

hanahmily pushed a change to branch perf/trace-merge-skywalking-plugin
in repository https://gitbox.apache.org/repos/asf/skywalking-banyandb.git


      at 3a93a0a8a test(trace): load SkyWalking sampler configuration

This branch includes the following new commits:

     new 3a93a0a8a test(trace): load SkyWalking sampler configuration

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(skywalking-banyandb) 01/01: test(trace): load SkyWalking sampler configuration

Posted by ha...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

hanahmily pushed a commit to branch perf/trace-merge-skywalking-plugin
in repository https://gitbox.apache.org/repos/asf/skywalking-banyandb.git

commit 3a93a0a8ac5f2f341df3928ddfb5565bfec2d7f1
Author: Gao Hongtao <ha...@gmail.com>
AuthorDate: Sun Aug 9 12:28:36 2026 +0000

    test(trace): load SkyWalking sampler configuration
---
 banyand/cmd/trace-merge-benchmark/main.go          | 12 ++-
 banyand/internal/benchmark/tracebaseline/model.go  | 54 +++++++-------
 banyand/internal/benchmark/tracebaseline/server.go | 49 +++++++-----
 .../benchmark/tracebaseline/server_test.go         | 25 +++++++
 .../trace-pipeline-merge-performance-test.md       |  8 ++
 scripts/run-trace-merge-baseline.sh                | 86 ++++++++++++++++------
 6 files changed, 166 insertions(+), 68 deletions(-)

diff --git a/banyand/cmd/trace-merge-benchmark/main.go b/banyand/cmd/trace-merge-benchmark/main.go
index 6e2b1ed1c..b84dd6fff 100644
--- a/banyand/cmd/trace-merge-benchmark/main.go
+++ b/banyand/cmd/trace-merge-benchmark/main.go
@@ -161,6 +161,7 @@ func render(arguments []string) {
 func serve(ctx context.Context, arguments []string) {
 	flags := flag.NewFlagSet("serve", flag.ExitOnError)
 	var options tracebaseline.ServerOptions
+	var pluginConfigPath string
 	var segmentMinTimeNanos, segmentMaxTimeNanos int64
 	flags.StringVar(&options.Root, "root", "", "data-node shard root")
 	flags.StringVar(&options.SocketPath, "socket", "", "Unix control socket")
@@ -185,11 +186,20 @@ func serve(ctx context.Context, arguments []string) {
 	flags.StringVar(&options.ExecutionIdentity.StorageDevice, "storage-device", "", "data-root storage device recorded in the environment envelope")
 	flags.StringVar(&options.ExecutionIdentity.CloneMethod, "clone-method", "", "clone method recorded in the environment envelope (e.g. os.CopyFS, hardlink)")
 	flags.StringVar(&options.ExecutionIdentity.BinarySHA256, "binary-sha256", "", "measured data-node binary checksum")
-	flags.StringVar(&options.ExecutionIdentity.PluginSHA256, "plugin-sha256", "", "plugin .so checksum for retain-all pipeline mode")
+	flags.StringVar(&options.ExecutionIdentity.PluginSHA256, "plugin-sha256", "", "sampler plugin .so checksum")
+	flags.StringVar(&options.ExecutionIdentity.PluginConfigSHA256, "plugin-config-sha256", "", "sampler configuration checksum")
 	flags.StringVar(&options.PluginPath, "plugin", "", "native sampler plugin .so path")
+	flags.StringVar(&pluginConfigPath, "plugin-config", "", "sampler configuration JSON file")
 	flags.Int64Var(&segmentMinTimeNanos, "segment-min-time-nanos", 0, "inclusive minimum fixture timestamp for sampler coverage")
 	flags.Int64Var(&segmentMaxTimeNanos, "segment-max-time-nanos", 0, "inclusive maximum fixture timestamp for sampler coverage")
 	_ = flags.Parse(arguments)
+	if pluginConfigPath != "" {
+		pluginConfig, readErr := os.ReadFile(pluginConfigPath)
+		if readErr != nil {
+			fatalf("cannot read sampler configuration: %v", readErr)
+		}
+		options.PluginConfig = pluginConfig
+	}
 	if segmentMinTimeNanos != 0 || segmentMaxTimeNanos != 0 {
 		options.SegmentTimeRange = timestamp.NewInclusiveTimeRange(time.Unix(0, segmentMinTimeNanos), time.Unix(0, segmentMaxTimeNanos))
 	}
diff --git a/banyand/internal/benchmark/tracebaseline/model.go b/banyand/internal/benchmark/tracebaseline/model.go
index 473b9350b..2227af3b4 100644
--- a/banyand/internal/benchmark/tracebaseline/model.go
+++ b/banyand/internal/benchmark/tracebaseline/model.go
@@ -45,12 +45,13 @@ const (
 // when the harness does not provide them. Fields remain optional for local
 // debugging; the SAME TEST BOUNDARY gate enforces them in benchmark suites.
 type ExecutionIdentity struct {
-	ImageDigest   string `json:"imageDigest,omitempty"`
-	Filesystem    string `json:"filesystem,omitempty"`
-	StorageDevice string `json:"storageDevice,omitempty"`
-	CloneMethod   string `json:"cloneMethod,omitempty"`
-	BinarySHA256  string `json:"binarySHA256,omitempty"`
-	PluginSHA256  string `json:"pluginSHA256,omitempty"`
+	ImageDigest        string `json:"imageDigest,omitempty"`
+	Filesystem         string `json:"filesystem,omitempty"`
+	StorageDevice      string `json:"storageDevice,omitempty"`
+	CloneMethod        string `json:"cloneMethod,omitempty"`
+	BinarySHA256       string `json:"binarySHA256,omitempty"`
+	PluginSHA256       string `json:"pluginSHA256,omitempty"`
+	PluginConfigSHA256 string `json:"pluginConfigSHA256,omitempty"`
 }
 
 // PublishRequest introduces one already-renamed fixture part at its logical publication time.
@@ -109,26 +110,27 @@ type PhaseResult struct {
 // and StorageDevice fall back to live mount detection when omitted. SAME TEST
 // BOUNDARY enforces complete and comparable identities for managed suites.
 type Environment struct {
-	Filesystem       string `json:"filesystem,omitempty"`
-	GoVersion        string `json:"goVersion"`
-	Kernel           string `json:"kernel"`
-	CgroupVersion    string `json:"cgroupVersion"`
-	CPUSet           string `json:"cpuSet"`
-	MemoryMax        string `json:"memoryMax"`
-	MemorySwapMax    string `json:"memorySwapMax"`
-	PIDsMax          string `json:"pidsMax"`
-	PluginSHA256     string `json:"pluginSHA256,omitempty"`
-	BinarySHA256     string `json:"binarySHA256,omitempty"`
-	ControllerCgroup string `json:"controllerCgroup"`
-	CloneMethod      string `json:"cloneMethod,omitempty"`
-	StorageDevice    string `json:"storageDevice,omitempty"`
-	DataNodeCgroup   string `json:"dataNodeCgroup"`
-	ImageDigest      string `json:"imageDigest,omitempty"`
-	Commit           string `json:"commit"`
-	ControllerPID    int    `json:"controllerPID"`
-	DataNodePID      int    `json:"dataNodePID"`
-	GOMAXPROCS       int    `json:"gomaxprocs"`
-	OneShardOnly     bool   `json:"oneShardOnly"`
+	Filesystem         string `json:"filesystem,omitempty"`
+	GoVersion          string `json:"goVersion"`
+	Kernel             string `json:"kernel"`
+	CgroupVersion      string `json:"cgroupVersion"`
+	CPUSet             string `json:"cpuSet"`
+	MemoryMax          string `json:"memoryMax"`
+	MemorySwapMax      string `json:"memorySwapMax"`
+	PIDsMax            string `json:"pidsMax"`
+	PluginSHA256       string `json:"pluginSHA256,omitempty"`
+	PluginConfigSHA256 string `json:"pluginConfigSHA256,omitempty"`
+	BinarySHA256       string `json:"binarySHA256,omitempty"`
+	ControllerCgroup   string `json:"controllerCgroup"`
+	CloneMethod        string `json:"cloneMethod,omitempty"`
+	StorageDevice      string `json:"storageDevice,omitempty"`
+	DataNodeCgroup     string `json:"dataNodeCgroup"`
+	ImageDigest        string `json:"imageDigest,omitempty"`
+	Commit             string `json:"commit"`
+	ControllerPID      int    `json:"controllerPID"`
+	DataNodePID        int    `json:"dataNodePID"`
+	GOMAXPROCS         int    `json:"gomaxprocs"`
+	OneShardOnly       bool   `json:"oneShardOnly"`
 }
 
 // RunReport is the machine-readable result of one fresh data-node process.
diff --git a/banyand/internal/benchmark/tracebaseline/server.go b/banyand/internal/benchmark/tracebaseline/server.go
index c9e908d64..290503f3f 100644
--- a/banyand/internal/benchmark/tracebaseline/server.go
+++ b/banyand/internal/benchmark/tracebaseline/server.go
@@ -18,6 +18,7 @@ package tracebaseline
 import (
 	"bufio"
 	"context"
+	"crypto/sha256"
 	"encoding/json"
 	"errors"
 	"fmt"
@@ -44,25 +45,26 @@ import (
 //
 // ExecutionIdentity holds the harness-recorded fields forwarded by the
 // wrapper; the readiness gate (SAME TEST BOUNDARY) enforces the harness
-// requirement that ImageDigest, CloneMethod, BinarySHA256, and (for
-// retain-all pipeline runs) PluginSHA256 are populated. The server itself
+// requirement that ImageDigest, CloneMethod, BinarySHA256, and the applicable
+// plugin and plugin-configuration checksums are populated. The server itself
 // tolerates empty values so out-of-harness invocations (e.g. local debug)
 // remain runnable; the readiness gate, not the server, is the enforcement
 // boundary.
 type ServerOptions struct {
 	ExpectedLedger    map[string]string
 	ExecutionIdentity ExecutionIdentity
-	ScheduleSHA256    string
-	ProfileDir        string
-	Commit            string
+	SegmentTimeRange  timestamp.TimeRange
+	Mode              string
+	SocketPath        string
 	FixtureSHA256     string
 	Root              string
 	RunID             string
-	Mode              string
+	ProfileDir        string
 	OutputPath        string
-	SocketPath        string
+	Commit            string
 	PluginPath        string
-	SegmentTimeRange  timestamp.TimeRange
+	ScheduleSHA256    string
+	PluginConfig      []byte
 	Acceleration      float64
 	ExpectedRows      uint64
 	MaxInputPartID    uint64
@@ -92,6 +94,9 @@ func Serve(ctx context.Context, options ServerOptions) (serveResultErr error) {
 	if options.RunFinalize && options.PluginPath == "" {
 		return fmt.Errorf("finalize requires a sampler plugin")
 	}
+	if len(options.PluginConfig) > 0 && options.PluginPath == "" {
+		return fmt.Errorf("sampler config requires a sampler plugin")
+	}
 	if mkdirErr := os.MkdirAll(options.ProfileDir, 0o755); mkdirErr != nil {
 		return fmt.Errorf("cannot create profile directory: %w", mkdirErr)
 	}
@@ -170,7 +175,12 @@ func openServerSampler(options ServerOptions) (sdk.Sampler, error) {
 		!options.SegmentTimeRange.Start.Before(options.SegmentTimeRange.End) {
 		return nil, fmt.Errorf("valid segment time range is required when the merge benchmark plugin is enabled")
 	}
-	sampler, openErr := sdk.OpenSampler(options.PluginPath, "NewSampler", nil)
+	pluginConfigSHA256 := fmt.Sprintf("%x", sha256.Sum256(options.PluginConfig))
+	if options.ExecutionIdentity.PluginConfigSHA256 != "" && options.ExecutionIdentity.PluginConfigSHA256 != pluginConfigSHA256 {
+		return nil, fmt.Errorf("merge benchmark sampler config checksum %s does not match expected %s",
+			pluginConfigSHA256, options.ExecutionIdentity.PluginConfigSHA256)
+	}
+	sampler, openErr := sdk.OpenSampler(options.PluginPath, "NewSampler", options.PluginConfig)
 	if openErr != nil {
 		return nil, fmt.Errorf("cannot load merge benchmark sampler: %w", openErr)
 	}
@@ -550,16 +560,17 @@ func readEnvironment(commit string, options ServerOptions) Environment {
 		Commit: commit, GoVersion: runtime.Version(), Kernel: strings.TrimSpace(string(kernelData)), CgroupVersion: "2",
 		CPUSet: readTextFile("/sys/fs/cgroup/cpuset.cpus.effective"), MemoryMax: readTextFile("/sys/fs/cgroup/memory.max"),
 		MemorySwapMax: readTextFile("/sys/fs/cgroup/memory.swap.max"), PIDsMax: readTextFile("/sys/fs/cgroup/pids.max"),
-		GOMAXPROCS:     runtime.GOMAXPROCS(0),
-		OneShardOnly:   true,
-		DataNodePID:    os.Getpid(),
-		DataNodeCgroup: hostname + ":" + identity.Cgroup,
-		Filesystem:     filesystem,
-		StorageDevice:  storageDevice,
-		ImageDigest:    options.ExecutionIdentity.ImageDigest,
-		CloneMethod:    options.ExecutionIdentity.CloneMethod,
-		BinarySHA256:   options.ExecutionIdentity.BinarySHA256,
-		PluginSHA256:   options.ExecutionIdentity.PluginSHA256,
+		GOMAXPROCS:         runtime.GOMAXPROCS(0),
+		OneShardOnly:       true,
+		DataNodePID:        os.Getpid(),
+		DataNodeCgroup:     hostname + ":" + identity.Cgroup,
+		Filesystem:         filesystem,
+		StorageDevice:      storageDevice,
+		ImageDigest:        options.ExecutionIdentity.ImageDigest,
+		CloneMethod:        options.ExecutionIdentity.CloneMethod,
+		BinarySHA256:       options.ExecutionIdentity.BinarySHA256,
+		PluginSHA256:       options.ExecutionIdentity.PluginSHA256,
+		PluginConfigSHA256: options.ExecutionIdentity.PluginConfigSHA256,
 	}
 }
 
diff --git a/banyand/internal/benchmark/tracebaseline/server_test.go b/banyand/internal/benchmark/tracebaseline/server_test.go
index d93e3a13a..dd6530005 100644
--- a/banyand/internal/benchmark/tracebaseline/server_test.go
+++ b/banyand/internal/benchmark/tracebaseline/server_test.go
@@ -19,10 +19,12 @@ import (
 	"context"
 	"path/filepath"
 	"testing"
+	"time"
 
 	"github.com/stretchr/testify/require"
 
 	storagetrace "github.com/apache/skywalking-banyandb/banyand/trace"
+	"github.com/apache/skywalking-banyandb/pkg/timestamp"
 )
 
 func TestServeRejectsFinalizeWithoutSampler(t *testing.T) {
@@ -34,6 +36,29 @@ func TestServeRejectsFinalizeWithoutSampler(t *testing.T) {
 	require.ErrorContains(t, serveErr, "finalize requires a sampler plugin")
 }
 
+func TestServeRejectsSamplerConfigWithoutPlugin(t *testing.T) {
+	root := t.TempDir()
+	serveErr := Serve(context.Background(), ServerOptions{
+		Root: root, SocketPath: filepath.Join(root, "control.sock"), OutputPath: filepath.Join(root, "report.json"),
+		ProfileDir: filepath.Join(root, "profiles"), PluginConfig: []byte(`{"healthySampleRate":"0.1"}`),
+	})
+	require.ErrorContains(t, serveErr, "sampler config requires a sampler plugin")
+}
+
+func TestServeRejectsUnexpectedSamplerConfigChecksum(t *testing.T) {
+	root := t.TempDir()
+	serveErr := Serve(context.Background(), ServerOptions{
+		Root: root, SocketPath: filepath.Join(root, "control.sock"), OutputPath: filepath.Join(root, "report.json"),
+		ProfileDir: filepath.Join(root, "profiles"), PluginPath: filepath.Join(root, "sampler.so"),
+		PluginConfig: []byte(`{"healthySampleRate":"0.1"}`),
+		ExecutionIdentity: ExecutionIdentity{
+			PluginConfigSHA256: "unexpected",
+		},
+		SegmentTimeRange: timestamp.NewInclusiveTimeRange(time.Unix(0, 1), time.Unix(0, 2)),
+	})
+	require.ErrorContains(t, serveErr, "sampler config checksum")
+}
+
 func TestPhaseProfilerStopsAndClosesIdempotently(t *testing.T) {
 	profilePath := filepath.Join(t.TempDir(), "cpu.pprof")
 	profiler, startErr := startPhaseProfiler(profilePath)
diff --git a/docs/design/trace-pipeline-merge-performance-test.md b/docs/design/trace-pipeline-merge-performance-test.md
index 2fe40318b..bd039f2ca 100644
--- a/docs/design/trace-pipeline-merge-performance-test.md
+++ b/docs/design/trace-pipeline-merge-performance-test.md
@@ -903,6 +903,14 @@ After framework and plugin-unit optimization, run the actual SkyWalking plugins
 projections and sampling rules. Dropped output reduces write I/O, so compare this result using retained bytes and work
 normalized by input traces, spans, and bytes rather than interpreting a lower elapsed time as lower framework overhead.
 
+The full-loop harness selects this variant with `FULL_PIPELINE=skywalking`. It builds the production
+`sw-trace-sampler`, loads its JSON configuration from `SKYWALKING_PLUGIN_CONFIG`, and passes those exact bytes to the
+native plugin constructor. The default harness configuration is the calibrated 500 ms duration threshold, error
+retention, and 10% deterministic healthy sampling policy. Every report records independent SHA-256 identities for the
+plugin binary and configuration so a result cannot silently mix policies. Custom configuration files are allowed, but
+they must remain inside the read-only repository mount and their observed verdict ratios must be reported as observed
+SkyWalking ratios rather than as the controlled 35% DeterministicDrop case.
+
 ## Iterative Execution Phases
 
 ### Phase 1: Protect the Ordinary Merge Path
diff --git a/scripts/run-trace-merge-baseline.sh b/scripts/run-trace-merge-baseline.sh
index 23d4abbd5..90a20961d 100755
--- a/scripts/run-trace-merge-baseline.sh
+++ b/scripts/run-trace-merge-baseline.sh
@@ -32,6 +32,10 @@ CONTROLLED_REPETITIONS=${CONTROLLED_REPETITIONS:-10}
 CONTROLLED_SEED=${CONTROLLED_SEED:-"$OUTPUT/controlled-seed"}
 DEFAULT_CONTROLLED_PLUGIN="$ROOT/.scratch/trace-pipeline-merge-performance/plugins/alwayskeepsampler.so"
 CONTROLLED_PLUGIN=${CONTROLLED_PLUGIN:-"$DEFAULT_CONTROLLED_PLUGIN"}
+DEFAULT_SKYWALKING_PLUGIN="$ROOT/.scratch/trace-pipeline-merge-performance/plugins/sw-trace-sampler.so"
+SKYWALKING_PLUGIN=${SKYWALKING_PLUGIN:-"$DEFAULT_SKYWALKING_PLUGIN"}
+DEFAULT_SKYWALKING_PLUGIN_CONFIG="$ROOT/.scratch/trace-pipeline-merge-performance/plugins/sw-trace-sampler.json"
+SKYWALKING_PLUGIN_CONFIG=${SKYWALKING_PLUGIN_CONFIG:-"$DEFAULT_SKYWALKING_PLUGIN_CONFIG"}
 FULL_PIPELINE=${FULL_PIPELINE:-disabled}
 RUN_FINALIZE=${RUN_FINALIZE:-0}
 BIN="$ROOT/.scratch/trace-pipeline-merge-performance/bin/trace-merge-benchmark"
@@ -69,11 +73,51 @@ SEGMENT_MIN_TIME_NANOS=${META[9]}
 SEGMENT_MAX_TIME_NANOS=${META[10]}
 
 mkdir -p "$OUTPUT" "$(dirname "$BIN")"
+if [[ "$FULL_PIPELINE" != "disabled" && "$FULL_PIPELINE" != "retain-all" && "$FULL_PIPELINE" != "skywalking" ]]; then
+  echo "FULL_PIPELINE must be disabled, retain-all, or skywalking" >&2
+  exit 1
+fi
+if [[ "$RUN_FINALIZE" != "0" && "$RUN_FINALIZE" != "1" ]]; then
+  echo "RUN_FINALIZE must be 0 or 1" >&2
+  exit 1
+fi
+if [[ "$RUN_FINALIZE" == "1" && "$FULL_PIPELINE" == "disabled" ]]; then
+  echo "RUN_FINALIZE=1 requires a plugin-enabled FULL_PIPELINE" >&2
+  exit 1
+fi
 go build -o "$BIN" "$ROOT/banyand/cmd/trace-merge-benchmark"
 if [[ ("$CONTROLLED_ALTERNATING" == "1" || "$FULL_PIPELINE" == "retain-all") && "$CONTROLLED_PLUGIN" == "$DEFAULT_CONTROLLED_PLUGIN" ]]; then
   mkdir -p "$(dirname "$CONTROLLED_PLUGIN")"
   go build -buildmode=plugin -o "$CONTROLLED_PLUGIN" "$ROOT/test/plugins/_alwayskeepsampler"
 fi
+if [[ "$FULL_PIPELINE" == "skywalking" && "$SKYWALKING_PLUGIN" == "$DEFAULT_SKYWALKING_PLUGIN" ]]; then
+  mkdir -p "$(dirname "$SKYWALKING_PLUGIN")"
+  go build -buildmode=plugin -o "$SKYWALKING_PLUGIN" "$ROOT/plugins/skywalking/sw-trace-sampler"
+fi
+if [[ "$FULL_PIPELINE" == "skywalking" && "$SKYWALKING_PLUGIN_CONFIG" == "$DEFAULT_SKYWALKING_PLUGIN_CONFIG" ]]; then
+  mkdir -p "$(dirname "$SKYWALKING_PLUGIN_CONFIG")"
+  printf '%s' '{"durationThresholdMs":500,"keepErrors":true,"healthySampleRate":"0.1"}' >"$SKYWALKING_PLUGIN_CONFIG"
+fi
+if [[ "$FULL_PIPELINE" == "retain-all" && ! -f "$CONTROLLED_PLUGIN" ]]; then
+  echo "FULL_PIPELINE=retain-all requires sampler plugin $CONTROLLED_PLUGIN" >&2
+  exit 1
+fi
+if [[ "$FULL_PIPELINE" == "skywalking" && ! -f "$SKYWALKING_PLUGIN" ]]; then
+  echo "FULL_PIPELINE=skywalking requires sampler plugin $SKYWALKING_PLUGIN" >&2
+  exit 1
+fi
+if [[ "$FULL_PIPELINE" == "skywalking" && ! -f "$SKYWALKING_PLUGIN_CONFIG" ]]; then
+  echo "FULL_PIPELINE=skywalking requires sampler config $SKYWALKING_PLUGIN_CONFIG" >&2
+  exit 1
+fi
+if [[ "$FULL_PIPELINE" == "retain-all" && "$CONTROLLED_PLUGIN" != "$ROOT/"* ]]; then
+  echo "CONTROLLED_PLUGIN must be inside $ROOT so the data-node container can mount it" >&2
+  exit 1
+fi
+if [[ "$FULL_PIPELINE" == "skywalking" && ("$SKYWALKING_PLUGIN" != "$ROOT/"* || "$SKYWALKING_PLUGIN_CONFIG" != "$ROOT/"*) ]]; then
+  echo "SKYWALKING_PLUGIN and SKYWALKING_PLUGIN_CONFIG must be inside $ROOT so the data-node container can mount them" >&2
+  exit 1
+fi
 BINARY_SHA=$(sha256sum "$BIN" | awk '{print $1}')
 git -C "$ROOT" diff --binary HEAD -- . ':(exclude).scratch' >"$OUTPUT/source.patch"
 SOURCE_PATCH_SHA=$(sha256sum "$OUTPUT/source.patch" | awk '{print $1}')
@@ -93,9 +137,20 @@ DATA_FILESYSTEM=$(df -T "$OUTPUT" 2>/dev/null | awk 'NR==2 {print $2}' || true)
 DATA_STORAGE_DEVICE=$(df --output=source "$OUTPUT" 2>/dev/null | tail -n1 | tr -d ' ' || true)
 DATA_CLONE_METHOD="cp -a"
 if [[ -n "$CONTROLLED_PLUGIN" && -f "$CONTROLLED_PLUGIN" ]]; then
-  PLUGIN_SHA=$(sha256sum "$CONTROLLED_PLUGIN" | awk '{print $1}')
+  CONTROLLED_PLUGIN_SHA=$(sha256sum "$CONTROLLED_PLUGIN" | awk '{print $1}')
 else
-  PLUGIN_SHA=""
+  CONTROLLED_PLUGIN_SHA=""
+fi
+FULL_PLUGIN=""
+FULL_PLUGIN_SHA=""
+FULL_PLUGIN_CONFIG_SHA=""
+if [[ "$FULL_PIPELINE" == "retain-all" ]]; then
+  FULL_PLUGIN=$CONTROLLED_PLUGIN
+  FULL_PLUGIN_SHA=$CONTROLLED_PLUGIN_SHA
+elif [[ "$FULL_PIPELINE" == "skywalking" ]]; then
+  FULL_PLUGIN=$SKYWALKING_PLUGIN
+  FULL_PLUGIN_SHA=$(sha256sum "$SKYWALKING_PLUGIN" | awk '{print $1}')
+  FULL_PLUGIN_CONFIG_SHA=$(sha256sum "$SKYWALKING_PLUGIN_CONFIG" | awk '{print $1}')
 fi
 
 active_container=""
@@ -122,9 +177,13 @@ run_once() {
   if [[ "$attribution" == true ]]; then attribution_flag=(--attribution); fi
   local plugin_flag=()
   local finalize_flag=()
-  if [[ "$FULL_PIPELINE" == "retain-all" ]]; then
-    plugin_flag=(--plugin=/workspace/${CONTROLLED_PLUGIN#"$ROOT/"} --plugin-sha256="$PLUGIN_SHA" \
+  if [[ "$FULL_PIPELINE" != "disabled" ]]; then
+    plugin_flag=(--plugin=/workspace/${FULL_PLUGIN#"$ROOT/"} --plugin-sha256="$FULL_PLUGIN_SHA" \
       --segment-min-time-nanos="$SEGMENT_MIN_TIME_NANOS" --segment-max-time-nanos="$SEGMENT_MAX_TIME_NANOS")
+    if [[ "$FULL_PIPELINE" == "skywalking" ]]; then
+      plugin_flag+=(--plugin-config=/workspace/${SKYWALKING_PLUGIN_CONFIG#"$ROOT/"} \
+        --plugin-config-sha256="$FULL_PLUGIN_CONFIG_SHA")
+    fi
   fi
   if [[ "$RUN_FINALIZE" == "1" ]]; then finalize_flag=(--finalize); fi
   docker run -d --name "$container" --cpuset-cpus="$DATA_CPUS" --cpus="$DATA_CPU_LIMIT" --memory="$DATA_MEMORY" --memory-swap="$DATA_MEMORY" --pids-limit=512 \
@@ -182,7 +241,7 @@ run_controlled_once() {
   local plugin_identity_flag=()
   if [[ "$pipeline" == "retain-all" ]]; then
     plugin_flag=(--plugin=/workspace/${CONTROLLED_PLUGIN#"$ROOT/"})
-    plugin_identity_flag=(--plugin-sha256="$PLUGIN_SHA")
+    plugin_identity_flag=(--plugin-sha256="$CONTROLLED_PLUGIN_SHA")
   fi
   docker run -d --name "$container" --cpuset-cpus="$DATA_CPUS" --cpus="$DATA_CPU_LIMIT" --memory="$DATA_MEMORY" --memory-swap="$DATA_MEMORY" --pids-limit=512 \
     -e GOMAXPROCS="$DATA_GOMAXPROCS" -e IMAGE_DIGEST="$IMAGE_DIGEST" \
@@ -218,23 +277,6 @@ run_controlled_once() {
   active_container=""
 }
 
-if [[ "$FULL_PIPELINE" != "disabled" && "$FULL_PIPELINE" != "retain-all" ]]; then
-  echo "FULL_PIPELINE must be disabled or retain-all" >&2
-  exit 1
-fi
-if [[ "$RUN_FINALIZE" != "0" && "$RUN_FINALIZE" != "1" ]]; then
-  echo "RUN_FINALIZE must be 0 or 1" >&2
-  exit 1
-fi
-if [[ "$RUN_FINALIZE" == "1" && "$FULL_PIPELINE" != "retain-all" ]]; then
-  echo "RUN_FINALIZE=1 requires FULL_PIPELINE=retain-all" >&2
-  exit 1
-fi
-if [[ "$FULL_PIPELINE" == "retain-all" && ! -f "$CONTROLLED_PLUGIN" ]]; then
-  echo "FULL_PIPELINE=retain-all requires sampler plugin $CONTROLLED_PLUGIN" >&2
-  exit 1
-fi
-
 if [[ -n "$PILOT_ACCELERATION" ]]; then
   run_once pilot serial 1 false
   echo "pilot report: $OUTPUT/pilot/report.json"