==> src/occupancy.c <==1/* backend.rs's co_resident and room. */
2#include "mesh/occupancy.h"
3#include "mesh/text.h"
4
5#include <stdlib.h>
6#include <string.h>
7
8bool mesh_co_resident(const mesh_occ_kernel *k, size_t n, uint32_t sms, uint32_t blocks_per_sm, char **err) {
9 uint32_t blocks = 0, whole = 0, small = 0;
10 double share = 0;
11 for (size_t i = 0; i < n; i++) {
12 uint32_t nodes = k[i].nodes, per_sm = k[i].per_sm;
13 if (per_sm == 0 || nodes > per_sm * sms)
14 return mesh_errf(err, "%u blocks; its occupancy allows %u per SM x %u SMs", (unsigned)nodes, (unsigned)per_sm, (unsigned)sms);
15 blocks += nodes;
16 share += (double)nodes / (double)(per_sm * sms);
17 if (per_sm == 1) whole += nodes;
18 else small += nodes;
19 }
20 if (blocks > blocks_per_sm * sms)
21 return mesh_errf(err, "%u resident blocks > %u per SM x %u SMs", (unsigned)blocks, (unsigned)blocks_per_sm, (unsigned)sms);
22 if (share > 1.0 + 1e-9) {
23 /* Rust's {:.0}: round half to even, as printf's %.0f. */
24 return mesh_errf(err, "the loaded kernels would need %.0f%% of the SMs' resident capacity", share * 100.0);
25 }
26 uint32_t spread = small < sms ? small : sms;
27 if (whole > 0 && whole + spread > sms)
28 return mesh_errf(err, "%u node(s) that each need a whole SM, and %u other block(s) that may occupy %u SMs, on %u SMs",
29 (unsigned)whole, (unsigned)small, (unsigned)spread, (unsigned)sms);
30 return true;
31}
32
33uint32_t mesh_occ_room(const mesh_occ_kernel *others, size_t n, uint32_t per_sm, uint32_t max, uint32_t sms, uint32_t blocks_per_sm) {
34 mesh_occ_kernel *k = mesh_alloc((n + 1) * sizeof *k);
35 if (n) memcpy(k, others, n * sizeof *k);
36 k[n] = (mesh_occ_kernel){0, per_sm};
37 uint32_t got = 0;
38 while (got < max) {
39 k[n].nodes = got + 1;
40 if (!mesh_co_resident(k, n + 1, sms, blocks_per_sm, NULL)) break;
41 got++;
42 }
43 free(k);
44 return got;
45}