Skip to main content

HOST_PROGRAM

Constant HOST_PROGRAM 

Source
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.