Inclocked/declocked

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Inclocked/declocked

Ryan Joseph
I was time profiling some code and saw these 2 functions taking up large amounts of time. They’re coming from dynamic arrays and SetLength I believe but I was curious what they are exactly because I don’t believe I’ve seen them before. Is this normal for resizing dynamic arrays or  are they doing something else I would be interested in?

SYSTEM_$$_INCLOCKED$INT64
SYSTEM_$$_DECLOCKED$INT64$$BOOLEAN

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Inclocked/declocked

Free Pascal - General mailing list

Am 11.09.2017 11:14 schrieb "Ryan Joseph" <[hidden email]>:
>
> I was time profiling some code and saw these 2 functions taking up large amounts of time. They’re coming from dynamic arrays and SetLength I believe but I was curious what they are exactly because I don’t believe I’ve seen them before. Is this normal for resizing dynamic arrays or  are they doing something else I would be interested in?
>
> SYSTEM_$$_INCLOCKED$INT64
> SYSTEM_$$_DECLOCKED$INT64$$BOOLEAN

They're used for the reference counter of the array (or string or interface). The reference counter changes each time you assign an array or pass it to a by-value parameter or if you change a value (cause the compiler/RTL needs to make sure that the reference to the array is unique then).

Regards,
Sven


_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Inclocked/declocked

Ryan Joseph

> On Sep 11, 2017, at 4:20 PM, Sven Barth via fpc-pascal <[hidden email]> wrote:
>
> They're used for the reference counter of the array (or string or interface). The reference counter changes each time you assign an array or pass it to a by-value parameter or if you change a value (cause the compiler/RTL needs to make sure that the reference to the array is unique then).
>
>

Maybe this is relevant to my poor performance then but perhaps it’s just the way the time profiler works? It’s telling me the program is spending  16% in system_delocked which seems extreme.

See if I have a dynamic array and call arr[0] := xxx then those functions will be called (or FPC_DYNARRAY_ASSIGN)? I also have a dynamic array in an object which is passed a function parameter, but not by value so that doesn’t fit your description.

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Inclocked/declocked

Free Pascal - General mailing list
On 11.09.2017 11:46, Ryan Joseph wrote:

>
>> On Sep 11, 2017, at 4:20 PM, Sven Barth via fpc-pascal <[hidden email]> wrote:
>>
>> They're used for the reference counter of the array (or string or interface). The reference counter changes each time you assign an array or pass it to a by-value parameter or if you change a value (cause the compiler/RTL needs to make sure that the reference to the array is unique then).
>>
>>
>
> Maybe this is relevant to my poor performance then but perhaps it’s just the way the time profiler works? It’s telling me the program is spending  16% in system_delocked which seems extreme.
>
> See if I have a dynamic array and call arr[0] := xxx then those functions will be called (or FPC_DYNARRAY_ASSIGN)? I also have a dynamic array in an object which is passed a function parameter, but not by value so that doesn’t fit your description.

I've rechecked and the thing is as follows:
- the IncLocked call happens each time you assign a dynamic array to
another dynamic array variable or a by-value parameter (this also
includes being part of a record, but not a class instance or TP-style
object)
- the DecLocked call happens each time the array is cleared (as long as
the reference count is > 0 this only means a decrement of the count)
which happens if you assign Nil, assign a different array (the
destination array is "cleared") or if the array variable goes out of scope

The two routines are also used in context of Ansi- and UnicodeString
variables as well as reference counted interfaces (aka COM-style
interfaces).

In contrast to what I wrote earlier the compiler does however not ensure
a unique array if you only change an element, so given the following
example:

=== code begin ===

program tarrtest;

procedure Test(aArg: array of LongInt);
var
  i: LongInt;
begin
  for i in aArg do
    Writeln(i);
end;

var
  ia1, ia2: array of LongInt;
begin
  ia1 := [1, 2, 3];
  ia2 := ia1;
  ia1[1] := 5;
  Test(ia1);
  Test(ia2);
end.

=== code end ===

The output will be

=== output begin ===

1
5
3
1
5
3

== output end ===

Regards,
Sven
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Inclocked/declocked

Ryan Joseph

> On Sep 12, 2017, at 2:35 AM, Sven Barth via fpc-pascal <[hidden email]> wrote:
>
> I've rechecked and the thing is as follows:
> - the IncLocked call happens each time you assign a dynamic array to
> another dynamic array variable or a by-value parameter (this also
> includes being part of a record, but not a class instance or TP-style
> object)
> - the DecLocked call happens each time the array is cleared (as long as
> the reference count is > 0 this only means a decrement of the count)
> which happens if you assign Nil, assign a different array (the
> destination array is "cleared") or if the array variable goes out of scope
>
> The two routines are also used in context of Ansi- and UnicodeString
> variables as well as reference counted interfaces (aka COM-style
> interfaces).
>
> In contrast to what I wrote earlier the compiler does however not ensure
> a unique array if you only change an element, so given the following
> example:

