>> Wanna know what's odd? I have a significant increase in responsiveness
>> by keeping virtual memory turned OFF for as long as possible. I don't
>> run com.apple.dynamic-pager.plist at system start -- I have a watchdog
>> script that keeps an eye on the available memory, and runs it when
>> things are tight.
>
>
> I'd like more details on this.

Ok.

First, dynamic pager.plist:

pbcopy < //Library/LaunchDaemons/com.apple.dynamic_pager.plist
Kleiman-ibook:~ michael$

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd";>
<plist version="1.0">
<dict>
        <key>Label</key>
        <string>com.apple.dynamic_pager</string>
        <key>ProgramArguments</key>
        <array>
                <string>/sbin/dynamic_pager-wrapper</string>
                <string>-F</string>
                <string>/tmp/swapFiles/swapfile</string>
                <string>-S</string>
                <string>134217728</string>
                <string>-H</string>
                <string>16000000</string>
                <string>-L</string>
                <string>150217729</string>
        </array>
        <key>RunAtLoad</key>
        <false/>
</dict>
</plist>

Note the following:
1. This is /Library, not /System/Library. This one overrides the system one.
2. RunAtLoad is false.
3. I'm using fixed size, collapsible swapfiles. I found that
adjustable sized swapfiles pretty much never clean up (seems to only
clean down to the high-water mark, and never collapse down to reuse
discarded pages.) This works better for small memory machines that use
a lot of swap.

So what triggers this?

Kleiman-ibook:~ michael$ pbcopy <
/Library/LaunchDaemons/michael.pagerwatch.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd";>
<plist version="1.0">
<dict>
        <key>Label</key>
        <string>michael.pager-watch</string>
        <key>Program</key>
        <string>/Users/Shared/Library/Launchd/bin/pagerwatch</string>
        <key>StartInterval</key>
        <integer>10</integer>
</dict>
</plist>

Kleiman-ibook:~ michael$ pbcopy < /Users/Shared/Library/Launchd/bin/pagerwatch

#!/bin/bash
# Bug: We really need to fetch and add free, active, and inactive.
#  Wired isn't accurate.

sleep 11

free=`vm_stat |     egrep     ' free' | awk '{print $NF}' | sed s,\\\\.,,`
active=`vm_stat |   egrep   ' active' | awk '{print $NF}' | sed s,\\\\.,,`
inactive=`vm_stat | egrep ' inactive' | awk '{print $NF}' | sed s,\\\\.,,`

freeTrig=4000
availTrig=8000
totalTrig=16000
reportTrig=25000

total=$(($free + $inactive + $active))
available=$(($free + $inactive))

[ $total -lt $reportTrig ] && echo "Debug: Free, Inactive, Active,
Total: $free ($freeTrig) $inactive ($availTrig) $active $total
($totalTrig)"


if  [ ! -f /tmp/startSwap ] ;
then {
        # Don't run dynamic pager if we have enough free space.
        [ $free -gt $freeTrig ] && exit 0 ;
        [ $available -gt $availTrig ] && exit 0 ;
        [ $total -gt $totalTrig ] && exit 0 ;
} ;
fi

# Remember: When pager isn't running, wired has all the private data, while
# active has the code pages (replacable from disk) still in use.
# "Free" and "inactive" are both immediately available.
# "Active" is "thrashing" space.

# Ok, we're tight on space, start pager and trade disk space for speed.
mkdir /tmp/swapFiles
launchctl start com.apple.dynamic_pager
launchctl remove michael.pager-watch

So the first thing it does: Wait 11 seconds to make launchd happy. It
then checks for /tmp/startSwap; if found, it skips the tests and
creates the swap. As I say this, I'm looking at a bug -- the test
needs to come before it tries to call "awk" and check the available
memory.

If there is enough memory, it is happy and does nothing. Otherwise, it
turns pager on, and itself off.

The sleep comes first: In the past, I tried testing first, and
sleeping later; this failed when the memory was so tight that launchd
could not launch a new shell to run this again. So, I make sure that
this testing program is sitting there, waiting for a chance to run.
Sadly, it still needs to use awk, so there are limits (awk is ...
big.)

