From 89c64653bfecca65a2e6e65ed96af99c8e918cfa Mon Sep 17 00:00:00 2001 From: "jkummerow@chromium.org" Date: Mon, 9 May 2011 08:58:57 +0000 Subject: [PATCH] Expose optimization info via runtime functions TEST=mjsunit/assert-opt-and-deopt.js Review URL: http://codereview.chromium.org/6879108 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7813 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/runtime.cc | 23 +++++ src/runtime.h | 2 + test/mjsunit/assert-opt-and-deopt.js | 181 +++++++++++++++++++++++++++++++++++ 3 files changed, 206 insertions(+) create mode 100644 test/mjsunit/assert-opt-and-deopt.js diff --git a/src/runtime.cc b/src/runtime.cc index 6738213..b32ae8a 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -7554,6 +7554,29 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) { } +RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + if (!V8::UseCrankshaft()) { + return Smi::FromInt(4); // 4 == "never". + } + if (FLAG_always_opt) { + return Smi::FromInt(3); // 3 == "always". + } + CONVERT_ARG_CHECKED(JSFunction, function, 0); + return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes". + : Smi::FromInt(2); // 2 == "no". +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) { + HandleScope scope(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_CHECKED(JSFunction, function, 0); + return Smi::FromInt(function->shared()->opt_count()); +} + + RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) { HandleScope scope(isolate); ASSERT(args.length() == 1); diff --git a/src/runtime.h b/src/runtime.h index f0beaf5..0641abd 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -87,6 +87,8 @@ namespace internal { F(NotifyOSR, 0, 1) \ F(DeoptimizeFunction, 1, 1) \ F(OptimizeFunctionOnNextCall, 1, 1) \ + F(GetOptimizationStatus, 1, 1) \ + F(GetOptimizationCount, 1, 1) \ F(CompileForOnStackReplacement, 1, 1) \ F(SetNewFunctionAttributes, 1, 1) \ F(AllocateInNewSpace, 1, 1) \ diff --git a/test/mjsunit/assert-opt-and-deopt.js b/test/mjsunit/assert-opt-and-deopt.js new file mode 100644 index 0000000..b624ba5 --- /dev/null +++ b/test/mjsunit/assert-opt-and-deopt.js @@ -0,0 +1,181 @@ +// Copyright 2011 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --allow-natives-syntax + +/** + * This class shows how to use %GetOptimizationCount() and + * %GetOptimizationStatus() to infer information about opts and deopts. + * Might be nice to put this into mjsunit.js, but that doesn't depend on + * the --allow-natives-syntax flag so far. + */ +function OptTracker() { + this.opt_counts_ = {}; +} + +/** + * The possible optimization states of a function. Must be in sync with the + * return values of Runtime_GetOptimizationStatus() in runtime.cc! + * @enum {int} + */ +OptTracker.OptimizationState = { + YES: 1, + NO: 2, + ALWAYS: 3, + NEVER: 4 +}; + +/** + * Always call this at the beginning of your test, once for each function + * that you later want to track de/optimizations for. It is necessary because + * tests are sometimes executed several times in a row, and you want to + * disregard counts from previous runs. + */ +OptTracker.prototype.CheckpointOptCount = function(func) { + this.opt_counts_[func] = %GetOptimizationCount(func); +}; + +OptTracker.prototype.AssertOptCount = function(func, optcount) { + if (this.DisableAsserts_(func)) { + return; + } + assertEquals(optcount, this.GetOptCount_(func)); +}; + +OptTracker.prototype.AssertDeoptCount = function(func, deopt_count) { + if (this.DisableAsserts_(func)) { + return; + } + assertEquals(deopt_count, this.GetDeoptCount_(func)); +}; + +OptTracker.prototype.AssertDeoptHappened = function(func, expect_deopt) { + if (this.DisableAsserts_(func)) { + return; + } + if (expect_deopt) { + assertTrue(this.GetDeoptCount_(func) > 0); + } else { + assertEquals(0, this.GetDeoptCount_(func)); + } +} + +OptTracker.prototype.AssertIsOptimized = function(func, expect_optimized) { + if (this.DisableAsserts_(func)) { + return; + } + var raw_optimized = %GetOptimizationStatus(func); + if (expect_optimized) { + assertEquals(OptTracker.OptimizationState.YES, raw_optimized); + } else { + assertEquals(OptTracker.OptimizationState.NO, raw_optimized); + } +} + +/** + * @private + */ +OptTracker.prototype.GetOptCount_ = function(func) { + var raw_count = %GetOptimizationCount(func); + if (func in this.opt_counts_) { + var checkpointed_count = this.opt_counts_[func]; + return raw_count - checkpointed_count; + } + return raw_count; +} + +/** + * @private + */ +OptTracker.prototype.GetDeoptCount_ = function(func) { + var count = this.GetOptCount_(func); + if (%GetOptimizationStatus(func) == OptTracker.OptimizationState.YES) { + count -= 1; + } + return count; +} + +/** + * @private + */ +OptTracker.prototype.DisableAsserts_ = function(func) { + switch(%GetOptimizationStatus(func)) { + case OptTracker.OptimizationState.YES: + case OptTracker.OptimizationState.NO: + return false; + case OptTracker.OptimizationState.ALWAYS: + case OptTracker.OptimizationState.NEVER: + return true; + } + return false; +} +// (End of class OptTracker.) + +// Example function used by the test below. +function f(a) { + return a+1; +} + +var tracker = new OptTracker(); +tracker.CheckpointOptCount(f); + +tracker.AssertOptCount(f, 0); +tracker.AssertIsOptimized(f, false); +tracker.AssertDeoptHappened(f, false); +tracker.AssertDeoptCount(f, 0); + +for (var i = 0; i < 5; i++) f(1); + +tracker.AssertOptCount(f, 0); +tracker.AssertIsOptimized(f, false); +tracker.AssertDeoptHappened(f, false); +tracker.AssertDeoptCount(f, 0); + +%OptimizeFunctionOnNextCall(f); +f(1); + +tracker.AssertOptCount(f, 1); +tracker.AssertIsOptimized(f, true); +tracker.AssertDeoptHappened(f, false); +tracker.AssertDeoptCount(f, 0); + +%DeoptimizeFunction(f); + +tracker.AssertOptCount(f, 1); +tracker.AssertIsOptimized(f, false); +tracker.AssertDeoptHappened(f, true); +tracker.AssertDeoptCount(f, 1); + +// Let's trigger optimization for another type. +for (var i = 0; i < 5; i++) f("a"); +%OptimizeFunctionOnNextCall(f); +f("b"); + +tracker.AssertOptCount(f, 2); +tracker.AssertIsOptimized(f, true); +tracker.AssertDeoptHappened(f, true); +tracker.AssertDeoptCount(f, 1); -- 2.7.4