Removed "proc ==(a: syserr, b: err_t)" and three other comparisons involving err_t in modules/standard/SysBasic.chpl.

[Reviewed/discussed with Brad and Michael.]

I am removing the following comparisons:

  inline proc ==(a: syserr, b: err_t)
  inline proc ==(a: err_t, b: syserr)
  inline proc !=(a: syserr, b: err_t)
  inline proc !=(a: err_t, b: syserr)

Explanation: Consider, for example, the first of the above.
SysBasic.chpl defined, since r21066:

  inline proc ==(a: syserr, b: err_t)
  inline proc ==(a: syserr, b: int(32))
  inline proc ==(a: syserr, b: int(64))

Since err_t is int(32), the first two functions always will be ambiguous
whenever one of them applies. I don't know why we have not hit this
ambiguity in our current code base, but it can get exposed.

Michael would like to make err_t distinct from int(32),
at which point this patch will need to be reverted.

Alternatively to removing, we could guard each function with
  where !_isIntegralType(err_t)
but that would make the current code less elegant.

Michael explains err_t:

  syserr is a pointer-based structure possiblycontaining an error code.
In order for it to be useful, one needs to be able to compare against
the system error codes like ENOENT or EINVAL. These should be wrapped in
the compiler as err_t values.

  I would rather solve the problem by having err_t be a different type
(with the same representation) that can compare against int(32); that
is, right now we have

 extern type err_t = c_int;

which makes err_t another name for c_int, but what I actually want is
for err_t to be a different type that has the same representation, and
to explicitly set which methods allow the combination of err_t and c_int
(as with == ).

  Of course, one way to do that would be to make err_t an opaque type...
but a more general way would be to support the generation of a new type
in these situations (e.g. new type err_t = c_int).

git-svn-id: 88467cb1fb04b8a755be7e1ee1026be4190196ef@22472 3a8e244f-b0f2-452b-bcba-4c88e055c3ca

/* BASIC TYPES */
use SysCTypes;

extern type c_float = real(32);
extern type c_double = real(64);
/*extern type c_wchar_t = uint(32); */
extern type off_t = int(64);
extern type mode_t = uint(32);
extern type socklen_t = int(32);

// C File type
//type c_file = _file;

// stdin/stdout/sterr
//extern proc chpl_cstdin():_file;
extern proc chpl_cstdout():_file;
extern proc chpl_cstderr():_file;
extern proc chpl_cnullfile():_file;

// system error number.
extern type syserr; // = c_int, opaque so we can manually override ==,!=,etc
extern type err_t = c_int;
// When to use syserr and when to use err_t?
// err_t is a system error code (a c_int by a nicer name).
// syserr is an enhanced error that might also include an
// error message. All user-facing Chapel library code,
// or user Chapel code, should generally use syserr.
// When wrapping functions or declaring them in C,
// use err_t to indicate that a function is returning
// an error code.

// system file descriptor.
extern type fd_t = c_int;

// NULL
extern const c_nil:c_void_ptr;
// To generate legal C prototypes, we have to manually instantiate this
// prototype for each pointer type that might be associated with 'x'.
pragma "no prototype"
extern proc is_c_nil(x):c_int;

// local C pointer class used in C integration.
// Similar to _ddata from ChapelBase, but differs
// from _ddata because it can never be wide.
pragma "data class"
pragma "no object"
pragma "no default functions"
pragma "no wide class"
class c_ptr {
  type eltType;
  inline proc this(i: integral) var {
    return __primitive("array_get", this, i);
  }
  inline proc deref() var {
    return __primitive("array_get", this, 0);
  }
}

inline proc _cast(type t, x) where t:c_ptr && x:_nilType {
  return __primitive("cast", t, x);
}

inline proc c_calloc(type eltType, size: integral) {
  var ret:c_ptr(eltType);
  __primitive("array_alloc", ret, eltType, size);
  init_elts(ret, size, eltType);
  return ret;
}

inline proc c_free(data: c_ptr) {
  __primitive("array_free", data);
}

inline proc ==(a: c_ptr, b: c_ptr) where a.eltType == b.eltType {
  return __primitive("ptr_eq", a, b);
}
inline proc ==(a: c_ptr, b: _nilType) {
  return __primitive("ptr_eq", a, nil);
}
inline proc ==(a: _nilType, b: c_ptr) {
  return __primitive("ptr_eq", nil, b);
}

inline proc !=(a: c_ptr, b: c_ptr) where a.eltType == b.eltType {
  return __primitive("ptr_neq", a, b);
}
inline proc !=(a: c_ptr, b: _nilType) {
  return __primitive("ptr_neq", a, nil);
}
inline proc !=(a: _nilType, b: c_ptr) {
  return __primitive("ptr_neq", nil, b);
}

inline proc _cond_test(x: c_ptr) return x != nil;

inline proc !(x: c_ptr) return x == nil;
extern proc c_ptrTo(ref x:?t):c_ptr(t);

// C strings
//extern type c_string; is a built-in primitive type

