!95 Temporarily drop profile saver

Merge pull request !95 from 胡晓炜/OpenHarmony-3.1-Release
This commit is contained in:
openharmony_ci
2022-03-14 05:27:47 +00:00
committed by Gitee
8 changed files with 0 additions and 1383 deletions
-2
View File
@@ -138,8 +138,6 @@ ohos_static_library("libarkruntime_static") {
"object_accessor.cpp",
"object_header.cpp",
"panda_vm.cpp",
"profilesaver/profile_dump_info.cpp",
"profilesaver/profile_saver.cpp",
"runtime.cpp",
"runtime_helpers.cpp",
"signal_handler.cpp",
-2
View File
@@ -128,8 +128,6 @@ set(SOURCES
object_accessor.cpp
arch/asm_support.cpp
signal_handler.cpp
profilesaver/profile_saver.cpp
profilesaver/profile_dump_info.cpp
runtime_helpers.cpp
handle_scope.cpp
file_manager.cpp
-2
View File
@@ -38,7 +38,6 @@ class CFrameTest;
class StackWalkerTest;
class PandaRunner;
class CompilerQueueTest;
class ProfileSaverTest;
class DynObjectsTest;
class JSObjectTest;
class JSFunctionTest;
@@ -312,7 +311,6 @@ private:
friend class panda::test::PandaRunner;
friend class verifier::test::VerifierTest;
friend class panda::Logger;
friend class test::ProfileSaverTest;
friend class panda::test::DynObjectsTest;
friend class panda::test::JSObjectTest;
friend class panda::test::JSFunctionTest;
-575
View File
@@ -1,575 +0,0 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* 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.
*/
#include "runtime/profilesaver/profile_dump_info.h"
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <cerrno>
#include <climits>
#include <cstring>
#include "libpandabase/os/unix/failure_retry.h"
#include "trace/trace.h"
#ifndef PATH_MAX
#define PATH_MAX 1024
#endif
namespace panda {
static constexpr size_t K_BITS_PER_BYTE = 8;
static constexpr size_t K_LINE_HEADER_SIZE = 3 * sizeof(uint32_t) + sizeof(uint16_t);
static constexpr size_t K_METHOD_BYTES = 4;
static constexpr size_t K_CLASS_BYTES = 4;
const uint8_t ProfileDumpInfo::kProfileMagic[] = {'p', 'r', 'o', 'f', '\0'}; // NOLINT
const uint8_t ProfileDumpInfo::kProfileVersion[] = {'0', '1', '\0'}; // NOLINT
static constexpr uint16_t K_MAX_FILE_KEY_LENGTH = PATH_MAX; // NOLINT
static bool WriteBuffer(int fd, const uint8_t *buffer, size_t byte_count)
{ // NOLINT
while (byte_count > 0) {
int bytes_written = write(fd, buffer, byte_count); // real place to write
if (bytes_written == -1) {
return false;
}
byte_count -= bytes_written;
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
buffer += bytes_written;
}
return true;
}
static void AddStringToBuffer(PandaVector<uint8_t> *buffer, const PandaString &value)
{ // NOLINT
buffer->insert(buffer->end(), value.begin(), value.end());
}
template <typename T>
static void AddUintToBuffer(PandaVector<uint8_t> *buffer, T value)
{
for (size_t i = 0; i < sizeof(T); i++) {
buffer->push_back((value >> (i * K_BITS_PER_BYTE)) & 0xff); // NOLINT
}
}
/*
* Tests for EOF by trying to read 1 byte from the descriptor.
* Returns:
* 0 if the descriptor is at the EOF,
* -1 if there was an IO error
* 1 if the descriptor has more content to read
*/
// NOLINTNEXTLINE(readability-identifier-naming)
static int testEOF(int fd)
{
// NOLINTNEXTLINE(modernize-avoid-c-arrays)
uint8_t buffer[1];
return read(fd, buffer, 1);
}
int64_t GetFileSizeBytes(const PandaString &filename)
{
struct stat stat_buf {
};
int rc = stat(filename.c_str(), &stat_buf);
return rc == 0 ? stat_buf.st_size : -1;
}
ProfileDumpInfo::ProfileLoadSatus ProfileDumpInfo::SerializerBuffer::FillFromFd(int fd, const PandaString &source,
PandaString *error)
{
size_t byte_count = ptr_end_ - ptr_current_;
uint8_t *buffer = ptr_current_;
while (byte_count > 0) {
int bytes_read = read(fd, buffer, byte_count);
if (bytes_read == 0) { // NOLINT
*error += "Profile EOF reached prematurely for " + source;
return PROFILE_LOAD_BAD_DATA;
} else if (bytes_read < 0) { // NOLINT
*error += "Profile IO error for " + source + ConvertToString(os::Error(errno).ToString());
return PROFILE_LOAD_IO_ERROR;
}
byte_count -= bytes_read;
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
buffer += bytes_read;
}
return PROFILE_LOAD_SUCCESS;
}
template <typename T>
T ProfileDumpInfo::SerializerBuffer::ReadUintAndAdvance()
{
static_assert(std::is_unsigned<T>::value, "Type is not unsigned");
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
ASSERT(ptr_current_ + sizeof(T) <= ptr_end_);
T value = 0;
for (size_t i = 0; i < sizeof(T); i++) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
value += ptr_current_[i] << (i * K_BITS_PER_BYTE);
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
ptr_current_ += sizeof(T);
return value;
}
bool ProfileDumpInfo::SerializerBuffer::CompareAndAdvance(const uint8_t *data, size_t data_size)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
if (ptr_current_ + data_size > ptr_end_) {
return false;
}
if (memcmp(ptr_current_, data, data_size) == 0) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
ptr_current_ += data_size;
return true;
}
return false;
}
bool ProfileDumpInfo::MergeWith(const ProfileDumpInfo &other)
{
for (const auto &other_it : other.dump_info_) {
auto info_it = dump_info_.find(other_it.first);
if ((info_it != dump_info_.end()) && (info_it->second.checksum != other_it.second.checksum)) {
LOG(INFO, RUNTIME) << "info_it->second.checksum" << info_it->second.checksum;
LOG(INFO, RUNTIME) << "other_it->second.checksum" << other_it.second.checksum;
LOG(INFO, RUNTIME) << "Checksum mismatch" << other_it.first;
return false;
}
}
LOG(INFO, RUNTIME) << "All checksums match";
for (const auto &other_it : other.dump_info_) {
const PandaString &other_profile_location = other_it.first;
const ProfileLineData &other_profile_data = other_it.second;
auto info_it = dump_info_.find(other_profile_location);
if (info_it == dump_info_.end()) {
auto ret =
dump_info_.insert(std::make_pair(other_profile_location, ProfileLineData(other_profile_data.checksum)));
ASSERT(ret.second);
info_it = ret.first;
}
info_it->second.method_wrapper_set.insert(other_profile_data.method_wrapper_set.begin(),
other_profile_data.method_wrapper_set.end());
info_it->second.class_wrapper_set.insert(other_profile_data.class_wrapper_set.begin(),
other_profile_data.class_wrapper_set.end());
}
return true;
}
bool ProfileDumpInfo::AddMethodsAndClasses(const PandaVector<ExtractedMethod> &methods,
const PandaSet<ExtractedResolvedClasses> &resolved_classes)
{
for (const ExtractedMethod &method : methods) {
if (!AddMethodWrapper(ConvertToString(method.panda_file_->GetFilename()),
method.panda_file_->GetHeader()->checksum, MethodWrapper(method.file_id_.GetOffset()))) {
return false;
}
}
for (const ExtractedResolvedClasses &class_resolved : resolved_classes) {
if (!AddResolvedClasses(class_resolved)) {
return false;
}
}
return true;
}
uint64_t ProfileDumpInfo::GetNumberOfMethods() const
{
uint64_t total = 0;
for (const auto &it : dump_info_) {
total += it.second.method_wrapper_set.size();
}
return total;
}
uint64_t ProfileDumpInfo::GetNumberOfResolvedClasses() const
{
uint64_t total = 0;
for (const auto &it : dump_info_) {
total += it.second.class_wrapper_set.size();
}
return total;
}
bool ProfileDumpInfo::ContainsMethod(const ExtractedMethod &method_ref) const
{
auto info_it = dump_info_.find(ConvertToString(method_ref.panda_file_->GetFilename()));
if (info_it != dump_info_.end()) {
if (method_ref.panda_file_->GetHeader()->checksum != info_it->second.checksum) {
return false;
}
const PandaSet<MethodWrapper> &methods = info_it->second.method_wrapper_set;
return methods.find(MethodWrapper(method_ref.file_id_.GetOffset())) != methods.end();
}
return false;
}
bool ProfileDumpInfo::ContainsClass(const panda_file::File &pandafile, uint32_t class_def_idx) const
{
auto info_it = dump_info_.find(ConvertToString(pandafile.GetFilename()));
if (info_it != dump_info_.end()) {
if (pandafile.GetHeader()->checksum != info_it->second.checksum) {
return false;
}
const PandaSet<ClassWrapper> &classes = info_it->second.class_wrapper_set;
return classes.find(ClassWrapper(class_def_idx)) != classes.end();
}
return false;
}
bool ProfileDumpInfo::AddMethodWrapper(const PandaString &panda_file_location, uint32_t checksum,
const ProfileDumpInfo::MethodWrapper &method_to_add)
{
ProfileLineData *const DATA = GetOrAddProfileLineData(panda_file_location, checksum);
if (DATA == nullptr) {
return false;
}
DATA->method_wrapper_set.insert(method_to_add);
return true;
}
bool ProfileDumpInfo::AddClassWrapper(const PandaString &panda_file_location, uint32_t checksum,
const ProfileDumpInfo::ClassWrapper &class_to_add)
{
ProfileLineData *const DATA = GetOrAddProfileLineData(panda_file_location, checksum);
if (DATA == nullptr) {
return false;
}
DATA->class_wrapper_set.insert(class_to_add);
return true;
}
bool ProfileDumpInfo::AddResolvedClasses(const ExtractedResolvedClasses &classes)
{ // NOLINT(readability-identifier-naming)
const PandaString panda_file_location = classes.GetPandaFileLocation(); // NOLINT(readability-identifier-naming)
const uint32_t checksum = classes.GetPandaFileChecksum(); // NOLINT(readability-identifier-naming)
ProfileLineData *const DATA = GetOrAddProfileLineData(panda_file_location, checksum);
if (DATA == nullptr) {
return false;
}
for (auto const &i : classes.GetClasses()) {
DATA->class_wrapper_set.insert(ClassWrapper(i));
}
return true;
}
ProfileDumpInfo::ProfileLineData *ProfileDumpInfo::GetOrAddProfileLineData(const PandaString &panda_file_location,
uint32_t checksum)
{
auto info_it = dump_info_.find(panda_file_location);
if (info_it == dump_info_.end()) {
auto ret = dump_info_.insert(std::make_pair(panda_file_location, ProfileLineData(checksum)));
ASSERT(ret.second);
info_it = ret.first;
}
if (info_it->second.checksum != checksum) {
LOG(INFO, RUNTIME) << "Checksum mismatch" << panda_file_location;
return nullptr;
}
return &(info_it->second);
}
bool ProfileDumpInfo::Save(int fd)
{
ASSERT(fd >= 0);
trace::ScopedTrace scoped_trace(__PRETTY_FUNCTION__);
static constexpr size_t K_MAX_BUFFER_SIZE = 8 * 1024;
PandaVector<uint8_t> buffer; // each element 1 byte
WriteBuffer(fd, kProfileMagic, sizeof(kProfileMagic));
WriteBuffer(fd, kProfileVersion, sizeof(kProfileVersion));
AddUintToBuffer(&buffer, static_cast<uint32_t>(dump_info_.size()));
for (const auto &it : dump_info_) {
if (buffer.size() > K_MAX_BUFFER_SIZE) {
if (!WriteBuffer(fd, buffer.data(), buffer.size())) {
return false;
}
buffer.clear();
}
const PandaString &file_location = it.first;
const ProfileLineData &file_data = it.second;
if (file_location.size() >= K_MAX_FILE_KEY_LENGTH) {
LOG(INFO, RUNTIME) << "PandaFileKey exceeds allocated limit";
return false;
}
size_t required_capacity = buffer.size() + K_LINE_HEADER_SIZE + file_location.size() +
K_METHOD_BYTES * file_data.method_wrapper_set.size() +
K_CLASS_BYTES * file_data.class_wrapper_set.size();
buffer.reserve(required_capacity);
ASSERT(file_location.size() <= std::numeric_limits<uint16_t>::max());
ASSERT(file_data.method_wrapper_set.size() <= std::numeric_limits<uint32_t>::max());
ASSERT(file_data.class_wrapper_set.size() <= std::numeric_limits<uint32_t>::max());
AddUintToBuffer(&buffer, static_cast<uint16_t>(file_location.size()));
AddUintToBuffer(&buffer, static_cast<uint32_t>(file_data.method_wrapper_set.size()));
AddUintToBuffer(&buffer, static_cast<uint32_t>(file_data.class_wrapper_set.size()));
AddUintToBuffer(&buffer, file_data.checksum);
AddStringToBuffer(&buffer, file_location);
if (UNLIKELY(file_data.empty())) {
LOG(INFO, RUNTIME) << "EMPTY FILE DATA, WERIED!";
}
for (auto method_it : file_data.method_wrapper_set) {
AddUintToBuffer(&buffer, method_it.method_id_);
}
for (auto class_it : file_data.class_wrapper_set) {
AddUintToBuffer(&buffer, class_it.class_id_);
}
ASSERT(required_capacity == buffer.size());
}
return WriteBuffer(fd, buffer.data(), buffer.size());
}
bool ProfileDumpInfo::Load(int fd)
{
trace::ScopedTrace scoped_trace(__PRETTY_FUNCTION__);
PandaString error;
ProfileLoadSatus status = LoadInternal(fd, &error);
if (status == PROFILE_LOAD_SUCCESS) {
return true;
}
LOG(INFO, RUNTIME) << "Error when reading profile " << error;
return false;
}
ProfileDumpInfo::ProfileLoadSatus ProfileDumpInfo::LoadInternal(int fd, PandaString *error)
{
ASSERT(fd >= 0);
trace::ScopedTrace scoped_trace(__PRETTY_FUNCTION__);
struct stat stat_buffer {
};
if (fstat(fd, &stat_buffer) != 0) {
return PROFILE_LOAD_IO_ERROR;
}
if (stat_buffer.st_size == 0) {
LOG(INFO, RUNTIME) << "empty file";
return PROFILE_LOAD_EMPTYFILE;
}
uint32_t number_of_lines;
ProfileLoadSatus status = ReadProfileHeader(fd, &number_of_lines, error);
if (status != PROFILE_LOAD_SUCCESS) {
return status;
}
LOG(INFO, RUNTIME) << "number of profile items = " << number_of_lines;
while (number_of_lines > 0) {
ProfileLineHeader line_header;
status = ReadProfileLineHeader(fd, &line_header, error);
if (status != PROFILE_LOAD_SUCCESS) {
return status;
}
status = ReadProfileLine(fd, line_header, error);
if (status != PROFILE_LOAD_SUCCESS) {
return status;
}
number_of_lines--;
}
int result = testEOF(fd);
if (result == 0) {
return PROFILE_LOAD_SUCCESS;
}
if (result < 0) {
return PROFILE_LOAD_IO_ERROR;
}
*error = "Unexpected content in the profile file";
return PROFILE_LOAD_BAD_DATA;
}
ProfileDumpInfo::ProfileLoadSatus ProfileDumpInfo::ReadProfileHeader(int fd, uint32_t *number_of_lines,
PandaString *error)
{
const size_t K_MAGIC_VERSION_SIZE = sizeof(kProfileMagic) + sizeof(kProfileVersion) + sizeof(uint32_t);
SerializerBuffer safe_buffer(K_MAGIC_VERSION_SIZE);
ProfileLoadSatus status = safe_buffer.FillFromFd(fd, "ReadProfileHeader", error);
if (status != PROFILE_LOAD_SUCCESS) {
return status;
}
if (!safe_buffer.CompareAndAdvance(kProfileMagic, sizeof(kProfileMagic))) {
*error = "Profile missing magic";
return PROFILE_LOAD_VERSION_MISMATCH;
}
if (!safe_buffer.CompareAndAdvance(kProfileVersion, sizeof(kProfileVersion))) {
*error = "Profile version mismatch";
return PROFILE_LOAD_VERSION_MISMATCH;
}
*number_of_lines = safe_buffer.ReadUintAndAdvance<uint32_t>();
return PROFILE_LOAD_SUCCESS;
}
ProfileDumpInfo::ProfileLoadSatus ProfileDumpInfo::ReadProfileLineHeader(int fd, ProfileLineHeader *line_header,
PandaString *error)
{
SerializerBuffer header_buffer(K_LINE_HEADER_SIZE);
ProfileLoadSatus status = header_buffer.FillFromFd(fd, "ReadProfileLineHeader", error);
if (status != PROFILE_LOAD_SUCCESS) {
return status;
}
auto panda_location_size = header_buffer.ReadUintAndAdvance<uint16_t>(); // max chars in location, 4096 = 2 ^ 12
line_header->method_set_size = header_buffer.ReadUintAndAdvance<uint32_t>();
line_header->class_set_size = header_buffer.ReadUintAndAdvance<uint32_t>();
line_header->checksum = header_buffer.ReadUintAndAdvance<uint32_t>();
if (panda_location_size == 0 || panda_location_size > K_MAX_FILE_KEY_LENGTH) {
*error = "PandaFileKey has an invalid size: " + std::to_string(panda_location_size);
return PROFILE_LOAD_BAD_DATA;
}
SerializerBuffer location_buffer(panda_location_size);
// Read the binary data: location string
status = location_buffer.FillFromFd(fd, "ReadProfileLineHeader", error);
if (status != PROFILE_LOAD_SUCCESS) {
return status;
}
line_header->panda_file_location.assign(reinterpret_cast<char *>(location_buffer.Get()), panda_location_size);
return PROFILE_LOAD_SUCCESS;
}
ProfileDumpInfo::ProfileLoadSatus ProfileDumpInfo::ReadProfileLine(int fd, const ProfileLineHeader &line_header,
PandaString *error)
{
static constexpr uint32_t K_MAX_NUMBER_OF_ENTRIES_TO_READ = 8000; // ~8 kb
uint32_t methods_left_to_read = line_header.method_set_size;
uint32_t classes_left_to_read = line_header.class_set_size;
while ((methods_left_to_read > 0) || (classes_left_to_read > 0)) {
uint32_t methods_to_read = std::min(K_MAX_NUMBER_OF_ENTRIES_TO_READ, methods_left_to_read);
uint32_t max_classes_to_read = K_MAX_NUMBER_OF_ENTRIES_TO_READ - methods_to_read; // >=0
uint32_t classes_to_read = std::min(max_classes_to_read, classes_left_to_read);
size_t line_size = K_METHOD_BYTES * methods_to_read + K_CLASS_BYTES * classes_to_read;
SerializerBuffer line_buffer(line_size);
ProfileLoadSatus status = line_buffer.FillFromFd(fd, "ReadProfileLine", error);
if (status != PROFILE_LOAD_SUCCESS) {
return status;
}
if (!ProcessLine(line_buffer, methods_to_read, classes_to_read, line_header.checksum,
line_header.panda_file_location)) {
*error = "Error when reading profile file line";
return PROFILE_LOAD_BAD_DATA;
}
methods_left_to_read -= methods_to_read;
classes_left_to_read -= classes_to_read;
}
return PROFILE_LOAD_SUCCESS;
}
// NOLINTNEXTLINE(google-runtime-references)
bool ProfileDumpInfo::ProcessLine(SerializerBuffer &line_buffer, uint32_t method_set_size, uint32_t class_set_size,
uint32_t checksum, const PandaString &panda_file_location)
{
for (uint32_t i = 0; i < method_set_size; i++) {
// NB! Read the method info from buffer...
auto method_idx = line_buffer.ReadUintAndAdvance<uint32_t>();
if (!AddMethodWrapper(panda_file_location, checksum, MethodWrapper(method_idx))) {
return false;
}
}
for (uint32_t i = 0; i < class_set_size; i++) {
auto class_def_idx = line_buffer.ReadUintAndAdvance<uint32_t>();
if (!AddClassWrapper(panda_file_location, checksum, ClassWrapper(class_def_idx))) {
return false;
}
}
return true;
}
bool ProfileDumpInfo::MergeAndSave(const PandaString &filename, uint64_t *bytes_written, bool force)
{
// NB! we using READWRITE mode to leave the creation job to framework layer.
panda::os::unix::file::File myfile = panda::os::file::Open(filename, panda::os::file::Mode::READWRITE);
if (!myfile.IsValid()) {
LOG(ERROR, RUNTIME) << "Cannot open the profile file" << filename;
return false;
}
panda::os::file::FileHolder fholder(myfile);
int fd = myfile.GetFd();
LOG(INFO, RUNTIME) << " Step3.2: starting merging ***";
PandaString error;
ProfileDumpInfo file_dump_info;
ProfileLoadSatus status = file_dump_info.LoadInternal(fd, &error);
if (status == PROFILE_LOAD_SUCCESS || status == PROFILE_LOAD_EMPTYFILE) {
if (MergeWith(file_dump_info)) {
if (dump_info_ == file_dump_info.dump_info_) {
if (bytes_written != nullptr) {
*bytes_written = 0;
}
LOG(INFO, RUNTIME) << " No Saving as no change byte_written = 0";
if (status != PROFILE_LOAD_EMPTYFILE) {
return true;
}
}
} else {
LOG(INFO, RUNTIME) << " No Saving as Could not merge previous profile data from file " << filename;
if (!force) {
return false;
}
}
} else if (force && ((status == PROFILE_LOAD_VERSION_MISMATCH) || (status == PROFILE_LOAD_BAD_DATA))) {
LOG(INFO, RUNTIME) << " Clearing bad or mismatch version profile data from file " << filename << ": " << error;
} else {
LOG(INFO, RUNTIME) << " No Saving as Could not load profile data from file " << filename << ": " << error;
return false;
}
LOG(INFO, RUNTIME) << " Step3.3: starting Saving ***";
LOG(INFO, RUNTIME) << " clear file data firstly";
if (!myfile.ClearData()) {
LOG(INFO, RUNTIME) << "Could not clear profile file: " << filename;
return false;
}
bool result = Save(fd);
if (result) {
if (bytes_written != nullptr) {
LOG(INFO, RUNTIME) << " Profile Saver Bingo! and bytes written = " << bytes_written;
*bytes_written = GetFileSizeBytes(filename);
}
} else {
LOG(ERROR, RUNTIME) << "Failed to save profile info to " << filename;
}
return result;
}
} // namespace panda
-289
View File
@@ -1,289 +0,0 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* 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 PANDA_RUNTIME_PROFILESAVER_PROFILE_DUMP_INFO_H_
#define PANDA_RUNTIME_PROFILESAVER_PROFILE_DUMP_INFO_H_
#include <map>
#include <set>
#include <string>
#include <unordered_set>
#include <vector>
#include "libpandabase/utils/logger.h"
#include "libpandafile/file.h"
#include "runtime/include/mem/panda_containers.h"
#include "runtime/include/mem/panda_smart_pointers.h"
#include "runtime/include/mem/panda_string.h"
// NB! suppose that, panda file can always provide such profile file format data!
// NB! we use serializer saving way which means the profile file is just binary file!
// profile header
// magic
// version
// checksum?(ommit)
// #lines
// Line1:
// profileline header
// file location
// #method
// #class
// checksum
// methods index/id(#method)
// class index/id(#class)
// LineN:
// ...
namespace panda {
/*
* Any newly added information, we have to change the following info naturely, especially
* ExtractedResolvedClasses
*/
struct ExtractedMethod {
ExtractedMethod(const panda_file::File *file, panda_file::File::EntityId file_id)
: panda_file_(file), file_id_(file_id)
{
}
const panda_file::File *panda_file_; // NOLINT(misc-non-private-member-variables-in-classes)
panda_file::File::EntityId file_id_; // NOLINT(misc-non-private-member-variables-in-classes)
};
struct ExtractedResolvedClasses {
public:
// NOLINTNEXTLINE(modernize-pass-by-value)
ExtractedResolvedClasses(const PandaString &location, uint32_t checksum)
: panda_file_location_(location), panda_file_checksum_(checksum)
{
}
int Compare(const ExtractedResolvedClasses &other) const
{
if (panda_file_checksum_ != other.panda_file_checksum_) {
return static_cast<int>(panda_file_checksum_ - other.panda_file_checksum_);
}
return panda_file_location_.compare(other.panda_file_location_);
}
template <class InputIt>
void AddClasses(InputIt begin, InputIt end) const
{
classes_.insert(begin, end);
}
void AddClass(uint32_t classindex) const
{
classes_.insert(classindex);
}
// NOLINTNEXTLINE(readability-const-return-type)
const PandaString GetPandaFileLocation() const
{
return panda_file_location_;
}
uint32_t GetPandaFileChecksum() const
{
return panda_file_checksum_;
}
const PandaUnorderedSet<uint32_t> &GetClasses() const
{
return classes_;
}
private:
const PandaString panda_file_location_; // NOLINT(readability-identifier-naming)
const uint32_t panda_file_checksum_; // NOLINT(readability-identifier-naming)
// Array of resolved class def indexes. we leave this as extention
mutable PandaUnorderedSet<uint32_t> classes_;
};
// we define this for PandaSet find() function
inline bool operator<(const ExtractedResolvedClasses &a, const ExtractedResolvedClasses &b)
{
return a.Compare(b) < 0;
}
class ProfileDumpInfo {
public:
// Content of profile header
static const uint8_t kProfileMagic[]; // NOLINT(modernize-avoid-c-arrays, readability-identifier-naming)
static const uint8_t kProfileVersion[]; // NOLINT(modernize-avoid-c-arrays, readability-identifier-naming)
/*
* Saves the profile data to the given file descriptor.
*/
bool Save(int fd);
/*
* Loads profile information from the given file descriptor.
*/
bool Load(int fd);
/*
* Merge the data from another ProfileDumpInfo into the current object.
*/
bool MergeWith(const ProfileDumpInfo &other);
/*
* Add the given methods and classes to the current profile object
*/
bool AddMethodsAndClasses(const PandaVector<ExtractedMethod> &methods,
const PandaSet<ExtractedResolvedClasses> &resolved_classes);
/*
* Loads and merges profile information from the given file into the current cache
* object and tries to save it back to disk.
*
* If `force` is true then the save will be forced regardless of bad data or mismatched version.
*/
bool MergeAndSave(const PandaString &filename, uint64_t *bytes_written, bool force);
/*
* Returns the number of methods that were profiled.
*/
uint64_t GetNumberOfMethods() const;
/*
* Returns the number of resolved classes that were profiled.
*/
uint64_t GetNumberOfResolvedClasses() const;
/*
* Returns true if the method reference is present in the profiling info.
*/
bool ContainsMethod(const ExtractedMethod &method_ref) const;
/*
* Returns true if the class is present in the profiling info.
*/
bool ContainsClass(const panda_file::File &pandafile, uint32_t class_def_idx) const;
private:
enum ProfileLoadSatus {
PROFILE_LOAD_IO_ERROR,
PROFILE_LOAD_VERSION_MISMATCH,
PROFILE_LOAD_BAD_DATA,
PROFILE_LOAD_EMPTYFILE,
PROFILE_LOAD_SUCCESS
};
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
struct ProfileLineHeader {
PandaString panda_file_location;
uint32_t method_set_size;
uint32_t class_set_size;
uint32_t checksum;
};
// A helper structure to make sure we don't read past our buffers in the loops.
struct SerializerBuffer {
public:
explicit SerializerBuffer(size_t size)
{
// NOLINTNEXTLINE(modernize-avoid-c-arrays)
storage_ = MakePandaUnique<uint8_t[]>(size);
ptr_current_ = storage_.get();
ptr_end_ = ptr_current_ + size; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic
}
ProfileLoadSatus FillFromFd(int fd, const PandaString &source, PandaString *error);
template <typename T>
T ReadUintAndAdvance();
bool CompareAndAdvance(const uint8_t *data, size_t data_size);
uint8_t *Get()
{
return storage_.get();
}
private:
PandaUniquePtr<uint8_t[]> storage_; // NOLINT(modernize-avoid-c-arrays)
uint8_t *ptr_current_;
uint8_t *ptr_end_;
};
struct MethodWrapper {
explicit MethodWrapper(uint32_t index) : method_id_(index) {}
uint32_t method_id_; // NOLINT(misc-non-private-member-variables-in-classes)
bool operator==(const MethodWrapper &other) const
{
return method_id_ == other.method_id_;
}
bool operator<(const MethodWrapper &other) const
{
return method_id_ < other.method_id_;
}
};
struct ClassWrapper {
explicit ClassWrapper(uint32_t index) : class_id_(index) {}
uint32_t class_id_; // NOLINT(misc-non-private-member-variables-in-classes)
bool operator==(const ClassWrapper &other) const
{
return class_id_ == other.class_id_;
}
bool operator<(const ClassWrapper &other) const
{
return class_id_ < other.class_id_;
}
};
struct ProfileLineData {
explicit ProfileLineData(uint32_t file_checksum) : checksum(file_checksum) {}
uint32_t checksum; // NOLINT(misc-non-private-member-variables-in-classes)
PandaSet<MethodWrapper> method_wrapper_set; // NOLINT(misc-non-private-member-variables-in-classes)
PandaSet<ClassWrapper> class_wrapper_set; // NOLINT(misc-non-private-member-variables-in-classes)
bool operator==(const ProfileLineData &other) const
{
return checksum == other.checksum && method_wrapper_set == other.method_wrapper_set &&
class_wrapper_set == other.class_wrapper_set;
}
// NOLINTNEXTLINE(readability-identifier-naming)
bool empty() const
{
return method_wrapper_set.empty() && class_wrapper_set.empty();
}
};
ProfileLoadSatus LoadInternal(int fd, PandaString *error);
ProfileLoadSatus ReadProfileHeader(int fd, uint32_t *number_of_lines, PandaString *error);
ProfileLoadSatus ReadProfileLineHeader(int fd, ProfileLineHeader *line_header, PandaString *error);
ProfileLoadSatus ReadProfileLine(int fd, const ProfileLineHeader &line_header, PandaString *error);
// NOLINTNEXTLINE(google-runtime-references)
bool ProcessLine(SerializerBuffer &line_buffer, uint32_t method_set_size, uint32_t class_set_size,
uint32_t checksum, const PandaString &panda_file_location);
bool AddMethodWrapper(const PandaString &panda_file_location, uint32_t checksum,
const MethodWrapper &method_to_add);
bool AddClassWrapper(const PandaString &panda_file_location, uint32_t checksum, const ClassWrapper &class_to_add);
bool AddResolvedClasses(const ExtractedResolvedClasses &classes);
ProfileLineData *GetOrAddProfileLineData(const PandaString &panda_file_location, uint32_t checksum);
PandaMap<const PandaString, ProfileLineData> dump_info_;
};
} // namespace panda
#endif // PANDA_RUNTIME_PROFILESAVER_PROFILE_DUMP_INFO_H_
-333
View File
@@ -1,333 +0,0 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* 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.
*/
#include "runtime/profilesaver/profile_saver.h"
#include <cerrno>
#include <chrono>
#include <thread>
#include "runtime/include/class_linker.h"
#include "runtime/include/runtime.h"
#include "runtime/jit/jit.h"
#include "trace/trace.h"
namespace panda {
ProfileSaver *ProfileSaver::instance = nullptr;
// NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
std::thread ProfileSaver::profiler_saver_daemon_thread;
static bool CheckLocationForCompilation(const PandaString &location)
{
return !location.empty();
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
ProfileSaver::ProfileSaver(const PandaString &output_filename, const PandaVector<PandaString> &code_paths,
const PandaString &app_dir)
: shutting_down_(false)
{
AddTrackedLocations(output_filename, code_paths, app_dir);
}
// NB! it is the caller's responsibility to pass suitable output_filename, code_paths as well as app_data_dir.
void ProfileSaver::AddTrackedLocations(const PandaString &output_filename, const PandaVector<PandaString> &code_paths,
const PandaString &app_data_dir)
{
auto it = tracked_pandafile_base_locations_.find(output_filename);
if (it == tracked_pandafile_base_locations_.end()) {
tracked_pandafile_base_locations_.insert(
std::make_pair(output_filename, PandaSet<PandaString>(code_paths.begin(), code_paths.end())));
if (!app_data_dir.empty()) {
app_data_dirs_.insert(app_data_dir);
}
} else {
if (UNLIKELY(app_data_dirs_.count(app_data_dir) <= 0)) {
LOG(INFO, RUNTIME) << "Cannot find app dir, bad output filename";
return;
}
it->second.insert(code_paths.begin(), code_paths.end());
}
}
void ProfileSaver::Start(const PandaString &output_filename, const PandaVector<PandaString> &code_paths,
const PandaString &app_data_dir)
{
if (Runtime::GetCurrent() == nullptr) {
LOG(ERROR, RUNTIME) << "Runtime is nullptr";
return;
}
if (!Runtime::GetCurrent()->SaveProfileInfo()) {
LOG(ERROR, RUNTIME) << "ProfileSaver is forbidden";
return;
}
if (output_filename.empty()) {
LOG(ERROR, RUNTIME) << "Invalid output filename";
return;
}
PandaVector<PandaString> code_paths_to_profile;
for (const PandaString &location : code_paths) {
if (CheckLocationForCompilation(location)) {
code_paths_to_profile.push_back(location);
}
}
if (code_paths_to_profile.empty()) {
LOG(INFO, RUNTIME) << "No code paths should be profiled.";
return;
}
if (UNLIKELY(instance != nullptr)) {
LOG(INFO, RUNTIME) << "Profile Saver Singleton already exists";
instance->AddTrackedLocations(output_filename, code_paths_to_profile, app_data_dir);
return;
}
LOG(INFO, RUNTIME) << "Starting dumping profile saver output file" << output_filename;
instance = new ProfileSaver(output_filename, code_paths_to_profile, app_data_dir);
profiler_saver_daemon_thread = std::thread(ProfileSaver::RunProfileSaverThread, reinterpret_cast<void *>(instance));
}
void ProfileSaver::Stop(bool dump_info)
{
{
os::memory::LockHolder lock(profile_saver_lock_);
if (instance == nullptr) {
LOG(ERROR, RUNTIME) << "Tried to stop a profile saver which was not started";
return;
}
if (instance->shutting_down_) {
LOG(ERROR, RUNTIME) << "Tried to stop the profile saver twice";
return;
}
instance->shutting_down_ = true;
if (dump_info) {
instance->DumpInfo();
}
}
// Wait for the saver thread to stop.
// NB! we must release profile_saver_lock_ here.
profiler_saver_daemon_thread.join();
// Kill the singleton ...
delete instance;
instance = nullptr;
}
bool ProfileSaver::IsStarted()
{
return instance != nullptr;
}
void ProfileSaver::DumpInfo()
{
LOG(INFO, RUNTIME) << "ProfileSaver stopped" << '\n';
}
void *ProfileSaver::RunProfileSaverThread(void *arg)
{
// NOLINTNEXTLINE(hicpp-use-auto, modernize-use-auto)
ProfileSaver *profile_saver = reinterpret_cast<ProfileSaver *>(arg);
profile_saver->Run();
LOG(INFO, RUNTIME) << "Profile saver shutdown";
return nullptr;
}
void ProfileSaver::Run()
{
while (!ShuttingDown()) {
LOG(INFO, RUNTIME) << "Step1: Time Sleeping >>>>>>> ";
uint32_t sleepytime = Runtime::GetOptions().GetProfilesaverSleepingTimeMs();
constexpr uint32_t TIME_SECONDS_IN_MS = 1000;
for (int i = 0; i < static_cast<int>(sleepytime / TIME_SECONDS_IN_MS); ++i) {
std::this_thread::sleep_for(std::chrono::seconds(1));
if (ShuttingDown()) {
break;
}
}
LOG(INFO, RUNTIME) << "Step2: tranverse the resolved class and methods >>>>>>> ";
TranverseAndCacheResolvedClassAndMethods();
LOG(INFO, RUNTIME) << "Step3: merge current profile file and save it back >>>>>>> ";
MergeAndDumpProfileData();
}
}
bool ProfileSaver::ShuttingDown()
{
os::memory::LockHolder lock(profile_saver_lock_);
return shutting_down_;
}
void ProfileSaver::TranverseAndCacheResolvedClassAndMethods()
{
trace::ScopedTrace scoped_trace(__PRETTY_FUNCTION__);
PandaSet<ExtractedResolvedClasses> resolved_classes;
PandaVector<ExtractedMethod> methods;
auto call_back = [&resolved_classes, &methods](Class *klass) -> bool {
const panda_file::File *pandafile = klass->GetPandaFile();
panda_file::File::EntityId classfieldid = klass->GetFileId();
if (pandafile == nullptr) {
LOG(INFO, RUNTIME) << "panda file is nullptr";
return false;
}
LOG(INFO, RUNTIME) << " pandafile name = " << pandafile->GetFilename()
<< " classname = " << klass->GetName();
Span<Method> tmp_methods = klass->GetMethods();
LOG(INFO, RUNTIME) << " methods size = " << tmp_methods.size();
for (int i = 0; i < static_cast<int>(tmp_methods.Size()); ++i) {
Method &method = tmp_methods[i];
if (!method.IsNative()) {
if (method.GetHotnessCounter() >= K_MIN_PROFILE_THRESHOLD) {
ASSERT(method.GetPandaFile() != nullptr);
LOG(INFO, RUNTIME) << " method pandafile name = " << method.GetPandaFile()->GetFilename();
methods.emplace_back(ExtractedMethod(method.GetPandaFile(), method.GetFileId()));
}
}
}
ExtractedResolvedClasses tmp_resolved_classes(ConvertToString(pandafile->GetFilename()),
pandafile->GetHeader()->checksum);
LOG(INFO, RUNTIME) << " Add class " << klass->GetName();
auto it = resolved_classes.find(tmp_resolved_classes);
if (it != resolved_classes.end()) {
it->AddClass(classfieldid.GetOffset());
} else {
tmp_resolved_classes.AddClass(classfieldid.GetOffset());
resolved_classes.insert(tmp_resolved_classes);
}
return true;
};
// NB: classliner == nullptr
if (Runtime::GetCurrent()->GetClassLinker() == nullptr) {
LOG(INFO, RUNTIME) << "classliner is nullptr";
return;
}
LOG(INFO, RUNTIME) << " Step2.1: tranverse the resolved class and methods";
Runtime::GetCurrent()->GetClassLinker()->EnumerateClasses(call_back);
LOG(INFO, RUNTIME) << " Step2.2: starting tracking all the pandafile locations and flush the cache";
for (const auto &it : tracked_pandafile_base_locations_) {
const PandaString &filename = it.first;
const PandaSet<PandaString> &locations = it.second;
PandaSet<ExtractedResolvedClasses> resolved_classes_for_location;
PandaVector<ExtractedMethod> methods_for_location;
LOG(INFO, RUNTIME) << " all the locations are:";
for (auto const &iter : locations) {
LOG(INFO, RUNTIME) << iter << " ";
}
LOG(INFO, RUNTIME) << " Methods name : ";
for (const ExtractedMethod &ref : methods) {
LOG(INFO, RUNTIME) << " " << ref.panda_file_->GetFilename();
if (locations.find(ConvertToString(ref.panda_file_->GetFilename())) != locations.end()) {
LOG(INFO, RUNTIME) << " bingo method!";
methods_for_location.push_back(ref);
}
}
LOG(INFO, RUNTIME) << std::endl;
LOG(INFO, RUNTIME) << " Classes name";
for (const ExtractedResolvedClasses &classes : resolved_classes) {
LOG(INFO, RUNTIME) << " " << classes.GetPandaFileLocation();
if (locations.find(classes.GetPandaFileLocation()) != locations.end()) {
LOG(INFO, RUNTIME) << " bingo class!";
resolved_classes_for_location.insert(classes);
}
}
ProfileDumpInfo *info = GetOrAddCachedProfiledInfo(filename);
LOG(INFO, RUNTIME) << " Adding Bingo Methods and Classes";
info->AddMethodsAndClasses(methods_for_location, resolved_classes_for_location);
}
}
ProfileDumpInfo *ProfileSaver::GetOrAddCachedProfiledInfo(const PandaString &filename)
{
auto info_it = profile_cache_.find(filename);
if (info_it == profile_cache_.end()) {
LOG(INFO, RUNTIME) << " bingo profile_cache_!";
auto ret = profile_cache_.insert(std::make_pair(filename, ProfileDumpInfo()));
ASSERT(ret.second);
info_it = ret.first;
}
return &(info_it->second);
}
ProfileSaver::CntStats *ProfileSaver::GetOrAddCachedProfiledStatsInfo(const PandaString &filename)
{
auto info_it = statcache.find(filename);
if (info_it == statcache.end()) {
LOG(INFO, RUNTIME) << " bingo StatsInfo_cache_!";
auto ret = statcache.insert(std::make_pair(filename, CntStats()));
ASSERT(ret.second);
info_it = ret.first;
}
return &(info_it->second);
}
void ProfileSaver::MergeAndDumpProfileData()
{
trace::ScopedTrace scoped_trace(__PRETTY_FUNCTION__);
for (const auto &it : tracked_pandafile_base_locations_) {
if (ShuttingDown()) {
return;
}
const PandaString &filename = it.first;
LOG(INFO, RUNTIME) << " Step3.1 starting merging and save the following file ***";
LOG(INFO, RUNTIME) << " filename = " << filename;
ProfileDumpInfo *cached_info = GetOrAddCachedProfiledInfo(filename);
CntStats *cached_stat = GetOrAddCachedProfiledStatsInfo(filename);
ASSERT(cached_info->GetNumberOfMethods() >= cached_stat->GetMethodCount());
ASSERT(cached_info->GetNumberOfResolvedClasses() >= cached_stat->GetClassCount());
uint64_t delta_number_of_methods = cached_info->GetNumberOfMethods() - cached_stat->GetMethodCount();
uint64_t delta_number_of_classes = cached_info->GetNumberOfResolvedClasses() - cached_stat->GetClassCount();
uint64_t numthreshold = Runtime::GetOptions().GetProfilesaverDeltaNumberThreshold();
if (delta_number_of_methods < numthreshold && delta_number_of_classes < numthreshold) {
LOG(INFO, RUNTIME) << " number of delta number/class not enough";
continue;
}
uint64_t bytes_written;
if (cached_info->MergeAndSave(filename, &bytes_written, true)) {
cached_stat->SetMethodCount(cached_info->GetNumberOfMethods());
cached_stat->SetClassCount(cached_info->GetNumberOfResolvedClasses());
} else {
LOG(INFO, RUNTIME) << "Could not save profiling info to " << filename;
}
}
}
} // namespace panda
-170
View File
@@ -1,170 +0,0 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* 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 PANDA_RUNTIME_PROFILESAVER_PROFILE_SAVER_H_
#define PANDA_RUNTIME_PROFILESAVER_PROFILE_SAVER_H_
#include <pthread.h>
#include <map>
#include <set>
#include <string>
#include <thread>
#include <vector>
#include "libpandabase/macros.h"
#include "libpandabase/os/mutex.h"
#include "libpandabase/utils/logger.h"
#include "runtime/include/mem/panda_containers.h"
#include "runtime/include/mem/panda_string.h"
#include "runtime/profilesaver/profile_dump_info.h"
namespace panda {
// NOLINTNEXTLINE(fuchsia-statically-constructed-objects, readability-identifier-naming)
static os::memory::Mutex profile_saver_lock_;
/*
* Note well! we take singleton pattern, multi-threading scenario should be taken more serious considerations.
*
* e.g. Global Mutex Management or corresponding alternatives should better than
* global mutex profile_saver_lock_.
*
*/
// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions, hicpp-special-member-functions)
class ProfileSaver {
public:
/*
* start the profile saver deamon thread
*
* output_filename records the profile name, code_paths stores all the locations contain pandafile(aka *.aex)
* app_data_dir contains the location of application package
*/
static void Start(const PandaString &output_filename, const PandaVector<PandaString> &code_paths,
const PandaString &app_data_dir);
/*
* stop the profile saver deamon thread.
*
* if dump_info == true, dumps the debug information
*/
static void Stop(bool dump_info);
/*
* whether profile saver instance exists.
*/
static bool IsStarted();
~ProfileSaver() = default;
private:
ProfileSaver(const PandaString &output_filename, const PandaVector<PandaString> &code_paths,
const PandaString &app_dir);
void AddTrackedLocations(const PandaString &output_filename, const PandaVector<PandaString> &code_paths,
const PandaString &app_data_dir);
/*
* Callback for pthread_create, we attach/detach this thread to Runtime here
*/
static void *RunProfileSaverThread(void *arg);
/*
* Run loop for the saver.
*/
void Run();
/*
* Returns true if the saver is shutting down (ProfileSaver::Stop() has been called, will set this flag).
*/
bool ShuttingDown();
/*
* Dump functions, we leave it stub and for test until now.
*/
void DumpInfo();
/*
* Fetches the current resolved classes and methods from the ClassLinker and stores them in the profile_cache_.
*/
void TranverseAndCacheResolvedClassAndMethods();
/*
* Retrieves the cached ProfileDumpInfo for the given profile filename.
* If no entry exists, a new empty one will be created, added to the cache and then returned.
*/
ProfileDumpInfo *GetOrAddCachedProfiledInfo(const PandaString &filename);
/*
* Processes the existing profiling info from the jit code cache(if exists) and returns
* true if it needed to be saved back to disk.
*/
void MergeAndDumpProfileData();
static ProfileSaver *instance;
static std::thread profiler_saver_daemon_thread;
PandaMap<PandaString, PandaSet<PandaString>> tracked_pandafile_base_locations_;
PandaMap<PandaString, ProfileDumpInfo> profile_cache_;
PandaSet<PandaString> app_data_dirs_;
bool shutting_down_ GUARDED_BY(profile_saver_lock_);
struct CntStats {
public:
uint64_t GetMethodCount()
{
return last_save_number_of_methods_;
}
void SetMethodCount(uint64_t methodcnt)
{
last_save_number_of_methods_ = methodcnt;
}
uint64_t GetClassCount()
{
return last_save_number_of_classes_;
}
void SetClassCount(uint64_t classcnt)
{
last_save_number_of_classes_ = classcnt;
}
private:
uint64_t last_save_number_of_methods_ {0};
uint64_t last_save_number_of_classes_ {0};
};
PandaMap<PandaString, CntStats> statcache; // NOLINT(readability-identifier-naming)
/*
* Retrieves the cached CntStats for the given profile filename.
* If no entry exists, a new empty one will be created, added to the cache and then returned.
*/
CntStats *GetOrAddCachedProfiledStatsInfo(const PandaString &filename);
NO_COPY_SEMANTIC(ProfileSaver);
NO_MOVE_SEMANTIC(ProfileSaver);
};
} // namespace panda
#endif // PANDA_RUNTIME_PROFILESAVER_PROFILE_SAVER_H_
-10
View File
@@ -58,7 +58,6 @@
#include "runtime/mem/internal_allocator-inl.h"
#include "runtime/core/core_class_linker_extension.h"
#include "runtime/include/panda_vm.h"
#include "runtime/profilesaver/profile_saver.h"
#include "runtime/tooling/debugger.h"
#include "runtime/tooling/pt_lang_ext_private.h"
#include "runtime/include/file_manager.h"
@@ -307,12 +306,6 @@ bool Runtime::Destroy()
trace::ScopedTrace scoped_trace("Runtime shutdown");
instance->GetPandaVM()->StopGC();
// NB! stop the profile saver thread before deleting the thread list to avoid dead loop here.
// the following WaitForThreadStop makes sure profile saver can be shut down.
if (instance->SaveProfileInfo()) {
ProfileSaver::Stop(false);
}
instance->GetPandaVM()->UninitializeThreads();
verifier::JobQueue::Stop(instance->GetVerificationOptions().Mode.OnlyVerify);
@@ -883,9 +876,6 @@ void Runtime::RegisterAppInfo(const PandaVector<PandaString> &code_paths, const
}(profile_output_filename);
StartDProfiler(app_name);
// this is exactly the place where start the profile saver
ProfileSaver::Start(profile_output_filename, code_paths, PandaString(app_name));
}
int Runtime::StartDProfiler(std::string_view app_name)