LarsJ Posted January 29, 2023 Share Posted January 29, 2023 (edited) Overview The interest in time measurements and speed comparisons arose primarily from these examples of using compiled code in AutoIt: Accessing AutoIt Variables Using C# and VB Code in AutoIt The first versions of Runtime and Speed Comparison reports appear in this post from March 2017 and in this post half a year later. Over the last 5 - 6 years, a set of small helper functions have been developed to make it easier and faster to create a new report. It's these small helper functions that are now gathered in an include file. The functions handle settings and options to test a new script during the development process, and to generate the final report through a complete test cycle, where the script can be executed as both 32 and 64 bit code. The include file also contains functions to present the time measurements with header sections and aligned rows and columns in the report. During the same years, the individual Runtime scripts have developed in a direction where existing scripts can be used as templates for creating new scripts. First of all, the Runtime scripts have achieved a common structure, such that the most important updates during the creation of a new script consist of adjusting the code to perform the specific time measurements. Development of this project has mainly taken place during the last year at the same time as development of Virtual TreeViews. This thread is a summary of the entire development process over the last 5 - 6 years. Basic ideasThe ideas for the whole project have been somewhat diffuse throughout this long period. The first time measurements 5 - 6 years ago were performed with very simple scripts that were run first as 32 and then as 64 bit code and resulted in 2 small reports. Using an editor, the reports were combined into a single report. It was a slow and tedious process. The considerations surrounding the entire project have mainly revolved around the possibilities of creating easy-to-use and flexible time measurement code, which can also be implemented relatively simply, preferably through a single include file and a single Runtime script. The following considerations are copies of old notes. The overall purpose of runtime measurements and speed comparisons: Time measurements to compare the execution speed of different implementations of code to perform the same task. To create simple, clear reports with headers and time measurements presented in aligned rows and columns. At the same time, the reports must appear so that they actually provide useful and usable information. The overall objectives expressed in more concrete development goals: Time measurements and comparisons must be easy and flexible Ideally, you should not spend too much time coding a new test Must also contain enough features to provide real information Preferably only one include file and only one script file Clear and manageable reports in a simple text file Code implementation of the ideas in an include file and Runtime scripts: Create a number of small but generally useful helper functions Structured script files that can be run in test and report modes Step-by-step development from a simple test towards the desired result Create example scripts that can act as templates for new scripts Posts below Below in this post there is first a presentation of the project illustrated through 2 Runtime reports. Then there is a description of Runtime scripts and the include file. Then follows an example of comparison of the Map data type and Dictionary object. Finally, there is a description of some selected features. The second post concerns the comparison of AutoIt and VB.NET code for executing functions used in Virtual TreeViews. It's a more advanced example that, among other things, deals with the time measurement of a GUI creation, which is complicated by a GUI main loop. The example also covers time measurement of sub-tasks of larger AutoIt functions and VB.NET methods. Old reports Fast Array Management Functions UDF Fast Array Sorting and Management Functions UDF Fast General Array Management Functions UDF Fast SQLite Management Functions UDF Runtimes and Speed Comparisons If code performance is a significant or decisive factor in a project, it's necessary to be able to measure and compare runtimes in different implementations of the code. These topics are the focus of this example. The basic ideaOf course, depending on the code that's target of runtime measurements and speed comparisons, there can be a lot of difference in performing these measurements and comparisons. There may also be a difference in the degree of detail. Therefore, it's not easy to create a set of generally applicable functions that can be used in all cases. The basic idea is to make some small but generally useful helper functions as well as a number of example scripts that can act as templates for other scripts. It's illustrated by this result of a comparison of the Map data type and the Dictionary object: (Examples\Map vs Dict Obj\7) Map vs Dict Obj - Large data.txt) expandcollapse popupMap Data Type vs Dictionary Object Map Data Type vs Dictionary Object Map Data Type: Int and Str Keys Dictionary Object: Floats and Strings Code executed as 32-bit code Code executed as 64-bit code Code executed as 32-bit code Code executed as 64-bit code ================================== ================================== ================================== ================================== 100 key/item pairs 100 key/item pairs 100 key/item pairs 100 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 0.0704 Time to SET integers: 0.0565 Time to SET floats: 0.3754 Time to SET floats: 0.2815 Time to SET strings: 0.1532 Time to SET strings: 0.1446 Time to SET strings: 0.4269 Time to SET strings: 0.3360 Time to GET integers: 0.0294 Time to GET integers: 0.0310 Time to GET floats: 0.1330 Time to GET floats: 0.1103 Time to GET strings: 0.0856 Time to GET strings: 0.0848 Time to GET strings: 0.2383 Time to GET strings: 0.1792 500 key/item pairs 500 key/item pairs 500 key/item pairs 500 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 0.2845 Time to SET integers: 0.3155 Time to SET floats: 0.9314 Time to SET floats: 0.7657 Time to SET strings: 0.5161 Time to SET strings: 0.5386 Time to SET strings: 1.4497 Time to SET strings: 1.2165 Time to GET integers: 0.1438 Time to GET integers: 0.1430 Time to GET floats: 0.6120 Time to GET floats: 0.4779 Time to GET strings: 0.3881 Time to GET strings: 0.4250 Time to GET strings: 1.1522 Time to GET strings: 0.8680 1,000 key/item pairs 1,000 key/item pairs 1,000 key/item pairs 1,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 0.5815 Time to SET integers: 0.4222 Time to SET floats: 1.6464 Time to SET floats: 1.4813 Time to SET strings: 1.2519 Time to SET strings: 0.8450 Time to SET strings: 2.9247 Time to SET strings: 2.2897 Time to GET integers: 0.2640 Time to GET integers: 0.2058 Time to GET floats: 1.6777 Time to GET floats: 1.0068 Time to GET strings: 1.1744 Time to GET strings: 0.6352 Time to GET strings: 2.6382 Time to GET strings: 1.9479 2,000 key/item pairs 2,000 key/item pairs 2,000 key/item pairs 2,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 1.0220 Time to SET integers: 0.8984 Time to SET floats: 3.0832 Time to SET floats: 2.5471 Time to SET strings: 2.3870 Time to SET strings: 1.9143 Time to SET strings: 5.4236 Time to SET strings: 4.5600 Time to GET integers: 0.5757 Time to GET integers: 0.4635 Time to GET floats: 2.7094 Time to GET floats: 1.9528 Time to GET strings: 1.6085 Time to GET strings: 1.3010 Time to GET strings: 4.9349 Time to GET strings: 3.7270 5,000 key/item pairs 5,000 key/item pairs 5,000 key/item pairs 5,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 3.3220 Time to SET integers: 2.2484 Time to SET floats: 7.4964 Time to SET floats: 6.1954 Time to SET strings: 6.3406 Time to SET strings: 5.0748 Time to SET strings: 13.6452 Time to SET strings: 10.7693 Time to GET integers: 1.5223 Time to GET integers: 1.2511 Time to GET floats: 6.3741 Time to GET floats: 4.9845 Time to GET strings: 5.3801 Time to GET strings: 3.9012 Time to GET strings: 12.0680 Time to GET strings: 9.0251 10,000 key/item pairs 10,000 key/item pairs 10,000 key/item pairs 10,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 6.0779 Time to SET integers: 14.7813 Time to SET floats: 15.8554 Time to SET floats: 13.1285 Time to SET strings: 14.6669 Time to SET strings: 30.0126 Time to SET strings: 27.9988 Time to SET strings: 21.5308 Time to GET integers: 3.4560 Time to GET integers: 3.1868 Time to GET floats: 13.3380 Time to GET floats: 10.5645 Time to GET strings: 12.5274 Time to GET strings: 27.8362 Time to GET strings: 25.2268 Time to GET strings: 18.8272 20,000 key/item pairs 20,000 key/item pairs 20,000 key/item pairs 20,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 15.1094 Time to SET integers: 15.7496 Time to SET floats: 31.8926 Time to SET floats: 26.1521 Time to SET strings: 31.4898 Time to SET strings: 29.5214 Time to SET strings: 56.7112 Time to SET strings: 44.5216 Time to GET integers: 10.6543 Time to GET integers: 10.3457 Time to GET floats: 27.6738 Time to GET floats: 23.0620 Time to GET strings: 27.5882 Time to GET strings: 25.7260 Time to GET strings: 52.1412 Time to GET strings: 39.0526 50,000 key/item pairs 50,000 key/item pairs 50,000 key/item pairs 50,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 83.3686 Time to SET integers: 83.2603 Time to SET floats: 87.4275 Time to SET floats: 76.2308 Time to SET strings: 189.6272 Time to SET strings: 213.1701 Time to SET strings: 169.7711 Time to SET strings: 133.3019 Time to GET integers: 54.5296 Time to GET integers: 74.2480 Time to GET floats: 83.1935 Time to GET floats: 72.8659 Time to GET strings: 165.4224 Time to GET strings: 223.6139 Time to GET strings: 156.2999 Time to GET strings: 124.4494 100,000 key/item pairs 100,000 key/item pairs 100,000 key/item pairs 100,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 287.5362 Time to SET integers: 424.6736 Time to SET floats: 228.1745 Time to SET floats: 222.7141 Time to SET strings: 1160.2881 Time to SET strings: 1312.8416 Time to SET strings: 495.5310 Time to SET strings: 374.6756 Time to GET integers: 260.1878 Time to GET integers: 436.5270 Time to GET floats: 253.5833 Time to GET floats: 251.1678 Time to GET strings: 1141.9491 Time to GET strings: 1229.7874 Time to GET strings: 463.2597 Time to GET strings: 338.7806 250,000 key/item pairs 250,000 key/item pairs 250,000 key/item pairs 250,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 2282.7196 Time to SET integers: 3625.0477 Time to SET floats: 1025.6096 Time to SET floats: 1077.6101 Time to SET strings: 5437.2090 Time to SET strings: 5723.4847 Time to SET strings: 2153.5655 Time to SET strings: 1670.7098 Time to GET integers: 2192.6946 Time to GET integers: 3519.7249 Time to GET floats: 1386.6677 Time to GET floats: 1458.5401 Time to GET strings: 5335.2307 Time to GET strings: 5642.7701 Time to GET strings: 2107.6820 Time to GET strings: 1588.3297 500,000 key/item pairs 500,000 key/item pairs 500,000 key/item pairs 500,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 10214.3356 Time to SET integers: 13896.4168 Time to SET floats: 3139.8242 Time to SET floats: 3657.8827 Time to SET strings: 33276.5766 Time to SET strings: 34839.8803 Time to SET strings: 8217.9557 Time to SET strings: 5754.7453 Time to GET integers: 9894.3836 Time to GET integers: 13681.4498 Time to GET floats: 5346.3679 Time to GET floats: 5819.9051 Time to GET strings: 32589.8393 Time to GET strings: 34073.4712 Time to GET strings: 8167.2764 Time to GET strings: 5622.3269 750,000 key/item pairs 750,000 key/item pairs 750,000 key/item pairs 750,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: >10000.0000 Time to SET integers: >10000.0000 Time to SET floats: 6649.1308 Time to SET floats: 7796.9872 Time to SET strings: >10000.0000 Time to SET strings: >10000.0000 Time to SET strings: 18203.5605 Time to SET strings: 12103.5838 Time to GET integers: >10000.0000 Time to GET integers: >10000.0000 Time to GET floats: 12250.9218 Time to GET floats: 13320.5233 Time to GET strings: >10000.0000 Time to GET strings: >10000.0000 Time to GET strings: 18109.2658 Time to GET strings: 11949.4221 1,000,000 key/item pairs 1,000,000 key/item pairs 1,000,000 key/item pairs 1,000,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: >10000.0000 Time to SET integers: >10000.0000 Time to SET floats: 11376.8179 Time to SET floats: 13575.6015 Time to SET strings: >10000.0000 Time to SET strings: >10000.0000 Time to SET strings: >10000.0000 Time to SET strings: >10000.0000 Time to GET integers: >10000.0000 Time to GET integers: >10000.0000 Time to GET floats: >10000.0000 Time to GET floats: >10000.0000 Time to GET strings: >10000.0000 Time to GET strings: >10000.0000 Time to GET strings: >10000.0000 Time to GET strings: >10000.0000 The idea also includes a step-by-step development from a very simple test towards the desired result. If the report above is an expression of the desired result, then this report can be the result of the very first step: (Examples\Map vs Dict Obj\1) First test.txt) expandcollapse popupMap Data Type Integer Key Type Code executed as 64-bit code ================================== 50 key/item pairs ---------------------------------- Time to SET integers: 0.0424 Time to GET integers: 0.0130 100 key/item pairs ---------------------------------- Time to SET integers: 0.0407 Time to GET integers: 0.0213 250 key/item pairs ---------------------------------- Time to SET integers: 0.1100 Time to GET integers: 0.0532 500 key/item pairs ---------------------------------- Time to SET integers: 0.1931 Time to GET integers: 0.1072 750 key/item pairs ---------------------------------- Time to SET integers: 0.3153 Time to GET integers: 0.1657 1,000 key/item pairs ---------------------------------- Time to SET integers: 0.4527 Time to GET integers: 0.2069 1,250 key/item pairs ---------------------------------- Time to SET integers: 0.5125 Time to GET integers: 0.2848 1,500 key/item pairs ---------------------------------- Time to SET integers: 0.6048 Time to GET integers: 0.3319 2,000 key/item pairs ---------------------------------- Time to SET integers: 0.8835 Time to GET integers: 0.4269 2,500 key/item pairs ---------------------------------- Time to SET integers: 1.1045 Time to GET integers: 0.5984 3,000 key/item pairs ---------------------------------- Time to SET integers: 1.3860 Time to GET integers: 0.6671 5,000 key/item pairs ---------------------------------- Time to SET integers: 3.9250 Time to GET integers: 2.1894 7,500 key/item pairs ---------------------------------- Time to SET integers: 3.7580 Time to GET integers: 2.0071 10,000 key/item pairs ---------------------------------- Time to SET integers: 4.9168 Time to GET integers: 2.9690 12,500 key/item pairs ---------------------------------- Time to SET integers: 6.6247 Time to GET integers: 4.1951 15,000 key/item pairs ---------------------------------- Time to SET integers: 8.7360 Time to GET integers: 7.6631 20,000 key/item pairs ---------------------------------- Time to SET integers: 20.5859 Time to GET integers: 11.6363 Runtime scripts All Runtime scripts are identical in structure. A script starts with a Runtime settings section, then follows a Runtime data section and finally a larger Runtime functions section. The result of a Runtime script is a report with 1 - 4 columns as shown above. The absolute easiest way to create a new Runtime script is to copy and use an existing script as a template. Settings sectionThis is the Runtime settings section in Examples\Map vs Dict Obj\1) First test.au3: ; === Runtime and Speed Comparison settings === If Not Runtime_Settings( _ ; Settings for the current Runtime and Speed Comparison script. 2, _ ; Number of time measurements in each Runtime function. Default 2. ; <<<<<<<<<< 0, _ ; Max time in milliseconds for a single time measurement. 0 to disable. ; <<<<<<<<<< 0, _ ; Visual validation of Runtime data for $aRuntime_Rows[0]. 0 to disable. ; <<<<<<<<<< 1, _ ; 0 to NOT delete report file given by $gsRuntime_File. Only used when $lbRuntime_Main = 0. ; <<<<<<<<<< 1, _ ; Indicate the current of up to 4 Runtime test functions. Only used when $lbRuntime_Main = 0. ; <<<<<<<<<< 0 ) Then ; 1 to perform a complete test cycle through Runtime_Main() function. 0 to test the function above. ; <<<<<<<<<< ConsoleWrite( "Runtime_Settings(): @error = " & @error & @CRLF ) Exit 1 EndIf ; Command line parameters when Runtime_Main() is performing a complete test cycle. Must be ; executed after Runtime_Settings() and before Runtime_Main() because it updates settings. If $CmdLine[0] Then Runtime_CmdLineParams() If $gbRuntime_Main = 1 Then ; Runtime_Main() performs a complete test cycle, where up to 4 Runtime test functions are executed. ; Parameters must be set to match the test cycle of the current Runtime and Speed Comparison script. If Not Runtime_Main( _ 1, _ ; $giRuntime_Test_Functions = 1 ; The number of Runtime test functions to run. Must be defined below. ; <<<<<<<<<< 3, _ ; $giRuntime_Test_Bitness = 3 ; 1, 2 or 3 for 32/64 bit test or both for each Runtime test function. ; <<<<<<<<<< 1 ) Then ; $giRuntime_Test_LogInfo = 1 ; Runtime LogInfo is enabled as default to update the LogInfo ListView. ; <<<<<<<<<< ConsoleWrite( "Runtime_Main(): @error = " & @error & @CRLF ) Exit 1 EndIf EndIf The Settings section is used to define settings and options for executing the Runtime script. More information on the Settings section below. Data sectionThe default Runtime data section is coded this way: ; === Runtime and Speed Comparison data === Func Runtime_Data() ; Number of test rows ; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Local $aRuntime_Rows = [ 50, 100, 250, 500, 750, 1000, 1250, 1500, 2000, 2500, 3000, 5000, 7500, 10000, 12500, 15000, 20000 ] ;Local $aRuntime_Rows = [ 100, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 250000, 500000, 750000, 1000000, 2500000, 5000000, 10000000, 16000000 ] ;ReDim $aRuntime_Rows[12] ; Limit row numbers to 50 - 5,000 or 100 - 750,000 rows ; Row numbers must be in ascending order ; --- Additional data for the current Runtimes --- Local $aRuntime_Data = 0 ; ------------------------------------------------ Local $aRuntime_Data_All = [ $aRuntime_Rows, Runtime_Times(), $aRuntime_Data ] Return $aRuntime_Data_All EndFunc Using the Runtime data section will be demonstrated in next post. Functions sectionThe Runtime functions section connects $giRuntime_Test variable to Runtime functions and implements the functions: expandcollapse popup; === Runtime and Speed Comparison functions === ; For each Runtime test from 1 - 4, the output will result in a ; vertical column when the function is executed via Runtime_Main(). If $giRuntime_Test = 1 Then Runtimes1( Runtime_Data() ) ; <<<<<<<<<< If $giRuntime_Test = 2 Then Runtimes2( Runtime_Data() ) ; <<<<<<<<<< If $giRuntime_Test = 3 Then Runtimes3( Runtime_Data() ) ; <<<<<<<<<< If $giRuntime_Test = 4 Then Runtimes4( Runtime_Data() ) ; <<<<<<<<<< ; === Runtime and Speed Comparison test 1 === ; Map data type Func Runtimes1( $aRuntime_Data_All ) ; --- General local variables --- Local $iLineLen = 34 ; Length of a Runtime info line <= 80 Local $iTest, $iTests = $giRuntime_Time_Tests, $iBit = @AutoItX64 ? 64 : 32;, $bDisplay = $gbRuntime_Display_Once Local $aRuntime_Rows = $aRuntime_Data_All[0], $iRuntime_Rows = UBound( $aRuntime_Rows ), $aRuntime_Info[5+$iRuntime_Rows*($iTests+3)] Local $hTimer, $aTimes = $aRuntime_Data_All[1] ; Set individual max times by updating $aTimes[$i][2] Runtime_InitStorage( $aRuntime_Info ) ;$aTimes[1][2] = 30000 ; --- Local variables for the current function --- Local $iRows, $sRows = "key/item pairs" ; --- Create header information --- ; Both $sHeader1 and $sHeader2 must always be specified Local $sHeader1 = "Map Data Type" Local $sHeader2 = "Integer Key Type" Runtime_HeaderInfo( $iBit, $sHeader1, $sHeader2, $iLineLen, $aRuntime_Info ) ; --- Execute Runtime and Speed Comparison code for the current function --- For $i = 0 To $iRuntime_Rows - 1 $iRows = $aRuntime_Rows[$i] Local $mMap[], $v ; Visual validation of Runtime data for $aRuntime_Rows[0] ;If $iRows = $aRuntime_Rows[0] Then ;EndIf Runtime_RowsInfo( $i, $iRows, $sRows, 0, $iTests, $iLineLen, $aRuntime_Info ) ; 0 = $iCols ; Time test 1 $iTest = 0 If Not $aTimes[$iTest][2] Or ( $aTimes[$iTest][1] < $aTimes[$iTest][2] ) Then $hTimer = TimerInit() ; Time test 1 For $j = 0 To $iRows - 1 $mMap[$j] = $j Next $aTimes[$iTest][1] = TimerDiff( $hTimer ) Runtime_Info1( 8+$iTest, $i, $iTests, $iLineLen, $aTimes[$iTest][1], $aRuntime_Info, "Time to SET integers:" ) Else Runtime_Info2( 8+$iTest, $i, $iTests, $iLineLen, $aTimes[$iTest][2], $aRuntime_Info, "Time to SET integers:" ) EndIf ; Time test 2 $iTest += 1 If Not $aTimes[$iTest][2] Or ( $aTimes[$iTest][1] < $aTimes[$iTest][2] ) Then $hTimer = TimerInit() ; Time test 2 For $j = 0 To $iRows - 1 $v = $mMap[$j] Next $aTimes[$iTest][1] = TimerDiff( $hTimer ) Runtime_Info1( 8+$iTest, $i, $iTests, $iLineLen, $aTimes[$iTest][1], $aRuntime_Info, "Time to GET integers:" ) Else Runtime_Info2( 8+$iTest, $i, $iTests, $iLineLen, $aTimes[$iTest][2], $aRuntime_Info, "Time to GET integers:" ) EndIf Next ; Store Runtime information _FileWriteFromArray( $gsRuntime_File, $aRuntime_Info ) #forceref $v EndFunc ; === Runtime and Speed Comparison test 2 === Func Runtimes2( $aRuntime_Data_All ) #forceref $aRuntime_Data_All EndFunc ; === Runtime and Speed Comparison test 3 === Func Runtimes3( $aRuntime_Data_All ) #forceref $aRuntime_Data_All EndFunc ; === Runtime and Speed Comparison test 4 === Func Runtimes4( $aRuntime_Data_All ) #forceref $aRuntime_Data_All EndFunc The names of the Runtime functions are only used in this section and not in the include file. The function names can therefore be chosen freely. The code at top of the functions in the local variables sections is the same in all scripts in the Map vs Dict Obj example below. In the header sections, there are changes to the header texts. Otherwise, the biggest updates to the code take place in the For loops above. More information about Runtime functions in the walkthrough of the Map vs Dict Obj example below. Include filesIncludes\Runtimes.au3 Includes\Runtimes.au3 contains helper functions to perform runtime measurements and speed comparisons from a very simple test that generates a report with a single data column, to a complete test cycle of both 32 and 64 bit code, where the report consists of up to 4 data columns. There are three groups of main functions. The first group is about running a Runtime script with different settings and options that can generate reports with up to 4 columns of output. The output is genereted of up to 4 Runtime functions that run as either 32 or 64 bit code. Or of up to 2 Runtime functions that run as both 32 and 64 bit code. The second group handles vertical division and alignment of single and multiple columns into sections with headings and time measurements. The third group handles horizontal alignment of single and multiple columns. Includes\LogInfoDisplay.au3 Includes\LogInfoDisplay.au3 displays report output in a ListView when a complete test cycle is performed. This output can be turned on and off. A single test (as opposed to a complete test cycle) generates report output in SciTE console. SettingsThis is the Runtime_Settings() function in Includes\Runtimes.au3: ; Settings for the current Runtime and Speed Comparison script. ; ; Error code in @error Return value ; 1 -> Invalid parameter value Success -> 1 ; Failure -> 0 Func Runtime_Settings( _ $liRuntime_Time_Tests = 2, _ ; Number of time measurements in each Runtime function. Default 2. $lfRuntime_Max_Time = 0, _ ; Max time in milliseconds for a single time measurement. 0 to disable. $lbRuntime_Display_Once = 1, _ ; Visual validation of Runtime data for $aRuntime_Rows[0]. 0 to disable. $lbRuntime_File_Del = 1, _ ; 0 to NOT delete report file given by $gsRuntime_File. Only used when $lbRuntime_Main = 0. $liRuntime_Test = 1, _ ; Indicate the current of up to 4 Runtime test functions. Only used when $lbRuntime_Main = 0. $lbRuntime_Main = 0 ) ; 1 to perform a complete test cycle through Runtime_Main() function. 0 to test the function above. If Not ( 1 <= $liRuntime_Time_Tests ) Then Return SetError( 1, 0, 0 ) ; Integer If Not ( 0 <= $lfRuntime_Max_Time ) Then Return SetError( 1, 0, 0 ) ; Float If Not ( 0 = $lbRuntime_Display_Once Or $lbRuntime_Display_Once = 1 ) Then Return SetError( 1, 0, 0 ) ; Boolean If Not ( 0 = $lbRuntime_File_Del Or $lbRuntime_File_Del = 1 ) Then Return SetError( 1, 0, 0 ) ; Boolean If Not ( 1 <= $liRuntime_Test And $liRuntime_Test <= 4 ) Then Return SetError( 1, 0, 0 ) ; Integer If Not ( 0 = $lbRuntime_Main Or $lbRuntime_Main = 1 ) Then Return SetError( 1, 0, 0 ) ; Boolean $giRuntime_Time_Tests = $liRuntime_Time_Tests ; Must be the same number in each function to ensure vertical column alignment. $gfRuntime_Max_Time = $lfRuntime_Max_Time ; Set individual max times by updating $aTimes[$i][2] in the Runtime functions. $gbRuntime_Display_Once = $lbRuntime_Display_Once $gbRuntime_File_Del = $lbRuntime_File_Del ; 0: Possible to run the same script on several PCs with output in same report. $giRuntime_Test = $liRuntime_Test $gbRuntime_Main = $lbRuntime_Main Return 1 EndFunc The last parameter, $lbRuntime_Main, is also the most crucial, and is used to execute the Runtime script in two different modes. Note that the function referenced in the last part of the comment line: "0 to test the function above", is the function given by $liRuntime_Test = 1. The function identified through this variable is defined at top of the Function section this way: ; === Runtime and Speed Comparison functions === ; For each Runtime test from 1 - 4, the output will result in a ; vertical column when the function is executed via Runtime_Main(). If $giRuntime_Test = 1 Then Runtimes1( Runtime_Data() ) ; <<<<<<<<<< If $giRuntime_Test = 2 Then Runtimes2( Runtime_Data() ) ; <<<<<<<<<< If $giRuntime_Test = 3 Then Runtimes3( Runtime_Data() ) ; <<<<<<<<<< If $giRuntime_Test = 4 Then Runtimes4( Runtime_Data() ) ; <<<<<<<<<< The $liRuntime_Test / $giRuntime_Test variables define which Runtime function is to be executed. In default mode when $lbRuntime_Main = 0 the Runtime script is executed directly in SciTE with report output in the console. The report always contains only one column. This mode is used to develop and test the Runtime script. When $lbRuntime_Main = 1 a complete Runtime test cycle is performed, running the Runtime script up to 4 times through the RunWait() command. A report with up to 4 columns is generated. Optional output in a ListView in a LogInfoDisplay GUI. In both modes, the output is saved as a report in the form of a text file with the same name as the Runtime script. Settings and options are discussed in more detail below in the review of Map vs Dict Obj example. Map vs Dict Obj In Examples\Map vs Dict Obj\, the Map data type is compared to the Dictionary object. The example is developed from a simple test in 1) First test.au3 to a complete test with both 32 and 64 bit code in 7) Map vs Dict Obj - Large data.au3. Run the examples in SciTE with F5. 1) First test.au31) First test.au3 is shown in the code boxes above. Runtime settings Default Runtime settings except that visual validation of Runtime data is disabled. Visual validation of Runtime data is demonstrated in next post. Runtime data Only default Runtime data in the Map vs Dict Obj example. Using the Runtime data section is demonstrated in next post. Runtime functions Runtime functions can be executed in two modes. Either by running the script without calling Runtime_Main() (at bottom of the settings section), whereby a single Runtime function is executed directly and results in a single column in the report. This mode displays ConsoleWrite() output in SciTE console. This makes it possible to find and correct errors in the Runtime function. Or by calling Runtime_Main(), which indirectly executes up to 4 Runtime functions (or 2 functions as both 32 and 64 bit) through the RunWait() command and thus performs a complete test cycle and produces a report with up to 4 columns. Runtime_Main() may optionally generate output in a ListView in a LogInfoDisplay GUI. Whether or not Runtime_Main() is called is determined by the last parameter, $lbRuntime_Main, in Runtime_Settings() (at top of the settings section). If this parameter is 1, Runtime_Main() is called. If the parameter is 0, Runtime_Main() isn't called. In 1) First test.au3 $lbRuntime_Main = 0 and thus the script is executed in development and test mode with output in SciTE console. Only one Runtime function is used: Runtimes1(). The actual Runtime tests are performed in loops in the middle of Runtimes1(). Here, how long it takes to write and read different numbers of key/item pairs of integer type in a Map variable is measured. In the first scripts, small numbers of key/item pairs are used to avoid spending too much time running and testing scripts in SciTE. The script generates a report as shown above. 2) First cycle.au32) First cycle.au3 performs a complete test cycle of both 32 and 64 bit code through Runtime_Main() function. The only change to the code in 2) First cycle.au3 is that the last parameter, $lbRuntime_Main, in Runtime_Settings() is changed from 0 to 1. When the script is run in SciTE, progress information for script execution shows up in the console. A report is generated with output in the LogInfoDisplay ListView. The report with 2 columns is also stored in 2) First cycle.txt. In addition to settings in Runtime_Settings(), which are modified in Runtime_CmdLineParams(), execution of Runtime_Main() is determined through 3 additional function parameters. Last part of Runtime_Settings() ; Command line parameters when Runtime_Main() is performing a complete test cycle. Must be ; executed after Runtime_Settings() and before Runtime_Main() because it updates settings. If $CmdLine[0] Then Runtime_CmdLineParams() If $gbRuntime_Main = 1 Then ; Runtime_Main() performs a complete test cycle, where up to 4 Runtime test functions are executed. ; Parameters must be set to match the test cycle of the current Runtime and Speed Comparison script. If Not Runtime_Main( _ 1, _ ; $giRuntime_Test_Functions = 1 ; The number of Runtime test functions to run. Must be defined below. ; <<<<<<<<<< 3, _ ; $giRuntime_Test_Bitness = 3 ; 1, 2 or 3 for 32/64 bit test or both for each Runtime test function. ; <<<<<<<<<< 1 ) Then ; $giRuntime_Test_LogInfo = 1 ; Runtime LogInfo is enabled as default to update the LogInfo ListView. ; <<<<<<<<<< ConsoleWrite( "Runtime_Main(): @error = " & @error & @CRLF ) Exit 1 EndIf EndIf Runtime_CmdLineParams() ; Command line parameters when Runtime_Main() ; is performing a complete test cycle. Func Runtime_CmdLineParams() $giRuntime_Test = $CmdLine[1]+0 $gbRuntime_Main = $CmdLine[2]+0 $gbRuntime_3264 = $CmdLine[3]+0 If $gbRuntime_Main Then $gbRuntime_File_Del = 1 If $CmdLine[0] = 4 Then $ghRuntime_Info = HWnd( $CmdLine[4] ) ; To update Runtimes and Speed Comparisons LogInfo GUI EndFunc Runtime_Main() expandcollapse popup; Runtime_Main() performs a complete test cycle, where up to 4 Runtime test functions ; are executed. ; ; Error code in @error Return value ; 1 -> Invalid parameter value Success -> 1 ; Failure -> 0 Func Runtime_Main( _ $giRuntime_Test_Functions = 1, _ ; The number of Runtime test functions $giRuntime_Test_Bitness = 3, _ ; 1, 2 or 3 for 32/64 bit test or both $giRuntime_Test_LogInfo = 1 ) ; Runtime LogInfo is enabled as default ; Maximum up to 4 Runtime test functions for EITHER 32 OR 64 bit tests If Not ( 1 <= $giRuntime_Test_Functions And $giRuntime_Test_Functions <= 4 ) Then Return SetError( 1, 0, 0 ) If Not ( 1 <= $giRuntime_Test_Bitness And $giRuntime_Test_Bitness <= 3 ) Then Return SetError( 1, 0, 0 ) If $giRuntime_Test_Functions > 2 And $giRuntime_Test_Bitness = 3 Then Return SetError( 1, 0, 0 ) ; Maximum up to 2 Runtime test functions for BOTH 32 AND 64 bit tests $gbRuntime_3264 = $giRuntime_Test_Bitness = 3 ? 1 : 0 Local $sAutoItExePath = StringLeft( @AutoItExe, StringInStr( @AutoItExe, "\", 0, -1 ) ) If $giRuntime_Test_LogInfo Then ; Start Runtimes and Speed Comparisons LogInfo GUI Local $sScriptName = $gsRuntime_Path & "\LogInfoDisplay.au3" Run( $sAutoItExePath & "AutoIt3_x64.exe" & " /AutoIt3ExecuteScript " & """" & $sScriptName & """" & " " & """" & @ScriptName & """" ) $ghRuntime_Info = WinWaitActive( "[TITLE:LogInfoDisplay;CLASS:AutoIt v3 GUI]" ) EndIf FileDelete( $gsRuntime_File ) ; Runtime and Speed Comparison test 1 is always performed $giRuntime_Test = 1 ; Execute @ScriptName as 32 bit If BitAND( $giRuntime_Test_Bitness, 1 ) Then ConsoleWrite( @ScriptName & ": Runtime Test 1 - Performing 32-bit Runtimes and Speed Comparison Tests ..." & @CRLF ) RunWait( $sAutoItExePath & "AutoIt3.exe" & " /AutoIt3ExecuteScript " & """" & @ScriptName & """" & " " & $giRuntime_Test & " 2 " & $gbRuntime_3264 & " " & $ghRuntime_Info ) ; 32 bit code EndIf ; Execute @ScriptName as 64 bit If BitAND( $giRuntime_Test_Bitness, 2 ) Then ConsoleWrite( @ScriptName & ": Runtime Test 1 - Performing 64-bit Runtimes and Speed Comparison Tests ..." & @CRLF ) RunWait( $sAutoItExePath & "AutoIt3_x64.exe" & " /AutoIt3ExecuteScript " & """" & @ScriptName & """" & " " & $giRuntime_Test & " 2 " & $gbRuntime_3264 & " " & $ghRuntime_Info ) ; 64 bit code EndIf ; Runtime and Speed Comparison test 2 is only performed if $giRuntime_Test_Functions >= 2 If $giRuntime_Test_Functions >= 2 Then $giRuntime_Test = 2 ; Execute @ScriptName as 32 bit If BitAND( $giRuntime_Test_Bitness, 1 ) Then ConsoleWrite( @ScriptName & ": Runtime Test 2 - Performing 32-bit Runtimes and Speed Comparison Tests ..." & @CRLF ) RunWait( $sAutoItExePath & "AutoIt3.exe" & " /AutoIt3ExecuteScript " & """" & @ScriptName & """" & " " & $giRuntime_Test & " 2 " & $gbRuntime_3264 & " " & $ghRuntime_Info ) ; 32 bit code EndIf ; Execute @ScriptName as 64 bit If BitAND( $giRuntime_Test_Bitness, 2 ) Then ConsoleWrite( @ScriptName & ": Runtime Test 2 - Performing 64-bit Runtimes and Speed Comparison Tests ..." & @CRLF ) RunWait( $sAutoItExePath & "AutoIt3_x64.exe" & " /AutoIt3ExecuteScript " & """" & @ScriptName & """" & " " & $giRuntime_Test & " 2 " & $gbRuntime_3264 & " " & $ghRuntime_Info ) ; 64 bit code EndIf EndIf ; Runtime and Speed Comparison test 3 is only performed if $giRuntime_Test_Functions >= 3 ; And if you only test with EITHER 32 OR 64 bit code If $giRuntime_Test_Functions >= 3 Then $giRuntime_Test = 3 ; Execute @ScriptName as 32 bit If BitAND( $giRuntime_Test_Bitness, 1 ) Then ConsoleWrite( @ScriptName & ": Runtime Test 3 - Performing 32-bit Runtimes and Speed Comparison Tests ..." & @CRLF ) RunWait( $sAutoItExePath & "AutoIt3.exe" & " /AutoIt3ExecuteScript " & """" & @ScriptName & """" & " " & $giRuntime_Test & " 2 " & $gbRuntime_3264 & " " & $ghRuntime_Info ) ; 32 bit code EndIf ; Execute @ScriptName as 64 bit If BitAND( $giRuntime_Test_Bitness, 2 ) Then ConsoleWrite( @ScriptName & ": Runtime Test 3 - Performing 64-bit Runtimes and Speed Comparison Tests ..." & @CRLF ) RunWait( $sAutoItExePath & "AutoIt3_x64.exe" & " /AutoIt3ExecuteScript " & """" & @ScriptName & """" & " " & $giRuntime_Test & " 2 " & $gbRuntime_3264 & " " & $ghRuntime_Info ) ; 64 bit code EndIf EndIf ; Runtime and Speed Comparison test 4 is only performed if $giRuntime_Test_Functions = 4 ; And if you only test with EITHER 32 OR 64 bit code If $giRuntime_Test_Functions >= 4 Then $giRuntime_Test = 4 ; Execute @ScriptName as 32 bit If BitAND( $giRuntime_Test_Bitness, 1 ) Then ConsoleWrite( @ScriptName & ": Runtime Test 4 - Performing 32-bit Runtimes and Speed Comparison Tests ..." & @CRLF ) RunWait( $sAutoItExePath & "AutoIt3.exe" & " /AutoIt3ExecuteScript " & """" & @ScriptName & """" & " " & $giRuntime_Test & " 2 " & $gbRuntime_3264 & " " & $ghRuntime_Info ) ; 32 bit code EndIf ; Execute @ScriptName as 64 bit If BitAND( $giRuntime_Test_Bitness, 2 ) Then ConsoleWrite( @ScriptName & ": Runtime Test 4 - Performing 64-bit Runtimes and Speed Comparison Tests ..." & @CRLF ) RunWait( $sAutoItExePath & "AutoIt3_x64.exe" & " /AutoIt3ExecuteScript " & """" & @ScriptName & """" & " " & $giRuntime_Test & " 2 " & $gbRuntime_3264 & " " & $ghRuntime_Info ) ; 64 bit code EndIf EndIf Exit ; Exit is needed to prevent code in the calling script that EndFunc ; follows execution of Runtime_Main() from being executed. 3) Add strings.au3In 3) Add strings.au3, time measurements are also made when the Map key consists of strings. This gives 4 time tests in Runtimes1(). 4) Strings cycle.au3 executes both 32 and 64 bit code. 5) Map vs Dict Obj.au3Runtimes2() is implemented in 5) Map vs Dict Obj.au3 to measure write and read times for key/item pairs of types floats and strings in Dictionary objects. When the script is run in SciTE, both Runtimes1() and Runtimes2() are executed in a complete test cycle but only as 64 bit code and generates 2 columns in the report. This is determined through parameters in Runtime_Settings() and Runtime_Main(). A new complete test cycle is performed in 6) Map vs Dict Obj - Cycle.au3, where Runtimes1() and Runtimes2() are executed as both 32 and 64 bit code and generates 4 columns in the report. The difference between script 5) and 6) is the $giRuntime_Test_Bitness parameter in Runtime_Main() which is 2 in script 5) (64 bit only) and 3 in script 6) (32 and 64 bit). Note that there appears to be an issue with AutoIt integer keys in Dictionary objects. In these 4 small pieces of code, it's thus only the last one, where the integer key is converted to a floating point number, that works. $oDict = ObjCreate( "Scripting.Dictionary" ) $oDict( 2^3 ) = 2^3 $iItem = $oDict( 2^3 ) ; Err $oDict = ObjCreate( "Scripting.Dictionary" ) $oDict( 2^3+0 ) = 2^3+0 $iItem = $oDict( 2^3+0 ) ; Err $oDict = ObjCreate( "Scripting.Dictionary" ) $oDict( Int( 2^3 ) ) = Int( 2^3 ) $iItem = $oDict( Int( 2^3 ) ) ; Err $oDict = ObjCreate( "Scripting.Dictionary" ) $oDict( 2^3+0.0 ) = 2^3+0.0 $iItem = $oDict( 2^3+0.0 ) ; OK Therefore, floats have been chosen instead of integers to test Dictionary objects. Script 7) perform the same Runtime tests as script 6), but with larger numbers of key/item pairs. Therefore, a limit has been set on all time tests of 10 seconds. When a specific test takes 10 seconds or more, this test isn't repeated for higher numbers of key/item pairs. The purpose is to limit the total time consumption of a Runtime test. And especially during the execution of a complete test cycle. The report with 4 columns generated by script 7) is the desired result of the Map vs Dict Obj Runtime and Speed Comparison test. The report is shown above. Script 8 ) is the same as script 7) but without a time limit. Therefore, some time measurements with large numbers of key/item pairs will take an unacceptably long time. Script 8 ) has been tested on a 6½-year-old Windows 7 medium PC, and a 1½-year-old Windows 10 PC, which is a medium PC in the higher end. Feature examplesExamples\Features\ contains au3- and txt-files to demonstrate and implement various features and techniques in Runtime scripts. The scripts are customized copies of the Map vs Dict Obj examples above. Blank lineIn the case of 2 Runtime functions with different numbers of time measurements, the vertical alignment of the columns in the report will not be correct. In this situation, one or more blank lines can be added to ensure correct vertical alignment: ; Blank line $iTest = 0 ; Runtime_Info2() must be used as code to add a blank line is only included in this function Runtime_Info2( 8+$iTest, $i, $iTests, $iLineLen, $aTimes[$iTest][2], $aRuntime_Info, "" ) Since $iTest = 0, a blank line is inserted before the first time measurement. Multiple PCsThe documentation also applies to Repeat test.au3. Func Runtime_Settings( _ $liRuntime_Time_Tests = 2, _ ; Number of time measurements in each Runtime function. Default 2. $lfRuntime_Max_Time = 0, _ ; Max time in milliseconds for a single time measurement. 0 to disable. $lbRuntime_Display_Once = 1, _ ; Visual validation of Runtime data for $aRuntime_Rows[0]. 0 to disable. $lbRuntime_File_Del = 1, _ ; 0 to NOT delete report file given by $gsRuntime_File. Only used when $lbRuntime_Main = 0. $liRuntime_Test = 1, _ ; Indicate the current of up to 4 Runtime test functions. Only used when $lbRuntime_Main = 0. $lbRuntime_Main = 0 ) ; 1 to perform a complete test cycle through Runtime_Main() function. 0 to test the function above. If the parameters $lbRuntime_File_Del and $lbRuntime_Main are both set to the value 0, the same Runtime script can be executed several times with output in the same report. $lbRuntime_File_Del = 0 prevents the report from being deleted between each run. This adds output to the existing report and can generate a report with up to 4 columns. If an old report already exists, e.g. after a test of the Runtime script during the development process, such an old report must be deleted manually. $lbRuntime_File_Del = 0 also prevents this old report from being deleted. The technique can be used to repeat the same test on multiple PCs and thus compare the performance of the PCs. Copy the include file, Runtime script and report from one PC to the other and execute the Runtime script. Up to 4 PCs can be compared. Multiple PCs.txt: expandcollapse popupDictionary Object Dictionary Object Dictionary Object Dictionary Object Lenovo labtop, Win 7, 10½ year Lenovo labtop, Win 10, 1½ year Windows 7, medium, 6½ year Win 10, medium (high end), 1½ year Code executed as 64-bit code Code executed as 64-bit code Code executed as 64-bit code Code executed as 64-bit code ================================== ================================== ================================== ================================== 100 key/item pairs 100 key/item pairs 100 key/item pairs 100 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET floats: 0.8063 Time to SET floats: 0.5487 Time to SET floats: 0.2867 Time to SET floats: 0.3784 Time to SET strings: 0.5148 Time to SET strings: 0.6275 Time to SET strings: 0.3344 Time to SET strings: 0.3988 Time to GET floats: 0.1741 Time to GET floats: 0.2134 Time to GET floats: 0.1092 Time to GET floats: 0.1147 Time to GET strings: 0.2902 Time to GET strings: 0.3827 Time to GET strings: 0.2130 Time to GET strings: 0.2039 500 key/item pairs 500 key/item pairs 500 key/item pairs 500 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET floats: 1.1392 Time to SET floats: 1.3766 Time to SET floats: 0.7685 Time to SET floats: 0.7832 Time to SET strings: 2.4873 Time to SET strings: 2.2805 Time to SET strings: 1.1439 Time to SET strings: 1.2693 Time to GET floats: 0.7677 Time to GET floats: 0.9510 Time to GET floats: 0.4909 Time to GET floats: 0.5043 Time to GET strings: 1.4032 Time to GET strings: 1.9148 Time to GET strings: 0.8824 Time to GET strings: 0.9730 1,000 key/item pairs 1,000 key/item pairs 1,000 key/item pairs 1,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET floats: 2.0752 Time to SET floats: 2.4859 Time to SET floats: 1.3481 Time to SET floats: 1.3554 Time to SET strings: 3.3659 Time to SET strings: 4.3570 Time to SET strings: 2.2315 Time to SET strings: 2.3319 Time to GET floats: 1.5033 Time to GET floats: 1.8988 Time to GET floats: 0.9696 Time to GET floats: 1.0115 Time to GET strings: 2.8129 Time to GET strings: 3.8353 Time to GET strings: 1.7586 Time to GET strings: 1.9669 2,000 key/item pairs 2,000 key/item pairs 2,000 key/item pairs 2,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET floats: 8.5532 Time to SET floats: 4.8982 Time to SET floats: 2.5667 Time to SET floats: 2.5717 Time to SET strings: 13.5443 Time to SET strings: 8.7610 Time to SET strings: 4.4963 Time to SET strings: 8.2610 Time to GET floats: 3.0875 Time to GET floats: 3.8538 Time to GET floats: 2.2520 Time to GET floats: 1.9955 Time to GET strings: 5.6032 Time to GET strings: 7.8478 Time to GET strings: 3.5303 Time to GET strings: 3.8151 5,000 key/item pairs 5,000 key/item pairs 5,000 key/item pairs 5,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET floats: 9.9753 Time to SET floats: 20.1038 Time to SET floats: 6.2331 Time to SET floats: 6.2076 Time to SET strings: 16.4886 Time to SET strings: 23.9255 Time to SET strings: 10.9092 Time to SET strings: 11.0983 Time to GET floats: 8.0573 Time to GET floats: 16.2224 Time to GET floats: 5.1293 Time to GET floats: 4.9316 Time to GET strings: 165.4877 Time to GET strings: 23.7091 Time to GET strings: 97.2250 Time to GET strings: 10.2493 10,000 key/item pairs 10,000 key/item pairs 10,000 key/item pairs 10,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET floats: 24.4564 Time to SET floats: 26.8007 Time to SET floats: 13.2881 Time to SET floats: 13.3160 Time to SET strings: 45.0839 Time to SET strings: 55.7773 Time to SET strings: 22.2477 Time to SET strings: 22.2675 Time to GET floats: 16.2213 Time to GET floats: 23.9157 Time to GET floats: 10.8169 Time to GET floats: 11.1769 Time to GET strings: 28.8736 Time to GET strings: 44.6960 Time to GET strings: 19.0022 Time to GET strings: 20.1813 20,000 key/item pairs 20,000 key/item pairs 20,000 key/item pairs 20,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET floats: 39.3476 Time to SET floats: 66.9533 Time to SET floats: 42.9892 Time to SET floats: 26.5579 Time to SET strings: 70.2702 Time to SET strings: 102.8037 Time to SET strings: 45.2218 Time to SET strings: 45.4328 Time to GET floats: 32.2920 Time to GET floats: 49.4208 Time to GET floats: 23.5141 Time to GET floats: 21.7608 Time to GET strings: 64.1431 Time to GET strings: 99.0432 Time to GET strings: 39.1290 Time to GET strings: 40.4980 50,000 key/item pairs 50,000 key/item pairs 50,000 key/item pairs 50,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET floats: 156.7391 Time to SET floats: 162.8337 Time to SET floats: 80.6036 Time to SET floats: 71.8760 Time to SET strings: 226.3471 Time to SET strings: 278.2435 Time to SET strings: 136.6088 Time to SET strings: 125.2966 Time to GET floats: 117.4066 Time to GET floats: 128.5505 Time to GET floats: 74.6459 Time to GET floats: 63.8180 Time to GET strings: 200.8788 Time to GET strings: 267.0520 Time to GET strings: 118.9311 Time to GET strings: 113.6837 100,000 key/item pairs 100,000 key/item pairs 100,000 key/item pairs 100,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET floats: 477.4047 Time to SET floats: 401.4525 Time to SET floats: 229.3125 Time to SET floats: 174.6070 Time to SET strings: 633.1885 Time to SET strings: 659.5374 Time to SET strings: 379.1723 Time to SET strings: 290.4244 Time to GET floats: 430.3122 Time to GET floats: 354.1500 Time to GET floats: 252.8540 Time to GET floats: 151.3619 Time to GET strings: 592.1220 Time to GET strings: 641.9996 Time to GET strings: 344.2435 Time to GET strings: 274.9410 250,000 key/item pairs 250,000 key/item pairs 250,000 key/item pairs 250,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET floats: 2506.0299 Time to SET floats: 1831.0226 Time to SET floats: 1102.2460 Time to SET floats: 941.9556 Time to SET strings: 2996.5019 Time to SET strings: 2834.2122 Time to SET strings: 1696.1518 Time to SET strings: 1596.9816 Time to GET floats: 2436.7968 Time to GET floats: 2059.1103 Time to GET floats: 1467.0756 Time to GET floats: 1068.0994 Time to GET strings: 2885.8160 Time to GET strings: 2736.6734 Time to GET strings: 1601.2007 Time to GET strings: 1507.9682 500,000 key/item pairs 500,000 key/item pairs 500,000 key/item pairs 500,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET floats: 9625.9954 Time to SET floats: 7067.7140 Time to SET floats: 3690.0478 Time to SET floats: 4083.9408 Time to SET strings: 11062.4177 Time to SET strings: 9705.4638 Time to SET strings: 5828.4754 Time to SET strings: 6309.6669 Time to GET floats: 9402.8360 Time to GET floats: 7386.4105 Time to GET floats: 5821.5921 Time to GET floats: 5125.1619 Time to GET strings: 10732.6361 Time to GET strings: 9606.9670 Time to GET strings: 5637.6283 Time to GET strings: 6165.0928 750,000 key/item pairs 750,000 key/item pairs 750,000 key/item pairs 750,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET floats: 21641.4441 Time to SET floats: 16346.8101 Time to SET floats: 7810.8329 Time to SET floats: 10127.1801 Time to SET strings: 24213.2453 Time to SET strings: 20998.8080 Time to SET strings: 12017.4508 Time to SET strings: 14443.3815 Time to GET floats: 20793.1913 Time to GET floats: 16415.3945 Time to GET floats: 13318.7511 Time to GET floats: 12215.9591 Time to GET strings: 23631.4639 Time to GET strings: 20436.8046 Time to GET strings: 11865.3739 Time to GET strings: 14166.9541 1,000,000 key/item pairs 1,000,000 key/item pairs 1,000,000 key/item pairs 1,000,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET floats: 38099.9143 Time to SET floats: 29468.5027 Time to SET floats: 13488.5462 Time to SET floats: 18590.9545 Time to SET strings: 42532.3169 Time to SET strings: 37539.1462 Time to SET strings: 20615.3748 Time to SET strings: 25993.1925 Time to GET floats: 37491.8000 Time to GET floats: 29424.1574 Time to GET floats: 22812.6073 Time to GET floats: 21492.3516 Time to GET strings: 41942.9129 Time to GET strings: 36578.6597 Time to GET strings: 20636.5487 Time to GET strings: 25661.0474 The Dictionary object is tested with float and string keys for large numbers of key/item pairs and no time limit. The header text to identify the PCs is added manually directly in the report. This is done after the test on the individual PC. The technique can also be used to repeat the same test multiple times. Eg. to verify that the time measurements are fairly stable from one test to the next. For very short time measurements up to around 100 ms, the numbers can fluctuate a lot. For time measurements of longer duration, the numbers become more stable. At least in terms of the percentage variation. There can still easily be several 100 ms between the numbers. Repeat test.txt: expandcollapse popupMap Data Type Map Data Type Map Data Type Map Data Type Integer Key Type Integer Key Type Integer Key Type Integer Key Type Code executed as 32-bit code Code executed as 32-bit code Code executed as 32-bit code Code executed as 32-bit code ================================== ================================== ================================== ================================== 100 key/item pairs 100 key/item pairs 100 key/item pairs 100 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 0.0562 Time to SET integers: 0.0634 Time to SET integers: 0.0925 Time to SET integers: 0.0942 Time to GET integers: 0.0269 Time to GET integers: 0.0277 Time to GET integers: 0.0496 Time to GET integers: 0.0477 500 key/item pairs 500 key/item pairs 500 key/item pairs 500 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 0.2455 Time to SET integers: 0.2399 Time to SET integers: 0.4228 Time to SET integers: 0.4061 Time to GET integers: 0.1247 Time to GET integers: 0.1252 Time to GET integers: 0.2000 Time to GET integers: 0.2081 1,000 key/item pairs 1,000 key/item pairs 1,000 key/item pairs 1,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 0.4710 Time to SET integers: 0.4881 Time to SET integers: 0.8655 Time to SET integers: 0.8671 Time to GET integers: 0.2477 Time to GET integers: 0.2571 Time to GET integers: 0.4374 Time to GET integers: 0.4330 2,000 key/item pairs 2,000 key/item pairs 2,000 key/item pairs 2,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 0.9444 Time to SET integers: 0.9696 Time to SET integers: 1.6484 Time to SET integers: 1.6766 Time to GET integers: 0.5020 Time to GET integers: 0.5139 Time to GET integers: 0.9007 Time to GET integers: 0.9223 5,000 key/item pairs 5,000 key/item pairs 5,000 key/item pairs 5,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 2.5191 Time to SET integers: 2.6676 Time to SET integers: 3.3990 Time to SET integers: 4.9568 Time to GET integers: 1.3661 Time to GET integers: 1.4093 Time to GET integers: 2.0144 Time to GET integers: 2.6770 10,000 key/item pairs 10,000 key/item pairs 10,000 key/item pairs 10,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 10.0263 Time to SET integers: 5.8289 Time to SET integers: 9.3263 Time to SET integers: 10.2020 Time to GET integers: 5.3923 Time to GET integers: 3.3081 Time to GET integers: 3.2209 Time to GET integers: 5.4117 20,000 key/item pairs 20,000 key/item pairs 20,000 key/item pairs 20,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 15.0419 Time to SET integers: 18.2819 Time to SET integers: 14.7576 Time to SET integers: 22.3435 Time to GET integers: 9.5388 Time to GET integers: 9.5052 Time to GET integers: 9.9704 Time to GET integers: 13.9207 50,000 key/item pairs 50,000 key/item pairs 50,000 key/item pairs 50,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 73.2189 Time to SET integers: 83.5524 Time to SET integers: 68.4244 Time to SET integers: 101.6177 Time to GET integers: 78.3893 Time to GET integers: 77.2465 Time to GET integers: 84.2608 Time to GET integers: 60.6623 100,000 key/item pairs 100,000 key/item pairs 100,000 key/item pairs 100,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 298.2182 Time to SET integers: 296.7654 Time to SET integers: 294.4335 Time to SET integers: 298.0808 Time to GET integers: 265.1449 Time to GET integers: 266.9922 Time to GET integers: 266.8074 Time to GET integers: 274.0365 250,000 key/item pairs 250,000 key/item pairs 250,000 key/item pairs 250,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 2281.5185 Time to SET integers: 2317.1292 Time to SET integers: 2268.9331 Time to SET integers: 2356.9431 Time to GET integers: 2214.9619 Time to GET integers: 2236.4405 Time to GET integers: 2239.2422 Time to GET integers: 2289.0354 500,000 key/item pairs 500,000 key/item pairs 500,000 key/item pairs 500,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: 10227.8703 Time to SET integers: 10255.9150 Time to SET integers: 10306.3266 Time to SET integers: 10393.5952 Time to GET integers: 9999.0337 Time to GET integers: 10217.8988 Time to GET integers: 10095.6638 Time to GET integers: 10271.2409 750,000 key/item pairs 750,000 key/item pairs 750,000 key/item pairs 750,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: >10000.0000 Time to SET integers: >10000.0000 Time to SET integers: >10000.0000 Time to SET integers: >10000.0000 Time to GET integers: >10000.0000 Time to GET integers: >10000.0000 Time to GET integers: >10000.0000 Time to GET integers: >10000.0000 1,000,000 key/item pairs 1,000,000 key/item pairs 1,000,000 key/item pairs 1,000,000 key/item pairs ---------------------------------- ---------------------------------- ---------------------------------- ---------------------------------- Time to SET integers: >10000.0000 Time to SET integers: >10000.0000 Time to SET integers: >10000.0000 Time to SET integers: >10000.0000 Time to GET integers: >10000.0000 Time to GET integers: >10000.0000 Time to GET integers: >10000.0000 Time to GET integers: >10000.0000 Time limit 1/2A limitation of the time consumption for a single time measurement has already been discussed regarding script 7) in the Map vs Dict Obj example above. Time limit 1.au3 with a 10 second limit on time measurements produces a report Time limit 1.txt: expandcollapse popupMap Data Type Integer Key Type Code executed as 32-bit code ================================== 100 key/item pairs ---------------------------------- Time to SET integers: 0.0562 Time to GET integers: 0.0269 500 key/item pairs ---------------------------------- Time to SET integers: 0.2455 Time to GET integers: 0.1247 1,000 key/item pairs ---------------------------------- Time to SET integers: 0.4710 Time to GET integers: 0.2477 2,000 key/item pairs ---------------------------------- Time to SET integers: 0.9444 Time to GET integers: 0.5020 5,000 key/item pairs ---------------------------------- Time to SET integers: 2.5191 Time to GET integers: 1.3661 10,000 key/item pairs ---------------------------------- Time to SET integers: 10.0263 Time to GET integers: 5.3923 20,000 key/item pairs ---------------------------------- Time to SET integers: 15.0419 Time to GET integers: 9.5388 50,000 key/item pairs ---------------------------------- Time to SET integers: 73.2189 Time to GET integers: 78.3893 100,000 key/item pairs ---------------------------------- Time to SET integers: 298.2182 Time to GET integers: 265.1449 250,000 key/item pairs ---------------------------------- Time to SET integers: 2281.5185 Time to GET integers: 2214.9619 500,000 key/item pairs ---------------------------------- Time to SET integers: 10227.8703 Time to GET integers: 9999.0337 750,000 key/item pairs ---------------------------------- Time to SET integers: >10000.0000 Time to GET integers: >10000.0000 1,000,000 key/item pairs ---------------------------------- Time to SET integers: >10000.0000 Time to GET integers: >10000.0000 But there is an issue at 500,000 key/item pairs. Here the SET-time has exceeded the 10 second limit, so the SET-code isn't executed for 750,000 key/item pairs. But the GET-time at 500,000 key/item pairs isn't exceeded, so the GET-code will be executed for 750,000 key/item pairs. The issue is that the GET-code is dependent on the SET-code. It makes no sense to time measure the GET-code if the SET-code isn't executed. Code has been added to the time measurement of the GET-time to handle this situation: ; Time test 1 $iTest = 0 If Not $aTimes[$iTest][2] Or ( $aTimes[$iTest][1] < $aTimes[$iTest][2] ) Then $hTimer = TimerInit() ; Time test 1 For $j = 0 To $iRows - 1 $mMap[$j] = $j Next $aTimes[$iTest][1] = TimerDiff( $hTimer ) Runtime_Info1( 8+$iTest, $i, $iTests, $iLineLen, $aTimes[$iTest][1], $aRuntime_Info, "Time to SET integers:" ) Else Runtime_Info2( 8+$iTest, $i, $iTests, $iLineLen, $aTimes[$iTest][2], $aRuntime_Info, "Time to SET integers:" ) EndIf ; Time test 2 ; Time test 2 is dependent on time test 1 being completed within the $iTest += 1 ; time limit. $aTimes[$iTest-1][0] indicates whether this is the case. If Not $aTimes[$iTest][2] Or ( $aTimes[$iTest-1][0] And $aTimes[$iTest][1] < $aTimes[$iTest][2] ) Then $hTimer = TimerInit() ; Time test 2 For $j = 0 To $iRows - 1 $v = $mMap[$j] Next ; $aTimes[$iTest-1][0] = 0 indicates that time test 1 wasn't completed within the time limit. $aTimes[$iTest][1] = TimerDiff( $hTimer ) ; Because $aTimes[$iTest-1][0] is set at this place in the code and not immediately after time If $aTimes[$iTest-1][1] > $aTimes[$iTest-1][2] Then $aTimes[$iTest-1][0] = 0 ; test 1, this test is still executed the FIRST time that time test 1 exceeds the time limit. Runtime_Info1( 8+$iTest, $i, $iTests, $iLineLen, $aTimes[$iTest][1], $aRuntime_Info, "Time to GET integers:" ) Else Runtime_Info2( 8+$iTest, $i, $iTests, $iLineLen, $aTimes[$iTest][2], $aRuntime_Info, "Time to GET integers:" ) EndIf In Time limit 2.au3 there are also time measurements on a Map data type of string keys. Here, the additional check in the GET-code that the SET-code has actually been executed must also be carried out for the string keys. 7z-fileThe 7z-file contains source code for include files and examples. You need AutoIt 3.3.16 or later. Tested on Windows 7 and Windows 10. Comments are welcome. Let me know if there are any issues. Runtimes.7z Edited February 11, 2023 by LarsJ New 7z-file mLipok, argumentum and Danyfirex 3 Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions Link to comment Share on other sites More sharing options...
LarsJ Posted February 5, 2023 Author Share Posted February 5, 2023 (edited) Virtual TreeViews Development of the Runtime measurement code is largely carried out in parallel with development of the second part of Virtual TreeViews. Especially for measuring the gain using compiled VB.NET code. The following example is used to demonstrate new functionality of the Runtime measurement code: 1) Example.au3: ; Copied from TVSourceCreatePlainExConstCount() output ; $iLevels, $iItems0, $iMultiplier, $iCount = 3, 90, 10, 10701 Example( 3, 90, 10, 10701 ) ; 10,701 treeview items Func Example( $iLevels, $iItems0, $iMultiplier, $iCount ) Local $sSources = ".\Sources\" & $iLevels & " levels, " & $iCount & " items, " Local $sPlain = $sSources & "Plain, debug.txt" ; Plain source Local $sVirtual = $sSources & "Virtual, debug.txt" ; Virtual source TVSourceCreatePlainExConst( $iLevels, $iItems0, $iMultiplier, $sPlain ) ; Create plain source TVSourceDisplayPlain( $sPlain ) ; Display plain TreeView TVSourceConvertPlainToVirtual( $iLevels, $sPlain, $sVirtual ) ; Convert to virtual source TVSourceDisplayVirtual( $sVirtual ) ; Display virtual TreeView FileDelete( $sPlain ) ; Delete plain source FileDelete( $sVirtual ) ; Delete virtual source EndFunc ; Copied from TVSourceCreatePlainExConstCount() output ; $iLevels, $iItems0, $iMultiplier, $iCount = 3, 90, 10, 10701 ExampleVb( 3, 90, 10, 10701 ) ; 10,701 treeview items Func ExampleVb( $iLevels, $iItems0, $iMultiplier, $iCount ) Local $sSources = ".\Sources\" & $iLevels & " levels, " & $iCount & " items, " Local $sPlain = $sSources & "Plain, debug.txt" ; Plain source Local $sVirtual = $sSources & "Virtual, debug.txt" ; Virtual source TVSourceCreatePlainExConstVb( $iLevels, $iItems0, $iMultiplier, $sPlain ) ; Create plain source TVSourceDisplayPlain( $sPlain ) ; Display plain TreeView TVSourceConvertPlainToVirtualVb( $iLevels, $sPlain, $sVirtual ) ; Convert to virtual source TVSourceDisplayVirtual( $sVirtual ) ; Display virtual TreeView FileDelete( $sPlain ) ; Delete plain source FileDelete( $sVirtual ) ; Delete virtual source EndFunc In the Runtime examples, time measurement of these 4 tasks is carried out: Create a constant source file for a plain treeview Display the corresponding semi-virtual treeview Convert the source file to a virtual source file Display the corresponding virtual treeview Measurements are performed on an increasing number of treeview items. The features demonstrated below are: Using the Runtime data section Visual validation of Runtime data The GUI must be closed after validation Set individual max time $aTimes[1][2] = 10000 Local variables for the current Runtime function Creation time measurement of GUI with blocking main loop The idea is to create the GUI in a new process with Run() Additional initialization code for the current function Necessary for time measurement of compiled VB.NET code Divide task into sub-tasks with individual time measurements Implementing sub-task time measurement inside a VB.NET method Sub-task time measurement during a GUI creation process Uses a ROT object to pass data back to the Runtime script Time limits in relation to interdependent measurements All examples can be found in Examples\Virtual TreeView\. Run the examples with F5 in SciTE. Runtime data sectionThe Runtime data section contains additional data that is used in the Runtime functions: ; --- Additional data for the current Runtimes --- ; Copied from TVSourceCreatePlainExConstCount() output ; $iLevels, $iItems0, $iMultiplier, $iCount = 3, 90, 10, 10701 ; $iLevels, $iItems0, $iMultiplier, $iCount = 5, 24, 4, 20346 ; $iLevels, $iItems0, $iMultiplier, $iCount = 5, 30, 5, 52134 ; $iLevels, $iItems0, $iMultiplier, $iCount = 4, 80, 10, 112472 ; $iLevels, $iItems0, $iMultiplier, $iCount = 5, 49, 7, 259399 ; $iLevels, $iItems0, $iMultiplier, $iCount = 5, 64, 8, 533240 ; $iLevels, $iItems0, $iMultiplier, $iCount = 6, 50, 5, 758890 ; $iLevels, $iItems0, $iMultiplier, $iCount = 5, 81, 9, 1012329 ; $iLevels, $iItems0, $iMultiplier, $iCount = 6, 42, 7, 2399622 ; $iLevels, $iItems0, $iMultiplier, $iCount = 6, 56, 8, 5511625 ;Local $aRuntime_Data = 0 Local $aRuntime_Data = [ _ [ 3, 90, 10 ], _ [ 5, 24, 4 ], _ [ 5, 30, 5 ], _ [ 4, 80, 10 ], _ [ 5, 49, 7 ], _ [ 5, 64, 8 ], _ [ 6, 50, 5 ], _ [ 5, 81, 9 ], _ [ 6, 42, 7 ], _ [ 6, 56, 8 ] ] ; ------------------------------------------------ 2) First test.au32) First test.au3 contains 2 Runtime functions that perform these Runtime tests: In Runtimes1() with pure AutoIt code: TVSourceCreatePlainExConst() TVSourceDisplayPlain() TVSourceConvertPlainToVirtual() TVSourceDisplayVirtual() In Runtimes2() also with VB.NET code: TVSourceCreatePlainExConstVb() TVSourceDisplayPlain() TVSourceConvertPlainToVirtualVb() TVSourceDisplayVirtual() Because Runtimes2() executes VB.NET code, additional initializations are needed to load the VB.NET code: ; --- Additional initializations for the current function --- If Not TVSourceCreateVbNetCodeObject( "..\..\Includes\Virtual TreeView\TVSourceFile.vb" ) Then ConsoleWrite( "TVSourceCreateVbNetCodeObject: @error = " & @error & @CRLF ) Exit 1 EndIf Note that the settings in 2) First test.au3 are defined to only execute Runtimes2(). These settings are used to develop and test time measurement of the VB.NET code. 3) First test - Cycle.au3 executes both Runtime functions as 32 and 64 bit code and generates a report with 4 columns. TVSourceDisplayPlain()TVSourceDisplayPlain() in both Runtime functions displays a plain source file as a semi-virtual treeview in a GUI. Because the GUI contains a blocking main loop, TVSourceDisplayPlain() is executed in a new process with the Run() command. The time measurement is coded this way: $hTimer = TimerInit() Run( $sAutoItExePath & ( $iBit = 32 ? "AutoIt3.exe" : "AutoIt3_x64.exe" ) & " /AutoIt3ExecuteScript " & _ """" & $sScriptPathPlain & """" & " " & """" & $sSources & "Plain, debug.txt" & """" & " " & 1 ) WinClose( WinWaitActive( "Display Plain TreeView From Source File" ) ) $aTimes[$iTest][1] = TimerDiff( $hTimer ) You can briefly see the GUI appear and close down again. $sScriptPathPlain is the name of the script to run, here TVSourceDisplayPlain.au3: #include "..\..\Includes\Virtual TreeView\TVSourceFile.au3" If UBound( $CmdLine ) > 1 Then TVSourceDisplayPlain( $CmdLine[1], $CmdLine[2]+0 ) TVSourceDisplayPlain() isn't that interesting compared to true virtual treeviews. It can only handle semi-virtual treeviews, where only the item texts are virtual. The entire treeview structure must be created before the treeview can be displayed in the GUI. This can be very time consuming for large source files. In both Runtime functions, the time taken to create this GUI is limited to 10 seconds. All other time measurements are limited to 30 seconds. 4) Divided tasks.au3The functions TVSourceConvertPlainToVirtual(), TVSourceConvertPlainToVirtualVb() and TVSourceDisplayVirtual() are divided into a few smaller and clearly separated sub-tasks. For the first two functions, it's about Read the plain source file from the disk Convert plain source to virtual source file Save the virtual source file to the disk For the last function, it's about Read the virtual source file from the disk Display the source file in a treeview in a GUI Because these are clearly separated sub-tasks, it provides more information with separate time measurements of the different sub-tasks. In 4) Divided tasks.au3, separate time measurements are performed for the sub-tasks. In the sections below, the techniques are discussed. TVSourceConvertPlainToVirtual()In 4) Divided tasks.au3, time measurements in TVSourceConvertPlainToVirtual() are divided into 3 sub-measurements that measure reading and converting the plain source file as well as saving the new virtual source file. Read and write times must be measured directly in TVSourceConvertPlainToVirtual(). Therefore the TVSourceFile.au3 include is copied to TVSourceFileRt.au3 and time measurement code is added in TVSourceConvertPlainToVirtual() in this new include. Also added 2 parameters to pass read and write times. Then the same functions (with the same names) can be used everywhere in the code, and only the name of the include file needs to be corrected. The read and write times in the parameters must of course be handled. The actual conversion time is calculated by subtracting read and write times from the total time measurement for the entire function. This ensures that the numbers match when added together. The time measurements in the report look like this: Load source: 57.9840 Convert src: 1634.2488 Save source: 646.1083 Convert source: 2338.3411 The sub-measurements are marked with an indentation. The new code in TVSourceConvertPlainToVirtual() Func TVSourceConvertPlainToVirtual( _ $iLevels, _ ; Treeview levels, 2 <= $iLevels <= 100 $sTVPlainSrc, _ ; Name of plain treeview input source file $sTVVirtualSrc, _ ; Name of virtual treeview output source file ByRef $fTimeLoad, ByRef $fTimeSave ) ; ... ; Read treeview input source file into array Local $hTimer = TimerInit() Local $aSource, $iSource, $bTVVirtual, $iTVLevels, $iTVItems If Not TVSourceReadToArray( $sTVPlainSrc, $aSource, $iSource, $bTVVirtual, $iTVLevels, $iTVItems ) _ Or $bTVVirtual Then Return SetError( @error+1, 0, 0 ) $fTimeLoad = TimerDiff( $hTimer ) $hTimer = 0 ; ... ; Save $oSource in source file $hTimer = TimerInit() Local $hTVVirtualSrc = FileOpen( $sTVVirtualSrc, 2+256 ) ; $FO_OVERWRITE+$FO_UTF8_NOBOM For $i = 0 To $iCnt FileWriteLine( $hTVVirtualSrc, $oSource( $i+0.0 ) ) Next FileClose( $hTVVirtualSrc ) $fTimeSave = TimerDiff( $hTimer ) The code in Runtimes1() ; Time test 3 - 6 $iTest += 1 If Not $aTimes[$iTest][2] Or ( $aTimes[$iTest][1] < $aTimes[$iTest][2] ) Then $hTimer = TimerInit() TVSourceConvertPlainToVirtual( $iLevels, $sSources & "Plain, debug.txt", $sSources & "Virtual, debug.txt", $fTimeLoad, $fTimeSave ) $aTimes[$iTest][1] = TimerDiff( $hTimer ) Runtime_Info1( 8+$iTest, $i, $iTests, $iLineLen, $fTimeLoad, $aRuntime_Info, " Load source:" ) $iTest += 1 ; Time test 4 Runtime_Info1( 8+$iTest, $i, $iTests, $iLineLen, $aTimes[$iTest-1][1] - $fTimeLoad - $fTimeSave, $aRuntime_Info, " Convert src:" ) $iTest += 1 ; Time test 5 Runtime_Info1( 8+$iTest, $i, $iTests, $iLineLen, $fTimeSave, $aRuntime_Info, " Save source:" ) $iTest += 1 ; Time test 6 Runtime_Info1( 8+$iTest, $i, $iTests, $iLineLen, $aTimes[$iTest-3][1], $aRuntime_Info, "Convert source:" ) Else Runtime_Info2( 8+$iTest, $i, $iTests, $iLineLen, $aTimes[$iTest][2], $aRuntime_Info, " Load source:" ) $iTest += 1 ; Time test 4 Runtime_Info2( 8+$iTest, $i, $iTests, $iLineLen, $aTimes[$iTest][2], $aRuntime_Info, " Convert src:" ) $iTest += 1 ; Time test 5 Runtime_Info2( 8+$iTest, $i, $iTests, $iLineLen, $aTimes[$iTest][2], $aRuntime_Info, " Save source:" ) $iTest += 1 ; Time test 6 Runtime_Info2( 8+$iTest, $i, $iTests, $iLineLen, $aTimes[$iTest][2], $aRuntime_Info, "Convert source:" ) EndIf Note how $iTest is used to indicate line locations in the report of sub-measurements and total measurement, as well as index in $aTimes, where column 1 (zero based) contains the time measurements and column 2 contains the maximum times. TVSourceConvertPlainToVirtualVb()The time measurements in TVSourceConvertPlainToVirtualVb() are performed in the same way as the time measurements in TVSourceConvertPlainToVirtual() except that the read and write times must be measured in the VB.NET code. The code in TVSourceConvertPlainToVirtualVb() Func TVSourceConvertPlainToVirtualVb( _ $iLevels, _ ; Treeview levels, 2 <= $iLevels <= 100 $sTVPlainSrc, _ ; Name of plain treeview input source file $sTVVirtualSrc, _ ; Name of virtual treeview output source file ByRef $fTimeLoad, ByRef $fTimeSave ) If Not ( 2 <= $iLevels And $iLevels <= 100 ) Then Return SetError( 1, 0, 0 ) If Not FileExists( $sTVPlainSrc ) Then Return SetError( 2, 0, 0 ) ; Get $oVbNetCode object to execute function as compiled VB.NET code Local $oVbNetCode = TVSourceCreateVbNetCodeObject() If Not IsObj( $oVbNetCode ) Then Return SetError( 6, 0, 0 ) ; Execute TVSourceConvertPlainToVirtualVb() as compiled VB.NET code Local $aRet = $oVbNetCode.TVSourceConvertPlainToVirtualVb( $iLevels, $sTVPlainSrc, $sTVVirtualSrc ) If $aRet[0] < 0 Then Return SetError( -$aRet[0]+2, 0, 0 ) $fTimeLoad = $aRet[1] $fTimeSave = $aRet[2] Return 1 EndFunc TVSourceFile.vb is copied to TVSourceFileRt.vb and VB.NET code for time measurement in TVSourceConvertPlainToVirtualVb() method is added to this file: Public Function TVSourceConvertPlainToVirtualVb( iLevels As Integer, sTVPlainSrc As String, sTVVirtualSrc As String ) As Object() Dim oStopWatch As New Stopwatch(), iFrequency As Long = oStopWatch.Frequency, fTicksPerMillisecond As Double = iFrequency / 1000 'Read treeview input source file into array oStopWatch.Restart() Dim aSource() As String = File.ReadAllLines( sTVPlainSrc ) Dim iSource As Integer, bVirtual As Boolean, iItems As Integer, aRet(2) As Object aRet(0) = TVSourceCheckArray( aSource, iSource, bVirtual, iLevels, iItems ) If aRet(0) = 0 And bVirtual Then aRet(0) = -2 If aRet(0) < 0 Then Return aRet oStopWatch.Stop() aRet(1) = oStopWatch.ElapsedTicks / fTicksPerMillisecond '$fTimeLoad '... 'Save $oSource in source file oStopWatch.Restart() Using SW As StreamWriter = New StreamWriter( sTVVirtualSrc ) For i As Integer = 0 To iCnt SW.WriteLine( oSource.Item(i) ) Next End Using oStopWatch.Stop() aRet(2) = oStopWatch.ElapsedTicks / fTicksPerMillisecond '$fTimeSave Return aRet End Function The code in Runtimes2() is similar to the code in Runtimes1(). TVSourceDisplayVirtual()Time measurement of TVSourceDisplayVirtual() is done in the same way as time measurement of TVSourceDisplayPlain() above by running the function in a separate process with Run(). But now there is an additional complication, as the time to read the source file must be sent back to the Runtime function through interprocess communication. The interprocess communication is implemented by a ROT object that is initialized in this way at the top of the Runtime function: ; --- Additional initializations for the current function --- ; Create a default ROT-object (Dictionary object) ; The script that creates the ROT object is the server Local $sDataTransferObject = "DataTransferObject", $oDict $oDict = ROT_CreateDefaultObject( $sDataTransferObject ) $oDict.Item( "Time" ) = 0.0 The $sDataTransferObject string identifying the ROT object must be passed to the process where TVSourceDisplayVirtual() is executed. This is done with a simple command line parameter. This is the code in TVSourceFileRt.au3 for separate time measurement of loading the virtual source file: Func TVSourceDisplayVirtual( $sTVVirtualSrc, $bLargeGui, $sDataTransferObject ) ; Get default ROT-object (Dictionary object) ; IRunningObjectTable.au3 not needed in client Local $oDict = ObjGet( $sDataTransferObject ) ; ... ; Read source file into $aSource ; Source file specification in TVCreateVirtualSrcDbg() Local $hTimer = TimerInit() If Not FileExists( $sTVVirtualSrc ) Then Return SetError( 1, 0, 0 ) Local $hTVVirtualSrc = FileOpen( $sTVVirtualSrc, 256 ) ; $FO_UTF8_NOBOM $aSource = FileReadToArray( $hTVVirtualSrc ) Local $iSource = @extended $iLevels = StringSplit( $aSource[$iSource-1], ":", 2 )[0] + 1 ; Last line in $aSource ; The line has this format: 4:218705|14151 Local $eLevels = @error ; 4->level, 218705->first row, 14151->number of rows FileClose( $hTVVirtualSrc ) ; Level in this line indicates the total number of levels $oDict.Item( "Time" ) = TimerDiff( $hTimer ) $hTimer = 0 The code in Runtimes1() ; Time test 7 - 9 ; This time test is dependent on the previous test being completed within $iTest += 1 ; the time limit. $aTimes[$iTest-4][0] indicates whether this is the case. If Not $aTimes[$iTest][2] Or ( $aTimes[$iTest-4][0] And $aTimes[$iTest][1] < $aTimes[$iTest][2] ) Then $hTimer = TimerInit() Run( $sAutoItExePath & ( $iBit = 32 ? "AutoIt3.exe" : "AutoIt3_x64.exe" ) & " /AutoIt3ExecuteScript " & """" & $sScriptPathVirtual & """" & " " & """" & $sSources & "Virtual, debug.txt" & """" & " " & 1 & " " & $sDataTransferObject ) WinClose( WinWaitActive( "Display Virtual TreeView From Source File" ) ) ; $aTimes[$iTest-4][0] = 0 indicates that the previous test wasn't completed within the time limit. $aTimes[$iTest][1] = TimerDiff( $hTimer ) ; Because $aTimes[$iTest-4][0] is set at this place in the code and not immediately after the prev If $aTimes[$iTest-4][1] > $aTimes[$iTest-4][2] Then $aTimes[$iTest-4][0] = 0 ; test, this test is still executed the FIRST time the previous test exceeds the time limit. Runtime_Info1( 8+$iTest, $i, $iTests, $iLineLen, $oDict.Item( "Time" ), $aRuntime_Info, " Load source:" ) ; Time tests 7 and 8 are subtests $iTest += 1 ; Time test 8 ; (indicated by indentation) of test 9. Runtime_Info1( 8+$iTest, $i, $iTests, $iLineLen, $aTimes[$iTest-1][1] - $oDict.Item( "Time" ), $aRuntime_Info, " Create GUI:" ) $iTest += 1 ; Time test 9 Runtime_Info1( 8+$iTest, $i, $iTests, $iLineLen, $aTimes[$iTest-2][1], $aRuntime_Info, "Display virtual:" ) ; Time test 9 is the sum of tests 7 and 8 Else Runtime_Info2( 8+$iTest, $i, $iTests, $iLineLen, $aTimes[$iTest][2], $aRuntime_Info, " Load source:" ) ; Time tests 7 and 8 are subtests $iTest += 1 ; Time test 8 ; (indicated by indentation) of test 9. Runtime_Info2( 8+$iTest, $i, $iTests, $iLineLen, $aTimes[$iTest][2], $aRuntime_Info, " Create GUI:" ) $iTest += 1 ; Time test 9 Runtime_Info2( 8+$iTest, $i, $iTests, $iLineLen, $aTimes[$iTest][2], $aRuntime_Info, "Display virtual:" ) ; Time test 9 is the sum of tests 7 and 8 EndIf 5) Divided tasks - No limit.au35) Divided tasks - No limit.au3 runs the same code as 4) Divided tasks.au3 but without time limits except for the 10 second time limit on TVSourceDisplayPlain(). The report is saved in 5) Divided tasks - No limit.txt: expandcollapse popupPure AutoIt Code Compiled VB.NET Code Create, Convert and Display TreeView Source File Create, Convert and Display TreeView Source File Code executed as 32-bit code Code executed as 64-bit code Code executed as 32-bit code Code executed as 64-bit code ============================== ============================== ============================== ============================== 10,701 items 10,701 items 10,701 items 10,701 items ------------------------------ ------------------------------ ------------------------------ ------------------------------ Create source: 62.1074 Create source: 55.0925 Create source: 6.9292 Create source: 5.2162 Display plain: 1310.1184 Display plain: 1279.0274 Display plain: 1466.3365 Display plain: 1248.0080 Load source: 6.4438 Load source: 5.3520 Load source: 1.4844 Load source: 0.8248 Convert src: 174.8612 Convert src: 168.1489 Convert src: 105.6492 Convert src: 108.3194 Save source: 45.1033 Save source: 57.4945 Save source: 2.9284 Save source: 1.6936 Convert source: 226.4083 Convert source: 230.9954 Convert source: 110.0620 Convert source: 110.8378 Load source: 31.3393 Load source: 31.4346 Load source: 17.5593 Load source: 17.4069 Create GUI: 777.7560 Create GUI: 759.7363 Create GUI: 757.9427 Create GUI: 741.3450 Display virtual: 809.0953 Display virtual: 791.1709 Display virtual: 775.5019 Display virtual: 758.7519 20,346 items 20,346 items 20,346 items 20,346 items ------------------------------ ------------------------------ ------------------------------ ------------------------------ Create source: 127.3154 Create source: 118.0155 Create source: 22.1183 Create source: 16.5561 Display plain: 2682.8592 Display plain: 1684.5415 Display plain: 2682.5587 Display plain: 1668.7154 Load source: 12.7071 Load source: 10.2092 Load source: 2.1324 Load source: 1.9302 Convert src: 350.3479 Convert src: 315.0080 Convert src: 224.8100 Convert src: 216.9120 Save source: 87.9589 Save source: 83.4993 Save source: 3.1977 Save source: 3.2877 Convert source: 451.0139 Convert source: 408.7165 Convert source: 230.1401 Convert source: 222.1299 Load source: 43.2681 Load source: 40.9371 Load source: 39.6455 Load source: 48.5210 Create GUI: 769.5770 Create GUI: 735.3170 Create GUI: 752.2369 Create GUI: 741.1237 Display virtual: 812.8451 Display virtual: 776.2541 Display virtual: 791.8823 Display virtual: 789.6446 52,134 items 52,134 items 52,134 items 52,134 items ------------------------------ ------------------------------ ------------------------------ ------------------------------ Create source: 299.3385 Create source: 281.6153 Create source: 47.1510 Create source: 35.3964 Display plain: 4039.9790 Display plain: 3197.4666 Display plain: 4086.8056 Display plain: 3165.9145 Load source: 30.7583 Load source: 26.7869 Load source: 4.6710 Load source: 5.1739 Convert src: 964.1700 Convert src: 883.4936 Convert src: 651.3202 Convert src: 689.5954 Save source: 254.3325 Save source: 232.0731 Save source: 11.8061 Save source: 7.2628 Convert source: 1249.2608 Convert source: 1142.3536 Convert source: 667.7973 Convert source: 702.0320 Load source: 71.0920 Load source: 94.0728 Load source: 37.3873 Load source: 66.1594 Create GUI: 745.4110 Create GUI: 744.5920 Create GUI: 768.2801 Create GUI: 738.8671 Display virtual: 816.5030 Display virtual: 838.6648 Display virtual: 805.6674 Display virtual: 805.0266 112,472 items 112,472 items 112,472 items 112,472 items ------------------------------ ------------------------------ ------------------------------ ------------------------------ Create source: 599.4971 Create source: 524.5084 Create source: 66.0073 Create source: 47.0230 Display plain: 7170.9434 Display plain: 5738.8998 Display plain: 7189.4322 Display plain: 5519.9219 Load source: 82.1756 Load source: 71.4516 Load source: 17.2459 Load source: 11.6925 Convert src: 2127.0630 Convert src: 2129.2415 Convert src: 1199.6497 Convert src: 1291.4186 Save source: 677.1560 Save source: 662.6223 Save source: 22.0474 Save source: 15.3304 Convert source: 2886.3945 Convert source: 2863.3154 Convert source: 1238.9430 Convert source: 1318.4415 Load source: 113.3855 Load source: 147.0694 Load source: 83.1979 Load source: 83.3907 Create GUI: 754.7151 Create GUI: 766.5056 Create GUI: 757.5615 Create GUI: 741.4110 Display virtual: 868.1006 Display virtual: 913.5751 Display virtual: 840.7593 Display virtual: 824.8017 259,399 items 259,399 items 259,399 items 259,399 items ------------------------------ ------------------------------ ------------------------------ ------------------------------ Create source: 1421.3263 Create source: 1213.4943 Create source: 128.4674 Create source: 98.3820 Display plain: 16345.0322 Display plain: 12618.3510 Display plain: 16548.6287 Display plain: 12383.4254 Load source: 171.1753 Load source: 145.5609 Load source: 57.0352 Load source: 41.5014 Convert src: 5476.9818 Convert src: 5336.6914 Convert src: 3044.4364 Convert src: 3101.9301 Save source: 2407.9014 Save source: 2475.1453 Save source: 50.0090 Save source: 38.3763 Convert source: 8056.0586 Convert source: 7957.3976 Convert source: 3151.4806 Convert source: 3181.8079 Load source: 232.9671 Load source: 206.9770 Load source: 213.1691 Load source: 195.5270 Create GUI: 762.8132 Create GUI: 768.1915 Create GUI: 768.0311 Create GUI: 753.9219 Display virtual: 995.7803 Display virtual: 975.1685 Display virtual: 981.2001 Display virtual: 949.4488 533,240 items 533,240 items 533,240 items 533,240 items ------------------------------ ------------------------------ ------------------------------ ------------------------------ Create source: 2940.3783 Create source: 2493.9978 Create source: 269.4767 Create source: 201.4929 Display plain: >10000.0000 Display plain: >10000.0000 Display plain: >10000.0000 Display plain: >10000.0000 Load source: 321.2050 Load source: 286.1879 Load source: 157.4970 Load source: 57.1485 Convert src: 12323.8170 Convert src: 14228.8776 Convert src: 5353.2245 Convert src: 5461.8312 Save source: 7808.0456 Save source: 8588.9200 Save source: 92.7671 Save source: 69.4851 Convert source: 20453.0676 Convert source: 23103.9855 Convert source: 5603.4885 Convert source: 5588.4648 Load source: 425.8721 Load source: 421.7100 Load source: 453.9295 Load source: 370.9353 Create GUI: 759.1212 Create GUI: 775.5487 Create GUI: 784.2907 Create GUI: 788.6021 Display virtual: 1184.9933 Display virtual: 1197.2588 Display virtual: 1238.2202 Display virtual: 1159.5374 758,890 items 758,890 items 758,890 items 758,890 items ------------------------------ ------------------------------ ------------------------------ ------------------------------ Create source: 4226.6064 Create source: 3571.2496 Create source: 333.9886 Create source: 257.9039 Display plain: >10000.0000 Display plain: >10000.0000 Display plain: >10000.0000 Display plain: >10000.0000 Load source: 477.4109 Load source: 401.9269 Load source: 157.8519 Load source: 83.5317 Convert src: 21411.7366 Convert src: 28981.0439 Convert src: 7530.1962 Convert src: 7341.7639 Save source: 15719.9689 Save source: 16863.5387 Save source: 126.6347 Save source: 99.2910 Convert source: 37609.1165 Convert source: 46246.5095 Convert source: 7814.6828 Convert source: 7524.5866 Load source: 625.1885 Load source: 543.1343 Load source: 582.0656 Load source: 514.3804 Create GUI: 762.6148 Create GUI: 791.0991 Create GUI: 829.6602 Create GUI: 771.9499 Display virtual: 1387.8033 Display virtual: 1334.2335 Display virtual: 1411.7258 Display virtual: 1286.3303 1,012,329 items 1,012,329 items 1,012,329 items 1,012,329 items ------------------------------ ------------------------------ ------------------------------ ------------------------------ Create source: 5516.6633 Create source: 4676.4791 Create source: 415.8247 Create source: 322.2628 Display plain: >10000.0000 Display plain: >10000.0000 Display plain: >10000.0000 Display plain: >10000.0000 Load source: 612.9120 Load source: 568.7687 Load source: 229.1037 Load source: 99.2511 Convert src: 30923.4898 Convert src: 43359.6711 Convert src: 9938.2783 Convert src: 10027.4878 Save source: 23744.0712 Save source: 27398.9498 Save source: 161.4105 Save source: 131.0168 Convert source: 55280.4730 Convert source: 71327.3896 Convert source: 10328.7925 Convert source: 10257.7557 Load source: 774.1494 Load source: 687.2840 Load source: 760.0064 Load source: 643.1498 Create GUI: 755.2697 Create GUI: 755.7249 Create GUI: 778.1790 Create GUI: 786.9553 Display virtual: 1529.4191 Display virtual: 1443.0089 Display virtual: 1538.1854 Display virtual: 1430.1051 2,399,622 items 2,399,622 items 2,399,622 items 2,399,622 items ------------------------------ ------------------------------ ------------------------------ ------------------------------ Create source: 13276.6749 Create source: 11204.7845 Create source: 1000.4516 Create source: 953.3488 Display plain: >10000.0000 Display plain: >10000.0000 Display plain: >10000.0000 Display plain: >10000.0000 Load source: 1586.1944 Load source: 1426.5512 Load source: 805.6862 Load source: 306.9113 Convert src: 172994.7627 Convert src: 297646.4029 Convert src: 23464.3343 Convert src: 23343.9714 Save source: 126799.6477 Save source: 153536.8562 Save source: 386.7730 Save source: 313.0233 Convert source: 301380.6048 Convert source: 452609.8102 Convert source: 24656.7935 Convert source: 23963.9060 Load source: 1862.5236 Load source: 1635.9128 Load source: 2377.0049 Load source: 1607.1037 Create GUI: 774.3998 Create GUI: 760.4771 Create GUI: 785.4887 Create GUI: 785.5621 Display virtual: 2636.9234 Display virtual: 2396.3899 Display virtual: 3162.4935 Display virtual: 2392.6658 5,511,625 items 5,511,625 items 5,511,625 items 5,511,625 items ------------------------------ ------------------------------ ------------------------------ ------------------------------ Create source: 30928.5165 Create source: 25546.8734 Create source: 2851.4060 Create source: 2027.6535 Display plain: >10000.0000 Display plain: >10000.0000 Display plain: >10000.0000 Display plain: >10000.0000 Load source: 3519.3227 Load source: 3262.8841 Load source: 2177.5527 Load source: 1571.7511 Convert src: 1143691.3887 Convert src: 3183438.0475 Convert src: 54347.2599 Convert src: 52933.0415 Save source: 687139.3046 Save source: 832546.3303 Save source: 2222.7075 Save source: 1536.9030 Convert source: 1834350.0160 Convert source: 4019247.2619 Convert source: 58747.5201 Convert source: 56041.6956 Load source: 4317.9148 Load source: 3456.4418 Load source: 6037.6460 Load source: 5253.7490 Create GUI: 769.7396 Create GUI: 750.2432 Create GUI: 818.7498 Create GUI: 773.9574 Display virtual: 5087.6544 Display virtual: 4206.6850 Display virtual: 6856.3959 Display virtual: 6027.7064 Note that the difference between AutoIt and VB.NET code is significant for large treeviews. For the largest treeview with 5.5 million items, it takes ½ - 1+ hours to execute the AutoIt code to convert the source. It takes 1 minute to execute the VB.NET code. It's also noteworthy that 32 bit AutoIt code is twice as fast as 64 bit code. You would have expected the opposite. Probably caused by an intense use of Dictionary objects. Overview section added at top of first post. New 7z-file at bottom of first post. Edited February 11, 2023 by LarsJ Simplified ROT object code argumentum 1 Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now