Skip to content

Commit

Permalink
Bug 1838497 - Add a profiler feature to record the clock frequency of…
Browse files Browse the repository at this point in the history
… every core while sampling, r=canaltinova.

Differential Revision: https://phabricator.services.mozilla.com/D180983
  • Loading branch information
fqueze committed Aug 10, 2023
1 parent d11c1d6 commit bdaa341
Show file tree
Hide file tree
Showing 13 changed files with 719 additions and 3 deletions.
9 changes: 9 additions & 0 deletions devtools/client/performance-new/shared/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,15 @@ const featureDescriptions = [
})(),
experimental: true,
},
{
name: "CPU Frequency",
value: "cpufreq",
title:
"Record the clock frequency of every CPU core for every profiler sample.",
experimental: true,
disabledReason:
"This feature is only available on Windows, Linux and Android.",
},
];

module.exports = {
Expand Down
65 changes: 65 additions & 0 deletions mozglue/baseprofiler/core/ProfilerMarkers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,25 @@ void MarkerSchema::Stream(JSONWriter& aWriter,
}
}
aWriter.EndArray();

if (!mGraphs.empty()) {
aWriter.StartArrayProperty("graphs");
{
for (const GraphData& graph : mGraphs) {
aWriter.StartObjectElement();
{
aWriter.StringProperty("key", graph.mKey);
aWriter.StringProperty("type", GraphTypeToStringSpan(graph.mType));
if (graph.mColor) {
aWriter.StringProperty("color",
GraphColorToStringSpan(*graph.mColor));
}
}
aWriter.EndObject();
}
}
aWriter.EndArray();
}
}
aWriter.EndObject();
}
Expand Down Expand Up @@ -331,6 +350,52 @@ Span<const char> MarkerSchema::FormatToStringSpan(
}
}

/* static */
Span<const char> MarkerSchema::GraphTypeToStringSpan(
MarkerSchema::GraphType aType) {
switch (aType) {
case GraphType::Line:
return mozilla::MakeStringSpan("line");
case GraphType::Bar:
return mozilla::MakeStringSpan("bar");
case GraphType::FilledLine:
return mozilla::MakeStringSpan("line-filled");
default:
MOZ_CRASH("Unexpected GraphType enum");
return {};
}
}

/* static */
Span<const char> MarkerSchema::GraphColorToStringSpan(
MarkerSchema::GraphColor aColor) {
switch (aColor) {
case GraphColor::Blue:
return mozilla::MakeStringSpan("blue");
case GraphColor::Green:
return mozilla::MakeStringSpan("green");
case GraphColor::Grey:
return mozilla::MakeStringSpan("grey");
case GraphColor::Ink:
return mozilla::MakeStringSpan("ink");
case GraphColor::Magenta:
return mozilla::MakeStringSpan("magenta");
case GraphColor::Orange:
return mozilla::MakeStringSpan("orange");
case GraphColor::Purple:
return mozilla::MakeStringSpan("purple");
case GraphColor::Red:
return mozilla::MakeStringSpan("red");
case GraphColor::Teal:
return mozilla::MakeStringSpan("teal");
case GraphColor::Yellow:
return mozilla::MakeStringSpan("yellow");
default:
MOZ_CRASH("Unexpected GraphColor enum");
return {};
}
}

} // namespace mozilla