inline proc toString(cstr:c_string):string {
  return __primitive("string_from_c_string", cstr, 0, 0);
}
inline proc toString(cstr:c_string, len:int):string {
  return __primitive("string_from_c_string", cstr, 1, len);
}

inline proc string.c_str():c_string {
  return __primitive("c_string_from_string", this);
}

// error numbers

extern proc qio_err_eq(a:syserr, b:syserr):c_int;
extern proc qio_err_to_int(a:syserr):int(32);
extern proc qio_int_to_err(a:int(32)):syserr;
extern proc qio_err_iserr(a:syserr):c_int;

inline proc ENOERR return 0:err_t;

// When err_t is no longer just int(32), will need to add cases for err_t too.
inline proc ==(a: syserr, b: syserr) return (qio_err_eq(a,b) != 0:c_int);
inline proc ==(a: syserr, b: int(32)) return (qio_err_to_int(a) == b:int(32));
inline proc ==(a: syserr, b: int(64)) return (qio_err_to_int(a) == b:int(32));
inline proc ==(a: int(32), b: syserr) return (a:int(32) == qio_err_to_int(b));
inline proc ==(a: int(64), b: syserr) return (a:int(32) == qio_err_to_int(b));
inline proc !=(a: syserr, b: syserr) return !(a == b);
inline proc !=(a: syserr, b: int(32)) return !(a == b);
inline proc !=(a: syserr, b: int(64)) return !(a == b);
inline proc !=(a: int(32), b: syserr) return !(a == b);
inline proc !=(a: int(64), b: syserr) return !(a == b);
inline proc !(a: syserr) return (qio_err_iserr(a) == 0:c_int);
inline proc _cond_test(a: syserr) return (qio_err_iserr(a) != 0:c_int);
inline proc _cast(type t, x: syserr) where t == int(32)
  return qio_err_to_int(x);
inline proc _cast(type t, x: syserr) where t == int(64)
  return qio_err_to_int(x):int(64);
inline proc _cast(type t, x: int(32)) where t == syserr
  return qio_int_to_err(x);
inline proc _cast(type t, x: int(64)) where t == syserr
  return qio_int_to_err(x:int(32));
inline proc =(ret:syserr, x:syserr) return x;
inline proc =(ret:syserr, x:int(32)) return qio_int_to_err(x);
inline proc =(ret:syserr, x:int(64)) return qio_int_to_err(x:int(32));
inline proc =(ret:err_t, x:syserr) return qio_err_to_int(x):err_t;

// end of file
extern proc chpl_macro_int_EEOF():err_t;
inline proc EEOF return chpl_macro_int_EEOF():err_t;
extern proc chpl_macro_int_ESHORT():err_t;
inline proc ESHORT return chpl_macro_int_ESHORT():err_t;
extern proc chpl_macro_int_EFORMAT():err_t;
inline proc EFORMAT return chpl_macro_int_EFORMAT():err_t;

