compiler.h | compiler.h | |||
---|---|---|---|---|
// @file mongo/platform/compiler.h | // Copyright 2012 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. | ||||
/* | #ifndef V8_COMPILER_H_ | |||
* Copyright 2012 10gen Inc. | #define V8_COMPILER_H_ | |||
* | ||||
* Licensed under the Apache License, Version 2.0 (the "License"); | #include "allocation.h" | |||
* you may not use this file except in compliance with the License. | #include "ast.h" | |||
* You may obtain a copy of the License at | #include "zone.h" | |||
* | ||||
* http://www.apache.org/licenses/LICENSE-2.0 | namespace v8 { | |||
* | namespace internal { | |||
* Unless required by applicable law or agreed to in writing, software | ||||
* distributed under the License is distributed on an "AS IS" BASIS, | class ScriptDataImpl; | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
* See the License for the specific language governing permissions and | // CompilationInfo encapsulates some information known at compile time. It | |||
* limitations under the License. | // is constructed based on the resources available at compile-time. | |||
*/ | class CompilationInfo { | |||
public: | ||||
#pragma once | CompilationInfo(Handle<Script> script, Zone* zone); | |||
CompilationInfo(Handle<SharedFunctionInfo> shared_info, Zone* zone); | ||||
/** | CompilationInfo(Handle<JSFunction> closure, Zone* zone); | |||
* Include "mongo/platform/compiler.h" to get compiler-specific macro defin | ||||
itions and utilities. | virtual ~CompilationInfo(); | |||
*/ | ||||
Isolate* isolate() { | ||||
#if defined(_MSC_VER) | ASSERT(Isolate::Current() == isolate_); | |||
#include "mongo/platform/compiler_msvc.h" | return isolate_; | |||
#elif defined(__GNUC__) | } | |||
#include "mongo/platform/compiler_gcc.h" | Zone* zone() { | |||
#else | return zone_; | |||
#error "Unsupported compiler family" | } | |||
bool is_lazy() const { return IsLazy::decode(flags_); } | ||||
bool is_eval() const { return IsEval::decode(flags_); } | ||||
bool is_global() const { return IsGlobal::decode(flags_); } | ||||
bool is_classic_mode() const { return language_mode() == CLASSIC_MODE; } | ||||
bool is_extended_mode() const { return language_mode() == EXTENDED_MODE; | ||||
} | ||||
LanguageMode language_mode() const { | ||||
return LanguageModeField::decode(flags_); | ||||
} | ||||
bool is_in_loop() const { return IsInLoop::decode(flags_); } | ||||
FunctionLiteral* function() const { return function_; } | ||||
Scope* scope() const { return scope_; } | ||||
Scope* global_scope() const { return global_scope_; } | ||||
Handle<Code> code() const { return code_; } | ||||
Handle<JSFunction> closure() const { return closure_; } | ||||
Handle<SharedFunctionInfo> shared_info() const { return shared_info_; } | ||||
Handle<Script> script() const { return script_; } | ||||
v8::Extension* extension() const { return extension_; } | ||||
ScriptDataImpl* pre_parse_data() const { return pre_parse_data_; } | ||||
Handle<Context> calling_context() const { return calling_context_; } | ||||
int osr_ast_id() const { return osr_ast_id_; } | ||||
void MarkAsEval() { | ||||
ASSERT(!is_lazy()); | ||||
flags_ |= IsEval::encode(true); | ||||
} | ||||
void MarkAsGlobal() { | ||||
ASSERT(!is_lazy()); | ||||
flags_ |= IsGlobal::encode(true); | ||||
} | ||||
void SetLanguageMode(LanguageMode language_mode) { | ||||
ASSERT(this->language_mode() == CLASSIC_MODE || | ||||
this->language_mode() == language_mode || | ||||
language_mode == EXTENDED_MODE); | ||||
flags_ = LanguageModeField::update(flags_, language_mode); | ||||
} | ||||
void MarkAsInLoop() { | ||||
ASSERT(is_lazy()); | ||||
flags_ |= IsInLoop::encode(true); | ||||
} | ||||
void MarkAsNative() { | ||||
flags_ |= IsNative::encode(true); | ||||
} | ||||
bool is_native() const { | ||||
return IsNative::decode(flags_); | ||||
} | ||||
void SetFunction(FunctionLiteral* literal) { | ||||
ASSERT(function_ == NULL); | ||||
function_ = literal; | ||||
} | ||||
void SetScope(Scope* scope) { | ||||
ASSERT(scope_ == NULL); | ||||
scope_ = scope; | ||||
} | ||||
void SetGlobalScope(Scope* global_scope) { | ||||
ASSERT(global_scope_ == NULL); | ||||
global_scope_ = global_scope; | ||||
} | ||||
void SetCode(Handle<Code> code) { code_ = code; } | ||||
void SetExtension(v8::Extension* extension) { | ||||
ASSERT(!is_lazy()); | ||||
extension_ = extension; | ||||
} | ||||
void SetPreParseData(ScriptDataImpl* pre_parse_data) { | ||||
ASSERT(!is_lazy()); | ||||
pre_parse_data_ = pre_parse_data; | ||||
} | ||||
void SetCallingContext(Handle<Context> context) { | ||||
ASSERT(is_eval()); | ||||
calling_context_ = context; | ||||
} | ||||
void SetOsrAstId(int osr_ast_id) { | ||||
ASSERT(IsOptimizing()); | ||||
osr_ast_id_ = osr_ast_id; | ||||
} | ||||
void MarkCompilingForDebugging(Handle<Code> current_code) { | ||||
ASSERT(mode_ != OPTIMIZE); | ||||
ASSERT(current_code->kind() == Code::FUNCTION); | ||||
flags_ |= IsCompilingForDebugging::encode(true); | ||||
if (current_code->is_compiled_optimizable()) { | ||||
EnableDeoptimizationSupport(); | ||||
} else { | ||||
mode_ = CompilationInfo::NONOPT; | ||||
} | ||||
} | ||||
bool IsCompilingForDebugging() { | ||||
return IsCompilingForDebugging::decode(flags_); | ||||
} | ||||
bool has_global_object() const { | ||||
return !closure().is_null() && (closure()->context()->global() != NULL) | ||||
; | ||||
} | ||||
GlobalObject* global_object() const { | ||||
return has_global_object() ? closure()->context()->global() : NULL; | ||||
} | ||||
// Accessors for the different compilation modes. | ||||
bool IsOptimizing() const { return mode_ == OPTIMIZE; } | ||||
bool IsOptimizable() const { return mode_ == BASE; } | ||||
void SetOptimizing(int osr_ast_id) { | ||||
SetMode(OPTIMIZE); | ||||
osr_ast_id_ = osr_ast_id; | ||||
} | ||||
void DisableOptimization(); | ||||
// Deoptimization support. | ||||
bool HasDeoptimizationSupport() const { | ||||
return SupportsDeoptimization::decode(flags_); | ||||
} | ||||
void EnableDeoptimizationSupport() { | ||||
ASSERT(IsOptimizable()); | ||||
flags_ |= SupportsDeoptimization::encode(true); | ||||
} | ||||
// Determines whether or not to insert a self-optimization header. | ||||
bool ShouldSelfOptimize(); | ||||
// Disable all optimization attempts of this info for the rest of the | ||||
// current compilation pipeline. | ||||
void AbortOptimization(); | ||||
void set_deferred_handles(DeferredHandles* deferred_handles) { | ||||
ASSERT(deferred_handles_ == NULL); | ||||
deferred_handles_ = deferred_handles; | ||||
} | ||||
void SaveHandles() { | ||||
SaveHandle(&closure_); | ||||
SaveHandle(&shared_info_); | ||||
SaveHandle(&calling_context_); | ||||
SaveHandle(&script_); | ||||
} | ||||
private: | ||||
Isolate* isolate_; | ||||
// Compilation mode. | ||||
// BASE is generated by the full codegen, optionally prepared for bailout | ||||
s. | ||||
// OPTIMIZE is optimized code generated by the Hydrogen-based backend. | ||||
// NONOPT is generated by the full codegen and is not prepared for | ||||
// recompilation/bailouts. These functions are never recompiled. | ||||
enum Mode { | ||||
BASE, | ||||
OPTIMIZE, | ||||
NONOPT | ||||
}; | ||||
void Initialize(Mode mode) { | ||||
mode_ = V8::UseCrankshaft() ? mode : NONOPT; | ||||
ASSERT(!script_.is_null()); | ||||
if (script_->type()->value() == Script::TYPE_NATIVE) { | ||||
MarkAsNative(); | ||||
} | ||||
if (!shared_info_.is_null()) { | ||||
ASSERT(language_mode() == CLASSIC_MODE); | ||||
SetLanguageMode(shared_info_->language_mode()); | ||||
} | ||||
} | ||||
void SetMode(Mode mode) { | ||||
ASSERT(V8::UseCrankshaft()); | ||||
mode_ = mode; | ||||
} | ||||
// Flags using template class BitField<type, start, length>. All are | ||||
// false by default. | ||||
// | ||||
// Compilation is either eager or lazy. | ||||
class IsLazy: public BitField<bool, 0, 1> {}; | ||||
// Flags that can be set for eager compilation. | ||||
class IsEval: public BitField<bool, 1, 1> {}; | ||||
class IsGlobal: public BitField<bool, 2, 1> {}; | ||||
// Flags that can be set for lazy compilation. | ||||
class IsInLoop: public BitField<bool, 3, 1> {}; | ||||
// Strict mode - used in eager compilation. | ||||
class LanguageModeField: public BitField<LanguageMode, 4, 2> {}; | ||||
// Is this a function from our natives. | ||||
class IsNative: public BitField<bool, 6, 1> {}; | ||||
// Is this code being compiled with support for deoptimization.. | ||||
class SupportsDeoptimization: public BitField<bool, 7, 1> {}; | ||||
// If compiling for debugging produce just full code matching the | ||||
// initial mode setting. | ||||
class IsCompilingForDebugging: public BitField<bool, 8, 1> {}; | ||||
unsigned flags_; | ||||
// Fields filled in by the compilation pipeline. | ||||
// AST filled in by the parser. | ||||
FunctionLiteral* function_; | ||||
// The scope of the function literal as a convenience. Set to indicate | ||||
// that scopes have been analyzed. | ||||
Scope* scope_; | ||||
// The global scope provided as a convenience. | ||||
Scope* global_scope_; | ||||
// The compiled code. | ||||
Handle<Code> code_; | ||||
// Possible initial inputs to the compilation process. | ||||
Handle<JSFunction> closure_; | ||||
Handle<SharedFunctionInfo> shared_info_; | ||||
Handle<Script> script_; | ||||
// Fields possibly needed for eager compilation, NULL by default. | ||||
v8::Extension* extension_; | ||||
ScriptDataImpl* pre_parse_data_; | ||||
// The context of the caller is needed for eval code, and will be a null | ||||
// handle otherwise. | ||||
Handle<Context> calling_context_; | ||||
// Compilation mode flag and whether deoptimization is allowed. | ||||
Mode mode_; | ||||
int osr_ast_id_; | ||||
// The zone from which the compilation pipeline working on this | ||||
// CompilationInfo allocates. | ||||
Zone* zone_; | ||||
DeferredHandles* deferred_handles_; | ||||
template<typename T> | ||||
void SaveHandle(Handle<T> *object) { | ||||
if (!object->is_null()) { | ||||
Handle<T> handle(*(*object)); | ||||
*object = handle; | ||||
} | ||||
} | ||||
DISALLOW_COPY_AND_ASSIGN(CompilationInfo); | ||||
}; | ||||
// Exactly like a CompilationInfo, except also creates and enters a | ||||
// Zone on construction and deallocates it on exit. | ||||
class CompilationInfoWithZone: public CompilationInfo { | ||||
public: | ||||
explicit CompilationInfoWithZone(Handle<Script> script) | ||||
: CompilationInfo(script, &zone_), | ||||
zone_(script->GetIsolate()), | ||||
zone_scope_(&zone_, DELETE_ON_EXIT) {} | ||||
explicit CompilationInfoWithZone(Handle<SharedFunctionInfo> shared_info) | ||||
: CompilationInfo(shared_info, &zone_), | ||||
zone_(shared_info->GetIsolate()), | ||||
zone_scope_(&zone_, DELETE_ON_EXIT) {} | ||||
explicit CompilationInfoWithZone(Handle<JSFunction> closure) | ||||
: CompilationInfo(closure, &zone_), | ||||
zone_(closure->GetIsolate()), | ||||
zone_scope_(&zone_, DELETE_ON_EXIT) {} | ||||
private: | ||||
Zone zone_; | ||||
ZoneScope zone_scope_; | ||||
}; | ||||
// A wrapper around a CompilationInfo that detaches the Handles from | ||||
// the underlying DeferredHandleScope and stores them in info_ on | ||||
// destruction. | ||||
class CompilationHandleScope BASE_EMBEDDED { | ||||
public: | ||||
explicit CompilationHandleScope(CompilationInfo* info) | ||||
: deferred_(info->isolate()), info_(info) {} | ||||
~CompilationHandleScope() { | ||||
info_->set_deferred_handles(deferred_.Detach()); | ||||
} | ||||
private: | ||||
DeferredHandleScope deferred_; | ||||
CompilationInfo* info_; | ||||
}; | ||||
class HGraph; | ||||
class HGraphBuilder; | ||||
class LChunk; | ||||
// A helper class that calls the three compilation phases in | ||||
// Crankshaft and keeps track of its state. The three phases | ||||
// CreateGraph, OptimizeGraph and GenerateAndInstallCode can either | ||||
// fail, bail-out to the full code generator or succeed. Apart from | ||||
// their return value, the status of the phase last run can be checked | ||||
// using last_status(). | ||||
class OptimizingCompiler: public ZoneObject { | ||||
public: | ||||
explicit OptimizingCompiler(CompilationInfo* info) | ||||
: info_(info), | ||||
oracle_(NULL), | ||||
graph_builder_(NULL), | ||||
graph_(NULL), | ||||
chunk_(NULL), | ||||
time_taken_to_create_graph_(0), | ||||
time_taken_to_optimize_(0), | ||||
time_taken_to_codegen_(0), | ||||
last_status_(FAILED) { } | ||||
enum Status { | ||||
FAILED, BAILED_OUT, SUCCEEDED | ||||
}; | ||||
MUST_USE_RESULT Status CreateGraph(); | ||||
MUST_USE_RESULT Status OptimizeGraph(); | ||||
MUST_USE_RESULT Status GenerateAndInstallCode(); | ||||
Status last_status() const { return last_status_; } | ||||
CompilationInfo* info() const { return info_; } | ||||
MUST_USE_RESULT Status AbortOptimization() { | ||||
info_->AbortOptimization(); | ||||
info_->shared_info()->DisableOptimization(); | ||||
return SetLastStatus(BAILED_OUT); | ||||
} | ||||
private: | ||||
CompilationInfo* info_; | ||||
TypeFeedbackOracle* oracle_; | ||||
HGraphBuilder* graph_builder_; | ||||
HGraph* graph_; | ||||
LChunk* chunk_; | ||||
int64_t time_taken_to_create_graph_; | ||||
int64_t time_taken_to_optimize_; | ||||
int64_t time_taken_to_codegen_; | ||||
Status last_status_; | ||||
MUST_USE_RESULT Status SetLastStatus(Status status) { | ||||
last_status_ = status; | ||||
return last_status_; | ||||
} | ||||
void RecordOptimizationStats(); | ||||
struct Timer { | ||||
Timer(OptimizingCompiler* compiler, int64_t* location) | ||||
: compiler_(compiler), | ||||
start_(OS::Ticks()), | ||||
location_(location) { } | ||||
~Timer() { | ||||
*location_ += (OS::Ticks() - start_); | ||||
} | ||||
OptimizingCompiler* compiler_; | ||||
int64_t start_; | ||||
int64_t* location_; | ||||
}; | ||||
}; | ||||
// The V8 compiler | ||||
// | ||||
// General strategy: Source code is translated into an anonymous function w | ||||
/o | ||||
// parameters which then can be executed. If the source code contains other | ||||
// functions, they will be compiled and allocated as part of the compilatio | ||||
n | ||||
// of the source code. | ||||
// Please note this interface returns shared function infos. This means yo | ||||
u | ||||
// need to call Factory::NewFunctionFromSharedFunctionInfo before you have | ||||
a | ||||
// real function with a context. | ||||
class Compiler : public AllStatic { | ||||
public: | ||||
// Default maximum number of function optimization attempts before we | ||||
// give up. | ||||
static const int kDefaultMaxOptCount = 10; | ||||
static const int kMaxInliningLevels = 3; | ||||
// Call count before primitive functions trigger their own optimization. | ||||
static const int kCallsUntilPrimitiveOpt = 200; | ||||
// All routines return a SharedFunctionInfo. | ||||
// If an error occurs an exception is raised and the return handle | ||||
// contains NULL. | ||||
// Compile a String source within a context. | ||||
static Handle<SharedFunctionInfo> Compile(Handle<String> source, | ||||
Handle<Object> script_name, | ||||
int line_offset, | ||||
int column_offset, | ||||
v8::Extension* extension, | ||||
ScriptDataImpl* pre_data, | ||||
Handle<Object> script_data, | ||||
NativesFlag is_natives_code); | ||||
// Compile a String source within a context for Eval. | ||||
static Handle<SharedFunctionInfo> CompileEval(Handle<String> source, | ||||
Handle<Context> context, | ||||
bool is_global, | ||||
LanguageMode language_mode, | ||||
int scope_position); | ||||
// Compile from function info (used for lazy compilation). Returns true o | ||||
n | ||||
// success and false if the compilation resulted in a stack overflow. | ||||
static bool CompileLazy(CompilationInfo* info); | ||||
static void RecompileParallel(Handle<JSFunction> function); | ||||
// Compile a shared function info object (the function is possibly lazily | ||||
// compiled). | ||||
static Handle<SharedFunctionInfo> BuildFunctionInfo(FunctionLiteral* node | ||||
, | ||||
Handle<Script> script | ||||
); | ||||
// Set the function info for a newly compiled function. | ||||
static void SetFunctionInfo(Handle<SharedFunctionInfo> function_info, | ||||
FunctionLiteral* lit, | ||||
bool is_toplevel, | ||||
Handle<Script> script); | ||||
static void InstallOptimizedCode(OptimizingCompiler* info); | ||||
#ifdef ENABLE_DEBUGGER_SUPPORT | ||||
static bool MakeCodeForLiveEdit(CompilationInfo* info); | ||||
#endif | #endif | |||
static void RecordFunctionCompilation(Logger::LogEventsAndTags tag, | ||||
CompilationInfo* info, | ||||
Handle<SharedFunctionInfo> shared); | ||||
}; | ||||
} } // namespace v8::internal | ||||
#endif // V8_COMPILER_H_ | ||||
End of changes. 3 change blocks. | ||||
30 lines changed or deleted | 471 lines changed or added | |||
counters.h | counters.h | |||
---|---|---|---|---|
// counters.h | // Copyright 2012 the V8 project authors. All rights reserved. | |||
/* | // Redistribution and use in source and binary forms, with or without | |||
* Copyright (C) 2010 10gen Inc. | // modification, are permitted provided that the following conditions are | |||
* | // met: | |||
* This program is free software: you can redistribute it and/or modify | // | |||
* it under the terms of the GNU Affero General Public License, version | // * Redistributions of source code must retain the above copyright | |||
3, | // notice, this list of conditions and the following disclaimer. | |||
* as published by the Free Software Foundation. | // * Redistributions in binary form must reproduce the above | |||
* | // copyright notice, this list of conditions and the following | |||
* This program is distributed in the hope that it will be useful, | // disclaimer in the documentation and/or other materials provided | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | // with the distribution. | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | // * Neither the name of Google Inc. nor the names of its | |||
* GNU Affero General Public License for more details. | // contributors may be used to endorse or promote products derived | |||
* | // from this software without specific prior written permission. | |||
* You should have received a copy of the GNU Affero General Public Lice | // | |||
nse | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | // "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 | ||||
#pragma once | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
#include "mongo/pch.h" | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
#include "../jsobj.h" | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
#include "../../util/net/message.h" | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
#include "../../util/processinfo.h" | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |||
#include "../../util/concurrency/spin_lock.h" | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
#include "mongo/db/pdfile.h" | ||||
#ifndef V8_COUNTERS_H_ | ||||
namespace mongo { | #define V8_COUNTERS_H_ | |||
/** | #include "../include/v8.h" | |||
* for storing operation counters | #include "allocation.h" | |||
* note: not thread safe. ok with that for speed | ||||
*/ | namespace v8 { | |||
class OpCounters { | namespace internal { | |||
public: | ||||
// StatsCounters is an interface for plugging into external | ||||
OpCounters(); | // counters for monitoring. Counters can be looked up and | |||
void incInsertInWriteLock(int n) { _insert.x += n; } | // manipulated by name. | |||
void gotInsert() { _insert++; } | ||||
void gotQuery() { _query++; } | class StatsTable { | |||
void gotUpdate() { _update++; } | public: | |||
void gotDelete() { _delete++; } | // Register an application-defined function where | |||
void gotGetMore() { _getmore++; } | // counters can be looked up. | |||
void gotCommand() { _command++; } | void SetCounterFunction(CounterLookupCallback f) { | |||
lookup_function_ = f; | ||||
void gotOp( int op , bool isCommand ); | } | |||
BSONObj getObj() const; | // Register an application-defined function to create | |||
// a histogram for passing to the AddHistogramSample function | ||||
// thse are used by snmp, and other things, do not remove | void SetCreateHistogramFunction(CreateHistogramCallback f) { | |||
const AtomicUInt * getInsert() const { return &_insert; } | create_histogram_function_ = f; | |||
const AtomicUInt * getQuery() const { return &_query; } | } | |||
const AtomicUInt * getUpdate() const { return &_update; } | ||||
const AtomicUInt * getDelete() const { return &_delete; } | // Register an application-defined function to add a sample | |||
const AtomicUInt * getGetMore() const { return &_getmore; } | // to a histogram created with CreateHistogram function | |||
const AtomicUInt * getCommand() const { return &_command; } | void SetAddHistogramSampleFunction(AddHistogramSampleCallback f) { | |||
add_histogram_sample_function_ = f; | ||||
private: | } | |||
void _checkWrap(); | ||||
bool HasCounterFunction() const { | ||||
// todo: there will be a lot of cache line contention on these. ne | return lookup_function_ != NULL; | |||
ed to do something | } | |||
// else eventually. | ||||
AtomicUInt _insert; | // Lookup the location of a counter by name. If the lookup | |||
AtomicUInt _query; | // is successful, returns a non-NULL pointer for writing the | |||
AtomicUInt _update; | // value of the counter. Each thread calling this function | |||
AtomicUInt _delete; | // may receive a different location to store it's counter. | |||
AtomicUInt _getmore; | // The return value must not be cached and re-used across | |||
AtomicUInt _command; | // threads, although a single thread is free to cache it. | |||
}; | int* FindLocation(const char* name) { | |||
if (!lookup_function_) return NULL; | ||||
extern OpCounters globalOpCounters; | return lookup_function_(name); | |||
extern OpCounters replOpCounters; | } | |||
class NetworkCounter { | // Create a histogram by name. If the create is successful, | |||
public: | // returns a non-NULL pointer for use with AddHistogramSample | |||
NetworkCounter() : _bytesIn(0), _bytesOut(0), _requests(0), _overfl | // function. min and max define the expected minimum and maximum | |||
ows(0) {} | // sample values. buckets is the maximum number of buckets | |||
void hit( long long bytesIn , long long bytesOut ); | // that the samples will be grouped into. | |||
void append( BSONObjBuilder& b ); | void* CreateHistogram(const char* name, | |||
private: | int min, | |||
long long _bytesIn; | int max, | |||
long long _bytesOut; | size_t buckets) { | |||
long long _requests; | if (!create_histogram_function_) return NULL; | |||
return create_histogram_function_(name, min, max, buckets); | ||||
} | ||||
// Add a sample to a histogram created with the CreateHistogram | ||||
// function. | ||||
void AddHistogramSample(void* histogram, int sample) { | ||||
if (!add_histogram_sample_function_) return; | ||||
return add_histogram_sample_function_(histogram, sample); | ||||
} | ||||
private: | ||||
StatsTable(); | ||||
CounterLookupCallback lookup_function_; | ||||
CreateHistogramCallback create_histogram_function_; | ||||
AddHistogramSampleCallback add_histogram_sample_function_; | ||||
friend class Isolate; | ||||
DISALLOW_COPY_AND_ASSIGN(StatsTable); | ||||
}; | ||||
// StatsCounters are dynamically created values which can be tracked in | ||||
// the StatsTable. They are designed to be lightweight to create and | ||||
// easy to use. | ||||
// | ||||
// Internally, a counter represents a value in a row of a StatsTable. | ||||
// The row has a 32bit value for each process/thread in the table and also | ||||
// a name (stored in the table metadata). Since the storage location can b | ||||
e | ||||
// thread-specific, this class cannot be shared across threads. | ||||
// | ||||
// This class is designed to be POD initialized. It will be registered wit | ||||
h | ||||
// the counter system on first use. For example: | ||||
// StatsCounter c = { "c:myctr", NULL, false }; | ||||
struct StatsCounter { | ||||
const char* name_; | ||||
int* ptr_; | ||||
bool lookup_done_; | ||||
// Sets the counter to a specific value. | ||||
void Set(int value) { | ||||
int* loc = GetPtr(); | ||||
if (loc) *loc = value; | ||||
} | ||||
// Increments the counter. | ||||
void Increment() { | ||||
int* loc = GetPtr(); | ||||
if (loc) (*loc)++; | ||||
} | ||||
void Increment(int value) { | ||||
int* loc = GetPtr(); | ||||
if (loc) | ||||
(*loc) += value; | ||||
} | ||||
// Decrements the counter. | ||||
void Decrement() { | ||||
int* loc = GetPtr(); | ||||
if (loc) (*loc)--; | ||||
} | ||||
void Decrement(int value) { | ||||
int* loc = GetPtr(); | ||||
if (loc) (*loc) -= value; | ||||
} | ||||
// Is this counter enabled? | ||||
// Returns false if table is full. | ||||
bool Enabled() { | ||||
return GetPtr() != NULL; | ||||
} | ||||
// Get the internal pointer to the counter. This is used | ||||
// by the code generator to emit code that manipulates a | ||||
// given counter without calling the runtime system. | ||||
int* GetInternalPointer() { | ||||
int* loc = GetPtr(); | ||||
ASSERT(loc != NULL); | ||||
return loc; | ||||
} | ||||
protected: | ||||
// Returns the cached address of this counter location. | ||||
int* GetPtr() { | ||||
if (lookup_done_) return ptr_; | ||||
lookup_done_ = true; | ||||
ptr_ = FindLocationInStatsTable(); | ||||
return ptr_; | ||||
} | ||||
private: | ||||
int* FindLocationInStatsTable() const; | ||||
}; | ||||
// StatsCounterTimer t = { { L"t:foo", NULL, false }, 0, 0 }; | ||||
struct StatsCounterTimer { | ||||
StatsCounter counter_; | ||||
int64_t start_time_; | ||||
int64_t stop_time_; | ||||
// Start the timer. | ||||
void Start(); | ||||
// Stop the timer and record the results. | ||||
void Stop(); | ||||
// Returns true if the timer is running. | ||||
bool Running() { | ||||
return counter_.Enabled() && start_time_ != 0 && stop_time_ == 0; | ||||
} | ||||
}; | ||||
// A Histogram represents a dynamically created histogram in the StatsTable | ||||
. | ||||
// | ||||
// This class is designed to be POD initialized. It will be registered wit | ||||
h | ||||
// the histogram system on first use. For example: | ||||
// Histogram h = { "myhist", 0, 10000, 50, NULL, false }; | ||||
struct Histogram { | ||||
const char* name_; | ||||
int min_; | ||||
int max_; | ||||
int num_buckets_; | ||||
void* histogram_; | ||||
bool lookup_done_; | ||||
// Add a single sample to this histogram. | ||||
void AddSample(int sample); | ||||
// Returns true if this histogram is enabled. | ||||
bool Enabled() { | ||||
return GetHistogram() != NULL; | ||||
} | ||||
protected: | ||||
// Returns the handle to the histogram. | ||||
void* GetHistogram() { | ||||
if (!lookup_done_) { | ||||
lookup_done_ = true; | ||||
histogram_ = CreateHistogram(); | ||||
} | ||||
return histogram_; | ||||
} | ||||
private: | ||||
void* CreateHistogram() const; | ||||
}; | ||||
// A HistogramTimer allows distributions of results to be created | ||||
// HistogramTimer t = { {L"foo", 0, 10000, 50, NULL, false}, 0, 0 }; | ||||
struct HistogramTimer { | ||||
Histogram histogram_; | ||||
int64_t start_time_; | ||||
int64_t stop_time_; | ||||
// Start the timer. | ||||
void Start(); | ||||
// Stop the timer and record the results. | ||||
void Stop(); | ||||
// Returns true if the timer is running. | ||||
bool Running() { | ||||
return histogram_.Enabled() && (start_time_ != 0) && (stop_time_ == 0); | ||||
} | ||||
}; | ||||
// Helper class for scoping a HistogramTimer. | ||||
class HistogramTimerScope BASE_EMBEDDED { | ||||
public: | ||||
explicit HistogramTimerScope(HistogramTimer* timer) : | ||||
timer_(timer) { | ||||
timer_->Start(); | ||||
} | ||||
~HistogramTimerScope() { | ||||
timer_->Stop(); | ||||
} | ||||
private: | ||||
HistogramTimer* timer_; | ||||
}; | ||||
long long _overflows; | } } // namespace v8::internal | |||
SpinLock _lock; | #endif // V8_COUNTERS_H_ | |||
}; | ||||
extern NetworkCounter networkCounter; | ||||
} | ||||
End of changes. 3 change blocks. | ||||
86 lines changed or deleted | 273 lines changed or added | |||