Odd performance issue with nested for loops - c++

Below is the full source code you can just copy paste into Visual Studio for easy repro.
#include <Windows.h>
#include <algorithm>
#include <vector>
#include <iostream>
#include <sstream>
LARGE_INTEGER gFreq;
struct CProfileData;
// Yes, we map the pointer itself not the string, for performance reasons
std::vector<CProfileData*> gProfileData;
// simulate a draw buffer access to avoid CBlock::Draw being optimized away
float gDrawBuffer = 0;
struct CTimer
{
CTimer()
{
Reset();
}
size_t GetElapsedMicro()
{
LARGE_INTEGER now;
::QueryPerformanceCounter(&now);
return (1000000 * (now.QuadPart - m_timer.QuadPart)) / gFreq.QuadPart;
}
inline void Reset()
{
::QueryPerformanceCounter(&m_timer);
}
LARGE_INTEGER m_timer;
};
struct CProfileData
{
CProfileData() : m_hitCount(0), m_totalTime(0), m_minTime(-1),
m_maxTime(0), m_name(NULL)
{
gProfileData.push_back(this);
}
size_t m_totalTime;
size_t m_minTime;
size_t m_maxTime;
size_t m_hitCount;
const char * m_name;
};
class CSimpleProfiler
{
public:
CSimpleProfiler(const char * aLocationName, CProfileData * aData)
: m_location(aLocationName), m_data(aData)
{
::QueryPerformanceCounter(&m_clock);
}
~CSimpleProfiler()
{
CProfileData & data = *m_data;
data.m_name = m_location;
++data.m_hitCount;
LARGE_INTEGER now;
::QueryPerformanceCounter(&now);
size_t elapsed = (1000000 * (now.QuadPart - m_clock.QuadPart)) / gFreq.QuadPart;
data.m_totalTime += elapsed;
elapsed < data.m_minTime ? data.m_minTime = elapsed : true;
elapsed > data.m_maxTime ? data.m_maxTime = elapsed : true;
}
static void PrintAll()
{
std::stringstream str;
str.width(20);
str << "Location";
str.width(15);
str << "Total time";
str.width(15);
str << "Average time";
str.width(15);
str << "Hit count";
str.width(15);
str << "Min";
str.width(15);
str << "Max" << std::endl;
::OutputDebugStringA(str.str().c_str());
for (auto i = gProfileData.begin(); i != gProfileData.end(); ++i)
{
CProfileData & data = **i;
std::stringstream str;
str.width(20);
str << data.m_name;
str.width(15);
str << data.m_totalTime;
str.width(15);
str << data.m_totalTime / (float)data.m_hitCount;
str.width(15);
str << data.m_hitCount;
str.width(15);
str << data.m_minTime;
str.width(15);
str << data.m_maxTime << std::endl;
::OutputDebugStringA(str.str().c_str());
}
}
static void Clear()
{
for (auto i = gProfileData.begin(); i != gProfileData.end(); ++i)
{
(*i)->m_totalTime = 0;
(*i)->m_minTime = 0;
(*i)->m_maxTime = 0;
(*i)->m_hitCount = 0;
}
}
private:
LARGE_INTEGER m_clock;
const char * m_location;
CProfileData * m_data;
};
#define PROFILING_ENABLED
#ifdef PROFILING_ENABLED
#define SIMPLE_PROFILE \
static CProfileData pdata ## __LINE__; \
CSimpleProfiler p ## __LINE__(__FUNCTION__, & pdata ## __LINE__)
#define SIMPLE_PROFILE_WITH_NAME(Name) \
static CProfileData pdata ## __LINE__; \
CSimpleProfiler p ## __LINE__(Name, & pdata ## __LINE__)
#else
#define SIMPLE_PROFILE __noop
#define SIMPLE_PROFILE_WITH_NAME(Name) __noop
#endif
void InvalidateL1Cache()
{
const int size = 256 * 1024;
static char *c = (char *)malloc(size);
for (int i = 0; i < 0x0fff; i++)
for (int j = 0; j < size; j++)
c[j] = i*j;
}
int _tmain(int argc, _TCHAR* argv[])
{
::QueryPerformanceFrequency(&gFreq);
LARGE_INTEGER pc;
::QueryPerformanceCounter(&pc);
struct CBlock
{
float x;
float y;
void Draw(float aBlend)
{
for (size_t i = 0; i < 100; ++i )
gDrawBuffer += aBlend;
}
};
typedef std::vector<std::vector<CBlock>> Layer;
typedef std::vector<Layer> Layers;
Layers mBlocks;
// populate with dummy data;
mBlocks.push_back(Layer());
Layer & layer = mBlocks.back();
layer.resize(109);
srand(0); // for reprodicibility (determinism)
for (auto i = layer.begin(); i != layer.end(); ++i)
{
i->resize(25 + rand() % 10 - 5);
}
// end populating dummy data
while (1)
{
CSimpleProfiler::Clear();
float aBlend = 1.f / (rand() % 100);
{
for (auto i = mBlocks.begin(); i != mBlocks.end(); ++i)
{
for (auto j = i->begin(); j != i->end(); ++j)
{
CTimer t;
{
SIMPLE_PROFILE_WITH_NAME("Main_Draw_3");
for (auto blockIt = j->begin(); blockIt != j->end();)
{
CBlock * b = nullptr;
{
b = &*blockIt;
}
{
b->Draw(aBlend);
}
{
++blockIt;
}
}
}
if (t.GetElapsedMicro() > 1000)
{
::OutputDebugStringA("SLOWDOWN!\n");
CSimpleProfiler::PrintAll();
}
}
}
}
}
return 0;
}
I get the following profiling from time to time, expressed in microseconds:
SLOWDOWN!
Location Total time Average time Hit count Min Max
Main_Draw_3 2047 36.5536 56 0 1040
This spikes from time to time. Normally, it takes 100 microseconds for Main_Draw_3 block to finish, but it spikes to 1000 (the Max column) from time to time. What causes this?
I'm aware cache misses could play a role, but is it really that in this case?... What is happening here and how can I mitigate this?
More info:
compiler VS 2013, compiled with Maximize Speed (/O2)

I think there might be two issues:
Are you compiling with optimizations on? What are the flags?
Maybe you could increase the sample size (by doing for instance ten (or hundred, or thousand etc) runs of this code in one profiling run). The reason is that if the sample size is small, the standard deviation is very high

Related

Why is the custom allocator significantly faster after adding a line of "memset"?

