From b5ae4bf78ddccd867021f216af265501076acdac Mon Sep 17 00:00:00 2001 From: Andrzej Krzemienski Date: Sat, 6 Dec 2014 19:27:53 +0100 Subject: [PATCH] Added performance notes to documentation --- doc/00_optional.qbk | 1 + doc/19_on_performance.qbk | 131 ++++++++++ .../tutorial/performance_considerations.html | 223 ++++++++++++++++++ .../tutorial/type_requirements.html | 6 +- doc/html/images/opt_align1.png | Bin 0 -> 417 bytes doc/html/images/opt_align2.png | Bin 0 -> 472 bytes doc/html/images/opt_align3.png | Bin 0 -> 468 bytes doc/html/images/opt_align4.png | Bin 0 -> 428 bytes doc/html/index.html | 4 +- doc/html/optional/reference.html | 6 +- doc/html/optional/tutorial.html | 2 + 11 files changed, 366 insertions(+), 7 deletions(-) create mode 100644 doc/19_on_performance.qbk create mode 100644 doc/html/boost_optional/tutorial/performance_considerations.html create mode 100644 doc/html/images/opt_align1.png create mode 100644 doc/html/images/opt_align2.png create mode 100644 doc/html/images/opt_align3.png create mode 100644 doc/html/images/opt_align4.png diff --git a/doc/00_optional.qbk b/doc/00_optional.qbk index 0693237..95c982f 100644 --- a/doc/00_optional.qbk +++ b/doc/00_optional.qbk @@ -85,6 +85,7 @@ This is how you solve it with `boost::optional`: [include 16_optional_bool.qbk] [include 17_exception_safety.qbk] [include 18_type_requirements.qbk] +[include 19_on_performance.qbk] [endsect] [section Reference] [include 20_reference.qbk] diff --git a/doc/19_on_performance.qbk b/doc/19_on_performance.qbk new file mode 100644 index 0000000..841190f --- /dev/null +++ b/doc/19_on_performance.qbk @@ -0,0 +1,131 @@ + +[section Performance considerations] + +Technical details aside, the memory layout of `optional` is more-less this: + + template + class optional + { + bool _initialized; + std::aligned_storage_t _storage; + }; + +But for the purpose of this analysis, considering memory layouts, we can think of it as: + + template + class optional + { + bool _initialized; + T _storage; + }; + +Given type `optional`, and assuming that `sizeof(int) == 4`, we will get `sizeof(optional) == 8`. This is so because of the alignment rules, for our two members we get the following alignment: + +[$images/opt_align1.png] + +This means you can fit twice as many `int`s as `optional`s into the same space of memory. Therefore, if the size of the objects is critical for your application (e.g., because you want to utilize your CPU cache in order to gain performance) and you have determined you are willing to trade the code clarity, it is recommended that you simply go with type `int` and use some 'magic value' to represent ['not-an-int]. + +Even if you cannot spare any value of `int` to represent ['not-an-int] (e.g., because every value is useful, or you do want to signal ['not-an-int] explicitly), at least for `Trivial` types you should consider storing the value and the `bool` flag representing the ['null-state] separately. Consider the following class: + + struct Record + { + optional _min; + optional _max; + }; + +Its memory layout can be depicted as follows: + +[$images/opt_align2.png] + +This is exactly the same as if we had the following members: + + struct Record + { + bool _has_min; + int _min; + bool _has_max; + int _max; + }; + +But when they are stored separately, we at least have an option to reorder them like this: + + struct Record + { + bool _has_min; + bool _has_max; + int _min; + int _max; + }; + +Which gives us the following layout (and smaller total size): + +[$images/opt_align3.png] + +Sometimes it requires detailed consideration what data we make optional. In our case above, if we determine that both minimum and maximum value can be provided or not provided together, but one is never provided without the other, we can make only one optional memebr: + + struct Limits + { + int _min; + int _max; + }; + + struct Record + { + optional _limits; + }; + +This would give us the following layout: + +[$images/opt_align4.png] + +[heading Optional function parameters] + +Having function parameters of type `const optional&` may incur certain unexpected run-time cost connected to copy construction of `T`. Consider the following code. + + void fun(const optional& v) + { + if (v) doSomethingWith(*v); + else doSomethingElse(); + } + + int main() + { + optional ov; + Big v; + fun(none); + fun(ov); // no copy + fun(v); // copy constructor of Big + } + +No copy elision or move semantics can save us from copying type `Big` here. Not that we need any copy, but this is how `optional` works. In order to avoid copying in this case, one could provide second overload of `fun`: + + void fun(const Big& v) + { + doSomethingWith(v); + } + + int main() + { + optional ov; + Big v; + fun(ov); // no copy + fun(v); // no copy: second overload selected + } + +Alternatively, you could consider using an optional reference instead: + + void fun(optional v) // note where the reference is + { + if (v) doSomethingWith(*v); + else doSomethingElse(); + } + + int main() + { + optional ov; + Big v; + fun(none); + fun(ov); // doesn't compile + fun(v); // no copy + } +[endsect] diff --git a/doc/html/boost_optional/tutorial/performance_considerations.html b/doc/html/boost_optional/tutorial/performance_considerations.html new file mode 100644 index 0000000..d054e01 --- /dev/null +++ b/doc/html/boost_optional/tutorial/performance_considerations.html @@ -0,0 +1,223 @@ + + + +Performance considerations + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ +

+ Technical details aside, the memory layout of optional<T> + is more-less this: +

+
template <typename T>
+class optional
+{
+  bool _initialized;
+  std::aligned_storage_t<sizeof(t), alignof(T)> _storage;
+};
+
+

+ But for the purpose of this analysis, considering memory layouts, we can + think of it as: +

+
template <typename T>
+class optional
+{
+  bool _initialized;
+  T _storage;
+};
+
+

+ Given type optional<int>, and + assuming that sizeof(int) == + 4, we will get sizeof(optional<int>) + == 8. + This is so because of the alignment rules, for our two members we get the + following alignment: +

+

+ opt_align1 +

+

+ This means you can fit twice as many ints + as optional<int>s into + the same space of memory. Therefore, if the size of the objects is critical + for your application (e.g., because you want to utilize your CPU cache in + order to gain performance) and you have determined you are willing to trade + the code clarity, it is recommended that you simply go with type int and use some 'magic value' to represent + not-an-int. +

+

+ Even if you cannot spare any value of int + to represent not-an-int (e.g., because every value is + useful, or you do want to signal not-an-int explicitly), + at least for Trivial types + you should consider storing the value and the bool + flag representing the null-state separately. Consider + the following class: +

+
struct Record
+{
+  optional<int> _min;
+  optional<int> _max;
+};
+
+

+ Its memory layout can be depicted as follows: +

+

+ opt_align2 +

+

+ This is exactly the same as if we had the following members: +

+
struct Record
+{
+  bool _has_min;
+  int  _min;
+  bool _has_max;
+  int  _max;
+};
+
+

+ But when they are stored separately, we at least have an option to reorder + them like this: +

+
struct Record
+{
+  bool _has_min;
+  bool _has_max;
+  int  _min;
+  int  _max;
+};
+
+

+ Which gives us the following layout (and smaller total size): +

+

+ opt_align3 +

+

+ Sometimes it requires detailed consideration what data we make optional. + In our case above, if we determine that both minimum and maximum value can + be provided or not provided together, but one is never provided without the + other, we can make only one optional memebr: +

+
struct Limits
+{
+  int  _min;
+  int  _max;
+};
+
+struct Record
+{
+  optional<Limits> _limits;
+};
+
+

+ This would give us the following layout: +

+

+ opt_align4 +

+
+ + Optional + function parameters +
+

+ Having function parameters of type const + optional<T>& + may incur certain unexpected run-time cost connected to copy construction + of T. Consider the following + code. +

+
void fun(const optional<Big>& v)
+{
+  if (v) doSomethingWith(*v);
+  else   doSomethingElse();
+}
+
+int main()
+{
+  optional<Big> ov;
+  Big v;
+  fun(none);
+  fun(ov); // no copy
+  fun(v);  // copy constructor of Big
+}
+
+

+ No copy elision or move semantics can save us from copying type Big here. Not that we need any copy, but + this is how optional works. + In order to avoid copying in this case, one could provide second overload + of fun: +

+
void fun(const Big& v)
+{
+  doSomethingWith(v);
+}
+
+int main()
+{
+  optional<Big> ov;
+  Big v;
+  fun(ov); // no copy
+  fun(v);  // no copy: second overload selected
+}
+
+

+ Alternatively, you could consider using an optional reference instead: +

+
void fun(optional<const Big&> v) // note where the reference is
+{
+  if (v) doSomethingWith(*v);
+  else   doSomethingElse();
+}
+
+int main()
+{
+  optional<Big> ov;
+  Big v;
+  fun(none);
+  fun(ov); // doesn't compile
+  fun(v);  // no copy
+}
+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/boost_optional/tutorial/type_requirements.html b/doc/html/boost_optional/tutorial/type_requirements.html index 38a106d..8612ea0 100644 --- a/doc/html/boost_optional/tutorial/type_requirements.html +++ b/doc/html/boost_optional/tutorial/type_requirements.html @@ -7,7 +7,7 @@ - + @@ -20,7 +20,7 @@

-PrevUpHomeNext +PrevUpHomeNext

@@ -103,7 +103,7 @@
-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/images/opt_align1.png b/doc/html/images/opt_align1.png new file mode 100644 index 0000000000000000000000000000000000000000..50e0205eab4aef06bdc02ac4490dd20ca50e887b GIT binary patch literal 417 zcmeAS@N?(olHy`uVBq!ia0y~yV9aD-U=ZM7V_;yoqS*JDfq{XsILO_JVcj{ImkbOH zEa{HEjtmSN`?>!lvNA9*a29w(7BevL9RXp+soH$f3=E8Bo-U3d6>)FxY|LeH6kxqz ztEHg4WrEKOzH^hL7g|XAYLN=ZX%yGzD5lhv*6XZ9!Fn`d{E@3Kj3_xZzI zd;Y&!RW^HDeCW?N1#kD=++W^Vxp(eGA#3}~#%=p2$sIS`^4aFR>o>byVPS_K#@N{> z{Xd+4d|}M@*}uj1{0!^=9p`sH_3tOCTiZjo9XHPUn)k)3T(nBLl|w+mLBZ9*bGd=E zQv*ZejD|^lJ3R&ICHCOI*q$k#Z6<;%_U_ueJ=-Ardv1}(ROf2z#ivT=>;2=F-52}K USWrxcfq{X+)78&qol`;+0CoSNbpQYW literal 0 HcmV?d00001 diff --git a/doc/html/images/opt_align2.png b/doc/html/images/opt_align2.png new file mode 100644 index 0000000000000000000000000000000000000000..fd7c079c9303f4797523b7ef10c775d2b42f959f GIT binary patch literal 472 zcmeAS@N?(olHy`uVBq!ia0y~yV9aD-U=ZM7V_;yoqS*JDfq{XsILO_JVcj{ImkbOH zEa{HEjtmSN`?>!lvNA9*a29w(7BevL9RXp+soH$f3=E99o-U3d6>)Fx82T|eN*w(d zsjskb<6(}7TM_F!)wVhLI%a&}nbVjo!Cjr}YjSh#)(s&^clz22npFdWa__0+H~kEL ze>;EQeYO6)O^Y;M9e97AE9UP!_qSnlYTcjSeR!kx?(^Qc*KOyy?R~V+w)@oX!;`Px zu{HX+Cnx$+5{>LL*?yoHM_{ ijqs^v%dBp&o1YI$tl-G1?_ywJVDNPHb6Mw<&;$UeS-J!O literal 0 HcmV?d00001 diff --git a/doc/html/images/opt_align3.png b/doc/html/images/opt_align3.png new file mode 100644 index 0000000000000000000000000000000000000000..7ca6ec800eb037540b8598efab9014c68701e4ad GIT binary patch literal 468 zcmeAS@N?(olHy`uVBq!ia0y~yV9aD-U=ZM7V_;yoqS*JDfq{XsILO_JVcj{ImkbOH zEa{HEjtmSN`?>!lvNA9*a29w(7BevL9RXp+soH$fAR|0o978JN-rg}>=jbSM?Bh~9_! zDDwTt^K8~%&)4nQURJA?KL6nTV~3`MADZ@8>+>SxYsOu1`;F`$#c96&6QWiBZ P7#KWV{an^LB{Ts5JQBDO literal 0 HcmV?d00001 diff --git a/doc/html/images/opt_align4.png b/doc/html/images/opt_align4.png new file mode 100644 index 0000000000000000000000000000000000000000..c7f9b72422ce3c1d6d1c475a531e533b61b19c73 GIT binary patch literal 428 zcmeAS@N?(olHy`uVBq!ia0y~yV9aD-U=ZM7V_;yoqS*JDfq{XsILO_JVcj{ImkbOH zEa{HEjtmSN`?>!lvNA9*a29w(7BevL9RXp+soH$f3=E8po-U3d6>)Fx80H;v5MaGf z>gOdL>K=aoN8B&;PWu z_b>ncx9vs0D)!|cT)n#L&iC)XBf?($X50_E`PsP3?ta+!7~}27jU#_YS8&bsP-J4^ z5bzKTxTJZeO+djxL2bd3Exception Safety Guarantees
Type requirements
+
Performance + considerations
Reference
@@ -134,7 +136,7 @@

- +

Last revised: November 21, 2014 at 23:32:40 GMT

Last revised: December 06, 2014 at 18:09:45 GMT


diff --git a/doc/html/optional/reference.html b/doc/html/optional/reference.html index 9c157df..4a16c15 100644 --- a/doc/html/optional/reference.html +++ b/doc/html/optional/reference.html @@ -6,7 +6,7 @@ - + @@ -20,7 +20,7 @@
-PrevUpHomeNext +PrevUpHomeNext

@@ -181,7 +181,7 @@
-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/optional/tutorial.html b/doc/html/optional/tutorial.html index 7b84efd..b5b8c50 100644 --- a/doc/html/optional/tutorial.html +++ b/doc/html/optional/tutorial.html @@ -44,6 +44,8 @@
Exception Safety Guarantees
Type requirements
+
Performance + considerations