- Methods: All Methods Documented Methods Hide Methods
- Source: Display Source Hide Source
- Variables: Show Variables Hide Variables
Class ::ns::stats::Sampler
::ns::stats::Samplercreate ...
Defined in
Class Relations
::nx::Class create ::ns::stats::Sampler \ -superclass ::ns::stats::CollectorMethods (to be applied on instances)
calculate (scripted, public)
<instance of ns::stats::Sampler> calculate current previous \ interval instance
Derive interval diagnostics from current and previous snapshots. Return the current observations augmented with counter deltas, rates, average request phase times and thread CPU percentages. Rates use measured elapsed time; interval records the configured sampling cadence, and instance identifies the sampler lifetime. Interval results require a previous snapshot from the same process lifetime and positive elapsed time. Missing baselines or decreased counters yield empty derived values. CPU comparisons match thread identifiers and creation times; percentages use one core as 100%. Does not collect observations or modify shared state.
- Parameters:
- current (required)
- previous (required)
- interval (required)
- instance (required)
- Testcases:
- No testcase defined.
set stamp [dict get $current timestamp] set elapsed {} set ready false set reset false if {$previous ne "" && [dict get $previous process pid] eq [dict get $current process pid] && [dict get $previous process bootTime] eq [dict get $current process bootTime] } { set elapsed [expr {($stamp-[dict get $previous timestamp])/1000000.0}] if {$elapsed > 0} { set ready true } else { set reset true } } set result $current dict set result instance $instance dict set result sampling [dict create ready $ready from {} to [expr {$stamp/1000000.0}] elapsedSeconds $elapsed ageSeconds 0 reset $reset intervalSeconds $interval] if {$ready} { dict set result sampling from [expr {[dict get $previous timestamp]/1000000.0}] } dict for {s server} [dict get $current servers] { dict for {p entry} [dict get $server pools] { set deltas {} set rates {} set invalid {} dict for {k v} [dict get $entry counters] { if {$k ni {requests queued spooled dropped queuetime filtertime runtime tracetime}} { continue } set d {} if {$ready && [dict exists $previous servers $s pools $p counters $k]} { set d [:delta $v [dict get $previous servers $s pools $p counters $k]] if {$d eq ""} { lappend invalid $k } } dict set deltas $k $d dict set rates $k [expr {$d eq "" ? "" : $d/$elapsed}] } dict set result servers $s pools $p deltas $deltas dict set result servers $s pools $p rates $rates dict set result servers $s pools $p resetCounters $invalid set timings {} set n [expr {[dict exists $deltas requests] ? [dict get $deltas requests] : ""}] foreach k {queuetime filtertime runtime tracetime} { set d [expr {[dict exists $deltas $k] ? [dict get $deltas $k] : ""}] dict set timings $k [expr {$n eq "" || $n == 0 || $d eq "" ? "" : $d/$n}] } dict set result servers $s pools $p timingAverageSeconds $timings } } dict for {thread entry} [dict get $current drivers] { set deltas {} set rates {} set invalid {} foreach k {received partial spooled errors} { set d {} if {$ready && [dict exists $entry $k] && [dict exists $previous drivers $thread $k]} { set d [:delta [dict get $entry $k] [dict get $previous drivers $thread $k]] if {$d eq ""} { lappend invalid $k } } dict set deltas $k $d dict set rates $k [expr {$d eq "" ? "" : $d/$elapsed}] } dict set result drivers $thread deltas $deltas dict set result drivers $thread rates $rates dict set result drivers $thread resetCounters $invalid } set percentages {} set totals {} set matched 0 dict for {id entry} [dict get $current cpu] { set percent {} if {$ready && [dict exists $previous cpu $id]} { set old [dict get $previous cpu $id] set user [:delta [dict get $entry user] [dict get $old user]] set system [:delta [dict get $entry system] [dict get $old system]] if {$user ne "" && $system ne ""} { set percent [expr {100.0*($user+$system)/($elapsed*1000000)}] incr matched } } set name [string trim [dict get $entry name] -] set group other foreach {pattern kind} {driver:* driver conn:* connection writer:* writer spooler:* spooler} { if {[string match $pattern $name]} { set group $kind break } } dict set percentages $id [dict create name $name group $group percent $percent] if {$percent ne ""} { set total [expr {[dict exists $totals $group] ? [dict get $totals $group] : 0.0}] dict set totals $group [expr {$total+$percent}] } } dict set result cpuPercent [dict create scope process matchedThreads $matched observedThreads [dict size [dict get $current cpu]] groups $totals threads $percentages] return $resultsample (scripted, public)
<instance of ns::stats::Sampler> sample [ -server server ]
Return the latest published sample, updating its reported age and running state. Before any publication, return a dictionary with sampling readiness false and no interval observations. An optional server argument restricts virtual-server data; CPU measurements remain process-wide. Does not collect observations or advance the baseline. The internal raw baseline is omitted from the returned dictionary.
- Switches:
- -server (optional)
- Testcases:
- No testcase defined.
if {$server ne "" && $server ni [ns_info servers]} { error "unknown server: $server" } set result [nsv_get ns_stats pair] if {$result eq ""} { return [dict create schemaVersion 1 sampling {ready false from {} to {} elapsedSeconds {} ageSeconds {} reset false} servers {} availability {}] } dict set result sampling running [dict get [nsv_get ns_stats control] running] dict set result sampling ageSeconds [expr {max(0,([clock microseconds]-[dict get $result timestamp])/1000000.0)}] dict unset result raw # CPU is process-wide; filtering server pools never attributes CPU to a vhost. return [:selectServer $result $server]sampling start (scripted, public)
<instance of ns::stats::Sampler> sampling start \ [ -interval interval ]
Start the process-wide sampling callback at the requested interval in seconds (default 10, range 1..3600). Time units and fractional seconds are normalized with ns_baseunit. Repeated calls with the same running interval reuse the scheduler; a different interval requires stopping the sampler first. Clears the previous sample and baseline when starting a stopped sampler. Returns the resulting status dictionary. Persistence must be enabled separately.
- Switches:
- -interval (optional, defaults to
"10")- Testcases:
- No testcase defined.
set interval [ns_baseunit -time $interval] if {$interval < 1 || $interval > 3600} { error "interval must be 1..3600 seconds" } :locked { set state [nsv_get ns_stats control] if {[dict get $state running]} { if {[dict get $state interval]!=$interval} { error "sampler already running with a different interval; stop it before reconfiguring" } } else { dict incr state generation dict set state running true dict set state interval $interval dict set state busy false dict set state scheduler [ns_schedule_proc -thread $interval [self] sampling tick] nsv_set ns_stats pair {} nsv_set ns_stats control $state } } return [:sampling status]sampling status (scripted, public)
<instance of ns::stats::Sampler> sampling status
Return the process-wide sampler configuration and status, including running state, scheduler identifier, interval, process instance, collection errors and readiness of the latest interval sample. latestAt is in epoch seconds; ageSeconds is the elapsed time since the latest publication. Both are empty before the first sample. Does not collect new observations or modify sampler state.
- Testcases:
- No testcase defined.
set result [nsv_get ns_stats control] dict unset result busy dict unset result generation set sample [nsv_get ns_stats pair] dict set result ready [expr {$sample ne "" && [dict get $sample sampling ready]}] dict set result latestAt {} dict set result ageSeconds {} if {$sample ne ""} { set stamp [dict get $sample timestamp] dict set result latestAt [expr {$stamp/1000000.0}] dict set result ageSeconds [expr {max(0,([clock microseconds]-$stamp)/1000000.0)}] } return $resultsampling stop (scripted, public)
<instance of ns::stats::Sampler> sampling stop
Unschedule collection and invalidate any collection already in progress so it cannot publish into the stopped sampler. Retains the latest published sample for subsequent reads. Returns the resulting status dictionary. Does not disable the separately configured history persistence callback.
- Testcases:
- No testcase defined.
:locked { set state [nsv_get ns_stats control] if {[dict get $state running]} { ns_unschedule_proc [dict get $state scheduler] } dict set state running false dict incr state generation dict set state busy false dict set state scheduler {} nsv_set ns_stats control $state } return [:sampling status]sampling tick (scripted, public)
<instance of ns::stats::Sampler> sampling tick
Perform one scheduled collection and publish its interval sample. Skip collection when the sampler is stopped or another collection is in progress. Collect observations outside the coordination lock, then calculate and publish only if the sampler generation is still current. Retain the raw snapshot as the next interval baseline. Collection failures retain the previous publication, update error status and emit a warning. Does not write SQLite history; persistence runs through a separate callback.
- Testcases:
- No testcase defined.
set generation {} :locked { set state [nsv_get ns_stats control] if {![dict get $state running] || [dict get $state busy]} { return } set generation [dict get $state generation] dict set state busy true nsv_set ns_stats control $state } if {$generation eq ""} { return } try { set current [:snapshot] :locked { set state [nsv_get ns_stats control] if {$generation!=[dict get $state generation]} { return } set pair [nsv_get ns_stats pair] set previous [expr {$pair eq "" ? "" : [dict get $pair raw]}] set sample [:calculate $current $previous [dict get $state interval] [dict get $state instance]] dict set sample raw $current nsv_set ns_stats pair $sample dict set state busy false dict set state lastError {} nsv_set ns_stats control $state } } on error {message options} { :locked { set state [nsv_get ns_stats control] if {$generation == [dict get $state generation]} { dict set state busy false dict incr state errors dict set state lastError $message nsv_set ns_stats control $state } } ns_log warning "ns_stats: sampling failed: $message" }
- Methods: All Methods Documented Methods Hide Methods
- Source: Display Source Hide Source
- Variables: Show Variables Hide Variables
![[i]](/resources/acs-subsite/ZoomIn16.gif)