1 /* Copyright (C) 2014 InfiniDB, Inc.
2 
3    This program is free software; you can redistribute it and/or
4    modify it under the terms of the GNU General Public License
5    as published by the Free Software Foundation; version 2 of
6    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,
16    MA 02110-1301, USA. */
17 
18 // $Id: tdriver-filter.cpp 9210 2013-01-21 14:10:42Z rdempsey $
19 
20 #include <list>
21 #include <sstream>
22 #include <pthread.h>
23 #include <iomanip>
24 #include <cppunit/extensions/HelperMacros.h>
25 #include <cppunit/extensions/TestFactoryRegistry.h>
26 #include <cppunit/ui/text/TestRunner.h>
27 
28 #include "fifo.h"
29 #include "constantdatalist.h"
30 
31 #include "calpontsystemcatalog.h"
32 using namespace joblist;
33 
34 #include "filteroperation.h"
35 
36 
37 #include <boost/any.hpp>
38 #include <boost/function.hpp>
39 #include "bytestream.h"
40 #include <time.h>
41 #include <sys/time.h>
42 
43 #define DEBUG
44 
45 using namespace std;
46 using namespace joblist;
47 using namespace messageqcpp;
48 
49 // Timer class used by this tdriver to output elapsed times, etc.
50 class Timer
51 {
52 public:
start(const string & message)53     void start(const string& message)
54     {
55         if (!fHeaderDisplayed)
56         {
57             header();
58             fHeaderDisplayed = true;
59         }
60 
61         gettimeofday(&fTvStart, 0);
62         cout << timestr() << "          Start " << message << endl;
63     }
64 
stop(const string & message)65     void stop(const string& message)
66     {
67         time_t now;
68         time(&now);
69         string secondsElapsed;
70         getTimeElapsed(secondsElapsed);
71         cout << timestr() << " " << secondsElapsed << " Stop  " << message << endl;
72     }
73 
Timer()74     Timer() : fHeaderDisplayed(false) {}
75 
76 private:
77 
78     struct timeval fTvStart;
79     bool fHeaderDisplayed;
80 
getTimeElapsed(string & seconds)81     double getTimeElapsed(string& seconds)
82     {
83         struct timeval tvStop;
84         gettimeofday(&tvStop, 0);
85         double secondsElapsed =
86             (tvStop.tv_sec + (tvStop.tv_usec / 1000000.0)) -
87             (fTvStart.tv_sec + (fTvStart.tv_usec / 1000000.0));
88         ostringstream oss;
89         oss << secondsElapsed;
90         seconds = oss.str();
91         seconds.resize(8, '0');
92         return secondsElapsed;
93     }
94 
timestr()95     string timestr()
96     {
97         struct tm tm;
98         struct timeval tv;
99 
100         gettimeofday(&tv, 0);
101         localtime_r(&tv.tv_sec, &tm);
102 
103         ostringstream oss;
104         oss << setfill('0')
105             << setw(2) << tm.tm_hour << ':'
106             << setw(2) << tm.tm_min << ':'
107             << setw(2) << tm.tm_sec	<< '.'
108             << setw(6) << tv.tv_usec
109             ;
110         return oss.str();
111     }
112 
header()113     void header()
114     {
115         cout << endl;
116         cout << "Time            Seconds  Activity" << endl;
117     }
118 };
119 
120 class FilterDriver : public CppUnit::TestFixture
121 {
122 
123     CPPUNIT_TEST_SUITE(FilterDriver);
124 
125     CPPUNIT_TEST(DOUBLE_TIME_TEST);
126 
127     CPPUNIT_TEST_SUITE_END();
128 
129 private:
130     // Creates two fifos with numRows and performs the passed comparison against their values.
131     // The first fifo will contain values 0..numRows-1.
132     // The second fifo will contain values numrows-1..0.
133     // Both bands will containt the same rids.
134     // Outputs timing results for loading each fifo, doing the comparison, and iterating over the results.
135     // Outputs the number of qualifying rows.
136     // Asserts that the number of qualifying rows is correct.
filterTest(const FilterOperation::FilterOperator & fo,const int & numRows)137     void filterTest(const FilterOperation::FilterOperator& fo, const int& numRows)
138     {
139         Timer timer;
140         cout << endl;
141         cout << "------------------------------------------------------------" << endl;
142         int i;
143         ElementType element;
144 
145         stringstream ss;
146         ss << "loading first fifo with " << numRows << " rows.";
147         string message = ss.str();
148         timer.start(message);
149         FIFO<ElementType> fifo1(1, numRows);
150 
151         for (i = 0; i < numRows; i++)
152         {
153             element.first = i;
154             element.second = i;
155             fifo1.insert(element);
156         }
157 
158         fifo1.endOfInput();
159         timer.stop(message);
160 
161         stringstream ss2;
162         ss2.flush();
163         ss2 << "loading second fifo with " << numRows << " rows.";
164         message = ss2.str();
165         timer.start(message);
166 
167         FIFO<ElementType> fifo2(1, numRows);
168 
169         for (i = 0; i < numRows; i++)
170         {
171             element.first = i;
172             element.second = numRows - (i + 1);
173             fifo2.insert(element);
174         }
175 
176         fifo2.endOfInput();
177         timer.stop(message);
178 
179         FIFO<ElementType> fifo3(1, numRows);
180 
181         DataList<ElementType>* dl1 =  (DataList<ElementType>*) &fifo1;
182         DataList<ElementType>* dl2 =  (DataList<ElementType>*) &fifo2;
183         DataList<ElementType>* dl3 =  (DataList<ElementType>*) &fifo3;
184         int assertCount;
185 
186         switch (fo)
187         {
188             case FilterOperation::GT:
189                 message = "GT Test";
190                 assertCount = numRows / 2;
191                 break;
192 
193             case FilterOperation::LT:
194                 message = "LT Test";
195                 assertCount = numRows / 2;
196                 break;
197 
198             case FilterOperation::GTE:
199                 message = "GTE Test";
200                 assertCount = (numRows / 2);
201 
202                 if (numRows % 2 > 0)
203                     assertCount++;
204 
205                 break;
206 
207             case FilterOperation::LTE:
208                 message = "LTE Test";
209                 assertCount = (numRows / 2);
210 
211                 if (numRows % 2 > 0)
212                     assertCount++;
213 
214                 break;
215 
216             case FilterOperation::EQ:
217                 message = "EQ Test";
218                 assertCount = numRows % 2;
219                 break;
220 
221             case FilterOperation::NE:
222                 message = "NE Test";
223                 assertCount = numRows - numRows % 2;
224                 break;
225 
226             default:
227                 break;
228         }
229 
230         timer.start(message);
231         FilterOperation filterOperation;
232         filterOperation.filter(fo, *dl1, *dl2, *dl3);
233         timer.stop(message);
234         fifo3.endOfInput();
235 
236         timer.start("iterating over result datalist");
237         bool more;
238         int it;
239         it = fifo3.getIterator();
240         int count = 0;
241 
242         do
243         {
244             more = fifo3.next(it, &element);
245 
246             if (more)
247             {
248                 count++;
249                 // cout << element.fRid << " " << element.fValue << endl;
250             }
251         }
252         while (more);
253 
254         timer.stop("iterating over result datalist");
255 
256         cout << count << " rows qualified." << endl;
257         idbassert(count == assertCount);
258     }
259 
260     // Creates two string fifos with numRows and performs the passed comparison against their values.
261     // The first fifo will contain values 0..numRows-1.
262     // The second fifo will contain values numrows-1..0.
263     // Both bands will containt the same rids.
264     // Outputs timing results for loading each fifo, doing the comparison, and iterating over the results.
265     // Outputs the number of qualifying rows.
266     // Asserts that the number of qualifying rows is correct.
stringFilterTest(const FilterOperation::FilterOperator & fo,const int & numRows)267     void stringFilterTest(const FilterOperation::FilterOperator& fo, const int& numRows)
268     {
269         Timer timer;
270         cout << endl;
271         cout << "------------------------------------------------------------" << endl;
272         int i;
273         StringElementType element;
274 
275         stringstream ss;
276         ss << "loading first fifo with " << numRows << " rows with StringElementType.";
277         string message = ss.str();
278         timer.start(message);
279         FIFO<StringElementType> fifo1(1, numRows);
280 
281         for (i = 0; i < numRows; i++)
282         {
283             element.first = i;
284             element.second = i;
285             fifo1.insert(element);
286         }
287 
288         fifo1.endOfInput();
289         timer.stop(message);
290 
291         stringstream ss2;
292         ss2.flush();
293         ss2 << "loading second fifo with " << numRows << " rows with StringElementType.";
294         message = ss2.str();
295         timer.start(message);
296 
297         FIFO<StringElementType> fifo2(1, numRows);
298 
299         for (i = 0; i < numRows; i++)
300         {
301             element.first = i;
302             element.second = numRows - (i + 1);
303             fifo2.insert(element);
304         }
305 
306         fifo2.endOfInput();
307         timer.stop(message);
308 
309         FIFO<StringElementType> fifo3(1, numRows);
310 
311         DataList<StringElementType>* dl1 =  (DataList<StringElementType>*) &fifo1;
312         DataList<StringElementType>* dl2 =  (DataList<StringElementType>*) &fifo2;
313         DataList<StringElementType>* dl3 =  (DataList<StringElementType>*) &fifo3;
314         int assertCount;
315 
316         switch (fo)
317         {
318             case FilterOperation::GT:
319                 message = "GT Test";
320                 assertCount = numRows / 2;
321                 break;
322 
323             case FilterOperation::LT:
324                 message = "LT Test";
325                 assertCount = numRows / 2;
326                 break;
327 
328             case FilterOperation::GTE:
329                 message = "GTE Test";
330                 assertCount = (numRows / 2);
331 
332                 if (numRows % 2 > 0)
333                     assertCount++;
334 
335                 break;
336 
337             case FilterOperation::LTE:
338                 message = "LTE Test";
339                 assertCount = (numRows / 2);
340 
341                 if (numRows % 2 > 0)
342                     assertCount++;
343 
344                 break;
345 
346             case FilterOperation::EQ:
347                 message = "EQ Test";
348                 assertCount = numRows % 2;
349                 break;
350 
351             case FilterOperation::NE:
352                 message = "NE Test";
353                 assertCount = numRows - numRows % 2;
354                 break;
355 
356             default:
357                 break;
358         }
359 
360         timer.start(message);
361         FilterOperation filterOperation;
362         filterOperation.filter(fo, *dl1, *dl2, *dl3);
363         timer.stop(message);
364         fifo3.endOfInput();
365 
366         timer.start("iterating over result datalist");
367         bool more;
368         int it;
369         it = fifo3.getIterator();
370         int count = 0;
371 
372         do
373         {
374             more = fifo3.next(it, &element);
375 
376             if (more)
377             {
378                 count++;
379                 // cout << element.fRid << " " << element.fValue << endl;
380             }
381         }
382         while (more);
383 
384         timer.stop("iterating over result datalist");
385 
386         cout << count << " rows qualified." << endl;
387         idbassert(count == assertCount);
388     }
389 
390     // Creates two double fifos with numRows and performs the passed comparison against their values.
391     // The first fifo will contain values 0..numRows-1.
392     // The second fifo will contain values numrows-1..0.
393     // Both bands will containt the same rids.
394     // Outputs timing results for loading each fifo, doing the comparison, and iterating over the results.
395     // Outputs the number of qualifying rows.
396     // Asserts that the number of qualifying rows is correct.
doubleFilterTest(const FilterOperation::FilterOperator & fo,const int & numRows)397     void doubleFilterTest(const FilterOperation::FilterOperator& fo, const int& numRows)
398     {
399         Timer timer;
400         cout << endl;
401         cout << "------------------------------------------------------------" << endl;
402         int i;
403         DoubleElementType element;
404 
405         stringstream ss;
406         ss << "loading first fifo with " << numRows << " rows of DoubleElementType.";
407         string message = ss.str();
408         timer.start(message);
409         FIFO<DoubleElementType> fifo1(1, numRows);
410 
411         for (i = 0; i < numRows; i++)
412         {
413             element.first = i;
414             element.second = i + 0.1;
415             fifo1.insert(element);
416         }
417 
418         fifo1.endOfInput();
419         timer.stop(message);
420 
421         stringstream ss2;
422         ss2.flush();
423         ss2 << "loading second fifo with " << numRows << " rows.";
424         message = ss2.str();
425         timer.start(message);
426 
427         FIFO<DoubleElementType> fifo2(1, numRows);
428 
429         for (i = 0; i < numRows; i++)
430         {
431             element.first = i;
432             element.second = numRows - (i + 1) + 0.1;
433             fifo2.insert(element);
434         }
435 
436         fifo2.endOfInput();
437         timer.stop(message);
438 
439         FIFO<DoubleElementType> fifo3(1, numRows);
440 
441         DataList<DoubleElementType>* dl1 =  (DataList<DoubleElementType>*) &fifo1;
442         DataList<DoubleElementType>* dl2 =  (DataList<DoubleElementType>*) &fifo2;
443         DataList<DoubleElementType>* dl3 =  (DataList<DoubleElementType>*) &fifo3;
444         int assertCount;
445 
446         switch (fo)
447         {
448             case FilterOperation::GT:
449                 message = "GT Test";
450                 assertCount = numRows / 2;
451                 break;
452 
453             case FilterOperation::LT:
454                 message = "LT Test";
455                 assertCount = numRows / 2;
456                 break;
457 
458             case FilterOperation::GTE:
459                 message = "GTE Test";
460                 assertCount = (numRows / 2);
461 
462                 if (numRows % 2 > 0)
463                     assertCount++;
464 
465                 break;
466 
467             case FilterOperation::LTE:
468                 message = "LTE Test";
469                 assertCount = (numRows / 2);
470 
471                 if (numRows % 2 > 0)
472                     assertCount++;
473 
474                 break;
475 
476             case FilterOperation::EQ:
477                 message = "EQ Test";
478                 assertCount = numRows % 2;
479                 break;
480 
481             case FilterOperation::NE:
482                 message = "NE Test";
483                 assertCount = numRows - numRows % 2;
484                 break;
485 
486             default:
487                 break;
488         }
489 
490         timer.start(message);
491         FilterOperation filterOperation;
492         filterOperation.filter(fo, *dl1, *dl2, *dl3);
493         timer.stop(message);
494         fifo3.endOfInput();
495 
496         timer.start("iterating over result datalist");
497         bool more;
498         int it;
499         it = fifo3.getIterator();
500         int count = 0;
501 
502         do
503         {
504             more = fifo3.next(it, &element);
505 
506             if (more)
507             {
508                 count++;
509                 // cout << element.fRid << " " << element.fValue << endl;
510             }
511         }
512         while (more);
513 
514         timer.stop("iterating over result datalist");
515 
516         cout << count << " rows qualified." << endl;
517         idbassert(count == assertCount);
518     }
519 
520 public:
521 
TIME_TEST()522     void TIME_TEST()
523     {
524         int numRows = 1000 * 1000 * 2;
525         filterTest(FilterOperation::GT, numRows);
526         filterTest(FilterOperation::LT, numRows);
527         filterTest(FilterOperation::LTE, numRows);
528         filterTest(FilterOperation::GTE, numRows);
529         filterTest(FilterOperation::EQ, numRows);
530         filterTest(FilterOperation::NE, numRows);
531     }
532 
STRING_TIME_TEST()533     void STRING_TIME_TEST()
534     {
535         int numRows = 1000 * 1000 * 2;
536         stringFilterTest(FilterOperation::GT, numRows);
537         stringFilterTest(FilterOperation::LT, numRows);
538         stringFilterTest(FilterOperation::LTE, numRows);
539         stringFilterTest(FilterOperation::GTE, numRows);
540         stringFilterTest(FilterOperation::EQ, numRows);
541         stringFilterTest(FilterOperation::NE, numRows);
542     }
543 
DOUBLE_TIME_TEST()544     void DOUBLE_TIME_TEST()
545     {
546         int numRows = 1000 * 1000 * 2;
547         doubleFilterTest(FilterOperation::GT, numRows);
548         doubleFilterTest(FilterOperation::LT, numRows);
549         doubleFilterTest(FilterOperation::LTE, numRows);
550         doubleFilterTest(FilterOperation::GTE, numRows);
551         doubleFilterTest(FilterOperation::EQ, numRows);
552         doubleFilterTest(FilterOperation::NE, numRows);
553     }
554 
QUICK_TEST()555     void QUICK_TEST()
556     {
557         float f = 1.1;
558         double d = 1.2;
559         uint64_t i = 1;
560         uint64_t* i_ptr = &i;
561         double* d_ptr = &d;
562         uint64_t* i2_ptr = (uint64_t*) d_ptr;
563         float* f_ptr = &f;
564         i_ptr = (uint64_t*) f_ptr;
565 
566         cout << "*i_ptr=" << *i_ptr << endl;
567         cout << "*i2_ptr=" << *i2_ptr << endl;
568         f_ptr = (float*) i_ptr;
569 
570         cout << "*f_ptr=" << *f_ptr << endl;
571 
572         cout << endl;
573 
574         if (d > i)
575             cout << "1.2 is greater than 1." << endl;
576 
577         if (f > i)
578             cout << "1.1 is greater than 1." << endl;
579 
580         if (d > f)
581             cout << "1.2 is greater than 1.1" << endl;
582 
583         if (*i_ptr < *i2_ptr)
584             cout << "1.1 < 1.2 when represented as uint64_t." << endl;
585 
586         cout << "sizeof(f) = " << sizeof(f) << endl;
587         cout << "sizeof(i) = " << sizeof(i) << endl;
588         cout << "sizeof(d) = " << sizeof(d) << endl;
589 
590         double dbl = 9.7;
591         double dbl2 = 1.3;
592         i_ptr = (uint64_t*) &dbl;
593         i2_ptr = (uint64_t*) &dbl2;
594         cout << endl;
595         cout << "9.7 as int is " << *i_ptr << endl;
596         cout << "9.7 as int is " << *i2_ptr << endl;
597         cout << "1.2 < 9.7 is " << (*i_ptr < *i2_ptr) << endl;
598     }
599 };
600 
601 CPPUNIT_TEST_SUITE_REGISTRATION(FilterDriver);
602 
603 
main(int argc,char ** argv)604 int main( int argc, char** argv)
605 {
606     CppUnit::TextUi::TestRunner runner;
607     CppUnit::TestFactoryRegistry& registry = CppUnit::TestFactoryRegistry::getRegistry();
608     runner.addTest( registry.makeTest() );
609     bool wasSuccessful = runner.run( "", false );
610     return (wasSuccessful ? 0 : 1);
611 }
612 
613 
614