summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattes D <github@xoft.cz>2014-08-27 11:32:51 +0200
committerMattes D <github@xoft.cz>2014-08-27 11:32:51 +0200
commit3da27fb7a3f45bc5a82bba13e9b836c8b3dca6a5 (patch)
treef5ababf68358785f38268f7b21442b0f7c13790b
parentAnvilStats: Rewritten to use CMake. (diff)
parentAnvilStats: Fixed thread start race condition. (diff)
downloadcuberite-3da27fb7a3f45bc5a82bba13e9b836c8b3dca6a5.tar
cuberite-3da27fb7a3f45bc5a82bba13e9b836c8b3dca6a5.tar.gz
cuberite-3da27fb7a3f45bc5a82bba13e9b836c8b3dca6a5.tar.bz2
cuberite-3da27fb7a3f45bc5a82bba13e9b836c8b3dca6a5.tar.lz
cuberite-3da27fb7a3f45bc5a82bba13e9b836c8b3dca6a5.tar.xz
cuberite-3da27fb7a3f45bc5a82bba13e9b836c8b3dca6a5.tar.zst
cuberite-3da27fb7a3f45bc5a82bba13e9b836c8b3dca6a5.zip
-rw-r--r--Tools/AnvilStats/.gitignore1
-rw-r--r--Tools/AnvilStats/CMakeLists.txt22
-rw-r--r--Tools/AnvilStats/Globals.h11
-rw-r--r--Tools/AnvilStats/Processor.cpp24
-rw-r--r--Tools/AnvilStats/Processor.h10
-rw-r--r--Tools/AnvilStats/Statistics.cpp127
-rw-r--r--Tools/AnvilStats/Statistics.h6
-rw-r--r--Tools/AnvilStats/Utils.cpp2
8 files changed, 187 insertions, 16 deletions
diff --git a/Tools/AnvilStats/.gitignore b/Tools/AnvilStats/.gitignore
index afd34cdda..f093bbe7d 100644
--- a/Tools/AnvilStats/.gitignore
+++ b/Tools/AnvilStats/.gitignore
@@ -11,3 +11,4 @@ Profiling
*.png
world/
*.html
+*.xls
diff --git a/Tools/AnvilStats/CMakeLists.txt b/Tools/AnvilStats/CMakeLists.txt
index 8cbcf6be4..557a4c17a 100644
--- a/Tools/AnvilStats/CMakeLists.txt
+++ b/Tools/AnvilStats/CMakeLists.txt
@@ -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 ()
+
+
+
diff --git a/Tools/AnvilStats/Globals.h b/Tools/AnvilStats/Globals.h
index df1430cc4..21d54739a 100644
--- a/Tools/AnvilStats/Globals.h
+++ b/Tools/AnvilStats/Globals.h
@@ -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"
diff --git a/Tools/AnvilStats/Processor.cpp b/Tools/AnvilStats/Processor.cpp
index a16f78c18..6c4bb0ad5 100644
--- a/Tools/AnvilStats/Processor.cpp
+++ b/Tools/AnvilStats/Processor.cpp
@@ -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");
diff --git a/Tools/AnvilStats/Processor.h b/Tools/AnvilStats/Processor.h
index 72fea3081..db50ec619 100644
--- a/Tools/AnvilStats/Processor.h
+++ b/Tools/AnvilStats/Processor.h
@@ -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);
} ;
diff --git a/Tools/AnvilStats/Statistics.cpp b/Tools/AnvilStats/Statistics.cpp
index f7519fd37..c8a98b488 100644
--- a/Tools/AnvilStats/Statistics.cpp
+++ b/Tools/AnvilStats/Statistics.cpp
@@ -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");
+ }
+}
+
+
+
+
diff --git a/Tools/AnvilStats/Statistics.h b/Tools/AnvilStats/Statistics.h
index 53e353f22..1b012e283 100644
--- a/Tools/AnvilStats/Statistics.h
+++ b/Tools/AnvilStats/Statistics.h
@@ -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);
} ;
diff --git a/Tools/AnvilStats/Utils.cpp b/Tools/AnvilStats/Utils.cpp
index baa87bd69..d7543cb4c 100644
--- a/Tools/AnvilStats/Utils.cpp
+++ b/Tools/AnvilStats/Utils.cpp
@@ -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)