// Spludlow Software // Copyright © Samuel P. Ludlow 2020 All Rights Reserved // Distributed under the terms of the GNU General Public License version 3 // Distributed WITHOUT ANY WARRANTY; without implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE // https://www.spludlow.co.uk/LICENCE.TXT // The Spludlow logo is a registered trademark of Samuel P. Ludlow and may not be used without permission // v1.14 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Data; using System.IO; namespace Spludlow { public class BenchMarker { public static string Queue = "Run"; public static DataTable Schema() { DataTable table = Spludlow.Data.TextTable.ReadText(new string[] { "HostId Cores TotalClockSpeed FreeMemory CurrentLoad UploadSpeed DownloadSpeed DoubleSpeed ByteSpeed DiskSpeed", "String* Int32 Int32 UInt64 Decimal Int32 Int32 Decimal Decimal Decimal", }); return table; } public static void Run() { string[] hosts = Spludlow.Config.Hosts(); List methods = new List(); foreach (string host in hosts) { methods.Add(new CallMethod(host + ":" + Queue, "Spludlow", "Spludlow.BenchMarker", "RunWork")); } Spludlow.Call.Parallel(methods.ToArray(), new CallMethod(Environment.MachineName + ":" + Queue, "Spludlow", "Spludlow.BenchMarker", "Results", new object[] { null, hosts }, CallFlags.ReportResult, 0)); } public static DataSet RunWork() { DataTable table = Schema(); ulong freeMemory = (UInt64)Spludlow.ManagementObjects.Query("Win32_OperatingSystem ", "FreePhysicalMemory")[0]; int totalCores = 0; foreach (UInt32 cores in Spludlow.ManagementObjects.Query("Win32_Processor", "NumberOfCores")) totalCores += (int)cores; int totalClockSpeed = 0; foreach (UInt32 clockSpeed in Spludlow.ManagementObjects.Query("Win32_Processor", "CurrentClockSpeed")) totalClockSpeed += (int)clockSpeed; int cpuCount = 0; decimal totalLoad = 0; foreach (UInt16 cpuLoad in Spludlow.ManagementObjects.Query("Win32_Processor", "LoadPercentage")) { ++cpuCount; totalLoad += (decimal)cpuLoad; } totalLoad /= cpuCount; decimal doubleSpeed = TestDouble(); decimal byteSpeed = TestByteArray(); decimal diskSpeed = TestDiskSpeed(); table.Rows.Add(new object[] { Environment.MachineName, totalCores, totalClockSpeed, freeMemory, totalLoad, 0, 0, doubleSpeed, byteSpeed, diskSpeed }); return Spludlow.Data.ADO.WireDataSet(table); } public static DataSet Results(object[] results, string[] hosts) { DataTable table = Schema(); DataSet dataSet; for (int index = 0; index < results.Length; ++index) { dataSet = (DataSet)results[index]; DataRow result = dataSet.Tables[0].Rows[0]; string host = hosts[index]; if (host != (string)result["HostId"]) throw new ApplicationException("Result data not syncroniszed properly."); table.ImportRow(result); int[] upDownSpeed = UpDownSpeed(host); table.Rows[index]["UploadSpeed"] = upDownSpeed[0]; table.Rows[index]["DownloadSpeed"] = upDownSpeed[1]; } dataSet = Spludlow.Data.ADO.WireDataSet(table); Spludlow.Log.Report("BenchMarker", new object[] { dataSet }); return dataSet; } public class FractalsInfo { public int PixelWidth; public int PixelHeight; public int Dpi; public string FractalType; public double X; public double Y; public double Width; public double Height; public int Iterations; public double PalleteFactor; public Dictionary Parameters; } public class FractalsRenderInfo { public int Offset; public int Lines; //public ManualResetEvent ManualResetEvent; public Random Random; } public static decimal TestDouble() { FractalsInfo info = new FractalsInfo(); info.X = -1; info.Y = -1; info.Width = 2; info.Height = 2; info.PixelWidth = 4096; info.PixelHeight = 4096; info.Iterations = 4096; FractalsRenderInfo renderInfo = new FractalsRenderInfo(); renderInfo.Offset = 0; renderInfo.Lines = info.PixelHeight; renderInfo.Random = new Random(); DateTime startTime = DateTime.Now; Mandelbrot(info, renderInfo); TimeSpan span = DateTime.Now - startTime; return (decimal) Math.Round(span.TotalSeconds, 3); } private static void Mandelbrot(FractalsInfo info, FractalsRenderInfo renderInfo) { double x1 = info.X - info.Width / 2.0; double y1 = info.Y - info.Height / 2.0; double xd = info.Width / (double)info.PixelWidth; double yd = info.Height / (double)info.PixelHeight; for (int yPixel = renderInfo.Offset; yPixel < renderInfo.Offset + renderInfo.Lines; yPixel++) { double y = y1 + yPixel * yd; for (int xPixel = 0; xPixel < info.PixelWidth; xPixel++) { double x = x1 + xPixel * xd; int iteration = 0; double r1 = 0; double i1 = 0; double r1pow2 = 0; double i1pow2 = 0; double rpow = 0; double rlastpow = 0; while ((iteration < info.Iterations) && (rpow < 4)) { r1pow2 = r1 * r1; i1pow2 = i1 * i1; i1 = 2 * i1 * r1 + y; r1 = r1pow2 - i1pow2 + x; rlastpow = rpow; rpow = r1pow2 + i1pow2; iteration++; } //if (iteration < this.Info.Iterations) // this.Plot(xPixel, yPixel, iteration); } } } private static decimal TestByteArray() { DateTime startTime = DateTime.Now; ulong size = 1 * 1024 * 1024 * 1024; byte[] data = new byte[size]; Random rand = new Random(); for (long index = 0; index < data.LongLength; ++index) { data[index] = (byte)rand.Next(256); } for (int iteration = 0; iteration < 4; ++iteration) { for (long index = 0; index < data.LongLength; ++index) { data[index] = data[data.LongLength - index - 1]; } } TimeSpan span = DateTime.Now - startTime; return (decimal)span.TotalMilliseconds; } public static decimal TestDiskSpeed() { using (TempDirectory tempDir = new TempDirectory()) { byte[] data = new byte[32 * 1024 * 1024]; Random rand = new Random(); for (long index = 0; index < data.LongLength; ++index) { data[index] = (byte)rand.Next(256); } DateTime startTime = DateTime.Now; using (FileStream stream = new FileStream(tempDir + @"\test.dat", FileMode.Create)) { for (int iteration = 0; iteration < 128; ++iteration) { stream.Write(data, 0, data.Length); } } using (FileStream stream = new FileStream(tempDir + @"\test.dat", FileMode.Open)) { for (int iteration = 0; iteration < 64; ++iteration) { stream.Read(data, 0, data.Length); } } TimeSpan span = DateTime.Now - startTime; return (decimal)span.TotalMilliseconds; } } // FlushFileBuffers win api public static int[] UpDownSpeed(string host) // MBytes / second { DataTable table = Spludlow.Data.TextTable.ReadText(new string[] { "HostId Direction Attempt Size SizeText Time", "String String Int32 UInt64 String UInt64", }); int totalAttemps = 4; List fileList = new List(); for (int attempt = 0; attempt < totalAttemps; ++attempt) { byte[] data = RandomData(48); //(attempt + 1) * 8); DateTime startTime = DateTime.Now; string filename = Spludlow.Call.Upload(host, data); TimeSpan took = DateTime.Now - startTime; fileList.Add(filename); table.Rows.Add(new object[] { host, "up", attempt, data.LongLength, Spludlow.Text.DataSize(data.LongLength), took.TotalMilliseconds }); } for (int attempt = 0; attempt < totalAttemps; ++attempt) { string remoteFilename = fileList[attempt]; DateTime startTime = DateTime.Now; byte[] data = Spludlow.Call.DownloadData(host, remoteFilename); TimeSpan took = DateTime.Now - startTime; table.Rows.Add(new object[] { host, "down", attempt, data.LongLength, Spludlow.Text.DataSize(data.LongLength), took.TotalMilliseconds }); } foreach (string filename in fileList) Spludlow.Call.Now(host, "System", "System.IO.File", "Delete", new object[] { filename }); int[] result = new int[2]; result[0] = (int)Math.Round(Speed("up", table), 0); result[1] = (int)Math.Round(Speed("down", table), 0); Spludlow.Log.Report("UpDownSpeed:\t" + host + "\tU/D (MBytes/s):\t" + result[0] + "/" + result[1], new object[] { table, result }); return result; } private static decimal Speed(string direction, DataTable table) { ulong totalBytes = 0; ulong totalMilliSeconds = 0; DataRow[] rows = table.Select("Direction ='" + direction + "'"); foreach (DataRow row in rows) { int attempt = (int)row["Attempt"]; if (attempt != 0) { totalBytes += (ulong)row["Size"]; totalMilliSeconds += (ulong)row["Time"]; } } return ((decimal)totalBytes / ((decimal)totalMilliSeconds / 1000.0M)) / 1024.0M / 1024.0M; } private static byte[] RandomData(int floppySize) { int size = 1440 * 1024 * floppySize; byte[] data = new byte[size]; Random rand = new Random(); for (int index = 0; index < size; ++index) data[index] = (byte)rand.Next(256); return data; } public static int TestDisk(string drivePath, int fileSize, int fileCount, int readCount) { int errorCount = 0; using (TempDirectory tempDir = new TempDirectory(drivePath)) { List files = new List(); for (int fileIndex = 0; fileIndex < fileCount; ++fileIndex) { Console.WriteLine("WRITE:\t" + fileIndex); byte[] data = RandomData(fileSize); string fileName = tempDir.Path + @"\" + fileIndex.ToString("0000") + ".dat"; string checkSum = Spludlow.Hashing.MD5Hex(data); files.Add(new string[] { fileName, checkSum }); File.WriteAllBytes(fileName, data); } for (int readIndex = 0; readIndex < readCount; ++readIndex) { for (int fileIndex = 0; fileIndex < fileCount; ++fileIndex) { Console.WriteLine("READ:\t" + readIndex + "\t" + fileIndex); string[] words = files[fileIndex]; string fileName = words[0]; string checkSum = words[1]; byte[] data = File.ReadAllBytes(fileName); if (checkSum != Spludlow.Hashing.MD5Hex(data)) { Console.WriteLine("ERROR:\t" + fileName); ++errorCount; } } } } return errorCount; } } }