@@ -18,45 +18,69 @@ size_t BLOCK_ALIGNMENT = FixedBlockPool::calculate_block_alignment<float>();
18
18
TEST (FeatureEvictTest, CounterBasedEviction) {
19
19
static constexpr int NUM_SHARDS = 8 ;
20
20
auto executor_ = std::make_unique<folly::CPUThreadPoolExecutor>(4 );
21
- auto kv_store_ = std::make_unique<SynchronizedShardedMap<int64_t , float *>>(NUM_SHARDS, BLOCK_SIZE, BLOCK_ALIGNMENT);
21
+ auto kv_store_ = std::make_unique<SynchronizedShardedMap<int64_t , float *>>(
22
+ NUM_SHARDS, BLOCK_SIZE, BLOCK_ALIGNMENT);
22
23
23
24
// Insert test data
24
25
for (int i = 0 ; i < 1000 ; ++i) {
25
26
int shard_id = i % NUM_SHARDS;
26
27
auto wlock = kv_store_->by (shard_id).wlock ();
27
28
auto * pool = kv_store_->pool_by (shard_id);
28
29
auto * block = pool->allocate_t <float >();
30
+ ASSERT_NE (block, nullptr );
29
31
FixedBlockPool::set_key (block, i);
30
- FixedBlockPool::set_count (block, 1 ); // Initial score
32
+ FixedBlockPool::set_count (block, 1 );
31
33
FixedBlockPool::set_used (block, true );
32
- wlock->insert ({i, block});
34
+ auto result = wlock->insert ({i, block});
35
+ ASSERT_TRUE (result.second );
33
36
}
34
37
35
38
for (int i = 1000 ; i < 2000 ; ++i) {
36
39
int shard_id = i % NUM_SHARDS;
37
40
auto wlock = kv_store_->by (shard_id).wlock ();
38
41
auto * pool = kv_store_->pool_by (shard_id);
39
42
auto * block = pool->allocate_t <float >();
43
+ ASSERT_NE (block, nullptr );
40
44
FixedBlockPool::set_key (block, i);
41
- FixedBlockPool::set_count (block, 2 ); // Initial score
45
+ FixedBlockPool::set_count (block, 2 );
42
46
FixedBlockPool::set_used (block, true );
43
- wlock->insert ({i, block});
47
+ auto result = wlock->insert ({i, block});
48
+ ASSERT_TRUE (result.second );
49
+ }
50
+
51
+ size_t count_1_blocks = 0 , count_2_blocks = 0 ;
52
+ for (int shard_id = 0 ; shard_id < NUM_SHARDS; ++shard_id) {
53
+ auto rlock = kv_store_->by (shard_id).rlock ();
54
+ for (const auto & [key, block] : *rlock) {
55
+ uint32_t count = FixedBlockPool::get_count (block);
56
+ if (count == 1 )
57
+ count_1_blocks++;
58
+ else if (count == 2 )
59
+ count_2_blocks++;
60
+ ASSERT_TRUE (FixedBlockPool::get_used (block));
61
+ }
44
62
}
63
+ ASSERT_EQ (count_1_blocks, 1000 );
64
+ ASSERT_EQ (count_2_blocks, 1000 );
45
65
46
66
std::unique_ptr<FeatureEvict<float >> feature_evict;
47
67
int evict_trigger_mode = 2 ;
48
68
int evict_trigger_strategy = 1 ;
49
69
uint32_t count_threshold = 1 ;
50
70
float count_decay_rate = 0.5 ;
51
- // feature evict config
52
- FeatureEvictConfig feature_evict_config;
53
- feature_evict_config.trigger_mode = static_cast <EvictTriggerMode>(evict_trigger_mode);
54
- feature_evict_config.trigger_strategy = static_cast <EvictTriggerStrategy>(evict_trigger_strategy);
71
+
72
+ FeatureEvictConfig feature_evict_config{};
73
+ feature_evict_config.trigger_mode =
74
+ static_cast <EvictTriggerMode>(evict_trigger_mode);
75
+ feature_evict_config.trigger_strategy =
76
+ static_cast <EvictTriggerStrategy>(evict_trigger_strategy);
55
77
feature_evict_config.count_threshold = count_threshold;
56
78
feature_evict_config.count_decay_rate = count_decay_rate;
57
79
58
80
if (feature_evict_config.trigger_mode != EvictTriggerMode::DISABLED) {
59
- feature_evict = create_feature_evict (feature_evict_config, executor_.get (),*kv_store_.get (), 4 );
81
+ feature_evict = create_feature_evict (
82
+ feature_evict_config, executor_.get (), *kv_store_.get (), 4 );
83
+ ASSERT_NE (feature_evict, nullptr );
60
84
}
61
85
62
86
// Initial validation
@@ -69,69 +93,101 @@ TEST(FeatureEvictTest, CounterBasedEviction) {
69
93
70
94
// Perform eviction
71
95
feature_evict->trigger_evict ();
96
+ ASSERT_TRUE (feature_evict->is_evicting ());
72
97
73
98
// Validate eviction process
74
- while (feature_evict->is_evicting ()) {
99
+ int max_iterations = 1000 ;
100
+ int iterations = 0 ;
101
+ while (feature_evict->is_evicting () && iterations < max_iterations) {
75
102
feature_evict->resume ();
76
103
std::this_thread::sleep_for (std::chrono::microseconds (5 ));
77
104
feature_evict->pause ();
105
+ iterations++;
78
106
}
107
+ ASSERT_LT (iterations, max_iterations);
108
+ ASSERT_FALSE (feature_evict->is_evicting ());
79
109
80
110
// Validate results
81
111
size_t remaining = 0 ;
112
+ size_t remaining_count_1 = 0 ;
82
113
for (int shard_id = 0 ; shard_id < NUM_SHARDS; ++shard_id) {
83
114
auto rlock = kv_store_->by (shard_id).rlock ();
84
115
remaining += rlock->size ();
85
116
// Validate score decay
86
117
for (const auto & [key, block] : *rlock) {
87
- ASSERT_EQ (FixedBlockPool::get_count (block), 1 );
118
+ uint32_t count = FixedBlockPool::get_count (block);
119
+ ASSERT_EQ (count, 1 );
120
+ if (count == 1 ) remaining_count_1++;
88
121
}
89
122
}
90
123
std::cout << " remaining: " << remaining << std::endl;
91
124
ASSERT_EQ (remaining, 1000 );
125
+ ASSERT_EQ (remaining_count_1, 1000 );
92
126
}
93
127
94
128
TEST (FeatureEvictTest, TimeBasedEviction) {
95
129
static constexpr int NUM_SHARDS = 8 ;
96
130
auto executor_ = std::make_unique<folly::CPUThreadPoolExecutor>(4 );
97
- auto kv_store_ = std::make_unique<SynchronizedShardedMap<int64_t , float *>>(NUM_SHARDS, BLOCK_SIZE, BLOCK_ALIGNMENT);
131
+ auto kv_store_ = std::make_unique<SynchronizedShardedMap<int64_t , float *>>(
132
+ NUM_SHARDS, BLOCK_SIZE, BLOCK_ALIGNMENT);
133
+
134
+ auto start_time = std::chrono::steady_clock::now ();
98
135
99
136
// Insert test data
100
137
for (int i = 0 ; i < 1000 ; ++i) {
101
138
int shard_id = i % NUM_SHARDS;
102
139
auto wlock = kv_store_->by (shard_id).wlock ();
103
140
auto * pool = kv_store_->pool_by (shard_id);
104
141
auto * block = pool->allocate_t <float >();
142
+ ASSERT_NE (block, nullptr );
105
143
FixedBlockPool::set_key (block, i);
106
- FixedBlockPool::update_timestamp (block); // Initial score
144
+ FixedBlockPool::update_timestamp (block);
107
145
FixedBlockPool::set_used (block, true );
108
- wlock->insert ({i, block});
146
+ auto result = wlock->insert ({i, block});
147
+ ASSERT_TRUE (result.second );
109
148
}
149
+
110
150
std::this_thread::sleep_for (std::chrono::seconds (5 ));
151
+ auto mid_time = std::chrono::steady_clock::now ();
111
152
112
153
for (int i = 1000 ; i < 2000 ; ++i) {
113
154
int shard_id = i % NUM_SHARDS;
114
155
auto wlock = kv_store_->by (shard_id).wlock ();
115
156
auto * pool = kv_store_->pool_by (shard_id);
116
157
auto * block = pool->allocate_t <float >();
158
+ ASSERT_NE (block, nullptr );
117
159
FixedBlockPool::set_key (block, i);
118
- FixedBlockPool::update_timestamp (block); // Initial score
160
+ FixedBlockPool::update_timestamp (block);
119
161
FixedBlockPool::set_used (block, true );
120
- wlock->insert ({i, block});
162
+ auto result = wlock->insert ({i, block});
163
+ ASSERT_TRUE (result.second );
121
164
}
122
165
166
+ auto current_time = std::chrono::steady_clock::now ();
167
+ auto old_blocks_age = std::chrono::duration_cast<std::chrono::seconds>(
168
+ current_time - start_time)
169
+ .count ();
170
+ auto new_blocks_age =
171
+ std::chrono::duration_cast<std::chrono::seconds>(current_time - mid_time)
172
+ .count ();
173
+ ASSERT_GT (old_blocks_age, new_blocks_age); // 确保时间差异存在
174
+
123
175
std::unique_ptr<FeatureEvict<float >> feature_evict;
124
176
int evict_trigger_mode = 2 ;
125
177
int evict_trigger_strategy = 0 ;
126
178
uint32_t ttl = 4 ;
127
- // feature evict config
179
+
128
180
FeatureEvictConfig feature_evict_config;
129
- feature_evict_config.trigger_mode = static_cast <EvictTriggerMode>(evict_trigger_mode);
130
- feature_evict_config.trigger_strategy = static_cast <EvictTriggerStrategy>(evict_trigger_strategy);
181
+ feature_evict_config.trigger_mode =
182
+ static_cast <EvictTriggerMode>(evict_trigger_mode);
183
+ feature_evict_config.trigger_strategy =
184
+ static_cast <EvictTriggerStrategy>(evict_trigger_strategy);
131
185
feature_evict_config.ttl = ttl;
132
186
133
187
if (feature_evict_config.trigger_mode != EvictTriggerMode::DISABLED) {
134
- feature_evict = create_feature_evict (feature_evict_config, executor_.get (),*kv_store_.get (), 4 );
188
+ feature_evict = create_feature_evict (
189
+ feature_evict_config, executor_.get (), *kv_store_.get (), 4 );
190
+ ASSERT_NE (feature_evict, nullptr );
135
191
}
136
192
137
193
// Initial validation
@@ -144,28 +200,40 @@ TEST(FeatureEvictTest, TimeBasedEviction) {
144
200
145
201
// Perform eviction
146
202
feature_evict->trigger_evict ();
203
+ ASSERT_TRUE (feature_evict->is_evicting ());
147
204
148
205
// Validate eviction process
149
- while (feature_evict->is_evicting ()) {
206
+ int max_iterations = 1000 ;
207
+ int iterations = 0 ;
208
+ while (feature_evict->is_evicting () && iterations < max_iterations) {
150
209
feature_evict->resume ();
151
210
std::this_thread::sleep_for (std::chrono::microseconds (5 ));
152
211
feature_evict->pause ();
212
+ iterations++;
153
213
}
214
+ ASSERT_LT (iterations, max_iterations);
215
+ ASSERT_FALSE (feature_evict->is_evicting ());
154
216
155
217
// Validate results
156
218
size_t remaining = 0 ;
219
+ size_t newer_blocks = 0 ;
157
220
for (int shard_id = 0 ; shard_id < NUM_SHARDS; ++shard_id) {
158
221
auto rlock = kv_store_->by (shard_id).rlock ();
159
222
remaining += rlock->size ();
223
+ for (const auto & [key, block] : *rlock) {
224
+ if (key >= 1000 ) newer_blocks++;
225
+ ASSERT_TRUE (FixedBlockPool::get_used (block));
226
+ }
160
227
}
161
228
std::cout << " remaining: " << remaining << std::endl;
162
229
ASSERT_EQ (remaining, 1000 );
230
+ ASSERT_GT (newer_blocks, 800 );
163
231
}
164
-
165
232
TEST (FeatureEvictTest, TimeCounterBasedEviction) {
166
233
static constexpr int NUM_SHARDS = 8 ;
167
234
auto executor_ = std::make_unique<folly::CPUThreadPoolExecutor>(4 );
168
- auto kv_store_ = std::make_unique<SynchronizedShardedMap<int64_t , float *>>(NUM_SHARDS, BLOCK_SIZE, BLOCK_ALIGNMENT);
235
+ auto kv_store_ = std::make_unique<SynchronizedShardedMap<int64_t , float *>>(
236
+ NUM_SHARDS, BLOCK_SIZE, BLOCK_ALIGNMENT);
169
237
170
238
// Insert test data
171
239
for (int i = 0 ; i < 500 ; ++i) {
@@ -198,7 +266,7 @@ TEST(FeatureEvictTest, TimeCounterBasedEviction) {
198
266
auto * pool = kv_store_->pool_by (shard_id);
199
267
auto * block = pool->allocate_t <float >();
200
268
FixedBlockPool::set_key (block, i);
201
- FixedBlockPool::update_timestamp (block); // Initial score
269
+ FixedBlockPool::update_timestamp (block); // Initial score
202
270
FixedBlockPool::set_count (block, 2 );
203
271
FixedBlockPool::set_used (block, true );
204
272
wlock->insert ({i, block});
@@ -213,14 +281,17 @@ TEST(FeatureEvictTest, TimeCounterBasedEviction) {
213
281
214
282
// feature evict config
215
283
FeatureEvictConfig feature_evict_config;
216
- feature_evict_config.trigger_mode = static_cast <EvictTriggerMode>(evict_trigger_mode);
217
- feature_evict_config.trigger_strategy = static_cast <EvictTriggerStrategy>(evict_trigger_strategy);
284
+ feature_evict_config.trigger_mode =
285
+ static_cast <EvictTriggerMode>(evict_trigger_mode);
286
+ feature_evict_config.trigger_strategy =
287
+ static_cast <EvictTriggerStrategy>(evict_trigger_strategy);
218
288
feature_evict_config.ttl = ttl;
219
289
feature_evict_config.count_threshold = count_threshold;
220
290
feature_evict_config.count_decay_rate = count_decay_rate;
221
291
222
292
if (feature_evict_config.trigger_mode != EvictTriggerMode::DISABLED) {
223
- feature_evict = create_feature_evict (feature_evict_config, executor_.get (),*kv_store_.get (), 4 );
293
+ feature_evict = create_feature_evict (
294
+ feature_evict_config, executor_.get (), *kv_store_.get (), 4 );
224
295
}
225
296
226
297
// Initial validation
@@ -254,7 +325,8 @@ TEST(FeatureEvictTest, TimeCounterBasedEviction) {
254
325
TEST (FeatureEvictTest, L2WeightBasedEviction) {
255
326
static constexpr int NUM_SHARDS = 8 ;
256
327
auto executor_ = std::make_unique<folly::CPUThreadPoolExecutor>(4 );
257
- auto kv_store_ = std::make_unique<SynchronizedShardedMap<int64_t , float *>>(NUM_SHARDS, BLOCK_SIZE, BLOCK_ALIGNMENT);
328
+ auto kv_store_ = std::make_unique<SynchronizedShardedMap<int64_t , float *>>(
329
+ NUM_SHARDS, BLOCK_SIZE, BLOCK_ALIGNMENT);
258
330
int dim = 4 ;
259
331
std::vector<float > weight1 (dim, 1.0 );
260
332
// Insert test data
@@ -288,12 +360,15 @@ TEST(FeatureEvictTest, L2WeightBasedEviction) {
288
360
double l2_weight_threshold = 3.0 ;
289
361
// feature evict config
290
362
FeatureEvictConfig feature_evict_config;
291
- feature_evict_config.trigger_mode = static_cast <EvictTriggerMode>(evict_trigger_mode);
292
- feature_evict_config.trigger_strategy = static_cast <EvictTriggerStrategy>(evict_trigger_strategy);
363
+ feature_evict_config.trigger_mode =
364
+ static_cast <EvictTriggerMode>(evict_trigger_mode);
365
+ feature_evict_config.trigger_strategy =
366
+ static_cast <EvictTriggerStrategy>(evict_trigger_strategy);
293
367
feature_evict_config.l2_weight_threshold = l2_weight_threshold;
294
368
295
369
if (feature_evict_config.trigger_mode != EvictTriggerMode::DISABLED) {
296
- feature_evict = create_feature_evict (feature_evict_config, executor_.get (),*kv_store_.get (), dim);
370
+ feature_evict = create_feature_evict (
371
+ feature_evict_config, executor_.get (), *kv_store_.get (), dim);
297
372
}
298
373
299
374
// Initial validation
@@ -327,7 +402,8 @@ TEST(FeatureEvictTest, L2WeightBasedEviction) {
327
402
TEST (FeatureEvictTest, PerformanceTest) {
328
403
static constexpr int NUM_SHARDS = 1 ;
329
404
// Test configurations
330
- const std::vector<int > test_sizes = {100'000 , 500'000 , 1'000'000 , 5'000'000 , 10'000'000 };
405
+ const std::vector<int > test_sizes = {
406
+ 100'000 , 500'000 , 1'000'000 , 5'000'000 , 10'000'000 };
331
407
332
408
fmt::print (" \n Performance Test Results:\n " );
333
409
fmt::print (" {:<15} {:<15} {:<15}\n " , " Size" , " Time(ms)" , " Items/ms" );
@@ -336,8 +412,8 @@ TEST(FeatureEvictTest, PerformanceTest) {
336
412
for (const auto & size : test_sizes) {
337
413
// Create executor and store for each test size
338
414
auto executor = std::make_unique<folly::CPUThreadPoolExecutor>(8 );
339
- auto kv_store =
340
- std::make_unique<SynchronizedShardedMap< int64_t , float *>>( NUM_SHARDS, BLOCK_SIZE, BLOCK_ALIGNMENT, 1000 );
415
+ auto kv_store = std::make_unique<SynchronizedShardedMap< int64_t , float *>>(
416
+ NUM_SHARDS, BLOCK_SIZE, BLOCK_ALIGNMENT, 1000 );
341
417
342
418
// Insert test data with different initial scores
343
419
for (int i = 0 ; i < size; ++i) {
@@ -346,7 +422,8 @@ TEST(FeatureEvictTest, PerformanceTest) {
346
422
auto * pool = kv_store->pool_by (shard_id);
347
423
auto * block = pool->allocate_t <float >();
348
424
FixedBlockPool::set_key (block, i);
349
- FixedBlockPool::set_count (block, (i % 2 ) ? 1 : 2 ); // Alternate between scores
425
+ FixedBlockPool::set_count (block,
426
+ (i % 2 ) ? 1 : 2 ); // Alternate between scores
350
427
FixedBlockPool::set_used (block, true );
351
428
wlock->insert ({i, block});
352
429
}
@@ -365,17 +442,22 @@ TEST(FeatureEvictTest, PerformanceTest) {
365
442
}
366
443
367
444
auto end_time = std::chrono::high_resolution_clock::now ();
368
- auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count ();
445
+ auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
446
+ end_time - start_time)
447
+ .count ();
369
448
370
449
std::size_t current_size = 0 ;
371
450
for (int shard_id = 0 ; shard_id < NUM_SHARDS; ++shard_id) {
372
451
auto wlock = kv_store->by (shard_id).wlock ();
373
452
current_size += wlock->size ();
374
453
}
375
- double eviction_rate = static_cast <double >(size - current_size) / static_cast <double >(size);
454
+ double eviction_rate =
455
+ static_cast <double >(size - current_size) / static_cast <double >(size);
376
456
377
457
// Print results
378
458
fmt::print (" {:<15d} {:<15d} {:<15.2f}\n " , size, duration, eviction_rate);
459
+ ASSERT_LT (current_size, size);
460
+ ASSERT_GT (eviction_rate, 0.0 );
379
461
}
380
462
}
381
463
} // namespace kv_mem
0 commit comments