Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
stupid-genius committed Nov 18, 2024
0 parents commit badea22
Show file tree
Hide file tree
Showing 12 changed files with 3,912 additions and 0 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/ci-master.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: CI - master

on:
push:
branches:
- master

jobs:
ci-tests:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
filter: blob:none
- name: Cache node_modules
uses: actions/cache@v3
id: tests
env:
cache-name: tests
with:
path: ./node_modules/
key: tests-${{ hashFiles('./package-lock.json') }}
restore-keys: tests-${{ hashFiles('./package-lock.json') }}
timeout-minutes: 4
- name: Install dependencies
if: steps.tests.outputs.cache-hit != true
run: npm ci
- name: Run tests
run: npm test
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*.swp
node_modules
*.log
*.log.gz
*.pem
119 changes: 119 additions & 0 deletions GCMon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
const { default: Logger } = require('log-ng');

const logger = new Logger('GCMon.js');

/**
* GC Monitor
* @description A simple garbage collector monitor
* @module GCMon
* @example
* const GCMon = require('./GCMon');
* const gcMon = new GCMon();
* const obj = Object.create(null);
* console.log(gcMon.report());
*/
function GCMon(){
if(GCMon.instance instanceof GCMon){
return GCMon.instance;
}
if(!new.target){
return new GCMon(...arguments);
}
Object.defineProperty(GCMon, 'instance', {
value: this
});

const objects = new WeakMap();
const keys = [];

const originalObjectCreate = Object.create;
const originalReflectConstruct = Reflect.construct;

// TODO figure out how to track more object creation methods
const instrumentedObjectCreate = new Proxy(Object.create, {
apply: function(target, thisArg, args){
const obj = Reflect.apply(target, thisArg, args);
objects.set(obj, {
created: new Date(),
type: obj.constructor?.name ?? 'Object (no prototype)'
});
keys.push(new WeakRef(obj));
return obj;
}
});
Object.create = instrumentedObjectCreate;

const instrumentedReflectConstruct = new Proxy(Reflect.construct, {
apply: function(target, thisArg, args){
const obj = Reflect.apply(target, thisArg, args);
objects.set(obj, {
created: new Date(),
type: obj.constructor?.name ?? 'Object (no constructor)'
});
keys.push(new WeakRef(obj));
return obj;
}
});
Reflect.construct = instrumentedReflectConstruct;

// TODO maybe utilize FinalizationRegistry to track object destruction

// TODO
// - track object access and keep stats
// - perhaps also track events and correlate, eg. objects created since last event
Object.defineProperties(this, {
report: {
value: function(){
// TODO refine the membership of each generation
const report = {
eden: [], // newly created objects
survivor: [], // objects that are ~5 mins
oldGen: [], // objects that are older and are accessed less
permGen: [] // objects that are older and are accessed a lot
};
keys.forEach((key) => {
const object = key.deref();
if(object){
const meta = objects.get(object);
const age = new Date() - meta.created;
if(age < 1000){
report.eden.push({
object,
meta
});
}else if(age < 300000){
report.survivor.push({
object,
meta
});
}else if(age > 300000){
report.oldGen.push({
object,
meta
});
}else{
logger.info('not implemented');
// report.permGen.push({
// object,
// meta
// });
}
}else{
logger.info('object has been collected');
keys.splice(keys.indexOf(key), 1);
}
});
return report;
}
},
uninstall: {
value: function(){
Object.create = originalObjectCreate;
Reflect.construct = originalReflectConstruct;
logger.info('uninstalled');
}
}
});
}

module.exports = GCMon;
4 changes: 4 additions & 0 deletions config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
logLevel: 'debug',
logFile: 'loggerTest.log'
};
105 changes: 105 additions & 0 deletions karma.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Karma configuration
// Generated on Fri Jan 05 2024 15:51:09 GMT-0500 (Eastern Standard Time)
const fs = require('fs');

