blob: c7ebf830c1350422c8bddc6f7ce7f9add27ebff0 [file] [log] [blame]
/*
* 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_