class LRUCache {
cache = new Map();
maxSize;
ttl;
hits = 0;
misses = 0;
constructor(config) {
this.maxSize = config.maxSize;
this.ttl = config.ttl;
}
get(key) {
const entry = this.cache.get(key);
if (!entry) {
this.misses++;
return undefined;
}
if (Date.now() - entry.lastUsed > this.ttl) {
this.cache.delete(key);
this.misses++;
return undefined;
}
entry.lastUsed = Date.now();
entry.useCount++;
this.hits++;
return entry.value;
}
set(key, value) {
if (this.cache.size >= this.maxSize) {
this.evict();
}
this.cache.set(key, {
value,
lastUsed: Date.now(),
useCount: 1
});
}
evict() {
let oldestKey;
let oldestTime = Infinity;
for (const [key, entry] of this.cache) {
if (entry.lastUsed < oldestTime) {
oldestTime = entry.lastUsed;
oldestKey = key;
}
}
if (oldestKey !== undefined) {
this.cache.delete(oldestKey);
}
}
getHitRate() {
const total = this.hits + this.misses;
return total > 0 ? this.hits / total : 0;
}
clear() {
this.cache.clear();
this.hits = 0;
this.misses = 0;
}
size() {
return this.cache.size;
}
}
class TypedArrayPool {
pools = new Map();
allocatedBytes = 0;
releasedBytes = 0;
peakBytes = 0;
maxPoolSize = 50;
acquire(type, length) {
const bytesPerElement = this.getBytesPerElement(type);
const totalBytes = length * bytesPerElement;
const key = `${type}_${length}`;
const pool = this.pools.get(key);
if (pool && pool.length > 0) {
const buffer = pool.pop();
this.allocatedBytes += totalBytes;
this.peakBytes = Math.max(this.peakBytes, this.allocatedBytes - this.releasedBytes);
return buffer;
}
const buffer = new ArrayBuffer(totalBytes);
this.allocatedBytes += totalBytes;
this.peakBytes = Math.max(this.peakBytes, this.allocatedBytes - this.releasedBytes);
return buffer;
}
release(type, buffer) {
const length = buffer.byteLength / this.getBytesPerElement(type);
const key = `${type}_${length}`;
let pool = this.pools.get(key);
if (!pool) {
pool = [];
this.pools.set(key, pool);
}
if (pool.length < this.maxPoolSize) {
pool.push(buffer);
}
this.releasedBytes += buffer.byteLength;
}
getBytesPerElement(type) {
switch (type) {
case 'float64': return 8;
case 'uint32': return 4;
case 'uint8': return 1;
}
}
getStats() {
const poolSizes = {};
for (const [key, pool] of this.pools) {
poolSizes[key] = pool.length;
}
return {
allocated: this.allocatedBytes,
released: this.releasedBytes,
current: this.allocatedBytes - this.releasedBytes,
peak: this.peakBytes,
poolSizes
};
}
clear() {
this.pools.clear();
this.allocatedBytes = 0;
this.releasedBytes = 0;
this.peakBytes = 0;
}
}
export class MemoryStreamManager {
cache;
arrayPool;
gcCount = 0;
streamingThreshold;
constructor(cacheConfig = { maxSize: 100, ttl: 300000, evictionPolicy: 'lru' }, streamingThreshold = 1024 * 1024 * 100 ) {
this.cache = new LRUCache(cacheConfig);
this.arrayPool = new TypedArrayPool();
this.streamingThreshold = streamingThreshold;
if (typeof globalThis !== 'undefined' && 'performance' in globalThis) {
performance.onGC?.(() => this.gcCount++);
}
}
async *streamMatrixChunks(data, chunkSize, processor) {
for (let i = 0; i < data.length; i += chunkSize) {
const chunk = data.slice(i, i + chunkSize);
const cacheKey = `chunk_${i}_${chunkSize}`;
let result = this.cache.get(cacheKey);
if (!result) {
result = await processor(chunk);
this.cache.set(cacheKey, result);
}
yield result;
if (i % (chunkSize * 10) === 0) {
await new Promise(resolve => setTimeout(resolve, 0));
}
}
}
async scheduleOperation(operation, estimatedMemory) {
const currentUsage = this.getCurrentMemoryUsage();
if (currentUsage + estimatedMemory > this.streamingThreshold) {
await this.freeMemory();
}
return operation();
}
async freeMemory() {
this.cache.clear();
this.arrayPool.clear();
if (typeof globalThis !== 'undefined' && globalThis.gc) {
globalThis.gc();
}
await new Promise(resolve => setTimeout(resolve, 100));
}
getCurrentMemoryUsage() {
if (typeof globalThis !== 'undefined' && 'performance' in globalThis && 'memory' in performance) {
return performance.memory.usedJSHeapSize;
}
return this.arrayPool.getStats().current;
}
acquireTypedArray(type, length) {
const buffer = this.arrayPool.acquire(type, length);
switch (type) {
case 'float64': return new Float64Array(buffer);
case 'uint32': return new Uint32Array(buffer);
case 'uint8': return new Uint8Array(buffer);
}
}
releaseTypedArray(array) {
let type;
if (array instanceof Float64Array)
type = 'float64';
else if (array instanceof Uint32Array)
type = 'uint32';
else
type = 'uint8';
this.arrayPool.release(type, array.buffer);
}
getMemoryStats() {
const poolStats = this.arrayPool.getStats();
return {
totalAllocated: poolStats.allocated,
totalReleased: poolStats.released,
currentUsage: poolStats.current,
peakUsage: poolStats.peak,
poolStats: {
arrayPool: poolStats.poolSizes,
cacheSize: this.cache.size(),
cacheHitRate: this.cache.getHitRate()
},
gcCount: this.gcCount,
cacheHitRate: this.cache.getHitRate()
};
}
async profileOperation(name, operation) {
const startStats = this.getMemoryStats();
const startTime = performance.now();
const result = await operation();
const endTime = performance.now();
const endStats = this.getMemoryStats();
const profile = {
name,
duration: endTime - startTime,
memoryDelta: endStats.currentUsage - startStats.currentUsage,
peakMemory: endStats.peakUsage,
allocations: endStats.totalAllocated - startStats.totalAllocated,
deallocations: endStats.totalReleased - startStats.totalReleased,
cacheHitRate: endStats.cacheHitRate
};
return { result, profile };
}
optimizeCache() {
const hitRate = this.cache.getHitRate();
if (hitRate < 0.5) {
console.warn(`Low cache hit rate: ${hitRate.toFixed(2)}`);
}
}
cleanup() {
this.cache.clear();
this.arrayPool.clear();
}
}
export class SIMDMemoryOptimizer {
static SIMD_WIDTH = 4; static CACHE_LINE_SIZE = 64; static alignForSIMD(length) {
return Math.ceil(length / this.SIMD_WIDTH) * this.SIMD_WIDTH;
}
static optimizeLayout(arrays, accessPattern) {
if (accessPattern === 'row') {
return arrays;
}
else {
const rows = arrays.length;
const cols = arrays[0]?.length || 0;
const transposed = Array(cols).fill(null).map(() => Array(rows));
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
transposed[j][i] = arrays[i][j];
}
}
return transposed;
}
}
static padForCacheLines(array, padValue) {
const elementSize = 8; const elementsPerCacheLine = this.CACHE_LINE_SIZE / elementSize;
const padding = elementsPerCacheLine - (array.length % elementsPerCacheLine);
if (padding === elementsPerCacheLine) {
return array;
}
return [...array, ...Array(padding).fill(padValue)];
}
static blockMatrixMultiply(a, b, result, blockSize = 64) {
const n = a.length;
const m = b[0].length;
const p = b.length;
for (let ii = 0; ii < n; ii += blockSize) {
for (let jj = 0; jj < m; jj += blockSize) {
for (let kk = 0; kk < p; kk += blockSize) {
const iEnd = Math.min(ii + blockSize, n);
const jEnd = Math.min(jj + blockSize, m);
const kEnd = Math.min(kk + blockSize, p);
for (let i = ii; i < iEnd; i++) {
for (let j = jj; j < jEnd; j++) {
let sum = result[i][j];
for (let k = kk; k < kEnd; k++) {
sum += a[i][k] * b[k][j];
}
result[i][j] = sum;
}
}
}
}
}
}
}
export const globalMemoryManager = new MemoryStreamManager();