2
Copyright (C) 2003-2006, 2008 MySQL AB
3
All rights reserved. Use is subject to license terms.
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; version 2 of the License.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, write to the Free Software
16
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
* Test the functionality of portlib
22
* TODO - Add tests for NdbMem
25
#include <ndb_global.h>
28
#include "NdbThread.h"
30
#include "NdbCondition.h"
40
static void fail(const char* test, const char* cause)
43
ndbout << test << " failed, " << cause << endl;
46
// test 1 variables and funcs
48
extern "C" void* thread1func(void* arg)
53
ndbout << "thread1: thread1func called with arg = " << arg1 << endl;
57
fail("TEST1", "Wrong arg");
59
return (void*) returnvalue;
62
// test 2 variables and funcs
66
extern "C" void* test2func(void* arg)
71
ndbout << "thread" << arg1 << " started in test2func" << endl;
73
if (NdbMutex_Lock(test2mutex) != 0)
74
fail("TEST2", "Failed to lock mutex");
76
ndbout << "thread" << arg1 << ", test2func " << endl;
78
if (NdbMutex_Unlock(test2mutex) != 0)
79
fail("TEST2", "Failed to unlock mutex");
81
int returnvalue = arg1;
82
return (void*) returnvalue;
86
// test 3 and 7 variables and funcs
89
NdbCondition* testcond;
92
extern "C" void* testfunc(void* arg)
98
threadno = *(int*)arg;
100
ndbout << "Thread" << threadno << " started in testfunc" << endl;
104
if ((threadno % 2) == 0)
105
result = NdbSleep_SecSleep(1);
107
result = NdbSleep_MilliSleep(100);
110
fail("TEST3", "Wrong result from sleep function");
112
if (NdbMutex_Lock(testmutex) != 0)
113
fail("TEST3", "Wrong result from NdbMutex_Lock function");
115
ndbout << "thread" << threadno << ", testfunc " << endl;
117
tmpVar = testthreadsdone;
119
if (NdbCondition_Signal(testcond) != 0)
120
fail("TEST3", "Wrong result from NdbCondition_Signal function");
122
if (NdbMutex_Unlock(testmutex) != 0)
123
fail("TEST3", "Wrong result from NdbMutex_Unlock function");
131
extern "C" void* testTryLockfunc(void* arg)
137
threadno = *(int*)arg;
139
ndbout << "Thread" << threadno << " started" << endl;
143
if ((threadno % 2) == 0)
144
result = NdbSleep_SecSleep(1);
146
result = NdbSleep_MilliSleep(100);
149
fail("TEST3", "Wrong result from sleep function");
151
if (NdbMutex_Trylock(testmutex) == 0){
153
ndbout << "thread" << threadno << ", testTryLockfunc locked" << endl;
155
tmpVar = testthreadsdone;
157
if (NdbCondition_Signal(testcond) != 0)
158
fail("TEST3", "Wrong result from NdbCondition_Signal function");
160
if (NdbMutex_Unlock(testmutex) != 0)
161
fail("TEST3", "Wrong result from NdbMutex_Unlock function");
172
void testMicros(int count);
173
Uint64 time_diff(Uint64 s1, Uint64 s2, Uint32 m1, Uint32 m2);
175
NDB_COMMAND(PortLibTest, "portlibtest", "portlibtest", "Test the portable function layer", 4096){
177
ndbout << "= TESTING ARGUMENT PASSING ============" << endl;
178
ndbout << "ARGC: " << argc << endl;
179
for(int i = 1; i < argc; i++){
180
ndbout << " ARGV"<<i<<": " << (char*)argv[i] << endl;
182
ndbout << endl << endl;
185
struct NdbThread* thread1var;
190
// create one thread and wait for it to return
191
ndbout << "= TEST1 ===============================" << endl;
193
thread1var = NdbThread_Create(thread1func, // Function
196
(char*)"thread1", // Thread name
197
NDB_THREAD_PRIO_MEAN); // Thread priority
200
if(NdbThread_WaitFor(thread1var, &status) != 0)
201
fail("TEST1", "NdbThread_WaitFor failed");
202
// NOTE! thread return value is not yet used in Ndb and thus not tested(does not work)
203
//ndbout << "thread1 returned, status = " << status << endl;
205
// fail("TEST1", "Wrong status");
206
ndbout << "TEST1 completed" << endl;
209
NdbThread_Destroy(&thread1var);
211
// Create 10 threads that will wait for a mutex before printing it's message to screen
212
ndbout << "= TEST2 ===============================" << endl;
213
#define T2_THREADS 10
214
NdbThread* threads[T2_THREADS];
215
int args[T2_THREADS];
217
test2mutex = NdbMutex_Create();
218
NdbMutex_Lock(test2mutex);
220
for (int i = 0; i < T2_THREADS; i++)
223
threads[i] = NdbThread_Create(test2func, // Function
224
(void**)&args[i],// Arg
226
(char*)"test2thread", // Thread name
227
NDB_THREAD_PRIO_MEAN); // Thread priority
228
if (threads[i] == NULL)
229
fail("TEST2", "NdbThread_Create failed");
232
ndbout << "All threads created" << endl;
234
NdbMutex_Unlock(test2mutex);
236
for (int i = 0; i < T2_THREADS; i++)
238
if (NdbThread_WaitFor(threads[i], &status2))
239
fail("TEST2", "NdbThread_WaitFor failed");
241
NdbThread_Destroy(&threads[i]);
242
// Don't test return values
243
// ndbout << "thread" << i << " returned, status = " << status2 << endl;
245
// fail("TEST2", "Wrong status");
248
if (NdbMutex_Lock(test2mutex) != 0)
249
fail("TEST2", "NdbMutex_Lock failed");
250
if (NdbMutex_Unlock(test2mutex) != 0)
251
fail("TEST2", "NdbMutex_Unlock failed");
252
if (NdbMutex_Destroy(test2mutex) != 0)
253
fail("TEST2", "NdbMutex_Destroy failed");
254
ndbout << "TEST2 completed" << endl;
256
ndbout << "= TEST3 ===============================" << endl;
257
// Create 10 threads that will by synchronised by a condition
258
// When they are awakened and have the mutex they will increment a global variable
259
#define T3_THREADS 10
260
NdbThread* t3threads[T3_THREADS];
261
int t3args[T3_THREADS];
264
testmutex = NdbMutex_Create();
265
testcond = NdbCondition_Create();
268
for (int i = 0; i < T3_THREADS; i++)
271
t3threads[i] = NdbThread_Create(testfunc, // Function
272
(void**)&t3args[i],// Arg
274
(char*)"test3thread", // Thread name
275
NDB_THREAD_PRIO_MEAN); // Thread priority
278
ndbout << "All threads created" << endl;
280
if (NdbMutex_Lock(testmutex) != 0)
281
fail("TEST3", "NdbMutex_Lock failed");
283
while (testthreadsdone < T3_THREADS*10)
285
if(NdbCondition_Wait(testcond, testmutex) != 0)
286
fail("TEST3", "NdbCondition_Wait failed");
287
ndbout << "Condition signaled, there are " << testthreadsdone << " completed threads" << endl;
289
if (NdbMutex_Unlock(testmutex) != 0)
290
fail("TEST3", "NdbMutex_Unlock failed");
292
for (int i = 0; i < T3_THREADS; i++)
294
if (NdbThread_WaitFor(t3threads[i], &status3) != 0)
295
fail("TEST3", "NdbThread_WaitFor failed");
297
NdbThread_Destroy(&t3threads[i]);
298
//ndbout << "thread" << i << " returned, status = " << status3 << endl;
300
// fail("TEST3", "Wrong status");
303
NdbMutex_Destroy(testmutex);
304
NdbCondition_Destroy(testcond);
305
ndbout << "TEST3 completed" << endl;
307
ndbout << "= TEST4 ===============================" << endl;
308
// Check tick functions
312
int sleeptimes[] = {78, 12, 199, 567, 899};
315
for (int i = 0; i < 5; i++)
317
ndbout << "*------------------------------- Measure" << i << endl;
319
NDB_TICKS millisec_now;
320
NDB_TICKS millisec_now2;
322
millisec_now = NdbTick_CurrentMillisecond();
323
NdbSleep_MilliSleep(sleeptimes[i]);
324
millisec_now2 = NdbTick_CurrentMillisecond();
326
ndbout << " Time before sleep = " << millisec_now << endl;
327
ndbout << " Time after sleep = " << millisec_now2 << endl;
328
ndbout << " Tried to sleep "<<sleeptimes[i]<<" milliseconds." << endl;
329
ndbout << " Sleep time was " << millisec_now2 -millisec_now <<" milliseconds." << endl;
333
ndbout << "TEST4 completed" << endl;
335
ndbout << "= TEST5 ===============================" << endl;
338
ndbout << "Testing hex and dec functions of NdbOut" << endl;
340
for (int i = 0; i<= 0xFF; i++)
342
ndbout << i << "=" <<hex << i << "="<<dec << i << ", ";
345
ndbout << endl<< "Testing that hex is reset to dec by endl" << endl;
346
ndbout << hex << 67 << endl;
347
ndbout << 67 << endl;
349
ndbout << "TEST5 completed" << endl;
352
ndbout << "= TEST6 ===============================" << endl;
353
const char* theEnvHostNamePtr;
355
char theHostHostName[256];
356
theEnvHostNamePtr = NdbEnv_GetEnv("HOSTNAME", buf, 255);
357
if(theEnvHostNamePtr == NULL)
358
fail("TEST6", "Could not get HOSTNAME from env");
360
ndbout << "HOSTNAME from GetEnv" << theEnvHostNamePtr << endl;
362
NdbHost_GetHostName(theHostHostName);
364
ndbout << "HOSTNAME from GetHostName" <<theHostHostName << endl;
366
if (strcmp(theEnvHostNamePtr, theHostHostName) != 0)
367
fail("TEST6", "NdbHost_GetHostName or NdbEnv_GetEnv failed");
370
ndbout << "= TEST7 ===============================" << endl;
372
testmutex = NdbMutex_Create();
373
testcond = NdbCondition_Create();
376
for (int i = 0; i < T3_THREADS; i++)
379
t3threads[i] = NdbThread_Create(testfunc, // Function
380
(void**)&t3args[i],// Arg
382
(char*)"test7thread", // Thread name
383
NDB_THREAD_PRIO_MEAN); // Thread priority
386
ndbout << "All threads created" << endl;
388
if (NdbMutex_Lock(testmutex) != 0)
389
fail("TEST7", "NdbMutex_Lock failed");
391
while (testthreadsdone < T3_THREADS*10)
393
// just testing the functionality without timing out, therefor 20 sec.
394
if(NdbCondition_WaitTimeout(testcond, testmutex, 20000) != 0)
395
fail("TEST7", "NdbCondition_WaitTimeout failed");
396
ndbout << "Condition signaled, there are " << testthreadsdone << " completed threads" << endl;
398
if (NdbMutex_Unlock(testmutex) != 0)
399
fail("TEST7", "NdbMutex_Unlock failed");
401
for (int i = 0; i < T3_THREADS; i++)
403
if (NdbThread_WaitFor(t3threads[i], &status3) != 0)
404
fail("TEST7", "NdbThread_WaitFor failed");
406
NdbThread_Destroy(&t3threads[i]);
409
NdbMutex_Destroy(testmutex);
410
NdbCondition_Destroy(testcond);
412
ndbout << "TEST7 completed" << endl;
415
ndbout << "= TEST8 ===============================" << endl;
416
ndbout << " NdbCondition_WaitTimeout" << endl;
417
testmutex = NdbMutex_Create();
418
testcond = NdbCondition_Create();
420
for (int i = 0; i < 5; i++)
422
ndbout << "*------------------------------- Measure" << i << endl;
424
NDB_TICKS millisec_now;
425
NDB_TICKS millisec_now2;
427
millisec_now = NdbTick_CurrentMillisecond();
428
if (NdbCondition_WaitTimeout(testcond, testmutex, sleeptimes[i]) != 0)
429
fail("TEST8", "NdbCondition_WaitTimeout failed");
430
millisec_now2 = NdbTick_CurrentMillisecond();
432
ndbout << " Time before WaitTimeout = " << millisec_now << endl;
433
ndbout << " Time after WaitTimeout = " << millisec_now2 << endl;
434
ndbout << " Tried to wait "<<sleeptimes[i]<<" milliseconds." << endl;
435
ndbout << " Wait time was " << millisec_now2 -millisec_now <<" milliseconds." << endl;
439
ndbout << "TEST8 completed" << endl;
442
ndbout << "= TEST9 ===============================" << endl;
443
ndbout << " NdbTick_CurrentXXXXXsecond compare" << endl;
445
for (int i = 0; i < 5; i++)
447
ndbout << "*------------------------------- Measure" << i << endl;
449
NDB_TICKS millisec_now;
450
NDB_TICKS millisec_now2;
451
Uint32 usec_now, usec_now2;
452
Uint64 msec_now, msec_now2;
455
millisec_now = NdbTick_CurrentMillisecond();
456
NdbTick_CurrentMicrosecond( &msec_now, &usec_now);
458
NdbSleep_MilliSleep(sleeptimes[i]);
460
millisec_now2 = NdbTick_CurrentMillisecond();
461
NdbTick_CurrentMicrosecond( &msec_now2, &usec_now2);
463
Uint64 usecdiff = time_diff(msec_now,msec_now2,usec_now,usec_now2);
464
NDB_TICKS msecdiff = millisec_now2 -millisec_now;
466
ndbout << " Slept "<<sleeptimes[i]<<" milliseconds." << endl;
467
ndbout << " Measured " << msecdiff <<" milliseconds with milli function ." << endl;
468
ndbout << " Measured " << usecdiff/1000 << "," << usecdiff%1000<<" milliseconds with micro function ." << endl;
471
ndbout << "TEST9 completed" << endl;
475
ndbout << "Testing microsecond timer - " << iter << " iterations" << endl;
477
ndbout << "Testing microsecond timer - COMPLETED" << endl;
479
ndbout << "= TEST10 ===============================" << endl;
481
testmutex = NdbMutex_Create();
482
testcond = NdbCondition_Create();
485
for (int i = 0; i < T3_THREADS; i++)
488
t3threads[i] = NdbThread_Create(testTryLockfunc, // Function
489
(void**)&t3args[i],// Arg
491
(char*)"test10thread", // Thread name
492
NDB_THREAD_PRIO_MEAN); // Thread priority
495
ndbout << "All threads created" << endl;
497
if (NdbMutex_Lock(testmutex) != 0)
498
fail("TEST10", "NdbMutex_Lock failed");
500
while (testthreadsdone < T3_THREADS*10)
502
if(NdbCondition_Wait(testcond, testmutex) != 0)
503
fail("TEST10", "NdbCondition_WaitTimeout failed");
504
ndbout << "Condition signaled, there are " << testthreadsdone << " completed threads" << endl;
506
if (NdbMutex_Unlock(testmutex) != 0)
507
fail("TEST10", "NdbMutex_Unlock failed");
509
for (int i = 0; i < T3_THREADS; i++)
511
if (NdbThread_WaitFor(t3threads[i], &status3) != 0)
512
fail("TEST10", "NdbThread_WaitFor failed");
514
NdbThread_Destroy(&t3threads[i]);
517
NdbMutex_Destroy(testmutex);
518
NdbCondition_Destroy(testcond);
520
ndbout << "TEST10 completed" << endl;
523
// Check total status of test
525
if (TestHasFailed == 1)
526
ndbout << endl << "TEST FAILED!" << endl;
528
ndbout << endl << "TEST PASSED!" << endl;
530
return TestHasFailed;
534
Uint64 time_diff(Uint64 s1, Uint64 s2, Uint32 m1, Uint32 m2){
537
diff += (s2 - s1) * 1000000;
546
// ndbout("(s1,m1) = (%d, %d) (s2,m2) = (%d, %d) -> diff = %d\n",
547
// (Uint32)s1,m1,(Uint32)s2,m2, (Uint32)diff);
553
testMicros(int count){
557
for(int i = 0; i<count; i++){
560
if(NdbTick_CurrentMicrosecond(&s1, &m1) != 0){
561
ndbout << "Failed to get current micro" << endl;
565
Uint32 r = (rand() % 1000) + 1;
566
NdbSleep_MilliSleep(r);
567
if(NdbTick_CurrentMicrosecond(&s2, &m2) != 0){
568
ndbout << "Failed to get current micro" << endl;
572
Uint64 m = time_diff(s1,s2,m1,m2);
574
ndbout << "Slept for " << r << " ms"
575
<< " - Measured " << m << " us" << endl;
578
avg += (m - (r*1000));
579
sum2 += (m - (r*1000)) * (m - (r*1000));
581
avg += ((r*1000) - m);
582
sum2 += ((r*1000) - m) * ((r*1000) - m);
586
if(m > r && ((m - r) > 10)){
587
ndbout << "Difference to big: " << (m - r) << " - Test failed" << endl;
590
if(m < r && ((r - m) > 10)){
591
ndbout << "Difference to big: " << (r - m) << " - Test failed" << endl;
597
Uint32 dev = (avg * avg - sum2) / count; dev /= count;
601
while((t*t)<dev) t++;
602
ndbout << "NOTE - measure are compared to NdbSleep_MilliSleep(...)" << endl;
603
ndbout << "Average error = " << avg << " us" << endl;
604
ndbout << "Stddev error = " << t << " us" << endl;