// system error numbers
extern const E2BIG:err_t;
extern const EACCES:err_t;
extern const EADDRINUSE:err_t;
extern const EADDRNOTAVAIL:err_t;
extern const EAFNOSUPPORT:err_t;
extern const EAGAIN:err_t;
extern const EALREADY:err_t;
extern const EBADE:err_t;
extern const EBADF:err_t;
extern const EBADFD:err_t;
extern const EBADMSG:err_t;
extern const EBADR:err_t;
extern const EBADRQC:err_t;
extern const EBADSLT:err_t;
extern const EBUSY:err_t;
extern const ECANCELED:err_t;
extern const ECHILD:err_t;
extern const ECHRNG:err_t;
extern const ECOMM:err_t;
extern const ECONNABORTED:err_t;
extern const ECONNREFUSED:err_t;
extern const ECONNRESET:err_t;
extern const EDEADLK:err_t;
extern const EDESTADDRREQ:err_t;
extern const EDOM:err_t;
extern const EDQUOT:err_t;
extern const EEXIST:err_t;
extern const EFAULT:err_t;
extern const EFBIG:err_t;
extern const EHOSTDOWN:err_t;
extern const EHOSTUNREACH:err_t;
extern const EIDRM:err_t;
extern const EILSEQ:err_t;
extern const EINPROGRESS:err_t;
extern const EINTR:err_t;
extern const EINVAL:err_t;
extern const EIO:err_t;
extern const EISCONN:err_t;
extern const EISDIR:err_t;
extern const EISNAM:err_t;
extern const EKEYEXPIRED:err_t;
extern const EKEYREJECTED:err_t;
extern const EKEYREVOKED:err_t;
extern const EL2HLT:err_t;
extern const EL2NSYNC:err_t;
extern const EL3HLT:err_t;
extern const EL3RST:err_t;
extern const ELIBACC:err_t;
extern const ELIBBAD:err_t;
extern const ELIBMAX:err_t;
extern const ELIBSCN:err_t;
extern const ELIBEXEC:err_t;
extern const ELOOP:err_t;
extern const EMEDIUMTYPE:err_t;
extern const EMFILE:err_t;
extern const EMLINK:err_t;
extern const EMSGSIZE:err_t;
extern const EMULTIHOP:err_t;
extern const ENAMETOOLONG:err_t;
extern const ENETDOWN:err_t;
extern const ENETRESET:err_t;
extern const ENETUNREACH:err_t;
extern const ENFILE:err_t;
extern const ENOBUFS:err_t;
extern const ENODATA:err_t;
extern const ENODEV:err_t;
extern const ENOENT:err_t;
extern const ENOEXEC:err_t;
extern const ENOKEY:err_t;
extern const ENOLCK:err_t;
extern const ENOLINK:err_t;
extern const ENOMEDIUM:err_t;
extern const ENOMEM:err_t;
extern const ENOMSG:err_t;
extern const ENONET:err_t;
extern const ENOPKG:err_t;
extern const ENOPROTOOPT:err_t;
extern const ENOSPC:err_t;
extern const ENOSR:err_t;
extern const ENOSTR:err_t;
extern const ENOSYS:err_t;
extern const ENOTBLK:err_t;
extern const ENOTCONN:err_t;
extern const ENOTDIR:err_t;
extern const ENOTEMPTY:err_t;
extern const ENOTSOCK:err_t;
extern const ENOTSUP:err_t;
extern const ENOTTY:err_t;
extern const ENOTUNIQ:err_t;
extern const ENXIO:err_t;
extern const EOPNOTSUPP:err_t;
extern const EOVERFLOW:err_t;
extern const EPERM:err_t;
extern const EPFNOSUPPORT:err_t;
extern const EPIPE:err_t;
extern const EPROTO:err_t;
extern const EPROTONOSUPPORT:err_t;
extern const EPROTOTYPE:err_t;
extern const ERANGE:err_t;
extern const EREMCHG:err_t;
extern const EREMOTE:err_t;
extern const EREMOTEIO:err_t;
extern const ERESTART:err_t;
extern const EROFS:err_t;
extern const ESHUTDOWN:err_t;
extern const ESPIPE:err_t;
extern const ESOCKTNOSUPPORT:err_t;
extern const ESRCH:err_t;
extern const ESTALE:err_t;
extern const ESTRPIPE:err_t;
extern const ETIME:err_t;
extern const ETIMEDOUT:err_t;
extern const ETXTBSY:err_t;
extern const EUCLEAN:err_t;
extern const EUNATCH:err_t;
extern const EUSERS:err_t;
extern const EWOULDBLOCK:err_t;
extern const EXDEV:err_t;
extern const EXFULL:err_t;

/* BASIC TYPES */
use SysCTypes;

extern type c_float = real(32);
extern type c_double = real(64);
/*extern type c_wchar_t = uint(32); */
extern type off_t = int(64);
extern type mode_t = uint(32);
extern type socklen_t = int(32);

// C File type
//type c_file = _file;

// stdin/stdout/sterr
//extern proc chpl_cstdin():_file;
extern proc chpl_cstdout():_file;
extern proc chpl_cstderr():_file;
extern proc chpl_cnullfile():_file;

// system error number.
extern type syserr; // = c_int, opaque so we can manually override ==,!=,etc
extern type err_t = c_int;
// When to use syserr and when to use err_t?
// err_t is a system error code (a c_int by a nicer name).
// syserr is an enhanced error that might also include an
// error message. All user-facing Chapel library code,
// or user Chapel code, should generally use syserr.
// When wrapping functions or declaring them in C,
// use err_t to indicate that a function is returning
// an error code.

// system file descriptor.
extern type fd_t = c_int;

// NULL
extern const c_nil:c_void_ptr;
// To generate legal C prototypes, we have to manually instantiate this
// prototype for each pointer type that might be associated with 'x'.
pragma "no prototype"
extern proc is_c_nil(x):c_int;

// local C pointer class used in C integration.
// Similar to _ddata from ChapelBase, but differs
// from _ddata because it can never be wide.
pragma "data class"
pragma "no object"
pragma "no default functions"
pragma "no wide class"
class c_ptr {
  type eltType;
  inline proc this(i: integral) var {
    return __primitive("array_get", this, i);
  }
  inline proc deref() var {
    return __primitive("array_get", this, 0);
  }
}

inline proc _cast(type t, x) where t:c_ptr && x:_nilType {
  return __primitive("cast", t, x);
}

inline proc c_calloc(type eltType, size: integral) {
  var ret:c_ptr(eltType);
  __primitive("array_alloc", ret, eltType, size);
  init_elts(ret, size, eltType);
  return ret;
}

inline proc c_free(data: c_ptr) {
  __primitive("array_free", data);
}

inline proc ==(a: c_ptr, b: c_ptr) where a.eltType == b.eltType {
  return __primitive("ptr_eq", a, b);
}
inline proc ==(a: c_ptr, b: _nilType) {
  return __primitive("ptr_eq", a, nil);
}
inline proc ==(a: _nilType, b: c_ptr) {
  return __primitive("ptr_eq", nil, b);
}

inline proc !=(a: c_ptr, b: c_ptr) where a.eltType == b.eltType {
  return __primitive("ptr_neq", a, b);
}
inline proc !=(a: c_ptr, b: _nilType) {
  return __primitive("ptr_neq", a, nil);
}
inline proc !=(a: _nilType, b: c_ptr) {
  return __primitive("ptr_neq", nil, b);
}

inline proc _cond_test(x: c_ptr) return x != nil;

inline proc !(x: c_ptr) return x == nil;
extern proc c_ptrTo(ref x:?t):c_ptr(t);

// C strings
//extern type c_string; is a built-in primitive type

inline proc toString(cstr:c_string):string {
  return __primitive("string_from_c_string", cstr, 0, 0);
}
inline proc toString(cstr:c_string, len:int):string {
  return __primitive("string_from_c_string", cstr, 1, len);
}

inline proc string.c_str():c_string {
  return __primitive("c_string_from_string", this);
}

// error numbers

extern proc qio_err_eq(a:syserr, b:syserr):c_int;
extern proc qio_err_to_int(a:syserr):int(32);
extern proc qio_int_to_err(a:int(32)):syserr;
extern proc qio_err_iserr(a:syserr):c_int;

inline proc ENOERR return 0:err_t;

inline proc ==(a: syserr, b: syserr) return (qio_err_eq(a,b) != 0:c_int);
inline proc ==(a: syserr, b: err_t) return (qio_err_to_int(a) == b:int(32));
inline proc ==(a: syserr, b: int(32)) return (qio_err_to_int(a) == b:int(32));
inline proc ==(a: syserr, b: int(64)) return (qio_err_to_int(a) == b:int(32));
inline proc ==(a: err_t, b: syserr) return (a:int(32) == qio_err_to_int(b));
inline proc ==(a: int(32), b: syserr) return (a:int(32) == qio_err_to_int(b));
inline proc ==(a: int(64), b: syserr) return (a:int(32) == qio_err_to_int(b));
inline proc !=(a: syserr, b: syserr) return !(a == b);
inline proc !=(a: syserr, b: err_t) return !(a == b);
inline proc !=(a: syserr, b: int(32)) return !(a == b);
inline proc !=(a: syserr, b: int(64)) return !(a == b);
inline proc !=(a: err_t, b: syserr) return !(a == b);
inline proc !=(a: int(32), b: syserr) return !(a == b);
inline proc !=(a: int(64), b: syserr) return !(a == b);
inline proc !(a: syserr) return (qio_err_iserr(a) == 0:c_int);
inline proc _cond_test(a: syserr) return (qio_err_iserr(a) != 0:c_int);
inline proc _cast(type t, x: syserr) where t == int(32)
  return qio_err_to_int(x);
inline proc _cast(type t, x: syserr) where t == int(64)
  return qio_err_to_int(x):int(64);
inline proc _cast(type t, x: int(32)) where t == syserr
  return qio_int_to_err(x);
inline proc _cast(type t, x: int(64)) where t == syserr
  return qio_int_to_err(x:int(32));
inline proc =(ret:syserr, x:syserr) return x;
inline proc =(ret:syserr, x:int(32)) return qio_int_to_err(x);
inline proc =(ret:syserr, x:int(64)) return qio_int_to_err(x:int(32));
inline proc =(ret:err_t, x:syserr) return qio_err_to_int(x):err_t;

// end of file
extern proc chpl_macro_int_EEOF():err_t;
inline proc EEOF return chpl_macro_int_EEOF():err_t;
extern proc chpl_macro_int_ESHORT():err_t;
inline proc ESHORT return chpl_macro_int_ESHORT():err_t;
extern proc chpl_macro_int_EFORMAT():err_t;
inline proc EFORMAT return chpl_macro_int_EFORMAT():err_t;

// system error numbers
extern const E2BIG:err_t;
extern const EACCES:err_t;
extern const EADDRINUSE:err_t;
extern const EADDRNOTAVAIL:err_t;
extern const EAFNOSUPPORT:err_t;
extern const EAGAIN:err_t;
extern const EALREADY:err_t;
extern const EBADE:err_t;
extern const EBADF:err_t;
extern const EBADFD:err_t;
extern const EBADMSG:err_t;
extern const EBADR:err_t;
extern const EBADRQC:err_t;
extern const EBADSLT:err_t;
extern const EBUSY:err_t;
extern const ECANCELED:err_t;
extern const ECHILD:err_t;
extern const ECHRNG:err_t;
extern const ECOMM:err_t;
extern const ECONNABORTED:err_t;
extern const ECONNREFUSED:err_t;
extern const ECONNRESET:err_t;
extern const EDEADLK:err_t;
extern const EDESTADDRREQ:err_t;
extern const EDOM:err_t;
extern const EDQUOT:err_t;
extern const EEXIST:err_t;
extern const EFAULT:err_t;
extern const EFBIG:err_t;
extern const EHOSTDOWN:err_t;
extern const EHOSTUNREACH:err_t;
extern const EIDRM:err_t;
extern const EILSEQ:err_t;
extern const EINPROGRESS:err_t;
extern const EINTR:err_t;
extern const EINVAL:err_t;
extern const EIO:err_t;
extern const EISCONN:err_t;
extern const EISDIR:err_t;
extern const EISNAM:err_t;
extern const EKEYEXPIRED:err_t;
extern const EKEYREJECTED:err_t;
extern const EKEYREVOKED:err_t;
extern const EL2HLT:err_t;
extern const EL2NSYNC:err_t;
extern const EL3HLT:err_t;
extern const EL3RST:err_t;
extern const ELIBACC:err_t;
extern const ELIBBAD:err_t;
extern const ELIBMAX:err_t;
extern const ELIBSCN:err_t;
extern const ELIBEXEC:err_t;
extern const ELOOP:err_t;
extern const EMEDIUMTYPE:err_t;
extern const EMFILE:err_t;
extern const EMLINK:err_t;
extern const EMSGSIZE:err_t;
extern const EMULTIHOP:err_t;
extern const ENAMETOOLONG:err_t;
extern const ENETDOWN:err_t;
extern const ENETRESET:err_t;
extern const ENETUNREACH:err_t;
extern const ENFILE:err_t;
extern const ENOBUFS:err_t;
extern const ENODATA:err_t;
extern const ENODEV:err_t;
extern const ENOENT:err_t;
extern const ENOEXEC:err_t;
extern const ENOKEY:err_t;
extern const ENOLCK:err_t;
extern const ENOLINK:err_t;
extern const ENOMEDIUM:err_t;
extern const ENOMEM:err_t;
extern const ENOMSG:err_t;
extern const ENONET:err_t;
extern const ENOPKG:err_t;
extern const ENOPROTOOPT:err_t;
extern const ENOSPC:err_t;
extern const ENOSR:err_t;
extern const ENOSTR:err_t;
extern const ENOSYS:err_t;
extern const ENOTBLK:err_t;
extern const ENOTCONN:err_t;
extern const ENOTDIR:err_t;
extern const ENOTEMPTY:err_t;
extern const ENOTSOCK:err_t;
extern const ENOTSUP:err_t;
extern const ENOTTY:err_t;
extern const ENOTUNIQ:err_t;
extern const ENXIO:err_t;
extern const EOPNOTSUPP:err_t;
extern const EOVERFLOW:err_t;
extern const EPERM:err_t;
extern const EPFNOSUPPORT:err_t;
extern const EPIPE:err_t;
extern const EPROTO:err_t;
extern const EPROTONOSUPPORT:err_t;
extern const EPROTOTYPE:err_t;
extern const ERANGE:err_t;
extern const EREMCHG:err_t;
extern const EREMOTE:err_t;
extern const EREMOTEIO:err_t;
extern const ERESTART:err_t;
extern const EROFS:err_t;
extern const ESHUTDOWN:err_t;
extern const ESPIPE:err_t;
extern const ESOCKTNOSUPPORT:err_t;
extern const ESRCH:err_t;
extern const ESTALE:err_t;
extern const ESTRPIPE:err_t;
extern const ETIME:err_t;
extern const ETIMEDOUT:err_t;
extern const ETXTBSY:err_t;
extern const EUCLEAN:err_t;
extern const EUNATCH:err_t;
extern const EUSERS:err_t;
extern const EWOULDBLOCK:err_t;
extern const EXDEV:err_t;
extern const EXFULL:err_t;


Added thread safe state to the load balancer.

git-svn-id: 88467cb1fb04b8a755be7e1ee1026be4190196ef@10991 3a8e244f-b0f2-452b-bcba-4c88e055c3ca

/*
**  UTS -- The Unbalanced Tree Search
**
**  James Dinan <dinan@cray.com>
**  July, 2007
*/

use Math;
use Time;
use sha1_rng;
use dequeue;

/**** UTS TYPES ****/
enum NodeDistrib { Binomial, Geometric, Hybrid, Constant };
enum GeoDistrib  { GeoFixed, GeoLinear, GeoPoly, GeoCyclic };

/**** COMPILE PARAMS ****/
config param debug:    bool = false;
config param parallel: bool = true;
param uts_version:   string = "2.1";

/**** UTS CONFIG VARS ****/
config const SEED:        uint = 16;    // Seed for the hash of the root node
config const MAX_CHILDREN: int = 10;    // Max. Children a node may have
config const B_0:          int = 4;     // Branching Factor
config const MAX_DEPTH:    int = 6;     // Depth limit
config const nonLeafProb: real = 0.10;  // Probability of a non-leaf (binomial)
config const nonLeafBF:    int = 4;     // Non-leaf branching factor (binomial)
config const shiftDepth:  real = 0.5;   // Depth at which hybrid trees go from Geo=>Bin

config const distrib: NodeDistrib = Geometric;
config const geoDist: GeoDistrib  = GeoFixed;

// Parallel search parameters
config const MAX_THREADS:   int = 4;
config const chunkSize:     int = 10;
config const threading_throttle = 1;

