Sprint 3 complete: Phases 3g+3h (Steps 68-75), all 75 steps done
Phase 3g — Optimization Pipeline (17/17 tests): Step 68: TransformEngine — constant folding, dead code elimination, OptimizationLock warning Step 69: StrategyAwareOptimizer — annotation-constrained (@Reclaim allows, @Owner blocks duplication, @Deallocate blocks reorder, @Allocate blocks dynamic) Step 70: StrategyValidator — post-optimization invariants (use-after-free, leak, aliasing) Step 71: IncrementalOptimizer — transform journal, undo by ID, provenance tracking Phase 3h — Integration & Validation (26/26 tests): Step 72: Pipeline — end-to-end parse→infer→validate→optimize→generate for Python/C++ Step 73: Error handling — empty ASTs, null roots, nonexistent IDs, unannotated code Step 74: Performance benchmarks — 1000-fn AST 1ms, JSON round-trip 4ms, 50 transforms+undo 1ms Step 75: APIDocGenerator — structured docs for 23 components across 6 categories Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
252
editor/tests/step74_test.cpp
Normal file
252
editor/tests/step74_test.cpp
Normal file
@@ -0,0 +1,252 @@
|
||||
// Step 74 TDD Test: Performance profiling and benchmarks
|
||||
//
|
||||
// Tests that core operations complete efficiently:
|
||||
// 1. Large AST creation (1000 functions with body) completes quickly
|
||||
// 2. TransformEngine constant folding on large AST
|
||||
// 3. StrategyValidator on deeply nested AST
|
||||
// 4. MemoryStrategyInference on large module
|
||||
// 5. Serialization round-trip on large AST
|
||||
// 6. Multiple IncrementalOptimizer transform passes
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include "ast/ASTNode.h"
|
||||
#include "ast/Module.h"
|
||||
#include "ast/Function.h"
|
||||
#include "ast/Variable.h"
|
||||
#include "ast/Statement.h"
|
||||
#include "ast/Expression.h"
|
||||
#include "ast/Annotation.h"
|
||||
#include "ast/Serialization.h"
|
||||
#include "TransformEngine.h"
|
||||
#include "StrategyValidator.h"
|
||||
#include "MemoryStrategyInference.h"
|
||||
#include "IncrementalOptimizer.h"
|
||||
|
||||
using Clock = std::chrono::high_resolution_clock;
|
||||
|
||||
// Helper: build a function with foldable body (return A + B)
|
||||
static Function* makeFoldableFunction(int index) {
|
||||
std::string id = "f" + std::to_string(index);
|
||||
Function* fn = new Function(id, "func_" + std::to_string(index));
|
||||
|
||||
Return* ret = new Return();
|
||||
ret->id = "r" + std::to_string(index);
|
||||
BinaryOperation* binOp = new BinaryOperation("b" + std::to_string(index), "+");
|
||||
IntegerLiteral* left = new IntegerLiteral("il" + std::to_string(index), index);
|
||||
IntegerLiteral* right = new IntegerLiteral("ir" + std::to_string(index), index * 2);
|
||||
binOp->setChild("left", left);
|
||||
binOp->setChild("right", right);
|
||||
ret->setChild("value", binOp);
|
||||
fn->addChild("body", ret);
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int passed = 0;
|
||||
int failed = 0;
|
||||
|
||||
// --- Test 1: Large AST creation (1000 functions) ---
|
||||
{
|
||||
auto start = Clock::now();
|
||||
|
||||
Module mod("m1", "Benchmark", "python");
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
mod.addChild("functions", makeFoldableFunction(i));
|
||||
}
|
||||
|
||||
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
Clock::now() - start).count();
|
||||
|
||||
auto functions = mod.getChildren("functions");
|
||||
assert(functions.size() == 1000 && "Should have 1000 functions");
|
||||
assert(elapsed < 5000 && "1000 function AST creation should complete in <5s");
|
||||
|
||||
std::cout << "Test 1 PASS: Large AST creation (" << elapsed << "ms for 1000 functions)" << std::endl;
|
||||
++passed;
|
||||
|
||||
// Clean up
|
||||
for (auto* fn : functions) {
|
||||
auto body = fn->getChildren("body");
|
||||
for (auto* stmt : body) {
|
||||
auto* val = stmt->getChild("value");
|
||||
if (val && val->conceptType == "IntegerLiteral") {
|
||||
// Folded — just the literal
|
||||
} else if (val) {
|
||||
// Original BinaryOp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Test 2: Constant folding on large AST ---
|
||||
{
|
||||
Module mod("m1", "Benchmark", "python");
|
||||
for (int i = 0; i < 500; ++i) {
|
||||
mod.addChild("functions", makeFoldableFunction(i));
|
||||
}
|
||||
|
||||
auto start = Clock::now();
|
||||
|
||||
TransformEngine engine;
|
||||
engine.setRoot(&mod);
|
||||
auto result = engine.constantFolding();
|
||||
|
||||
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
Clock::now() - start).count();
|
||||
|
||||
assert(result.applied && "Should fold constants in 500 functions");
|
||||
assert(result.nodesModified >= 500 && "Should modify at least 500 nodes");
|
||||
assert(elapsed < 5000 && "Folding 500 functions should complete in <5s");
|
||||
|
||||
std::cout << "Test 2 PASS: Constant folding on 500 functions (" << elapsed << "ms, "
|
||||
<< result.nodesModified << " nodes modified)" << std::endl;
|
||||
++passed;
|
||||
}
|
||||
|
||||
// --- Test 3: StrategyValidator on deeply nested AST ---
|
||||
{
|
||||
Module mod("m1", "Benchmark", "cpp");
|
||||
Function* fn = new Function("f1", "deep");
|
||||
|
||||
DeallocateAnnotation* anno = new DeallocateAnnotation();
|
||||
anno->id = "a1";
|
||||
anno->strategy = "Explicit";
|
||||
fn->addChild("annotations", anno);
|
||||
|
||||
// Create 100 variables (potential leak sources)
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
Variable* var = new Variable("v" + std::to_string(i), "ptr" + std::to_string(i));
|
||||
fn->addChild("body", var);
|
||||
}
|
||||
mod.addChild("functions", fn);
|
||||
|
||||
auto start = Clock::now();
|
||||
|
||||
StrategyValidator validator;
|
||||
auto violations = validator.validateInvariants(&mod);
|
||||
|
||||
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
Clock::now() - start).count();
|
||||
|
||||
// Should detect leaks for all 100 variables
|
||||
int leakCount = 0;
|
||||
for (const auto& v : violations) {
|
||||
if (v.category == "leak") leakCount++;
|
||||
}
|
||||
assert(leakCount == 100 && "Should detect 100 leaked allocations");
|
||||
assert(elapsed < 5000 && "Validating 100 variables should complete in <5s");
|
||||
|
||||
std::cout << "Test 3 PASS: StrategyValidator on 100 variables (" << elapsed << "ms, "
|
||||
<< leakCount << " leaks detected)" << std::endl;
|
||||
++passed;
|
||||
}
|
||||
|
||||
// --- Test 4: MemoryStrategyInference on large module ---
|
||||
{
|
||||
Module mod("m1", "Benchmark", "cpp");
|
||||
for (int i = 0; i < 200; ++i) {
|
||||
Function* fn = new Function("f" + std::to_string(i), "func_" + std::to_string(i));
|
||||
// Add a variable to each function
|
||||
Variable* var = new Variable("v" + std::to_string(i), "data");
|
||||
fn->addChild("body", var);
|
||||
mod.addChild("functions", fn);
|
||||
}
|
||||
|
||||
auto start = Clock::now();
|
||||
|
||||
MemoryStrategyInference inferrer;
|
||||
auto suggestions = inferrer.inferAnnotations(&mod);
|
||||
|
||||
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
Clock::now() - start).count();
|
||||
|
||||
assert(!suggestions.empty() && "Should produce suggestions for C++ module");
|
||||
assert(elapsed < 5000 && "Inference on 200 functions should complete in <5s");
|
||||
|
||||
std::cout << "Test 4 PASS: MemoryStrategyInference on 200 functions (" << elapsed << "ms, "
|
||||
<< suggestions.size() << " suggestions)" << std::endl;
|
||||
++passed;
|
||||
}
|
||||
|
||||
// --- Test 5: JSON serialization round-trip on large AST ---
|
||||
{
|
||||
Module mod("m1", "Benchmark", "python");
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
mod.addChild("functions", makeFoldableFunction(i));
|
||||
}
|
||||
|
||||
auto start = Clock::now();
|
||||
|
||||
json j = toJson(&mod);
|
||||
std::string serialized = j.dump();
|
||||
|
||||
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
Clock::now() - start).count();
|
||||
|
||||
assert(!serialized.empty() && "Serialization should produce non-empty output");
|
||||
assert(serialized.size() > 1000 && "Serialized 100 functions should be >1KB");
|
||||
assert(elapsed < 5000 && "Serializing 100 functions should complete in <5s");
|
||||
|
||||
// Deserialize back
|
||||
auto start2 = Clock::now();
|
||||
json parsed = json::parse(serialized);
|
||||
ASTNode* restored = fromJson(parsed);
|
||||
auto elapsed2 = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
Clock::now() - start2).count();
|
||||
|
||||
assert(restored != nullptr && "Deserialization should produce a node");
|
||||
assert(restored->conceptType == "Module" && "Should restore a Module");
|
||||
|
||||
std::cout << "Test 5 PASS: JSON round-trip on 100 functions (serialize: " << elapsed
|
||||
<< "ms, deserialize: " << elapsed2 << "ms, " << serialized.size() << " bytes)" << std::endl;
|
||||
++passed;
|
||||
|
||||
deleteTree(restored);
|
||||
}
|
||||
|
||||
// --- Test 6: Multiple IncrementalOptimizer passes with undo ---
|
||||
{
|
||||
Module mod("m1", "Benchmark", "python");
|
||||
for (int i = 0; i < 50; ++i) {
|
||||
mod.addChild("functions", makeFoldableFunction(i));
|
||||
}
|
||||
|
||||
auto start = Clock::now();
|
||||
|
||||
IncrementalOptimizer opt;
|
||||
opt.setRoot(&mod);
|
||||
|
||||
// Apply 50 constant-fold transforms
|
||||
std::vector<std::string> transformIds;
|
||||
for (int i = 0; i < 50; ++i) {
|
||||
std::string tid = opt.applyTransform("constant-fold");
|
||||
transformIds.push_back(tid);
|
||||
}
|
||||
|
||||
auto history = opt.getTransformHistory();
|
||||
assert(history.size() == 50 && "Should have 50 transforms in history");
|
||||
|
||||
// Undo all transforms
|
||||
for (int i = 49; i >= 0; --i) {
|
||||
bool undone = opt.undoLast();
|
||||
// First undo should work, subsequent may be no-ops if nothing to fold
|
||||
}
|
||||
|
||||
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
Clock::now() - start).count();
|
||||
|
||||
assert(elapsed < 5000 && "50 transforms + undo should complete in <5s");
|
||||
|
||||
std::cout << "Test 6 PASS: 50 IncrementalOptimizer passes + undo (" << elapsed << "ms)" << std::endl;
|
||||
++passed;
|
||||
}
|
||||
|
||||
// --- Summary ---
|
||||
std::cout << "\n=== Step 74 Results: " << passed << " passed, " << failed << " failed ===" << std::endl;
|
||||
return failed > 0 ? 1 : 0;
|
||||
}
|
||||
Reference in New Issue
Block a user