Nugget
Bare-metal libraries and examples for the original PlayStation
Loading...
Searching...
No Matches
pcsxprof.h
Go to the documentation of this file.
1/*
2
3MIT License
4
5Copyright (c) 2026 PCSX-Redux authors
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26
27/* Layout of a scoped-profiler ring buffer, shared between the guest
28 (psyqo/profiler.hh) and the emulator, which reads it live out of guest RAM
29 once the guest registers it with PCSX_CMD_REGISTER_PROFILER (pcsxcmd.h).
30
31 Pointer-sized fields are uint32_t so the layout is the same on a 64-bit
32 host as on the R3000.
33
34 Timestamps are (root counter 1 << 16) | root counter 2, with counter 1
35 counting hblanks and counter 2 free-running on the system clock. Neither
36 alone covers a frame, and they are not read atomically, so the elapsed
37 cycles between two stamps are rebuilt from both: the line delta times the
38 measured cycles per line gives an estimate within about one line, and the
39 counter 2 delta gives the exact cycle count modulo 65536. That is exact
40 for spans up to the counter 1 wrap, 65536 lines or about 4 seconds. See
41 pcsx_profElapsed. */
42
43#pragma once
44
45#include <stdint.h>
46
47#define PCSX_PROF_MAGIC 0x46505150 /* 'PQPF' */
48#define PCSX_PROF_VERSION 1
49
51 /* Set when the console was in PAL mode at install time. Informational:
52 elapsed times use cyclesPer16Lines, which was measured. */
54};
55
56/* One static descriptor per profiled scope, in read-only data. Its address
57 is the zone's identity. */
59 uint32_t name; /* const char*, NUL-terminated */
60 uint32_t file; /* const char*, NUL-terminated */
61 uint32_t line;
62};
63
64/* One completed scope. Written when the scope ends, so nested scopes land
65 innermost first. */
67 uint32_t zone; /* const struct pcsx_ProfZone* */
68 uint32_t start;
69 uint32_t end;
70 /* Low 16 bits of the vsync counter when the scope started. */
71 uint16_t vsync;
72 /* Nesting level among profiled scopes, 0 for the outermost. */
73 uint8_t depth;
74 /* Shadow call stack depth when the scope started, in builds that keep
75 one (psyqo's BUILD=FastDebug), clamped to 255. 0 otherwise. */
76 uint8_t stackDepth;
77};
78
80 uint32_t magic;
81 uint16_t version;
82 uint16_t entrySize;
83 /* Number of entries, a power of two. */
84 uint32_t capacity;
85 uint32_t flags;
86 /* System clock cycles per 16 hblanks, measured at install time. */
88 uint32_t entries; /* struct pcsx_ProfEntry*, capacity of them */
89 /* Total entries ever written. Entry n lives at entries[n % capacity], and
90 is complete once written has moved past it. A reader that falls more
91 than capacity entries behind has lost the difference. */
92 volatile uint32_t written;
93};
94
95/* What a reader checks before trusting a header: the layout version it
96 knows, whole aligned entries, and an entry array that fits in 2 MB of RAM. */
97static inline int pcsx_profHeaderValid(uint32_t magic, uint32_t version, uint32_t entrySize, uint32_t capacity,
98 uint32_t entries) {
99 return (magic == PCSX_PROF_MAGIC) && (version == PCSX_PROF_VERSION) &&
100 (entrySize >= sizeof(struct pcsx_ProfEntry)) && !(entrySize & 3) && capacity &&
101 !(capacity & (capacity - 1)) && (entrySize <= 64) && (capacity <= 0x200000 / entrySize) && !(entries & 3);
102}
103
104/* Elapsed system clock cycles from stamp a to stamp b, b no more than about
105 4 seconds after a. */
106static inline uint32_t pcsx_profElapsed(uint32_t a, uint32_t b, uint32_t cyclesPer16Lines) {
107 uint32_t lines = (uint16_t)((b >> 16) - (a >> 16));
108 uint32_t cycles = (uint16_t)(b - a);
109 /* Fits: at most 65535 lines times about 34.7k cycles per 16 lines. */
110 uint32_t estimate = (lines * cyclesPer16Lines) >> 4;
111 int32_t wraps = ((int32_t)(estimate - cycles) + 32768) >> 16;
112 return cycles + ((uint32_t)wraps << 16);
113}
uint8_t b
Definition gte-depthcue.c:41
int a
Definition mktest.py:134
int cycles
Definition mktest.py:120
pcsx_ProfFlags
Definition pcsxprof.h:50
@ PCSX_PROF_FLAG_PAL
Definition pcsxprof.h:53
#define PCSX_PROF_MAGIC
Definition pcsxprof.h:47
#define PCSX_PROF_VERSION
Definition pcsxprof.h:48
Definition pcsxprof.h:66
uint32_t end
Definition pcsxprof.h:69
uint8_t depth
Definition pcsxprof.h:73
uint32_t zone
Definition pcsxprof.h:67
uint16_t vsync
Definition pcsxprof.h:71
uint32_t start
Definition pcsxprof.h:68
uint8_t stackDepth
Definition pcsxprof.h:76
Definition pcsxprof.h:79
uint32_t magic
Definition pcsxprof.h:80
uint32_t flags
Definition pcsxprof.h:85
uint32_t cyclesPer16Lines
Definition pcsxprof.h:87
uint32_t capacity
Definition pcsxprof.h:84
uint32_t entries
Definition pcsxprof.h:88
volatile uint32_t written
Definition pcsxprof.h:92
uint16_t entrySize
Definition pcsxprof.h:82
uint16_t version
Definition pcsxprof.h:81
Definition pcsxprof.h:58
uint32_t name
Definition pcsxprof.h:59
uint32_t file
Definition pcsxprof.h:60
uint32_t line
Definition pcsxprof.h:61
uint32_t wraps
Definition timers.c:594
int lines
Definition timers.c:412