diff --git a/DevHome.sln b/DevHome.sln
index b842116a53..bb03d89b0a 100644
--- a/DevHome.sln
+++ b/DevHome.sln
@@ -80,6 +80,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DevHome.QuietBackgroundProc
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DevHome.QuietBackgroundProcesses.Common", "tools\QuietBackgroundProcesses\DevHome.QuietBackgroundProcesses.Common\DevHome.QuietBackgroundProcesses.Common.vcxproj", "{4B370E2F-FB1D-4887-90BF-3B72517485CE}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevHome.QuietBackgroundProcesses.UI", "tools\QuietBackgroundProcesses\DevHome.QuietBackgroundProcesses.UI\DevHome.QuietBackgroundProcesses.UI.csproj", "{1477F3EA-A9F6-4B4F-82F4-C2427F57EBEE}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DevHome.QuietBackgroundProcesses.PerformanceRecorderEngine", "tools\QuietBackgroundProcesses\DevHome.QuietBackgroundProcesses.PerformanceRecorderEngine\DevHome.QuietBackgroundProcesses.PerformanceRecorderEngine.vcxproj", "{AF5A7FA0-E3E8-44C8-8830-31DD08F583E8}"
+EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", "{DCAF188B-60C3-4EDB-8049-BAA927FBCD7D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SampleTool", "SampleTool", "{E7C94F61-D6CF-464D-8D50-210488AF7A50}"
@@ -516,6 +520,22 @@ Global
{4B370E2F-FB1D-4887-90BF-3B72517485CE}.Release|x64.Build.0 = Release|x64
{4B370E2F-FB1D-4887-90BF-3B72517485CE}.Release|x86.ActiveCfg = Release|Win32
{4B370E2F-FB1D-4887-90BF-3B72517485CE}.Release|x86.Build.0 = Release|Win32
+ {1477F3EA-A9F6-4B4F-82F4-C2427F57EBEE}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {1477F3EA-A9F6-4B4F-82F4-C2427F57EBEE}.Debug|Any CPU.Build.0 = Debug|x64
+ {1477F3EA-A9F6-4B4F-82F4-C2427F57EBEE}.Debug|arm64.ActiveCfg = Debug|arm64
+ {1477F3EA-A9F6-4B4F-82F4-C2427F57EBEE}.Debug|arm64.Build.0 = Debug|arm64
+ {1477F3EA-A9F6-4B4F-82F4-C2427F57EBEE}.Debug|x64.ActiveCfg = Debug|x64
+ {1477F3EA-A9F6-4B4F-82F4-C2427F57EBEE}.Debug|x64.Build.0 = Debug|x64
+ {1477F3EA-A9F6-4B4F-82F4-C2427F57EBEE}.Debug|x86.ActiveCfg = Debug|x86
+ {1477F3EA-A9F6-4B4F-82F4-C2427F57EBEE}.Debug|x86.Build.0 = Debug|x86
+ {1477F3EA-A9F6-4B4F-82F4-C2427F57EBEE}.Release|Any CPU.ActiveCfg = Release|x64
+ {1477F3EA-A9F6-4B4F-82F4-C2427F57EBEE}.Release|Any CPU.Build.0 = Release|x64
+ {1477F3EA-A9F6-4B4F-82F4-C2427F57EBEE}.Release|arm64.ActiveCfg = Release|arm64
+ {1477F3EA-A9F6-4B4F-82F4-C2427F57EBEE}.Release|arm64.Build.0 = Release|arm64
+ {1477F3EA-A9F6-4B4F-82F4-C2427F57EBEE}.Release|x64.ActiveCfg = Release|x64
+ {1477F3EA-A9F6-4B4F-82F4-C2427F57EBEE}.Release|x64.Build.0 = Release|x64
+ {1477F3EA-A9F6-4B4F-82F4-C2427F57EBEE}.Release|x86.ActiveCfg = Release|x86
+ {1477F3EA-A9F6-4B4F-82F4-C2427F57EBEE}.Release|x86.Build.0 = Release|x86
{CFD8A90D-8B6D-4ED6-BA35-FF894BEB46C0}.Debug|Any CPU.ActiveCfg = Debug|x64
{CFD8A90D-8B6D-4ED6-BA35-FF894BEB46C0}.Debug|Any CPU.Build.0 = Debug|x64
{CFD8A90D-8B6D-4ED6-BA35-FF894BEB46C0}.Debug|arm64.ActiveCfg = Debug|ARM64
@@ -740,6 +760,22 @@ Global
{AF527EA4-6A24-4BD6-BC6E-A5863DC3489C}.Release|x64.Build.0 = Release|x64
{AF527EA4-6A24-4BD6-BC6E-A5863DC3489C}.Release|x86.ActiveCfg = Release|x86
{AF527EA4-6A24-4BD6-BC6E-A5863DC3489C}.Release|x86.Build.0 = Release|x86
+ {AF5A7FA0-E3E8-44C8-8830-31DD08F583E8}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {AF5A7FA0-E3E8-44C8-8830-31DD08F583E8}.Debug|Any CPU.Build.0 = Debug|x64
+ {AF5A7FA0-E3E8-44C8-8830-31DD08F583E8}.Debug|arm64.ActiveCfg = Debug|ARM64
+ {AF5A7FA0-E3E8-44C8-8830-31DD08F583E8}.Debug|arm64.Build.0 = Debug|ARM64
+ {AF5A7FA0-E3E8-44C8-8830-31DD08F583E8}.Debug|x64.ActiveCfg = Debug|x64
+ {AF5A7FA0-E3E8-44C8-8830-31DD08F583E8}.Debug|x64.Build.0 = Debug|x64
+ {AF5A7FA0-E3E8-44C8-8830-31DD08F583E8}.Debug|x86.ActiveCfg = Debug|Win32
+ {AF5A7FA0-E3E8-44C8-8830-31DD08F583E8}.Debug|x86.Build.0 = Debug|Win32
+ {AF5A7FA0-E3E8-44C8-8830-31DD08F583E8}.Release|Any CPU.ActiveCfg = Release|x64
+ {AF5A7FA0-E3E8-44C8-8830-31DD08F583E8}.Release|Any CPU.Build.0 = Release|x64
+ {AF5A7FA0-E3E8-44C8-8830-31DD08F583E8}.Release|arm64.ActiveCfg = Release|ARM64
+ {AF5A7FA0-E3E8-44C8-8830-31DD08F583E8}.Release|arm64.Build.0 = Release|ARM64
+ {AF5A7FA0-E3E8-44C8-8830-31DD08F583E8}.Release|x64.ActiveCfg = Release|x64
+ {AF5A7FA0-E3E8-44C8-8830-31DD08F583E8}.Release|x64.Build.0 = Release|x64
+ {AF5A7FA0-E3E8-44C8-8830-31DD08F583E8}.Release|x86.ActiveCfg = Release|Win32
+ {AF5A7FA0-E3E8-44C8-8830-31DD08F583E8}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -767,6 +803,8 @@ Global
{092AC740-DA01-4872-8E93-B9557DAD6BE5} = {D04CD3A1-0B45-4CB3-925F-204F5F6AE2D8}
{80805B43-CE75-4C6E-92F8-F385C1039E53} = {D04CD3A1-0B45-4CB3-925F-204F5F6AE2D8}
{4B370E2F-FB1D-4887-90BF-3B72517485CE} = {D04CD3A1-0B45-4CB3-925F-204F5F6AE2D8}
+ {1477F3EA-A9F6-4B4F-82F4-C2427F57EBEE} = {D04CD3A1-0B45-4CB3-925F-204F5F6AE2D8}
+ {AF5A7FA0-E3E8-44C8-8830-31DD08F583E8} = {D04CD3A1-0B45-4CB3-925F-204F5F6AE2D8}
{E7C94F61-D6CF-464D-8D50-210488AF7A50} = {A972EC5B-FC61-4964-A6FF-F9633EB75DFD}
{8FC9A04E-1FFD-42BA-B304-D1FA964D99CE} = {A972EC5B-FC61-4964-A6FF-F9633EB75DFD}
{CFD8A90D-8B6D-4ED6-BA35-FF894BEB46C0} = {8FC9A04E-1FFD-42BA-B304-D1FA964D99CE}
diff --git a/settings/DevHome.Settings/Strings/en-us/Resources.resw b/settings/DevHome.Settings/Strings/en-us/Resources.resw
index d73581bd82..b078587296 100644
--- a/settings/DevHome.Settings/Strings/en-us/Resources.resw
+++ b/settings/DevHome.Settings/Strings/en-us/Resources.resw
@@ -559,12 +559,12 @@
Title text for the Environments configuration feature.
- Quiet background processes experiment
- Name of experimental feature ()'Quiet Background Processes') on the 'Settings -> Experiments' page where you enable it.
+ Quiet background processes
+ Name of experimental feature 'Quiet background processes' on the 'Settings -> Experiments' page where you enable it.
- Silence and track background processes that may hinder device performance
- Inline description of the Quiet Background Processes experimental feature on the 'Settings -> Experiments' page where you enable it.
+ Quiet background processes allows you to free up resources while developing
+ Inline description of the Quiet background processes experimental feature on the 'Settings -> Experiments' page where you enable it.
Create a local or cloud machine from Dev Home
diff --git a/src/DevHome.csproj b/src/DevHome.csproj
index d749292754..039b6a841d 100644
--- a/src/DevHome.csproj
+++ b/src/DevHome.csproj
@@ -119,7 +119,7 @@
true
-
+
<_DevHomeInternal_CppPlatform>$(Platform)
<_DevHomeInternal_CppPlatform Condition="'$(Platform)' == 'x86'">Win32
@@ -138,6 +138,9 @@
PreserveNewest
+
+ PreserveNewest
+
diff --git a/src/NavConfig.jsonc b/src/NavConfig.jsonc
index 8aa0a372e2..9689941e21 100644
--- a/src/NavConfig.jsonc
+++ b/src/NavConfig.jsonc
@@ -86,18 +86,18 @@
"buildTypeOverrides": [
{
"buildType": "dev",
- "enabledByDefault": false,
+ "enabledByDefault": true,
"visible": true
},
{
"buildType": "canary",
- "enabledByDefault": false,
- "visible": false
+ "enabledByDefault": true,
+ "visible": true
},
{
"buildType": "stable",
"enabledByDefault": false,
- "visible": false
+ "visible": true
}
]
},
diff --git a/src/Package.appxmanifest b/src/Package.appxmanifest
index 3e44bb0bc3..0e9dc3da0a 100644
--- a/src/Package.appxmanifest
+++ b/src/Package.appxmanifest
@@ -22,6 +22,7 @@
DevHome.QuietBackgroundProcesses.ElevatedServer.exe
singleInstance
+
diff --git a/tools/Customization/DevHome.Customization/DevHome.Customization.csproj b/tools/Customization/DevHome.Customization/DevHome.Customization.csproj
index be0924d636..d06a565d6b 100644
--- a/tools/Customization/DevHome.Customization/DevHome.Customization.csproj
+++ b/tools/Customization/DevHome.Customization/DevHome.Customization.csproj
@@ -24,9 +24,9 @@
+
-
@@ -40,7 +40,6 @@
-
@@ -60,9 +59,6 @@
MSBuild:Compile
$(DefaultXamlRuntime)
-
- $(DefaultXamlRuntime)
-
diff --git a/tools/Customization/DevHome.Customization/Extensions/ServiceExtensions.cs b/tools/Customization/DevHome.Customization/Extensions/ServiceExtensions.cs
index e3788796c5..1372f2b018 100644
--- a/tools/Customization/DevHome.Customization/Extensions/ServiceExtensions.cs
+++ b/tools/Customization/DevHome.Customization/Extensions/ServiceExtensions.cs
@@ -4,6 +4,7 @@
using DevHome.Customization.ViewModels;
using DevHome.Customization.ViewModels.DevDriveInsights;
using DevHome.Customization.Views;
+using DevHome.QuietBackgroundProcesses.UI.ViewModels;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
@@ -19,7 +20,9 @@ public static IServiceCollection AddWindowsCustomization(this IServiceCollection
services.AddSingleton();
services.AddTransient();
- services.AddSingleton(sp => (cacheLocation, environmentVariable, exampleDevDriveLocation, existingDevDriveLetters) => ActivatorUtilities.CreateInstance(sp, cacheLocation, environmentVariable, exampleDevDriveLocation, existingDevDriveLetters));
+ services.AddSingleton(sp =>
+ (cacheLocation, environmentVariable, exampleDevDriveLocation, existingDevDriveLetters) =>
+ ActivatorUtilities.CreateInstance(sp, cacheLocation, environmentVariable, exampleDevDriveLocation, existingDevDriveLetters));
services.AddSingleton();
services.AddTransient();
diff --git a/tools/Customization/DevHome.Customization/Strings/en-us/Resources.resw b/tools/Customization/DevHome.Customization/Strings/en-us/Resources.resw
index 8c4f0d8428..ce4d1ddcbd 100644
--- a/tools/Customization/DevHome.Customization/Strings/en-us/Resources.resw
+++ b/tools/Customization/DevHome.Customization/Strings/en-us/Resources.resw
@@ -249,56 +249,4 @@
Windows developer settings
The header for the Windows developer settings card
-
-
-
- Start session
- Button that starts a quiet background session
-
-
- Stop session
- Button that stops a quiet background session
-
-
- Silence and track background processes that may hinder device performance
- Description of the Quiet Background Processes feature
-
-
- Quiet background processes
- Inline title of the Quiet Background Processes feature
-
-
- This feature can be activated for 2 hours.
- A description of the Quiet Background Processes time window
-
-
- Link to docs
- Link that launches documentation
-
-
- Provide feedback
- Link that launches feedback
-
-
- Related links
- Label for the doc links
-
-
-
-
- Feature not supported on this version of Windows
- Indicates that this OS isn't new enough to support the feature
-
-
- Session Error
- Something went wrong when running the session
-
-
- Session ended
- The quiet session was cancelled or the time expired
-
-
- Unable to cancel session
- Something went wrong when cancelling the session
-
\ No newline at end of file
diff --git a/tools/Customization/DevHome.Customization/Views/MainPageView.xaml b/tools/Customization/DevHome.Customization/Views/MainPageView.xaml
index cb805cb118..9e957a96f2 100644
--- a/tools/Customization/DevHome.Customization/Views/MainPageView.xaml
+++ b/tools/Customization/DevHome.Customization/Views/MainPageView.xaml
@@ -6,6 +6,7 @@
xmlns:converters="using:CommunityToolkit.WinUI.Converters"
xmlns:ui="using:CommunityToolkit.WinUI"
xmlns:views="using:DevHome.Customization.Views"
+ xmlns:quietviews="using:DevHome.QuietBackgroundProcesses.UI.Views"
Loaded="UserControl_Loaded">
@@ -39,7 +40,7 @@
-
+
diff --git a/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.Common/Common.h b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.Common/Common.h
new file mode 100644
index 0000000000..e92ab65a15
--- /dev/null
+++ b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.Common/Common.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include
+
+// Get temporary path for performance data
+inline std::filesystem::path GetTemporaryPerformanceDataPath()
+{
+ auto tempDirectory = std::filesystem::temp_directory_path();
+ return std::filesystem::path(tempDirectory) / L"DevHome.QuietMode.PerformanceData.dat";
+}
diff --git a/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.Common/DevHome.QuietBackgroundProcesses.Common.vcxproj b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.Common/DevHome.QuietBackgroundProcesses.Common.vcxproj
index 54ea440e67..b790816874 100644
--- a/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.Common/DevHome.QuietBackgroundProcesses.Common.vcxproj
+++ b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.Common/DevHome.QuietBackgroundProcesses.Common.vcxproj
@@ -145,6 +145,7 @@
+
diff --git a/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.Common/DevHome.QuietBackgroundProcesses.idl b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.Common/DevHome.QuietBackgroundProcesses.idl
index c64cb8d568..26e7ead7da 100644
--- a/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.Common/DevHome.QuietBackgroundProcesses.idl
+++ b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.Common/DevHome.QuietBackgroundProcesses.idl
@@ -2,15 +2,66 @@
// Licensed under the MIT License.
import "inspectable.idl";
+import "windows.foundation.idl";
namespace DevHome.QuietBackgroundProcesses
{
+ // Performance Engine types
+ enum ProcessCategory
+ {
+ Unknown,
+ User,
+ System,
+ Developer,
+ Background,
+ };
+
+ [default_interface]
+ runtimeclass ProcessRow
+ {
+ UInt32 Pid { get; };
+ String Name { get; };
+ String PackageFullName { get; };
+ String Aumid { get; };
+ String Path { get; };
+ ProcessCategory Category { get; };
+ Windows.Foundation.DateTime CreateTime { get; };
+ Windows.Foundation.DateTime ExitTime { get; };
+
+ UInt64 SampleCount { get; };
+ Double PercentCumulative { get; };
+ Double VarianceCumulative { get; };
+ Double Sigma4Cumulative { get; };
+ Double MaxPercent { get; };
+ UInt32 SamplesAboveThreshold { get; };
+
+ UInt64 TotalCpuTimeInMicroseconds { get; };
+ }
+
+ [default_interface]
+ runtimeclass ProcessPerformanceTable
+ {
+ ProcessRow[] Rows { get; };
+ }
+
+ [default_interface]
+ runtimeclass PerformanceRecorderEngine
+ {
+ static ProcessPerformanceTable TryGetLastPerformanceRecording();
+
+ PerformanceRecorderEngine();
+ void Start(Windows.Foundation.TimeSpan periodInMs);
+ ProcessPerformanceTable Stop();
+ }
+
+ // Quiet background process types
[default_interface]
runtimeclass QuietBackgroundProcessesSession
{
static QuietBackgroundProcessesSession GetSingleton();
+
Int64 Start();
- void Stop();
+ ProcessPerformanceTable Stop();
Boolean IsActive { get; };
Int64 TimeLeftInSeconds { get; };
}
@@ -21,5 +72,7 @@ namespace DevHome.QuietBackgroundProcesses
static Boolean IsFeaturePresent();
static QuietBackgroundProcessesSession GetSession();
static QuietBackgroundProcessesSession TryGetSession();
+ static Boolean HasLastPerformanceRecording();
+ static ProcessPerformanceTable TryGetLastPerformanceRecording();
}
}
diff --git a/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/DevHome.QuietBackgroundProcesses.ElevatedServer.vcxproj b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/DevHome.QuietBackgroundProcesses.ElevatedServer.vcxproj
index 001ddcadaa..b2a6ac18a7 100644
--- a/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/DevHome.QuietBackgroundProcesses.ElevatedServer.vcxproj
+++ b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/DevHome.QuietBackgroundProcesses.ElevatedServer.vcxproj
@@ -112,8 +112,8 @@
- stdcpp17
- $(ProjectDir)..\DevHome.QuietBackgroundProcesses.Common\;$(ProjectDir)..\DevHome.QuietBackgroundProcesses.Common\$(GeneratedFilesDir)midl;%(AdditionalIncludeDirectories)
+ stdcpp20
+ $(ProjectDir)..\DevHome.QuietBackgroundProcesses.Common\;$(ProjectDir)..\DevHome.QuietBackgroundProcesses.Common\$(GeneratedFilesDir)midl;$(ProjectDir)..\DevHome.QuietBackgroundProcesses.PerformanceRecorderEngine\;%(AdditionalIncludeDirectories)
onecore.lib;%(AdditionalDependencies)
@@ -135,16 +135,19 @@
+
+
Create
+
@@ -158,6 +161,9 @@
{4b370e2f-fb1d-4887-90bf-3b72517485ce}
+
+ {af5a7fa0-e3e8-44c8-8830-31dd08f583e8}
+
diff --git a/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/Helpers.cpp b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/Helpers.cpp
new file mode 100644
index 0000000000..1fe81e8cfb
--- /dev/null
+++ b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/Helpers.cpp
@@ -0,0 +1,46 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include "PerformanceRecorderEngine.h"
+#include "Helpers.h"
+
+void WritePerformanceDataToDisk(_In_ PCWSTR path, const std::span& data)
+{
+ std::ofstream file(path, std::ios::binary);
+ if (!file.is_open())
+ {
+ // Handle error
+ return;
+ }
+
+ for (const auto& item : data)
+ {
+ file.write(reinterpret_cast(&item), sizeof(ProcessPerformanceSummary));
+ }
+
+ file.close();
+}
+
+std::vector ReadPerformanceDataFromDisk(_In_ PCWSTR path)
+{
+ std::vector data;
+
+ std::ifstream file(path, std::ios::binary);
+ THROW_WIN32_IF(ERROR_SHARING_VIOLATION, !file.is_open());
+
+ ProcessPerformanceSummary item;
+ while (file.read(reinterpret_cast(&item), sizeof(ProcessPerformanceSummary)))
+ {
+ data.push_back(item);
+ }
+
+ file.close();
+ return data;
+}
diff --git a/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/Helpers.h b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/Helpers.h
new file mode 100644
index 0000000000..9045c9ae2f
--- /dev/null
+++ b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/Helpers.h
@@ -0,0 +1,43 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include
+#include
+
+#include
+#include
+
+#include "DevHome.QuietBackgroundProcesses.h"
+#include "PerformanceRecorderEngine.h"
+
+struct com_ptr_deleter
+{
+ template
+ void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T p) const
+ {
+ if (p)
+ {
+ p.reset();
+ }
+ }
+};
+
+template
+using unique_comptr_array = wil::unique_any_array_ptr, ArrayDeleter, com_ptr_deleter>;
+
+template
+unique_comptr_array make_unique_comptr_array(size_t numOfElements)
+{
+ auto list = unique_comptr_array(reinterpret_cast*>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, numOfElements * sizeof(wil::com_ptr_nothrow))), numOfElements);
+ THROW_IF_NULL_ALLOC(list.get());
+ return list;
+}
+
+// Create a performance recorder engine
+wil::com_ptr MakePerformanceRecorderEngine();
+
+// Read/write the performance data to/from disk
+void WritePerformanceDataToDisk(_In_ PCWSTR path, const std::span& data);
+std::vector ReadPerformanceDataFromDisk(_In_ PCWSTR path);
diff --git a/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/PerformanceRecorderEngineWinrt.cpp b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/PerformanceRecorderEngineWinrt.cpp
new file mode 100644
index 0000000000..df66eff75a
--- /dev/null
+++ b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/PerformanceRecorderEngineWinrt.cpp
@@ -0,0 +1,346 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "Common.h"
+#include "TimedQuietSession.h"
+#include "DevHome.QuietBackgroundProcesses.h"
+#include "PerformanceRecorderEngine.h"
+#include "Helpers.h"
+
+
+namespace ABI::DevHome::QuietBackgroundProcesses
+{
+ class ProcessRow :
+ public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags,
+ IProcessRow,
+ Microsoft::WRL::FtmBase>
+ {
+ InspectableClass(RuntimeClass_DevHome_QuietBackgroundProcesses_ProcessRow, BaseTrust);
+
+ public:
+ STDMETHODIMP RuntimeClassInitialize(ProcessPerformanceSummary summary) noexcept
+ {
+ m_summary = summary;
+ return S_OK;
+ }
+
+ STDMETHODIMP get_Pid(unsigned int* value) noexcept override
+ try
+ {
+ *value = m_summary.pid;
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ STDMETHODIMP get_Name(HSTRING* value) noexcept override
+ try
+ {
+ Microsoft::WRL::Wrappers::HString str;
+ str.Set(m_summary.name);
+ *value = str.Detach();
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ STDMETHODIMP get_PackageFullName(HSTRING* value) noexcept override
+ try
+ {
+ Microsoft::WRL::Wrappers::HString str;
+ str.Set(m_summary.packageFullName);
+ *value = str.Detach();
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ STDMETHODIMP get_Aumid(HSTRING* value) noexcept override
+ try
+ {
+ Microsoft::WRL::Wrappers::HString str;
+ str.Set(m_summary.aumid);
+ *value = str.Detach();
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ STDMETHODIMP get_Path(HSTRING* value) noexcept override
+ try
+ {
+ Microsoft::WRL::Wrappers::HString str;
+ str.Set(m_summary.path);
+ *value = str.Detach();
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ STDMETHODIMP get_Category(ABI::DevHome::QuietBackgroundProcesses::ProcessCategory* value) noexcept override
+ try
+ {
+ *value = static_cast(m_summary.category);
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ STDMETHODIMP get_CreateTime(struct ABI::Windows::Foundation::DateTime* value) noexcept override
+ try
+ {
+ INT64 time = m_summary.createTime.dwLowDateTime + ((UINT64)m_summary.createTime.dwHighDateTime << 32);
+ *value = ABI::Windows::Foundation::DateTime{ time };
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ STDMETHODIMP get_ExitTime(struct ABI::Windows::Foundation::DateTime* value) noexcept override
+ try
+ {
+ INT64 time = m_summary.exitTime.dwLowDateTime + ((UINT64)m_summary.exitTime.dwHighDateTime << 32);
+ *value = ABI::Windows::Foundation::DateTime{ time };
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ STDMETHODIMP get_SampleCount(unsigned __int64* value) noexcept override
+ try
+ {
+ *value = m_summary.sampleCount;
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ STDMETHODIMP get_PercentCumulative(double* value) noexcept override
+ try
+ {
+ *value = m_summary.percentCumulative;
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ STDMETHODIMP get_VarianceCumulative(double* value) noexcept override
+ try
+ {
+ *value = m_summary.varianceCumulative;
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ STDMETHODIMP get_Sigma4Cumulative(double* value) noexcept override
+ try
+ {
+ *value = m_summary.sigma4Cumulative;
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ STDMETHODIMP get_MaxPercent(double* value) noexcept override
+ try
+ {
+ *value = m_summary.maxPercent;
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ STDMETHODIMP get_SamplesAboveThreshold(unsigned __int32* value) noexcept override
+ try
+ {
+ *value = m_summary.samplesAboveThreshold;
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ STDMETHODIMP get_TotalCpuTimeInMicroseconds(unsigned __int64* value) noexcept override
+ try
+ {
+ *value = m_summary.totalCpuTimeInMicroseconds;
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ private:
+ ProcessPerformanceSummary m_summary;
+ };
+}
+
+namespace ABI::DevHome::QuietBackgroundProcesses
+{
+ class ProcessPerformanceTable :
+ public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags,
+ IProcessPerformanceTable,
+ Microsoft::WRL::FtmBase>
+ {
+ InspectableClass(RuntimeClass_DevHome_QuietBackgroundProcesses_ProcessPerformanceTable, BaseTrust);
+
+ public:
+ STDMETHODIMP RuntimeClassInitialize(unique_process_utilization_monitoring_thread context) noexcept
+ {
+ m_context = std::move(context);
+ return S_OK;
+ }
+
+ STDMETHODIMP get_Rows(unsigned int* valueLength, ABI::DevHome::QuietBackgroundProcesses::IProcessRow*** value) noexcept override
+ try
+ {
+ std::span span;
+ wil::unique_cotaskmem_array_ptr summariesCoarray;
+ std::vector summariesVector;
+
+ if (m_context)
+ {
+ // We have a live context, read performance data from it
+ THROW_IF_FAILED(GetMonitoringProcessUtilization(m_context.get(), summariesCoarray.addressof(), summariesCoarray.size_address()));
+
+ // Make span from cotaskmem_array
+ span = std::span{ summariesCoarray.get(), summariesCoarray.size() };
+ }
+ else
+ {
+ // We don't have a live context. Let's try to read performance data from disk.
+ auto performanceDataFile = GetTemporaryPerformanceDataPath();
+ THROW_HR_IF(E_FAIL, !std::filesystem::exists(performanceDataFile));
+
+ // Make span from vector
+ summariesVector = ReadPerformanceDataFromDisk(performanceDataFile.c_str());
+ span = std::span{ summariesVector };
+ }
+
+ // Create IProcessRow entries
+ auto list = make_unique_comptr_array(span.size());
+ for (uint32_t i = 0; i < span.size(); i++)
+ {
+ auto& summary = span[i];
+ wil::com_ptr row;
+ THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&row, summary));
+ list[i] = std::move(row);
+ }
+ *valueLength = static_cast(span.size());
+ *value = (ABI::DevHome::QuietBackgroundProcesses::IProcessRow**)list.release();
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ private:
+ unique_process_utilization_monitoring_thread m_context;
+ };
+}
+
+namespace ABI::DevHome::QuietBackgroundProcesses
+{
+ class PerformanceRecorderEngine :
+ public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags,
+ IPerformanceRecorderEngine,
+ Microsoft::WRL::FtmBase>
+ {
+ InspectableClass(RuntimeClass_DevHome_QuietBackgroundProcesses_PerformanceRecorderEngine, BaseTrust);
+
+ public:
+ STDMETHODIMP RuntimeClassInitialize() noexcept
+ {
+ return S_OK;
+ }
+
+ // IPerformanceRecorderEngine
+ STDMETHODIMP Start(ABI::Windows::Foundation::TimeSpan samplingPeriod) noexcept override
+ try
+ {
+ // Convert TimeSpan from 100ns to milliseconds
+ auto periodInMs = static_cast(samplingPeriod.Duration / 10000);
+ THROW_IF_FAILED(StartMonitoringProcessUtilization(periodInMs, &m_context));
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ STDMETHODIMP Stop(ABI::DevHome::QuietBackgroundProcesses::IProcessPerformanceTable** result) noexcept override
+ try
+ {
+ THROW_IF_FAILED(StopMonitoringProcessUtilization(m_context.get()));
+
+ if (result)
+ {
+ wil::com_ptr performanceTable;
+ THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&performanceTable, std::move(m_context)));
+ *result = performanceTable.detach();
+ }
+ else
+ {
+ // No one (no client) is currently asking for the performance data (presumably Dev Home is closed) so write it to disk
+ wil::unique_cotaskmem_array_ptr summaries;
+ THROW_IF_FAILED(GetMonitoringProcessUtilization(m_context.get(), summaries.addressof(), summaries.size_address()));
+
+ // Write the performance .csv data to disk
+ std::span data(summaries.get(), summaries.size());
+ try
+ {
+ auto performanceDataFile = GetTemporaryPerformanceDataPath();
+ WritePerformanceDataToDisk(performanceDataFile.c_str(), data);
+ }
+ CATCH_LOG();
+
+ // Destroy the performance engine instance
+ m_context.reset();
+ }
+
+ return S_OK;
+ }
+ CATCH_RETURN()
+
+ private:
+ unique_process_utilization_monitoring_thread m_context;
+ };
+
+ class PerformanceRecorderEngineStatics WrlFinal :
+ public Microsoft::WRL::AgileActivationFactory<
+ Microsoft::WRL::Implements>
+ {
+ InspectableClassStatic(RuntimeClass_DevHome_QuietBackgroundProcesses_PerformanceRecorderEngine, BaseTrust);
+
+ public:
+ STDMETHODIMP ActivateInstance(_COM_Outptr_ IInspectable**) noexcept
+ {
+ // Disallow activation - must use GetSingleton()
+ return E_NOTIMPL;
+ }
+
+ // IPerformanceRecorderEngineStatics
+ STDMETHODIMP TryGetLastPerformanceRecording(_COM_Outptr_ ABI::DevHome::QuietBackgroundProcesses::IProcessPerformanceTable** result) noexcept override
+ try
+ {
+ // Reconstruct a perform table from disk (passing nullptr for context)
+ wil::com_ptr performanceTable;
+ THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&performanceTable, nullptr));
+ *result = performanceTable.detach();
+
+ return S_OK;
+ }
+ CATCH_RETURN()
+ };
+
+ ActivatableClassWithFactory(PerformanceRecorderEngine, PerformanceRecorderEngineStatics);
+}
+
+wil::com_ptr MakePerformanceRecorderEngine()
+{
+ using namespace ABI::DevHome::QuietBackgroundProcesses;
+ wil::com_ptr result;
+ THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&result));
+ return result;
+}
diff --git a/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/QuietBackgroundProcessesSession.cpp b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/QuietBackgroundProcessesSession.cpp
index fbd08ff74a..f0483e7b73 100644
--- a/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/QuietBackgroundProcessesSession.cpp
+++ b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/QuietBackgroundProcessesSession.cpp
@@ -49,7 +49,7 @@ namespace ABI::DevHome::QuietBackgroundProcesses
// Stop and discard the previous timer
if (g_activeTimer)
{
- g_activeTimer->Cancel();
+ g_activeTimer->Cancel(nullptr);
}
std::chrono::seconds duration = DEFAULT_QUIET_DURATION;
@@ -67,14 +67,16 @@ namespace ABI::DevHome::QuietBackgroundProcesses
}
CATCH_RETURN()
- STDMETHODIMP Stop() noexcept override try
+ STDMETHODIMP Stop(ABI::DevHome::QuietBackgroundProcesses::IProcessPerformanceTable** result) noexcept override
+ try
{
auto lock = std::scoped_lock(g_mutex);
+ *result = nullptr;
// Turn off quiet mode and cancel timer
if (g_activeTimer)
{
- g_activeTimer->Cancel();
+ g_activeTimer->Cancel(result);
g_activeTimer.reset();
}
diff --git a/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/TimedQuietSession.h b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/TimedQuietSession.h
index 3dcc157e69..7e809cf045 100644
--- a/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/TimedQuietSession.h
+++ b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.ElevatedServer/TimedQuietSession.h
@@ -20,6 +20,7 @@
#include "Timer.h"
#include "QuietState.h"
+#include "Helpers.h"
using ElevatedServerReference = wrl_server_process_ref;
@@ -39,7 +40,7 @@ struct UnelevatedServerReference
};
-// TimedQuietSession is a 2 hour "Quiet Background Processes" timed window that disables quiet
+// TimedQuietSession is a 2 hour "Quiet background processes" timed window that disables quiet
// mode when the timer expires or when explicitly cancelled. It keeps also keeps the server alive.
//
// TimedQuietSession maintains,
@@ -88,6 +89,12 @@ struct TimedQuietSession
// Turn on quiet mode
m_quietState = QuietState::TurnOn();
+
+ // Start performance recorder
+ ABI::Windows::Foundation::TimeSpan samplingPeriod;
+ samplingPeriod.Duration = 1000 * 10000; // 1 second
+ m_performanceRecorderEngine = MakePerformanceRecorderEngine();
+ THROW_IF_FAILED(m_performanceRecorderEngine->Start(samplingPeriod));
}
TimedQuietSession(TimedQuietSession&& other) noexcept = default;
@@ -108,11 +115,11 @@ struct TimedQuietSession
return (bool)m_quietState;
}
- void Cancel()
+ void Cancel(ABI::DevHome::QuietBackgroundProcesses::IProcessPerformanceTable** result)
{
auto lock = std::scoped_lock(m_mutex);
- Deactivate();
+ Deactivate(result);
m_timer->Cancel();
// Destruct timer on another thread because it's destructor is blocking
@@ -124,11 +131,20 @@ struct TimedQuietSession
}
private:
- void Deactivate()
+ void Deactivate(ABI::DevHome::QuietBackgroundProcesses::IProcessPerformanceTable** result = nullptr)
{
// Turn off quiet mode
m_quietState.reset();
+ // Stop the performance recorder
+ if (m_performanceRecorderEngine)
+ {
+ LOG_IF_FAILED(m_performanceRecorderEngine->Stop(result));
+ }
+
+ // Disable performance recorder
+ m_performanceRecorderEngine.reset();
+
// Release lifetime handles to this elevated server and unelevated client server
m_unelevatedServer.reset();
m_elevatedServer.reset();
@@ -139,5 +155,6 @@ struct TimedQuietSession
QuietState::unique_quietwindowclose_call m_quietState{ false };
std::unique_ptr m_timer;
+ wil::com_ptr m_performanceRecorderEngine;
std::mutex m_mutex;
};
diff --git a/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.PerformanceRecorderEngine/DevHome.QuietBackgroundProcesses.PerformanceRecorderEngine.vcxproj b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.PerformanceRecorderEngine/DevHome.QuietBackgroundProcesses.PerformanceRecorderEngine.vcxproj
new file mode 100644
index 0000000000..6f47427600
--- /dev/null
+++ b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.PerformanceRecorderEngine/DevHome.QuietBackgroundProcesses.PerformanceRecorderEngine.vcxproj
@@ -0,0 +1,188 @@
+
+
+
+ C++
+
+
+
+
+
+ Debug
+ ARM64
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ ARM64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {af5a7fa0-e3e8-44c8-8830-31dd08f583e8}
+ DynamicLibrary
+ DevHome_QuietBackgroundProcesses_PerformanceRecorderEngine
+ en-US
+ 14.0
+ false
+ Windows Store
+ 10.0.22621.0
+ 10.0.17134.0
+ 10.0
+ $(CppOutDir)
+
+
+
+ DynamicLibrary
+ true
+ v143
+
+
+ DynamicLibrary
+ true
+ v143
+
+
+ DynamicLibrary
+ true
+ v143
+
+
+ DynamicLibrary
+ false
+ true
+ v143
+
+
+ DynamicLibrary
+ false
+ true
+ v143
+
+
+ DynamicLibrary
+ false
+ true
+ v143
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+ false
+ false
+
+
+
+ Use
+ false
+ stdcpp20
+
+
+ Console
+ false
+ false
+ onecore.lib;onecoreuap_apiset.lib;%(AdditionalDependencies)
+
+
+
+
+ _DEBUG;%(PreprocessorDefinitions)
+ Disabled
+
+
+
+
+ NDEBUG;%(PreprocessorDefinitions)
+
+
+ true
+ true
+
+
+
+
+
+
+
+
+
+ Create
+ Create
+ Create
+ Create
+ Create
+ Create
+
+
+
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
\ No newline at end of file
diff --git a/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.PerformanceRecorderEngine/DevHome.QuietBackgroundProcesses.PerformanceRecorderEngine.vcxproj.filters b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.PerformanceRecorderEngine/DevHome.QuietBackgroundProcesses.PerformanceRecorderEngine.vcxproj.filters
new file mode 100644
index 0000000000..e1d45a4ab6
--- /dev/null
+++ b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.PerformanceRecorderEngine/DevHome.QuietBackgroundProcesses.PerformanceRecorderEngine.vcxproj.filters
@@ -0,0 +1,29 @@
+
+
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {a4747e26-49cd-412b-b5ad-2d499887d0d5}
+
+
+
+
+
+
+
+
+
+
+ inc
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.PerformanceRecorderEngine/PerformanceRecorderEngine.cpp b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.PerformanceRecorderEngine/PerformanceRecorderEngine.cpp
new file mode 100644
index 0000000000..b182a1ff6f
--- /dev/null
+++ b/tools/QuietBackgroundProcesses/DevHome.QuietBackgroundProcesses.PerformanceRecorderEngine/PerformanceRecorderEngine.cpp
@@ -0,0 +1,674 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "pch.h"
+
+#include
+#include
+#include
+#include