diff options
Diffstat (limited to 'src/Shiny/ShinyManager.c')
-rw-r--r-- | src/Shiny/ShinyManager.c | 445 |
1 files changed, 445 insertions, 0 deletions
diff --git a/src/Shiny/ShinyManager.c b/src/Shiny/ShinyManager.c new file mode 100644 index 000000000..6b2811851 --- /dev/null +++ b/src/Shiny/ShinyManager.c @@ -0,0 +1,445 @@ +/* +The MIT License + +Copyright (c) 2007-2010 Aidin Abedi http://code.google.com/p/shinyprofiler/ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifdef SLIC3R_PROFILE + +#include "ShinyManager.h" + +#include <malloc.h> +#include <memory.h> +#include <string.h> +#include <stdio.h> + +/*---------------------------------------------------------------------------*/ + +#define TABLE_SIZE_INIT 256 + +/*---------------------------------------------------------------------------*/ + +ShinyManager Shiny_instance = { +#if SHINY_HAS_ENABLED == TRUE + /* enabled = */ false, +#endif + /* _lastTick = */ 0, + /* _curNode = */ &Shiny_instance.rootNode, + /* _tableMask = */ 0, + /* _nodeTable = */ _ShinyManager_dummyNodeTable, +#if SHINY_LOOKUP_RATE == TRUE + /* _lookupCount = */ 0, + /* _lookupSuccessCount = */ 0, +#endif + /* _tableSize = */ 1, + /* nodeCount = */ 1, + /* zoneCount = */ 1, + /* _lastZone = */ &Shiny_instance.rootZone, + /* _lastNodePool = */ NULL, + /* _firstNodePool = */ NULL, + /* rootNode = */ { + /* _last = */ { 0, 0 }, + /* zone = */ &Shiny_instance.rootZone, + /* parent = */ &Shiny_instance.rootNode, + /* nextSibling = */ NULL, + /* firstChild = */ NULL, + /* lastChild = */ NULL, + /* childCount = */ 0, + /* entryLevel = */ 0, + /* _cache = */ NULL, + /* data = */ { { 0, 0 }, { 0, 0 }, { 0, 0 } } + }, + /* rootZone = */ { + /* next = */ NULL, + /* _state = */ SHINY_ZONE_STATE_HIDDEN, + /* name = */ "<unprofiled>", + /* data = */ { { 0, 0 }, { 0, 0 }, { 0, 0 } } + }, + /* damping = */ 0.f, // Damping disabled, every PROFILE_UPDATE will be performed from scratch. Original value: 0.9f + /* _initialized = */ FALSE, + /* _firstUpdate = */ TRUE +}; + +ShinyNode* _ShinyManager_dummyNodeTable[] = { NULL }; + + +/*---------------------------------------------------------------------------*/ + +#if SHINY_COMPILER == SHINY_COMPILER_MSVC +# pragma warning (push) +# pragma warning (disable: 4311) +#endif + +/* primary hash function */ +SHINY_INLINE uint32_t hash_value(void* a_pParent, void* a_pZone) { + uint32_t a = (uint32_t) a_pParent + (uint32_t) a_pZone; +// uint32_t a = *reinterpret_cast<uint32_t*>(&a_pParent) + *reinterpret_cast<uint32_t*>(&a_pZone); + + a = (a+0x7ed55d16) + (a<<12); + a = (a^0xc761c23c) ^ (a>>19); + return a; +} + +/* + * secondary hash used as index offset: force it to be odd + * so it's relatively prime to the power-of-two table size + */ +SHINY_INLINE uint32_t hash_offset(uint32_t a) { + return ((a << 8) + (a >> 4)) | 1; +} + +#if SHINY_COMPILER == SHINY_COMPILER_MSVC +# pragma warning (pop) +#endif + + +/*---------------------------------------------------------------------------*/ + +void ShinyManager_preLoad(ShinyManager *self) { + if (!self->_initialized) { + _ShinyManager_init(self); + + _ShinyManager_createNodeTable(self, TABLE_SIZE_INIT); + _ShinyManager_createNodePool(self, TABLE_SIZE_INIT / 2); + } +} + + +/*---------------------------------------------------------------------------*/ + +void ShinyManager_update(ShinyManager *self) { +#if SHINY_HAS_ENABLED == TRUE + if (!enabled) return; +#endif + + _ShinyManager_appendTicksToCurNode(self); + ShinyZone_preUpdateChain(&self->rootZone); + + if (self->_firstUpdate || self->damping == 0) { + self->_firstUpdate = FALSE; + ShinyNode_updateTreeClean(&self->rootNode); + ShinyZone_updateChainClean(&self->rootZone); + + } else { + ShinyNode_updateTree(&self->rootNode, self->damping); + ShinyZone_updateChain(&self->rootZone, self->damping); + } +} + + +/*---------------------------------------------------------------------------*/ + +void ShinyManager_updateClean(ShinyManager *self) { +#if SHINY_HAS_ENABLED == TRUE + if (!enabled) return; +#endif + + _ShinyManager_appendTicksToCurNode(self); + ShinyZone_preUpdateChain(&self->rootZone); + + self->_firstUpdate = FALSE; + ShinyNode_updateTreeClean(&self->rootNode); + ShinyZone_updateChainClean(&self->rootZone); +} + + +/*---------------------------------------------------------------------------*/ + +void ShinyManager_clear(ShinyManager *self) { + ShinyManager_destroy(self); + ShinyManager_preLoad(self); +} + + +/*---------------------------------------------------------------------------*/ + +void ShinyManager_destroy(ShinyManager *self) { + ShinyManager_destroyNodes(self); + ShinyManager_resetZones(self); + _ShinyManager_uninit(self); +} + + +/*---------------------------------------------------------------------------*/ + +ShinyNode* _ShinyManager_lookupNode(ShinyManager *self, ShinyNodeCache *a_cache, ShinyZone *a_zone) { + uint32_t nHash = hash_value(self->_curNode, a_zone); + uint32_t nIndex = nHash & self->_tableMask; + ShinyNode* pNode = self->_nodeTable[nIndex]; + + _ShinyManager_incLookup(self); + _ShinyManager_incLookupSuccess(self); + + if (pNode) { + uint32_t nStep; + + if (ShinyNode_isEqual(pNode, self->_curNode, a_zone)) return pNode; /* found it! */ + + /* hash collision: */ + + /* compute a secondary hash function for stepping */ + nStep = hash_offset(nHash); + + for (;;) { + _ShinyManager_incLookup(self); + + nIndex = (nIndex + nStep) & self->_tableMask; + pNode = self->_nodeTable[nIndex]; + + if (!pNode) break; /* found empty slot */ + else if (ShinyNode_isEqual(pNode, self->_curNode, a_zone)) return pNode; /* found it! */ + } + + /* loop is guaranteed to end because the hash table is never full */ + } + + if (a_zone->_state == SHINY_ZONE_STATE_HIDDEN) { /* zone is not initialized */ + ShinyZone_init(a_zone, self->_lastZone); + + self->_lastZone = a_zone; + self->zoneCount++; + + if (self->_initialized == FALSE) { /* first time init */ + _ShinyManager_init(self); + + _ShinyManager_createNodeTable(self, TABLE_SIZE_INIT); + _ShinyManager_createNodePool(self, TABLE_SIZE_INIT / 2); + + /* initialization has invalidated nIndex + * we must compute nIndex again + */ + return _ShinyManager_createNode(self, a_cache, a_zone); + } + } + + /* Althouth nodeCount is not updated + * it includes rootNode so it adds up. + * + * check if we need to grow the table + * we keep it at most 1/2 full to be very fast + */ + if (self->_tableSize < 2 * self->nodeCount) { + + _ShinyManager_resizeNodeTable(self, 2 * self->_tableSize); + _ShinyManager_resizeNodePool(self, self->nodeCount - 1); + + /* resize has invalidated nIndex + * we must compute nIndex again + */ + return _ShinyManager_createNode(self, a_cache, a_zone); + } + + self->nodeCount++; + + { + ShinyNode* pNewNode = ShinyNodePool_newItem(self->_lastNodePool); + ShinyNode_init(pNewNode, self->_curNode, a_zone, a_cache); + + self->_nodeTable[nIndex] = pNewNode; + return pNewNode; + } +} + + +/*---------------------------------------------------------------------------*/ + +void _ShinyManager_insertNode(ShinyManager *self, ShinyNode* a_pNode) { + uint32_t nHash = hash_value(a_pNode->parent, a_pNode->zone); + uint32_t nIndex = nHash & self->_tableMask; + + if (self->_nodeTable[nIndex]) { + uint32_t nStep = hash_offset(nHash); + + while (self->_nodeTable[nIndex]) + nIndex = (nIndex + nStep) & self->_tableMask; + } + + self->_nodeTable[nIndex] = a_pNode; +} + + +/*---------------------------------------------------------------------------*/ + +ShinyNode* _ShinyManager_createNode(ShinyManager *self, ShinyNodeCache* a_cache, ShinyZone* a_pZone) { + ShinyNode* pNewNode = ShinyNodePool_newItem(self->_lastNodePool); + ShinyNode_init(pNewNode, self->_curNode, a_pZone, a_cache); + + self->nodeCount++; + _ShinyManager_insertNode(self, pNewNode); + return pNewNode; +} + + +/*---------------------------------------------------------------------------*/ + +void _ShinyManager_createNodePool(ShinyManager *self, uint32_t a_nCount) { + self->_firstNodePool = ShinyNodePool_create(a_nCount); + self->_lastNodePool = self->_firstNodePool; +} + + +/*---------------------------------------------------------------------------*/ + +void _ShinyManager_resizeNodePool(ShinyManager *self, uint32_t a_nCount) { + ShinyNodePool* pPool = ShinyNodePool_create(a_nCount); + self->_lastNodePool->nextPool = pPool; + self->_lastNodePool = pPool; +} + + +/*---------------------------------------------------------------------------*/ + +void _ShinyManager_createNodeTable(ShinyManager *self, uint32_t a_nCount) { + self->_tableSize = a_nCount; + self->_tableMask = a_nCount - 1; + + self->_nodeTable = (ShinyNodeTable*) + malloc(sizeof(ShinyNode) * a_nCount); + + memset(self->_nodeTable, 0, a_nCount * sizeof(ShinyNode*)); +} + + +/*---------------------------------------------------------------------------*/ + +void _ShinyManager_resizeNodeTable(ShinyManager *self, uint32_t a_nCount) { + ShinyNodePool* pPool; + + free(self->_nodeTable); + _ShinyManager_createNodeTable(self, a_nCount); + + pPool = self->_firstNodePool; + while (pPool) { + + ShinyNode *pIter = ShinyNodePool_firstItem(pPool); + + while (pIter != pPool->_nextItem) + _ShinyManager_insertNode(self, pIter++); + + pPool = pPool->nextPool; + } +} + + +/*---------------------------------------------------------------------------*/ + +void ShinyManager_resetZones(ShinyManager *self) { + ShinyZone_resetChain(&self->rootZone); + self->_lastZone = &self->rootZone; + self->zoneCount = 1; +} + + +/*---------------------------------------------------------------------------*/ + +void ShinyManager_destroyNodes(ShinyManager *self) { + if (self->_firstNodePool) { + ShinyNodePool_destroy(self->_firstNodePool); + self->_firstNodePool = NULL; + } + + if (self->_nodeTable != _ShinyManager_dummyNodeTable) { + free(self->_nodeTable); + + self->_nodeTable = _ShinyManager_dummyNodeTable; + self->_tableSize = 1; + self->_tableMask = 0; + } + + self->_curNode = &self->rootNode; + self->nodeCount = 1; + + _ShinyManager_init(self); +} + + +/*---------------------------------------------------------------------------*/ + +const char* ShinyManager_getOutputErrorString(ShinyManager *self) { + if (self->_firstUpdate) return "!!! Profile data must first be updated !!!"; + else if (!self->_initialized) return "!!! No profiles where executed !!!"; + else return NULL; +} + + +/*---------------------------------------------------------------------------*/ + +#if SHINY_COMPILER == SHINY_COMPILER_MSVC +# pragma warning (push) +# pragma warning (disable: 4996) +#endif + +int ShinyManager_output(ShinyManager *self, const char *a_filename) { + if (!a_filename) { + ShinyManager_outputToStream(self, stdout); + + } else { + FILE *file = fopen(a_filename, "w"); + if (!file) return FALSE; + ShinyManager_outputToStream(self, file); + fclose(file); + } + + return TRUE; +} + +#if SHINY_COMPILER == SHINY_COMPILER_MSVC +# pragma warning (pop) +#endif + + +/*---------------------------------------------------------------------------*/ + +void ShinyManager_outputToStream(ShinyManager *self, FILE *a_stream) { + const char *error = ShinyManager_getOutputErrorString(self); + + if (error) { + fwrite(error, 1, strlen(error), a_stream); + fwrite("\n\n", 1, 2, a_stream); + return; + } + +#if SHINY_OUTPUT_MODE & SHINY_OUTPUT_MODE_FLAT + ShinyManager_sortZones(self); + + { + int size = ShinyPrintZonesSize(self->zoneCount); + char *buffer = (char*) malloc(size); + ShinyPrintZones(buffer, &self->rootZone); + fwrite(buffer, 1, size - 1, a_stream); + fwrite("\n\n", 1, 2, a_stream); + free(buffer); + } +#endif + +#if SHINY_OUTPUT_MODE & SHINY_OUTPUT_MODE_TREE + { + int size = ShinyPrintNodesSize(self->nodeCount); + char *buffer = (char*) malloc(size); + ShinyPrintNodes(buffer, &self->rootNode); + fwrite(buffer, 1, size - 1, a_stream); + fwrite("\n\n", 1, 2, a_stream); + free(buffer); + } +#endif +} + +#endif /* SLIC3R_PROFILE */ |