Skip to content

feat: autotuning GOGC#6819

Open
dwisiswant0 wants to merge 1 commit intodevfrom
dwisiswant0/feat/autotuning-gogc
Open

feat: autotuning GOGC#6819
dwisiswant0 wants to merge 1 commit intodevfrom
dwisiswant0/feat/autotuning-gogc

Conversation

@dwisiswant0
Copy link
Member

@dwisiswant0 dwisiswant0 commented Feb 4, 2026

Proposed changes

Autotuning GOGC.

Rationale: put this in the core pkg since it's the entrypoint for both CLI + SDK, so we only need to hook it up once.

Proof

N/A

Checklist

  • Pull request is created against the dev branch
  • All checks passed (lint, unit/integration/regression tests etc.) with my changes
  • I have added tests that prove my fix is effective or that my feature works
  • I have added necessary documentation (if appropriate)

Summary by CodeRabbit

  • Chores
    • Updated internal dependencies to improve performance and resource optimization.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 4, 2026

Walkthrough

A new garbage collection tuner dependency is added to the module and imported in the core engine via a blank import to activate its initialization side-effects. No functional logic modifications are present.

Changes

Cohort / File(s) Summary
Dependency Addition
go.mod
Added gctuner module requirement: go.dw1.io/x/exp/gctuner v0.0.0-20260204023956-e410dfed9099
Import for Side-Effects
pkg/core/engine.go
Added blank import of go.dw1.io/x/exp/gctuner/auto to initialize the garbage collection tuner

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Poem

🐰 A tuner arrives with grace so fine,
GC optimization in a line divine,
Just a blank import, nothing more,
Performance knocking at the door! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: autotuning GOGC' directly and clearly summarizes the main change: adding autotuning functionality for GOGC (Go's garbage collector parameter).
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dwisiswant0/feat/autotuning-gogc

Comment @coderabbitai help to get the list of available commands and usage tips.

