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