wiki:AppMultiThread

Version 9 (modified by davea, 16 years ago) (diff)

--

API for multi-thread apps

T(DesignDocument)?

Why write a multi-threaded app?

The average number of cores per PC will increase over the next few years, possibly at a faster rate than the average amount of available RAM.

Depending on your application and project, it may be desirable to develop a multi-threaded application. Possible reasons to do this:

  • If your application's memory footprint is large enough that, on some PCs, there's not enough RAM to run a separate copy of the app on each CPU.
  • If you want to reduce the turnaround time of your jobs (either because of human factors, or to reduce server occupancy).

Writing and debugging a multi-threaded app is hard. You may be able to use languages like Titanium or Cilk, or libraries of numerical "kernels" that are multi-threaded.

Assumptions

We assume that applications have the following properties:

  • Given a number of CPUs N, the app can select a number of threads so that it uses N CPUs as fully as possible. This number may be less than or greater than N; it may be 1.
  • There may be periods during the app's execution during which its number of threads becomes less than N; e.g. there may be periods during which the app is not parallel, and the number of threads becomes 1.

Scheduling policy

Suppose an app A uses NT(A) threads. Ideally, on a host with N CPUs, we want NT(A), summed over running apps, to be at least N; otherwise CPU time is wasted. However, if it's much more than N, we increase latency without increasing throughput, we may increase synchronization overhead, and we may use more RAM than needed.

Our scheduling policy, given N CPUs, is:

  • Instruct applications to use enough threads for N CPUs, and monitor how many threads NT(A) they actually use.
  • Given a set of runnable applications A1, A2 (ordered by priority or deadline), run applications until the number of actual threads exceeds N.
  • Reschedule the CPUs whenever NT(A) changes for a running app A.

API

API functions:

int boinc_ncpus();

This returns the number of available CPUs (this may be less than the number of physical CPUs, if the user preferences specify this). An application should call boinc_ncpus() on startup to decide how many threads to use. It may optionally call it again at points where it is able to change its number of threads, in case the number of available CPUs has changed (e.g. as the computer becomes idle and busy).

void boinc_nthreads(int actual);

An application calls this to report its actual number of threads. It should call this whenever this quantity changes.

A WU DB record can specify "max average threads", an estimate of the average number of threads on a host with arbitrarily many CPUs. This is used by the client and scheduler to estimate completion time.

Implementation

App init file:

  • <ncpus_available>

Shared-memory messages:

  • core->app (process control channel): <ncpus_available>
  • app->core (process control channel): <nthreads>

State:

  • ACTIVE_TASK::nthreads_actual

Implementation (enforce_schedule()): as we schedule jobs, decrement CPU count by actual_nthreads. rr_simulation() needs to be modified too.

Notes

The average number of processors used, Ncpus(A), may be less (because of I/O or synchronization).