@@ -45,14 +45,60 @@ impl CommitMetrics {
45
45
let bot_regex_pattern = get_no_bots_regex ( & options. info . no_bots ) ?;
46
46
let mut time_of_most_recent_commit = None ;
47
47
let mut time_of_first_commit = None ;
48
+
49
+ let num_threads = std:: thread:: available_parallelism ( )
50
+ . map ( |p| p. get ( ) )
51
+ . unwrap_or ( 1 ) ;
52
+ let commit_graph = repo. commit_graph ( ) . ok ( ) ;
53
+ let can_use_author_threads = num_threads > 1 && commit_graph. is_some ( ) ;
48
54
let commit_iter = repo
49
55
. head_commit ( ) ?
50
56
. id ( )
51
57
. ancestors ( )
52
58
. sorting ( Sorting :: ByCommitTimeNewestFirst )
59
+ . use_commit_graph ( can_use_author_threads)
60
+ . with_commit_graph ( commit_graph)
53
61
. all ( ) ?;
54
62
55
- let mailmap_config = repo. open_mailmap ( ) ;
63
+ let mailmap = repo. open_mailmap ( ) ;
64
+ let author_threads = can_use_author_threads. then ( || {
65
+ // we intentionally over-allocate threads a little as the main thread won't be very busy anyway
66
+ // traversing commits with the graph available.
67
+ // The channel is generously bounded to assure all threads are fed, without consuming excessive memory.
68
+ // We have to wait for the threads to finish anyway so some synchronization here will be fine, while tests
69
+ // show that this is about as fast as if it was unbounded.
70
+ let ( tx, rx) = crossbeam_channel:: bounded ( num_threads * 100 ) ;
71
+ let threads: Vec < _ > = ( 0 ..num_threads)
72
+ . map ( |_| {
73
+ std:: thread:: spawn ( {
74
+ let mut repo = repo. clone ( ) ;
75
+ let mailmap = mailmap. clone ( ) ;
76
+ let bot_regex_pattern = bot_regex_pattern. clone ( ) ;
77
+ let rx = rx. clone ( ) ;
78
+ move || -> anyhow:: Result < _ > {
79
+ let mut number_of_commits_by_signature: HashMap < Sig , usize > =
80
+ HashMap :: new ( ) ;
81
+ // We are sure to see each object only once.
82
+ repo. object_cache_size ( 0 ) ;
83
+ for commit_id in rx {
84
+ if let Some ( commit) =
85
+ repo. try_find_object ( commit_id) ?. map ( |c| c. into_commit ( ) )
86
+ {
87
+ let sig = mailmap. resolve ( commit. author ( ) ?) ;
88
+ if !is_bot ( & sig. name , & bot_regex_pattern) {
89
+ * number_of_commits_by_signature
90
+ . entry ( sig. into ( ) )
91
+ . or_insert ( 0 ) += 1 ;
92
+ }
93
+ }
94
+ }
95
+ Ok ( number_of_commits_by_signature)
96
+ }
97
+ } )
98
+ } )
99
+ . collect ( ) ;
100
+ ( threads, tx)
101
+ } ) ;
56
102
let mut number_of_commits_by_signature: HashMap < Sig , usize > = HashMap :: new ( ) ;
57
103
let ( sender, receiver) = std:: sync:: mpsc:: channel :: < gix:: hash:: ObjectId > ( ) ;
58
104
let has_graph_commit_traversal_ended = Arc :: new ( AtomicBool :: default ( ) ) ;
@@ -93,11 +139,15 @@ impl CommitMetrics {
93
139
continue ;
94
140
}
95
141
96
- let sig = mailmap_config. resolve ( commit. object ( ) ?. author ( ) ?) ;
97
- if !is_bot ( & sig. name , & bot_regex_pattern) {
98
- * number_of_commits_by_signature
99
- . entry ( sig. into ( ) )
100
- . or_insert ( 0 ) += 1 ;
142
+ if let Some ( ( _threads, send_commit) ) = author_threads. as_ref ( ) {
143
+ send_commit. send ( commit. id ) ?;
144
+ } else {
145
+ let sig = mailmap. resolve ( commit. object ( ) ?. author ( ) ?) ;
146
+ if !is_bot ( & sig. name , & bot_regex_pattern) {
147
+ * number_of_commits_by_signature
148
+ . entry ( sig. into ( ) )
149
+ . or_insert ( 0 ) += 1 ;
150
+ }
101
151
}
102
152
let commit_time = gix:: actor:: Time :: new (
103
153
commit
@@ -118,6 +168,16 @@ impl CommitMetrics {
118
168
has_graph_commit_traversal_ended. store ( true , Ordering :: SeqCst ) ;
119
169
total_number_of_commits. store ( count, Ordering :: SeqCst ) ;
120
170
171
+ if let Some ( ( threads, sender) ) = author_threads {
172
+ drop ( sender) ;
173
+ for thread in threads {
174
+ let mapping = thread. join ( ) . expect ( "no panic" ) ?;
175
+ for ( sig, num_commits) in mapping {
176
+ * number_of_commits_by_signature. entry ( sig) . or_insert ( 0 ) += num_commits;
177
+ }
178
+ }
179
+ }
180
+
121
181
let ( authors_to_display, total_number_of_authors) = compute_authors (
122
182
number_of_commits_by_signature,
123
183
count,
0 commit comments