Generate less code in v8::internal::Counters constructor
This saves 72 KiB (approximately 0.1%) of the Chrome APK size of for ARM/Android. In Counters, each similar group of counters generates a compact data structure, which a loop then iterates over, rather than having the full loop unrolled (though the compiler will automatically unroll small ones). In RuntimeCallStats, the compiler was not being clever enough to avoid initializing count_ and time_ to zero individually, even after the initialization of names was moved into a loop. As a result, RuntimeCallCounter was modified to have a non-initializing constructor for exclusive use by RuntimeCallStats, which explicitly initializes the counters in a loop. Since v8::base::TimeDelta does not support an uninitialized state, time_ was changed to be stored as int64_t microseconds internally, which generates the same code (it's the same representation as TimeDelta). BUG=v8:6119 Review-Url: https://codereview.chromium.org/2759033002 Cr-Commit-Position: refs/heads/master@{#43996}
This commit is contained in:
parent
3d3dafee71
commit
53562fd9fb
163
src/counters.cc
163
src/counters.cc
@ -61,26 +61,65 @@ void HistogramTimer::Stop() {
|
|||||||
|
|
||||||
|
|
||||||
Counters::Counters(Isolate* isolate) {
|
Counters::Counters(Isolate* isolate) {
|
||||||
|
static const struct {
|
||||||
|
Histogram Counters::*member;
|
||||||
|
const char* caption;
|
||||||
|
int min;
|
||||||
|
int max;
|
||||||
|
int num_buckets;
|
||||||
|
} kHistograms[] = {
|
||||||
#define HR(name, caption, min, max, num_buckets) \
|
#define HR(name, caption, min, max, num_buckets) \
|
||||||
name##_ = Histogram(#caption, min, max, num_buckets, isolate);
|
{&Counters::name##_, #caption, min, max, num_buckets},
|
||||||
HISTOGRAM_RANGE_LIST(HR)
|
HISTOGRAM_RANGE_LIST(HR)
|
||||||
#undef HR
|
#undef HR
|
||||||
|
};
|
||||||
|
for (const auto& histogram : kHistograms) {
|
||||||
|
this->*histogram.member =
|
||||||
|
Histogram(histogram.caption, histogram.min, histogram.max,
|
||||||
|
histogram.num_buckets, isolate);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
HistogramTimer Counters::*member;
|
||||||
|
const char* caption;
|
||||||
|
int max;
|
||||||
|
HistogramTimer::Resolution res;
|
||||||
|
} kHistogramTimers[] = {
|
||||||
#define HT(name, caption, max, res) \
|
#define HT(name, caption, max, res) \
|
||||||
name##_ = HistogramTimer(#caption, 0, max, HistogramTimer::res, 50, isolate);
|
{&Counters::name##_, #caption, max, HistogramTimer::res},
|
||||||
HISTOGRAM_TIMER_LIST(HT)
|
HISTOGRAM_TIMER_LIST(HT)
|
||||||
#undef HT
|
#undef HT
|
||||||
|
};
|
||||||
|
for (const auto& timer : kHistogramTimers) {
|
||||||
|
this->*timer.member =
|
||||||
|
HistogramTimer(timer.caption, 0, timer.max, timer.res, 50, isolate);
|
||||||
|
}
|
||||||
|
|
||||||
#define AHT(name, caption) \
|
static const struct {
|
||||||
name##_ = AggregatableHistogramTimer(#caption, 0, 10000000, 50, isolate);
|
AggregatableHistogramTimer Counters::*member;
|
||||||
|
const char* caption;
|
||||||
|
} kAggregatableHistogramTimers[] = {
|
||||||
|
#define AHT(name, caption) {&Counters::name##_, #caption},
|
||||||
AGGREGATABLE_HISTOGRAM_TIMER_LIST(AHT)
|
AGGREGATABLE_HISTOGRAM_TIMER_LIST(AHT)
|
||||||
#undef AHT
|
#undef AHT
|
||||||
|
};
|
||||||
|
for (const auto& aht : kAggregatableHistogramTimers) {
|
||||||
|
this->*aht.member =
|
||||||
|
AggregatableHistogramTimer(aht.caption, 0, 10000000, 50, isolate);
|
||||||
|
}
|
||||||
|
|
||||||
#define HP(name, caption) \
|
static const struct {
|
||||||
name##_ = Histogram(#caption, 0, 101, 100, isolate);
|
Histogram Counters::*member;
|
||||||
|
const char* caption;
|
||||||
|
} kHistogramPercentages[] = {
|
||||||
|
#define HP(name, caption) {&Counters::name##_, #caption},
|
||||||
HISTOGRAM_PERCENTAGE_LIST(HP)
|
HISTOGRAM_PERCENTAGE_LIST(HP)
|
||||||
#undef HP
|
#undef HP
|
||||||
|
};
|
||||||
|
for (const auto& percentage : kHistogramPercentages) {
|
||||||
|
this->*percentage.member =
|
||||||
|
Histogram(percentage.caption, 0, 101, 100, isolate);
|
||||||
|
}
|
||||||
|
|
||||||
// Exponential histogram assigns bucket limits to points
|
// Exponential histogram assigns bucket limits to points
|
||||||
// p[1], p[2], ... p[n] such that p[i+1] / p[i] = constant.
|
// p[1], p[2], ... p[n] such that p[i+1] / p[i] = constant.
|
||||||
@ -88,57 +127,76 @@ Counters::Counters(Isolate* isolate) {
|
|||||||
// where the n is the number of buckets, the low is the lower limit,
|
// where the n is the number of buckets, the low is the lower limit,
|
||||||
// the high is the upper limit.
|
// the high is the upper limit.
|
||||||
// For n = 50, low = 1000, high = 500000: the factor = 1.13.
|
// For n = 50, low = 1000, high = 500000: the factor = 1.13.
|
||||||
#define HM(name, caption) \
|
static const struct {
|
||||||
name##_ = Histogram(#caption, 1000, 500000, 50, isolate);
|
Histogram Counters::*member;
|
||||||
|
const char* caption;
|
||||||
|
} kLegacyMemoryHistograms[] = {
|
||||||
|
#define HM(name, caption) {&Counters::name##_, #caption},
|
||||||
HISTOGRAM_LEGACY_MEMORY_LIST(HM)
|
HISTOGRAM_LEGACY_MEMORY_LIST(HM)
|
||||||
#undef HM
|
#undef HM
|
||||||
|
};
|
||||||
|
for (const auto& histogram : kLegacyMemoryHistograms) {
|
||||||
|
this->*histogram.member =
|
||||||
|
Histogram(histogram.caption, 1000, 500000, 50, isolate);
|
||||||
|
}
|
||||||
|
|
||||||
// For n = 100, low = 4000, high = 2000000: the factor = 1.06.
|
// For n = 100, low = 4000, high = 2000000: the factor = 1.06.
|
||||||
|
static const struct {
|
||||||
|
Histogram Counters::*member;
|
||||||
|
AggregatedMemoryHistogram<Histogram> Counters::*aggregated;
|
||||||
|
const char* caption;
|
||||||
|
} kMemoryHistograms[] = {
|
||||||
#define HM(name, caption) \
|
#define HM(name, caption) \
|
||||||
name##_ = Histogram(#caption, 4000, 2000000, 100, isolate);
|
{&Counters::name##_, &Counters::aggregated_##name##_, #caption},
|
||||||
HISTOGRAM_MEMORY_LIST(HM)
|
HISTOGRAM_MEMORY_LIST(HM)
|
||||||
#undef HM
|
#undef HM
|
||||||
|
};
|
||||||
|
for (const auto& histogram : kMemoryHistograms) {
|
||||||
|
this->*histogram.member =
|
||||||
|
Histogram(histogram.caption, 4000, 2000000, 100, isolate);
|
||||||
|
this->*histogram.aggregated =
|
||||||
|
AggregatedMemoryHistogram<Histogram>(&(this->*histogram.member));
|
||||||
|
}
|
||||||
|
|
||||||
#define HM(name, caption) \
|
// clang-format off
|
||||||
aggregated_##name##_ = AggregatedMemoryHistogram<Histogram>(&name##_);
|
static const struct {
|
||||||
HISTOGRAM_MEMORY_LIST(HM)
|
StatsCounter Counters::*member;
|
||||||
#undef HM
|
const char* caption;
|
||||||
|
} kStatsCounters[] = {
|
||||||
#define SC(name, caption) \
|
#define SC(name, caption) {&Counters::name##_, "c:" #caption},
|
||||||
name##_ = StatsCounter(isolate, "c:" #caption);
|
STATS_COUNTER_LIST_1(SC) STATS_COUNTER_LIST_2(SC)
|
||||||
|
|
||||||
STATS_COUNTER_LIST_1(SC)
|
|
||||||
STATS_COUNTER_LIST_2(SC)
|
|
||||||
#undef SC
|
#undef SC
|
||||||
|
|
||||||
#define SC(name) \
|
#define SC(name) \
|
||||||
count_of_##name##_ = StatsCounter(isolate, "c:" "V8.CountOf_" #name); \
|
{&Counters::count_of_##name##_, "c:" "V8.CountOf_" #name}, \
|
||||||
size_of_##name##_ = StatsCounter(isolate, "c:" "V8.SizeOf_" #name);
|
{&Counters::size_of_##name##_, "c:" "V8.SizeOf_" #name},
|
||||||
INSTANCE_TYPE_LIST(SC)
|
INSTANCE_TYPE_LIST(SC)
|
||||||
#undef SC
|
#undef SC
|
||||||
|
|
||||||
#define SC(name) \
|
#define SC(name) \
|
||||||
count_of_CODE_TYPE_##name##_ = \
|
{&Counters::count_of_CODE_TYPE_##name##_, \
|
||||||
StatsCounter(isolate, "c:" "V8.CountOf_CODE_TYPE-" #name); \
|
"c:" "V8.CountOf_CODE_TYPE-" #name}, \
|
||||||
size_of_CODE_TYPE_##name##_ = \
|
{&Counters::size_of_CODE_TYPE_##name##_, \
|
||||||
StatsCounter(isolate, "c:" "V8.SizeOf_CODE_TYPE-" #name);
|
"c:" "V8.SizeOf_CODE_TYPE-" #name},
|
||||||
CODE_KIND_LIST(SC)
|
CODE_KIND_LIST(SC)
|
||||||
#undef SC
|
#undef SC
|
||||||
|
|
||||||
#define SC(name) \
|
#define SC(name) \
|
||||||
count_of_FIXED_ARRAY_##name##_ = \
|
{&Counters::count_of_FIXED_ARRAY_##name##_, \
|
||||||
StatsCounter(isolate, "c:" "V8.CountOf_FIXED_ARRAY-" #name); \
|
"c:" "V8.CountOf_FIXED_ARRAY-" #name}, \
|
||||||
size_of_FIXED_ARRAY_##name##_ = \
|
{&Counters::size_of_FIXED_ARRAY_##name##_, \
|
||||||
StatsCounter(isolate, "c:" "V8.SizeOf_FIXED_ARRAY-" #name);
|
"c:" "V8.SizeOf_FIXED_ARRAY-" #name},
|
||||||
FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(SC)
|
FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(SC)
|
||||||
#undef SC
|
#undef SC
|
||||||
|
|
||||||
#define SC(name) \
|
#define SC(name) \
|
||||||
count_of_CODE_AGE_##name##_ = \
|
{&Counters::count_of_CODE_AGE_##name##_, \
|
||||||
StatsCounter(isolate, "c:" "V8.CountOf_CODE_AGE-" #name); \
|
"c:" "V8.CountOf_CODE_AGE-" #name}, \
|
||||||
size_of_CODE_AGE_##name##_ = \
|
{&Counters::size_of_CODE_AGE_##name##_, \
|
||||||
StatsCounter(isolate, "c:" "V8.SizeOf_CODE_AGE-" #name);
|
"c:" "V8.SizeOf_CODE_AGE-" #name},
|
||||||
CODE_AGE_LIST_COMPLETE(SC)
|
CODE_AGE_LIST_COMPLETE(SC)
|
||||||
#undef SC
|
#undef SC
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
for (const auto& counter : kStatsCounters) {
|
||||||
|
this->*counter.member = StatsCounter(isolate, counter.caption);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -275,19 +333,19 @@ class RuntimeCallStatEntries {
|
|||||||
|
|
||||||
void RuntimeCallCounter::Reset() {
|
void RuntimeCallCounter::Reset() {
|
||||||
count_ = 0;
|
count_ = 0;
|
||||||
time_ = base::TimeDelta();
|
time_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RuntimeCallCounter::Dump(v8::tracing::TracedValue* value) {
|
void RuntimeCallCounter::Dump(v8::tracing::TracedValue* value) {
|
||||||
value->BeginArray(name_);
|
value->BeginArray(name_);
|
||||||
value->AppendDouble(count_);
|
value->AppendDouble(count_);
|
||||||
value->AppendDouble(time_.InMicroseconds());
|
value->AppendDouble(time_);
|
||||||
value->EndArray();
|
value->EndArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RuntimeCallCounter::Add(RuntimeCallCounter* other) {
|
void RuntimeCallCounter::Add(RuntimeCallCounter* other) {
|
||||||
count_ += other->count();
|
count_ += other->count();
|
||||||
time_ += other->time();
|
time_ += other->time().InMicroseconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RuntimeCallTimer::Snapshot() {
|
void RuntimeCallTimer::Snapshot() {
|
||||||
@ -303,6 +361,29 @@ void RuntimeCallTimer::Snapshot() {
|
|||||||
Resume(now);
|
Resume(now);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RuntimeCallStats::RuntimeCallStats() : in_use_(false) {
|
||||||
|
static const char* const kNames[] = {
|
||||||
|
#define CALL_RUNTIME_COUNTER(name) #name,
|
||||||
|
FOR_EACH_MANUAL_COUNTER(CALL_RUNTIME_COUNTER) //
|
||||||
|
#undef CALL_RUNTIME_COUNTER
|
||||||
|
#define CALL_RUNTIME_COUNTER(name, nargs, ressize) #name,
|
||||||
|
FOR_EACH_INTRINSIC(CALL_RUNTIME_COUNTER) //
|
||||||
|
#undef CALL_RUNTIME_COUNTER
|
||||||
|
#define CALL_BUILTIN_COUNTER(name) #name,
|
||||||
|
BUILTIN_LIST_C(CALL_BUILTIN_COUNTER) //
|
||||||
|
#undef CALL_BUILTIN_COUNTER
|
||||||
|
#define CALL_BUILTIN_COUNTER(name) "API_" #name,
|
||||||
|
FOR_EACH_API_COUNTER(CALL_BUILTIN_COUNTER) //
|
||||||
|
#undef CALL_BUILTIN_COUNTER
|
||||||
|
#define CALL_BUILTIN_COUNTER(name) #name,
|
||||||
|
FOR_EACH_HANDLER_COUNTER(CALL_BUILTIN_COUNTER)
|
||||||
|
#undef CALL_BUILTIN_COUNTER
|
||||||
|
};
|
||||||
|
for (int i = 0; i < counters_count; i++) {
|
||||||
|
this->*(counters[i]) = RuntimeCallCounter(kNames[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
const RuntimeCallStats::CounterId RuntimeCallStats::counters[] = {
|
const RuntimeCallStats::CounterId RuntimeCallStats::counters[] = {
|
||||||
#define CALL_RUNTIME_COUNTER(name) &RuntimeCallStats::name,
|
#define CALL_RUNTIME_COUNTER(name) &RuntimeCallStats::name,
|
||||||
|
@ -486,21 +486,29 @@ double AggregatedMemoryHistogram<Histogram>::Aggregate(double current_ms,
|
|||||||
|
|
||||||
class RuntimeCallCounter final {
|
class RuntimeCallCounter final {
|
||||||
public:
|
public:
|
||||||
explicit RuntimeCallCounter(const char* name) : name_(name) {}
|
explicit RuntimeCallCounter(const char* name)
|
||||||
|
: name_(name), count_(0), time_(0) {}
|
||||||
V8_NOINLINE void Reset();
|
V8_NOINLINE void Reset();
|
||||||
V8_NOINLINE void Dump(v8::tracing::TracedValue* value);
|
V8_NOINLINE void Dump(v8::tracing::TracedValue* value);
|
||||||
void Add(RuntimeCallCounter* other);
|
void Add(RuntimeCallCounter* other);
|
||||||
|
|
||||||
const char* name() const { return name_; }
|
const char* name() const { return name_; }
|
||||||
int64_t count() const { return count_; }
|
int64_t count() const { return count_; }
|
||||||
base::TimeDelta time() const { return time_; }
|
base::TimeDelta time() const {
|
||||||
|
return base::TimeDelta::FromMicroseconds(time_);
|
||||||
|
}
|
||||||
void Increment() { count_++; }
|
void Increment() { count_++; }
|
||||||
void Add(base::TimeDelta delta) { time_ += delta; }
|
void Add(base::TimeDelta delta) { time_ += delta.InMicroseconds(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
RuntimeCallCounter() {}
|
||||||
|
|
||||||
const char* name_;
|
const char* name_;
|
||||||
int64_t count_ = 0;
|
int64_t count_;
|
||||||
base::TimeDelta time_;
|
// Stored as int64_t so that its initialization can be deferred.
|
||||||
|
int64_t time_;
|
||||||
|
|
||||||
|
friend class RuntimeCallStats;
|
||||||
};
|
};
|
||||||
|
|
||||||
// RuntimeCallTimer is used to keep track of the stack of currently active
|
// RuntimeCallTimer is used to keep track of the stack of currently active
|
||||||
@ -827,25 +835,22 @@ class RuntimeCallTimer final {
|
|||||||
class RuntimeCallStats final : public ZoneObject {
|
class RuntimeCallStats final : public ZoneObject {
|
||||||
public:
|
public:
|
||||||
typedef RuntimeCallCounter RuntimeCallStats::*CounterId;
|
typedef RuntimeCallCounter RuntimeCallStats::*CounterId;
|
||||||
|
V8_EXPORT_PRIVATE RuntimeCallStats();
|
||||||
|
|
||||||
#define CALL_RUNTIME_COUNTER(name) \
|
#define CALL_RUNTIME_COUNTER(name) RuntimeCallCounter name;
|
||||||
RuntimeCallCounter name = RuntimeCallCounter(#name);
|
|
||||||
FOR_EACH_MANUAL_COUNTER(CALL_RUNTIME_COUNTER)
|
FOR_EACH_MANUAL_COUNTER(CALL_RUNTIME_COUNTER)
|
||||||
#undef CALL_RUNTIME_COUNTER
|
#undef CALL_RUNTIME_COUNTER
|
||||||
#define CALL_RUNTIME_COUNTER(name, nargs, ressize) \
|
#define CALL_RUNTIME_COUNTER(name, nargs, ressize) \
|
||||||
RuntimeCallCounter Runtime_##name = RuntimeCallCounter(#name);
|
RuntimeCallCounter Runtime_##name;
|
||||||
FOR_EACH_INTRINSIC(CALL_RUNTIME_COUNTER)
|
FOR_EACH_INTRINSIC(CALL_RUNTIME_COUNTER)
|
||||||
#undef CALL_RUNTIME_COUNTER
|
#undef CALL_RUNTIME_COUNTER
|
||||||
#define CALL_BUILTIN_COUNTER(name) \
|
#define CALL_BUILTIN_COUNTER(name) RuntimeCallCounter Builtin_##name;
|
||||||
RuntimeCallCounter Builtin_##name = RuntimeCallCounter(#name);
|
|
||||||
BUILTIN_LIST_C(CALL_BUILTIN_COUNTER)
|
BUILTIN_LIST_C(CALL_BUILTIN_COUNTER)
|
||||||
#undef CALL_BUILTIN_COUNTER
|
#undef CALL_BUILTIN_COUNTER
|
||||||
#define CALL_BUILTIN_COUNTER(name) \
|
#define CALL_BUILTIN_COUNTER(name) RuntimeCallCounter API_##name;
|
||||||
RuntimeCallCounter API_##name = RuntimeCallCounter("API_" #name);
|
|
||||||
FOR_EACH_API_COUNTER(CALL_BUILTIN_COUNTER)
|
FOR_EACH_API_COUNTER(CALL_BUILTIN_COUNTER)
|
||||||
#undef CALL_BUILTIN_COUNTER
|
#undef CALL_BUILTIN_COUNTER
|
||||||
#define CALL_BUILTIN_COUNTER(name) \
|
#define CALL_BUILTIN_COUNTER(name) RuntimeCallCounter Handler_##name;
|
||||||
RuntimeCallCounter Handler_##name = RuntimeCallCounter(#name);
|
|
||||||
FOR_EACH_HANDLER_COUNTER(CALL_BUILTIN_COUNTER)
|
FOR_EACH_HANDLER_COUNTER(CALL_BUILTIN_COUNTER)
|
||||||
#undef CALL_BUILTIN_COUNTER
|
#undef CALL_BUILTIN_COUNTER
|
||||||
|
|
||||||
@ -875,11 +880,6 @@ class RuntimeCallStats final : public ZoneObject {
|
|||||||
V8_EXPORT_PRIVATE void Print(std::ostream& os);
|
V8_EXPORT_PRIVATE void Print(std::ostream& os);
|
||||||
V8_NOINLINE void Dump(v8::tracing::TracedValue* value);
|
V8_NOINLINE void Dump(v8::tracing::TracedValue* value);
|
||||||
|
|
||||||
RuntimeCallStats() {
|
|
||||||
Reset();
|
|
||||||
in_use_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RuntimeCallTimer* current_timer() { return current_timer_.Value(); }
|
RuntimeCallTimer* current_timer() { return current_timer_.Value(); }
|
||||||
bool InUse() { return in_use_; }
|
bool InUse() { return in_use_; }
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user