summaryrefslogtreecommitdiff
path: root/internal/flags/flags.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-20 11:38:19 +0300
committerPaul Buetow <paul@buetow.org>2026-05-20 11:38:19 +0300
commit9310b54d439d4a1a8d4d337987aa63884df0af76 (patch)
treec6fb38085891a04ce81672f977af316a2e96b2fd /internal/flags/flags.go
parent5fd613562e2aa2ab3aac3349f44db88330046c1c (diff)
feat: add syscall aggregate sampling infrastructure (task 17)
Diffstat (limited to 'internal/flags/flags.go')
-rw-r--r--internal/flags/flags.go59
1 files changed, 46 insertions, 13 deletions
diff --git a/internal/flags/flags.go b/internal/flags/flags.go
index 285569c..3a6456a 100644
--- a/internal/flags/flags.go
+++ b/internal/flags/flags.go
@@ -12,6 +12,7 @@ import (
appconfig "ior/internal/config"
"ior/internal/globalfilter"
"ior/internal/tracepoints"
+ "ior/internal/types"
)
// Config captures runtime configuration parsed from CLI flags.
@@ -72,6 +73,13 @@ type Config struct {
// ResetTimer is the interval at which aggregate dashboard state (flamegraph
// trie and stats engine) is automatically cleared; 0 disables auto-reset.
ResetTimer time.Duration
+ // SyscallFamilySamplingRates controls in-kernel syscall sampling by family.
+ // Rate semantics: 0 aggregate-only, 1 emit every event, N>1 emit 1-in-N events.
+ SyscallFamilySamplingRates map[types.SyscallFamily]uint32
+ // SyscallSamplingRates controls in-kernel syscall sampling by syscall name.
+ // Keys use syscall names (for example "futex"), not tracepoint names.
+ // Rate semantics: 0 aggregate-only, 1 emit every event, N>1 emit 1-in-N events.
+ SyscallSamplingRates map[string]uint32
// ShowVersion prints the banner plus version and exits without running.
ShowVersion bool
@@ -86,16 +94,18 @@ const DefaultResetTimer = 30 * time.Second
// NewFlags returns a configuration instance initialized with project defaults.
func NewFlags() Config {
return Config{
- PidFilter: -1,
- TidFilter: -1,
- EventMapSize: appconfig.DefaultEventMapSize,
- Duration: 900,
- LiveInterval: 200 * time.Millisecond,
- TUIFastRefreshInterval: 250 * time.Millisecond,
- TUIExportEnable: true,
- CollapsedFields: []string{"comm", "tracepoint", "path"},
- CountField: "count",
- ResetTimer: DefaultResetTimer,
+ PidFilter: -1,
+ TidFilter: -1,
+ EventMapSize: appconfig.DefaultEventMapSize,
+ Duration: 900,
+ LiveInterval: 200 * time.Millisecond,
+ TUIFastRefreshInterval: 250 * time.Millisecond,
+ TUIExportEnable: true,
+ CollapsedFields: []string{"comm", "tracepoint", "path"},
+ CountField: "count",
+ ResetTimer: DefaultResetTimer,
+ SyscallFamilySamplingRates: make(map[types.SyscallFamily]uint32),
+ SyscallSamplingRates: make(map[string]uint32),
}
}
@@ -121,6 +131,8 @@ func (f Config) Clone() Config {
out.TracepointSelector = f.TracepointSelector.Clone()
out.CollapsedFields = slices.Clone(f.CollapsedFields)
out.GlobalFilter = f.GlobalFilter.Clone()
+ out.SyscallFamilySamplingRates = cloneFamilySamplingRates(f.SyscallFamilySamplingRates)
+ out.SyscallSamplingRates = cloneSyscallSamplingRates(f.SyscallSamplingRates)
return out
}
@@ -136,7 +148,7 @@ func Parse() (Config, error) {
// fresh FlagSet and custom argument slices without touching global state.
func parseFromFlagSet(fs *flag.FlagSet, args []string) (Config, error) {
cfg := NewFlags()
- tpsAttach, tpsExclude, fields := registerFlags(fs, &cfg)
+ tpsAttach, tpsExclude, fields, familySampling, syscallSampling := registerFlags(fs, &cfg)
if err := fs.Parse(args); err != nil {
return Config{}, err
@@ -144,6 +156,9 @@ func parseFromFlagSet(fs *flag.FlagSet, args []string) (Config, error) {
if err := resolvePostParseFields(&cfg, tpsAttach, tpsExclude, fields); err != nil {
return Config{}, err
}
+ if err := resolveSamplingRates(&cfg, familySampling, syscallSampling); err != nil {
+ return Config{}, err
+ }
if err := validateConfig(cfg); err != nil {
return Config{}, err
}
@@ -152,7 +167,7 @@ func parseFromFlagSet(fs *flag.FlagSet, args []string) (Config, error) {
// registerFlags binds all CLI flags to cfg and returns the string pointers for
// fields that require post-parse resolution (tracepoint regexes, collapse fields).
-func registerFlags(fs *flag.FlagSet, cfg *Config) (tpsAttach, tpsExclude, fields *string) {
+func registerFlags(fs *flag.FlagSet, cfg *Config) (tpsAttach, tpsExclude, fields, familySampling, syscallSampling *string) {
validFields := collapse.ValidFields()
validCounts := collapse.ValidCountFields()
@@ -180,12 +195,16 @@ func registerFlags(fs *flag.FlagSet, cfg *Config) (tpsAttach, tpsExclude, fields
fs.BoolVar(&cfg.TUIExportEnable, "tuiExport", cfg.TUIExportEnable, "Enable TUI CSV snapshot export files (separate from Parquet recording)")
fs.DurationVar(&cfg.ResetTimer, "resetTimer", cfg.ResetTimer,
"Auto-reset interval for aggregate dashboard state (flamegraph trie + stats engine); set to 0 to disable")
+ familySampling = fs.String("syscall-sampling-families", "",
+ "Per-family sampling rates, for example \"Time=100,Misc=0\" (0=aggregate-only, 1=all, N=1-in-N)")
+ syscallSampling = fs.String("syscall-sampling-syscalls", "",
+ "Per-syscall sampling rates, for example \"futex=0,clock_gettime=200\" (overrides family rates)")
fs.BoolVar(&cfg.ShowVersion, "version", false, "Print version banner and exit")
fields = fs.String("fields", "",
fmt.Sprintf("Comma separated list of fields to collapse, valid are: %v", validFields))
fs.StringVar(&cfg.CountField, "count", cfg.CountField,
fmt.Sprintf("Count field to collapse, valid are: %v", validCounts))
- return tpsAttach, tpsExclude, fields
+ return tpsAttach, tpsExclude, fields, familySampling, syscallSampling
}
// resolvePostParseFields compiles the tracepoint selector and collapse field
@@ -220,6 +239,20 @@ func resolvePostParseFields(cfg *Config, tpsAttach, tpsExclude, fields *string)
return nil
}
+func resolveSamplingRates(cfg *Config, familySampling, syscallSampling *string) error {
+ familyRates, err := parseFamilySamplingRates(*familySampling)
+ if err != nil {
+ return err
+ }
+ syscallRates, err := parseSyscallSamplingRates(*syscallSampling)
+ if err != nil {
+ return err
+ }
+ cfg.SyscallFamilySamplingRates = familyRates
+ cfg.SyscallSamplingRates = syscallRates
+ return nil
+}
+
// validateConfig checks numeric/duration bounds that cannot be enforced by the
// flag package itself and returns a descriptive error on the first violation.
func validateConfig(cfg Config) error {