#!/usr/bin/env dub
/+ dub.sdl:
name "cpu_pmu_sampling_symbolize"
platforms "linux"
libs "dw" "elf"
dflags "-g"
targetPath "build"
+/
/**
* Overflow/IP sampling through the `perf_event` mmap ring buffer, then
* symbolization of the sampled instruction pointers via elfutils `libdwfl`.
*
* This is the end-to-end "profiler core": a hardware event (`cycles`) is armed
* with a target sample *frequency*; on each overflow the kernel writes a
* `PERF_RECORD_SAMPLE` (carrying the interrupted IP) into a memory-mapped ring
* buffer. We drain the ring, then hand the *live* process to `libdwfl`
* (`dwfl_linux_proc_report`, the library's own `/proc/PID/maps` reader) and
* resolve each IP to module → symbol (`dwfl_module_addrinfo`) → source line
* (`dwfl_module_getsrc` + `dwfl_lineinfo`).
*
* A key, verified subtlety about `PERF_RECORD_MMAP2` (`attr.mmap2 = 1`): the
* kernel emits it only for executable mappings **created while the event is
* enabled** — it does NOT re-emit pre-existing code (our own binary, libc).
* That is why the `perf` tool *synthesizes* `MMAP2` for the already-mapped
* regions from `/proc/PID/maps` at start, and why `libdwfl`'s
* `dwfl_linux_proc_report` reads the same file. To make a real captured
* `MMAP2` visible, we deliberately map `/proc/self/exe` `PROT_EXEC` mid-window;
* its record's `filename` matches the binary `libdwfl` symbolizes against —
* tying the two halves of the address-space model together.
*
* Companion to docs/research/cpu-pmu/linux-perf-events.md
* § "Overflow sampling: the ring buffer, `PERF_RECORD_MMAP2`, and IP
* symbolization" and docs/research/cpu-pmu/elfutils.md § "Address →
* module → symbol → line".
*
* Run with: nix shell nixpkgs#elfutils nixpkgs#pkg-config -c dub run --single sampling-symbolize.d
*
* Environment recorded: Linux 6.18.26, AMD Ryzen 9 7940HX (Zen 4),
* `/proc/sys/kernel/perf_event_paranoid` = -1, elfutils 0.195 (libdw/libdwfl),
* LDC 1.41 druntime `core.sys.linux.perf_event`. Linked with the flake
* stdenv dynamic linker (glibc 2.42) so elfutils 0.195 can resolve
* `GLIBC_ABI_GNU2_TLS` — see nix/d-toolchain.nix.
*
* Portability: any missing capability (`perf_event_open`/`mmap` refused by
* `perf_event_paranoid`/seccomp, no PMU, non-Linux) prints a `SKIP:` line and
* exits 0 so CI stays green on any host. A binary with no DWARF line table just
* prints symbol names without `file:line` — also a success.
*/
module (module) cpu_pmu_sampling_symbolizeOverflow/IP sampling through the perf_event mmap ring buffer, then
symbolization of the sampled instruction pointers via elfutils libdwfl.
This is the end-to-end "profiler core": a hardware event (cycles) is armed
with a target sample frequency; on each overflow the kernel writes a
PERF_RECORD_SAMPLE (carrying the interrupted IP) into a memory-mapped ring
buffer. We drain the ring, then hand the live process to libdwfl
(dwfl_linux_proc_report, the library's own /proc/PID/maps reader) and
resolve each IP to module → symbol (dwfl_module_addrinfo) → source line
(dwfl_module_getsrc + dwfl_lineinfo).
A key, verified subtlety about PERF_RECORD_MMAP2 (attr.mmap2 = 1): the
kernel emits it only for executable mappings created while the event is
enabled — it does NOT re-emit pre-existing code (our own binary, libc).
That is why the perf tool synthesizes MMAP2 for the already-mapped
regions from /proc/PID/maps at start, and why libdwfl's
dwfl_linux_proc_report reads the same file. To make a real captured
MMAP2 visible, we deliberately map /proc/self/exe PROT_EXEC mid-window;
its record's filename matches the binary libdwfl symbolizes against —
tying the two halves of the address-space model together.
Companion to docs/research/cpu-pmu/linux-perf-events.md
§ "Overflow sampling: the ring buffer, PERF_RECORD_MMAP2, and IP
symbolization" and docs/research/cpu-pmu/elfutils.md § "Address →
module → symbol → line".
Run with: nix shell nixpkgs#elfutils nixpkgs#pkg-config -c dub run --single sampling-symbolize.d
Environment recorded: Linux 6.18.26, AMD Ryzen 9 7940HX (Zen 4),
/proc/sys/kernel/perf_event_paranoid = -1, elfutils 0.195 (libdw/libdwfl),
LDC 1.41 druntime core.sys.linux.perf_event. Linked with the flake
stdenv dynamic linker (glibc 2.42) so elfutils 0.195 can resolve
GLIBC_ABI_GNU2_TLS — see nix/d-toolchain.nix.
Portability
any missing capability (perf_event_open/mmap refused by
perf_event_paranoid/seccomp, no PMU, non-Linux) prints a SKIP: line and
exits 0 so CI stays green on any host. A binary with no DWARF line table just
prints symbol names without file:line — also a success.
cpu_pmu_sampling_symbolize;
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;
import (package) corecore.(package) core.syssys.(package) core.sys.posixposix.(module) core.sys.posix.unistdD header file for POSIX.
unistd : (alias) cpu_pmu_sampling_symbolize.close = int core.sys.posix.unistd.close(int) nothrow @nogc @trustedclose, (alias) cpu_pmu_sampling_symbolize.getpid = int core.sys.posix.unistd.getpid() nothrow @nogc @trustedgetpid, (alias) cpu_pmu_sampling_symbolize.sysconf = long core.sys.posix.unistd.sysconf(int) nothrow @nogc @trustedsysconf, (alias enum value) cpu_pmu_sampling_symbolize._SC_PAGESIZE = core.sys.posix.unistd._SC_PAGESIZE = 30_SC_PAGESIZE;
import (package) corecore.(package) core.syssys.(package) core.sys.posixposix.(module) core.sys.posix.fcntlD header file for POSIX.
fcntl : open, (alias constant) cpu_pmu_sampling_symbolize.O_RDONLY = int core.sys.posix.fcntl.O_RDONLY = 0O_RDONLY;
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_sampling_symbolize.ioctl = int core.sys.posix.sys.ioctl.ioctl(int __fd, ulong __request, ...) nothrow @nogcioctl;
import (package) corecore.(package) core.syssys.(package) core.sys.posixposix.(package) core.sys.posix.syssys.(module) core.sys.posix.sys.mmanD header file for POSIX.
mman : (alias) cpu_pmu_sampling_symbolize.mmap = void* core.sys.posix.sys.mman.mmap64(void*, ulong, int, int, int, long) nothrow @nogcmmap, (alias) cpu_pmu_sampling_symbolize.munmap = int core.sys.posix.sys.mman.munmap(void*, ulong) nothrow @nogcmunmap, (alias constant) cpu_pmu_sampling_symbolize.PROT_READ = int core.sys.posix.sys.mman.PROT_READ = 1PROT_READ, (alias constant) cpu_pmu_sampling_symbolize.PROT_WRITE = int core.sys.posix.sys.mman.PROT_WRITE = 2PROT_WRITE, (alias constant) cpu_pmu_sampling_symbolize.PROT_EXEC = int core.sys.posix.sys.mman.PROT_EXEC = 4PROT_EXEC,
(alias constant) cpu_pmu_sampling_symbolize.MAP_SHARED = int core.sys.posix.sys.mman.MAP_SHARED = 1MAP_SHARED, (alias constant) cpu_pmu_sampling_symbolize.MAP_PRIVATE = int core.sys.posix.sys.mman.MAP_PRIVATE = 2MAP_PRIVATE, (alias constant) cpu_pmu_sampling_symbolize.MAP_FAILED = void* core.sys.posix.sys.mman.MAP_FAILED = cast(void*)cast(size_t)18446744073709551615LUMAP_FAILED;
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_sampling_symbolize.memcpy = void* core.stdc.string.memcpy(return scope void* s1, scope const(void*) s2, ulong n) pure nothrow @nogcmemcpy, (alias) cpu_pmu_sampling_symbolize.strlen = ulong core.stdc.string.strlen(scope const(char*) s) pure nothrow @nogcstrlen;
import (package) corecore.(module) core.atomicThe atomic module provides basic support for lock-free
concurrent programming.
Use the -preview=nosharedaccess compiler flag to detect
unsafe individual read or write operations on shared data.
Source
core/atomic.d
Examples
int y = 2;
shared int x = y; // OK
//x++; // read modify write error
x.atomicOp!"+="(1); // OK
//y = x; // read error with preview flag
y = x.atomicLoad(); // OK
assert(y == 3);
//x = 5; // write error with preview flag
x.atomicStore(5); // OK
assert(x.atomicLoad() == 5);
atomic : (alias template) cpu_pmu_sampling_symbolize.atomicLoad = core.atomic.atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(auto ref return scope const T val) if (!is(T == shared(U), U) && !is(T == shared(inout(U)), U) && !is(T == shared(const(U)), U))Loads 'val' from memory and returns it. The memory barrier specified
by 'ms' is applied to the operation, which is fully sequenced by
default. Valid memory orders are MemoryOrder.raw, MemoryOrder.acq,
and MemoryOrder.seq.
atomicLoad, (alias template) cpu_pmu_sampling_symbolize.atomicStore = core.atomic.atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref T val, V newval) if (!is(T == shared) && !is(V == shared))Writes 'newval' into 'val'. The memory barrier specified by 'ms' is
applied to the operation, which is fully sequenced by default.
Valid memory orders are MemoryOrder.raw, MemoryOrder.rel, and
MemoryOrder.seq.
atomicStore, (enum) core.atomic.MemoryOrderSpecifies the memory ordering semantics of an atomic operation.
MemoryOrder;
import (package) corecore.(module) core.timeModule containing core time functionality, such as Duration (which
represents a duration of time) or MonoTime (which represents a
timestamp of the system's monotonic clock).
Various functions take a string (or strings) to represent a unit of time
(e.g. convert!("days", "hours")(numDays)). The valid strings to use
with such functions are "years", "months", "weeks", "days", "hours",
"minutes", "seconds", "msecs" (milliseconds), "usecs" (microseconds),
"hnsecs" (hecto-nanoseconds - i.e. 100 ns) or some subset thereof. There
are a few functions that also allow "nsecs", but very little actually
has precision greater than hnsecs.
Symbol Description Types Duration Represents a duration of time of weeks or less (kept internally as hnsecs). (e.g. 22 days or 700 seconds). TickDuration DEPRECATED Represents a duration of time in system clock ticks, using the highest precision that the system provides. MonoTime Represents a monotonic timestamp in system clock ticks, using the highest precision that the system provides. Functions convert Generic way of converting between two time units. dur Allows constructing a Duration from the given time units with the given length. weeks days hours
minutes seconds msecs
usecs hnsecs nsecs |
Convenience aliases for dur. |
| abs | Returns the absolute value of a duration. |
From Duration
From TickDuration
From units
To Duration tickDuration.to, std,conv!Duration() dur!"msecs"(5) or 5.msecs()
| To TickDuration |
duration.to, std,conv!TickDuration() |
|
TickDuration.from!"msecs"(msecs) |
| To units |
duration.total!"days" |
tickDuration.msecs |
convert!("days", "msecs")(msecs) |
Source
core/time.d
time : (struct) core.time.MonoTimeImpl!(ClockType.normal)MonoTime, msecs;
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_sampling_symbolize.writefln = std.stdio.writefln(alias fmt, A...)(A args) if (isSomeString!(typeof(fmt)))Equivalent to writef(fmt, args, '\n').
writefln, (alias template) cpu_pmu_sampling_symbolize.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_sampling_symbolize.fromStringz = std.string.fromStringz(Char)(return scope inout(Char)* cString) if (isSomeChar!Char)fromStringz;
// ---- elfutils libdwfl: extern(C) prototypes declared in-file --------
// (a single-file dub program cannot compile a C shim; we link -ldw -lelf).
alias (alias) cpu_pmu_sampling_symbolize.Dwarf_Addr = ulongDwarf_Addr = ulong;
alias (alias) cpu_pmu_sampling_symbolize.Dwarf_Word = ulongDwarf_Word = ulong;
alias (alias) cpu_pmu_sampling_symbolize.GElf_Addr = ulongGElf_Addr = ulong;
alias (alias) cpu_pmu_sampling_symbolize.GElf_Off = ulongGElf_Off = ulong;
alias (alias) cpu_pmu_sampling_symbolize.GElf_Word = uintGElf_Word = uint;
/// `Elf64_Sym` (== `GElf_Sym` on LP64) — dwfl fills this; we read `st_value`.
struct (struct) cpu_pmu_sampling_symbolize.GElf_SymElf64_Sym (== GElf_Sym on LP64) — dwfl fills this; we read st_value.
GElf_Sym
{
uint (field) uint cpu_pmu_sampling_symbolize.GElf_Sym.st_namest_name;
ubyte (field) ubyte cpu_pmu_sampling_symbolize.GElf_Sym.st_infost_info;
ubyte (field) ubyte cpu_pmu_sampling_symbolize.GElf_Sym.st_otherst_other;
ushort (field) ushort cpu_pmu_sampling_symbolize.GElf_Sym.st_shndxst_shndx;
ulong (field) ulong cpu_pmu_sampling_symbolize.GElf_Sym.st_valuest_value;
ulong (field) ulong cpu_pmu_sampling_symbolize.GElf_Sym.st_sizest_size;
}
struct (struct) cpu_pmu_sampling_symbolize.DwflDwfl; // opaque
struct (struct) cpu_pmu_sampling_symbolize.Dwfl_ModuleDwfl_Module; // opaque
struct (struct) cpu_pmu_sampling_symbolize.Dwfl_LineDwfl_Line; // opaque
struct (struct) cpu_pmu_sampling_symbolize.ElfElf; // opaque
/// `Dwfl_Callbacks` (elfutils@6f8f78c libdwfl/libdwfl.h:72) as four pointers:
/// `find_elf`, `find_debuginfo`, `section_address`, `debuginfo_path`.
struct (struct) cpu_pmu_sampling_symbolize.DwflCallbacksDwfl_Callbacks (elfutils@6f8f78c libdwfl/libdwfl.h:72) as four pointers:
find_elf, find_debuginfo, section_address, debuginfo_path.
DwflCallbacks
{
void* (field) void* cpu_pmu_sampling_symbolize.DwflCallbacks.find_elffind_elf;
void* (field) void* cpu_pmu_sampling_symbolize.DwflCallbacks.find_debuginfofind_debuginfo;
void* (field) void* cpu_pmu_sampling_symbolize.DwflCallbacks.section_addresssection_address;
char** (field) char** cpu_pmu_sampling_symbolize.DwflCallbacks.debuginfo_pathdebuginfo_path;
}
extern (C) @nogc nothrow
{
(struct) cpu_pmu_sampling_symbolize.DwflDwfl* cpu_pmu_sampling_symbolize.Dwfl* cpu_pmu_sampling_symbolize.dwfl_begin(const(cpu_pmu_sampling_symbolize.DwflCallbacks)*) nothrow @nogcdwfl_begin(const((struct) cpu_pmu_sampling_symbolize.DwflCallbacksDwfl_Callbacks (elfutils@6f8f78c libdwfl/libdwfl.h:72) as four pointers:
find_elf, find_debuginfo, section_address, debuginfo_path.
DwflCallbacks)*);
void void cpu_pmu_sampling_symbolize.dwfl_end(cpu_pmu_sampling_symbolize.Dwfl*) nothrow @nogcdwfl_end((struct) cpu_pmu_sampling_symbolize.DwflDwfl*);
int int cpu_pmu_sampling_symbolize.dwfl_linux_proc_report(cpu_pmu_sampling_symbolize.Dwfl*, int pid) nothrow @nogcdwfl_linux_proc_report((struct) cpu_pmu_sampling_symbolize.DwflDwfl*, int (parameter) int pidpid);
int int cpu_pmu_sampling_symbolize.dwfl_report_end(cpu_pmu_sampling_symbolize.Dwfl*, void* removed, void* arg) nothrow @nogcdwfl_report_end((struct) cpu_pmu_sampling_symbolize.DwflDwfl*, void* (parameter) void* removedremoved, void* (parameter) void* argarg);
(struct) cpu_pmu_sampling_symbolize.Dwfl_ModuleDwfl_Module* cpu_pmu_sampling_symbolize.Dwfl_Module* cpu_pmu_sampling_symbolize.dwfl_addrmodule(cpu_pmu_sampling_symbolize.Dwfl*, ulong) nothrow @nogcdwfl_addrmodule((struct) cpu_pmu_sampling_symbolize.DwflDwfl*, (alias) cpu_pmu_sampling_symbolize.Dwarf_Addr = ulongDwarf_Addr);
const(char)* const(char)* cpu_pmu_sampling_symbolize.dwfl_module_addrinfo(cpu_pmu_sampling_symbolize.Dwfl_Module*, ulong, ulong*, cpu_pmu_sampling_symbolize.GElf_Sym*, uint*, cpu_pmu_sampling_symbolize.Elf**, ulong*) nothrow @nogcdwfl_module_addrinfo((struct) cpu_pmu_sampling_symbolize.Dwfl_ModuleDwfl_Module*, (alias) cpu_pmu_sampling_symbolize.GElf_Addr = ulongGElf_Addr, (alias) cpu_pmu_sampling_symbolize.GElf_Off = ulongGElf_Off*,
(struct) cpu_pmu_sampling_symbolize.GElf_SymElf64_Sym (== GElf_Sym on LP64) — dwfl fills this; we read st_value.
GElf_Sym*, (alias) cpu_pmu_sampling_symbolize.GElf_Word = uintGElf_Word*, (struct) cpu_pmu_sampling_symbolize.ElfElf**, (alias) cpu_pmu_sampling_symbolize.Dwarf_Addr = ulongDwarf_Addr*);
(struct) cpu_pmu_sampling_symbolize.Dwfl_LineDwfl_Line* cpu_pmu_sampling_symbolize.Dwfl_Line* cpu_pmu_sampling_symbolize.dwfl_module_getsrc(cpu_pmu_sampling_symbolize.Dwfl_Module*, ulong) nothrow @nogcdwfl_module_getsrc((struct) cpu_pmu_sampling_symbolize.Dwfl_ModuleDwfl_Module*, (alias) cpu_pmu_sampling_symbolize.Dwarf_Addr = ulongDwarf_Addr);
const(char)* const(char)* cpu_pmu_sampling_symbolize.dwfl_lineinfo(cpu_pmu_sampling_symbolize.Dwfl_Line*, ulong*, int*, int*, ulong*, ulong*) nothrow @nogcdwfl_lineinfo((struct) cpu_pmu_sampling_symbolize.Dwfl_LineDwfl_Line*, (alias) cpu_pmu_sampling_symbolize.Dwarf_Addr = ulongDwarf_Addr*, int*, int*, (alias) cpu_pmu_sampling_symbolize.Dwarf_Word = ulongDwarf_Word*, (alias) cpu_pmu_sampling_symbolize.Dwarf_Word = ulongDwarf_Word*);
// The two standard callbacks we take the address of for DwflCallbacks:
int int cpu_pmu_sampling_symbolize.dwfl_linux_proc_find_elf() nothrow @nogcdwfl_linux_proc_find_elf();
int int cpu_pmu_sampling_symbolize.dwfl_standard_find_debuginfo() nothrow @nogcdwfl_standard_find_debuginfo();
}
// ---- captured records -----------------------------------------------
struct (struct) cpu_pmu_sampling_symbolize.MappingMapping
{
ulong (field) ulong cpu_pmu_sampling_symbolize.Mapping.addraddr, (field) ulong cpu_pmu_sampling_symbolize.Mapping.lenlen, (field) ulong cpu_pmu_sampling_symbolize.Mapping.pgoffpgoff;
uint (field) uint cpu_pmu_sampling_symbolize.Mapping.protprot;
(alias) object.string = stringstring (field) string cpu_pmu_sampling_symbolize.Mapping.filenamefilename;
}
__gshared ulong (__gshared global) ulong cpu_pmu_sampling_symbolize.sinksink;
/// Two deliberately non-inlined hot functions, so sampled IPs land in
/// named symbols we can point at.
pragma(inline, false) ulong ulong cpu_pmu_sampling_symbolize.mixHash(ulong x)Two deliberately non-inlined hot functions, so sampled IPs land in
named symbols we can point at.
mixHash(ulong (parameter) ulong xx)
{
foreach ((local variable) int __; 0 .. 96)
(parameter) ulong xx = ((parameter) ulong xx * 6364136223846793005UL + 1442695040888963407UL) ^ ((parameter) ulong xx >> 29);
return (parameter) ulong xx;
}
pragma(inline, false) ulong ulong cpu_pmu_sampling_symbolize.sumSquares(ulong n)sumSquares(ulong (parameter) ulong nn)
{
ulong (local variable) ulong ss = 0;
foreach ((local variable) ulong ii; 0 .. (parameter) ulong nn)
(local variable) ulong ss += (local variable) ulong ii * (local variable) ulong ii;
return (local variable) ulong ss;
}
void void cpu_pmu_sampling_symbolize.workload()workload()
{
auto (local variable) core.time.MonoTimeImpl!(ClockType.normal) deadlinedeadline = (struct) core.time.MonoTimeImpl!(ClockType.normal)MonoTime.core.time.MonoTimeImpl!(ClockType.normal) core.time.MonoTimeImpl!(ClockType.normal).currTime() nothrow @nogc @property @trustedThe current time of the system's monotonic clock. This has no relation
to the wall clock time, as the wall clock time can be adjusted (e.g.
by NTP), whereas the monotonic clock always moves forward. The source
of the monotonic time is system-specific.
On Windows, QueryPerformanceCounter is used. On Mac OS X,
mach_absolute_time is used, while on other POSIX systems,
clock_gettime is used.
Warning: On some systems, the monotonic clock may stop counting
when the computer goes to sleep or hibernates. So, the
monotonic clock may indicate less time than has actually
passed if that occurs. This is known to happen on
Mac OS X. It has not been tested whether it occurs on
either Windows or Linux.
currTime + 500.msecs;
ulong (local variable) ulong accacc = 0x1234_5678_9ABC_DEF0UL;
while ((struct) core.time.MonoTimeImpl!(ClockType.normal)MonoTime.core.time.MonoTimeImpl!(ClockType.normal) core.time.MonoTimeImpl!(ClockType.normal).currTime() nothrow @nogc @property @trustedThe current time of the system's monotonic clock. This has no relation
to the wall clock time, as the wall clock time can be adjusted (e.g.
by NTP), whereas the monotonic clock always moves forward. The source
of the monotonic time is system-specific.
On Windows, QueryPerformanceCounter is used. On Mac OS X,
mach_absolute_time is used, while on other POSIX systems,
clock_gettime is used.
Warning: On some systems, the monotonic clock may stop counting
when the computer goes to sleep or hibernates. So, the
monotonic clock may indicate less time than has actually
passed if that occurs. This is known to happen on
Mac OS X. It has not been tested whether it occurs on
either Windows or Linux.
currTime < (local variable) core.time.MonoTimeImpl!(ClockType.normal) deadlinedeadline)
{
(local variable) ulong accacc += ulong cpu_pmu_sampling_symbolize.mixHash(ulong x)Two deliberately non-inlined hot functions, so sampled IPs land in
named symbols we can point at.
mixHash((local variable) ulong accacc);
(local variable) ulong accacc += ulong cpu_pmu_sampling_symbolize.sumSquares(ulong n)sumSquares(2048);
}
(__gshared global) ulong cpu_pmu_sampling_symbolize.sinksink += (local variable) ulong accacc;
}
int int cpu_pmu_sampling_symbolize.run()run()
{
const (local variable) const(ulong) pageSizepageSize = cast((alias) object.size_t = ulongsize_t) long core.sys.posix.unistd.sysconf(int) nothrow @nogc @trustedsysconf((enum value) core.sys.posix.unistd._SC_PAGESIZE = 30_SC_PAGESIZE);
enum (constant) int cpu_pmu_sampling_symbolize.run.dataPages = 256dataPages = 256; // power of two
const (local variable) const(ulong) dataSizedataSize = (constant) int cpu_pmu_sampling_symbolize.run.dataPages = 256dataPages * (local variable) const(ulong) pageSizepageSize;
const (local variable) const(ulong) mmapSizemmapSize = (1 + (constant) int cpu_pmu_sampling_symbolize.run.dataPages = 256dataPages) * (local variable) const(ulong) pageSizepageSize;
// Sampling event: cycles at ~4 kHz, user-space only so every IP is
// symbolizable against the process image. IP+TID+TIME per sample; the
// kernel also emits MMAP2 for executable mappings (attr.mmap2 = 1).
(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 (local variable) core.sys.linux.perf_event.perf_event_attr attrattr;
(local variable) core.sys.linux.perf_event.perf_event_attr 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;
(local variable) core.sys.linux.perf_event.perf_event_attr attrattr.(field) uint core.sys.linux.perf_event.perf_event_attr.typeMajor type: hardware/software/tracepoint/etc.
type = (enum) core.sys.linux.perf_event.perf_type_idattr.type
perf_type_id.(enum value) core.sys.linux.perf_event.perf_type_id.PERF_TYPE_HARDWARE = 0PERF_TYPE_HARDWARE;
(local variable) core.sys.linux.perf_event.perf_event_attr attrattr.(field) ulong core.sys.linux.perf_event.perf_event_attr.configType specific configuration information.
config = (enum) core.sys.linux.perf_event.perf_hw_idGeneralized performance event event_id types, used by the
attr.event_id parameter of the sys_perf_event_open()
syscall:
perf_hw_id.(enum value) core.sys.linux.perf_event.perf_hw_id.PERF_COUNT_HW_CPU_CYCLES = 0PERF_COUNT_HW_CPU_CYCLES;
(local variable) core.sys.linux.perf_event.perf_event_attr attrattr.(field) ulong core.sys.linux.perf_event.perf_event_attr.sample_typesample_type = (enum) core.sys.linux.perf_event.perf_event_sample_formatBits that can be set in attr.sample_type to request information
in the overflow packets.
perf_event_sample_format.(enum value) core.sys.linux.perf_event.perf_event_sample_format.PERF_SAMPLE_IP = 1uPERF_SAMPLE_IP
| (enum) core.sys.linux.perf_event.perf_event_sample_formatBits that can be set in attr.sample_type to request information
in the overflow packets.
perf_event_sample_format.(enum value) core.sys.linux.perf_event.perf_event_sample_format.PERF_SAMPLE_TID = 2uPERF_SAMPLE_TID
| (enum) core.sys.linux.perf_event.perf_event_sample_formatBits that can be set in attr.sample_type to request information
in the overflow packets.
perf_event_sample_format.(enum value) core.sys.linux.perf_event.perf_event_sample_format.PERF_SAMPLE_TIME = 4uPERF_SAMPLE_TIME;
(local variable) core.sys.linux.perf_event.perf_event_attr attrattr.void core.sys.linux.perf_event.perf_event_attr.freq(ulong v) pure nothrow @nogc @property @safefreq = 1;
(local variable) core.sys.linux.perf_event.perf_event_attr attrattr.(field) ulong core.sys.linux.perf_event.perf_event_attr.sample_freqsample_freq = 4000;
(local variable) 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;
(local variable) core.sys.linux.perf_event.perf_event_attr attrattr.void core.sys.linux.perf_event.perf_event_attr.exclude_kernel(ulong v) pure nothrow @nogc @property @safeexclude_kernel = 1;
(local variable) 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;
(local variable) core.sys.linux.perf_event.perf_event_attr attrattr.void core.sys.linux.perf_event.perf_event_attr.mmap(ulong v) pure nothrow @nogc @property @safemmap = 1;
(local variable) core.sys.linux.perf_event.perf_event_attr attrattr.void core.sys.linux.perf_event.perf_event_attr.mmap2(ulong v) pure nothrow @nogc @property @safemmap2 = 1;
int (local variable) int fdfd = (() @trusted => 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(&(local variable) core.sys.linux.perf_event.perf_event_attr attrattr, 0, -1, -1, 0))();
if ((local variable) int fdfd < 0)
{
void std.stdio.writefln!char(in char[] fmt) @safeEquivalent to writef(fmt, args, '\n').
writefln("SKIP: perf_event_open (sampling) failed — perf_event_paranoid, "
~ "seccomp, or no PMU on this host");
return 0;
}
void* (local variable) void* basebase = (() @trusted => void* core.sys.posix.sys.mman.mmap64(void*, ulong, int, int, int, long) nothrow @nogcmmap(null, (local variable) const(ulong) mmapSizemmapSize, (constant) int core.sys.posix.sys.mman.PROT_READ = 1PROT_READ | (constant) int core.sys.posix.sys.mman.PROT_WRITE = 2PROT_WRITE, (constant) int core.sys.posix.sys.mman.MAP_SHARED = 1MAP_SHARED, (local variable) int fdfd, 0))();
if ((local variable) void* basebase is (constant) void* core.sys.posix.sys.mman.MAP_FAILED = cast(void*)cast(size_t)18446744073709551615LUMAP_FAILED)
{
void std.stdio.writefln!char(in char[] fmt) @safeEquivalent to writef(fmt, args, '\n').
writefln("SKIP: mmap of the perf ring buffer failed "
~ "(perf_event_mlock_kb too small?)");
int core.sys.posix.unistd.close(int) nothrow @nogc @trustedclose((local variable) int fdfd);
return 0;
}
auto (local variable) core.sys.linux.perf_event.perf_event_mmap_page* metameta = cast((struct) core.sys.linux.perf_event.perf_event_mmap_pageStructure of the page that can be mapped via mmap
perf_event_mmap_page*) (local variable) void* basebase;
auto (local variable) ubyte* dataAreadataArea = cast(ubyte*) (local variable) void* basebase + (local variable) const(ulong) pageSizepageSize;
// A fresh PROT_EXEC mapping of our own binary, created *inside* the
// enabled window, so the kernel emits a real PERF_RECORD_MMAP2 we can
// capture (pre-existing code is never re-emitted — see the header note).
int (local variable) int exeFdexeFd = (() @trusted => open("/proc/self/exe", (constant) int core.sys.posix.fcntl.O_RDONLY = 0O_RDONLY))();
int core.sys.posix.sys.ioctl.ioctl(int __fd, ulong __request, ...) nothrow @nogcioctl((local variable) int fdfd, cast(c_ulong) (constant) int core.sys.linux.perf_event.PERF_EVENT_IOC_RESET = 9219PERF_EVENT_IOC_RESET, 0);
int core.sys.posix.sys.ioctl.ioctl(int __fd, ulong __request, ...) nothrow @nogcioctl((local variable) int fdfd, cast(c_ulong) (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, 0);
void* (local variable) void* exeMapexeMap = (constant) void* core.sys.posix.sys.mman.MAP_FAILED = cast(void*)cast(size_t)18446744073709551615LUMAP_FAILED;
if ((local variable) int exeFdexeFd >= 0)
(local variable) void* exeMapexeMap = (() @trusted => void* core.sys.posix.sys.mman.mmap64(void*, ulong, int, int, int, long) nothrow @nogcmmap(null, (local variable) const(ulong) pageSizepageSize, (constant) int core.sys.posix.sys.mman.PROT_READ = 1PROT_READ | (constant) int core.sys.posix.sys.mman.PROT_EXEC = 4PROT_EXEC, (constant) int core.sys.posix.sys.mman.MAP_PRIVATE = 2MAP_PRIVATE, (local variable) int exeFdexeFd, 0))();
void cpu_pmu_sampling_symbolize.workload()workload();
if ((local variable) void* exeMapexeMap !is (constant) void* core.sys.posix.sys.mman.MAP_FAILED = cast(void*)cast(size_t)18446744073709551615LUMAP_FAILED)
(() @trusted => int core.sys.posix.sys.mman.munmap(void*, ulong) nothrow @nogcmunmap((local variable) void* exeMapexeMap, (local variable) const(ulong) pageSizepageSize))();
if ((local variable) int exeFdexeFd >= 0)
int core.sys.posix.unistd.close(int) nothrow @nogc @trustedclose((local variable) int exeFdexeFd);
int core.sys.posix.sys.ioctl.ioctl(int __fd, ulong __request, ...) nothrow @nogcioctl((local variable) int fdfd, cast(c_ulong) (constant) int core.sys.linux.perf_event.PERF_EVENT_IOC_DISABLE = 9217PERF_EVENT_IOC_DISABLE, 0);
// ---- drain the ring: data_tail .. data_head, wrapping mod dataSize
// (the reader-side seqcount contract: acquire-load head, process, then
// release-store the new tail).
const (local variable) const(ulong) headhead = ulong core.atomic.atomicLoad!(MemoryOrder.acq, ulong)(ref return scope const(ulong) val) pure nothrow @nogc @trustedLoads 'val' from memory and returns it. The memory barrier specified
by 'ms' is applied to the operation, which is fully sequenced by
default. Valid memory orders are MemoryOrder.raw, MemoryOrder.acq,
and MemoryOrder.seq.
atomicLoad!((enum) core.atomic.MemoryOrderSpecifies the memory ordering semantics of an atomic operation.
MemoryOrder.(enum value) core.atomic.MemoryOrder.acq = 2Hoist-load + hoist-store barrier.
Corresponds to LLVM AtomicOrdering.Acquire
and C++11/C11 memory_order_acquire.
acq)((local variable) core.sys.linux.perf_event.perf_event_mmap_page* metameta.(field) ulong core.sys.linux.perf_event.perf_event_mmap_page.data_headControl data for the mmap() data buffer.
User-space reading the @data_head value should issue an smp_rmb(),
after reading this value.
When the mapping is PROT_WRITE the @data_tail value should be
written by userspace to reflect the last read data, after issueing
an smp_mb() to separate the data read from the ->data_tail store.
In this case the kernel will not over-write unread data.
See perf_output_put_handle() for the data ordering.
data_{offset,size} indicate the location and size of the perf record
buffer within the mmapped area.
head in the data section
data_head);
ulong (local variable) ulong tailtail = (local variable) core.sys.linux.perf_event.perf_event_mmap_page* metameta.(field) ulong core.sys.linux.perf_event.perf_event_mmap_page.data_tailuser-space written tail
data_tail;
(struct) cpu_pmu_sampling_symbolize.MappingMapping[] (local variable) cpu_pmu_sampling_symbolize.Mapping[] mapsmaps;
ulong[] (local variable) ulong[] ipsips;
ulong (local variable) ulong lostlost = 0;
ubyte[8192] (local variable) ubyte[8192] recrec;
void void cpu_pmu_sampling_symbolize.run.ringCopy(ulong pos, ubyte* dst, ulong n) pure nothrow @nogc @trustedringCopy(ulong (parameter) ulong pospos, ubyte* (parameter) ubyte* dstdst, (alias) object.size_t = ulongsize_t (parameter) ulong nn) @trusted
{
const (local variable) const(ulong) oo = (parameter) ulong pospos % (local variable) const(ulong) dataSizedataSize;
if ((local variable) const(ulong) oo + (parameter) ulong nn <= (local variable) const(ulong) dataSizedataSize)
void* core.stdc.string.memcpy(return scope void* s1, scope const(void*) s2, ulong n) pure nothrow @nogcmemcpy((parameter) ubyte* dstdst, (local variable) ubyte* dataAreadataArea + (local variable) const(ulong) oo, (parameter) ulong nn);
else
{
const (local variable) const(ulong) firstfirst = cast((alias) object.size_t = ulongsize_t)((local variable) const(ulong) dataSizedataSize - (local variable) const(ulong) oo);
void* core.stdc.string.memcpy(return scope void* s1, scope const(void*) s2, ulong n) pure nothrow @nogcmemcpy((parameter) ubyte* dstdst, (local variable) ubyte* dataAreadataArea + (local variable) const(ulong) oo, (local variable) const(ulong) firstfirst);
void* core.stdc.string.memcpy(return scope void* s1, scope const(void*) s2, ulong n) pure nothrow @nogcmemcpy((parameter) ubyte* dstdst + (local variable) const(ulong) firstfirst, (local variable) ubyte* dataAreadataArea, (parameter) ulong nn - (local variable) const(ulong) firstfirst);
}
}
while ((local variable) ulong tailtail < (local variable) const(ulong) headhead)
{
(struct) core.sys.linux.perf_event.perf_event_headerperf_event_header (local variable) core.sys.linux.perf_event.perf_event_header hh;
void cpu_pmu_sampling_symbolize.run.ringCopy(ulong pos, ubyte* dst, ulong n) pure nothrow @nogc @trustedringCopy((local variable) ulong tailtail, cast(ubyte*)&(local variable) core.sys.linux.perf_event.perf_event_header hh, (local variable) core.sys.linux.perf_event.perf_event_header hh.(constant) ulong core.sys.linux.perf_event.perf_event_header.sizeof = 8LUsizeof);
if ((local variable) core.sys.linux.perf_event.perf_event_header hh.(field) ushort core.sys.linux.perf_event.perf_event_header.sizesize == 0)
break;
(alias) object.size_t = ulongsize_t (local variable) ulong szsz = (local variable) core.sys.linux.perf_event.perf_event_header hh.(field) ushort core.sys.linux.perf_event.perf_event_header.sizesize;
if ((local variable) ulong szsz > (local variable) ubyte[8192] recrec.(constant) ulong ubyte[8192].length = 8192LUlength)
(local variable) ulong szsz = (local variable) ubyte[8192] recrec.(constant) ulong ubyte[8192].length = 8192LUlength;
void cpu_pmu_sampling_symbolize.run.ringCopy(ulong pos, ubyte* dst, ulong n) pure nothrow @nogc @trustedringCopy((local variable) ulong tailtail, (local variable) ubyte[8192] recrec.(constant) ubyte* ubyte[8192].ptr = &recptr, (local variable) ulong szsz);
(local variable) ulong tailtail += (local variable) core.sys.linux.perf_event.perf_event_header hh.(field) ushort core.sys.linux.perf_event.perf_event_header.sizesize;
if ((local variable) core.sys.linux.perf_event.perf_event_header hh.(field) uint core.sys.linux.perf_event.perf_event_header.typetype == (enum) core.sys.linux.perf_event.perf_event_typeperf_event_type.(enum value) core.sys.linux.perf_event.perf_event_type.PERF_RECORD_SAMPLE = 9struct {
struct perf_event_header header;
#
# Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.
# The advantage of PERF_SAMPLE_IDENTIFIER is that its position
# is fixed relative to header.
#
{ u64 id; } && PERF_SAMPLE_IDENTIFIER
{ u64 ip; } && PERF_SAMPLE_IP
{ u32 pid, tid; } && PERF_SAMPLE_TID
{ u64 time; } && PERF_SAMPLE_TIME
{ u64 addr; } && PERF_SAMPLE_ADDR
{ u64 id; } && PERF_SAMPLE_ID
{ u64 stream_id;} && PERF_SAMPLE_STREAM_ID
{ u32 cpu, res; } && PERF_SAMPLE_CPU
{ u64 period; } && PERF_SAMPLE_PERIOD
{ struct read_format values; } && PERF_SAMPLE_READ
{ u64 nr,
u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN
#
# The RAW record below is opaque data wrt the ABI
#
# That is, the ABI doesn't make any promises wrt to
# the stability of its content, it may vary depending
# on event, hardware, kernel version and phase of
# the moon.
#
# In other words, PERF_SAMPLE_RAW contents are not an ABI.
#
{ u32 size;
char data[size];}&& PERF_SAMPLE_RAW
{ u64 nr;
{ u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
{ u64 abi; # enum perf_sample_regs_abi
u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
{ u64 size;
char data[size];
u64 dyn_size; } && PERF_SAMPLE_STACK_USER
{ u64 weight; } && PERF_SAMPLE_WEIGHT
{ u64 data_src; } && PERF_SAMPLE_DATA_SRC
{ u64 transaction; } && PERF_SAMPLE_TRANSACTION
{ u64 abi; # enum perf_sample_regs_abi
u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_INTR
{ u64 phys_addr;} && PERF_SAMPLE_PHYS_ADDR
};
PERF_RECORD_SAMPLE)
{
// body: ip(u64), pid(u32), tid(u32), time(u64)
(local variable) ulong[] ipsips ~= *(() @trusted => cast(ulong*)((local variable) ubyte[8192] recrec.(constant) ubyte* ubyte[8192].ptr = &recptr + 8))();
}
else if ((local variable) core.sys.linux.perf_event.perf_event_header hh.(field) uint core.sys.linux.perf_event.perf_event_header.typetype == (enum) core.sys.linux.perf_event.perf_event_typeperf_event_type.(enum value) core.sys.linux.perf_event.perf_event_type.PERF_RECORD_MMAP2 = 10The MMAP2 records are an augmented version of MMAP, they add
maj, min, ino numbers to be used to uniquely identify each mapping
struct {
struct perf_event_header header;
u32 pid, tid;
u64 addr;
u64 len;
u64 pgoff;
u32 maj;
u32 min;
u64 ino;
u64 ino_generation;
u32 prot, flags;
char filename[];
struct sample_id sample_id;
};
PERF_RECORD_MMAP2)
{
// body offsets (after 8-byte header): addr@16 len@24 pgoff@32
// maj@40 min@44 ino@48 ino_gen@56 prot@64 flags@68 filename@72
(struct) cpu_pmu_sampling_symbolize.MappingMapping (local variable) cpu_pmu_sampling_symbolize.Mapping mm;
(() @trusted {
(local variable) cpu_pmu_sampling_symbolize.Mapping mm.(field) ulong cpu_pmu_sampling_symbolize.Mapping.addraddr = *cast(ulong*)((local variable) ubyte[8192] recrec.(constant) ubyte* ubyte[8192].ptr = &recptr + 16);
(local variable) cpu_pmu_sampling_symbolize.Mapping mm.(field) ulong cpu_pmu_sampling_symbolize.Mapping.lenlen = *cast(ulong*)((local variable) ubyte[8192] recrec.(constant) ubyte* ubyte[8192].ptr = &recptr + 24);
(local variable) cpu_pmu_sampling_symbolize.Mapping mm.(field) ulong cpu_pmu_sampling_symbolize.Mapping.pgoffpgoff = *cast(ulong*)((local variable) ubyte[8192] recrec.(constant) ubyte* ubyte[8192].ptr = &recptr + 32);
(local variable) cpu_pmu_sampling_symbolize.Mapping mm.(field) uint cpu_pmu_sampling_symbolize.Mapping.protprot = *cast(uint*)((local variable) ubyte[8192] recrec.(constant) ubyte* ubyte[8192].ptr = &recptr + 64);
auto (local variable) char* fnfn = cast(char*)((local variable) ubyte[8192] recrec.(constant) ubyte* ubyte[8192].ptr = &recptr + 72);
(local variable) cpu_pmu_sampling_symbolize.Mapping mm.(field) string cpu_pmu_sampling_symbolize.Mapping.filenamefilename = inout(char)[] std.string.fromStringz!char(return scope inout(char)* cString) pure nothrow @nogc @systemfromStringz((local variable) char* fnfn).string object.idup!char(char[] a) pure nothrow @property @safeProvide the .idup array property, which creates an immutable duplicate.
idup;
})();
(local variable) cpu_pmu_sampling_symbolize.Mapping[] mapsmaps ~= (local variable) cpu_pmu_sampling_symbolize.Mapping mm;
}
else if ((local variable) core.sys.linux.perf_event.perf_event_header hh.(field) uint core.sys.linux.perf_event.perf_event_header.typetype == (enum) core.sys.linux.perf_event.perf_event_typeperf_event_type.(enum value) core.sys.linux.perf_event.perf_event_type.PERF_RECORD_LOST = 2struct {
struct perf_event_header header;
u64 id;
u64 lost;
struct sample_id sample_id;
};
PERF_RECORD_LOST)
(local variable) ulong lostlost += *(() @trusted => cast(ulong*)((local variable) ubyte[8192] recrec.(constant) ubyte* ubyte[8192].ptr = &recptr + 8 + 8))(); // id(u64), lost(u64)
}
void core.atomic.atomicStore!(MemoryOrder.rel, ulong, const(ulong))(ref ulong val, const(ulong) newval) pure nothrow @nogc @trustedWrites 'newval' into 'val'. The memory barrier specified by 'ms' is
applied to the operation, which is fully sequenced by default.
Valid memory orders are MemoryOrder.raw, MemoryOrder.rel, and
MemoryOrder.seq.
atomicStore!((enum) core.atomic.MemoryOrderSpecifies the memory ordering semantics of an atomic operation.
MemoryOrder.(enum value) core.atomic.MemoryOrder.rel = 3Sink-load + sink-store barrier.
Corresponds to LLVM AtomicOrdering.Release
and C++11/C11 memory_order_release.
rel)((local variable) core.sys.linux.perf_event.perf_event_mmap_page* metameta.(field) ulong core.sys.linux.perf_event.perf_event_mmap_page.data_tailuser-space written tail
data_tail, (local variable) const(ulong) headhead);
(() @trusted => int core.sys.posix.sys.mman.munmap(void*, ulong) nothrow @nogcmunmap((local variable) void* basebase, (local variable) const(ulong) mmapSizemmapSize))();
int core.sys.posix.unistd.close(int) nothrow @nogc @trustedclose((local variable) int fdfd);
void std.stdio.writefln!(char, ulong, ulong, string)(in char[] fmt, ulong __param_1, ulong __param_2, string __param_3) @safeEquivalent to writef(fmt, args, '\n').
writefln("captured: %d PERF_RECORD_MMAP2 mappings, %d IP samples%s",
(local variable) cpu_pmu_sampling_symbolize.Mapping[] mapsmaps.(field) ulong cpu_pmu_sampling_symbolize.Mapping[].lengthlength, (local variable) ulong[] ipsips.(field) ulong ulong[].lengthlength, (local variable) ulong lostlost ? " (" ~ "some LOST — ring overflow" ~ ")" : "");
if ((local variable) ulong[] ipsips.(field) ulong ulong[].lengthlength == 0)
{
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("note: no samples captured (workload too short, or overflow "
~ "interrupts denied) — nothing to symbolize, but the ring path ran");
return 0;
}
// ---- symbolize via libdwfl: build the module model from the live
// process, then addr -> symbol -> line for each IP ------------
__gshared (struct) cpu_pmu_sampling_symbolize.DwflCallbacksDwfl_Callbacks (elfutils@6f8f78c libdwfl/libdwfl.h:72) as four pointers:
find_elf, find_debuginfo, section_address, debuginfo_path.
DwflCallbacks (__gshared global) cpu_pmu_sampling_symbolize.DwflCallbacks cpu_pmu_sampling_symbolize.run.cbcb;
(__gshared global) cpu_pmu_sampling_symbolize.DwflCallbacks cpu_pmu_sampling_symbolize.run.cbcb.(field) void* cpu_pmu_sampling_symbolize.DwflCallbacks.find_elffind_elf = (() @trusted => cast(void*)&int cpu_pmu_sampling_symbolize.dwfl_linux_proc_find_elf() nothrow @nogcdwfl_linux_proc_find_elf)();
(__gshared global) cpu_pmu_sampling_symbolize.DwflCallbacks cpu_pmu_sampling_symbolize.run.cbcb.(field) void* cpu_pmu_sampling_symbolize.DwflCallbacks.find_debuginfofind_debuginfo = (() @trusted => cast(void*)&int cpu_pmu_sampling_symbolize.dwfl_standard_find_debuginfo() nothrow @nogcdwfl_standard_find_debuginfo)();
(__gshared global) cpu_pmu_sampling_symbolize.DwflCallbacks cpu_pmu_sampling_symbolize.run.cbcb.(field) void* cpu_pmu_sampling_symbolize.DwflCallbacks.section_addresssection_address = null;
(__gshared global) cpu_pmu_sampling_symbolize.DwflCallbacks cpu_pmu_sampling_symbolize.run.cbcb.(field) char** cpu_pmu_sampling_symbolize.DwflCallbacks.debuginfo_pathdebuginfo_path = null;
(struct) cpu_pmu_sampling_symbolize.DwflDwfl* (local variable) cpu_pmu_sampling_symbolize.Dwfl* dwfldwfl = (() @trusted => cpu_pmu_sampling_symbolize.Dwfl* cpu_pmu_sampling_symbolize.dwfl_begin(const(cpu_pmu_sampling_symbolize.DwflCallbacks)*) nothrow @nogcdwfl_begin(&(__gshared global) cpu_pmu_sampling_symbolize.DwflCallbacks cpu_pmu_sampling_symbolize.run.cbcb))();
bool (local variable) bool symbolizedsymbolized = false;
int[(alias) object.string = stringstring] (local variable) int[string] symCountsymCount;
(alias) object.string = stringstring[(alias) object.string = stringstring] (local variable) string[string] symLinesymLine; // representative file:line per symbol
ulong[(alias) object.string = stringstring] (local variable) ulong[string] symIpsymIp; // representative IP per symbol
if ((local variable) cpu_pmu_sampling_symbolize.Dwfl* dwfldwfl !is null)
{
const (local variable) const(int) rc1rc1 = (() @trusted => int cpu_pmu_sampling_symbolize.dwfl_linux_proc_report(cpu_pmu_sampling_symbolize.Dwfl*, int pid) nothrow @nogcdwfl_linux_proc_report((local variable) cpu_pmu_sampling_symbolize.Dwfl* dwfldwfl, int core.sys.posix.unistd.getpid() nothrow @nogc @trustedgetpid()))();
const (local variable) const(int) rc2rc2 = (() @trusted => int cpu_pmu_sampling_symbolize.dwfl_report_end(cpu_pmu_sampling_symbolize.Dwfl*, void* removed, void* arg) nothrow @nogcdwfl_report_end((local variable) cpu_pmu_sampling_symbolize.Dwfl* dwfldwfl, null, null))();
if ((local variable) const(int) rc1rc1 == 0 && (local variable) const(int) rc2rc2 == 0)
{
(local variable) bool symbolizedsymbolized = true;
foreach ((parameter) ulong ipip; (local variable) ulong[] ipsips)
{
auto (local variable) cpu_pmu_sampling_symbolize.Dwfl_Module* modmod = (() @trusted => cpu_pmu_sampling_symbolize.Dwfl_Module* cpu_pmu_sampling_symbolize.dwfl_addrmodule(cpu_pmu_sampling_symbolize.Dwfl*, ulong) nothrow @nogcdwfl_addrmodule((local variable) cpu_pmu_sampling_symbolize.Dwfl* dwfldwfl, (local variable) ulong ipip))();
if ((local variable) cpu_pmu_sampling_symbolize.Dwfl_Module* modmod is null)
{
int* core.internal.newaa._d_aaGetY!(string, int, int[string], string, int, string)(ref scope int[string] aa, string key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
symCount["<no module>"]++;
continue;
}
(alias) cpu_pmu_sampling_symbolize.GElf_Off = ulongGElf_Off (local variable) ulong offoff;
(struct) cpu_pmu_sampling_symbolize.GElf_SymElf64_Sym (== GElf_Sym on LP64) — dwfl fills this; we read st_value.
GElf_Sym (local variable) cpu_pmu_sampling_symbolize.GElf_Sym symsym;
const (local variable) const(char*) nameznamez = (() @trusted => const(char)* cpu_pmu_sampling_symbolize.dwfl_module_addrinfo(cpu_pmu_sampling_symbolize.Dwfl_Module*, ulong, ulong*, cpu_pmu_sampling_symbolize.GElf_Sym*, uint*, cpu_pmu_sampling_symbolize.Elf**, ulong*) nothrow @nogcdwfl_module_addrinfo(
(local variable) cpu_pmu_sampling_symbolize.Dwfl_Module* modmod, (local variable) ulong ipip, &(local variable) ulong offoff, &(local variable) cpu_pmu_sampling_symbolize.GElf_Sym symsym, null, null, null))();
(alias) object.string = stringstring (local variable) string namename = (local variable) const(char*) nameznamez ? inout(char)[] std.string.fromStringz!char(return scope inout(char)* cString) pure nothrow @nogc @systemfromStringz((local variable) const(char*) nameznamez).string object.idup!(const(char))(const(char)[] a) pure nothrow @property @safeProvide the .idup array property, which creates an immutable duplicate.
idup : "<unknown>";
int* core.internal.newaa._d_aaGetY!(string, int, int[string], string, int, string)(ref scope int[string] aa, ref string key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
symCount[(local variable) string namename]++;
if ((local variable) string namename !in (local variable) ulong[string] symIpsymIp)
ulong* core.internal.newaa._d_aaGetY!(string, ulong, ulong[string], string, ulong, string)(ref scope ulong[string] aa, ref string key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
symIp[ulong* core.internal.newaa._d_aaGetY!(string, ulong, ulong[string], string, ulong, string)(ref scope ulong[string] aa, ref string key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
name] = (local variable) ulong ipip;
if ((local variable) string namename !in (local variable) string[string] symLinesymLine)
{
auto (local variable) cpu_pmu_sampling_symbolize.Dwfl_Line* lineline = (() @trusted => cpu_pmu_sampling_symbolize.Dwfl_Line* cpu_pmu_sampling_symbolize.dwfl_module_getsrc(cpu_pmu_sampling_symbolize.Dwfl_Module*, ulong) nothrow @nogcdwfl_module_getsrc((local variable) cpu_pmu_sampling_symbolize.Dwfl_Module* modmod, (local variable) ulong ipip))();
if ((local variable) cpu_pmu_sampling_symbolize.Dwfl_Line* lineline !is null)
{
int (local variable) int linenolineno;
auto (local variable) const(char)* srczsrcz = (() @trusted => const(char)* cpu_pmu_sampling_symbolize.dwfl_lineinfo(cpu_pmu_sampling_symbolize.Dwfl_Line*, ulong*, int*, int*, ulong*, ulong*) nothrow @nogcdwfl_lineinfo(
(local variable) cpu_pmu_sampling_symbolize.Dwfl_Line* lineline, null, &(local variable) int linenolineno, null, null, null))();
if ((local variable) const(char)* srczsrcz)
{
import (package) stdstd.(module) std.pathThis module is used to manipulate path strings.
All functions, with the exception of expandTilde (and in some
cases absolutePath and relativePath), are pure
string manipulation functions; they don't depend on any state outside
the program, nor do they perform any actual file system actions.
This has the consequence that the module does not make any distinction
between a path that points to a directory and a path that points to a
file, and it does not know whether or not the object pointed to by the
path actually exists in the file system.
To differentiate between these cases, use isDir and
exists.
Note that on Windows, both the backslash (\) and the slash (/)
are in principle valid directory separators. This module treats them
both on equal footing, but in cases where a new separator is
added, a backslash will be used. Furthermore, the buildNormalizedPath
function will replace all slashes with backslashes on that platform.
In general, the functions in this module assume that the input paths
are well-formed. (That is, they should not contain invalid characters,
they should follow the file system's path format, etc.) The result
of calling a function on an ill-formed path is undefined. When there
is a chance that a path or a file name is invalid (for instance, when it
has been input by the user), it may sometimes be desirable to use the
isValidFilename and isValidPath functions to check
this.
Most functions do not perform any memory allocations, and if a string is
returned, it is usually a slice of an input string. If a function
allocates, this is explicitly mentioned in the documentation.
Category Functions Normalization absolutePath asAbsolutePath asNormalizedPath asRelativePath buildNormalizedPath buildPath chainPath expandTilde Partitioning baseName dirName dirSeparator driveName pathSeparator pathSplitter relativePath rootName stripDrive Validation isAbsolute isDirSeparator isRooted isValidFilename isValidPath Extension defaultExtension extension setExtension stripExtension withDefaultExtension withExtension Other filenameCharCmp filenameCmp globMatch CaseSensitive
Source
std/path.d
path : (alias template) baseName = std.path.baseName(R)(return scope R path) if (isRandomAccessRange!R && hasSlicing!R && isSomeChar!(ElementType!R) && !isSomeString!R)Params:
cs = Whether or not suffix matching is case-sensitive.
path = A path name. It can be a string, or any random-access range of
characters.
suffix = An optional suffix to be removed from the file name.
Returns: The name of the file in the path name, without any leading
directory and with an optional suffix chopped off.
If `suffix` is specified, it will be compared to `path`
using `filenameCmp!cs`,
where `cs` is an optional template parameter determining whether
the comparison is case sensitive or not. See the
$(LREF filenameCmp) documentation for details.
Note:
This function $(I only) strips away the specified suffix, which
doesn't necessarily have to represent an extension.
To remove the extension from a path, regardless of what the extension
is, use $(LREF stripExtension).
To obtain the filename without leading directories and without
an extension, combine the functions like this:
---
assert(baseName(stripExtension("dir/file.ext")) == "file");
---
Standards:
This function complies with
$(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/basename.html,
the POSIX requirements for the 'basename' shell utility)
(with suitable adaptations for Windows paths).
baseName;
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;
string* core.internal.newaa._d_aaGetY!(string, string, string[string], string, string, string)(ref scope string[string] aa, ref string key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
symLine[string* core.internal.newaa._d_aaGetY!(string, string, string[string], string, string, string)(ref scope string[string] aa, ref string key, out bool found) pure nothrow @safeLookup key in aa.
Called only from implementation of (aakey) expressions when value is mutable.
name] = string std.path.baseName!(immutable(char))(return scope string path) pure nothrow @nogc @safeNote
This function only strips away the specified suffix, which
doesn't necessarily have to represent an extension.
To remove the extension from a path, regardless of what the extension
is, use stripExtension.
To obtain the filename without leading directories and without
an extension, combine the functions like this:
assert(baseName(stripExtension("dir/file.ext")) == "file");
baseName(inout(char)[] std.string.fromStringz!char(return scope inout(char)* cString) pure nothrow @nogc @systemfromStringz((local variable) const(char)* srczsrcz).string object.idup!(const(char))(const(char)[] a) pure nothrow @property @safeProvide the .idup array property, which creates an immutable duplicate.
idup) ~ ":" ~ (local variable) int linenolineno.string std.conv.to!string.to!int(int __param_0) pure nothrow @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!(alias) object.string = stringstring;
}
}
}
}
}
}
if (!(local variable) bool symbolizedsymbolized)
{
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("note: libdwfl unavailable/failed to report modules — "
~ "capture succeeded; symbolization skipped");
(() @trusted { if ((local variable) cpu_pmu_sampling_symbolize.Dwfl* dwfldwfl) void cpu_pmu_sampling_symbolize.dwfl_end(cpu_pmu_sampling_symbolize.Dwfl*) nothrow @nogcdwfl_end((local variable) cpu_pmu_sampling_symbolize.Dwfl* dwfldwfl); })();
return 0;
}
// Top symbols by sample count.
import (package) stdstd.(module) std.algorithmThis package implements generic algorithms oriented towards the processing of
sequences. Sequences processed by these functions define range-based
interfaces. See also Reference on ranges and
tutorial on ranges.
Algorithms are categorized into the following submodules:
Submodule Functions
| Searching |
all
any
balancedParens
boyerMooreFinder
canFind
commonPrefix
count
countUntil
endsWith
find
findAdjacent
findAmong
findSkip
findSplit
findSplitAfter
findSplitBefore
minCount
maxCount
minElement
maxElement
minIndex
maxIndex
minPos
maxPos
skipOver
startsWith
until
|
| Comparison |
among
castSwitch
clamp
cmp
either
equal
isPermutation
isSameLength
levenshteinDistance
levenshteinDistanceAndPath
max
min
mismatch
predSwitch
|
| Iteration |
cache
cacheBidirectional
chunkBy
cumulativeFold
each
filter
filterBidirectional
fold
group
joiner
map
mean
permutations
reduce
splitWhen
splitter
substitute
sum
uniq
|
| Sorting |
completeSort
isPartitioned
isSorted
isStrictlyMonotonic
ordered
strictlyOrdered
makeIndex
merge
multiSort
nextEvenPermutation
nextPermutation
nthPermutation
partialSort
partition
partition3
schwartzSort
sort
topN
topNCopy
topNIndex
|
| Set operations (setops) |
cartesianProduct
largestPartialIntersection
largestPartialIntersectionWeighted
multiwayMerge
multiwayUnion
setDifference
setIntersection
setSymmetricDifference
|
| Mutation |
bringToFront
copy
fill
initializeAll
move
moveAll
moveSome
moveEmplace
moveEmplaceAll
moveEmplaceSome
remove
reverse
strip
stripLeft
stripRight
swap
swapRanges
uninitializedFill
|
Many functions in this package are parameterized with a predicate.
The predicate may be any suitable callable type
(a function, a delegate, a functor, or a lambda), or a
compile-time string. The string may consist of any legal D
expression that uses the symbol a (for unary functions) or the
symbols a and b (for binary functions). These names will NOT
interfere with other homonym symbols in user code because they are
evaluated in a different context. The default for all binary
comparison predicates is "a == b" for unordered operations and
"a < b" for ordered operations.
Example
int[] a = ...;
static bool greater(int a, int b)
{
return a > b;
}
sort!greater(a); // predicate as alias
sort!((a, b) => a > b)(a); // predicate as a lambda.
sort!"a > b"(a); // predicate as string
// (no ambiguity with array name)
sort(a); // no predicate, "a < b" is implicit
Source
std/algorithm/package.d
algorithm : (alias template) sort = std.algorithm.sorting.sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r)Sorts a random-access range according to the predicate less.
Performs $(BIGOH r.length * log(r.length)) evaluations of `less`. If `less` involves
expensive computations on the _sort key, it may be worthwhile to use
$(LREF schwartzSort) instead.
Stable sorting requires hasAssignableElements!Range to be true.
sort returns a $(REF SortedRange, std,range) over the original range,
allowing functions that can take advantage of sorted data to know that the
range is sorted and adjust accordingly. The $(REF SortedRange, std,range) is a
wrapper around the original range, so both it and the original range are sorted.
Other functions can't know that the original range has been sorted, but
they $(I can) know that $(REF SortedRange, std,range) has been sorted.
Preconditions:
The predicate is expected to satisfy certain rules in order for sort to
behave as expected - otherwise, the program may fail on certain inputs (but not
others) when not compiled in release mode, due to the cursory assumeSorted
check. Specifically, sort expects less(a,b) && less(b,c) to imply
less(a,c) (transitivity), and, conversely, !less(a,b) && !less(b,c) to
imply !less(a,c). Note that the default predicate ("a < b") does not
always satisfy these conditions for floating point types, because the expression
will always be false when either a or b is NaN.
Use $(REF cmp, std,math) instead.
Params:
less = The predicate to sort by.
ss = The swapping strategy to use.
r = The range to sort.
Returns: The initial range wrapped as a SortedRange with the predicate
binaryFun!less.
Algorithms: $(HTTP en.wikipedia.org/wiki/Introsort, Introsort) is used for unstable sorting and
$(HTTP en.wikipedia.org/wiki/Timsort, Timsort) is used for stable sorting.
Each algorithm has benefits beyond stability. Introsort is generally faster but
Timsort may achieve greater speeds on data with low entropy or if predicate calls
are expensive. Introsort performs no allocations whereas Timsort will perform one
or more allocations per call. Both algorithms have $(BIGOH n log n) worst-case
time complexity.
See_Also:
$(REF assumeSorted, std,range)$(BR)
$(REF SortedRange, std,range)$(BR)
$(REF SwapStrategy, std,algorithm,mutation)$(BR)
$(REF binaryFun, std,functional)
sort;
import (package) stdstd.(module) std.arrayFunctions and types that manipulate built-in arrays and associative arrays.
This module provides all kinds of functions to create, manipulate or convert arrays:
Function Name Description
| array |
Returns a copy of the input in a newly allocated dynamic array.
|
| appender |
Returns a new Appender or RefAppender initialized with a given array.
|
| assocArray |
Returns a newly allocated associative array from a range/ranges of keys and values.
|
| byPair |
Construct a range iterating over an associative array by key/value tuples.
|
| insertInPlace |
Inserts into an existing array at a given position.
|
| join |
Concatenates a range of ranges into one array.
|
| minimallyInitializedArray |
Returns a new array of type T.
|
| replace |
Returns a new array with all occurrences of a certain subrange replaced.
|
| replaceFirst |
Returns a new array with the first occurrence of a certain subrange replaced.
|
| replaceInPlace |
Replaces all occurrences of a certain subrange and puts the result into a given array.
|
| replaceInto |
Replaces all occurrences of a certain subrange and puts the result into an output range.
|
| replaceLast |
Returns a new array with the last occurrence of a certain subrange replaced.
|
| replaceSlice |
Returns a new array with a given slice replaced.
|
| replicate |
Creates a new array out of several copies of an input array or range.
|
| sameHead |
Checks if the initial segments of two arrays refer to the same
place in memory.
|
| sameTail |
Checks if the final segments of two arrays refer to the same place
in memory.
|
| split |
Eagerly split a range or string into an array.
|
| staticArray |
Creates a new static array from given data.
|
| uninitializedArray |
Returns a new array of type T without initializing its elements.
|
Source
std/array.d
array : (alias template) array = std.array.array(Range)(Range r) if (isIterable!Range && !isAutodecodableString!Range && !isInfinite!Range)Allocates an array and initializes it with copies of the elements
of range r.
Narrow strings are handled as follows:
If autodecoding is turned on (default), then they are handled as a separate overload.
If autodecoding is turned off, then this is equivalent to duplicating the array.
Params:
r = range (or aggregate with opApply function) whose elements are copied into the allocated array
Returns:
allocated and initialized array
array;
auto (local variable) object.byKeyValue!(int[string], string, int).Result.front.Pair[] rowsrows = (local variable) int[string] symCountsymCount.object.byKeyValue!(int[string], string, int).Result object.byKeyValue!(int[string], string, int)(int[string] aa) pure nothrow @nogc @safeReturns a forward range
which will iterate over the key-value pairs of the associative array. The
returned pairs are represented by an opaque type with .key and .value
properties for accessing references to the key and value of the pair,
respectively.
If structural changes are made to the array (removing or adding keys), all
ranges previously obtained through this function are invalidated. The
following example program will dereference a null pointer:
import std.stdio : writeln;
auto dict = ["k1": 1, "k2": 2];
auto kvRange = dict.byKeyValue;
dict.clear;
writeln(kvRange.front.key, ": ", kvRange.front.value); // Segmentation fault
Note that this is a low-level interface to iterating over the associative
array and is not compatible with the
Tuple type in Phobos.
For compatibility with Tuple, use
std.array.byPair instead.
byKeyValue.object.byKeyValue!(int[string], string, int).Result.front.Pair[] std.array.array!(object.byKeyValue!(int[string], string, int).Result)(object.byKeyValue!(int[string], string, int).Result r) pure nothrow @safeAllocates an array and initializes it with copies of the elements
of range r.
Narrow strings are handled as follows:
If autodecoding is turned on (default), then they are handled as a separate overload.
If autodecoding is turned off, then this is equivalent to duplicating the array.
array;
(local variable) object.byKeyValue!(int[string], string, int).Result.front.Pair[] rowsrows.cpu_pmu_sampling_symbolize.run.SortedRange!(Pair[], __lambda_L359_C20, SortedRangeOptions.assumeSorted) cpu_pmu_sampling_symbolize.run.sort!((a, b) => a.value > b.value, SwapStrategy.unstable, object.byKeyValue!(int[string], string, int).Result.front.Pair[])(object.byKeyValue!(int[string], string, int).Result.front.Pair[] r) pure nothrow @nogc @safeSorts a random-access range according to the predicate less.
Performs O(r.length * log(r.length)) evaluations of less. If less involves
expensive computations on the sort key, it may be worthwhile to use
schwartzSort instead.
Stable sorting requires hasAssignableElements!Range to be true.
sort returns a SortedRange over the original range,
allowing functions that can take advantage of sorted data to know that the
range is sorted and adjust accordingly. The SortedRange is a
wrapper around the original range, so both it and the original range are sorted.
Other functions can't know that the original range has been sorted, but
they can know that SortedRange has been sorted.
Preconditions
The predicate is expected to satisfy certain rules in order for sort to
behave as expected - otherwise, the program may fail on certain inputs (but not
others) when not compiled in release mode, due to the cursory assumeSorted
check. Specifically, sort expects less(a,b) && less(b,c) to imply
less(a,c) (transitivity), and, conversely, !less(a,b) && !less(b,c) to
imply !less(a,c). Note that the default predicate ("a < b") does not
always satisfy these conditions for floating point types, because the expression
will always be false when either a or b is NaN.
Use cmp instead.
Algorithms
Introsort is used for unstable sorting and
Timsort is used for stable sorting.
Each algorithm has benefits beyond stability. Introsort is generally faster but
Timsort may achieve greater speeds on data with low entropy or if predicate calls
are expensive. Introsort performs no allocations whereas Timsort will perform one
or more allocations per call. Both algorithms have O(n log n) worst-case
time complexity.
Examples
int[] array = [ 1, 2, 3, 4 ];
// sort in descending order
array.sort!("a > b");
assert(array == [ 4, 3, 2, 1 ]);
// sort in ascending order
array.sort();
assert(array == [ 1, 2, 3, 4 ]);
// sort with reusable comparator and chain
alias myComp = (x, y) => x > y;
assert(array.sort!(myComp).release == [ 4, 3, 2, 1 ]);
// Showcase stable sorting
import std.algorithm.mutation : SwapStrategy;
string[] words = [ "aBc", "a", "abc", "b", "ABC", "c" ];
sort!("toUpper(a) < toUpper(b)", SwapStrategy.stable)(words);
assert(words == [ "a", "aBc", "abc", "ABC", "b", "c" ]);
// Sorting floating-point numbers in presence of NaN
double[] numbers = [-0.0, 3.0, -2.0, double.nan, 0.0, -double.nan];
import std.algorithm.comparison : equal;
import std.math.operations : cmp;
import std.math.traits : isIdentical;
sort!((a, b) => cmp(a, b) < 0)(numbers);
double[] sorted = [-double.nan, -2.0, -0.0, 0.0, 3.0, double.nan];
assert(numbers.equal!isIdentical(sorted));
sort!((a, b) => a.value > b.value);
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("top self-symbols (dwfl: name — samples — file:line):");
(alias) object.size_t = ulongsize_t (local variable) ulong shownshown = 0;
foreach ((parameter) object.byKeyValue!(int[string], string, int).Result.front.Pair rr; (local variable) object.byKeyValue!(int[string], string, int).Result.front.Pair[] rowsrows)
{
void std.stdio.writefln!(char, string, int, string)(in char[] fmt, string __param_1, int __param_2, string __param_3) @safeEquivalent to writef(fmt, args, '\n').
writefln(" %-28s %6d %s", (local variable) object.byKeyValue!(int[string], string, int).Result.front.Pair rr.string object.byKeyValue!(int[string], string, int).Result.front.Pair.key() inout pure nothrow @nogc @property ref @trustedkey, (local variable) object.byKeyValue!(int[string], string, int).Result.front.Pair rr.int object.byKeyValue!(int[string], string, int).Result.front.Pair.value() inout pure nothrow @nogc @property ref @trustedvalue,
(local variable) object.byKeyValue!(int[string], string, int).Result.front.Pair rr.string object.byKeyValue!(int[string], string, int).Result.front.Pair.key() inout pure nothrow @nogc @property ref @trustedkey in (local variable) string[string] symLinesymLine ? (local variable) string* __aaget843symLine[(local variable) string* __aaget843r.string object.byKeyValue!(int[string], string, int).Result.front.Pair.key() inout pure nothrow @nogc @property ref @trustedkey] : "(no DWARF line info)");
if (++(local variable) ulong shownshown >= 8)
break;
}
// ---- the captured PERF_RECORD_MMAP2 stream -----------------------
import (package) stdstd.(module) std.pathThis module is used to manipulate path strings.
All functions, with the exception of expandTilde (and in some
cases absolutePath and relativePath), are pure
string manipulation functions; they don't depend on any state outside
the program, nor do they perform any actual file system actions.
This has the consequence that the module does not make any distinction
between a path that points to a directory and a path that points to a
file, and it does not know whether or not the object pointed to by the
path actually exists in the file system.
To differentiate between these cases, use isDir and
exists.
Note that on Windows, both the backslash (\) and the slash (/)
are in principle valid directory separators. This module treats them
both on equal footing, but in cases where a new separator is
added, a backslash will be used. Furthermore, the buildNormalizedPath
function will replace all slashes with backslashes on that platform.
In general, the functions in this module assume that the input paths
are well-formed. (That is, they should not contain invalid characters,
they should follow the file system's path format, etc.) The result
of calling a function on an ill-formed path is undefined. When there
is a chance that a path or a file name is invalid (for instance, when it
has been input by the user), it may sometimes be desirable to use the
isValidFilename and isValidPath functions to check
this.
Most functions do not perform any memory allocations, and if a string is
returned, it is usually a slice of an input string. If a function
allocates, this is explicitly mentioned in the documentation.
Category Functions Normalization absolutePath asAbsolutePath asNormalizedPath asRelativePath buildNormalizedPath buildPath chainPath expandTilde Partitioning baseName dirName dirSeparator driveName pathSeparator pathSplitter relativePath rootName stripDrive Validation isAbsolute isDirSeparator isRooted isValidFilename isValidPath Extension defaultExtension extension setExtension stripExtension withDefaultExtension withExtension Other filenameCharCmp filenameCmp globMatch CaseSensitive
Source
std/path.d
path : (alias template) baseName = std.path.baseName(R)(return scope R path) if (isRandomAccessRange!R && hasSlicing!R && isSomeChar!(ElementType!R) && !isSomeString!R)Params:
cs = Whether or not suffix matching is case-sensitive.
path = A path name. It can be a string, or any random-access range of
characters.
suffix = An optional suffix to be removed from the file name.
Returns: The name of the file in the path name, without any leading
directory and with an optional suffix chopped off.
If `suffix` is specified, it will be compared to `path`
using `filenameCmp!cs`,
where `cs` is an optional template parameter determining whether
the comparison is case sensitive or not. See the
$(LREF filenameCmp) documentation for details.
Note:
This function $(I only) strips away the specified suffix, which
doesn't necessarily have to represent an extension.
To remove the extension from a path, regardless of what the extension
is, use $(LREF stripExtension).
To obtain the filename without leading directories and without
an extension, combine the functions like this:
---
assert(baseName(stripExtension("dir/file.ext")) == "file");
---
Standards:
This function complies with
$(LINK2 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/basename.html,
the POSIX requirements for the 'basename' shell utility)
(with suitable adaptations for Windows paths).
baseName;
void std.stdio.writefln!(char, ulong)(in char[] fmt, ulong __param_1) @safeEquivalent to writef(fmt, args, '\n').
writefln("\nPERF_RECORD_MMAP2 captured during the window: %d record(s)", (local variable) cpu_pmu_sampling_symbolize.Mapping[] mapsmaps.(field) ulong cpu_pmu_sampling_symbolize.Mapping[].lengthlength);
foreach (ref (parameter) cpu_pmu_sampling_symbolize.Mapping mm; (local variable) cpu_pmu_sampling_symbolize.Mapping[] mapsmaps)
void std.stdio.writefln!(char, ulong, ulong, ulong, uint, string)(in char[] fmt, ulong __param_1, ulong __param_2, ulong __param_3, uint __param_4, string __param_5) @safeEquivalent to writef(fmt, args, '\n').
writefln(" [0x%x, 0x%x) pgoff=0x%x prot=0x%x %s",
(local variable) cpu_pmu_sampling_symbolize.Mapping mm.(field) ulong cpu_pmu_sampling_symbolize.Mapping.addraddr, (local variable) cpu_pmu_sampling_symbolize.Mapping mm.(field) ulong cpu_pmu_sampling_symbolize.Mapping.addraddr + (local variable) cpu_pmu_sampling_symbolize.Mapping mm.(field) ulong cpu_pmu_sampling_symbolize.Mapping.lenlen, (local variable) cpu_pmu_sampling_symbolize.Mapping mm.(field) ulong cpu_pmu_sampling_symbolize.Mapping.pgoffpgoff, (local variable) cpu_pmu_sampling_symbolize.Mapping mm.(field) uint cpu_pmu_sampling_symbolize.Mapping.protprot, (local variable) cpu_pmu_sampling_symbolize.Mapping mm.(field) string cpu_pmu_sampling_symbolize.Mapping.filenamefilename);
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(" (the kernel re-emits MMAP2 only for mappings made while enabled; "
~ "pre-existing code is recovered from /proc/PID/maps — what dwfl reads.)");
// Tie the two halves together: the deliberate exe mapping's filename is
// the same binary libdwfl symbolized our functions against.
(alias) object.string = stringstring (local variable) string hothot = (local variable) object.byKeyValue!(int[string], string, int).Result.front.Pair[] rowsrows[0].string object.byKeyValue!(int[string], string, int).Result.front.Pair.key() inout pure nothrow @nogc @property ref @trustedkey;
enum (constant) string cpu_pmu_sampling_symbolize.run.exeName = "cpu_pmu_sampling_symbolize"exeName = "cpu_pmu_sampling_symbolize"; // matches dub's `name`
bool (local variable) bool exeSeenexeSeen = false;
foreach (ref (parameter) cpu_pmu_sampling_symbolize.Mapping mm; (local variable) cpu_pmu_sampling_symbolize.Mapping[] mapsmaps)
if ((local variable) cpu_pmu_sampling_symbolize.Mapping mm.(field) string cpu_pmu_sampling_symbolize.Mapping.filenamefilename.string std.path.baseName!(immutable(char))(return scope string path) pure nothrow @nogc @safeNote
This function only strips away the specified suffix, which
doesn't necessarily have to represent an extension.
To remove the extension from a path, regardless of what the extension
is, use stripExtension.
To obtain the filename without leading directories and without
an extension, combine the functions like this:
assert(baseName(stripExtension("dir/file.ext")) == "file");
baseName == (constant) string cpu_pmu_sampling_symbolize.run.exeName = "cpu_pmu_sampling_symbolize"exeName)
{
(local variable) bool exeSeenexeSeen = true;
break;
}
if ((local variable) bool exeSeenexeSeen && (local variable) string hothot in (local variable) ulong[string] symIpsymIp)
void std.stdio.writefln!(char, string, ulong, string)(in char[] fmt, string __param_1, ulong __param_2, string __param_3) @safeEquivalent to writef(fmt, args, '\n').
writefln("model check: hottest symbol %s (IP 0x%x) was symbolized by libdwfl, "
~ "and a captured MMAP2 names the same image (%s).", (local variable) string hothot, (local variable) ulong* __aaget859symIp[(local variable) ulong* __aaget859hot], (constant) string cpu_pmu_sampling_symbolize.run.exeName = "cpu_pmu_sampling_symbolize"exeName);
else if ((local variable) cpu_pmu_sampling_symbolize.Mapping[] mapsmaps.(field) ulong cpu_pmu_sampling_symbolize.Mapping[].lengthlength)
void std.stdio.writefln!(char, string)(in char[] fmt, string __param_1) @safeEquivalent to writef(fmt, args, '\n').
writefln("model check: captured MMAP2 for %s; symbolization via /proc/self/maps.",
(local variable) cpu_pmu_sampling_symbolize.Mapping[] mapsmaps[0].(field) string cpu_pmu_sampling_symbolize.Mapping.filenamefilename.string std.path.baseName!(immutable(char))(return scope string path) pure nothrow @nogc @safeNote
This function only strips away the specified suffix, which
doesn't necessarily have to represent an extension.
To remove the extension from a path, regardless of what the extension
is, use stripExtension.
To obtain the filename without leading directories and without
an extension, combine the functions like this:
assert(baseName(stripExtension("dir/file.ext")) == "file");
baseName);
else
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("model check: no MMAP2 captured this window — symbolization still "
~ "succeeded via /proc/self/maps (the pre-existing-mapping path).");
(() @trusted => void cpu_pmu_sampling_symbolize.dwfl_end(cpu_pmu_sampling_symbolize.Dwfl*) nothrow @nogcdwfl_end((local variable) cpu_pmu_sampling_symbolize.Dwfl* dwfldwfl))();
return 0;
}
}
int int D main()main()
{
version (linuxlinux)
return int cpu_pmu_sampling_symbolize.run()run();
else
{
import std.stdio : writefln;
writefln("SKIP: perf_event sampling is Linux-only");
return 0;
}
}