Class ::ns::stats::Sampler (public)
::nx::Class ::ns::stats::Sampler![[i]](/resources/acs-subsite/ZoomIn16.gif)
Defined in
- Testcases:
-
No testcase defined.
Source code:
namespace eval ::ns::stats {}
::nsf::object::alloc ::nx::Class ::ns::stats::Sampler {}
::ns::stats::Sampler public method calculate {current previous interval instance} {
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 $result
}
::ns::stats::Sampler protected method delta {now:double before:double} {
if {$now < $before} {
return {}
}
expr {$now - $before}
}
::ns::stats::Sampler protected method init {} {
:locked {
if {[nsv_get ns_stats control] eq ""} {
nsv_set ns_stats control [dict create running false interval 10 scheduler {} generation 0 busy false instance "[pid]:[ns_info boottime]:[clock microseconds]" errors 0 lastError {}]
}
}
}
::ns::stats::Sampler protected method locked script {
uplevel 1 [list nsv_array eval ns_stats $script]
}
::ns::stats::Sampler public method sample {{-server {}}} {
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
return [:selectServer $result $server]
}
::ns::stats::Sampler public method {sampling start} {{-interval 10}} {
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]
}
::ns::stats::Sampler public method {sampling status} {} {
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 $result
}
::ns::stats::Sampler public method {sampling stop} {} {
: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]
}
::ns::stats::Sampler public method {sampling tick} {} {
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"
}
}
::nsf::relation::set ::ns::stats::Sampler superclass ::ns::stats::Collector
::nx::slotObj -container slot ::ns::stats::Sampler
XQL Not present:Generic, PostgreSQL, Oracle
[
hide source ]
| [
make this the default ]