Ну, во первых, не 2, а 3 раза:
Код: Выделить всё
Concat w/default manager (15000000): 1.21 s (80.51 ns/sym)
Concat w/fast manager (15000000): 0.37 s (24.60 ns/sym)
SmartConcat w/default manager (15000000): 0.07 s (4.40 ns/sym)
Во вторых, на практике, я таки буду использовать динамические массивы из упакованных записей по 64 байта (структура чанков мира).
Если тест слегка модифицировать, то оказывается, что на блоках 64 байта быстрофейковый ММ в 80 раз быстрее стокового и всего лишь вдвое медленнее умной реаллокации.
А размеры мне заранее известны редко будут.
Код: Выделить всё
program testrealloc;
{$mode objfpc} {$h+} {$typedaddress on} {$coperators on}
uses
Windows;
var aaa: AnsiString;
function QPC: double;
var
counter, frequency: TLargeInteger;
begin
QueryPerformanceFrequency((@frequency)^);
QueryPerformanceCounter((@counter)^);
result := counter / frequency;
end;
procedure TestConcat(var s: ansistring; iterations: integer);
var
it: integer;
begin
for it := 1 to iterations do
s += aaa;
end;
procedure TestSmartConcat(var s: ansistring; iterations: integer);
var
pos: SizeInt;
begin
pos := length(s) + 1;
SetLength(s, length(s) + length(aaa) * iterations);
while pos + length(aaa) - 1 <= length(s) do
begin
MOVE(aaa[1], s[pos], sizeof(aaa[1]) * length(aaa));
pos += length(aaa);
end;
end;
const
blcksize = 15000000;
HugeBlock = 2 * blcksize * sizeof(char);
var
OldMgr, NewMgr: TMemoryManager;
function FastGetMem(size: SizeUint): pointer;
begin
Assert(size <= HugeBlock);
result := OldMgr.GetMem(HugeBlock);
end;
function FastReallocMem(var p: pointer; size: SizeUint): pointer;
begin
Assert(size <= HugeBlock);
Assert(Assigned(p) and (size > 0));
result := p;
end;
var
s: string = '';
timeC, timeCMM, timeSC: double;
i, j, k: integer;
Iterations: integer;
begin
for i:= 0 to 8 do begin
j:= 1 shl i;
writeln(j, ' bytes:');
aaa:= '';
for k:= 1 to j do aaa+= 'a';
Iterations:= blcksize div length(aaa);
timeC := QPC;
TestConcat(s, Iterations);
timeC := QPC - timeC;
writeln('Concat w/default manager (', length(s), '): ', timeC:0:2, ' s (', timeC/iterations*1e9:0:2, ' ns/sym)');
s := '';
GetMemoryManager((@OldMgr)^);
NewMgr := OldMgr;
NewMgr.GetMem := @FastGetMem;
NewMgr.ReallocMem := @FastReallocMem;
SetMemoryManager(NewMgr);
timeCMM := QPC;
TestConcat(s, Iterations);
timeCMM := QPC - timeCMM;
writeln('Concat w/fast manager (', length(s), '): ', timeCMM:0:2, ' s (', timeCMM/iterations*1e9:0:2, ' ns/sym)');
writeln('Ratio: ', timeC / timeCMM:0:2);
s := '';
SetMemoryManager(OldMgr);
timeSC := QPC;
TestSmartConcat(s, Iterations);
timeSC := QPC - timeSC;
writeln('SmartConcat w/default manager (', length(s), '): ', timeSC:0:2, ' s (', timeSC/iterations*1e9:0:2, ' ns/sym)');
writeln('Ratio: ',timeCMM / timeSC:0:2);
s := '';
writeln;
end;
readln;
end.
(нижнее Ratio это fast MM / smart concat)
Код: Выделить всё
1 bytes:
Concat w/default manager (15000000): 1.12 s (74.85 ns/sym)
Concat w/fast manager (15000000): 0.40 s (26.35 ns/sym)
Ratio: 2.84
SmartConcat w/default manager (15000000): 0.11 s (7.66 ns/sym)
Ratio: 3.44
2 bytes:
Concat w/default manager (15000000): 0.98 s (131.07 ns/sym)
Concat w/fast manager (15000000): 0.20 s (26.73 ns/sym)
Ratio: 4.90
SmartConcat w/default manager (15000000): 0.06 s (8.43 ns/sym)
Ratio: 3.17
4 bytes:
Concat w/default manager (15000000): 0.90 s (239.76 ns/sym)
Concat w/fast manager (15000000): 0.12 s (31.06 ns/sym)
Ratio: 7.72
SmartConcat w/default manager (15000000): 0.04 s (10.54 ns/sym)
Ratio: 2.95
8 bytes:
Concat w/default manager (15000000): 0.86 s (459.32 ns/sym)
Concat w/fast manager (15000000): 0.05 s (28.12 ns/sym)
Ratio: 16.33
SmartConcat w/default manager (15000000): 0.02 s (9.45 ns/sym)
Ratio: 2.98
16 bytes:
Concat w/default manager (15000000): 0.84 s (894.72 ns/sym)
Concat w/fast manager (15000000): 0.03 s (31.40 ns/sym)
Ratio: 28.50
SmartConcat w/default manager (15000000): 0.01 s (12.71 ns/sym)
Ratio: 2.47
32 bytes:
Concat w/default manager (15000000): 0.84 s (1795.98 ns/sym)
Concat w/fast manager (15000000): 0.02 s (36.75 ns/sym)
Ratio: 48.87
SmartConcat w/default manager (15000000): 0.01 s (17.75 ns/sym)
Ratio: 2.07
64 bytes:
Concat w/default manager (15000000): 0.83 s (3553.46 ns/sym)
Concat w/fast manager (15000000): 0.01 s (43.75 ns/sym)
Ratio: 81.22
SmartConcat w/default manager (15000000): 0.01 s (28.49 ns/sym)
Ratio: 1.54
128 bytes:
Concat w/default manager (14999936): 0.83 s (7062.42 ns/sym)
Concat w/fast manager (14999936): 0.01 s (67.95 ns/sym)
Ratio: 103.93
SmartConcat w/default manager (14999936): 0.01 s (51.94 ns/sym)
Ratio: 1.31
256 bytes:
Concat w/default manager (14999808): 0.82 s (14055.24 ns/sym)
Concat w/fast manager (14999808): 0.01 s (111.87 ns/sym)
Ratio: 125.64
SmartConcat w/default manager (14999808): 0.01 s (105.47 ns/sym)
Ratio: 1.06
Кстати, в комплекте с фпц идёт pagemem.pp, выделяющая по страницам работающая по сходным принципам.
Добавлено спустя 1 час 45 минут 31 секунду:З.Ы. Увеличиваем размер с 15 до 100 мегабайт:
Код: Выделить всё
1 bytes:
Concat w/default manager (100000000): 37.92 s (379.22 ns/sym)
Concat w/fast manager (100000000): 2.61 s (26.13 ns/sym)
Ratio: 14.51
SmartConcat w/default manager (100000000): 0.76 s (7.56 ns/sym)
Ratio: 3.45
2 bytes:
Concat w/default manager (100000000): 35.84 s (716.82 ns/sym)
Concat w/fast manager (100000000): 1.33 s (26.55 ns/sym)
Ratio: 27.00
SmartConcat w/default manager (100000000): 0.42 s (8.43 ns/sym)
Ratio: 3.15
4 bytes:
Concat w/default manager (100000000): 35.63 s (1425.38 ns/sym)
Concat w/fast manager (100000000): 0.74 s (29.52 ns/sym)
Ratio: 48.29
SmartConcat w/default manager (100000000): 0.26 s (10.55 ns/sym)
Ratio: 2.80
8 bytes:
Concat w/default manager (100000000): 35.68 s (2854.53 ns/sym)
Concat w/fast manager (100000000): 0.35 s (27.66 ns/sym)
Ratio: 103.21
SmartConcat w/default manager (100000000): 0.12 s (9.28 ns/sym)
Ratio: 2.98
16 bytes:
Concat w/default manager (100000000): 35.90 s (5743.79 ns/sym)
Concat w/fast manager (100000000): 0.20 s (31.55 ns/sym)
Ratio: 182.07
SmartConcat w/default manager (100000000): 0.08 s (12.13 ns/sym)
Ratio: 2.60
32 bytes:
Concat w/default manager (100000000): 36.02 s (11524.86 ns/sym)
Concat w/fast manager (100000000): 0.11 s (35.61 ns/sym)
Ratio: 323.64
SmartConcat w/default manager (100000000): 0.05 s (16.87 ns/sym)
Ratio: 2.11
64 bytes:
Concat w/default manager (100000000): 36.03 s (23058.25 ns/sym)
Concat w/fast manager (100000000): 0.07 s (42.33 ns/sym)
Ratio: 544.71
SmartConcat w/default manager (100000000): 0.04 s (27.29 ns/sym)
Ratio: 1.55
128 bytes:
Concat w/default manager (100000000): 36.20 s (46335.83 ns/sym)
Concat w/fast manager (100000000): 0.05 s (59.49 ns/sym)
Ratio: 778.90
SmartConcat w/default manager (100000000): 0.04 s (51.64 ns/sym)
Ratio: 1.15
256 bytes:
Concat w/default manager (100000000): 35.99 s (92136.14 ns/sym)
Concat w/fast manager (100000000): 0.04 s (110.75 ns/sym)
Ratio: 831.96
SmartConcat w/default manager (100000000): 0.04 s (101.05 ns/sym)
Ratio: 1.10
Добавлено спустя 2 часа 22 минуты 29 секунд:Тест на гигабайт гонится. Ножка полки с ноутбуком (растёт вниз от полки с цветами и принтером) уже горячая, на всю свою четырёхсантиметровую толщину. Потму что выхлоп аккурат на неё попадает.
Код: Выделить всё
1 bytes:
Concat w/default manager (1000000000): 3999.36 s (3999.36 ns/sym)
Concat w/fast manager (1000000000): 26.81 s (26.81 ns/sym)
Ratio: 149.16
SmartConcat w/default manager (1000000000): 7.69 s (7.69 ns/sym)
Ratio: 3.49
2 bytes:
Concat w/default manager (1000000000): 3855.59 s (7711.18 ns/sym)
Concat w/fast manager (1000000000): 13.93 s (27.85 ns/sym)
Ratio: 276.87
SmartConcat w/default manager (1000000000): 4.34 s (8.68 ns/sym)
Ratio: 3.21
4 bytes:
- иии здравствуй, гомерическая прогрессия. Уже имеем час с хвостиком против 14 секунд.
Добавлено спустя 1 час 7 минут 46 секунд:Код: Выделить всё
Concat w/default manager (1000000000): 4319.92 s (17279.70 ns/sym)
Concat w/fast manager (1000000000): 7.45 s (29.81 ns/sym)
Ratio: 579.57
SmartConcat w/default manager (1000000000): 2.51 s (10.06 ns/sym)
Ratio: 2.96
8 bytes:
Добавлено спустя 7 часов 54 минуты 26 секунд:Код: Выделить всё
Concat w/default manager (1000000000): 3731.54 s (29852.35 ns/sym)
Concat w/fast manager (1000000000): 3.40 s (27.19 ns/sym)
Ratio: 1097.91
SmartConcat w/default manager (1000000000): 1.17 s (9.37 ns/sym)
Ratio: 2.90
16 bytes:
Concat w/default manager (1000000000): 3680.53 s (58888.54 ns/sym)
Concat w/fast manager (1000000000): 1.93 s (30.92 ns/sym)
Ratio: 1904.44
SmartConcat w/default manager (1000000000): 0.74 s (11.85 ns/sym)
Ratio: 2.61
32 bytes:
Concat w/default manager (1000000000): 3692.76 s (118168.29 ns/sym)
Concat w/fast manager (1000000000): 1.11 s (35.61 ns/sym)
Ratio: 3318.32
SmartConcat w/default manager (1000000000): 0.53 s (17.04 ns/sym)
Ratio: 2.09
64 bytes:
Concat w/default manager (1000000000): 3717.94 s (237948.02 ns/sym)
Concat w/fast manager (1000000000): 0.68 s (43.45 ns/sym)
Ratio: 5476.52
SmartConcat w/default manager (1000000000): 0.42 s (26.97 ns/sym)
Ratio: 1.61
128 bytes:
Concat w/default manager (1000000000): 3710.61 s (474957.93 ns/sym)
Concat w/fast manager (1000000000): 0.48 s (60.91 ns/sym)
Ratio: 7797.62
SmartConcat w/default manager (1000000000): 0.40 s (51.32 ns/sym)
Ratio: 1.19
256 bytes:
Concat w/default manager (1000000000): 3754.27 s (961093.90 ns/sym)
Concat w/fast manager (1000000000): 0.44 s (112.52 ns/sym)
Ratio: 8541.82
SmartConcat w/default manager (1000000000): 0.40 s (101.52 ns/sym)
Ratio: 1.11
Добавлено спустя 9 часов 18 минут 9 секунд:Самое важное: я смогу обходу дерева объектов (и исохранению, которое тоже осуществляется обходом) добавить маску по ThreadID'ам, с пренебрежимо малым пенальти на производительность, и тем самым сделать чеперси многопоточной. Например, задействовать *все* ядра 8-ядерника для просчёта лагокомпенсации в мультиплеере. Или задействовать *все* ядра для ИИ в сингл-плеере.
Хмм... Есля я буду результаты решений ИИ пропускать через те же ворота, что и действия игроков мышью, и упаковывать их достаточно компактно, я смогу и в мультиплеере задействовать полный ИИ, только у сервера лишния ядра будут думать за неписей, а на клиентах неписи будут болванчиками, управляемыми командами с сервера, а лишние ядра заняты ускоренной промоткой параллельных ветвей реальности.
Причём, команды ИИ должны быть не непрерывным потоком "шевелил мышью влево, жал вперёд" как у игроков. От этого сеть треснет. Нет, они должны быть более абстрактными типа "пойти к навигационной точке Ы и там осмотреться" или "жрать повер-апы" или "обитеться на игрока Н". Т.е. в пределах одного решения в две-четыре секунды. А все рефлексы, что в районе 10 тиков в секунду - таки локальные. Но тупыыыые.