@Override
    public void validate(Context context) {
        if (!context.deployState().isHostedTenantApplication(context.model().getAdmin().getApplicationType())) return;

        context.model().getContainerClusters().forEach((clusterId, appCluster) -> {
            var mp = appCluster.getMemoryPercentage().orElse(null);
            if (mp == null) return;
            if (mp.asAbsoluteGb().isEmpty()) {
                context.deployState().getDeployLogger().log(Level.FINE, "Host resources unknown or percentage overridden with 'allocated-memory'");
                return;
            }
            long jvmModelCost = appCluster.onnxModelCostCalculator().aggregatedModelCostInBytes();
            if (jvmModelCost > 0) {
                double availableMemoryGb = mp.asAbsoluteGb().getAsDouble();
                int percentageOfTotal = mp.ofContainerTotal().getAsInt();
                double modelCostGb = jvmModelCost / (1024D * 1024 * 1024);
                context.deployState().getDeployLogger().log(Level.FINE, () -> Text.format("JVM: %d%% (limit: %d%%), %.2fGB (limit: %.2fGB), ONNX: %.2fGB",
                        percentageOfTotal, percentLimit, availableMemoryGb, gbLimit, modelCostGb));
                if (percentageOfTotal < percentLimit) {
                    context.illegal(Text.format("Allocated percentage of memory of JVM in cluster '%s' is too low (%d%% < %d%%). " +
                                    "Estimated cost of ONNX models is %.2fGB. Either use a node flavor with more memory or use less expensive models. " +
                                    "You may override this validation by specifying 'allocated-memory' (https://docs.vespa.ai/en/performance/container-tuning.html#jvm-heap-size).",
                            clusterId, percentageOfTotal, percentLimit, modelCostGb));
                }
                if (availableMemoryGb < gbLimit) {
                    context.illegal(
                            Text.format("Allocated memory to JVM in cluster '%s' is too low (%.2fGB < %.2fGB). " +
                                    "Estimated cost of ONNX models is %.2fGB. Either use a node flavor with more memory or use less expensive models. " +
                                    "You may override this validation by specifying 'allocated-memory' (https://docs.vespa.ai/en/performance/container-tuning.html#jvm-heap-size).",
                                            clusterId, availableMemoryGb, gbLimit, modelCostGb));
                }
            }
        });
    }
@Test
    void accepts_services_with_explicit_jvm_size() throws IOException, SAXException {
        String servicesXml =
                """
                <?xml version="1.0" encoding="utf-8" ?>
                <services version='1.0'>
                    <container version='1.0'>
                        <nodes count="2">
                            <jvm allocated-memory='5%'/>
                            <resources vcpu="4" memory="2Gb" disk="125Gb"/>
                        </nodes>
                        <component id="hf-embedder" type="hugging-face-embedder">
                            <transformer-model url="https://my/url/model.onnx"/>
                            <tokenizer-model path="app/tokenizer.json"/>
                        </component>
                    </container>
                </services>""";
        var deployState = createDeployState(servicesXml, 2, 1024L * 1024 * 1024);
        var model = new VespaModel(new NullConfigModelRegistry(), deployState);
        assertDoesNotThrow(() -> ValidationTester.validate(new JvmHeapSizeValidator(), model, deployState));
    }