Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
F
flatbuffers
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
flatbuffers
Commits
4c3b6c24
Unverified
Commit
4c3b6c24
authored
Nov 01, 2018
by
Robert
Committed by
GitHub
Nov 01, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Rust: test that no heap allocs happen on hot paths (#5022)
parent
160e8f2f
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
155 additions
and
1 deletion
+155
-1
RustTest.bat
tests/RustTest.bat
+1
-0
RustTest.sh
tests/RustTest.sh
+10
-1
Cargo.toml
tests/rust_usage_test/Cargo.toml
+4
-0
alloc_check.rs
tests/rust_usage_test/bin/alloc_check.rs
+140
-0
No files found.
tests/RustTest.bat
View file @
4c3b6c24
...
@@ -19,4 +19,5 @@ rem TODO(rw): how do we make this script abort the calling script in appveyor?
...
@@ -19,4 +19,5 @@ rem TODO(rw): how do we make this script abort the calling script in appveyor?
cd rust_usage_test
cd rust_usage_test
cargo test -- --quiet || exit /b 1
cargo test -- --quiet || exit /b 1
cargo run --bin=alloc_check || exit /b 1
cd ..
cd ..
tests/RustTest.sh
View file @
4c3b6c24
#!/bin/bash
#!/bin/bash
set
-e
x
set
-e
#
#
# Copyright 2018 Google Inc. All rights reserved.
# Copyright 2018 Google Inc. All rights reserved.
#
#
...
@@ -25,4 +25,13 @@ else
...
@@ -25,4 +25,13 @@ else
exit
1
exit
1
fi
fi
cargo run
--bin
=
alloc_check
TEST_RESULT
=
$?
if
[[
$TEST_RESULT
==
0
]]
;
then
echo
"OK: Rust heap alloc test passed."
else
echo
"KO: Rust heap alloc test failed."
exit
1
fi
cargo bench
cargo bench
tests/rust_usage_test/Cargo.toml
View file @
4c3b6c24
...
@@ -10,6 +10,10 @@ flatbuffers = { path = "../../rust/flatbuffers" }
...
@@ -10,6 +10,10 @@ flatbuffers = { path = "../../rust/flatbuffers" }
name
=
"monster_example"
name
=
"monster_example"
path
=
"bin/monster_example.rs"
path
=
"bin/monster_example.rs"
[[bin]]
name
=
"alloc_check"
path
=
"bin/alloc_check.rs"
[dev-dependencies]
[dev-dependencies]
quickcheck
=
"0.6"
quickcheck
=
"0.6"
...
...
tests/rust_usage_test/bin/alloc_check.rs
0 → 100644
View file @
4c3b6c24
// define a passthrough allocator that tracks alloc calls.
// (note that we can't drop this in to the usual test suite, because it's a big
// global variable).
use
std
::
alloc
::{
GlobalAlloc
,
Layout
,
System
};
static
mut
N_ALLOCS
:
usize
=
0
;
struct
TrackingAllocator
;
impl
TrackingAllocator
{
fn
n_allocs
(
&
self
)
->
usize
{
unsafe
{
N_ALLOCS
}
}
}
unsafe
impl
GlobalAlloc
for
TrackingAllocator
{
unsafe
fn
alloc
(
&
self
,
layout
:
Layout
)
->
*
mut
u8
{
N_ALLOCS
+=
1
;
System
.alloc
(
layout
)
}
unsafe
fn
dealloc
(
&
self
,
ptr
:
*
mut
u8
,
layout
:
Layout
)
{
System
.dealloc
(
ptr
,
layout
)
}
}
// use the tracking allocator:
#[global_allocator]
static
A
:
TrackingAllocator
=
TrackingAllocator
;
// import the flatbuffers generated code:
extern
crate
flatbuffers
;
#[path
=
"../../monster_test_generated.rs"
]
mod
monster_test_generated
;
pub
use
monster_test_generated
::
my_game
;
// verbatim from the test suite:
fn
create_serialized_example_with_generated_code
(
builder
:
&
mut
flatbuffers
::
FlatBufferBuilder
)
{
let
mon
=
{
let
s0
=
builder
.create_string
(
"test1"
);
let
s1
=
builder
.create_string
(
"test2"
);
let
fred_name
=
builder
.create_string
(
"Fred"
);
// can't inline creation of this Vec3 because we refer to it by reference, so it must live
// long enough to be used by MonsterArgs.
let
pos
=
my_game
::
example
::
Vec3
::
new
(
1.0
,
2.0
,
3.0
,
3.0
,
my_game
::
example
::
Color
::
Green
,
&
my_game
::
example
::
Test
::
new
(
5i16
,
6i8
));
let
args
=
my_game
::
example
::
MonsterArgs
{
hp
:
80
,
mana
:
150
,
name
:
Some
(
builder
.create_string
(
"MyMonster"
)),
pos
:
Some
(
&
pos
),
test_type
:
my_game
::
example
::
Any
::
Monster
,
test
:
Some
(
my_game
::
example
::
Monster
::
create
(
builder
,
&
my_game
::
example
::
MonsterArgs
{
name
:
Some
(
fred_name
),
..
Default
::
default
()
})
.as_union_value
()),
inventory
:
Some
(
builder
.create_vector_direct
(
&
[
0u8
,
1
,
2
,
3
,
4
][
..
])),
test4
:
Some
(
builder
.create_vector_direct
(
&
[
my_game
::
example
::
Test
::
new
(
10
,
20
),
my_game
::
example
::
Test
::
new
(
30
,
40
)])),
testarrayofstring
:
Some
(
builder
.create_vector
(
&
[
s0
,
s1
])),
..
Default
::
default
()
};
my_game
::
example
::
Monster
::
create
(
builder
,
&
args
)
};
my_game
::
example
::
finish_monster_buffer
(
builder
,
mon
);
}
fn
main
()
{
// test the allocation tracking:
{
let
before
=
A
.n_allocs
();
let
_x
:
Vec
<
u8
>
=
vec!
[
0u8
;
1
];
let
after
=
A
.n_allocs
();
assert_eq!
(
before
+
1
,
after
);
}
let
builder
=
&
mut
flatbuffers
::
FlatBufferBuilder
::
new
();
{
// warm up the builder (it can make small allocs internally, such as for storing vtables):
create_serialized_example_with_generated_code
(
builder
);
}
// reset the builder, clearing its heap-allocted memory:
builder
.reset
();
{
let
before
=
A
.n_allocs
();
create_serialized_example_with_generated_code
(
builder
);
let
after
=
A
.n_allocs
();
assert_eq!
(
before
,
after
,
"KO: Heap allocs occurred in Rust write path"
);
}
let
buf
=
builder
.finished_data
();
// use the allocation tracking on the read path:
{
let
before
=
A
.n_allocs
();
// do many reads, forcing them to execute by using assert_eq:
{
let
m
=
my_game
::
example
::
get_root_as_monster
(
buf
);
assert_eq!
(
80
,
m
.hp
());
assert_eq!
(
150
,
m
.mana
());
assert_eq!
(
"MyMonster"
,
m
.name
());
let
pos
=
m
.pos
()
.unwrap
();
assert_eq!
(
pos
.x
(),
1.0f32
);
assert_eq!
(
pos
.y
(),
2.0f32
);
assert_eq!
(
pos
.z
(),
3.0f32
);
assert_eq!
(
pos
.test1
(),
3.0f64
);
assert_eq!
(
pos
.test2
(),
my_game
::
example
::
Color
::
Green
);
let
pos_test3
=
pos
.test3
();
assert_eq!
(
pos_test3
.a
(),
5i16
);
assert_eq!
(
pos_test3
.b
(),
6i8
);
assert_eq!
(
m
.test_type
(),
my_game
::
example
::
Any
::
Monster
);
let
table2
=
m
.test
()
.unwrap
();
let
m2
=
my_game
::
example
::
Monster
::
init_from_table
(
table2
);
assert_eq!
(
m2
.name
(),
"Fred"
);
let
inv
=
m
.inventory
()
.unwrap
();
assert_eq!
(
inv
.len
(),
5
);
assert_eq!
(
inv
.iter
()
.sum
::
<
u8
>
(),
10u8
);
let
test4
=
m
.test4
()
.unwrap
();
assert_eq!
(
test4
.len
(),
2
);
assert_eq!
(
test4
[
0
]
.a
()
as
i32
+
test4
[
0
]
.b
()
as
i32
+
test4
[
1
]
.a
()
as
i32
+
test4
[
1
]
.b
()
as
i32
,
100
);
let
testarrayofstring
=
m
.testarrayofstring
()
.unwrap
();
assert_eq!
(
testarrayofstring
.len
(),
2
);
assert_eq!
(
testarrayofstring
.get
(
0
),
"test1"
);
assert_eq!
(
testarrayofstring
.get
(
1
),
"test2"
);
}
// assert that no allocs occurred:
let
after
=
A
.n_allocs
();
assert_eq!
(
before
,
after
,
"KO: Heap allocs occurred in Rust read path"
);
}
println!
(
"Rust: Heap alloc checks completed successfully"
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment