hostsupport/hostopenvg/src/src/sfFunctionCache.h
branchbug235_bringup_0
changeset 54 067180f57b12
parent 53 c2ef9095503a
child 55 09263774e342
--- a/hostsupport/hostopenvg/src/src/sfFunctionCache.h	Wed Oct 06 17:59:01 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,310 +0,0 @@
-/* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and /or associated documentation files
- * (the "Materials "), to deal in the Materials without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Materials,
- * and to permit persons to whom the Materials are 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 Materials.
- *
- * THE MATERIALS ARE 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 MATERIALS OR
- * THE USE OR OTHER DEALINGS IN THE MATERIALS.
- */
-
-#ifndef __SFFUNCTIONCACHE_H
-#define __SFFUNCTIONCACHE_H
-
-// (LRU) Cache for compiled pixelpipe functions. Never takes ownership of
-// any of the objects.
-// \todo LRU might not be the best strategy or the best strategy might
-// depend on the use-case -> create more of these.
-
-#include "riArray.h"
-
-#if defined(__unix__)
-#   include <pthread.h>
-#else
-#   include <windows.h>
-#endif
-
-#include "llvm/ExecutionEngine/ExecutionEngine.h"
-#include "llvm/Module.h"
-
-namespace llvm {
-    class Function;
-}
-
-namespace OpenVGRI {
-
-template<class HashClass> class FunctionCache 
-{
-private:
-    enum { IMPLEMENTATION_MAX_CACHE_ENTRIES = 1024 };
-    //enum { MAX_GLOBAL_TIME = 10000};
-    enum { MAX_GLOBAL_TIME = RI_UINT32_MAX };
-
-    struct CacheEntry 
-    {
-        CacheEntry() : refCount(1) {}
-        CacheEntry(HashClass aHash, ::llvm::Function* aFunc, ::llvm::GlobalVariable* aConst, RIuint32 theUT) : refCount(1) {hash = aHash; llvmFunction = aFunc; llvmConstant = aConst; ut = theUT;}
-        bool operator==(const CacheEntry& rhs) const { return hash == rhs.hash; }
-        bool operator<(const CacheEntry& rhs) const { return ut < rhs.ut; } // Sort by time of usage.
-
-        HashClass           hash;
-        ::llvm::Function*   llvmFunction;
-        ::llvm::GlobalVariable*   llvmConstant;
-        RIuint32            ut;
-        RIint32             refCount;
-    };
-
-public:
-    typedef CacheEntry* EntryHandle;
-
-public:
-    FunctionCache(int nMaxEntries) :
-        m_time(0)
-    {
-        // Limit so that if the cache is too large, you must optimize the implementation.
-        // Also note that the optimized pixel pipes are most likely small, so it would 
-        // be better to have a fast cache and a lot of entries!
-        // \note A simple optimization is to sort the usage time sort order and remove the last
-        // item in the array (instead of the first).
-        RI_ASSERT(nMaxEntries > 0 && nMaxEntries < IMPLEMENTATION_MAX_CACHE_ENTRIES); 
-        m_nMaxEntries = nMaxEntries;
-        m_entries.reserve(nMaxEntries);
-    }
-
-    ~FunctionCache() 
-    {
-        for (int i = 0; i < m_entries.size(); i++)
-        {
-            clearEntry(m_entries[i]);
-        }
-    }
-    
-    // This info is needed for the module to remove functions and deallocate executable
-    // functions:
-    void setLLVMInterface(::llvm::ExecutionEngine* ee, ::llvm::Module* module)
-    {
-        m_executionEngine = ee;
-        m_module = module;
-    }
-
-    // \todo If we never need the entry index, the locking can be
-    // simplified a lot.
-    // Must lock the cache during this operation!
-    EntryHandle findCachedItemByHash(const HashClass& hash)
-    {
-        acquireMutex();
-        int i = findCachedItemIndexByHash(hash, true);
-        if (i == -1)
-        {
-            releaseMutex();
-            return NULL;
-        }
-        EntryHandle handle = &m_entries[i];
-        releaseMutex();
-        
-        return handle;
-    }
-
-    /**
-     * \brief   Caches a function. Sets the reference count to 1
-     * \return  EntryHandle != NULL on success.
-     * \todo    The cache must be locked during the operation.
-     */
-    EntryHandle cacheFunction(HashClass hash, ::llvm::Function* function, ::llvm::GlobalVariable* constant)
-    {
-        acquireMutex();
-        RI_ASSERT(findCachedItemIndexByHash(hash) == -1);
-
-        if (m_entries.size() == m_nMaxEntries)
-        {
-            if (!removeLRU())
-            {
-                releaseMutex();
-                return NULL;
-            }
-        }
-
-        m_entries.push_back(CacheEntry(hash, function, constant, m_time));
-        
-        RI_ASSERT(m_entries.size() > 0);
-        EntryHandle ret = &m_entries[m_entries.size()-1];
-        incrementGlobalTime();
-
-        releaseMutex();
-        return ret;
-    }
-
-    ::llvm::Function* getFunction(EntryHandle handle)
-    {
-        return handle->llvmFunction;
-    }
-
-    // \note Does not remove the function from cache!
-    void releaseEntry(EntryHandle handle)
-    {
-        RI_ASSERT(handle->refCount > 0);
-        handle->refCount--;
-    }
-
-private:
-    void incrementGlobalTime()
-    {
-        m_time++;
-        if (m_time == MAX_GLOBAL_TIME)
-            rebaseUsageTime();
-    }
-
-    void incrementAccessTime(CacheEntry &entry)
-    {
-        entry.ut = m_time;
-        incrementGlobalTime();
-    }
-
-    int findCachedItemIndexByHash(const HashClass& hash, bool reserve = false)
-    {
-        // \note Could just overload operator== from entry and use the Array.find function.
-        for (int i = 0; i < m_entries.size(); i++)
-        {
-            if (m_entries[i].hash == hash)
-            {
-                if (reserve)
-                {
-                    incrementAccessTime(m_entries[i]);
-                    m_entries[i].refCount++;
-                }
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    void clearEntry(CacheEntry& entry)
-    {
-        m_executionEngine->freeMachineCodeForFunction(entry.llvmFunction);
-        entry.llvmFunction->eraseFromParent();
-        //entry.llvmConstant->eraseFromParent();
-    }
-
-    /**
-     * \return  true if LRU item was successfully removed, false otherwise.
-     * \note    Could try other pipes, but it is unlikely that the cache gets filled
-     *          so soon that the blit for the least recently used blit has not been
-     *          released.
-     * \todo    Implement drop of other cache-entries?
-     */
-    bool removeLRU() 
-    {
-        // \note This is pretty inefficient for many cache size:
-        // After first LRU removal, the cache is almost sorted anyway, so
-        // more efficient solution should be implemented.
-        //
-        m_entries.sort();
-
-        if (m_entries[0].refCount > 0)
-            return false;
-
-        clearEntry(m_entries[0]);
-        m_entries.remove(m_entries[0]);
-
-        return true;
-    }
-
-    void rebaseUsageTime()
-    {
-        RIuint32 i;
-        m_entries.sort();
-        RI_ASSERT(m_entries.size() > 0);
-        for(i = 0; i < (RIuint32)m_entries.size(); i++)
-        {
-            m_entries[i].ut = i;
-        };
-        m_time = i;
-    }
-
-    static void acquireMutex();
-    static void releaseMutex();
-
-private:
-    ::llvm::Module              *m_module;
-    ::llvm::ExecutionEngine     *m_executionEngine;
-
-    RIuint32            m_time;
-    Array <CacheEntry>  m_entries;
-    int                 m_nMaxEntries;
-
-    static bool             s_mutexInitialized;
-#if defined(__unix__)
-    static pthread_mutex_t  s_mutex;
-#else
-    static CRITICAL_SECTION s_mutex;
-#endif
-};
-
-template<class HashClass>
-bool FunctionCache<HashClass>::s_mutexInitialized = false;
-
-#if defined(__unix__)
-template<class HashClass>
-pthread_mutex_t FunctionCache<HashClass>::s_mutex;
-#else
-template<class HashClass>
-CRITICAL_SECTION FunctionCache<HashClass>::s_mutex;
-#endif
-
-template<class HashClass>
-void FunctionCache<HashClass>::acquireMutex()
-{
-    if (!s_mutexInitialized)
-    {
-#if defined(__unix__)
-        int ret;
-        pthread_mutexattr_t attr;
-        ret = pthread_mutexattr_init(&attr);	//initially not locked
-        RI_ASSERT(!ret);	//check that there aren't any errors
-        ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);	//count the number of recursive locks
-        RI_ASSERT(!ret);	//check that there aren't any errors
-        ret = pthread_mutex_init(&s_mutex, &attr);
-        pthread_mutexattr_destroy(&attr);
-        RI_ASSERT(!ret);	//check that there aren't more errors
-#else
-        ::InitializeCriticalSection(&s_mutex);
-#endif
-        s_mutexInitialized = true;
-    }
-#if defined(__unix__)
-    int ret = pthread_mutex_lock(&s_mutex);
-    RI_ASSERT(!ret);
-#else
-    ::EnterCriticalSection(&s_mutex);
-#endif
-}
-
-template<class HashClass>
-void FunctionCache<HashClass>::releaseMutex()
-{
-    RI_ASSERT(s_mutexInitialized);
-#if defined(__unix__)
-    int ret = pthread_mutex_unlock(&s_mutex);
-    RI_ASSERT(!ret);
-#else
-    ::LeaveCriticalSection(&s_mutex);
-#endif
-}
-
-}
-
-
-#endif
-