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ってところ。