source: trunk/p2p/wonks.tcl @ 1926

Last change on this file since 1926 was 1273, checked in by mmc, 15 years ago

Major reorganization of p2p code, and support for solicit/proffer
messages.

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) 2008  Purdue Research Foundation
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.