package unit; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; /** * CWE-407 unit test: opencv-0003 — ifInt8Output() O(N*I*L) vs O(N*I) * * Models modules/dnn/src/onnx/onnx_importer.cpp ifInt8Output(): * * slow() = static vector + std::find, O(L) per lookup * called N*I times during ONNX model import (N nodes, I inputs each) * total: O(N * I * L) * * fast() = static unordered_set, O(1) per lookup * total: O(N * I) * * L=35 (size of input8output8 list), N=1000 nodes, I=3 inputs/node * Expected ratio: >30x op-count reduction. */ public class OpenCVOnnxInt8OutputTest { static long slowOps = 0; static long fastOps = 0; // The 35-entry list from op_timvx.cpp static final List INPUT8OUTPUT8_LIST = new ArrayList<>(); static final Set INPUT8OUTPUT8_SET = new HashSet<>(); static { String[] types = { "QuantizeLinear", "QLinearAdd", "QLinearMul", "QLinearAveragePool", "QLinearGlobalAveragePool", "QLinearLeakyRelu", "QLinearSigmoid", "QLinearConcat", "QGemm", "QLinearSoftmax", "QLinearConv", "QLinearMatMul", "MaxPool", "ReduceMax", "ReduceMin", "Split", "Clip", "Abs", "Transpose", "Squeeze", "Flatten", "Unsqueeze", "Expand", "Reshape", "Pad", "Gather", "Concat", "Resize", "SpaceToDepth", "DepthToSpace", "Pow", "Add", "Sub", "Mul", "Div" }; for (String t : types) { INPUT8OUTPUT8_LIST.add(t); INPUT8OUTPUT8_SET.add(t); } } /** * Slow: O(L) linear scan per call — models std::find on static vector. */ static boolean ifInt8OutputSlow(String layerType) { for (String s : INPUT8OUTPUT8_LIST) { slowOps++; if (s.equals(layerType)) return true; } return false; } /** * Fast: O(1) hash lookup — models unordered_set::count. */ static boolean ifInt8OutputFast(String layerType) { fastOps++; return INPUT8OUTPUT8_SET.contains(layerType); } /** * Simulate ONNX populateNet(): loop over N nodes, I inputs each, * call ifInt8Output() per input. */ static void simulatePopulateNet(int nNodes, int inputsPerNode, boolean useSlow) { // Mix of types: half match, half do not String[] layerTypes = {"Conv", "Relu", "Add", "Reshape", "BatchNormalization"}; for (int n = 0; n < nNodes; n++) { String layerType = layerTypes[n % layerTypes.length]; for (int i = 0; i < inputsPerNode; i++) { if (useSlow) { ifInt8OutputSlow(layerType); } else { ifInt8OutputFast(layerType); } } } } public static void main(String[] args) { final int N_NODES = 1000; final int INPUTS_PER_NODE = 3; // Warm up simulatePopulateNet(10, 3, true); simulatePopulateNet(10, 3, false); slowOps = 0; fastOps = 0; // Measure simulatePopulateNet(N_NODES, INPUTS_PER_NODE, true); long measuredSlowOps = slowOps; slowOps = 0; simulatePopulateNet(N_NODES, INPUTS_PER_NODE, false); long measuredFastOps = fastOps; double ratio = (double) measuredSlowOps / measuredFastOps; System.out.printf("opencv-0003 ifInt8Output O(N*I*L) vs O(N*I)%n"); System.out.printf(" N=%d nodes, I=%d inputs, L=%d list entries%n", N_NODES, INPUTS_PER_NODE, INPUT8OUTPUT8_LIST.size()); System.out.printf(" slow ops (vector+find): %d%n", measuredSlowOps); System.out.printf(" fast ops (hash set): %d%n", measuredFastOps); System.out.printf(" ratio: %.1fx%n", ratio); // Verify correctness: both return same result boolean slowResult = ifInt8OutputSlow("Add"); boolean fastResult = ifInt8OutputFast("Add"); boolean slowMiss = ifInt8OutputSlow("Conv"); boolean fastMiss = ifInt8OutputFast("Conv"); assert slowResult == fastResult : "hit mismatch"; assert slowMiss == fastMiss : "miss mismatch"; assert slowResult : "Add should be in int8output set"; assert !slowMiss : "Conv should not be in int8output set"; assert ratio > 10.0 : "Expected >10x ratio, got " + ratio; System.out.println("PASS"); } }