Example #1
0
        private void AnalyzeBase(RawData rawData, IProgress <ProgressInfo> progress, CancellationToken cancellationToken)
        {
            var score = CombineLocationData(rawData.BlockOffsetMultiple, rawData.Data).ToArray();

            if (!score.Any())
            {
                return;
            }

            cancellationToken.ThrowIfCancellationRequested();

            // ------------------------
            // Process scores of steps.
            // ------------------------
            Dictionary <double, double> diskScoresStepAveraged;

            try
            {
                if (rawData.BlockOffsetMultiple == 0)                 // If initial step of run
                {
                    // Store initial score.
                    _diskScoresStep      = score;
                    _diskScoresStepCount = 1;

                    diskScoresStepAveraged = _diskScoresStep.ToDictionary(pair => pair.Key, pair => pair.Value);
                }
                else
                {
                    // Combine scores into one sequential score.
                    _diskScoresStep = _diskScoresStep
                                      .Concat(score)
                                      .OrderBy(x => x.Key)           // Order by locations.
                                      .ToArray();
                    _diskScoresStepCount++;

                    // Prepare score of averaged transfer rates (values) of locations (keys) within block size length.
                    diskScoresStepAveraged = new Dictionary <double, double>();

                    var blockSizeMibiBytes = (double)Settings.Current.BlockSize / 1024D;                     // Convert KiB to MiB.

                    foreach (var data in _diskScoresStep.Select((body, index) => new { body, index }))
                    {
                        var dataCopy = data;

                        var valueList = new List <double>();
                        var index     = dataCopy.index;
                        var keyBottom = dataCopy.body.Key - blockSizeMibiBytes;

                        do
                        {
                            valueList.Add(_diskScoresStep[index].Value);
                            index--;
                        } while ((0 <= index) && (keyBottom < _diskScoresStep[index].Key));

                        if (Settings.Current.RemovesOutlier && (3 <= valueList.Count))                         // Removing outliers from data less than 3 makes no sense.
                        {
                            // Remove outliers using average and standard deviation.
                            valueList = RemoveOutlier(valueList, 2).ToList();                             // This multiple (2) is to be considered.
                        }

                        diskScoresStepAveraged.Add(dataCopy.body.Key, valueList.Average());
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Failed to process scores of steps. {0}", ex);
                throw;
            }

            cancellationToken.ThrowIfCancellationRequested();

            // -----------------------
            // Process scores of runs.
            // -----------------------
            try
            {
                if (!_diskScoresRun.Any())                 // If initial step of initial run.
                {
                    // Store initial score.
                    _diskScoresRun.Add(diskScoresStepAveraged);

                    progress.Report(new ProgressInfo(_diskScoresRun[0]));
                }
                else
                {
                    if (rawData.BlockOffsetMultiple != 0)                     // If not initial step of run.
                    {
                        // Remove existing score of that run.
                        _diskScoresRun.RemoveAt(_diskScoresRun.Count - 1);
                    }

                    _diskScoresRun.Add(diskScoresStepAveraged);

                    // Prepare score of list of transfer rates (values) of the same locations (keys) over all runs.
                    var diskScoresRunAll = _diskScoresRun
                                           .AsParallel()
                                           .SelectMany(dict => dict)
                                           .ToLookup(pair => pair.Key, pair => pair.Value);

                    // Prepare score of averaged transfer rates (values) over all runs.
                    var diskScoresRunAllAveraged = new Dictionary <double, double>();

                    foreach (var data in diskScoresRunAll)
                    {
                        var dataArray = data.ToArray();

                        if (Settings.Current.RemovesOutlier && (3 <= dataArray.Length))                         // Removing outliers from data less than 3 makes no sense.
                        {
                            // Remove outliers using average and standard deviation.
                            dataArray = RemoveOutlier(dataArray, 2).ToArray();                             // This multiple (2) is to be considered.
                        }

                        diskScoresRunAllAveraged.Add(data.Key, dataArray.Average());
                    }

                    progress.Report(new ProgressInfo(diskScoresRunAllAveraged));
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Failed to process scores of runs. {0}", ex);
                throw;
            }
        }
Example #2
0
        /// <summary>
        /// Read disk by P/Invoke (synchronously and with cancellation).
        /// </summary>
        /// <param name="rawData">Raw data</param>
        /// <param name="cancellationToken">Cancellation token</param>
        /// <returns>Result data</returns>
        internal static RawData ReadDiskPInvoke(RawData rawData, CancellationToken cancellationToken)
        {
            var blockOffsetMultiple = rawData.BlockOffsetMultiple;

            SafeFileHandle hFile = null;

            try
            {
                // ----------
                // Read disk.
                // ----------
                // This section is based on sequential read test of CrystalDiskMark (3.0.2)
                // created by hiyohiyo (http://crystalmark.info/).

                // Get handle to disk.
                hFile = NativeMethod.CreateFile(
                    String.Format(@"\\.\PhysicalDrive{0}", Settings.Current.PhysicalDrive),
                    NativeMethod.GENERIC_READ,                     // Administrative privilege is required.
                    0,
                    IntPtr.Zero,
                    NativeMethod.OPEN_EXISTING,
                    NativeMethod.FILE_ATTRIBUTE_NORMAL | NativeMethod.FILE_FLAG_NO_BUFFERING | NativeMethod.FILE_FLAG_SEQUENTIAL_SCAN,
                    IntPtr.Zero);
                if (hFile == null || hFile.IsInvalid)
                {
                    // This is normal when this application is not run by administrator.
                    throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to get handle to disk.");
                }

                // Prepare parameters.
                var areaSizeActual = Settings.Current.AreaSize;                 // Area size for actual reading (MiB)
                if (0 < Settings.Current.BlockOffset)
                {
                    areaSizeActual -= 1;                                            // 1 is for the last MiB of area. If offset, it may exceed disk size.
                }
                int readNum = (areaSizeActual * 1024) / Settings.Current.BlockSize; // The number of reads

                int loopOuter = 1;                                                  // The number of outer loops
                int loopInner = readNum;                                            // The number of inner loops

                if (Settings.Current.AreaRatioInner < Settings.Current.AreaRatioOuter)
                {
                    loopOuter = (areaSizeActual * 1024) / (Settings.Current.BlockSize * Settings.Current.AreaRatioOuter);
                    loopInner = Settings.Current.AreaRatioInner;

                    readNum = loopInner * loopOuter;
                }

                var areaLocationBytes = (long)Settings.Current.AreaLocation * 1024L * 1024L;                              // Bytes
                var blockOffsetBytes  = (long)Settings.Current.BlockOffset * (long)blockOffsetMultiple * 1024L;           // Bytes
                var jumpBytes         = (long)Settings.Current.BlockSize * (long)Settings.Current.AreaRatioOuter * 1024L; // Bytes

                areaLocationBytes += blockOffsetBytes;

                var  buffSize = (uint)Settings.Current.BlockSize * 1024U; // Buffer size (Bytes)
                var  buff     = new byte[buffSize];                       // Buffer
                uint readSize = 0U;

                var sw      = new Stopwatch();
                var lapTime = new TimeSpan[readNum + 1];    // 1 is for leading zero time.
                lapTime[0] = TimeSpan.Zero;                 // Leading zero time

                for (int i = 0; i < loopOuter; i++)
                {
                    if (0 < i)
                    {
                        areaLocationBytes += jumpBytes;
                    }

                    // Move pointer.
                    var result1 = NativeMethod.SetFilePointerEx(
                        hFile,
                        areaLocationBytes,
                        IntPtr.Zero,
                        NativeMethod.FILE_BEGIN);
                    if (result1 == false)
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to move pointer.");
                    }

                    // Measure disk transfer rate (sequential read).
                    for (int j = 1; j <= loopInner; j++)
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        sw.Start();

                        var result2 = NativeMethod.ReadFile(
                            hFile,
                            buff,
                            buffSize,
                            ref readSize,
                            IntPtr.Zero);
                        if (result2 == false)
                        {
                            throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to measure disk transfer rate.");
                        }

                        sw.Stop();

                        lapTime[i * loopInner + j] = sw.Elapsed;
                    }
                }

                cancellationToken.ThrowIfCancellationRequested();

                // ----------------
                // Process results.
                // ----------------
                // Calculate each transfer rate.
                var data = new double[readNum];

                for (int i = 1; i <= readNum; i++)
                {
                    var timeEach  = (lapTime[i] - lapTime[i - 1]).TotalSeconds;                    // Second
                    var scoreEach = Math.Floor(buffSize / timeEach) / 1000000D;                    // MB/s

                    data[i - 1] = scoreEach;
                }

                // Calculate total transfer rate (just for reference).
                var totalTime = lapTime[readNum].TotalSeconds;                                // Second
                var totalRead = (double)Settings.Current.BlockSize * (double)readNum * 1024D; // Bytes

                var totalScore = Math.Floor(totalRead / totalTime) / 1000000D;                // MB/s

                // Compose outcome.
                var outcome = "[Start data]" + Environment.NewLine;

                int k = 0;
                for (int i = 0; i < readNum; i++)
                {
                    outcome += String.Format("{0:f6} ", data[i]);                     // Data have 6 decimal places.

                    k++;
                    if ((k == 6) |
                        (i == readNum - 1))
                    {
                        k        = 0;
                        outcome += Environment.NewLine;
                    }
                }

                outcome += "[End data]" + Environment.NewLine;
                outcome += String.Format("Total {0:f6} MB/s", totalScore);

                rawData.Result  = ReadResult.Success;
                rawData.Outcome = outcome;
                rawData.Data    = data;
            }
            catch (Win32Exception ex)
            {
                rawData.Result  = ReadResult.Failure;
                rawData.Message = String.Format("{0} (Code: {1}).", ex.Message.Substring(0, ex.Message.Length - 1), ex.ErrorCode);
            }
            catch (Exception ex)             // Including OperationCanceledException
            {
                rawData.Result  = ReadResult.Failure;
                rawData.Message = ex.Message;
            }
            finally
            {
                if (hFile != null)
                {
                    // CloseHandle is inappropriate to close SafeFileHandle.
                    // Dispose method is not necessary because Close method will call it internally.
                    hFile.Close();
                }
            }

            return(rawData);
        }
Example #3
0
        /// <summary>
        /// Read disk by native (synchronously).
        /// </summary>
        /// <param name="rawData">Raw data</param>
        /// <returns>Result data</returns>
        internal static RawData ReadDiskNative(RawData rawData)
        {
            if (!NativeExeExists)
            {
                rawData.Result  = ReadResult.Failure;
                rawData.Message = String.Format("Cannot find {0}.", _nativeExeFile);
                return(rawData);
            }

            var blockOffsetMultiple = rawData.BlockOffsetMultiple;

            try
            {
                var arguments = String.Format("{0} {1} {2} {3} {4}",
                                              Settings.Current.PhysicalDrive,
                                              Settings.Current.BlockSize,
                                              Settings.Current.BlockOffset * blockOffsetMultiple,
                                              Settings.Current.AreaSize,
                                              Settings.Current.AreaLocation);

                if (Settings.Current.AreaRatioInner < Settings.Current.AreaRatioOuter)
                {
                    arguments += String.Format(" {0} {1}",
                                               Settings.Current.AreaRatioInner,
                                               Settings.Current.AreaRatioOuter);
                }

                using (_readProcess = new Process
                {
                    StartInfo =
                    {
                        FileName               = _nativeExePath,
                        Verb                   = "RunAs",       // Run as administrator.
                        Arguments              = arguments,
                        UseShellExecute        = false,
                        CreateNoWindow         = true,
                        //WindowStyle = ProcessWindowStyle.Hidden,
                        RedirectStandardOutput = true,
                    }
                })
                {
                    _readProcess.Start();
                    var outcome = _readProcess.StandardOutput.ReadToEnd();
                    _readProcess.WaitForExit();

                    rawData.Result = (_readProcess.HasExited & (_readProcess.ExitCode == 0))
                                                ? ReadResult.Success
                                                : ReadResult.Failure;

                    rawData.Outcome = outcome;

                    switch (rawData.Result)
                    {
                    case ReadResult.Success:
                        rawData.Data = FindData(outcome);
                        break;

                    case ReadResult.Failure:
                        rawData.Message = FindMessage(outcome);
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                rawData.Result  = ReadResult.Failure;
                rawData.Message = String.Format("Failed to execute {0}. {1}", _nativeExeFile, ex.Message);
            }

            return(rawData);
        }
Example #4
0
 /// <summary>
 /// Read disk by P/Invoke (asynchronously and with cancellation).
 /// </summary>
 /// <param name="rawData">Raw data</param>
 /// <param name="cancellationToken">Cancellation token</param>
 /// <returns>Result data</returns>
 internal static async Task <RawData> ReadDiskPInvokeAsync(RawData rawData, CancellationToken cancellationToken)
 {
     return(await Task.Run(() => ReadDiskPInvoke(rawData, cancellationToken), cancellationToken));
 }