Skip to content

Commit 6c83298

Browse files
authored
Merge pull request #39 from synopse/main
abouchez/mormot: noticeable performance boost
2 parents 1402f2b + d82e345 commit 6c83298

File tree

1 file changed

+43
-38
lines changed

1 file changed

+43
-38
lines changed

entries/abouchez/src/brcmormot.lpr

Lines changed: 43 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -34,27 +34,32 @@
3434
Min, Max: SmallInt; // 16-bit (-32767..+32768) temperatures * 10
3535
end;
3636
PBrcStation = ^TBrcStation;
37-
TBrcStations = array of TBrcStation;
37+
TBrcStationDynArray = array of TBrcStation;
38+
39+
TBrcStations = array[word] of TBrcStation;
40+
PBrcStations = ^TBrcStations;
3841

3942
TBrcList = record
4043
public
41-
Station: TBrcStations;
4244
Count: integer;
4345
{$ifdef CUSTOMHASH}
46+
Station: PBrcStations; // perfectly aligned to 64 bytes from StationMem[]
4447
StationHash: array of word; // store 0 if void, or Station[] index + 1
48+
StationMem: TBrcStationDynArray;
4549
function Search(name: pointer; namelen: PtrInt): PBrcStation;
4650
{$else}
51+
Station: TBrcStationDynArray;
4752
Stations: TDynArrayHashed;
4853
function Search(name: PByteArray): PBrcStation;
4954
{$endif CUSTOMHASH}
50-
procedure Init(max: integer);
55+
procedure Init(max: integer; align: boolean);
5156
end;
5257

5358
TBrcMain = class
5459
protected
5560
fSafe: TLightLock;
5661
fEvent: TSynEvent;
57-
fRunning: integer;
62+
fRunning, fMax: integer;
5863
fCurrentChunk: PByteArray;
5964
fCurrentRemain: PtrUInt;
6065
fList: TBrcList;
@@ -90,10 +95,14 @@ TBrcThread = class(TThread)
9095
const
9196
HASHSIZE = 1 shl 18; // slightly oversized to avoid most collisions
9297

93-
procedure TBrcList.Init(max: integer);
98+
procedure TBrcList.Init(max: integer; align: boolean);
9499
begin
95100
assert(max <= high(StationHash[0]));
96-
SetLength(Station, max);
101+
SetLength(StationMem, max); // RTL won't align by 64 bytes
102+
Station := pointer(StationMem);
103+
if align then
104+
while PtrUInt(Station) and 63 <> 0 do // manual alignment
105+
inc(PByte(Station));
97106
SetLength(StationHash, HASHSIZE);
98107
end;
99108

@@ -206,10 +215,11 @@ function StationComp(const A, B): integer;
206215
result := MemCmp(@sa.NameLen, @sb.NameLen, sa.NameLen + 1);
207216
end;
208217

209-
procedure TBrcList.Init(max: integer);
218+
procedure TBrcList.Init(max: integer; align: boolean);
210219
begin
220+
// align is just ignored, because TDynArray requires natural alignment
211221
Stations.Init(
212-
TypeInfo(TBrcStations), Station, @StationHash, @StationComp, nil, @Count);
222+
TypeInfo(TBrcStationDynArray), Station, @StationHash, @StationComp, nil, @Count);
213223
Stations.Capacity := max;
214224
end;
215225

