1 /*
   2  * Copyright (c) 2018, 2020, Red Hat, Inc. All rights reserved.
   3  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * This code is free software; you can redistribute it and/or modify it
   7  * under the terms of the GNU General Public License version 2 only, as
   8  * published by the Free Software Foundation.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  *
  24  */
  25 #ifndef SHARE_GC_SHARED_TASKTERMINATOR_HPP
  26 #define SHARE_GC_SHARED_TASKTERMINATOR_HPP
  27 
  28 #include "memory/allocation.hpp"
  29 #include "memory/padded.hpp"
  30 
  31 class Monitor;
  32 class TaskQueueSetSuper;
  33 class TerminatorTerminator;
  34 class Thread;
  35 
  36 /*
  37  * Provides a task termination protocol.
  38  *
  39  * This is an enhanced implementation of Google's OWST work stealing task termination
  40  * protocol (OWST stands for Optimized Work Stealing Threads).
  41  *
  42  * It is described in the paper:
  43  * "Wessam Hassanein. 2016. Understanding and improving JVM GC work
  44  * stealing at the data center scale. In Proceedings of the 2016 ACM
  45  * SIGPLAN International Symposium on Memory Management (ISMM 2016). ACM,
  46  * New York, NY, USA, 46-54. DOI: https://doi.org/10.1145/2926697.2926706"
  47  *
  48  * Instead of a dedicated spin-master, our implementation will let spin-master relinquish
  49  * the role before it goes to sleep/wait, allowing newly arrived threads to compete for the role.
  50  * The intention of above enhancement is to reduce spin-master's latency on detecting new tasks
  51  * for stealing and termination condition.
  52  */
  53 class TaskTerminator : public CHeapObj<mtGC> {
  54   struct DelayContext {
  55     uint _yield_count;
  56     // Number of hard spin loops done since last yield
  57     uint _hard_spin_count;
  58     // Number of iterations in the hard spin loop.
  59     uint _hard_spin_limit;
  60 
  61     DelayContext();
  62   };
  63 
  64   uint _n_threads;
  65   TaskQueueSetSuper* _queue_set;
  66 
  67   DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, 0);
  68   volatile uint _offered_termination;
  69   DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile uint));
  70 
  71   void assert_queue_set_empty() const NOT_DEBUG_RETURN;
  72 
  73   void yield();
  74 
  75   Monitor* _blocker;
  76   Thread* _spin_master;
  77 
  78   // Prepare for return from offer_termination. Gives up the spin master token
  79   // and wakes up up to tasks threads waiting on _blocker (the default value
  80   // means to wake up everyone).
  81   void prepare_for_return(Thread* this_thread, size_t tasks = SIZE_MAX);
  82 
  83   // If we should exit current termination protocol
  84   bool exit_termination(size_t tasks, TerminatorTerminator* terminator);
  85 
  86   size_t tasks_in_queue_set() const;
  87 
  88   // Perform one iteration of spin-master work.
  89   bool do_delay_step(DelayContext& delay_context);
  90 
  91   NONCOPYABLE(TaskTerminator);
  92 
  93 public:
  94   TaskTerminator(uint n_threads, TaskQueueSetSuper* queue_set);
  95   ~TaskTerminator();
  96 
  97   // The current thread has no work, and is ready to terminate if everyone
  98   // else is.  If returns "true", all threads are terminated.  If returns
  99   // "false", available work has been observed in one of the task queues,
 100   // so the global task is not complete.
 101   bool offer_termination() {
 102     return offer_termination(NULL);
 103   }
 104 
 105   // As above, but it also terminates if the should_exit_termination()
 106   // method of the terminator parameter returns true. If terminator is
 107   // NULL, then it is ignored.
 108   bool offer_termination(TerminatorTerminator* terminator);
 109 
 110   // Reset the terminator, so that it may be reused again.
 111   // The caller is responsible for ensuring that this is done
 112   // in an MT-safe manner, once the previous round of use of
 113   // the terminator is finished.
 114   void reset_for_reuse();
 115   // Same as above but the number of parallel threads is set to the
 116   // given number.
 117   void reset_for_reuse(uint n_threads);
 118 };
 119 
 120 #endif // SHARE_GC_SHARED_TASKTERMINATOR_HPP