qos-parallelism.dhover×73all
#!/usr/bin/env dub
/+ dub.sdl:
    name "gcd_qos_parallelism"
    platforms "osx"
    targetPath "build"
+/
/**
 * GCD — how wide is "wide"? `pthread_qos_max_parallelism` per QoS class.
 *
 * `dispatch_apply` does not fan out to `nproc` threads. libdispatch sizes it
 * with `_dispatch_qos_max_parallelism(qos, DISPATCH_MAX_PARALLELISM_ACTIVE)`
 * (`src/shims.h`), which calls `pthread_qos_max_parallelism(qos_class, flags)`
 * and falls back to the CPU count only if that returns zero. On Apple silicon
 * the answer is *not* uniform: the background QoS class is confined to the
 * efficiency cluster, so its parallelism is the E-core count, not the total.
 *
 * This program prints the kernel's answer for each QoS class in both the
 * logical and the `PTHREAD_MAX_PARALLELISM_PHYSICAL` flavour, and asserts the
 * ordering libdispatch relies on (background never wider than default).
 *
 * Companion to the GCD deep-dive:
 * see docs/research/async-io/gcd/index.md § "`dispatch_apply` and QoS-aware parallelism".
 *
 * Run with: `dub run --single qos-parallelism.d`
 *
 * Portability: macOS only. `pthread_qos_max_parallelism` exists since macOS
 * 10.13; on an older host it returns a negative value and the program prints a
 * `SKIP:` line and exits 0.
 */
module 
(module) gcd_qos_parallelism

GCD — how wide is "wide"? pthread_qos_max_parallelism per QoS class.

dispatch_apply does not fan out to nproc threads. libdispatch sizes it with _dispatch_qos_max_parallelism(qos, DISPATCH_MAX_PARALLELISM_ACTIVE) (src/shims.h), which calls pthread_qos_max_parallelism(qos_class, flags) and falls back to the CPU count only if that returns zero. On Apple silicon the answer is not uniform: the background QoS class is confined to the efficiency cluster, so its parallelism is the E-core count, not the total.

This program prints the kernel's answer for each QoS class in both the logical and the PTHREAD_MAX_PARALLELISM_PHYSICAL flavour, and asserts the ordering libdispatch relies on (background never wider than default).

Companion to the GCD deep-dive: see docs/research/async-io/gcd/index.md § "dispatch_apply and QoS-aware parallelism".

Run with: dub run --single qos-parallelism.d

Portability

macOS only. pthread_qos_max_parallelism exists since macOS 10.13; on an older host it returns a negative value and the program prints a SKIP: line and exits 0.

gcd_qos_parallelism
;
import
(package) std
std
.
(module) std.parallelism

std.parallelism implements high-level primitives for SMP `parallelism`. These include parallel foreach, parallel reduce, parallel eager map, pipelining and future/promise `parallelism`. `std.`parallelism is recommended when the same operation is to be executed in parallel on different data, or when a function is to be executed in a background thread and its result returned to a well-defined main thread. For communication between arbitrary threads, see std.concurrency.

std.parallelism`` is based on the concept of a Task. A Task is an object that represents the fundamental unit of work in this library and may be executed in parallel with any other Task. Using Task directly allows programming with a future/promise paradigm. All other supported parallelism paradigms (parallel foreach, map, reduce, pipelining) represent an additional level of abstraction over Task. They automatically create one or more Task objects, or closely related types that are conceptually identical but not part of the public API.

After creation, a Task may be executed in a new thread, or submitted to a TaskPool for execution. A TaskPool encapsulates a task queue and its worker threads. Its purpose is to efficiently map a large number of Tasks onto a smaller number of threads. A task queue is a FIFO queue of Task objects that have been submitted to the TaskPool and are awaiting execution. A worker thread is a thread that is associated with exactly one task queue. It executes the Task at the front of its queue when the queue has work available, or sleeps when no work is available. Each task queue is associated with zero or more worker threads. If the result of a Task is needed before execution by a worker thread has begun, the Task can be removed from the task queue and executed immediately in the thread where the result is needed.

Warning

Unless marked as @trusted or @safe, artifacts in this module allow implicit data sharing between threads and cannot guarantee that client code is free from low level data races.

Source

std/parallelism.d

Author

David Simcha

@copyrightCopyright (c) 2009-2011, David Simcha.@licenseBoost License 1.0
parallelism
: totalCPUs;
import
(package) std
std
.
(module) std.stdio
Category Symbols
File handles _popen File isFileHandle openNetwork stderr stdin stdout
Reading chunks lines readf readfln readln
Writing toFile write writef writefln writeln
Misc KeepTerminator LockType StdioException

Standard I/O functions that extend core.stdc.stdio. core.stdc.stdio is publically imported when importing std.stdio.

There are three layers of I/O:

  1. The lowest layer is the operating system layer. The two main schemes are Windows and Posix.

  2. C's stdio.h which unifies the two operating system schemes.

  3. std.stdio, this module, unifies the various stdio.h implementations into a high level package for D programs.

Source

std/stdio.d

@copyrightCopyright The D Language Foundation 2007-.@licenseBoost License 1.0.@authorsWalter Bright, Andrei Alexandrescu, Alex Rønne Petersen
stdio
:
(alias template) gcd_qos_parallelism.writefln = std.stdio.writefln(alias fmt, A...)(A args) if (isSomeString!(typeof(fmt)))

Equivalent to writef(fmt, args, '\n').

writefln
,
(alias template) gcd_qos_parallelism.writeln = std.stdio.writeln(T...)(T args)

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
;
extern (C) nothrow @nogc int
int gcd_qos_parallelism.pthread_qos_max_parallelism(uint qosClass, ulong flags) nothrow @nogc
pthread_qos_max_parallelism
(uint
(parameter) uint qosClass
qosClass
, ulong
(parameter) ulong flags
flags
);
/// `PTHREAD_MAX_PARALLELISM_PHYSICAL` — count physical cores, not logical ones. enum
(constant) ulong gcd_qos_parallelism.PTHREAD_MAX_PARALLELISM_PHYSICAL = 1LU

PTHREAD_MAX_PARALLELISM_PHYSICAL — count physical cores, not logical ones.

