import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1150717 - Test request with no params in the Network Monitor. r=brings (a60e9e8d9)
- Bug 1168077 - Remove remaining spidermonkey js specific syntax from browser/devtools; r=miker (c98f20c30)
- Bug 1168125 - Fix existing tests, r=jsantell (b1dfa101e)
- Bug 1169439 - Pull out marker definitions into its own file, and move formatter and collapse functions into marker-utils. r=vp (17eb24ab3)
- Bug 1173654 - Part 1: Add logging methods for SurfaceType and ImageFormat. r=Bas (22f2fa019)
- Bug 1169125 - Part 1: Allow sending any DataSourceSurface-backed image over WebRTC and fix failure cases. r=bwc (1fb0def92)
- Bug 1169125 - Part 2: Use UniquePtr for scoped delete of yuv data in MediaPipeline. r=bwc (cdb79e201)
- Bug 1173654 - Part 2: Use namespaces in MediaPipeline.cpp. r=bwc (311696260)
- Bug 1173654 - Part 3: Attempt to GetDataSurface() and convert if sending pure I420 fails. r=bwc, r=jesup (58520b820)
- Bug 1173654 - Part 4: Add detailed logging and asserts to MediaPipeline::ProcessVideoChunk. r=bwc (ba08ae5bc)
- Bug 1155089 - Part 1: Reset |TrackID| for MediaPipelineTransmit::PipelineListener on replaceTrack(). r=bwc (304fb8703)
- adapted Bug 1142688 - Wait for actual audio data on remote side before checking audio sanity. r=jesup,padenot (479f6356c)
- Bug 858927 - Move the mozilla::TimeStamp into mozglue. r=glandium (751938e09)
- Bug 1166559 - Add documentation for ProfileTimelineMarkers from a dev tools perspective. r=fitzgen (ed1563dfb)
- Bug 1141614 - Part 4: Expose cycle collection markers in the devtools frontend; r=jsantell (2eb830de7)
This commit is contained in:
2021-07-30 11:25:34 +08:00
parent 11b532c453
commit 45b8007f3d
182 changed files with 1322 additions and 827 deletions
@@ -17,12 +17,24 @@ createHTML({
// output side. We then sanity check the audio by comparing the frequency domain
// data from both analysers.
/*
* Use as callback to Array.reduce to get an object { value, index }
* that contains the largest element in the array.
*/
var maxWithIndex = function(a, b, i) {
if (b >= a.value) {
return { value: b, index: i };
} else {
return a;
}
};
runNetworkTest(function() {
var test = new PeerConnectionTest();
var audioContext = new AudioContext();
var inputAnalyser;
var outputAnalyser;
var inputAnalyser, outputAnalyser;
var inputData, outputData;
test.setMediaConstraints([{audio: true}], []);
test.chain.replace("PC_LOCAL_GUM", [
@@ -56,12 +68,35 @@ runNetworkTest(function() {
return Promise.resolve();
}]);
test.chain.append([
function CHECK_AUDIO_FLOW(test) {
var inputData = new Uint8Array(inputAnalyser.frequencyBinCount);
function GET_INPUT_DATA(test) {
inputData = new Uint8Array(inputAnalyser.frequencyBinCount);
inputAnalyser.getByteFrequencyData(inputData);
var outputData = new Uint8Array(outputAnalyser.frequencyBinCount);
outputAnalyser.getByteFrequencyData(outputData);
return Promise.resolve();
},
function GET_OUTPUT_DATA(test) {
// We've seen completely silent output with e10s, suggesting that the
// machine is overloaded. Here we wait for actual audio data on the
// output side before we proceed.
return new Promise(resolve => {
is(test.pcRemote.mediaCheckers.length, 1, "One media element on remote side");
var elem = test.pcRemote.mediaCheckers[0].element;
var data = new Uint8Array(outputAnalyser.frequencyBinCount);
elem.ontimeupdate = ev => {
outputAnalyser.getByteFrequencyData(data);
if (data.reduce(maxWithIndex, { value: -1, index: -1 }).value === 0) {
info("Waiting for output data... time: " + elem.currentTime);
return;
}
elem.ontimeupdate = null;
outputData = data;
resolve();
};
});
},
function CHECK_AUDIO_FLOW(test) {
// This is for sanity check only. We'll deem that the streams are working
// if the global maxima in the frequency domain for both the input and
// the output are within 10 (out of 1024) steps of each other.
is(inputData.length, outputData.length, "Equally sized datasets");
var numChecks = 0;
+78
View File
@@ -8,6 +8,7 @@
#include "LayersLogging.h"
#include <stdint.h> // for uint8_t
#include "gfxColor.h" // for gfxRGBA
#include "ImageTypes.h" // for ImageFormat
#include "mozilla/gfx/Matrix.h" // for Matrix4x4, Matrix
#include "mozilla/gfx/Point.h" // for IntSize
#include "nsDebug.h" // for NS_ERROR
@@ -334,6 +335,83 @@ AppendToString(std::stringstream& aStream, mozilla::gfx::SurfaceFormat format,
case SurfaceFormat::A8: aStream << "SurfaceFormat::A8"; break;
case SurfaceFormat::YUV: aStream << "SurfaceFormat::YUV"; break;
case SurfaceFormat::UNKNOWN: aStream << "SurfaceFormat::UNKNOWN"; break;
default:
NS_ERROR("unknown surface format");
aStream << "???";
}
aStream << sfx;
}
void
AppendToString(std::stringstream& aStream, gfx::SurfaceType aType,
const char* pfx, const char* sfx)
{
aStream << pfx;
switch(aType) {
case SurfaceType::DATA:
aStream << "SurfaceType::DATA"; break;
case SurfaceType::D2D1_BITMAP:
aStream << "SurfaceType::D2D1_BITMAP"; break;
case SurfaceType::D2D1_DRAWTARGET:
aStream << "SurfaceType::D2D1_DRAWTARGET"; break;
case SurfaceType::CAIRO:
aStream << "SurfaceType::CAIRO"; break;
case SurfaceType::CAIRO_IMAGE:
aStream << "SurfaceType::CAIRO_IMAGE"; break;
case SurfaceType::COREGRAPHICS_IMAGE:
aStream << "SurfaceType::COREGRAPHICS_IMAGE"; break;
case SurfaceType::COREGRAPHICS_CGCONTEXT:
aStream << "SurfaceType::COREGRAPHICS_CGCONTEXT"; break;
case SurfaceType::SKIA:
aStream << "SurfaceType::SKIA"; break;
case SurfaceType::DUAL_DT:
aStream << "SurfaceType::DUAL_DT"; break;
case SurfaceType::D2D1_1_IMAGE:
aStream << "SurfaceType::D2D1_1_IMAGE"; break;
case SurfaceType::RECORDING:
aStream << "SurfaceType::RECORDING"; break;
case SurfaceType::TILED:
aStream << "SurfaceType::TILED"; break;
default:
NS_ERROR("unknown surface type");
aStream << "???";
}
aStream << sfx;
}
void
AppendToString(std::stringstream& aStream, ImageFormat format,
const char* pfx, const char* sfx)
{
aStream << pfx;
switch (format) {
case ImageFormat::PLANAR_YCBCR:
aStream << "ImageFormat::PLANAR_YCBCR"; break;
case ImageFormat::GRALLOC_PLANAR_YCBCR:
aStream << "ImageFormat::GRALLOC_PLANAR_YCBCR"; break;
case ImageFormat::GONK_CAMERA_IMAGE:
aStream << "ImageFormat::GONK_CAMERA_IMAGE"; break;
case ImageFormat::SHARED_RGB:
aStream << "ImageFormat::SHARED_RGB"; break;
case ImageFormat::CAIRO_SURFACE:
aStream << "ImageFormat::CAIRO_SURFACE"; break;
case ImageFormat::MAC_IOSURFACE:
aStream << "ImageFormat::MAC_IOSURFACE"; break;
case ImageFormat::SURFACE_TEXTURE:
aStream << "ImageFormat::SURFACE_TEXTURE"; break;
case ImageFormat::EGLIMAGE:
aStream << "ImageFormat::EGLIMAGE"; break;
case ImageFormat::D3D9_RGB32_TEXTURE:
aStream << "ImageFormat::D3D9_RBG32_TEXTURE"; break;
case ImageFormat::OVERLAY_IMAGE:
aStream << "ImageFormat::OVERLAY_IMAGE"; break;
case ImageFormat::D3D11_SHARE_HANDLE_TEXTURE:
aStream << "ImageFormat::D3D11_SHARE_HANDLE_TEXTURE"; break;
default:
NS_ERROR("unknown image format");
aStream << "???";
}
aStream << sfx;
+10
View File
@@ -24,6 +24,8 @@ class Matrix4x4;
template <class units> struct RectTyped;
} // namespace gfx
enum class ImageFormat;
namespace layers {
void
@@ -210,6 +212,14 @@ void
AppendToString(std::stringstream& aStream, mozilla::gfx::SurfaceFormat format,
const char* pfx="", const char* sfx="");
void
AppendToString(std::stringstream& aStream, gfx::SurfaceType format,
const char* pfx="", const char* sfx="");
void
AppendToString(std::stringstream& aStream, ImageFormat format,
const char* pfx="", const char* sfx="");
// Sometimes, you just want a string from a single value.
template <typename T>
std::string
+22
View File
@@ -2445,6 +2445,28 @@ AC_PROG_GCC_TRADITIONAL
AC_FUNC_MEMCMP
AC_CHECK_FUNCS([getc_unlocked _getc_nolock gmtime_r localtime_r])
dnl check for clock_gettime(), the CLOCK_MONOTONIC clock
AC_CACHE_CHECK(for clock_gettime(CLOCK_MONOTONIC),
ac_cv_clock_monotonic,
[for libs in "" -lrt; do
_SAVE_LIBS="$LIBS"
LIBS="$LIBS $libs"
AC_TRY_LINK([#include <time.h>],
[ struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts); ],
ac_cv_clock_monotonic=$libs
LIBS="$_SAVE_LIBS"
break,
ac_cv_clock_monotonic=no)
LIBS="$_SAVE_LIBS"
done])
if test "$ac_cv_clock_monotonic" != "no"; then
HAVE_CLOCK_MONOTONIC=1
REALTIME_LIBS=$ac_cv_clock_monotonic
AC_DEFINE(HAVE_CLOCK_MONOTONIC)
AC_SUBST(HAVE_CLOCK_MONOTONIC)
AC_SUBST_LIST(REALTIME_LIBS)
fi
dnl Checks for math functions.
dnl ========================================================
@@ -19,6 +19,7 @@
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
#include "VideoSegment.h"
#include "Layers.h"
#include "LayersLogging.h"
#include "ImageTypes.h"
#include "ImageContainer.h"
#include "VideoUtils.h"
@@ -43,11 +44,13 @@
#endif
#include "mozilla/gfx/Point.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/UniquePtr.h"
#include "logging.h"
using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::layers;
// Logging context
MOZ_MTLOG_MODULE("mediapipeline")
@@ -688,6 +691,8 @@ nsresult MediaPipelineTransmit::ReplaceTrack(DOMMediaStream *domstream,
}
domstream_ = domstream; // Detach clears it
stream_ = domstream->GetStream();
// Unsets the track id after RemoveListener() takes effect.
listener_->UnsetTrackId(stream_->GraphImpl());
track_id_ = track_id;
AttachToTrack(track_id);
return NS_OK;
@@ -853,6 +858,24 @@ nsresult MediaPipeline::PipelineTransport::SendRtcpPacket_s(
out_len);
}
void MediaPipelineTransmit::PipelineListener::
UnsetTrackId(MediaStreamGraphImpl* graph) {
#ifndef USE_FAKE_MEDIA_STREAMS
class Message : public ControlMessage {
public:
Message(PipelineListener* listener) :
ControlMessage(nullptr), listener_(listener) {}
virtual void Run() override
{
listener_->UnsetTrackIdImpl();
}
nsRefPtr<PipelineListener> listener_;
};
graph->AppendMessage(new Message(this));
#else
UnsetTrackIdImpl();
#endif
}
// Called if we're attached with AddDirectListener()
void MediaPipelineTransmit::PipelineListener::
NotifyRealtimeData(MediaStreamGraph* graph, TrackID tid,
@@ -1048,7 +1071,7 @@ void MediaPipelineTransmit::PipelineListener::ProcessAudioChunk(
void MediaPipelineTransmit::PipelineListener::ProcessVideoChunk(
VideoSessionConduit* conduit,
VideoChunk& chunk) {
layers::Image *img = chunk.mFrame.GetImage();
Image *img = chunk.mFrame.GetImage();
// We now need to send the video frame to the other side
if (!img) {
@@ -1057,7 +1080,7 @@ void MediaPipelineTransmit::PipelineListener::ProcessVideoChunk(
}
if (!enabled_ || chunk.mFrame.GetForceBlack()) {
gfx::IntSize size = img->GetSize();
IntSize size = img->GetSize();
uint32_t yPlaneLen = YSIZE(size.width, size.height);
uint32_t cbcrPlaneLen = 2 * CRSIZE(size.width, size.height);
uint32_t length = yPlaneLen + cbcrPlaneLen;
@@ -1087,7 +1110,7 @@ void MediaPipelineTransmit::PipelineListener::ProcessVideoChunk(
ImageFormat format = img->GetFormat();
#ifdef WEBRTC_GONK
layers::GrallocImage* nativeImage = img->AsGrallocImage();
GrallocImage* nativeImage = img->AsGrallocImage();
if (nativeImage) {
android::sp<android::GraphicBuffer> graphicBuffer = nativeImage->GetGraphicBuffer();
int pixelFormat = graphicBuffer->getPixelFormat(); /* PixelFormat is an enum == int */
@@ -1097,10 +1120,10 @@ void MediaPipelineTransmit::PipelineListener::ProcessVideoChunk(
// all android must support this
destFormat = mozilla::kVideoYV12;
break;
case layers::GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP:
case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP:
destFormat = mozilla::kVideoNV21;
break;
case layers::GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_P:
case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_P:
destFormat = mozilla::kVideoI420;
break;
default:
@@ -1121,95 +1144,125 @@ void MediaPipelineTransmit::PipelineListener::ProcessVideoChunk(
height,
destFormat, 0);
graphicBuffer->unlock();
return;
} else
#endif
if (format == ImageFormat::PLANAR_YCBCR) {
// Cast away constness b/c some of the accessors are non-const
layers::PlanarYCbCrImage* yuv =
const_cast<layers::PlanarYCbCrImage *>(
static_cast<const layers::PlanarYCbCrImage *>(img));
// Big-time assumption here that this is all contiguous data coming
// from getUserMedia or other sources.
const layers::PlanarYCbCrData *data = yuv->GetData();
PlanarYCbCrImage* yuv = const_cast<PlanarYCbCrImage *>(
static_cast<const PlanarYCbCrImage *>(img));
uint8_t *y = data->mYChannel;
uint8_t *cb = data->mCbChannel;
uint8_t *cr = data->mCrChannel;
uint32_t width = yuv->GetSize().width;
uint32_t height = yuv->GetSize().height;
uint32_t length = yuv->GetDataSize();
// NOTE: length may be rounded up or include 'other' data (see
// YCbCrImageDataDeserializerBase::ComputeMinBufferSize())
const PlanarYCbCrData *data = yuv->GetData();
if (data) {
uint8_t *y = data->mYChannel;
uint8_t *cb = data->mCbChannel;
uint8_t *cr = data->mCrChannel;
uint32_t width = yuv->GetSize().width;
uint32_t height = yuv->GetSize().height;
uint32_t length = yuv->GetDataSize();
// NOTE: length may be rounded up or include 'other' data (see
// YCbCrImageDataDeserializerBase::ComputeMinBufferSize())
// SendVideoFrame only supports contiguous YCrCb 4:2:0 buffers
// Verify it's contiguous and in the right order
if (cb != (y + YSIZE(width, height)) ||
cr != (cb + CRSIZE(width, height))) {
MOZ_ASSERT(false, "Incorrect cb/cr pointers in ProcessVideoChunk()!");
return;
// XXX Consider modifying these checks if we ever implement
// any subclasses of PlanarYCbCrImage that allow disjoint buffers such
// that y+3(width*height)/2 might go outside the allocation or there are
// pads between y, cr and cb.
// GrallocImage can have wider strides, and so in some cases
// would encode as garbage. If we need to encode it we'll either want to
// modify SendVideoFrame or copy/move the data in the buffer.
if (cb == (y + YSIZE(width, height)) &&
cr == (cb + CRSIZE(width, height)) &&
length >= I420SIZE(width, height)) {
MOZ_MTLOG(ML_DEBUG, "Sending an I420 video frame");
conduit->SendVideoFrame(y, I420SIZE(width, height), width, height, mozilla::kVideoI420, 0);
return;
} else {
MOZ_MTLOG(ML_ERROR, "Unsupported PlanarYCbCrImage format: "
"width=" << width << ", height=" << height << ", y=" << y
<< "\n Expected: cb=y+" << YSIZE(width, height)
<< ", cr=y+" << YSIZE(width, height)
+ CRSIZE(width, height)
<< "\n Observed: cb=y+" << cb - y
<< ", cr=y+" << cr - y
<< "\n ystride=" << data->mYStride
<< ", yskip=" << data->mYSkip
<< "\n cbcrstride=" << data->mCbCrStride
<< ", cbskip=" << data->mCbSkip
<< ", crskip=" << data->mCrSkip
<< "\n ywidth=" << data->mYSize.width
<< ", yheight=" << data->mYSize.height
<< "\n cbcrwidth=" << data->mCbCrSize.width
<< ", cbcrheight=" << data->mCbCrSize.height);
NS_ASSERTION(false, "Unsupported PlanarYCbCrImage format");
}
}
if (length < I420SIZE(width, height)) {
MOZ_ASSERT(false, "Invalid length for ProcessVideoChunk()");
return;
}
// XXX Consider modifying these checks if we ever implement
// any subclasses of PlanarYCbCrImage that allow disjoint buffers such
// that y+3(width*height)/2 might go outside the allocation or there are
// pads between y, cr and cb.
// GrallocImage can have wider strides, and so in some cases
// would encode as garbage. If we need to encode it we'll either want to
// modify SendVideoFrame or copy/move the data in the buffer.
}
// OK, pass it on to the conduit
MOZ_MTLOG(ML_DEBUG, "Sending a video frame");
// Not much for us to do with an error
conduit->SendVideoFrame(y, I420SIZE(width, height), width, height, mozilla::kVideoI420, 0);
} else if(format == ImageFormat::CAIRO_SURFACE) {
layers::CairoImage* rgb =
const_cast<layers::CairoImage *>(
static_cast<const layers::CairoImage *>(img));
gfx::IntSize size = rgb->GetSize();
int half_width = (size.width + 1) >> 1;
int half_height = (size.height + 1) >> 1;
int c_size = half_width * half_height;
int buffer_size = YSIZE(size.width, size.height) + 2 * c_size;
uint8* yuv = (uint8*) malloc(buffer_size); // fallible
if (!yuv)
return;
int cb_offset = YSIZE(size.width, size.height);
int cr_offset = cb_offset + c_size;
RefPtr<gfx::SourceSurface> tempSurf = rgb->GetAsSourceSurface();
RefPtr<gfx::DataSourceSurface> surf = tempSurf->GetDataSurface();
switch (surf->GetFormat()) {
case gfx::SurfaceFormat::B8G8R8A8:
case gfx::SurfaceFormat::B8G8R8X8:
libyuv::ARGBToI420(static_cast<uint8*>(surf->GetData()), surf->Stride(),
yuv, size.width,
yuv + cb_offset, half_width,
yuv + cr_offset, half_width,
size.width, size.height);
break;
case gfx::SurfaceFormat::R5G6B5:
libyuv::RGB565ToI420(static_cast<uint8*>(surf->GetData()), surf->Stride(),
yuv, size.width,
yuv + cb_offset, half_width,
yuv + cr_offset, half_width,
size.width, size.height);
break;
default:
MOZ_MTLOG(ML_ERROR, "Unsupported RGB video format");
MOZ_ASSERT(PR_FALSE);
}
conduit->SendVideoFrame(yuv, buffer_size, size.width, size.height, mozilla::kVideoI420, 0);
free(yuv);
} else {
MOZ_MTLOG(ML_ERROR, "Unsupported video format");
MOZ_ASSERT(PR_FALSE);
RefPtr<SourceSurface> surf = img->GetAsSourceSurface();
if (!surf) {
MOZ_MTLOG(ML_ERROR, "Getting surface from " << Stringify(format) << " image failed");
return;
}
RefPtr<DataSourceSurface> data = surf->GetDataSurface();
if (!data) {
MOZ_MTLOG(ML_ERROR, "Getting data surface from " << Stringify(format)
<< " image with " << Stringify(surf->GetType()) << "("
<< Stringify(surf->GetFormat()) << ") surface failed");
return;
}
IntSize size = img->GetSize();
int half_width = (size.width + 1) >> 1;
int half_height = (size.height + 1) >> 1;
int c_size = half_width * half_height;
int buffer_size = YSIZE(size.width, size.height) + 2 * c_size;
UniquePtr<uint8[]> yuv_scoped(new (fallible) uint8[buffer_size]);
if (!yuv_scoped)
return;
uint8* yuv = yuv_scoped.get();
DataSourceSurface::ScopedMap map(data, DataSourceSurface::READ);
if (!map.IsMapped()) {
MOZ_MTLOG(ML_ERROR, "Reading DataSourceSurface from " << Stringify(format)
<< " image with " << Stringify(surf->GetType()) << "("
<< Stringify(surf->GetFormat()) << ") surface failed");
return;
}
int rv;
int cb_offset = YSIZE(size.width, size.height);
int cr_offset = cb_offset + c_size;
switch (surf->GetFormat()) {
case SurfaceFormat::B8G8R8A8:
case SurfaceFormat::B8G8R8X8:
rv = libyuv::ARGBToI420(static_cast<uint8*>(map.GetData()),
map.GetStride(),
yuv, size.width,
yuv + cb_offset, half_width,
yuv + cr_offset, half_width,
size.width, size.height);
break;
case SurfaceFormat::R5G6B5:
rv = libyuv::RGB565ToI420(static_cast<uint8*>(map.GetData()),
map.GetStride(),
yuv, size.width,
yuv + cb_offset, half_width,
yuv + cr_offset, half_width,
size.width, size.height);
break;
default:
MOZ_MTLOG(ML_ERROR, "Unsupported RGB video format" << Stringify(surf->GetFormat()));
MOZ_ASSERT(PR_FALSE);
return;
}
if (rv != 0) {
MOZ_MTLOG(ML_ERROR, Stringify(surf->GetFormat()) << " to I420 conversion failed");
return;
}
MOZ_MTLOG(ML_DEBUG, "Sending an I420 video frame converted from " <<
Stringify(surf->GetFormat()));
conduit->SendVideoFrame(yuv, buffer_size, size.width, size.height, mozilla::kVideoI420, 0);
}
#endif
@@ -1413,14 +1466,14 @@ MediaPipelineReceiveVideo::PipelineListener::PipelineListener(
width_(640),
height_(480),
#if defined(MOZILLA_XPCOMRT_API)
image_(new mozilla::SimpleImageBuffer),
image_(new SimpleImageBuffer),
#elif defined(MOZILLA_INTERNAL_API)
image_container_(),
image_(),
#endif
monitor_("Video PipelineListener") {
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
image_container_ = layers::LayerManager::CreateImageContainer();
image_container_ = LayerManager::CreateImageContainer();
#endif
}
@@ -1429,7 +1482,7 @@ void MediaPipelineReceiveVideo::PipelineListener::RenderVideoFrame(
unsigned int buffer_size,
uint32_t time_stamp,
int64_t render_time,
const RefPtr<layers::Image>& video_image) {
const RefPtr<Image>& video_image) {
#ifdef MOZILLA_INTERNAL_API
ReentrantMonitorAutoEnter enter(monitor_);
@@ -1447,11 +1500,11 @@ void MediaPipelineReceiveVideo::PipelineListener::RenderVideoFrame(
#else
ImageFormat format = ImageFormat::PLANAR_YCBCR;
#endif
nsRefPtr<layers::Image> image = image_container_->CreateImage(format);
layers::PlanarYCbCrImage* yuvImage = static_cast<layers::PlanarYCbCrImage*>(image.get());
nsRefPtr<Image> image = image_container_->CreateImage(format);
PlanarYCbCrImage* yuvImage = static_cast<PlanarYCbCrImage*>(image.get());
uint8_t* frame = const_cast<uint8_t*>(static_cast<const uint8_t*> (buffer));
layers::PlanarYCbCrData yuvData;
PlanarYCbCrData yuvData;
yuvData.mYChannel = frame;
yuvData.mYSize = IntSize(width_, height_);
yuvData.mYStride = width_;
@@ -1485,7 +1538,7 @@ NotifyPull(MediaStreamGraph* graph, StreamTime desired_time) {
#if defined(MOZILLA_XPCOMRT_API)
nsRefPtr<SimpleImageBuffer> image = image_;
#elif defined(MOZILLA_INTERNAL_API)
nsRefPtr<layers::Image> image = image_;
nsRefPtr<Image> image = image_;
// our constructor sets track_rate_ to the graph rate
MOZ_ASSERT(track_rate_ == source_->GraphRate());
#endif
@@ -466,6 +466,12 @@ public:
}
}
// Dispatches setting the internal TrackID to TRACK_INVALID to the media
// graph thread to keep it in sync with other MediaStreamGraph operations
// like RemoveListener() and AddListener(). The TrackID will be updated on
// the next NewData() callback.
void UnsetTrackId(MediaStreamGraphImpl* graph);
void SetActive(bool active) { active_ = active; }
void SetEnabled(bool enabled) { enabled_ = enabled; }
TrackID trackid() {
@@ -487,6 +493,11 @@ public:
const MediaSegment& media) override;
private:
void UnsetTrackIdImpl() {
MutexAutoLock lock(mMutex);
track_id_ = track_id_external_ = TRACK_INVALID;
}
void NewData(MediaStreamGraph* graph, TrackID tid,
StreamTime offset,
uint32_t events,
@@ -30,6 +30,7 @@ class nsIDOMWindow;
namespace mozilla {
class MediaStreamGraph;
class MediaStreamGraphImpl;
class MediaSegment;
};
@@ -103,6 +104,7 @@ class Fake_MediaStream {
virtual Fake_SourceMediaStream *AsSourceStream() { return nullptr; }
virtual mozilla::MediaStreamGraphImpl *GraphImpl() { return nullptr; }
virtual nsresult Start() { return NS_OK; }
virtual nsresult Stop() { return NS_OK; }
virtual void StopStream() {}
@@ -9,7 +9,8 @@
*/
#include "mozilla/TimeStamp.h"
#include "prenv.h"
#include <stdio.h>
#include <string.h>
namespace mozilla {
@@ -45,13 +46,13 @@ struct TimeStampInitialization
static TimeStampInitialization sInitOnce;
TimeStamp
MFBT_API TimeStamp
TimeStamp::ProcessCreation(bool& aIsInconsistent)
{
aIsInconsistent = false;
if (sInitOnce.mProcessCreation.IsNull()) {
char* mozAppRestart = PR_GetEnv("MOZ_APP_RESTART");
char* mozAppRestart = getenv("MOZ_APP_RESTART");
TimeStamp ts;
/* When calling PR_SetEnv() with an empty value the existing variable may
@@ -12,8 +12,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/TypeTraits.h"
#include "nscore.h"
#include "nsDebug.h"
#include "mozilla/Types.h"
namespace IPC {
template<typename T> struct ParamTraits;
@@ -39,10 +38,10 @@ class TimeStamp;
class BaseTimeDurationPlatformUtils
{
public:
static double ToSeconds(int64_t aTicks);
static double ToSecondsSigDigits(int64_t aTicks);
static int64_t TicksFromMilliseconds(double aMilliseconds);
static int64_t ResolutionInTicks();
static MFBT_API double ToSeconds(int64_t aTicks);
static MFBT_API double ToSecondsSigDigits(int64_t aTicks);
static MFBT_API int64_t TicksFromMilliseconds(double aMilliseconds);
static MFBT_API int64_t ResolutionInTicks();
};
/**
@@ -206,7 +205,6 @@ public:
BaseTimeDuration operator*(const uint64_t aMultiplier) const
{
if (aMultiplier > INT64_MAX) {
NS_WARNING("Out-of-range multiplier when multiplying BaseTimeDuration");
return Forever();
}
return FromTicks(ValueCalculator::Multiply(mValue, aMultiplier));
@@ -428,8 +426,8 @@ public:
* lower precision, usually 15.6 ms, but with very good performance benefit.
* Use it for measurements of longer times, like >200ms timeouts.
*/
static TimeStamp Now() { return Now(true); }
static TimeStamp NowLoRes() { return Now(false); }
static MFBT_API TimeStamp Now() { return Now(true); }
static MFBT_API TimeStamp NowLoRes() { return Now(false); }
/**
* Return a timestamp representing the time when the current process was
@@ -443,14 +441,14 @@ public:
* @returns A timestamp representing the time when the process was created,
* this timestamp is always valid even when errors are reported
*/
static TimeStamp ProcessCreation(bool& aIsInconsistent);
static MFBT_API TimeStamp ProcessCreation(bool& aIsInconsistent);
/**
* Records a process restart. After this call ProcessCreation() will return
* the time when the browser was restarted instead of the actual time when
* the process was created.
*/
static void RecordProcessRestart();
static MFBT_API void RecordProcessRestart();
/**
* Compute the difference between two timestamps. Both must be non-null.
@@ -536,8 +534,8 @@ public:
// two TimeStamps, or scaling TimeStamps, is nonsense and must never
// be allowed.
static nsresult Startup();
static void Shutdown();
static MFBT_API void Startup();
static MFBT_API void Shutdown();
private:
friend struct IPC::ParamTraits<mozilla::TimeStamp>;
@@ -545,7 +543,7 @@ private:
MOZ_IMPLICIT TimeStamp(TimeStampValue aValue) : mValue(aValue) {}
static TimeStamp Now(bool aHighResolution);
static MFBT_API TimeStamp Now(bool aHighResolution);
/**
* Computes the uptime of the current process in microseconds. The result
@@ -555,7 +553,7 @@ private:
* @returns The number of microseconds since the calling process was started
* or 0 if an error was encountered while computing the uptime
*/
static uint64_t ComputeProcessUptime();
static MFBT_API uint64_t ComputeProcessUptime();
/**
* When built with PRIntervalTime, a value of 0 means this instance
@@ -23,7 +23,6 @@
#include <unistd.h>
#include "mozilla/TimeStamp.h"
#include "nsDebug.h"
// Estimate of the smallest duration of time we can measure.
static uint64_t sResolution;
@@ -120,11 +119,11 @@ BaseTimeDurationPlatformUtils::ResolutionInTicks()
return static_cast<int64_t>(sResolution);
}
nsresult
void
TimeStamp::Startup()
{
if (gInitialized) {
return NS_OK;
return;
}
mach_timebase_info_data_t timebaseInfo;
@@ -133,7 +132,7 @@ TimeStamp::Startup()
// to cache the result.
kern_return_t kr = mach_timebase_info(&timebaseInfo);
if (kr != KERN_SUCCESS) {
NS_RUNTIMEABORT("mach_timebase_info failed");
MOZ_RELEASE_ASSERT(false, "mach_timebase_info failed");
}
sNsPerTick = double(timebaseInfo.numer) / timebaseInfo.denom;
@@ -149,7 +148,7 @@ TimeStamp::Startup()
gInitialized = true;
return NS_OK;
return;
}
void
@@ -48,10 +48,7 @@
#include "mozilla/Snprintf.h"
#include "mozilla/TimeStamp.h"
#include "nsCRT.h"
#include "prprf.h"
#include "prthread.h"
#include "nsDebug.h"
#include <pthread.h>
// Estimate of the smallest duration of time we can measure.
static uint64_t sResolution;
@@ -171,16 +168,16 @@ BaseTimeDurationPlatformUtils::ResolutionInTicks()
static bool gInitialized = false;
nsresult
void
TimeStamp::Startup()
{
if (gInitialized) {
return NS_OK;
return;
}
struct timespec dummy;
if (clock_gettime(CLOCK_MONOTONIC, &dummy) != 0) {
NS_RUNTIMEABORT("CLOCK_MONOTONIC is absent!");
MOZ_CRASH("CLOCK_MONOTONIC is absent!");
}
sResolution = ClockResolutionNs();
@@ -194,7 +191,7 @@ TimeStamp::Startup()
gInitialized = true;
return NS_OK;
return;
}
void
@@ -259,7 +256,7 @@ JiffiesSinceBoot(const char* aFile)
// process uptime. This value will be stored at the address pointed by aTime;
// if an error occurred 0 will be stored instead.
static void
static void*
ComputeProcessUptimeThread(void* aTime)
{
uint64_t* uptime = static_cast<uint64_t*>(aTime);
@@ -268,7 +265,7 @@ ComputeProcessUptimeThread(void* aTime)
*uptime = 0;
if (!hz) {
return;
return nullptr;
}
char threadStat[40];
@@ -278,10 +275,11 @@ ComputeProcessUptimeThread(void* aTime)
uint64_t selfJiffies = JiffiesSinceBoot("/proc/self/stat");
if (!threadJiffies || !selfJiffies) {
return;
return nullptr;
}
*uptime = ((threadJiffies - selfJiffies) * kNsPerSec) / hz;
return nullptr;
}
// Computes and returns the process uptime in us on Linux & its derivatives.
@@ -291,15 +289,14 @@ uint64_t
TimeStamp::ComputeProcessUptime()
{
uint64_t uptime = 0;
PRThread* thread = PR_CreateThread(PR_USER_THREAD,
ComputeProcessUptimeThread,
&uptime,
PR_PRIORITY_NORMAL,
PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD,
0);
pthread_t uptime_pthread;
PR_JoinThread(thread);
if (pthread_create(&uptime_pthread, nullptr, ComputeProcessUptimeThread, &uptime)) {
MOZ_CRASH("Failed to create process uptime thread.");
return 0;
}
pthread_join(uptime_pthread, NULL);
return uptime / kNsPerUs;
}
@@ -8,37 +8,31 @@
// values of GetTickCount().
#include "mozilla/MathAlgorithms.h"
#include "mozilla/Mutex.h"
#include "mozilla/TimeStamp.h"
#include "nsWindowsHelpers.h"
#include <windows.h>
#include "nsCRT.h"
#include "mozilla/Logging.h"
#include "prprf.h"
#include <stdio.h>
#include <intrin.h>
#include <windows.h>
// Log module for mozilla::TimeStamp for Windows logging...
//
// To enable logging (see prlog.h for full details):
//
// set NSPR_LOG_MODULES=TimeStampWindows:5
// set NSPR_LOG_FILE=nspr.log
//
// this enables LogLevel::Debug level information and places all output in
// the file nspr.log
static PRLogModuleInfo*
GetTimeStampLog()
// To enable logging define to your favorite logging API
#define LOG(x)
class AutoCriticalSection
{
static PRLogModuleInfo* sLog;
if (!sLog) {
sLog = PR_NewLogModule("TimeStampWindows");
public:
AutoCriticalSection(LPCRITICAL_SECTION aSection)
: mSection(aSection)
{
::EnterCriticalSection(mSection);
}
return sLog;
}
#define LOG(x) MOZ_LOG(GetTimeStampLog(), mozilla::LogLevel::Debug, x)
~AutoCriticalSection()
{
::LeaveCriticalSection(mSection);
}
private:
LPCRITICAL_SECTION mSection;
};
// Estimate of the smallest duration of time we can measure.
static volatile ULONGLONG sResolution;
@@ -293,7 +287,7 @@ InitResolution()
// ----------------------------------------------------------------------------
// TimeStampValue implementation
// ----------------------------------------------------------------------------
MFBT_API
TimeStampValue::TimeStampValue(ULONGLONG aGTC, ULONGLONG aQPC, bool aHasQPC)
: mGTC(aGTC)
, mQPC(aQPC)
@@ -302,7 +296,7 @@ TimeStampValue::TimeStampValue(ULONGLONG aGTC, ULONGLONG aQPC, bool aHasQPC)
{
}
TimeStampValue&
MFBT_API TimeStampValue&
TimeStampValue::operator+=(const int64_t aOther)
{
mGTC += aOther;
@@ -310,7 +304,7 @@ TimeStampValue::operator+=(const int64_t aOther)
return *this;
}
TimeStampValue&
MFBT_API TimeStampValue&
TimeStampValue::operator-=(const int64_t aOther)
{
mGTC -= aOther;
@@ -320,7 +314,7 @@ TimeStampValue::operator-=(const int64_t aOther)
// If the duration is less then two seconds, perform check of QPC stability
// by comparing both GTC and QPC calculated durations of this and aOther.
uint64_t
MFBT_API uint64_t
TimeStampValue::CheckQPC(const TimeStampValue& aOther) const
{
uint64_t deltaGTC = mGTC - aOther.mGTC;
@@ -394,7 +388,7 @@ TimeStampValue::CheckQPC(const TimeStampValue& aOther) const
return deltaGTC;
}
uint64_t
MFBT_API uint64_t
TimeStampValue::operator-(const TimeStampValue& aOther) const
{
if (mIsNull && aOther.mIsNull) {
@@ -408,14 +402,14 @@ TimeStampValue::operator-(const TimeStampValue& aOther) const
// TimeDuration and TimeStamp implementation
// ----------------------------------------------------------------------------
double
MFBT_API double
BaseTimeDurationPlatformUtils::ToSeconds(int64_t aTicks)
{
// Converting before arithmetic avoids blocked store forward
return double(aTicks) / (double(sFrequencyPerSec) * 1000.0);
}
double
MFBT_API double
BaseTimeDurationPlatformUtils::ToSecondsSigDigits(int64_t aTicks)
{
// don't report a value < mResolution ...
@@ -427,7 +421,7 @@ BaseTimeDurationPlatformUtils::ToSecondsSigDigits(int64_t aTicks)
return double(valueSigDigs) / kNsPerSecd;
}
int64_t
MFBT_API int64_t
BaseTimeDurationPlatformUtils::TicksFromMilliseconds(double aMilliseconds)
{
double result = ms2mt(aMilliseconds);
@@ -440,7 +434,7 @@ BaseTimeDurationPlatformUtils::TicksFromMilliseconds(double aMilliseconds)
return result;
}
int64_t
MFBT_API int64_t
BaseTimeDurationPlatformUtils::ResolutionInTicks()
{
return static_cast<int64_t>(sResolution);
@@ -482,7 +476,7 @@ HasStableTSC()
return regs[3] & (1 << 8);
}
nsresult
MFBT_API void
TimeStamp::Startup()
{
// Decide which implementation to use for the high-performance timer.
@@ -508,7 +502,7 @@ TimeStamp::Startup()
InitResolution();
LOG(("TimeStamp: using GetTickCount"));
return NS_OK;
return;
}
sFrequencyPerSec = freq.QuadPart;
@@ -517,16 +511,16 @@ TimeStamp::Startup()
InitThresholds();
InitResolution();
return NS_OK;
return;
}
void
MFBT_API void
TimeStamp::Shutdown()
{
DeleteCriticalSection(&sTimeStampLock);
}
TimeStamp
MFBT_API TimeStamp
TimeStamp::Now(bool aHighResolution)
{
// sUseQPC is volatile
@@ -541,7 +535,7 @@ TimeStamp::Now(bool aHighResolution)
// Computes and returns the process uptime in microseconds.
// Returns 0 if an error was encountered.
uint64_t
MFBT_API uint64_t
TimeStamp::ComputeProcessUptime()
{
SYSTEMTIME nowSys;
@@ -7,6 +7,8 @@
#ifndef mozilla_TimeStamp_windows_h
#define mozilla_TimeStamp_windows_h
#include "mozilla/Types.h"
namespace mozilla {
class TimeStamp;
@@ -23,9 +25,9 @@ class TimeStampValue
bool mHasQPC;
bool mIsNull;
TimeStampValue(uint64_t aGTC, uint64_t aQPC, bool aHasQPC);
MFBT_API TimeStampValue(uint64_t aGTC, uint64_t aQPC, bool aHasQPC);
uint64_t CheckQPC(const TimeStampValue& aOther) const;
MFBT_API uint64_t CheckQPC(const TimeStampValue& aOther) const;
struct _SomethingVeryRandomHere;
MOZ_CONSTEXPR TimeStampValue(_SomethingVeryRandomHere* aNullValue)
@@ -37,7 +39,7 @@ class TimeStampValue
}
public:
uint64_t operator-(const TimeStampValue& aOther) const;
MFBT_API uint64_t operator-(const TimeStampValue& aOther) const;
TimeStampValue operator+(const int64_t aOther) const
{
@@ -47,8 +49,8 @@ public:
{
return TimeStampValue(mGTC - aOther, mQPC - aOther, mHasQPC);
}
TimeStampValue& operator+=(const int64_t aOther);
TimeStampValue& operator-=(const int64_t aOther);
MFBT_API TimeStampValue& operator+=(const int64_t aOther);
MFBT_API TimeStampValue& operator-=(const int64_t aOther);
bool operator<(const TimeStampValue& aOther) const
{
+40
View File
@@ -0,0 +1,40 @@
FINAL_LIBRARY = 'mozglue'
EXPORTS.mozilla += [
'TimeStamp.h',
]
if CONFIG['OS_ARCH'] == 'WINNT':
EXPORTS.mozilla += [
'TimeStamp_windows.h',
]
SOURCES += [
'TimeStamp.cpp',
]
OS_LIBS += CONFIG['REALTIME_LIBS']
# Don't use STL wrappers here (i.e. wrapped <new>); they require mozalloc
DISABLE_STL_WRAPPING = True
DEFINES['MOZ_NO_MOZALLOC'] = True
DEFINES['IMPL_MFBT'] = True
if CONFIG['OS_ARCH'] == 'WINNT':
SOURCES += [
'TimeStamp_windows.cpp',
]
elif CONFIG['HAVE_CLOCK_MONOTONIC']:
SOURCES += [
'TimeStamp_posix.cpp',
]
elif CONFIG['OS_ARCH'] == 'Darwin':
SOURCES += [
'TimeStamp_darwin.cpp',
]
elif CONFIG['COMPILE_ENVIRONMENT']:
error('No TimeStamp implementation on this platform. Build will not succeed')
FAIL_ON_WARNINGS = True
+4 -1
View File
@@ -7,7 +7,10 @@
if CONFIG['MOZ_LINKER']:
DIRS += ['linker']
DIRS += ['build']
DIRS += [
'build',
'misc',
]
if CONFIG['MOZ_CRT']:
DIRS += ['crt']
@@ -48,7 +48,7 @@ function waitForUpdate() {
}
function changeManifestValue(key, value) {
return Task.spawn(function() {
return Task.spawn(function*() {
let propElem = gManifestWindow.document
.querySelector("[id ^= '" + key + "']");
is(propElem.querySelector(".name").value, key,
@@ -74,7 +74,7 @@ function changeManifestValue(key, value) {
}
function changeManifestValueBad(key, value) {
return Task.spawn(function() {
return Task.spawn(function*() {
let propElem = gManifestWindow.document
.querySelector("[id ^= '" + key + "']");
is(propElem.querySelector(".name").value, key,
@@ -102,7 +102,7 @@ function changeManifestValueBad(key, value) {
function addNewManifestProperty(parent, key, value) {
info("Adding new property - parent: " + parent + "; key: " + key + "; value: " + value + "\n\n");
return Task.spawn(function() {
return Task.spawn(function*() {
let parentElem = gManifestWindow.document
.querySelector("[id ^= '" + parent + "']");
ok(parentElem, "Found parent element: " + parentElem.id);
@@ -143,7 +143,7 @@ function addNewManifestProperty(parent, key, value) {
}
function addNewManifestPropertyBad(parent, key, value) {
return Task.spawn(function() {
return Task.spawn(function*() {
let parentElem = gManifestWindow.document
.querySelector("[id ^= '" + parent + "']");
ok(parentElem,
@@ -176,7 +176,7 @@ function addNewManifestPropertyBad(parent, key, value) {
function removeManifestProperty(parent, key) {
info("*** Remove property test ***");
return Task.spawn(function() {
return Task.spawn(function*() {
let parentElem = gManifestWindow.document
.querySelector("[id ^= '" + parent + "']");
ok(parentElem, "Found parent element");
+3 -3
View File
@@ -127,7 +127,7 @@ function waitForProjectsPanel(deferred = promise.defer()) {
}
function selectProjectsPanel() {
return Task.spawn(function() {
return Task.spawn(function*() {
let projectsButton = content.document.querySelector(".projects-button");
EventUtils.sendMouseEvent({ type: "click" }, projectsButton, content);
@@ -144,7 +144,7 @@ function waitForProjectSelection() {
}
function selectFirstProject() {
return Task.spawn(function() {
return Task.spawn(function*() {
let projectsFrame = content.document.querySelector(".projects-panel");
let projectsWindow = projectsFrame.contentWindow;
let projectsDoc = projectsWindow.document;
@@ -156,7 +156,7 @@ function selectFirstProject() {
}
function showSampleProjectDetails() {
return Task.spawn(function() {
return Task.spawn(function*() {
yield selectProjectsPanel();
yield selectFirstProject();
});
@@ -25,7 +25,7 @@ function* spawnTest() {
pbWin.close();
}
function addTabWithToolbarRunTests(win) {
function* addTabWithToolbarRunTests(win) {
let options = yield helpers.openTab(TEST_URI, { chromeWindow: win });
yield helpers.openToolbar(options);
@@ -368,7 +368,9 @@ function TargetEventsHandler() {
}
TargetEventsHandler.prototype = {
get target() NetMonitorController._target,
get target() {
return NetMonitorController._target;
},
/**
* Listen for events emitted by the current tab target.
@@ -448,8 +450,13 @@ function NetworkEventsHandler() {
}
NetworkEventsHandler.prototype = {
get client() NetMonitorController._target.client,
get webConsoleClient() NetMonitorController.webConsoleClient,
get client() {
return NetMonitorController._target.client;
},
get webConsoleClient() {
return NetMonitorController.webConsoleClient;
},
/**
* Connect to the current target client.
@@ -763,7 +770,9 @@ NetMonitorController.NetworkEventsHandler = new NetworkEventsHandler();
*/
Object.defineProperties(window, {
"gNetwork": {
get: function() NetMonitorController.NetworkEventsHandler,
get: function() {
return NetMonitorController.NetworkEventsHandler;
},
configurable: true
}
});
+86 -61
View File
@@ -954,19 +954,21 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
/**
* Returns an object with all the filter predicates as [key: function] pairs.
*/
get _allFilterPredicates() ({
all: () => true,
html: this.isHtml,
css: this.isCss,
js: this.isJs,
xhr: this.isXHR,
fonts: this.isFont,
images: this.isImage,
media: this.isMedia,
flash: this.isFlash,
other: this.isOther,
freetext: this.isFreetextMatch
}),
get _allFilterPredicates() {
return {
all: () => true,
html: this.isHtml,
css: this.isCss,
js: this.isJs,
xhr: this.isXHR,
fonts: this.isFont,
images: this.isImage,
media: this.isMedia,
flash: this.isFlash,
other: this.isOther,
freetext: this.isFreetextMatch
};
},
/**
* Sorts all network requests in this container by a specified detail.
@@ -1080,52 +1082,72 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
* @return boolean
* True if the item should be visible, false otherwise.
*/
isHtml: function({ attachment: { mimeType } })
mimeType && mimeType.includes("/html"),
isHtml: function({ attachment: { mimeType } }) {
return mimeType && mimeType.includes("/html");
},
isCss: function({ attachment: { mimeType } })
mimeType && mimeType.includes("/css"),
isCss: function({ attachment: { mimeType } }) {
return mimeType && mimeType.includes("/css");
},
isJs: function({ attachment: { mimeType } })
mimeType && (
isJs: function({ attachment: { mimeType } }) {
return mimeType && (
mimeType.includes("/ecmascript") ||
mimeType.includes("/javascript") ||
mimeType.includes("/x-javascript")),
mimeType.includes("/x-javascript"));
},
isXHR: function({ attachment: { isXHR } })
isXHR,
isXHR: function({ attachment: { isXHR } }) {
return isXHR;
},
isFont: function({ attachment: { url, mimeType } }) // Fonts are a mess.
(mimeType && (
mimeType.includes("font/") ||
mimeType.includes("/font"))) ||
url.includes(".eot") ||
url.includes(".ttf") ||
url.includes(".otf") ||
url.includes(".woff"),
isFont: function({ attachment: { url, mimeType } }) {
// Fonts are a mess.
return (mimeType && (
mimeType.includes("font/") ||
mimeType.includes("/font"))) ||
url.includes(".eot") ||
url.includes(".ttf") ||
url.includes(".otf") ||
url.includes(".woff");
},
isImage: function({ attachment: { mimeType } })
mimeType && mimeType.includes("image/"),
isImage: function({ attachment: { mimeType } }) {
return mimeType && mimeType.includes("image/");
},
isMedia: function({ attachment: { mimeType } }) // Not including images.
mimeType && (
isMedia: function({ attachment: { mimeType } }) {
// Not including images.
return mimeType && (
mimeType.includes("audio/") ||
mimeType.includes("video/") ||
mimeType.includes("model/")),
mimeType.includes("model/"));
},
isFlash: function({ attachment: { url, mimeType } }) // Flash is a mess.
(mimeType && (
mimeType.includes("/x-flv") ||
mimeType.includes("/x-shockwave-flash"))) ||
url.includes(".swf") ||
url.includes(".flv"),
isFlash: function({ attachment: { url, mimeType } }) {
// Flash is a mess.
return (mimeType && (
mimeType.includes("/x-flv") ||
mimeType.includes("/x-shockwave-flash"))) ||
url.includes(".swf") ||
url.includes(".flv");
},
isOther: function(e)
!this.isHtml(e) && !this.isCss(e) && !this.isJs(e) && !this.isXHR(e) &&
!this.isFont(e) && !this.isImage(e) && !this.isMedia(e) && !this.isFlash(e),
isOther: function(e) {
return !this.isHtml(e) &&
!this.isCss(e) &&
!this.isJs(e) &&
!this.isXHR(e) &&
!this.isFont(e) &&
!this.isImage(e) &&
!this.isMedia(e) &&
!this.isFlash(e);
},
isFreetextMatch: function({ attachment: { url } }, text) //no text is a positive match
!text || url.includes(text),
isFreetextMatch: function({ attachment: { url } }, text) {
//no text is a positive match
return !text || url.includes(text);
},
/**
* Predicates used when sorting items.
@@ -1139,18 +1161,21 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
* 0 to leave aFirst and aSecond unchanged with respect to each other
* 1 to sort aSecond to a lower index than aFirst
*/
_byTiming: function({ attachment: first }, { attachment: second })
first.startedMillis > second.startedMillis,
_byTiming: function({ attachment: first }, { attachment: second }) {
return first.startedMillis > second.startedMillis;
},
_byStatus: function({ attachment: first }, { attachment: second })
first.status == second.status
? first.startedMillis > second.startedMillis
: first.status > second.status,
_byStatus: function({ attachment: first }, { attachment: second }) {
return first.status == second.status
? first.startedMillis > second.startedMillis
: first.status > second.status;
},
_byMethod: function({ attachment: first }, { attachment: second })
first.method == second.method
? first.startedMillis > second.startedMillis
: first.method > second.method,
_byMethod: function({ attachment: first }, { attachment: second }) {
return first.method == second.method
? first.startedMillis > second.startedMillis
: first.method > second.method;
},
_byFile: function({ attachment: first }, { attachment: second }) {
let firstUrl = this._getUriNameWithQuery(first.url).toLowerCase();
@@ -3300,8 +3325,8 @@ PerformanceStatisticsView.prototype = {
/**
* DOM query helper.
*/
function $(aSelector, aTarget = document) aTarget.querySelector(aSelector);
function $all(aSelector, aTarget = document) aTarget.querySelectorAll(aSelector);
let $ = (aSelector, aTarget = document) => aTarget.querySelector(aSelector);
let $all = (aSelector, aTarget = document) => aTarget.querySelectorAll(aSelector);
/**
* Helper for getting an nsIURL instance out of a string.
@@ -3396,7 +3421,7 @@ function parseRequestText(aText, aName, aDivider) {
* List of headers in text format
*/
function writeHeaderText(aHeaders) {
return [(name + ": " + value) for ({name, value} of aHeaders)].join("\n");
return aHeaders.map(({name, value}) => name + ": " + value).join("\n");
}
/**
@@ -3408,7 +3433,7 @@ function writeHeaderText(aHeaders) {
* List of query params in text format
*/
function writeQueryText(aParams) {
return [(name + "=" + value) for ({name, value} of aParams)].join("\n");
return aParams.map(({name, value}) => name + "=" + value).join("\n");
}
/**
@@ -3420,7 +3445,7 @@ function writeQueryText(aParams) {
* Query string that can be appended to a url.
*/
function writeQueryString(aParams) {
return [(name + "=" + value) for ({name, value} of aParams)].join("&");
return aParams.map(({name, value}) => name + "=" + value).join("&");
}
/**
+3 -1
View File
@@ -56,7 +56,9 @@ NetMonitorPanel.prototype = {
// DevToolPanel API
get target() this._toolbox.target,
get target() {
return this._toolbox.target;
},
destroy: function() {
// Make sure this panel is not already destroyed.
@@ -17,7 +17,7 @@ function test() {
NetworkDetails._params.lazyEmpty = false;
Task.spawn(function*() {
yield waitForNetworkEvents(aMonitor, 0, 6);
yield waitForNetworkEvents(aMonitor, 1, 6);
EventUtils.sendMouseEvent({ type: "mousedown" },
document.getElementById("details-pane-toggle"));
@@ -47,6 +47,10 @@ function test() {
yield waitFor(aMonitor.panelWin, EVENTS.REQUEST_POST_PARAMS_DISPLAYED);
yield testParamsTab2('a', '"b"', '?foo=bar', "text");
RequestsMenu.selectedIndex = 6;
yield waitFor(aMonitor.panelWin, EVENTS.SIDEBAR_POPULATED);
yield testParamsTab3('a', '"b"');
yield teardown(aMonitor);
finish();
});
@@ -141,6 +145,25 @@ function test() {
});
}
function testParamsTab3(aQueryStringParamName, aQueryStringParamValue) {
let tab = document.querySelectorAll("#details-pane tab")[2];
let tabpanel = document.querySelectorAll("#details-pane tabpanel")[2];
is(tabpanel.querySelectorAll(".variables-view-scope").length, 0,
"The number of param scopes displayed in this tabpanel is incorrect.");
is(tabpanel.querySelectorAll(".variable-or-property").length, 0,
"The number of param values displayed in this tabpanel is incorrect.");
is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 1,
"The empty notice should be displayed in this tabpanel.");
is(tabpanel.querySelector("#request-params-box")
.hasAttribute("hidden"), false,
"The request params box should not be hidden.");
is(tabpanel.querySelector("#request-post-data-textarea-box")
.hasAttribute("hidden"), true,
"The request post data textarea box should be hidden.");
}
aDebuggee.performRequests();
});
}
@@ -14,7 +14,7 @@ function test() {
let TAB_UPDATED = aMonitor.panelWin.EVENTS.TAB_UPDATED;
RequestsMenu.lazyUpdate = false;
Task.spawn(function () {
Task.spawn(function*() {
yield waitForNetworkEvents(aMonitor, 1);
is(RequestsMenu.selectedItem, null,
"There shouldn't be any selected item in the requests menu.");
@@ -174,7 +174,7 @@ function test() {
EventUtils.sendMouseEvent({ type: "mousedown" },
document.querySelectorAll("#details-pane tab")[3]);
return Task.spawn(function () {
return Task.spawn(function*() {
yield waitFor(aMonitor.panelWin, TAB_UPDATED);
let tab = document.querySelectorAll("#details-pane tab")[3];
+1 -1
View File
@@ -404,7 +404,7 @@ function testFilterButtons(aMonitor, aFilterType) {
let buttons = doc.querySelectorAll(".requests-menu-footer-button");
// Only target should be checked.
let checkStatus = [(button == target) ? 1 : 0 for (button of buttons)]
let checkStatus = [...buttons].map(button => button == target ? 1 : 0);
testFilterButtonsCustom(aMonitor, checkStatus);
}
@@ -15,6 +15,12 @@
<p>Request params type test</p>
<script type="text/javascript">
function get(aAddress, aQuery) {
var xhr = new XMLHttpRequest();
xhr.open("GET", aAddress + aQuery, true);
xhr.send();
}
function post(aAddress, aQuery, aContentType, aPostBody) {
var xhr = new XMLHttpRequest();
xhr.open("POST", aAddress + aQuery, true);
@@ -43,7 +49,11 @@
setTimeout(function() {
post("baz", "?a=b", undefined, '?foo=bar');
// Done.
setTimeout(function() {
get("baz", "");
// Done.
}, 10);
}, 10);
}, 10);
}, 10);
@@ -0,0 +1,146 @@
# Timeline Markers
## Common
* DOMHighResTimeStamp start
* DOMHighResTimeStamp end
* DOMString name
* object? stack
* object? endStack
## DOMEvent
Triggered when a DOM event occurs, like a click or a keypress.
* unsigned short eventPhase - a number indicating what phase this event is
in (target, bubbling, capturing, maps to Ci.nsIDOMEvent constants)
* DOMString type - the type of event, like "keypress" or "click"
## Reflow
Reflow markers (labeled as "Layout") indicate when a change has occurred to
a DOM element's positioning that requires the frame tree (rendering
representation of the DOM) to figure out the new position of a handful of
elements. Fired via `PresShell::DoReflow`
## Paint
* sequence<{ long height, long width, long x, long y }> rectangles - An array
of rectangle objects indicating where painting has occurred.
## Styles
Style markers (labeled as "Recalculating Styles") are triggered when Gecko
needs to figure out the computational style of an element. Fired via
`RestyleTracker::DoProcessRestyles` when there are elements to restyle.
* DOMString restyleHint - A string indicating what kind of restyling will need
to be processed; for example "eRestyle_StyleAttribute" is relatively cheap,
whereas "eRestyle_Subtree" is more expensive. The hint can be a string of
any amount of the following, separated via " | ". All future restyleHints
are from `RestyleManager::RestyleHintToString`.
* "eRestyle_Self"
* "eRestyle_Subtree"
* "eRestyle_LaterSiblings"
* "eRestyle_CSSTransitions"
* "eRestyle_CSSAnimations"
* "eRestyle_SVGAttrAnimations"
* "eRestyle_StyleAttribute"
* "eRestyle_StyleAttribute_Animations"
* "eRestyle_Force"
* "eRestyle_ForceDescendants"
## Javascript
`Javascript` markers are emitted indicating when JS execution begins and ends,
with a reason that triggered it (causeName), like a requestAnimationFrame or
a setTimeout.
* string causeName - The reason that JS was entered. There are many possible
reasons, and the interesting ones to show web developers (triggered by content) are:
* "\<script\> element"
* "EventListener.handleEvent"
* "setInterval handler"
* "setTimeout handler"
* "FrameRequestCallback"
* "EventHandlerNonNull"
* "promise callback"
* "promise initializer"
* "Worker runnable"
There are also many more potential JS causes, some which are just internally
used and won't emit a marker, but the below ones are only of interest to
Gecko hackers, most likely
* "promise thenable"
* "worker runnable"
* "nsHTTPIndex set HTTPIndex property"
* "XPCWrappedJS method call"
* "nsHTTPIndex OnFTPControlLog"
* "XPCWrappedJS QueryInterface"
* "xpcshell argument processing”
* "XPConnect sandbox evaluation "
* "component loader report global"
* "component loader load module"
* "Cross-Process Object Wrapper call/construct"
* "Cross-Process Object Wrapper set'"
* "Cross-Process Object Wrapper 'get'"
* "nsXULTemplateBuilder creation"
* "TestShellCommand"
* "precompiled XUL \<script\> element"
* "XBL \<field\> initialization "
* "NPAPI NPN_evaluate"
* "NPAPI get"
* "NPAPI set"
* "NPAPI doInvoke"
* "javascript: URI"
* "geolocation.always_precise indexing"
* "geolocation.app_settings enumeration"
* "WebIDL dictionary creation"
* "XBL \<constructor\>/\<destructor\> invocation"
* "message manager script load"
* "message handler script load"
* "nsGlobalWindow report new global"
## GarbageCollection
Emitted after a full GC cycle has completed (which is after any number of
incremental slices).
* DOMString causeName - The reason for a GC event to occur. A full list of
GC reasons can be found [on MDN](https://developer.mozilla.org/en-US/docs/Tools/Debugger-API/Debugger.Memory#Debugger.Memory_Handler_Functions).
* DOMString nonincremenetalReason - If the GC could not do an incremental
GC (smaller, quick GC events), and we have to walk the entire heap and
GC everything marked, then the reason listed here is why.
## nsCycleCollector::Collect
An `nsCycleCollector::Collect` marker is emitted for each incremental cycle
collection slice and each non-incremental cycle collection.
# nsCycleCollector::ForgetSkippable
`nsCycleCollector::ForgetSkippable` is presented as "Cycle Collection", but in
reality it is preparation/pre-optimization for cycle collection, and not the
actual tracing of edges and collecting of cycles.
## ConsoleTime
A marker generated via `console.time()` and `console.timeEnd()`.
* DOMString causeName - the label passed into `console.time(label)` and
`console.timeEnd(label)` if passed in.
## TimeStamp
A marker generated via `console.timeStamp(label)`.
* DOMString causeName - the label passed into `console.timeStamp(label)`
if passed in.
## Parse HTML
## Parse XML
@@ -3,12 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { Cc, Ci, Cu, Cr } = require("chrome");
const { ViewHelpers } = require("resource:///modules/devtools/ViewHelpers.jsm");
// String used to fill in platform data when it should be hidden.
const GECKO_SYMBOL = "(Gecko)";
/**
* Localization convenience methods.
+ TODO: merge these into a single file: Bug 1082695.
@@ -87,307 +83,6 @@ const CATEGORY_MAPPINGS = {
"4096": CATEGORIES[7], // js::ProfileEntry::Category::EVENTS
};
/**
* A simple schema for mapping markers to the timeline UI. The keys correspond
* to marker names, while the values are objects with the following format:
*
* - group: The row index in the timeline overview graph; multiple markers
* can be added on the same row. @see <overview.js/buildGraphImage>
* - label: The label used in the waterfall to identify the marker. Can be a
* string or just a function that accepts the marker and returns a
* string, if you want to use a dynamic property for the main label.
* If you use a function for a label, it *must* handle the case where
* no marker is provided for a main label to describe all markers of
* this type.
* - colorName: The label of the DevTools color used for this marker. If
* adding a new color, be sure to check that there's an entry
* for `.marker-details-bullet.{COLORNAME}` for the equivilent
* entry in ./browser/themes/shared/devtools/performance.inc.css
* https://developer.mozilla.org/en-US/docs/Tools/DevToolsColors
* - collapseFunc: A function determining how markers are collapsed together.
* Invoked with 3 arguments: the current parent marker, the
* current marker and a method for peeking i markers ahead. If
* nothing is returned, the marker is added as a standalone entry
* in the waterfall. Otherwise, an object needs to be returned
* with the following properties:
* - toParent: The parent marker name (needs to be an entry in
* the `TIMELINE_BLUEPRINT` itself).
* - withData: An object containing some properties to staple
* on the parent marker.
* - forceNew: True if a new parent marker needs to be created
* even though there is one currently available
* with the same name.
* - forceEnd: True if the current parent marker is full after
* this collapse operation and should be finalized.
* - fields: An optional array of marker properties you wish to display in the
* marker details view. For example, a field in the array such as
* { property: "aCauseName", label: "Cause" } would render a string
* like `Cause: ${marker.aCauseName}` in the marker details view.
* Each `field` item may take the following properties:
* - property: The property that must exist on the marker to render,
* and the value of the property will be displayed.
* - label: The name of the property that should be displayed.
* - formatter: If a formatter is provided, instead of directly using
* the `property` property on the marker, the marker is
* passed into the formatter function to determine the
* displayed value.
* Can also be a function that returns an object. Each key in the object
* will be rendered as a field, with its value rendering as the value.
*
* Whenever this is changed, browser_timeline_waterfall-styles.js *must* be
* updated as well.
*/
const TIMELINE_BLUEPRINT = {
/* Group 0 - Reflow and Rendering pipeline */
"Styles": {
group: 0,
colorName: "graphs-purple",
collapseFunc: collapseConsecutiveIdentical,
label: L10N.getStr("timeline.label.styles2"),
fields: getStylesFields,
},
"Reflow": {
group: 0,
colorName: "graphs-purple",
collapseFunc: collapseConsecutiveIdentical,
label: L10N.getStr("timeline.label.reflow2"),
},
"Paint": {
group: 0,
colorName: "graphs-green",
collapseFunc: collapseConsecutiveIdentical,
label: L10N.getStr("timeline.label.paint"),
},
/* Group 1 - JS */
"DOMEvent": {
group: 1,
colorName: "graphs-yellow",
collapseFunc: collapseDOMIntoDOMJS,
label: L10N.getStr("timeline.label.domevent"),
fields: getDOMEventFields,
},
"Javascript": {
group: 1,
colorName: "graphs-yellow",
collapseFunc: either(collapseJSIntoDOMJS, collapseConsecutiveIdentical),
label: getJSLabel,
fields: getJSFields,
},
"meta::DOMEvent+JS": {
colorName: "graphs-yellow",
label: getDOMJSLabel,
fields: getDOMEventFields,
},
"Parse HTML": {
group: 1,
colorName: "graphs-yellow",
collapseFunc: collapseConsecutiveIdentical,
label: L10N.getStr("timeline.label.parseHTML"),
},
"Parse XML": {
group: 1,
colorName: "graphs-yellow",
collapseFunc: collapseConsecutiveIdentical,
label: L10N.getStr("timeline.label.parseXML"),
},
"GarbageCollection": {
group: 1,
colorName: "graphs-red",
collapseFunc: collapseAdjacentGC,
label: getGCLabel,
fields: [
{ property: "causeName", label: "Reason:" },
{ property: "nonincrementalReason", label: "Non-incremental Reason:" }
],
},
/* Group 2 - User Controlled */
"ConsoleTime": {
group: 2,
colorName: "graphs-grey",
label: sublabelForProperty(L10N.getStr("timeline.label.consoleTime"), "causeName"),
fields: [{
property: "causeName",
label: L10N.getStr("timeline.markerDetail.consoleTimerName")
}],
},
"TimeStamp": {
group: 2,
colorName: "graphs-blue",
label: sublabelForProperty(L10N.getStr("timeline.label.timestamp"), "causeName"),
fields: [{
property: "causeName",
label: "Label:"
}],
},
};
/**
* Helper for creating a function that returns the first defined result from
* a list of functions passed in as params, in order.
* @param ...function fun
* @return any
*/
function either(...fun) {
return function() {
for (let f of fun) {
let result = f.apply(null, arguments);
if (result !== undefined) return result;
}
}
}
/**
* A series of collapsers used by the blueprint. These functions are
* consecutively invoked on a moving window of two markers.
*/
function collapseConsecutiveIdentical(parent, curr, peek) {
// If there is a parent marker currently being filled and the current marker
// should go into the parent marker, make it so.
if (parent && parent.name == curr.name) {
return { toParent: parent.name };
}
// Otherwise if the current marker is the same type as the next marker type,
// create a new parent marker containing the current marker.
let next = peek(1);
if (next && curr.name == next.name) {
return { toParent: curr.name };
}
}
function collapseAdjacentGC(parent, curr, peek) {
let next = peek(1);
if (next && (next.start < curr.end || next.start - curr.end <= 10 /* ms */)) {
return collapseConsecutiveIdentical(parent, curr, peek);
}
}
function collapseDOMIntoDOMJS(parent, curr, peek) {
// If the next marker is a JavaScript marker, create a new meta parent marker
// containing the current marker.
let next = peek(1);
if (next && next.name == "Javascript") {
return {
forceNew: true,
toParent: "meta::DOMEvent+JS",
withData: {
type: curr.type,
eventPhase: curr.eventPhase
},
};
}
}
function collapseJSIntoDOMJS(parent, curr, peek) {
// If there is a parent marker currently being filled, and it's the one
// created from a `DOMEvent` via `collapseDOMIntoDOMJS`, then the current
// marker has to go into that one.
if (parent && parent.name == "meta::DOMEvent+JS") {
return {
forceEnd: true,
toParent: "meta::DOMEvent+JS",
withData: {
stack: curr.stack,
endStack: curr.endStack
},
};
}
}
/**
* A series of formatters used by the blueprint.
*/
function getGCLabel (marker={}) {
let label = L10N.getStr("timeline.label.garbageCollection");
// Only if a `nonincrementalReason` exists, do we want to label
// this as a non incremental GC event.
if ("nonincrementalReason" in marker) {
label = `${label} (Non-incremental)`;
}
return label;
}
/**
* Mapping of JS marker causes to a friendlier form. Only
* markers that are considered "from content" should be labeled here.
*/
const JS_MARKER_MAP = {
"<script> element": "Script Tag",
"setInterval handler": "setInterval",
"setTimeout handler": "setTimeout",
"FrameRequestCallback": "requestAnimationFrame",
"promise callback": "Promise Callback",
"promise initializer": "Promise Init",
"Worker runnable": "Worker",
"javascript: URI": "JavaScript URI",
// The difference between these two event handler markers are differences
// in their WebIDL implementation, so distinguishing them is not necessary.
"EventHandlerNonNull": "Event Handler",
"EventListener.handleEvent": "Event Handler",
};
function getJSLabel (marker={}) {
let generic = L10N.getStr("timeline.label.javascript2");
if ("causeName" in marker) {
return JS_MARKER_MAP[marker.causeName] || generic;
}
return generic;
}
function getDOMJSLabel (marker={}) {
return `Event (${marker.type})`;
}
/**
* Returns a hash for computing a fields object for a JS marker. If the cause
* is considered content (so an entry exists in the JS_MARKER_MAP), do not display it
* since it's redundant with the label. Otherwise for Gecko code, either display
* the cause, or "(Gecko)", depending on if "show-platform-data" is set.
*/
function getJSFields (marker) {
if ("causeName" in marker && !JS_MARKER_MAP[marker.causeName]) {
return { Reason: PREFS["show-platform-data"] ? marker.causeName : GECKO_SYMBOL };
}
}
function getDOMEventFields (marker) {
let fields = Object.create(null);
if ("type" in marker) {
fields[L10N.getStr("timeline.markerDetail.DOMEventType")] = marker.type;
}
if ("eventPhase" in marker) {
let phase;
if (marker.eventPhase === Ci.nsIDOMEvent.AT_TARGET) {
phase = L10N.getStr("timeline.markerDetail.DOMEventTargetPhase");
} else if (marker.eventPhase === Ci.nsIDOMEvent.CAPTURING_PHASE) {
phase = L10N.getStr("timeline.markerDetail.DOMEventCapturingPhase");
} else if (marker.eventPhase === Ci.nsIDOMEvent.BUBBLING_PHASE) {
phase = L10N.getStr("timeline.markerDetail.DOMEventBubblingPhase");
}
fields[L10N.getStr("timeline.markerDetail.DOMEventPhase")] = phase;
}
return fields;
}
function getStylesFields (marker) {
if ("restyleHint" in marker) {
return { "Restyle Hint": marker.restyleHint.replace(/eRestyle_/g, "") };
}
}
/**
* Takes a main label (like "Timestamp") and a property,
* and returns a marker that will print out the property
* value for a marker if it exists ("Timestamp (rendering)"),
* or just the main label if it does not.
*/
function sublabelForProperty (mainLabel, prop) {
return (marker={}) => marker[prop] ? `${mainLabel} (${marker[prop]})` : mainLabel;
}
/**
* Get the numeric bitmask (or set of masks) for the given category
* abbreviation. See CATEGORIES and CATEGORY_MAPPINGS above.
@@ -449,7 +144,6 @@ const CATEGORY_JIT = CATEGORY_MASK('js');
// Exported symbols.
exports.L10N = L10N;
exports.PREFS = PREFS;
exports.TIMELINE_BLUEPRINT = TIMELINE_BLUEPRINT;
exports.CATEGORIES = CATEGORIES;
exports.CATEGORY_MAPPINGS = CATEGORY_MAPPINGS;
exports.CATEGORY_MASK = CATEGORY_MASK;
@@ -8,13 +8,20 @@
* and parsing out the blueprint to generate correct values for markers.
*/
const { Ci } = require("chrome");
loader.lazyRequireGetter(this, "L10N",
"devtools/performance/global", true);
loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
loader.lazyRequireGetter(this, "PREFS",
"devtools/performance/global", true);
loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
"devtools/performance/markers", true);
loader.lazyRequireGetter(this, "WebConsoleUtils",
"devtools/toolkit/webconsole/utils");
// String used to fill in platform data when it should be hidden.
const GECKO_SYMBOL = "(Gecko)";
/**
* Returns the correct label to display for passed in marker, based
* off of the blueprints.
@@ -270,7 +277,159 @@ const DOM = {
}
};
/**
* A series of collapsers used by the blueprint. These functions are
* invoked on a moving window of two markers.
*/
const CollapseFunctions = {
identical: function (parent, curr, peek) {
// If there is a parent marker currently being filled and the current marker
// should go into the parent marker, make it so.
if (parent && parent.name == curr.name) {
return { toParent: parent.name };
}
// Otherwise if the current marker is the same type as the next marker type,
// create a new parent marker containing the current marker.
let next = peek(1);
if (next && curr.name == next.name) {
return { toParent: curr.name };
}
},
adjacent: function (parent, curr, peek) {
let next = peek(1);
if (next && (next.start < curr.end || next.start - curr.end <= 10 /* ms */)) {
return CollapseFunctions.identical(parent, curr, peek);
}
},
DOMtoDOMJS: function (parent, curr, peek) {
// If the next marker is a JavaScript marker, create a new meta parent marker
// containing the current marker.
let next = peek(1);
if (next && next.name == "Javascript") {
return {
forceNew: true,
toParent: "meta::DOMEvent+JS",
withData: {
type: curr.type,
eventPhase: curr.eventPhase
},
};
}
},
JStoDOMJS: function (parent, curr, peek) {
// If there is a parent marker currently being filled, and it's the one
// created from a `DOMEvent` via `collapseDOMIntoDOMJS`, then the current
// marker has to go into that one.
if (parent && parent.name == "meta::DOMEvent+JS") {
return {
forceEnd: true,
toParent: "meta::DOMEvent+JS",
withData: {
stack: curr.stack,
endStack: curr.endStack
},
};
}
},
};
/**
* Mapping of JS marker causes to a friendlier form. Only
* markers that are considered "from content" should be labeled here.
*/
const JS_MARKER_MAP = {
"<script> element": "Script Tag",
"setInterval handler": "setInterval",
"setTimeout handler": "setTimeout",
"FrameRequestCallback": "requestAnimationFrame",
"promise callback": "Promise Callback",
"promise initializer": "Promise Init",
"Worker runnable": "Worker",
"javascript: URI": "JavaScript URI",
// The difference between these two event handler markers are differences
// in their WebIDL implementation, so distinguishing them is not necessary.
"EventHandlerNonNull": "Event Handler",
"EventListener.handleEvent": "Event Handler",
};
/**
* A series of formatters used by the blueprint.
*/
const Formatters = {
GCLabel: function (marker={}) {
let label = L10N.getStr("timeline.label.garbageCollection");
// Only if a `nonincrementalReason` exists, do we want to label
// this as a non incremental GC event.
if ("nonincrementalReason" in marker) {
label = `${label} (Non-incremental)`;
}
return label;
},
JSLabel: function (marker={}) {
let generic = L10N.getStr("timeline.label.javascript2");
if ("causeName" in marker) {
return JS_MARKER_MAP[marker.causeName] || generic;
}
return generic;
},
DOMJSLabel: function (marker={}) {
return `Event (${marker.type})`;
},
/**
* Returns a hash for computing a fields object for a JS marker. If the cause
* is considered content (so an entry exists in the JS_MARKER_MAP), do not display it
* since it's redundant with the label. Otherwise for Gecko code, either display
* the cause, or "(Gecko)", depending on if "show-platform-data" is set.
*/
JSFields: function (marker) {
if ("causeName" in marker && !JS_MARKER_MAP[marker.causeName]) {
return { Reason: PREFS["show-platform-data"] ? marker.causeName : GECKO_SYMBOL };
}
},
DOMEventFields: function (marker) {
let fields = Object.create(null);
if ("type" in marker) {
fields[L10N.getStr("timeline.markerDetail.DOMEventType")] = marker.type;
}
if ("eventPhase" in marker) {
let phase;
if (marker.eventPhase === Ci.nsIDOMEvent.AT_TARGET) {
phase = L10N.getStr("timeline.markerDetail.DOMEventTargetPhase");
} else if (marker.eventPhase === Ci.nsIDOMEvent.CAPTURING_PHASE) {
phase = L10N.getStr("timeline.markerDetail.DOMEventCapturingPhase");
} else if (marker.eventPhase === Ci.nsIDOMEvent.BUBBLING_PHASE) {
phase = L10N.getStr("timeline.markerDetail.DOMEventBubblingPhase");
}
fields[L10N.getStr("timeline.markerDetail.DOMEventPhase")] = phase;
}
return fields;
},
StylesFields: function (marker) {
if ("restyleHint" in marker) {
return { "Restyle Hint": marker.restyleHint.replace(/eRestyle_/g, "") };
}
},
CycleCollectionFields: function (marker) {
let Type = PREFS["show-platform-data"]
? marker.name
: marker.name.replace(/nsCycleCollector::/g, "");
return { Type };
},
};
exports.getMarkerLabel = getMarkerLabel;
exports.getMarkerClassName = getMarkerClassName;
exports.getMarkerFields = getMarkerFields;
exports.DOM = DOM;
exports.CollapseFunctions = CollapseFunctions;
exports.Formatters = Formatters;
@@ -8,7 +8,7 @@
*/
loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
"devtools/performance/global", true);
"devtools/performance/markers", true);
/**
* Collapses markers into a tree-like structure. Currently, this only goes
@@ -0,0 +1,185 @@
/* 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/. */
"use strict";
const { L10N } = require("devtools/performance/global");
const { Formatters, CollapseFunctions } = require("devtools/performance/marker-utils");
/**
* A simple schema for mapping markers to the timeline UI. The keys correspond
* to marker names, while the values are objects with the following format:
*
* - group: The row index in the timeline overview graph; multiple markers
* can be added on the same row. @see <overview.js/buildGraphImage>
* - label: The label used in the waterfall to identify the marker. Can be a
* string or just a function that accepts the marker and returns a
* string, if you want to use a dynamic property for the main label.
* If you use a function for a label, it *must* handle the case where
* no marker is provided for a main label to describe all markers of
* this type.
* - colorName: The label of the DevTools color used for this marker. If
* adding a new color, be sure to check that there's an entry
* for `.marker-details-bullet.{COLORNAME}` for the equivilent
* entry in ./browser/themes/shared/devtools/performance.inc.css
* https://developer.mozilla.org/en-US/docs/Tools/DevToolsColors
* - collapseFunc: A function determining how markers are collapsed together.
* Invoked with 3 arguments: the current parent marker, the
* current marker and a method for peeking i markers ahead. If
* nothing is returned, the marker is added as a standalone entry
* in the waterfall. Otherwise, an object needs to be returned
* with the following properties:
* - toParent: The parent marker name (needs to be an entry in
* the `TIMELINE_BLUEPRINT` itself).
* - withData: An object containing some properties to staple
* on the parent marker.
* - forceNew: True if a new parent marker needs to be created
* even though there is one currently available
* with the same name.
* - forceEnd: True if the current parent marker is full after
* this collapse operation and should be finalized.
* - fields: An optional array of marker properties you wish to display in the
* marker details view. For example, a field in the array such as
* { property: "aCauseName", label: "Cause" } would render a string
* like `Cause: ${marker.aCauseName}` in the marker details view.
* Each `field` item may take the following properties:
* - property: The property that must exist on the marker to render,
* and the value of the property will be displayed.
* - label: The name of the property that should be displayed.
* - formatter: If a formatter is provided, instead of directly using
* the `property` property on the marker, the marker is
* passed into the formatter function to determine the
* displayed value.
* Can also be a function that returns an object. Each key in the object
* will be rendered as a field, with its value rendering as the value.
*
* Whenever this is changed, browser_timeline_waterfall-styles.js *must* be
* updated as well.
*/
const TIMELINE_BLUEPRINT = {
/* Group 0 - Reflow and Rendering pipeline */
"Styles": {
group: 0,
colorName: "graphs-purple",
collapseFunc: CollapseFunctions.identical,
label: L10N.getStr("timeline.label.styles2"),
fields: Formatters.StylesFields,
},
"Reflow": {
group: 0,
colorName: "graphs-purple",
collapseFunc: CollapseFunctions.identical,
label: L10N.getStr("timeline.label.reflow2"),
},
"Paint": {
group: 0,
colorName: "graphs-green",
collapseFunc: CollapseFunctions.identical,
label: L10N.getStr("timeline.label.paint"),
},
/* Group 1 - JS */
"DOMEvent": {
group: 1,
colorName: "graphs-yellow",
collapseFunc: CollapseFunctions.DOMtoDOMJS,
label: L10N.getStr("timeline.label.domevent"),
fields: Formatters.DOMEventFields,
},
"Javascript": {
group: 1,
colorName: "graphs-yellow",
collapseFunc: either(CollapseFunctions.JStoDOMJS, CollapseFunctions.identical),
label: Formatters.JSLabel,
fields: Formatters.JSFields
},
"meta::DOMEvent+JS": {
colorName: "graphs-yellow",
label: Formatters.DOMJSLabel,
fields: Formatters.DOMJSFields,
},
"Parse HTML": {
group: 1,
colorName: "graphs-yellow",
collapseFunc: CollapseFunctions.identical,
label: L10N.getStr("timeline.label.parseHTML"),
},
"Parse XML": {
group: 1,
colorName: "graphs-yellow",
collapseFunc: CollapseFunctions.identical,
label: L10N.getStr("timeline.label.parseXML"),
},
"GarbageCollection": {
group: 1,
colorName: "graphs-red",
collapseFunc: CollapseFunctions.adjacent,
label: Formatters.GCLabel,
fields: [
{ property: "causeName", label: "Reason:" },
{ property: "nonincrementalReason", label: "Non-incremental Reason:" }
],
},
"nsCycleCollector::Collect": {
group: 1,
colorName: "graphs-red",
collapseFunc: either(collapse.parent, collapse.child),
label: "Cycle Collection",
fields: Formatters.CycleCollectionFields,
},
"nsCycleCollector::ForgetSkippable": {
group: 1,
colorName: "graphs-red",
collapseFunc: either(collapse.parent, collapse.child),
label: "Cycle Collection",
fields: Formatters.CycleCollectionFields,
},
/* Group 2 - User Controlled */
"ConsoleTime": {
group: 2,
colorName: "graphs-grey",
label: sublabelForProperty(L10N.getStr("timeline.label.consoleTime"), "causeName"),
fields: [{
property: "causeName",
label: L10N.getStr("timeline.markerDetail.consoleTimerName")
}],
},
"TimeStamp": {
group: 2,
colorName: "graphs-blue",
label: sublabelForProperty(L10N.getStr("timeline.label.timestamp"), "causeName"),
fields: [{
property: "causeName",
label: "Label:"
}],
},
};
/**
* Helper for creating a function that returns the first defined result from
* a list of functions passed in as params, in order.
* @param ...function fun
* @return any
*/
function either(...fun) {
return function() {
for (let f of fun) {
let result = f.apply(null, arguments);
if (result !== undefined) return result;
}
}
}
/**
* Takes a main label (like "Timestamp") and a property,
* and returns a marker that will print out the property
* value for a marker if it exists ("Timestamp (rendering)"),
* or just the main label if it does not.
*/
function sublabelForProperty (mainLabel, prop) {
return (marker={}) => marker[prop] ? `${mainLabel} (${marker[prop]})` : mainLabel;
}
// Exported symbols.
exports.TIMELINE_BLUEPRINT = TIMELINE_BLUEPRINT;
@@ -14,7 +14,7 @@ loader.lazyRequireGetter(this, "EventEmitter",
loader.lazyRequireGetter(this, "L10N",
"devtools/performance/global", true);
loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
"devtools/performance/global", true);
"devtools/performance/markers", true);
loader.lazyRequireGetter(this, "MarkerUtils",
"devtools/performance/marker-utils");
@@ -11,7 +11,7 @@
const { Cc, Ci, Cu, Cr } = require("chrome");
const { Heritage } = require("resource:///modules/devtools/ViewHelpers.jsm");
const { AbstractTreeItem } = require("resource:///modules/devtools/AbstractTreeItem.jsm");
const { TIMELINE_BLUEPRINT: ORIGINAL_BP } = require("devtools/performance/global");
const { TIMELINE_BLUEPRINT: ORIGINAL_BP } = require("devtools/performance/markers");
loader.lazyRequireGetter(this, "MarkerUtils",
"devtools/performance/marker-utils");
+1
View File
@@ -16,6 +16,7 @@ EXTRA_JS_MODULES.devtools.performance += [
'modules/logic/recording-utils.js',
'modules/logic/tree-model.js',
'modules/logic/waterfall-utils.js',
'modules/markers.js',
'modules/widgets/graphs.js',
'modules/widgets/marker-details.js',
'modules/widgets/marker-view.js',
+3 -1
View File
@@ -56,7 +56,9 @@ PerformancePanel.prototype = {
// DevToolPanel API
get target() this._toolbox.target,
get target() {
return this._toolbox.target;
},
destroy: Task.async(function*() {
// Make sure this panel is not already destroyed.
@@ -18,7 +18,7 @@ loader.lazyRequireGetter(this, "DevToolsUtils",
loader.lazyRequireGetter(this, "L10N",
"devtools/performance/global", true);
loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
"devtools/performance/global", true);
"devtools/performance/markers", true);
loader.lazyRequireGetter(this, "RecordingUtils",
"devtools/performance/recording-utils");
loader.lazyRequireGetter(this, "RecordingModel",
@@ -6,7 +6,7 @@
* You can also use this initialization format as a template for other tests.
*/
function spawnTest () {
function* spawnTest() {
let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
ok(target, "Should have a target available.");
@@ -5,8 +5,8 @@
* Tests the marker utils methods.
*/
function spawnTest () {
let { TIMELINE_BLUEPRINT } = devtools.require("devtools/performance/global");
function* spawnTest() {
let { TIMELINE_BLUEPRINT } = devtools.require("devtools/performance/markers");
let Utils = devtools.require("devtools/performance/marker-utils");
Services.prefs.setBoolPref(PLATFORM_DATA_PREF, false);
@@ -5,7 +5,7 @@
* Tests that the categories are shown in the js call tree when platform data
* is enabled.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, $, DetailsView, JsCallTreeView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the js call tree view renders the correct columns.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, $, $$, DetailsView, JsCallTreeView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the memory call tree view renders the correct columns.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, $, $$, DetailsView, MemoryCallTreeView } = panel.panelWin;
@@ -7,7 +7,7 @@
let WAIT_TIME = 100;
function spawnTest () {
function* spawnTest() {
let { target, front } = yield initBackend(SIMPLE_URL, {
TEST_MOCK_MEMORY_ACTOR: true,
TEST_MOCK_TIMELINE_ACTOR: true
@@ -7,7 +7,7 @@
let WAIT_TIME = 100;
function spawnTest () {
function* spawnTest() {
let { target, front } = yield initBackend(SIMPLE_URL, {
TEST_MOCK_MEMORY_ACTOR: true
});
@@ -9,7 +9,7 @@
const WAIT_TIME = 1000; // ms
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { gFront: front, gTarget: target } = panel.panelWin;
let connection = getPerformanceActorsConnection(target);
@@ -7,7 +7,7 @@
* `getBufferUsage()` values.
*/
function spawnTest () {
function* spawnTest() {
let { target, front } = yield initBackend(SIMPLE_URL, {
TEST_MOCK_PROFILER_CHECK_TIMER: 10,
TEST_PROFILER_FILTER_STATUS: ["position", "totalSize", "generation"]
@@ -5,7 +5,7 @@
* Tests that recording notices does not display any buffer
* status on servers that do not support buffer statuses.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL, void 0, {
TEST_MOCK_PROFILER_CHECK_TIMER: 10,
TEST_PROFILER_FILTER_STATUS: ["position", "totalSize", "generation"]
@@ -9,7 +9,7 @@
let { getPerformanceActorsConnection } = devtools.require("devtools/performance/front");
let WAIT_TIME = 10;
function spawnTest () {
function* spawnTest() {
let profilerConnected = waitForProfilerConnection();
let { target, toolbox, console } = yield initConsole(SIMPLE_URL);
yield profilerConnected;
@@ -9,7 +9,7 @@
let { getPerformanceActorsConnection } = devtools.require("devtools/performance/front");
let WAIT_TIME = 10;
function spawnTest () {
function* spawnTest() {
let profilerConnected = waitForProfilerConnection();
let { target, toolbox, console } = yield initConsole(SIMPLE_URL);
yield profilerConnected;
@@ -9,7 +9,7 @@
let { getPerformanceActorsConnection } = devtools.require("devtools/performance/front");
let WAIT_TIME = 10;
function spawnTest () {
function* spawnTest() {
let profilerConnected = waitForProfilerConnection();
let { target, toolbox, console } = yield initConsole(SIMPLE_URL);
yield profilerConnected;
@@ -6,7 +6,7 @@
* after being opened.
*/
function spawnTest () {
function* spawnTest() {
loadFrameScripts();
let { target, toolbox, panel } = yield initPerformance(SIMPLE_URL);
let { $, EVENTS, gFront, PerformanceController, OverviewView, RecordingsView } = panel.panelWin;
@@ -6,7 +6,7 @@
* in the recording list.
*/
function spawnTest () {
function* spawnTest() {
loadFrameScripts();
let { target, toolbox, panel } = yield initPerformance(SIMPLE_URL);
let { $, EVENTS, gFront, PerformanceController, OverviewView, RecordingsView } = panel.panelWin;
@@ -5,7 +5,7 @@
* Tests that console recordings can overlap (not completely nested).
*/
function spawnTest () {
function* spawnTest() {
loadFrameScripts();
let { target, toolbox, panel } = yield initPerformance(SIMPLE_URL);
let { $, EVENTS, gFront, PerformanceController, OverviewView, RecordingsView, WaterfallView } = panel.panelWin;
@@ -7,7 +7,7 @@
* match any pending recordings does nothing.
*/
function spawnTest () {
function* spawnTest() {
loadFrameScripts();
let { target, toolbox, panel } = yield initPerformance(SIMPLE_URL);
let { $, EVENTS, gFront, PerformanceController, OverviewView, RecordingsView, WaterfallView } = panel.panelWin;
@@ -21,7 +21,7 @@ function testRecordings (win, expected) {
});
}
function spawnTest () {
function* spawnTest() {
loadFrameScripts();
let { target, toolbox, panel } = yield initPerformance(SIMPLE_URL);
let win = panel.panelWin;
@@ -8,7 +8,7 @@
const WAIT_TIME = 1000; // ms
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let front = panel.panelWin.gFront;
@@ -9,7 +9,7 @@
const WAIT_TIME = 1000; // ms
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let front = panel.panelWin.gFront;
@@ -4,7 +4,7 @@
/**
* Tests that the details view toggles subviews.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, $, DetailsView, document: doc } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the details view utility functions work as advertised.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView } = panel.panelWin;
let { WaterfallView, JsCallTreeView, JsFlameGraphView } = panel.panelWin;
@@ -6,7 +6,7 @@
* have memory data (withMemory: false), and that when a memory panel is selected,
* switching to a panel that does not have memory goes to a default panel instead.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, OverviewView, DetailsView } = panel.panelWin;
let { $, RecordingsView, WaterfallView, MemoryCallTreeView, MemoryFlameGraphView } = panel.panelWin;
@@ -5,7 +5,7 @@
* Tests that the details view hides the toolbar buttons when a recording
* doesn't exist or is in progress.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, $, $$, PerformanceController, RecordingsView, WaterfallView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the details view utility functions work as advertised.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView } = panel.panelWin;
let { PerformanceController, WaterfallView, JsCallTreeView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the views with `shouldUpdateWhileMouseIsActive` works as intended.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, OverviewView, DetailsView, WaterfallView, JsFlameGraphView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the call tree view renders content after recording.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsCallTreeView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the flamegraph view renders content after recording.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsFlameGraphView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the memory call tree view renders content after recording.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, MemoryCallTreeView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the memory flamegraph view renders content after recording.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, MemoryFlameGraphView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the waterfall view renders content after recording.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, DetailsView, WaterfallView } = panel.panelWin;
@@ -7,7 +7,7 @@
const { ThreadNode } = devtools.require("devtools/performance/tree-model");
const RecordingUtils = devtools.require("devtools/performance/recording-utils")
function spawnTest () {
function* spawnTest() {
let focus = 0;
let focusEvent = () => focus++;
@@ -7,7 +7,7 @@
let WAIT_TIME = 1000;
function spawnTest () {
function* spawnTest() {
let { target, front } = yield initBackend(SIMPLE_URL);
let recording = yield front.startRecording({
@@ -8,7 +8,7 @@
let WAIT_TIME = 1000;
function spawnTest () {
function* spawnTest() {
let { target, front } = yield initBackend(SIMPLE_URL);
let config = { withMarkers: true, withMemory: true, withTicks: true };
@@ -7,7 +7,7 @@
let WAIT_TIME = 1000;
function spawnTest () {
function* spawnTest() {
let { target, front } = yield initBackend(SIMPLE_URL);
let startModel = yield front.startRecording();
@@ -5,7 +5,7 @@
* Test basic functionality of PerformanceFront, retrieving timeline data.
*/
function spawnTest () {
function* spawnTest() {
let { target, front } = yield initBackend(SIMPLE_URL);
let lastMemoryDelta = 0;
@@ -68,8 +68,11 @@ function spawnTest () {
counters.ticks.push({ delta, timestamps });
lastTickDelta = delta;
}
else if (name === "frames") {
// Nothing to do here.
}
else {
throw new Error("unknown event " + name);
ok(false, `Received unknown event: ${name}`);
}
if (name === "markers" && counters[name].length === 1 ||
@@ -8,7 +8,7 @@
let { getPerformanceActorsConnection } = devtools.require("devtools/performance/front");
function spawnTest () {
function* spawnTest() {
let profilerConnected = waitForProfilerConnection();
let { target, toolbox, console } = yield initConsole(SIMPLE_URL);
yield profilerConnected;
@@ -10,7 +10,7 @@ const RecordingUtils = devtools.require("devtools/performance/recording-utils");
Services.prefs.setBoolPref(INVERT_PREF, false);
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, $, $$, window, PerformanceController } = panel.panelWin;
let { OverviewView, DetailsView, JITOptimizationsView, JsCallTreeView, RecordingsView } = panel.panelWin;
@@ -12,7 +12,7 @@ const RecordingUtils = devtools.require("devtools/performance/recording-utils");
Services.prefs.setBoolPref(INVERT_PREF, false);
Services.prefs.setBoolPref(PLATFORM_DATA_PREF, false);
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, $, $$, window, PerformanceController } = panel.panelWin;
let { OverviewView, DetailsView, JITOptimizationsView, JsCallTreeView, RecordingsView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that toggling preferences before there are any recordings does not throw.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsCallTreeView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that toggling preferences during a recording does not throw.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsCallTreeView } = panel.panelWin;
@@ -7,7 +7,7 @@
Services.prefs.setBoolPref(EXPERIMENTAL_PREF, false);
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { $, EVENTS, PerformanceController } = panel.panelWin;
@@ -5,7 +5,7 @@
/**
* Tests that setting the `devtools.performance.memory.` prefs propagate to the memory actor.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, $, gFront } = panel.panelWin;
Services.prefs.setBoolPref(MEMORY_PREF, true);
@@ -5,7 +5,7 @@
* Tests that `enable-framerate` toggles the visibility of the fps graph,
* as well as enabling ticks data on the PerformanceFront.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, $ } = panel.panelWin;
Services.prefs.setBoolPref(FRAMERATE_PREF, false);
@@ -5,7 +5,7 @@
* Tests that `enable-memory` toggles the visibility of the memory graph,
* as well as enabling memory data on the PerformanceFront.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, $ } = panel.panelWin;
@@ -5,7 +5,7 @@
* Tests that toggling `enable-memory` during a recording doesn't change that
* recording's state and does not break.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, $ } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the js flamegraphs get rerendered when toggling `flatten-tree-recursion`
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, DetailsView, JsFlameGraphView, FlameGraphUtils } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the memory flamegraphs get rerendered when toggling `flatten-tree-recursion`
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, DetailsView, MemoryFlameGraphView, RecordingUtils, FlameGraphUtils } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the js call tree views get rerendered when toggling `invert-call-tree`
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsCallTreeView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the memory call tree views get rerendered when toggling `invert-call-tree`
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, MemoryCallTreeView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the js Flamegraphs gets rerendered when toggling `invert-flame-graph`
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsFlameGraphView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the memory Flamegraphs gets rerendered when toggling `invert-flame-graph`
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, MemoryFlameGraphView } = panel.panelWin;
@@ -5,7 +5,7 @@
/**
* Tests that setting the `devtools.performance.profiler.` prefs propagate to the profiler actor.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { gFront } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the js flamegraphs get rerendered when toggling `show-idle-blocks`
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsFlameGraphView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the memory flamegraphs get rerendered when toggling `show-idle-blocks`
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, MemoryFlameGraphView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the js call tree views get rerendered when toggling `show-platform-data`
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsCallTreeView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the js flamegraphs get rerendered when toggling `show-platform-data`
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsFlameGraphView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the overview continuously renders content when recording.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, OverviewView } = panel.panelWin;
@@ -5,7 +5,7 @@
* Tests that the overview graphs cannot be selected during recording
* and that they're cleared upon rerecording.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, OverviewView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the overview graphs share the exact same width and scaling.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, OverviewView } = panel.panelWin;
@@ -5,7 +5,7 @@
* Tests that the overview graphs do not render when realtime rendering is off
* due to lack of e10s.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { $, EVENTS, PerformanceController, OverviewView, RecordingsView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that events are fired from OverviewView from selection manipulation.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, OverviewView } = panel.panelWin;
let startTime, endTime, params, _;
@@ -4,7 +4,7 @@
/**
* Tests that the graphs' selection is correctly disabled or enabled.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, OverviewView } = panel.panelWin;
@@ -4,7 +4,7 @@
/**
* Tests that the graphs' selections are linked.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, OverviewView } = panel.panelWin;
@@ -5,7 +5,7 @@
* Tests that the `setTimeInterval` and `getTimeInterval` functions
* work properly.
*/
function spawnTest () {
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, OverviewView } = panel.panelWin;

Some files were not shown because too many files have changed in this diff Show More