00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <math.h>
00015 #include <stddef.h>
00016 #include <algorithm>
00017 #include "base/hash.h"
00018 #include <string>
00019 #include <utility>
00020 #include <vector>
00021
00022 #include "base/integral_types.h"
00023 #include "base/logging.h"
00024 #include "base/stringprintf.h"
00025 #include "base/file.h"
00026 #include "base/stl_util.h"
00027 #include "base/hash.h"
00028 #include "constraint_solver/constraint_solver.h"
00029 #include "constraint_solver/constraint_solveri.h"
00030 #include "constraint_solver/demon_profiler.pb.h"
00031
00032 namespace operations_research {
00033
00034
00035
00036
00037 class DemonProfiler : public PropagationMonitor {
00038 public:
00039 explicit DemonProfiler(Solver* const solver)
00040 : PropagationMonitor(solver),
00041 active_constraint_(NULL),
00042 active_demon_(NULL),
00043 start_time_(WallTimer::GetTimeInMicroSeconds()) {}
00044
00045 virtual ~DemonProfiler() {
00046 STLDeleteContainerPairSecondPointers(constraint_map_.begin(),
00047 constraint_map_.end());
00048 }
00049
00050 int64 CurrentTime() const {
00051 return WallTimer::GetTimeInMicroSeconds() - start_time_;
00052 }
00053
00054 virtual void BeginConstraintInitialPropagation(
00055 const Constraint* const constraint) {
00056 if (solver()->state() == Solver::IN_SEARCH) {
00057 return;
00058 }
00059
00060 CHECK(active_constraint_ == NULL);
00061 CHECK(active_demon_ == NULL);
00062 CHECK_NOTNULL(constraint);
00063 ConstraintRuns* const ct_run = new ConstraintRuns;
00064 ct_run->set_constraint_id(constraint->DebugString());
00065 ct_run->add_initial_propagation_start_time(CurrentTime());
00066 active_constraint_ = constraint;
00067 constraint_map_[constraint] = ct_run;
00068 }
00069
00070 virtual void EndConstraintInitialPropagation(
00071 const Constraint* const constraint) {
00072 CHECK_NOTNULL(active_constraint_);
00073 CHECK(active_demon_ == NULL);
00074 CHECK_NOTNULL(constraint);
00075 CHECK_EQ(constraint, active_constraint_);
00076 ConstraintRuns* const ct_run = constraint_map_[constraint];
00077 if (ct_run != NULL) {
00078 ct_run->add_initial_propagation_end_time(CurrentTime());
00079 ct_run->set_failures(0);
00080 }
00081 active_constraint_ = NULL;
00082 }
00083
00084 virtual void BeginNestedConstraintInitialPropagation(
00085 const Constraint* const constraint,
00086 const Constraint* const delayed) {
00087 if (solver()->state() == Solver::IN_SEARCH) {
00088 return;
00089 }
00090
00091 CHECK(active_constraint_ == NULL);
00092 CHECK(active_demon_ == NULL);
00093 CHECK_NOTNULL(constraint);
00094 CHECK_NOTNULL(delayed);
00095 ConstraintRuns* const ct_run = constraint_map_[constraint];
00096 ct_run->add_initial_propagation_start_time(CurrentTime());
00097 active_constraint_ = constraint;
00098 }
00099
00100 virtual void EndNestedConstraintInitialPropagation(
00101 const Constraint* const constraint,
00102 const Constraint* const delayed) {
00103 CHECK_NOTNULL(active_constraint_);
00104 CHECK(active_demon_ == NULL);
00105 CHECK_NOTNULL(constraint);
00106 CHECK_NOTNULL(delayed);
00107 CHECK_EQ(constraint, active_constraint_);
00108 ConstraintRuns* const ct_run = constraint_map_[constraint];
00109 if (ct_run != NULL) {
00110 ct_run->add_initial_propagation_end_time(CurrentTime());
00111 ct_run->set_failures(0);
00112 }
00113 active_constraint_ = NULL;
00114 }
00115
00116 virtual void RegisterDemon(const Demon* const demon) {
00117 if (solver()->state() == Solver::IN_SEARCH) {
00118 return;
00119 }
00120
00121 if (demon_map_.find(demon) == demon_map_.end()) {
00122 CHECK_NOTNULL(active_constraint_);
00123 CHECK(active_demon_ == NULL);
00124 CHECK_NOTNULL(demon);
00125 ConstraintRuns* const ct_run = constraint_map_[active_constraint_];
00126 DemonRuns* const demon_run = ct_run->add_demons();
00127 demon_run->set_demon_id(demon->DebugString());
00128 demon_run->set_failures(0);
00129 demon_map_[demon] = demon_run;
00130 demons_per_constraint_[active_constraint_].push_back(demon_run);
00131 }
00132 }
00133
00134 virtual void BeginDemonRun(const Demon* const demon) {
00135 if (demon->priority() == Solver::VAR_PRIORITY) {
00136 return;
00137 }
00138 CHECK(active_demon_ == NULL);
00139 CHECK_NOTNULL(demon);
00140 active_demon_ = demon;
00141 DemonRuns* const demon_run = demon_map_[active_demon_];
00142 if (demon_run != NULL) {
00143 demon_run->add_start_time(CurrentTime());
00144 }
00145 }
00146
00147 virtual void EndDemonRun(const Demon* const demon) {
00148 if (demon->priority() == Solver::VAR_PRIORITY) {
00149 return;
00150 }
00151 CHECK_EQ(active_demon_, demon);
00152 CHECK_NOTNULL(demon);
00153 DemonRuns* const demon_run = demon_map_[active_demon_];
00154 if (demon_run != NULL) {
00155 demon_run->add_end_time(CurrentTime());
00156 }
00157 active_demon_ = NULL;
00158 }
00159
00160 virtual void PushContext(const string& context) {}
00161 virtual void PopContext() {}
00162
00163 virtual void BeginFail() {
00164 if (active_demon_ != NULL) {
00165 DemonRuns* const demon_run = demon_map_[active_demon_];
00166 if (demon_run != NULL) {
00167 demon_run->add_end_time(CurrentTime());
00168 demon_run->set_failures(demon_run->failures() + 1);
00169 }
00170 active_demon_ = NULL;
00171
00172 active_constraint_ = NULL;
00173 } else if (active_constraint_ != NULL) {
00174 ConstraintRuns* const ct_run = constraint_map_[active_constraint_];
00175 if (ct_run != NULL) {
00176 ct_run->add_initial_propagation_end_time(CurrentTime());
00177 ct_run->set_failures(1);
00178 }
00179 active_constraint_ = NULL;
00180 }
00181 }
00182
00183
00184 virtual void RestartSearch() {
00185 STLDeleteContainerPairSecondPointers(constraint_map_.begin(),
00186 constraint_map_.end());
00187 constraint_map_.clear();
00188 demon_map_.clear();
00189 demons_per_constraint_.clear();
00190 }
00191
00192
00193 virtual void SetMin(IntExpr* const expr, int64 new_min) {}
00194 virtual void SetMax(IntExpr* const expr, int64 new_max) {}
00195 virtual void SetRange(IntExpr* const expr, int64 new_min, int64 new_max) {}
00196
00197 virtual void SetMin(IntVar* const var, int64 new_min) {}
00198 virtual void SetMax(IntVar* const var, int64 new_max) {}
00199 virtual void SetRange(IntVar* const var, int64 new_min, int64 new_max) {}
00200 virtual void RemoveValue(IntVar* const var, int64 value) {}
00201 virtual void SetValue(IntVar* const var, int64 value) {}
00202 virtual void RemoveInterval(IntVar* const var, int64 imin, int64 imax) {}
00203 virtual void SetValues(IntVar* const var,
00204 const int64* const values,
00205 int size) {}
00206 virtual void RemoveValues(IntVar* const var,
00207 const int64* const values,
00208 int size) {}
00209
00210 virtual void SetStartMin(IntervalVar* const var, int64 new_min) {}
00211 virtual void SetStartMax(IntervalVar* const var, int64 new_max) {}
00212 virtual void SetStartRange(IntervalVar* const var,
00213 int64 new_min,
00214 int64 new_max) {}
00215 virtual void SetEndMin(IntervalVar* const var, int64 new_min) {}
00216 virtual void SetEndMax(IntervalVar* const var, int64 new_max) {}
00217 virtual void SetEndRange(IntervalVar* const var,
00218 int64 new_min,
00219 int64 new_max) {}
00220 virtual void SetDurationMin(IntervalVar* const var, int64 new_min) {}
00221 virtual void SetDurationMax(IntervalVar* const var, int64 new_max) {}
00222 virtual void SetDurationRange(IntervalVar* const var,
00223 int64 new_min,
00224 int64 new_max) {}
00225 virtual void SetPerformed(IntervalVar* const var, bool value) {}
00226 virtual void RankFirst(SequenceVar* const var, int index) {}
00227 virtual void RankNotFirst(SequenceVar* const var, int index) {}
00228 virtual void RankLast(SequenceVar* const var, int index) {}
00229 virtual void RankNotLast(SequenceVar* const var, int index) {}
00230 virtual void RankSequence(SequenceVar* const var,
00231 const std::vector<int>& rank_first,
00232 const std::vector<int>& rank_last,
00233 const std::vector<int>& unperformed) {}
00234
00235
00236 void AddFakeRun(const Demon* const demon,
00237 int64 start_time,
00238 int64 end_time,
00239 bool is_fail) {
00240 CHECK_NOTNULL(demon);
00241 DemonRuns* const demon_run = demon_map_[demon];
00242 CHECK_NOTNULL(demon_run);
00243 demon_run->add_start_time(start_time);
00244 demon_run->add_end_time(end_time);
00245 if (is_fail) {
00246 demon_run->set_failures(demon_run->failures() + 1);
00247 }
00248 }
00249
00250
00251 void PrintOverview(Solver* const solver, const string& filename) {
00252 const char* const kConstraintFormat =
00253 " - Constraint: %s\n failures=%"
00254 GG_LL_FORMAT "d, initial propagation runtime=%" GG_LL_FORMAT
00255 "d us, demons=%d, demon invocations=%" GG_LL_FORMAT
00256 "d, total demon runtime=%" GG_LL_FORMAT "d us\n";
00257 const char* const kDemonFormat =
00258 " --- Demon: %s\n invocations=%" GG_LL_FORMAT
00259 "d, failures=%" GG_LL_FORMAT "d, total runtime=%" GG_LL_FORMAT
00260 "d us, [average=%.2lf, median=%.2lf, stddev=%.2lf]\n";
00261 File* const file = File::Open(filename, "w");
00262 const string model = StringPrintf("Model %s:\n",
00263 solver->model_name().c_str());
00264 if (file) {
00265 file->Write(model.c_str(), model.length());
00266 for (hash_map<const Constraint*, ConstraintRuns*>::const_iterator it =
00267 constraint_map_.begin();
00268 it != constraint_map_.end();
00269 ++it) {
00270 const Constraint* const ct = it->first;
00271 int64 fails = 0;
00272 int64 demon_invocations = 0;
00273 int64 initial_propagation_runtime = 0;
00274 int64 total_demon_runtime = 0;
00275 int demon_count = 0;
00276 ExportInformation(ct,
00277 &fails,
00278 &initial_propagation_runtime,
00279 &demon_invocations,
00280 &total_demon_runtime,
00281 &demon_count);
00282 const string constraint_message =
00283 StringPrintf(kConstraintFormat,
00284 ct->DebugString().c_str(),
00285 fails,
00286 initial_propagation_runtime,
00287 demon_count,
00288 demon_invocations,
00289 total_demon_runtime);
00290 file->Write(constraint_message.c_str(), constraint_message.length());
00291 const std::vector<DemonRuns*>& demons = demons_per_constraint_[ct];
00292 const int demon_size = demons.size();
00293 for (int demon_index = 0; demon_index < demon_size; ++demon_index) {
00294 DemonRuns* const demon_runs = demons[demon_index];
00295 int64 invocations = 0;
00296 int64 fails = 0;
00297 int64 runtime = 0;
00298 double mean_runtime = 0;
00299 double median_runtime = 0;
00300 double standard_deviation = 0.0;
00301 ExportInformation(demon_runs,
00302 &invocations,
00303 &fails,
00304 &runtime,
00305 &mean_runtime,
00306 &median_runtime,
00307 &standard_deviation);
00308 const string runs = StringPrintf(kDemonFormat,
00309 demon_runs->demon_id().c_str(),
00310 invocations,
00311 fails,
00312 runtime,
00313 mean_runtime,
00314 median_runtime,
00315 standard_deviation);
00316 file->Write(runs.c_str(), runs.length());
00317 }
00318 }
00319 }
00320 file->Close();
00321 }
00322
00323
00324 void ExportInformation(const Constraint* const constraint,
00325 int64* const fails,
00326 int64* const initial_propagation_runtime,
00327 int64* const demon_invocations,
00328 int64* const total_demon_runtime,
00329 int* demons) {
00330 CHECK_NOTNULL(constraint);
00331 ConstraintRuns* const ct_run = constraint_map_[constraint];
00332 CHECK_NOTNULL(ct_run);
00333 *demon_invocations = 0;
00334 *fails = ct_run->failures();
00335 *initial_propagation_runtime = 0;
00336 for (int i = 0; i < ct_run->initial_propagation_start_time_size(); ++i) {
00337 *initial_propagation_runtime +=
00338 ct_run->initial_propagation_end_time(i) -
00339 ct_run->initial_propagation_start_time(i);
00340 }
00341 *total_demon_runtime = 0;
00342
00343
00344 *demons = ct_run->demons_size();
00345 CHECK_EQ(*demons, demons_per_constraint_[constraint].size());
00346 for (int demon_index = 0; demon_index < *demons; ++demon_index) {
00347 const DemonRuns& demon_runs = ct_run->demons(demon_index);
00348 *fails += demon_runs.failures();
00349 CHECK_EQ(demon_runs.start_time_size(), demon_runs.end_time_size());
00350 const int runs = demon_runs.start_time_size();
00351 *demon_invocations += runs;
00352 for (int run_index = 0; run_index < runs; ++run_index) {
00353 const int64 demon_time = demon_runs.end_time(run_index) -
00354 demon_runs.start_time(run_index);
00355 *total_demon_runtime += demon_time;
00356 }
00357 }
00358 }
00359
00360 void ExportInformation(DemonRuns* const demon_runs,
00361 int64* const demon_invocations,
00362 int64* const fails,
00363 int64* const total_demon_runtime,
00364 double* const mean_demon_runtime,
00365 double* const median_demon_runtime,
00366 double* const stddev_demon_runtime) {
00367 CHECK_NOTNULL(demon_runs);
00368 CHECK_EQ(demon_runs->start_time_size(), demon_runs->end_time_size());
00369
00370 const int runs = demon_runs->start_time_size();
00371 *demon_invocations = runs;
00372 *fails = demon_runs->failures();
00373 *total_demon_runtime = 0;
00374 *mean_demon_runtime = 0.0;
00375 *median_demon_runtime = 0.0;
00376 *stddev_demon_runtime = 0.0;
00377 std::vector<double> runtimes;
00378 for (int run_index = 0; run_index < runs; ++run_index) {
00379 const int64 demon_time = demon_runs->end_time(run_index) -
00380 demon_runs->start_time(run_index);
00381 *total_demon_runtime += demon_time;
00382 runtimes.push_back(demon_time);
00383 }
00384
00385 if (runtimes.size()) {
00386 *mean_demon_runtime = (1.0L * *total_demon_runtime) / runtimes.size();
00387
00388
00389 sort(runtimes.begin(), runtimes.end());
00390 const int pivot = runtimes.size() / 2;
00391
00392 if (runtimes.size() == 1) {
00393 *median_demon_runtime = runtimes[0];
00394 } else {
00395 *median_demon_runtime = runtimes.size() % 2 == 1 ?
00396 runtimes[pivot] :
00397 (runtimes[pivot - 1] + runtimes[pivot]) / 2.0;
00398 }
00399
00400
00401 double total_deviation = 0.0f;
00402
00403 for (int i = 0; i < runtimes.size(); ++i) {
00404 total_deviation += pow(runtimes[i] - *mean_demon_runtime, 2);
00405 }
00406
00407 *stddev_demon_runtime = sqrt(total_deviation / runtimes.size());
00408 }
00409 }
00410
00411
00412
00413
00414 virtual void Install() {
00415 SearchMonitor::Install();
00416 }
00417
00418 private:
00419 const Constraint* active_constraint_;
00420 const Demon* active_demon_;
00421 const int64 start_time_;
00422 hash_map<const Constraint*, ConstraintRuns*> constraint_map_;
00423 hash_map<const Demon*, DemonRuns*> demon_map_;
00424 hash_map<const Constraint*, std::vector<DemonRuns*> > demons_per_constraint_;
00425 };
00426
00427 void Solver::ExportProfilingOverview(const string& filename) {
00428 if (demon_profiler_ != NULL) {
00429 demon_profiler_->PrintOverview(this, filename);
00430 }
00431 }
00432
00433
00434
00435 void InstallDemonProfiler(DemonProfiler* const monitor) {
00436 monitor->Install();
00437 }
00438
00439 DemonProfiler* BuildDemonProfiler(Solver* const solver) {
00440 if (solver->IsProfilingEnabled()) {
00441 return new DemonProfiler(solver);
00442 } else {
00443 return NULL;
00444 }
00445 }
00446
00447 void DeleteDemonProfiler(DemonProfiler* const monitor) {
00448 delete monitor;
00449 }
00450
00451 Demon* Solver::RegisterDemon(Demon* const demon) {
00452 CHECK_NOTNULL(demon);
00453 if (InstrumentsDemons()) {
00454 propagation_monitor_->RegisterDemon(demon);
00455 }
00456 return demon;
00457 }
00458
00459
00460
00461 void RegisterDemon(Solver* const solver,
00462 Demon* const demon,
00463 DemonProfiler* const monitor) {
00464 monitor->RegisterDemon(demon);
00465 }
00466
00467 void DemonProfilerAddFakeRun(DemonProfiler* const monitor,
00468 const Demon* const demon,
00469 int64 start_time,
00470 int64 end_time,
00471 bool is_fail) {
00472 monitor->AddFakeRun(demon, start_time, end_time, is_fail);
00473 }
00474
00475 void DemonProfilerExportInformation(DemonProfiler* const monitor,
00476 const Constraint* const constraint,
00477 int64* const fails,
00478 int64* const initial_propagation_runtime,
00479 int64* const demon_invocations,
00480 int64* const total_demon_runtime,
00481 int* const demon_count) {
00482 monitor->ExportInformation(constraint,
00483 fails,
00484 initial_propagation_runtime,
00485 demon_invocations,
00486 total_demon_runtime,
00487 demon_count);
00488 }
00489
00490 void DemonProfilerBeginInitialPropagation(DemonProfiler* const monitor,
00491 const Constraint* const constraint) {
00492 monitor->BeginConstraintInitialPropagation(constraint);
00493 }
00494
00495 void DemonProfilerEndInitialPropagation(DemonProfiler* const monitor,
00496 const Constraint* const constraint) {
00497 monitor->EndConstraintInitialPropagation(constraint);
00498 }
00499
00500 }