git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 3/3] diff --stat: sometimes use non-linear scaling.
@ 2006-09-27  2:40 Junio C Hamano
  2006-09-27  3:11 ` David Rientjes
                   ` (3 more replies)
  0 siblings, 4 replies; 19+ messages in thread
From: Junio C Hamano @ 2006-09-27  2:40 UTC (permalink / raw)
  To: git; +Cc: Jan Engelhardt, Linus Torvalds, Adrian Bunk

When some files have big changes and others are touched only
slightly, diffstat graph did not show differences among smaller
changes that well.  This changes the graph scaling to non-linear
algorithm in such a case.

Without this, "git show --stat fd88d9c" gives:

 .gitignore                       |    1
 Documentation/git-tar-tree.txt   |    3 +
 Documentation/git-upload-tar.txt |   39 -----------
 Documentation/git.txt            |    4 -
 Makefile                         |    1
 builtin-tar-tree.c               |  130 +++++++++++++++-----------------------
 builtin-upload-tar.c             |   74 ----------------------
 git.c                            |    1
 8 files changed, 53 insertions(+), 200 deletions(-)

while with this, it shows:

 .gitignore                       |    1
 Documentation/git-tar-tree.txt   |    3 +++++++++
 Documentation/git-upload-tar.txt |   39 -----------------------------
 Documentation/git.txt            |    4 -----------
 Makefile                         |    1
 builtin-tar-tree.c               |  130 +++++++++++++++-----------------------
 builtin-upload-tar.c             |   74 ----------------------------------
 git.c                            |    1
 8 files changed, 53 insertions(+), 200 deletions(-)

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 * Jan Engelhardt wondered about doing non-linear scaling on the
   kernel list and this is an experimental patch to do so.  I do
   not seriously consider this for inclusion but it is more of a
   "see if people like it" patch.

 Makefile |    2 +-
 diff.c   |   29 +++++++++++++++++++++++++++--
 2 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index 28091d6..0fc59c4 100644
--- a/Makefile
+++ b/Makefile
@@ -304,7 +304,7 @@ BUILTIN_OBJS = \
 	builtin-write-tree.o
 
 GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
-LIBS = $(GITLIBS) -lz
+LIBS = $(GITLIBS) -lz -lm
 
 #
 # Platform specific tweaks
diff --git a/diff.c b/diff.c
index 13aac2d..163ef48 100644
--- a/diff.c
+++ b/diff.c
@@ -4,6 +4,7 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <signal.h>
+#include <math.h>
 #include "cache.h"
 #include "quote.h"
 #include "diff.h"
@@ -555,6 +556,16 @@ static int scale_linear(int it, int widt
 	return (it * width * 2 + max_change) / (max_change * 2);
 }
 
