Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
99699e0
Add vthread-context-cascade chaos antagonist; default MALLOC_CHECK_/M…
jbachorik Jul 8, 2026
0b03bba
Exclude J9 from MALLOC_CHECK_ default test env
jbachorik Jul 8, 2026
4dce8c6
Reference PROF-15360 in J9 MALLOC_CHECK_ exclusion comment
jbachorik Jul 8, 2026
8565ed8
Merge branch 'main' into jb/vt_churn
jbachorik Jul 9, 2026
4e3c9ca
Fix isRawPointer() false-positive on unencoded ASGCT BCIs (PROF-15364)
jbachorik Jul 9, 2026
d17272e
chaos: wire vthread-context-cascade into ANTAGONISTS lists
jbachorik Jul 9, 2026
e1dd0fb
ci(chaos): enable NativeMemoryTracking=summary for OOM diagnosis
jbachorik Jul 9, 2026
3673735
chaos: fix stale-racer wake timing and stopGracefully timeout budget
jbachorik Jul 9, 2026
17c3771
chaos: fix vthread-context-cascade NoClassDefFoundError by driving co…
jbachorik Jul 9, 2026
0bfeed0
chaos: fail fast on missing RUNTIME argument
jbachorik Jul 9, 2026
3e379a7
Merge branch 'main' into jb/vt_churn
jbachorik Jul 10, 2026
bf5c239
chaos: standalone harness script + debug-only stale-carrier UAF watchdog
jbachorik Jul 10, 2026
723aa71
Merge branch 'main' into jb/vt_churn
jbachorik Jul 13, 2026
b71ca62
Remove debug-only UAF watcher causing ASan/TSan failures
jbachorik Jul 13, 2026
1d054cc
Drop stale J9 MALLOC_CHECK_ skip (PROF-15360 fixed as PROF-15364)
jbachorik Jul 13, 2026
66478fb
Merge branch 'main' into jb/vt_churn
jbachorik Jul 13, 2026
fb6a1e8
chaos: restore Maven jar fallback, drop vthread-context-cascade from …
jbachorik Jul 13, 2026
c7bf65c
chaos: grant jdk.internal.misc export so OtelContextStorage uses CARR…
jbachorik Jul 13, 2026
2e34507
Merge origin/main into jb/vt_churn
Copilot Jul 13, 2026
cfe1245
chaos: tune gmalloc/jemalloc decommit to fix aarch64 chaos OOMs
jbachorik Jul 13, 2026
33a8f3d
chaos: log cgroup memory limit and trim aarch64 heap to stop OOMKills
jbachorik Jul 14, 2026
37276d3
Merge origin/main into jb/vt_churn
Copilot Jul 14, 2026
944fa81
Clarify merged FrameType raw-pointer guards
Copilot Jul 14, 2026
8254e49
Harden FrameType VM test cleanup
Copilot Jul 14, 2026
17d0792
chaos: clean stale JFR chunk dir and log /tmp disk usage
jbachorik Jul 14, 2026
be3c3bf
chaos: raise Xmx to 2.5GiB, drop aarch64 heap trim
jbachorik Jul 14, 2026
ae3daa1
chaos: add memory-pressure governor, restore Xmx to 2.5GiB
jbachorik Jul 14, 2026
2a3e926
Extend MemoryGovernor to heap usage and 5 more antagonists; bump chao…
jbachorik Jul 15, 2026
d1f2a0f
Gate DirectMemoryAntagonist.burstLoop() on governor; log throttle tra…
jbachorik Jul 15, 2026
2ef0fd2
Add critical watermark + GC nudge to chaos MemoryGovernor
jbachorik Jul 15, 2026
08390ce
Speed up governor reaction time, exit cleanly on first heap OOME
jbachorik Jul 15, 2026
68ceb93
Tolerate a late clean heap OOME, still fail an early one
jbachorik Jul 15, 2026
8c1402d
Bound in-flight virtual threads in VirtualThreadChurnAntagonist
jbachorik Jul 16, 2026
9ef1d89
Guard chaos harness malloc checking and gate hotspot in raw-pointer test
jbachorik Jul 16, 2026
cb331de
Implement reference chains for surviving live-heap samples (PROF-15341)
jbachorik Jul 7, 2026
2ed0660
Add JFR round-trip test for ReferenceChain array-of-cpool field; capt…
jbachorik Jul 7, 2026
fb01f7c
Gate reference-chain search restarts on leak indication + pain budget
jbachorik Jul 8, 2026
a1b6fb1
Suppress LSAN false-positive for JfrMetadata::initialize() in referen…
jbachorik Jul 9, 2026
dfbf4cd
Cap ReferenceChainTrackingTest population-growth rounds at 16 to fit …
jbachorik Jul 9, 2026
b4babbc
Fix TSAN data race on FrontierTable::_table_size; cap test garbage gr…
jbachorik Jul 9, 2026
1e4343c
ci: install libgtest-dev/libgmock-dev on glibc-aarch64
jbachorik Jul 9, 2026
fde6403
Add debug-only test seams to decouple leak-candidate slope detection …
jbachorik Jul 9, 2026
e6f9b38
Fix concurrency, overflow, and validation issues in reference-chain t…
jbachorik Jul 10, 2026
689291a
Fix reference-chain test-seam races and cross-test candidate pollution
jbachorik Jul 14, 2026
161972a
Fix reference-chain class-tag reuse after StringDictionary reset
jbachorik Jul 15, 2026
43699fc
Fix LivenessTracker forced-cleanup gate silently dropping population …
jbachorik Jul 15, 2026
6c4b96b
Fix FrontierTable capacity poisoning across shared-JVM tests
jbachorik Jul 15, 2026
4c9dd19
Reset frontier search state before directly tagging a root in Referen…
jbachorik Jul 15, 2026
f04639d
Add TEST_LOG diagnostics for silent dump/copy failure paths
jbachorik Jul 15, 2026
71c74f4
Decouple LeakingCacheScenario from real allocation-sampling timing
jbachorik Jul 15, 2026
11573bb
Profiler's fuzz tests store corpus files under wrong directories
zhengyu123 Jul 13, 2026
653f507
Fix typo
zhengyu123 Jul 13, 2026
7d81b77
fix(profiler): guard line-number-table copy against stale jmethodID (…
jbachorik Jul 14, 2026
b18cdfa
Optimize SafeAccess:safeCopy() implementation in assembly
zhengyu123 Jul 14, 2026
657e0b6
Review comments
zhengyu123 Jul 14, 2026
442f509
Force apt IPv4 in aarch64 Setup OS to avoid dead IPv6 route to ports.…
jbachorik Jul 16, 2026
baba070
Add apt retries alongside IPv4 force in aarch64 Setup OS
jbachorik Jul 16, 2026
35c49c2
Fix LivenessTracker::_gc_generations staleness across shared-JVM test…
jbachorik Jul 16, 2026
a9fb05f
Fix gcRootHolder empty-array race in shouldReconstructReferrerChainTo…
jbachorik Jul 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/test_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -387,10 +387,14 @@ jobs:
- name: Setup OS
if: steps.set_enabled.outputs.enabled == 'true'
run: |
# ports.ubuntu.com's IPv6 route is intermittently unreachable from GH-hosted
# aarch64 runners; force IPv4 so apt doesn't stall/fail on a dead IPv6 path,
# and retry on top in case of other transient connection blips.
printf 'Acquire::ForceIPv4 "true";\nAcquire::Retries "5";\n' | sudo tee /etc/apt/apt.conf.d/99force-ipv4 >/dev/null
sudo apt update -y
sudo apt remove -y g++
sudo apt autoremove -y
sudo apt install -y curl zip unzip clang make build-essential binutils gdb
sudo apt install -y curl zip unzip clang make build-essential binutils gdb libgtest-dev libgmock-dev
# Install debug symbols for system libraries
sudo apt install -y libc6-dbg
if [[ ${{ matrix.java_version }} =~ "-zing" ]]; then
Expand Down
183 changes: 11 additions & 172 deletions .gitlab/reliability/chaos_check.sh
Original file line number Diff line number Diff line change
@@ -1,178 +1,17 @@
#!/usr/bin/env bash

set +e # Disable exit on error
#
# CI entry point for the chaos harness. Thin wrapper around
# utils/run-chaos-harness.sh — this file only supplies the CI-specific
# caching paths (so repeated scheduled runs on the same runner reuse the
# downloaded JDK/agent jar) and the fixed hs_err.log location the pipeline's
# `artifacts:` block expects at the repo root. All the actual build/run logic
# lives in the standalone script, which is also runnable by hand.

HERE="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
ROOT="$( cd "${HERE}/../.." >/dev/null 2>&1 && pwd )"

RUNTIME=${1}
CONFIG=${2:-profiler+tracer}
ALLOCATOR=${3:-gmalloc}

echo "Chaos run: runtime=${RUNTIME}s config=${CONFIG} allocator=${ALLOCATOR}"

CHAOS_JDK="${CHAOS_JDK:-21.0.3-tem}"
# CHAOS_JDK uses sdkman notation (<version>-<dist>); extract major for Adoptium API.
JDK_MAJOR="${CHAOS_JDK%%.*}"
JDK_ARCH=$(uname -m | sed 's/x86_64/x64/')
JDK_INSTALL_DIR="/opt/jdk-${CHAOS_JDK}"

if [ ! -x "${JDK_INSTALL_DIR}/bin/java" ]; then
TMP=$(mktemp -d)
DL_URL="https://api.adoptium.net/v3/binary/latest/${JDK_MAJOR}/ga/linux/${JDK_ARCH}/jdk/hotspot/normal/eclipse"
echo "Downloading JDK ${CHAOS_JDK} (major ${JDK_MAJOR}) from Adoptium..."
if ! curl -fsSL --max-time 300 "${DL_URL}" -o "${TMP}/jdk.tar.gz"; then
echo "FAIL:JDK ${CHAOS_JDK} download failed" >&2
rm -rf "${TMP}"
exit 1
fi
mkdir -p "${JDK_INSTALL_DIR}"
tar -xzf "${TMP}/jdk.tar.gz" -C "${JDK_INSTALL_DIR}" --strip-components=1
rm -rf "${TMP}"
fi

if [ ! -x "${JDK_INSTALL_DIR}/bin/java" ]; then
echo "FAIL:JDK ${CHAOS_JDK} not available after install" >&2
exit 1
fi
export JAVA_HOME="${JDK_INSTALL_DIR}"
export PATH="${JAVA_HOME}/bin:${PATH}"
ACTIVE_JDK=$(java -version 2>&1 | head -1)
# Check major version only — patch may differ from the Adoptium latest GA.
if ! echo "${ACTIVE_JDK}" | grep -qE "\"${JDK_MAJOR}\."; then
echo "FAIL:wrong JDK active (expected major ${JDK_MAJOR}, got: ${ACTIVE_JDK})" >&2
exit 1
fi

# Resolve ddprof.jar: prefer local build artifact, fall back to Maven snapshot.
# Running mvn from /tmp avoids the empty pom.xml at the repo root.
DDPROF_JAR_LOCAL=$(ls "${ROOT}/ddprof-lib/build/libs/ddprof-"*.jar 2>/dev/null | head -1)
if [ -n "${DDPROF_JAR_LOCAL}" ] && [ -f "${DDPROF_JAR_LOCAL}" ]; then
DDPROF_JAR="${DDPROF_JAR_LOCAL}"
echo "Using local ddprof jar: ${DDPROF_JAR}"
else
if [ -z "${CURRENT_VERSION:-}" ]; then
echo "FAIL:CURRENT_VERSION is empty and no local jar found (get-versions dotenv missing)" >&2
exit 1
fi
echo "Local ddprof jar not found — downloading ${CURRENT_VERSION} from Maven snapshots"
(cd /tmp && mvn org.apache.maven.plugins:maven-dependency-plugin:2.1:get \
-DrepoUrl=https://central.sonatype.com/repository/maven-snapshots/ \
-Dartifact=com.datadoghq:ddprof:${CURRENT_VERSION})
DDPROF_JAR="/root/.m2/repository/com/datadoghq/ddprof/${CURRENT_VERSION}/ddprof-${CURRENT_VERSION}.jar"
fi

if [ ! -f "${DDPROF_JAR}" ]; then
echo "FAIL:ddprof jar unavailable" >&2
exit 1
fi

mkdir -p /var/lib/datadog
wget -q --timeout=120 --tries=3 -O /var/lib/datadog/dd-java-agent.jar 'https://dtdg.co/latest-java-tracer'

# chaos.jar is produced once per pipeline by the chaos:build job (stresstest
# stage) and pulled here as an artifact. Fall back to an inline build if the
# artifact is absent (e.g. local repro outside CI).
CHAOS_JAR="${ROOT}/ddprof-stresstest/build/libs/chaos.jar"
if [ ! -f "${CHAOS_JAR}" ]; then
echo "chaos.jar artifact not present — building inline"
( cd "${ROOT}" && ./gradlew :ddprof-stresstest:chaosJar -q )
fi

if [ ! -f "${CHAOS_JAR}" ]; then
echo "FAIL:chaos.jar unavailable" >&2
exit 1
fi

# Patch dd-java-agent.jar with the locally built ddprof contents so the agent's
# (relocated) profiler classes match the version under test.
DD_AGENT_JAR=/var/lib/datadog/dd-java-agent.jar \
DDPROF_JAR=${DDPROF_JAR} \
OUTPUT_JAR=/var/lib/datadog/dd-java-agent-patched.jar \
"${ROOT}/utils/patch-dd-java-agent.sh"

if [ ! -f /var/lib/datadog/dd-java-agent-patched.jar ]; then
echo "FAIL:dd-java-agent patching failed" >&2
exit 1
fi

PATCHED_AGENT=/var/lib/datadog/dd-java-agent-patched.jar

case $CONFIG in
profiler)
echo "Running with profiler only"
ENABLEMENT="-Ddd.profiling.enabled=true -Ddd.trace.enabled=false"
# @Trace is a no-op without the tracer, so trace-context is excluded here.
ANTAGONISTS="thread-churn,alloc-storm,vthread-churn,classloader-churn,bounded-pool,context-hop,consumer-group,hidden-class-churn,direct-memory,weakref-wave,dump-storm"
;;
profiler+tracer)
echo "Running with profiler and tracer"
ENABLEMENT="-Ddd.profiling.enabled=true -Ddd.trace.enabled=true"
ANTAGONISTS="thread-churn,alloc-storm,vthread-churn,classloader-churn,trace-context,bounded-pool,context-hop,consumer-group,hidden-class-churn,direct-memory,weakref-wave,dump-storm"
;;
*)
echo "Unknown configuration: $CONFIG"
exit 1
;;
esac

