Add more autodiff benchmarks

- Create new subdirectory internal/ceres/autodiff_benchmarks
- Move the ba-autodiff benchmark to the new subdir.
- Add new autodiff benchmarks for linear cost functions (1 and 10 params)

Change-Id: Ic0e31cf2c05389935bb90c6a4fd9c0382a7e1ed0
diff --git a/internal/ceres/CMakeLists.txt b/internal/ceres/CMakeLists.txt
index a8813a6..9329162 100644
--- a/internal/ceres/CMakeLists.txt
+++ b/internal/ceres/CMakeLists.txt
@@ -511,9 +511,6 @@
 endmacro()
 
 if (BUILD_BENCHMARKS)
-  add_executable(autodiff_cost_function_benchmark autodiff_cost_function_benchmark.cc)
-  add_dependencies_to_benchmark(autodiff_cost_function_benchmark)
-
   add_executable(small_blas_gemv_benchmark small_blas_gemv_benchmark.cc)
   add_dependencies_to_benchmark(small_blas_gemv_benchmark)
 
@@ -525,9 +522,10 @@
 
   add_executable(schur_eliminator_benchmark schur_eliminator_benchmark.cc)
   add_dependencies_to_benchmark(schur_eliminator_benchmark)
+
+  add_subdirectory(autodiff_benchmarks)
 endif (BUILD_BENCHMARKS)
 
 if(CODE_GENERATION)
   add_subdirectory(codegen)
 endif()
-
diff --git a/internal/ceres/autodiff_benchmarks/CMakeLists.txt b/internal/ceres/autodiff_benchmarks/CMakeLists.txt
new file mode 100644
index 0000000..e42e584
--- /dev/null
+++ b/internal/ceres/autodiff_benchmarks/CMakeLists.txt
@@ -0,0 +1,55 @@
+
+if(CODE_GENERATION)
+  macro (generate_benchmark_functor FUNCTOR_NAME FUNCTOR_FILE)
+    ceres_generate_cost_function_implementation_for_functor(
+      NAME ${FUNCTOR_NAME}
+      INPUT_FILE ${FUNCTOR_FILE}
+      OUTPUT_DIRECTORY benchmarks
+      NAMESPACE ceres
+      )
+  endmacro()
+  include(CeresCodeGeneration)
+
+  generate_benchmark_functor(SnavelyReprojectionError snavely_reprojection_error.h)
+  generate_benchmark_functor(Linear1CostFunction linear_cost_functions.h)
+  generate_benchmark_functor(Linear10CostFunction linear_cost_functions.h)
+
+  list(APPEND CERES_BENCHMARK_FLAGS "-DWITH_CODE_GENERATION")
+endif()
+
+
+# TODO: Add support for other compilers
+if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+  list(APPEND CERES_BENCHMARK_FLAGS "-mllvm" "-inline-threshold=1000000")
+
+  # All other flags + fast-math
+  list(APPEND CERES_BENCHMARK_FAST_MATH_FLAGS ${CERES_BENCHMARK_FLAGS} "-ffast-math")
+endif()
+
+add_executable(rat43_benchmark rat43_benchmark.cc)
+add_dependencies_to_benchmark(rat43_benchmark)
+
+
+add_executable(snavely_reprojection_error_benchmark snavely_reprojection_error_benchmark.cc)
+add_dependencies_to_benchmark(snavely_reprojection_error_benchmark)
+target_compile_options(snavely_reprojection_error_benchmark PRIVATE ${CERES_BENCHMARK_FLAGS})
+
+add_executable(snavely_reprojection_error_benchmark_fast_math snavely_reprojection_error_benchmark.cc)
+add_dependencies_to_benchmark(snavely_reprojection_error_benchmark_fast_math)
+target_compile_options(snavely_reprojection_error_benchmark_fast_math PRIVATE ${CERES_BENCHMARK_FAST_MATH_FLAGS})
+
+add_executable(linear_benchmark linear_benchmark.cc)
+add_dependencies_to_benchmark(linear_benchmark)
+target_compile_options(linear_benchmark PRIVATE ${CERES_BENCHMARK_FLAGS})
+
+add_executable(linear_benchmark_fast_math linear_benchmark.cc)
+add_dependencies_to_benchmark(linear_benchmark_fast_math)
+target_compile_options(linear_benchmark_fast_math PRIVATE ${CERES_BENCHMARK_FAST_MATH_FLAGS})
+
+if(CODE_GENERATION)
+  target_link_libraries(snavely_reprojection_error_benchmark PUBLIC SnavelyReprojectionError)
+  target_link_libraries(snavely_reprojection_error_benchmark_fast_math PUBLIC SnavelyReprojectionError)
+  target_link_libraries(linear_benchmark PUBLIC Linear1CostFunction Linear10CostFunction)
+  target_link_libraries(linear_benchmark_fast_math PUBLIC Linear1CostFunction Linear10CostFunction)
+endif()
+
diff --git a/internal/ceres/autodiff_benchmarks/linear_benchmark.cc b/internal/ceres/autodiff_benchmarks/linear_benchmark.cc
new file mode 100644
index 0000000..25f6bd6
--- /dev/null
+++ b/internal/ceres/autodiff_benchmarks/linear_benchmark.cc
@@ -0,0 +1,119 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2020 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// 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.
+//
+// Author: darius.rueckert@fau.de (Darius Rueckert)
+
+#include <memory>
+
+#include "benchmark/benchmark.h"
+#include "ceres/ceres.h"
+#include "codegen/test_utils.h"
+#include "linear_cost_functions.h"
+
+namespace ceres {
+
+#ifdef WITH_CODE_GENERATION
+static void BM_Linear1CodeGen(benchmark::State& state) {
+  double parameter_block1[] = {1.};
+  double* parameters[] = {parameter_block1};
+
+  double jacobian1[1];
+  double residuals[1];
+  double* jacobians[] = {jacobian1};
+
+  std::unique_ptr<ceres::CostFunction> cost_function(new Linear1CostFunction());
+
+  while (state.KeepRunning()) {
+    cost_function->Evaluate(parameters, residuals, jacobians);
+  }
+}
+BENCHMARK(BM_Linear1CodeGen);
+#endif
+
+static void BM_Linear1AutoDiff(benchmark::State& state) {
+  using FunctorType =
+      ceres::internal::CostFunctionToFunctor<Linear1CostFunction>;
+
+  double parameter_block1[] = {1.};
+  double* parameters[] = {parameter_block1};
+
+  double jacobian1[1];
+  double residuals[1];
+  double* jacobians[] = {jacobian1};
+
+  std::unique_ptr<ceres::CostFunction> cost_function(
+      new ceres::AutoDiffCostFunction<FunctorType, 1, 1>(new FunctorType()));
+
+  while (state.KeepRunning()) {
+    cost_function->Evaluate(parameters, residuals, jacobians);
+  }
+}
+BENCHMARK(BM_Linear1AutoDiff);
+
+#ifdef WITH_CODE_GENERATION
+static void BM_Linear10CodeGen(benchmark::State& state) {
+  double parameter_block1[] = {1., 2., 3., 4., 5., 6., 7., 8., 9., 10.};
+  double* parameters[] = {parameter_block1};
+
+  double jacobian1[10 * 10];
+  double residuals[10];
+  double* jacobians[] = {jacobian1};
+
+  std::unique_ptr<ceres::CostFunction> cost_function(
+      new Linear10CostFunction());
+
+  while (state.KeepRunning()) {
+    cost_function->Evaluate(parameters, residuals, jacobians);
+  }
+}
+BENCHMARK(BM_Linear10CodeGen);
+#endif
+
+static void BM_Linear10AutoDiff(benchmark::State& state) {
+  using FunctorType =
+      ceres::internal::CostFunctionToFunctor<Linear10CostFunction>;
+
+  double parameter_block1[] = {1., 2., 3., 4., 5., 6., 7., 8., 9., 10.};
+  double* parameters[] = {parameter_block1};
+
+  double jacobian1[10 * 10];
+  double residuals[10];
+  double* jacobians[] = {jacobian1};
+
+  std::unique_ptr<ceres::CostFunction> cost_function(
+      new ceres::AutoDiffCostFunction<FunctorType, 10, 10>(new FunctorType()));
+
+  while (state.KeepRunning()) {
+    cost_function->Evaluate(parameters, residuals, jacobians);
+  }
+}
+BENCHMARK(BM_Linear10AutoDiff);
+
+}  // namespace ceres
+
+BENCHMARK_MAIN();
diff --git a/internal/ceres/autodiff_benchmarks/linear_cost_functions.h b/internal/ceres/autodiff_benchmarks/linear_cost_functions.h
new file mode 100644
index 0000000..2a9c06c
--- /dev/null
+++ b/internal/ceres/autodiff_benchmarks/linear_cost_functions.h
@@ -0,0 +1,75 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2020 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// 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.
+//
+// Author: darius.rueckert@fau.de (Darius Rueckert)
+//
+//
+#ifndef CERES_INTERNAL_AUTODIFF_BENCHMARKS_LINEAR_COST_FUNCTIONS_H_
+#define CERES_INTERNAL_AUTODIFF_BENCHMARKS_LINEAR_COST_FUNCTIONS_H_
+
+#include "ceres/codegen/codegen_cost_function.h"
+#include "ceres/rotation.h"
+namespace ceres {
+
+struct Linear1CostFunction : public ceres::CodegenCostFunction<1, 1> {
+  template <typename T>
+  bool operator()(const T* const x, T* residuals) const {
+    residuals[0] = x[0] + T(10);
+    return true;
+  }
+#ifdef WITH_CODE_GENERATION
+#include "benchmarks/linear1costfunction.h"
+#else
+  virtual bool Evaluate(double const* const* parameters,
+                        double* residuals,
+                        double** jacobians) const {
+    return false;
+  }
+#endif
+};
+
+struct Linear10CostFunction : public ceres::CodegenCostFunction<10, 10> {
+  template <typename T>
+  bool operator()(const T* const x, T* residuals) const {
+    for (int i = 0; i < 10; ++i) {
+      residuals[i] = x[i] + T(i);
+    }
+    return true;
+  }
+#ifdef WITH_CODE_GENERATION
+#include "benchmarks/linear10costfunction.h"
+#else
+  virtual bool Evaluate(double const* const* parameters,
+                        double* residuals,
+                        double** jacobians) const {
+    return false;
+  }
+#endif
+};
+}
+#endif  // CERES_INTERNAL_AUTODIFF_BENCHMARKS_LINEAR_COST_FUNCTIONS_H_
diff --git a/internal/ceres/autodiff_cost_function_benchmark.cc b/internal/ceres/autodiff_benchmarks/rat43_benchmark.cc
similarity index 100%
rename from internal/ceres/autodiff_cost_function_benchmark.cc
rename to internal/ceres/autodiff_benchmarks/rat43_benchmark.cc
diff --git a/internal/ceres/codegen/snavely_reprojection_error.h b/internal/ceres/autodiff_benchmarks/snavely_reprojection_error.h
similarity index 81%
rename from internal/ceres/codegen/snavely_reprojection_error.h
rename to internal/ceres/autodiff_benchmarks/snavely_reprojection_error.h
index d3c9da0..aa86fd7 100644
--- a/internal/ceres/codegen/snavely_reprojection_error.h
+++ b/internal/ceres/autodiff_benchmarks/snavely_reprojection_error.h
@@ -29,20 +29,19 @@
 // Author: darius.rueckert@fau.de (Darius Rueckert)
 //
 //
-#ifndef CERES_INTERNAL_CODEGEN_SNAVELY_REPROJECTION_ERROR_H_
-#define CERES_INTERNAL_CODEGEN_SNAVELY_REPROJECTION_ERROR_H_
+#ifndef CERES_INTERNAL_AUTODIFF_BENCHMARK_SNAVELY_REPROJECTION_ERROR_H_
+#define CERES_INTERNAL_AUTODIFF_BENCHMARK_SNAVELY_REPROJECTION_ERROR_H_
 
 #include "ceres/codegen/codegen_cost_function.h"
 #include "ceres/rotation.h"
 
-namespace test {
+namespace ceres {
 
-struct SnavelyReprojectionErrorGen
-    : public ceres::CodegenCostFunction<2, 9, 3> {
-  SnavelyReprojectionErrorGen(double observed_x, double observed_y)
+struct SnavelyReprojectionError : public ceres::CodegenCostFunction<2, 9, 3> {
+  SnavelyReprojectionError(double observed_x, double observed_y)
       : observed_x(observed_x), observed_y(observed_y) {}
 
-  SnavelyReprojectionErrorGen() = default;
+  SnavelyReprojectionError() = default;
   template <typename T>
   bool operator()(const T* const camera,
                   const T* const point,
@@ -82,11 +81,17 @@
 
     return true;
   }
-
-#include "tests/snavelyreprojectionerrorgen.h"
+#ifdef WITH_CODE_GENERATION
+#include "benchmarks/snavelyreprojectionerror.h"
+#else
+  virtual bool Evaluate(double const* const* parameters,
+                        double* residuals,
+                        double** jacobians) const {
+    return false;
+  }
+#endif
   double observed_x;
   double observed_y;
 };
-
-}  // namespace test
-#endif  // CERES_INTERNAL_CODEGEN_SNAVELY_REPROJECTION_ERROR_H_
+}  // namespace ceres
+#endif  // CERES_INTERNAL_AUTODIFF_BENCHMARK_SNAVELY_REPROJECTION_ERROR_H_
diff --git a/internal/ceres/codegen/codegen_ba_benchmark.cc b/internal/ceres/autodiff_benchmarks/snavely_reprojection_error_benchmark.cc
similarity index 76%
rename from internal/ceres/codegen/codegen_ba_benchmark.cc
rename to internal/ceres/autodiff_benchmarks/snavely_reprojection_error_benchmark.cc
index 8d37d75..4a58db2 100644
--- a/internal/ceres/codegen/codegen_ba_benchmark.cc
+++ b/internal/ceres/autodiff_benchmarks/snavely_reprojection_error_benchmark.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2020 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -26,20 +26,44 @@
 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 // POSSIBILITY OF SUCH DAMAGE.
 //
-// Authors: sameeragarwal@google.com (Sameer Agarwal)
-//#define EIGEN_DONT_VECTORIZE
+// Author: darius.rueckert@fau.de (Darius Rueckert)
+
 #include <memory>
 
 #include "benchmark/benchmark.h"
 #include "ceres/ceres.h"
+#include "codegen/test_utils.h"
 #include "snavely_reprojection_error.h"
-#include "test_utils.h"
 
 namespace ceres {
 
-static void BM_BAAutoDiff(benchmark::State& state) {
+#ifdef WITH_CODE_GENERATION
+static void BM_SnavelyReprojectionCodeGen(benchmark::State& state) {
+  double parameter_block1[] = {1., 2., 3., 4., 5., 6., 7., 8., 9.};
+  double parameter_block2[] = {1., 2., 3.};
+  double* parameters[] = {parameter_block1, parameter_block2};
+
+  double jacobian1[2 * 9];
+  double jacobian2[2 * 3];
+  double residuals[2];
+  double* jacobians[] = {jacobian1, jacobian2};
+
+  const double x = 0.2;
+  const double y = 0.3;
+
+  std::unique_ptr<ceres::CostFunction> cost_function(
+      new SnavelyReprojectionError(x, y));
+
+  while (state.KeepRunning()) {
+    cost_function->Evaluate(parameters, residuals, jacobians);
+  }
+}
+BENCHMARK(BM_SnavelyReprojectionCodeGen);
+#endif
+
+static void BM_SnavelyReprojectionAutoDiff(benchmark::State& state) {
   using FunctorType =
-      ceres::internal::CostFunctionToFunctor<test::SnavelyReprojectionErrorGen>;
+      ceres::internal::CostFunctionToFunctor<SnavelyReprojectionError>;
 
   double parameter_block1[] = {1., 2., 3., 4., 5., 6., 7., 8., 9.};
   double parameter_block2[] = {1., 2., 3.};
@@ -57,37 +81,11 @@
           new FunctorType(x, y)));
 
   while (state.KeepRunning()) {
-    cost_function->Evaluate(
-        parameters, residuals, state.range(0) ? jacobians : nullptr);
+    cost_function->Evaluate(parameters, residuals, jacobians);
   }
 }
 
-static void BM_BACodeGen(benchmark::State& state) {
-  double parameter_block1[] = {1., 2., 3., 4., 5., 6., 7., 8., 9.};
-  double parameter_block2[] = {1., 2., 3.};
-  double* parameters[] = {parameter_block1, parameter_block2};
-
-  double jacobian1[2 * 9];
-  double jacobian2[2 * 3];
-  double residuals[2];
-  double* jacobians[] = {jacobian1, jacobian2};
-
-  const double x = 0.2;
-  const double y = 0.3;
-
-  std::unique_ptr<ceres::CostFunction> cost_function(
-      new test::SnavelyReprojectionErrorGen(x, y));
-
-  while (state.KeepRunning()) {
-    cost_function->Evaluate(
-        parameters, residuals, state.range(0) ? jacobians : nullptr);
-  }
-}
-
-BENCHMARK(BM_BAAutoDiff)->ArgName("Residual")->Arg(0);
-BENCHMARK(BM_BAAutoDiff)->ArgName("Residual+Jacobian")->Arg(1);
-BENCHMARK(BM_BACodeGen)->ArgName("Residual")->Arg(0);
-BENCHMARK(BM_BACodeGen)->ArgName("Residual+Jacobian")->Arg(1);
+BENCHMARK(BM_SnavelyReprojectionAutoDiff);
 
 }  // namespace ceres
 
