• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2019 Google LLC. 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/lite/experimental/ruy/wait.h"
17 
18 #include <chrono>  // NOLINT(build/c++11)
19 
20 namespace ruy {
21 
Wait(const std::function<bool ()> & condition,const Duration & spin_duration,std::condition_variable * condvar,std::mutex * mutex)22 void Wait(const std::function<bool()>& condition, const Duration& spin_duration,
23           std::condition_variable* condvar, std::mutex* mutex) {
24   // First, trivial case where the `condition` is already true;
25   if (condition()) {
26     return;
27   }
28 
29   // Then try busy-waiting.
30   const TimePoint wait_start = Now();
31   while (Now() - wait_start < spin_duration) {
32     if (condition()) {
33       return;
34     }
35   }
36 
37   // Finally, do real passive waiting.
38   std::unique_lock<std::mutex> lock(*mutex);
39   condvar->wait(lock, condition);
40 }
41 
Wait(const std::function<bool ()> & condition,std::condition_variable * condvar,std::mutex * mutex)42 void Wait(const std::function<bool()>& condition,
43           std::condition_variable* condvar, std::mutex* mutex) {
44   // This value was empirically derived with some microbenchmark, we don't have
45   // high confidence in it.
46   //
47   // TODO(b/135595069): make this value configurable at runtime.
48   // I almost wanted to file another bug to ask for experimenting in a more
49   // principled way to tune this value better, but this would have to be tuned
50   // on real end-to-end applications and we'd expect different applications to
51   // require different tunings. So the more important point is the need for
52   // this to be controllable by the application.
53   //
54   // That this value means that we may be sleeping substantially longer
55   // than a scheduler timeslice's duration is not necessarily surprising. The
56   // idea is to pick up quickly new work after having finished the previous
57   // workload. When it's new work within the same GEMM as the previous work, the
58   // time interval that we might be busy-waiting is very small, so for that
59   // purpose it would be more than enough to sleep for 1 ms.
60   // That is all what we would observe on a GEMM benchmark. However, in a real
61   // application, after having finished a GEMM, we might do unrelated work for
62   // a little while, then start on a new GEMM. In that case the wait interval
63   // may be a little longer. There may also not be another GEMM for a long time,
64   // in which case we'll end up passively waiting below.
65   const Duration spin_duration = DurationFromMilliseconds(2);
66   Wait(condition, spin_duration, condvar, mutex);
67 }
68 
69 }  // namespace ruy
70