blob: 80768365f331db1cd2f7737c4ba7e505a0a86c58 [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__PROFILER_H_
#define MPACT_CHERIOT__PROFILER_H_
#include <cstdint>
#include <ostream>
#include "absl/container/btree_map.h"
#include "mpact/sim/generic/counters_base.h"
#include "mpact/sim/util/memory/memory_watcher.h"
#include "mpact/sim/util/program_loader/elf_program_loader.h"
// This file contains a class definition for a profiler. It connects to a
// counter, and whenever that counter's value is changed, the profiler takes
// the new value using the CounterValueSetInterface SetValue() and adds that
// sample to the profile. Instruction profiling is implemented by connecting
// a profiler instance to a counter that has pc values written to it.
namespace mpact::sim::cheriot {
using AddressRange = mpact::sim::util::MemoryWatcher::AddressRange;
using AddressRangeLess = mpact::sim::util::MemoryWatcher::AddressRangeLess;
using ::mpact::sim::generic::CounterValueSetInterface;
using ::mpact::sim::util::ElfProgramLoader;
class Profiler : public CounterValueSetInterface<uint64_t> {
public:
// Currently the only constructor works from text ranges in an elf file.
// TODO(torerik): Add constructors for other sets of ranges.
// The granularity is a power of two and determines the value difference
// between two adjacent sample buckets. For instruction profiling this is
// the smallest instruction size in bytes.
Profiler(ElfProgramLoader &elf_loader, unsigned granularity);
explicit Profiler(unsigned granularity);
~Profiler() override;
// Inherited from CounterValueSetInterface. This will connect to a counter
// that is assigned the value to profile. The most recently used range is
// cached for performance. If it doesn't match, call AddSampleInternal().
void SetValue(const uint64_t &value) override {
// See if the previously referenced range applies.
uint64_t sample = value >> shift_;
if ((sample >= last_start_) && (sample <= last_end_)) {
last_profile_range_[sample - last_start_]++;
return;
}
AddSampleInternal(sample);
}
// Write the profile to the given stream in csv format.
void WriteProfile(std::ostream &os);
// If the elf loader wasn't set in the constructor, use this method to set
// it once the elf file is available.
void SetElfLoader(ElfProgramLoader *elf_loader);
private:
void AddSampleInternal(uint64_t sample);
int shift_ = 0;
ElfProgramLoader *elf_loader_ = nullptr;
absl::btree_map<AddressRange, uint64_t *, AddressRangeLess> profile_ranges_;
uint64_t last_start_ = 0xffff'ffff'ffff'ffffULL;
uint64_t last_end_ = 0xffff'ffff'ffff'ffffULL;
uint64_t *last_profile_range_ = nullptr;
};
} // namespace mpact::sim::cheriot
#endif // MPACT_CHERIOT__PROFILER_H_