]> git.uio.no Git - u/mrichter/AliRoot.git/blob - HLT/BASE/test/testAliHLTDataBuffer.C
#97492 Request to: patch AliSimulation; port to Release; make tag on release; for...
[u/mrichter/AliRoot.git] / HLT / BASE / test / testAliHLTDataBuffer.C
1 // $Id$
2
3 /**************************************************************************
4  * This file is property of and copyright by the ALICE HLT Project        * 
5  * ALICE Experiment at CERN, All rights reserved.                         *
6  *                                                                        *
7  * Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
8  *                  for The ALICE HLT Project.                            *
9  *                                                                        *
10  * Permission to use, copy, modify and distribute this software and its   *
11  * documentation strictly for non-commercial purposes is hereby granted   *
12  * without fee, provided that the above copyright notice appears in all   *
13  * copies and that both the copyright notice and this permission notice   *
14  * appear in the supporting documentation. The authors make no claims     *
15  * about the suitability of this software for any purpose. It is          *
16  * provided "as is" without express or implied warranty.                  *
17  **************************************************************************/
18
19 /** @file   testAliHLTDataBuffer.C
20     @author Matthias Richter
21     @date   
22     @brief  Test program for the AliHLTDataBuffer class
23  */
24
25 #ifndef __CINT__
26 #include "TDatime.h"
27 #include "TRandom.h"
28 #include "AliHLTDataTypes.h"
29 #include "algorithm"
30 #include "TObjArray.h"
31 #include "TObjString.h"
32 #include "TString.h"
33 #include "AliHLTDAQ.h"
34 #include <cstdio>
35 #include <cstring>
36 #include <iostream>
37 #include <cerrno>
38 #include "AliHLTDataBuffer.h"
39 #endif
40
41 using namespace std;
42
43 int gVerbosity=0;
44 const int gPagesize=1024*1024;
45
46 template<class T>
47 int testLoop(vector<T>& descriptions, int nofLevels, int nofCycles);
48 int GetRandom(int min, int max);
49
50 class AliHLTRandomBuffer {
51 public:
52   AliHLTRandomBuffer(): fpBuffer(NULL), fBufferSize(0), fInstances() {}
53   AliHLTRandomBuffer(AliHLTUInt32_t size): fpBuffer(NULL), fBufferSize(0), fInstances() {Init(size);}
54   AliHLTRandomBuffer(const AliHLTRandomBuffer&): fpBuffer(NULL), fBufferSize(0), fInstances() {}
55   AliHLTRandomBuffer& operator=(const AliHLTRandomBuffer& src) {if (&src!=this) {fpBuffer=NULL; fBufferSize=0;} return *this;}
56   ~AliHLTRandomBuffer() {}
57
58   int Init(AliHLTUInt32_t size) {
59     if (fpBuffer) return -EINPROGRESS;
60     
61     fpBuffer=new AliHLTUInt8_t[size];
62     if (!fpBuffer) return -ENOMEM;
63     fBufferSize=size;
64
65     int words=size/sizeof(AliHLTUInt32_t);
66     AliHLTUInt32_t* pTgt=reinterpret_cast<AliHLTUInt32_t*>(fpBuffer);
67     for (int i=0; i<words; i++, pTgt++) *pTgt=GetRandom(0, 0x7fffffff);
68     return 0;
69   }
70
71   struct AliHLTRandomBufferInstance {
72     int fId;
73     AliHLTUInt32_t fOffset;
74     AliHLTUInt32_t fSize;
75   };
76
77   int CreateInstance(AliHLTUInt32_t size) {
78     if (size>fBufferSize) return -ENOSPC;
79
80     AliHLTRandomBufferInstance instance;
81     instance.fId=fInstances.size()>0?fInstances.back().fId+1:0;
82     instance.fOffset=GetRandom(0, fBufferSize-size);
83     instance.fSize=size;
84     fInstances.push_back(instance);
85     return instance.fId;
86   }
87
88   int ReleaseInstance(int id) {
89     for (vector<AliHLTRandomBufferInstance>::iterator instance=fInstances.begin();
90          instance!=fInstances.end(); instance++) {
91       if (instance->fId==id) {
92         fInstances.erase(instance);
93         return 0;
94       }
95     }
96     return -ENOENT;
97   }
98
99   const AliHLTUInt8_t* GetBuffer(int id) {
100     for (vector<AliHLTRandomBufferInstance>::iterator instance=fInstances.begin();
101          instance!=fInstances.end(); instance++) {
102       if (instance->fId==id) {
103
104         return fpBuffer+instance->fOffset;
105       }
106     }
107     return NULL;
108   }
109
110   bool CompareBuffer(const AliHLTUInt8_t* buffer, AliHLTUInt32_t size, int id) {
111     if (!buffer) return false;
112     for (vector<AliHLTRandomBufferInstance>::iterator instance=fInstances.begin();
113          instance!=fInstances.end(); instance++) {
114       if (instance->fId==id) {
115         if (instance->fSize!=size) {
116           cout << "CompareBuffer ("<< instance->fId << "): size missmatch: " << size << ", expected " << instance->fSize << endl; 
117           return false;
118         }
119         return memcmp(buffer, fpBuffer+instance->fOffset, size)==0;
120       }
121     }
122     return false;
123   }
124
125   void Print(const char* /*option*/) {
126     cout << "AliHLTRandomBufferInstance " << this << ": buffer " << (void*)fpBuffer << " size " << fBufferSize << endl;
127     if (!fpBuffer) return;
128
129     int words=fBufferSize/sizeof(AliHLTUInt32_t);
130     int lines=words/4;
131     AliHLTUInt32_t* pTgt=reinterpret_cast<AliHLTUInt32_t*>(fpBuffer);
132     for (int line=0; line<lines; line++) {
133       for (int i=0; i<4; i++, pTgt++) cout << hex << " 0x" << (*pTgt);
134       cout << endl;
135     }
136     if (words*sizeof(AliHLTUInt32_t)!=fBufferSize) cout << "some remaining bytes left due to alignment" << endl;
137   }
138
139 private:
140   AliHLTUInt8_t* fpBuffer;
141   AliHLTUInt32_t fBufferSize;
142
143   vector<AliHLTRandomBufferInstance> fInstances;
144 };
145
146 AliHLTRandomBuffer gData(2*gPagesize);
147
148 /**
149  * @class AliHLTTestRawPage
150  * Helper class for testing cycles of memory allocation, buffer modification, and
151  * cleanup with the AliHLTRawPage within the function testLoop.
152  */
153 class AliHLTTestRawPage {
154 public:
155   AliHLTTestRawPage() : fBuffer(NULL) {}
156   AliHLTTestRawPage(const AliHLTTestRawPage& src) : fBuffer(src.fBuffer) {}
157   AliHLTTestRawPage& operator=(const AliHLTTestRawPage& src) {
158     fBuffer=src.fBuffer;
159     return *this;
160   }
161
162   ~AliHLTTestRawPage() {}
163
164   bool IsAllocated() {return fBuffer!=NULL;}
165   bool Alloc(AliHLTUInt32_t size, int verbosity) {
166     fBuffer=AliHLTDataBuffer::AliHLTRawPage::GlobalAlloc(size);
167     if (!fBuffer) return false;
168     if (verbosity>1) {
169       printf("allocated raw buffer %p from page %p\n", fBuffer, AliHLTDataBuffer::AliHLTRawPage::FindPage(fBuffer));
170       fBuffer->Print("min");
171     }
172     return true;
173   }
174
175   AliHLTUInt8_t* GetPointer() {return fBuffer?fBuffer->GetPointer():NULL;}
176
177   bool SetSize(AliHLTUInt32_t size, int verbosity) {
178     AliHLTDataBuffer::AliHLTRawPage* rawpage=AliHLTDataBuffer::AliHLTRawPage::FindPage(fBuffer);
179     if (rawpage) {
180       if (rawpage->SetSize(fBuffer, size)==0) {
181         if (verbosity>1) {
182           cout << "setting size for raw buffer " << fBuffer << " of page " << rawpage << endl;
183           fBuffer->Print("min");
184         }
185         return true;
186       } else {
187         cerr << "failed to set size for raw buffer " << fBuffer << endl; 
188       }
189     } else {
190       cerr << "can not find raw page for buffer " << fBuffer << endl;
191     }
192     
193     return false;
194   }
195
196   bool Free(int verbosity) {
197     AliHLTDataBuffer::AliHLTRawPage* rawpage=AliHLTDataBuffer::AliHLTRawPage::FindPage(fBuffer);
198     if (rawpage) {
199       if (rawpage->Free(fBuffer)==0) {
200         if (verbosity>1) cout << "released raw buffer " << fBuffer << " from page " << rawpage << endl;
201         fBuffer=NULL;
202         return true;
203       } else {
204         cerr << "failed to release raw buffer " << fBuffer  << endl;
205       }
206     } else {
207       cerr << "can not find raw page for buffer " << fBuffer  << endl;
208     }
209     return false;
210   }
211
212   AliHLTUInt32_t GetTotalSize() {return fBuffer?fBuffer->GetTotalSize():0;}
213
214   bool GlobalClean(int verbosity) {
215     int nofPages=0;
216     for (AliHLTDataBuffer::AliHLTRawPage* rawpage=AliHLTDataBuffer::AliHLTRawPage::NextPage(NULL);
217          rawpage!=NULL; 
218          rawpage=AliHLTDataBuffer::AliHLTRawPage::NextPage(rawpage)) {
219       nofPages++;
220     }
221     if (verbosity>=1) {
222       cout << "total number of pages: " << nofPages << endl;
223     }
224
225     AliHLTDataBuffer::AliHLTRawPage::GlobalClean();
226     return true;
227   }
228
229   void Print(const char* options) {
230     if (strcmp(options, "pages")==0 ||
231         strcmp(options, "global")==0) {
232       AliHLTDataBuffer::AliHLTRawPage::NextPage(NULL)->Print("global");
233       return;
234     }
235   }
236 private:
237   AliHLTDataBuffer::AliHLTRawBuffer* fBuffer;
238 };
239
240 struct testRawPageDescription {
241   testRawPageDescription() : fLevel(0), fBufferSize(0), fDataId(-1), fTest() {};
242   int fLevel;
243   AliHLTUInt32_t fBufferSize;
244   int fDataId;
245   AliHLTTestRawPage fTest;
246 };
247
248 class AliHLTDataBufferWrapper : public AliHLTDataBuffer {
249 public:
250   int ResetDataBuffer() {
251     return AliHLTDataBuffer::ResetDataBuffer();
252   }
253 };
254
255 /**
256  * @class AliHLTTestDataBuffer
257  * Helper class for testing cycles of memory allocation, buffer modification, and
258  * cleanup with the AliHLTDataBuffer within the function testLoop.
259  */
260 class AliHLTTestDataBuffer {
261 public:
262   AliHLTTestDataBuffer() : fInstance(NULL), fBuffer(NULL), fSize(0) {}
263   AliHLTTestDataBuffer(const AliHLTTestDataBuffer&)  : fInstance(NULL), fBuffer(NULL), fSize(0) {} ;
264   AliHLTTestDataBuffer& operator=(const AliHLTTestDataBuffer&) {
265     fInstance=NULL;
266     fBuffer=NULL;
267     fSize=0;
268     return *this;
269   }
270
271   bool IsAllocated() {return fBuffer!=NULL;}
272   bool Alloc(AliHLTUInt32_t size, int verbosity) {
273     if (!fInstance) {
274       fInstance=new AliHLTDataBufferWrapper;
275       if (!fInstance) return false;
276       fInstance->SetGlobalLoggingLevel(verbosity>1?kHLTLogAll:(AliHLTComponentLogSeverity)0x7c);
277     }
278     
279     fBuffer=fInstance->GetTargetBuffer(size);
280     if (!fBuffer) return false;
281     fSize=size;
282     if (verbosity>1) {
283       cout << "allocated data buffer" << this << endl;
284     }
285     return true;
286   }
287
288   AliHLTUInt8_t* GetPointer() {return fBuffer;}
289
290   bool SetSize(AliHLTUInt32_t size, int verbosity) {
291     if (!fInstance) return false;
292     AliHLTComponentBlockData bd;
293     AliHLTComponent::FillBlockData(bd);
294     bd.fSize=size;
295     bd.fOffset=0;
296     fInstance->SetSegments(fBuffer, &bd, 1);
297
298     if (verbosity>1) {
299       cout << "setting size for data buffer " << this << ": allocated size " << fSize << " -> " << size << endl;
300     }
301     fSize=size;
302     return true;
303   }
304
305   bool Free(int verbosity) {
306     if (!fInstance) return false;
307     fSize=0;
308     if (fInstance->ResetDataBuffer()==0) {
309       if (verbosity>1) cout << "released data buffer " << this << endl;
310       fBuffer=NULL;
311       return true;
312     } else {
313       cerr << "failed to release raw buffer " << fBuffer  << endl;
314     }
315
316     return false;
317   }
318
319   AliHLTUInt32_t GetTotalSize() {return fSize;}
320
321   bool GlobalClean(int verbosity) {
322     if (!fInstance) return false;
323     if (verbosity>=1) {
324       fInstance->PrintStatistics();
325     }
326     delete fInstance;
327
328     AliHLTDataBuffer::AliHLTRawPage::GlobalClean();
329     return true;
330   }
331
332   void Print(const char* options) {
333     if (strcmp(options, "pages")==0 ||
334         strcmp(options, "global")==0) {
335       fInstance->PrintStatistics();
336       AliHLTDataBuffer::AliHLTRawPage::NextPage(NULL)->Print("global");
337       return;
338     }
339   }
340 private:
341   AliHLTDataBufferWrapper* fInstance;
342   AliHLTUInt8_t* fBuffer;
343   AliHLTUInt32_t fSize;
344 };
345
346 struct testDataBufferDescription {
347   testDataBufferDescription() : fLevel(0), fBufferSize(0), fDataId(-1), fTest() {};
348   int fLevel;
349   AliHLTUInt32_t fBufferSize;
350   int fDataId;
351   AliHLTTestDataBuffer fTest;
352 };
353
354 template<class T,class S>
355 int CopyDescription(vector<T>& target, vector<S>& source)
356 {
357   target.clear();
358   for (unsigned i=0; i<source.size(); i++) {
359     T clone;
360     clone.fLevel=source[i].fLevel;
361     clone.fBufferSize=source[i].fBufferSize;
362     clone.fDataId=source[i].fDataId;
363     target.push_back(clone);
364   }
365   return 0;
366 }
367
368 template<class T>
369 int fillTestSample(int levels, int processes, vector<T>& descriptions)
370 {
371   int availableProcesses=processes;
372   for (int level=0; level<levels; level++) {
373     int levelprocesses=GetRandom(availableProcesses/2, availableProcesses-(levels-level));
374     for (int process=0; process<levelprocesses; process++) {
375       T desc;
376       desc.fLevel=level;
377       desc.fBufferSize=GetRandom(1024, 2*gPagesize);
378       //desc.fTest.Clear();
379       descriptions.push_back(desc);
380     }
381     availableProcesses-=levelprocesses;
382   }
383   return 0;
384 }
385
386 template<class T>
387 int allocateBuffers(vector<T>& descriptions,
388                     int level=-1)
389 {
390   for (unsigned i=0; i<descriptions.size(); i++) {
391     if (level>=0 && descriptions[i].fLevel<level) continue;
392     if (level>=0 && descriptions[i].fLevel>level) break;
393     if (descriptions[i].fTest.IsAllocated()) {
394       cerr << "warning: buffer already allocated" << endl;
395       continue;
396     }
397
398     if (descriptions[i].fTest.Alloc(GetRandom(descriptions[i].fBufferSize/2, descriptions[i].fBufferSize), gVerbosity)) {
399     }
400
401     if (!descriptions[i].fTest.IsAllocated()) {
402       cerr << "failed to allocate buffer for process " << i << endl;
403       return -EFAULT;
404     }
405   }
406   return 0;
407 }
408                    
409 template<class T>
410 int setBufferSizes(vector<T>& descriptions,
411                    int level=-1)
412 {
413   // set buffer size for all processes of the specified level
414   // buffer size is chosen randomly between 0 and the allocated size
415   vector<unsigned> positions;
416   for (unsigned i=0; i<descriptions.size(); i++) {
417     if (!descriptions[i].fTest.IsAllocated()) continue;
418     if (level>=0 && descriptions[i].fLevel<level) continue;
419     if (level>=0 && descriptions[i].fLevel>level) break;
420     positions.push_back(i);
421   }
422
423   random_shuffle(positions.begin(), positions.end());
424   for (vector<unsigned>::iterator position=positions.begin();
425        position!=positions.end(); position++) {
426     AliHLTUInt32_t datasize=GetRandom(0, descriptions[*position].fTest.GetTotalSize());
427     descriptions[*position].fDataId=gData.CreateInstance(datasize);
428     const AliHLTUInt8_t* pSrc=gData.GetBuffer(descriptions[*position].fDataId);
429     if (!pSrc) {
430       cout << "error creating data instance" << endl;
431       return -1;
432     }
433     AliHLTUInt8_t* pTgt=descriptions[*position].fTest.GetPointer();
434     if (!pTgt) {
435       cout << "error target buffer" << endl;
436       return -1;
437     }
438     memcpy(pTgt, pSrc, datasize);
439     if (descriptions[*position].fTest.SetSize(datasize, gVerbosity)) {
440       if (gVerbosity>1) cout << "  process " << *position << " level " << descriptions[*position].fLevel << endl;
441     } else {
442       cout << "failed allocation for process " << *position << " level " << descriptions[*position].fLevel << endl;
443       return -1;
444     }
445   }
446   return 0;
447 }
448
449 template<class T>                  
450 int releaseBuffers(vector<T>& descriptions,
451                    int level=-1)
452 {
453   // find the processes to be releases according to the specified level
454   // shuffle the processes and then release in this random order
455   vector<unsigned> positions;
456   for (unsigned i=0; i<descriptions.size(); i++) {
457     if (!descriptions[i].fTest.IsAllocated()) continue;
458     if (level>=0 && descriptions[i].fLevel<level) continue;
459     if (level>=0 && descriptions[i].fLevel>level) break;
460     positions.push_back(i);
461   }
462
463   random_shuffle(positions.begin(), positions.end());
464   for (vector<unsigned>::iterator position=positions.begin();
465        position!=positions.end(); position++) {
466     if (!gData.CompareBuffer(descriptions[*position].fTest.GetPointer(), descriptions[*position].fTest.GetTotalSize(), descriptions[*position].fDataId)) {
467       cout << "data comparison failed for process " << *position << " level " << descriptions[*position].fLevel << endl;
468       return -1;
469     }
470     gData.ReleaseInstance(descriptions[*position].fDataId);
471     if (descriptions[*position].fTest.Free(gVerbosity)) {
472       if (gVerbosity>1) cout << "  process " << *position << " level " << descriptions[*position].fLevel << endl;
473     } else {
474       cout << "failed deallocation for process " << *position << " level " << descriptions[*position].fLevel << endl;
475       return -1;
476     }
477   }
478   return 0;
479 }
480
481 template<class T>
482 int testLoop(vector<T>& descriptions, int nofLevels, int nofCycles)
483 {
484   // test the buffer allocation and deallocation from the AliHLTRawPage
485   //
486   // build a hierarchy of processes like in a real chain, in the first
487   // implementation it is only a linear tree
488   // the number of levels and processes are randomly chosen from a certain range
489   // processes are distributed among the levels such that there is a decreasing
490   // number of processes but at least one process
491   //
492   // The test cycle consists of the following steps
493   // - loop over all levels
494   //   - allocation of a maximum buffer for every process of the current level
495   //   - set the buffer size to be used for every process of the current level
496   //   - release buffers of the previous level
497   // - check all created raw pages and throw error, if
498   //   - not all buffers released
499   //   - not all memory released
500   //   - still fragmented
501   // 
502   int iResult=0;
503
504   AliHLTDataBuffer::AliHLTRawPage* rawpage=NULL;
505   for (int cycle=0; cycle<nofCycles && iResult>=0; cycle++) {
506     for (int level=0; level<=nofLevels; level++) {
507       // allocate buffers
508       if (level<nofLevels) {
509         if ((iResult=allocateBuffers(descriptions, level))<0) {
510           cerr << "failed to allocate buffers" << endl;
511           return iResult;
512         }
513       }
514
515       if (gVerbosity>1) {
516         cout << "finished allocation - level " << level << " ";
517         descriptions[0].fTest.Print("pages");
518       }
519
520       if (level<nofLevels) {
521         if ((iResult=setBufferSizes(descriptions, level))<0) {
522           cerr << "failed setting  buffers" << endl;
523           return iResult;
524         }
525       }
526
527       if (gVerbosity>1) {
528         cout << "finished size modification - level " << level << " ";
529         descriptions[0].fTest.Print("pages");
530       }
531
532       if (level>0) {
533         if ((iResult=releaseBuffers(descriptions, level-1))<0) {
534           cerr << "failed to release buffers" << endl;
535           return iResult;
536         }
537       }
538     }
539
540     if (gVerbosity>1) {
541       cout << "status of released pages: " << endl << "  ";
542       descriptions[0].fTest.Print("pages");
543     }
544     for (rawpage=AliHLTDataBuffer::AliHLTRawPage::NextPage(NULL);
545          rawpage!=NULL; 
546          rawpage=AliHLTDataBuffer::AliHLTRawPage::NextPage(rawpage)) {
547       if (rawpage->IsUsed()) {
548         cerr << "page " << rawpage << " has used buffers" << endl;
549         iResult=-EFAULT;
550       } else if (rawpage->Size()!=rawpage->Capacity()) {
551         cerr << "page " << rawpage << " not completely released" << endl;
552         iResult=-EFAULT;
553       } else if (rawpage->IsFragmented()) {
554         cerr << "page " << rawpage << " is still fragmented" << endl;
555         iResult=-EFAULT;
556       }
557     }
558     AliHLTDataBuffer::SetGlobalEventCount(cycle);
559   }
560
561   if (iResult<0) {
562     descriptions[0].fTest.Print("pages");
563   }
564
565   descriptions[0].fTest.GlobalClean(gVerbosity);
566
567   return iResult;
568 }
569
570 /**
571  * Get a random number in the given range.
572  */
573 int GetRandom(int min, int max)
574 {
575   if (max-min<2) return min;
576   static TRandom rand;
577   static bool seedSet=false;
578   if (!seedSet) {
579     TDatime dt;
580     rand.SetSeed(dt.Get());
581     seedSet=true;
582   }
583   return min+rand.Integer(max-min);
584 }
585
586 int testAliHLTDataBuffer()
587 {
588   int iResult=0;
589   const int iMaxLevels=10;
590   int nofLevels=GetRandom(3,iMaxLevels);
591   int nofProcesses=GetRandom(nofLevels,2*iMaxLevels);
592   int nofCycles=GetRandom(100,1000);
593
594   vector<testDataBufferDescription> descriptions;
595
596   if ((iResult=fillTestSample(nofLevels, nofProcesses, descriptions))<0) {
597     cerr << "failed to fill test sample" << endl;
598     return iResult;
599   }
600
601   // adjust to the level of the last entry
602   nofLevels=descriptions[descriptions.size()-1].fLevel;
603
604   if (gVerbosity>0) {
605     cout << "    Test setup: " << nofLevels << " levels/ " << nofProcesses << " processes/ " << nofCycles << " cycle(s)" << endl;
606     cout << "    Pagesize: " << gPagesize << endl;
607     for (unsigned i=0; i<descriptions.size(); i++) {
608       cout << "      process " << i << ": level " << descriptions[i].fLevel << "   max size " << descriptions[i].fBufferSize << endl;
609     }
610   }
611
612   if ((iResult=testLoop(descriptions, nofLevels, nofCycles))<0) return iResult;
613
614   if (gVerbosity>0) {
615     cout << "checking memory allocation using AliHLTRawPage directly ..." << endl;
616   }
617   vector<testRawPageDescription> rawpagedesc;
618   CopyDescription(rawpagedesc, descriptions);
619   if ((iResult=testLoop(rawpagedesc, nofLevels, nofCycles))<0) return iResult;
620
621   return 0;
622 }
623
624 /////////////////////////////////////////////////////////////////////////
625 /////////////////////////////////////////////////////////////////////////
626 //
627 // main functions
628
629 int main(int /*argc*/, const char** /*argv*/)
630 {
631   int iResult=0;
632   const int nofCycles=10;
633   for (int cycle=0; cycle<nofCycles && iResult>=0; cycle++) {
634     iResult=testAliHLTDataBuffer();
635     if (((cycle+1)*100/nofCycles)%10==0) {
636       cout << (cycle+1)*100/nofCycles << "% complete" << endl;
637     }
638   }
639
640   return iResult;
641 }