#!/usr/bin/env dub
/+ dub.sdl:
name "cpu_pmu_unwind_stack_user"
platforms "linux"
libs "dw" "elf"
dflags "-g"
dflags "--frame-pointer=none" platform="ldc"
targetPath "build"
+/
/**
* DWARF-CFI stack unwinding from `PERF_SAMPLE_STACK_USER` + `PERF_SAMPLE_REGS_USER`
* on a frame-pointer-less build — the "call-graph profiler" acquisition path.
*
* Frame-pointer omission (`--frame-pointer=none`; applied under LDC only —
* DMD has no such switch, so a DMD build keeps frame pointers while the CFI
* unwind path stays identical) makes the classic `%rbp`
* chain-walk impossible, so a backtrace must come from DWARF Call Frame
* Information. We arm `cycles` sampling that, on each overflow, additionally
* copies the interrupted thread's **register file** (`REGS_USER`) and a slab of
* its **user stack** (`STACK_USER`) into the ring buffer. Offline, we feed those
* to elfutils `libdwfl`'s frame API — `dwfl_attach_state` with a
* `Dwfl_Thread_Callbacks` whose `memory_read` serves bytes from the captured
* stack slab and whose `set_initial_registers` seeds the captured registers,
* then `dwfl_getthread_frames` drives the CFI unwinder frame by frame
* (`dwfl_frame_pc`) — exactly the wiring `perf`'s `unwind-libdw.c` uses.
*
* The probe has two guaranteed stages: (1) it demonstrably *captures* the
* registers + stack (printing the register ABI, key registers, and stack
* `dyn_size`); (2) it attempts the full in-process CFI unwind and prints the
* recovered backtrace. If the unwind cannot complete in-process it degrades to
* stage 1 and notes that the unwind API path is grounded by source-reading —
* either way it exits 0.
*
* Companion to docs/research/cpu-pmu/linux-perf-events.md
* § "Stack unwinding: `STACK_USER` + `REGS_USER` and DWARF CFI" and
* docs/research/cpu-pmu/elfutils.md § "DWARF-CFI stack unwinding".
*
* Run with: nix shell nixpkgs#elfutils nixpkgs#pkg-config -c dub run --single unwind-stack-user.d
*
* Environment recorded: Linux 6.18.26, AMD Ryzen 9 7940HX (Zen 4, x86-64),
* `/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. The perf→DWARF
* register mapping below is x86-64-specific.
*
* Portability: any missing capability prints a `SKIP:` line and exits 0.
*/
module (module) cpu_pmu_unwind_stack_userDWARF-CFI stack unwinding from PERF_SAMPLE_STACK_USER + PERF_SAMPLE_REGS_USER
on a frame-pointer-less build — the "call-graph profiler" acquisition path.
Frame-pointer omission (--frame-pointer=none; applied under LDC only —
DMD has no such switch, so a DMD build keeps frame pointers while the CFI
unwind path stays identical) makes the classic %rbp
chain-walk impossible, so a backtrace must come from DWARF Call Frame
Information. We arm cycles sampling that, on each overflow, additionally
copies the interrupted thread's register file (REGS_USER) and a slab of
its user stack (STACK_USER) into the ring buffer. Offline, we feed those
to elfutils libdwfl's frame API — dwfl_attach_state with a
Dwfl_Thread_Callbacks whose memory_read serves bytes from the captured
stack slab and whose set_initial_registers seeds the captured registers,
then dwfl_getthread_frames drives the CFI unwinder frame by frame
(dwfl_frame_pc) — exactly the wiring perf's unwind-libdw.c uses.
The probe has two guaranteed stages: (1) it demonstrably captures the
registers + stack (printing the register ABI, key registers, and stack
dyn_size); (2) it attempts the full in-process CFI unwind and prints the
recovered backtrace. If the unwind cannot complete in-process it degrades to
stage 1 and notes that the unwind API path is grounded by source-reading —
either way it exits 0.
Companion to docs/research/cpu-pmu/linux-perf-events.md
§ "Stack unwinding: STACK_USER + REGS_USER and DWARF CFI" and
docs/research/cpu-pmu/elfutils.md § "DWARF-CFI stack unwinding".
Run with: nix shell nixpkgs#elfutils nixpkgs#pkg-config -c dub run --single unwind-stack-user.d
Environment recorded: Linux 6.18.26, AMD Ryzen 9 7940HX (Zen 4, x86-64),
/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. The perf→DWARF
register mapping below is x86-64-specific.
Portability
any missing capability prints a SKIP: line and exits 0.
cpu_pmu_unwind_stack_user;
version (linuxlinux)
{
version (X86_64X86_64) {}
else
version = NotX86_64;
}
version (linuxlinux)
version (X86_64X86_64)
{
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_unwind_stack_user.close = int core.sys.posix.unistd.close(int) nothrow @nogc @trustedclose, (alias) cpu_pmu_unwind_stack_user.getpid = int core.sys.posix.unistd.getpid() nothrow @nogc @trustedgetpid, (alias) cpu_pmu_unwind_stack_user.sysconf = long core.sys.posix.unistd.sysconf(int) nothrow @nogc @trustedsysconf, (alias enum value) cpu_pmu_unwind_stack_user._SC_PAGESIZE = core.sys.posix.unistd._SC_PAGESIZE = 30_SC_PAGESIZE;
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_unwind_stack_user.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 : mmap, (alias) cpu_pmu_unwind_stack_user.munmap = int core.sys.posix.sys.mman.munmap(void*, ulong) nothrow @nogcmunmap, (alias constant) cpu_pmu_unwind_stack_user.PROT_READ = int core.sys.posix.sys.mman.PROT_READ = 1PROT_READ, (alias constant) cpu_pmu_unwind_stack_user.PROT_WRITE = int core.sys.posix.sys.mman.PROT_WRITE = 2PROT_WRITE, (alias constant) cpu_pmu_unwind_stack_user.MAP_SHARED = int core.sys.posix.sys.mman.MAP_SHARED = 1MAP_SHARED, (alias constant) cpu_pmu_unwind_stack_user.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_unwind_stack_user.memcpy = void* core.stdc.string.memcpy(return scope void* s1, scope const(void*) s2, ulong n) pure nothrow @nogcmemcpy;
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_unwind_stack_user.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_unwind_stack_user.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_unwind_stack_user.writefln = std.stdio.writefln(alias fmt, A...)(A args) if (isSomeString!(typeof(fmt)))Equivalent to writef(fmt, args, '\n').
writefln, (alias template) cpu_pmu_unwind_stack_user.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_unwind_stack_user.fromStringz = std.string.fromStringz(Char)(return scope inout(Char)* cString) if (isSomeChar!Char)fromStringz;
// ---- elfutils libdwfl: extern(C) prototypes ------------------------
alias (alias) cpu_pmu_unwind_stack_user.Dwarf_Addr = ulongDwarf_Addr = ulong;
alias (alias) cpu_pmu_unwind_stack_user.Dwarf_Word = ulongDwarf_Word = ulong;
alias (alias) cpu_pmu_unwind_stack_user.GElf_Addr = ulongGElf_Addr = ulong;
alias (alias) cpu_pmu_unwind_stack_user.GElf_Off = ulongGElf_Off = ulong;
alias (alias) cpu_pmu_unwind_stack_user.GElf_Word = uintGElf_Word = uint;
struct (struct) cpu_pmu_unwind_stack_user.GElf_SymGElf_Sym
{
uint (field) uint cpu_pmu_unwind_stack_user.GElf_Sym.st_namest_name;
ubyte (field) ubyte cpu_pmu_unwind_stack_user.GElf_Sym.st_infost_info;
ubyte (field) ubyte cpu_pmu_unwind_stack_user.GElf_Sym.st_otherst_other;
ushort (field) ushort cpu_pmu_unwind_stack_user.GElf_Sym.st_shndxst_shndx;
ulong (field) ulong cpu_pmu_unwind_stack_user.GElf_Sym.st_valuest_value;
ulong (field) ulong cpu_pmu_unwind_stack_user.GElf_Sym.st_sizest_size;
}
struct (struct) cpu_pmu_unwind_stack_user.DwflDwfl;
struct (struct) cpu_pmu_unwind_stack_user.Dwfl_ModuleDwfl_Module;
struct (struct) cpu_pmu_unwind_stack_user.Dwfl_FrameDwfl_Frame;
struct (struct) cpu_pmu_unwind_stack_user.Dwfl_ThreadDwfl_Thread;
struct (struct) cpu_pmu_unwind_stack_user.ElfElf;
/// `Dwfl_Callbacks` (find_elf, find_debuginfo, section_address, debuginfo_path).
struct (struct) cpu_pmu_unwind_stack_user.DwflCallbacksDwfl_Callbacks (find_elf, find_debuginfo, section_address, debuginfo_path).
DwflCallbacks
{
void* (field) void* cpu_pmu_unwind_stack_user.DwflCallbacks.find_elffind_elf;
void* (field) void* cpu_pmu_unwind_stack_user.DwflCallbacks.find_debuginfofind_debuginfo;
void* (field) void* cpu_pmu_unwind_stack_user.DwflCallbacks.section_addresssection_address;
char** (field) char** cpu_pmu_unwind_stack_user.DwflCallbacks.debuginfo_pathdebuginfo_path;
}
/// `Dwfl_Thread_Callbacks` (elfutils@6f8f78c libdwfl/libdwfl.h:661): field
/// order next_thread, get_thread, memory_read, set_initial_registers,
/// detach, thread_detach.
struct (struct) cpu_pmu_unwind_stack_user.DwflThreadCallbacksDwfl_Thread_Callbacks (elfutils@6f8f78c libdwfl/libdwfl.h:661): field
order next_thread, get_thread, memory_read, set_initial_registers,
detach, thread_detach.
DwflThreadCallbacks
{
void* (field) void* cpu_pmu_unwind_stack_user.DwflThreadCallbacks.next_threadnext_thread;
void* (field) void* cpu_pmu_unwind_stack_user.DwflThreadCallbacks.get_threadget_thread;
void* (field) void* cpu_pmu_unwind_stack_user.DwflThreadCallbacks.memory_readmemory_read;
void* (field) void* cpu_pmu_unwind_stack_user.DwflThreadCallbacks.set_initial_registersset_initial_registers;
void* (field) void* cpu_pmu_unwind_stack_user.DwflThreadCallbacks.detachdetach;
void* (field) void* cpu_pmu_unwind_stack_user.DwflThreadCallbacks.thread_detachthread_detach;
}
extern (C) @nogc nothrow
{
(struct) cpu_pmu_unwind_stack_user.DwflDwfl* cpu_pmu_unwind_stack_user.Dwfl* cpu_pmu_unwind_stack_user.dwfl_begin(const(cpu_pmu_unwind_stack_user.DwflCallbacks)*) nothrow @nogcdwfl_begin(const((struct) cpu_pmu_unwind_stack_user.DwflCallbacksDwfl_Callbacks (find_elf, find_debuginfo, section_address, debuginfo_path).
DwflCallbacks)*);
void void cpu_pmu_unwind_stack_user.dwfl_end(cpu_pmu_unwind_stack_user.Dwfl*) nothrow @nogcdwfl_end((struct) cpu_pmu_unwind_stack_user.DwflDwfl*);
int int cpu_pmu_unwind_stack_user.dwfl_linux_proc_report(cpu_pmu_unwind_stack_user.Dwfl*, int pid) nothrow @nogcdwfl_linux_proc_report((struct) cpu_pmu_unwind_stack_user.DwflDwfl*, int (parameter) int pidpid);
int int cpu_pmu_unwind_stack_user.dwfl_report_end(cpu_pmu_unwind_stack_user.Dwfl*, void* removed, void* arg) nothrow @nogcdwfl_report_end((struct) cpu_pmu_unwind_stack_user.DwflDwfl*, void* (parameter) void* removedremoved, void* (parameter) void* argarg);
(struct) cpu_pmu_unwind_stack_user.Dwfl_ModuleDwfl_Module* cpu_pmu_unwind_stack_user.Dwfl_Module* cpu_pmu_unwind_stack_user.dwfl_addrmodule(cpu_pmu_unwind_stack_user.Dwfl*, ulong) nothrow @nogcdwfl_addrmodule((struct) cpu_pmu_unwind_stack_user.DwflDwfl*, (alias) cpu_pmu_unwind_stack_user.Dwarf_Addr = ulongDwarf_Addr);
const(char)* const(char)* cpu_pmu_unwind_stack_user.dwfl_module_addrinfo(cpu_pmu_unwind_stack_user.Dwfl_Module*, ulong, ulong*, cpu_pmu_unwind_stack_user.GElf_Sym*, uint*, cpu_pmu_unwind_stack_user.Elf**, ulong*) nothrow @nogcdwfl_module_addrinfo((struct) cpu_pmu_unwind_stack_user.Dwfl_ModuleDwfl_Module*, (alias) cpu_pmu_unwind_stack_user.GElf_Addr = ulongGElf_Addr, (alias) cpu_pmu_unwind_stack_user.GElf_Off = ulongGElf_Off*,
(struct) cpu_pmu_unwind_stack_user.GElf_SymGElf_Sym*, (alias) cpu_pmu_unwind_stack_user.GElf_Word = uintGElf_Word*, (struct) cpu_pmu_unwind_stack_user.ElfElf**, (alias) cpu_pmu_unwind_stack_user.Dwarf_Addr = ulongDwarf_Addr*);
bool bool cpu_pmu_unwind_stack_user.dwfl_attach_state(cpu_pmu_unwind_stack_user.Dwfl*, cpu_pmu_unwind_stack_user.Elf*, int pid, const(cpu_pmu_unwind_stack_user.DwflThreadCallbacks)*, void* arg) nothrow @nogcdwfl_attach_state((struct) cpu_pmu_unwind_stack_user.DwflDwfl*, (struct) cpu_pmu_unwind_stack_user.ElfElf*, int (parameter) int pidpid, const((struct) cpu_pmu_unwind_stack_user.DwflThreadCallbacksDwfl_Thread_Callbacks (elfutils@6f8f78c libdwfl/libdwfl.h:661): field
order next_thread, get_thread, memory_read, set_initial_registers,
detach, thread_detach.
DwflThreadCallbacks)*, void* (parameter) void* argarg);
int int cpu_pmu_unwind_stack_user.dwfl_getthread_frames(cpu_pmu_unwind_stack_user.Dwfl*, int tid, void* callback, void* arg) nothrow @nogcdwfl_getthread_frames((struct) cpu_pmu_unwind_stack_user.DwflDwfl*, int (parameter) int tidtid, void* (parameter) void* callbackcallback, void* (parameter) void* argarg);
bool bool cpu_pmu_unwind_stack_user.dwfl_frame_pc(cpu_pmu_unwind_stack_user.Dwfl_Frame*, ulong* pc, bool* isactivation) nothrow @nogcdwfl_frame_pc((struct) cpu_pmu_unwind_stack_user.Dwfl_FrameDwfl_Frame*, (alias) cpu_pmu_unwind_stack_user.Dwarf_Addr = ulongDwarf_Addr* (parameter) ulong* pcpc, bool* (parameter) bool* isactivationisactivation);
void void cpu_pmu_unwind_stack_user.dwfl_thread_state_register_pc(cpu_pmu_unwind_stack_user.Dwfl_Thread*, ulong pc) nothrow @nogcdwfl_thread_state_register_pc((struct) cpu_pmu_unwind_stack_user.Dwfl_ThreadDwfl_Thread*, (alias) cpu_pmu_unwind_stack_user.Dwarf_Word = ulongDwarf_Word (parameter) ulong pcpc);
bool bool cpu_pmu_unwind_stack_user.dwfl_thread_state_registers(cpu_pmu_unwind_stack_user.Dwfl_Thread*, int firstreg, uint nregs, const(ulong)* regs) nothrow @nogcdwfl_thread_state_registers((struct) cpu_pmu_unwind_stack_user.Dwfl_ThreadDwfl_Thread*, int (parameter) int firstregfirstreg, uint (parameter) uint nregsnregs, const((alias) cpu_pmu_unwind_stack_user.Dwarf_Word = ulongDwarf_Word)* (parameter) const(ulong)* regsregs);
int int cpu_pmu_unwind_stack_user.dwfl_linux_proc_find_elf() nothrow @nogcdwfl_linux_proc_find_elf();
int int cpu_pmu_unwind_stack_user.dwfl_standard_find_debuginfo() nothrow @nogcdwfl_standard_find_debuginfo();
}
// ---- perf x86-64 register order (arch/x86/include/uapi/asm/perf_regs.h)
// The sample_regs_user mask we set selects, in ascending bit order:
// AX BX CX DX SI DI BP SP IP (bits 0..8), then R8..R15 (bits 16..23).
enum ulong (constant) ulong cpu_pmu_unwind_stack_user.regsMask = 16712191LUregsMask = 0x1FFUL | (0xFFUL << 16); // 17 registers
enum (enum) cpu_pmu_unwind_stack_user.CapIdxCapIdx { (enum value) cpu_pmu_unwind_stack_user.CapIdx.AX = 0AX, (enum value) cpu_pmu_unwind_stack_user.CapIdx.BX = 1BX, (enum value) cpu_pmu_unwind_stack_user.CapIdx.CX = 2CX, (enum value) cpu_pmu_unwind_stack_user.CapIdx.DX = 3DX, (enum value) cpu_pmu_unwind_stack_user.CapIdx.SI = 4SI, (enum value) cpu_pmu_unwind_stack_user.CapIdx.DI = 5DI, (enum value) cpu_pmu_unwind_stack_user.CapIdx.BP = 6BP, (enum value) cpu_pmu_unwind_stack_user.CapIdx.SP = 7SP, (enum value) cpu_pmu_unwind_stack_user.CapIdx.IP = 8IP, (enum value) cpu_pmu_unwind_stack_user.CapIdx.R8 = 9R8, (enum value) cpu_pmu_unwind_stack_user.CapIdx.R9 = 10R9, (enum value) cpu_pmu_unwind_stack_user.CapIdx.R10 = 11R10, (enum value) cpu_pmu_unwind_stack_user.CapIdx.R11 = 12R11, (enum value) cpu_pmu_unwind_stack_user.CapIdx.R12 = 13R12, (enum value) cpu_pmu_unwind_stack_user.CapIdx.R13 = 14R13, (enum value) cpu_pmu_unwind_stack_user.CapIdx.R14 = 15R14, (enum value) cpu_pmu_unwind_stack_user.CapIdx.R15 = 16R15 }
/// One captured sample: leaf IP, the 17 selected registers (perf order), and
/// a copy of the user-stack slab (valid `dyn_size` bytes from `sp` upward).
struct (struct) cpu_pmu_unwind_stack_user.SampleOne captured sample: leaf IP, the 17 selected registers (perf order), and
a copy of the user-stack slab (valid dyn_size bytes from sp upward).
Sample
{
ulong (field) ulong cpu_pmu_unwind_stack_user.Sample.ipip;
int (field) int cpu_pmu_unwind_stack_user.Sample.tidtid;
ulong (field) ulong cpu_pmu_unwind_stack_user.Sample.regsAbiregsAbi;
ulong[17] (field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs;
ubyte[] (field) ubyte[] cpu_pmu_unwind_stack_user.Sample.stackstack;
ulong (field) ulong cpu_pmu_unwind_stack_user.Sample.spsp;
}
// The unwind callbacks are C function pointers; a single-threaded probe can
// route their context through one global.
__gshared (struct) cpu_pmu_unwind_stack_user.SampleOne captured sample: leaf IP, the 17 selected registers (perf order), and
a copy of the user-stack slab (valid dyn_size bytes from sp upward).
Sample* (__gshared global) cpu_pmu_unwind_stack_user.Sample* cpu_pmu_unwind_stack_user.gSamplegSample;
__gshared (alias) cpu_pmu_unwind_stack_user.Dwarf_Addr = ulongDwarf_Addr[64] (__gshared global) ulong[64] cpu_pmu_unwind_stack_user.gFramesgFrames;
__gshared (alias) object.size_t = ulongsize_t (__gshared global) ulong cpu_pmu_unwind_stack_user.gNFramesgNFrames;
extern (C) int int cpu_pmu_unwind_stack_user.uwNextThread(cpu_pmu_unwind_stack_user.Dwfl* dwfl, void* arg, void** threadArgp) nothrow @nogcuwNextThread((struct) cpu_pmu_unwind_stack_user.DwflDwfl* (parameter) cpu_pmu_unwind_stack_user.Dwfl* dwfldwfl, void* (parameter) void* argarg, void** (parameter) void** threadArgpthreadArgp) @nogc nothrow
{
if (*(parameter) void** threadArgpthreadArgp !is null)
return 0;
*(parameter) void** threadArgpthreadArgp = (parameter) void* argarg;
return (__gshared global) cpu_pmu_unwind_stack_user.Sample* cpu_pmu_unwind_stack_user.gSamplegSample.(field) int cpu_pmu_unwind_stack_user.Sample.tidtid;
}
extern (C) bool bool cpu_pmu_unwind_stack_user.uwMemoryRead(cpu_pmu_unwind_stack_user.Dwfl* dwfl, ulong addr, ulong* result, void* arg) nothrow @nogcuwMemoryRead((struct) cpu_pmu_unwind_stack_user.DwflDwfl* (parameter) cpu_pmu_unwind_stack_user.Dwfl* dwfldwfl, (alias) cpu_pmu_unwind_stack_user.Dwarf_Addr = ulongDwarf_Addr (parameter) ulong addraddr, (alias) cpu_pmu_unwind_stack_user.Dwarf_Word = ulongDwarf_Word* (parameter) ulong* resultresult, void* (parameter) void* argarg) @nogc nothrow
{
auto (local variable) cpu_pmu_unwind_stack_user.Sample* ss = (__gshared global) cpu_pmu_unwind_stack_user.Sample* cpu_pmu_unwind_stack_user.gSamplegSample;
if ((parameter) ulong addraddr >= (local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong cpu_pmu_unwind_stack_user.Sample.spsp && (parameter) ulong addraddr + 8 <= (local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong cpu_pmu_unwind_stack_user.Sample.spsp + (local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ubyte[] cpu_pmu_unwind_stack_user.Sample.stackstack.(field) ulong ubyte[].lengthlength)
{
*(parameter) ulong* resultresult = *cast(ulong*)((local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ubyte[] cpu_pmu_unwind_stack_user.Sample.stackstack.(field) ubyte* ubyte[].ptrptr + ((parameter) ulong addraddr - (local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong cpu_pmu_unwind_stack_user.Sample.spsp));
return true;
}
return false; // outside the captured slab → unwinder stops here
}
extern (C) bool bool cpu_pmu_unwind_stack_user.uwSetInitialRegisters(cpu_pmu_unwind_stack_user.Dwfl_Thread* thread, void* arg) nothrow @nogcuwSetInitialRegisters((struct) cpu_pmu_unwind_stack_user.Dwfl_ThreadDwfl_Thread* (parameter) cpu_pmu_unwind_stack_user.Dwfl_Thread* threadthread, void* (parameter) void* argarg) @nogc nothrow
{
auto (local variable) cpu_pmu_unwind_stack_user.Sample* ss = (__gshared global) cpu_pmu_unwind_stack_user.Sample* cpu_pmu_unwind_stack_user.gSamplegSample;
// Map perf capture order → DWARF x86-64 register numbers 0..16.
with ((enum) cpu_pmu_unwind_stack_user.CapIdxCapIdx)
{
(alias) cpu_pmu_unwind_stack_user.Dwarf_Word = ulongDwarf_Word[17] (local variable) ulong[17] dwdw = [
(local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.AX = 0AX], (local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.DX = 3DX], (local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.CX = 2CX], (local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.BX = 1BX], // dw 0..3
(local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.SI = 4SI], (local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.DI = 5DI], (local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.BP = 6BP], (local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.SP = 7SP], // dw 4..7
(local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.R8 = 9R8], (local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.R9 = 10R9], (local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.R10 = 11R10], (local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.R11 = 12R11], // dw 8..11
(local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.R12 = 13R12], (local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.R13 = 14R13], (local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.R14 = 15R14], (local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.R15 = 16R15], // dw 12..15
(local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.IP = 8IP], // dw 16 = RIP
];
void cpu_pmu_unwind_stack_user.dwfl_thread_state_register_pc(cpu_pmu_unwind_stack_user.Dwfl_Thread*, ulong pc) nothrow @nogcdwfl_thread_state_register_pc((parameter) cpu_pmu_unwind_stack_user.Dwfl_Thread* threadthread, (local variable) cpu_pmu_unwind_stack_user.Sample* ss.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.IP = 8IP]);
return bool cpu_pmu_unwind_stack_user.dwfl_thread_state_registers(cpu_pmu_unwind_stack_user.Dwfl_Thread*, int firstreg, uint nregs, const(ulong)* regs) nothrow @nogcdwfl_thread_state_registers((parameter) cpu_pmu_unwind_stack_user.Dwfl_Thread* threadthread, 0, 17, (local variable) ulong[17] dwdw.(constant) ulong* ulong[17].ptr = &dwptr);
}
}
extern (C) int int cpu_pmu_unwind_stack_user.uwFrameCb(cpu_pmu_unwind_stack_user.Dwfl_Frame* state, void* arg) nothrow @nogcuwFrameCb((struct) cpu_pmu_unwind_stack_user.Dwfl_FrameDwfl_Frame* (parameter) cpu_pmu_unwind_stack_user.Dwfl_Frame* statestate, void* (parameter) void* argarg) @nogc nothrow
{
(alias) cpu_pmu_unwind_stack_user.Dwarf_Addr = ulongDwarf_Addr (local variable) ulong pcpc;
bool (local variable) bool isActivationisActivation;
if (!bool cpu_pmu_unwind_stack_user.dwfl_frame_pc(cpu_pmu_unwind_stack_user.Dwfl_Frame*, ulong* pc, bool* isactivation) nothrow @nogcdwfl_frame_pc((parameter) cpu_pmu_unwind_stack_user.Dwfl_Frame* statestate, &(local variable) ulong pcpc, &(local variable) bool isActivationisActivation))
return 1; // DWARF_CB_ABORT
if (!(local variable) bool isActivationisActivation && (local variable) ulong pcpc)
(local variable) ulong pcpc -= 1; // step back into the call instruction for the caller frames
if ((__gshared global) ulong cpu_pmu_unwind_stack_user.gNFramesgNFrames < (__gshared global) ulong[64] cpu_pmu_unwind_stack_user.gFramesgFrames.(constant) ulong ulong[64].length = 64LUlength)
(__gshared global) ulong[64] cpu_pmu_unwind_stack_user.gFramesgFrames[(__gshared global) ulong cpu_pmu_unwind_stack_user.gNFramesgNFrames++] = (local variable) ulong pcpc;
return (__gshared global) ulong cpu_pmu_unwind_stack_user.gNFramesgNFrames >= 32 ? 1 : 0; // cap depth; DWARF_CB_OK = 0
}
// ---- a deliberately deep, frame-pointer-less call chain ------------
__gshared ulong (__gshared global) ulong cpu_pmu_unwind_stack_user.sinksink;
pragma(inline, false) ulong ulong cpu_pmu_unwind_stack_user.level3(ulong x)level3(ulong (parameter) ulong xx)
{
ulong (local variable) ulong ss = 0;
foreach ((local variable) int ii; 0 .. 6000)
(local variable) ulong ss += ((parameter) ulong xx ^ (local variable) int ii) * ((local variable) int ii + 1);
return (local variable) ulong ss;
}
pragma(inline, false) ulong ulong cpu_pmu_unwind_stack_user.level2(ulong x)level2(ulong (parameter) ulong xx) => ulong cpu_pmu_unwind_stack_user.level3(ulong x)level3((parameter) ulong xx) + ulong cpu_pmu_unwind_stack_user.level3(ulong x)level3((parameter) ulong xx >> 1);
pragma(inline, false) ulong ulong cpu_pmu_unwind_stack_user.level1(ulong x)level1(ulong (parameter) ulong xx) => ulong cpu_pmu_unwind_stack_user.level2(ulong x)level2((parameter) ulong xx) ^ ulong cpu_pmu_unwind_stack_user.level2(ulong x)level2((parameter) ulong xx + 1);
void void cpu_pmu_unwind_stack_user.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 + 400.msecs;
ulong (local variable) ulong accacc = 0xABCD_1234_5678_9EF0UL;
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_unwind_stack_user.level1(ulong x)level1((local variable) ulong accacc);
(__gshared global) ulong cpu_pmu_unwind_stack_user.sinksink += (local variable) ulong accacc;
}
/// Resolve a PC to `name+off` for the backtrace print.
(alias) object.string = stringstring string cpu_pmu_unwind_stack_user.symbolize(cpu_pmu_unwind_stack_user.Dwfl* dwfl, ulong pc)Resolve a PC to name+off for the backtrace print.
symbolize((struct) cpu_pmu_unwind_stack_user.DwflDwfl* (parameter) cpu_pmu_unwind_stack_user.Dwfl* dwfldwfl, ulong (parameter) ulong pcpc)
{
auto (local variable) cpu_pmu_unwind_stack_user.Dwfl_Module* modmod = (() @trusted => cpu_pmu_unwind_stack_user.Dwfl_Module* cpu_pmu_unwind_stack_user.dwfl_addrmodule(cpu_pmu_unwind_stack_user.Dwfl*, ulong) nothrow @nogcdwfl_addrmodule((parameter) cpu_pmu_unwind_stack_user.Dwfl* dwfldwfl, (parameter) ulong pcpc))();
if ((local variable) cpu_pmu_unwind_stack_user.Dwfl_Module* modmod is null)
return "<no module>";
(alias) cpu_pmu_unwind_stack_user.GElf_Off = ulongGElf_Off (local variable) ulong offoff;
(struct) cpu_pmu_unwind_stack_user.GElf_SymGElf_Sym (local variable) cpu_pmu_unwind_stack_user.GElf_Sym symsym;
const (local variable) const(char*) nameznamez = (() @trusted => const(char)* cpu_pmu_unwind_stack_user.dwfl_module_addrinfo(cpu_pmu_unwind_stack_user.Dwfl_Module*, ulong, ulong*, cpu_pmu_unwind_stack_user.GElf_Sym*, uint*, cpu_pmu_unwind_stack_user.Elf**, ulong*) nothrow @nogcdwfl_module_addrinfo((local variable) cpu_pmu_unwind_stack_user.Dwfl_Module* modmod, (parameter) ulong pcpc, &(local variable) ulong offoff, &(local variable) cpu_pmu_unwind_stack_user.GElf_Sym symsym, null, null, null))();
if ((local variable) const(char*) nameznamez is null)
return "<unknown>";
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;
return 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 ~ "+0x" ~ (local variable) ulong offoff.string std.conv.to!string.to!(ulong, int)(ulong __param_0, int __param_1) 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!(alias) object.string = stringstring(16);
}
int int cpu_pmu_unwind_stack_user.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_unwind_stack_user.run.dataPages = 256dataPages = 256;
const (local variable) const(ulong) dataSizedataSize = (constant) int cpu_pmu_unwind_stack_user.run.dataPages = 256dataPages * (local variable) const(ulong) pageSizepageSize;
const (local variable) const(ulong) mmapSizemmapSize = (1 + (constant) int cpu_pmu_unwind_stack_user.run.dataPages = 256dataPages) * (local variable) const(ulong) pageSizepageSize;
enum (constant) uint cpu_pmu_unwind_stack_user.run.stackBytes = 8192ustackBytes = 8192u;
(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
| (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_REGS_USER = 4096uPERF_SAMPLE_REGS_USER
| (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_STACK_USER = 8192uPERF_SAMPLE_STACK_USER;
(local variable) core.sys.linux.perf_event.perf_event_attr attrattr.(field) ulong core.sys.linux.perf_event.perf_event_attr.sample_regs_userDefines set of user regs to dump on samples.
See asm/perf_regs.h for details.
sample_regs_user = (constant) ulong cpu_pmu_unwind_stack_user.regsMask = 16712191LUregsMask;
(local variable) core.sys.linux.perf_event.perf_event_attr attrattr.(field) uint core.sys.linux.perf_event.perf_event_attr.sample_stack_userDefines size of the user stack to dump on samples.
sample_stack_user = (constant) uint cpu_pmu_unwind_stack_user.run.stackBytes = 8192ustackBytes;
(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 = 1500;
(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;
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 (stack sampling) failed — "
~ "perf_event_paranoid, seccomp, or no PMU");
return 0;
}
void* (local variable) void* basebase = (() @trusted => mmap(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 perf ring buffer failed");
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;
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 cpu_pmu_unwind_stack_user.workload()workload();
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);
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;
ubyte[32768] (local variable) ubyte[32768] recrec;
void void cpu_pmu_unwind_stack_user.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);
}
}
(struct) cpu_pmu_unwind_stack_user.SampleOne captured sample: leaf IP, the 17 selected registers (perf order), and
a copy of the user-stack slab (valid dyn_size bytes from sp upward).
Sample[] (local variable) cpu_pmu_unwind_stack_user.Sample[] samplessamples;
(alias) object.size_t = ulongsize_t (local variable) ulong nRegsAbiNonenRegsAbiNone = 0;
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_unwind_stack_user.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[32768] recrec.(constant) ulong ubyte[32768].length = 32768LUlength)
(local variable) ulong szsz = (local variable) ubyte[32768] recrec.(constant) ulong ubyte[32768].length = 32768LUlength;
void cpu_pmu_unwind_stack_user.run.ringCopy(ulong pos, ubyte* dst, ulong n) pure nothrow @nogc @trustedringCopy((local variable) ulong tailtail, (local variable) ubyte[32768] recrec.(constant) ubyte* ubyte[32768].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)
continue;
// body: ip(8) pid(4) tid(4) time(8) regsAbi(8) regs[17*8]
// stackSize(8) stackData[stackSize] dynSize(8)
(() @trusted {
(alias) object.size_t = ulongsize_t (local variable) ulong oo = 8;
(struct) cpu_pmu_unwind_stack_user.SampleOne captured sample: leaf IP, the 17 selected registers (perf order), and
a copy of the user-stack slab (valid dyn_size bytes from sp upward).
Sample (local variable) cpu_pmu_unwind_stack_user.Sample ss;
(local variable) cpu_pmu_unwind_stack_user.Sample ss.(field) ulong cpu_pmu_unwind_stack_user.Sample.ipip = *cast(ulong*)((local variable) ubyte[32768] recrec.(constant) ubyte* ubyte[32768].ptr = &recptr + (local variable) ulong oo); (local variable) ulong oo += 8;
(local variable) ulong oo += 4; // pid
(local variable) cpu_pmu_unwind_stack_user.Sample ss.(field) int cpu_pmu_unwind_stack_user.Sample.tidtid = *cast(int*)((local variable) ubyte[32768] recrec.(constant) ubyte* ubyte[32768].ptr = &recptr + (local variable) ulong oo); (local variable) ulong oo += 4;
(local variable) ulong oo += 8; // time
(local variable) cpu_pmu_unwind_stack_user.Sample ss.(field) ulong cpu_pmu_unwind_stack_user.Sample.regsAbiregsAbi = *cast(ulong*)((local variable) ubyte[32768] recrec.(constant) ubyte* ubyte[32768].ptr = &recptr + (local variable) ulong oo); (local variable) ulong oo += 8;
if ((local variable) cpu_pmu_unwind_stack_user.Sample ss.(field) ulong cpu_pmu_unwind_stack_user.Sample.regsAbiregsAbi == 0)
{
(local variable) ulong nRegsAbiNonenRegsAbiNone++;
return;
}
void* core.stdc.string.memcpy(return scope void* s1, scope const(void*) s2, ulong n) pure nothrow @nogcmemcpy((local variable) cpu_pmu_unwind_stack_user.Sample ss.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs.(constant) ulong* ulong[17].ptr = &s.regsptr, (local variable) ubyte[32768] recrec.(constant) ubyte* ubyte[32768].ptr = &recptr + (local variable) ulong oo, 17 * 8); (local variable) ulong oo += 17 * 8;
const (local variable) const(ulong) stackSizestackSize = *cast(ulong*)((local variable) ubyte[32768] recrec.(constant) ubyte* ubyte[32768].ptr = &recptr + (local variable) ulong oo); (local variable) ulong oo += 8;
const (local variable) const(ulong) dynSizedynSize = *cast(ulong*)((local variable) ubyte[32768] recrec.(constant) ubyte* ubyte[32768].ptr = &recptr + (local variable) ulong oo + (local variable) const(ulong) stackSizestackSize);
(local variable) cpu_pmu_unwind_stack_user.Sample ss.(field) ulong cpu_pmu_unwind_stack_user.Sample.spsp = (local variable) cpu_pmu_unwind_stack_user.Sample ss.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum) cpu_pmu_unwind_stack_user.CapIdxCapIdx.(enum value) cpu_pmu_unwind_stack_user.CapIdx.SP = 7SP];
const (local variable) const(ulong) validvalid = (local variable) const(ulong) dynSizedynSize < (local variable) const(ulong) stackSizestackSize ? (local variable) const(ulong) dynSizedynSize : (local variable) const(ulong) stackSizestackSize;
(local variable) cpu_pmu_unwind_stack_user.Sample ss.(field) ubyte[] cpu_pmu_unwind_stack_user.Sample.stackstack = ((local variable) ubyte[32768] recrec.(constant) ubyte* ubyte[32768].ptr = &recptr + (local variable) ulong oo)[0 .. cast((alias) object.size_t = ulongsize_t) (local variable) const(ulong) validvalid].ubyte[] object.dup!ubyte(const(ubyte)[] a) pure nothrow @property @safedup;
(local variable) cpu_pmu_unwind_stack_user.Sample[] samplessamples ~= (local variable) cpu_pmu_unwind_stack_user.Sample ss;
})();
}
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)(in char[] fmt, ulong __param_1, ulong __param_2) @safeEquivalent to writef(fmt, args, '\n').
writefln("captured: %d samples with REGS_USER+STACK_USER "
~ "(%d had ABI_NONE, no user regs)", (local variable) cpu_pmu_unwind_stack_user.Sample[] samplessamples.(field) ulong cpu_pmu_unwind_stack_user.Sample[].lengthlength, (local variable) ulong nRegsAbiNonenRegsAbiNone);
if ((local variable) cpu_pmu_unwind_stack_user.Sample[] samplessamples.(field) ulong cpu_pmu_unwind_stack_user.Sample[].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 register/stack samples captured — the ring path ran; "
~ "nothing to unwind");
return 0;
}
// ---- set up libdwfl module model ---------------------------------
__gshared (struct) cpu_pmu_unwind_stack_user.DwflCallbacksDwfl_Callbacks (find_elf, find_debuginfo, section_address, debuginfo_path).
DwflCallbacks (__gshared global) cpu_pmu_unwind_stack_user.DwflCallbacks cpu_pmu_unwind_stack_user.run.cbcb;
(__gshared global) cpu_pmu_unwind_stack_user.DwflCallbacks cpu_pmu_unwind_stack_user.run.cbcb.(field) void* cpu_pmu_unwind_stack_user.DwflCallbacks.find_elffind_elf = (() @trusted => cast(void*)&int cpu_pmu_unwind_stack_user.dwfl_linux_proc_find_elf() nothrow @nogcdwfl_linux_proc_find_elf)();
(__gshared global) cpu_pmu_unwind_stack_user.DwflCallbacks cpu_pmu_unwind_stack_user.run.cbcb.(field) void* cpu_pmu_unwind_stack_user.DwflCallbacks.find_debuginfofind_debuginfo = (() @trusted => cast(void*)&int cpu_pmu_unwind_stack_user.dwfl_standard_find_debuginfo() nothrow @nogcdwfl_standard_find_debuginfo)();
(struct) cpu_pmu_unwind_stack_user.DwflDwfl* (local variable) cpu_pmu_unwind_stack_user.Dwfl* dwfldwfl = (() @trusted => cpu_pmu_unwind_stack_user.Dwfl* cpu_pmu_unwind_stack_user.dwfl_begin(const(cpu_pmu_unwind_stack_user.DwflCallbacks)*) nothrow @nogcdwfl_begin(&(__gshared global) cpu_pmu_unwind_stack_user.DwflCallbacks cpu_pmu_unwind_stack_user.run.cbcb))();
if ((local variable) cpu_pmu_unwind_stack_user.Dwfl* dwfldwfl is null
|| (() @trusted => int cpu_pmu_unwind_stack_user.dwfl_linux_proc_report(cpu_pmu_unwind_stack_user.Dwfl*, int pid) nothrow @nogcdwfl_linux_proc_report((local variable) cpu_pmu_unwind_stack_user.Dwfl* dwfldwfl, int core.sys.posix.unistd.getpid() nothrow @nogc @trustedgetpid()))() != 0
|| (() @trusted => int cpu_pmu_unwind_stack_user.dwfl_report_end(cpu_pmu_unwind_stack_user.Dwfl*, void* removed, void* arg) nothrow @nogcdwfl_report_end((local variable) cpu_pmu_unwind_stack_user.Dwfl* dwfldwfl, null, null))() != 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: libdwfl module reporting failed — capture verified; "
~ "unwind skipped");
return 0;
}
// Pick a sample whose leaf IP lands in level3 (the deepest frame) so the
// backtrace is a stable demonstration; fall back to the first sample.
(struct) cpu_pmu_unwind_stack_user.SampleOne captured sample: leaf IP, the 17 selected registers (perf order), and
a copy of the user-stack slab (valid dyn_size bytes from sp upward).
Sample* (local variable) cpu_pmu_unwind_stack_user.Sample* chosenchosen = &(local variable) cpu_pmu_unwind_stack_user.Sample[] samplessamples[0];
foreach (ref (parameter) cpu_pmu_unwind_stack_user.Sample ss; (local variable) cpu_pmu_unwind_stack_user.Sample[] samplessamples)
{
auto (local variable) string nmnm = string cpu_pmu_unwind_stack_user.symbolize(cpu_pmu_unwind_stack_user.Dwfl* dwfl, ulong pc)Resolve a PC to name+off for the backtrace print.
symbolize((local variable) cpu_pmu_unwind_stack_user.Dwfl* dwfldwfl, (local variable) cpu_pmu_unwind_stack_user.Sample ss.(field) ulong cpu_pmu_unwind_stack_user.Sample.ipip);
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) canFind = std.algorithm.searching.canFind(alias pred = "a == b")Convenience function. Like find, but only returns whether or not the search
was successful.
For more information about pred see $(LREF find).
See_Also:
$(REF among, std,algorithm,comparison) for checking a value against multiple arguments.
canFind;
if ((local variable) string nmnm.bool std.algorithm.searching.canFind!().canFind!(string, string)(string haystack, scope string needle) pure nothrow @nogc @safeConvenience function. Like find, but only returns whether or not the search
was successful.
For more information about pred see find.
Examples
const arr = [0, 1, 2, 3];
assert(canFind(arr, 2));
assert(!canFind(arr, 4));
// find one of several needles
assert(arr.canFind(3, 2));
assert(arr.canFind(3, 2) == 2); // second needle found
assert(arr.canFind([1, 3], 2) == 2);
assert(canFind(arr, [1, 2], [2, 3]));
assert(canFind(arr, [1, 2], [2, 3]) == 1);
assert(canFind(arr, [1, 7], [2, 3]));
assert(canFind(arr, [1, 7], [2, 3]) == 2);
assert(!canFind(arr, [1, 3], [2, 4]));
assert(canFind(arr, [1, 3], [2, 4]) == 0);
Example using a custom predicate.
Note that the needle appears as the second argument of the predicate.
auto words = [
"apple",
"beeswax",
"cardboard"
];
assert(!canFind(words, "bees"));
assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees"));
Search for multiple items in an array of items (search for needles in an array of haystacks)
string s1 = "aaa111aaa";
string s2 = "aaa222aaa";
string s3 = "aaa333aaa";
string s4 = "aaa444aaa";
const hay = [s1, s2, s3, s4];
assert(hay.canFind!(e => e.canFind("111", "222")));
canFind("level3"))
{
(local variable) cpu_pmu_unwind_stack_user.Sample* chosenchosen = &(local variable) cpu_pmu_unwind_stack_user.Sample ss;
break;
}
}
// ---- Stage 1: prove the capture (registers + stack) ---------------
with ((enum) cpu_pmu_unwind_stack_user.CapIdxCapIdx)
void std.stdio.writefln!(char, ulong, string, ulong, ulong, ulong, ulong, ulong)(in char[] fmt, ulong __param_1, string __param_2, ulong __param_3, ulong __param_4, ulong __param_5, ulong __param_6, ulong __param_7) @safeEquivalent to writef(fmt, args, '\n').
writefln("\nchosen sample: leaf IP 0x%x (%s)\n"
~ " regs ABI=%d RIP=0x%x RSP=0x%x RBP=0x%x captured stack=%d bytes",
(local variable) cpu_pmu_unwind_stack_user.Sample* chosenchosen.(field) ulong cpu_pmu_unwind_stack_user.Sample.ipip, string cpu_pmu_unwind_stack_user.symbolize(cpu_pmu_unwind_stack_user.Dwfl* dwfl, ulong pc)Resolve a PC to name+off for the backtrace print.
symbolize((local variable) cpu_pmu_unwind_stack_user.Dwfl* dwfldwfl, (local variable) cpu_pmu_unwind_stack_user.Sample* chosenchosen.(field) ulong cpu_pmu_unwind_stack_user.Sample.ipip), (local variable) cpu_pmu_unwind_stack_user.Sample* chosenchosen.(field) ulong cpu_pmu_unwind_stack_user.Sample.regsAbiregsAbi,
(local variable) cpu_pmu_unwind_stack_user.Sample* chosenchosen.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.IP = 8IP], (local variable) cpu_pmu_unwind_stack_user.Sample* chosenchosen.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.SP = 7SP], (local variable) cpu_pmu_unwind_stack_user.Sample* chosenchosen.(field) ulong[17] cpu_pmu_unwind_stack_user.Sample.regsregs[(enum value) cpu_pmu_unwind_stack_user.CapIdx.BP = 6BP], (local variable) cpu_pmu_unwind_stack_user.Sample* chosenchosen.(field) ubyte[] cpu_pmu_unwind_stack_user.Sample.stackstack.(field) ulong ubyte[].lengthlength);
// ---- Stage 2: attempt the full in-process CFI unwind --------------
(__gshared global) cpu_pmu_unwind_stack_user.Sample* cpu_pmu_unwind_stack_user.gSamplegSample = (local variable) cpu_pmu_unwind_stack_user.Sample* chosenchosen;
(__gshared global) ulong cpu_pmu_unwind_stack_user.gNFramesgNFrames = 0;
__gshared (struct) cpu_pmu_unwind_stack_user.DwflThreadCallbacksDwfl_Thread_Callbacks (elfutils@6f8f78c libdwfl/libdwfl.h:661): field
order next_thread, get_thread, memory_read, set_initial_registers,
detach, thread_detach.
DwflThreadCallbacks (__gshared global) cpu_pmu_unwind_stack_user.DwflThreadCallbacks cpu_pmu_unwind_stack_user.run.tcbtcb;
(__gshared global) cpu_pmu_unwind_stack_user.DwflThreadCallbacks cpu_pmu_unwind_stack_user.run.tcbtcb.(field) void* cpu_pmu_unwind_stack_user.DwflThreadCallbacks.next_threadnext_thread = (() @trusted => cast(void*)&int cpu_pmu_unwind_stack_user.uwNextThread(cpu_pmu_unwind_stack_user.Dwfl* dwfl, void* arg, void** threadArgp) nothrow @nogcuwNextThread)();
(__gshared global) cpu_pmu_unwind_stack_user.DwflThreadCallbacks cpu_pmu_unwind_stack_user.run.tcbtcb.(field) void* cpu_pmu_unwind_stack_user.DwflThreadCallbacks.memory_readmemory_read = (() @trusted => cast(void*)&bool cpu_pmu_unwind_stack_user.uwMemoryRead(cpu_pmu_unwind_stack_user.Dwfl* dwfl, ulong addr, ulong* result, void* arg) nothrow @nogcuwMemoryRead)();
(__gshared global) cpu_pmu_unwind_stack_user.DwflThreadCallbacks cpu_pmu_unwind_stack_user.run.tcbtcb.(field) void* cpu_pmu_unwind_stack_user.DwflThreadCallbacks.set_initial_registersset_initial_registers = (() @trusted => cast(void*)&bool cpu_pmu_unwind_stack_user.uwSetInitialRegisters(cpu_pmu_unwind_stack_user.Dwfl_Thread* thread, void* arg) nothrow @nogcuwSetInitialRegisters)();
const (local variable) const(bool) attachedattached = (() @trusted => bool cpu_pmu_unwind_stack_user.dwfl_attach_state(cpu_pmu_unwind_stack_user.Dwfl*, cpu_pmu_unwind_stack_user.Elf*, int pid, const(cpu_pmu_unwind_stack_user.DwflThreadCallbacks)*, void* arg) nothrow @nogcdwfl_attach_state((local variable) cpu_pmu_unwind_stack_user.Dwfl* dwfldwfl, null, (local variable) cpu_pmu_unwind_stack_user.Sample* chosenchosen.(field) int cpu_pmu_unwind_stack_user.Sample.tidtid, &(__gshared global) cpu_pmu_unwind_stack_user.DwflThreadCallbacks cpu_pmu_unwind_stack_user.run.tcbtcb, null))();
int (local variable) int rcrc = -1;
if ((local variable) const(bool) attachedattached)
(local variable) int rcrc = (() @trusted => int cpu_pmu_unwind_stack_user.dwfl_getthread_frames(cpu_pmu_unwind_stack_user.Dwfl*, int tid, void* callback, void* arg) nothrow @nogcdwfl_getthread_frames((local variable) cpu_pmu_unwind_stack_user.Dwfl* dwfldwfl, (__gshared global) cpu_pmu_unwind_stack_user.Sample* cpu_pmu_unwind_stack_user.gSamplegSample.(field) int cpu_pmu_unwind_stack_user.Sample.tidtid,
(() @trusted => cast(void*)&int cpu_pmu_unwind_stack_user.uwFrameCb(cpu_pmu_unwind_stack_user.Dwfl_Frame* state, void* arg) nothrow @nogcuwFrameCb)(), null))();
if ((local variable) const(bool) attachedattached && (__gshared global) ulong cpu_pmu_unwind_stack_user.gNFramesgNFrames > 0)
{
void std.stdio.writefln!(char, ulong)(in char[] fmt, ulong __param_1) @safeEquivalent to writef(fmt, args, '\n').
writefln("\nDWARF-CFI backtrace (%d frames, frame pointers OMITTED — "
~ "so this came purely from .eh_frame/.debug_frame CFI):", (__gshared global) ulong cpu_pmu_unwind_stack_user.gNFramesgNFrames);
foreach ((parameter) ulong ii, (parameter) ulong pcpc; (__gshared global) ulong[64] cpu_pmu_unwind_stack_user.gFramesgFrames[0 .. (__gshared global) ulong cpu_pmu_unwind_stack_user.gNFramesgNFrames])
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(" #%-2d 0x%x %s", (local variable) ulong ii, (local variable) ulong pcpc, string cpu_pmu_unwind_stack_user.symbolize(cpu_pmu_unwind_stack_user.Dwfl* dwfl, ulong pc)Resolve a PC to name+off for the backtrace print.
symbolize((local variable) cpu_pmu_unwind_stack_user.Dwfl* dwfldwfl, (local variable) ulong pcpc));
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(" (dwfl_getthread_frames drove the unwind; memory_read served "
~ "the captured STACK_USER slab, set_initial_registers the REGS_USER set.)");
}
else
{
void std.stdio.writefln!(char, const(bool), int)(in char[] fmt, const(bool) __param_1, int __param_2) @safeEquivalent to writef(fmt, args, '\n').
writefln("\nnote: in-process dwfl unwind did not complete "
~ "(attach=%s, rc=%d) — the CAPTURE is verified above; the unwind API "
~ "path (dwfl_attach_state → Dwfl_Thread_Callbacks → "
~ "dwfl_getthread_frames → dwfl_frame_pc) is grounded in "
~ "docs/research/cpu-pmu/elfutils.md by source-reading.", (local variable) const(bool) attachedattached, (local variable) int rcrc);
}
(() @trusted => void cpu_pmu_unwind_stack_user.dwfl_end(cpu_pmu_unwind_stack_user.Dwfl*) nothrow @nogcdwfl_end((local variable) cpu_pmu_unwind_stack_user.Dwfl* dwfldwfl))();
return 0;
}
}
int int D main()main()
{
version (linuxlinux)
{
version (X86_64X86_64)
return int cpu_pmu_unwind_stack_user.run()run();
else
{
import std.stdio : writefln;
writefln("SKIP: this unwind probe's perf→DWARF register map is x86-64-only");
return 0;
}
}
else
{
import std.stdio : writefln;
writefln("SKIP: perf_event sampling is Linux-only");
return 0;
}
}