Skip to content

Commit 0cbf75a

Browse files
committed
WIP
1 parent d8d13d2 commit 0cbf75a

File tree

10 files changed

+735
-94
lines changed

10 files changed

+735
-94
lines changed

Cargo.lock

+544-28
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+12
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ authors = ["Prusti Devs <[email protected]>"]
55
edition = "2021"
66
build = "build.rs"
77

8+
[features]
9+
default = ["memory_profiling"]
10+
memory_profiling = [
11+
"tikv-jemallocator",
12+
"axum",
13+
"tokio",
14+
"jemalloc_pprof",
15+
]
816

917
[dependencies]
1018
# For RustRover
@@ -34,6 +42,10 @@ shell-escape = "0.1.5"
3442
smallvec = { version = "^1.11", features = ["union", "const_new"] }
3543
tracing = "0.1"
3644
tracing-subscriber = "0.3"
45+
tikv-jemallocator = { version = "0.6", features = ["profiling", "unprefixed_malloc_on_supported_platforms"], optional = true }
46+
axum = { version = "0.7", features = ["multipart"], optional = true }
47+
tokio = { version = "1.0", features = ["full", "rt-multi-thread"], optional = true }
48+
jemalloc_pprof = { version = "0.6", optional = true }
3749

3850
[dev-dependencies]
3951
reqwest = { version = "^0.11", features = ["blocking"] }

Dockerfile

+25-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
# Build stage for Rust projects
2-
FROM rust:1.75 as rust-builder
1+
FROM rust:1.75 as rust-deps
32

43
# Install required dependencies
54
RUN apt-get update && apt-get install -y \
@@ -11,7 +10,27 @@ WORKDIR /usr/src/app
1110
# Copy Rust project files
1211
COPY . .
1312

