Skip to content

Commit e65792d

Browse files
celinvaltedinski
authored andcommitted
Minimize IRep Serialization memory consumption (rust-lang#621)
* Use serde to serialize irep to reduce mem consumption This change allow us to serialize the irep without having to buffer the entire json in memory. I'm not removing the old code yet because this new logic is slower and still need some prunning. * Add a BufWriter to speed up serialization. * Address PR comments - Add more test coverage. - Added utility function.
1 parent 70efafa commit e65792d

File tree

7 files changed

+280
-13
lines changed

7 files changed

+280
-13
lines changed

Cargo.lock

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,8 @@ dependencies = [
501501
"rustc_session",
502502
"rustc_span",
503503
"rustc_target",
504+
"serde",
505+
"serde_test",
504506
"smallvec",
505507
"snap",
506508
"tracing",
@@ -3873,6 +3875,8 @@ dependencies = [
38733875
"rustc_session",
38743876
"rustc_span",
38753877
"rustc_target",
3878+
"serde",
3879+
"serde_json",
38763880
"smallvec",
38773881
"snap",
38783882
"tracing",
@@ -5006,6 +5010,15 @@ dependencies = [
50065010
"syn",
50075011
]
50085012

5013+
[[package]]
5014+
name = "serde_test"
5015+
version = "1.0.130"
5016+
source = "registry+https://github.com/rust-lang/crates.io-index"
5017+
checksum = "d82178225dbdeae2d5d190e8649287db6a3a32c6d24da22ae3146325aa353e4c"
5018+
dependencies = [
5019+
"serde",
5020+
]
5021+
50095022
[[package]]
50105023
name = "sha-1"
50115024
version = "0.8.2"

compiler/cbmc/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ cstr = "0.2"
1616
libc = "0.2"
1717
measureme = "9.1.0"
1818
num = "0.4.0"
19+
serde = {version = "1", features = ["derive"]}
1920
snap = "1"
2021
tracing = "0.1"
2122
rustc_middle = { path = "../rustc_middle" }
@@ -36,3 +37,6 @@ rustc_target = { path = "../rustc_target" }
3637
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
3738
rustc_ast = { path = "../rustc_ast" }
3839
rustc_span = { path = "../rustc_span" }
40+
41+
[dev-dependencies]
42+
serde_test = "1"

compiler/cbmc/src/irep/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
1717
mod irep;
1818
mod irep_id;
19+
pub mod serialize;
1920
mod symbol;
2021
mod symbol_table;
2122
mod to_irep;

compiler/cbmc/src/irep/serialize.rs

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
//! This crate implements irep serialization using serde Serializer.
4+
use crate::irep::{Irep, IrepId, Symbol, SymbolTable};
5+
use serde::ser::{SerializeMap, Serializer};
6+
use serde::Serialize;
7+
8+
impl Serialize for Irep {
9+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
10+
where
11+
S: Serializer,
12+
{
13+
let mut obj = serializer.serialize_map(None)?;
14+
obj.serialize_entry("id", &self.id)?;
15+
if !self.sub.is_empty() {
16+
obj.serialize_entry("sub", &self.sub)?;
17+
}
18+
if !self.named_sub.is_empty() {
19+
obj.serialize_entry("namedSub", &self.named_sub)?;
20+
}
21+
obj.end()
22+
}
23+
}
24+
25+
impl Serialize for IrepId {
26+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
27+
where
28+
S: Serializer,
29+
{
30+
self.to_string().serialize(serializer)
31+
}
32+
}
33+
34+
impl Serialize for SymbolTable {
35+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
36+
where
37+
S: Serializer,
38+
{
39+
let mut obj = serializer.serialize_map(None)?;
40+
obj.serialize_entry("symbolTable", &self.symbol_table)?;
41+
obj.end()
42+
}
43+
}
44+
45+
impl Serialize for Symbol {
46+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
47+
where
48+
S: Serializer,
49+
{
50+
let mut obj = serializer.serialize_map(None)?;
51+
obj.serialize_entry(&IrepId::Type.to_string(), &self.typ)?;
52+
obj.serialize_entry(&IrepId::Value.to_string(), &self.value)?;
53+
obj.serialize_entry("location", &self.location)?;
54+
obj.serialize_entry(&IrepId::Name.to_string(), &self.name)?;
55+
obj.serialize_entry(&IrepId::Module.to_string(), &self.module)?;
56+
obj.serialize_entry("baseName", &self.base_name)?;
57+
obj.serialize_entry("prettyName", &self.pretty_name)?;
58+
obj.serialize_entry(&IrepId::Mode.to_string(), &self.mode)?;
59+
obj.serialize_entry("isType", &self.is_type)?;
60+
obj.serialize_entry("isMacro", &self.is_macro)?;
61+
obj.serialize_entry("isExported", &self.is_exported)?;
62+
obj.serialize_entry("isInput", &self.is_input)?;
63+
obj.serialize_entry("isOutput", &self.is_output)?;
64+
obj.serialize_entry("isStateVar", &self.is_state_var)?;
65+
obj.serialize_entry("isProperty", &self.is_property)?;
66+
obj.serialize_entry("isStaticLifetime", &self.is_static_lifetime)?;
67+
obj.serialize_entry("isThreadLocal", &self.is_thread_local)?;
68+
obj.serialize_entry("isLvalue", &self.is_lvalue)?;
69+
obj.serialize_entry("isFileLocal", &self.is_file_local)?;
70+
obj.serialize_entry("isExtern", &self.is_extern)?;
71+
obj.serialize_entry("isVolatile", &self.is_volatile)?;
72+
obj.serialize_entry("isParameter", &self.is_parameter)?;
73+
obj.serialize_entry("isAuxiliary", &self.is_auxiliary)?;
74+
obj.serialize_entry("isWeak", &self.is_weak)?;
75+
76+
obj.end()
77+
}
78+
}
79+
80+
#[cfg(test)]
81+
mod test {
82+
use super::*;
83+
use serde_test::{assert_ser_tokens, Token};
84+
#[test]
85+
fn serialize_irep() {
86+
let irep = Irep::empty();
87+
assert_ser_tokens(
88+
&irep,
89+
&[Token::Map { len: None }, Token::String("id"), Token::String("empty"), Token::MapEnd],
90+
);
91+
}
92+
93+
#[test]
94+
fn serialize_sym_table() {
95+
let mut sym_table = SymbolTable::new();
96+
let symbol = Symbol {
97+
typ: Irep::empty(),
98+
value: Irep::empty(),
99+
location: Irep::empty(),
100+
name: String::from("my_name"),
101+
module: String::new(),
102+
base_name: String::new(),
103+
pretty_name: String::new(),
104+
mode: String::new(),
105+
is_type: false,
106+
is_macro: false,
107+
is_exported: false,
108+
is_input: false,
109+
is_output: false,
110+
is_state_var: false,
111+
is_property: false,
112+
113+
// ansi-C properties
114+
is_static_lifetime: false,
115+
is_thread_local: false,
116+
is_lvalue: false,
117+
is_file_local: false,
118+
is_extern: false,
119+
is_volatile: false,
120+
is_parameter: false,
121+
is_auxiliary: false,
122+
is_weak: false,
123+
};
124+
sym_table.insert(symbol.clone());
125+
assert_ser_tokens(
126+
&sym_table,
127+
&[
128+
Token::Map { len: None },
129+
Token::String("symbolTable"),
130+
Token::Map { len: Some(1) },
131+
Token::String("my_name"),
132+
// symbol start
133+
Token::Map { len: None },
134+
// type irep
135+
Token::String("type"),
136+
Token::Map { len: None },
137+
Token::String("id"),
138+
Token::String("empty"),
139+
Token::MapEnd,
140+
// value irep
141+
Token::String("value"),
142+
Token::Map { len: None },
143+
Token::String("id"),
144+
Token::String("empty"),
145+
Token::MapEnd,
146+
// value locaton
147+
Token::String("location"),
148+
Token::Map { len: None },
149+
Token::String("id"),
150+
Token::String("empty"),
151+
Token::MapEnd,
152+
Token::String("name"),
153+
Token::String("my_name"),
154+
Token::String("module"),
155+
Token::String(""),
156+
Token::String("baseName"),
157+
Token::String(""),
158+
Token::String("prettyName"),
159+
Token::String(""),
160+
Token::String("mode"),
161+
Token::String(""),
162+
Token::String("isType"),
163+
Token::Bool(false),
164+
Token::String("isMacro"),
165+
Token::Bool(false),
166+
Token::String("isExported"),
167+
Token::Bool(false),
168+
Token::String("isInput"),
169+
Token::Bool(false),
170+
Token::String("isOutput"),
171+
Token::Bool(false),
172+
Token::String("isStateVar"),
173+
Token::Bool(false),
174+
Token::String("isProperty"),
175+
Token::Bool(false),
176+
Token::String("isStaticLifetime"),
177+
Token::Bool(false),
178+
Token::String("isThreadLocal"),
179+
Token::Bool(false),
180+
Token::String("isLvalue"),
181+
Token::Bool(false),
182+
Token::String("isFileLocal"),
183+
Token::Bool(false),
184+
Token::String("isExtern"),
185+
Token::Bool(false),
186+
Token::String("isVolatile"),
187+
Token::Bool(false),
188+
Token::String("isParameter"),
189+
Token::Bool(false),
190+
Token::String("isAuxiliary"),
191+
Token::Bool(false),
192+
Token::String("isWeak"),
193+
Token::Bool(false),
194+
Token::MapEnd,
195+
Token::MapEnd,
196+
Token::MapEnd,
197+
],
198+
);
199+
}
200+
201+
#[test]
202+
fn serialize_irep_sub() {
203+
let empty_irep = Irep::empty();
204+
let one_irep = Irep::one();
205+
let sub_irep = Irep::just_sub(vec![empty_irep.clone(), one_irep]);
206+
let top_irep = Irep::just_sub(vec![sub_irep, empty_irep]);
207+
assert_ser_tokens(
208+
&top_irep,
209+
&[
210+
// top_irep
211+
Token::Map { len: None },
212+
Token::String("id"),
213+
Token::String(""),
214+
Token::String("sub"),
215+
Token::Seq { len: Some(2) },
216+
// sub_irep
217+
Token::Map { len: None },
218+
Token::String("id"),
219+
Token::String(""),
220+
Token::String("sub"),
221+
Token::Seq { len: Some(2) },
222+
// empty_irep
223+
Token::Map { len: None },
224+
Token::String("id"),
225+
Token::String("empty"),
226+
Token::MapEnd,
227+
// one_irep
228+
Token::Map { len: None },
229+
Token::String("id"),
230+
Token::String("1"),
231+
Token::MapEnd,
232+
Token::SeqEnd,
233+
Token::MapEnd,
234+
// empty_irep
235+
Token::Map { len: None },
236+
Token::String("id"),
237+
Token::String("empty"),
238+
Token::MapEnd,
239+
Token::SeqEnd,
240+
Token::MapEnd,
241+
],
242+
);
243+
}
244+
}

compiler/cbmc/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@ pub mod goto_program;
3030
pub mod irep;
3131
mod machine_model;
3232
pub mod utils;
33+
pub use irep::serialize;
3334
pub use machine_model::{MachineModel, RoundingMode};

compiler/rustc_codegen_rmc/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ cstr = "0.2"
1717
libc = "0.2"
1818
measureme = "9.1.0"
1919
num = "0.4.0"
20+
serde = "1"
21+
serde_json = "1"
2022
snap = "1"
2123
tracing = "0.1"
2224
rustc_middle = { path = "../rustc_middle" }

compiler/rustc_codegen_rmc/src/compiler_interface.rs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@ use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
1616
use rustc_middle::mir::mono::{CodegenUnit, MonoItem};
1717
use rustc_middle::ty::query::Providers;
1818
use rustc_middle::ty::{self, TyCtxt};
19-
use rustc_serialize::json::ToJson;
2019
use rustc_session::config::{OutputFilenames, OutputType};
2120
use rustc_session::cstore::MetadataLoaderDyn;
2221
use rustc_session::Session;
2322
use std::collections::BTreeMap;
23+
use std::io::BufWriter;
2424
use std::iter::FromIterator;
25+
use std::path::PathBuf;
2526
use tracing::{debug, warn};
2627

2728
// #[derive(RustcEncodable, RustcDecodable)]
@@ -150,8 +151,6 @@ impl CodegenBackend for GotocCodegenBackend {
150151
codegen_results: Box<dyn Any>,
151152
outputs: &OutputFilenames,
152153
) -> Result<(), ErrorReported> {
153-
use std::io::Write;
154-
155154
let result = codegen_results
156155
.downcast::<GotocCodegenResult>()
157156
.expect("in link: codegen_results is not a GotocCodegenResult");
@@ -160,18 +159,21 @@ impl CodegenBackend for GotocCodegenBackend {
160159
if !sess.opts.debugging_opts.no_codegen && sess.opts.output_types.should_codegen() {
161160
// "path.o"
162161
let base_filename = outputs.path(OutputType::Object);
163-
164-
let symtab_filename = base_filename.with_extension("symtab.json");
165-
debug!("output to {:?}", symtab_filename);
166-
let mut out_file = ::std::fs::File::create(&symtab_filename).unwrap();
167-
write!(out_file, "{}", result.symtab.to_irep().to_json().pretty().to_string()).unwrap();
168-
169-
let type_map_filename = base_filename.with_extension("type_map.json");
170-
debug!("type_map to {:?}", type_map_filename);
171-
let mut out_file = ::std::fs::File::create(&type_map_filename).unwrap();
172-
write!(out_file, "{}", result.type_map.to_json().pretty().to_string()).unwrap();
162+
write_file(&base_filename, "symtab.json", &result.symtab.to_irep());
163+
write_file(&base_filename, "type_map.json", &result.type_map);
173164
}
174165

175166
Ok(())
176167
}
177168
}
169+
170+
fn write_file<T>(base_filename: &PathBuf, extension: &str, source: &T)
171+
where
172+
T: serde::Serialize,
173+
{
174+
let filename = base_filename.with_extension(extension);
175+
debug!("output to {:?}", filename);
176+
let out_file = ::std::fs::File::create(&filename).unwrap();
177+
let writer = BufWriter::new(out_file);
178+
serde_json::to_writer(writer, &source).unwrap();
179+
}

0 commit comments

Comments
 (0)