nsprpub/pr/tests/switch.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/nsprpub/pr/tests/switch.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,237 @@
     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.c
    1.11 +** Description:     trying to time context switches
    1.12 +*/
    1.13 +
    1.14 +#include "prinit.h"
    1.15 +#include "prcvar.h"
    1.16 +#include "prmem.h"
    1.17 +#include "prinrval.h"
    1.18 +#include "prlock.h"
    1.19 +#include "prlog.h"
    1.20 +#include "prthread.h"
    1.21 +#include "prprf.h"
    1.22 +
    1.23 +#include "plerror.h"
    1.24 +#include "plgetopt.h"
    1.25 +
    1.26 +#include "private/pprio.h"
    1.27 +
    1.28 +#include <stdlib.h>
    1.29 +
    1.30 +#define INNER_LOOPS 100
    1.31 +#define DEFAULT_LOOPS 100
    1.32 +#define DEFAULT_THREADS 10
    1.33 +
    1.34 +static PRFileDesc *debug_out = NULL;
    1.35 +static PRBool debug_mode = PR_FALSE, verbosity = PR_FALSE, failed = PR_FALSE;
    1.36 +
    1.37 +typedef struct Shared
    1.38 +{
    1.39 +    PRLock *ml;
    1.40 +    PRCondVar *cv;
    1.41 +    PRBool twiddle;
    1.42 +    PRThread *thread;
    1.43 +    struct Shared *next;
    1.44 +} Shared;
    1.45 +
    1.46 +static void Help(void)
    1.47 +{
    1.48 +    debug_out = PR_STDOUT;
    1.49 +
    1.50 +    PR_fprintf(
    1.51 +		debug_out, "Usage: >./switch [-c n] [-t n] [-d] [-v] [-G] [-C n]\n");
    1.52 +    PR_fprintf(
    1.53 +		debug_out, "-c n\tloops at thread level (default: %d)\n", DEFAULT_LOOPS);
    1.54 +    PR_fprintf(
    1.55 +		debug_out, "-t n\tnumber of threads (default: %d)\n", DEFAULT_THREADS);
    1.56 +    PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n");
    1.57 +    PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n");
    1.58 +    PR_fprintf(debug_out, "-G\tglobal threads only (default: FALSE)\n");
    1.59 +    PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n");
    1.60 +}  /* Help */
    1.61 +
    1.62 +static void PR_CALLBACK Notified(void *arg)
    1.63 +{
    1.64 +    Shared *shared = (Shared*)arg;
    1.65 +    PRStatus status = PR_SUCCESS;
    1.66 +    while (PR_SUCCESS == status)
    1.67 +    {
    1.68 +        PR_Lock(shared->ml);
    1.69 +        while (shared->twiddle && (PR_SUCCESS == status))
    1.70 +            status = PR_WaitCondVar(shared->cv, PR_INTERVAL_NO_TIMEOUT);
    1.71 +		if (verbosity) PR_fprintf(debug_out, "+");
    1.72 +        shared->twiddle = PR_TRUE;
    1.73 +        shared->next->twiddle = PR_FALSE;
    1.74 +        PR_NotifyCondVar(shared->next->cv);
    1.75 +        PR_Unlock(shared->ml);
    1.76 +    }
    1.77 +}  /* Notified */
    1.78 +
    1.79 +static Shared home;
    1.80 +PRIntn PR_CALLBACK Switch(PRIntn argc, char **argv)
    1.81 +{
    1.82 +	PLOptStatus os;
    1.83 +    PRStatus status;
    1.84 +    PRBool help = PR_FALSE;
    1.85 +    PRUintn concurrency = 1;
    1.86 +    Shared *shared, *link;
    1.87 +    PRIntervalTime timein, timeout;
    1.88 +    PRThreadScope thread_scope = PR_LOCAL_THREAD;
    1.89 +    PRUintn thread_count, inner_count, loop_count, average;
    1.90 +    PRUintn thread_limit = DEFAULT_THREADS, loop_limit = DEFAULT_LOOPS;
    1.91 +	PLOptState *opt = PL_CreateOptState(argc, argv, "hdvc:t:C:G");
    1.92 +	while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
    1.93 +    {
    1.94 +		if (PL_OPT_BAD == os) continue;
    1.95 +        switch (opt->option)
    1.96 +        {
    1.97 +        case 'v':  /* verbose mode */
    1.98 +			verbosity = PR_TRUE;
    1.99 +        case 'd':  /* debug mode */
   1.100 +			debug_mode = PR_TRUE;
   1.101 +            break;
   1.102 +        case 'c':  /* loop counter */
   1.103 +			loop_limit = atoi(opt->value);
   1.104 +            break;
   1.105 +        case 't':  /* thread limit */
   1.106 +			thread_limit = atoi(opt->value);
   1.107 +            break;
   1.108 +        case 'C':  /* Concurrency limit */
   1.109 +			concurrency = atoi(opt->value);
   1.110 +            break;
   1.111 +        case 'G':  /* global threads only */
   1.112 +			thread_scope = PR_GLOBAL_THREAD;
   1.113 +            break;
   1.114 +        case 'h':  /* help message */
   1.115 +			Help();
   1.116 +			help = PR_TRUE;
   1.117 +            break;
   1.118 +         default:
   1.119 +            break;
   1.120 +        }
   1.121 +    }
   1.122 +	PL_DestroyOptState(opt);
   1.123 +
   1.124 +    if (help) return -1;
   1.125 +
   1.126 +	if (PR_TRUE == debug_mode)
   1.127 +	{
   1.128 +		debug_out = PR_STDOUT;
   1.129 +		PR_fprintf(debug_out, "Test parameters\n");
   1.130 +		PR_fprintf(debug_out, "\tThreads involved: %d\n", thread_limit);
   1.131 +		PR_fprintf(debug_out, "\tIteration limit: %d\n", loop_limit);
   1.132 +		PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency);
   1.133 +		PR_fprintf(
   1.134 +			debug_out, "\tThread type: %s\n",
   1.135 +			(PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL");
   1.136 +	}
   1.137 +
   1.138 +    PR_SetConcurrency(concurrency);
   1.139 +
   1.140 +    link = &home;
   1.141 +    home.ml = PR_NewLock();
   1.142 +    home.cv = PR_NewCondVar(home.ml);
   1.143 +    home.twiddle = PR_FALSE;
   1.144 +    home.next = NULL;
   1.145 +
   1.146 +    timeout = 0;
   1.147 +
   1.148 +    for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
   1.149 +    {
   1.150 +        shared = PR_NEWZAP(Shared);
   1.151 +
   1.152 +        shared->ml = home.ml;
   1.153 +        shared->cv = PR_NewCondVar(home.ml);
   1.154 +        shared->twiddle = PR_TRUE;
   1.155 +        shared->next = link;
   1.156 +        link = shared;
   1.157 +
   1.158 +        shared->thread = PR_CreateThread(
   1.159 +            PR_USER_THREAD, Notified, shared,
   1.160 +            PR_PRIORITY_HIGH, thread_scope,
   1.161 +            PR_JOINABLE_THREAD, 0);
   1.162 +        PR_ASSERT(shared->thread != NULL);
   1.163 +        if (NULL == shared->thread)
   1.164 +            failed = PR_TRUE;
   1.165 +	}
   1.166 +
   1.167 +    for (loop_count = 1; loop_count <= loop_limit; ++loop_count)
   1.168 +    {
   1.169 +		timein = PR_IntervalNow();
   1.170 +		for (inner_count = 0; inner_count < INNER_LOOPS; ++inner_count)
   1.171 +		{
   1.172 +			PR_Lock(home.ml);
   1.173 +			home.twiddle = PR_TRUE;
   1.174 +			shared->twiddle = PR_FALSE;
   1.175 +			PR_NotifyCondVar(shared->cv);
   1.176 +			while (home.twiddle)
   1.177 +            {
   1.178 +				status = PR_WaitCondVar(home.cv, PR_INTERVAL_NO_TIMEOUT);
   1.179 +				if (PR_FAILURE == status)
   1.180 +				    failed = PR_TRUE;
   1.181 +            }
   1.182 +			PR_Unlock(home.ml);
   1.183 +		}
   1.184 +		timeout += (PR_IntervalNow() - timein);
   1.185 +	}
   1.186 +
   1.187 +	if (debug_mode)
   1.188 +	{
   1.189 +		average = PR_IntervalToMicroseconds(timeout)
   1.190 +			/ (INNER_LOOPS * loop_limit * thread_count);
   1.191 +		PR_fprintf(
   1.192 +			debug_out, "Average switch times %d usecs for %d threads\n",
   1.193 +            average, thread_limit);
   1.194 +	}
   1.195 +
   1.196 +    link = shared;
   1.197 +    for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
   1.198 +    {
   1.199 +        if (&home == link) break;
   1.200 +        status = PR_Interrupt(link->thread);
   1.201 +		if (PR_SUCCESS != status)
   1.202 +        {
   1.203 +            failed = PR_TRUE;
   1.204 +            if (debug_mode)
   1.205 +			    PL_FPrintError(debug_out, "Failed to interrupt");
   1.206 +        }
   1.207 +		link = link->next; 
   1.208 +    }
   1.209 +
   1.210 +    for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
   1.211 +    {
   1.212 +        link = shared->next;
   1.213 +        status = PR_JoinThread(shared->thread);
   1.214 +		if (PR_SUCCESS != status)
   1.215 +		{
   1.216 +            failed = PR_TRUE;
   1.217 +            if (debug_mode)
   1.218 +			    PL_FPrintError(debug_out, "Failed to join");
   1.219 +        }
   1.220 +        PR_DestroyCondVar(shared->cv);
   1.221 +        PR_DELETE(shared);
   1.222 +        if (&home == link) break;
   1.223 +        shared = link;
   1.224 +    }
   1.225 +    PR_DestroyCondVar(home.cv);
   1.226 +    PR_DestroyLock(home.ml);
   1.227 +
   1.228 +    PR_fprintf(PR_STDOUT, ((failed) ? "FAILED\n" : "PASSED\n"));
   1.229 +    return ((failed) ? 1 : 0);
   1.230 +}  /* Switch */
   1.231 +
   1.232 +int main(int argc, char **argv)
   1.233 +{
   1.234 +    PRIntn result;
   1.235 +    PR_STDIO_INIT();
   1.236 +    result = PR_Initialize(Switch, argc, argv, 0);
   1.237 +    return result;
   1.238 +}  /* main */
   1.239 +
   1.240 +/* switch.c */

mercurial