Skip to content

Commit ccd7b3d

Browse files
excelle08facebook-github-bot
authored andcommitted
Add memory-streaming stride-sweep to feature extractors (prod DRAM/LLC match)
Differential Revision: D114964801
1 parent 1615581 commit ccd7b3d

3 files changed

Lines changed: 110 additions & 0 deletions

File tree

packages/feedsim/third_party/src/workloads/ranking/feature_extractors/FeatureExtractorSuite.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include <iostream>
1010
#include <random>
1111

12+
#include "generated/extractor_helpers.h"
13+
1214
void FeatureExtractorSuite::addExtractor(
1315
std::unique_ptr<FeatureExtractorBase> extractor) {
1416
extractors_.push_back(std::move(extractor));
@@ -191,7 +193,15 @@ void FeatureExtractorSuite::runFlatExtractors(
191193
size_t start = flat_pos_.fetch_add(static_cast<size_t>(count),
192194
std::memory_order_relaxed) %
193195
total;
196+
// Memory-streaming lever: FEEDSIM_SWEEP_N reads per call over a large
197+
// read-only buffer, folded into live state so it can't be elided. No-op
198+
// when FEEDSIM_SWEEP_N=0. Hoist the enabled check out of the loop.
199+
const int sweep_n = dcperf::feature_extractors::helpers::sweepReadsPerCall();
194200
for (int i = 0; i < count; ++i) {
195201
flat_copies_[(start + static_cast<size_t>(i)) % total](&ctx);
202+
if (sweep_n > 0) {
203+
local_struct[0] += dcperf::feature_extractors::helpers::runStrideSweep(
204+
start + static_cast<size_t>(i));
205+
}
196206
}
197207
}

packages/feedsim/third_party/src/workloads/ranking/feature_extractors/generated/extractor_helpers.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55

66
#include "extractor_helpers.h"
77
#include <cmath>
8+
#include <cstdint>
9+
#include <cstdlib>
810
#include <cstring>
11+
#include <mutex>
12+
#include <vector>
913

1014
namespace dcperf {
1115
namespace feature_extractors {
@@ -280,6 +284,84 @@ float cappedConvertFloat(double value, float min_val, float max_val) {
280284
return result;
281285
}
282286

287+
// ======================================================================
288+
// Memory-streaming stride sweep (backend/DRAM-pressure lever)
289+
// ======================================================================
290+
291+
namespace {
292+
293+
struct SweepConfig {
294+
std::vector<float> buf; // process-wide, read-only after init
295+
size_t size = 0; // element count
296+
int n = 0; // reads per extractor call (FEEDSIM_SWEEP_N)
297+
size_t stride = 16; // element stride (FEEDSIM_SWEEP_STRIDE); 16 = 64B line
298+
};
299+
300+
SweepConfig g_sweep;
301+
std::once_flag g_sweep_once;
302+
303+
int envInt(const char* name, int fallback) {
304+
const char* v = std::getenv(name);
305+
if (v == nullptr || v[0] == '\0') {
306+
return fallback;
307+
}
308+
int parsed = std::atoi(v);
309+
return parsed;
310+
}
311+
312+
void initSweep() {
313+
// Defaults are the validated winning config (CPL/BGM/Grace, 2026-08-04):
314+
// 16 strided reads/call over a 64 MB DRAM-resident buffer at a 64 B (1 cache
315+
// line) stride. This closes most of the DRAM-bandwidth / LLC / L1-D / IPC gap
316+
// to prod (BGM mean uArch err 27%->18%, Grace 34%->23%). Override any knob via
317+
// the FEEDSIM_SWEEP_* env vars; set FEEDSIM_SWEEP_N=0 to disable entirely.
318+
int mb = envInt("FEEDSIM_SWEEP_MB", 64);
319+
if (mb < 1) {
320+
mb = 1;
321+
}
322+
g_sweep.n = envInt("FEEDSIM_SWEEP_N", 16);
323+
if (g_sweep.n < 0) {
324+
g_sweep.n = 0;
325+
}
326+
int stride = envInt("FEEDSIM_SWEEP_STRIDE", 16);
327+
g_sweep.stride = stride < 1 ? 1 : static_cast<size_t>(stride);
328+
g_sweep.size = static_cast<size_t>(mb) * 1024 * 1024 / sizeof(float);
329+
g_sweep.buf.resize(g_sweep.size);
330+
// Fill with pseudo-random data so the compiler can't fold the buffer away.
331+
uint64_t s = 0x9E3779B97F4A7C15ULL;
332+
for (size_t i = 0; i < g_sweep.size; ++i) {
333+
s = s * 6364136223846793005ULL + 1442695040888963407ULL;
334+
g_sweep.buf[i] = static_cast<float>((s >> 40) & 0xFFFF) * 1e-3f;
335+
}
336+
}
337+
338+
} // namespace
339+
340+
int sweepReadsPerCall() {
341+
std::call_once(g_sweep_once, initSweep);
342+
return g_sweep.n;
343+
}
344+
345+
float runStrideSweep(uint64_t seed) {
346+
const SweepConfig& c = g_sweep;
347+
if (c.n == 0 || c.size == 0) {
348+
return 0.0f;
349+
}
350+
// Rotate the start offset per call so successive calls cover the whole
351+
// buffer rather than re-touching one region (that was the flaw in the
352+
// earlier size-only bumps and the B3 random gather).
353+
size_t off = (seed * 2654435761ULL) % c.size;
354+
float acc = 0.0f;
355+
for (int i = 0; i < c.n; ++i) {
356+
acc += c.buf[off];
357+
off += c.stride;
358+
if (off >= c.size) {
359+
off -= c.size;
360+
}
361+
}
362+
return acc;
363+
}
364+
283365
} // namespace helpers
284366
} // namespace feature_extractors
285367
} // namespace dcperf

packages/feedsim/third_party/src/workloads/ranking/feature_extractors/generated/extractor_helpers.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,24 @@ bool validateFeatureValue(float value, int validation_type);
115115
__attribute__((noinline))
116116
float cappedConvertFloat(double value, float min_val, float max_val);
117117

118+
// ======================================================================
119+
// Memory-streaming stride sweep (backend/DRAM-pressure lever)
120+
// ======================================================================
121+
// Reads FEEDSIM_SWEEP_N elements, FEEDSIM_SWEEP_STRIDE floats apart, from a
122+
// process-wide read-only buffer of FEEDSIM_SWEEP_MB megabytes. Adds genuine
123+
// memory-level-parallelism / working-set pressure per extractor call to close
124+
// the backend-bound / DRAM-bandwidth gap vs prod. All three knobs are read
125+
// from the environment once, so one build sweeps the full parameter space;
126+
// FEEDSIM_SWEEP_N=0 (default) makes it a no-op. Returns FEEDSIM_SWEEP_N (cached
127+
// after first call, which initializes the buffer).
128+
int sweepReadsPerCall();
129+
130+
// Accumulate a strided walk seeded by `seed` (rotates the start offset so
131+
// successive calls cover the whole buffer). Caller folds the result into live
132+
// state to defeat dead-code elimination. Assumes sweepReadsPerCall() ran first.
133+
__attribute__((noinline))
134+
float runStrideSweep(uint64_t seed);
135+
118136
} // namespace helpers
119137
} // namespace feature_extractors
120138
} // namespace dcperf

0 commit comments

Comments
 (0)