1 /* Copyright (c) 2003, 2006, 2007 MySQL AB
2    Use is subject to license terms
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA */
16 
17 #include "DynArr256.hpp"
18 #include <stdio.h>
19 #include <assert.h>
20 #include <NdbOut.hpp>
21 
22 #define DA256_BITS  5
23 #define DA256_MASK 31
24 
25 struct DA256CL
26 {
27   Uint32 m_magic;
28   Uint32 m_data[15];
29 };
30 
31 struct DA256Free
32 {
33   Uint32 m_magic;
34   Uint32 m_next_free;
35 };
36 
37 struct DA256Node
38 {
39   struct DA256CL m_lines[17];
40 };
41 
42 struct DA256Page
43 {
44   struct DA256CL m_header[2];
45   struct DA256Node m_nodes[30];
46 };
47 
48 #define require(x) require_impl(x, __LINE__)
49 //#define DA256_USE_PX
50 //#define DA256_USE_PREFETCH
51 #define DA256_EXTRA_SAFE
52 
53 
54 #ifdef UNIT_TEST
55 #ifdef USE_CALLGRIND
56 #include <valgrind/callgrind.h>
57 #else
58 #define CALLGRIND_TOGGLE_COLLECT()
59 #endif
60 Uint32 allocatedpages = 0;
61 Uint32 allocatednodes = 0;
62 Uint32 releasednodes = 0;
63 #endif
64 
65 inline
66 void
require_impl(bool x,int line)67 require_impl(bool x, int line)
68 {
69   if (!x)
70   {
71     ndbout_c("LINE: %d", line);
72     abort();
73   }
74 }
75 
DynArr256Pool()76 DynArr256Pool::DynArr256Pool()
77 {
78   m_type_id = RNIL;
79   m_first_free = RNIL;
80   m_memroot = 0;
81 }
82 
83 void
init(Uint32 type_id,const Pool_context & pc)84 DynArr256Pool::init(Uint32 type_id, const Pool_context & pc)
85 {
86   m_ctx = pc;
87   m_type_id = type_id;
88   m_memroot = (DA256Page*)m_ctx.get_memroot();
89 }
90 
91 static const Uint32 g_max_sizes[5] = { 0, 256, 65536, 16777216, ~0 };
92 
93 /**
94  * sz = 0     =     1 - 0 level
95  * sz = 1     = 256^1 - 1 level
96  * sz = 2     = 256^2 - 2 level
97  * sz = 3     = 256^3 - 3 level
98  * sz = 4     = 256^4 - 4 level
99  */
100 Uint32 *
get(Uint32 pos) const101 DynArr256::get(Uint32 pos) const
102 {
103   Uint32 sz = m_head.m_sz;
104   Uint32 ptrI = m_head.m_ptr_i;
105   DA256Page * memroot = m_pool.m_memroot;
106   Uint32 type_id = (~m_pool.m_type_id) & 0xFFFF;
107 
108   if (unlikely(pos >= g_max_sizes[sz]))
109   {
110     return 0;
111   }
112 
113 #ifdef DA256_USE_PX
114   Uint32 px[4] = { (pos >> 24) & 255,
115 		   (pos >> 16) & 255,
116 		   (pos >> 8)  & 255,
117 		   (pos >> 0)  & 255 };
118 #endif
119 
120   Uint32* retVal = &m_head.m_ptr_i;
121   for(; sz --;)
122   {
123     if (unlikely(ptrI == RNIL))
124     {
125       return 0;
126     }
127 #ifdef DA256_USE_PX
128     Uint32 p0 = px[sz];
129 #else
130     Uint32 shr = sz << 3;
131     Uint32 p0 = (pos >> shr) & 255;
132 #endif
133     Uint32 page_no = ptrI >> DA256_BITS;
134     Uint32 page_idx = ptrI & DA256_MASK;
135     DA256Page * page = memroot + page_no;
136 
137     Uint32 *magic_ptr, p;
138     if (p0 != 255)
139     {
140       Uint32 line = ((p0 << 8) + (p0 << 4) + p0 + 255) >> 12;
141       Uint32 * ptr = (Uint32*)(page->m_nodes + page_idx);
142 
143       p = 0;
144       retVal = (ptr + 1 + p0 + line);
145       magic_ptr =(ptr + (p0 & ~15));
146     }
147     else
148     {
149       Uint32 b = (page_idx + 1) >> 4;
150       Uint32 * ptr = (Uint32*)(page->m_header+b);
151 
152       p = page_idx - (b << 4) + b;
153       retVal = (ptr + 1 + p);
154       magic_ptr = ptr;
155     }
156 
157     ptrI = *retVal;
158     Uint32 magic = *magic_ptr;
159 
160     if (unlikely(! ((magic & (1 << p)) && (magic >> 16) == type_id)))
161       goto err;
162   }
163 
164   return retVal;
165 err:
166   require(false);
167   return 0;
168 }
169 
170 Uint32 *
set(Uint32 pos)171 DynArr256::set(Uint32 pos)
172 {
173   Uint32 sz = m_head.m_sz;
174   Uint32 type_id = (~m_pool.m_type_id) & 0xFFFF;
175   DA256Page * memroot = m_pool.m_memroot;
176 
177   if (unlikely(pos >= g_max_sizes[sz]))
178   {
179     if (unlikely(!expand(pos)))
180     {
181       return 0;
182     }
183     sz = m_head.m_sz;
184   }
185 
186 #ifdef DA256_USE_PX
187   Uint32 px[4] = { (pos >> 24) & 255,
188 		   (pos >> 16) & 255,
189 		   (pos >> 8)  & 255,
190 		   (pos >> 0)  & 255 };
191 #endif
192 
193   Uint32 ptrI = m_head.m_ptr_i;
194   Uint32 *retVal = &m_head.m_ptr_i;
195   for(; sz --;)
196   {
197 #ifdef DA256_USE_PX
198     Uint32 p0 = px[sz];
199 #else
200     Uint32 shr = sz << 3;
201     Uint32 p0 = (pos >> shr) & 255;
202 #endif
203     if (ptrI == RNIL)
204     {
205       if (unlikely((ptrI = m_pool.seize()) == RNIL))
206       {
207 	return 0;
208       }
209       * retVal = ptrI;
210     }
211 
212     Uint32 page_no = ptrI >> DA256_BITS;
213     Uint32 page_idx = ptrI & DA256_MASK;
214     DA256Page * page = memroot + page_no;
215 
216     Uint32 *magic_ptr, p;
217     if (p0 != 255)
218     {
219       Uint32 line = ((p0 << 8) + (p0 << 4) + p0 + 255) >> 12;
220       Uint32 * ptr = (Uint32*)(page->m_nodes + page_idx);
221 
222       p = 0;
223       magic_ptr = (ptr + (p0 & ~15));
224       retVal = (ptr + 1 + p0 + line);
225     }
226     else
227     {
228       Uint32 b = (page_idx + 1) >> 4;
229       Uint32 * ptr = (Uint32*)(page->m_header+b);
230 
231       p = page_idx - (b << 4) + b;
232       magic_ptr = ptr;
233       retVal = (ptr + 1 + p);
234     }
235 
236     ptrI = * retVal;
237     Uint32 magic = *magic_ptr;
238 
239     if (unlikely(! ((magic & (1 << p)) && (magic >> 16) == type_id)))
240       goto err;
241   }
242 
243   return retVal;
244 
245 err:
246   require(false);
247   return 0;
248 }
249 
250 static
251 inline
252 void
initpage(DA256Page * p,Uint32 page_no,Uint32 type_id)253 initpage(DA256Page* p, Uint32 page_no, Uint32 type_id)
254 {
255   Uint32 i, j;
256 #ifdef DA256_USE_PREFETCH
257 #if defined(__GNUC__) && !(__GNUC__ == 2 && __GNUC_MINOR__ < 96)
258 #ifdef DA256_EXTRA_SAFE
259   for (i = 0; i<(30 * 17 + 2); i++)
260   {
261     __builtin_prefetch (p->m_header + i, 1);
262   }
263 #else
264   {
265     __builtin_prefetch (p->m_header + 0, 1);
266     __builtin_prefetch (p->m_header + 1, 1);
267     for (i = 0; i<30; i++)
268     {
269       __builtin_prefetch (p->m_nodes + i, 1);
270     }
271   }
272 #endif
273 #endif
274 #endif
275   DA256CL* cl;
276   for  (i = 0; i<2; i++)
277   {
278     cl = p->m_header + i;
279     cl->m_magic = (~type_id << 16);
280   }
281 
282   DA256Free* free;
283 
284   for (i = 0; i<30; i++)
285   {
286     free = (DA256Free*)(p->m_nodes+i);
287     free->m_magic = type_id;
288     free->m_next_free = (page_no << DA256_BITS) + (i + 1);
289 #ifdef DA256_EXTRA_SAFE
290     DA256Node* node = p->m_nodes+i;
291     for (j = 0; j<17; j++)
292       node->m_lines[j].m_magic = type_id;
293 #endif
294   }
295 
296   free = (DA256Free*)(p->m_nodes+29);
297   free->m_next_free = RNIL;
298 }
299 
300 bool
expand(Uint32 pos)301 DynArr256::expand(Uint32 pos)
302 {
303   Uint32 i;
304   Uint32 idx = 0;
305   Uint32 alloc[5];
306   Uint32 sz = m_head.m_sz;
307 
308   for (; pos >= g_max_sizes[sz]; sz++);
309 
310   if (m_head.m_sz == 0)
311   {
312     m_head.m_sz = sz;
313     return true;
314   }
315 
316   sz =  m_head.m_sz;
317   for (; pos >= g_max_sizes[sz]; sz++)
318   {
319     Uint32 ptrI = m_pool.seize();
320     if (unlikely(ptrI == RNIL))
321       goto err;
322     alloc[idx++] = ptrI;
323   }
324 
325   alloc[idx] = m_head.m_ptr_i;
326   m_head.m_sz = 1;
327   for (Uint32 i = 0; i<idx; i++)
328   {
329     m_head.m_ptr_i = alloc[i];
330     Uint32 * ptr = get(0);
331     * ptr = alloc[i + 1];
332   }
333 
334   m_head.m_sz = sz;
335   m_head.m_ptr_i = alloc[0];
336 
337   return true;
338 
339 err:
340   for (i = 0; i<idx; i++)
341     m_pool.release(alloc[i]);
342   return false;
343 }
344 
345 void
init(ReleaseIterator & iter)346 DynArr256::init(ReleaseIterator &iter)
347 {
348   iter.m_sz = 1;
349   iter.m_pos = 0;
350   iter.m_ptr_i[0] = RNIL;
351   iter.m_ptr_i[1] = m_head.m_ptr_i;
352   iter.m_ptr_i[2] = RNIL;
353   iter.m_ptr_i[3] = RNIL;
354   iter.m_ptr_i[4] = RNIL;
355 }
356 
357 /**
358  * Iter is in next pos
359  *
360  * 0 - done
361  * 1 - data
362  * 2 - no data
363  */
364 Uint32
release(ReleaseIterator & iter,Uint32 * retptr)365 DynArr256::release(ReleaseIterator &iter, Uint32 * retptr)
366 {
367   Uint32 sz = iter.m_sz;
368   Uint32 ptrI = iter.m_ptr_i[sz];
369   Uint32 page_no = ptrI >> DA256_BITS;
370   Uint32 page_idx = ptrI & DA256_MASK;
371   Uint32 type_id = (~m_pool.m_type_id) & 0xFFFF;
372   DA256Page * memroot = m_pool.m_memroot;
373   DA256Page * page = memroot + page_no;
374 
375   if (ptrI != RNIL)
376   {
377     Uint32 p0 = iter.m_pos & 255;
378     for (; p0<256; p0++)
379     {
380       Uint32 *retVal, *magic_ptr, p;
381       if (p0 != 255)
382       {
383 	Uint32 line = ((p0 << 8) + (p0 << 4) + p0 + 255) >> 12;
384 	Uint32 * ptr = (Uint32*)(page->m_nodes + page_idx);
385 
386 	p = 0;
387 	retVal = (ptr + 1 + p0 + line);
388 	magic_ptr =(ptr + (p0 & ~15));
389       }
390       else
391       {
392 	Uint32 b = (page_idx + 1) >> 4;
393 	Uint32 * ptr = (Uint32*)(page->m_header+b);
394 
395 	p = page_idx - (b << 4) + b;
396 	retVal = (ptr + 1 + p);
397 	magic_ptr = ptr;
398       }
399 
400       Uint32 magic = *magic_ptr;
401       Uint32 val = *retVal;
402       if (unlikely(! ((magic & (1 << p)) && (magic >> 16) == type_id)))
403 	goto err;
404 
405       if (sz == m_head.m_sz)
406       {
407 	* retptr = val;
408 	p0++;
409 	if (p0 != 256)
410 	{
411 	  /**
412 	   * Move next
413 	   */
414 	  iter.m_pos &= ~(Uint32)255;
415 	  iter.m_pos |= p0;
416 	}
417 	else
418 	{
419 	  /**
420 	   * Move up
421 	   */
422 	  m_pool.release(ptrI);
423 	  iter.m_sz --;
424 	  iter.m_pos >>= 8;
425 	}
426 	return 1;
427       }
428       else if (val != RNIL)
429       {
430 	iter.m_sz++;
431 	iter.m_ptr_i[iter.m_sz] = val;
432 	iter.m_pos = (p0 << 8);
433 	* retVal = RNIL;
434 	return 2;
435       }
436     }
437 
438     assert(p0 == 256);
439     m_pool.release(ptrI);
440     iter.m_sz --;
441     iter.m_pos >>= 8;
442     return 2;
443   }
444 
445   new (&m_head) Head();
446   return 0;
447 
448 err:
449   require(false);
450   return false;
451 }
452 
453 static
454 inline
455 bool
seizenode(DA256Page * page,Uint32 idx,Uint32 type_id)456 seizenode(DA256Page* page, Uint32 idx, Uint32 type_id)
457 {
458   Uint32 i;
459   Uint32 b = (idx + 1) >> 4;
460   Uint32 p = idx - (b << 4) + b;
461 
462   DA256Node * ptr = (DA256Node*)(page->m_nodes + idx);
463 
464 #ifdef DA256_USE_PREFETCH
465 #if defined(__GNUC__) && !(__GNUC__ == 2 && __GNUC_MINOR__ < 96)
466   __builtin_prefetch (page->m_header + b, 1);
467   for (i = 0; i<17; i++)
468   {
469     __builtin_prefetch (ptr->m_lines+i, 1);
470   }
471 #endif
472 #endif
473 
474 #ifdef DA256_EXTRA_SAFE
475   Uint32 check = type_id;
476 #endif
477   type_id = ((~type_id) << 16) | 0xFFFF;
478 
479 #ifdef DA256_EXTRA_SAFE
480   if (unlikely(((page->m_header + b)->m_magic & (1 << p)) != 0))
481   {
482     return false;
483   }
484 #endif
485 
486   (page->m_header + b)->m_magic |= (1 << p);
487   (page->m_header + b)->m_data[p] = RNIL;
488   for (i = 0; i<17; i++)
489   {
490     DA256CL * line = ptr->m_lines + i;
491 #ifdef DA256_EXTRA_SAFE
492     if (unlikely(line->m_magic != check))
493     {
494       return false;
495     }
496 #endif
497     line->m_magic = type_id;
498     for (Uint32 j = 0; j<15; j++)
499       line->m_data[j] = RNIL;
500   }
501 
502 #ifdef UNIT_TEST
503   allocatednodes++;
504 #endif
505   return true;
506 }
507 
508 static
509 bool
releasenode(DA256Page * page,Uint32 idx,Uint32 type_id)510 releasenode(DA256Page* page, Uint32 idx, Uint32 type_id)
511 {
512   Uint32 i;
513   Uint32 b = (idx + 1) >> 4;
514   Uint32 p = idx - (b << 4) + b;
515 
516   DA256Node * ptr = (DA256Node*)(page->m_nodes + idx);
517 
518 #ifdef DA256_USE_PREFETCH
519 #if defined(__GNUC__) && !(__GNUC__ == 2 && __GNUC_MINOR__ < 96)
520   __builtin_prefetch (page->m_header + b, 1);
521   for (i = 0; i<17; i++)
522   {
523     __builtin_prefetch (ptr->m_lines+i, 1);
524   }
525 #endif
526 #endif
527 
528 #ifdef DA256_EXTRA_SAFE
529   Uint32 check = ((~type_id) << 16) | 0xFFFF;
530 #endif
531 
532 #ifdef DA256_EXTRA_SAFE
533   if (unlikely((((page->m_header + b)->m_magic & (1 << p)) == 0)))
534   {
535     return false;
536   }
537 #endif
538 
539   (page->m_header + b)->m_magic ^= (1 << p);
540   for (i = 0; i<17; i++)
541   {
542     DA256CL * line = ptr->m_lines + i;
543 #ifdef DA256_EXTRA_SAFE
544     if (unlikely(line->m_magic != check))
545     {
546       return false;
547     }
548 #endif
549     line->m_magic = type_id;
550   }
551 
552 #ifdef UNIT_TEST
553   releasednodes++;
554 #endif
555 
556   return true;
557 }
558 
559 Uint32
seize()560 DynArr256Pool::seize()
561 {
562   Uint32 ff = m_first_free;
563   Uint32 type_id = m_type_id;
564 
565   DA256Page* page;
566   DA256Page * memroot = m_memroot;
567   if (ff == RNIL)
568   {
569     Uint32 page_no;
570     if (likely((page = (DA256Page*)m_ctx.alloc_page(type_id, &page_no)) != 0))
571     {
572       initpage(page, page_no, type_id);
573 #ifdef UNIT_TEST
574       allocatedpages++;
575 #endif
576     }
577     else
578     {
579       return RNIL;
580     }
581     ff = (page_no << DA256_BITS);
582   }
583   else
584   {
585     page = memroot + (ff >> DA256_BITS);
586   }
587 
588   Uint32 idx = ff & DA256_MASK;
589   DA256Free * ptr = (DA256Free*)(page->m_nodes + idx);
590   if (likely(ptr->m_magic == type_id))
591   {
592     Uint32 next = ptr->m_next_free;
593     if (likely(seizenode(page, idx, type_id)))
594     {
595       m_first_free = next;
596       return ff;
597     }
598   }
599 
600 //error:
601   require(false);
602   return 0;
603 }
604 
605 void
release(Uint32 ptrI)606 DynArr256Pool::release(Uint32 ptrI)
607 {
608   Uint32 ff = m_first_free;
609   Uint32 type_id = m_type_id;
610 
611   Uint32 page_no = ptrI >> DA256_BITS;
612   Uint32 page_idx = ptrI & DA256_MASK;
613   DA256Page * memroot = m_memroot;
614   DA256Page * page = memroot + page_no;
615 
616   DA256Free * ptr = (DA256Free*)(page->m_nodes + page_idx);
617   if (likely(releasenode(page, page_idx, type_id)))
618   {
619     ptr->m_next_free = ff;
620     ptr->m_magic = type_id;
621     m_first_free = ptrI;
622     return;
623   }
624   require(false);
625 }
626 
627 #ifdef UNIT_TEST
628 
629 #include <NdbTick.h>
630 #include "ndbd_malloc_impl.hpp"
631 #include "SimulatedBlock.hpp"
632 
633 Ndbd_mem_manager mm;
634 Configuration cfg;
635 Block_context ctx(cfg, mm);
636 struct BB : public SimulatedBlock
637 {
BBBB638   BB(int no, Block_context& ctx) : SimulatedBlock(no, ctx) {}
639 };
640 
641 BB block(DBACC, ctx);
642 
643 static
644 void
simple(DynArr256 & arr,int argc,char * argv[])645 simple(DynArr256 & arr, int argc, char* argv[])
646 {
647   ndbout_c("argc: %d", argc);
648   for (Uint32 i = 1; i<(Uint32)argc; i++)
649   {
650     Uint32 * s = arr.set(atoi(argv[i]));
651     {
652       bool found = false;
653       for (Uint32 j = 1; j<i; j++)
654       {
655 	if (atoi(argv[i]) == atoi(argv[j]))
656 	{
657 	  found = true;
658 	  break;
659 	}
660       }
661       if (!found)
662 	* s = i;
663     }
664 
665     Uint32 * g = arr.get(atoi(argv[i]));
666     Uint32 v = g ? *g : ~0;
667     ndbout_c("p: %p %p %d", s, g, v);
668   }
669 }
670 
671 static
672 void
basic(DynArr256 & arr,int argc,char * argv[])673 basic(DynArr256& arr, int argc, char* argv[])
674 {
675 #define MAXLEN 65536
676 
677   Uint32 len = 0;
678   Uint32 save[2*MAXLEN];
679   for (Uint32 i = 0; i<MAXLEN; i++)
680   {
681     int op = (rand() % 100) > 50;
682     if (len == 0)
683       op = 1;
684     if (len == MAXLEN)
685       op = 0;
686     switch(op){
687     case 0:{ // get
688       Uint32 item = (rand() % len) << 1;
689       Uint32 idx = save[item];
690       Uint32 val = save[item+1];
691       //ndbout_c("get(%d)", idx);
692       Uint32 *p = arr.get(idx);
693       assert(p);
694       assert(* p == val);
695       break;
696     }
697     case 1:{ // set
698       Uint32 item = len << 1;
699       Uint32 idx = i; //rand() & 0xFFFFF; // & 0xFFFFF; //rand(); //(65536*i) / 10000;
700       Uint32 val = rand();
701 #if 0
702       for(Uint32 j = 0; j < item; j += 2)
703       {
704 	if (save[j] == idx)
705 	{
706 	  item = j;
707 	  break;
708 	}
709       }
710 #endif
711       //ndbout_c("set(%d, %x)", idx, val);
712       Uint32 *p = arr.set(idx);
713       assert(* p);
714       if (item == (len << 1))
715       {
716 	*p = val;
717 	len++;
718       }
719       else
720       {
721 	assert(* p == save[item+1]);
722 	* p = val;
723       }
724       save[item] = idx;
725       save[item+1] = val;
726     }
727     }
728   }
729 }
730 
731 unsigned long long
micro()732 micro()
733 {
734   struct timeval tv;
735   gettimeofday(&tv, 0);
736   unsigned long long ret = tv.tv_sec;
737   ret *= 1000000;
738   ret += tv.tv_usec;
739   return ret;
740 }
741 
742 static
743 void
read(DynArr256 & arr,int argc,char ** argv)744 read(DynArr256& arr, int argc, char ** argv)
745 {
746   Uint32 cnt = 100000;
747   Uint64 mbytes = 16*1024;
748   Uint32 seed = time(0);
749   Uint32 seq = 0, seqmask = 0;
750 
751   for (Uint32 i = 2; i<argc; i++)
752   {
753     if (strncmp(argv[i], "--mbytes=", sizeof("--mbytes=")-1) == 0)
754     {
755       mbytes = atoi(argv[i]+sizeof("--mbytes=")-1);
756       if (argv[i][strlen(argv[i])-1] == 'g' ||
757 	  argv[i][strlen(argv[i])-1] == 'G')
758 	mbytes *= 1024;
759     }
760     else if (strncmp(argv[i], "--cnt=", sizeof("--cnt=")-1) == 0)
761     {
762       cnt = atoi(argv[i]+sizeof("--cnt=")-1);
763     }
764     else if (strncmp(argv[i], "--seq", sizeof("--seq")-1) == 0)
765     {
766       seq = 1;
767     }
768   }
769 
770   /**
771    * Populate with 5Mb
772    */
773   Uint32 maxidx = (1024*mbytes+31) / 32;
774   Uint32 nodes = (maxidx+255) / 256;
775   Uint32 pages = (nodes + 29)/ 30;
776   ndbout_c("%lldmb data -> %d entries (%dkb)",
777 	   mbytes, maxidx, 32*pages);
778 
779   for (Uint32 i = 0; i<maxidx; i++)
780   {
781     Uint32 *ptr = arr.set(i);
782     assert(ptr);
783     * ptr = i;
784   }
785 
786   srand(seed);
787 
788   if (seq)
789   {
790     seq = rand();
791     seqmask = ~(Uint32)0;
792   }
793 
794   ndbout_c("Timing %d %s reads (seed: %u)", cnt,
795 	   seq ? "sequential" : "random", seed);
796 
797   for (Uint32 i = 0; i<10; i++)
798   {
799     Uint32 sum0 = 0, sum1 = 0;
800     Uint64 start = micro();
801     for (Uint32 i = 0; i<cnt; i++)
802     {
803       Uint32 idx = ((rand() & (~seqmask)) + ((i + seq) & seqmask)) % maxidx;
804       Uint32 *ptr = arr.get(idx);
805       sum0 += idx;
806       sum1 += *ptr;
807     }
808     start = micro() - start;
809     float uspg = start; uspg /= cnt;
810     ndbout_c("Elapsed %lldus diff: %d -> %f us/get", start, sum0 - sum1, uspg);
811   }
812 }
813 
814 static
815 void
write(DynArr256 & arr,int argc,char ** argv)816 write(DynArr256& arr, int argc, char ** argv)
817 {
818   Uint32 seq = 0, seqmask = 0;
819   Uint32 cnt = 100000;
820   Uint64 mbytes = 16*1024;
821   Uint32 seed = time(0);
822 
823   for (Uint32 i = 2; i<argc; i++)
824   {
825     if (strncmp(argv[i], "--mbytes=", sizeof("--mbytes=")-1) == 0)
826     {
827       mbytes = atoi(argv[i]+sizeof("--mbytes=")-1);
828       if (argv[i][strlen(argv[i])-1] == 'g' ||
829 	  argv[i][strlen(argv[i])-1] == 'G')
830 	mbytes *= 1024;
831     }
832     else if (strncmp(argv[i], "--cnt=", sizeof("--cnt=")-1) == 0)
833     {
834       cnt = atoi(argv[i]+sizeof("--cnt=")-1);
835     }
836     else if (strncmp(argv[i], "--seq", sizeof("--seq")-1) == 0)
837     {
838       seq = 1;
839     }
840   }
841 
842   /**
843    * Populate with 5Mb
844    */
845   Uint32 maxidx = (1024*mbytes+31) / 32;
846   Uint32 nodes = (maxidx+255) / 256;
847   Uint32 pages = (nodes + 29)/ 30;
848   ndbout_c("%lldmb data -> %d entries (%dkb)",
849 	   mbytes, maxidx, 32*pages);
850 
851   srand(seed);
852 
853   if (seq)
854   {
855     seq = rand();
856     seqmask = ~(Uint32)0;
857   }
858 
859   ndbout_c("Timing %d %s writes (seed: %u)", cnt,
860 	   seq ? "sequential" : "random", seed);
861   for (Uint32 i = 0; i<10; i++)
862   {
863     Uint64 start = micro();
864     for (Uint32 i = 0; i<cnt; i++)
865     {
866       Uint32 idx = ((rand() & (~seqmask)) + ((i + seq) & seqmask)) % maxidx;
867       Uint32 *ptr = arr.set(idx);
868       *ptr = i;
869     }
870     start = micro() - start;
871     float uspg = start; uspg /= cnt;
872     ndbout_c("Elapsed %lldus -> %f us/set", start, uspg);
873     DynArr256::ReleaseIterator iter;
874     arr.init(iter);
875     Uint32 val;
876     while(arr.release(iter, &val));
877   }
878 }
879 
880 int
main(int argc,char ** argv)881 main(int argc, char** argv)
882 {
883   if (0)
884   {
885     for (Uint32 i = 0; i<30; i++)
886     {
887       Uint32 b = (i + 1) >> 4;
888       Uint32 p = i - (b << 4) + b;
889       printf("[ %d %d %d ]\n", i, b, p);
890     }
891     return 0;
892   }
893 
894   Pool_context pc;
895   pc.m_block = &block;
896 
897   Resource_limit rl;
898   rl.m_min = 0;
899   rl.m_max = 10000;
900   rl.m_resource_id = 0;
901   mm.set_resource_limit(rl);
902   if(!mm.init())
903   {
904     abort();
905   }
906 
907   DynArr256Pool pool;
908   pool.init(0x2001, pc);
909 
910   DynArr256::Head head;
911   DynArr256 arr(pool, head);
912 
913   if (strcmp(argv[1], "--simple") == 0)
914     simple(arr, argc, argv);
915   else if (strcmp(argv[1], "--basic") == 0)
916     basic(arr, argc, argv);
917   else if (strcmp(argv[1], "--read") == 0)
918     read(arr, argc, argv);
919   else if (strcmp(argv[1], "--write") == 0)
920     write(arr, argc, argv);
921 
922   DynArr256::ReleaseIterator iter;
923   arr.init(iter);
924   Uint32 cnt = 0, val;
925   while (arr.release(iter, &val)) cnt++;
926 
927   ndbout_c("allocatedpages: %d allocatednodes: %d releasednodes: %d"
928 	   " releasecnt: %d",
929 	   allocatedpages,
930 	   allocatednodes,
931 	   releasednodes,
932 	   cnt);
933 
934   return 0;
935 #if 0
936   printf("sizeof(DA256Page): %d\n", sizeof(DA256Page));
937 
938   DA256Page page;
939 
940   for (Uint32 i = 0; i<10000; i++)
941   {
942     Uint32 arg = rand() & 255;
943     Uint32 base = 0;
944     Uint32 idx = arg & 256;
945     printf("%d\n", arg);
946 
947     assert(base <= 30);
948 
949     if (idx == 255)
950     {
951       Uint32 b = (base + 1) >> 4;
952       Uint32 p = base - (b << 4) + b;
953       Uint32 magic = page.m_header[b].m_magic;
954       Uint32 retVal = page.m_header[b].m_data[p];
955 
956       require(magic & (1 << p));
957       return retVal;
958     }
959     else
960     {
961       // 4 bit extra offset per idx
962       Uint32 line = idx / 15;
963       Uint32 off = idx % 15;
964 
965       {
966 	Uint32 pos = 1 + idx + line;
967 	Uint32 magic = pos & ~15;
968 
969 	Uint32 * ptr = (Uint32*)&page.m_nodes[base];
970 	assert((ptr + pos) == &page.m_nodes[base].m_lines[line].m_data[off]);
971 	assert((ptr + magic) == &page.m_nodes[base].m_lines[line].m_magic);
972       }
973     }
974   }
975 #endif
976 }
977 
978 Uint32 g_currentStartPhase;
979 Uint32 g_start_type;
980 NdbNodeBitmask g_nowait_nodes;
981 
childExit(int code,Uint32 currentStartPhase)982 void childExit(int code, Uint32 currentStartPhase)
983 {
984   abort();
985 }
986 
childAbort(int code,Uint32 currentStartPhase)987 void childAbort(int code, Uint32 currentStartPhase)
988 {
989   abort();
990 }
991 
childReportError(int error)992 void childReportError(int error)
993 {
994   abort();
995 }
996 
997 void
sendCmAppChg(Ndbcntr & cntr,Signal * signal,Uint32 startLevel)998 UpgradeStartup::sendCmAppChg(Ndbcntr& cntr, Signal* signal, Uint32 startLevel){
999 }
1000 
1001 void
execCM_APPCHG(SimulatedBlock & block,Signal * signal)1002 UpgradeStartup::execCM_APPCHG(SimulatedBlock & block, Signal* signal){
1003 }
1004 
1005 void
sendCntrMasterReq(Ndbcntr & cntr,Signal * signal,Uint32 n)1006 UpgradeStartup::sendCntrMasterReq(Ndbcntr& cntr, Signal* signal, Uint32 n){
1007 }
1008 
1009 void
execCNTR_MASTER_REPLY(SimulatedBlock & block,Signal * signal)1010 UpgradeStartup::execCNTR_MASTER_REPLY(SimulatedBlock & block, Signal* signal){
1011 }
1012 
1013 #include <SimBlockList.hpp>
1014 
1015 void
unload()1016 SimBlockList::unload()
1017 {
1018 
1019 }
1020 
1021 #endif
1022