Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
C
capnproto
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
capnproto
Commits
7b187dbd
Commit
7b187dbd
authored
Mar 28, 2013
by
Kenton Varda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
More benchmark updates, delete unused descriptor code.
parent
4dd3161d
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
251 additions
and
480 deletions
+251
-480
capnproto-carsales.c++
c++/src/capnproto/benchmark/capnproto-carsales.c++
+2
-0
capnproto-common.h
c++/src/capnproto/benchmark/capnproto-common.h
+6
-0
common.h
c++/src/capnproto/benchmark/common.h
+2
-0
null-carsales.c++
c++/src/capnproto/benchmark/null-carsales.c++
+46
-27
null-common.h
c++/src/capnproto/benchmark/null-common.h
+32
-19
protobuf-carsales.c++
c++/src/capnproto/benchmark/protobuf-carsales.c++
+2
-0
protobuf-common.h
c++/src/capnproto/benchmark/protobuf-common.h
+8
-0
runner.c++
c++/src/capnproto/benchmark/runner.c++
+77
-50
descriptor-test.c++
c++/src/capnproto/descriptor-test.c++
+0
-72
descriptor.c++
c++/src/capnproto/descriptor.c++
+0
-30
descriptor.h
c++/src/capnproto/descriptor.h
+0
-273
generated-header-support.h
c++/src/capnproto/generated-header-support.h
+0
-2
list.h
c++/src/capnproto/list.h
+0
-1
wire-format-test.c++
c++/src/capnproto/wire-format-test.c++
+0
-1
wire-format.c++
c++/src/capnproto/wire-format.c++
+0
-1
wire-format.h
c++/src/capnproto/wire-format.h
+76
-4
No files found.
c++/src/capnproto/benchmark/capnproto-carsales.c++
View file @
7b187dbd
...
@@ -93,6 +93,8 @@ void randomCar(Car::Builder car) {
...
@@ -93,6 +93,8 @@ void randomCar(Car::Builder car) {
engine
.
setHorsepower
(
100
*
fastRand
(
400
));
engine
.
setHorsepower
(
100
*
fastRand
(
400
));
engine
.
setCylinders
(
4
+
2
*
fastRand
(
3
));
engine
.
setCylinders
(
4
+
2
*
fastRand
(
3
));
engine
.
setCc
(
800
+
fastRand
(
10000
));
engine
.
setCc
(
800
+
fastRand
(
10000
));
engine
.
setUsesGas
(
true
);
engine
.
setUsesElectric
(
fastRand
(
2
));
car
.
setFuelCapacity
(
10.0
+
fastRandDouble
(
30.0
));
car
.
setFuelCapacity
(
10.0
+
fastRandDouble
(
30.0
));
car
.
setFuelLevel
(
fastRandDouble
(
car
.
getFuelCapacity
()));
car
.
setFuelLevel
(
fastRandDouble
(
car
.
getFuelCapacity
()));
...
...
c++/src/capnproto/benchmark/capnproto-common.h
View file @
7b187dbd
...
@@ -27,7 +27,9 @@
...
@@ -27,7 +27,9 @@
#include "common.h"
#include "common.h"
#include <capnproto/serialize.h>
#include <capnproto/serialize.h>
#include <capnproto/serialize-packed.h>
#include <capnproto/serialize-packed.h>
#if HAVE_SNAPPY
#include <capnproto/serialize-snappy.h>
#include <capnproto/serialize-snappy.h>
#endif // HAVE_SNAPPY
#include <thread>
#include <thread>
namespace
capnproto
{
namespace
capnproto
{
...
@@ -96,6 +98,7 @@ struct Packed {
...
@@ -96,6 +98,7 @@ struct Packed {
}
}
};
};
#if HAVE_SNAPPY
static
byte
snappyReadBuffer
[
SNAPPY_BUFFER_SIZE
];
static
byte
snappyReadBuffer
[
SNAPPY_BUFFER_SIZE
];
static
byte
snappyWriteBuffer
[
SNAPPY_BUFFER_SIZE
];
static
byte
snappyWriteBuffer
[
SNAPPY_BUFFER_SIZE
];
static
byte
snappyCompressedBuffer
[
SNAPPY_COMPRESSED_BUFFER_SIZE
];
static
byte
snappyCompressedBuffer
[
SNAPPY_COMPRESSED_BUFFER_SIZE
];
...
@@ -120,6 +123,7 @@ struct SnappyCompressed {
...
@@ -120,6 +123,7 @@ struct SnappyCompressed {
arrayPtr
(
snappyCompressedBuffer
,
SNAPPY_COMPRESSED_BUFFER_SIZE
));
arrayPtr
(
snappyCompressedBuffer
,
SNAPPY_COMPRESSED_BUFFER_SIZE
));
}
}
};
};
#endif // HAVE_SNAPPY
// =======================================================================================
// =======================================================================================
...
@@ -395,7 +399,9 @@ struct BenchmarkMethods {
...
@@ -395,7 +399,9 @@ struct BenchmarkMethods {
struct
BenchmarkTypes
{
struct
BenchmarkTypes
{
typedef
capnp
::
Uncompressed
Uncompressed
;
typedef
capnp
::
Uncompressed
Uncompressed
;
typedef
capnp
::
Packed
Packed
;
typedef
capnp
::
Packed
Packed
;
#if HAVE_SNAPPY
typedef
capnp
::
SnappyCompressed
SnappyCompressed
;
typedef
capnp
::
SnappyCompressed
SnappyCompressed
;
#endif // HAVE_SNAPPY
typedef
capnp
::
UseScratch
ReusableResources
;
typedef
capnp
::
UseScratch
ReusableResources
;
typedef
capnp
::
NoScratch
SingleUseResources
;
typedef
capnp
::
NoScratch
SingleUseResources
;
...
...
c++/src/capnproto/benchmark/common.h
View file @
7b187dbd
...
@@ -254,9 +254,11 @@ uint64_t doBenchmark3(const std::string& mode, const std::string& reuse,
...
@@ -254,9 +254,11 @@ uint64_t doBenchmark3(const std::string& mode, const std::string& reuse,
}
else
if
(
compression
==
"packed"
)
{
}
else
if
(
compression
==
"packed"
)
{
return
doBenchmark2
<
BenchmarkTypes
,
TestCase
,
typename
BenchmarkTypes
::
Packed
>
(
return
doBenchmark2
<
BenchmarkTypes
,
TestCase
,
typename
BenchmarkTypes
::
Packed
>
(
mode
,
reuse
,
iters
);
mode
,
reuse
,
iters
);
#if HAVE_SNAPPY
}
else
if
(
compression
==
"snappy"
)
{
}
else
if
(
compression
==
"snappy"
)
{
return
doBenchmark2
<
BenchmarkTypes
,
TestCase
,
typename
BenchmarkTypes
::
SnappyCompressed
>
(
return
doBenchmark2
<
BenchmarkTypes
,
TestCase
,
typename
BenchmarkTypes
::
SnappyCompressed
>
(
mode
,
reuse
,
iters
);
mode
,
reuse
,
iters
);
#endif // HAVE_SNAPPY
}
else
{
}
else
{
fprintf
(
stderr
,
"Unknown compression mode: %s
\n
"
,
compression
.
c_str
());
fprintf
(
stderr
,
"Unknown compression mode: %s
\n
"
,
compression
.
c_str
());
exit
(
1
);
exit
(
1
);
...
...
c++/src/capnproto/benchmark/null-carsales.c++
View file @
7b187dbd
...
@@ -27,7 +27,7 @@ namespace capnproto {
...
@@ -27,7 +27,7 @@ namespace capnproto {
namespace
benchmark
{
namespace
benchmark
{
namespace
null
{
namespace
null
{
enum
class
Color
{
enum
class
Color
:
uint8_t
{
BLACK
,
BLACK
,
WHITE
,
WHITE
,
RED
,
RED
,
...
@@ -41,38 +41,55 @@ enum class Color {
...
@@ -41,38 +41,55 @@ enum class Color {
constexpr
uint
COLOR_RANGE
=
static_cast
<
uint
>
(
Color
::
SILVER
)
+
1
;
constexpr
uint
COLOR_RANGE
=
static_cast
<
uint
>
(
Color
::
SILVER
)
+
1
;
struct
Wheel
{
struct
Wheel
{
uint16_t
diameter
;
float
airPressure
;
float
airPressure
;
uint16_t
diameter
;
bool
snowTires
;
bool
snowTires
;
};
};
struct
Engine
{
struct
Engine
{
uint32_t
cc
;
uint16_t
horsepower
;
uint16_t
horsepower
;
uint8_t
cylinders
;
uint8_t
cylinders
;
uint32_t
cc
;
uint8_t
bits
;
bool
usesGas
;
inline
bool
usesGas
()
const
{
return
bits
&
1
;
}
bool
usesElectric
;
inline
bool
usesElectric
()
const
{
return
bits
&
2
;
}
inline
void
setBits
(
bool
usesGas
,
bool
usesElectric
)
{
bits
=
(
uint8_t
)
usesGas
|
((
uint8_t
)
usesElectric
<<
1
);
}
};
};
struct
Car
{
struct
Car
{
// SORT FIELDS BY SIZE since we need "theoretical best" memory usage
Engine
engine
;
List
<
Wheel
>
wheels
;
const
char
*
make
;
const
char
*
make
;
const
char
*
model
;
const
char
*
model
;
Color
color
;
float
fuelCapacity
;
uint8_t
seats
;
float
fuelLevel
;
uint8_t
doors
;
uint32_t
weight
;
List
<
Wheel
>
wheels
;
uint16_t
length
;
uint16_t
length
;
uint16_t
width
;
uint16_t
width
;
uint16_t
height
;
uint16_t
height
;
uint32_t
weight
;
Color
color
;
Engine
engine
;
uint8_t
seats
;
float
fuelCapacity
;
uint8_t
doors
;
float
fuelLevel
;
bool
hasPowerWindows
;
bool
hasPowerSteering
;
bool
hasCruiseControl
;
uint8_t
cupHolders
;
uint8_t
cupHolders
;
bool
hasNavSystem
;
uint8_t
bits
;
inline
bool
hasPowerWindows
()
const
{
return
bits
&
1
;
}
inline
bool
hasPowerSteering
()
const
{
return
bits
&
2
;
}
inline
bool
hasCruiseControl
()
const
{
return
bits
&
4
;
}
inline
bool
hasNavSystem
()
const
{
return
bits
&
8
;
}
inline
void
setBits
(
bool
hasPowerWindows
,
bool
hasPowerSteering
,
bool
hasCruiseControl
,
bool
hasNavSystem
)
{
bits
=
(
uint8_t
)
hasPowerWindows
|
((
uint8_t
)
hasPowerSteering
<<
1
)
|
((
uint8_t
)
hasCruiseControl
<<
2
)
|
((
uint8_t
)
hasNavSystem
<<
3
);
}
};
};
...
@@ -92,8 +109,8 @@ uint64_t carValue(const Car& car) {
...
@@ -92,8 +109,8 @@ uint64_t carValue(const Car& car) {
auto
engine
=
car
.
engine
;
auto
engine
=
car
.
engine
;
result
+=
engine
.
horsepower
*
40
;
result
+=
engine
.
horsepower
*
40
;
if
(
engine
.
usesElectric
)
{
if
(
engine
.
usesElectric
()
)
{
if
(
engine
.
usesGas
)
{
if
(
engine
.
usesGas
()
)
{
// hybrid
// hybrid
result
+=
5000
;
result
+=
5000
;
}
else
{
}
else
{
...
@@ -101,10 +118,10 @@ uint64_t carValue(const Car& car) {
...
@@ -101,10 +118,10 @@ uint64_t carValue(const Car& car) {
}
}
}
}
result
+=
car
.
hasPowerWindows
?
100
:
0
;
result
+=
car
.
hasPowerWindows
()
?
100
:
0
;
result
+=
car
.
hasPowerSteering
?
200
:
0
;
result
+=
car
.
hasPowerSteering
()
?
200
:
0
;
result
+=
car
.
hasCruiseControl
?
400
:
0
;
result
+=
car
.
hasCruiseControl
()
?
400
:
0
;
result
+=
car
.
hasNavSystem
?
2000
:
0
;
result
+=
car
.
hasNavSystem
()
?
2000
:
0
;
result
+=
car
.
cupHolders
*
25
;
result
+=
car
.
cupHolders
*
25
;
...
@@ -138,14 +155,16 @@ void randomCar(Car* car) {
...
@@ -138,14 +155,16 @@ void randomCar(Car* car) {
car
->
engine
.
horsepower
=
100
*
fastRand
(
400
);
car
->
engine
.
horsepower
=
100
*
fastRand
(
400
);
car
->
engine
.
cylinders
=
4
+
2
*
fastRand
(
3
);
car
->
engine
.
cylinders
=
4
+
2
*
fastRand
(
3
);
car
->
engine
.
cc
=
800
+
fastRand
(
10000
);
car
->
engine
.
cc
=
800
+
fastRand
(
10000
);
car
->
engine
.
setBits
(
true
,
fastRand
(
2
));
car
->
fuelCapacity
=
10.0
+
fastRandDouble
(
30.0
);
car
->
fuelCapacity
=
10.0
+
fastRandDouble
(
30.0
);
car
->
fuelLevel
=
fastRandDouble
(
car
->
fuelCapacity
);
car
->
fuelLevel
=
fastRandDouble
(
car
->
fuelCapacity
);
car
->
hasPowerWindows
=
fastRand
(
2
);
bool
hasPowerWindows
=
fastRand
(
2
);
car
->
hasPowerSteering
=
fastRand
(
2
);
bool
hasPowerSteering
=
fastRand
(
2
);
car
->
hasCruiseControl
=
fastRand
(
2
);
bool
hasCruiseControl
=
fastRand
(
2
);
car
->
cupHolders
=
fastRand
(
12
);
car
->
cupHolders
=
fastRand
(
12
);
car
->
hasNavSystem
=
fastRand
(
2
);
bool
hasNavSystem
=
fastRand
(
2
);
car
->
setBits
(
hasPowerWindows
,
hasPowerSteering
,
hasCruiseControl
,
hasNavSystem
);
}
}
class
CarSalesTestCase
{
class
CarSalesTestCase
{
...
...
c++/src/capnproto/benchmark/null-common.h
View file @
7b187dbd
...
@@ -65,24 +65,35 @@ struct List {
...
@@ -65,24 +65,35 @@ struct List {
// =======================================================================================
// =======================================================================================
struct
SingleUseObjects
{
struct
SingleUseObjects
{
template
<
typename
ObjectType
>
class
ObjectSizeCounter
{
struct
Object
{
public
:
struct
Reusable
{};
ObjectSizeCounter
(
uint64_t
iters
)
:
counter
(
0
)
{}
struct
SingleUse
{
ObjectType
value
;
void
add
(
uint64_t
wordCount
)
{
inline
SingleUse
(
Reusable
&
)
{}
counter
+=
wordCount
;
};
}
uint64_t
get
()
{
return
counter
;
}
private
:
uint64_t
counter
;
};
};
};
};
struct
ReusableObjects
{
struct
ReusableObjects
{
template
<
typename
ObjectType
>
class
ObjectSizeCounter
{
struct
Object
{
public
:
typedef
ObjectType
Reusable
;
ObjectSizeCounter
(
uint64_t
iters
)
:
iters
(
iters
),
maxSize
(
0
)
{}
struct
SingleUse
{
ObjectType
&
value
;
void
add
(
size_t
wordCount
)
{
inline
SingleUse
(
Reusable
&
reusable
)
:
value
(
reusable
)
{}
maxSize
=
std
::
max
(
wordCount
,
maxSize
);
};
}
uint64_t
get
()
{
return
iters
*
maxSize
;
}
private
:
uint64_t
iters
;
size_t
maxSize
;
};
};
};
};
...
@@ -120,7 +131,7 @@ struct BenchmarkMethods {
...
@@ -120,7 +131,7 @@ struct BenchmarkMethods {
}
}
static
uint64_t
passByObject
(
uint64_t
iters
,
bool
countObjectSize
)
{
static
uint64_t
passByObject
(
uint64_t
iters
,
bool
countObjectSize
)
{
uint64_t
throughput
=
0
;
typename
ReuseStrategy
::
ObjectSizeCounter
sizeCounter
(
iters
)
;
for
(;
iters
>
0
;
--
iters
)
{
for
(;
iters
>
0
;
--
iters
)
{
arenaPos
=
arena
;
arenaPos
=
arena
;
...
@@ -134,10 +145,10 @@ struct BenchmarkMethods {
...
@@ -134,10 +145,10 @@ struct BenchmarkMethods {
throw
std
::
logic_error
(
"Incorrect response."
);
throw
std
::
logic_error
(
"Incorrect response."
);
}
}
throughput
+=
(
arenaPos
-
arena
)
*
sizeof
(
arena
[
0
]
);
sizeCounter
.
add
((
arenaPos
-
arena
)
*
sizeof
(
arena
[
0
])
);
}
}
return
throughput
;
return
sizeCounter
.
get
()
;
}
}
static
uint64_t
passByBytes
(
uint64_t
iters
)
{
static
uint64_t
passByBytes
(
uint64_t
iters
)
{
...
@@ -149,10 +160,12 @@ struct BenchmarkMethods {
...
@@ -149,10 +160,12 @@ struct BenchmarkMethods {
struct
BenchmarkTypes
{
struct
BenchmarkTypes
{
typedef
void
Uncompressed
;
typedef
void
Uncompressed
;
typedef
void
Packed
;
typedef
void
Packed
;
#if HAVE_SNAPPY
typedef
void
SnappyCompressed
;
typedef
void
SnappyCompressed
;
#endif // HAVE_SNAPPY
typedef
void
ReusableResources
;
typedef
ReusableObjects
ReusableResources
;
typedef
void
SingleUseResources
;
typedef
SingleUseObjects
SingleUseResources
;
template
<
typename
TestCase
,
typename
ReuseStrategy
,
typename
Compression
>
template
<
typename
TestCase
,
typename
ReuseStrategy
,
typename
Compression
>
struct
BenchmarkMethods
:
public
null
::
BenchmarkMethods
<
TestCase
,
ReuseStrategy
,
Compression
>
{};
struct
BenchmarkMethods
:
public
null
::
BenchmarkMethods
<
TestCase
,
ReuseStrategy
,
Compression
>
{};
...
...
c++/src/capnproto/benchmark/protobuf-carsales.c++
View file @
7b187dbd
...
@@ -92,6 +92,8 @@ void randomCar(Car* car) {
...
@@ -92,6 +92,8 @@ void randomCar(Car* car) {
engine
->
set_horsepower
(
100
*
fastRand
(
400
));
engine
->
set_horsepower
(
100
*
fastRand
(
400
));
engine
->
set_cylinders
(
4
+
2
*
fastRand
(
3
));
engine
->
set_cylinders
(
4
+
2
*
fastRand
(
3
));
engine
->
set_cc
(
800
+
fastRand
(
10000
));
engine
->
set_cc
(
800
+
fastRand
(
10000
));
engine
->
set_uses_gas
(
true
);
engine
->
set_uses_electric
(
fastRand
(
2
));
car
->
set_fuel_capacity
(
10.0
+
fastRandDouble
(
30.0
));
car
->
set_fuel_capacity
(
10.0
+
fastRandDouble
(
30.0
));
car
->
set_fuel_level
(
fastRandDouble
(
car
->
fuel_capacity
()));
car
->
set_fuel_level
(
fastRandDouble
(
car
->
fuel_capacity
()));
...
...
c++/src/capnproto/benchmark/protobuf-common.h
View file @
7b187dbd
...
@@ -24,8 +24,10 @@
...
@@ -24,8 +24,10 @@
#include "common.h"
#include "common.h"
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <thread>
#include <thread>
#if HAVE_SNAPPY
#include <snappy/snappy.h>
#include <snappy/snappy.h>
#include <snappy/snappy-sinksource.h>
#include <snappy/snappy-sinksource.h>
#endif // HAVE_SNAPPY
namespace
capnproto
{
namespace
capnproto
{
namespace
benchmark
{
namespace
benchmark
{
...
@@ -121,6 +123,8 @@ struct Uncompressed {
...
@@ -121,6 +123,8 @@ struct Uncompressed {
// arrays in some static scratch space. This probably gives protobufs an edge that it doesn't
// arrays in some static scratch space. This probably gives protobufs an edge that it doesn't
// deserve.
// deserve.
#if HAVE_SNAPPY
static
char
scratch
[
1
<<
20
];
static
char
scratch
[
1
<<
20
];
static
char
scratch2
[
1
<<
20
];
static
char
scratch2
[
1
<<
20
];
...
@@ -158,6 +162,8 @@ struct SnappyCompressed {
...
@@ -158,6 +162,8 @@ struct SnappyCompressed {
static
void
flush
(
OutputStream
*
)
{}
static
void
flush
(
OutputStream
*
)
{}
};
};
#endif // HAVE_SNAPPY
// =======================================================================================
// =======================================================================================
#define REUSABLE(type) \
#define REUSABLE(type) \
...
@@ -337,7 +343,9 @@ struct BenchmarkMethods {
...
@@ -337,7 +343,9 @@ struct BenchmarkMethods {
struct
BenchmarkTypes
{
struct
BenchmarkTypes
{
typedef
protobuf
::
Uncompressed
Uncompressed
;
typedef
protobuf
::
Uncompressed
Uncompressed
;
typedef
protobuf
::
Uncompressed
Packed
;
typedef
protobuf
::
Uncompressed
Packed
;
#if HAVE_SNAPPY
typedef
protobuf
::
SnappyCompressed
SnappyCompressed
;
typedef
protobuf
::
SnappyCompressed
SnappyCompressed
;
#endif // HAVE_SNAPPY
typedef
protobuf
::
ReusableMessages
ReusableResources
;
typedef
protobuf
::
ReusableMessages
ReusableResources
;
typedef
protobuf
::
SingleUseMessages
SingleUseResources
;
typedef
protobuf
::
SingleUseMessages
SingleUseResources
;
...
...
c++/src/capnproto/benchmark/runner.c++
View file @
7b187dbd
...
@@ -78,7 +78,8 @@ Times currentTimes() {
...
@@ -78,7 +78,8 @@ Times currentTimes() {
}
}
struct
TestResult
{
struct
TestResult
{
uint64_t
throughput
;
uint64_t
objectSize
;
uint64_t
messageSize
;
Times
time
;
Times
time
;
};
};
...
@@ -237,7 +238,8 @@ TestResult runTest(Product product, TestCase testCase, Mode mode, Reuse reuse,
...
@@ -237,7 +238,8 @@ TestResult runTest(Product product, TestCase testCase, Mode mode, Reuse reuse,
// Calculate results.
// Calculate results.
TestResult
result
;
TestResult
result
;
result
.
throughput
=
throughput
;
result
.
objectSize
=
mode
==
Mode
::
OBJECT_SIZE
?
throughput
:
0
;
result
.
messageSize
=
mode
==
Mode
::
OBJECT_SIZE
?
0
:
throughput
;
result
.
time
.
real
=
asNanosecs
(
end
)
-
asNanosecs
(
start
);
result
.
time
.
real
=
asNanosecs
(
end
)
-
asNanosecs
(
start
);
result
.
time
.
user
=
asNanosecs
(
usage
.
ru_utime
);
result
.
time
.
user
=
asNanosecs
(
usage
.
ru_utime
);
result
.
time
.
sys
=
asNanosecs
(
usage
.
ru_stime
);
result
.
time
.
sys
=
asNanosecs
(
usage
.
ru_stime
);
...
@@ -246,20 +248,20 @@ TestResult runTest(Product product, TestCase testCase, Mode mode, Reuse reuse,
...
@@ -246,20 +248,20 @@ TestResult runTest(Product product, TestCase testCase, Mode mode, Reuse reuse,
}
}
void
reportTableHeader
()
{
void
reportTableHeader
()
{
cout
<<
setw
(
50
)
<<
right
<<
"obj size or"
<<
endl
;
cout
<<
setw
(
40
)
<<
left
<<
"Test"
cout
<<
setw
(
40
)
<<
left
<<
"Test"
<<
setw
(
10
)
<<
right
<<
"obj size"
<<
setw
(
10
)
<<
right
<<
"I/O bytes"
<<
setw
(
10
)
<<
right
<<
"I/O bytes"
<<
setw
(
10
)
<<
right
<<
"wall ns"
<<
setw
(
10
)
<<
right
<<
"wall ns"
<<
setw
(
10
)
<<
right
<<
"user ns"
<<
setw
(
10
)
<<
right
<<
"user ns"
<<
setw
(
10
)
<<
right
<<
"sys ns"
<<
setw
(
10
)
<<
right
<<
"sys ns"
<<
endl
;
<<
endl
;
cout
<<
setfill
(
'='
)
<<
setw
(
8
0
)
<<
""
<<
setfill
(
' '
)
<<
endl
;
cout
<<
setfill
(
'='
)
<<
setw
(
9
0
)
<<
""
<<
setfill
(
' '
)
<<
endl
;
}
}
void
reportResults
(
const
char
*
name
,
uint64_t
iters
,
TestResult
results
)
{
void
reportResults
(
const
char
*
name
,
uint64_t
iters
,
TestResult
results
)
{
cout
<<
setw
(
40
)
<<
left
<<
name
cout
<<
setw
(
40
)
<<
left
<<
name
<<
setw
(
10
)
<<
right
<<
(
results
.
throughput
/
iters
)
<<
setw
(
10
)
<<
right
<<
(
results
.
objectSize
/
iters
)
<<
setw
(
10
)
<<
right
<<
(
results
.
messageSize
/
iters
)
<<
setw
(
10
)
<<
right
<<
(
results
.
time
.
real
/
iters
)
<<
setw
(
10
)
<<
right
<<
(
results
.
time
.
real
/
iters
)
<<
setw
(
10
)
<<
right
<<
(
results
.
time
.
user
/
iters
)
<<
setw
(
10
)
<<
right
<<
(
results
.
time
.
user
/
iters
)
<<
setw
(
10
)
<<
right
<<
(
results
.
time
.
sys
/
iters
)
<<
setw
(
10
)
<<
right
<<
(
results
.
time
.
sys
/
iters
)
...
@@ -267,12 +269,12 @@ void reportResults(const char* name, uint64_t iters, TestResult results) {
...
@@ -267,12 +269,12 @@ void reportResults(const char* name, uint64_t iters, TestResult results) {
}
}
void
reportComparisonHeader
()
{
void
reportComparisonHeader
()
{
cout
<<
setw
(
35
)
<<
left
<<
"Overhead typ
e"
cout
<<
setw
(
40
)
<<
left
<<
"Measur
e"
<<
setw
(
15
)
<<
right
<<
"Protobuf"
<<
setw
(
15
)
<<
right
<<
"Protobuf"
<<
setw
(
15
)
<<
right
<<
"Cap'n Proto"
<<
setw
(
15
)
<<
right
<<
"Cap'n Proto"
<<
setw
(
15
)
<<
right
<<
"Improvement"
<<
setw
(
15
)
<<
right
<<
"Improvement"
<<
endl
;
<<
endl
;
cout
<<
setfill
(
'='
)
<<
setw
(
8
0
)
<<
""
<<
setfill
(
' '
)
<<
endl
;
cout
<<
setfill
(
'='
)
<<
setw
(
8
5
)
<<
""
<<
setfill
(
' '
)
<<
endl
;
}
}
class
Gain
{
class
Gain
{
...
@@ -300,7 +302,7 @@ ostream& operator<<(ostream& os, Gain gain) {
...
@@ -300,7 +302,7 @@ ostream& operator<<(ostream& os, Gain gain) {
void
reportComparison
(
const
char
*
name
,
double
base
,
double
protobuf
,
double
capnproto
,
void
reportComparison
(
const
char
*
name
,
double
base
,
double
protobuf
,
double
capnproto
,
uint64_t
iters
)
{
uint64_t
iters
)
{
cout
<<
setw
(
35
)
<<
left
<<
name
cout
<<
setw
(
40
)
<<
left
<<
name
<<
setw
(
14
)
<<
right
<<
Gain
(
base
,
protobuf
)
<<
setw
(
14
)
<<
right
<<
Gain
(
base
,
protobuf
)
<<
setw
(
14
)
<<
right
<<
Gain
(
base
,
capnproto
);
<<
setw
(
14
)
<<
right
<<
Gain
(
base
,
capnproto
);
...
@@ -310,7 +312,7 @@ void reportComparison(const char* name, double base, double protobuf, double cap
...
@@ -310,7 +312,7 @@ void reportComparison(const char* name, double base, double protobuf, double cap
void
reportComparison
(
const
char
*
name
,
const
char
*
unit
,
double
protobuf
,
double
capnproto
,
void
reportComparison
(
const
char
*
name
,
const
char
*
unit
,
double
protobuf
,
double
capnproto
,
uint64_t
iters
)
{
uint64_t
iters
)
{
cout
<<
setw
(
35
)
<<
left
<<
name
cout
<<
setw
(
40
)
<<
left
<<
name
<<
setw
(
15
-
strlen
(
unit
))
<<
fixed
<<
right
<<
setprecision
(
2
)
<<
(
protobuf
/
iters
)
<<
unit
<<
setw
(
15
-
strlen
(
unit
))
<<
fixed
<<
right
<<
setprecision
(
2
)
<<
(
protobuf
/
iters
)
<<
unit
<<
setw
(
15
-
strlen
(
unit
))
<<
fixed
<<
right
<<
setprecision
(
2
)
<<
(
capnproto
/
iters
)
<<
unit
;
<<
setw
(
15
-
strlen
(
unit
))
<<
fixed
<<
right
<<
setprecision
(
2
)
<<
(
capnproto
/
iters
)
<<
unit
;
...
@@ -320,7 +322,7 @@ void reportComparison(const char* name, const char* unit, double protobuf, doubl
...
@@ -320,7 +322,7 @@ void reportComparison(const char* name, const char* unit, double protobuf, doubl
void
reportIntComparison
(
const
char
*
name
,
const
char
*
unit
,
uint64_t
protobuf
,
uint64_t
capnproto
,
void
reportIntComparison
(
const
char
*
name
,
const
char
*
unit
,
uint64_t
protobuf
,
uint64_t
capnproto
,
uint64_t
iters
)
{
uint64_t
iters
)
{
cout
<<
setw
(
35
)
<<
left
<<
name
cout
<<
setw
(
40
)
<<
left
<<
name
<<
setw
(
15
-
strlen
(
unit
))
<<
right
<<
(
protobuf
/
iters
)
<<
unit
<<
setw
(
15
-
strlen
(
unit
))
<<
right
<<
(
protobuf
/
iters
)
<<
unit
<<
setw
(
15
-
strlen
(
unit
))
<<
right
<<
(
capnproto
/
iters
)
<<
unit
;
<<
setw
(
15
-
strlen
(
unit
))
<<
right
<<
(
capnproto
/
iters
)
<<
unit
;
...
@@ -352,7 +354,6 @@ int main(int argc, char* argv[]) {
...
@@ -352,7 +354,6 @@ int main(int argc, char* argv[]) {
TestCase
testCase
=
TestCase
::
CATRANK
;
TestCase
testCase
=
TestCase
::
CATRANK
;
Mode
mode
=
Mode
::
PIPE_SYNC
;
Mode
mode
=
Mode
::
PIPE_SYNC
;
Reuse
reuse
=
Reuse
::
YES
;
Compression
compression
=
Compression
::
NONE
;
Compression
compression
=
Compression
::
NONE
;
uint64_t
iters
=
1
;
uint64_t
iters
=
1
;
...
@@ -368,10 +369,6 @@ int main(int argc, char* argv[]) {
...
@@ -368,10 +369,6 @@ int main(int argc, char* argv[]) {
testCase
=
TestCase
::
EVAL
;
testCase
=
TestCase
::
EVAL
;
}
else
if
(
arg
==
"carsales"
)
{
}
else
if
(
arg
==
"carsales"
)
{
testCase
=
TestCase
::
CARSALES
;
testCase
=
TestCase
::
CARSALES
;
}
else
if
(
arg
==
"no-reuse"
)
{
reuse
=
Reuse
::
NO
;
}
else
if
(
arg
==
"packed"
)
{
compression
=
Compression
::
PACKED
;
}
else
if
(
arg
==
"snappy"
)
{
}
else
if
(
arg
==
"snappy"
)
{
compression
=
Compression
::
SNAPPY
;
compression
=
Compression
::
SNAPPY
;
}
else
{
}
else
{
...
@@ -380,6 +377,7 @@ int main(int argc, char* argv[]) {
...
@@ -380,6 +377,7 @@ int main(int argc, char* argv[]) {
}
}
}
}
// Scale iterations to something reasonable for each case.
switch
(
testCase
)
{
switch
(
testCase
)
{
case
TestCase
:
:
EVAL
:
case
TestCase
:
:
EVAL
:
iters
*=
100000
;
iters
*=
100000
;
...
@@ -413,23 +411,18 @@ int main(int argc, char* argv[]) {
...
@@ -413,23 +411,18 @@ int main(int argc, char* argv[]) {
// Can't happen.
// Can't happen.
break
;
break
;
case
Mode
:
:
BYTES
:
case
Mode
:
:
BYTES
:
cout
<<
"* client and server in the same process (passing bytes in memory)"
<<
endl
;
cout
<<
"* in-memory I/O"
<<
endl
;
cout
<<
" * with client an server in the same thread"
<<
endl
;
break
;
break
;
case
Mode
:
:
PIPE_SYNC
:
case
Mode
:
:
PIPE_SYNC
:
cout
<<
"* client and server passing messages over pipes"
<<
endl
;
cout
<<
"* pipe I/O"
<<
endl
;
cout
<<
"* client sending one request at a time"
<<
endl
;
cout
<<
" * with client and server in separate processes"
<<
endl
;
cout
<<
" * client waits for each response before sending next request"
<<
endl
;
break
;
break
;
case
Mode
:
:
PIPE_ASYNC
:
case
Mode
:
:
PIPE_ASYNC
:
cout
<<
"* client and server passing messages over pipes"
<<
endl
;
cout
<<
"* pipe I/O"
<<
endl
;
cout
<<
"* client saturating pipe with requests without waiting for responses"
<<
endl
;
cout
<<
" * with client and server in separate processes"
<<
endl
;
break
;
cout
<<
" * client sends as many simultaneous requests as it can"
<<
endl
;
}
switch
(
reuse
)
{
case
Reuse
:
:
YES
:
cout
<<
"* ideal object reuse"
<<
endl
;
break
;
case
Reuse
:
:
NO
:
cout
<<
"* no object reuse"
<<
endl
;
break
;
break
;
}
}
switch
(
compression
)
{
switch
(
compression
)
{
...
@@ -445,54 +438,88 @@ int main(int argc, char* argv[]) {
...
@@ -445,54 +438,88 @@ int main(int argc, char* argv[]) {
break
;
break
;
}
}
cout
<<
endl
;
reportTableHeader
();
reportTableHeader
();
TestResult
nullCase
=
runTest
(
TestResult
nullCase
=
runTest
(
Product
::
NULLCASE
,
testCase
,
Mode
::
OBJECT
S
,
reuse
,
compression
,
iters
);
Product
::
NULLCASE
,
testCase
,
Mode
::
OBJECT
_SIZE
,
Reuse
::
YES
,
compression
,
iters
);
reportResults
(
"Theoretical best pass-by-object"
,
iters
,
nullCase
);
reportResults
(
"Theoretical best pass-by-object"
,
iters
,
nullCase
);
TestResult
protobufBase
=
runTest
(
TestResult
protobufBase
=
runTest
(
Product
::
PROTOBUF
,
testCase
,
Mode
::
OBJECTS
,
reuse
,
compression
,
iters
);
Product
::
PROTOBUF
,
testCase
,
Mode
::
OBJECTS
,
Reuse
::
YES
,
compression
,
iters
);
protobufBase
.
throughput
=
runTest
(
protobufBase
.
objectSize
=
runTest
(
Product
::
PROTOBUF
,
testCase
,
Mode
::
OBJECT_SIZE
,
reuse
,
compression
,
iters
).
throughput
;
Product
::
PROTOBUF
,
testCase
,
Mode
::
OBJECT_SIZE
,
Reuse
::
YES
,
compression
,
iters
).
objectSize
;
reportResults
(
"Protobuf pass-by-object"
,
iters
,
protobufBase
);
reportResults
(
"Protobuf pass-by-object"
,
iters
,
protobufBase
);
TestResult
capnpBase
=
runTest
(
TestResult
capnpBase
=
runTest
(
Product
::
CAPNPROTO
,
testCase
,
Mode
::
OBJECTS
,
reuse
,
compression
,
iters
);
Product
::
CAPNPROTO
,
testCase
,
Mode
::
OBJECTS
,
Reuse
::
YES
,
compression
,
iters
);
capnpBase
.
throughput
=
runTest
(
capnpBase
.
objectSize
=
runTest
(
Product
::
CAPNPROTO
,
testCase
,
Mode
::
OBJECT_SIZE
,
reuse
,
compression
,
iters
).
throughput
;
Product
::
CAPNPROTO
,
testCase
,
Mode
::
OBJECT_SIZE
,
Reuse
::
YES
,
compression
,
iters
).
objectSize
;
reportResults
(
"Cap'n Proto pass-by-object"
,
iters
,
capnpBase
);
reportResults
(
"Cap'n Proto pass-by-object"
,
iters
,
capnpBase
);
TestResult
protobuf
=
runTest
(
TestResult
nullCaseNoReuse
=
runTest
(
Product
::
PROTOBUF
,
testCase
,
mode
,
reuse
,
compression
,
iters
);
Product
::
NULLCASE
,
testCase
,
Mode
::
OBJECT_SIZE
,
Reuse
::
NO
,
compression
,
iters
);
reportResults
(
"
Protobuf pass-by-I/O"
,
iters
,
protobuf
);
reportResults
(
"
Theoretical best w/o object reuse"
,
iters
,
nullCaseNoReuse
);
TestResult
protobufNoReuse
=
runTest
(
Product
::
PROTOBUF
,
testCase
,
Mode
::
OBJECTS
,
Reuse
::
NO
,
compression
,
iters
);
protobufNoReuse
.
objectSize
=
runTest
(
Product
::
PROTOBUF
,
testCase
,
Mode
::
OBJECT_SIZE
,
Reuse
::
NO
,
compression
,
iters
).
objectSize
;
reportResults
(
"Protobuf w/o object reuse"
,
iters
,
protobufNoReuse
);
TestResult
capnpNoReuse
=
runTest
(
Product
::
CAPNPROTO
,
testCase
,
Mode
::
OBJECTS
,
Reuse
::
NO
,
compression
,
iters
);
capnpNoReuse
.
objectSize
=
runTest
(
Product
::
CAPNPROTO
,
testCase
,
Mode
::
OBJECT_SIZE
,
Reuse
::
NO
,
compression
,
iters
).
objectSize
;
reportResults
(
"Cap'n Proto w/o object reuse"
,
iters
,
capnpNoReuse
);
TestResult
protobuf
=
runTest
(
Product
::
PROTOBUF
,
testCase
,
mode
,
Reuse
::
YES
,
compression
,
iters
);
protobuf
.
objectSize
=
protobufBase
.
objectSize
;
reportResults
(
"Protobuf I/O"
,
iters
,
protobuf
);
TestResult
capnp
=
runTest
(
TestResult
capnp
=
runTest
(
Product
::
CAPNPROTO
,
testCase
,
mode
,
reuse
,
compression
,
iters
);
Product
::
CAPNPROTO
,
testCase
,
mode
,
Reuse
::
YES
,
compression
,
iters
);
reportResults
(
"Cap'n Proto pass-by-I/O"
,
iters
,
capnp
);
capnp
.
objectSize
=
capnpBase
.
objectSize
;
reportResults
(
"Cap'n Proto I/O"
,
iters
,
capnp
);
TestResult
capnpPacked
=
runTest
(
Product
::
CAPNPROTO
,
testCase
,
mode
,
Reuse
::
YES
,
Compression
::
PACKED
,
iters
);
capnpPacked
.
objectSize
=
capnpBase
.
objectSize
;
reportResults
(
"Cap'n Proto packed I/O"
,
iters
,
capnpPacked
);
cout
<<
endl
;
cout
<<
endl
;
reportComparisonHeader
();
reportComparisonHeader
();
reportComparison
(
"memory"
,
reportComparison
(
"memory overhead (vs ideal)"
,
nullCase
.
throughput
,
protobufBase
.
throughput
,
capnpBase
.
throughput
,
iters
);
nullCase
.
objectSize
,
protobufBase
.
objectSize
,
capnpBase
.
objectSize
,
iters
);
reportComparison
(
"object manipulation"
,
reportComparison
(
"memory overhead w/o object reuse"
,
nullCase
.
time
.
cpu
(),
protobufBase
.
time
.
cpu
(),
capnpBase
.
time
.
cpu
(),
iters
);
nullCaseNoReuse
.
objectSize
,
protobufNoReuse
.
objectSize
,
capnpNoReuse
.
objectSize
,
iters
);
reportComparison
(
"I/O time"
,
"us"
,
reportComparison
(
"object manipulation time (us)"
,
""
,
((
int64_t
)
protobufBase
.
time
.
cpu
()
-
(
int64_t
)
nullCase
.
time
.
cpu
())
/
1000.0
,
((
int64_t
)
capnpBase
.
time
.
cpu
()
-
(
int64_t
)
nullCase
.
time
.
cpu
())
/
1000.0
,
iters
);
reportComparison
(
"object manipulation time w/o reuse (us)"
,
""
,
((
int64_t
)
protobufNoReuse
.
time
.
cpu
()
-
(
int64_t
)
nullCaseNoReuse
.
time
.
cpu
())
/
1000.0
,
((
int64_t
)
capnpNoReuse
.
time
.
cpu
()
-
(
int64_t
)
nullCaseNoReuse
.
time
.
cpu
())
/
1000.0
,
iters
);
reportComparison
(
"I/O time (us)"
,
""
,
((
int64_t
)
protobuf
.
time
.
cpu
()
-
(
int64_t
)
protobufBase
.
time
.
cpu
())
/
1000.0
,
((
int64_t
)
protobuf
.
time
.
cpu
()
-
(
int64_t
)
protobufBase
.
time
.
cpu
())
/
1000.0
,
((
int64_t
)
capnp
.
time
.
cpu
()
-
(
int64_t
)
capnpBase
.
time
.
cpu
())
/
1000.0
,
iters
);
((
int64_t
)
capnp
.
time
.
cpu
()
-
(
int64_t
)
capnpBase
.
time
.
cpu
())
/
1000.0
,
iters
);
reportComparison
(
"packed I/O time (us)"
,
""
,
((
int64_t
)
protobuf
.
time
.
cpu
()
-
(
int64_t
)
protobufBase
.
time
.
cpu
())
/
1000.0
,
((
int64_t
)
capnpPacked
.
time
.
cpu
()
-
(
int64_t
)
capnpBase
.
time
.
cpu
())
/
1000.0
,
iters
);
reportIntComparison
(
"bandwidth"
,
"B"
,
protobuf
.
throughput
,
capnp
.
throughput
,
iters
);
reportIntComparison
(
"message size (bytes)"
,
""
,
protobuf
.
messageSize
,
capnp
.
messageSize
,
iters
);
reportIntComparison
(
"packed message size (bytes)"
,
""
,
protobuf
.
messageSize
,
capnpPacked
.
messageSize
,
iters
);
reportComparison
(
"binary size
"
,
"kB
"
,
reportComparison
(
"binary size
(KiB)"
,
"
"
,
fileSize
(
"protobuf-"
+
std
::
string
(
testCaseName
(
testCase
)))
/
1024.0
,
fileSize
(
"protobuf-"
+
std
::
string
(
testCaseName
(
testCase
)))
/
1024.0
,
fileSize
(
"capnproto-"
+
std
::
string
(
testCaseName
(
testCase
)))
/
1024.0
,
1
);
fileSize
(
"capnproto-"
+
std
::
string
(
testCaseName
(
testCase
)))
/
1024.0
,
1
);
reportComparison
(
"generated code size
"
,
"kB
"
,
reportComparison
(
"generated code size
(KiB)"
,
"
"
,
fileSize
(
std
::
string
(
testCaseName
(
testCase
))
+
".pb.cc"
)
/
1024.0
fileSize
(
std
::
string
(
testCaseName
(
testCase
))
+
".pb.cc"
)
/
1024.0
+
fileSize
(
std
::
string
(
testCaseName
(
testCase
))
+
".pb.h"
)
/
1024.0
,
+
fileSize
(
std
::
string
(
testCaseName
(
testCase
))
+
".pb.h"
)
/
1024.0
,
fileSize
(
std
::
string
(
testCaseName
(
testCase
))
+
".capnp.c++"
)
/
1024.0
fileSize
(
std
::
string
(
testCaseName
(
testCase
))
+
".capnp.c++"
)
/
1024.0
+
fileSize
(
std
::
string
(
testCaseName
(
testCase
))
+
".capnp.h"
)
/
1024.0
,
1
);
+
fileSize
(
std
::
string
(
testCaseName
(
testCase
))
+
".capnp.h"
)
/
1024.0
,
1
);
reportComparison
(
"generated obj size
"
,
"kB
"
,
reportComparison
(
"generated obj size
(KiB)"
,
"
"
,
fileSize
(
std
::
string
(
testCaseName
(
testCase
))
+
".pb.o"
)
/
1024.0
,
fileSize
(
std
::
string
(
testCaseName
(
testCase
))
+
".pb.o"
)
/
1024.0
,
fileSize
(
std
::
string
(
testCaseName
(
testCase
))
+
".capnp.o"
)
/
1024.0
,
1
);
fileSize
(
std
::
string
(
testCaseName
(
testCase
))
+
".capnp.o"
)
/
1024.0
,
1
);
...
...
c++/src/capnproto/descriptor-test.c++
deleted
100644 → 0
View file @
4dd3161d
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "descriptor.h"
#include <gtest/gtest.h>
namespace
capnproto
{
namespace
internal
{
namespace
{
const
int
READONLY_SEGMENT_START
=
123
;
const
FieldDescriptor
TEST_FIELDS
[
2
]
=
{
{
1
*
WORDS
,
0
*
REFERENCES
,
FieldSize
::
FOUR_BYTES
,
0
*
ELEMENTS
,
0
*
BYTES
,
1
,
0
,
0
*
BYTES
,
0
*
BITS
,
nullptr
,
nullptr
},
{
1
*
WORDS
,
1
*
REFERENCES
,
FieldSize
::
REFERENCE
,
0
*
ELEMENTS
,
0
*
BYTES
,
1
,
0
,
0
*
BYTES
,
0
*
BITS
,
nullptr
,
nullptr
}
};
extern
const
StructDescriptor
TEST_STRUCT
;
const
AlignedData
<
1
>
TEST_STRUCT_DEFAULT_VALUE
=
{
{
0x12
,
0x34
,
0x56
,
0x78
,
0x9a
,
0xbc
,
0xde
,
0xf0
}
};
const
StructDescriptor
TEST_STRUCT
=
{
{
Descriptor
::
Kind
::
STRUCT
},
FieldNumber
(
2
),
1
*
WORDS
,
1
*
REFERENCES
,
TEST_FIELDS
,
TEST_STRUCT_DEFAULT_VALUE
.
words
};
const
int
READONLY_SEGMENT_END
=
321
;
TEST
(
Descriptors
,
InReadOnlySegment
)
{
// It's extremely important that statically-initialized descriptors end up in the read-only
// segment, proving that they will not require any dynamic initialization at startup. We hackily
// assume that variables will be placed in each segment in the order that they appear, therefore
// if our test declarations above do in fact land in the read-only segment, they should appear
// between READONLY_SEGMENT_START and READONLY_SEGMENT_END.
EXPECT_LE
((
const
void
*
)
&
READONLY_SEGMENT_START
,
(
const
void
*
)
&
TEST_FIELDS
);
EXPECT_GE
((
const
void
*
)
&
READONLY_SEGMENT_END
,
(
const
void
*
)
&
TEST_FIELDS
);
EXPECT_LE
((
const
void
*
)
&
READONLY_SEGMENT_START
,
(
const
void
*
)
&
TEST_STRUCT_DEFAULT_VALUE
);
EXPECT_GE
((
const
void
*
)
&
READONLY_SEGMENT_END
,
(
const
void
*
)
&
TEST_STRUCT_DEFAULT_VALUE
);
EXPECT_LE
((
const
void
*
)
&
READONLY_SEGMENT_START
,
(
const
void
*
)
&
TEST_STRUCT
);
EXPECT_GE
((
const
void
*
)
&
READONLY_SEGMENT_END
,
(
const
void
*
)
&
TEST_STRUCT
);
}
}
// namespace
}
// namespace internal
}
// namespace capnproto
c++/src/capnproto/descriptor.c++
deleted
100644 → 0
View file @
4dd3161d
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "descriptor.h"
namespace
capnproto
{
namespace
internal
{
}
// namespace internal
}
// namespace capnproto
c++/src/capnproto/descriptor.h
deleted
100644 → 0
View file @
4dd3161d
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// This file is NOT intended for use by clients, except in generated code.
//
// The structures declared here provide basic information about user-defined capnproto data types
// needed in order to read, write, and traverse the raw message data. Basically, descriptors
// serve two purposes:
// - Define the layout of struct types so that they can be allocated and so that incoming structs
// can be validated.
// - Define the default values used when fields are absent on the wire.
//
// We use raw structs with no inheritance in order to allow for static initialization via the data
// segment with no need to execute any code at startup.
#ifndef CAPNPROTO_DESCRIPTOR_H_
#define CAPNPROTO_DESCRIPTOR_H_
#include <inttypes.h>
#include "macros.h"
#include "type-safety.h"
namespace
capnproto
{
namespace
internal
{
struct
ListDescriptor
;
struct
StructDescriptor
;
struct
FieldDescriptor
;
typedef
Id
<
uint8_t
,
FieldDescriptor
>
FieldNumber
;
template
<
int
wordCount
>
union
AlignedData
{
// Useful for declaring static constant data blobs as an array of bytes, but forcing those
// bytes to be word-aligned.
uint8_t
bytes
[
wordCount
*
sizeof
(
word
)];
word
words
[
wordCount
];
};
struct
Descriptor
{
// This is the "base type" for descriptors that describe the target of a reference.
// StructDescriptor and ListDescriptor should be treated as if they subclass this type. However,
// because subclassing breaks the ability to initialize structs using an initializer list -- which
// we need for static initialization purposes -- we don't actually use inheritance. Instead,
// each of the "subclasses" has a field of type Descriptor as its first field.
enum
class
Kind
:
uint8_t
{
LIST
,
// This is a ListDescriptor
STRUCT
// This is a StructDescriptor
};
Kind
kind
;
inline
const
ListDescriptor
*
asList
()
const
;
inline
const
StructDescriptor
*
asStruct
()
const
;
// Poor-man's downcast.
};
enum
class
FieldSize
:
uint8_t
{
// TODO: Rename to FieldLayout or maybe ValueLayout.
VOID
=
0
,
BIT
=
1
,
BYTE
=
2
,
TWO_BYTES
=
3
,
FOUR_BYTES
=
4
,
EIGHT_BYTES
=
5
,
REFERENCE
=
6
,
// Indicates that the field lives in the reference segment, not the data segment.
INLINE_COMPOSITE
=
7
// A composite type of fixed width. This serves two purposes:
// 1) For lists of composite types where all the elements would have the exact same width,
// allocating a list of references which in turn point at the elements would waste space. We
// can avoid a layer of indirection by placing all the elements in a flat sequence, and only
// indicating the element properties (e.g. field count for structs) once.
//
// Specifically, a list reference indicating INLINE_COMPOSITE element size actually points to
// a "tag" describing one element. This tag is formatted like a wire reference, but the
// "offset" instead stores the element count of the list. The flat list of elements appears
// immediately after the tag. In the list reference itself, the element count is replaced with
// a word count for the whole list (excluding tag). This allows the tag and elements to be
// precached in a single step rather than two sequential steps.
//
// It is NOT intended to be possible to substitute an INLINE_COMPOSITE list for a REFERENCE
// list or vice-versa without breaking recipients. Recipients expect one or the other
// depending on the message definition.
//
// However, it IS allowed to substitute an INLINE_COMPOSITE list -- specifically, of structs --
// when a list was expected, or vice versa, with the assumption that the first field of the
// struct (field number zero) correspond to the element type. This allows a list of
// primitives to be upgraded to a list of structs, avoiding the need to use parallel arrays
// when you realize that you need to attach some extra information to each element of some
// primitive list.
//
// 2) For struct fields of composite types where the field's total size is known at compile time,
// we can embed the field directly into the parent struct to avoid indirection through a
// reference. However, this means that the field size can never change -- e.g. if it is a
// struct, new fields cannot be added to it. It's unclear if this is really useful so at this
// time it is not supported.
};
typedef
decltype
(
BITS
/
ELEMENTS
)
BitsPerElement
;
namespace
internal
{
static
constexpr
BitsPerElement
BITS_PER_ELEMENT_TABLE
[
8
]
=
{
0
*
BITS
/
ELEMENTS
,
1
*
BITS
/
ELEMENTS
,
8
*
BITS
/
ELEMENTS
,
16
*
BITS
/
ELEMENTS
,
32
*
BITS
/
ELEMENTS
,
64
*
BITS
/
ELEMENTS
,
64
*
BITS
/
ELEMENTS
,
0
*
BITS
/
ELEMENTS
};
}
inline
constexpr
BitsPerElement
bitsPerElement
(
FieldSize
size
)
{
return
internal
::
BITS_PER_ELEMENT_TABLE
[
static_cast
<
int
>
(
size
)];
}
struct
ListDescriptor
{
// Describes a list.
Descriptor
base
;
FieldSize
elementSize
;
// Size of each element of the list. Also determines whether it is a reference list or a data
// list.
ElementCount32
defaultCount
;
// Number of elements in the default value.
const
word
*
defaultValue
;
// Default content, parseable as a raw (trusted) message.
const
Descriptor
*
elementDescriptor
;
// For a reference list, this is a descriptor of an element. Otherwise, NULL.
};
static_assert
(
CAPNPROTO_OFFSETOF
(
ListDescriptor
,
base
)
==
0
,
"'base' must be the first member of ListDescriptor to allow reinterpret_cast from "
"Descriptor to ListDescriptor."
);
struct
StructDescriptor
{
// Describes a struct.
Descriptor
base
;
FieldNumber
fieldCount
;
// Number of fields in this type -- that we were aware of at compile time, of course.
WordCount8
dataSize
;
// Size of the data segment, in 64-bit words.
WireReferenceCount8
referenceCount
;
// Number of references in the reference segment.
const
FieldDescriptor
*
fields
;
// Descriptors for fields, ordered by field number.
const
word
*
defaultValue
;
// Default content, parseable as a raw (trusted) message. This pointer actually points at a
// struct reference which in turn points at the struct content.
WordCount
wordSize
()
const
{
return
WordCount
(
dataSize
)
+
referenceCount
*
WORDS_PER_REFERENCE
;
}
};
static_assert
(
CAPNPROTO_OFFSETOF
(
StructDescriptor
,
base
)
==
0
,
"'base' must be the first member of StructDescriptor to allow reinterpret_cast from "
"Descriptor to StructDescriptor."
);
static
constexpr
uint16_t
INVALID_FIELD_OFFSET
=
0xffff
;
static
constexpr
ByteCount16
FIELD_ITSELF_IS_UNION_TAG
=
0xfffe
*
BYTES
;
struct
FieldDescriptor
{
// Describes one field of a struct.
WordCount8
requiredDataSize
;
// The minimum size of the data segment of any object which includes this field. This is always
// offset * size / 64 bits, rounded up. This value is useful for validating object references
// received on the wire -- if dataSize is insufficient to support fieldCount, don't trust it!
WireReferenceCount8
requiredReferenceCount
;
// The minimum size of the reference segment of any object which includes this field. Same deal
// as with requiredDataSize.
FieldSize
size
;
// Size of this field.
ElementCount16
offset
;
// If the field is a data field (size != REFERENCE), then this is the offset within the object's
// data segment at which the field is positioned, measured in multiples of the field's size. Note
// that for size == BIT, bits are considered to be in little-endian order. Therefore, an offset
// of zero refers to the least-significant bit of the first byte, 15 refers to the
// most-significant bit of the second byte, etc.
//
// If the field is a reference field (size == REFERENCE), then this is the index within the
// reference array at which the field is located.
//
// For void fields, the offset is irrelevant and may be INVALID_FIELD_OFFSET.
ByteCount16
unionTagOffset
;
// Offset within the data segment at which a union tag exists deciding whether this field is
// valid. If the tag byte does not contain this field's number, then this field is considered
// to be unset. An offset of INVALID_FIELD_OFFSET means the field is not a member of a union.
// An offset of FIELD_ITSELF_IS_UNION_TAG means that this field itself is actually a union tag.
uint16_t
hole32Offset
;
uint16_t
hole16Offset
;
ByteCount16
hole8Offset
;
// In the case that this field is the last one in the object, and thus the object's data segment
// size is equal to requiredDataSize, then the following offsets indicate locations of "holes" in
// the data segment which are not occupied by any field. The packing algorithm guarantees that
// there can be at most one hole of each size, and such holes will always be located at an offset
// that is an odd multiple of the hole size. The hole offsets here are given in multiples of the
// hole size, with INVALID_FIELD_OFFSET meaning there is no hole.
//
// TODO: Measurement types for hole16 and hole32?
BitCount16
bitholeOffset
;
// If the object contains boolean fields and the number of booleans is not divisible by 8, then
// there will also be a hole of 1-7 bits somewhere. bitholeOffset is the offset, in bits, of the
// first (least-significant) such missing bit. All subsequent (more-significant) bits within the
// same byte are also missing. A value of INVALID_FIELD_OFFSET indicates that there is no hole.
const
Descriptor
*
descriptor
;
// If the field has a composite type, this is its descriptor.
const
void
*
defaultValue
;
// Pointer to the field's default value. For reference fields, this should actually be a pointer
// to a reference, which may be interpreted as a raw (trusted) message. This pointer must be
// aligned correctly for the value it points at.
//
// You might wonder why we can't just pull the default field value from the struct's defalut
// value. The problem is with unions -- at best, the struct default data only encodes one member
// of each union.
};
inline
const
ListDescriptor
*
Descriptor
::
asList
()
const
{
CAPNPROTO_DEBUG_ASSERT
(
kind
==
Kind
::
LIST
,
"asList() called on Descriptor that isn't a list."
);
return
reinterpret_cast
<
const
ListDescriptor
*>
(
this
);
}
inline
const
StructDescriptor
*
Descriptor
::
asStruct
()
const
{
CAPNPROTO_DEBUG_ASSERT
(
kind
==
Kind
::
STRUCT
,
"asStruct() called on Descriptor that isn't a struct."
);
return
reinterpret_cast
<
const
StructDescriptor
*>
(
this
);
}
}
// namespace internal
}
// namespace capnproto
#endif // CAPNPROTO_DESCRIPTOR_H_
c++/src/capnproto/generated-header-support.h
View file @
7b187dbd
...
@@ -29,6 +29,4 @@
...
@@ -29,6 +29,4 @@
#include "wire-format.h"
#include "wire-format.h"
#include "list.h"
#include "list.h"
#include "descriptor.h" // TODO: Eliminate this.
#endif // CAPNPROTO_GENERATED_HEADER_SUPPORT_H_
#endif // CAPNPROTO_GENERATED_HEADER_SUPPORT_H_
c++/src/capnproto/list.h
View file @
7b187dbd
...
@@ -25,7 +25,6 @@
...
@@ -25,7 +25,6 @@
#define CAPNPROTO_LIST_H_
#define CAPNPROTO_LIST_H_
#include "wire-format.h"
#include "wire-format.h"
#include "descriptor.h" // only for FieldSize; TODO: Eliminate this
#include <initializer_list>
#include <initializer_list>
namespace
capnproto
{
namespace
capnproto
{
...
...
c++/src/capnproto/wire-format-test.c++
View file @
7b187dbd
...
@@ -22,7 +22,6 @@
...
@@ -22,7 +22,6 @@
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "wire-format.h"
#include "wire-format.h"
#include "descriptor.h"
#include "message.h"
#include "message.h"
#include "arena.h"
#include "arena.h"
#include <gtest/gtest.h>
#include <gtest/gtest.h>
...
...
c++/src/capnproto/wire-format.c++
View file @
7b187dbd
...
@@ -23,7 +23,6 @@
...
@@ -23,7 +23,6 @@
#include "wire-format.h"
#include "wire-format.h"
#include "arena.h"
#include "arena.h"
#include "descriptor.h"
#include <string.h>
#include <string.h>
#include <limits>
#include <limits>
...
...
c++/src/capnproto/wire-format.h
View file @
7b187dbd
...
@@ -37,10 +37,6 @@
...
@@ -37,10 +37,6 @@
namespace
capnproto
{
namespace
capnproto
{
namespace
internal
{
namespace
internal
{
class
FieldDescriptor
;
typedef
Id
<
uint8_t
,
FieldDescriptor
>
FieldNumber
;
enum
class
FieldSize
:
uint8_t
;
class
StructBuilder
;
class
StructBuilder
;
class
StructReader
;
class
StructReader
;
class
ListBuilder
;
class
ListBuilder
;
...
@@ -50,6 +46,82 @@ struct WireHelpers;
...
@@ -50,6 +46,82 @@ struct WireHelpers;
class
SegmentReader
;
class
SegmentReader
;
class
SegmentBuilder
;
class
SegmentBuilder
;
class
FieldDescriptor
;
typedef
Id
<
uint8_t
,
FieldDescriptor
>
FieldNumber
;
enum
class
FieldSize
:
uint8_t
;
enum
class
FieldSize
:
uint8_t
{
// TODO: Rename to FieldLayout or maybe ValueLayout.
VOID
=
0
,
BIT
=
1
,
BYTE
=
2
,
TWO_BYTES
=
3
,
FOUR_BYTES
=
4
,
EIGHT_BYTES
=
5
,
REFERENCE
=
6
,
// Indicates that the field lives in the reference segment, not the data segment.
INLINE_COMPOSITE
=
7
// A composite type of fixed width. This serves two purposes:
// 1) For lists of composite types where all the elements would have the exact same width,
// allocating a list of references which in turn point at the elements would waste space. We
// can avoid a layer of indirection by placing all the elements in a flat sequence, and only
// indicating the element properties (e.g. field count for structs) once.
//
// Specifically, a list reference indicating INLINE_COMPOSITE element size actually points to
// a "tag" describing one element. This tag is formatted like a wire reference, but the
// "offset" instead stores the element count of the list. The flat list of elements appears
// immediately after the tag. In the list reference itself, the element count is replaced with
// a word count for the whole list (excluding tag). This allows the tag and elements to be
// precached in a single step rather than two sequential steps.
//
// It is NOT intended to be possible to substitute an INLINE_COMPOSITE list for a REFERENCE
// list or vice-versa without breaking recipients. Recipients expect one or the other
// depending on the message definition.
//
// However, it IS allowed to substitute an INLINE_COMPOSITE list -- specifically, of structs --
// when a list was expected, or vice versa, with the assumption that the first field of the
// struct (field number zero) correspond to the element type. This allows a list of
// primitives to be upgraded to a list of structs, avoiding the need to use parallel arrays
// when you realize that you need to attach some extra information to each element of some
// primitive list.
//
// 2) For struct fields of composite types where the field's total size is known at compile time,
// we can embed the field directly into the parent struct to avoid indirection through a
// reference. However, this means that the field size can never change -- e.g. if it is a
// struct, new fields cannot be added to it. It's unclear if this is really useful so at this
// time it is not supported.
};
typedef
decltype
(
BITS
/
ELEMENTS
)
BitsPerElement
;
namespace
internal
{
static
constexpr
BitsPerElement
BITS_PER_ELEMENT_TABLE
[
8
]
=
{
0
*
BITS
/
ELEMENTS
,
1
*
BITS
/
ELEMENTS
,
8
*
BITS
/
ELEMENTS
,
16
*
BITS
/
ELEMENTS
,
32
*
BITS
/
ELEMENTS
,
64
*
BITS
/
ELEMENTS
,
64
*
BITS
/
ELEMENTS
,
0
*
BITS
/
ELEMENTS
};
}
inline
constexpr
BitsPerElement
bitsPerElement
(
FieldSize
size
)
{
return
internal
::
BITS_PER_ELEMENT_TABLE
[
static_cast
<
int
>
(
size
)];
}
template
<
int
wordCount
>
union
AlignedData
{
// Useful for declaring static constant data blobs as an array of bytes, but forcing those
// bytes to be word-aligned.
uint8_t
bytes
[
wordCount
*
sizeof
(
word
)];
word
words
[
wordCount
];
};
// -------------------------------------------------------------------
// -------------------------------------------------------------------
template
<
typename
T
>
template
<
typename
T
>
...
...
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