0.11.11: changed Statistics table name to Info and added new Statistics table containing detection statistics. StatisticsToolBox can cache statistics (true by default). DatabaseViewer: new Statistics panel to see all statistics contained in the database.

This commit is contained in:
matlabbe
2016-09-20 11:19:34 -04:00
parent a0972158dc
commit 3530da935b
20 changed files with 609 additions and 219 deletions

View File

@@ -197,6 +197,15 @@ ParametersMap DBDriver::getLastParameters() const
return parameters;
}
std::map<std::string, float> DBDriver::getStatistics(int nodeId, double & stamp) const
{
std::map<std::string, float> statistics;
_dbSafeAccessMutex.lock();
statistics = getStatisticsQuery(nodeId, stamp);
_dbSafeAccessMutex.unlock();
return statistics;
}
std::string DBDriver::getDatabaseVersion() const
{
std::string version = "0.0.0";
@@ -866,7 +875,7 @@ void DBDriver::getAllLabels(std::map<int, std::string> & labels) const
_dbSafeAccessMutex.unlock();
}
void DBDriver::addStatisticsAfterRun(
void DBDriver::addInfoAfterRun(
int stMemSize,
int lastSignAdded,
int processMemUsed,
@@ -881,13 +890,26 @@ void DBDriver::addStatisticsAfterRun(
if(uStrNumCmp(this->getDatabaseVersion(), "0.11.8") >= 0)
{
std::string param = Parameters::serialize(parameters);
query << "INSERT INTO Statistics(STM_size,last_sign_added,process_mem_used,database_mem_used,dictionary_size,parameters) values("
<< stMemSize << ","
<< lastSignAdded << ","
<< processMemUsed << ","
<< databaseMemUsed << ","
<< dictionarySize << ","
"\"" << param.c_str() << "\");";
if(uStrNumCmp(this->getDatabaseVersion(), "0.11.11") >= 0)
{
query << "INSERT INTO Info(STM_size,last_sign_added,process_mem_used,database_mem_used,dictionary_size,parameters) values("
<< stMemSize << ","
<< lastSignAdded << ","
<< processMemUsed << ","
<< databaseMemUsed << ","
<< dictionarySize << ","
"\"" << param.c_str() << "\");";
}
else
{
query << "INSERT INTO Statistics(STM_size,last_sign_added,process_mem_used,database_mem_used,dictionary_size,parameters) values("
<< stMemSize << ","
<< lastSignAdded << ","
<< processMemUsed << ","
<< databaseMemUsed << ","
<< dictionarySize << ","
"\"" << param.c_str() << "\");";
}
}
else
{
@@ -903,6 +925,13 @@ void DBDriver::addStatisticsAfterRun(
}
}
void DBDriver::addStatistics(const Statistics & statistics) const
{
_dbSafeAccessMutex.lock();
addStatisticsQuery(statistics);
_dbSafeAccessMutex.unlock();
}
void DBDriver::generateGraph(
const std::string & fileName,
const std::set<int> & idsInput,

View File

@@ -617,7 +617,15 @@ int DBDriverSqlite3::getLastNodesSizeQuery() const
int size = 0;
if(_ppDb)
{
std::string query = "SELECT count(id) from Node WHERE time_enter >= (SELECT MAX(time_enter) FROM Statistics);";
std::string query;
if(uStrNumCmp(_version, "0.11.11") >= 0)
{
query = "SELECT count(id) from Node WHERE time_enter >= (SELECT MAX(time_enter) FROM Info);";
}
else
{
query = "SELECT count(id) from Node WHERE time_enter >= (SELECT MAX(time_enter) FROM Statistics);";
}
int rc = SQLITE_OK;
sqlite3_stmt * ppStmt = 0;
@@ -641,7 +649,15 @@ int DBDriverSqlite3::getLastDictionarySizeQuery() const
int size = 0;
if(_ppDb)
{
std::string query = "SELECT count(id) from Word WHERE time_enter >= (SELECT MAX(time_enter) FROM Statistics);";
std::string query;
if(uStrNumCmp(_version, "0.11.11") >= 0)
{
query = "SELECT count(id) from Word WHERE time_enter >= (SELECT MAX(time_enter) FROM Info);";
}
else
{
query = "SELECT count(id) from Word WHERE time_enter >= (SELECT MAX(time_enter) FROM Statistics);";
}
int rc = SQLITE_OK;
sqlite3_stmt * ppStmt = 0;
@@ -716,9 +732,19 @@ ParametersMap DBDriverSqlite3::getLastParametersQuery() const
{
if(uStrNumCmp(_version, "0.11.8") >= 0)
{
std::string query = "SELECT parameters "
"FROM Statistics "
"WHERE time_enter >= (SELECT MAX(time_enter) FROM Statistics);";
std::string query;
if(uStrNumCmp(_version, "0.11.11") >= 0)
{
query = "SELECT parameters "
"FROM Info "
"WHERE time_enter >= (SELECT MAX(time_enter) FROM Info);";
}
else
{
query = "SELECT parameters "
"FROM Statistics "
"WHERE time_enter >= (SELECT MAX(time_enter) FROM Statistics);";
}
int rc = SQLITE_OK;
sqlite3_stmt * ppStmt = 0;
@@ -744,6 +770,44 @@ ParametersMap DBDriverSqlite3::getLastParametersQuery() const
return parameters;
}
std::map<std::string, float> DBDriverSqlite3::getStatisticsQuery(int nodeId, double & stamp) const
{
UDEBUG("");
std::map<std::string, float> data;
if(_ppDb)
{
if(uStrNumCmp(_version, "0.11.11") >= 0)
{
std::stringstream query;
query << "SELECT stamp, data "
<< "FROM Statistics "
<< "WHERE id=" << nodeId << ";";
int rc = SQLITE_OK;
sqlite3_stmt * ppStmt = 0;
rc = sqlite3_prepare_v2(_ppDb, query.str().c_str(), -1, &ppStmt, 0);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
rc = sqlite3_step(ppStmt);
if(rc == SQLITE_ROW)
{
stamp = sqlite3_column_double(ppStmt, 0);
std::string text((const char *)sqlite3_column_text(ppStmt, 1));
if(text.size())
{
data = Statistics::deserializeData(text);
}
rc = sqlite3_step(ppStmt);
}
UASSERT_MSG(rc == SQLITE_DONE, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
rc = sqlite3_finalize(ppStmt);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
}
}
return data;
}
void DBDriverSqlite3::loadNodeDataQuery(std::list<Signature *> & signatures, bool images, bool scan, bool userData, bool occupancyGrid) const
{
UDEBUG("load data for %d signatures", (int)signatures.size());
@@ -2127,10 +2191,20 @@ void DBDriverSqlite3::loadLastNodesQuery(std::list<Signature *> & nodes) const
std::string query;
std::list<int> ids;
query = "SELECT n.id "
"FROM Node AS n "
"WHERE n.time_enter >= (SELECT MAX(time_enter) FROM Statistics) "
"ORDER BY n.id;";
if(uStrNumCmp(_version, "0.11.11") >= 0)
{
query = "SELECT n.id "
"FROM Node AS n "
"WHERE n.time_enter >= (SELECT MAX(time_enter) FROM Info) "
"ORDER BY n.id;";
}
else
{
query = "SELECT n.id "
"FROM Node AS n "
"WHERE n.time_enter >= (SELECT MAX(time_enter) FROM Statistics) "
"ORDER BY n.id;";
}
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
@@ -2169,10 +2243,20 @@ void DBDriverSqlite3::loadQuery(VWDictionary * dictionary) const
std::list<VisualWord *> visualWords;
// Get the visual words
query = "SELECT id, descriptor_size, descriptor "
"FROM Word "
"WHERE time_enter >= (SELECT MAX(time_enter) FROM Statistics) "
"ORDER BY id;";
if(uStrNumCmp(_version, "0.11.11") >= 0)
{
query = "SELECT id, descriptor_size, descriptor "
"FROM Word "
"WHERE time_enter >= (SELECT MAX(time_enter) FROM Info) "
"ORDER BY id;";
}
else
{
query = "SELECT id, descriptor_size, descriptor "
"FROM Word "
"WHERE time_enter >= (SELECT MAX(time_enter) FROM Statistics) "
"ORDER BY id;";
}
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
@@ -3077,6 +3161,52 @@ void DBDriverSqlite3::updateOccupancyGridQuery(
}
}
void DBDriverSqlite3::addStatisticsQuery(const Statistics & statistics) const
{
UDEBUG("");
if(_ppDb)
{
std::string type;
UTimer timer;
timer.start();
int rc = SQLITE_OK;
sqlite3_stmt * ppStmt = 0;
// Create query
if(uStrNumCmp(this->getDatabaseVersion(), "0.11.11") >= 0)
{
std::string param = Statistics::serializeData(statistics.data());
if(param.size() && statistics.refImageId()>0)
{
std::string query = "INSERT INTO Statistics(id, stamp, data) values(?,?,?);";
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
int index = 1;
rc = sqlite3_bind_int(ppStmt, index++, statistics.refImageId());
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
rc = sqlite3_bind_double(ppStmt, index++, statistics.stamp());
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
rc = sqlite3_bind_text(ppStmt, index++, param.c_str(), -1, SQLITE_STATIC);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
//step
rc=sqlite3_step(ppStmt);
UASSERT_MSG(rc == SQLITE_DONE, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
rc = sqlite3_reset(ppStmt);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
// Finalize (delete) the statement
rc = sqlite3_finalize(ppStmt);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
UDEBUG("Time=%fs", timer.ticks());
}
}
}
}
std::string DBDriverSqlite3::queryStepNode() const
{
if(uStrNumCmp(_version, "0.11.1") >= 0)

View File

@@ -63,6 +63,7 @@ private:
virtual int getTotalNodesSizeQuery() const;
virtual int getTotalDictionarySizeQuery() const;
virtual ParametersMap getLastParametersQuery() const;
virtual std::map<std::string, float> getStatisticsQuery(int nodeId, double & stamp) const;
virtual void executeNoResultQuery(const std::string & sql) const;
@@ -83,6 +84,8 @@ private:
float cellSize,
const cv::Point3f & viewpoint) const;
virtual void addStatisticsQuery(const Statistics & statistics) const;
// Load objects
virtual void loadQuery(VWDictionary * dictionary) const;
virtual void loadLastNodesQuery(std::list<Signature *> & signatures) const;

View File

@@ -1285,7 +1285,7 @@ void Memory::clear()
if(_memoryChanged)
{
UDEBUG("");
_dbDriver->addStatisticsAfterRun(memSize,
_dbDriver->addInfoAfterRun(memSize,
_lastSignature?_lastSignature->id():0,
UProcessInfo::getMemoryUsage(),
_dbDriver->getMemoryUsed(),
@@ -1582,6 +1582,14 @@ int Memory::cleanup()
return signatureRemoved;
}
void Memory::saveStatistics(const Statistics & statistics)
{
if(_dbDriver)
{
_dbDriver->addStatistics(statistics);
}
}
void Memory::emptyTrash()
{
if(_dbDriver)

View File

@@ -2557,6 +2557,9 @@ bool Rtabmap::process(
UDEBUG("");
}
//Save statistics to database
_memory->saveStatistics(statistics_);
//Start trashing
UDEBUG("Empty trash...");
_memory->emptyTrash();

View File

@@ -27,6 +27,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/Statistics.h"
#include <rtabmap/utilite/UStl.h>
#include <rtabmap/utilite/UConversion.h>
namespace rtabmap {
std::map<std::string, float> Statistics::_defaultData;
@@ -38,11 +39,44 @@ const std::map<std::string, float> & Statistics::defaultData()
return _defaultData;
}
std::string Statistics::serializeData(const std::map<std::string, float> & data)
{
std::stringstream output;
for(std::map<std::string, float>::const_iterator iter=data.begin(); iter!=data.end(); ++iter)
{
if(iter != data.begin())
{
output << ";";
}
// make sure there are no commas instead of dots
output << iter->first << ":" << uReplaceChar(uNumber2Str(iter->second), ',', '.');
}
return output.str();
}
std::map<std::string, float> Statistics::deserializeData(const std::string & data)
{
std::map<std::string, float> output;
std::list<std::string> tuplets = uSplit(data, ';');
for(std::list<std::string>::iterator iter=tuplets.begin(); iter!=tuplets.end(); ++iter)
{
std::list<std::string> p = uSplit(*iter, ':');
if(p.size() == 2)
{
std::string key = p.front();
std::string value = p.back();
uInsert(output, std::make_pair(key, uStr2Float(value)));
}
}
return output;
}
Statistics::Statistics() :
_extended(0),
_refImageId(0),
_loopClosureId(0),
_proximiyDetectionId(0),
_stamp(0.0f),
_currentGoalId(0)
{
_defaultDataInitialized = true;

View File

@@ -85,7 +85,7 @@ CREATE TABLE Map_Node_Word (
FOREIGN KEY (word_id) REFERENCES Word(id)
);
CREATE TABLE Statistics (
CREATE TABLE Info (
STM_size INTEGER,
last_sign_added INTEGER,
process_mem_used INTEGER,
@@ -95,6 +95,13 @@ CREATE TABLE Statistics (
time_enter DATE
);
CREATE TABLE Statistics (
id INTEGER NOT NULL,
stamp FLOAT,
data TEXT,
FOREIGN KEY (id) REFERENCES Node(id)
);
CREATE TABLE Admin (
version TEXT,
time_enter DATE
@@ -120,18 +127,19 @@ BEGIN
UPDATE Word SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
END;
CREATE TRIGGER insert_Statistics_timeEnter AFTER INSERT ON Statistics
CREATE TRIGGER insert_Info_timeEnter AFTER INSERT ON Info
BEGIN
UPDATE Statistics SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
UPDATE Info SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
END;
-- *******************************************************************
-- INDEXES
-- *******************************************************************
CREATE UNIQUE INDEX IDX_Node_id on Node (id);
CREATE INDEX IDX_Map_Node_Word_node_id on Map_Node_Word (node_id);
CREATE INDEX IDX_Link_from_id on Link (from_id);
CREATE UNIQUE INDEX IDX_node_label on Node (label);
CREATE UNIQUE INDEX IDX_Statistics_id on Statistics (id);
-- *******************************************************************
-- VERSION