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 #pragma once
15 
16 #include <algorithm>
17 #include <numeric>
18 
19 #include "pw_containers/vector.h"
20 #include "pw_kvs/flash_memory.h"
21 #include "pw_kvs/key_value_store.h"
22 #include "pw_status/status.h"
23 
24 #ifndef PW_KVS_RECORD_PARTITION_STATS
25 // PW_KVS_RECORD_PARTITION_STATS enables saving stats.
26 #define PW_KVS_RECORD_PARTITION_STATS 0
27 #endif  // PW_KVS_RECORD_PARTITION_STATS
28 
29 namespace pw::kvs {
30 
31 class FlashPartitionWithStats : public FlashPartition {
32  public:
33   // Save flash partition and KVS storage stats. Does not save if
34   // sector_counters_ is zero.
35   Status SaveStorageStats(const KeyValueStore& kvs, const char* label);
36 
37   using FlashPartition::Erase;
38 
39   Status Erase(Address address, size_t num_sectors) override;
40 
sector_erase_counters()41   std::span<size_t> sector_erase_counters() {
42     return std::span(sector_counters_.data(), sector_counters_.size());
43   }
44 
min_erase_count()45   size_t min_erase_count() const {
46     if (sector_counters_.empty()) {
47       return 0;
48     }
49     return *std::min_element(sector_counters_.begin(), sector_counters_.end());
50   }
51 
max_erase_count()52   size_t max_erase_count() const {
53     if (sector_counters_.empty()) {
54       return 0;
55     }
56     return *std::max_element(sector_counters_.begin(), sector_counters_.end());
57   }
58 
average_erase_count()59   size_t average_erase_count() const {
60     return sector_counters_.empty()
61                ? 0
62                : total_erase_count() / sector_counters_.size();
63   }
64 
total_erase_count()65   size_t total_erase_count() const {
66     return std::accumulate(sector_counters_.begin(), sector_counters_.end(), 0);
67   }
68 
ResetCounters()69   void ResetCounters() { sector_counters_.assign(sector_count(), 0); }
70 
71  protected:
72   FlashPartitionWithStats(
73       Vector<size_t>& sector_counters,
74       FlashMemory* flash,
75       uint32_t start_sector_index,
76       uint32_t sector_count,
77       uint32_t alignment_bytes = 0,  // Defaults to flash alignment
78       PartitionPermission permission = PartitionPermission::kReadAndWrite)
FlashPartition(flash,start_sector_index,sector_count,alignment_bytes,permission)79       : FlashPartition(flash,
80                        start_sector_index,
81                        sector_count,
82                        alignment_bytes,
83                        permission),
84         sector_counters_(sector_counters) {
85     sector_counters_.assign(FlashPartition::sector_count(), 0);
86   }
87 
88  private:
89   Vector<size_t>& sector_counters_;
90 };
91 
92 template <size_t kMaxSectors>
93 class FlashPartitionWithStatsBuffer : public FlashPartitionWithStats {
94  public:
95   FlashPartitionWithStatsBuffer(
96       FlashMemory* flash,
97       uint32_t start_sector_index,
98       uint32_t sector_count,
99       uint32_t alignment_bytes = 0,  // Defaults to flash alignment
100       PartitionPermission permission = PartitionPermission::kReadAndWrite)
FlashPartitionWithStats(sector_counters_,flash,start_sector_index,sector_count,alignment_bytes,permission)101       : FlashPartitionWithStats(sector_counters_,
102                                 flash,
103                                 start_sector_index,
104                                 sector_count,
105                                 alignment_bytes,
106                                 permission) {}
107 
FlashPartitionWithStatsBuffer(FlashMemory * flash)108   FlashPartitionWithStatsBuffer(FlashMemory* flash)
109       : FlashPartitionWithStatsBuffer(
110             flash, 0, flash->sector_count(), flash->alignment_bytes()) {}
111 
112  private:
113   // If PW_KVS_RECORD_PARTITION_STATS is not set, use zero size vector which
114   // will not save any stats.
115   Vector<size_t, PW_KVS_RECORD_PARTITION_STATS ? kMaxSectors : 0>
116       sector_counters_;
117 };
118 
119 }  // namespace pw::kvs
120