Re: [fpc-pascal] Re: UnicodeString comparison performance
HI, On Mon, 2012-07-23 at 16:58 +0200, OBones wrote: Jonas Maebe wrote: On 23 Jul 2012, at 10:58, OBones wrote: leledumbo wrote: I look at the generated code and in the direct one there's additional overhead of decrementing the reference counter on each iteration. I see it too now (I forgot about the -a option). I can understand why there is a call to the decrementer outside the loop when using the variable, but I don't understand why it pushes it completely out of the loop. I mean, isn't there a reference count problem here? Reference counted data types are returned by reference in a location passed to the function by the caller. The compiler here passes the address of S to the function, so that when assigning something to the function result inside the function, S' reference count gets decreased. The fact that when the result is returned in a temp, this temp also gets finalized on the caller side before the call is just a code generator inefficiency. I've changed that in trunk. Thanks for the explanation and the fix. Because the finalization happened too early, those memory allocations and deallocations were very costly and I found the direct code to be 30 times slower. Doing it this way has the advantage of being inherently thread safe, but considering the performance penalty, I have moved to doing it this way: var Buffer: array [0..1024*1024-1] of WideChar; BufferLock: NativeInt; function GetSomeString(Index: Integer): UnicodeString; begin while BufferLock 0 do Sleep(1); InterlockedIncrement(BufferLock); try CallToAnAPIThatWritesBackAWideString(@Buffer[0], Length(Buffer) - 1); Result := PWideChar(@Buffer[0]); finally InterlockedDecrement(BufferLock); end; end; This works, with an equivalent penalty on both methods and is threadsafe (I believe). This code is not thread safe at all. A thread switch after the while loop and before the increment will not prevent progress on other threads, so multiple threads can enter the critical section. Use EnterCriticalSection/LeaveCriticalSection from the RTL if you need that. If you could somewhat decrease the size of your buffer to something reasonable - do you really expect to translate a string with 1M chars? - use the stack. Actually even a 2M data object on the stack might be reasonable. Further, in any case you'll need some code that works in all cases anyway - what if your string does exceed 1M chars after all? I mean, on a 1M string, heap allocation will probably be the least of your performance worries. This will completely avoid use of any synchronization primitive. E.g. function GetSomeString(index : integer) : UnicodeString; const bufsize = 1024; // as you wish var buffer : array[0..bufsize-1] of WideChar; pbuffer : PWideChar; islongstring : boolean; lengthofstring : integer; begin lengthofstring := length(stringfromindex(integer)); islongstring := lengthofstring bufsize; if (islongstring) then pbuffer := getmem(lengthofstring * sizeof(WideChar)); else pbuffer := @buffer; CallToAnAPIThatWritesBackAWideString(stringfromindex(integer), pbuffer, lengthofstring); if (islongstring) then freemem(pbuffer); result := pbuffer; end; You may want to improve the code further by e.g. checking whether the memory allocation has been successful or not; or factor out the case when the string is big into a separate method to improve readability. Thomas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Re: UnicodeString comparison performance
Thomas Schatzl wrote: This code is not thread safe at all. A thread switch after the while loop and before the increment will not prevent progress on other threads, so multiple threads can enter the critical section. Well, yes, even if under Windows it's rare that a thread is preempted right in the middle of its execution. At least that's what my own experience has told me and why I'm calling Sleep in the while loop, so that the thread yields to other ones. Use EnterCriticalSection/LeaveCriticalSection from the RTL if you need that. I did not because I thought that would be too slow, but it turns out it's not so yes, it's much better. If you could somewhat decrease the size of your buffer to something reasonable - do you really expect to translate a string with 1M chars? - use the stack. Actually even a 2M data object on the stack might be reasonable. That's the highest value that the documentation of the API is giving, so I guess the API will respect its own publicized contract. function GetSomeString(index : integer) : UnicodeString; const bufsize = 1024; // as you wish var buffer : array[0..bufsize-1] of WideChar; pbuffer : PWideChar; islongstring : boolean; lengthofstring : integer; begin lengthofstring := length(stringfromindex(integer)); islongstring := lengthofstring bufsize; if (islongstring) then pbuffer := getmem(lengthofstring * sizeof(WideChar)); else pbuffer := @buffer; CallToAnAPIThatWritesBackAWideString(stringfromindex(integer), pbuffer, lengthofstring); if (islongstring) then freemem(pbuffer); result := pbuffer; end; Thanks for your example, but it implies that the string length is known before calling the API while this is not the case. The API is given a buffer and a maximum length, a buffer into which it writes a zero terminated string. But the length of that string cannot be known beforehand, hence the reason why I wrote it that way. Note also that having buffer local to the function is just as bad (performance wise) as setting the length of the result string. In the end, many thanks for your suggestions, I'll go with the critical section as it is much safer. Regards Olivier ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Re: UnicodeString comparison performance
Am 24.07.2012 13:21, schrieb OBones: Thomas Schatzl wrote: This code is not thread safe at all. A thread switch after the while loop and before the increment will not prevent progress on other threads, so multiple threads can enter the critical section. Well, yes, even if under Windows it's rare that a thread is preempted right in the middle of its execution. At least that's what my own experience has told me and why I'm calling Sleep in the while loop, so that the thread yields to other ones. Windows will preempt a thread once it's time slice has run out or it yields it's execution. In the first case it does not matter whether the thread is inside some function execution, because the sheduler does not know about such a concept. Regards, Sven ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
[fpc-pascal] Dynamic messaging in Delphi
I was asking on the Mac Pascal list if Delphi had any ways to invoke methods on objects which the class was unknown at compile time (like a class that invokes a user defined delegate commonly used in Cocoa Mac programming and I assume Delphi not knowing) and one user told me interfaces will work for this. Btw, I'm aware you can use strings to invoke methods with a single argument but I wanted something better since this has been a real drawback in Pascal for me in recent years. The idea is Main.pas has a delegate class which implements IMyInterface and MyInterface.pas declares the interface and can invoke its methods using a generic delegate object (typed TObject). This is really typical of UI elements like a button that wants to tell a receiver an action occurred but doesn't know the class of the receiving object. Providing this example works it's sort of a workaround to multiple inheritence but I don't see that Pascal would be capable of this, i.e. simply type casting an object and forcing it to call a method that may or may not exist (I feel like I tried this before and got crashing). He swears this works and no one else answered otherwise but I'm getting Error: Class or Object types TObject and IMyInterface are not related errors at the line shown below. Any ideas? Thanks. {$mode delphi} {$interfaces corba} unit MyInterface; interface type IMyInterface = interface procedure DoThis (value: integer); end; procedure InvokeDelegate (delegate: TObject); implementation procedure InvokeDelegate (delegate: TObject); var intfDelegate: IMyInterface; begin ERROR intfDelegate := IMyInterface(delegate); intfDelegate.DoThis(1); end; end. {$mode delphi} {$interfaces corba} program Main; uses MyInterface; type TMyDelegate = class (TInterfacedObject, IMyDelegate) procedure DoThis (value: integer); end; procedure TMyDelegate.DoThis (value: integer); begin writeln('did this ', value); end; var delegate: TMyDelegate; begin delegate := TMyDelegate.Create; TestDelegate(delegate); end. Regards, Ryan Joseph thealchemistguild.com ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Dynamic messaging in Delphi
Em 24/7/2012 11:13, Ryan Joseph escreveu: I was asking on the Mac Pascal list if Delphi had any ways to invoke methods on objects which the class was unknown at compile time (like a class that invokes a user defined delegate commonly used in Cocoa Mac programming and I assume Delphi not knowing) and one user told me interfaces will work for this. Btw, I'm aware you can use strings to invoke methods with a single argument but I wanted something better since this has been a real drawback in Pascal for me in recent years. The idea is Main.pas has a delegate class which implements IMyInterface and MyInterface.pas declares the interface and can invoke its methods using a generic delegate object (typed TObject). This is really typical of UI elements like a button that wants to tell a receiver an action occurred but doesn't know the class of the receiving object. Providing this example works it's sort of a workaround to multiple inheritence but I don't see that Pascal would be capable of this, i.e. simply type casting an object and forcing it to call a method that may or may not exist (I feel like I tried this before and got crashing). He swears this works and no one else answered otherwise but I'm getting Error: Class or Object types TObject and IMyInterface are not related errors at the line shown below. if delegate.GetInterface(IMyInterface, intfDelegate) then intfDelegate.DoThis Luiz Any ideas? Thanks. {$mode delphi} {$interfaces corba} unit MyInterface; interface type IMyInterface = interface procedure DoThis (value: integer); end; procedure InvokeDelegate (delegate: TObject); implementation procedure InvokeDelegate (delegate: TObject); var intfDelegate: IMyInterface; begin ERROR intfDelegate := IMyInterface(delegate); intfDelegate.DoThis(1); end; end. {$mode delphi} {$interfaces corba} program Main; uses MyInterface; type TMyDelegate = class (TInterfacedObject, IMyDelegate) procedure DoThis (value: integer); end; procedure TMyDelegate.DoThis (value: integer); begin writeln('did this ', value); end; var delegate: TMyDelegate; begin delegate := TMyDelegate.Create; TestDelegate(delegate); end. Regards, Ryan Joseph thealchemistguild.com ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Dynamic messaging in Delphi
I never heard of this syntax, is it Delphi only? Trying this I got Error: Interface type IMyInterface has no valid GUID. What else do I need to do? Thanks. On Jul 24, 2012, at 4:26 PM, Luiz Americo Pereira Camara wrote: if delegate.GetInterface(IMyInterface, intfDelegate) then intfDelegate.DoThis Regards, Ryan Joseph thealchemistguild.com ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Dynamic messaging in Delphi
Em 24/7/2012 20:17, Ryan Joseph escreveu: I never heard of this syntax, is it Delphi only? Trying this I got Error: Interface type IMyInterface has no valid GUID. What else do I need to do? The sintaxe i posted is for COM interfaces. For CORBA interfaces do IMyInterface = interface ['myintf'] procedure DoThis (value: integer); end; if delegate.GetInterface('myintf', intfDelegate) then intfDelegate.DoThis Luiz Thanks. On Jul 24, 2012, at 4:26 PM, Luiz Americo Pereira Camara wrote: if delegate.GetInterface(IMyInterface, intfDelegate) then intfDelegate.DoThis Regards, Ryan Joseph thealchemistguild.com http://thealchemistguild.com ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal