Add a constant cost function to the autodiff benchmarks

The constant cost function is run with a variable number of
parameters to test at which point, different compilers fail
to optimize the autodiff code.

Clang achieves expected performance which fails at >50 parameters.
G++ fails already at 20 parameters

Change-Id: I75d8c683ef0011d813ec6d966d7ad58f86530f44
diff --git a/internal/ceres/autodiff_benchmarks/autodiff_benchmarks.cc b/internal/ceres/autodiff_benchmarks/autodiff_benchmarks.cc
index 252cb52..c274aa5 100644
--- a/internal/ceres/autodiff_benchmarks/autodiff_benchmarks.cc
+++ b/internal/ceres/autodiff_benchmarks/autodiff_benchmarks.cc
@@ -32,6 +32,7 @@
 
 #include "benchmark/benchmark.h"
 #include "ceres/autodiff_benchmarks/brdf_cost_function.h"
+#include "ceres/autodiff_benchmarks/constant_cost_function.h"
 #include "ceres/autodiff_benchmarks/linear_cost_functions.h"
 #include "ceres/autodiff_benchmarks/snavely_reprojection_error.h"
 #include "ceres/ceres.h"
@@ -39,6 +40,64 @@
 
 namespace ceres {
 
+template <int kParameterBlockSize>
+static void BM_ConstantAnalytic(benchmark::State& state) {
+  constexpr int num_residuals = 1;
+  std::array<double, kParameterBlockSize> parameters_values;
+  std::iota(parameters_values.begin(), parameters_values.end(), 0);
+  double* parameters[] = {parameters_values.data()};
+
+  std::array<double, num_residuals> residuals;
+
+  std::array<double, num_residuals * kParameterBlockSize> jacobian_values;
+  double* jacobians[] = {jacobian_values.data()};
+
+  std::unique_ptr<ceres::CostFunction> cost_function(
+      new ConstantCostFunction<kParameterBlockSize>());
+
+  for (auto _ : state) {
+    cost_function->Evaluate(parameters, residuals.data(), jacobians);
+  }
+}
+
+template <int kParameterBlockSize>
+static void BM_ConstantAutodiff(benchmark::State& state) {
+  constexpr int num_residuals = 1;
+  std::array<double, kParameterBlockSize> parameters_values;
+  std::iota(parameters_values.begin(), parameters_values.end(), 0);
+  double* parameters[] = {parameters_values.data()};
+
+  std::array<double, num_residuals> residuals;
+
+  std::array<double, num_residuals * kParameterBlockSize> jacobian_values;
+  double* jacobians[] = {jacobian_values.data()};
+
+  using AutoDiffFunctor = ceres::internal::CostFunctionToFunctor<
+      ConstantCostFunction<kParameterBlockSize>>;
+  std::unique_ptr<ceres::CostFunction> cost_function(
+      new ceres::AutoDiffCostFunction<AutoDiffFunctor, 1, kParameterBlockSize>(
+          new AutoDiffFunctor()));
+
+  for (auto _ : state) {
+    cost_function->Evaluate(parameters, residuals.data(), jacobians);
+  }
+}
+
+BENCHMARK_TEMPLATE(BM_ConstantAnalytic, 1);
+BENCHMARK_TEMPLATE(BM_ConstantAutodiff, 1);
+BENCHMARK_TEMPLATE(BM_ConstantAnalytic, 10);
+BENCHMARK_TEMPLATE(BM_ConstantAutodiff, 10);
+BENCHMARK_TEMPLATE(BM_ConstantAnalytic, 20);
+BENCHMARK_TEMPLATE(BM_ConstantAutodiff, 20);
+BENCHMARK_TEMPLATE(BM_ConstantAnalytic, 30);
+BENCHMARK_TEMPLATE(BM_ConstantAutodiff, 30);
+BENCHMARK_TEMPLATE(BM_ConstantAnalytic, 40);
+BENCHMARK_TEMPLATE(BM_ConstantAutodiff, 40);
+BENCHMARK_TEMPLATE(BM_ConstantAnalytic, 50);
+BENCHMARK_TEMPLATE(BM_ConstantAutodiff, 50);
+BENCHMARK_TEMPLATE(BM_ConstantAnalytic, 60);
+BENCHMARK_TEMPLATE(BM_ConstantAutodiff, 60);
+
 #ifdef WITH_CODE_GENERATION
 static void BM_Linear1CodeGen(benchmark::State& state) {
   double parameter_block1[] = {1.};
diff --git a/internal/ceres/autodiff_benchmarks/constant_cost_function.h b/internal/ceres/autodiff_benchmarks/constant_cost_function.h
new file mode 100644
index 0000000..00f39d6
--- /dev/null
+++ b/internal/ceres/autodiff_benchmarks/constant_cost_function.h
@@ -0,0 +1,63 @@
+// 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_CONSTANT_COST_FUNCTIONS_H_
+#define CERES_INTERNAL_AUTODIFF_BENCHMARKS_CONSTANT_COST_FUNCTIONS_H_
+
+#include "ceres/sized_cost_function.h"
+
+namespace ceres {
+
+template <int kParameterBlockSize>
+struct ConstantCostFunction
+    : public ceres::SizedCostFunction<1, kParameterBlockSize> {
+  template <typename T>
+  bool operator()(const T* const x, T* residuals) const {
+    residuals[0] = T(5);
+    return true;
+  }
+
+  virtual bool Evaluate(double const* const* parameters,
+                        double* residuals,
+                        double** jacobians) const {
+    residuals[0] = 5.0;
+    if (jacobians) {
+      if (jacobians[0]) {
+        memset(jacobians[0], 0, sizeof(double) * kParameterBlockSize);
+      }
+    }
+    return true;
+  }
+};
+
+}  // namespace ceres
+
+#endif  // CERES_INTERNAL_AUTODIFF_BENCHMARKS_CONSTANT_COST_FUNCTIONS_H_