Skip to content

Commit

Permalink
Modified plot checker during plotting so that it
Browse files Browse the repository at this point in the history
checks plots before they are renamed from .plot.tmp.
  • Loading branch information
haorldbchi committed Sep 16, 2023
1 parent b7cfae8 commit c8bbd9f
Show file tree
Hide file tree
Showing 9 changed files with 347 additions and 320 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@
// "--memo", "80a836a74b077cabaca7a76d1c3c9f269f7f3a8f2fa196a65ee8953eb81274eb8b7328d474982617af5a0fe71b47e9b8ade0cc43610ce7540ab96a524d0ab17f5df7866ef13d1221a7203e5d10ad2a4ae37f7b73f6cdfd6ddf4122e8a1c2f8ef207d52406afa2b6d7d92ea778f407205bd9dca40816c1b1cacfca2a6612b93eb",

"args":
"-w -z 1 -f ade0cc43610ce7540ab96a524d0ab17f5df7866ef13d1221a7203e5d10ad2a4ae37f7b73f6cdfd6ddf4122e8a1c2f8ef -p 80a836a74b077cabaca7a76d1c3c9f269f7f3a8f2fa196a65ee8953eb81274eb8b7328d474982617af5a0fe71b47e9b8 -i c6b84729c23dc6d60c92f22c17083f47845c1179227c5509f07a5d2804a7b835 cudaplot --check 100 /home/harold/plot",
"-w -n 1 -z 1 -f ade0cc43610ce7540ab96a524d0ab17f5df7866ef13d1221a7203e5d10ad2a4ae37f7b73f6cdfd6ddf4122e8a1c2f8ef -p 80a836a74b077cabaca7a76d1c3c9f269f7f3a8f2fa196a65ee8953eb81274eb8b7328d474982617af5a0fe71b47e9b8 -i c6b84729c23dc6d60c92f22c17083f47845c1179227c5509f07a5d2804a7b835 cudaplot --check 100 --check-threshold 0.7 /home/harold/plot",

// "-w -z 3 -f ade0cc43610ce7540ab96a524d0ab17f5df7866ef13d1221a7203e5d10ad2a4ae37f7b73f6cdfd6ddf4122e8a1c2f8ef -p 80a836a74b077cabaca7a76d1c3c9f269f7f3a8f2fa196a65ee8953eb81274eb8b7328d474982617af5a0fe71b47e9b8 -i c6b84729c23dc6d60c92f22c17083f47845c1179227c5509f07a5d2804a7b835 --benchmark cudaplot /home/harold/plot",
// "-w -z 3 -f ade0cc43610ce7540ab96a524d0ab17f5df7866ef13d1221a7203e5d10ad2a4ae37f7b73f6cdfd6ddf4122e8a1c2f8ef -p 80a836a74b077cabaca7a76d1c3c9f269f7f3a8f2fa196a65ee8953eb81274eb8b7328d474982617af5a0fe71b47e9b8 -i c6b84729c23dc6d60c92f22c17083f47845c1179227c5509f07a5d2804a7b835 --benchmark cudaplot --disk-128 -t1 /home/harold/plotdisk /home/harold/plot",
Expand Down
1 change: 1 addition & 0 deletions cuda/CudaPlotContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ struct CudaK32PlotContext

// Used when '--check' is enabled
struct GreenReaperContext* grCheckContext = nullptr;
class PlotChecker* plotChecker = nullptr;

