• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #define LOG_TAG "SingleStorePerfPhoneTest"
16 #include "distributed_kv_data_manager.h"
17 #include <gtest/gtest.h>
18 #include "log_print.h"
19 #include <random>
20 #include <sys/time.h>
21 #include <thread>
22 #include <vector>
23 #include "store_manager.h"
24 #include "types.h"
25 #include "process_system_api_adapter_impl.h"
26 
27 #ifdef DB_DEBUG_ENV
28 
29 #include "system_time.h"
30 
31 #endif // DB_DEBUG_ENV
32 
33 using namespace testing::ext;
34 using namespace OHOS::DistributedKv;
35 using namespace std;
36 namespace OHOS::Test {
37 // define some variables to init a KvStoreDelegateManager object.
38 std::shared_ptr<SingleKvStore> store1;
39 std::shared_ptr<SingleKvStore> store2;
40 std::shared_ptr<SingleKvStore> store3;
41 
42 class SingleStorePerfPhoneTest : public testing::Test {
43 public:
44     struct DataConfig {
45         int batch;
46         int count;
47         int size;
48         int ratio;
49     };
50 
51     struct PresetResult {
52         std::string firstKey;
53         std::string lastKey;
54     };
55     std::shared_ptr<SingleKvStore> CreateKVStore(std::string storeIdTest, KvStoreType type, bool encrypt, bool backup);
56     static void SetUpTestCase();
57     static void TearDownTestCase();
58     void SetUp() override;
59     void TearDown() override;
60 };
61 
GenerateBytes(const string & str)62 OHOS::DistributedKv::Key GenerateBytes(const string &str)
63 {
64     DistributedDB::Key bytes;
65     const char *buffer = str.c_str();
66     for (uint32_t i = 0; i < str.size(); i++) {
67         bytes.emplace_back(buffer[i]);
68     }
69     return bytes;
70 }
71 
GenerateRandomString(long length)72 string GenerateRandomString(long length)
73 {
74     std::string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
75     std::string out;
76     std::random_device rd;
77     std::mt19937 gen(rd());
78     std::uniform_int_distribution<> dis(0, chars.size() - 1);
79     for (int i = 0; i < length; i++) {
80         out += chars[dis(gen)];
81     }
82     return out;
83 }
84 
GetDate(char * cType,int iDay)85 string GetDate(char *cType, int iDay)
86 {
87     char cTimePARTNUMBER[256] = "";
88     time_t rawtime;
89     struct tm timeinfo{};
90     rawtime = time(nullptr) + iDay * 24 * 3600; // 24 hours a day, 3600 seconds per hour
91     localtime_r(&rawtime, &timeinfo);
92     char buffer1[256];
93     size_t n = strftime(cTimePARTNUMBER, sizeof(buffer1), cType, &timeinfo); //20180623
94     if (n != 0) {
95         string strTimePARTNUMBER = cTimePARTNUMBER;
96         return strTimePARTNUMBER;
97     } else {
98         return "";
99     }
100 }
101 
102 /**
103  * Presets data to a specified single-key value store.
104  * @param store Smart pointer of a single key-value store.
105  * @param batch The number of batches, representing the batch in which the data was inserted.
106  * @param count Number of pictures on a screen.
107  * @param size Size of the value in kilobytes for each key-value pair.
108  * @param ratio Ratio of compression
109  * @param firstKey An output parameter that receives the first key in the first batch
110  * @param lastKey An output parameter that receives the last key in the last batch
111  * @details This function is responsible for writing a preset set of data to a specified
112  *      single-key value store based on a given batch, quantity, size, and ratio.
113  */
PresetData(std::shared_ptr<SingleKvStore> & store,SingleStorePerfPhoneTest::DataConfig & config,SingleStorePerfPhoneTest::PresetResult & result)114 void PresetData(std::shared_ptr<SingleKvStore> &store,
115     SingleStorePerfPhoneTest::DataConfig &config, SingleStorePerfPhoneTest::PresetResult &result)
116 {
117     std::ostringstream s;
118     s << std::setw(16) << std::setfill('0') << 0; // 16 bytes
119     string strDate;
120     // The batches are iterated backward to generate data for different dates
121     string ss = to_string(config.size) + "K";
122     for (int i = config.batch; i >= 1; i--) {
123         strDate = GetDate(const_cast<char*>("%Y%m%d"), -i);
124         for (int index = 1; index <= config.count; index++) {
125             // Produces a unique key string containing date, size, and index information
126             string tmp =
127             s.str() + "_" + ss + "_" + strDate + string(3 - to_string(index).length(), '0') + to_string(index);
128             string val;
129             // Generate random value string based on ratio If the ratio is 0, an empty string is generated
130             if (config.ratio != 0) {
131                 val = GenerateRandomString(static_cast<long>(config.size * 1024) / config.ratio); // 1024 bytes per 1K
132             } else {
133                 val = GenerateRandomString(0);
134             }
135             const DistributedDB::Key key = GenerateBytes(tmp);
136             const DistributedDB::Value value = GenerateBytes(val);
137             ASSERT_EQ(store->Put(key, value), SUCCESS);
138             if (i == config.batch && index == 1) {
139                 // Convert the contents of the key to std::string and assign it to the firstKey
140                 result.firstKey = std::string(key.begin(), key.end());
141             }
142             if (i == 1 && index == config.count) {
143                 result.lastKey = std::string(key.begin(), key.end());
144             }
145         }
146     }
147     cout << "put success!" << endl;
148 }
149 
150 /**
151  * @brief Calculates the duration of a RangeResultSet.
152  * @param store Smart pointer of a single key-value store.
153  * @param batch The number of batches, representing the batch in which the data was inserted.
154  * @param size Size of the value in kilobytes for each key-value pair.
155  * @param count Number of pictures on a screen.
156  * @param firstKey An output parameter that receives the first key in the first batch
157  * @param lastKey An output parameter that receives the last key in the last batch
158  * @details This function is used to calculate the duration for obtaining data on a screen.
159  *      Data is obtained through multiple cycles and the average time is calculated.
160  */
CalcRangeResultSetDuration(std::shared_ptr<SingleKvStore> & store,SingleStorePerfPhoneTest::DataConfig & config,SingleStorePerfPhoneTest::PresetResult & result)161 void CalcRangeResultSetDuration(std::shared_ptr<SingleKvStore> &store,
162     SingleStorePerfPhoneTest::DataConfig &config, SingleStorePerfPhoneTest::PresetResult &result)
163 {
164     // batch = totolCnt / (448/ 112) size(4 8) count (448 112)
165     double dur = 0.0;
166     double totalTime = 0.0;
167     double avrTime = 0.0;
168     int failCount = 0;
169     // The outer loop is run 100 times to improve the accuracy of the test results
170     for (int n = 0; n < 100; ++n) { // 100 times
171         DataQuery query;
172         // The sequential query is carried out according to the actual business scenario
173         query.Between("", result.lastKey);
174         std::shared_ptr<KvStoreResultSet> readResultSet;
175         ASSERT_EQ(store->GetResultSet(query, readResultSet), SUCCESS);
176         ASSERT_TRUE(readResultSet != nullptr);
177         for (int ind = config.batch; ind >= 1; ind--) {
178             struct timeval startTime{};
179             struct timeval endTime{};
180             (void) gettimeofday(&startTime, nullptr);
181             for (int i = 0; i < config.count; ++i) { // Loop through a screen of data
182                 readResultSet->MoveToNext(); // Move the read position to the next row.
183                 Entry entry; // Data is organized by entry definition.
184                 readResultSet->GetEntry(entry);
185             }
186             (void) gettimeofday(&endTime, nullptr);
187             double startUsec = static_cast<double>((startTime.tv_sec * 1000 * 1000) + startTime.tv_usec);
188             double endUsec = static_cast<double>((endTime.tv_sec * 1000 * 1000) + endTime.tv_usec);
189             dur = endUsec - startUsec;
190             totalTime += dur;
191             avrTime = (dur / 1000); // 1000 is to convert ms
192             if (avrTime >= 3.0) { // 3.0 ms is upper bound on performance
193                 failCount += 1;
194             }
195         }
196         EXPECT_EQ(store->CloseResultSet(readResultSet), SUCCESS);
197         readResultSet = nullptr;
198     }
199     if (config.batch != 0) {
200         // 100 is for unit conversion
201         avrTime = (((totalTime / config.batch) / 100) / 1000); // 1000 is to convert ms
202         cout << "Scan Range ResultSet avg cost = " << avrTime << " ms." << endl;
203         cout << "failCount: " << failCount << endl;
204         EXPECT_LT(avrTime, 3.0); // 3.0 ms is upper bound on performance
205     } else {
206         cout << "Error: Division by zero." << endl;
207     }
208 }
209 
SetUpTestCase()210 void SingleStorePerfPhoneTest::SetUpTestCase()
211 {
212     std::string baseDir = "/data/service/el1/public/database/SingleStorePerfPhoneTest";
213     mkdir(baseDir.c_str(), (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH));
214 }
215 
TearDownTestCase()216 void SingleStorePerfPhoneTest::TearDownTestCase()
217 {
218     std::string baseDir = "/data/service/el1/public/database/SingleStorePerfPhoneTest";
219     StoreManager::GetInstance().Delete({ "SingleStorePerfPhoneTest" }, { "SingleKVStore" }, baseDir);
220 
221     (void)remove("/data/service/el1/public/database/SingleStorePerfPhoneTest/key");
222     (void)remove("/data/service/el1/public/database/SingleStorePerfPhoneTest/kvdb");
223     (void)remove("/data/service/el1/public/database/SingleStorePerfPhoneTest");
224 }
225 
SetUp()226 void SingleStorePerfPhoneTest::SetUp()
227 {
228     store1 = CreateKVStore("SingleKVStore1", LOCAL_ONLY, false, false);
229     if (store1 == nullptr) {
230         store1 = CreateKVStore("SingleKVStore1", LOCAL_ONLY, false, false);
231     }
232     ASSERT_NE(store1, nullptr);
233 
234     store2 = CreateKVStore("SingleKVStore2", LOCAL_ONLY, false, false);
235     if (store2 == nullptr) {
236         store2 = CreateKVStore("SingleKVStore2", LOCAL_ONLY, false, false);
237     }
238     ASSERT_NE(store2, nullptr);
239 
240     store3 = CreateKVStore("SingleKVStore3", LOCAL_ONLY, false, false);
241     if (store3 == nullptr) {
242         store3 = CreateKVStore("SingleKVStore3", LOCAL_ONLY, false, false);
243     }
244     ASSERT_NE(store3, nullptr);
245 }
246 
TearDown()247 void SingleStorePerfPhoneTest::TearDown()
248 {
249     AppId appId = { "SingleStorePerfPhoneTest" };
250     StoreId storeId1 = { "SingleKVStore1" };
251     StoreId storeId2 = { "SingleKVStore2" };
252     StoreId storeId3 = { "SingleKVStore3" };
253     store1 = nullptr;
254     store2 = nullptr;
255     store3 = nullptr;
256     auto status = StoreManager::GetInstance().CloseKVStore(appId, storeId1);
257     ASSERT_EQ(status, SUCCESS);
258     status = StoreManager::GetInstance().CloseKVStore(appId, storeId2);
259     ASSERT_EQ(status, SUCCESS);
260     status = StoreManager::GetInstance().CloseKVStore(appId, storeId3);
261     ASSERT_EQ(status, SUCCESS);
262     auto baseDir = "/data/service/el1/public/database/SingleStorePerfPhoneTest";
263     status = StoreManager::GetInstance().Delete(appId, storeId1, baseDir);
264     ASSERT_EQ(status, SUCCESS);
265     status = StoreManager::GetInstance().Delete(appId, storeId2, baseDir);
266     ASSERT_EQ(status, SUCCESS);
267     status = StoreManager::GetInstance().Delete(appId, storeId3, baseDir);
268     ASSERT_EQ(status, SUCCESS);
269 }
270 
CreateKVStore(std::string storeIdTest,KvStoreType type,bool encrypt,bool backup)271 std::shared_ptr<SingleKvStore> SingleStorePerfPhoneTest::CreateKVStore(std::string storeIdTest, KvStoreType type,
272     bool encrypt, bool backup)
273 {
274     Options options;
275     options.kvStoreType = type;
276     options.securityLevel = S1;
277     options.encrypt = encrypt;
278     options.area = EL1;
279     options.backup = backup;
280     options.baseDir = "/data/service/el1/public/database/SingleStorePerfPhoneTest";
281 
282     AppId appId = { "SingleStorePerfPhoneTest" };
283     StoreId storeId = { storeIdTest };
284     Status status = StoreManager::GetInstance().Delete(appId, storeId, options.baseDir);
285     return StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
286 }
287 
288 /**
289  * @tc.name: Gallery1WThumbnailsKVStoreBetweenTest
290  * @tc.desc: Gallery 10,000 thumbnails High-performance KV database Native interface Between
291  *               query performance less than 3 ms
292  * @tc.type: PERF
293  * @tc.require:
294  * @tc.author: Gang Wang
295  */
296 HWTEST_F(SingleStorePerfPhoneTest, Gallery1WThumbnailsKVStoreBetweenTest, TestSize.Level0)
297 {
298     cout << "monthly start" << endl;
299     SingleStorePerfPhoneTest::DataConfig monthlyConfig = {
300         .batch = static_cast<int>(10000 / 112),
301         .count = 112,
302         .size = 8,
303         .ratio = 1
304     };
305     SingleStorePerfPhoneTest::PresetResult result1;
306     PresetData(store1, monthlyConfig, result1);
307     cout << "first key: " << result1.firstKey << ", last key: " << result1.lastKey << endl;
308     CalcRangeResultSetDuration(store1, monthlyConfig, result1);
309 
310     cout << "annually start" << endl;
311     SingleStorePerfPhoneTest::DataConfig annuallyConfig = {
312         .batch = static_cast<int>(10000 / 448),
313         .count = 448,
314         .size = 4,
315         .ratio = 1
316     };
317     SingleStorePerfPhoneTest::PresetResult result2;
318     PresetData(store2, annuallyConfig, result2);
319     cout << "first key: " << result2.firstKey << ", last key: " << result2.lastKey << endl;
320     CalcRangeResultSetDuration(store2, annuallyConfig, result2);
321 }
322 
323 /**
324  * @tc.name: Gallery5WThumbnailsKVStoreBetweenTest
325  * @tc.desc: Gallery 50,000 thumbnails High-performance KV database Native interface Between
326  *               query performance less than 3 ms
327  * @tc.type: PERF
328  * @tc.require:
329  * @tc.author: Gang Wang
330  */
331 HWTEST_F(SingleStorePerfPhoneTest, Gallery5WThumbnailsKVStoreBetweenTest, TestSize.Level0)
332 {
333     cout << "monthly start" << endl;
334     SingleStorePerfPhoneTest::DataConfig monthlyConfig = {
335         .batch = static_cast<int>(50000 / 112),
336         .count = 112,
337         .size = 8,
338         .ratio = 1
339     };
340     SingleStorePerfPhoneTest::PresetResult result1;
341     PresetData(store1, monthlyConfig, result1);
342     cout << "first key: " << result1.firstKey << ", last key: " << result1.lastKey << endl;
343     CalcRangeResultSetDuration(store1, monthlyConfig, result1);
344 
345     cout << "annually start" << endl;
346     SingleStorePerfPhoneTest::DataConfig annuallyConfig = {
347         .batch = static_cast<int>(50000 / 448),
348         .count = 448,
349         .size = 4,
350         .ratio = 1
351     };
352     SingleStorePerfPhoneTest::PresetResult result2;
353     PresetData(store2, annuallyConfig, result2);
354     cout << "first key: " << result2.firstKey << ", last key: " << result2.lastKey << endl;
355     CalcRangeResultSetDuration(store2, annuallyConfig, result2);
356 }
357 } // namespace OHOS::Test