// Global thread counter
var thread_cnt: sync int = 0;
var threads_spawned: int = 0; // "Locked" by thread_cnt

// Global stats, updated by a thread when it exits
var global_count: sync int = 0;
var global_maxDepth: sync int = 0;

// Shared termination detection
var terminated: single bool;

/**** State of the load balancer ****/
record LDBalanceState {
  var throttle_period = threading_throttle;
  var throttle: int;
}

/**** UTS TreeNode Class ****/
class TreeNode {
  var depth:   int;
  var hash:    string = "__Here_be_dragons__";  // Handle delicately, if this is ever copied, things will go off the rails

  var nChildren: int = 0;

  // Generate this node's children
  def genChildren(inout q: DeQueue(TreeNode)): int {
    select distrib {
      when Geometric do
        nChildren = numGeoChildren(geoDist);
      when Binomial do
        nChildren = numBinChildren();
      when Hybrid do
        nChildren = numHybridChildren();
      when Constant do
        nChildren = numConstChildren();
    }

    if debug then writeln("Constructing ", nChildren, " children");

    forall i in [0..nChildren-1] {
      if debug then writeln("  + (", depth, ", ", i, ")");
      var t = TreeNode(depth+1);
      rng_spawn(hash, t.hash, i);
      q.pushTop(t);
    }

    return nChildren;
  }

  // Constant Distribution: Find the number of children
  //  Note: This is a _balanced_ tree.
  def numConstChildren(): int {
    return if depth < MAX_DEPTH then B_0 else 0;
  }

  // Hybrid trees are geometric at the top of the tree and binomial
  // below a certain depth.
  def numHybridChildren(): int {
    if (depth < shiftDepth * MAX_DEPTH) then
      return numGeoChildren(geoDist);

    else
      return numBinChildren();
  }

  // Binomial Distribution: Find the number of children
  //  Note: distribution is identical everywhere below root
  def numBinChildren(): int {
    if (depth == 0) then
      return B_0;

    else
      return if to_prob(rng_rand(hash)) < nonLeafProb then nonLeafBF else 0;
  }

  // Geometric Distribution: Find the number of children
  def numGeoChildren(shape: GeoDistrib): int {
    var b_i: real = B_0;

    // use shape function to compute target b_i
    if (depth > 0) {
      select shape {

        // Expected size is polynomial in depth
        when GeoPoly do
          b_i = B_0 * (depth:real ** (-log(B_0:real)/log(MAX_DEPTH:real)));

        // Expected size is cyclic
        when GeoCyclic {
          if (depth > 5 * MAX_DEPTH) then
            b_i = 0.0;
          else
            b_i = B_0 ** sin(2.0*3.141592653589793*depth:real / MAX_DEPTH:real);
        }

        // Expected size is the same at all nodes up to max depth
        when GeoFixed do
          b_i = if (depth < MAX_DEPTH) then B_0 else 0;

        // Expected size decreases linearly in b_i
        when GeoLinear do
          b_i =  B_0 * (1.0 - depth:real / MAX_DEPTH:real);

      }
    }

    // given target b_i, find prob p so expected value of
    // geometric distribution is b_i.
    var p: real = 1.0 / (1.0 + b_i);

    // get uniform random number on [0,1)
    var u: real = to_prob(rng_rand(hash));

    // max number of children at this cumulative probability
    // (from inverse geometric cumulative density function)
    return floor(log(1 - u) / log(1 - p));
  }
}

/*
** Print out search parameters
*/
def uts_showSearchParams() {
  writeln("UTS v", uts_version, " - Unbalanced Tree Search (",
      if parallel then "Parallel Chapel (DeQueue)" else "Sequential Chapel (DeQueue)", ")");

  writeln("Tree type: ", distrib);
  writeln("Tree shape parameters:");
  writeln("  root branching factor b_0 = ", B_0, ", root seed = ", SEED);

  if (distrib == Geometric || distrib == Hybrid) then
    writeln("  Geo. params: Max_Depth = ", MAX_DEPTH, ", shape function = ", geoDist);

  if (distrib == Binomial || distrib == Hybrid) then
    writeln("  Bin. params: nonLeafProb=", nonLeafProb, " nonLeafBF=", nonLeafBF);

  if (distrib == Hybrid) then
    writeln("  Hybrid params: shiftDepth=", shiftDepth);

  writeln("Random number generator: ", rng_getName());

  if (parallel) {
    writeln("Parallel execution parameters:");
    writeln("  MAX_THREADS = ", MAX_THREADS, ", chunkSize = ", chunkSize);
  }

  writeln();
}

def balance_load(inout state: LDBalanceState, inout q: DeQueue(TreeNode)): int {
  if (parallel) {
    // Trade some imbalance here for blocking overhead
    if (q.size > 2*chunkSize && readXX(thread_cnt) < MAX_THREADS) {
      if debug then writeln(" ** dequeue ", q.id, " splitting off ", chunkSize, " nodes");

      // Attempt to reduce thread creation overhead
      if state.throttle < state.throttle_period {
        state.throttle += 1;
        return 0;
      } else {
        state.throttle = 0;
      }

      // Split off chunkSize nodes into a new queue
      var work = q.split(chunkSize);

      // Spawn a new worker on this queue
      thread_cnt += 1;
      threads_spawned += 1;
      begin create_tree(work);
      return 1;
    }
  }

  return 0;
}

