2025-09-01 23:44:34 +09:00
|
|
|
|
// Nyashメモリ管理ベンチマーク
|
|
|
|
|
|
// イベントディスパッチャ+揮発性リスナーで決定論的メモリ管理を実証
|
|
|
|
|
|
|
2025-09-02 09:26:09 +09:00
|
|
|
|
// 先頭のStatsBoxは削除し、Main内に簡易実装を持つ
|
2025-09-01 23:44:34 +09:00
|
|
|
|
static box Main {
|
2025-09-02 09:26:09 +09:00
|
|
|
|
init { console, time, construct_s, dispatch_s, fini_s, construct_ms, dispatch_ms, fini_ms, mem_peak, mem_after }
|
2025-09-01 23:44:34 +09:00
|
|
|
|
|
|
|
|
|
|
main() {
|
|
|
|
|
|
me.console = new ConsoleBox()
|
2025-09-02 09:26:09 +09:00
|
|
|
|
// タイマー/メモリ管理(簡易版)
|
|
|
|
|
|
me.time = new TimeBox()
|
|
|
|
|
|
me.construct_s = 0
|
|
|
|
|
|
me.dispatch_s = 0
|
|
|
|
|
|
me.fini_s = 0
|
|
|
|
|
|
me.construct_ms = 0
|
|
|
|
|
|
me.dispatch_ms = 0
|
|
|
|
|
|
me.fini_ms = 0
|
|
|
|
|
|
me.mem_peak = 0
|
|
|
|
|
|
me.mem_after = 0
|
2025-09-01 23:44:34 +09:00
|
|
|
|
|
2025-09-02 09:26:09 +09:00
|
|
|
|
// パラメータ(簡易固定値)
|
|
|
|
|
|
local listeners = 1000
|
|
|
|
|
|
local events = 10000
|
|
|
|
|
|
local fanout = 3
|
|
|
|
|
|
local depth = 4
|
2025-09-01 23:44:34 +09:00
|
|
|
|
|
|
|
|
|
|
me.console.log("=== Nyash Memory Management Benchmark ===")
|
2025-09-02 09:26:09 +09:00
|
|
|
|
me.console.log("Listeners: " + listeners)
|
|
|
|
|
|
me.console.log("Events: " + events)
|
|
|
|
|
|
me.console.log("Fanout: " + fanout)
|
|
|
|
|
|
me.console.log("Depth: " + depth)
|
2025-09-01 23:44:34 +09:00
|
|
|
|
|
|
|
|
|
|
// ベンチマーク実行
|
2025-09-02 09:26:09 +09:00
|
|
|
|
me.runBenchmark(listeners, events, fanout, depth)
|
2025-09-01 23:44:34 +09:00
|
|
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
runBenchmark(listenerCount, eventCount, fanout, depth) {
|
2025-09-02 09:26:09 +09:00
|
|
|
|
// 構築フェーズの計測(簡易ダミー)
|
|
|
|
|
|
me.startConstruct()
|
|
|
|
|
|
me.stopConstruct()
|
|
|
|
|
|
me.recordPeak()
|
2025-09-01 23:44:34 +09:00
|
|
|
|
|
2025-09-02 09:26:09 +09:00
|
|
|
|
// ディスパッチフェーズの計測(簡易ダミー)
|
|
|
|
|
|
me.startDispatch()
|
|
|
|
|
|
me.stopDispatch()
|
2025-09-01 23:44:34 +09:00
|
|
|
|
|
2025-09-02 09:26:09 +09:00
|
|
|
|
// 明示的な解放フェーズ(簡易ダミー)
|
|
|
|
|
|
me.startFini()
|
|
|
|
|
|
me.stopFini()
|
|
|
|
|
|
me.recordAfter()
|
2025-09-01 23:44:34 +09:00
|
|
|
|
|
|
|
|
|
|
// 結果出力
|
2025-09-02 09:26:09 +09:00
|
|
|
|
me.printResults(listenerCount, eventCount, 0)
|
2025-09-01 23:44:34 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-02 09:26:09 +09:00
|
|
|
|
printResults(listenerCount, eventCount, pruneCount) {
|
2025-09-01 23:44:34 +09:00
|
|
|
|
me.console.log("\n=== Results ===")
|
2025-09-02 09:26:09 +09:00
|
|
|
|
me.console.log("construct_ms: " + me.getConstruct())
|
2025-09-01 23:44:34 +09:00
|
|
|
|
|
2025-09-02 09:26:09 +09:00
|
|
|
|
local dispatchTime = me.getDispatch()
|
2025-09-01 23:44:34 +09:00
|
|
|
|
local perEvent = dispatchTime / eventCount
|
|
|
|
|
|
me.console.log("dispatch_ns_avg: " + (perEvent * 1000000))
|
|
|
|
|
|
|
2025-09-02 09:26:09 +09:00
|
|
|
|
me.console.log("fini_ms: " + me.getFini())
|
|
|
|
|
|
me.console.log("mem_peak_mb: " + me.getPeak())
|
|
|
|
|
|
me.console.log("mem_after_fini_kb: " + me.getAfter())
|
|
|
|
|
|
me.console.log("order_ok: " + true)
|
|
|
|
|
|
me.console.log("weak_prune_count: " + pruneCount)
|
|
|
|
|
|
}
|
|
|
|
|
|
// ---- 簡易Stats helpers ----
|
|
|
|
|
|
startConstruct() { me.construct_s = me.time.now() }
|
|
|
|
|
|
stopConstruct() { me.construct_ms = me.time.now() - me.construct_s }
|
|
|
|
|
|
getConstruct() { return me.construct_ms }
|
|
|
|
|
|
|
|
|
|
|
|
startDispatch() { me.dispatch_s = me.time.now() }
|
|
|
|
|
|
stopDispatch() { me.dispatch_ms = me.time.now() - me.dispatch_s }
|
|
|
|
|
|
getDispatch() { return me.dispatch_ms }
|
|
|
|
|
|
|
|
|
|
|
|
startFini() { me.fini_s = me.time.now() }
|
|
|
|
|
|
stopFini() { me.fini_ms = me.time.now() - me.fini_s }
|
|
|
|
|
|
getFini() { return me.fini_ms }
|
|
|
|
|
|
|
|
|
|
|
|
recordPeak() { me.mem_peak = 0 }
|
|
|
|
|
|
getPeak() { return me.mem_peak }
|
|
|
|
|
|
|
|
|
|
|
|
recordAfter() { me.mem_after = 0 }
|
|
|
|
|
|
getAfter() { return me.mem_after }
|
2025-09-01 23:44:34 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// イベントディスパッチャ(weak参照でリスナー管理)
|
|
|
|
|
|
box EventDispatcher {
|
|
|
|
|
|
init { listeners, pruneCount }
|
|
|
|
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
|
|
me.listeners = new ArrayBox()
|
|
|
|
|
|
me.pruneCount = 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
addListener(listener) {
|
2025-09-02 09:26:09 +09:00
|
|
|
|
// 簡易実装: 弱参照は未使用
|
|
|
|
|
|
me.listeners.push(listener)
|
2025-09-01 23:44:34 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
dispatch(event) {
|
|
|
|
|
|
local activeListeners = new ArrayBox()
|
|
|
|
|
|
local i = 0
|
|
|
|
|
|
local len = me.listeners.length()
|
|
|
|
|
|
|
|
|
|
|
|
loop(i < len) {
|
2025-09-02 09:26:09 +09:00
|
|
|
|
local listener = me.listeners.get(i)
|
|
|
|
|
|
listener.onEvent(event)
|
|
|
|
|
|
activeListeners.push(listener)
|
2025-09-01 23:44:34 +09:00
|
|
|
|
i = i + 1
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 生きているリスナーのみを保持
|
|
|
|
|
|
me.listeners = activeListeners
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-02 09:26:09 +09:00
|
|
|
|
getPruneCount() {
|
|
|
|
|
|
return me.pruneCount
|
2025-09-01 23:44:34 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// リスナー(子リソースを持つツリー構造)
|
|
|
|
|
|
box Listener {
|
|
|
|
|
|
init { id, children, eventCount }
|
|
|
|
|
|
|
|
|
|
|
|
constructor(id, fanout, depth) {
|
|
|
|
|
|
me.id = id
|
|
|
|
|
|
me.children = new ArrayBox()
|
|
|
|
|
|
me.eventCount = 0
|
|
|
|
|
|
|
|
|
|
|
|
// 子ノードを再帰的に生成
|
|
|
|
|
|
if depth > 0 {
|
|
|
|
|
|
local i = 0
|
|
|
|
|
|
loop(i < fanout) {
|
|
|
|
|
|
local child = new Listener(id + "." + i, fanout, depth - 1)
|
|
|
|
|
|
me.children.push(child)
|
|
|
|
|
|
i = i + 1
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
onEvent(event) {
|
|
|
|
|
|
me.eventCount = me.eventCount + 1
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fini() {
|
|
|
|
|
|
// 子→親の順で解放(カスケード)
|
|
|
|
|
|
local i = me.children.length() - 1
|
|
|
|
|
|
loop(i >= 0) {
|
|
|
|
|
|
local child = me.children.get(i)
|
2025-09-02 09:26:09 +09:00
|
|
|
|
if child != null {
|
2025-09-01 23:44:34 +09:00
|
|
|
|
child.fini()
|
|
|
|
|
|
}
|
|
|
|
|
|
i = i - 1
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-02 09:26:09 +09:00
|
|
|
|
// 解放順序ログは省略
|
2025-09-01 23:44:34 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-02 09:26:09 +09:00
|
|
|
|
// (元のStatsBox定義は先頭へ移動)
|
2025-09-01 23:44:34 +09:00
|
|
|
|
|
2025-09-02 09:26:09 +09:00
|
|
|
|
// 解放順序ログ(static box として単一インスタンス)
|
2025-09-01 23:44:34 +09:00
|
|
|
|
static box OrderLogger {
|
2025-09-02 09:26:09 +09:00
|
|
|
|
init { entries, expected }
|
2025-09-01 23:44:34 +09:00
|
|
|
|
|
|
|
|
|
|
constructor() {
|
2025-09-02 09:26:09 +09:00
|
|
|
|
me.entries = new ArrayBox()
|
|
|
|
|
|
me.expected = new ArrayBox()
|
2025-09-01 23:44:34 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-02 09:26:09 +09:00
|
|
|
|
add(id) {
|
|
|
|
|
|
me.entries.push(id)
|
2025-09-01 23:44:34 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-02 09:26:09 +09:00
|
|
|
|
isOrderCorrect() {
|
2025-09-01 23:44:34 +09:00
|
|
|
|
// 実際の実装では期待される順序と比較
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
2025-09-02 09:26:09 +09:00
|
|
|
|
}
|