SPIRV-Tools/source/val
Nathan Gauër 0f3bea06ef
NFC: rewrite EnumSet to handle larger enums. (#5289)
The current EnumSet implementation is only efficient for enums with
values < than 64. The reason is the first 63 values are stored as a
bitmask in a 64 bit unsigned integer, and the other values are stored
in a std::set.
For small enums, this is fine (most SPIR-V enums have IDs < than 64),
but performance starts to drop with larger enums (Capabilities,
opcodes).

Design considerations:
----------------------

This PR changes the internal behavior of the EnumSet to handle enums
with arbitrary values while staying performant.
The idea is to extend the 64-bits buckets sparsely:
 - each bucket can store 64 value, starting from a multiplier of 64.
This could be considered as a hashset with linear probing.

- For small enums, there is a slight memory overhead due to the bucket
storage, but lookup is still constant.
- For linearly distributed values, lookup is constant.
- Worse case for storage are for enums with values which are multiples of 64.
But lookup is constant.
- Worse case for lookup are enums with a lot of small ranges scattered in
the space (requires linear probing).

For enums like capabilities/opcodes, this bucketing is useful as values
are usually scatters in distinct, but almost contiguous blocks.
(vendors usually have allocated ranges, like [5000;5500], while [1000;5000]
is mostly unused).

Benchmarking:
-------------

Benchmarking was done in 2 ways:
 - a benchmark built for the occasion, which only measure the EnumSet
   performance.
 - SPIRV-Tools tests, to measure a more realist scenario.

Running SPIR-V tests with both implementations shows the same
performance (delta < noise). So seems like we have no regressions.
This method is noisy by nature (I/O, etc), but the most representative
of a real-life scenario.

Protocol:
 - run spirv-tests with no stdout using perf, multiple times.
Result:
 - measure noise is larger than the observed difference.

The custom benchmark was testing EnumSet interfaces using SPIRV enums.
Doing thousand of insertion/deletion/lookup, with 2 kind of scenarios:
 - add once, lookup many times.
 - add/delete/loopkup many time.

For small enums, results are similar (delta < noise). Seems relevant
with the previously observed results as most SPIRV enums are small, and
SPIRV-Tools is not doing that many intensive operations on EnumSets.

Performance on large enums (opcode/capabilities) shows an improvement:

+-----------------------------+---------+---------+---------+
| Metric                      |  Old    |   New   | Delta % |
+-----------------------------+---------+---------+---------+
| Execution time              |   27s   |   7s    |  -72%   |
| Instruction count           |  174b   |  129b   |  -25%   |
| Branch count                |   28b   |   33b   |  +17%   |
| Branch miss                 |  490m   |   26m   |  -94%   |
| Cache-misses                |  149k   |   26k   |  -82%   |
+-----------------------------+---------+---------+---------+

Future work
-----------

This was by-design an NFC change to compare apples-to-apples.
The next PR aims to add STL-like iterators to the EnumSet to allow
using it with STL algorithms, and range-based for loops.

Signed-off-by: Nathan Gauër <brioche@google.com>
2023-07-07 10:41:52 -04:00
..
basic_block.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
basic_block.h Use structural reachability in CFG checks (#4849) 2022-07-06 17:43:32 -04:00
construct.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
construct.h Allows breaks selection breaks to switches (#2605) 2019-05-21 22:49:37 -07:00
decoration.h Switch SPIRV-Tools to use spirv.hpp11 internally (#4981) 2022-11-04 17:27:10 -04:00
function.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
function.h Switch SPIRV-Tools to use spirv.hpp11 internally (#4981) 2022-11-04 17:27:10 -04:00
instruction.cpp Fix endianness of string literals (#4622) 2021-12-08 12:01:26 -05:00
instruction.h Switch SPIRV-Tools to use spirv.hpp11 internally (#4981) 2022-11-04 17:27:10 -04:00
validate_adjacency.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validate_annotation.cpp Add support for SPV_EXT_shader_tile_image (#5188) 2023-04-13 16:58:00 -04:00
validate_arithmetics.cpp SPV_KHR_cooperative_matrix (#5286) 2023-06-22 18:33:36 -04:00
validate_atomics.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validate_barriers.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validate_bitwise.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validate_builtins.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validate_capability.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validate_cfg.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validate_composites.cpp SPV_KHR_cooperative_matrix (#5286) 2023-06-22 18:33:36 -04:00
validate_constants.cpp SPV_KHR_cooperative_matrix (#5286) 2023-06-22 18:33:36 -04:00
validate_conversion.cpp SPV_KHR_cooperative_matrix (#5286) 2023-06-22 18:33:36 -04:00
validate_debug.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validate_decorations.cpp Validate layouts for PhysicalStorageBuffer pointers (#5291) 2023-06-23 19:17:55 +00:00
validate_derivatives.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validate_execution_limitations.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validate_extensions.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validate_function.cpp Add support for SPV_EXT_shader_tile_image (#5188) 2023-04-13 16:58:00 -04:00
validate_id.cpp SPV_KHR_cooperative_matrix (#5286) 2023-06-22 18:33:36 -04:00
validate_image.cpp spirv-val: Remove VUID from 1.3.251 spec (#5244) 2023-05-29 09:20:07 -04:00
validate_instruction.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validate_interfaces.cpp Allow physical storage buffer pointer in IO (#5251) 2023-05-30 20:07:58 -04:00
validate_layout.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validate_literals.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validate_logicals.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validate_memory_semantics.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validate_memory_semantics.h spirv-val: Add Vulkan Invocation Sematics check (#4182) 2021-03-16 10:53:37 -04:00
validate_memory.cpp spirv-val: Label SPV_KHR_cooperative_matrix VUID (#5301) 2023-07-04 09:01:04 -04:00
validate_mesh_shading.cpp Switch SPIRV-Tools to use spirv.hpp11 internally (#4981) 2022-11-04 17:27:10 -04:00
validate_misc.cpp Switch SPIRV-Tools to use spirv.hpp11 internally (#4981) 2022-11-04 17:27:10 -04:00
validate_mode_setting.cpp Add support for SPV_EXT_shader_tile_image (#5188) 2023-04-13 16:58:00 -04:00
validate_non_uniform.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validate_primitives.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validate_ray_query.cpp Switch SPIRV-Tools to use spirv.hpp11 internally (#4981) 2022-11-04 17:27:10 -04:00
validate_ray_tracing_reorder.cpp Fix missing declaration of std::numeric_limits (#5002) 2022-11-25 10:54:38 -05:00
validate_ray_tracing.cpp Switch SPIRV-Tools to use spirv.hpp11 internally (#4981) 2022-11-04 17:27:10 -04:00
validate_scopes.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validate_scopes.h Re-enable OpReadClockKHR validation (#3013) 2019-11-07 09:51:38 -05:00
validate_small_type_uses.cpp Switch SPIRV-Tools to use spirv.hpp11 internally (#4981) 2022-11-04 17:27:10 -04:00
validate_type.cpp SPV_KHR_cooperative_matrix (#5286) 2023-06-22 18:33:36 -04:00
validate.cpp spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validate.h spirv-val: Remove unused includes and code (#5176) 2023-03-28 14:18:19 -04:00
validation_state.cpp NFC: rewrite EnumSet to handle larger enums. (#5289) 2023-07-07 10:41:52 -04:00
validation_state.h SPV_KHR_cooperative_matrix (#5286) 2023-06-22 18:33:36 -04:00