I removed the dynamic arrays from the my code and replaced with static arrays which fixed the performance problem I was having.

It’s still not clear when this was being called (how could I track in the debugger?) but I consider this a pretty serious bug and I wouldn’t use dynamic arrays in high performance code.

If I had to guess I would say it was from SetLength but 16%? When I replaced with static arrays and used ReAllocMem instead this didn’t happen so what are those 2 functions doing to eat up so much CPU?

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Inclocked/declocked

Free Pascal - General mailing list

Am 12.09.2017 06:54 schrieb "Ryan Joseph" <[hidden email]>:
>
>
> > On Sep 12, 2017, at 2:35 AM, Sven Barth via fpc-pascal <[hidden email]> wrote:
> >
> > I've rechecked and the thing is as follows:
> > - the IncLocked call happens each time you assign a dynamic array to
> > another dynamic array variable or a by-value parameter (this also
> > includes being part of a record, but not a class instance or TP-style
> > object)
> > - the DecLocked call happens each time the array is cleared (as long as
> > the reference count is > 0 this only means a decrement of the count)
> > which happens if you assign Nil, assign a different array (the
> > destination array is "cleared") or if the array variable goes out of scope
> >
> > The two routines are also used in context of Ansi- and UnicodeString
> > variables as well as reference counted interfaces (aka COM-style
> > interfaces).
> >
> > In contrast to what I wrote earlier the compiler does however not ensure
> > a unique array if you only change an element, so given the following
> > example:
>
> I removed the dynamic arrays from the my code and replaced with static arrays which fixed the performance problem I was having.
>
> It’s still not clear when this was being called (how could I track in the debugger?) but I consider this a pretty serious bug and I wouldn’t use dynamic arrays in high performance code.

Dynamic arrays are a fairly high level construct. The general advice for them is not to repeatedly grow (or shrink) them by miniscule amounts, but mainly by twice the current length. (Don't know if you've been doing that)

> If I had to guess I would say it was from SetLength but 16%? When I replaced with static arrays and used ReAllocMem instead this didn’t happen so what are those 2 functions doing to eat up so much CPU?

The Inc-/DecLocked routines perform a locked increment/decrement, so they're blocking the memory bus for all cores (simply spoken), thus leading to a higher CPU utilization. On e.g. i386 there is an optimisation to only do that locking if IsMultiThread is True (some other platforms might benefit from that optimization as well :/ ).
Additionally they are the leave routines of the dynamic array management code, so the time would be really used up there if not for the locking.

Regards,
Sven


_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Inclocked/declocked

Mark Morgan Lloyd-5
In reply to this post by Free Pascal - General mailing list
On 11/09/17 19:45, Sven Barth via fpc-pascal wrote:

> I've rechecked and the thing is as follows:- the IncLocked call happens each time you assign a dynamic array toanother dynamic array variable or a by-value parameter (this alsoincludes being part of a record, but not a class instance or TP-styleobject)- the DecLocked call happens each time the array is cleared (as long asthe reference count is > 0 this only means a decrement of the count)which happens if you assign Nil, assign a different array (thedestination array is "cleared") or if the array variable goes out of scope
> The two routines are also used in context of Ansi- and UnicodeStringvariables as well as reference counted interfaces (aka COM-styleinterfaces).
> In contrast to what I wrote earlier the compiler does however not ensurea unique array if you only change an element, so given the followingexample:

In the general case, will these force a membar or a cache flush?

--
Mark Morgan Lloyd
markMLl .AT. telemetry.co .DOT. uk

[Opinions above are the author's, not those of his employers or colleagues]
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Inclocked/declocked

Ryan Joseph
In reply to this post by Free Pascal - General mailing list

> On Sep 12, 2017, at 12:56 PM, Sven Barth via fpc-pascal <[hidden email]> wrote:
>
> The Inc-/DecLocked routines perform a locked increment/decrement, so they're blocking the memory bus for all cores (simply spoken), thus leading to a higher CPU utilization. On e.g. i386 there is an optimisation to only do that locking if IsMultiThread is True (some other platforms might benefit from that optimization as well :/ ).
> Additionally they are the leave routines of the dynamic array management code, so the time would be really used up there if not for the locking.

That’s probably it then even though I wasn’t growing the arrays by single elements (ReAllocMem didn’t give me problems). De facto Solution is to be safe and not use dynamic arrays in low-level high performance code.

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal