mirror of
https://github.com/openharmony/ark_js_runtime.git
synced 2026-08-27 02:31:17 -04:00
61b6782b65
Description:Snapshot code optimization include modify class name SnapShotSerialize to SnapShotHandler, delete some magic number, add interface to acquire global env and global const object index. Issue:https://gitee.com/openharmony/ark_js_runtime/issues/I55CQ3 Signed-off-by: dingwen <dingwen6@huawei.com> Change-Id: I338028c5cfd4f992095f2bded2956e33f275bb1b
390 lines
13 KiB
C++
390 lines
13 KiB
C++
/*
|
|
* 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 <cstdio>
|
|
#include <fstream>
|
|
|
|
#include "ecmascript/accessor_data.h"
|
|
#include "ecmascript/ecma_vm.h"
|
|
#include "ecmascript/global_dictionary-inl.h"
|
|
#include "ecmascript/global_env.h"
|
|
#include "ecmascript/dfx/hprof/heap_profiler.h"
|
|
#include "ecmascript/dfx/hprof/heap_profiler_interface.h"
|
|
#include "ecmascript/dfx/hprof/heap_snapshot.h"
|
|
#include "ecmascript/dfx/hprof/heap_snapshot_json_serializer.h"
|
|
#include "ecmascript/dfx/hprof/string_hashmap.h"
|
|
#include "ecmascript/ic/ic_handler.h"
|
|
#include "ecmascript/ic/property_box.h"
|
|
#include "ecmascript/ic/proto_change_details.h"
|
|
#include "ecmascript/jobs/micro_job_queue.h"
|
|
#include "ecmascript/jobs/pending_job.h"
|
|
#include "ecmascript/jspandafile/program_object.h"
|
|
#include "ecmascript/js_arguments.h"
|
|
#include "ecmascript/js_array.h"
|
|
#include "ecmascript/js_array_iterator.h"
|
|
#include "ecmascript/js_arraybuffer.h"
|
|
#include "ecmascript/js_async_function.h"
|
|
#include "ecmascript/js_collator.h"
|
|
#include "ecmascript/js_dataview.h"
|
|
#include "ecmascript/js_date.h"
|
|
#include "ecmascript/js_date_time_format.h"
|
|
#include "ecmascript/js_for_in_iterator.h"
|
|
#include "ecmascript/js_function.h"
|
|
#include "ecmascript/js_generator_object.h"
|
|
#include "ecmascript/js_global_object.h"
|
|
#include "ecmascript/js_handle.h"
|
|
#include "ecmascript/js_intl.h"
|
|
#include "ecmascript/js_locale.h"
|
|
#include "ecmascript/js_map.h"
|
|
#include "ecmascript/js_map_iterator.h"
|
|
#include "ecmascript/js_number_format.h"
|
|
#include "ecmascript/js_object-inl.h"
|
|
#include "ecmascript/js_plural_rules.h"
|
|
#include "ecmascript/js_primitive_ref.h"
|
|
#include "ecmascript/js_promise.h"
|
|
#include "ecmascript/js_realm.h"
|
|
#include "ecmascript/js_regexp.h"
|
|
#include "ecmascript/js_relative_time_format.h"
|
|
#include "ecmascript/js_set.h"
|
|
#include "ecmascript/js_set_iterator.h"
|
|
#include "ecmascript/js_string_iterator.h"
|
|
#include "ecmascript/js_tagged_number.h"
|
|
#include "ecmascript/js_tagged_value-inl.h"
|
|
#include "ecmascript/js_thread.h"
|
|
#include "ecmascript/js_typed_array.h"
|
|
#include "ecmascript/js_weak_container.h"
|
|
#include "ecmascript/layout_info-inl.h"
|
|
#include "ecmascript/lexical_env.h"
|
|
#include "ecmascript/linked_hash_table.h"
|
|
#include "ecmascript/mem/assert_scope.h"
|
|
#include "ecmascript/mem/c_containers.h"
|
|
#include "ecmascript/mem/machine_code.h"
|
|
#include "ecmascript/object_factory.h"
|
|
#include "ecmascript/tagged_array.h"
|
|
#include "ecmascript/tagged_dictionary.h"
|
|
#include "ecmascript/template_map.h"
|
|
#include "ecmascript/tests/test_helper.h"
|
|
#include "ecmascript/transitions_dictionary.h"
|
|
|
|
using namespace panda::ecmascript;
|
|
using namespace panda::ecmascript::base;
|
|
|
|
namespace panda::test {
|
|
using MicroJobQueue = panda::ecmascript::job::MicroJobQueue;
|
|
using PendingJob = panda::ecmascript::job::PendingJob;
|
|
class HProfTest : public testing::Test {
|
|
public:
|
|
static void SetUpTestCase()
|
|
{
|
|
GTEST_LOG_(INFO) << "SetUpTestCase";
|
|
}
|
|
|
|
static void TearDownTestCase()
|
|
{
|
|
GTEST_LOG_(INFO) << "TearDownCase";
|
|
}
|
|
|
|
void SetUp() override
|
|
{
|
|
TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
|
|
}
|
|
|
|
void TearDown() override
|
|
{
|
|
TestHelper::DestroyEcmaVMWithScope(instance, scope);
|
|
}
|
|
EcmaVM *instance {nullptr};
|
|
EcmaHandleScope *scope {nullptr};
|
|
JSThread *thread {nullptr};
|
|
};
|
|
|
|
class HProfTestHelper {
|
|
public:
|
|
explicit HProfTestHelper(const CString &aFilePath) : filePath(aFilePath) {}
|
|
~HProfTestHelper() = default;
|
|
|
|
bool IsFileExist()
|
|
{
|
|
bool exist = false;
|
|
exist = SafeOpenFile();
|
|
SafeCloseFile();
|
|
return exist;
|
|
}
|
|
|
|
bool RemoveExistingFile()
|
|
{
|
|
int code = 0;
|
|
if (IsFileExist()) {
|
|
code = std::remove(filePath.c_str());
|
|
}
|
|
return code == 0 ? true : false;
|
|
}
|
|
|
|
bool GenerateHeapDump(JSThread *thread)
|
|
{
|
|
int retry = 2;
|
|
RemoveExistingFile();
|
|
HeapProfilerInterface::DumpHeapSnapshot(thread, DumpFormat::JSON, filePath);
|
|
while (!IsFileExist() && retry > 0) {
|
|
retry--;
|
|
HeapProfilerInterface::DumpHeapSnapshot(thread, DumpFormat::JSON, filePath);
|
|
}
|
|
return IsFileExist();
|
|
}
|
|
|
|
bool ContrastJSONLineHeader(int lineId, CString lineHeader)
|
|
{
|
|
bool allSame = false;
|
|
if (!SafeOpenFile()) { // No JSON File
|
|
allSame = false;
|
|
SafeCloseFile();
|
|
} else {
|
|
CString line;
|
|
int i = 1;
|
|
while (getline(inputFile, line)) {
|
|
if (i == lineId && line.find(lineHeader) != line.npos) {
|
|
allSame = true;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
SafeCloseFile();
|
|
}
|
|
|
|
return allSame;
|
|
}
|
|
|
|
bool ContrastJSONSectionPayload(CString dataLable, int fieldNum)
|
|
{
|
|
if (!SafeOpenFile()) { // No JSON File
|
|
SafeCloseFile();
|
|
return false;
|
|
} else {
|
|
CString line;
|
|
int i = 1;
|
|
while (getline(inputFile, line)) {
|
|
if (i > 10 && line.find(dataLable) != line.npos) { // 10 : Hit the line
|
|
CString::size_type pos = 0;
|
|
int loop = 0;
|
|
while ((pos = line.find(",", pos)) != line.npos) {
|
|
pos++;
|
|
loop++; // "," count
|
|
}
|
|
SafeCloseFile();
|
|
return loop == fieldNum - 1;
|
|
break;
|
|
}
|
|
i++; // Search the Next Line
|
|
}
|
|
SafeCloseFile();
|
|
}
|
|
return false; // Lost the Line
|
|
}
|
|
|
|
bool ContrastJSONClousure()
|
|
{
|
|
if (!SafeOpenFile()) { // No JSON File
|
|
SafeCloseFile();
|
|
return false;
|
|
}
|
|
CString lineBk; // The Last Line
|
|
CString line;
|
|
while (getline(inputFile, line)) {
|
|
lineBk = line;
|
|
}
|
|
SafeCloseFile();
|
|
return lineBk.compare("}") == 0;
|
|
}
|
|
|
|
int ExtractCountFromMeta(CString typeLable)
|
|
{
|
|
if (!SafeOpenFile()) { // No JSON File
|
|
SafeCloseFile();
|
|
return -1;
|
|
} else {
|
|
CString line;
|
|
int i = 1;
|
|
while (getline(inputFile, line)) {
|
|
int length = line.length() - typeLable.length() - 1;
|
|
if (line.find(typeLable) != line.npos) { // Get
|
|
if (line.find(",") == line.npos) { // "trace_function_count" end without ","
|
|
length = line.length() - typeLable.length();
|
|
}
|
|
line = line.substr(typeLable.length(), length);
|
|
SafeCloseFile();
|
|
return std::stoi(line.c_str());
|
|
}
|
|
i++;
|
|
}
|
|
SafeCloseFile();
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int ExtractCountFromPayload(CString dataLabel)
|
|
{
|
|
if (!SafeOpenFile()) { // No JSON File
|
|
SafeCloseFile();
|
|
return -1;
|
|
} else {
|
|
CString line;
|
|
bool hit = false;
|
|
int loop = 0;
|
|
while (getline(inputFile, line)) {
|
|
if (!hit && line.find(dataLabel) != line.npos) { // Get
|
|
loop += 1; // First Line
|
|
hit = true;
|
|
if (line.find("[]") != line.npos) { // Empty
|
|
loop = 0;
|
|
SafeCloseFile();
|
|
return loop;
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
if (hit) {
|
|
if (line.find("],") != line.npos) { // Reach End
|
|
loop += 1; // End Line
|
|
SafeCloseFile();
|
|
return loop;
|
|
} else {
|
|
loop++;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
SafeCloseFile();
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
private:
|
|
bool SafeOpenFile()
|
|
{
|
|
inputFile.clear();
|
|
inputFile.open(filePath.c_str(), std::ios::in);
|
|
int retry = 2;
|
|
while (!inputFile.good() && retry > 0) {
|
|
inputFile.open(filePath.c_str(), std::ios::in);
|
|
retry--;
|
|
}
|
|
return inputFile.good();
|
|
}
|
|
|
|
void SafeCloseFile()
|
|
{
|
|
inputFile.close();
|
|
inputFile.clear(); // Reset File status
|
|
}
|
|
CString filePath;
|
|
std::fstream inputFile {};
|
|
};
|
|
|
|
HWTEST_F_L0(HProfTest, GenerateFileForManualCheck)
|
|
{
|
|
HProfTestHelper tester("hprof_json_test.heapsnapshot");
|
|
ASSERT_TRUE(tester.GenerateHeapDump(thread));
|
|
}
|
|
|
|
HWTEST_F_L0(HProfTest, GenerateFile)
|
|
{
|
|
HProfTestHelper tester("GenerateFile.heapsnapshot");
|
|
ASSERT_TRUE(tester.GenerateHeapDump(thread));
|
|
ASSERT_TRUE(tester.RemoveExistingFile());
|
|
}
|
|
|
|
HWTEST_F_L0(HProfTest, ParseJSONHeader)
|
|
{
|
|
HProfTestHelper tester("ParseJSONHeader.heapsnapshot");
|
|
ASSERT_TRUE(tester.GenerateHeapDump(thread));
|
|
ASSERT_TRUE(tester.ContrastJSONLineHeader(1, "{\"snapshot\":"));
|
|
ASSERT_TRUE(tester.ContrastJSONLineHeader(2, "{\"meta\":"));
|
|
ASSERT_TRUE(tester.ContrastJSONLineHeader(3, "{\"node_fields\":"));
|
|
ASSERT_TRUE(tester.ContrastJSONLineHeader(4, "\"node_types\":"));
|
|
ASSERT_TRUE(tester.ContrastJSONLineHeader(5, "\"edge_fields\":"));
|
|
ASSERT_TRUE(tester.ContrastJSONLineHeader(6, "\"edge_types\":"));
|
|
ASSERT_TRUE(tester.ContrastJSONLineHeader(7, "\"trace_function_info_fields\":"));
|
|
ASSERT_TRUE(tester.ContrastJSONLineHeader(8, "\"trace_node_fields\":"));
|
|
ASSERT_TRUE(tester.ContrastJSONLineHeader(9, "\"sample_fields\":"));
|
|
ASSERT_TRUE(tester.ContrastJSONLineHeader(10, "\"location_fields\":"));
|
|
ASSERT_TRUE(tester.RemoveExistingFile());
|
|
}
|
|
|
|
HWTEST_F_L0(HProfTest, ContrastTraceFunctionInfo)
|
|
{
|
|
HProfTestHelper tester("ContrastTraceFunctionInfo.heapsnapshot");
|
|
ASSERT_TRUE(tester.GenerateHeapDump(thread));
|
|
ASSERT_TRUE(tester.ContrastJSONSectionPayload("\"trace_function_infos\":", 2)); // Empty
|
|
ASSERT_TRUE(tester.RemoveExistingFile());
|
|
}
|
|
|
|
HWTEST_F_L0(HProfTest, ContrastTraceTree)
|
|
{
|
|
HProfTestHelper tester("ContrastTraceTree.heapsnapshot");
|
|
ASSERT_TRUE(tester.GenerateHeapDump(thread));
|
|
ASSERT_TRUE(tester.ContrastJSONSectionPayload("\"trace_tree\":", 2)); // Empty
|
|
ASSERT_TRUE(tester.RemoveExistingFile());
|
|
}
|
|
|
|
HWTEST_F_L0(HProfTest, ContrastSamples)
|
|
{
|
|
HProfTestHelper tester("ContrastSamples.heapsnapshot");
|
|
ASSERT_TRUE(tester.GenerateHeapDump(thread));
|
|
ASSERT_TRUE(tester.ContrastJSONSectionPayload("\"samples\":", 2)); // Empty
|
|
ASSERT_TRUE(tester.RemoveExistingFile());
|
|
}
|
|
|
|
HWTEST_F_L0(HProfTest, ContrastLocations)
|
|
{
|
|
HProfTestHelper tester("ContrastLocations.heapsnapshot");
|
|
ASSERT_TRUE(tester.GenerateHeapDump(thread));
|
|
ASSERT_TRUE(tester.ContrastJSONSectionPayload("\"locations\":", 2)); // Empty
|
|
ASSERT_TRUE(tester.RemoveExistingFile());
|
|
}
|
|
|
|
HWTEST_F_L0(HProfTest, ContrastString)
|
|
{
|
|
HProfTestHelper tester("ContrastString.heapsnapshot");
|
|
ASSERT_TRUE(tester.GenerateHeapDump(thread));
|
|
ASSERT_TRUE(tester.ContrastJSONSectionPayload("\"strings\":[", 1 + 1));
|
|
ASSERT_TRUE(tester.RemoveExistingFile());
|
|
}
|
|
|
|
HWTEST_F_L0(HProfTest, ContrastClosure)
|
|
{
|
|
HProfTestHelper tester("ContrastClosure.heapsnapshot");
|
|
ASSERT_TRUE(tester.GenerateHeapDump(thread));
|
|
ASSERT_TRUE(tester.ContrastJSONClousure());
|
|
ASSERT_TRUE(tester.RemoveExistingFile());
|
|
}
|
|
|
|
HWTEST_F_L0(HProfTest, ContrastEdgeCount)
|
|
{
|
|
HProfTestHelper tester("ContrastEdgeCount.heapsnapshot");
|
|
ASSERT_TRUE(tester.GenerateHeapDump(thread));
|
|
ASSERT_TRUE(tester.ExtractCountFromMeta("\"edge_count\":") == tester.ExtractCountFromPayload("\"edges\":["));
|
|
ASSERT_TRUE(tester.RemoveExistingFile());
|
|
}
|
|
|
|
HWTEST_F_L0(HProfTest, ContrastTraceFunctionInfoCount)
|
|
{
|
|
HProfTestHelper tester("ContrastTraceFunctionInfoCount.heapsnapshot");
|
|
ASSERT_TRUE(tester.GenerateHeapDump(thread));
|
|
ASSERT_TRUE(tester.ExtractCountFromMeta("\"trace_function_count\":") ==
|
|
tester.ExtractCountFromPayload("\"trace_function_infos\":"));
|
|
ASSERT_TRUE(tester.RemoveExistingFile());
|
|
}
|
|
} // namespace panda::test
|