case $ALLOCATOR in
gmalloc)
echo "Running with gmalloc"
;;
tcmalloc)
echo "Running with tcmalloc"
export LD_PRELOAD=$(find /usr/lib/ -name 'libtcmalloc_minimal.so.4')
# thread-churn/dump-storm antagonists cycle many short-lived threads;
# tcmalloc's defaults are slow to return their per-thread caches to the
# OS, which was inflating container RSS past the OOM limit on aarch64.
export TCMALLOC_RELEASE_RATE=10
export TCMALLOC_AGGRESSIVE_DECOMMIT=1
;;
jemalloc)
echo "Running with jemalloc"
export LD_PRELOAD=$(find /usr/lib/ -name 'libjemalloc.so')
;;
*)
echo "Unknown allocator: $ALLOCATOR"
echo "Valid values are: gmalloc, tcmalloc, jemalloc"
exit 1
;;
esac

echo "LD_PRELOAD=$LD_PRELOAD"

timeout "$((RUNTIME + 300))" \
java -javaagent:${PATCHED_AGENT} \
${ENABLEMENT} \
-Ddd.profiling.upload.period=10 \
-Ddd.profiling.start-force-first=true \
-Ddd.profiling.ddprof.liveheap.enabled=true \
-Ddd.profiling.ddprof.alloc.enabled=true \
-Ddd.profiling.ddprof.wall.enabled=true \
-Ddd.profiling.ddprof.nativemem.enabled=true \
-Ddd.env=java-profiler-stability \
-Ddd.service=java-profiler-chaos \
-Xmx2g -Xms2g \
-XX:MaxMetaspaceSize=384m \
-XX:ErrorFile=${HERE}/../../hs_err.log \
-XX:OnError="${HERE}/../../dd_crash_uploader.sh %p" \
-jar ${CHAOS_JAR} \
--duration ${RUNTIME}s \
--antagonists ${ANTAGONISTS}

