Chia
Chia plotterについて。
HDDが20台あり、SSDが5台ある。HDDの空き容量ぴったりに、SSDをまんべんなく使いながら、Chiaのplottingをしたい。HDDは文字の割当が足りないので、適当なフォルダにマウントしたとする。
madmax plotterにコマンドラインで指定では、上記の条件は満たせないので、プログラム書いた。久しぶりに。C#。
相変わらずの無駄が多いクソプログラムだ。需要あればbinary貼ります。
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Management; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; namespace plothelper { class Program { static void Main(string[] args) { Program pm = new Program(); pm.Run(); } static ulong plotsize = 108836888948; static string MadMaxPath = ""; static string OptionText = ""; static List<string> ssds = new List<string>(); static List<string> dirs = new List<string>(); /// <summary> /// HDDごとのタスクカウント /// </summary> Dictionary<string, int> HDDRestTaskCount = new Dictionary<string, int>(); public void Run() { try { using (StreamReader sr = new StreamReader("config.txt", Encoding.GetEncoding("shift-jis"))) { string line = "", mode = ""; while (!sr.EndOfStream) { line = sr.ReadLine().Trim('\t', ' ').ToLower(); line = Regex.Replace(line, "#.*", ""); if (line == "") continue; if (line.StartsWith("[")) { mode = Regex.Match(line, "\\[(.*?)\\]").Groups[1].Value; continue; } switch (mode) { case "madmax": MadMaxPath = line; break; case "option": OptionText = line; break; case "plotssd": if (!line.EndsWith("\\")) line += "\\"; ssds.Add(line); break; case "dirs": if (!line.EndsWith("\\")) line += "\\"; dirs.Add(line); break; case "": break; } } } } catch { } // string dir = "c:\\chia\\"; /// リアルタイムで更新される、タスクカウント Dictionary<string, int> dirsTask = new Dictionary<string, int>(); /// SSDを使っているかどうか? Dictionary<string, int> ssdsTask = new Dictionary<string, int>(); foreach (string s in dirs) { var freespace = GetFreeSpaceOfPathInBytes(s); int count = (int)(freespace / plotsize); if (count < 1) continue; HDDRestTaskCount[s] = count; /// ディレクトリごとのタスク数 /// 現在やっているタスクのカウント 今は0 dirsTask[s] = 0; } /// SSDタスクカウントをゼロにする。 foreach(string s in ssds) { ssdsTask[s] = 0; } List<PlotProcess> procs = new List<PlotProcess>(); int plotcreationcount = 0; int plotcreationtimesum = 0; while (HDDRestTaskCount.Values.Sum() > 0) { Thread.Sleep(500); /// プロセスが終わってないかチェック。 foreach (var p in procs) { if (p.IsRunning() == false) { dirsTask[p.destdir]--; ssdsTask[p.plotdir]--; /// 終わったタスクのかかった時間を表示する int tim = p.SpentTime; plotcreationcount++; plotcreationtimesum += tim; int average = plotcreationtimesum / plotcreationcount / 1000; Console.WriteLine("EndTask: " + tim / 1000 / 60 + "min. Average: " + average / 60 + "min. " + 24 * 60 * 60 / (average / ssds.Count) + "plots/day Rest:" + HDDRestTaskCount.Values.Sum() + "plots " + HDDRestTaskCount.Values.Sum() * average / 60 / 60 / ssds.Count + "hours"); } } procs.RemoveAll(p => p.IsRunning() == false); /// プロセスが満タンなら終了. /// if (procs.Count == ssds.Count) continue; /// タスクが少ないHDDを探したい string taskLowDir = (from d in dirsTask orderby d.Value ascending where HDDRestTaskCount[d.Key] > 0 select d.Key).FirstOrDefault(); /// 使っていないSSDを探す string taskSSD = (from s in ssdsTask where s.Value == 0 select s.Key).FirstOrDefault(); /// SSDが見つからなかったらループする。 if (taskSSD == null) continue; Console.WriteLine(taskLowDir + " Rest:" + HDDRestTaskCount[taskLowDir] + " SSD: " + taskSSD ); PlotProcess pp = new PlotProcess(taskLowDir, taskSSD); pp.Start(); procs.Add(pp); ///タスクを始めたら++する。 dirsTask[taskLowDir]++; ssdsTask[taskSSD]++; HDDRestTaskCount[taskLowDir]--; } // Console.WriteLine(dir + " " + freespace / 1024 / 1024 / 1024 + "Gib Free"); Console.ReadLine(); } static Random random = new Random(); class PlotProcess { /// SSD1つにつき、plotタスクは1本ずつ走らせる /// SSD5枚あれば、常に5本のplotタスクは動いている /// 例えば、HDD1にE:\を使い、HDD2にF:\を使い、HDD3にG:\を使い・・・ /// 終わり次第、余ったSSDは別のタスクへ。 /// SSDをクラスにして、そのクラスでタスク管理したほうが良さそう。 /// 今、動かしているSSDとHDDを記録しておく必要あり? /// タスクが終わり次第、余っているSSDとHDDを組み合わせていく? /// どれだけタスクが必要かどうか、一旦計算するとか・・・ /// HDDにタスクをスタックしておく? /// /// 1回やるタスク。 public string destdir; public string plotdir; Process p = null; int starttime = 0; int debug_waittime = 0; public PlotProcess(string dest, string plot) { destdir = dest; plotdir = plot; debug_waittime = random.Next(1000, 10000); } public int SpentTime { get { return Environment.TickCount - starttime; } } public void Start() { string cmdtext = "-n 1 -d " + destdir + " -t " + plotdir + " " + OptionText; // Console.WriteLine("start " + MadMaxPath + " " + cmdtext); // debug comment p = Process.Start(MadMaxPath, cmdtext); starttime = Environment.TickCount; } public bool IsRunning() { /// debug //if (Environment.TickCount - starttime > debug_waittime) return false; else return true; return !p.HasExited; } } public static ulong GetFreeSpaceOfPathInBytes(string path) { if ((new Uri(path)).IsUnc) { throw new NotImplementedException("Cannot find free space for UNC path " + path); } ulong freeSpace = 0; int prevVolumeNameLength = 0; foreach (ManagementObject volume in new ManagementObjectSearcher("Select * from Win32_Volume").Get()) { string name = volume["Name"].ToString(); string pathh = path.ToLower(); if (!pathh.EndsWith("\\")) pathh += "\\"; if (UInt32.Parse(volume["DriveType"].ToString()) > 1 && // Is Volume monuted on Host volume["Name"] != null && // Volume has a root directory pathh == (volume["Name"].ToString()).ToLower() // Required Path is under Volume's root directory ) { // If multiple volumes have their root directory matching the required path, // one with most nested (longest) Volume Name is given preference. // Case: CSV volumes monuted under other drive volumes. int currVolumeNameLength = volume["Name"].ToString().Length; if ((prevVolumeNameLength == 0 || currVolumeNameLength > prevVolumeNameLength) && volume["FreeSpace"] != null ) { freeSpace = ulong.Parse(volume["FreeSpace"].ToString()); prevVolumeNameLength = volume["Name"].ToString().Length; } } } if (prevVolumeNameLength > 0) { return freeSpace; } //throw new Exception("Could not find Volume Information for path " + path); return 0; } } }
設定ファイルに次の通り記載する。
[madmax] #plotterの場所 C:\Users\Hoge\Desktop\madmax\chia_plot [option] -r 4 -c xch10xpf~ec5kdql29cew -f 8d05a7~a1329bfcb1 [plotssd] D:\ E:\ I:\ K:\ L:\ [dirs] c:\chia\hdd01 c:\chia\hdd02 c:\chia\hdd03 c:\chia\hdd04 c:\chia\hdd05 c:\chia\hdd06 c:\chia\hdd07 c:\chia\hdd08 c:\chia\hdd09 c:\chia\hdd10 c:\chia\hdd11 c:\chia\hdd12 c:\chia\hdd13 c:\chia\hdd14 c:\chia\hdd15
同一フォルダにおいておく。あとは、dirsにあるHDDに対して、plotssdにあるものを取りながらplotしてくれる。
今の所、5SSD並列で動かして45plots / dayってところ。