blob: f4ab2ce2a9df22cf79e986edf3ff87180359bac3 [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
24import os
25import sys
Dave Houltoncacef472018-05-29 13:00:42 -060026import operator
Tobin Ehlis35308dd2016-10-31 13:27:36 -060027import platform
Dave Houltoncacef472018-05-29 13:00:42 -060028import json
29import re
30import csv
31import html
Dave Houlton729c7822018-11-19 11:52:23 -070032import time
Dave Houltoncacef472018-05-29 13:00:42 -060033from collections import defaultdict
Tobin Ehlis35308dd2016-10-31 13:27:36 -060034
Dave Houltoncacef472018-05-29 13:00:42 -060035verbose_mode = False
36txt_db = False
37csv_db = False
38html_db = False
39txt_filename = "validation_error_database.txt"
40csv_filename = "validation_error_database.csv"
41html_filename = "validation_error_database.html"
Mike Schuchardt7b12d652019-07-01 11:00:21 -070042header_filename = "vk_validation_error_messages.h"
Dave Houltoncacef472018-05-29 13:00:42 -060043vuid_prefixes = ['VUID-', 'UNASSIGNED-']
Tobin Ehlis35308dd2016-10-31 13:27:36 -060044
Dave Houltoncacef472018-05-29 13:00:42 -060045# Hard-coded flags that could be command line args, if we decide that's useful
46# replace KHR vuids with non-KHR during consistency checking
47dealias_khr = True
48ignore_unassigned = True # These are not found in layer code unless they appear explicitly (most don't), so produce false positives
49
Mike Schuchardt7b12d652019-07-01 11:00:21 -070050# helper to define paths relative to this file
51def script_relative(path):
52 return os.path.abspath(os.path.join(os.path.dirname(__file__), path))
53
54layer_source_files = [script_relative(path) for path in [
55 '../layers/buffer_validation.cpp',
56 '../layers/core_validation.cpp',
57 '../layers/descriptor_sets.cpp',
58 '../layers/drawdispatch.cpp',
59 '../layers/parameter_validation_utils.cpp',
60 '../layers/object_tracker_utils.cpp',
61 '../layers/shader_validation.cpp',
62 '../layers/stateless_validation.h',
63 '../layers/generated/parameter_validation.cpp',
64 '../layers/generated/object_tracker.cpp',
65]]
66
67test_source_files = [script_relative(path) for path in [
68 '../tests/layer_validation_tests.cpp',
69 '../tests/vklayertests_buffer_image_memory_sampler.cpp',
70 '../tests/vklayertests_command.cpp',
71 '../tests/vklayertests_descriptor_renderpass_framebuffer.cpp',
72 '../tests/vklayertests_others.cpp',
73 '../tests/vklayertests_pipeline_shader.cpp',
74 '../tests/vkpositivelayertests.cpp',
75]]
Tobin Ehlis35308dd2016-10-31 13:27:36 -060076
Dave Houlton407df732018-08-06 17:58:24 -060077# This needs to be updated as new extensions roll in
Mark Lobodzinski02e23172019-03-04 15:27:55 -070078khr_aliases = {
79 'VUID-vkBindBufferMemory2KHR-device-parameter' : 'VUID-vkBindBufferMemory2-device-parameter',
80 'VUID-vkBindBufferMemory2KHR-pBindInfos-parameter' : 'VUID-vkBindBufferMemory2-pBindInfos-parameter',
81 'VUID-vkBindImageMemory2KHR-device-parameter' : 'VUID-vkBindImageMemory2-device-parameter',
82 'VUID-vkBindImageMemory2KHR-pBindInfos-parameter' : 'VUID-vkBindImageMemory2-pBindInfos-parameter',
83 'VUID-vkCmdDispatchBaseKHR-commandBuffer-parameter' : 'VUID-vkCmdDispatchBase-commandBuffer-parameter',
84 'VUID-vkCmdSetDeviceMaskKHR-commandBuffer-parameter' : 'VUID-vkCmdSetDeviceMask-commandBuffer-parameter',
85 'VUID-vkCreateDescriptorUpdateTemplateKHR-device-parameter' : 'VUID-vkCreateDescriptorUpdateTemplate-device-parameter',
86 'VUID-vkCreateDescriptorUpdateTemplateKHR-pDescriptorUpdateTemplate-parameter' : 'VUID-vkCreateDescriptorUpdateTemplate-pDescriptorUpdateTemplate-parameter',
87 'VUID-vkCreateSamplerYcbcrConversionKHR-device-parameter' : 'VUID-vkCreateSamplerYcbcrConversion-device-parameter',
88 'VUID-vkCreateSamplerYcbcrConversionKHR-pYcbcrConversion-parameter' : 'VUID-vkCreateSamplerYcbcrConversion-pYcbcrConversion-parameter',
89 'VUID-vkDestroyDescriptorUpdateTemplateKHR-descriptorUpdateTemplate-parameter' : 'VUID-vkDestroyDescriptorUpdateTemplate-descriptorUpdateTemplate-parameter',
Dave Houltoncacef472018-05-29 13:00:42 -060090 'VUID-vkDestroyDescriptorUpdateTemplateKHR-descriptorUpdateTemplate-parent' : 'VUID-vkDestroyDescriptorUpdateTemplate-descriptorUpdateTemplate-parent',
Mark Lobodzinski02e23172019-03-04 15:27:55 -070091 'VUID-vkDestroyDescriptorUpdateTemplateKHR-device-parameter' : 'VUID-vkDestroyDescriptorUpdateTemplate-device-parameter',
92 'VUID-vkDestroySamplerYcbcrConversionKHR-device-parameter' : 'VUID-vkDestroySamplerYcbcrConversion-device-parameter',
93 'VUID-vkDestroySamplerYcbcrConversionKHR-ycbcrConversion-parameter' : 'VUID-vkDestroySamplerYcbcrConversion-ycbcrConversion-parameter',
Dave Houltoncacef472018-05-29 13:00:42 -060094 'VUID-vkDestroySamplerYcbcrConversionKHR-ycbcrConversion-parent' : 'VUID-vkDestroySamplerYcbcrConversion-ycbcrConversion-parent',
Mark Lobodzinski02e23172019-03-04 15:27:55 -070095 'VUID-vkEnumeratePhysicalDeviceGroupsKHR-instance-parameter' : 'VUID-vkEnumeratePhysicalDeviceGroups-instance-parameter',
96 'VUID-vkEnumeratePhysicalDeviceGroupsKHR-pPhysicalDeviceGroupProperties-parameter' : 'VUID-vkEnumeratePhysicalDeviceGroups-pPhysicalDeviceGroupProperties-parameter',
97 'VUID-vkGetBufferMemoryRequirements2KHR-device-parameter' : 'VUID-vkGetBufferMemoryRequirements2-device-parameter',
98 'VUID-vkGetDescriptorSetLayoutSupportKHR-device-parameter' : 'VUID-vkGetDescriptorSetLayoutSupport-device-parameter',
99 'VUID-vkGetDeviceGroupPeerMemoryFeaturesKHR-device-parameter' : 'VUID-vkGetDeviceGroupPeerMemoryFeatures-device-parameter',
100 'VUID-vkGetDeviceGroupPeerMemoryFeaturesKHR-pPeerMemoryFeatures-parameter' : 'VUID-vkGetDeviceGroupPeerMemoryFeatures-pPeerMemoryFeatures-parameter',
101 'VUID-vkGetImageMemoryRequirements2KHR-device-parameter' : 'VUID-vkGetImageMemoryRequirements2-device-parameter',
102 'VUID-vkGetImageSparseMemoryRequirements2KHR-device-parameter' : 'VUID-vkGetImageSparseMemoryRequirements2-device-parameter',
103 'VUID-vkGetImageSparseMemoryRequirements2KHR-pSparseMemoryRequirements-parameter' : 'VUID-vkGetImageSparseMemoryRequirements2-pSparseMemoryRequirements-parameter',
104 'VUID-vkGetPhysicalDeviceExternalBufferPropertiesKHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceExternalBufferProperties-physicalDevice-parameter',
105 'VUID-vkGetPhysicalDeviceExternalFencePropertiesKHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceExternalFenceProperties-physicalDevice-parameter',
106 'VUID-vkGetPhysicalDeviceExternalSemaphorePropertiesKHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceExternalSemaphoreProperties-physicalDevice-parameter',
107 'VUID-vkGetPhysicalDeviceFeatures2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceFeatures2-physicalDevice-parameter',
108 'VUID-vkGetPhysicalDeviceFormatProperties2KHR-format-parameter' : 'VUID-vkGetPhysicalDeviceFormatProperties2-format-parameter',
109 'VUID-vkGetPhysicalDeviceFormatProperties2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceFormatProperties2-physicalDevice-parameter',
110 'VUID-vkGetPhysicalDeviceImageFormatProperties2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceImageFormatProperties2-physicalDevice-parameter',
111 'VUID-vkGetPhysicalDeviceMemoryProperties2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceMemoryProperties2-physicalDevice-parameter',
112 'VUID-vkGetPhysicalDeviceProperties2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceProperties2-physicalDevice-parameter',
113 'VUID-vkGetPhysicalDeviceQueueFamilyProperties2KHR-pQueueFamilyProperties-parameter' : 'VUID-vkGetPhysicalDeviceQueueFamilyProperties2-pQueueFamilyProperties-parameter',
114 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2KHR-pProperties-parameter' : 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2-pProperties-parameter',
115 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2KHR-physicalDevice-parameter' : 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2-physicalDevice-parameter',
116 'VUID-vkTrimCommandPoolKHR-commandPool-parameter' : 'VUID-vkTrimCommandPool-commandPool-parameter',
Dave Houltoncacef472018-05-29 13:00:42 -0600117 'VUID-vkTrimCommandPoolKHR-commandPool-parent' : 'VUID-vkTrimCommandPool-commandPool-parent',
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700118 'VUID-vkTrimCommandPoolKHR-device-parameter' : 'VUID-vkTrimCommandPool-device-parameter',
Dave Houltoncacef472018-05-29 13:00:42 -0600119 'VUID-vkTrimCommandPoolKHR-flags-zerobitmask' : 'VUID-vkTrimCommandPool-flags-zerobitmask',
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700120 'VUID-vkUpdateDescriptorSetWithTemplateKHR-descriptorSet-parameter' : 'VUID-vkUpdateDescriptorSetWithTemplate-descriptorSet-parameter',
121 'VUID-vkUpdateDescriptorSetWithTemplateKHR-descriptorUpdateTemplate-parameter' : 'VUID-vkUpdateDescriptorSetWithTemplate-descriptorUpdateTemplate-parameter',
Dave Houltoncacef472018-05-29 13:00:42 -0600122 'VUID-vkUpdateDescriptorSetWithTemplateKHR-descriptorUpdateTemplate-parent' : 'VUID-vkUpdateDescriptorSetWithTemplate-descriptorUpdateTemplate-parent',
123 'VUID-vkUpdateDescriptorSetWithTemplateKHR-device-parameter' : 'VUID-vkUpdateDescriptorSetWithTemplate-device-parameter',
124 'VUID-vkCreateDescriptorUpdateTemplateKHR-pCreateInfo-parameter' : 'VUID-vkCreateDescriptorUpdateTemplate-pCreateInfo-parameter',
125 'VUID-vkCreateSamplerYcbcrConversionKHR-pCreateInfo-parameter' : 'VUID-vkCreateSamplerYcbcrConversion-pCreateInfo-parameter',
126 'VUID-vkGetBufferMemoryRequirements2KHR-pInfo-parameter' : 'VUID-vkGetBufferMemoryRequirements2-pInfo-parameter',
127 'VUID-vkGetBufferMemoryRequirements2KHR-pMemoryRequirements-parameter' : 'VUID-vkGetBufferMemoryRequirements2-pMemoryRequirements-parameter',
128 'VUID-vkGetDescriptorSetLayoutSupportKHR-pCreateInfo-parameter' : 'VUID-vkGetDescriptorSetLayoutSupport-pCreateInfo-parameter',
129 'VUID-vkGetDescriptorSetLayoutSupportKHR-pSupport-parameter' : 'VUID-vkGetDescriptorSetLayoutSupport-pSupport-parameter',
130 'VUID-vkGetImageMemoryRequirements2KHR-pInfo-parameter' : 'VUID-vkGetImageMemoryRequirements2-pInfo-parameter',
131 'VUID-vkGetImageMemoryRequirements2KHR-pMemoryRequirements-parameter' : 'VUID-vkGetImageMemoryRequirements2-pMemoryRequirements-parameter',
132 'VUID-vkGetImageSparseMemoryRequirements2KHR-pInfo-parameter' : 'VUID-vkGetImageSparseMemoryRequirements2-pInfo-parameter',
133 'VUID-vkGetPhysicalDeviceExternalBufferPropertiesKHR-pExternalBufferInfo-parameter' : 'VUID-vkGetPhysicalDeviceExternalBufferProperties-pExternalBufferInfo-parameter',
134 'VUID-vkGetPhysicalDeviceExternalBufferPropertiesKHR-pExternalBufferProperties-parameter' : 'VUID-vkGetPhysicalDeviceExternalBufferProperties-pExternalBufferProperties-parameter',
135 'VUID-vkGetPhysicalDeviceExternalFencePropertiesKHR-pExternalFenceInfo-parameter' : 'VUID-vkGetPhysicalDeviceExternalFenceProperties-pExternalFenceInfo-parameter',
136 'VUID-vkGetPhysicalDeviceExternalFencePropertiesKHR-pExternalFenceProperties-parameter' : 'VUID-vkGetPhysicalDeviceExternalFenceProperties-pExternalFenceProperties-parameter',
137 'VUID-vkGetPhysicalDeviceExternalSemaphorePropertiesKHR-pExternalSemaphoreInfo-parameter' : 'VUID-vkGetPhysicalDeviceExternalSemaphoreProperties-pExternalSemaphoreInfo-parameter',
138 'VUID-vkGetPhysicalDeviceExternalSemaphorePropertiesKHR-pExternalSemaphoreProperties-parameter' : 'VUID-vkGetPhysicalDeviceExternalSemaphoreProperties-pExternalSemaphoreProperties-parameter',
139 'VUID-vkGetPhysicalDeviceFeatures2KHR-pFeatures-parameter' : 'VUID-vkGetPhysicalDeviceFeatures2-pFeatures-parameter',
140 'VUID-vkGetPhysicalDeviceFormatProperties2KHR-pFormatProperties-parameter' : 'VUID-vkGetPhysicalDeviceFormatProperties2-pFormatProperties-parameter',
141 'VUID-vkGetPhysicalDeviceImageFormatProperties2KHR-pImageFormatInfo-parameter' : 'VUID-vkGetPhysicalDeviceImageFormatProperties2-pImageFormatInfo-parameter',
142 'VUID-vkGetPhysicalDeviceImageFormatProperties2KHR-pImageFormatProperties-parameter' : 'VUID-vkGetPhysicalDeviceImageFormatProperties2-pImageFormatProperties-parameter',
143 'VUID-vkGetPhysicalDeviceMemoryProperties2KHR-pMemoryProperties-parameter' : 'VUID-vkGetPhysicalDeviceMemoryProperties2-pMemoryProperties-parameter',
144 'VUID-vkGetPhysicalDeviceProperties2KHR-pProperties-parameter' : 'VUID-vkGetPhysicalDeviceProperties2-pProperties-parameter',
145 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2KHR-pFormatInfo-parameter' : 'VUID-vkGetPhysicalDeviceSparseImageFormatProperties2-pFormatInfo-parameter' }
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600146
Dave Houltoncacef472018-05-29 13:00:42 -0600147def printHelp():
148 print ("Usage:")
149 print (" python vk_validation_stats.py <json_file>")
150 print (" [ -c ]")
151 print (" [ -todo ]")
152 print (" [ -vuid <vuid_name> ]")
153 print (" [ -text [ <text_out_filename>] ]")
154 print (" [ -csv [ <csv_out_filename>] ]")
155 print (" [ -html [ <html_out_filename>] ]")
Dave Houlton407df732018-08-06 17:58:24 -0600156 print (" [ -export_header ]")
Dave Houltoncacef472018-05-29 13:00:42 -0600157 print (" [ -verbose ]")
158 print (" [ -help ]")
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700159 print ("\n The vk_validation_stats script parses validation layer source files to")
160 print (" determine the set of valid usage checks and tests currently implemented,")
Dave Houltoncacef472018-05-29 13:00:42 -0600161 print (" and generates coverage values by comparing against the full set of valid")
162 print (" usage identifiers in the Vulkan-Headers registry file 'validusage.json'")
163 print ("\nArguments: ")
164 print (" <json-file> (required) registry file 'validusage.json'")
165 print (" -c report consistency warnings")
166 print (" -todo report unimplemented VUIDs")
167 print (" -vuid <vuid_name> report status of individual VUID <vuid_name>")
168 print (" -text [filename] output the error database text to <text_database_filename>,")
169 print (" defaults to 'validation_error_database.txt'")
170 print (" -csv [filename] output the error database in csv to <csv_database_filename>,")
171 print (" defaults to 'validation_error_database.csv'")
172 print (" -html [filename] output the error database in html to <html_database_filename>,")
173 print (" defaults to 'validation_error_database.html'")
Dave Houlton407df732018-08-06 17:58:24 -0600174 print (" -export_header export a new VUID error text header file to <%s>" % header_filename)
Dave Houltoncacef472018-05-29 13:00:42 -0600175 print (" -verbose show your work (to stdout)")
176
177class ValidationJSON:
178 def __init__(self, filename):
179 self.filename = filename
180 self.explicit_vuids = set()
181 self.implicit_vuids = set()
182 self.all_vuids = set()
183 self.vuid_db = defaultdict(list) # Maps VUID string to list of json-data dicts
184 self.apiversion = ""
Dave Houltoncacef472018-05-29 13:00:42 -0600185 self.duplicate_vuids = set()
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700186
Dave Houlton407df732018-08-06 17:58:24 -0600187 # A set of specific regular expression substitutions needed to clean up VUID text
188 self.regex_dict = {}
189 self.regex_dict[re.compile('<.*?>|&(amp;)+lt;|&(amp;)+gt;')] = ""
190 self.regex_dict[re.compile(r'\\\(codeSize \\over 4\\\)')] = "(codeSize/4)"
Shannon McPherson3ea65132018-12-05 10:37:39 -0700191 self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{height}{maxFragmentDensityTexelSize_{height}}}\\rceil\\\)')] = "the ceiling of height/maxFragmentDensityTexelSize.height"
192 self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{width}{maxFragmentDensityTexelSize_{width}}}\\rceil\\\)')] = "the ceiling of width/maxFragmentDensityTexelSize.width"
193 self.regex_dict[re.compile(r'\\\(\\lceil{\\frac{maxFramebufferHeight}{minFragmentDensityTexelSize_{height}}}\\rceil\\\)')] = "the ceiling of maxFramebufferHeight/minFragmentDensityTexelSize.height"
194 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 -0600195 self.regex_dict[re.compile(r'\\\(\\lceil\{\\mathit\{rasterizationSamples} \\over 32}\\rceil\\\)')] = "(rasterizationSamples/32)"
Shannon McPhersonb40f1a22018-10-30 16:45:07 -0600196 self.regex_dict[re.compile(r'\\\(\\textrm\{codeSize} \\over 4\\\)')] = "(codeSize/4)"
Dave Houlton407df732018-08-06 17:58:24 -0600197 # Some fancy punctuation chars that break the Android build...
198 self.regex_dict[re.compile('&#8594;')] = "->" # Arrow char
199 self.regex_dict[re.compile('&#8217;')] = "'" # Left-slanting apostrophe to apostrophe
200 self.regex_dict[re.compile('&#822(0|1);')] = "'" # L/R-slanting quotes to apostrophe
Dave Houltoncacef472018-05-29 13:00:42 -0600201
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600202 def read(self):
Dave Houltoncacef472018-05-29 13:00:42 -0600203 self.json_dict = {}
204 if os.path.isfile(self.filename):
Dave Houlton407df732018-08-06 17:58:24 -0600205 json_file = open(self.filename, 'r', encoding='utf-8')
Dave Houltoncacef472018-05-29 13:00:42 -0600206 self.json_dict = json.load(json_file)
207 json_file.close()
208 if len(self.json_dict) == 0:
209 print("Error: Error loading validusage.json file <%s>" % self.filename)
210 sys.exit(-1)
211 try:
212 version = self.json_dict['version info']
213 validation = self.json_dict['validation']
214 self.apiversion = version['api version']
215 except:
216 print("Error: Failure parsing validusage.json object")
217 sys.exit(-1)
218
219 # Parse vuid from json into local databases
220 for apiname in validation.keys():
221 # print("entrypoint:%s"%apiname)
222 apidict = validation[apiname]
223 for ext in apidict.keys():
224 vlist = apidict[ext]
225 for ventry in vlist:
226 vuid_string = ventry['vuid']
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700227 if (vuid_string[-5:-1].isdecimal()):
Dave Houltoncacef472018-05-29 13:00:42 -0600228 self.explicit_vuids.add(vuid_string) # explicit end in 5 numeric chars
229 vtype = 'explicit'
230 else:
231 self.implicit_vuids.add(vuid_string) # otherwise, implicit
232 vtype = 'implicit'
233 vuid_text = ventry['text']
Dave Houlton407df732018-08-06 17:58:24 -0600234 for regex, replacement in self.regex_dict.items():
235 vuid_text = re.sub(regex, replacement, vuid_text) # do regex substitution
236 vuid_text = html.unescape(vuid_text) # anything missed by the regex
237 self.vuid_db[vuid_string].append({'api':apiname, 'ext':ext, 'type':vtype, 'text':vuid_text})
Dave Houltoncacef472018-05-29 13:00:42 -0600238 self.all_vuids = self.explicit_vuids | self.implicit_vuids
239 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 -0600240 if len(self.duplicate_vuids) > 0:
241 print("Warning: duplicate VUIDs found in validusage.json")
242
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600243
244class ValidationSource:
Mike Schuchardt7b12d652019-07-01 11:00:21 -0700245 def __init__(self, source_file_list):
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600246 self.source_files = source_file_list
Dave Houltoncacef472018-05-29 13:00:42 -0600247 self.vuid_count_dict = {} # dict of vuid values to the count of how much they're used, and location of where they're used
248 self.duplicated_checks = 0
249 self.explicit_vuids = set()
250 self.implicit_vuids = set()
251 self.unassigned_vuids = set()
252 self.all_vuids = set()
Mark Lobodzinski05849f02017-06-21 14:44:14 -0600253
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600254 def parse(self):
Dave Houltoncacef472018-05-29 13:00:42 -0600255 prepend = None
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600256 for sf in self.source_files:
Tobin Ehlis3d1f2bd2016-12-22 11:19:15 -0700257 line_num = 0
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600258 with open(sf) as f:
259 for line in f:
Tobin Ehlis3d1f2bd2016-12-22 11:19:15 -0700260 line_num = line_num + 1
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600261 if True in [line.strip().startswith(comment) for comment in ['//', '/*']]:
262 continue
Dave Houltoncacef472018-05-29 13:00:42 -0600263 # Find vuid strings
Michał Janiszewski3c3ce9e2018-10-30 23:25:21 +0100264 if prepend is not None:
Dave Houltoncacef472018-05-29 13:00:42 -0600265 line = prepend[:-2] + line.lstrip().lstrip('"') # join lines skipping CR, whitespace and trailing/leading quote char
266 prepend = None
267 if any(prefix in line for prefix in vuid_prefixes):
Shannon McPhersondad26362019-06-12 10:51:46 -0600268 # Replace the '(' of lines containing validation helper functions with ' ' to make them easier to parse
269 line = line.replace("(", " ")
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600270 line_list = line.split()
Dave Houltoncacef472018-05-29 13:00:42 -0600271
272 # 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
273 broken_vuid = line_list[-1].strip('"')
274 if any(broken_vuid.startswith(prefix) for prefix in vuid_prefixes) and broken_vuid.endswith('-'):
275 prepend = line
276 continue
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700277
Dave Houltoncacef472018-05-29 13:00:42 -0600278 vuid_list = []
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600279 for str in line_list:
Dave Houltoncacef472018-05-29 13:00:42 -0600280 if any(prefix in str for prefix in vuid_prefixes):
281 vuid_list.append(str.strip(',);{}"'))
282 for vuid in vuid_list:
283 if vuid not in self.vuid_count_dict:
284 self.vuid_count_dict[vuid] = {}
285 self.vuid_count_dict[vuid]['count'] = 1
286 self.vuid_count_dict[vuid]['file_line'] = []
287 else:
288 if self.vuid_count_dict[vuid]['count'] == 1: # only count first time duplicated
289 self.duplicated_checks = self.duplicated_checks + 1
290 self.vuid_count_dict[vuid]['count'] = self.vuid_count_dict[vuid]['count'] + 1
291 self.vuid_count_dict[vuid]['file_line'].append('%s,%d' % (sf, line_num))
292 # Sort vuids by type
293 for vuid in self.vuid_count_dict.keys():
294 if (vuid.startswith('VUID-')):
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700295 if (vuid[-5:-1].isdecimal()):
Dave Houltoncacef472018-05-29 13:00:42 -0600296 self.explicit_vuids.add(vuid) # explicit end in 5 numeric chars
297 else:
298 self.implicit_vuids.add(vuid)
299 elif (vuid.startswith('UNASSIGNED-')):
300 self.unassigned_vuids.add(vuid)
301 else:
302 print("Unable to categorize VUID: %s" % vuid)
303 print("Confused while parsing VUIDs in layer source code - cannot proceed. (FIXME)")
304 exit(-1)
305 self.all_vuids = self.explicit_vuids | self.implicit_vuids | self.unassigned_vuids
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600306
307# Class to parse the validation layer test source and store testnames
Dave Houltoncacef472018-05-29 13:00:42 -0600308class ValidationTests:
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600309 def __init__(self, test_file_list, test_group_name=['VkLayerTest', 'VkPositiveLayerTest', 'VkWsiEnabledLayerTest']):
310 self.test_files = test_file_list
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600311 self.test_trigger_txt_list = []
312 for tg in test_group_name:
313 self.test_trigger_txt_list.append('TEST_F(%s' % tg)
Dave Houltoncacef472018-05-29 13:00:42 -0600314 self.explicit_vuids = set()
315 self.implicit_vuids = set()
316 self.unassigned_vuids = set()
317 self.all_vuids = set()
318 #self.test_to_vuids = {} # Map test name to VUIDs tested
319 self.vuid_to_tests = defaultdict(set) # Map VUIDs to set of test names where implemented
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600320
321 # Parse test files into internal data struct
322 def parse(self):
323 # For each test file, parse test names into set
324 grab_next_line = False # handle testname on separate line than wildcard
Tobin Ehlis9a68c982016-12-29 14:51:17 -0700325 testname = ''
Dave Houltoncacef472018-05-29 13:00:42 -0600326 prepend = None
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600327 for test_file in self.test_files:
328 with open(test_file) as tf:
329 for line in tf:
330 if True in [line.strip().startswith(comment) for comment in ['//', '/*']]:
331 continue
332
Dave Houltoncacef472018-05-29 13:00:42 -0600333 # if line ends in a broken VUID string, fix that before proceeding
Michał Janiszewski3c3ce9e2018-10-30 23:25:21 +0100334 if prepend is not None:
Dave Houltoncacef472018-05-29 13:00:42 -0600335 line = prepend[:-2] + line.lstrip().lstrip('"') # join lines skipping CR, whitespace and trailing/leading quote char
336 prepend = None
337 if any(prefix in line for prefix in vuid_prefixes):
338 line_list = line.split()
339
340 # 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
341 broken_vuid = line_list[-1].strip('"')
342 if any(broken_vuid.startswith(prefix) for prefix in vuid_prefixes) and broken_vuid.endswith('-'):
343 prepend = line
344 continue
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700345
Dave Houltoncacef472018-05-29 13:00:42 -0600346 if any(ttt in line for ttt in self.test_trigger_txt_list):
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600347 testname = line.split(',')[-1]
348 testname = testname.strip().strip(' {)')
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600349 if ('' == testname):
350 grab_next_line = True
351 continue
Dave Houltoncacef472018-05-29 13:00:42 -0600352 #self.test_to_vuids[testname] = []
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600353 if grab_next_line: # test name on its own line
354 grab_next_line = False
355 testname = testname.strip().strip(' {)')
Dave Houltoncacef472018-05-29 13:00:42 -0600356 #self.test_to_vuids[testname] = []
357 if any(prefix in line for prefix in vuid_prefixes):
358 line_list = re.split('[\s{}[\]()"]+',line)
Tobin Ehlis71f38c12017-01-12 14:26:56 -0700359 for sub_str in line_list:
Dave Houltoncacef472018-05-29 13:00:42 -0600360 if any(prefix in sub_str for prefix in vuid_prefixes):
361 vuid_str = sub_str.strip(',);:"')
362 self.vuid_to_tests[vuid_str].add(testname)
363 #self.test_to_vuids[testname].append(vuid_str)
364 if (vuid_str.startswith('VUID-')):
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700365 if (vuid_str[-5:-1].isdecimal()):
Dave Houltoncacef472018-05-29 13:00:42 -0600366 self.explicit_vuids.add(vuid_str) # explicit end in 5 numeric chars
367 else:
368 self.implicit_vuids.add(vuid_str)
369 elif (vuid_str.startswith('UNASSIGNED-')):
370 self.unassigned_vuids.add(vuid_str)
371 else:
372 print("Unable to categorize VUID: %s" % vuid_str)
373 print("Confused while parsing VUIDs in test code - cannot proceed. (FIXME)")
374 exit(-1)
375 self.all_vuids = self.explicit_vuids | self.implicit_vuids | self.unassigned_vuids
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600376
Dave Houltoncacef472018-05-29 13:00:42 -0600377# Class to do consistency checking
378#
379class Consistency:
380 def __init__(self, all_json, all_checks, all_tests):
381 self.valid = all_json
382 self.checks = all_checks
383 self.tests = all_tests
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600384
Dave Houltoncacef472018-05-29 13:00:42 -0600385 if (dealias_khr):
386 dk = set()
387 for vuid in self.checks:
388 if vuid in khr_aliases:
389 dk.add(khr_aliases[vuid])
390 else:
391 dk.add(vuid)
392 self.checks = dk
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600393
Dave Houltoncacef472018-05-29 13:00:42 -0600394 dk = set()
395 for vuid in self.tests:
396 if vuid in khr_aliases:
397 dk.add(khr_aliases[vuid])
398 else:
399 dk.add(vuid)
400 self.tests = dk
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600401
Dave Houltoncacef472018-05-29 13:00:42 -0600402 # Report undefined VUIDs in source code
403 def undef_vuids_in_layer_code(self):
404 undef_set = self.checks - self.valid
405 undef_set.discard('VUID-Undefined') # don't report Undefined
406 if ignore_unassigned:
407 unassigned = set({uv for uv in undef_set if uv.startswith('UNASSIGNED-')})
408 undef_set = undef_set - unassigned
409 if (len(undef_set) > 0):
410 print("\nFollowing VUIDs found in layer code are not defined in validusage.json (%d):" % len(undef_set))
411 undef = list(undef_set)
412 undef.sort()
413 for vuid in undef:
414 print(" %s" % vuid)
415 return False
416 return True
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600417
Dave Houltoncacef472018-05-29 13:00:42 -0600418 # Report undefined VUIDs in tests
419 def undef_vuids_in_tests(self):
420 undef_set = self.tests - self.valid
421 undef_set.discard('VUID-Undefined') # don't report Undefined
422 if ignore_unassigned:
423 unassigned = set({uv for uv in undef_set if uv.startswith('UNASSIGNED-')})
424 undef_set = undef_set - unassigned
425 if (len(undef_set) > 0):
426 ok = False
427 print("\nFollowing VUIDs found in layer tests are not defined in validusage.json (%d):" % len(undef_set))
428 undef = list(undef_set)
429 undef.sort()
430 for vuid in undef:
431 print(" %s" % vuid)
432 return False
433 return True
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600434
Dave Houltoncacef472018-05-29 13:00:42 -0600435 # Report vuids in tests that are not in source
436 def vuids_tested_not_checked(self):
437 undef_set = self.tests - self.checks
438 undef_set.discard('VUID-Undefined') # don't report Undefined
439 if ignore_unassigned:
440 unassigned = set()
441 for vuid in undef_set:
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700442 if vuid.startswith('UNASSIGNED-'):
Dave Houltoncacef472018-05-29 13:00:42 -0600443 unassigned.add(vuid)
444 undef_set = undef_set - unassigned
445 if (len(undef_set) > 0):
446 ok = False
447 print("\nFollowing VUIDs found in tests but are not checked in layer code (%d):" % len(undef_set))
448 undef = list(undef_set)
449 undef.sort()
450 for vuid in undef:
451 print(" %s" % vuid)
452 return False
453 return True
454
455 # TODO: Explicit checked VUIDs which have no test
456 # def explicit_vuids_checked_not_tested(self):
457
458
459# Class to output database in various flavors
460#
461class OutputDatabase:
462 def __init__(self, val_json, val_source, val_tests):
463 self.vj = val_json
464 self.vs = val_source
465 self.vt = val_tests
Dave Houlton729c7822018-11-19 11:52:23 -0700466 self.header_version = "/* THIS FILE IS GENERATED - DO NOT EDIT (scripts/vk_validation_stats.py) */"
467 self.header_version += "\n/* Vulkan specification version: %s */" % val_json.apiversion
Dave Houlton729c7822018-11-19 11:52:23 -0700468 self.header_preamble = """
Dave Houlton407df732018-08-06 17:58:24 -0600469/*
470 * Vulkan
471 *
Jasper St. Pierre1948bcc2019-01-18 13:55:20 -0800472 * Copyright (c) 2016-2019 Google Inc.
473 * Copyright (c) 2016-2019 LunarG, Inc.
Dave Houlton407df732018-08-06 17:58:24 -0600474 *
475 * Licensed under the Apache License, Version 2.0 (the "License");
476 * you may not use this file except in compliance with the License.
477 * You may obtain a copy of the License at
478 *
479 * http://www.apache.org/licenses/LICENSE-2.0
480 *
481 * Unless required by applicable law or agreed to in writing, software
482 * distributed under the License is distributed on an "AS IS" BASIS,
483 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
484 * See the License for the specific language governing permissions and
485 * limitations under the License.
486 *
487 * Author: Tobin Ehlis <tobine@google.com>
488 * Author: Dave Houlton <daveh@lunarg.com>
489 */
490
491#pragma once
492
493// Disable auto-formatting for generated file
494// clang-format off
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700495
Dave Houlton407df732018-08-06 17:58:24 -0600496// Mapping from VUID string to the corresponding spec text
Dave Houlton4d9b2f82018-10-24 18:21:06 -0600497typedef struct _vuid_spec_text_pair {
498 const char * vuid;
499 const char * spec_text;
500} vuid_spec_text_pair;
501
502static const vuid_spec_text_pair vuid_spec_text[] = {
Dave Houlton407df732018-08-06 17:58:24 -0600503"""
504 self.header_postamble = """};
Dave Houlton4d9b2f82018-10-24 18:21:06 -0600505"""
Dave Houlton407df732018-08-06 17:58:24 -0600506 self.spec_url = "https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html"
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700507
Dave Houltoncacef472018-05-29 13:00:42 -0600508 def dump_txt(self):
509 print("\n Dumping database to text file: %s" % txt_filename)
510 with open (txt_filename, 'w') as txt:
511 txt.write("## VUID Database\n")
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700512 txt.write("## Format: VUID_NAME | CHECKED | TEST | TYPE | API/STRUCT | EXTENSION | VUID_TEXT\n##\n")
Dave Houltoncacef472018-05-29 13:00:42 -0600513 vuid_list = list(self.vj.all_vuids)
514 vuid_list.sort()
515 for vuid in vuid_list:
516 db_list = self.vj.vuid_db[vuid]
517 db_list.sort(key=operator.itemgetter('ext')) # sort list to ease diffs of output file
518 for db_entry in db_list:
519 checked = 'N'
520 if vuid in self.vs.all_vuids:
521 checked = 'Y'
522 test = 'None'
523 if vuid in self.vt.vuid_to_tests:
524 test_list = list(self.vt.vuid_to_tests[vuid])
525 test_list.sort() # sort tests, for diff-ability
526 sep = ', '
527 test = sep.join(test_list)
528
529 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']))
530
531 def dump_csv(self):
532 print("\n Dumping database to csv file: %s" % csv_filename)
533 with open (csv_filename, 'w', newline='') as csvfile:
534 cw = csv.writer(csvfile)
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700535 cw.writerow(['VUID_NAME','CHECKED','TEST','TYPE','API/STRUCT','EXTENSION','VUID_TEXT'])
Dave Houltoncacef472018-05-29 13:00:42 -0600536 vuid_list = list(self.vj.all_vuids)
537 vuid_list.sort()
538 for vuid in vuid_list:
539 for db_entry in self.vj.vuid_db[vuid]:
540 row = [vuid]
541 if vuid in self.vs.all_vuids:
542 row.append('Y')
543 else:
544 row.append('N')
545 test = 'None'
546 if vuid in self.vt.vuid_to_tests:
547 sep = ', '
548 test = sep.join(self.vt.vuid_to_tests[vuid])
549 row.append(test)
550 row.append(db_entry['type'])
551 row.append(db_entry['api'])
552 row.append(db_entry['ext'])
553 row.append(db_entry['text'])
554 cw.writerow(row)
555
556 def dump_html(self):
557 print("\n Dumping database to html file: %s" % html_filename)
558 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 -0700559 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 -0600560 with open (html_filename, 'w') as hfile:
561 hfile.write(preamble)
562 hfile.write(headers)
563 vuid_list = list(self.vj.all_vuids)
564 vuid_list.sort()
565 for vuid in vuid_list:
566 for db_entry in self.vj.vuid_db[vuid]:
567 hfile.write('<tr><th>%s</th>' % vuid)
568 checked = '<span style="color:red;">N</span>'
569 if vuid in self.vs.all_vuids:
570 checked = '<span style="color:limegreen;">Y</span>'
571 hfile.write('<th>%s</th>' % checked)
572 test = 'None'
573 if vuid in self.vt.vuid_to_tests:
574 sep = ', '
575 test = sep.join(self.vt.vuid_to_tests[vuid])
576 hfile.write('<th>%s</th>' % test)
577 hfile.write('<th>%s</th>' % db_entry['type'])
578 hfile.write('<th>%s</th>' % db_entry['api'])
579 hfile.write('<th>%s</th>' % db_entry['ext'])
580 hfile.write('<th>%s</th></tr>\n' % db_entry['text'])
581 hfile.write('</table>\n</body>\n</html>\n')
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600582
Dave Houlton407df732018-08-06 17:58:24 -0600583 def export_header(self):
584 print("\n Exporting header file to: %s" % header_filename)
585 with open (header_filename, 'w') as hfile:
Dave Houlton729c7822018-11-19 11:52:23 -0700586 hfile.write(self.header_version)
Dave Houlton407df732018-08-06 17:58:24 -0600587 hfile.write(self.header_preamble)
588 vuid_list = list(self.vj.all_vuids)
589 vuid_list.sort()
John Zulaufd09ba822019-04-29 07:05:07 -0600590 cmd_dict = {}
Dave Houlton407df732018-08-06 17:58:24 -0600591 for vuid in vuid_list:
592 db_entry = self.vj.vuid_db[vuid][0]
John Zulaufd09ba822019-04-29 07:05:07 -0600593 db_text = db_entry['text'].strip(' ')
594 hfile.write(' {"%s", "%s (%s#%s)"},\n' % (vuid, db_text, self.spec_url, vuid))
Dave Houlton407df732018-08-06 17:58:24 -0600595 # For multiply-defined VUIDs, include versions with extension appended
596 if len(self.vj.vuid_db[vuid]) > 1:
597 for db_entry in self.vj.vuid_db[vuid]:
John Zulaufd09ba822019-04-29 07:05:07 -0600598 hfile.write(' {"%s[%s]", "%s (%s#%s)"},\n' % (vuid, db_entry['ext'].strip(' '), db_text, self.spec_url, vuid))
599 if 'commandBuffer must be in the recording state' in db_text:
600 cmd_dict[vuid] = db_text
Dave Houlton407df732018-08-06 17:58:24 -0600601 hfile.write(self.header_postamble)
602
John Zulaufd09ba822019-04-29 07:05:07 -0600603 # Generate the information for validating recording state VUID's
604 cmd_prefix = 'prefix##'
605 cmd_regex = re.compile(r'VUID-vk(Cmd|End)(\w+)')
606 cmd_vuid_vector = [' "VUID_Undefined"']
607 cmd_name_vector = [ ' "Command_Undefined"' ]
608 cmd_enum = [' ' + cmd_prefix + 'NONE = 0']
609
610 cmd_ordinal = 1
Mike Schuchardtaed5ac32019-06-21 09:03:31 -0700611 for vuid, db_text in sorted(cmd_dict.items()):
John Zulaufd09ba822019-04-29 07:05:07 -0600612 cmd_match = cmd_regex.match(vuid)
613 if cmd_match.group(1) == "End":
614 end = "END"
615 else:
616 end = ""
617 cmd_name_vector.append(' "vk'+ cmd_match.group(1) + cmd_match.group(2) + '"')
618 cmd_name = cmd_prefix + end + cmd_match.group(2).upper()
619 cmd_enum.append(' {} = {}'.format(cmd_name, cmd_ordinal))
620 cmd_ordinal += 1
621 cmd_vuid_vector.append(' "{}"'.format(vuid))
622
623 hfile.write('\n// Defines to allow creating "must be recording" meta data\n')
624 cmd_enum.append(' {}RANGE_SIZE = {}'.format(cmd_prefix, cmd_ordinal))
625 cmd_enum_string = '#define VUID_CMD_ENUM_LIST(prefix)\\\n' + ',\\\n'.join(cmd_enum) + '\n\n'
626 hfile.write(cmd_enum_string)
627 cmd_name_list_string = '#define VUID_CMD_NAME_LIST\\\n' + ',\\\n'.join(cmd_name_vector) + '\n\n'
628 hfile.write(cmd_name_list_string)
629 vuid_vector_string = '#define VUID_MUST_BE_RECORDING_LIST\\\n' + ',\\\n'.join(cmd_vuid_vector) + '\n'
630 hfile.write(vuid_vector_string)
631
Mark Lobodzinskib44c54a2017-06-12 12:02:38 -0600632def main(argv):
Dave Houltoncacef472018-05-29 13:00:42 -0600633 global verbose_mode
634 global txt_filename
635 global csv_filename
636 global html_filename
637
638 run_consistency = False
639 report_unimplemented = False
640 get_vuid_status = ''
641 txt_out = False
642 csv_out = False
643 html_out = False
Dave Houlton407df732018-08-06 17:58:24 -0600644 header_out = False
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700645
Dave Houltoncacef472018-05-29 13:00:42 -0600646 if (1 > len(argv)):
647 printHelp()
648 sys.exit()
649
650 # Parse script args
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700651 json_filename = argv[0]
Dave Houltoncacef472018-05-29 13:00:42 -0600652 i = 1
653 while (i < len(argv)):
654 arg = argv[i]
655 i = i + 1
656 if (arg == '-c'):
657 run_consistency = True
658 elif (arg == '-vuid'):
659 get_vuid_status = argv[i]
660 i = i + 1
661 elif (arg == '-todo'):
662 report_unimplemented = True
Karl Schultz49d66bb2018-07-09 16:24:46 -0600663 elif (arg == '-text'):
Dave Houltoncacef472018-05-29 13:00:42 -0600664 txt_out = True
665 # Set filename if supplied, else use default
666 if i < len(argv) and not argv[i].startswith('-'):
667 txt_filename = argv[i]
668 i = i + 1
669 elif (arg == '-csv'):
670 csv_out = True
671 # Set filename if supplied, else use default
672 if i < len(argv) and not argv[i].startswith('-'):
673 csv_filename = argv[i]
674 i = i + 1
675 elif (arg == '-html'):
676 html_out = True
677 # Set filename if supplied, else use default
678 if i < len(argv) and not argv[i].startswith('-'):
679 html_filename = argv[i]
680 i = i + 1
Dave Houlton407df732018-08-06 17:58:24 -0600681 elif (arg == '-export_header'):
682 header_out = True
Dave Houltoncacef472018-05-29 13:00:42 -0600683 elif (arg in ['-verbose']):
684 verbose_mode = True
685 elif (arg in ['-help', '-h']):
686 printHelp()
687 sys.exit()
688 else:
689 print("Unrecognized argument: %s\n" % arg)
690 printHelp()
691 sys.exit()
692
Tobin Ehlis20e32582016-12-05 14:50:03 -0700693 result = 0 # Non-zero result indicates an error case
Dave Houltoncacef472018-05-29 13:00:42 -0600694
695 # Parse validusage json
696 val_json = ValidationJSON(json_filename)
697 val_json.read()
698 exp_json = len(val_json.explicit_vuids)
699 imp_json = len(val_json.implicit_vuids)
700 all_json = len(val_json.all_vuids)
701 if verbose_mode:
702 print("Found %d unique error vuids in validusage.json file." % all_json)
703 print(" %d explicit" % exp_json)
704 print(" %d implicit" % imp_json)
705 if len(val_json.duplicate_vuids) > 0:
706 print("%d VUIDs appear in validusage.json more than once." % len(val_json.duplicate_vuids))
707 for vuid in val_json.duplicate_vuids:
708 print(" %s" % vuid)
709 for ext in val_json.vuid_db[vuid]:
710 print(" with extension: %s" % ext['ext'])
711
712 # Parse layer source files
Mike Schuchardt7b12d652019-07-01 11:00:21 -0700713 val_source = ValidationSource(layer_source_files)
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600714 val_source.parse()
Dave Houltoncacef472018-05-29 13:00:42 -0600715 exp_checks = len(val_source.explicit_vuids)
716 imp_checks = len(val_source.implicit_vuids)
717 all_checks = len(val_source.vuid_count_dict.keys())
718 if verbose_mode:
719 print("Found %d unique vuid checks in layer source code." % all_checks)
720 print(" %d explicit" % exp_checks)
721 print(" %d implicit" % imp_checks)
722 print(" %d unassigned" % len(val_source.unassigned_vuids))
723 print(" %d checks are implemented more that once" % val_source.duplicated_checks)
724
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600725 # Parse test files
Mike Schuchardt7b12d652019-07-01 11:00:21 -0700726 val_tests = ValidationTests(test_source_files)
Dave Houltoncacef472018-05-29 13:00:42 -0600727 val_tests.parse()
728 exp_tests = len(val_tests.explicit_vuids)
729 imp_tests = len(val_tests.implicit_vuids)
730 all_tests = len(val_tests.all_vuids)
Mark Lobodzinski060a8e32018-01-08 09:08:06 -0700731 if verbose_mode:
Mike Schuchardt7b12d652019-07-01 11:00:21 -0700732 print("Found %d unique error vuids in test source code." % all_tests)
Dave Houltoncacef472018-05-29 13:00:42 -0600733 print(" %d explicit" % exp_tests)
734 print(" %d implicit" % imp_tests)
735 print(" %d unassigned" % len(val_tests.unassigned_vuids))
Mike Weiblenfe186122017-02-03 12:44:53 -0700736
Dave Houltoncacef472018-05-29 13:00:42 -0600737 # Process stats
738 print("\nValidation Statistics (using validusage.json version %s)" % val_json.apiversion)
739 print(" VUIDs defined in JSON file: %04d explicit, %04d implicit, %04d total." % (exp_json, imp_json, all_json))
740 print(" VUIDs checked in layer code: %04d explicit, %04d implicit, %04d total." % (exp_checks, imp_checks, all_checks))
741 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 -0700742
Dave Houltoncacef472018-05-29 13:00:42 -0600743 print("\nVUID check coverage")
744 print(" Explicit VUIDs checked: %.1f%% (%d checked vs %d defined)" % ((100.0 * exp_checks / exp_json), exp_checks, exp_json))
745 print(" Implicit VUIDs checked: %.1f%% (%d checked vs %d defined)" % ((100.0 * imp_checks / imp_json), imp_checks, imp_json))
746 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 -0700747
Dave Houltoncacef472018-05-29 13:00:42 -0600748 print("\nVUID test coverage")
749 print(" Explicit VUIDs tested: %.1f%% (%d tested vs %d checks)" % ((100.0 * exp_tests / exp_checks), exp_tests, exp_checks))
750 print(" Implicit VUIDs tested: %.1f%% (%d tested vs %d checks)" % ((100.0 * imp_tests / imp_checks), imp_tests, imp_checks))
751 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 -0700752
Dave Houltoncacef472018-05-29 13:00:42 -0600753 # Report status of a single VUID
754 if len(get_vuid_status) > 1:
755 print("\n\nChecking status of <%s>" % get_vuid_status);
756 if get_vuid_status not in val_json.all_vuids:
757 print(' Not a valid VUID string.')
758 else:
759 if get_vuid_status in val_source.explicit_vuids:
760 print(' Implemented!')
761 line_list = val_source.vuid_count_dict[get_vuid_status]['file_line']
762 for line in line_list:
763 print(' => %s' % line)
Dave Houltonf93bbab2018-06-26 17:21:12 -0600764 elif get_vuid_status in val_source.implicit_vuids:
765 print(' Implemented! (Implicit)')
766 line_list = val_source.vuid_count_dict[get_vuid_status]['file_line']
767 for line in line_list:
768 print(' => %s' % line)
Tobin Ehlis9a68c982016-12-29 14:51:17 -0700769 else:
Dave Houltoncacef472018-05-29 13:00:42 -0600770 print(' Not implemented.')
Dave Houltonf93bbab2018-06-26 17:21:12 -0600771 if get_vuid_status in val_tests.all_vuids:
Dave Houltoncacef472018-05-29 13:00:42 -0600772 print(' Has a test!')
773 test_list = val_tests.vuid_to_tests[get_vuid_status]
774 for test in test_list:
775 print(' => %s' % test)
776 else:
777 print(' Not tested.')
Mike Weiblenfe186122017-02-03 12:44:53 -0700778
Dave Houltoncacef472018-05-29 13:00:42 -0600779 # Report unimplemented explicit VUIDs
780 if report_unimplemented:
781 unim_explicit = val_json.explicit_vuids - val_source.explicit_vuids
782 print("\n\n%d explicit VUID checks remain unimplemented:" % len(unim_explicit))
783 ulist = list(unim_explicit)
784 ulist.sort()
785 for vuid in ulist:
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700786 print(" => %s" % vuid)
Dave Houltoncacef472018-05-29 13:00:42 -0600787
788 # Consistency tests
789 if run_consistency:
790 print("\n\nRunning consistency tests...")
791 con = Consistency(val_json.all_vuids, val_source.all_vuids, val_tests.all_vuids)
792 ok = con.undef_vuids_in_layer_code()
793 ok &= con.undef_vuids_in_tests()
Mark Lobodzinski02e23172019-03-04 15:27:55 -0700794 ok &= con.vuids_tested_not_checked()
Dave Houltoncacef472018-05-29 13:00:42 -0600795
796 if ok:
797 print(" OK! No inconsistencies found.")
798
799 # Output database in requested format(s)
800 db_out = OutputDatabase(val_json, val_source, val_tests)
801 if txt_out:
802 db_out.dump_txt()
803 if csv_out:
804 db_out.dump_csv()
805 if html_out:
806 db_out.dump_html()
Dave Houlton407df732018-08-06 17:58:24 -0600807 if header_out:
808 db_out.export_header()
Tobin Ehlis20e32582016-12-05 14:50:03 -0700809 return result
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600810
811if __name__ == "__main__":
Mark Lobodzinskib44c54a2017-06-12 12:02:38 -0600812 sys.exit(main(sys.argv[1:]))
Tobin Ehlis35308dd2016-10-31 13:27:36 -0600813