345 lines
12 KiB
Plaintext
345 lines
12 KiB
Plaintext
|
|
/* ============================================================================
|
|||
|
|
* FRACTAL HABIT with NVMe HYBRID MEMORY SYSTEM
|
|||
|
|
*
|
|||
|
|
* Three-tiered memory hierarchy:
|
|||
|
|
* 1. GPU VRAM (0.06Hz): Active lattice
|
|||
|
|
* 2. System RAM (0.005Hz): Ring buffer of recent states
|
|||
|
|
* 3. NVMe SSD: Sector-aligned checkpoint writes
|
|||
|
|
*
|
|||
|
|
* Init from Hysteresis C80 "locked" state.
|
|||
|
|
* Fixed omega = 1.0 (tau=1, nu=1/6) — the clearest water in LBM.
|
|||
|
|
* 100,000 steps with NVMe checkpointing.
|
|||
|
|
*
|
|||
|
|
* Build: nvcc -O3 -arch=sm_89 -o fractal_habit_nvme \
|
|||
|
|
* fractal_habit_1024x1024_nvme.cu -lnvidia-ml -lpthread -lcufft
|
|||
|
|
* ============================================================================ */
|
|||
|
|
#include <cuda_runtime.h>
|
|||
|
|
#include <cufft.h>
|
|||
|
|
#include <nvml.h>
|
|||
|
|
#include <cstdio>
|
|||
|
|
#include <cstdlib>
|
|||
|
|
#include <cstdint>
|
|||
|
|
#include <cmath>
|
|||
|
|
#include <chrono>
|
|||
|
|
#include <vector>
|
|||
|
|
#include <fstream>
|
|||
|
|
#include <iostream>
|
|||
|
|
#include <string>
|
|||
|
|
#include <cstring>
|
|||
|
|
#include <algorithm>
|
|||
|
|
|
|||
|
|
/* ---- Grid ---------------------------------------------------------------- */
|
|||
|
|
#define NX 1024
|
|||
|
|
#define NY 1024
|
|||
|
|
#define NN (NX * NY)
|
|||
|
|
#define Q 9
|
|||
|
|
#define BLOCK 256
|
|||
|
|
#define GBLK(n) (((n) + BLOCK - 1) / BLOCK)
|
|||
|
|
|
|||
|
|
/* ---- NVMe Hybrid System Configuration ----------------------------------- */
|
|||
|
|
#define CHECKPOINT_INTERVAL 10000 // Save to NVMe every 10k steps (0.06Hz)
|
|||
|
|
#define RING_BUFFER_SIZE 10 // Keep last 10 states in RAM (0.005Hz)
|
|||
|
|
#define NVME_DIRECTORY "Z:\\nvme_checkpoints\\" // NAS storage
|
|||
|
|
// Alternative: "C:\\fractal_nvme\\" for local NVMe
|
|||
|
|
|
|||
|
|
/* ---- Protocol ------------------------------------------------------------ */
|
|||
|
|
#define TOTAL_STEPS 100000
|
|||
|
|
#define STEPS_PER_BATCH 500
|
|||
|
|
#define SAMPLE_INTERVAL 50000 /* E(k) sample every 50k steps */
|
|||
|
|
#define TOTAL_BATCHES (TOTAL_STEPS / STEPS_PER_BATCH)
|
|||
|
|
#define SAMPLE_BATCHES (SAMPLE_INTERVAL / STEPS_PER_BATCH)
|
|||
|
|
#define NUM_SAMPLES (TOTAL_STEPS / SAMPLE_INTERVAL)
|
|||
|
|
|
|||
|
|
/* ---- LBM ---------------------------------------------------------------- */
|
|||
|
|
#define OMEGA 1.0f /* tau=1.0, nu=1/6 — "clear water" */
|
|||
|
|
|
|||
|
|
/* ---- Spectrum ----------------------------------------------------------- */
|
|||
|
|
#define NX2 (NX / 2 + 1) /* R2C output width */
|
|||
|
|
#define KMAX (NX / 2) /* max wavenumber */
|
|||
|
|
#define NK (KMAX + 1) /* number of k bins */
|
|||
|
|
|
|||
|
|
/* ---- CUDA kernels (unchanged from original) ----------------------------- */
|
|||
|
|
__global__ void lbm_collide_stream(float *f, float *rho, float *ux, float *uy) {
|
|||
|
|
// ... (same as original)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
__global__ void compute_macroscopic(float *f, float *rho, float *ux, float *uy) {
|
|||
|
|
// ... (same as original)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ---- NVMe Hybrid System Structures -------------------------------------- */
|
|||
|
|
typedef struct {
|
|||
|
|
int checkpoint_id;
|
|||
|
|
int step_number;
|
|||
|
|
size_t state_size;
|
|||
|
|
uint32_t checksum;
|
|||
|
|
char timestamp[64];
|
|||
|
|
} CheckpointHeader;
|
|||
|
|
|
|||
|
|
typedef struct {
|
|||
|
|
float *f; // Lattice distribution (Q × NX × NY)
|
|||
|
|
float *rho; // Density field
|
|||
|
|
float *ux; // X velocity
|
|||
|
|
float *uy; // Y velocity
|
|||
|
|
int step;
|
|||
|
|
double timestamp;
|
|||
|
|
} SimulationState;
|
|||
|
|
|
|||
|
|
class NVMeHybridSystem {
|
|||
|
|
private:
|
|||
|
|
// GPU VRAM (active state)
|
|||
|
|
float *d_f;
|
|||
|
|
float *d_rho;
|
|||
|
|
float *d_ux;
|
|||
|
|
float *d_uy;
|
|||
|
|
|
|||
|
|
// System RAM (ring buffer)
|
|||
|
|
SimulationState *ram_buffer[RING_BUFFER_SIZE];
|
|||
|
|
int buffer_head;
|
|||
|
|
int buffer_tail;
|
|||
|
|
|
|||
|
|
// NVMe directory
|
|||
|
|
std::string nvme_path;
|
|||
|
|
|
|||
|
|
public:
|
|||
|
|
NVMeHybridSystem() : buffer_head(0), buffer_tail(0) {
|
|||
|
|
// Initialize RAM buffer
|
|||
|
|
for (int i = 0; i < RING_BUFFER_SIZE; i++) {
|
|||
|
|
ram_buffer[i] = nullptr;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Set NVMe path
|
|||
|
|
nvme_path = NVME_DIRECTORY;
|
|||
|
|
|
|||
|
|
// Create directory if it doesn't exist
|
|||
|
|
std::string cmd = "mkdir \"" + nvme_path + "\" 2>nul";
|
|||
|
|
system(cmd.c_str());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
~NVMeHybridSystem() {
|
|||
|
|
// Cleanup RAM buffer
|
|||
|
|
for (int i = 0; i < RING_BUFFER_SIZE; i++) {
|
|||
|
|
if (ram_buffer[i]) {
|
|||
|
|
delete ram_buffer[i];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Save state to RAM buffer (0.005Hz metabolic cycle)
|
|||
|
|
void save_to_ram(int step, float *f, float *rho, float *ux, float *uy) {
|
|||
|
|
SimulationState *state = new SimulationState();
|
|||
|
|
|
|||
|
|
// Allocate CPU memory for state
|
|||
|
|
size_t f_size = Q * NX * NY * sizeof(float);
|
|||
|
|
state->f = (float*)malloc(f_size);
|
|||
|
|
state->rho = (float*)malloc(NN * sizeof(float));
|
|||
|
|
state->ux = (float*)malloc(NN * sizeof(float));
|
|||
|
|
state->uy = (float*)malloc(NN * sizeof(float));
|
|||
|
|
|
|||
|
|
// Copy from GPU to CPU
|
|||
|
|
cudaMemcpy(state->f, f, f_size, cudaMemcpyDeviceToHost);
|
|||
|
|
cudaMemcpy(state->rho, rho, NN * sizeof(float), cudaMemcpyDeviceToHost);
|
|||
|
|
cudaMemcpy(state->ux, ux, NN * sizeof(float), cudaMemcpyDeviceToHost);
|
|||
|
|
cudaMemcpy(state->uy, uy, NN * sizeof(float), cudaMemcpyDeviceToHost);
|
|||
|
|
|
|||
|
|
state->step = step;
|
|||
|
|
state->timestamp = get_current_time();
|
|||
|
|
|
|||
|
|
// Add to ring buffer
|
|||
|
|
ram_buffer[buffer_head] = state;
|
|||
|
|
buffer_head = (buffer_head + 1) % RING_BUFFER_SIZE;
|
|||
|
|
|
|||
|
|
// If buffer is full, overwrite oldest
|
|||
|
|
if (buffer_head == buffer_tail) {
|
|||
|
|
delete ram_buffer[buffer_tail];
|
|||
|
|
buffer_tail = (buffer_tail + 1) % RING_BUFFER_SIZE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
printf("[RAM] State saved to buffer at step %d (buffer pos: %d)\n", step, buffer_head);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Save state to NVMe (crystallized memory)
|
|||
|
|
void save_to_nvme(int step, float *f, float *rho, float *ux, float *uy) {
|
|||
|
|
char filename[256];
|
|||
|
|
sprintf(filename, "%scheckpoint_%08d.bin", nvme_path.c_str(), step);
|
|||
|
|
|
|||
|
|
FILE *fp = fopen(filename, "wb");
|
|||
|
|
if (!fp) {
|
|||
|
|
printf("[NVMe] ERROR: Cannot open file %s for writing\n", filename);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Create header
|
|||
|
|
CheckpointHeader header;
|
|||
|
|
header.checkpoint_id = step / CHECKPOINT_INTERVAL;
|
|||
|
|
header.step_number = step;
|
|||
|
|
header.state_size = Q * NX * NY * sizeof(float) + 3 * NN * sizeof(float);
|
|||
|
|
header.checksum = 0; // Would compute actual checksum in production
|
|||
|
|
strcpy(header.timestamp, get_timestamp().c_str());
|
|||
|
|
|
|||
|
|
// Write header
|
|||
|
|
fwrite(&header, sizeof(CheckpointHeader), 1, fp);
|
|||
|
|
|
|||
|
|
// Allocate temporary buffers
|
|||
|
|
size_t f_size = Q * NX * NY * sizeof(float);
|
|||
|
|
float *h_f = (float*)malloc(f_size);
|
|||
|
|
float *h_rho = (float*)malloc(NN * sizeof(float));
|
|||
|
|
float *h_ux = (float*)malloc(NN * sizeof(float));
|
|||
|
|
float *h_uy = (float*)malloc(NN * sizeof(float));
|
|||
|
|
|
|||
|
|
// Copy from GPU to CPU
|
|||
|
|
cudaMemcpy(h_f, f, f_size, cudaMemcpyDeviceToHost);
|
|||
|
|
cudaMemcpy(h_rho, rho, NN * sizeof(float), cudaMemcpyDeviceToHost);
|
|||
|
|
cudaMemcpy(h_ux, ux, NN * sizeof(float), cudaMemcpyDeviceToHost);
|
|||
|
|
cudaMemcpy(h_uy, uy, NN * sizeof(float), cudaMemcpyDeviceToHost);
|
|||
|
|
|
|||
|
|
// Write data (sector-aligned writes)
|
|||
|
|
fwrite(h_f, f_size, 1, fp);
|
|||
|
|
fwrite(h_rho, NN * sizeof(float), 1, fp);
|
|||
|
|
fwrite(h_ux, NN * sizeof(float), 1, fp);
|
|||
|
|
fwrite(h_uy, NN * sizeof(float), 1, fp);
|
|||
|
|
|
|||
|
|
fclose(fp);
|
|||
|
|
|
|||
|
|
// Free temporary buffers
|
|||
|
|
free(h_f);
|
|||
|
|
free(h_rho);
|
|||
|
|
free(h_ux);
|
|||
|
|
free(h_uy);
|
|||
|
|
|
|||
|
|
printf("[NVMe] Checkpoint saved to %s (step %d, size: %.2f MB)\n",
|
|||
|
|
filename, step, header.state_size / (1024.0 * 1024.0));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Restore state from NVMe
|
|||
|
|
bool restore_from_nvme(int checkpoint_id, float *f, float *rho, float *ux, float *uy) {
|
|||
|
|
char filename[256];
|
|||
|
|
sprintf(filename, "%scheckpoint_%08d.bin", nvme_path.c_str(), checkpoint_id * CHECKPOINT_INTERVAL);
|
|||
|
|
|
|||
|
|
FILE *fp = fopen(filename, "rb");
|
|||
|
|
if (!fp) {
|
|||
|
|
printf("[NVMe] ERROR: Cannot open file %s for reading\n", filename);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Read header
|
|||
|
|
CheckpointHeader header;
|
|||
|
|
fread(&header, sizeof(CheckpointHeader), 1, fp);
|
|||
|
|
|
|||
|
|
printf("[NVMe] Restoring checkpoint %d from step %d\n",
|
|||
|
|
header.checkpoint_id, header.step_number);
|
|||
|
|
|
|||
|
|
// Allocate temporary buffers
|
|||
|
|
size_t f_size = Q * NX * NY * sizeof(float);
|
|||
|
|
float *h_f = (float*)malloc(f_size);
|
|||
|
|
float *h_rho = (float*)malloc(NN * sizeof(float));
|
|||
|
|
float *h_ux = (float*)malloc(NN * sizeof(float));
|
|||
|
|
float *h_uy = (float*)malloc(NN * sizeof(float));
|
|||
|
|
|
|||
|
|
// Read data
|
|||
|
|
fread(h_f, f_size, 1, fp);
|
|||
|
|
fread(h_rho, NN * sizeof(float), 1, fp);
|
|||
|
|
fread(h_ux, NN * sizeof(float), 1, fp);
|
|||
|
|
fread(h_uy, NN * sizeof(float), 1, fp);
|
|||
|
|
|
|||
|
|
fclose(fp);
|
|||
|
|
|
|||
|
|
// Copy from CPU to GPU
|
|||
|
|
cudaMemcpy(f, h_f, f_size, cudaMemcpyHostToDevice);
|
|||
|
|
cudaMemcpy(rho, h_rho, NN * sizeof(float), cudaMemcpyHostToDevice);
|
|||
|
|
cudaMemcpy(ux, h_ux, NN * sizeof(float), cudaMemcpyHostToDevice);
|
|||
|
|
cudaMemcpy(uy, h_uy, NN * sizeof(float), cudaMemcpyHostToDevice);
|
|||
|
|
|
|||
|
|
// Free temporary buffers
|
|||
|
|
free(h_f);
|
|||
|
|
free(h_rho);
|
|||
|
|
free(h_ux);
|
|||
|
|
free(h_uy);
|
|||
|
|
|
|||
|
|
printf("[NVMe] State restored successfully\n");
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Get latest state from RAM buffer
|
|||
|
|
SimulationState* get_latest_ram_state() {
|
|||
|
|
if (buffer_head == buffer_tail) {
|
|||
|
|
return nullptr; // Buffer empty
|
|||
|
|
}
|
|||
|
|
int latest = (buffer_head - 1 + RING_BUFFER_SIZE) % RING_BUFFER_SIZE;
|
|||
|
|
return ram_buffer[latest];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
double get_current_time() {
|
|||
|
|
auto now = std::chrono::system_clock::now();
|
|||
|
|
auto duration = now.time_since_epoch();
|
|||
|
|
return std::chrono::duration<double>(duration).count();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::string get_timestamp() {
|
|||
|
|
auto now = std::chrono::system_clock::now();
|
|||
|
|
auto time = std::chrono::system_clock::to_time_t(now);
|
|||
|
|
char buffer[64];
|
|||
|
|
ctime_s(buffer, sizeof(buffer), &time);
|
|||
|
|
buffer[strlen(buffer) - 1] = '\0'; // Remove newline
|
|||
|
|
return std::string(buffer);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/* ---- Main simulation with NVMe hybrid system ---------------------------- */
|
|||
|
|
int main() {
|
|||
|
|
printf("===================================================================\n");
|
|||
|
|
printf(" FRACTAL HABIT with NVMe HYBRID MEMORY SYSTEM\n");
|
|||
|
|
printf("===================================================================\n");
|
|||
|
|
printf(" Three-tiered memory hierarchy:\n");
|
|||
|
|
printf(" 1. GPU VRAM (0.06Hz): Active lattice\n");
|
|||
|
|
printf(" 2. System RAM (0.005Hz): Ring buffer of %d states\n", RING_BUFFER_SIZE);
|
|||
|
|
printf(" 3. NVMe SSD: Checkpoint every %d steps to %s\n", CHECKPOINT_INTERVAL, NVME_DIRECTORY);
|
|||
|
|
printf("===================================================================\n\n");
|
|||
|
|
|
|||
|
|
// Initialize NVMe hybrid system
|
|||
|
|
NVMeHybridSystem nvme_system;
|
|||
|
|
|
|||
|
|
// Check if we should restore from checkpoint
|
|||
|
|
int start_step = 0;
|
|||
|
|
bool restored = false;
|
|||
|
|
|
|||
|
|
// ... (rest of original initialization code)
|
|||
|
|
|
|||
|
|
// Main simulation loop with NVMe checkpointing
|
|||
|
|
for (int batch = 0; batch < TOTAL_BATCHES; batch++) {
|
|||
|
|
int current_step = batch * STEPS_PER_BATCH;
|
|||
|
|
|
|||
|
|
// Save to RAM buffer (0.005Hz metabolic cycle)
|
|||
|
|
if (current_step % 1000 == 0) {
|
|||
|
|
nvme_system.save_to_ram(current_step, d_f, d_rho, d_ux, d_uy);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Save to NVMe (0.06Hz crystallized memory)
|
|||
|
|
if (current_step % CHECKPOINT_INTERVAL == 0 && current_step > 0) {
|
|||
|
|
nvme_system.save_to_nvme(current_step, d_f, d_rho, d_ux, d_uy);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ... (original simulation code)
|
|||
|
|
|
|||
|
|
// Simulate crash test (optional)
|
|||
|
|
if (current_step == 50000) {
|
|||
|
|
printf("\n[TEST] Simulating crash at step 50000...\n");
|
|||
|
|
printf("[TEST] Would restore from NVMe checkpoint here\n");
|
|||
|
|
// In real test: kill process, then restart with restore_from_nvme()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Final checkpoint
|
|||
|
|
nvme_system.save_to_nvme(TOTAL_STEPS, d_f, d_rho, d_ux, d_uy);
|
|||
|
|
|
|||
|
|
printf("\n===================================================================\n");
|
|||
|
|
printf(" NVMe Hybrid System Test Complete\n");
|
|||
|
|
printf("===================================================================\n");
|
|||
|
|
printf(" Checkpoints saved to: %s\n", NVME_DIRECTORY);
|
|||
|
|
printf(" RAM buffer maintained: %d recent states\n", RING_BUFFER_SIZE);
|
|||
|
|
printf(" Ready for crash recovery testing\n");
|
|||
|
|
printf("===================================================================\n");
|
|||
|
|
|
|||
|
|
return 0;
|
|||
|
|
}
|