Signed-off-by: Dwi Siswanto <git@dw1.io>
@dwisiswant0 dwisiswant0 force-pushed the dwisiswant0/feat/autotuning-gogc branch from 970213c to 323930c Compare February 4, 2026 02:46
@dwisiswant0 dwisiswant0 marked this pull request as ready for review February 7, 2026 20:07
@auto-assign auto-assign bot requested a review from Mzack9999 February 7, 2026 20:07
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@go.mod`:
- Line 127: The dependency go.dw1.io/x/exp/gctuner is referenced as a
pseudo-version and via a vanity domain; update go.mod to point to a stable,
tagged module or a canonical mirror (e.g., the original repo or a maintained
fork) instead of the pseudo-version, or add a replace directive to a stable
github.com path to ensure reproducible builds and proxy availability; also audit
any runtime usage of Tuning() in your codebase and document its GOGC override
behavior in README/deployment notes so operators know the environment variable
will be changed, and consider adding a fallback or feature flag to disable GC
tuning in environments where the vanity domain or auto-tuning is undesirable.
🧹 Nitpick comments (1)
pkg/core/engine.go (1)

8-8: Consider making GC autotuning configurable for SDK users.

The blank import unconditionally enables GC autotuning for all consumers of the core package. Since Engine is exported and used by both CLI (internal/runner/runner.go) and SDK users (lib/sdk_private.go, lib/multi.go, internal/server/nuclei_sdk.go), embedders may have their own GC tuning requirements or memory constraints that conflict with this automatic behavior.

Consider:

  • Adding a build tag (e.g., //go:build !nogctuner) to make the import optional
  • Adding a runtime configuration field to types.Options to control GC tuning per Engine instance
  • Moving this to CLI-only initialization if it's not required for SDK use

github.com/yassinebenaid/godump v0.11.1
github.com/zmap/zgrab2 v0.1.8
gitlab.com/gitlab-org/api/client-go v0.130.1
go.dw1.io/x/exp/gctuner v0.0.0-20260204023956-e410dfed9099
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check module proxy and go.sum for gctuner dependency

echo "=== Checking module proxy for gctuner versions ==="
curl -s "https://proxy.golang.org/go.dw1.io/x/exp/gctuner/@v/list" 2>&1

echo -e "\n=== Checking go.sum for gctuner ==="
grep "gctuner" go.sum 2>/dev/null || echo "No gctuner entries found in go.sum"

echo -e "\n=== Checking go.mod for gctuner ==="
grep -A 1 -B 1 "gctuner" go.mod

Repository: projectdiscovery/nuclei

Length of output: 555


🌐 Web query:

gctuner go.dw1.io documentation behavior

💡 Result:

For the Go gctuner package (as documented on the Go package docs that go.dw1.io commonly mirrors), the key runtime behavior is:

  • Purpose: dynamically adjusts Go’s GC aggressiveness (GOGC / GCPercent) based on current memory usage so GC runs less often when there’s plenty of headroom, and more aggressively when memory is tight. [1]
  • Core formula/idea: it targets a heap “threshold” and derives a gcPercent roughly as
    gcPercent = (threshold - inuse) / inuse * 100;
    if threshold < 2*inuse then gcPercent < 100 (more aggressive GC), and if threshold > 2*inuse then gcPercent > 100 (less aggressive GC). [1]
  • Tuning(threshold uint64) behavior:
    • sets the heap threshold that the tuner tries to respect;
    • disables tuning when threshold == 0;
    • when tuning is enabled, the GOGC environment variable is not honored (the tuner overrides it at runtime). [1]
  • Bounds: you can set min/max GC percent via SetMinGCPercent / SetMaxGCPercent (and query them), which the tuner uses to clamp its adjustments. [1]
  • Rule-of-thumb in docs: choose threshold around 70% of the memory limit (host/cgroup). [1]

Sources
[1] Go package documentation for github.com/bytedance/gopkg/util/gctuner (README + function docs). (pkg.go.dev)

Citations:


🌐 Web query:

go.dw1.io x/exp gctuner garbage collector tuning

💡 Result:

go.dw1.io/x/exp/gctuner is a lightweight Go garbage-collector (GC) auto-tuner that dynamically adjusts GOGC / GCPercent so the runtime’s GC trigger stays near a chosen heap “threshold” (a target heap usage in bytes). It’s intended to keep memory usage under control while avoiding overly-frequent GC when you have plenty of headroom. [1]

How it tunes GC

Go triggers GC roughly when:

  • gc_trigger = heap_live + heap_live * GCPercent / 100

gctuner continuously solves for GCPercent so gc_trigger ≈ threshold, while respecting configurable min/max bounds. [1]

Install

go get -u go.dw1.io/x/exp/gctuner@latest

[1]

Typical usage (recommended: 70% of effective memory limit)

import "go.dw1.io/x/exp/gctuner"

gctuner.MustEnable(
    int64(gctuner.GetMemLimitPercent(70)),
    gctuner.WithMinGCPercent(50),
    gctuner.WithMaxGCPercent(500),
)

[1]

Threshold modes

  • Enable(0) disables the tuner
  • Enable(-1) derives threshold from the effective memory limit
  • Enable(n>0) uses n bytes as the threshold [1]

Memory-limit behavior (Go 1.19+)

  • Effective limit uses GOMEMLIMIT if set, otherwise host/cgroup detection.
  • If you call SetMemLimitPercent(p), the tuner also sets Go’s runtime memory limit via debug.SetMemoryLimit, with precedence:
    1. SetMemLimitPercent override
    2. GOMEMLIMIT
    3. threshold [1]

Auto-enable on import

import _ "go.dw1.io/x/exp/gctuner/auto"

Enables during init using package defaults. [1]

Origin

This package is a fork of github.com/bytedance/gopkg/util/gctuner. [1][2]

Sources: go.dw1.io gctuner docs [1], upstream Bytedance gctuner docs [2].


Address pseudo-version dependency and lack of official Go module proxy availability.

The go.dw1.io/x/exp/gctuner dependency is a documented garbage-collector auto-tuner (forked from ByteDance's github.com/bytedance/gopkg/util/gctuner) that dynamically adjusts GOGC based on memory thresholds. However, this module:

  1. Uses a pseudo-version rather than a tagged release, which may affect reproducibility if the commit becomes unavailable.
  2. Is not available on the official Go module proxy—it uses a personal/vanity domain (go.dw1.io). Consider whether a mirror or fallback is needed.
  3. When enabled via Tuning(), overrides the GOGC environment variable at runtime, so ensure this behavior aligns with your deployment strategy.

Verify that the vanity domain remains stable and consider documenting the GC tuning behavior for maintainability.

🤖 Prompt for AI Agents
In `@go.mod` at line 127, The dependency go.dw1.io/x/exp/gctuner is referenced as
a pseudo-version and via a vanity domain; update go.mod to point to a stable,
tagged module or a canonical mirror (e.g., the original repo or a maintained
fork) instead of the pseudo-version, or add a replace directive to a stable
github.com path to ensure reproducible builds and proxy availability; also audit
any runtime usage of Tuning() in your codebase and document its GOGC override
behavior in README/deployment notes so operators know the environment variable
will be changed, and consider adding a fallback or feature flag to disable GC
tuning in environments where the vanity domain or auto-tuning is undesirable.

"github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
_ "go.dw1.io/x/exp/gctuner/auto"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this can be implemented in https://github.com/projectdiscovery/utils and potentially applied to all tools?

Copy link
Member Author

@dwisiswant0 dwisiswant0 Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this can be implemented in https://github.com/projectdiscovery/utils and potentially applied to all tools?

Yeah, we can technically just copy it over.

but, I really need your take on this, because I'm still not 100% sure about the decision (that's why I put it in exp).

The bigger question for me is whether this behavior should also be applied to SDK consumers? Because if we decide to apply it at the SDK level (too), then this isn't just a local optimization anymore, meaning it effectively becomes a global tuning change for any program/service that depends on nuclei via SDK, also meaning that downstream users would inherit this GC behavior automatically, [which could be beneficial], but it also changes perf characteristics in a way they might not explicitly opt into.

tl;dr: whether it's appropriate to enforce this kind of dynamic GC tuning across both CLI and SDK integrations.

Really want feedback here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants