OOPS
Run.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2009-2016 ECMWF.
3  *
4  * This software is licensed under the terms of the Apache Licence Version 2.0
5  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6  * In applying this licence, ECMWF does not waive the privileges and immunities
7  * granted to it by virtue of its status as an intergovernmental organisation nor
8  * does it submit to any jurisdiction.
9  */
10 
11 #include "oops/runs/Run.h"
12 
13 #include <string>
14 
15 #include "eckit/config/LocalConfiguration.h"
16 #include "eckit/config/YAMLConfiguration.h"
17 #include "eckit/exception/Exceptions.h"
18 
19 #include "oops/runs/Application.h"
20 #include "oops/util/LibOOPS.h"
21 #include "oops/util/Logger.h"
22 #include "oops/util/ObjectCountHelper.h"
23 #include "oops/util/TimerHelper.h"
24 
25 #ifdef ENABLE_GPTL
26 #include <gptl.h>
27 #endif
28 
29 // GPTL implementation in JEDI requires retrieval of both integer and string env. var.
30 int getEnv(const std::string& env, int default_value) {
31  if (::getenv(env.c_str())) {return eckit::Translator<std::string, int>()(::getenv(env.c_str()));}
32  return default_value;
33 }
34 
35 std::string getEnv(const std::string& env, std::string default_value) {
36  if ((::getenv(env.c_str()))) {return ::getenv(env.c_str());}
37  return default_value;
38 }
39 
40 namespace oops {
41 
42  // -----------------------------------------------------------------------------
43 
44 Run::Run(int argc, char** argv) : eckit::Main(argc, argv, "OOPS_HOME"), config_(), timer_() {
45  // Initialize MPI and LibOOPS variables that require eckit::Main
46 #ifdef ENABLE_GPTL
47  int do_profile = getEnv("OOPS_PROFILE", 0); // Default is profiling disabled
48  if (do_profile) {
49  int ret;
50  // All GPTLsetutr() and GPTLsetoption() calls must precede GPTLinitialize()
51 
52  // Default JEDI behavior: Change the GPTL default from expensive gettimeofday() to inexpensive
53  // register read ("nanotime"). User can control with $OOPS_UNDERLYING_TIMER
54  std::string utr = getEnv("OOPS_UNDERLYING_TIMER", "nanotime");
55  if (utr == "nanotime") {
56  ret = GPTLsetutr(GPTLnanotime); // Use x86-specific register read to gather timings
57  } else if (utr == "gettimeofday") {
58  ret = GPTLsetutr(GPTLgettimeofday); // Use gettimeofday() to gather timings
59  } else {
60  Log::warning() << "OOPS_UNDERLYING_TIMER=" << utr << " is invalid: ignoring" << std::endl;
61  }
62 
63  // Set printout method. Another common method is full_tree, but that can create tons of output
64  ret = GPTLsetoption(GPTLprint_method, GPTLmost_frequent);
65 
66  // For MPI codes, synchronize and time collectives and receives to avoid mis-assignment
67  // of load imbalance to true MPI time. Disable by changing 1 to 0 here or via env. var.
68  int sync_mpi = getEnv("OOPS_SYNC_MPI", 1);
69  if (sync_mpi)
70  ret = GPTLsetoption(GPTLsync_mpi, 1);
71 
72  // Default behavior is do not print hi-water mark increases as the process runs
73  int dopr_memusage = getEnv("OOPS_MEMUSAGE", 0);
74  if (dopr_memusage)
75  ret = GPTLsetoption(GPTLdopr_memusage, 1); // Print growth of resident set size (RSS)
76 
77  ret = GPTLinitialize(); // Initialize GPTL timing library
78  }
79 #endif
80 
81  LibOOPS::instance().initialise();
82 
83 // Get configuration file and optional output file from command line
84  ASSERT(argc >= 2);
85  eckit::PathName configfile = argv[1];
86  if (argc == 3) {
87  eckit::PathName outputfile;
88  outputfile = argv[2];
89  LibOOPS::instance().teeOutput(outputfile);
90  }
91 
92 // Read configuration
93  config_.reset(new eckit::YAMLConfiguration(configfile));
94 
95  Log::info() << "Configuration input file is: " << configfile << std::endl;
96  Log::info() << "Full configuration is:" << *config_ << std::endl;
97 
98 // Start measuring performance
99  util::ObjectCountHelper::start();
100  util::TimerHelper::start();
101 }
102 
103 // -----------------------------------------------------------------------------
104 
106  LibOOPS::instance().finalise(); // Finalize MPI and logs
107  Log::trace() << "Oops::Run destructed" << std::endl;
108 }
109 
110 // -----------------------------------------------------------------------------
111 
112 int Run::execute(const Application & app) {
113  int status = 1;
114  Log::info() << "Run: Starting " << app << std::endl;
115  try {
116  status = app.execute(*config_);
117  }
118  catch(const eckit::Exception & e) {
119  status = 1;
120  Log::error() << e.what() << " caught in " << Here() << std::endl;
121  Log::error() << "Exception: " << app << " terminating..." << std::endl;
122  eckit::Exception::exceptionStack(eckit::Log::error(), true);
123  }
124  catch(const std::exception & e) {
125  status = 1;
126  Log::error() << "Exception: " << e.what() << std::endl;
127  Log::error() << "Exception: " << app << " terminating..." << std::endl;
128  }
129  catch(...) {
130  status = 1;
131  Log::error() << "Unknown exception: " << app << " terminating..." << std::endl;
132  }
133  Log::info() << "Run: Finishing " << app << std::endl;
134 
135 // Performance diagnostics
136  util::ObjectCountHelper::stop();
137  util::TimerHelper::stop();
138 
139  Log::info() << "Run: Finishing " << app << " with status = " << status << std::endl;
140  return status;
141 }
142 
143 // -----------------------------------------------------------------------------
144 
145 } // namespace oops
oops
The namespace for the main oops code.
Definition: ErrorCovarianceL95.cc:22
oops::Run::config_
std::unique_ptr< const eckit::YAMLConfiguration > config_
Definition: Run.h:39
oops::Run::Run
Run(int argc, char **argv)
Definition: Run.cc:44
run_time_test.status
string status
Definition: run_time_test.py:42
oops::Application::execute
virtual int execute(const eckit::Configuration &) const =0
getEnv
int getEnv(const std::string &env, int default_value)
Definition: Run.cc:30
oops::Run::execute
int execute(const Application &)
Definition: Run.cc:112
eckit
Definition: FieldL95.h:22
Run.h
Application.h
oops::Run::~Run
virtual ~Run()
Definition: Run.cc:105
oops::Application
Definition: Application.h:29
compare.error
int error
Definition: compare.py:168