| @@ -18,6 +18,8 @@ pub struct Context<W> { · 17 unmodified lines |
| 18 | pub file_stats: bool, | 18 | pub file_stats: bool, |
| 19 | /// Collect how many lines in files have been added, removed and modified (without rename tracking). | 19 | /// Collect how many lines in files have been added, removed and modified (without rename tracking). |
| 20 | pub line_stats: bool, | 20 | pub line_stats: bool, |
| | 21 | /// The amount of threads to use. If unset, use all cores, if 0 use al physical cores. |
| | 22 | pub threads: Option<usize>, |
| 21 | /// Omit unifying identities by name and email which can lead to the same author appear multiple times | 23 | /// Omit unifying identities by name and email which can lead to the same author appear multiple times |
| 22 | /// due to using different names or email addresses. | 24 | /// due to using different names or email addresses. |
| 23 | pub omit_unify_identities: bool, | 25 | pub omit_unify_identities: bool, |
| @@ -41,6 +43,7 @@ pub fn estimate<W, P>( · 17 unmodified lines |
| 41 | file_stats, | 43 | file_stats, |
| 42 | line_stats, | 44 | line_stats, |
| 43 | omit_unify_identities, | 45 | omit_unify_identities, |
| | 46 | threads, |
| 44 | mut out, | 47 | mut out, |
| 45 | }: Context<W>, | 48 | }: Context<W>, |
| 46 | ) -> anyhow::Result<()> | 49 | ) -> anyhow::Result<()> |
| @@ -52,6 +55,14 @@ where · 5 unmodified lines |
| 52 | let commit_id = repo.rev_parse_single(rev_spec)?.detach(); | 55 | let commit_id = repo.rev_parse_single(rev_spec)?.detach(); |
| 53 | let mut string_heap = BTreeSet::<&'static [u8]>::new(); | 56 | let mut string_heap = BTreeSet::<&'static [u8]>::new(); |
| 54 | let needs_stats = file_stats || line_stats; | 57 | let needs_stats = file_stats || line_stats; |
| | 58 | let threads = { |
| | 59 | let t = threads.unwrap_or_else(num_cpus::get); |
| | 60 | (t == 0) |
| | 61 | .then(num_cpus::get_physical) |
| | 62 | .unwrap_or(t) |
| | 63 | .saturating_sub(1 /*main thread*/) |
| | 64 | .max(1) |
| | 65 | }; |
| 55 | | 66 | |
| 56 | let (commit_authors, stats, is_shallow, skipped_merge_commits) = { | 67 | let (commit_authors, stats, is_shallow, skipped_merge_commits) = { |
| 57 | let stat_progress = needs_stats.then(|| progress.add_child("extract stats")).map(|mut p| { | 68 | let stat_progress = needs_stats.then(|| progress.add_child("extract stats")).map(|mut p| { |
| @@ -125,10 +136,9 @@ where · 67 unmodified lines |
| 125 | | 136 | |
| 126 | let (tx_tree_id, stat_threads) = needs_stats | 137 | let (tx_tree_id, stat_threads) = needs_stats |
| 127 | .then(|| { | 138 | .then(|| { |
| 128 | let num_threads = num_cpus::get().saturating_sub(1 /*main thread*/).max(1); | | |
| 129 | let (tx, rx) = | 139 | let (tx, rx) = |
| 130 | crossbeam_channel::unbounded::<(u32, Option<git::hash::ObjectId>, git::hash::ObjectId)>(); | 140 | crossbeam_channel::unbounded::<(u32, Option<git::hash::ObjectId>, git::hash::ObjectId)>(); |
| 131 | let stat_workers = (0..num_threads) | 141 | let stat_workers = (0..threads) |
| 132 | .map(|_| { | 142 | .map(|_| { |
| 133 | scope.spawn({ | 143 | scope.spawn({ |
| 134 | let commit_counter = stat_counter.clone(); | 144 | let commit_counter = stat_counter.clone(); |