diff --git a/xs/MANIFEST b/xs/MANIFEST index 9ba08d735..572f05c29 100644 --- a/xs/MANIFEST +++ b/xs/MANIFEST @@ -116,6 +116,26 @@ src/slic3r/GUI/3DScene.cpp src/slic3r/GUI/3DScene.hpp src/slic3r/GUI/GUI.cpp src/slic3r/GUI/GUI.hpp +src/Shiny/Shiny.h +src/Shiny/ShinyData.h +src/Shiny/ShinyManager.h +src/Shiny/ShinyNodePool.h +src/Shiny/ShinyOutput.h +src/Shiny/ShinyTools.h +src/Shiny/ShinyZone.h +src/Shiny/ShinyConfig.h +src/Shiny/ShinyMacros.h +src/Shiny/ShinyNode.h +src/Shiny/ShinyNodeState.h +src/Shiny/ShinyPrereqs.h +src/Shiny/ShinyVersion.h +src/Shiny/ShinyManager.c +src/Shiny/ShinyNode.c +src/Shiny/ShinyNodePool.c +src/Shiny/ShinyNodeState.c +src/Shiny/ShinyOutput.c +src/Shiny/ShinyTools.c +src/Shiny/ShinyZone.c src/xsinit.h t/01_trianglemesh.t t/03_point.t diff --git a/xs/src/Shiny/Shiny.h b/xs/src/Shiny/Shiny.h new file mode 100644 index 000000000..40c66685f --- /dev/null +++ b/xs/src/Shiny/Shiny.h @@ -0,0 +1,33 @@ +/* +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. +*/ + +#ifndef SHINY_H +#define SHINY_H + +/*---------------------------------------------------------------------------*/ + +#include "ShinyMacros.h" +#include "ShinyManager.h" + +#endif /* SHINY_H */ diff --git a/xs/src/Shiny/ShinyConfig.h b/xs/src/Shiny/ShinyConfig.h new file mode 100644 index 000000000..d318574d5 --- /dev/null +++ b/xs/src/Shiny/ShinyConfig.h @@ -0,0 +1,69 @@ +/* +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. +*/ + +#ifndef SHINY_CONFIG_H +#define SHINY_CONFIG_H + + +/*---------------------------------------------------------------------------*/ + +/* SHINY_IS_COMPILED is the master on or off swith at compile time. Define it to TRUE or FALSE before including header Shiny.h or inside ShinyConfig.h. Default is TRUE. + */ +#if defined(SLIC3R_PROFILE) && defined(WIN32) +#define SHINY_IS_COMPILED TRUE +#endif + +#define SHINY_STATIC_LINK TRUE + +/* if SHINY_LOOKUP_RATE is defined to TRUE then Shiny will record the success of its hash function. This is useful for debugging. Default is FALSE. + */ +#ifndef SHINY_LOOKUP_RATE +// #define SHINY_LOOKUP_RATE FALSE +#endif + +/* if SHINY_HAS_ENABLED is defined to TRUE then Shiny can be enabled and disabled at runtime. TODO: bla bla... + */ +#ifndef SHINY_HAS_ENABLED +// #define SHINY_HAS_ENABLED FALSE +#endif + +/* TODO: + */ +#define SHINY_OUTPUT_MODE_FLAT 0x1 + +/* TODO: + */ +#define SHINY_OUTPUT_MODE_TREE 0x2 + +/* TODO: + */ +#define SHINY_OUTPUT_MODE_BOTH 0x3 + +/* TODO: + */ +#ifndef SHINY_OUTPUT_MODE +#define SHINY_OUTPUT_MODE SHINY_OUTPUT_MODE_BOTH +#endif + +#endif /* SHINY_CONFIG_H */ diff --git a/xs/src/Shiny/ShinyData.h b/xs/src/Shiny/ShinyData.h new file mode 100644 index 000000000..d75d4f5bf --- /dev/null +++ b/xs/src/Shiny/ShinyData.h @@ -0,0 +1,102 @@ +/* +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. +*/ + +#ifndef SHINY_DATA_H +#define SHINY_DATA_H + +#include "ShinyPrereqs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*---------------------------------------------------------------------------*/ + +typedef struct { + uint32_t entryCount; + shinytick_t selfTicks; +} ShinyLastData; + + +/*---------------------------------------------------------------------------*/ + +typedef struct { + shinytick_t cur; + float avg; +} ShinyTickData; + +typedef struct { + uint32_t cur; + float avg; +} ShinyCountData; + +typedef struct { + ShinyCountData entryCount; + ShinyTickData selfTicks; + ShinyTickData childTicks; +} ShinyData; + +SHINY_INLINE shinytick_t ShinyData_totalTicksCur(const ShinyData *self) { + return self->selfTicks.cur + self->childTicks.cur; +} + +SHINY_INLINE float ShinyData_totalTicksAvg(const ShinyData *self) { + return self->selfTicks.avg + self->childTicks.avg; +} + +SHINY_INLINE void ShinyData_computeAverage(ShinyData *self, float a_damping) { + self->entryCount.avg = self->entryCount.cur + + a_damping * (self->entryCount.avg - self->entryCount.cur); + self->selfTicks.avg = self->selfTicks.cur + + a_damping * (self->selfTicks.avg - self->selfTicks.cur); + self->childTicks.avg = self->childTicks.cur + + a_damping * (self->childTicks.avg - self->childTicks.cur); +} + +SHINY_INLINE void ShinyData_copyAverage(ShinyData *self) { + self->entryCount.avg = (float) self->entryCount.cur; + self->selfTicks.avg = (float) self->selfTicks.cur; + self->childTicks.avg = (float) self->childTicks.cur; +} + +SHINY_INLINE void ShinyData_clearAll(ShinyData *self) { + self->entryCount.cur = 0; + self->entryCount.avg = 0; + self->selfTicks.cur = 0; + self->selfTicks.avg = 0; + self->childTicks.cur = 0; + self->childTicks.avg = 0; +} + +SHINY_INLINE void ShinyData_clearCurrent(ShinyData *self) { + self->entryCount.cur = 0; + self->selfTicks.cur = 0; + self->childTicks.cur = 0; +} + +#if __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* SHINY_DATA_H */ diff --git a/xs/src/Shiny/ShinyMacros.h b/xs/src/Shiny/ShinyMacros.h new file mode 100644 index 000000000..645cbeff1 --- /dev/null +++ b/xs/src/Shiny/ShinyMacros.h @@ -0,0 +1,297 @@ +/* +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. +*/ + +#ifndef SHINY_MACROS_H +#define SHINY_MACROS_H + +#include "ShinyManager.h" + +#ifdef SHINY_IS_COMPILED + +/*---------------------------------------------------------------------------*/ +/* public preprocessors */ + +#define PROFILE_UPDATE() \ + ShinyManager_update(&Shiny_instance) + +#define PROFILE_SET_DAMPING(floatfrom0to1) \ + Shiny_instance.damping = (floatfrom0to1); + +#define PROFILE_GET_DAMPING() \ + (Shiny_instance.damping) + +#define PROFILE_OUTPUT(filename) \ + ShinyManager_output(&Shiny_instance, (filename)) + +#define PROFILE_OUTPUT_STREAM(stream) \ + ShinyManager_outputToStream(&Shiny_instance, (stream)) + +#ifdef __cplusplus +#define PROFILE_GET_TREE_STRING() \ + ShinyManager_outputTreeToString(&Shiny_instance) + +#define PROFILE_GET_FLAT_STRING() \ + ShinyManager_outputFlatToString(&Shiny_instance) +#endif /* __cplusplus */ + +#define PROFILE_DESTROY() \ + ShinyManager_destroy(&Shiny_instance) + +#define PROFILE_CLEAR() \ + ShinyManager_clear(&Shiny_instance) + +#define PROFILE_SORT_ZONES() \ + ShinyManager_sortZones(&Shiny_instance) + + +/*---------------------------------------------------------------------------*/ +/* public preprocessors */ + +#define PROFILE_GET_TOTAL_TICKS_CUR() \ + ShinyData_totalTicksCur(&Shiny_instance.rootZone.data) + +#define PROFILE_GET_TOTAL_TICKS() \ + ShinyData_totalTicksAvg(&Shiny_instance.rootZone.data) + +#define PROFILE_GET_PROFILED_TICKS_CUR() \ + (Shiny_instance.rootZone.data.selfTicks.cur) + +#define PROFILE_GET_PROFILED_TICKS() \ + (Shiny_instance.rootZone.data.selfTicks.avg) + +#define PROFILE_GET_UNPROFILED_TICKS_CUR() \ + (Shiny_instance.rootZone.data.childTicks.cur) + +#define PROFILE_GET_UNPROFILED_TICKS() \ + (Shiny_instance.rootZone.data.childTicks.avg) + +#define PROFILE_GET_SHARED_TOTAL_TICKS_CUR(name) \ + ShinyData_totalTicksCur(&(_PROFILE_ID_ZONE_SHARED(name).data)) + +#define PROFILE_GET_SHARED_TOTAL_TICKS(name) \ + ShinyData_totalTicksAvg(&(_PROFILE_ID_ZONE_SHARED(name).data)) + +#define PROFILE_GET_SHARED_SELF_TICKS_CUR(name) \ + (_PROFILE_ID_ZONE_SHARED(name).data.selfTicks.cur) + +#define PROFILE_GET_SHARED_SELF_TICKS(name) \ + (_PROFILE_ID_ZONE_SHARED(name).data.selfTicks.avg) + + +/*---------------------------------------------------------------------------*/ +/* public preprocessors */ + +#define PROFILE_IS_SHARED_SELF_BELOW(name, floatfrom0to1) \ + ShinyManager_isZoneSelfTimeBelow( \ + &Shiny_instance, _PROFILE_ID_ZONE_SHARED(name), floatfrom0to1) + +#define PROFILE_IS_SHARED_TOTAL_BELOW(name, floatfrom0to1) \ + ShinyManager_isZoneTotalTimeBelow( \ + &Shiny_instance, _PROFILE_ID_ZONE_SHARED(name), floatfrom0to1) + + +/*---------------------------------------------------------------------------*/ +/* public preprocessors */ + +#define PROFILE_END() \ + ShinyManager_endCurNode(&Shiny_instance) + + +/*---------------------------------------------------------------------------*/ +/* public preprocessors */ + +#define PROFILE_BEGIN( name ) \ + \ + static _PROFILE_ZONE_DEFINE(_PROFILE_ID_ZONE(name), #name); \ + _PROFILE_ZONE_BEGIN(_PROFILE_ID_ZONE(name)) + + +/*---------------------------------------------------------------------------*/ +/* public preprocessors */ + +#ifdef __cplusplus +#define PROFILE_BLOCK( name ) \ + \ + _PROFILE_BLOCK_DEFINE(_PROFILE_ID_BLOCK()); \ + PROFILE_BEGIN(name) +#endif /* __cplusplus */ + +/*---------------------------------------------------------------------------*/ +/* public preprocessors */ + +#ifdef __cplusplus +#define PROFILE_FUNC() \ + \ + _PROFILE_BLOCK_DEFINE(_PROFILE_ID_BLOCK()); \ + static _PROFILE_ZONE_DEFINE(_PROFILE_ID_ZONE_FUNC(), __FUNCTION__); \ + _PROFILE_ZONE_BEGIN(_PROFILE_ID_ZONE_FUNC()) +#endif /* __cplusplus */ + +/*---------------------------------------------------------------------------*/ +/* public preprocessors */ + +#define PROFILE_CODE( code ) \ + \ + do { \ + static _PROFILE_ZONE_DEFINE(_PROFILE_ID_ZONE_CODE(), #code); \ + _PROFILE_ZONE_BEGIN(_PROFILE_ID_ZONE_CODE()); \ + { code; } \ + PROFILE_END(); \ + } while(0) + + +/*---------------------------------------------------------------------------*/ +/* public preprocessors */ + +#define PROFILE_SHARED_EXTERN( name ) \ + \ + _PROFILE_ZONE_DECLARE(extern, _PROFILE_ID_ZONE_SHARED(name)) + + +/*---------------------------------------------------------------------------*/ +/* public preprocessors */ + +#define PROFILE_SHARED_DEFINE( name ) \ + \ + _PROFILE_ZONE_DEFINE(_PROFILE_ID_ZONE_SHARED(name), #name) + + +/*---------------------------------------------------------------------------*/ +/* public preprocessors */ + +#define PROFILE_SHARED_BEGIN( name ) \ + \ + _PROFILE_ZONE_BEGIN(_PROFILE_ID_ZONE_SHARED(name)) + + +/*---------------------------------------------------------------------------*/ +/* public preprocessors */ + +#ifdef __cplusplus +#define PROFILE_SHARED_BLOCK( name ) \ + \ + _PROFILE_BLOCK_DEFINE(_PROFILE_ID_BLOCK()); \ + _PROFILE_ZONE_BEGIN(_PROFILE_ID_ZONE_SHARED(name)) +#endif /* __cplusplus */ + + +/*---------------------------------------------------------------------------*/ +/* public preprocessors */ + +#ifdef SHINY_HAS_ENABLED +#define PROFILE_SET_ENABLED( boolean ) \ + Shiny_instance.enabled = boolean +#endif + + +/*---------------------------------------------------------------------------*/ +/* internal preprocessors */ + +#define _PROFILE_ID_ZONE( name ) __ShinyZone_##name +#define _PROFILE_ID_ZONE_FUNC() __ShinyZoneFunc +#define _PROFILE_ID_ZONE_CODE() __ShinyZoneCode +#define _PROFILE_ID_ZONE_SHARED( name ) name##__ShinyZoneShared +#define _PROFILE_ID_BLOCK() __ShinyBlock + + +/*---------------------------------------------------------------------------*/ +/* internal preprocessor */ + +#define _PROFILE_ZONE_DEFINE( id, string ) \ + \ + ShinyZone id = { \ + NULL, SHINY_ZONE_STATE_HIDDEN, string, \ + { { 0, 0 }, { 0, 0 }, { 0, 0 } } \ + } + + +/*---------------------------------------------------------------------------*/ +/* internal preprocessor */ + +#define _PROFILE_ZONE_DECLARE( prefix, id ) \ + \ + prefix ShinyZone id + + +/*---------------------------------------------------------------------------*/ +/* internal preprocessor */ + +#define _PROFILE_BLOCK_DEFINE( id ) \ + \ + ShinyEndNodeOnDestruction SHINY_UNUSED id + + +/*---------------------------------------------------------------------------*/ +/* internal preprocessor */ + +#define _PROFILE_ZONE_BEGIN( id ) \ + \ + do { \ + static ShinyNodeCache cache = &_ShinyNode_dummy; \ + ShinyManager_lookupAndBeginNode(&Shiny_instance, &cache, &id); \ + } while(0) + +/*---------------------------------------------------------------------------*/ + +#else /* #if SHINY_IS_COMPILED == TRUE */ + +#ifdef __cplusplus +extern "C" { +#endif +SHINY_INLINE ShinyData GetEmptyData() { + ShinyData a = { { 0, 0 }, { 0, 0 }, { 0, 0 } }; + return a; +} +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#define PROFILE_UPDATE() +#define PROFILE_SET_DAMPING(x) +#define PROFILE_GET_DAMPING() 0.0f +#define PROFILE_OUTPUT(x) +#define PROFILE_OUTPUT_STREAM(x) +#define PROFILE_CLEAR() +#define PROFILE_GET_TREE_STRING() std::string() +#define PROFILE_GET_FLAT_STRING() std::string() +#define PROFILE_DESTROY() +#define PROFILE_BEGIN(name) +#define PROFILE_BLOCK(name) +#define PROFILE_FUNC() +#define PROFILE_CODE(code) do { code; } while (0) +#define PROFILE_SHARED_GLOBAL(name) +#define PROFILE_SHARED_MEMBER(name) +#define PROFILE_SHARED_DEFINE(name) +#define PROFILE_SHARED_BEGIN(name) +#define PROFILE_SHARED_BLOCK(name) +#define PROFILE_GET_SHARED_DATA(name) ShinyGetEmptyData() +#define PROFILE_GET_ROOT_DATA() ShinyGetEmptyData() + +#if SHINY_HAS_ENABLED == TRUE +#define PROFILE_SET_ENABLED(boolean) +#endif + +#endif /* SHINY_IS_COMPILED */ + +#endif /* SHINY_MACROS_H */ diff --git a/xs/src/Shiny/ShinyManager.c b/xs/src/Shiny/ShinyManager.c new file mode 100644 index 000000000..ec06f461f --- /dev/null +++ b/xs/src/Shiny/ShinyManager.c @@ -0,0 +1,446 @@ +/* +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. +*/ + +#include "ShinyManager.h" + +#include +#include +#include +#include + +#if SHINY_IS_COMPILED == TRUE + + +/*---------------------------------------------------------------------------*/ + +#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 = */ "", + /* data = */ { { 0, 0 }, { 0, 0 }, { 0, 0 } } + }, + /* damping = */ 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(&a_pParent) + *reinterpret_cast(&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 /* if SHINY_IS_COMPILED == TRUE */ diff --git a/xs/src/Shiny/ShinyManager.h b/xs/src/Shiny/ShinyManager.h new file mode 100644 index 000000000..11af2c082 --- /dev/null +++ b/xs/src/Shiny/ShinyManager.h @@ -0,0 +1,267 @@ +/* +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. +*/ + +#ifndef SHINY_MANAGER_H +#define SHINY_MANAGER_H + +#include "ShinyZone.h" +#include "ShinyNode.h" +#include "ShinyNodePool.h" +#include "ShinyTools.h" +#include "ShinyOutput.h" + +#include + +#ifdef SHINY_IS_COMPILED + +#ifdef __cplusplus +extern "C" { +#endif + +/*---------------------------------------------------------------------------*/ + +typedef struct { +#ifdef SHINY_HAS_ENABLED + bool enabled; +#endif + + shinytick_t _lastTick; + + ShinyNode* _curNode; + + uint32_t _tableMask; /* = _tableSize - 1 */ + + ShinyNodeTable* _nodeTable; + +#ifdef SHINY_LOOKUP_RATE + uint64_t _lookupCount; + uint64_t _lookupSuccessCount; +#endif + + uint32_t _tableSize; + + uint32_t nodeCount; + uint32_t zoneCount; + + ShinyZone* _lastZone; + + ShinyNodePool* _lastNodePool; + ShinyNodePool* _firstNodePool; + + ShinyNode rootNode; + ShinyZone rootZone; + + float damping; + + int _initialized; + int _firstUpdate; +} ShinyManager; + + +/*---------------------------------------------------------------------------*/ + +extern ShinyNode* _ShinyManager_dummyNodeTable[]; + +extern ShinyManager Shiny_instance; + + +/*---------------------------------------------------------------------------*/ + +SHINY_INLINE void _ShinyManager_appendTicksToCurNode(ShinyManager *self) { + shinytick_t curTick; + ShinyGetTicks(&curTick); + + ShinyNode_appendTicks(self->_curNode, curTick - self->_lastTick); + self->_lastTick = curTick; +} + +SHINY_API ShinyNode* _ShinyManager_lookupNode(ShinyManager *self, ShinyNodeCache* a_cache, ShinyZone* a_zone); + +SHINY_API void _ShinyManager_createNodeTable(ShinyManager *self, uint32_t a_count); +SHINY_API void _ShinyManager_resizeNodeTable(ShinyManager *self, uint32_t a_count); + +SHINY_API void _ShinyManager_createNodePool(ShinyManager *self, uint32_t a_count); +SHINY_API void _ShinyManager_resizeNodePool(ShinyManager *self, uint32_t a_count); + +SHINY_API ShinyNode* _ShinyManager_createNode(ShinyManager *self, ShinyNodeCache* a_cache, ShinyZone* a_pZone); +SHINY_API void _ShinyManager_insertNode(ShinyManager *self, ShinyNode* a_pNode); + +SHINY_INLINE void _ShinyManager_init(ShinyManager *self) { + self->_initialized = TRUE; + + self->rootNode._last.entryCount = 1; + self->rootNode._last.selfTicks = 0; + ShinyGetTicks(&self->_lastTick); +} + +SHINY_INLINE void _ShinyManager_uninit(ShinyManager *self) { + self->_initialized = FALSE; + + ShinyNode_clear(&self->rootNode); + self->rootNode.parent = &self->rootNode; + self->rootNode.zone = &self->rootZone; +} + +#ifdef SHINY_LOOKUP_RATE +SHINY_INLINE void _ShinyManager_incLookup(ShinyManager *self) { self->_lookupCount++; } +SHINY_INLINE void _ShinyManager_incLookupSuccess(ShinyManager *self) { self->_lookupSuccessCount++; } +SHINY_INLINE float ShinyManager_lookupRate(const ShinyManager *self) { return ((float) self->_lookupSuccessCount) / ((float) self->_lookupCount); } + +#else +SHINY_INLINE void _ShinyManager_incLookup(ShinyManager * self) { self = self; } +SHINY_INLINE void _ShinyManager_incLookupSuccess(ShinyManager * self) { self = self; } +SHINY_INLINE float ShinyManager_lookupRate(const ShinyManager * self) { self = self; return -1; } +#endif + +SHINY_API void ShinyManager_resetZones(ShinyManager *self); +SHINY_API void ShinyManager_destroyNodes(ShinyManager *self); + +SHINY_INLINE float ShinyManager_tableUsage(const ShinyManager *self) { + return ((float) self->nodeCount) / ((float) self->_tableSize); +} + +SHINY_INLINE uint32_t ShinyManager_allocMemInBytes(const ShinyManager *self) { + return self->_tableSize * sizeof(ShinyNode*) + + (self->_firstNodePool)? ShinyNodePool_memoryUsageChain(self->_firstNodePool) : 0; +} + +SHINY_INLINE void ShinyManager_beginNode(ShinyManager *self, ShinyNode* a_node) { + ShinyNode_beginEntry(a_node); + + _ShinyManager_appendTicksToCurNode(self); + self->_curNode = a_node; +} + +SHINY_INLINE void ShinyManager_lookupAndBeginNode(ShinyManager *self, ShinyNodeCache* a_cache, ShinyZone* a_zone) { +#ifdef SHINY_HAS_ENABLED + if (!self->enabled) return; +#endif + + if (self->_curNode != (*a_cache)->parent) + *a_cache = _ShinyManager_lookupNode(self, a_cache, a_zone); + + ShinyManager_beginNode(self, *a_cache); +} + +SHINY_INLINE void ShinyManager_endCurNode(ShinyManager *self) { +#ifdef SHINY_HAS_ENABLED + if (!self->enabled) return; +#endif + + _ShinyManager_appendTicksToCurNode(self); + self->_curNode = self->_curNode->parent; +} + +/**/ + +SHINY_API void ShinyManager_preLoad(ShinyManager *self); + +SHINY_API void ShinyManager_updateClean(ShinyManager *self); +SHINY_API void ShinyManager_update(ShinyManager *self); + +SHINY_API void ShinyManager_clear(ShinyManager *self); +SHINY_API void ShinyManager_destroy(ShinyManager *self); + +SHINY_INLINE void ShinyManager_sortZones(ShinyManager *self) { + if (self->rootZone.next) + self->_lastZone = ShinyZone_sortChain(&self->rootZone.next); +} + +SHINY_API const char* ShinyManager_getOutputErrorString(ShinyManager *self); + +SHINY_API int ShinyManager_output(ShinyManager *self, const char *a_filename); +SHINY_API void ShinyManager_outputToStream(ShinyManager *self, FILE *stream); + +#if __cplusplus +} /* end of extern "C" */ + +SHINY_INLINE std::string ShinyManager_outputTreeToString(ShinyManager *self) { + const char* error = ShinyManager_getOutputErrorString(self); + if (error) return error; + else return ShinyNodesToString(&self->rootNode, self->nodeCount); +} + +SHINY_INLINE std::string ShinyManager_outputFlatToString(ShinyManager *self) { + const char* error = ShinyManager_getOutputErrorString(self); + if (error) return error; + + ShinyManager_sortZones(self); + return ShinyZonesToString(&self->rootZone, self->zoneCount); +} + +extern "C" { /* end of c++ */ +#endif + +SHINY_INLINE int ShinyManager_isZoneSelfTimeBelow(ShinyManager *self, ShinyZone* a_zone, float a_percentage) { + return a_percentage * (float) self->rootZone.data.childTicks.cur + <= (float) a_zone->data.selfTicks.cur; +} + +SHINY_INLINE int ShinyManager_isZoneTotalTimeBelow(ShinyManager *self, ShinyZone* a_zone, float a_percentage) { + return a_percentage * (float) self->rootZone.data.childTicks.cur + <= (float) ShinyData_totalTicksCur(&a_zone->data); +} + +/**/ + +SHINY_INLINE void ShinyManager_enumerateNodes(ShinyManager *self, void (*a_func)(const ShinyNode*)) { + ShinyNode_enumerateNodes(&self->rootNode, a_func); +} + +SHINY_INLINE void ShinyManager_enumerateZones(ShinyManager *self, void (*a_func)(const ShinyZone*)) { + ShinyZone_enumerateZones(&self->rootZone, a_func); +} + +#if __cplusplus +} /* end of extern "C" */ + +template void ShinyManager_enumerateNodes(ShinyManager *self, T* a_this, void (T::*a_func)(const ShinyNode*)) { + ShinyNode_enumerateNodes(&self->rootNode, a_this, a_func); +} + +template void ShinyManager_enumerateZones(ShinyManager *self, T* a_this, void (T::*a_func)(const ShinyZone*)) { + ShinyZone_enumerateZones(&self->rootZone, a_this, a_func); +} + +extern "C" { /* end of c++ */ +#endif + + +/*---------------------------------------------------------------------------*/ + +#if __cplusplus +} /* end of extern "C" */ + +class ShinyEndNodeOnDestruction { +public: + + SHINY_INLINE ~ShinyEndNodeOnDestruction() { + ShinyManager_endCurNode(&Shiny_instance); + } +}; +#endif + +#endif /* if SHINY_IS_COMPILED == TRUE */ + +#endif /* SHINY_MANAGER_H */ diff --git a/xs/src/Shiny/ShinyNode.c b/xs/src/Shiny/ShinyNode.c new file mode 100644 index 000000000..8c6a67bd4 --- /dev/null +++ b/xs/src/Shiny/ShinyNode.c @@ -0,0 +1,130 @@ +/* +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. +*/ + +#include "ShinyNode.h" +#include "ShinyZone.h" +#include "ShinyNodeState.h" + +#include + + +#if SHINY_IS_COMPILED == TRUE + +/*---------------------------------------------------------------------------*/ + +ShinyNode _ShinyNode_dummy = { + /* _last = */ { 0, 0 }, + /* zone = */ NULL, + /* parent = */ NULL, + /* nextSibling = */ NULL, + /* firstChild = */ NULL, + /* lastChild = */ NULL +}; + + +/*---------------------------------------------------------------------------*/ + +void ShinyNode_updateTree(ShinyNode* first, float a_damping) { + ShinyNodeState *top = NULL; + ShinyNode *node = first; + + for (;;) { + do { + top = ShinyNodeState_push(top, node); + node = node->firstChild; + } while (node); + + for (;;) { + node = ShinyNodeState_finishAndGetNext(top, a_damping); + top = ShinyNodeState_pop(top); + + if (node) break; + else if (!top) return; + } + } +} + + +/*---------------------------------------------------------------------------*/ + +void ShinyNode_updateTreeClean(ShinyNode* first) { + ShinyNodeState *top = NULL; + ShinyNode *node = first; + + for (;;) { + do { + top = ShinyNodeState_push(top, node); + node = node->firstChild; + } while (node); + + for (;;) { + node = ShinyNodeState_finishAndGetNextClean(top); + top = ShinyNodeState_pop(top); + + if (node) break; + else if (!top) return; + } + } +} + + +/*---------------------------------------------------------------------------*/ + +const ShinyNode* ShinyNode_findNextInTree(const ShinyNode* self) { + if (self->firstChild) { + return self->firstChild; + + } else if (self->nextSibling) { + return self->nextSibling; + + } else { + ShinyNode* pParent = self->parent; + + while (!ShinyNode_isRoot(pParent)) { + if (pParent->nextSibling) return pParent->nextSibling; + else pParent = pParent->parent; + } + + return NULL; + } +} + + +/*---------------------------------------------------------------------------*/ + +void ShinyNode_clear(ShinyNode* self) { + memset(self, 0, sizeof(ShinyNode)); +} + + +/*---------------------------------------------------------------------------*/ + +void ShinyNode_enumerateNodes(const ShinyNode* a_node, void (*a_func)(const ShinyNode*)) { + a_func(a_node); + + if (a_node->firstChild) ShinyNode_enumerateNodes(a_node->firstChild, a_func); + if (a_node->nextSibling) ShinyNode_enumerateNodes(a_node->nextSibling, a_func); +} + +#endif diff --git a/xs/src/Shiny/ShinyNode.h b/xs/src/Shiny/ShinyNode.h new file mode 100644 index 000000000..abbcc9a1e --- /dev/null +++ b/xs/src/Shiny/ShinyNode.h @@ -0,0 +1,137 @@ +/* +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. +*/ + +#ifndef SHINY_NODE_H +#define SHINY_NODE_H + +#include "ShinyData.h" +#include "ShinyTools.h" + +#ifdef SHINY_IS_COMPILED + +#ifdef __cplusplus +extern "C" { +#endif + +/*---------------------------------------------------------------------------*/ + +typedef struct _ShinyNode { + + ShinyLastData _last; + + struct _ShinyZone* zone; + struct _ShinyNode* parent; + struct _ShinyNode* nextSibling; + + struct _ShinyNode* firstChild; + struct _ShinyNode* lastChild; + + uint32_t childCount; + uint32_t entryLevel; + + ShinyNodeCache* _cache; + + ShinyData data; + +} ShinyNode; + + +/*---------------------------------------------------------------------------*/ + +extern ShinyNode _ShinyNode_dummy; + + +/*---------------------------------------------------------------------------*/ + +SHINY_INLINE void ShinyNode_addChild(ShinyNode* self, ShinyNode* a_child) { + if (self->childCount++) { + self->lastChild->nextSibling = a_child; + self->lastChild = a_child; + + } else { + self->lastChild = a_child; + self->firstChild = a_child; + } +} + +SHINY_INLINE void ShinyNode_init(ShinyNode* self, ShinyNode* a_parent, struct _ShinyZone* a_zone, ShinyNodeCache* a_cache) { + /* NOTE: all member variables are assumed to be zero when allocated */ + + self->zone = a_zone; + self->parent = a_parent; + + self->entryLevel = a_parent->entryLevel + 1; + ShinyNode_addChild(a_parent, self); + + self->_cache = a_cache; +} + +SHINY_API void ShinyNode_updateTree(ShinyNode* self, float a_damping); +SHINY_API void ShinyNode_updateTreeClean(ShinyNode* self); + +SHINY_INLINE void ShinyNode_destroy(ShinyNode* self) { + *(self->_cache) = &_ShinyNode_dummy; +} + +SHINY_INLINE void ShinyNode_appendTicks(ShinyNode* self, shinytick_t a_elapsedTicks) { + self->_last.selfTicks += a_elapsedTicks; +} + +SHINY_INLINE void ShinyNode_beginEntry(ShinyNode* self) { + self->_last.entryCount++; +} + +SHINY_INLINE int ShinyNode_isRoot(ShinyNode* self) { + return (self->entryLevel == 0); +} + +SHINY_INLINE int ShinyNode_isDummy(ShinyNode* self) { + return (self == &_ShinyNode_dummy); +} + +SHINY_INLINE int ShinyNode_isEqual(ShinyNode* self, const ShinyNode* a_parent, const struct _ShinyZone* a_zone) { + return (self->parent == a_parent && self->zone == a_zone); +} + +SHINY_API const ShinyNode* ShinyNode_findNextInTree(const ShinyNode* self); + +SHINY_API void ShinyNode_clear(ShinyNode* self); + +SHINY_API void ShinyNode_enumerateNodes(const ShinyNode* a_node, void (*a_func)(const ShinyNode*)); + +#if __cplusplus +} /* end of extern "C" */ + +template +void ShinyNode_enumerateNodes(const ShinyNode* a_node, T* a_this, void (T::*a_func)(const ShinyNode*)) { + (a_this->*a_func)(a_node); + + if (a_node->firstChild) ShinyNode_enumerateNodes(a_node->firstChild, a_this, a_func); + if (a_node->nextSibling) ShinyNode_enumerateNodes(a_node->nextSibling, a_this, a_func); +} +#endif /* __cplusplus */ + +#endif /* if SHINY_IS_COMPILED == TRUE */ + +#endif /* SHINY_NODE_H */ diff --git a/xs/src/Shiny/ShinyNodePool.c b/xs/src/Shiny/ShinyNodePool.c new file mode 100644 index 000000000..a574e3dd6 --- /dev/null +++ b/xs/src/Shiny/ShinyNodePool.c @@ -0,0 +1,78 @@ +/* +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. +*/ + +#include "ShinyNodePool.h" +#include "ShinyTools.h" + +#include +#include + +#if SHINY_IS_COMPILED == TRUE + + +/*---------------------------------------------------------------------------*/ + +ShinyNodePool* ShinyNodePool_create(uint32_t a_items) { + ShinyNodePool* pPool = (ShinyNodePool*) + malloc(sizeof(ShinyNodePool) + sizeof(ShinyNode) * (a_items - 1)); + + pPool->nextPool = NULL; + pPool->_nextItem = &pPool->_items[0]; + pPool->endOfItems = &pPool->_items[a_items]; + + memset(&pPool->_items[0], 0, a_items * sizeof(ShinyNode)); + return pPool; +} + + +/*---------------------------------------------------------------------------*/ + +uint32_t ShinyNodePool_memoryUsageChain(ShinyNodePool *first) { + uint32_t bytes = (uint32_t) ((char*) first->endOfItems - (char*) first); + ShinyNodePool *pool = first->nextPool; + + while (pool) { + bytes += (uint32_t) ((char*) pool->endOfItems - (char*) pool); + pool = pool->nextPool; + } + + return bytes; +} + + +/*---------------------------------------------------------------------------*/ + +void ShinyNodePool_destroy(ShinyNodePool *self) { + ShinyNode* firstNode = ShinyNodePool_firstItem(self); + ShinyNode* lastNode = self->_nextItem; + + while (firstNode != lastNode) + ShinyNode_destroy(firstNode++); + + /* TODO: make this into a loop or a tail recursion */ + if (self->nextPool) ShinyNodePool_destroy(self->nextPool); + free(self); +} + +#endif diff --git a/xs/src/Shiny/ShinyNodePool.h b/xs/src/Shiny/ShinyNodePool.h new file mode 100644 index 000000000..fb6db0920 --- /dev/null +++ b/xs/src/Shiny/ShinyNodePool.h @@ -0,0 +1,72 @@ +/* +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. +*/ + +#ifndef SHINY_NODE_POOL_H +#define SHINY_NODE_POOL_H + +#include "ShinyNode.h" + +#ifdef SHINY_IS_COMPILED + +#ifdef __cplusplus +extern "C" { +#endif + +/*---------------------------------------------------------------------------*/ + +typedef struct _ShinyNodePool { + + struct _ShinyNodePool* nextPool; + + ShinyNode *_nextItem; + ShinyNode *endOfItems; + + ShinyNode _items[1]; + +} ShinyNodePool; + + +/*---------------------------------------------------------------------------*/ + +SHINY_INLINE ShinyNode* ShinyNodePool_firstItem(ShinyNodePool *self) { + return &(self->_items[0]); +} + +SHINY_INLINE ShinyNode* ShinyNodePool_newItem(ShinyNodePool *self) { + return self->_nextItem++; +} + +ShinyNodePool* ShinyNodePool_create(uint32_t a_items); +void ShinyNodePool_destroy(ShinyNodePool *self); + +uint32_t ShinyNodePool_memoryUsageChain(ShinyNodePool *first); + +#if __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* if SHINY_IS_COMPILED == TRUE */ + + +#endif /* SHINY_NODE_POOL_H */ diff --git a/xs/src/Shiny/ShinyNodeState.c b/xs/src/Shiny/ShinyNodeState.c new file mode 100644 index 000000000..b293636d0 --- /dev/null +++ b/xs/src/Shiny/ShinyNodeState.c @@ -0,0 +1,109 @@ +/* +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. +*/ + +#include "ShinyNodeState.h" +#include "ShinyNode.h" +#include "ShinyZone.h" + +#include + + +#if SHINY_IS_COMPILED == TRUE + +/*---------------------------------------------------------------------------*/ + +ShinyNodeState* ShinyNodeState_push(ShinyNodeState *a_top, ShinyNode *a_node) { + ShinyZone *zone = a_node->zone; + ShinyNodeState *self = (ShinyNodeState*) malloc(sizeof(ShinyNodeState)); + self->node = a_node; + self->_prev = a_top; + + a_node->data.selfTicks.cur = a_node->_last.selfTicks; + a_node->data.entryCount.cur = a_node->_last.entryCount; + + zone->data.selfTicks.cur += a_node->_last.selfTicks; + zone->data.entryCount.cur += a_node->_last.entryCount; + + a_node->data.childTicks.cur = 0; + a_node->_last.selfTicks = 0; + a_node->_last.entryCount = 0; + + self->zoneUpdating = zone->_state != SHINY_ZONE_STATE_UPDATING; + if (self->zoneUpdating) { + zone->_state = SHINY_ZONE_STATE_UPDATING; + } else { + zone->data.childTicks.cur -= a_node->data.selfTicks.cur; + } + + return self; +} + +/*---------------------------------------------------------------------------*/ + +ShinyNodeState* ShinyNodeState_pop(ShinyNodeState *a_top) { + ShinyNodeState *prev = a_top->_prev; + free(a_top); + return prev; +} + +/*---------------------------------------------------------------------------*/ + +ShinyNode* ShinyNodeState_finishAndGetNext(ShinyNodeState *self, float a_damping) { + ShinyNode *node = self->node; + ShinyZone *zone = node->zone; + + if (self->zoneUpdating) { + zone->data.childTicks.cur += node->data.childTicks.cur; + zone->_state = SHINY_ZONE_STATE_INITIALIZED; + } + + ShinyData_computeAverage(&node->data, a_damping); + + if (!ShinyNode_isRoot(node)) + node->parent->data.childTicks.cur += node->data.selfTicks.cur + node->data.childTicks.cur; + + return node->nextSibling; +} + + +/*---------------------------------------------------------------------------*/ + +ShinyNode* ShinyNodeState_finishAndGetNextClean(ShinyNodeState *self) { + ShinyNode *node = self->node; + ShinyZone *zone = node->zone; + + if (self->zoneUpdating) { + zone->data.childTicks.cur += node->data.childTicks.cur; + zone->_state = SHINY_ZONE_STATE_INITIALIZED; + } + + ShinyData_copyAverage(&node->data); + + if (!ShinyNode_isRoot(node)) + node->parent->data.childTicks.cur += node->data.selfTicks.cur + node->data.childTicks.cur; + + return node->nextSibling; +} + +#endif diff --git a/xs/src/Shiny/ShinyNodeState.h b/xs/src/Shiny/ShinyNodeState.h new file mode 100644 index 000000000..bbd156307 --- /dev/null +++ b/xs/src/Shiny/ShinyNodeState.h @@ -0,0 +1,60 @@ +/* +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. +*/ + +#ifndef SHINY_NODE_STATE_H +#define SHINY_NODE_STATE_H + +#include "ShinyNode.h" + +#if SHINY_IS_COMPILED == TRUE + +#ifdef __cplusplus +extern "C" { +#endif + +/*---------------------------------------------------------------------------*/ + +typedef struct _ShinyNodeState { + ShinyNode *node; + int zoneUpdating; + + struct _ShinyNodeState *_prev; +} ShinyNodeState; + + +/*---------------------------------------------------------------------------*/ + +ShinyNodeState* ShinyNodeState_push(ShinyNodeState *a_top, ShinyNode *a_node); +ShinyNodeState* ShinyNodeState_pop(ShinyNodeState *a_top); + +ShinyNode* ShinyNodeState_finishAndGetNext(ShinyNodeState *self, float a_damping); +ShinyNode* ShinyNodeState_finishAndGetNextClean(ShinyNodeState *self); + +#if __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* if SHINY_IS_COMPILED == TRUE */ + +#endif /* SHINY_NODE_STATE_H */ diff --git a/xs/src/Shiny/ShinyOutput.c b/xs/src/Shiny/ShinyOutput.c new file mode 100644 index 000000000..f3de582ee --- /dev/null +++ b/xs/src/Shiny/ShinyOutput.c @@ -0,0 +1,190 @@ +/* +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. +*/ + +#include "ShinyOutput.h" + +#include + +#if SHINY_COMPILER == SHINY_COMPILER_MSVC +# pragma warning(disable: 4996) +# define snprintf _snprintf +# define TRAILING 0 + +#else +# define TRAILING 1 +#endif + +#if SHINY_IS_COMPILED == TRUE + + +/*---------------------------------------------------------------------------*/ + +#define OUTPUT_WIDTH_CALL 6 +#define OUTPUT_WIDTH_TIME 6 +#define OUTPUT_WIDTH_PERC 4 +#define OUTPUT_WIDTH_SUM 79 + +#define OUTPUT_WIDTH_DATA (1+OUTPUT_WIDTH_CALL + 1 + 2*(OUTPUT_WIDTH_TIME+4+OUTPUT_WIDTH_PERC+1) + 1) +#define OUTPUT_WIDTH_NAME (OUTPUT_WIDTH_SUM - OUTPUT_WIDTH_DATA) + + +/*---------------------------------------------------------------------------*/ + +SHINY_INLINE char* printHeader(char *output, const char *a_title) { + snprintf(output, OUTPUT_WIDTH_SUM + TRAILING, + "%-*s %*s %*s %*s", + OUTPUT_WIDTH_NAME, a_title, + OUTPUT_WIDTH_CALL, "calls", + OUTPUT_WIDTH_TIME+4+OUTPUT_WIDTH_PERC+1, "self time", + OUTPUT_WIDTH_TIME+4+OUTPUT_WIDTH_PERC+1, "total time"); + + return output + OUTPUT_WIDTH_SUM; +} + + +/*---------------------------------------------------------------------------*/ + +SHINY_INLINE char* printData(char *output, const ShinyData *a_data, float a_topercent) { + float totalTicksAvg = ShinyData_totalTicksAvg(a_data); + const ShinyTimeUnit *selfUnit = ShinyGetTimeUnit(a_data->selfTicks.avg); + const ShinyTimeUnit *totalUnit = ShinyGetTimeUnit(totalTicksAvg); + + snprintf(output, OUTPUT_WIDTH_DATA + TRAILING, + " %*.1f %*.0f %-2s %*.0f%% %*.0f %-2s %*.0f%%", + OUTPUT_WIDTH_CALL, a_data->entryCount.avg, + OUTPUT_WIDTH_TIME, a_data->selfTicks.avg * selfUnit->invTickFreq, selfUnit->suffix, + OUTPUT_WIDTH_PERC, a_data->selfTicks.avg * a_topercent, + OUTPUT_WIDTH_TIME, totalTicksAvg * totalUnit->invTickFreq, totalUnit->suffix, + OUTPUT_WIDTH_PERC, totalTicksAvg * a_topercent); + + return output + OUTPUT_WIDTH_DATA; +} + + +/*---------------------------------------------------------------------------*/ + +SHINY_INLINE char* printNode(char* output, const ShinyNode *a_node, float a_topercent) { + int offset = a_node->entryLevel * 2; + + snprintf(output, OUTPUT_WIDTH_NAME + TRAILING, "%*s%-*s", + offset, "", OUTPUT_WIDTH_NAME - offset, a_node->zone->name); + + output += OUTPUT_WIDTH_NAME; + + output = printData(output, &a_node->data, a_topercent); + return output; +} + + +/*---------------------------------------------------------------------------*/ + +SHINY_INLINE char* printZone(char* output, const ShinyZone *a_zone, float a_topercent) { + snprintf(output, OUTPUT_WIDTH_NAME + TRAILING, "%-*s", + OUTPUT_WIDTH_NAME, a_zone->name); + + output += OUTPUT_WIDTH_NAME; + + output = printData(output, &a_zone->data, a_topercent); + return output; +} + + +/*---------------------------------------------------------------------------*/ + +int ShinyPrintNodesSize(uint32_t a_count) { + return (1 + a_count) * (OUTPUT_WIDTH_SUM + 1); +} + + +/*---------------------------------------------------------------------------*/ + +int ShinyPrintZonesSize(uint32_t a_count) { + return (1 + a_count) * (OUTPUT_WIDTH_SUM + 1); +} + + +/*---------------------------------------------------------------------------*/ + +void ShinyPrintANode(char* output, const ShinyNode *a_node, const ShinyNode *a_root) { + float fTicksToPc = 100.0f / a_root->data.childTicks.avg; + output = printNode(output, a_node, fTicksToPc); + (*output++) = '\0'; +} + + +/*---------------------------------------------------------------------------*/ + +void ShinyPrintAZone(char* output, const ShinyZone *a_zone, const ShinyZone *a_root) { + float fTicksToPc = 100.0f / a_root->data.childTicks.avg; + output = printZone(output, a_zone, fTicksToPc); + (*output++) = '\0'; +} + + +/*---------------------------------------------------------------------------*/ + +void ShinyPrintNodes(char* output, const ShinyNode *a_root) { + float fTicksToPc = 100.0f / a_root->data.childTicks.avg; + const ShinyNode *node = a_root; + + output = printHeader(output, "call tree"); + (*output++) = '\n'; + + for (;;) { + output = printNode(output, node, fTicksToPc); + + node = ShinyNode_findNextInTree(node); + if (node) { + (*output++) = '\n'; + } else { + (*output++) = '\0'; + return; + } + } +} + + +/*---------------------------------------------------------------------------*/ + +void ShinyPrintZones(char* output, const ShinyZone *a_root) { + float fTicksToPc = 100.0f / a_root->data.childTicks.avg; + const ShinyZone *zone = a_root; + + output = printHeader(output, "sorted list"); + (*output++) = '\n'; + + for (;;) { + output = printZone(output, zone, fTicksToPc); + + zone = zone->next; + if (zone) { + (*output++) = '\n'; + } else { + (*output++) = '\0'; + return; + } + } +} + +#endif diff --git a/xs/src/Shiny/ShinyOutput.h b/xs/src/Shiny/ShinyOutput.h new file mode 100644 index 000000000..96007138e --- /dev/null +++ b/xs/src/Shiny/ShinyOutput.h @@ -0,0 +1,72 @@ +/* +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. +*/ + +#ifndef SHINY_OUTPUT_H +#define SHINY_OUTPUT_H + +#include "ShinyNode.h" +#include "ShinyZone.h" + +#ifdef SHINY_IS_COMPILED + +#ifdef __cplusplus +extern "C" { +#endif + +/*---------------------------------------------------------------------------*/ + +SHINY_API int ShinyPrintNodesSize(uint32_t a_count); +SHINY_API int ShinyPrintZonesSize(uint32_t a_count); + +SHINY_API void ShinyPrintANode(char* output, const ShinyNode *a_node, const ShinyNode *a_root); +SHINY_API void ShinyPrintAZone(char* output, const ShinyZone *a_zone, const ShinyZone *a_root); + +SHINY_API void ShinyPrintNodes(char* output, const ShinyNode *a_root); +SHINY_API void ShinyPrintZones(char* output, const ShinyZone *a_root); + + +/*---------------------------------------------------------------------------*/ + +#if __cplusplus +} /* end of extern "C" */ +#include + +SHINY_INLINE std::string ShinyNodesToString(const ShinyNode *a_root, uint32_t a_count) { + std::string str; + str.resize(ShinyPrintNodesSize(a_count) - 1); + ShinyPrintNodes(&str[0], a_root); + return str; +} + +SHINY_INLINE std::string ShinyZonesToString(const ShinyZone *a_root, uint32_t a_count) { + std::string str; + str.resize(ShinyPrintZonesSize(a_count) - 1); + ShinyPrintZones(&str[0], a_root); + return str; +} +#endif /* __cplusplus */ + +#endif /* if SHINY_IS_COMPILED == TRUE */ + +#endif /* SHINY_OUTPUT_H */ diff --git a/xs/src/Shiny/ShinyPrereqs.h b/xs/src/Shiny/ShinyPrereqs.h new file mode 100644 index 000000000..9f52d0d34 --- /dev/null +++ b/xs/src/Shiny/ShinyPrereqs.h @@ -0,0 +1,149 @@ +/* +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. +*/ + +#ifndef SHINY_PREREQS_H +#define SHINY_PREREQS_H + +#include "ShinyConfig.h" +#include "ShinyVersion.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*---------------------------------------------------------------------------*/ + +#define SHINY_PLATFORM_WIN32 0x1 +#define SHINY_PLATFORM_POSIX 0x2 + +#if defined (_WIN32) +# define SHINY_PLATFORM SHINY_PLATFORM_WIN32 + +#else /* ASSUME: POSIX-compliant OS */ +# define SHINY_PLATFORM SHINY_PLATFORM_POSIX +#endif + + +/*---------------------------------------------------------------------------*/ + +#define SHINY_COMPILER_MSVC 0x1 +#define SHINY_COMPILER_GNUC 0x2 +#define SHINY_COMPILER_OTHER 0x3 + +#if defined (_MSC_VER) +# define SHINY_COMPILER SHINY_COMPILER_MSVC + +#elif defined (__GNUG__) +# define SHINY_COMPILER SHINY_COMPILER_GNUC + +#else +# define SHINY_COMPILER SHINY_COMPILER_OTHER +#endif + + +/*---------------------------------------------------------------------------*/ + +#ifndef FALSE +#define FALSE 0x0 +#endif + +#ifndef TRUE +#define TRUE 0x1 +#endif + +#ifndef NULL +#define NULL 0 +#endif + + +/*---------------------------------------------------------------------------*/ + +#if SHINY_COMPILER == SHINY_COMPILER_GNUC +#include +#include +#endif + + +/*---------------------------------------------------------------------------*/ + +#ifdef SHINY_IS_COMPILED + struct _ShinyNode; + struct _ShinyZone; + + typedef struct _ShinyNode* ShinyNodeCache; + typedef struct _ShinyNode* ShinyNodeTable; +#endif + + +/*---------------------------------------------------------------------------*/ + +#ifdef SHINY_STATIC_LINK +# define SHINY_API +#else +# define SHINY_API SHINY_EXPORT +#endif + + +/*---------------------------------------------------------------------------*/ + +#if SHINY_COMPILER == SHINY_COMPILER_MSVC +# define SHINY_INLINE __inline +# define SHINY_UNUSED +# define SHINY_EXPORT __declspec(dllexport) + +#elif SHINY_COMPILER == SHINY_COMPILER_GNUC +# define SHINY_INLINE inline +# define SHINY_UNUSED __attribute__((unused)) +# define SHINY_EXPORT __attribute__((dllexport)) + +#elif SHINY_COMPILER == SHINY_COMPILER_OTHER +# define SHINY_INLINE inline +# define SHINY_UNUSED +# define SHINY_EXPORT extern +#endif + + +/*---------------------------------------------------------------------------*/ + +#if SHINY_COMPILER == SHINY_COMPILER_MSVC + typedef int int32_t; + typedef unsigned int uint32_t; + + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; + +/* +#elif defined(__CYGWIN__) + typedef u_int32_t uint32_t; + typedef u_int64_t uint64_t; +*/ +#endif + + typedef uint64_t shinytick_t; + +#if __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* SHINY_PREREQS_H */ diff --git a/xs/src/Shiny/ShinyTools.c b/xs/src/Shiny/ShinyTools.c new file mode 100644 index 000000000..85e96e049 --- /dev/null +++ b/xs/src/Shiny/ShinyTools.c @@ -0,0 +1,109 @@ +/* +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. +*/ + +#include "ShinyTools.h" + +#if SHINY_PLATFORM == SHINY_PLATFORM_WIN32 +#define WIN32_LEAN_AND_MEAN +#ifndef NOMINMAX + #define NOMINMAX +#endif /* NOMINMAX */ +#include + +#elif SHINY_PLATFORM == SHINY_PLATFORM_POSIX +#include +#endif + + +/*---------------------------------------------------------------------------*/ + +const ShinyTimeUnit* ShinyGetTimeUnit(float ticks) { + static ShinyTimeUnit units[4] = { 0 }; + + if (units[0].tickFreq == 0) { /* auto initialize first time */ + units[0].tickFreq = ShinyGetTickFreq() / 1.0f; + units[0].invTickFreq = ShinyGetTickInvFreq() * 1.0f; + units[0].suffix = "s"; + + units[1].tickFreq = ShinyGetTickFreq() / 1000.0f; + units[1].invTickFreq = ShinyGetTickInvFreq() * 1000.0f; + units[1].suffix = "ms"; + + units[2].tickFreq = ShinyGetTickFreq() / 1000000.0f; + units[2].invTickFreq = ShinyGetTickInvFreq() * 1000000.0f; + units[2].suffix = "us"; + + units[3].tickFreq = ShinyGetTickFreq() / 1000000000.0f; + units[3].invTickFreq = ShinyGetTickInvFreq() * 1000000000.0f; + units[3].suffix = "ns"; + } + + if (units[0].tickFreq < ticks) return &units[0]; + else if (units[1].tickFreq < ticks) return &units[1]; + else if (units[2].tickFreq < ticks) return &units[2]; + else return &units[3]; +} + + +/*---------------------------------------------------------------------------*/ + +#if SHINY_PLATFORM == SHINY_PLATFORM_WIN32 + +void ShinyGetTicks(shinytick_t *p) { + QueryPerformanceCounter((LARGE_INTEGER*)(p)); +} + +shinytick_t ShinyGetTickFreq(void) { + static shinytick_t freq = 0; + if (freq == 0) QueryPerformanceFrequency((LARGE_INTEGER*)(&freq)); + return freq; +} + +float ShinyGetTickInvFreq(void) { + static float invfreq = 0; + if (invfreq == 0) invfreq = 1.0f / ShinyGetTickFreq(); + return invfreq; +} + + +/*---------------------------------------------------------------------------*/ + +#elif SHINY_PLATFORM == SHINY_PLATFORM_POSIX + +void ShinyGetTicks(shinytick_t *p) { + timeval time; + gettimeofday(&time, NULL); + + *p = time.tv_sec * 1000000 + time.tv_usec; +} + +const shinytick_t& ShinyGetTickFreq(void) { + return 1000000; +} + +float ShinyGetTickInvFreq(void) { + return 1.0f / 1000000.0f; +} + +#endif diff --git a/xs/src/Shiny/ShinyTools.h b/xs/src/Shiny/ShinyTools.h new file mode 100644 index 000000000..379703ee6 --- /dev/null +++ b/xs/src/Shiny/ShinyTools.h @@ -0,0 +1,57 @@ +/* +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. +*/ + +#ifndef SHINY_TOOLS_H +#define SHINY_TOOLS_H + +#include "ShinyPrereqs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*---------------------------------------------------------------------------*/ + +typedef struct { + float tickFreq; + float invTickFreq; + const char* suffix; +} ShinyTimeUnit; + + +/*---------------------------------------------------------------------------*/ + +SHINY_API const ShinyTimeUnit* ShinyGetTimeUnit(float ticks); + +SHINY_API void ShinyGetTicks(shinytick_t *p); + +SHINY_API shinytick_t ShinyGetTickFreq(void); + +SHINY_API float ShinyGetTickInvFreq(void); + +#if __cplusplus +} /* end of extern "C" */ +#endif + +#endif /* SHINY_TOOLS_H */ diff --git a/xs/src/Shiny/ShinyVersion.h b/xs/src/Shiny/ShinyVersion.h new file mode 100644 index 000000000..fe6cd4a33 --- /dev/null +++ b/xs/src/Shiny/ShinyVersion.h @@ -0,0 +1,37 @@ +/* +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. +*/ + +#ifndef SHINY_VERSION_H +#define SHINY_VERSION_H + + +/*---------------------------------------------------------------------------*/ + +#define SHINY_VERSION "2.6 RC1" +#define SHINY_SHORTNAME "Shiny" +#define SHINY_FULLNAME "Shiny Profiler" +#define SHINY_COPYRIGHT "Copyright (C) 2007-2010 Aidin Abedi" +#define SHINY_DESCRIPTION "Shiny is a state of the art profiler designed to help finding bottlenecks in your project." + +#endif /* SHINY_VERSION_H */ diff --git a/xs/src/Shiny/ShinyZone.c b/xs/src/Shiny/ShinyZone.c new file mode 100644 index 000000000..132fe56c0 --- /dev/null +++ b/xs/src/Shiny/ShinyZone.c @@ -0,0 +1,201 @@ +/* +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. +*/ + +#include "ShinyZone.h" + +#include + +#if SHINY_IS_COMPILED == TRUE + +/*---------------------------------------------------------------------------*/ + +void ShinyZone_preUpdateChain(ShinyZone *first) { + ShinyZone* zone = first; + + while (zone) { + ShinyData_clearCurrent(&(zone->data)); + zone = zone->next; + } +} + + +/*---------------------------------------------------------------------------*/ + +void ShinyZone_updateChain(ShinyZone *first, float a_damping) { + ShinyZone* zone = first; + + do { + ShinyData_computeAverage(&(zone->data), a_damping); + zone = zone->next; + } while (zone); +} + + +/*---------------------------------------------------------------------------*/ + +void ShinyZone_updateChainClean(ShinyZone *first) { + ShinyZone* zone = first; + + do { + ShinyData_copyAverage(&(zone->data)); + zone = zone->next; + } while (zone); +} + + +/*---------------------------------------------------------------------------*/ + +void ShinyZone_resetChain(ShinyZone *first) { + ShinyZone* zone = first, *temp; + + do { + zone->_state = SHINY_ZONE_STATE_HIDDEN; + temp = zone->next; + zone->next = NULL; + zone = temp; + } while (zone); +} + +/*---------------------------------------------------------------------------*/ + +/* A Linked-List Memory Sort + by Philip J. Erdelsky + pje@efgh.com + http://www.alumni.caltech.edu/~pje/ + + Modified by Aidin Abedi +*/ + +ShinyZone* ShinyZone_sortChain(ShinyZone **first) /* return ptr to last zone */ +{ + ShinyZone *p = *first; + + unsigned base; + unsigned long block_size; + + struct tape + { + ShinyZone *first, *last; + unsigned long count; + } tape[4]; + + /* Distribute the records alternately to tape[0] and tape[1]. */ + + tape[0].count = tape[1].count = 0L; + tape[0].first = NULL; + base = 0; + while (p != NULL) + { + ShinyZone *next = p->next; + p->next = tape[base].first; + tape[base].first = p; + tape[base].count++; + p = next; + base ^= 1; + } + + /* If the list is empty or contains only a single record, then */ + /* tape[1].count == 0L and this part is vacuous. */ + + for (base = 0, block_size = 1L; tape[base+1].count != 0L; + base ^= 2, block_size <<= 1) + { + int dest; + struct tape *tape0, *tape1; + tape0 = tape + base; + tape1 = tape + base + 1; + dest = base ^ 2; + tape[dest].count = tape[dest+1].count = 0; + for (; tape0->count != 0; dest ^= 1) + { + unsigned long n0, n1; + struct tape *output_tape = tape + dest; + n0 = n1 = block_size; + while (1) + { + ShinyZone *chosen_record; + struct tape *chosen_tape; + if (n0 == 0 || tape0->count == 0) + { + if (n1 == 0 || tape1->count == 0) + break; + chosen_tape = tape1; + n1--; + } + else if (n1 == 0 || tape1->count == 0) + { + chosen_tape = tape0; + n0--; + } + else if (ShinyZone_compare(tape1->first, tape0->first) > 0) + { + chosen_tape = tape1; + n1--; + } + else + { + chosen_tape = tape0; + n0--; + } + chosen_tape->count--; + chosen_record = chosen_tape->first; + chosen_tape->first = chosen_record->next; + if (output_tape->count == 0) + output_tape->first = chosen_record; + else + output_tape->last->next = chosen_record; + output_tape->last = chosen_record; + output_tape->count++; + } + } + } + + if (tape[base].count > 1L) { + ShinyZone* last = tape[base].last; + *first = tape[base].first; + last->next = NULL; + return last; + + } else { + return NULL; + } +} + + +/*---------------------------------------------------------------------------*/ + +void ShinyZone_clear(ShinyZone* self) { + memset(self, 0, sizeof(ShinyZone)); +} + + +/*---------------------------------------------------------------------------*/ + +void ShinyZone_enumerateZones(const ShinyZone* a_zone, void (*a_func)(const ShinyZone*)) { + a_func(a_zone); + + if (a_zone->next) ShinyZone_enumerateZones(a_zone->next, a_func); +} + +#endif diff --git a/xs/src/Shiny/ShinyZone.h b/xs/src/Shiny/ShinyZone.h new file mode 100644 index 000000000..2b6ac77b8 --- /dev/null +++ b/xs/src/Shiny/ShinyZone.h @@ -0,0 +1,95 @@ +/* +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. +*/ + +#ifndef SHINY_ZONE_H +#define SHINY_ZONE_H + +#include "ShinyData.h" +#include + +#ifdef SHINY_IS_COMPILED + +#ifdef __cplusplus +extern "C" { +#endif + +/*---------------------------------------------------------------------------*/ + +#define SHINY_ZONE_STATE_HIDDEN 0 +#define SHINY_ZONE_STATE_INITIALIZED 1 +#define SHINY_ZONE_STATE_UPDATING 2 + + +/*---------------------------------------------------------------------------*/ + +typedef struct _ShinyZone { + struct _ShinyZone* next; + int _state; + const char* name; + ShinyData data; +} ShinyZone; + + +/*---------------------------------------------------------------------------*/ + +SHINY_INLINE void ShinyZone_init(ShinyZone *self, ShinyZone* a_prev) { + self->_state = SHINY_ZONE_STATE_INITIALIZED; + a_prev->next = self; +} + +SHINY_INLINE void ShinyZone_uninit(ShinyZone *self) { + self->_state = SHINY_ZONE_STATE_HIDDEN; + self->next = NULL; +} + +SHINY_API void ShinyZone_preUpdateChain(ShinyZone *first); +SHINY_API void ShinyZone_updateChain(ShinyZone *first, float a_damping); +SHINY_API void ShinyZone_updateChainClean(ShinyZone *first); + +SHINY_API void ShinyZone_resetChain(ShinyZone *first); + +SHINY_API ShinyZone* ShinyZone_sortChain(ShinyZone **first); + +SHINY_INLINE float ShinyZone_compare(ShinyZone *a, ShinyZone *b) { + return a->data.selfTicks.avg - b->data.selfTicks.avg; +} + +SHINY_API void ShinyZone_clear(ShinyZone* self); + +SHINY_API void ShinyZone_enumerateZones(const ShinyZone* a_zone, void (*a_func)(const ShinyZone*)); + +#if __cplusplus +} /* end of extern "C" */ + +template +void ShinyZone_enumerateZones(const ShinyZone* a_zone, T* a_this, void (T::*a_func)(const ShinyZone*)) { + (a_this->*a_func)(a_zone); + + if (a_zone->next) ShinyZone_enumerateZones(a_zone->next, a_this, a_func); +} +#endif /* __cplusplus */ + +#endif /* if SHINY_IS_COMPILED == TRUE */ + +#endif /* SHINY_ZONE_H */