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 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).