Mercurial > hg > orthanc
comparison UnitTestsSources/MultiThreadingTests.cpp @ 2566:c09ce3c038fc jobs
improved handling of eta
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 07 May 2018 13:51:23 +0200 |
parents | 0f06b4d5b3d0 |
children | 3caca43371f5 |
comparison
equal
deleted
inserted
replaced
2565:0f06b4d5b3d0 | 2566:c09ce3c038fc |
---|---|
391 float progress_; | 391 float progress_; |
392 Json::Value description_; | 392 Json::Value description_; |
393 | 393 |
394 public: | 394 public: |
395 JobStatus() : | 395 JobStatus() : |
396 errorCode_(ErrorCode_Success), | 396 errorCode_(ErrorCode_InternalError), |
397 progress_(0), | 397 progress_(0), |
398 description_(Json::objectValue) | 398 description_(Json::objectValue) |
399 { | 399 { |
400 } | 400 } |
401 | 401 |
440 std::string id_; | 440 std::string id_; |
441 int priority_; | 441 int priority_; |
442 JobState state_; | 442 JobState state_; |
443 boost::posix_time::ptime timestamp_; | 443 boost::posix_time::ptime timestamp_; |
444 boost::posix_time::ptime creationTime_; | 444 boost::posix_time::ptime creationTime_; |
445 boost::posix_time::ptime lastStateChangeTime_; | |
445 boost::posix_time::time_duration runtime_; | 446 boost::posix_time::time_duration runtime_; |
447 bool hasEta_; | |
446 boost::posix_time::ptime eta_; | 448 boost::posix_time::ptime eta_; |
447 JobStatus status_; | 449 JobStatus status_; |
448 | 450 |
449 public: | 451 public: |
450 JobInfo(const std::string& id, | 452 JobInfo(const std::string& id, |
451 int priority, | 453 int priority, |
452 JobState state, | 454 JobState state, |
453 const JobStatus& status, | 455 const JobStatus& status, |
454 const boost::posix_time::ptime& creationTime, | 456 const boost::posix_time::ptime& creationTime, |
457 const boost::posix_time::ptime& lastStateChangeTime, | |
455 const boost::posix_time::time_duration& runtime) : | 458 const boost::posix_time::time_duration& runtime) : |
456 id_(id), | 459 id_(id), |
457 priority_(priority), | 460 priority_(priority), |
458 state_(state), | 461 state_(state), |
459 timestamp_(boost::posix_time::microsec_clock::universal_time()), | 462 timestamp_(boost::posix_time::microsec_clock::universal_time()), |
460 creationTime_(creationTime), | 463 creationTime_(creationTime), |
464 lastStateChangeTime_(lastStateChangeTime), | |
461 runtime_(runtime), | 465 runtime_(runtime), |
466 hasEta_(false), | |
462 status_(status) | 467 status_(status) |
463 { | 468 { |
464 float ms = static_cast<float>(runtime_.total_milliseconds()); | 469 if (state_ == JobState_Running) |
465 float remaining = boost::math::llround(1.0f - status_.GetProgress()) * ms; | 470 { |
466 eta_ = timestamp_ + boost::posix_time::milliseconds(remaining); | 471 float ms = static_cast<float>(runtime_.total_milliseconds()); |
472 | |
473 if (status_.GetProgress() > 0.01f && | |
474 ms > 0.01f) | |
475 { | |
476 float remaining = boost::math::llround(1.0f - status_.GetProgress()) * ms; | |
477 eta_ = timestamp_ + boost::posix_time::milliseconds(remaining); | |
478 hasEta_ = true; | |
479 } | |
480 } | |
467 } | 481 } |
468 | 482 |
469 JobInfo() : | 483 JobInfo() : |
470 priority_(0), | 484 priority_(0), |
471 state_(JobState_Failure), | 485 state_(JobState_Failure), |
472 timestamp_(boost::posix_time::microsec_clock::universal_time()), | 486 timestamp_(boost::posix_time::microsec_clock::universal_time()), |
473 creationTime_(timestamp_), | 487 creationTime_(timestamp_), |
488 lastStateChangeTime_(timestamp_), | |
474 runtime_(boost::posix_time::milliseconds(0)), | 489 runtime_(boost::posix_time::milliseconds(0)), |
475 eta_(timestamp_) | 490 hasEta_(false) |
476 { | 491 { |
477 } | 492 } |
478 | 493 |
479 const std::string& GetIdentifier() const | 494 const std::string& GetIdentifier() const |
480 { | 495 { |
504 const boost::posix_time::time_duration& GetRuntime() const | 519 const boost::posix_time::time_duration& GetRuntime() const |
505 { | 520 { |
506 return runtime_; | 521 return runtime_; |
507 } | 522 } |
508 | 523 |
524 bool HasEstimatedTimeOfArrival() const | |
525 { | |
526 return hasEta_; | |
527 } | |
528 | |
529 bool HasCompletionTime() const | |
530 { | |
531 return (state_ == JobState_Success || | |
532 state_ == JobState_Failure); | |
533 } | |
534 | |
509 const boost::posix_time::ptime& GetEstimatedTimeOfArrival() const | 535 const boost::posix_time::ptime& GetEstimatedTimeOfArrival() const |
510 { | 536 { |
511 return eta_; | 537 if (hasEta_) |
538 { | |
539 return eta_; | |
540 } | |
541 else | |
542 { | |
543 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
544 } | |
545 } | |
546 | |
547 const boost::posix_time::ptime& GetCompletionTime() const | |
548 { | |
549 if (HasCompletionTime()) | |
550 { | |
551 return lastStateChangeTime_; | |
552 } | |
553 else | |
554 { | |
555 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
556 } | |
512 } | 557 } |
513 | 558 |
514 const JobStatus& GetStatus() const | 559 const JobStatus& GetStatus() const |
515 { | 560 { |
516 return status_; | 561 return status_; |
524 void Format(Json::Value& target) const | 569 void Format(Json::Value& target) const |
525 { | 570 { |
526 target = Json::objectValue; | 571 target = Json::objectValue; |
527 target["ID"] = id_; | 572 target["ID"] = id_; |
528 target["Priority"] = priority_; | 573 target["Priority"] = priority_; |
529 target["ErrorCode"] = EnumerationToString(status_.GetErrorCode()); | 574 target["ErrorCode"] = static_cast<int>(status_.GetErrorCode()); |
575 target["ErrorDescription"] = EnumerationToString(status_.GetErrorCode()); | |
530 target["State"] = EnumerationToString(state_); | 576 target["State"] = EnumerationToString(state_); |
531 target["Timestamp"] = boost::posix_time::to_iso_string(timestamp_); | 577 target["Timestamp"] = boost::posix_time::to_iso_string(timestamp_); |
532 target["CreationTime"] = boost::posix_time::to_iso_string(creationTime_); | 578 target["CreationTime"] = boost::posix_time::to_iso_string(creationTime_); |
533 target["Runtime"] = static_cast<uint32_t>(runtime_.total_milliseconds()); | 579 target["Runtime"] = static_cast<uint32_t>(runtime_.total_milliseconds()); |
534 target["EstimatedTimeOfArrival"] = boost::posix_time::to_iso_string(eta_); | |
535 target["Progress"] = boost::math::iround(status_.GetProgress() * 100.0f); | 580 target["Progress"] = boost::math::iround(status_.GetProgress() * 100.0f); |
536 target["Description"] = status_.GetDescription(); | 581 target["Description"] = status_.GetDescription(); |
582 | |
583 if (HasEstimatedTimeOfArrival()) | |
584 { | |
585 target["EstimatedTimeOfArrival"] = boost::posix_time::to_iso_string(GetEstimatedTimeOfArrival()); | |
586 } | |
587 | |
588 if (HasCompletionTime()) | |
589 { | |
590 target["CompletionTime"] = boost::posix_time::to_iso_string(GetCompletionTime()); | |
591 } | |
537 } | 592 } |
538 }; | 593 }; |
539 | 594 |
540 | 595 |
541 class JobHandler : public boost::noncopyable | 596 class JobHandler : public boost::noncopyable |
550 boost::posix_time::time_duration runtime_; | 605 boost::posix_time::time_duration runtime_; |
551 boost::posix_time::ptime retryTime_; | 606 boost::posix_time::ptime retryTime_; |
552 bool pauseScheduled_; | 607 bool pauseScheduled_; |
553 JobStatus lastStatus_; | 608 JobStatus lastStatus_; |
554 | 609 |
610 void Touch() | |
611 { | |
612 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time(); | |
613 | |
614 if (state_ == JobState_Running) | |
615 { | |
616 runtime_ += (now - lastStateChangeTime_); | |
617 } | |
618 | |
619 lastStateChangeTime_ = now; | |
620 } | |
621 | |
555 void SetStateInternal(JobState state) | 622 void SetStateInternal(JobState state) |
556 { | 623 { |
557 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time(); | |
558 | |
559 if (state_ == JobState_Running) | |
560 { | |
561 runtime_ += (now - lastStateChangeTime_); | |
562 } | |
563 | |
564 state_ = state; | 624 state_ = state; |
565 lastStateChangeTime_ = now; | |
566 pauseScheduled_ = false; | 625 pauseScheduled_ = false; |
626 Touch(); | |
567 } | 627 } |
568 | 628 |
569 public: | 629 public: |
570 JobHandler(IJob* job, | 630 JobHandler(IJob* job, |
571 int priority) : | 631 int priority) : |
581 { | 641 { |
582 if (job == NULL) | 642 if (job == NULL) |
583 { | 643 { |
584 throw OrthancException(ErrorCode_NullPointer); | 644 throw OrthancException(ErrorCode_NullPointer); |
585 } | 645 } |
646 | |
647 lastStatus_ = JobStatus(ErrorCode_Success, *job); | |
586 } | 648 } |
587 | 649 |
588 const std::string& GetId() const | 650 const std::string& GetId() const |
589 { | 651 { |
590 return id_; | 652 return id_; |
672 const boost::posix_time::ptime& GetCreationTime() const | 734 const boost::posix_time::ptime& GetCreationTime() const |
673 { | 735 { |
674 return creationTime_; | 736 return creationTime_; |
675 } | 737 } |
676 | 738 |
739 const boost::posix_time::ptime& GetLastStateChangeTime() const | |
740 { | |
741 return lastStateChangeTime_; | |
742 } | |
743 | |
677 const boost::posix_time::time_duration& GetRuntime() const | 744 const boost::posix_time::time_duration& GetRuntime() const |
678 { | 745 { |
679 return runtime_; | 746 return runtime_; |
680 } | 747 } |
681 | 748 |
685 } | 752 } |
686 | 753 |
687 void SetLastStatus(const JobStatus& status) | 754 void SetLastStatus(const JobStatus& status) |
688 { | 755 { |
689 lastStatus_ = status; | 756 lastStatus_ = status; |
757 Touch(); | |
690 } | 758 } |
691 }; | 759 }; |
692 | 760 |
693 | 761 |
694 class JobsRegistry : public boost::noncopyable | 762 class JobsRegistry : public boost::noncopyable |
941 target[it->first] = JobInfo(handler.GetId(), | 1009 target[it->first] = JobInfo(handler.GetId(), |
942 handler.GetPriority(), | 1010 handler.GetPriority(), |
943 handler.GetState(), | 1011 handler.GetState(), |
944 handler.GetLastStatus(), | 1012 handler.GetLastStatus(), |
945 handler.GetCreationTime(), | 1013 handler.GetCreationTime(), |
1014 handler.GetLastStateChangeTime(), | |
946 handler.GetRuntime()); | 1015 handler.GetRuntime()); |
947 } | 1016 } |
948 } | 1017 } |
949 | 1018 |
950 | 1019 |
2033 engine.GetRegistry().Submit(s, new DummyJob(), rand() % 10); | 2102 engine.GetRegistry().Submit(s, new DummyJob(), rand() % 10); |
2034 | 2103 |
2035 engine.SetWorkersCount(3); | 2104 engine.SetWorkersCount(3); |
2036 engine.Start(); | 2105 engine.Start(); |
2037 | 2106 |
2038 boost::this_thread::sleep(boost::posix_time::milliseconds(200)); | 2107 boost::this_thread::sleep(boost::posix_time::milliseconds(100)); |
2108 | |
2109 { | |
2110 typedef std::map<std::string, JobInfo> Jobs; | |
2111 | |
2112 Jobs jobs; | |
2113 engine.GetRegistry().GetJobsInfo(jobs); | |
2114 | |
2115 Json::Value v; | |
2116 for (Jobs::const_iterator it = jobs.begin(); it != jobs.end(); ++it) | |
2117 { | |
2118 Json::Value vv; | |
2119 it->second.Format(vv); | |
2120 v[it->first] = vv; | |
2121 } | |
2122 | |
2123 std::cout << v << std::endl; | |
2124 } | |
2125 std::cout << "====================================================" << std::endl; | |
2126 | |
2127 boost::this_thread::sleep(boost::posix_time::milliseconds(100)); | |
2039 | 2128 |
2040 engine.Stop(); | 2129 engine.Stop(); |
2041 | 2130 |
2042 typedef std::map<std::string, JobInfo> Jobs; | 2131 |
2043 | 2132 { |
2044 Jobs jobs; | 2133 typedef std::map<std::string, JobInfo> Jobs; |
2045 engine.GetRegistry().GetJobsInfo(jobs); | 2134 |
2046 | 2135 Jobs jobs; |
2047 Json::Value v; | 2136 engine.GetRegistry().GetJobsInfo(jobs); |
2048 for (Jobs::const_iterator it = jobs.begin(); it != jobs.end(); ++it) | 2137 |
2049 { | 2138 Json::Value v; |
2050 Json::Value vv; | 2139 for (Jobs::const_iterator it = jobs.begin(); it != jobs.end(); ++it) |
2051 it->second.Format(vv); | 2140 { |
2052 v[it->first] = vv; | 2141 Json::Value vv; |
2053 } | 2142 it->second.Format(vv); |
2054 | 2143 v[it->first] = vv; |
2055 std::cout << v << std::endl; | 2144 } |
2145 | |
2146 std::cout << v << std::endl; | |
2147 } | |
2056 } | 2148 } |