OXYGENHUB

git import: OXY_IMPORT_TRACE=1 traces each commit (refs #25) fb5b6181618a

Where its base came from (kept, cloned, rebuilt), how many changes a
merge added, the graphs its kept state holds, the kept states and the
resident memory: to find what pushed the full vscode import past 14 GB
after 2 h 18 min.
Author
Andy McCall @andymccall <[email protected]>
When
· 2026-10-01 03:50 UTC
Signature
✔ signed by Andy McCall
Hash
fb5b6181618a39ba4e6807b0d16b307d58b843457d5d3ca4cde526b1a7a6abae
Depends on
03571027793e 30ea9c1e70fa 79ab8528ff62 958fb27dda7c c3069537d7c5 f9575918477f ff0af1ee299d
Depended on by
ce118287d9da 810691ca6ce6 9935d490ddfb d45dab0484ea fd280228bdc2 d2e3c39da1b1
In bookmarks
agents-in-readme bare-hashes carried-not-removed carry-identical doctor-trust identical-sides keyless-tags main merge-remote-bookmark only-help-103 paths-for-resolutions-and-amend push-notes show-stat subrepo-pin-state switch-says
In tags
v0.10.0 v0.11.0 v0.2.0 v0.3.0 v0.3.1 v0.4.0 v0.4.1 v0.4.2 v0.4.3 v0.4.4 v0.4.5 v0.4.6 v0.5.0 v0.5.1 v0.6.0 v0.7.0 v0.8.0 v0.9.0
Edits
9 atoms, 0 tree operations, 2 files

Browse the tree at this change

modified crates/oxy-core/src/repo/git.rs +38 −0
…
741 unchanged lines
742 742
        // Time spent per phase over all commits (`OXY_TIMINGS=1`).
743 743
        let mut spent = [std::time::Duration::ZERO; 6];
744 744
        let mut clock = std::time::Instant::now();
745 +
        // One line per commit on stderr with OXY_IMPORT_TRACE=1: where its
746 +
        // base came from, what a merge added, the graphs its state holds,
747 +
        // the kept states and the process's resident memory.
748 +
        let trace = std::env::var_os("OXY_IMPORT_TRACE").is_some();
749 +
        let rss_mb = || -> u64 {
750 +
            std::fs::read_to_string("/proc/self/statm")
751 +
                .ok()
752 +
                .and_then(|s| s.split_whitespace().nth(1)?.parse::<u64>().ok())
753 +
                .map(|pages| pages * 4096 >> 20)
754 +
                .unwrap_or(0)
755 +
        };
756 +
        let mut done = 0usize;
745 757
        let mut lap = |i: usize, clock: &mut std::time::Instant| {
746 758
            let now = std::time::Instant::now();
747 759
            spent[i] += now - *clock;
…
4 unchanged lines
752 764
            if known.imported.contains_key(&gc.sha) || known.exported.contains_key(&gc.sha) {
753 765
                continue;
754 766
            }
767 +
            let mut base_how = "root";
755 768
            // Base: union of every parent's state, starting from the first
756 769
            // parent's kept state when there is one; its tree tells which
757 770
            // paths this commit leaves alone.
…
8 unchanged lines
766 779
                        kept.remove(p1.as_str())
767 780
                    } else {
768 781
                        kept.get(p1.as_str()).cloned()
782 +
                    };
783 +
                    let how = match (&found, left) {
784 +
                        (Some(_), Some(0)) => "kept",
785 +
                        (Some(_), _) => "cloned",
786 +
                        (None, _) => "rebuilt",
769 787
                    };
788 +
                    if trace {
789 +
                        base_how = how;
790 +
                    }
770 791
                    match found {
771 792
                        Some((st, tree)) => (st, Some(tree)),
772 793
                        None => {
…
14 unchanged lines
787 808
            // Nodes the other parents' changes touch: the first parent's
788 809
            // tree cannot vouch for them.
789 810
            let mut touched: HashSet<NodeId> = HashSet::new();
811 +
            let mut merged = 0usize;
790 812
            if gc.parents.len() > 1 {
791 813
                report.merges += 1;
792 814
                let mut args: Vec<String> = gc.parents[1..].to_vec();
793 815
                args.push(format!("^{}", gc.parents[0]));
794 816
                let refs: Vec<&str> = args.iter().map(String::as_str).collect();
817 +
                let before = base.len();
795 818
                self.add_git_ancestors_touching(&mut base, git_dir, &refs, &known, &mut touched)?;
819 +
                merged = base.len() - before;
796 820
            }
797 821
            lap(0, &mut clock);
798 822
            // The commit's tree: its first parent's with the diff applied,
…
310 unchanged lines
1109 1133
            last = Some(gc.sha.clone());
1110 1134
            report.commits += 1;
1111 1135
            lap(5, &mut clock);
1136 +
            done += 1;
1137 +
            if trace {
1138 +
                let built = kept
1139 +
                    .get(gc.sha.as_str())
1140 +
                    .map(|(st, _)| st.built_count())
1141 +
                    .unwrap_or(0);
1142 +
                eprintln!(
1143 +
                    "trace {done} {} parents={} base={base_how} merged={merged} built={built} kept={} rss_mb={}",
1144 +
                    &gc.sha[..12.min(gc.sha.len())],
1145 +
                    gc.parents.len(),
1146 +
                    kept.len(),
1147 +
                    rss_mb()
1148 +
                );
1149 +
            }
1112 1150
        }
1113 1151
        for (name, d) in [
1114 1152
            "git import: bases",
…
526 unchanged lines
modified crates/oxy-core/src/state.rs +5 −0
…
821 unchanged lines
822 822
    pub fn len(&self) -> usize {
823 823
        self.changes.len()
824 824
    }
825 +
826 +
    /// How many file graphs this state has built.
827 +
    pub fn built_count(&self) -> usize {
828 +
        self.files.len()
829 +
    }
825 830
}
826 831
827 832
impl Deferred {
…
1551 unchanged lines