/* * semscale.cpp - sysv scaling test * * Copyright (C) 1999, 2001, 2005, 2008, 2010 by Manfred Spraul. * All rights reserved except the rights granted by the GPL. * * Redistribution of this file is permitted under the terms of the GNU * General Public License (GPL) version 2 or later. * $Header$ */ #include #include #include #include #include #include #include #include #include #include #ifdef __sun #include /* P_PID, processor_bind() */ #endif #define VERBOSE #undef VERBOSE ////////////////////////////////////////////////////////////////////////////// #define DELAY_LOOPS 20 static volatile int g_numerator = 12345678; static volatile int g_denominator = 123456; unsigned long long do_delay(int loops) { unsigned long long sum; int i, j; sum = loops; for (i=0;i0) { ret += interleave; if (ret >=g_max_cpus) { off++; ret = off; } cpunr--; } #ifdef VERBOSE printf("get_cpunr %p: result %d.\n", (void*)pthread_self(), ret); #endif return ret; } void bind_cpu(int cpunr) { int ret; #if __sun ret = processor_bind(P_PID, getpid(), cpunr, NULL); if (ret == -1) { perror("bind_thread:processor_bind"); printf(" Binding to cpu %d failed.\n", cpunr); } #else cpu_set_t cpus; cpu_set_t v; CPU_ZERO(&cpus); CPU_SET(cpunr, &cpus); pthread_t self; self = pthread_self(); ret = pthread_setaffinity_np(self, sizeof(cpus), &cpus); if (ret < 0) { printf("pthread_setaffinity_np failed for thread %p with errno %d.\n", (void*)self, errno); } ret = pthread_getaffinity_np(self, sizeof(v), &v); if (ret < 0) { printf("pthread_getaffinity_np() failed for thread %p with errno %d.\n", (void*)self, errno); fflush(stdout); } if (memcmp(&v, &cpus, sizeof(cpus) != 0)) { printf("Note: Actual affinity does not match intention: got 0x%08lx, expected 0x%08lx.\n", (unsigned long)v.__bits[0], (unsigned long)cpus.__bits[0]); } fflush(stdout); #endif } void* worker_thread(void *arg) { struct taskinfo *ti = (struct taskinfo*)arg; unsigned long long rounds; int ret; int cpu = get_cpunr(ti->cpubind, ti->interleave); bind_cpu(cpu); #ifdef VERBOSE printf("thread %d: sysvsem %8d, off %8d bound to cpu %d\n",ti->threadid, ti->svsem_id, ti->svsem_nr,cpu); #endif rounds = 0; while(g_state == WAITING) { #ifdef __GNUC__ #if defined(__i386__) || defined (__x86_64__) __asm__ __volatile__("pause": : :"memory"); #else __asm__ __volatile__("": : :"memory"); #endif #endif } while(g_state == RUNNING) { struct sembuf sop[1]; /* 1) check if the semaphore value is 0 */ sop[0].sem_num=ti->svsem_nr; sop[0].sem_op=0; sop[0].sem_flg=0; ret = semop(ti->svsem_id,sop,1); if (ret != 0) { /* EIDRM can happen */ if (errno == EIDRM) break; printf("main semop failed, ret %d errno %d.\n", ret, errno); /* Some OS do not report EIDRM properly */ if (g_state != RUNNING) break; printf(" round %lld sop: num %d op %d flg %d.\n", rounds, sop[0].sem_num, sop[0].sem_op, sop[0].sem_flg); fflush(stdout); exit(1); } if (ti->delay) do_delay(ti->delay); rounds++; } g_results[ti->threadid] = rounds; pthread_exit(0); return NULL; } void init_threads(int cpu, int cpus, int delay, int interleave) { int ret; struct taskinfo *ti; ti = (struct taskinfo*)malloc(sizeof(struct taskinfo)); if (!ti) { printf("Could not allocate task info\n"); exit(1); } if (cpu == 0) { int i; g_svsem_id = semget(IPC_PRIVATE,cpus,0777|IPC_CREAT); if(g_svsem_id == -1) { printf("sem array create failed.\n"); exit(1); } for (i=0;isvsem_id = g_svsem_id; ti->svsem_nr = g_svsem_nrs[cpu]; ti->threadid = cpu; ti->cpubind = cpu; ti->interleave = interleave; ti->delay = delay; ret = pthread_create(&g_threads[ti->threadid], NULL, worker_thread, ti); if (ret) { printf(" pthread_create failed with error code %d\n", ret); exit(1); } } ////////////////////////////////////////////////////////////////////////////// unsigned long long do_psem(int cpus, int timeout, int delay, int interleave) { unsigned long long totals; int i; int res; g_state = WAITING; g_results = (unsigned long long*)malloc(sizeof(unsigned long long)*cpus); g_svsem_nrs = (int*)malloc(sizeof(int)*cpus); g_threads = (pthread_t*)malloc(sizeof(pthread_t)*cpus); for (i=0;i \n"); if (argc < 2) { printf(" Invalid parameters.\n"); return 0; } timeout = atoi(argv[1]); if (argc > 2) { max_interleave = atoi(argv[2]); } else { max_interleave = 16; } if (argc > 3) { g_max_cpus = atoi(argv[3]); } else { cpu_set_t cpus; int ret; ret = pthread_getaffinity_np(pthread_self(), sizeof(cpus), &cpus); if (ret < 0) { printf("pthread_getaffinity_np() failed with errno %d.\n", errno); fflush(stdout); g_max_cpus = 4; } else { g_max_cpus = 0; while (CPU_ISSET(g_max_cpus, &cpus)) g_max_cpus++; } if (g_max_cpus == 0) { printf("Autodetection of the number of cpus failed.\n"); return 1; } printf("Autodetected number of cpus: %d.\n", g_max_cpus); } if (g_max_cpus >= 2) { while (max_interleave >= g_max_cpus) { max_interleave = max_interleave/2; } } else { max_interleave = 1; } printf("Adjusted max interleave: %d.\n", max_interleave); for (k=1;k<=max_interleave;k*=2) { for (j=0;;) { max_totals = 0; fastest = 0; for (i=1;;) { totals = do_psem(i, timeout, j, k); if (totals > max_totals) { max_totals = totals; fastest = i; } else { if (totals < 0.5*max_totals && i > 1.5*fastest) break; } if (i== g_max_cpus) break; i += i * 0.2 + 1; if (i > g_max_cpus) i = g_max_cpus; } printf("Interleave %d, delay %d: Max total: %lld with %d cpus\n", k, j, max_totals, fastest); if (fastest == g_max_cpus) break; j += j * 0.2 + 1; } } }