1 /*
2    Copyright (c) 2006, 2021, Oracle and/or its affiliates.
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, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 
26 #include "ArrayPool.hpp"
27 #include "WOPool.hpp"
28 #include "RWPool.hpp"
29 #include <NdbTick.h>
30 #include "ndbd_malloc_impl.hpp"
31 #include "SimulatedBlock.hpp"
32 
33 #ifdef USE_CALLGRIND
34 #include <valgrind/callgrind.h>
35 #else
36 #define CALLGRIND_TOGGLE_COLLECT()
37 #endif
38 
39 #define T_TEST_AP   (1 << 0)
40 #define T_TEST_WO   (1 << 1)
41 #define T_TEST_RW   (1 << 2)
42 
43 #define T_SEIZE       (1 << 0)
44 #define T_RELEASE     (1 << 1)
45 #define T_G_RELEASE   (1 << 2)
46 #define T_R_RELEASE   (1 << 3)
47 #define T_R_G_RELEASE (1 << 4)
48 #define T_MIX         (1 << 5)
49 #define T_GETPTR      (1 << 6)
50 #define T_FIFO        (1 << 7)
51 
52 const char *test_names[] = {
53   "seize",
54   "release",
55   "get+rel",
56   "r-rel",
57   "r-get+rel",
58   "mix",
59   "getptr",
60   "fifo",
61   0
62 };
63 
64 Uint32 pools = ~0;
65 Uint32 tests = ~0;
66 Uint32 records = ~0;
67 Uint32 sizes = 7;
68 unsigned int seed;
69 Ndbd_mem_manager mm;
70 Configuration cfg;
71 Block_context ctx(cfg, mm);
72 struct BB : public SimulatedBlock
73 {
BBBB74   BB(int no, Block_context& ctx) : SimulatedBlock(no, ctx) {}
75 };
76 
77 BB block(DBACC, ctx);
78 
79 template <typename T>
80 void
init(ArrayPool<T> & pool,Uint32 cnt)81 init(ArrayPool<T> & pool, Uint32 cnt)
82 {
83   pool.setSize(cnt + 1, true);
84 }
85 
86 template <typename T>
87 void
init(RecordPool<T,WOPool> & pool,Uint32 cnt)88 init(RecordPool<T, WOPool> & pool, Uint32 cnt)
89 {
90   Pool_context pc;
91   pc.m_block = &block;
92   pool.wo_pool_init(0x2001, pc);
93 }
94 
95 template <typename T>
96 void
init(RecordPool<T,RWPool> & pool,Uint32 cnt)97 init(RecordPool<T, RWPool> & pool, Uint32 cnt)
98 {
99   Pool_context pc;
100   pc.m_block = &block;
101   pool.init(0x2001, pc);
102 }
103 
104 template <typename T, typename R>
105 void
test_pool(R & pool,Uint32 cnt,Uint32 loops)106 test_pool(R& pool, Uint32 cnt, Uint32 loops)
107 {
108   Ptr<T> ptr;
109   Uint32 *arr = (Uint32*)alloca(cnt * sizeof(Uint32));
110   memset(arr, 0, cnt * sizeof(Uint32));
111   if (tests & T_SEIZE)
112   {
113     Uint64 sum = 0;
114     for(Uint32 i = 0; i<loops; i++)
115     { // seize
116       Uint64 start = NdbTick_CurrentMillisecond();
117       CALLGRIND_TOGGLE_COLLECT();
118       for(Uint32 j = 0; j<cnt; j++)
119       {
120 	bool b = pool.seize(ptr);
121 	arr[j] = ptr.i;
122 	ptr.p->do_stuff();
123 	assert(b);
124       }
125       CALLGRIND_TOGGLE_COLLECT();
126       Uint64 stop = NdbTick_CurrentMillisecond();
127 
128       for(Uint32 j = 0; j<cnt; j++)
129       {
130 	ptr.i = arr[j];
131 	pool.getPtr(ptr);
132 	ptr.p->do_stuff();
133 	pool.release(ptr.i);
134 	arr[j] = RNIL;
135       }
136       sum += (stop - start);
137     }
138     printf(" ; %lld", sum); fflush(stdout);
139   }
140 
141   if (tests & T_RELEASE)
142   { // release
143     Uint64 sum = 0;
144     for(Uint32 i = 0; i<loops; i++)
145     {
146       for(Uint32 j = 0; j<cnt; j++)
147       {
148 	bool b = pool.seize(ptr);
149 	arr[j] = ptr.i;
150 	ptr.p->do_stuff();
151       }
152 
153       Uint64 start = NdbTick_CurrentMillisecond();
154       CALLGRIND_TOGGLE_COLLECT();
155       for(Uint32 j = 0; j<cnt; j++)
156       {
157 	pool.release(arr[j]);
158 	arr[j] = RNIL;
159       }
160       CALLGRIND_TOGGLE_COLLECT();
161       Uint64 stop = NdbTick_CurrentMillisecond();
162 
163       sum += (stop - start);
164     }
165     printf(" ; %lld", sum); fflush(stdout);
166   }
167 
168   if (tests & T_G_RELEASE)
169   { // getptr + release
170     Uint64 sum = 0;
171     for(Uint32 i = 0; i<loops; i++)
172     {
173       for(Uint32 j = 0; j<cnt; j++)
174       {
175 	bool b = pool.seize(ptr);
176 	arr[j] = ptr.i;
177 	ptr.p->do_stuff();
178       }
179 
180       Uint64 start = NdbTick_CurrentMillisecond();
181       CALLGRIND_TOGGLE_COLLECT();
182       for(Uint32 j = 0; j<cnt; j++)
183       {
184 	pool.getPtr(ptr, arr[j]);
185 	ptr.p->do_stuff();
186 	pool.release(ptr);
187 	arr[j] = RNIL;
188       }
189       CALLGRIND_TOGGLE_COLLECT();
190       Uint64 stop = NdbTick_CurrentMillisecond();
191 
192       sum += (stop - start);
193     }
194     printf(" ; %lld", sum); fflush(stdout);
195   }
196 
197   if (tests & T_R_RELEASE)
198   { // release reverse
199     Uint64 sum = 0;
200     for(Uint32 i = 0; i<loops; i++)
201     {
202       for(Uint32 j = 0; j<cnt; j++)
203       {
204 	bool b = pool.seize(ptr);
205 	arr[j] = ptr.i;
206 	ptr.p->do_stuff();
207       }
208 
209       Uint64 start = NdbTick_CurrentMillisecond();
210       CALLGRIND_TOGGLE_COLLECT();
211       for(Uint32 j = 0; j<cnt; j++)
212       {
213 	pool.release(arr[cnt - j - 1]);
214 	arr[cnt - j - 1] = RNIL;
215       }
216       CALLGRIND_TOGGLE_COLLECT();
217       Uint64 stop = NdbTick_CurrentMillisecond();
218 
219       sum += (stop - start);
220     }
221     printf(" ; %lld", sum); fflush(stdout);
222   }
223 
224   if (tests & T_R_G_RELEASE)
225   { // getptr + release
226     Uint64 sum = 0;
227     for(Uint32 i = 0; i<loops; i++)
228     {
229       for(Uint32 j = 0; j<cnt; j++)
230       {
231 	bool b = pool.seize(ptr);
232 	arr[j] = ptr.i;
233 	ptr.p->do_stuff();
234       }
235 
236       Uint64 start = NdbTick_CurrentMillisecond();
237       CALLGRIND_TOGGLE_COLLECT();
238       for(Uint32 j = 0; j<cnt; j++)
239       {
240 	pool.getPtr(ptr, arr[cnt - j - 1]);
241 	ptr.p->do_stuff();
242 	pool.release(ptr);
243 	arr[cnt - j - 1] = RNIL;
244       }
245       CALLGRIND_TOGGLE_COLLECT();
246       Uint64 stop = NdbTick_CurrentMillisecond();
247 
248       sum += (stop - start);
249     }
250     printf(" ; %lld", sum); fflush(stdout);
251   }
252 
253   if (tests & T_MIX)
254   {
255     Uint64 sum = 0;
256     Uint64 start = NdbTick_CurrentMillisecond();
257     Uint32 lseed = seed;
258     CALLGRIND_TOGGLE_COLLECT();
259     for(Uint32 i = 0; i<loops * cnt; i++)
260     {
261       int pos = rand_r(&lseed) % cnt;
262       ptr.i = arr[pos];
263       if (ptr.i == RNIL)
264       {
265 	pool.seize(ptr);
266 	arr[pos] = ptr.i;
267 	assert(ptr.i != RNIL);
268 	ptr.p->do_stuff();
269       }
270       else
271       {
272 	pool.getPtr(ptr);
273 	ptr.p->do_stuff();
274 	pool.release(ptr);
275 	arr[pos] = RNIL;
276       }
277     }
278     CALLGRIND_TOGGLE_COLLECT();
279     Uint64 stop = NdbTick_CurrentMillisecond();
280 
281     for(Uint32 j = 0; j<cnt; j++)
282     {
283       ptr.i = arr[j];
284       if (ptr.i != RNIL)
285       {
286 	pool.getPtr(ptr);
287 	pool.release(ptr.i);
288       }
289       arr[j] = RNIL;
290     }
291 
292     sum += (stop - start);
293     printf(" ; %lld", sum); fflush(stdout);
294   }
295 
296   if (tests & T_GETPTR)
297   {
298     Uint32 lseed = seed;
299     for(Uint32 j = 0; j<cnt; j++)
300     {
301       bool b = pool.seize(ptr);
302       arr[j] = ptr.i;
303       ptr.p->do_stuff();
304       assert(b);
305     }
306 
307     Uint64 sum = 0;
308     Uint64 start = NdbTick_CurrentMillisecond();
309     CALLGRIND_TOGGLE_COLLECT();
310     for(Uint32 i = 0; i<loops * cnt; i++)
311     {
312       int pos = rand_r(&lseed) % cnt;
313       ptr.i = arr[pos];
314       pool.getPtr(ptr);
315       ptr.p->do_stuff();
316     }
317     CALLGRIND_TOGGLE_COLLECT();
318     Uint64 stop = NdbTick_CurrentMillisecond();
319 
320     for(Uint32 j = 0; j<cnt; j++)
321     {
322       ptr.i = arr[j];
323       pool.getPtr(ptr);
324       ptr.p->do_stuff();
325       pool.release(ptr.i);
326       arr[j] = RNIL;
327     }
328 
329     sum += (stop - start);
330     printf(" ; %lld", sum); fflush(stdout);
331   }
332 
333   if (tests & T_FIFO)
334   { // fifo
335     Uint64 sum = 0;
336     Uint64 start = NdbTick_CurrentMillisecond();
337     CALLGRIND_TOGGLE_COLLECT();
338     for(Uint32 i = 0; i<loops; i++)
339     {
340       Uint32 head = RNIL;
341       Uint32 last = RNIL;
342 
343       Uint64 sum = 0;
344       for(Uint32 j = 0; j<cnt; j++)
345       {
346 	pool.seize(ptr);
347 	ptr.p->do_stuff();
348 	ptr.p->m_nextList = RNIL;
349 	if (head == RNIL)
350 	{
351 	  head = ptr.i;
352 	}
353 	else
354 	{
355 	  T* t = pool.getPtr(last);
356 	  t->m_nextList = ptr.i;
357 	}
358 	last = ptr.i;
359       }
360 
361       while (head != RNIL)
362       {
363 	pool.getPtr(ptr, head);
364 	ptr.p->do_stuff();
365 	head = ptr.p->m_nextList;
366 	pool.release(ptr);
367       }
368     }
369     CALLGRIND_TOGGLE_COLLECT();
370     Uint64 stop = NdbTick_CurrentMillisecond();
371     sum += (stop - start);
372     printf(" ; %lld", sum); fflush(stdout);
373   }
374 
375   ndbout_c("");
376 }
377 
378 template <Uint32 sz>
379 struct Rec {
380   Uint32 m_data;
381   Uint32 m_magic;
382   Uint32 nextPool;
383   Uint32 m_nextList;
384   char m_cdata[sz-16];
385 
do_stuffRec386   void do_stuff() {
387     Uint32 sum = 0;
388     Uint32 *ptr = (Uint32*)this;
389     for(Uint32 i = 0; i<(sz >> 2); i++)
390       sum += * ptr ++;
391     m_data = sum;
392   }
393 };
394 
395 typedef Rec<32> Rec32;
396 typedef Rec<36> Rec36;
397 typedef Rec<56> Rec56;
398 typedef Rec<224> Rec224;
399 
400 template <typename T>
test_ap(Uint32 cnt,Uint32 loop)401 void test_ap(Uint32 cnt, Uint32 loop)
402 {
403   printf("AP ; %d ; %d", sizeof(T), (cnt * sizeof(T))>>10); fflush(stdout);
404   ArrayPool<T> pool;
405   init(pool, cnt);
406   test_pool<T, ArrayPool<T> >(pool, cnt, loop);
407 }
408 
409 template <typename T>
test_rw(Uint32 cnt,Uint32 loop)410 void test_rw(Uint32 cnt, Uint32 loop)
411 {
412   printf("RW ; %d ; %d", sizeof(T), (cnt * sizeof(T))>>10); fflush(stdout);
413   RecordPool<T, RWPool> pool;
414   init(pool, cnt);
415   test_pool<T, RecordPool<T, RWPool> >(pool, cnt, loop);
416 }
417 
418 template <typename T>
test_wo(Uint32 cnt,Uint32 loop)419 void test_wo(Uint32 cnt, Uint32 loop)
420 {
421   printf("WO ; %d ; %d", sizeof(T), (cnt * sizeof(T))>>10); fflush(stdout);
422   RecordPool<T, WOPool> pool;
423   init(pool, cnt);
424   test_pool<T, RecordPool<T, WOPool> >(pool, cnt, loop);
425 }
426 
427 #include <EventLogger.hpp>
428 extern EventLogger * g_eventLogger;
429 
430 int
main(int argc,char ** argv)431 main(int argc, char **argv)
432 {
433   Uint32 loops = 300000;
434   for (Uint32 i = 1 ; i<argc ; i++)
435   {
436     if (argc > i+1 && strcmp(argv[i], "-pools") == 0)
437     {
438       pools = 0;
439       for (Uint32 j = 0; j<strlen(argv[i+1]); j++)
440       {
441 	char c = argv[i+1][j];
442 	if (c >= '0' && c <= '9')
443 	  pools |= 1 << (c - '0');
444 	else
445 	  pools |= 1 << (10 + (c - 'a'));
446       }
447     }
448     else if (argc > i+1 && strcmp(argv[i], "-tests") == 0)
449     {
450       tests = 0;
451       for (Uint32 j = 0; j<strlen(argv[i+1]); j++)
452       {
453 	char c = argv[i+1][j];
454 	if (c >= '0' && c <= '9')
455 	  tests |= 1 << (c - '0');
456 	else
457 	  tests |= 1 << (10 + (c - 'a'));
458       }
459     }
460     else if (argc > i+1 && strcmp(argv[i], "-sizes") == 0)
461     {
462       sizes = 0;
463       for (Uint32 j = 0; j<strlen(argv[i+1]); j++)
464       {
465 	char c = argv[i+1][j];
466 	if (c >= '0' && c <= '9')
467 	  sizes |= 1 << (c - '0');
468 	else
469 	  sizes |= 1 << (10 + (c - 'a'));
470       }
471     }
472     else if (argc > i+1 && strcmp(argv[i], "-records") == 0)
473     {
474       records = 0;
475       for (Uint32 j = 0; j<strlen(argv[i+1]); j++)
476       {
477 	char c = argv[i+1][j];
478 	if (c >= '0' && c <= '9')
479 	  records |= 1 << (c - '0');
480 	else
481 	  records |= 1 << (10 + (c - 'a'));
482       }
483     }
484     else if (argc > i+1 && strcmp(argv[i], "-loop") == 0)
485     {
486       loops = atoi(argv[i+1]);
487     }
488   }
489 
490   Resource_limit rl;
491   rl.m_min = 0;
492   rl.m_max = 10000;
493   rl.m_resource_id = 0;
494   mm.set_resource_limit(rl);
495   if(!mm.init())
496   {
497     abort();
498   }
499 
500   seed = time(0);
501   Uint32 sz = 0;
502   Uint32 cnt = 256;
503 
504   printf("pool ; rs ; ws");
505   for (Uint32 i = 0; test_names[i] && i<31; i++)
506     if (tests & (1 << i))
507       printf(" ; %s", test_names[i]);
508   ndbout_c("");
509 
510   while(cnt <= 1000000)
511   {
512     Uint32 loop = 768 * loops / cnt;
513     if (sizes & (1 << sz))
514     {
515       if (records & 1)
516       {
517 	if (pools & T_TEST_AP)
518 	  test_ap<Rec32>(cnt, loop);
519 	if (pools & T_TEST_WO)
520 	  test_wo<Rec32>(cnt, loop);
521 	if (pools & T_TEST_RW)
522 	  test_rw<Rec32>(cnt, loop);
523       }
524       if (records & 2)
525       {
526 	if (pools & T_TEST_AP)
527 	  test_ap<Rec36>(cnt, loop);
528 	if (pools & T_TEST_WO)
529 	  test_wo<Rec36>(cnt, loop);
530 	if (pools & T_TEST_RW)
531 	  test_rw<Rec36>(cnt, loop);
532       }
533       if (records & 4)
534       {
535 	if (pools & T_TEST_AP)
536 	  test_ap<Rec56>(cnt, loop);
537 	if (pools & T_TEST_WO)
538 	  test_wo<Rec56>(cnt, loop);
539 	if (pools & T_TEST_RW)
540 	  test_rw<Rec56>(cnt, loop);
541       }
542       if (records & 8)
543       {
544 	if (pools & T_TEST_AP)
545 	  test_ap<Rec224>(cnt, loop);
546 	if (pools & T_TEST_WO)
547 	  test_wo<Rec224>(cnt, loop);
548 	if (pools & T_TEST_RW)
549 	  test_rw<Rec224>(cnt, loop);
550       }
551     }
552 
553     cnt += (512 << sz);
554     sz++;
555   }
556 }
557 
558 Uint32 g_currentStartPhase;
559 Uint32 g_start_type;
560 NdbNodeBitmask g_nowait_nodes;
561 
562 void
sendCmAppChg(Ndbcntr & cntr,Signal * signal,Uint32 startLevel)563 UpgradeStartup::sendCmAppChg(Ndbcntr& cntr, Signal* signal, Uint32 startLevel){
564 }
565 
566 void
execCM_APPCHG(SimulatedBlock & block,Signal * signal)567 UpgradeStartup::execCM_APPCHG(SimulatedBlock & block, Signal* signal){
568 }
569 
570 void
sendCntrMasterReq(Ndbcntr & cntr,Signal * signal,Uint32 n)571 UpgradeStartup::sendCntrMasterReq(Ndbcntr& cntr, Signal* signal, Uint32 n){
572 }
573 
574 void
execCNTR_MASTER_REPLY(SimulatedBlock & block,Signal * signal)575 UpgradeStartup::execCNTR_MASTER_REPLY(SimulatedBlock & block, Signal* signal){
576 }
577 
578 #include <SimBlockList.hpp>
579 
580 #define JAM_FILE_ID 267
581 
582 
583 void
unload()584 SimBlockList::unload()
585 {
586 
587 }
588 
589 #define INSTANCE(X) \
590 template void test_ap<X>(unsigned, unsigned);\
591 template void test_wo<X>(unsigned, unsigned);\
592 template void test_rw<X>(unsigned, unsigned);\
593 template void test_pool<X, ArrayPool<X> >(ArrayPool<X>&, unsigned, unsigned);\
594 template void test_pool<X, RecordPool<X, RWPool> >(RecordPool<X, RWPool>&, unsigned, unsigned); \
595 template void test_pool<X, RecordPool<X, WOPool> >(RecordPool<X, WOPool>&, unsigned, unsigned);\
596 template void init<X>(ArrayPool<X>&, unsigned);\
597 template void init<X>(RecordPool<X, RWPool>&, unsigned);\
598 template void init<X>(RecordPool<X, WOPool>&, unsigned)
599 
600 INSTANCE(Rec32);
601 INSTANCE(Rec36);
602 INSTANCE(Rec56);
603 INSTANCE(Rec224);
604 
605