git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH] Teach "git add" and friends to be paranoid

From
Nicolas Pitre <nico@fluxnic.net>
Date
Feb 22, 2010, 18:01 UTC
Message-ID
<alpine.LFD.2.00.1002221238110.1946@xanadu.home>
In-Reply-To
<20100222173122.GG11733@gibbs.hungrycats.org>
On Mon, 22 Feb 2010, Zygo Blaxell wrote:
Show 19 quoted lines
> On Mon, Feb 22, 2010 at 10:40:59AM -0500, Nicolas Pitre wrote:
> > On Sun, 21 Feb 2010, Junio C Hamano wrote:
> > > Dmitry Potapov <dpotapov@gmail.com> writes:
> > > > But overall the outcome is clear -- read() is always a winner.
> > > 
> > > "... a winner, below 128kB; above that the difference is within noise and
> > > measurement error"?
> > 
> > read() is not always a winner.  A read() call will always have the data 
> > duplicated in memory.  Especially with large files, it is more efficient 
> > on the system as a whole to mmap() a 50 MB file rather than allocating 
> > an extra 50 MB of anonymous memory that cannot be paged out (except to 
> > the swap file which would be yet another data duplication).  With mmap() 
> > when there is memory pressure the read-only mapped memory is simply 
> > dropped with no extra IO.
> 
> That holds if you're comparing read() and mmap() of the entire file as a
> single chunk, instead of in fixed-size chunks at the sweet spot between
> syscall overhead and CPU cache size.

Obviously. But we currently don't have the infrastructure to do chunked read of the input data. I think we should do that eventually, by applying the pack windowing code to input files as well. That would make memory usage constant even for huge files, but this is much more complicated to support especially for data fed through stdin.

Show 8 quoted lines
> If you're read()ing a chunk at a time into a fixed size buffer, and
> doing sha1 and deflate in chunks, the data should be copied once into CPU
> cache, processed with both algorithms, and replaced with new data from
> the next chunk.  The data will be copied from the page cache instead
> of directly mapped, which is a small overhead, but setting up the page
> map in mmap() also a small overhead, so you have to use benchmarks to
> know which of the overheads is smaller.  It might be that there's no
> one answer that applies to all CPU configurations.

Normally mmap() has more overhead than read(). However mmap() provides much nicer properties than read() by simplifying the code a lot, and by letting the OS manage memory pressure much more gracefully.

Show 6 quoted lines
> If you're doing mmap() and sha1 and deflate of a 50MB file in two
> separate passes that are the same size as the file, you load 50MB of
> data into CPU cache at least twice, you get two sets of associated
> things like TLB misses, and if the file is very large, you page it from
> disk twice.  So it might make sense to process in chunks regardless
> of read() vs mmap() fetching the data.

We do have to make two separate passes anyway. The first pass is to hash the data only, and if that hash already exists in the object store then we call it done and skip over the deflate process which is still the dominant cost. And that happens quite often.

However, with a really large file, then it becomes advantageous to simply do the hash and deflate in parallel one chunk at a time, and simply discard the newly created objects if it happens to already exists. That's the whole idea behind the newly introduced core.bigFileThreshold config variable (but the code to honor it in sha1_file.c doesn't exist yet).

> If you're malloc()ing 50MB, you're wasting memory and CPU bandwidth
> making up pages full of zeros before you've even processed the first byte.
> I don't see how that could ever be faster for large file cases.

It can't. This is why read() is not much better than mmap() in those cases.

