ADDED Tests/memory.eagle Index: Tests/memory.eagle ================================================================== --- /dev/null +++ Tests/memory.eagle @@ -0,0 +1,144 @@ +############################################################################### +# +# memory.eagle -- +# +# Written by Joe Mistachkin. +# Released to the public domain, use at your own risk! +# +############################################################################### + +package require Eagle +package require Eagle.Library +package require Eagle.Test + +runTestPrologue + +############################################################################### + +package require System.Data.SQLite.Test +runSQLiteTestPrologue + +############################################################################### + +# +# NOTE: Report before test, before shutdown. +# +checkForSQLiteDirectories $test_channel +getSQLiteHandleCounts $test_channel +reportSQLiteResources $test_channel + +############################################################################### + +# +# NOTE: Make sure that SQLite core library is completely shutdown prior to +# starting any of the tests in this file. +# +shutdownSQLite $test_channel + +############################################################################### + +# +# NOTE: Report before test, after shutdown. +# +checkForSQLiteDirectories $test_channel +getSQLiteHandleCounts $test_channel +reportSQLiteResources $test_channel + +############################################################################### + +runTest {test memory-1.1 {SQLiteDataReader memory testing} -setup { + setupMemoryCounters counter + reportMemoryCounters $test_channel counter initial + + setupDb [set fileName $test_repository_file] \ + "" "" "" "" "Read Only=True" false false +} -body { + set connection [getDbConnection] + + set sql "SELECT rid, rcvid, size, uuid, content FROM blob ORDER BY rid;" + + set working(rowCount) 0 + set working(contentLength) 0 + + set working(time) [time { + set dataReader [sql execute -execute reader -format datareader \ + -alias $db $sql] + + while {[$dataReader Read]} { + incr working(rowCount) + + set working(rid) [$dataReader GetValue \ + [$dataReader GetOrdinal rid]] + + set working(rcvid) [$dataReader GetValue \ + [$dataReader GetOrdinal rcvid]] + + set working(size) [$dataReader GetValue \ + [$dataReader GetOrdinal size]] + + set working(uuid) [$dataReader GetValue \ + [$dataReader GetOrdinal uuid]] + + set working(content) [$dataReader -create -alias GetValue \ + [$dataReader GetOrdinal content]] + + incr working(contentLength) [$working(content) Length] + + set working(counter1Cur) [$counter(1) RawValue] + set working(counter2Cur) [$counter(2) RawValue] + set working(counter3Cur) [$counter(3) RawValue] + + if {![info exists working(counter1Max)] || \ + $working(counter1Cur) > $working(counter1Max)} then { + set working(counter1Max) $working(counter1Cur) + reportMemoryCounters $test_channel counter current + cleanupMemory connection + } + + if {![info exists working(counter2Max)] || \ + $working(counter2Cur) > $working(counter2Max)} then { + set working(counter2Max) $working(counter2Cur) + reportMemoryCounters $test_channel counter current + cleanupMemory connection + } + + if {![info exists working(counter3Max)] || \ + $working(counter3Cur) > $working(counter3Max)} then { + set working(counter3Max) $working(counter3Cur) + reportMemoryCounters $test_channel counter current + cleanupMemory connection + } + } + }] + + reportMemoryCounters $test_channel counter final + + tputs $test_channel [appendArgs \ + "---- found " $working(rowCount) " rows with " \ + $working(contentLength) " bytes of content in " \ + $working(time) \n] +} -cleanup { + freeDbConnection + + unset -nocomplain dataReader connection + + cleanupDb $fileName db true false false + + unset -nocomplain working sql counter db fileName +} -constraints {eagle command.object monoBug28 command.sql compile.DATA SQLite\ +System.Data.SQLite fossil_repository_file variable_test_repository_file} \ +-result {}} + +############################################################################### + +# +# NOTE: Report after test. +# +checkForSQLiteDirectories $test_channel +getSQLiteHandleCounts $test_channel +reportSQLiteResources $test_channel + +############################################################################### + +runSQLiteTestEpilogue +runTestEpilogue Index: lib/System.Data.SQLite/common.eagle ================================================================== --- lib/System.Data.SQLite/common.eagle +++ lib/System.Data.SQLite/common.eagle @@ -2467,10 +2467,106 @@ set code 0 } return $code } + + proc cleanupMemory { varName {quiet false} } { + if {[haveSQLiteObjectCommand] && \ + [string length $varName] > 0} then { + # + # NOTE: Refer to the specified variable (e.g. "connection") in the + # context of our caller. The opaque object handle for an + # ADO.NET connection previously returned by [getDbConnection] + # should be stored there. + # + upvar 1 $varName connection + + if {[catch { + object invoke $connection ReleaseMemory + } result]} then { + if {!$quiet} then { + tputs $::test_channel [appendArgs \ + "==== WARNING: failed to release database memory, error: " \ + \n\t $result \n] + } + } + } + + if {[llength [info commands debug]] > 0} then { + if {[catch { + uplevel 1 [list debug purge] + } result]} then { + if {!$quiet} then { + tputs $::test_channel [appendArgs \ + "==== WARNING: failed to purge call frame, error: " \ + \n\t $result \n] + } + } + + if {[catch { + uplevel 1 [list debug cleanup] + } result]} then { + if {!$quiet} then { + tputs $::test_channel [appendArgs \ + "==== WARNING: failed to cleanup interpreter, error: " \ + \n\t $result \n] + } + } + + if {[catch { + uplevel 1 [list debug collect] + } result]} then { + if {!$quiet} then { + tputs $::test_channel [appendArgs \ + "==== WARNING: failed to collect garbage, error: " \ + \n\t $result \n] + } + } + } + } + + proc setupMemoryCounters { varName } { + if {[haveSQLiteObjectCommand]} then { + upvar 1 $varName counter + + set counter(1) [object create -alias \ + System.Diagnostics.PerformanceCounter Process \ + "Working Set" [file rootname [file tail $::bin_file]]] + + set counter(2) [object create -alias \ + System.Diagnostics.PerformanceCounter Process \ + "Working Set Peak" [file rootname [file tail $::bin_file]]] + + set counter(3) [object create -alias \ + System.Diagnostics.PerformanceCounter Process \ + "Private Bytes" [file rootname [file tail $::bin_file]]] + } + + return "" + } + + proc reportMemoryCounters { channel varName prefix } { + if {[haveSQLiteObjectCommand]} then { + upvar 1 $varName counter + + tputs $channel [appendArgs \ + "---- " $prefix " counter \"" \ + [object invoke $counter(1) CounterName] "\" value is " \ + [object invoke $counter(1) RawValue] \n] + + tputs $channel [appendArgs \ + "---- " $prefix " counter \"" \ + [object invoke $counter(2) CounterName] "\" value is " \ + [object invoke $counter(2) RawValue] \n] + + tputs $channel [appendArgs \ + "---- " $prefix " counter \"" \ + [object invoke $counter(3) CounterName] "\" value is " \ + [object invoke $counter(3) RawValue] \n] + } + } proc collectGarbage { channel {milliseconds 1000} {quiet true} } { if {[haveSQLiteObjectCommand]} then { if {[catch { object invoke GC GetTotalMemory false