Compare commits

..
Author SHA1 Message Date
tequ 37b2d2995c Merge branch 'dev' into refactor/transactions-macro-includes 2026-10-24 09:48:29 +09:00
tequ 86ac135c63 refactor: include transactor headers from transactions.macro
Partial cherry-pick of XRPLF/rippled#5590. Each TRANSACTION entry now
carries its transactor header behind `#if TRANSACTION_INCLUDE`, and
applySteps.cpp pulls them in by expanding the macro with
TRANSACTION_INCLUDE defined. Adding a transaction type no longer
requires touching the include list in applySteps.cpp.

ApplyContext.h (reached via Transactor.h) and XahauGenesis.h (unused
there) are dropped from applySteps.cpp.
2026-10-22 15:44:30 +09:00
9 changed files with 211 additions and 786 deletions

No files matched your search

-34
View File
@@ -1,34 +0,0 @@
// [TEST PR] Print hypervisor identification and KVM paravirt feature bits.
#include <cpuid.h>
#include <stdio.h>
#include <string.h>
int
main(void)
{
unsigned a = 0, b = 0, c = 0, d = 0;
char sig[13] = {0};
__cpuid(0x40000000, a, b, c, d);
memcpy(sig, &b, 4);
memcpy(sig + 4, &c, 4);
memcpy(sig + 8, &d, 4);
printf("hv_signature=%s hv_max_leaf=0x%x\n", sig, a);
if (strcmp(sig, "KVMKVMKVM") == 0 && a >= 0x40000001)
{
__cpuid(0x40000001, a, b, c, d);
printf(
"kvm_features=0x%x clocksource2=%u async_pf=%u steal_time=%u "
"pv_eoi=%u pv_unhalt=%u pv_tlb_flush=%u pv_sched_yield=%u "
"hints_realtime=%u\n",
a,
(a >> 3) & 1,
(a >> 4) & 1,
(a >> 5) & 1,
(a >> 6) & 1,
(a >> 7) & 1,
(a >> 9) & 1,
(a >> 13) & 1,
d & 1);
}
return 0;
}
-89
View File
@@ -1,89 +0,0 @@
// [TEST PR] Host first-touch latency probe.
// memfresh <MB> <interval_sec>
// Every <interval_sec>: mmap <MB> of fresh anonymous memory, touch each page
// while timing it, munmap. Fresh guest pages that the host has never backed
// need a host-side allocation (EPT fault); on a host under memory pressure or
// doing hugepage compaction that costs milliseconds to seconds per page
// instead of about a microsecond.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
static double
now_ms(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1e3 + ts.tv_nsec / 1e6;
}
static void
utc(char* buf, size_t n)
{
struct timespec ts;
struct tm tm;
clock_gettime(CLOCK_REALTIME, &ts);
gmtime_r(&ts.tv_sec, &tm);
size_t l = strftime(buf, n, "%FT%T", &tm);
snprintf(buf + l, n - l, ".%03ldZ", ts.tv_nsec / 1000000);
}
int
main(int argc, char** argv)
{
if (argc < 3)
return 2;
size_t const mb = (size_t)atoi(argv[1]);
int const interval = atoi(argv[2]);
size_t const len = mb << 20, page = 4096;
setvbuf(stdout, NULL, _IOLBF, 0);
char b[48];
for (;;)
{
volatile unsigned char* buf = mmap(
NULL,
len,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
-1,
0);
if (buf == MAP_FAILED)
{
perror("mmap");
return 1;
}
double const t0 = now_ms();
double max = 0, sum_slow = 0;
long slow = 0;
for (size_t off = 0; off < len; off += page)
{
double const a = now_ms();
buf[off] = 1;
double const d = now_ms() - a;
if (d > 1.0)
{
++slow;
sum_slow += d;
}
if (d > max)
max = d;
}
double const total = now_ms() - t0;
munmap((void*)buf, len);
utc(b, sizeof b);
printf(
"%s memfresh mb=%zu total=%.0fms us_per_page=%.2f pages_over_1ms=%ld "
"slow_sum=%.0fms max_page=%.1fms\n",
b,
mb,
total,
total * 1000.0 / (double)(len / page),
slow,
sum_slow,
max);
sleep(interval);
}
}
-85
View File
@@ -1,85 +0,0 @@
// [TEST PR] Host-swap / page-residency probe.
// memtouch <MB> <idle_sec>
// Allocates and touches <MB> of memory, then repeatedly sleeps <idle_sec> and
// re-touches every page while timing each touch. Guest-resident memory costs
// well under a microsecond per page; pages the host has swapped out or
// reclaimed cost milliseconds each (a host page-in per page). A re-touch of a
// 512 MB buffer that takes seconds, with many pages over 1 ms, means the host
// is paging this VM's memory.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
static double
now_ms(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1e3 + ts.tv_nsec / 1e6;
}
static void
utc(char* buf, size_t n)
{
struct timespec ts;
struct tm tm;
clock_gettime(CLOCK_REALTIME, &ts);
gmtime_r(&ts.tv_sec, &tm);
size_t l = strftime(buf, n, "%FT%T", &tm);
snprintf(buf + l, n - l, ".%03ldZ", ts.tv_nsec / 1000000);
}
int
main(int argc, char** argv)
{
if (argc < 3)
return 2;
size_t const mb = (size_t)atoi(argv[1]);
int const idle = atoi(argv[2]);
size_t const len = mb << 20, page = 4096;
setvbuf(stdout, NULL, _IOLBF, 0);
volatile unsigned char* buf = mmap(
NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (buf == MAP_FAILED)
{
perror("mmap");
return 1;
}
memset((void*)buf, 1, len);
char b[48];
for (;;)
{
sleep(idle);
double const t0 = now_ms();
double max = 0, sum_slow = 0;
long slow = 0;
for (size_t off = 0; off < len; off += page)
{
double const a = now_ms();
buf[off] += 1;
double const d = now_ms() - a;
if (d > 1.0)
{
++slow;
sum_slow += d;
}
if (d > max)
max = d;
}
utc(b, sizeof b);
printf(
"%s memtouch mb=%zu idle=%ds total=%.0fms pages_over_1ms=%ld "
"slow_sum=%.0fms max_page=%.1fms\n",
b,
mb,
idle,
now_ms() - t0,
slow,
sum_slow,
max);
}
}
-187
View File
@@ -1,187 +0,0 @@
// [TEST PR] Stall probe for the coverage runner VM.
// stall_probe spin <cpu> <threshold_ms> pin to <cpu>, spin, report gaps
// between
// consecutive clock reads above
// threshold
// stall_probe sleep <ms> <threshold_ms> nanosleep(<ms>) in a loop, report
// wake-ups
// late by more than threshold
// stall_probe exit <cpu> <threshold_ms> pin, execute cpuid (an
// unconditional VM
// exit) once per ms; a gap whose
// work= equals the gap is a vCPU
// stuck in the hypervisor
// stall_probe fault <cpu> <threshold_ms> pin, map+touch+unmap 2 MB of fresh
// pages
// every 5 ms; work= equal to the gap
// means the stall is in the
// page-fault/EPT path
// Each gap line carries the thread's voluntary/involuntary context switch
// deltas: a spin gap with nivcsw+=0 means the thread stayed on its CPU from the
// guest's point of view, i.e. the vCPU itself was not running (hypervisor),
// while nivcsw>0 is ordinary in-guest preemption. Counters are read every
// iteration so the deltas cover exactly the reported gap.
#define _GNU_SOURCE
#include <cpuid.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <time.h>
#include <unistd.h>
static double
now_ms(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1e3 + ts.tv_nsec / 1e6;
}
static void
utc(char* buf, size_t n)
{
struct timespec ts;
struct tm tm;
clock_gettime(CLOCK_REALTIME, &ts);
gmtime_r(&ts.tv_sec, &tm);
size_t l = strftime(buf, n, "%FT%T", &tm);
snprintf(buf + l, n - l, ".%03ldZ", ts.tv_nsec / 1000000);
}
enum mode { SPIN, SLEEP, EXIT, FAULT, BIG };
// One unit of work for the exit/fault modes; returns its duration in ms.
// For fault mode the three phases are timed separately so a slow unit can
// be attributed to mmap (guest VMA work), the touches (guest page fault +
// EPT fault in the host) or munmap (TLB shootdown / PV flush).
static double g_map, g_touch, g_unmap;
static double
work(enum mode m)
{
double const t0 = now_ms();
if (m == EXIT)
{
unsigned a, b, c, d;
__cpuid(0, a, b, c, d);
}
else if (m == FAULT || m == BIG)
{
size_t const n = m == BIG ? 64u << 20 : 2u << 20;
char* p = mmap(
NULL,
n,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
-1,
0);
double const t1 = now_ms();
if (p != MAP_FAILED)
{
for (size_t i = 0; i < n; i += 4096)
p[i] = 1;
}
double const t2 = now_ms();
if (p != MAP_FAILED)
munmap(p, n);
double const t3 = now_ms();
g_map = t1 - t0;
g_touch = t2 - t1;
g_unmap = t3 - t2;
}
return now_ms() - t0;
}
int
main(int argc, char** argv)
{
if (argc < 4)
return 2;
enum mode const m = strcmp(argv[1], "spin") == 0 ? SPIN
: strcmp(argv[1], "sleep") == 0 ? SLEEP
: strcmp(argv[1], "exit") == 0 ? EXIT
: strcmp(argv[1], "fault") == 0 ? FAULT
: BIG;
int const spin = m != SLEEP;
double const pace = m == EXIT ? 1 : m == FAULT ? 5 : m == BIG ? 1000 : 0;
int const arg = atoi(argv[2]);
double const thr = atof(argv[3]);
setvbuf(stdout, NULL, _IOLBF, 0);
if (spin)
{
cpu_set_t s;
CPU_ZERO(&s);
CPU_SET(arg, &s);
if (sched_setaffinity(0, sizeof s, &s) != 0)
perror("sched_setaffinity");
}
struct rusage ru;
getrusage(RUSAGE_THREAD, &ru);
long pv = ru.ru_nvcsw, pi = ru.ru_nivcsw;
double prev = now_ms(), last_report = prev, maxgap = 0;
long gaps = 0, gaps_no_switch = 0;
char b[48];
for (;;)
{
double w = 0;
if (!spin)
{
struct timespec r = {arg / 1000, (arg % 1000) * 1000000L};
nanosleep(&r, NULL);
}
else if (pace > 0)
{
w = work(m);
while (now_ms() - prev < pace)
;
}
double const t = now_ms();
double const gap = t - prev - (spin ? 0 : arg);
// Track the switch counters continuously so a gap's delta covers
// only that gap (a syscall per iteration is fine for a probe).
getrusage(RUSAGE_THREAD, &ru);
long const dv = ru.ru_nvcsw - pv, di = ru.ru_nivcsw - pi;
pv = ru.ru_nvcsw;
pi = ru.ru_nivcsw;
if (gap > thr)
{
utc(b, sizeof b);
printf(
"%s %s gap=%.0fms cpu=%d nvcsw+=%ld nivcsw+=%ld work=%.0fms "
"map/touch/unmap=%.0f/%.0f/%.0f\n",
b,
argv[1],
gap,
sched_getcpu(),
dv,
di,
w,
g_map,
g_touch,
g_unmap);
++gaps;
if (spin && di == 0)
++gaps_no_switch;
if (gap > maxgap)
maxgap = gap;
}
if (t - last_report > 60000)
{
utc(b, sizeof b);
printf(
"%s %s alive cpu=%d gaps=%ld gaps_without_switch=%ld "
"maxgap=%.0fms\n",
b,
argv[1],
sched_getcpu(),
gaps,
gaps_no_switch,
maxgap);
last_report = t;
}
prev = t;
}
}
-146
View File
@@ -286,110 +286,6 @@ jobs:
clang_gcc_toolchain: ${{ matrix.clang_gcc_toolchain || '' }}
ccache_max_size: '100G'
# [TEST PR] Host sampler: every 20s record load, PSI, steal time, cgroup
# CPU throttling and the number of rippled processes for the whole
# coverage build+test run, so a multi_runner stall report can be
# correlated with host state. Detached; printed by the step after Build.
- name: Start host sampler (coverage)
if: matrix.job_type == 'coverage'
shell: bash
run: |
cat > "$RUNNER_TEMP/sampler.sh" <<'EOF'
#!/bin/bash
out="$1"
prev_total=0; prev_steal=0; prev_up=""
while true; do
read -r _ u n s i w q sq st _ < /proc/stat
total=$((u+n+s+i+w+q+sq+st))
dt=$((total-prev_total)); ds=$((st-prev_steal))
steal_pct=0
[ "$prev_total" -gt 0 ] && [ "$dt" -gt 0 ] && steal_pct=$((100*ds/dt))
# Fraction of guest CPU time actually accounted over the interval:
# jiffies delta / (wall delta * ncpu * HZ). Well below 100% with
# steal%=0 means the vCPUs were not running (hypervisor), which the
# guest cannot see as steal on this VM.
now_up=$(cut -d' ' -f1 /proc/uptime)
delivered="n/a"
if [ -n "$prev_up" ]; then
delivered=$(awk -v dj="$dt" -v du="$(awk -v a="$now_up" -v b="$prev_up" 'BEGIN{print a-b}')" -v n="$(nproc)" 'BEGIN{ if (du>0) printf "%d%%", 100*dj/(du*n*100); else print "n/a"}')
fi
prev_up=$now_up
prev_total=$total; prev_steal=$st
nr=0; nl=0
for c in /proc/[0-9]*/comm; do
read -r name < "$c" 2>/dev/null || continue
[ "$name" = rippled ] && nr=$((nr+1))
case "$name" in llvm*) nl=$((nl+1));; esac
done
# block I/O: sectors written and ms spent doing I/O, summed over whole disks
disk=$(awk '$3 ~ /^(sd[a-z]+|vd[a-z]+|nvme[0-9]+n[0-9]+)$/ {w+=$10; t+=$13} END{printf "wr_sectors=%d io_ms=%d", w, t}' /proc/diskstats)
vm=$(awk '/^(pgpgout|nr_dirty|nr_writeback|pgfault|thp_fault_alloc|thp_fault_fallback|compact_stall|compact_fail|pgmigrate_success|pgalloc_normal|pgfree|nr_free_pages|balloon_inflate|balloon_deflate) /{printf "%s=%s ", $1, $2}' /proc/vmstat)
thr=$(grep -E '^(nr_throttled|throttled_usec)' /sys/fs/cgroup/cpu.stat 2>/dev/null | tr '\n' ' ')
# the multi_runner parent: the rippled whose cmdline has --unittest but not --unittest-child
pp=""
for d in /proc/[0-9]*; do
read -r name < "$d/comm" 2>/dev/null && [ "$name" = rippled ] || continue
cl=$(tr '\0' ' ' < "$d/cmdline" 2>/dev/null) || continue
case "$cl" in
*--unittest-child*) ;;
*--unittest*) pp=${d#/proc/}; break ;;
esac
done
parent=""
if [ -n "$pp" ] && [ -r "/proc/$pp/schedstat" ]; then
# schedstat: on-cpu ns, runqueue-wait ns, timeslices; thread states (R/S/D counts)
parent="parent_pid=$pp schedstat=[$(cat /proc/$pp/schedstat)] threads=[$(awk '{print $3}' /proc/$pp/task/*/stat 2>/dev/null | sort | uniq -c | tr -s ' \n' ' ')] ctxsw=[$(awk '/ctxt_switches/{printf "%s ", $2}' /proc/$pp/status)]"
fi
percpu=$(awk '/^cpu[0-9]/{printf "%d,", $2+$3+$4+$5+$6+$7+$8+$9}' /proc/stat)
echo "$(date -u +%FT%TZ) up=$(cut -d' ' -f1 /proc/uptime) load=$(cut -d' ' -f1-3 /proc/loadavg) steal%=$steal_pct steal_total=$st cpu_delivered=$delivered jiffies=$total psi_cpu=$(awk '/^some/{print $2}' /proc/pressure/cpu 2>/dev/null) psi_mem=$(awk '/^full/{print $2}' /proc/pressure/memory 2>/dev/null) psi_io=$(awk '/^some/{print $2}' /proc/pressure/io 2>/dev/null) memavail_mb=$(awk '/MemAvailable/{print int($2/1024)}' /proc/meminfo) rippled_procs=$nr llvm_procs=$nl $disk $vm$thr$parent percpu_jiffies=$percpu" >> "$out"
sleep 5
done
EOF
chmod +x "$RUNNER_TEMP/sampler.sh"
echo "nproc=$(nproc) cpu.max=$(cat /sys/fs/cgroup/cpu.max 2>/dev/null || echo n/a) cpuset=$(cat /sys/fs/cgroup/cpuset.cpus.effective 2>/dev/null || echo n/a)"
echo "kernel=$(uname -r) clocksource=$(cat /sys/devices/system/clocksource/clocksource0/current_clocksource 2>/dev/null) hypervisor_flag=$(grep -c -w hypervisor /proc/cpuinfo) dmi=$(cat /sys/class/dmi/id/sys_vendor /sys/class/dmi/id/product_name 2>/dev/null | tr '\n' ' ') dmesg_restrict=$(cat /proc/sys/kernel/dmesg_restrict 2>/dev/null)"
grep -E '^(model name|cpu MHz)' /proc/cpuinfo | sort | uniq -c | head -4
setsid nohup "$RUNNER_TEMP/sampler.sh" "$RUNNER_TEMP/host-samples.log" > /dev/null 2>&1 &
echo "sampler pid $!"
# Probes (see .github/scripts/ci-probe/*.c): hypervisor features once, then a
# 10ms sleeper (timer wake-up latency, the parent heartbeat's situation) and
# two spinners pinned to CPUs 3 and 17 (vCPU not running vs in-guest preemption),
# two cpuid loops pinned to CPUs 5 and 11 (is a vCPU stuck returning from a VM
# exit?) and a fresh-page toucher pinned to CPU 9 (is it the page-fault path?).
${{ matrix.cc }} -O2 -o "$RUNNER_TEMP/hv_info" .github/scripts/ci-probe/hv_info.c && "$RUNNER_TEMP/hv_info" || echo "hv_info unavailable"
cat /sys/class/dmi/id/bios_vendor /sys/class/dmi/id/bios_version /sys/class/dmi/id/product_version 2>/dev/null | tr '\n' ' '; echo
if ${{ matrix.cc }} -O2 -o "$RUNNER_TEMP/stall_probe" .github/scripts/ci-probe/stall_probe.c; then
setsid nohup "$RUNNER_TEMP/stall_probe" sleep 10 100 > "$RUNNER_TEMP/probe-sleep.log" 2>&1 &
setsid nohup "$RUNNER_TEMP/stall_probe" spin 3 100 > "$RUNNER_TEMP/probe-spin3.log" 2>&1 &
setsid nohup "$RUNNER_TEMP/stall_probe" spin 17 100 > "$RUNNER_TEMP/probe-spin17.log" 2>&1 &
setsid nohup "$RUNNER_TEMP/stall_probe" exit 5 100 > "$RUNNER_TEMP/probe-exit5.log" 2>&1 &
setsid nohup "$RUNNER_TEMP/stall_probe" exit 11 100 > "$RUNNER_TEMP/probe-exit11.log" 2>&1 &
setsid nohup "$RUNNER_TEMP/stall_probe" fault 9 100 > "$RUNNER_TEMP/probe-fault9.log" 2>&1 &
setsid nohup "$RUNNER_TEMP/stall_probe" big 13 100 > "$RUNNER_TEMP/probe-big13.log" 2>&1 &
echo "probes started"
else
echo "stall_probe build failed; continuing without probes"
fi
# Host paging probe: 512 MB re-touched after 120 s idle, and 64 MB after 10 s (control).
if ${{ matrix.cc }} -O2 -o "$RUNNER_TEMP/memtouch" .github/scripts/ci-probe/memtouch.c; then
setsid nohup "$RUNNER_TEMP/memtouch" 512 120 > "$RUNNER_TEMP/probe-mem512.log" 2>&1 &
setsid nohup "$RUNNER_TEMP/memtouch" 64 10 > "$RUNNER_TEMP/probe-mem64.log" 2>&1 &
fi
if ${{ matrix.cc }} -O2 -o "$RUNNER_TEMP/memfresh" .github/scripts/ci-probe/memfresh.c; then
setsid nohup "$RUNNER_TEMP/memfresh" 512 90 > "$RUNNER_TEMP/probe-memfresh.log" 2>&1 &
fi
echo "clockevent=$(cat /sys/devices/system/clockevents/clockevent0/current_device 2>/dev/null) available_clocksource=$(cat /sys/devices/system/clocksource/clocksource0/available_clocksource 2>/dev/null) thp=$(cat /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null) virtio_drivers=$(ls /sys/bus/virtio/drivers 2>/dev/null | tr '\n' ',')"
# Is idle time in /proc/stat wall-clock based (NO_HZ idle) or tick based? Decides
# whether lost per-vCPU jiffies on an idle guest mean "halted vCPU not woken" or
# "vCPU frozen while running". Plus the TSC flags behind the missing tsc clocksource.
echo "cmdline=$(cat /proc/cmdline) nohz_full=$(cat /sys/devices/system/cpu/nohz_full 2>/dev/null) $(grep -E '^CONFIG_(NO_HZ|HZ=|VIRT_CPU_ACCOUNTING|TICK_CPU_ACCOUNTING|IRQ_TIME_ACCOUNTING)' /boot/config-$(uname -r) 2>/dev/null | tr '\n' ' ') tsc_flags=$(grep -m1 '^flags' /proc/cpuinfo | grep -o -w -E 'constant_tsc|nonstop_tsc|tsc_known_freq|tsc_reliable|rdtscp|tsc_adjust|hypervisor' | tr '\n' ',')"
grep -m2 -E "nohz_mode|hres_active|Clock Event Device" /proc/timer_list 2>/dev/null || echo "timer_list not readable"
# Are the guest's free pages handed back to the host (balloon / free page reporting)?
# If so every fresh page costs a host-side allocation, which is where the fault probe stalls.
for d in /sys/bus/virtio/drivers/virtio_balloon/virtio*; do echo "balloon $(basename $d) features=$(cat $d/features 2>/dev/null)"; done
grep -E "^(balloon_|thp_fault_alloc|thp_collapse_alloc|compact_stall|compact_fail|pgmigrate_success)" /proc/vmstat | tr '\n' ' '; echo
echo "page_reporting_order=$(cat /sys/module/page_reporting/parameters/page_reporting_order 2>/dev/null) thp_defrag=$(cat /sys/kernel/mm/transparent_hugepage/defrag 2>/dev/null) khugepaged_defrag=$(cat /sys/kernel/mm/transparent_hugepage/khugepaged/defrag 2>/dev/null) compaction_proactiveness=$(cat /proc/sys/vm/compaction_proactiveness 2>/dev/null) numa_balancing=$(cat /proc/sys/kernel/numa_balancing 2>/dev/null) nodes=$(ls -d /sys/devices/system/node/node* 2>/dev/null | wc -l)"
- name: Build (Coverage)
if: matrix.job_type == 'coverage'
uses: ./.github/actions/xahau-ga-build
@@ -410,48 +306,6 @@ jobs:
cmake-target: 'coverage'
ccache_max_size: '100G'
# [TEST PR] Keep the slot for 12 more minutes with nothing but the sampler and
# probes running, to see whether the stalls also happen on an idle guest.
- name: Idle stall observation (coverage)
if: always() && matrix.job_type == 'coverage'
shell: bash
run: |
# 3 min quiet baseline, then a controlled 2 GB fdatasync write every 3 min
# (does a guest write burst coincide with vCPU stalls?), 12 min in total.
log="$RUNNER_TEMP/iotest.log"
sleep 180
for i in 1 2 3; do
s=$(date -u +%FT%T.%3NZ); t0=$SECONDS
dd if=/dev/zero of="$RUNNER_TEMP/iotest.bin" bs=1M count=2048 conv=fdatasync 2>/dev/null
echo "$s dd 2GB fdatasync start, took $((SECONDS-t0))s, ended $(date -u +%FT%T.%3NZ)" >> "$log"
rm -f "$RUNNER_TEMP/iotest.bin"
sleep 180
done
# [TEST PR] see "Start host sampler" above.
- name: Show host samples (coverage)
if: always() && matrix.job_type == 'coverage'
shell: bash
run: |
pkill -f sampler.sh || true
pkill -x stall_probe || true
for f in sleep spin3 spin17 exit5 exit11 fault9 big13; do
echo "---- probe-$f: $(grep -c ' gap=' "$RUNNER_TEMP/probe-$f.log" 2>/dev/null || true) gaps >100ms; gaps >=500ms or without a context switch:"
{ grep -E ' gap=' "$RUNNER_TEMP/probe-$f.log" 2>/dev/null || true; } | awk '{g=$3; sub("gap=","",g); sub("ms","",g); if (g+0>=500 || $6=="nivcsw+=0") print}' | head -60 || true
{ grep ' alive ' "$RUNNER_TEMP/probe-$f.log" 2>/dev/null || true; } | tail -1 || true
done
pkill -x memtouch || true
pkill -x memfresh || true
echo "---- controlled writes:"; cat "$RUNNER_TEMP/iotest.log" 2>/dev/null || true
for f in mem512 mem64 memfresh; do
echo "---- probe-$f (all lines):"
cat "$RUNNER_TEMP/probe-$f.log" 2>/dev/null || true
done
echo "---- host samples"
cat "$RUNNER_TEMP/host-samples.log" || echo "no samples recorded"
echo "---- kernel messages (if readable) mentioning timers/clock/lockups/kvm, last 40"
dmesg 2>&1 | grep -iE "hrtimer|clocksource|rcu|lockup|stall|kvm|hung task|steal" | tail -40 || true
- name: Set artifact name
if: matrix.job_type == 'build'
id: set-artifact-name
+167 -1
View File
@@ -24,11 +24,21 @@
/**
* TRANSACTION(tag, value, name, fields)
*
* To ease maintenance, you may replace any unneeded values with "..."
* e.g. #define TRANSACTION(tag, value, name, ...)
*
* You must define a transactor class in the `ripple` namespace named `name`,
* and include its header in `src/xrpld/app/tx/detail/applySteps.cpp`.
* and include its header alongside the TRANSACTOR definition using this
* format:
* #if TRANSACTION_INCLUDE
* # include <xrpld/app/tx/detail/HEADER.h>
* #endif
*/
/** This transaction type executes a payment. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/Payment.h>
#endif
TRANSACTION(ttPAYMENT, 0, Payment, ({
{sfDestination, soeREQUIRED},
{sfAmount, soeREQUIRED, soeMPTSupported},
@@ -41,6 +51,9 @@ TRANSACTION(ttPAYMENT, 0, Payment, ({
}))
/** This transaction type creates an escrow object. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/Escrow.h>
#endif
TRANSACTION(ttESCROW_CREATE, 1, EscrowCreate, ({
{sfDestination, soeREQUIRED},
{sfAmount, soeREQUIRED},
@@ -62,6 +75,9 @@ TRANSACTION(ttESCROW_FINISH, 2, EscrowFinish, ({
/** This transaction type adjusts various account settings. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/SetAccount.h>
#endif
TRANSACTION(ttACCOUNT_SET, 3, AccountSet, ({
{sfEmailHash, soeOPTIONAL},
{sfWalletLocator, soeOPTIONAL},
@@ -85,6 +101,9 @@ TRANSACTION(ttESCROW_CANCEL, 4, EscrowCancel, ({
}))
/** This transaction type sets or clears an account's "regular key". */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/SetRegularKey.h>
#endif
TRANSACTION(ttREGULAR_KEY_SET, 5, SetRegularKey, ({
{sfRegularKey, soeOPTIONAL},
}))
@@ -92,6 +111,9 @@ TRANSACTION(ttREGULAR_KEY_SET, 5, SetRegularKey, ({
// 6 deprecated
/** This transaction type creates an offer to trade one asset for another. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/CreateOffer.h>
#endif
TRANSACTION(ttOFFER_CREATE, 7, OfferCreate, ({
{sfTakerPays, soeREQUIRED},
{sfTakerGets, soeREQUIRED},
@@ -101,6 +123,9 @@ TRANSACTION(ttOFFER_CREATE, 7, OfferCreate, ({
}))
/** This transaction type cancels existing offers to trade one asset for another. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/CancelOffer.h>
#endif
TRANSACTION(ttOFFER_CANCEL, 8, OfferCancel, ({
{sfOfferSequence, soeOPTIONAL},
{sfOfferID, soeOPTIONAL}, // keylet as alternative to offerseq
@@ -109,6 +134,9 @@ TRANSACTION(ttOFFER_CANCEL, 8, OfferCancel, ({
// 9 deprecated
/** This transaction type creates a new set of tickets. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/CreateTicket.h>
#endif
TRANSACTION(ttTICKET_CREATE, 10, TicketCreate, ({
{sfTicketCount, soeREQUIRED},
}))
@@ -118,12 +146,18 @@ TRANSACTION(ttTICKET_CREATE, 10, TicketCreate, ({
/** This transaction type modifies the signer list associated with an account. */
// The SignerEntries are optional because a SignerList is deleted by
// setting the SignerQuorum to zero and omitting SignerEntries.
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/SetSignerList.h>
#endif
TRANSACTION(ttSIGNER_LIST_SET, 12, SignerListSet, ({
{sfSignerQuorum, soeREQUIRED},
{sfSignerEntries, soeOPTIONAL},
}))
/** This transaction type creates a new unidirectional XRP payment channel. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/PayChan.h>
#endif
TRANSACTION(ttPAYCHAN_CREATE, 13, PaymentChannelCreate, ({
{sfDestination, soeREQUIRED},
{sfAmount, soeREQUIRED},
@@ -151,6 +185,9 @@ TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim, ({
}))
/** This transaction type creates a new check. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/CreateCheck.h>
#endif
TRANSACTION(ttCHECK_CREATE, 16, CheckCreate, ({
{sfDestination, soeREQUIRED},
{sfSendMax, soeREQUIRED},
@@ -160,6 +197,9 @@ TRANSACTION(ttCHECK_CREATE, 16, CheckCreate, ({
}))
/** This transaction type cashes an existing check. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/CashCheck.h>
#endif
TRANSACTION(ttCHECK_CASH, 17, CheckCash, ({
{sfCheckID, soeREQUIRED},
{sfAmount, soeOPTIONAL},
@@ -167,11 +207,17 @@ TRANSACTION(ttCHECK_CASH, 17, CheckCash, ({
}))
/** This transaction type cancels an existing check. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/CancelCheck.h>
#endif
TRANSACTION(ttCHECK_CANCEL, 18, CheckCancel, ({
{sfCheckID, soeREQUIRED},
}))
/** This transaction type grants or revokes authorization to transfer funds. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/DepositPreauth.h>
#endif
TRANSACTION(ttDEPOSIT_PREAUTH, 19, DepositPreauth, ({
{sfAuthorize, soeOPTIONAL},
{sfUnauthorize, soeOPTIONAL},
@@ -180,6 +226,9 @@ TRANSACTION(ttDEPOSIT_PREAUTH, 19, DepositPreauth, ({
}))
/** This transaction type modifies a trustline between two accounts. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/SetTrust.h>
#endif
TRANSACTION(ttTRUST_SET, 20, TrustSet, ({
{sfLimitAmount, soeOPTIONAL},
{sfQualityIn, soeOPTIONAL},
@@ -187,6 +236,9 @@ TRANSACTION(ttTRUST_SET, 20, TrustSet, ({
}))
/** This transaction type deletes an existing account. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/DeleteAccount.h>
#endif
TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete, ({
{sfDestination, soeREQUIRED},
{sfDestinationTag, soeOPTIONAL},
@@ -194,11 +246,17 @@ TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete, ({
}))
/** This transaction type installs a hook. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/SetHook.h>
#endif
TRANSACTION(ttHOOK_SET, 22, SetHook, ({
{sfHooks, soeREQUIRED},
}))
/** This transaction mints a new NFT. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/NFTokenMint.h>
#endif
TRANSACTION(ttNFTOKEN_MINT, 25, NFTokenMint, ({
{sfNFTokenTaxon, soeREQUIRED},
{sfTransferFee, soeOPTIONAL},
@@ -210,12 +268,18 @@ TRANSACTION(ttNFTOKEN_MINT, 25, NFTokenMint, ({
}))
/** This transaction burns (i.e. destroys) an existing NFT. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/NFTokenBurn.h>
#endif
TRANSACTION(ttNFTOKEN_BURN, 26, NFTokenBurn, ({
{sfNFTokenID, soeREQUIRED},
{sfOwner, soeOPTIONAL},
}))
/** This transaction creates a new offer to buy or sell an NFT. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/NFTokenCreateOffer.h>
#endif
TRANSACTION(ttNFTOKEN_CREATE_OFFER, 27, NFTokenCreateOffer, ({
{sfNFTokenID, soeREQUIRED},
{sfAmount, soeREQUIRED},
@@ -225,11 +289,17 @@ TRANSACTION(ttNFTOKEN_CREATE_OFFER, 27, NFTokenCreateOffer, ({
}))
/** This transaction cancels an existing offer to buy or sell an existing NFT. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/NFTokenCancelOffer.h>
#endif
TRANSACTION(ttNFTOKEN_CANCEL_OFFER, 28, NFTokenCancelOffer, ({
{sfNFTokenOffers, soeREQUIRED},
}))
/** This transaction accepts an existing offer to buy or sell an existing NFT. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/NFTokenAcceptOffer.h>
#endif
TRANSACTION(ttNFTOKEN_ACCEPT_OFFER, 29, NFTokenAcceptOffer, ({
{sfNFTokenBuyOffer, soeOPTIONAL},
{sfNFTokenSellOffer, soeOPTIONAL},
@@ -237,12 +307,18 @@ TRANSACTION(ttNFTOKEN_ACCEPT_OFFER, 29, NFTokenAcceptOffer, ({
}))
/** This transaction claws back issued tokens. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/Clawback.h>
#endif
TRANSACTION(ttCLAWBACK, 30, Clawback, ({
{sfAmount, soeREQUIRED, soeMPTSupported},
{sfHolder, soeOPTIONAL},
}))
/** This transaction claws back tokens from an AMM pool. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/AMMClawback.h>
#endif
TRANSACTION(ttAMM_CLAWBACK, 31, AMMClawback, ({
{sfHolder, soeREQUIRED},
{sfAsset, soeREQUIRED},
@@ -251,6 +327,9 @@ TRANSACTION(ttAMM_CLAWBACK, 31, AMMClawback, ({
}))
/** This transaction type creates an AMM instance */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/AMMCreate.h>
#endif
TRANSACTION(ttAMM_CREATE, 35, AMMCreate, ({
{sfAmount, soeREQUIRED},
{sfAmount2, soeREQUIRED},
@@ -258,6 +337,9 @@ TRANSACTION(ttAMM_CREATE, 35, AMMCreate, ({
}))
/** This transaction type deposits into an AMM instance */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/AMMDeposit.h>
#endif
TRANSACTION(ttAMM_DEPOSIT, 36, AMMDeposit, ({
{sfAsset, soeREQUIRED},
{sfAsset2, soeREQUIRED},
@@ -269,6 +351,9 @@ TRANSACTION(ttAMM_DEPOSIT, 36, AMMDeposit, ({
}))
/** This transaction type withdraws from an AMM instance */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/AMMWithdraw.h>
#endif
TRANSACTION(ttAMM_WITHDRAW, 37, AMMWithdraw, ({
{sfAsset, soeREQUIRED},
{sfAsset2, soeREQUIRED},
@@ -279,6 +364,9 @@ TRANSACTION(ttAMM_WITHDRAW, 37, AMMWithdraw, ({
}))
/** This transaction type votes for the trading fee */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/AMMVote.h>
#endif
TRANSACTION(ttAMM_VOTE, 38, AMMVote, ({
{sfAsset, soeREQUIRED},
{sfAsset2, soeREQUIRED},
@@ -286,6 +374,9 @@ TRANSACTION(ttAMM_VOTE, 38, AMMVote, ({
}))
/** This transaction type bids for the auction slot */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/AMMBid.h>
#endif
TRANSACTION(ttAMM_BID, 39, AMMBid, ({
{sfAsset, soeREQUIRED},
{sfAsset2, soeREQUIRED},
@@ -295,12 +386,18 @@ TRANSACTION(ttAMM_BID, 39, AMMBid, ({
}))
/** This transaction type deletes AMM in the empty state */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/AMMDelete.h>
#endif
TRANSACTION(ttAMM_DELETE, 40, AMMDelete, ({
{sfAsset, soeREQUIRED},
{sfAsset2, soeREQUIRED},
}))
/** This transaction mints/burns/buys/sells a URI TOKEN */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/URIToken.h>
#endif
TRANSACTION(ttURITOKEN_MINT, 45, URITokenMint, ({
{sfURI, soeREQUIRED},
{sfDigest, soeOPTIONAL},
@@ -328,6 +425,9 @@ TRANSACTION(ttURITOKEN_CANCEL_SELL_OFFER, 49, URITokenCancelSellOffer, ({
}))
/** This transactions creates a crosschain sequence number */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/XChainBridge.h>
#endif
TRANSACTION(ttXCHAIN_CREATE_CLAIM_ID, 50, XChainCreateClaimID, ({
{sfXChainBridge, soeREQUIRED},
{sfSignatureReward, soeREQUIRED},
@@ -407,6 +507,9 @@ TRANSACTION(ttXCHAIN_CREATE_BRIDGE, 57, XChainCreateBridge, ({
}))
/** This transaction type creates or updates a DID */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/DID.h>
#endif
TRANSACTION(ttDID_SET, 58, DIDSet, ({
{sfDIDDocument, soeOPTIONAL},
{sfURI, soeOPTIONAL},
@@ -417,6 +520,9 @@ TRANSACTION(ttDID_SET, 58, DIDSet, ({
TRANSACTION(ttDID_DELETE, 59, DIDDelete, ({}))
/** This transaction type creates an Oracle instance */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/SetOracle.h>
#endif
TRANSACTION(ttORACLE_SET, 60, OracleSet, ({
{sfOracleDocumentID, soeREQUIRED},
{sfProvider, soeOPTIONAL},
@@ -427,17 +533,26 @@ TRANSACTION(ttORACLE_SET, 60, OracleSet, ({
}))
/** This transaction type deletes an Oracle instance */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/DeleteOracle.h>
#endif
TRANSACTION(ttORACLE_DELETE, 61, OracleDelete, ({
{sfOracleDocumentID, soeREQUIRED},
}))
/** This transaction type fixes a problem in the ledger state */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/LedgerStateFix.h>
#endif
TRANSACTION(ttLEDGER_STATE_FIX, 62, LedgerStateFix, ({
{sfLedgerFixType, soeREQUIRED},
{sfOwner, soeOPTIONAL},
}))
/** This transaction type creates a MPTokensIssuance instance */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/MPTokenIssuanceCreate.h>
#endif
TRANSACTION(ttMPTOKEN_ISSUANCE_CREATE, 63, MPTokenIssuanceCreate, ({
{sfAssetScale, soeOPTIONAL},
{sfTransferFee, soeOPTIONAL},
@@ -446,23 +561,35 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_CREATE, 63, MPTokenIssuanceCreate, ({
}))
/** This transaction type destroys a MPTokensIssuance instance */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/MPTokenIssuanceDestroy.h>
#endif
TRANSACTION(ttMPTOKEN_ISSUANCE_DESTROY, 64, MPTokenIssuanceDestroy, ({
{sfMPTokenIssuanceID, soeREQUIRED},
}))
/** This transaction type sets flags on a MPTokensIssuance or MPToken instance */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/MPTokenIssuanceSet.h>
#endif
TRANSACTION(ttMPTOKEN_ISSUANCE_SET, 65, MPTokenIssuanceSet, ({
{sfMPTokenIssuanceID, soeREQUIRED},
{sfHolder, soeOPTIONAL},
}))
/** This transaction type authorizes a MPToken instance */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/MPTokenAuthorize.h>
#endif
TRANSACTION(ttMPTOKEN_AUTHORIZE, 66, MPTokenAuthorize, ({
{sfMPTokenIssuanceID, soeREQUIRED},
{sfHolder, soeOPTIONAL},
}))
/** This transaction type create an Credential instance */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/Credentials.h>
#endif
TRANSACTION(ttCREDENTIAL_CREATE, 67, CredentialCreate, ({
{sfSubject, soeREQUIRED},
{sfCredentialType, soeREQUIRED},
@@ -484,6 +611,9 @@ TRANSACTION(ttCREDENTIAL_DELETE, 69, CredentialDelete, ({
}))
/** This transaction type modify a NFToken */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/NFTokenModify.h>
#endif
TRANSACTION(ttNFTOKEN_MODIFY, 70, NFTokenModify, ({
{sfNFTokenID, soeREQUIRED},
{sfOwner, soeOPTIONAL},
@@ -491,12 +621,18 @@ TRANSACTION(ttNFTOKEN_MODIFY, 70, NFTokenModify, ({
}))
/** This transaction type creates or modifies a Permissioned Domain */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/PermissionedDomainSet.h>
#endif
TRANSACTION(ttPERMISSIONED_DOMAIN_SET, 71, PermissionedDomainSet, ({
{sfDomainID, soeOPTIONAL},
{sfAcceptedCredentials, soeREQUIRED},
}))
/** This transaction type deletes a Permissioned Domain */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/PermissionedDomainDelete.h>
#endif
TRANSACTION(ttPERMISSIONED_DOMAIN_DELETE, 72, PermissionedDomainDelete, ({
{sfDomainID, soeREQUIRED},
}))
@@ -510,6 +646,9 @@ TRANSACTION(ttPERMISSIONED_DOMAIN_DELETE, 72, PermissionedDomainDelete, ({
open ledger, so a reveal only becomes public after the revealing
validator's transaction set is locked.
*/
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/Change.h>
#endif
TRANSACTION(ttENTROPY, 89, Entropy, ({
{sfLedgerSequence, soeREQUIRED},
{sfPublicKey, soeREQUIRED},
@@ -519,17 +658,26 @@ TRANSACTION(ttENTROPY, 89, Entropy, ({
/* sfAccount is supplied by TxFormats::commonFields; listing it here as well
makes the SOTemplate reject the format at construction. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/SetManifest.h>
#endif
TRANSACTION(ttMANIFEST_SET, 91, SetManifest, ({
{sfManifest, soeREQUIRED},
}))
/* A pseudo-txn alarm signal for invoking a hook, emitted by validators after alarm set conditions are met */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/Cron.h>
#endif
TRANSACTION(ttCRON, 92, Cron, ({
{sfOwner, soeREQUIRED},
{sfLedgerSequence, soeREQUIRED},
}))
/* Sechedule an alarm for later */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/CronSet.h>
#endif
TRANSACTION(ttCRON_SET, 93, CronSet, ({
{sfDelaySeconds, soeOPTIONAL},
{sfRepeatCount, soeOPTIONAL},
@@ -537,6 +685,9 @@ TRANSACTION(ttCRON_SET, 93, CronSet, ({
}))
/* A note attaching transactor that allows the owner or issuer (on a object by object basis) to attach remarks */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/SetRemarks.h>
#endif
TRANSACTION(ttREMARKS_SET, 94, SetRemarks, ({
{sfObjectID, soeREQUIRED},
{sfRemarks, soeREQUIRED},
@@ -544,6 +695,9 @@ TRANSACTION(ttREMARKS_SET, 94, SetRemarks, ({
/* A payment transactor that delivers only the exact amounts specified, creating accounts and TLs as needed
* that the sender pays for. */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/Remit.h>
#endif
TRANSACTION(ttREMIT, 95, Remit, ({
{sfDestination, soeREQUIRED},
{sfAmounts, soeOPTIONAL},
@@ -558,12 +712,18 @@ TRANSACTION(ttREMIT, 95, Remit, ({
/** This transaction can only be used by the genesis account, which is controlled exclusively by
* rewards/governance hooks, to print new XRP to be delivered directly to an array of destinations,
* according to reward schedule */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/GenesisMint.h>
#endif
TRANSACTION(ttGENESIS_MINT, 96, GenesisMint, ({
{sfGenesisMints, soeREQUIRED},
}))
/** This transaction accepts a proof of burn from an external network as a basis
* for minting according to featureImport */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/Import.h>
#endif
TRANSACTION(ttIMPORT, 97, Import, ({
{sfBlob, soeREQUIRED},
{sfIssuer, soeOPTIONAL},
@@ -571,12 +731,18 @@ TRANSACTION(ttIMPORT, 97, Import, ({
/** This transaction resets accumulator/counters and claims a reward for holding an average balance
* from a specified hook */
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/ClaimReward.h>
#endif
TRANSACTION(ttCLAIM_REWARD, 98, ClaimReward, ({
{sfIssuer, soeOPTIONAL},
{sfClaimCurrency, soeOPTIONAL},
}))
/** This transaction invokes a hook, providing arbitrary data. Essentially as a 0 drop payment. **/
#if TRANSACTION_INCLUDE
# include <xrpld/app/tx/detail/Invoke.h>
#endif
TRANSACTION(ttINVOKE, 99, Invoke, ({
{sfBlob, soeOPTIONAL},
{sfDestination, soeOPTIONAL},
+29 -182
View File
@@ -24,86 +24,16 @@
#include <boost/lexical_cast.hpp>
#include <algorithm>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <vector>
#ifndef _WIN32
#include <unistd.h>
#endif
namespace ripple {
namespace test {
namespace detail {
// UTC wall clock, for correlating stall reports with CI/host logs.
static std::string
now_str()
{
auto const t =
std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
std::tm tm{};
#ifdef _WIN32
gmtime_s(&tm, &t);
#else
gmtime_r(&t, &tm);
#endif
std::stringstream ss;
ss << std::put_time(&tm, "%FT%TZ");
return ss.str();
}
static long
parent_pid()
{
#ifdef _WIN32
return 0;
#else
return static_cast<long>(getppid());
#endif
}
// One line to stderr in a single write, so reports from the parent and
// many children sharing the same pipe do not interleave mid-line.
template <class... Ts>
static void
say(Ts const&... ts)
{
std::ostringstream oss;
(oss << ... << ts) << '\n';
std::cerr << oss.str();
}
// Report when a step of a watchdog-relevant thread took longer than
// `threshold`; returns the elapsed time.
template <class F>
static std::chrono::milliseconds
timed(
char const* who,
char const* what,
F&& f,
std::chrono::milliseconds threshold)
{
using namespace std::chrono;
auto const start = steady_clock::now();
f();
auto const elapsed =
duration_cast<milliseconds>(steady_clock::now() - start);
if (elapsed > threshold)
say(who,
": ",
what,
" took ",
elapsed.count(),
"ms (ended ",
now_str(),
")");
return elapsed;
}
std::string
fmtdur(typename clock_type::duration const& d)
{
@@ -462,32 +392,20 @@ multi_runner_base<IsParent>::add_failures(std::size_t failures)
multi_runner_parent::multi_runner_parent() : os_(std::cout)
{
// Heartbeat: a dedicated thread so the children only stop seeing
// increments when this process really is not running. A sleep that
// overran by more than a second is reported: that is the parent process
// itself being starved by the host, not a blocked I/O.
keep_alive_thread_ = std::thread([this] {
using namespace std::chrono;
while (this->continue_keep_alive_)
{
this->inc_keep_alive_count();
detail::timed(
"multi_runner_parent",
"heartbeat sleep(100ms)",
[] { std::this_thread::sleep_for(milliseconds(100)); },
milliseconds(1000));
}
});
message_queue_thread_ = std::thread([this] {
using namespace std::chrono;
std::vector<char> buf(1 << 20);
while (this->continue_message_queue_ ||
this->message_queue_->get_num_msg())
{
// let children know the parent is still alive
this->inc_keep_alive_count();
if (!this->message_queue_->get_num_msg())
{
std::this_thread::sleep_for(milliseconds(100));
// If a child does not see the keep alive count incremented,
// it will assume the parent has died. This sleep time needs
// to be small enough so the child will see increments from
// a live parent.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
continue;
}
try
@@ -501,32 +419,16 @@ multi_runner_parent::multi_runner_parent() : os_(std::cout)
assert(recvd_size == 1);
MessageType mt{*reinterpret_cast<MessageType*>(buf.data())};
// Blocks until the sending child finishes its second send();
// report if that child was stalled for long.
detail::timed(
"multi_runner_parent",
"receive(body)",
[&] {
this->message_queue_->receive(
buf.data(), buf.size(), recvd_size, priority);
},
milliseconds(1000));
this->message_queue_->receive(
buf.data(), buf.size(), recvd_size, priority);
if (recvd_size)
{
std::string s{buf.data(), recvd_size};
switch (mt)
{
case MessageType::log:
// Blocks if whoever reads our stdout (e.g. ninja)
// is not draining the pipe.
detail::timed(
"multi_runner_parent",
"stdout write+flush",
[&] {
this->os_ << s;
this->os_.flush();
},
milliseconds(1000));
this->os_ << s;
this->os_.flush();
break;
case MessageType::test_start:
running_suites_.insert(std::move(s));
@@ -560,8 +462,6 @@ multi_runner_parent::~multi_runner_parent()
continue_message_queue_ = false;
message_queue_thread_.join();
continue_keep_alive_ = false;
keep_alive_thread_.join();
print_results(os_);
@@ -609,82 +509,29 @@ multi_runner_child::multi_runner_child(
{
if (num_jobs_ > 1)
{
parent_pid_ = detail::parent_pid();
keep_alive_thread_ = std::thread([this] {
using namespace std::chrono;
// A dead parent is detected within one tick through the ppid
// check. The heartbeat is the fallback for a parent that is alive
// but wedged (and for Windows, which has no ppid here), so its
// grace period must exceed any scheduling stall a loaded CI host
// can produce. The old 2.5s limit fired on live parents.
constexpr auto grace = seconds(60);
constexpr auto warn_after = milliseconds(2500);
auto last_count = this->get_keep_alive_count();
auto last_change = steady_clock::now();
bool warned = false;
std::size_t last_count = get_keep_alive_count();
while (this->continue_keep_alive_)
{
std::this_thread::sleep_for(milliseconds(500));
if (parent_pid_ != 0 && detail::parent_pid() != parent_pid_)
// Use a small sleep time so in the normal case the child
// process may shutdown quickly. However, to protect against
// false alarms, use a longer sleep time later on.
std::this_thread::sleep_for(std::chrono::milliseconds(500));
auto cur_count = this->get_keep_alive_count();
if (cur_count == last_count)
{
detail::say(
"multi_runner_child ",
job_index_,
": parent pid ",
parent_pid_,
" is gone (ppid now ",
detail::parent_pid(),
"), exiting. ",
detail::now_str());
std::exit(EXIT_FAILURE);
}
auto const cur_count = this->get_keep_alive_count();
auto const now = steady_clock::now();
if (cur_count != last_count)
{
if (warned)
detail::say(
"multi_runner_child ",
job_index_,
": keep-alive resumed after ",
duration_cast<milliseconds>(now - last_change)
.count(),
"ms. ",
detail::now_str());
last_count = cur_count;
last_change = now;
warned = false;
continue;
}
auto const stalled =
duration_cast<milliseconds>(now - last_change);
if (!warned && stalled >= warn_after)
{
detail::say(
"multi_runner_child ",
job_index_,
": no keep-alive from parent for ",
stalled.count(),
"ms",
parent_pid_ ? " but its pid is still alive" : "",
"; continuing. ",
detail::now_str());
warned = true;
}
if (stalled >= grace)
{
detail::say(
"multi_runner_child ",
job_index_,
": Assuming parent died (no keep-alive for ",
stalled.count(),
"ms), exiting. ",
detail::now_str());
std::exit(EXIT_FAILURE);
// longer sleep time to protect against false alarms
std::this_thread::sleep_for(std::chrono::seconds(2));
cur_count = this->get_keep_alive_count();
if (cur_count == last_count)
{
// assume parent process is no longer alive
std::cerr << "multi_runner_child " << job_index_
<< ": Assuming parent died, exiting.\n";
std::exit(EXIT_FAILURE);
}
}
last_count = cur_count;
}
});
}
-7
View File
@@ -223,11 +223,6 @@ private:
std::ostream& os_;
std::atomic<bool> continue_message_queue_{true};
std::thread message_queue_thread_;
// Heartbeat for the children runs on its own thread so a blocking
// receive() or a blocked stdout write in message_queue_thread_ cannot
// make the children believe the parent died.
std::atomic<bool> continue_keep_alive_{true};
std::thread keep_alive_thread_;
// track running suites so if a child crashes the culprit can be flagged
std::set<std::string> running_suites_;
@@ -268,8 +263,6 @@ private:
bool quiet_{false};
bool print_log_{true};
// pid of the parent at construction; 0 where unavailable (Windows)
long parent_pid_{0};
std::atomic<bool> continue_keep_alive_{true};
std::thread keep_alive_thread_;
+15 -55
View File
@@ -18,61 +18,21 @@
//==============================================================================
#include <xrpld/app/tx/applySteps.h>
#include <xrpld/app/tx/detail/AMMBid.h>
#include <xrpld/app/tx/detail/AMMClawback.h>
#include <xrpld/app/tx/detail/AMMCreate.h>
#include <xrpld/app/tx/detail/AMMDelete.h>
#include <xrpld/app/tx/detail/AMMDeposit.h>
#include <xrpld/app/tx/detail/AMMVote.h>
#include <xrpld/app/tx/detail/AMMWithdraw.h>
#include <xrpld/app/tx/detail/ApplyContext.h>
#include <xrpld/app/tx/detail/CancelCheck.h>
#include <xrpld/app/tx/detail/CancelOffer.h>
#include <xrpld/app/tx/detail/CashCheck.h>
#include <xrpld/app/tx/detail/Change.h>
#include <xrpld/app/tx/detail/ClaimReward.h>
#include <xrpld/app/tx/detail/Clawback.h>
#include <xrpld/app/tx/detail/CreateCheck.h>
#include <xrpld/app/tx/detail/CreateOffer.h>
#include <xrpld/app/tx/detail/CreateTicket.h>
#include <xrpld/app/tx/detail/Credentials.h>
#include <xrpld/app/tx/detail/Cron.h>
#include <xrpld/app/tx/detail/CronSet.h>
#include <xrpld/app/tx/detail/DID.h>
#include <xrpld/app/tx/detail/DeleteAccount.h>
#include <xrpld/app/tx/detail/DeleteOracle.h>
#include <xrpld/app/tx/detail/DepositPreauth.h>
#include <xrpld/app/tx/detail/Escrow.h>
#include <xrpld/app/tx/detail/GenesisMint.h>
#include <xrpld/app/tx/detail/Import.h>
#include <xrpld/app/tx/detail/Invoke.h>
#include <xrpld/app/tx/detail/LedgerStateFix.h>
#include <xrpld/app/tx/detail/MPTokenAuthorize.h>
#include <xrpld/app/tx/detail/MPTokenIssuanceCreate.h>
#include <xrpld/app/tx/detail/MPTokenIssuanceDestroy.h>
#include <xrpld/app/tx/detail/MPTokenIssuanceSet.h>
#include <xrpld/app/tx/detail/NFTokenAcceptOffer.h>
#include <xrpld/app/tx/detail/NFTokenBurn.h>
#include <xrpld/app/tx/detail/NFTokenCancelOffer.h>
#include <xrpld/app/tx/detail/NFTokenCreateOffer.h>
#include <xrpld/app/tx/detail/NFTokenMint.h>
#include <xrpld/app/tx/detail/NFTokenModify.h>
#include <xrpld/app/tx/detail/PayChan.h>
#include <xrpld/app/tx/detail/Payment.h>
#include <xrpld/app/tx/detail/PermissionedDomainDelete.h>
#include <xrpld/app/tx/detail/PermissionedDomainSet.h>
#include <xrpld/app/tx/detail/Remit.h>
#include <xrpld/app/tx/detail/SetAccount.h>
#include <xrpld/app/tx/detail/SetHook.h>
#include <xrpld/app/tx/detail/SetManifest.h>
#include <xrpld/app/tx/detail/SetOracle.h>
#include <xrpld/app/tx/detail/SetRegularKey.h>
#include <xrpld/app/tx/detail/SetRemarks.h>
#include <xrpld/app/tx/detail/SetSignerList.h>
#include <xrpld/app/tx/detail/SetTrust.h>
#include <xrpld/app/tx/detail/URIToken.h>
#include <xrpld/app/tx/detail/XChainBridge.h>
#include <xrpld/app/tx/detail/XahauGenesis.h>
#pragma push_macro("TRANSACTION")
#undef TRANSACTION
// Do nothing
#define TRANSACTION(...)
#define TRANSACTION_INCLUDE 1
#include <xrpl/protocol/detail/transactions.macro>
#undef TRANSACTION
#pragma pop_macro("TRANSACTION")
// DO NOT INCLUDE TRANSACTOR HEADER FILES HERE.
// See the instructions at the top of transactions.macro instead.
#include <xrpl/protocol/TxFormats.h>
#include <stdexcept>