testatomic.c (20556B)
1/* 2 Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> 3 4 This software is provided 'as-is', without any express or implied 5 warranty. In no event will the authors be held liable for any damages 6 arising from the use of this software. 7 8 Permission is granted to anyone to use this software for any purpose, 9 including commercial applications, and to alter it and redistribute it 10 freely. 11*/ 12#include <stdio.h> 13 14#include "SDL.h" 15#include "SDL_atomic.h" 16#include "SDL_assert.h" 17#include "SDL_cpuinfo.h" 18 19/* 20 Absolutely basic tests just to see if we get the expected value 21 after calling each function. 22*/ 23 24static 25char * 26tf(SDL_bool tf) 27{ 28 static char *t = "TRUE"; 29 static char *f = "FALSE"; 30 31 if (tf) 32 { 33 return t; 34 } 35 36 return f; 37} 38 39static 40void RunBasicTest() 41{ 42 int value; 43 SDL_SpinLock lock = 0; 44 45 SDL_atomic_t v; 46 SDL_bool tfret = SDL_FALSE; 47 48 SDL_Log("\nspin lock---------------------------------------\n\n"); 49 50 SDL_AtomicLock(&lock); 51 SDL_Log("AtomicLock lock=%d\n", lock); 52 SDL_AtomicUnlock(&lock); 53 SDL_Log("AtomicUnlock lock=%d\n", lock); 54 55 SDL_Log("\natomic -----------------------------------------\n\n"); 56 57 SDL_AtomicSet(&v, 0); 58 tfret = SDL_AtomicSet(&v, 10) == 0 ? SDL_TRUE : SDL_FALSE; 59 SDL_Log("AtomicSet(10) tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v)); 60 tfret = SDL_AtomicAdd(&v, 10) == 10 ? SDL_TRUE : SDL_FALSE; 61 SDL_Log("AtomicAdd(10) tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v)); 62 63 SDL_AtomicSet(&v, 0); 64 SDL_AtomicIncRef(&v); 65 tfret = (SDL_AtomicGet(&v) == 1) ? SDL_TRUE : SDL_FALSE; 66 SDL_Log("AtomicIncRef() tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v)); 67 SDL_AtomicIncRef(&v); 68 tfret = (SDL_AtomicGet(&v) == 2) ? SDL_TRUE : SDL_FALSE; 69 SDL_Log("AtomicIncRef() tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v)); 70 tfret = (SDL_AtomicDecRef(&v) == SDL_FALSE) ? SDL_TRUE : SDL_FALSE; 71 SDL_Log("AtomicDecRef() tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v)); 72 tfret = (SDL_AtomicDecRef(&v) == SDL_TRUE) ? SDL_TRUE : SDL_FALSE; 73 SDL_Log("AtomicDecRef() tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v)); 74 75 SDL_AtomicSet(&v, 10); 76 tfret = (SDL_AtomicCAS(&v, 0, 20) == SDL_FALSE) ? SDL_TRUE : SDL_FALSE; 77 SDL_Log("AtomicCAS() tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v)); 78 value = SDL_AtomicGet(&v); 79 tfret = (SDL_AtomicCAS(&v, value, 20) == SDL_TRUE) ? SDL_TRUE : SDL_FALSE; 80 SDL_Log("AtomicCAS() tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v)); 81} 82 83/**************************************************************************/ 84/* Atomic operation test 85 * Adapted with permission from code by Michael Davidsaver at: 86 * http://bazaar.launchpad.net/~mdavidsaver/epics-base/atomic/revision/12105#src/libCom/test/epicsAtomicTest.c 87 * Original copyright 2010 Brookhaven Science Associates as operator of Brookhaven National Lab 88 * http://www.aps.anl.gov/epics/license/open.php 89 */ 90 91/* Tests semantics of atomic operations. Also a stress test 92 * to see if they are really atomic. 93 * 94 * Several threads adding to the same variable. 95 * at the end the value is compared with the expected 96 * and with a non-atomic counter. 97 */ 98 99/* Number of concurrent incrementers */ 100#define NThreads 2 101#define CountInc 100 102#define VALBITS (sizeof(atomicValue)*8) 103 104#define atomicValue int 105#define CountTo ((atomicValue)((unsigned int)(1<<(VALBITS-1))-1)) 106#define NInter (CountTo/CountInc/NThreads) 107#define Expect (CountTo-NInter*CountInc*NThreads) 108 109SDL_COMPILE_TIME_ASSERT(size, CountTo>0); /* check for rollover */ 110 111static SDL_atomic_t good = { 42 }; 112 113static atomicValue bad = 42; 114 115static SDL_atomic_t threadsRunning; 116 117static SDL_sem *threadDone; 118 119static 120int adder(void* junk) 121{ 122 unsigned long N=NInter; 123 SDL_Log("Thread subtracting %d %lu times\n",CountInc,N); 124 while (N--) { 125 SDL_AtomicAdd(&good, -CountInc); 126 bad-=CountInc; 127 } 128 SDL_AtomicAdd(&threadsRunning, -1); 129 SDL_SemPost(threadDone); 130 return 0; 131} 132 133static 134void runAdder(void) 135{ 136 Uint32 start, end; 137 int T=NThreads; 138 139 start = SDL_GetTicks(); 140 141 threadDone = SDL_CreateSemaphore(0); 142 143 SDL_AtomicSet(&threadsRunning, NThreads); 144 145 while (T--) 146 SDL_CreateThread(adder, "Adder", NULL); 147 148 while (SDL_AtomicGet(&threadsRunning) > 0) 149 SDL_SemWait(threadDone); 150 151 SDL_DestroySemaphore(threadDone); 152 153 end = SDL_GetTicks(); 154 155 SDL_Log("Finished in %f sec\n", (end - start) / 1000.f); 156} 157 158static 159void RunEpicTest() 160{ 161 int b; 162 atomicValue v; 163 164 SDL_Log("\nepic test---------------------------------------\n\n"); 165 166 SDL_Log("Size asserted to be >= 32-bit\n"); 167 SDL_assert(sizeof(atomicValue)>=4); 168 169 SDL_Log("Check static initializer\n"); 170 v=SDL_AtomicGet(&good); 171 SDL_assert(v==42); 172 173 SDL_assert(bad==42); 174 175 SDL_Log("Test negative values\n"); 176 SDL_AtomicSet(&good, -5); 177 v=SDL_AtomicGet(&good); 178 SDL_assert(v==-5); 179 180 SDL_Log("Verify maximum value\n"); 181 SDL_AtomicSet(&good, CountTo); 182 v=SDL_AtomicGet(&good); 183 SDL_assert(v==CountTo); 184 185 SDL_Log("Test compare and exchange\n"); 186 187 b=SDL_AtomicCAS(&good, 500, 43); 188 SDL_assert(!b); /* no swap since CountTo!=500 */ 189 v=SDL_AtomicGet(&good); 190 SDL_assert(v==CountTo); /* ensure no swap */ 191 192 b=SDL_AtomicCAS(&good, CountTo, 44); 193 SDL_assert(!!b); /* will swap */ 194 v=SDL_AtomicGet(&good); 195 SDL_assert(v==44); 196 197 SDL_Log("Test Add\n"); 198 199 v=SDL_AtomicAdd(&good, 1); 200 SDL_assert(v==44); 201 v=SDL_AtomicGet(&good); 202 SDL_assert(v==45); 203 204 v=SDL_AtomicAdd(&good, 10); 205 SDL_assert(v==45); 206 v=SDL_AtomicGet(&good); 207 SDL_assert(v==55); 208 209 SDL_Log("Test Add (Negative values)\n"); 210 211 v=SDL_AtomicAdd(&good, -20); 212 SDL_assert(v==55); 213 v=SDL_AtomicGet(&good); 214 SDL_assert(v==35); 215 216 v=SDL_AtomicAdd(&good, -50); /* crossing zero down */ 217 SDL_assert(v==35); 218 v=SDL_AtomicGet(&good); 219 SDL_assert(v==-15); 220 221 v=SDL_AtomicAdd(&good, 30); /* crossing zero up */ 222 SDL_assert(v==-15); 223 v=SDL_AtomicGet(&good); 224 SDL_assert(v==15); 225 226 SDL_Log("Reset before count down test\n"); 227 SDL_AtomicSet(&good, CountTo); 228 v=SDL_AtomicGet(&good); 229 SDL_assert(v==CountTo); 230 231 bad=CountTo; 232 SDL_assert(bad==CountTo); 233 234 SDL_Log("Counting down from %d, Expect %d remaining\n",CountTo,Expect); 235 runAdder(); 236 237 v=SDL_AtomicGet(&good); 238 SDL_Log("Atomic %d Non-Atomic %d\n",v,bad); 239 SDL_assert(v==Expect); 240 SDL_assert(bad!=Expect); 241} 242 243/* End atomic operation test */ 244/**************************************************************************/ 245 246/**************************************************************************/ 247/* Lock-free FIFO test */ 248 249/* This is useful to test the impact of another thread locking the queue 250 entirely for heavy-weight manipulation. 251 */ 252#define TEST_SPINLOCK_FIFO 253 254#define NUM_READERS 4 255#define NUM_WRITERS 4 256#define EVENTS_PER_WRITER 1000000 257 258/* The number of entries must be a power of 2 */ 259#define MAX_ENTRIES 256 260#define WRAP_MASK (MAX_ENTRIES-1) 261 262typedef struct 263{ 264 SDL_atomic_t sequence; 265 SDL_Event event; 266} SDL_EventQueueEntry; 267 268typedef struct 269{ 270 SDL_EventQueueEntry entries[MAX_ENTRIES]; 271 272 char cache_pad1[SDL_CACHELINE_SIZE-((sizeof(SDL_EventQueueEntry)*MAX_ENTRIES)%SDL_CACHELINE_SIZE)]; 273 274 SDL_atomic_t enqueue_pos; 275 276 char cache_pad2[SDL_CACHELINE_SIZE-sizeof(SDL_atomic_t)]; 277 278 SDL_atomic_t dequeue_pos; 279 280 char cache_pad3[SDL_CACHELINE_SIZE-sizeof(SDL_atomic_t)]; 281 282#ifdef TEST_SPINLOCK_FIFO 283 SDL_SpinLock lock; 284 SDL_atomic_t rwcount; 285 SDL_atomic_t watcher; 286 287 char cache_pad4[SDL_CACHELINE_SIZE-sizeof(SDL_SpinLock)-2*sizeof(SDL_atomic_t)]; 288#endif 289 290 volatile SDL_bool active; 291 292 /* Only needed for the mutex test */ 293 SDL_mutex *mutex; 294 295} SDL_EventQueue; 296 297static void InitEventQueue(SDL_EventQueue *queue) 298{ 299 int i; 300 301 for (i = 0; i < MAX_ENTRIES; ++i) { 302 SDL_AtomicSet(&queue->entries[i].sequence, i); 303 } 304 SDL_AtomicSet(&queue->enqueue_pos, 0); 305 SDL_AtomicSet(&queue->dequeue_pos, 0); 306#ifdef TEST_SPINLOCK_FIFO 307 queue->lock = 0; 308 SDL_AtomicSet(&queue->rwcount, 0); 309 SDL_AtomicSet(&queue->watcher, 0); 310#endif 311 queue->active = SDL_TRUE; 312} 313 314static SDL_bool EnqueueEvent_LockFree(SDL_EventQueue *queue, const SDL_Event *event) 315{ 316 SDL_EventQueueEntry *entry; 317 unsigned queue_pos; 318 unsigned entry_seq; 319 int delta; 320 SDL_bool status; 321 322#ifdef TEST_SPINLOCK_FIFO 323 /* This is a gate so an external thread can lock the queue */ 324 SDL_AtomicLock(&queue->lock); 325 SDL_assert(SDL_AtomicGet(&queue->watcher) == 0); 326 SDL_AtomicIncRef(&queue->rwcount); 327 SDL_AtomicUnlock(&queue->lock); 328#endif 329 330 queue_pos = (unsigned)SDL_AtomicGet(&queue->enqueue_pos); 331 for ( ; ; ) { 332 entry = &queue->entries[queue_pos & WRAP_MASK]; 333 entry_seq = (unsigned)SDL_AtomicGet(&entry->sequence); 334 335 delta = (int)(entry_seq - queue_pos); 336 if (delta == 0) { 337 /* The entry and the queue position match, try to increment the queue position */ 338 if (SDL_AtomicCAS(&queue->enqueue_pos, (int)queue_pos, (int)(queue_pos+1))) { 339 /* We own the object, fill it! */ 340 entry->event = *event; 341 SDL_AtomicSet(&entry->sequence, (int)(queue_pos + 1)); 342 status = SDL_TRUE; 343 break; 344 } 345 } else if (delta < 0) { 346 /* We ran into an old queue entry, which means it still needs to be dequeued */ 347 status = SDL_FALSE; 348 break; 349 } else { 350 /* We ran into a new queue entry, get the new queue position */ 351 queue_pos = (unsigned)SDL_AtomicGet(&queue->enqueue_pos); 352 } 353 } 354 355#ifdef TEST_SPINLOCK_FIFO 356 SDL_AtomicDecRef(&queue->rwcount); 357#endif 358 return status; 359} 360 361static SDL_bool DequeueEvent_LockFree(SDL_EventQueue *queue, SDL_Event *event) 362{ 363 SDL_EventQueueEntry *entry; 364 unsigned queue_pos; 365 unsigned entry_seq; 366 int delta; 367 SDL_bool status; 368 369#ifdef TEST_SPINLOCK_FIFO 370 /* This is a gate so an external thread can lock the queue */ 371 SDL_AtomicLock(&queue->lock); 372 SDL_assert(SDL_AtomicGet(&queue->watcher) == 0); 373 SDL_AtomicIncRef(&queue->rwcount); 374 SDL_AtomicUnlock(&queue->lock); 375#endif 376 377 queue_pos = (unsigned)SDL_AtomicGet(&queue->dequeue_pos); 378 for ( ; ; ) { 379 entry = &queue->entries[queue_pos & WRAP_MASK]; 380 entry_seq = (unsigned)SDL_AtomicGet(&entry->sequence); 381 382 delta = (int)(entry_seq - (queue_pos + 1)); 383 if (delta == 0) { 384 /* The entry and the queue position match, try to increment the queue position */ 385 if (SDL_AtomicCAS(&queue->dequeue_pos, (int)queue_pos, (int)(queue_pos+1))) { 386 /* We own the object, fill it! */ 387 *event = entry->event; 388 SDL_AtomicSet(&entry->sequence, (int)(queue_pos+MAX_ENTRIES)); 389 status = SDL_TRUE; 390 break; 391 } 392 } else if (delta < 0) { 393 /* We ran into an old queue entry, which means we've hit empty */ 394 status = SDL_FALSE; 395 break; 396 } else { 397 /* We ran into a new queue entry, get the new queue position */ 398 queue_pos = (unsigned)SDL_AtomicGet(&queue->dequeue_pos); 399 } 400 } 401 402#ifdef TEST_SPINLOCK_FIFO 403 SDL_AtomicDecRef(&queue->rwcount); 404#endif 405 return status; 406} 407 408static SDL_bool EnqueueEvent_Mutex(SDL_EventQueue *queue, const SDL_Event *event) 409{ 410 SDL_EventQueueEntry *entry; 411 unsigned queue_pos; 412 unsigned entry_seq; 413 int delta; 414 SDL_bool status = SDL_FALSE; 415 416 SDL_LockMutex(queue->mutex); 417 418 queue_pos = (unsigned)queue->enqueue_pos.value; 419 entry = &queue->entries[queue_pos & WRAP_MASK]; 420 entry_seq = (unsigned)entry->sequence.value; 421 422 delta = (int)(entry_seq - queue_pos); 423 if (delta == 0) { 424 ++queue->enqueue_pos.value; 425 426 /* We own the object, fill it! */ 427 entry->event = *event; 428 entry->sequence.value = (int)(queue_pos + 1); 429 status = SDL_TRUE; 430 } else if (delta < 0) { 431 /* We ran into an old queue entry, which means it still needs to be dequeued */ 432 } else { 433 SDL_Log("ERROR: mutex failed!\n"); 434 } 435 436 SDL_UnlockMutex(queue->mutex); 437 438 return status; 439} 440 441static SDL_bool DequeueEvent_Mutex(SDL_EventQueue *queue, SDL_Event *event) 442{ 443 SDL_EventQueueEntry *entry; 444 unsigned queue_pos; 445 unsigned entry_seq; 446 int delta; 447 SDL_bool status = SDL_FALSE; 448 449 SDL_LockMutex(queue->mutex); 450 451 queue_pos = (unsigned)queue->dequeue_pos.value; 452 entry = &queue->entries[queue_pos & WRAP_MASK]; 453 entry_seq = (unsigned)entry->sequence.value; 454 455 delta = (int)(entry_seq - (queue_pos + 1)); 456 if (delta == 0) { 457 ++queue->dequeue_pos.value; 458 459 /* We own the object, fill it! */ 460 *event = entry->event; 461 entry->sequence.value = (int)(queue_pos + MAX_ENTRIES); 462 status = SDL_TRUE; 463 } else if (delta < 0) { 464 /* We ran into an old queue entry, which means we've hit empty */ 465 } else { 466 SDL_Log("ERROR: mutex failed!\n"); 467 } 468 469 SDL_UnlockMutex(queue->mutex); 470 471 return status; 472} 473 474static SDL_sem *writersDone; 475static SDL_sem *readersDone; 476static SDL_atomic_t writersRunning; 477static SDL_atomic_t readersRunning; 478 479typedef struct 480{ 481 SDL_EventQueue *queue; 482 int index; 483 char padding1[SDL_CACHELINE_SIZE-(sizeof(SDL_EventQueue*)+sizeof(int))%SDL_CACHELINE_SIZE]; 484 int waits; 485 SDL_bool lock_free; 486 char padding2[SDL_CACHELINE_SIZE-sizeof(int)-sizeof(SDL_bool)]; 487} WriterData; 488 489typedef struct 490{ 491 SDL_EventQueue *queue; 492 int counters[NUM_WRITERS]; 493 int waits; 494 SDL_bool lock_free; 495 char padding[SDL_CACHELINE_SIZE-(sizeof(SDL_EventQueue*)+sizeof(int)*NUM_WRITERS+sizeof(int)+sizeof(SDL_bool))%SDL_CACHELINE_SIZE]; 496} ReaderData; 497 498static int FIFO_Writer(void* _data) 499{ 500 WriterData *data = (WriterData *)_data; 501 SDL_EventQueue *queue = data->queue; 502 int i; 503 SDL_Event event; 504 505 event.type = SDL_USEREVENT; 506 event.user.windowID = 0; 507 event.user.code = 0; 508 event.user.data1 = data; 509 event.user.data2 = NULL; 510 511 if (data->lock_free) { 512 for (i = 0; i < EVENTS_PER_WRITER; ++i) { 513 event.user.code = i; 514 while (!EnqueueEvent_LockFree(queue, &event)) { 515 ++data->waits; 516 SDL_Delay(0); 517 } 518 } 519 } else { 520 for (i = 0; i < EVENTS_PER_WRITER; ++i) { 521 event.user.code = i; 522 while (!EnqueueEvent_Mutex(queue, &event)) { 523 ++data->waits; 524 SDL_Delay(0); 525 } 526 } 527 } 528 SDL_AtomicAdd(&writersRunning, -1); 529 SDL_SemPost(writersDone); 530 return 0; 531} 532 533static int FIFO_Reader(void* _data) 534{ 535 ReaderData *data = (ReaderData *)_data; 536 SDL_EventQueue *queue = data->queue; 537 SDL_Event event; 538 539 if (data->lock_free) { 540 for ( ; ; ) { 541 if (DequeueEvent_LockFree(queue, &event)) { 542 WriterData *writer = (WriterData*)event.user.data1; 543 ++data->counters[writer->index]; 544 } else if (queue->active) { 545 ++data->waits; 546 SDL_Delay(0); 547 } else { 548 /* We drained the queue, we're done! */ 549 break; 550 } 551 } 552 } else { 553 for ( ; ; ) { 554 if (DequeueEvent_Mutex(queue, &event)) { 555 WriterData *writer = (WriterData*)event.user.data1; 556 ++data->counters[writer->index]; 557 } else if (queue->active) { 558 ++data->waits; 559 SDL_Delay(0); 560 } else { 561 /* We drained the queue, we're done! */ 562 break; 563 } 564 } 565 } 566 SDL_AtomicAdd(&readersRunning, -1); 567 SDL_SemPost(readersDone); 568 return 0; 569} 570 571#ifdef TEST_SPINLOCK_FIFO 572/* This thread periodically locks the queue for no particular reason */ 573static int FIFO_Watcher(void* _data) 574{ 575 SDL_EventQueue *queue = (SDL_EventQueue *)_data; 576 577 while (queue->active) { 578 SDL_AtomicLock(&queue->lock); 579 SDL_AtomicIncRef(&queue->watcher); 580 while (SDL_AtomicGet(&queue->rwcount) > 0) { 581 SDL_Delay(0); 582 } 583 /* Do queue manipulation here... */ 584 SDL_AtomicDecRef(&queue->watcher); 585 SDL_AtomicUnlock(&queue->lock); 586 587 /* Wait a bit... */ 588 SDL_Delay(1); 589 } 590 return 0; 591} 592#endif /* TEST_SPINLOCK_FIFO */ 593 594static void RunFIFOTest(SDL_bool lock_free) 595{ 596 SDL_EventQueue queue; 597 WriterData writerData[NUM_WRITERS]; 598 ReaderData readerData[NUM_READERS]; 599 Uint32 start, end; 600 int i, j; 601 int grand_total; 602 char textBuffer[1024]; 603 int len; 604 605 SDL_Log("\nFIFO test---------------------------------------\n\n"); 606 SDL_Log("Mode: %s\n", lock_free ? "LockFree" : "Mutex"); 607 608 readersDone = SDL_CreateSemaphore(0); 609 writersDone = SDL_CreateSemaphore(0); 610 611 SDL_memset(&queue, 0xff, sizeof(queue)); 612 613 InitEventQueue(&queue); 614 if (!lock_free) { 615 queue.mutex = SDL_CreateMutex(); 616 } 617 618 start = SDL_GetTicks(); 619 620#ifdef TEST_SPINLOCK_FIFO 621 /* Start a monitoring thread */ 622 if (lock_free) { 623 SDL_CreateThread(FIFO_Watcher, "FIFOWatcher", &queue); 624 } 625#endif 626 627 /* Start the readers first */ 628 SDL_Log("Starting %d readers\n", NUM_READERS); 629 SDL_zero(readerData); 630 SDL_AtomicSet(&readersRunning, NUM_READERS); 631 for (i = 0; i < NUM_READERS; ++i) { 632 char name[64]; 633 SDL_snprintf(name, sizeof (name), "FIFOReader%d", i); 634 readerData[i].queue = &queue; 635 readerData[i].lock_free = lock_free; 636 SDL_CreateThread(FIFO_Reader, name, &readerData[i]); 637 } 638 639 /* Start up the writers */ 640 SDL_Log("Starting %d writers\n", NUM_WRITERS); 641 SDL_zero(writerData); 642 SDL_AtomicSet(&writersRunning, NUM_WRITERS); 643 for (i = 0; i < NUM_WRITERS; ++i) { 644 char name[64]; 645 SDL_snprintf(name, sizeof (name), "FIFOWriter%d", i); 646 writerData[i].queue = &queue; 647 writerData[i].index = i; 648 writerData[i].lock_free = lock_free; 649 SDL_CreateThread(FIFO_Writer, name, &writerData[i]); 650 } 651 652 /* Wait for the writers */ 653 while (SDL_AtomicGet(&writersRunning) > 0) { 654 SDL_SemWait(writersDone); 655 } 656 657 /* Shut down the queue so readers exit */ 658 queue.active = SDL_FALSE; 659 660 /* Wait for the readers */ 661 while (SDL_AtomicGet(&readersRunning) > 0) { 662 SDL_SemWait(readersDone); 663 } 664 665 end = SDL_GetTicks(); 666 667 SDL_DestroySemaphore(readersDone); 668 SDL_DestroySemaphore(writersDone); 669 670 if (!lock_free) { 671 SDL_DestroyMutex(queue.mutex); 672 } 673 674 SDL_Log("Finished in %f sec\n", (end - start) / 1000.f); 675 676 SDL_Log("\n"); 677 for (i = 0; i < NUM_WRITERS; ++i) { 678 SDL_Log("Writer %d wrote %d events, had %d waits\n", i, EVENTS_PER_WRITER, writerData[i].waits); 679 } 680 SDL_Log("Writers wrote %d total events\n", NUM_WRITERS*EVENTS_PER_WRITER); 681 682 /* Print a breakdown of which readers read messages from which writer */ 683 SDL_Log("\n"); 684 grand_total = 0; 685 for (i = 0; i < NUM_READERS; ++i) { 686 int total = 0; 687 for (j = 0; j < NUM_WRITERS; ++j) { 688 total += readerData[i].counters[j]; 689 } 690 grand_total += total; 691 SDL_Log("Reader %d read %d events, had %d waits\n", i, total, readerData[i].waits); 692 SDL_snprintf(textBuffer, sizeof(textBuffer), " { "); 693 for (j = 0; j < NUM_WRITERS; ++j) { 694 if (j > 0) { 695 len = SDL_strlen(textBuffer); 696 SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, ", "); 697 } 698 len = SDL_strlen(textBuffer); 699 SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, "%d", readerData[i].counters[j]); 700 } 701 len = SDL_strlen(textBuffer); 702 SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, " }\n"); 703 SDL_Log("%s", textBuffer); 704 } 705 SDL_Log("Readers read %d total events\n", grand_total); 706} 707 708/* End FIFO test */ 709/**************************************************************************/ 710 711int 712main(int argc, char *argv[]) 713{ 714 /* Enable standard application logging */ 715 SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); 716 717 RunBasicTest(); 718 RunEpicTest(); 719/* This test is really slow, so don't run it by default */ 720#if 0 721 RunFIFOTest(SDL_FALSE); 722#endif 723 RunFIFOTest(SDL_TRUE); 724 return 0; 725} 726 727/* vi: set ts=4 sw=4 expandtab: */