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