Bug 719176. Add the ability to maintain a temporary buffer of samples. r=ehsan

This lets us make the decision about whether to discard samples later
than when we record them which is important for about:jank.
This commit is contained in:
Jeff Muizelaar 2012-01-18 18:07:46 -05:00
parent 534d4e8c67
commit e8612f5cb7

View File

@ -158,6 +158,7 @@ class Profile
public:
Profile(int aEntrySize)
: mWritePos(0)
, mLastFlushPos(0)
, mReadPos(0)
, mEntrySize(aEntrySize)
{
@ -180,6 +181,72 @@ public:
mEntries[mReadPos] = ProfileEntry();
mReadPos = (mReadPos + 1) % mEntrySize;
}
// we also need to move the flush pos to ensure we
// do not pass it
if (mWritePos == mLastFlushPos) {
mLastFlushPos = (mLastFlushPos + 1) % mEntrySize;
}
}
// flush the new entries
void flush()
{
mLastFlushPos = mWritePos;
}
// discards all of the entries since the last flush()
// NOTE: that if mWritePos happens to wrap around past
// mLastFlushPos we actually only discard mWritePos - mLastFlushPos entries
//
// r = mReadPos
// w = mWritePos
// f = mLastFlushPos
//
// r f w
// |-----------------------------|
// | abcdefghijklmnopq | -> 'abcdefghijklmnopq'
// |-----------------------------|
//
//
// mWritePos and mReadPos have passed mLastFlushPos
// f
// w r
// |-----------------------------|
// |ABCDEFGHIJKLMNOPQRSqrstuvwxyz|
// |-----------------------------|
// w
// r
// |-----------------------------|
// |ABCDEFGHIJKLMNOPQRSqrstuvwxyz| -> ''
// |-----------------------------|
//
//
// mWritePos will end up the same as mReadPos
// r
// w f
// |-----------------------------|
// |ABCDEFGHIJKLMklmnopqrstuvwxyz|
// |-----------------------------|
// r
// w
// |-----------------------------|
// |ABCDEFGHIJKLMklmnopqrstuvwxyz| -> ''
// |-----------------------------|
//
//
// mWritePos has moved past mReadPos
// w r f
// |-----------------------------|
// |ABCDEFdefghijklmnopqrstuvwxyz|
// |-----------------------------|
// r w
// |-----------------------------|
// |ABCDEFdefghijklmnopqrstuvwxyz| -> 'defghijkl'
// |-----------------------------|
void erase()
{
mWritePos = mLastFlushPos;
}
void ToString(StringBuilder &profile)
@ -190,8 +257,9 @@ public:
mSharedLibraryInfo = SharedLibraryInfo::GetInfoForSelf();
}
//XXX: this code is not thread safe and needs to be fixed
int oldReadPos = mReadPos;
while (mReadPos != mWritePos) {
while (mReadPos != mLastFlushPos) {
profile.Append(mEntries[mReadPos].TagToString(this).c_str());
mReadPos = (mReadPos + 1) % mEntrySize;
}
@ -206,8 +274,9 @@ public:
mSharedLibraryInfo = SharedLibraryInfo::GetInfoForSelf();
}
//XXX: this code is not thread safe and needs to be fixed
int oldReadPos = mReadPos;
while (mReadPos != mWritePos) {
while (mReadPos != mLastFlushPos) {
string tag = mEntries[mReadPos].TagToString(this);
fwrite(tag.data(), 1, tag.length(), stream);
mReadPos = (mReadPos + 1) % mEntrySize;
@ -224,6 +293,7 @@ private:
// for simplicity
ProfileEntry *mEntries;
int mWritePos; // points to the next entry we will write to
int mLastFlushPos; // points to the next entry since the last flush()
int mReadPos; // points to the next entry we will read to
int mEntrySize;
bool mNeedsSharedLibraryInfo;
@ -252,6 +322,7 @@ class TableTicker: public Sampler {
{
mUseStackWalk = hasFeature(aFeatures, aFeatureCount, "stackwalk");
mProfile.addTag(ProfileEntry('m', "Start"));
//XXX: It's probably worth splitting the jank profiler out from the regular profiler at some point
mJankOnly = hasFeature(aFeatures, aFeatureCount, "jank");
}
@ -421,6 +492,18 @@ void doSampleStackTrace(Stack *aStack, Profile &aProfile, TickSample *sample)
}
}
/* used to keep track of the last event that we sampled during */
unsigned int sLastSampledEventGeneration = 0;
/* a counter that's incremented everytime we get responsiveness event
* note: it might also be worth tracking everytime we go around
* the event loop */
unsigned int sCurrentEventGeneration = 0;
/* we don't need to worry about overflow because we only treat the
* case of them being the same as special. i.e. we only run into
* a problem if 2^32 events happen between samples that we need
* to know are associated with different events */
void TableTicker::Tick(TickSample* sample)
{
// Marker(s) come before the sample
@ -432,6 +515,16 @@ void TableTicker::Tick(TickSample* sample)
}
mStack->mQueueClearMarker = true;
// if we are on a different event we can discard any temporary samples
// we've kept around
if (sLastSampledEventGeneration != sCurrentEventGeneration) {
// XXX: we also probably want to add an entry to the profile to help
// distinguish which samples are part of the same event. That, or record
// the event generation in each sample
mProfile.erase();
}
sLastSampledEventGeneration = sCurrentEventGeneration;
bool recordSample = true;
if (mJankOnly) {
recordSample = false;
@ -444,17 +537,18 @@ void TableTicker::Tick(TickSample* sample)
}
}
if (recordSample) {
#if defined(USE_BACKTRACE) || defined(USE_NS_STACKWALK)
if (mUseStackWalk) {
doBacktrace(mProfile);
} else {
doSampleStackTrace(mStack, mProfile, sample);
}
#else
if (mUseStackWalk) {
doBacktrace(mProfile);
} else {
doSampleStackTrace(mStack, mProfile, sample);
#endif
}
#else
doSampleStackTrace(mStack, mProfile, sample);
#endif
if (recordSample)
mProfile.flush();
if (!mJankOnly && !sLastTracerEvent.IsNull() && sample) {
TimeDuration delta = sample->timestamp - sLastTracerEvent;
@ -659,6 +753,7 @@ void mozilla_sampler_responsiveness(TimeStamp aTime)
TimeDuration delta = aTime - sLastTracerEvent;
sResponsivenessTimes[sResponsivenessLoc++] = delta.ToMilliseconds();
}
sCurrentEventGeneration++;
sLastTracerEvent = aTime;
}