Leaderboard
Popular Content
Showing content with the highest reputation on 01/05/21 in all areas
-
Performance of MOVE vs + for concatenating mixed type values
Attila Kovacs replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
You mean after somebody read the RTL code for you? -
Performance of MOVE vs + for concatenating mixed type values
Anders Melander replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Less questions. More autonomy. -
The Case of Delphi Const String Parameters
Dalija Prasnikar replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
This problem is pure ARC problem. One instance of something is destroyed when other one is created and assigned because const parameter did not trigger reference counting mechanism - this is why const is used as speed optimization in the first place. Same thing that happens with strings happens with reference counted objects, but it is easier to see what happens with objects. You need form with memo and button to test following code. IFoo = interface function GetCount: Integer; function GetNumber: Integer; end; TFoo = class(TInterfacedObject, IFoo) private FNumber: Integer; public constructor Create(ANumber: Integer); destructor Destroy; override; function GetCount: Integer; function GetNumber: Integer; end; constructor TFoo.Create(ANumber: Integer); begin inherited Create; FNumber := ANumber; Form1.Memo1.Lines.Add('Created ' + FNumber.ToString); end; destructor TFoo.Destroy; begin Form1.Memo1.Lines.Add('Destroyed ' + FNumber.ToString); inherited; end; function TFoo.GetCount: Integer; begin Result := FRefCount; end; function TFoo.GetNumber: Integer; begin Result := FNumber; end; procedure TForm1.Button1Click(Sender: TObject); var s1: IFoo; procedure Test(const Value: IFoo); begin s1 := TFoo.Create(456); Memo1.Lines.Add('Test Value ' + Value.GetNumber.ToString); end; begin s1 := TFoo.Create(123); Test(s1); end; Output is: Created 123 Created 456 Destroyed 123 Test Value 123 Destroyed 456 It is pretty obvious that object instance holding 123 is destroyed before its value is printed. Value.GetNumber.ToString is accessing dangling pointer - if the memory where object or string previously occupied is not reused, you may get expected value even though that instance is dead, but if memory is reused in the meantime you will read content of some other data. Also the whole thing might crash, or it might not. Basically you get undefined behavior. -
When sorting a “StringList” is very costly
David Heffernan replied to dummzeuch's topic in Tips / Blogs / Tutorials / Videos
Paying the price for using a GUI control to hold your data, rather than to view your data. -
The Case of Delphi Const String Parameters
balabuev replied to Mike Torrettinni's topic in RTL and Delphi Object Pascal
Agree. I'm always use "const" modifier before any parameter of managed type (arrays, strings, interfaces, references to procedure types) or of big record type, because it executes faster. I remeber one or two such issues, which, by the way, was quite hard to debug, but, imho, this is still not the reason to remove all "const" parameter modifiers. -
Performance of MOVE vs + for concatenating mixed type values
Rollo62 replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
function PrepareLineForExport2(const aDataIn: TData): string; begin Result := aDataIn.ID1.ToString + cSeparator + aDataIn.S1 + cSeparator + BoolToStr(aDataIn.B1) + cSeparator + aDataIn.S2 + cSeparator + aDataIn.C1 + cSeparator + aDataIn.S3 ; end; Sometimes I like to use a "prefix" pattern like this. To make things visually more readble, and to easily include/exclude parts for testing ( by puttin // in frontt). -
Performance of MOVE vs + for concatenating mixed type values
David Heffernan replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
The funny thing about this, is that the RTL code that implements a concatenation does this: Sum the length of all input strings. Allocate a new string of that length. Loop through all the input strings, moving their content to the new string. Return that new string. So even if this was your bottleneck, the RTL is already optimised!! In that original post that you linked, you were concatenating two strings, but repeatedly in a loop. So you had one allocation per expression. Here you have a single expression concatenating 11 strings. And that also has one allocation, because the RTL is, in this instance, not stupid. Bottom line is that your code using Move should be slower!! Please, please, please, take on board the lesson that optimisation starts with first identifying, with confidence, what your bottleneck is. If you can just take that lesson, then you will save lots of your time (and ours). -
Performance of MOVE vs + for concatenating mixed type values
David Heffernan replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
It's like we are talking two completely different languages. -
Performance of MOVE vs + for concatenating mixed type values
David Heffernan replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
You aren't doing it effectively though, because you are still creating lots of intermediate string objects along the way. Your goal should be to create no intermediate string objects. In my own code which writes huge YAML files containing lots of numbers (both integer and floating point), I export without any heap allocation, without any intermediate string objects. I use functions like this: // disable range checks and overflow checks so that Abs() functions in case Value = Low(Value) {$R-} {$Q-} function CopyIntegerToAnsiBuffer(const Value: Integer; var Buffer: array of AnsiChar): Integer; var i, j: Integer; val, remainder: Cardinal; negative: Boolean; tmp: array [0..15] of AnsiChar; begin negative := Value<0; val := Abs(Value); Result := 0; repeat DivMod(val, 10, val, remainder); tmp[Result] := AnsiChar(remainder + Ord('0')); Inc(Result); until val=0; if negative then begin tmp[Result] := '-'; Inc(Result); end; Assert(Result<=Length(Buffer)); i := 0; j := Result-1; while i<Result do begin Buffer[i] := tmp[j]; Inc(i); Dec(j); end; end; {$IFDEF RANGECHECKSON}{$R+}{$ENDIF} {$IFDEF OVERFLOWCHECKSON}{$Q+}{$ENDIF} This performs the same job as IntToStr but writes to a user supplied buffer, rather than forcing a heap allocation and a new string. The user supplied buffer is stack allocated, and then gets pushed to the file using one of my buffered stream classes. I'm using ANSI characters here because the output encoding is UTF-8. I have similar code for floating point, but that's obviously much more complex. As an aside, this has the benefit that I can escape the tyranny of the RTL's broken code which converts between floating point and text. In summary though, I don't think you are going about this in the right way. You have not yet correctly identified the bottleneck in your code. I know I keep saying this, but it doesn't make it any less true each time I say it. -
Security - How freaky can you get!
dummzeuch replied to Clément's topic in Algorithms, Data Structures and Class Design
I think you meant "worse" here. -
Security - How freaky can you get!
Arnaud Bouchez replied to Clément's topic in Algorithms, Data Structures and Class Design
Signing the executable is the key here. And also make a minimal security audit. A password should be hashed, and never stored in the executable itself. It has nothing to do with Delphi. It was a poor security design of the application. About logic security, and reverse engeniering, Java or C# are much worse than Delphi. You can easily decompile Java or C# executable.... unless it has been obfuscated explicitly. I can tell you that I "hacked" so many C# dlls which we lost the source... 😉 Whereas a Delphi exe is compiled, and lack a lot of RTTI, so it is much more difficult to get something about it. -
Performance of MOVE vs + for concatenating mixed type values
Arnaud Bouchez replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Note that you don't store the content, you re-assign each new line. So you are testing something non reallistic, which is worthless trying to optimize it. What is slow is not data moving, but memory allocation. One performance problem is the temporary allocation of strings, if you call Integer.ToString. For our mORMot TTextWriter, we don't use any temporary allocation, and even have pre-computed values for the smallest integers. Note that Delphi TStringBuilder will actually be slower on Win32 than naive concatenation. It also allocate a temporary string for integer appending... 😞 https://www.delphitools.info/2013/10/30/efficient-string-building-in-delphi/3/ I would stick with naive string concatenation, and I guess it will be fast enough in practice. It would be premature optimization otherwise. -
Using a timer and two edits on a form I've created small tool (which is not full featured "spy", of course): procedure TForm11.Timer1Timer(Sender: TObject); var awn: HWND; buf: array[0..1024] of Char; begin awn := GetForegroundWindow; if awn <> 0 then begin GetClassName(awn, @buf, Length(buf)); Edit1.Text := buf; end else Edit1.Text := ''; Edit2.Text := IntToHex(awn, 8); end; So, clicking on different forms in Photoshop gives the following results: 1) "Photoshop". 2) "OWL.Dock". So, the conclusion: active window is changed to follow real focus, and so, main form just "simulates" its pseudo-active state. I've also checked Paint.NET - same results.
-
Photoshop also have such behavior: Photoshop does not respect theme colors, but this is not big deal. I'm sure that Paint.NET (just like Photoshop) - are just a custom drawn non-client area of the main form. Which is fine - this seems to be the closest possible solution. And - good idea about "spy" tool to realize what really happens. I thought about it yesterday too... Also, I want to duplicate my simple code, cause it was hidden by other messages. It allows to keep impression that the form is always "active", even if the user clicked on another form or application. So, this way can be used to "simulate" what I need: type TForm1 = class(TForm) private procedure WMNCActivate(var Message: TWMNCActivate); message WM_NCACTIVATE; end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.WMNCActivate(var Message: TWMNCActivate); begin Message.Active := True; inherited; end; The code works even with standard forms, without the need to custom draw form's non-client area. Also, system shadow around the form, which is slightly different in active and non-active states, is respected.
-
Security - How freaky can you get!
FPiette replied to Clément's topic in Algorithms, Data Structures and Class Design
After reading you messages, I think that the software has been hacked by someone inside the company, or by someone hired by an employee. That employee wanted to get access to the password protected resource and hacked the software (or asked some one to hack it). Search who benefit from the hack and you'll find the culprit. It is very difficult to prevent software hacking. Hack can be detected by signing the executable with strong cryptography and having an external tool to check the signature. The signature can be checked by the executable itself, but then the hacker can bypass this code. If an external tool check the signature, then the hacker has to hack that tool as well. Having the tool running from another computer, thru a network share would help. The hacker need to hack that other computer. -
Performance of MOVE vs + for concatenating mixed type values
Pierre le Riche replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
In the SetLength call you're calling Integer.ToString and BoolToStr in order to determine the resultant string lengths, and lower down you're calling those again to get the actual strings. I reckon that's where the 30% is going. Even if you fix that I doubt you'll see more than a marginal performance improvement going from PrepareLineForExport and PrepareLineForExport_MOVE. String concatenation is decently implemented in the RTL. (The 32-bit implementation is even in assembly language.) -
It's sampling every time it draws something. That doesn't mean that it necessarily resamples the whole bitmap though. It will only sample the parts that it needs in order to paint the visible part of the bitmap. Read this: https://graphics32.github.io/Docs/Additional Topics/Sampling and Rasterization.htm https://graphics32.github.io/Docs/Additional Topics/Repaint Optimization.htm Of course when scale < 1 then the whole bitmap will probably be visible and everything will be sampled. As far as I remember there's no repaint optimization with regard to panning - I guess that's something I could look into if I run out of other stuff to do Anyway, even if you did pan 1 pixel at a time (which I doubt you're doing) it should be fast enough that you shouldn't experience any stutter. Of course it depends on the type of sampler/kernel you're using, your hardware and the size of the bitmap but on my old system I can pan a zoomed (in or out) 4000x4000 multi layer bitmap without any noticeable stutter.
-
Security - How freaky can you get!
David Heffernan replied to Clément's topic in Algorithms, Data Structures and Class Design
Tampering with executables is pretty routine, and can be done for pretty much any program irrespective of the language it is coded in. The real question here is why the target was running a tampered executable in the first place. That seems like the real source of the problem, not that the original executable was written in Delphi. If your new customer thinks that the problem will be solved by writing programs in "safe" languages then he/she is delusional. Once you let an attacker execute their code in your computer, the game is over.