Vendored
+36
@@ -205,6 +205,42 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "(gdb) pipedalProfilePlugin",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
// Resolved by CMake Tools:
|
||||||
|
"program": "${command:cmake.launchTargetPath}",
|
||||||
|
|
||||||
|
"args": [
|
||||||
|
"--no-profile", "-w",
|
||||||
|
// "TooB NAM"
|
||||||
|
"--preset-file", "/tmp/namPreset.preset"
|
||||||
|
],
|
||||||
|
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"environment": [
|
||||||
|
{
|
||||||
|
"name": "PATH",
|
||||||
|
"value": "$PATH:${command:cmake.launchTargetDirectory}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "OTHER_VALUE",
|
||||||
|
"value": "Something something"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"externalConsole": false,
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"description": "Enable pretty-printing for gdb",
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
"name": "(gdb) processCopyrights Launch",
|
"name": "(gdb) processCopyrights Launch",
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
https://rerdavies.github.io/pipedal/funding.json
|
||||||
|
https://github.com/rerdavies/ToobAmp
|
||||||
|
https://github.com/rerdavies/pipedal
|
||||||
|
https://github.com/sponsors/rerdavies
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
{
|
||||||
|
"version": "v1.0.0",
|
||||||
|
"entity": {
|
||||||
|
"type": "individual",
|
||||||
|
"role": "maintainer",
|
||||||
|
"name": "Robin E. R. Davies",
|
||||||
|
"email": "rerdavies@gmail.com",
|
||||||
|
"phone": "1-613-857-8382",
|
||||||
|
"description": "I'm a developer, and jazz musician, interested in developing Raspbery Pi software for use in live performance.\n\nPiPedal started as a pandemic project, to see if I could build what I wanted to use when I perform. It has since grown into something beautiful and true, so I would like to make it available for everyone.",
|
||||||
|
"webpageUrl": {
|
||||||
|
"url": "https://github.com/rerdavies",
|
||||||
|
"wellKnown": "https://github.com/rerdavies/pipedal/blob/master/docs/.well-known/funding-manifest-urls"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"projects": [{
|
||||||
|
"guid": "com-twoplay-pipedal",
|
||||||
|
"name": "The PiPedal Project",
|
||||||
|
"description": "PiPedal is a guitar stomp box that runs on a Raspberry Pi (Raspberry Pi 4 or later). PiPedal is controlled remotely via a web application, or using the Android PiPedal Remote app.\n\nPipedal's user interface has been specifically designed with Phone and Tablet user interfaces in mind. Clip your phone or tablet onto a microphone stand, plugin your Raspberry Pi, and you're set to play!\n\nPiPedal started as Pandemic Project. I spent two years developing PiPedal full time during the pandemic. I would very much like to continue working on it full time, but I need your help to do so.",
|
||||||
|
"webpageUrl": {
|
||||||
|
"url": "https://rerdavies.github.io/pipedal/",
|
||||||
|
"wellKnown": "https://rerdavies.github.io/pipedal/.well-known/funding-manifest-urls"
|
||||||
|
},
|
||||||
|
"repositoryUrl": {
|
||||||
|
"url": "https://github.com/rerdavies/pipedal",
|
||||||
|
"wellKnown": "https://github.com/rerdavies/pipedal/blob/master/docs/.well-known/funding-manifest-urls"
|
||||||
|
},
|
||||||
|
"licenses": ["spdx:MIT"],
|
||||||
|
"tags": ["audio", "effects-pedal", "guitar", "raspberry-pi", "lv2-plugin"]
|
||||||
|
}],
|
||||||
|
"funding": {
|
||||||
|
"channels": [
|
||||||
|
{
|
||||||
|
"guid": "mybank",
|
||||||
|
"type": "bank",
|
||||||
|
"address": "",
|
||||||
|
"description": "Will accept direct bank transfers. Please e-mail me for details."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"guid": "github-sponsors",
|
||||||
|
"type": "payment-provider",
|
||||||
|
"address": "https://github.com/sponsors/rerdavies",
|
||||||
|
"description": "Pay with your debit/credit card through through GitHub Sponsors, or set up a monthly payment play.."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"plans": [
|
||||||
|
{
|
||||||
|
"guid": "hosting-monthly",
|
||||||
|
"status": "active",
|
||||||
|
"name": "Hosting support",
|
||||||
|
"description": "This will cover the monthly server hosting costs for the projects.",
|
||||||
|
"amount": 60,
|
||||||
|
"currency": "USD",
|
||||||
|
"frequency": "monthly",
|
||||||
|
"channels": ["mybank","github-sponsors"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"guid": "developer-time",
|
||||||
|
"status": "active",
|
||||||
|
"name": "Developer compensation",
|
||||||
|
"description": "This will cover the cost of one developer working full-time on the projects.",
|
||||||
|
"amount": 2000,
|
||||||
|
"currency": "USD",
|
||||||
|
"frequency": "monthly",
|
||||||
|
"channels": ["mybank","github-sponsors"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"guid": "angel-plan",
|
||||||
|
"status": "active",
|
||||||
|
"name": "Goodwill plan",
|
||||||
|
"description": "Pay anything you wish to show your goodwill for the project.",
|
||||||
|
"amount": 0,
|
||||||
|
"currency": "USD",
|
||||||
|
"frequency": "one-time",
|
||||||
|
"channels": ["mybank", "github-sponsors"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"history": [
|
||||||
|
{"year": 2022, "income": 0, "expenses": 0, "taxes": 0, "currency": "USD", "description": ""},
|
||||||
|
{"year": 2023, "income": 0, "expenses": 0, "taxes": 0, "currency": "USD", "description": ""},
|
||||||
|
{"year": 2024, "income": 47.00, "expenses": 0, "taxes": 0, "currency": "USD", "description": ""}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,3 +3,6 @@
|
|||||||
cmake --install build --prefix /usr --config Release -v
|
cmake --install build --prefix /usr --config Release -v
|
||||||
# Done as an install action by the debian package.
|
# Done as an install action by the debian package.
|
||||||
sudo /usr/bin/pipedalconfig --install
|
sudo /usr/bin/pipedalconfig --install
|
||||||
|
# copy pipedalPluginProfile as well.
|
||||||
|
sudo cp build/src/pipedalProfilePlugin /usr/bin/pipedalProfilePlugin
|
||||||
|
chmod +X /usr/bin/pipedalProfilePlugin
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import AudioFileIcon from '@mui/icons-material/AudioFile';
|
|||||||
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
||||||
import FolderIcon from '@mui/icons-material/Folder';
|
import FolderIcon from '@mui/icons-material/Folder';
|
||||||
import InsertDriveFileOutlinedIcon from '@mui/icons-material/InsertDriveFileOutlined';
|
import InsertDriveFileOutlinedIcon from '@mui/icons-material/InsertDriveFileOutlined';
|
||||||
|
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
|
||||||
import DialogActions from '@mui/material/DialogActions';
|
import DialogActions from '@mui/material/DialogActions';
|
||||||
import DialogTitle from '@mui/material/DialogTitle';
|
import DialogTitle from '@mui/material/DialogTitle';
|
||||||
import DialogContent from '@mui/material/DialogContent';
|
import DialogContent from '@mui/material/DialogContent';
|
||||||
@@ -60,6 +61,32 @@ const styles = (theme: Theme) => createStyles({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const audioFileExtensions: {[name: string]: boolean} = {
|
||||||
|
".wav": true,
|
||||||
|
".flac": true,
|
||||||
|
".ogg": true,
|
||||||
|
".aac": true,
|
||||||
|
".au": true,
|
||||||
|
".snd": true,
|
||||||
|
".mid": true,
|
||||||
|
".rmi": true,
|
||||||
|
".mp3": true,
|
||||||
|
".mp4": true,
|
||||||
|
".aif": true,
|
||||||
|
".aifc": true,
|
||||||
|
".aiff": true,
|
||||||
|
".ra": true
|
||||||
|
};
|
||||||
|
|
||||||
|
function isAudioFile(filename: string) {
|
||||||
|
let npos = filename.lastIndexOf('.');
|
||||||
|
let nposSlash = filename.lastIndexOf('/');
|
||||||
|
if (nposSlash >= npos) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let extension = filename.substring(npos);
|
||||||
|
return audioFileExtensions[extension] !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export interface FilePropertyDialogProps extends WithStyles<typeof styles> {
|
export interface FilePropertyDialogProps extends WithStyles<typeof styles> {
|
||||||
open: boolean,
|
open: boolean,
|
||||||
@@ -470,6 +497,25 @@ export default withStyles(styles, { withTheme: true })(
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
private getIcon(fileEntry: FileEntry)
|
||||||
|
{
|
||||||
|
if (fileEntry.filename === "")
|
||||||
|
{
|
||||||
|
return (<InsertDriveFileOutlinedIcon style={{ flex: "0 0 auto", opacity: 0.5, marginRight: 8, marginLeft: 8 }} />);
|
||||||
|
}
|
||||||
|
if (fileEntry.isDirectory)
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
<FolderIcon style={{ flex: "0 0 auto", opacity: 0.7, marginRight: 8, marginLeft: 8 }} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (isAudioFile(fileEntry.filename))
|
||||||
|
{
|
||||||
|
return (<AudioFileIcon style={{ flex: "0 0 auto", opacity: 0.7, marginRight: 8, marginLeft: 8 }} />);
|
||||||
|
}
|
||||||
|
return (<InsertDriveFileIcon style={{ flex: "0 0 auto", opacity: 0.7, marginRight: 8, marginLeft: 8 }} />);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let classes = this.props.classes;
|
let classes = this.props.classes;
|
||||||
let columnWidth = this.state.columnWidth;
|
let columnWidth = this.state.columnWidth;
|
||||||
@@ -571,12 +617,11 @@ export default withStyles(styles, { withTheme: true })(
|
|||||||
(this.state.columns !== 0) && // don't render until we have number of columns derived from layout.
|
(this.state.columns !== 0) && // don't render until we have number of columns derived from layout.
|
||||||
this.state.fileEntries.map(
|
this.state.fileEntries.map(
|
||||||
(value: FileEntry, index: number) => {
|
(value: FileEntry, index: number) => {
|
||||||
let isDefault = this.props.fileProperty.directory.startsWith("default");
|
|
||||||
let displayValue = value.filename;
|
let displayValue = value.filename;
|
||||||
if (displayValue === "") {
|
if (displayValue === "") {
|
||||||
displayValue = "<none>";
|
displayValue = "<none>";
|
||||||
} else {
|
} else {
|
||||||
if (isDefault)
|
if (value.isDirectory)
|
||||||
{
|
{
|
||||||
displayValue = pathFileName(displayValue);
|
displayValue = pathFileName(displayValue);
|
||||||
} else {
|
} else {
|
||||||
@@ -601,14 +646,7 @@ export default withStyles(styles, { withTheme: true })(
|
|||||||
>
|
>
|
||||||
<div ref={scrollRef} style={{ position: "absolute", background: selectBg, width: "100%", height: "100%", borderRadius: 4 }} />
|
<div ref={scrollRef} style={{ position: "absolute", background: selectBg, width: "100%", height: "100%", borderRadius: 4 }} />
|
||||||
<div style={{ display: "flex", flexFlow: "row nowrap", textOverflow: "ellipsis", justifyContent: "start", alignItems: "center", width: "100%", height: "100%" }}>
|
<div style={{ display: "flex", flexFlow: "row nowrap", textOverflow: "ellipsis", justifyContent: "start", alignItems: "center", width: "100%", height: "100%" }}>
|
||||||
{value.filename === "" ?
|
{this.getIcon(value)}
|
||||||
(<InsertDriveFileOutlinedIcon style={{ flex: "0 0 auto", opacity: 0.7, marginRight: 8, marginLeft: 8 }} />)
|
|
||||||
: (
|
|
||||||
value.isDirectory ? (
|
|
||||||
<FolderIcon style={{ flex: "0 0 auto", opacity: 0.7, marginRight: 8, marginLeft: 8 }} />
|
|
||||||
) : (
|
|
||||||
<AudioFileIcon style={{ flex: "0 0 auto", opacity: 0.7, marginRight: 8, marginLeft: 8 }} />
|
|
||||||
))}
|
|
||||||
<Typography noWrap className={classes.secondaryText} variant="body2" style={{ flex: "1 1 auto", textAlign: "left" }}>{displayValue}</Typography>
|
<Typography noWrap className={classes.secondaryText} variant="body2" style={{ flex: "1 1 auto", textAlign: "left" }}>{displayValue}</Typography>
|
||||||
</div>
|
</div>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
@@ -725,7 +763,7 @@ export default withStyles(styles, { withTheme: true })(
|
|||||||
}
|
}
|
||||||
openSelectedFile(): void {
|
openSelectedFile(): void {
|
||||||
if (this.isDirectory(this.state.selectedFile)) {
|
if (this.isDirectory(this.state.selectedFile)) {
|
||||||
let directoryName = pathFileNameOnly(this.state.selectedFile);
|
let directoryName = pathFileName(this.state.selectedFile);
|
||||||
let navDirectory = pathConcat(this.state.navDirectory, directoryName);
|
let navDirectory = pathConcat(this.state.navDirectory, directoryName);
|
||||||
this.requestFiles(navDirectory);
|
this.requestFiles(navDirectory);
|
||||||
this.setState({ navDirectory: navDirectory });
|
this.setState({ navDirectory: navDirectory });
|
||||||
|
|||||||
@@ -0,0 +1,147 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <linux/perf_event.h>
|
||||||
|
#include <asm/unistd.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sched.h>
|
||||||
|
|
||||||
|
namespace pipedal
|
||||||
|
{
|
||||||
|
class CacheMissCounter
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int fd_l1;
|
||||||
|
int fd_l2;
|
||||||
|
bool affinity_set = false;
|
||||||
|
cpu_set_t original_cpu_set;
|
||||||
|
|
||||||
|
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
|
||||||
|
int cpu, int group_fd, unsigned long flags)
|
||||||
|
{
|
||||||
|
return syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_counter(int &fd, uint64_t config, const std::string &name)
|
||||||
|
{
|
||||||
|
struct perf_event_attr pe;
|
||||||
|
memset(&pe, 0, sizeof(struct perf_event_attr));
|
||||||
|
pe.type = PERF_TYPE_HW_CACHE;
|
||||||
|
pe.size = sizeof(struct perf_event_attr);
|
||||||
|
pe.config = config;
|
||||||
|
pe.disabled = 1;
|
||||||
|
pe.exclude_kernel = 1;
|
||||||
|
pe.exclude_hv = 1;
|
||||||
|
|
||||||
|
fd = perf_event_open(&pe, 0, -1, -1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
CacheMissCounter() : fd_l1(-1), fd_l2(-1)
|
||||||
|
{
|
||||||
|
uint64_t l1_config = (PERF_COUNT_HW_CACHE_L1D << 0) |
|
||||||
|
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||||
|
(PERF_COUNT_HW_CACHE_RESULT_MISS << 16);
|
||||||
|
uint64_t l2_config = (PERF_COUNT_HW_CACHE_LL << 0) |
|
||||||
|
(PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
||||||
|
(PERF_COUNT_HW_CACHE_RESULT_MISS << 16);
|
||||||
|
|
||||||
|
setup_counter(fd_l1, l1_config, "L1");
|
||||||
|
setup_counter(fd_l2, l2_config, "L2");
|
||||||
|
|
||||||
|
int32_t cpu = 1;
|
||||||
|
if (cpu >= 0)
|
||||||
|
{
|
||||||
|
if (pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &original_cpu_set) != 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to get thread affinity");
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu_set_t cpu_set;
|
||||||
|
CPU_ZERO(&cpu_set);
|
||||||
|
CPU_SET(cpu, &cpu_set);
|
||||||
|
if (pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpu_set) != 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Failed to set thread affinity");
|
||||||
|
}
|
||||||
|
affinity_set = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~CacheMissCounter()
|
||||||
|
{
|
||||||
|
if (fd_l1 != -1)
|
||||||
|
close(fd_l1);
|
||||||
|
if (fd_l2 != -1)
|
||||||
|
close(fd_l2);
|
||||||
|
if (affinity_set)
|
||||||
|
{
|
||||||
|
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &original_cpu_set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void start()
|
||||||
|
{
|
||||||
|
ioctl(fd_l1, PERF_EVENT_IOC_RESET, 0);
|
||||||
|
ioctl(fd_l2, PERF_EVENT_IOC_RESET, 0);
|
||||||
|
ioctl(fd_l1, PERF_EVENT_IOC_ENABLE, 0);
|
||||||
|
ioctl(fd_l2, PERF_EVENT_IOC_ENABLE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop()
|
||||||
|
{
|
||||||
|
ioctl(fd_l1, PERF_EVENT_IOC_DISABLE, 0);
|
||||||
|
ioctl(fd_l2, PERF_EVENT_IOC_DISABLE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
long long get_l1_misses()
|
||||||
|
{
|
||||||
|
long long count;
|
||||||
|
read(fd_l1, &count, sizeof(long long));
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
long long get_l2_misses()
|
||||||
|
{
|
||||||
|
if (fd_l2 == -1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
long long count;
|
||||||
|
read(fd_l2, &count, sizeof(long long));
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// // Example usage
|
||||||
|
// int main() {
|
||||||
|
// try {
|
||||||
|
// CacheMissCounter counter;
|
||||||
|
|
||||||
|
// counter.start();
|
||||||
|
|
||||||
|
// // Your code to measure goes here
|
||||||
|
// // For example, let's do some memory operations
|
||||||
|
// volatile int* array = new int[1000000];
|
||||||
|
// for (int i = 0; i < 1000000; i++) {
|
||||||
|
// array[i] = i;
|
||||||
|
// }
|
||||||
|
// delete[] array;
|
||||||
|
|
||||||
|
// counter.stop();
|
||||||
|
|
||||||
|
// std::cout << "L1 cache misses: " << counter.get_l1_misses() << std::endl;
|
||||||
|
// std::cout << "L2 cache misses: " << counter.get_l2_misses() << std::endl;
|
||||||
|
|
||||||
|
// } catch (const std::exception& e) {
|
||||||
|
// std::cerr << "Error: " << e.what() << std::endl;
|
||||||
|
// return 1;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
}
|
||||||
+13
-6
@@ -134,6 +134,9 @@ if (ENABLE_BACKTRACE)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
|
# message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
|
||||||
# set(CMAKE_ENABLE_EXPORTS 1)
|
# set(CMAKE_ENABLE_EXPORTS 1)
|
||||||
|
|
||||||
@@ -351,15 +354,19 @@ set_target_properties(pipedaltest PROPERTIES EXCLUDE_FROM_ALL true)
|
|||||||
if (NOT GITHUB_ACTIONS) # Google perftools are not available on Github action servers.
|
if (NOT GITHUB_ACTIONS) # Google perftools are not available on Github action servers.
|
||||||
|
|
||||||
|
|
||||||
add_executable(profilePlugin
|
|
||||||
profilePluginMain.cpp
|
|
||||||
)
|
|
||||||
target_link_libraries(profilePlugin PRIVATE profiler ${PIPEDAL_LIBS})
|
|
||||||
|
|
||||||
target_include_directories(profilePlugin PRIVATE ${PIPEDAL_INCLUDES}
|
add_executable(pipedalProfilePlugin
|
||||||
|
profilePluginMain.cpp ArmPerformanceCounters.hpp
|
||||||
)
|
)
|
||||||
|
target_link_libraries(pipedalProfilePlugin PRIVATE profiler ${PIPEDAL_LIBS})
|
||||||
|
|
||||||
|
target_include_directories(pipedalProfilePlugin PRIVATE ${PIPEDAL_INCLUDES}
|
||||||
|
)
|
||||||
|
if (${DEBIAN_ARCHITECTURE} MATCHES arm64)
|
||||||
|
target_compile_definitions(pipedalProfilePlugin PRIVATE "PIPEDAL_AARCH64")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
set_target_properties(profilePlugin PROPERTIES EXCLUDE_FROM_ALL true)
|
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
add_executable(jsonTest
|
add_executable(jsonTest
|
||||||
|
|||||||
+43
-8
@@ -68,7 +68,7 @@ public:
|
|||||||
virtual void SetUpdatePolicy(UpdatePolicyT updatePolicy) override;
|
virtual void SetUpdatePolicy(UpdatePolicyT updatePolicy) override;
|
||||||
virtual void ForceUpdateCheck() override;
|
virtual void ForceUpdateCheck() override;
|
||||||
virtual void DownloadUpdate(const std::string &url, std::filesystem::path *file, std::filesystem::path *signatureFile) override;
|
virtual void DownloadUpdate(const std::string &url, std::filesystem::path *file, std::filesystem::path *signatureFile) override;
|
||||||
virtual UpdateStatus GetCurrentStatus() const override { return this->currentResult; }
|
virtual UpdateStatus GetCurrentStatus() const override;
|
||||||
virtual UpdateStatus GetReleaseGeneratorStatus() override;
|
virtual UpdateStatus GetReleaseGeneratorStatus() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -156,7 +156,7 @@ UpdateStatus UpdaterImpl::GetCachedUpdateStatus()
|
|||||||
reader.read(&status);
|
reader.read(&status);
|
||||||
|
|
||||||
// cached curruent version might come from a different version.
|
// cached curruent version might come from a different version.
|
||||||
status.ResetCurrentVersion();
|
status.UpdateForCurrentVersion();
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -416,6 +416,36 @@ static int compareVersions(const std::string &l, const std::string &r)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UpdateRelease::UpdateForCurrentVersion(const std::string¤tVersion)
|
||||||
|
{
|
||||||
|
if (compareVersions(currentVersion,this->UpgradeVersion()) >= 0)
|
||||||
|
{
|
||||||
|
this->updateAvailable_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UpdateStatus::UpdateAvailable() const
|
||||||
|
{
|
||||||
|
if (!isValid_) return false;
|
||||||
|
|
||||||
|
switch (this->UpdatePolicy())
|
||||||
|
{
|
||||||
|
case UpdatePolicyT::Development:
|
||||||
|
return this->devRelease_.UpdateAvailable();
|
||||||
|
break;
|
||||||
|
case UpdatePolicyT::ReleaseOnly:
|
||||||
|
return this->releaseOnlyRelease_.UpdateAvailable();
|
||||||
|
case UpdatePolicyT::ReleaseOrBeta:
|
||||||
|
this->releaseOrBetaRelease_.UpdateAvailable();
|
||||||
|
default:
|
||||||
|
case UpdatePolicyT::Disabled:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static std::string normalizeReleaseName(const std::string &releaseName)
|
static std::string normalizeReleaseName(const std::string &releaseName)
|
||||||
{
|
{
|
||||||
// e.g. "PiPedal 1.2.34 Release" -> "PiPedal v1.2.34-Release"
|
// e.g. "PiPedal 1.2.34 Release" -> "PiPedal v1.2.34-Release"
|
||||||
@@ -897,16 +927,20 @@ UpdateStatus::UpdateStatus()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateStatus::ResetCurrentVersion()
|
void UpdateStatus::UpdateForCurrentVersion()
|
||||||
{
|
{
|
||||||
currentVersion_ = PROJECT_VER;
|
currentVersion_ = PROJECT_VER;
|
||||||
currentVersionDisplayName_ = PROJECT_DISPLAY_VERSION;
|
currentVersionDisplayName_ = PROJECT_DISPLAY_VERSION;
|
||||||
|
|
||||||
#ifdef TEST_UPDATE
|
#if defined(TEST_UPDATE) && defined(DEBUG)
|
||||||
// uncomment this line to test upgrading.
|
// uncomment this line to test upgrading.
|
||||||
currentVersion_ = "1.2.39";
|
currentVersion_ = "1.2.39";
|
||||||
currentVersionDisplayName_ = "PiPedal 1.2.39-Debug";
|
currentVersionDisplayName_ = "PiPedal 1.2.39-Fictional";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
this->devRelease_.UpdateForCurrentVersion(currentVersion_);;
|
||||||
|
this->releaseOnlyRelease_.UpdateForCurrentVersion(currentVersion_);
|
||||||
|
this->releaseOrBetaRelease_.UpdateForCurrentVersion(currentVersion_);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::chrono::system_clock::time_point UpdateStatus::LastUpdateTime() const
|
std::chrono::system_clock::time_point UpdateStatus::LastUpdateTime() const
|
||||||
@@ -953,9 +987,6 @@ const GithubAsset *GithubRelease::GetDownloadForCurrentArchitecture() const
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateRelease::UpdateRelease()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string UpdaterImpl::GetSignatureUrl(const std::string &url)
|
std::string UpdaterImpl::GetSignatureUrl(const std::string &url)
|
||||||
{
|
{
|
||||||
@@ -1327,6 +1358,10 @@ void UpdaterImpl::DownloadUpdate(const std::string &url, std::filesystem::path *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateStatus UpdaterImpl::GetCurrentStatus() const {
|
||||||
|
return this->currentResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void UpdateStatus::AddRelease(const std::string&packageName)
|
void UpdateStatus::AddRelease(const std::string&packageName)
|
||||||
{
|
{
|
||||||
|
|||||||
+10
-3
@@ -22,7 +22,9 @@
|
|||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
|
|
||||||
namespace pipedal {
|
namespace pipedal {
|
||||||
enum class UpdatePolicyT
|
class UpdateStatus;
|
||||||
|
|
||||||
|
enum class UpdatePolicyT
|
||||||
{
|
{
|
||||||
// ordinal values must not change, as files depend on them.
|
// ordinal values must not change, as files depend on them.
|
||||||
// must match declaration in Updater.tsx
|
// must match declaration in Updater.tsx
|
||||||
@@ -37,14 +39,15 @@ namespace pipedal {
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
friend class UpdaterImpl;
|
friend class UpdaterImpl;
|
||||||
|
friend class UpdateStatus;
|
||||||
bool updateAvailable_ = false;
|
bool updateAvailable_ = false;
|
||||||
std::string upgradeVersion_; // just the version.
|
std::string upgradeVersion_; // just the version.
|
||||||
std::string upgradeVersionDisplayName_; // display name for the version.
|
std::string upgradeVersionDisplayName_; // display name for the version.
|
||||||
std::string assetName_; // filename only
|
std::string assetName_; // filename only
|
||||||
std::string updateUrl_; // url from which to download the .deb file.
|
std::string updateUrl_; // url from which to download the .deb file.
|
||||||
std::string gpgSignatureUrl_; // url from which to download the .deb.asc file.
|
std::string gpgSignatureUrl_; // url from which to download the .deb.asc file.
|
||||||
|
void UpdateForCurrentVersion(const std::string¤tVersion);
|
||||||
public:
|
public:
|
||||||
UpdateRelease();
|
|
||||||
|
|
||||||
bool UpdateAvailable() const { return updateAvailable_; }
|
bool UpdateAvailable() const { return updateAvailable_; }
|
||||||
const std::string &UpgradeVersion() const { return upgradeVersion_; }
|
const std::string &UpgradeVersion() const { return upgradeVersion_; }
|
||||||
@@ -78,8 +81,12 @@ namespace pipedal {
|
|||||||
std::chrono::system_clock::time_point LastUpdateTime() const;
|
std::chrono::system_clock::time_point LastUpdateTime() const;
|
||||||
void LastUpdateTime(const std::chrono::system_clock::time_point &timePoint);
|
void LastUpdateTime(const std::chrono::system_clock::time_point &timePoint);
|
||||||
|
|
||||||
void ResetCurrentVersion();
|
|
||||||
|
void UpdateForCurrentVersion();
|
||||||
bool IsValid() const { return isValid_; }
|
bool IsValid() const { return isValid_; }
|
||||||
|
|
||||||
|
bool UpdateAvailable() const;
|
||||||
|
|
||||||
const std::string &ErrorMessage() const { return errorMessage_; }
|
const std::string &ErrorMessage() const { return errorMessage_; }
|
||||||
bool IsOnline() const { return isOnline_; }
|
bool IsOnline() const { return isOnline_; }
|
||||||
const std::string &CurrentVersion() const { return currentVersion_; }
|
const std::string &CurrentVersion() const { return currentVersion_; }
|
||||||
|
|||||||
+87
-17
@@ -6,9 +6,11 @@
|
|||||||
#include "CommandLineParser.hpp"
|
#include "CommandLineParser.hpp"
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include "ss.hpp"
|
||||||
|
|
||||||
// apt install google-perftools
|
// apt install google-perftools
|
||||||
#include <gperftools/profiler.h>
|
#include <gperftools/profiler.h>
|
||||||
|
#include "ArmPerformanceCounters.hpp"
|
||||||
|
|
||||||
using namespace pipedal;
|
using namespace pipedal;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@@ -79,6 +81,7 @@ private:
|
|||||||
struct ProfileOptions
|
struct ProfileOptions
|
||||||
{
|
{
|
||||||
std::string presetName;
|
std::string presetName;
|
||||||
|
std::string presetFileName;
|
||||||
float benchmark_seconds = 20;
|
float benchmark_seconds = 20;
|
||||||
std::string outputFilename = "/tmp/profilePlugin.perf";
|
std::string outputFilename = "/tmp/profilePlugin.perf";
|
||||||
bool noProfile = false;
|
bool noProfile = false;
|
||||||
@@ -88,11 +91,17 @@ struct ProfileOptions
|
|||||||
|
|
||||||
void profilePlugin(const ProfileOptions &profileOptions)
|
void profilePlugin(const ProfileOptions &profileOptions)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#ifdef PIPEDAL_AARCH64
|
||||||
|
CacheMissCounter cacheMissCounter;
|
||||||
|
#endif
|
||||||
|
|
||||||
size_t nFrames = profileOptions.frameSize;
|
size_t nFrames = profileOptions.frameSize;
|
||||||
Lv2Log::log_level(LogLevel::Info);
|
Lv2Log::log_level(LogLevel::Info);
|
||||||
|
|
||||||
/*** Initialize the model */
|
/*** Initialize the model */
|
||||||
PiPedalModel model;
|
PiPedalModel model;
|
||||||
|
Lv2Log::log_level(LogLevel::Error);
|
||||||
fs::path doc_root = "/etc/pipedal/config";
|
fs::path doc_root = "/etc/pipedal/config";
|
||||||
PiPedalConfiguration configuration;
|
PiPedalConfiguration configuration;
|
||||||
try
|
try
|
||||||
@@ -113,25 +122,59 @@ void profilePlugin(const ProfileOptions &profileOptions)
|
|||||||
// model.Load(); don't start audio.
|
// model.Load(); don't start audio.
|
||||||
|
|
||||||
/* *** Load the preset. */
|
/* *** Load the preset. */
|
||||||
PresetIndex presetIndex;
|
|
||||||
model.GetPresets(&presetIndex);
|
|
||||||
|
|
||||||
int64_t presetIndexId = 0;
|
bool presetValid = false;
|
||||||
bool presetIndexFound = false;
|
|
||||||
for (const auto &preset : presetIndex.presets())
|
if (profileOptions.presetName.length() != 0)
|
||||||
{
|
{
|
||||||
if (preset.name() == profileOptions.presetName)
|
PresetIndex presetIndex;
|
||||||
|
model.GetPresets(&presetIndex);
|
||||||
|
|
||||||
|
int64_t presetIndexId = 0;
|
||||||
|
bool presetIndexFound = false;
|
||||||
|
for (const auto &preset : presetIndex.presets())
|
||||||
{
|
{
|
||||||
presetIndexId = preset.instanceId();
|
if (preset.name() == profileOptions.presetName)
|
||||||
presetIndexFound = true;
|
{
|
||||||
break;
|
presetIndexId = preset.instanceId();
|
||||||
|
presetIndexFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!presetIndexFound)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Preset not found.");
|
||||||
|
}
|
||||||
|
model.LoadPreset(-1, presetIndexId);
|
||||||
|
}
|
||||||
|
else if (profileOptions.presetFileName.length() != 0)
|
||||||
|
{
|
||||||
|
std::ifstream f(profileOptions.presetFileName);
|
||||||
|
if (!f.is_open())
|
||||||
|
{
|
||||||
|
throw std::runtime_error(SS("Unable to load preset file " << profileOptions.presetFileName << "."));
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
json_reader reader(f);
|
||||||
|
BankFile bankFile;
|
||||||
|
reader.read(&bankFile);
|
||||||
|
if (bankFile.presets().size() != 1)
|
||||||
|
{
|
||||||
|
throw new std::runtime_error(SS("Invalid preset file. Expection one preset, but " << bankFile.presets().size() << " presets were found."));
|
||||||
|
}
|
||||||
|
Pedalboard pedalboard = (bankFile.presets()[0]->preset());
|
||||||
|
model.SetPedalboard(-1,pedalboard);
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(SS("Invalid file format: " << profileOptions.presetFileName << ". " << e.what() ));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!presetIndexFound)
|
else
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Preset not found.");
|
throw std::runtime_error("You must specify either a preset name or a preset file.");
|
||||||
}
|
}
|
||||||
model.LoadPreset(-1, presetIndexId);
|
|
||||||
|
|
||||||
auto pedalboard = model.GetCurrentPedalboardCopy();
|
auto pedalboard = model.GetCurrentPedalboardCopy();
|
||||||
cout << "uri: " << pedalboard.items()[0].uri() << endl;
|
cout << "uri: " << pedalboard.items()[0].uri() << endl;
|
||||||
@@ -153,7 +196,6 @@ void profilePlugin(const ProfileOptions &profileOptions)
|
|||||||
|
|
||||||
RingBufferSink ringBufferSink(writerRingbuffer);
|
RingBufferSink ringBufferSink(writerRingbuffer);
|
||||||
|
|
||||||
|
|
||||||
// run once to get memory allocations in NAM and ML out of the way.
|
// run once to get memory allocations in NAM and ML out of the way.
|
||||||
lv2Pedalboard->Run(inputBuffers, outputBuffers, nFrames, &ringBufferWriter);
|
lv2Pedalboard->Run(inputBuffers, outputBuffers, nFrames, &ringBufferWriter);
|
||||||
|
|
||||||
@@ -184,6 +226,10 @@ void profilePlugin(const ProfileOptions &profileOptions)
|
|||||||
{
|
{
|
||||||
ProfilerStart(profileOptions.outputFilename.c_str());
|
ProfilerStart(profileOptions.outputFilename.c_str());
|
||||||
}
|
}
|
||||||
|
#ifdef PIPEDAL_AARCH64
|
||||||
|
cacheMissCounter.start();
|
||||||
|
#endif
|
||||||
|
|
||||||
auto startTime = std::chrono::system_clock::now();
|
auto startTime = std::chrono::system_clock::now();
|
||||||
|
|
||||||
size_t repetitions = static_cast<size_t>(48000 * profileOptions.benchmark_seconds / nFrames);
|
size_t repetitions = static_cast<size_t>(48000 * profileOptions.benchmark_seconds / nFrames);
|
||||||
@@ -193,12 +239,21 @@ void profilePlugin(const ProfileOptions &profileOptions)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto elapsedTime = std::chrono::high_resolution_clock::now() - startTime;
|
auto elapsedTime = std::chrono::high_resolution_clock::now() - startTime;
|
||||||
|
|
||||||
|
#ifdef PIPEDAL_AARCH64
|
||||||
|
cacheMissCounter.stop();
|
||||||
|
#endif
|
||||||
if (!profileOptions.noProfile)
|
if (!profileOptions.noProfile)
|
||||||
{
|
{
|
||||||
ProfilerStop();
|
ProfilerStop();
|
||||||
}
|
}
|
||||||
std::chrono::milliseconds us = std::chrono::duration_cast<chrono::milliseconds>(elapsedTime);
|
std::chrono::milliseconds us = std::chrono::duration_cast<chrono::milliseconds>(elapsedTime);
|
||||||
std::cout << "Ellapsed time: " << (us.count() / 1000.0) << "s" << endl;
|
std::cout << "Ellapsed time: " << (us.count() / 1000.0) << "s" << endl;
|
||||||
|
#ifdef PIPEDAL_AARCH64
|
||||||
|
std::cout << "L1 Cache Misses: " << cacheMissCounter.get_l1_misses() << endl;
|
||||||
|
// non-functional on Raspberry PI OS.
|
||||||
|
// std::cout << "L2 Cache Misses: " << cacheMissCounter.get_l2_misses() << endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
ringBufferSink.Close();
|
ringBufferSink.Close();
|
||||||
|
|
||||||
@@ -212,20 +267,29 @@ int main(int argc, char **argv)
|
|||||||
ProfileOptions profileOptions;
|
ProfileOptions profileOptions;
|
||||||
bool help = false;
|
bool help = false;
|
||||||
CommandLineParser commandLineParser;
|
CommandLineParser commandLineParser;
|
||||||
|
std::string presetFileName;
|
||||||
commandLineParser.AddOption("w", "wait-for-work", &profileOptions.waitForWork);
|
commandLineParser.AddOption("w", "wait-for-work", &profileOptions.waitForWork);
|
||||||
commandLineParser.AddOption("", "no-profile", &profileOptions.noProfile);
|
commandLineParser.AddOption("", "no-profile", &profileOptions.noProfile);
|
||||||
|
commandLineParser.AddOption("p", "preset-file", &presetFileName);
|
||||||
commandLineParser.AddOption("o", "output", &profileOptions.outputFilename);
|
commandLineParser.AddOption("o", "output", &profileOptions.outputFilename);
|
||||||
commandLineParser.AddOption("s", "seconds", &profileOptions.benchmark_seconds);
|
commandLineParser.AddOption("s", "seconds", &profileOptions.benchmark_seconds);
|
||||||
commandLineParser.AddOption("h", "help", &help);
|
commandLineParser.AddOption("h", "help", &help);
|
||||||
|
|
||||||
commandLineParser.Parse(argc, (const char **)argv);
|
commandLineParser.Parse(argc, (const char **)argv);
|
||||||
|
|
||||||
if (commandLineParser.Arguments().size() != 1 || help)
|
bool argumentError = false;
|
||||||
|
if (commandLineParser.Arguments().size() == 1 && presetFileName.length() == 0)
|
||||||
|
{
|
||||||
|
cerr << "Error: You must supply either a preset name, or a preset file name" << endl;
|
||||||
|
argumentError = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argumentError || help)
|
||||||
{
|
{
|
||||||
cout << "profilePlugin - Generate profiling data for LV2 Plugins" << endl;
|
cout << "profilePlugin - Generate profiling data for LV2 Plugins" << endl;
|
||||||
cout << "Copyright (c) 2024 Robin E. R. Davies" << endl;
|
cout << "Copyright (c) 2024 Robin E. R. Davies" << endl;
|
||||||
cout << endl;
|
cout << endl;
|
||||||
cout << "Syntax: profilePlugin preset_name [options...]" << endl;
|
cout << "Syntax: profilePlugin [preset_name] [options...]" << endl;
|
||||||
cout << " where preset_name is the name of a PiPedal preset." << endl;
|
cout << " where preset_name is the name of a PiPedal preset." << endl;
|
||||||
cout << endl;
|
cout << endl;
|
||||||
cout << " A google-perf profile capture will be written to " << endl;
|
cout << " A google-perf profile capture will be written to " << endl;
|
||||||
@@ -234,6 +298,8 @@ int main(int argc, char **argv)
|
|||||||
cout << "Options:" << endl;
|
cout << "Options:" << endl;
|
||||||
cout << " --no-profile:" << endl;
|
cout << " --no-profile:" << endl;
|
||||||
cout << " do NOT generate a perf file." << endl;
|
cout << " do NOT generate a perf file." << endl;
|
||||||
|
cout << " -p, --preset-file filename:" << endl;
|
||||||
|
cout << " Load the specified preset file. " << endl;
|
||||||
cout << " -o, --output filename:" << endl;
|
cout << " -o, --output filename:" << endl;
|
||||||
cout << " The file to which profiler data is written. " << endl;
|
cout << " The file to which profiler data is written. " << endl;
|
||||||
cout << " Defaults to /tmp/profilePlugin.perf" << endl;
|
cout << " Defaults to /tmp/profilePlugin.perf" << endl;
|
||||||
@@ -241,12 +307,16 @@ int main(int argc, char **argv)
|
|||||||
cout << " Assume that the plugin will load data on the LV2 scheduler thread." << endl;
|
cout << " Assume that the plugin will load data on the LV2 scheduler thread." << endl;
|
||||||
cout << " -s, --seconds time_in_seconds: " << endl;
|
cout << " -s, --seconds time_in_seconds: " << endl;
|
||||||
cout << " The number of seconds of audio to process." << endl;
|
cout << " The number of seconds of audio to process." << endl;
|
||||||
cout << " -h, --help: display this message." << endl;
|
cout << " -h, --help: display this message." << endl;
|
||||||
cout << endl;
|
cout << endl;
|
||||||
return help ? EXIT_SUCCESS : EXIT_FAILURE;
|
return help ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
profileOptions.presetName = commandLineParser.Arguments()[0];
|
if (commandLineParser.Arguments().size() != 0)
|
||||||
|
{
|
||||||
|
profileOptions.presetName = commandLineParser.Arguments()[0];
|
||||||
|
}
|
||||||
|
profileOptions.presetFileName = presetFileName;
|
||||||
|
|
||||||
profilePlugin(profileOptions);
|
profilePlugin(profileOptions);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user