Jump to content

Arnaud Bouchez

  • Content Count

  • Joined

  • Last visited

  • Days Won


Arnaud Bouchez last won the day on February 13

Arnaud Bouchez had the most liked content!

Community Reputation

260 Excellent


Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Without a JIT, I don't see any much interest for WebAsm, to be honnest... I know that https://github.com/wasm3/wasm3 projects are good enough to run most simple processes. Having a Delphi version - sad it is not FPC compatible - is a good idea. Even if it is Wintel only. In terms of interpreting some logic, with proper sandboxing, a transpiler from other languages to JavaScript could be of a better interest, since most high-level features (like object mapping/dictionary, or strings) are already coded in compiled/native code. Since everyone is throughin away references, take a look at https://github.com/saghul/txiki.js coupled quickjs (fastest interpreter, but slower than Chakra, V8 or SM) and wasm3. 🙂 Edit: the FPC webassembly backend is more a proof of concept, just like the LLVM backend - on which it is based somehow, at least to produce the binary output. It lacks some pascal features, and is not ready to be used on any project sharing the same code than regular FPC pascal code. Also in this respect, the JavaScript FPC transpiler is much more advanced and usable.
  2. On Windows, you can use the UniScribe API to get the glyphs from UTF-16 sequences. We did that for our https://github.com/synopse/mORMot/blob/master/SynPdf.pas library. But it is not cross-platform at all! ICU is huge, but the cross-platform way of using it. This is what we did in mORMot 2 - not for glyphs but for case folding, comparison and codepage conversions. Check also https://github.com/BeRo1985/pucu/tree/master/src which is a pure-pascal Unicode library... I recently found https://github.com/bellard/quickjs/blob/master/libunicode.h which is very well written, and eventually available in our mORMot2 QuickJS wrapper.
  3. Arnaud Bouchez

    QueryPerformanceCounter precision

    To benchmarks instructions, you need specific SW tooling, and also proper HW. The reference is https://www.agner.org/optimize/#testp To benchmark Sleep() doesn't make any sense, especially on Windows. On windows, the Sleep() resolution is around the system timer which is typically between 14-20ms. Sleep() waits "at least" for the number of milliseconds specified. So in a waiting loop, you should never count the number of Sleep() iterations, but call GetTickCount64, with a timeout.
  4. Arnaud Bouchez

    Adressing IP with System.Net.HttpClient

    What is the error? I guess you have in fact an https/TLS error: the certificate is for the domain name, and you use the IP which doesn't match the certificate. So the request is rejected. Try to relax the HTTPS certification validation.
  5. As David wrote, mORMot has a 3 license - if you use MPL it is very commercial-project-friendly. TL&LR: Nothing to pay, just mention somewhere in your software that you used it, and publish any modification you may do to the source code. Another article worth looking at: https://www.delphitools.info/2015/03/17/long-strings-hash-vs-sorted-vs-unsorted/ It depends what you expect. Also note that for long strings, hashing may have a cost - this is why we implemented https://blog.synopse.info/?post/2021/02/12/New-AesNiHash-for-mORMot-2
  6. Arnaud Bouchez

    Edge Webview update (?)

    Personal note: each time I see GetIt involved, I remember that mORMot was never accepted as part of it because it was "breaking their license policy". In short, you could use any Delphi version (even the free edition) and create Client-Server apps with it. I guess this is the same reason the great ZEOS library or even UniDAC are not part of it, if I checked correctly their registration. That's why I prefer more open package solutions like Delphinus and I hope in the future the very promising https://github.com/DelphiPackageManager/DPM Old but still relevant discussion at https://synopse.info/forum/viewtopic.php?pid=17453#p17453
  7. Side note: inlining is not necessary faster. Sometimes, after inlining the compiler has troubles assigning properly the registers: so a sub-function with a loop is sometimes faster when NOT inlined, because the loop index and pointer could be in a register, whereas once inlined the stack may be used. The worse use of "inline;" I have seen is perhaps the inlining of FileCreate/FileClose/DeleteFile/RenameFile from SysUtils which required the Windows unit to be part of any unit calling it. With obviously no performance benefit because those calls are slow by nature. Embarcadero made this mistake in early versions of Delphi, then they fixed some of it (but RenameFile is still inlined!), and re-used "inline;" when POSIX was introduced... 😞 I had to redefine those functions in mormot.core.os.pas so that I was not required to write {$ifdef MsWindows} Windows, {$endif} in my units when writing cross-platform code...
  8. Arnaud Bouchez

    Micro optimization: Split strings

    Your code is sometimes not correct. For instance, CustomSplitWithPrecount() exit directly without setting result := nil so it won't change the value passed as input (remember than an array result is in fact a "var" appended argument). All those are microoptimisations - not worth it unless you really need it. I would not use TStringList for sure. But any other method is good enough in most cases. Also no need to use a PChar and increment it. In practice, a loop with an index of the string is safer - and slightly faster since you use only the i variable which is already incremented each time. To optimize any further, I would use PosEx() to find the delimiter which may be faster than your manual search on some targets. The golden rule is to make it right first. Then make it fast - only if it is worth it, and I don't see why it would be worth it.
  9. Arnaud Bouchez

    Quickly zero all local variables?

    First, all managed types (string, variable, dynamic arrays) will be already initialized with zero by the compiler. What you can do is define all local variables inside a record, then call FillChar() on it. There won't be any performance penalty procedure MyFunction; var i: integer; loc: record x,y,z: integer; a: array[0..10] of double; end; begin writeln(loc.x); // write random value (may be 0) FillChar(loc, SizeOf(loc), 0); writeln(loc.x); // write 0 for sure for i := 0 to high(loc.a) do writeln(loc.a[i]); // will write 0 values end; But as drawback, all those variables will be forced to be on stack, so the compiler won't be able to optimize and use register for them - which is the case for the "i" variable above. So don't put ALL local variables in the record, only those needed to be initialized. Anyway, if you have a lot of variables and a lot of code in a method, it may be time to refactor it, and use a dedicated class to implement the logic. This class could contain the variables of the "record" in my sample code. You could keep this class in the implementation section of your unit, for safety. It will be the safer way to debug - and test! One huge benefit of a dedicated class for any complex process is that it could be tested.
  10. If you look at the asm - at least on FPC - in fact CtrNistCarryBigEndian() is inlined so has very little impact. It is called 1/256th times, and only add a two inc/test opcodes. Using branchless instructions seems pointless in this part of the loop: DoBlock() takes dozen of cycles for sure, and the bottleneck is likely to be the critical section. Also note that 2^24 depends on the re-seed parameter, which may be set to something more than 2^24*16 bytes (even NIST seems to allow up to 2^48), so a 3 bytes counter won't be enough. CtrNistCarryBigEndian() is a nice and readable solution, in the context of filling a single block of 16 bytes. Current 32MB default for the reseed value is still far below from the NIST advice of 2^48. We used 32MB from user perspective - previous limit was 1MB which was really paranoid. Anyway, if an application needs a lot of random values, then it will instantiate its own TAesPrng, with a proper reseed, for each huge random need.
  11. Arnaud Bouchez

    Delphi 64bit compiler RTL speedup

    Nope: FPC Linux + mORMot DB and SOA layer since years. With high performance and stability - we had servers handling thousands of requests per seconds receiving TB of data running for months with no restart and no problem. Especially with our MM which uses much less memory than TBB. One problem I noticed on Linux with C memory managers running FPC services is that they are subject to SIGABRT if they encounter any memory problem. This is why we worked on our own https://github.com/synopse/mORMot2/blob/master/src/core/mormot.core.fpcx64mm.pas which consumes much less memory than TBB, and if there is a problem in our code, we have a GPF exception we can trace, and not a SIGABRT which kills the process. I can tell you that a SIGABRT for a service is a disaster - it always happen when you are far AFK and can't react quickly. And if you need to install something like https://mmonit.com/monit/ on your server, it becomes complicated...
  12. Two blog posts to share: https://blog.synopse.info/?post/2021/02/13/Fastest-AES-PRNG%2C-AES-CTR-and-AES-GCM-Delphi-implementation https://blog.synopse.info/?post/2021/02/12/New-AesNiHash-for-mORMot-2 TL&DR: new AES assembly code burst AES-CTR AES-GCM AES-PRNG and AES-HASH implementation, especially on x86_64, for mORMot 2. It outperforms OpenSSL for AES-CTR and AES-PRNG, and is magnitude times faster than every other Delphi library I know about.
  13. New hasher in town, to test and benchmark: https://blog.synopse.info/?post/2021/02/12/New-AesNiHash-for-mORMot-2 Murmur and xxHash just far away from it, in terms of speed, and also in terms of collisions I guess... 15GB/s on my Core i3, on both Win32 and Win64. The smallest length of 0-15 bytes are taken without any branch, 16-128 bytes have no loop, and 129+ are hashed with 128 bytes per iteration. Also note its anti-DOS abilities, thanks to its random seed at process startup. So it was especially tuned for a hashmap/dictionary.
  14. Arnaud Bouchez

    AnsiPos and AnsiString

    1. Use RawByteString instead of AnsiString if you don't want to force any conversion. 2. Note that Ansi*() functions are not all meant to deal with AnsiString, but they expect string/UnicodeString types, and deal with current system locale e.g. for comparison or case folding... A bit confusing indeed... 3. Consider using your own version of functions- as we did with https://github.com/synopse/mORMot2/blob/master/src/core/mormot.core.base.pas - so you are sure there is no hidden conversion. 4. The main trick is indeed to never let any 'Implicit string cast' warning unfixed. And sometimes use Alt+F2 to see the generated asm, and check there is no hidden "call" during the conversion. 5. Another good idea is to write some unit tests of your core process, uncoupled from TCP itself: write them in the original pre-Unicode Delphi, then recompile the code with the Unicode version of Delphi and ensure they do pass. It will save you a lot of time!
  15. Arnaud Bouchez

    Delphi 64bit compiler RTL speedup

    Tests were done last year on the last Debian.