blob: 8f6c87fcccdfe8541f3b8958ec95dea6d8f3ad29 [file] [log] [blame]
Tobin Ehlis35308dd2016-10-31 13:27:36 -06001#!/usr/bin/env python3
Shannon McPherson9a4ae982019-01-07 16:05:25 -07002# Copyright (c) 2015-2019 The Khronos Group Inc.
3# Copyright (c) 2015-2019 Valve Corporation
4# Copyright (c) 2015-2019 LunarG, Inc.
5# Copyright (c) 2015-2019 Google Inc.
Tobin Ehlis35308dd2016-10-31 13:27:36 -06006#
7# Licensed under the Apache License, Version 2.0 (the "License");
8# you may not use this file except in compliance with the License.
9# You may obtain a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS,
15# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16# See the License for the specific language governing permissions and
17# limitations under the License.
18#
19# Author: Tobin Ehlis <tobine@google.com>
Dave Houltoncacef472018-05-29 13:00:42 -060020# Author: Dave Houlton <daveh@lunarg.com>
Shannon McPherson3ea65132018-12-05 10:37:39 -070021# Author: Shannon McPherson <shannon@lunarg.com>
Tobin Ehlis35308dd2016-10-31 13:27:36 -060022
23import argparse
Mike Schuchardte51c74b2019-07-10 17:01:21 -070024import common_codegen
Dave Houltoncacef472018-05-29 13:00:42 -060025import csv
Mike Schuchardt49c7d7f2019-07-10 17:09:29 -070026import glob
Dave Houltoncacef472018-05-29 13:00:42 -060027import html
Mike Schuchardte51c74b2019-07-10 17:01:21 -070028import json
29import operator
30import os
31import platform
32import re
33import sys
Dave Houlton729c7822018-11-19 11:52:23 -070034import time
Dave Houltoncacef472018-05-29 13:00:42 -060035from collections import defaultdict
Tobin Ehlis35308dd2016-10-31 13:27:36 -060036
Dave Houltoncacef472018-05-29 13:00:42 -060037verbose_mode = False
38txt_db = False
39csv_db = False
40html_db = False
41txt_filename = "validation_error_database.txt"
42csv_filename = "validation_error_database.csv"
43html_filename = "validation_error_database.html"
Mike Schuchardt7b12d652019-07-01 11:00:21 -070044header_filename = "vk_validation_error_messages.h"
Dave Houltoncacef472018-05-29 13:00:42 -060045vuid_prefixes = ['VUID-', 'UNASSIGNED-']
Tobin Ehlis35308dd2016-10-31 13:27:36 -060046
Dave Houltoncacef472018-05-29 13:00:42 -060047# Hard-coded flags that could be command line args, if we decide that's useful
48# replace KHR vuids with non-KHR during consistency checking
49dealias_khr = True
50ignore_unassigned = True # These are not found in layer code unless they appear explicitly (most don't), so produce false positives
51
Mike Schuchardte51c74b2019-07-10 17:01:21 -070052layer_source_files = [common_codegen.repo_relative(path) for path in [
53 'layers/buffer_validation.cpp',
54 'layers/core_validation.cpp',
55 'layers/descriptor_sets.cpp',
56 'layers/drawdispatch.cpp',
57 'layers/parameter_validation_utils.cpp',
58 'layers/object_tracker_utils.cpp',
59 'layers/shader_validation.cpp',
60 'layers/stateless_validation.h',
61 'layers/generated/parameter_validation.cpp',
62 'layers/generated/object_tracker.cpp',
Mike Schuchardt7b12d652019-07-01 11:00:21 -070063]]
64
Mike Schuchardt49c7d7f2019-07-10 17:09:29 -070065test_source_files = glob.glob(os.path.join(common_codegen.repo_relative('tests'), '*.cpp'))
Tobin Ehlis35308dd2016-10-31 13:27:36 -060066
Dave Houlton407df732018-08-06 17:58:24 -060067# This needs to be updated as new extensions roll in
Mark Lobodzinski02e23172019-03-04 15:27:55 -070068khr_aliases = {
69 'VUID-vkBindBufferMemory2KHR-device-parameter' : 'VUID-vkBindBufferMemory2-device-parameter',
70 'VUID-vkBindBufferMemory2KHR-pBindInfos-parameter' : 'VUID-vkBindBufferMemory2-pBindInfos-parameter',
71 'VUID-vkBindImageMemory2KHR-device-parameter' : 'VUID-vkBindImageMemory2-device-parameter',
72 'VUID-vkBindImageMemory2KHR-pBindInfos-parameter' : 'VUID-vkBindImageMemory2-pBindInfos-parameter',
73 'VUID-vkCmdDispatchBaseKHR-commandBuffer-parameter' : 'VUID-vkCmdDispatchBase-commandBuffer-parameter',
74 'VUID-vkCmdSetDeviceMaskKHR-commandBuffer-parameter' : 'VUID-vkCmdSetDeviceMask-commandBuffer-parameter',
75 'VUID-vkCreateDescriptorUpdateTemplateKHR-device-parameter' : 'VUID-vkCreateDescriptorUpdateTemplate-device-parameter',
76 'VUID-vkCreateDescriptorUpdateTemplateKHR-pDescriptorUpdateTemplate-parameter' : 'VUID-vkCreateDescriptorUpdateTemplate-pDescriptorUpdateTemplate-parameter',
77 'VUID-vkCreateSamplerYcbcrConversionKHR-device-parameter' : 'VUID-vkCreateSamplerYcbcrConversion-device-parameter',
78 'VUID-vkCreateSamplerYcbcrConversionKHR-pYcbcrConversion-parameter' : 'VUID-vkCreateSamplerYcbcrConversion-pYcbcrConversion-parameter',
79 'VUID-vkDestroyDescriptorUpdateTemplateKHR-descriptorUpdateTemplate-parameter' : 'VUID-vkDestroyDescriptorUpdateTemplate-descriptorUpdateTemplate-parameter',
Dave Houltoncacef472018-05-29 13:00:42 -060080 'VUID-vkDestroyDescriptorUpdateTemplateKHR-descriptorUpdateTemplate-parent' : 'VUID-vkDestroyDescriptorUpdateTemplate-descriptorUpdateTemplate-parent',
Mark Lobodzinski02e23172019-03-04 15:27:55 -070081 'VUID-vkDestroyDescriptorUpdateTemplateKHR-device-parameter' : 'VUID-vkDestroyDescriptorUpdateTemplate-device-parameter',
82 'VUID-vkDestroySamplerYcbcrConversionKHR-device-parameter' : 'VUID-vkDestroySamplerYcbcrConversion-device-parameter',
83 'VUID-vkDestroySamplerYcbcrConversionKHR-ycbcrConversion-parameter' : 'VUID-vkDestroySamplerYcbcrConversion-ycbcrConversion-parameter',
Dave Houltoncacef472018-05-29 13:00:42 -060084 'VUID-vkDestroySamplerYcbcrConversionKHR-ycbcrConversion-parent' : 'VUID-vkDestroySamplerYcbcrConversion-ycbcrConversion-parent',
Mark Lobodzinski02e23172019-03-04 15:27:55 -070085 'VUID-vkEnumeratePhysicalDeviceGroupsKHR-instance-parameter' : 'VUID-vkEnumeratePhysicalDeviceGroups-instance-parameter',
86 'VUID-vkEnumeratePhysicalDeviceGroupsKHR-pPhysicalDeviceGroupProperties-parameter' : 'VUID-vkEnumeratePhysicalDeviceGroups-pPhysicalDeviceGroupProperties-parameter',
87 'VUID-vkGetBufferMemoryRequirements2KHR-device-parameter' : 'VUID-vkGetBufferMemoryRequirements2-device-parameter',
88 'VUID-vkGetDescriptorSetLayoutSupportKHR-device-parameter' : 'VUID-vkGetDescriptorSetLayoutSupport-device-parameter',
89 'VUID-vkGetDeviceGroupPeerMemoryFeaturesKHR-device-parameter' : 'VUID-vkGetDeviceGroupPeerMemoryFeatures-device-parameter',
90 'VUID-vkGetDeviceGroupPeerMemoryFeaturesKHR-pPeerMemoryFeatures-parameter' : 'VUID-vkGetDeviceGroupPeerMemoryFeatures-pPeerMemoryFeatures-parameter',
91 'VUID-vkGetImageMemoryRequirements2KHR-device-parameter' : 'VUID-vkGetImageMemoryRequirements2-device-parameter',
92 'VUID-vkGetImageSparseMemoryRequirements2KHR-device-parameter' : 'VUID-vkGetImageSparseMemoryRequirements2-device-parameter',
93 'VUID-vkGetImageSparseMemoryRequirements2KHR-pSparseMemoryRequirements-parameter' : 'VUID-vkGetImageSparseMemoryRequirements2-pSparseMemoryRequirements-parameter',
94 'VUID-vkGetPhysicalDeviceExternalBufferPropertiesKHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceExternalBufferProperties-physicalDevice-parameter',
95 'VUID-vkGetPhysicalDeviceExternalFencePropertiesKHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceExternalFenceProperties-physicalDevice-parameter',
96 'VUID-vkGetPhysicalDeviceExternalSemaphorePropertiesKHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceExternalSemaphoreProperties-physicalDevice-parameter',
97 'VUID-vkGetPhysicalDeviceFeatures2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceFeatures2-physicalDevice-parameter',
98 'VUID-vkGetPhysicalDeviceFormatProperties2KHR-format-parameter' : 'VUID-vkGetPhysicalDeviceFormatProperties2-format-parameter',
99 'VUID-vkGetPhysicalDeviceFormatProperties2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceFormatProperties2-physicalDevice-parameter',
100 'VUID-vkGetPhysicalDeviceImageFormatProperties2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceImageFormatProperties2-physicalDevice-parameter',
101 'VUID-vkGetPhysicalDeviceMemoryProperties2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceMemoryProperties2-physicalDevice-parameter',
102 'VUID-vkGetPhysicalDeviceProperties2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceProperties2-physicalDevice-parameter',
103 'VUID-vkGetPhysicalDeviceQueueFamilyProperties2KHR-pQueueFamilyProperties-parameter' : 'VUID-vkGetPhysicalDeviceQueueFamilyProperties2-pQueueFamilyProperties-parameter',
104 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2KHR-pProperties-parameter' : 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2-pProperties-parameter',
105 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2-physicalDevice-parameter',
106 'VUID-vkTrimCommandPoolKHR-commandPool-parameter' : 'VUID-vkTrimCommandPool-commandPool-parameter',
Dave Houltoncacef472018-05-29 13:00:42 -0600107 'VUID-vkTrimCommandPoolKHR-commandPool-parent' : 'VUID-vkTrimCommandPool-commandPool-parent',
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700108 'VUID-vkTrimCommandPoolKHR-device-parameter' : 'VUID-vkTrimCommandPool-device-parameter',
Dave Houltoncacef472018-05-29 13:00:42 -0600109 'VUID-vkTrimCommandPoolKHR-flags-zerobitmask' : 'VUID-vkTrimCommandPool-flags-zerobitmask',
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700110 'VUID-vkUpdateDescriptorSetWithTemplateKHR-descriptorSet-parameter' : 'VUID-vkUpdateDescriptorSetWithTemplate-descriptorSet-parameter',
111 'VUID-vkUpdateDescriptorSetWithTemplateKHR-descriptorUpdateTemplate-parameter' : 'VUID-vkUpdateDescriptorSetWithTemplate-descriptorUpdateTemplate-parameter',
Dave Houltoncacef472018-05-29 13:00:42 -0600112 'VUID-vkUpdateDescriptorSetWithTemplateKHR-descriptorUpdateTemplate-parent' : 'VUID-vkUpdateDescriptorSetWithTemplate-descriptorUpdateTemplate-parent',
113 'VUID-vkUpdateDescriptorSetWithTemplateKHR-device-parameter' : 'VUID-vkUpdateDescriptorSetWithTemplate-device-parameter',
114 'VUID-vkCreateDescriptorUpdateTemplateKHR-pCreateInfo-parameter' : 'VUID-vkCreateDescriptorUpdateTemplate-pCreateInfo-parameter',
115 'VUID-vkCreateSamplerYcbcrConversionKHR-pCreateInfo-parameter' : 'VUID-vkCreateSamplerYcbcrConversion-pCreateInfo-parameter',
116 'VUID-vkGetBufferMemoryRequirements2KHR-pInfo-parameter' : 'VUID-vkGetBufferMemoryRequirements2-pInfo-parameter',
117 'VUID-vkGetBufferMemoryRequirements2KHR-pMemoryRequirements-parameter' : 'VUID-vkGetBufferMemoryRequirements2-pMemoryRequirements-parameter',
118 'VUID-vkGetDescriptorSetLayoutSupportKHR-pCreateInfo-parameter' : 'VUID-vkGetDescriptorSetLayoutSupport-pCreateInfo-parameter',
119 'VUID-vkGetDescriptorSetLayoutSupportKHR-pSupport-parameter' : 'VUID-vkGetDescriptorSetLayoutSupport-pSupport-parameter',
120 'VUID-vkGetImageMemoryRequirements2KHR-pInfo-parameter' : 'VUID-vkGetImageMemoryRequirements2-pInfo-parameter',
121 'VUID-vkGetImageMemoryRequirements2KHR-pMemoryRequirements-parameter' : 'VUID-vkGetImageMemoryRequirements2-pMemoryRequirements-parameter',
122 'VUID-vkGetImageSparseMemoryRequirements2KHR-pInfo-parameter' : 'VUID-vkGetImageSparseMemoryRequirements2-pInfo-parameter',
123 'VUID-vkGetPhysicalDeviceExternalBufferPropertiesKHR-pExternalBufferInfo-parameter' : 'VUID-vkGetPhysicalDeviceExternalBufferProperties-pExternalBufferInfo-parameter',
124 'VUID-vkGetPhysicalDeviceExternalBufferPropertiesKHR-pExternalBufferProperties-parameter' : 'VUID-vkGetPhysicalDeviceExternalBufferProperties-pExternalBufferProperties-parameter',
125 'VUID-vkGetPhysicalDeviceExternalFencePropertiesKHR-pExternalFenceInfo-parameter' : 'VUID-vkGetPhysicalDeviceExternalFenceProperties-pExternalFenceInfo-parameter',
126 'VUID-vkGetPhysicalDeviceExternalFencePropertiesKHR-pExternalFenceProperties-parameter' : 'VUID-vkGetPhysicalDeviceExternalFenceProperties-pExternalFenceProperties-parameter',
127 'VUID-vkGetPhysicalDeviceExternalSemaphorePropertiesKHR-pExternalSemaphoreInfo-parameter' : 'VUID-vkGetPhysicalDeviceExternalSemaphoreProperties-pExternalSemaphoreInfo-parameter',
128 'VUID-vkGetPhysicalDeviceExternalSemaphorePropertiesKHR-pExternalSemaphoreProperties-parameter' : 'VUID-vkGetPhysicalDeviceExternalSemaphoreProperties-pExternalSemaphoreProperties-parameter',
129 'VUID-vkGetPhysicalDeviceFeatures2KHR-pFeatures-parameter' : 'VUID-vkGetPhysicalDeviceFeatures2-pFeatures-parameter',
130 'VUID-vkGetPhysicalDeviceFormatProperties2KHR-pFormatProperties-parameter' : 'VUID-vkGetPhysicalDeviceFormatProperties2-pFormatProperties-parameter',
131 'VUID-vkGetPhysicalDeviceImageFormatProperties2KHR-pImageFormatInfo-parameter' : 'VUID-vkGetPhysicalDeviceImageFormatProperties2-pImageFormatInfo-parameter',
132 'VUID-vkGetPhysicalDeviceImageFormatProperties2KHR-pImageFormatProperties-parameter' : 'VUID-vkGetPhysicalDeviceImageFormatProperties2-pImageFormatProperties-parameter',
133 'VUID-vkGetPhysicalDeviceMemoryProperties2KHR-pMemoryProperties-parameter' : 'VUID-vkGetPhysicalDeviceMemoryProperties2-pMemoryProperties-parameter',
134 'VUID-vkGetPhysicalDeviceProperties2KHR-pProperties-parameter' : 'VUID-vkGetPhysicalDeviceProperties2-pProperties-parameter',
135 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2KHR-pFormatInfo-parameter' : 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2-pFormatInfo-parameter' }
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600136
Dave Houltoncacef472018-05-29 13:00:42 -0600137def printHelp():
138 print ("Usage:")
139 print (" python vk_validation_stats.py <json_file>")
140 print (" [ -c ]")
141 print (" [ -todo ]")
142 print (" [ -vuid <vuid_name> ]")
143 print (" [ -text [ <text_out_filename>] ]")
144 print (" [ -csv [ <csv_out_filename>] ]")
145 print (" [ -html [ <html_out_filename>] ]")
Dave Houlton407df732018-08-06 17:58:24 -0600146 print (" [ -export_header ]")
Mike Schuchardt647e84c2019-08-01 10:23:38 -0700147 print (" [ -summary ]")
Dave Houltoncacef472018-05-29 13:00:42 -0600148 print (" [ -verbose ]")
149 print (" [ -help ]")
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700150 print ("\n The vk_validation_stats script parses validation layer source files to")
151 print (" determine the set of valid usage checks and tests currently implemented,")
Dave Houltoncacef472018-05-29 13:00:42 -0600152 print (" and generates coverage values by comparing against the full set of valid")
153 print (" usage identifiers in the Vulkan-Headers registry file 'validusage.json'")
154 print ("\nArguments: ")
155 print (" <json-file> (required) registry file 'validusage.json'")
156 print (" -c report consistency warnings")
157 print (" -todo report unimplemented VUIDs")
158 print (" -vuid <vuid_name> report status of individual VUID <vuid_name>")
159 print (" -text [filename] output the error database text to <text_database_filename>,")
160 print (" defaults to 'validation_error_database.txt'")
161 print (" -csv [filename] output the error database in csv to <csv_database_filename>,")
162 print (" defaults to 'validation_error_database.csv'")
163 print (" -html [filename] output the error database in html to <html_database_filename>,")
164 print (" defaults to 'validation_error_database.html'")
Dave Houlton407df732018-08-06 17:58:24 -0600165 print (" -export_header export a new VUID error text header file to <%s>" % header_filename)
Mike Schuchardt647e84c2019-08-01 10:23:38 -0700166 print (" -summary output summary of VUID coverage")
Dave Houltoncacef472018-05-29 13:00:42 -0600167 print (" -verbose show your work (to stdout)")
168
169class ValidationJSON:
170 def __init__(self, filename):
171 self.filename = filename
172 self.explicit_vuids = set()
173 self.implicit_vuids = set()
174 self.all_vuids = set()
175 self.vuid_db = defaultdict(list) # Maps VUID string to list of json-data dicts
176 self.apiversion = ""
Dave Houltoncacef472018-05-29 13:00:42 -0600177 self.duplicate_vuids = set()
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700178
Dave Houlton407df732018-08-06 17:58:24 -0600179 # A set of specific regular expression substitutions needed to clean up VUID text
180 self.regex_dict = {}
181 self.regex_dict[re.compile('<.*?>|&(amp;)+lt;|&(amp;)+gt;')] = ""
182 self.regex_dict[re.compile(r'\\\(codeSize \\over 4\\\)')] = "(codeSize/4)"
Shannon McPherson3ea65132018-12-05 10:37:39 -0700183 self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{height}{maxFragmentDensityTexelSize_{height}}}\\rceil\\\)')] = "the ceiling of height/maxFragmentDensityTexelSize.height"
184 self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{width}{maxFragmentDensityTexelSize_{width}}}\\rceil\\\)')] = "the ceiling of width/maxFragmentDensityTexelSize.width"
185 self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{maxFramebufferHeight}{minFragmentDensityTexelSize_{height}}}\\rceil\\\)')] = "the ceiling of maxFramebufferHeight/minFragmentDensityTexelSize.height"
186 self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{maxFramebufferWidth}{minFragmentDensityTexelSize_{width}}}\\rceil\\\)')] = "the ceiling of maxFramebufferWidth/minFragmentDensityTexelSize.width"
Dave Houlton407df732018-08-06 17:58:24 -0600187 self.regex_dict[re.compile(r'\\\(\\lceil\{\\mathit\{rasterizationSamples} \\over 32}\\rceil\\\)')] = "(rasterizationSamples/32)"
Shannon McPhersonb40f1a22018-10-30 16:45:07 -0600188 self.regex_dict[re.compile(r'\\\(\\textrm\{codeSize} \\over 4\\\)')] = "(codeSize/4)"
Dave Houlton407df732018-08-06 17:58:24 -0600189 # Some fancy punctuation chars that break the Android build...
190 self.regex_dict[re.compile('&#8594;')] = "->" # Arrow char
191 self.regex_dict[re.compile('&#8217;')] = "'" # Left-slanting apostrophe to apostrophe
192 self.regex_dict[re.compile('&#822(0|1);')] = "'" # L/R-slanting quotes to apostrophe
Dave Houltoncacef472018-05-29 13:00:42 -0600193
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600194 def read(self):
Dave Houltoncacef472018-05-29 13:00:42 -0600195 self.json_dict = {}
196 if os.path.isfile(self.filename):
Dave Houlton407df732018-08-06 17:58:24 -0600197 json_file = open(self.filename, 'r', encoding='utf-8')
Dave Houltoncacef472018-05-29 13:00:42 -0600198 self.json_dict = json.load(json_file)
199 json_file.close()
200 if len(self.json_dict) == 0:
201 print("Error: Error loading validusage.json file <%s>" % self.filename)
202 sys.exit(-1)
203 try:
204 version = self.json_dict['version info']
205 validation = self.json_dict['validation']
206 self.apiversion = version['api version']
207 except:
208 print("Error: Failure parsing validusage.json object")
209 sys.exit(-1)
210
211 # Parse vuid from json into local databases
212 for apiname in validation.keys():
213 # print("entrypoint:%s"%apiname)
214 apidict = validation[apiname]
215 for ext in apidict.keys():
216 vlist = apidict[ext]
217 for ventry in vlist:
218 vuid_string = ventry['vuid']
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700219 if (vuid_string[-5:-1].isdecimal()):
Dave Houltoncacef472018-05-29 13:00:42 -0600220 self.explicit_vuids.add(vuid_string) # explicit end in 5 numeric chars
221 vtype = 'explicit'
222 else:
223 self.implicit_vuids.add(vuid_string) # otherwise, implicit
224 vtype = 'implicit'
225 vuid_text = ventry['text']
Dave Houlton407df732018-08-06 17:58:24 -0600226 for regex, replacement in self.regex_dict.items():
227 vuid_text = re.sub(regex, replacement, vuid_text) # do regex substitution
228 vuid_text = html.unescape(vuid_text) # anything missed by the regex
229 self.vuid_db[vuid_string].append({'api':apiname, 'ext':ext, 'type':vtype, 'text':vuid_text})
Dave Houltoncacef472018-05-29 13:00:42 -0600230 self.all_vuids = self.explicit_vuids | self.implicit_vuids
231 self.duplicate_vuids = set({v for v in self.vuid_db if len(self.vuid_db[v]) > 1})
Dave Houlton407df732018-08-06 17:58:24 -0600232 if len(self.duplicate_vuids) > 0:
233 print("Warning: duplicate VUIDs found in validusage.json")
234
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600235
236class ValidationSource:
Mike Schuchardt7b12d652019-07-01 11:00:21 -0700237 def __init__(self, source_file_list):
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600238 self.source_files = source_file_list
Dave Houltoncacef472018-05-29 13:00:42 -0600239 self.vuid_count_dict = {} # dict of vuid values to the count of how much they're used, and location of where they're used
240 self.duplicated_checks = 0
241 self.explicit_vuids = set()
242 self.implicit_vuids = set()
243 self.unassigned_vuids = set()
244 self.all_vuids = set()
Mark Lobodzinski05849f02017-06-21 14:44:14 -0600245
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600246 def parse(self):
Dave Houltoncacef472018-05-29 13:00:42 -0600247 prepend = None
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600248 for sf in self.source_files:
Tobin Ehlis3d1f2bd2016-12-22 11:19:15 -0700249 line_num = 0
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600250 with open(sf) as f:
251 for line in f:
Tobin Ehlis3d1f2bd2016-12-22 11:19:15 -0700252 line_num = line_num + 1
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600253 if True in [line.strip().startswith(comment) for comment in ['//', '/*']]:
254 continue
Dave Houltoncacef472018-05-29 13:00:42 -0600255 # Find vuid strings
Michał Janiszewski3c3ce9e2018-10-30 23:25:21 +0100256 if prepend is not None:
Dave Houltoncacef472018-05-29 13:00:42 -0600257 line = prepend[:-2] + line.lstrip().lstrip('"') # join lines skipping CR, whitespace and trailing/leading quote char
258 prepend = None
259 if any(prefix in line for prefix in vuid_prefixes):
Shannon McPhersondad26362019-06-12 10:51:46 -0600260 # Replace the '(' of lines containing validation helper functions with ' ' to make them easier to parse
261 line = line.replace("(", " ")
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600262 line_list = line.split()
Dave Houltoncacef472018-05-29 13:00:42 -0600263
264 # A VUID string that has been broken by clang will start with a vuid prefix and end with -, and will be last in the list
265 broken_vuid = line_list[-1].strip('"')
266 if any(broken_vuid.startswith(prefix) for prefix in vuid_prefixes) and broken_vuid.endswith('-'):
267 prepend = line
268 continue
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700269
Dave Houltoncacef472018-05-29 13:00:42 -0600270 vuid_list = []
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600271 for str in line_list:
Dave Houltoncacef472018-05-29 13:00:42 -0600272 if any(prefix in str for prefix in vuid_prefixes):
273 vuid_list.append(str.strip(',);{}"'))
274 for vuid in vuid_list:
275 if vuid not in self.vuid_count_dict:
276 self.vuid_count_dict[vuid] = {}
277 self.vuid_count_dict[vuid]['count'] = 1
278 self.vuid_count_dict[vuid]['file_line'] = []
279 else:
280 if self.vuid_count_dict[vuid]['count'] == 1: # only count first time duplicated
281 self.duplicated_checks = self.duplicated_checks + 1
282 self.vuid_count_dict[vuid]['count'] = self.vuid_count_dict[vuid]['count'] + 1
283 self.vuid_count_dict[vuid]['file_line'].append('%s,%d' % (sf, line_num))
284 # Sort vuids by type
285 for vuid in self.vuid_count_dict.keys():
286 if (vuid.startswith('VUID-')):
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700287 if (vuid[-5:-1].isdecimal()):
Dave Houltoncacef472018-05-29 13:00:42 -0600288 self.explicit_vuids.add(vuid) # explicit end in 5 numeric chars
289 else:
290 self.implicit_vuids.add(vuid)
291 elif (vuid.startswith('UNASSIGNED-')):
292 self.unassigned_vuids.add(vuid)
293 else:
294 print("Unable to categorize VUID: %s" % vuid)
295 print("Confused while parsing VUIDs in layer source code - cannot proceed. (FIXME)")
296 exit(-1)
297 self.all_vuids = self.explicit_vuids | self.implicit_vuids | self.unassigned_vuids
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600298
299# Class to parse the validation layer test source and store testnames
Dave Houltoncacef472018-05-29 13:00:42 -0600300class ValidationTests:
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600301 def __init__(self, test_file_list, test_group_name=['VkLayerTest', 'VkPositiveLayerTest', 'VkWsiEnabledLayerTest']):
302 self.test_files = test_file_list
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600303 self.test_trigger_txt_list = []
304 for tg in test_group_name:
305 self.test_trigger_txt_list.append('TEST_F(%s' % tg)
Dave Houltoncacef472018-05-29 13:00:42 -0600306 self.explicit_vuids = set()
307 self.implicit_vuids = set()
308 self.unassigned_vuids = set()
309 self.all_vuids = set()
310 #self.test_to_vuids = {} # Map test name to VUIDs tested
311 self.vuid_to_tests = defaultdict(set) # Map VUIDs to set of test names where implemented
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600312
313 # Parse test files into internal data struct
314 def parse(self):
315 # For each test file, parse test names into set
316 grab_next_line = False # handle testname on separate line than wildcard
Tobin Ehlis9a68c982016-12-29 14:51:17 -0700317 testname = ''
Dave Houltoncacef472018-05-29 13:00:42 -0600318 prepend = None
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600319 for test_file in self.test_files:
320 with open(test_file) as tf:
321 for line in tf:
322 if True in [line.strip().startswith(comment) for comment in ['//', '/*']]:
323 continue
324
Dave Houltoncacef472018-05-29 13:00:42 -0600325 # if line ends in a broken VUID string, fix that before proceeding
Michał Janiszewski3c3ce9e2018-10-30 23:25:21 +0100326 if prepend is not None:
Dave Houltoncacef472018-05-29 13:00:42 -0600327 line = prepend[:-2] + line.lstrip().lstrip('"') # join lines skipping CR, whitespace and trailing/leading quote char
328 prepend = None
329 if any(prefix in line for prefix in vuid_prefixes):
330 line_list = line.split()
331
332 # A VUID string that has been broken by clang will start with a vuid prefix and end with -, and will be last in the list
333 broken_vuid = line_list[-1].strip('"')
334 if any(broken_vuid.startswith(prefix) for prefix in vuid_prefixes) and broken_vuid.endswith('-'):
335 prepend = line
336 continue
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700337
Dave Houltoncacef472018-05-29 13:00:42 -0600338 if any(ttt in line for ttt in self.test_trigger_txt_list):
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600339 testname = line.split(',')[-1]
340 testname = testname.strip().strip(' {)')
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600341 if ('' == testname):
342 grab_next_line = True
343 continue
Dave Houltoncacef472018-05-29 13:00:42 -0600344 #self.test_to_vuids[testname] = []
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600345 if grab_next_line: # test name on its own line
346 grab_next_line = False
347 testname = testname.strip().strip(' {)')
Dave Houltoncacef472018-05-29 13:00:42 -0600348 #self.test_to_vuids[testname] = []
349 if any(prefix in line for prefix in vuid_prefixes):
350 line_list = re.split('[\s{}[\]()"]+',line)
Tobin Ehlis71f38c12017-01-12 14:26:56 -0700351 for sub_str in line_list:
Dave Houltoncacef472018-05-29 13:00:42 -0600352 if any(prefix in sub_str for prefix in vuid_prefixes):
353 vuid_str = sub_str.strip(',);:"')
354 self.vuid_to_tests[vuid_str].add(testname)
355 #self.test_to_vuids[testname].append(vuid_str)
356 if (vuid_str.startswith('VUID-')):
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700357 if (vuid_str[-5:-1].isdecimal()):
Dave Houltoncacef472018-05-29 13:00:42 -0600358 self.explicit_vuids.add(vuid_str) # explicit end in 5 numeric chars
359 else:
360 self.implicit_vuids.add(vuid_str)
361 elif (vuid_str.startswith('UNASSIGNED-')):
362 self.unassigned_vuids.add(vuid_str)
363 else:
364 print("Unable to categorize VUID: %s" % vuid_str)
365 print("Confused while parsing VUIDs in test code - cannot proceed. (FIXME)")
366 exit(-1)
367 self.all_vuids = self.explicit_vuids | self.implicit_vuids | self.unassigned_vuids
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600368
Dave Houltoncacef472018-05-29 13:00:42 -0600369# Class to do consistency checking
370#
371class Consistency:
372 def __init__(self, all_json, all_checks, all_tests):
373 self.valid = all_json
374 self.checks = all_checks
375 self.tests = all_tests
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600376
Dave Houltoncacef472018-05-29 13:00:42 -0600377 if (dealias_khr):
378 dk = set()
379 for vuid in self.checks:
380 if vuid in khr_aliases:
381 dk.add(khr_aliases[vuid])
382 else:
383 dk.add(vuid)
384 self.checks = dk
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600385
Dave Houltoncacef472018-05-29 13:00:42 -0600386 dk = set()
387 for vuid in self.tests:
388 if vuid in khr_aliases:
389 dk.add(khr_aliases[vuid])
390 else:
391 dk.add(vuid)
392 self.tests = dk
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600393
Dave Houltoncacef472018-05-29 13:00:42 -0600394 # Report undefined VUIDs in source code
395 def undef_vuids_in_layer_code(self):
396 undef_set = self.checks - self.valid
397 undef_set.discard('VUID-Undefined') # don't report Undefined
398 if ignore_unassigned:
399 unassigned = set({uv for uv in undef_set if uv.startswith('UNASSIGNED-')})
400 undef_set = undef_set - unassigned
401 if (len(undef_set) > 0):
402 print("\nFollowing VUIDs found in layer code are not defined in validusage.json (%d):" % len(undef_set))
403 undef = list(undef_set)
404 undef.sort()
405 for vuid in undef:
406 print(" %s" % vuid)
407 return False
408 return True
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600409
Dave Houltoncacef472018-05-29 13:00:42 -0600410 # Report undefined VUIDs in tests
411 def undef_vuids_in_tests(self):
412 undef_set = self.tests - self.valid
413 undef_set.discard('VUID-Undefined') # don't report Undefined
414 if ignore_unassigned:
415 unassigned = set({uv for uv in undef_set if uv.startswith('UNASSIGNED-')})
416 undef_set = undef_set - unassigned
417 if (len(undef_set) > 0):
418 ok = False
419 print("\nFollowing VUIDs found in layer tests are not defined in validusage.json (%d):" % len(undef_set))
420 undef = list(undef_set)
421 undef.sort()
422 for vuid in undef:
423 print(" %s" % vuid)
424 return False
425 return True
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600426
Dave Houltoncacef472018-05-29 13:00:42 -0600427 # Report vuids in tests that are not in source
428 def vuids_tested_not_checked(self):
429 undef_set = self.tests - self.checks
430 undef_set.discard('VUID-Undefined') # don't report Undefined
431 if ignore_unassigned:
432 unassigned = set()
433 for vuid in undef_set:
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700434 if vuid.startswith('UNASSIGNED-'):
Dave Houltoncacef472018-05-29 13:00:42 -0600435 unassigned.add(vuid)
436 undef_set = undef_set - unassigned
437 if (len(undef_set) > 0):
438 ok = False
439 print("\nFollowing VUIDs found in tests but are not checked in layer code (%d):" % len(undef_set))
440 undef = list(undef_set)
441 undef.sort()
442 for vuid in undef:
443 print(" %s" % vuid)
444 return False
445 return True
446
447 # TODO: Explicit checked VUIDs which have no test
448 # def explicit_vuids_checked_not_tested(self):
449
450
451# Class to output database in various flavors
452#
453class OutputDatabase:
454 def __init__(self, val_json, val_source, val_tests):
455 self.vj = val_json
456 self.vs = val_source
457 self.vt = val_tests
Dave Houlton729c7822018-11-19 11:52:23 -0700458 self.header_version = "/* THIS FILE IS GENERATED - DO NOT EDIT (scripts/vk_validation_stats.py) */"
459 self.header_version += "\n/* Vulkan specification version: %s */" % val_json.apiversion
Dave Houlton729c7822018-11-19 11:52:23 -0700460 self.header_preamble = """
Dave Houlton407df732018-08-06 17:58:24 -0600461/*
462 * Vulkan
463 *
Jasper St. Pierre1948bcc2019-01-18 13:55:20 -0800464 * Copyright (c) 2016-2019 Google Inc.
465 * Copyright (c) 2016-2019 LunarG, Inc.
Dave Houlton407df732018-08-06 17:58:24 -0600466 *
467 * Licensed under the Apache License, Version 2.0 (the "License");
468 * you may not use this file except in compliance with the License.
469 * You may obtain a copy of the License at
470 *
471 * http://www.apache.org/licenses/LICENSE-2.0
472 *
473 * Unless required by applicable law or agreed to in writing, software
474 * distributed under the License is distributed on an "AS IS" BASIS,
475 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
476 * See the License for the specific language governing permissions and
477 * limitations under the License.
478 *
479 * Author: Tobin Ehlis <tobine@google.com>
480 * Author: Dave Houlton <daveh@lunarg.com>
481 */
482
483#pragma once
484
485// Disable auto-formatting for generated file
486// clang-format off
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700487
Dave Houlton407df732018-08-06 17:58:24 -0600488// Mapping from VUID string to the corresponding spec text
Dave Houlton4d9b2f82018-10-24 18:21:06 -0600489typedef struct _vuid_spec_text_pair {
490 const char * vuid;
491 const char * spec_text;
492} vuid_spec_text_pair;
493
494static const vuid_spec_text_pair vuid_spec_text[] = {
Dave Houlton407df732018-08-06 17:58:24 -0600495"""
496 self.header_postamble = """};
Dave Houlton4d9b2f82018-10-24 18:21:06 -0600497"""
Dave Houlton407df732018-08-06 17:58:24 -0600498 self.spec_url = "https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html"
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700499
Dave Houltoncacef472018-05-29 13:00:42 -0600500 def dump_txt(self):
501 print("\n Dumping database to text file: %s" % txt_filename)
502 with open (txt_filename, 'w') as txt:
503 txt.write("## VUID Database\n")
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700504 txt.write("## Format: VUID_NAME | CHECKED | TEST | TYPE | API/STRUCT | EXTENSION | VUID_TEXT\n##\n")
Dave Houltoncacef472018-05-29 13:00:42 -0600505 vuid_list = list(self.vj.all_vuids)
506 vuid_list.sort()
507 for vuid in vuid_list:
508 db_list = self.vj.vuid_db[vuid]
509 db_list.sort(key=operator.itemgetter('ext')) # sort list to ease diffs of output file
510 for db_entry in db_list:
511 checked = 'N'
512 if vuid in self.vs.all_vuids:
513 checked = 'Y'
514 test = 'None'
515 if vuid in self.vt.vuid_to_tests:
516 test_list = list(self.vt.vuid_to_tests[vuid])
517 test_list.sort() # sort tests, for diff-ability
518 sep = ', '
519 test = sep.join(test_list)
520
521 txt.write("%s | %s | %s | %s | %s | %s | %s\n" % (vuid, checked, test, db_entry['type'], db_entry['api'], db_entry['ext'], db_entry['text']))
522
523 def dump_csv(self):
524 print("\n Dumping database to csv file: %s" % csv_filename)
525 with open (csv_filename, 'w', newline='') as csvfile:
526 cw = csv.writer(csvfile)
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700527 cw.writerow(['VUID_NAME','CHECKED','TEST','TYPE','API/STRUCT','EXTENSION','VUID_TEXT'])
Dave Houltoncacef472018-05-29 13:00:42 -0600528 vuid_list = list(self.vj.all_vuids)
529 vuid_list.sort()
530 for vuid in vuid_list:
531 for db_entry in self.vj.vuid_db[vuid]:
532 row = [vuid]
533 if vuid in self.vs.all_vuids:
534 row.append('Y')
535 else:
536 row.append('N')
537 test = 'None'
538 if vuid in self.vt.vuid_to_tests:
539 sep = ', '
540 test = sep.join(self.vt.vuid_to_tests[vuid])
541 row.append(test)
542 row.append(db_entry['type'])
543 row.append(db_entry['api'])
544 row.append(db_entry['ext'])
545 row.append(db_entry['text'])
546 cw.writerow(row)
547
548 def dump_html(self):
549 print("\n Dumping database to html file: %s" % html_filename)
550 preamble = '<!DOCTYPE html>\n<html>\n<head>\n<style>\ntable, th, td {\n border: 1px solid black;\n border-collapse: collapse; \n}\n</style>\n<body>\n<h2>Valid Usage Database</h2>\n<font size="2" face="Arial">\n<table style="width:100%">\n'
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700551 headers = '<tr><th>VUID NAME</th><th>CHECKED</th><th>TEST</th><th>TYPE</th><th>API/STRUCT</th><th>EXTENSION</th><th>VUID TEXT</th></tr>\n'
Dave Houltoncacef472018-05-29 13:00:42 -0600552 with open (html_filename, 'w') as hfile:
553 hfile.write(preamble)
554 hfile.write(headers)
555 vuid_list = list(self.vj.all_vuids)
556 vuid_list.sort()
557 for vuid in vuid_list:
558 for db_entry in self.vj.vuid_db[vuid]:
559 hfile.write('<tr><th>%s</th>' % vuid)
560 checked = '<span style="color:red;">N</span>'
561 if vuid in self.vs.all_vuids:
562 checked = '<span style="color:limegreen;">Y</span>'
563 hfile.write('<th>%s</th>' % checked)
564 test = 'None'
565 if vuid in self.vt.vuid_to_tests:
566 sep = ', '
567 test = sep.join(self.vt.vuid_to_tests[vuid])
568 hfile.write('<th>%s</th>' % test)
569 hfile.write('<th>%s</th>' % db_entry['type'])
570 hfile.write('<th>%s</th>' % db_entry['api'])
571 hfile.write('<th>%s</th>' % db_entry['ext'])
572 hfile.write('<th>%s</th></tr>\n' % db_entry['text'])
573 hfile.write('</table>\n</body>\n</html>\n')
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600574
Dave Houlton407df732018-08-06 17:58:24 -0600575 def export_header(self):
Mike Schuchardt647e84c2019-08-01 10:23:38 -0700576 if verbose_mode:
577 print("\n Exporting header file to: %s" % header_filename)
Dave Houlton407df732018-08-06 17:58:24 -0600578 with open (header_filename, 'w') as hfile:
Dave Houlton729c7822018-11-19 11:52:23 -0700579 hfile.write(self.header_version)
Dave Houlton407df732018-08-06 17:58:24 -0600580 hfile.write(self.header_preamble)
581 vuid_list = list(self.vj.all_vuids)
582 vuid_list.sort()
John Zulaufd09ba822019-04-29 07:05:07 -0600583 cmd_dict = {}
Dave Houlton407df732018-08-06 17:58:24 -0600584 for vuid in vuid_list:
585 db_entry = self.vj.vuid_db[vuid][0]
John Zulaufd09ba822019-04-29 07:05:07 -0600586 db_text = db_entry['text'].strip(' ')
587 hfile.write(' {"%s", "%s (%s#%s)"},\n' % (vuid, db_text, self.spec_url, vuid))
Dave Houlton407df732018-08-06 17:58:24 -0600588 # For multiply-defined VUIDs, include versions with extension appended
589 if len(self.vj.vuid_db[vuid]) > 1:
590 for db_entry in self.vj.vuid_db[vuid]:
John Zulaufd09ba822019-04-29 07:05:07 -0600591 hfile.write(' {"%s[%s]", "%s (%s#%s)"},\n' % (vuid, db_entry['ext'].strip(' '), db_text, self.spec_url, vuid))
592 if 'commandBuffer must be in the recording state' in db_text:
593 cmd_dict[vuid] = db_text
Dave Houlton407df732018-08-06 17:58:24 -0600594 hfile.write(self.header_postamble)
595
John Zulaufd09ba822019-04-29 07:05:07 -0600596 # Generate the information for validating recording state VUID's
597 cmd_prefix = 'prefix##'
598 cmd_regex = re.compile(r'VUID-vk(Cmd|End)(\w+)')
599 cmd_vuid_vector = [' "VUID_Undefined"']
600 cmd_name_vector = [ ' "Command_Undefined"' ]
601 cmd_enum = [' ' + cmd_prefix + 'NONE = 0']
602
603 cmd_ordinal = 1
Mike Schuchardtaed5ac32019-06-21 09:03:31 -0700604 for vuid, db_text in sorted(cmd_dict.items()):
John Zulaufd09ba822019-04-29 07:05:07 -0600605 cmd_match = cmd_regex.match(vuid)
606 if cmd_match.group(1) == "End":
607 end = "END"
608 else:
609 end = ""
610 cmd_name_vector.append(' "vk'+ cmd_match.group(1) + cmd_match.group(2) + '"')
611 cmd_name = cmd_prefix + end + cmd_match.group(2).upper()
612 cmd_enum.append(' {} = {}'.format(cmd_name, cmd_ordinal))
613 cmd_ordinal += 1
614 cmd_vuid_vector.append(' "{}"'.format(vuid))
615
616 hfile.write('\n// Defines to allow creating "must be recording" meta data\n')
617 cmd_enum.append(' {}RANGE_SIZE = {}'.format(cmd_prefix, cmd_ordinal))
618 cmd_enum_string = '#define VUID_CMD_ENUM_LIST(prefix)\\\n' + ',\\\n'.join(cmd_enum) + '\n\n'
619 hfile.write(cmd_enum_string)
620 cmd_name_list_string = '#define VUID_CMD_NAME_LIST\\\n' + ',\\\n'.join(cmd_name_vector) + '\n\n'
621 hfile.write(cmd_name_list_string)
622 vuid_vector_string = '#define VUID_MUST_BE_RECORDING_LIST\\\n' + ',\\\n'.join(cmd_vuid_vector) + '\n'
623 hfile.write(vuid_vector_string)
624
Mark Lobodzinskib44c54a2017-06-12 12:02:38 -0600625def main(argv):
Dave Houltoncacef472018-05-29 13:00:42 -0600626 global verbose_mode
627 global txt_filename
628 global csv_filename
629 global html_filename
630
631 run_consistency = False
632 report_unimplemented = False
633 get_vuid_status = ''
634 txt_out = False
635 csv_out = False
636 html_out = False
Dave Houlton407df732018-08-06 17:58:24 -0600637 header_out = False
Mike Schuchardt647e84c2019-08-01 10:23:38 -0700638 show_summary = False
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700639
Dave Houltoncacef472018-05-29 13:00:42 -0600640 if (1 > len(argv)):
641 printHelp()
642 sys.exit()
643
644 # Parse script args
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700645 json_filename = argv[0]
Dave Houltoncacef472018-05-29 13:00:42 -0600646 i = 1
647 while (i < len(argv)):
648 arg = argv[i]
649 i = i + 1
650 if (arg == '-c'):
651 run_consistency = True
652 elif (arg == '-vuid'):
653 get_vuid_status = argv[i]
654 i = i + 1
655 elif (arg == '-todo'):
656 report_unimplemented = True
Karl Schultz49d66bb2018-07-09 16:24:46 -0600657 elif (arg == '-text'):
Dave Houltoncacef472018-05-29 13:00:42 -0600658 txt_out = True
659 # Set filename if supplied, else use default
660 if i < len(argv) and not argv[i].startswith('-'):
661 txt_filename = argv[i]
662 i = i + 1
663 elif (arg == '-csv'):
664 csv_out = True
665 # Set filename if supplied, else use default
666 if i < len(argv) and not argv[i].startswith('-'):
667 csv_filename = argv[i]
668 i = i + 1
669 elif (arg == '-html'):
670 html_out = True
671 # Set filename if supplied, else use default
672 if i < len(argv) and not argv[i].startswith('-'):
673 html_filename = argv[i]
674 i = i + 1
Dave Houlton407df732018-08-06 17:58:24 -0600675 elif (arg == '-export_header'):
676 header_out = True
Dave Houltoncacef472018-05-29 13:00:42 -0600677 elif (arg in ['-verbose']):
678 verbose_mode = True
Mike Schuchardt647e84c2019-08-01 10:23:38 -0700679 elif (arg in ['-summary']):
680 show_summary = True
Dave Houltoncacef472018-05-29 13:00:42 -0600681 elif (arg in ['-help', '-h']):
682 printHelp()
683 sys.exit()
684 else:
685 print("Unrecognized argument: %s\n" % arg)
686 printHelp()
687 sys.exit()
688
Tobin Ehlis20e32582016-12-05 14:50:03 -0700689 result = 0 # Non-zero result indicates an error case
Dave Houltoncacef472018-05-29 13:00:42 -0600690
691 # Parse validusage json
692 val_json = ValidationJSON(json_filename)
693 val_json.read()
694 exp_json = len(val_json.explicit_vuids)
695 imp_json = len(val_json.implicit_vuids)
696 all_json = len(val_json.all_vuids)
697 if verbose_mode:
698 print("Found %d unique error vuids in validusage.json file." % all_json)
699 print(" %d explicit" % exp_json)
700 print(" %d implicit" % imp_json)
701 if len(val_json.duplicate_vuids) > 0:
702 print("%d VUIDs appear in validusage.json more than once." % len(val_json.duplicate_vuids))
703 for vuid in val_json.duplicate_vuids:
704 print(" %s" % vuid)
705 for ext in val_json.vuid_db[vuid]:
706 print(" with extension: %s" % ext['ext'])
707
708 # Parse layer source files
Mike Schuchardt7b12d652019-07-01 11:00:21 -0700709 val_source = ValidationSource(layer_source_files)
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600710 val_source.parse()
Dave Houltoncacef472018-05-29 13:00:42 -0600711 exp_checks = len(val_source.explicit_vuids)
712 imp_checks = len(val_source.implicit_vuids)
713 all_checks = len(val_source.vuid_count_dict.keys())
714 if verbose_mode:
715 print("Found %d unique vuid checks in layer source code." % all_checks)
716 print(" %d explicit" % exp_checks)
717 print(" %d implicit" % imp_checks)
718 print(" %d unassigned" % len(val_source.unassigned_vuids))
719 print(" %d checks are implemented more that once" % val_source.duplicated_checks)
720
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600721 # Parse test files
Mike Schuchardt7b12d652019-07-01 11:00:21 -0700722 val_tests = ValidationTests(test_source_files)
Dave Houltoncacef472018-05-29 13:00:42 -0600723 val_tests.parse()
724 exp_tests = len(val_tests.explicit_vuids)
725 imp_tests = len(val_tests.implicit_vuids)
726 all_tests = len(val_tests.all_vuids)
Mark Lobodzinski060a8e32018-01-08 09:08:06 -0700727 if verbose_mode:
Mike Schuchardt7b12d652019-07-01 11:00:21 -0700728 print("Found %d unique error vuids in test source code." % all_tests)
Dave Houltoncacef472018-05-29 13:00:42 -0600729 print(" %d explicit" % exp_tests)
730 print(" %d implicit" % imp_tests)
731 print(" %d unassigned" % len(val_tests.unassigned_vuids))
Mike Weiblenfe186122017-02-03 12:44:53 -0700732
Dave Houltoncacef472018-05-29 13:00:42 -0600733 # Process stats
Mike Schuchardt647e84c2019-08-01 10:23:38 -0700734 if show_summary:
735 print("\nValidation Statistics (using validusage.json version %s)" % val_json.apiversion)
736 print(" VUIDs defined in JSON file: %04d explicit, %04d implicit, %04d total." % (exp_json, imp_json, all_json))
737 print(" VUIDs checked in layer code: %04d explicit, %04d implicit, %04d total." % (exp_checks, imp_checks, all_checks))
738 print(" VUIDs tested in layer tests: %04d explicit, %04d implicit, %04d total." % (exp_tests, imp_tests, all_tests))
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700739
Mike Schuchardt647e84c2019-08-01 10:23:38 -0700740 print("\nVUID check coverage")
741 print(" Explicit VUIDs checked: %.1f%% (%d checked vs %d defined)" % ((100.0 * exp_checks / exp_json), exp_checks, exp_json))
742 print(" Implicit VUIDs checked: %.1f%% (%d checked vs %d defined)" % ((100.0 * imp_checks / imp_json), imp_checks, imp_json))
743 print(" Overall VUIDs checked: %.1f%% (%d checked vs %d defined)" % ((100.0 * all_checks / all_json), all_checks, all_json))
Mike Weiblenfe186122017-02-03 12:44:53 -0700744
Mike Schuchardt647e84c2019-08-01 10:23:38 -0700745 print("\nVUID test coverage")
746 print(" Explicit VUIDs tested: %.1f%% (%d tested vs %d checks)" % ((100.0 * exp_tests / exp_checks), exp_tests, exp_checks))
747 print(" Implicit VUIDs tested: %.1f%% (%d tested vs %d checks)" % ((100.0 * imp_tests / imp_checks), imp_tests, imp_checks))
748 print(" Overall VUIDs tested: %.1f%% (%d tested vs %d checks)" % ((100.0 * all_tests / all_checks), all_tests, all_checks))
Mike Weiblenfe186122017-02-03 12:44:53 -0700749
Dave Houltoncacef472018-05-29 13:00:42 -0600750 # Report status of a single VUID
751 if len(get_vuid_status) > 1:
752 print("\n\nChecking status of <%s>" % get_vuid_status);
753 if get_vuid_status not in val_json.all_vuids:
754 print(' Not a valid VUID string.')
755 else:
756 if get_vuid_status in val_source.explicit_vuids:
757 print(' Implemented!')
758 line_list = val_source.vuid_count_dict[get_vuid_status]['file_line']
759 for line in line_list:
760 print(' => %s' % line)
Dave Houltonf93bbab2018-06-26 17:21:12 -0600761 elif get_vuid_status in val_source.implicit_vuids:
762 print(' Implemented! (Implicit)')
763 line_list = val_source.vuid_count_dict[get_vuid_status]['file_line']
764 for line in line_list:
765 print(' => %s' % line)
Tobin Ehlis9a68c982016-12-29 14:51:17 -0700766 else:
Dave Houltoncacef472018-05-29 13:00:42 -0600767 print(' Not implemented.')
Dave Houltonf93bbab2018-06-26 17:21:12 -0600768 if get_vuid_status in val_tests.all_vuids:
Dave Houltoncacef472018-05-29 13:00:42 -0600769 print(' Has a test!')
770 test_list = val_tests.vuid_to_tests[get_vuid_status]
771 for test in test_list:
772 print(' => %s' % test)
773 else:
774 print(' Not tested.')
Mike Weiblenfe186122017-02-03 12:44:53 -0700775
Dave Houltoncacef472018-05-29 13:00:42 -0600776 # Report unimplemented explicit VUIDs
777 if report_unimplemented:
778 unim_explicit = val_json.explicit_vuids - val_source.explicit_vuids
779 print("\n\n%d explicit VUID checks remain unimplemented:" % len(unim_explicit))
780 ulist = list(unim_explicit)
781 ulist.sort()
782 for vuid in ulist:
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700783 print(" => %s" % vuid)
Dave Houltoncacef472018-05-29 13:00:42 -0600784
785 # Consistency tests
786 if run_consistency:
787 print("\n\nRunning consistency tests...")
788 con = Consistency(val_json.all_vuids, val_source.all_vuids, val_tests.all_vuids)
789 ok = con.undef_vuids_in_layer_code()
790 ok &= con.undef_vuids_in_tests()
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700791 ok &= con.vuids_tested_not_checked()
Dave Houltoncacef472018-05-29 13:00:42 -0600792
793 if ok:
794 print(" OK! No inconsistencies found.")
795
796 # Output database in requested format(s)
797 db_out = OutputDatabase(val_json, val_source, val_tests)
798 if txt_out:
799 db_out.dump_txt()
800 if csv_out:
801 db_out.dump_csv()
802 if html_out:
803 db_out.dump_html()
Dave Houlton407df732018-08-06 17:58:24 -0600804 if header_out:
805 db_out.export_header()
Tobin Ehlis20e32582016-12-05 14:50:03 -0700806 return result
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600807
808if __name__ == "__main__":
Mark Lobodzinskib44c54a2017-06-12 12:02:38 -0600809 sys.exit(main(sys.argv[1:]))
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600810