mirror of
https://github.com/gomson/TimothyLottes.github.io.git
synced 2026-08-04 22:58:49 +00:00
Add files via upload
This commit is contained in:
+106
@@ -0,0 +1,106 @@
|
|||||||
|
<html><head><link rel="stylesheet" href="style.css"></head><body><div class="page">
|
||||||
|
<h1>20151113 - Rethinking the Symbolic Dictionary</h1>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<i>Another permutation of dictionary implementation for forth like languages...</i><br>
|
||||||
|
<br>
|
||||||
|
<b>Source</b>
|
||||||
|
<br>
|
||||||
|
Exported source is composed of two parts,<br>
|
||||||
|
<br>
|
||||||
|
(1.) Token array, where tokens can reference a local symbol by index into local hash table.<br>
|
||||||
|
(2.) Local symbol hash table, has string for each entry.<br>
|
||||||
|
<br>
|
||||||
|
Strings are 64-bits maximum and are stored in a reversible nearly pre-hashed form.
|
||||||
|
So hashing of a string is just an AND operation.
|
||||||
|
Tokens are 32-bits.
|
||||||
|
Local symbol hash is after the token array, so it can be trivially discarded after import.<br>
|
||||||
|
<br>
|
||||||
|
<b>Global Dictionary</b>
|
||||||
|
<br>
|
||||||
|
Global dictionary maps 32-bit index to 32-bit value.
|
||||||
|
Each 32-bit index has an associated 64-bit string stored in the same reversible nearly pre-hashed form.
|
||||||
|
Dictionary entries are allocated by just taking the next entry in a line.
|
||||||
|
There is no deletion. Just two arrays (32-bit value array, and 32-bit string array), and an index for the top.
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<b>Source Import</b>
|
||||||
|
<br>
|
||||||
|
Starts with loaded source in memory and allocated space for one extra array,<br>
|
||||||
|
<br>
|
||||||
|
(1.) Source token array, gets translated to loaded-in-memory form.<br>
|
||||||
|
(2.) Source local symbol hash table, with each entry being a 64-bit string.<br>
|
||||||
|
(3.) Remap space, extra zeroed array with a 32-bit value per entry in local hash table.<br>
|
||||||
|
<br>
|
||||||
|
Import streams through the global dictionary,
|
||||||
|
checking for a match in the source's local symbol hash table.
|
||||||
|
Upon finding a match, it writes the global index for the symbol into the associated remap space entry.
|
||||||
|
Import next streams through the source token array,
|
||||||
|
replacing the local symbol index
|
||||||
|
with the global index from the remap space entry.
|
||||||
|
When the remap space entry is zero,
|
||||||
|
a new symbol is allocated in the global dictionary
|
||||||
|
(this involves adding a symbol to the end of the dictionary,
|
||||||
|
and coping over the string from the local symbol hash table to the global dictionary string array).
|
||||||
|
After import the local symbol hash table and remap space are discarded.
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
This solves many of the core problems from a more conventional design where the global dictionary is a giant hash table.
|
||||||
|
That conventional design suffers from bad cache locality (because of the huge hash table).
|
||||||
|
This new design maintains a cache packed global dictionary (no gaps).
|
||||||
|
That conventional design can have worst case first load behavior,
|
||||||
|
each initial lookup of a new word in the dictionary on load would miss through to DRAM,
|
||||||
|
adding 100 ns per lookup.
|
||||||
|
This new design is composed of either linear streaming operations for big data
|
||||||
|
(global dictionary, source token array, etc) all of which get hardware auto-prefetch.
|
||||||
|
The source local symbol hash table is expected to be not too big and easily stay in cache (the only thing with random access).
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
Note with this new design, interpreting source at run-time no longer has any hash lookup,
|
||||||
|
just a direct lookup.<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<b>First Source Import</b>
|
||||||
|
<br>
|
||||||
|
First source import (after machine reboot) has effectively an empty dictionary,
|
||||||
|
so import can be optimized.<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<b>Editing</b>
|
||||||
|
<br>
|
||||||
|
Edit time operations, such as find the index for an existing symbol,
|
||||||
|
check if a symbol already exists,
|
||||||
|
or tab complete a symbol,
|
||||||
|
is done via a full stream through the global dictionary string table.
|
||||||
|
This is a linear operation with full auto-prefetch, so expected to be quite fast in practice.
|
||||||
|
Edit time operations are limited by human factors, so not a problem.
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<b>Source Export</b>
|
||||||
|
<br>
|
||||||
|
Source export requires first checking how many unique symbols are in the chunk of source.
|
||||||
|
Use a bit array with one bit per global dictionary entry.
|
||||||
|
Zero the bit array.
|
||||||
|
Stream through the chunk of source tokens and check for a clear bit in the bit array.
|
||||||
|
For each clear bit, set the bit, and advance the count of unique words.
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
Setup space for the local symbol hash.
|
||||||
|
Scale up the unique symbol count to make sure the hashing is efficient.
|
||||||
|
Pad up to the next power of 2 in size.
|
||||||
|
Stream through the source tokens,
|
||||||
|
using the token index to get a global dictionary string,
|
||||||
|
hash the string into the local symbol hash, writing the associated string if new entry,
|
||||||
|
and remapping the source token index to the local hash.
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
Export is the most complex part of the design, but still quite simple.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div></body></html>
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
<html><head><link rel="stylesheet" href="style.css"></head><body><div class="page">
|
||||||
|
<h1>20151121 - ISA Toolbox</h1>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
For years now I have found that nearly everything I work on can be made better by leveraging ISA features which are not always exposed in all the graphics APIs.
|
||||||
|
For example, currently working on a project now which could use the combination of the following,<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
(1.) From <a href="https://www.opengl.org/registry/specs/AMD/shader_trinary_minmax.txt">AMD_shader_trinary_minmax</a>, max3().
|
||||||
|
Direct access to max of three values in a single V_MAX3_F32 operation.
|
||||||
|
If the GPU has 3 read ports on the register file for FMA, might at well take advantage of that for min/max/median.
|
||||||
|
AMD's DX driver shader compiler automatically optimizes these cases, for example "min(x,min(y,z))" gets transformed to "min3(x,y,z)".
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
(2.) Direct exposure of V_SIN_F32 and V_COS_F32, which have a range of +/- 512 PI and take normalized input.
|
||||||
|
Avoids and extra V_MUL_F32 and V_FRACT_F32 per operation.
|
||||||
|
Nearly all the time I use sin() or cos() I'm in range (no need for V_FRACT_F32).
|
||||||
|
Nearly all the time I'm in the {0 to 1} range for 360 degrees,
|
||||||
|
and need to scale by 2 PI only so code generation can later scale back by 1/2 PI.
|
||||||
|
Portable fallback for machines without V_SIN_F32 and V_COS_F32 like functionality looks like,
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<tt>float sinNormalized(float x) { return sin(x * 2.0 * PI); }<br>
|
||||||
|
float cosNormalized(float x) { return cos(x * 2.0 * PI); }</tt><br>
|
||||||
|
<br>
|
||||||
|
(3.) Branching if any or all of the SIMD vector want to do something.
|
||||||
|
Massively important tool to avoid divergence.
|
||||||
|
For example in a full screen triangle, if any pixel needs the more complex path,
|
||||||
|
just have the full SIMD vector only do the complex path instead of divergently processing both complex and simple.
|
||||||
|
API can be quite simple,
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<tt>
|
||||||
|
bool anyInvocations(bool x)<br>
|
||||||
|
bool allInvocations(bool x)</tt><br>
|
||||||
|
<br>
|
||||||
|
Example of how these could map in GCN (these scalar instructions execute in parallel with vector instructions, so low cost),<br>
|
||||||
|
<br>
|
||||||
|
<tt>// S_CMP_NEQ_U64 x,0<br>
|
||||||
|
// S_CBRANCH_SCCNZ<br>
|
||||||
|
if(anyInvocations(x)) { }<br>
|
||||||
|
<br>
|
||||||
|
// S_CMP_EQ_U64 x,-1<br>
|
||||||
|
// S_CBRANCH_SCCNZ<br>
|
||||||
|
if(allInvocations(x)) { }</tt><br>
|
||||||
|
<br>
|
||||||
|
(4.) Quad swizzle for fragment shaders for cross-invocation communication is super useful.
|
||||||
|
Given a 2x2 fragment quad as follows,<br>
|
||||||
|
<br>
|
||||||
|
<tt>01<br>
|
||||||
|
23</tt><br>
|
||||||
|
<br>
|
||||||
|
These functions would be quite useful (they map to DS_SWIZZLE_B32 in GCN),<br>
|
||||||
|
<br>
|
||||||
|
<tt>// Swap value horizontally.<br>
|
||||||
|
type quadSwizzle1032(type x)<br>
|
||||||
|
<br>
|
||||||
|
// Swap value vertically.<br>
|
||||||
|
type quadSwizzle2301(type x)</tt><br>
|
||||||
|
<br>
|
||||||
|
For example one could simultaneously write out the results of a fragment shader to the standard full screen pass
|
||||||
|
and write out the 1/2 x 1/2 resolution next smaller mip level at the same time using an extra image store.
|
||||||
|
Just use the following to do a 2x2 box filter in the shader,<br>
|
||||||
|
<br>
|
||||||
|
<tt>boxFilterColor = quadSwizzle1032(color) + color;<br>
|
||||||
|
boxFilterColor += quadSwizzle2301(boxFilterColor);</tt><br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div></body></html>
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user