threads / patch / 35851

patchblame.c: prepare_lines should not call xrealloc for every line

Subject: [PATCH] blame.c: prepare_lines should not call xrealloc for every line

## tl;dr

2 messages between Feb 12, 2014 and Feb 12, 2014. Diffs are folded; open one to read it.

replies: 1people: 2as markdown or json

David Kastrup· Feb 12, 2014, 14:27 UTC · lore

Making a single preparation run for counting the lines will avoid memory fragmentation. Also, fix the allocated memory size which was wrong when sizeof(int *) != sizeof(int), and would have been too small for sizeof(int *) < sizeof(int), admittedly unlikely.

Signed-off-by: David Kastrup <dak@gnu.org>
---

Since there was no feedback after the last defense/explanation of the coding choices, the code rewritten by this patch was much more awful, and the kind of style requests (fixed already in the last iteration) are not actually heeded by the core developers themselves, I have no idea whether this patch will be dropped just like the last one.

As opposed to the last try, this incorporates a suggestion from Jeff to change sizeof(type) to sizeof(expression) which is not helping much since the types of lineno and sb->lineno still need to be changed in sync.

It also fiddles cosmetically with the code layout of the loops.
builtin/blame.c | 46 +++++++++++++++++++++++++++++++---------------
 1 file changed, 31 insertions(+), 15 deletions(-)
Show changes to builtin/blame.c +31 −15
diff --git a/builtin/blame.c b/builtin/blame.c
index e44a6bb..1aefedf 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -1772,25 +1772,41 @@ static int prepare_lines(struct scoreboard *sb)
 {
 	const char *buf = sb->final_buf;
 	unsigned long len = sb->final_buf_size;
-	int num = 0, incomplete = 0, bol = 1;
+	const char *end = buf + len;
+	const char *p;
+	int *lineno;
+	int num = 0, incomplete = 0;
 
-	if (len && buf[len-1] != '\n')
-		incomplete++; /* incomplete line at the end */
-	while (len--) {
-		if (bol) {
-			sb->lineno = xrealloc(sb->lineno,
-					      sizeof(int *) * (num + 1));
-			sb->lineno[num] = buf - sb->final_buf;
-			bol = 0;
-		}
-		if (*buf++ == '\n') {
+	for (p = buf;;) {
+		p = memchr(p, '\n', end - p);
+		if (p) {
+			p++;
 			num++;
-			bol = 1;
+			continue;
 		}
+		break;
 	}
-	sb->lineno = xrealloc(sb->lineno,
-			      sizeof(int *) * (num + incomplete + 1));
-	sb->lineno[num + incomplete] = buf - sb->final_buf;
+
+	if (len && end[-1] != '\n')
+		incomplete++; /* incomplete line at the end */
+
+	sb->lineno = xmalloc(sizeof(*sb->lineno) * (num + incomplete + 1));
+	lineno = sb->lineno;
+
+	*lineno++ = 0;
+	for (p = buf;;) {
+		p = memchr(p, '\n', end - p);
+		if (p) {
+			p++;
+			*lineno++ = p - buf;
+			continue;
+		}
+		break;
+	}
+
+	if (incomplete)
+		*lineno++ = len;
+
 	sb->num_lines = num + incomplete;
 	return sb->num_lines;
 }
-- 
1.8.3.2
Junio C Hamano· Feb 12, 2014, 19:36 UTC · re: David Kastrup · lore

Re: [PATCH] blame.c: prepare_lines should not call xrealloc for every line

David Kastrup <dak@gnu.org> writes:
Show 7 quoted lines
> Making a single preparation run for counting the lines will avoid memory
> fragmentation.  Also, fix the allocated memory size which was wrong
> when sizeof(int *) != sizeof(int), and would have been too small
> for sizeof(int *) < sizeof(int), admittedly unlikely.
>
> Signed-off-by: David Kastrup <dak@gnu.org>
> ---

I think I took sizeof(int*)->sizeof(int) patch to the 'next' branch already, which might have to conflict with this clean-up, but it should be trivial to resolve.

Thanks for resending. I was busy elsewhere (i.e. "no feedback" does not mean "silent rejection" nor "silent agreement" at least from me), and such a resend does help prevent patches fall thru cracks.

Show 46 quoted lines
> diff --git a/builtin/blame.c b/builtin/blame.c
> index e44a6bb..1aefedf 100644
> --- a/builtin/blame.c
> +++ b/builtin/blame.c
> @@ -1772,25 +1772,41 @@ static int prepare_lines(struct scoreboard *sb)
>  {
>  	const char *buf = sb->final_buf;
>  	unsigned long len = sb->final_buf_size;
> +	const char *end = buf + len;
> +	const char *p;
> +	int *lineno;
> +	int num = 0, incomplete = 0;
>  
> +	for (p = buf;;) {
> +		p = memchr(p, '\n', end - p);
> +		if (p) {
> +			p++;
>  			num++;
> +			continue;
>  		}
> +		break;
>  	}
> +
> +	if (len && end[-1] != '\n')
> +		incomplete++; /* incomplete line at the end */
> +
> +	sb->lineno = xmalloc(sizeof(*sb->lineno) * (num + incomplete + 1));
> +	lineno = sb->lineno;
> +
> +	*lineno++ = 0;
> +	for (p = buf;;) {
> +		p = memchr(p, '\n', end - p);
> +		if (p) {
> +			p++;
> +			*lineno++ = p - buf;
> +			continue;
> +		}
> +		break;
> +	}
> +
> +	if (incomplete)
> +		*lineno++ = len;
> +
>  	sb->num_lines = num + incomplete;
>  	return sb->num_lines;
>  }

← back to recent threads