Changeset 9f7fff4
- Timestamp:
- Jun 30, 2020, 1:56:55 PM (5 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- 8291293
- Parents:
- 7812a7b5
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
TabularUnified examples/hashtable2.cfa ¶
r7812a7b5 r9f7fff4 32 32 DATA_EXCEPTION(ht_fill_limit_crossed)( 33 33 void * theHashtable; 34 bool want_throwResume_ht_auto_resize_pending; 35 size_t size_for_ht_auto_resize_pending; 34 36 ); 35 37 … … 37 39 VTABLE_INIT(this, ht_fill_limit_crossed); 38 40 this.theHashtable = theHashtable; 41 this.want_throwResume_ht_auto_resize_pending = false; 42 this.size_for_ht_auto_resize_pending = 0; 39 43 } 40 44 … … 45 49 VTABLE_INSTANCE(ht_fill_limit_crossed)(ht_fill_limit_crossed_msg); 46 50 51 52 DATA_EXCEPTION(ht_auto_resize_pending)( 53 void * theHashtable; 54 size_t new_size; 55 ); 56 57 void ?{}(ht_auto_resize_pending & this, void * theHashtable, size_t new_size) { 58 VTABLE_INIT(this, ht_auto_resize_pending); 59 this.theHashtable = theHashtable; 60 this.new_size = new_size; 61 } 62 63 const char * ht_auto_resize_pending_msg(ht_auto_resize_pending * this) { 64 return "ht_auto_resize_pending"; 65 } 66 67 VTABLE_INSTANCE(ht_auto_resize_pending)(ht_auto_resize_pending_msg); 47 68 48 69 … … 75 96 size_t item_count; 76 97 float ff_next_warn_up; 98 float ff_warn_step_factor; 77 99 78 100 void (*defaultResumptionHandler) (ht_fill_limit_crossed &); … … 84 106 forall( otype Tt_unused | pretendsToMatter(Tt_unused) | { void defaultResumptionHandler(ht_fill_limit_crossed &); } ) { 85 107 86 void ?{}( hashtable_rbs(Tt_unused) & this, size_t n_buckets, dlist(request_in_ht_by_src, request) *buckets ) { 108 void ?{}( hashtable_rbs(Tt_unused) & this, size_t n_buckets, dlist(request_in_ht_by_src, request) *buckets, 109 float ff_next_warn_up, float ff_warn_step_factor ) { 110 111 printf( "base hashtable ctor with %ld buckets at %p\n", n_buckets, buckets); 87 112 88 113 this.n_buckets = n_buckets; … … 90 115 91 116 this.item_count = 0; 92 this.ff_next_warn_up = 0.5; 117 this.ff_next_warn_up = ff_next_warn_up; 118 this.ff_warn_step_factor = ff_warn_step_factor; 93 119 94 120 this.defaultResumptionHandler = defaultResumptionHandler; … … 98 124 } 99 125 } 100 } 101 126 127 void ?{}( hashtable_rbs(Tt_unused) & this, size_t n_buckets, dlist(request_in_ht_by_src, request) *buckets ) { 128 printf( "base hashtable ctor with default warning steps\n" ); 129 ( this ) { n_buckets, buckets, 0.5, 2 }; 130 } 131 132 } 133 134 // this fwd declaration is artifact of workaround trac#192 135 void defaultResumptionHandler( ht_auto_resize_pending & ex ); 102 136 103 137 forall( otype Tt_unused | pretendsToMatter(Tt_unused) ) { … … 126 160 void check_ff_warning( hashtable_rbs(Tt_unused) & this ) with (this) { 127 161 if (fill_frac(this) > ff_next_warn_up) { 128 throwResume (ht_fill_limit_crossed){ &this }; 162 ht_fill_limit_crossed ex1 = { &this }; 163 throwResume ex1; 164 // workaround trac#192: want the second throwResume to be in __dynamic_defaultResumptionHandler 165 // ... want base hashtable decoupled from resize 166 if ( ex1.want_throwResume_ht_auto_resize_pending ) { 167 throwResume( (ht_auto_resize_pending) { & this, ex1.size_for_ht_auto_resize_pending } ); 168 } 129 169 } 130 170 } … … 170 210 171 211 void defaultResumptionHandler(ht_fill_limit_crossed & ex) { 172 printf("default resumption ht_fill_limit_crossed\n");173 212 hashtable_rbs(t_unused) & ht = *(hashtable_rbs(t_unused) *)ex.theHashtable; 174 ht.ff_next_warn_up *= 2; 213 printf("base default resumption handler ht_fill_limit_crossed with ht filled at %f\n", fill_frac(ht)); 214 ht.ff_next_warn_up *= ht.ff_warn_step_factor; 175 215 } 176 216 … … 192 232 struct hashtable_rbs_dynamic { 193 233 inline hashtable_rbs(Tt_unused); 234 235 struct resize_policy { 236 // When fill factor exceeds grow limit, grow big enough for 237 // resulting fill factor to be lower than grow_target. Vice versa. 238 // Using different grow and shrink limits prevents noisy current 239 // size from triggering grow-shrink oscillation. OK to use same 240 // grow and shrink targets. 241 float grow_limit, shrink_limit, grow_target, shrink_target; 242 243 // warn with exception but do nothing, this many -1 times, then actually resize 244 unsigned short int warns_per_grow, warns_per_shrink; 245 246 // Don't shrink below. 247 size_t nbuckets_floor; 248 } policy; 249 194 250 dlist(request_in_ht_by_src, request) * (*alloc)( size_t ); 195 251 void (*free)( void * ); … … 209 265 forall( otype Tt_unused | heaped( dlist(request_in_ht_by_src, request) ) ) { 210 266 211 void ?{}( hashtable_rbs_dynamic(Tt_unused) & this, size_t n_buckets ) { 267 void ?{}( hashtable_rbs_dynamic(Tt_unused).resize_policy & this, size_t nbuckets_floor ) { 268 printf("default dynamic policy ctor\n"); 269 270 (this.grow_limit) {2.0}; 271 (this.shrink_limit) {0.5}; 272 (this.grow_target) {1.0}; 273 (this.shrink_target) {1.0}; 274 (this.warns_per_grow) {4}; 275 (this.warns_per_shrink){4}; 276 (this.nbuckets_floor) {nbuckets_floor}; 277 } 278 279 void ?{}( hashtable_rbs_dynamic(Tt_unused) & this, size_t n_buckets, hashtable_rbs_dynamic(Tt_unused).resize_policy rp ) { 280 printf("ctor hashtable_rbs_dynamic{ size_t, resize_policy }\n"); 281 282 float first_first_warn_up = rp.grow_target; 283 float ff_warn_step_factor = (rp.grow_limit / rp.grow_target) \ ( 1. / rp.warns_per_grow ); 284 212 285 void (*defaultResumptionHandler) (ht_fill_limit_crossed &) = __dynamic_defaultResumptionHandler; 213 286 dlist(request_in_ht_by_src, request) *buckets = alloc(n_buckets); 214 ((hashtable_rbs(Tt_unused) &)this){ n_buckets, buckets }; 287 ( ( hashtable_rbs( Tt_unused ) & ) this ){ n_buckets, buckets, first_first_warn_up, ff_warn_step_factor }; 288 ( this.policy ){ rp }; 215 289 this.alloc = alloc; 216 290 this.free = free; 291 } 292 void ?{}( hashtable_rbs_dynamic(Tt_unused) & this, hashtable_rbs_dynamic(Tt_unused).resize_policy rp ) { 293 printf("ctor hashtable_rbs_dynamic{ resize_policy }\n"); 294 ( this ) { rp.nbuckets_floor, rp }; 295 } 296 void ?{}( hashtable_rbs_dynamic(Tt_unused) & this, size_t n_buckets ) { 297 printf("ctor hashtable_rbs_dynamic{ size_t }\n"); 298 ( this ) { n_buckets, (hashtable_rbs_dynamic(Tt_unused).resize_policy){ n_buckets } }; 217 299 } 218 300 void ^?{}( hashtable_rbs_dynamic(Tt_unused) & this ) { … … 230 312 // make empty hash table of new size 231 313 dlist(request_in_ht_by_src, request) *oldBuckets = buckets; 314 float oldFfWarnStepFactor = ff_warn_step_factor; 315 float newFfNextWarnUp = ((float)item_count) / ((float) new_n_buckets); 232 316 ^?{}( (hashtable_rbs(Tt_unused) &)this ); 233 317 free( oldBuckets ); 234 ?{}( (hashtable_rbs(Tt_unused) &)this, new_n_buckets, alloc(new_n_buckets) );318 ?{}( (hashtable_rbs(Tt_unused) &)this, new_n_buckets, alloc(new_n_buckets), newFfNextWarnUp, oldFfWarnStepFactor ); 235 319 236 320 // fill new table with old items … … 247 331 } 248 332 333 void defaultResumptionHandler( ht_auto_resize_pending & ex ) { 334 hashtable_rbs_dynamic(t_unused) & ht = *(hashtable_rbs_dynamic(t_unused) *)ex.theHashtable; 335 printf("auto-resize unhandled: proceeding with resize\n"); 336 rehashToLarger_STEP( ht, ex.new_size ); 337 } 338 249 339 void __dynamic_defaultResumptionHandler(ht_fill_limit_crossed & ex) { 250 340 hashtable_rbs_dynamic(t_unused) & ht = *(hashtable_rbs_dynamic(t_unused) *)ex.theHashtable; 251 printf("dynamic limit crossed with fill_frac = %f and buckets at %p\n", fill_frac(ht), ht.buckets); 252 rehashToLarger_STEP( ht, 2 * ht.n_buckets ); 341 printf("dynamic warning received with fill_frac = %f and buckets at %p\n", fill_frac(ht), ht.buckets); 342 if ( fill_frac( ht ) >= ht.policy.grow_limit ) { 343 float grow_amount = ht.policy.grow_limit / ht.policy.grow_target; 344 ex.want_throwResume_ht_auto_resize_pending = true; 345 ex.size_for_ht_auto_resize_pending = ( size_t )( grow_amount * ht.n_buckets ); 346 } else { 347 // base handler, not specialized for dynamic 348 defaultResumptionHandler( ex ); 349 } 253 350 } 254 351 … … 260 357 #include <stdlib.hfa> 261 358 262 int main() { 263 264 265 HASHTABLE_RBS_STATIC(67, h_src) 266 267 request & wasnt_found = get(h_src, 17); 359 void basicFillingTestHelper( hashtable_rbs(t_unused) & ht, size_t n_elems ) { 360 361 request & wasnt_found = get(ht, 17); 268 362 assert( &wasnt_found == 0p ); 269 363 … … 272 366 r.tgt_id = 998; 273 367 274 put(h _src, r);275 276 request & found = get(h _src, 117);368 put(ht, r); 369 370 request & found = get(ht, 117); 277 371 assert( &found == &r ); 278 372 279 & wasnt_found = & get(h _src, 998);373 & wasnt_found = & get(ht, 998); 280 374 assert( &wasnt_found == 0p ); 281 375 282 printf( "%f\n", fill_frac(h_src) ); 283 284 285 request rs[500]; 286 try { 287 for (i; 500) { 288 rs[i].src_id = 8000 * i; 289 put(h_src, rs[i]); 290 } 291 } catchResume(ht_fill_limit_crossed*) { 292 printf("fill limit tripped with h_src filled at %f\n", fill_frac(h_src)); 293 throwResume; 294 } 295 296 assert( & get(h_src, 117 ) ); 297 assert( & get(h_src, 8000*25 ) ); 298 assert(! & get(h_src, 8000*25+1) ); 299 300 376 request rs[n_elems]; 377 for (i; n_elems) { 378 rs[i].src_id = 8000 * i; 379 put(ht, rs[i]); 380 } 381 382 assert( & get(ht, 117 ) ); 383 assert( & get(ht, 8000*25 ) ); 384 assert(! & get(ht, 8000*25+1) ); 385 } 386 387 void basicFillingTest_static() { 388 389 printf("---start basic fill test static ----\n"); 390 391 HASHTABLE_RBS_STATIC(67, ht) 392 393 basicFillingTestHelper(ht, 500); 394 } 395 396 void basicFillingTest_dynamic() { 301 397 302 398 dlist(request_in_ht_by_src, request) * (*old_alloc)( size_t ) = alloc; … … 313 409 } 314 410 315 hashtable_rbs_dynamic(t_unused) ht2 = { 113 }; 316 request rs2[500]; 411 printf("---start basic fill test dynamic ----\n"); 412 413 hashtable_rbs_dynamic(t_unused) ht = { 113 }; 414 415 basicFillingTestHelper(ht, 500); 416 } 417 418 // Demonstrates user-provided instrumentation monitoring a fixed-size hash table 419 void logTest() { 420 421 printf("---start log test ----\n"); 422 423 HASHTABLE_RBS_STATIC(67, ht) 424 317 425 try { 318 for (i; 500) { 319 if (i % 10 == 0) {printf("%d(%f),", i, fill_frac(ht2));} 320 rs2[i].src_id = 8000 * i; 321 put(ht2, rs2[i]); 322 } 323 } catchResume(ht_fill_limit_crossed*) { 324 printf("fill limit tripped with ht2 filled at %f\n", fill_frac(ht2)); 426 basicFillingTestHelper(ht, 500); 427 } catchResume( ht_fill_limit_crossed * ) { 428 printf("log test instrumentation runs\n"); 325 429 throwResume; 326 430 } 327 328 329 } 431 } 432 433 // Demonstrates "snoozing" a growing hash table's auto-resize event, 434 // in that that next call to put will get the resize exception instead. 435 void snoozeTest() { 436 437 printf("---start snooze test ----\n"); 438 439 hashtable_rbs_dynamic(t_unused) ht = { 113 }; 440 441 bool lastResizeSnoozed = false; 442 443 try { 444 basicFillingTestHelper(ht, 500); 445 } catchResume( ht_auto_resize_pending * ) { 446 447 if ( lastResizeSnoozed == false ) { 448 lastResizeSnoozed = true; 449 printf("snooze test intervention decides to snooze this time\n"); 450 } else { 451 lastResizeSnoozed = false; 452 printf("snooze test intervention decides to allow the resize\n"); 453 throwResume; 454 } 455 456 } 457 } 458 459 int main() { 460 461 basicFillingTest_static(); 462 basicFillingTest_dynamic(); 463 464 logTest(); 465 snoozeTest(); 466 }
Note: See TracChangeset
for help on using the changeset viewer.