1+ using System ;
2+ using BenchmarkDotNet . Attributes ;
3+ using BenchmarkDotNet . Order ;
4+ using System . Collections . Generic ;
5+ using System . Runtime . CompilerServices ;
6+ using System . Runtime . InteropServices ;
7+ using BenchmarkDotNet . Jobs ;
8+
9+ public class ObjectForCWT
10+ {
11+ // Other data to make the object somewhat realistic
12+ public long DataField1 ;
13+ public string DataField2 ;
14+ }
15+
16+ public class StateMachine
17+ {
18+ public long TimeDebt ;
19+ public long LastDecayTime ;
20+ public long LastMovementTime ;
21+ }
22+
23+ public class ObjectWithDirectProperties
24+ {
25+ // Other data
26+ public long DataField1 ;
27+ public string DataField2 ;
28+
29+ // State machine properties
30+ public long TimeDebt ;
31+ public long LastDecayTime ;
32+ public long LastMovementTime ;
33+ }
34+
35+ [ SimpleJob ( RuntimeMoniker . Net10_0 ) ]
36+ [ Orderer ( SummaryOrderPolicy . FastestToSlowest ) ]
37+ public class BenchmarkConditionalWeakTable
38+ {
39+ private static readonly ConditionalWeakTable < ObjectForCWT , StateMachine > _cwt = new ( ) ;
40+ private List < ObjectForCWT > _cwtObjects ;
41+ private List < ObjectWithDirectProperties > _directObjects ;
42+
43+ [ Params ( 10 , 100 , 1000 ) ]
44+ public int N ;
45+
46+ [ GlobalSetup ]
47+ public void Setup ( )
48+ {
49+ _cwtObjects = new List < ObjectForCWT > ( N ) ;
50+ _directObjects = new List < ObjectWithDirectProperties > ( N ) ;
51+
52+ for ( int i = 0 ; i < N ; i ++ )
53+ {
54+ var cwtObj = new ObjectForCWT { DataField1 = i , DataField2 = $ "Object { i } " } ;
55+ var state = new StateMachine { TimeDebt = i , LastDecayTime = i - N , LastMovementTime = i * - N } ;
56+
57+ _cwtObjects . Add ( cwtObj ) ;
58+ _cwt . Add ( cwtObj , state ) ;
59+
60+ _directObjects . Add ( new ObjectWithDirectProperties
61+ {
62+ DataField1 = i ,
63+ DataField2 = $ "Object { i } ",
64+ TimeDebt = i ,
65+ LastDecayTime = i - N ,
66+ LastMovementTime = i * - N
67+ } ) ;
68+ }
69+ }
70+
71+ [ Benchmark ]
72+ public void ConditionalWeakTable_Access ( )
73+ {
74+ long totalState = 0 ;
75+ var span = CollectionsMarshal . AsSpan ( _cwtObjects ) ;
76+ for ( var i = 0 ; i < span . Length ; i ++ )
77+ {
78+ var obj = span [ i ] ;
79+ // The core operation: TryGetValue
80+ if ( _cwt . TryGetValue ( obj , out var state ) )
81+ {
82+ // Perform a simple read/write
83+ totalState += state ! . TimeDebt ++ ;
84+ }
85+ }
86+
87+ // Use the result to prevent dead code elimination
88+ if ( totalState == - 1 ) throw new Exception ( ) ;
89+ }
90+
91+ [ Benchmark ( Baseline = true ) ]
92+ public void DirectProperty_Access ( )
93+ {
94+ long totalState = 0 ;
95+ var span = CollectionsMarshal . AsSpan ( _directObjects ) ;
96+ for ( var i = 0 ; i < span . Length ; i ++ )
97+ {
98+ var obj = span [ i ] ;
99+ // The core operation: direct access
100+ totalState += obj . TimeDebt ++ ;
101+ }
102+
103+ // Use the result to prevent dead code elimination
104+ if ( totalState == - 1 ) throw new Exception ( ) ;
105+ }
106+ }
0 commit comments