I need to join 2 big files. The task is similar to what the join utility is doing. While playing around with my algorithm, which is very similar to this problem: I've realized that coreutil's join is way faster ( but not doing exactly what I need). However after checking this perl code for join implemented in perl which seem to be quite similar to the C code of the coreutil's join I see that the difference is the same, perl code is too slow.
Some tests:
time join -j 2 file1.txt file2.txt| mbuffer > result.c
in @ 20.0 MiB/s, out @ 20.0 MiB/s, 86.0 MiB total, buffer 0% full
summary: 95.6 MiByte in 5.9sec - average of 16.2 MiB/s
join -j 2 file1.txt file2.txt 4.99s user 0.09s system 99% cpu 5.091 total
time perl ./join -j 1 file1.txt file2.txt| mbuffer > result.perl
in @ 4092 kiB/s, out @ 4092 kiB/s, 94.0 MiB total, buffer 0% full
summary: 95.6 MiByte in 44.5sec - average of 2202 kiB/s
perl ./join -j 1 file1.txt file2.txt 44.15s user 0.08s system 99% cpu 44.226 total
Any hint on how to improve the performance? I suspect it might be related to the buffering.
According to nytrpof the bottleneck is get_a_line() sub
# spent 59.4s (57.3+2.12) within main::get_a_line which was called 25884852 times, avg 2µs/call:
# 15574181 times (34.4s+1.27s) by main::RUNTIME at line 69, avg 2µs/call
# 10309895 times (22.9s+857ms) by main::RUNTIME at line 75, avg 2µs/call
# 478 times (868µs+42µs) by main::RUNTIME at line 85, avg 2µs/call
# 296 times (533µs+30µs) by main::RUNTIME at line 80, avg 2µs/call
# once (12µs+26µs) by main::RUNTIME at line 59
# once (4µs+7µs) by main::RUNTIME at line 60
sub get_a_line {
121 25884852 2.60s my ($aref, $fh) = @_;
122 25884852 29.1s 25884852 2.12s my $not_eof = defined(my $line = <$fh>);
# spent 2.12s making 25884852 calls to main::CORE:readline, avg 82ns/call
123 25884852 5.50s if ($not_eof) {
124 25884851 1.92s chomp $line;
125 25884851 12.5s push (@$aref,
126 defined $delimiter ?
127 [split $delimiter, $line, -1] : [split ' ', $line, -1]);
128 }
129 1 300ns else { push @$aref, undef }
130 25884852 27.4s return $not_eof;
131 }