#!/usr/bin/env dub
/+ dub.sdl:
name "cpu_pmu_pfm4_name_roundtrip"
platforms "linux"
libs "pfm"
targetPath "build"
+/
/**
* libpfm4 human-name → `perf_event_attr.{type,config}` round trip, then live count.
*
* The *event-naming & encoding* concern of the analysis spine, exercised end to
* end on this host. libpfm4 is the name-resolution layer under `perf`, PAPI, and
* many profilers: it owns per-microarchitecture event tables and turns a symbolic
* string into the `type`/`config`/`exclude_*` fields the `perf_event_open(2)` ABI
* expects. This probe:
*
* 1. `pfm_get_os_event_encoding(str, …, PFM_OS_PERF_EVENT, &arg)` with `arg.attr`
* pointing at druntime's `perf_event_attr` — the same struct `perf_event_open`
* consumes — so libpfm fills it directly (no hand-built encodings).
* 2. Encodes four names spanning the naming layers and prints the resulting
* `type`/`config` hex plus the fully-qualified string libpfm echoes back:
* - `PERF_COUNT_HW_CPU_CYCLES` — a *generic* perf name → `PERF_TYPE_HARDWARE`
* (type 0), config 0: the OS-abstracted event, portable across vendors.
* - `RETIRED_INSTRUCTIONS` — a *Zen 4-specific* name from libpfm's
* `amd64_fam19h_zen4` table → `PERF_TYPE_RAW` (type 4), config `0xc0`
* (the raw AMD PMC event-select), proving the per-µarch table is what
* supplies the bits.
* - `RETIRED_SSE_AVX_FLOPS:ADD_SUB_FLOPS` — a name carrying a *unit mask* →
* the umask lands in config bits [15:8] (`0x103`), showing libpfm's
* `event:umask` grammar.
* - `RETIRED_INSTRUCTIONS:u` — a name carrying a *modifier* → config is
* unchanged (`0xc0`) but `attr.exclude_kernel` is set: user/kernel/hv
* filtering is lifted OUT of the raw config into the perf_event ABI's
* `exclude_*` fields (`pfm_amd64_get_perf_encoding` zeroes the OS/USR
* MSR bits; the common perf layer sets the attr fields). This split is
* the whole reason `PFM_OS_PERF_EVENT` exists.
* 3. `perf_event_open`s each encoding on the calling thread and counts a fixed
* workload window (integer mixing + scalar SSE FP), proving the encodings
* are *live*, not just plausible.
*
* Auto-detect caveat (source-verified, load-bearing): stock **libpfm 4.13.0**
* (the current nixpkgs build) does NOT auto-detect this CPU's core PMU. Its
* family-19h detect (`lib/pfmlib_amd64.c`) maps only `model == 0x11` to Zen 4, so
* the Ryzen 9 7940HX (family 25/`0x19`, model **0x61**, Dragon Range) matches no
* branch, `revision` stays `PFM_PMU_NONE`, and only the software `perf`/`perf_raw`
* PMUs activate — a bare `pfm_get_os_event_encoding("RETIRED_INSTRUCTIONS", …)`
* then returns `PFM_ERR_NOTFOUND` (-4). libpfm git HEAD fixes this (`model >= 0x60`).
* To stay robust we (a) derive the correct table name from `/proc/cpuinfo`
* ourselves — exactly what a fixed `detect()` would pick — and address events with
* the explicit `amd64_fam19h_zen4::` prefix, and (b) set `LIBPFM_ENCODE_INACTIVE=1`
* before `pfm_initialize`, which places even un-detected tables on the searchable
* list. The lesson for a backend: do not trust libpfm auto-detect on very recent
* silicon — force the PMU by a name you resolve from CPUID, or require a new libpfm.
*
* Companion to docs/research/cpu-pmu/event-naming.md
* § "libpfm4: the name→encoding pipeline" and § "The OS-layer split".
*
* Run with (nixpkgs libpfm has no pkg-config .pc, and `nix shell` does not run
* setup hooks, so feed its lib dir through LIBRARY_PATH/LD_LIBRARY_PATH):
*
* P=$(nix eval --raw nixpkgs#libpfm)/lib; \
* env LIBRARY_PATH="$P:$LIBRARY_PATH" LD_LIBRARY_PATH="$P:$LD_LIBRARY_PATH" \
* dub run --single pfm4-name-roundtrip.d
*
* (Adding `libpfm` to the flake devShell's buildInputs would let a plain
* `dub run --single` resolve `libs "pfm"` via NIX_LDFLAGS — the intended CI path.)
*
* Environment recorded: Linux 6.18.26, AMD Ryzen 9 7940HX (Zen 4, family 25 /
* model 0x61), `/proc/sys/kernel/perf_event_paranoid` = -1, libpfm 4.13.0
* (nixpkgs), LDC 1.41 druntime `core.sys.linux.perf_event`.
*
* Portability: on a host without libpfm the build fails to link (libpfm is a
* link-time dependency, like `libdw` in the sibling probes). At runtime, a raised
* `perf_event_paranoid`, a non-AMD CPU, or any `perf_event_open` failure prints a
* `SKIP:` line and exits 0 so CI stays green on any host.
*/
module (module) cpu_pmu_pfm4_name_roundtriplibpfm4 human-name → perf_event_attr.{type,config} round trip, then live count.
The event-naming & encoding concern of the analysis spine, exercised end to
end on this host. libpfm4 is the name-resolution layer under perf, PAPI, and
many profilers: it owns per-microarchitecture event tables and turns a symbolic
string into the type/config/exclude_* fields the perf_event_open(2) ABI
expects. This probe:
pfm_get_os_event_encoding(str, …, PFM_OS_PERF_EVENT, &arg) with arg.attr
pointing at druntime's perf_event_attr — the same struct perf_event_open
consumes — so libpfm fills it directly (no hand-built encodings).
Encodes four names spanning the naming layers and prints the resulting
type/config hex plus the fully-qualified string libpfm echoes back:
PERF_COUNT_HW_CPU_CYCLES — a generic perf name → PERF_TYPE_HARDWARE
(type 0), config 0: the OS-abstracted event, portable across vendors.
RETIRED_INSTRUCTIONS — a Zen 4-specific name from libpfm's
amd64_fam19h_zen4 table → PERF_TYPE_RAW (type 4), config 0xc0
(the raw AMD PMC event-select), proving the per-µarch table is what
supplies the bits.
RETIRED_SSE_AVX_FLOPS:ADD_SUB_FLOPS — a name carrying a unit mask →
the umask lands in config bits 15:8 (0x103), showing libpfm's
event:umask grammar.
RETIRED_INSTRUCTIONS:u — a name carrying a modifier → config is
unchanged (0xc0) but attr.exclude_kernel is set: user/kernel/hv
filtering is lifted OUT of the raw config into the perf_event ABI's
exclude_* fields (pfm_amd64_get_perf_encoding zeroes the OS/USR
MSR bits; the common perf layer sets the attr fields). This split is
the whole reason PFM_OS_PERF_EVENT exists.
perf_event_opens each encoding on the calling thread and counts a fixed
workload window (integer mixing + scalar SSE FP), proving the encodings
are live, not just plausible.
Auto-detect caveat (source-verified, load-bearing): stock libpfm 4.13.0
(the current nixpkgs build) does NOT auto-detect this CPU's core PMU. Its
family-19h detect (lib/pfmlib_amd64.c) maps only model == 0x11 to Zen 4, so
the Ryzen 9 7940HX (family 25/0x19, model 0x61, Dragon Range) matches no
branch, revision stays PFM_PMU_NONE, and only the software perf/perf_raw
PMUs activate — a bare pfm_get_os_event_encoding("RETIRED_INSTRUCTIONS", …)
then returns PFM_ERR_NOTFOUND (-4). libpfm git HEAD fixes this (model >= 0x60).
To stay robust we (a) derive the correct table name from /proc/cpuinfo
ourselves — exactly what a fixed detect() would pick — and address events with
the explicit amd64_fam19h_zen4:: prefix, and (b) set LIBPFM_ENCODE_INACTIVE=1
before pfm_initialize, which places even un-detected tables on the searchable
list. The lesson for a backend: do not trust libpfm auto-detect on very recent
silicon — force the PMU by a name you resolve from CPUID, or require a new libpfm.
Companion to docs/research/cpu-pmu/event-naming.md
§ "libpfm4: the name→encoding pipeline" and § "The OS-layer split".
Run with (nixpkgs libpfm has no pkg-config .pc, and nix shell does not run
setup hooks, so feed its lib dir through LIBRARY_PATH/LD_LIBRARY_PATH):
P=eval --raw nixpkgs#libpfm/lib;
env LIBRARY_PATH="$P:$LIBRARY_PATH" LD_LIBRARY_PATH="$P:$LD_LIBRARY_PATH"
dub run --single pfm4-name-roundtrip.d
(Adding libpfm to the flake devShell's buildInputs would let a plain
dub run --single resolve libs "pfm" via NIX_LDFLAGS — the intended CI path.)
Environment recorded: Linux 6.18.26, AMD Ryzen 9 7940HX (Zen 4, family 25 /
model 0x61), /proc/sys/kernel/perf_event_paranoid = -1, libpfm 4.13.0
(nixpkgs), LDC 1.41 druntime core.sys.linux.perf_event.
Portability
on a host without libpfm the build fails to link (libpfm is a
link-time dependency, like libdw in the sibling probes). At runtime, a raised
perf_event_paranoid, a non-AMD CPU, or any perf_event_open failure prints a
SKIP: line and exits 0 so CI stays green on any host.
cpu_pmu_pfm4_name_roundtrip;
version (linuxlinux)
{
import (package) corecore.(package) core.syssys.(package) core.sys.linuxlinux.(module) core.sys.linux.perf_eventD header file for perf_event_open system call.
Converted from linux userspace header, comments included.
perf_event : (struct) core.sys.linux.perf_event.perf_event_attrHardware event_id to monitor via a performance monitoring event:
@sample_max_stack: Max number of frame pointers in a callchain,
should be < /proc/sys/kernel/perf_event_max_stack
perf_event_attr, (alias) cpu_pmu_pfm4_name_roundtrip.perf_event_open = long core.sys.linux.perf_event.perf_event_open(core.sys.linux.perf_event.perf_event_attr* hw_event, int pid, int cpu, int group_fd, ulong flags) nothrow @nogcperf_event_open,
(enum) core.sys.linux.perf_event.perf_type_idattr.type
perf_type_id, (enum) core.sys.linux.perf_event.perf_event_read_formatThe format of the data returned by read() on a perf event fd,
as specified by attr.read_format:
struct read_format {
{ u64 value;
{ u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
{ u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
{ u64 id; } && PERF_FORMAT_ID
} && !PERF_FORMAT_GROUP
{ u64 nr;
{ u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
{ u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
{ u64 value;
{ u64 id; } && PERF_FORMAT_ID
} cntr[nr];
} && PERF_FORMAT_GROUP
};
perf_event_read_format, (alias constant) cpu_pmu_pfm4_name_roundtrip.PERF_EVENT_IOC_RESET = int core.sys.linux.perf_event.PERF_EVENT_IOC_RESET = 9219PERF_EVENT_IOC_RESET,
(alias constant) cpu_pmu_pfm4_name_roundtrip.PERF_EVENT_IOC_ENABLE = int core.sys.linux.perf_event.PERF_EVENT_IOC_ENABLE = 9216Ioctls that can be done on a perf event fd:
PERF_EVENT_IOC_ENABLE, (alias constant) cpu_pmu_pfm4_name_roundtrip.PERF_EVENT_IOC_DISABLE = int core.sys.linux.perf_event.PERF_EVENT_IOC_DISABLE = 9217PERF_EVENT_IOC_DISABLE;
import (package) corecore.(package) core.syssys.(package) core.sys.posixposix.(module) core.sys.posix.unistdD header file for POSIX.
unistd : (alias) cpu_pmu_pfm4_name_roundtrip.read = long core.sys.posix.unistd.read(int, void*, ulong) nothrow @nogcread, (alias) cpu_pmu_pfm4_name_roundtrip.close = int core.sys.posix.unistd.close(int) nothrow @nogc @trustedclose;
import (package) corecore.(package) core.syssys.(package) core.sys.posixposix.(package) core.sys.posix.syssys.(module) core.sys.posix.sys.ioctlD header file for POSIX.
ioctl : (alias) cpu_pmu_pfm4_name_roundtrip.ioctl = int core.sys.posix.sys.ioctl.ioctl(int __fd, ulong __request, ...) nothrow @nogcioctl;
import (package) corecore.(package) core.syssys.(package) core.sys.posixposix.(module) core.sys.posix.stdlibD header file for POSIX.
stdlib : (alias) cpu_pmu_pfm4_name_roundtrip.setenv = int core.sys.posix.stdlib.setenv(scope const(char*), scope const(char*), int) nothrow @nogcsetenv;
import (package) corecore.(package) core.stdcstdc.(module) core.stdc.configD compatible types that correspond to various basic types in associated
C and C++ compilers.
Source
core/stdc/config.d
config : c_ulong;
import (package) corecore.(package) core.stdcstdc.(module) core.stdc.stringD header file for C99.
pubs.opengroup.org/onlinepubs/009695399/basedefs/string.h.html, string.h
Source
core/stdc/string.d
string : (alias) cpu_pmu_pfm4_name_roundtrip.strlen = ulong core.stdc.string.strlen(scope const(char*) s) pure nothrow @nogcstrlen;
import (package) stdstd.(module) std.stdioCategory 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:
The lowest layer is the operating system layer. The two main schemes are Windows and Posix.
C's stdio.h which unifies the two operating system schemes.
std.stdio, this module, unifies the various stdio.h implementations into
a high level package for D programs.
Source
std/stdio.d
stdio : (alias template) cpu_pmu_pfm4_name_roundtrip.writefln = std.stdio.writefln(alias fmt, A...)(A args) if (isSomeString!(typeof(fmt)))Equivalent to writef(fmt, args, '\n').
writefln, (alias template) cpu_pmu_pfm4_name_roundtrip.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);
}
}
writeln;
import (package) stdstd.(module) std.stringString handling functions.
Category Functions Searching column indexOf indexOfAny indexOfNeither lastIndexOf lastIndexOfAny lastIndexOfNeither Comparison isNumeric Mutation capitalize Pruning and Filling center chomp chompPrefix chop detabber detab entab entabber leftJustify outdent rightJustify strip stripLeft stripRight wrap Substitution abbrev soundex soundexer succ tr translate Miscellaneous assumeUTF fromStringz lineSplitter representation splitLines toStringz Objects of types string, wstring, and dstring are value types and cannot be mutated element-by-element. For using mutation during building strings, use char[], wchar[], or dchar[]. The xxxstring types are preferable because they don't exhibit undesired aliasing, thus making code more robust.
The following functions are publicly imported:
Module Functions Publicly imported functions std.algorithm cmp, std,algorithm,comparison count, std,algorithm,searching endsWith, std,algorithm,searching startsWith, std,algorithm,searching std.array join, std,array replace, std,array replaceInPlace, std,array split, std,array empty, std,array std.format format, std,format sformat, std,format std.uni icmp, std,uni toLower, std,uni toLowerInPlace, std,uni toUpper, std,uni toUpperInPlace, std,uni There is a rich set of functions for string handling defined in other modules. Functions related to Unicode and ASCII are found in std.uni and std.ascii, respectively. Other functions that have a wider generality than just strings can be found in std.algorithm and std.range.
Source
std/string.d
string : (alias template) cpu_pmu_pfm4_name_roundtrip.lineSplitter = std.string.lineSplitter(Flag keepTerm = No.keepTerminator, Range)(Range r) if (hasSlicing!Range && hasLength!Range && isSomeChar!(ElementType!Range) && !isSomeString!Range)Split an array or slicable range of characters into a range of lines
using '\r', '\n', '\v', '\f', "\r\n",
lineSep, paraSep and '\u0085' (NEL)
as delimiters. If keepTerm is set to Yes.keepTerminator, then the
delimiter is included in the slices returned.
Does not throw on invalid UTF; such is simply passed unchanged
to the output.
Adheres to Unicode 7.0.
Does not allocate memory.
lineSplitter, (alias template) cpu_pmu_pfm4_name_roundtrip.startsWith = std.algorithm.searching.startsWith(alias pred = (a, b) => a == b, Range, Needles...)(Range doesThisStart, Needles withOneOfThese) if (isInputRange!Range && (Needles.length > 1) && allSatisfy!(canTestStartsWith!(pred, Range), Needles))Checks whether the given
input range starts with (one
of) the given needle(s) or, if no needles are given,
if its front element fulfils predicate pred.
For more information about pred see find.
startsWith, (alias template) cpu_pmu_pfm4_name_roundtrip.strip = std.string.strip(Range)(Range str) if (isSomeString!Range || isRandomAccessRange!Range && hasLength!Range && hasSlicing!Range && !isConvertibleToString!Range && isSomeChar!(ElementEncodingType!Range))Strips both leading and trailing whitespace (as defined by
isWhite) or as specified in the second argument.
strip;
// ---- libpfm4 (extern(C), verified against $REPOS/c/libpfm4@6870a9f0
// include/perfmon/pfmlib.h + pfmlib_perf_event.h) --------------------
enum (constant) int cpu_pmu_pfm4_name_roundtrip.PFM_OS_PERF_EVENT = 1PFM_OS_PERF_EVENT = 1; // pfm_os_t: perf_events attribute subset + PMU
enum (constant) int cpu_pmu_pfm4_name_roundtrip.PFM_PLM0 = 1PFM_PLM0 = 0x01; // priv level 0 (kernel)
enum (constant) int cpu_pmu_pfm4_name_roundtrip.PFM_PLM3 = 8PFM_PLM3 = 0x08; // priv level 3/2/1 (user)
enum (constant) int cpu_pmu_pfm4_name_roundtrip.PFM_SUCCESS = 0PFM_SUCCESS = 0;
/// `pfm_perf_encode_arg_t` (pfmlib_perf_event.h): 40 bytes on LP64.
struct (struct) cpu_pmu_pfm4_name_roundtrip.pfm_perf_encode_arg_tpfm_perf_encode_arg_t (pfmlib_perf_event.h): 40 bytes on LP64.
pfm_perf_encode_arg_t
{
(struct) core.sys.linux.perf_event.perf_event_attrHardware event_id to monitor via a performance monitoring event:
@sample_max_stack: Max number of frame pointers in a callchain,
should be < /proc/sys/kernel/perf_event_max_stack
perf_event_attr* (field) core.sys.linux.perf_event.perf_event_attr* cpu_pmu_pfm4_name_roundtrip.pfm_perf_encode_arg_t.attrattr; // in/out: the struct libpfm fills
char** (field) char** cpu_pmu_pfm4_name_roundtrip.pfm_perf_encode_arg_t.fstrfstr; // out: fully-qualified event string
(alias) object.size_t = ulongsize_t (field) ulong cpu_pmu_pfm4_name_roundtrip.pfm_perf_encode_arg_t.sizesize; // sizeof(*this) — libpfm ABI-checks this
int (field) int cpu_pmu_pfm4_name_roundtrip.pfm_perf_encode_arg_t.idxidx; // out: opaque event id
int (field) int cpu_pmu_pfm4_name_roundtrip.pfm_perf_encode_arg_t.cpucpu; // out: cpu to program, -1 = unset
int (field) int cpu_pmu_pfm4_name_roundtrip.pfm_perf_encode_arg_t.flagsflags; // out: perf_event_open flags
int (field) int cpu_pmu_pfm4_name_roundtrip.pfm_perf_encode_arg_t.pad0pad0;
}
extern (C) int int cpu_pmu_pfm4_name_roundtrip.pfm_initialize()pfm_initialize();
extern (C) int int cpu_pmu_pfm4_name_roundtrip.pfm_get_version()pfm_get_version();
extern (C) const(char)* const(char)* cpu_pmu_pfm4_name_roundtrip.pfm_strerror(int)pfm_strerror(int);
extern (C) int int cpu_pmu_pfm4_name_roundtrip.pfm_get_os_event_encoding(const(char)*, int, int, void*)pfm_get_os_event_encoding(const(char)*, int, int, void*);
(alias) object.string = stringstring string cpu_pmu_pfm4_name_roundtrip.cstr(const(char)* p) @trustedcstr(const(char)* (parameter) const(char)* pp) @trusted =>
(parameter) const(char)* pp is null ? "(null)" : cast((alias) object.string = stringstring) (parameter) const(char)* pp[0 .. ulong core.stdc.string.strlen(scope const(char*) s) pure nothrow @nogcstrlen((parameter) const(char)* pp)];
/// Result of one encode.
struct (struct) cpu_pmu_pfm4_name_roundtrip.EncodedResult of one encode.
Encoded
{
bool (field) bool cpu_pmu_pfm4_name_roundtrip.Encoded.okok;
int (field) int cpu_pmu_pfm4_name_roundtrip.Encoded.errerr; // pfm_err_t when !ok
(struct) core.sys.linux.perf_event.perf_event_attrHardware event_id to monitor via a performance monitoring event:
@sample_max_stack: Max number of frame pointers in a callchain,
should be < /proc/sys/kernel/perf_event_max_stack
perf_event_attr (field) core.sys.linux.perf_event.perf_event_attr cpu_pmu_pfm4_name_roundtrip.Encoded.attrattr;
(alias) object.string = stringstring (field) string cpu_pmu_pfm4_name_roundtrip.Encoded.fstrfstr;
}
/// Name → `perf_event_attr` via libpfm. Counting at both priv levels
/// (PLM0|PLM3) is the default; per-name `:u`/`:k` modifiers override it.
(struct) cpu_pmu_pfm4_name_roundtrip.EncodedResult of one encode.
Encoded cpu_pmu_pfm4_name_roundtrip.Encoded cpu_pmu_pfm4_name_roundtrip.encode(string name) @trustedName → perf_event_attr via libpfm. Counting at both priv levels
(PLM0|PLM3) is the default; per-name :u/:k modifiers override it.
encode((alias) object.string = stringstring (parameter) string namename) @trusted
{
(struct) cpu_pmu_pfm4_name_roundtrip.EncodedResult of one encode.
Encoded (local variable) cpu_pmu_pfm4_name_roundtrip.Encoded ee;
(local variable) cpu_pmu_pfm4_name_roundtrip.Encoded ee.(field) core.sys.linux.perf_event.perf_event_attr cpu_pmu_pfm4_name_roundtrip.Encoded.attrattr.(field) uint core.sys.linux.perf_event.perf_event_attr.sizeSize of the attr structure, for fwd/bwd compat.
size = (struct) core.sys.linux.perf_event.perf_event_attrHardware event_id to monitor via a performance monitoring event:
@sample_max_stack: Max number of frame pointers in a callchain,
should be < /proc/sys/kernel/perf_event_max_stack
perf_event_attr.(constant) ulong core.sys.linux.perf_event.perf_event_attr.sizeof = 112LUsizeof;
char* (local variable) char* fstrfstr;
(struct) cpu_pmu_pfm4_name_roundtrip.pfm_perf_encode_arg_tpfm_perf_encode_arg_t (pfmlib_perf_event.h): 40 bytes on LP64.
pfm_perf_encode_arg_t (local variable) cpu_pmu_pfm4_name_roundtrip.pfm_perf_encode_arg_t argarg;
(local variable) cpu_pmu_pfm4_name_roundtrip.pfm_perf_encode_arg_t argarg.(field) core.sys.linux.perf_event.perf_event_attr* cpu_pmu_pfm4_name_roundtrip.pfm_perf_encode_arg_t.attrattr = &(local variable) cpu_pmu_pfm4_name_roundtrip.Encoded ee.(field) core.sys.linux.perf_event.perf_event_attr cpu_pmu_pfm4_name_roundtrip.Encoded.attrattr;
(local variable) cpu_pmu_pfm4_name_roundtrip.pfm_perf_encode_arg_t argarg.(field) char** cpu_pmu_pfm4_name_roundtrip.pfm_perf_encode_arg_t.fstrfstr = &(local variable) char* fstrfstr;
(local variable) cpu_pmu_pfm4_name_roundtrip.pfm_perf_encode_arg_t argarg.(field) ulong cpu_pmu_pfm4_name_roundtrip.pfm_perf_encode_arg_t.sizesize = (struct) cpu_pmu_pfm4_name_roundtrip.pfm_perf_encode_arg_tpfm_perf_encode_arg_t (pfmlib_perf_event.h): 40 bytes on LP64.
pfm_perf_encode_arg_t.(constant) ulong cpu_pmu_pfm4_name_roundtrip.pfm_perf_encode_arg_t.sizeof = 40LUsizeof;
const (local variable) const(int) rr = int cpu_pmu_pfm4_name_roundtrip.pfm_get_os_event_encoding(const(char)*, int, int, void*)pfm_get_os_event_encoding(
((parameter) string namename ~ '\0').(field) immutable(char)* string.ptrptr, (constant) int cpu_pmu_pfm4_name_roundtrip.PFM_PLM0 = 1PFM_PLM0 | (constant) int cpu_pmu_pfm4_name_roundtrip.PFM_PLM3 = 8PFM_PLM3, (constant) int cpu_pmu_pfm4_name_roundtrip.PFM_OS_PERF_EVENT = 1PFM_OS_PERF_EVENT, &(local variable) cpu_pmu_pfm4_name_roundtrip.pfm_perf_encode_arg_t argarg);
(local variable) cpu_pmu_pfm4_name_roundtrip.Encoded ee.(field) int cpu_pmu_pfm4_name_roundtrip.Encoded.errerr = (local variable) const(int) rr;
(local variable) cpu_pmu_pfm4_name_roundtrip.Encoded ee.(field) bool cpu_pmu_pfm4_name_roundtrip.Encoded.okok = (local variable) const(int) rr == (constant) int cpu_pmu_pfm4_name_roundtrip.PFM_SUCCESS = 0PFM_SUCCESS;
if ((local variable) cpu_pmu_pfm4_name_roundtrip.Encoded ee.(field) bool cpu_pmu_pfm4_name_roundtrip.Encoded.okok)
(local variable) cpu_pmu_pfm4_name_roundtrip.Encoded ee.(field) string cpu_pmu_pfm4_name_roundtrip.Encoded.fstrfstr = string cpu_pmu_pfm4_name_roundtrip.cstr(const(char)* p) @trustedcstr((local variable) char* fstrfstr).string object.idup!(immutable(char))(string a) pure nothrow @property @safeProvide the .idup array property, which creates an immutable duplicate.
idup;
return (local variable) cpu_pmu_pfm4_name_roundtrip.Encoded ee;
}
// ---- perf_event_open counting (mirrors counting-group.d) ----------------
void void cpu_pmu_pfm4_name_roundtrip.ctl(int fd, uint request) @trustedctl(int (parameter) int fdfd, uint (parameter) uint requestrequest) @trusted => cast(void) int core.sys.posix.sys.ioctl.ioctl(int __fd, ulong __request, ...) nothrow @nogcioctl((parameter) int fdfd, cast(c_ulong) (parameter) uint requestrequest, 0);
long long cpu_pmu_pfm4_name_roundtrip.readN(int fd, ulong[] buf) @trustedreadN(int (parameter) int fdfd, ulong[] (parameter) ulong[] bufbuf) @trusted => long core.sys.posix.unistd.read(int, void*, ulong) nothrow @nogcread((parameter) int fdfd, (parameter) ulong[] bufbuf.(field) ulong* ulong[].ptrptr, (parameter) ulong[] bufbuf.(field) ulong ulong[].lengthlength * ulong.(constant) ulong ulong.sizeof = 8LUsizeof);
/// A fixed workload: integer mixing (retired instructions) plus scalar SSE
/// double arithmetic (SSE/AVX FLOPS — one multiply and one add per iter).
/// `__gshared` sinks defeat dead-code elimination.
__gshared ulong (__gshared global) ulong cpu_pmu_pfm4_name_roundtrip.iSinkA fixed workload: integer mixing (retired instructions) plus scalar SSE
double arithmetic (SSE/AVX FLOPS — one multiply and one add per iter).
__gshared sinks defeat dead-code elimination.
iSink;
__gshared double (__gshared global) double cpu_pmu_pfm4_name_roundtrip.fSinkfSink;
void void cpu_pmu_pfm4_name_roundtrip.workload()workload()
{
ulong (local variable) ulong accacc = 0x9E3779B97F4A7C15UL;
double (local variable) double ff = 1.0;
foreach ((local variable) ulong ii; 0 .. 3_000_000UL)
{
(local variable) ulong accacc = ((local variable) ulong accacc + (local variable) ulong ii) * 2654435761UL ^ ((local variable) ulong accacc >> 13);
(local variable) double ff = (local variable) double ff * 1.0000000001 + 0.5; // 1 MULT + 1 ADD_SUB FLOP
}
(__gshared global) ulong cpu_pmu_pfm4_name_roundtrip.iSinkA fixed workload: integer mixing (retired instructions) plus scalar SSE
double arithmetic (SSE/AVX FLOPS — one multiply and one add per iter).
__gshared sinks defeat dead-code elimination.
iSink += (local variable) ulong accacc;
(__gshared global) double cpu_pmu_pfm4_name_roundtrip.fSinkfSink += (local variable) double ff;
}
/// Open the already-encoded `attr` on this thread (pid 0, any cpu), run the
/// workload, and return the multiplexing-scaled count, or `ulong.max` on
/// failure. Adds the two time fields so a rotated counter still scales.
ulong ulong cpu_pmu_pfm4_name_roundtrip.countWith(ref core.sys.linux.perf_event.perf_event_attr attr) @trustedOpen the already-encoded attr on this thread (pid 0, any cpu), run the
workload, and return the multiplexing-scaled count, or ulong.max on
failure. Adds the two time fields so a rotated counter still scales.
countWith(ref (struct) core.sys.linux.perf_event.perf_event_attrHardware event_id to monitor via a performance monitoring event:
@sample_max_stack: Max number of frame pointers in a callchain,
should be < /proc/sys/kernel/perf_event_max_stack
perf_event_attr (parameter) core.sys.linux.perf_event.perf_event_attr attrattr) @trusted
{
(parameter) core.sys.linux.perf_event.perf_event_attr attrattr.(field) ulong core.sys.linux.perf_event.perf_event_attr.read_formatread_format = (enum) core.sys.linux.perf_event.perf_event_read_formatThe format of the data returned by read() on a perf event fd,
as specified by attr.read_format:
struct read_format {
{ u64 value;
{ u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
{ u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
{ u64 id; } && PERF_FORMAT_ID
} && !PERF_FORMAT_GROUP
{ u64 nr;
{ u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
{ u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
{ u64 value;
{ u64 id; } && PERF_FORMAT_ID
} cntr[nr];
} && PERF_FORMAT_GROUP
};
perf_event_read_format.(enum value) core.sys.linux.perf_event.perf_event_read_format.PERF_FORMAT_TOTAL_TIME_ENABLED = 1uPERF_FORMAT_TOTAL_TIME_ENABLED
| (enum) core.sys.linux.perf_event.perf_event_read_formatThe format of the data returned by read() on a perf event fd,
as specified by attr.read_format:
struct read_format {
{ u64 value;
{ u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
{ u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
{ u64 id; } && PERF_FORMAT_ID
} && !PERF_FORMAT_GROUP
{ u64 nr;
{ u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
{ u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
{ u64 value;
{ u64 id; } && PERF_FORMAT_ID
} cntr[nr];
} && PERF_FORMAT_GROUP
};
perf_event_read_format.(enum value) core.sys.linux.perf_event.perf_event_read_format.PERF_FORMAT_TOTAL_TIME_RUNNING = 2uPERF_FORMAT_TOTAL_TIME_RUNNING;
(parameter) core.sys.linux.perf_event.perf_event_attr attrattr.void core.sys.linux.perf_event.perf_event_attr.disabled(ulong v) pure nothrow @nogc @property @safedisabled = 1;
(parameter) core.sys.linux.perf_event.perf_event_attr attrattr.void core.sys.linux.perf_event.perf_event_attr.exclude_hv(ulong v) pure nothrow @nogc @property @safeexclude_hv = 1;
const (local variable) const(int) fdfd = cast(int) long core.sys.linux.perf_event.perf_event_open(core.sys.linux.perf_event.perf_event_attr* hw_event, int pid, int cpu, int group_fd, ulong flags) nothrow @nogcperf_event_open(&(parameter) core.sys.linux.perf_event.perf_event_attr attrattr, 0, -1, -1, 0);
if ((local variable) const(int) fdfd < 0)
return ulong.(constant) ulong ulong.max = 18446744073709551615LUmax;
void cpu_pmu_pfm4_name_roundtrip.ctl(int fd, uint request) @trustedctl((local variable) const(int) fdfd, (constant) int core.sys.linux.perf_event.PERF_EVENT_IOC_RESET = 9219PERF_EVENT_IOC_RESET);
void cpu_pmu_pfm4_name_roundtrip.ctl(int fd, uint request) @trustedctl((local variable) const(int) fdfd, (constant) int core.sys.linux.perf_event.PERF_EVENT_IOC_ENABLE = 9216Ioctls that can be done on a perf event fd:
PERF_EVENT_IOC_ENABLE);
void cpu_pmu_pfm4_name_roundtrip.workload()workload();
void cpu_pmu_pfm4_name_roundtrip.ctl(int fd, uint request) @trustedctl((local variable) const(int) fdfd, (constant) int core.sys.linux.perf_event.PERF_EVENT_IOC_DISABLE = 9217PERF_EVENT_IOC_DISABLE);
ulong[3] (local variable) ulong[3] ss; // value, time_enabled, time_running
const (local variable) const(long) gotgot = long cpu_pmu_pfm4_name_roundtrip.readN(int fd, ulong[] buf) @trustedreadN((local variable) const(int) fdfd, (local variable) ulong[3] ss[]);
int core.sys.posix.unistd.close(int) nothrow @nogc @trustedclose((local variable) const(int) fdfd);
if ((local variable) const(long) gotgot < cast(long)(3 * ulong.(constant) ulong ulong.sizeof = 8LUsizeof) || (local variable) ulong[3] ss[2] == 0)
return ulong.(constant) ulong ulong.max = 18446744073709551615LUmax;
return (local variable) ulong[3] ss[2] < (local variable) ulong[3] ss[1] ? cast(ulong)((local variable) ulong[3] ss[0] * (cast(double) (local variable) ulong[3] ss[1] / (local variable) ulong[3] ss[2])) : (local variable) ulong[3] ss[0];
}
/// Report one name: encode, print type/config/exclude, then count.
void void cpu_pmu_pfm4_name_roundtrip.report(string label, string name) @trustedReport one name: encode, print type/config/exclude, then count.
report((alias) object.string = stringstring (parameter) string labellabel, (alias) object.string = stringstring (parameter) string namename) @trusted
{
auto (local variable) cpu_pmu_pfm4_name_roundtrip.Encoded ee = cpu_pmu_pfm4_name_roundtrip.Encoded cpu_pmu_pfm4_name_roundtrip.encode(string name) @trustedName → perf_event_attr via libpfm. Counting at both priv levels
(PLM0|PLM3) is the default; per-name :u/:k modifiers override it.
encode((parameter) string namename);
if (!(local variable) cpu_pmu_pfm4_name_roundtrip.Encoded ee.(field) bool cpu_pmu_pfm4_name_roundtrip.Encoded.okok)
{
void std.stdio.writefln!(char, string, string, string, int)(in char[] fmt, string __param_1, string __param_2, string __param_3, int __param_4) @safeEquivalent to writef(fmt, args, '\n').
writefln(" %-13s %-42s ENCODE FAILED: %s (%d)",
(parameter) string labellabel, (parameter) string namename, string cpu_pmu_pfm4_name_roundtrip.cstr(const(char)* p) @trustedcstr(const(char)* cpu_pmu_pfm4_name_roundtrip.pfm_strerror(int)pfm_strerror((local variable) cpu_pmu_pfm4_name_roundtrip.Encoded ee.(field) int cpu_pmu_pfm4_name_roundtrip.Encoded.errerr)), (local variable) cpu_pmu_pfm4_name_roundtrip.Encoded ee.(field) int cpu_pmu_pfm4_name_roundtrip.Encoded.errerr);
return;
}
auto (local variable) core.sys.linux.perf_event.perf_event_attr attrattr = (local variable) cpu_pmu_pfm4_name_roundtrip.Encoded ee.(field) core.sys.linux.perf_event.perf_event_attr cpu_pmu_pfm4_name_roundtrip.Encoded.attrattr; // copy: countWith mutates read_format/flags
const (local variable) const(ulong) cntcnt = ulong cpu_pmu_pfm4_name_roundtrip.countWith(ref core.sys.linux.perf_event.perf_event_attr attr) @trustedOpen the already-encoded attr on this thread (pid 0, any cpu), run the
workload, and return the multiplexing-scaled count, or ulong.max on
failure. Adds the two time fields so a rotated counter still scales.
countWith((local variable) core.sys.linux.perf_event.perf_event_attr attrattr);
void std.stdio.writefln!(char, string, string)(in char[] fmt, string __param_1, string __param_2) @safeEquivalent to writef(fmt, args, '\n').
writefln(" %-13s %s", (parameter) string labellabel, (parameter) string namename);
void std.stdio.writefln!(char, uint, ulong, ulong, ulong)(in char[] fmt, uint __param_1, ulong __param_2, ulong __param_3, ulong __param_4) @safeEquivalent to writef(fmt, args, '\n').
writefln(" type=%d config=0x%x exclude_user=%d exclude_kernel=%d",
(local variable) cpu_pmu_pfm4_name_roundtrip.Encoded ee.(field) core.sys.linux.perf_event.perf_event_attr cpu_pmu_pfm4_name_roundtrip.Encoded.attrattr.(field) uint core.sys.linux.perf_event.perf_event_attr.typeMajor type: hardware/software/tracepoint/etc.
type, (local variable) cpu_pmu_pfm4_name_roundtrip.Encoded ee.(field) core.sys.linux.perf_event.perf_event_attr cpu_pmu_pfm4_name_roundtrip.Encoded.attrattr.(field) ulong core.sys.linux.perf_event.perf_event_attr.configType specific configuration information.
config, (local variable) cpu_pmu_pfm4_name_roundtrip.Encoded ee.(field) core.sys.linux.perf_event.perf_event_attr cpu_pmu_pfm4_name_roundtrip.Encoded.attrattr.ulong core.sys.linux.perf_event.perf_event_attr.exclude_user() const pure nothrow @nogc @property @safeexclude_user, (local variable) cpu_pmu_pfm4_name_roundtrip.Encoded ee.(field) core.sys.linux.perf_event.perf_event_attr cpu_pmu_pfm4_name_roundtrip.Encoded.attrattr.ulong core.sys.linux.perf_event.perf_event_attr.exclude_kernel() const pure nothrow @nogc @property @safeexclude_kernel);
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safeEquivalent to writef(fmt, args, '\n').
writefln(" fstr=%s", (local variable) cpu_pmu_pfm4_name_roundtrip.Encoded ee.(field) string cpu_pmu_pfm4_name_roundtrip.Encoded.fstrfstr);
if ((local variable) const(ulong) cntcnt == ulong.(constant) ulong ulong.max = 18446744073709551615LUmax)
void std.stdio.writefln!char(in char[] fmt) @safeEquivalent to writef(fmt, args, '\n').
writefln(" count: <perf_event_open/read failed on this host>");
else
void std.stdio.writefln!(char, const(ulong))(in char[] fmt, const(ulong) __param_1) @safeEquivalent to writef(fmt, args, '\n').
writefln(" count over workload window: %d", (local variable) const(ulong) cntcnt);
}
/// Map /proc/cpuinfo (vendor + family + model) to the libpfm core-PMU table
/// name — mirroring the *fixed* `amd64_get_revision` (libpfm HEAD). Returns
/// null for anything this probe does not have a hand table for (non-AMD, or
/// an AMD family we don't enumerate) → the µarch-specific section is skipped.
(alias) object.string = stringstring string cpu_pmu_pfm4_name_roundtrip.amdPmuName() @trustedMap /proc/cpuinfo (vendor + family + model) to the libpfm core-PMU table
name — mirroring the fixed amd64_get_revision (libpfm HEAD). Returns
null for anything this probe does not have a hand table for (non-AMD, or
an AMD family we don't enumerate) → the µarch-specific section is skipped.
amdPmuName() @trusted
{
import (package) stdstd.(module) std.convA one-stop shop for converting values from one type to another.
Category Functions Generic asOriginalType castFrom parse to toChars bitCast Strings text wtext dtext writeText writeWText writeDText hexString Numeric octal roundTo signed unsigned Exceptions ConvException ConvOverflowException
Source
std/conv.d
conv : (alias template) to = std.conv.to(T)The to template converts a value from one type _to another.
The source type is deduced and the target type must be specified, for example the
expression to!int(42.0) converts the number 42 from
double _to int. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., to!double(42) does not do
any checking because any int fits in a double.
Conversions from string _to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings _to signed types, the grammar recognized is:
$(PRE $(I Integer):
$(I Sign UnsignedInteger)
$(I UnsignedInteger)
$(I Sign):
$(B +)
$(B -))
For conversion _to unsigned types, the grammar recognized is:
$(PRE $(I UnsignedInteger):
$(I DecimalDigit)
$(I DecimalDigit) $(I UnsignedInteger))
to;
(alias) object.string = stringstring (local variable) string vendorvendor;
int (local variable) int familyfamily = -1, (local variable) int modelmodel = -1;
try
{
import (package) stdstd.(module) std.fileUtilities for manipulating files and scanning directories. Functions
in this module handle files as a unit, e.g., read or write one file
at a time. For opening files and manipulating them via handles refer
to module std.stdio.
Category Functions General exists isDir isFile isSymlink rename thisExePath Directories chdir dirEntries getcwd mkdir mkdirRecurse rmdir rmdirRecurse tempDir Files append copy read readText remove slurp write Symlinks symlink readLink Attributes attrIsDir attrIsFile attrIsSymlink getAttributes getLinkAttributes getSize setAttributes Timestamp getTimes getTimesWin setTimes timeLastModified timeLastAccessed timeStatusChanged Other DirEntry FileException PreserveAttributes SpanMode getAvailableDiskSpace
Source
std/file.d
file : (alias template) readText = std.file.readText(S = string, R)(auto ref R name) if (isSomeString!S && (isSomeFiniteCharInputRange!R || is(StringTypeOf!R)))Reads and validates (using $(REF validate, std, utf)) a text file. S can be
an array of any character type. However, no width or endian conversions are
performed. So, if the width or endianness of the characters in the given
file differ from the width or endianness of the element type of S, then
validation will fail.
Params:
S = the string type of the file
name = string or range of characters representing the file _name
Returns: Array of characters read.
Throws: $(LREF FileException) if there is an error reading the file,
$(REF UTFException, std, utf) on UTF decoding error.
See_Also: $(REF read, std,file) for reading a binary file.
readText;
foreach ((local variable) string lineline; string std.file.readText!(string, string)(string name) @safeReads and validates (using validate) a text file. S can be
an array of any character type. However, no width or endian conversions are
performed. So, if the width or endianness of the characters in the given
file differ from the width or endianness of the element type of S, then
validation will fail.
Examples
Read file with UTF-8 text.
write(deleteme, "abc"); // deleteme is the name of a temporary file
scope(exit) remove(deleteme);
string content = readText(deleteme);
assert(content == "abc");
readText("/proc/cpuinfo").std.string.LineSplitter!(Flag.no, string) std.string.lineSplitter!(Flag.no, immutable(char))(string r) pure nothrow @nogc @safeSplit an array or slicable range of characters into a range of lines
using '\r', '\n', '\v', '\f', "\r\n",
lineSep, paraSep and '\u0085' (NEL)
as delimiters. If keepTerm is set to Yes.keepTerminator, then the
delimiter is included in the slices returned.
Does not throw on invalid UTF; such is simply passed unchanged
to the output.
Adheres to Unicode 7.0.
Does not allocate memory.
Examples
import std.array : array;
string s = "Hello\nmy\rname\nis";
/* notice the call to 'array' to turn the lazy range created by
lineSplitter comparable to the string[] created by splitLines.
*/
assert(lineSplitter(s).array == splitLines(s));
auto s = "\rpeter\n\rpaul\r\njerry\u2028ice\u2029cream\n\nsunday\nmon\u2030day\n";
auto lines = s.lineSplitter();
static immutable witness = ["", "peter", "", "paul", "jerry", "ice", "cream", "", "sunday", "mon\u2030day"];
uint i;
foreach (line; lines)
{
assert(line == witness[i++]);
}
assert(i == witness.length);
lineSplitter)
{
if ((local variable) string lineline.bool std.algorithm.searching.startsWith!("a == b", string, string)(string doesThisStart, string withThis) pure nothrow @nogc @safeChecks whether the given
input range starts with (one
of) the given needle(s) or, if no needles are given,
if its front element fulfils predicate pred.
For more information about pred see find.
startsWith("vendor_id") && (local variable) string vendorvendor is null)
(local variable) string vendorvendor = (local variable) string lineline["vendor_id".(constant) ulong "vendor_id".length = 9LUlength .. $].string std.string.strip!(string, char)(string str, const(char)[] chars) pure @safeExamples
assert(strip(" hello world ", "x") ==
" hello world ");
assert(strip(" hello world ", " ") ==
"hello world");
assert(strip(" xyxyhello worldxyxy ", "xy ") ==
"hello world");
assert(strip("\u2020hello\u2020"w, "\u2020"w) == "hello"w);
assert(strip("\U00010001hello\U00010001"d, "\U00010001"d) == "hello"d);
assert(strip(" hello ", "") == " hello ");
strip(" \t:").string object.idup!(immutable(char))(string a) pure nothrow @property @safeProvide the .idup array property, which creates an immutable duplicate.
idup;
else if ((local variable) string lineline.bool std.algorithm.searching.startsWith!("a == b", string, string)(string doesThisStart, string withThis) pure nothrow @nogc @safeChecks whether the given
input range starts with (one
of) the given needle(s) or, if no needles are given,
if its front element fulfils predicate pred.
For more information about pred see find.
startsWith("cpu family") && (local variable) int familyfamily < 0)
(local variable) int familyfamily = (local variable) string lineline["cpu family".(constant) ulong "cpu family".length = 10LUlength .. $].string std.string.strip!(string, char)(string str, const(char)[] chars) pure @safeExamples
assert(strip(" hello world ", "x") ==
" hello world ");
assert(strip(" hello world ", " ") ==
"hello world");
assert(strip(" xyxyhello worldxyxy ", "xy ") ==
"hello world");
assert(strip("\u2020hello\u2020"w, "\u2020"w) == "hello"w);
assert(strip("\U00010001hello\U00010001"d, "\U00010001"d) == "hello"d);
assert(strip(" hello ", "") == " hello ");
strip(" \t:").int std.conv.to!int.to!string(string __param_0) pure @safeThe to template converts a value from one type to another.
The source type is deduced and the target type must be specified, for example the
expression to`!int(42.0)` converts the number 42 from
`double` to `int`. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., ``to!double(42) does not do
any checking because any int fits in a double.
Conversions from string to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings to signed types, the grammar recognized is:
Integer:
Sign UnsignedInteger
UnsignedInteger
Sign:
+
-
For conversion to unsigned types, the grammar recognized is:
UnsignedInteger:
DecimalDigit
DecimalDigit UnsignedInteger
Examples
Converting a value to its own type (useful mostly for generic code)
simply returns its argument.
int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14
Converting among numeric types is a safe way to cast them around.
Conversions from floating-point types to integral types allow loss of
precision (the fractional part of a floating-point number). The
conversion is truncating towards zero, the same way a cast would
truncate. (To round a floating point value when casting to an
integral, use roundTo.)
import std.exception : assertThrown;
int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));
assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);
When converting strings to numeric types, note that D hexadecimal and binary
literals are not handled. Neither the prefixes that indicate the base, nor the
horizontal bar used to separate groups of digits are recognized. This also
applies to the suffixes that indicate the type.
To work around this, you can specify a radix for conversions involving numbers.
auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);
Conversions from integral types to floating-point types always
succeed, but might lose accuracy. The largest integers with a
predecessor representable in floating-point format are 2^24-1 for
float, 2^53-1 for double, and 2^64-1 for real (when
real is 80-bit, e.g. on Intel machines).
// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);
Conversion from string types to char types enforces the input
to consist of a single code point, and said code point must
fit in the target type. Otherwise, ConvException is thrown.
import std.exception : assertThrown;
assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');
// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');
// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));
Converting an array to another array type works by converting each
element in turn. Associative arrays can be converted to associative
arrays as long as keys and values can in turn be converted.
import std.string : split;
int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);
Conversions operate transitively, meaning that they work on arrays and
associative arrays of any complexity.
This conversion works because to`!short` applies to an `int`, to!wstring
applies to a string, to`!string` applies to a `double`, and
to!(double[]) applies to an int[]. The conversion might throw an
exception because ``to!short might fail the range check.
int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);
Object-to-object conversions by dynamic casting throw exception when
the source is non-null and the target is null.
import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));
Stringize conversion from all types is supported.
String to string conversion works for any two string types having
(char, wchar, dchar) character widths and any
combination of qualifiers (mutable, const, or immutable).
Converts array (other than strings) to string.
Each element is converted by calling ``to!T.
Associative array to string conversion.
Each element is converted by calling ``to!T.
Object to string conversion calls toString against the object or
returns "null" if the object is null.
Struct to string conversion calls toString against the struct if
it is defined.
For structs that do not define toString, the conversion to string
produces the list of fields.
Enumerated types are converted to strings as their symbolic names.
Boolean values are converted to "true" or "false".
char, wchar, dchar to a string type.
Unsigned or signed integers to strings.
: Convert integral value to string in radix radix.
radix must be a value from 2 to 36.
value is treated as a signed value only if radix is 10.
The characters A through Z are used to represent values 10 through 36
and their case is determined by the letterCase parameter.
All floating point types to all string types.
Pointer to string conversions convert the pointer to a size_t value.
If pointer is char*, treat it as C-style strings.
In that case, this function is @system.
See formatValue on how toString should be defined.
// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");
// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
to!string(associativeArray) == `["1":2, "0":1]`);
// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");
// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);
auto c = to!(wchar[])(b);
assert(c == "abcx");
Strings can be converted to enum types. The enum member with the same name as the
input string is returned. The comparison is case-sensitive.
A ConvException is thrown if the enum does not have the specified member.
import std.exception : assertThrown;
enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to!int;
else if ((local variable) string lineline.bool std.algorithm.searching.startsWith!("a == b", string, string)(string doesThisStart, string withThis) pure nothrow @nogc @safeChecks whether the given
input range starts with (one
of) the given needle(s) or, if no needles are given,
if its front element fulfils predicate pred.
For more information about pred see find.
startsWith("model") && !(local variable) string lineline.bool std.algorithm.searching.startsWith!("a == b", string, string)(string doesThisStart, string withThis) pure nothrow @nogc @safeChecks whether the given
input range starts with (one
of) the given needle(s) or, if no needles are given,
if its front element fulfils predicate pred.
For more information about pred see find.
startsWith("model name") && (local variable) int modelmodel < 0)
(local variable) int modelmodel = (local variable) string lineline["model".(constant) ulong "model".length = 5LUlength .. $].string std.string.strip!(string, char)(string str, const(char)[] chars) pure @safeExamples
assert(strip(" hello world ", "x") ==
" hello world ");
assert(strip(" hello world ", " ") ==
"hello world");
assert(strip(" xyxyhello worldxyxy ", "xy ") ==
"hello world");
assert(strip("\u2020hello\u2020"w, "\u2020"w) == "hello"w);
assert(strip("\U00010001hello\U00010001"d, "\U00010001"d) == "hello"d);
assert(strip(" hello ", "") == " hello ");
strip(" \t:").int std.conv.to!int.to!string(string __param_0) pure @safeThe to template converts a value from one type to another.
The source type is deduced and the target type must be specified, for example the
expression to`!int(42.0)` converts the number 42 from
`double` to `int`. The conversion is "safe", i.e.,
it checks for overflow; to!int(4.2e10) would throw the
ConvOverflowException exception. Overflow checks are only
inserted when necessary, e.g., ``to!double(42) does not do
any checking because any int fits in a double.
Conversions from string to numeric types differ from the C equivalents
atoi() and atol() by checking for overflow and not allowing whitespace.
For conversion of strings to signed types, the grammar recognized is:
Integer:
Sign UnsignedInteger
UnsignedInteger
Sign:
+
-
For conversion to unsigned types, the grammar recognized is:
UnsignedInteger:
DecimalDigit
DecimalDigit UnsignedInteger
Examples
Converting a value to its own type (useful mostly for generic code)
simply returns its argument.
int a = 42;
int b = to!int(a);
double c = to!double(3.14); // c is double with value 3.14
Converting among numeric types is a safe way to cast them around.
Conversions from floating-point types to integral types allow loss of
precision (the fractional part of a floating-point number). The
conversion is truncating towards zero, the same way a cast would
truncate. (To round a floating point value when casting to an
integral, use roundTo.)
import std.exception : assertThrown;
int a = 420;
assert(to!long(a) == a);
assertThrown!ConvOverflowException(to!byte(a));
assert(to!int(4.2e6) == 4200000);
assertThrown!ConvOverflowException(to!uint(-3.14));
assert(to!uint(3.14) == 3);
assert(to!uint(3.99) == 3);
assert(to!int(-3.99) == -3);
When converting strings to numeric types, note that D hexadecimal and binary
literals are not handled. Neither the prefixes that indicate the base, nor the
horizontal bar used to separate groups of digits are recognized. This also
applies to the suffixes that indicate the type.
To work around this, you can specify a radix for conversions involving numbers.
auto str = to!string(42, 16);
assert(str == "2A");
auto i = to!int(str, 16);
assert(i == 42);
Conversions from integral types to floating-point types always
succeed, but might lose accuracy. The largest integers with a
predecessor representable in floating-point format are 2^24-1 for
float, 2^53-1 for double, and 2^64-1 for real (when
real is 80-bit, e.g. on Intel machines).
// 2^24 - 1, largest proper integer representable as float
int a = 16_777_215;
assert(to!int(to!float(a)) == a);
assert(to!int(to!float(-a)) == -a);
Conversion from string types to char types enforces the input
to consist of a single code point, and said code point must
fit in the target type. Otherwise, ConvException is thrown.
import std.exception : assertThrown;
assert(to!char("a") == 'a');
assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
assert(to!wchar("ñ") == 'ñ');
assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
assert(to!dchar("😃") == '😃');
// Using wstring or dstring as source type does not affect the result
assert(to!char("a"w) == 'a');
assert(to!char("a"d) == 'a');
// Two code points cannot be converted to a single one
assertThrown(to!char("ab"));
Converting an array to another array type works by converting each
element in turn. Associative arrays can be converted to associative
arrays as long as keys and values can in turn be converted.
import std.string : split;
int[] a = [1, 2, 3];
auto b = to!(float[])(a);
assert(b == [1.0f, 2, 3]);
string str = "1 2 3 4 5 6";
auto numbers = to!(double[])(split(str));
assert(numbers == [1.0, 2, 3, 4, 5, 6]);
int[string] c;
c["a"] = 1;
c["b"] = 2;
auto d = to!(double[wstring])(c);
assert(d["a"w] == 1 && d["b"w] == 2);
Conversions operate transitively, meaning that they work on arrays and
associative arrays of any complexity.
This conversion works because to`!short` applies to an `int`, to!wstring
applies to a string, to`!string` applies to a `double`, and
to!(double[]) applies to an int[]. The conversion might throw an
exception because ``to!short might fail the range check.
int[string][double[int[]]] a;
auto b = to!(short[wstring][string[double[]]])(a);
Object-to-object conversions by dynamic casting throw exception when
the source is non-null and the target is null.
import std.exception : assertThrown;
// Testing object conversions
class A {}
class B : A {}
class C : A {}
A a1 = new A, a2 = new B, a3 = new C;
assert(to!B(a2) is a2);
assert(to!C(a3) is a3);
assertThrown!ConvException(to!B(a3));
Stringize conversion from all types is supported.
String to string conversion works for any two string types having
(char, wchar, dchar) character widths and any
combination of qualifiers (mutable, const, or immutable).
Converts array (other than strings) to string.
Each element is converted by calling ``to!T.
Associative array to string conversion.
Each element is converted by calling ``to!T.
Object to string conversion calls toString against the object or
returns "null" if the object is null.
Struct to string conversion calls toString against the struct if
it is defined.
For structs that do not define toString, the conversion to string
produces the list of fields.
Enumerated types are converted to strings as their symbolic names.
Boolean values are converted to "true" or "false".
char, wchar, dchar to a string type.
Unsigned or signed integers to strings.
: Convert integral value to string in radix radix.
radix must be a value from 2 to 36.
value is treated as a signed value only if radix is 10.
The characters A through Z are used to represent values 10 through 36
and their case is determined by the letterCase parameter.
All floating point types to all string types.
Pointer to string conversions convert the pointer to a size_t value.
If pointer is char*, treat it as C-style strings.
In that case, this function is @system.
See formatValue on how toString should be defined.
// Conversion representing dynamic/static array with string
long[] a = [ 1, 3, 5 ];
assert(to!string(a) == "[1, 3, 5]");
// Conversion representing associative array with string
int[string] associativeArray = ["0":1, "1":2];
assert(to!string(associativeArray) == `["0":1, "1":2]` ||
to!string(associativeArray) == `["1":2, "0":1]`);
// char* to string conversion
assert(to!string(cast(char*) null) == "");
assert(to!string("foo\0".ptr) == "foo");
// Conversion reinterpreting void array to string
auto w = "abcx"w;
const(void)[] b = w;
assert(b.length == 8);
auto c = to!(wchar[])(b);
assert(c == "abcx");
Strings can be converted to enum types. The enum member with the same name as the
input string is returned. The comparison is case-sensitive.
A ConvException is thrown if the enum does not have the specified member.
import std.exception : assertThrown;
enum E { a, b, c }
assert(to!E("a") == E.a);
assert(to!E("b") == E.b);
assertThrown!ConvException(to!E("A"));
to!int;
}
}
catch ((class) object.ExceptionThe base class of all errors that are safe to catch and handle.
In principle, only thrown objects derived from this class are safe to catch
inside a catch block. Thrown objects not derived from Exception
represent runtime errors that should not be caught, as certain runtime
guarantees may not hold, making it unsafe to continue program execution.
Examples
bool gotCaught;
try
{
throw new Exception("msg");
}
catch (Exception e)
{
gotCaught = true;
assert(e.msg == "msg");
}
assert(gotCaught);
Exception)
return null;
if ((local variable) string vendorvendor != "AuthenticAMD")
return null;
switch ((local variable) int familyfamily)
{
case 23: // 17h
return (local variable) int modelmodel >= 0x30 ? "amd64_fam17h_zen2" : "amd64_fam17h_zen1";
case 25: // 19h
return ((local variable) int modelmodel >= 0x60 || ((local variable) int modelmodel >= 0x10 && (local variable) int modelmodel <= 0x1f))
? "amd64_fam19h_zen4" : "amd64_fam19h_zen3";
case 26: // 1ah
return ((local variable) int modelmodel <= 0x4f || ((local variable) int modelmodel >= 0x60 && (local variable) int modelmodel <= 0x7f))
? "amd64_fam1ah_zen5" : "amd64_fam1ah_zen6";
default:
return null;
}
}
int int cpu_pmu_pfm4_name_roundtrip.run()run()
{
// Work around libpfm 4.13.0's auto-detect gap (see the header): place
// un-detected per-µarch tables on the searchable list so an explicit
// `pmu::event` prefix resolves. Must precede pfm_initialize.
int core.sys.posix.stdlib.setenv(scope const(char*), scope const(char*), int) nothrow @nogcsetenv("LIBPFM_ENCODE_INACTIVE", "1", 1);
const (local variable) const(int) initRcinitRc = int cpu_pmu_pfm4_name_roundtrip.pfm_initialize()pfm_initialize();
if ((local variable) const(int) initRcinitRc != (constant) int cpu_pmu_pfm4_name_roundtrip.PFM_SUCCESS = 0PFM_SUCCESS)
{
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safeEquivalent to writef(fmt, args, '\n').
writefln("SKIP: pfm_initialize failed (%s) — libpfm unusable on this host",
string cpu_pmu_pfm4_name_roundtrip.cstr(const(char)* p) @trustedcstr(const(char)* cpu_pmu_pfm4_name_roundtrip.pfm_strerror(int)pfm_strerror((local variable) const(int) initRcinitRc)));
return 0;
}
const (local variable) const(int) vv = int cpu_pmu_pfm4_name_roundtrip.pfm_get_version()pfm_get_version();
void std.stdio.writefln!(char, const(int), int)(in char[] fmt, const(int) __param_1, int __param_2) @safeEquivalent to writef(fmt, args, '\n').
writefln("libpfm interface version %d.%d (release: see nixpkgs libpfm)",
(local variable) const(int) vv >> 16, (local variable) const(int) vv & 0xffff);
// --- Generic (OS-abstracted) name: resolves via the always-present
// `perf` PMU regardless of hardware. ---
void std.stdio.writeln!string(string __param_0) @safeEquivalent 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);
}
}
writeln("\n== generic perf name (PERF_TYPE_HARDWARE) ==");
void cpu_pmu_pfm4_name_roundtrip.report(string label, string name) @trustedReport one name: encode, print type/config/exclude, then count.
report("generic", "PERF_COUNT_HW_CPU_CYCLES");
// Probe whether we can count at all; if the generic open failed for
// permission reasons, everything else will too.
{
auto (local variable) cpu_pmu_pfm4_name_roundtrip.Encoded probeprobe = cpu_pmu_pfm4_name_roundtrip.Encoded cpu_pmu_pfm4_name_roundtrip.encode(string name) @trustedName → perf_event_attr via libpfm. Counting at both priv levels
(PLM0|PLM3) is the default; per-name :u/:k modifiers override it.
encode("PERF_COUNT_HW_CPU_CYCLES");
if ((local variable) cpu_pmu_pfm4_name_roundtrip.Encoded probeprobe.(field) bool cpu_pmu_pfm4_name_roundtrip.Encoded.okok)
{
auto (local variable) core.sys.linux.perf_event.perf_event_attr aa = (local variable) cpu_pmu_pfm4_name_roundtrip.Encoded probeprobe.(field) core.sys.linux.perf_event.perf_event_attr cpu_pmu_pfm4_name_roundtrip.Encoded.attrattr;
if (ulong cpu_pmu_pfm4_name_roundtrip.countWith(ref core.sys.linux.perf_event.perf_event_attr attr) @trustedOpen the already-encoded attr on this thread (pid 0, any cpu), run the
workload, and return the multiplexing-scaled count, or ulong.max on
failure. Adds the two time fields so a rotated counter still scales.
countWith((local variable) core.sys.linux.perf_event.perf_event_attr aa) == ulong.(constant) ulong ulong.max = 18446744073709551615LUmax)
{
void std.stdio.writefln!char(in char[] fmt) @safeEquivalent to writef(fmt, args, '\n').
writefln("SKIP: perf_event_open failed — perf_event_paranoid too high, "
~ "seccomp, or no PMU on this host");
return 0;
}
}
}
// --- Microarchitecture-specific names via the host's libpfm table. ---
const (local variable) const(string) pmupmu = string cpu_pmu_pfm4_name_roundtrip.amdPmuName() @trustedMap /proc/cpuinfo (vendor + family + model) to the libpfm core-PMU table
name — mirroring the fixed amd64_get_revision (libpfm HEAD). Returns
null for anything this probe does not have a hand table for (non-AMD, or
an AMD family we don't enumerate) → the µarch-specific section is skipped.
amdPmuName();
if ((local variable) const(string) pmupmu is null)
{
void std.stdio.writeln!string(string __param_0) @safeEquivalent 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);
}
}
writeln("\n== µarch-specific names: SKIPPED (no hand table for this CPU; "
~ "generic path above still demonstrates the round trip) ==");
return 0;
}
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safeEquivalent to writef(fmt, args, '\n').
writefln("\n== µarch-specific names via the %s table (PERF_TYPE_RAW) ==", (local variable) const(string) pmupmu);
void cpu_pmu_pfm4_name_roundtrip.report(string label, string name) @trustedReport one name: encode, print type/config/exclude, then count.
report("zen4-native", (local variable) const(string) pmupmu ~ "::RETIRED_INSTRUCTIONS");
void cpu_pmu_pfm4_name_roundtrip.report(string label, string name) @trustedReport one name: encode, print type/config/exclude, then count.
report("with-umask", (local variable) const(string) pmupmu ~ "::RETIRED_SSE_AVX_FLOPS:ADD_SUB_FLOPS");
void cpu_pmu_pfm4_name_roundtrip.report(string label, string name) @trustedReport one name: encode, print type/config/exclude, then count.
report("with-modifier", (local variable) const(string) pmupmu ~ "::RETIRED_INSTRUCTIONS:u");
void std.stdio.writeln!string(string __param_0) @safeEquivalent 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);
}
}
writeln("\n (config unchanged between native and :u — user/kernel filtering "
~ "moved into attr.exclude_*, the PFM_OS_PERF_EVENT split.)");
return 0;
}
}
int int D main()main()
{
version (linuxlinux)
return int cpu_pmu_pfm4_name_roundtrip.run()run();
else
{
import std.stdio : writefln;
writefln("SKIP: libpfm4 / perf_event_open is Linux-only");
return 0;
}
}