RC=$?
echo "RC=$RC"
export CHAOS_JDK_DIR="${CHAOS_JDK_DIR:-/opt/jdk-${CHAOS_JDK}}"
export CHAOS_WORK_DIR="${CHAOS_WORK_DIR:-/var/lib/datadog}"
export CHAOS_ERROR_FILE="${ROOT}/hs_err.log"

if [ $RC -ne 0 ]; then
CRASH_MSG="Chaos harness crashed (RC=${RC})"
HS_ERR="${HERE}/../../hs_err.log"
if [ -f "${HS_ERR}" ]; then
SIG=$(grep -m1 '^siginfo:' "${HS_ERR}" 2>/dev/null | tr -d '\n' | cut -c1-120)
FRAME=$(grep -m1 'libjavaProfiler\|AsyncProfiler' "${HS_ERR}" 2>/dev/null | sed 's/^[[:space:]]*//' | tr -d '\n' | cut -c1-120)
[ -n "${SIG}" ] && CRASH_MSG="${CRASH_MSG};${SIG}"
[ -n "${FRAME}" ] && CRASH_MSG="${CRASH_MSG};${FRAME}"
fi
echo "FAIL:${CRASH_MSG}" >&2
exit 1
fi
exec "${ROOT}/utils/run-chaos-harness.sh" "$@"
13 changes: 13 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,19 @@ table: see [doc/build/JdkUpgrades.md](doc/build/JdkUpgrades.md).
- All code needs to strive to be lean in terms of resources consumption and easy to follow -
do not shy away from factoring out self containing code to shorter functions with explicit name

