2013-03-10 15:00:23 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2013-09-25 08:28:34 -07:00
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2013-03-10 15:00:23 -07:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
#ifndef MOZ_PROFILE_ENTRY_H
|
|
|
|
#define MOZ_PROFILE_ENTRY_H
|
|
|
|
|
2015-03-20 20:48:31 -07:00
|
|
|
#include <map>
|
2013-03-29 12:34:49 -07:00
|
|
|
#include <ostream>
|
2013-09-27 09:08:45 -07:00
|
|
|
#include "GeckoProfiler.h"
|
2013-03-25 14:57:28 -07:00
|
|
|
#include "platform.h"
|
2014-04-21 13:48:47 -07:00
|
|
|
#include "JSStreamWriter.h"
|
2013-09-25 08:28:34 -07:00
|
|
|
#include "ProfilerBacktrace.h"
|
2015-01-30 11:49:32 -08:00
|
|
|
#include "nsRefPtr.h"
|
2015-03-20 20:48:31 -07:00
|
|
|
#include "mozilla/Maybe.h"
|
2013-03-10 15:00:23 -07:00
|
|
|
#include "mozilla/Mutex.h"
|
2015-03-20 20:48:31 -07:00
|
|
|
#include "mozilla/Vector.h"
|
2014-04-07 12:29:07 -07:00
|
|
|
#include "gtest/MozGtestFriend.h"
|
2015-01-30 11:49:32 -08:00
|
|
|
#include "mozilla/UniquePtr.h"
|
2013-03-10 15:00:23 -07:00
|
|
|
|
2013-03-25 14:57:28 -07:00
|
|
|
class ThreadProfile;
|
2013-03-10 15:00:23 -07:00
|
|
|
|
2014-03-31 05:19:00 -07:00
|
|
|
#pragma pack(push, 1)
|
|
|
|
|
2013-03-25 14:57:28 -07:00
|
|
|
class ProfileEntry
|
2013-03-10 15:00:23 -07:00
|
|
|
{
|
|
|
|
public:
|
2013-03-25 14:57:28 -07:00
|
|
|
ProfileEntry();
|
2013-03-10 15:00:23 -07:00
|
|
|
|
|
|
|
// aTagData must not need release (i.e. be a string from the text segment)
|
2013-03-25 14:57:28 -07:00
|
|
|
ProfileEntry(char aTagName, const char *aTagData);
|
|
|
|
ProfileEntry(char aTagName, void *aTagPtr);
|
2013-07-10 21:27:04 -07:00
|
|
|
ProfileEntry(char aTagName, ProfilerMarker *aTagMarker);
|
2014-04-10 07:52:23 -07:00
|
|
|
ProfileEntry(char aTagName, float aTagFloat);
|
2013-03-25 14:57:28 -07:00
|
|
|
ProfileEntry(char aTagName, uintptr_t aTagOffset);
|
|
|
|
ProfileEntry(char aTagName, Address aTagAddress);
|
|
|
|
ProfileEntry(char aTagName, int aTagLine);
|
|
|
|
ProfileEntry(char aTagName, char aTagChar);
|
2013-03-10 15:00:23 -07:00
|
|
|
bool is_ent_hint(char hintChar);
|
|
|
|
bool is_ent_hint();
|
|
|
|
bool is_ent(char tagName);
|
|
|
|
void* get_tagPtr();
|
2013-07-10 21:27:04 -07:00
|
|
|
const ProfilerMarker* getMarker() {
|
|
|
|
MOZ_ASSERT(mTagName == 'm');
|
|
|
|
return mTagMarker;
|
|
|
|
}
|
2013-03-10 15:00:23 -07:00
|
|
|
|
2013-03-25 14:57:28 -07:00
|
|
|
char getTagName() const { return mTagName; }
|
|
|
|
|
2013-03-10 15:00:23 -07:00
|
|
|
private:
|
2014-04-07 12:29:07 -07:00
|
|
|
FRIEND_TEST(ThreadProfile, InsertOneTag);
|
|
|
|
FRIEND_TEST(ThreadProfile, InsertOneTagWithTinyBuffer);
|
|
|
|
FRIEND_TEST(ThreadProfile, InsertTagsNoWrap);
|
|
|
|
FRIEND_TEST(ThreadProfile, InsertTagsWrap);
|
|
|
|
FRIEND_TEST(ThreadProfile, MemoryMeasure);
|
2015-01-30 11:49:32 -08:00
|
|
|
friend class ProfileBuffer;
|
2013-03-10 15:00:23 -07:00
|
|
|
union {
|
|
|
|
const char* mTagData;
|
|
|
|
char mTagChars[sizeof(void*)];
|
|
|
|
void* mTagPtr;
|
2013-07-10 21:27:04 -07:00
|
|
|
ProfilerMarker* mTagMarker;
|
2014-04-10 07:52:23 -07:00
|
|
|
float mTagFloat;
|
2013-03-10 15:00:23 -07:00
|
|
|
Address mTagAddress;
|
|
|
|
uintptr_t mTagOffset;
|
2014-06-04 11:37:49 -07:00
|
|
|
int mTagInt;
|
2013-03-10 15:00:23 -07:00
|
|
|
char mTagChar;
|
|
|
|
};
|
|
|
|
char mTagName;
|
|
|
|
};
|
|
|
|
|
2014-03-31 05:19:00 -07:00
|
|
|
#pragma pack(pop)
|
|
|
|
|
2013-03-25 14:57:28 -07:00
|
|
|
typedef void (*IterateTagsCallback)(const ProfileEntry& entry, const char* tagStringData);
|
2013-03-10 15:00:23 -07:00
|
|
|
|
2015-03-20 20:48:31 -07:00
|
|
|
class UniqueJITOptimizations {
|
|
|
|
public:
|
|
|
|
bool empty() const {
|
|
|
|
return mOpts.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
mozilla::Maybe<unsigned> getIndex(void* addr, JSRuntime* rt);
|
|
|
|
void stream(JSStreamWriter& b, JSRuntime* rt);
|
|
|
|
|
|
|
|
private:
|
|
|
|
struct OptimizationKey {
|
|
|
|
void* mEntryAddr;
|
|
|
|
uint8_t mIndex;
|
|
|
|
bool operator<(const OptimizationKey& other) const;
|
|
|
|
};
|
|
|
|
|
|
|
|
mozilla::Vector<OptimizationKey> mOpts;
|
|
|
|
std::map<OptimizationKey, unsigned> mOptToIndexMap;
|
|
|
|
};
|
|
|
|
|
2015-01-30 11:49:32 -08:00
|
|
|
class ProfileBuffer {
|
|
|
|
public:
|
2015-02-06 01:49:00 -08:00
|
|
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ProfileBuffer)
|
2015-01-30 11:49:32 -08:00
|
|
|
|
2015-03-27 16:39:25 -07:00
|
|
|
explicit ProfileBuffer(int aEntrySize, uint32_t aGeneration = 0);
|
2015-01-30 11:49:32 -08:00
|
|
|
|
|
|
|
void addTag(const ProfileEntry& aTag);
|
|
|
|
void IterateTagsForThread(IterateTagsCallback aCallback, int aThreadId);
|
2015-03-20 20:48:31 -07:00
|
|
|
void StreamSamplesToJSObject(JSStreamWriter& b, int aThreadId, JSRuntime* rt,
|
|
|
|
UniqueJITOptimizations& aUniqueOpts);
|
2015-01-30 11:49:32 -08:00
|
|
|
void StreamMarkersToJSObject(JSStreamWriter& b, int aThreadId);
|
|
|
|
void DuplicateLastSample(int aThreadId);
|
|
|
|
|
|
|
|
void addStoredMarker(ProfilerMarker* aStoredMarker);
|
|
|
|
void deleteExpiredStoredMarkers();
|
|
|
|
|
|
|
|
protected:
|
|
|
|
char* processDynamicTag(int readPos, int* tagsConsumed, char* tagBuff);
|
|
|
|
int FindLastSampleOfThread(int aThreadId);
|
|
|
|
|
2015-03-05 16:23:17 -08:00
|
|
|
~ProfileBuffer();
|
2015-01-30 11:49:32 -08:00
|
|
|
|
|
|
|
public:
|
|
|
|
// Circular buffer 'Keep One Slot Open' implementation for simplicity
|
|
|
|
mozilla::UniquePtr<ProfileEntry[]> mEntries;
|
|
|
|
|
|
|
|
// Points to the next entry we will write to, which is also the one at which
|
|
|
|
// we need to stop reading.
|
|
|
|
int mWritePos;
|
|
|
|
|
|
|
|
// Points to the entry at which we can start reading.
|
|
|
|
int mReadPos;
|
|
|
|
|
|
|
|
// The number of entries in our buffer.
|
|
|
|
int mEntrySize;
|
|
|
|
|
|
|
|
// How many times mWritePos has wrapped around.
|
2015-03-27 16:39:25 -07:00
|
|
|
uint32_t mGeneration;
|
2015-01-30 11:49:32 -08:00
|
|
|
|
|
|
|
// Markers that marker entries in the buffer might refer to.
|
|
|
|
ProfilerMarkerLinkedList mStoredMarkers;
|
|
|
|
};
|
|
|
|
|
2013-03-25 14:57:28 -07:00
|
|
|
class ThreadProfile
|
2013-03-10 15:00:23 -07:00
|
|
|
{
|
|
|
|
public:
|
2015-01-30 11:49:32 -08:00
|
|
|
ThreadProfile(ThreadInfo* aThreadInfo, ProfileBuffer* aBuffer);
|
2013-09-25 08:28:34 -07:00
|
|
|
virtual ~ThreadProfile();
|
2015-01-30 11:49:32 -08:00
|
|
|
void addTag(const ProfileEntry& aTag);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Track a marker which has been inserted into the ThreadProfile.
|
|
|
|
* This marker can safely be deleted once the generation has
|
|
|
|
* expired.
|
|
|
|
*/
|
|
|
|
void addStoredMarker(ProfilerMarker *aStoredMarker);
|
|
|
|
|
2013-03-25 14:57:28 -07:00
|
|
|
void IterateTags(IterateTagsCallback aCallback);
|
|
|
|
void ToStreamAsJSON(std::ostream& stream);
|
2013-09-05 16:10:37 -07:00
|
|
|
JSObject *ToJSObject(JSContext *aCx);
|
2013-03-10 15:00:23 -07:00
|
|
|
PseudoStack* GetPseudoStack();
|
|
|
|
mozilla::Mutex* GetMutex();
|
2014-04-21 13:48:47 -07:00
|
|
|
void StreamJSObject(JSStreamWriter& b);
|
2013-09-25 08:28:34 -07:00
|
|
|
void BeginUnwind();
|
|
|
|
virtual void EndUnwind();
|
|
|
|
virtual SyncProfile* AsSyncProfile() { return nullptr; }
|
2013-03-29 12:34:49 -07:00
|
|
|
|
|
|
|
bool IsMainThread() const { return mIsMainThread; }
|
2014-06-06 14:53:42 -07:00
|
|
|
const char* Name() const { return mThreadInfo->Name(); }
|
2015-01-30 11:49:32 -08:00
|
|
|
int ThreadId() const { return mThreadId; }
|
2013-03-29 12:34:49 -07:00
|
|
|
|
2014-06-06 14:53:42 -07:00
|
|
|
PlatformData* GetPlatformData() const { return mPlatformData; }
|
2013-09-11 11:50:46 -07:00
|
|
|
void* GetStackTop() const { return mStackTop; }
|
2014-03-28 13:08:22 -07:00
|
|
|
void DuplicateLastSample();
|
2014-06-06 14:53:42 -07:00
|
|
|
|
|
|
|
ThreadInfo* GetThreadInfo() const { return mThreadInfo; }
|
|
|
|
ThreadResponsiveness* GetThreadResponsiveness() { return &mRespInfo; }
|
2014-10-06 11:12:52 -07:00
|
|
|
void SetPendingDelete()
|
|
|
|
{
|
|
|
|
mPseudoStack = nullptr;
|
|
|
|
mPlatformData = nullptr;
|
|
|
|
}
|
2015-02-25 13:43:39 -08:00
|
|
|
|
|
|
|
uint32_t bufferGeneration() const {
|
|
|
|
return mBuffer->mGeneration;
|
|
|
|
}
|
|
|
|
|
2013-03-10 15:00:23 -07:00
|
|
|
private:
|
2014-04-07 12:29:07 -07:00
|
|
|
FRIEND_TEST(ThreadProfile, InsertOneTag);
|
|
|
|
FRIEND_TEST(ThreadProfile, InsertOneTagWithTinyBuffer);
|
|
|
|
FRIEND_TEST(ThreadProfile, InsertTagsNoWrap);
|
|
|
|
FRIEND_TEST(ThreadProfile, InsertTagsWrap);
|
|
|
|
FRIEND_TEST(ThreadProfile, MemoryMeasure);
|
2014-06-06 14:53:42 -07:00
|
|
|
ThreadInfo* mThreadInfo;
|
2015-01-30 11:49:32 -08:00
|
|
|
|
|
|
|
const nsRefPtr<ProfileBuffer> mBuffer;
|
|
|
|
|
2013-03-10 15:00:23 -07:00
|
|
|
PseudoStack* mPseudoStack;
|
|
|
|
mozilla::Mutex mMutex;
|
2015-01-30 11:49:32 -08:00
|
|
|
int mThreadId;
|
2013-03-29 12:34:49 -07:00
|
|
|
bool mIsMainThread;
|
2013-04-03 15:59:17 -07:00
|
|
|
PlatformData* mPlatformData; // Platform specific data.
|
2013-09-11 11:50:46 -07:00
|
|
|
void* const mStackTop;
|
2014-06-06 14:53:42 -07:00
|
|
|
ThreadResponsiveness mRespInfo;
|
2014-05-19 11:31:31 -07:00
|
|
|
|
|
|
|
// Only Linux is using a signal sender, instead of stopping the thread, so we
|
|
|
|
// need some space to store the data which cannot be collected in the signal
|
|
|
|
// handler code.
|
|
|
|
#ifdef XP_LINUX
|
|
|
|
public:
|
|
|
|
int64_t mRssMemory;
|
2014-06-05 08:31:09 -07:00
|
|
|
int64_t mUssMemory;
|
2014-05-19 11:31:31 -07:00
|
|
|
#endif
|
2013-03-10 15:00:23 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* ndef MOZ_PROFILE_ENTRY_H */
|