1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/renderer/benchmarking_extension.h"
6
7#include "base/command_line.h"
8#include "base/metrics/stats_table.h"
9#include "base/time/time.h"
10#include "content/public/common/content_switches.h"
11#include "content/public/renderer/render_thread.h"
12#include "v8/include/v8.h"
13
14const char kBenchmarkingExtensionName[] = "v8/Benchmarking";
15
16namespace extensions_v8 {
17
18class BenchmarkingWrapper : public v8::Extension {
19 public:
20  BenchmarkingWrapper() :
21      v8::Extension(kBenchmarkingExtensionName,
22        "if (typeof(chrome) == 'undefined') {"
23        "  chrome = {};"
24        "};"
25        "if (typeof(chrome.benchmarking) == 'undefined') {"
26        "  chrome.benchmarking = {};"
27        "};"
28        "chrome.benchmarking.counter = function(name) {"
29        "  native function GetCounter();"
30        "  return GetCounter(name);"
31        "};"
32        "chrome.benchmarking.counterForRenderer = function(name) {"
33        "  native function GetCounterForRenderer();"
34        "  return GetCounterForRenderer(name);"
35        "};"
36        "chrome.benchmarking.isSingleProcess = function() {"
37        "  native function IsSingleProcess();"
38        "  return IsSingleProcess();"
39        "};"
40        "chrome.Interval = function() {"
41        "  var start_ = 0;"
42        "  var stop_ = 0;"
43        "  native function HiResTime();"
44        "  this.start = function() {"
45        "    stop_ = 0;"
46        "    start_ = HiResTime();"
47        "  };"
48        "  this.stop = function() {"
49        "    stop_ = HiResTime();"
50        "    if (start_ == 0)"
51        "      stop_ = 0;"
52        "  };"
53        "  this.microseconds = function() {"
54        "    var stop = stop_;"
55        "    if (stop == 0 && start_ != 0)"
56        "      stop = HiResTime();"
57        "    return Math.ceil(stop - start_);"
58        "  };"
59        "}"
60        ) {}
61
62  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
63      v8::Isolate* isolate,
64      v8::Handle<v8::String> name) OVERRIDE {
65    if (name->Equals(v8::String::NewFromUtf8(isolate, "GetCounter"))) {
66      return v8::FunctionTemplate::New(isolate, GetCounter);
67    } else if (name->Equals(
68                   v8::String::NewFromUtf8(isolate, "GetCounterForRenderer"))) {
69      return v8::FunctionTemplate::New(isolate, GetCounterForRenderer);
70    } else if (name->Equals(
71                   v8::String::NewFromUtf8(isolate, "IsSingleProcess"))) {
72      return v8::FunctionTemplate::New(isolate, IsSingleProcess);
73    } else if (name->Equals(v8::String::NewFromUtf8(isolate, "HiResTime"))) {
74      return v8::FunctionTemplate::New(isolate, HiResTime);
75    }
76
77    return v8::Handle<v8::FunctionTemplate>();
78  }
79
80  /*
81   * Extract the counter name from arguments.
82   */
83  static void ExtractCounterName(
84      const v8::FunctionCallbackInfo<v8::Value>& args,
85      char* name,
86      size_t capacity) {
87    name[0] = 'c';
88    name[1] = ':';
89    args[0]->ToString()->WriteUtf8(&name[2], capacity - 3);
90  }
91
92  static void GetCounter(const v8::FunctionCallbackInfo<v8::Value>& args) {
93    if (!args.Length() || !args[0]->IsString() || !base::StatsTable::current())
94      return;
95
96    char name[256];
97    ExtractCounterName(args, name, sizeof(name));
98    int counter = base::StatsTable::current()->GetCounterValue(name);
99    args.GetReturnValue().Set(static_cast<int32_t>(counter));
100  }
101
102  static void GetCounterForRenderer(
103      const v8::FunctionCallbackInfo<v8::Value>& args) {
104    if (!args.Length() || !args[0]->IsString() || !base::StatsTable::current())
105      return;
106
107    char name[256];
108    ExtractCounterName(args, name, sizeof(name));
109    int counter = base::StatsTable::current()->GetCounterValue(
110        name,
111        base::GetCurrentProcId());
112    args.GetReturnValue().Set(static_cast<int32_t>(counter));
113  }
114
115  static void IsSingleProcess(const v8::FunctionCallbackInfo<v8::Value>& args) {
116    args.GetReturnValue().Set(
117       CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess));
118  }
119
120  static void HiResTime(const v8::FunctionCallbackInfo<v8::Value>& args) {
121    args.GetReturnValue().Set(
122        static_cast<double>(base::TimeTicks::HighResNow().ToInternalValue()));
123  }
124};
125
126v8::Extension* BenchmarkingExtension::Get() {
127  return new BenchmarkingWrapper();
128}
129
130}  // namespace extensions_v8
131