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 //
19 // C++ Implementation: bcTest
20 //
21 // Description:  A simple Test driver for the Disk Block Buffer Cache
22 //
23 // Author: Jason Rodriguez <jrodriguez@calpont.com>, (C) 2007
24 //
25 //
26 
27 #include <vector>
28 #include <string>
29 #include <iomanip>
30 #include <iostream>
31 #include <sys/time.h>
32 #include <unistd.h>
33 #include <boost/thread/thread.hpp>
34 
35 #include "blockrequestprocessor.h"
36 #include "blockcacheclient.h"
37 #include "stats.h"
38 #include "brm.h"
39 #include "logger.h"
40 #include "iomanager.h"
41 
42 using namespace BRM;
43 using namespace dbbc;
44 using namespace std;
45 using namespace logging;
46 using namespace primitiveprocessor;
47 
48 Stats* gPMStatsPtr = NULL;
49 bool gPMProfOn = false;
50 uint32_t gSession = 0;
51 uint32_t lastRangeListIdx = 0;
52 
timespec_sub(const struct timespec & tv1,const struct timespec & tv2,double & tm)53 void timespec_sub(const struct timespec& tv1,
54                   const struct timespec& tv2,
55                   double& tm)
56 {
57     tm = (double)(tv2.tv_sec - tv1.tv_sec) + 1.e-9 * (tv2.tv_nsec - tv1.tv_nsec);
58 }
59 
60 namespace primitiveprocessor
61 {
62 Logger ml;
63 }
64 
65 
66 class BCTest
67 {
68 
69 public:
70 
71     struct OidRanges
72     {
73         OID_t oid;
74         HWM_t hwm;
75         LBIDRange_v ranges;
OidRangesBCTest::OidRanges76         OidRanges(const OID_t o, const HWM_t h, const LBIDRange_v r)
77         {
78             oid = o;
79             hwm = h;
80             ranges = r;
81         }
82     }; //struct OidRanges
83 
84     BCTest(const int cacheSz = 64 * 1024, int readThr = 2, int readAhead = 1024);
85 
86     typedef OidRanges OidRanges_t;
87     typedef vector<OidRanges_t>OidRangesList_t;
88     OidRangesList_t OidRangesList;
89 
90     DBRM dbrm;
91     uint32_t extentSize;
92     BRM::OID_t maxOid;
93 
94     int fCacheSz;
95     int fReadThr;
96     int fReadAhead;
97     uint32_t maxBlocksAvailable;
98     uint32_t fExtentSize;
99 
100     void setUp();
101     int LoadOid(const OidRanges_t& o, uint32_t& loadCount);
102     void LoadLbid(const BRM::LBID_t lbid, const BRM::VER_t ver);
103     int ReadOidRanges(const OidRanges_t& v);
104     void ReadOidLbids(const BRM::LBID_t lbid, const BRM::VER_t ver);
105 
106     BlockRequestProcessor BRP;
107 
108 }; // class BCTest
109 
110 
BCTest(int cacheSz,int readThr,int readAhead)111 BCTest::BCTest(int cacheSz, int readThr, int readAhead) :
112     fCacheSz(cacheSz),
113     fReadThr(readThr),
114     fReadAhead(readAhead),
115     BRP(fCacheSz, fReadThr, fReadAhead)
116 {
117     setUp();
118 } // ctor
119 
120 //
setUp()121 void BCTest::setUp()
122 {
123     LBIDRange_v r;
124     HWM_t hwm;
125     OID_t oid = 1000;
126     extentSize = dbrm.getExtentSize();
127     maxBlocksAvailable = 0;
128     int i = 0;
129     fExtentSize = dbrm.getExtentSize();
130 
131     while ( oid < 5000 )
132     {
133         int ret = 0;
134         ret = dbrm.lookup(oid, r);
135 
136         if (ret == 0 && r.size() > 0)
137         {
138             dbrm.getHWM(oid, hwm);
139             maxBlocksAvailable += (r.size() * extentSize);
140             OidRanges_t oid_range(oid, hwm, r);
141             OidRangesList.push_back(oid_range);
142             //cout << "Setup i: " << i++ << " o: " << oid
143             //	<< " r: " << ret << " s: " << r.size()
144             //	<< " m: " << maxBlocksAvailable
145             //	<< endl;
146             hwm = 0;
147             r.clear();
148         }
149 
150         oid++;
151     }
152 
153     //cout << "\t" << OidRangesList.size() << " oid ranges loaded " << endl << endl;
154     i = 0;
155 } // setUp()
156 
LoadOid(const OidRanges_t & o,uint32_t & loadCount)157 int BCTest::LoadOid(const OidRanges_t& o, uint32_t& loadCount)
158 {
159     blockCacheClient bc(BRP);
160     uint32_t rCount = 0;
161 
162     for (uint32_t i = 0; i < o.ranges.size() ; i++)
163     {
164         const InlineLBIDRange r = {o.ranges[i].start, o.ranges[i].size};
165 
166         if (r.size > 0)
167         {
168             bc.check(r, 0, rCount);
169             //cout <<  "i: " << i << " c: " <<  rCount << " " << o.ranges[i].size << endl;
170             loadCount += rCount;
171         }
172 
173         rCount = 0;
174     } // for
175 
176     //cout << "hwm: " << o.hwm << " tot: " << loadCount <<  " " << o.ranges.size() << endl;
177 
178     return loadCount;
179 
180 } // LoadOid
181 
ReadOidRanges(const OidRanges_t & v)182 int BCTest::ReadOidRanges(const OidRanges_t& v)
183 {
184 
185     blockCacheClient bc(BRP);
186     int32_t readBlocks = 0;
187     int32_t missBlocks = 0;
188 
189     //int ret;
190     for (uint32_t i = 0; i < v.ranges.size(); i++)
191     {
192         FileBuffer fb(-1, -1);
193         const InlineLBIDRange r = {v.ranges[i].start, v.ranges[i].size};
194 
195         for (int j = r.start; readBlocks < fCacheSz && j < r.start + r.size; j++)
196         {
197             //ret=0;
198             //ret=bc.read(j, 0, fb);
199             FileBuffer* ptr = bc.getBlockPtr(j, 0);
200 
201             if (ptr)
202                 readBlocks++;
203             else
204                 missBlocks++;
205         }
206 
207         //cout << " -- Read range idx: " << i << " hits: " << readBlocks << " miss: " << missBlocks << " hwm: " << v.hwm << endl;
208     }
209 
210     return readBlocks;
211 
212 } // ReadRange
213 
214 // add one block to block cache
215 //
LoadLbid(const BRM::LBID_t lbid,const BRM::VER_t ver)216 void BCTest::LoadLbid(const BRM::LBID_t lbid, const BRM::VER_t ver)
217 {
218     blockCacheClient bc(BRP);
219     bool b;
220     bc.check(lbid, ver, false, b);
221 } // LoadLbid
222 
223 // get one block out of block cache
224 //
ReadOidLbids(const BRM::LBID_t lbid,const BRM::VER_t ver)225 void BCTest::ReadOidLbids(const BRM::LBID_t lbid, const BRM::VER_t ver)
226 {
227     uint8_t d[8192] = {'\0'};
228     blockCacheClient bc(BRP);
229     bc.read(lbid, ver, d);
230 } // ReadLbid
231 
232 
233 struct loadThr
234 {
loadThr(BCTest & bc,int reps=1)235     loadThr::loadThr(BCTest& bc, int reps = 1) : fBC(bc), fReps(reps) {}
236 
operator ()loadThr237     void operator()()
238     {
239         uint32_t loadedBlocks = 0;
240         uint32_t oidBlocks;
241         uint32_t i = 0;
242         uint32_t rc = 0;
243 
244         clock_gettime(CLOCK_REALTIME, &tm1);
245 
246         for (uint32_t j = 0; j < fReps; j++)
247             for (i = 0; /*loadedBlocks<cacheSize &&*/ i < fBC.OidRangesList.size(); i++)
248             {
249                 oidBlocks = 0;
250                 rc = fBC.LoadOid(fBC.OidRangesList[i], oidBlocks);
251                 /**
252                 cout << "."
253                 	<< "-- " << i << " " << fBC.OidRangesList[i].oid
254                 	<< " h: " << fBC.OidRangesList[i].hwm
255                 	<< "/" << oidBlocks
256                 	<< endl;
257                 **/
258                 loadedBlocks += oidBlocks;
259             }
260 
261         clock_gettime(CLOCK_REALTIME, &tm2);
262         double tm3;
263         timespec_sub(tm1, tm2, tm3);
264         lastRangeListIdx = i;
265 
266         cout << "loadtest ld: " << loadedBlocks
267              << " sz: " 		<< fBC.fCacheSz
268              //<< " last: "	<< lastRangeListIdx
269              << " tm: " << right << setw(10) << fixed << tm3
270              << endl;
271 
272     } // operator()
273 
274     BCTest& fBC;
275     uint32_t fReps;
276     struct timespec tm1;
277     struct timespec tm2;
278 
279 };
280 
281 struct readThr
282 {
283 
readThr(BCTest & bc,int reps=1)284     readThr::readThr(BCTest& bc, int reps = 1) : fBC(bc), fReps(reps) {}
285 
operator ()readThr286     void operator()()
287     {
288         uint32_t rc = 0;
289         uint32_t loadedBlocks = 0;
290 
291         for (uint32_t k = 0; k < fReps; k++)
292         {
293             for (uint32_t i = 0; i < fBC.OidRangesList.size() ; i++)
294             {
295                 rc = fBC.ReadOidRanges(fBC.OidRangesList[i]);
296                 cout << ".";
297                 //cout << "-- ReadTest " << OidRangesList[i].oid << " h: " << OidRangesList[i].hwm << "/" << rc << endl;
298                 loadedBlocks += rc;
299                 rc = 0;
300             }
301         }
302 
303         cout << "loadtest " << loadedBlocks << " " << rc << endl << endl;
304 
305     } // operator()
306 
307 
308     BCTest& fBC;
309     uint32_t fReps;
310 
311 };
312 
usage()313 void usage()
314 {
315     cout << "testbc <cacheSz/1024> <reader threads> <read ahead> <client threads> <reps>" << endl;
316 }
317 
318 //
main(int argc,char * argv[])319 int main(int argc, char* argv[])
320 {
321 
322     int cacheSz = 128; // K number of blocks
323     int thr = 1;
324     int ra = 1024;
325     int clients = 1;
326     int reps = 1;
327 
328     if (argc > 1 && atoi(argv[1]) > 0)
329         cacheSz = atoi(argv[1]) * 1024;
330 
331     if (argc > 2 && atoi(argv[2]) > 0)
332         thr = atoi(argv[2]);
333 
334     if (argc > 3 && atoi(argv[3]) > 0)
335         ra = atoi(argv[3]);
336 
337     if (argc > 4 && atoi(argv[4]) > 0)
338         clients = atoi(argv[4]);
339 
340     if (argc > 5 && atoi(argv[5]) > 0)
341         reps = atoi(argv[5]);
342 
343     BCTest bc(cacheSz, thr, ra);
344 
345     cout <<
346          "Cache Size: " << cacheSz <<
347          " read Threads: " << thr <<
348          " read Ahead: " << ra <<
349          " clients: " << clients <<
350          " repetitions: " << reps <<
351          " max Blocks: " << bc.maxBlocksAvailable <<
352          endl;
353 
354 // loader test
355     struct loadThr loader1(bc, reps);
356     vector<boost::thread*> v;
357 
358     for (int i = 0; i < clients; i++)
359     {
360         boost::thread* th1 = new boost::thread(loader1);
361         v.push_back(th1);
362     }
363 
364     for (int i = 0; i < clients; i++)
365     {
366         boost::thread* th1 = v[i];
367         th1->join();
368         delete th1;
369     }
370 
371     v.clear();
372 
373 // reader test
374 
375 
376     return 0;
377 
378 } // end main
379