<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<br>
<div class="moz-cite-prefix">On 12/30/23 00:20, Sven Barth via
fpc-pascal wrote:<br>
</div>
<blockquote type="cite"
cite="mid:CAFMUeB8OJMJ8oBcx_62_pwTBiq8sjJMCFXArA0AEAsQhf7DxAA@mail.gmail.com">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<div dir="auto">
<div>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">Amir via fpc-pascal <<a
href="mailto:fpc-pascal@lists.freepascal.org"
moz-do-not-send="true" class="moz-txt-link-freetext">fpc-pascal@lists.freepascal.org</a>>
schrieb am Sa., 30. Dez. 2023, 08:11:<br>
</div>
<blockquote class="gmail_quote"
style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div dir="auto">
<div><br>
<div class="gmail_extra"><br>
<div class="gmail_quote">On Dec 29, 2023 9:50 PM,
Adriaan van Os <<a
href="mailto:adriaan@adriaan.biz"
target="_blank" rel="noreferrer"
moz-do-not-send="true"
class="moz-txt-link-freetext">adriaan@adriaan.biz</a>>
wrote:<br type="attribution">
<blockquote
style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Amir---
via fpc-pascal wrote:
<br>
> Hi all,
<br>
> <br>
> I have a List of record, where the record
has a WideString field.
<br>
> I have some code like the following:
<br>
> <br>
> function check(constref v: TMyRecord; data:
TListOfMyRecord): Boolean;
<br>
> var
<br>
> r: TMyRecord;
<br>
> <br>
> begin
<br>
> Result := False;
<br>
> for r in data do
<br>
> if r.State = v.State then
<br>
> Exit(True);
<br>
> end;
<br>
> <br>
> I call this method a lot and the CPU
profiling shows a lot of cpu time <br>
> spent on "fpc_copy_proc" (which I assume is
doing the deep copy on <br>
> records) from
"TCustomListEnumerator.GetCurrent".
<br>
> I considered other alternatives like using
enumerators but they all need <br>
> a to return a record (and hence copying the
widestring field).
<br>
> I can think of two solutions to get rid of
the wasting(!) so much time <br>
> on "fpc_copy_proc":
<br>
> 1) Changing the TMyRecord to TMyClass. But
then I need to Create and <br>
> Free a "lot" of objects.
<br>
> 2) Update TListOfMyRecord to
TListOfPointerToMyRecord. This requires a <br>
> "lot" of memory allocation/fragmentation.
<br>
> <br>
> Is there a better solution?
<br>
<br>
Pass the data parameter by reference.</blockquote>
</div>
</div>
</div>
<div dir="auto">This means I need to have a
ListOfMyRecord and a ListOfConstRefMyRecord, right? </div>
</div>
</blockquote>
</div>
</div>
<div dir="auto"><br>
</div>
<div dir="auto">No, that's not a thing.</div>
<div dir="auto"><br>
</div>
<div dir="auto">You simply need to declare your "data" parameter
as "constref" or "const" as well, just like your "v"
parameter. </div>
</div>
</blockquote>
Have a look at this piece of code (The complete code is attached):<br>
<font face="monospace">type</font><br>
<font face="monospace"> TMyRecord = record</font><br>
<font face="monospace"> Str: AnsiString;</font><br>
<font face="monospace"> Index: Integer;</font><br>
<br>
<font face="monospace"> end;</font><br>
<font face="monospace"> PMyRecord = ^TMyRecord;</font><br>
<br>
<font face="monospace"> TMyList = specialize
TList<TMyRecord>;</font><br>
<font face="monospace"> TMyPtrList = specialize
TList<PMyRecord>;</font><br>
<br>
<font face="monospace">function Check1(const MyList: TMyList):
Integer;</font><br>
<font face="monospace">var</font><br>
<font face="monospace"> data: TMyRecord;</font><br>
<br>
<font face="monospace">begin</font><br>
<font face="monospace"> Result := 0;</font><br>
<font face="monospace"> for data in MyList do</font><br>
<font face="monospace"> if data.Index mod 100 = 0 then</font><br>
<font face="monospace"> Inc(Result);</font><br>
<br>
<font face="monospace">end;</font><br>
<br>
<font face="monospace">function Check2(MyList: TMyList): Integer;</font><br>
<font face="monospace">var</font><br>
<font face="monospace"> data: TMyRecord;</font><br>
<br>
<font face="monospace">begin</font><br>
<font face="monospace"> Result := 0;</font><br>
<font face="monospace"> for data in MyList do</font><br>
<font face="monospace"> if data.Index mod 100 = 0 then</font><br>
<font face="monospace"> Inc(Result);</font><br>
<br>
<font face="monospace">end;</font><br>
<br>
<font face="monospace">function Check3(MyPtrList: TMyPtrList):
Integer;</font><br>
<font face="monospace">var</font><br>
<font face="monospace"> data: PMyRecord;</font><br>
<br>
<font face="monospace">begin</font><br>
<font face="monospace"> Result := 0;</font><br>
<font face="monospace"> for data in MyPtrList do</font><br>
<font face="monospace"> if data^.Index mod 100 = 0 then</font><br>
<font face="monospace"> Inc(Result);</font><br>
<br>
<font face="monospace">end;</font><br>
<br>
<br>
I compiled the code with `fpc -O3 -Sd -gv -g -gl ` and ran
`valgrind` on it (the output is attached). It does not look like
there is a big difference between the Check1 and Check2 but Check3
is about 20 times faster than the other two.<br>
I believe the issue could be resolved if we make
"TCustomListWithPointers.GetPtrEnumerator" a public method. Then,
one can implement the following function:<br>
<br>
<font face="monospace">function Check4(MyList: TMyList): Integer;</font><br>
<font face="monospace">....</font><br>
<font face="monospace"> it := MyList.GetPreEnumerator;</font><br>
<font face="monospace"> while it.MoveNext do</font><br>
<font face="monospace"> begin</font><br>
<font face="monospace"> if it.Current^.Index mod 100 = 0 then</font><br>
<font face="monospace"> ....</font><br>
<font face="monospace"> end;</font><br>
<br>
</body>
</html>