/* * Copyright (C) 2009 Török Edwin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ /* * Compile with: gcc scheduler.c -Wall -lm -pthread -g -O2 */ #include #include #include #include #include #include #include #include #include #include #include #include #define RUSAGE_THREAD 1 /* why isn't this in resource.h? */ static int32_t mmap_sem_congestion_all() { void *data = mmap(NULL, 256*1024, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if (data == MAP_FAILED) { perror("mmap"); abort(); } madvise(data, 256*1024, MADV_RANDOM|MADV_DONTFORK); memset(data, 0x5a, 256*1024); munmap(data, 256*1024); return 1; } static int32_t mmap_sem_congestion_firstpage() { void *data = mmap(NULL, 256*1024, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if (data == MAP_FAILED) { perror("mmap"); abort(); } madvise(data, 256*1024, MADV_RANDOM|MADV_DONTFORK); memset(data, 0x5a, 4096); munmap(data, 256*1024); return 1; } static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static int32_t mmap_sem_congestion_mtx_all() { pthread_mutex_lock(&mutex); void *data = mmap(NULL, 256*1024, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); madvise(data, 256*1024, MADV_RANDOM|MADV_DONTFORK); pthread_mutex_unlock(&mutex); if (data == MAP_FAILED) { perror("mmap"); abort(); } memset(data, 0x5a, 256*1024); pthread_mutex_lock(&mutex); munmap(data, 256*1024); pthread_mutex_unlock(&mutex); return 1; } static int32_t mmap_sem_congestion_mtx_firstpage() { pthread_mutex_lock(&mutex); void *data = mmap(NULL, 256*1024, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); madvise(data, 256*1024, MADV_RANDOM|MADV_DONTFORK); memset(data, 0x5a, 4096); pthread_mutex_unlock(&mutex); if (data == MAP_FAILED) { perror("mmap"); abort(); } pthread_mutex_lock(&mutex); munmap(data, 256*1024); pthread_mutex_unlock(&mutex); return 1; } typedef int32_t (*foofunc)(void); volatile int nodce; struct result { long double average; long double sum; long double sum2; uint64_t tmax; uint64_t tmin; struct timeval elapsedtime; struct rusage rusage; } result; static pthread_mutex_t result_mutex = PTHREAD_MUTEX_INITIALIZER; static void timeit(foofunc f, const char *name, unsigned ntimings, unsigned nloops) { struct rusage rs0, rs1; struct timeval tv00, tv01; int64_t timings[ntimings], tmin,tmax; long double avg, sum2; int64_t sum=0; int32_t tmp=0; unsigned i, j; if (getrusage(RUSAGE_THREAD, &rs0) == -1) { perror("getrusage"); abort(); } gettimeofday(&tv00, NULL); for (j=0;j tmax) tmax = timings[j]; else if (timings[j] < tmin) { tmin = timings[j]; } long double t = timings[j]/nloops; sum2 += t*t; } pthread_mutex_lock(&result_mutex); result.average += avg; result.sum += sum/nloops; result.sum2 += sum2; result.elapsedtime.tv_sec += tv01.tv_sec - tv00.tv_sec; result.elapsedtime.tv_usec += tv01.tv_usec - tv00.tv_usec; if (tmax > result.tmax) result.tmax = tmax; if (tmin < result.tmin) result.tmin = tmin; result.rusage.ru_utime.tv_sec += rs1.ru_utime.tv_sec - rs0.ru_utime.tv_sec; result.rusage.ru_utime.tv_usec += rs1.ru_utime.tv_usec - rs0.ru_utime.tv_usec; result.rusage.ru_stime.tv_sec += rs1.ru_stime.tv_sec - rs0.ru_stime.tv_sec; result.rusage.ru_stime.tv_usec += rs1.ru_stime.tv_usec - rs0.ru_stime.tv_usec; result.rusage.ru_minflt += rs1.ru_minflt - rs0.ru_minflt; result.rusage.ru_majflt += rs1.ru_majflt - rs0.ru_majflt; result.rusage.ru_nvcsw += rs1.ru_nvcsw - rs0.ru_nvcsw; result.rusage.ru_nivcsw += rs1.ru_nivcsw - rs0.ru_nivcsw; pthread_mutex_unlock(&result_mutex); } struct data { const char *name; foofunc f; unsigned ntimings; unsigned nloops; }; static void *thread(void* arg) { struct data *data = (struct data*)arg; timeit(data->f, data->name, data->ntimings, data->nloops); return arg; } static int numcpu; static void runtest(const char *name, foofunc f, unsigned ntimings, unsigned nloops, unsigned nthreads) { unsigned i; pthread_t threads[nthreads]; struct data data; data.name = name; data.f = f; data.ntimings = ntimings; data.nloops = nloops; printf("Starting test %s\n", name); memset(&result, 0, sizeof(result)); for (i=0;i 2) { ntimings = atoi(argv[1]); if (argc > 3) { nloops = atoi(argv[2]); if (argc > 4) { nthreads = atoi(argv[3]); } } } printf("Running tests with ntimings=%u, nloops=%u, nthreads=%u, number of CPUs=%u\n", ntimings, nloops, nthreads, numcpu); runtest("mmap sem congestion (memset all)", mmap_sem_congestion_all, ntimings, nloops, nthreads); runtest("mmap sem congestion with mutex workaround (memset all)", mmap_sem_congestion_mtx_all, ntimings, nloops, nthreads); runtest("mmap sem congestion (memset firstpage)", mmap_sem_congestion_firstpage, ntimings, nloops, nthreads); runtest("mmap sem congestion with mutex workaround (memset firstpage)", mmap_sem_congestion_mtx_firstpage, ntimings, nloops, nthreads); return 0; }