Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | 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 00086 // --- ShTransfer --- // 00088 ShTransfer::ShTransfer(const std::string& from, const std::string& to) 00089 { 00090 ShStorage::addTransfer(from, to, this); 00091 } 00092 00093 00095 // --- ShStorage --- // 00097 ShStorage::ShStorage() 00098 : m_timestamp(-1) 00099 { 00100 } 00101 00102 ShStorage::~ShStorage() 00103 { 00104 if (m_memory) { 00105 m_memory->removeStorage(this); 00106 } 00107 } 00108 00109 int ShStorage::timestamp() const 00110 { 00111 return m_timestamp; 00112 } 00113 00114 void ShStorage::setTimestamp(int timestamp) 00115 { 00116 SH_DEBUG_ASSERT(timestamp >= m_timestamp); // TODO: Assert this 00117 // assertion :). 00118 m_timestamp = timestamp; 00119 } 00120 00121 const ShMemory* ShStorage::memory() const 00122 { 00123 return m_memory; 00124 } 00125 00126 ShMemory* ShStorage::memory() 00127 { 00128 return m_memory; 00129 } 00130 00131 void ShStorage::orphan() 00132 { 00133 m_memory = 0; 00134 } 00135 00136 void ShStorage::sync() 00137 { 00138 SH_DEBUG_ASSERT(m_memory); 00139 00140 if (m_memory->timestamp() == timestamp()) return; // We are already 00141 // in sync 00142 00143 // Out of sync. Find the cheapest other storage to sync from 00144 ShStorage* source = 0; 00145 int transfer_cost = -1; 00146 ShMemory::StorageList::const_iterator I; 00147 for (I = m_memory->m_storages.begin(); I != m_memory->m_storages.end(); ++I) { 00148 ShStorage* other = I->object(); 00149 if (other == this) continue; 00150 if (other->timestamp() < m_memory->timestamp()) continue; 00151 int local_cost = cost(other, this); 00152 if (local_cost < 0) continue; // Can't transfer from that storage. 00153 if (!source || local_cost < transfer_cost) { 00154 source = other; 00155 transfer_cost = local_cost; 00156 } 00157 } 00158 00159 // For now: 00160 SH_DEBUG_ASSERT(source); 00161 // TODO: In the future, traverse the graph of transfers to find a 00162 // cheap, working one. 00163 00164 // Do the actual transfer 00165 if (!transfer(source, this)) { 00166 SH_DEBUG_WARN("Transfer from " << source << " to " << this << " failed!"); 00167 } 00168 } 00169 00170 void ShStorage::dirty() 00171 { 00172 // TODO: Maybe in the future check that the sync worked 00173 sync(); 00174 00175 // TODO: Don't do this if we are the only sync'd storage of the 00176 // memory. 00177 // That's an optimization though. 00178 m_timestamp++; 00179 m_memory->updateTimestamp(m_timestamp); 00180 } 00181 00182 int ShStorage::cost(ShStorage* from, ShStorage* to) 00183 { 00184 if (!from) return -1; 00185 if (!to) return -1; 00186 if (!m_transfers) return false; 00187 00188 TransferMap::const_iterator I = m_transfers->find(std::make_pair(from->id(), to->id())); 00189 if (I == m_transfers->end()) return -1; 00190 00191 return I->second->cost(); 00192 } 00193 00194 bool ShStorage::transfer(ShStorage* from, ShStorage* to) 00195 { 00196 if (!from) return false; 00197 if (!to) return false; 00198 if (!m_transfers) return false; 00199 00200 TransferMap::const_iterator I = m_transfers->find(std::make_pair(from->id(), to->id())); 00201 if (I == m_transfers->end()) return false; // No transfer function? 00202 00203 // TODO: Should we only allow transfers between storages 00204 // corresponding to the same memory? 00205 // Probably. 00206 if (I->second->transfer(from, to)) { 00207 to->setTimestamp(from->timestamp()); 00208 return true; 00209 } else { 00210 return false; 00211 } 00212 } 00213 00214 void ShStorage::addTransfer(const std::string& from, 00215 const std::string& to, 00216 ShTransfer* transfer) 00217 { 00218 if (!m_transfers) m_transfers = new TransferMap(); 00219 (*m_transfers)[std::make_pair(from, to)] = transfer; 00220 } 00221 00222 ShStorage::ShStorage(ShMemory* memory) 00223 : m_memory(memory), m_timestamp(-1) 00224 { 00225 m_memory->addStorage(this); 00226 } 00227 00228 ShStorage::TransferMap* ShStorage::m_transfers = 0; 00229 00231 // --- ShHostStorage --- // 00233 00234 ShHostStorage::ShHostStorage(ShMemory* memory, int length) 00235 : ShStorage(memory), 00236 m_length(length), 00237 m_data(new char[length]), 00238 m_managed(true) 00239 { 00240 } 00241 00242 ShHostStorage::ShHostStorage(ShMemory* memory, int length, void* data) 00243 : ShStorage(memory), 00244 m_length(length), 00245 m_data(data), 00246 m_managed(false) 00247 { 00248 } 00249 00250 ShHostStorage::~ShHostStorage() 00251 { 00252 if (m_managed) { 00253 delete [] reinterpret_cast<char*>(m_data); 00254 } 00255 } 00256 00257 std::string ShHostStorage::id() const 00258 { 00259 return "host"; 00260 } 00261 00262 00263 int ShHostStorage::length() const 00264 { 00265 return m_length; 00266 } 00267 00268 const void* ShHostStorage::data() const 00269 { 00270 return m_data; 00271 } 00272 00273 void* ShHostStorage::data() 00274 { 00275 return m_data; 00276 } 00277 00279 // --- ShHostMemory --- // 00281 00282 ShHostMemory::ShHostMemory(int length) 00283 : m_hostStorage(new ShHostStorage(this, length)) 00284 { 00285 m_hostStorage->setTimestamp(0); 00286 } 00287 00288 ShHostMemory::ShHostMemory(int length, void* data) 00289 : m_hostStorage(new ShHostStorage(this, length, data)) 00290 { 00291 m_hostStorage->setTimestamp(0); 00292 } 00293 00294 ShHostMemory::~ShHostMemory() 00295 { 00296 } 00297 00298 ShHostStoragePtr ShHostMemory::hostStorage() 00299 { 00300 return m_hostStorage; 00301 } 00302 00303 ShPointer<const ShHostStorage> ShHostMemory::hostStorage() const 00304 { 00305 return m_hostStorage; 00306 } 00307 00308 class ShHostHostTransfer : public ShTransfer { 00309 public: 00310 bool transfer(const ShStorage* from, ShStorage* to) 00311 { 00312 const ShHostStorage* host_from = dynamic_cast<const ShHostStorage*>(from); 00313 ShHostStorage* host_to = dynamic_cast<ShHostStorage*>(to); 00314 00315 // Check that casts succeeded 00316 if (!host_from) return false; 00317 if (!host_to) return false; 00318 00319 // Check that sizes match 00320 if (host_from->length() != host_to->length()) return false; 00321 00322 std::memcpy(host_to->data(), host_from->data(), host_to->length()); 00323 00324 return true; 00325 } 00326 00327 int cost() 00328 { 00329 return 10; // Maybe this should be 0, but you never know... 00330 } 00331 00332 private: 00333 ShHostHostTransfer() 00334 : ShTransfer("host", "host") 00335 { 00336 } 00337 00338 static ShHostHostTransfer* instance; 00339 }; 00340 00341 ShHostHostTransfer* ShHostHostTransfer::instance = new ShHostHostTransfer(); 00342 00343 }

Generated on Mon Oct 18 14:17:39 2004 for Sh by doxygen 1.3.7