14-
# Build PCS
13+
FROM rust-deps as dev-profile
14+
15+
# Install extra useful stuff
16+
RUN apt-get update && apt-get install -y \
17+
golang-go tmux vim graphviz \
18+
&& rm -rf /var/lib/apt/lists/*
19+
20+
# Install latest pprof
21+
RUN go install github.com/google/pprof@latest
22+
23+
# Build a debug version
24+
RUN cargo build
25+
26+
# Set up Rust environment variables
27+
ENV PATH="/usr/local/cargo/bin:${PATH}"
28+
ENV RUSTUP_HOME="/usr/local/rustup"
29+
ENV CARGO_HOME="/usr/local/cargo"
30+
31+
FROM rust-deps as rust-builder
32+
33+
# Build PCG binary
1534
RUN cargo build --release
1635

1736
# Build pcg-server
@@ -66,4 +85,7 @@ ENV RUST_BACKTRACE=1
6685
# Expose port for pcg-server
6786
EXPOSE 4000
6887

88+
# Expose port for memory profiling
89+
EXPOSE 4444
90+
6991
CMD ["./pcg-server"]

shell.nix

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pkgs.mkShell {
1717
pkg-config
1818
rustNightly
1919
libiconv
20+
zlib
2021
] ++ (if pkgs.stdenv.isDarwin then [
2122
darwin.apple_sdk.frameworks.Security
2223
darwin.apple_sdk.frameworks.SystemConfiguration

src/borrows/edge/abstraction.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -214,11 +214,11 @@ pub struct AbstractionBlockEdge<'tcx> {
214214
}
215215

216216
impl<'tcx> EdgeData<'tcx> for AbstractionBlockEdge<'tcx> {
217-
fn blocked_nodes(&self, repacker: PlaceRepacker<'_, 'tcx>) -> FxHashSet<PCGNode<'tcx>> {
217+
fn blocked_nodes(&self, _repacker: PlaceRepacker<'_, 'tcx>) -> FxHashSet<PCGNode<'tcx>> {
218218
self.inputs().into_iter().map(|i| i.into()).collect()
219219
}
220220

221-
fn blocked_by_nodes(&self, repacker: PlaceRepacker<'_, 'tcx>) -> FxHashSet<LocalNode<'tcx>> {
221+
fn blocked_by_nodes(&self, _repacker: PlaceRepacker<'_, 'tcx>) -> FxHashSet<LocalNode<'tcx>> {
222222
self.outputs()
223223
.into_iter()
224224
.map(|o| o.to_local_node())

src/combined_pcs/domain.rs

+37-25
Original file line numberDiff line numberDiff line change
@@ -89,15 +89,19 @@ impl DataflowStmtPhase {
8989
}
9090
}
9191

92+
#[derive(Clone)]
93+
pub (crate) struct PCGDebugData {
94+
pub(crate) dot_output_dir: String,
95+
pub(crate) dot_graphs: Rc<RefCell<DotGraphs>>,
96+
}
97+
9298
#[derive(Clone)]
9399
pub struct PlaceCapabilitySummary<'a, 'tcx> {
94100
cgx: Rc<PCGContext<'a, 'tcx>>,
95101
pub(crate) block: Option<BasicBlock>,
96102

97103
pub(crate) pcg: PCG<'a, 'tcx>,
98-
dot_graphs: Option<Rc<RefCell<DotGraphs>>>,
99-
100-
dot_output_dir: Option<String>,
104+
debug_data: Option<PCGDebugData>,
101105

102106
join_history: FxHashSet<BasicBlock>,
103107
}
@@ -262,16 +266,19 @@ impl<'a, 'tcx> PlaceCapabilitySummary<'a, 'tcx> {
262266
self.pcg.borrow.set_block(block);
263267
}
264268

265-
pub fn set_dot_graphs(&mut self, dot_graphs: Rc<RefCell<DotGraphs>>) {
266-
self.dot_graphs = Some(dot_graphs);
269+
pub fn set_debug_data(&mut self, output_dir: String, dot_graphs: Rc<RefCell<DotGraphs>>) {
270+
self.debug_data = Some(PCGDebugData {
271+
dot_output_dir: output_dir,
272+
dot_graphs,
273+
});
267274
}
268275

269276
pub(crate) fn block(&self) -> BasicBlock {
270277
self.block.unwrap()
271278
}
272279

273-
pub fn dot_graphs(&self) -> Rc<RefCell<DotGraphs>> {
274-
self.dot_graphs.clone().unwrap()
280+
pub fn dot_graphs(&self) -> Option<Rc<RefCell<DotGraphs>>> {
281+
self.debug_data.as_ref().map(|data| data.dot_graphs.clone())
275282
}
276283

277284
fn dot_filename_for(
@@ -283,9 +290,11 @@ impl<'a, 'tcx> PlaceCapabilitySummary<'a, 'tcx> {
283290
format!(
284291
"{}/{}",
285292
output_dir,
286-
self.dot_graphs()
287-
.borrow()
288-
.relative_filename(phase, self.block(), statement_index)
293+
self.dot_graphs().unwrap().borrow().relative_filename(
294+
phase,
295+
self.block(),
296+
statement_index
297+
)
289298
)
290299
}
291300

@@ -296,19 +305,22 @@ impl<'a, 'tcx> PlaceCapabilitySummary<'a, 'tcx> {
296305
if self.block().as_usize() == 0 {
297306
assert!(!matches!(phase, DataflowStmtPhase::Join(_)));
298307
}
299-
if let Some(output_dir) = &self.dot_output_dir {
308+
if let Some(debug_data) = &self.debug_data {
300309
if phase == DataflowStmtPhase::Initial {
301-
self.dot_graphs()
310+
debug_data
311+
.dot_graphs
302312
.borrow_mut()
303313
.register_new_iteration(statement_index);
304314
}
305-
let relative_filename =
306-
self.dot_graphs()
307-
.borrow()
308-
.relative_filename(phase, self.block(), statement_index);
309-
let filename = self.dot_filename_for(&output_dir, phase, statement_index);
310-
if !self
311-
.dot_graphs()
315+
let relative_filename = debug_data.dot_graphs.borrow().relative_filename(
316+
phase,
317+
self.block(),
318+
statement_index,
319+
);
320+
let filename =
321+
self.dot_filename_for(&debug_data.dot_output_dir, phase, statement_index);
322+
if !debug_data
323+
.dot_graphs
312324
.borrow_mut()
313325
.insert(statement_index, phase, relative_filename)
314326
{
@@ -335,8 +347,7 @@ impl<'a, 'tcx> PlaceCapabilitySummary<'a, 'tcx> {
335347
pub(crate) fn new(
336348
cgx: Rc<PCGContext<'a, 'tcx>>,
337349
block: Option<BasicBlock>,
338-
dot_output_dir: Option<String>,
339-
dot_graphs: Option<Rc<RefCell<DotGraphs>>>,
350+
debug_data: Option<PCGDebugData>,
340351
) -> Self {
341352
let fpcs = FreePlaceCapabilitySummary::new(cgx.rp);
342353
let borrows =
@@ -349,8 +360,7 @@ impl<'a, 'tcx> PlaceCapabilitySummary<'a, 'tcx> {
349360
cgx,
350361
block,
351362
pcg,
352-
dot_graphs,
353-
dot_output_dir,
363+
debug_data,
354364
join_history: FxHashSet::default(),
355365
}
356366
}
@@ -438,8 +448,10 @@ impl JoinSemiLattice for PlaceCapabilitySummary<'_, '_> {
438448
}
439449
}
440450
}
441-
self.dot_graphs().borrow_mut().register_new_iteration(0);
442-
self.generate_dot_graph(DataflowStmtPhase::Join(other.block()), 0);
451+
if let Some(debug_data) = &self.debug_data {
452+
debug_data.dot_graphs.borrow_mut().register_new_iteration(0);
453+
self.generate_dot_graph(DataflowStmtPhase::Join(other.block()), 0);
454+
}
443455
fpcs || borrows
444456
}
445457
}

src/combined_pcs/engine.rs

+48-25
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ use crate::{
3434
utils::PlaceRepacker,
3535
};
3636

37-
use super::{domain::PlaceCapabilitySummary, DataflowStmtPhase, DotGraphs, EvalStmtPhase};
37+
use super::{
38+
domain::PlaceCapabilitySummary, DataflowStmtPhase, DotGraphs, EvalStmtPhase, PCGDebugData,
39+
};
3840

3941
#[rustversion::since(2024-10-14)]
4042
type OutputFacts = Box<PoloniusOutput>;
@@ -137,36 +139,59 @@ impl<'mir, 'tcx> PCGContext<'mir, 'tcx> {
137139
}
138140
}
139141

142+
struct PCGEngineDebugData {
143+
debug_output_dir: String,
144+
dot_graphs: IndexVec<BasicBlock, Rc<RefCell<DotGraphs>>>,
145+
}
146+
140147
pub struct PCGEngine<'a, 'tcx> {
141148
pub(crate) cgx: Rc<PCGContext<'a, 'tcx>>,
142149
pub(crate) fpcs: FpcsEngine<'a, 'tcx>,
143150
pub(crate) borrows: BorrowsEngine<'a, 'tcx>,
144-
debug_output_dir: Option<String>,
145-
dot_graphs: IndexVec<BasicBlock, Rc<RefCell<DotGraphs>>>,
151+
debug_data: Option<PCGEngineDebugData>,
146152
curr_block: Cell<BasicBlock>,
147153
}
148154
impl<'a, 'tcx> PCGEngine<'a, 'tcx> {
155+
fn dot_graphs(&self, block: BasicBlock) -> Option<Rc<RefCell<DotGraphs>>> {
156+
self.debug_data
157+
.as_ref()
158+
.map(|data| data.dot_graphs[block].clone())
159+
}
160+
fn debug_output_dir(&self) -> Option<String> {
161+
self.debug_data
162+
.as_ref()
163+
.map(|data| data.debug_output_dir.clone())
164+
}
149165
fn initialize(&self, state: &mut PlaceCapabilitySummary<'a, 'tcx>, block: BasicBlock) {
150166
if let Some(existing_block) = state.block {
151167
assert!(existing_block == block);
152168
return;
153169
}
154170
state.set_block(block);
155-
state.set_dot_graphs(self.dot_graphs[block].clone());
171+
if let Some(debug_data) = &self.debug_data {
172+
state.set_debug_data(
173+
debug_data.debug_output_dir.clone(),
174+
debug_data.dot_graphs[block].clone(),
175+
);
176+
}
156177
assert!(state.is_initialized());
157178
}
158179

159180
pub(crate) fn new(cgx: PCGContext<'a, 'tcx>, debug_output_dir: Option<String>) -> Self {
160-
if let Some(dir_path) = &debug_output_dir {
161-
if std::path::Path::new(dir_path).exists() {
162-
std::fs::remove_dir_all(dir_path).expect("Failed to delete directory contents");
181+
let debug_data = debug_output_dir.map(|dir_path| {
182+
if std::path::Path::new(&dir_path).exists() {
183+
std::fs::remove_dir_all(&dir_path).expect("Failed to delete directory contents");
163184
}
164185
create_dir_all(&dir_path).expect("Failed to create directory for DOT files");
165-
}
166-
let dot_graphs = IndexVec::from_fn_n(
167-
|_| Rc::new(RefCell::new(DotGraphs::new())),
168-
cgx.rp.body().basic_blocks.len(),
169-
);
186+
let dot_graphs = IndexVec::from_fn_n(
187+
|_| Rc::new(RefCell::new(DotGraphs::new())),
188+
cgx.rp.body().basic_blocks.len(),
189+
);
190+
PCGEngineDebugData {
191+
debug_output_dir: dir_path.clone(),
192+
dot_graphs,
193+
}
194+
});
170195
let fpcs = FpcsEngine(cgx.rp);
171196
let borrows = BorrowsEngine::new(
172197
cgx.rp.tcx(),
@@ -176,10 +201,9 @@ impl<'a, 'tcx> PCGEngine<'a, 'tcx> {
176201
);
177202
Self {
178203
cgx: Rc::new(cgx),
179-
dot_graphs,
180204
fpcs,
181205
borrows,
182-
debug_output_dir,
206+
debug_data,
183207
curr_block: Cell::new(START_BLOCK),
184208
}
185209
}
@@ -199,20 +223,19 @@ impl<'a, 'tcx> Analysis<'tcx> for PCGEngine<'a, 'tcx> {
199223
const NAME: &'static str = "pcs";
200224

201225
fn bottom_value(&self, body: &Body<'tcx>) -> Self::Domain {
202-
let block = self.curr_block.get();
203-
let (block, dot_graphs) = if block.as_usize() < body.basic_blocks.len() {
204-
self.curr_block.set(block.plus(1));
205-
(Some(block), Some(self.dot_graphs[block].clone()))
226+
let curr_block = self.curr_block.get();
227+
let (block, debug_data) = if curr_block.as_usize() < body.basic_blocks.len() {
228+
self.curr_block.set(curr_block.plus(1));
229+
let debug_data = self.debug_output_dir().map(|dir| PCGDebugData {
230+
dot_output_dir: dir,
231+
dot_graphs: self.dot_graphs(curr_block).unwrap(),
232+
});
233+
(Some(curr_block), debug_data)
206234
} else {
207-
// For results cursor, don't set block
235+
// For results cursor, don't set block or consider debug data
208236
(None, None)
209237
};
210-
PlaceCapabilitySummary::new(
211-
self.cgx.clone(),
212-
block,
213-
self.debug_output_dir.clone(),
214-
dot_graphs,
215-
)
238+
PlaceCapabilitySummary::new(self.cgx.clone(), block, debug_data)
216239
}
217240

218241
fn initialize_start_block(&self, _body: &Body<'tcx>, state: &mut Self::Domain) {

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ pub fn run_combined_pcs<'mir, 'tcx>(
320320
format!("{}/block_{}_iterations.json", dir_path, block.index());
321321
state
322322
.dot_graphs()
323+
.unwrap()
323324
.borrow()
324325
.write_json_file(&block_iterations_json_file);
325326
}

0 commit comments

Comments
 (0)