TensorFlow Serving C++ API Documentation
streaming_batch_scheduler.cc
1 /* Copyright 2016 Google Inc. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7  http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 #include "tensorflow_serving/batching/streaming_batch_scheduler.h"
17 
18 #include <functional>
19 #include <utility>
20 
21 #include "absl/types/optional.h"
22 
23 namespace tensorflow {
24 namespace serving {
25 
26 namespace internal {
27 
28 // SingleTaskScheduler
29 
30 SingleTaskScheduler::SingleTaskScheduler(Env* env, string thread_name,
31  uint64_t no_tasks_wait_time_micros)
32  : env_(env),
33  thread_name_(std::move(thread_name)),
34  no_tasks_wait_time_micros_(no_tasks_wait_time_micros) {}
35 
36 SingleTaskScheduler::~SingleTaskScheduler() { stop_.Notify(); }
37 
38 void SingleTaskScheduler::Schedule(uint64_t time_micros,
39  std::function<void()> closure) {
40  DCHECK_GE(time_micros, last_task_time_);
41  last_task_time_ = time_micros;
42 
43  {
44  mutex_lock l(mu_);
45  updated_task_ = {time_micros, std::move(closure)};
46  }
47 
48  if (thread_ == nullptr) {
49  ThreadOptions options;
50  thread_.reset(env_->StartThread(options, thread_name_,
51  [this] { this->ThreadLogic(); }));
52  }
53 }
54 
55 void SingleTaskScheduler::ThreadLogic() {
56  absl::optional<Task> current_task = absl::nullopt;
57  for (;;) {
58  // Sleep until the time specified in the current task, if any.
59  if (current_task) {
60  const uint64_t now = env_->NowMicros();
61  if (current_task->time_micros > now) {
62  env_->SleepForMicroseconds(current_task->time_micros - now);
63  }
64  }
65 
66  // Check for an updated task.
67  {
68  mutex_lock l(mu_);
69  if (updated_task_) {
70  current_task = updated_task_;
71  updated_task_ = absl::nullopt;
72  // We've got an updated task. Start over.
73  continue;
74  }
75  }
76 
77  // Invoke the closure of the current task, if any. Otherwise, we've got
78  // nothing to do, so sleep for a spell.
79  if (current_task) {
80  current_task->closure();
81  current_task = absl::nullopt;
82  } else {
83  if (stop_.HasBeenNotified()) {
84  return;
85  }
86  env_->SleepForMicroseconds(no_tasks_wait_time_micros_);
87  }
88  }
89 }
90 
91 } // namespace internal
92 
93 } // namespace serving
94 } // namespace tensorflow