/*
**  Parallel Tree Creation
*/
def create_tree(inout q: DeQueue(TreeNode)) {
  var count, maxDepth: int;
  var ldbal_state = LDBalanceState();

  if q.isEmpty() {
    writeln("create_tree(): Warning, called with no work");
  }

  while !q.isEmpty() {
    var node = q.popTop();
    count += node.genChildren(q);
    maxDepth = max(maxDepth, node.depth);

    if (q.size > 2*chunkSize) then
      balance_load(ldbal_state, q);
  }

  // Update search stats
  global_count += count;
  global_maxDepth = max(global_maxDepth, maxDepth);

  // Update thread counts and detect termination
  var thread_cnt_l = thread_cnt;
  thread_cnt_l -= 1;
  if thread_cnt_l == 0 then
    terminated = true;
  thread_cnt = thread_cnt_l;
}

def main() {
  var t_create: Timer();
  var root: TreeNode;
  var queue: DeQueue(TreeNode);

  // Create the root and push it into a queue
  root = TreeNode(0);
  rng_init(root.hash, SEED:int);
  global_count += 1;
  queue.pushTop(root);

  uts_showSearchParams();

  writeln("Performing ", if parallel then "parallel" else "serial", " tree search...");

  t_create.start();
  writeXF(thread_cnt, 1);
  create_tree(queue);
  if parallel then while !terminated { } // Wait for termination
  t_create.stop();

  writeln();
  writeln("Threads spawned: ", threads_spawned);
  writeln("Tree size = ", readXX(global_count), ", depth = ", readXX(global_maxDepth));
  writeln("Time: t_create= ", t_create.elapsed(), " (", readXX(global_count)/t_create.elapsed(), " nodes/sec)");
}

/*
**  UTS -- The Unbalanced Tree Search
**
**  James Dinan <dinan@cray.com>
**  July, 2007
*/

use Math;
use Time;
use sha1_rng;
use dequeue;

/**** UTS TYPES ****/
enum NodeDistrib { Binomial, Geometric, Hybrid, Constant };
enum GeoDistrib  { GeoFixed, GeoLinear, GeoPoly, GeoCyclic };

/**** COMPILE PARAMS ****/
config param debug:    bool = false;
config param parallel: bool = true;
param uts_version:   string = "2.1";

/**** UTS CONFIG VARS ****/
config const SEED:        uint = 16;    // Seed for the hash of the root node
config const MAX_CHILDREN: int = 10;    // Max. Children a node may have
config const B_0:          int = 4;     // Branching Factor
config const MAX_DEPTH:    int = 6;     // Depth limit
config const nonLeafProb: real = 0.10;  // Probability of a non-leaf (binomial)
config const nonLeafBF:    int = 4;     // Non-leaf branching factor (binomial)
config const shiftDepth:  real = 0.5;   // Depth at which hybrid trees go from Geo=>Bin

config const distrib: NodeDistrib = Geometric;
config const geoDist: GeoDistrib  = GeoFixed;

config const MAX_THREADS:  int = 4;
config const chunkSize:    int = 10;

// Global thread counter
var thread_cnt: sync int = 0;
var threads_spawned: int = 0; // "Locked" by thread_cnt

// Global stats, updated by a thread when it exits
var global_count: sync int = 0;
var global_maxDepth: sync int = 0;

// Shared termination detection
var terminated: single bool;

/**** UTS TreeNode Class ****/
class TreeNode {
  var depth:   int;
  var hash:    string = "__Here_be_dragons__";  // Handle delicately, if this is ever copied, things will go off the rails

  var nChildren: int = 0;

  // Generate this node's children
  def genChildren(inout q: DeQueue(TreeNode)): int {
    select distrib {
      when Geometric do
        nChildren = numGeoChildren(geoDist);
      when Binomial do
        nChildren = numBinChildren();
      when Hybrid do
        nChildren = numHybridChildren();
      when Constant do
        nChildren = numConstChildren();
    }

    if debug then writeln("Constructing ", nChildren, " children");

    forall i in [0..nChildren-1] {
      if debug then writeln("  + (", depth, ", ", i, ")");
      var t = TreeNode(depth+1);
      rng_spawn(hash, t.hash, i);
      q.pushTop(t);
    }

    return nChildren;
  }

  // Constant Distribution: Find the number of children
  //  Note: This is a _balanced_ tree.
  def numConstChildren(): int {
    return if depth < MAX_DEPTH then B_0 else 0;
  }

  // Hybrid trees are geometric at the top of the tree and binomial
  // below a certain depth.
  def numHybridChildren(): int {
    if (depth < shiftDepth * MAX_DEPTH) then
      return numGeoChildren(geoDist);

    else
      return numBinChildren();
  }

