| /* |
| * Copyright 2024 Google LLC |
| * |
| * 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 |
| * |
| * http://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. |
| */ |
| |
| #ifndef MPACT_CHERIOT__MEMORY_USE_PROFILER_H_ |
| #define MPACT_CHERIOT__MEMORY_USE_PROFILER_H_ |
| |
| #include <cstdint> |
| #include <ostream> |
| |
| #include "absl/container/btree_map.h" |
| #include "mpact/sim/generic/data_buffer.h" |
| #include "mpact/sim/generic/instruction.h" |
| #include "mpact/sim/generic/ref_count.h" |
| #include "mpact/sim/util/memory/memory_interface.h" |
| #include "mpact/sim/util/memory/memory_watcher.h" |
| #include "mpact/sim/util/memory/tagged_memory_interface.h" |
| |
| namespace mpact::sim::cheriot { |
| |
| using AddressRange = util::MemoryWatcher::AddressRange; |
| using AddressRangeLess = util::MemoryWatcher::AddressRangeLess; |
| using generic::DataBuffer; |
| using generic::Instruction; |
| using generic::ReferenceCount; |
| using util::MemoryInterface; |
| using util::TaggedMemoryInterface; |
| |
| namespace internal { |
| |
| // This class is used to track the use of word addresses. It dynamically |
| // allocates tracking memory as needed, and marks a bit for each word that is |
| // accessed. |
| class MemoryUseTracker { |
| public: |
| MemoryUseTracker() = default; |
| ~MemoryUseTracker(); |
| |
| // Memory use is tracked on word granularity. |
| static constexpr int kGranularity = sizeof(uint32_t); |
| // The segment size is the size of the address range for each segment. |
| static constexpr int kSegmentSize = 128 * 1024; |
| static constexpr int kBaseMask = kSegmentSize - 1; |
| // Size of each 'use' bit store. |
| static constexpr int kBitsSize = kSegmentSize / (kGranularity * 8); |
| void MarkUsed(uint64_t address, int size); |
| void WriteUseProfile(std::ostream &os) const; |
| |
| private: |
| uint64_t last_start_ = 0; |
| uint64_t last_end_ = 0; |
| uint8_t *last_used_ = nullptr; |
| absl::btree_map<AddressRange, uint8_t *, AddressRangeLess> memory_use_map_; |
| }; |
| |
| } // namespace internal |
| |
| // Use profiler for the MemoryInterface. |
| class MemoryUseProfiler : public MemoryInterface { |
| public: |
| // The default constructor does not set up memory forwarding. |
| MemoryUseProfiler(); |
| explicit MemoryUseProfiler(MemoryInterface *memory); |
| ~MemoryUseProfiler() override = default; |
| |
| // Inherited from memory interfaces. |
| void Load(uint64_t address, DataBuffer *db, Instruction *inst, |
| ReferenceCount *context) override; |
| void Load(DataBuffer *address_db, DataBuffer *mask_db, int el_size, |
| DataBuffer *db, Instruction *inst, |
| ReferenceCount *context) override; |
| void Store(uint64_t address, DataBuffer *db) override; |
| void Store(DataBuffer *address_db, DataBuffer *mask_db, int el_size, |
| DataBuffer *db) override; |
| |
| void WriteProfile(std::ostream &os) const { tracker_.WriteUseProfile(os); } |
| |
| // Accessor. |
| void set_is_enabled(bool is_enabled) { is_enabled_ = is_enabled; } |
| |
| private: |
| bool is_enabled_ = false; |
| MemoryInterface *memory_; |
| internal::MemoryUseTracker tracker_; |
| }; |
| |
| // Use profiler for the TaggedMemoryInterface. |
| class TaggedMemoryUseProfiler : public TaggedMemoryInterface { |
| public: |
| // The default constructor does not set up memory forwarding. |
| TaggedMemoryUseProfiler(); |
| explicit TaggedMemoryUseProfiler(TaggedMemoryInterface *tagged_memory); |
| ~TaggedMemoryUseProfiler() override = default; |
| |
| // Inherited from memory interfaces. |
| void Load(uint64_t address, DataBuffer *db, Instruction *inst, |
| ReferenceCount *context) override; |
| void Load(DataBuffer *address_db, DataBuffer *mask_db, int el_size, |
| DataBuffer *db, Instruction *inst, |
| ReferenceCount *context) override; |
| void Load(uint64_t address, DataBuffer *db, DataBuffer *tags, |
| Instruction *inst, ReferenceCount *context) override; |
| void Store(uint64_t address, DataBuffer *db) override; |
| void Store(DataBuffer *address_db, DataBuffer *mask_db, int el_size, |
| DataBuffer *db) override; |
| void Store(uint64_t address, DataBuffer *db, DataBuffer *tags) override; |
| |
| void WriteProfile(std::ostream &os) const { tracker_.WriteUseProfile(os); } |
| |
| // Accessor. |
| void set_is_enabled(bool is_enabled) { is_enabled_ = is_enabled; } |
| |
| private: |
| bool is_enabled_ = false; |
| TaggedMemoryInterface *tagged_memory_; |
| internal::MemoryUseTracker tracker_; |
| }; |
| |
| } // namespace mpact::sim::cheriot |
| |
| #endif // MPACT_CHERIOT__MEMORY_USE_PROFILER_H_ |