On Tue, May 15, 2001 at 02:51:24PM -0400, Paul Davis wrote:
> in real-life, there is (period_duration-cpu_time_for_period) after the
> completion of a "proc" cycle during which the processor is free to run
> other threads.

Actually, its not as bad as it seems, because I forgot to run the tests as
root, so there were plenty of processes intrupting. Too many infact ;)

I will rerun the graph script if Abramo changes the program so that it
sleeps for the right amount of time.

I've attached my working version of hte latest test program and the very
dodgy perl script I use to make the graph data.

- Steve
#!/usr/bin/perl -w

if ($ARGV[0] eq "WO") {
open("WO0", ">worker-sp") || die "open failed: $!";
open("WO2", ">worker-mp") || die "open fialed: $!";

for ($size = 0; $size < 327680; $size+=8192) {
        system("cc -DWORKER_POLLUTION_SIZE=$size ctx.c -o ctx.tmp -lpthread 2> 
/dev/null");

        @foo = `./ctx.tmp 5 1024 0 866`;
        @bar = splice(@foo,-11);

        $l = 0;
        for (@bar) {
                if (/^%.*?([0-9.]+)/) {
                        if ($l < $1) {
                                $l = $1;
                        }
                }
        }

        print WO0 "$size\t$l\n";

        @foo = `./ctx.tmp 5 1024 2 866`;
        @bar = splice(@foo,-11);

        $l = 0;
        for (@bar) {
                if (/^%.*?([0-9.]+)/) {
                        if ($l < $1) {
                                $l = $1;
                        }
                }
        }

        print WO2 "$size\t$l\n";
}

close(WO0);
close(WO2);
}

if ($ARGV[0] eq "ST") {
open("ST0", ">stack-sp") || die "open failed: $!";
open("ST2", ">stack-mp") || die "open fialed: $!";

for ($size = 0; $size < 40960; $size+=128) {
        system("cc -DSTACK_POLLUTION_SIZE=$size ctx.c -o ctx.tmp -lpthread 2> 
/dev/null");

        @foo = `./ctx.tmp 5 1024 0 866`;
        @bar = splice(@foo,-11);

        $l = 0;
        for (@bar) {
                if (/^%.*?([0-9.]+)/) {
                        if ($l < $1) {
                                $l = $1;
                        }
                }
        }

        print ST0 "$size\t$l\n";

        @foo = `./ctx.tmp 5 1024 2 866`;
        @bar = splice(@foo,-11);

        $l = 0;
        for (@bar) {
                if (/^%.*?([0-9.]+)/) {
                        if ($l < $1) {
                                $l = $1;
                        }
                }
        }

        print ST2 "$size\t$l\n";
}

close(ST0);
close(ST2);
}

if ($ARGV[0] eq "SH") {
open("SH0", ">shared-sp") || die "open failed: $!";
open("SH2", ">shared-mp") || die "open fialed: $!";

for ($size = 0; $size < 204800; $size+=1024) {
        system("cc -DSHARED_POLLUTION_SIZE=$size ctx.c -o ctx.tmp -lpthread 2> 
/dev/null");

        @foo = `./ctx.tmp 5 1024 0 866`;
        @bar = splice(@foo,-11);

        $l = 0;
        for (@bar) {
                if (/^%.*?([0-9.]+)/) {
                        if ($l < $1) {
                                $l = $1;
                        }
                }
        }

        print SH0 "$size\t$l\n";

        @foo = `./ctx.tmp 5 1024 2 866`;
        @bar = splice(@foo,-11);

        $l = 0;
        for (@bar) {
                if (/^%.*?([0-9.]+)/) {
                        if ($l < $1) {
                                $l = $1;
                        }
                }
        }

        print SH2 "$size\t$l\n";
}

close(SH0);
close(SH2);
}
/*
 *  Audio component approach cost meter
 *  Copyright (c) 2001 by Abramo Bagnara <[EMAIL PROTECTED]>
 *
 *   This library is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Library General Public License as
 *   published by the Free Software Foundation; either version 2 of
 *   the License, or (at your option) any later version.
 *
 *   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 Library General Public License for more details.
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this library; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <limits.h>
#include <pthread.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <asm/msr.h>

#define MAX_WORKERS 16

#define KEY 0xabce

#define PERIOD_SIZE 64
#define RATE 48000
#define CHANNELS 26

#define BUFSIZE (PERIOD_SIZE*CHANNELS)

#ifndef STACK_POLLUTION_SIZE
#define STACK_POLLUTION_SIZE (4*1024)
#endif

#ifndef WORKER_POLLUTION_SIZE
#define WORKER_POLLUTION_SIZE (32*1024)
#endif

#ifndef SHARED_POLLUTION_SIZE
#define SHARED_POLLUTION_SIZE (64*1024)
#endif

struct space {
        float samples[BUFSIZE];
        char shared_pollution[SHARED_POLLUTION_SIZE];
};

char worker_pollution[MAX_WORKERS][WORKER_POLLUTION_SIZE];

struct space *area;

void proc(unsigned int n)
{
        unsigned int k;
        float *samples = area->samples;
        char *wp = worker_pollution[n];
#if STACK_POLLUTION_SIZE > 0
        {
                char stack_pollution[STACK_POLLUTION_SIZE];
                memset(stack_pollution, 0xaa, STACK_POLLUTION_SIZE);
        }
#endif
#if SHARED_POLLUTION_SIZE > 0
        memset(area->shared_pollution, 0xaa, SHARED_POLLUTION_SIZE);
#endif
#if WORKER_POLLUTION_SIZE > 0
        memset(wp, 0xaa, WORKER_POLLUTION_SIZE);
#endif
        for (k = 0; k < BUFSIZE; k++)
                samples[k]++;
}

unsigned long long singlethread(unsigned int workers, unsigned int periods)
{
        unsigned long long begin, end;
        unsigned int k;
        float *samples;
        unsigned int p;
        area = malloc(sizeof(*area));
        samples = area->samples;
        for (k = 0; k < BUFSIZE; k++)
                samples[k] = 0.0;

        p = periods;

        rdtscll(begin);
        while (p-- > 0) {
                int n;
                for (n = 0; n < workers; ++n) {
                        proc(n);
                }
        }
        rdtscll(end);

        for (k = 0; k < BUFSIZE; k++)
                assert(samples[k] == periods * workers);
        
        free(area);
        return end - begin;
}

struct thr {
        int worker;
        pthread_t thread;
        int in, out;
} threads[MAX_WORKERS];

void *thread(void *data)
{
        char buf[1];
        struct thr *t = data;
        int err;
        float *samples = area->samples;
        char *wp = worker_pollution[t->worker];
        while (1) {
                unsigned int k;
                err = read(t->in, buf, 1);
                assert(err == 1);
                if (!buf[0]) {
                        err = write(t->out, buf, 1);
                        assert(err == 1);
                        break;
                }
#if STACK_POLLUTION_SIZE > 0
                {
                        char stack_pollution[STACK_POLLUTION_SIZE];
                        memset(stack_pollution, 0xaa, STACK_POLLUTION_SIZE);
                }
#endif
#if SHARED_POLLUTION_SIZE > 0
                memset(area->shared_pollution, 0xaa, SHARED_POLLUTION_SIZE);
#endif
#if WORKER_POLLUTION_SIZE > 0
                memset(wp, 0xaa, WORKER_POLLUTION_SIZE);
#endif
                for (k = 0; k < BUFSIZE; k++)
                        samples[k]++;
                err = write(t->out, buf, 1);
                assert(err == 1);
        }
        return 0;
}

unsigned long long multithread(unsigned int workers, unsigned int periods)
{
        unsigned long long begin, end;
        int err;
        unsigned int k;
        char buf[1] = { 1 };
        float *samples;
        unsigned int p;
        int fds[workers + 1][2];
        int in, out;
        area = malloc(sizeof(*area));

        samples = area->samples;

        for (k = 0; k <= workers; ++k) {
                err = pipe(fds[k]);
                assert(err == 0);
        }

        out = fds[0][1];
        in = fds[workers][0];
        for (k = 0; k < workers; ++k) {
                threads[k].worker = k;
                threads[k].in = fds[k][0];
                threads[k].out = fds[k + 1][1];
                err = pthread_create(&threads[k].thread, NULL, thread, &threads[k]);
                assert(err == 0);
        }

        /* Ensure all is started */
        err = write(out, buf, 1);
        assert(err == 1);
        err = read(in, buf, 1);
        assert(err == 1);

        for (k = 0; k < BUFSIZE; k++)
                samples[k] = 0.0;
        p = periods;

        rdtscll(begin);
        while (p-- > 0) {
                err = write(out, buf, 1);
                assert(err == 1);
                err = read(in, buf, 1);
                assert(err == 1);
        }
        rdtscll(end);

        buf[0] = 0;
        err = write(out, buf, 1);
        assert(err == 1);

        for (k = 0; k < workers; ++k) {
                err = pthread_join(threads[k].thread, 0);
                assert(err == 0);
        }
        for (k = 0; k <= workers; ++k) {
                close(fds[k][0]);
                close(fds[k][1]);
        }

        for (k = 0; k < BUFSIZE; k++)
                assert(samples[k] == periods * workers);

        free(area);
        return end - begin;
}

struct pro {
        int worker;
        pid_t pid;
        int in, out;
} processes[MAX_WORKERS];

void process(struct pro *p)
{
        char buf[1];
        int err;
        float *samples;
        int shmid = shmget(KEY, sizeof(*area), 0666);
        char *wp = worker_pollution[p->worker];
        assert(shmid >= 0);
        area = shmat(shmid, NULL, 0);
        assert(area != (void *) -1);
        samples = area->samples;
        while (1) {
                unsigned int k;
                err = read(p->in, buf, 1);
                assert(err == 1);
                if (!buf[0]) {
                        err = write(p->out, buf, 1);
                        assert(err == 1);
                        break;
                }
#if STACK_POLLUTION_SIZE > 0
                {
                        char stack_pollution[STACK_POLLUTION_SIZE];
                        memset(stack_pollution, 0xaa, STACK_POLLUTION_SIZE);
                }
#endif
#if SHARED_POLLUTION_SIZE > 0
                memset(area->shared_pollution, 0xaa, SHARED_POLLUTION_SIZE);
#endif
#if WORKER_POLLUTION_SIZE > 0
                memset(wp, 0xaa, WORKER_POLLUTION_SIZE);
#endif
                for (k = 0; k < BUFSIZE; k++)
                        samples[k]++;
                err = write(p->out, buf, 1);
                assert(err == 1);
        
        }
        exit(0);
}

unsigned long long multiprocess(unsigned int workers, unsigned int periods)
{
        unsigned long long begin, end;
        int err;
        unsigned int k;
        char buf[1] = { 1 };
        float *samples;
        int fds[workers + 1][2];
        int in, out;
        int shmid = shmget(KEY, sizeof(*area), IPC_CREAT | 0666);
        unsigned int p;
        assert(shmid >= 0);
        area = shmat(shmid, NULL, 0);
        assert(area != (void *) -1);

        samples = area->samples;

        for (k = 0; k <= workers; ++k) {
                err = pipe(fds[k]);
                assert(err == 0);
        }

        out = fds[0][1];
        in = fds[workers][0];
        for (k = 0; k < workers; ++k) {
                processes[k].worker = k;
                processes[k].in = fds[k][0];
                processes[k].out = fds[k + 1][1];
                err = fork();
                assert(err >= 0);
                if (err == 0)
                        process(&processes[k]);
                processes[k].pid = err;
        }

        /* Ensure all is started */
        err = write(out, buf, 1);
        assert(err == 1);
        err = read(in, buf, 1);
        assert(err == 1);
        
        for (k = 0; k < BUFSIZE; k++)
                samples[k] = 0.0;
        p = periods;

        rdtscll(begin);
        while (p-- > 0) {
                err = write(out, buf, 1);
                assert(err == 1);
                err = read(in, buf, 1);
                assert(err == 1);
        }
        rdtscll(end);

        buf[0] = 0;
        err = write(out, buf, 1);
        assert(err == 1);

        for (k = 0; k < workers; ++k) {
                err = waitpid(processes[k].pid, NULL, 0);
                assert(err >= 0);
        }
        for (k = 0; k <= workers; ++k) {
                close(fds[k][0]);
                close(fds[k][1]);
        }

        for (k = 0; k < BUFSIZE; k++)
                assert(samples[k] == periods * workers);

        err = shmdt(area);
        assert(err >= 0);
        err = shmctl(shmid, IPC_RMID, 0);
        assert(err >= 0);

        return end - begin;
}

void setscheduler(void)
{
        struct sched_param sched_param;

        if (sched_getparam(0, &sched_param) < 0) {
                printf("Scheduler getparam failed\n");
                return;
        }
        sched_param.sched_priority = sched_get_priority_max(SCHED_RR);
        if (!sched_setscheduler(0, SCHED_RR, &sched_param)) {
                printf("Scheduler set to Round Robin with priority %i...\n", 
sched_param.sched_priority);
                return;
        }
        printf("Scheduler set to Round Robin with priority %i failed\n", 
sched_param.sched_priority);
}


#define ST 0
#define MT 1
#define MP 2

/* Usage: ctx workers periods how mhz */

int main(int argc, char **argv)
{
        unsigned long long t;
        unsigned int workers = atoi(argv[1]);
        unsigned int periods = atoi(argv[2]);
        unsigned int how = atoi(argv[3]);
        double mhz = atof(argv[4]);
        double c;
        int k;

        setscheduler();

        for (k = 0; k < 5; ++k) {
        switch (how) {
        case ST:
                t = singlethread(workers, periods);
                break;
        case MT:
                t = multithread(workers, periods);
                break;
        case MP:
                t = multiprocess(workers, periods);
                break;
        default:
                assert(0);
                break;
        }

        c = (double) t / periods;
        printf("Cycles per period: %f\n", c);
        printf("%%CPU usage: %f\n", (100 * c / mhz) / (1000000.0 * PERIOD_SIZE / 
RATE));
        }
        return 0;
}

Reply via email to