I am writing a "freelist allocator". I started with a line of memset in the initialization phase for debugging purposes. Later I removed the memset. But I found that the allocation part in the testing function test1_managed is running 3-4 times faster with the memset in the initialization than the one without. I am confused with the result. What reason could it be?
I compiled the code in Visual Studio 2019 (in Release mode) with MSVC 19.29.30140 and "/O2" optimization enabled.
Here is the code:
#pragma once
#include <cstdio>
#include <iostream>
#include <chrono>
using namespace std;
using namespace chrono;
const uint64_t MemSize = 1 << 20;
const uint64_t TestSize = 1 << 12;
typedef int TestType;
struct MemSegInfo {
MemSegInfo* m_next{ 0 };
MemSegInfo* m_nextFree{ 0 };
uint64_t m_size{ 0 };
uint64_t m_handle{ 0 };
};
const uint64_t infoSize = sizeof(MemSegInfo);
const uint64_t ptrSize = sizeof(MemSegInfo*);
const uint64_t maxAlignment = 16;
char* m_dataBuffer{ 0 };
char* m_dataBufferEnd{ 0 };
MemSegInfo* m_head;
MemSegInfo m_segFree;
MemSegInfo* m_segFreeCursor;
inline void* OffsetFromMemSegInfo(MemSegInfo* seg) {
return ((char*)seg) + infoSize;
}
inline MemSegInfo* OffsetToMemSegInfo(void* ptr) {
return (MemSegInfo*)(((char*)ptr) - infoSize);
}
template<class T>
inline void SetMem(MemSegInfo* seg, T&& val) {
*((T*)OffsetFromMemSegInfo(seg)) = val;
}
template<class T>
inline void SetMem(MemSegInfo* seg, const T& val) {
*((T*)OffsetFromMemSegInfo(seg)) = val;
}
template<class T>
inline T GetMem(MemSegInfo* seg) {
return *((T*)OffsetFromMemSegInfo(seg));
}
void Init() {
m_dataBuffer = (char*)malloc(MemSize);
if (!m_dataBuffer)
throw "Out of mem! ";
m_dataBufferEnd = m_dataBuffer + MemSize;
m_head = (MemSegInfo*)m_dataBuffer;
m_head->m_next = m_head;
//m_head->m_last = m_head;
m_head->m_size = MemSize - infoSize;
m_head->m_nextFree = &m_segFree;
m_segFree.m_size = 0;
m_segFree.m_nextFree = m_head;
m_segFreeCursor = &m_segFree;
/***THE MEMSET I AM TALKING ABOUT***/
memset(OffsetFromMemSegInfo(m_head), 0xfafafafa, m_head->m_size);
}
MemSegInfo* Allocate(size_t size) {
const uint64_t sizeAligned = ((size - 1) / maxAlignment + 1) * maxAlignment;
const uint64_t sizeAlloc = sizeAligned + infoSize;
MemSegInfo* segCurPrev = m_segFreeCursor;
while (segCurPrev->m_nextFree->m_size < sizeAlloc) { // Go through freelist to find the First Fit.
segCurPrev = segCurPrev->m_nextFree;
if (segCurPrev == m_segFreeCursor)
throw "Out of mem! ";
}
MemSegInfo* const segCur = segCurPrev->m_nextFree;
const uint64_t sizeRest = segCur->m_size - sizeAligned;
if (sizeRest <= infoSize) { // There is not enough space for another seg. Just gonna use it.
segCurPrev->m_nextFree = segCur->m_nextFree; // This can also deal with the case where this is the last one available.
m_segFreeCursor = segCurPrev;
}
else { // There is enough space for another seg. Separate and make a new seg.
MemSegInfo* const segNew = (MemSegInfo*)(((char*)segCur) + sizeAlloc);
MemSegInfo* const segNext = segCur->m_next;
MemSegInfo* const segNextFree = segCur->m_nextFree;
// Rearrange seg list
//segNew->m_last = segCur;
//segNext->m_last = segNew;
segNew->m_next = segNext;
segCur->m_next = segNew;
segNew->m_size = sizeRest - infoSize;
segCur->m_size = sizeAligned;
segCur->m_nextFree = nullptr;
// Join freelist
segNew->m_nextFree = segNextFree;
segCurPrev->m_nextFree = segNew;
m_segFreeCursor = segCurPrev;
}
return segCur;
}
inline void Free(MemSegInfo* segFree) {
// Join the freelist
segFree->m_nextFree = m_segFree.m_nextFree;
m_segFree.m_nextFree = segFree->m_nextFree;
}
void Cleanup() {
free(m_dataBuffer);
}
MemSegInfo* mems[16];
struct MyStruct
{
uint64_t m_a;
uint64_t m_b;
uint32_t m_c;
uint32_t m_d;
};
void test0() {
Init();
mems[0] = Allocate(8);
SetMem<uint64_t>(mems[0], 128);
uint64_t t0 = GetMem<uint64_t>(mems[0]);
mems[1] = Allocate(4);
uint64_t t1 = GetMem<uint64_t>(mems[0]);
SetMem<uint32_t>(mems[1], 256);
uint64_t t2 = GetMem<uint64_t>(mems[0]);
mems[2] = Allocate(64);
int* a = (int*)OffsetFromMemSegInfo(mems[2]);
for (int i = 0; i < 16; ++i) {
a[i] = i;
}
mems[3] = Allocate(sizeof(MyStruct) * 8);
MyStruct* b = (MyStruct*)OffsetFromMemSegInfo(mems[3]);
for (int i = 0; i < 8; ++i) {
b[i] = { (uint64_t)i, (uint64_t)i * 2, (uint32_t)i * 3, (uint32_t)i * 4 };
}
for (int i = 0; i < 16; ++i) {
printf("%d ", a[i]);
}
printf("\n");
Free(mems[1]);
printf("%lld\n", GetMem<uint64_t>(mems[0]));
for (int i = 0; i < 16; ++i) {
printf("%d ", a[i]);
}
printf("\n");
for (int i = 0; i < 8; ++i) {
printf("%lld %lld %ld %ld\t", b[i].m_a, b[i].m_b, b[i].m_c, b[i].m_d);
}
Cleanup();
}
TestType* bufferManaged[TestSize];
void test1_managed() {
Init();
/***ALLOCATION START***/
system_clock::time_point beg_alloc = system_clock::now();
TestType sum = 0;
for (uint64_t i = 0; i < TestSize; ++i) {
TestType val = i % INT32_MAX;
bufferManaged[i] = new (OffsetFromMemSegInfo(Allocate(sizeof(TestType)))) TestType(val);
sum += *bufferManaged[i];
}
/***ALLOCATION END***/
std::atomic_signal_fence(std::memory_order_seq_cst);
system_clock::time_point end_alloc = system_clock::now();
printf("managed %llu ns\n", (std::chrono::duration_cast<std::chrono::nanoseconds>(end_alloc - beg_alloc)).count());
printf("sum %d\n", sum);
system_clock::time_point beg_free = system_clock::now();
for (uint64_t i = 0; i < TestSize; ++i) {
Free((MemSegInfo*)OffsetToMemSegInfo(bufferManaged[i]));
}
Cleanup();
std::atomic_signal_fence(std::memory_order_seq_cst);
system_clock::time_point end_free = system_clock::now();
printf("managedfree %llu ns\n\n", (std::chrono::duration_cast<std::chrono::nanoseconds>(end_free - beg_free)).count());
}
TestType* bufferUnmanaged[TestSize];
void test1_unmnged() {
system_clock::time_point beg_alloc = system_clock::now();
TestType sum = 0;
for (uint64_t i = 0; i < TestSize; ++i) {
TestType val = i % INT32_MAX;
bufferUnmanaged[i] = new TestType(val);
sum += *bufferUnmanaged[i];
}
std::atomic_signal_fence(std::memory_order_seq_cst);
system_clock::time_point end_alloc = system_clock::now();
printf("unmnged %llu ns\n", (std::chrono::duration_cast<std::chrono::nanoseconds>(end_alloc - beg_alloc)).count());
printf("sum %d\n", sum);
system_clock::time_point beg_free = system_clock::now();
for (uint64_t i = 0; i < TestSize; ++i) {
delete bufferUnmanaged[i];
}
std::atomic_signal_fence(std::memory_order_seq_cst);
system_clock::time_point end_free = system_clock::now();
printf("unmngedfree %llu ns\n\n", (std::chrono::duration_cast<std::chrono::nanoseconds>(end_free - beg_free)).count());
}
void test1() {
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
auto epoch = now.time_since_epoch();
auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
long duration = value.count();
srand(duration);
for (int i = 0; i < 10; i++) {
printf("test%d\n", i);
test1_managed();
test1_unmnged();
printf("\n");
}
}
void test() {
test1();
}

