v8/test/unittests/profiler/strings-storage-unittest.cc
Corentin Pescheloche 731fd3f581 [cpu-profiler] Add method to estimate mem size of ProfilerCodeObserver
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}
2021-08-23 19:07:15 +00:00

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