git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org
Cc: "Thomas Rast" <trast@inf.ethz.ch>,
	"Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH 5/5] Support multithread in traverse_commit_list and rev-list
Date: Tue, 10 Apr 2012 21:39:31 +0700	[thread overview]
Message-ID: <1334068771-32725-6-git-send-email-pclouds@gmail.com> (raw)
In-Reply-To: <1334068771-32725-1-git-send-email-pclouds@gmail.com>


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/rev-list.c |    3 +-
 list-objects.c     |  153 +++++++++++++++++++++++++++++++++++++++++++++++++--
 revision.c         |   16 ++++++
 revision.h         |    2 +
 4 files changed, 167 insertions(+), 7 deletions(-)

diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index e720561..e07ba40 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -395,7 +395,8 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
 			return show_bisect_vars(&info, reaches, all);
 	}
 
-	traverse_commit_list(&revs, show_commit, show_object, &info, 0);
+	traverse_commit_list(&revs, show_commit, show_object, &info,
+			     getenv("REV_LIST") ? 2 : 0);
 
 	if (revs.count) {
 		if (revs.left_right && revs.cherry_mark)
diff --git a/list-objects.c b/list-objects.c
index 4f365e8..59a7c33 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -7,6 +7,29 @@
 #include "tree-walk.h"
 #include "revision.h"
 #include "list-objects.h"
+#include "semaphore.h"
+
+struct thread_data {
+	pthread_t thread;
+	pthread_mutex_t mutex;
+	sem_t sem;
+
+	struct rev_info *revs;
+	struct tree *tree;
+	show_object_fn show;
+	struct name_path *path;
+	struct strbuf base;
+	const char *name;
+	void *cb_data;
+};
+
+static struct thread_data *threads;
+static int nr_threads;
+static pthread_mutex_t obj_lock;
+static int done;
+
+#define LOCK_OBJ() { if (nr_threads) pthread_mutex_lock(&obj_lock); }
+#define UNLOCK_OBJ() { if (nr_threads) pthread_mutex_unlock(&obj_lock); }
 
 static void process_blob(struct rev_info *revs,
 			 struct blob *blob,
@@ -21,10 +44,14 @@ static void process_blob(struct rev_info *revs,
 		return;
 	if (!obj)
 		die("bad blob object");
-	if (obj->flags & (UNINTERESTING | SEEN))
+	LOCK_OBJ();
+	if (obj->flags & (UNINTERESTING | SEEN)) {
+		UNLOCK_OBJ();
 		return;
+	}
 	obj->flags |= SEEN;
 	show(obj, path, name, cb_data);
+	UNLOCK_OBJ();
 }
 
 /*
@@ -79,12 +106,20 @@ static void process_tree(struct rev_info *revs,
 		return;
 	if (!obj)
 		die("bad tree object");
-	if (obj->flags & (UNINTERESTING | SEEN))
+
+	LOCK_OBJ();
+	if (obj->flags & (UNINTERESTING | SEEN)) {
+		UNLOCK_OBJ();
 		return;
+	}
+	obj->flags |= SEEN;
+	UNLOCK_OBJ();
 	if (parse_tree(tree) < 0)
 		die("bad tree object %s", sha1_to_hex(obj->sha1));
-	obj->flags |= SEEN;
+	LOCK_OBJ();
 	show(obj, path, name, cb_data);
+	UNLOCK_OBJ();
+
 	me.up = path;
 	me.elem = name;
 	me.elem_len = strlen(name);
@@ -167,6 +202,80 @@ static void add_pending_tree(struct rev_info *revs, struct tree *tree)
 	add_pending_object(revs, &tree->object, "");
 }
 
+static void *woodchipper(void *arg)
+{
+	struct thread_data *data = arg;
+	struct tree *tree;
+
+	init_pack_context();
+
+	while (!done) {
+		pthread_mutex_lock(&data->mutex);
+		tree = data->tree;
+		pthread_mutex_unlock(&data->mutex);
+		if (!tree) {
+			sem_wait(&data->sem);
+			continue;
+		}
+
+		process_tree(data->revs, tree, data->show, data->path,
+			     &data->base, data->name, data->cb_data);
+		free(data->path);
+		strbuf_reset(&data->base);
+
+		pthread_mutex_lock(&data->mutex);
+		data->tree = NULL;
+		pthread_mutex_unlock(&data->mutex);
+
+		sem_wait(&data->sem);
+	}
+	return NULL;
+}
+
+static void distribute_tree(struct rev_info *revs,
+			    struct tree *tree,
+			    show_object_fn show,
+			    struct name_path *path,
+			    struct strbuf *base,
+			    const char *name,
+			    void *cb_data)
+{
+	int i = 0;
+
+	while (nr_threads && i < nr_threads) {
+		struct tree *old_tree;
+		struct thread_data *thr = threads + i;
+		pthread_mutex_lock(&thr->mutex);
+		old_tree = thr->tree;
+		pthread_mutex_unlock(&thr->mutex);
+#if 0
+		if (old_tree) {
+			i = (i + 1) % nr_threads;
+			sched_yield();
+			continue;
+		}
+#else
+		if (old_tree) {
+			i++;
+			continue;
+		}
+#endif
+
+		/* the thread must be asleep, or going to sleep by now */
+		thr->revs = revs;
+		thr->tree = tree;
+		thr->show = show;
+		thr->path = dup_name_path(path);
+		strbuf_addbuf(&thr->base, base);
+		thr->name = name;
+		thr->cb_data = cb_data;
+		sem_post(&thr->sem);
+		return;
+	}
+
+	process_tree(revs, tree, show, path, base, name, cb_data);
+}
+
 void traverse_commit_list(struct rev_info *revs,
 			  show_commit_fn show_commit,
 			  show_object_fn show_object,
@@ -186,20 +295,45 @@ void traverse_commit_list(struct rev_info *revs,
 			add_pending_tree(revs, commit->tree);
 		show_commit(commit, data);
 	}
+
+	nr_threads = nr_threads_;
+	if (nr_threads) {
+		threads = xmalloc((sizeof*threads) * nr_threads);
+		memset(threads, 0, sizeof(*threads) * nr_threads);
+		pthread_mutex_init(&obj_lock, NULL);
+		done = 0;
+		for (i = 0; i < nr_threads; i++) {
+			threads[i].tree = NULL;
+			strbuf_init(&threads[i].base, PATH_MAX);
+			pthread_mutex_init(&threads[i].mutex, NULL);
+			sem_init(&threads[i].sem, 0, 0);
+			pthread_create(&threads[i].thread, NULL, woodchipper, threads + i);
+		}
+
+		pthread_mutex_init(&mtx, NULL);
+		multithread_object_access = 1;
+	}
+
 	for (i = 0; i < revs->pending.nr; i++) {
 		struct object_array_entry *pending = revs->pending.objects + i;
 		struct object *obj = pending->item;
 		const char *name = pending->name;
-		if (obj->flags & (UNINTERESTING | SEEN))
+		LOCK_OBJ();
+		if (obj->flags & (UNINTERESTING | SEEN)) {
+			UNLOCK_OBJ();
 			continue;
+		}
+		UNLOCK_OBJ();
 		if (obj->type == OBJ_TAG) {
+			LOCK_OBJ();
 			obj->flags |= SEEN;
 			show_object(obj, NULL, name, data);
+			UNLOCK_OBJ();
 			continue;
 		}
 		if (obj->type == OBJ_TREE) {
-			process_tree(revs, (struct tree *)obj, show_object,
-				     NULL, &base, name, data);
+			distribute_tree(revs, (struct tree *)obj, show_object,
+					NULL, &base, name, data);
 			continue;
 		}
 		if (obj->type == OBJ_BLOB) {
@@ -210,6 +344,13 @@ void traverse_commit_list(struct rev_info *revs,
 		die("unknown pending object %s (%s)",
 		    sha1_to_hex(obj->sha1), name);
 	}
+	if (nr_threads) {
+		done = 1;
+		for (i = 0; i < nr_threads; i++) {
+			sem_post(&threads[i].sem);
+			pthread_join(threads[i].thread, NULL);
+		}
+	}
 	if (revs->pending.nr) {
 		free(revs->pending.objects);
 		revs->pending.nr = 0;
diff --git a/revision.c b/revision.c
index b3554ed..40b6e15 100644
--- a/revision.c
+++ b/revision.c
@@ -40,6 +40,22 @@ char *path_name(const struct name_path *path, const char *name)
 	return n;
 }
 
+struct name_path *dup_name_path(const struct name_path *path)
+{
+	const struct name_path *src;
+	struct name_path *dup, *dst;
+	int len;
+	for (len = 0, src = path; src; src = src->up)
+		len++;
+	dup = xmalloc(sizeof(*dup) * len);
+	for (src = path, dst = dup; src; src = src->up, dst++) {
+		memcpy(dst, src, sizeof(*src));
+		if (dst > dup)
+			dst[-1].up = dst;
+	}
+	return dup;
+}
+
 static int show_path_component_truncated(FILE *out, const char *name, int len)
 {
 	int cnt;
diff --git a/revision.h b/revision.h
index b8e9223..0da4636 100644
--- a/revision.h
+++ b/revision.h
@@ -208,6 +208,8 @@ struct name_path {
 
 char *path_name(const struct name_path *path, const char *name);
 
+struct name_path *dup_name_path(const struct name_path *);
+
 extern void show_object_with_name(FILE *, struct object *, const struct name_path *, const char *);
 
 extern void add_object(struct object *obj,
-- 
1.7.8.36.g69ee2

  parent reply	other threads:[~2012-04-10 14:43 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-04-10 14:39 [PATCH 0/5] multithread traverse_commit_list (aka rev-list) Nguyễn Thái Ngọc Duy
2012-04-10 14:39 ` [PATCH 1/5] Remove global pointer "packed_git" in favor or set/get function pair Nguyễn Thái Ngọc Duy
2012-04-10 14:39 ` [PATCH 2/5] sha1_file: stuff various pack reading variables into a struct Nguyễn Thái Ngọc Duy
2012-04-10 14:39 ` [PATCH 3/5] Make lookup_*() functions thread-safe Nguyễn Thái Ngọc Duy
2012-04-10 14:39 ` [PATCH 4/5] Teach traverse_commit_list callsites about new parameter, nr_threads Nguyễn Thái Ngọc Duy
2012-04-10 14:39 ` Nguyễn Thái Ngọc Duy [this message]
2012-04-10 16:51 ` [PATCH 0/5] multithread traverse_commit_list (aka rev-list) Martin Fick

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1334068771-32725-6-git-send-email-pclouds@gmail.com \
    --to=pclouds@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=trast@inf.ethz.ch \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).