Tag - multithread

Entries feed - Comments feed

2013-12-05

New Open Source Multi-Thread ready Memory Manager: SAPMM

Do you remember this former article about scalability of the Delphi memory manager, in multi-thread execution context?

Our SynScaleMM is still experimental.
But did pretty well, for an experiment!

At first, you can take a look at ScaleMM2, which is more stable, and based on the same ground.

But a new multi-thread friendly memory manager for Delphi just came out.
It is in fact the anonymous (and already famous) "NN memory manager" Primož talked about in his article about string building and memory managers.


(Note that in this article, our SynScaleMM was found to be scaling very well, but on the other hand, Primož did compile its benchmark program in Debug mode, so our TTextWriter was not in good shape: when you compile in Release mode, optimizations and inlining are ON, and our good TTextWriter just flies... See the note at the beginning of the article - this is why I never find those benchmarks very informative. I always prefer profiling from the real world with real useful process… and was never convinced by any such naive benchmark.)

OK, back to our business!

SapMM is an interesting beast.
https://code.google.com/p/sapmm

Sounds like if Alexei (the initial coder) has a C coding background. But that's fine when you have to deal with low-level structures and algorithms, as required by a memory manager. :)
It features everything we may ask for such a piece of code: clear design, optimized code (mostly by inlining process), memory leak reporting, some parameters for tuning.

It is only for Delphi XE (and up) under Win32 by now, but contributors are welcome!
It is used in production since more than half a year, and it passed all FastcodeMM benchmark tests.

If you want a direct link of the today's source code, without SVN, you may try this direct link from our site.
(but it probably will never be updated - you are warned)

Continue reading

2013-11-04

Updated mORMot database benchmark - including MS SQL and PostgreSQL

On an recent notebook computer (Core i7 and SSD drive), depending on the back-end database interfaced, mORMot excels in speed:

  • You can persist up to 570,000 objects per second, or retrieve more than 900,000 objects per second (for our pure Delphi in-memory engine);
  • When data is retrieved from server or client cache, you can read more than 900,000 objects per second, whatever the database back-end is;
  • With a high-performance database like Oracle and our direct access classes, you can write 65,000 (via array binding) and read 160,000 objects per second, over a 100 MB network;
  • When using alternate database access libraries (e.g. Zeos, or DB.pas based classes), speed is lower, but still enough for most work.

Difficult to find a faster ORM, I suspect.

The following tables try to sum up all available possibilities, and give some benchmark (average objects/second for writing or read).

In these tables:

  • 'SQLite3 (file full/off/exc)' indicates use of the internal SQLite3 engine, with or without Synchronous := smOff and/or DB.LockingMode := lmExclusive;
  • 'SQLite3 (mem)' stands for the internal SQLite3 engine running in memory;
  • 'SQLite3 (ext ...)' is about access to a SQLite3 engine as external database - either as file or memory;
  • 'TObjectList' indicates a TSQLRestServerStaticInMemory instance, either static (with no SQL support) or virtual (i.e. SQL featured via SQLite3 virtual table mechanism) which may persist the data on disk as JSON or compressed binary;
  • 'Oracle' shows the results of our direct OCI access layer (SynDBOracle.pas);
  • 'NexusDB' is the free embedded edition, available from official site;
  • 'Zeos *' indicates that the database was accessed directly via the ZDBC layer;
  • 'FireDAC *' stands for FireDAC library;
  • 'UniDAC *' stands for UniDAC library;
  • 'BDE *' when using a BDE connection;
  • 'ODBC *' for a direct access to ODBC;
  • 'Jet' stands for a MSAccess database engine, accessed via OleDB;
  • 'MSSQL local' for a local connection to a MS SQL Express 2008 R2 running instance (this was the version installed with Visual Studio 2010), accessed via OleDB.

This list of database providers is to be extended in the future. Any feedback is welcome!

Numbers are expressed in rows/second (or objects/second). This benchmark was compiled with Delphi 7, so newer compilers may give even better results, with in-lining and advanced optimizations.

Note that these tests are not about the relative speed of each database engine, but reflect the current status of the integration of several DB libraries within the mORMot database access.

Purpose here is not to say that one library or database is better or faster than another, but publish a snapshot of current mORMot persistence layer abilities.