How should I parse and check through a string?

Okay so I have a C++ project I want to complete which involves receiving NMEA sentences and parsing through them to check if they conform to the "grammar rules" of NMEA.
The current method I have been doing this is using if statements but this is obviously not good coding practice.
What are other methods I could use to attempt to check string sentences for specific characters and groups of characters?
Let us assume that you have NMEA data like this
$GPGGA,124613.90,5543.3221231,N,03739.1368442,E,1,15,0.69,147.0851,M,14.4298,M,,*54
$GPGSV,3,1,10,27,12,078,41,05,31,308,49,16,25,043,44,02,11,268,44*7E
$GPGSV,3,2,10,26,03,031,39,07,74,216,52,09,58,121,52,30,39,234,48*71
$GPGSV,3,3,10,23,30,116,46,04,37,114,47*79
$GLGSV,2,1,07,84,17,338,43,78,15,212,48,85,12,032,46,67,84,223,53*67
$GLGSV,2,2,07,77,67,195,47,76,50,047,54,66,32,144,52*5C
$GPGGA,124614.00,5543.3221239,N,03739.1368445,E,1,15,0.69,147.0864,M,14.4298,M,,*53
$GPGSV,3,1,10,27,12,078,41,05,31,308,49,16,25,043,43,02,11,268,44*79
$GPGSV,3,2,10,26,03,031,39,07,74,216,52,09,58,121,52,30,39,234,48*71
$GPGSV,3,3,10,23,30,116,46,04,37,114,47*79
$GLGSV,2,1,07,84,17,338,43,78,15,212,48,85,12,032,46,67,84,223,53*67
$GLGSV,2,2,07,77,67,195,47,76,50,047,54,66,32,144,52*5C
And if we want to extract GGA and GSV data, you may want to use the following code:
#include <string>
#include <ctime>
#include <cstring>
#include <iostream>
#include <fstream>
#include <iomanip>
constexpr size_t NumberOfFixQualityStrings = 9;
constexpr size_t NumberOfSatellitesPerGSVSentencePart = 4;
constexpr size_t MaxNumberOfPartsInSentence = 10;
constexpr size_t MaxTokensInSentence = 64;
constexpr size_t NumberOfFieldsInGGA = 12;
std::string fixQualityString[NumberOfFixQualityStrings]{
"invalid", "GPS fix (SPS)", "DGPS fix", "PPS fix", "Real Time Kinematic", "Float RTK",
"estimated (dead reckoning", "Manual input mode", "Simulation mode" };
// essential fix data which provide 3D location and accuracy data
struct GGA {
// Time of last satellite fix
unsigned int fixTimeInUtcHours{};
unsigned int fixTimeInUtcMinutes{};
unsigned int fixTimeInUtcSeconds{};
unsigned int fixTimeInUtcMilliSeconds{};
// Position: Lattitude
unsigned int lattitudeInDegree{};
double lattitudeInMinutes{};
std::string lattitideDirection{};
// Position: Longitude
unsigned int longitudeInDegree{};
double longitudeInMinutes{};
std::string longitudeDirection{};
// FixQuality // see dteails as string above
unsigned int fixQuality{};
std::string fixQualityString{};
// Number of satellites being tracked (can be more than shown in GSV, not all are beeing used for calculation)
unsigned int numberOfTrackedSatellites{};
// Horizontal dilution of position
double horizontalDilution{};
// Altitude, Meters, above mean sea level
double altitude{};
std::string altitudeDimension{};
// Height of geoid (mean sea level) above WGS84 ellipsoid
double goidHight{};
std::string goidHightDimension{};
};
// Detail information for satellites in satellit view (GSV)
struct SatelliteData {
std::string satellitePRNnumber{};
double elevationInDegress{};
double azimuthInDegrees{};
double snr{}; // signal noise ratio
};
// Part of a GSV sentence
struct GSVSentencePart {
size_t numberOfSentencesForFullData{};
size_t sentencePartNumber{};
size_t numberOfSatellitesInView{};
size_t numberOfSatellitesInThisPart{};
SatelliteData satelliteData[NumberOfSatellitesPerGSVSentencePart];
};
struct GSV
{
GSVSentencePart gsvSentencePart[MaxNumberOfPartsInSentence];
size_t numberOfParts{};
};
bool checksumTest(std::string& line) {
bool result{ false };
// Check, if there is a 2 digt checksum at the end and convert it to decimal
if (size_t pos{}, checkSumGiven{ std::stoul(line.substr(line.size() - 2), &pos, 16) }; pos == 2)
{
// Strip off checksum part
line = line.substr(1,line.size() - 4);
// Calculate checksum
unsigned char calculatedChecksum{ 0U }; for (const unsigned char c : line) calculatedChecksum ^= c;
// Get result
result = (calculatedChecksum == checkSumGiven);
}
return result;
}
// Split all strings into a tokens
size_t splitIntoTokens(std::string& s, std::string (&tokens)[MaxTokensInSentence]) {
// Number of converted tokens
size_t numberOfTokens{ 0 };
// First check checksum
if (checksumTest(s)) {
// Now split along each comma
for (size_t i{ 0U }, startpos{ 0U }; i < s.size(); ++i) {
// So, if there is a comma or the end of the string
if ((s[i] == ',') || (i == (s.size() - 1))) {
// Copy substring
tokens[numberOfTokens++] = s.substr(startpos, i - startpos);
startpos = i + 1;
}
}
}
return numberOfTokens;
}
GGA convertStringToGGA(std::string& s) {
GGA gga;
// Split string into tokens and check, if it worked
if (std::string tokens[MaxTokensInSentence]; splitIntoTokens(s, tokens) > NumberOfFieldsInGGA && tokens[0] == "GPGGA") {
gga.fixTimeInUtcHours = std::stoul(tokens[1].substr(0, 2));
gga.fixTimeInUtcMinutes = std::stoul(tokens[1].substr(2, 2));
gga.fixTimeInUtcSeconds = std::stoul(tokens[1].substr(4, 2));
gga.fixTimeInUtcMilliSeconds = std::stod(tokens[1].substr(6, 2))*1000.0;
gga.lattitudeInDegree = std::stoul(tokens[2].substr(0, 2));
gga.lattitudeInMinutes = std::stod(tokens[2].substr(2));
gga.lattitideDirection = tokens[3];
gga.longitudeInDegree = std::stoul(tokens[4].substr(0, 2));
gga.longitudeInMinutes = std::stod(tokens[4].substr(2));
gga.longitudeDirection = tokens[5];
gga.fixQuality = std::stoul(tokens[6]);
gga.fixQualityString = (gga.fixQuality < NumberOfFixQualityStrings) ? fixQualityString[gga.fixQuality] : fixQualityString[0];
gga.numberOfTrackedSatellites = std::stoul(tokens[7]);
gga.horizontalDilution = std::stod(tokens[8]);
gga.altitude = std::stod(tokens[9]);
gga.altitudeDimension = tokens[10];
gga.goidHight = std::stod(tokens[11]);
gga.goidHightDimension = tokens[12];
}
return gga;
}
GSVSentencePart convertToGSVSentencePart(std::string& s) {
GSVSentencePart gsvsp;
// Split string into tokens and check, if it worked
std::string tokens[MaxTokensInSentence];
if (size_t numberOfCOnvertedTokens = splitIntoTokens(s, tokens); numberOfCOnvertedTokens > 0 && tokens[0] == "GPGSV") {
gsvsp.numberOfSentencesForFullData = std::stoul(tokens[1]);
gsvsp.sentencePartNumber = std::stoul(tokens[2]);
gsvsp.numberOfSatellitesInView = std::stoul(tokens[3]);
gsvsp.numberOfSatellitesInThisPart = 0;
for (size_t currentToken = 4; currentToken < numberOfCOnvertedTokens; currentToken += 4) {
gsvsp.satelliteData[gsvsp.numberOfSatellitesInThisPart].satellitePRNnumber = tokens[currentToken];
gsvsp.satelliteData[gsvsp.numberOfSatellitesInThisPart].elevationInDegress = stod(tokens[currentToken + 1]);
gsvsp.satelliteData[gsvsp.numberOfSatellitesInThisPart].azimuthInDegrees= stod(tokens[currentToken + 2]);
gsvsp.satelliteData[gsvsp.numberOfSatellitesInThisPart].snr = stod(tokens[currentToken + 3]);
++gsvsp.numberOfSatellitesInThisPart;
}
}
return gsvsp;
}
std::string calculateElapsedTime(const GGA& previousGGA, const GGA& nextGGA) {
std::tm tmPrevious{}, tmNext{};
tmPrevious.tm_year = 100; tmPrevious.tm_mon = 1; tmPrevious.tm_mday = 1;
tmNext.tm_year = 100; tmNext.tm_mon = 1; tmNext.tm_mday = 1;
tmPrevious.tm_hour = previousGGA.fixTimeInUtcHours;
tmPrevious.tm_min = previousGGA.fixTimeInUtcMinutes;
tmPrevious.tm_sec = previousGGA.fixTimeInUtcSeconds;
std::time_t previousTime = std::mktime(&tmPrevious);
tmNext.tm_hour = nextGGA.fixTimeInUtcHours;
tmNext.tm_min = nextGGA.fixTimeInUtcMinutes;
tmNext.tm_sec = nextGGA.fixTimeInUtcSeconds;
std::time_t nextTime = std::mktime(&tmNext);
double diff = std::difftime(nextTime, previousTime);
diff = diff + 1.0*nextGGA.fixTimeInUtcMilliSeconds/1000.0- 1.0*previousGGA.fixTimeInUtcMilliSeconds/1000.0;
return std::to_string(diff);
}
int main() {
// Open file and check, if it is open
if (std::ifstream nmeaFile("r:\\log.txt"); nmeaFile) {
GGA previousGGA;
GGA nextGGA;
GSV gsv;
size_t state{ 0 };
for (std::string line{}; std::getline(nmeaFile, line); ) {
switch ( state) {
case 0: // wait for first GGA data
if (line.substr(0, 6) == "$GPGGA") {
previousGGA = nextGGA;
nextGGA = convertStringToGGA(line);
state = 1;
gsv = {};
}
break;
case 1: // wait for GSV
if (line.substr(0, 6) == "$GPGSV") {
gsv.gsvSentencePart[gsv.numberOfParts] = convertToGSVSentencePart(line);
if (gsv.gsvSentencePart[gsv.numberOfParts].numberOfSentencesForFullData ==
gsv.gsvSentencePart[gsv.numberOfParts].sentencePartNumber) {
state = 0;
++gsv.numberOfParts;
// Now all data are available in reable and structed format.
// You can do, what you want with them
// For example, we can print all Satellite Data:
size_t counter{ 0 };
for (size_t i = 0; i < gsv.numberOfParts; ++i) {
for (size_t j = 0; j < gsv.gsvSentencePart[i].numberOfSatellitesInThisPart; j++) {
std::cout << "Satellite: " << std::setw(2) << ++counter << " Satellite name: " <<
std::setw(3) << gsv.gsvSentencePart[i].satelliteData[j].satellitePRNnumber <<
" SNR: " << std::setw(8) << gsv.gsvSentencePart[i].satelliteData[j].snr <<
" Elapsed time: "<< calculateElapsedTime(previousGGA, nextGGA)<< " s\n";
}
}
--gsv.numberOfParts;
}
++gsv.numberOfParts;
}
break;
}
}
}
return 0;
}
Coding style is "beginner"-level for easier understanding.
Modern C++ approach would be totally different, but not so easy to understand.

