x86 LargeAddressAware兼容性的单元测试

对于win32可执行文件(x86),我们可以设置LargeAddressAware标志,以便在x64 Windows上运行时可以访问4 GB(而不是2 GB)的虚拟地址空间。
这看起来非常有吸引力。 但是,涉及风险。
例如,请参阅:在32位Windows可执行文件中使用/ LARGEADDRESSAWARE的缺点?

因此,让我们继续并配置正在执行某些单元测试的系统,并将全系统注册表开关AllocationPreference设置为MEM_TOP_DOWN
应该这样做,不是吗?

它不!
问题在于Visual Studio的x86“测试运行器”(执行引擎)本身不是LAA启用的。
这个父进程只会看到“低”2 GB的VAS,我们的模块也会被测试。

来自VS2013.1的例子

  • mstest.exe产生QTAgent32.exe
  • vstest.console.exe产生vstest.executionengine.x86.exe
  • 所有这些都不是LAA启用!

    那么推荐使用启用LAA的x86测试运行器的方式是什么?


    这里有一个代码片段(VS单元测试,csharp)来检查LAA执行环境。
    除非它成功,否则你的测试环境适合让你的单元测试(也)覆盖与LAA的兼容性:

    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    
    namespace TestCheckEnv32LAA
    {
        [TestClass]
        public class CheckEnv32LAA
        {
            #region [Native DLL import]
    
            [Flags()]
            public enum AllocationType : uint
            {
                COMMIT = 0x1000,
                RESERVE = 0x2000,
                RESET = 0x80000,
                LARGE_PAGES = 0x20000000,
                PHYSICAL = 0x400000,
                TOP_DOWN = 0x100000,
                WRITE_WATCH = 0x200000
            }
    
            [Flags()]
            public enum MemoryProtection : uint
            {
                EXECUTE = 0x10,
                EXECUTE_READ = 0x20,
                EXECUTE_READWRITE = 0x40,
                EXECUTE_WRITECOPY = 0x80,
                NOACCESS = 0x01,
                READONLY = 0x02,
                READWRITE = 0x04,
                WRITECOPY = 0x08,
                GUARD_Modifierflag = 0x100,
                NOCACHE_Modifierflag = 0x200,
                WRITECOMBINE_Modifierflag = 0x400
            }
    
            [StructLayout(LayoutKind.Sequential)]
            struct MEMORYSTATUSEX
            {
                public uint dwLength;
                public uint dwMemoryLoad;
                public ulong ullTotalPhys;
                public ulong ullAvailPhys;
                public ulong ullTotalPageFile;
                public ulong ullAvailPageFile;
                public ulong ullTotalVirtual;
                public ulong ullAvailVirtual;
                public ulong ullAvailExtendedVirtual;
            }
    
            [DllImport("kernel32.dll")]
            extern static void GlobalMemoryStatusEx(ref MEMORYSTATUSEX status);
    
            [DllImport("kernel32.dll", SetLastError = true)]
            public static extern UIntPtr VirtualAlloc(UIntPtr lpAddress, UIntPtr dwSize,
            AllocationType flAllocationType, MemoryProtection flProtect);
    
            #endregion
    
            public CheckEnv32LAA()
            {
            }
    
            [TestMethod]
            public void CheckEnvironment32LAA()
            {
                // check for a suitable environment to test modules for compatibility with LargeAddressAware (LAA):
                // 1) OS must be x64
                // 2) test runner must be x86
                // 3) test runner must be LAA enabled itself
                // 4) memory allocation (with manual TopDown flag) must happen beyond the 2 GB boundary
                // 5) memory allocation (with default settings) must happen beyond the 2 GB boundary
                //
                // RE 3) this requirement is true for "regular" unit tests (to test DLL modules). it does not apply
                // for any tests spawning the application (EXE) to be tested as a separate process.
                // 
                // RE 5) a failure indicates the following registry switch has not been set:
                // [HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSession ManagerMemory Management]
                // "AllocationPreference"=dword:00100000
                //
                // see:
                // https://stackoverflow.com/questions/2288728/
    
                String sParentProcName = Process.GetCurrentProcess().MainModule.FileName;
    
                //CHECK_1
                Assert.IsTrue(Environment.Is64BitOperatingSystem, "Test is not executing on x64 OS");
    
                //CHECK_2
                Assert.IsFalse(Environment.Is64BitProcess, "Test runner is not x86: " + sParentProcName);
    
                //CHECK_3
                MEMORYSTATUSEX tmpStatus = new MEMORYSTATUSEX();
                tmpStatus.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
                tmpStatus.ullTotalPhys = 0;
                GlobalMemoryStatusEx(ref tmpStatus);
                ulong uVM = tmpStatus.ullTotalVirtual;
                Assert.IsTrue(uVM > 0x80000000, "Test runner is not LAA enabled (max: " + uVM / (1024 * 1024) + "): " + sParentProcName);
                Assert.IsTrue(uVM <= 0x100000000, "Test runner is not x86 (max: " + uVM / (1024 * 1024) + "): " + sParentProcName);
    
                //CHECK_4
                UIntPtr pMem = UIntPtr.Zero;
                ulong uAddress = 0;
                pMem = VirtualAlloc(UIntPtr.Zero, (UIntPtr)1024, AllocationType.RESERVE | AllocationType.TOP_DOWN, MemoryProtection.READWRITE);
                uAddress = (ulong)pMem;
                Assert.IsTrue(uAddress > 0x80000000, "Test runner is not LAA enabled (highest: " + uAddress / (1024 * 1024) + "): " + sParentProcName);
    
                //CHECK_5
                pMem = VirtualAlloc(UIntPtr.Zero, (UIntPtr)1024, AllocationType.RESERVE, MemoryProtection.READWRITE);
                uAddress = (ulong)pMem;
                Assert.IsTrue(uAddress > 0x80000000, "System-wide MEM_TOP_DOWN is not set (allocated at: " + uAddress / (1024 * 1024) + ")");
            }
        }
    }
    

    到目前为止,我只是遇到了一些建议,想要解决问题中列出的Microsoft二进制文件(例如使用editbin.exe手动“修补”它们)。 但是这有以下缺点:

  • 一旦为Visual Studio安装了任何未来的Service Pack,我需要重复修补
  • 我不能再同时测试:使用LAA的“常规”x86和“扩展”x86
  • 这似乎是一个适当的长期解决方案必须由微软实施?:
    http://visualstudio.uservoice.com/forums/196039-microsoft-test-tools/suggestions/5781437

    链接地址: http://www.djcxy.com/p/20033.html

    上一篇: Unit Testing for x86 LargeAddressAware compatibility

    下一篇: What is the fastest way to create the union of many boost::polygons?