@@ -220,7 +230,7 @@ function TBrcList.Search(name: PByteArray): PBrcStation;
220230
begin
221231
assert(name^[0] < SizeOf(TBrcStation.NameText));
222232
i := Stations.FindHashedForAdding(name^, added);
223-
result := @Station[i]; // in two steps (Station[] may be reallocated if added)
233+
result := @Station[i]; // in two steps (Station[] may be reallocated)
224234
if not added then
225235
exit;
226236
MoveFast(name^, result^.NameLen, name^[0] + 1);
@@ -237,7 +247,7 @@ constructor TBrcThread.Create(owner: TBrcMain);
237247
begin
238248
fOwner := owner;
239249
FreeOnTerminate := true;
240-
fList.Init(length(fOwner.fList.Station));
250+
fList.Init(fOwner.fMax, {align=}true);
241251
InterlockedIncrement(fOwner.fRunning);
242252
inherited Create({suspended=}false);
243253
end;
@@ -328,7 +338,8 @@ constructor TBrcMain.Create(const fn: TFileName; threads, max: integer;
328338
fEvent := TSynEvent.Create;
329339
if not fMem.Map(fn) then
330340
raise ESynException.CreateUtf8('Impossible to find %', [fn]);
331-
fList.Init(max);
341+
fMax := max;
342+
fList.Init(fMax, {align=}false); // not aligned for TDynArray.Sort to work
332343
fCurrentChunk := pointer(fMem.Buffer);
333344
fCurrentRemain := fMem.Size;
334345
core := 0;
@@ -391,30 +402,23 @@ procedure TBrcMain.Aggregate(const another: TBrcList);
391402
n: integer;
392403
begin
393404
fSafe.Lock; // several TBrcThread may finish at the same time
394-
{$ifdef CUSTOMHASH}
395-
if fList.Count = 0 then
396-
fList := another // we can reuse the existing hash table
397-
else
398-
{$endif CUSTOMHASH}
399-
begin
400-
n := another.Count;
401-
s := pointer(another.Station);
402-
repeat
403-
{$ifdef CUSTOMHASH}
404-
d := fList.Search(@s^.NameText, s^.NameLen);
405-
{$else}
406-
d := fList.Search(@s^.NameLen);
407-
{$endif CUSTOMHASH}
408-
inc(d^.Count, s^.Count);
409-
inc(d^.Sum, s^.Sum);
410-
if s^.Max > d^.Max then
411-
d^.Max := s^.Max;
412-
if s^.Min < d^.Min then
413-
d^.Min := s^.Min;
414-
inc(s);
415-
dec(n);
416-
until n = 0;
417-
end;
405+
n := another.Count;
406+
s := pointer(another.Station);
407+
repeat
408+
{$ifdef CUSTOMHASH}
409+
d := fList.Search(@s^.NameText, s^.NameLen);
410+
{$else}
411+
d := fList.Search(@s^.NameLen);
412+
{$endif CUSTOMHASH}
413+
inc(d^.Count, s^.Count);
414+
inc(d^.Sum, s^.Sum);
415+
if s^.Max > d^.Max then
416+
d^.Max := s^.Max;
417+
if s^.Min < d^.Min then
418+
d^.Min := s^.Min;
419+
inc(s);
420+
dec(n);
421+
until n = 0;
418422
fSafe.UnLock;
419423
if InterlockedDecrement(fRunning) = 0 then
420424
fEvent.SetEvent; // all threads finished: release main console thread
@@ -482,8 +486,8 @@ function TBrcMain.SortedText: RawUtf8;
482486
tmp: TTextWriterStackBuffer;
483487
begin
484488
{$ifdef CUSTOMHASH}
485-
DynArrayFakeLength(pointer(fList.Station), fList.Count);
486-
DynArray(TypeInfo(TBrcStations), fList.Station).Sort(ByStationName);
489+
DynArrayFakeLength(fList.Station, fList.Count);
490+
DynArray(TypeInfo(TBrcStationDynArray), fList.Station).Sort(ByStationName);
487491
{$else}
488492
fList.Stations.Sort(ByStationName);
489493
{$endif CUSTOMHASH}
@@ -530,7 +534,8 @@ function TBrcMain.SortedText: RawUtf8;
530534
assert(SizeOf(TBrcStation) = 64); // 64 bytes = CPU L1 cache line size
531535
// read command line parameters
532536
Executable.Command.ExeDescription := 'The mORMot One Billion Row Challenge';
533-
fn := Executable.Command.ArgString(0, 'the data source #filename');
537+
if Executable.Command.Arg(0, 'the data source #filename') then
538+
Utf8ToFileName(Executable.Command.Args[0], fn);
534539
verbose := Executable.Command.Option(
535540
['v', 'verbose'], 'generate verbose output with timing');
536541
affinity := Executable.Command.Option(

0 commit comments

Comments
 (0)