  // Binomial Distribution: Find the number of children
  //  Note: distribution is identical everywhere below root
  def numBinChildren(): int {
    if (depth == 0) then
      return B_0;

    else
      return if to_prob(rng_rand(hash)) < nonLeafProb then nonLeafBF else 0;
  }

  // Geometric Distribution: Find the number of children
  def numGeoChildren(shape: GeoDistrib): int {
    var b_i: real = B_0;

    // use shape function to compute target b_i
    if (depth > 0) {
      select shape {

        // Expected size is polynomial in depth
        when GeoPoly do
          b_i = B_0 * (depth:real ** (-log(B_0:real)/log(MAX_DEPTH:real)));

        // Expected size is cyclic
        when GeoCyclic {
          if (depth > 5 * MAX_DEPTH) then
            b_i = 0.0;
          else
            b_i = B_0 ** sin(2.0*3.141592653589793*depth:real / MAX_DEPTH:real);
        }

        // Expected size is the same at all nodes up to max depth
        when GeoFixed do
          b_i = if (depth < MAX_DEPTH) then B_0 else 0;

        // Expected size decreases linearly in b_i
        when GeoLinear do
          b_i =  B_0 * (1.0 - depth:real / MAX_DEPTH:real);

      }
    }

    // given target b_i, find prob p so expected value of
    // geometric distribution is b_i.
    var p: real = 1.0 / (1.0 + b_i);

    // get uniform random number on [0,1)
    var u: real = to_prob(rng_rand(hash));

    // max number of children at this cumulative probability
    // (from inverse geometric cumulative density function)
    return floor(log(1 - u) / log(1 - p));
  }
}

/*
** Print out search parameters
*/
def uts_showSearchParams() {
  writeln("UTS v", uts_version, " - Unbalanced Tree Search (",
      if parallel then "Parallel Chapel (DeQueue)" else "Sequential Chapel (DeQueue)", ")");

  writeln("Tree type: ", distrib);
  writeln("Tree shape parameters:");
  writeln("  root branching factor b_0 = ", B_0, ", root seed = ", SEED);

  if (distrib == Geometric || distrib == Hybrid) then
    writeln("  Geo. params: Max_Depth = ", MAX_DEPTH, ", shape function = ", geoDist);

  if (distrib == Binomial || distrib == Hybrid) then
    writeln("  Bin. params: nonLeafProb=", nonLeafProb, " nonLeafBF=", nonLeafBF);

  if (distrib == Hybrid) then
    writeln("  Hybrid params: shiftDepth=", shiftDepth);

  writeln("Random number generator: ", rng_getName());

  if (parallel) {
    writeln("Parallel execution parameters:");
    writeln("  MAX_THREADS = ", MAX_THREADS, ", chunkSize = ", chunkSize);
  }

  writeln();
}

def balance_load(inout q: DeQueue(TreeNode)): int {
  if (parallel) {
    // Trade some imbalance here for blocking overhead
    if (q.size > 2*chunkSize && readXX(thread_cnt) < MAX_THREADS) {
      if debug then writeln(" ** dequeue ", q.id, " splitting off ", chunkSize, " nodes");

      // Split off chunkSize nodes into a new queue
      var work = q.split(chunkSize);

      // Spawn a new worker on this queue
      thread_cnt += 1;
      threads_spawned += 1;
      begin create_tree(work);
      return 1;
    }
  }

  return 0;
}

/*
**  Parallel Tree Creation
*/
def create_tree(inout q: DeQueue(TreeNode)) {
  var count, maxDepth: int;

  if q.isEmpty() {
    writeln("create_tree(): Warning, called with no work");
  }

  while !q.isEmpty() {
    var node = q.popTop();
    count += node.genChildren(q);
    maxDepth = max(maxDepth, node.depth);

    if (q.size > 2*chunkSize) then
      balance_load(q);
  }

  // Update search stats
  global_count += count;
  global_maxDepth = max(global_maxDepth, maxDepth);

  // Update thread counts and detect termination
  var thread_cnt_l = thread_cnt;
  thread_cnt_l -= 1;
  if thread_cnt_l == 0 then
    terminated = true;
  thread_cnt = thread_cnt_l;
}

def main() {
  var t_create: Timer();
  var root: TreeNode;
  var queue: DeQueue(TreeNode);

  // Create the root and push it into a queue
  root = TreeNode(0);
  rng_init(root.hash, SEED:int);
  global_count += 1;
  queue.pushTop(root);

  uts_showSearchParams();

  writeln("Performing ", if parallel then "parallel" else "serial", " tree search...");

  t_create.start();
  writeXF(thread_cnt, 1);
  create_tree(queue);
  if parallel then while !terminated { } // Wait for termination
  t_create.stop();

  writeln();
  writeln("Threads spawned: ", threads_spawned);
  writeln("Tree size = ", readXX(global_count), ", depth = ", readXX(global_maxDepth));
  writeln("Time: t_create= ", t_create.elapsed(), " (", readXX(global_count)/t_create.elapsed(), " nodes/sec)");
}