Newer
Older
TIASShot / TIASshot.Tests / MemBenchSupport.cs
using System;
using System.Diagnostics;
using NUnit.Framework;
using OpenCvSharp;

namespace TIASshot.Tests {
    /// <summary>
    /// メモリ計測ベンチ(ConvertImageMemoryBenchmark / ContinuousShootMemoryBenchmark)が
    /// 共有する補助ロジック.
    ///
    /// - リーク版 ConvertImage の再現(ConvertImageLeaky)
    /// - 計測ユーティリティ(Sample / ReclaimNative / GB / MB / PrintRow)
    /// - 環境変数パースヘルパー(EnvInt / EnvDouble)
    ///
    /// 本番の ColorCorrector.ConvertImage(Mat,Mat) は通常ビルドでは修正後(中間 Mat を
    /// using 解放)であり,リーク挙動はこのクラスでのみ再現する.
    /// </summary>
    internal static class MemBenchSupport {

        // ---- リーク版 ConvertImage -----------------------------------------------

        /// <summary>
        /// 修正前(リーク版)の ConvertImage を忠実に再現したもの.
        /// 中間 Mat(flatten / extended / converted / convertedImage)を Dispose しない.
        /// (git 0003cc2^ の ColorCorrector.ConvertImage(Mat,Mat) と等価)
        ///
        /// 本番コードは無改造のため,リーク再現に必要な internal メソッド(ExtendMat)と
        /// 行列積のみを ColorCorrector インスタンス経由で利用する.
        /// </summary>
        internal static Mat ConvertImageLeaky(ColorCorrector corrector, Mat src, Mat conv) {
            if (src.Type() != MatType.CV_64FC3) {
                src.ConvertTo(src, MatType.CV_64FC3);
            }
            var flatten = src.Reshape(3, src.Height * src.Width);
            var extended = corrector.ExtendMat(flatten, conv.Rows);
            var converted = (extended * conv).ToMat();
            var convertedImage = converted.Reshape(3, src.Height);

            var convImg8 = new Mat();
            convertedImage.ConvertTo(convImg8, MatType.CV_8UC3);
            return convImg8; // flatten / extended / converted / convertedImage は放置(=リーク)
        }

        // ---- 計測ユーティリティ -------------------------------------------------

        /// <summary>現在のプロセスのメモリ使用量をサンプリングする.</summary>
        internal static (long priv, long ws) Sample() {
            using (var p = Process.GetCurrentProcess()) {
                p.Refresh();
                return (p.PrivateMemorySize64, p.WorkingSet64);
            }
        }

        /// <summary>未参照 Mat のネイティブメモリを GC+ファイナライザで回収する.</summary>
        internal static void ReclaimNative() {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
        }

        internal static double GB(long bytes) => bytes / (1024.0 * 1024.0 * 1024.0);
        internal static double MB(long bytes) => bytes / (1024.0 * 1024.0);

        internal static void PrintRow(string a, string b, string c) {
            TestContext.WriteLine($"{a,-24} | {b,-22} | {c,-22}");
        }

        // ---- 環境変数パースヘルパー ---------------------------------------------

        internal static int EnvInt(string name, int fallback) {
            var v = Environment.GetEnvironmentVariable(name);
            return int.TryParse(v, out var n) ? n : fallback;
        }

        internal static double EnvDouble(string name, double fallback) {
            var v = Environment.GetEnvironmentVariable(name);
            return double.TryParse(v, out var n) ? n : fallback;
        }
    }
}