⬢ DragonFlyBSD Kernel Audit
DF-3093 / conc.c
← back to finding ↓ download raw
/* concurrency probe: are N pinned children really running in parallel?
 * mode A (default): N pinned spinners increment shared counters for 2s;
 *   print per-child and aggregate rates.  6x single rate == parallel.
 * mode W: N pinned children barrier-release then each does one write()
 *   of chunk bytes to its own pre-created file; print per-child release
 *   timestamp (ns) and write duration (ns).
 * build: cc -O2 -o conc conc.c
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/usched.h>
#include <sys/wait.h>
#include <sys/mman.h>

#define MAXP 8
struct shm {
	volatile unsigned int go;
	volatile unsigned int ready[MAXP];
	volatile unsigned long cnt[MAXP];
	volatile long long trel[MAXP];	/* ns at release */
	volatile long long tdur[MAXP];	/* ns write duration */
};
static struct shm *shm;

static long long
nsnow(void)
{
	struct timespec ts;
	clock_gettime(CLOCK_MONOTONIC, &ts);
	return ((long long)ts.tv_sec * 1000000000LL + ts.tv_nsec);
}

int
main(int argc, char **argv)
{
	int nprocs = 6, i;
	long chunk = 2097152;
	const char *mnt = ".";
	int writemode = 0;

	if (argc > 1) nprocs = atoi(argv[1]);
	if (argc > 2) writemode = strcmp(argv[2], "w") == 0;
	if (argc > 3) chunk = strtol(argv[3], NULL, 0);
	if (argc > 4) mnt = argv[4];

	shm = mmap(NULL, sizeof(*shm), PROT_READ | PROT_WRITE,
	    MAP_ANON | MAP_SHARED, -1, 0);
	memset((void *)shm, 0, sizeof(*shm));

	if (!writemode) {
		for (i = 0; i < nprocs; i++)
			if (fork() == 0) {
				int cpuid = i, dummy = 0;
				usched_set(0, USCHED_SET_CPU, &cpuid,
				    sizeof(cpuid));
				shm->ready[i] = 1;
				while (!shm->go)
					;
				for (;;)
					shm->cnt[i]++;
				_exit(0);
			}
		while (1) {
			int done = 1;
			for (i = 0; i < nprocs; i++)
				if (!shm->ready[i]) done = 0;
			if (done) break;
			usleep(1000);
		}
		shm->go = 1;
		sleep(2);
		for (i = 0; i < nprocs; i++)
			printf("child %d: %lu spins/sec\n", i, shm->cnt[i]/2);
		fflush(stdout);
		kill(0, SIGKILL);
		exit(0);
	}

	/* write mode: pre-create files, barrier, one write each, timing */
	{
		char path[512];
		char *buf = malloc(chunk);
		for (i = 0; i < nprocs; i++) {
			snprintf(path, sizeof(path), "%s/w%d", mnt, i);
			int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
			if (fd < 0) { perror(path); exit(1); }
			close(fd);
		}
		for (i = 0; i < nprocs; i++)
			if (fork() == 0) {
				int cpuid = i, fd;
				long long t0, t1;
				usched_set(0, USCHED_SET_CPU, &cpuid,
				    sizeof(cpuid));
				snprintf(path, sizeof(path), "%s/w%d", mnt, i);
				fd = open(path, O_WRONLY);
				shm->ready[i] = 1;
				while (!shm->go)
					;
				t0 = nsnow();
				ssize_t _n = write(fd, buf, chunk);
				if (_n != chunk) {
					shm->tdur[i] = -errno - 1000000;
				} else {
					t1 = nsnow();
					shm->trel[i] = t0;
					shm->tdur[i] = t1 - t0;
				}
				close(fd);
				_exit(0);
			}
		while (1) {
			int done = 1;
			for (i = 0; i < nprocs; i++)
				if (!shm->ready[i]) done = 0;
			if (done) break;
			usleep(1000);
		}
		shm->go = 1;
		for (i = 0; i < nprocs; i++) {
			int st;
			wait(&st);
			printf("child %d: release=%lld write_dur=%lld us%s\n",
			    i, shm->trel[i] ? shm->trel[i] : -1,
			    shm->tdur[i] / 1000,
			    shm->tdur[i] <= -1000000 ?
			    "  WRITE FAILED" : "");
		}
		exit(0);
	}
}