mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
99 lines
5.3 KiB
C
99 lines
5.3 KiB
C
#ifndef PSX_HOST_SPAN_RING_H
|
|
#define PSX_HOST_SPAN_RING_H
|
|
/* Always-on host wall-time rings: where an emulation-thread stall comes from.
|
|
*
|
|
* Two rings, both written continuously from process start in EVERY build
|
|
* (Release too); probes only ever QUERY a window that already happened:
|
|
*
|
|
* - frame stamps: one {guest frame, wall us} per guest frame (131072 frames,
|
|
* ~36 min at 60 Hz). Successive deltas are the per-frame wall time, so a
|
|
* hitch is visible headless as well as windowed (no GL present ring needed).
|
|
* - spans: every named blocking-capable runtime operation (loader, capture,
|
|
* publication commit, cache rescan, autocompile spawn/prepare/compile child)
|
|
* as {kind, start wall us, duration us, guest frame, thread class, arg}.
|
|
* The emulation thread's spans are the candidates for a hitch; background
|
|
* spans show the work that fed them.
|
|
*
|
|
* Wall time is microseconds since the first call in the process (monotonic).
|
|
* Writers may be different threads. Per-slot ownership and publication sequence
|
|
* validation prevent torn or overwritten rows. Contended samples are dropped;
|
|
* diagnostics never wait for a reader to release a slot.
|
|
*
|
|
* Reading: TCP "host_span_ring" / "frame_wall_ring"; a title's hitch report
|
|
* tool joins them (LegendOfDragoonRecomp tools/lod_hitch_report.py). */
|
|
#include <stdint.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
typedef enum HostSpanKind {
|
|
HSPAN_NONE = 0,
|
|
HSPAN_AUTOCAPTURE_TICK, /* emu: overlay_autocapture_tick (whole) */
|
|
HSPAN_PROVIDER_POLL, /* emu: code provider poll_main (whole) */
|
|
HSPAN_PUBLISH_COMMIT, /* emu: overlay_loader_commit_published */
|
|
HSPAN_LOADER_RESCAN, /* emu: overlay_loader_rescan */
|
|
HSPAN_DLL_REGISTER, /* emu: parse manifest + load_overlay_dll */
|
|
HSPAN_LAZY_LOAD, /* emu: try_load_region (miss -> cache load) */
|
|
HSPAN_CAPTURE_ON_DMA, /* emu: overlay_capture_on_dma (CD/DMA arrival) */
|
|
HSPAN_CAPTURE_BEFORE_DMA, /* emu: overlay_capture_before_dma (evidence save) */
|
|
HSPAN_AC_REQUEST, /* emu: autocompile_request (spawn compiler) */
|
|
HSPAN_AC_DONE_JOIN, /* emu: poll_main joining finished workers */
|
|
HSPAN_AC_PREPARE_IMAGE, /* bg : publication preparer LoadLibrary */
|
|
HSPAN_AC_CHILD, /* bg : compiler child process lifetime */
|
|
HSPAN_OVERLAY_DISPATCH, /* emu: overlay_loader_dispatch slow path */
|
|
HSPAN_MOD_WORK, /* emu: resident pack / mod host work */
|
|
HSPAN_FRAME_PRESENT, /* emu: frontend present for the frame */
|
|
HSPAN_DISC_READ, /* emu: one sector read from the disc image (arg lba) */
|
|
HSPAN_HOST_EVENTS, /* emu: pump and dispatch host window events */
|
|
HSPAN_REWIND_CAPTURE, /* emu: snapshot, store and thumbnail */
|
|
HSPAN_DISPLAY_PROBE, /* emu: host refresh/mode query */
|
|
HSPAN_AUDIO_UPDATE, /* emu: host audio pump */
|
|
HSPAN_KIND_COUNT
|
|
} HostSpanKind;
|
|
|
|
typedef struct HostSpan {
|
|
uint64_t t0_us; /* start, wall us since process clock origin */
|
|
uint32_t dur_us; /* duration (saturates at ~71 min) */
|
|
uint32_t frame; /* guest frame when the span ended */
|
|
uint32_t arg; /* kind-specific (address, ok flag, count) */
|
|
uint16_t kind; /* HostSpanKind */
|
|
uint16_t emu; /* 1 = emulation thread, 0 = background */
|
|
} HostSpan;
|
|
|
|
/* Wall microseconds since the process clock origin. */
|
|
uint64_t host_clock_us(void);
|
|
|
|
/* Open / close a span. begin returns the start stamp; end records it. */
|
|
uint64_t host_span_begin(void);
|
|
void host_span_end(HostSpanKind kind, uint64_t t0_us, uint32_t arg);
|
|
/* Record a span whose duration the caller already measured. */
|
|
void host_span_record(HostSpanKind kind, uint64_t t0_us, uint64_t dur_us, uint32_t arg);
|
|
|
|
uint64_t host_span_total(void);
|
|
int host_span_get(uint64_t seq, HostSpan *out);
|
|
const char *host_span_kind_name(unsigned kind);
|
|
/* 65536 spans; spans shorter than HOST_SPAN_MIN_US are not recorded (the per-frame
|
|
* tick wrappers would otherwise flood the ring; a hitch is milliseconds). */
|
|
#define HOST_SPAN_RING_CAP 65536u
|
|
#define HOST_SPAN_MIN_US 50u
|
|
|
|
/* Stamp guest frame `frame` at the current wall time. Also marks the calling
|
|
* thread as the emulation thread for span attribution. Call once per frame.
|
|
* interp_insns is the low 32 bits of the cumulative count of guest instructions run by the
|
|
* interpreter (successive differences = interpreter work in that frame); static_checks likewise
|
|
* counts static-AOT dispatch checks (guest calls into statically compiled code), the work a native
|
|
* stretch of guest code between two vblanks does. Each stamp also records the process's cumulative
|
|
* page-fault count and disk-read volume (KiB), so a frame that waited on the OS (code or data pages
|
|
* paged in from disk) is told apart from one that computed. */
|
|
void host_frame_stamp(uint32_t frame, uint32_t interp_insns, uint32_t static_checks);
|
|
uint64_t host_frame_stamp_total(void);
|
|
int host_frame_stamp_get(uint64_t seq, uint32_t *frame, uint64_t *t_us, uint32_t *interp_insns,
|
|
uint32_t *static_checks, uint32_t *page_faults, uint32_t *io_read_kb);
|
|
#define HOST_FRAME_STAMP_CAP 131072u
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
#endif
|