1
0

Merge pull request #1346 from mc-server/AnvilStatsHeights

Anvil stats heights
This commit is contained in:
Mattes D 2014-08-27 12:32:51 +03:00
commit 3da27fb7a3
8 changed files with 187 additions and 16 deletions

View File

@ -11,3 +11,4 @@ Profiling
*.png
world/
*.html
*.xls

View File

@ -118,5 +118,27 @@ add_executable(AnvilStats
${SHARED_OSS_HDR}
)
target_link_libraries(AnvilStats zlib)
# Under MSVC we need to enlarge the default stack size for the executable:
if (MSVC)
get_target_property(TEMP AnvilStats LINK_FLAGS)
if (TEMP STREQUAL "TEMP-NOTFOUND")
SET(TEMP "") # set to empty string
message("LINKER_FLAGS not found")
else ()
SET(TEMP "${TEMP} ") # a space to cleanly separate from existing content
message("LINKER_FLAGS: ${LINKER_FLAGS}")
endif ()
# append our values
SET(TEMP "${TEMP}/STACK:16777216")
set_target_properties(AnvilStats PROPERTIES LINK_FLAGS ${TEMP})
endif ()

View File

@ -241,6 +241,17 @@ public:
/** Clamp value to the specified range. */
template <typename T>
T Clamp(T a_Value, T a_Min, T a_Max)
{
return (a_Value < a_Min) ? a_Min : ((a_Value > a_Max) ? a_Max : a_Value);
}
// Common headers (part 2, with macros):
#include "../../src/ChunkDef.h"
#include "../../src/BlockID.h"

View File