## CI / Automation Script Changes
- Before rewriting or replacing a script invoked from `.gitlab-ci.yml`, `.gitlab/**/*.yml`, or any CI job,
run `git log -p -- <script>` (or diff against the version being replaced) and enumerate every behavior
branch it has — fallbacks, env-var-driven paths, error exits. Preserve all of them unless explicitly
asked to drop one; do not silently narrow behavior while refactoring.
- Grep the calling `.gitlab-ci.yml` / `.gitlab/**/*.yml` jobs for how the script is invoked (env vars set,
exit codes expected) and confirm the rewrite still satisfies every caller, not just the common/local case.
- When removing an item from a default list or config (an antagonist, a test tag, a feature flag), cite
the exact file/line proving it is inert or unused in that context before removing it — never remove
based on assumption alone.
- After changing a CI-invoked script, run a syntax check (e.g. `bash -n <script>`) and trace through each
CI job that calls it before considering the change complete.

### C/C++ Code Style
- **Indentation**: Match the exact indentation style of the surrounding code in each file. Do not introduce inconsistent indentation — reviewers will flag it.
- **Minimal complexity**: Do not split inline logic into separate helper functions unless the helpers are reused or the original is genuinely hard to follow. Unnecessary splits add indirection without value.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.datadoghq.profiler

