Download raw body.
tog is sluggish with FreeBSD src.git
On Thu, Dec 24, 2020 at 04:39:29PM +0100, Christian Weisgerber wrote: > Stefan Sperling: > > > The patch below shows us where the problem is: Iterating a long SIMPLEQ > > relifst in order to decorate commit hashes with branch names is too slow. > > "got log" has the same problem, although it's less noticeable. > got.c:print_commit() Right. This can be fixed once we have a known-good fix for tog. > > This patch makes commits load faster but moving the selection cursor > > in the log view is still too slow. > > It's also buggy: > * tog log -r got.git > * first entry is shown as "main, origin/main" in the status line > * move down > * move up again > * no more "main, origin/main" Yes, let's forget about that patch. > > It looks like we'll need to populate a cache of reference names which > > is indexed by commit ID, ideally while reading references from the repo? > > got_ref_tree()? Something along those lines, I guess. Can you try this? Merry christmas <3 diff refs/heads/main refs/heads/object_id_map blob - 5f2594f5af806ea9b99c358f35fa4e7ce16f7efb blob + 8a7ddd1fed280c5ace7be5e759d1b7ef2c6cc784 --- include/got_reference.h +++ include/got_reference.h @@ -139,3 +139,28 @@ const struct got_error *got_ref_delete(struct got_refe /* Unlock a reference which was opened in locked state. */ const struct got_error *got_ref_unlock(struct got_reference *); + +/* Map object IDs to references. */ +struct got_reflist_object_id_map; + +/* + * Create and populate an object ID map for a given list of references. + * Map entries will contain deep-copies of elements of the reflist. + * The caller must dispose of the map with got_reflist_object_map_free(). + */ +const struct got_error *got_reflist_object_id_map_create( + struct got_reflist_object_id_map **, struct got_reflist_head *, + struct got_repository *); + +/* + * Return a list of references which correspond to a given object ID. + * The returned list must be considered read-only. + * The caller must _not_ call free(3) on the returned pointer! + * If no references are associated with the ID, return NULL. + */ +struct got_reflist_head * +got_reflist_object_id_map_lookup(struct got_reflist_object_id_map *, + struct got_object_id *); + +/* Free the specified object ID map. */ +void got_reflist_object_map_free(struct got_reflist_object_id_map *); blob - ef042bcbd8a8763b42a65397975a53c336f74544 blob + d9f1596591be3332b0a51e1ec4e6c77a90720fae --- lib/reference.c +++ lib/reference.c @@ -43,6 +43,7 @@ #include "got_lib_delta.h" #include "got_lib_inflate.h" #include "got_lib_object.h" +#include "got_lib_object_idset.h" #include "got_lib_lockfile.h" #ifndef nitems @@ -535,8 +536,8 @@ got_ref_dup(struct got_reference *ref) return NULL; } } else { - ref->ref.ref.name = strdup(ref->ref.ref.name); - if (ref->ref.ref.name == NULL) { + ret->ref.ref.name = strdup(ref->ref.ref.name); + if (ret->ref.ref.name == NULL) { free(ret); return NULL; } @@ -1400,3 +1401,97 @@ got_ref_unlock(struct got_reference *ref) ref->lf = NULL; return err; } + +struct got_reflist_object_id_map { + struct got_object_idset *idset; +}; + +struct got_reflist_object_id_map_entry { + struct got_reflist_head refs; +}; + +const struct got_error * +got_reflist_object_id_map_create(struct got_reflist_object_id_map **map, + struct got_reflist_head *refs, struct got_repository *repo) +{ + const struct got_error *err = NULL; + struct got_object_idset *idset; + struct got_object_id *id = NULL; + struct got_reflist_entry *re; + + idset = got_object_idset_alloc(); + if (idset == NULL) + return got_error_from_errno("got_object_idset_alloc"); + + *map = malloc(sizeof(**map)); + if (*map == NULL) { + got_object_idset_free(idset); + return got_error_from_errno("malloc"); + } + (*map)->idset = idset; + + SIMPLEQ_FOREACH(re, refs, entry) { + struct got_reflist_entry *new; + struct got_reflist_object_id_map_entry *ent; + + err = got_ref_resolve(&id, repo, re->ref); + if (err) + goto done; + + ent = got_object_idset_get(idset, id); + if (ent == NULL) { + ent = malloc(sizeof(*ent)); + if (ent == NULL) { + err = got_error_from_errno("malloc"); + goto done; + } + SIMPLEQ_INIT(&ent->refs); + err = got_object_idset_add(idset, id, ent); + if (err) + goto done; + } + + err = got_reflist_entry_dup(&new, re); + if (err) + goto done; + SIMPLEQ_INSERT_TAIL(&ent->refs, new, entry); + free(id); + id = NULL; + } +done: + free(id); + if (err) { + got_reflist_object_map_free(*map); + *map = NULL; + } + return NULL; +} + +struct got_reflist_head * +got_reflist_object_id_map_lookup(struct got_reflist_object_id_map *map, + struct got_object_id *id) +{ + struct got_reflist_object_id_map_entry *ent; + ent = got_object_idset_get(map->idset, id); + if (ent) + return &ent->refs; + return NULL; +} + +static const struct got_error * +free_id_map_entry(struct got_object_id *id, void *data, void *arg) +{ + struct got_reflist_object_id_map_entry *ent = data; + + got_ref_list_free(&ent->refs); + free(ent); + return NULL; +} + +void +got_reflist_object_map_free(struct got_reflist_object_id_map *map) +{ + got_object_idset_for_each(map->idset, free_id_map_entry, NULL); + got_object_idset_free(map->idset); + free(map); +} blob - d3d4a63398b4c4b05caa731b093b038b0b1d9bee blob + a28a00571d687d94f4f9215df59a0fe82423e7c9 --- tog/tog.c +++ tog/tog.c @@ -263,6 +263,7 @@ struct tog_diff_view_state { int force_text_diff; struct got_repository *repo; struct got_reflist_head refs; + struct got_reflist_object_id_map *idmap; struct tog_colors colors; size_t nlines; off_t *line_offsets; @@ -304,6 +305,7 @@ struct tog_log_view_state { int log_branches; struct got_repository *repo; struct got_reflist_head refs; + struct got_reflist_object_id_map *idmap; struct got_object_id *start_id; sig_atomic_t quit; pthread_t thread; @@ -1572,13 +1574,18 @@ draw_commits(struct tog_view *view) if (s->selected_entry && !(view->searching && view->search_next_done == 0)) { + struct got_reflist_head *refs; err = got_object_id_str(&id_str, s->selected_entry->id); if (err) return err; - err = build_refs_str(&refs_str, &s->refs, - s->selected_entry->id, s->repo); - if (err) - goto done; + refs = got_reflist_object_id_map_lookup(s->idmap, + s->selected_entry->id); + if (refs) { + err = build_refs_str(&refs_str, refs, + s->selected_entry->id, s->repo); + if (err) + goto done; + } } if (s->thread_args.commits_needed == 0) @@ -2118,6 +2125,10 @@ close_log_view(struct tog_view *view) s->start_id = NULL; free(s->head_ref_name); s->head_ref_name = NULL; + if (s->idmap) { + got_reflist_object_map_free(s->idmap); + s->idmap = NULL; + } got_ref_list_free(&s->refs); return err; } @@ -2263,6 +2274,9 @@ open_log_view(struct tog_view *view, struct got_object err = got_ref_list(&s->refs, repo, NULL, got_ref_cmp_by_name, NULL); if (err) goto done; + err = got_reflist_object_id_map_create(&s->idmap, &s->refs, repo); + if (err) + goto done; s->repo = repo; if (head_ref_name) { @@ -2529,11 +2543,19 @@ input_log_view(struct tog_view **new_view, struct tog_ got_repo_get_path(s->repo), NULL); if (err) return err; + if (s->idmap) { + got_reflist_object_map_free(s->idmap); + s->idmap = NULL; + } got_ref_list_free(&s->refs); err = got_ref_list(&s->refs, s->repo, NULL, got_ref_cmp_by_name, NULL); if (err) return err; + err = got_reflist_object_id_map_create(&s->idmap, &s->refs, + s->repo); + if (err) + return err; err = got_commit_graph_open(&s->thread_args.graph, s->in_repo_path, !s->log_branches); if (err) @@ -3254,14 +3276,16 @@ create_diff(struct tog_diff_view_state *s) const struct got_object_id_queue *parent_ids; struct got_object_qid *pid; struct got_commit_object *commit2; + struct got_reflist_head *refs; err = got_object_open_as_commit(&commit2, s->repo, s->id2); if (err) goto done; + refs = got_reflist_object_id_map_lookup(s->idmap, s->id2); /* Show commit info if we're diffing to a parent/root commit. */ if (s->id1 == NULL) { err = write_commit_info(&s->line_offsets, &s->nlines, - s->id2, &s->refs, s->repo, s->f); + s->id2, refs, s->repo, s->f); if (err) goto done; } else { @@ -3270,7 +3294,7 @@ create_diff(struct tog_diff_view_state *s) if (got_object_id_cmp(s->id1, pid->id) == 0) { err = write_commit_info( &s->line_offsets, &s->nlines, - s->id2, &s->refs, s->repo, s->f); + s->id2, refs, s->repo, s->f); if (err) goto done; break; @@ -3492,6 +3516,16 @@ open_diff_view(struct tog_view *view, struct got_objec free_colors(&s->colors); return err; } + err = got_reflist_object_id_map_create(&s->idmap, &s->refs, repo); + if (err) { + free(s->id1); + s->id1 = NULL; + free(s->id2); + s->id2 = NULL; + free_colors(&s->colors); + got_ref_list_free(&s->refs); + return err; + } if (log_view && view_is_splitscreen(view)) show_log_view(log_view); /* draw vborder */ @@ -3507,6 +3541,8 @@ open_diff_view(struct tog_view *view, struct got_objec s->id2 = NULL; free_colors(&s->colors); got_ref_list_free(&s->refs); + got_reflist_object_map_free(s->idmap); + s->idmap = NULL; return err; } @@ -3535,6 +3571,10 @@ close_diff_view(struct tog_view *view) free(s->line_offsets); s->line_offsets = NULL; s->nlines = 0; + if (s->idmap) { + got_reflist_object_map_free(s->idmap); + s->idmap = NULL; + } got_ref_list_free(&s->refs); return err; }
tog is sluggish with FreeBSD src.git