зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland a=backout on a CLOSED TREE
--HG-- extra : rebase_source : 3bbd9b3ffa46ec76f58d6d4d6ce672dd909b8457
This commit is contained in:
Коммит
5a4b5686f6
|
@ -1,269 +0,0 @@
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
/* Implementation of an asynchronous lock-free logging system. */
|
|
||||||
|
|
||||||
#ifndef mozilla_dom_AsyncLogger_h
|
|
||||||
#define mozilla_dom_AsyncLogger_h
|
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <thread>
|
|
||||||
#include "mozilla/Logging.h"
|
|
||||||
#include "mozilla/Attributes.h"
|
|
||||||
#include "mozilla/MathAlgorithms.h"
|
|
||||||
#include "mozilla/Sprintf.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
// This class implements a lock-free multiple producer single consumer queue of
|
|
||||||
// fixed size log messages, with the following characteristics:
|
|
||||||
// - Unbounded (uses a intrinsic linked list)
|
|
||||||
// - Allocates on Push. Push can be called on any thread.
|
|
||||||
// - Deallocates on Pop. Pop MUST always be called on the same thread for the
|
|
||||||
// life-time of the queue.
|
|
||||||
//
|
|
||||||
// In our scenario, the producer threads are real-time, they can't block. The
|
|
||||||
// consummer thread runs every now and then and empties the queue to a log
|
|
||||||
// file, on disk.
|
|
||||||
//
|
|
||||||
// Having fixed size messages and jemalloc is probably not the fastest, but
|
|
||||||
// allows having a simpler design, we count on the fact that jemalloc will get
|
|
||||||
// the memory from a thread-local source most of the time.
|
|
||||||
template<size_t MESSAGE_LENGTH>
|
|
||||||
class MPSCQueue
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct Message {
|
|
||||||
Message()
|
|
||||||
{
|
|
||||||
mNext.store(nullptr, std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
Message(const Message& aMessage) = delete;
|
|
||||||
void operator=(const Message& aMessage) = delete;
|
|
||||||
|
|
||||||
char data[MESSAGE_LENGTH];
|
|
||||||
std::atomic<Message*> mNext;
|
|
||||||
};
|
|
||||||
// Creates a new MPSCQueue. Initially, the queue has a single sentinel node,
|
|
||||||
// pointed to by both mHead and mTail.
|
|
||||||
MPSCQueue()
|
|
||||||
// At construction, the initial message points to nullptr (it has no
|
|
||||||
// successor). It is a sentinel node, that does not contain meaningful
|
|
||||||
// data.
|
|
||||||
: mHead(new Message())
|
|
||||||
, mTail(mHead.load(std::memory_order_relaxed))
|
|
||||||
{ }
|
|
||||||
|
|
||||||
~MPSCQueue()
|
|
||||||
{
|
|
||||||
Message dummy;
|
|
||||||
while (this->Pop(dummy.data)) {}
|
|
||||||
Message* front = mHead.load(std::memory_order_relaxed);
|
|
||||||
delete front;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Push(MPSCQueue<MESSAGE_LENGTH>::Message* aMessage)
|
|
||||||
{
|
|
||||||
// The next two non-commented line are called A and B in this paragraph.
|
|
||||||
// Producer threads i, i-1, etc. are numbered in the order they reached
|
|
||||||
// A in time, thread i being the thread that has reached A first.
|
|
||||||
// Atomically, on line A the new `mHead` is set to be the node that was
|
|
||||||
// just allocated, with strong memory order. From now one, any thread
|
|
||||||
// that reaches A will see that the node just allocated is
|
|
||||||
// effectively the head of the list, and will make itself the new head
|
|
||||||
// of the list.
|
|
||||||
// In a bad case (when thread i executes A and then
|
|
||||||
// is not scheduled for a long time), it is possible that thread i-1 and
|
|
||||||
// subsequent threads create a seemingly disconnected set of nodes, but
|
|
||||||
// they all have the correct value for the next node to set as their
|
|
||||||
// mNext member on their respective stacks (in `prev`), and this is
|
|
||||||
// always correct. When the scheduler resumes, and line B is executed,
|
|
||||||
// the correct linkage is resumed.
|
|
||||||
// Before line B, since mNext for the node the was the last element of
|
|
||||||
// the queue still has an mNext of nullptr, Pop will not see the node
|
|
||||||
// added.
|
|
||||||
// For line A, it's critical to have strong ordering both ways (since
|
|
||||||
// it's going to possibly be read and write repeatidly by multiple
|
|
||||||
// threads)
|
|
||||||
// Line B can have weaker guarantees, it's only going to be written by a
|
|
||||||
// single thread, and we just need to ensure it's read properly by a
|
|
||||||
// single other one.
|
|
||||||
Message* prev = mHead.exchange(aMessage, std::memory_order_acq_rel);
|
|
||||||
prev->mNext.store(aMessage, std::memory_order_release);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocates a new node, copy aInput to the new memory location, and pushes
|
|
||||||
// it to the end of the list.
|
|
||||||
void
|
|
||||||
Push(const char aInput[MESSAGE_LENGTH])
|
|
||||||
{
|
|
||||||
// Create a new message, and copy the messages passed on argument to the
|
|
||||||
// new memory location. We are not touching the queue right now. The
|
|
||||||
// successor for this new node is set to be nullptr.
|
|
||||||
Message* msg = new Message();
|
|
||||||
strncpy(msg->data, aInput, MESSAGE_LENGTH);
|
|
||||||
|
|
||||||
Push(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the content of the first message of the queue to aOutput, and
|
|
||||||
// frees the message. Returns true if there was a message, in which case
|
|
||||||
// `aOutput` contains a valid value. If the queue was empty, returns false,
|
|
||||||
// in which case `aOutput` is left untouched.
|
|
||||||
bool
|
|
||||||
Pop(char aOutput[MESSAGE_LENGTH])
|
|
||||||
{
|
|
||||||
// Similarly, in this paragraph, the two following lines are called A
|
|
||||||
// and B, and threads are called thread i, i-1, etc. in order of
|
|
||||||
// execution of line A.
|
|
||||||
// On line A, the first element of the queue is acquired. It is simply a
|
|
||||||
// sentinel node.
|
|
||||||
// On line B, we acquire the node that has the data we want. If B is
|
|
||||||
// null, then only the sentinel node was present in the queue, we can
|
|
||||||
// safely return false.
|
|
||||||
// mTail can be loaded with relaxed ordering, since it's not written nor
|
|
||||||
// read by any other thread (this queue is single consumer).
|
|
||||||
// mNext can be written to by one of the producer, so it's necessary to
|
|
||||||
// ensure those writes are seen, hence the stricter ordering.
|
|
||||||
Message* tail = mTail.load(std::memory_order_relaxed);
|
|
||||||
Message* next = tail->mNext.load(std::memory_order_acquire);
|
|
||||||
|
|
||||||
if (next == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(aOutput, next->data, MESSAGE_LENGTH);
|
|
||||||
|
|
||||||
// Simply shift the queue one node further, so that the sentinel node is
|
|
||||||
// now pointing to the correct most ancient node. It contains stale data,
|
|
||||||
// but this data will never be read again.
|
|
||||||
// It's only necessary to ensure the previous load on this thread is not
|
|
||||||
// reordered past this line, so release ordering is sufficient here.
|
|
||||||
mTail.store(next, std::memory_order_release);
|
|
||||||
|
|
||||||
// This thread is now the only thing that points to `tail`, it can be
|
|
||||||
// safely deleted.
|
|
||||||
delete tail;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// An atomic pointer to the most recent message in the queue.
|
|
||||||
std::atomic<Message*> mHead;
|
|
||||||
// An atomic pointer to a sentinel node, that points to the oldest message
|
|
||||||
// in the queue.
|
|
||||||
std::atomic<Message*> mTail;
|
|
||||||
|
|
||||||
MPSCQueue(const MPSCQueue&) = delete;
|
|
||||||
void operator=(const MPSCQueue&) = delete;
|
|
||||||
public:
|
|
||||||
// The goal here is to make it easy on the allocator. We pack a pointer in the
|
|
||||||
// message struct, and we still want to do power of two allocations to
|
|
||||||
// minimize allocator slop. The allocation size are going to be constant, so
|
|
||||||
// the allocation is probably going to hit the thread local cache in jemalloc,
|
|
||||||
// making it cheap and, more importantly, lock-free enough.
|
|
||||||
static const size_t MESSAGE_PADDING = sizeof(Message::mNext);
|
|
||||||
private:
|
|
||||||
static_assert(IsPowerOfTwo(MESSAGE_LENGTH + MESSAGE_PADDING),
|
|
||||||
"MPSCQueue internal allocations must have a size that is a"
|
|
||||||
"power of two ");
|
|
||||||
};
|
|
||||||
} // end namespace detail
|
|
||||||
|
|
||||||
// This class implements a lock-free asynchronous logger, that outputs to
|
|
||||||
// MOZ_LOG.
|
|
||||||
// Any thread can use this logger without external synchronization and without
|
|
||||||
// being blocked. This log is suitable for use in real-time audio threads.
|
|
||||||
// Log formatting is best done externally, this class implements the output
|
|
||||||
// mechanism only.
|
|
||||||
// This class uses a thread internally, and must be started and stopped
|
|
||||||
// manually.
|
|
||||||
// If logging is disabled, all the calls are no-op.
|
|
||||||
class AsyncLogger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static const uint32_t MAX_MESSAGE_LENGTH = 512 - detail::MPSCQueue<sizeof(void*)>::MESSAGE_PADDING;
|
|
||||||
|
|
||||||
// aLogModuleName is the name of the MOZ_LOG module.
|
|
||||||
explicit AsyncLogger(const char* aLogModuleName)
|
|
||||||
: mThread(nullptr)
|
|
||||||
, mLogModule(aLogModuleName)
|
|
||||||
, mRunning(false)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
~AsyncLogger()
|
|
||||||
{
|
|
||||||
if (Enabled()) {
|
|
||||||
Stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Start()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(!mRunning, "Double calls to AsyncLogger::Start");
|
|
||||||
if (Enabled()) {
|
|
||||||
mRunning = true;
|
|
||||||
Run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Stop()
|
|
||||||
{
|
|
||||||
if (Enabled()) {
|
|
||||||
if (mRunning) {
|
|
||||||
mRunning = false;
|
|
||||||
mThread->join();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
MOZ_ASSERT(!mRunning && !mThread);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Log(const char* format, ...) MOZ_FORMAT_PRINTF(2,3)
|
|
||||||
{
|
|
||||||
if (Enabled()) {
|
|
||||||
auto* msg = new detail::MPSCQueue<MAX_MESSAGE_LENGTH>::Message();
|
|
||||||
va_list args;
|
|
||||||
va_start(args, format);
|
|
||||||
VsprintfLiteral(msg->data, format, args);
|
|
||||||
va_end(args);
|
|
||||||
mMessageQueue.Push(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Enabled()
|
|
||||||
{
|
|
||||||
return MOZ_LOG_TEST(mLogModule, mozilla::LogLevel::Verbose);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void Run()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(Enabled());
|
|
||||||
mThread.reset(new std::thread([this]() {
|
|
||||||
while (mRunning) {
|
|
||||||
char message[MAX_MESSAGE_LENGTH];
|
|
||||||
while (mMessageQueue.Pop(message) && mRunning) {
|
|
||||||
MOZ_LOG(mLogModule, mozilla::LogLevel::Verbose, ("%s", message));
|
|
||||||
}
|
|
||||||
Sleep();
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sleep() { std::this_thread::sleep_for(std::chrono::milliseconds(10)); }
|
|
||||||
|
|
||||||
std::unique_ptr<std::thread> mThread;
|
|
||||||
mozilla::LazyLogModule mLogModule;
|
|
||||||
detail::MPSCQueue<MAX_MESSAGE_LENGTH> mMessageQueue;
|
|
||||||
std::atomic<bool> mRunning;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end namespace mozilla
|
|
||||||
|
|
||||||
#endif // mozilla_dom_AsyncLogger_h
|
|
|
@ -1,5 +1,4 @@
|
||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* 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,
|
* 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/. */
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
@ -10,7 +9,6 @@
|
||||||
#include "mozilla/ClearOnShutdown.h"
|
#include "mozilla/ClearOnShutdown.h"
|
||||||
#include "mozilla/Unused.h"
|
#include "mozilla/Unused.h"
|
||||||
#include "CubebUtils.h"
|
#include "CubebUtils.h"
|
||||||
#include "Tracing.h"
|
|
||||||
|
|
||||||
#ifdef MOZ_WEBRTC
|
#ifdef MOZ_WEBRTC
|
||||||
#include "webrtc/MediaEngineWebRTC.h"
|
#include "webrtc/MediaEngineWebRTC.h"
|
||||||
|
@ -883,9 +881,6 @@ long
|
||||||
AudioCallbackDriver::DataCallback(const AudioDataValue* aInputBuffer,
|
AudioCallbackDriver::DataCallback(const AudioDataValue* aInputBuffer,
|
||||||
AudioDataValue* aOutputBuffer, long aFrames)
|
AudioDataValue* aOutputBuffer, long aFrames)
|
||||||
{
|
{
|
||||||
TRACE_AUDIO_CALLBACK_BUDGET(aFrames, mSampleRate);
|
|
||||||
TRACE_AUDIO_CALLBACK();
|
|
||||||
|
|
||||||
// Don't add the callback until we're inited and ready
|
// Don't add the callback until we're inited and ready
|
||||||
if (!mAddedMixer) {
|
if (!mAddedMixer) {
|
||||||
mGraphImpl->mMixer.AddCallback(this);
|
mGraphImpl->mMixer.AddCallback(this);
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
#include "mozilla/Unused.h"
|
#include "mozilla/Unused.h"
|
||||||
#include "mtransport/runnable_utils.h"
|
#include "mtransport/runnable_utils.h"
|
||||||
#include "VideoUtils.h"
|
#include "VideoUtils.h"
|
||||||
#include "Tracing.h"
|
|
||||||
|
|
||||||
#include "webaudio/blink/DenormalDisabler.h"
|
#include "webaudio/blink/DenormalDisabler.h"
|
||||||
#include "webaudio/blink/HRTFDatabaseLoader.h"
|
#include "webaudio/blink/HRTFDatabaseLoader.h"
|
||||||
|
@ -42,8 +41,6 @@ using namespace mozilla::dom;
|
||||||
using namespace mozilla::gfx;
|
using namespace mozilla::gfx;
|
||||||
using namespace mozilla::media;
|
using namespace mozilla::media;
|
||||||
|
|
||||||
mozilla::AsyncLogger gMSGTraceLogger("MSGTracing");
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
LazyLogModule gMediaStreamGraphLog("MediaStreamGraph");
|
LazyLogModule gMediaStreamGraphLog("MediaStreamGraph");
|
||||||
|
@ -71,10 +68,6 @@ MediaStreamGraphImpl::~MediaStreamGraphImpl()
|
||||||
"All streams should have been destroyed by messages from the main thread");
|
"All streams should have been destroyed by messages from the main thread");
|
||||||
LOG(LogLevel::Debug, ("MediaStreamGraph %p destroyed", this));
|
LOG(LogLevel::Debug, ("MediaStreamGraph %p destroyed", this));
|
||||||
LOG(LogLevel::Debug, ("MediaStreamGraphImpl::~MediaStreamGraphImpl"));
|
LOG(LogLevel::Debug, ("MediaStreamGraphImpl::~MediaStreamGraphImpl"));
|
||||||
|
|
||||||
#ifdef TRACING
|
|
||||||
gMSGTraceLogger.Stop();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1129,7 +1122,6 @@ MediaStreamGraphImpl::RunMessageAfterProcessing(UniquePtr<ControlMessage> aMessa
|
||||||
void
|
void
|
||||||
MediaStreamGraphImpl::RunMessagesInQueue()
|
MediaStreamGraphImpl::RunMessagesInQueue()
|
||||||
{
|
{
|
||||||
TRACE_AUDIO_CALLBACK();
|
|
||||||
MOZ_ASSERT(OnGraphThread());
|
MOZ_ASSERT(OnGraphThread());
|
||||||
// Calculate independent action times for each batch of messages (each
|
// Calculate independent action times for each batch of messages (each
|
||||||
// batch corresponding to an event loop task). This isolates the performance
|
// batch corresponding to an event loop task). This isolates the performance
|
||||||
|
@ -1147,7 +1139,6 @@ MediaStreamGraphImpl::RunMessagesInQueue()
|
||||||
void
|
void
|
||||||
MediaStreamGraphImpl::UpdateGraph(GraphTime aEndBlockingDecisions)
|
MediaStreamGraphImpl::UpdateGraph(GraphTime aEndBlockingDecisions)
|
||||||
{
|
{
|
||||||
TRACE_AUDIO_CALLBACK();
|
|
||||||
MOZ_ASSERT(OnGraphThread());
|
MOZ_ASSERT(OnGraphThread());
|
||||||
MOZ_ASSERT(aEndBlockingDecisions >= mProcessedTime);
|
MOZ_ASSERT(aEndBlockingDecisions >= mProcessedTime);
|
||||||
// The next state computed time can be the same as the previous: it
|
// The next state computed time can be the same as the previous: it
|
||||||
|
@ -1243,7 +1234,6 @@ MediaStreamGraphImpl::UpdateGraph(GraphTime aEndBlockingDecisions)
|
||||||
void
|
void
|
||||||
MediaStreamGraphImpl::Process()
|
MediaStreamGraphImpl::Process()
|
||||||
{
|
{
|
||||||
TRACE_AUDIO_CALLBACK();
|
|
||||||
MOZ_ASSERT(OnGraphThread());
|
MOZ_ASSERT(OnGraphThread());
|
||||||
// Play stream contents.
|
// Play stream contents.
|
||||||
bool allBlockedForever = true;
|
bool allBlockedForever = true;
|
||||||
|
@ -1348,7 +1338,6 @@ MediaStreamGraphImpl::UpdateMainThreadState()
|
||||||
bool
|
bool
|
||||||
MediaStreamGraphImpl::OneIteration(GraphTime aStateEnd)
|
MediaStreamGraphImpl::OneIteration(GraphTime aStateEnd)
|
||||||
{
|
{
|
||||||
TRACE_AUDIO_CALLBACK();
|
|
||||||
// Changes to LIFECYCLE_RUNNING occur before starting or reviving the graph
|
// Changes to LIFECYCLE_RUNNING occur before starting or reviving the graph
|
||||||
// thread, and so the monitor need not be held to check mLifecycleState.
|
// thread, and so the monitor need not be held to check mLifecycleState.
|
||||||
// LIFECYCLE_THREAD_NOT_STARTED is possible when shutting down offline
|
// LIFECYCLE_THREAD_NOT_STARTED is possible when shutting down offline
|
||||||
|
@ -1555,7 +1544,6 @@ public:
|
||||||
}
|
}
|
||||||
NS_IMETHOD Run() override
|
NS_IMETHOD Run() override
|
||||||
{
|
{
|
||||||
TRACE();
|
|
||||||
if (mGraph) {
|
if (mGraph) {
|
||||||
mGraph->RunInStableState(mSourceIsMSG);
|
mGraph->RunInStableState(mSourceIsMSG);
|
||||||
}
|
}
|
||||||
|
@ -2777,7 +2765,6 @@ SourceMediaStream::PullNewData(
|
||||||
StreamTime aDesiredUpToTime,
|
StreamTime aDesiredUpToTime,
|
||||||
nsTArray<RefPtr<SourceMediaStream::NotifyPullPromise>>& aPromises)
|
nsTArray<RefPtr<SourceMediaStream::NotifyPullPromise>>& aPromises)
|
||||||
{
|
{
|
||||||
TRACE_AUDIO_CALLBACK();
|
|
||||||
MutexAutoLock lock(mMutex);
|
MutexAutoLock lock(mMutex);
|
||||||
if (!mPullEnabled || mFinished) {
|
if (!mPullEnabled || mFinished) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -3627,12 +3614,6 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(GraphDriverType aDriverRequested,
|
||||||
} else {
|
} else {
|
||||||
mDriver = new SystemClockDriver(this);
|
mDriver = new SystemClockDriver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TRACING
|
|
||||||
// This is a noop if the logger has not been enabled.
|
|
||||||
gMSGTraceLogger.Start();
|
|
||||||
gMSGTraceLogger.Log("[");
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
mDriver = new OfflineClockDriver(this, MEDIA_GRAPH_TARGET_PERIOD_MS);
|
mDriver = new OfflineClockDriver(this, MEDIA_GRAPH_TARGET_PERIOD_MS);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,13 +25,6 @@ class nsIRunnable;
|
||||||
class nsIGlobalObject;
|
class nsIGlobalObject;
|
||||||
class nsPIDOMWindowInner;
|
class nsPIDOMWindowInner;
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
class AsyncLogger;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern mozilla::AsyncLogger gMSGTraceLogger;
|
|
||||||
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
class nsAutoRefTraits<SpeexResamplerState> : public nsPointerRefTraits<SpeexResamplerState>
|
class nsAutoRefTraits<SpeexResamplerState> : public nsPointerRefTraits<SpeexResamplerState>
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
#include "nsIRunnable.h"
|
#include "nsIRunnable.h"
|
||||||
#include "nsIThread.h"
|
#include "nsIThread.h"
|
||||||
#include "nsITimer.h"
|
#include "nsITimer.h"
|
||||||
#include "AsyncLogger.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
|
|
|
@ -1,96 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
#include "Tracing.h"
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
#include "AsyncLogger.h"
|
|
||||||
#include "mozilla/TimeStamp.h"
|
|
||||||
|
|
||||||
using namespace mozilla;
|
|
||||||
|
|
||||||
uint64_t
|
|
||||||
AutoTracer::NowInUs()
|
|
||||||
{
|
|
||||||
static TimeStamp base = TimeStamp::Now();
|
|
||||||
return (TimeStamp::Now() - base).ToMicroseconds();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
AutoTracer::PrintEvent(const char* aName,
|
|
||||||
const char* aCategory,
|
|
||||||
const char* aComment,
|
|
||||||
TracingPhase aPhase,
|
|
||||||
uint64_t aTime,
|
|
||||||
uint64_t aPID,
|
|
||||||
uint64_t aThread)
|
|
||||||
{
|
|
||||||
mLogger.Log("{\"name\": \"%s\", \"cat\": \"%s\", \"ph\": \"%c\","
|
|
||||||
"\"ts\": %" PRIu64 ", \"pid\": %" PRIu64 ", \"tid\":"
|
|
||||||
" %" PRIu64 ", \"args\": { \"comment\": \"%s\"}},",
|
|
||||||
aName, aCategory, TRACING_PHASE_STRINGS[static_cast<int>(aPhase)],
|
|
||||||
aTime, aPID, aThread, aComment);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
AutoTracer::PrintBudget(const char* aName,
|
|
||||||
const char* aCategory,
|
|
||||||
const char* aComment,
|
|
||||||
uint64_t aDuration,
|
|
||||||
uint64_t aPID,
|
|
||||||
uint64_t aThread,
|
|
||||||
uint64_t aFrames)
|
|
||||||
{
|
|
||||||
mLogger.Log("{\"name\": \"%s\", \"cat\": \"%s\", \"ph\": \"X\","
|
|
||||||
"\"ts\": %" PRIu64 ", \"dur\": %" PRIu64 ", \"pid\": %" PRIu64 ","
|
|
||||||
"\"tid\": %" PRIu64 ", \"args\": { \"comment\": %" PRIu64 "}},",
|
|
||||||
aName, aCategory, NowInUs(), aDuration, aPID, aThread, aFrames);
|
|
||||||
}
|
|
||||||
|
|
||||||
AutoTracer::AutoTracer(AsyncLogger& aLogger,
|
|
||||||
const char* aLocation,
|
|
||||||
uint64_t aPID,
|
|
||||||
uint64_t aTID,
|
|
||||||
EventType aEventType,
|
|
||||||
uint64_t aFrames,
|
|
||||||
uint64_t aSampleRate)
|
|
||||||
: mLogger(aLogger)
|
|
||||||
, mLocation(aLocation)
|
|
||||||
, mEventType(aEventType)
|
|
||||||
, mPID(aPID)
|
|
||||||
, mTID(aTID)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(aEventType == EventType::BUDGET);
|
|
||||||
|
|
||||||
float durationUS = (static_cast<float>(aFrames) / aSampleRate) * 1e6;
|
|
||||||
PrintBudget(aLocation, "perf", mComment, durationUS, mPID, mTID, aFrames);
|
|
||||||
}
|
|
||||||
|
|
||||||
AutoTracer::AutoTracer(AsyncLogger& aLogger,
|
|
||||||
const char* aLocation,
|
|
||||||
uint64_t aPID,
|
|
||||||
uint64_t aTID,
|
|
||||||
EventType aEventType,
|
|
||||||
const char* aComment)
|
|
||||||
: mLogger(aLogger)
|
|
||||||
, mLocation(aLocation)
|
|
||||||
, mComment(aComment)
|
|
||||||
, mEventType(aEventType)
|
|
||||||
, mPID(aPID)
|
|
||||||
, mTID(aTID)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(aEventType == EventType::DURATION);
|
|
||||||
PrintEvent(aLocation, "perf", mComment, TracingPhase::BEGIN, NowInUs(), aPID, aTID);
|
|
||||||
}
|
|
||||||
|
|
||||||
AutoTracer::~AutoTracer()
|
|
||||||
{
|
|
||||||
if (mEventType == EventType::DURATION) {
|
|
||||||
PrintEvent(mLocation, "perf", mComment, TracingPhase::END, NowInUs(), mPID, mTID);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,140 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
||||||
/* 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 TRACING_H
|
|
||||||
#define TRACING_H
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
#include "AsyncLogger.h"
|
|
||||||
|
|
||||||
#include <mozilla/Attributes.h>
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#include <process.h>
|
|
||||||
#define getpid() _getpid()
|
|
||||||
#else
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
// MSVC
|
|
||||||
#define FUNCTION_SIGNATURE __FUNCSIG__
|
|
||||||
#elif defined(__GNUC__)
|
|
||||||
// gcc, clang
|
|
||||||
#define FUNCTION_SIGNATURE __PRETTY_FUNCTION__
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TRACING
|
|
||||||
/* TRACE is for use in the real-time audio rendering thread.
|
|
||||||
* It would be better to always pass in the thread id. However, the thread an
|
|
||||||
* audio callback runs on can change when the underlying audio device change,
|
|
||||||
* and also it seems to be called from a thread pool in a round-robin fashion
|
|
||||||
* when audio remoting is activated, making the traces unreadable.
|
|
||||||
* The thread on which the AudioCallbackDriver::DataCallback is to always
|
|
||||||
* be thread 0, and the budget is set to always be thread 1. This allows
|
|
||||||
* displaying those elements in two separate lanes.
|
|
||||||
* The other thread have "normal" tid. Hashing allows being able to get a
|
|
||||||
* string representation that is unique and guaranteed to be portable. */
|
|
||||||
#define TRACE_AUDIO_CALLBACK() \
|
|
||||||
AutoTracer trace(gMSGTraceLogger, FUNCTION_SIGNATURE, getpid(), 0);
|
|
||||||
#define TRACE_AUDIO_CALLBACK_BUDGET(aFrames, aSampleRate) \
|
|
||||||
AutoTracer budget(gMSGTraceLogger, "Real-time budget", getpid(), 1, \
|
|
||||||
AutoTracer::EventType::BUDGET, aFrames, aSampleRate);
|
|
||||||
#define TRACE() \
|
|
||||||
AutoTracer trace(gMSGTraceLogger, FUNCTION_SIGNATURE, getpid(), \
|
|
||||||
std::hash<std::thread::id>{}(std::this_thread::get_id()));
|
|
||||||
#define TRACE_COMMENT(aComment) \
|
|
||||||
AutoTracer trace(gMSGTraceLogger, FUNCTION_SIGNATURE, getpid(), \
|
|
||||||
std::hash<std::thread::id>{}(std::this_thread::get_id()), \
|
|
||||||
AutoTracer::EventType::DURATION, \
|
|
||||||
aComment);
|
|
||||||
#else
|
|
||||||
#define TRACE_AUDIO_CALLBACK()
|
|
||||||
#define TRACE_AUDIO_CALLBACK_BUDGET(aFrames, aSampleRate)
|
|
||||||
#define TRACE()
|
|
||||||
#define TRACE_COMMENT(aComment)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class MOZ_RAII AutoTracer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum class EventType
|
|
||||||
{
|
|
||||||
DURATION,
|
|
||||||
BUDGET
|
|
||||||
};
|
|
||||||
|
|
||||||
AutoTracer(mozilla::AsyncLogger& aLogger,
|
|
||||||
const char* aLocation,
|
|
||||||
uint64_t aPID,
|
|
||||||
uint64_t aTID,
|
|
||||||
EventType aEventType = EventType::DURATION,
|
|
||||||
const char* aComment = nullptr);
|
|
||||||
AutoTracer(mozilla::AsyncLogger& aLogger,
|
|
||||||
const char* aLocation,
|
|
||||||
uint64_t aPID,
|
|
||||||
uint64_t aTID,
|
|
||||||
EventType aEventType,
|
|
||||||
uint64_t aSampleRate,
|
|
||||||
uint64_t aFrames);
|
|
||||||
~AutoTracer();
|
|
||||||
private:
|
|
||||||
uint64_t NowInUs();
|
|
||||||
|
|
||||||
enum class TracingPhase
|
|
||||||
{
|
|
||||||
BEGIN,
|
|
||||||
END,
|
|
||||||
COMPLETE
|
|
||||||
};
|
|
||||||
|
|
||||||
const char TRACING_PHASE_STRINGS[3] = {
|
|
||||||
'B',
|
|
||||||
'E',
|
|
||||||
'X'
|
|
||||||
};
|
|
||||||
|
|
||||||
void PrintEvent(const char* aName,
|
|
||||||
const char* aCategory,
|
|
||||||
const char* aComment,
|
|
||||||
TracingPhase aPhase,
|
|
||||||
uint64_t aTime,
|
|
||||||
uint64_t aPID,
|
|
||||||
uint64_t aThread);
|
|
||||||
|
|
||||||
void PrintBudget(const char* aName,
|
|
||||||
const char* aCategory,
|
|
||||||
const char* aComment,
|
|
||||||
uint64_t aDuration,
|
|
||||||
uint64_t aPID,
|
|
||||||
uint64_t aThread,
|
|
||||||
uint64_t aFrames);
|
|
||||||
|
|
||||||
// The logger to use. It musdt have a lifetime longer than the block an
|
|
||||||
// instance of this class traces.
|
|
||||||
mozilla::AsyncLogger& mLogger;
|
|
||||||
// The location for this trace point, arbitrary string literal, often the
|
|
||||||
// name of the calling function, with a static lifetime.
|
|
||||||
const char* mLocation;
|
|
||||||
// A comment for this trace point, abitrary string literal with a static
|
|
||||||
// lifetime.
|
|
||||||
const char* mComment;
|
|
||||||
// The event type, for now either a budget or a duration.
|
|
||||||
const EventType mEventType;
|
|
||||||
// The process ID of the calling process. Traces are grouped by PID in the
|
|
||||||
// vizualizer.
|
|
||||||
const uint64_t mPID;
|
|
||||||
// The thread ID of the calling thread, will be displayed in a separate
|
|
||||||
// section in the trace visualizer.
|
|
||||||
const uint64_t mTID;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#undef getpid
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* TRACING_H */
|
|
|
@ -68,7 +68,6 @@ TrackUnionStream::TrackUnionStream()
|
||||||
}
|
}
|
||||||
void TrackUnionStream::ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags)
|
void TrackUnionStream::ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags)
|
||||||
{
|
{
|
||||||
TRACE();
|
|
||||||
if (IsFinishedOnGraphThread()) {
|
if (IsFinishedOnGraphThread()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,6 @@ XPIDL_MODULE = 'dom_media'
|
||||||
EXPORTS += [
|
EXPORTS += [
|
||||||
'ADTSDecoder.h',
|
'ADTSDecoder.h',
|
||||||
'ADTSDemuxer.h',
|
'ADTSDemuxer.h',
|
||||||
'AsyncLogger.h',
|
|
||||||
'AudioBufferUtils.h',
|
'AudioBufferUtils.h',
|
||||||
'AudioChannelFormat.h',
|
'AudioChannelFormat.h',
|
||||||
'AudioCompactor.h',
|
'AudioCompactor.h',
|
||||||
|
@ -154,7 +153,6 @@ EXPORTS += [
|
||||||
'StreamTracks.h',
|
'StreamTracks.h',
|
||||||
'ThreadPoolCOMListener.h',
|
'ThreadPoolCOMListener.h',
|
||||||
'TimeUnits.h',
|
'TimeUnits.h',
|
||||||
'Tracing.h',
|
|
||||||
'TrackID.h',
|
'TrackID.h',
|
||||||
'TrackUnionStream.h',
|
'TrackUnionStream.h',
|
||||||
'VideoFrameContainer.h',
|
'VideoFrameContainer.h',
|
||||||
|
@ -265,7 +263,6 @@ UNIFIED_SOURCES += [
|
||||||
'TextTrackCueList.cpp',
|
'TextTrackCueList.cpp',
|
||||||
'TextTrackList.cpp',
|
'TextTrackList.cpp',
|
||||||
'TextTrackRegion.cpp',
|
'TextTrackRegion.cpp',
|
||||||
'Tracing.cpp',
|
|
||||||
'TrackUnionStream.cpp',
|
'TrackUnionStream.cpp',
|
||||||
'VideoFrameContainer.cpp',
|
'VideoFrameContainer.cpp',
|
||||||
'VideoPlaybackQuality.cpp',
|
'VideoPlaybackQuality.cpp',
|
||||||
|
@ -329,7 +326,6 @@ if CONFIG['MOZ_WEBRTC']:
|
||||||
]
|
]
|
||||||
|
|
||||||
DEFINES['MOZILLA_INTERNAL_API'] = True
|
DEFINES['MOZILLA_INTERNAL_API'] = True
|
||||||
DEFINES['TRACING'] = True
|
|
||||||
|
|
||||||
if CONFIG['MOZ_ANDROID_HLS_SUPPORT']:
|
if CONFIG['MOZ_ANDROID_HLS_SUPPORT']:
|
||||||
DEFINES['MOZ_ANDROID_HLS_SUPPORT'] = True
|
DEFINES['MOZ_ANDROID_HLS_SUPPORT'] = True
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
#include "mozilla/ErrorNames.h"
|
#include "mozilla/ErrorNames.h"
|
||||||
#include "mtransport/runnable_utils.h"
|
#include "mtransport/runnable_utils.h"
|
||||||
#include "nsAutoPtr.h"
|
#include "nsAutoPtr.h"
|
||||||
#include "Tracing.h"
|
|
||||||
|
|
||||||
// scoped_ptr.h uses FF
|
// scoped_ptr.h uses FF
|
||||||
#ifdef FF
|
#ifdef FF
|
||||||
|
@ -1184,7 +1183,6 @@ MediaEngineWebRTCMicrophoneSource::NotifyInputData(MediaStreamGraph* aGraph,
|
||||||
TrackRate aRate,
|
TrackRate aRate,
|
||||||
uint32_t aChannels)
|
uint32_t aChannels)
|
||||||
{
|
{
|
||||||
TRACE_AUDIO_CALLBACK();
|
|
||||||
// If some processing is necessary, packetize and insert in the WebRTC.org
|
// If some processing is necessary, packetize and insert in the WebRTC.org
|
||||||
// code. Otherwise, directly insert the mic data in the MSG, bypassing all processing.
|
// code. Otherwise, directly insert the mic data in the MSG, bypassing all processing.
|
||||||
if (PassThrough()) {
|
if (PassThrough()) {
|
||||||
|
|
|
@ -50,7 +50,6 @@
|
||||||
#include "transportlayer.h"
|
#include "transportlayer.h"
|
||||||
#include "transportlayerdtls.h"
|
#include "transportlayerdtls.h"
|
||||||
#include "transportlayerice.h"
|
#include "transportlayerice.h"
|
||||||
#include "Tracing.h"
|
|
||||||
|
|
||||||
#include "webrtc/base/bind.h"
|
#include "webrtc/base/bind.h"
|
||||||
#include "webrtc/base/keep_ref_until_done.h"
|
#include "webrtc/base/keep_ref_until_done.h"
|
||||||
|
@ -1932,13 +1931,12 @@ MediaPipelineTransmit::PipelineListener::NotifyRealtimeTrackData(
|
||||||
aMedia.GetDuration());
|
aMedia.GetDuration());
|
||||||
|
|
||||||
if (aMedia.GetType() == MediaSegment::VIDEO) {
|
if (aMedia.GetType() == MediaSegment::VIDEO) {
|
||||||
TRACE_COMMENT("Video");
|
|
||||||
// We have to call the upstream NotifyRealtimeTrackData and
|
// We have to call the upstream NotifyRealtimeTrackData and
|
||||||
// MediaStreamVideoSink will route them to SetCurrentFrames.
|
// MediaStreamVideoSink will route them to SetCurrentFrames.
|
||||||
MediaStreamVideoSink::NotifyRealtimeTrackData(aGraph, aOffset, aMedia);
|
MediaStreamVideoSink::NotifyRealtimeTrackData(aGraph, aOffset, aMedia);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
TRACE_COMMENT("Audio");
|
|
||||||
NewData(aMedia, aGraph->GraphRate());
|
NewData(aMedia, aGraph->GraphRate());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2024,7 +2022,6 @@ MediaPipelineTransmit::PipelineListener::NewData(const MediaSegment& aMedia,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const VideoSegment* video = static_cast<const VideoSegment*>(&aMedia);
|
const VideoSegment* video = static_cast<const VideoSegment*>(&aMedia);
|
||||||
|
|
||||||
for (VideoSegment::ConstChunkIterator iter(*video); !iter.IsEnded();
|
for (VideoSegment::ConstChunkIterator iter(*video); !iter.IsEnded();
|
||||||
iter.Next()) {
|
iter.Next()) {
|
||||||
mConverter->QueueVideoChunk(*iter, !mEnabled);
|
mConverter->QueueVideoChunk(*iter, !mEnabled);
|
||||||
|
@ -2237,7 +2234,6 @@ private:
|
||||||
|
|
||||||
void NotifyPullImpl(StreamTime aDesiredTime)
|
void NotifyPullImpl(StreamTime aDesiredTime)
|
||||||
{
|
{
|
||||||
TRACE();
|
|
||||||
uint32_t samplesPer10ms = mRate / 100;
|
uint32_t samplesPer10ms = mRate / 100;
|
||||||
|
|
||||||
// mSource's rate is not necessarily the same as the graph rate, since there
|
// mSource's rate is not necessarily the same as the graph rate, since there
|
||||||
|
|
Загрузка…
Ссылка в новой задаче