blob: c34a0496953187c36125926d6fea2b3765527440 [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 ]")
Dave Houltoncacef472018-05-29 13:00:42 -0600147 print (" [ -verbose ]")
148 print (" [ -help ]")
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700149 print ("\n The vk_validation_stats script parses validation layer source files to")
150 print (" determine the set of valid usage checks and tests currently implemented,")
Dave Houltoncacef472018-05-29 13:00:42 -0600151 print (" and generates coverage values by comparing against the full set of valid")
152 print (" usage identifiers in the Vulkan-Headers registry file 'validusage.json'")
153 print ("\nArguments: ")
154 print (" <json-file> (required) registry file 'validusage.json'")
155 print (" -c report consistency warnings")
156 print (" -todo report unimplemented VUIDs")
157 print (" -vuid <vuid_name> report status of individual VUID <vuid_name>")
158 print (" -text [filename] output the error database text to <text_database_filename>,")
159 print (" defaults to 'validation_error_database.txt'")
160 print (" -csv [filename] output the error database in csv to <csv_database_filename>,")
161 print (" defaults to 'validation_error_database.csv'")
162 print (" -html [filename] output the error database in html to <html_database_filename>,")
163 print (" defaults to 'validation_error_database.html'")
Dave Houlton407df732018-08-06 17:58:24 -0600164 print (" -export_header export a new VUID error text header file to <%s>" % header_filename)
Dave Houltoncacef472018-05-29 13:00:42 -0600165 print (" -verbose show your work (to stdout)")
166
167class ValidationJSON:
168 def __init__(self, filename):
169 self.filename = filename
170 self.explicit_vuids = set()
171 self.implicit_vuids = set()
172 self.all_vuids = set()
173 self.vuid_db = defaultdict(list) # Maps VUID string to list of json-data dicts
174 self.apiversion = ""
Dave Houltoncacef472018-05-29 13:00:42 -0600175 self.duplicate_vuids = set()
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700176
Dave Houlton407df732018-08-06 17:58:24 -0600177 # A set of specific regular expression substitutions needed to clean up VUID text
178 self.regex_dict = {}
179 self.regex_dict[re.compile('<.*?>|&(amp;)+lt;|&(amp;)+gt;')] = ""
180 self.regex_dict[re.compile(r'\\\(codeSize \\over 4\\\)')] = "(codeSize/4)"
Shannon McPherson3ea65132018-12-05 10:37:39 -0700181 self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{height}{maxFragmentDensityTexelSize_{height}}}\\rceil\\\)')] = "the ceiling of height/maxFragmentDensityTexelSize.height"
182 self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{width}{maxFragmentDensityTexelSize_{width}}}\\rceil\\\)')] = "the ceiling of width/maxFragmentDensityTexelSize.width"
183 self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{maxFramebufferHeight}{minFragmentDensityTexelSize_{height}}}\\rceil\\\)')] = "the ceiling of maxFramebufferHeight/minFragmentDensityTexelSize.height"
184 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 -0600185 self.regex_dict[re.compile(r'\\\(\\lceil\{\\mathit\{rasterizationSamples} \\over 32}\\rceil\\\)')] = "(rasterizationSamples/32)"
Shannon McPhersonb40f1a22018-10-30 16:45:07 -0600186 self.regex_dict[re.compile(r'\\\(\\textrm\{codeSize} \\over 4\\\)')] = "(codeSize/4)"
Dave Houlton407df732018-08-06 17:58:24 -0600187 # Some fancy punctuation chars that break the Android build...
188 self.regex_dict[re.compile('&#8594;')] = "->" # Arrow char
189 self.regex_dict[re.compile('&#8217;')] = "'" # Left-slanting apostrophe to apostrophe
190 self.regex_dict[re.compile('&#822(0|1);')] = "'" # L/R-slanting quotes to apostrophe
Dave Houltoncacef472018-05-29 13:00:42 -0600191
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600192 def read(self):
Dave Houltoncacef472018-05-29 13:00:42 -0600193 self.json_dict = {}
194 if os.path.isfile(self.filename):
Dave Houlton407df732018-08-06 17:58:24 -0600195 json_file = open(self.filename, 'r', encoding='utf-8')
Dave Houltoncacef472018-05-29 13:00:42 -0600196 self.json_dict = json.load(json_file)
197 json_file.close()
198 if len(self.json_dict) == 0:
199 print("Error: Error loading validusage.json file <%s>" % self.filename)
200 sys.exit(-1)
201 try:
202 version = self.json_dict['version info']
203 validation = self.json_dict['validation']
204 self.apiversion = version['api version']
205 except:
206 print("Error: Failure parsing validusage.json object")
207 sys.exit(-1)
208
209 # Parse vuid from json into local databases
210 for apiname in validation.keys():
211 # print("entrypoint:%s"%apiname)
212 apidict = validation[apiname]
213 for ext in apidict.keys():
214 vlist = apidict[ext]
215 for ventry in vlist:
216 vuid_string = ventry['vuid']
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700217 if (vuid_string[-5:-1].isdecimal()):
Dave Houltoncacef472018-05-29 13:00:42 -0600218 self.explicit_vuids.add(vuid_string) # explicit end in 5 numeric chars
219 vtype = 'explicit'
220 else:
221 self.implicit_vuids.add(vuid_string) # otherwise, implicit
222 vtype = 'implicit'
223 vuid_text = ventry['text']
Dave Houlton407df732018-08-06 17:58:24 -0600224 for regex, replacement in self.regex_dict.items():
225 vuid_text = re.sub(regex, replacement, vuid_text) # do regex substitution
226 vuid_text = html.unescape(vuid_text) # anything missed by the regex
227 self.vuid_db[vuid_string].append({'api':apiname, 'ext':ext, 'type':vtype, 'text':vuid_text})
Dave Houltoncacef472018-05-29 13:00:42 -0600228 self.all_vuids = self.explicit_vuids | self.implicit_vuids
229 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 -0600230 if len(self.duplicate_vuids) > 0:
231 print("Warning: duplicate VUIDs found in validusage.json")
232
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600233
234class ValidationSource:
Mike Schuchardt7b12d652019-07-01 11:00:21 -0700235 def __init__(self, source_file_list):
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600236 self.source_files = source_file_list
Dave Houltoncacef472018-05-29 13:00:42 -0600237 self.vuid_count_dict = {} # dict of vuid values to the count of how much they're used, and location of where they're used
238 self.duplicated_checks = 0
239 self.explicit_vuids = set()
240 self.implicit_vuids = set()
241 self.unassigned_vuids = set()
242 self.all_vuids = set()
Mark Lobodzinski05849f02017-06-21 14:44:14 -0600243
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600244 def parse(self):
Dave Houltoncacef472018-05-29 13:00:42 -0600245 prepend = None
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600246 for sf in self.source_files:
Tobin Ehlis3d1f2bd2016-12-22 11:19:15 -0700247 line_num = 0
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600248 with open(sf) as f:
249 for line in f:
Tobin Ehlis3d1f2bd2016-12-22 11:19:15 -0700250 line_num = line_num + 1
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600251 if True in [line.strip().startswith(comment) for comment in ['//', '/*']]:
252 continue
Dave Houltoncacef472018-05-29 13:00:42 -0600253 # Find vuid strings
Michał Janiszewski3c3ce9e2018-10-30 23:25:21 +0100254 if prepend is not None:
Dave Houltoncacef472018-05-29 13:00:42 -0600255 line = prepend[:-2] + line.lstrip().lstrip('"') # join lines skipping CR, whitespace and trailing/leading quote char
256 prepend = None
257 if any(prefix in line for prefix in vuid_prefixes):
Shannon McPhersondad26362019-06-12 10:51:46 -0600258 # Replace the '(' of lines containing validation helper functions with ' ' to make them easier to parse
259 line = line.replace("(", " ")
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600260 line_list = line.split()
Dave Houltoncacef472018-05-29 13:00:42 -0600261
262 # 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
263 broken_vuid = line_list[-1].strip('"')
264 if any(broken_vuid.startswith(prefix) for prefix in vuid_prefixes) and broken_vuid.endswith('-'):
265 prepend = line
266 continue
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700267
Dave Houltoncacef472018-05-29 13:00:42 -0600268 vuid_list = []
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600269 for str in line_list:
Dave Houltoncacef472018-05-29 13:00:42 -0600270 if any(prefix in str for prefix in vuid_prefixes):
271 vuid_list.append(str.strip(',);{}"'))
272 for vuid in vuid_list:
273 if vuid not in self.vuid_count_dict:
274 self.vuid_count_dict[vuid] = {}
275 self.vuid_count_dict[vuid]['count'] = 1
276 self.vuid_count_dict[vuid]['file_line'] = []
277 else:
278 if self.vuid_count_dict[vuid]['count'] == 1: # only count first time duplicated
279 self.duplicated_checks = self.duplicated_checks + 1
280 self.vuid_count_dict[vuid]['count'] = self.vuid_count_dict[vuid]['count'] + 1
281 self.vuid_count_dict[vuid]['file_line'].append('%s,%d' % (sf, line_num))
282 # Sort vuids by type
283 for vuid in self.vuid_count_dict.keys():
284 if (vuid.startswith('VUID-')):
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700285 if (vuid[-5:-1].isdecimal()):
Dave Houltoncacef472018-05-29 13:00:42 -0600286 self.explicit_vuids.add(vuid) # explicit end in 5 numeric chars
287 else:
288 self.implicit_vuids.add(vuid)
289 elif (vuid.startswith('UNASSIGNED-')):
290 self.unassigned_vuids.add(vuid)
291 else:
292 print("Unable to categorize VUID: %s" % vuid)
293 print("Confused while parsing VUIDs in layer source code - cannot proceed. (FIXME)")
294 exit(-1)
295 self.all_vuids = self.explicit_vuids | self.implicit_vuids | self.unassigned_vuids
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600296
297# Class to parse the validation layer test source and store testnames
Dave Houltoncacef472018-05-29 13:00:42 -0600298class ValidationTests:
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600299 def __init__(self, test_file_list, test_group_name=['VkLayerTest', 'VkPositiveLayerTest', 'VkWsiEnabledLayerTest']):
300 self.test_files = test_file_list
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600301 self.test_trigger_txt_list = []
302 for tg in test_group_name:
303 self.test_trigger_txt_list.append('TEST_F(%s' % tg)
Dave Houltoncacef472018-05-29 13:00:42 -0600304 self.explicit_vuids = set()
305 self.implicit_vuids = set()
306 self.unassigned_vuids = set()
307 self.all_vuids = set()
308 #self.test_to_vuids = {} # Map test name to VUIDs tested
309 self.vuid_to_tests = defaultdict(set) # Map VUIDs to set of test names where implemented
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600310
311 # Parse test files into internal data struct
312 def parse(self):
313 # For each test file, parse test names into set
314 grab_next_line = False # handle testname on separate line than wildcard
Tobin Ehlis9a68c982016-12-29 14:51:17 -0700315 testname = ''
Dave Houltoncacef472018-05-29 13:00:42 -0600316 prepend = None
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600317 for test_file in self.test_files:
318 with open(test_file) as tf:
319 for line in tf:
320 if True in [line.strip().startswith(comment) for comment in ['//', '/*']]:
321 continue
322
Dave Houltoncacef472018-05-29 13:00:42 -0600323 # if line ends in a broken VUID string, fix that before proceeding
Michał Janiszewski3c3ce9e2018-10-30 23:25:21 +0100324 if prepend is not None:
Dave Houltoncacef472018-05-29 13:00:42 -0600325 line = prepend[:-2] + line.lstrip().lstrip('"') # join lines skipping CR, whitespace and trailing/leading quote char
326 prepend = None
327 if any(prefix in line for prefix in vuid_prefixes):
328 line_list = line.split()
329
330 # 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
331 broken_vuid = line_list[-1].strip('"')
332 if any(broken_vuid.startswith(prefix) for prefix in vuid_prefixes) and broken_vuid.endswith('-'):
333 prepend = line
334 continue
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700335
Dave Houltoncacef472018-05-29 13:00:42 -0600336 if any(ttt in line for ttt in self.test_trigger_txt_list):
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600337 testname = line.split(',')[-1]
338 testname = testname.strip().strip(' {)')
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600339 if ('' == testname):
340 grab_next_line = True
341 continue
Dave Houltoncacef472018-05-29 13:00:42 -0600342 #self.test_to_vuids[testname] = []
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600343 if grab_next_line: # test name on its own line
344 grab_next_line = False
345 testname = testname.strip().strip(' {)')
Dave Houltoncacef472018-05-29 13:00:42 -0600346 #self.test_to_vuids[testname] = []
347 if any(prefix in line for prefix in vuid_prefixes):
348 line_list = re.split('[\s{}[\]()"]+',line)
Tobin Ehlis71f38c12017-01-12 14:26:56 -0700349 for sub_str in line_list:
Dave Houltoncacef472018-05-29 13:00:42 -0600350 if any(prefix in sub_str for prefix in vuid_prefixes):
351 vuid_str = sub_str.strip(',);:"')
352 self.vuid_to_tests[vuid_str].add(testname)
353 #self.test_to_vuids[testname].append(vuid_str)
354 if (vuid_str.startswith('VUID-')):
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700355 if (vuid_str[-5:-1].isdecimal()):
Dave Houltoncacef472018-05-29 13:00:42 -0600356 self.explicit_vuids.add(vuid_str) # explicit end in 5 numeric chars
357 else:
358 self.implicit_vuids.add(vuid_str)
359 elif (vuid_str.startswith('UNASSIGNED-')):
360 self.unassigned_vuids.add(vuid_str)
361 else:
362 print("Unable to categorize VUID: %s" % vuid_str)
363 print("Confused while parsing VUIDs in test code - cannot proceed. (FIXME)")
364 exit(-1)
365 self.all_vuids = self.explicit_vuids | self.implicit_vuids | self.unassigned_vuids
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600366
Dave Houltoncacef472018-05-29 13:00:42 -0600367# Class to do consistency checking
368#
369class Consistency:
370 def __init__(self, all_json, all_checks, all_tests):
371 self.valid = all_json
372 self.checks = all_checks
373 self.tests = all_tests
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600374
Dave Houltoncacef472018-05-29 13:00:42 -0600375 if (dealias_khr):
376 dk = set()
377 for vuid in self.checks:
378 if vuid in khr_aliases:
379 dk.add(khr_aliases[vuid])
380 else:
381 dk.add(vuid)
382 self.checks = dk
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600383
Dave Houltoncacef472018-05-29 13:00:42 -0600384 dk = set()
385 for vuid in self.tests:
386 if vuid in khr_aliases:
387 dk.add(khr_aliases[vuid])
388 else:
389 dk.add(vuid)
390 self.tests = dk
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600391
Dave Houltoncacef472018-05-29 13:00:42 -0600392 # Report undefined VUIDs in source code
393 def undef_vuids_in_layer_code(self):
394 undef_set = self.checks - self.valid
395 undef_set.discard('VUID-Undefined') # don't report Undefined
396 if ignore_unassigned:
397 unassigned = set({uv for uv in undef_set if uv.startswith('UNASSIGNED-')})
398 undef_set = undef_set - unassigned
399 if (len(undef_set) > 0):
400 print("\nFollowing VUIDs found in layer code are not defined in validusage.json (%d):" % len(undef_set))
401 undef = list(undef_set)
402 undef.sort()
403 for vuid in undef:
404 print(" %s" % vuid)
405 return False
406 return True
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600407
Dave Houltoncacef472018-05-29 13:00:42 -0600408 # Report undefined VUIDs in tests
409 def undef_vuids_in_tests(self):
410 undef_set = self.tests - self.valid
411 undef_set.discard('VUID-Undefined') # don't report Undefined
412 if ignore_unassigned:
413 unassigned = set({uv for uv in undef_set if uv.startswith('UNASSIGNED-')})
414 undef_set = undef_set - unassigned
415 if (len(undef_set) > 0):
416 ok = False
417 print("\nFollowing VUIDs found in layer tests are not defined in validusage.json (%d):" % len(undef_set))
418 undef = list(undef_set)
419 undef.sort()
420 for vuid in undef:
421 print(" %s" % vuid)
422 return False
423 return True
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600424
Dave Houltoncacef472018-05-29 13:00:42 -0600425 # Report vuids in tests that are not in source
426 def vuids_tested_not_checked(self):
427 undef_set = self.tests - self.checks
428 undef_set.discard('VUID-Undefined') # don't report Undefined
429 if ignore_unassigned:
430 unassigned = set()
431 for vuid in undef_set:
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700432 if vuid.startswith('UNASSIGNED-'):
Dave Houltoncacef472018-05-29 13:00:42 -0600433 unassigned.add(vuid)
434 undef_set = undef_set - unassigned
435 if (len(undef_set) > 0):
436 ok = False
437 print("\nFollowing VUIDs found in tests but are not checked in layer code (%d):" % len(undef_set))
438 undef = list(undef_set)
439 undef.sort()
440 for vuid in undef:
441 print(" %s" % vuid)
442 return False
443 return True
444
445 # TODO: Explicit checked VUIDs which have no test
446 # def explicit_vuids_checked_not_tested(self):
447
448
449# Class to output database in various flavors
450#
451class OutputDatabase:
452 def __init__(self, val_json, val_source, val_tests):
453 self.vj = val_json
454 self.vs = val_source
455 self.vt = val_tests
Dave Houlton729c7822018-11-19 11:52:23 -0700456 self.header_version = "/* THIS FILE IS GENERATED - DO NOT EDIT (scripts/vk_validation_stats.py) */"
457 self.header_version += "\n/* Vulkan specification version: %s */" % val_json.apiversion
Dave Houlton729c7822018-11-19 11:52:23 -0700458 self.header_preamble = """
Dave Houlton407df732018-08-06 17:58:24 -0600459/*
460 * Vulkan
461 *
Jasper St. Pierre1948bcc2019-01-18 13:55:20 -0800462 * Copyright (c) 2016-2019 Google Inc.
463 * Copyright (c) 2016-2019 LunarG, Inc.
Dave Houlton407df732018-08-06 17:58:24 -0600464 *
465 * Licensed under the Apache License, Version 2.0 (the "License");
466 * you may not use this file except in compliance with the License.
467 * You may obtain a copy of the License at
468 *
469 * http://www.apache.org/licenses/LICENSE-2.0
470 *
471 * Unless required by applicable law or agreed to in writing, software
472 * distributed under the License is distributed on an "AS IS" BASIS,
473 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
474 * See the License for the specific language governing permissions and
475 * limitations under the License.
476 *
477 * Author: Tobin Ehlis <tobine@google.com>
478 * Author: Dave Houlton <daveh@lunarg.com>
479 */
480
481#pragma once
482
483// Disable auto-formatting for generated file
484// clang-format off
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700485
Dave Houlton407df732018-08-06 17:58:24 -0600486// Mapping from VUID string to the corresponding spec text
Dave Houlton4d9b2f82018-10-24 18:21:06 -0600487typedef struct _vuid_spec_text_pair {
488 const char * vuid;
489 const char * spec_text;
490} vuid_spec_text_pair;
491
492static const vuid_spec_text_pair vuid_spec_text[] = {
Dave Houlton407df732018-08-06 17:58:24 -0600493"""
494 self.header_postamble = """};
Dave Houlton4d9b2f82018-10-24 18:21:06 -0600495"""
Dave Houlton407df732018-08-06 17:58:24 -0600496 self.spec_url = "https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html"
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700497
Dave Houltoncacef472018-05-29 13:00:42 -0600498 def dump_txt(self):
499 print("\n Dumping database to text file: %s" % txt_filename)
500 with open (txt_filename, 'w') as txt:
501 txt.write("## VUID Database\n")
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700502 txt.write("## Format: VUID_NAME | CHECKED | TEST | TYPE | API/STRUCT | EXTENSION | VUID_TEXT\n##\n")
Dave Houltoncacef472018-05-29 13:00:42 -0600503 vuid_list = list(self.vj.all_vuids)
504 vuid_list.sort()
505 for vuid in vuid_list:
506 db_list = self.vj.vuid_db[vuid]
507 db_list.sort(key=operator.itemgetter('ext')) # sort list to ease diffs of output file
508 for db_entry in db_list:
509 checked = 'N'
510 if vuid in self.vs.all_vuids:
511 checked = 'Y'
512 test = 'None'
513 if vuid in self.vt.vuid_to_tests:
514 test_list = list(self.vt.vuid_to_tests[vuid])
515 test_list.sort() # sort tests, for diff-ability
516 sep = ', '
517 test = sep.join(test_list)
518
519 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']))
520
521 def dump_csv(self):
522 print("\n Dumping database to csv file: %s" % csv_filename)
523 with open (csv_filename, 'w', newline='') as csvfile:
524 cw = csv.writer(csvfile)
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700525 cw.writerow(['VUID_NAME','CHECKED','TEST','TYPE','API/STRUCT','EXTENSION','VUID_TEXT'])
Dave Houltoncacef472018-05-29 13:00:42 -0600526 vuid_list = list(self.vj.all_vuids)
527 vuid_list.sort()
528 for vuid in vuid_list:
529 for db_entry in self.vj.vuid_db[vuid]:
530 row = [vuid]
531 if vuid in self.vs.all_vuids:
532 row.append('Y')
533 else:
534 row.append('N')
535 test = 'None'
536 if vuid in self.vt.vuid_to_tests:
537 sep = ', '
538 test = sep.join(self.vt.vuid_to_tests[vuid])
539 row.append(test)
540 row.append(db_entry['type'])
541 row.append(db_entry['api'])
542 row.append(db_entry['ext'])
543 row.append(db_entry['text'])
544 cw.writerow(row)
545
546 def dump_html(self):
547 print("\n Dumping database to html file: %s" % html_filename)
548 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 -0700549 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 -0600550 with open (html_filename, 'w') as hfile:
551 hfile.write(preamble)
552 hfile.write(headers)
553 vuid_list = list(self.vj.all_vuids)
554 vuid_list.sort()
555 for vuid in vuid_list:
556 for db_entry in self.vj.vuid_db[vuid]:
557 hfile.write('<tr><th>%s</th>' % vuid)
558 checked = '<span style="color:red;">N</span>'
559 if vuid in self.vs.all_vuids:
560 checked = '<span style="color:limegreen;">Y</span>'
561 hfile.write('<th>%s</th>' % checked)
562 test = 'None'
563 if vuid in self.vt.vuid_to_tests:
564 sep = ', '
565 test = sep.join(self.vt.vuid_to_tests[vuid])
566 hfile.write('<th>%s</th>' % test)
567 hfile.write('<th>%s</th>' % db_entry['type'])
568 hfile.write('<th>%s</th>' % db_entry['api'])
569 hfile.write('<th>%s</th>' % db_entry['ext'])
570 hfile.write('<th>%s</th></tr>\n' % db_entry['text'])
571 hfile.write('</table>\n</body>\n</html>\n')
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600572
Dave Houlton407df732018-08-06 17:58:24 -0600573 def export_header(self):
574 print("\n Exporting header file to: %s" % header_filename)
575 with open (header_filename, 'w') as hfile:
Dave Houlton729c7822018-11-19 11:52:23 -0700576 hfile.write(self.header_version)
Dave Houlton407df732018-08-06 17:58:24 -0600577 hfile.write(self.header_preamble)
578 vuid_list = list(self.vj.all_vuids)
579 vuid_list.sort()
John Zulaufd09ba822019-04-29 07:05:07 -0600580 cmd_dict = {}
Dave Houlton407df732018-08-06 17:58:24 -0600581 for vuid in vuid_list:
582 db_entry = self.vj.vuid_db[vuid][0]
John Zulaufd09ba822019-04-29 07:05:07 -0600583 db_text = db_entry['text'].strip(' ')
584 hfile.write(' {"%s", "%s (%s#%s)"},\n' % (vuid, db_text, self.spec_url, vuid))
Dave Houlton407df732018-08-06 17:58:24 -0600585 # For multiply-defined VUIDs, include versions with extension appended
586 if len(self.vj.vuid_db[vuid]) > 1:
587 for db_entry in self.vj.vuid_db[vuid]:
John Zulaufd09ba822019-04-29 07:05:07 -0600588 hfile.write(' {"%s[%s]", "%s (%s#%s)"},\n' % (vuid, db_entry['ext'].strip(' '), db_text, self.spec_url, vuid))
589 if 'commandBuffer must be in the recording state' in db_text:
590 cmd_dict[vuid] = db_text
Dave Houlton407df732018-08-06 17:58:24 -0600591 hfile.write(self.header_postamble)
592
John Zulaufd09ba822019-04-29 07:05:07 -0600593 # Generate the information for validating recording state VUID's
594 cmd_prefix = 'prefix##'
595 cmd_regex = re.compile(r'VUID-vk(Cmd|End)(\w+)')
596 cmd_vuid_vector = [' "VUID_Undefined"']
597 cmd_name_vector = [ ' "Command_Undefined"' ]
598 cmd_enum = [' ' + cmd_prefix + 'NONE = 0']
599
600 cmd_ordinal = 1
Mike Schuchardtaed5ac32019-06-21 09:03:31 -0700601 for vuid, db_text in sorted(cmd_dict.items()):
John Zulaufd09ba822019-04-29 07:05:07 -0600602 cmd_match = cmd_regex.match(vuid)
603 if cmd_match.group(1) == "End":
604 end = "END"
605 else:
606 end = ""
607 cmd_name_vector.append(' "vk'+ cmd_match.group(1) + cmd_match.group(2) + '"')
608 cmd_name = cmd_prefix + end + cmd_match.group(2).upper()
609 cmd_enum.append(' {} = {}'.format(cmd_name, cmd_ordinal))
610 cmd_ordinal += 1
611 cmd_vuid_vector.append(' "{}"'.format(vuid))
612
613 hfile.write('\n// Defines to allow creating "must be recording" meta data\n')
614 cmd_enum.append(' {}RANGE_SIZE = {}'.format(cmd_prefix, cmd_ordinal))
615 cmd_enum_string = '#define VUID_CMD_ENUM_LIST(prefix)\\\n' + ',\\\n'.join(cmd_enum) + '\n\n'
616 hfile.write(cmd_enum_string)
617 cmd_name_list_string = '#define VUID_CMD_NAME_LIST\\\n' + ',\\\n'.join(cmd_name_vector) + '\n\n'
618 hfile.write(cmd_name_list_string)
619 vuid_vector_string = '#define VUID_MUST_BE_RECORDING_LIST\\\n' + ',\\\n'.join(cmd_vuid_vector) + '\n'
620 hfile.write(vuid_vector_string)
621
Mark Lobodzinskib44c54a2017-06-12 12:02:38 -0600622def main(argv):
Dave Houltoncacef472018-05-29 13:00:42 -0600623 global verbose_mode
624 global txt_filename
625 global csv_filename
626 global html_filename
627
628 run_consistency = False
629 report_unimplemented = False
630 get_vuid_status = ''
631 txt_out = False
632 csv_out = False
633 html_out = False
Dave Houlton407df732018-08-06 17:58:24 -0600634 header_out = False
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700635
Dave Houltoncacef472018-05-29 13:00:42 -0600636 if (1 > len(argv)):
637 printHelp()
638 sys.exit()
639
640 # Parse script args
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700641 json_filename = argv[0]
Dave Houltoncacef472018-05-29 13:00:42 -0600642 i = 1
643 while (i < len(argv)):
644 arg = argv[i]
645 i = i + 1
646 if (arg == '-c'):
647 run_consistency = True
648 elif (arg == '-vuid'):
649 get_vuid_status = argv[i]
650 i = i + 1
651 elif (arg == '-todo'):
652 report_unimplemented = True
Karl Schultz49d66bb2018-07-09 16:24:46 -0600653 elif (arg == '-text'):
Dave Houltoncacef472018-05-29 13:00:42 -0600654 txt_out = True
655 # Set filename if supplied, else use default
656 if i < len(argv) and not argv[i].startswith('-'):
657 txt_filename = argv[i]
658 i = i + 1
659 elif (arg == '-csv'):
660 csv_out = True
661 # Set filename if supplied, else use default
662 if i < len(argv) and not argv[i].startswith('-'):
663 csv_filename = argv[i]
664 i = i + 1
665 elif (arg == '-html'):
666 html_out = True
667 # Set filename if supplied, else use default
668 if i < len(argv) and not argv[i].startswith('-'):
669 html_filename = argv[i]
670 i = i + 1
Dave Houlton407df732018-08-06 17:58:24 -0600671 elif (arg == '-export_header'):
672 header_out = True
Dave Houltoncacef472018-05-29 13:00:42 -0600673 elif (arg in ['-verbose']):
674 verbose_mode = True
675 elif (arg in ['-help', '-h']):
676 printHelp()
677 sys.exit()
678 else:
679 print("Unrecognized argument: %s\n" % arg)
680 printHelp()
681 sys.exit()
682
Tobin Ehlis20e32582016-12-05 14:50:03 -0700683 result = 0 # Non-zero result indicates an error case
Dave Houltoncacef472018-05-29 13:00:42 -0600684
685 # Parse validusage json
686 val_json = ValidationJSON(json_filename)
687 val_json.read()
688 exp_json = len(val_json.explicit_vuids)
689 imp_json = len(val_json.implicit_vuids)
690 all_json = len(val_json.all_vuids)
691 if verbose_mode:
692 print("Found %d unique error vuids in validusage.json file." % all_json)
693 print(" %d explicit" % exp_json)
694 print(" %d implicit" % imp_json)
695 if len(val_json.duplicate_vuids) > 0:
696 print("%d VUIDs appear in validusage.json more than once." % len(val_json.duplicate_vuids))
697 for vuid in val_json.duplicate_vuids:
698 print(" %s" % vuid)
699 for ext in val_json.vuid_db[vuid]:
700 print(" with extension: %s" % ext['ext'])
701
702 # Parse layer source files
Mike Schuchardt7b12d652019-07-01 11:00:21 -0700703 val_source = ValidationSource(layer_source_files)
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600704 val_source.parse()
Dave Houltoncacef472018-05-29 13:00:42 -0600705 exp_checks = len(val_source.explicit_vuids)
706 imp_checks = len(val_source.implicit_vuids)
707 all_checks = len(val_source.vuid_count_dict.keys())
708 if verbose_mode:
709 print("Found %d unique vuid checks in layer source code." % all_checks)
710 print(" %d explicit" % exp_checks)
711 print(" %d implicit" % imp_checks)
712 print(" %d unassigned" % len(val_source.unassigned_vuids))
713 print(" %d checks are implemented more that once" % val_source.duplicated_checks)
714
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600715 # Parse test files
Mike Schuchardt7b12d652019-07-01 11:00:21 -0700716 val_tests = ValidationTests(test_source_files)
Dave Houltoncacef472018-05-29 13:00:42 -0600717 val_tests.parse()
718 exp_tests = len(val_tests.explicit_vuids)
719 imp_tests = len(val_tests.implicit_vuids)
720 all_tests = len(val_tests.all_vuids)
Mark Lobodzinski060a8e32018-01-08 09:08:06 -0700721 if verbose_mode:
Mike Schuchardt7b12d652019-07-01 11:00:21 -0700722 print("Found %d unique error vuids in test source code." % all_tests)
Dave Houltoncacef472018-05-29 13:00:42 -0600723 print(" %d explicit" % exp_tests)
724 print(" %d implicit" % imp_tests)
725 print(" %d unassigned" % len(val_tests.unassigned_vuids))
Mike Weiblenfe186122017-02-03 12:44:53 -0700726
Dave Houltoncacef472018-05-29 13:00:42 -0600727 # Process stats
728 print("\nValidation Statistics (using validusage.json version %s)" % val_json.apiversion)
729 print(" VUIDs defined in JSON file: %04d explicit, %04d implicit, %04d total." % (exp_json, imp_json, all_json))
730 print(" VUIDs checked in layer code: %04d explicit, %04d implicit, %04d total." % (exp_checks, imp_checks, all_checks))
731 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 -0700732
Dave Houltoncacef472018-05-29 13:00:42 -0600733 print("\nVUID check coverage")
734 print(" Explicit VUIDs checked: %.1f%% (%d checked vs %d defined)" % ((100.0 * exp_checks / exp_json), exp_checks, exp_json))
735 print(" Implicit VUIDs checked: %.1f%% (%d checked vs %d defined)" % ((100.0 * imp_checks / imp_json), imp_checks, imp_json))
736 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 -0700737
Dave Houltoncacef472018-05-29 13:00:42 -0600738 print("\nVUID test coverage")
739 print(" Explicit VUIDs tested: %.1f%% (%d tested vs %d checks)" % ((100.0 * exp_tests / exp_checks), exp_tests, exp_checks))
740 print(" Implicit VUIDs tested: %.1f%% (%d tested vs %d checks)" % ((100.0 * imp_tests / imp_checks), imp_tests, imp_checks))
741 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 -0700742
Dave Houltoncacef472018-05-29 13:00:42 -0600743 # Report status of a single VUID
744 if len(get_vuid_status) > 1:
745 print("\n\nChecking status of <%s>" % get_vuid_status);
746 if get_vuid_status not in val_json.all_vuids:
747 print(' Not a valid VUID string.')
748 else:
749 if get_vuid_status in val_source.explicit_vuids:
750 print(' Implemented!')
751 line_list = val_source.vuid_count_dict[get_vuid_status]['file_line']
752 for line in line_list:
753 print(' => %s' % line)
Dave Houltonf93bbab2018-06-26 17:21:12 -0600754 elif get_vuid_status in val_source.implicit_vuids:
755 print(' Implemented! (Implicit)')
756 line_list = val_source.vuid_count_dict[get_vuid_status]['file_line']
757 for line in line_list:
758 print(' => %s' % line)
Tobin Ehlis9a68c982016-12-29 14:51:17 -0700759 else:
Dave Houltoncacef472018-05-29 13:00:42 -0600760 print(' Not implemented.')
Dave Houltonf93bbab2018-06-26 17:21:12 -0600761 if get_vuid_status in val_tests.all_vuids:
Dave Houltoncacef472018-05-29 13:00:42 -0600762 print(' Has a test!')
763 test_list = val_tests.vuid_to_tests[get_vuid_status]
764 for test in test_list:
765 print(' => %s' % test)
766 else:
767 print(' Not tested.')
Mike Weiblenfe186122017-02-03 12:44:53 -0700768
Dave Houltoncacef472018-05-29 13:00:42 -0600769 # Report unimplemented explicit VUIDs
770 if report_unimplemented:
771 unim_explicit = val_json.explicit_vuids - val_source.explicit_vuids
772 print("\n\n%d explicit VUID checks remain unimplemented:" % len(unim_explicit))
773 ulist = list(unim_explicit)
774 ulist.sort()
775 for vuid in ulist:
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700776 print(" => %s" % vuid)
Dave Houltoncacef472018-05-29 13:00:42 -0600777
778 # Consistency tests
779 if run_consistency:
780 print("\n\nRunning consistency tests...")
781 con = Consistency(val_json.all_vuids, val_source.all_vuids, val_tests.all_vuids)
782 ok = con.undef_vuids_in_layer_code()
783 ok &= con.undef_vuids_in_tests()
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700784 ok &= con.vuids_tested_not_checked()
Dave Houltoncacef472018-05-29 13:00:42 -0600785
786 if ok:
787 print(" OK! No inconsistencies found.")
788
789 # Output database in requested format(s)
790 db_out = OutputDatabase(val_json, val_source, val_tests)
791 if txt_out:
792 db_out.dump_txt()
793 if csv_out:
794 db_out.dump_csv()
795 if html_out:
796 db_out.dump_html()
Dave Houlton407df732018-08-06 17:58:24 -0600797 if header_out:
798 db_out.export_header()
Tobin Ehlis20e32582016-12-05 14:50:03 -0700799 return result
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600800
801if __name__ == "__main__":
Mark Lobodzinskib44c54a2017-06-12 12:02:38 -0600802 sys.exit(main(sys.argv[1:]))
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600803