namespace mozilla::baseprofiler {
Expand Down
36 changes: 36 additions & 0 deletions mozglue/baseprofiler/public/BaseProfilerMarkersPrerequisites.h
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,19 @@ class MarkerSchema {
};

enum class Searchable { NotSearchable, Searchable };
enum class GraphType { Line, Bar, FilledLine };
enum class GraphColor {
Blue,
Green,
Grey,
Ink,
Magenta,
Orange,
Purple,
Red,
Teal,
Yellow
};

// Marker schema, with a non-empty list of locations where markers should be
// shown.
Expand Down Expand Up @@ -854,12 +867,28 @@ class MarkerSchema {
return *this;
}

// Markers can be shown as timeline tracks.

MarkerSchema& AddChart(std::string aKey, GraphType aType) {
mGraphs.emplace_back(GraphData{std::move(aKey), aType, mozilla::Nothing{}});
return *this;
}

MarkerSchema& AddChartColor(std::string aKey, GraphType aType,
GraphColor aColor) {
mGraphs.emplace_back(
GraphData{std::move(aKey), aType, mozilla::Some(aColor)});
return *this;
}

// Internal streaming function.
MFBT_API void Stream(JSONWriter& aWriter, const Span<const char>& aName) &&;

private:
MFBT_API static Span<const char> LocationToStringSpan(Location aLocation);
MFBT_API static Span<const char> FormatToStringSpan(Format aFormat);
MFBT_API static Span<const char> GraphTypeToStringSpan(GraphType aType);
MFBT_API static Span<const char> GraphColorToStringSpan(GraphColor aColor);

// List of marker display locations. Empty for SpecialFrontendLocation.
std::vector<Location> mLocations;
Expand All @@ -883,6 +912,13 @@ class MarkerSchema {
using DataRowVector = std::vector<DataRow>;

DataRowVector mData;

struct GraphData {
std::string mKey;
GraphType mType;
mozilla::Maybe<GraphColor> mColor;
};
std::vector<GraphData> mGraphs;
};

} // namespace mozilla
Expand Down
6 changes: 5 additions & 1 deletion mozglue/baseprofiler/public/BaseProfilerState.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,11 @@ class MOZ_RAII AutoProfilerStats {
MACRO(20, "processcpu", ProcessCPU, \
"Sample the CPU utilization of each process") \
\
MACRO(21, "power", Power, POWER_HELP)
MACRO(21, "power", Power, POWER_HELP) \
\
MACRO(22, "cpufreq", CPUFrequency, \
"Record the clock frequency of " \
"every CPU core for every profiler sample.")
// *** Synchronize with lists in ProfilerState.h and geckoProfiler.json ***

struct ProfilerFeature {
Expand Down
3 changes: 2 additions & 1 deletion toolkit/components/extensions/schemas/geckoProfiler.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@
"unregisteredthreads",
"processcpu",
"power",
"responsiveness"
"responsiveness",
"cpufreq"
]
},
{
Expand Down
73 changes: 73 additions & 0 deletions tools/profiler/core/ProfilerCPUFreq-linux-android.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/* 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 "ProfilerCPUFreq.h"
#include "nsThreadUtils.h"
#include <fcntl.h>
#include <unistd.h>

ProfilerCPUFreq::ProfilerCPUFreq() {
if (!mCPUCounters.resize(mozilla::GetNumberOfProcessors())) {
NS_WARNING("failing to resize the mCPUCounters vector");
return;
}

for (unsigned cpuId = 0; cpuId < mCPUCounters.length(); ++cpuId) {
const size_t buf_sz = 64;
char buf[buf_sz];
int rv = sprintf(
buf, "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq", cpuId);
if (NS_WARN_IF(rv < 0)) {
continue;
}

int fd = open(buf, O_RDONLY);
if (NS_WARN_IF(!fd)) {
continue;
}

mCPUCounters[cpuId].fd = fd;
}
}

ProfilerCPUFreq::~ProfilerCPUFreq() {
for (CPUCounterInfo& CPUCounter : mCPUCounters) {
int fd = CPUCounter.fd;
if (NS_WARN_IF(!fd)) {
continue;
}
close(fd);
CPUCounter.fd = 0;
}
}

uint32_t ProfilerCPUFreq::GetCPUSpeedMHz(unsigned cpuId) {
MOZ_ASSERT(cpuId < mCPUCounters.length());
int fd = mCPUCounters[cpuId].fd;
if (NS_WARN_IF(!fd)) {
return 0;
}

long rv = lseek(fd, 0, SEEK_SET);
if (NS_WARN_IF(rv < 0)) {
return 0;
}

const size_t buf_sz = 64;
char buf[buf_sz];
rv = read(fd, buf, buf_sz);
if (NS_WARN_IF(rv < 0)) {
return 0;
}

int cpufreq = 0;
rv = sscanf(buf, "%u", &cpufreq);
if (NS_WARN_IF(rv != 1)) {
return 0;
}

// Convert kHz to MHz, rounding to the nearst 10Mhz, to ignore tiny
// variations that are likely due to rounding errors.
return uint32_t(cpufreq / 10000) * 10;
}
Loading

0 comments on commit bdaa341

Please sign in to comment.