In this timing, we do not benchmark only the "pure" SQL/DB layer access (SynDB units), but the whole Client-Server ORM of our framework: process below includes read and write RTTI access of a TSQLRecord, JSON marshaling, CRUD/REST routing, virtual cross-database layer, SQL on-the-fly translation. We just bypass the communication layer, since TSQLRestClient and TSQLRestServer are run in-process, in the same thread - as a TSQLRestServerDB instance. So you have here some raw performance testimony of our framework's ORM and RESTful core.

You can compile the "15 - External DB performance" supplied sample code, and run the very same benchmark on your own configuration.

Continue reading

2013-10-09

Good old object is not to be deprecated - it is the future

Yes, I know this article title is a huge moment of trolling for most Delphi developer.
But object could be legend... - wait for it - ... dary!

You perhaps already noticed by several blog posts here that I still like the good old (and deprecated) object type, in addition to the common heap-allocated class type.
Plain record with methods does not match the object-oriented approach of object, since it does not feature inheritance.

When you take a look at modern strongly-typed languages, targeting concurrent programming (you know, multi-thread/multi-core execution), you will see that the objects may be allocated in several ways, to facilitate execution flow.

The Rust language for instance is pretty interesting. It has optional task-local Garbage Collection and safe pointer types with region analysis.

To some extent, it is very similar to what object allows in the Delphi world, and why I'm still using/loving it!

Continue reading

2013-07-24

Tempering Garbage Collection

I'm currently fighting against out of memory errors on an heavy-loaded Java server.

If only it had been implemented in Delphi and mORMot!
But at this time, the mORMot was still in its burrow. :)
Copy-On-Write and a good heap manager can do wonders of stability.

Here are some thoughts about Garbage Collector, and how to temper their limitations.
They may apply to both the JVM and the .Net runtime, by the way.

Continue reading

2012-12-20

How to make it fast?

On our forum, a clever question was posted about publishing some enhanced RTL functions for newer versions of Delphi - as we did for Delphi 7 and 2007.

I was looking for a faster IntToStr implementation and discovered SynCommons.pas.
(....)
That's really too bad, SynCommons.pas really does contain some seriously fast stuff, people would greatly benefit from it if it was made general-purpose.

In fact, it would not be enough to change the RTL function implementations.
IMHO, to write something scalable, you need to get rid of such functions.

Continue reading

2012-10-06

Delphi XE3 is preparing (weak) reference counting for class instances

In Delphi, you have several ways of handling data life time, therefore several ways of handling memory:

  • For simple value objects (e.g.  byte integer double shortstring and fixed size arrays or record containing only such types), the value is copied in fixed-size buffers;
  • For more complex value objets (e.g. string and dynamic arrays or record containing such types), there is a reference counter handled by each instance, with copy-on-write feature and compiler-generated reference counting at code scope level (with hidden try..finally blocks);
  • For most class instances (e.g. deriving from TObject), you have to Create then Free each instance, and manage its life time by hand - with explicit try..finally blocks;
  • For class deriving from TInterfacedObject, you have a RefCount property, with _AddRef _Release methods (this is the reference-counted COM model), and you can use Delphi interface to work with such instances - see this blog article.
With Delphi XE3, we were told that some automatic memory handling at class level are about to be introduced at the compiler and RTL level.
Even if this feature is not finished, and disabled, there are a lot of changes in the Delphi XE3 Run Time Library which sounds like a preparation of such a new feature.

Continue reading

2012-06-18

Circular reference and zeroing weak pointers

The memory allocation model of the Delphi interface type uses some kind of Automatic Reference Counting (ARC). In order to avoid memory and resource leaks and potential random errors in the applications (aka the terrible EAccessViolation exception on customer side) when using interface, a SOA framework like mORMot has to offer so-called Weak pointers and Zeroing Weak pointers features.

