00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include <stdint.h>
00034 #include <stdlib.h>
00035 #include <pthread.h>
00036 #include <mmintrin.h>
00037 #include <list.h>
00038 #include <spinlock.h>
00039 #include "cuckoo_hash/PointerHashInline.h"
00040 #include "pcm_i.h"
00041
00042
00043
00044
00045 typedef uint64_t cacheline_bitmask_t;
00046
00047 typedef struct pcm_storeset_list_s pcm_storeset_list_t;
00048
00049 struct pcm_storeset_list_s {
00050 uint32_t count;
00051 struct list_head list;
00052 volatile uint8_t outstanding_crash;
00053 pthread_mutex_t lock;
00054 pthread_cond_t cond_halt;
00055 pthread_cond_t cond_wait_storesets_halt;
00056 volatile uint32_t waiters;
00057 };
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072 typedef struct cacheline_crash_cdf_s cacheline_crash_cdf_t;
00073
00074 struct cacheline_crash_cdf_s {
00075 int word[CACHELINE_SIZE/sizeof(pcm_word_t)+1];
00076 };
00077
00078
00079 typedef struct cacheline_s cacheline_t;
00080
00081 struct cacheline_s {
00082 cacheline_bitmask_t bitmask;
00083 uint8_t bytes[CACHELINE_SIZE];
00084 };
00085
00086
00087 struct cacheline_tbl_s {
00088 cacheline_t *cachelines;
00089 unsigned int cachelines_count;
00090 unsigned int cachelines_size;
00091 };
00092
00093
00094
00095
00096 pcm_storeset_list_t pcm_storeset_list = { 0,
00097 LIST_HEAD_INIT(pcm_storeset_list.list),
00098 0,
00099 PTHREAD_MUTEX_INITIALIZER,
00100 PTHREAD_COND_INITIALIZER,
00101 PTHREAD_COND_INITIALIZER,
00102 0 };
00103
00104
00105
00106
00107 #define NO_PARTIAL_CRASH {{0,0,0,0,0,0,0,0,1000000}}
00108
00109 cacheline_crash_cdf_t cacheline_crash_cdf = NO_PARTIAL_CRASH;
00110
00111
00112
00113 unsigned int pcm_likelihood_store_blockwaits = 1000;
00114
00115
00116 unsigned int pcm_likelihood_evicted_cacheline = 10000;
00117
00118 volatile arch_spinlock_t ticket_lock = {0};
00119
00120
00121 __thread pcm_storeset_t* _thread_pcm_storeset;
00122
00123
00124 static inline
00125 cacheline_t *
00126 cacheline_alloc()
00127 {
00128 cacheline_t *l;
00129
00130 l = (cacheline_t*) malloc(sizeof(cacheline_t));
00131 memset(l, 0x0, sizeof(cacheline_t));
00132 return l;
00133 }
00134
00135 static inline
00136 void
00137 cacheline_free(cacheline_t *l)
00138 {
00139 free(l);
00140 }
00141
00142
00143 int
00144 pcm_storeset_create(pcm_storeset_t **setp)
00145 {
00146 pcm_storeset_t *set;
00147
00148 set = (pcm_storeset_t *) malloc(sizeof(pcm_storeset_t));
00149 pthread_mutex_lock(&pcm_storeset_list.lock);
00150 pcm_storeset_list.count++;
00151 list_add(&set->list, &pcm_storeset_list.list);
00152 pthread_mutex_unlock(&pcm_storeset_list.lock);
00153 set->hashtbl = PointerHash_new();
00154 memset(set->wcbuf_hashtbl, 0, WCBUF_HASHTBL_SIZE);
00155 set->wcbuf_hashtbl_count = 0;
00156 set->seqstream_len = 0;
00157 set->in_crash_emulation_code = 0;
00158
00159 set->rand_seed = pthread_self();
00160 rand_int(&set->rand_seed);
00161 *setp = set;
00162 return 0;
00163 }
00164
00165
00166 void
00167 pcm_storeset_destroy(pcm_storeset_t *set)
00168 {
00169 pthread_mutex_lock(&pcm_storeset_list.lock);
00170 pcm_storeset_list.count--;
00171 list_del(&set->list);
00172 pthread_mutex_unlock(&pcm_storeset_list.lock);
00173 PointerHash_free(set->hashtbl);
00174 free(set);
00175 }
00176
00177
00178 pcm_storeset_t*
00179 pcm_storeset_get(void)
00180 {
00181 pcm_storeset_t *set = _thread_pcm_storeset;
00182
00183 if (set) {
00184 return set;
00185 }
00186
00187 pcm_storeset_create(&set);
00188 _thread_pcm_storeset = set;
00189
00190 return set;
00191 }
00192
00193
00194 void
00195 pcm_storeset_put(void)
00196 {
00197 pcm_storeset_t *set = _thread_pcm_storeset;
00198
00199 if (set) {
00200 pcm_storeset_destroy(set);
00201 _thread_pcm_storeset = NULL;
00202 }
00203 }
00204
00205
00206
00207 void
00208 pcm_check_crash(pcm_storeset_t *set)
00209 {
00210 int was_in_crash_emulation_code;
00211
00212 if (pcm_storeset_list.outstanding_crash) {
00213 was_in_crash_emulation_code = set->in_crash_emulation_code;
00214 set->in_crash_emulation_code = 0;
00215 pthread_mutex_lock(&pcm_storeset_list.lock);
00216 if (pcm_storeset_list.outstanding_crash) {
00217 pcm_storeset_list.waiters++;
00218 pthread_cond_signal(&pcm_storeset_list.cond_wait_storesets_halt);
00219 while(pcm_storeset_list.outstanding_crash) {
00220 pthread_cond_wait(&pcm_storeset_list.cond_halt, &pcm_storeset_list.lock);
00221 }
00222 }
00223 pthread_mutex_unlock(&pcm_storeset_list.lock);
00224 set->in_crash_emulation_code = was_in_crash_emulation_code;
00225 }
00226 }
00227
00228
00229 static inline
00230 void
00231 crash_save_oldvalue(pcm_storeset_t *set, volatile pcm_word_t *addr)
00232 {
00233 uintptr_t byte_addr;
00234 uintptr_t block_byte_addr;
00235 uintptr_t index_byte_addr;
00236 int i;
00237 cacheline_t *cacheline;
00238 cacheline_bitmask_t bitmask;
00239 uint8_t byte_oldvalue;
00240
00241 assert(set->in_crash_emulation_code);
00242
00243 for (i=0; i<sizeof(pcm_word_t); i++) {
00244 byte_addr = (uintptr_t) addr + i;
00245 block_byte_addr = (uintptr_t) BLOCK_ADDR(byte_addr);
00246 index_byte_addr = (uintptr_t) INDEX_ADDR(byte_addr);
00247 cacheline = (cacheline_t *) PointerHash_at_(set->hashtbl, (void *) block_byte_addr);
00248 if (!cacheline) {
00249 cacheline = cacheline_alloc();
00250 PointerHash_at_put_(set->hashtbl, (void *) block_byte_addr, (void *) cacheline);
00251 }
00252 bitmask = 1ULL << index_byte_addr;
00253 if (!(cacheline->bitmask & bitmask)) {
00254 byte_oldvalue = *((uint8_t *) byte_addr);
00255 cacheline->bytes[index_byte_addr] = byte_oldvalue;
00256 cacheline->bitmask |= bitmask;
00257 }
00258 }
00259
00260 }
00261
00262
00263 static inline
00264 void
00265 crash_restore_unflushed_values(pcm_storeset_t *set)
00266 {
00267 uintptr_t byte_addr;
00268 uintptr_t block_byte_addr;
00269 int i;
00270 int j;
00271 cacheline_t *cacheline;
00272 cacheline_bitmask_t bitmask;
00273
00274 assert(set->in_crash_emulation_code);
00275
00276 for(i = 0; i < set->hashtbl->size; i++) {
00277 PointerHashRecord *r = PointerHashRecords_recordAt_(set->hashtbl->records, i);
00278 if ((block_byte_addr = (uintptr_t) r->k)) {
00279 cacheline = (cacheline_t *) r->v;
00280 for (j=0; j<CACHELINE_SIZE; j++) {
00281 byte_addr = block_byte_addr + j;
00282 bitmask = 1ULL << j;
00283 if (cacheline->bitmask & bitmask) {
00284 *((uint8_t*)byte_addr) = cacheline->bytes[j];
00285 }
00286 }
00287 }
00288 }
00289 }
00290
00291
00292
00293
00294
00295 void
00296 crash_flush_cacheline(pcm_storeset_t *set, volatile pcm_word_t *addr, int allow_partial_crash)
00297 {
00298 uintptr_t byte_addr;
00299 uintptr_t block_byte_addr;
00300 int random_number;
00301 int i;
00302 int sum;
00303 int successfully_flushed_words_num=0;
00304 cacheline_t *cacheline;
00305 cacheline_bitmask_t bitmask;
00306
00307 assert(set->in_crash_emulation_code);
00308
00309 byte_addr = (uintptr_t) addr;
00310 block_byte_addr = (uintptr_t) BLOCK_ADDR(addr);
00311
00312 flush_cacheline:
00313 cacheline = (cacheline_t *) PointerHash_at_(set->hashtbl, (void *) block_byte_addr);
00314 if (!cacheline) {
00315
00316 return;
00317 }
00318
00319
00320
00321
00322
00323
00324
00325 if (pcm_storeset_list.outstanding_crash && allow_partial_crash) {
00326 random_number = rand_int(&set->rand_seed) % TOTAL_OUTCOMES_NUM;
00327 for (i=0, sum=0; i<CACHELINE_SIZE/sizeof(pcm_word_t)+1; i++) {
00328 sum += cacheline_crash_cdf.word[i];
00329 if (random_number <= sum) {
00330 successfully_flushed_words_num = i;
00331 break;
00332 }
00333 }
00334 } else {
00335 successfully_flushed_words_num = CACHELINE_SIZE/sizeof(pcm_word_t);
00336 }
00337 if (successfully_flushed_words_num == CACHELINE_SIZE/sizeof(pcm_word_t)) {
00338 bitmask = 0x0;
00339 } else {
00340
00341
00342
00343 bitmask = (((uint64_t) -1)
00344 << (successfully_flushed_words_num * sizeof(pcm_word_t))) & ((uint64_t) -1);
00345 }
00346 cacheline->bitmask = cacheline->bitmask & bitmask;
00347
00348 if (cacheline->bitmask == 0x0) {
00349 cacheline_free(cacheline);
00350 PointerHash_removeKey_(set->hashtbl, (void *) block_byte_addr);
00351 }
00352
00353
00354 byte_addr += sizeof(pcm_word_t)-1;
00355 block_byte_addr += sizeof(pcm_word_t)-1;
00356 goto flush_cacheline;
00357
00358 }
00359
00360
00361
00362
00363
00364
00365 static inline
00366 void
00367 crash_flush_cachelines(pcm_storeset_t *set, int all, int likelihood_flush_cacheline)
00368 {
00369 int i;
00370 int count;
00371 int random_number;
00372 int do_flush;
00373 PointerHashRecord *ra[1024];
00374
00375 assert(set->in_crash_emulation_code);
00376
00377 for(i = 0, count=0, do_flush=0; i < set->hashtbl->size; i++) {
00378 PointerHashRecord *r = PointerHashRecords_recordAt_(set->hashtbl->records, i);
00379 if (r->k) {
00380 if (!all) {
00381 random_number = rand_int(&set->rand_seed) % TOTAL_OUTCOMES_NUM;
00382 if (random_number < likelihood_flush_cacheline) {
00383 do_flush = 1;
00384 } else {
00385 do_flush = 0;
00386 }
00387 }
00388 if (all || (!all && do_flush)) {
00389 assert(count < 1024);
00390 ra[count++] = r;
00391 }
00392 }
00393 }
00394
00395 for(i = 0; i < count; i++) {
00396 crash_flush_cacheline(set, (pcm_word_t *) ra[i]->k, 0);
00397 }
00398 }
00399
00400
00401
00402 void
00403 pcm_trigger_crash(pcm_storeset_t *set, int wait_storesets_halt)
00404 {
00405 int waiters;
00406 pcm_storeset_t *set_iter;
00407
00408
00409 pthread_mutex_lock(&pcm_storeset_list.lock);
00410 if (pcm_storeset_list.outstanding_crash) {
00411
00412 pthread_mutex_unlock(&pcm_storeset_list.lock);
00413 pcm_check_crash(set);
00414 return;
00415 }
00416 pcm_storeset_list.outstanding_crash = 1;
00417 pcm_storeset_list.waiters = 0;
00418
00419 if (wait_storesets_halt) {
00420
00421 waiters = pcm_storeset_list.count;
00422 if (set) {
00423
00424
00425 waiters--;
00426 }
00427 while(pcm_storeset_list.waiters < waiters) {
00428 pthread_cond_wait(&pcm_storeset_list.cond_wait_storesets_halt, &pcm_storeset_list.lock);
00429 }
00430 } {
00431
00432
00433
00434 list_for_each_entry(set_iter, &pcm_storeset_list.list, list)
00435 {
00436 while (set_iter->in_crash_emulation_code);
00437 }
00438
00439 }
00440
00441
00442
00443
00444
00445
00446
00447 list_for_each_entry(set_iter, &pcm_storeset_list.list, list)
00448 {
00449 crash_flush_cachelines(set, 0, pcm_likelihood_evicted_cacheline);
00450 crash_restore_unflushed_values(set_iter);
00451 }
00452
00453
00454 pcm_storeset_list.outstanding_crash = 0;
00455 pthread_cond_broadcast(&pcm_storeset_list.cond_halt);
00456 pthread_mutex_unlock(&pcm_storeset_list.lock);
00457 }
00458
00459
00460
00461
00462
00463
00464 static inline
00465 void
00466 nt_flush_buffers(pcm_storeset_t *set)
00467 {
00468 int i;
00469 int count;
00470 PointerHashRecord *ra[WRITE_COMBINING_BUFFERS_NUM];
00471
00472 assert(set->in_crash_emulation_code);
00473
00474 for(i = 0, count=0; i < set->hashtbl->size; i++) {
00475 PointerHashRecord *r = PointerHashRecords_recordAt_(set->hashtbl->records, i);
00476 if (r->k) {
00477 assert(count < WRITE_COMBINING_BUFFERS_NUM);
00478 ra[count++] = r;
00479 }
00480 }
00481
00482 for(i = 0; i < count; i++) {
00483 crash_flush_cacheline(set, (pcm_word_t *) ra[i]->k, 1);
00484 }
00485 }
00486
00487
00488 void
00489 pcm_wb_store_emulate_crash(pcm_storeset_t *set, volatile pcm_word_t *addr, pcm_word_t val)
00490 {
00491 if (!set) {
00492 return;
00493 }
00494 pcm_check_crash(set);
00495 set->in_crash_emulation_code = 1;
00496 crash_save_oldvalue(set, addr);
00497 set->in_crash_emulation_code = 0;
00498 }
00499
00500
00501 void
00502 pcm_wb_flush_emulate_crash(pcm_storeset_t *set, volatile pcm_word_t *addr)
00503 {
00504 set->in_crash_emulation_code = 1;
00505 crash_flush_cacheline(set, addr, 1);
00506 set->in_crash_emulation_code = 0;
00507 pcm_check_crash(set);
00508 }
00509
00510
00511 void
00512 pcm_nt_store_emulate_crash(pcm_storeset_t *set, volatile pcm_word_t *addr, pcm_word_t val)
00513 {
00514 unsigned int active_buffers_count;
00515 uintptr_t byte_addr;
00516 uintptr_t block_byte_addr1;
00517 uintptr_t block_byte_addr2;
00518 cacheline_t *cacheline;
00519 int buffers_needed = 0;
00520
00521 pcm_check_crash(set);
00522 set->in_crash_emulation_code = 1;
00523 byte_addr = (uintptr_t) addr;
00524
00525
00526
00527
00528 block_byte_addr1 = (uintptr_t) BLOCK_ADDR(byte_addr);
00529 block_byte_addr2 = (uintptr_t) BLOCK_ADDR(byte_addr+sizeof(pcm_word_t)-1);
00530 if (!(cacheline = PointerHash_at_(set->hashtbl, (void *) block_byte_addr1))) {
00531 buffers_needed++;
00532 }
00533 if (block_byte_addr1 != block_byte_addr2
00534 && (!(cacheline = PointerHash_at_(set->hashtbl, (void *) block_byte_addr2))))
00535 {
00536 buffers_needed++;
00537 }
00538
00539
00540 active_buffers_count = PointerHash_count(set->hashtbl);
00541 if (active_buffers_count + buffers_needed > WRITE_COMBINING_BUFFERS_NUM) {
00542 nt_flush_buffers(set);
00543 }
00544 crash_save_oldvalue(set, addr);
00545 set->in_crash_emulation_code = 0;
00546 }
00547
00548
00549 void
00550 pcm_nt_flush_emulate_crash(pcm_storeset_t *set)
00551 {
00552 pcm_check_crash(set);
00553 set->in_crash_emulation_code = 1;
00554 nt_flush_buffers(set);
00555 set->in_crash_emulation_code = 0;
00556 }