struct
{
Expand Down
106 changes: 34 additions & 72 deletions cuda/CudaPlotter.cu
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "plotting/PlotTools.h"
#include "util/VirtualAllocator.h"
#include "harvesting/GreenReaper.h"
#include "tools/PlotChecker.h"


// TEST/DEBUG
#if _DEBUG
Expand Down Expand Up @@ -249,16 +251,38 @@ void InitContext( CudaK32PlotConfig& cfg, CudaK32PlotContext*& outContext )
// Allocate GR Context if --check was specified
if( cfg.plotCheckCount > 0 )
{
GreenReaperConfig grCfg{
.apiVersion = GR_API_VERSION,
.threadCount = 1,
.gpuRequest = GRGpuRequestKind_ExactDevice,
.gpuDeviceIndex = cfg.deviceIndex
if( cfg.gCfg->compressionLevel > 0 )
{
GreenReaperConfig grCfg{
.apiVersion = GR_API_VERSION,
.threadCount = 1,
.gpuRequest = GRGpuRequestKind_ExactDevice,
.gpuDeviceIndex = cfg.deviceIndex
};

auto grResult = grCreateContext( &cx.grCheckContext, &grCfg, sizeof( grCfg ) );
FatalIf( grResult != GRResult_OK, "Failed to create decompression context for plot check with error '%s' (%d).",
grResultToString( grResult ), (int)grResult );

grResult = grPreallocateForCompressionLevel( cx.grCheckContext, BBCU_K, cfg.gCfg->compressionLevel );
FatalIf( grResult != GRResult_OK, "Failed to preallocate memory for decompression context with error '%s' (%d).",
grResultToString( grResult ), (int)grResult );
}

PlotCheckerConfig checkerCfg{
.proofCount = cfg.plotCheckCount,
.noGpu = false,
.gpuIndex = cfg.deviceIndex,
.threadCount = 1,
.disableCpuAffinity = false,
.silent = false,
.hasSeed = false,
.deletePlots = true,
.deleteThreshold = cfg.plotCheckThreshhold,
.grContext = cx.grCheckContext
};

const auto grResult = grCreateContext( &cx.grCheckContext, &grCfg, sizeof( grCfg ) );
FatalIf( grResult != GRResult_OK, "Failed to create decompression context for plot check with error '%s' (%d).",
grResultToString( grResult ), (int)grResult );
cx.plotChecker = PlotChecker::Create( checkerCfg );
}
}

Expand Down Expand Up @@ -330,6 +354,8 @@ void CudaK32Plotter::Run( const PlotRequest& req )
cx.plotWriter = new PlotWriter( !cfg.gCfg->disableOutputDirectIO );
if( cx.gCfg->benchmarkMode )
cx.plotWriter->EnableDummyMode();
if( cx.plotChecker )
cx.plotWriter->EnablePlotChecking( *cx.plotChecker );

FatalIf( !cx.plotWriter->BeginPlot( cfg.gCfg->compressionLevel > 0 ? PlotVersion::v2_0 : PlotVersion::v1_0,
req.outDir, req.plotFileName, req.plotId, req.memo, req.memoSize, cfg.gCfg->compressionLevel ),
Expand Down Expand Up @@ -357,9 +383,6 @@ void CudaK32Plotter::Run( const PlotRequest& req )
delete cx.plotWriter;
cx.plotWriter = nullptr;

// Perform checks if neccesarry
CheckPlot( req, cx );


// Delete any temporary files
#if !(DBG_BBCU_KEEP_TEMP_FILES)
Expand Down Expand Up @@ -1254,67 +1277,6 @@ void UploadBucketForTable( CudaK32PlotContext& cx, const uint64 bucket )
}


//-----------------------------------------------------------
void CheckPlot( const PlotRequest& req, CudaK32PlotContext& cx )
{
const auto& cfg = cx.cfg;
if( cfg.plotCheckCount <= 0 )
return;

std::string plotPath = req.plotOutPath;
plotPath.resize( plotPath.length() - 4 ); // Remove '.tmp'

PlotCheckConfig checksCfg{
.proofCount = cfg.plotCheckCount,
.plotPath = plotPath.c_str(),
.gpuIndex = (int)cfg.deviceIndex,
.silent = false,
.grContext = cx.grCheckContext
};

// Log::Line( "Running plot check with %llu proofs...", (llu)cfg.plotCheckCount );
PlotCheckResult checksResult{};

if( !RunPlotsCheck( checksCfg, 1, false, &checksResult ) )
{
Log::Line( "An error occured checking the plot: %s.", checksResult.error.c_str() );
Log::Line( "Any actions against plot '%s' will be ignored.", plotPath.c_str() );
}
else
{
const double passRate = checksResult.proofCount / (double)checksResult.checkCount;

// Print stats
std::string seedHex = BytesToHexStdString( checksResult.seedUsed, sizeof( checksResult.seedUsed ) );
Log::Line( "Seed used: 0x%s", seedHex.c_str() );
Log::Line( "Proofs requested/fetched: %llu / %llu ( %.3lf%% )", checksResult.proofCount, checksResult.checkCount, passRate * 100.0 );

if( checksResult.proofFetchFailCount > 0 )
Log::Line( "Proof fetches failed : %llu ( %.3lf%% )", checksResult.proofFetchFailCount, checksResult.proofFetchFailCount / (double)checksResult.checkCount * 100.0 );
if( checksResult.proofValidationFailCount > 0 )
Log::Line( "Proof validation failed : %llu ( %.3lf%% )", checksResult.proofValidationFailCount, checksResult.proofValidationFailCount / (double)checksResult.checkCount * 100.0 );
Log::NewLine();

// Delete the plot if it's below the set threshold
if( checksResult.proofFetchFailCount > 0 || passRate < cfg.plotCheckThreshhold )
{
if( checksResult.proofFetchFailCount > 0 )
Log::Line( "WARNING: Deleting plot '%s' as it failed to fetch some proofs. This might indicate corrupt plot file.",
plotPath.c_str() );
else
Log::Line( "WARNING: Deleting plot '%s' as it is below the proof threshold: %.3lf / %.3lf.",
plotPath.c_str(), passRate, cfg.plotCheckThreshhold );

remove( plotPath.c_str() );
Log::NewLine();
}
else
{
Log::Line( "Plot is OK. It passed the proof threshold of %.3lf%%", cfg.plotCheckThreshhold * 100.0 );
Log::NewLine();
}
}
}

///
/// Allocations
Expand Down
201 changes: 58 additions & 143 deletions src/commands/CmdPlotCheck.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
#include "CmdPlotCheckInternal.h"
#include "threading/MTJob.h"
#include "util/CliParser.h"
#include "tools/PlotReader.h"
#include "plotting/GlobalPlotConfig.h"
#include "plotting/PlotValidation.h"
#include "plotting/f1/F1Gen.h"
#include "tools/PlotChecker.h"
#include "harvesting/GreenReaper.h"


void CmdPlotsCheckHelp();
struct PlotCheckConfig
{
GlobalPlotConfig* gCfg = nullptr;

uint64 proofCount = 100;
std::vector<const char*> plotPaths{};
byte seed[BB_PLOT_ID_LEN]{};
bool hasSeed = false;
bool noGpu = false;
int32 gpuIndex = -1;
};

void CmdPlotsCheckHelp();

//-----------------------------------------------------------
void CmdPlotsCheckMain( GlobalPlotConfig& gCfg, CliParser& cli )
Expand All @@ -34,157 +47,59 @@ void CmdPlotsCheckMain( GlobalPlotConfig& gCfg, CliParser& cli )
}

FatalIf( !cli.HasArgs(), "Expected a path to a plot file." );
do
{
cfg.plotPath = cli.Arg();
cfg.plotPaths.push_back( cli.Arg() );
cli.NextArg();

if( cli.HasArgs() )
{
Fatal( "Unexpected argument '%s'.", cli.Arg() );
Exit( 1 );
}
}

PlotCheckResult result{};
if( !RunPlotsCheck( cfg, gCfg.threadCount, gCfg.disableCpuAffinity, &result ) )
{
Fatal( result.error.c_str() );
}

Log::Line( "%llu / %llu (%.2lf%%) valid proofs found.",
(llu)result.proofCount, (llu)cfg.proofCount, ((double)result.proofCount / cfg.proofCount) * 100.0 );
}

//-----------------------------------------------------------
bool RunPlotsCheck( PlotCheckConfig& cfg, uint32 threadCount, const bool disableCpuAffinity, PlotCheckResult* outResult )
{
if( outResult )
{
outResult->proofFetchFailCount = 0;
outResult->proofValidationFailCount = 0;
}

cfg.proofCount = std::max( cfg.proofCount, (uint64)1 );

FilePlot plot;
if( !plot.Open( cfg.plotPath ) )
{
if( outResult )
{
std::stringstream err; err << "Failed to open plot file at '" << cfg.plotPath << "' with error " << plot.GetError() << ".";
outResult->error = err.str();
}

return false;
}

threadCount = threadCount == 0 ? SysHost::GetLogicalCPUCount() :
std::min( (uint32)MAX_THREADS, std::min( threadCount, SysHost::GetLogicalCPUCount() ) );

const bool useGpu = plot.CompressionLevel() > 0 && !cfg.noGpu;

PlotReader reader( plot );

if( cfg.grContext )
reader.AssignDecompressionContext( cfg.grContext );
else
reader.ConfigDecompressor( threadCount, disableCpuAffinity, 0, useGpu, (int)cfg.gpuIndex );

const uint32 k = plot.K();

byte AlignAs(8) seed[BB_PLOT_ID_LEN] = {};

if( !cfg.hasSeed )
SysHost::Random( seed, sizeof( seed ) );
else
memcpy( seed, cfg.seed, sizeof( cfg.seed ) );

{
std::string seedHex = BytesToHexStdString( seed, sizeof( seed ) );
if( !cfg.silent )
Log::Line( "Checking %llu random proofs with seed 0x%s...", (llu)cfg.proofCount, seedHex.c_str() );
}

if( !cfg.silent )
Log::Line( "Plot compression level: %u", plot.CompressionLevel() );

if( !cfg.grContext && plot.CompressionLevel() > 0 && useGpu )
{
const bool hasGPU = grHasGpuDecompressor( reader.GetDecompressorContext() );
if( hasGPU && !cfg.silent )
Log::Line( "Using GPU for decompression." );
else if( !cfg.silent )
Log::Line( "No GPU was selected for decompression." );
}

const uint64 f7Mask = (1ull << k) - 1;

uint64 prevF7 = 0;
uint64 proofCount = 0;

uint64 proofXs[BB_PLOT_PROOF_X_COUNT];

uint64 nextPercentage = 10;

for( uint64 i = 0; i < cfg.proofCount; i++ )
while( cli.HasArgs() );


// GreenReaperContext* grContext = nullptr;
// {
// // Pre-create decompressor here?
// grCreateContext( &grcontext, grCfg, sizeof( GreenReaperConfig ) )
// }

// const bool hasGPU = grHasGpuDecompressor( reader.GetDecompressorContext() );
// if( hasGPU && !cfg.silent )
// Log::Line( "Using GPU for decompression." );
// else if( !cfg.silent )
// Log::Line( "No GPU was selected for decompression." );

PlotCheckerConfig checkerCfg{
.proofCount = cfg.proofCount,
.noGpu = cfg.noGpu,
.gpuIndex = cfg.gpuIndex,
.threadCount = gCfg.threadCount,
.disableCpuAffinity = gCfg.disableCpuAffinity,
.silent = false,
.hasSeed = cfg.hasSeed,
.deletePlots = false,
.deleteThreshold = 0.0
};

static_assert( sizeof( checkerCfg.seed ) == sizeof( cfg.seed ) );
if( cfg.hasSeed )
memcpy( checkerCfg.seed, cfg.seed, sizeof( checkerCfg.seed ) );

ptr<PlotChecker> checker( PlotChecker::Create( checkerCfg ) );

for( auto* plotPath : cfg.plotPaths )
{
const uint64 f7 = F1GenSingleForK( k, seed, prevF7 ) & f7Mask;
prevF7 = f7;

uint64 startP7Idx = 0;
const uint64 nF7Proofs = reader.GetP7IndicesForF7( f7, startP7Idx );

for( uint64 j = 0; j < nF7Proofs; j++ )
PlotCheckResult result{};
checker->CheckPlot( plotPath, &result );
if( !result.error.empty() )
{
uint64 p7Entry;
if( !reader.ReadP7Entry( startP7Idx + j, p7Entry ) )
{
if( outResult )
outResult->proofFetchFailCount ++;

continue;
}

const auto r = reader.FetchProof( p7Entry, proofXs );
if( r == ProofFetchResult::OK )
{
// Convert to
uint64 outF7 = 0;
if( PlotValidation::ValidateFullProof( k, plot.PlotId(), proofXs, outF7 ) && outF7 == f7 )
{
proofCount++;
}
else if( outResult )
{
outResult->proofValidationFailCount++;
}
}
else
{
if( r != ProofFetchResult::NoProof && outResult )
outResult->proofFetchFailCount ++;
}
Fatal( result.error.c_str() );
}

const double percent = i / (double)cfg.proofCount * 100.0;
if( (uint64)percent == nextPercentage )
{
if( !cfg.silent )
Log::Line( " %llu%%...", (llu)nextPercentage );
nextPercentage += 10;
}
}
Log::NewLine();

if( outResult )
{
outResult->checkCount = cfg.proofCount;
outResult->proofCount = proofCount;
outResult->error.clear();
static_assert( sizeof(PlotCheckResult::seedUsed) == sizeof(seed) );
memcpy( outResult->seedUsed, seed, sizeof( outResult->seedUsed ) );
// Log::Line( "%llu / %llu (%.2lf%%) valid proofs found.",
// (llu)result.proofCount, (llu)cfg.proofCount, ((double)result.proofCount / cfg.proofCount) * 100.0 );
}

return true;
}

//-----------------------------------------------------------
Expand Down
Loading

0 comments on commit c8bbd9f

Please sign in to comment.