module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://www.npmjs.com/search?q=keywords:karma-adapter
frameworks: ['mocha'],
// list of files / patterns to load in the browser
files: [
'spec.js'
],
// list of files / patterns to exclude
exclude: [
],
// preprocess matching files before serving them to the browser
// available preprocessors: https://www.npmjs.com/search?q=keywords:karma-preprocessor
preprocessors: {
'spec.js': ['esbuild']
},
esbuild: {
bundle: true,
// external: [],
// format: 'cjs'
// platform: 'node',
target: 'es2022'
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://www.npmjs.com/search?q=keywords:karma-reporter
reporters: ['mocha'],
// protocol: 'https:',
// web server port
port: 9876,
// httpsServerOptions: {
// key: fs.readFileSync('key.pem'),
// cert: fs.readFileSync('cert.pem'),
// },
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// loggers: [
// {type: 'console'}
// ],
client: {
// allowConsoleLogs: false,
captureConsole: true
},
// browserConsoleLogOptions: {
// level: 'log',
// format: '%b %T: %m',
// terminal: true,
// },
// enable / disable watching file and executing tests whenever any file changes
autoWatch: false,
customLaunchers: {
ChromeHeadlessSecure: {
base: 'ChromeHeadless',
flags: [
'--disable-web-security',
'--ignore-certificate-errors',
'--enable-features=SharedArrayBuffer'
]
},
FirefoxHeadlessSecure: {
base: 'Firefox',
prefs: {
// 'javascript.options.shared_memory': true,
// 'dom.postMessage.sharedArrayBuffer.withCOOP_COEP': true,
// 'security.fileuri.strict_origin_policy': false,
// 'security.fileuri.origin_policy': 'null',
// 'dom.webgpu.enabled': false,
// 'security.sandbox.content.level': 0,
// 'network.http.use-cache': false
},
flags: [
'-headless',
// '--disable-gpu',
// '--allow-insecure-localhost'
]
},
FirefoxHeadless: {
base: 'Firefox',
flags: ['-headless']
}
},
// start these browsers
// available browser launchers: https://www.npmjs.com/search?q=keywords:karma-launcher
browsers: ['ChromeHeadless', 'FirefoxHeadless'],
// browsers: ['ChromeHeadlessSecure', 'FirefoxHeadlessSecure'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: true,
// Concurrency level
// how many browser instances should be started simultaneously
concurrency: Infinity,
// browserDisconnectTimeout: 10000,
// browserNoActivityTimeout: 300000
})
}
105 changes: 105 additions & 0 deletions karma.server.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Karma configuration
// Generated on Fri Jan 05 2024 15:51:09 GMT-0500 (Eastern Standard Time)
const fs = require('fs');

module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://www.npmjs.com/search?q=keywords:karma-adapter
frameworks: ['mocha'],
// list of files / patterns to load in the browser
files: [
'spec.js'
],
// list of files / patterns to exclude
exclude: [
],
// preprocess matching files before serving them to the browser
// available preprocessors: https://www.npmjs.com/search?q=keywords:karma-preprocessor
preprocessors: {
'spec.js': ['esbuild']
},
esbuild: {
bundle: true,
// external: [],
// format: 'cjs'
// platform: 'node',
target: 'es2022'
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://www.npmjs.com/search?q=keywords:karma-reporter
reporters: ['mocha'],
// protocol: 'https:',
// web server port
port: 9876,
// httpsServerOptions: {
// key: fs.readFileSync('key.pem'),
// cert: fs.readFileSync('cert.pem'),
// },
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// loggers: [
// {type: 'console'}
// ],
client: {
// allowConsoleLogs: false,
captureConsole: true
},
// browserConsoleLogOptions: {
// level: 'log',
// format: '%b %T: %m',
// terminal: true,
// },
// enable / disable watching file and executing tests whenever any file changes
autoWatch: false,
customLaunchers: {
ChromeHeadlessSecure: {
base: 'ChromeHeadless',
flags: [
'--disable-web-security',
'--ignore-certificate-errors',
'--enable-features=SharedArrayBuffer'
]
},
FirefoxHeadlessSecure: {
base: 'Firefox',
prefs: {
// 'javascript.options.shared_memory': true,
// 'dom.postMessage.sharedArrayBuffer.withCOOP_COEP': true,
// 'security.fileuri.strict_origin_policy': false,
// 'security.fileuri.origin_policy': 'null',
// 'dom.webgpu.enabled': false,
// 'security.sandbox.content.level': 0,
// 'network.http.use-cache': false
},
flags: [
'-headless',
// '--disable-gpu',
// '--allow-insecure-localhost'
]
},
FirefoxHeadless: {
base: 'Firefox',
flags: ['-headless']
}
},
// start these browsers
// available browser launchers: https://www.npmjs.com/search?q=keywords:karma-launcher
browsers: ['ChromeHeadless', 'FirefoxHeadless'],
// browsers: ['ChromeHeadlessSecure', 'FirefoxHeadlessSecure'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: true,
// Concurrency level
// how many browser instances should be started simultaneously
concurrency: Infinity,
// browserDisconnectTimeout: 10000,
// browserNoActivityTimeout: 300000
})
}
Loading

0 comments on commit badea22

Please sign in to comment.