1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://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, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #define PW_LOG_MODULE_NAME "KVS"
16 #define PW_LOG_LEVEL PW_KVS_LOG_LEVEL
17 
18 #include "pw_kvs/flash_partition_with_stats.h"
19 
20 #include <cstdio>
21 
22 #include "pw_kvs/flash_memory.h"
23 #include "pw_kvs_private/config.h"
24 #include "pw_log/log.h"
25 
26 namespace pw::kvs {
27 
SaveStorageStats(const KeyValueStore & kvs,const char * label)28 Status FlashPartitionWithStats::SaveStorageStats(const KeyValueStore& kvs,
29                                                  const char* label) {
30   // If size is zero saving stats is disabled so do not save any stats.
31   if (sector_counters_.size() == 0) {
32     return OkStatus();
33   }
34 
35   KeyValueStore::StorageStats stats = kvs.GetStorageStats();
36   size_t utilization_percentage = (stats.in_use_bytes * 100) / size_bytes();
37 
38   const char* file_name = "flash_stats.csv";
39   std::FILE* out_file = std::fopen(file_name, "a+");
40   if (out_file == nullptr) {
41     PW_LOG_ERROR("Failed to dump to %s", file_name);
42     return Status::NotFound();
43   }
44 
45   // If file is empty add the header row.
46   std::fseek(out_file, 0, SEEK_END);
47   if (std::ftell(out_file) == 0) {
48     std::fprintf(out_file,
49                  "Test Name,Total Erases,Utilization Percentage,Transaction "
50                  "Count,Entry Count");
51     for (size_t i = 0; i < sector_counters_.size(); i++) {
52       std::fprintf(out_file, ",Sector %zu", i);
53     }
54     std::fprintf(out_file, "\n");
55   }
56 
57   std::fprintf(out_file, "\"%s\",%zu", label, total_erase_count());
58   std::fprintf(out_file,
59                ",%zu,%u,%zu",
60                utilization_percentage,
61                unsigned(kvs.transaction_count()),
62                kvs.size());
63 
64   for (size_t counter : sector_erase_counters()) {
65     std::fprintf(out_file, ",%zu", counter);
66   }
67 
68   std::fprintf(out_file, "\n");
69   std::fclose(out_file);
70   return OkStatus();
71 }
72 
Erase(Address address,size_t num_sectors)73 Status FlashPartitionWithStats::Erase(Address address, size_t num_sectors) {
74   size_t base_index = address / FlashPartition::sector_size_bytes();
75   if (base_index < sector_counters_.size()) {
76     num_sectors = std::min(num_sectors, (sector_counters_.size() - base_index));
77     for (size_t i = 0; i < num_sectors; i++) {
78       sector_counters_[base_index + i]++;
79     }
80   }
81 
82   return FlashPartition::Erase(address, num_sectors);
83 }
84 
85 }  // namespace pw::kvs
86