hlsf goes bad
This commit is contained in:
@@ -0,0 +1,322 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
// file="TestL4"
|
||||
// Project: StgSharp
|
||||
// AuthorGroup: Nitload
|
||||
// Copyright (c) Nitload. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using StgSharp.HighPerformance.Memory;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace StgSharp
|
||||
{
|
||||
// ====================================================================
|
||||
// SequentialPredictor
|
||||
// 辅助类:给定一批地址,每次 Predict 返回全部地址(幂等);
|
||||
// Prefetch 将缓存行填充为 0xAB,WriteBack 为空操作。
|
||||
// 仅供 L4 内存安全测试使用。
|
||||
// ====================================================================
|
||||
|
||||
internal sealed unsafe class SequentialPredictor : IL4Predict
|
||||
{
|
||||
|
||||
private readonly nuint[] _addresses;
|
||||
|
||||
public SequentialPredictor(
|
||||
nuint[] addresses
|
||||
)
|
||||
{
|
||||
_addresses = addresses;
|
||||
}
|
||||
|
||||
public bool Predict(
|
||||
Span<CacheLineDescription> node,
|
||||
out int count
|
||||
)
|
||||
{
|
||||
count = Math.Min(_addresses.Length, node.Length);
|
||||
for (int i = 0; i < count; i++) {
|
||||
node[i] = new CacheLineDescription
|
||||
{
|
||||
Address = _addresses[i],
|
||||
MapPolicy = 0,
|
||||
};
|
||||
}
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
// 将缓存行填充 0xAB,便于数据完整性断言
|
||||
public void Prefetch(
|
||||
nuint origin,
|
||||
ulong policy,
|
||||
Span<byte> cache
|
||||
)
|
||||
{
|
||||
cache.Fill(0xAB);
|
||||
}
|
||||
|
||||
// 只读路径测试:无需回写
|
||||
public void WriteBack(
|
||||
nuint origin,
|
||||
ulong policy,
|
||||
ReadOnlySpan<byte> cache
|
||||
) { }
|
||||
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// L4MemorySafetyTest — 挂载到 Program partial class
|
||||
// ====================================================================
|
||||
|
||||
internal static partial class Program
|
||||
{
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// 统一的断言辅助:条件为 false 时打印 FAIL 并记录失败数
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
private static int _l4FailCount;
|
||||
|
||||
// ================================================================
|
||||
// 入口:从 Main 调用 TestL4MemorySafety()
|
||||
// ================================================================
|
||||
|
||||
public static void TestL4MemorySafety()
|
||||
{
|
||||
_l4FailCount = 0;
|
||||
Console.WriteLine("=== L4 Memory Safety Tests (P0) ===");
|
||||
Console.WriteLine();
|
||||
|
||||
L4Test_Dispose_NoLeak();
|
||||
L4Test_Map_CacheHit_DataIntegrity();
|
||||
L4Test_CacheLine_Dispose_DecrementsCounts();
|
||||
L4Test_CacheLine_Dispose_Idempotent();
|
||||
|
||||
Console.WriteLine();
|
||||
if (_l4FailCount == 0)
|
||||
{
|
||||
Console.WriteLine("=== ALL P0 TESTS PASSED ===");
|
||||
} else
|
||||
{
|
||||
Console.WriteLine($"=== {_l4FailCount} TEST(S) FAILED ===");
|
||||
}
|
||||
}
|
||||
|
||||
private static void L4Assert(
|
||||
bool condition,
|
||||
string message,
|
||||
[CallerMemberName] string caller = "",
|
||||
[CallerLineNumber] int line = 0
|
||||
)
|
||||
{
|
||||
if (!condition)
|
||||
{
|
||||
Console.WriteLine($" [FAIL] {caller}:{line} {message}");
|
||||
_l4FailCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// P0-3 CacheLine_Dispose_DecrementsCounts
|
||||
// Dispose 后 refCount/activeCount 正确递减:
|
||||
// 连续 Map → Dispose 同一地址 3 轮,每轮都能拿到有效句柄。
|
||||
// 若 refCount 未递减,驱逐时 CAS 永远失败,缓存满后
|
||||
// Evict 超时会抛出 OverflowException。
|
||||
// ================================================================
|
||||
|
||||
private static void L4Test_CacheLine_Dispose_DecrementsCounts()
|
||||
{
|
||||
Console.Write("[P0-3] CacheLine_Dispose_DecrementsCounts ... ");
|
||||
try
|
||||
{
|
||||
nuint[] addresses = MakeL4FakeAddresses(1);
|
||||
using L4 l4 = new L4();
|
||||
l4.PrefetchPredict = new SequentialPredictor(addresses);
|
||||
|
||||
nuint target = addresses[0];
|
||||
bool passed = true;
|
||||
|
||||
for (int round = 0; round < 3; round++)
|
||||
{
|
||||
L4.CacheLine line = l4.Map(target);
|
||||
if (line.Address == nuint.Zero)
|
||||
{
|
||||
L4Assert(false,
|
||||
$"Round {round}: Map returned zero address");
|
||||
passed = false;
|
||||
line.Dispose();
|
||||
break;
|
||||
}
|
||||
line.Dispose();
|
||||
}
|
||||
|
||||
if (passed) {
|
||||
Console.WriteLine("PASS");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"FAIL ({ex.GetType().Name}: {ex.Message})");
|
||||
_l4FailCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// P0-4 CacheLine_Dispose_Idempotent
|
||||
// 对同一 CacheLine 连续 Dispose 两次:
|
||||
// - 不抛异常
|
||||
// - 计数未被双减:之后再次 Map 同地址仍能成功
|
||||
// ================================================================
|
||||
|
||||
private static void L4Test_CacheLine_Dispose_Idempotent()
|
||||
{
|
||||
Console.Write("[P0-4] CacheLine_Dispose_Idempotent ... ");
|
||||
try
|
||||
{
|
||||
nuint[] addresses = MakeL4FakeAddresses(1);
|
||||
using L4 l4 = new L4();
|
||||
l4.PrefetchPredict = new SequentialPredictor(addresses);
|
||||
|
||||
nuint target = addresses[0];
|
||||
|
||||
// 第一轮:Map → Dispose × 2
|
||||
L4.CacheLine line = l4.Map(target);
|
||||
line.Dispose(); // 正常释放
|
||||
line.Dispose(); // 幂等:_handle 已为 0,直接返回
|
||||
|
||||
// 第二轮:计数未双减,应仍能成功 Map
|
||||
L4.CacheLine line2 = l4.Map(target);
|
||||
L4Assert(line2.Address != nuint.Zero,
|
||||
"After double-dispose, Map should still return valid address");
|
||||
line2.Dispose();
|
||||
|
||||
if (_l4FailCount == 0) {
|
||||
Console.WriteLine("PASS");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"FAIL ({ex.GetType().Name}: {ex.Message})");
|
||||
_l4FailCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// P0-1 Dispose_NoLeak
|
||||
// 构造后立即 Dispose,不抛异常;连续 Dispose 两次幂等。
|
||||
// ================================================================
|
||||
|
||||
private static void L4Test_Dispose_NoLeak()
|
||||
{
|
||||
Console.Write("[P0-1] Dispose_NoLeak ... ");
|
||||
try
|
||||
{
|
||||
L4 l4 = new L4();
|
||||
l4.PrefetchPredict = new SequentialPredictor(Array.Empty<nuint>());
|
||||
|
||||
l4.Dispose(); // 第一次:正常释放
|
||||
l4.Dispose(); // 第二次:_disposed 保护,应幂等
|
||||
|
||||
Console.WriteLine("PASS");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"FAIL ({ex.GetType().Name}: {ex.Message})");
|
||||
_l4FailCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// P0-2 Map_CacheHit_DataIntegrity
|
||||
// 经由 SequentialPredictor 预取后,Map() 命中的缓存行数据
|
||||
// 应与 Prefetch() 写入的内容一致(全 0xAB)。
|
||||
//
|
||||
// 注意:需要 CacheLine 暴露 public nuint Address 才能读取内容。
|
||||
// 若该属性尚未暴露,本测试会编译报错,届时先添加该属性。
|
||||
// ================================================================
|
||||
|
||||
private static unsafe void L4Test_Map_CacheHit_DataIntegrity()
|
||||
{
|
||||
Console.Write("[P0-2] Map_CacheHit_DataIntegrity ... ");
|
||||
try
|
||||
{
|
||||
nuint[] addresses = MakeL4FakeAddresses(4);
|
||||
using L4 l4 = new L4();
|
||||
l4.PrefetchPredict = new SequentialPredictor(addresses);
|
||||
|
||||
// Map 触发内部同步 Prefetch,命中第一个地址
|
||||
L4.CacheLine line = l4.Map(addresses[0]);
|
||||
try
|
||||
{
|
||||
// 读取缓存行内容,应全为 0xAB
|
||||
ReadOnlySpan<byte> data = new ReadOnlySpan<byte>(
|
||||
(byte*)line.Address,
|
||||
8192 // CacheLineData.Data 固定 8192 字节
|
||||
);
|
||||
|
||||
bool allAb = true;
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
if (data[i] != 0xAB)
|
||||
{
|
||||
allAb = false;
|
||||
L4Assert(false,
|
||||
$"data[{i}] == 0x{data[i]:X2}, expected 0xAB");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allAb) {
|
||||
Console.WriteLine("PASS");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
line.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"FAIL ({ex.GetType().Name}: {ex.Message})");
|
||||
_l4FailCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// 生成 count 个互不相同的假地址(仅用作 SwissTable key,
|
||||
// 不会被解引用;偏移足够大以避开地址 0)
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
private static nuint[] MakeL4FakeAddresses(
|
||||
int count
|
||||
)
|
||||
{
|
||||
nuint[] result = new nuint[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
result[i] = (nuint)(0x1_0000_0000UL + (((ulong)i) * 0x1000));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user