You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
232 lines
4.2 KiB
232 lines
4.2 KiB
#include <litc.h>
|
|
|
|
static long
|
|
nowms(void)
|
|
{
|
|
struct timeval tv;
|
|
if (gettimeofday(&tv, NULL))
|
|
err(-1, "gettimeofday");
|
|
return tv.tv_sec*1000 + tv.tv_usec/1000;
|
|
}
|
|
|
|
static long
|
|
_fetch(long n)
|
|
{
|
|
long ret;
|
|
if ((ret = sys_info(n)) < 0)
|
|
errx(-1, "sysinfo");
|
|
return ret;
|
|
}
|
|
|
|
static long
|
|
gccount(void)
|
|
{
|
|
return _fetch(SINFO_GCCOUNT);
|
|
}
|
|
|
|
static long
|
|
gctotns(void)
|
|
{
|
|
return _fetch(SINFO_GCPAUSENS);
|
|
}
|
|
|
|
static long
|
|
gcheapuse(void)
|
|
{
|
|
return _fetch(SINFO_GCHEAPSZ);
|
|
}
|
|
|
|
struct res_t {
|
|
long xput;
|
|
long longest;
|
|
};
|
|
|
|
__attribute__((noreturn))
|
|
static void _workmmap(long endms, int resfd)
|
|
{
|
|
long longest = 0;
|
|
long count = 0;
|
|
while (1) {
|
|
long st = nowms();
|
|
if (st > endms)
|
|
break;
|
|
size_t sz = 4096 * 100;
|
|
void *m = mmap(NULL, sz, PROT_READ | PROT_WRITE,
|
|
MAP_PRIVATE | MAP_ANON, -1, 0);
|
|
if (m == MAP_FAILED)
|
|
err(-1, "mmap");
|
|
if (munmap(m, sz))
|
|
err(-1, "munmap");
|
|
long tot = nowms() - st;
|
|
if (tot > longest)
|
|
longest = tot;
|
|
count++;
|
|
}
|
|
struct res_t rs = {.xput = count, .longest = longest};
|
|
if (write(resfd, &rs, sizeof(rs)) != sizeof(rs))
|
|
err(-1, "res write");
|
|
exit(0);
|
|
}
|
|
|
|
static void work(long wf, const long np)
|
|
{
|
|
long secs = wf;
|
|
if (secs < 0)
|
|
secs = 1;
|
|
else if (secs > 60)
|
|
secs = 60;
|
|
|
|
printf("working for %ld seconds with %ld processes...\n", secs, np);
|
|
|
|
int resp[2];
|
|
if (pipe(resp))
|
|
err(-1, "pipe");
|
|
|
|
long bgcs = gccount();
|
|
long bgcns = gctotns();
|
|
|
|
long endms = nowms() + secs*1000;
|
|
pid_t ps[np];
|
|
int i;
|
|
for (i = 0; i < np; i++) {
|
|
if ((ps[i] = fork()) < 0)
|
|
errx(-1, "fork");
|
|
else if (ps[i] == 0) {
|
|
close(resp[0]);
|
|
_workmmap(endms, resp[1]);
|
|
}
|
|
}
|
|
close(resp[1]);
|
|
|
|
struct gcfrac_t gcf = gcfracst();
|
|
//fake_sys(1);
|
|
|
|
long longest = 0, totalxput = 0;
|
|
long longarr[np];
|
|
for (i = 0; i < np; i++) {
|
|
int status;
|
|
if (wait(&status) < 0)
|
|
err(-1, "wait");
|
|
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
|
err(-1, "child failed");
|
|
|
|
struct res_t got;
|
|
if (read(resp[0], &got, sizeof(got)) != sizeof(got))
|
|
err(-1, "res read");
|
|
|
|
totalxput += got.xput;
|
|
longarr[i] = got.longest;
|
|
if (got.longest > longest)
|
|
longest = got.longest;
|
|
}
|
|
|
|
//fake_sys(0);
|
|
|
|
long gcs = gccount() - bgcs;
|
|
long gcns = gctotns() - bgcns;
|
|
|
|
long xput = secs > 0 ? totalxput/secs : 0;
|
|
printf("iterations/sec: %ld (%ld total)\n", xput, totalxput);
|
|
printf("CPU time GC'ing: %f%%\n", gcfracend(&gcf, NULL, NULL, NULL));
|
|
printf("max latency: %ld ms\n", longest);
|
|
printf("each process' latency:\n");
|
|
for (i = 0; i < np; i++)
|
|
printf(" %ld\n", longarr[i]);
|
|
printf("%ld gcs (%ld ms)\n", gcs, gcns/1000000);
|
|
printf("kernel heap use: %ld Mb\n", gcheapuse()/(1 << 20));
|
|
}
|
|
|
|
int _vnodes(long sf)
|
|
{
|
|
size_t nf = 1000*sf;
|
|
printf("creating %zu vnodes...\n", nf);
|
|
size_t tenpct = nf/10;
|
|
size_t next = 1;
|
|
size_t n;
|
|
for (n = 0; n < nf; n++) {
|
|
int fd = open("dummy", O_CREAT | O_EXCL | O_RDWR, S_IRWXU);
|
|
if (fd < 0)
|
|
err(-1, "open");
|
|
if (unlink("dummy"))
|
|
err(-1, "unlink");
|
|
size_t cp = n/tenpct;
|
|
if (cp >= next) {
|
|
printf("%zu%%\n", cp*10);
|
|
next = cp + 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
__attribute__((noreturn))
|
|
void usage(void)
|
|
{
|
|
printf("usage:\n");
|
|
printf("%s [-g] [-s <int>] [-w <int>] [-n <int>]\n", __progname);
|
|
printf("where:\n");
|
|
printf("-g force kernel GC, then exit\n");
|
|
printf("-s <int> set scale factor to int\n");
|
|
printf("-w <int> set work factor to int\n");
|
|
printf("-n <int> set number of worker processes to int\n\n");
|
|
exit(-1);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
long sf = 1, wf = 1, nprocs = 1;
|
|
int dogc = 0;
|
|
|
|
int c;
|
|
while ((c = getopt(argc, argv, "n:gms:w:")) != -1) {
|
|
switch (c) {
|
|
case 'g':
|
|
dogc = 1;
|
|
break;
|
|
case 'n':
|
|
nprocs = strtol(optarg, NULL, 0);
|
|
break;
|
|
case 's':
|
|
sf = strtol(optarg, NULL, 0);
|
|
break;
|
|
case 'w':
|
|
wf = strtol(optarg, NULL, 0);
|
|
break;
|
|
default:
|
|
usage();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (optind != argc)
|
|
usage();
|
|
|
|
if (dogc) {
|
|
_fetch(10);
|
|
printf("kernel heap use: %ld Mb\n", gcheapuse()/(1 << 20));
|
|
return 0;
|
|
}
|
|
|
|
if (sf < 0)
|
|
sf = 1;
|
|
if (wf < 0)
|
|
wf = 1;
|
|
if (nprocs < 0)
|
|
nprocs = 1;
|
|
printf("scale factor: %ld, work factor: %ld, worker procs: %ld\n",
|
|
sf, wf, nprocs);
|
|
|
|
long st = nowms();
|
|
|
|
int (*f)(long) = _vnodes;
|
|
if (f(sf))
|
|
return -1;
|
|
|
|
long tot = nowms() - st;
|
|
printf("setup: %ld ms\n", tot);
|
|
|
|
work(wf, nprocs);
|
|
|
|
return 0;
|
|
}
|