Skip to content

Commit 27c1da7

Browse files
mpizenbergEh2406
andcommitted
feat: logging to help debugging (#107)
* feat: add logging to help debugging * debug: impl Display for partial solution * fix cherry picking * Fix display of assignments in partial_solution * debug: nits Co-authored-by: Jacob Finkelman <[email protected]>
1 parent 7f3ae14 commit 27c1da7

File tree

5 files changed

+93
-0
lines changed

5 files changed

+93
-0
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@ include = ["Cargo.toml", "LICENSE", "README.md", "src/**", "tests/**", "examples
2323
thiserror = "1.0"
2424
rustc-hash = "1.1.0"
2525
serde = { version = "1.0", features = ["derive"], optional = true }
26+
log = "0.4.14" # for debug logs in tests
2627

2728
[dev-dependencies]
2829
proptest = "0.10.1"
2930
ron = "0.6"
3031
varisat = "0.2.2"
3132
criterion = "0.3"
33+
env_logger = "0.9.0"
3234

3335
[[bench]]
3436
name = "large_case"

src/internal/core.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ impl<P: Package, V: Version> State<P, V> {
115115
// If the partial solution satisfies the incompatibility
116116
// we must perform conflict resolution.
117117
Relation::Satisfied => {
118+
log::info!(
119+
"Start conflict resolution because incompat satisfied:\n {}",
120+
current_incompat
121+
);
118122
conflict_id = Some(incompat_id);
119123
break;
120124
}
@@ -183,6 +187,7 @@ impl<P: Package, V: Version> State<P, V> {
183187
current_incompat_changed,
184188
previous_satisfier_level,
185189
);
190+
log::info!("backtrack to {:?}", previous_satisfier_level);
186191
return Ok((package, current_incompat_id));
187192
}
188193
SameDecisionLevels { satisfier_cause } => {
@@ -192,6 +197,7 @@ impl<P: Package, V: Version> State<P, V> {
192197
&package,
193198
&self.incompatibility_store,
194199
);
200+
log::info!("prior cause: {}", prior_cause);
195201
current_incompat_id = self.incompatibility_store.alloc(prior_cause);
196202
current_incompat_changed = true;
197203
}

src/internal/partial_solution.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
//! A Memory acts like a structured partial solution
44
//! where terms are regrouped by package in a [Map](crate::type_aliases::Map).
55
6+
use std::fmt::Display;
7+
68
use crate::internal::arena::Arena;
79
use crate::internal::incompatibility::{IncompId, Incompatibility, Relation};
810
use crate::internal::small_map::SmallMap;
@@ -32,6 +34,24 @@ pub struct PartialSolution<P: Package, V: Version> {
3234
package_assignments: Map<P, PackageAssignments<P, V>>,
3335
}
3436

37+
impl<P: Package, V: Version> Display for PartialSolution<P, V> {
38+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39+
let mut assignments: Vec<_> = self
40+
.package_assignments
41+
.iter()
42+
.map(|(p, pa)| format!("{}: {}", p, pa))
43+
.collect();
44+
assignments.sort();
45+
write!(
46+
f,
47+
"next_global_index: {}\ncurrent_decision_level: {:?}\npackage_assignements:\n{}",
48+
self.next_global_index,
49+
self.current_decision_level,
50+
assignments.join("\t\n")
51+
)
52+
}
53+
}
54+
3555
/// Package assignments contain the potential decision and derivations
3656
/// that have already been made for a given package,
3757
/// as well as the intersection of terms by all of these.
@@ -43,19 +63,54 @@ struct PackageAssignments<P: Package, V: Version> {
4363
assignments_intersection: AssignmentsIntersection<V>,
4464
}
4565

66+
impl<P: Package, V: Version> Display for PackageAssignments<P, V> {
67+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68+
let derivations: Vec<_> = self
69+
.dated_derivations
70+
.iter()
71+
.map(|dd| dd.to_string())
72+
.collect();
73+
write!(
74+
f,
75+
"decision range: {:?}..{:?}\nderivations:\n {}\n,assignments_intersection: {}",
76+
self.smallest_decision_level,
77+
self.highest_decision_level,
78+
derivations.join("\n "),
79+
self.assignments_intersection
80+
)
81+
}
82+
}
83+
4684
#[derive(Clone, Debug)]
4785
pub struct DatedDerivation<P: Package, V: Version> {
4886
global_index: u32,
4987
decision_level: DecisionLevel,
5088
cause: IncompId<P, V>,
5189
}
5290

91+
impl<P: Package, V: Version> Display for DatedDerivation<P, V> {
92+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93+
write!(f, "{:?}, cause: {:?}", self.decision_level, self.cause)
94+
}
95+
}
96+
5397
#[derive(Clone, Debug)]
5498
enum AssignmentsIntersection<V: Version> {
5599
Decision((u32, V, Term<V>)),
56100
Derivations(Term<V>),
57101
}
58102

