97 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			97 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| #!/usr/bin/env node
 | ||
| 
 | ||
| import autocannon from 'autocannon';
 | ||
| 
 | ||
| const API_URL = process.env.API_URL || 'http://127.0.0.1:4000';
 | ||
| const QUERIES = [
 | ||
|   '*',
 | ||
|   'tag:work notes',
 | ||
|   'path:Projects file:readme',
 | ||
|   'obsidian search',
 | ||
|   'tag:dev path:Projects'
 | ||
| ];
 | ||
| 
 | ||
| console.log('🚀 Starting Meilisearch search benchmark...');
 | ||
| console.log(`API URL: ${API_URL}`);
 | ||
| console.log(`Queries to test: ${QUERIES.length}\n`);
 | ||
| 
 | ||
| async function benchQuery(query) {
 | ||
|   const encodedQuery = encodeURIComponent(query);
 | ||
|   const url = `${API_URL}/api/search?q=${encodedQuery}`;
 | ||
|   
 | ||
|   console.log(`\n📊 Benchmarking: "${query}"`);
 | ||
|   console.log(`URL: ${url}`);
 | ||
|   
 | ||
|   return new Promise((resolve, reject) => {
 | ||
|     autocannon(
 | ||
|       {
 | ||
|         url,
 | ||
|         connections: 20,
 | ||
|         duration: 10,
 | ||
|         pipelining: 1
 | ||
|       },
 | ||
|       (err, result) => {
 | ||
|         if (err) {
 | ||
|           reject(err);
 | ||
|           return;
 | ||
|         }
 | ||
|         
 | ||
|         console.log(`\n✅ Results for "${query}":`);
 | ||
|         console.log(`  Average:     ${result.latency.mean.toFixed(2)} ms`);
 | ||
|         console.log(`  Median (P50): ${result.latency.p50.toFixed(2)} ms`);
 | ||
|         console.log(`  P95:         ${result.latency.p95.toFixed(2)} ms`);
 | ||
|         console.log(`  P99:         ${result.latency.p99.toFixed(2)} ms`);
 | ||
|         console.log(`  Requests/sec: ${result.requests.average.toFixed(2)}`);
 | ||
|         console.log(`  Total requests: ${result.requests.total}`);
 | ||
|         
 | ||
|         resolve({
 | ||
|           query,
 | ||
|           latency: result.latency,
 | ||
|           requests: result.requests
 | ||
|         });
 | ||
|       }
 | ||
|     );
 | ||
|   });
 | ||
| }
 | ||
| 
 | ||
| async function runBenchmarks() {
 | ||
|   const results = [];
 | ||
|   
 | ||
|   for (const query of QUERIES) {
 | ||
|     try {
 | ||
|       const result = await benchQuery(query);
 | ||
|       results.push(result);
 | ||
|     } catch (err) {
 | ||
|       console.error(`\n❌ Failed to benchmark "${query}":`, err.message);
 | ||
|     }
 | ||
|   }
 | ||
|   
 | ||
|   console.log('\n\n' + '='.repeat(60));
 | ||
|   console.log('📈 SUMMARY');
 | ||
|   console.log('='.repeat(60));
 | ||
|   
 | ||
|   for (const result of results) {
 | ||
|     console.log(`\n"${result.query}"`);
 | ||
|     console.log(`  P95: ${result.latency.p95.toFixed(2)} ms | Avg: ${result.latency.mean.toFixed(2)} ms`);
 | ||
|   }
 | ||
|   
 | ||
|   const allP95s = results.map(r => r.latency.p95);
 | ||
|   const maxP95 = Math.max(...allP95s);
 | ||
|   const avgP95 = allP95s.reduce((a, b) => a + b, 0) / allP95s.length;
 | ||
|   
 | ||
|   console.log('\n' + '='.repeat(60));
 | ||
|   console.log(`Overall P95: Avg ${avgP95.toFixed(2)} ms | Max ${maxP95.toFixed(2)} ms`);
 | ||
|   console.log('='.repeat(60));
 | ||
|   
 | ||
|   if (maxP95 < 150) {
 | ||
|     console.log('\n✅ SUCCESS: P95 < 150ms target met!');
 | ||
|   } else {
 | ||
|     console.log('\n⚠️  WARNING: P95 exceeds 150ms target');
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| runBenchmarks().catch(err => {
 | ||
|   console.error('\n💥 Benchmark suite failed:', err);
 | ||
|   process.exit(1);
 | ||
| });
 |