Avoid issues on platforms where Eigen decides it needs 32 byte alignment.

release/4.3a0
Frank Dellaert 2023-02-11 15:19:48 -08:00
parent 38a9ba3692
commit 81ce4f4d9e
1 changed files with 15 additions and 7 deletions

View File

@ -27,6 +27,7 @@
#include <iostream> #include <iostream>
#include <optional> #include <optional>
#include <string>
#include <type_traits> #include <type_traits>
namespace gtsam { namespace gtsam {
@ -37,7 +38,13 @@ template<int T> struct CallRecord;
/// Storage type for the execution trace. /// Storage type for the execution trace.
/// It enforces the proper alignment in a portable way. /// It enforces the proper alignment in a portable way.
/// Provide a traceSize() sized array of this type to traceExecution as traceStorage. /// Provide a traceSize() sized array of this type to traceExecution as traceStorage.
static const unsigned TraceAlignment = 16; // 16 bytes is the default alignment used by Eigen. #ifdef _MSC_VER
// TODO(dellaert): this might lead to trouble if Eigen decides to use 32 on Windows.
static const unsigned TraceAlignment = 16; // 16 bytes max_align on Windows
#else
static const unsigned TraceAlignment = 32; // Alignment used by Eigen on some platforms.
#endif
// TODO(dellaert): we *should* be able to simplify the code using the pointer arithmetic from ExecutionTraceStorage.
typedef std::aligned_storage<1, TraceAlignment>::type ExecutionTraceStorage; typedef std::aligned_storage<1, TraceAlignment>::type ExecutionTraceStorage;
template<bool UseBlock, typename Derived> template<bool UseBlock, typename Derived>
@ -123,11 +130,11 @@ class ExecutionTrace {
/// Print /// Print
void print(const std::string& indent = "") const { void print(const std::string& indent = "") const {
if (kind == Constant) if (kind == Constant) {
std::cout << indent << "Constant" << std::endl; std::cout << indent << "Constant" << std::endl;
else if (kind == Leaf) } else if (kind == Leaf) {
std::cout << indent << "Leaf, key = " << content.key << std::endl; std::cout << indent << "Leaf, key = " << content.key << std::endl;
else if (kind == Function) { } else if (kind == Function) {
content.ptr->print(indent + " "); content.ptr->print(indent + " ");
} }
} }
@ -135,9 +142,9 @@ class ExecutionTrace {
/// Return record pointer, quite unsafe, used only for testing /// Return record pointer, quite unsafe, used only for testing
template<class Record> template<class Record>
std::optional<Record*> record() { std::optional<Record*> record() {
if (kind != Function) if (kind != Function) {
return {}; return {};
else { } else {
Record* p = dynamic_cast<Record*>(content.ptr); Record* p = dynamic_cast<Record*>(content.ptr);
return p ? std::optional<Record*>(p) : std::nullopt; return p ? std::optional<Record*>(p) : std::nullopt;
} }
@ -152,11 +159,12 @@ class ExecutionTrace {
// This branch will only be called on trivial Leaf expressions, i.e. Priors // This branch will only be called on trivial Leaf expressions, i.e. Priors
static const JacobianTT I = JacobianTT::Identity(); static const JacobianTT I = JacobianTT::Identity();
handleLeafCase(I, jacobians, content.key); handleLeafCase(I, jacobians, content.key);
} else if (kind == Function) } else if (kind == Function) {
// This is the more typical entry point, starting the AD pipeline // This is the more typical entry point, starting the AD pipeline
// Inside startReverseAD2 the correctly dimensioned pipeline is chosen. // Inside startReverseAD2 the correctly dimensioned pipeline is chosen.
content.ptr->startReverseAD2(jacobians); content.ptr->startReverseAD2(jacobians);
} }
}
/// Either add to Jacobians (Leaf) or propagate (Function) /// Either add to Jacobians (Leaf) or propagate (Function)
// This is a crucial method in selecting the pipeline dimension: since it is templated method // This is a crucial method in selecting the pipeline dimension: since it is templated method