PTHREAD_MAX_PARALLELISM_PHYSICAL
= 0x1UL;
struct
(struct) gcd_qos_parallelism.QosClass
QosClass
{
(alias) object.string = string
string
(field) string gcd_qos_parallelism.QosClass.name
name
;
uint
(field) uint gcd_qos_parallelism.QosClass.value
value
;
} static immutable
(struct) gcd_qos_parallelism.QosClass
QosClass
[]
(immutable global) immutable(gcd_qos_parallelism.QosClass[]) gcd_qos_parallelism.qosClasses
qosClasses
= [
(struct) gcd_qos_parallelism.QosClass
QosClass
("QOS_CLASS_BACKGROUND", 0x09),
(struct) gcd_qos_parallelism.QosClass
QosClass
("QOS_CLASS_UTILITY", 0x11),
(struct) gcd_qos_parallelism.QosClass
QosClass
("QOS_CLASS_DEFAULT", 0x15),
(struct) gcd_qos_parallelism.QosClass
QosClass
("QOS_CLASS_USER_INITIATED", 0x19),
(struct) gcd_qos_parallelism.QosClass
QosClass
("QOS_CLASS_USER_INTERACTIVE", 0x21),
]; int
int D main()
main
()
{ const
(local variable) const(int) probe
probe
=
int gcd_qos_parallelism.pthread_qos_max_parallelism(uint qosClass, ulong flags) nothrow @nogc
pthread_qos_max_parallelism
(
(immutable global) immutable(gcd_qos_parallelism.QosClass[]) gcd_qos_parallelism.qosClasses
qosClasses
[0].
(field) uint gcd_qos_parallelism.QosClass.value
value
, 0);
if (
(local variable) const(int) probe
probe
<= 0)
{
void std.stdio.writefln!(char, const(int))(in char[] fmt, const(int) __param_1) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("SKIP: pthread_qos_max_parallelism unavailable (returned %d)",
(local variable) const(int) probe
probe
);
return 0; }
void std.stdio.writefln!(char, immutable(uint))(in char[] fmt, immutable(uint) __param_1) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("std.parallelism.totalCPUs = %d", totalCPUs);
void std.stdio.writeln!()() @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
();
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("QoS class logical physical");
int
(local variable) int background
background
,
(local variable) int dflt
dflt
;
foreach (
(parameter) immutable(gcd_qos_parallelism.QosClass) qos
qos
;
(immutable global) immutable(gcd_qos_parallelism.QosClass[]) gcd_qos_parallelism.qosClasses
qosClasses
)
{ const
(local variable) const(int) logical
logical
=
int gcd_qos_parallelism.pthread_qos_max_parallelism(uint qosClass, ulong flags) nothrow @nogc
pthread_qos_max_parallelism
(
(local variable) immutable(gcd_qos_parallelism.QosClass) qos
qos
.
(field) uint gcd_qos_parallelism.QosClass.value
value
, 0);
const
(local variable) const(int) physical
physical
=
int gcd_qos_parallelism.pthread_qos_max_parallelism(uint qosClass, ulong flags) nothrow @nogc
pthread_qos_max_parallelism
(
(local variable) immutable(gcd_qos_parallelism.QosClass) qos
qos
.
(field) uint gcd_qos_parallelism.QosClass.value
value
,
(constant) ulong gcd_qos_parallelism.PTHREAD_MAX_PARALLELISM_PHYSICAL = 1LU

PTHREAD_MAX_PARALLELISM_PHYSICAL — count physical cores, not logical ones.

PTHREAD_MAX_PARALLELISM_PHYSICAL
);
void std.stdio.writefln!(char, string, const(int), const(int))(in char[] fmt, string __param_1, const(int) __param_2, const(int) __param_3) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("%-29s %7d %8d",
(local variable) immutable(gcd_qos_parallelism.QosClass) qos
qos
.
(field) string gcd_qos_parallelism.QosClass.name
name
,
(local variable) const(int) logical
logical
,
(local variable) const(int) physical
physical
);
assert(
(local variable) const(int) logical
logical
> 0 &&
(local variable) const(int) physical
physical
> 0, "kernel reported non-positive parallelism");
assert(
(local variable) const(int) physical
physical
<=
(local variable) const(int) logical
logical
, "physical parallelism exceeded logical");
if (
(local variable) immutable(gcd_qos_parallelism.QosClass) qos
qos
.
(field) string gcd_qos_parallelism.QosClass.name
name
== "QOS_CLASS_BACKGROUND")
(local variable) int background
background
=
(local variable) const(int) logical
logical
;
else if (
(local variable) immutable(gcd_qos_parallelism.QosClass) qos
qos
.
(field) string gcd_qos_parallelism.QosClass.name
name
== "QOS_CLASS_DEFAULT")
(local variable) int dflt
dflt
=
(local variable) const(int) logical
logical
;
} // The invariant libdispatch's apply sizing depends on: a lower QoS class is // never granted more parallelism than a higher one. On an asymmetric // (P-core/E-core) machine this is a strict inequality. assert(
(local variable) int background
background
<=
(local variable) int dflt
dflt
, "background QoS was wider than default QoS");
void std.stdio.writeln!()() @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
();
if (
(local variable) int background
background
<
(local variable) int dflt
dflt
)
void std.stdio.writefln!(char, int, int)(in char[] fmt, int __param_1, int __param_2) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("asymmetric host: background QoS is confined to %d of %d cores",
(local variable) int background
background
,
(local variable) int dflt
dflt
);
else
void std.stdio.writefln!(char, int)(in char[] fmt, int __param_1) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("symmetric host: every QoS class gets %d-way parallelism",
(local variable) int dflt
dflt
);
return 0; }