1
// @(#) $Revision: 4.15 $ $Source: /judy/test/manual/Judy1LCheck.c $
2
// This program tests the accuracy of a Judy1 with a JudyL Array.
4
// Douglas L. Baskins (8/2001) doug@sourcejudy.com
7
#include <unistd.h> // unavailable on Win32, and no getopt().
10
#include <stdlib.h> // calloc()
11
#include <math.h> // pow()
12
#include <stdio.h> // printf()
16
// Common macro to handle a failure
17
#define FAILURE(STR, UL) \
19
printf( "Error: %s %lu, file='%s', 'function='%s', line %d\n", \
20
STR, UL, __FILE__, __FUNCTI0N__, __LINE__); \
21
fprintf(stderr, "Error: %s %lu, file='%s', 'function='%s', line %d\n", \
22
STR, UL, __FILE__, __FUNCTI0N__, __LINE__); \
26
// Structure to keep track of times
27
typedef struct MEASUREMENTS_STRUCT
33
// Specify prototypes for each test routine
35
NextNumb(Word_t * PNumber, double *PDNumb, double DMult, Word_t MaxNumb);
37
Word_t TestJudyIns(void **J1, void **JL, Word_t Seed, Word_t Elements);
39
Word_t TestJudyDup(void **J1, void **JL, Word_t Seed, Word_t Elements);
41
int TestJudyDel(void **J1, void **JL, Word_t Seed, Word_t Elements);
43
Word_t TestJudyGet(void *J1, void *JL, Word_t Seed, Word_t Elements);
45
int TestJudyCount(void *J1, void *JL, Word_t LowIndex, Word_t Elements);
47
Word_t TestJudyNext(void *J1, void *JL, Word_t LowIndex, Word_t Elements);
49
int TestJudyPrev(void *J1, void *JL, Word_t HighIndex, Word_t Elements);
52
TestJudyNextEmpty(void *J1, void *JL, Word_t LowIndex, Word_t Elements);
55
TestJudyPrevEmpty(void *J1, void *JL, Word_t HighIndex, Word_t Elements);
59
0,0,0,0,0,0,0,0,0,0, // 0..9
85
0x145f9, // 35 following tested with Seed=0xc1fc to 35Gig numbers
117
// Routine to "mirror" the input data word
121
// BIT REVERSAL, Ron Gutman in Dr. Dobb's Journal, #316, Sept 2000, pp133-136
125
word = ((word & 0x00000000ffffffff) << 32) |
126
((word & 0xffffffff00000000) >> 32);
127
word = ((word & 0x0000ffff0000ffff) << 16) |
128
((word & 0xffff0000ffff0000) >> 16);
129
word = ((word & 0x00ff00ff00ff00ff) << 8) |
130
((word & 0xff00ff00ff00ff00) >> 8);
131
word = ((word & 0x0f0f0f0f0f0f0f0f) << 4) |
132
((word & 0xf0f0f0f0f0f0f0f0) >> 4);
133
word = ((word & 0x3333333333333333) << 2) |
134
((word & 0xcccccccccccccccc) >> 2);
135
word = ((word & 0x5555555555555555) << 1) |
136
((word & 0xaaaaaaaaaaaaaaaa) >> 1);
138
word = ((word & 0x0000ffff) << 16) | ((word & 0xffff0000) >> 16);
139
word = ((word & 0x00ff00ff) << 8) | ((word & 0xff00ff00) >> 8);
140
word = ((word & 0x0f0f0f0f) << 4) | ((word & 0xf0f0f0f0) >> 4);
141
word = ((word & 0x33333333) << 2) | ((word & 0xcccccccc) >> 2);
142
word = ((word & 0x55555555) << 1) | ((word & 0xaaaaaaaa) >> 1);
152
Word_t SkipN = 0; // default == Random skip
153
Word_t nElms = 1000000; // Default = 1M
154
Word_t ErrorFlag = 0;
159
// Stuff for LFSR (pseudo random number generator)
160
Word_t RandomBit = ~0UL / 2 + 1;
161
Word_t BValue = sizeof(Word_t) * 8;
163
Word_t StartSeed = 0xc1fc; // default beginning number
167
#define __FUNCTI0N__ "Random"
169
static Word_t // Placed here so INLINING compilers get to look at it.
170
Random(Word_t newseed)
172
if (newseed & RandomBit)
181
newseed &= RandomBit * 2 - 1;
182
if (newseed == FirstSeed)
184
printf("End of LFSR, Total Population = %lu\n", TotalPop);
190
static Word_t // Placed here so INLINING compilers get to look at it.
191
GetNextIndex(Word_t Index)
196
Index = Random(Index);
202
#define __FUNCTI0N__ "main"
205
main(int argc, char *argv[])
207
// Names of Judy Arrays
208
void *J1 = NULL; // Judy1
209
void *JL = NULL; // JudyL
214
Word_t PtsPdec = 10; // points per decade
215
Word_t Groups; // Number of measurement groups
221
//////////////////////////////////////////////////////////////
222
// PARSE INPUT PARAMETERS
223
//////////////////////////////////////////////////////////////
225
while ((c = getopt(argc, argv, "n:S:P:b:L:B:pdDC")) != -1)
229
case 'n': // Number of elements
230
nElms = strtoul(optarg, NULL, 0); // Size of Linear Array
232
FAILURE("No tests: -n", nElms);
234
// Check if more than a trillion (64 bit only)
235
if ((double)nElms > 1e12)
236
FAILURE("Too many Indexes=", nElms);
239
case 'S': // Step Size, 0 == Random
240
SkipN = strtoul(optarg, NULL, 0);
244
PtsPdec = strtoul(optarg, NULL, 0);
247
case 'b': // May not work past 35 bits if changed
248
StartSeed = strtoul(optarg, NULL, 0);
252
BValue = strtoul(optarg, NULL, 0);
254
(BValue > (sizeof(Word_t) * 8))
256
(MagicList[BValue] == 0)
260
printf("\nIllegal number of random bits of %lu !!!\n", BValue);
264
case 'p': // Print test indexes
268
case 'd': // Delete indexes
272
case 'D': // Swizzle indexes
276
case 'C': // Skip counting test.
288
printf("\n%s -n# -S# -B# -P# -b # -DRCpd\n\n", argv[0]);
290
printf("-n <#> number of indexes used in tests\n");
291
printf("-C skip JudyCount tests\n");
292
printf("-p print index set - for debug\n");
293
printf("-d do not call JudyDel/Unset\n");
294
printf("-D Swizzle data (mirror)\n");
295
printf("-S <#> index skip amount, 0 = random\n");
296
printf("-B <#> # bits-1 in random number generator\n");
297
printf("-P <#> number measurement points per decade\n");
302
// Set number of Random bits in LFSR
303
RandomBit = 1UL << (BValue - 1);
304
Magic = MagicList[BValue];
306
if (nElms > ((RandomBit-2) * 2))
308
printf("# Number = -n%lu of Indexes reduced to max expanse of Random numbers\n", nElms);
309
nElms = ((RandomBit-2) * 2);
312
printf("\n%s -n%lu -S%lu -B%lu", argv[0], nElms, SkipN, BValue);
324
if (sizeof(Word_t) == 8)
325
printf("%s 64 Bit version\n", argv[0]);
326
else if (sizeof(Word_t) == 4)
327
printf("%s 32 Bit version\n", argv[0]);
329
//////////////////////////////////////////////////////////////
330
// CALCULATE NUMBER OF MEASUREMENT GROUPS
331
//////////////////////////////////////////////////////////////
333
// Calculate Multiplier for number of points per decade
334
Mult = pow(10.0, 1.0 / (double)PtsPdec);
337
Word_t numb, prevnumb;
339
// Count number of measurements needed (10K max)
341
for (Groups = 2; Groups < 10000; Groups++)
342
if (NextNumb(&numb, &sum, Mult, nElms))
345
// Get memory for measurements
346
Pms = (Pms_t) calloc(Groups, sizeof(ms_t));
348
// Now calculate number of Indexes for each measurement point
351
for (grp = 0; grp < Groups; grp++)
353
Pms[grp].ms_delta = numb - prevnumb;
356
NextNumb(&numb, &sum, Mult, nElms);
358
} // Groups = number of sizes
360
//////////////////////////////////////////////////////////////
361
// BEGIN TESTS AT EACH GROUP SIZE
362
//////////////////////////////////////////////////////////////
364
// Get the kicker to test the LFSR
365
FirstSeed = Seed = StartSeed & (RandomBit * 2 - 1);
367
printf("Total Pop Total Ins New Ins Total Del");
368
printf(" J1MU/I JLMU/I\n");
376
Seed1 = GetNextIndex(Seed1);
378
if (TotalPop > 40000000000) printf("Total = %lu\n", TotalPop), exit(1);
383
for (grp = 0; grp < Groups; grp++)
385
Word_t LowIndex, HighIndex;
389
Delta = Pms[grp].ms_delta;
392
NewSeed = TestJudyIns(&J1, &JL, Seed, Delta);
395
LowIndex = TestJudyGet(J1, JL, Seed, Delta);
397
// Test JLI, J1S -dup
398
LowIndex = TestJudyDup(&J1, &JL, Seed, Delta);
403
TestJudyCount(J1, JL, LowIndex, Delta);
406
HighIndex = TestJudyNext(J1, JL, LowIndex, Delta);
409
TestJudyPrev(J1, JL, HighIndex, Delta);
412
TestJudyNextEmpty(J1, JL, LowIndex, Delta);
415
TestJudyPrevEmpty(J1, JL, HighIndex, Delta);
420
TestJudyDel(&J1, &JL, Seed, Delta);
423
printf("%9lu %9lu %7lu %9lu", TotalPop, TotalIns, Delta, TotalDel);
425
Word_t Count1, CountL;
427
// Print the number of bytes used per Index
428
J1C(Count1, J1, 0, ~0);
429
printf(" %6.3f", (double)Judy1MemUsed(J1) / (double)Count1);
430
JLC(CountL, JL, 0, ~0);
431
printf(" %6.3f", (double)JudyLMemUsed(JL) / (double)CountL);
435
// Advance Index number set
439
Word_t Count1, CountL;
442
JLC(CountL, JL, 0, ~0);
443
J1C(Count1, J1, 0, ~0);
445
if (CountL != TotalPop)
446
FAILURE("JudyLCount wrong", CountL);
448
if (Count1 != TotalPop)
449
FAILURE("Judy1Count wrong", Count1);
453
J1FA(Bytes, J1); // Free the Judy1 Array
454
printf("Judy1FreeArray = %6.3f Bytes/Index\n",
455
(double)Bytes / (double)Count1);
457
if (pFlag) { printf("J1FA: %8lu\tbytes = %lu\n", TotalPop, Bytes); }
459
JLFA(Bytes, JL); // Free the JudyL Array
460
printf("JudyLFreeArray = %6.3f Bytes/Index\n",
461
(double)Bytes / (double)CountL);
463
if (pFlag) { printf("JLFA: %8lu\tbytes = %lu\n", TotalPop, Bytes); }
468
printf("Passed JudyL and Judy1 tests\n");
473
#define __FUNCTI0N__ "TestJudyIns"
476
TestJudyIns(void **J1, void **JL, Word_t Seed, Word_t Elements)
480
Word_t *PValue, *PValue1;
484
for (Seed1 = Seed, elm = 0; elm < Elements; elm++)
486
Seed1 = GetNextIndex(Seed1);
488
FAILURE("This command not robust if Index == 0", elm);
491
TstIndex = Swizzle(Seed1);
495
if (pFlag) { printf("Ins: %8lu\t0x%lx\n", elm, TstIndex); }
497
J1S(Rcode, *J1, TstIndex);
499
FAILURE("Judy1Set failed at", elm);
501
FAILURE("Judy1Set failed - DUP Index, population =", TotalPop);
503
J1T(Rcode, *J1, TstIndex);
505
FAILURE("Judy1Test failed - Index missing, population =", TotalPop);
507
J1S(Rcode, *J1, TstIndex);
509
FAILURE("Judy1Set failed - Index missing, population =", TotalPop);
511
JLI(PValue, *JL, TstIndex);
513
FAILURE("JudyLIns failed at", elm);
514
if (*PValue == TstIndex)
515
FAILURE("JudyLIns failed - DUP Index, population =", TotalPop);
517
// Save Index in Value
520
JLG(PValue1, *JL, TstIndex);
521
if (PValue != PValue1)
522
FAILURE("JudyLGet failed - Index missing, population =", TotalPop);
524
JLI(PValue1, *JL, TstIndex);
525
if (PValue != PValue1)
527
if (*PValue1 != TstIndex)
529
FAILURE("JudyLIns failed - Index missing, population =", TotalPop);
533
// not ready for this yet! printf("Index moved -- TotalPop = %lu\n", TotalPop);
539
return (Seed1); // New seed
543
#define __FUNCTI0N__ "TestJudyGet"
546
TestJudyGet(void *J1, void *JL, Word_t Seed, Word_t Elements)
548
Word_t LowIndex = ~0UL;
555
for (Seed1 = Seed, elm = 0; elm < Elements; elm++)
557
Seed1 = GetNextIndex(Seed1);
560
TstIndex = Swizzle(Seed1);
564
if (TstIndex < LowIndex)
567
J1T(Rcode, J1, TstIndex);
569
FAILURE("Judy1Test Rcode != 1", (Word_t) Rcode);
571
JLG(PValue, JL, TstIndex);
572
if (PValue == (Word_t *) NULL)
573
FAILURE("JudyLGet ret PValue = NULL", 0L);
574
if (*PValue != TstIndex)
575
FAILURE("JudyLGet ret wrong Value at", elm);
582
#define __FUNCTI0N__ "TestJudyDup"
585
TestJudyDup(void **J1, void **JL, Word_t Seed, Word_t Elements)
587
Word_t LowIndex = ~0UL;
594
for (Seed1 = Seed, elm = 0; elm < Elements; elm++)
596
Seed1 = GetNextIndex(Seed1);
599
TstIndex = Swizzle(Seed1);
603
if (TstIndex < LowIndex)
606
J1S(Rcode, *J1, TstIndex);
608
FAILURE("Judy1Set Rcode != 0", (Word_t) Rcode);
610
JLI(PValue, *JL, TstIndex);
611
if (PValue == (Word_t *) NULL)
612
FAILURE("JudyLIns ret PValue = NULL", 0L);
613
if (*PValue != TstIndex)
614
FAILURE("JudyLIns ret wrong Value at", elm);
621
#define __FUNCTI0N__ "TestJudyCount"
624
TestJudyCount(void *J1, void *JL, Word_t LowIndex, Word_t Elements)
627
Word_t Count1, CountL;
628
Word_t TstIndex = LowIndex;
632
for (elm = 0; elm < Elements; elm++)
634
J1C(Count1, J1, LowIndex, TstIndex);
636
FAILURE("Judy1Count ret JERR", (Word_t) Count1);
638
if (Count1 != (elm + 1))
640
J1C(CountL, J1, 0, -1);
641
printf("J1C(%lu, J1, 0, -1)\n", CountL);
643
JLC(CountL, JL, 0, -1);
644
printf("JLC(%lu, JL, 0, -1)\n", CountL);
646
printf("LowIndex = 0x%lx, TstIndex = 0x%lx, diff = %lu\n", LowIndex,
647
TstIndex, TstIndex - LowIndex);
648
JLC(CountL, JL, LowIndex, TstIndex);
649
printf("CountL = %lu, Count1 = %lu, should be: elm + 1 = %lu\n", CountL, Count1, elm + 1);
650
FAILURE("J1C at", elm);
653
JLC(CountL, JL, LowIndex, TstIndex);
655
FAILURE("JudyLCount ret JERR", (Word_t) CountL);
657
if (CountL != (elm + 1)) FAILURE("JLC at", elm);
659
J1N(Rcode, J1, TstIndex);
665
#define __FUNCTI0N__ "TestJudyNext"
667
Word_t TestJudyNext(void *J1, void *JL, Word_t LowIndex, Word_t Elements)
669
Word_t JLindex, J1index;
674
// Get an Index low enough for Elements
675
J1index = JLindex = LowIndex;
677
JLF(PValue, JL, JLindex);
678
J1F(Rcode, J1, J1index);
680
for (elm = 0; elm < Elements; elm++)
683
FAILURE("JudyLNext ret NULL PValue at", elm);
685
FAILURE("Judy1Next Rcode != 1 =", (Word_t) Rcode);
686
if (JLindex != J1index)
687
FAILURE("Judy1Next & Judy1Next ret different PIndex at", elm);
689
JLN(PValue, JL, JLindex); // Get next one
690
J1N(Rcode, J1, J1index); // Get next one
692
// perhaps a check should be done here -- if I knew what to expect.
693
return(JLindex); // return last one
698
#define __FUNCTI0N__ "TestJudyPrev"
701
TestJudyPrev(void *J1, void *JL, Word_t HighIndex, Word_t Elements)
703
Word_t JLindex, J1index;
708
// Get an Index high enough for Elements
709
J1index = JLindex = HighIndex;
711
JLL(PValue, JL, JLindex);
712
J1L(Rcode, J1, J1index);
714
for (elm = 0; elm < Elements; elm++)
717
FAILURE("JudyLPrev ret NULL PValue at", elm);
719
FAILURE("Judy1Prev Rcode != 1 =", (Word_t) Rcode);
720
if (JLindex != J1index)
721
FAILURE("Judy1Prev & Judy1Prev ret different PIndex at", elm);
723
JLP(PValue, JL, JLindex); // Get previous one
724
J1P(Rcode, J1, J1index); // Get previous one
726
// perhaps a check should be done here -- if I knew what to expect.
732
#define __FUNCTI0N__ "TestJudyNextEmpty"
735
TestJudyNextEmpty(void *J1, void *JL, Word_t LowIndex, Word_t Elements)
738
Word_t JLindex, J1index;
740
int Rcode; // Return code
742
// Set 1st search to ..
744
J1index = JLindex = Seed1;
746
for (elm = 0; elm < Elements; elm++)
750
// Find next Empty Index, JLindex is modified by JLNE
751
JLNE(Rcode, JL, JLindex); // Rcode = JudyLNextEmpty(JL, &JLindex, PJE0)
753
FAILURE("JudyLNextEmpty Rcode != 1 =", (Word_t) Rcode);
755
if (pFlag) { printf("JNE: %8lu\t0x%lx\n", elm, JLindex); }
757
// Find next Empty Index, J1index is modified by J1NE
758
J1NE(Rcode, J1, J1index); // Rcode = Judy1NextEmpty(J1, &J1index, PJE0)
760
FAILURE("Judy1NextEmpty Rcode != 1 =", (Word_t) Rcode);
762
if (J1index != JLindex)
763
FAILURE("JLNE != J1NE returned index at", elm);
765
J1T(Rcode, J1, J1index);
767
FAILURE("J1NE returned non-empty Index =", J1index);
769
JLG(PValue, JL, JLindex);
770
if (PValue != (Word_t *) NULL)
771
FAILURE("JLNE returned non-empty Index =", JLindex);
773
Seed1 = GetNextIndex(Seed1);
774
J1index = JLindex = Seed1;
780
// Routine to JudyPrevEmpty routines
783
#define __FUNCTI0N__ "TestJudyPrevEmpty"
786
TestJudyPrevEmpty(void *J1, void *JL, Word_t HighIndex, Word_t Elements)
789
Word_t JLindex, J1index;
793
// Set 1st search to ..
795
J1index = JLindex = Seed1;
797
for (elm = 0; elm < Elements; elm++)
801
J1PE(Rcode, J1, J1index); // Rcode = Judy1PrevEmpty(J1, &J1index, PJE0)
803
FAILURE("Judy1PrevEmpty Rcode != 1 =", (Word_t) Rcode);
805
if (pFlag) { printf("JPE: %8lu\t0x%lx\n", elm, J1index); }
807
// Find next Empty Index, JLindex is modified by JLPE
808
JLPE(Rcode, JL, JLindex); // Rcode = JudyLPrevEmpty(JL, &JLindex, PJE0)
810
FAILURE("JudyLPrevEmpty Rcode != 1 =", (Word_t) Rcode);
812
if (J1index != JLindex)
813
FAILURE("JLPE != J1PE returned index at", elm);
815
J1T(Rcode, J1, J1index);
817
FAILURE("J1PE returned non-empty Index =", J1index);
819
JLG(PValue, JL, JLindex);
820
if (PValue != (Word_t *) NULL)
821
FAILURE("JLPE returned non-empty Index =", JLindex);
823
Seed1 = GetNextIndex(Seed1);
824
J1index = JLindex = Seed1;
830
#define __FUNCTI0N__ "TestJudyDel"
833
TestJudyDel(void **J1, void **JL, Word_t Seed, Word_t Elements)
840
// Only delete half of thoes inserted
841
for (Seed1 = Seed, elm = 0; elm < (Elements / 2); elm++)
843
Seed1 = GetNextIndex(Seed1);
846
TstIndex = Swizzle(Seed1);
850
if (pFlag) { printf("Del: %8lu\t0x%lx\n", elm, TstIndex); }
854
J1U(Rcode, *J1, TstIndex);
856
FAILURE("Judy1Unset ret Rcode != 1", (Word_t) Rcode);
858
JLD(Rcode, *JL, TstIndex);
860
FAILURE("JudyLDel ret Rcode != 1", (Word_t) Rcode);
867
// Routine to get next size of Indexes
868
int // return 1 if last number
869
NextNumb(Word_t * PNumber, // pointer to returned next number
870
double *PDNumb, // Temp double of above
871
double DMult, // Multiplier
872
Word_t MaxNumb) // Max number to return
877
Word_t PrevNumb = *PNumber;
879
// Verify integer number increased
880
for (num = 0; num < 1000; num++)
885
// Return it in integer format
886
*PNumber = (Word_t) (*PDNumb + 0.5);
888
if (*PNumber != PrevNumb)
892
// Verify it did exceed max ulong
893
if ((*PDNumb + 0.5) > (double)(-1UL))
895
// It did, so return max number
897
return (1); // flag it
900
// Verify it did not exceed max number
901
if ((*PDNumb + 0.5) > (double)MaxNumb)
903
// it did, so return max
905
return(1); // flag it
907
return(0); // more available