Step by step to optimize Delphi string SEARCH

Source: Internet
Author: User
Document directory
  • Step by step to optimize Delphi string SEARCH
Step by step to optimize Delphi string SEARCH

Author: Zhu Xiaofeng Source: csdn development expert responsible editor: Fangzhou

I used a large number of string processing functions in the process of compiling an Offline Browser webseizer. This is a CPU-consuming processing process. In order to compile an efficient Web parsing engine, I have made some research on the optimization code.
1. High-precision timing functions
A precise timer is required for code optimization. The commonly used gettickcount function can achieve millisecond-level precision. But it is not enough. In this case, you can increase the number of cycles. In addition, there is a high-resolution performance counter (high-resolution Performance Counter), which provides two API functions, obtain the queryperformancefrequency of the counter frequency and queryperformancecounter of the counter value. The implementation principle is implemented by using the 8253,8254 programmable time interval timer chip in the computer. There are three independent 16-bit counters in the computer.
The counter can be counted in binary or decimal (BDC. The counter generates 1193180 pulses per second. Each pulse reduces the number of the counter by one and the generation frequency is variable. You can use queryperformancefrequency to obtain the result, which is generally 1193180. Queryperformance counter can get the current counter value. So as long as your computer
Fast enough. Theoretically, the precision can reach 1/1193180 seconds.
2. code optimization example
The following uses a custom string function as an example to describe the code optimization process.
The string function provided by Delphi contains a pos function, which is defined:

Function pos (substr: string; s: string): integer;

It is used to search for the string substr in string S. The returned value is the position where substr first appeared in S. If not found, the return value is 0.
During my preparation of webseizer software (which has been downloaded from the sky software station), POS cannot meet the requirements. On the one hand, when processing strings in a Web page, it must be case insensitive, that is, the meaning of

Function rightpos (const substr, S: string): integer;
VaR
IPOs: integer;
Tmpstr: string;
Begin
Tmpstr: = s;
IPOs: = pos (substr, tmpstr); Result: = 0;
// Find the location where substr appears for the first time
While IPOs <> 0 do
Begin
Delete (tmpstr, 1, IPOs + Length (substr)-1 );
// Delete the searched characters
Result: = Result + IPOs;
IPOs: = pos (substr, tmpstr); // find the position where the substr appears
If IPOs = 0 Then break;
Result: = Result + Length (substr)-1;
End;
End;

The delete function is used in this function. Let's take a look at the implementation process of the delete function in the system. Pas file. See the following code:

Procedure _ lstrdelete {var S: ansistring; index, Count: integer };
ASM
{Eax pointer to s}
{EdX index}
{ECx count}
Push EBX
Push ESI
Push EDI
MoV EBX, eax
MoV ESI, EDX
MoV EDI, ECx
Call uniquestring
MoV edX, [EBX]
Test edX, EDX {source already empty:
Nothing to do}
Je @ exit
MoV ECx, [edX-skew]. strrec. Length
{Make index 0-based, if not in [0 .. length (S)-1]
Do nothing}
Dec ESI
Jl @ exit
Cmp esi, ECx
Jge @ exit
{Limit count to [0 .. length (S)-Index]}
Test EDI, EDI
Jle @ exit
Sub ECx, ESI {ECx = length (S)-Index
}
Cmp edi, ECx
Jle @ 1
MoV EDI, ECx
@ 1:
{Move length-index-count characters from
S + index + count to S + index}
Sub ECx, EDI {ECx = length (S)-Index
-Count}
Add edX, ESI {edX = S + index}
Lea eax, [edX + EDI] {eax = S + index + Count}
Call move
{Set length (s) to length (S)-count}
MoV edX, [EBX]
MoV eax, EBX
MoV edX, [edX-skew]. strrec. Length
Sub edX, EDI
Call _ lstrsetlength
@ Exit:
Pop EDI
Pop ESI
Pop EBX
End;

The delete function has the following two sentences: Call move and call_lstrsetlength. Here, the move function copies a memory block to another address, and the lstrsetlength function changes the length of the string, which also contains code for memory allocation. These memory operations all consume the CPU running time, so the delete function is also a function that consumes the CPU running time. To avoid using these functions as much as possible, I have rewritten the custom function rightpos.
After modification, the delete and Pos functions are no longer used, and memory operations are directly performed through pointers, improving efficiency.

Function rightposex (const substr, S: string): integer;
VaR
IPOs: integer;
Tmpstr: string;
I, j, lvlen: integer;
Pchars, pcharsub: pchar;
Begin
Pchars: = pchar (s); // convert the string to the pchar format
Pcharsub: = pchar (substr );
Result: = 0;
Lvlen: = length (substr );
For I: = 0 to length (S)-1 do
Begin
For J: = 0 to lvlen-1 do
Begin
If pchars [I + J] <> pcharsub [J] Then break;
End;
If J = lvlen then result: = I + 1;
End;
End;

Please refer to the first sentence pchars: = pchar (s). It is used to forcibly convert the Delphi string to the pchar format (pchar is a standard string used in windows and does not contain length information, use 0 as the end flag), and obtain the pointer pchars pointing to the pchar string.
The following describes how to measure the running time of a custom function. To improve the measurement accuracy and reduce randomness, we calculate the time required to repeat 10000 times. The Code is as follows:

VaR
I, Len, IPOs: integer;
Performancecount1, performancecount2, Count: int64;
Begin
Len: = 10000; // repeated times
Queryperformancecounter (performancecount1); // starts counting
For I: = 0 to len-1 do
Begin
IPOs: = rightpos ('12', edit1.text); // function to be tested
End;
Queryperformancecounter (performancecount2); // end count
Count: = (PerformanceCount2-PerformanceCount1 );
Label1.caption: = inttostr (IPOs) + 'time = '+ inttostr (count );
End;

My configuration is duron700, with 10000 MB of memory. The rightpos function has been repeated for times in the test. The parameters used by rightpos are substr = 12, S = edit12ewew12tet. The measured result is Count = 217000, and several other functions are compared. The results are as follows:

Function Name
Repeated times
Queryperformancecounter Count value

Pos
10000
150000

Rightpos
10000
217000

Rightposex
10000
160000

We can see that the test results are satisfactory. The improved rightposex function is much more efficient than rightpos. Considering that the test string is short, the effect of using a long string is more obvious. If you directly use the string format of Delphi instead of pchar format, the efficiency can be improved. However, the string format is customized by the Delphi language, which causes compatibility issues. Therefore, the string search functions of this version are not listed, and the reader can easily write them based on the previous code. The question of how to implement code optimization is a matter of benevolence and wisdom. Some focus on improving efficiency, while others focus on ensuring compatibility. This requires a trade-off during actual use.

 

----

Actual test,

{*

// Long string (about 1 MB)

1000 times

See demos for BDS 2007
(Delete) Time: 323301
(Copystr) Time: 953036

(Lastposex) pos: 144881
Time: 3665003
(POS) pos: 58745
Time: 314023
(Fastposex) pos: 58745
Time: 11383136
(Fstat) pos: 58745
Time: 354948
(Smartpos) pos: 58745
Time: 206409

*}

 

Const
Count _ num = 10000;

Procedure tform1.btndeleteandcopystrclick (Sender: tobject );
VaR
I, lvlen, IPOs: integer;
Performancecount1, performancecount2, Count: int64;
Lvsubstring, lvsourcestring: string;
Begin
Lvlen: = count_num; // number of repetitions

Lvsourcestring: = edtsourcestring. text;
If chkusememosource. Checked then
Begin
Lvsourcestring: = mmosourcestring. text;
Lvlen: = lvlen Div 10;
End;

 

Queryperformancecounter (performancecount1); // starts counting
Lvsubstring: = lvsourcestring;
For I: = 0 to lvlen-1 do
Begin
Delete (lvsubstring, 1, 1 );
End;
Queryperformancecounter (performancecount2); // end count
Count: = (performancecount2-performancecount1 );
Mmomessage. lines. Add ('(delete) Time:' + inttostr (count ));

Queryperformancecounter (performancecount1); // starts counting
Lvsubstring: = lvsourcestring;
For I: = 0 to lvlen-1 do
Begin
Lvsubstring: = copystr (lvsubstring, 2, length (lvsubstring ));
End;
Queryperformancecounter (performancecount2); // end count
Count: = (performancecount2-performancecount1 );
Mmomessage. lines. Add ('(copystr) Time:' + inttostr (count ));

End;

Procedure tform1.btnpostestclick (Sender: tobject );
VaR
I, lvlen, IPOs: integer;
Performancecount1, performancecount2, Count: int64;
Lvsubstring, lvsourcestring: string;
Begin

Lvlen: = count_num; // number of repetitions

Lvsourcestring: = edtsourcestring. text;
Lvsubstring: = edtpostest. text;
If chkusememosource. Checked then
Begin
Lvsourcestring: = mmosourcestring. text;
Lvlen: = lvlen Div 10;
End;

Queryperformancecounter (performancecount1); // starts counting
For I: = 0 to lvlen-1 do
Begin
IPOs: = lastposex (lvsubstring, lvsourcestring); // function to be tested
End;
Queryperformancecounter (performancecount2); // end count
Count: = (performancecount2-performancecount1 );
Mmomessage. lines. Add ('(lastposex) pos:' + inttostr (IPOs) + slinebreak + 'time: '+ inttostr (count ));

Queryperformancecounter (performancecount1); // starts counting
For I: = 0 to lvlen-1 do
Begin
IPOs: = pos (lvsubstring, lvsourcestring); // function to be tested
End;
Queryperformancecounter (performancecount2); // end count
Count: = (performancecount2-performancecount1 );
Mmomessage. lines. Add ('(POS) pos:' + inttostr (IPOs) + slinebreak + 'time: '+ inttostr (count ));

Queryperformancecounter (performancecount1); // starts counting
For I: = 0 to lvlen-1 do
Begin
IPOs: = fastposex (pchar (lvsourcestring), length (lvsourcestring), pchar (lvsubstring), length (lvsubstring); // function to be tested
End;
Queryperformancecounter (performancecount2); // end count
Count: = (performancecount2-performancecount1 );
Mmomessage. lines. Add ('(fastposex) pos:' + inttostr (IPOs) + slinebreak + 'time: '+ inttostr (count ));

Queryperformancecounter (performancecount1); // starts counting
For I: = 0 to lvlen-1 do
Begin
IPOs: = fstat (lvsubstring, lvsourcestring); // function to be tested
End;
Queryperformancecounter (performancecount2); // end count
Count: = (performancecount2-performancecount1 );
Mmomessage. lines. Add ('(fstat) pos:' + inttostr (IPOs) + slinebreak + 'time: '+ inttostr (count ));

Queryperformancecounter (performancecount1); // starts counting
For I: = 0 to lvlen-1 do
Begin
IPOs: = smartpos (lvsubstring, lvsourcestring); // function to be tested
End;
Queryperformancecounter (performancecount2); // end count
Count: = (performancecount2-performancecount1 );
Mmomessage. lines. Add ('(smartpos) pos:' + inttostr (IPOs) + slinebreak + 'time: '+ inttostr (count ));
End;

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.