103+
impl<V: Version> Display for AssignmentsIntersection<V> {
104+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105+
match self {
106+
Self::Decision((lvl, version, _)) => {
107+
write!(f, "Decision: level {}, v = {}", lvl, version)
108+
}
109+
Self::Derivations(term) => write!(f, "Derivations term: {}", term),
110+
}
111+
}
112+
}
113+
59114
#[derive(Clone, Debug)]
60115
pub enum SatisfierSearch<P: Package, V: Version> {
61116
DifferentDecisionLevels {
@@ -258,7 +313,14 @@ impl<P: Package, V: Version> PartialSolution<P, V> {
258313
// Check none of the dependencies (new_incompatibilities)
259314
// would create a conflict (be satisfied).
260315
if store[new_incompatibilities].iter().all(not_satisfied) {
316+
log::info!("add_decision: {} @ {}", package, version);
261317
self.add_decision(package, version);
318+
} else {
319+
log::info!(
320+
"not adding {} @ {} because of its dependencies",
321+
package,
322+
version
323+
);
262324
}
263325
}
264326

src/solver.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,12 @@ pub fn resolve<P: Package, V: Version>(
9292
.should_cancel()
9393
.map_err(|err| PubGrubError::ErrorInShouldCancel(err))?;
9494

95+
log::info!("unit_propagation: {}", &next);
9596
state.unit_propagation(next)?;
97+
log::debug!(
98+
"Partial solution after unit propagation: {}",
99+
state.partial_solution
100+
);
96101

97102
let potential_packages = state.partial_solution.potential_packages();
98103
if potential_packages.is_none() {
@@ -109,6 +114,7 @@ pub fn resolve<P: Package, V: Version>(
109114
let decision = dependency_provider
110115
.choose_package_version(potential_packages.unwrap())
111116
.map_err(PubGrubError::ErrorChoosingPackageVersion)?;
117+
log::info!("DP chose: {} @ {:?}", decision.0, decision.1);
112118
next = decision.0.clone();
113119

114120
// Pick the next compatible version.
@@ -194,6 +200,7 @@ pub fn resolve<P: Package, V: Version>(
194200
} else {
195201
// `dep_incompats` are already in `incompatibilities` so we know there are not satisfied
196202
// terms and can add the decision directly.
203+
log::info!("add_decision (not first time): {} @ {}", &next, v);
197204
state.partial_solution.add_decision(next.clone(), v);
198205
}
199206
}

tests/examples.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,21 @@ use pubgrub::solver::{resolve, OfflineDependencyProvider};
55
use pubgrub::type_aliases::Map;
66
use pubgrub::version::{NumberVersion, SemanticVersion};
77

8+
use log::LevelFilter;
9+
use std::io::Write;
10+
11+
fn init_log() {
12+
let _ = env_logger::builder()
13+
.filter_level(LevelFilter::Trace)
14+
.format(|buf, record| writeln!(buf, "{}", record.args()))
15+
.is_test(true)
16+
.try_init();
17+
}
18+
819
#[test]
920
/// https://github.com/dart-lang/pub/blob/master/doc/solver.md#no-conflicts
1021
fn no_conflict() {
22+
init_log();
1123
let mut dependency_provider = OfflineDependencyProvider::<&str, SemanticVersion>::new();
1224
#[rustfmt::skip]
1325
dependency_provider.add_dependencies(
@@ -38,6 +50,7 @@ fn no_conflict() {
3850
#[test]
3951
/// https://github.com/dart-lang/pub/blob/master/doc/solver.md#avoiding-conflict-during-decision-making
4052
fn avoiding_conflict_during_decision_making() {
53+
init_log();
4154
let mut dependency_provider = OfflineDependencyProvider::<&str, SemanticVersion>::new();
4255
#[rustfmt::skip]
4356
dependency_provider.add_dependencies(
@@ -73,6 +86,7 @@ fn avoiding_conflict_during_decision_making() {
7386
#[test]
7487
/// https://github.com/dart-lang/pub/blob/master/doc/solver.md#performing-conflict-resolution
7588
fn conflict_resolution() {
89+
init_log();
7690
let mut dependency_provider = OfflineDependencyProvider::<&str, SemanticVersion>::new();
7791
#[rustfmt::skip]
7892
dependency_provider.add_dependencies(
@@ -106,6 +120,7 @@ fn conflict_resolution() {
106120
#[test]
107121
/// https://github.com/dart-lang/pub/blob/master/doc/solver.md#conflict-resolution-with-a-partial-satisfier
108122
fn conflict_with_partial_satisfier() {
123+
init_log();
109124
let mut dependency_provider = OfflineDependencyProvider::<&str, SemanticVersion>::new();
110125
#[rustfmt::skip]
111126
// root 1.0.0 depends on foo ^1.0.0 and target ^2.0.0
@@ -171,6 +186,7 @@ fn conflict_with_partial_satisfier() {
171186
///
172187
/// Solution: a0, b0, c0, d0
173188
fn double_choices() {
189+
init_log();
174190
let mut dependency_provider = OfflineDependencyProvider::<&str, NumberVersion>::new();
175191
dependency_provider.add_dependencies("a", 0, vec![("b", Range::any()), ("c", Range::any())]);
176192
dependency_provider.add_dependencies("b", 0, vec![("d", Range::exact(0))]);

0 commit comments

Comments
 (0)