parsing text and output "time of appearance" of some lines [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
So I got file that look like:
$GPGGA,124613.90,5543.3221231,N,03739.1368442,E,1,15,0.69,147.0851,M,14.4298,M,,*54
$GPGSV,3,1,10,27,12,078,41,05,31,308,49,16,25,043,44,02,11,268,44*7E
$GPGSV,3,2,10,26,03,031,39,07,74,216,52,09,58,121,52,30,39,234,48*71
$GPGSV,3,3,10,23,30,116,46,04,37,114,47*79
$GLGSV,2,1,07,84,17,338,43,78,15,212,48,85,12,032,46,67,84,223,53*67
$GLGSV,2,2,07,77,67,195,47,76,50,047,54,66,32,144,52*5C
$GPGGA,124614.00,5543.3221239,N,03739.1368445,E,1,15,0.69,147.0864,M,14.4298,M,,*53
$GPGSV,3,1,10,27,12,078,41,05,31,308,49,16,25,043,43,02,11,268,44*79
$GPGSV,3,2,10,26,03,031,39,07,74,216,52,09,58,121,52,30,39,234,48*71
$GPGSV,3,3,10,23,30,116,46,04,37,114,47*79
$GLGSV,2,1,07,84,17,338,43,78,15,212,48,85,12,032,46,67,84,223,53*67
$GLGSV,2,2,07,77,67,195,47,76,50,047,54,66,32,144,52*5C
My cod is checking check sum of string and output some values in strings.
In $GPGGA line "124614.00" is time. 12 hours 46 minutes 14.00 sec. I need to output time of "appearance" $GPGSV lines. I`ve tried subtract first value and the following ones through the pointer, but I must have messed up somewhere.
#include <iostream>
#include <fstream>
#include <string>
#include <stdlib.h>
#include <numeric>
#include <cstdlib>
#include <cstring>
#include <stdio.h>
int checksum(const char* s) {
int c = 0;
while (*s)
c ^= *s++;
return c;
}
int main() {
char linec_h[200];
int k, key;
int* hour = NULL;
int* minute = NULL;
float* sec = NULL;
std::string line, key_s;
std::ifstream logs_("C:/Users/Olya/Desktop/broken.txt");
std::ofstream pout("C:/Users/Olya/Desktop/outLOG.txt");
if (logs_.is_open()) {
while (getline(logs_, line)) {
key_s = line.substr(line.length() - 2, 2);
key = strtol(key_s.c_str(), NULL, 16);
line = line.substr(1, line.length() - 4);
strcpy_s(linec_h, line.c_str());
if (key != checksum(linec_h))
pout << "Line is corrupted!" << std::endl;
else {
k = 0;
if (line.substr(0, 5) == "GPGGA") {
if (hour, minute, sec) {
*hour = stoi(line.substr(5, 2)) - *hour;
*minute = stoi(line.substr(7, 2)) - *minute;
*sec = stof(line.substr(9, 4)) - *sec;
}
else {
hour = new int;
minute = new int;
sec = new float;
*hour = stoi(line.substr(5, 2));
*minute = stoi(line.substr(7, 2));
*sec = stof(line.substr(9, 4));
}
} else if (line.substr(0, 5) == "GPGSV") {
for (size_t i = 0, SNR = 7, N = 4; i < line.size(); i++) {
if (line[i] == ',')
k++;
if (k == N) {
pout << "Satellite number -- " << line.substr(i + 1, 2) << " ";
if ((N += 4) > 16)
;
} else if (k == SNR) {
pout << "SNR -- " << line.substr(i + 1, 2) << " time -- " << hour
<< "." << minute << "." << sec << std::endl;
if ((SNR += 4) > 19)
break;
}
}
}
}
delete hour;
delete minute;
delete sec;
}
logs_.close();
std::cout << "Success" << std::endl;
} else
std::cout << "File is not open" << '\n';
pout.close();
return 0;
}
Just for the FUn of it. I created a complete solution which parses your GPS NMEA format completely and put all results in structs. So you can get ALL satellite data.
However. I show only the values that you used in your example.
I adapted my coding style to yours. In C++ I would do things completel different. Anyway.
Please find attached an complete example:
#include <string>
#include <ctime>
#include <cstring>
#include <iostream>
#include <fstream>
#include <iomanip>
constexpr size_t NumberOfFixQualityStrings = 9;
constexpr size_t NumberOfSatellitesPerGSVSentencePart = 4;
constexpr size_t MaxNumberOfPartsInSentence = 10;
constexpr size_t MaxTokensInSentence = 64;
constexpr size_t NumberOfFieldsInGGA = 12;
std::string fixQualityString[NumberOfFixQualityStrings]{
"invalid", "GPS fix (SPS)", "DGPS fix", "PPS fix", "Real Time Kinematic", "Float RTK",
"estimated (dead reckoning", "Manual input mode", "Simulation mode" };
// essential fix data which provide 3D location and accuracy data
struct GGA {
// Time of last satellite fix
unsigned int fixTimeInUtcHours{};
unsigned int fixTimeInUtcMinutes{};
unsigned int fixTimeInUtcSeconds{};
unsigned int fixTimeInUtcMilliSeconds{};
// Position: Lattitude
unsigned int lattitudeInDegree{};
double lattitudeInMinutes{};
std::string lattitideDirection{};
// Position: Longitude
unsigned int longitudeInDegree{};
double longitudeInMinutes{};
std::string longitudeDirection{};
// FixQuality // see dteails as string above
unsigned int fixQuality{};
std::string fixQualityString{};
// Number of satellites being tracked (can be more than shown in GSV, not all are beeing used for calculation)
unsigned int numberOfTrackedSatellites{};
// Horizontal dilution of position
double horizontalDilution{};
// Altitude, Meters, above mean sea level
double altitude{};
std::string altitudeDimension{};
// Height of geoid (mean sea level) above WGS84 ellipsoid
double goidHight{};
std::string goidHightDimension{};
};
// Detail information for satellites in satellit view (GSV)
struct SatelliteData {
std::string satellitePRNnumber{};
double elevationInDegress{};
double azimuthInDegrees{};
double snr{}; // signal noise ratio
};
// Part of a GSV sentence
struct GSVSentencePart {
size_t numberOfSentencesForFullData{};
size_t sentencePartNumber{};
size_t numberOfSatellitesInView{};
size_t numberOfSatellitesInThisPart{};
SatelliteData satelliteData[NumberOfSatellitesPerGSVSentencePart];
};
struct GSV
{
GSVSentencePart gsvSentencePart[MaxNumberOfPartsInSentence];
size_t numberOfParts{};
};
bool checksumTest(std::string& line) {
bool result{ false };
// Check, if there is a 2 digt checksum at the end and convert it to decimal
if (size_t pos{}, checkSumGiven{ std::stoul(line.substr(line.size() - 2), &pos, 16) }; pos == 2)
{
// Strip off checksum part
line = line.substr(1,line.size() - 4);
// Calculate checksum
unsigned char calculatedChecksum{ 0U }; for (const unsigned char c : line) calculatedChecksum ^= c;
// Get result
result = (calculatedChecksum == checkSumGiven);
}
return result;
}
// Split all strings into a tokens
size_t splitIntoTokens(std::string& s, std::string (&tokens)[MaxTokensInSentence]) {
// Number of converted tokens
size_t numberOfTokens{ 0 };
// First check checksum
if (checksumTest(s)) {
// Now split along each comma
for (size_t i{ 0U }, startpos{ 0U }; i < s.size(); ++i) {
// So, if there is a comma or the end of the string
if ((s[i] == ',') || (i == (s.size() - 1))) {
// Copy substring
tokens[numberOfTokens++] = s.substr(startpos, i - startpos);
startpos = i + 1;
}
}
}
return numberOfTokens;
}
GGA convertStringToGGA(std::string& s) {
GGA gga;
// Split string into tokens and check, if it worked
if (std::string tokens[MaxTokensInSentence]; splitIntoTokens(s, tokens) > NumberOfFieldsInGGA && tokens[0] == "GPGGA") {
gga.fixTimeInUtcHours = std::stoul(tokens[1].substr(0, 2));
gga.fixTimeInUtcMinutes = std::stoul(tokens[1].substr(2, 2));
gga.fixTimeInUtcSeconds = std::stoul(tokens[1].substr(4, 2));
gga.fixTimeInUtcMilliSeconds = std::stod(tokens[1].substr(6, 2))*1000.0;
gga.lattitudeInDegree = std::stoul(tokens[2].substr(0, 2));
gga.lattitudeInMinutes = std::stod(tokens[2].substr(2));
gga.lattitideDirection = tokens[3];
gga.longitudeInDegree = std::stoul(tokens[4].substr(0, 2));
gga.longitudeInMinutes = std::stod(tokens[4].substr(2));
gga.longitudeDirection = tokens[5];
gga.fixQuality = std::stoul(tokens[6]);
gga.fixQualityString = (gga.fixQuality < NumberOfFixQualityStrings) ? fixQualityString[gga.fixQuality] : fixQualityString[0];
gga.numberOfTrackedSatellites = std::stoul(tokens[7]);
gga.horizontalDilution = std::stod(tokens[8]);
gga.altitude = std::stod(tokens[9]);
gga.altitudeDimension = tokens[10];
gga.goidHight = std::stod(tokens[11]);
gga.goidHightDimension = tokens[12];
}
return gga;
}
GSVSentencePart convertToGSVSentencePart(std::string& s) {
GSVSentencePart gsvsp;
// Split string into tokens and check, if it worked
std::string tokens[MaxTokensInSentence];
if (size_t numberOfCOnvertedTokens = splitIntoTokens(s, tokens); numberOfCOnvertedTokens > 0 && tokens[0] == "GPGSV") {
gsvsp.numberOfSentencesForFullData = std::stoul(tokens[1]);
gsvsp.sentencePartNumber = std::stoul(tokens[2]);
gsvsp.numberOfSatellitesInView = std::stoul(tokens[3]);
gsvsp.numberOfSatellitesInThisPart = 0;
for (size_t currentToken = 4; currentToken < numberOfCOnvertedTokens; currentToken += 4) {
gsvsp.satelliteData[gsvsp.numberOfSatellitesInThisPart].satellitePRNnumber = tokens[currentToken];
gsvsp.satelliteData[gsvsp.numberOfSatellitesInThisPart].elevationInDegress = stod(tokens[currentToken + 1]);
gsvsp.satelliteData[gsvsp.numberOfSatellitesInThisPart].azimuthInDegrees= stod(tokens[currentToken + 2]);
gsvsp.satelliteData[gsvsp.numberOfSatellitesInThisPart].snr = stod(tokens[currentToken + 3]);
++gsvsp.numberOfSatellitesInThisPart;
}
}
return gsvsp;
}
std::string calculateElapsedTime(const GGA& previousGGA, const GGA& nextGGA) {
std::tm tmPrevious{}, tmNext{};
tmPrevious.tm_year = 100; tmPrevious.tm_mon = 1; tmPrevious.tm_mday = 1;
tmNext.tm_year = 100; tmNext.tm_mon = 1; tmNext.tm_mday = 1;
tmPrevious.tm_hour = previousGGA.fixTimeInUtcHours;
tmPrevious.tm_min = previousGGA.fixTimeInUtcMinutes;
tmPrevious.tm_sec = previousGGA.fixTimeInUtcSeconds;
std::time_t previousTime = std::mktime(&tmPrevious);
tmNext.tm_hour = nextGGA.fixTimeInUtcHours;
tmNext.tm_min = nextGGA.fixTimeInUtcMinutes;
tmNext.tm_sec = nextGGA.fixTimeInUtcSeconds;
std::time_t nextTime = std::mktime(&tmNext);
double diff = std::difftime(nextTime, previousTime);
diff = diff + 1.0*nextGGA.fixTimeInUtcMilliSeconds/1000.0- 1.0*previousGGA.fixTimeInUtcMilliSeconds/1000.0;
return std::to_string(diff);
}
int main() {
// Open file and check, if it is open
if (std::ifstream nmeaFile("r:\\log.txt"); nmeaFile) {
GGA previousGGA;
GGA nextGGA;
GSV gsv;
size_t state{ 0 };
for (std::string line{}; std::getline(nmeaFile, line); ) {
switch ( state) {
case 0: // wait for first GGA data
if (line.substr(0, 6) == "$GPGGA") {
previousGGA = nextGGA;
nextGGA = convertStringToGGA(line);
state = 1;
gsv = {};
}
break;
case 1: // wait for GSV
if (line.substr(0, 6) == "$GPGSV") {
gsv.gsvSentencePart[gsv.numberOfParts] = convertToGSVSentencePart(line);
if (gsv.gsvSentencePart[gsv.numberOfParts].numberOfSentencesForFullData ==
gsv.gsvSentencePart[gsv.numberOfParts].sentencePartNumber) {
state = 0;
++gsv.numberOfParts;
// Now all data are available in reable and structed format.
// You can do, what you want with them
// For example, we can print all Satellite Data:
size_t counter{ 0 };
for (size_t i = 0; i < gsv.numberOfParts; ++i) {
for (size_t j = 0; j < gsv.gsvSentencePart[i].numberOfSatellitesInThisPart; j++) {
std::cout << "Satellite: " << std::setw(2) << ++counter << " Satellite name: " <<
std::setw(3) << gsv.gsvSentencePart[i].satelliteData[j].satellitePRNnumber <<
" SNR: " << std::setw(8) << gsv.gsvSentencePart[i].satelliteData[j].snr <<
" Elapsed time: "<< calculateElapsedTime(previousGGA, nextGGA)<< " s\n";
}
}
--gsv.numberOfParts;
}
++gsv.numberOfParts;
}
break;
}
}
}
return 0;
}
I can see bugs like if (hour, minute, sec) { and many C-Style code, operating with pointers or so. I do not want to debug you code.
As a samll hint for you, I created a parser that reads all source lines, splits tem into tokens and checks the checksum.
Only a few lines of code will do the trick. From that on you can develop further.
#include <iostream>
#include <regex>
#include <vector>
#include <iterator>
#include <string>
#include <utility>
#include <algorithm>
#include <functional>
#include <numeric>
#include <fstream>
const std::regex re{ R"(\$(.*)\*[abcdefABCDEF\d]{2})" };
const std::regex delimiter{ "," };
using Tokens = std::vector<std::string>;
std::tuple<bool, Tokens> checkString(const std::string& str) {
// Return value of the function. Assume that string is not ok
std::tuple<bool, std::vector<std::string>> result(false, {});
// We want to find a string in the given format
std::smatch sm{};
if (std::regex_match(str, sm, re)) {
// OK, found. Validate checksum
if (std::string s = sm[1]; std::stoul(str.substr(str.size() - 2), nullptr, 16) == std::accumulate(s.begin(), s.end(), 0U, std::bit_xor<unsigned char>())) {
// Tokenize string
Tokens tokens(std::sregex_token_iterator(str.begin(), str.end(), delimiter, -1), {});
// Build return value
result = std::make_tuple(true, std::move(tokens));
}
}
return result;
}
int main() {
std::vector<Tokens> csvData{};
// Open file and check if it is open
if (std::ifstream logs("r:\\log.txt"); logs) {
// Read all lines of files
for (std::string line{}; std::getline(logs, line);) {
if (const auto& [ok, data] = checkString(line); ok) {
csvData.push_back(std::move(data));
}
else {
std::cerr << "**** Coruppted: " << line << "\n";
}
}
}
// So, now we have read all csv data
// Show eight column of GPGSV data
for (const Tokens& t : csvData) {
if (t[0] == "$GPGGA") {
std::cout << "$GPGGA -->" << t[1] << "\n";
}
else if (t[0] == "$GPGSV") {
std::cout << "$GPGSV -->" << t[4] << " " << t[7] << "\n";
}
}
return 0;
}
Of course there are many other possibilities . .

Why calling via weak_ptr is so slow?

I have read the question What's the performance penalty of weak_ptr? but my own tests show different results.
I'm making delegates with smart pointers. The simple code below shows reproduces the performance issues with weak_ptr. Can anybody tell me why?
#include <chrono>
#include <functional>
#include <iostream>
#include <memory>
#include <stdint.h>
#include <string>
#include <utility>
struct Foo
{
Foo() : counter(0) { incrStep = 1;}
void bar()
{
counter += incrStep;
}
virtual ~Foo()
{
std::cout << "End " << counter << std::endl;
}
private:
uint64_t counter;
uint64_t incrStep;
};
void pf(const std::string &md, const std::function<void()> &g)
{
const auto st = std::chrono::high_resolution_clock::now();
g();
const auto ft = std::chrono::high_resolution_clock::now();
const auto del = std::chrono::duration_cast<std::chrono::milliseconds>(ft - st);
std::cout << md << " \t: \t" << del.count() << std::endl;
}
And the test:
int main(int , char** )
{
volatile size_t l = 1000000000ULL;
size_t maxCounter = l;
auto a = std::make_shared<Foo>();
std::weak_ptr<Foo> wp = a;
pf("call via raw ptr ", [=](){
for (size_t i = 0; i < maxCounter; ++i)
{
auto p = a.get();
if (p)
{
p->bar();
}
}
});
pf("call via shared_ptr ", [=](){
for (size_t i = 0; i < maxCounter; ++i)
{
if (a)
{
a->bar();
}
}
});
pf("call via weak_ptr ", [=](){
std::shared_ptr<Foo> p;
for (size_t i = 0; i < maxCounter; ++i)
{
p = wp.lock();
if (p)
{
p->bar();
}
}
});
pf("call via shared_ptr copy", [=](){
volatile std::shared_ptr<Foo> p1 = a;
std::shared_ptr<Foo> p;
for (size_t i = 0; i < maxCounter; ++i)
{
p = const_cast<std::shared_ptr<Foo>& >(p1);
if (p)
{
p->bar();
}
}
});
pf("call via mem_fn ", [=](){
auto fff = std::mem_fn(&Foo::bar);
for (size_t i = 0; i < maxCounter; ++i)
{
fff(a.get());
}
});
return 0;
}
Results:
$ ./test
call via raw ptr : 369
call via shared_ptr : 302
call via weak_ptr : 22663
call via shared_ptr copy : 2171
call via mem_fn : 2124
End 5000000000
As you can see, weak_ptr is 10 times slower than shared_ptr with copying and std::mem_fn and 60 times slower than using raw ptr or shared_ptr.get()
In trying to reproduce your test I realised that the optimizer might be eliminating more than it should. What I did was to utilize random numbers to defeat over-optimization and these results seem realistic with std::weak_ptr being nearly three times slower than the std::shared_ptr or its raw pointer.
I calculate a checksum in each test to ensure they are all doing the same work:
#include <chrono>
#include <memory>
#include <random>
#include <vector>
#include <iomanip>
#include <iostream>
#define OUT(m) do{std::cout << m << '\n';}while(0)
class Timer
{
using clock = std::chrono::steady_clock;
using microseconds = std::chrono::microseconds;
clock::time_point tsb;
clock::time_point tse;
public:
void start() { tsb = clock::now(); }
void stop() { tse = clock::now(); }
void clear() { tsb = tse; }
friend std::ostream& operator<<(std::ostream& o, const Timer& timer)
{
return o << timer.secs();
}
// return time difference in seconds
double secs() const
{
if(tse <= tsb)
return 0.0;
auto d = std::chrono::duration_cast<microseconds>(tse - tsb);
return double(d.count()) / 1000000.0;
}
};
constexpr auto N = 100000000U;
int main()
{
std::mt19937 rnd{std::random_device{}()};
std::uniform_int_distribution<int> pick{0, 100};
std::vector<int> random_ints;
for(auto i = 0U; i < 1024; ++i)
random_ints.push_back(pick(rnd));
std::shared_ptr<int> sptr = std::make_shared<int>(std::rand() % 100);
int* rptr = sptr.get();
std::weak_ptr<int> wptr = sptr;
Timer timer;
unsigned sum = 0;
sum = 0;
timer.start();
for(auto i = 0U; i < N; ++i)
{
sum += random_ints[i % random_ints.size()] * *sptr;
}
timer.stop();
OUT("sptr: " << sum << " " << timer);
sum = 0;
timer.start();
for(auto i = 0U; i < N; ++i)
{
sum += random_ints[i % random_ints.size()] * *rptr;
}
timer.stop();
OUT("rptr: " << sum << " " << timer);
sum = 0;
timer.start();
for(auto i = 0U; i < N; ++i)
{
sum += random_ints[i % random_ints.size()] * *wptr.lock();
}
timer.stop();
OUT("wptr: " << sum << " " << timer);
}
Compiler flags:
g++ -std=c++14 -O3 -g0 -D NDEBUG -o bin/timecpp src/timecpp.cpp
Example Output:
sptr: 1367265700 1.26869 // shared pointer
rptr: 1367265700 1.26435 // raw pointer
wptr: 1367265700 2.99008 // weak pointer

BK-Tree Implementation Insertion time is more how to reduce

Following is my attempt to write BK-Tree , for 150000 word file it takes around 8 seconds
Is there any way to reduce this time.
Following is my code
#include <stdio.h>
#include <string>
#include <vector>
#include <fstream>
#include <iostream>
#include <sstream>
#include "Timer.h"
class BkTree {
public:
BkTree();
~BkTree();
void insert(std::string m_item);
private:
size_t EditDistance( const std::string &s, const std::string &t );
struct Node {
std::string m_item;
size_t m_distToParent;
Node *m_firstChild;
Node *m_nextSibling;
Node(std::string x, size_t dist);
~Node();
};
Node *m_root;
int m_size;
protected:
};
BkTree::BkTree() {
m_root = NULL;
m_size = 0;
}
BkTree::~BkTree() {
if( m_root )
delete m_root;
}
BkTree::Node::Node(std::string x, size_t dist) {
m_item = x;
m_distToParent = dist;
m_firstChild = m_nextSibling = NULL;
}
BkTree::Node::~Node() {
if( m_firstChild )
delete m_firstChild;
if( m_nextSibling )
delete m_nextSibling;
}
void BkTree::insert(std::string m_item) {
if( !m_root ){
m_size = 1;
m_root = new Node(m_item, -1);
return;
}
Node *t = m_root;
while( true ) {
size_t d = EditDistance( t->m_item, m_item );
if( !d )
return;
Node *ch = t->m_firstChild;
while( ch ) {
if( ch->m_distToParent == d ) {
t = ch;
break;
}
ch = ch->m_nextSibling;
}
if( !ch ) {
Node *newChild = new Node(m_item, d);
newChild->m_nextSibling = t->m_firstChild;
t->m_firstChild = newChild;
m_size++;
break;
}
}
}
size_t BkTree::EditDistance( const std::string &left, const std::string &right ) {
size_t asize = left.size();
size_t bsize = right.size();
std::vector<size_t> prevrow(bsize+1);
std::vector<size_t> thisrow(bsize+1);
for(size_t i = 0; i <= bsize; i++)
prevrow[i] = i;
for(size_t i = 1; i <= asize; i ++) {
thisrow[0] = i;
for(size_t j = 1; j <= bsize; j++) {
thisrow[j] = std::min(prevrow[j-1] + size_t(left[i-1] != right[j-1]),
1 + std::min(prevrow[j],thisrow[j-1]) );
}
std::swap(thisrow,prevrow);
}
return prevrow[bsize];
}
void trim(std::string& input_str) {
if(input_str.empty()) return;
size_t startIndex = input_str.find_first_not_of(" ");
size_t endIndex = input_str.find_last_not_of("\r\n");
std::string temp_str = input_str;
input_str.erase();
input_str = temp_str.substr(startIndex, (endIndex-startIndex+ 1) );
}
int main( int argc, char **argv ) {
BkTree *pDictionary = new BkTree();
std::ifstream dictFile("D:\\dictionary.txt");
Timer *t = new Timer("Time Taken to prepare Tree = ");
std::string line;
if (dictFile.is_open()) {
while (! dictFile.eof() ) {
std::getline (dictFile,line);
trim(line);
pDictionary->insert(line);
}
dictFile.close();
}
delete t;
delete pDictionary;
return 0;
}
class Timer {
public:
Timer (const std::string &name = "undef");
~Timer (void);
private:
std::string m_name;
std::clock_t m_started;
protected:
};
Timer::Timer (const std::string &name) : m_name(name), m_started(clock()) {
}
Timer::~Timer (void) {
double secs = static_cast<double>(std::clock() - m_started) / CLOCKS_PER_SEC;
std::cout << m_name << ": " << secs << " secs." << std::endl;
}
You can reduce the time by eliminating the I/O. To test your algorithm, remove as many objects out of the equation that are not directly under the control of your program. For example, the OS controls the I/O, it is out of your control. An array of constant text removes much OS involvement (the OS still may page the array depending on OS memory allocation).
Next, most tree structures are data oriented. Their performance times depend on the data. Try three sets of data: sorted ascending, "random", and sorted descending. Note the times for each.
Look at your loops and factor out any constants. Create temporary variables in loops for constant calculations in inner loops. Remove unnecessary operations.
Lastly, if your program and algorithm is very robust, work on other projects. Optimize only if necessary.