pub const HOST_PROGRAM: &str = r##"/* Measure the card's floating-point DSP block with the oracle persona: find the multiply's and the add's latencies
as the taps at which their classes come nearest every vector, the multiply-add's as the shift at which its results with
C zero are the products; then, the three aligned, record every vector's results and count each class's
disagreements over <steps> triples of the random stream and of the near stream. One JSON object on stdout.
logos_fp_oracle [<steps>] [--seed <n>] */
#include "logos_core.h"
#include "logos_fp_oracle.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef LOGOS_PROGRAM_MAIN
#define LOGOS_PROGRAM_MAIN main
#endif
static uint64_t tag = 1;
static int run(logos_dev *dev, uint8_t op, uint64_t a0, uint64_t a1, uint64_t a2) {
uint64_t t = tag++;
logos_record r = logos_core_run(dev, op, t, a0, a1, a2);
return (r.status >> 8) == t && (r.status & 0xff) == LOGOS_D5005_STATUS_OK;
}
/* A run's word: its source, whether it records every step, the soft tap, each block's delay. */
static uint64_t run_word(unsigned source, int record, unsigned tap, const unsigned d[3]) {
return source | (uint64_t)(record != 0) << 2 | (uint64_t)(tap & 15) << 4 | (uint64_t)(d[0] & 15) << 8 |
(uint64_t)(d[1] & 15) << 12 | (uint64_t)(d[2] & 15) << 16;
}
/* One run of `steps` triples, its store read into `buf`: the header and the counters, then the records the header
counts. */
static int oracle_run(logos_dev *dev, uint64_t *buf, uint64_t io, uint64_t word, uint64_t steps) {
if (!run(dev, LOGOS_D5005_OP_ENGINE_RUN, word, steps, 0)) return 0;
if (!run(dev, LOGOS_D5005_OP_STORE_READ, io >> 6, 0, LOGOS_FPO_RECORDS_AT)) return 0;
if (buf[0] != LOGOS_FPO_MAGIC || buf[6] != LOGOS_FPO_PRODUCTS || buf[7] != LOGOS_FPO_SUMS || buf[4] > LOGOS_FPO_RECORD_CAP) return 0;
return buf[4] == 0 || run(dev, LOGOS_D5005_OP_STORE_READ, (io >> 6) + LOGOS_FPO_RECORDS_AT, LOGOS_FPO_RECORDS_AT, buf[4]);
}
static uint64_t counter(const uint64_t *buf, unsigned k) { return buf[8 + k]; }
static uint64_t least(const uint64_t *buf, unsigned from, unsigned n) {
uint64_t m = UINT64_MAX;
for (unsigned k = 0; k < n; ++k) if (counter(buf, from + k) < m) m = counter(buf, from + k);
return m;
}
/* Record r's words: (B, A), (the product, C), (the multiply-add, the sum), the flags with the least-registered
multiply's result above them, the product classes' agreement in two words, the sum classes' with the
least-registered add's result above it. */
static const uint64_t *record(const uint64_t *buf, uint64_t r) { return buf + 8 * (LOGOS_FPO_RECORDS_AT + r); }
/* The 32 bits of word `word` of record `r` from bit `at`. */
static uint32_t field(const uint64_t *buf, uint64_t r, unsigned word, unsigned at) { return (uint32_t)(record(buf, r)[word] >> at); }
/* The shift s at which field `seen` of record k is, most often, field `want` of record k + s, over the records whose C
is zero when `c_zero` (over all otherwise); -1 when no shift matches more than half of them. A result recorded as it
leaves a block of latency L, the run at tap t, is that of the record t + 1 - L on. */
static int best_shift(const uint64_t *buf, const unsigned seen[2], const unsigned want[2], int c_zero, uint64_t *best, uint64_t *n) {
int shift = -1;
*best = 0;
*n = 0;
for (unsigned s = 0; s < LOGOS_FPO_TAPS; ++s) {
uint64_t matches = 0, of = 0;
for (uint64_t k = 0; k + s < buf[4]; ++k) {
if (c_zero && field(buf, k + s, 1, 0) != 0) continue;
++of;
if (field(buf, k, seen[0], seen[1]) == field(buf, k + s, want[0], want[1])) ++matches;
}
if (matches > *best) *best = matches, *n = of, shift = (int)s;
}
return shift >= 0 && 2 * *best > *n ? shift : -1;
}
static void counters(const uint64_t *buf, const char *name) {
printf(" \"%s\": {\"steps\": %" PRIu64 ", \"lone_products\": %" PRIu64 ", \"lone_sums\": %" PRIu64 ", \"records\": %" PRIu64 ",\n",
name, buf[1], buf[2], buf[3], buf[4]);
printf(" \"products\": [");
for (unsigned k = 0; k < LOGOS_FPO_PRODUCTS; ++k) printf("%s%" PRIu64, k ? ", " : "", counter(buf, k));
printf("],\n \"sums\": [");
for (unsigned k = 0; k < LOGOS_FPO_SUMS; ++k) printf("%s%" PRIu64, k ? ", " : "", counter(buf, LOGOS_FPO_PRODUCTS + k));
printf("]}");
}
static void records(const uint64_t *buf) {
printf(" \"records\": [");
for (uint64_t r = 0; r < buf[4]; ++r) {
const uint64_t *w = record(buf, r);
printf("%s\n [\"%08" PRIx32 "\", \"%08" PRIx32 "\", \"%08" PRIx32 "\", \"%08" PRIx32 "\", \"%08" PRIx32 "\", \"%08" PRIx32 "\", \"%06" PRIx32 "\", \"%08" PRIx32 "\", \"%08" PRIx32 "\"]",
r ? "," : "", (uint32_t)w[0], (uint32_t)(w[0] >> 32), (uint32_t)w[1], (uint32_t)(w[1] >> 32), (uint32_t)w[2],
(uint32_t)(w[2] >> 32), (uint32_t)(w[3] & 0xffffff), (uint32_t)(w[3] >> 24), (uint32_t)(w[7] >> 32));
}
printf("]");
}
int LOGOS_PROGRAM_MAIN(int argc, char **argv) {
uint64_t steps = 1ull << 24, seed = 0x5eedf00du;
for (int i = 1; i < argc; ++i) {
if (strcmp(argv[i], "--seed") == 0 && i + 1 < argc) seed = strtoull(argv[++i], NULL, 0);
else steps = strtoull(argv[i], NULL, 0);
}
logos_dev *dev = logos_open(LOGOS_D5005_AFU_ID);
if (!dev) {
fprintf(stderr, "logos_fp_oracle: no card\n");
return 2;
}
uint64_t io = 0;
uint64_t *buf = logos_buffer(dev, (size_t)LOGOS_FPO_STORE_BEATS * 64, &io);
memset(buf, 0, (size_t)LOGOS_FPO_STORE_BEATS * 64);
buf[0] = seed;
int ok = run(dev, LOGOS_D5005_OP_ENGINE_TABLE, io >> 6, 0, 1);
const unsigned none[3] = {0, 0, 0};
int tm = -1, ta = -1, lf = -1;
uint64_t pmin = UINT64_MAX, smin = UINT64_MAX;
printf("{\n \"seed\": %" PRIu64 ",\n \"taps\": [", seed);
for (unsigned t = 0; ok && t < LOGOS_FPO_TAPS; ++t) {
ok = oracle_run(dev, buf, io, run_word(0, 0, t, none), LOGOS_FPO_VECTORS);
uint64_t p = ok ? least(buf, 0, LOGOS_FPO_PRODUCTS) : UINT64_MAX, s = ok ? least(buf, LOGOS_FPO_PRODUCTS, LOGOS_FPO_SUMS) : UINT64_MAX;
printf("%s{\"tap\": %u, \"least_product\": %" PRIu64 ", \"least_sum\": %" PRIu64 "}", t ? ", " : "", t, p, s);
if (ok && p < pmin) pmin = p, tm = (int)t;
if (ok && s < smin) smin = s, ta = (int)t;
}
printf("],\n");
/* The multiply-add's results at the last tap undelayed: the shift at which they are the products of the triples
whose C is zero. */
uint64_t fbest = 0, fn = 0, mbest = 0, mn = 0, abest = 0, an = 0;
const unsigned fma_at[2] = {2, 32}, product_at[2] = {1, 32}, sum_at[2] = {2, 0}, least_product[2] = {3, 24}, least_sum[2] = {7, 32};
if (ok && tm >= 0 && ta >= 0) {
const unsigned d[3] = {15u - (unsigned)tm, 15u - (unsigned)ta, 0};
ok = oracle_run(dev, buf, io, run_word(0, 1, 15, d), LOGOS_FPO_VECTORS);
int s = ok ? best_shift(buf, fma_at, product_at, 1, &fbest, &fn) : -1;
if (s >= 0) lf = 16 - s;
}
int found = tm >= 0 && ta >= 0 && lf > 0, lm1 = -1, la1 = -1;
unsigned tap = 0, d[3] = {0, 0, 0};
if (ok && found) {
int l[3] = {tm + 1, ta + 1, lf};
int top = l[0] > l[1] ? l[0] : l[1];
top = top > l[2] ? top : l[2];
tap = (unsigned)(top - 1);
for (int k = 0; k < 3; ++k) d[k] = tap + 1 - (unsigned)l[k];
ok = oracle_run(dev, buf, io, run_word(0, 1, tap, d), LOGOS_FPO_VECTORS);
/* The least-registered blocks' results as they leave them: the shift at which they are the aligned ones'. */
int sm = ok ? best_shift(buf, least_product, product_at, 0, &mbest, &mn) : -1, sa = ok ? best_shift(buf, least_sum, sum_at, 0, &abest, &an) : -1;
if (sm >= 0) lm1 = (int)tap + 1 - sm;
if (sa >= 0) la1 = (int)tap + 1 - sa;
}
printf(" \"latency\": {\"product\": %d, \"sum\": %d, \"multiply_add\": %d, \"product_least\": %d, \"sum_least\": %d,\n", tm + 1, ta + 1, lf, lm1, la1);
printf(" \"matches\": {\"multiply_add\": [%" PRIu64 ", %" PRIu64 "], \"product_least\": [%" PRIu64 ", %" PRIu64 "], \"sum_least\": [%" PRIu64 ", %" PRIu64 "]}},\n",
fbest, fn, mbest, mn, abest, an);
printf(" \"runs\": {\n");
if (ok && found) {
counters(buf, "vectors");
printf(",\n");
records(buf);
const char *names[2] = {"random", "near"};
for (unsigned source = 1; ok && source <= 2; ++source) {
ok = oracle_run(dev, buf, io, run_word(source, 0, tap, d), steps);
if (ok) {
printf(",\n");
counters(buf, names[source - 1]);
}
}
printf("\n },\n \"run_word\": %" PRIu64 ",\n", run_word(0, 0, tap, d));
} else {
printf("\n },\n");
}
printf(" \"complete\": %s\n}\n", ok ? "true" : "false");
logos_buffer_free(dev, buf);
logos_close(dev);
return !ok ? 2 : !found ? 1 : 0;
}
"##;Expand description
The measurement on the card (sw/logos_fp_oracle.c): the multiply’s and the add’s latencies as the taps at which
their classes come nearest every vector (counting runs over the vectors at each tap, no delay: the first tap of the
fewest disagreements, so a block no class names still has its depth); the multiply-add’s as
the shift at which its results on the vectors whose C is zero are the products (a recording run at the last tap);
then, the three aligned (Run::aligned), a recording run over the vectors and counting runs of <steps> triples
from the random and the near streams; one JSON object on stdout. The exit status is 0 when every latency was found
and every run completed, 1 when a latency was not, 2 when the card cannot be had or a command failed.