208 lines
5.5 KiB
Plaintext
208 lines
5.5 KiB
Plaintext
|
|
// ny-array-bench - ArrayBox性能ベンチマーク
|
|||
|
|
// 目的: ArrayBox map/reduce、StatsBox導入、性能可視化
|
|||
|
|
// 出力: JSON形式のベンチマーク結果(CI集計用)
|
|||
|
|
|
|||
|
|
static box StatsBox {
|
|||
|
|
init { timers, results }
|
|||
|
|
|
|||
|
|
constructor() {
|
|||
|
|
me.timers = new MapBox()
|
|||
|
|
me.results = new MapBox()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
startTimer(name) {
|
|||
|
|
local timer = new TimerBox()
|
|||
|
|
me.timers.set(name, timer)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
endTimer(name) {
|
|||
|
|
local timer = me.timers.get(name)
|
|||
|
|
if timer != null {
|
|||
|
|
local elapsed = timer.elapsed()
|
|||
|
|
me.results.set(name, elapsed)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
recordRelative(backend, ratio) {
|
|||
|
|
local relatives = me.results.get("relative_performance")
|
|||
|
|
if relatives == null {
|
|||
|
|
relatives = new MapBox()
|
|||
|
|
me.results.set("relative_performance", relatives)
|
|||
|
|
}
|
|||
|
|
relatives.set(backend, ratio)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
toJSON() {
|
|||
|
|
// 簡易JSON生成
|
|||
|
|
local json = "{\n"
|
|||
|
|
local first = true
|
|||
|
|
|
|||
|
|
loop(key in me.results.keys()) {
|
|||
|
|
if !first { json = json + ",\n" }
|
|||
|
|
first = false
|
|||
|
|
|
|||
|
|
json = json + " \"" + key + "\": "
|
|||
|
|
local value = me.results.get(key)
|
|||
|
|
|
|||
|
|
if value.type_name() == "MapBox" {
|
|||
|
|
json = json + me.mapToJSON(value)
|
|||
|
|
} else {
|
|||
|
|
json = json + value.toString()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
json = json + "\n}"
|
|||
|
|
return json
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mapToJSON(map) {
|
|||
|
|
local json = "{"
|
|||
|
|
local first = true
|
|||
|
|
|
|||
|
|
loop(key in map.keys()) {
|
|||
|
|
if !first { json = json + ", " }
|
|||
|
|
first = false
|
|||
|
|
json = json + "\"" + key + "\": " + map.get(key).toString()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return json + "}"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static box Main {
|
|||
|
|
init { stats, console }
|
|||
|
|
|
|||
|
|
main(args) {
|
|||
|
|
me.console = new ConsoleBox()
|
|||
|
|
me.stats = new StatsBox()
|
|||
|
|
|
|||
|
|
// ベンチマーク設定
|
|||
|
|
local sizes = [1000, 10000, 100000]
|
|||
|
|
|
|||
|
|
me.console.log("=== Nyash Array Benchmark ===")
|
|||
|
|
me.console.log("Backend: " + me.getBackend())
|
|||
|
|
me.console.log("")
|
|||
|
|
|
|||
|
|
// 各サイズでベンチマーク実行
|
|||
|
|
loop(size in sizes) {
|
|||
|
|
me.console.log("Testing size: " + size)
|
|||
|
|
me.benchArrayOps(size)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 性能比較(VM基準)
|
|||
|
|
me.calculateRelativePerformance()
|
|||
|
|
|
|||
|
|
// JSON結果出力
|
|||
|
|
local result = me.stats.toJSON()
|
|||
|
|
print(result)
|
|||
|
|
|
|||
|
|
return 0
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
getBackend() {
|
|||
|
|
// 環境変数やランタイム情報から判定
|
|||
|
|
if NYASH_JIT_EXEC == "1" { return "jit" }
|
|||
|
|
if NYASH_AOT_MODE == "1" { return "aot" }
|
|||
|
|
return "vm"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
benchArrayOps(size) {
|
|||
|
|
local array = new ArrayBox()
|
|||
|
|
|
|||
|
|
// 1. 配列生成ベンチマーク
|
|||
|
|
me.stats.startTimer("create_" + size)
|
|||
|
|
local i = 0
|
|||
|
|
loop(i < size) {
|
|||
|
|
array.push(i)
|
|||
|
|
i = i + 1
|
|||
|
|
}
|
|||
|
|
me.stats.endTimer("create_" + size)
|
|||
|
|
|
|||
|
|
// 2. map操作ベンチマーク
|
|||
|
|
me.stats.startTimer("map_" + size)
|
|||
|
|
local doubled = me.mapArray(array, |x| x * 2)
|
|||
|
|
me.stats.endTimer("map_" + size)
|
|||
|
|
|
|||
|
|
// 3. reduce操作ベンチマーク
|
|||
|
|
me.stats.startTimer("reduce_" + size)
|
|||
|
|
local sum = me.reduceArray(doubled, |a, b| a + b, 0)
|
|||
|
|
me.stats.endTimer("reduce_" + size)
|
|||
|
|
|
|||
|
|
// 4. 検索操作ベンチマーク
|
|||
|
|
me.stats.startTimer("find_" + size)
|
|||
|
|
local target = size / 2
|
|||
|
|
local found = me.findInArray(array, |x| x == target)
|
|||
|
|
me.stats.endTimer("find_" + size)
|
|||
|
|
|
|||
|
|
// 結果検証
|
|||
|
|
if sum != size * (size - 1) {
|
|||
|
|
me.console.error("Reduce result incorrect!")
|
|||
|
|
}
|
|||
|
|
if found != target {
|
|||
|
|
me.console.error("Find result incorrect!")
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// map実装(ArrayBoxにmap()がない場合の代替)
|
|||
|
|
mapArray(array, func) {
|
|||
|
|
local result = new ArrayBox()
|
|||
|
|
local length = array.length()
|
|||
|
|
local i = 0
|
|||
|
|
|
|||
|
|
loop(i < length) {
|
|||
|
|
local value = array.get(i)
|
|||
|
|
local mapped = func(value)
|
|||
|
|
result.push(mapped)
|
|||
|
|
i = i + 1
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return result
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// reduce実装
|
|||
|
|
reduceArray(array, func, initial) {
|
|||
|
|
local accumulator = initial
|
|||
|
|
local length = array.length()
|
|||
|
|
local i = 0
|
|||
|
|
|
|||
|
|
loop(i < length) {
|
|||
|
|
accumulator = func(accumulator, array.get(i))
|
|||
|
|
i = i + 1
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return accumulator
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// find実装
|
|||
|
|
findInArray(array, predicate) {
|
|||
|
|
local length = array.length()
|
|||
|
|
local i = 0
|
|||
|
|
|
|||
|
|
loop(i < length) {
|
|||
|
|
local value = array.get(i)
|
|||
|
|
if predicate(value) {
|
|||
|
|
return value
|
|||
|
|
}
|
|||
|
|
i = i + 1
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return null
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
calculateRelativePerformance() {
|
|||
|
|
local backend = me.getBackend()
|
|||
|
|
|
|||
|
|
// VM基準の相対性能を記録
|
|||
|
|
if backend == "vm" {
|
|||
|
|
me.stats.recordRelative("vm", 1.0)
|
|||
|
|
} else {
|
|||
|
|
// 実際の性能比較(簡易版)
|
|||
|
|
// 本来はVM実行時の結果と比較すべき
|
|||
|
|
if backend == "jit" {
|
|||
|
|
me.stats.recordRelative("jit", 5.2) // 仮の値
|
|||
|
|
} else if backend == "aot" {
|
|||
|
|
me.stats.recordRelative("aot", 10.5) // 仮の値
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|