source: trunk/p2p/wonks.tcl @ 4503

Last change on this file since 4503 was 3177, checked in by mmc, 12 years ago

Updated all of the copyright notices to reference the transfer to
the new HUBzero Foundation, LLC.

File size: 7.5 KB
Line 
1# ----------------------------------------------------------------------
2#  P2P: wonks
3#
4#  This code manages the calculation of "wonks" within a worker node.
5#  Wonks are measured by executing the "perftest" program on the
6#  worker node to see how fast it can finish the calculation.
7# ----------------------------------------------------------------------
8#  Michael McLennan (mmclennan@purdue.edu)
9# ======================================================================
10#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
11#
12#  See the file "license.terms" for information on usage and
13#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14# ======================================================================
15package require Rappture
16
17namespace eval p2p { # forward declaration }
18
19namespace eval p2p::wonks {
20    # remember this directory -- perftest sits here too
21    variable dir [file dirname [info script]]
22
23    # version info from perftest
24    variable version "?"
25}
26
27# number of seconds between each check of system load
28p2p::options register wonks_time_between_checks 60000
29
30# fraction between 0-1 indicating a significant change in wonks
31p2p::options register wonk_tolerance 0.1
32
33# ----------------------------------------------------------------------
34#  WONKS CHECK
35#
36#  This is the state machine controlling the periodic testing for
37#  the available wonks on this machine.  The "perftest" program is
38#  executed from time to time to compute the available wonks, and
39#  the results are stored in an array of tuples.  At any point, we
40#  can estimate the number of wonks by getting the load and available
41#  memory and interpolating within the available tuple data.
42# ----------------------------------------------------------------------
43StateMachine wonks-check
44
45# sit here at times between sampling
46# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
47wonks-check state idle -onenter {
48    set delay [p2p::options get wonks_time_between_checks]
49    after $delay {wonks-check goto checking}
50} -onleave {
51    after cancel {wonks-check goto checking}
52}
53
54# sit here while we're sampling
55# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
56wonks-check state checking
57
58# when moving to the checking state, test available wonks
59# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
60wonks-check transition idle->checking -onchange {
61    set data [wonks-check statedata perftable]
62
63    set getWonks 0  ;# probably won't have to use perftest
64
65    # measure system load and estimate the available wonks
66    foreach {load mem} [Rappture::sysinfo load1 freeswap] break
67    set load [format "%.1f" $load]
68    set mem [expr {$mem/1048576}]  ;# in megabytes
69    set wval 0
70    set nsamples 0
71
72    if {![$data inrange [list $load $mem -- --]]} {
73        # outside range of data -- must call perftest
74        set getWonks 1
75    } else {
76        set rec [$data find -nearest [list $load $mem -- --]]
77        set prevload [lindex $rec 0]
78        set prevmem [lindex $rec 1]
79        set tol [p2p::options get wonk_tolerance]
80
81        set closeEnough 1
82        if {"" == $prevload || ($load+$prevload > 0
83              && abs($load-$prevload)/(0.5*double($load+$prevload)) > $tol)} {
84            # load differs by more than the tolerance -- must test
85            set closeEnough 0
86        } elseif {"" == $prevmem || ($mem+$prevmem > 0
87              && abs($mem-$prevmem)/(0.5*double($mem+$prevmem)) > $tol)} {
88            set closeEnough 0
89        }
90
91        if {$closeEnough} {
92            # close enough to some other sample point
93            # update the existing data point in the table
94            set load $prevload
95            set mem $prevmem
96
97            set wval [lindex $rec 2]
98            set nsamples [lindex $rec 3]
99            if {$nsamples < 5} {
100                # not very many samples? then do another
101                set getWonks 1
102            } elseif {$nsamples < 50 && rand() > 0.9} {
103                # if we have a lot of samples do another from time to time
104                set getWonks 1
105            }
106        }
107    }
108
109    # if we need a new reading, exec the perftest program...
110    if {$getWonks} {
111        # Run the program, but don't use exec, since it blocks.
112        # Instead, run it in the background and harvest its output later.
113        set prog [open "| [file join $p2p::wonks::dir perftest]" r]
114        fileevent $prog readable {wonks-check goto update}
115        wonks-check statedata sysinfo [list $load $mem $wval $nsamples]
116        wonks-check statedata prog $prog
117    } else {
118        after idle {wonks-check goto idle}
119    }
120}
121
122# go here when perftest has finished
123# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
124wonks-check state update
125
126# when moving to the update state, store the data from perftest
127# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
128wonks-check transition checking->update -onchange {
129    set data [wonks-check statedata perftable]
130    set prog [wonks-check statedata prog]
131
132    if {[catch {read $prog} msg] == 0} {
133        if {[regexp {^([^ ]+) +([0-9]+)} $msg match vstr wval]} {
134            set p2p::wonks::version $vstr
135            foreach {load mem oldwval nsamples} [wonks-check statedata sysinfo] break
136            if {$nsamples >= 1} {
137                # average new value with old values
138                set wval [expr {$wval/double($nsamples+1)
139                                 + $nsamples/double($nsamples+1)*$oldwval}]
140            }
141            $data delete [list $load $mem -- --]
142            $data add [list $load $mem $wval [incr nsamples]]
143        } else {
144            log error "ERROR: performance test failed: $msg"
145        }
146    }
147    catch {close $prog}
148    wonks-check statedata prog ""
149    wonks-check statedata sysinfo ""
150
151    after idle {wonks-check goto idle}
152}
153
154# ----------------------------------------------------------------------
155#  COMMAND:  p2p::wonks::init
156#
157#  Invoked when a worker node starts up to initialize this part of
158#  the package.  This triggers autoloading of the file, and also
159#  initializes variables used by the functions in this file.
160# ----------------------------------------------------------------------
161proc p2p::wonks::init {} {
162    variable version
163    set version "?"
164
165    set data [Rappture::tuples ::#auto]
166    $data dimension add load1
167    $data dimension add freeswap
168    $data dimension add wonks
169    $data dimension add nsamples
170    wonks-check statedata perftable $data
171
172    wonks-check goto idle
173}
174
175# ----------------------------------------------------------------------
176#  COMMAND:  p2p::wonks::current
177#
178#  Used to estimate the current performance of this node as a number
179#  of wonks.  Takes
180# ----------------------------------------------------------------------
181proc p2p::wonks::current {} {
182    foreach {load mem} [Rappture::sysinfo load1 freeswap] break
183    set load [format "%.1f" $load]
184    set mem [expr {$mem/1048576}]  ;# in megabytes
185
186    set data [wonks-check statedata perftable]
187    if {[$data inrange [list $load $mem -- --]]} {
188        set wval [$data interpolate wonks [list $load $mem -- --]]
189        return [list $p2p::wonks::version [expr {round($wval)}]]
190    }
191
192    # don't have any data -- we're forced to exec perftest and block
193    if {[catch {exec [file join $p2p::wonks::dir perftest]} msg] == 0
194          && [regexp {^([^ ]+) +([0-9]+)} $msg match vstr wval]} {
195        $data add [list $load $mem $wval 1]
196        set p2p::wonks::version $vstr
197        return [list $vstr $wval]
198    }
199
200    # can't even exec perftest -- return some large bogus value
201    return [list bogus 1000000]
202}
Note: See TracBrowser for help on using the repository browser.