Skip to content

Commit

Permalink
MeasureProcess: Remove use of background thread
Browse files Browse the repository at this point in the history
Previously, a background thread woke up to update the process list 250ms. This
can be reduced to a function that caches the results and updates them if 250ms
has elapsed since the last call.

We also now store the process names lowercased in a std::unordered_set to
avoid iterating over a std::vector.

Both of these optimizations should reduce the amount of work done.
  • Loading branch information
poiru committed Aug 28, 2020
1 parent a0c762c commit de137b5
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 90 deletions.
108 changes: 33 additions & 75 deletions Library/MeasureProcess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,99 +9,57 @@
#include "MeasureProcess.h"
#include "ConfigParser.h"
#include "Logger.h"
#include <chrono>
#include "System.h"
#include <TlHelp32.h>

std::vector<std::wstring> MeasureProcess::c_Processes;
std::thread MeasureProcess::c_ProcessThread;
std::promise<void> MeasureProcess::c_ProcessExitSignal;
std::future<void> MeasureProcess::c_ProcessFuture;
std::mutex MeasureProcess::c_ProcessMutex;
UINT MeasureProcess::c_References = 0;
int MeasureProcess::c_UpdateInterval = 250; // milliseconds
std::unordered_set<std::wstring>& GetRunningProcessLowercase() {
static std::unordered_set<std::wstring> s_Processes;
static ULONGLONG s_LastUpdateTickCount = 0;
const ULONGLONG updateInterval = 250; // ms

MeasureProcess::MeasureProcess(Skin* skin, const WCHAR* name) : Measure(skin, name)
{
if (c_References == 0)
ULONGLONG tickCount = System::GetTickCount64();
if (tickCount >= (s_LastUpdateTickCount + updateInterval))
{
std::lock_guard<std::mutex> lock(c_ProcessMutex);
c_ProcessExitSignal = std::promise<void>();
c_ProcessFuture = c_ProcessExitSignal.get_future();
std::thread th(MeasureProcess::MonitorProcesses);
c_ProcessThread = std::move(th);
std::this_thread::sleep_for(std::chrono::milliseconds(25)); // Let the thread get an initial list of processes
s_LastUpdateTickCount = tickCount;

s_Processes = {};
HANDLE thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (thSnapshot != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 processEntry = { sizeof(processEntry) };
if (Process32First(thSnapshot, &processEntry))
{
do
{
std::wstring name = processEntry.szExeFile;
StringUtil::ToLowerCase(name);
s_Processes.insert(name);
} while (Process32Next(thSnapshot, &processEntry));
}
CloseHandle(thSnapshot);
}
}

++c_References;
return s_Processes;
}

MeasureProcess::~MeasureProcess()
MeasureProcess::MeasureProcess(Skin* skin, const WCHAR* name) : Measure(skin, name)
{
--c_References;
if (c_References == 0)
{
std::lock_guard<std::mutex> lock(c_ProcessMutex);
c_ProcessExitSignal.set_value();
if (c_ProcessThread.joinable())
{
c_ProcessThread.join();
}
}

c_Processes.clear();
}
MeasureProcess::~MeasureProcess()
{
}

void MeasureProcess::ReadOptions(ConfigParser& parser, const WCHAR* section)
{
Measure::ReadOptions(parser, section);

m_ProcessName = parser.ReadString(section, L"ProcessName", L"");
m_ProcessNameLowercase = parser.ReadString(section, L"ProcessName", L"");
StringUtil::ToLowerCase(m_ProcessNameLowercase);
}

void MeasureProcess::UpdateValue()
{
std::vector<std::wstring> processes;
{
std::lock_guard<std::mutex> lock(c_ProcessMutex);
processes = c_Processes;
}

for (const auto& name : processes)
{
if (_wcsicmp(name.c_str(), m_ProcessName.c_str()) == 0)
{
m_Value = 1.0;
return;
}
}

m_Value = -1.0;
}

void MeasureProcess::MonitorProcesses()
{
while (c_ProcessFuture.wait_for(std::chrono::milliseconds(1)) == std::future_status::timeout)
{
{
std::lock_guard<std::mutex> lock(c_ProcessMutex);

c_Processes.clear();

HANDLE thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (thSnapshot != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 processEntry = { sizeof(processEntry) };
if (Process32First(thSnapshot, &processEntry))
{
do
{
c_Processes.emplace_back(processEntry.szExeFile);
}
while (Process32Next(thSnapshot, &processEntry));
}
CloseHandle(thSnapshot);
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(c_UpdateInterval));
}
m_Value = GetRunningProcessLowercase().count(m_ProcessNameLowercase) ? 1.0 : -1.0;
}
16 changes: 1 addition & 15 deletions Library/MeasureProcess.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@
#define RM_LIBRARY_MEASUREPROCESS_H_

#include "Measure.h"
#include <thread>
#include <mutex>
#include <future>

class MeasureProcess : public Measure
{
Expand All @@ -29,18 +26,7 @@ class MeasureProcess : public Measure
void UpdateValue() override;

private:
static void MonitorProcesses();

std::wstring m_ProcessName;

static std::vector<std::wstring> c_Processes;
static std::thread c_ProcessThread;
static std::promise<void> c_ProcessExitSignal;
static std::future<void> c_ProcessFuture;
static std::mutex c_ProcessMutex;

static UINT c_References;
static int c_UpdateInterval;
std::wstring m_ProcessNameLowercase;
};

#endif

0 comments on commit de137b5

Please sign in to comment.