// // With contributions from Paul Dorwin // // cl -O2 sync5.cpp // // gcc -O2 sync5.cpp -o sync5 -lpthread // #ifdef _WIN32 #include #define WINDEC __stdcall #define YIELD Sleep(0) #define LOCK EnterCriticalSection #define UNLOCK LeaveCriticalSection #define SLEEP(x) Sleep(1000*x) #define SLASHC '\\' #define SLASHSTR "\\" #else #include #include #include #include #include #include #include #include #include #include #define WINDEC #define YIELD sched_yield() #define LOCK pthread_mutex_lock #define UNLOCK pthread_mutex_unlock #define SLEEP(x) sleep(x) #define SLASHC '/' #define SLASHSTR "/" #endif #include #include #define equal !strcmp #define MAXCOUNT 1000*1000 // // sync6 [nseconds] // unsigned int count = 0; char *applname; char applbuf[256]; unsigned long atoik(char *str); void tstart(void); void tend(void); double tval(void); int startTimedTest(volatile int *); void endTimedTest(); int nseconds = 2; unsigned long WINDEC timerloop(void *); volatile int timedtestflag; volatile int run_count = 0; #ifdef _WIN32 CRITICAL_SECTION critA; CRITICAL_SECTION lock_run_count; HANDLE mutexA; unsigned long timerId; HANDLE th1; HANDLE semaA; #else pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t lock_run_count; unsigned long threadreturn; pthread_t tA; int semaA; struct sembuf sop; sem_t semaAA; #endif int main(int ac, char *av[]) { int ret = 0; double t; applname = av[0]; if(strrchr(applname,SLASHC)) applname = strrchr(applname,SLASHC) + 1; #ifdef _WIN32 strncpy(applbuf, applname, sizeof(applbuf)-5); if(strrchr(applname,'.')) { if(!equal(strrchr(applname,'.'), ".exe")) strcat(applbuf, ".exe"); } else { strcat(applbuf, ".exe"); } applname = applbuf; #endif if(ac > 1 && isdigit(av[1][0])) { nseconds = atoik(av[1]); ac--; av++; } #ifdef _WIN32 // // WINDOWS SEMAPHORES // semaA = CreateSemaphore(NULL, 0, 1, "semaABC"); if(semaA == NULL) { printf("CreateSemaphore \"semaABC\" failed ERROR=%d\n", GetLastError()); return 1; } count = 0; timedtestflag = 0; if(startTimedTest(&timedtestflag)) return 1; tstart(); while(timedtestflag) { count++; // // Increment // if(!ReleaseSemaphore(semaA,1,0)) { printf("ReleaseSema failed: error=%d\n",GetLastError()); return 1; } // // Decrement // if(WaitForSingleObject(semaA, INFINITE) == WAIT_FAILED) { printf("Wait in ALREADY_EXISTS child failed err=%d\n", GetLastError()); return 1; } } tend(); endTimedTest(); t = tval(); printf("Windows %s: ",applname); printf("%u ReleaseSema/WaitForSingleObject calls in %8.3f Seconds", count,t); printf(" -- %8.3f usec/(ReleaseSema/Wait)\n", (t*1E6)/count); // // WINDOWS EnterCriticalSection and LeaveCriticalSection // InitializeCriticalSection(&critA); mutexA = CreateMutex(NULL, TRUE, "mutexABC"); if(mutexA == NULL) { printf("CreateMutex \"mutexABC\" failed ERROR=%d\n", GetLastError()); return 1; } count = 0; timedtestflag = 0; if(startTimedTest(&timedtestflag)) return 1; tstart(); while(timedtestflag) { count++; EnterCriticalSection(&critA); LeaveCriticalSection(&critA); } tend(); endTimedTest(); t = tval(); printf("Windows %s: ",applname); printf("%u Enter/Leave Criticalsection calls in %8.3f Seconds", count,t); printf(" -- %8.3f usec/(Enter/Leave)\n", (t*1E6)/count); // // WINDOWS ReleaseMutex and WaitForSingleObject // count = 0; timedtestflag = 0; if(startTimedTest(&timedtestflag)) return 1; tstart(); while(timedtestflag) { count++; if(!ReleaseMutex(mutexA)) { printf("ReleaseMutex FAILED: err=%d\n",GetLastError()); return 1; } if(WaitForSingleObject(mutexA, INFINITE) == WAIT_FAILED) { printf("Wait in ALREADY_EXISTS child failed err=%d\n", GetLastError()); return 1; } } tend(); endTimedTest(); t = tval(); printf("Windows %s: ",applname); printf("%u ReleaseMutex/WaitForSingleObject calls in %8.3f Seconds", count,t); printf(" %8.3f usec/ReleaseMutex/Wait\n\n", (t/count)*1E6); #else if(sem_init(&semaAA,0,1) == -1) { // not shared, initial value 1 printf("sem_init FAILED: err=%d\n", errno); return 1; } semaA = semget(IPC_PRIVATE, 1, IPC_CREAT|0777); if(semaA == -1) { printf("semget FAILED: err=%d\n", errno); return 1; } // // Initialize to 1 // sop.sem_num = 0; sop.sem_op = 1; sop.sem_flg = 0; if(semop(semaA, &sop, 1) == -1) { printf("semop FAILED: err=%d\n", errno); return 1; } // // LINUX semaphores // count = 0; timedtestflag = 0; if(startTimedTest(&timedtestflag)) return 1; tstart(); while(timedtestflag) { count++; // // Increment // sop.sem_op = -1; if(semop(semaA, &sop, 1) == -1) { printf("semop (increment) FAILED: err=%d\n", errno); return 1; } // // Decrement // sop.sem_op = 1; if(semop(semaA, &sop, 1) == -1) { printf("semop (decrement) FAILED: err=%d\n", errno); return 1; } } tend(); endTimedTest(); t = tval(); printf("Linux Semaphores %s: ",applname); printf("%u semop(-1)/semop(1): %8.3f Seconds", count,t); printf(" -- %8.3f usec/(lock/unlock)\n", (t*1E6)/count); // // LINUX POSIX semaphores // count = 0; timedtestflag = 0; if(startTimedTest(&timedtestflag)) return 1; tstart(); while(timedtestflag) { count++; sem_wait(&semaAA); if(sem_post(&semaAA) == -1) { printf("sem_post FAILED: err=%d\n", errno); return 1; } } tend(); endTimedTest(); t = tval(); printf("Linux POSIX Semaphores %s: ",applname); printf("%u sem_wait/sem_post: %8.3f Seconds", count,t); printf(" -- %8.3f usec/(sem_wait/sem_post)\n", (t*1E6)/count); // // LINUX pthread_mutex_lock and pthread_mutex_unlock // count = 0; timedtestflag = 0; if(startTimedTest(&timedtestflag)) return 1; tstart(); while(timedtestflag) { count++; pthread_mutex_lock(&mut); pthread_mutex_unlock(&mut); } tend(); endTimedTest(); t = tval(); printf("Linux %s: ",applname); printf("%u mutex_lock/mutex_unlock: %8.3f Seconds", count,t); printf(" -- %8.3f usec/(mutex_lock/mutex_unlock)\n", (t*1E6)/count); #endif return ret; } #include unsigned long atoik(char *s) { size_t ret = 0; size_t base; if(*s == '0') { base = 8; if(*++s == 'x' || *s == 'X') { base = 16; s++; } } else base = 10; for(; isxdigit(*s); s++) { if(base == 16) if(isalpha(*s)) ret = base*ret + (toupper(*s) - 'A'); else ret = base*ret + (*s - '0'); else if(isdigit(*s)) ret = base*ret + (*s - '0'); else break; } for(; isalpha(*s); s++) { switch(toupper(*s)) { case 'K': ret *= 1024; break; case 'M': ret *= 1024*1024; break; default: return ret; } } return ret; } void *Malloc(size_t sz) { char *p; p = (char *)malloc(sz); if(p == NULL) { (void)printf("malloc(%d) failed\n",sz); exit(1); } return (void *)p; } #ifdef _WIN32 static LARGE_INTEGER _tstart, _tend; static LARGE_INTEGER freq; void tstart(void) { static int first = 1; if(first) { QueryPerformanceFrequency(&freq); first = 0; } QueryPerformanceCounter(&_tstart); } void tend(void) { QueryPerformanceCounter(&_tend); } double tval() { return ((double)_tend.QuadPart - (double)_tstart.QuadPart)/((double)freq.QuadPart); } #else static struct timeval _tstart, _tend; static struct timezone tz; void tstart(void) { gettimeofday(&_tstart, &tz); } void tend(void) { gettimeofday(&_tend,&tz); } double tval() { double t1, t2; t1 = (double)_tstart.tv_sec + (double)_tstart.tv_usec/(1000*1000); t2 = (double)_tend.tv_sec + (double)_tend.tv_usec/(1000*1000); return t2-t1; } #endif int startTimedTest(volatile int *flg) { static int first = 1; if(first) { #ifdef _WIN32 InitializeCriticalSection(&lock_run_count); #else (void)pthread_mutex_init(&lock_run_count,NULL); #endif first = 0; } run_count = 0; #ifdef _WIN32 th1 = CreateThread(NULL, 4096,timerloop,(char *)flg,NULL,&timerId); if(th1 == NULL) { printf("CreateThread FAILED: err=%d\n",errno); return 1; } #else # define DEC (void *(*)(void *)) if(pthread_create(&tA, NULL, DEC timerloop, (void *)&timedtestflag)) { printf("pthread_create FAILED: err=%d\n", errno); return 1; } #endif while(run_count != 1) YIELD; return 0; } unsigned long WINDEC timerloop(void *v) { int *flg = (int *)v; LOCK(&lock_run_count); run_count++; UNLOCK(&lock_run_count); *flg = 1; SLEEP(nseconds); *flg = 0; return 0; } void endTimedTest() { #ifdef _WIN32 (void)WaitForSingleObject(&th1, INFINITE); #else if(pthread_join(tA, (void **)&threadreturn)) { printf("pthread_join FAILED: err=%d\n",errno); return; } #endif }