const fs = require('fs'); const path = require('path'); const readline = require('readline'); const seedrandom = require('seedrandom'); let RNG; class GPSData { constructor(gpsTracesFilePath) { this.tracks = {}; this.coordinates = []; this.trackIds = []; this._loadGPSTraces(gpsTracesFilePath); } _loadGPSTraces(gpsTracesFilePath) { const expandedPath = path.resolve(gpsTracesFilePath); const data = fs.readFileSync(expandedPath, 'utf-8'); const lines = data.split('\n'); const headers = lines[0].split(','); const latitudeIndex = headers.indexOf('Latitude'); const longitudeIndex = headers.indexOf('Longitude'); const trackIdIndex = headers.indexOf('TrackID'); for (let i = 1; i < lines.length; i++) { if (lines[i].trim() === '') continue; const row = lines[i].split(','); const latitude = parseFloat(row[latitudeIndex]); const longitude = parseFloat(row[longitudeIndex]); const trackId = row[trackIdIndex]; const coord = [longitude, latitude]; this.coordinates.push(coord); if (!this.tracks[trackId]) { this.tracks[trackId] = []; } this.tracks[trackId].push(coord); } this.trackIds = Object.keys(this.tracks); } getRandomCoordinate() { const randomIndex = Math.floor(RNG() * this.coordinates.length); return this.coordinates[randomIndex]; } getRandomTrack() { const randomIndex = Math.floor(RNG() * this.trackIds.length); const trackId = this.trackIds[randomIndex]; return this.tracks[trackId]; } }; async function runOSRMMethod(osrm, method, coordinates) { const time = await new Promise((resolve, reject) => { const startTime = process.hrtime(); osrm[method]({coordinates}, (err, result) => { if (err) { if (['NoSegment', 'NoMatch', 'NoRoute', 'NoTrips'].includes(err.message)) { resolve(null); } else { reject(err); } } else { const endTime = process.hrtime(startTime); resolve(endTime[0] + endTime[1] / 1e9); } }); }); return time; } async function nearest(osrm, gpsData) { const times = []; for (let i = 0; i < 1000; i++) { const coord = gpsData.getRandomCoordinate(); times.push(await runOSRMMethod(osrm, 'nearest', [coord])); } return times; } async function route(osrm, gpsData) { const times = []; for (let i = 0; i < 1000; i++) { const from = gpsData.getRandomCoordinate(); const to = gpsData.getRandomCoordinate(); times.push(await runOSRMMethod(osrm, 'route', [from, to])); } return times; } async function table(osrm, gpsData) { const times = []; for (let i = 0; i < 250; i++) { const numPoints = Math.floor(RNG() * 3) + 15; const coordinates = []; for (let i = 0; i < numPoints; i++) { coordinates.push(gpsData.getRandomCoordinate()); } times.push(await runOSRMMethod(osrm, 'table', coordinates)); } return times; } async function match(osrm, gpsData) { const times = []; for (let i = 0; i < 1000; i++) { const numPoints = Math.floor(RNG() * 50) + 50; const coordinates = gpsData.getRandomTrack().slice(0, numPoints); times.push(await runOSRMMethod(osrm, 'match', coordinates)); } return times; } async function trip(osrm, gpsData) { const times = []; for (let i = 0; i < 250; i++) { const numPoints = Math.floor(RNG() * 2) + 5; const coordinates = []; for (let i = 0; i < numPoints; i++) { coordinates.push(gpsData.getRandomCoordinate()); } times.push(await runOSRMMethod(osrm, 'trip', coordinates)); } return times; } function bootstrapConfidenceInterval(data, numSamples = 1000, confidenceLevel = 0.95) { let means = []; let dataLength = data.length; for (let i = 0; i < numSamples; i++) { let sample = []; for (let j = 0; j < dataLength; j++) { let randomIndex = Math.floor(RNG() * dataLength); sample.push(data[randomIndex]); } let sampleMean = sample.reduce((a, b) => a + b, 0) / sample.length; means.push(sampleMean); } means.sort((a, b) => a - b); let lowerBoundIndex = Math.floor((1 - confidenceLevel) / 2 * numSamples); let upperBoundIndex = Math.floor((1 + confidenceLevel) / 2 * numSamples); let mean = means.reduce((a, b) => a + b, 0) / means.length; let lowerBound = means[lowerBoundIndex]; let upperBound = means[upperBoundIndex]; return { mean: mean, lowerBound: lowerBound, upperBound: upperBound }; } function calculateConfidenceInterval(data) { let { mean, lowerBound, upperBound } = bootstrapConfidenceInterval(data); let bestValue = Math.max(...data); let errorMargin = (upperBound - lowerBound) / 2; return { mean, errorMargin, bestValue }; } async function main() { const args = process.argv.slice(2); const {OSRM} = require(args[0]); const path = args[1]; const algorithm = args[2].toUpperCase(); const method = args[3]; const gpsTracesFilePath = args[4]; const iterations = parseInt(args[5]); const gpsData = new GPSData(gpsTracesFilePath); const osrm = new OSRM({path, algorithm}); const functions = { route: route, table: table, nearest: nearest, match: match, trip: trip }; const func = functions[method]; if (!func) { throw new Error('Unknown method'); } const allTimes = []; for (let i = 0; i < iterations; i++) { RNG = seedrandom(42); allTimes.push((await func(osrm, gpsData)).filter(t => t !== null)); } const opsPerSec = allTimes.map(times => times.length / times.reduce((a, b) => a + b, 0)); const { mean, errorMargin, bestValue } = calculateConfidenceInterval(opsPerSec); console.log(`Ops: ${mean.toFixed(1)} ± ${errorMargin.toFixed(1)} ops/s. Best: ${bestValue.toFixed(1)} ops/s`); } main();