@ -28,6 +28,7 @@ cProcessor::cThread::cThread(cCallback & a_Callback, cProcessor & a_ParentProces
m_Callback(a_Callback),
m_ParentProcessor(a_ParentProcessor)
{
LOG("Created a new thread: %p", this);
super::Start();
}
@ -35,11 +36,20 @@ cProcessor::cThread::cThread(cCallback & a_Callback, cProcessor & a_ParentProces
void cProcessor::cThread::WaitForStart(void)
{
m_HasStarted.Wait();
}
void cProcessor::cThread::Execute(void)
{
LOG("Started a new thread: %d", cIsThread::GetCurrentID());
LOG("Started a new thread: %p, ID %d", this, cIsThread::GetCurrentID());
m_ParentProcessor.m_ThreadsHaveStarted.Set();
m_HasStarted.Set();
for (;;)
{
@ -52,7 +62,7 @@ void cProcessor::cThread::Execute(void)
ProcessFile(FileName);
} // for-ever
LOG("Thread %d terminated", cIsThread::GetCurrentID());
LOG("Thread %p (ID %d) terminated", this, cIsThread::GetCurrentID());
}
@ -522,20 +532,18 @@ void cProcessor::ProcessWorld(const AString & a_WorldFolder, cCallbackFactory &
#endif // _DEBUG
//*/
// Start all the threads:
for (int i = 0; i < NumThreads; i++)
{
cCallback * Callback = a_CallbackFactory.GetNewCallback();
m_Threads.push_back(new cThread(*Callback, *this));
}
// Wait for the first thread to start processing:
m_ThreadsHaveStarted.Wait();
// Wait for all threads to finish
// simply by calling each thread's destructor sequentially
// Wait for all threads to finish:
LOG("Waiting for threads to finish");
for (cThreads::iterator itr = m_Threads.begin(), end = m_Threads.end(); itr != end; ++itr)
{
(*itr)->WaitForStart();
delete *itr;
} // for itr - m_Threads[]
LOG("Processor finished");

View File

@ -30,6 +30,7 @@ class cProcessor
cCallback & m_Callback;
cProcessor & m_ParentProcessor;
cEvent m_HasStarted;
// cIsThread override:
virtual void Execute(void) override;
@ -48,6 +49,9 @@ class cProcessor
public:
cThread(cCallback & a_Callback, cProcessor & a_ParentProcessor);
/** Waits until the thread starts processing the callback code. */
void WaitForStart(void);
} ;
typedef std::vector<cThread *> cThreads;
@ -65,10 +69,12 @@ protected:
AStringList m_FileQueue;
cThreads m_Threads;
cEvent m_ThreadsHaveStarted; // This is signalled by each thread to notify the parent thread that it can start waiting for those threads
/** Populates m_FileQueue with Anvil files from the specified folder. */
void PopulateFileQueue(const AString & a_WorldFolder);
/** Returns one filename from m_FileQueue, and removes the name from the queue. */
AString GetOneFileName(void);
} ;

View File

@ -26,9 +26,11 @@ cStatistics::cStats::cStats(void) :
m_MinChunkZ(0x7fffffff),
m_MaxChunkZ(0x80000000)
{
memset(m_BiomeCounts, 0, sizeof(m_BiomeCounts));
memset(m_BlockCounts, 0, sizeof(m_BlockCounts));
memset(m_SpawnerEntity, 0, sizeof(m_SpawnerEntity));
memset(m_BiomeCounts, 0, sizeof(m_BiomeCounts));
memset(m_BlockCounts, 0, sizeof(m_BlockCounts));
memset(m_PerHeightBlockCounts, 0, sizeof(m_PerHeightBlockCounts));
memset(m_PerHeightSpawners, 0, sizeof(m_PerHeightSpawners));
memset(m_SpawnerEntity, 0, sizeof(m_SpawnerEntity));
}
@ -46,6 +48,11 @@ void cStatistics::cStats::Add(const cStatistics::cStats & a_Stats)
for (int j = 0; j <= 255; j++)
{
m_BlockCounts[i][j] += a_Stats.m_BlockCounts[i][j];
m_PerHeightBlockCounts[i][j] += a_Stats.m_PerHeightBlockCounts[i][j];
}
for (int j = 0; j < ARRAYCOUNT(m_PerHeightSpawners[0]); j++)
{
m_PerHeightSpawners[i][j] += a_Stats.m_PerHeightSpawners[i][j];
}
}
for (int i = 0; i < ARRAYCOUNT(m_SpawnerEntity); i++)
@ -149,6 +156,7 @@ bool cStatistics::OnSection
for (int y = 0; y < 16; y++)
{
int Height = (int)a_Y * 16 + y;
for (int z = 0; z < 16; z++)
{
for (int x = 0; x < 16; x++)
@ -156,6 +164,7 @@ bool cStatistics::OnSection
unsigned char Biome = m_BiomeData[x + 16 * z]; // Cannot use cChunkDef, different datatype
unsigned char BlockType = cChunkDef::GetBlock(a_BlockTypes, x, y, z);
m_Stats.m_BlockCounts[Biome][BlockType] += 1;
m_Stats.m_PerHeightBlockCounts[Height][BlockType] += 1;
}
}
}
@ -259,16 +268,27 @@ bool cStatistics::OnTileTick(
void cStatistics::OnSpawner(cParsedNBT & a_NBT, int a_TileEntityTag)
{
// Get the spawned entity type:
int EntityIDTag = a_NBT.FindChildByName(a_TileEntityTag, "EntityId");
if ((EntityIDTag < 0) || (a_NBT.GetType(EntityIDTag) != TAG_String))
{
return;
}
eEntityType Ent = GetEntityType(a_NBT.GetString(EntityIDTag));
if (Ent < ARRAYCOUNT(m_Stats.m_SpawnerEntity))
if (Ent >= ARRAYCOUNT(m_Stats.m_SpawnerEntity))
{
m_Stats.m_SpawnerEntity[Ent] += 1;
return;
}
m_Stats.m_SpawnerEntity[Ent] += 1;
// Get the spawner pos:
int PosYTag = a_NBT.FindChildByName(a_TileEntityTag, "y");
if ((PosYTag < 0) || (a_NBT.GetType(PosYTag) != TAG_Int))
{
return;
}
int BlockY = Clamp(a_NBT.GetInt(PosYTag), 0, 255);
m_Stats.m_PerHeightSpawners[BlockY][Ent] += 1;
}
@ -316,10 +336,14 @@ cStatisticsFactory::~cStatisticsFactory()
SaveBiomes();
LOG(" BlockTypes.xls");
SaveBlockTypes();
LOG(" PerHeightBlockTypes.xls");
SavePerHeightBlockTypes();
LOG(" BiomeBlockTypes.xls");
SaveBiomeBlockTypes();
LOG(" Spawners.xls");
SaveSpawners();
LOG(" PerHeightSpawners.xls");
SavePerHeightSpawners();
}
@ -395,6 +419,61 @@ void cStatisticsFactory::SaveBlockTypes(void)
void cStatisticsFactory::SavePerHeightBlockTypes(void)
{
// Export as two tables: biomes 0-127 and 128-255, because OpenOffice doesn't support more than 256 columns
cFile f;
if (!f.Open("PerHeightBlockTypes.xls", cFile::fmWrite))
{
LOG("Cannot write to file PerHeightBlockTypes.xls. Statistics not written.");
return;
}
// Write header:
f.Printf("Blocks 0 - 127:\nHeight");
for (int i = 0; i < 128; i++)
{
f.Printf("\t%s(%d)", GetBlockTypeString(i), i);
}
f.Printf("\n");
// Write first half:
for (int y = 0; y < 256; y++)
{
f.Printf("%d", y);
for (int BlockType = 0; BlockType < 128; BlockType++)
{
f.Printf("\t%llu", m_CombinedStats.m_PerHeightBlockCounts[y][BlockType]);
} // for BlockType
f.Printf("\n");
} // for y - height (0 - 127)
f.Printf("\n");
// Write second header:
f.Printf("Blocks 128 - 255:\nHeight");
for (int i = 128; i < 256; i++)
{
f.Printf("\t%s(%d)", GetBlockTypeString(i), i);
}
f.Printf("\n");
// Write second half:
for (int y = 0; y < 256; y++)
{
f.Printf("%d", y);
for (int BlockType = 128; BlockType < 256; BlockType++)
{
f.Printf("\t%llu", m_CombinedStats.m_PerHeightBlockCounts[y][BlockType]);
} // for BlockType
f.Printf("\n");
} // for y - height (0 - 127)
}
void cStatisticsFactory::SaveBiomeBlockTypes(void)
{
// Export as two tables: biomes 0-127 and 128-255, because OpenOffice doesn't support more than 256 columns
@ -521,3 +600,41 @@ void cStatisticsFactory::SaveSpawners(void)
void cStatisticsFactory::SavePerHeightSpawners(void)
{
cFile f;
if (!f.Open("PerHeightSpawners.xls", cFile::fmWrite))
{
LOG("Cannot write to file PerHeightSpawners.xls. Statistics not written.");
return;
}
// Write header:
f.Printf("Height\tTotal");
for (int i = 0; i < entMax; i++)
{
f.Printf("\t%s", GetEntityTypeString((eEntityType)i));
}
f.Printf("\n");
// Write individual lines:
for (int y = 0; y < 256; y++)
{
UInt64 Total = 0;
for (int i = 0; i < entMax; i++)
{
Total += m_CombinedStats.m_PerHeightSpawners[y][i];
}
f.Printf("%d\t%llu", y, Total);
for (int i = 0; i < entMax; i++)
{
f.Printf("\t%llu", m_CombinedStats.m_PerHeightSpawners[y][i]);
}
f.Printf("\n");
}
}

View File

@ -31,6 +31,8 @@ public:
UInt64 m_NumEntities;
UInt64 m_NumTileEntities;
UInt64 m_NumTileTicks;
UInt64 m_PerHeightBlockCounts[256][256]; // First dimension is the height, second dimension is BlockType
UInt64 m_PerHeightSpawners[256][entMax + 1]; // First dimension is the height, second dimension is spawned entity type
int m_MinChunkX, m_MaxChunkX; // X coords range
int m_MinChunkZ, m_MaxChunkZ; // Z coords range
@ -74,6 +76,8 @@ protected:
virtual bool OnEmptySection(unsigned char a_Y) override;
virtual bool OnSectionsFinished(void) override { return false; } // continue processing
virtual bool OnEntity(
const AString & a_EntityType,
double a_PosX, double a_PosY, double a_PosZ,
@ -128,9 +132,11 @@ protected:
void JoinResults(void);
void SaveBiomes(void);
void SaveBlockTypes(void);
void SavePerHeightBlockTypes(void);
void SaveBiomeBlockTypes(void);
void SaveStatistics(void);
void SaveSpawners(void);
void SavePerHeightSpawners(void);
} ;

View File

@ -272,7 +272,7 @@ extern const char * GetEntityTypeString(eEntityType a_EntityType)
int GetNumCores(void)
{
// Get number of cores by querying the system process affinity mask (Windows-specific)
DWORD Affinity, ProcAffinity;
DWORD_PTR Affinity, ProcAffinity;
GetProcessAffinityMask(GetCurrentProcess(), &ProcAffinity, &Affinity);
int NumCores = 0;
while (Affinity > 0)