Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(354)

Unified Diff: test/cctest/test-log-ia32.cc

Issue 50052: Support profiler stack sampling in any situation. (Closed)
Patch Set: Fixes according to comments Created 11 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/platform-win32.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/cctest/test-log-ia32.cc
diff --git a/test/cctest/test-log-ia32.cc b/test/cctest/test-log-ia32.cc
index 588be7158c3e767ceaea885db135d10f4eb2bde9..b171339c24da6d9d83c83b7ad3270fef9ec25dbc 100644
--- a/test/cctest/test-log-ia32.cc
+++ b/test/cctest/test-log-ia32.cc
@@ -9,6 +9,7 @@
#include "v8.h"
#include "log.h"
+#include "top.h"
#include "cctest.h"
using v8::Function;
@@ -23,6 +24,7 @@ using v8::internal::Handle;
using v8::internal::JSFunction;
using v8::internal::StackTracer;
using v8::internal::TickSample;
+using v8::internal::Top;
static v8::Persistent<v8::Context> env;
@@ -31,7 +33,7 @@ static v8::Persistent<v8::Context> env;
static struct {
StackTracer* tracer;
TickSample* sample;
-} trace_env;
+} trace_env = { NULL, NULL };
static void InitTraceEnv(StackTracer* tracer, TickSample* sample) {
@@ -42,62 +44,43 @@ static void InitTraceEnv(StackTracer* tracer, TickSample* sample) {
static void DoTrace(unsigned int fp) {
trace_env.sample->fp = fp;
- // something that is less than fp
- trace_env.sample->sp = trace_env.sample->fp - 100;
+ // sp is only used to define stack high bound
+ trace_env.sample->sp =
+ reinterpret_cast<unsigned int>(trace_env.sample) - 10240;
trace_env.tracer->Trace(trace_env.sample);
}
-static void CFuncDoTrace() {
- unsigned int fp;
-#ifdef __GNUC__
- fp = reinterpret_cast<unsigned int>(__builtin_frame_address(0));
-#elif defined _MSC_VER
- __asm mov [fp], ebp // NOLINT
-#endif
+// Hide c_entry_fp to emulate situation when sampling is done while
+// pure JS code is being executed
+static void DoTraceHideCEntryFPAddress(unsigned int fp) {
+ v8::internal::Address saved_c_frame_fp = *(Top::c_entry_fp_address());
+ CHECK(saved_c_frame_fp);
+ *(Top::c_entry_fp_address()) = 0;
DoTrace(fp);
+ *(Top::c_entry_fp_address()) = saved_c_frame_fp;
}
-static void CFunc(int i) {
- for (int j = i; j >= 0; --j) {
- CFuncDoTrace();
- }
-}
-
-
-static void CheckRetAddrIsInFunction(unsigned int ret_addr,
+static void CheckRetAddrIsInFunction(const char* func_name,
+ unsigned int ret_addr,
unsigned int func_start_addr,
unsigned int func_len) {
- printf("CheckRetAddrIsInFunction: %08x %08x %08x\n",
- func_start_addr, ret_addr, func_start_addr + func_len);
+ printf("CheckRetAddrIsInFunction \"%s\": %08x %08x %08x\n",
+ func_name, func_start_addr, ret_addr, func_start_addr + func_len);
CHECK_GE(ret_addr, func_start_addr);
CHECK_GE(func_start_addr + func_len, ret_addr);
}
-#ifdef DEBUG
-static const int kMaxCFuncLen = 0x40; // seems enough for a small C function
-
-static void CheckRetAddrIsInCFunction(unsigned int ret_addr,
- unsigned int func_start_addr) {
- CheckRetAddrIsInFunction(ret_addr, func_start_addr, kMaxCFuncLen);
-}
-#endif
-
-
-TEST(PureCStackTrace) {
- TickSample sample;
- StackTracer tracer(reinterpret_cast<unsigned int>(&sample));
- InitTraceEnv(&tracer, &sample);
- CFunc(0);
-#ifdef DEBUG
- // C stack trace works only in debug mode, in release mode EBP is
- // usually treated as a general-purpose register
- CHECK_GT(sample.frames_count, 0);
- CheckRetAddrIsInCFunction(reinterpret_cast<unsigned int>(sample.stack[0]),
- reinterpret_cast<unsigned int>(&CFunc));
-#endif
+static void CheckRetAddrIsInJSFunction(const char* func_name,
+ unsigned int ret_addr,
+ Handle<JSFunction> func) {
+ v8::internal::Code* func_code = func->code();
+ CheckRetAddrIsInFunction(
+ func_name, ret_addr,
+ reinterpret_cast<unsigned int>(func_code->instruction_start()),
+ func_code->ExecutableSize());
}
@@ -107,27 +90,49 @@ class TraceExtension : public v8::Extension {
public:
TraceExtension() : v8::Extension("v8/trace", kSource) { }
virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
- v8::Handle<v8::String> name);
+ v8::Handle<String> name);
static v8::Handle<v8::Value> Trace(const v8::Arguments& args);
+ static v8::Handle<v8::Value> JSTrace(const v8::Arguments& args);
private:
+ static unsigned int GetFP(const v8::Arguments& args);
static const char* kSource;
};
-const char* TraceExtension::kSource = "native function trace();";
+const char* TraceExtension::kSource =
+ "native function trace();"
+ "native function js_trace();";
v8::Handle<v8::FunctionTemplate> TraceExtension::GetNativeFunction(
- v8::Handle<v8::String> str) {
- return v8::FunctionTemplate::New(TraceExtension::Trace);
+ v8::Handle<String> name) {
+ if (name->Equals(String::New("trace"))) {
+ return v8::FunctionTemplate::New(TraceExtension::Trace);
+ } else if (name->Equals(String::New("js_trace"))) {
+ return v8::FunctionTemplate::New(TraceExtension::JSTrace);
+ } else {
+ CHECK(false);
+ return v8::Handle<v8::FunctionTemplate>();
+ }
}
-v8::Handle<v8::Value> TraceExtension::Trace(const v8::Arguments& args) {
+unsigned int TraceExtension::GetFP(const v8::Arguments& args) {
CHECK_EQ(1, args.Length());
unsigned int fp = args[0]->Int32Value() << 2;
printf("Trace: %08x\n", fp);
- DoTrace(fp);
+ return fp;
+}
+
+
+v8::Handle<v8::Value> TraceExtension::Trace(const v8::Arguments& args) {
+ DoTrace(GetFP(args));
+ return v8::Undefined();
+}
+
+
+v8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) {
+ DoTraceHideCEntryFPAddress(GetFP(args));
return v8::Undefined();
}
@@ -163,6 +168,21 @@ static Local<Value> GetGlobalProperty(const char* name) {
}
+static Handle<JSFunction> GetGlobalJSFunction(const char* name) {
+ Handle<JSFunction> js_func(JSFunction::cast(
+ *(v8::Utils::OpenHandle(
+ *GetGlobalProperty(name)))));
+ return js_func;
+}
+
+
+static void CheckRetAddrIsInJSFunction(const char* func_name,
+ unsigned int ret_addr) {
+ CheckRetAddrIsInJSFunction(func_name, ret_addr,
+ GetGlobalJSFunction(func_name));
+}
+
+
static void SetGlobalProperty(const char* name, Local<Value> value) {
env->Global()->Set(String::New(name), value);
}
@@ -188,17 +208,17 @@ static bool Patch(byte* from,
}
-TEST(PureJSStackTrace) {
- TickSample sample;
- StackTracer tracer(reinterpret_cast<unsigned int>(&sample));
- InitTraceEnv(&tracer, &sample);
-
- InitializeVM();
- v8::HandleScope scope;
- Handle<JSFunction> call_trace = CompileFunction("trace(0x6666);");
- CHECK(!call_trace.is_null());
- v8::internal::Code* call_trace_code = call_trace->code();
- CHECK(call_trace_code->IsCode());
+// Creates a global function named 'func_name' that calls the tracing
+// function 'trace_func_name' with an actual EBP register value,
+// shifted right to be presented as Smi.
+static void CreateTraceCallerFunction(const char* func_name,
+ const char* trace_func_name) {
+ ::v8::internal::EmbeddedVector<char, 256> trace_call_buf;
+ ::v8::internal::OS::SNPrintF(trace_call_buf, "%s(0x6666);", trace_func_name);
+ Handle<JSFunction> func = CompileFunction(trace_call_buf.start());
+ CHECK(!func.is_null());
+ v8::internal::Code* func_code = func->code();
+ CHECK(func_code->IsCode());
// push 0xcccc (= 0x6666 << 1)
byte original[] = { 0x68, 0xcc, 0xcc, 0x00, 0x00 };
@@ -206,29 +226,89 @@ TEST(PureJSStackTrace) {
byte patch[] = { 0x89, 0xe8, 0xd1, 0xe8, 0x50 };
// Patch generated code to replace pushing of a constant with
// pushing of ebp contents in a Smi
- CHECK(Patch(call_trace_code->instruction_start(),
- call_trace_code->instruction_size(),
+ CHECK(Patch(func_code->instruction_start(),
+ func_code->instruction_size(),
original, patch, sizeof(patch)));
- SetGlobalProperty("JSFuncDoTrace", v8::ToApi<Value>(call_trace));
+ SetGlobalProperty(func_name, v8::ToApi<Value>(func));
+}
+
+TEST(CFromJSStackTrace) {
+ TickSample sample;
+ StackTracer tracer(reinterpret_cast<unsigned int>(&sample));
+ InitTraceEnv(&tracer, &sample);
+
+ InitializeVM();
+ v8::HandleScope scope;
+ CreateTraceCallerFunction("JSFuncDoTrace", "trace");
CompileRun(
"function JSTrace() {"
" JSFuncDoTrace();"
"};\n"
"JSTrace();");
CHECK_GT(sample.frames_count, 1);
- CheckRetAddrIsInFunction(
- reinterpret_cast<unsigned int>(sample.stack[0]),
- reinterpret_cast<unsigned int>(call_trace_code->instruction_start()),
- call_trace_code->instruction_size());
- Handle<JSFunction> js_trace(JSFunction::cast(*(v8::Utils::OpenHandle(
- *GetGlobalProperty("JSTrace")))));
- v8::internal::Code* js_trace_code = js_trace->code();
- CheckRetAddrIsInFunction(
- reinterpret_cast<unsigned int>(sample.stack[1]),
- reinterpret_cast<unsigned int>(js_trace_code->instruction_start()),
- js_trace_code->instruction_size());
+ // Stack sampling will start from the first JS function, i.e. "JSFuncDoTrace"
+ CheckRetAddrIsInJSFunction("JSFuncDoTrace",
+ reinterpret_cast<unsigned int>(sample.stack[0]));
+ CheckRetAddrIsInJSFunction("JSTrace",
+ reinterpret_cast<unsigned int>(sample.stack[1]));
+}
+
+
+TEST(PureJSStackTrace) {
+ TickSample sample;
+ StackTracer tracer(reinterpret_cast<unsigned int>(&sample));
+ InitTraceEnv(&tracer, &sample);
+
+ InitializeVM();
+ v8::HandleScope scope;
+ CreateTraceCallerFunction("JSFuncDoTrace", "js_trace");
+ CompileRun(
+ "function JSTrace() {"
+ " JSFuncDoTrace();"
+ "};\n"
+ "function OuterJSTrace() {"
+ " JSTrace();"
+ "};\n"
+ "OuterJSTrace();");
+ CHECK_GT(sample.frames_count, 1);
+ // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace"
+ CheckRetAddrIsInJSFunction("JSTrace",
+ reinterpret_cast<unsigned int>(sample.stack[0]));
+ CheckRetAddrIsInJSFunction("OuterJSTrace",
+ reinterpret_cast<unsigned int>(sample.stack[1]));
}
+
+static void CFuncDoTrace() {
+ unsigned int fp;
+#ifdef __GNUC__
+ fp = reinterpret_cast<unsigned int>(__builtin_frame_address(0));
+#elif defined _MSC_VER
+ __asm mov [fp], ebp // NOLINT
+#endif
+ DoTrace(fp);
+}
+
+
+static int CFunc(int depth) {
+ if (depth <= 0) {
+ CFuncDoTrace();
+ return 0;
+ } else {
+ return CFunc(depth - 1) + 1;
+ }
+}
+
+
+TEST(PureCStackTrace) {
+ TickSample sample;
+ StackTracer tracer(reinterpret_cast<unsigned int>(&sample));
+ InitTraceEnv(&tracer, &sample);
+ // Check that sampler doesn't crash
+ CHECK_EQ(10, CFunc(10));
+}
+
+
#endif // ENABLE_LOGGING_AND_PROFILING
« no previous file with comments | « src/platform-win32.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698