PSChiaPlotter.psm1
enum KSize{ K32 = 32 K33 = 33 K34 = 34 K35 = 35 } class MaximizedKSize { [KSize]$KSize [int]$MaxPlots [Decimal]$RemainingBytes [Decimal]$KSizeBytes [int64]$TotalBytes static [Decimal]$K35 = 884.1 * 1gb static [Decimal]$K34 = 429.8 * 1gb static [Decimal]$K33 = 208.8 * 1gb static [Decimal]$K32 = 101.4 * 1gb MaximizedKSize( [KSize]$KSize, [int64]$TotalBytes ){ $this.KSize = $Ksize $this.TotalBytes = $TotalBytes $this.KSizeBytes = switch ($this.KSize){ "K35" {[MaximizedKSize]::K35} "K34" {[MaximizedKSize]::K34} "K33" {[MaximizedKSize]::K33} "K32" {[MaximizedKSize]::K32} } $this.MaxPlots = [math]::Floor([decimal]($this.TotalBytes / $this.KSizeBytes)) $this.RemainingBytes = $Totalbytes - (([math]::Floor([decimal]($this.TotalBytes / $this.KSizeBytes))) * $this.KSizeBytes) } } class OptimizedKPlots { [int]$K35 [int]$K34 [int]$K33 [int]$K32 [decimal]$RemainingBytes [double]$RemainingGB OptimizedKPlots ( [int]$K35, [int]$K34, [int]$K33, [int64]$Totalbytes ){ $sizeremaining = $TotalBytes - (($K35 * [MaximizedKSize]::K35) + ($K34 * [MaximizedKSize]::K34) + ($K33 * [MaximizedKSize]::K33)) $k32max = Get-MaxKSize -Totalbytes $sizeremaining -KSize "K32" $this.K35 = $K35 $this.K34 = $K34 $this.K33 = $K33 $this.K32 = $k32max.MaxPlots $this.RemainingBytes = $k32max.RemainingBytes $this.RemainingGB = [math]::Round($k32max.RemainingBytes / 1gb,2) } } function ConvertTo-FriendlyTimeSpan { [CmdletBinding()] param( [int32]$Seconds ) $TimeSpan = New-TimeSpan -Seconds $Seconds switch ($TimeSpan){ {$_.Days -ge 1} {return "$([math]::Round($TimeSpan.TotalDays,2)) days";break} {$_.Hours -ge 1} {return "$([math]::Round($TimeSpan.TotalHours,2)) hrs";break} {$_.Minutes -ge 1} {return "$([math]::Round($TimeSpan.TotalMinutes,2)) mins";break} {$_.seconds -ge 1} {return "$([math]::Round($TimeSpan.TotalSeconds,2)) sec";break} } } function Get-ChiaHarvesterActivity { [CmdletBinding()] param( [string[]]$DebugLogFilePath = (Get-ChildItem -Path "$([System.Environment]::GetFolderPath("User"))\.chia\mainnet\log" -filter "debug.log*").FullName, [switch]$Summary ) $chiaharvesterlog = "([0-9:.\-T]*) harvester (?:src|chia).harvester.harvester(?:\s?): INFO\s*([0-9]*) plots were eligible for farming ([a-z0-9.]*) Found ([0-9]*) proofs. Time: ([0-9.]*) s. Total ([0-9]*) plots" foreach ($logfile in $DebugLogFilePath){ try{ $SummaryLog = New-Object 'System.Collections.Generic.List[System.Object]' Get-Content -Path $logfile | foreach-object { switch -Regex ($_){ $chiaharvesterlog { $harvesterActivity = [pscustomobject]@{ PSTypeName = "PSChiaPlotter.ChiaHarvesterActivity" Time = [datetime]::parse($Matches[1]) EligiblePlots = $Matches[2] LookUpTime = [double]$Matches[5] ProofsFound = $Matches[4] TotalPlots = $Matches[6] FilterRatio = $Matches[2] / $Matches[6] } #psobject if (-not$Summary){ $harvesterActivity } else{ $SummaryLog.Add($harvesterActivity) } } } #switch } #foreach line if ($Summary.IsPresent -and $SummaryLog.Count -ne 0){ Write-Information "Computing Summary for $logfile" if ([System.Environment]::OSVersion.Platform -eq "Win32NT"){ $FirstandLast = $SummaryLog | Sort-Object Time -Descending | Select-Object -First 1 -Last 1 | Sort-Object -Descending $RunTime = $FirstandLast[1].Time - $FirstandLast[0].Time if ($RunTime.TotalMinutes -lt 0){$RunTime = $FirstandLast[0].Time - $FirstandLast[1].Time} if ($RunTime.TotalMinutes -ne 0){$ChallengesPerMinute = $SummaryLog.Count / $RunTime.TotalMinutes} } else{ Write-Warning "Unable to calculate average challenges per min on linux due the timestamps missing the date portion." } [PSCustomObject]@{ PSTypeName = "PSChiaPlotter.ChiaHarvesterSummary" RunTime = $RunTime TotalEligiblePlots = ($SummaryLog | Measure-Object EligiblePlots -Sum).Sum BestLookUpTime = ($SummaryLog | Measure-Object LookUpTime -Minimum).Minimum WorstLookUpTime = ($SummaryLog | Measure-Object LookUpTime -Maximum).Maximum AverageLookUpTime = ($SummaryLog | Measure-Object LookUpTime -Average).Average ProofsFound = ($SummaryLog | Measure-Object -Property ProofsFound -Sum).Sum FilterRatio = ($SummaryLog | Measure-Object -Property FilterRatio -Average).Average ChallengesPerMinute = $ChallengesPerMinute } } } catch{ $PSCmdlet.WriteError($_) } } #foreach } function Get-ChiaKPlotCombination{ [CmdletBinding(DefaultParameterSetName = "DriveLetter")] param( [Parameter(ParameterSetName="FreeSpace")] [int64[]]$FreeSpace, [Parameter(ParameterSetName="DriveLetter")] [string[]]$DriveLetter = (Get-Volume).DriveLetter ) if ($PSCmdlet.ParameterSetName -eq "FreeSpace"){ foreach ($space in $FreeSpace){ $Max = Get-MaxKSize -TotalBytes $space $AllCombos = Get-OptimizedKSizePlotNumbers $Max | sort RemainingBytes $AllCombos | Add-Member -MemberType NoteProperty -Name "StartingFreeSpace" -Value $space $AllCombos } } elseif ($PSCmdlet.ParameterSetName -eq "DriveLetter"){ foreach ($letter in $DriveLetter){ $Drive = Get-Volume -DriveLetter $letter $Max = Get-MaxKSize -TotalBytes $Drive.SizeRemaining $AllCombos = Get-OptimizedKSizePlotNumbers $Max | sort RemainingBytes $AllCombos | Add-Member -NotePropertyMembers @{ DriveLetter = $letter FriendlyName = $Drive.FileSystemLabel } $AllCombos | foreach {$_.psobject.TypeNames.Insert(0,"PSChiaPlotter.KSizeCombination")} $AllCombos } } } function Get-ChiaMaxParallelCount { [CmdletBinding()] param( [Parameter()] [ValidateRange(1,128)] [int]$ThreadCount = 2, [Parameter()] [ValidateRange(1, [int]::MaxValue)] [int]$BufferMiB = 3390 ) if (!$PSBoundParameters.ContainsKey("ThreadCount") -and !$PSBoundParameters.ContainsKey("BufferMiB")){ Write-Warning "All calculations based on plotting k32 plot size only. SSD TB suggestion rounded up to the nearest TB." } else{ Write-Warning "SSD TB suggestion rounded up to the nearest TB." } $Processor = Get-CimInstance -ClassName Win32_Processor $Threads = ($Processor | measure -Property ThreadCount -Sum).Sum $MaxParallelCountCPU = [math]::Floor($Threads / $ThreadCount) #1mb = 1048576 bytes $RAM = (Get-CimInstance -ClassName Win32_PhysicalMemory | measure -Property Capacity -Sum).Sum / 1mb $MaxParallelCountRAM = [Math]::Floor([decimal]($RAM / $BufferMiB)) $SystemDisk = Get-CimInstance -Namespace ROOT/Microsoft/Windows/Storage -ClassName MSFT_Disk -Filter "IsSystem=True" $SSDs = Get-CimInstance -Namespace root/microsoft/windows/storage -ClassName MSFT_PhysicalDisk -Filter "MediaType=4" #4 -eq SSD $SSDs = $SSDs | where UniqueId -ne $SystemDisk.UniqueId | select $One_TB = 1000000000000 $One_GB = 1000000000 $TotalSSDspace = ($SSDs | measure -Property Size -Sum).Sum $SSD_Count = ($SSDs | Measure-Object).Count if ($SSD_Count -eq 0){ Write-Warning "No non-system SSD found, therefore Current_MaxParallelPlots will be 0. (Ignore if using mutiple HDDs)" } if ($Threads -gt ($Processor.NumberOfCores * 2)){ Write-Warning "Threads may actually only be half what is reported and therefore all calculations are off." } $SSD_MAX = [math]::Floor([decimal]($TotalSSDspace / (256.6 * $One_GB))) if ($MaxParallelCountCPU -le $MaxParallelCountRAM){ $MAXCount = $MaxParallelCountCPU $BottleNeck = "CPU" } else{ $MAXCount = $MaxParallelCountRAM $BottleNeck = "RAM" } $Suggested_SSD_TB = [math]::Ceiling([decimal](256.6 * $MAXCount) / 1000) if ($SSD_MAX -le $MAXCount){ $CurrentMax = $SSD_MAX $BottleNeck = "SSD" } else{ $CurrentMax = $MAXCount } $Suggested_SSD_TB = [math]::Ceiling([decimal](256.6 * $MAXCount) / 1000) [PSCustomObject]@{ ThreadCount = $ThreadCount Buffer = $BufferMiB CPUTotalThreads = $Threads CPUCores = ($Processor | Measure -Property NumberOfCores -Sum).Sum NumberOfProcessors = ($Processor | measure).Count TotalRAM_MiB = $RAM BottleNeck = $BottleNeck Current_SSD_SPACE_TB = [math]::Round(($TotalSSDspace / $One_TB),2) Current_SSD_Count = $SSD_Count Suggested_SSD_SPACE_TB = $Suggested_SSD_TB Current_MaxParallelPlots = $CurrentMax Potential_MAXParallelPlots = $MAXCount } } function Get-ChiaPlotProgress { [CmdletBinding()] param( [Parameter(Mandatory)] [ValidateScript({Test-Path -Path $_})] [string]$LogPath ) if ([System.IO.Directory]::Exists($LogPath)){ Write-Error "You provided a directory path and not a file path to the log file" -ErrorAction Stop } #base code from https://github.com/swar/Swar-Chia-Plot-Manager/blob/7287eef4796dbfa4cc009086c6502d19f0706f3e/config.yaml.default $phase1_line_end = 801 $phase2_line_end = 834 $phase3_line_end = 2474 $phase4_line_end = 2620 $copyfile_line_end = 2627 $phase1_weight = 33 $phase2_weight = 20 $phase3_weight = 42 $phase4_weight = 3 $copyphase_weight = 2 $LogItem = Get-Item -Path $LogPath $StartTime = $LogItem.CreationTime $EndTime = Get-Date $ElaspedTime = New-TimeSpan -Start $StartTime -End $EndTime $LogFile = Get-Content -Path $LogPath $plotId = $LogFile | Select-String -SimpleMatch "ID: " | foreach {$_.ToString().Split(" ")[1]} $line_count = $LogFile.Count if ($line_count -ge $phase1_line_end){ $progress += $phase1_weight } else{ $progress += $phase1_weight * ($line_count / $phase1_line_end) $Est_TimeRemaining = ($ElaspedTime.TotalSeconds * 100) / $progress $secondsRemaining = [int]($Est_TimeRemaining - $ElaspedTime.TotalSeconds) return [PSCustomObject]@{ Progress = [math]::Round($progress,2) Phase = "Phase 1" ElaspedTime = $ElaspedTime EST_TimeReamining = New-TimeSpan -Seconds $secondsRemaining PlotId = $plotId } } if ($line_count -ge $phase2_line_end){ $progress += $phase2_weight } else{ $progress += $phase2_weight * (($line_count - $phase1_line_end) / ($phase2_line_end - $phase1_line_end)) $Est_TimeRemaining = ($ElaspedTime.TotalSeconds * 100) / $progress $secondsRemaining = [int]($Est_TimeRemaining - $ElaspedTime.TotalSeconds) return [PSCustomObject]@{ Progress = [math]::Round($progress,2) Phase = "Phase 2" ElaspedTime = $ElaspedTime EST_TimeReamining = New-TimeSpan -Seconds $secondsRemaining PlotId = $plotId } } if ($line_count -ge $phase3_line_end){ $progress += $phase3_weight } else{ $progress += $phase3_weight * (($line_count - $phase2_line_end) / ($phase3_line_end - $phase2_line_end)) $Est_TimeRemaining = ($ElaspedTime.TotalSeconds * 100) / $progress $secondsRemaining = [int]($Est_TimeRemaining - $ElaspedTime.TotalSeconds) return [PSCustomObject]@{ Progress = [math]::Round($progress,2) Phase = "Phase 3" ElaspedTime = $ElaspedTime EST_TimeReamining = New-TimeSpan -Seconds $secondsRemaining PlotId = $plotId } } if ($line_count -ge $phase4_line_end){ $progress += $phase4_weight } else{ $progress += $phase4_weight * (($line_count - $phase3_line_end) / ($phase4_line_end - $phase3_line_end)) $Est_TimeRemaining = ($ElaspedTime.TotalSeconds * 100) / $progress $secondsRemaining = [int]($Est_TimeRemaining - $ElaspedTime.TotalSeconds) return [PSCustomObject]@{ Progress = [math]::Round($progress,2) Phase = "Phase 4" ElaspedTime = $ElaspedTime EST_TimeReamining = New-TimeSpan -Seconds $secondsRemaining PlotId = $plotId } } if ($line_count -lt $copyfile_line_end){ $Est_TimeRemaining = ($ElaspedTime.TotalSeconds * 100) / $progress $secondsRemaining = [int]($Est_TimeRemaining - $ElaspedTime.TotalSeconds) return [PSCustomObject]@{ Progress = [math]::Round($progress,2) Phase = "Copying" ElaspedTime = $ElaspedTime EST_TimeReamining = New-TimeSpan -Seconds $secondsRemaining PlotId = $plotId } } $progress += $copyphase_weight return [PSCustomObject]@{ Progress = [math]::Round($progress,2) Phase = "Completed" ElaspedTime = New-TimeSpan -Start $StartTime -End $LogItem.LastWriteTime EST_TimeReamining = 0 PlotId = $plotId } } function Get-ChiaPlottingStatistic { [CmdletBinding()] param( [Parameter(ValueFromPipeline,ValueFromPipelineByPropertyName)] [string[]]$Path = (Get-ChildItem -Path $env:USERPROFILE\.chia\mainnet\plotter\ | sort CreationTime -Descending).FullName ) Process{ foreach ($log in $path){ if (Test-Path $log){ $Content = Get-Content -Path $log | Select-String "Time for phase","Total time","Plot size","Buffer size","threads of stripe","Copy time","Copied final file from","Starting plotting progress into temporary dirs" | foreach {$_.ToString()} foreach ($line in $Content){ switch -Wildcard ($line){ "Plot size*" {$PlotSize = $line.split(' ') | select -Skip 3} #using select for these since indexing will error if empty "Buffer Size*" {$BufferSize = ($line.Split(' ') | select -Skip 3).split("M") | select -First 1} "*threads*" {$ThreadCount = $line.split(' ') | select -First 1 -Skip 1} "*phase 1*" {$Phase_1 = $line.Split(' ') | select -First 1 -Skip 5} "*phase 2*" {$Phase_2 = $line.Split(' ') | select -First 1 -Skip 5} "*phase 3*" {$Phase_3 = $line.Split(' ') | select -First 1 -Skip 5} "*phase 4*" {$phase_4 = $line.Split(' ') | select -First 1 -Skip 5} "Total time*" {$TotalTime = $line.Split(' ') | select -First 1 -Skip 3} "Copy time*" {$CopyTime = $line.Split(' ') | select -First 1 -Skip 3} "Starting plotting progress into temporary dirs*" {$TempDrive = ($line.Split(' ') | select -First 1 -Skip 6).Split('\') | select -First 1 } "Copied final file from*" {$FinalDrive = ($line.Split(' ') | select -First 1 -Skip 6).Split('\').Replace('"', '') | select -First 1} default {Write-Information "Could not match line: $line"} } } [PSCustomObject]@{ PSTypeName = "PSChiaPlotter.ChiaPlottingStatistic" KSize = $PlotSize "RAM(MiB)" = $BufferSize Threads = $ThreadCount "Phase_1_sec" = [int]$Phase_1 "Phase_2_sec" = [int]$Phase_2 "Phase_3_sec" = [int]$Phase_3 "Phase_4_sec" = [int]$phase_4 "TotalTime_sec" = [int]$TotalTime "CopyTime_sec" = [int]$CopyTime "PlotAndCopyTime_sec" = ([int]$CopyTime + [int]$TotalTime) "Time_Started" = (Get-Item -Path $log).CreationTime "Temp_drive" = $TempDrive "Final_drive" = $FinalDrive } Clear-Variable -Name "Phase_1","Phase_2","Phase_3","Phase_4","TotalTime","CopyTime" -ErrorAction SilentlyContinue } } } } function Get-ChiaProcessCounter{ [CmdletBinding()] param( [Parameter(Mandatory)] [int[]]$ChiaPID ) foreach ($ID in $ChiaPID){ $QueryString += "OR IDProcess=$ID " } $Performance = Get-CimInstance -Query "Select workingSetPrivate,PercentProcessorTime,IDProcess FROM Win32_PerfFormattedData_PerfProc_Process WHERE NAME='_Total' $QueryString" $TotalCPU = $Performance | where {$_.Name -eq '_Total'} $ChiaProcesses = $Performance | where {$_.Name -ne '_Total'} foreach ($process in $ChiaProcesses){ if ($process.PercentProcessorTime -ne 0){ $CPUPer = ($process.PercentProcessorTime / $TotalCPU.PercentProcessorTime) * 100 $RoundedCPU = [math]::Round($CPUPer,2) } else{$CPUPer = 0} [PSCustomObject]@{ ChiaPID = $process.IDProcess CPUPercent = $RoundedCPU } } } function Get-ChiaRAMInfo { [CmdletBinding()] param( ) Begin{ } #Begin Process{ $Array = Get-CimInstance -Class Win32_PhysicalMemoryArray $CurrentRAM = Get-CimInstance -Class Win32_PhysicalMemory [PSCustomObject]@{ PSTypeName = "PSChiaPlotter.RAMInfo" ComputerName = $ENV:COMPUTERNAME SlotsInUse = ($CurrentRAM | Measure).Count SlotsFree = $Array.MemoryDevices - ($CurrentRAM | Measure).Count CurrentSize_GB = (($CurrentRAM).Capacity | Measure -Sum).Sum / 1gb MaxSize_GB = $Array.MaxCapacityEx / 1mb PartNumber = ($CurrentRAM.PartNumber | Select -Unique | foreach {$_.Trim()}) Manufacturer = ($CurrentRAM.Manufacturer | Select -Unique | foreach {$_.Trim()}) TotalSlots = $Array.MemoryDevices RAMDevices = $CurrentRAM } } #Process } function Start-ChiaHarvesterWatcher { [CmdletBinding()] param( [string]$DebugLogFilePath = (Get-ChildItem -Path "$ENV:USERPROFILE\.chia\mainnet\log" -filter "debug.log").FullName, [ValidateRange(1,1000)] [int]$Sensitivity = 1, [Parameter()] [ValidateScript({[System.IO.Directory]::Exists((Split-Path -Path $_ -Parent))})] [string]$ExportCSVPath ) if ($PSBoundParameters.ContainsKey("ExportCSVPath")){ if (-not($ExportCSVPath.EndsWith('.csv'))){ Write-Warning "Export CSV Path does not end with .csv, please provide a valid CSV path and run the command again... exiting." return } } $chiaharvesterlog = "([0-9:.\-T]*) harvester chia.harvester.harvester: INFO\s*([0-9]*) plots were eligible for farming ([a-z0-9.]*) Found ([0-9]*) proofs. Time: ([0-9.]*) s. Total ([0-9]*) plots" $BestSpeed = 1000 $WorstSpeed = 0 $Over1Seconds = 0 $Over5Seconds = 0 $Over30Seconds = 0 $TotalAttempts = 0 $TotalFilterRatio = 0 $TotalLookupTime = 0 $proofsFound = 0 Get-Content -Path $DebugLogFilePath -Wait | foreach-object { switch -Regex ($_){ $chiaharvesterlog { $harvesterActivity = [pscustomobject]@{ Time = [datetime]::parse($Matches[1]) EligiblePlots = $Matches[2] LookUpTime = [double]$Matches[5] ProofsFound = $Matches[4] TotalPlots = $Matches[6] FilterRatio = $Matches[2] / $Matches[6] } $TotalAttempts++ switch ($harvesterActivity.LookUpTime) { {$_ -lt $BestSpeed} {$BestSpeed = $_} {$_ -gt $WorstSpeed} {$WorstSpeed = $_} {$_ -ge 1} {$Over1Seconds++} {$_ -ge 5} {$Over5Seconds++} {$_ -ge 30} {$Over30Seconds++} } if ($PSBoundParameters.ContainsKey("ExportCSVPath")){ $harvesterActivity | Export-Csv -Path $ExportCSVPath -Append } $proofsFound += $harvesterActivity.ProofsFound $TotalLookupTime += $harvesterActivity.LookUpTime $AverageSpeed = [math]::Round(($TotalLookupTime / $TotalAttempts),5) $TotalFilterRatio += $harvesterActivity.FilterRatio $newRatio = [math]::Round(($TotalFilterRatio / $TotalAttempts),5) $RGB = [math]::Round((255 * $harvesterActivity.LookUpTime * $Sensitivity) / 5) $eligibleplots = " " if ($harvesterActivity.EligiblePlots -gt 0){ $eligibleplots = $harvesterActivity.EligiblePlots } $host.UI.RawUI.WindowTitle = "Total Attempts: $TotalAttempts || LookUp Time - Best: $BestSpeed, Worst: $WorstSpeed, Avg: $AverageSpeed || Over 1 Sec:$Over1Seconds, Over 5 Sec: $Over5Seconds, Over 30 Sec: $Over30Seconds || FilterRatio: $newRatio || Proofs Found: $proofsFound || RGB: $RGB" Write-RGBText -Text "$eligibleplots|" -bRed ([math]::Min($RGB,255)) -bGreen ([math]::max([math]::Min(255,(510 - $RGB)),0)) -NoNewLine -UnderLine } } #switch } #foreach } function Start-ChiaParallelPlotting { param( [ValidateRange(1,128)] [int]$ParallelCount = 1, [ValidateRange(0,[int]::MaxValue)] [Alias("Delay")] [int]$DelayInSeconds = 3600, [int]$PlotsPerQueue = 1, [ValidateRange(3390,[int]::MaxValue)] [int]$Buffer = 3390, [ValidateRange(1,128)] [int]$Threads = 2, [Parameter(Mandatory)] [ValidateScript({[System.IO.Directory]::Exists($_)})] [string]$TempDirectoryPath, [Parameter(Mandatory)] [ValidateScript({[System.IO.Directory]::Exists($_)})] [string]$FinalDirectoryPath, [Parameter(Mandatory)] [ValidateScript({[System.IO.Directory]::Exists($_)})] [string]$LogDirectoryPath = "$ENV:USERPROFILE\.chia\mainnet\plotter", [switch]$NoExit, [ValidateNotNullOrEmpty()] [string]$WindowTitle ) if ($PSBoundParameters.ContainsKey("WindowTitle")){ $AddTitle = "-WindowTitle $WindowTitle" } for ($Queue = 1; $Queue -le $ParallelCount;$Queue++){ if ($NoExit){ $NoExitFlag = "-NoExit" } $processParam = @{ FilePath = "powershell.exe" ArgumentList = "$NoExitFlag -Command Start-ChiaPlotting -TotalPlots $plotsperQueue -Buffer $Buffer -Threads $Threads -TempDirectoryPath $TempDirectoryPath -FinalDirectoryPath $FinalDirectoryPath -LogDirectoryPath $LogDirectoryPath -QueueName Queue_$Queue $AddTitle" } Start-Process @processParam if ($Queue -lt $ParallelCount){ Start-Sleep -Seconds $DelayInSeconds } } #for } function Start-ChiaPlotting { [CmdletBinding()] param( [ValidateRange(32,35)] [int]$KSize = 32, [ValidateRange(1,5000)] [int]$TotalPlots = 1, [int]$Buffer, [ValidateRange(1,256)] [int]$Threads = 2, [switch]$DisableBitfield, [switch]$ExcludeFinalDirectory, [Parameter(Mandatory)] [ValidateScript({[System.IO.Directory]::Exists($_)})] [string]$TempDirectoryPath, [Parameter()] [ValidateScript({[System.IO.Directory]::Exists($_)})] [string]$SecondTempDirecoryPath, [Parameter(Mandatory)] [ValidateScript({[System.IO.Directory]::Exists($_)})] [string]$FinalDirectoryPath, #$FarmerPublicKey, #$PoolPublicKey, [ValidateScript({[System.IO.Directory]::Exists($_)})] [string]$LogDirectoryPath = "$ENV:USERPROFILE\.chia\mainnet\plotter", [switch]$NewWindow, [string]$QueueName = "Default_Queue", [string]$WindowTitle ) if (-not$PSBoundParameters.ContainsKey("Buffer")){ switch ($KSize){ 32 {$Buffer = 3390} 33 {$Buffer = 7400} 34 {$Buffer = 14800} 35 {$Buffer = 29600} } Write-Information "Buffer set to: $Buffer" } if ($PSBoundParameters.ContainsKey("WindowTitle")){ $WindowTitle = $WindowTitle + " |" } $E = if ($DisableBitfield){"-e"} $X = if ($ExcludeFinalDirectory){"-x"} #remove any trailing '\' since chia.exe hates them $TempDirectoryPath = $TempDirectoryPath.TrimEnd('\') $FinalDirectoryPath = $FinalDirectoryPath.TrimEnd('\') #path to chia.exe $ChiaPath = (Get-Item -Path "$ENV:LOCALAPPDATA\chia-blockchain\app-*\resources\app.asar.unpacked\daemon\chia.exe").FullName $ChiaArguments = "plots create -k $KSize -b $Buffer -r $Threads -t `"$TempDirectoryPath`" -d `"$FinalDirectoryPath`" $E $X" if ($PSBoundParameters.ContainsKey("SecondTempDirecoryPath")){ $SecondTempDirecoryPath = $SecondTempDirecoryPath.TrimEnd('\') $ChiaArguments += " -2 $SecondTempDirecoryPath" Write-Information "Added 2nd Temp Dir to Chia ArguementList" } if (Test-Path $LogDirectoryPath){ $LogPath = Join-Path $LogDirectoryPath ((Get-Date -Format yyyy_MM_dd_hh-mm-ss-tt_) + "plotlog" + ".log") } else{ $Message = "The log path provided was not found: $LogDirectoryPath" $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( [System.IO.FileNotFoundException]::new($Message,$SErvicePath), 'LogPathInvalid', [System.Management.Automation.ErrorCategory]::ObjectNotFound, "$LogDirectoryPath" ) $PSCmdlet.ThrowTerminatingError($ErrorRecord) $PSCmdlet.ThrowTerminatingError("Invalid Log Path Directory: $LogDirectoryPath") } if ($ChiaPath){ Write-Information "Chia path exists, starting the plotting process" if (!$NewWindow){ for ($plotNumber = 1;$plotNumber -le $TotalPlots;$plotNumber++){ try{ $LogPath = Join-Path $LogDirectoryPath ((Get-Date -Format yyyy_MM_dd_hh-mm-ss-tt_) + "plotlog-" + $plotNumber + ".log") $PlottingParam = @{ FilePath = $ChiaPath ArgumentList = $ChiaArguments RedirectStandardOutput = $LogPath NoNewWindow = $true } $chiaProcess = Start-Process @PlottingParam -PassThru $host.ui.RawUI.WindowTitle = "$WindowTitle $QueueName - Plot $plotNumber out of $TotalPlots | Chia Process Id - $($chiaProcess.id)" #Have noticed that giving the process a second to start before checking the logs works better Start-Sleep 1 while (!$chiaProcess.HasExited){ try{ $progress = Get-ChiaPlotProgress -LogPath $LogPath -ErrorAction Stop $plotid = $progress.PlotId #write-progress will fail if secondsremaining is less than 0... $secondsRemaining = $progress.EST_TimeReamining.TotalSeconds if ($progress.EST_TimeReamining.TotalSeconds -le 0){ $secondsRemaining = 0 } Write-Progress -Activity "Queue $($QueueName): Plot $plotNumber out of $TotalPlots" -Status "$($progress.phase) - $($progress.Progress)%" -PercentComplete $progress.progress -SecondsRemaining $secondsRemaining Start-Sleep 5 } catch{ Write-Progress -Activity "Queue $($QueueName): Plot $plotNumber out of $TotalPlots" -Status "WARNING! PROGRESS UPDATES HAS FAILED! $($progress.phase) - $($progress.Progress)%" -PercentComplete $progress.progress -SecondsRemaining $secondsRemaining Start-Sleep 30 } } #while if ($chiaProcess.ExitCode -ne 0){ Get-ChildItem -Path $TempDirectoryPath -Filter "*$plotid*.tmp" | Remove-Item -Force } } catch{ $PSCmdlet.WriteError($_) } } #for } #if noNewWindow else{ $ChiaArguments += " -n $TotalPlots" $PlottingParam = @{ FilePath = $ChiaPath ArgumentList = $ChiaArguments RedirectStandardOutput = $LogPath } $PlottingProcess = Start-Process @PlottingParam -PassThru [PSCustomObject]@{ KSize = $KSize Buffer = $Buffer Threads = $Threads PID = $PlottingProcess.Id StartTime = $PlottingProcess.StartTime TempDir = $TempDirectoryPath FinalDir = $FinalDirectoryPath TempDir2 = $SecondTempDirecoryPath LogPath = $LogPath TotalPlotCount = $TotalPlots BitfieldEnabled = !$DisableBitfield.IsPresent ExcludeFinalDir = $ExcludeFinalDirectory.IsPresent } Write-Information "Plotting started, PID = $PID" } # else } #if chia path exits } function Get-MaxKSize { [CmdletBinding()] param( [ValidateSet("K32","K33","K34","K35")] [string[]]$KSize = ("K32","K33","K34","K35"), [Parameter(Mandatory)] [int64]$TotalBytes ) foreach ($size in $KSize){ [MaximizedKSize]::new($size,$TotalBytes) } #foreach } function Get-OptimizedKSizePlotNumbers { [CmdletBinding()] param( [MaximizedKSize[]]$MaximizedKSize ) foreach ($size in $MaximizedKSize){ switch ($size.KSize){ "K32" { [OptimizedKPlots]::new(0,0,0,$Size.TotalBytes) } "K33" { for ($K33Count = 1; $K33Count -le $size.MaxPlots; $K33Count++){ [OptimizedKPlots]::new(0,0,$K33Count,$Size.TotalBytes) } #for } "K34" { for ($K34Count = 1; $K34Count -le $size.maxplots; $K34Count++){ [OptimizedKPlots]::new(0,$K34Count,0,$Size.TotalBytes) $k34sizeremaining = $Size.TotalBytes - ($K34Count * $size.KSizeBytes) $K33Max = Get-MaxKSize -TotalBytes $k34sizeremaining -KSize "K33" for ($k33 = 1; $k33 -le $k33max.MaxPlots; $k33++){ [OptimizedKPlots]::new(0,$K34Count,$k33,$Size.TotalBytes) } #for 33 } #for 34 } #34 "K35" { for ($k35count = 1; $k35count -le $size.maxplots; $k35count++){ [OptimizedKPlots]::new($k35count,0,0,$Size.TotalBytes) $k35sizeremaining = $Size.TotalBytes - ($k35count * $size.KSizeBytes) $k33max = Get-MaxKSize -Totalbytes $k35sizeremaining -KSize "K33" for ($k33 = 1; $k33 -le $k33max.MaxPlots; $k33++){ [OptimizedKPlots]::new($k35count,0,$k33,$Size.TotalBytes) } #for 33 $k34max = Get-MaxKSize -Totalbytes $k35sizeremaining -KSize "K34" for ($k34 = 1; $k34 -le $k34max.maxplots; $k34++){ [OptimizedKPlots]::new($k35count,$k34,0,$Size.TotalBytes) $sizeremaining = $Size.TotalBytes - (($k35count * $size.KSizeBytes) + ($k34 * $k34max.KSizeBytes)) $K33max = Get-MaxKSize -TotalBytes $sizeremaining -KSize "K33" for ($k33 = 1;$k33 -le $k33max.maxplots; $k33++){ [OptimizedKPlots]::new($k35count,$k34,$k33,$Size.TotalBytes) } } } } } #switch } #foreach } function Write-RGBText { [CmdletBinding()] param( [string]$Text, [Parameter(Position = 1)] [int]$fRed = 0, [int]$fGreen = 0, [int]$fBlue = 0, [int]$bRed = 0, [int]$bGreen = 0, [int]$bBlue = 0, # No newline after the text. [Parameter()] [switch] $NoNewLine, [switch]$UnderLine ) $escape = [char]27 + '[' $resetAttributes = "$($escape)0m" if ($UnderLine){ $UL = "$($escape)4m" } $foreground = "$($escape)38;2;$($fRed);$($fGreen);$($fBlue)m" $background = "$($escape)48;2;$($bRed);$($bGreen);$($bBlue)m" Write-Host ($foreground + $background + $UL + $Text + $resetAttributes) -NoNewline:$NoNewLine } Export-ModuleMember -function ConvertTo-FriendlyTimeSpan, Get-ChiaHarvesterActivity, Get-ChiaKPlotCombination, Get-ChiaMaxParallelCount, Get-ChiaPlotProgress, Get-ChiaPlottingStatistic, Get-ChiaProcessCounter, Get-ChiaRAMInfo, Start-ChiaHarvesterWatcher, Start-ChiaParallelPlotting, Start-ChiaPlotting |