In the last 9 months, there has only been one time where the system
failed to launch dynamic pager that was untrackable. There is one
program that gobbles so much memory in one big chunk (Ufo-AI) that
this system consistently does not have the chance to start the pager
-- hence the need for "startSwap". The rest of the time it just works.

Now, the numbers are "fine tuning" -- these work for my PPC, 1 GB
system. "totalTrig" is the primary trigger -- when the available
memory drops below this, start up. It pretty much only triggers during
a Time Machine backup run, and this one value can be raised up to give
more safety room. Too high and this just has no effect; too low and
the system can fail to start pager before memory starves.

I've got one more script in here, but I'm not nearly as happy with
this one. This one has the job of running purge every so often, to
clean up unused memory. The goal here was to slow down swapfile
creation -- surprisingly, I found that swapfiles would come in large
amounts as soon as swapping was needed, and this kept the swapfile
usage down for a couple of days. The problem?
1. Java programs can cause a system crash when a purge comes in
(windowserver seems to hang).
2. It causers random 10-25 second system pauses, where nothing happens at all.
3. Overall, it seems to have less of a positive effect since I added
pager watch (it was more useful before that).

Kleiman-ibook:~ michael$ pbcopy <
/Library/LaunchDaemons/michael.purgewatch.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd";>
<plist version="1.0">
<dict>
        <key>Label</key>
        <string>michael.purge-watch</string>
        <key>Program</key>
        <string>/Users/Shared/Library/Launchd/bin/purgewatch</string>
        <key>StartInterval</key>
        <integer>10</integer>
</dict>
</plist>

Kleiman-ibook:~ michael$ pbcopy < /Users/Shared/Library/Launchd/bin/purgewatch


#!/bin/bash
# Purge loop script.
# Job: Run purge every so often to keep memory available.
# Test: If free space is too low, run purge and wait a long time.
# Otherwise, wait a short time.
#
# What is too low? For now, 9000 -- tune it later.
# Alright, pager seems to add a swapfile around 12,000 free.
# Set a new target of 13,500
#
# Cavets: This has an interesting interaction with pager-watch.
# If pager isn't running yet, and space fills up, then the system
# will throw out the unused cache pages nicely. We don't *need*
# this in that situation. However, the "yellow" page set gets larger
# and larger, until pager is triggered.
#
# The problem? Well, those yellow pages are the active programs. They
# may include code pages that aren't being used anymore (and we don't
# need them, and want to purge them), but they'll also include all
# the currently active pages.
# Bottom line: This slows the system down when a purge happens prior
# to the paging system happens. Maybe turn this off until paging, and retest?

reportTrig=15500
purgeTrig=13500
goodTrig=20000
purgeSleep=3600 # An hour
noPurgeLongSleep=76000  # about a day
waitSleep=60    # No purge, check again in a minute.

free=`vm_stat | egrep ' free' | awk '{print $NF}' | sed s,\\\\.,,`
[ $free -lt $reportTrig ] && echo purge test: free space $free

if [ $free -gt $purgeTrig ] ;
then {
        [ $free -lt $reportTrig ] && echo not purging, sleep $waitSleep
        sleep $waitSleep
# exit

} else {
        echo purging
        purge
        free=`vm_stat | egrep ' free' | awk '{print $NF}' | sed s,\\\\.,,`
        echo after purging, free is $free
        if [ $free -lt $goodTrig ] ;
        then {
                echo bad, long sleep $noPurgeLongSleep
                sleep $noPurgeLongSleep ;
                # Exit

        } else {
                echo good, short sleep $purgeSleep
                sleep $purgeSleep ;
                free=`vm_stat | egrep ' free' | awk '{print $NF}' | sed 
s,\\\\.,,`
                [ $free -lt $goodTrig ] && {
                    echo After short sleep, no room. Sleep $noPurgeLongSleep
                    sleep $noPurgeLongSleep
                }
        }
        fi ;
} ;
fi

-- 
Political and economic blog of a strict constitutionalist
http://StrictConstitution.BlogSpot.com
_______________________________________________
MacOSX-talk mailing list
[email protected]
http://www.omnigroup.com/mailman/listinfo/macosx-talk

Reply via email to