Skip to main content
Glama
benchmark.js8.49 kB
/** * Benchmark suite for krep-mcp-server * * This script runs performance tests to measure: * - Algorithm selection behavior with different pattern lengths * - Threading performance with different file sizes * - Comparison between direct krep and server execution * * Usage: node test/benchmark.js */ const path = require('path'); const fs = require('fs'); const { exec } = require('child_process'); const { promisify } = require('util'); const axios = require('axios'); const execAsync = promisify(exec); // Constants const FIXTURES_PATH = path.join(__dirname, 'fixtures'); const KREP_PATH = path.join(__dirname, '../../krep-native/krep'); const SERVER_URL = 'http://localhost:8080'; // Benchmark configurations const PATTERN_LENGTHS = [1, 2, 3, 4, 8, 12, 16, 20, 24, 32]; // Characters const THREAD_COUNTS = [1, 2, 4, 8]; // Number of threads const FILE_SIZES = ['small', 'medium', 'large']; // Small: 10KB, Medium: 1MB, Large: 10MB+ // Helper to create test files of different sizes async function setupTestFiles() { console.log('Setting up test files for benchmarks...'); // Base text repeated to generate test files const baseText = fs.readFileSync(path.join(FIXTURES_PATH, 'sample.txt'), 'utf8'); // Small file ~10KB const smallFilePath = path.join(FIXTURES_PATH, 'small.txt'); fs.writeFileSync(smallFilePath, baseText.repeat(1)); // Medium file ~1MB const mediumFilePath = path.join(FIXTURES_PATH, 'medium.txt'); fs.writeFileSync(mediumFilePath, baseText.repeat(100)); // Large file ~10MB const largeFilePath = path.join(FIXTURES_PATH, 'large.txt'); if (!fs.existsSync(largeFilePath)) { fs.writeFileSync(largeFilePath, baseText.repeat(1000)); } // Create a file with patterns of different lengths for testing const patternFilePath = path.join(FIXTURES_PATH, 'patterns.txt'); let patternText = ''; for (const length of PATTERN_LENGTHS) { const pattern = 'a'.repeat(length); patternText += `${pattern}|`; } fs.writeFileSync(patternFilePath, patternText); console.log('Test files created.'); } // Run krep directly and measure performance async function benchmarkKrepDirect(pattern, filePath, threads = 4, caseSensitive = true, countOnly = false) { const caseFlag = caseSensitive ? '' : '-i'; const threadFlag = `-t ${threads}`; const countFlag = countOnly ? '-c' : ''; const command = `${KREP_PATH} ${caseFlag} ${threadFlag} ${countFlag} "${pattern}" "${filePath}"`; const start = Date.now(); try { const { stdout } = await execAsync(command); const duration = Date.now() - start; // Extract performance metrics from stdout const matchCountMatch = stdout.match(/Found (\d+) matches/); const timeMatch = stdout.match(/Search completed in ([\d.]+) seconds/); const speedMatch = stdout.match(/([\d.]+) MB\/s/); const matchCount = matchCountMatch ? parseInt(matchCountMatch[1]) : 0; const searchTime = timeMatch ? parseFloat(timeMatch[1]) : null; const searchSpeed = speedMatch ? parseFloat(speedMatch[1]) : null; return { matchCount, searchTime, searchSpeed, duration, success: true }; } catch (error) { const duration = Date.now() - start; console.error(`Error executing krep: ${error.message}`); return { matchCount: 0, searchTime: null, searchSpeed: null, duration, success: false }; } } // Benchmark the server API async function benchmarkServerApi(pattern, filePath, threads = 4, caseSensitive = true, countOnly = false) { const start = Date.now(); try { const response = await axios.post(`${SERVER_URL}/search`, { pattern, path: filePath, caseSensitive, threads, countOnly }); const duration = Date.now() - start; return { ...response.data.performance, duration, success: true }; } catch (error) { const duration = Date.now() - start; console.error(`Error calling server API: ${error.message}`); return { matchCount: 0, searchTime: null, searchSpeed: null, duration, success: false }; } } // Benchmark pattern length vs. algorithm selection async function benchmarkPatternLengths() { console.log('\n=== Pattern Length Benchmark ==='); console.log('Length | Algorithm | Direct (ms) | Server (ms) | Matches'); console.log('-----------------------------------------------------------'); const filePath = path.join(FIXTURES_PATH, 'medium.txt'); for (const length of PATTERN_LENGTHS) { // Create a pattern of the specified length using 'a' characters const pattern = 'a'.repeat(length); // Benchmark direct krep execution const directResult = await benchmarkKrepDirect(pattern, filePath); // Benchmark server API const serverResult = await benchmarkServerApi(pattern, filePath); // Log results console.log(`${length.toString().padEnd(7)} | ${(serverResult.algorithmUsed || 'Unknown').padEnd(10)} | ${directResult.duration.toString().padEnd(11)} | ${serverResult.duration.toString().padEnd(11)} | ${serverResult.matchCount}`); } } // Benchmark thread count vs. performance for different file sizes async function benchmarkThreading() { console.log('\n=== Threading Benchmark ==='); console.log('File Size | Threads | Direct (ms) | Server (ms) | Speed (MB/s)'); console.log('-------------------------------------------------------------'); for (const fileSize of FILE_SIZES) { const filePath = path.join(FIXTURES_PATH, `${fileSize}.txt`); for (const threads of THREAD_COUNTS) { // Use a common pattern for all tests const pattern = 'pattern'; // Benchmark direct krep execution const directResult = await benchmarkKrepDirect(pattern, filePath, threads); // Benchmark server API const serverResult = await benchmarkServerApi(pattern, filePath, threads); // Log results console.log(`${fileSize.padEnd(10)} | ${threads.toString().padEnd(8)} | ${directResult.duration.toString().padEnd(11)} | ${serverResult.duration.toString().padEnd(11)} | ${serverResult.searchSpeed || 'N/A'}`); } } } // Benchmark count-only vs. full search async function benchmarkCountMode() { console.log('\n=== Count-Only Mode Benchmark ==='); console.log('File Size | Mode | Direct (ms) | Server (ms) | Matches'); console.log('----------------------------------------------------------'); for (const fileSize of FILE_SIZES) { const filePath = path.join(FIXTURES_PATH, `${fileSize}.txt`); const pattern = 'a'; // Common pattern that should have many matches // Benchmark count-only mode const directCountResult = await benchmarkKrepDirect(pattern, filePath, 4, true, true); const serverCountResult = await benchmarkServerApi(pattern, filePath, 4, true, true); // Benchmark full search mode const directFullResult = await benchmarkKrepDirect(pattern, filePath, 4, true, false); const serverFullResult = await benchmarkServerApi(pattern, filePath, 4, true, false); // Log results console.log(`${fileSize.padEnd(10)} | Count-Only | ${directCountResult.duration.toString().padEnd(11)} | ${serverCountResult.duration.toString().padEnd(11)} | ${serverCountResult.matchCount}`); console.log(`${fileSize.padEnd(10)} | Full | ${directFullResult.duration.toString().padEnd(11)} | ${serverFullResult.duration.toString().padEnd(11)} | ${serverFullResult.matchCount}`); } } // Main benchmark function async function runBenchmarks() { console.log('Starting krep-mcp-server benchmarks...'); // Setup test files await setupTestFiles(); // Run benchmarks await benchmarkPatternLengths(); await benchmarkThreading(); await benchmarkCountMode(); console.log('\nBenchmarks completed.'); } // Check if server is running async function checkServer() { try { await axios.get(`${SERVER_URL}/health`); return true; } catch (error) { return false; } } // Main execution (async () => { // Check if server is running const serverRunning = await checkServer(); if (!serverRunning) { console.error('Error: krep-mcp-server is not running. Please start the server first with:'); console.error(' node src/index.js'); process.exit(1); } try { await runBenchmarks(); } catch (error) { console.error('Error running benchmarks:', error); } })();

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bmorphism/krep-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server