working memory tracking utility
parent
7f65b75491
commit
a259b09a7e
|
@ -0,0 +1,37 @@
|
||||||
|
module.exports = {
|
||||||
|
"ecmaFeatures": {
|
||||||
|
"modules": true,
|
||||||
|
"spread" : true,
|
||||||
|
"restParams" : true
|
||||||
|
},
|
||||||
|
// "plugins": [
|
||||||
|
// "unicorn"
|
||||||
|
// ],
|
||||||
|
"env": {
|
||||||
|
"es6": true,
|
||||||
|
"node": true,
|
||||||
|
"mocha": true
|
||||||
|
},
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 2017,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"extends": "eslint:recommended",
|
||||||
|
"rules": {
|
||||||
|
"indent": [
|
||||||
|
"error",
|
||||||
|
2
|
||||||
|
],
|
||||||
|
// "unicorn/no-array-instanceof": "error",
|
||||||
|
"no-console": 0,
|
||||||
|
"semi": ["error", "never"],
|
||||||
|
"linebreak-style": [
|
||||||
|
"error",
|
||||||
|
"unix"
|
||||||
|
],
|
||||||
|
"quotes": [
|
||||||
|
"error",
|
||||||
|
"single"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
/node_modules/
|
||||||
|
/coverage/
|
|
@ -0,0 +1,5 @@
|
||||||
|
tests/
|
||||||
|
test/
|
||||||
|
*.test.js
|
||||||
|
testing/
|
||||||
|
examples/
|
|
@ -0,0 +1,22 @@
|
||||||
|
import Memory from '../src/memory.js'
|
||||||
|
|
||||||
|
const mem = new Memory({db:0})
|
||||||
|
|
||||||
|
// let text
|
||||||
|
// mem.watch(console.log)
|
||||||
|
|
||||||
|
mem.watch()
|
||||||
|
|
||||||
|
setInterval(()=>
|
||||||
|
mem.emit('tick')
|
||||||
|
,5000)
|
||||||
|
|
||||||
|
mem.on('tick',()=> {
|
||||||
|
mem.log({msg:'testing'})
|
||||||
|
let text
|
||||||
|
for (let i = 0; i < 1000000; i++) {
|
||||||
|
text += 'a'
|
||||||
|
}
|
||||||
|
mem.text = text
|
||||||
|
console.log('memory that text is using', mem.sizeof(mem.text),mem.sizeof(text), 'M')
|
||||||
|
})
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"ignore":["examples/*.json"]
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"name": "@uci-utils/memory",
|
||||||
|
"version": "0.1.4",
|
||||||
|
"description": "memory logger and watcher",
|
||||||
|
"main": "src/memory.js",
|
||||||
|
"scripts": {
|
||||||
|
"example": "node -r esm examples/example",
|
||||||
|
"example:dev": "./node_modules/.bin/nodemon -r esm examples/example"
|
||||||
|
},
|
||||||
|
"author": "David Kebler",
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/uCOMmandIt/.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"node.js"
|
||||||
|
],
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/uCOMmandIt/uci-utils/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/uCOMmandIt/uci-utils#readme",
|
||||||
|
"dependencies": {
|
||||||
|
"debounce-fn": "^4.0.0",
|
||||||
|
"exact-math": "^2.2.0",
|
||||||
|
"gc-stats": "^1.4.0",
|
||||||
|
"object-sizeof": "^1.6.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"esm": "^3.2.25",
|
||||||
|
"nodemon": "^2.0.4"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
# uCOMmandIt Reactive Class
|
||||||
|
|
||||||
|
A Great Class to Extend! It has built in support to make reactive any/all class properties and their nested leaves.
|
||||||
|
|
||||||
|
## Why?
|
||||||
|
|
||||||
|
To have reactivity similar to vue and react but in any backend object?
|
||||||
|
This allow a backend app to maintain app settings and allow "clients" to get updated values when the app changes state. Essentially will create a 'mini' state event bus.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
Will both emit and allow subscriptions to any property 'path' that has been made reactive.
|
||||||
|
|
||||||
|
Allows custom registration of unlimited state change event hooks.
|
||||||
|
|
||||||
|
Allows additional rxjs operators for the pipe the observer for each property.
|
||||||
|
|
||||||
|
See Examples folder
|
|
@ -0,0 +1,131 @@
|
||||||
|
import EventEmitter from 'events'
|
||||||
|
import gc from 'gc-stats'
|
||||||
|
import _ from 'exact-math'
|
||||||
|
import dbfn from 'debounce-fn'
|
||||||
|
import sizeof from 'object-sizeof'
|
||||||
|
import { getHeapStatistics } from 'v8'
|
||||||
|
|
||||||
|
const STATS =
|
||||||
|
{
|
||||||
|
total_heap_size: 'byte',
|
||||||
|
total_heap_size_executable: 'byte',
|
||||||
|
total_physical_size: 'byte',
|
||||||
|
total_available_size: 'byte',
|
||||||
|
used_heap_size: 'byte',
|
||||||
|
heap_size_limit: 'byte',
|
||||||
|
malloced_memory: 'byte',
|
||||||
|
peak_malloced_memory: 'byte',
|
||||||
|
does_zap_garbage: 'boolean',
|
||||||
|
number_of_native_contexts: 'val',
|
||||||
|
number_of_detached_contexts: 'val'
|
||||||
|
}
|
||||||
|
|
||||||
|
const PROPS = Object.keys(STATS)
|
||||||
|
|
||||||
|
class Memory extends EventEmitter {
|
||||||
|
constructor(opts={}) {
|
||||||
|
super()
|
||||||
|
this._props = Object.keys(this.stats)
|
||||||
|
this._diff = {}
|
||||||
|
PROPS.forEach(prop=>this._diff[prop]={})
|
||||||
|
this._current = this.get()
|
||||||
|
this.db = opts.db || 3000
|
||||||
|
this.reset()
|
||||||
|
this.last = this.first
|
||||||
|
this.gc = gc()
|
||||||
|
}
|
||||||
|
|
||||||
|
get stats () {
|
||||||
|
return getHeapStatistics()
|
||||||
|
}
|
||||||
|
|
||||||
|
sizeof (obj, u='M') {
|
||||||
|
return mb(sizeof(obj))
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
this.first=this.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
get() {
|
||||||
|
const mem = this.stats
|
||||||
|
PROPS.forEach(prop => {
|
||||||
|
if (STATS[prop] === 'byte') mem[prop] = mb(mem[prop],2)
|
||||||
|
})
|
||||||
|
return mem
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshot() {
|
||||||
|
this.last=Object.assign({},this._current)
|
||||||
|
this._current=this.get()
|
||||||
|
this.remaining = _.sub(this._current.heap_size_limit,this._current.used_heap_size)
|
||||||
|
PROPS.forEach(prop => {
|
||||||
|
if (STATS[prop] !== 'boolean') {
|
||||||
|
this._diff[prop].last = _.sub(this._current[prop],this.last[prop])
|
||||||
|
this._diff[prop].overall=_.sub(this._current[prop],this.first[prop])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return { remaining:this.remaining, first:this.first, last:this.last, current:this._current, diff:this._diff }
|
||||||
|
}
|
||||||
|
|
||||||
|
log (opts) {
|
||||||
|
this.snapshot()
|
||||||
|
console.log(`============= ${opts.msg||''} =====================`,new Date().toLocaleString())
|
||||||
|
console.log(`remaining Heap: ${this.remaining} mb`)
|
||||||
|
console.log(this._log('used_heap_size'))
|
||||||
|
console.log(this._log('number_of_native_contexts'))
|
||||||
|
console.log(`============= ${opts.msg||''} =====================`)
|
||||||
|
}
|
||||||
|
|
||||||
|
_log (prop) {
|
||||||
|
return `${prop} > \
|
||||||
|
diff:${this._diff[prop].overall}, \
|
||||||
|
lastdiff:${this._diff[prop].last}, \
|
||||||
|
current:${this._current[prop]}, \
|
||||||
|
last:${this.last[prop]}, \
|
||||||
|
first:${this.first[prop]}, \
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
// totalHeapSize: 17911808,
|
||||||
|
// totalHeapExecutableSize: 573440,
|
||||||
|
// usedHeapSize: 13410032,
|
||||||
|
// heapSizeLimit: 2197815296,
|
||||||
|
// totalPhysicalSize: 17675040,
|
||||||
|
// totalAvailableSize: 2184093576,
|
||||||
|
// mallocedMemory: 8192,
|
||||||
|
// peakMallocedMemory: 897248,
|
||||||
|
// numberOfNativeContexts: 3,
|
||||||
|
// numberOfDetachedContexts: 0
|
||||||
|
|
||||||
|
watch (handler) {
|
||||||
|
gc().on('stats', dbfn(
|
||||||
|
stats => {
|
||||||
|
const diff = _.sub(stats.after.heapSizeLimit,stats.after.usedHeapSize)
|
||||||
|
if (stats.gctype > 0) {
|
||||||
|
if (!handler) {
|
||||||
|
console.log(stats.gctype,'----------- Heap at GC ------------',new Date().toLocaleString())
|
||||||
|
console.log(`Heap> \
|
||||||
|
remaining: ${mb(diff)} mb \
|
||||||
|
before:${mb(stats.before.usedHeapSize)}, \
|
||||||
|
after:${mb(stats.after.usedHeapSize)} mb, \
|
||||||
|
diff:${mb(stats.diff.usedHeapSize)} mb \
|
||||||
|
`)
|
||||||
|
console.log('-----------------------')
|
||||||
|
}
|
||||||
|
else handler(stats)
|
||||||
|
}},
|
||||||
|
{wait:this.db}
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
} // end class
|
||||||
|
|
||||||
|
function mb (val,p=2) {
|
||||||
|
// console.log(val,val / 1024 / 1024, _.round(val / 1024 / 1024, -p) )
|
||||||
|
return _.round(val / 1024 / 1024, -p)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Memory
|
||||||
|
export { Memory }
|
Loading…
Reference in New Issue