Skip to content

Commit

Permalink
attempt to make PRPLL compatible with AutoPrimeNet
Browse files Browse the repository at this point in the history
  • Loading branch information
olympichek committed Dec 31, 2024
1 parent e27a797 commit 6c2a195
Show file tree
Hide file tree
Showing 13 changed files with 121 additions and 169 deletions.
40 changes: 15 additions & 25 deletions src/Args.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,10 @@ and should be able to run.
Worktodo:
PRPLL keeps the active tasks in per-worker files worktodo-0.txt, worktodo-1.txt etc in the local directory.
These per-worker files are supplied from the global worktodo.txt file if -pool is used.
In turn the global worktodo.txt can be supplied through the primenet.py script,
either the one located at gpuowl/tools/primenet.py or https://download.mersenne.ca/primenet.py
It is also possible to manually add exponents by adding lines of the form "PRP=118063003" to worktodo-<N>.txt
PRPLL keeps the active tasks in worktodo.txt files in per-worker directories: worker-0, worker-1 etc.
Per-worker worktodo.txt can be supplied through the primenet.py script, either the one located at
gpuowl/tools/primenet.py or https://download.mersenne.ca/primenet.py
It is possible to manually add exponents by adding lines of the form "PRP=118063003" to worktodo.txt
The configuration options listed below can be passed on the command line or can be put in a file
Expand All @@ -130,9 +128,6 @@ named "config.txt" in the prpll run directory.
-h : print general help, list of FFTs, list of devices
-info <fft> : print detailed information about the given FFT; e.g. -h 1K:13:256
-dir <folder> : specify local work directory (containing worktodo.txt, results.txt, config.txt, gpuowl.log)
-pool <dir> : specify a directory with the shared (pooled) worktodo.txt and results.txt
Multiple PRPLL instances, each in its own directory, can share a pool of assignments and report
the results back to the common pool.
-verbose : print more log, useful for developers
-version : print only the version and exit
-user <name> : specify the mersenne.org user name (for result reporting)
Expand Down Expand Up @@ -350,13 +345,6 @@ void Args::parse(const string& line) {
}
verifyPath = s;
}
else if (key == "-pool") {
masterDir = s;
if (!masterDir.is_absolute()) {
log("-pool <path> requires an absolute path\n");
throw("-pool <path> requires an absolute path");
}
}
else if (key == "-results") { resultsFile = s; }
else if (key == "-maxAlloc" || key == "-maxalloc") {
assert(!s.empty());
Expand Down Expand Up @@ -408,15 +396,17 @@ void Args::parse(const string& line) {
void Args::setDefaults() {
uid = getUidFromPos(device);
log("device %d, OpenCL %s, unique id '%s'\n", device, getDriverVersionByPos(device).c_str(), uid.c_str());

if (!masterDir.empty()) {
assert(masterDir.is_absolute());
for (filesystem::path* p : {&proofResultDir, &proofToVerifyDir, &cacheDir, &resultsFile}) {
if (p->is_relative()) { *p = masterDir / *p; }
}
}

for (auto& p : {proofResultDir, proofToVerifyDir, cacheDir}) { fs::create_directory(p); }
fs::create_directory(cacheDir);

for (u32 i = 0; i < workers; ++i) {
fs::path worker = "worker-" + to_string(i);
fs::create_directory(worker);

fs::create_directory(worker / proofResultDir);
fs::create_directory(worker / proofToVerifyDir);

File::openAppend(worker / resultsFile); // verify that it's possible to write results
}

File::openAppend(resultsFile); // verify that it's possible to write results
}
1 change: 0 additions & 1 deletion src/Args.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ class Args {
bool useCache = false;
bool profile = false;

fs::path masterDir;
fs::path proofResultDir = "proof";
fs::path proofToVerifyDir = "proof-tmp";
fs::path cacheDir = "kernel-cache";
Expand Down
43 changes: 22 additions & 21 deletions src/Gpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1132,13 +1132,14 @@ void Gpu::doDiv9(u32 E, Words& words) {
doDiv3(E, words);
}

fs::path Gpu::saveProof(const Args& args, const ProofSet& proofSet) {
fs::path Gpu::saveProof(const Args& args, const ProofSet& proofSet, u32 instance) {
for (int retry = 0; retry < 2; ++retry) {
auto [proof, hashes] = proofSet.computeProof(this);
fs::path tmpFile = proof.file(args.proofToVerifyDir);
fs::path worker = "worker-" + to_string(instance);
fs::path tmpFile = proof.file(worker / args.proofToVerifyDir);
proof.save(tmpFile);

fs::path proofFile = proof.file(args.proofResultDir);
fs::path proofFile = proof.file(worker / args.proofResultDir);

bool ok = Proof::load(tmpFile).verify(this, hashes);
log("Proof '%s' verification %s\n", tmpFile.string().c_str(), ok ? "OK" : "FAILED");
Expand Down Expand Up @@ -1175,8 +1176,8 @@ PRPState Gpu::loadPRP(Saver<PRPState>& saver) {
throw "Error on load";
}

u32 Gpu::getProofPower(u32 k) {
u32 power = ProofSet::effectivePower(E, args.getProofPow(E), k);
u32 Gpu::getProofPower(u32 k, u32 instance) {
u32 power = ProofSet::effectivePower(E, args.getProofPow(E), k, instance);

if (power != args.getProofPow(E)) {
log("Proof using power %u (vs %u)\n", power, args.getProofPow(E));
Expand Down Expand Up @@ -1381,7 +1382,7 @@ double Gpu::timePRP() {
return secsPerIt * 1e6;
}

PRPResult Gpu::isPrimePRP(const Task& task) {
PRPResult Gpu::isPrimePRP(const Task& task, u32 instance) {
const constexpr u32 LOG_STEP = 20'000; // log every 20k its
assert(E == task.exponent);

Expand All @@ -1398,7 +1399,7 @@ PRPResult Gpu::isPrimePRP(const Task& task) {
double elapsedBefore = 0;

{
PRPState state = loadPRP(*getSaver());
PRPState state = loadPRP(*getSaver(instance));
nErrors = std::max(nErrors, state.nErrors);
blockSize = state.blockSize;
k = state.k;
Expand All @@ -1410,9 +1411,9 @@ PRPResult Gpu::isPrimePRP(const Task& task) {
u32 checkStep = checkStepForErrors(blockSize, nErrors);
assert(checkStep % LOG_STEP == 0);

u32 power = getProofPower(k);
u32 power = getProofPower(k, instance);

ProofSet proofSet{E, power};
ProofSet proofSet{E, power, instance};

bool isPrime = false;

Expand Down Expand Up @@ -1472,7 +1473,7 @@ PRPResult Gpu::isPrimePRP(const Task& task) {
++nErrors;
goto reload;
}
(*background)([=, E=this->E] { ProofSet::save(E, power, k, compactBits(rawData, E)); });
(*background)([=, E=this->E] { ProofSet::save(E, power, k, compactBits(rawData, E), instance); });
persistK = proofSet.next(k);
}

Expand Down Expand Up @@ -1510,8 +1511,8 @@ PRPResult Gpu::isPrimePRP(const Task& task) {

if (!doCheck) {
(*background)([=, this] {
getSaver()->saveUnverified({E, k, blockSize, res, compactBits(rawCheck, E), nErrors,
elapsedBefore + elapsedTimer.at()});
getSaver(instance)->saveUnverified({E, k, blockSize, res, compactBits(rawCheck, E), nErrors,
elapsedBefore + elapsedTimer.at()});
});

log(" %9u %016" PRIx64 " %4.0f\n", k, res, /*k / float(kEndEnd) * 100*,*/ secsPerIt * 1'000'000);
Expand All @@ -1532,14 +1533,14 @@ PRPResult Gpu::isPrimePRP(const Task& task) {

if (k < kEnd) {
(*background)([=, this, rawCheck = std::move(rawCheck)] {
getSaver()->save({E, k, blockSize, res, compactBits(rawCheck, E), nErrors, elapsedBefore + elapsedTimer.at()});
getSaver(instance)->save({E, k, blockSize, res, compactBits(rawCheck, E), nErrors, elapsedBefore + elapsedTimer.at()});
});
}

doBigLog(k, res, ok, secsPerIt, kEndEnd, nErrors);

if (k >= kEndEnd) {
fs::path proofFile = saveProof(args, proofSet);
fs::path proofFile = saveProof(args, proofSet, instance);
return {isPrime, finalRes64, nErrors, proofFile.string(), toHex(res2048)};
}
} else {
Expand Down Expand Up @@ -1569,13 +1570,13 @@ PRPResult Gpu::isPrimePRP(const Task& task) {
}
}

LLResult Gpu::isPrimeLL(const Task& task) {
LLResult Gpu::isPrimeLL(const Task& task, u32 instance) {
assert(E == task.exponent);
wantROE = 0;

Timer elapsedTimer;

Saver<LLState> saver{E, 1000, args.nSavefiles};
Saver<LLState> saver{E, 1000, args.nSavefiles, instance};

reload:
elapsedTimer.reset();
Expand Down Expand Up @@ -1715,15 +1716,15 @@ array<u64, 4> Gpu::isCERT(const Task& task) {
}


void Gpu::clear(bool isPRP) {
void Gpu::clear(bool isPRP, u32 instance) {
if (isPRP) {
Saver<PRPState>::clear(E);
Saver<PRPState>::clear(E, instance);
} else {
Saver<LLState>::clear(E);
Saver<LLState>::clear(E, instance);
}
}

Saver<PRPState> *Gpu::getSaver() {
if (!saver) { saver = make_unique<Saver<PRPState>>(E, args.blockSize, args.nSavefiles); }
Saver<PRPState> *Gpu::getSaver(u32 instance) {
if (!saver) { saver = make_unique<Saver<PRPState>>(E, args.blockSize, args.nSavefiles, instance); }
return saver.get();
}
12 changes: 6 additions & 6 deletions src/Gpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ class Gpu {

void modMul(Buffer<int>& ioA, Buffer<int>& inB, bool mul3 = false);

fs::path saveProof(const Args& args, const ProofSet& proofSet);
fs::path saveProof(const Args& args, const ProofSet& proofSet, u32 instance);
std::pair<RoeInfo, RoeInfo> readROE();
RoeInfo readCarryStats();

Expand All @@ -260,16 +260,16 @@ class Gpu {

~Gpu();

PRPResult isPrimePRP(const Task& task);
LLResult isPrimeLL(const Task& task);
PRPResult isPrimePRP(const Task& task, u32 instance);
LLResult isPrimeLL(const Task& task, u32 instance);
array<u64, 4> isCERT(const Task& task);

double timePRP();

tuple<bool, u64, RoeInfo, RoeInfo> measureROE(bool quick);
tuple<bool, RoeInfo> measureCarry();

Saver<PRPState> *getSaver();
Saver<PRPState> *getSaver(u32 instance);

void carryA(Buffer<double>& a, Buffer<double>& b) { carryA(reinterpret_cast<Buffer<int>&>(a), b); }

Expand Down Expand Up @@ -314,9 +314,9 @@ class Gpu {
Words expExp2(const Words& A, u32 n);
vector<Buffer<i32>> makeBufVector(u32 size);

void clear(bool isPRP);
void clear(bool isPRP, u32 instance);

private:
u32 getProofPower(u32 k);
u32 getProofPower(u32 k, u32 instance);
void doBigLog(u32 k, u64 res, bool checkOK, float secsPerIt, u32 nIters, u32 nErrors);
};
26 changes: 13 additions & 13 deletions src/Proof.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,16 +127,16 @@ bool Proof::verify(Gpu *gpu, const vector<u64>& hashes) const {

// ---- ProofSet ----

ProofSet::ProofSet(u32 E, u32 power)
: E{E}, power{power} {
ProofSet::ProofSet(u32 E, u32 power, u32 instance)
: E{E}, power{power}, instance{instance} {

assert(E & 1); // E is supposed to be prime
if (power <= 0 || power > 12) {
log("Invalid proof power: %u\n", power);
throw "Invalid proof power";
}

fs::create_directories(proofPath(E));
fs::create_directories(proofPath(E, instance));

vector<u32> spans;
for (u32 span = (E + 1) / 2; spans.size() < power; span = (span + 1) / 2) { spans.push_back(span); }
Expand Down Expand Up @@ -179,9 +179,9 @@ bool ProofSet::isInPoints(u32 E, u32 power, u32 k) {
return false;
}

bool ProofSet::canDo(u32 E, u32 power, u32 currentK) {
bool ProofSet::canDo(u32 E, u32 power, u32 currentK, u32 instance) {
assert(power > 0 && power <= 12);
return ProofSet{E, power}.isValidTo(currentK);
return ProofSet{E, power, instance}.isValidTo(currentK);
}

u32 ProofSet::bestPower(u32 E) {
Expand All @@ -205,16 +205,16 @@ double ProofSet::diskUsageGB(u32 E, u32 power) {
return power ? ldexp(E, -33 + int(power)) * 1.05 : 0.0;
}

u32 ProofSet::effectivePower(u32 E, u32 power, u32 currentK) {
u32 ProofSet::effectivePower(u32 E, u32 power, u32 currentK, u32 instance) {
for (u32 p = power; p > 0; --p) {
// log("validating proof residues for power %u\n", p);
if (canDo(E, p, currentK)) { return p; }
if (canDo(E, p, currentK, instance)) { return p; }
}
return 0;
}

bool ProofSet::fileExists(u32 k) const {
return File::size(proofPath(E) / to_string(k)) == i64(E / 32 + 2) * 4;
return File::size(proofPath(E, instance) / to_string(k)) == i64(E / 32 + 2) * 4;
}

bool ProofSet::isValidTo(u32 limitK) const {
Expand Down Expand Up @@ -245,18 +245,18 @@ u32 ProofSet::next(u32 k) const {
return *cacheIt;
}

void ProofSet::save(u32 E, u32 power, u32 k, const Words& words) {
void ProofSet::save(u32 E, u32 power, u32 k, const Words& words, u32 instance) {
assert(k && k <= E);
assert(isInPoints(E, power, k));

File::openWrite(proofPath(E) / to_string(k)).writeChecked(words);
assert(load(E, power, k) == words);
File::openWrite(proofPath(E, instance) / to_string(k)).writeChecked(words);
assert(load(E, power, k, instance) == words);
}

Words ProofSet::load(u32 E, u32 power, u32 k) {
Words ProofSet::load(u32 E, u32 power, u32 k, u32 instance) {
assert(k && k <= E);
assert(isInPoints(E, power, k));
return File::openReadThrow(proofPath(E) / to_string(k)).readChecked<u32>(E/32 + 1);
return File::openReadThrow(proofPath(E, instance) / to_string(k)).readChecked<u32>(E/32 + 1);
}

std::pair<Proof, vector<u64>> ProofSet::computeProof(Gpu *gpu) const {
Expand Down
20 changes: 12 additions & 8 deletions src/Proof.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,35 +55,39 @@ class ProofSet {
public:
const u32 E;
const u32 power;
const u32 instance;

private:
vector<u32> points;

bool isValidTo(u32 limitK) const;

static bool canDo(u32 E, u32 power, u32 currentK);
static bool canDo(u32 E, u32 power, u32 currentK, u32 instance);

mutable decltype(points)::const_iterator cacheIt{};

bool fileExists(u32 k) const;

static fs::path proofPath(u32 E) { return fs::path(to_string(E)) / "proof"; }
static fs::path proofPath(u32 E, u32 instance) {
fs::path worker = "worker-" + to_string(instance);
return fs::path(worker / to_string(E)) / "proof";
}
public:

static u32 bestPower(u32 E);
static u32 effectivePower(u32 E, u32 power, u32 currentK);
static u32 effectivePower(u32 E, u32 power, u32 currentK, u32 instance);
static double diskUsageGB(u32 E, u32 power);
static bool isInPoints(u32 E, u32 power, u32 k);

ProofSet(u32 E, u32 power);
ProofSet(u32 E, u32 power, u32 instance);

u32 next(u32 k) const;

static void save(u32 E, u32 power, u32 k, const Words& words);
static Words load(u32 E, u32 power, u32 k);
static void save(u32 E, u32 power, u32 k, const Words& words, u32 instance);
static Words load(u32 E, u32 power, u32 k, u32 instance);

void save(u32 k, const Words& words) const { return save(E, power, k, words); }
Words load(u32 k) const { return load(E, power, k); }
void save(u32 k, const Words& words) const { return save(E, power, k, words, instance); }
Words load(u32 k) const { return load(E, power, k, instance); }


std::pair<Proof, vector<u64>> computeProof(Gpu *gpu) const;
Expand Down
Loading

0 comments on commit 6c2a195

Please sign in to comment.