You are not logged in.
We have just added a new "25 - JSON performance" sample for benchmarking of JSON process...
a new fight
featuring
mORMot vs SuperObject/dwsJSON/DBXJSON
On mORMot side, it covers TDocVariant, late binding, TSQLTable, ORM, record access, BSON...
We tried to face several scenarios:
* parse/access/write iteration over a small JSON document,
* read of deeply nested 680 KB JSON (here mORMot is slower than SO/dwsJSON),
* read of one 180 MB JSON file (with on-the-fly adaptation to fit a record layout),
* named access to all rows and columns of a 1 MB JSON table, extracted from a SQL request (with comparison with our ORM performance)
On average and in details, mORMot is the fastest in almost all scenarios (with an amazing performance for table/ORM processing), dwsJSON performs better than SuperObject, and DBXJSON is the slowest (by far, but XE6 version is faster than XE4).
See http://synopse.info/fossil/info/f23534b4a2
and blog article http://blog.synopse.info/post/json-benc … on-dbxjson
Stay tuned for the details!
Online
Congratulations for the great performance !
Offline
You can find the source code of the sample at http://synopse.info/fossil/finfo?name=S … tCases.pas
From my tests, for our code, Delphi 2007 gives the better performance, Delphi 7 is faster when using late binding of variants, and XE6 is a bit faster than XE4, once I've removed some "inline" methods which were badly compiled.
See http://synopse.info/fossil/info/ceacb5b371
Here are some values, compiled with XE6 on my Core i7 notebook.
You have the number of iterations per second, and the peak memory used during each process.
JSON benchmarking
-------------------
1. Small content
1.1. Synopse record:
- Read: 25,000 assertions passed 70.67ms 353,721/s
- Access: 50,000 assertions passed 493us 50,709,939/s
- Write: 25,000 assertions passed 49.25ms 507,562/s
Total failed: 0 / 100,000 - Synopse record PASSED 121.03ms
1.2. Synopse variant:
- Read: 25,000 assertions passed 120.29ms 207,827/s
- Access direct: 50,000 assertions passed 29.04ms 860,614/s
- Access late binding: 50,000 assertions passed 98.13ms 254,764/s
- Write: 25,000 assertions passed 57.84ms 432,204/s
Total failed: 0 / 150,000 - Synopse variant PASSED 306.04ms
1.3. Super object record:
- Read: 25,000 assertions passed 2.00s 12,470/s
- Access: 50,000 assertions passed 408us 61,274,509/s
- Write: 25,000 assertions passed 1.71s 14,539/s
Total failed: 0 / 100,000 - Super object record PASSED 3.72s
1.4. Super object properties:
- Read: 25,000 assertions passed 2.14s 11,631/s
- Access: 50,000 assertions passed 1.92s 12,971/s
- Write: 25,000 assertions passed 186.63ms 133,952/s
Total failed: 0 / 100,000 - Super object properties PASSED 4.26s
1.5. dws JSON:
- Read: 25,000 assertions passed 136.42ms 183,250/s
- Access: 50,000 assertions passed 37.07ms 674,236/s
- Write: 25,000 assertions passed 97.86ms 255,464/s
Total failed: 0 / 100,000 - dws JSON PASSED 273.66ms
1.6. DBXJSON:
- Read: 25,000 assertions passed 2.35s 10,622/s
- Access: 50,000 assertions passed 23.38ms 1,069,244/s
- Write: 25,000 assertions passed 309.64ms 80,737/s
Total failed: 0 / 100,000 - DBXJSON PASSED 2.68s
2. Big content
2.1. Depth content:
- Download files if necessary: no assertion 384us
- Synopse read variant: 1 assertion passed 87.99ms 284,100/s 337 KB
- Synopse read to BSON: 2 assertions passed 2.55ms 9,784,735/s 155 KB
- Super object read: 2 assertions passed 9.20ms 2,716,210/s 529 KB
- dws JSON read: 1 assertion passed 5.55ms 4,503,693/s 439 KB
- DBXJSON read: 1 assertion passed 92.20ms 271,126/s 679 KB
Total failed: 0 / 7 - Depth content PASSED 202.86ms
2.2. Table content:
- Download files if necessary: no assertion 356us 23,112,359/s
- Synopse parse: 1 assertion passed 2.69ms 3,052,690/s 1.2 MB
- Synopse ORM loop: 41,135 assertions passed 6.14ms 1,339,465/s 1.2 MB
- Synopse ORM list: 41,135 assertions passed 6.52ms 1,260,070/s 951 KB
- Synopse table direct: 41,135 assertions passed 20.40ms 403,126/s 1.2 MB
- Synopse table variant: 41,135 assertions passed 20.29ms 405,330/s 1.2 MB
- Synopse doc variant: 41,137 assertions passed 39.80ms 206,661/s 4.6 MB
- Synopse late binding: 41,137 assertions passed 34.45ms 238,768/s 4.6 MB
- Synopse to BSON: 2 assertions passed 8.92ms 922,206/s 1.1 MB
- Super object properties: 41,136 assertions passed 2.14s 3,840/s 6.3 MB
- Super object record: 41,136 assertions passed 148.57ms 55,373/s 6.3 MB
- dws JSON: 41,136 assertions passed 28.87ms 284,888/s 4.7 MB
- DBXJSON: 1 assertion passed 236.75ms 34,749/s 9.9 MB
Total failed: 0 / 370,226 - Table content PASSED 2.70s
2.3. Huge content:
- Download files if necessary: no assertion 428us
- Synopse read record: 4 assertions passed 1.52s 135,810/s 122.6 MB
- Synopse read variant: 2 assertions passed 2.45s 84,134/s 512.9 MB
- Synopse read to BSON: 3 assertions passed 2.01s 102,333/s 168.1 MB
- Super object read: 2 assertions passed 9.07s 22,769/s 1.1 GB
- dws JSON read: 2 assertions passed 3.26s 63,323/s 672.7 MB
- DBXJSON read: no assertion 703us 35,561,877/s
DBXJSON will raise EOutOfMemory for 185 MB JSON in Win32 -> skip
Total failed: 0 / 13 - Huge content PASSED 18.92s
Generated with: Delphi XE6 compiler
Time elapsed for all tests: 33.22s
Tests performed at 17/05/2014 08:47:02
Total assertions failed for all test suits: 0 / 1,020,246
! All tests passed successfully.
SuperObject has some issues for property names lookup...
I've added a new TTestTableContent.SuperObjectRecord method: accessing the values via a record (and RTTI) is much faster than using S[...] I[...] and such methods.
See http://synopse.info/fossil/info/2e384cc0a8
And when compiled for Win64, the sample program just explosed... SuperObject needs some tuning!
It is worth saying that dwsJSON performs very well, for its purpose.
See http://www.delphitools.info/2012/09/17/ … n-dwsjson/
Even on Win64 platform.
Great work, Eric!
DBXJSON is pretty slow, and is even givine an EOutOfMEmory error in Win32 for the huge content (more than 2GB is used!) - under Win64, it passes, with 3GB used for the 180 MB JSON file.
In the meanwhile, mORMot uses 150 MB of memory with records. smile
The mORMot code has some advantages, especially for ORM / table process.
Our record-based RTTI gives also impressive results, in both terms of speed and memory consumption.
And late-binding for properties access gives very readable code.
Which syntax do you prefer?
// Synopse direct record access
Check(gloss.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso[0]='GML');
// Synopse TDocVariant with properties
Check(DocVariantData(doc.GetValueByPath([
'glossary','GlossDiv','GlossList','GlossEntry','GlossDef','GlossSeeAlso'])).Value[0]='GML');
// Synopse TDocVariant with late binding
Check(doc.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso._(0)='GML');
// SuperObject properties
check(obj['glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso[0]'].AsString='GML');
// SuperObject direct record access
Check(gloss.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso[0]='GML');
// XSuperObject
check(obj['glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso[0]'].AsString='GML');
// dwsJSON
check(obj['glossary']['GlossDiv']['GlossList']['GlossEntry']['GlossDef']['GlossSeeAlso'][0].AsString='GML');
// DBXJSON
check(((((((obj.GetValue('glossary') as TJSONObject).
GetValue('GlossDiv') as TJSONObject).
GetValue('GlossList') as TJSONObject).
GetValue('GlossEntry') as TJSONObject).
GetValue('GlossDef') as TJSONObject).
GetValue('GlossSeeAlso') as TJSONArray).Get(0).Value='GML');
Any feedback is welcome!
Online
Hardware: Macbook Pro (i7-2.8GHz) with Windows 8.1 in VMWare VM
32Bit DEBUG
JSON benchmarking
-------------------
1. Small content
1.1. Synopse record:
- Read: 50,000 assertions passed 172.87ms 289,231/s
- Access: 100,000 assertions passed 914us 54,704,595/s
- Write: 50,000 assertions passed 113.53ms 440,381/s
Total failed: 0 / 200,000 - Synopse record PASSED 288.73ms
1.2. Synopse variant:
- Read: 50,000 assertions passed 260.27ms 192,101/s
- Access direct: 100,000 assertions passed 52.18ms 958,184/s
- Access late binding: 100,000 assertions passed 163.41ms 305,971/s
- Write: 50,000 assertions passed 172.68ms 289,541/s
Total failed: 0 / 300,000 - Synopse variant PASSED 651.15ms
1.3. X super object record:
- Read: 50,000 assertions passed 20.66s 2,419/s
- Access: 100,000 assertions passed 911us 54,884,742/s
- Write: 50,000 assertions passed 4.03s 12,400/s
Total failed: 0 / 200,000 - X super object record PASSED 24.69s
1.4. X super object properties:
- Read: 50,000 assertions passed 16.30s 3,067/s
- Access: 100,000 assertions passed 585.54ms 85,390/s
- Write: 50,000 assertions passed 782.88ms 63,866/s
Total failed: 0 / 200,000 - X super object properties PASSED 17.67s
1.5. dws JSON:
- Read: 50,000 assertions passed 308.65ms 161,993/s
- Access: 100,000 assertions passed 77.20ms 647,626/s
- Write: 50,000 assertions passed 312.43ms 160,031/s
Total failed: 0 / 200,000 - dws JSON PASSED 700.71ms
1.6. DBXJSON:
- Read: 50,000 assertions passed 3.79s 13,161/s
- Access: 100,000 assertions passed 41.85ms 1,194,486/s
- Write: 50,000 assertions passed 566.02ms 88,335/s
Total failed: 0 / 200,000 - DBXJSON PASSED 4.40s
2. Big content
2.1. Depth content:
- Download files if necessary: no assertion 781us
- Synopse read variant: 1 assertion passed 265.45ms 188,357/s 337 KB
- Synopse read to BSON: 2 assertions passed 3.17ms 15,762,925/s 175 KB
- dws JSON read: 1 assertion passed 8.29ms 6,030,635/s 307 KB
- DBXJSON read: 1 assertion passed 87.47ms 571,598/s 679 KB
Total failed: 0 / 5 - Depth content PASSED 370.94ms
2.2. Table content:
- Download files if necessary: no assertion 753us 10,926,958/s
- Synopse parse: 1 assertion passed 4.68ms 1,756,779/s 1.2 MB
- Synopse ORM loop: 41,135 assertions passed 7.77ms 1,058,135/s 1.2 MB
- Synopse ORM list: 41,135 assertions passed 8.63ms 953,191/s 952 KB
- Synopse table direct: 41,135 assertions passed 31.49ms 261,182/s 1.1 MB
- Synopse table variant: 41,135 assertions passed 29.99ms 274,324/s 1.1 MB
- Synopse doc variant: 41,137 assertions passed 49.79ms 165,210/s 4.6 MB
- Synopse late binding: 41,137 assertions passed 38.64ms 212,864/s 4.6 MB
- Synopse to BSON: 2 assertions passed 10.39ms 791,819/s 1.1 MB
- dws JSON: 41,136 assertions passed 33.89ms 242,720/s 4.7 MB
- DBXJSON: 41,136 assertions passed 215.80ms 38,123/s 9.9 MB
Total failed: 0 / 329,089 - Table content PASSED 446.50ms
2.3. Huge content:
- Download files if necessary: no assertion 733us
- Synopse read record: 4 assertions passed 2.45s 84,247/s 122.6 MB
- Synopse read variant: 2 assertions passed 3.37s 61,151/s 512.9 MB
- Synopse read to BSON: 3 assertions passed 2.12s 97,275/s 168.1 MB
- dws JSON read: 2 assertions passed 3.50s 59,005/s 672.7 MB
- DBXJSON read: no assertion 615us 81,300,813/s
DBXJSON will raise EOutOfMemory for 185 MB JSON in Win32 -> skip
Total failed: 0 / 11 - Huge content PASSED 11.81s
Generated with: Delphi XE6 compiler
Time elapsed for all tests: 61.06s
Tests performed at 18.05.2014 12:32:17
Total assertions failed for all test suits: 0 / 1,629,105
! All tests passed successfully.
32Bit Release
JSON benchmarking
-------------------
1. Small content
1.1. Synopse record:
- Read: 50,000 assertions passed 126.96ms 393,800/s
- Access: 100,000 assertions passed 988us 50,607,287/s
- Write: 50,000 assertions passed 74.86ms 667,886/s
Total failed: 0 / 200,000 - Synopse record PASSED 204.75ms
1.2. Synopse variant:
- Read: 50,000 assertions passed 201.74ms 247,841/s
- Access direct: 100,000 assertions passed 50.88ms 982,685/s
- Access late binding: 100,000 assertions passed 159.65ms 313,173/s
- Write: 50,000 assertions passed 103.98ms 480,824/s
Total failed: 0 / 300,000 - Synopse variant PASSED 518.63ms
1.3. X super object record:
- Read: 50,000 assertions passed 20.40s 2,450/s
- Access: 100,000 assertions passed 984us 50,813,008/s
- Write: 50,000 assertions passed 3.88s 12,883/s
Total failed: 0 / 200,000 - X super object record PASSED 24.29s
1.4. X super object properties:
- Read: 50,000 assertions passed 16.07s 3,111/s
- Access: 100,000 assertions passed 530.41ms 94,265/s
- Write: 50,000 assertions passed 716.42ms 69,790/s
Total failed: 0 / 200,000 - X super object properties PASSED 17.32s
1.5. dws JSON:
- Read: 50,000 assertions passed 224.79ms 222,428/s
- Access: 100,000 assertions passed 64.19ms 778,864/s
- Write: 50,000 assertions passed 159.79ms 312,893/s
Total failed: 0 / 200,000 - dws JSON PASSED 451.24ms
1.6. DBXJSON:
- Read: 50,000 assertions passed 4.09s 12,218/s
- Access: 100,000 assertions passed 42.63ms 1,172,855/s
- Write: 50,000 assertions passed 531.19ms 94,126/s
Total failed: 0 / 200,000 - DBXJSON PASSED 4.66s
2. Big content
2.1. Depth content:
- Download files if necessary: no assertion 758us
- Synopse read variant: 1 assertion passed 69.91ms 715,133/s 337 KB
- Synopse read to BSON: 2 assertions passed 2.60ms 19,208,605/s 175 KB
- dws JSON read: 1 assertion passed 5.79ms 8,634,087/s 307 KB
- DBXJSON read: 1 assertion passed 83.36ms 599,764/s 679 KB
Total failed: 0 / 5 - Depth content PASSED 166.82ms
2.2. Table content:
- Download files if necessary: no assertion 758us 10,854,881/s
- Synopse parse: 1 assertion passed 3.43ms 2,394,353/s 1.2 MB
- Synopse ORM loop: 41,135 assertions passed 7.10ms 1,157,428/s 1.2 MB
- Synopse ORM list: 41,135 assertions passed 5.43ms 1,513,428/s 952 KB
- Synopse table direct: 41,135 assertions passed 22.68ms 362,694/s 1.1 MB
- Synopse table variant: 41,135 assertions passed 26.37ms 311,900/s 1.1 MB
- Synopse doc variant: 41,137 assertions passed 40.31ms 204,062/s 4.6 MB
- Synopse late binding: 41,137 assertions passed 32.77ms 251,006/s 4.6 MB
- Synopse to BSON: 2 assertions passed 8.97ms 916,249/s 1.1 MB
- dws JSON: 41,136 assertions passed 30.23ms 272,146/s 4.7 MB
- DBXJSON: 41,136 assertions passed 234.10ms 35,143/s 9.9 MB
Total failed: 0 / 329,089 - Table content PASSED 426.91ms
2.3. Huge content:
- Download files if necessary: no assertion 666us
- Synopse read record: 4 assertions passed 1.23s 167,382/s 122.6 MB
- Synopse read variant: 2 assertions passed 2.16s 95,524/s 512.9 MB
- Synopse read to BSON: 3 assertions passed 1.66s 124,376/s 168.1 MB
- dws JSON read: 2 assertions passed 3.42s 60,266/s 672.7 MB
- DBXJSON read: no assertion 335us 149,253,731/s
DBXJSON will raise EOutOfMemory for 185 MB JSON in Win32 -> skip
Total failed: 0 / 11 - Huge content PASSED 8.86s
Generated with: Delphi XE6 compiler
Time elapsed for all tests: 56.91s
Tests performed at 18.05.2014 12:36:06
Total assertions failed for all test suits: 0 / 1,629,105
! All tests passed successfully.
64Bit Release
JSON benchmarking
-------------------
1. Small content
1.1. Synopse record:
- Read: 50,000 assertions passed 168.00ms 297,619/s
- Access: 100,000 assertions passed 1.85ms 26,910,656/s
- Write: 50,000 assertions passed 84.16ms 594,049/s
Total failed: 0 / 200,000 - Synopse record PASSED 255.94ms
1.2. Synopse variant:
- Read: 50,000 assertions passed 244.35ms 204,620/s
- Access direct: 100,000 assertions passed 48.51ms 1,030,651/s
- Access late binding: 100,000 assertions passed 153.71ms 325,287/s
- Write: 50,000 assertions passed 111.38ms 448,909/s
Total failed: 0 / 300,000 - Synopse variant PASSED 560.17ms
1.3. dws JSON:
- Read: 50,000 assertions passed 260.82ms 191,698/s
- Access: 100,000 assertions passed 69.11ms 723,411/s
- Write: 50,000 assertions passed 161.97ms 308,699/s
Total failed: 0 / 200,000 - dws JSON PASSED 493.75ms
1.4. DBXJSON:
- Read: 50,000 assertions passed 2.89s 17,266/s
- Access: 100,000 assertions passed 45.87ms 1,089,870/s
- Write: 50,000 assertions passed 493.61ms 101,294/s
Total failed: 0 / 200,000 - DBXJSON PASSED 3.43s
2. Big content
2.1. Depth content:
- Download files if necessary: no assertion 596us
- Synopse read variant: 1 assertion passed 145.50ms 343,642/s 458 KB
- Synopse read to BSON: 2 assertions passed 2.76ms 18,115,942/s 155 KB
- dws JSON read: 1 assertion passed 5.61ms 8,912,655/s 414 KB
- DBXJSON read: 1 assertion passed 53.63ms 932,157/s 877 KB
Total failed: 0 / 5 - Depth content PASSED 213.25ms
2.2. Table content:
- Download files if necessary: no assertion 590us 13,945,762/s
- Synopse parse: 1 assertion passed 2.95ms 2,784,094/s 1.4 MB
- Synopse ORM loop: 41,135 assertions passed 5.99ms 1,372,310/s 1.3 MB
- Synopse ORM list: 41,135 assertions passed 7.79ms 1,054,878/s 1.3 MB
- Synopse table direct: 41,135 assertions passed 16.75ms 491,046/s 1.3 MB
- Synopse table variant: 41,135 assertions passed 20.81ms 395,319/s 1.3 MB
- Synopse doc variant: 41,137 assertions passed 40.20ms 204,651/s 7.0 MB
- Synopse late binding: 41,137 assertions passed 32.70ms 251,544/s 7.0 MB
- Synopse to BSON: 2 assertions passed 11.24ms 731,548/s 1.2 MB
- dws JSON: 41,136 assertions passed 34.23ms 240,295/s 6.7 MB
- DBXJSON: 41,136 assertions passed 195.13ms 42,161/s 16.6 MB
Total failed: 0 / 329,089 - Table content PASSED 382.61ms
2.3. Huge content:
- Download files if necessary: no assertion 185us
- Synopse read record: 4 assertions passed 2.07s 99,706/s 148.7 MB
- Synopse read variant: 2 assertions passed 3.52s 58,559/s 766.1 MB
- Synopse read to BSON: 3 assertions passed 1.97s 104,480/s 170.0 MB
- dws JSON read: 2 assertions passed 7.64s 27,015/s 1.0 GB
- DBXJSON read: 2 assertions passed 35.37s 5,839/s 3.0 GB
Total failed: 0 / 13 - Huge content PASSED 51.07s
Generated with: Delphi XE6 64 bit compiler
Time elapsed for all tests: 56.42s
Tests performed at 18.05.2014 12:39:35
Total assertions failed for all test suits: 0 / 1,229,107
! All tests passed successfully.
Rad Studio 12.1 Santorini
Offline
Also to mention the new SynCrossPlatformJSON .pas unit, which is another reader/writer of JSON content into JSON objects or arrays.
It is meant to be cross-platform, so it does not use SynCommons.pas or the other units of mORMot.
But all needed features are there: fast JSON parsing and writing, document or array storage, variant access to values, late-binding access
See http://synopse.info/forum/viewtopic.php … 674#p10674 for some numbers.
For a ORM table result content, it is 10 times faster than DBXJSON, and 100 times faster than SuperObject, when all rows and all fields are accessed.
Online
Very good work. I put it in one of my Programs instead of JSON unit. And works fine.
ATM i have a Problem with the German Umlaute: öäüßÖÄÜ
I store them in a TDocVariant on the Server. Retrieve it with TSQLRecord. But after Loading the TDocVariant Field into TJSONVariantData with Init.
The ä has changed to : ä
It seems the ä is converted to UTF8 Representation of ä but after loading the UTF8 representation ist converted to Single Unicode Chars.
Can you give me a clue how to deal best with this ?
Should i Convert the "umlaute" to something else like ä# or do you have something in your lib ?
Rad Studio 12.1 Santorini
Offline
You're right I fixed it using SynCommons.Utf8ToString.
Rad Studio 12.1 Santorini
Offline
I guess you are mixing rawutf8 and string types.
The Syncrossplatform unit uses strings, not rawutf8.
Could you help to comment, if it does not use RawUTF8, how can it handle UTF8 when the Kylix/FPC compiler is used ?
Offline
SynCrossPlatformJSON .pas uses the plain "string" type of the compiler.
It will let the encoding be outside of its own scope.
So under Kylix, under a UTF-8 system, it will be string=RawUTF8.
Under FPC, if you supply an UTF-8 string to the unit, it will return UTF-8 content.
Under Unicode Delphi, you need to convert the UTF-8 content to/from string=UnicodeString.
Online
Thank you for your helpful comment !
PS: Just for reference purpose, OXml (www.kluug.net/oxml.php) claims to be compatible with D/FPC on Windows/Linux/Mac. Probably contains useful ideas. :-P
Offline
I've fixed and compiled SynCrossPlatform.pas with FPC/Lazarus, and also created some samples targeting desktop or mobile FireMonkey (not tested on all platforms).
See http://synopse.info/fossil/info/53c61c86b6
I'm using FPC 2.7.1 with latest CodeTyphon distro, but with it UTF-8 seems broken.
See the comments in the code.
Is there any option to deactivate AnsiString code pages and force string = UTF8String, as we expect?
Any feedback is welcome!
Online
Thank you for your efforts ! Sorry for trouble !
I do not know why "// assume string is UTF-8 encoded (as with Lazarus/LCL) // note that when working with variants, FPC 2.7.1 sometimes clear the code page".
Could you present the problem in "Lazarus forum" http://forum.lazarus.freepascal.org/index.php ? :-P
-------------
from this FPC webpage, it is claimed "There are significant improvements to development branches of FPC 2.7.1 with regard to Strings. See RawByteString and UTF8String."
http://wiki.freepascal.org/LCL_Unicode_Support
from this FPC webpage, UTF8String is Not implemented. It is currently just an alias for ansistring.
http://wiki.freepascal.org/FPC_Unicode_ … UTF8String
from this 2007 FPC maillist and two related webpages, it seems that Unicode as stored in 16-bit Unicode format is supported by FPC.
http://free-pascal-general.1045716.n5.n … 14536.html
http://lptk.sourceforge.net/
http://pasgf.sourceforge.net/
Last edited by ComingNine (2014-05-28 12:32:25)
Offline
Could you help to provide a test case that fails for sure for FPC ? It may be easier to diagonise ... :-D
Offline