package iskra import "bytes" type BenchClass uint8 const ( BenchSkip BenchClass = 0 BenchSimple BenchClass = 1 BenchComplex BenchClass = 2 ) // ClassifyBenchCost determines if a function warrants benchmarking // based on its AST dump structure. func ClassifyBenchCost(astDump string, funcName string) BenchClass { data := []byte(astDump) lines := bytes.Split(data, []byte("\n")) hasLoop := false hasSwitch := false maxDepth := int32(0) blockCount := int32(0) hasSliceParam := false isRecursive := false funcNameBytes := []byte(funcName) for _, line := range lines { trimmed := bytes.TrimSpace(line) if len(trimmed) == 0 { continue } depth := indentDepth(line) if depth > maxDepth { maxDepth = depth } if bytes.HasPrefix(trimmed, []byte("For")) || bytes.HasPrefix(trimmed, []byte("Range")) { hasLoop = true } if bytes.HasPrefix(trimmed, []byte("Switch")) || bytes.HasPrefix(trimmed, []byte("Select")) { hasSwitch = true } if bytes.HasPrefix(trimmed, []byte("Block")) { blockCount++ } if bytes.HasPrefix(trimmed, []byte("Params")) { hasSliceParam = checkSliceParams(lines) } if bytes.Contains(trimmed, []byte("[")) && bytes.Contains(trimmed, funcNameBytes) { isRecursive = true } } if hasLoop || isRecursive { return BenchComplex } if hasSwitch || hasSliceParam || maxDepth > 4 || blockCount > 2 { return BenchSimple } if maxDepth <= 2 && blockCount <= 1 { return BenchSkip } return BenchSimple } func indentDepth(line []byte) int32 { d := int32(0) for _, b := range string(line) { if b == ' ' { d++ } else if b == '\t' { d += 2 } else { break } } return d / 2 } func checkSliceParams(lines [][]byte) bool { inParams := false for _, line := range lines { trimmed := bytes.TrimSpace(line) if bytes.HasPrefix(trimmed, []byte("Params")) { inParams = true continue } if inParams { if len(trimmed) > 0 && trimmed[0] != ' ' && !bytes.HasPrefix(line, []byte(" ")) { break } if bytes.Contains(trimmed, []byte("[]")) || bytes.Contains(trimmed, []byte("string")) { return true } } } return false } func (c BenchClass) String() string { switch c { case BenchSkip: return "skip" case BenchSimple: return "simple" case BenchComplex: return "complex" default: return "unknown" } }