::namespace eval ::qw::memoryutil {} ::proc ::qw::memoryutil::memory_refresh {} { # ------------------------------------------------------------ # background virtual memory refresher (windows only for now) # ------------------------------------------------------------ /* { The virtual memory refresher tries to keep newviews memory loaded by accessing it periodically. We use an ::after xxx background task to run the refresher from time to time. We believe windows kicks out newviews memory to the virtual memory swap file and reloads it on demand, but reloading seems to take "forever". Users may believe the problem is with newviews and might even kill the process. Note: we don't run the refresher on linux (yet). */ } ::if {![::qw::command_exists [::qw::system]]} { ::return; } ::set rwb1_debug 0; ::if {$rwb1_debug} { ::switch -- $::tcl_version { 8.4 { ::set Milli0 [::clock clicks -milliseconds]; } 8.6 { ::set Micro0 [::clock clicks -microseconds]; } } } [::qw::system] cpp_memory_refresh; ::if {$rwb1_debug} { ::switch -- $::tcl_version { 8.4 { ::set Milli1 [::clock clicks -milliseconds]; ::set Milli [::expr {$Milli1-$Milli0}]; ::puts "rwb1_debug,::qw::memoryutil::memory_refresh,milliseconds==$Milli"; } 8.6 { ::set Micro1 [::clock clicks -microseconds]; ::set Micro [::expr {$Micro1-$Micro0}]; ::puts "rwb1_debug,::qw::memoryutil::memory_refresh,microseconds==$Micro"; } } } /* { We set the refresh interval to 5 minutes which is somewhat arbitrary. */ } ::set Interval [::expr {5*60*1000}]; ::after $Interval [::list ::qw::memoryutil::memory_refresh]; } ::if {$::tcl_platform(platform) eq "windows"} { ::proc ::qw::memoryutil::memory_physical {} { /* { Returns the total physical memory on this computer as reported by the operating system. 2.28.3 Switched to twapi because Windows GlobalMemoryStatus only handles 4G and don't have GlobalMemoryStatus in vc60. Don't want to upgrade because going to gnu anyway. twapi get_memory_info options -totalphysical -availphysical -totalcommit -availcommit -swapfiles -swapfiledetail -pagesize -minappaddr -maxappaddr -allocationgranularity additional 8.6 options -processtotalvirtual -processavailvirtual -processavailcommit -processcommitlimit */ } #2.28.3 - switched from windows api to twapi because of 4G limit /* { This returns total physical, not total in process virtual space. */ } # ::qw::packages::package_require_twapi; ::return [::lindex [::twapi::get_memory_info -totalphysical] end]; } ::proc ::qw::memoryutil::memory_allocated {} { /* { Returns the total memory allocated to this application as reported by the operating system. This is the total allocated. Whether any of it is in ram or in virtual memory swap file is unknown and generally is not of concern. */ } ::return [::expr {[::qw::memoryutil::memory_physical]-[::qw::memoryutil::memory_available]}]; } ::proc ::qw::memoryutil::memory_available {} { /* { */ } #2.28.3 - switched from windows api to twapi because of 4G limit # ::qw::packages::package_require_twapi; ::return [::lindex [::twapi::get_memory_info -availphysical] end]; } ::proc ::qw::memoryutil::process_memory_total {} { # 2.33.3 ::if {$::tcl_version==8.4} { ::return [::qw::memoryutil::memory_physical] } # ::qw::packages::package_require_twapi; ::set Total [::lindex [::twapi::get_memory_info -processtotalvirtual] end]; ::set Available [::lindex [::twapi::get_memory_info -processavailvirtual] end]; ::set Allocated [::expr {$Total-$Allocated}]; ::return $Allocated; } ::proc ::qw::memoryutil::process_memory_allocated {} { # 2.33.3 ::if {$::tcl_version==8.4} { ::return [::qw::memoryutil::memory_allocated]; } # ::qw::packages::package_require_twapi; ::set Total [::lindex [::twapi::get_memory_info -processtotalvirtual] end]; ::set Available [::lindex [::twapi::get_memory_info -processavailvirtual] end]; ::set Allocated [::expr {$Total-$Available}]; ::return $Allocated; } ::proc ::qw::memoryutil::process_memory_available {} { # 2.33.3 ::if {$::tcl_version==8.4} { ::return [::qw::memoryutil::memory_available]; } # ::qw::packages::package_require_twapi; ::set Value [::lindex [::twapi::get_memory_info -processavailvirtual] end]; ::return $Value; } } # ------------------------------------------------------------ # memory methods # ------------------------------------------------------------ ::if {$::tcl_platform(platform) eq "unix"} { ::proc ::qw::memoryutil::linux_proc_scrape {Path Field} { /* { Extracts the field from /proc/info on linux. If there is any problem at all, returns "". Since all of the numbers in /proc/meminfo are in KB, we multiply the result by 1024. Here is a /proc/meminfo file content: MemTotal: 16339472 kB MemFree: 4216068 kB MemAvailable: 13263172 kB Buffers: 795352 kB Cached: 8788608 kB SwapCached: 0 kB Active: 4704152 kB Inactive: 6689804 kB Active(anon): 1876204 kB Inactive(anon): 638880 kB Active(file): 2827948 kB Inactive(file): 6050924 kB Unevictable: 64 kB Mlocked: 64 kB SwapTotal: 16684028 kB SwapFree: 16684028 kB Dirty: 56 kB Writeback: 0 kB AnonPages: 1810084 kB Mapped: 608944 kB Shmem: 705092 kB Slab: 565684 kB SReclaimable: 509548 kB SUnreclaim: 56136 kB KernelStack: 9712 kB PageTables: 42492 kB NFS_Unstable: 0 kB Bounce: 0 kB WritebackTmp: 0 kB CommitLimit: 24853764 kB Committed_AS: 6166668 kB VmallocTotal: 34359738367 kB VmallocUsed: 0 kB VmallocChunk: 0 kB HardwareCorrupted: 0 kB AnonHugePages: 1179648 kB CmaTotal: 0 kB CmaFree: 0 kB HugePages_Total: 0 HugePages_Free: 0 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB DirectMap4k: 175248 kB DirectMap2M: 8120320 kB DirectMap1G: 8388608 kB */ } ::set rwb1_debug 0; ::if {$rwb1_debug} {::puts "rwb1_debug,::qw::memoryutil::linux_proc_scrape,1000.0";} ::set Handle [::open $Path "r"]; ::set Data [::read $Handle]; ::if {$rwb1_debug} {::puts "rwb1_debug,::qw::memoryutil::linux_proc_scrape,1000.1,Data=$Data";} ::close $Handle; ::if {$rwb1_debug} {::puts "rwb1_debug,::qw::memoryutil::linux_proc_scrape,1000.2";} ::set Pos [::lsearch $Data $Field]; ::if {$rwb1_debug} {::puts "rwb1_debug,::qw::memoryutil::linux_proc_scrape,1000.3,Pos==$Pos";} ::if {$Pos<0} { ::if {$rwb1_debug} {::puts "rwb1_debug,::qw::memoryutil::linux_proc_scrape,1000.4";} ::return ""; } ::if {$rwb1_debug} {::puts "rwb1_debug,::qw::memoryutil::linux_proc_scrape,1000.5";} ::incr Pos 1; ::set Value [::lindex $Data $Pos]; ::if {![::string is integer $Value]} { ::if {$rwb1_debug} {::puts "rwb1_debug,::qw::memoryutil::linux_proc_scrape,1000.6,Value==$Value";} ::return ""; } ::if {$rwb1_debug} {::puts "rwb1_debug,::qw::memoryutil::linux_proc_scrape,1000.9,Value==$Value";} ::set Value [::expr {$Value*1024}]; ::if {$rwb1_debug} {::puts "rwb1_debug,::qw::memoryutil::linux_proc_scrape,1000.10,Value==$Value";} ::return $Value; } ::proc ::qw::memoryutil::memory_physical {} { /* { Returns the total physical memory on this computer as reported by the operating system. */ } /* { We scrape "MemTotal:" out of file /proc/meminfo. */ } # ::set MemInfoPath "c:/test/meminfo.txt"; ::set MemInfoPath "/proc/meminfo"; ::set Value [::qw::memoryutil::linux_proc_scrape $MemInfoPath "MemTotal:"]; ::if {$Value eq ""} { ::set Value [::expr {8*1024*1024*1024}]; } ::return $Value; } ::proc ::qw::memoryutil::memory_allocated {} { /* { Returns the total memory allocated to this application as reported by the operating system. This is the total allocated. Whether any of it is in ram or in virtual memory swap file is unknown and generally is not of concern. */ } ::set Value [::expr {[::qw::memory_physical]-[::qw::memory_available]}]; ::return $Value; } ::proc ::qw::memoryutil::memory_available {} { /* { */ } ::set MemInfoPath "/proc/meminfo"; ::set Value [::qw::memoryutil::linux_proc_scrape $MemInfoPath "MemAvailable:"]; ::if {$Value eq ""} { ::set Value [::expr {8*1024*1024*1024}]; } ::return $Value; } ::proc ::qw::memoryutil::process_memory_total {} { # unimplemented ::return 0; } ::proc ::qw::memoryutil::process_memory_allocated {} { # unimplemented ::return 0; } ::proc ::qw::memoryutil::process_memory_available {} { # unimplemented ::return 0; } }