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:
jbroman 2017-03-21 12:31:14 -07:00 committed by Commit bot
parent 3d3dafee71
commit 53562fd9fb
2 changed files with 162 additions and 81 deletions

View File

@ -61,26 +61,65 @@ void HistogramTimer::Stop() {
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) \
name##_ = Histogram(#caption, min, max, num_buckets, isolate);
{&Counters::name##_, #caption, min, max, num_buckets},
HISTOGRAM_RANGE_LIST(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) \
name##_ = HistogramTimer(#caption, 0, max, HistogramTimer::res, 50, isolate);
{&Counters::name##_, #caption, max, HistogramTimer::res},
HISTOGRAM_TIMER_LIST(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) \
name##_ = AggregatableHistogramTimer(#caption, 0, 10000000, 50, isolate);
static const struct {
AggregatableHistogramTimer Counters::*member;
const char* caption;
} kAggregatableHistogramTimers[] = {
#define AHT(name, caption) {&Counters::name##_, #caption},
AGGREGATABLE_HISTOGRAM_TIMER_LIST(AHT)
#undef AHT
};
for (const auto& aht : kAggregatableHistogramTimers) {
this->*aht.member =
AggregatableHistogramTimer(aht.caption, 0, 10000000, 50, isolate);
}
#define HP(name, caption) \
name##_ = Histogram(#caption, 0, 101, 100, isolate);
static const struct {
Histogram Counters::*member;
const char* caption;
} kHistogramPercentages[] = {
#define HP(name, caption) {&Counters::name##_, #caption},
HISTOGRAM_PERCENTAGE_LIST(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
// 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,
// the high is the upper limit.
// For n = 50, low = 1000, high = 500000: the factor = 1.13.
#define HM(name, caption) \
name##_ = Histogram(#caption, 1000, 500000, 50, isolate);
static const struct {
Histogram Counters::*member;
const char* caption;
} kLegacyMemoryHistograms[] = {
#define HM(name, caption) {&Counters::name##_, #caption},
HISTOGRAM_LEGACY_MEMORY_LIST(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.
static const struct {
Histogram Counters::*member;
AggregatedMemoryHistogram<Histogram> Counters::*aggregated;
const char* caption;
} kMemoryHistograms[] = {
#define HM(name, caption) \
name##_ = Histogram(#caption, 4000, 2000000, 100, isolate);
{&Counters::name##_, &Counters::aggregated_##name##_, #caption},
HISTOGRAM_MEMORY_LIST(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) \
aggregated_##name##_ = AggregatedMemoryHistogram<Histogram>(&name##_);
HISTOGRAM_MEMORY_LIST(HM)
#undef HM
#define SC(name, caption) \
name##_ = StatsCounter(isolate, "c:" #caption);
STATS_COUNTER_LIST_1(SC)
STATS_COUNTER_LIST_2(SC)
// clang-format off
static const struct {
StatsCounter Counters::*member;
const char* caption;
} kStatsCounters[] = {
#define SC(name, caption) {&Counters::name##_, "c:" #caption},
STATS_COUNTER_LIST_1(SC) STATS_COUNTER_LIST_2(SC)
#undef SC
#define SC(name) \
count_of_##name##_ = StatsCounter(isolate, "c:" "V8.CountOf_" #name); \
size_of_##name##_ = StatsCounter(isolate, "c:" "V8.SizeOf_" #name);
{&Counters::count_of_##name##_, "c:" "V8.CountOf_" #name}, \
{&Counters::size_of_##name##_, "c:" "V8.SizeOf_" #name},
INSTANCE_TYPE_LIST(SC)
#undef SC
#define SC(name) \
count_of_CODE_TYPE_##name##_ = \
StatsCounter(isolate, "c:" "V8.CountOf_CODE_TYPE-" #name); \
size_of_CODE_TYPE_##name##_ = \
StatsCounter(isolate, "c:" "V8.SizeOf_CODE_TYPE-" #name);
{&Counters::count_of_CODE_TYPE_##name##_, \
"c:" "V8.CountOf_CODE_TYPE-" #name}, \
{&Counters::size_of_CODE_TYPE_##name##_, \
"c:" "V8.SizeOf_CODE_TYPE-" #name},
CODE_KIND_LIST(SC)
#undef SC
#define SC(name) \
count_of_FIXED_ARRAY_##name##_ = \
StatsCounter(isolate, "c:" "V8.CountOf_FIXED_ARRAY-" #name); \
size_of_FIXED_ARRAY_##name##_ = \
StatsCounter(isolate, "c:" "V8.SizeOf_FIXED_ARRAY-" #name);
{&Counters::count_of_FIXED_ARRAY_##name##_, \
"c:" "V8.CountOf_FIXED_ARRAY-" #name}, \
{&Counters::size_of_FIXED_ARRAY_##name##_, \
"c:" "V8.SizeOf_FIXED_ARRAY-" #name},
FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(SC)
#undef SC
#define SC(name) \
count_of_CODE_AGE_##name##_ = \
StatsCounter(isolate, "c:" "V8.CountOf_CODE_AGE-" #name); \
size_of_CODE_AGE_##name##_ = \
StatsCounter(isolate, "c:" "V8.SizeOf_CODE_AGE-" #name);
{&Counters::count_of_CODE_AGE_##name##_, \
"c:" "V8.CountOf_CODE_AGE-" #name}, \
{&Counters::size_of_CODE_AGE_##name##_, \
"c:" "V8.SizeOf_CODE_AGE-" #name},
CODE_AGE_LIST_COMPLETE(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() {
count_ = 0;
time_ = base::TimeDelta();
time_ = 0;
}
void RuntimeCallCounter::Dump(v8::tracing::TracedValue* value) {
value->BeginArray(name_);
value->AppendDouble(count_);
value->AppendDouble(time_.InMicroseconds());
value->AppendDouble(time_);
value->EndArray();
}
void RuntimeCallCounter::Add(RuntimeCallCounter* other) {
count_ += other->count();
time_ += other->time();
time_ += other->time().InMicroseconds();
}
void RuntimeCallTimer::Snapshot() {
@ -303,6 +361,29 @@ void RuntimeCallTimer::Snapshot() {
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
const RuntimeCallStats::CounterId RuntimeCallStats::counters[] = {
#define CALL_RUNTIME_COUNTER(name) &RuntimeCallStats::name,

View File

@ -486,21 +486,29 @@ double AggregatedMemoryHistogram<Histogram>::Aggregate(double current_ms,
class RuntimeCallCounter final {
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 Dump(v8::tracing::TracedValue* value);
void Add(RuntimeCallCounter* other);
const char* name() const { return name_; }
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 Add(base::TimeDelta delta) { time_ += delta; }
void Add(base::TimeDelta delta) { time_ += delta.InMicroseconds(); }
private:
RuntimeCallCounter() {}
const char* name_;
int64_t count_ = 0;
base::TimeDelta time_;
int64_t count_;
// 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
@ -827,25 +835,22 @@ class RuntimeCallTimer final {
class RuntimeCallStats final : public ZoneObject {
public:
typedef RuntimeCallCounter RuntimeCallStats::*CounterId;
V8_EXPORT_PRIVATE RuntimeCallStats();
#define CALL_RUNTIME_COUNTER(name) \
RuntimeCallCounter name = RuntimeCallCounter(#name);
#define CALL_RUNTIME_COUNTER(name) RuntimeCallCounter name;
FOR_EACH_MANUAL_COUNTER(CALL_RUNTIME_COUNTER)
#undef CALL_RUNTIME_COUNTER
#define CALL_RUNTIME_COUNTER(name, nargs, ressize) \
RuntimeCallCounter Runtime_##name = RuntimeCallCounter(#name);
RuntimeCallCounter Runtime_##name;
FOR_EACH_INTRINSIC(CALL_RUNTIME_COUNTER)
#undef CALL_RUNTIME_COUNTER
#define CALL_BUILTIN_COUNTER(name) \
RuntimeCallCounter Builtin_##name = RuntimeCallCounter(#name);
#define CALL_BUILTIN_COUNTER(name) RuntimeCallCounter Builtin_##name;
BUILTIN_LIST_C(CALL_BUILTIN_COUNTER)
#undef CALL_BUILTIN_COUNTER
#define CALL_BUILTIN_COUNTER(name) \
RuntimeCallCounter API_##name = RuntimeCallCounter("API_" #name);
#define CALL_BUILTIN_COUNTER(name) RuntimeCallCounter API_##name;
FOR_EACH_API_COUNTER(CALL_BUILTIN_COUNTER)
#undef CALL_BUILTIN_COUNTER
#define CALL_BUILTIN_COUNTER(name) \
RuntimeCallCounter Handler_##name = RuntimeCallCounter(#name);
#define CALL_BUILTIN_COUNTER(name) RuntimeCallCounter Handler_##name;
FOR_EACH_HANDLER_COUNTER(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_NOINLINE void Dump(v8::tracing::TracedValue* value);
RuntimeCallStats() {
Reset();
in_use_ = false;
}
RuntimeCallTimer* current_timer() { return current_timer_.Value(); }
bool InUse() { return in_use_; }