sdk-core v2026.11.05
PS2 SDK - core tier (build-critical EE/IOP modules)
Loading...
Searching...
No Matches
main.c
1#include <stdio.h>
2#include <string.h>
3#include <math.h>
4#include <kernel.h>
5#include <tamtypes.h>
6
7extern int kputs(char *s);
8
9typedef unsigned long long u64;
10typedef unsigned int u32;
11typedef unsigned short u16;
12typedef unsigned char u8;
13
14static inline u32 cycles(void)
15{
16 u32 v;
17 __asm__ __volatile__("mfc0 %0, $9" : "=r"(v) : : "memory");
18 return v;
19}
20
21#define BUF_BYTES (64 * 1024)
22
23static u8 src_buf[BUF_BYTES] __attribute__((aligned(64)));
24static u8 dst_buf[BUF_BYTES] __attribute__((aligned(64)));
25
26static u32 checksum(const void *p, u32 bytes)
27{
28 const u8 *b = p;
29 u32 h = 2166136261u;
30
31 for (u32 i = 0; i < bytes; i++)
32 h = (h ^ b[i]) * 16777619u;
33 return h;
34}
35
36static u32 rng_state = 12345;
37
38static u32 rng(void)
39{
40 rng_state = rng_state * 1664525u + 1013904223u;
41 return rng_state >> 8;
42}
43
44/* 128-bit loads and stores, the way an MMI memcpy is written. */
45__attribute__((noinline)) static void bench_memcpy_mmi(void *dst, const void *src, u32 bytes)
46{
47 u64 *d = dst;
48 const u64 *s = src;
49
50 for (u32 i = 0; i < bytes / 64; i++) {
51 __asm__ __volatile__(
52 "lq $8, 0(%1)\n\tlq $9, 16(%1)\n\tlq $10, 32(%1)\n\tlq $11, 48(%1)\n\t"
53 "sq $8, 0(%0)\n\tsq $9, 16(%0)\n\tsq $10, 32(%0)\n\tsq $11, 48(%0)"
54 :
55 : "r"(d), "r"(s)
56 : "$8", "$9", "$10", "$11", "memory");
57 d += 8;
58 s += 8;
59 }
60}
61
62__attribute__((noinline)) static void bench_memset_mmi(void *dst, u32 bytes)
63{
64 u64 *d = dst;
65
66 for (u32 i = 0; i < bytes / 64; i++) {
67 __asm__ __volatile__(
68 "pcpyld $8, %1, %1\n\tsq $8, 0(%0)\n\tsq $8, 16(%0)\n\tsq $8, 32(%0)\n\tsq $8, 48(%0)"
69 :
70 : "r"(d), "r"(0x0101010101010101ull)
71 : "$8", "memory");
72 d += 8;
73 }
74}
75
76__attribute__((noinline)) static void bench_memcpy_libc(void *dst, const void *src, u32 bytes)
77{
78 memcpy(dst, src, bytes);
79}
80
81__attribute__((noinline)) static void bench_memcpy_loop(u32 *dst, const u32 *src, u32 words)
82{
83 for (u32 i = 0; i < words; i++)
84 dst[i] = src[i];
85}
86
87/* GIF-style packet building: a tag, then per vertex an RGBAQ, an ST-like pair and an XYZ2 quadword. */
88__attribute__((noinline)) static u32 bench_packet_build(u64 *out, u32 vertices)
89{
90 u64 *p = out;
91
92 *p++ = 0x1000000000008001ull | ((u64)vertices << 0);
93 *p++ = 0x5551ull;
94 for (u32 i = 0; i < vertices; i++) {
95 u32 x = (i * 37) & 0x1ff, y = (i * 91) & 0x1ff, z = i * 3;
96 u32 r = (i * 5) & 0xff, g = (i * 11) & 0xff, b = (i * 17) & 0xff;
97
98 *p++ = (u64)r | ((u64)g << 8) | ((u64)b << 16) | (0x80ull << 24);
99 *p++ = 0x3f800000ull;
100 *p++ = ((u64)(x << 4)) | ((u64)(y << 4) << 16) | ((u64)z << 32);
101 *p++ = 0;
102 }
103 return (u32)(p - out);
104}
105
106/* A small LZ77 decoder: literals and (length, distance) matches. */
107__attribute__((noinline)) static u32 bench_decompress(u8 *out, const u8 *in, u32 in_len)
108{
109 u8 *o = out;
110 const u8 *end = in + in_len;
111
112 while (in < end) {
113 u32 tag = *in++;
114
115 if (tag < 0x80) {
116 u32 n = tag + 1;
117
118 while (n--)
119 *o++ = *in++;
120 } else {
121 u32 len = (tag & 0x7f) + 3;
122 u32 dist = ((u32)in[0] << 8 | in[1]) + 1;
123 const u8 *m = o - dist;
124
125 in += 2;
126 while (len--)
127 *o++ = *m++;
128 }
129 }
130 return (u32)(o - out);
131}
132
133/* Builds a compressed stream of repeated phrases and literals. */
134static u32 make_compressed(u8 *out)
135{
136 u8 *o = out;
137 u32 produced = 0;
138
139 for (u32 i = 0; i < 2000; i++) {
140 u32 n = 4 + (rng() & 7);
141
142 *o++ = (u8)(n - 1);
143 for (u32 k = 0; k < n; k++)
144 *o++ = (u8)rng();
145 produced += n;
146 if (produced > 64) {
147 u32 len = 3 + (rng() & 15), dist = rng() % 48;
148
149 *o++ = (u8)(0x80 | (len - 3));
150 *o++ = (u8)(dist >> 8);
151 *o++ = (u8)dist;
152 produced += len;
153 }
154 }
155 return (u32)(o - out);
156}
157
158#include "inflate_data.h"
159
160/* A table-driven raw deflate (RFC 1951) decoder: 9-bit lookup, canonical walk for longer codes. Like zlib's
161 inflate_table, the table builder is a function of its own; its size counts towards inflate. */
162#define INF_FAST_BITS 9
163
164struct inf_huff {
165 u16 count[16];
166 u16 symbol[320];
167 u16 fast[1 << INF_FAST_BITS];
168};
169
170struct inf_state {
171 const u8 *in, *in_end;
172 u32 bitbuf, bitcnt;
173};
174
175static const u16 inf_len_base[29] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
176 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258};
177static const u8 inf_len_extra[29] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
178 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
179static const u16 inf_dist_base[30] = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
180 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577};
181static const u8 inf_dist_extra[30] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
182 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
183static const u8 inf_clen_order[19] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
184
185static inline __attribute__((always_inline)) void inf_refill(struct inf_state *s)
186{
187 while (s->bitcnt <= 24) {
188 u32 b = s->in < s->in_end ? *s->in++ : 0;
189
190 s->bitbuf |= b << s->bitcnt;
191 s->bitcnt += 8;
192 }
193}
194
195static inline __attribute__((always_inline)) u32 inf_bits(struct inf_state *s, u32 n)
196{
197 u32 v;
198
199 inf_refill(s);
200 v = s->bitbuf & ((1u << n) - 1);
201 s->bitbuf >>= n;
202 s->bitcnt -= n;
203 return v;
204}
205
206__attribute__((noinline)) static void bench_inflate_table(struct inf_huff *h, const u8 *lens, u32 n)
207{
208 u16 offs[16], next[16];
209 u32 code = 0;
210
211 memset(h->count, 0, sizeof(h->count));
212 memset(h->fast, 0, sizeof(h->fast));
213 for (u32 i = 0; i < n; i++)
214 h->count[lens[i]]++;
215 h->count[0] = 0;
216 offs[1] = 0;
217 for (u32 len = 1; len < 15; len++)
218 offs[len + 1] = offs[len] + h->count[len];
219 for (u32 len = 1; len < 16; len++) {
220 code = (code + h->count[len - 1]) << 1;
221 next[len] = (u16)code;
222 }
223 for (u32 i = 0; i < n; i++) {
224 u32 len = lens[i];
225
226 if (len == 0)
227 continue;
228 h->symbol[offs[len]++] = (u16)i;
229 if (len <= INF_FAST_BITS) {
230 u32 c = next[len], rev = 0;
231
232 for (u32 b = 0; b < len; b++)
233 rev |= ((c >> b) & 1) << (len - 1 - b);
234 for (u32 k = rev; k < (1u << INF_FAST_BITS); k += 1u << len)
235 h->fast[k] = (u16)((len << 9) | i);
236 }
237 next[len]++;
238 }
239}
240
241static inline __attribute__((always_inline)) u32 inf_decode(struct inf_state *s, const struct inf_huff *h)
242{
243 u32 e, code = 0, first = 0, index = 0;
244
245 inf_refill(s);
246 e = h->fast[s->bitbuf & ((1u << INF_FAST_BITS) - 1)];
247 if (e) {
248 s->bitbuf >>= e >> 9;
249 s->bitcnt -= e >> 9;
250 return e & 0x1ff;
251 }
252 for (u32 len = 1; len < 16; len++) {
253 u32 count = h->count[len];
254
255 code |= s->bitbuf & 1;
256 s->bitbuf >>= 1;
257 s->bitcnt--;
258 if (code - first < count)
259 return h->symbol[index + code - first];
260 index += count;
261 first = (first + count) << 1;
262 code <<= 1;
263 }
264 return 0xffff;
265}
266
267static struct inf_huff inf_lit, inf_dist;
268
269__attribute__((noinline)) static u32 bench_inflate(u8 *out, const u8 *in, u32 in_len)
270{
271 struct inf_state s = {in, in + in_len, 0, 0};
272 u8 *o = out;
273 u32 last;
274
275 do {
276 u32 type;
277
278 last = inf_bits(&s, 1);
279 type = inf_bits(&s, 2);
280 if (type == 0) {
281 u32 n;
282
283 s.bitbuf >>= s.bitcnt & 7;
284 s.bitcnt -= s.bitcnt & 7;
285 n = inf_bits(&s, 16);
286 inf_bits(&s, 16);
287 while (n--)
288 *o++ = (u8)inf_bits(&s, 8);
289 continue;
290 }
291 if (type == 1) {
292 u8 lens[320];
293 u32 i = 0;
294
295 for (; i < 144; i++)
296 lens[i] = 8;
297 for (; i < 256; i++)
298 lens[i] = 9;
299 for (; i < 280; i++)
300 lens[i] = 7;
301 for (; i < 288; i++)
302 lens[i] = 8;
303 bench_inflate_table(&inf_lit, lens, 288);
304 for (i = 0; i < 30; i++)
305 lens[i] = 5;
306 bench_inflate_table(&inf_dist, lens, 30);
307 } else {
308 u8 lens[320];
309 u32 hlit = inf_bits(&s, 5) + 257, hdist = inf_bits(&s, 5) + 1, hclen = inf_bits(&s, 4) + 4;
310 u32 i;
311
312 memset(lens, 0, 19);
313 for (i = 0; i < hclen; i++)
314 lens[inf_clen_order[i]] = (u8)inf_bits(&s, 3);
315 bench_inflate_table(&inf_lit, lens, 19);
316 for (i = 0; i < hlit + hdist;) {
317 u32 sym = inf_decode(&s, &inf_lit), rep, val = 0;
318
319 if (sym < 16) {
320 lens[i++] = (u8)sym;
321 continue;
322 }
323 if (sym == 16) {
324 val = lens[i - 1];
325 rep = 3 + inf_bits(&s, 2);
326 } else if (sym == 17) {
327 rep = 3 + inf_bits(&s, 3);
328 } else {
329 rep = 11 + inf_bits(&s, 7);
330 }
331 while (rep--)
332 lens[i++] = (u8)val;
333 }
334 bench_inflate_table(&inf_lit, lens, hlit);
335 bench_inflate_table(&inf_dist, lens + hlit, hdist);
336 }
337 for (;;) {
338 u32 sym = inf_decode(&s, &inf_lit);
339
340 if (sym < 256) {
341 *o++ = (u8)sym;
342 } else if (sym == 256) {
343 break;
344 } else {
345 u32 len, dist;
346 const u8 *m;
347
348 sym -= 257;
349 len = inf_len_base[sym] + inf_bits(&s, inf_len_extra[sym]);
350 sym = inf_decode(&s, &inf_dist);
351 dist = inf_dist_base[sym] + inf_bits(&s, inf_dist_extra[sym]);
352 m = o - dist;
353 while (len--)
354 *o++ = *m++;
355 }
356 }
357 } while (!last);
358 return (u32)(o - out);
359}
360
361#define PARTICLES 1024
362
363static float px[PARTICLES], py[PARTICLES], pz[PARTICLES];
364static float vx[PARTICLES], vy[PARTICLES], vz[PARTICLES];
365
366static void init_particles(u32 seed)
367{
368 rng_state = seed;
369 for (u32 i = 0; i < PARTICLES; i++) {
370 px[i] = (float)(rng() & 15) - 8.0f;
371 py[i] = (float)(rng() & 15);
372 pz[i] = (float)(rng() & 15) - 8.0f;
373 vx[i] = (float)(rng() & 7) - 4.0f;
374 vy[i] = 0.0f;
375 vz[i] = (float)(rng() & 7) - 4.0f;
376 }
377}
378
379__attribute__((noinline)) static float bench_physics(u32 frames)
380{
381 float energy = 0.0f;
382 const float dt = 1.0f / 60.0f;
383
384 for (u32 f = 0; f < frames; f++) {
385 for (u32 i = 0; i < PARTICLES; i++) {
386 vy[i] -= 9.8f * dt;
387 px[i] += vx[i] * dt;
388 py[i] += vy[i] * dt;
389 pz[i] += vz[i] * dt;
390 if (py[i] < 0.0f) {
391 py[i] = -py[i];
392 vy[i] = -vy[i] * 0.8f;
393 }
394 float d2 = px[i] * px[i] + pz[i] * pz[i];
395 if (d2 > 100.0f) {
396 float inv = 1.0f / sqrtf(d2);
397 vx[i] = -px[i] * inv;
398 vz[i] = -pz[i] * inv;
399 }
400 }
401 }
402 for (u32 i = 0; i < PARTICLES; i++)
403 energy += vx[i] * vx[i] + vy[i] * vy[i] + vz[i] * vz[i];
404 return energy;
405}
406
407#define FB_W 128
408#define FB_H 128
409
410static u32 fb[FB_W * FB_H];
411
412__attribute__((noinline)) static void bench_raster(u32 triangles)
413{
414 for (u32 t = 0; t < triangles; t++) {
415 int x0 = (int)(rng() % FB_W), y0 = (int)(rng() % FB_H);
416 int x1 = (int)(rng() % FB_W), y1 = (int)(rng() % FB_H);
417 int x2 = (int)(rng() % FB_W), y2 = (int)(rng() % FB_H);
418 u32 color = rng();
419 int minx = x0 < x1 ? (x0 < x2 ? x0 : x2) : (x1 < x2 ? x1 : x2);
420 int maxx = x0 > x1 ? (x0 > x2 ? x0 : x2) : (x1 > x2 ? x1 : x2);
421 int miny = y0 < y1 ? (y0 < y2 ? y0 : y2) : (y1 < y2 ? y1 : y2);
422 int maxy = y0 > y1 ? (y0 > y2 ? y0 : y2) : (y1 > y2 ? y1 : y2);
423 int area = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0);
424
425 if (area == 0)
426 continue;
427 for (int y = miny; y <= maxy; y++) {
428 for (int x = minx; x <= maxx; x++) {
429 int w0 = (x1 - x0) * (y - y0) - (x - x0) * (y1 - y0);
430 int w1 = (x2 - x1) * (y - y1) - (x - x1) * (y2 - y1);
431 int w2 = (x0 - x2) * (y - y2) - (x - x2) * (y0 - y2);
432
433 if (area > 0 ? (w0 >= 0 && w1 >= 0 && w2 >= 0) : (w0 <= 0 && w1 <= 0 && w2 <= 0))
434 fb[y * FB_W + x] = color;
435 }
436 }
437 }
438}
439
440static char line[96];
441
442static void report(const char *name, u32 cyc, u32 sum)
443{
444 snprintf(line, sizeof(line), "bench %s %u %08x\n", name, cyc, sum);
445 kputs(line);
446 printf("%s", line);
447}
448
449#define TIMED_SETUP(name, setup, call, sum) \
450 do { \
451 u32 best = 0xffffffffu; \
452 for (int rep = 0; rep < 3; rep++) { \
453 setup; \
454 DIntr(); \
455 u32 t0 = cycles(); \
456 call; \
457 u32 t1 = cycles() - t0; \
458 EIntr(); \
459 if (t1 < best) \
460 best = t1; \
461 } \
462 report(name, best, sum); \
463 } while (0)
464
465#define TIMED(name, call, sum) TIMED_SETUP(name, (void)0, call, sum)
466
467int main(void)
468{
469 static u8 comp[16384], plain[65536];
470 static u64 packets[8192];
471 u32 comp_len;
472
473 for (u32 i = 0; i < BUF_BYTES; i++)
474 src_buf[i] = (u8)(i * 7 + (i >> 8));
475
476 TIMED("memcpy_mmi", bench_memcpy_mmi(dst_buf, src_buf, BUF_BYTES), checksum(dst_buf, BUF_BYTES));
477 memset(dst_buf, 0, sizeof(dst_buf));
478 TIMED("memcpy_libc", bench_memcpy_libc(dst_buf, src_buf, BUF_BYTES), checksum(dst_buf, BUF_BYTES));
479 memset(dst_buf, 0, sizeof(dst_buf));
480 TIMED("memcpy_loop", bench_memcpy_loop((u32 *)dst_buf, (const u32 *)src_buf, BUF_BYTES / 4), checksum(dst_buf, BUF_BYTES));
481 TIMED("memset_mmi", bench_memset_mmi(dst_buf, BUF_BYTES), checksum(dst_buf, BUF_BYTES));
482 TIMED("packet_build", bench_packet_build(packets, 2000), checksum(packets, 2000 * 32));
483
484 comp_len = make_compressed(comp);
485 TIMED("decompress", bench_decompress(plain, comp, comp_len), checksum(plain, 4096));
486 TIMED("inflate", bench_inflate(plain, inflate_in, sizeof(inflate_in)), checksum(plain, INFLATE_OUT_BYTES));
487
488 {
489 u32 seed = rng_state;
490 float e = 0.0f;
491 u32 bits;
492
493 TIMED_SETUP("physics", init_particles(seed), e = bench_physics(30), (memcpy(&bits, &e, sizeof(bits)), bits));
494 }
495 {
496 u32 seed = rng_state;
497
498 TIMED_SETUP("raster", rng_state = seed, bench_raster(200), checksum(fb, sizeof(fb)));
499 }
500
501 kputs("ee-bench: PASS\n");
502 printf("[ps2rig] exit=0\n");
503 SleepThread();
504 return 0;
505}
u32 count
start sector of fragmented bd/file