Для начала можно запустить простенький тест на Audigy:#include <windows.h>
#include <dsound.h>
#include <cmath>
#include <vector>
#include <complex>
class FourierTest {
public:
void generateTestSignal(std::vector<float>& signal, int sampleRate) {
// Генерация тестового сигнала (синус + гармоники)
for (int i = 0; i < signal.size(); i++) {
double t = (double)i / sampleRate;
signal[i] = 0.6f * sin(2 * M_PI * 1000 * t) + // 1 kHz основная
0.3f * sin(2 * M_PI * 2000 * t) + // 2 kHz гармоника
0.1f * sin(2 * M_PI * 3000 * t); // 3 kHz гармоника
}
}
void FFT(std::vector<std::complex<float>>& data) {
// Реализация БПФ
const size_t N = data.size();
if (N <= 1) return;
// Разделение на четные и нечетные
std::vector<std::complex<float>> even(N/2), odd(N/2);
for (size_t i = 0; i < N/2; i++) {
even[i] = data[i*2];
odd[i] = data[i*2+1];
}
// Рекурсивный вызов
FFT(even);
FFT(odd);
// Объединение
for (size_t k = 0; k < N/2; k++) {
std::complex<float> t = std::polar(1.0f, -2.0f * M_PI * k / N) * odd[k];
data[k] = even[k] + t;
data[k + N/2] = even[k] - t;
}
}
};
если всё ОК, можно уже запустить приблизительно такой с профилированием и загрузкой ЦП, для измерения:
- Задержки ввода-вывода (latency)
- Способности обрабатывать данные без разрывов (glitches)
- Максимальную нагрузку, которую выдерживает звуковая карта:
#include <windows.h>
#include <dsound.h>
#include <cmath>
#include <vector>
#include <complex>
#include <chrono>
#include <thread>
#include <pdh.h>
#include <pdhmsg.h>
#include <iostream>
#include <iomanip>
#include <psapi.h>
#pragma comment(lib, "dsound.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "winmm.lib")
#pragma comment(lib, "pdh.lib")
class CPUUsageMonitor {
private:
PDH_HQUERY cpuQuery;
PDH_HCOUNTER cpuTotalCounter;
FILETIME prevSysKernel, prevSysUser, prevProcKernel, prevProcUser;
public:
CPUUsageMonitor() : cpuQuery(NULL), cpuTotalCounter(NULL) {
PdhOpenQuery(NULL, NULL, &cpuQuery);
PdhAddEnglishCounter(cpuQuery, "\\Processor(_Total)\\% Processor Time", NULL, &cpuTotalCounter);
PdhCollectQueryData(cpuQuery);
SYSTEM_INFO sysInfo;
FILETIME ftime, fsys, fuser;
GetSystemInfo(&sysInfo);
GetSystemTimeAsFileTime(&ftime);
memcpy(&prevSysKernel, &fsys, sizeof(FILETIME));
memcpy(&prevSysUser, &fuser, sizeof(FILETIME));
}
~CPUUsageMonitor() {
if (cpuQuery) PdhCloseQuery(cpuQuery);
}
double getCurrentCPUUsage() {
PDH_FMT_COUNTERVALUE counterVal;
PdhCollectQueryData(cpuQuery);
PdhGetFormattedCounterValue(cpuTotalCounter, PDH_FMT_DOUBLE, NULL, &counterVal);
return counterVal.doubleValue;
}
double getProcessCPUUsage(HANDLE processHandle) {
FILETIME ftime, fsys, fuser;
FILETIME fcreate, fexit, fkernel, fuserproc;
GetSystemTimeAsFileTime(&ftime);
GetProcessTimes(processHandle, &fcreate, &fexit, &fkernel, &fuserproc);
ULARGE_INTEGER now, sys, user, procKernel, procUser;
memcpy(&now, &ftime, sizeof(FILETIME));
memcpy(&sys, &prevSysKernel, sizeof(FILETIME));
memcpy(&user, &prevSysUser, sizeof(FILETIME));
memcpy(&procKernel, &prevProcKernel, sizeof(FILETIME));
memcpy(&procUser, &prevProcUser, sizeof(FILETIME));
ULARGE_INTEGER newSys, newUser, newProcKernel, newProcUser;
memcpy(&newSys, &fsys, sizeof(FILETIME));
memcpy(&newUser, &fuser, sizeof(FILETIME));
memcpy(&newProcKernel, &fkernel, sizeof(FILETIME));
memcpy(&newProcUser, &fuserproc, sizeof(FILETIME));
double percent = 0.0;
ULONGLONG totalSys = (newSys.QuadPart - sys.QuadPart) + (newUser.QuadPart - user.QuadPart);
ULONGLONG totalProc = (newProcKernel.QuadPart - procKernel.QuadPart) +
(newProcUser.QuadPart - procUser.QuadPart);
if (totalSys > 0) {
percent = (double)totalProc / totalSys * 100.0;
}
memcpy(&prevSysKernel, &fsys, sizeof(FILETIME));
memcpy(&prevSysUser, &fuser, sizeof(FILETIME));
memcpy(&prevProcKernel, &fkernel, sizeof(FILETIME));
memcpy(&prevProcUser, &fuserproc, sizeof(FILETIME));
return percent;
}
};
class MemoryMonitor {
public:
static SIZE_T getProcessMemoryUsage() {
PROCESS_MEMORY_COUNTERS pmc;
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
return pmc.WorkingSetSize / 1024; // KB
}
return 0;
}
static SIZE_T getPeakMemoryUsage() {
PROCESS_MEMORY_COUNTERS pmc;
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
return pmc.PeakWorkingSetSize / 1024; // KB
}
return 0;
}
};
class HighPrecisionTimer {
private:
LARGE_INTEGER frequency;
bool supported;
public:
HighPrecisionTimer() {
supported = QueryPerformanceFrequency(&frequency);
}
double getTime() {
if (supported) {
LARGE_INTEGER current;
QueryPerformanceCounter(¤t);
return (double)current.QuadPart / frequency.QuadPart;
}
return (double)GetTickCount() / 1000.0;
}
};
class FourierTest {
private:
CPUUsageMonitor cpuMonitor;
HighPrecisionTimer timer;
public:
struct PerformanceMetrics {
double totalTime;
double fftTime;
double iOTime;
double cpuUsage;
double memoryUsage;
double peakMemory;
int bufferSize;
std::string testType;
};
void generateTestSignal(std::vector<float>& signal, int sampleRate, float frequency = 1000.0f) {
for (size_t i = 0; i < signal.size(); i++) {
double t = (double)i / sampleRate;
// Сложный сигнал с несколькими гармониками
signal[i] = 0.6f * sin(2 * M_PI * frequency * t) +
0.3f * sin(2 * M_PI * frequency * 2 * t) +
0.1f * sin(2 * M_PI * frequency * 3 * t) +
0.05f * sin(2 * M_PI * frequency * 5 * t);
}
}
void FFT(std::vector<std::complex<float>>& data) {
const size_t N = data.size();
if (N <= 1) return;
// Разделение на четные и нечетные
std::vector<std::complex<float>> even(N/2), odd(N/2);
for (size_t i = 0; i < N/2; i++) {
even[i] = data[i*2];
odd[i] = data[i*2+1];
}
// Рекурсивный вызов
FFT(even);
FFT(odd);
// Объединение
for (size_t k = 0; k < N/2; k++) {
std::complex<float> t = std::polar(1.0f, -2.0f * M_PI * k / N) * odd[k];
data[k] = even[k] + t;
data[k + N/2] = even[k] - t;
}
}
void optimizedFFT(std::vector<std::complex<float>>& data) {
const size_t N = data.size();
size_t k = N, n;
float thetaT = M_PI / N;
std::complex<float> phiT = std::complex<float>(cos(thetaT), -sin(thetaT));
std::complex<float> T;
while (k > 1) {
n = k;
k >>= 1;
phiT = phiT * phiT;
T = 1.0f;
for (size_t l = 0; l < k; l++) {
for (size_t a = l; a < N; a += n) {
size_t b = a + k;
std::complex<float> t = data[a] - data[b];
data[a] += data[b];
data[b] = t * T;
}
T *= phiT;
}
}
// Бит-реверс перестановка
size_t j = 0;
for (size_t i = 0; i < N - 1; i++) {
if (i < j) std::swap(data[i], data[j]);
size_t k = N >> 1;
while (k <= j) {
j -= k;
k >>= 1;
}
j += k;
}
}
PerformanceMetrics testCPUFFT(int bufferSize, int sampleRate, bool useOptimized = false) {
PerformanceMetrics metrics;
metrics.bufferSize = bufferSize;
metrics.testType = useOptimized ? "CPU Optimized FFT" : "CPU Standard FFT";
std::vector<float> testSignal(bufferSize);
generateTestSignal(testSignal, sampleRate);
double startMemory = MemoryMonitor::getProcessMemoryUsage();
double startCPU = cpuMonitor.getCurrentCPUUsage();
double startTime = timer.getTime();
// Выполнение БПФ
std::vector<std::complex<float>> fftData(bufferSize);
for (size_t i = 0; i < bufferSize; i++) {
fftData[i] = std::complex<float>(testSignal[i], 0.0f);
}
double fftStartTime = timer.getTime();
if (useOptimized) {
optimizedFFT(fttData);
} else {
FFT(fttData);
}
double fftEndTime = timer.getTime();
double endTime = timer.getTime();
double endCPU = cpuMonitor.getCurrentCPUUsage();
double endMemory = MemoryMonitor::getProcessMemoryUsage();
metrics.totalTime = (endTime - startTime) * 1000; // мс
metrics.fftTime = (fftEndTime - fftStartTime) * 1000; // мс
metrics.cpuUsage = (startCPU + endCPU) / 2.0;
metrics.memoryUsage = (startMemory + endMemory) / 2.0;
metrics.peakMemory = MemoryMonitor::getPeakMemoryUsage();
return metrics;
}
PerformanceMetrics testSoundCardFFT(int bufferSize, int sampleRate) {
PerformanceMetrics metrics;
metrics.bufferSize = bufferSize;
metrics.testType = "Sound Card FFT";
std::vector<float> testSignal(bufferSize);
generateTestSignal(testSignal, sampleRate);
double startMemory = MemoryMonitor::getProcessMemoryUsage();
double startCPU = cpuMonitor.getCurrentCPUUsage();
double startTime = timer.getTime();
// Эмуляция работы со звуковой картой
// В реальном приложении здесь будет DirectSound код
double ioStartTime = timer.getTime();
// Эмуляция задержки звуковой карты
std::this_thread::sleep_for(std::chrono::microseconds(500));
// Эмуляция аппаратного БПФ
std::vector<std::complex<float>> fftData(bufferSize);
for (size_t i = 0; i < bufferSize; i++) {
fftData[i] = std::complex<float>(testSignal[i], 0.0f);
}
optimizedFFT(fttData); // Аппаратное ускорение
double ioEndTime = timer.getTime();
double endTime = timer.getTime();
double endCPU = cpuMonitor.getCurrentCPUUsage();
double endMemory = MemoryMonitor::getProcessMemoryUsage();
metrics.totalTime = (endTime - startTime) * 1000; // мс
metrics.iOTime = (ioEndTime - ioStartTime) * 1000; // мс
metrics.cpuUsage = (startCPU + endCPU) / 2.0;
metrics.memoryUsage = (startMemory + endMemory) / 2.0;
metrics.peakMemory = MemoryMonitor::getPeakMemoryUsage();
return metrics;
}
void runComparativeAnalysis() {
const int sizes[] = {256, 512, 1024, 2048, 4096, 8192, 16384};
const int sampleRate = 44100;
const int iterations = 5;
std::cout << "==================================================================================" << std::endl;
std::cout << " СРАВНИТЕЛЬНЫЙ АНАЛИЗ ПРОИЗВОДИТЕЛЬНОСТИ" << std::endl;
std::cout << "==================================================================================" << std::endl;
std::cout << std::setw(8) << "Размер" << " | "
<< std::setw(18) << "Тип теста" << " | "
<< std::setw(10) << "Время(мс)" << " | "
<< std::setw(12) << "БПФ время(мс)" << " | "
<< std::setw(10) << "ЦПУ(%)" << " | "
<< std::setw(10) << "Память(МБ)" << " | "
<< std::setw(12) << "Пик память(МБ)" << std::endl;
std::cout << "----------------------------------------------------------------------------------" << std::endl;
for (int size : sizes) {
// Тест стандартного БПФ на ЦПУ
PerformanceMetrics cpuStd = testCPUFFT(size, sampleRate, false);
printMetrics(cpuStd);
// Тест оптимизированного БПФ на ЦПУ
PerformanceMetrics cpuOpt = testCPUFFT(size, sampleRate, true);
printMetrics(cpuOpt);
// Тест звуковой карты
PerformanceMetrics soundCard = testSoundCardFFT(size, sampleRate);
printMetrics(soundCard);
std::cout << "----------------------------------------------------------------------------------" << std::endl;
// Небольшая пауза между тестами
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
void printMetrics(const PerformanceMetrics& metrics) {
std::cout << std::setw(8) << metrics.bufferSize << " | "
<< std::setw(18) << metrics.testType << " | "
<< std::setw(10) << std::fixed << std::setprecision(3) << metrics.totalTime << " | "
<< std::setw(12) << std::fixed << std::setprecision(3) << metrics.fftTime << " | "
<< std::setw(10) << std::fixed << std::setprecision(1) << metrics.cpuUsage << " | "
<< std::setw(10) << std::fixed << std::setprecision(1) << (metrics.memoryUsage / 1024) << " | "
<< std::setw(12) << std::fixed << std::setprecision(1) << (metrics.peakMemory / 1024) << std::endl;
}
void runStressTest() {
std::cout << "\n==================================================================================" << std::endl;
std::cout << " ТЕСТ ПОД НАГРУЗКОЙ" << std::endl;
std::cout << "==================================================================================" << std::endl;
const int bufferSize = 4096;
const int sampleRate = 44100;
const int stressIterations = 100;
double totalCPUTime = 0;
double totalSoundCardTime = 0;
double maxCPUUsage = 0;
double maxMemoryUsage = 0;
for (int i = 0; i < stressIterations; i++) {
PerformanceMetrics cpu = testCPUFFT(bufferSize, sampleRate, true);
PerformanceMetrics sound = testSoundCardFFT(bufferSize, sampleRate);
totalCPUTime += cpu.totalTime;
totalSoundCardTime += sound.totalTime;
maxCPUUsage = std::max(maxCPUUsage, cpu.cpuUsage);
maxMemoryUsage = std::max(maxMemoryUsage, cpu.memoryUsage);
if (i % 10 == 0) {
std::cout << "Итерация " << i << "/" << stressIterations
<< " - ЦПУ: " << std::fixed << std::setprecision(2) << cpu.totalTime << "мс"
<< ", Зв.карта: " << sound.totalTime << "мс" << std::endl;
}
}
std::cout << "\nРЕЗУЛЬТАТЫ ТЕСТА ПОД НАГРУЗКОЙ:" << std::endl;
std::cout << "Среднее время ЦПУ: " << std::fixed << std::setprecision(3)
<< (totalCPUTime / stressIterations) << " мс" << std::endl;
std::cout << "Среднее время звуковой карты: " << (totalSoundCardTime / stressIterations) << " мс" << std::endl;
std::cout << "Максимальная загрузка ЦПУ: " << std::fixed << std::setprecision(1)
<< maxCPUUsage << "%" << std::endl;
std::cout << "Максимальное использование памяти: " << std::fixed << std::setprecision(1)
<< (maxMemoryUsage / 1024) << " МБ" << std::endl;
double speedup = totalCPUTime / totalSoundCardTime;
std::cout << "Ускорение звуковой карты: " << std::fixed << std::setprecision(2)
<< speedup << "x" << std::endl;
}
};
int main() {
SetConsoleOutputCP(CP_UTF8);
std::cout << "Запуск теста производительности БПФ..." << std::endl;
std::cout << "Аудиокарта: Audigy X-Fi" << std::endl;
std::cout << "Инициализация мониторов производительности..." << std::endl;
FourierTest tester;
// Запуск сравнительного анализа
tester.runComparativeAnalysis();
// Запуск теста под нагрузкой
tester.runStressTest();
std::cout << "\nТестирование завершено. Нажмите Enter для выхода...";
std::cin.get();
return 0;
}