Note that garbage collector based languages (like Java or C#) do not suffer from this problem, since the circular references are handled by their memory model: objects lifetime are maintained globally by the memory manager. Of course, it will increase memory use, slowdown the process due to additional actions during allocation and assignments (all objects and their references have to be maintained in internal lists), and may slow down the application when garbage collector enters in action. In order to avoid such issues when performance matters, experts tend to pre-allocate and re-use objects: this is one common limitation of this memory model, and why Delphi is still a good candidate (like unmanaged C or C++ - and also Objective C) when it deals with performance and stability.

Continue reading

2011-08-28

Multi-threading and Delphi

Writing working multi-threaded code is not easy - it's even hard, as as a Delphi expert just wrote in his blog.

In fact, the first step into multi-thread application development could be:

"protect your shared variables with locks (aka critical sections), because you are not sure that the data you read/write is the same for all threads".

The CPU per-core cache is just one of the possible issues, which will lead into reading wrong values. Another issue which may lead into race condition is two threads writing to a resource at the same time: it's impossible to know which value will be stored afterward.

Continue reading

2011-06-16

Which Delphi compiler produces faster code?

After a question on StackOverflow, I wanted to comment about the speed of generated code by diverse Delphi compiler versions.

Since performance matters when we write general purpose libraries like ours, we have some feedback to propose:

Continue reading

2011-05-20

How to write fast multi-thread Delphi applications

How to make your software run fast, especially in a multi-threaded architecture?

We tried to remove the Memory Manager scaling problems in our SynScaleMM. It worked as expected in a multi-threaded server environment. Scaling is much better than FastMM4, for some critical tests. But it's not ready for production yet...

To be honest, the Memory Manager is perhaps not the bigger bottleneck in Multi-Threaded applications.

Here are some (not dogmatic, just from experiment and knowledge of low-level Delphi RTL) advice if you want to write FAST multi-threaded application in Delphi.

Continue reading

2010-12-04

SynScaleMM - a multi-thread scaling Memory Manager

We just released a new unit to the source code repository.

It's a simple, small and compact MM, built on top of the main Memory Manager(FastMM4 is a good candidate, standard since Delphi 2007), architectured in order to scale on multi core CPU's (which is what FastMM4 is lacking).

Original code is ScaleMM - Fast scaling memory manager for Delphi by André Mussche.

Continue reading

When inlining works

It was told on this Blog that the Delphi memory manager (FastMM4 since Borland 2006 - but it was even worse with the previous "Borland's" MM), doesn't scale well on multi-code CPU. That is, if you have a multi-threaded application with a lot of memory handling (e.g. aString := aString+someString), the Delphi MM won't scale with multi cores. When I mean "don't scale", I mean that the optimistic though of "my CPU has 4 cores, therefore the same work run in 4 threads will be 4 times faster than with 1 thread" is false. It performs even worse with multiple threads than with 1 thread...

So we went into forking a nice project, named ScaleMM, and created our scalable optimized MM, named SynScaleMM. Our forked modifications were even included in the main ScaleMM branch.

During my profiling of our SynScaleMM, I discovered some very nice results with Delphi compiler inlining features.

Continue reading

2010-08-24

Synopse SQLite3 Framework 1.9.1

The Synopse SQLite3 Database Framework was just released under version 1.9.1:
- internal SQLite3 database engine is updated to version 3.7.2;
- new TSQLRecordFTS3 record, for using FTS3 virtual tables, i.e. implementing full-text search;
- new SQLite3UIEdit unit, to edit table content with a dialog created from RTTI;
- new dedicated BLOB methods and JSON array serialization;
- a lot of fixes and speed enhancements (including our HTTP/1.1 RESTful server now using Thread Pool).

The new 3.7.2 version of the SQLite3 engine, which is mandatory according to SQLite3's authors, is included.

Continue reading

2010-07-30

Compiler enhancement proposal: threadlocalvar

As I wrote in a previous post, Delphi string, dynamic array and memory manager don't like multi-core CPU.

My proposal is to add a threadlocalvar keyword, to be used instead of var in your code, to mark some variables to be used in only the current thread. Then the compiler and RTL won't have to use the LOCK instruction, and the application will be MUCH faster in multi-thread environment.

Continue reading

2010-07-15

Delphi doesn't like multi-core CPUs (or the contrary)

If you're like me, you are proud of the new CPU your computer runs on - in my case a i7-720Q with 8 embedded cores...

But Delphi is not very multi-thread or multi-core friendly... guess why....

Continue reading

page 2 of 2 -