Configurable CPU Governor (fixed)

modified:   .vscode/launch.json
	modified:   react/CMakeLists.txt
	modified:   react/public/var/config.json
	new file:   react/src/GovernorSettings.tsx
	modified:   react/src/JackHostStatus.tsx
	new file:   react/src/ListSelectDialog.tsx
	modified:   react/src/PiPedalModel.tsx
	modified:   react/src/SettingsDialog.tsx
	modified:   react/tmp.txt
	modified:   src/BeastServer.cpp
	modified:   src/BeastServer.hpp
	modified:   src/CMakeLists.txt
	modified:   src/ConfigMain.cpp
	new file:   src/CpuGovernor.cpp
	new file:   src/CpuGovernor.hpp
	new file:   src/GovernorSettings.cpp
	new file:   src/GovernorSettings.hpp
	new file:   src/Ipv6Helpers.cpp
	new file:   src/Ipv6Helpers.hpp
	modified:   src/JackHost.cpp
	modified:   src/PiPedalModel.cpp
This commit is contained in:
Robin Davies
2022-03-09 21:35:01 -05:00
parent 5d42ec0753
commit 8ad2de8c72
31 changed files with 1642 additions and 377 deletions
+212 -103
View File
@@ -23,6 +23,7 @@
#include "pch.h"
#include "CommandLineParser.hpp"
#include "CpuGovernor.hpp"
#include <iostream>
#include <cstdint>
#include <boost/asio.hpp>
@@ -40,7 +41,10 @@
#include "SetWifiConfig.hpp"
#include "SysExec.hpp"
#include <filesystem>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
using namespace std;
using namespace pipedal;
@@ -50,15 +54,122 @@ using ip::tcp;
const size_t MAX_LENGTH = 128;
static bool startsWith(const std::string&s, const char*text)
class GovernorMonitorThread
{
if (s.length() < strlen(text)) return false;
const char*sp = s.c_str();
public:
~GovernorMonitorThread()
{
Stop();
}
void Start(std::string governor)
{
std::unique_lock<std::mutex> lock(mutex);
if (!pThread)
{
this->governor = governor;
cancelled = false;
wake = false;
pThread = std::make_unique<std::thread>([this]()
{ this->ServiceProc(); });
} else {
this->governor = governor;
wake = true;
lock.unlock();
cv.notify_one();
}
}
void Stop()
{
std::unique_lock<std::mutex> lock(mutex);
if (pThread)
{
wake = true;
cancelled = true;
lock.unlock();
cv.notify_one();
pThread->join();
pThread.reset();
}
}
void SetGovernor(const std::string &governor)
{
{
std::unique_lock<std::mutex> lock(mutex);
wake = true;
this->governor = governor;
}
cv.notify_one();
}
private:
bool wake = false;
bool cancelled = false;
std::string savedGovernor;
void ServiceProc()
{
savedGovernor = pipedal::GetCpuGovernor();
pipedal::SetCpuGovernor(this->governor);
while (true)
{
bool cancelled;
std::string governor;
{
std::unique_lock<std::mutex> lock(mutex);
auto timeToWaitFor = std::chrono::system_clock::now() + 5000ms;
cv.wait_until(
lock,
timeToWaitFor,
[this]()
{ return wake; });
wake = false;
governor = this->governor;
cancelled = this->cancelled;
}
if (cancelled) {
break;
}
std::string activeGovernor = pipedal::GetCpuGovernor();
if (activeGovernor != governor)
{
// somebody set it so they must have wanted it.
// save the value so that we can restore it when done.
savedGovernor = activeGovernor;
// but insist on using ours!!
pipedal::SetCpuGovernor(governor);
}
}
pipedal::SetCpuGovernor(savedGovernor);
}
std::unique_ptr<std::thread> pThread;
std::string governor;
std::mutex mutex;
bool canceled;
std::condition_variable cv;
};
GovernorMonitorThread governorMonitorThread;
void StopGovernorMonitorThread()
{
governorMonitorThread.Stop();
}
void StartGovernorMonitorThread(const std::string&governor)
{
governorMonitorThread.Start(governor);
}
static bool startsWith(const std::string &s, const char *text)
{
if (s.length() < strlen(text))
return false;
const char *sp = s.c_str();
while (*text)
{
if (*text++ != *sp++) return false;
if (*text++ != *sp++)
return false;
}
return true;
}
@@ -67,7 +178,7 @@ static std::vector<std::string> tokenize(std::string value)
std::vector<std::string> result;
std::stringstream s(value);
std::string item;
while (std::getline(s,item,' '))
while (std::getline(s, item, ' '))
{
if (item.length() != 0)
result.push_back(item);
@@ -75,26 +186,17 @@ static std::vector<std::string> tokenize(std::string value)
return result;
}
static void CaptureAccessPoint(const std::string gatewayAddress)
{
}
static void ReleaseAccessPoint(const std::string gatewayAddress)
{
}
void delayedRestartProc()
static void delayedRestartProc()
{
sleep(1); // give a chance for websocket messages to propagate.
Lv2Log::error("Delayed Restart");
std::string pipedalConfigPath = std::filesystem::path(getSelfExePath()).parent_path() / "pipedalconfig";
std::stringstream s;
s << pipedalConfigPath.c_str() << " --restart --excludeShutdownService";
if (::system(s.str().c_str())!= EXIT_SUCCESS)
s << pipedalConfigPath.c_str() << " --restart --excludeShutdownService";
if (::system(s.str().c_str()) != EXIT_SUCCESS)
{
Lv2Log::error("Delayed Restart failed.");
}
}
@@ -110,8 +212,6 @@ bool setJackConfiguration(JackServerSettings serverSettings)
std::thread delayedRestartThread(delayedRestartProc);
delayedRestartThread.detach();
return true;
}
class Reader : public std::enable_shared_from_this<Reader>
@@ -162,7 +262,7 @@ private:
return;
}
socket.async_write_some(
boost::asio::buffer(response.c_str()+ writePosition, response.length()-writePosition),
boost::asio::buffer(response.c_str() + writePosition, response.length() - writePosition),
boost::bind(&Reader::HandleWrite,
shared_from_this(),
boost::asio::placeholders::error,
@@ -185,7 +285,7 @@ private:
if (c == '\n')
{
std::string command = message.str();
cout << "Received command: " << command << endl;
cout << command << endl;
HandleCommand(command);
socket.close();
return;
@@ -202,59 +302,88 @@ private:
socket.close();
}
}
void HandleCommand(const std::string &s)
void HandleCommand(const std::string &text)
{
int result = -1;
try {
if (startsWith(s,"WifiConfigSettings "))
std::string command;
std::string args;
auto pos = text.find_first_of(' ');
if (pos == std::string::npos)
{
command = text;
}
else
{
command = text.substr(0, pos);
args = text.substr(pos + 1);
}
try
{
if (command == "UnmonitorGovernor")
{
std::string json = s.substr(strlen("WifiConfigSettings "));
std::stringstream ss(json);
StopGovernorMonitorThread();
result = 0;
}
else if (command == "MonitorGovernor")
{
std::stringstream ss(args);
std::string governor;
try
{
json_reader reader(ss);
reader.read(&governor);
}
catch (const std::exception &e)
{
throw PiPedalArgumentException("Invalid arguments.");
}
StartGovernorMonitorThread(governor);
result = 0;
}
else if (command == "GovernorSettings")
{
std::stringstream ss(args);
std::string governor;
try
{
json_reader reader(ss);
reader.read(&governor);
}
catch (const std::exception &e)
{
throw PiPedalArgumentException("Invalid arguments.");
}
governorMonitorThread.SetGovernor(governor);
result = 0;
}
else if (command == "WifiConfigSettings ")
{
std::stringstream ss(args);
WifiConfigSettings settings;
try {
try
{
json_reader reader(ss);
reader.read(&settings);
} catch (const std::exception &e)
}
catch (const std::exception &e)
{
throw PiPedalArgumentException("Invalid arguments.");
}
pipedal::SetWifiConfig(settings);
result = 0;
} else if (startsWith(s,"release_ap "))
{
std::vector<std::string> argv = tokenize(s);
if (argv.size() == 2) {
ReleaseAccessPoint(argv[1]);
result = 0;
} else {
throw PiPedalArgumentException("Invalid arguments.");
}
} else if (startsWith(s,"capture_ap "))
{
std::vector<std::string> argv = tokenize(s);
if (argv.size() == 2) {
CaptureAccessPoint(argv[1]);
result = 0;
} else {
throw PiPedalArgumentException("Invalid arguments.");
}
} else if (s == "shutdown")
}
else if (command == "shutdown")
{
result = sysExec("/usr/sbin/shutdown -P now");
}
else if (s == "restart")
else if (command == "restart")
{
result = sysExec("/usr/sbin/shutdown -r now");
} else if (startsWith(s,"setJackConfiguration "))
}
else if (command == "setJackConfiguration")
{
auto remainder = s.substr(strlen("setJackConfiguration "));
std::stringstream input(remainder);
std::stringstream input(args);
JackServerSettings serverSettings;
json_reader reader(input);
@@ -263,12 +392,18 @@ private:
if (input.fail())
{
result = -1;
} else {
result = setJackConfiguration(serverSettings) ? 0: -1;
}
else
{
result = setJackConfiguration(serverSettings) ? 0 : -1;
}
}
} catch (const std::exception &e)
else
{
throw std::invalid_argument(SS("Unknown command:" << command));
}
}
catch (const std::exception &e)
{
std::stringstream t;
t << "-2 " << e.what() << "\n";
@@ -284,7 +419,6 @@ private:
this->writePosition = 0;
WriteSome();
}
};
class Server
@@ -314,16 +448,16 @@ private:
}
public:
//constructor for accepting connection from client
// constructor for accepting connection from client
Server(boost::asio::io_service &io_service, const tcp::endpoint &endpoint)
: acceptor_(io_service, endpoint),
io_service(io_service)
io_service(io_service)
{
StartAccept();
}
~Server() {
~Server()
{
}
};
@@ -332,29 +466,26 @@ void runServer(uint16_t port)
asio::ip::tcp::endpoint endpoint(ip::make_address_v4("127.0.0.1"), port);
asio::io_service ios;
try {
Server server(ios,endpoint);
try
{
Server server(ios, endpoint);
ios.run();
cout << "Processing terminated." << endl;
} catch (const std::exception & e)
}
catch (const std::exception &e)
{
cout << "Error: " << e.what() << endl;
}
}
int main(int argc, char **argv)
{
Lv2Log::set_logger(MakeLv2SystemdLogger());
CommandLineParser parser;
uint16_t port = 0;
std::string captureAccessPoint;
std::string releaseAccessPoint;
parser.AddOption("-port", &port);
parser.AddOption("-captureAP",&captureAccessPoint);
parser.AddOption("-releaseAP",&releaseAccessPoint);
try
{
@@ -369,34 +500,12 @@ int main(int argc, char **argv)
cout << "Error: " << e.what() << endl;
return EXIT_FAILURE;
}
if (captureAccessPoint.length() != 0)
if (port == 0)
{
try{
CaptureAccessPoint(captureAccessPoint);
} catch (const std::exception &e)
{
std::cerr << "Error: " << e.what() << std::endl;
return EXIT_FAILURE;
}
std::cout << "Access point captured." << std::endl;
} else if (releaseAccessPoint.length() != 0)
{
try{
ReleaseAccessPoint(releaseAccessPoint);
} catch (const std::exception &e)
{
std::cerr << "Error: " << e.what() << std::endl;
return EXIT_FAILURE;
}
std::cout << "Access point released." << std::endl;
} else {
if (port == 0) {
std::cerr << "Error: port not specified." << std::endl;
return EXIT_FAILURE;
}
runServer(port);
std::cerr << "Error: port not specified." << std::endl;
return EXIT_FAILURE;
}
runServer(port);
governorMonitorThread.Stop();
return EXIT_SUCCESS;
}