Bug 1570549 - P8 - Restore SDP comparison telemetry;r=bwc

This moves the telemetry and preferences out into their own files and restores the parse result telemetery.

Differential Revision: https://phabricator.services.mozilla.com/D52749

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Nico Grunbaum 2019-11-22 23:42:34 +00:00
Родитель 8bc5a22903
Коммит ecd11a5b59
12 изменённых файлов: 317 добавлений и 165 удалений

Просмотреть файл

@ -5,12 +5,15 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "signaling/src/sdp/HybridSdpParser.h"
#include "signaling/src/sdp/SdpLog.h"
#include "signaling/src/sdp/SdpPref.h"
#include "signaling/src/sdp/SdpTelemetry.h"
#include "signaling/src/sdp/SipccSdpParser.h"
#include "signaling/src/sdp/RsdparsaSdpParser.h"
#include "signaling/src/sdp/ParsingResultComparer.h"
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
#include "mozilla/Telemetry.h"
#include <unordered_map>
@ -18,112 +21,6 @@ namespace mozilla {
using mozilla::LogLevel;
// Interprets about:config SDP parsing preferences
class SdpPref {
private:
static const std::string PRIMARY_PREF;
static const std::string ALTERNATE_PREF;
static const std::string DEFAULT;
// Supported Parsers
enum class Parsers {
Sipcc,
WebRtcSdp,
};
// How is the alternate used
enum class AlternateParseModes {
Parallel, // Alternate is always run, if A succedes it is used, otherwise B
// is used
Failover, // Alternate is only run on failure of the primary to parse
Never, // Alternate is never run; this is effectively a kill switch
};
// Finds the mapping between a pref string and pref value, if none exists the
// default is used
template <class T>
static auto Pref(const std::string& aPrefName,
const std::unordered_map<std::string, T>& aMap) -> T {
MOZ_ASSERT(aMap.find(DEFAULT) != aMap.end());
nsCString value;
if (NS_FAILED(Preferences::GetCString(aPrefName.c_str(), value))) {
return aMap.at(DEFAULT);
}
const auto found = aMap.find(value.get());
if (found != aMap.end()) {
return found->second;
}
return aMap.at(DEFAULT);
}
// The value of the parser pref
static auto Parser() -> Parsers {
static const auto values = std::unordered_map<std::string, Parsers>{
{"legacy", Parsers::Sipcc},
{"webrtc-sdp", Parsers::WebRtcSdp},
{DEFAULT, Parsers::Sipcc},
};
return Pref(PRIMARY_PREF, values);
}
// The value of the alternate parse mode pref
static auto AlternateParseMode() -> AlternateParseModes {
static const auto values =
std::unordered_map<std::string, AlternateParseModes>{
{"parallel", AlternateParseModes::Parallel},
{"failover", AlternateParseModes::Failover},
{"never", AlternateParseModes::Never},
{DEFAULT, AlternateParseModes::Parallel},
};
return Pref(ALTERNATE_PREF, values);
}
public:
// Functions to get the primary, secondary and failover parsers.
// These exist as they do so that the coresponding fields in HybridSdpParser
// can be const initialized.
// Reads about:config to choose the primary Parser
static auto Primary() -> UniquePtr<SdpParser> {
switch (Parser()) {
case Parsers::Sipcc:
return UniquePtr<SdpParser>(new SipccSdpParser());
case Parsers::WebRtcSdp:
return UniquePtr<SdpParser>(new RsdparsaSdpParser());
}
}
static auto Secondary() -> Maybe<UniquePtr<SdpParser>> {
if (AlternateParseMode() != AlternateParseModes::Parallel) {
return Nothing();
}
switch (Parser()) { // Choose whatever the primary parser isn't
case Parsers::Sipcc:
return Some(UniquePtr<SdpParser>(new RsdparsaSdpParser()));
case Parsers::WebRtcSdp:
return Some(UniquePtr<SdpParser>(new SipccSdpParser()));
}
}
static auto Failover() -> Maybe<UniquePtr<SdpParser>> {
if (AlternateParseMode() != AlternateParseModes::Failover) {
return Nothing();
}
switch (Parser()) {
case Parsers::Sipcc:
return Some(UniquePtr<SdpParser>(new RsdparsaSdpParser()));
case Parsers::WebRtcSdp:
return Some(UniquePtr<SdpParser>(new SipccSdpParser()));
}
}
};
const std::string SdpPref::PRIMARY_PREF = "media.peerconnection.sdp.parser";
const std::string SdpPref::ALTERNATE_PREF =
"media.peerconnection.sdp.alternate_parse_mode";
const std::string SdpPref::DEFAULT = "default";
HybridSdpParser::HybridSdpParser()
: mPrimary(SdpPref::Primary()),
mSecondary(SdpPref::Secondary()),
@ -145,22 +42,33 @@ HybridSdpParser::HybridSdpParser()
auto HybridSdpParser::Parse(const std::string& aText)
-> UniquePtr<SdpParser::Results> {
using Results = UniquePtr<SdpParser::Results>;
using Role = SdpTelemetry::Roles;
using Mode = SdpPref::AlternateParseModes;
Mode mode = Mode::Never;
auto results = mPrimary->Parse(aText);
// Pass results on for comparison and return A if it was a success and B
// otherwise.
auto compare = [&results, &aText](Results&& aResB) -> Results {
ParsingResultComparer::Compare(results, aResB, aText);
auto compare = [&](Results&& aResB) -> Results {
SdpTelemetry::RecordParse(aResB, mode, Role::Secondary);
ParsingResultComparer::Compare(results, aResB, aText, mode);
return std::move(results->Ok() ? results : aResB);
};
// Run secondary parser, if there is one, and update selected results.
mSecondary.apply(
[&](auto& sec) { results = compare(std::move(sec->Parse(aText))); });
mSecondary.apply([&](auto& sec) {
mode = Mode::Parallel;
results = compare(std::move(sec->Parse(aText)));
});
// Run failover parser, if there is one, and update selected results.
mFailover.apply([&](auto& failover) { // Only run if primary parser failed
mode = Mode::Failover;
if (!results->Ok()) {
results = compare(std::move(failover->Parse(aText)));
}
});
SdpTelemetry::RecordParse(results, mode, Role::Primary);
return results;
}

Просмотреть файл

@ -8,6 +8,7 @@
#define _HYBRIDSDPPARSER_H_
#include "signaling/src/sdp/SdpParser.h"
#include "signaling/src/sdp/SdpTelemetry.h"
namespace mozilla {

Просмотреть файл

@ -44,40 +44,27 @@ std::string ToString(const T& serializable) {
os << serializable;
return os.str();
}
// TODO from JsepSessionImpl
// if (mRunRustParser) {
// auto results = mRsdparsaParser.Parse(sdp);
// auto rustParsed = std::move(results->Sdp());
// auto errors = results->Errors();
// if (mRunSdpComparer) {
// ParsingResultComparer comparer;
// if (rustParsed) {
// comparer.Compare(*rustParsed, *parsed, sdp);
// } else {
// comparer.TrackRustParsingFailed(errors.size());
// }
// }
// }
bool ParsingResultComparer::Compare(const UniquePtr<SdpParser::Results>& aResA,
const UniquePtr<SdpParser::Results>& aResB,
const std::string& originalSdp) {
bool ParsingResultComparer::Compare(const Results& aResA, const Results& aResB,
const std::string& aOriginalSdp,
const SdpPref::AlternateParseModes& aMode) {
MOZ_ASSERT(aResA, "aResA must not be a nullptr");
MOZ_ASSERT(aResB, "aResB must not be a nullptr");
MOZ_ASSERT(aResA->ParserName() != aResB->ParserName(),
"aResA and aResB must be from different parsers");
SdpTelemetry::RecordCompare(aResA, aResB, aMode);
ParsingResultComparer comparer;
if (!aResA->Sdp() || !aResB->Sdp()) {
return !aResA->Sdp() && !aResB->Sdp(); // TODO handle telemetery for this
return !aResA->Sdp() && !aResB->Sdp();
}
if (SipccSdpParser::IsNamed(aResA->ParserName())) {
MOZ_ASSERT(RsdparsaSdpParser::IsNamed(aResB->ParserName()));
return comparer.Compare(*aResB->Sdp(), *aResA->Sdp(), originalSdp,
return comparer.Compare(*aResB->Sdp(), *aResA->Sdp(), aOriginalSdp,
SdpComparisonResult::Equal);
}
MOZ_ASSERT(SipccSdpParser::IsNamed(aResB->ParserName()));
MOZ_ASSERT(RsdparsaSdpParser::IsNamed(aResA->ParserName()));
return comparer.Compare(*aResA->Sdp(), *aResB->Sdp(), originalSdp,
return comparer.Compare(*aResA->Sdp(), *aResB->Sdp(), aOriginalSdp,
SdpComparisonResult::Equal);
}
@ -304,33 +291,6 @@ bool ParsingResultComparer::CompareAttrLists(
return result;
}
// TODO Track a tuple of failures?
void ParsingResultComparer::TrackRustParsingFailed(
size_t sipccErrorCount) const {
if (sipccErrorCount) {
Telemetry::ScalarAdd(Telemetry::ScalarID::WEBRTC_SDP_PARSER_DIFF,
NS_LITERAL_STRING("rsdparsa_failed__sipcc_has_errors"),
1);
} else {
Telemetry::ScalarAdd(Telemetry::ScalarID::WEBRTC_SDP_PARSER_DIFF,
NS_LITERAL_STRING("rsdparsa_failed__sipcc_succeeded"),
1);
}
}
void ParsingResultComparer::TrackSipccParsingFailed(
size_t webrtcSdpErrorCount) const {
if (webrtcSdpErrorCount) {
Telemetry::ScalarAdd(
Telemetry::ScalarID::WEBRTC_SDP_PARSER_DIFF,
NS_LITERAL_STRING("sipcc_failed__webrtcsdp_has_errors"), 1);
} else {
Telemetry::ScalarAdd(Telemetry::ScalarID::WEBRTC_SDP_PARSER_DIFF,
NS_LITERAL_STRING("sipcc_failed__webrtcsdp_succeeded"),
1);
}
}
std::vector<std::string> SplitLines(const std::string& sdp) {
std::stringstream ss(sdp);
std::string to;

Просмотреть файл

@ -8,6 +8,8 @@
#define _PARSINGRESULTCOMPARER_H_
#include "signaling/src/sdp/SdpParser.h"
#include "signaling/src/sdp/SdpPref.h"
#include <string>
namespace mozilla {
@ -23,13 +25,15 @@ enum class SdpComparisonResult {
class ParsingResultComparer {
public:
using Results = UniquePtr<SdpParser::Results>;
ParsingResultComparer() = default;
static bool Compare(const UniquePtr<SdpParser::Results>& aResA,
const UniquePtr<SdpParser::Results>& aResB,
const std::string& orignalSdp);
static bool Compare(const Results& aResA, const Results& aResB,
const std::string& aOrignalSdp,
const SdpPref::AlternateParseModes& aMode);
bool Compare(const Sdp& rsdparsaSdp, const Sdp& sipccSdp,
const std::string& originalSdp,
const std::string& aOriginalSdp,
const SdpComparisonResult expect = SdpComparisonResult::Equal);
bool CompareMediaSections(
const SdpMediaSection& rustMediaSection,

Просмотреть файл

@ -17,7 +17,7 @@
namespace mozilla {
static const std::string& WEBRTC_SDP_NAME = "WEBRTC_SDP_NAME";
static const std::string& WEBRTC_SDP_NAME = "WEBRTCSDP";
const std::string& RsdparsaSdpParser::Name() const { return WEBRTC_SDP_NAME; }

Просмотреть файл

@ -11,6 +11,8 @@
#include <string>
#include "signaling/src/sdp/Sdp.h"
#include "mozilla/Telemetry.h"
namespace mozilla {
class SdpParser {

Просмотреть файл

@ -0,0 +1,91 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "signaling/src/sdp/SdpPref.h"
namespace mozilla {
const std::string SdpPref::PRIMARY_PREF = "media.peerconnection.sdp.parser";
const std::string SdpPref::ALTERNATE_PREF =
"media.peerconnection.sdp.alternate_parse_mode";
const std::string SdpPref::DEFAULT = "default";
auto SdpPref::ToString(const Parsers& aParser) -> std::string {
switch (aParser) {
case Parsers::Sipcc:
return "sipcc";
case Parsers::WebRtcSdp:
return "webrtc-sdp";
};
MOZ_CRASH("ALL Parsers CASES ARE NOT COVERED");
}
auto SdpPref::ToString(const AlternateParseModes& aMode) -> std::string {
switch (aMode) {
case AlternateParseModes::Parallel:
return "parallel";
case AlternateParseModes::Failover:
return "failover";
case AlternateParseModes::Never:
return "never";
};
MOZ_CRASH("ALL AlternateParseModes CASES ARE NOT COVERED");
}
auto SdpPref::Parser() -> Parsers {
static const auto values = std::unordered_map<std::string, Parsers>{
{"legacy", Parsers::Sipcc},
{"webrtc-sdp", Parsers::WebRtcSdp},
{DEFAULT, Parsers::Sipcc},
};
return Pref(PRIMARY_PREF, values);
}
auto SdpPref::AlternateParseMode() -> AlternateParseModes {
static const auto values =
std::unordered_map<std::string, AlternateParseModes>{
{"parallel", AlternateParseModes::Parallel},
{"failover", AlternateParseModes::Failover},
{"never", AlternateParseModes::Never},
{DEFAULT, AlternateParseModes::Parallel},
};
return Pref(ALTERNATE_PREF, values);
}
auto SdpPref::Primary() -> UniquePtr<SdpParser> {
switch (Parser()) {
case Parsers::Sipcc:
return UniquePtr<SdpParser>(new SipccSdpParser());
case Parsers::WebRtcSdp:
return UniquePtr<SdpParser>(new RsdparsaSdpParser());
}
}
auto SdpPref::Secondary() -> Maybe<UniquePtr<SdpParser>> {
if (AlternateParseMode() != AlternateParseModes::Parallel) {
return Nothing();
}
switch (Parser()) { // Choose whatever the primary parser isn't
case Parsers::Sipcc:
return Some(UniquePtr<SdpParser>(new RsdparsaSdpParser()));
case Parsers::WebRtcSdp:
return Some(UniquePtr<SdpParser>(new SipccSdpParser()));
}
}
auto SdpPref::Failover() -> Maybe<UniquePtr<SdpParser>> {
if (AlternateParseMode() != AlternateParseModes::Failover) {
return Nothing();
}
switch (Parser()) {
case Parsers::Sipcc:
return Some(UniquePtr<SdpParser>(new RsdparsaSdpParser()));
case Parsers::WebRtcSdp:
return Some(UniquePtr<SdpParser>(new SipccSdpParser()));
}
}
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,79 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _SDPPREF_H_
#define _SDPPREF_H_
#include "mozilla/Maybe.h"
#include "mozilla/Preferences.h"
#include <string>
#include <unordered_map>
namespace mozilla {
class SdpParser;
// Interprets about:config SDP parsing preferences
class SdpPref {
private:
static const std::string PRIMARY_PREF;
static const std::string ALTERNATE_PREF;
static const std::string DEFAULT;
public:
// Supported Parsers
enum class Parsers {
Sipcc,
WebRtcSdp,
};
static auto ToString(const Parsers& aParser) -> std::string;
// How is the alternate used
enum class AlternateParseModes {
Parallel, // Alternate is always run, if A succedes it is used, otherwise B
// is used
Failover, // Alternate is only run on failure of the primary to parse
Never, // Alternate is never run; this is effectively a kill switch
};
static auto ToString(const AlternateParseModes& aMode) -> std::string;
private:
// Finds the mapping between a pref string and pref value, if none exists the
// default is used
template <class T>
static auto Pref(const std::string& aPrefName,
const std::unordered_map<std::string, T>& aMap) -> T {
MOZ_ASSERT(aMap.find(DEFAULT) != aMap.end());
nsCString value;
if (NS_FAILED(Preferences::GetCString(aPrefName.c_str(), value))) {
return aMap.at(DEFAULT);
}
const auto found = aMap.find(value.get());
if (found != aMap.end()) {
return found->second;
}
return aMap.at(DEFAULT);
}
// The value of the parser pref
static auto Parser() -> Parsers;
// The value of the alternate parse mode pref
static auto AlternateParseMode() -> AlternateParseModes;
public:
// Functions to create the primary, secondary and failover parsers.
// Reads about:config to choose the primary Parser
static auto Primary() -> UniquePtr<SdpParser>;
static auto Secondary() -> Maybe<UniquePtr<SdpParser>>;
static auto Failover() -> Maybe<UniquePtr<SdpParser>>;
};
} // namespace mozilla
#endif

Просмотреть файл

@ -0,0 +1,63 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "signaling/src/sdp/SdpTelemetry.h"
#include "mozilla/Telemetry.h"
namespace mozilla {
auto SdpTelemetry::RecordParse(const SdpTelemetry::Results& aResult,
const SdpTelemetry::Modes& aMode,
const SdpTelemetry::Roles& aRole) -> void {
Telemetry::ScalarAdd(Telemetry::ScalarID::WEBRTC_SDP_PARSER_DIFF,
BucketNameFragment(aResult, aMode, aRole), 1);
}
auto SdpTelemetry::RecordCompare(const SdpTelemetry::Results& aFirst,
const SdpTelemetry::Results& aSecond,
const SdpTelemetry::Modes& aMode) -> void {
const nsAutoString bucket =
BucketNameFragment(aFirst, aMode, Roles::Primary) +
NS_ConvertASCIItoUTF16("__") +
BucketNameFragment(aSecond, aMode, Roles::Secondary);
Telemetry::ScalarAdd(Telemetry::ScalarID::WEBRTC_SDP_PARSER_DIFF, bucket, 1);
}
auto SdpTelemetry::BucketNameFragment(const SdpTelemetry::Results& aResult,
const SdpTelemetry::Modes& aMode,
const SdpTelemetry::Roles& aRole)
-> nsAutoString {
auto mode = [&]() -> std::string {
switch (aMode) {
case Modes::Parallel:
return "parallel";
case Modes::Failover:
return "failover";
case Modes::Never:
return "standalone";
}
MOZ_CRASH("Unknown SDP Parse Mode!");
};
auto role = [&]() -> std::string {
switch (aRole) {
case Roles::Primary:
return "primary";
case Roles::Secondary:
return "secondary";
}
MOZ_CRASH("Unknown SDP Parse Role!");
};
auto success = [&]() -> std::string {
return aResult->Ok() ? "success" : "failure";
};
nsAutoString name;
name.AssignASCII(nsCString(aResult->ParserName() + "_" + mode() + "_" +
role() + "_" + success()));
return name;
}
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,42 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _SDPTELEMETRY_H_
#define _SDPTELEMETRY_H_
#include "signaling/src/sdp/SdpPref.h"
namespace mozilla {
class SdpTelemetry {
public:
SdpTelemetry() = delete;
using Results = UniquePtr<SdpParser::Results>;
using Modes = SdpPref::AlternateParseModes;
enum class Roles {
Primary,
Secondary,
};
static auto RecordParse(const Results& aResults, const Modes& aMode,
const Roles& aRole) -> void;
static auto RecordSecondaryParse(const Results& aResult, const Modes& aMode)
-> void;
static auto RecordCompare(const Results& aFirst, const Results& aSecond,
const Modes& aMode) -> void;
private:
static auto BucketNameFragment(const Results& aResult, const Modes& aModes,
const Roles& aRoles) -> nsAutoString;
};
} // namespace mozilla
#endif

Просмотреть файл

@ -36,6 +36,8 @@ UNIFIED_SOURCES += [
'SdpHelper.cpp',
'SdpLog.cpp',
'SdpMediaSection.cpp',
'SdpPref.cpp',
'SdpTelemetry.cpp',
'SipccSdp.cpp',
'SipccSdpAttributeList.cpp',
'SipccSdpMediaSection.cpp',

Просмотреть файл

@ -431,10 +431,10 @@ pref("media.videocontrols.picture-in-picture.video-toggle.always-show", false);
pref("media.navigator.video.red_ulpfec_enabled", false);
#ifdef NIGHTLY_BUILD
pref("media.peerconnection.sdp.parser", "legacy");
pref("media.peerconnection.sdp.parser", "sipcc");
pref("media.peerconnection.sdp.alternate_parse_mode", "parallel");
#else
pref("media.peerconnection.sdp.parser", "legacy");
pref("media.peerconnection.sdp.parser", "sipcc");
pref("media.peerconnection.sdp.alternate_parse_mode", "failover");
#endif