Adding high-precision timer using OpenMP

(fixes issue #41)

Change-Id: Ieffe5f789a591c1e766ae619b75f0d7f6cd890f4
diff --git a/internal/ceres/CMakeLists.txt b/internal/ceres/CMakeLists.txt
index 16f25cf..cd4e6ac 100644
--- a/internal/ceres/CMakeLists.txt
+++ b/internal/ceres/CMakeLists.txt
@@ -88,6 +88,7 @@
     types.cc
     visibility_based_preconditioner.cc
     visibility.cc
+    wall_time.cc
 )
 
 If (${PROTOBUF_FOUND})
diff --git a/internal/ceres/solver.cc b/internal/ceres/solver.cc
index 66ca932..84c2756 100644
--- a/internal/ceres/solver.cc
+++ b/internal/ceres/solver.cc
@@ -37,20 +37,21 @@
 #include "ceres/program.h"
 #include "ceres/solver_impl.h"
 #include "ceres/stringprintf.h"
+#include "ceres/wall_time.h"
 
 namespace ceres {
 
 Solver::~Solver() {}
 
-// TODO(sameeragarwal): Use subsecond timers.
 void Solver::Solve(const Solver::Options& options,
                    Problem* problem,
                    Solver::Summary* summary) {
-  time_t start_time_seconds = time(NULL);
+  double start_time_seconds = internal::WallTimeInSeconds();
   internal::ProblemImpl* problem_impl =
       CHECK_NOTNULL(problem)->problem_impl_.get();
   internal::SolverImpl::Solve(options, problem_impl, summary);
-  summary->total_time_in_seconds =  time(NULL) - start_time_seconds;
+  summary->total_time_in_seconds =
+      internal::WallTimeInSeconds() - start_time_seconds;
 }
 
 void Solve(const Solver::Options& options,
diff --git a/internal/ceres/solver_impl.cc b/internal/ceres/solver_impl.cc
index 5d253dd..0ece8ee 100644
--- a/internal/ceres/solver_impl.cc
+++ b/internal/ceres/solver_impl.cc
@@ -48,6 +48,7 @@
 #include "ceres/schur_ordering.h"
 #include "ceres/stringprintf.h"
 #include "ceres/trust_region_minimizer.h"
+#include "ceres/wall_time.h"
 
 namespace ceres {
 namespace internal {
@@ -189,15 +190,16 @@
   minimizer_options.trust_region_strategy = strategy.get();
 
   TrustRegionMinimizer minimizer;
-  time_t minimizer_start_time = time(NULL);
+  double minimizer_start_time = WallTimeInSeconds();
   minimizer.Minimize(minimizer_options, parameters, summary);
-  summary->minimizer_time_in_seconds = time(NULL) - minimizer_start_time;
+  summary->minimizer_time_in_seconds =
+      WallTimeInSeconds() - minimizer_start_time;
 }
 
 void SolverImpl::Solve(const Solver::Options& original_options,
                        ProblemImpl* original_problem_impl,
                        Solver::Summary* summary) {
-  time_t solver_start_time = time(NULL);
+  double solver_start_time = WallTimeInSeconds();
   Solver::Options options(original_options);
   Program* original_program = original_problem_impl->mutable_program();
   ProblemImpl* problem_impl = original_problem_impl;
@@ -330,7 +332,7 @@
   // Collect the discontiguous parameters into a contiguous state vector.
   reduced_program->ParameterBlocksToStateVector(parameters.data());
 
-  time_t minimizer_start_time = time(NULL);
+  double minimizer_start_time = WallTimeInSeconds();
   summary->preprocessor_time_in_seconds =
       minimizer_start_time - solver_start_time;
 
@@ -350,7 +352,7 @@
     return;
   }
 
-  time_t post_process_start_time = time(NULL);
+  double post_process_start_time = WallTimeInSeconds();
 
   // Push the contiguous optimized parameters back to the user's parameters.
   reduced_program->StateVectorToParameterBlocks(parameters.data());
@@ -369,7 +371,8 @@
   // Ensure the program state is set to the user parameters on the way out.
   original_program->SetParameterBlockStatePtrsToUserStatePtrs();
   // Stick a fork in it, we're done.
-  summary->postprocessor_time_in_seconds = time(NULL) - post_process_start_time;
+  summary->postprocessor_time_in_seconds =
+      WallTimeInSeconds() - post_process_start_time;
 }
 
 // Strips varying parameters and residuals, maintaining order, and updating
diff --git a/internal/ceres/trust_region_minimizer.cc b/internal/ceres/trust_region_minimizer.cc
index d848a17..5e9fc04 100644
--- a/internal/ceres/trust_region_minimizer.cc
+++ b/internal/ceres/trust_region_minimizer.cc
@@ -47,6 +47,7 @@
 #include "ceres/sparse_matrix.h"
 #include "ceres/trust_region_strategy.h"
 #include "ceres/types.h"
+#include "ceres/wall_time.h"
 #include "glog/logging.h"
 
 namespace ceres {
@@ -117,8 +118,8 @@
 void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
                                     double* parameters,
                                     Solver::Summary* summary) {
-  time_t start_time = time(NULL);
-  time_t iteration_start_time =  start_time;
+  double start_time = WallTimeInSeconds();
+  double iteration_start_time =  start_time;
   Init(options);
 
   summary->termination_type = NO_CONVERGENCE;
@@ -204,9 +205,10 @@
   }
 
   iteration_summary.iteration_time_in_seconds =
-      time(NULL) - iteration_start_time;
-  iteration_summary.cumulative_time_in_seconds = time(NULL) - start_time +
-        summary->preprocessor_time_in_seconds;
+      WallTimeInSeconds() - iteration_start_time;
+  iteration_summary.cumulative_time_in_seconds =
+      WallTimeInSeconds() - start_time
+      + summary->preprocessor_time_in_seconds;
   summary->iterations.push_back(iteration_summary);
 
   // Call the various callbacks.
@@ -227,7 +229,7 @@
 
   int num_consecutive_invalid_steps = 0;
   while (true) {
-    iteration_start_time = time(NULL);
+    iteration_start_time = WallTimeInSeconds();
     if (iteration_summary.iteration >= options_.max_num_iterations) {
       summary->termination_type = NO_CONVERGENCE;
       VLOG(1) << "Terminating: Maximum number of iterations reached.";
@@ -248,7 +250,7 @@
     iteration_summary.step_is_valid = false;
     iteration_summary.step_is_successful = false;
 
-    const time_t strategy_start_time = time(NULL);
+    const double strategy_start_time = WallTimeInSeconds();
     TrustRegionStrategy::PerSolveOptions per_solve_options;
     per_solve_options.eta = options_.eta;
     TrustRegionStrategy::Summary strategy_summary =
@@ -258,7 +260,7 @@
                               trust_region_step.data());
 
     iteration_summary.step_solver_time_in_seconds =
-        time(NULL) - strategy_start_time;
+        WallTimeInSeconds() - strategy_start_time;
     iteration_summary.linear_solver_iterations =
         strategy_summary.num_iterations;
 
@@ -505,9 +507,10 @@
     }
 
     iteration_summary.iteration_time_in_seconds =
-        time(NULL) - iteration_start_time;
-    iteration_summary.cumulative_time_in_seconds = time(NULL) - start_time +
-        summary->preprocessor_time_in_seconds;
+        WallTimeInSeconds() - iteration_start_time;
+    iteration_summary.cumulative_time_in_seconds =
+        WallTimeInSeconds() - start_time
+        + summary->preprocessor_time_in_seconds;
     summary->iterations.push_back(iteration_summary);
 
     switch (RunCallbacks(iteration_summary)) {
diff --git a/internal/ceres/wall_time.cc b/internal/ceres/wall_time.cc
new file mode 100644
index 0000000..0dce19f
--- /dev/null
+++ b/internal/ceres/wall_time.cc
@@ -0,0 +1,49 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2012 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// 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: strandmark@google.com (Petter Strandmark)
+
+#ifdef CERES_USE_OPENMP
+#include <omp.h>
+#else
+#include <ctime>
+#endif
+
+namespace ceres {
+namespace internal {
+
+double WallTimeInSeconds() {
+#ifdef CERES_USE_OPENMP
+  return omp_get_wtime();
+#else
+  return static_cast<double>(std::time(NULL));
+#endif
+}
+
+}  // namespace internal
+}  // namespace ceres
diff --git a/internal/ceres/wall_time.h b/internal/ceres/wall_time.h
new file mode 100644
index 0000000..1a6e3bb
--- /dev/null
+++ b/internal/ceres/wall_time.h
@@ -0,0 +1,44 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2012 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// 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: strandmark@google.com (Petter Strandmark)
+
+#ifndef CERES_INTERNAL_WALL_TIME_H_
+#define CERES_INTERNAL_WALL_TIME_H_
+
+namespace ceres {
+namespace internal {
+
+// Returns time, in seconds, from some arbitrary starting point. Has very
+// high precision if OpenMP is available, otherwise only second granularity.
+double WallTimeInSeconds();
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_INTERNAL_WALL_TIME_H_