src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.hpp

changeset 3294
bca17e38de00
parent 2314
f95d63e2154a
child 3900
d2a62e0f25eb
     1.1 --- a/src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.hpp	Tue Nov 22 04:47:10 2011 -0500
     1.2 +++ b/src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.hpp	Tue Aug 09 10:16:01 2011 -0700
     1.3 @@ -45,6 +45,7 @@
     1.4  class ReleasingBarrierGCTask;
     1.5  class NotifyingBarrierGCTask;
     1.6  class WaitForBarrierGCTask;
     1.7 +class IdleGCTask;
     1.8  // A free list of Monitor*'s.
     1.9  class MonitorSupply;
    1.10  
    1.11 @@ -64,7 +65,8 @@
    1.12        unknown_task,
    1.13        ordinary_task,
    1.14        barrier_task,
    1.15 -      noop_task
    1.16 +      noop_task,
    1.17 +      idle_task
    1.18      };
    1.19      static const char* to_string(kind value);
    1.20    };
    1.21 @@ -108,6 +110,9 @@
    1.22    bool is_noop_task() const {
    1.23      return kind()==Kind::noop_task;
    1.24    }
    1.25 +  bool is_idle_task() const {
    1.26 +    return kind()==Kind::idle_task;
    1.27 +  }
    1.28    void print(const char* message) const PRODUCT_RETURN;
    1.29  protected:
    1.30    // Constructors: Only create subclasses.
    1.31 @@ -153,6 +158,7 @@
    1.32      assert(((insert_end() == NULL && remove_end() == NULL) ||
    1.33              (insert_end() != NULL && remove_end() != NULL)),
    1.34             "insert_end and remove_end don't match");
    1.35 +    assert((insert_end() != NULL) || (_length == 0), "Not empty");
    1.36      return insert_end() == NULL;
    1.37    }
    1.38    uint length() const {
    1.39 @@ -204,6 +210,8 @@
    1.40    GCTask* remove();                     // Remove from remove end.
    1.41    GCTask* remove(GCTask* task);         // Remove from the middle.
    1.42    void print(const char* message) const PRODUCT_RETURN;
    1.43 +  // Debug support
    1.44 +  void verify_length() const PRODUCT_RETURN;
    1.45  };
    1.46  
    1.47  // A GCTaskQueue that can be synchronized.
    1.48 @@ -285,12 +293,76 @@
    1.49    }
    1.50  };
    1.51  
    1.52 +// Dynamic number of GC threads
    1.53 +//
    1.54 +//  GC threads wait in get_task() for work (i.e., a task) to perform.
    1.55 +// When the number of GC threads was static, the number of tasks
    1.56 +// created to do a job was equal to or greater than the maximum
    1.57 +// number of GC threads (ParallelGCThreads).  The job might be divided
    1.58 +// into a number of tasks greater than the number of GC threads for
    1.59 +// load balancing (i.e., over partitioning).  The last task to be
    1.60 +// executed by a GC thread in a job is a work stealing task.  A
    1.61 +// GC  thread that gets a work stealing task continues to execute
    1.62 +// that task until the job is done.  In the static number of GC theads
    1.63 +// case, tasks are added to a queue (FIFO).  The work stealing tasks are
    1.64 +// the last to be added.  Once the tasks are added, the GC threads grab
    1.65 +// a task and go.  A single thread can do all the non-work stealing tasks
    1.66 +// and then execute a work stealing and wait for all the other GC threads
    1.67 +// to execute their work stealing task.
    1.68 +//  In the dynamic number of GC threads implementation, idle-tasks are
    1.69 +// created to occupy the non-participating or "inactive" threads.  An
    1.70 +// idle-task makes the GC thread wait on a barrier that is part of the
    1.71 +// GCTaskManager.  The GC threads that have been "idled" in a IdleGCTask
    1.72 +// are released once all the active GC threads have finished their work
    1.73 +// stealing tasks.  The GCTaskManager does not wait for all the "idled"
    1.74 +// GC threads to resume execution. When those GC threads do resume
    1.75 +// execution in the course of the thread scheduling, they call get_tasks()
    1.76 +// as all the other GC threads do.  Because all the "idled" threads are
    1.77 +// not required to execute in order to finish a job, it is possible for
    1.78 +// a GC thread to still be "idled" when the next job is started.  Such
    1.79 +// a thread stays "idled" for the next job.  This can result in a new
    1.80 +// job not having all the expected active workers.  For example if on
    1.81 +// job requests 4 active workers out of a total of 10 workers so the
    1.82 +// remaining 6 are "idled", if the next job requests 6 active workers
    1.83 +// but all 6 of the "idled" workers are still idle, then the next job
    1.84 +// will only get 4 active workers.
    1.85 +//  The implementation for the parallel old compaction phase has an
    1.86 +// added complication.  In the static case parold partitions the chunks
    1.87 +// ready to be filled into stacks, one for each GC thread.  A GC thread
    1.88 +// executing a draining task (drains the stack of ready chunks)
    1.89 +// claims a stack according to it's id (the unique ordinal value assigned
    1.90 +// to each GC thread).  In the dynamic case not all GC threads will
    1.91 +// actively participate so stacks with ready to fill chunks can only be
    1.92 +// given to the active threads.  An initial implementation chose stacks
    1.93 +// number 1-n to get the ready chunks and required that GC threads
    1.94 +// 1-n be the active workers.  This was undesirable because it required
    1.95 +// certain threads to participate.  In the final implementation a
    1.96 +// list of stacks equal in number to the active workers are filled
    1.97 +// with ready chunks.  GC threads that participate get a stack from
    1.98 +// the task (DrainStacksCompactionTask), empty the stack, and then add it to a
    1.99 +// recycling list at the end of the task.  If the same GC thread gets
   1.100 +// a second task, it gets a second stack to drain and returns it.  The
   1.101 +// stacks are added to a recycling list so that later stealing tasks
   1.102 +// for this tasks can get a stack from the recycling list.  Stealing tasks
   1.103 +// use the stacks in its work in a way similar to the draining tasks.
   1.104 +// A thread is not guaranteed to get anything but a stealing task and
   1.105 +// a thread that only gets a stealing task has to get a stack. A failed
   1.106 +// implementation tried to have the GC threads keep the stack they used
   1.107 +// during a draining task for later use in the stealing task but that didn't
   1.108 +// work because as noted a thread is not guaranteed to get a draining task.
   1.109 +//
   1.110 +// For PSScavenge and ParCompactionManager the GC threads are
   1.111 +// held in the GCTaskThread** _thread array in GCTaskManager.
   1.112 +
   1.113 +
   1.114  class GCTaskManager : public CHeapObj {
   1.115   friend class ParCompactionManager;
   1.116   friend class PSParallelCompact;
   1.117   friend class PSScavenge;
   1.118   friend class PSRefProcTaskExecutor;
   1.119   friend class RefProcTaskExecutor;
   1.120 + friend class GCTaskThread;
   1.121 + friend class IdleGCTask;
   1.122  private:
   1.123    // Instance state.
   1.124    NotifyDoneClosure*        _ndc;               // Notify on completion.
   1.125 @@ -298,6 +370,7 @@
   1.126    Monitor*                  _monitor;           // Notification of changes.
   1.127    SynchronizedGCTaskQueue*  _queue;             // Queue of tasks.
   1.128    GCTaskThread**            _thread;            // Array of worker threads.
   1.129 +  uint                      _active_workers;    // Number of active workers.
   1.130    uint                      _busy_workers;      // Number of busy workers.
   1.131    uint                      _blocking_worker;   // The worker that's blocking.
   1.132    bool*                     _resource_flag;     // Array of flag per threads.
   1.133 @@ -307,6 +380,8 @@
   1.134    uint                      _emptied_queue;     // Times we emptied the queue.
   1.135    NoopGCTask*               _noop_task;         // The NoopGCTask instance.
   1.136    uint                      _noop_tasks;        // Count of noop tasks.
   1.137 +  WaitForBarrierGCTask*     _idle_inactive_task;// Task for inactive workers
   1.138 +  volatile uint             _idle_workers;      // Number of idled workers
   1.139  public:
   1.140    // Factory create and destroy methods.
   1.141    static GCTaskManager* create(uint workers) {
   1.142 @@ -324,6 +399,9 @@
   1.143    uint busy_workers() const {
   1.144      return _busy_workers;
   1.145    }
   1.146 +  volatile uint idle_workers() const {
   1.147 +    return _idle_workers;
   1.148 +  }
   1.149    //     Pun between Monitor* and Mutex*
   1.150    Monitor* monitor() const {
   1.151      return _monitor;
   1.152 @@ -331,6 +409,9 @@
   1.153    Monitor * lock() const {
   1.154      return _monitor;
   1.155    }
   1.156 +  WaitForBarrierGCTask* idle_inactive_task() {
   1.157 +    return _idle_inactive_task;
   1.158 +  }
   1.159    // Methods.
   1.160    //     Add the argument task to be run.
   1.161    void add_task(GCTask* task);
   1.162 @@ -350,6 +431,10 @@
   1.163    bool should_release_resources(uint which); // Predicate.
   1.164    //     Note the release of resources by the argument worker.
   1.165    void note_release(uint which);
   1.166 +  //     Create IdleGCTasks for inactive workers and start workers
   1.167 +  void task_idle_workers();
   1.168 +  //     Release the workers in IdleGCTasks
   1.169 +  void release_idle_workers();
   1.170    // Constants.
   1.171    //     A sentinel worker identifier.
   1.172    static uint sentinel_worker() {
   1.173 @@ -375,6 +460,15 @@
   1.174    uint workers() const {
   1.175      return _workers;
   1.176    }
   1.177 +  void set_active_workers(uint v) {
   1.178 +    assert(v <= _workers, "Trying to set more workers active than there are");
   1.179 +    _active_workers = MIN2(v, _workers);
   1.180 +    assert(v != 0, "Trying to set active workers to 0");
   1.181 +    _active_workers = MAX2(1U, _active_workers);
   1.182 +  }
   1.183 +  // Sets the number of threads that will be used in a collection
   1.184 +  void set_active_gang();
   1.185 +
   1.186    NotifyDoneClosure* notify_done_closure() const {
   1.187      return _ndc;
   1.188    }
   1.189 @@ -457,8 +551,21 @@
   1.190    void reset_noop_tasks() {
   1.191      _noop_tasks = 0;
   1.192    }
   1.193 +  void increment_idle_workers() {
   1.194 +    _idle_workers++;
   1.195 +  }
   1.196 +  void decrement_idle_workers() {
   1.197 +    _idle_workers--;
   1.198 +  }
   1.199    // Other methods.
   1.200    void initialize();
   1.201 +
   1.202 + public:
   1.203 +  // Return true if all workers are currently active.
   1.204 +  bool all_workers_active() { return workers() == active_workers(); }
   1.205 +  uint active_workers() const {
   1.206 +    return _active_workers;
   1.207 +  }
   1.208  };
   1.209  
   1.210  //
   1.211 @@ -475,6 +582,8 @@
   1.212    static NoopGCTask* create();
   1.213    static NoopGCTask* create_on_c_heap();
   1.214    static void destroy(NoopGCTask* that);
   1.215 +
   1.216 +  virtual char* name() { return (char *)"noop task"; }
   1.217    // Methods from GCTask.
   1.218    void do_it(GCTaskManager* manager, uint which) {
   1.219      // Nothing to do.
   1.220 @@ -518,6 +627,8 @@
   1.221    }
   1.222    // Destructor-like method.
   1.223    void destruct();
   1.224 +
   1.225 +  virtual char* name() { return (char *)"barrier task"; }
   1.226    // Methods.
   1.227    //     Wait for this to be the only task running.
   1.228    void do_it_internal(GCTaskManager* manager, uint which);
   1.229 @@ -586,11 +697,13 @@
   1.230  // the BarrierGCTask is done.
   1.231  // This may cover many of the uses of NotifyingBarrierGCTasks.
   1.232  class WaitForBarrierGCTask : public BarrierGCTask {
   1.233 +  friend class GCTaskManager;
   1.234 +  friend class IdleGCTask;
   1.235  private:
   1.236    // Instance state.
   1.237 -  Monitor*   _monitor;                  // Guard and notify changes.
   1.238 -  bool       _should_wait;              // true=>wait, false=>proceed.
   1.239 -  const bool _is_c_heap_obj;            // Was allocated on the heap.
   1.240 +  Monitor*      _monitor;                  // Guard and notify changes.
   1.241 +  volatile bool _should_wait;              // true=>wait, false=>proceed.
   1.242 +  const bool    _is_c_heap_obj;            // Was allocated on the heap.
   1.243  public:
   1.244    virtual char* name() { return (char *) "waitfor-barrier-task"; }
   1.245  
   1.246 @@ -600,7 +713,10 @@
   1.247    static void destroy(WaitForBarrierGCTask* that);
   1.248    // Methods.
   1.249    void     do_it(GCTaskManager* manager, uint which);
   1.250 -  void     wait_for();
   1.251 +  void     wait_for(bool reset);
   1.252 +  void set_should_wait(bool value) {
   1.253 +    _should_wait = value;
   1.254 +  }
   1.255  protected:
   1.256    // Constructor.  Clients use factory, but there might be subclasses.
   1.257    WaitForBarrierGCTask(bool on_c_heap);
   1.258 @@ -613,14 +729,38 @@
   1.259    bool should_wait() const {
   1.260      return _should_wait;
   1.261    }
   1.262 -  void set_should_wait(bool value) {
   1.263 -    _should_wait = value;
   1.264 -  }
   1.265    bool is_c_heap_obj() {
   1.266      return _is_c_heap_obj;
   1.267    }
   1.268  };
   1.269  
   1.270 +// Task that is used to idle a GC task when fewer than
   1.271 +// the maximum workers are wanted.
   1.272 +class IdleGCTask : public GCTask {
   1.273 +  const bool    _is_c_heap_obj;            // Was allocated on the heap.
   1.274 + public:
   1.275 +  bool is_c_heap_obj() {
   1.276 +    return _is_c_heap_obj;
   1.277 +  }
   1.278 +  // Factory create and destroy methods.
   1.279 +  static IdleGCTask* create();
   1.280 +  static IdleGCTask* create_on_c_heap();
   1.281 +  static void destroy(IdleGCTask* that);
   1.282 +
   1.283 +  virtual char* name() { return (char *)"idle task"; }
   1.284 +  // Methods from GCTask.
   1.285 +  virtual void do_it(GCTaskManager* manager, uint which);
   1.286 +protected:
   1.287 +  // Constructor.
   1.288 +  IdleGCTask(bool on_c_heap) :
   1.289 +    GCTask(GCTask::Kind::idle_task),
   1.290 +    _is_c_heap_obj(on_c_heap) {
   1.291 +    // Nothing to do.
   1.292 +  }
   1.293 +  // Destructor-like method.
   1.294 +  void destruct();
   1.295 +};
   1.296 +
   1.297  class MonitorSupply : public AllStatic {
   1.298  private:
   1.299    // State.

mercurial