diff --git a/internal/ceres/codegen/CMakeLists.txt b/internal/ceres/codegen/CMakeLists.txt
index 4dd75ed..4bea21f 100644
--- a/internal/ceres/codegen/CMakeLists.txt
+++ b/internal/ceres/codegen/CMakeLists.txt
@@ -88,31 +88,3 @@
     UnaryArithmetic BinaryComparison LogicalOperators ScalarFunctions
     LogicalFunctions Branches)
 endif()
-
-if (BUILD_BENCHMARKS)
-  generate_test_functor(SnavelyReprojectionErrorGen snavely_reprojection_error.h)
-
-  # Benchmark with default compiler flags
-  add_executable(codegen_ba_benchmark codegen_ba_benchmark.cc)
-  add_dependencies_to_benchmark(codegen_ba_benchmark)
-  target_link_libraries(codegen_ba_benchmark PUBLIC SnavelyReprojectionErrorGen)
-
-  # Benchmark with all optimizations (clang only)
-  if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
-
-    # Always fine
-    list(APPEND CERES_BENCHMARK_FLAGS "-march=native")
-    list(APPEND CERES_BENCHMARK_FLAGS "-fno-math-errno" "-fno-trapping-math" "-fassociative-math" "-fno-signed-zeros" "-ffp-contract=fast")
-
-    # This enables the 0*x=0 optimization
-    list(APPEND CERES_BENCHMARK_FLAGS "-fno-honor-infinities" "-fno-honor-nans")
-
-    # Total overkill but we want to make sure everything inlineable is inlined.
-    list(APPEND CERES_BENCHMARK_FLAGS "-mllvm" "-inline-threshold=1000000")
-
-    add_executable(codegen_ba_benchmark_fast_math codegen_ba_benchmark.cc)
-    add_dependencies_to_benchmark(codegen_ba_benchmark_fast_math)
-    target_link_libraries(codegen_ba_benchmark_fast_math PUBLIC SnavelyReprojectionErrorGen)
-    target_compile_options(codegen_ba_benchmark_fast_math PRIVATE ${CERES_BENCHMARK_FLAGS})
-  endif()
-endif()