From d3d7e3f286a0066bec9b831c57ebcbe8f0ebdfd8 Mon Sep 17 00:00:00 2001 From: TimothyLottes Date: Mon, 21 Nov 2016 22:44:07 -0500 Subject: [PATCH] Add files via upload --- 20151113.html | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++ 20151121.html | 77 ++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 20151113.html create mode 100644 20151121.html diff --git a/20151113.html b/20151113.html new file mode 100644 index 0000000..e333219 --- /dev/null +++ b/20151113.html @@ -0,0 +1,106 @@ +
+

20151113 - Rethinking the Symbolic Dictionary

+
+ +Another permutation of dictionary implementation for forth like languages...
+
+Source +
+Exported source is composed of two parts,
+
+(1.) Token array, where tokens can reference a local symbol by index into local hash table.
+(2.) Local symbol hash table, has string for each entry.
+
+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.
+
+Global Dictionary +
+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. +
+
+ +Source Import +
+Starts with loaded source in memory and allocated space for one extra array,
+
+(1.) Source token array, gets translated to loaded-in-memory form.
+(2.) Source local symbol hash table, with each entry being a 64-bit string.
+(3.) Remap space, extra zeroed array with a 32-bit value per entry in local hash table.
+
+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. +
+
+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). +
+
+Note with this new design, interpreting source at run-time no longer has any hash lookup, +just a direct lookup.
+
+ +First Source Import +
+First source import (after machine reboot) has effectively an empty dictionary, +so import can be optimized.
+
+ +Editing +
+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. +
+
+ +Source Export +
+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. +
+
+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. +
+
+Export is the most complex part of the design, but still quite simple. + + + + +
+ + diff --git a/20151121.html b/20151121.html new file mode 100644 index 0000000..853a6a8 --- /dev/null +++ b/20151121.html @@ -0,0 +1,77 @@ +
+

20151121 - ISA Toolbox

+
+ +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,
+
+ +(1.) From AMD_shader_trinary_minmax, 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)". +
+
+ +(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, +
+
+float sinNormalized(float x) { return sin(x * 2.0 * PI); }
+float cosNormalized(float x) { return cos(x * 2.0 * PI); }

+
+(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, +
+
+ +bool anyInvocations(bool x)
+bool allInvocations(bool x)

+
+Example of how these could map in GCN (these scalar instructions execute in parallel with vector instructions, so low cost),
+
+// S_CMP_NEQ_U64 x,0
+// S_CBRANCH_SCCNZ
+if(anyInvocations(x)) { }
+
+// S_CMP_EQ_U64 x,-1
+// S_CBRANCH_SCCNZ
+if(allInvocations(x)) { }

+
+(4.) Quad swizzle for fragment shaders for cross-invocation communication is super useful. +Given a 2x2 fragment quad as follows,
+
+01
+23

+
+These functions would be quite useful (they map to DS_SWIZZLE_B32 in GCN),
+
+// Swap value horizontally.
+type quadSwizzle1032(type x)
+
+// Swap value vertically.
+type quadSwizzle2301(type x)

+
+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,
+
+boxFilterColor = quadSwizzle1032(color) + color;
+boxFilterColor += quadSwizzle2301(boxFilterColor);

+
+ + + + + + +
+ +