| // Copyright 2020 The Pigweed Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| // use this file except in compliance with the License. You may obtain a copy of |
| // the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| // License for the specific language governing permissions and limitations under |
| // the License. |
| #pragma once |
| |
| #include <algorithm> |
| #include <numeric> |
| |
| #include "pw_containers/vector.h" |
| #include "pw_kvs/flash_memory.h" |
| #include "pw_kvs/key_value_store.h" |
| #include "pw_status/status.h" |
| |
| #ifndef PW_KVS_RECORD_PARTITION_STATS |
| // PW_KVS_RECORD_PARTITION_STATS enables saving stats. |
| #define PW_KVS_RECORD_PARTITION_STATS 0 |
| #endif // PW_KVS_RECORD_PARTITION_STATS |
| |
| namespace pw::kvs { |
| |
| class FlashPartitionWithStats : public FlashPartition { |
| public: |
| // Save flash partition and KVS storage stats. Does not save if |
| // sector_counters_ is zero. |
| Status SaveStorageStats(const KeyValueStore& kvs, const char* label); |
| |
| using FlashPartition::Erase; |
| |
| Status Erase(Address address, size_t num_sectors) override; |
| |
| std::span<size_t> sector_erase_counters() { |
| return std::span(sector_counters_.data(), sector_counters_.size()); |
| } |
| |
| size_t min_erase_count() const { |
| if (sector_counters_.empty()) { |
| return 0; |
| } |
| return *std::min_element(sector_counters_.begin(), sector_counters_.end()); |
| } |
| |
| size_t max_erase_count() const { |
| if (sector_counters_.empty()) { |
| return 0; |
| } |
| return *std::max_element(sector_counters_.begin(), sector_counters_.end()); |
| } |
| |
| size_t average_erase_count() const { |
| return sector_counters_.empty() |
| ? 0 |
| : total_erase_count() / sector_counters_.size(); |
| } |
| |
| size_t total_erase_count() const { |
| return std::accumulate(sector_counters_.begin(), sector_counters_.end(), 0); |
| } |
| |
| void ResetCounters() { sector_counters_.assign(sector_count(), 0); } |
| |
| protected: |
| FlashPartitionWithStats( |
| Vector<size_t>& sector_counters, |
| FlashMemory* flash, |
| uint32_t start_sector_index, |
| uint32_t sector_count, |
| uint32_t alignment_bytes = 0, // Defaults to flash alignment |
| PartitionPermission permission = PartitionPermission::kReadAndWrite) |
| : FlashPartition(flash, |
| start_sector_index, |
| sector_count, |
| alignment_bytes, |
| permission), |
| sector_counters_(sector_counters) { |
| sector_counters_.assign(FlashPartition::sector_count(), 0); |
| } |
| |
| private: |
| Vector<size_t>& sector_counters_; |
| }; |
| |
| template <size_t kMaxSectors> |
| class FlashPartitionWithStatsBuffer : public FlashPartitionWithStats { |
| public: |
| FlashPartitionWithStatsBuffer( |
| FlashMemory* flash, |
| uint32_t start_sector_index, |
| uint32_t sector_count, |
| uint32_t alignment_bytes = 0, // Defaults to flash alignment |
| PartitionPermission permission = PartitionPermission::kReadAndWrite) |
| : FlashPartitionWithStats(sector_counters_, |
| flash, |
| start_sector_index, |
| sector_count, |
| alignment_bytes, |
| permission) {} |
| |
| FlashPartitionWithStatsBuffer(FlashMemory* flash) |
| : FlashPartitionWithStatsBuffer( |
| flash, 0, flash->sector_count(), flash->alignment_bytes()) {} |
| |
| private: |
| // If PW_KVS_RECORD_PARTITION_STATS is not set, use zero size vector which |
| // will not save any stats. |
| Vector<size_t, PW_KVS_RECORD_PARTITION_STATS ? kMaxSectors : 0> |
| sector_counters_; |
| }; |
| |
| } // namespace pw::kvs |