Skip to content

Commit

Permalink
Limit max process count in phase 1
Browse files Browse the repository at this point in the history
Allow specifying maximum number of simultaneous plot processes
entering phase 1 for staggered plotting.
Temporary files are used as flags: one file per process.
Sample cli usage:
mkdir -p /home/user/.config/chia/run
./ProofOfSpace create -k 24 --p1maxproc 2 --runtimedir /home/user/.config/chia/run
  • Loading branch information
zmeyc committed Mar 9, 2021
1 parent f069c53 commit 8beabe1
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 7 deletions.
8 changes: 6 additions & 2 deletions python-bindings/chiapos.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ PYBIND11_MODULE(chiapos, m)
uint32_t num_buckets,
uint32_t stripe_size,
uint8_t num_threads,
bool nobitfield) {
bool nobitfield,
const std::string runtime_dir,
uint32_t phase1_max_processes) {
std::string memo_str(memo);
const uint8_t *memo_ptr = reinterpret_cast<const uint8_t *>(memo_str.data());
std::string id_str(id);
Expand All @@ -68,7 +70,9 @@ PYBIND11_MODULE(chiapos, m)
num_buckets,
stripe_size,
num_threads,
nobitfield);
nobitfield,
runtime_dir,
phase1_max_processes);
} catch (const std::exception &e) {
std::cout << "Caught plotting error: " << e.what() << std::endl;
throw e;
Expand Down
8 changes: 7 additions & 1 deletion src/cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ int main(int argc, char *argv[]) try {
string memo = "0102030405";
string id = "022fb42c08c12de3a6af053880199806532e79515f94e83461612101f9412f9e";
bool nobitfield = false;
uint32_t phase1_max_processes = 0;
string runtimedir = ".";
uint32_t buffmegabytes = 0;

options.allow_unrecognised_options().add_options()(
Expand All @@ -96,6 +98,8 @@ int main(int argc, char *argv[]) try {
"m, memo", "Memo to insert into the plot", cxxopts::value<string>(memo))(
"i, id", "Unique 32-byte seed for the plot", cxxopts::value<string>(id))(
"e, nobitfield", "Disable bitfield", cxxopts::value<bool>(nobitfield))(
"p1maxproc", "Phase 1 max process count", cxxopts::value<uint32_t>(phase1_max_processes))(
"runtimedir", "Runtime directory", cxxopts::value<string>(runtimedir))(
"b, buffer",
"Megabytes to be used as buffer for sorting and plotting",
cxxopts::value<uint32_t>(buffmegabytes))("help", "Print help");
Expand Down Expand Up @@ -145,7 +149,9 @@ int main(int argc, char *argv[]) try {
num_buckets,
num_stripes,
num_threads,
nobitfield);
nobitfield,
runtimedir,
phase1_max_processes);
} else if (operation == "prove") {
if (argc < 3) {
HelpAndQuit(options);
Expand Down
129 changes: 126 additions & 3 deletions src/disk_util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,12 @@
#include <sys/sysmacros.h>
#endif

#include "chia_filesystem.hpp"
#include "util.hpp"

using namespace std::chrono;
using namespace std::chrono_literals;

namespace DiskUtil {

inline bool IsRotational(const std::string &dir)
Expand Down Expand Up @@ -102,7 +106,6 @@ namespace DiskUtil {
return -1;
}
while (0 != flock(dir_fd, LOCK_EX | LOCK_NB)) {
using namespace std::chrono_literals;
if (EWOULDBLOCK == errno) {
std::this_thread::sleep_for(10s);
} else {
Expand Down Expand Up @@ -158,8 +161,6 @@ class DirectoryLock
bool Lock()
{
if (fd_ == -1) {
using namespace std::chrono;

std::cout << "Acquiring directory lock: " << dirname_ << std::endl;

steady_clock::time_point start = steady_clock::now();
Expand Down Expand Up @@ -191,6 +192,128 @@ class DirectoryLock
std::string dirname_;
};

class MultiFileLock
{
public:
MultiFileLock(const std::string &runtime_dir, const std::string &lock_name,
int max_slots, bool lock = true)
{
runtime_dir_ = runtime_dir;
lock_name_ = lock_name;

std::ostringstream prefix;
prefix << "." << lock_name << "-lock";
prefix_ = prefix.str();

max_slots_ = max_slots;
if (lock) {
Lock();
}
}

MultiFileLock(const MultiFileLock&) = delete;

virtual ~MultiFileLock()
{
Unlock();
}

bool Lock()
{
#ifdef _WIN32
return false;
#else
if (max_slots_ < 1 || fd_ != -1) {
return false;
}

std::cout << "Acquiring " << lock_name_ << " lock" << std::endl;

steady_clock::time_point start = steady_clock::now();
while (!TryLock()) {
std::this_thread::sleep_for(20s);
}
steady_clock::time_point end = steady_clock::now();

std::cout << "Lock acquired (took "
<< duration_cast<seconds>(end - start).count()
<< " sec)" << std::endl;

return true;
#endif
}

bool Unlock()
{
#ifdef _WIN32
return false;
#else
if (fd_ == -1) {
return false;
}

std::cout << "Releasing " << lock_name_ << " lock" << std::endl;

if (-1 == flock(fd_, LOCK_UN)) {
std::cerr << "Failed to unlock the file: " << strerror(errno)
<< std::endl;
return false;
}

if (-1 == close(fd_)) {
std::cerr << "Failed to close the file during unlocking: "
<< strerror(errno) << std::endl;
return false;
}

fd_ = -1;

return true;
#endif
}

private:
#ifndef _WIN32
bool TryLock()
{
for (int current_slot = 0; current_slot < max_slots_; ++current_slot) {
fs::path path(runtime_dir_);
std::ostringstream filename;
filename << prefix_ << "-" << current_slot;
path.append(filename.str());

std::string fullname = path.string();

fd_ = open(fullname.c_str(), O_CREAT | O_RDONLY | O_NOCTTY, 0666);
if (fd_ == -1) {
std::cerr << "Unable to open file for locking: " << fullname
<< ". Error: " << strerror(errno) << std::endl;
return false;
}
if (0 == flock(fd_, LOCK_EX | LOCK_NB)) {
return true;
}
if (EWOULDBLOCK != errno) {
std::cerr << "Error while trying to lock " << fullname << ": "
<< strerror(errno) << std::endl;
}
if (-1 == close(fd_)) {
std::cerr << "Failed to close " << fullname << ": "
<< strerror(errno) << std::endl;
}
fd_ = -1;
}
return false;
}
#endif

int fd_ = -1;
std::string runtime_dir_;
std::string lock_name_;
std::string prefix_;
int max_slots_ = 0;
};

#endif // SRC_CPP_DISK_UTIL_HPP_


Expand Down
10 changes: 9 additions & 1 deletion src/plotter_disk.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ class DiskPlotter {
uint32_t num_buckets_input = 0,
uint64_t stripe_size_input = 0,
uint8_t num_threads_input = 0,
bool nobitfield = false)
bool nobitfield = false,
std::string runtime_dir = ".",
uint32_t phase1_max_processes = 0)
{
// Increases the open file limit, we will open a lot of files.
#ifndef _WIN32
Expand Down Expand Up @@ -216,6 +218,9 @@ class DiskPlotter {

Timer p1;
Timer all_phases;

MultiFileLock lock(runtime_dir, "phase1", phase1_max_processes);

std::vector<uint64_t> table_sizes = RunPhase1(
tmp_1_disks,
k,
Expand All @@ -227,6 +232,9 @@ class DiskPlotter {
log_num_buckets,
stripe_size,
num_threads);

lock.Unlock();

p1.PrintElapsed("Time for phase 1 =");

uint64_t finalsize=0;
Expand Down
2 changes: 2 additions & 0 deletions tests/test_python_bindings.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ def test_k_21(self):
8192,
8,
False,
".",
0
)
pl = None

Expand Down

0 comments on commit 8beabe1

Please sign in to comment.