threads / discuss / 1813

Avoid wasting memory in git-rev-list

Subject: Avoid wasting memory in git-rev-list

## tl;dr

4 messages between Sep 15, 2005 and Sep 15, 2005.

replies: 3people: 3as markdown or json

Linus Torvalds· Sep 15, 2005, 21:43 UTC · lore
As pointed out on the list, git-rev-list can use a lot of memory.

One low-hanging fruit is to free the commit buffer for commits that we parse. By default, parse_commit() will save away the buffer, since a lot of cases do want it, and re-reading it continually would be unnecessary. However, in many cases the buffer isn't actually necessary and saving it just wastes memory.

We could just free the buffer ourselves, but especially in git-rev-list, we actually end up using the helper functions that automatically add parent commits to the commit lists, so we don't actually control the commit parsing directly.

Instead, just make this behaviour of "parse_commit()" a global flag. Maybe this is a bit tasteless, but it's very simple, and it makes a noticable difference in memory usage.

Before the change:
	[torvalds@g5 linux]$ /usr/bin/time git-rev-list v2.6.12..HEAD > /dev/null
	0.26user 0.02system 0:00.28elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k
	0inputs+0outputs (0major+3714minor)pagefaults 0swaps
after the change:
	[torvalds@g5 linux]$ /usr/bin/time git-rev-list v2.6.12..HEAD > /dev/null
	0.26user 0.00system 0:00.27elapsed 100%CPU (0avgtext+0avgdata 0maxresident)k
	0inputs+0outputs (0major+2433minor)pagefaults 0swaps

note how the minor faults have decreased from 3714 pages to 2433 pages. That's all due to the fewer anonymous pages allocated to hold the comment buffers and their metadata.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---
Hey, I'm not proud. If somebody wants to do a prettier patch, go wild.
This still doesn't attack the _big_ memory use by
	"git-rev-list --objects"
where we just parse more stuff than we need to, but it's a first step.
diff --git a/commit.c b/commit.c
--- a/commit.c
+++ b/commit.c
@@ -3,6 +3,8 @@
 #include "commit.h"
 #include "cache.h"
 
+int save_commit_buffer = 1;
+
 struct sort_node
 {
 	/*
@@ -264,7 +266,7 @@ int parse_commit(struct commit *item)
 			     sha1_to_hex(item->object.sha1));
 	}
 	ret = parse_commit_buffer(item, buffer, size);
-	if (!ret) {
+	if (save_commit_buffer && !ret) {
 		item->buffer = buffer;
 		return 0;
 	}
diff --git a/commit.h b/commit.h
--- a/commit.h
+++ b/commit.h
@@ -17,6 +17,7 @@ struct commit {
 	char *buffer;
 };
 
+extern int save_commit_buffer;
 extern const char *commit_type;
 
 struct commit *lookup_commit(const unsigned char *sha1);
diff --git a/rev-list.c b/rev-list.c
--- a/rev-list.c
+++ b/rev-list.c
@@ -582,6 +582,8 @@ int main(int argc, char **argv)
 		handle_one_commit(commit, &list);
 	}
 
+	save_commit_buffer = verbose_header;
+
 	if (!merge_order) {		
 		sort_by_date(&list);
 	        if (limited)
Junio C Hamano· Sep 15, 2005, 22:02 UTC · re: Linus Torvalds · lore

Re: Avoid wasting memory in git-rev-list

So using this I could also avoid wasting memory by the "are we already walking the commit reachable from our existing refs" check by doing something like this?

------------ git diff

diff --git a/fetch.c b/fetch.c
--- a/fetch.c
+++ b/fetch.c
@@ -207,6 +207,7 @@ int pull(char *target)
 	unsigned char sha1[20];
 	int fd = -1;
 
+	save_commit_buffer = 0;
 	if (write_ref && current_ref) {
 		fd = lock_ref_sha1(write_ref, current_ref);
 		if (fd < 0)
Linus Torvalds· Sep 15, 2005, 22:07 UTC · re: Junio C Hamano · lore

Re: Avoid wasting memory in git-rev-list

On Thu, 15 Sep 2005, Junio C Hamano wrote:
>
> So using this I could also avoid wasting memory by the "are we
> already walking the commit reachable from our existing refs"
> check by doing something like this?
Yes. It's still ugly, but it's _simple_.
		Linus
Johannes Schindelin· Sep 15, 2005, 22:38 UTC · re: Junio C Hamano · lore

Re: Avoid wasting memory in git-rev-list

Hi Linus, hi Junio,
On Thu, 15 Sep 2005, Junio C Hamano wrote:
Show 17 quoted lines
> So using this I could also avoid wasting memory by the "are we
> already walking the commit reachable from our existing refs"
> check by doing something like this?
> 
> ------------
> git diff
> diff --git a/fetch.c b/fetch.c
> --- a/fetch.c
> +++ b/fetch.c
> @@ -207,6 +207,7 @@ int pull(char *target)
>  	unsigned char sha1[20];
>  	int fd = -1;
>  
> +	save_commit_buffer = 0;
>  	if (write_ref && current_ref) {
>  		fd = lock_ref_sha1(write_ref, current_ref);
>  		if (fd < 0)

Together with both of Linus' patches, this works wonders! It uses _lots_ less of memory. Actually, the performance impact on my tiny server was negligible.

Ciao, Dscho

← back to recent threads