@@ -14,203 +14,179 @@ namespace BitFaster.Caching.UnitTests.Lfu
1414 [ Collection ( "Soak" ) ]
1515 public class ConcurrentLfuSoakTests
1616 {
17- private const int iterations = 10 ;
17+ private const int soakIterations = 10 ;
18+ private const int threads = 4 ;
19+ private const int loopIterations = 100_000 ;
20+
1821 private readonly ITestOutputHelper output ;
1922 public ConcurrentLfuSoakTests ( ITestOutputHelper testOutputHelper )
2023 {
2124 this . output = testOutputHelper ;
2225 }
2326
2427 [ Theory ]
25- [ Repeat ( iterations ) ]
28+ [ Repeat ( soakIterations ) ]
2629 public async Task WhenConcurrentGetCacheEndsInConsistentState ( int iteration )
2730 {
28- var scheduler = new BackgroundThreadScheduler ( ) ;
29- var lfu = new ConcurrentLfuBuilder < int , string > ( ) . WithCapacity ( 9 ) . WithScheduler ( scheduler ) . Build ( ) as ConcurrentLfu < int , string > ;
31+ var lfu = CreateWithBackgroundScheduler ( ) ;
3032
31- await Threaded . Run ( 4 , ( ) => {
32- for ( int i = 0 ; i < 100000 ; i ++ )
33+ await Threaded . Run ( threads , ( ) => {
34+ for ( int i = 0 ; i < loopIterations ; i ++ )
3335 {
3436 lfu . GetOrAdd ( i + 1 , i => i . ToString ( ) ) ;
3537 }
3638 } ) ;
37-
38- this . output . WriteLine ( $ "iteration { iteration } keys={ string . Join ( " " , lfu . Keys ) } ") ;
39-
40- scheduler . Dispose ( ) ;
41- await scheduler . Completion ;
42-
43- RunIntegrityCheck ( lfu ) ;
39+
40+ await RunIntegrityCheckAsync ( lfu , iteration ) ;
4441 }
4542
4643 [ Theory ]
47- [ Repeat ( iterations ) ]
44+ [ Repeat ( soakIterations ) ]
4845 public async Task WhenConcurrentGetAsyncCacheEndsInConsistentState ( int iteration )
4946 {
50- var scheduler = new BackgroundThreadScheduler ( ) ;
51- var lfu = new ConcurrentLfuBuilder < int , string > ( ) . WithCapacity ( 9 ) . WithScheduler ( scheduler ) . Build ( ) as ConcurrentLfu < int , string > ;
47+ var lfu = CreateWithBackgroundScheduler ( ) ;
5248
53- await Threaded . RunAsync ( 4 , async ( ) => {
54- for ( int i = 0 ; i < 100000 ; i ++ )
49+ await Threaded . RunAsync ( threads , async ( ) => {
50+ for ( int i = 0 ; i < loopIterations ; i ++ )
5551 {
5652 await lfu . GetOrAddAsync ( i + 1 , i => Task . FromResult ( i . ToString ( ) ) ) ;
5753 }
58- } ) ;
59-
60- this . output . WriteLine ( $ "iteration { iteration } keys={ string . Join ( " " , lfu . Keys ) } ") ;
61-
62- scheduler . Dispose ( ) ;
63- await scheduler . Completion ;
54+ } ) ;
6455
65- RunIntegrityCheck ( lfu ) ;
56+ await RunIntegrityCheckAsync ( lfu , iteration ) ;
6657 }
6758
6859 [ Theory ]
69- [ Repeat ( iterations ) ]
60+ [ Repeat ( soakIterations ) ]
7061 public async Task WhenConcurrentGetWithArgCacheEndsInConsistentState ( int iteration )
7162 {
72- var scheduler = new BackgroundThreadScheduler ( ) ;
73- var lfu = new ConcurrentLfuBuilder < int , string > ( ) . WithCapacity ( 9 ) . WithScheduler ( scheduler ) . Build ( ) as ConcurrentLfu < int , string > ;
63+ var lfu = CreateWithBackgroundScheduler ( ) ;
7464
75- await Threaded . Run ( 4 , ( ) => {
76- for ( int i = 0 ; i < 100000 ; i ++ )
65+ await Threaded . Run ( threads , ( ) => {
66+ for ( int i = 0 ; i < loopIterations ; i ++ )
7767 {
7868 // use the arg overload
7969 lfu . GetOrAdd ( i + 1 , ( i , s ) => i . ToString ( ) , "Foo" ) ;
8070 }
8171 } ) ;
8272
83- this . output . WriteLine ( $ "iteration { iteration } keys={ string . Join ( " " , lfu . Keys ) } ") ;
84-
85- scheduler . Dispose ( ) ;
86- await scheduler . Completion ;
87-
88- RunIntegrityCheck ( lfu ) ;
73+ await RunIntegrityCheckAsync ( lfu , iteration ) ;
8974 }
9075
9176 [ Theory ]
92- [ Repeat ( iterations ) ]
77+ [ Repeat ( soakIterations ) ]
9378 public async Task WhenConcurrentGetAsyncWithArgCacheEndsInConsistentState ( int iteration )
9479 {
95- var scheduler = new BackgroundThreadScheduler ( ) ;
96- var lfu = new ConcurrentLfuBuilder < int , string > ( ) . WithCapacity ( 9 ) . WithScheduler ( scheduler ) . Build ( ) as ConcurrentLfu < int , string > ;
80+ var lfu = CreateWithBackgroundScheduler ( ) ;
9781
98- await Threaded . RunAsync ( 4 , async ( ) => {
99- for ( int i = 0 ; i < 100000 ; i ++ )
82+ await Threaded . RunAsync ( threads , async ( ) => {
83+ for ( int i = 0 ; i < loopIterations ; i ++ )
10084 {
10185 // use the arg overload
10286 await lfu . GetOrAddAsync ( i + 1 , ( i , s ) => Task . FromResult ( i . ToString ( ) ) , "Foo" ) ;
10387 }
10488 } ) ;
10589
106- this . output . WriteLine ( $ "iteration { iteration } keys={ string . Join ( " " , lfu . Keys ) } ") ;
107-
108- scheduler . Dispose ( ) ;
109- await scheduler . Completion ;
110-
111- RunIntegrityCheck ( lfu ) ;
90+ await RunIntegrityCheckAsync ( lfu , iteration ) ;
11291 }
11392
11493 [ Theory ]
115- [ Repeat ( iterations ) ]
94+ [ Repeat ( soakIterations ) ]
11695 public async Task WhenConcurrentGetAndUpdateCacheEndsInConsistentState ( int iteration )
11796 {
118- var scheduler = new BackgroundThreadScheduler ( ) ;
119- var lfu = new ConcurrentLfuBuilder < int , string > ( ) . WithCapacity ( 9 ) . WithScheduler ( scheduler ) . Build ( ) as ConcurrentLfu < int , string > ;
97+ var lfu = CreateWithBackgroundScheduler ( ) ;
12098
121- await Threaded . Run ( 4 , ( ) => {
122- for ( int i = 0 ; i < 100000 ; i ++ )
99+ await Threaded . Run ( threads , ( ) => {
100+ for ( int i = 0 ; i < loopIterations ; i ++ )
123101 {
124102 lfu . TryUpdate ( i + 1 , i . ToString ( ) ) ;
125103 lfu . GetOrAdd ( i + 1 , i => i . ToString ( ) ) ;
126104 }
127105 } ) ;
128106
129- this . output . WriteLine ( $ "iteration { iteration } keys={ string . Join ( " " , lfu . Keys ) } ") ;
130-
131- scheduler . Dispose ( ) ;
132- await scheduler . Completion ;
133-
134- RunIntegrityCheck ( lfu ) ;
107+ await RunIntegrityCheckAsync ( lfu , iteration ) ;
135108 }
136109
137110 [ Theory ]
138- [ Repeat ( iterations ) ]
111+ [ Repeat ( soakIterations ) ]
139112 public async Task WhenSoakConcurrentGetAndRemoveCacheEndsInConsistentState ( int iteration )
140113 {
141- var scheduler = new BackgroundThreadScheduler ( ) ;
142- var lfu = new ConcurrentLfuBuilder < int , string > ( ) . WithCapacity ( 9 ) . WithScheduler ( scheduler ) . Build ( ) as ConcurrentLfu < int , string > ;
114+ var lfu = CreateWithBackgroundScheduler ( ) ;
143115
144- await Threaded . Run ( 4 , ( ) => {
145- for ( int i = 0 ; i < 100000 ; i ++ )
116+ await Threaded . Run ( threads , ( ) => {
117+ for ( int i = 0 ; i < loopIterations ; i ++ )
146118 {
147119 lfu . TryRemove ( i + 1 ) ;
148120 lfu . GetOrAdd ( i + 1 , i => i . ToString ( ) ) ;
149121 }
150122 } ) ;
151123
152- this . output . WriteLine ( $ "iteration { iteration } keys={ string . Join ( " " , lfu . Keys ) } ") ;
153-
154- scheduler . Dispose ( ) ;
155- await scheduler . Completion ;
156-
157- RunIntegrityCheck ( lfu ) ;
124+ await RunIntegrityCheckAsync ( lfu , iteration ) ;
158125 }
159126
160127 [ Theory ]
161- [ Repeat ( iterations ) ]
128+ [ Repeat ( soakIterations ) ]
162129 public async Task WhenConcurrentGetAndRemoveKvpCacheEndsInConsistentState ( int iteration )
163130 {
164- var scheduler = new BackgroundThreadScheduler ( ) ;
165- var lfu = new ConcurrentLfuBuilder < int , string > ( ) . WithCapacity ( 9 ) . WithScheduler ( scheduler ) . Build ( ) as ConcurrentLfu < int , string > ;
131+ var lfu = CreateWithBackgroundScheduler ( ) ;
166132
167- await Threaded . Run ( 4 , ( ) => {
168- for ( int i = 0 ; i < 100000 ; i ++ )
133+ await Threaded . Run ( threads , ( ) => {
134+ for ( int i = 0 ; i < loopIterations ; i ++ )
169135 {
170136 lfu . TryRemove ( new KeyValuePair < int , string > ( i + 1 , ( i + 1 ) . ToString ( ) ) ) ;
171137 lfu . GetOrAdd ( i + 1 , i => i . ToString ( ) ) ;
172138 }
173139 } ) ;
174140
175- this . output . WriteLine ( $ "iteration { iteration } keys={ string . Join ( " " , lfu . Keys ) } ") ;
176-
177- scheduler . Dispose ( ) ;
178- await scheduler . Completion ;
179-
180- RunIntegrityCheck ( lfu ) ;
141+ await RunIntegrityCheckAsync ( lfu , iteration ) ;
181142 }
182143
183144 [ Fact ]
184145 public async Task ThreadedVerifyMisses ( )
185146 {
186147 // buffer size is 1, this will cause dropped writes on some threads where the buffer is full
187- var cache = new ConcurrentLfu < int , int > ( 1 , 20 , new NullScheduler ( ) , EqualityComparer < int > . Default ) ;
188-
189- int threads = 4 ;
190- int iterations = 100_000 ;
148+ var cache = new ConcurrentLfu < int , string > ( 1 , 20 , new NullScheduler ( ) , EqualityComparer < int > . Default ) ;
191149
192150 await Threaded . Run ( threads , i =>
193151 {
194- Func < int , int > func = x => x ;
152+ Func < int , string > func = x => x . ToString ( ) ;
195153
196- int start = i * iterations ;
154+ int start = i * loopIterations ;
197155
198- for ( int j = start ; j < start + iterations ; j ++ )
156+ for ( int j = start ; j < start + loopIterations ; j ++ )
199157 {
200158 cache . GetOrAdd ( j , func ) ;
201159 }
202160 } ) ;
203161
204- var samplePercent = cache . Metrics . Value . Misses / ( double ) iterations / threads * 100 ;
162+ var samplePercent = cache . Metrics . Value . Misses / ( double ) loopIterations / threads * 100 ;
205163
206164 this . output . WriteLine ( $ "Cache misses { cache . Metrics . Value . Misses } (sampled { samplePercent } %)") ;
207165 this . output . WriteLine ( $ "Maintenance ops { cache . Scheduler . RunCount } ") ;
208166
209- cache . Metrics . Value . Misses . Should ( ) . Be ( iterations * threads ) ;
167+ cache . Metrics . Value . Misses . Should ( ) . Be ( loopIterations * threads ) ;
210168 RunIntegrityCheck ( cache ) ;
211- }
169+ }
170+
171+ private ConcurrentLfu < int , string > CreateWithBackgroundScheduler ( )
172+ {
173+ var scheduler = new BackgroundThreadScheduler ( ) ;
174+ return new ConcurrentLfuBuilder < int , string > ( ) . WithCapacity ( 9 ) . WithScheduler ( scheduler ) . Build ( ) as ConcurrentLfu < int , string > ;
175+ }
176+
177+ private async Task RunIntegrityCheckAsync ( ConcurrentLfu < int , string > lfu , int iteration )
178+ {
179+ this . output . WriteLine ( $ "iteration { iteration } keys={ string . Join ( " " , lfu . Keys ) } ") ;
180+
181+ var scheduler = lfu . Scheduler as BackgroundThreadScheduler ;
182+ scheduler . Dispose ( ) ;
183+ await scheduler . Completion ;
184+
185+ RunIntegrityCheck ( lfu ) ;
186+ }
187+
212188
213- private void RunIntegrityCheck < K , V > ( ConcurrentLfu < K , V > cache )
189+ private static void RunIntegrityCheck < K , V > ( ConcurrentLfu < K , V > cache )
214190 {
215191 new ConcurrentLfuIntegrityChecker < K , V > ( cache ) . Validate ( ) ;
216192 }
0 commit comments