Commit f6965281 authored by Peter Marshall's avatar Peter Marshall Committed by Commit Bot

[cpu-profiler] Log OSR code when starting the profiler

OSR code doesn't hang off any JSFunction or SFI, so we missed it when
starting up the profiler. This meant we didn't properly attribute
ticks to SFI code. The ticks ended up going to the caller instead.

There is a weak cache of OSR code per native context, so iterate that
on profiler startup and log all the code objects.

Change-Id: I2e9738b86a488b37f36ac89803561607dc76f745
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2414216
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Reviewed-by: 's avatarDominik Inführ <dinfuehr@chromium.org>
Reviewed-by: 's avatarMythri Alle <mythria@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69964}
parent fa5a65ad
......@@ -1528,6 +1528,8 @@ class Heap {
static Isolate* GetIsolateFromWritableObject(HeapObject object);
std::vector<Handle<NativeContext>> FindAllNativeContexts();
private:
using ExternalStringTableUpdaterCallback = String (*)(Heap* heap,
FullObjectSlot pointer);
......@@ -2019,7 +2021,6 @@ class Heap {
V8_EXPORT_PRIVATE void IncrementObjectCounters();
#endif // DEBUG
std::vector<Handle<NativeContext>> FindAllNativeContexts();
std::vector<WeakArrayList> FindAllRetainedMaps();
MemoryMeasurement* memory_measurement() { return memory_measurement_.get(); }
......
......@@ -31,6 +31,7 @@
#include "src/logging/log-inl.h"
#include "src/logging/log-utils.h"
#include "src/objects/api-callbacks.h"
#include "src/objects/osr-optimized-code-cache.h"
#include "src/profiler/tick-sample.h"
#include "src/snapshot/embedded/embedded-data.h"
#include "src/strings/string-stream.h"
......@@ -1901,6 +1902,17 @@ static int EnumerateCompiledFunctions(Heap* heap,
}
}
for (Handle<NativeContext> native_context : heap->FindAllNativeContexts()) {
OSROptimizedCodeCache::Iterator osr_iterator(native_context);
for (std::pair<SharedFunctionInfo, Code> sfiCodePair = osr_iterator.Next();
!sfiCodePair.first.is_null(); sfiCodePair = osr_iterator.Next()) {
AddFunctionAndCode(sfiCodePair.first,
AbstractCode::cast(sfiCodePair.second), sfis,
code_objects, compiled_funcs_count);
++compiled_funcs_count;
}
}
return compiled_funcs_count;
}
......
......@@ -219,5 +219,24 @@ bool OSROptimizedCodeCache::NeedsTrimming(int num_valid_entries,
return curr_length > kInitialLength && curr_length > num_valid_entries * 3;
}
OSROptimizedCodeCache::Iterator::Iterator(Handle<NativeContext> native_context)
: cache_(native_context->GetOSROptimizedCodeCache(),
native_context->GetIsolate()) {}
std::pair<SharedFunctionInfo, Code> OSROptimizedCodeCache::Iterator::Next() {
while (index_ < cache_->length()) {
if (cache_->Get(index_ + kSharedOffset)->IsCleared() ||
cache_->Get(index_ + kCachedCodeOffset)->IsCleared()) {
index_ += kEntryLength;
continue;
}
auto result = std::make_pair(cache_->GetSFIFromEntry(index_),
cache_->GetCodeFromEntry(index_));
index_ += kEntryLength;
return result;
}
return std::make_pair(SharedFunctionInfo(), Code());
}
} // namespace internal
} // namespace v8
......@@ -48,6 +48,19 @@ class V8_EXPORT OSROptimizedCodeCache : public WeakFixedArray {
// Remove all code objects marked for deoptimization from OSR code cache.
void EvictMarkedCode(Isolate* isolate);
// Iterate over all entries in the cache, skipping cleared or null entries.
class Iterator {
public:
explicit Iterator(Handle<NativeContext> native_context);
// Both results will be null when iteration has finished.
std::pair<SharedFunctionInfo, Code> Next();
private:
Handle<OSROptimizedCodeCache> cache_;
int index_ = 0; // Index into the FixedArray; a multiple of kEntryLength.
};
private:
// Functions that implement heuristics on when to grow / shrink the cache.
static int CapacityForLength(int curr_capacity);
......
......@@ -2241,10 +2241,7 @@ static const char* pre_profiling_osr_script = R"(
)";
// Testing profiling of OSR code that was OSR optimized before profiling
// started. Currently the behavior is not quite right so we're currently
// testing a deopt event being sent to the sampling thread for a function
// it knows nothing about. This deopt does mean we start getting samples
// for hot so we expect some samples, just fewer than for notHot.
// started.
//
// We should get something like:
// 0 (root):0 3 0 #1
......@@ -2253,15 +2250,6 @@ static const char* pre_profiling_osr_script = R"(
// 85 hot:5 0 4 #6
// 0 whenPass:2 0 4 #3
// 0 startProfiling:0 2 0 #4
//
// But currently get something like:
// 0 (root):0 3 0 #1
// 12 (garbage collector):0 3 0 #5
// 57 notHot:22 0 4 #2
// 33 hot:5 0 4 #6
// 0 whenPass:2 0 4 #3
// 0 startProfiling:0 2 0 #4
TEST(StartProfilingAfterOsr) {
i::FLAG_allow_natives_syntax = true;
v8::HandleScope scope(CcTest::isolate());
......@@ -2284,10 +2272,8 @@ TEST(StartProfilingAfterOsr) {
const CpuProfileNode* root = profile->GetTopDownRoot();
const v8::CpuProfileNode* notHotNode = GetChild(env, root, "notHot");
const v8::CpuProfileNode* hotNode = GetChild(env, notHotNode, "hot");
USE(hotNode);
// If/when OSR sampling is fixed the following CHECK_GT could/should be
// uncommented and the node = node line deleted.
// CHECK_GT(hotNode->GetHitCount(), notHotNode->GetHitCount());
CHECK_GT(hotNode->GetHitCount(), notHotNode->GetHitCount());
}
TEST(DontStopOnFinishedProfileDelete) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment