test: benchmark particle-only C FastPath CPU across R layouts
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled

This commit is contained in:
tei
2026-10-11 18:02:33 +09:00
parent 1072816740
commit 32ac795fc4
10 changed files with 710 additions and 87 deletions

View File

@@ -792,16 +792,16 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
Step113PbfGateScene.Scenario.values().forEachIndexed { index, scenario ->
menu.add(0, index, index, "STEP-113 正式 PBF · ${scenario.name}")
}
menu.add(0, 10, 10, "EXPORT LAST SNAPSHOT")
menu.add(0, 11, 11, "MUTATE PROBE SOURCE ONCE")
menu.add(0, 12, 12, "EXIT STEP-113")
menu.add(0, 100, 100, "EXPORT LAST SNAPSHOT")
menu.add(0, 101, 101, "MUTATE PROBE SOURCE ONCE")
menu.add(0, 102, 102, "EXIT STEP-113")
setOnMenuItemClickListener { item ->
when (item.itemId) {
in Step113PbfGateScene.Scenario.values().indices ->
startStep113Scene(Step113PbfGateScene.Scenario.values()[item.itemId])
10 -> step113Scene?.export()
11 -> step113Scene?.mutateSource()
12 -> { stopStep113Scene(); loadValidationStyle(active, enabled, "STEP113_EXIT") }
100 -> step113Scene?.export()
101 -> step113Scene?.mutateSource()
102 -> { stopStep113Scene(); loadValidationStyle(active, enabled, "STEP113_EXIT") }
}
true
}
@@ -827,7 +827,7 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
styleReady = false
++styleLoadEpoch // Cancel previous asynchronous style callbacks.
step113Scenario = scenario
retainedCacheEnabled = true
retainedCacheEnabled = scenario != Step113PbfGateScene.Scenario.RCRR_FULL_CONTROL_NO_TIDE
updateRetainedCacheButtonState()
step113DiagnosticsHeight = diagnostics.layoutParams.height
step113DiagnosticsMaxLines = diagnostics.maxLines

View File

@@ -29,7 +29,8 @@ internal class Step113PbfGateScene(
private val display: (String) -> Unit
) {
enum class Scenario { PBF63, STATIC_RC, PARTICLE_OFF, PARTIAL_RCRR, SOURCE_CHANGE, STATIC_RC_NO_TIDE,
RCRR_C_NARROW_NO_TIDE, RCRR_C_WIDE_NO_TIDE, RCRR_R_DYNAMIC_NO_TIDE }
RCRR_C_NARROW_NO_TIDE, RCRR_C_WIDE_NO_TIDE, RCRR_R_DYNAMIC_NO_TIDE,
RCR_PARTICLE_ONLY_NO_TIDE, RCRRR_PARTICLE_ONLY_NO_TIDE, RCRR_FULL_CONTROL_NO_TIDE }
private val handler = Handler(Looper.getMainLooper())
private var generation = 0
@@ -80,7 +81,8 @@ internal class Step113PbfGateScene(
}
})
val now = SystemClock.elapsedRealtime()
if (now - lastLogMs >= 30000L) {
val summaryIntervalMs = if (isCpuBenchmark(scenario)) 6000L else 30000L
if (now - lastLogMs >= summaryIntervalMs) {
lastLogMs = now
logRecord("summary", summary(native))
}
@@ -112,7 +114,11 @@ internal class Step113PbfGateScene(
ui.isDoubleTapGesturesEnabled(), ui.isQuickZoomGesturesEnabled())
ui.setAllGesturesEnabled(false)
map.cancelTransitions()
map.setRetainedUnderlayEnabled(true)
// CPU A/B control: exactly the same style, camera, weather and RCRR plan.
// Only the retained-cache enable bit differs.
val fullControl = scenario == Scenario.RCRR_FULL_CONTROL_NO_TIDE
map.setRetainedUnderlayEnabled(!fullControl)
commandResults.put("forceFullControl", fullControl)
if (!paused) handler.post(poll)
map.setStyle(Style.Builder().fromUri(STYLE_URL)) production@ { loaded ->
if (!running || epoch != generation) return@production
@@ -190,7 +196,7 @@ internal class Step113PbfGateScene(
check(!sources.has(SOURCE)) { "天气 Source ID 冲突" }
sources.put(SOURCE, JSONObject().put("type", "raster-array").put("host-field-submission", true))
val layers = JSONArray()
val prefix = isRcrrVariant(scenario)
val prefix = isSegmentedScenario(scenario)
for (i in 0 until effectiveBase.length()) {
layers.put(effectiveBase.getJSONObject(i))
if (prefix && effectiveBase.getJSONObject(i).getString("id") == "clip-outline") addFields(layers)
@@ -230,9 +236,12 @@ internal class Step113PbfGateScene(
val plan = planJson(scenario, effectiveIds.last(), effectiveIds[clipIndex + 1])
parity.put("testPlanSelector", when (scenario) {
Scenario.PARTIAL_RCRR -> "旧RCRR缺源负对照:R0包含缺源tide,C1混合天气与大量静态PBF"
Scenario.RCRR_C_NARROW_NO_TIDE -> "RCRR窄C:仅天气;两段后续静态R"
Scenario.RCRR_C_NARROW_NO_TIDE -> "RCRR粒子独占C:WeatherColor及海图均在R"
Scenario.RCRR_C_WIDE_NO_TIDE -> "RCRR宽C:天气及部分PBF;后续静态R"
Scenario.RCRR_R_DYNAMIC_NO_TIDE -> "RCRR错误动态R:天气落R0;验证安全拒绝"
Scenario.RCRR_R_DYNAMIC_NO_TIDE -> "RCRR负例:粒子进入R,C含普通海图"
Scenario.RCR_PARTICLE_ONLY_NO_TIDE -> "RCR粒子独占C:与RCRR同Style测试缓存分段开销"
Scenario.RCRRR_PARTICLE_ONLY_NO_TIDE -> "RCRRR粒子独占C:增加R段测试分段开销"
Scenario.RCRR_FULL_CONTROL_NO_TIDE -> "与粒子独占C的RCRR同Style/Plan;缓存禁用Full CPU基线"
else -> if (hasField) "当前NavSea源码RC:rn-weather-color" else "基础63层全RETAINED"
})
.put("requestedPlan", JSONObject(plan))
@@ -382,9 +391,12 @@ internal class Step113PbfGateScene(
counts.put(JSONArray().put(g.optString("reason")).put(g.optLong("failures")).put(g.optLong("firstFailures")))
}
val rs = JSONArray()
val segmentRanges = JSONArray()
val segments = native.optJSONArray("segments") ?: JSONArray()
for (i in 0 until segments.length()) {
val s = segments.getJSONObject(i)
segmentRanges.put(JSONObject().put("strategy", s.optString("strategy"))
.put("begin", s.optInt("beginIndex")).put("end", s.optInt("endExclusive")))
val c = s.optJSONObject("cache") ?: continue
rs.put(JSONObject().put("segment", s.optInt("segmentIndex")).put("begin", s.optInt("beginIndex"))
.put("end", s.optInt("endExclusive")).put("state", c.optString("cacheState"))
@@ -397,6 +409,7 @@ internal class Step113PbfGateScene(
.put("placementGatePassed", s.optBoolean("placementGatePassed"))
}
return JSONObject().put("schema", "step113-summary").put("schemaVersion", 1).put("scenario", scenario.name)
.put("sampleElapsedMs", SystemClock.elapsedRealtime())
.put("sceneReady", ready).put("blockedReason", failureReason ?: JSONObject.NULL)
.put("sceneGeneration", generation).put("full113Equivalent", false).put("basePreserved", parity.optBoolean("baseLayersPreserved"))
.put("originalBaseLayerCount", parity.optInt("baseLayerCount"))
@@ -415,7 +428,7 @@ internal class Step113PbfGateScene(
.put("processSimulationAdvance", lastPost(native)?.opt("processSimulationAdvance") ?: JSONObject.NULL)
.put("overwritten", t.optLong("overwritten")).put("decisionMismatch", t.optLong("decisionMismatch"))
.put("fullRendered", t.optLong("fullRendered")).put("fastRendered", t.optLong("fastRendered"))
.put("gateFailureCounts", counts).put("retained", rs)
.put("gateFailureCounts", counts).put("segmentRanges", segmentRanges).put("retained", rs)
.put("commands", JSONObject(commandResults.toString()))
.put("sources", native.optJSONArray("sources") ?: JSONArray())
.put("placementChanged", native.optBoolean("placementChanged"))
@@ -503,13 +516,19 @@ internal class Step113PbfGateScene(
private const val ANNOTATION_LAYER = "org.maplibre.annotations.points"
private const val FORECAST_MS = 1786060800000L
private fun isRcrrVariant(s: Scenario): Boolean = s == Scenario.PARTIAL_RCRR ||
private fun isSegmentedScenario(s: Scenario): Boolean = s == Scenario.PARTIAL_RCRR ||
s == Scenario.RCRR_C_NARROW_NO_TIDE || s == Scenario.RCRR_C_WIDE_NO_TIDE ||
s == Scenario.RCRR_R_DYNAMIC_NO_TIDE
s == Scenario.RCRR_R_DYNAMIC_NO_TIDE || s == Scenario.RCR_PARTICLE_ONLY_NO_TIDE ||
s == Scenario.RCRRR_PARTICLE_ONLY_NO_TIDE || s == Scenario.RCRR_FULL_CONTROL_NO_TIDE
private fun isCpuBenchmark(s: Scenario): Boolean = s == Scenario.RCRR_C_NARROW_NO_TIDE ||
s == Scenario.RCR_PARTICLE_ONLY_NO_TIDE || s == Scenario.RCRRR_PARTICLE_ONLY_NO_TIDE ||
s == Scenario.RCRR_FULL_CONTROL_NO_TIDE
private fun isNoTideVariant(s: Scenario): Boolean = s == Scenario.STATIC_RC_NO_TIDE ||
s == Scenario.RCRR_C_NARROW_NO_TIDE || s == Scenario.RCRR_C_WIDE_NO_TIDE ||
s == Scenario.RCRR_R_DYNAMIC_NO_TIDE
s == Scenario.RCRR_R_DYNAMIC_NO_TIDE || s == Scenario.RCR_PARTICLE_ONLY_NO_TIDE ||
s == Scenario.RCRRR_PARTICLE_ONLY_NO_TIDE || s == Scenario.RCRR_FULL_CONTROL_NO_TIDE
private fun planJson(s: Scenario, finalBaseId: String, firstAfterClipId: String): String {
val segments = JSONArray().put(JSONObject().put("strategy", "RETAINED"))
@@ -517,14 +536,27 @@ internal class Step113PbfGateScene(
val continuousStart = when (s) {
Scenario.PARTIAL_RCRR, Scenario.RCRR_C_WIDE_NO_TIDE -> "sea-area-fill"
Scenario.RCRR_R_DYNAMIC_NO_TIDE -> firstAfterClipId
else -> COLOR
else -> if (s == Scenario.RCRR_C_NARROW_NO_TIDE ||
s == Scenario.RCR_PARTICLE_ONLY_NO_TIDE ||
s == Scenario.RCRRR_PARTICLE_ONLY_NO_TIDE ||
s == Scenario.RCRR_FULL_CONTROL_NO_TIDE) PARTICLE else COLOR
}
segments.put(JSONObject().put("strategy", "CONTINUOUS").put("startLayerId", continuousStart))
if (isRcrrVariant(s)) {
val upperRetainedStart = if (s == Scenario.RCRR_C_NARROW_NO_TIDE)
if (isSegmentedScenario(s)) {
val particleOnlyC = s == Scenario.RCRR_C_NARROW_NO_TIDE ||
s == Scenario.RCR_PARTICLE_ONLY_NO_TIDE ||
s == Scenario.RCRRR_PARTICLE_ONLY_NO_TIDE ||
s == Scenario.RCRR_FULL_CONTROL_NO_TIDE
val upperRetainedStart = if (particleOnlyC)
firstAfterClipId else "special-pattern-line-754"
segments.put(JSONObject().put("strategy", "RETAINED").put("startLayerId", upperRetainedStart))
segments.put(JSONObject().put("strategy", "RETAINED").put("startLayerId", finalBaseId))
if (s == Scenario.RCRRR_PARTICLE_ONLY_NO_TIDE) {
segments.put(JSONObject().put("strategy", "RETAINED")
.put("startLayerId", "special-pattern-line-754"))
}
if (s != Scenario.RCR_PARTICLE_ONLY_NO_TIDE) {
segments.put(JSONObject().put("strategy", "RETAINED").put("startLayerId", finalBaseId))
}
}
}
return JSONObject().put("schemaVersion", 1).put("segments", segments).toString()