nsprpub/pr/src/cplus/tests/switch.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/nsprpub/pr/src/cplus/tests/switch.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,234 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/*
    1.10 +** File:            switch.cpp
    1.11 +** Description:     trying to time context switches
    1.12 +*/
    1.13 +
    1.14 +#include "rccv.h"
    1.15 +#include "rcinrval.h"
    1.16 +#include "rclock.h"
    1.17 +#include "rcthread.h"
    1.18 +
    1.19 +#include <prio.h>
    1.20 +#include <prlog.h>
    1.21 +#include <prprf.h>
    1.22 +#include <plerror.h>
    1.23 +#include <plgetopt.h>
    1.24 +
    1.25 +#include <stdlib.h>
    1.26 +
    1.27 +#define INNER_LOOPS 100
    1.28 +#define DEFAULT_LOOPS 100
    1.29 +#define DEFAULT_THREADS 10
    1.30 +
    1.31 +static PRFileDesc *debug_out = NULL;
    1.32 +static PRBool debug_mode = PR_FALSE, verbosity = PR_FALSE, failed = PR_FALSE;
    1.33 +
    1.34 +class Home: public RCCondition
    1.35 +{
    1.36 +public:
    1.37 +    virtual ~Home();
    1.38 +    Home(Home *link, RCLock* ml);
    1.39 +
    1.40 +public:
    1.41 +    Home *next;
    1.42 +    RCLock* ml;
    1.43 +    PRBool twiddle;
    1.44 +};  /* Home */
    1.45 +
    1.46 +Home::~Home() { }
    1.47 +
    1.48 +Home::Home(Home *link, RCLock* lock): RCCondition(lock)
    1.49 +{
    1.50 +    ml = lock;
    1.51 +    next = link;
    1.52 +    twiddle = PR_FALSE;
    1.53 +}  /* Home::Home */
    1.54 +
    1.55 +class Shared: public Home, public RCThread
    1.56 +{
    1.57 +public:
    1.58 +    Shared(RCThread::Scope scope, Home* link, RCLock* ml);
    1.59 +
    1.60 +private:
    1.61 +    ~Shared();
    1.62 +    void RootFunction();
    1.63 +};  /* Shared */
    1.64 +
    1.65 +Shared::Shared(RCThread::Scope scope, Home* link, RCLock* lock):
    1.66 +    Home(link, lock), RCThread(scope, RCThread::joinable) { }
    1.67 +
    1.68 +Shared::~Shared() { }
    1.69 +
    1.70 +void Shared::RootFunction()
    1.71 +{
    1.72 +    PRStatus status = PR_SUCCESS;
    1.73 +    while (PR_SUCCESS == status)
    1.74 +    {
    1.75 +        RCEnter entry(ml);
    1.76 +        while (twiddle && (PR_SUCCESS == status)) status = Wait();
    1.77 +		if (verbosity) PR_fprintf(debug_out, "+");
    1.78 +        twiddle = PR_TRUE;
    1.79 +        next->twiddle = PR_FALSE;
    1.80 +        next->Notify();
    1.81 +    }
    1.82 +}  /* Shared::RootFunction */
    1.83 +
    1.84 +static void Help(void)
    1.85 +{
    1.86 +    debug_out = PR_STDOUT;
    1.87 +
    1.88 +    PR_fprintf(
    1.89 +		debug_out, "Usage: >./switch [-d] [-c n] [-t n] [-T n] [-G]\n");
    1.90 +    PR_fprintf(
    1.91 +		debug_out, "-c n\tloops at thread level (default: %d)\n", DEFAULT_LOOPS);
    1.92 +    PR_fprintf(
    1.93 +		debug_out, "-t n\tnumber of threads (default: %d)\n", DEFAULT_THREADS);
    1.94 +    PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n");
    1.95 +    PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n");
    1.96 +    PR_fprintf(debug_out, "-G n\tglobal threads only (default: FALSE)\n");
    1.97 +    PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n");
    1.98 +}  /* Help */
    1.99 +
   1.100 +PRIntn main(PRIntn argc, char **argv)
   1.101 +{
   1.102 +	PLOptStatus os;
   1.103 +    PRStatus status;
   1.104 +    PRBool help = PR_FALSE;
   1.105 +    PRUintn concurrency = 1;
   1.106 +    RCThread::Scope thread_scope = RCThread::local;
   1.107 +    PRUintn thread_count, inner_count, loop_count, average;
   1.108 +    PRUintn thread_limit = DEFAULT_THREADS, loop_limit = DEFAULT_LOOPS;
   1.109 +	PLOptState *opt = PL_CreateOptState(argc, argv, "hdvc:t:C:G");
   1.110 +	while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
   1.111 +    {
   1.112 +		if (PL_OPT_BAD == os) continue;
   1.113 +        switch (opt->option)
   1.114 +        {
   1.115 +        case 'v':  /* verbose mode */
   1.116 +			verbosity = PR_TRUE;
   1.117 +        case 'd':  /* debug mode */
   1.118 +			debug_mode = PR_TRUE;
   1.119 +            break;
   1.120 +        case 'c':  /* loop counter */
   1.121 +			loop_limit = atoi(opt->value);
   1.122 +            break;
   1.123 +        case 't':  /* thread limit */
   1.124 +			thread_limit = atoi(opt->value);
   1.125 +            break;
   1.126 +        case 'C':  /* Concurrency limit */
   1.127 +			concurrency = atoi(opt->value);
   1.128 +            break;
   1.129 +        case 'G':  /* global threads only */
   1.130 +			thread_scope = RCThread::global;
   1.131 +            break;
   1.132 +        case 'h':  /* help message */
   1.133 +			Help();
   1.134 +			help = PR_TRUE;
   1.135 +            break;
   1.136 +         default:
   1.137 +            break;
   1.138 +        }
   1.139 +    }
   1.140 +	PL_DestroyOptState(opt);
   1.141 +
   1.142 +    if (help) return -1;
   1.143 +
   1.144 +	if (PR_TRUE == debug_mode)
   1.145 +	{
   1.146 +		debug_out = PR_STDOUT;
   1.147 +		PR_fprintf(debug_out, "Test parameters\n");
   1.148 +		PR_fprintf(debug_out, "\tThreads involved: %d\n", thread_limit);
   1.149 +		PR_fprintf(debug_out, "\tIteration limit: %d\n", loop_limit);
   1.150 +		PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency);
   1.151 +		PR_fprintf(
   1.152 +			debug_out, "\tThread type: %s\n",
   1.153 +			(PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL");
   1.154 +	}
   1.155 +
   1.156 +    /*
   1.157 +    ** The interesting part starts here
   1.158 +    */
   1.159 +    RCLock lock;
   1.160 +    Shared* shared;
   1.161 +    Home home(NULL, &lock);
   1.162 +    Home* link = &home;
   1.163 +    RCInterval timein, timeout = 0;
   1.164 +
   1.165 +    /* Build up the string of objects */
   1.166 +    for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
   1.167 +    {
   1.168 +        shared = new Shared(thread_scope, link, &lock);
   1.169 +        shared->Start();  /* make it run */
   1.170 +        link = (Home*)shared;
   1.171 +	}
   1.172 +
   1.173 +    /* Pass the message around the horn a few times */
   1.174 +    for (loop_count = 1; loop_count <= loop_limit; ++loop_count)
   1.175 +    {
   1.176 +		timein.SetToNow();
   1.177 +		for (inner_count = 0; inner_count < INNER_LOOPS; ++inner_count)
   1.178 +		{
   1.179 +			RCEnter entry(&lock);
   1.180 +			home.twiddle = PR_TRUE;
   1.181 +			shared->twiddle = PR_FALSE;
   1.182 +			shared->Notify();
   1.183 +			while (home.twiddle)
   1.184 +            {
   1.185 +				failed = (PR_FAILURE == home.Wait()) ? PR_TRUE : PR_FALSE;
   1.186 +            }
   1.187 +		}
   1.188 +		timeout += (RCInterval(RCInterval::now) - timein);
   1.189 +	}
   1.190 +
   1.191 +    /* Figure out how well we did */
   1.192 +	if (debug_mode)
   1.193 +	{
   1.194 +		average = timeout.ToMicroseconds()
   1.195 +			/ (INNER_LOOPS * loop_limit * thread_count);
   1.196 +		PR_fprintf(
   1.197 +			debug_out, "Average switch times %d usecs for %d threads\n",
   1.198 +            average, thread_limit);
   1.199 +	}
   1.200 +
   1.201 +    /* Start reclamation process */
   1.202 +    link = shared;
   1.203 +    for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
   1.204 +    {
   1.205 +        if (&home == link) break;
   1.206 +        status = ((Shared*)link)->Interrupt();
   1.207 +		if (PR_SUCCESS != status)
   1.208 +        {
   1.209 +            failed = PR_TRUE;
   1.210 +            if (debug_mode)
   1.211 +			    PL_FPrintError(debug_out, "Failed to interrupt");
   1.212 +        }
   1.213 +		link = link->next; 
   1.214 +    }
   1.215 +
   1.216 +    for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
   1.217 +    {
   1.218 +        link = shared->next;
   1.219 +        status = shared->Join();
   1.220 +		if (PR_SUCCESS != status)
   1.221 +		{
   1.222 +            failed = PR_TRUE;
   1.223 +            if (debug_mode)
   1.224 +			    PL_FPrintError(debug_out, "Failed to join");
   1.225 +        }
   1.226 +        if (&home == link) break;
   1.227 +        shared = (Shared*)link;
   1.228 +    }
   1.229 +
   1.230 +    PR_fprintf(PR_STDOUT, ((failed) ? "FAILED\n" : "PASSED\n"));
   1.231 +
   1.232 +    failed |= (PR_SUCCESS == RCPrimordialThread::Cleanup());
   1.233 +
   1.234 +    return ((failed) ? 1 : 0);
   1.235 +}  /* main */
   1.236 +
   1.237 +/* switch.c */

mercurial