import com.datadoghq.native.NativeBuildExtension
import com.datadoghq.native.model.BuildConfiguration
import com.datadoghq.native.model.Platform
import com.datadoghq.native.util.PlatformUtils
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
Expand Down Expand Up @@ -204,6 +205,18 @@ class ProfilerTestPlugin : Plugin<Project> {

// Environment variables (explicit for consistency across both paths)
val envVars = buildMap<String, String> {
// Turn silent glibc heap corruption (e.g. a use-after-free write into a
// freed chunk) into an immediate, attributable SIGABRT instead of a crash
// much later in an unrelated allocation. Only meaningful against glibc's
// own malloc: skip on musl (no MALLOC_CHECK_ support), and skip whenever a
// sanitizer/allocator already replaces malloc via LD_PRELOAD.
if (PlatformUtils.currentPlatform == Platform.LINUX &&
!PlatformUtils.isMusl() &&
!testEnv.containsKey("LD_PRELOAD")
) {
put("MALLOC_CHECK_", "3")
put("MALLOC_PERTURB_", (1..255).random().toString())
}
putAll(testEnv)
put("DDPROF_TEST_DISABLE_RATE_LIMIT", "1")
put("CI", (project.hasProperty("CI") || System.getenv("CI")?.toBoolean() ?: false).toString())
Expand Down
96 changes: 96 additions & 0 deletions ddprof-lib/src/main/cpp/arguments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "arguments.h"
#include "vmEntry.h"

#include <algorithm>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
Expand Down Expand Up @@ -81,6 +82,24 @@ static const Multiplier UNIVERSAL[] = {
// and keep the liveness track of 10% of the allocation
// samples
// generations - track surviving generations
// referencechains[=BOOL[:hops=N][:budget=N][:ttl=N][:framecap=N][:pausetarget=N][:painbudget=N][:firstpassbudget=N]]
// - (PROF-15341, off by default) tag/BFS-walk live-heap
// samples' referrer chains back toward a GC root.
// pausetarget=N (ms) is the pause-time-SLO ceiling
// ReferenceChainTracker::updatePacing() adapts the
// effective budget/cadence toward (pause-time pacing
// controller). painbudget=N (percent) bounds how much
// wall-clock time a *restarted* search (one begun
// after a prior search already completed/abandoned)
// may spend on average - see PainBudget (painBudget.h).
// firstpassbudget=N overrides just the search's
// one-shot, root-seeded first pass's edge budget
// (default 0 - falls back to budget=N) since that
// pass alone decides which GC roots ever enter the
// frontier at all, unlike every later pass's cheap,
// incremental per-node expansion.
// Sub-options are placeholders pending future tuning;
// see doc/architecture/LiveHeapReferenceChains*.md
// lightweight[=BOOL] - enable lightweight profiling - events without
// stacktraces (default: true)
// remotesym[=BOOL] - enable remote symbolication for native frames
Expand Down Expand Up @@ -428,6 +447,83 @@ Error Arguments::parse(const char *args) {
_nativesocket = true;
}

CASE("referencechains")
{
// Sub-options are colon-delimited key=value pairs after the boolean,
// e.g. "referencechains=true:hops=64:budget=2000". Parsed manually
// (not via strtok) because the outer arg loop above is itself mid
// strtok(..., ",") over the same buffer - a nested strtok call would
// clobber its saved state.
char *config = value ? strchr(value, ':') : nullptr;
if (config) {
*(config++) = 0;
}
if (value != NULL) {
switch (value[0]) {
case 'n': // no
case 'f': // false
case '0': // 0
_reference_chains = false;
break;
default:
_reference_chains = true;
}
} else {
_reference_chains = true;
}
char *cursor = config;
while (cursor != NULL) {
char *next = strchr(cursor, ':');
if (next) {
*(next++) = 0;
}
char *eq = strchr(cursor, '=');
if (eq) {
*(eq++) = 0;
// Floor every sub-option at the parse boundary rather than
// trusting a downstream cast/clamp to make an operator-supplied
// negative value safe: a negative hops value in particular gets
// compared as `depth >= (u32)ctx->hop_cap` (referenceChains.cpp),
// so an unclamped negative wraps to ~4e9 and silently disables
// the hop cap entirely - the opposite of the flag's intent, and
// it removes the one guard that otherwise bounds how long a
// single reference chain (and therefore its
// datadog.ReferenceChain JFR event) can grow. A negative budget
// similarly collapses ReferenceChainTracker::_effective_budget
// to 0 (updatePacing()'s own PID-clamp logic), which truncates
// every pass immediately and leaves the search RUNNING
// (re-walking the whole graph each cadence) until TTL instead of
// making progress. A negative framecap is handed straight to
// FrontierTable's constructor, which floors it to a
// zero-capacity table (that class's own std::max(max_cap, 0)),
// silently disabling tracking rather than erroring. ttl/
// pausetarget/painbudget already have incidental downstream
// clamps (runPass()'s `_ttl_ms > 0` gate, this class's own
// PidController/PainBudget std::max(..., 0) calls) but are
// floored here too so every sub-option's validation lives at one
// boundary instead of being split between here and several
// unrelated call sites.
if (strcasecmp(cursor, "hops") == 0) {
_reference_chains_hop_cap = std::max(atoi(eq), 1);
} else if (strcasecmp(cursor, "budget") == 0) {
_reference_chains_budget = std::max(atoi(eq), 1);
} else if (strcasecmp(cursor, "ttl") == 0) {
_reference_chains_ttl_ms = std::max(atol(eq), 0L);
} else if (strcasecmp(cursor, "framecap") == 0) {
_reference_chains_frontier_cap = std::max(atoi(eq), 1);
} else if (strcasecmp(cursor, "pausetarget") == 0) {
_reference_chains_pause_target_ms = std::max(atol(eq), 0L);
} else if (strcasecmp(cursor, "painbudget") == 0) {
_reference_chains_pain_budget_percent =
std::min(std::max(atoi(eq), 0), 100);
} else if (strcasecmp(cursor, "firstpassbudget") == 0) {
_reference_chains_first_pass_budget = std::max(atoi(eq), 0);
}
}
cursor = next;
}
}

DEFAULT()
if (_unknown_arg == NULL)
_unknown_arg = arg;
Expand Down
Loading
Loading