File size: 6,675 Bytes
bbb6388 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | // src/core/load_main.cpp - `strata-load`: the expert arena load, measurable at any scale.
//
// P2.S1 gives this a target (<= 60 s cold, <= 10 s warm for 33.97 GB) and a method (8 threads, 16 MB chunks,
// a checksum per layer). The size is a FLAG rather than hard-coded because the honest way to measure a 34 GB
// load is to measure a smaller one first and project - and because pinning 34 GB evicts every page of page
// cache on the machine, which is not something a test should do while other work is running.
#include "strata/core/pinned.hpp"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
int main(int argc, char** argv) {
std::string path;
uint64_t layers = 2;
int threads = 8;
uint64_t chunk = 16ull << 20;
uint64_t blob_bytes = 1382400; // architecture §3.2, asserted by tools/pack_layer.py
uint64_t blobs_per_layer = 512;
bool pin = true;
bool stream = false;
for (int i = 1; i < argc; ++i) {
const std::string a = argv[i];
auto val = [&]() -> const char* {
if (i + 1 >= argc) { std::fprintf(stderr, "%s needs a value\n", a.c_str()); std::exit(2); }
return argv[++i];
};
if (a == "--file") path = val();
else if (a == "--layers") layers = std::strtoull(val(), nullptr, 10);
else if (a == "--threads") threads = std::atoi(val());
else if (a == "--chunk-mb") chunk = std::strtoull(val(), nullptr, 10) << 20;
else if (a == "--no-pin") pin = false;
else if (a == "--stream") stream = true;
else if (a == "--help" || a == "-h") {
std::printf("usage: strata-load --file experts.bin [--layers N] [--threads N] [--chunk-mb N]\n"
" [--no-pin]\n");
return 0;
} else {
std::fprintf(stderr, "unknown argument: %s\n", a.c_str());
return 2;
}
}
if (path.empty()) { std::fprintf(stderr, "--file is required\n"); return 2; }
const uint64_t bytes = layers * blobs_per_layer * blob_bytes;
std::printf("expert arena: %llu layers x %llu blobs x %llu B = %.3f GiB\n", (unsigned long long) layers,
(unsigned long long) blobs_per_layer, (unsigned long long) blob_bytes,
(double) bytes / (1024.0 * 1024 * 1024));
strata::core::PinnedArena arena;
uint8_t* dst = nullptr;
if (pin) {
// constructed in place so the note from the constructor can be printed before the load
new (&arena) strata::core::PinnedArena(bytes);
std::printf("backing: %s\n", arena.note.c_str());
if (!arena.valid()) { std::fprintf(stderr, "arena allocation failed\n"); return 1; }
dst = arena.data();
} else {
dst = (uint8_t*) std::malloc((size_t) bytes);
if (!dst) { std::fprintf(stderr, "malloc failed\n"); return 1; }
std::printf("backing: malloc, NOT pinned (--no-pin)\n");
}
const strata::core::LoadStats st =
strata::core::load_experts(path, dst, blob_bytes, blobs_per_layer, layers, threads, chunk);
if (!st.ok) {
std::fprintf(stderr, "loading the experts failed: %s\n", st.error.empty() ? "unknown" : st.error.c_str());
return 1;
}
std::printf("loaded %.3f GiB in %.3f s with %d threads and %llu MiB chunks -> %.2f GiB/s\n",
(double) st.bytes / (1024.0 * 1024 * 1024), st.seconds, threads,
(unsigned long long) (chunk >> 20), st.gib_per_second());
std::printf("per-layer checksums (FNV-1a 64):\n");
for (size_t i = 0; i < st.layer_checksums.size() && i < 4; ++i) {
std::printf(" layer %zu %016llx\n", i, (unsigned long long) st.layer_checksums[i]);
}
if (st.layer_checksums.size() > 4) {
std::printf(" ... %zu more (all layers loaded)\n", st.layer_checksums.size() - 4);
}
if (stream) {
// The bus is the ceiling, so measure it at the granularity the engine actually uses. Printed as a
// sweep rather than one number because "bandwidth" without a transfer size is not a specification.
std::printf("\nexpert stream over the pinned arena (host -> device, one reused destination):\n");
const uint64_t granularities[] = {blob_bytes, 16 * blob_bytes, 512 * blob_bytes, bytes};
const char* names[] = {"1 blob (1.38 MB)", "16 blobs (22 MB)", "1 layer (707 MB)", "whole arena"};
for (int i = 0; i < 4; ++i) {
const uint64_t g = granularities[i];
if (g > bytes) continue;
const int iters = (int) (g >= bytes ? 3 : (bytes / g >= 8 ? 8 : 3));
const strata::core::StreamStats ss =
strata::core::stream_bandwidth(dst, (bytes / g) * g, g, iters);
if (ss.seconds < 0) continue;
std::printf(" %-18s chunk %8.2f MB %6.2f GB/s (%.3f GiB in %.3f s)\n", names[i],
(double) g / 1e6, ss.gib_per_second() * 1.073741824,
(double) ss.bytes / (1024.0 * 1024 * 1024), ss.seconds);
}
// And what it means, using the design's own constants, stated with the assumption attached.
const double best = 60.0; // GB/s, replaced below by the measured best if it is larger
(void) best;
std::printf("\nper-token expert stream at E = 663.6 MB and hit rate h (VRAM-resident fraction):\n");
std::printf(" %-8s %-14s %-14s %s\n", "h", "miss MB/token", "ms at 1 blob", "tok/s ceiling");
const strata::core::StreamStats one = strata::core::stream_bandwidth(dst, blob_bytes, blob_bytes, 64);
for (double h : {0.0, 0.5, 0.833, 0.9, 0.95}) {
const double miss_mb = (1.0 - h) * 663.6;
const double ms = miss_mb / 1000.0 / (one.gib_per_second() * 1.073741824) * 1000.0;
std::printf(" %-8.3f %-14.1f %-14.2f %.1f\n", h, miss_mb, ms, ms > 0 ? 1000.0 / ms : 0.0);
}
std::printf(" h = 0.167 is the design's constant; h = 0.833 is its complement, shown because the\n"
" plan's E = 663.6 MB is the FULL expert set per token, so which fraction is cached is\n"
" the question the number hinges on.\n");
}
// The projection is the number the phase's <= 60 s target is about, and it is printed as a projection
// rather than as the result, because at --layers 2 this program has NOT loaded 33.97 GB.
const double full = 33973862400.0;
std::printf("projection for the full %.2f GiB at this rate: %.1f s\n", full / (1024.0 * 1024 * 1024),
full / (1024.0 * 1024 * 1024) / (st.gib_per_second() > 0 ? st.gib_per_second() : 1e-9));
return 0;
}
|