-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy paththreads.pp
More file actions
90 lines (75 loc) · 2.96 KB
/
Copy paththreads.pp
File metadata and controls
90 lines (75 loc) · 2.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
program threads;
{ zuse_threads splits compression across worker threads. Each chunk becomes its
own DEFLATE block on its own core, and the blocks are written back in order,
so the result is an ordinary gzip stream that any decoder reads.
Build with optimizations, or the numbers are about a third lower:
fpc -O2 -Fu../src threads.pp }
{$mode unleashed}
uses sysutils, zflate;
var
src: string;
spos: integer;
acc: string;
function reader(buf: pointer; maxlen: dword): dword;
begin
var left := length(src) - spos;
if left > maxlen then left := maxlen;
if left > 0 then Move(src[1+spos], buf^, left);
spos := spos + left;
result := left;
end;
function writer(data: pointer; datasize: dword): boolean;
begin
var old := length(acc);
setlength(acc, old + datasize);
if datasize > 0 then Move(data^, acc[old+1], datasize);
result := true;
end;
// Deterministic text-like payload. It must not repeat itself: the codec cuts
// the input into 1 MB blocks and compresses each on its own, so a payload built
// by copying one megabyte over and over would hand every block identical data
// and the levels would all land on the same ratio.
function maketext(size: integer): string;
const
WORDS: array[12] of string = ('deflate', 'stream', 'compress', 'the quick brown fox', 'zflate',
'lorem ipsum dolor sit amet', 'consectetur', 'adipiscing elit', 'huffman', 'window', 'match', 'literal');
begin
RandSeed := 3;
setlength(result, size);
var p := 1;
while p <= size do begin
var w := WORDS[Random(12)] + ' ';
if Random(8) = 0 then w := w + IntToStr(Random(100_000)) + ' ';
if Random(20) = 0 then w := w + sLineBreak;
var n := length(w);
if p + n - 1 > size then n := size - p + 1;
Move(w[1], result[p], n);
inc(p, n);
end;
end;
begin
writeln('building test data...');
src := maketext(96*1024*1024);
writeln('input: ', length(src) div (1024*1024), ' MB, cores available: ', GetCPUCount);
writeln;
writeln('threads time speed output roundtrip');
var basetime: double := 0;
for var nt in [1, 2, 4, 8] do begin
zuse_threads := nt; // 0 or 1 = sequential, N = N workers
spos := 0; acc := '';
var t := GetTickCount64;
var code := gzencode_stream(@reader, @writer, length(src), ZFLATE_BEST);
var secs := (GetTickCount64 - t) / 1000;
if code <> ZFLATE_OK then begin writeln('failed: ', zflate_error_str(code)); halt(1); end;
if nt = 1 then basetime := secs;
// the parallel output is a plain gzip stream: the ordinary decoder reads it
var ok := gzdecode(acc) = src;
writeln(format('%4d %7.2fs %6.1f MB/s %5.1f MB %s %.2fx', [nt, secs,
length(src) / (1024*1024) / secs, length(acc) / (1024*1024),
BoolToStr(ok, 'identical', 'MISMATCH!'), basetime / secs]));
end;
zuse_threads := 1;
writeln;
writeln('decompression is always single-threaded: a generic DEFLATE stream');
writeln('carries no block index, so it cannot be split up front.');
end.