TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Fastcat – A Faster `cat` Implementation Using Splice

96 pointsby jontroalmost 7 years ago

9 comments

cojoalmost 7 years ago
&gt; &quot;Nice, but why on earth would I want that?&quot; I have no idea.<p>I know this is referring mostly to the `cat` portion and not the `splice` portion of the article, but I&#x27;ll throw in a quick shoutout to `splice` for giving me one of the single biggest build performance wins in my time at Zynga (and possibly across most teams at the company at the time).<p>We had a ruby script which ran the majority of the build, and as the game grew we found that by far the slowest part was a loop which MD5 hashed each individual asset and used that as its filename on our CDN for per-asset-versioning.<p>At its worst it was taking nearly an hour and a half; the code was basically as inefficient as you could make it - multiple shell calls for each file rather than any sort of inlining of the hashing process.<p>I wrote a basic C program using splice and an MD5 library which took the whole process to under 10s. A bit overkill, perhaps, but the naive speedup I tried first still took over 1-2 minutes, and I figured 99.99% was worth the extra few hours to put it together knowing how many builds we ran each day.<p>Definitely gave me a healthy appreciation for the cost of transferring to user space that has stuck with me.
accrualalmost 7 years ago
&gt; In this case, if you notice that cat is the bottleneck try fcat (but first try to avoid cat altogether).<p>&quot;Useless Use of Cat Award&quot; [0] is the canonical text for avoiding unnecessary use of cat, for those who haven&#x27;t come across it yet.<p>[0] <a href="http:&#x2F;&#x2F;porkmail.org&#x2F;era&#x2F;unix&#x2F;award.html" rel="nofollow">http:&#x2F;&#x2F;porkmail.org&#x2F;era&#x2F;unix&#x2F;award.html</a> (2000)
评论 #17664795 未加载
评论 #17660869 未加载
pantalaimonalmost 7 years ago
I re-implemented it in C and for some reason O_APPEND is set on stdout by default.<p>But aside from that it works just as the Rust version.<p><pre><code> #define _GNU_SOURCE #include &lt;fcntl.h&gt; #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;string.h&gt; #include &lt;unistd.h&gt; #define BUF_SIZE 16384 static void unset_flag(int fd, int flag) { int flags = fcntl(fd, F_GETFL, 0); flags &amp;= ~flags; fcntl(fd, F_SETFL, flags); } int main(int argc, char** argv) { int pipefd[2]; pipe(pipefd); unset_flag(STDOUT_FILENO, O_APPEND); for (int i = 1; i &lt; argc; ++i) { int fd = strcmp(argv[i], &quot;-&quot;) ? open(argv[i], O_RDONLY) : STDIN_FILENO; if (fd &lt; 0) { fprintf(stderr, &quot;%s: No such file or directory\n&quot;, argv[i]); exit(1); } while (splice(fd, NULL, pipefd[1], NULL, BUF_SIZE, 0)) splice(pipefd[0], NULL, STDOUT_FILENO, NULL, BUF_SIZE, 0); close(fd); } return 0; } </code></pre> WTFPL if anyone cares.
评论 #17668029 未加载
the8472almost 7 years ago
Newer kernels also have the copy_file_range syscall (with compatibility shim in glibc) which is supposed to use the most efficient copying approach available between any two file descriptors. So it&#x27;s more general than splice or sendfile.
modellsalmost 7 years ago
There is a ruby gem for Linux called io_splice that does zero-copy IO. Hasn’t been updated in a while but it doesn’t have any dependencies other than modern Linux and doesn’t mean it won’t work. “Old” code that works still works, novelty, job-securitization and API churn be damned when it doesn’t add value.<p><a href="https:&#x2F;&#x2F;rubygems.org&#x2F;gems&#x2F;io_splice&#x2F;versions&#x2F;4.4.0" rel="nofollow">https:&#x2F;&#x2F;rubygems.org&#x2F;gems&#x2F;io_splice&#x2F;versions&#x2F;4.4.0</a><p><a href="http:&#x2F;&#x2F;www.bigfastblog.com&#x2F;zero-copy-transfer-data-faster-in-ruby" rel="nofollow">http:&#x2F;&#x2F;www.bigfastblog.com&#x2F;zero-copy-transfer-data-faster-in...</a><p>EDIT: source to current stable coreutils’ cat <a href="http:&#x2F;&#x2F;git.savannah.gnu.org&#x2F;gitweb&#x2F;?p=coreutils.git;a=blob_plain;f=src&#x2F;cat.c;hb=e5dae2c6b0bcd0e4ac6e5b212688d223e2e62f79" rel="nofollow">http:&#x2F;&#x2F;git.savannah.gnu.org&#x2F;gitweb&#x2F;?p=coreutils.git;a=blob_p...</a>
Rapzidalmost 7 years ago
The most interesting thing about all this to me, other than the existence of splice(I really should finish The Linux Programming Interface), is that you need a pipe and two splice operations to get the data between other file types.. There must be some dirty implementation detail forcing this right? Right?!
评论 #17666575 未加载
omn1almost 7 years ago
&gt;Windows doesn&#x27;t provide zero-copy file-to-file transfer (only file-to-socket transfer using the TransmitFile API).<p>Anybody knows if the Windows TransmitFile API can also be used to make file-to-file copies?
评论 #17664210 未加载
评论 #17664333 未加载
type0almost 7 years ago
Great educational post, but really someone needs to make a long awaited version called long cat!
mcguirealmost 7 years ago
Tl;dr: splice() as a Linux-only, zero-userspace-copy, file-descriptor to file-descriptor copy that has to use pipes for one FD.<p>Interesting, but less than earthshaking.