Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

ShMemory.cpp

00001 // Sh: A GPU metaprogramming language.
00002 //
00003 // Copyright (c) 2003 University of Waterloo Computer Graphics Laboratory
00004 // Project administrator: Michael D. McCool
00005 // Authors: Zheng Qin, Stefanus Du Toit, Kevin Moule, Tiberiu S. Popa,
00006 //          Michael D. McCool
00007 // 
00008 // This software is provided 'as-is', without any express or implied
00009 // warranty. In no event will the authors be held liable for any damages
00010 // arising from the use of this software.
00011 // 
00012 // Permission is granted to anyone to use this software for any purpose,
00013 // including commercial applications, and to alter it and redistribute it
00014 // freely, subject to the following restrictions:
00015 // 
00016 // 1. The origin of this software must not be misrepresented; you must
00017 // not claim that you wrote the original software. If you use this
00018 // software in a product, an acknowledgment in the product documentation
00019 // would be appreciated but is not required.
00020 // 
00021 // 2. Altered source versions must be plainly marked as such, and must
00022 // not be misrepresented as being the original software.
00023 // 
00024 // 3. This notice may not be removed or altered from any source
00025 // distribution.
00027 #include "ShMemory.hpp"
00028 #include "ShDebug.hpp"
00029 #include <cstring>
00030 #include <algorithm>
00031 
00032 namespace SH {
00033 
00035 // --- ShMemory --- //
00037 
00038 ShMemory::~ShMemory()
00039 {
00040   for (StorageList::iterator I = m_storages.begin(); I != m_storages.end(); ++I) {
00041     (*I)->orphan(); // We don't need these storages to tell us that they are
00042                     // going away, since we're going away ourselves.
00043   }
00044 }
00045 
00046 int ShMemory::timestamp() const
00047 {
00048   return m_timestamp;
00049 }
00050 
00051 ShPointer<ShStorage> ShMemory::findStorage(const std::string& id)
00052 {
00053   for (StorageList::iterator I = m_storages.begin(); I != m_storages.end(); ++I) {
00054     if ((*I)->id() == id) return *I;
00055   }
00056   return 0;
00057 }
00058 
00059 ShMemory::ShMemory()
00060   : m_timestamp(0)
00061 {
00062 }
00063 
00064 void ShMemory::updateTimestamp(int timestamp)
00065 {
00066   SH_DEBUG_ASSERT(timestamp >= m_timestamp);
00067   m_timestamp = timestamp;
00068 }
00069 
00070 void ShMemory::addStorage(const ShPointer<ShStorage>& storage)
00071 {
00072   m_storages.push_back(storage);
00073 }
00074 
00075 void ShMemory::removeStorage(const ShPointer<ShStorage>& storage)
00076 {
00077   StorageList::iterator I = std::find(m_storages.begin(), m_storages.end(), storage);
00078   if (I == m_storages.end()) return;
00079   (*I)->orphan();
00080   m_storages.erase(I);
00081 
00082   // TODO: fix this, refcount lossage.
00083 }
00084 
00085 void ShMemory::add_dep(ShMemoryDep* dep)
00086 {
00087   dependencies.push_back(dep);
00088 }
00089 
00090 void ShMemory::flush()
00091 {
00092   ShHostStoragePtr storage = shref_dynamic_cast<ShHostStorage>(findStorage("host"));
00093   storage->dirtyall();
00094   for(std::list<ShMemoryDep*>::iterator i = dependencies.begin() ; i != dependencies.end() ; i++)
00095     (*i)->memory_update();
00096 }
00097 
00099 // --- ShTransfer --- //
00101 ShTransfer::ShTransfer(const std::string& from, const std::string& to)
00102 {
00103   ShStorage::addTransfer(from, to, this);
00104 }
00105 
00106 
00108 // --- ShStorage --- //
00110 ShStorage::ShStorage()
00111   : m_timestamp(-1)
00112 {
00113 }
00114 
00115 ShStorage::~ShStorage()
00116 {
00117   if (m_memory) {
00118     m_memory->removeStorage(this);
00119   }
00120 }
00121 
00122 int ShStorage::timestamp() const
00123 {
00124   return m_timestamp;
00125 }
00126 
00127 void ShStorage::setTimestamp(int timestamp)
00128 {
00129   SH_DEBUG_ASSERT(timestamp >= m_timestamp); // TODO: Assert this
00130                                              // assertion :).
00131   m_timestamp = timestamp;
00132 }
00133 
00134 const ShMemory* ShStorage::memory() const
00135 {
00136   return m_memory;
00137 }
00138 
00139 ShMemory* ShStorage::memory()
00140 {
00141   return m_memory;
00142 }
00143 
00144 void ShStorage::orphan()
00145 {
00146   m_memory = 0;
00147 }
00148 
00149 void ShStorage::sync()
00150 {
00151   SH_DEBUG_ASSERT(m_memory);
00152   
00153   if (m_memory->timestamp() == timestamp()) return; // We are already
00154                                                     // in sync
00155 
00156   // Out of sync. Find the cheapest other storage to sync from
00157   ShStorage* source = 0;
00158   int transfer_cost = -1;
00159   ShMemory::StorageList::const_iterator I;
00160   for (I = m_memory->m_storages.begin(); I != m_memory->m_storages.end(); ++I) {
00161     ShStorage* other = I->object();
00162     if (other == this) continue;
00163     if (other->timestamp() < m_memory->timestamp()) continue;
00164     int local_cost = cost(other, this);
00165     if (local_cost < 0) continue; // Can't transfer from that storage.
00166     if (!source || local_cost < transfer_cost) {
00167       source = other;
00168       transfer_cost = local_cost;
00169     }
00170   }
00171   
00172   // For now:
00173   SH_DEBUG_ASSERT(source);
00174   // TODO: In the future, traverse the graph of transfers to find a
00175   // cheap, working one.
00176 
00177   // Do the actual transfer
00178   if (!transfer(source, this)) {
00179     SH_DEBUG_WARN("Transfer from " << source << " to " << this << " failed!");
00180   }
00181 }
00182 
00183 void ShStorage::dirty()
00184 {
00185   // TODO: Maybe in the future check that the sync worked
00186   sync();
00187 
00188   dirtyall();
00189 }
00190 
00191 void ShStorage::dirtyall()
00192 {
00193   m_timestamp++;
00194   m_memory->updateTimestamp(m_timestamp);
00195 }
00196 
00197 int ShStorage::cost(ShStorage* from, ShStorage* to)
00198 {
00199   if (!from) return -1;
00200   if (!to) return -1;
00201   if (!m_transfers) return false;
00202   
00203   TransferMap::const_iterator I = m_transfers->find(std::make_pair(from->id(), to->id()));
00204   if (I == m_transfers->end()) return -1;
00205 
00206   return I->second->cost();
00207 }
00208 
00209 bool ShStorage::transfer(ShStorage* from, ShStorage* to)
00210 {
00211   if (!from) return false;
00212   if (!to) return false;
00213   if (!m_transfers) return false;
00214   
00215   TransferMap::const_iterator I = m_transfers->find(std::make_pair(from->id(), to->id()));
00216   if (I == m_transfers->end()) return false; // No transfer function?
00217 
00218   // TODO: Should we only allow transfers between storages
00219   // corresponding to the same memory?
00220   // Probably.
00221   if (I->second->transfer(from, to)) {
00222     to->setTimestamp(from->timestamp());
00223     return true;
00224   } else {
00225     return false;
00226   }
00227 }
00228 
00229 void ShStorage::addTransfer(const std::string& from,
00230                             const std::string& to,
00231                             ShTransfer* transfer)
00232 {
00233   if (!m_transfers) m_transfers = new TransferMap();
00234   (*m_transfers)[std::make_pair(from, to)] = transfer;
00235 }
00236 
00237 ShStorage::ShStorage(ShMemory* memory)
00238   : m_memory(memory), m_timestamp(-1)
00239 {
00240   m_memory->addStorage(this);
00241 }
00242 
00243 ShStorage::TransferMap* ShStorage::m_transfers = 0;
00244 
00246 // --- ShHostStorage --- //
00248 
00249 ShHostStorage::ShHostStorage(ShMemory* memory, int length)
00250   : ShStorage(memory),
00251     m_length(length),
00252     m_data(new char[length]),
00253     m_managed(true)
00254 {
00255 }
00256 
00257 ShHostStorage::ShHostStorage(ShMemory* memory, int length, void* data)
00258   : ShStorage(memory),
00259     m_length(length),
00260     m_data(data),
00261     m_managed(false)
00262 {
00263 }
00264 
00265 ShHostStorage::~ShHostStorage()
00266 {
00267   if (m_managed) {
00268     delete [] reinterpret_cast<char*>(m_data);
00269   }
00270 }
00271 
00272 std::string ShHostStorage::id() const
00273 {
00274   return "host";
00275 }
00276 
00277 
00278 int ShHostStorage::length() const
00279 {
00280   return m_length;
00281 }
00282 
00283 const void* ShHostStorage::data() const
00284 {
00285   return m_data;
00286 }
00287 
00288 void* ShHostStorage::data()
00289 {
00290   return m_data;
00291 }
00292 
00294 // --- ShHostMemory --- //
00296 
00297 ShHostMemory::ShHostMemory(int length)
00298   : m_hostStorage(new ShHostStorage(this, length))
00299 {
00300   m_hostStorage->setTimestamp(0);
00301 }
00302 
00303 ShHostMemory::ShHostMemory(int length, void* data)
00304   : m_hostStorage(new ShHostStorage(this, length, data))
00305 {
00306   m_hostStorage->setTimestamp(0);
00307 }
00308 
00309 ShHostMemory::~ShHostMemory()
00310 {
00311 }
00312 
00313 ShHostStoragePtr ShHostMemory::hostStorage()
00314 {
00315   return m_hostStorage;
00316 }
00317 
00318 ShPointer<const ShHostStorage> ShHostMemory::hostStorage() const
00319 {
00320   return m_hostStorage;
00321 }
00322 
00323 class ShHostHostTransfer : public ShTransfer {
00324 public:
00325   bool transfer(const ShStorage* from, ShStorage* to)
00326   {
00327     const ShHostStorage* host_from = dynamic_cast<const ShHostStorage*>(from);
00328     ShHostStorage* host_to = dynamic_cast<ShHostStorage*>(to);
00329 
00330     // Check that casts succeeded
00331     if (!host_from) return false;
00332     if (!host_to) return false;
00333 
00334     // Check that sizes match
00335     if (host_from->length() != host_to->length()) return false;
00336 
00337     std::memcpy(host_to->data(), host_from->data(), host_to->length());
00338     
00339     return true;
00340   }
00341 
00342   int cost()
00343   {
00344     return 10; // Maybe this should be 0, but you never know...
00345   }
00346 
00347 private:
00348   ShHostHostTransfer()
00349     : ShTransfer("host", "host")
00350   {
00351   }
00352   
00353   static ShHostHostTransfer* instance;
00354 };
00355 
00356 ShHostHostTransfer* ShHostHostTransfer::instance = new ShHostHostTransfer();
00357 
00358 }

Generated on Mon Jan 24 18:36:33 2005 for Sh by  doxygen 1.4.1