+static int scale_non_linear(int it, int width, int max_change)
+{
+	/*
+	 * round(width * log(it)/log(max_change))
+	 */
+	if (!it || !max_change)
+		return 0;
+	return (int)(0.5 + width * log(it) / log(max_change));
+}
+
 static void show_name(const char *prefix, const char *name, int len,
 		      const char *reset, const char *set)
 {
@@ -574,10 +585,11 @@ static void show_graph(char ch, int cnt,
 static void show_stats(struct diffstat_t* data, struct diff_options *options)
 {
 	int i, len, add, del, total, adds = 0, dels = 0;
-	int max_change = 0, max_len = 0;
+	int max_change = 0, max_len = 0, min_change = 0;
 	int total_files = data->nr;
 	int width, name_width;
 	const char *reset, *set, *add_c, *del_c;
+	int non_linear_scale = 0;
 
 	if (data->nr == 0)
 		return;
@@ -595,12 +607,12 @@ static void show_stats(struct diffstat_t
 			width = name_width + 15;
 	}
 
-	/* Find the longest filename and max number of changes */
 	reset = diff_get_color(options->color_diff, DIFF_RESET);
 	set = diff_get_color(options->color_diff, DIFF_PLAIN);
 	add_c = diff_get_color(options->color_diff, DIFF_FILE_NEW);
 	del_c = diff_get_color(options->color_diff, DIFF_FILE_OLD);
 
+	/* Find the longest filename and max/min number of changes */
 	for (i = 0; i < data->nr; i++) {
 		struct diffstat_file *file = data->files[i];
 		int change = file->added + file->deleted;
@@ -620,6 +632,8 @@ static void show_stats(struct diffstat_t
 			continue;
 		if (max_change < change)
 			max_change = change;
+		if (0 < change && (!min_change || change < min_change))
+			min_change = change;
 	}
 
 	/* Compute the width of the graph part;
@@ -635,6 +649,12 @@ static void show_stats(struct diffstat_t
 	else
 		width = max_change;
 
+	/* See if the minimum change is shown with the normal scale
+	 * and if not switch to non-linear scale
+	 */
+	if (min_change && !scale_linear(min_change, width, max_change))
+		non_linear_scale = 1;
+
 	for (i = 0; i < data->nr; i++) {
 		const char *prefix = "";
 		char *name = data->files[i]->name;
@@ -684,6 +704,11 @@ static void show_stats(struct diffstat_t
 
 		if (max_change < width)
 			;
+		else if (non_linear_scale) {
+			total = scale_non_linear(total, width, max_change);
+			add = scale_linear(add, total, add + del);
+			del = total - add;
+		}
 		else {
 			total = scale_linear(total, width, max_change);
 			add = scale_linear(add, width, max_change);
-- 
1.4.2.1.gf80a

^ permalink raw reply related	[flat|nested] 19+ messages in thread
* Re: [PATCH 3/3] diff --stat: sometimes use non-linear scaling.
@ 2006-10-12 15:04 apodtele
  0 siblings, 0 replies; 19+ messages in thread
From: apodtele @ 2006-10-12 15:04 UTC (permalink / raw)
  To: git

Sublinear solution without patch is below.

On Sept 28, 2006 Martin Waitz wrote:
> On Wed, Sep 27, 2006 at 08:12:49AM -0700, Linus Torvalds wrote:
>> No _way_ is it correct to show more than three characters if there were
>> three lines of changes.
>>
>> I think "nonlinear" is fine, but this is something that is "superlinear"
>> in small changes, and then sublinear in bigger ones (and then apparently
>> totally wrong for one-line changes).
>>
>> It should at least never be superlinear, I believe.
>
> So if we want to keep the logarithmic scale we can do some maths:
> Assume we use a formula ala
>         length = a log(change + b) + c

You are probably looking for much simpler, log-less, and pure integer:

        length = width * change / (width + change) + 1

Assuming target witdth of 40, for example, it will produce

Change    Length
1         1
2         2
3         3
4         4
10        9
20        14
30        18
50        23
100       29
1000      39
10000     40
1000000   40

--
Alexei

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2006-10-12 15:04 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-09-27  2:40 [PATCH 3/3] diff --stat: sometimes use non-linear scaling Junio C Hamano
2006-09-27  3:11 ` David Rientjes
2006-09-27  5:09   ` Junio C Hamano
2006-09-27  5:32     ` David Rientjes
2006-09-27  6:19       ` Junio C Hamano
2006-09-27  6:49         ` David Rientjes
2006-09-27  7:05           ` Junio C Hamano
2006-09-27  7:19             ` David Rientjes
2006-09-27  7:50               ` Johannes Schindelin
     [not found]                 ` <BAYC1-PASMTP024D1DA4730F9DF93F857FAE1A0@CEZ.ICE>
2006-09-27  8:35                   ` Johannes Schindelin
     [not found]                     ` <20060927044112.cc170405.seanlkml@sympatico.ca>
2006-09-27  8:41                       ` Sean
2006-10-06 15:53                 ` Petr Baudis
2006-09-27  7:36 ` Johannes Schindelin
2006-09-27  9:16 ` Martin Waitz
2006-09-27 15:12 ` Linus Torvalds
2006-09-28  8:17   ` Martin Waitz
2006-09-28  9:20     ` Junio C Hamano
2006-09-29 10:56       ` Andreas Ericsson
  -- strict thread matches above, loose matches on Subject: below --
2006-10-12 15:04 apodtele

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).