731fd3f581
This patchset introduces instrumentation of the memory usage of the datatructures maintained by the CPU profiler. It captures: * The total size of the strings held in StringsStorage for CodeEntries * Estimated size held by CodeMap's entries. The target is to surface that metric through telemetry to get better visibility into the memory profile of CpuProfiler. For now, STL containers overhead is ignored as it is implementation specific. Change-Id: I8c6a0cd4f14348fe8832dec1f24861befc67d700 Bug: chromium:1241491 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3101580 Auto-Submit: Corentin Pescheloche <cpescheloche@fb.com> Commit-Queue: Camillo Bruni <cbruni@chromium.org> Reviewed-by: Camillo Bruni <cbruni@chromium.org> Cr-Commit-Position: refs/heads/main@{#76438}
180 lines
5.5 KiB
C++
180 lines
5.5 KiB
C++
// Copyright 2018 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "src/profiler/strings-storage.h"
|
|
|
|
#include <cstdio>
|
|
|
|
#include "test/unittests/test-utils.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
|
|
using StringsStorageWithIsolate = TestWithIsolate;
|
|
|
|
bool StringEq(const char* left, const char* right) {
|
|
return strcmp(left, right) == 0;
|
|
}
|
|
|
|
TEST_F(StringsStorageWithIsolate, GetNameFromString) {
|
|
StringsStorage storage;
|
|
|
|
// One char strings are canonical on the v8 heap so use a 2 char string here.
|
|
Handle<String> str = isolate()->factory()->NewStringFromAsciiChecked("xy");
|
|
const char* stored_str = storage.GetName(*str);
|
|
CHECK(StringEq("xy", stored_str));
|
|
|
|
// The storage should de-duplicate the underlying char arrays and return the
|
|
// exact same pointer for equivalent input strings.
|
|
const char* stored_str_twice = storage.GetName(*str);
|
|
CHECK_EQ(stored_str, stored_str_twice);
|
|
|
|
// Even if the input string was a different one on the v8 heap, if the char
|
|
// array is the same, it should be de-duplicated.
|
|
Handle<String> str2 = isolate()->factory()->NewStringFromAsciiChecked("xy");
|
|
CHECK_NE(*str, *str2);
|
|
const char* stored_str_thrice = storage.GetName(*str2);
|
|
CHECK_EQ(stored_str_twice, stored_str_thrice);
|
|
}
|
|
|
|
TEST_F(StringsStorageWithIsolate, GetNameFromSymbol) {
|
|
StringsStorage storage;
|
|
|
|
Handle<Symbol> symbol = isolate()->factory()->NewSymbol();
|
|
const char* stored_symbol = storage.GetName(*symbol);
|
|
CHECK(StringEq("<symbol>", stored_symbol));
|
|
|
|
Handle<Symbol> symbol2 = isolate()->factory()->NewSymbol();
|
|
CHECK_NE(*symbol, *symbol2);
|
|
const char* stored_symbol2 = storage.GetName(*symbol2);
|
|
CHECK_EQ(stored_symbol, stored_symbol2);
|
|
}
|
|
|
|
TEST_F(StringsStorageWithIsolate, GetConsName) {
|
|
StringsStorage storage;
|
|
|
|
Handle<String> str = isolate()->factory()->NewStringFromAsciiChecked("xy");
|
|
|
|
const char* empty_prefix_str = storage.GetConsName("", *str);
|
|
CHECK(StringEq("xy", empty_prefix_str));
|
|
|
|
const char* get_str = storage.GetConsName("get ", *str);
|
|
CHECK(StringEq("get xy", get_str));
|
|
}
|
|
|
|
TEST_F(StringsStorageWithIsolate, GetNameFromInt) {
|
|
StringsStorage storage;
|
|
|
|
const char* stored_str = storage.GetName(0);
|
|
CHECK(StringEq("0", stored_str));
|
|
|
|
stored_str = storage.GetName(2147483647);
|
|
CHECK(StringEq("2147483647", stored_str));
|
|
|
|
stored_str = storage.GetName(std::numeric_limits<int>::min());
|
|
char str_negative_int[12];
|
|
snprintf(str_negative_int, sizeof(str_negative_int), "%d",
|
|
std::numeric_limits<int>::min());
|
|
CHECK(StringEq(str_negative_int, stored_str));
|
|
}
|
|
|
|
TEST_F(StringsStorageWithIsolate, Format) {
|
|
StringsStorage storage;
|
|
|
|
const char* xy = "xy";
|
|
const char* stored_str = storage.GetFormatted("%s", xy);
|
|
CHECK(StringEq("xy", stored_str));
|
|
// Check that the string is copied.
|
|
CHECK_NE(xy, stored_str);
|
|
|
|
const char* formatted_str = storage.GetFormatted("%s / %s", xy, xy);
|
|
CHECK(StringEq("xy / xy", formatted_str));
|
|
|
|
// A different format specifier that results in the same string should share
|
|
// the string in storage.
|
|
const char* formatted_str2 = storage.GetFormatted("%s", "xy / xy");
|
|
CHECK_EQ(formatted_str, formatted_str2);
|
|
}
|
|
|
|
TEST_F(StringsStorageWithIsolate, FormatAndGetShareStorage) {
|
|
StringsStorage storage;
|
|
|
|
Handle<String> str = isolate()->factory()->NewStringFromAsciiChecked("xy");
|
|
const char* stored_str = storage.GetName(*str);
|
|
|
|
const char* formatted_str = storage.GetFormatted("%s", "xy");
|
|
CHECK_EQ(stored_str, formatted_str);
|
|
}
|
|
|
|
TEST_F(StringsStorageWithIsolate, Refcounting) {
|
|
StringsStorage storage;
|
|
|
|
const char* a = storage.GetCopy("12");
|
|
CHECK_EQ(storage.GetStringCountForTesting(), 1);
|
|
CHECK_EQ(2, storage.GetStringSize());
|
|
|
|
const char* b = storage.GetCopy("12");
|
|
CHECK_EQ(storage.GetStringCountForTesting(), 1);
|
|
CHECK_EQ(2, storage.GetStringSize());
|
|
|
|
// Ensure that we deduplicate the string.
|
|
CHECK_EQ(a, b);
|
|
|
|
CHECK(storage.Release(a));
|
|
CHECK_EQ(storage.GetStringCountForTesting(), 1);
|
|
CHECK_EQ(2, storage.GetStringSize());
|
|
|
|
CHECK(storage.Release(b));
|
|
CHECK_EQ(storage.GetStringCountForTesting(), 0);
|
|
CHECK_EQ(0, storage.GetStringSize());
|
|
|
|
#if !DEBUG
|
|
CHECK(!storage.Release("12"));
|
|
#endif // !DEBUG
|
|
|
|
// Verify that other constructors refcount as intended.
|
|
const char* c = storage.GetFormatted("%d", 12);
|
|
CHECK_EQ(storage.GetStringCountForTesting(), 1);
|
|
CHECK_EQ(2, storage.GetStringSize());
|
|
|
|
const char* d = storage.GetName(12);
|
|
CHECK_EQ(storage.GetStringCountForTesting(), 1);
|
|
CHECK_EQ(2, storage.GetStringSize());
|
|
|
|
CHECK_EQ(c, d);
|
|
|
|
CHECK(storage.Release(c));
|
|
CHECK_EQ(storage.GetStringCountForTesting(), 1);
|
|
CHECK_EQ(2, storage.GetStringSize());
|
|
CHECK(storage.Release(d));
|
|
CHECK_EQ(storage.GetStringCountForTesting(), 0);
|
|
CHECK_EQ(0, storage.GetStringSize());
|
|
|
|
CHECK(!storage.Release("12"));
|
|
}
|
|
|
|
TEST_F(StringsStorageWithIsolate, InvalidRelease) {
|
|
StringsStorage storage;
|
|
|
|
// If we attempt to release a string not being managed by the StringsStorage,
|
|
// return false.
|
|
CHECK(!storage.Release("12"));
|
|
}
|
|
|
|
TEST_F(StringsStorageWithIsolate, CopyAndConsShareStorage) {
|
|
StringsStorage storage;
|
|
|
|
Handle<String> str = isolate()->factory()->NewStringFromAsciiChecked("foo");
|
|
|
|
const char* copy_str = storage.GetCopy("get foo");
|
|
const char* cons_str = storage.GetConsName("get ", *str);
|
|
|
|
CHECK_EQ(storage.GetStringCountForTesting(), 1);
|
|
CHECK_EQ(copy_str, cons_str);
|
|
}
|
|
|
|
} // namespace internal
|
|
} // namespace v8
|