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 const uint32_t maxLoadBlocks(1024 * 1024);
53 
timespec_sub(const struct timespec & tv1,const struct timespec & tv2,double & tm)54 void timespec_sub(const struct timespec& tv1,
55                   const struct timespec& tv2,
56                   double& tm)
57 {
58     tm = (double)(tv2.tv_sec - tv1.tv_sec) + 1.e-9 * (tv2.tv_nsec - tv1.tv_nsec);
59 }
60 
61 namespace primitiveprocessor
62 {
63 Logger ml;
64 }
65 
66 
67 class BCTest
68 {
69 
70 public:
71 
72     struct OidRanges
73     {
74         OID_t oid;
75         HWM_t hwm;
76         LBIDRange_v ranges;
OidRangesBCTest::OidRanges77         OidRanges(const OID_t o, const HWM_t h, const LBIDRange_v r)
78         {
79             oid = o;
80             hwm = h;
81             ranges = r;
82         }
83     }; //struct OidRanges
84 
85     BCTest(const int cacheSz = 64 * 1024, int readThr = 2, int readAhead = 1024);
86 
87     typedef OidRanges OidRanges_t;
88     typedef vector<OidRanges_t>OidRangesList_t;
89     OidRangesList_t OidRangesList;
90 
91     DBRM dbrm;
92     uint32_t extentSize;
93     BRM::OID_t maxOid;
94 
95     int fCacheSz;
96     int fReadThr;
97     int fReadAhead;
98     uint32_t maxBlocksAvailable;
99     uint32_t fExtentSize;
100 
101     void setUp();
102     int LoadOid(const OidRanges_t& o, uint32_t& loadCount);
103     void LoadLbid(const BRM::LBID_t lbid, const BRM::VER_t ver);
104     int ReadOidRanges(const OidRanges_t& v, uint32_t* hits, uint32_t* miss);
105     void ReadOidLbids(const BRM::LBID_t lbid, const BRM::VER_t ver);
106 
107     BlockRequestProcessor BRP;
108 
109 }; // class BCTest
110 
111 
BCTest(int cacheSz,int readThr,int readAhead)112 BCTest::BCTest(int cacheSz, int readThr, int readAhead) :
113     fCacheSz(cacheSz),
114     fReadThr(readThr),
115     fReadAhead(readAhead),
116     BRP(fCacheSz, fReadThr, fReadAhead)
117 {
118     setUp();
119 } // ctor
120 
121 //
setUp()122 void BCTest::setUp()
123 {
124     LBIDRange_v r;
125     HWM_t hwm;
126     OID_t oid = 1000;
127     extentSize = dbrm.getExtentSize();
128     maxBlocksAvailable = 0;
129     int i = 0;
130     fExtentSize = dbrm.getExtentSize();
131 
132     while ( oid < 5000 )
133     {
134         int ret = 0;
135         ret = dbrm.lookup(oid, r);
136 
137         if (ret == 0 && r.size() > 0)
138         {
139             dbrm.getHWM(oid, hwm);
140             maxBlocksAvailable += (r.size() * extentSize);
141             OidRanges_t oid_range(oid, hwm, r);
142             OidRangesList.push_back(oid_range);
143             //cout << "Setup i: " << i++ << " o: " << oid
144             //	<< " r: " << ret << " s: " << r.size()
145             //	<< " m: " << maxBlocksAvailable
146             //	<< endl;
147             hwm = 0;
148             r.clear();
149         }
150 
151         oid++;
152     }
153 
154     //cout << "\t" << OidRangesList.size() << " oid ranges loaded " << endl << endl;
155     i = 0;
156 } // setUp()
157 
LoadOid(const OidRanges_t & o,uint32_t & loadCount)158 int BCTest::LoadOid(const OidRanges_t& o, uint32_t& loadCount)
159 {
160     blockCacheClient bc(BRP);
161     uint32_t rCount = 0;
162 
163     for (uint32_t i = 0; i < o.ranges.size() ; i++)
164     {
165         const InlineLBIDRange r = {o.ranges[i].start, o.ranges[i].size};
166 
167         if (r.size > 0)
168         {
169             bc.check(r, 0, rCount);
170             //cout <<  "i: " << i << " c: " <<  rCount << " " << o.ranges[i].size << endl;
171             loadCount += rCount;
172         }
173 
174         rCount = 0;
175     } // for
176 
177     //cout << "hwm: " << o.hwm << " tot: " << loadCount <<  " " << o.ranges.size() << endl;
178 
179     return loadCount;
180 
181 } // LoadOid
182 
ReadOidRanges(const OidRanges_t & v,uint32_t * hits,uint32_t * miss)183 int BCTest::ReadOidRanges(const OidRanges_t& v, uint32_t* hits, uint32_t* miss)
184 {
185 
186     blockCacheClient bc(BRP);
187     uint32_t readBlocks = 0;
188     uint32_t missBlocks = 0;
189     uint8_t inBuff[8192];
190     int ret;
191 
192     for (uint32_t i = 0; i < v.ranges.size() && i < lastRangeListIdx; i++)
193     {
194         FileBuffer fb(-1, -1);
195         const InlineLBIDRange r = {v.ranges[i].start, v.ranges[i].size};
196 
197         for (int j = r.start; j < r.start + r.size; j++)
198         {
199             ret = bc.read(j, 0, fb);
200             FileBuffer* ptr = bc.getBlockPtr(j, 0);
201 
202             if (ptr)
203             {
204                 readBlocks++;
205                 memcpy(inBuff, ptr->getData(), 8192);
206             }
207             else
208                 missBlocks++;
209         }
210 
211         *hits += readBlocks;
212         *miss += missBlocks;
213 
214         //cout << " -- Read range idx: " << i << " hits: " << readBlocks << " miss: " << missBlocks << " hwm: " << v.hwm << endl;
215     }
216 
217     return readBlocks;
218 
219 } // ReadRange
220 
221 // add one block to block cache
222 //
LoadLbid(const BRM::LBID_t lbid,const BRM::VER_t ver)223 void BCTest::LoadLbid(const BRM::LBID_t lbid, const BRM::VER_t ver)
224 {
225     blockCacheClient bc(BRP);
226     bool b;
227     bc.check(lbid, ver, false, b);
228 } // LoadLbid
229 
230 // get one block out of block cache
231 //
ReadOidLbids(const BRM::LBID_t lbid,const BRM::VER_t ver)232 void BCTest::ReadOidLbids(const BRM::LBID_t lbid, const BRM::VER_t ver)
233 {
234     uint8_t d[8192] = {'\0'};
235     blockCacheClient bc(BRP);
236     bc.read(lbid, ver, d);
237 } // ReadLbid
238 
239 
240 struct loadThr
241 {
loadThrloadThr242     loadThr(BCTest& bc, int reps = 1) : fBC(bc), fReps(reps)
243     {
244     }
245 
operator ()loadThr246     void operator()()
247     {
248         uint32_t loadedBlocks = 0;
249         uint32_t oidBlocks;
250         uint32_t i = 0;
251         uint32_t rc = 0;
252         struct timespec tm1;
253         struct timespec tm2;
254 
255         tm1.tv_sec = 0;
256         tm1.tv_nsec = 0;
257         tm2.tv_sec = 0;
258         tm2.tv_nsec = 0;
259         double tm3 = 0;
260         clock_gettime(CLOCK_REALTIME, &tm1);
261 
262         for (i = 0; (loadedBlocks + (fBC.OidRangesList[i].ranges.size()*fBC.extentSize)) < fBC.fCacheSz && i < fBC.OidRangesList.size(); i++)
263         {
264             oidBlocks = 0;
265             rc = fBC.LoadOid(fBC.OidRangesList[i], oidBlocks);
266             //cout
267             //	<< "-- Load " << i << " " << fBC.OidRangesList[i].oid
268             //	<< " h: " << fBC.OidRangesList[i].hwm
269             //	<< "/" << oidBlocks << " " << loadedBlocks
270             //	<< endl;
271             loadedBlocks += oidBlocks;
272         } // for (i...
273 
274         lastRangeListIdx = i;
275 
276         clock_gettime(CLOCK_REALTIME, &tm2);
277         timespec_sub(tm1, tm2, tm3);
278 
279         cout << "load ld: " << loadedBlocks
280              << " sz: " << fBC.fCacheSz
281              << " rng: " << lastRangeListIdx
282              << " tm: " << right << setw(10) << fixed << tm3
283              << endl;
284 
285     } // operator()
286 
287     BCTest& fBC;
288     uint32_t fReps;
289 
290 };
291 
292 struct readThr
293 {
294 
readThrreadThr295     readThr(BCTest& bc, int reps = 1) : fBC(bc), fReps(reps) {}
296 
operator ()readThr297     void operator()()
298     {
299         uint32_t rc = 0;
300         uint32_t readBlocks = 0;
301         uint32_t hits = 0;
302         uint32_t miss = 0;
303         uint32_t hitsTot = 0;
304         uint32_t missTot = 0;
305         struct timespec tm1;
306         struct timespec tm2;
307         tm1.tv_sec = 0;
308         tm1.tv_nsec = 0;
309         tm2.tv_sec = 0;
310         tm2.tv_nsec = 0;
311         double tm3 = 0;
312         clock_gettime(CLOCK_REALTIME, &tm1);
313 
314         for (uint32_t k = 0; k < fReps; k++)
315         {
316             for (uint32_t i = 0; i < lastRangeListIdx && i < fBC.OidRangesList.size() ; i++)
317             {
318                 rc = fBC.ReadOidRanges(fBC.OidRangesList[i], &hits, &miss);
319                 //cout << "-- ReadTest " << fBC.OidRangesList[i].oid << " h: " << fBC.OidRangesList[i].hwm << "/" << rc << endl;
320                 readBlocks += rc;
321                 rc = 0;
322             }
323 
324             hitsTot += hits;
325             missTot += miss;
326             hits = 0;
327             miss = 0;
328         }
329 
330         clock_gettime(CLOCK_REALTIME, &tm2);
331         timespec_sub(tm1, tm2, tm3);
332 
333         cout << "readtest rd: " << hitsTot << "/" << missTot
334              << " sz: " 		<< fBC.fCacheSz
335              << " tm: " << right << setw(10) << fixed << tm3
336              << endl;
337 
338     } // operator()
339 
340 
341     BCTest& fBC;
342     uint32_t fReps;
343 
344 };
345 
usage()346 void usage()
347 {
348     cout << "testbc <cacheSz/1024> <reader threads> <read ahead> <client threads> <reps>" << endl;
349 }
350 
351 //
main(int argc,char * argv[])352 int main(int argc, char* argv[])
353 {
354 
355     int cacheSz = 128; // K number of blocks
356     int thr = 1;
357     int ra = 1024;
358     int clients = 1;
359     int reps = 1;
360 
361     if (argc > 1 && atoi(argv[1]) > 0)
362         cacheSz = atoi(argv[1]) * 1024;
363 
364     if (argc > 2 && atoi(argv[2]) > 0)
365         thr = atoi(argv[2]);
366 
367     if (argc > 3 && atoi(argv[3]) > 0)
368         ra = atoi(argv[3]);
369 
370     if (argc > 4 && atoi(argv[4]) > 0)
371         clients = atoi(argv[4]);
372 
373     if (argc > 5 && atoi(argv[5]) > 0)
374         reps = atoi(argv[5]);
375 
376     BCTest bc(cacheSz, thr, ra);
377 
378     cout <<
379          "Cache Size: " << cacheSz <<
380          " read Threads: " << thr <<
381          " read Ahead: " << ra <<
382          " clients: " << clients <<
383          " repetitions: " << reps <<
384          " max Blocks: " << bc.maxBlocksAvailable <<
385          endl;
386 
387     // loader cache
388     struct loadThr loader1(bc, 1);
389     struct readThr reader1(bc, reps);
390     vector<boost::thread*> v;
391 
392     boost::thread* th1 = new boost::thread(loader1);
393     th1->join();
394 
395     for (int i = 0; i < clients; i++)
396     {
397         boost::thread* rd1 = new boost::thread(reader1);
398         v.push_back(rd1);
399     }
400 
401     for (int i = 0; i < clients; i++)
402     {
403         boost::thread* rd1 = v[i];
404         rd1->join();
405         delete rd1;
406     }
407 
408     v.clear();
409 
410     delete th1;
411 
412     return 0;
413 
414 } // end main
415