DF-3093 / conc.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | /* 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); } } |