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
205
src/counters.cc
205
src/counters.cc
@ -61,84 +61,142 @@ 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);
|
||||
HISTOGRAM_RANGE_LIST(HR)
|
||||
{&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);
|
||||
HISTOGRAM_TIMER_LIST(HT)
|
||||
{&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);
|
||||
AGGREGATABLE_HISTOGRAM_TIMER_LIST(AHT)
|
||||
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);
|
||||
HISTOGRAM_PERCENTAGE_LIST(HP)
|
||||
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.
|
||||
// The constant factor is equal to the n-th root of (high / low),
|
||||
// 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);
|
||||
HISTOGRAM_LEGACY_MEMORY_LIST(HM)
|
||||
// Exponential histogram assigns bucket limits to points
|
||||
// p[1], p[2], ... p[n] such that p[i+1] / p[i] = constant.
|
||||
// The constant factor is equal to the n-th root of (high / low),
|
||||
// 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.
|
||||
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 n = 100, low = 4000, high = 2000000: the factor = 1.06.
|
||||
};
|
||||
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);
|
||||
HISTOGRAM_MEMORY_LIST(HM)
|
||||
{&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);
|
||||
INSTANCE_TYPE_LIST(SC)
|
||||
#define SC(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);
|
||||
CODE_KIND_LIST(SC)
|
||||
#define SC(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);
|
||||
FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(SC)
|
||||
#define SC(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);
|
||||
CODE_AGE_LIST_COMPLETE(SC)
|
||||
#define SC(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,
|
||||
|
@ -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_; }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user