Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
** File: instrumt.c
** Description: This test is for the NSPR debug aids defined in
** prcountr.h, prtrace.h, prolock.h
**
** The test case tests the three debug aids in NSPR:
**
** Diagnostic messages can be enabled using "instrumt -v 6"
** This sets the msgLevel to something that PR_LOG() likes.
** Also define in the environment "NSPR_LOG_MODULES=Test:6"
**
** CounterTest() tests the counter facility. This test
** creates 4 threads. Each thread either increments, decrements,
** adds to or subtracts from a counter, depending on an argument
** passed to the thread at thread-create time. Each of these threads
** does COUNT_LIMIT iterations doing its thing. When all 4 threads
** are done, the result of the counter is evaluated. If all was atomic,
** the the value of the counter should be zero.
**
** TraceTest():
** This test mingles with the counter test. Counters trace.
** A thread to extract trace entries on the fly is started.
** A thread to dump trace entries to a file is started.
**
** OrderedLockTest():
**
**
**
**
**
*/
#include <stdio.h>
#include <plstr.h>
#include <prclist.h>
#include <prmem.h>
#include <plgetopt.h>
#include <prlog.h>
#include <prmon.h>
#include <pratom.h>
#include <prtrace.h>
#include <prcountr.h>
#include <prolock.h>
#define COUNT_LIMIT (10 * (1024))
#define SMALL_TRACE_BUFSIZE (60 * 1024)
typedef enum { CountLoop = 1, TraceLoop = 2, TraceFlow = 3 } TraceTypes;
PRLogModuleLevel msgLevel = PR_LOG_ALWAYS;
PRBool help = PR_FALSE;
PRBool failed = PR_FALSE;
PRLogModuleInfo* lm;
PRMonitor* mon;
PRInt32 activeThreads = 0;
PR_DEFINE_COUNTER(hCounter);
PR_DEFINE_TRACE(hTrace);
static void Help(void) { printf("Help? ... Ha!\n"); }
static void ListCounters(void) {
PR_DEFINE_COUNTER(qh);
PR_DEFINE_COUNTER(rh);
const char *qn, *rn, *dn;
const char **qname = &qn, **rname = &rn, **desc = &dn;
PRUint32 tCtr;
PR_INIT_COUNTER_HANDLE(qh, NULL);
PR_FIND_NEXT_COUNTER_QNAME(qh, qh);
while (qh != NULL) {
PR_INIT_COUNTER_HANDLE(rh, NULL);
PR_FIND_NEXT_COUNTER_RNAME(rh, rh, qh);
while (rh != NULL) {
PR_GET_COUNTER_NAME_FROM_HANDLE(rh, qname, rname, desc);
PR_GET_COUNTER(tCtr, rh);
PR_LOG(
lm, msgLevel,
("QName: %s RName: %s Desc: %s Value: %ld\n", qn, rn, dn, tCtr));
PR_FIND_NEXT_COUNTER_RNAME(rh, rh, qh);
}
PR_FIND_NEXT_COUNTER_QNAME(qh, qh);
}
return;
} /* end ListCounters() */
static void ListTraces(void) {
PR_DEFINE_TRACE(qh);
PR_DEFINE_TRACE(rh);
const char *qn, *rn, *dn;
const char **qname = &qn, **rname = &rn, **desc = &dn;
PR_INIT_TRACE_HANDLE(qh, NULL);
PR_FIND_NEXT_TRACE_QNAME(qh, qh);
while (qh != NULL) {
PR_INIT_TRACE_HANDLE(rh, NULL);
PR_FIND_NEXT_TRACE_RNAME(rh, rh, qh);
while (rh != NULL) {
PR_GET_TRACE_NAME_FROM_HANDLE(rh, qname, rname, desc);
PR_LOG(lm, msgLevel, ("QName: %s RName: %s Desc: %s", qn, rn, dn));
PR_FIND_NEXT_TRACE_RNAME(rh, rh, qh);
}
PR_FIND_NEXT_TRACE_QNAME(qh, qh);
}
return;
} /* end ListCounters() */
static PRInt32 one = 1;
static PRInt32 two = 2;
static PRInt32 three = 3;
static PRInt32 four = 4;
/*
** Thread to iteratively count something.
*/
static void PR_CALLBACK CountSomething(void* arg) {
PRInt32 switchVar = *((PRInt32*)arg);
PRInt32 i;
PR_LOG(lm, msgLevel, ("CountSomething: begin thread %ld", switchVar));
for (i = 0; i < COUNT_LIMIT; i++) {
switch (switchVar) {
case 1:
PR_INCREMENT_COUNTER(hCounter);
break;
case 2:
PR_DECREMENT_COUNTER(hCounter);
break;
case 3:
PR_ADD_TO_COUNTER(hCounter, 1);
break;
case 4:
PR_SUBTRACT_FROM_COUNTER(hCounter, 1);
break;
default:
PR_ASSERT(0);
break;
}
PR_TRACE(hTrace, CountLoop, switchVar, i, 0, 0, 0, 0, 0);
} /* end for() */
PR_LOG(lm, msgLevel, ("CounterSomething: end thread %ld", switchVar));
PR_EnterMonitor(mon);
--activeThreads;
PR_Notify(mon);
PR_ExitMonitor(mon);
return;
} /* end CountSomething() */
/*
** Create the counter threads.
*/
static void CounterTest(void) {
PRThread *t1, *t2, *t3, *t4;
PRIntn i = 0;
PR_DEFINE_COUNTER(tc);
PR_DEFINE_COUNTER(zCounter);
PR_LOG(lm, msgLevel, ("Begin CounterTest"));
/*
** Test Get and Set of a counter.
**
*/
PR_CREATE_COUNTER(zCounter, "Atomic", "get/set test",
"test get and set of counter");
PR_SET_COUNTER(zCounter, 9);
PR_GET_COUNTER(i, zCounter);
if (i != 9) {
failed = PR_TRUE;
PR_LOG(lm, msgLevel, ("Counter set/get failed"));
}
activeThreads += 4;
PR_CREATE_COUNTER(hCounter, "Atomic", "SMP Tests",
"test atomic nature of counter");
PR_GET_COUNTER_HANDLE_FROM_NAME(tc, "Atomic", "SMP Tests");
PR_ASSERT(tc == hCounter);
t1 = PR_CreateThread(PR_USER_THREAD, CountSomething, &one, PR_PRIORITY_NORMAL,
PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
PR_ASSERT(t1);
t2 = PR_CreateThread(PR_USER_THREAD, CountSomething, &two, PR_PRIORITY_NORMAL,
PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
PR_ASSERT(t2);
t3 = PR_CreateThread(PR_USER_THREAD, CountSomething, &three,
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
PR_UNJOINABLE_THREAD, 0);
PR_ASSERT(t3);
t4 =
PR_CreateThread(PR_USER_THREAD, CountSomething, &four, PR_PRIORITY_NORMAL,
PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
PR_ASSERT(t4);
PR_LOG(lm, msgLevel, ("Counter Threads started"));
ListCounters();
return;
} /* end CounterTest() */
/*
** Thread to dump trace buffer to a file.
*/
static void PR_CALLBACK RecordTrace(void* arg) {
PR_RECORD_TRACE_ENTRIES();
PR_EnterMonitor(mon);
--activeThreads;
PR_Notify(mon);
PR_ExitMonitor(mon);
return;
} /* end RecordTrace() */
#define NUM_TRACE_RECORDS (10000)
/*
** Thread to extract and print trace entries from the buffer.
*/
static void PR_CALLBACK SampleTrace(void* arg) {
#if defined(DEBUG) || defined(FORCE_NSPR_TRACE)
PRInt32 found, rc;
PRTraceEntry* foundEntries;
PRInt32 i;
foundEntries =
(PRTraceEntry*)PR_Malloc(NUM_TRACE_RECORDS * sizeof(PRTraceEntry));
PR_ASSERT(foundEntries != NULL);
do {
rc = PR_GetTraceEntries(foundEntries, NUM_TRACE_RECORDS, &found);
PR_LOG(lm, msgLevel, ("SampleTrace: Lost Data: %ld found: %ld", rc, found));
if (found != 0) {
for (i = 0; i < found; i++) {
PR_LOG(
lm, msgLevel,
("SampleTrace, detail: Thread: %p, Time: %llX, UD0: %ld, UD1: %ld, "
"UD2: %8.8ld",
(foundEntries + i)->thread, (foundEntries + i)->time,
(foundEntries + i)->userData[0], (foundEntries + i)->userData[1],
(foundEntries + i)->userData[2]));
}
}
PR_Sleep(PR_MillisecondsToInterval(50));
} while (found != 0 && activeThreads >= 1);
PR_Free(foundEntries);
PR_EnterMonitor(mon);
--activeThreads;
PR_Notify(mon);
PR_ExitMonitor(mon);
PR_LOG(lm, msgLevel, ("SampleTrace(): exiting"));
#endif
return;
} /* end RecordTrace() */
/*
** Basic trace test.
*/
static void TraceTest(void) {
PRInt32 i;
PRInt32 size;
PR_DEFINE_TRACE(th);
PRThread *t1, *t2;
PR_LOG(lm, msgLevel, ("Begin TraceTest"));
size = SMALL_TRACE_BUFSIZE;
PR_SET_TRACE_OPTION(PRTraceBufSize, &size);
PR_GET_TRACE_OPTION(PRTraceBufSize, &i);
PR_CREATE_TRACE(th, "TraceTest", "tt2", "A description for the trace test");
PR_CREATE_TRACE(th, "TraceTest", "tt3", "A description for the trace test");
PR_CREATE_TRACE(th, "TraceTest", "tt4", "A description for the trace test");
PR_CREATE_TRACE(th, "TraceTest", "tt5", "A description for the trace test");
PR_CREATE_TRACE(th, "TraceTest", "tt6", "A description for the trace test");
PR_CREATE_TRACE(th, "TraceTest", "tt7", "A description for the trace test");
PR_CREATE_TRACE(th, "TraceTest", "tt8", "A description for the trace test");
PR_CREATE_TRACE(th, "Trace Test", "tt0",
"QName is Trace Test, not TraceTest");
PR_CREATE_TRACE(th, "Trace Test", "tt1",
"QName is Trace Test, not TraceTest");
PR_CREATE_TRACE(th, "Trace Test", "tt2",
"QName is Trace Test, not TraceTest");
PR_CREATE_TRACE(th, "Trace Test", "tt3",
"QName is Trace Test, not TraceTest");
PR_CREATE_TRACE(th, "Trace Test", "tt4",
"QName is Trace Test, not TraceTest");
PR_CREATE_TRACE(th, "Trace Test", "tt5",
"QName is Trace Test, not TraceTest");
PR_CREATE_TRACE(th, "Trace Test", "tt6",
"QName is Trace Test, not TraceTest");
PR_CREATE_TRACE(th, "Trace Test", "tt7",
"QName is Trace Test, not TraceTest");
PR_CREATE_TRACE(th, "Trace Test", "tt8",
"QName is Trace Test, not TraceTest");
PR_CREATE_TRACE(th, "Trace Test", "tt9",
"QName is Trace Test, not TraceTest");
PR_CREATE_TRACE(th, "Trace Test", "tt10",
"QName is Trace Test, not TraceTest");
activeThreads += 2;
t1 = PR_CreateThread(PR_USER_THREAD, RecordTrace, NULL, PR_PRIORITY_NORMAL,
PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
PR_ASSERT(t1);
t2 = PR_CreateThread(PR_USER_THREAD, SampleTrace, 0, PR_PRIORITY_NORMAL,
PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
PR_ASSERT(t2);
ListTraces();
PR_GET_TRACE_HANDLE_FROM_NAME(th, "TraceTest", "tt1");
PR_ASSERT(th == hTrace);
PR_LOG(lm, msgLevel, ("End TraceTest"));
return;
} /* end TraceTest() */
/*
** Ordered lock test.
*/
static void OrderedLockTest(void) {
PR_LOG(lm, msgLevel, ("Begin OrderedLockTest"));
} /* end OrderedLockTest() */
int main(int argc, char** argv) {
#if defined(DEBUG) || defined(FORCE_NSPR_TRACE)
PRUint32 counter;
PLOptStatus os;
PLOptState* opt = PL_CreateOptState(argc, argv, "hdv:");
lm = PR_NewLogModule("Test");
while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
if (PL_OPT_BAD == os) {
continue;
}
switch (opt->option) {
case 'v': /* verbose mode */
msgLevel = (PRLogModuleLevel)atol(opt->value);
break;
case 'h': /* help message */
Help();
help = PR_TRUE;
break;
default:
break;
}
}
PL_DestroyOptState(opt);
PR_CREATE_TRACE(hTrace, "TraceTest", "tt1",
"A description for the trace test");
mon = PR_NewMonitor();
PR_EnterMonitor(mon);
TraceTest();
CounterTest();
OrderedLockTest();
/* Wait for all threads to exit */
while (activeThreads > 0) {
if (activeThreads == 1) {
PR_SET_TRACE_OPTION(PRTraceStopRecording, NULL);
}
PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT);
PR_GET_COUNTER(counter, hCounter);
}
PR_ExitMonitor(mon);
/*
** Evaluate results
*/
PR_GET_COUNTER(counter, hCounter);
if (counter != 0) {
failed = PR_TRUE;
PR_LOG(lm, msgLevel, ("Expected counter == 0, found: %ld", counter));
printf("FAIL\n");
} else {
printf("PASS\n");
}
PR_DESTROY_COUNTER(hCounter);
PR_DestroyMonitor(mon);
PR_TRACE(hTrace, TraceFlow, 0xfff, 0, 0, 0, 0, 0, 0);
PR_DESTROY_TRACE(hTrace);
#else
printf("Test not defined\n");
#endif
return 0;
} /* main() */
/* end instrumt.c */