Nicolas
Previous: Zygo BlaxellNext: Junio C Hamano
Message 77 of 84 in “Re: Bug#569505: git-core: 'git add' corrupts repository if the working directory is modified as it runs”
  1. Jonathan NiederFeb 12, 2010
  2. Zygo BlaxellFeb 12, 2010
  3. Jonathan NiederFeb 13, 2010
  4. Ilari LiusvaaraFeb 13, 2010
  5. Thomas RastFeb 13, 2010
  6. Ilari LiusvaaraFeb 13, 2010
  7. Dmitry PotapovFeb 13, 2010
  8. Zygo BlaxellFeb 13, 2010
  9. don't use mmap() to hash filesDmitry Potapov, Feb 14, 2010
  10. Junio C HamanoFeb 14, 2010
  11. Dmitry PotapovFeb 14, 2010
  12. Junio C HamanoFeb 14, 2010
  13. Thomas RastFeb 14, 2010
  14. Junio C HamanoFeb 14, 2010
  15. Johannes SchindelinFeb 14, 2010
  16. Junio C HamanoFeb 14, 2010
  17. Dmitry PotapovFeb 14, 2010
  18. Jakub NarebskiFeb 14, 2010
  19. Paolo BonziniFeb 14, 2010
  20. Johannes SchindelinFeb 14, 2010
  21. Dmitry PotapovFeb 14, 2010
  22. Johannes SchindelinFeb 14, 2010
  23. Johannes SchindelinFeb 14, 2010
  24. Dmitry PotapovFeb 14, 2010
  25. Zygo BlaxellFeb 14, 2010
  26. Nicolas PitreFeb 15, 2010
  27. Dmitry PotapovFeb 15, 2010
  28. Paolo BonziniFeb 15, 2010
  29. Dmitry PotapovFeb 15, 2010
  30. Dmitry PotapovFeb 14, 2010
  31. Avery PennarunFeb 14, 2010
  32. Nicolas PitreFeb 15, 2010
  33. Avery PennarunFeb 15, 2010
  34. Nicolas PitreFeb 15, 2010
  35. Avery PennarunFeb 15, 2010
  36. Nicolas PitreFeb 15, 2010
  37. don't use mmap() to hash filesDmitry Potapov, Feb 14, 2010
  38. Teach "git add" and friends to be paranoidJunio C Hamano, Feb 18, 2010
  39. Junio C HamanoFeb 18, 2010
  40. Zygo BlaxellFeb 18, 2010
  41. Junio C HamanoFeb 19, 2010
  42. Jeff KingFeb 18, 2010
  43. Nicolas PitreFeb 18, 2010
  44. Junio C HamanoFeb 18, 2010
  45. Wincent ColaiutaFeb 18, 2010
  46. Zygo BlaxellFeb 18, 2010
  47. Jonathan NiederFeb 18, 2010
  48. Junio C HamanoFeb 18, 2010
  49. Paolo BonziniFeb 22, 2010
  50. Dmitry PotapovFeb 22, 2010
  51. Thomas RastFeb 18, 2010
  52. Junio C HamanoFeb 18, 2010
  53. Nicolas PitreFeb 18, 2010
  54. 16 gig, 350,000 file repositoryBill Lear, Feb 18, 2010
  55. Nicolas PitreFeb 18, 2010
  56. Erik Faye-LundFeb 19, 2010
  57. Bill LearFeb 22, 2010
  58. Nicolas PitreFeb 22, 2010
  59. Peter HarrisFeb 18, 2010
  60. Junio C HamanoFeb 18, 2010
  61. Nicolas PitreFeb 18, 2010
  62. Jonathan NiederFeb 19, 2010
  63. Zygo BlaxellFeb 19, 2010
  64. Junio C HamanoFeb 19, 2010
  65. Zygo BlaxellFeb 19, 2010
  66. Dmitry PotapovFeb 19, 2010
  67. Junio C HamanoFeb 19, 2010
  68. Junio C HamanoFeb 20, 2010
  69. Dmitry PotapovFeb 21, 2010
  70. Junio C HamanoFeb 21, 2010
  71. Dmitry PotapovFeb 22, 2010
  72. Junio C HamanoFeb 22, 2010
  73. Dmitry PotapovFeb 22, 2010
  74. Nicolas PitreFeb 22, 2010
  75. Dmitry PotapovFeb 22, 2010
  76. Zygo BlaxellFeb 22, 2010
  77. Nicolas PitreFeb 22, 2010
  78. Junio C HamanoFeb 22, 2010
  79. Nicolas PitreFeb 22, 2010
  80. Dmitry PotapovFeb 22, 2010
  81. Nicolas PitreFeb 22, 2010
  82. mmap with MAP_PRIVATE is useless (was Re: Bug#569505: git-core: 'git add' corrupts repository if the working directory is modified as it runs)Paolo Bonzini, Feb 14, 2010
  83. Junio C HamanoFeb 14, 2010
  84. Paolo BonziniFeb 14, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.