Graph Generator::Generate(list<int> parameter) { if(MinParamCount > 0 && (((int)parameter.size()) < MinParamCount)) { stringstream exception; exception << "generator requires at least " << MinParamCount << " parameters"; throw exception.str().c_str(); } if(MaxParamCount >= 0 && (((int)parameter.size()) > MaxParamCount)) { stringstream exception; exception << "generator allows at most " << MaxParamCount << " parameters"; throw exception.str().c_str(); } return DoGenerate(parameter); }
void cChunkGenerator::Execute(void) { // To be able to display performance information, the generator counts the chunks generated. // When the queue gets empty, the count is reset, so that waiting for the queue is not counted into the total time. int NumChunksGenerated = 0; // Number of chunks generated since the queue was last empty clock_t GenerationStart = clock(); // Clock tick when the queue started to fill clock_t LastReportTick = clock(); // Clock tick of the last report made (so that performance isn't reported too often) while (!m_ShouldTerminate) { cCSLock Lock(m_CS); while (m_Queue.empty()) { if ((NumChunksGenerated > 16) && (clock() - LastReportTick > CLOCKS_PER_SEC)) { LOG("Chunk generator performance: %.2f ch / sec (%d ch total)", static_cast<double>(NumChunksGenerated) * CLOCKS_PER_SEC/ (clock() - GenerationStart), NumChunksGenerated ); } cCSUnlock Unlock(Lock); m_Event.Wait(); if (m_ShouldTerminate) { return; } NumChunksGenerated = 0; GenerationStart = clock(); LastReportTick = clock(); } if (m_Queue.empty()) { // Sometimes the queue remains empty // If so, we can't do any front() operations on it! continue; } cQueueItem item = m_Queue.front(); // Get next chunk from the queue bool SkipEnabled = (m_Queue.size() > QUEUE_SKIP_LIMIT); m_Queue.erase(m_Queue.begin()); // Remove the item from the queue Lock.Unlock(); // Unlock ASAP m_evtRemoved.Set(); // Display perf info once in a while: if ((NumChunksGenerated > 16) && (clock() - LastReportTick > 2 * CLOCKS_PER_SEC)) { LOG("Chunk generator performance: %.2f ch / sec (%d ch total)", static_cast<double>(NumChunksGenerated) * CLOCKS_PER_SEC / (clock() - GenerationStart), NumChunksGenerated ); LastReportTick = clock(); } // Skip the chunk if it's already generated and regeneration is not forced: if (!item.m_ForceGenerate && m_ChunkSink->IsChunkValid(item.m_ChunkX, item.m_ChunkZ)) { LOGD("Chunk [%d, %d] already generated, skipping generation", item.m_ChunkX, item.m_ChunkZ); if (item.m_Callback != nullptr) { item.m_Callback->Call(item.m_ChunkX, item.m_ChunkZ); } continue; } // Skip the chunk if the generator is overloaded: if (SkipEnabled && !m_ChunkSink->HasChunkAnyClients(item.m_ChunkX, item.m_ChunkZ)) { LOGWARNING("Chunk generator overloaded, skipping chunk [%d, %d]", item.m_ChunkX, item.m_ChunkZ); if (item.m_Callback != nullptr) { item.m_Callback->Call(item.m_ChunkX, item.m_ChunkZ); } continue; } // Generate the chunk: LOGD("Generating chunk [%d, %d]", item.m_ChunkX, item.m_ChunkZ); DoGenerate(item.m_ChunkX, item.m_ChunkZ); if (item.m_Callback != nullptr) { item.m_Callback->Call(item.m_ChunkX, item.m_ChunkZ); } NumChunksGenerated++; } // while (!bStop) }
static void Generate( void ) { //================================ // Generate code. TYPE typ1; TYPE typ2; OPTR op; OPR opr; itnode *next; unsigned_16 mask; uint res_size; next = CITNode->link; if( next->opn.ds == DSOPN_PHI ) { BadSequence(); } else { typ1 = CITNode->typ; typ2 = next->typ; opr = next->opr; if( RecNOpn() ) { typ1 = FT_NO_TYPE; CITNode->size = next->size; if( (opr != OPR_PLS) && (opr != OPR_MIN) && (opr != OPR_NOT) ) { BadSequence(); return; } } op = OprNum[ opr ]; if( typ1 == FT_NO_TYPE ) { mask = LegalOprsU[ typ2 - FT_FIRST ]; } else { mask = LegalOprsB[ ( typ2 - FT_FIRST ) * LEGALOPR_TAB_COLS + typ1 - FT_FIRST ]; } if( (( mask >> ( op - OPTR_FIRST ) ) & 1) == 0 ) { // illegal combination MoveDown(); if( typ1 == FT_NO_TYPE ) { TypeErr( MD_UNARY_OP, typ2 ); } else if( typ1 == typ2 ) { TypeErr( MD_ILL_OPR, typ1 ); } else { TypeTypeErr( MD_MIXED, typ1, typ2 ); } BackTrack(); } else if( DoGenerate( typ1, typ2, &res_size ) ) { if( ( opr >= OPR_FIRST_RELOP ) && ( opr <= OPR_LAST_RELOP ) && ( (ResultType == FT_COMPLEX) || (ResultType == FT_DCOMPLEX) || (ResultType == FT_XCOMPLEX) ) && ( opr != OPR_EQ ) && ( opr != OPR_NE ) ) { // can only compare complex with .EQ. and .NE. Error( MD_RELOP_OPND_COMPLEX ); } else { if( ( next->opn.us == USOPN_CON ) && ( ( CITNode->opn.us == USOPN_CON ) || ( typ1 == FT_NO_TYPE ) ) ) { // we can do some constant folding ConstTable[ op ]( typ1, typ2, op ); } else { // we have to generate code if( CITNode->opn.us == USOPN_CON ) { AddConst( CITNode ); } else if( next->opn.us == USOPN_CON ) { AddConst( next ); } GenOprTable[ op ]( typ1, typ2, op ); } } switch( opr ) { case OPR_EQV: case OPR_NEQV: case OPR_OR: case OPR_AND: case OPR_NOT: if( _IsTypeInteger( typ1 ) ) { Extension( MD_LOGOPR_INTOPN ); } break; case OPR_EQ: // relational operators case OPR_NE: case OPR_LT: case OPR_GE: case OPR_LE: case OPR_GT: ResultType = FT_LOGICAL; res_size = TypeSize( ResultType ); break; case OPR_FLD: case OPR_DPT: // set result size to size of field res_size = next->size; FixFldNode(); break; } CITNode->size = res_size; CITNode->typ = ResultType; FixList(); } }
void cChunkGenerator::Execute(void) { // To be able to display performance information, the generator counts the chunks generated. // When the queue gets empty, the count is reset, so that waiting for the queue is not counted into the total time. int NumChunksGenerated = 0; // Number of chunks generated since the queue was last empty clock_t GenerationStart = clock(); // Clock tick when the queue started to fill clock_t LastReportTick = clock(); // Clock tick of the last report made (so that performance isn't reported too often) while (!m_ShouldTerminate) { cCSLock Lock(m_CS); while (m_Queue.size() == 0) { if ((NumChunksGenerated > 16) && (clock() - LastReportTick > CLOCKS_PER_SEC)) { LOG("Chunk generator performance: %.2f ch/s (%d ch total)", (double)NumChunksGenerated * CLOCKS_PER_SEC/ (clock() - GenerationStart), NumChunksGenerated ); } cCSUnlock Unlock(Lock); m_Event.Wait(); if (m_ShouldTerminate) { return; } NumChunksGenerated = 0; GenerationStart = clock(); LastReportTick = clock(); } cChunkCoords coords = m_Queue.front(); // Get next coord from queue m_Queue.erase( m_Queue.begin() ); // Remove coordinate from queue bool SkipEnabled = (m_Queue.size() > QUEUE_SKIP_LIMIT); Lock.Unlock(); // Unlock ASAP m_evtRemoved.Set(); // Display perf info once in a while: if ((NumChunksGenerated > 16) && (clock() - LastReportTick > 2 * CLOCKS_PER_SEC)) { LOG("Chunk generator performance: %.2f ch/s (%d ch total)", (double)NumChunksGenerated * CLOCKS_PER_SEC / (clock() - GenerationStart), NumChunksGenerated ); LastReportTick = clock(); } // Hack for regenerating chunks: if Y != 0, the chunk is considered invalid, even if it has its data set if ((coords.m_ChunkY == 0) && m_World->IsChunkValid(coords.m_ChunkX, coords.m_ChunkZ)) { LOGD("Chunk [%d, %d] already generated, skipping generation", coords.m_ChunkX, coords.m_ChunkZ); // Already generated, ignore request continue; } if (SkipEnabled && !m_World->HasChunkAnyClients(coords.m_ChunkX, coords.m_ChunkZ)) { LOGWARNING("Chunk generator overloaded, skipping chunk [%d, %d]", coords.m_ChunkX, coords.m_ChunkZ); continue; } LOGD("Generating chunk [%d, %d, %d]", coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); DoGenerate(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); // Save the chunk right after generating, so that we don't have to generate it again on next run m_World->GetStorage().QueueSaveChunk(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); NumChunksGenerated++; } // while (!bStop) }