[SRUK] Initial copy from Tizen 2.2 version
[platform/core/uifw/dali-adaptor.git] / platform-abstractions / slp / data-cache / tests / data-cache-debug.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://floralicense.org/license/
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an AS IS BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 // CLASS HEADER
18 #include "data-cache-debug.h"
19
20 #ifdef DATA_CACHE_DEBUG
21
22 // INTERNAL INCLUDES
23 #include "../data-cache-io.h"
24 #include "../data-compression.h"
25 #include <dali/integration-api/debug.h>
26
27 // EXTERNAL INCLUDES
28 #include <boost/thread.hpp>
29 #include <set>
30
31 namespace Dali
32 {
33
34 namespace SlpPlatform
35 {
36
37 namespace DataCacheIo
38 {
39
40 namespace
41 {
42 const char * const DALI_USER_FONT_CACHE_PATH( DALI_USER_FONT_CACHE_DIR );
43 const std::string TEST_FILE("test-file");
44
45 const unsigned int NUMBER_TEST_ITERATIONS(25000);               ///< number of test iterations to perform per thread
46 const bool RANDOM_DATA_SIZE(true);                              ///< whether to use random data sizes (up to DATA_SIZE)
47 const unsigned int MAX_KEY_VALUE(200000);                       ////< number key index value
48 const unsigned int DATA_SIZE(64);                               ///< maximum data size
49 const unsigned int MAX_NUMBER_ENTRIES( 200000 );                ///< Maximum number of entries size
50 const unsigned int ENTRIES_TO_READ_WRITE(1);                    ///< maximum number of entries to read/write in one API call
51 const Platform::DataCache::CompressionMode COMPRESSION_MODE(  Platform::DataCache::RUN_LENGTH_ENCODING); //or COMPRESSION_OFF );
52
53 /**
54  * Fills the key vector with random keys between 0 and MAX_KEY_VALUE
55  */
56 void FillVectorWithRandomKeys( Platform::DataCache::KeyVector& keyVector)
57 {
58   // make sure if we are setup to write 20 key/data pairs in a single API call
59   // the we have at least 20  unique keys
60   DALI_ASSERT_ALWAYS( MAX_KEY_VALUE > ENTRIES_TO_READ_WRITE);
61
62   // create a set of unique keys, then insert them in to the key vector
63   typedef std::set< Platform::DataCache::DataKey > KeySet;
64   KeySet uniqueKeys;
65   while( uniqueKeys.size() != keyVector.size() )
66   {
67     uniqueKeys.insert(  rand() % MAX_KEY_VALUE );
68   }
69   int i(0);
70   for( KeySet::const_iterator iter =  uniqueKeys.begin(), endIter = uniqueKeys.end(); iter != endIter; ++iter )
71   {
72     keyVector[i] =  (*iter);
73     i++;
74   }
75 }
76
77 /**
78  * Fill the data vector with random data
79  */
80 void FillVectorWithRandomData( Platform::DataCache::DataVector& dataVector)
81 {
82   for( unsigned int i = 0; i < dataVector.size(); i++ )
83   {
84     unsigned int length( DATA_SIZE );
85     if( RANDOM_DATA_SIZE )
86     {
87      length =  1 + rand() % DATA_SIZE;
88     }
89     unsigned char* data =  new unsigned char[length];
90     dataVector[i].SetData( data, length );
91   }
92 }
93
94 /**
95  * delete the data vector, and check the exists flag is correct
96  */
97 void DeleteData(Platform::DataCache::DataVector& dataVector )
98 {
99   for( unsigned int i = 0; i < dataVector.size(); i++ )
100   {
101     Platform::DataCache::Data& data( dataVector[i] );
102     // check the exists flag
103     if (data.data && !data.exists)
104     {
105       DALI_ASSERT_ALWAYS(0 && "data exist flag wrong #1 ");
106     }
107     if (!data.data && data.exists)
108     {
109       DALI_ASSERT_ALWAYS(0 && "data exist flag wrong #2 ");
110     }
111     if (data.data)
112     {
113       delete []data.data;
114     }
115   }
116 }
117
118 /**
119  * read the number of entries, and get the entry list
120  */
121 unsigned int CheckNumberEntries(  FILE* indexFile, KeyMeta** keyMeta  )
122 {
123   unsigned int numberEntries;
124
125   bool ok = ReadNumberEntries( indexFile, numberEntries );
126   if( !ok )
127   {
128     // ReadEntries will log an error
129     DALI_ASSERT_ALWAYS(0);
130   }
131   // Check there is no data after the header, if there are no entries in the index file
132   if( numberEntries == 0 )
133   {
134     if( fgetc( indexFile ) != EOF)
135     {
136       // data index is corrupt, it contains more data than are recorded in numberEntries field
137       DALI_LOG_ERROR("index file has zero entries, but contains data after header\n");
138       DALI_ASSERT_ALWAYS(0);
139     }
140     return 0;
141   }
142
143   // allocate an array of  ( key | offset ) structures
144   *keyMeta = new  DataCacheIo::KeyMeta[ numberEntries ];
145
146   // read the index table in to memory
147   ok = ReadEntries(indexFile, *keyMeta, 0, numberEntries);
148   if( !ok )
149   {
150     // ReadEntries will log an error
151     DALI_ASSERT_ALWAYS(0);
152   }
153   // check there's no data at the end of the file
154   if( fgetc( indexFile ) != EOF)
155   {
156     // data index is corrupt, it contains more entries than are recorded in numberEntries field
157     DALI_LOG_ERROR("index has  more entries than recorded\n");
158     DALI_ASSERT_ALWAYS(0);
159   }
160   return numberEntries;
161 }
162
163 unsigned int GetMaxDataSizeOnFile( unsigned int dataSize )
164 {
165   if( COMPRESSION_MODE == Platform::DataCache::RUN_LENGTH_ENCODING )
166   {
167     return DataCompression::GetMaximumRleCompressedSize(  dataSize );
168   }
169   return dataSize;
170 }
171
172 /**
173  * Checks every single entry in the data file.
174  * This is slow, it should not be performed unless debugging.
175  */
176 void FullFileCheck(  FILE* indexFile,
177                      FILE* dataFile,
178                      unsigned int maxDataSize)
179 {
180   //  Read entries from index file and make sure the file size is correct
181   DataCacheIo::KeyMeta* keyMeta(NULL);
182   unsigned int numberEntries = CheckNumberEntries( indexFile, &keyMeta );
183   unsigned int maxDataSizeOnFile = GetMaxDataSizeOnFile( maxDataSize );
184
185   // Allocate the file buffer for reading the data, and a decode buffer if the data is compressed
186   unsigned char* fileDataBuffer = new unsigned char[ maxDataSizeOnFile ];
187   unsigned char* decodeBuffer = new unsigned char[ maxDataSize ];
188
189   // For each entry, check the data is valid in the
190   unsigned int previousOffset = GetHeaderSize();
191
192   std::set< Dali::Platform::DataCache::DataKey  > KeyLookup;
193
194   for(unsigned int i = 0; i < numberEntries; ++i )
195   {
196     Dali::Platform::DataCache::DataKey key( keyMeta[i].mKey );
197     Dali::Platform::DataCache::Data data;
198
199     // check for duplicate keys
200     if( KeyLookup.find(key) != KeyLookup.end() )
201     {
202       printf(" Duplicate Key Found %d \n",key);
203       DALI_ASSERT_ALWAYS(0 );
204     }
205     KeyLookup.insert(key);
206
207     unsigned int offset( keyMeta[i].mOffset);
208
209     // ensure the offset of each entry is correct
210     DALI_ASSERT_ALWAYS( previousOffset == offset);
211
212     bool ok = ReadData( dataFile, offset, key, data, fileDataBuffer, maxDataSizeOnFile );
213     if( !ok )
214     {
215       DALI_ASSERT_ALWAYS(0 && "DataCacheIO::ReadData failed");
216     }
217
218     unsigned int dataLengthOnFile = data.length;
219
220     if( COMPRESSION_MODE == Platform::DataCache::RUN_LENGTH_ENCODING )
221     {
222       // try and de-compress it
223       std::size_t decodedSize;
224       bool ok = DataCompression::DecodeRle( fileDataBuffer, data.length, decodeBuffer, maxDataSize, decodedSize);
225       DALI_ASSERT_ALWAYS( ok && " DataCompression::DecodeRle failed");
226       data.length = decodedSize;
227     }
228
229    // un-comment for list of key / data entries
230    // printf(" key = %d, length = %d \n",key,data.length);
231     previousOffset = offset + dataLengthOnFile + 8; /* 8 = key + length field */
232   }
233   delete []keyMeta;
234   delete []decodeBuffer;
235   delete []fileDataBuffer;
236 }
237
238 void ClearTestFiles( const std::string& indexFileName, const std::string& dataFileName )
239 {
240   FILE* dataFile = DataCacheIo::OpenFile( dataFileName, DataCacheIo::DATA_FILE, DataCacheIo::NO_LOCK, DataCacheIo::READ_WRITE, DataCacheIo::CREATE_IF_MISSING );
241   FILE* indexFile = DataCacheIo::OpenFile( indexFileName, DataCacheIo::INDEX_FILE, DataCacheIo::NO_LOCK, DataCacheIo::READ_WRITE, DataCacheIo::CREATE_IF_MISSING);
242
243   ReCreateFiles( indexFile, dataFile, COMPRESSION_MODE);
244
245   fclose( dataFile );
246   fclose( indexFile );
247 }
248
249 } // unnamed name space
250
251 void DataCacheStressTest(void)
252 {
253   printf("thread started \n");
254
255   static unsigned int apiCalls(0);
256   std::string path(DALI_USER_FONT_CACHE_PATH);
257   std::string file = path + TEST_FILE ;
258
259   Platform::DataCache* cache =  Platform::DataCache::New(   Platform::DataCache::READ_WRITE,
260                                           COMPRESSION_MODE,
261                                           file,
262                                           DATA_SIZE,
263                                           MAX_NUMBER_ENTRIES);
264
265
266   for(unsigned int i = 0; i < NUMBER_TEST_ITERATIONS; ++i )
267   {
268     apiCalls+=2;
269     if( i%50 == 0)
270     {
271       printf("DataCache Add() & Find() calls: %d \r",apiCalls);
272     }
273
274     // Read a random array of key/data pairs
275     Platform::DataCache::KeyVector keyVector;
276     Platform::DataCache::DataVector dataVector;
277
278     unsigned int arraySize  =  ENTRIES_TO_READ_WRITE;
279     keyVector.resize( arraySize );
280
281     // read a random entry
282     FillVectorWithRandomKeys( keyVector );
283     cache->Find( keyVector, dataVector);
284     DeleteData( dataVector);
285
286     // Write a random entry
287     FillVectorWithRandomKeys( keyVector );
288     FillVectorWithRandomData( dataVector );
289     cache->Add( keyVector, dataVector );
290     DeleteData(dataVector);
291   }
292   delete cache;
293 }
294
295 void ThreadedStressTest()
296 {
297   //  only allow test to run once
298   static int done(false);
299   if( done )
300   {
301     return;
302   }
303   done = true;
304
305   std::string path(DALI_USER_FONT_CACHE_PATH);
306   std::string dataFileName = path + TEST_FILE + ".data";
307   std::string indexFileName = path + TEST_FILE + ".index";
308
309   // Make sure the data files are empty to start with
310   ClearTestFiles( indexFileName  , dataFileName);
311
312
313   printf("____ DataCache Multi Thread Test Starting ____ \n");
314
315   boost::thread t1(DataCacheStressTest);
316   boost::thread t2(DataCacheStressTest);
317   boost::thread t3(DataCacheStressTest);
318   boost::thread t4(DataCacheStressTest);
319   boost::thread t5(DataCacheStressTest);
320   boost::thread t6(DataCacheStressTest);
321   boost::thread t7(DataCacheStressTest);
322   boost::thread t8(DataCacheStressTest);
323
324   t1.join();
325   t2.join();
326   t3.join();
327   t4.join();
328   t5.join();
329   t6.join();
330   t7.join();
331   t8.join();
332
333   // Check the data that was written is not corrupt
334
335   FILE* dataFile = OpenFile( dataFileName, DataCacheIo::DATA_FILE, DataCacheIo::NO_LOCK, DataCacheIo::READ_ONLY );
336   FILE* indexFile = OpenFile( indexFileName, DataCacheIo::INDEX_FILE, DataCacheIo::NO_LOCK, DataCacheIo::READ_ONLY );
337
338   FullFileCheck( indexFile, dataFile, DATA_SIZE );
339
340   fclose( dataFile );
341   fclose( indexFile );
342
343   printf("____ DataCache Multi Thread Test PASSED ____ \n");
344 }
345
346 } // namespace DataCacheIO
347
348 } // namespace SlpPlatform
349
350 } // namespace Dali
351 #endif // #ifdef DATA_CACHE_DEBUG