instrumt.c (11618B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 /* 7 ** File: instrumt.c 8 ** Description: This test is for the NSPR debug aids defined in 9 ** prcountr.h, prtrace.h, prolock.h 10 ** 11 ** The test case tests the three debug aids in NSPR: 12 ** 13 ** Diagnostic messages can be enabled using "instrumt -v 6" 14 ** This sets the msgLevel to something that PR_LOG() likes. 15 ** Also define in the environment "NSPR_LOG_MODULES=Test:6" 16 ** 17 ** CounterTest() tests the counter facility. This test 18 ** creates 4 threads. Each thread either increments, decrements, 19 ** adds to or subtracts from a counter, depending on an argument 20 ** passed to the thread at thread-create time. Each of these threads 21 ** does COUNT_LIMIT iterations doing its thing. When all 4 threads 22 ** are done, the result of the counter is evaluated. If all was atomic, 23 ** the the value of the counter should be zero. 24 ** 25 ** TraceTest(): 26 ** This test mingles with the counter test. Counters trace. 27 ** A thread to extract trace entries on the fly is started. 28 ** A thread to dump trace entries to a file is started. 29 ** 30 ** OrderedLockTest(): 31 ** 32 ** 33 ** 34 ** 35 ** 36 */ 37 38 #include <stdio.h> 39 #include <plstr.h> 40 #include <prclist.h> 41 #include <prmem.h> 42 #include <plgetopt.h> 43 #include <prlog.h> 44 #include <prmon.h> 45 #include <pratom.h> 46 #include <prtrace.h> 47 #include <prcountr.h> 48 #include <prolock.h> 49 50 #define COUNT_LIMIT (10 * (1024)) 51 52 #define SMALL_TRACE_BUFSIZE (60 * 1024) 53 54 typedef enum { CountLoop = 1, TraceLoop = 2, TraceFlow = 3 } TraceTypes; 55 56 PRLogModuleLevel msgLevel = PR_LOG_ALWAYS; 57 58 PRBool help = PR_FALSE; 59 PRBool failed = PR_FALSE; 60 61 PRLogModuleInfo* lm; 62 PRMonitor* mon; 63 PRInt32 activeThreads = 0; 64 PR_DEFINE_COUNTER(hCounter); 65 PR_DEFINE_TRACE(hTrace); 66 67 static void Help(void) { printf("Help? ... Ha!\n"); } 68 69 static void ListCounters(void) { 70 PR_DEFINE_COUNTER(qh); 71 PR_DEFINE_COUNTER(rh); 72 const char *qn, *rn, *dn; 73 const char **qname = &qn, **rname = &rn, **desc = &dn; 74 PRUint32 tCtr; 75 76 PR_INIT_COUNTER_HANDLE(qh, NULL); 77 PR_FIND_NEXT_COUNTER_QNAME(qh, qh); 78 while (qh != NULL) { 79 PR_INIT_COUNTER_HANDLE(rh, NULL); 80 PR_FIND_NEXT_COUNTER_RNAME(rh, rh, qh); 81 while (rh != NULL) { 82 PR_GET_COUNTER_NAME_FROM_HANDLE(rh, qname, rname, desc); 83 PR_GET_COUNTER(tCtr, rh); 84 PR_LOG( 85 lm, msgLevel, 86 ("QName: %s RName: %s Desc: %s Value: %ld\n", qn, rn, dn, tCtr)); 87 PR_FIND_NEXT_COUNTER_RNAME(rh, rh, qh); 88 } 89 PR_FIND_NEXT_COUNTER_QNAME(qh, qh); 90 } 91 return; 92 } /* end ListCounters() */ 93 94 static void ListTraces(void) { 95 PR_DEFINE_TRACE(qh); 96 PR_DEFINE_TRACE(rh); 97 const char *qn, *rn, *dn; 98 const char **qname = &qn, **rname = &rn, **desc = &dn; 99 100 PR_INIT_TRACE_HANDLE(qh, NULL); 101 PR_FIND_NEXT_TRACE_QNAME(qh, qh); 102 while (qh != NULL) { 103 PR_INIT_TRACE_HANDLE(rh, NULL); 104 PR_FIND_NEXT_TRACE_RNAME(rh, rh, qh); 105 while (rh != NULL) { 106 PR_GET_TRACE_NAME_FROM_HANDLE(rh, qname, rname, desc); 107 PR_LOG(lm, msgLevel, ("QName: %s RName: %s Desc: %s", qn, rn, dn)); 108 PR_FIND_NEXT_TRACE_RNAME(rh, rh, qh); 109 } 110 PR_FIND_NEXT_TRACE_QNAME(qh, qh); 111 } 112 return; 113 } /* end ListCounters() */ 114 115 static PRInt32 one = 1; 116 static PRInt32 two = 2; 117 static PRInt32 three = 3; 118 static PRInt32 four = 4; 119 120 /* 121 ** Thread to iteratively count something. 122 */ 123 static void PR_CALLBACK CountSomething(void* arg) { 124 PRInt32 switchVar = *((PRInt32*)arg); 125 PRInt32 i; 126 127 PR_LOG(lm, msgLevel, ("CountSomething: begin thread %ld", switchVar)); 128 129 for (i = 0; i < COUNT_LIMIT; i++) { 130 switch (switchVar) { 131 case 1: 132 PR_INCREMENT_COUNTER(hCounter); 133 break; 134 case 2: 135 PR_DECREMENT_COUNTER(hCounter); 136 break; 137 case 3: 138 PR_ADD_TO_COUNTER(hCounter, 1); 139 break; 140 case 4: 141 PR_SUBTRACT_FROM_COUNTER(hCounter, 1); 142 break; 143 default: 144 PR_ASSERT(0); 145 break; 146 } 147 PR_TRACE(hTrace, CountLoop, switchVar, i, 0, 0, 0, 0, 0); 148 } /* end for() */ 149 150 PR_LOG(lm, msgLevel, ("CounterSomething: end thread %ld", switchVar)); 151 152 PR_EnterMonitor(mon); 153 --activeThreads; 154 PR_Notify(mon); 155 PR_ExitMonitor(mon); 156 157 return; 158 } /* end CountSomething() */ 159 160 /* 161 ** Create the counter threads. 162 */ 163 static void CounterTest(void) { 164 PRThread *t1, *t2, *t3, *t4; 165 PRIntn i = 0; 166 PR_DEFINE_COUNTER(tc); 167 PR_DEFINE_COUNTER(zCounter); 168 169 PR_LOG(lm, msgLevel, ("Begin CounterTest")); 170 171 /* 172 ** Test Get and Set of a counter. 173 ** 174 */ 175 PR_CREATE_COUNTER(zCounter, "Atomic", "get/set test", 176 "test get and set of counter"); 177 PR_SET_COUNTER(zCounter, 9); 178 PR_GET_COUNTER(i, zCounter); 179 if (i != 9) { 180 failed = PR_TRUE; 181 PR_LOG(lm, msgLevel, ("Counter set/get failed")); 182 } 183 184 activeThreads += 4; 185 PR_CREATE_COUNTER(hCounter, "Atomic", "SMP Tests", 186 "test atomic nature of counter"); 187 188 PR_GET_COUNTER_HANDLE_FROM_NAME(tc, "Atomic", "SMP Tests"); 189 PR_ASSERT(tc == hCounter); 190 191 t1 = PR_CreateThread(PR_USER_THREAD, CountSomething, &one, PR_PRIORITY_NORMAL, 192 PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); 193 PR_ASSERT(t1); 194 195 t2 = PR_CreateThread(PR_USER_THREAD, CountSomething, &two, PR_PRIORITY_NORMAL, 196 PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); 197 PR_ASSERT(t2); 198 199 t3 = PR_CreateThread(PR_USER_THREAD, CountSomething, &three, 200 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, 201 PR_UNJOINABLE_THREAD, 0); 202 PR_ASSERT(t3); 203 204 t4 = 205 PR_CreateThread(PR_USER_THREAD, CountSomething, &four, PR_PRIORITY_NORMAL, 206 PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); 207 PR_ASSERT(t4); 208 209 PR_LOG(lm, msgLevel, ("Counter Threads started")); 210 211 ListCounters(); 212 return; 213 } /* end CounterTest() */ 214 215 /* 216 ** Thread to dump trace buffer to a file. 217 */ 218 static void PR_CALLBACK RecordTrace(void* arg) { 219 PR_RECORD_TRACE_ENTRIES(); 220 221 PR_EnterMonitor(mon); 222 --activeThreads; 223 PR_Notify(mon); 224 PR_ExitMonitor(mon); 225 226 return; 227 } /* end RecordTrace() */ 228 229 #define NUM_TRACE_RECORDS (10000) 230 /* 231 ** Thread to extract and print trace entries from the buffer. 232 */ 233 static void PR_CALLBACK SampleTrace(void* arg) { 234 #if defined(DEBUG) || defined(FORCE_NSPR_TRACE) 235 PRInt32 found, rc; 236 PRTraceEntry* foundEntries; 237 PRInt32 i; 238 239 foundEntries = 240 (PRTraceEntry*)PR_Malloc(NUM_TRACE_RECORDS * sizeof(PRTraceEntry)); 241 PR_ASSERT(foundEntries != NULL); 242 243 do { 244 rc = PR_GetTraceEntries(foundEntries, NUM_TRACE_RECORDS, &found); 245 PR_LOG(lm, msgLevel, ("SampleTrace: Lost Data: %ld found: %ld", rc, found)); 246 247 if (found != 0) { 248 for (i = 0; i < found; i++) { 249 PR_LOG( 250 lm, msgLevel, 251 ("SampleTrace, detail: Thread: %p, Time: %llX, UD0: %ld, UD1: %ld, " 252 "UD2: %8.8ld", 253 (foundEntries + i)->thread, (foundEntries + i)->time, 254 (foundEntries + i)->userData[0], (foundEntries + i)->userData[1], 255 (foundEntries + i)->userData[2])); 256 } 257 } 258 PR_Sleep(PR_MillisecondsToInterval(50)); 259 } while (found != 0 && activeThreads >= 1); 260 261 PR_Free(foundEntries); 262 263 PR_EnterMonitor(mon); 264 --activeThreads; 265 PR_Notify(mon); 266 PR_ExitMonitor(mon); 267 268 PR_LOG(lm, msgLevel, ("SampleTrace(): exiting")); 269 270 #endif 271 return; 272 } /* end RecordTrace() */ 273 274 /* 275 ** Basic trace test. 276 */ 277 static void TraceTest(void) { 278 PRInt32 i; 279 PRInt32 size; 280 PR_DEFINE_TRACE(th); 281 PRThread *t1, *t2; 282 283 PR_LOG(lm, msgLevel, ("Begin TraceTest")); 284 285 size = SMALL_TRACE_BUFSIZE; 286 PR_SET_TRACE_OPTION(PRTraceBufSize, &size); 287 PR_GET_TRACE_OPTION(PRTraceBufSize, &i); 288 289 PR_CREATE_TRACE(th, "TraceTest", "tt2", "A description for the trace test"); 290 PR_CREATE_TRACE(th, "TraceTest", "tt3", "A description for the trace test"); 291 PR_CREATE_TRACE(th, "TraceTest", "tt4", "A description for the trace test"); 292 PR_CREATE_TRACE(th, "TraceTest", "tt5", "A description for the trace test"); 293 PR_CREATE_TRACE(th, "TraceTest", "tt6", "A description for the trace test"); 294 PR_CREATE_TRACE(th, "TraceTest", "tt7", "A description for the trace test"); 295 PR_CREATE_TRACE(th, "TraceTest", "tt8", "A description for the trace test"); 296 297 PR_CREATE_TRACE(th, "Trace Test", "tt0", 298 "QName is Trace Test, not TraceTest"); 299 PR_CREATE_TRACE(th, "Trace Test", "tt1", 300 "QName is Trace Test, not TraceTest"); 301 PR_CREATE_TRACE(th, "Trace Test", "tt2", 302 "QName is Trace Test, not TraceTest"); 303 PR_CREATE_TRACE(th, "Trace Test", "tt3", 304 "QName is Trace Test, not TraceTest"); 305 PR_CREATE_TRACE(th, "Trace Test", "tt4", 306 "QName is Trace Test, not TraceTest"); 307 PR_CREATE_TRACE(th, "Trace Test", "tt5", 308 "QName is Trace Test, not TraceTest"); 309 PR_CREATE_TRACE(th, "Trace Test", "tt6", 310 "QName is Trace Test, not TraceTest"); 311 PR_CREATE_TRACE(th, "Trace Test", "tt7", 312 "QName is Trace Test, not TraceTest"); 313 PR_CREATE_TRACE(th, "Trace Test", "tt8", 314 "QName is Trace Test, not TraceTest"); 315 PR_CREATE_TRACE(th, "Trace Test", "tt9", 316 "QName is Trace Test, not TraceTest"); 317 PR_CREATE_TRACE(th, "Trace Test", "tt10", 318 "QName is Trace Test, not TraceTest"); 319 320 activeThreads += 2; 321 t1 = PR_CreateThread(PR_USER_THREAD, RecordTrace, NULL, PR_PRIORITY_NORMAL, 322 PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); 323 PR_ASSERT(t1); 324 325 t2 = PR_CreateThread(PR_USER_THREAD, SampleTrace, 0, PR_PRIORITY_NORMAL, 326 PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0); 327 PR_ASSERT(t2); 328 329 ListTraces(); 330 331 PR_GET_TRACE_HANDLE_FROM_NAME(th, "TraceTest", "tt1"); 332 PR_ASSERT(th == hTrace); 333 334 PR_LOG(lm, msgLevel, ("End TraceTest")); 335 return; 336 } /* end TraceTest() */ 337 338 /* 339 ** Ordered lock test. 340 */ 341 static void OrderedLockTest(void) { 342 PR_LOG(lm, msgLevel, ("Begin OrderedLockTest")); 343 344 } /* end OrderedLockTest() */ 345 346 int main(int argc, char** argv) { 347 #if defined(DEBUG) || defined(FORCE_NSPR_TRACE) 348 PRUint32 counter; 349 PLOptStatus os; 350 PLOptState* opt = PL_CreateOptState(argc, argv, "hdv:"); 351 lm = PR_NewLogModule("Test"); 352 353 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { 354 if (PL_OPT_BAD == os) { 355 continue; 356 } 357 switch (opt->option) { 358 case 'v': /* verbose mode */ 359 msgLevel = (PRLogModuleLevel)atol(opt->value); 360 break; 361 case 'h': /* help message */ 362 Help(); 363 help = PR_TRUE; 364 break; 365 default: 366 break; 367 } 368 } 369 PL_DestroyOptState(opt); 370 371 PR_CREATE_TRACE(hTrace, "TraceTest", "tt1", 372 "A description for the trace test"); 373 mon = PR_NewMonitor(); 374 PR_EnterMonitor(mon); 375 376 TraceTest(); 377 CounterTest(); 378 OrderedLockTest(); 379 380 /* Wait for all threads to exit */ 381 while (activeThreads > 0) { 382 if (activeThreads == 1) { 383 PR_SET_TRACE_OPTION(PRTraceStopRecording, NULL); 384 } 385 PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); 386 PR_GET_COUNTER(counter, hCounter); 387 } 388 PR_ExitMonitor(mon); 389 390 /* 391 ** Evaluate results 392 */ 393 PR_GET_COUNTER(counter, hCounter); 394 if (counter != 0) { 395 failed = PR_TRUE; 396 PR_LOG(lm, msgLevel, ("Expected counter == 0, found: %ld", counter)); 397 printf("FAIL\n"); 398 } else { 399 printf("PASS\n"); 400 } 401 402 PR_DESTROY_COUNTER(hCounter); 403 404 PR_DestroyMonitor(mon); 405 406 PR_TRACE(hTrace, TraceFlow, 0xfff, 0, 0, 0, 0, 0, 0); 407 PR_DESTROY_TRACE(hTrace); 408 #else 409 printf("Test not defined\n"); 410 #endif 411 return 0; 412 } /* main() */ 413 /* end instrumt.c */