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
next prev 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.