>> 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
