<div dir="ltr">On 4 February 2014 19:52, Paul Berry <span dir="ltr"><<a href="mailto:stereotype441@gmail.com" target="_blank">stereotype441@gmail.com</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote">
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">Whoops, I discovered another issue:<br><div><div class="gmail_extra"><br><br><div class="gmail_quote">
<div class="im">On 29 January 2014 01:24, Tapani Pälli <span dir="ltr"><<a href="mailto:tapani.palli@intel.com" target="_blank">tapani.palli@intel.com</a>></span> wrote:<br>
</div><div><div class="h5"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Class will be used by the shader binary cache implementation.<br>
<br>
Signed-off-by: Tapani Pälli <<a href="mailto:tapani.palli@intel.com" target="_blank">tapani.palli@intel.com</a>><br>
---<br>
src/glsl/memory_writer.h | 188 +++++++++++++++++++++++++++++++++++++++++++++++<br>
1 file changed, 188 insertions(+)<br>
create mode 100644 src/glsl/memory_writer.h<br>
<br>
diff --git a/src/glsl/memory_writer.h b/src/glsl/memory_writer.h<br>
new file mode 100644<br>
index 0000000..979169f<br>
--- /dev/null<br>
+++ b/src/glsl/memory_writer.h<br>
@@ -0,0 +1,188 @@<br>
+/* -*- c++ -*- */<br>
+/*<br>
+ * Copyright © 2013 Intel Corporation<br>
+ *<br>
+ * Permission is hereby granted, free of charge, to any person obtaining a<br>
+ * copy of this software and associated documentation files (the "Software"),<br>
+ * to deal in the Software without restriction, including without limitation<br>
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,<br>
+ * and/or sell copies of the Software, and to permit persons to whom the<br>
+ * Software is furnished to do so, subject to the following conditions:<br>
+ *<br>
+ * The above copyright notice and this permission notice (including the next<br>
+ * paragraph) shall be included in all copies or substantial portions of the<br>
+ * Software.<br>
+ *<br>
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL<br>
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br>
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING<br>
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER<br>
+ * DEALINGS IN THE SOFTWARE.<br>
+ */<br>
+<br>
+#pragma once<br>
+#ifndef MEMORY_WRITER_H<br>
+#define MEMORY_WRITER_H<br>
+<br>
+#include <stdlib.h><br>
+#include <unistd.h><br>
+#include <string.h><br>
+<br>
+#include "main/hash_table.h"<br>
+<br>
+#ifdef __cplusplus<br>
+/**<br>
+ * Helper class for writing data to memory<br>
+ *<br>
+ * This class maintains a dynamically-sized memory buffer and allows<br>
+ * for data to be efficiently appended to it with automatic resizing.<br>
+ */<br>
+class memory_writer<br>
+{<br>
+public:<br>
+ memory_writer() :<br>
+ memory(NULL),<br>
+ curr_size(0),<br>
+ pos(0)<br>
+ {<br>
+ data_hash = _mesa_hash_table_create(0, int_equal);<br>
+ hash_value = _mesa_hash_data(this, sizeof(memory_writer));<br>
+ }<br>
+<br>
+ ~memory_writer()<br>
+ {<br>
+ free(memory);<br>
+ _mesa_hash_table_destroy(data_hash, NULL);<br>
+ }<br>
+<br>
+ /* user wants to claim the memory */<br>
+ char *release_memory(size_t *size)<br>
+ {<br>
+ /* final realloc to free allocated but unused memory */<br>
+ char *result = (char *) realloc(memory, pos);<br>
+ *size = pos;<br>
+ memory = NULL;<br>
+ curr_size = 0;<br>
+ pos = 0;<br>
+ return result;<br>
+ }<br>
+<br>
+/**<br>
+ * write functions per type<br>
+ */<br>
+#define DECL_WRITER(type) void write_ ##type (const type data) {\<br>
+ write(&data, sizeof(type));\<br>
+}<br>
+<br>
+ DECL_WRITER(int32_t);<br>
+ DECL_WRITER(int64_t);<br>
+ DECL_WRITER(uint8_t);<br>
+ DECL_WRITER(uint32_t);<br>
+<br>
+ void write_bool(bool data)<br>
+ {<br>
+ uint8_t val = data;<br>
+ write_uint8_t(val);<br>
+ }<br>
+<br>
+ /* write function that reallocates more memory if required */<br>
+ void write(const void *data, int size)<br>
+ {<br>
+ if (!memory || pos > (curr_size - size))<br>
+ if (!grow(size))<br>
+ return;<br>
+<br>
+ memcpy(memory + pos, data, size);<br>
+<br>
+ pos += size;<br>
+ }<br>
+<br>
+ void overwrite(const void *data, int size, int offset)<br>
+ {<br>
+ if (offset < 0 || offset + size > pos)<br>
+ return;<br>
+ memcpy(memory + offset, data, size);<br>
+ }<br>
+<br>
+ /* length is written to make reading safe */<br>
+ void write_string(const char *str)<br>
+ {<br>
+ uint32_t len = str ? strlen(str) : 0;<br>
+ write_uint32_t(len);<br>
+<br>
+ if (str)<br>
+ write(str, len + 1);<br>
+ }<br>
+<br>
+ unsigned position()<br>
+ {<br>
+ return pos;<br>
+ }<br>
+<br>
+ /**<br>
+ * check if some data was written<br>
+ */<br>
+ bool data_was_written(void *data, uint32_t id)<br>
+ {<br>
+ hash_entry *entry =<br>
+ _mesa_hash_table_search(data_hash, hash_value,<br>
+ (void*) (intptr_t) id);<br></blockquote><div><br></div></div></div><div>This isn't an efficient way to use a hashtable. You're always passing the same hash_value (the one computed in the constructor), which means that every single hash entry will be stored in the same chain, and lookups will be really slow.<br>
<br>Since you're only using this hashtable to detect duplicate glsl_types, there's a much easier approach: take advantage of the fact that glsl_type is a flyweight class (in other words, code elsewhere in Mesa ensures that no duplicate glsl_type objects exist anywhere in memory, so any two glsl_type pointers can be compared simply using pointer equality). Because of that, you should be able to just use a pointer-based hashtable, like ir_variable_refcount_visitor does. In short, that means:<br>
<br></div><div>- Get rid of the hash_value class member.<br><br></div><div>- In the constructor, do this: _mesa_hash_table_create(NULL, _mesa_key_pointer_equal)<br><br></div><div>- The data_was_written() function can just look like this:<br>
<br> bool data_was_written(void *data)<br> {<br> return _mesa_hash_table_search(data_hash, _mesa_hash_pointer(data),<br> data) != NULL;<br> }<br><br></div><div>- The mark_data_written() function can just look like this:<br>
</div><div><br></div><div> void mark_data_written(void *data)<br> {<br> _mesa_hash_table_insert(data_hash, _mesa_hash_pointer(data),<br> data, NULL);<br> }<br><br>Note that I'm passing NULL for the last argument of _mesa_hash_table_insert because we don't actually need the hashtable to act as a key/value store; we are just using it to check whether we've seen a pointer before; so when we're marking that we've seen a pointer we don't need to store any data with it. <br>
</div></div></div></div></div></blockquote><div><br></div><div>Oops, sorry, I was wrong about this. We do actually need the hashtable to act as a key/value store, because we need it to store the mapping from "data" to the unique ID. However, the problem with what you've written is that there's nothing to guarantee that the ID is unique. (In patch 2, when you call these functions, you form the ID by calling _mesa_hash_data() on the contents of the glsl_type, but that's not safe because two distinct glsl_types might hash to the same value).<br>
<br></div><div>How about if we replace data_was_written() and mark_data_written() with something like this:<br><br> /**<br> * Convert the given pointer into a small integer unique ID. In other<br> * words, if make_unique_id() has previously been called with this pointer,<br>
* return the same ID that was returned last time. If this is the first<br> * call to make_unique_id() with this pointer, return a fresh ID.<br> *<br> * Return value is true if the pointer has been seen before, false<br>
* otherwise.<br> */<br> bool make_unique_id(void *ptr, uint32_t *id_out)<br> {<br> void *entry =<br> _mesa_hash_table_search(data_hash, _mesa_hash_pointer(ptr), ptr);<br> if (entry != NULL) {<br>
*id_out = (uint32_t) (intptr_t) entry;<br> return true;<br> } else {<br> /* Note: hashtable uses 0 to represent "entry not found" so our<br> * unique ID's need to start at 1. Hence, preincrement<br>
* unique_id_counter.<br> */<br> *id_out = ++this->unique_id_counter;<br> _mesa_hash_table_insert(data_hash, _mesa_hash_pointer(ptr), ptr,<br> (void *) (intptr_t) *id_out);<br>
return false;<br> }<br> }<br></div></div></div></div>